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.
This commit is contained in:
Cameron Gutman
2024-02-24 14:18:15 -06:00
parent e430f51e2f
commit 75a97883e7

View File

@@ -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,39 +385,41 @@ 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;
}
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);
// 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);
}
// 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_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);
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<std::uint8_t[]>(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<std::uint8_t[]>(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;