Fix viewport

This commit is contained in:
2026-07-23 23:17:24 -07:00
parent a30a407de6
commit 637a7804b5

View File

@ -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()