diff --git a/libretro/LibretroD3D11Context.cpp b/libretro/LibretroD3D11Context.cpp index 5e1c6ab953..55d1613ef0 100644 --- a/libretro/LibretroD3D11Context.cpp +++ b/libretro/LibretroD3D11Context.cpp @@ -12,95 +12,118 @@ #endif bool LibretroD3D11Context::Init() { - if (!LibretroHWRenderContext::Init(true)) - return false; + if (!LibretroHWRenderContext::Init(true)) { + return false; + } - g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D11; - return true; + g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D11; + return true; } void LibretroD3D11Context::CreateDrawContext() { - std::vector adapterNames; + retro_hw_render_interface_d3d11 *d3d11Interface = nullptr; + if (!Libretro::environ_cb(RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE, (void **)&d3d11Interface) || !d3d11Interface) { + ERROR_LOG(Log::G3D, "Failed to get HW rendering interface!\n"); + return; + } - if (!Libretro::environ_cb(RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE, (void **)&d3d11_) || !d3d11_) { - ERROR_LOG(Log::G3D, "Failed to get HW rendering interface!\n"); - return; - } - - if (d3d11_->interface_version != RETRO_HW_RENDER_INTERFACE_D3D11_VERSION) { - ERROR_LOG(Log::G3D, "HW render interface mismatch, expected %u, got %u!\n", RETRO_HW_RENDER_INTERFACE_D3D11_VERSION, d3d11_->interface_version); - return; - } + if (d3d11Interface->interface_version != RETRO_HW_RENDER_INTERFACE_D3D11_VERSION) { + ERROR_LOG(Log::G3D, "HW render interface mismatch, expected %u, got %u!\n", RETRO_HW_RENDER_INTERFACE_D3D11_VERSION, d3d11Interface->interface_version); + return; + } // Reject lower feature levels. We have D3D9 for these ancient GPUs. - if (d3d11_->featureLevel < D3D_FEATURE_LEVEL_10_0) { + if (d3d11Interface->featureLevel < D3D_FEATURE_LEVEL_10_0) { ERROR_LOG(Log::G3D, "D3D11 featureLevel not high enough - rejecting!\n"); return; } - ptr_D3DCompile = d3d11_->D3DCompile; + // Workaround: RetroArch doesn't correctly persist interface pointers across context_reset calls even + // with cache_context set. Pointers within the structure are persisted. Make a hard copy instead to + // avoid crashes. + hwInterface_ = *d3d11Interface; - ID3D11Device1 *device1 = nullptr; - d3d11_->device->QueryInterface(__uuidof(ID3D11Device1), (void **)&device1); + ptr_D3DCompile = hwInterface_.D3DCompile; + hwInterface_.device->QueryInterface(__uuidof(ID3D11Device1), (void **)&device1_); + hwInterface_.context->QueryInterface(__uuidof(ID3D11DeviceContext1), (void **)&context1_); - ID3D11DeviceContext1 *context1 = nullptr; - d3d11_->context->QueryInterface(__uuidof(ID3D11DeviceContext1), (void **)&context1); - - draw_ = Draw::T3DCreateD3D11Context(d3d11_->device, d3d11_->context, device1, context1, nullptr, d3d11_->featureLevel, NULL, adapterNames, 3); + std::vector adapterNames; + draw_ = Draw::T3DCreateD3D11Context(hwInterface_.device, hwInterface_.context, device1_, context1_, nullptr, hwInterface_.featureLevel, nullptr, adapterNames, g_Config.iInflightFrames); } void LibretroD3D11Context::DestroyDrawContext() { - LibretroHWRenderContext::DestroyDrawContext(); - d3d11_ = nullptr; + LibretroHWRenderContext::DestroyDrawContext(); + if (device1_) { + device1_->Release(); + device1_ = nullptr; + } + if (context1_) { + context1_->Release(); + context1_ = nullptr; + } + hwInterface_ = {}; } void LibretroD3D11Context::GotBackbuffer() { - D3D11_TEXTURE2D_DESC desc{}; - desc.Width = PSP_CoreParameter().pixelWidth; - desc.Height = PSP_CoreParameter().pixelHeight; - desc.MipLevels = 1; - desc.ArraySize = 1; - desc.Format = format_; - desc.SampleDesc.Count = 1; - desc.SampleDesc.Quality = 0; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; - desc.CPUAccessFlags = 0; - desc.MiscFlags = 0; + D3D11_TEXTURE2D_DESC desc{}; + desc.Width = PSP_CoreParameter().pixelWidth; + desc.Height = PSP_CoreParameter().pixelHeight; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = format_; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; - if (SUCCEEDED(d3d11_->device->CreateTexture2D(&desc, nullptr, &texture_))) { - if (SUCCEEDED(d3d11_->device->CreateRenderTargetView(texture_, nullptr, &RTView_))) { - if (SUCCEEDED(d3d11_->device->CreateShaderResourceView(texture_, nullptr, &SRView_))) { - draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight, RTView_, texture_); - return; - } - RTView_->Release(); - RTView_ = nullptr; - } - texture_->Release(); - texture_ = nullptr; - } + if (SUCCEEDED(hwInterface_.device->CreateTexture2D(&desc, nullptr, &texture_))) { + if (SUCCEEDED(hwInterface_.device->CreateRenderTargetView(texture_, nullptr, &texture_rt_view_))) { + if (SUCCEEDED(hwInterface_.device->CreateShaderResourceView(texture_, nullptr, &texture_sr_view_))) { + draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, desc.Width, desc.Height, texture_rt_view_, texture_); + return; + } + texture_rt_view_->Release(); + texture_rt_view_ = nullptr; + } + texture_->Release(); + texture_ = nullptr; + } } void LibretroD3D11Context::LostBackbuffer() { - LibretroGraphicsContext::LostBackbuffer(); - SRView_->Release(); - SRView_ = nullptr; - RTView_->Release(); - RTView_ = nullptr; - texture_->Release(); - texture_ = nullptr; + if (draw_ && texture_) { + D3D11_TEXTURE2D_DESC desc; + texture_->GetDesc(&desc); + + draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, desc.Width, desc.Height); + } + if (texture_sr_view_) { + texture_sr_view_->Release(); + texture_sr_view_ = nullptr; + } + if (texture_rt_view_) { + texture_rt_view_->Release(); + texture_rt_view_ = nullptr; + } + if (texture_) { + texture_->Release(); + texture_ = nullptr; + } } void LibretroD3D11Context::SwapBuffers() { - ID3D11RenderTargetView *nullView = nullptr; - d3d11_->context->OMSetRenderTargets(1, &nullView, nullptr); + ID3D11RenderTargetView *nullView = nullptr; + hwInterface_.context->OMSetRenderTargets(1, &nullView, nullptr); - d3d11_->context->PSSetShaderResources(0, 1, &SRView_); - LibretroHWRenderContext::SwapBuffers(); + // libretro doesn't specify how to pass our D3D11 frame to the frontend. RetroArch expects it to be + // bound to the first shader resource slot. + hwInterface_.context->PSSetShaderResources(0, 1, &texture_sr_view_); + LibretroHWRenderContext::SwapBuffers(); - ID3D11ShaderResourceView *nullSRV = nullptr; - d3d11_->context->PSSetShaderResources(0, 1, &nullSRV); + ID3D11ShaderResourceView *nullSRV = nullptr; + hwInterface_.context->PSSetShaderResources(0, 1, &nullSRV); - draw_->HandleEvent(Draw::Event::PRESENTED, 0, 0, nullptr, nullptr); + draw_->HandleEvent(Draw::Event::PRESENTED, 0, 0, nullptr, nullptr); } diff --git a/libretro/LibretroD3D11Context.h b/libretro/LibretroD3D11Context.h index 8fa5c92b4e..2fd51dfdf6 100644 --- a/libretro/LibretroD3D11Context.h +++ b/libretro/LibretroD3D11Context.h @@ -6,22 +6,24 @@ class LibretroD3D11Context : public LibretroHWRenderContext { public: - LibretroD3D11Context() : LibretroHWRenderContext(RETRO_HW_CONTEXT_DIRECT3D, 11) {} - bool Init() override; + LibretroD3D11Context() : LibretroHWRenderContext(RETRO_HW_CONTEXT_DIRECT3D, 11) {} + bool Init() override; - void SwapBuffers() override; - void GotBackbuffer() override; - void LostBackbuffer() override; - void CreateDrawContext() override; - void DestroyDrawContext() override; + void SwapBuffers() override; + void GotBackbuffer() override; + void LostBackbuffer() override; + void CreateDrawContext() override; + void DestroyDrawContext() override; - GPUCore GetGPUCore() override { return GPUCORE_DIRECTX11; } - const char *Ident() override { return "DirectX 11"; } + GPUCore GetGPUCore() override { return GPUCORE_DIRECTX11; } + const char *Ident() override { return "DirectX 11"; } private: - retro_hw_render_interface_d3d11 *d3d11_ = nullptr; - ID3D11Texture2D *texture_ = nullptr; - ID3D11RenderTargetView *RTView_ = nullptr; - ID3D11ShaderResourceView *SRView_ = nullptr; - DXGI_FORMAT format_ = DXGI_FORMAT_R8G8B8A8_UNORM; + retro_hw_render_interface_d3d11 hwInterface_ = {}; + ID3D11Device1 *device1_ = nullptr; + ID3D11DeviceContext1 *context1_ = nullptr; + ID3D11Texture2D *texture_ = nullptr; + ID3D11RenderTargetView *texture_rt_view_ = nullptr; + ID3D11ShaderResourceView *texture_sr_view_ = nullptr; + DXGI_FORMAT format_ = DXGI_FORMAT_R8G8B8A8_UNORM; };