From 75a97883e71d1c17eb2784c110469042f520f81f Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 24 Feb 2024 14:18:15 -0600 Subject: [PATCH] Rework dummy image handling to avoid RTX HDR driver bug As a side effect, it avoids useless allocations and uploads of a zeroed memory buffer to clear the dummy image textures. --- src/platform/windows/display_vram.cpp | 83 +++++++++++++-------------- 1 file changed, 39 insertions(+), 44 deletions(-) diff --git a/src/platform/windows/display_vram.cpp b/src/platform/windows/display_vram.cpp index e9f8140d525..a56869eab40 100644 --- a/src/platform/windows/display_vram.cpp +++ b/src/platform/windows/display_vram.cpp @@ -125,6 +125,9 @@ namespace platf::dxgi { // the first successful capture of a desktop frame bool dummy = false; + // Set to true if the image is blank (contains no content at all, including a cursor) + bool blank = true; + // Unique identifier for this image uint32_t id = 0; @@ -382,38 +385,40 @@ namespace platf::dxgi { } auto &img = (img_d3d_t &) img_base; - auto &img_ctx = img_ctx_map[img.id]; + if (!img.blank) { + auto &img_ctx = img_ctx_map[img.id]; - // Open the shared capture texture with our ID3D11Device - if (initialize_image_context(img, img_ctx)) { - return -1; - } + // Open the shared capture texture with our ID3D11Device + if (initialize_image_context(img, img_ctx)) { + return -1; + } - // Acquire encoder mutex to synchronize with capture code - auto status = img_ctx.encoder_mutex->AcquireSync(0, INFINITE); - if (status != S_OK) { - BOOST_LOG(error) << "Failed to acquire encoder mutex [0x"sv << util::hex(status).to_string_view() << ']'; - return -1; - } + // Acquire encoder mutex to synchronize with capture code + auto status = img_ctx.encoder_mutex->AcquireSync(0, INFINITE); + if (status != S_OK) { + BOOST_LOG(error) << "Failed to acquire encoder mutex [0x"sv << util::hex(status).to_string_view() << ']'; + return -1; + } - device_ctx->OMSetRenderTargets(1, &nv12_Y_rt, nullptr); - device_ctx->VSSetShader(scene_vs.get(), nullptr, 0); - device_ctx->PSSetShader(img.format == DXGI_FORMAT_R16G16B16A16_FLOAT ? convert_Y_fp16_ps.get() : convert_Y_ps.get(), nullptr, 0); - device_ctx->RSSetViewports(1, &outY_view); - device_ctx->PSSetShaderResources(0, 1, &img_ctx.encoder_input_res); - device_ctx->Draw(3, 0); + device_ctx->OMSetRenderTargets(1, &nv12_Y_rt, nullptr); + device_ctx->VSSetShader(scene_vs.get(), nullptr, 0); + device_ctx->PSSetShader(img.format == DXGI_FORMAT_R16G16B16A16_FLOAT ? convert_Y_fp16_ps.get() : convert_Y_ps.get(), nullptr, 0); + device_ctx->RSSetViewports(1, &outY_view); + device_ctx->PSSetShaderResources(0, 1, &img_ctx.encoder_input_res); + device_ctx->Draw(3, 0); - device_ctx->OMSetRenderTargets(1, &nv12_UV_rt, nullptr); - device_ctx->VSSetShader(convert_UV_vs.get(), nullptr, 0); - device_ctx->PSSetShader(img.format == DXGI_FORMAT_R16G16B16A16_FLOAT ? convert_UV_fp16_ps.get() : convert_UV_ps.get(), nullptr, 0); - device_ctx->RSSetViewports(1, &outUV_view); - device_ctx->Draw(3, 0); + device_ctx->OMSetRenderTargets(1, &nv12_UV_rt, nullptr); + device_ctx->VSSetShader(convert_UV_vs.get(), nullptr, 0); + device_ctx->PSSetShader(img.format == DXGI_FORMAT_R16G16B16A16_FLOAT ? convert_UV_fp16_ps.get() : convert_UV_ps.get(), nullptr, 0); + device_ctx->RSSetViewports(1, &outUV_view); + device_ctx->Draw(3, 0); - // Release encoder mutex to allow capture code to reuse this image - img_ctx.encoder_mutex->ReleaseSync(0); + // Release encoder mutex to allow capture code to reuse this image + img_ctx.encoder_mutex->ReleaseSync(0); - ID3D11ShaderResourceView *emptyShaderResourceView = nullptr; - device_ctx->PSSetShaderResources(0, 1, &emptyShaderResourceView); + ID3D11ShaderResourceView *emptyShaderResourceView = nullptr; + device_ctx->PSSetShaderResources(0, 1, &emptyShaderResourceView); + } return 0; } @@ -1144,6 +1149,9 @@ namespace platf::dxgi { return { nullptr, nullptr }; } + // Clear the blank flag now that we're ready to capture into the image + d3d_img->blank = false; + return { std::move(d3d_img), std::move(lock_helper) }; }; @@ -1289,15 +1297,14 @@ namespace platf::dxgi { // Clear the image if it has been used as a dummy. // It can have the mouse cursor blended onto it. auto old_d3d_img = (img_d3d_t *) img_out.get(); - bool reclear_dummy = old_d3d_img->dummy && old_d3d_img->capture_texture; + bool reclear_dummy = !old_d3d_img->blank && old_d3d_img->capture_texture; auto [d3d_img, lock] = get_locked_d3d_img(img_out, true); if (!d3d_img) return capture_e::error; if (reclear_dummy) { - auto dummy_data = std::make_unique(d3d_img->row_pitch * d3d_img->height); - std::fill_n(dummy_data.get(), d3d_img->row_pitch * d3d_img->height, 0); - device_ctx->UpdateSubresource(d3d_img->capture_texture.get(), 0, nullptr, dummy_data.get(), d3d_img->row_pitch, 0); + const float rgb_black[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + device_ctx->ClearRenderTargetView(d3d_img->capture_rt.get(), rgb_black); } if (blend_mouse_cursor_flag) { @@ -1409,6 +1416,7 @@ namespace platf::dxgi { img->width = width_before_rotation; img->height = height_before_rotation; img->id = next_image_id++; + img->blank = true; return img; } @@ -1456,20 +1464,7 @@ namespace platf::dxgi { t.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; t.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX; - HRESULT status; - if (dummy) { - auto dummy_data = std::make_unique(img->row_pitch * img->height); - std::fill_n(dummy_data.get(), img->row_pitch * img->height, 0); - D3D11_SUBRESOURCE_DATA initial_data { - dummy_data.get(), - (UINT) img->row_pitch, - 0 - }; - status = device->CreateTexture2D(&t, &initial_data, &img->capture_texture); - } - else { - status = device->CreateTexture2D(&t, nullptr, &img->capture_texture); - } + auto status = device->CreateTexture2D(&t, nullptr, &img->capture_texture); if (FAILED(status)) { BOOST_LOG(error) << "Failed to create img buf texture [0x"sv << util::hex(status).to_string_view() << ']'; return -1;