From 808bf8e681b35fe946d41187a2068dbd5eaf091f Mon Sep 17 00:00:00 2001 From: aliaspider Date: Sun, 25 Mar 2018 23:07:02 +0100 Subject: [PATCH] Libretro: add experimental D3D11 support. --- ext/native/thin3d/thin3d_d3d11.cpp | 30 ++++++++ libretro/CMakeLists.txt | 17 +++-- libretro/LibretroD3D11Context.cpp | 104 +++++++++++++++++++++++++++ libretro/LibretroD3D11Context.h | 28 ++++++++ libretro/LibretroGraphicsContext.cpp | 24 +++++-- libretro/LibretroGraphicsContext.h | 21 ++---- libretro/Makefile.common | 3 +- libretro/libretro.cpp | 1 + libretro/libretro_d3d.h | 60 ++++++++++++++++ 9 files changed, 260 insertions(+), 28 deletions(-) create mode 100644 libretro/LibretroD3D11Context.cpp create mode 100644 libretro/LibretroD3D11Context.h create mode 100644 libretro/libretro_d3d.h diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index 82b9759fd8..9cb46b3fc6 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -98,6 +98,8 @@ public: void DrawUP(const void *vdata, int vertexCount) override; void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal); + void BeginFrame() override; + std::string GetInfoString(InfoField info) const override { switch (info) { case APIVERSION: return "Direct3D 11"; @@ -1274,6 +1276,34 @@ void D3D11DrawContext::Clear(int mask, uint32_t colorval, float depthVal, int st } } +void D3D11DrawContext::BeginFrame() { + context_->OMSetRenderTargets(1, &curRenderTargetView_, curDepthStencilView_); + + if (curBlend_) { + context_->OMSetBlendState(curBlend_->bs, blendFactor_, 0xFFFFFFFF); + } + if (curDepth_) { + context_->OMSetDepthStencilState(curDepth_->dss, stencilRef_); + } + if (curRaster_) { + context_->RSSetState(curRaster_->rs); + } + context_->IASetInputLayout(curInputLayout_); + context_->VSSetShader(curVS_, nullptr, 0); + context_->PSSetShader(curPS_, nullptr, 0); + context_->GSSetShader(curGS_, nullptr, 0); + if (curTopology_ != D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED) { + context_->IASetPrimitiveTopology(curTopology_); + } + if (curPipeline_) { + context_->IASetVertexBuffers(0, 1, nextVertexBuffers_, (UINT *)curPipeline_->input->strides.data(), (UINT *)nextVertexBufferOffsets_); + context_->IASetIndexBuffer(nextIndexBuffer_, DXGI_FORMAT_R32_UINT, nextIndexBufferOffset_); + if (curPipeline_->dynamicUniforms) { + context_->VSSetConstantBuffers(0, 1, &curPipeline_->dynamicUniforms); + } + } +} + void D3D11DrawContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x, int y, int z, Framebuffer *dstfb, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBit) { D3D11Framebuffer *src = (D3D11Framebuffer *)srcfb; D3D11Framebuffer *dst = (D3D11Framebuffer *)dstfb; diff --git a/libretro/CMakeLists.txt b/libretro/CMakeLists.txt index fb4823c9f2..b590cc25df 100644 --- a/libretro/CMakeLists.txt +++ b/libretro/CMakeLists.txt @@ -1,10 +1,15 @@ + set(LIBRETRO_SRCS - libretro.cpp - LibretroGraphicsContext.cpp - LibretroGLContext.cpp - LibretroVulkanContext.cpp - libretro_vulkan.cpp -) + libretro.cpp + LibretroGraphicsContext.cpp + LibretroGLContext.cpp + LibretroVulkanContext.cpp + libretro_vulkan.cpp) + +if(WIN32) + set(LIBRETRO_SRCS ${LIBRETRO_SRCS} + LibretroD3D11Context.cpp) +endif() include_directories(libretro) diff --git a/libretro/LibretroD3D11Context.cpp b/libretro/LibretroD3D11Context.cpp new file mode 100644 index 0000000000..c6bcfe459e --- /dev/null +++ b/libretro/LibretroD3D11Context.cpp @@ -0,0 +1,104 @@ + +#include "libretro/LibretroD3D11Context.h" +#include "thin3d/d3d11_loader.h" +#include + +#ifdef __MINGW32__ +#undef __uuidof +#define __uuidof(type) IID_##type +#endif + +bool LibretroD3D11Context::Init() { + if (!LibretroHWRenderContext::Init()) + return false; + + g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D11; + return true; +} + +void LibretroD3D11Context::CreateDrawContext() { + if (!Libretro::environ_cb(RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE, (void **)&d3d11_) || !d3d11_) { + ERROR_LOG(G3D, "Failed to get HW rendering interface!\n"); + return; + } + + if (d3d11_->interface_version != RETRO_HW_RENDER_INTERFACE_D3D11_VERSION) { + ERROR_LOG(G3D, "HW render interface mismatch, expected %u, got %u!\n", RETRO_HW_RENDER_INTERFACE_D3D11_VERSION, d3d11_->interface_version); + return; + } + + ptr_D3DCompile = d3d11_->D3DCompile; + + ID3D11Device1 *device1 = nullptr; + d3d11_->device->QueryInterface(__uuidof(ID3D11Device1), (void **)&device1); + + ID3D11DeviceContext1 *context1 = nullptr; + d3d11_->context->QueryInterface(__uuidof(ID3D11DeviceContext1), (void **)&context1); + + draw_ = Draw::T3DCreateD3D11Context(d3d11_->device, d3d11_->context, device1, context1, d3d11_->featureLevel, NULL); +} + +void LibretroD3D11Context::DestroyDrawContext() { + LibretroHWRenderContext::DestroyDrawContext(); + d3d11_ = nullptr; +} + +void LibretroD3D11Context::ContextDestroy() +{ + LibretroHWRenderContext::ContextDestroy(); +#if 0 + // this should be enabled once DeviceLost/DeviceRestore can fully switch to a new draw context. + DestroyDrawContext(); +#endif +} + +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; + + 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; + } +} + +void LibretroD3D11Context::LostBackbuffer() { + LibretroGraphicsContext::LostBackbuffer(); + SRView_->Release(); + SRView_ = nullptr; + RTView_->Release(); + RTView_ = nullptr; + texture_->Release(); + texture_ = nullptr; +} + +void LibretroD3D11Context::SwapBuffers() { + ID3D11RenderTargetView *nullView = nullptr; + d3d11_->context->OMSetRenderTargets(1, &nullView, nullptr); + + d3d11_->context->PSSetShaderResources(0, 1, &SRView_); + LibretroHWRenderContext::SwapBuffers(); + + ID3D11ShaderResourceView * nullSRV = nullptr; + d3d11_->context->PSSetShaderResources(0, 1, &nullSRV); + + draw_->HandleEvent(Draw::Event::PRESENTED, 0, 0, nullptr, nullptr); +} diff --git a/libretro/LibretroD3D11Context.h b/libretro/LibretroD3D11Context.h new file mode 100644 index 0000000000..435c11b4aa --- /dev/null +++ b/libretro/LibretroD3D11Context.h @@ -0,0 +1,28 @@ +#pragma once + +#define HAVE_D3D11 +#include "libretro/libretro_d3d.h" +#include "libretro/LibretroGraphicsContext.h" + +class LibretroD3D11Context : public LibretroHWRenderContext { + public: + 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 ContextDestroy() override; + + 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; +}; diff --git a/libretro/LibretroGraphicsContext.cpp b/libretro/LibretroGraphicsContext.cpp index abf114f8f6..8245febb81 100644 --- a/libretro/LibretroGraphicsContext.cpp +++ b/libretro/LibretroGraphicsContext.cpp @@ -5,6 +5,9 @@ #ifndef NO_VULKAN #include "libretro/LibretroVulkanContext.h" #endif +#ifdef _WIN32 +#include "libretro/LibretroD3D11Context.h" +#endif #include "Common/Log.h" #include "Core/Config.h" @@ -34,8 +37,8 @@ void LibretroHWRenderContext::ContextReset() { INFO_LOG(G3D, "Context reset"); - // needed to restart the thread - // TODO: find a way to move this to ContextDestroy. + // needed to restart the thread + // TODO: find a way to move this to ContextDestroy. if (Libretro::useEmuThread && draw_ && Libretro::emuThreadState != Libretro::EmuThreadState::PAUSED) DestroyDrawContext(); @@ -43,10 +46,12 @@ void LibretroHWRenderContext::ContextReset() { CreateDrawContext(); PSP_CoreParameter().thin3d = draw_; - draw_->CreatePresets(); - draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); + bool success = draw_->CreatePresets(); + assert(success); } + GotBackbuffer(); + if (gpu) gpu->DeviceRestore(); } @@ -64,9 +69,20 @@ void LibretroHWRenderContext::ContextDestroy() #endif } + LostBackbuffer(); gpu->DeviceLost(); } +void LibretroGraphicsContext::GotBackbuffer() +{ + draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); +} + +void LibretroGraphicsContext::LostBackbuffer() +{ + draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, -1, -1); +} + LibretroGraphicsContext *LibretroGraphicsContext::CreateGraphicsContext() { LibretroGraphicsContext *ctx; diff --git a/libretro/LibretroGraphicsContext.h b/libretro/LibretroGraphicsContext.h index 06fc00814c..413643c008 100644 --- a/libretro/LibretroGraphicsContext.h +++ b/libretro/LibretroGraphicsContext.h @@ -11,7 +11,7 @@ class LibretroGraphicsContext : public GraphicsContext { public: LibretroGraphicsContext() {} - ~LibretroGraphicsContext() override {} + ~LibretroGraphicsContext() override { Shutdown();} virtual bool Init() = 0; virtual void SetRenderTarget() {} @@ -26,12 +26,14 @@ class LibretroGraphicsContext : public GraphicsContext { void SwapInterval(int interval) override {} void Resize() override {} + virtual void GotBackbuffer(); + virtual void LostBackbuffer(); + virtual void CreateDrawContext() {} virtual void DestroyDrawContext() { if (!draw_) return; - draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, -1, -1); delete draw_; draw_ = nullptr; } @@ -81,21 +83,6 @@ class LibretroD3D9Context : public LibretroHWRenderContext { GPUCore GetGPUCore() override { return GPUCORE_DIRECTX9; } const char *Ident() override { return "DirectX 9"; } }; - -class LibretroD3D11Context : public LibretroHWRenderContext { - public: - LibretroD3D11Context() : LibretroHWRenderContext(RETRO_HW_CONTEXT_DIRECT3D, 11) {} - bool Init() override { return false; } - - void CreateDrawContext() override - { - draw_ = Draw::T3DCreateD3D11Context(nullptr, nullptr, nullptr, nullptr, D3D_FEATURE_LEVEL_11_0, nullptr); - draw_->CreatePresets(); - } - - GPUCore GetGPUCore() override { return GPUCORE_DIRECTX11; } - const char *Ident() override { return "DirectX 11"; } -}; #endif class LibretroSoftwareContext : public LibretroGraphicsContext { diff --git a/libretro/Makefile.common b/libretro/Makefile.common index 92054bbe93..ff051222e6 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -636,7 +636,8 @@ SOURCES_CXX += \ $(GPUDIR)/D3D11/StencilBufferD3D11.cpp \ $(GPUDIR)/D3D11/TextureCacheD3D11.cpp \ $(GPUDIR)/D3D11/TextureScalerD3D11.cpp \ - $(GPUDIR)/D3D11/VertexShaderGeneratorD3D11.cpp + $(GPUDIR)/D3D11/VertexShaderGeneratorD3D11.cpp \ + $(LIBRETRODIR)/LibretroD3D11Context.cpp SOURCES_CXX += \ $(NATIVEDIR)/thin3d/thin3d_d3d9.cpp \ diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index f97369b4a4..928c6fdf3f 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "base/timeutil.h" #include "Common/ChunkFile.h" diff --git a/libretro/libretro_d3d.h b/libretro/libretro_d3d.h new file mode 100644 index 0000000000..2ed71aa7c0 --- /dev/null +++ b/libretro/libretro_d3d.h @@ -0,0 +1,60 @@ +/* Copyright (C) 2010-2016 The RetroArch team + * + * --------------------------------------------------------------------------------------------- + * The following license statement only applies to this libretro API header (libretro_vulkan.h) + * --------------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the + * "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef LIBRETRO_DIRECT3D_H__ +#define LIBRETRO_DIRECT3D_H__ + +#include "libretro.h" + +#ifdef HAVE_D3D11 + +#include +#include + +#define RETRO_HW_RENDER_INTERFACE_D3D11_VERSION 1 + +struct retro_hw_render_interface_d3d11 +{ + /* Must be set to RETRO_HW_RENDER_INTERFACE_D3D11. */ + enum retro_hw_render_interface_type interface_type; + /* Must be set to RETRO_HW_RENDER_INTERFACE_D3D11_VERSION. */ + unsigned interface_version; + + /* Opaque handle to the d3d11 backend in the frontend + * which must be passed along to all function pointers + * in this interface. + */ + void* handle; + ID3D11Device *device; + ID3D11DeviceContext *context; + D3D_FEATURE_LEVEL featureLevel; + pD3DCompile D3DCompile; +}; + + +#endif + +#endif /* LIBRETRO_DIRECT3D_H__ */