From 4eb16023d1d16795ea1d39aa69e4ca72c5897ba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Sun, 7 May 2006 18:07:37 +0000 Subject: [PATCH] Marcus' change had a point, though: we now handle the first mode switch differently in that we try really hard to let it succeed. If setting the desired mode failed, we now try almost anything to get a working mode. Since the kernel also knows the VESA mode, maybe we should better ask that one for the current mode, as most drivers probably haven't got B_GET_DISPLAY_MODE implemented in the we're using it. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17355 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../app/drawing/AccelerantHWInterface.cpp | 104 +++++++++++++++--- .../app/drawing/AccelerantHWInterface.h | 2 + 2 files changed, 93 insertions(+), 13 deletions(-) diff --git a/src/servers/app/drawing/AccelerantHWInterface.cpp b/src/servers/app/drawing/AccelerantHWInterface.cpp index 5d9b2e9b6d..e988966cf1 100644 --- a/src/servers/app/drawing/AccelerantHWInterface.cpp +++ b/src/servers/app/drawing/AccelerantHWInterface.cpp @@ -103,6 +103,8 @@ AccelerantHWInterface::AccelerantHWInterface() fBackBuffer(NULL), fFrontBuffer(new (nothrow) AccelerantBuffer()), + fInitialModeSwitch(true), + fRectParams(new (nothrow) fill_rect_params[kDefaultParamsCount]), fRectParamsCount(kDefaultParamsCount), fBlitParams(new (nothrow) blit_params[kDefaultParamsCount]), @@ -359,9 +361,65 @@ AccelerantHWInterface::Shutdown() return B_OK; } -// SetMode + +/*! + This method is used for the initial mode set only - because that one + should really not fail. + Basically we try to set all modes as found in the mode list the driver + returned, but we start with the one that best fits the originally + desired mode. +*/ status_t -AccelerantHWInterface::SetMode(const display_mode &mode) +AccelerantHWInterface::_SetFallbackMode(display_mode& newMode) const +{ + if (fModeList == NULL) + return B_ERROR; + + // At first, we search the closest display mode from the list of + // supported modes - if that fails, we just take one + + int32 bestDiff = 0; + int32 bestIndex = -1; + for (int32 i = 0; i < fModeCount; i++) { + display_mode& mode = fModeList[i]; + + // compute some random equality score + int32 diff = abs(mode.virtual_width - newMode.virtual_width) + + abs(mode.virtual_height - newMode.virtual_height) + + 10 * abs(mode.space - newMode.space); + + if (bestIndex == -1 || diff < bestDiff) { + bestDiff = diff; + bestIndex = i; + } + } + + if (bestIndex < 0) + return B_ERROR; + + newMode = fModeList[bestIndex]; + status_t status = fAccSetDisplayMode(&newMode); + if (status == B_OK) + return B_OK; + + // That failed as well, this looks like a bug in the graphics + // driver, but we have to try to be as forgiving as possible + // here - just take the first mode that fits! + + for (int32 i = 0; i < fModeCount; i++) { + newMode = fModeList[i]; + status = fAccSetDisplayMode(&newMode); + if (status == B_OK) + return B_OK; + } + + // Well, we tried. + return B_ERROR; +} + + +status_t +AccelerantHWInterface::SetMode(const display_mode& mode) { AutoWriteLocker _(this); // TODO: There are places this function can fail, @@ -386,21 +444,41 @@ AccelerantHWInterface::SetMode(const display_mode &mode) display_mode newMode = mode; - if (fAccSetDisplayMode(&newMode) != B_OK) { + status_t status = fAccSetDisplayMode(&newMode); + if (status != B_OK) { ATRACE(("setting display mode failed\n")); - // We just keep the current mode and continue. - // Note, on startup, this may be different from - // what we think is the current display mode - if (fAccGetDisplayMode(&newMode) != B_OK) - return B_ERROR; + if (!fInitialModeSwitch) + return status; + + // If this is the initial mode switch, we try a number of fallback + // modes first, before we have to fail + + status = _SetFallbackMode(newMode); + if (status != B_OK) { + // The driver doesn't allow us the mode switch - this usually + // means we have a driver that doesn't allow mode switches at + // all. + // All we can do now is to ask the driver which mode we can + // use - this is always necessary for VESA mode, for example. + if (fAccGetDisplayMode(&newMode) != B_OK) + return B_ERROR; + + // TODO: if the mode switch before fails as well, we must forbid + // any uses of this class! + status = B_OK; + } } fDisplayMode = newMode; + fInitialModeSwitch = false; // update frontbuffer fFrontBuffer->SetDisplayMode(fDisplayMode); - if (_UpdateFrameBufferConfig() != B_OK) + if (_UpdateFrameBufferConfig() != B_OK) { + // TODO: if this fails, we're basically toasted - we need to handle this + // differently to crashing later on! return B_ERROR; + } // Update the frame buffer used by the on-screen KDL #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST @@ -435,11 +513,11 @@ AccelerantHWInterface::SetMode(const display_mode &mode) fBackBuffer = new(nothrow) MallocBuffer(fDisplayMode.virtual_width, fDisplayMode.virtual_height); - status_t ret = fBackBuffer ? fBackBuffer->InitCheck() : B_NO_MEMORY; - if (ret < B_OK) { + status = fBackBuffer ? fBackBuffer->InitCheck() : B_NO_MEMORY; + if (status < B_OK) { delete fBackBuffer; fBackBuffer = NULL; - return ret; + return status; } // clear out backbuffer, alpha is 255 this way memset(fBackBuffer->Bits(), 255, fBackBuffer->BitsLength()); @@ -456,7 +534,7 @@ AccelerantHWInterface::SetMode(const display_mode &mode) fAccScreenBlit = (screen_to_screen_blit)fAccelerantHook(B_SCREEN_TO_SCREEN_BLIT, (void *)&fDisplayMode); - return B_OK; + return status; } diff --git a/src/servers/app/drawing/AccelerantHWInterface.h b/src/servers/app/drawing/AccelerantHWInterface.h index e3c49ad9cb..0a0df04e96 100644 --- a/src/servers/app/drawing/AccelerantHWInterface.h +++ b/src/servers/app/drawing/AccelerantHWInterface.h @@ -103,6 +103,7 @@ private: void _RegionToRectParams(/*const*/ BRegion* region, uint32* count) const; uint32 _NativeColor(const RGBColor& color) const; + status_t _SetFallbackMode(display_mode& mode) const; void _SetSystemPalette(); int fCardFD; @@ -156,6 +157,7 @@ private: AccelerantBuffer* fFrontBuffer; display_mode fDisplayMode; + bool fInitialModeSwitch; mutable fill_rect_params* fRectParams; mutable uint32 fRectParamsCount;