/* * Copyright 2001-2009, Haiku. * Distributed under the terms of the MIT License. * * Authors: * DarkWyrm * Michael Lotz * Stephan Aßmus */ /*! BView/BDirectWindow/Accelerant combination HWInterface implementation */ #include "DWindowHWInterface.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "DWindowBuffer.h" #include "PortLink.h" #include "RGBColor.h" #include "ServerConfig.h" #include "ServerCursor.h" #include "UpdateQueue.h" #ifdef DEBUG_DRIVER_MODULE # include # define STRACE(x) printf x #else # define STRACE(x) ; #endif const unsigned char kEmptyCursor[] = { 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static int32 run_app_thread(void* cookie) { if (BApplication* app = (BApplication*)cookie) { app->Lock(); app->Run(); } return 0; } //#define INPUTSERVER_TEST_MODE 1 class DView : public BView { public: DView(BRect bounds); virtual ~DView(); // DView void ForwardMessage(BMessage* message = NULL); private: port_id fInputPort; }; class DWindow : public BWindow { public: DWindow(BRect frame, DWindowHWInterface* interface, DWindowBuffer* buffer); virtual ~DWindow(); virtual bool QuitRequested(); // virtual void DirectConnected(direct_buffer_info* info); virtual void FrameMoved(BPoint newOffset); private: DWindowHWInterface* fHWInterface; DWindowBuffer* fBuffer; }; class DirectMessageFilter : public BMessageFilter { public: DirectMessageFilter(DView* view); virtual filter_result Filter(BMessage *message, BHandler** _target); private: DView* fView; }; // #pragma mark - DView::DView(BRect bounds) : BView(bounds, "graphics card view", B_FOLLOW_ALL, 0) { SetViewColor(B_TRANSPARENT_COLOR); #ifndef INPUTSERVER_TEST_MODE fInputPort = create_port(200, SERVER_INPUT_PORT); #else fInputPort = create_port(100, "ViewInputDevice"); #endif #ifdef ENABLE_INPUT_SERVER_EMULATION AddFilter(new DirectMessageFilter(this)); #endif } DView::~DView() { } /*! This function emulates the Input Server by sending the *exact* same kind of messages to the server's port. Being we're using a regular window, it would make little sense to do anything else. */ void DView::ForwardMessage(BMessage* message) { if (message == NULL) message = Window()->CurrentMessage(); if (message == NULL) return; // remove some fields that potentially mess up our own message processing BMessage copy = *message; copy.RemoveName("screen_where"); copy.RemoveName("be:transit"); copy.RemoveName("be:view_where"); copy.RemoveName("be:cursor_needed"); size_t length = copy.FlattenedSize(); char stream[length]; if (copy.Flatten(stream, length) == B_OK) write_port(fInputPort, 0, stream, length); } // #pragma mark - DirectMessageFilter::DirectMessageFilter(DView* view) : BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE), fView(view) { } filter_result DirectMessageFilter::Filter(BMessage* message, BHandler** target) { switch (message->what) { case B_KEY_DOWN: case B_UNMAPPED_KEY_DOWN: case B_KEY_UP: case B_UNMAPPED_KEY_UP: case B_MOUSE_DOWN: case B_MOUSE_UP: case B_MOUSE_WHEEL_CHANGED: fView->ForwardMessage(message); return B_SKIP_MESSAGE; case B_MOUSE_MOVED: { int32 transit; if (message->FindInt32("be:transit", &transit) == B_OK && transit == B_ENTERED_VIEW) { // A bug in R5 prevents this call from having an effect if // called elsewhere, and calling it here works, if we're lucky :-) BCursor cursor(kEmptyCursor); fView->SetViewCursor(&cursor, true); } fView->ForwardMessage(message); return B_SKIP_MESSAGE; } } return B_DISPATCH_MESSAGE; } // #pragma mark - DWindow::DWindow(BRect frame, DWindowHWInterface* interface, DWindowBuffer* buffer) : BWindow(frame, "Haiku App Server", B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, B_NOT_ZOOMABLE | B_NOT_RESIZABLE | B_NOT_MOVABLE), fHWInterface(interface), fBuffer(buffer) { DView* view = new DView(Bounds()); AddChild(view); view->MakeFocus(); // make it receive key events } DWindow::~DWindow() { } bool DWindow::QuitRequested() { port_id serverport = find_port(SERVER_PORT_NAME); if (serverport >= 0) { BPrivate::PortLink link(serverport); link.StartMessage(B_QUIT_REQUESTED); link.Flush(); } else printf("ERROR: couldn't find the app_server's main port!"); // we don't quit on ourself, we let us be Quit()! return false; } /* void DWindow::DirectConnected(direct_buffer_info* info) { // fDesktop->LockClipping(); // // fEngine.Lock(); // switch(info->buffer_state & B_DIRECT_MODE_MASK) { case B_DIRECT_START: case B_DIRECT_MODIFY: fBuffer->SetTo(info); // fDesktop->SetOffset(info->window_bounds.left, info->window_bounds.top); break; case B_DIRECT_STOP: fBuffer->SetTo(NULL); break; } // // fDesktop->SetMasterClipping(&fBuffer.WindowClipping()); // // fEngine.Unlock(); // // fDesktop->UnlockClipping(); } */ void DWindow::FrameMoved(BPoint newOffset) { fHWInterface->SetOffset((int32)newOffset.x, (int32)newOffset.y); } // #pragma mark - const int32 kDefaultParamsCount = 64; DWindowHWInterface::DWindowHWInterface() : HWInterface(), fFrontBuffer(new DWindowBuffer()), fWindow(NULL), fXOffset(50), fYOffset(50), fCardFD(-1), fAccelerantImage(-1), fAccelerantHook(NULL), fEngineToken(NULL), fSyncToken(), // required hooks fAccAcquireEngine(NULL), fAccReleaseEngine(NULL), fAccSyncToToken(NULL), fAccGetModeCount(NULL), fAccGetModeList(NULL), fAccGetFrameBufferConfig(NULL), fAccSetDisplayMode(NULL), fAccGetDisplayMode(NULL), fAccGetPixelClockLimits(NULL), // optional accelerant hooks fAccGetTimingConstraints(NULL), fAccProposeDisplayMode(NULL), fAccFillRect(NULL), fAccInvertRect(NULL), fAccScreenBlit(NULL), fAccSetCursorShape(NULL), fAccMoveCursor(NULL), fAccShowCursor(NULL), fRectParams(new (std::nothrow) fill_rect_params[kDefaultParamsCount]), fRectParamsCount(kDefaultParamsCount), fBlitParams(new (std::nothrow) blit_params[kDefaultParamsCount]), fBlitParamsCount(kDefaultParamsCount) { fDisplayMode.virtual_width = 800; fDisplayMode.virtual_height = 600; fDisplayMode.space = B_RGBA32; memset(&fSyncToken, 0, sizeof(sync_token)); } DWindowHWInterface::~DWindowHWInterface() { if (fWindow) { fWindow->Lock(); fWindow->Quit(); } delete[] fRectParams; delete[] fBlitParams; be_app->Lock(); be_app->Quit(); delete be_app; } status_t DWindowHWInterface::Initialize() { status_t ret = HWInterface::Initialize(); if (!fRectParams || !fBlitParams) return B_NO_MEMORY; if (ret >= B_OK) { for (int32 i = 1; fCardFD != B_ENTRY_NOT_FOUND; i++) { fCardFD = _OpenGraphicsDevice(i); if (fCardFD < 0) { STRACE(("Failed to open graphics device\n")); continue; } if (_OpenAccelerant(fCardFD) == B_OK) break; close(fCardFD); // _OpenAccelerant() failed, try to open next graphics card } return fCardFD >= 0 ? B_OK : fCardFD; } return ret; } /*! \brief Opens a graphics device for read-write access \param deviceNumber Number identifying which graphics card to open (1 for first card) \return The file descriptor for the opened graphics device The deviceNumber is relative to the number of graphics devices that can be successfully opened. One represents the first card that can be successfully opened (not necessarily the first one listed in the directory). Graphics drivers must be able to be opened more than once, so we really get the first working entry. */ int DWindowHWInterface::_OpenGraphicsDevice(int deviceNumber) { DIR *directory = opendir("/dev/graphics"); if (!directory) return B_ENTRY_NOT_FOUND; // TODO: We do not need to avoid the "vesa" or "framebuffer" drivers this way // once they been ported to the new driver architecture - the special case here // can then be removed. int count = 0; struct dirent *entry = NULL; int current_card_fd = -1; char path[PATH_MAX]; while (count < deviceNumber && (entry = readdir(directory)) != NULL) { if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..") || !strcmp(entry->d_name, "vesa") || !strcmp(entry->d_name, "framebuffer")) continue; if (current_card_fd >= 0) { close(current_card_fd); current_card_fd = -1; } sprintf(path, "/dev/graphics/%s", entry->d_name); current_card_fd = open(path, B_READ_WRITE); if (current_card_fd >= 0) count++; } // Open VESA or Framebuffer driver if we were not able to get a better one. if (count < deviceNumber) { if (deviceNumber == 1) { sprintf(path, "/dev/graphics/vesa"); current_card_fd = open(path, B_READ_WRITE); if (current_card_fd < 0) { sprintf(path, "/dev/graphics/framebuffer"); current_card_fd = open(path, B_READ_WRITE); } } else { close(current_card_fd); current_card_fd = B_ENTRY_NOT_FOUND; } } if (entry) fCardNameInDevFS = entry->d_name; return current_card_fd; } status_t DWindowHWInterface::_OpenAccelerant(int device) { char signature[1024]; if (ioctl(device, B_GET_ACCELERANT_SIGNATURE, &signature, sizeof(signature)) != B_OK) return B_ERROR; STRACE(("accelerant signature is: %s\n", signature)); struct stat accelerant_stat; const static directory_which dirs[] = { B_USER_NONPACKAGED_ADDONS_DIRECTORY, B_USER_ADDONS_DIRECTORY, B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY, B_SYSTEM_ADDONS_DIRECTORY }; fAccelerantImage = -1; for (uint32 i = 0; i < sizeof(dirs) / sizeof(directory_which); i++) { char path[PATH_MAX]; if (find_directory(dirs[i], -1, false, path, PATH_MAX) != B_OK) continue; strcat(path, "/accelerants/"); strcat(path, signature); if (stat(path, &accelerant_stat) != 0) continue; fAccelerantImage = load_add_on(path); if (fAccelerantImage >= 0) { if (get_image_symbol(fAccelerantImage, B_ACCELERANT_ENTRY_POINT, B_SYMBOL_TYPE_ANY, (void**)(&fAccelerantHook)) != B_OK ) { STRACE(("unable to get B_ACCELERANT_ENTRY_POINT\n")); unload_add_on(fAccelerantImage); fAccelerantImage = -1; return B_ERROR; } accelerant_clone_info_size cloneInfoSize; cloneInfoSize = (accelerant_clone_info_size)fAccelerantHook( B_ACCELERANT_CLONE_INFO_SIZE, NULL); if (!cloneInfoSize) { STRACE(("unable to get B_ACCELERANT_CLONE_INFO_SIZE (%s)\n", path)); unload_add_on(fAccelerantImage); fAccelerantImage = -1; return B_ERROR; } ssize_t cloneSize = cloneInfoSize(); void* cloneInfoData = malloc(cloneSize); // get_accelerant_clone_info getCloneInfo; // getCloneInfo = (get_accelerant_clone_info)fAccelerantHook(B_GET_ACCELERANT_CLONE_INFO, NULL); // if (!getCloneInfo) { // STRACE(("unable to get B_GET_ACCELERANT_CLONE_INFO (%s)\n", path)); // unload_add_on(fAccelerantImage); // fAccelerantImage = -1; // return B_ERROR; // } // printf("getCloneInfo: %p\n", getCloneInfo); // // getCloneInfo(cloneInfoData); // TODO: this is what works for the ATI Radeon driver... sprintf((char*)cloneInfoData, "graphics/%s", fCardNameInDevFS.String()); clone_accelerant cloneAccelerant; cloneAccelerant = (clone_accelerant)fAccelerantHook(B_CLONE_ACCELERANT, NULL); if (!cloneAccelerant) { STRACE(("unable to get B_CLONE_ACCELERANT\n")); unload_add_on(fAccelerantImage); fAccelerantImage = -1; free(cloneInfoData); return B_ERROR; } status_t ret = cloneAccelerant(cloneInfoData); if (ret != B_OK) { STRACE(("Cloning accelerant unsuccessful: %s\n", strerror(ret))); unload_add_on(fAccelerantImage); fAccelerantImage = -1; return B_ERROR; } break; } } if (fAccelerantImage < B_OK) return B_ERROR; if (_SetupDefaultHooks() != B_OK) { STRACE(("cannot setup default hooks\n")); uninit_accelerant uninitAccelerant = (uninit_accelerant) fAccelerantHook(B_UNINIT_ACCELERANT, NULL); if (uninitAccelerant != NULL) uninitAccelerant(); unload_add_on(fAccelerantImage); return B_ERROR; } else { _UpdateFrameBufferConfig(); } return B_OK; } status_t DWindowHWInterface::_SetupDefaultHooks() { // required fAccAcquireEngine = (acquire_engine)fAccelerantHook(B_ACQUIRE_ENGINE, NULL); fAccReleaseEngine = (release_engine)fAccelerantHook(B_RELEASE_ENGINE, NULL); fAccSyncToToken = (sync_to_token)fAccelerantHook(B_SYNC_TO_TOKEN, NULL); fAccGetModeCount = (accelerant_mode_count)fAccelerantHook( B_ACCELERANT_MODE_COUNT, NULL); fAccGetModeList = (get_mode_list)fAccelerantHook(B_GET_MODE_LIST, NULL); fAccGetFrameBufferConfig = (get_frame_buffer_config)fAccelerantHook( B_GET_FRAME_BUFFER_CONFIG, NULL); fAccSetDisplayMode = (set_display_mode)fAccelerantHook( B_SET_DISPLAY_MODE, NULL); fAccGetDisplayMode = (get_display_mode)fAccelerantHook( B_GET_DISPLAY_MODE, NULL); fAccGetPixelClockLimits = (get_pixel_clock_limits)fAccelerantHook( B_GET_PIXEL_CLOCK_LIMITS, NULL); if (!fAccAcquireEngine || !fAccReleaseEngine || !fAccGetFrameBufferConfig || !fAccGetModeCount || !fAccGetModeList || !fAccSetDisplayMode || !fAccGetDisplayMode || !fAccGetPixelClockLimits) { return B_ERROR; } // optional fAccGetTimingConstraints = (get_timing_constraints)fAccelerantHook( B_GET_TIMING_CONSTRAINTS, NULL); fAccProposeDisplayMode = (propose_display_mode)fAccelerantHook( B_PROPOSE_DISPLAY_MODE, NULL); // cursor fAccSetCursorShape = (set_cursor_shape)fAccelerantHook( B_SET_CURSOR_SHAPE, NULL); fAccMoveCursor = (move_cursor)fAccelerantHook(B_MOVE_CURSOR, NULL); fAccShowCursor = (show_cursor)fAccelerantHook(B_SHOW_CURSOR, NULL); // update acceleration hooks // TODO: would actually have to pass a valid display_mode! fAccFillRect = (fill_rectangle)fAccelerantHook(B_FILL_RECTANGLE, NULL); fAccInvertRect = (invert_rectangle)fAccelerantHook(B_INVERT_RECTANGLE, NULL); fAccScreenBlit = (screen_to_screen_blit)fAccelerantHook( B_SCREEN_TO_SCREEN_BLIT, NULL); return B_OK; } status_t DWindowHWInterface::_UpdateFrameBufferConfig() { frame_buffer_config config; if (fAccGetFrameBufferConfig(&config) != B_OK) { STRACE(("unable to get frame buffer config\n")); return B_ERROR; } fFrontBuffer->SetTo(&config, fXOffset, fYOffset, fDisplayMode.virtual_width, fDisplayMode.virtual_height, (color_space)fDisplayMode.space); return B_OK; } status_t DWindowHWInterface::Shutdown() { printf("DWindowHWInterface::Shutdown()\n"); if (fAccelerantHook) { uninit_accelerant UninitAccelerant = (uninit_accelerant)fAccelerantHook(B_UNINIT_ACCELERANT, NULL); if (UninitAccelerant) UninitAccelerant(); } if (fAccelerantImage >= 0) unload_add_on(fAccelerantImage); if (fCardFD >= 0) close(fCardFD); return B_OK; } status_t DWindowHWInterface::SetMode(const display_mode& mode) { AutoWriteLocker _(this); status_t ret = B_OK; // prevent from doing the unnecessary if (fFrontBuffer.IsSet() && fDisplayMode.virtual_width == mode.virtual_width && fDisplayMode.virtual_height == mode.virtual_height && fDisplayMode.space == mode.space) return ret; // check if we support the mode display_mode *modes; uint32 modeCount, i; if (GetModeList(&modes, &modeCount) != B_OK) return B_NO_MEMORY; for (i = 0; i < modeCount; i++) { // we only care for the bare minimum if (modes[i].virtual_width == mode.virtual_width && modes[i].virtual_height == mode.virtual_height && modes[i].space == mode.space) { // take over settings fDisplayMode = modes[i]; break; } } delete[] modes; if (i == modeCount) return B_BAD_VALUE; BRect frame(0.0, 0.0, fDisplayMode.virtual_width - 1, fDisplayMode.virtual_height - 1); // create the window if we don't have one already if (!fWindow) { // if the window has not been created yet, the BApplication // has not been created either, but we need one to display // a real BWindow in the test environment. // be_app->Run() needs to be called in another thread BApplication* app = new BApplication( "application/x-vnd.Haiku-test-app_server"); app->Unlock(); thread_id appThread = spawn_thread(run_app_thread, "app thread", B_NORMAL_PRIORITY, app); if (appThread >= B_OK) ret = resume_thread(appThread); else ret = appThread; if (ret < B_OK) return ret; fWindow = new DWindow(frame.OffsetByCopy(fXOffset, fYOffset), this, fFrontBuffer.Get()); // fire up the window thread but don't show it on screen yet fWindow->Hide(); fWindow->Show(); } if (fWindow->Lock()) { // free and reallocate the bitmaps while the window is locked, // so that the view does not accidentally draw a freed bitmap if (ret >= B_OK) { // change the window size and update the bitmap used for drawing fWindow->ResizeTo(frame.Width(), frame.Height()); } // window is hidden when this function is called the first time if (fWindow->IsHidden()) fWindow->Show(); fWindow->Unlock(); } else { ret = B_ERROR; } _UpdateFrameBufferConfig(); _NotifyFrameBufferChanged(); return ret; } void DWindowHWInterface::GetMode(display_mode* mode) { if (mode && ReadLock()) { *mode = fDisplayMode; ReadUnlock(); } } status_t DWindowHWInterface::GetDeviceInfo(accelerant_device_info* info) { // We really don't have to provide anything here because this is strictly // a software-only driver, but we'll have some fun, anyway. if (ReadLock()) { info->version = 100; sprintf(info->name, "Haiku, Inc. DWindowHWInterface"); sprintf(info->chipset, "Haiku, Inc. Chipset"); sprintf(info->serial_no, "3.14159265358979323846"); info->memory = 134217728; // 128 MB, not that we really have that much. :) info->dac_speed = 0xFFFFFFFF; // *heh* ReadUnlock(); } return B_OK; } status_t DWindowHWInterface::GetFrameBufferConfig(frame_buffer_config& config) { if (!fFrontBuffer.IsSet()) return B_ERROR; config.frame_buffer = fFrontBuffer->Bits(); config.frame_buffer_dma = NULL; config.bytes_per_row = fFrontBuffer->BytesPerRow(); return B_OK; } status_t DWindowHWInterface::GetModeList(display_mode** _modes, uint32* _count) { AutoReadLocker _(this); #if 1 // setup a whole bunch of different modes const struct resolution { int32 width, height; } resolutions[] = { {640, 480}, {800, 600}, {1024, 768}, {1152, 864}, {1280, 960}, {1280, 1024}, {1400, 1050}, {1600, 1200} }; uint32 resolutionCount = sizeof(resolutions) / sizeof(resolutions[0]); // const uint32 colors[] = {B_CMAP8, B_RGB15, B_RGB16, B_RGB32}; uint32 count = resolutionCount/* * 4*/; display_mode* modes = new(std::nothrow) display_mode[count]; if (modes == NULL) return B_NO_MEMORY; *_modes = modes; *_count = count; int32 index = 0; for (uint32 i = 0; i < resolutionCount; i++) { modes[index].virtual_width = resolutions[i].width; modes[index].virtual_height = resolutions[i].height; modes[index].space = B_RGB32; modes[index].h_display_start = 0; modes[index].v_display_start = 0; modes[index].timing.h_display = resolutions[i].width; modes[index].timing.v_display = resolutions[i].height; modes[index].timing.h_total = 22000; modes[index].timing.v_total = 22000; modes[index].timing.pixel_clock = ((uint32)modes[index].timing.h_total * modes[index].timing.v_total * 60) / 1000; modes[index].flags = B_PARALLEL_ACCESS; index++; } #else // support only a single mode, useful // for testing a specific mode display_mode *modes = new(std::nothrow) display_mode[1]; modes[0].virtual_width = 800; modes[0].virtual_height = 600; modes[0].space = B_BRGB32; *_modes = modes; *_count = 1; #endif return B_OK; } status_t DWindowHWInterface::GetPixelClockLimits(display_mode* mode, uint32* low, uint32* high) { return B_ERROR; } status_t DWindowHWInterface::GetTimingConstraints( display_timing_constraints* constraints) { return B_ERROR; } status_t DWindowHWInterface::ProposeMode(display_mode* candidate, const display_mode* low, const display_mode* high) { // We should be able to get away with this because we're not dealing with // any specific hardware. This is a Good Thing(TM) because we can support // any hardware we wish within reasonable expectaions and programmer // laziness. :P return B_OK; } sem_id DWindowHWInterface::RetraceSemaphore() { return -1; } status_t DWindowHWInterface::WaitForRetrace(bigtime_t timeout) { // Locking shouldn't be necessary here - R5 should handle this for us. :) BScreen screen; return screen.WaitForRetrace(timeout); } status_t DWindowHWInterface::SetDPMSMode(uint32 state) { AutoWriteLocker _(this); return BScreen().SetDPMS(state); } uint32 DWindowHWInterface::DPMSMode() { AutoReadLocker _(this); return BScreen().DPMSState(); } uint32 DWindowHWInterface::DPMSCapabilities() { AutoReadLocker _(this); return BScreen().DPMSCapabilites(); } status_t DWindowHWInterface::SetBrightness(float brightness) { AutoReadLocker _(this); return BScreen().SetBrightness(brightness); } status_t DWindowHWInterface::GetBrightness(float* brightness) { AutoReadLocker _(this); return BScreen().GetBrightness(brightness); } uint32 DWindowHWInterface::AvailableHWAcceleration() const { uint32 flags = 0; if (!IsDoubleBuffered()) { if (fAccScreenBlit) flags |= HW_ACC_COPY_REGION; if (fAccFillRect) flags |= HW_ACC_FILL_REGION; if (fAccInvertRect) flags |= HW_ACC_INVERT_REGION; } return flags; } void DWindowHWInterface::CopyRegion(const clipping_rect* sortedRectList, uint32 count, int32 xOffset, int32 yOffset) { if (fAccScreenBlit && fAccAcquireEngine) { if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken, &fEngineToken) >= B_OK) { // make sure the blit_params cache is large enough if (fBlitParamsCount < count) { fBlitParamsCount = (count / kDefaultParamsCount + 1) * kDefaultParamsCount; // NOTE: realloc() could be used instead... blit_params* params = new(std::nothrow) blit_params[fBlitParamsCount]; if (params) { delete[] fBlitParams; fBlitParams = params; } else { count = fBlitParamsCount; } } // convert the rects for (uint32 i = 0; i < count; i++) { fBlitParams[i].src_left = (uint16)sortedRectList[i].left + fXOffset; fBlitParams[i].src_top = (uint16)sortedRectList[i].top + fYOffset; fBlitParams[i].dest_left = (uint16)sortedRectList[i].left + xOffset + fXOffset; fBlitParams[i].dest_top = (uint16)sortedRectList[i].top + yOffset + fYOffset; // NOTE: width and height are expressed as distance, not count! fBlitParams[i].width = (uint16)(sortedRectList[i].right - sortedRectList[i].left); fBlitParams[i].height = (uint16)(sortedRectList[i].bottom - sortedRectList[i].top); } // go fAccScreenBlit(fEngineToken, fBlitParams, count); // done if (fAccReleaseEngine) fAccReleaseEngine(fEngineToken, &fSyncToken); // sync if (fAccSyncToToken) fAccSyncToToken(&fSyncToken); } } } void DWindowHWInterface::FillRegion(/*const*/ BRegion& region, const rgb_color& color, bool autoSync) { if (fAccFillRect && fAccAcquireEngine) { if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken, &fEngineToken) >= B_OK) { // convert the region uint32 count; _RegionToRectParams(®ion, &count); // go fAccFillRect(fEngineToken, _NativeColor(color), fRectParams, count); // done if (fAccReleaseEngine) fAccReleaseEngine(fEngineToken, &fSyncToken); // sync if (autoSync && fAccSyncToToken) fAccSyncToToken(&fSyncToken); } } } void DWindowHWInterface::InvertRegion(/*const*/ BRegion& region) { if (fAccInvertRect && fAccAcquireEngine) { if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken, &fEngineToken) >= B_OK) { // convert the region uint32 count; _RegionToRectParams(®ion, &count); // go fAccInvertRect(fEngineToken, fRectParams, count); // done if (fAccReleaseEngine) fAccReleaseEngine(fEngineToken, &fSyncToken); // sync if (fAccSyncToToken) fAccSyncToToken(&fSyncToken); } else { fprintf(stderr, "AcquireEngine failed!\n"); } } else { fprintf(stderr, "AccelerantHWInterface::InvertRegion() called, but " "hook not available!\n"); } } void DWindowHWInterface::Sync() { if (fAccSyncToToken) fAccSyncToToken(&fSyncToken); } RenderingBuffer* DWindowHWInterface::FrontBuffer() const { return fFrontBuffer.Get(); } RenderingBuffer* DWindowHWInterface::BackBuffer() const { return fFrontBuffer.Get(); } bool DWindowHWInterface::IsDoubleBuffered() const { return false; } status_t DWindowHWInterface::Invalidate(const BRect& frame) { return HWInterface::Invalidate(frame); } void DWindowHWInterface::SetOffset(int32 left, int32 top) { if (!WriteLock()) return; fXOffset = left; fYOffset = top; _UpdateFrameBufferConfig(); // TODO: someone would have to call DrawingEngine::Update() now! WriteUnlock(); } void DWindowHWInterface::_RegionToRectParams(/*const*/ BRegion* region, uint32* count) const { *count = region->CountRects(); if (fRectParamsCount < *count) { fRectParamsCount = (*count / kDefaultParamsCount + 1) * kDefaultParamsCount; // NOTE: realloc() could be used instead... fill_rect_params* params = new(std::nothrow) fill_rect_params[fRectParamsCount]; if (params) { delete[] fRectParams; fRectParams = params; } else { *count = fRectParamsCount; } } for (uint32 i = 0; i < *count; i++) { clipping_rect r = region->RectAtInt(i); fRectParams[i].left = (uint16)r.left + fXOffset; fRectParams[i].top = (uint16)r.top + fYOffset; fRectParams[i].right = (uint16)r.right + fXOffset; fRectParams[i].bottom = (uint16)r.bottom + fYOffset; } } uint32 DWindowHWInterface::_NativeColor(const rgb_color& color) const { // NOTE: This functions looks somehow suspicios to me. // It assumes that all graphics cards have the same native endianess, no? switch (fDisplayMode.space) { case B_CMAP8: case B_GRAY8: return RGBColor(color).GetColor8(); case B_RGB15_BIG: case B_RGBA15_BIG: case B_RGB15_LITTLE: case B_RGBA15_LITTLE: return RGBColor(color).GetColor15(); case B_RGB16_BIG: case B_RGB16_LITTLE: return RGBColor(color).GetColor16(); case B_RGB32_BIG: case B_RGBA32_BIG: case B_RGB32_LITTLE: case B_RGBA32_LITTLE: { uint32 native = (color.alpha << 24) | (color.red << 16) | (color.green << 8) | (color.blue); return native; } } return 0; }