From 17a4024ca9e730cafb989660625cbaffc663a574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Sat, 10 Dec 2005 16:43:38 +0000 Subject: [PATCH] classes needed for the new cloned Accelerant based test environment git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15470 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/servers/app/drawing/DWindowBuffer.cpp | 100 ++ src/servers/app/drawing/DWindowBuffer.h | 35 + .../app/drawing/DWindowHWInterface.cpp | 1020 +++++++++++++++++ src/servers/app/drawing/DWindowHWInterface.h | 121 ++ 4 files changed, 1276 insertions(+) create mode 100644 src/servers/app/drawing/DWindowBuffer.cpp create mode 100644 src/servers/app/drawing/DWindowBuffer.h create mode 100644 src/servers/app/drawing/DWindowHWInterface.cpp create mode 100644 src/servers/app/drawing/DWindowHWInterface.h diff --git a/src/servers/app/drawing/DWindowBuffer.cpp b/src/servers/app/drawing/DWindowBuffer.cpp new file mode 100644 index 0000000000..27510f6404 --- /dev/null +++ b/src/servers/app/drawing/DWindowBuffer.cpp @@ -0,0 +1,100 @@ +#include + +#include + +#include "DWindowBuffer.h" + +// constructor +DWindowBuffer::DWindowBuffer() + : fBits(NULL), + fWidth(0), + fHeight(0), + fBytesPerRow(0), + fFormat(B_NO_COLOR_SPACE), + fWindowClipping() +{ +} + +// destructor +DWindowBuffer::~DWindowBuffer() +{ +} + +// InitCheck +status_t +DWindowBuffer::InitCheck() const +{ + if (fBits) + return B_OK; + + return B_NO_INIT; +} + +// ColorSpace +color_space +DWindowBuffer::ColorSpace() const +{ + return fFormat; +} + +// Bits +void* +DWindowBuffer::Bits() const +{ + return (void*)fBits; +} + +// BytesPerRow +uint32 +DWindowBuffer::BytesPerRow() const +{ + return fBytesPerRow; +} + +// Width +uint32 +DWindowBuffer::Width() const +{ + return fWidth; +} + +// Height +uint32 +DWindowBuffer::Height() const +{ + return fHeight; +} + +// Set +void +DWindowBuffer::SetTo(direct_buffer_info* info) +{ +printf("DWindowBuffer::SetTo(%p)\n", info); + fWindowClipping.MakeEmpty(); + + if (info) { + int32 xOffset = info->window_bounds.left; + int32 yOffset = info->window_bounds.top; + // Get clipping information + for (uint32 i = 0; i < info->clip_list_count; i++) { + fWindowClipping.Include(info->clip_list[i]); + } + fWindowClipping.OffsetBy(xOffset, yOffset); + + fBytesPerRow = info->bytes_per_row; + fBits = (uint8*)info->bits; + fFormat = info->pixel_format; + fWidth = info->window_bounds.right - info->window_bounds.left + 1; + fHeight = info->window_bounds.bottom - info->window_bounds.top + 1; +printf(" width: %ld, height: %ld\n", fWidth, fHeight); +// offset bits to left top corner of window +fBits += xOffset * 4 + yOffset * fBytesPerRow; + } else { + fBits = NULL; + fWidth = 0; + fHeight = 0; + fBytesPerRow = 0; + fFormat = B_NO_COLOR_SPACE; + } +} + diff --git a/src/servers/app/drawing/DWindowBuffer.h b/src/servers/app/drawing/DWindowBuffer.h new file mode 100644 index 0000000000..475b89a449 --- /dev/null +++ b/src/servers/app/drawing/DWindowBuffer.h @@ -0,0 +1,35 @@ +#ifndef D_WINDOW_BUFFER_H +#define D_WINDOW_BUFFER_H + +#include "RenderingBuffer.h" + +struct direct_buffer_info; + +class DWindowBuffer : public RenderingBuffer { + public: + DWindowBuffer(); + virtual ~DWindowBuffer(); + + virtual status_t InitCheck() const; + + virtual color_space ColorSpace() const; + virtual void* Bits() const; + virtual uint32 BytesPerRow() const; + virtual uint32 Width() const; + virtual uint32 Height() const; + + void SetTo(direct_buffer_info* info); + + BRegion& WindowClipping() + { return fWindowClipping; } + private: + uint8* fBits; + uint32 fWidth; + uint32 fHeight; + uint32 fBytesPerRow; + color_space fFormat; + + BRegion fWindowClipping; +}; + +#endif // D_WINDOW_BUFFER_H diff --git a/src/servers/app/drawing/DWindowHWInterface.cpp b/src/servers/app/drawing/DWindowHWInterface.cpp new file mode 100644 index 0000000000..afeaaaf914 --- /dev/null +++ b/src/servers/app/drawing/DWindowHWInterface.cpp @@ -0,0 +1,1020 @@ +/* + * Copyright 2001-2005, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * DarkWyrm + * Michael Lotz +* Stephan Aßmus + */ + +/** BView/BDirectWindow/Accelerant combination HWInterface + implementation */ + +#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 "ServerProtocol.h" +#include "UpdateQueue.h" + +#include "DWindowHWInterface.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 }; + +// run_app_thread +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() {} + + virtual void AttachedToWindow(); + + // DView + void ForwardMessage(BMessage* message = NULL); + +private: + port_id fInputPort; +}; + +class DWindow : public BDirectWindow { + public: + DWindow(BRect frame, + DWindowBuffer* buffer); + virtual ~DWindow() {} + + virtual void MessageReceived(BMessage* message); + virtual bool QuitRequested(); + + virtual void DirectConnected(direct_buffer_info* info); + + private: + 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) +{ +#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 +} + + +// 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, DWindowBuffer* buffer) + : BDirectWindow(frame, "Haiku App Server", B_TITLED_WINDOW, + B_NOT_ZOOMABLE | B_NOT_RESIZABLE), + fBuffer(buffer) +{ + DView* view = new DView(Bounds()); + AddChild(view); + view->MakeFocus(); + // make it receive key events +} + + +// QuitRequested +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; +} + +// DirectConnected +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(); +} + +// #pragma mark - + + +DWindowHWInterface::DWindowHWInterface() + : HWInterface(), + fFrontBuffer(new DWindowBuffer()), + fWindow(NULL), + + 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) +{ + fDisplayMode.virtual_width = 640; + fDisplayMode.virtual_height = 480; + fDisplayMode.space = B_RGBA32; + + memset(&fSyncToken, 0, sizeof(sync_token)); +} + + +DWindowHWInterface::~DWindowHWInterface() +{ + if (fWindow) { + fWindow->Lock(); + fWindow->Quit(); + } + + delete fFrontBuffer; + + be_app->Lock(); + be_app->Quit(); + delete be_app; +} + +// Initialize +status_t +DWindowHWInterface::Initialize() +{ + status_t ret = HWInterface::Initialize(); + 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 -1; + + // ToDo: the former R5 "stub" driver is called "vesa" under Haiku; however, + // we do not need to avoid this driver this way when is has 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, "stub") || !strcmp(entry->d_name, "vesa")) + 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 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); + } 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_ADDONS_DIRECTORY, + B_COMMON_ADDONS_DIRECTORY, + B_BEOS_ADDONS_DIRECTORY + }; + + fAccelerantImage = -1; + + for (int32 i = 0; i < 3; 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; + 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; + } + + 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; +} + +// Shutdown +status_t +DWindowHWInterface::Shutdown() +{ + 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; +} + +// SetMode +status_t +DWindowHWInterface::SetMode(const display_mode &mode) +{ + AutoWriteLocker _(this); + + status_t ret = B_OK; + // prevent from doing the unnecessary + if (fFrontBuffer + && 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-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.OffsetToCopy(BPoint(50.0, 50.0)), fFrontBuffer); + + // 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) { + // clear out buffers, alpha is 255 this way + // TODO: maybe this should handle different color spaces in different ways +// memset(fFrontBuffer->Bits(), 255, fFrontBuffer->BitsLength()); + + // 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; + } + return ret; +} + +// GetMode +void +DWindowHWInterface::GetMode(display_mode* mode) +{ + if (mode && ReadLock()) { + *mode = fDisplayMode; + ReadUnlock(); + } +} + +// GetDeviceInfo +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 == NULL) + 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(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++) { + for (uint32 c = 0; c < 4; c++) { + modes[index].virtual_width = resolutions[i].width; + modes[index].virtual_height = resolutions[i].height; + modes[index].space = colors[c]; + + 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(nothrow) display_mode[1]; + modes[0].virtual_width = 640; + modes[0].virtual_height = 480; + modes[0].space = B_CMAP8; + + *_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 *dtc) +{ + 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; +} + +// RetraceSemaphore +sem_id +DWindowHWInterface::RetraceSemaphore() +{ + return -1; +} + +// WaitForRetrace +status_t +DWindowHWInterface::WaitForRetrace(bigtime_t timeout = B_INFINITE_TIMEOUT) +{ + // Locking shouldn't be necessary here - R5 should handle this for us. :) + BScreen screen; + return screen.WaitForRetrace(timeout); +} + +// SetDPMSMode +status_t +DWindowHWInterface::SetDPMSMode(const uint32 &state) +{ + AutoWriteLocker _(this); + + return BScreen().SetDPMS(state); +} + +// DPMSMode +uint32 +DWindowHWInterface::DPMSMode() +{ + AutoReadLocker _(this); + + return BScreen().DPMSState(); +} + +// DPMSCapabilities +uint32 +DWindowHWInterface::DPMSCapabilities() +{ + AutoReadLocker _(this); + + return BScreen().DPMSCapabilites(); +} + +// AvailableHardwareAcceleration +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; +} + +// CopyRegion +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) { + + // convert the rects + blit_params* params = new blit_params[count]; + for (uint32 i = 0; i < count; i++) { + params[i].src_left = (uint16)sortedRectList[i].left; + params[i].src_top = (uint16)sortedRectList[i].top; + + params[i].dest_left = (uint16)sortedRectList[i].left + xOffset; + params[i].dest_top = (uint16)sortedRectList[i].top + yOffset; + + // NOTE: width and height are expressed as distance, not pixel count! + params[i].width = (uint16)(sortedRectList[i].right - sortedRectList[i].left); + params[i].height = (uint16)(sortedRectList[i].bottom - sortedRectList[i].top); + } + + // go + fAccScreenBlit(fEngineToken, params, count); + + // done + if (fAccReleaseEngine) + fAccReleaseEngine(fEngineToken, &fSyncToken); + + // sync + if (fAccSyncToToken) + fAccSyncToToken(&fSyncToken); + + delete[] params; + } + } +} + +// FillRegion +void +DWindowHWInterface::FillRegion(/*const*/ BRegion& region, const RGBColor& color) +{ + if (fAccFillRect && fAccAcquireEngine) { + if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken, &fEngineToken) >= B_OK) { + + // convert the region + uint32 count; + fill_rect_params* fillParams; + _RegionToRectParams(®ion, &fillParams, &count); + + // go + fAccFillRect(fEngineToken, _NativeColor(color), fillParams, count); + + // done + if (fAccReleaseEngine) + fAccReleaseEngine(fEngineToken, &fSyncToken); + + // sync + if (fAccSyncToToken) + fAccSyncToToken(&fSyncToken); + + delete[] fillParams; + } + } +} + +// InvertRegion +void +DWindowHWInterface::InvertRegion(/*const*/ BRegion& region) +{ + if (fAccInvertRect && fAccAcquireEngine) { + if (fAccAcquireEngine(B_2D_ACCELERATION, 0xff, &fSyncToken, &fEngineToken) >= B_OK) { + + // convert the region + uint32 count; + fill_rect_params* fillParams; + _RegionToRectParams(®ion, &fillParams, &count); + + // go + fAccInvertRect(fEngineToken, fillParams, count); + + // done + if (fAccReleaseEngine) + fAccReleaseEngine(fEngineToken, &fSyncToken); + + // sync + if (fAccSyncToToken) + fAccSyncToToken(&fSyncToken); + + delete[] fillParams; + } else { + fprintf(stderr, "AcquireEngine failed!\n"); + } + } else { + fprintf(stderr, "AccelerantHWInterface::InvertRegion() called, but hook not available!\n"); + } +} + +// FrontBuffer +RenderingBuffer* +DWindowHWInterface::FrontBuffer() const +{ + return fFrontBuffer; +} + +// BackBuffer +RenderingBuffer* +DWindowHWInterface::BackBuffer() const +{ + return NULL; +} + +// IsDoubleBuffered +bool +DWindowHWInterface::IsDoubleBuffered() const +{ + return false; +} + +// Invalidate +status_t +DWindowHWInterface::Invalidate(const BRect& frame) +{ + return HWInterface::Invalidate(frame); +} + +// _RegionToRectParams +void +DWindowHWInterface::_RegionToRectParams(/*const*/ BRegion* region, + fill_rect_params** params, + uint32* count) const +{ + *count = region->CountRects(); + *params = new fill_rect_params[*count]; + + for (uint32 i = 0; i < *count; i++) { + clipping_rect r = region->RectAtInt(i); + (*params)[i].left = (uint16)r.left; + (*params)[i].top = (uint16)r.top; + (*params)[i].right = (uint16)r.right; + (*params)[i].bottom = (uint16)r.bottom; + } +} + +// _NativeColor +uint32 +DWindowHWInterface::_NativeColor(const RGBColor& 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 color.GetColor8(); + + case B_RGB15_BIG: + case B_RGBA15_BIG: + case B_RGB15_LITTLE: + case B_RGBA15_LITTLE: + return color.GetColor15(); + + case B_RGB16_BIG: + case B_RGB16_LITTLE: + return color.GetColor16(); + + case B_RGB32_BIG: + case B_RGBA32_BIG: + case B_RGB32_LITTLE: + case B_RGBA32_LITTLE: { + rgb_color c = color.GetColor32(); + uint32 native = (c.alpha << 24) | + (c.red << 16) | + (c.green << 8) | + (c.blue); + return native; + } + } + return 0; +} diff --git a/src/servers/app/drawing/DWindowHWInterface.h b/src/servers/app/drawing/DWindowHWInterface.h new file mode 100644 index 0000000000..0d48bf4fc1 --- /dev/null +++ b/src/servers/app/drawing/DWindowHWInterface.h @@ -0,0 +1,121 @@ +/* + * Copyright 2005, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Michael Lotz + * Stephan Aßmus + */ +#ifndef D_WINDOW_HW_INTERACE_H +#define D_WINDOW_HW_INTERACE_H + + +#include +#include +#include + +#include "HWInterface.h" + +class DWindowBuffer; +class DWindow; +class UpdateQueue; + + +class DWindowHWInterface : public HWInterface { + public: + DWindowHWInterface(); + virtual ~DWindowHWInterface(); + + virtual status_t Initialize(); + virtual status_t Shutdown(); + + virtual status_t SetMode(const display_mode &mode); + virtual void GetMode(display_mode *mode); + + virtual status_t GetDeviceInfo(accelerant_device_info *info); + virtual status_t GetFrameBufferConfig(frame_buffer_config& config); + + virtual status_t GetModeList(display_mode **mode_list, + uint32 *count); + virtual status_t GetPixelClockLimits(display_mode *mode, + uint32 *low, + uint32 *high); + virtual status_t GetTimingConstraints(display_timing_constraints *dtc); + virtual status_t ProposeMode(display_mode *candidate, + const display_mode *low, + const display_mode *high); + + virtual sem_id RetraceSemaphore(); + virtual status_t WaitForRetrace(bigtime_t timeout = B_INFINITE_TIMEOUT); + + virtual status_t SetDPMSMode(const uint32 &state); + virtual uint32 DPMSMode(); + virtual uint32 DPMSCapabilities(); + + // query for available hardware accleration and perform it + virtual uint32 AvailableHWAcceleration() const; + + virtual void CopyRegion(const clipping_rect* sortedRectList, + uint32 count, + int32 xOffset, int32 yOffset); + virtual void FillRegion(/*const*/ BRegion& region, + const RGBColor& color); + virtual void InvertRegion(/*const*/ BRegion& region); + + // frame buffer access + virtual RenderingBuffer* FrontBuffer() const; + virtual RenderingBuffer* BackBuffer() const; + virtual bool IsDoubleBuffered() const; + + virtual status_t Invalidate(const BRect& frame); + + private: + DWindowBuffer* fFrontBuffer; + + DWindow* fWindow; + + display_mode fDisplayMode; + + // accelerant stuff + int _OpenGraphicsDevice(int deviceNumber); + status_t _OpenAccelerant(int device); + status_t _SetupDefaultHooks(); + + void _RegionToRectParams(/*const*/ BRegion* region, + fill_rect_params** params, + uint32* count) const; + uint32 _NativeColor(const RGBColor& color) const; + + + + int fCardFD; + image_id fAccelerantImage; + GetAccelerantHook fAccelerantHook; + engine_token *fEngineToken; + sync_token fSyncToken; + + // required hooks - guaranteed to be valid + acquire_engine fAccAcquireEngine; + release_engine fAccReleaseEngine; + sync_to_token fAccSyncToToken; + accelerant_mode_count fAccGetModeCount; + get_mode_list fAccGetModeList; + get_frame_buffer_config fAccGetFrameBufferConfig; + set_display_mode fAccSetDisplayMode; + get_display_mode fAccGetDisplayMode; + get_pixel_clock_limits fAccGetPixelClockLimits; + + // optional accelerant hooks + get_timing_constraints fAccGetTimingConstraints; + propose_display_mode fAccProposeDisplayMode; + fill_rectangle fAccFillRect; + invert_rectangle fAccInvertRect; + screen_to_screen_blit fAccScreenBlit; + set_cursor_shape fAccSetCursorShape; + move_cursor fAccMoveCursor; + show_cursor fAccShowCursor; + + BString fCardNameInDevFS; +}; + +#endif // D_WINDOW_HW_INTERACE_H