From 9fe35223cf4eb9714865152d62e8efc36b327fef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Thu, 27 Aug 2009 12:10:59 +0000 Subject: [PATCH] * BWindowScreens had no sychronization mechanism whatsoever - since the workspace activation message was asynchronous, whether or not the BWindowScreen stopped drawing in time was pure luck (this also caused crashes with the VESA driver, as that one unmaps its frame buffer during mode switch). Introduced a new AS_DIRECT_SCREEN_LOCK protocol for this. * In the long term, we should let BWindowScreen use the same mechanism as BDirectWindows, though. * Removed superfluous locking in BDirectWindow::_InitData(). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32746 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/game/WindowScreen.h | 6 +- headers/private/app/ServerProtocol.h | 3 +- src/kits/game/DirectWindow.cpp | 12 +-- src/kits/game/WindowScreen.cpp | 144 +++++++++++++++------------ src/kits/interface/InterfaceDefs.cpp | 3 +- src/servers/app/Desktop.cpp | 42 ++++++++ src/servers/app/Desktop.h | 5 + src/servers/app/ServerApp.cpp | 20 ++++ 8 files changed, 158 insertions(+), 77 deletions(-) diff --git a/headers/os/game/WindowScreen.h b/headers/os/game/WindowScreen.h index b005bdee64..662b0a22b1 100644 --- a/headers/os/game/WindowScreen.h +++ b/headers/os/game/WindowScreen.h @@ -72,7 +72,7 @@ class BWindowScreen : public BWindow { virtual void _ReservedWindowScreen3(); virtual void _ReservedWindowScreen4(); - // not implemented: + // not implemented: BWindowScreen(); BWindowScreen(BWindowScreen& other); BWindowScreen &operator=(BWindowScreen& other); @@ -80,6 +80,7 @@ class BWindowScreen : public BWindow { status_t _InitData(uint32 space, uint32 attributes); void _DisposeData(); + status_t _LockScreen(bool lock); status_t _Activate(); status_t _Deactivate(); @@ -103,7 +104,6 @@ class BWindowScreen : public BWindow { display_mode* fOriginalDisplayMode; display_mode* fDisplayMode; - sem_id fActivateSem; sem_id fDebugSem; image_id fAddonImage; uint32 fAttributes; @@ -126,7 +126,7 @@ class BWindowScreen : public BWindow { GetAccelerantHook fGetAccelerantHook; wait_engine_idle fWaitEngineIdle; - uint32 _reserved[162]; + uint32 _reserved[163]; }; #endif // _WINDOW_SCREEN_H diff --git a/headers/private/app/ServerProtocol.h b/headers/private/app/ServerProtocol.h index 8e16b6ae09..e630df167e 100644 --- a/headers/private/app/ServerProtocol.h +++ b/headers/private/app/ServerProtocol.h @@ -318,9 +318,10 @@ enum { AS_VIEW_SET_PATTERN, AS_SET_CURRENT_VIEW, - // BDirectWindow codes + // BDirectWindow/BWindowScreen codes AS_DIRECT_WINDOW_GET_SYNC_DATA, AS_DIRECT_WINDOW_SET_FULLSCREEN, + AS_DIRECT_SCREEN_LOCK, AS_LAST_CODE }; diff --git a/src/kits/game/DirectWindow.cpp b/src/kits/game/DirectWindow.cpp index 8109030e0e..701b9bef20 100644 --- a/src/kits/game/DirectWindow.cpp +++ b/src/kits/game/DirectWindow.cpp @@ -564,14 +564,12 @@ BDirectWindow::_InitData() status_t status = B_ERROR; struct direct_window_sync_data syncData; - if (Lock()) { - fLink->StartMessage(AS_DIRECT_WINDOW_GET_SYNC_DATA); - if (fLink->FlushWithReply(status) == B_OK && status == B_OK) - fLink->Read(&syncData); - Unlock(); - } - if (status < B_OK) + fLink->StartMessage(AS_DIRECT_WINDOW_GET_SYNC_DATA); + if (fLink->FlushWithReply(status) == B_OK && status == B_OK) + fLink->Read(&syncData); + + if (status != B_OK) return; #if DW_NEEDS_LOCKING diff --git a/src/kits/game/WindowScreen.cpp b/src/kits/game/WindowScreen.cpp index 9edd3bea55..b6ebed418a 100644 --- a/src/kits/game/WindowScreen.cpp +++ b/src/kits/game/WindowScreen.cpp @@ -78,12 +78,13 @@ blit(int32 sx, int32 sy, int32 dx, int32 dy, int32 width, int32 height) return 0; } + // TODO: This function seems not to be exported through CardHookAt(). // At least, nothing I've tried uses it. -/* +#if 0 static int32 -transparent_blit(int32 sx, int32 sy, int32 dx, int32 dy, - int32 width, int32 height, uint32 transparent_color) +transparent_blit(int32 sx, int32 sy, int32 dx, int32 dy, int32 width, + int32 height, uint32 transparent_color) { blit_params param; param.src_left = sx; @@ -98,10 +99,12 @@ transparent_blit(int32 sx, int32 sy, int32 dx, int32 dy, sReleaseEngineHook(sEngineToken, 0); return 0; } -*/ +#endif + static int32 -scaled_filtered_blit(int32 sx, int32 sy, int32 sw, int32 sh, int32 dx, int32 dy, int32 dw, int32 dh) +scaled_filtered_blit(int32 sx, int32 sy, int32 sw, int32 sh, int32 dx, int32 dy, + int32 dw, int32 dh) { scaled_blit_params param; param.src_left = sx; @@ -185,16 +188,17 @@ set_mouse_position(int32 x, int32 y) // #pragma mark - -BWindowScreen::BWindowScreen(const char *title, uint32 space, - status_t *error, bool debug_enable) - : BWindow(BScreen().Frame(), title, B_NO_BORDER_WINDOW_LOOK, +BWindowScreen::BWindowScreen(const char *title, uint32 space, status_t *error, + bool debugEnable) + : + BWindow(BScreen().Frame(), title, B_NO_BORDER_WINDOW_LOOK, kWindowScreenFeel, kWindowScreenFlag | B_NOT_MINIMIZABLE | B_NOT_CLOSABLE | B_NOT_ZOOMABLE | B_NOT_MOVABLE | B_NOT_RESIZABLE, B_CURRENT_WORKSPACE) { CALLED(); uint32 attributes = 0; - if (debug_enable) + if (debugEnable) attributes |= B_ENABLE_DEBUGGER; status_t status = _InitData(space, attributes); @@ -205,7 +209,8 @@ BWindowScreen::BWindowScreen(const char *title, uint32 space, BWindowScreen::BWindowScreen(const char *title, uint32 space, uint32 attributes, status_t *error) - : BWindow(BScreen().Frame(), title, B_NO_BORDER_WINDOW_LOOK, + : + BWindow(BScreen().Frame(), title, B_NO_BORDER_WINDOW_LOOK, kWindowScreenFeel, kWindowScreenFlag | B_NOT_MINIMIZABLE | B_NOT_CLOSABLE | B_NOT_ZOOMABLE | B_NOT_MOVABLE | B_NOT_RESIZABLE, B_CURRENT_WORKSPACE) @@ -265,10 +270,11 @@ BWindowScreen::WindowActivated(bool active) void -BWindowScreen::WorkspaceActivated(int32 ws, bool state) +BWindowScreen::WorkspaceActivated(int32 workspace, bool state) { CALLED(); fWorkState = state; + if (state) { if (fLockState == 0 && fWindowState) { _Activate(); @@ -283,7 +289,7 @@ BWindowScreen::WorkspaceActivated(int32 ws, bool state) void -BWindowScreen::ScreenChanged(BRect screen_size, color_space depth) +BWindowScreen::ScreenChanged(BRect screenFrame, color_space depth) { // Implemented in subclasses } @@ -305,11 +311,6 @@ BWindowScreen::Show() CALLED(); BWindow::Show(); - - if (!fActivateState) { - release_sem(fActivateSem); - fActivateState = true; - } } @@ -343,8 +344,8 @@ BWindowScreen::SetColorList(rgb_color *list, int32 firstIndex, int32 lastIndex) } if (fAddonImage >= 0) { - set_indexed_colors setIndexedColors = - (set_indexed_colors)fGetAccelerantHook(B_SET_INDEXED_COLORS, + set_indexed_colors setIndexedColors + = (set_indexed_colors)fGetAccelerantHook(B_SET_INDEXED_COLORS, NULL); if (setIndexedColors != NULL) { setIndexedColors(255, 0, @@ -511,7 +512,8 @@ BWindowScreen::RegisterThread(thread_id thread) if (status < B_OK) return; - void *newDebugList = realloc(fDebugThreads, (fDebugThreadCount + 1) * sizeof(thread_id)); + void *newDebugList = realloc(fDebugThreads, + (fDebugThreadCount + 1) * sizeof(thread_id)); if (newDebugList != NULL) { fDebugThreads = (thread_id *)newDebugList; fDebugThreads[fDebugThreadCount] = thread; @@ -534,8 +536,8 @@ BWindowScreen::Suspend(char* label) CALLED(); if (fDebugState) { fprintf(stderr, "## Debugger(\"%s\").", label); - fprintf(stderr, " Press Alt-F%ld or Cmd-F%ld to resume.\n", fWorkspaceIndex + 1, - fWorkspaceIndex + 1); + fprintf(stderr, " Press Alt-F%ld or Cmd-F%ld to resume.\n", + fWorkspaceIndex + 1, fWorkspaceIndex + 1); if (IsLocked()) Unlock(); @@ -564,14 +566,6 @@ void BWindowScreen::_ReservedWindowScreen3() {} void BWindowScreen::_ReservedWindowScreen4() {} -/* unimplemented for protection of the user: - * - * BWindowScreen::BWindowScreen() - * BWindowScreen::BWindowScreen(BWindowScreen &) - * BWindowScreen &BWindowScreen::operator=(BWindowScreen &) - */ - - status_t BWindowScreen::_InitData(uint32 space, uint32 attributes) { @@ -583,7 +577,8 @@ BWindowScreen::_InitData(uint32 space, uint32 attributes) fDebugFirst = true; fAttributes = attributes; - // TODO: not really used right now, but should probably be known by the app_server + // TODO: not really used right now, but should probably be known by + // the app_server fWorkspaceIndex = fDebugWorkspace = current_workspace(); fLockState = 0; @@ -593,10 +588,9 @@ BWindowScreen::_InitData(uint32 space, uint32 attributes) fDisplayMode = NULL; fModeList = NULL; fModeCount = 0; - fActivateSem = -1; fDebugSem = -1; - fActivateState = 0; - fWorkState = 0; + fActivateState = false; + fWorkState = false; status_t status = B_ERROR; try { @@ -620,20 +614,15 @@ BWindowScreen::_InitData(uint32 space, uint32 attributes) if (status < B_OK) throw status; - fActivateSem = create_sem(0, "WindowScreen start lock"); - if (fActivateSem < B_OK) - throw (status_t)fActivateSem; - fDebugSem = create_sem(1, "WindowScreen debug sem"); if (fDebugSem < B_OK) throw (status_t)fDebugSem; memcpy(fPalette, screen.ColorMap()->color_list, sizeof(fPalette)); - fActivateState = 0; - fWorkState = 1; + fActivateState = false; + fWorkState = true; status = B_OK; - } catch (std::bad_alloc) { status = B_NO_MEMORY; } catch (status_t error) { @@ -642,7 +631,7 @@ BWindowScreen::_InitData(uint32 space, uint32 attributes) status = B_ERROR; } - if (status < B_OK) + if (status != B_OK) _DisposeData(); return status; @@ -659,8 +648,6 @@ BWindowScreen::_DisposeData() fAddonImage = -1; } - delete_sem(fActivateSem); - fActivateSem = -1; delete_sem(fDebugSem); fDebugSem = -1; @@ -679,6 +666,25 @@ BWindowScreen::_DisposeData() } +status_t +BWindowScreen::_LockScreen(bool lock) +{ + if (fActivateState == lock) + return B_OK; + + // TODO: the BWindowScreen should use the same mechanism as BDirectWindows! + BPrivate::AppServerLink link; + + link.StartMessage(AS_DIRECT_SCREEN_LOCK); + link.Attach(lock); + + status_t status = B_ERROR; + if (link.FlushWithReply(status) == B_OK && status == B_OK) + fActivateState = lock; + + return status; +} + status_t BWindowScreen::_Activate() @@ -693,11 +699,8 @@ BWindowScreen::_Activate() return status; if (!fActivateState) { - do { - status = acquire_sem(fActivateSem); - } while (status == B_INTERRUPTED); - - if (status < B_OK) + status = _LockScreen(true); + if (status != B_OK) return status; } @@ -728,12 +731,15 @@ BWindowScreen::_Deactivate() ScreenConnected(false); if (fActivateState) { + status_t status = _LockScreen(false); + if (status != B_OK) + return status; + BScreen screen(this); SetColorList((rgb_color *)screen.ColorMap()->color_list); } _AssertDisplayMode(fOriginalDisplayMode); - _ResetAccelerantHooks(); be_app->ShowCursor(); @@ -754,13 +760,20 @@ BWindowScreen::_SetupAccelerantHooks() _ResetAccelerantHooks(); if (status == B_OK) { - sWaitIdleHook = fWaitEngineIdle = (wait_engine_idle)fGetAccelerantHook(B_WAIT_ENGINE_IDLE, NULL); - sReleaseEngineHook = (release_engine)fGetAccelerantHook(B_RELEASE_ENGINE, NULL); - sAcquireEngineHook = (acquire_engine)fGetAccelerantHook(B_ACQUIRE_ENGINE, NULL); - sFillRectHook = (fill_rectangle)fGetAccelerantHook(B_FILL_RECTANGLE, NULL); - sBlitRectHook = (screen_to_screen_blit)fGetAccelerantHook(B_SCREEN_TO_SCREEN_BLIT, NULL); - sTransparentBlitHook = (screen_to_screen_transparent_blit)fGetAccelerantHook(B_SCREEN_TO_SCREEN_TRANSPARENT_BLIT, NULL); - sScaledFilteredBlitHook = (screen_to_screen_scaled_filtered_blit)fGetAccelerantHook(B_SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT, NULL); + sWaitIdleHook = fWaitEngineIdle = (wait_engine_idle) + fGetAccelerantHook(B_WAIT_ENGINE_IDLE, NULL); + sReleaseEngineHook + = (release_engine)fGetAccelerantHook(B_RELEASE_ENGINE, NULL); + sAcquireEngineHook + = (acquire_engine)fGetAccelerantHook(B_ACQUIRE_ENGINE, NULL); + sFillRectHook + = (fill_rectangle)fGetAccelerantHook(B_FILL_RECTANGLE, NULL); + sBlitRectHook = (screen_to_screen_blit) + fGetAccelerantHook(B_SCREEN_TO_SCREEN_BLIT, NULL); + sTransparentBlitHook = (screen_to_screen_transparent_blit) + fGetAccelerantHook(B_SCREEN_TO_SCREEN_TRANSPARENT_BLIT, NULL); + sScaledFilteredBlitHook = (screen_to_screen_scaled_filtered_blit) + fGetAccelerantHook(B_SCREEN_TO_SCREEN_SCALED_FILTERED_BLIT, NULL); if (fWaitEngineIdle) fWaitEngineIdle(); @@ -869,7 +882,7 @@ BWindowScreen::_Suspend() status = acquire_sem(fDebugSem); } while (status == B_INTERRUPTED); - if (status < B_OK) + if (status != B_OK) return; // Suspend all the registered threads @@ -894,7 +907,8 @@ BWindowScreen::_Resume() graphics_card_info *info = CardInfo(); // Copy the content of the debug_buffer back into the frame buffer. - memcpy(info->frame_buffer, fDebugFrameBuffer, info->bytes_per_row * info->height); + memcpy(info->frame_buffer, fDebugFrameBuffer, + info->bytes_per_row * info->height); free(fDebugFrameBuffer); fDebugFrameBuffer = NULL; @@ -918,7 +932,8 @@ BWindowScreen::_GetModeFromSpace(uint32 space, display_mode *dmode) return B_BAD_VALUE; for (uint32 i = 0; i < fModeCount; i++) { - if (fModeList[i].space == colorSpace && fModeList[i].virtual_width == width + if (fModeList[i].space == colorSpace + && fModeList[i].virtual_width == width && fModeList[i].virtual_height == height) { memcpy(dmode, &fModeList[i], sizeof(display_mode)); return B_OK; @@ -1004,7 +1019,7 @@ BWindowScreen::_AssertDisplayMode(display_mode* displayMode) display_mode currentMode; status_t status = screen.GetMode(¤tMode); - if (status < B_OK) + if (status != B_OK) return status; if (currentMode.virtual_height != displayMode->virtual_height @@ -1012,8 +1027,9 @@ BWindowScreen::_AssertDisplayMode(display_mode* displayMode) || currentMode.space != displayMode->space || currentMode.flags != displayMode->flags) { status = screen.SetMode(displayMode); - if (status < B_OK) { - fprintf(stderr, "AssertDisplayMode: Setting mode failed: %s\n", strerror(status)); + if (status != B_OK) { + fprintf(stderr, "AssertDisplayMode: Setting mode failed: %s\n", + strerror(status)); return status; } @@ -1021,7 +1037,7 @@ BWindowScreen::_AssertDisplayMode(display_mode* displayMode) } status = _GetCardInfo(); - if (status < B_OK) + if (status != B_OK) return status; fFrameBufferInfo.bits_per_pixel = fCardInfo.bits_per_pixel; diff --git a/src/kits/interface/InterfaceDefs.cpp b/src/kits/interface/InterfaceDefs.cpp index b74b1d8c90..88895d49f5 100644 --- a/src/kits/interface/InterfaceDefs.cpp +++ b/src/kits/interface/InterfaceDefs.cpp @@ -319,7 +319,6 @@ set_is_subpixel_ordering_regular(bool subpixelOrdering) status_t get_is_subpixel_ordering_regular(bool* subpixelOrdering) { - BPrivate::AppServerLink link; link.StartMessage(AS_GET_SUBPIXEL_ORDERING); @@ -984,7 +983,7 @@ _init_interface_kit_() status = get_menu_info(&BMenu::sMenuInfo); if (status != B_OK) return status; - + general_info.background_color = ui_color(B_PANEL_BACKGROUND_COLOR); general_info.mark_color.set_to(0, 0, 0); general_info.highlight_color = ui_color(B_CONTROL_HIGHLIGHT_COLOR); diff --git a/src/servers/app/Desktop.cpp b/src/servers/app/Desktop.cpp index c7c778ae02..646ea07c20 100644 --- a/src/servers/app/Desktop.cpp +++ b/src/servers/app/Desktop.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -298,6 +299,8 @@ Desktop::Desktop(uid_t userID) fApplicationsLock("application list"), fShutdownSemaphore(-1), fScreenLock("screen lock"), + fDirectScreenLock("direct screen lock"), + fDirectScreenTeam(-1), fCurrentWorkspace(0), fPreviousWorkspace(0), fAllWindows(kAllWindowList), @@ -672,6 +675,33 @@ Desktop::RevertScreenModes(uint32 workspaces) } +status_t +Desktop::LockDirectScreen(team_id team) +{ + // TODO: BWindowScreens should use the same mechanism as BDirectWindow, + // which would make this method superfluous. + + status_t status = fDirectScreenLock.LockWithTimeout(1000000L); + if (status == B_OK) + fDirectScreenTeam = team; + + return status; +} + + +status_t +Desktop::UnlockDirectScreen(team_id team) +{ + if (fDirectScreenTeam == team) { + fDirectScreenLock.Unlock(); + fDirectScreenTeam = -1; + return B_OK; + } + + return B_PERMISSION_DENIED; +} + + // #pragma mark - Workspaces methods @@ -2946,6 +2976,18 @@ Desktop::_SetCurrentWorkspaceConfiguration() { ASSERT_MULTI_WRITE_LOCKED(fWindowLock); + status_t status = fDirectScreenLock.LockWithTimeout(1000000L); + if (status != B_OK) { + // The application having the direct screen lock didn't give it up in + // time, make it crash + syslog(LOG_ERR, "Team %ld did not give up its direct screen lock.\n", + fDirectScreenTeam); + + debug_thread(fDirectScreenTeam); + fDirectScreenTeam = -1; + } else + fDirectScreenLock.Unlock(); + AutoWriteLocker _(fScreenLock); uint32 changedScreens; diff --git a/src/servers/app/Desktop.h b/src/servers/app/Desktop.h index 94b6871427..eea2414696 100644 --- a/src/servers/app/Desktop.h +++ b/src/servers/app/Desktop.h @@ -127,6 +127,9 @@ public: MultiLocker& ScreenLocker() { return fScreenLock; } + status_t LockDirectScreen(team_id team); + status_t UnlockDirectScreen(team_id team); + const ::VirtualScreen& VirtualScreen() const { return fVirtualScreen; } DrawingEngine* GetDrawingEngine() const @@ -309,6 +312,8 @@ private: ::Workspace::Private fWorkspaces[kMaxWorkspaces]; MultiLocker fScreenLock; + BLocker fDirectScreenLock; + team_id fDirectScreenTeam; int32 fCurrentWorkspace; int32 fPreviousWorkspace; diff --git a/src/servers/app/ServerApp.cpp b/src/servers/app/ServerApp.cpp index f90370a70d..45ae62b065 100644 --- a/src/servers/app/ServerApp.cpp +++ b/src/servers/app/ServerApp.cpp @@ -2735,6 +2735,26 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) break; } + // BWindowScreen communication + + case AS_DIRECT_SCREEN_LOCK: + { + bool lock; + link.Read(&lock); + + status_t status; + if (lock) + status = fDesktop->LockDirectScreen(ClientTeam()); + else + status = fDesktop->UnlockDirectScreen(ClientTeam()); + + fLink.StartMessage(status); + fLink.Flush(); + break; + } + + // Hinting and aliasing + case AS_SET_SUBPIXEL_ANTIALIASING: { bool subpix;