diff --git a/sunshine/platform/windows/display_vram.cpp b/sunshine/platform/windows/display_vram.cpp index 9c44b6fb..b3fbde3f 100644 --- a/sunshine/platform/windows/display_vram.cpp +++ b/sunshine/platform/windows/display_vram.cpp @@ -1,3 +1,5 @@ +#include + #include #include @@ -12,8 +14,6 @@ using namespace std::literals; } namespace platf::dxgi { -constexpr float aquamarine[] { 0.498039246f, 1.000000000f, 0.831372619f, 1.000000000f }; - using input_layout_t = util::safe_ptr>; using render_target_t = util::safe_ptr>; using shader_res_t = util::safe_ptr>; @@ -329,19 +329,32 @@ public: input_res_p = scene_sr.get(); } - _init_view_port(out_width, out_height); + _init_view_port(this->img.width, this->img.height); device_ctx_p->OMSetRenderTargets(1, &nv12_Y_rt, nullptr); device_ctx_p->VSSetShader(scene_vs.get(), nullptr, 0); device_ctx_p->PSSetShader(convert_Y_ps.get(), nullptr, 0); + device_ctx_p->PSSetShaderResources(0, 1, &back_img.input_res); + device_ctx_p->Draw(3, 0); + + device_ctx_p->RSSetViewports(1, &outY_view); device_ctx_p->PSSetShaderResources(0, 1, &input_res_p); device_ctx_p->Draw(3, 0); - _init_view_port(out_width / 2, out_height / 2); + // Artifacts start appearing on the rendered image if Sunshine doesn't flush + // before rendering on the UV part of the image. + device_ctx_p->Flush(); + + _init_view_port(this->img.width / 2, this->img.height / 2); device_ctx_p->OMSetRenderTargets(1, &nv12_UV_rt, nullptr); device_ctx_p->VSSetShader(convert_UV_vs.get(), nullptr, 0); device_ctx_p->PSSetShader(convert_UV_ps.get(), nullptr, 0); + device_ctx_p->PSSetShaderResources(0, 1, &back_img.input_res); + device_ctx_p->Draw(3, 0); + + device_ctx_p->RSSetViewports(1, &outUV_view); device_ctx_p->PSSetShaderResources(0, 1, &input_res_p); device_ctx_p->Draw(3, 0); + device_ctx_p->Flush(); return 0; } @@ -377,7 +390,7 @@ public: int init( std::shared_ptr display, device_t::pointer device_p, device_ctx_t::pointer device_ctx_p, - int in_width, int in_height, int out_width, int out_height, + int out_width, int out_height, pix_fmt_e pix_fmt) { HRESULT status; @@ -392,8 +405,20 @@ public: platf::hwdevice_t::img = &img; - this->out_width = out_width; - this->out_height = out_height; + float in_width = display->width; + float in_height = display->height; + + // // Ensure aspect ratio is maintained + auto scalar = std::fminf(out_width / in_width, out_height / in_height); + auto out_width_f = in_width * scalar; + auto out_height_f = in_height * scalar; + + // result is always positive + auto offsetX = (out_width - out_width_f) / 2; + auto offsetY = (out_height - out_height_f) / 2; + + outY_view = D3D11_VIEWPORT { offsetX, offsetY, out_width_f, out_height_f, 0.0f, 1.0f }; + outUV_view = D3D11_VIEWPORT { offsetX / 2, offsetY / 2, out_width_f / 2, out_height_f / 2, 0.0f, 1.0f }; status = device_p->CreateVertexShader(scene_vs_hlsl->GetBufferPointer(), scene_vs_hlsl->GetBufferSize(), nullptr, &scene_vs); if(status) { @@ -514,6 +539,25 @@ public: return -1; } + // Color the background black, so that the padding for keeping the aspect ratio + // is black + if(img.display->dummy_img(&back_img)) { + BOOST_LOG(warning) << "Couldn't create an image to set background color to black"sv; + return -1; + } + + D3D11_SHADER_RESOURCE_VIEW_DESC desc { + DXGI_FORMAT_B8G8R8A8_UNORM, + D3D11_SRV_DIMENSION_TEXTURE2D + }; + desc.Texture2D.MipLevels = 1; + + status = device_p->CreateShaderResourceView(back_img.texture.get(), &desc, &back_img.input_res); + if(FAILED(status)) { + BOOST_LOG(error) << "Failed to create input shader resource view [0x"sv << util::hex(status).to_string_view() << ']'; + return -1; + } + device_ctx_p->OMSetBlendState(blend_disable.get(), nullptr, 0xFFFFFFFFu); device_ctx_p->PSSetSamplers(0, 1, &sampler_linear); device_ctx_p->PSSetConstantBuffers(0, 1, &color_matrix); @@ -619,17 +663,21 @@ public: img_d3d_t img; + // Clear nv12 render target to black + img_d3d_t back_img; + vs_t convert_UV_vs; ps_t convert_UV_ps; ps_t convert_Y_ps; ps_t scene_ps; vs_t scene_vs; + D3D11_VIEWPORT outY_view; + D3D11_VIEWPORT outUV_view; + D3D11_VIEWPORT cursor_view; bool cursor_visible; - float out_width, out_height; - device_ctx_t::pointer device_ctx_p; // The destructor will remove itself from the list of hardware devices, this is done synchronously @@ -768,6 +816,7 @@ int display_vram_t::dummy_img(platf::img_t *img_base) { dummy_data.get(), (UINT)img->row_pitch }; + std::fill_n(dummy_data.get(), width * height, 0); D3D11_TEXTURE2D_DESC t {}; t.Width = width; @@ -808,7 +857,6 @@ std::shared_ptr display_vram_t::make_hwdevice(int width, int shared_from_this(), device.get(), device_ctx.get(), - this->width, this->height, width, height, pix_fmt);