Skip to content

Commit

Permalink
Rework dummy image handling to avoid RTX HDR driver bug
Browse files Browse the repository at this point in the history
As a side effect, it avoids useless allocations and uploads of
a zeroed memory buffer to clear the dummy image textures.
  • Loading branch information
cgutman committed Mar 1, 2024
1 parent e430f51 commit 75a9788
Showing 1 changed file with 39 additions and 44 deletions.
83 changes: 39 additions & 44 deletions src/platform/windows/display_vram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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) };
};

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 75a9788

Please sign in to comment.