From f6be811473446b2676a4907b23e12e548eaf77ff Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Mon, 23 Mar 2026 12:16:11 -0400 Subject: [PATCH] BDirectWindow: Clone the framebuffer from app_server, if necessary. This paves the way for accelerants to map the framebuffer in user memory, not kernel memory. It uses the ServerMemoryAllocator in order to avoid mapping the framebuffer multiple times in client applications. While at it, clean up some names. Tested with DirectWindowStars and GLTeapot, both work. Change-Id: I4e0c003fae99891044af0a5e6e1d6a4506da6430 Reviewed-on: https://review.haiku-os.org/c/haiku/+/10571 Tested-by: Commit checker robot Reviewed-by: waddlesplash --- headers/os/game/DirectWindow.h | 15 +++++----- src/kits/game/DirectWindow.cpp | 43 +++++++++++++++++++++------- src/servers/app/DirectWindowInfo.cpp | 27 +++++++++++++---- src/servers/app/DirectWindowInfo.h | 2 +- src/servers/app/Jamfile | 3 ++ 5 files changed, 66 insertions(+), 24 deletions(-) diff --git a/headers/os/game/DirectWindow.h b/headers/os/game/DirectWindow.h index 01ab10a3ce..19241677df 100644 --- a/headers/os/game/DirectWindow.h +++ b/headers/os/game/DirectWindow.h @@ -35,15 +35,14 @@ typedef struct { direct_buffer_state buffer_state; direct_driver_state driver_state; void *bits; - void *pci_bits; + addr_t _reserved; // was pci_bits int32 bytes_per_row; uint32 bits_per_pixel; color_space pixel_format; buffer_layout layout; buffer_orientation orientation; - uint32 _reserved[9]; - uint32 _dd_type_; - uint32 _dd_token_; + area_id bits_area; + uint32 _reserved1[10]; uint32 clip_list_count; clipping_rect window_bounds; clipping_rect clip_bounds; @@ -141,7 +140,7 @@ private: bool fConnectionEnable; bool fIsFullScreen; bool _unused; - bool fInDirectConnect; + bool fInDirectConnected; int32 fDirectLock; sem_id fDirectSem; uint32 fDirectLockCount; @@ -151,12 +150,12 @@ private: sem_id fDisableSemAck; uint32 fInitStatus; - uint32 fInfoAreaSize; uint32 _reserved[2]; - area_id fClonedClippingArea; - area_id fSourceClippingArea; + area_id fSourceDirectArea; + area_id fClonedDirectArea; + area_id fSourceBitsArea; thread_id fDirectDaemonId; direct_buffer_info* fBufferDesc; diff --git a/src/kits/game/DirectWindow.cpp b/src/kits/game/DirectWindow.cpp index 262bfb4cd3..a9053d1952 100644 --- a/src/kits/game/DirectWindow.cpp +++ b/src/kits/game/DirectWindow.cpp @@ -17,8 +17,10 @@ #include #include +#include #include #include +#include //#define DEBUG 1 @@ -128,7 +130,6 @@ print_direct_buffer_info(const direct_buffer_info &info) # if DEBUG > 1 OUTPUT("bits: %p\n", info.bits); - OUTPUT("pci_bits: %p\n", info.pci_bits); OUTPUT("bytes_per_row: %ld\n", info.bytes_per_row); OUTPUT("bits_per_pixel: %lu\n", info.bits_per_pixel); OUTPUT("pixel_format: %d\n", info.pixel_format); @@ -366,7 +367,7 @@ BDirectWindow::GetClippingRegion(BRegion* region, BPoint* origin) const if (IsLocked() || !_LockDirect()) return B_ERROR; - if (!fInDirectConnect) { + if (!fInDirectConnected) { _UnlockDirect(); return B_ERROR; } @@ -486,9 +487,29 @@ BDirectWindow::_DirectDaemon() == B_DIRECT_START) fConnectionEnable = true; - fInDirectConnect = true; + if (fBufferDesc->bits == NULL) { + // (re-)clone the bits area + BPrivate::AppServerLink linkLocker; + // protects ServerAllocator + BPrivate::ServerMemoryAllocator* allocator + = BApplication::Private::ServerAllocator(); + allocator->RemoveArea(fSourceBitsArea); + area_id localArea; + uint8* bits; + status_t status = allocator->AddArea(fBufferDesc->bits_area, + localArea, bits, (size_t)-1); + if (status != B_OK) { + _UnlockDirect(); + return -1; + } + + fBufferDesc->bits = (void*)bits; + fSourceBitsArea = fBufferDesc->bits_area; + } + + fInDirectConnected = true; DirectConnected(fBufferDesc); - fInDirectConnect = false; + fInDirectConnected = false; if ((fBufferDesc->buffer_state & B_DIRECT_MODE_MASK) == B_DIRECT_STOP) @@ -559,7 +580,7 @@ BDirectWindow::_InitData() { fConnectionEnable = false; fIsFullScreen = false; - fInDirectConnect = false; + fInDirectConnected = false; fInitStatus = 0; @@ -583,14 +604,16 @@ BDirectWindow::_InitData() fInitStatus |= DW_STATUS_SEM_CREATED; #endif - fSourceClippingArea = syncData.area; + fSourceDirectArea = syncData.area; fDisableSem = syncData.disable_sem; fDisableSemAck = syncData.disable_sem_ack; - fClonedClippingArea = clone_area("cloned direct area", (void**)&fBufferDesc, - B_ANY_ADDRESS, B_READ_AREA, fSourceClippingArea); + fClonedDirectArea = clone_area("cloned direct area", (void**)&fBufferDesc, + B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, fSourceDirectArea); - if (fClonedClippingArea > 0) { + fSourceBitsArea = -1; + + if (fClonedDirectArea > 0) { fInitStatus |= DW_STATUS_AREA_CLONED; fDirectDaemonId = spawn_thread(_daemon_thread, "direct daemon", @@ -633,7 +656,7 @@ BDirectWindow::_DisposeData() #endif if (fInitStatus & DW_STATUS_AREA_CLONED) - delete_area(fClonedClippingArea); + delete_area(fClonedDirectArea); } diff --git a/src/servers/app/DirectWindowInfo.cpp b/src/servers/app/DirectWindowInfo.cpp index aadbe66696..88c2ada8b9 100644 --- a/src/servers/app/DirectWindowInfo.cpp +++ b/src/servers/app/DirectWindowInfo.cpp @@ -15,6 +15,7 @@ #include #include +#include #include "RenderingBuffer.h" #include "clipping.h" @@ -35,6 +36,7 @@ DirectWindowInfo::DirectWindowInfo() memset(fBufferInfo, 0, DIRECT_BUFFER_INFO_AREA_SIZE); fBufferInfo->buffer_state = B_DIRECT_STOP; + fBufferInfo->bits_area = -1; fSem = create_sem(0, "direct sem"); fAcknowledgeSem = create_sem(0, "direct sem ack"); @@ -92,9 +94,21 @@ DirectWindowInfo::SetState(direct_buffer_state bufferState, if ((int)driverState != -1) fBufferInfo->driver_state = driverState; - if ((bufferState & B_DIRECT_MODE_MASK) != B_DIRECT_STOP) { - fBufferInfo->bits = buffer->Bits(); - fBufferInfo->pci_bits = NULL; // TODO + if ((bufferState & B_BUFFER_RESET) != 0 || fBufferInfo->bits_area < 0) { + void* bits = buffer->Bits(); + if (IS_USER_ADDRESS(bits)) { + fBufferInfo->bits = NULL; + + area_id area = area_for(bits); + fBufferInfo->bits_area = area; + + // make sure the area is cloneable + set_area_protection(area, B_READ_AREA | B_WRITE_AREA | B_CLONEABLE_AREA); + } else { + // framebuffer is in kernel address space + // TODO: update all drivers and then drop this case! + fBufferInfo->bits = bits; + } fBufferInfo->bytes_per_row = buffer->BytesPerRow(); switch (buffer->ColorSpace()) { @@ -137,6 +151,9 @@ DirectWindowInfo::SetState(direct_buffer_state bufferState, fBufferInfo->layout = B_BUFFER_NONINTERLEAVED; fBufferInfo->orientation = B_BUFFER_TOP_TO_BOTTOM; // TODO + } + + if ((bufferState & B_DIRECT_MODE_MASK) != B_DIRECT_STOP) { fBufferInfo->window_bounds = to_clipping_rect(windowFrame); const int32 kMaxClipRectsCount = (DIRECT_BUFFER_INFO_AREA_SIZE @@ -150,7 +167,7 @@ DirectWindowInfo::SetState(direct_buffer_state bufferState, fBufferInfo->clip_list[i] = clipRegion.RectAtInt(i); } - return _SyncronizeWithClient(); + return _SynchronizeWithClient(); } @@ -171,7 +188,7 @@ DirectWindowInfo::DisableFullScreen() status_t -DirectWindowInfo::_SyncronizeWithClient() +DirectWindowInfo::_SynchronizeWithClient() { // Releasing this semaphore causes the client to call // BDirectWindow::DirectConnected() diff --git a/src/servers/app/DirectWindowInfo.h b/src/servers/app/DirectWindowInfo.h index 4a26ac98d0..5aa5a46d30 100644 --- a/src/servers/app/DirectWindowInfo.h +++ b/src/servers/app/DirectWindowInfo.h @@ -40,7 +40,7 @@ public: window_feel OriginalFeel() const { return fOriginalFeel; } private: - status_t _SyncronizeWithClient(); + status_t _SynchronizeWithClient(); direct_buffer_info* fBufferInfo; sem_id fSem; diff --git a/src/servers/app/Jamfile b/src/servers/app/Jamfile index 408da96b27..9ecb85e7dc 100644 --- a/src/servers/app/Jamfile +++ b/src/servers/app/Jamfile @@ -3,6 +3,9 @@ SubDir HAIKU_TOP src servers app ; UseLibraryHeaders agg ; UsePrivateHeaders app graphics input interface shared storage support ; +UsePrivateKernelHeaders ; + # TODO: Remove! (only needed by DirectWindowInfo.cpp) + UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing ] ; UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing Painter ] ; UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing Painter drawing_modes ] ;