From 637a7804b560c5f8c72a4b18eddc279f9c1377ae Mon Sep 17 00:00:00 2001 From: Onek8 Date: Thu, 23 Jul 2026 23:17:24 -0700 Subject: [PATCH] Fix viewport --- Sources/viewport_server.cpp | 112 +++++++++++++++++++++++++----------- 1 file changed, 77 insertions(+), 35 deletions(-) diff --git a/Sources/viewport_server.cpp b/Sources/viewport_server.cpp index d77cfac..085b38b 100644 --- a/Sources/viewport_server.cpp +++ b/Sources/viewport_server.cpp @@ -275,6 +275,11 @@ bool viewport_server_init(const char* shmem_name, int width, int height) { g_viewport_state.initialized = true; g_viewport_state.frame_count = 0; +#ifdef KINC_DIRECT3D11 + // disable vsync so the GPU queue flushes + dx_ctx.windows[0].vsync = 0; +#endif + kinc_log(KINC_LOG_LEVEL_INFO, "Viewport server initialized: %dx%d, shmem=%s", width, height, g_viewport_state.shmem_name); @@ -282,8 +287,10 @@ bool viewport_server_init(const char* shmem_name, int width, int height) { } #ifdef KINC_DIRECT3D11 -static ID3D11Texture2D* g_stagingTexture = NULL; +static ID3D11Texture2D* g_stagingTextures[2] = {NULL, NULL}; static int g_stagingWidth = 0, g_stagingHeight = 0; +static int g_stagingWriteIdx = 0; +static bool g_stagingHasData[2] = {false, false}; #endif void viewport_server_shutdown(void) { @@ -292,12 +299,16 @@ void viewport_server_shutdown(void) { } #ifdef KINC_DIRECT3D11 - if (g_stagingTexture) { - g_stagingTexture->Release(); - g_stagingTexture = NULL; - g_stagingWidth = 0; - g_stagingHeight = 0; + for (int i = 0; i < 2; i++) { + if (g_stagingTextures[i]) { + g_stagingTextures[i]->Release(); + g_stagingTextures[i] = NULL; + g_stagingHasData[i] = false; + } } + g_stagingWidth = 0; + g_stagingHeight = 0; + g_stagingWriteIdx = 0; #endif #if !defined(KINC_DIRECT3D11) && !defined(KINC_OPENGL) @@ -347,12 +358,19 @@ void viewport_server_end_frame(void) { SharedFramebufferHeader* header = (SharedFramebufferHeader*)g_viewport_state.shmem_ptr; + // Drop-frame guard so that if blender hasnt consumed the previous frame it skip writeback + if (header->ready_flag == 1) { + g_viewport_state.frame_count++; + return; + } + header->width = g_viewport_state.width; header->height = g_viewport_state.height; size_t pixel_size = (size_t)g_viewport_state.width * g_viewport_state.height * 4; uint8_t* pixels = g_viewport_state.pixel_buffer; uint8_t* pixel_dest = (uint8_t*)g_viewport_state.shmem_ptr + VIEWPORT_HEADER_SIZE; + bool pixels_written = false; #ifdef KINC_DIRECT3D11 // Direct3D11 - read from backbuffer BEFORE swap_buffers @@ -378,10 +396,20 @@ void viewport_server_end_frame(void) { header->height = captureHeight; pixel_size = (size_t)captureWidth * captureHeight * 4; - // same dimensions between source and destination - if (!g_stagingTexture || g_stagingWidth != bbWidth || g_stagingHeight != bbHeight) { - if (g_stagingTexture) g_stagingTexture->Release(); - + // textures dimensions changed + if (g_stagingWidth != bbWidth || g_stagingHeight != bbHeight) { + for (int i = 0; i < 2; i++) { + if (g_stagingTextures[i]) { + g_stagingTextures[i]->Release(); + g_stagingTextures[i] = NULL; + g_stagingHasData[i] = false; + } + } + g_stagingWidth = bbWidth; + g_stagingHeight = bbHeight; + } + + if (!g_stagingTextures[0] || !g_stagingTextures[1]) { D3D11_TEXTURE2D_DESC desc = {}; desc.Width = bbWidth; desc.Height = bbHeight; @@ -392,38 +420,46 @@ void viewport_server_end_frame(void) { desc.Usage = D3D11_USAGE_STAGING; desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - HRESULT hr = device->CreateTexture2D(&desc, NULL, &g_stagingTexture); - if (FAILED(hr)) { - kinc_log(KINC_LOG_LEVEL_ERROR, "Failed to create staging texture: 0x%08X", hr); - g_stagingTexture = NULL; - g_stagingWidth = 0; - g_stagingHeight = 0; - g_viewport_state.frame_count++; - return; + for (int i = 0; i < 2; i++) { + if (!g_stagingTextures[i]) { + HRESULT hr = device->CreateTexture2D(&desc, NULL, &g_stagingTextures[i]); + if (FAILED(hr)) { + g_stagingTextures[i] = NULL; + g_viewport_state.frame_count++; + return; + } + } } - g_stagingWidth = bbWidth; - g_stagingHeight = bbHeight; } - context->CopyResource(g_stagingTexture, backBuffer); + int writeIdx = g_stagingWriteIdx; + context->CopyResource(g_stagingTextures[writeIdx], backBuffer); + g_stagingHasData[writeIdx] = true; - // only read the portion we need - D3D11_MAPPED_SUBRESOURCE mapped; - if (SUCCEEDED(context->Map(g_stagingTexture, 0, D3D11_MAP_READ, 0, &mapped))) { - for (int y = 0; y < captureHeight; y++) { - memcpy(pixels + y * captureWidth * 4, - (uint8_t*)mapped.pData + y * mapped.RowPitch, - captureWidth * 4); + int readIdx = writeIdx ^ 1; + if (g_stagingHasData[readIdx]) { + D3D11_MAPPED_SUBRESOURCE mapped; + HRESULT hr = context->Map(g_stagingTextures[readIdx], 0, D3D11_MAP_READ, D3D11_MAP_FLAG_DO_NOT_WAIT, &mapped); + if (hr == DXGI_ERROR_WAS_STILL_DRAWING) { + hr = context->Map(g_stagingTextures[readIdx], 0, D3D11_MAP_READ, 0, &mapped); } - context->Unmap(g_stagingTexture, 0); - - // BGRA to RGBA conversion - for (size_t i = 0; i < pixel_size; i += 4) { - uint8_t t = pixels[i]; pixels[i] = pixels[i+2]; pixels[i+2] = t; + if (SUCCEEDED(hr)) { + for (int y = 0; y < captureHeight; y++) { + uint8_t* src = (uint8_t*)mapped.pData + y * mapped.RowPitch; + uint8_t* dst = pixel_dest + y * captureWidth * 4; + for (int x = 0; x < captureWidth * 4; x += 4) { + dst[x] = src[x + 2]; // R <- B + dst[x + 1] = src[x + 1]; // G + dst[x + 2] = src[x]; // B <- R + dst[x + 3] = src[x + 3]; // A + } + } + context->Unmap(g_stagingTextures[readIdx], 0); + pixels_written = true; } - - memcpy(pixel_dest, pixels, pixel_size); } + + g_stagingWriteIdx = writeIdx ^ 1; } //#elif defined(KINC_OPENGL) // glReadPixels(0, 0, g_viewport_state.width, g_viewport_state.height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); @@ -444,10 +480,16 @@ void viewport_server_end_frame(void) { kinc_g4_render_target_t* rt = (kinc_g4_render_target_t*)g_viewport_state.render_target; kinc_g4_render_target_get_pixels(rt, pixels); memcpy(pixel_dest, pixels, pixel_size); + pixels_written = true; } #endif g_viewport_state.frame_count++; + + if (!pixels_written) { + return; + } + header->frame_id = g_viewport_state.frame_count; // NOTE: Camera sync from RunT to Blender is handled via viewport_server_set_camera()