diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index dbc1ea15e8..21f25d750e 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -11,6 +11,7 @@ add_library(common Crypto/ec.cpp Debug/MemoryPatches.cpp Debug/Watches.cpp + DynamicLibrary.cpp ENetUtil.cpp File.cpp FileSearch.cpp diff --git a/Source/Core/Common/Common.vcxproj b/Source/Core/Common/Common.vcxproj index 75b1563876..4fd4119418 100644 --- a/Source/Core/Common/Common.vcxproj +++ b/Source/Core/Common/Common.vcxproj @@ -63,6 +63,7 @@ + @@ -184,6 +185,7 @@ + @@ -258,4 +260,4 @@ - + \ No newline at end of file diff --git a/Source/Core/Common/Common.vcxproj.filters b/Source/Core/Common/Common.vcxproj.filters index 47c0b42053..5849e34f66 100644 --- a/Source/Core/Common/Common.vcxproj.filters +++ b/Source/Core/Common/Common.vcxproj.filters @@ -276,6 +276,8 @@ GL\GLInterface + + @@ -357,6 +359,7 @@ GL\GLInterface + @@ -364,4 +367,4 @@ - + \ No newline at end of file diff --git a/Source/Core/Common/DynamicLibrary.cpp b/Source/Core/Common/DynamicLibrary.cpp new file mode 100644 index 0000000000..1c32cc6708 --- /dev/null +++ b/Source/Core/Common/DynamicLibrary.cpp @@ -0,0 +1,100 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "Common/DynamicLibrary.h" +#include +#include "Common/Assert.h" +#include "Common/StringUtil.h" + +#ifdef _WIN32 +#include +#else +#include +#endif + +namespace Common +{ +DynamicLibrary::DynamicLibrary() = default; + +DynamicLibrary::DynamicLibrary(const char* filename) +{ + Open(filename); +} + +DynamicLibrary::~DynamicLibrary() +{ + Close(); +} + +std::string DynamicLibrary::GetUnprefixedFilename(const char* filename) +{ +#if defined(_WIN32) + return std::string(filename) + ".dll"; +#elif defined(__APPLE__) + return std::string(filename) + ".dylib"; +#else + return std::string(filename) + ".so"; +#endif +} + +std::string DynamicLibrary::GetVersionedFilename(const char* libname, int major, int minor) +{ +#if defined(_WIN32) + if (major >= 0 && minor >= 0) + return StringFromFormat("%s-%d-%d.dll", libname, major, minor); + else if (major >= 0) + return StringFromFormat("%s-%d.dll", libname, major); + else + return StringFromFormat("%s.dll", libname); +#elif defined(__APPLE__) + const char* prefix = std::strncmp(libname, "lib", 3) ? "lib" : ""; + if (major >= 0 && minor >= 0) + return StringFromFormat("%s%s.%d.%d.dylib", prefix, libname, major, minor); + else if (major >= 0) + return StringFromFormat("%s%s.%d.dylib", prefix, libname, major); + else + return StringFromFormat("%s%s.dylib", prefix, libname); +#else + const char* prefix = std::strncmp(libname, "lib", 3) ? "lib" : ""; + if (major >= 0 && minor >= 0) + return StringFromFormat("%s%s.so.%d.%d", prefix, libname, major, minor); + else if (major >= 0) + return StringFromFormat("%s%s.so.%d", prefix, libname, major); + else + return StringFromFormat("%s%s.so", prefix, libname); +#endif +} + +bool DynamicLibrary::Open(const char* filename) +{ +#ifdef _WIN32 + m_handle = reinterpret_cast(LoadLibraryA(filename)); +#else + m_handle = dlopen(filename, RTLD_NOW); +#endif + return m_handle != nullptr; +} + +void DynamicLibrary::Close() +{ + if (!IsOpen()) + return; + +#ifdef _WIN32 + FreeLibrary(reinterpret_cast(m_handle)); +#else + dlclose(m_handle); +#endif + m_handle = nullptr; +} + +void* DynamicLibrary::GetSymbolAddress(const char* name) const +{ +#ifdef _WIN32 + return reinterpret_cast(GetProcAddress(reinterpret_cast(m_handle), name)); +#else + return reinterpret_cast(dlsym(m_handle, name)); +#endif +} +} // namespace Common diff --git a/Source/Core/Common/DynamicLibrary.h b/Source/Core/Common/DynamicLibrary.h new file mode 100644 index 0000000000..2320ace2e7 --- /dev/null +++ b/Source/Core/Common/DynamicLibrary.h @@ -0,0 +1,67 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once +#include +#include + +namespace Common +{ +/** + * Provides a platform-independent interface for loading a dynamic library and retrieving symbols. + * The interface maintains an internal reference count to allow one handle to be shared between + * multiple users. + */ +class DynamicLibrary final +{ +public: + // Default constructor, does not load a library. + DynamicLibrary(); + + // Automatically loads the specified library. Call IsOpen() to check validity before use. + DynamicLibrary(const char* filename); + + // Closes the library. + ~DynamicLibrary(); + + // Returns the specified library name with the platform-specific suffix added. + static std::string GetUnprefixedFilename(const char* filename); + + // Returns the specified library name in platform-specific format. + // Major/minor versions will not be included if set to -1. + // If libname already contains the "lib" prefix, it will not be added again. + // Windows: LIBNAME-MAJOR-MINOR.dll + // Linux: libLIBNAME.so.MAJOR.MINOR + // Mac: libLIBNAME.MAJOR.MINOR.dylib + static std::string GetVersionedFilename(const char* libname, int major = -1, int minor = -1); + + // Returns true if a module is loaded, otherwise false. + bool IsOpen() const { return m_handle != nullptr; } + + // Loads (or replaces) the handle with the specified library file name. + // Returns true if the library was loaded and can be used. + bool Open(const char* filename); + + // Unloads the library, any function pointers from this library are no longer valid. + void Close(); + + // Returns the address of the specified symbol (function or variable) as an untyped pointer. + // If the specified symbol does not exist in this library, nullptr is returned. + void* GetSymbolAddress(const char* name) const; + + // Obtains the address of the specified symbol, automatically casting to the correct type. + // Returns true if the symbol was found and assigned, otherwise false. + template + bool GetSymbol(const char* name, T* ptr) const + { + *ptr = reinterpret_cast(GetSymbolAddress(name)); + return *ptr != nullptr; + } + +private: + // Platform-dependent data type representing a dynamic library handle. + void* m_handle = nullptr; +}; + +} // namespace Common diff --git a/Source/Core/VideoBackends/CMakeLists.txt b/Source/Core/VideoBackends/CMakeLists.txt index e670dd7d4a..b53d85e10a 100644 --- a/Source/Core/VideoBackends/CMakeLists.txt +++ b/Source/Core/VideoBackends/CMakeLists.txt @@ -4,6 +4,7 @@ add_subdirectory(Software) add_subdirectory(Vulkan) if(CMAKE_SYSTEM_NAME STREQUAL "Windows") + add_subdirectory(D3DCommon) add_subdirectory(D3D) endif() diff --git a/Source/Core/VideoBackends/D3D/BoundingBox.cpp b/Source/Core/VideoBackends/D3D/BoundingBox.cpp index abbd7036a1..7cae36e1a1 100644 --- a/Source/Core/VideoBackends/D3D/BoundingBox.cpp +++ b/Source/Core/VideoBackends/D3D/BoundingBox.cpp @@ -6,17 +6,18 @@ #include "Common/CommonTypes.h" #include "Common/MsgHandler.h" #include "VideoBackends/D3D/D3DState.h" +#include "VideoBackends/D3DCommon/Common.h" #include "VideoCommon/VideoConfig.h" namespace DX11 { -static ID3D11Buffer* s_bbox_buffer; -static ID3D11Buffer* s_bbox_staging_buffer; -static ID3D11UnorderedAccessView* s_bbox_uav; +static ComPtr s_bbox_buffer; +static ComPtr s_bbox_staging_buffer; +static ComPtr s_bbox_uav; -ID3D11UnorderedAccessView*& BBox::GetUAV() +ID3D11UnorderedAccessView* BBox::GetUAV() { - return s_bbox_uav; + return s_bbox_uav.Get(); } void BBox::Init() @@ -35,7 +36,7 @@ void BBox::Init() HRESULT hr; hr = D3D::device->CreateBuffer(&desc, &data, &s_bbox_buffer); CHECK(SUCCEEDED(hr), "Create BoundingBox Buffer."); - D3D::SetDebugObjectName(s_bbox_buffer, "BoundingBox Buffer"); + D3DCommon::SetDebugObjectName(s_bbox_buffer.Get(), "BoundingBox Buffer"); // Second to use as a staging buffer. desc.Usage = D3D11_USAGE_STAGING; @@ -43,7 +44,7 @@ void BBox::Init() desc.BindFlags = 0; hr = D3D::device->CreateBuffer(&desc, nullptr, &s_bbox_staging_buffer); CHECK(SUCCEEDED(hr), "Create BoundingBox Staging Buffer."); - D3D::SetDebugObjectName(s_bbox_staging_buffer, "BoundingBox Staging Buffer"); + D3DCommon::SetDebugObjectName(s_bbox_staging_buffer.Get(), "BoundingBox Staging Buffer"); // UAV is required to allow concurrent access. D3D11_UNORDERED_ACCESS_VIEW_DESC UAVdesc = {}; @@ -52,37 +53,37 @@ void BBox::Init() UAVdesc.Buffer.FirstElement = 0; UAVdesc.Buffer.Flags = 0; UAVdesc.Buffer.NumElements = 4; - hr = D3D::device->CreateUnorderedAccessView(s_bbox_buffer, &UAVdesc, &s_bbox_uav); + hr = D3D::device->CreateUnorderedAccessView(s_bbox_buffer.Get(), &UAVdesc, &s_bbox_uav); CHECK(SUCCEEDED(hr), "Create BoundingBox UAV."); - D3D::SetDebugObjectName(s_bbox_uav, "BoundingBox UAV"); - D3D::stateman->SetOMUAV(s_bbox_uav); + D3DCommon::SetDebugObjectName(s_bbox_uav.Get(), "BoundingBox UAV"); + D3D::stateman->SetOMUAV(s_bbox_uav.Get()); } } void BBox::Shutdown() { - SAFE_RELEASE(s_bbox_buffer); - SAFE_RELEASE(s_bbox_staging_buffer); - SAFE_RELEASE(s_bbox_uav); + s_bbox_uav.Reset(); + s_bbox_staging_buffer.Reset(); + s_bbox_buffer.Reset(); } void BBox::Set(int index, int value) { D3D11_BOX box{index * sizeof(s32), 0, 0, (index + 1) * sizeof(s32), 1, 1}; - D3D::context->UpdateSubresource(s_bbox_buffer, 0, &box, &value, 0, 0); + D3D::context->UpdateSubresource(s_bbox_buffer.Get(), 0, &box, &value, 0, 0); } int BBox::Get(int index) { int data = 0; - D3D::context->CopyResource(s_bbox_staging_buffer, s_bbox_buffer); + D3D::context->CopyResource(s_bbox_staging_buffer.Get(), s_bbox_buffer.Get()); D3D11_MAPPED_SUBRESOURCE map; - HRESULT hr = D3D::context->Map(s_bbox_staging_buffer, 0, D3D11_MAP_READ, 0, &map); + HRESULT hr = D3D::context->Map(s_bbox_staging_buffer.Get(), 0, D3D11_MAP_READ, 0, &map); if (SUCCEEDED(hr)) { data = ((s32*)map.pData)[index]; } - D3D::context->Unmap(s_bbox_staging_buffer, 0); + D3D::context->Unmap(s_bbox_staging_buffer.Get(), 0); return data; } }; // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/BoundingBox.h b/Source/Core/VideoBackends/D3D/BoundingBox.h index e46add7f37..4d78af2346 100644 --- a/Source/Core/VideoBackends/D3D/BoundingBox.h +++ b/Source/Core/VideoBackends/D3D/BoundingBox.h @@ -10,7 +10,7 @@ namespace DX11 class BBox { public: - static ID3D11UnorderedAccessView*& GetUAV(); + static ID3D11UnorderedAccessView* GetUAV(); static void Init(); static void Shutdown(); diff --git a/Source/Core/VideoBackends/D3D/CMakeLists.txt b/Source/Core/VideoBackends/D3D/CMakeLists.txt index facd2b07e3..b80d9df818 100644 --- a/Source/Core/VideoBackends/D3D/CMakeLists.txt +++ b/Source/Core/VideoBackends/D3D/CMakeLists.txt @@ -26,4 +26,5 @@ target_link_libraries(videod3d PUBLIC common videocommon + videod3dcommon ) diff --git a/Source/Core/VideoBackends/D3D/D3D.vcxproj b/Source/Core/VideoBackends/D3D/D3D.vcxproj index 5721e4d3ce..5fd3dbcbce 100644 --- a/Source/Core/VideoBackends/D3D/D3D.vcxproj +++ b/Source/Core/VideoBackends/D3D/D3D.vcxproj @@ -46,6 +46,7 @@ + @@ -57,6 +58,7 @@ + @@ -64,6 +66,9 @@ {3de9ee35-3e91-4f27-a014-2866ad8c3fe3} + + {dea96cf2-f237-4a1a-b32f-c916769efb50} + diff --git a/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters b/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters index 4ca2cfa179..630e95a808 100644 --- a/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters +++ b/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters @@ -40,6 +40,9 @@ Render + + Render + @@ -70,5 +73,8 @@ Render + + Render + \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3D/D3DBase.cpp b/Source/Core/VideoBackends/D3D/D3DBase.cpp index 9a86cd3c0c..0631ded2c0 100644 --- a/Source/Core/VideoBackends/D3D/D3DBase.cpp +++ b/Source/Core/VideoBackends/D3D/D3DBase.cpp @@ -5,6 +5,7 @@ #include #include "Common/CommonTypes.h" +#include "Common/DynamicLibrary.h" #include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/StringUtil.h" @@ -13,221 +14,31 @@ #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/DXTexture.h" +#include "VideoBackends/D3DCommon/Common.h" #include "VideoCommon/VideoConfig.h" namespace DX11 { -using D3DREFLECT = HRESULT(WINAPI*)(LPCVOID, SIZE_T, REFIID, void**); - -static HINSTANCE s_d3d_compiler_dll; -static int s_d3dcompiler_dll_ref; -static D3DREFLECT s_d3d_reflect; -pD3DCompile PD3DCompile = nullptr; - -CREATEDXGIFACTORY PCreateDXGIFactory = nullptr; -static HINSTANCE s_dxgi_dll; -static int s_dxgi_dll_ref; - -static D3D11CREATEDEVICE s_d3d11_create_device; -static HINSTANCE s_d3d_dll; -static int s_d3d_dll_ref; - +static Common::DynamicLibrary s_d3d11_library; namespace D3D { -ID3D11Device* device = nullptr; -ID3D11Device1* device1 = nullptr; -ID3D11DeviceContext* context = nullptr; -IDXGISwapChain1* swapchain = nullptr; +ComPtr dxgi_factory; +ComPtr device; +ComPtr device1; +ComPtr context; +D3D_FEATURE_LEVEL feature_level; -static IDXGIFactory2* s_dxgi_factory; -static ID3D11Debug* s_debug; -static D3D_FEATURE_LEVEL s_featlevel; -static std::unique_ptr s_swap_chain_texture; -static std::unique_ptr s_swap_chain_framebuffer; +static ComPtr s_debug; -static std::vector s_aa_modes; // supported AA modes of the current adapter - -static bool s_bgra_textures_supported; -static bool s_allow_tearing_supported; - -constexpr UINT NUM_SUPPORTED_FEATURE_LEVELS = 3; -constexpr D3D_FEATURE_LEVEL supported_feature_levels[NUM_SUPPORTED_FEATURE_LEVELS] = { +static constexpr D3D_FEATURE_LEVEL s_supported_feature_levels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0}; -HRESULT LoadDXGI() -{ - if (s_dxgi_dll_ref++ > 0) - return S_OK; - - if (s_dxgi_dll) - return S_OK; - s_dxgi_dll = LoadLibraryA("dxgi.dll"); - if (!s_dxgi_dll) - { - MessageBoxA(nullptr, "Failed to load dxgi.dll", "Critical error", MB_OK | MB_ICONERROR); - --s_dxgi_dll_ref; - return E_FAIL; - } - - // Even though we use IDXGIFactory2 we use CreateDXGIFactory1 to create it to maintain - // compatibility with Windows 7 - PCreateDXGIFactory = (CREATEDXGIFACTORY)GetProcAddress(s_dxgi_dll, "CreateDXGIFactory1"); - if (PCreateDXGIFactory == nullptr) - MessageBoxA(nullptr, "GetProcAddress failed for CreateDXGIFactory1!", "Critical error", - MB_OK | MB_ICONERROR); - - return S_OK; -} - -HRESULT LoadD3D() -{ - if (s_d3d_dll_ref++ > 0) - return S_OK; - - if (s_d3d_dll) - return S_OK; - s_d3d_dll = LoadLibraryA("d3d11.dll"); - if (!s_d3d_dll) - { - MessageBoxA(nullptr, "Failed to load d3d11.dll", "Critical error", MB_OK | MB_ICONERROR); - --s_d3d_dll_ref; - return E_FAIL; - } - s_d3d11_create_device = (D3D11CREATEDEVICE)GetProcAddress(s_d3d_dll, "D3D11CreateDevice"); - if (s_d3d11_create_device == nullptr) - MessageBoxA(nullptr, "GetProcAddress failed for D3D11CreateDevice!", "Critical error", - MB_OK | MB_ICONERROR); - - return S_OK; -} - -HRESULT LoadD3DCompiler() -{ - if (s_d3dcompiler_dll_ref++ > 0) - return S_OK; - if (s_d3d_compiler_dll) - return S_OK; - - // The older version of the D3D compiler cannot compile our ubershaders without various - // graphical issues. D3DCOMPILER_DLL_A should point to d3dcompiler_47.dll, so if this fails - // to load, inform the user that they need to update their system. - s_d3d_compiler_dll = LoadLibraryA(D3DCOMPILER_DLL_A); - if (!s_d3d_compiler_dll) - { - PanicAlertT("Failed to load %s. If you are using Windows 7, try installing the " - "KB4019990 update package.", - D3DCOMPILER_DLL_A); - return E_FAIL; - } - - s_d3d_reflect = (D3DREFLECT)GetProcAddress(s_d3d_compiler_dll, "D3DReflect"); - if (s_d3d_reflect == nullptr) - MessageBoxA(nullptr, "GetProcAddress failed for D3DReflect!", "Critical error", - MB_OK | MB_ICONERROR); - PD3DCompile = (pD3DCompile)GetProcAddress(s_d3d_compiler_dll, "D3DCompile"); - if (PD3DCompile == nullptr) - MessageBoxA(nullptr, "GetProcAddress failed for D3DCompile!", "Critical error", - MB_OK | MB_ICONERROR); - - return S_OK; -} - -void UnloadDXGI() -{ - if (!s_dxgi_dll_ref) - return; - if (--s_dxgi_dll_ref != 0) - return; - - if (s_dxgi_dll) - FreeLibrary(s_dxgi_dll); - s_dxgi_dll = nullptr; - PCreateDXGIFactory = nullptr; -} - -void UnloadD3D() -{ - if (!s_d3d_dll_ref) - return; - if (--s_d3d_dll_ref != 0) - return; - - if (s_d3d_dll) - FreeLibrary(s_d3d_dll); - s_d3d_dll = nullptr; - s_d3d11_create_device = nullptr; -} - -void UnloadD3DCompiler() -{ - if (!s_d3dcompiler_dll_ref) - return; - if (--s_d3dcompiler_dll_ref != 0) - return; - - if (s_d3d_compiler_dll) - FreeLibrary(s_d3d_compiler_dll); - s_d3d_compiler_dll = nullptr; - s_d3d_reflect = nullptr; -} - -std::vector EnumAAModes(IDXGIAdapter* adapter) -{ - std::vector _aa_modes; - - // NOTE: D3D 10.0 doesn't support multisampled resources which are bound as depth buffers AND - // shader resources. - // Thus, we can't have MSAA with 10.0 level hardware. - ID3D11Device* _device; - ID3D11DeviceContext* _context; - D3D_FEATURE_LEVEL feat_level; - HRESULT hr = s_d3d11_create_device(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, - supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, - D3D11_SDK_VERSION, &_device, &feat_level, &_context); - if (FAILED(hr) || feat_level == D3D_FEATURE_LEVEL_10_0) - { - DXGI_SAMPLE_DESC desc; - desc.Count = 1; - desc.Quality = 0; - _aa_modes.push_back(desc); - SAFE_RELEASE(_context); - SAFE_RELEASE(_device); - } - else - { - for (int samples = 0; samples < D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; ++samples) - { - UINT quality_levels = 0; - _device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, samples, &quality_levels); - - DXGI_SAMPLE_DESC desc; - desc.Count = samples; - desc.Quality = 0; - - if (quality_levels > 0) - _aa_modes.push_back(desc); - } - _context->Release(); - _device->Release(); - } - return _aa_modes; -} - -D3D_FEATURE_LEVEL GetFeatureLevel(IDXGIAdapter* adapter) -{ - D3D_FEATURE_LEVEL feat_level = D3D_FEATURE_LEVEL_9_1; - s_d3d11_create_device(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, supported_feature_levels, - NUM_SUPPORTED_FEATURE_LEVELS, D3D11_SDK_VERSION, nullptr, &feat_level, - nullptr); - return feat_level; -} - -static bool SupportsS3TCTextures(ID3D11Device* dev) +static bool SupportsS3TCTextures() { UINT bc1_support, bc2_support, bc3_support; - if (FAILED(dev->CheckFormatSupport(DXGI_FORMAT_BC1_UNORM, &bc1_support)) || - FAILED(dev->CheckFormatSupport(DXGI_FORMAT_BC2_UNORM, &bc2_support)) || - FAILED(dev->CheckFormatSupport(DXGI_FORMAT_BC3_UNORM, &bc3_support))) + if (FAILED(device->CheckFormatSupport(DXGI_FORMAT_BC1_UNORM, &bc1_support)) || + FAILED(device->CheckFormatSupport(DXGI_FORMAT_BC2_UNORM, &bc2_support)) || + FAILED(device->CheckFormatSupport(DXGI_FORMAT_BC3_UNORM, &bc3_support))) { return false; } @@ -235,449 +46,201 @@ static bool SupportsS3TCTextures(ID3D11Device* dev) return ((bc1_support & bc2_support & bc3_support) & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0; } -static bool SupportsBPTCTextures(ID3D11Device* dev) +static bool SupportsBPTCTextures() { // Currently, we only care about BC7. This could be extended to BC6H in the future. UINT bc7_support; - if (FAILED(dev->CheckFormatSupport(DXGI_FORMAT_BC7_UNORM, &bc7_support))) + if (FAILED(device->CheckFormatSupport(DXGI_FORMAT_BC7_UNORM, &bc7_support))) return false; return (bc7_support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0; } -static bool CreateSwapChainFramebuffer() +bool Create(u32 adapter_index, bool enable_debug_layer) { - ID3D11Texture2D* texture; - HRESULT hr = swapchain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&texture); - CHECK(SUCCEEDED(hr), "GetBuffer for swap chain failed with HRESULT %08X", hr); - if (FAILED(hr)) - return false; - - D3D11_TEXTURE2D_DESC desc; - texture->GetDesc(&desc); - - s_swap_chain_texture = std::make_unique( - TextureConfig(desc.Width, desc.Height, desc.MipLevels, desc.ArraySize, desc.SampleDesc.Count, - AbstractTextureFormat::RGBA8, AbstractTextureFlag_RenderTarget), - texture, nullptr, nullptr); - - ID3D11RenderTargetView* rtv; - CD3D11_RENDER_TARGET_VIEW_DESC rtv_desc(texture, D3D11_RTV_DIMENSION_TEXTURE2DARRAY, desc.Format, - 0, 0, desc.ArraySize); - hr = device->CreateRenderTargetView(texture, &rtv_desc, &rtv); - CHECK(SUCCEEDED(hr), "Create render target view for swap chain"); - if (FAILED(hr)) + PFN_D3D11_CREATE_DEVICE d3d11_create_device; + if (!s_d3d11_library.Open("d3d11.dll") || + !s_d3d11_library.GetSymbol("D3D11CreateDevice", &d3d11_create_device)) { - s_swap_chain_texture.reset(); + PanicAlertT("Failed to load d3d11.dll"); + s_d3d11_library.Close(); return false; } - SetDebugObjectName(texture, "backbuffer texture"); - SetDebugObjectName(rtv, "backbuffer render target view"); - s_swap_chain_framebuffer = std::make_unique( - s_swap_chain_texture.get(), nullptr, AbstractTextureFormat::RGBA8, - AbstractTextureFormat::Undefined, desc.Width, desc.Height, desc.ArraySize, - desc.SampleDesc.Count, rtv, nullptr, nullptr); - - return true; -} - -static bool CreateSwapChain(HWND hWnd) -{ - DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {}; - swap_chain_desc.BufferCount = 2; - swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swap_chain_desc.SampleDesc.Count = 1; - swap_chain_desc.SampleDesc.Quality = 0; - swap_chain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - swap_chain_desc.Scaling = DXGI_SCALING_STRETCH; - swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; - swap_chain_desc.Stereo = g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer; - - // This flag is necessary if we want to use a flip-model swapchain without locking the framerate - swap_chain_desc.Flags = s_allow_tearing_supported ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0; - - HRESULT hr = s_dxgi_factory->CreateSwapChainForHwnd(device, hWnd, &swap_chain_desc, nullptr, - nullptr, &swapchain); - if (FAILED(hr)) + if (!D3DCommon::LoadLibraries()) { - // Flip-model discard swapchains aren't supported on Windows 8, so here we fall back to - // a sequential swapchain - swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; - hr = s_dxgi_factory->CreateSwapChainForHwnd(device, hWnd, &swap_chain_desc, nullptr, nullptr, - &swapchain); - } - - if (FAILED(hr)) - { - // Flip-model swapchains aren't supported on Windows 7, so here we fall back to a legacy - // BitBlt-model swapchain - swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; - hr = s_dxgi_factory->CreateSwapChainForHwnd(device, hWnd, &swap_chain_desc, nullptr, nullptr, - &swapchain); - } - - if (FAILED(hr)) - { - ERROR_LOG(VIDEO, "Failed to create swap chain with HRESULT %08X", hr); + s_d3d11_library.Close(); return false; } - if (!CreateSwapChainFramebuffer()) + dxgi_factory = D3DCommon::CreateDXGIFactory(enable_debug_layer); + if (!dxgi_factory) { - SAFE_RELEASE(swapchain); + PanicAlertT("Failed to create DXGI factory"); + D3DCommon::UnloadLibraries(); + s_d3d11_library.Close(); return false; } - return true; -} - -HRESULT Create(HWND wnd) -{ - HRESULT hr = LoadDXGI(); - if (SUCCEEDED(hr)) - hr = LoadD3D(); - if (SUCCEEDED(hr)) - hr = LoadD3DCompiler(); + ComPtr adapter; + HRESULT hr = dxgi_factory->EnumAdapters(adapter_index, &adapter); if (FAILED(hr)) { - UnloadDXGI(); - UnloadD3D(); - UnloadD3DCompiler(); - return hr; + WARN_LOG(VIDEO, "Adapter %u not found, using default", adapter_index); + adapter = nullptr; } - hr = PCreateDXGIFactory(__uuidof(IDXGIFactory2), (void**)&s_dxgi_factory); - if (FAILED(hr)) - MessageBox(wnd, _T("Failed to create IDXGIFactory object"), _T("Dolphin Direct3D 11 backend"), - MB_OK | MB_ICONERROR); - - IDXGIAdapter* adapter; - hr = s_dxgi_factory->EnumAdapters(g_ActiveConfig.iAdapter, &adapter); - if (FAILED(hr)) - { - // try using the first one - hr = s_dxgi_factory->EnumAdapters(0, &adapter); - if (FAILED(hr)) - MessageBox(wnd, _T("Failed to enumerate adapters"), _T("Dolphin Direct3D 11 backend"), - MB_OK | MB_ICONERROR); - } - - // get supported AA modes - s_aa_modes = EnumAAModes(adapter); - - if (std::find_if(s_aa_modes.begin(), s_aa_modes.end(), [](const DXGI_SAMPLE_DESC& desc) { - return desc.Count == g_Config.iMultisamples; - }) == s_aa_modes.end()) - { - Config::SetCurrent(Config::GFX_MSAA, UINT32_C(1)); - UpdateActiveConfig(); - } - - // Check support for allow tearing, we query the interface for backwards compatibility - UINT allow_tearing = FALSE; - IDXGIFactory5* factory5; - hr = s_dxgi_factory->QueryInterface(&factory5); - if (SUCCEEDED(hr)) - { - hr = factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing, - sizeof(allow_tearing)); - factory5->Release(); - } - s_allow_tearing_supported = SUCCEEDED(hr) && allow_tearing; - // Creating debug devices can sometimes fail if the user doesn't have the correct // version of the DirectX SDK. If it does, simply fallback to a non-debug device. - if (g_Config.bEnableValidationLayer) + if (enable_debug_layer) { - hr = s_d3d11_create_device(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_DEBUG, - supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, - D3D11_SDK_VERSION, &device, &s_featlevel, &context); + hr = d3d11_create_device(adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, + D3D11_CREATE_DEVICE_DEBUG, s_supported_feature_levels, + static_cast(ArraySize(s_supported_feature_levels)), + D3D11_SDK_VERSION, &device, &feature_level, &context); // Debugbreak on D3D error - if (SUCCEEDED(hr) && SUCCEEDED(device->QueryInterface(__uuidof(ID3D11Debug), (void**)&s_debug))) + if (SUCCEEDED(hr) && SUCCEEDED(device->QueryInterface(IID_PPV_ARGS(&s_debug)))) { - ID3D11InfoQueue* infoQueue = nullptr; - if (SUCCEEDED(s_debug->QueryInterface(__uuidof(ID3D11InfoQueue), (void**)&infoQueue))) + ComPtr info_queue; + if (SUCCEEDED(s_debug->QueryInterface(IID_PPV_ARGS(&info_queue)))) { - infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true); - infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true); + info_queue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true); + info_queue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true); D3D11_MESSAGE_ID hide[] = {D3D11_MESSAGE_ID_SETPRIVATEDATA_CHANGINGPARAMS}; D3D11_INFO_QUEUE_FILTER filter = {}; filter.DenyList.NumIDs = sizeof(hide) / sizeof(D3D11_MESSAGE_ID); filter.DenyList.pIDList = hide; - infoQueue->AddStorageFilterEntries(&filter); - infoQueue->Release(); + info_queue->AddStorageFilterEntries(&filter); } } + else + { + WARN_LOG(VIDEO, "Debug layer requested but not available."); + } } - if (!g_Config.bEnableValidationLayer || FAILED(hr)) + if (!enable_debug_layer || FAILED(hr)) { - hr = s_d3d11_create_device(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, - supported_feature_levels, NUM_SUPPORTED_FEATURE_LEVELS, - D3D11_SDK_VERSION, &device, &s_featlevel, &context); + hr = d3d11_create_device(adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, + s_supported_feature_levels, + static_cast(ArraySize(s_supported_feature_levels)), + D3D11_SDK_VERSION, &device, &feature_level, &context); } - SAFE_RELEASE(adapter); - - if (FAILED(hr) || (wnd && !CreateSwapChain(wnd))) + if (FAILED(hr)) { - MessageBox( - wnd, - _T("Failed to initialize Direct3D.\nMake sure your video card supports at least D3D 10.0"), - _T("Dolphin Direct3D 11 backend"), MB_OK | MB_ICONERROR); - SAFE_RELEASE(device); - SAFE_RELEASE(context); - SAFE_RELEASE(s_dxgi_factory); - return E_FAIL; + PanicAlertT( + "Failed to initialize Direct3D.\nMake sure your video card supports at least D3D 10.0"); + D3DCommon::UnloadLibraries(); + return false; } - hr = device->QueryInterface(&device1); + hr = device->QueryInterface(IID_PPV_ARGS(&device1)); if (FAILED(hr)) { WARN_LOG(VIDEO, "Missing Direct3D 11.1 support. Logical operations will not be supported."); g_Config.backend_info.bSupportsLogicOp = false; } - // BGRA textures are easier to deal with in TextureCache, but might not be supported - UINT format_support; - device->CheckFormatSupport(DXGI_FORMAT_B8G8R8A8_UNORM, &format_support); - s_bgra_textures_supported = (format_support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0; - g_Config.backend_info.bSupportsST3CTextures = SupportsS3TCTextures(device); - g_Config.backend_info.bSupportsBPTCTextures = SupportsBPTCTextures(device); + g_Config.backend_info.bSupportsST3CTextures = SupportsS3TCTextures(); + g_Config.backend_info.bSupportsBPTCTextures = SupportsBPTCTextures(); - // prevent DXGI from responding to Alt+Enter, unfortunately DXGI_MWA_NO_ALT_ENTER - // does not work so we disable all monitoring of window messages. However this - // may make it more difficult for DXGI to handle display mode changes. - if (wnd) - { - hr = s_dxgi_factory->MakeWindowAssociation(wnd, DXGI_MWA_NO_WINDOW_CHANGES); - if (FAILED(hr)) - MessageBox(wnd, _T("Failed to associate the window"), _T("Dolphin Direct3D 11 backend"), - MB_OK | MB_ICONERROR); - } + // Features only supported with a FL11.0+ device. + const bool shader_model_5_supported = feature_level >= D3D_FEATURE_LEVEL_11_0; + g_Config.backend_info.bSupportsEarlyZ = shader_model_5_supported; + g_Config.backend_info.bSupportsBBox = shader_model_5_supported; + g_Config.backend_info.bSupportsFragmentStoresAndAtomics = shader_model_5_supported; + g_Config.backend_info.bSupportsGSInstancing = shader_model_5_supported; + g_Config.backend_info.bSupportsSSAA = shader_model_5_supported; - SetDebugObjectName(context, "device context"); - - stateman = new StateManager; - return S_OK; + stateman = std::make_unique(); + return true; } -void Close() +void Destroy() { - // we can't release the swapchain while in fullscreen. - if (swapchain) - swapchain->SetFullscreenState(false, nullptr); + stateman.reset(); - // release all bound resources context->ClearState(); - s_swap_chain_framebuffer.reset(); - s_swap_chain_texture.reset(); - SAFE_RELEASE(swapchain); - SAFE_DELETE(stateman); - context->Flush(); // immediately destroy device objects + context->Flush(); - SAFE_RELEASE(context); - SAFE_RELEASE(device1); - ULONG references = device->Release(); + context.Reset(); + device1.Reset(); + auto remaining_references = device.Reset(); if (s_debug) { - --references; // the debug interface increases the refcount of the device, subtract that. - if (references) + --remaining_references; // the debug interface increases the refcount of the device, subtract + // that. + if (remaining_references) { // print out alive objects, but only if we actually have pending references // note this will also print out internal live objects to the debug console s_debug->ReportLiveDeviceObjects(D3D11_RLDO_SUMMARY | D3D11_RLDO_DETAIL); } - SAFE_RELEASE(s_debug) + s_debug.Reset(); } - if (references) - { - ERROR_LOG(VIDEO, "Unreleased references: %i.", references); - } + if (remaining_references) + ERROR_LOG(VIDEO, "Unreleased references: %i.", remaining_references); else - { NOTICE_LOG(VIDEO, "Successfully released all device references!"); - } - device = nullptr; - // unload DLLs - UnloadD3D(); - UnloadDXGI(); + D3DCommon::UnloadLibraries(); + s_d3d11_library.Close(); } -const char* VertexShaderVersionString() +std::vector GetAAModes(u32 adapter_index) { - if (s_featlevel == D3D_FEATURE_LEVEL_11_0) - return "vs_5_0"; - else if (s_featlevel == D3D_FEATURE_LEVEL_10_1) - return "vs_4_1"; - else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ - return "vs_4_0"; -} - -const char* GeometryShaderVersionString() -{ - if (s_featlevel == D3D_FEATURE_LEVEL_11_0) - return "gs_5_0"; - else if (s_featlevel == D3D_FEATURE_LEVEL_10_1) - return "gs_4_1"; - else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ - return "gs_4_0"; -} - -const char* PixelShaderVersionString() -{ - if (s_featlevel == D3D_FEATURE_LEVEL_11_0) - return "ps_5_0"; - else if (s_featlevel == D3D_FEATURE_LEVEL_10_1) - return "ps_4_1"; - else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ - return "ps_4_0"; -} - -const char* ComputeShaderVersionString() -{ - if (s_featlevel == D3D_FEATURE_LEVEL_11_0) - return "cs_5_0"; - else if (s_featlevel == D3D_FEATURE_LEVEL_10_1) - return "cs_4_1"; - else /*if(featlevel == D3D_FEATURE_LEVEL_10_0)*/ - return "cs_4_0"; -} - -DXTexture* GetSwapChainTexture() -{ - return s_swap_chain_texture.get(); -} -DXFramebuffer* GetSwapChainFramebuffer() -{ - return s_swap_chain_framebuffer.get(); -} -bool BGRATexturesSupported() -{ - return s_bgra_textures_supported; -} - -bool AllowTearingSupported() -{ - return s_allow_tearing_supported; -} - -// Returns the maximum width/height of a texture. This value only depends upon the feature level in -// DX11 -u32 GetMaxTextureSize(D3D_FEATURE_LEVEL feature_level) -{ - switch (feature_level) + // Use temporary device if we don't have one already. + Common::DynamicLibrary temp_lib; + ComPtr temp_device = device; + if (!temp_device) { - case D3D_FEATURE_LEVEL_11_0: - return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; + ComPtr temp_dxgi_factory = D3DCommon::CreateDXGIFactory(false); + if (!temp_dxgi_factory) + return {}; - case D3D_FEATURE_LEVEL_10_1: - case D3D_FEATURE_LEVEL_10_0: - return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION; + ComPtr adapter; + temp_dxgi_factory->EnumAdapters(adapter_index, &adapter); - case D3D_FEATURE_LEVEL_9_3: - return 4096; + PFN_D3D11_CREATE_DEVICE d3d11_create_device; + if (!temp_lib.Open("d3d11.dll") || + !temp_lib.GetSymbol("D3D11CreateDevice", &d3d11_create_device)) + { + return {}; + } - case D3D_FEATURE_LEVEL_9_2: - case D3D_FEATURE_LEVEL_9_1: - return 2048; - - default: - return 0; + HRESULT hr = d3d11_create_device(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, + s_supported_feature_levels, + static_cast(ArraySize(s_supported_feature_levels)), + D3D11_SDK_VERSION, &temp_device, nullptr, nullptr); + if (FAILED(hr)) + return {}; } -} -void Reset(HWND new_wnd) -{ - s_swap_chain_framebuffer.reset(); - s_swap_chain_texture.reset(); + // NOTE: D3D 10.0 doesn't support multisampled resources which are bound as depth buffers AND + // shader resources. Thus, we can't have MSAA with 10.0 level hardware. + if (temp_device->GetFeatureLevel() == D3D_FEATURE_LEVEL_10_0) + return {}; - if (swapchain) + std::vector aa_modes; + for (u32 samples = 1; samples < D3D11_MAX_MULTISAMPLE_SAMPLE_COUNT; ++samples) { - if (GetFullscreenState()) - swapchain->SetFullscreenState(FALSE, nullptr); - SAFE_RELEASE(swapchain); + UINT quality_levels = 0; + if (SUCCEEDED(temp_device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM, samples, + &quality_levels)) && + quality_levels > 0) + { + aa_modes.push_back(samples); + } } - if (new_wnd) - CreateSwapChain(new_wnd); + return aa_modes; } - -void ResizeSwapChain() -{ - s_swap_chain_framebuffer.reset(); - s_swap_chain_texture.reset(); - const UINT swap_chain_flags = AllowTearingSupported() ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0; - swapchain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_R8G8B8A8_UNORM, swap_chain_flags); - if (!CreateSwapChainFramebuffer()) - { - PanicAlert("Failed to get swap chain textures"); - SAFE_RELEASE(swapchain); - } -} - -void Present() -{ - UINT present_flags = 0; - - // When using sync interval 0, it is recommended to always pass the tearing - // flag when it is supported, even when presenting in windowed mode. - // However, this flag cannot be used if the app is in fullscreen mode as a - // result of calling SetFullscreenState. - if (AllowTearingSupported() && !g_ActiveConfig.bVSyncActive && !GetFullscreenState()) - present_flags |= DXGI_PRESENT_ALLOW_TEARING; - - if (swapchain->IsTemporaryMonoSupported() && g_ActiveConfig.stereo_mode != StereoMode::QuadBuffer) - { - present_flags |= DXGI_PRESENT_STEREO_TEMPORARY_MONO; - } - - // TODO: Is 1 the correct value for vsyncing? - swapchain->Present(static_cast(g_ActiveConfig.bVSyncActive), present_flags); -} - -HRESULT SetFullscreenState(bool enable_fullscreen) -{ - return swapchain->SetFullscreenState(enable_fullscreen, nullptr); -} - -bool GetFullscreenState() -{ - BOOL state = FALSE; - swapchain->GetFullscreenState(&state, nullptr); - return !!state; -} - -void SetDebugObjectName(ID3D11DeviceChild* resource, const char* name) -{ -#if defined(_DEBUG) || defined(DEBUGFAST) - if (resource) - resource->SetPrivateData(WKPDID_D3DDebugObjectName, (UINT)(name ? strlen(name) : 0), name); -#endif -} - -std::string GetDebugObjectName(ID3D11DeviceChild* resource) -{ - std::string name; -#if defined(_DEBUG) || defined(DEBUGFAST) - if (resource) - { - UINT size = 0; - resource->GetPrivateData(WKPDID_D3DDebugObjectName, &size, nullptr); // get required size - name.resize(size); - resource->GetPrivateData(WKPDID_D3DDebugObjectName, &size, const_cast(name.data())); - } -#endif - return name; -} - } // namespace D3D } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/D3DBase.h b/Source/Core/VideoBackends/D3D/D3DBase.h index fedb2fe0c4..5c92c9b18f 100644 --- a/Source/Core/VideoBackends/D3D/D3DBase.h +++ b/Source/Core/VideoBackends/D3D/D3DBase.h @@ -9,90 +9,37 @@ #include #include #include +#include #include "Common/Common.h" #include "Common/CommonTypes.h" #include "Common/MsgHandler.h" -namespace DX11 -{ -#define SAFE_RELEASE(x) \ - { \ - if (x) \ - (x)->Release(); \ - (x) = nullptr; \ - } -#define SAFE_DELETE(x) \ - { \ - delete (x); \ - (x) = nullptr; \ - } -#define SAFE_DELETE_ARRAY(x) \ - { \ - delete[](x); \ - (x) = nullptr; \ - } #define CHECK(cond, Message, ...) \ if (!(cond)) \ { \ PanicAlert("%s failed in %s at line %d: " Message, __func__, __FILE__, __LINE__, __VA_ARGS__); \ } -class DXTexture; -class DXFramebuffer; +namespace DX11 +{ +using Microsoft::WRL::ComPtr; +class SwapChain; namespace D3D { -HRESULT LoadDXGI(); -HRESULT LoadD3D(); -HRESULT LoadD3DCompiler(); -void UnloadDXGI(); -void UnloadD3D(); -void UnloadD3DCompiler(); +extern ComPtr dxgi_factory; +extern ComPtr device; +extern ComPtr device1; +extern ComPtr context; +extern D3D_FEATURE_LEVEL feature_level; -D3D_FEATURE_LEVEL GetFeatureLevel(IDXGIAdapter* adapter); -std::vector EnumAAModes(IDXGIAdapter* adapter); +bool Create(u32 adapter_index, bool enable_debug_layer); +void Destroy(); -HRESULT Create(HWND wnd); -void Close(); - -extern ID3D11Device* device; -extern ID3D11Device1* device1; -extern ID3D11DeviceContext* context; -extern IDXGISwapChain1* swapchain; - -void Reset(HWND new_wnd); -void ResizeSwapChain(); -void Present(); - -DXTexture* GetSwapChainTexture(); -DXFramebuffer* GetSwapChainFramebuffer(); -const char* PixelShaderVersionString(); -const char* GeometryShaderVersionString(); -const char* VertexShaderVersionString(); -const char* ComputeShaderVersionString(); -bool BGRATexturesSupported(); -bool AllowTearingSupported(); - -u32 GetMaxTextureSize(D3D_FEATURE_LEVEL feature_level); - -HRESULT SetFullscreenState(bool enable_fullscreen); -bool GetFullscreenState(); - -// This function will assign a name to the given resource. -// The DirectX debug layer will make it easier to identify resources that way, -// e.g. when listing up all resources who have unreleased references. -void SetDebugObjectName(ID3D11DeviceChild* resource, const char* name); -std::string GetDebugObjectName(ID3D11DeviceChild* resource); +// Returns a list of supported AA modes for the current device. +std::vector GetAAModes(u32 adapter_index); } // namespace D3D -typedef HRESULT(WINAPI* CREATEDXGIFACTORY)(REFIID, void**); -extern CREATEDXGIFACTORY PCreateDXGIFactory; -typedef HRESULT(WINAPI* D3D11CREATEDEVICE)(IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, UINT, - CONST D3D_FEATURE_LEVEL*, UINT, UINT, ID3D11Device**, - D3D_FEATURE_LEVEL*, ID3D11DeviceContext**); - -extern pD3DCompile PD3DCompile; - } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/D3DState.cpp b/Source/Core/VideoBackends/D3D/D3DState.cpp index 72528e51d6..15e84f2018 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D/D3DState.cpp @@ -13,13 +13,14 @@ #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/DXTexture.h" +#include "VideoBackends/D3DCommon/Common.h" #include "VideoCommon/VideoConfig.h" namespace DX11 { namespace D3D { -StateManager* stateman; +std::unique_ptr stateman; StateManager::StateManager() = default; StateManager::~StateManager() = default; @@ -298,27 +299,14 @@ void StateManager::SyncComputeBindings() } } // namespace D3D -StateCache::~StateCache() -{ - for (auto& it : m_depth) - SAFE_RELEASE(it.second); - - for (auto& it : m_raster) - SAFE_RELEASE(it.second); - - for (auto& it : m_blend) - SAFE_RELEASE(it.second); - - for (auto& it : m_sampler) - SAFE_RELEASE(it.second); -} +StateCache::~StateCache() = default; ID3D11SamplerState* StateCache::Get(SamplerState state) { std::lock_guard guard(m_lock); auto it = m_sampler.find(state.hex); if (it != m_sampler.end()) - return it->second; + return it->second.Get(); D3D11_SAMPLER_DESC sampdc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT()); if (state.mipmap_filter == SamplerState::Filter::Linear) @@ -358,14 +346,11 @@ ID3D11SamplerState* StateCache::Get(SamplerState state) sampdc.MaxAnisotropy = 1u << g_ActiveConfig.iMaxAnisotropy; } - ID3D11SamplerState* res = nullptr; + ComPtr res; HRESULT hr = D3D::device->CreateSamplerState(&sampdc, &res); - if (FAILED(hr)) - PanicAlert("Fail %s %d\n", __FILE__, __LINE__); - - D3D::SetDebugObjectName(res, "sampler state used to emulate the GX pipeline"); + CHECK(SUCCEEDED(hr), "Creating D3D sampler state failed"); m_sampler.emplace(state.hex, res); - return res; + return res.Get(); } ID3D11BlendState* StateCache::Get(BlendingState state) @@ -373,7 +358,7 @@ ID3D11BlendState* StateCache::Get(BlendingState state) std::lock_guard guard(m_lock); auto it = m_blend.find(state.hex); if (it != m_blend.end()) - return it->second; + return it->second.Get(); if (state.logicopenable && D3D::device1) { @@ -400,7 +385,6 @@ ID3D11BlendState* StateCache::Get(BlendingState state) HRESULT hr = D3D::device1->CreateBlendState1(&desc, &res); if (SUCCEEDED(hr)) { - D3D::SetDebugObjectName(res, "blend state used to emulate the GX pipeline"); m_blend.emplace(state.hex, res); return res; } @@ -440,15 +424,11 @@ ID3D11BlendState* StateCache::Get(BlendingState state) tdesc.BlendOp = state.subtract ? D3D11_BLEND_OP_REV_SUBTRACT : D3D11_BLEND_OP_ADD; tdesc.BlendOpAlpha = state.subtractAlpha ? D3D11_BLEND_OP_REV_SUBTRACT : D3D11_BLEND_OP_ADD; - ID3D11BlendState* res = nullptr; - + ComPtr res; HRESULT hr = D3D::device->CreateBlendState(&desc, &res); - if (FAILED(hr)) - PanicAlert("Failed to create blend state at %s %d\n", __FILE__, __LINE__); - - D3D::SetDebugObjectName(res, "blend state used to emulate the GX pipeline"); + CHECK(SUCCEEDED(hr), "Creating D3D blend state failed"); m_blend.emplace(state.hex, res); - return res; + return res.Get(); } ID3D11RasterizerState* StateCache::Get(RasterizationState state) @@ -456,7 +436,7 @@ ID3D11RasterizerState* StateCache::Get(RasterizationState state) std::lock_guard guard(m_lock); auto it = m_raster.find(state.hex); if (it != m_raster.end()) - return it->second; + return it->second.Get(); static constexpr std::array cull_modes = { {D3D11_CULL_NONE, D3D11_CULL_BACK, D3D11_CULL_FRONT, D3D11_CULL_BACK}}; @@ -466,14 +446,11 @@ ID3D11RasterizerState* StateCache::Get(RasterizationState state) desc.CullMode = cull_modes[state.cullmode]; desc.ScissorEnable = TRUE; - ID3D11RasterizerState* res = nullptr; + ComPtr res; HRESULT hr = D3D::device->CreateRasterizerState(&desc, &res); - if (FAILED(hr)) - PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__); - - D3D::SetDebugObjectName(res, "rasterizer state used to emulate the GX pipeline"); + CHECK(SUCCEEDED(hr), "Creating D3D rasterizer state failed"); m_raster.emplace(state.hex, res); - return res; + return res.Get(); } ID3D11DepthStencilState* StateCache::Get(DepthState state) @@ -481,7 +458,7 @@ ID3D11DepthStencilState* StateCache::Get(DepthState state) std::lock_guard guard(m_lock); auto it = m_depth.find(state.hex); if (it != m_depth.end()) - return it->second; + return it->second.Get(); D3D11_DEPTH_STENCIL_DESC depthdc = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT()); @@ -512,17 +489,11 @@ ID3D11DepthStencilState* StateCache::Get(DepthState state) depthdc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; } - ID3D11DepthStencilState* res = nullptr; - + ComPtr res; HRESULT hr = D3D::device->CreateDepthStencilState(&depthdc, &res); - if (SUCCEEDED(hr)) - D3D::SetDebugObjectName(res, "depth-stencil state used to emulate the GX pipeline"); - else - PanicAlert("Failed to create depth state at %s %d\n", __FILE__, __LINE__); - + CHECK(SUCCEEDED(hr), "Creating D3D depth stencil state failed"); m_depth.emplace(state.hex, res); - - return res; + return res.Get(); } D3D11_PRIMITIVE_TOPOLOGY StateCache::GetPrimitiveTopology(PrimitiveType primitive) diff --git a/Source/Core/VideoBackends/D3D/D3DState.h b/Source/Core/VideoBackends/D3D/D3DState.h index 66542c6250..c152907389 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.h +++ b/Source/Core/VideoBackends/D3D/D3DState.h @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -34,10 +35,10 @@ public: static D3D11_PRIMITIVE_TOPOLOGY GetPrimitiveTopology(PrimitiveType primitive); private: - std::unordered_map m_depth; - std::unordered_map m_raster; - std::unordered_map m_blend; - std::unordered_map m_sampler; + std::unordered_map> m_depth; + std::unordered_map> m_raster; + std::unordered_map> m_blend; + std::unordered_map> m_sampler; std::mutex m_lock; }; @@ -296,7 +297,7 @@ private: ID3D11ComputeShader* m_compute_shader = nullptr; }; -extern StateManager* stateman; +extern std::unique_ptr stateman; } // namespace D3D diff --git a/Source/Core/VideoBackends/D3D/DXPipeline.cpp b/Source/Core/VideoBackends/D3D/DXPipeline.cpp index 9c694d20cd..bc48ce061d 100644 --- a/Source/Core/VideoBackends/D3D/DXPipeline.cpp +++ b/Source/Core/VideoBackends/D3D/DXPipeline.cpp @@ -28,39 +28,9 @@ DXPipeline::DXPipeline(ID3D11InputLayout* input_layout, ID3D11VertexShader* vert m_rasterizer_state(rasterizer_state), m_depth_state(depth_state), m_blend_state(blend_state), m_primitive_topology(primitive_topology), m_use_logic_op(use_logic_op) { - if (m_input_layout) - m_input_layout->AddRef(); - if (m_vertex_shader) - m_vertex_shader->AddRef(); - if (m_geometry_shader) - m_geometry_shader->AddRef(); - if (m_pixel_shader) - m_pixel_shader->AddRef(); - if (m_rasterizer_state) - m_rasterizer_state->AddRef(); - if (m_depth_state) - m_depth_state->AddRef(); - if (m_blend_state) - m_blend_state->AddRef(); } -DXPipeline::~DXPipeline() -{ - if (m_input_layout) - m_input_layout->Release(); - if (m_vertex_shader) - m_vertex_shader->Release(); - if (m_geometry_shader) - m_geometry_shader->Release(); - if (m_pixel_shader) - m_pixel_shader->Release(); - if (m_rasterizer_state) - m_rasterizer_state->Release(); - if (m_depth_state) - m_depth_state->Release(); - if (m_blend_state) - m_blend_state->Release(); -} +DXPipeline::~DXPipeline() = default; std::unique_ptr DXPipeline::Create(const AbstractPipelineConfig& config) { @@ -71,12 +41,7 @@ std::unique_ptr DXPipeline::Create(const AbstractPipelineConfig& con D3D11_PRIMITIVE_TOPOLOGY primitive_topology = StateCache::GetPrimitiveTopology(config.rasterization_state.primitive); if (!rasterizer_state || !depth_state || !blend_state) - { - SAFE_RELEASE(rasterizer_state); - SAFE_RELEASE(depth_state); - SAFE_RELEASE(blend_state); return nullptr; - } const DXShader* vertex_shader = static_cast(config.vertex_shader); const DXShader* geometry_shader = static_cast(config.geometry_shader); diff --git a/Source/Core/VideoBackends/D3D/DXPipeline.h b/Source/Core/VideoBackends/D3D/DXPipeline.h index 3a03bf948d..28e2369405 100644 --- a/Source/Core/VideoBackends/D3D/DXPipeline.h +++ b/Source/Core/VideoBackends/D3D/DXPipeline.h @@ -20,13 +20,13 @@ public: bool use_logic_op); ~DXPipeline() override; - ID3D11InputLayout* GetInputLayout() const { return m_input_layout; } - ID3D11VertexShader* GetVertexShader() const { return m_vertex_shader; } - ID3D11GeometryShader* GetGeometryShader() const { return m_geometry_shader; } - ID3D11PixelShader* GetPixelShader() const { return m_pixel_shader; } - ID3D11RasterizerState* GetRasterizerState() const { return m_rasterizer_state; } - ID3D11DepthStencilState* GetDepthState() const { return m_depth_state; } - ID3D11BlendState* GetBlendState() const { return m_blend_state; } + ID3D11InputLayout* GetInputLayout() const { return m_input_layout.Get(); } + ID3D11VertexShader* GetVertexShader() const { return m_vertex_shader.Get(); } + ID3D11GeometryShader* GetGeometryShader() const { return m_geometry_shader.Get(); } + ID3D11PixelShader* GetPixelShader() const { return m_pixel_shader.Get(); } + ID3D11RasterizerState* GetRasterizerState() const { return m_rasterizer_state.Get(); } + ID3D11DepthStencilState* GetDepthState() const { return m_depth_state.Get(); } + ID3D11BlendState* GetBlendState() const { return m_blend_state.Get(); } D3D11_PRIMITIVE_TOPOLOGY GetPrimitiveTopology() const { return m_primitive_topology; } bool HasGeometryShader() const { return m_geometry_shader != nullptr; } bool UseLogicOp() const { return m_use_logic_op; } @@ -34,13 +34,13 @@ public: static std::unique_ptr Create(const AbstractPipelineConfig& config); private: - ID3D11InputLayout* m_input_layout; - ID3D11VertexShader* m_vertex_shader; - ID3D11GeometryShader* m_geometry_shader; - ID3D11PixelShader* m_pixel_shader; - ID3D11RasterizerState* m_rasterizer_state; - ID3D11DepthStencilState* m_depth_state; - ID3D11BlendState* m_blend_state; + ComPtr m_input_layout; + ComPtr m_vertex_shader; + ComPtr m_geometry_shader; + ComPtr m_pixel_shader; + ComPtr m_rasterizer_state; + ComPtr m_depth_state; + ComPtr m_blend_state; D3D11_PRIMITIVE_TOPOLOGY m_primitive_topology; bool m_use_logic_op; }; diff --git a/Source/Core/VideoBackends/D3D/DXShader.cpp b/Source/Core/VideoBackends/D3D/DXShader.cpp index 18f9aa0d3d..8365a63c6d 100644 --- a/Source/Core/VideoBackends/D3D/DXShader.cpp +++ b/Source/Core/VideoBackends/D3D/DXShader.cpp @@ -2,62 +2,41 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. -#include - -#include "Common/Assert.h" -#include "Common/FileUtil.h" -#include "Common/Logging/Log.h" -#include "Common/MsgHandler.h" -#include "Common/StringUtil.h" - -#include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/DXShader.h" -#include "VideoCommon/VideoConfig.h" +#include "Common/Assert.h" +#include "VideoBackends/D3D/D3DBase.h" namespace DX11 { DXShader::DXShader(ShaderStage stage, BinaryData bytecode, ID3D11DeviceChild* shader) - : AbstractShader(stage), m_bytecode(bytecode), m_shader(shader) + : D3DCommon::Shader(stage, std::move(bytecode)), m_shader(shader) { } -DXShader::~DXShader() -{ - m_shader->Release(); -} +DXShader::~DXShader() = default; ID3D11VertexShader* DXShader::GetD3DVertexShader() const { DEBUG_ASSERT(m_stage == ShaderStage::Vertex); - return static_cast(m_shader); + return static_cast(m_shader.Get()); } ID3D11GeometryShader* DXShader::GetD3DGeometryShader() const { DEBUG_ASSERT(m_stage == ShaderStage::Geometry); - return static_cast(m_shader); + return static_cast(m_shader.Get()); } ID3D11PixelShader* DXShader::GetD3DPixelShader() const { DEBUG_ASSERT(m_stage == ShaderStage::Pixel); - return static_cast(m_shader); + return static_cast(m_shader.Get()); } ID3D11ComputeShader* DXShader::GetD3DComputeShader() const { DEBUG_ASSERT(m_stage == ShaderStage::Compute); - return static_cast(m_shader); -} - -bool DXShader::HasBinary() const -{ - return true; -} - -AbstractShader::BinaryData DXShader::GetBinary() const -{ - return m_bytecode; + return static_cast(m_shader.Get()); } std::unique_ptr DXShader::CreateFromBytecode(ShaderStage stage, BinaryData bytecode) @@ -66,48 +45,48 @@ std::unique_ptr DXShader::CreateFromBytecode(ShaderStage stage, Binary { case ShaderStage::Vertex: { - ID3D11VertexShader* vs; + ComPtr vs; HRESULT hr = D3D::device->CreateVertexShader(bytecode.data(), bytecode.size(), nullptr, &vs); CHECK(SUCCEEDED(hr), "Create vertex shader"); if (FAILED(hr)) return nullptr; - return std::make_unique(ShaderStage::Vertex, std::move(bytecode), vs); + return std::make_unique(ShaderStage::Vertex, std::move(bytecode), vs.Get()); } case ShaderStage::Geometry: { - ID3D11GeometryShader* gs; + ComPtr gs; HRESULT hr = D3D::device->CreateGeometryShader(bytecode.data(), bytecode.size(), nullptr, &gs); CHECK(SUCCEEDED(hr), "Create geometry shader"); if (FAILED(hr)) return nullptr; - return std::make_unique(ShaderStage::Geometry, std::move(bytecode), gs); + return std::make_unique(ShaderStage::Geometry, std::move(bytecode), gs.Get()); } break; case ShaderStage::Pixel: { - ID3D11PixelShader* ps; + ComPtr ps; HRESULT hr = D3D::device->CreatePixelShader(bytecode.data(), bytecode.size(), nullptr, &ps); CHECK(SUCCEEDED(hr), "Create pixel shader"); if (FAILED(hr)) return nullptr; - return std::make_unique(ShaderStage::Pixel, std::move(bytecode), ps); + return std::make_unique(ShaderStage::Pixel, std::move(bytecode), ps.Get()); } break; case ShaderStage::Compute: { - ID3D11ComputeShader* cs; + ComPtr cs; HRESULT hr = D3D::device->CreateComputeShader(bytecode.data(), bytecode.size(), nullptr, &cs); CHECK(SUCCEEDED(hr), "Create compute shader"); if (FAILED(hr)) return nullptr; - return std::make_unique(ShaderStage::Compute, std::move(bytecode), cs); + return std::make_unique(ShaderStage::Compute, std::move(bytecode), cs.Get()); } break; @@ -117,86 +96,4 @@ std::unique_ptr DXShader::CreateFromBytecode(ShaderStage stage, Binary return nullptr; } - -static const char* GetCompileTarget(ShaderStage stage) -{ - switch (stage) - { - case ShaderStage::Vertex: - return D3D::VertexShaderVersionString(); - case ShaderStage::Geometry: - return D3D::GeometryShaderVersionString(); - case ShaderStage::Pixel: - return D3D::PixelShaderVersionString(); - case ShaderStage::Compute: - return D3D::ComputeShaderVersionString(); - default: - return ""; - } -} - -bool DXShader::CompileShader(BinaryData* out_bytecode, ShaderStage stage, const char* source, - size_t length) -{ - static constexpr D3D_SHADER_MACRO macros[] = {{"API_D3D", "1"}, {nullptr, nullptr}}; - const UINT flags = g_ActiveConfig.bEnableValidationLayer ? - (D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION) : - (D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_SKIP_VALIDATION); - const char* target = GetCompileTarget(stage); - - ID3DBlob* code = nullptr; - ID3DBlob* errors = nullptr; - HRESULT hr = PD3DCompile(source, length, nullptr, macros, nullptr, "main", target, flags, 0, - &code, &errors); - if (FAILED(hr)) - { - static int num_failures = 0; - std::string filename = StringFromFormat( - "%sbad_%s_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), target, num_failures++); - std::ofstream file; - File::OpenFStream(file, filename, std::ios_base::out); - file.write(source, length); - file << "\n"; - file.write(static_cast(errors->GetBufferPointer()), errors->GetBufferSize()); - file.close(); - - PanicAlert("Failed to compile %s:\nDebug info (%s):\n%s", filename.c_str(), target, - static_cast(errors->GetBufferPointer())); - errors->Release(); - return false; - } - - if (errors && errors->GetBufferSize() > 0) - { - WARN_LOG(VIDEO, "%s compilation succeeded with warnings:\n%s", target, - static_cast(errors->GetBufferPointer())); - } - SAFE_RELEASE(errors); - - out_bytecode->resize(code->GetBufferSize()); - std::memcpy(out_bytecode->data(), code->GetBufferPointer(), code->GetBufferSize()); - code->Release(); - return true; -} - -std::unique_ptr DXShader::CreateFromSource(ShaderStage stage, const char* source, - size_t length) -{ - BinaryData bytecode; - if (!CompileShader(&bytecode, stage, source, length)) - return nullptr; - - return CreateFromBytecode(stage, std::move(bytecode)); -} - -std::unique_ptr DXShader::CreateFromBinary(ShaderStage stage, const void* data, - size_t length) -{ - if (length == 0) - return nullptr; - - BinaryData bytecode(length); - std::memcpy(bytecode.data(), data, length); - return CreateFromBytecode(stage, std::move(bytecode)); -} } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/DXShader.h b/Source/Core/VideoBackends/D3D/DXShader.h index a86a993b80..1913322679 100644 --- a/Source/Core/VideoBackends/D3D/DXShader.h +++ b/Source/Core/VideoBackends/D3D/DXShader.h @@ -3,14 +3,14 @@ // Refer to the license.txt file included. #pragma once -#include #include -#include "VideoCommon/AbstractShader.h" +#include "VideoBackends/D3D/D3DBase.h" +#include "VideoBackends/D3DCommon/Shader.h" namespace DX11 { -class DXShader final : public AbstractShader +class DXShader final : public D3DCommon::Shader { public: DXShader(ShaderStage stage, BinaryData bytecode, ID3D11DeviceChild* shader); @@ -23,22 +23,10 @@ public: ID3D11PixelShader* GetD3DPixelShader() const; ID3D11ComputeShader* GetD3DComputeShader() const; - bool HasBinary() const override; - BinaryData GetBinary() const override; - - // Creates a new shader object. static std::unique_ptr CreateFromBytecode(ShaderStage stage, BinaryData bytecode); - static bool CompileShader(BinaryData* out_bytecode, ShaderStage stage, const char* source, - size_t length); - - static std::unique_ptr CreateFromBinary(ShaderStage stage, const void* data, - size_t length); - static std::unique_ptr CreateFromSource(ShaderStage stage, const char* source, - size_t length); private: - ID3D11DeviceChild* m_shader; - BinaryData m_bytecode; + ComPtr m_shader; }; } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/DXTexture.cpp b/Source/Core/VideoBackends/D3D/DXTexture.cpp index dc1c04991a..30737ff318 100644 --- a/Source/Core/VideoBackends/D3D/DXTexture.cpp +++ b/Source/Core/VideoBackends/D3D/DXTexture.cpp @@ -11,141 +11,27 @@ #include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/DXTexture.h" +#include "VideoBackends/D3DCommon/Common.h" namespace DX11 { -namespace -{ -DXGI_FORMAT GetDXGIFormatForHostFormat(AbstractTextureFormat format, bool typeless) -{ - switch (format) - { - case AbstractTextureFormat::DXT1: - return DXGI_FORMAT_BC1_UNORM; - case AbstractTextureFormat::DXT3: - return DXGI_FORMAT_BC2_UNORM; - case AbstractTextureFormat::DXT5: - return DXGI_FORMAT_BC3_UNORM; - case AbstractTextureFormat::BPTC: - return DXGI_FORMAT_BC7_UNORM; - case AbstractTextureFormat::RGBA8: - return typeless ? DXGI_FORMAT_R8G8B8A8_TYPELESS : DXGI_FORMAT_R8G8B8A8_UNORM; - case AbstractTextureFormat::BGRA8: - return typeless ? DXGI_FORMAT_B8G8R8A8_TYPELESS : DXGI_FORMAT_B8G8R8A8_UNORM; - case AbstractTextureFormat::R16: - return typeless ? DXGI_FORMAT_R16_TYPELESS : DXGI_FORMAT_R16_UNORM; - case AbstractTextureFormat::R32F: - return typeless ? DXGI_FORMAT_R32_TYPELESS : DXGI_FORMAT_R32_FLOAT; - case AbstractTextureFormat::D16: - return DXGI_FORMAT_R16_TYPELESS; - case AbstractTextureFormat::D24_S8: - return DXGI_FORMAT_R24G8_TYPELESS; - case AbstractTextureFormat::D32F: - return DXGI_FORMAT_R32_TYPELESS; - case AbstractTextureFormat::D32F_S8: - return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; - default: - PanicAlert("Unhandled texture format."); - return DXGI_FORMAT_R8G8B8A8_UNORM; - } -} -DXGI_FORMAT GetSRVFormatForHostFormat(AbstractTextureFormat format) -{ - switch (format) - { - case AbstractTextureFormat::DXT1: - return DXGI_FORMAT_BC1_UNORM; - case AbstractTextureFormat::DXT3: - return DXGI_FORMAT_BC2_UNORM; - case AbstractTextureFormat::DXT5: - return DXGI_FORMAT_BC3_UNORM; - case AbstractTextureFormat::BPTC: - return DXGI_FORMAT_BC7_UNORM; - case AbstractTextureFormat::RGBA8: - return DXGI_FORMAT_R8G8B8A8_UNORM; - case AbstractTextureFormat::BGRA8: - return DXGI_FORMAT_B8G8R8A8_UNORM; - case AbstractTextureFormat::R16: - return DXGI_FORMAT_R16_UNORM; - case AbstractTextureFormat::R32F: - return DXGI_FORMAT_R32_FLOAT; - case AbstractTextureFormat::D16: - return DXGI_FORMAT_R16_UNORM; - case AbstractTextureFormat::D24_S8: - return DXGI_FORMAT_R24_UNORM_X8_TYPELESS; - case AbstractTextureFormat::D32F: - return DXGI_FORMAT_R32_FLOAT; - case AbstractTextureFormat::D32F_S8: - return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; - default: - PanicAlert("Unhandled SRV format"); - return DXGI_FORMAT_UNKNOWN; - } -} -DXGI_FORMAT GetRTVFormatForHostFormat(AbstractTextureFormat format, bool integer) -{ - switch (format) - { - case AbstractTextureFormat::RGBA8: - return integer ? DXGI_FORMAT_R8G8B8A8_UINT : DXGI_FORMAT_R8G8B8A8_UNORM; - case AbstractTextureFormat::BGRA8: - return DXGI_FORMAT_B8G8R8A8_UNORM; - case AbstractTextureFormat::R16: - return integer ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R16_UNORM; - case AbstractTextureFormat::R32F: - return DXGI_FORMAT_R32_FLOAT; - default: - PanicAlert("Unhandled RTV format"); - return DXGI_FORMAT_UNKNOWN; - } -} -DXGI_FORMAT GetDSVFormatForHostFormat(AbstractTextureFormat format) -{ - switch (format) - { - case AbstractTextureFormat::D16: - return DXGI_FORMAT_D16_UNORM; - case AbstractTextureFormat::D24_S8: - return DXGI_FORMAT_D24_UNORM_S8_UINT; - case AbstractTextureFormat::D32F: - return DXGI_FORMAT_D32_FLOAT; - case AbstractTextureFormat::D32F_S8: - return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; - default: - PanicAlert("Unhandled DSV format"); - return DXGI_FORMAT_UNKNOWN; - } -} -} // Anonymous namespace - -DXTexture::DXTexture(const TextureConfig& tex_config, ID3D11Texture2D* d3d_texture, - ID3D11ShaderResourceView* d3d_srv, ID3D11UnorderedAccessView* d3d_uav) - : AbstractTexture(tex_config), m_d3d_texture(d3d_texture), m_d3d_srv(d3d_srv), - m_d3d_uav(d3d_uav) +DXTexture::DXTexture(const TextureConfig& config, ID3D11Texture2D* texture) + : AbstractTexture(config), m_texture(texture) { } DXTexture::~DXTexture() { - if (m_d3d_uav) - m_d3d_uav->Release(); - - if (m_d3d_srv) - { - if (D3D::stateman->UnsetTexture(m_d3d_srv) != 0) - D3D::stateman->ApplyTextures(); - - m_d3d_srv->Release(); - } - m_d3d_texture->Release(); + if (m_srv && D3D::stateman->UnsetTexture(m_srv.Get()) != 0) + D3D::stateman->ApplyTextures(); } std::unique_ptr DXTexture::Create(const TextureConfig& config) { // Use typeless to create the texture when it's a render target, so we can alias it with an // integer format (for EFB). - const DXGI_FORMAT tex_format = GetDXGIFormatForHostFormat(config.format, config.IsRenderTarget()); - const DXGI_FORMAT srv_format = GetSRVFormatForHostFormat(config.format); + const DXGI_FORMAT tex_format = + D3DCommon::GetDXGIFormatForAbstractFormat(config.format, config.IsRenderTarget()); UINT bindflags = D3D11_BIND_SHADER_RESOURCE; if (config.IsRenderTarget()) bindflags |= IsDepthFormat(config.format) ? D3D11_BIND_DEPTH_STENCIL : D3D11_BIND_RENDER_TARGET; @@ -154,7 +40,7 @@ std::unique_ptr DXTexture::Create(const TextureConfig& config) CD3D11_TEXTURE2D_DESC desc(tex_format, config.width, config.height, config.layers, config.levels, bindflags, D3D11_USAGE_DEFAULT, 0, config.samples, 0, 0); - ID3D11Texture2D* d3d_texture; + ComPtr d3d_texture; HRESULT hr = D3D::device->CreateTexture2D(&desc, nullptr, &d3d_texture); if (FAILED(hr)) { @@ -163,36 +49,69 @@ std::unique_ptr DXTexture::Create(const TextureConfig& config) return nullptr; } - ID3D11ShaderResourceView* d3d_srv; - const CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(d3d_texture, - config.IsMultisampled() ? - D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY : - D3D11_SRV_DIMENSION_TEXTURE2DARRAY, - srv_format, 0, config.levels, 0, config.layers); - hr = D3D::device->CreateShaderResourceView(d3d_texture, &srv_desc, &d3d_srv); + std::unique_ptr tex(new DXTexture(config, d3d_texture.Get())); + if (!tex->CreateSRV() || (config.IsComputeImage() && !tex->CreateUAV())) + return nullptr; + + return tex; +} + +std::unique_ptr DXTexture::CreateAdopted(ID3D11Texture2D* texture) +{ + D3D11_TEXTURE2D_DESC desc; + texture->GetDesc(&desc); + + // Convert to our texture config format. + TextureConfig config(desc.Width, desc.Height, desc.MipLevels, desc.ArraySize, + desc.SampleDesc.Count, + D3DCommon::GetAbstractFormatForDXGIFormat(desc.Format), 0); + if (desc.BindFlags & D3D11_BIND_RENDER_TARGET) + config.flags |= AbstractTextureFlag_RenderTarget; + if (desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) + config.flags |= AbstractTextureFlag_ComputeImage; + + std::unique_ptr tex(new DXTexture(config, texture)); + if (desc.BindFlags & D3D11_BIND_SHADER_RESOURCE && !tex->CreateSRV()) + return nullptr; + if (desc.BindFlags & D3D11_BIND_UNORDERED_ACCESS && !tex->CreateUAV()) + return nullptr; + + return tex; +} + +bool DXTexture::CreateSRV() +{ + const CD3D11_SHADER_RESOURCE_VIEW_DESC desc( + m_texture.Get(), + m_config.IsMultisampled() ? D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY : + D3D11_SRV_DIMENSION_TEXTURE2DARRAY, + D3DCommon::GetSRVFormatForAbstractFormat(m_config.format), 0, m_config.levels, 0, + m_config.layers); + HRESULT hr = D3D::device->CreateShaderResourceView(m_texture.Get(), &desc, &m_srv); if (FAILED(hr)) { - PanicAlert("Failed to create %ux%ux%u D3D SRV", config.width, config.height, config.layers); - d3d_texture->Release(); - return nullptr; + PanicAlert("Failed to create %ux%ux%u D3D SRV", m_config.width, m_config.height, + m_config.layers); + return false; } - ID3D11UnorderedAccessView* d3d_uav = nullptr; - if (config.IsComputeImage()) + return true; +} + +bool DXTexture::CreateUAV() +{ + const CD3D11_UNORDERED_ACCESS_VIEW_DESC desc( + m_texture.Get(), D3D11_UAV_DIMENSION_TEXTURE2DARRAY, + D3DCommon::GetSRVFormatForAbstractFormat(m_config.format), 0, 0, m_config.layers); + HRESULT hr = D3D::device->CreateUnorderedAccessView(m_texture.Get(), &desc, &m_uav); + if (FAILED(hr)) { - const CD3D11_UNORDERED_ACCESS_VIEW_DESC uav_desc( - d3d_texture, D3D11_UAV_DIMENSION_TEXTURE2DARRAY, srv_format, 0, 0, config.layers); - hr = D3D::device->CreateUnorderedAccessView(d3d_texture, &uav_desc, &d3d_uav); - if (FAILED(hr)) - { - PanicAlert("Failed to create %ux%ux%u D3D UAV", config.width, config.height, config.layers); - d3d_uav->Release(); - d3d_texture->Release(); - return nullptr; - } + PanicAlert("Failed to create %ux%ux%u D3D UAV", m_config.width, m_config.height, + m_config.layers); + return false; } - return std::make_unique(config, d3d_texture, d3d_srv, d3d_uav); + return true; } void DXTexture::CopyRectangleFromTexture(const AbstractTexture* src, @@ -213,8 +132,8 @@ void DXTexture::CopyRectangleFromTexture(const AbstractTexture* src, src_box.back = 1; D3D::context->CopySubresourceRegion( - m_d3d_texture, D3D11CalcSubresource(dst_level, dst_layer, m_config.levels), dst_rect.left, - dst_rect.top, 0, srcentry->m_d3d_texture, + m_texture.Get(), D3D11CalcSubresource(dst_level, dst_layer, m_config.levels), dst_rect.left, + dst_rect.top, 0, srcentry->m_texture.Get(), D3D11CalcSubresource(src_level, src_layer, srcentry->m_config.levels), &src_box); } @@ -228,16 +147,16 @@ void DXTexture::ResolveFromTexture(const AbstractTexture* src, const MathUtil::R rect.top + rect.GetHeight() <= static_cast(srcentry->m_config.height)); D3D::context->ResolveSubresource( - m_d3d_texture, D3D11CalcSubresource(level, layer, m_config.levels), srcentry->m_d3d_texture, - D3D11CalcSubresource(level, layer, srcentry->m_config.levels), - GetDXGIFormatForHostFormat(m_config.format, false)); + m_texture.Get(), D3D11CalcSubresource(level, layer, m_config.levels), + srcentry->m_texture.Get(), D3D11CalcSubresource(level, layer, srcentry->m_config.levels), + D3DCommon::GetDXGIFormatForAbstractFormat(m_config.format, false)); } void DXTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer, size_t buffer_size) { size_t src_pitch = CalculateStrideForFormat(m_config.format, row_length); - D3D::context->UpdateSubresource(m_d3d_texture, level, nullptr, buffer, + D3D::context->UpdateSubresource(m_texture.Get(), level, nullptr, buffer, static_cast(src_pitch), 0); } @@ -251,7 +170,6 @@ DXStagingTexture::~DXStagingTexture() { if (IsMapped()) DXStagingTexture::Unmap(); - SAFE_RELEASE(m_tex); } std::unique_ptr DXStagingTexture::Create(StagingTextureType type, @@ -275,16 +193,16 @@ std::unique_ptr DXStagingTexture::Create(StagingTextureType ty cpu_flags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; } - CD3D11_TEXTURE2D_DESC desc(GetDXGIFormatForHostFormat(config.format, false), config.width, - config.height, 1, 1, 0, usage, cpu_flags); + CD3D11_TEXTURE2D_DESC desc(D3DCommon::GetDXGIFormatForAbstractFormat(config.format, false), + config.width, config.height, 1, 1, 0, usage, cpu_flags); - ID3D11Texture2D* texture; + ComPtr texture; HRESULT hr = D3D::device->CreateTexture2D(&desc, nullptr, &texture); CHECK(SUCCEEDED(hr), "Create staging texture"); if (FAILED(hr)) return nullptr; - return std::unique_ptr(new DXStagingTexture(type, config, texture)); + return std::unique_ptr(new DXStagingTexture(type, config, texture.Get())); } void DXStagingTexture::CopyFromTexture(const AbstractTexture* src, @@ -307,14 +225,14 @@ void DXStagingTexture::CopyFromTexture(const AbstractTexture* src, { // Copy whole resource, needed for depth textures. D3D::context->CopySubresourceRegion( - m_tex, 0, 0, 0, 0, static_cast(src)->GetD3DTexture(), + m_tex.Get(), 0, 0, 0, 0, static_cast(src)->GetD3DTexture(), D3D11CalcSubresource(src_level, src_layer, src->GetLevels()), nullptr); } else { CD3D11_BOX src_box(src_rect.left, src_rect.top, 0, src_rect.right, src_rect.bottom, 1); D3D::context->CopySubresourceRegion( - m_tex, 0, static_cast(dst_rect.left), static_cast(dst_rect.top), 0, + m_tex.Get(), 0, static_cast(dst_rect.left), static_cast(dst_rect.top), 0, static_cast(src)->GetD3DTexture(), D3D11CalcSubresource(src_level, src_layer, src->GetLevels()), &src_box); } @@ -342,7 +260,8 @@ void DXStagingTexture::CopyToTexture(const MathUtil::Rectangle& src_rect, A { D3D::context->CopySubresourceRegion( static_cast(dst)->GetD3DTexture(), - D3D11CalcSubresource(dst_level, dst_layer, dst->GetLevels()), 0, 0, 0, m_tex, 0, nullptr); + D3D11CalcSubresource(dst_level, dst_layer, dst->GetLevels()), 0, 0, 0, m_tex.Get(), 0, + nullptr); } else { @@ -350,7 +269,8 @@ void DXStagingTexture::CopyToTexture(const MathUtil::Rectangle& src_rect, A D3D::context->CopySubresourceRegion( static_cast(dst)->GetD3DTexture(), D3D11CalcSubresource(dst_level, dst_layer, dst->GetLevels()), - static_cast(dst_rect.left), static_cast(dst_rect.top), 0, m_tex, 0, &src_box); + static_cast(dst_rect.left), static_cast(dst_rect.top), 0, m_tex.Get(), 0, + &src_box); } } @@ -368,7 +288,7 @@ bool DXStagingTexture::Map() map_type = D3D11_MAP_READ_WRITE; D3D11_MAPPED_SUBRESOURCE sr; - HRESULT hr = D3D::context->Map(m_tex, 0, map_type, 0, &sr); + HRESULT hr = D3D::context->Map(m_tex.Get(), 0, map_type, 0, &sr); CHECK(SUCCEEDED(hr), "Map readback texture"); if (FAILED(hr)) return false; @@ -383,7 +303,7 @@ void DXStagingTexture::Unmap() if (!m_map_pointer) return; - D3D::context->Unmap(m_tex, 0); + D3D::context->Unmap(m_tex.Get(), 0); m_map_pointer = nullptr; } @@ -404,15 +324,7 @@ DXFramebuffer::DXFramebuffer(AbstractTexture* color_attachment, AbstractTexture* { } -DXFramebuffer::~DXFramebuffer() -{ - if (m_rtv) - m_rtv->Release(); - if (m_integer_rtv) - m_integer_rtv->Release(); - if (m_dsv) - m_dsv->Release(); -} +DXFramebuffer::~DXFramebuffer() = default; std::unique_ptr DXFramebuffer::Create(DXTexture* color_attachment, DXTexture* depth_attachment) @@ -430,21 +342,24 @@ std::unique_ptr DXFramebuffer::Create(DXTexture* color_attachment const u32 layers = either_attachment->GetLayers(); const u32 samples = either_attachment->GetSamples(); - ID3D11RenderTargetView* rtv = nullptr; - ID3D11RenderTargetView* integer_rtv = nullptr; + ComPtr rtv; + ComPtr integer_rtv; if (color_attachment) { CD3D11_RENDER_TARGET_VIEW_DESC desc( color_attachment->IsMultisampled() ? D3D11_RTV_DIMENSION_TEXTURE2DMSARRAY : D3D11_RTV_DIMENSION_TEXTURE2DARRAY, - GetRTVFormatForHostFormat(color_attachment->GetFormat(), false), 0, 0, + D3DCommon::GetRTVFormatForAbstractFormat(color_attachment->GetFormat(), false), 0, 0, color_attachment->GetLayers()); HRESULT hr = D3D::device->CreateRenderTargetView(color_attachment->GetD3DTexture(), &desc, &rtv); CHECK(SUCCEEDED(hr), "Create render target view for framebuffer"); + if (FAILED(hr)) + return nullptr; // Only create the integer RTV on Win8+. - DXGI_FORMAT integer_format = GetRTVFormatForHostFormat(color_attachment->GetFormat(), true); + DXGI_FORMAT integer_format = + D3DCommon::GetRTVFormatForAbstractFormat(color_attachment->GetFormat(), true); if (D3D::device1 && integer_format != desc.Format) { desc.Format = integer_format; @@ -454,22 +369,24 @@ std::unique_ptr DXFramebuffer::Create(DXTexture* color_attachment } } - ID3D11DepthStencilView* dsv = nullptr; + ComPtr dsv; if (depth_attachment) { const CD3D11_DEPTH_STENCIL_VIEW_DESC desc( depth_attachment->GetConfig().IsMultisampled() ? D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY : D3D11_DSV_DIMENSION_TEXTURE2DARRAY, - GetDSVFormatForHostFormat(depth_attachment->GetFormat()), 0, 0, + D3DCommon::GetDSVFormatForAbstractFormat(depth_attachment->GetFormat()), 0, 0, depth_attachment->GetLayers(), 0); HRESULT hr = D3D::device->CreateDepthStencilView(depth_attachment->GetD3DTexture(), &desc, &dsv); CHECK(SUCCEEDED(hr), "Create depth stencil view for framebuffer"); + if (FAILED(hr)) + return nullptr; } return std::make_unique(color_attachment, depth_attachment, color_format, - depth_format, width, height, layers, samples, rtv, - integer_rtv, dsv); + depth_format, width, height, layers, samples, rtv.Get(), + integer_rtv.Get(), dsv.Get()); } } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/DXTexture.h b/Source/Core/VideoBackends/D3D/DXTexture.h index 0a4e0ace48..21e38c35bb 100644 --- a/Source/Core/VideoBackends/D3D/DXTexture.h +++ b/Source/Core/VideoBackends/D3D/DXTexture.h @@ -17,11 +17,10 @@ namespace DX11 class DXTexture final : public AbstractTexture { public: - explicit DXTexture(const TextureConfig& tex_config, ID3D11Texture2D* d3d_texture, - ID3D11ShaderResourceView* d3d_srv, ID3D11UnorderedAccessView* d3d_uav); ~DXTexture(); static std::unique_ptr Create(const TextureConfig& config); + static std::unique_ptr CreateAdopted(ID3D11Texture2D* texture); void CopyRectangleFromTexture(const AbstractTexture* src, const MathUtil::Rectangle& src_rect, u32 src_layer, @@ -32,14 +31,19 @@ public: void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer, size_t buffer_size) override; - ID3D11Texture2D* GetD3DTexture() const { return m_d3d_texture; } - ID3D11ShaderResourceView* GetD3DSRV() const { return m_d3d_srv; } - ID3D11UnorderedAccessView* GetD3DUAV() const { return m_d3d_uav; } + ID3D11Texture2D* GetD3DTexture() const { return m_texture.Get(); } + ID3D11ShaderResourceView* GetD3DSRV() const { return m_srv.Get(); } + ID3D11UnorderedAccessView* GetD3DUAV() const { return m_uav.Get(); } private: - ID3D11Texture2D* m_d3d_texture; - ID3D11ShaderResourceView* m_d3d_srv; - ID3D11UnorderedAccessView* m_d3d_uav; + DXTexture(const TextureConfig& config, ID3D11Texture2D* texture); + + bool CreateSRV(); + bool CreateUAV(); + + ComPtr m_texture; + ComPtr m_srv; + ComPtr m_uav; }; class DXStagingTexture final : public AbstractStagingTexture @@ -65,7 +69,7 @@ public: private: DXStagingTexture(StagingTextureType type, const TextureConfig& config, ID3D11Texture2D* tex); - ID3D11Texture2D* m_tex = nullptr; + ComPtr m_tex = nullptr; }; class DXFramebuffer final : public AbstractFramebuffer @@ -77,17 +81,17 @@ public: ID3D11RenderTargetView* integer_rtv, ID3D11DepthStencilView* dsv); ~DXFramebuffer() override; - ID3D11RenderTargetView* const* GetRTVArray() const { return &m_rtv; } - ID3D11RenderTargetView* const* GetIntegerRTVArray() const { return &m_integer_rtv; } + ID3D11RenderTargetView* const* GetRTVArray() const { return m_rtv.GetAddressOf(); } + ID3D11RenderTargetView* const* GetIntegerRTVArray() const { return m_integer_rtv.GetAddressOf(); } UINT GetNumRTVs() const { return m_rtv ? 1 : 0; } - ID3D11DepthStencilView* GetDSV() const { return m_dsv; } + ID3D11DepthStencilView* GetDSV() const { return m_dsv.Get(); } static std::unique_ptr Create(DXTexture* color_attachment, DXTexture* depth_attachment); protected: - ID3D11RenderTargetView* m_rtv; - ID3D11RenderTargetView* m_integer_rtv; - ID3D11DepthStencilView* m_dsv; + ComPtr m_rtv; + ComPtr m_integer_rtv; + ComPtr m_dsv; }; } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/NativeVertexFormat.cpp b/Source/Core/VideoBackends/D3D/NativeVertexFormat.cpp index 4d3407ed04..4611d9945d 100644 --- a/Source/Core/VideoBackends/D3D/NativeVertexFormat.cpp +++ b/Source/Core/VideoBackends/D3D/NativeVertexFormat.cpp @@ -147,7 +147,8 @@ D3DVertexFormat::D3DVertexFormat(const PortableVertexDeclaration& vtx_decl) D3DVertexFormat::~D3DVertexFormat() { ID3D11InputLayout* layout = m_layout.load(); - SAFE_RELEASE(layout); + if (layout) + layout->Release(); } ID3D11InputLayout* D3DVertexFormat::GetInputLayout(const void* vs_bytecode, size_t vs_bytecode_size) @@ -160,16 +161,16 @@ ID3D11InputLayout* D3DVertexFormat::GetInputLayout(const void* vs_bytecode, size HRESULT hr = D3D::device->CreateInputLayout(m_elems.data(), m_num_elems, vs_bytecode, vs_bytecode_size, &layout); - if (FAILED(hr)) - PanicAlert("Failed to create input layout, %s %d\n", __FILE__, __LINE__); - DX11::D3D::SetDebugObjectName(m_layout, "input layout used to emulate the GX pipeline"); + CHECK(SUCCEEDED(hr), "Failed to create input layout"); // This method can be called from multiple threads, so ensure that only one thread sets the // cached input layout pointer. If another thread beats this thread, use the existing layout. ID3D11InputLayout* expected = nullptr; if (!m_layout.compare_exchange_strong(expected, layout)) { - SAFE_RELEASE(layout); + if (layout) + layout->Release(); + layout = expected; } diff --git a/Source/Core/VideoBackends/D3D/PerfQuery.cpp b/Source/Core/VideoBackends/D3D/PerfQuery.cpp index 15574a9c76..0382be903c 100644 --- a/Source/Core/VideoBackends/D3D/PerfQuery.cpp +++ b/Source/Core/VideoBackends/D3D/PerfQuery.cpp @@ -22,14 +22,7 @@ PerfQuery::PerfQuery() : m_query_read_pos() ResetQuery(); } -PerfQuery::~PerfQuery() -{ - for (ActiveQuery& entry : m_query_buffer) - { - // TODO: EndQuery? - entry.query->Release(); - } -} +PerfQuery::~PerfQuery() = default; void PerfQuery::EnableQuery(PerfQueryGroup type) { @@ -49,7 +42,7 @@ void PerfQuery::EnableQuery(PerfQueryGroup type) { auto& entry = m_query_buffer[(m_query_read_pos + m_query_count) % m_query_buffer.size()]; - D3D::context->Begin(entry.query); + D3D::context->Begin(entry.query.Get()); entry.query_type = type; ++m_query_count; @@ -63,7 +56,7 @@ void PerfQuery::DisableQuery(PerfQueryGroup type) { auto& entry = m_query_buffer[(m_query_read_pos + m_query_count + m_query_buffer.size() - 1) % m_query_buffer.size()]; - D3D::context->End(entry.query); + D3D::context->End(entry.query.Get()); } } @@ -98,7 +91,7 @@ void PerfQuery::FlushOne() while (hr != S_OK) { // TODO: Might cause us to be stuck in an infinite loop! - hr = D3D::context->GetData(entry.query, &result, sizeof(result), 0); + hr = D3D::context->GetData(entry.query.Get(), &result, sizeof(result), 0); } // NOTE: Reported pixel metrics should be referenced to native resolution @@ -125,8 +118,8 @@ void PerfQuery::WeakFlush() auto& entry = m_query_buffer[m_query_read_pos]; UINT64 result = 0; - HRESULT hr = - D3D::context->GetData(entry.query, &result, sizeof(result), D3D11_ASYNC_GETDATA_DONOTFLUSH); + HRESULT hr = D3D::context->GetData(entry.query.Get(), &result, sizeof(result), + D3D11_ASYNC_GETDATA_DONOTFLUSH); if (hr == S_OK) { @@ -149,4 +142,4 @@ bool PerfQuery::IsFlushed() const return 0 == m_query_count; } -} // namespace +} // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/PerfQuery.h b/Source/Core/VideoBackends/D3D/PerfQuery.h index 80e2fc7570..fd52293db4 100644 --- a/Source/Core/VideoBackends/D3D/PerfQuery.h +++ b/Source/Core/VideoBackends/D3D/PerfQuery.h @@ -5,8 +5,7 @@ #pragma once #include -#include - +#include "VideoBackends/D3D/D3DBase.h" #include "VideoCommon/PerfQueryBase.h" namespace DX11 @@ -27,7 +26,7 @@ public: private: struct ActiveQuery { - ID3D11Query* query; + ComPtr query; PerfQueryGroup query_type; }; @@ -43,4 +42,4 @@ private: int m_query_read_pos; }; -} // namespace +} // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index 82f3cba743..a132efadf3 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -26,6 +26,7 @@ #include "VideoBackends/D3D/DXPipeline.h" #include "VideoBackends/D3D/DXShader.h" #include "VideoBackends/D3D/DXTexture.h" +#include "VideoBackends/D3D/SwapChain.h" #include "VideoCommon/BPFunctions.h" #include "VideoCommon/FramebufferManager.h" @@ -48,11 +49,12 @@ typedef struct _Nv_Stereo_Image_Header #define NVSTEREO_IMAGE_SIGNATURE 0x4433564e -Renderer::Renderer(int backbuffer_width, int backbuffer_height, float backbuffer_scale) - : ::Renderer(backbuffer_width, backbuffer_height, backbuffer_scale, - AbstractTextureFormat::RGBA8) +Renderer::Renderer(std::unique_ptr swap_chain, float backbuffer_scale) + : ::Renderer(swap_chain ? swap_chain->GetWidth() : 0, swap_chain ? swap_chain->GetHeight() : 0, + backbuffer_scale, + swap_chain ? swap_chain->GetFormat() : AbstractTextureFormat::Undefined), + m_swap_chain(std::move(swap_chain)) { - m_last_fullscreen_state = D3D::GetFullscreenState(); } Renderer::~Renderer() = default; @@ -82,17 +84,13 @@ void Renderer::Create3DVisionTexture(int width, int height) ID3D11Texture2D* texture; HRESULT hr = D3D::device->CreateTexture2D(&texture_desc, &sys_data, &texture); CHECK(SUCCEEDED(hr), "Create 3D Vision Texture"); - m_3d_vision_texture = std::make_unique(TextureConfig(width * 2, height + 1, 1, 1, 1, - AbstractTextureFormat::RGBA8, - AbstractTextureFlag_RenderTarget), - texture, nullptr, nullptr); - m_3d_vision_framebuffer = - DXFramebuffer::Create(static_cast(m_3d_vision_texture.get()), nullptr); + m_3d_vision_texture = DXTexture::CreateAdopted(texture); + m_3d_vision_framebuffer = DXFramebuffer::Create(m_3d_vision_texture.get(), nullptr); } bool Renderer::IsHeadless() const { - return D3D::swapchain == nullptr; + return !m_swap_chain; } std::unique_ptr Renderer::CreateTexture(const TextureConfig& config) @@ -116,13 +114,17 @@ std::unique_ptr Renderer::CreateFramebuffer(AbstractTexture std::unique_ptr Renderer::CreateShaderFromSource(ShaderStage stage, const char* source, size_t length) { - return DXShader::CreateFromSource(stage, source, length); + DXShader::BinaryData bytecode; + if (!DXShader::CompileShader(D3D::feature_level, &bytecode, stage, source, length)) + return nullptr; + + return DXShader::CreateFromBytecode(stage, std::move(bytecode)); } std::unique_ptr Renderer::CreateShaderFromBinary(ShaderStage stage, const void* data, size_t length) { - return DXShader::CreateFromBinary(stage, data, length); + return DXShader::CreateFromBytecode(stage, DXShader::CreateByteCode(data, length)); } std::unique_ptr Renderer::CreatePipeline(const AbstractPipelineConfig& config) @@ -196,64 +198,44 @@ void Renderer::DispatchComputeShader(const AbstractShader* shader, u32 groups_x, void Renderer::BindBackbuffer(const ClearColor& clear_color) { - CheckForSurfaceChange(); - CheckForSurfaceResize(); - SetAndClearFramebuffer(D3D::GetSwapChainFramebuffer(), clear_color); + CheckForSwapChainChanges(); + SetAndClearFramebuffer(m_swap_chain->GetFramebuffer(), clear_color); } void Renderer::PresentBackbuffer() { - D3D::Present(); + m_swap_chain->Present(); } void Renderer::OnConfigChanged(u32 bits) { + // Quad-buffer changes require swap chain recreation. + if (bits & CONFIG_CHANGE_BIT_STEREO_MODE && m_swap_chain) + m_swap_chain->SetStereo(SwapChain::WantsStereo()); } -void Renderer::CheckForSurfaceChange() +void Renderer::CheckForSwapChainChanges() { - if (!m_surface_changed.TestAndClear()) + const bool surface_changed = m_surface_changed.TestAndClear(); + const bool surface_resized = + m_surface_resized.TestAndClear() || m_swap_chain->CheckForFullscreenChange(); + if (!surface_changed && !surface_resized) return; - m_3d_vision_framebuffer.reset(); - m_3d_vision_texture.reset(); - - D3D::Reset(reinterpret_cast(m_new_surface_handle)); - m_new_surface_handle = nullptr; - - UpdateBackbufferSize(); -} - -void Renderer::CheckForSurfaceResize() -{ - const bool fullscreen_state = D3D::GetFullscreenState(); - const bool exclusive_fullscreen_changed = fullscreen_state != m_last_fullscreen_state; - if (!m_surface_resized.TestAndClear() && !exclusive_fullscreen_changed) - return; - - m_3d_vision_framebuffer.reset(); - m_3d_vision_texture.reset(); - - m_last_fullscreen_state = fullscreen_state; - if (D3D::swapchain) - D3D::ResizeSwapChain(); - UpdateBackbufferSize(); -} - -void Renderer::UpdateBackbufferSize() -{ - if (D3D::swapchain) + if (surface_changed) { - DXGI_SWAP_CHAIN_DESC1 desc = {}; - D3D::swapchain->GetDesc1(&desc); - m_backbuffer_width = std::max(desc.Width, 1u); - m_backbuffer_height = std::max(desc.Height, 1u); + m_swap_chain->ChangeSurface(m_new_surface_handle); + m_new_surface_handle = nullptr; } else { - m_backbuffer_width = 1; - m_backbuffer_height = 1; + m_swap_chain->ResizeSwapChain(); } + + m_backbuffer_width = m_swap_chain->GetWidth(); + m_backbuffer_height = m_swap_chain->GetHeight(); + m_3d_vision_framebuffer.reset(); + m_3d_vision_texture.reset(); } void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer) @@ -363,22 +345,23 @@ void Renderer::RenderXFBToScreen(const AbstractTexture* texture, const EFBRectan // Copy the left eye to the backbuffer, if Nvidia 3D Vision is enabled it should // recognize the signature and automatically include the right eye frame. - const CD3D11_BOX box(0, 0, 0, m_backbuffer_width, m_backbuffer_height, 1); - D3D::context->CopySubresourceRegion(D3D::GetSwapChainTexture()->GetD3DTexture(), 0, 0, 0, 0, + const CD3D11_BOX box(0, 0, 0, m_swap_chain->GetWidth(), m_swap_chain->GetHeight(), 1); + D3D::context->CopySubresourceRegion(m_swap_chain->GetTexture()->GetD3DTexture(), 0, 0, 0, 0, m_3d_vision_texture->GetD3DTexture(), 0, &box); // Restore render target to backbuffer - SetFramebuffer(D3D::GetSwapChainFramebuffer()); + SetFramebuffer(m_swap_chain->GetFramebuffer()); } void Renderer::SetFullscreen(bool enable_fullscreen) { - D3D::SetFullscreenState(enable_fullscreen); + if (m_swap_chain) + m_swap_chain->SetFullscreen(enable_fullscreen); } bool Renderer::IsFullscreen() const { - return D3D::GetFullscreenState(); + return m_swap_chain && m_swap_chain->GetFullscreen(); } } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/Render.h b/Source/Core/VideoBackends/D3D/Render.h index 0f9b38761e..551295a9d5 100644 --- a/Source/Core/VideoBackends/D3D/Render.h +++ b/Source/Core/VideoBackends/D3D/Render.h @@ -11,13 +11,14 @@ namespace DX11 { +class SwapChain; class DXTexture; class DXFramebuffer; class Renderer : public ::Renderer { public: - Renderer(int backbuffer_width, int backbuffer_height, float backbuffer_scale); + Renderer(std::unique_ptr swap_chain, float backbuffer_scale); ~Renderer() override; StateCache& GetStateCache() { return m_state_cache; } @@ -69,15 +70,12 @@ public: private: void Create3DVisionTexture(int width, int height); - void CheckForSurfaceChange(); - void CheckForSurfaceResize(); - void UpdateBackbufferSize(); + void CheckForSwapChainChanges(); StateCache m_state_cache; + std::unique_ptr m_swap_chain; std::unique_ptr m_3d_vision_texture; std::unique_ptr m_3d_vision_framebuffer; - - bool m_last_fullscreen_state = false; }; } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/SwapChain.cpp b/Source/Core/VideoBackends/D3D/SwapChain.cpp new file mode 100644 index 0000000000..d5ce3372c0 --- /dev/null +++ b/Source/Core/VideoBackends/D3D/SwapChain.cpp @@ -0,0 +1,52 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "VideoBackends/D3D/SwapChain.h" +#include "VideoBackends/D3D/DXTexture.h" + +namespace DX11 +{ +SwapChain::SwapChain(const WindowSystemInfo& wsi, IDXGIFactory2* dxgi_factory, + ID3D11Device* d3d_device) + : D3DCommon::SwapChain(wsi, dxgi_factory, d3d_device) +{ +} + +SwapChain::~SwapChain() = default; + +std::unique_ptr SwapChain::Create(const WindowSystemInfo& wsi) +{ + std::unique_ptr swap_chain = + std::make_unique(wsi, D3D::dxgi_factory.Get(), D3D::device.Get()); + if (!swap_chain->CreateSwapChain(WantsStereo())) + return nullptr; + + return swap_chain; +} + +bool SwapChain::CreateSwapChainBuffers() +{ + ComPtr texture; + HRESULT hr = m_swap_chain->GetBuffer(0, IID_PPV_ARGS(&texture)); + CHECK(SUCCEEDED(hr), "Get swap chain buffer"); + if (FAILED(hr)) + return false; + + m_texture = DXTexture::CreateAdopted(texture.Get()); + if (!m_texture) + return false; + + m_framebuffer = DXFramebuffer::Create(m_texture.get(), nullptr); + if (!m_framebuffer) + return false; + + return true; +} + +void SwapChain::DestroySwapChainBuffers() +{ + m_framebuffer.reset(); + m_texture.reset(); +} +} // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/SwapChain.h b/Source/Core/VideoBackends/D3D/SwapChain.h new file mode 100644 index 0000000000..1579459eb6 --- /dev/null +++ b/Source/Core/VideoBackends/D3D/SwapChain.h @@ -0,0 +1,44 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include + +#include "Common/CommonTypes.h" +#include "Common/WindowSystemInfo.h" +#include "VideoBackends/D3D/D3DBase.h" +#include "VideoBackends/D3DCommon/SwapChain.h" +#include "VideoCommon/TextureConfig.h" + +namespace DX11 +{ +class DXTexture; +class DXFramebuffer; + +class SwapChain : public D3DCommon::SwapChain +{ +public: + SwapChain(const WindowSystemInfo& wsi, IDXGIFactory2* dxgi_factory, ID3D11Device* d3d_device); + ~SwapChain(); + + static std::unique_ptr Create(const WindowSystemInfo& wsi); + + DXTexture* GetTexture() const { return m_texture.get(); } + DXFramebuffer* GetFramebuffer() const { return m_framebuffer.get(); } + +protected: + bool CreateSwapChainBuffers() override; + void DestroySwapChainBuffers() override; + +private: + // The runtime takes care of renaming the buffers. + std::unique_ptr m_texture; + std::unique_ptr m_framebuffer; +}; + +} // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/VertexManager.cpp b/Source/Core/VideoBackends/D3D/VertexManager.cpp index 479f601037..5b6fe0921b 100644 --- a/Source/Core/VideoBackends/D3D/VertexManager.cpp +++ b/Source/Core/VideoBackends/D3D/VertexManager.cpp @@ -14,6 +14,7 @@ #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DState.h" #include "VideoBackends/D3D/Render.h" +#include "VideoBackends/D3DCommon/Common.h" #include "VideoCommon/BoundingBox.h" #include "VideoCommon/GeometryShaderManager.h" @@ -27,15 +28,18 @@ namespace DX11 { -static ID3D11Buffer* AllocateConstantBuffer(u32 size) +static ComPtr AllocateConstantBuffer(u32 size) { const u32 cbsize = Common::AlignUp(size, 16u); // must be a multiple of 16 const CD3D11_BUFFER_DESC cbdesc(cbsize, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DYNAMIC, D3D11_CPU_ACCESS_WRITE); - ID3D11Buffer* cbuf; + ComPtr cbuf; const HRESULT hr = D3D::device->CreateBuffer(&cbdesc, nullptr, &cbuf); - CHECK(hr == S_OK, "shader constant buffer (size=%u)", cbsize); - D3D::SetDebugObjectName(cbuf, "constant buffer used to emulate the GX pipeline"); + CHECK(SUCCEEDED(hr), "shader constant buffer (size=%u)", cbsize); + if (FAILED(hr)) + return nullptr; + + D3DCommon::SetDebugObjectName(cbuf.Get(), "constant buffer"); return cbuf; } @@ -49,10 +53,10 @@ static void UpdateConstantBuffer(ID3D11Buffer* const buffer, const void* data, u ADDSTAT(stats.thisFrame.bytesUniformStreamed, data_size); } -static ID3D11ShaderResourceView* +static ComPtr CreateTexelBufferView(ID3D11Buffer* buffer, TexelBufferFormat format, DXGI_FORMAT srv_format) { - ID3D11ShaderResourceView* srv; + ComPtr srv; CD3D11_SHADER_RESOURCE_VIEW_DESC srv_desc(buffer, srv_format, 0, VertexManager::TEXEL_STREAM_BUFFER_SIZE / VertexManager::GetTexelBufferElementSize(format)); @@ -63,17 +67,7 @@ CreateTexelBufferView(ID3D11Buffer* buffer, TexelBufferFormat format, DXGI_FORMA VertexManager::VertexManager() = default; -VertexManager::~VertexManager() -{ - for (auto& srv_ptr : m_texel_buffer_views) - SAFE_RELEASE(srv_ptr); - SAFE_RELEASE(m_texel_buffer); - SAFE_RELEASE(m_pixel_constant_buffer); - SAFE_RELEASE(m_geometry_constant_buffer); - SAFE_RELEASE(m_vertex_constant_buffer); - for (auto& buffer : m_buffers) - SAFE_RELEASE(buffer); -} +VertexManager::~VertexManager() = default; bool VertexManager::Initialize() { @@ -88,7 +82,8 @@ bool VertexManager::Initialize() { CHECK(SUCCEEDED(D3D::device->CreateBuffer(&bufdesc, nullptr, &m_buffers[i])), "Failed to create buffer."); - D3D::SetDebugObjectName(m_buffers[i], "Buffer of VertexManager"); + if (m_buffers[i]) + D3DCommon::SetDebugObjectName(m_buffers[i].Get(), "Buffer of VertexManager"); } m_vertex_constant_buffer = AllocateConstantBuffer(sizeof(VertexShaderConstants)); @@ -113,7 +108,8 @@ bool VertexManager::Initialize() }}; for (const auto& it : format_mapping) { - m_texel_buffer_views[it.first] = CreateTexelBufferView(m_texel_buffer, it.first, it.second); + m_texel_buffer_views[it.first] = + CreateTexelBufferView(m_texel_buffer.Get(), it.first, it.second); if (!m_texel_buffer_views[it.first]) return false; } @@ -125,10 +121,10 @@ void VertexManager::UploadUtilityUniforms(const void* uniforms, u32 uniforms_siz { // Just use the one buffer for all three. InvalidateConstants(); - UpdateConstantBuffer(m_vertex_constant_buffer, uniforms, uniforms_size); - D3D::stateman->SetVertexConstants(m_vertex_constant_buffer); - D3D::stateman->SetGeometryConstants(m_vertex_constant_buffer); - D3D::stateman->SetPixelConstants(m_vertex_constant_buffer); + UpdateConstantBuffer(m_vertex_constant_buffer.Get(), uniforms, uniforms_size); + D3D::stateman->SetVertexConstants(m_vertex_constant_buffer.Get()); + D3D::stateman->SetGeometryConstants(m_vertex_constant_buffer.Get()); + D3D::stateman->SetPixelConstants(m_vertex_constant_buffer.Get()); } bool VertexManager::MapTexelBuffer(u32 required_size, D3D11_MAPPED_SUBRESOURCE& sr) @@ -136,7 +132,7 @@ bool VertexManager::MapTexelBuffer(u32 required_size, D3D11_MAPPED_SUBRESOURCE& if ((m_texel_buffer_offset + required_size) > TEXEL_STREAM_BUFFER_SIZE) { // Restart buffer. - HRESULT hr = D3D::context->Map(m_texel_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &sr); + HRESULT hr = D3D::context->Map(m_texel_buffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &sr); CHECK(SUCCEEDED(hr), "Map texel buffer"); if (FAILED(hr)) return false; @@ -146,7 +142,7 @@ bool VertexManager::MapTexelBuffer(u32 required_size, D3D11_MAPPED_SUBRESOURCE& else { // Don't overwrite the earlier-used space. - HRESULT hr = D3D::context->Map(m_texel_buffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &sr); + HRESULT hr = D3D::context->Map(m_texel_buffer.Get(), 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &sr); CHECK(SUCCEEDED(hr), "Map texel buffer"); if (FAILED(hr)) return false; @@ -173,8 +169,8 @@ bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBuff ADDSTAT(stats.thisFrame.bytesUniformStreamed, data_size); m_texel_buffer_offset += data_size; - D3D::context->Unmap(m_texel_buffer, 0); - D3D::stateman->SetTexture(0, m_texel_buffer_views[static_cast(format)]); + D3D::context->Unmap(m_texel_buffer.Get(), 0); + D3D::stateman->SetTexture(0, m_texel_buffer_views[static_cast(format)].Get()); return true; } @@ -203,9 +199,9 @@ bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBuff *out_palette_offset = (m_texel_buffer_offset + palette_byte_offset) / palette_elem_size; m_texel_buffer_offset += palette_byte_offset + palette_size; - D3D::context->Unmap(m_texel_buffer, 0); - D3D::stateman->SetTexture(0, m_texel_buffer_views[static_cast(format)]); - D3D::stateman->SetTexture(1, m_texel_buffer_views[static_cast(palette_format)]); + D3D::context->Unmap(m_texel_buffer.Get(), 0); + D3D::stateman->SetTexture(0, m_texel_buffer_views[static_cast(format)].Get()); + D3D::stateman->SetTexture(1, m_texel_buffer_views[static_cast(palette_format)].Get()); return true; } @@ -245,48 +241,48 @@ void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_in *out_base_vertex = vertex_stride > 0 ? (cursor / vertex_stride) : 0; *out_base_index = (cursor + vertexBufferSize) / sizeof(u16); - D3D::context->Map(m_buffers[m_current_buffer], 0, MapType, 0, &map); + D3D::context->Map(m_buffers[m_current_buffer].Get(), 0, MapType, 0, &map); u8* mappedData = reinterpret_cast(map.pData); if (vertexBufferSize > 0) std::memcpy(mappedData + cursor, m_base_buffer_pointer, vertexBufferSize); if (indexBufferSize > 0) std::memcpy(mappedData + cursor + vertexBufferSize, m_cpu_index_buffer.data(), indexBufferSize); - D3D::context->Unmap(m_buffers[m_current_buffer], 0); + D3D::context->Unmap(m_buffers[m_current_buffer].Get(), 0); m_buffer_cursor = cursor + totalBufferSize; ADDSTAT(stats.thisFrame.bytesVertexStreamed, vertexBufferSize); ADDSTAT(stats.thisFrame.bytesIndexStreamed, indexBufferSize); - D3D::stateman->SetVertexBuffer(m_buffers[m_current_buffer], vertex_stride, 0); - D3D::stateman->SetIndexBuffer(m_buffers[m_current_buffer]); + D3D::stateman->SetVertexBuffer(m_buffers[m_current_buffer].Get(), vertex_stride, 0); + D3D::stateman->SetIndexBuffer(m_buffers[m_current_buffer].Get()); } void VertexManager::UploadUniforms() { if (VertexShaderManager::dirty) { - UpdateConstantBuffer(m_vertex_constant_buffer, &VertexShaderManager::constants, + UpdateConstantBuffer(m_vertex_constant_buffer.Get(), &VertexShaderManager::constants, sizeof(VertexShaderConstants)); VertexShaderManager::dirty = false; } if (GeometryShaderManager::dirty) { - UpdateConstantBuffer(m_geometry_constant_buffer, &GeometryShaderManager::constants, + UpdateConstantBuffer(m_geometry_constant_buffer.Get(), &GeometryShaderManager::constants, sizeof(GeometryShaderConstants)); GeometryShaderManager::dirty = false; } if (PixelShaderManager::dirty) { - UpdateConstantBuffer(m_pixel_constant_buffer, &PixelShaderManager::constants, + UpdateConstantBuffer(m_pixel_constant_buffer.Get(), &PixelShaderManager::constants, sizeof(PixelShaderConstants)); PixelShaderManager::dirty = false; } - D3D::stateman->SetPixelConstants(m_pixel_constant_buffer, g_ActiveConfig.bEnablePixelLighting ? - m_vertex_constant_buffer : - nullptr); - D3D::stateman->SetVertexConstants(m_vertex_constant_buffer); - D3D::stateman->SetGeometryConstants(m_geometry_constant_buffer); + D3D::stateman->SetPixelConstants( + m_pixel_constant_buffer.Get(), + g_ActiveConfig.bEnablePixelLighting ? m_vertex_constant_buffer.Get() : nullptr); + D3D::stateman->SetVertexConstants(m_vertex_constant_buffer.Get()); + D3D::stateman->SetGeometryConstants(m_geometry_constant_buffer.Get()); } } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/VertexManager.h b/Source/Core/VideoBackends/D3D/VertexManager.h index d9cb0a8755..02bf19dc6f 100644 --- a/Source/Core/VideoBackends/D3D/VertexManager.h +++ b/Source/Core/VideoBackends/D3D/VertexManager.h @@ -4,18 +4,15 @@ #pragma once -#include - #include #include #include #include +#include "VideoBackends/D3D/D3DBase.h" #include "VideoCommon/NativeVertexFormat.h" #include "VideoCommon/VertexManagerBase.h" -struct ID3D11Buffer; - namespace DX11 { class D3DVertexFormat : public NativeVertexFormat @@ -60,16 +57,16 @@ private: bool MapTexelBuffer(u32 required_size, D3D11_MAPPED_SUBRESOURCE& sr); - ID3D11Buffer* m_buffers[BUFFER_COUNT] = {}; + ComPtr m_buffers[BUFFER_COUNT] = {}; u32 m_current_buffer = 0; u32 m_buffer_cursor = 0; - ID3D11Buffer* m_vertex_constant_buffer = nullptr; - ID3D11Buffer* m_geometry_constant_buffer = nullptr; - ID3D11Buffer* m_pixel_constant_buffer = nullptr; + ComPtr m_vertex_constant_buffer = nullptr; + ComPtr m_geometry_constant_buffer = nullptr; + ComPtr m_pixel_constant_buffer = nullptr; - ID3D11Buffer* m_texel_buffer = nullptr; - std::array m_texel_buffer_views; + ComPtr m_texel_buffer = nullptr; + std::array, NUM_TEXEL_BUFFER_FORMATS> m_texel_buffer_views; u32 m_texel_buffer_offset = 0; }; diff --git a/Source/Core/VideoBackends/D3D/VideoBackend.h b/Source/Core/VideoBackends/D3D/VideoBackend.h index e288dddb9a..0b4c61fc66 100644 --- a/Source/Core/VideoBackends/D3D/VideoBackend.h +++ b/Source/Core/VideoBackends/D3D/VideoBackend.h @@ -11,6 +11,7 @@ namespace DX11 { class VideoBackend : public VideoBackendBase { +public: bool Initialize(const WindowSystemInfo& wsi) override; void Shutdown() override; @@ -18,5 +19,8 @@ class VideoBackend : public VideoBackendBase std::string GetDisplayName() const override; void InitBackendInfo() override; + +private: + void FillBackendInfo(); }; } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/main.cpp b/Source/Core/VideoBackends/D3D/main.cpp index c9a5ab7091..a3c56dbc7e 100644 --- a/Source/Core/VideoBackends/D3D/main.cpp +++ b/Source/Core/VideoBackends/D3D/main.cpp @@ -14,8 +14,10 @@ #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/PerfQuery.h" #include "VideoBackends/D3D/Render.h" +#include "VideoBackends/D3D/SwapChain.h" #include "VideoBackends/D3D/VertexManager.h" #include "VideoBackends/D3D/VideoBackend.h" +#include "VideoBackends/D3DCommon/Common.h" #include "VideoCommon/FramebufferManager.h" #include "VideoCommon/ShaderCache.h" @@ -37,15 +39,15 @@ std::string VideoBackend::GetDisplayName() const void VideoBackend::InitBackendInfo() { - HRESULT hr = DX11::D3D::LoadDXGI(); - if (SUCCEEDED(hr)) - hr = DX11::D3D::LoadD3D(); - if (FAILED(hr)) - { - DX11::D3D::UnloadDXGI(); + if (!D3DCommon::LoadLibraries()) return; - } + FillBackendInfo(); + D3DCommon::UnloadLibraries(); +} + +void VideoBackend::FillBackendInfo() +{ g_Config.backend_info.api_type = APIType::D3D; g_Config.backend_info.MaxTextureSize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; g_Config.backend_info.bUsesLowerLeftOrigin = false; @@ -73,82 +75,36 @@ void VideoBackend::InitBackendInfo() g_Config.backend_info.bSupportsBPTCTextures = false; g_Config.backend_info.bSupportsFramebufferFetch = false; g_Config.backend_info.bSupportsBackgroundCompiling = true; + g_Config.backend_info.bSupportsST3CTextures = true; + g_Config.backend_info.bSupportsBPTCTextures = true; + g_Config.backend_info.bSupportsEarlyZ = true; + g_Config.backend_info.bSupportsBBox = true; + g_Config.backend_info.bSupportsFragmentStoresAndAtomics = true; + g_Config.backend_info.bSupportsGSInstancing = true; + g_Config.backend_info.bSupportsSSAA = true; - IDXGIFactory2* factory; - IDXGIAdapter* ad; - hr = DX11::PCreateDXGIFactory(__uuidof(IDXGIFactory2), (void**)&factory); - if (FAILED(hr)) - PanicAlert("Failed to create IDXGIFactory object"); - - // adapters - g_Config.backend_info.Adapters.clear(); - g_Config.backend_info.AAModes.clear(); - while (factory->EnumAdapters((UINT)g_Config.backend_info.Adapters.size(), &ad) != - DXGI_ERROR_NOT_FOUND) - { - const size_t adapter_index = g_Config.backend_info.Adapters.size(); - - DXGI_ADAPTER_DESC desc; - ad->GetDesc(&desc); - - // TODO: These don't get updated on adapter change, yet - if (adapter_index == g_Config.iAdapter) - { - std::vector modes = DX11::D3D::EnumAAModes(ad); - // First iteration will be 1. This equals no AA. - for (unsigned int i = 0; i < modes.size(); ++i) - { - g_Config.backend_info.AAModes.push_back(modes[i].Count); - } - - D3D_FEATURE_LEVEL feature_level = D3D::GetFeatureLevel(ad); - bool shader_model_5_supported = feature_level >= D3D_FEATURE_LEVEL_11_0; - g_Config.backend_info.MaxTextureSize = D3D::GetMaxTextureSize(feature_level); - - // Requires the earlydepthstencil attribute (only available in shader model 5) - g_Config.backend_info.bSupportsEarlyZ = shader_model_5_supported; - - // Requires full UAV functionality (only available in shader model 5) - g_Config.backend_info.bSupportsBBox = - g_Config.backend_info.bSupportsFragmentStoresAndAtomics = shader_model_5_supported; - - // Requires the instance attribute (only available in shader model 5) - g_Config.backend_info.bSupportsGSInstancing = shader_model_5_supported; - - // Sample shading requires shader model 5 - g_Config.backend_info.bSupportsSSAA = shader_model_5_supported; - } - g_Config.backend_info.Adapters.push_back(UTF16ToUTF8(desc.Description)); - ad->Release(); - } - factory->Release(); - - DX11::D3D::UnloadDXGI(); - DX11::D3D::UnloadD3D(); + g_Config.backend_info.Adapters = D3DCommon::GetAdapterNames(); + g_Config.backend_info.AAModes = D3D::GetAAModes(g_Config.iAdapter); } bool VideoBackend::Initialize(const WindowSystemInfo& wsi) { + if (!D3D::Create(g_Config.iAdapter, g_Config.bEnableValidationLayer)) + return false; + + FillBackendInfo(); InitializeShared(); - if (FAILED(D3D::Create(reinterpret_cast(wsi.render_surface)))) + std::unique_ptr swap_chain; + if (wsi.render_surface && !(swap_chain = SwapChain::Create(wsi))) { - PanicAlert("Failed to create D3D device."); + PanicAlertT("Failed to create D3D swap chain"); + ShutdownShared(); + D3D::Destroy(); return false; } - int backbuffer_width = 1, backbuffer_height = 1; - if (D3D::swapchain) - { - DXGI_SWAP_CHAIN_DESC1 desc = {}; - D3D::swapchain->GetDesc1(&desc); - backbuffer_width = std::max(desc.Width, 1u); - backbuffer_height = std::max(desc.Height, 1u); - } - - // internal interfaces - g_renderer = - std::make_unique(backbuffer_width, backbuffer_height, wsi.render_surface_scale); + g_renderer = std::make_unique(std::move(swap_chain), wsi.render_surface_scale); g_vertex_manager = std::make_unique(); g_shader_cache = std::make_unique(); g_framebuffer_manager = std::make_unique(); @@ -158,6 +114,7 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi) !g_shader_cache->Initialize() || !g_framebuffer_manager->Initialize() || !g_texture_cache->Initialize()) { + Shutdown(); return false; } @@ -181,7 +138,6 @@ void VideoBackend::Shutdown() g_renderer.reset(); ShutdownShared(); - - D3D::Close(); + D3D::Destroy(); } } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3DCommon/CMakeLists.txt b/Source/Core/VideoBackends/D3DCommon/CMakeLists.txt new file mode 100644 index 0000000000..ba24ba133f --- /dev/null +++ b/Source/Core/VideoBackends/D3DCommon/CMakeLists.txt @@ -0,0 +1,15 @@ +add_library(videod3dcommon + Common.cpp + Common.h + Shader.cpp + Shader.h + SwapChain.cpp + SwapChain.h +) + +target_link_libraries(videod3dcommon +PUBLIC + common + videocommon + videod3dcommon +) diff --git a/Source/Core/VideoBackends/D3DCommon/Common.cpp b/Source/Core/VideoBackends/D3DCommon/Common.cpp new file mode 100644 index 0000000000..f82c2d3f8c --- /dev/null +++ b/Source/Core/VideoBackends/D3DCommon/Common.cpp @@ -0,0 +1,320 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include +#include +#include + +#include "Common/Assert.h" +#include "Common/DynamicLibrary.h" +#include "Common/MsgHandler.h" +#include "Common/StringUtil.h" +#include "VideoBackends/D3DCommon/Common.h" +#include "VideoCommon/TextureConfig.h" +#include "VideoCommon/VideoConfig.h" + +namespace D3DCommon +{ +pD3DCompile d3d_compile; + +static Common::DynamicLibrary s_dxgi_library; +static Common::DynamicLibrary s_d3dcompiler_library; +static bool s_libraries_loaded = false; + +static HRESULT (*create_dxgi_factory)(REFIID riid, _COM_Outptr_ void** ppFactory); +static HRESULT (*create_dxgi_factory2)(UINT Flags, REFIID riid, void** ppFactory); + +bool LoadLibraries() +{ + if (s_libraries_loaded) + return true; + + if (!s_dxgi_library.Open("dxgi.dll")) + { + PanicAlertT("Failed to load dxgi.dll"); + return false; + } + + if (!s_d3dcompiler_library.Open(D3DCOMPILER_DLL_A)) + { + PanicAlertT("Failed to load %s. If you are using Windows 7, try installing the " + "KB4019990 update package.", + D3DCOMPILER_DLL_A); + s_dxgi_library.Close(); + return false; + } + + // Required symbols. + if (!s_d3dcompiler_library.GetSymbol("D3DCompile", &d3d_compile) || + !s_dxgi_library.GetSymbol("CreateDXGIFactory", &create_dxgi_factory)) + { + PanicAlertT("Failed to find one or more D3D symbols"); + s_d3dcompiler_library.Close(); + s_dxgi_library.Close(); + return false; + } + + // Optional symbols. + s_dxgi_library.GetSymbol("CreateDXGIFactory2", &create_dxgi_factory2); + s_libraries_loaded = true; + return true; +} + +void UnloadLibraries() +{ + create_dxgi_factory = nullptr; + create_dxgi_factory2 = nullptr; + d3d_compile = nullptr; + s_d3dcompiler_library.Close(); + s_dxgi_library.Close(); + s_libraries_loaded = false; +} + +IDXGIFactory2* CreateDXGIFactory(bool debug_device) +{ + IDXGIFactory2* factory; + + // Use Win8.1 version if available. + if (create_dxgi_factory2 && + SUCCEEDED(create_dxgi_factory2(debug_device ? DXGI_CREATE_FACTORY_DEBUG : 0, + IID_PPV_ARGS(&factory)))) + { + return factory; + } + + // Fallback to original version, without debug support. + HRESULT hr = create_dxgi_factory(IID_PPV_ARGS(&factory)); + if (FAILED(hr)) + { + PanicAlert("CreateDXGIFactory() failed with HRESULT %08X", hr); + return nullptr; + } + + return factory; +} + +std::vector GetAdapterNames() +{ + Microsoft::WRL::ComPtr factory; + HRESULT hr = create_dxgi_factory(IID_PPV_ARGS(&factory)); + if (!SUCCEEDED(hr)) + return {}; + + std::vector adapters; + IDXGIAdapter* adapter; + while (factory->EnumAdapters(static_cast(adapters.size()), &adapter) != + DXGI_ERROR_NOT_FOUND) + { + std::string name; + DXGI_ADAPTER_DESC desc; + if (SUCCEEDED(adapter->GetDesc(&desc))) + name = UTF16ToUTF8(desc.Description); + + adapters.push_back(std::move(name)); + } + + return adapters; +} + +DXGI_FORMAT GetDXGIFormatForAbstractFormat(AbstractTextureFormat format, bool typeless) +{ + switch (format) + { + case AbstractTextureFormat::DXT1: + return DXGI_FORMAT_BC1_UNORM; + case AbstractTextureFormat::DXT3: + return DXGI_FORMAT_BC2_UNORM; + case AbstractTextureFormat::DXT5: + return DXGI_FORMAT_BC3_UNORM; + case AbstractTextureFormat::BPTC: + return DXGI_FORMAT_BC7_UNORM; + case AbstractTextureFormat::RGBA8: + return typeless ? DXGI_FORMAT_R8G8B8A8_TYPELESS : DXGI_FORMAT_R8G8B8A8_UNORM; + case AbstractTextureFormat::BGRA8: + return typeless ? DXGI_FORMAT_B8G8R8A8_TYPELESS : DXGI_FORMAT_B8G8R8A8_UNORM; + case AbstractTextureFormat::R16: + return typeless ? DXGI_FORMAT_R16_TYPELESS : DXGI_FORMAT_R16_UNORM; + case AbstractTextureFormat::R32F: + return typeless ? DXGI_FORMAT_R32_TYPELESS : DXGI_FORMAT_R32_FLOAT; + case AbstractTextureFormat::D16: + return DXGI_FORMAT_R16_TYPELESS; + case AbstractTextureFormat::D24_S8: + return DXGI_FORMAT_R24G8_TYPELESS; + case AbstractTextureFormat::D32F: + return DXGI_FORMAT_R32_TYPELESS; + case AbstractTextureFormat::D32F_S8: + return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; + default: + PanicAlert("Unhandled texture format."); + return DXGI_FORMAT_R8G8B8A8_UNORM; + } +} +DXGI_FORMAT GetSRVFormatForAbstractFormat(AbstractTextureFormat format) +{ + switch (format) + { + case AbstractTextureFormat::DXT1: + return DXGI_FORMAT_BC1_UNORM; + case AbstractTextureFormat::DXT3: + return DXGI_FORMAT_BC2_UNORM; + case AbstractTextureFormat::DXT5: + return DXGI_FORMAT_BC3_UNORM; + case AbstractTextureFormat::BPTC: + return DXGI_FORMAT_BC7_UNORM; + case AbstractTextureFormat::RGBA8: + return DXGI_FORMAT_R8G8B8A8_UNORM; + case AbstractTextureFormat::BGRA8: + return DXGI_FORMAT_B8G8R8A8_UNORM; + case AbstractTextureFormat::R16: + return DXGI_FORMAT_R16_UNORM; + case AbstractTextureFormat::R32F: + return DXGI_FORMAT_R32_FLOAT; + case AbstractTextureFormat::D16: + return DXGI_FORMAT_R16_UNORM; + case AbstractTextureFormat::D24_S8: + return DXGI_FORMAT_R24_UNORM_X8_TYPELESS; + case AbstractTextureFormat::D32F: + return DXGI_FORMAT_R32_FLOAT; + case AbstractTextureFormat::D32F_S8: + return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; + default: + PanicAlert("Unhandled SRV format"); + return DXGI_FORMAT_UNKNOWN; + } +} + +DXGI_FORMAT GetRTVFormatForAbstractFormat(AbstractTextureFormat format, bool integer) +{ + switch (format) + { + case AbstractTextureFormat::RGBA8: + return integer ? DXGI_FORMAT_R8G8B8A8_UINT : DXGI_FORMAT_R8G8B8A8_UNORM; + case AbstractTextureFormat::BGRA8: + return DXGI_FORMAT_B8G8R8A8_UNORM; + case AbstractTextureFormat::R16: + return integer ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R16_UNORM; + case AbstractTextureFormat::R32F: + return DXGI_FORMAT_R32_FLOAT; + default: + PanicAlert("Unhandled RTV format"); + return DXGI_FORMAT_UNKNOWN; + } +} +DXGI_FORMAT GetDSVFormatForAbstractFormat(AbstractTextureFormat format) +{ + switch (format) + { + case AbstractTextureFormat::D16: + return DXGI_FORMAT_D16_UNORM; + case AbstractTextureFormat::D24_S8: + return DXGI_FORMAT_D24_UNORM_S8_UINT; + case AbstractTextureFormat::D32F: + return DXGI_FORMAT_D32_FLOAT; + case AbstractTextureFormat::D32F_S8: + return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; + default: + PanicAlert("Unhandled DSV format"); + return DXGI_FORMAT_UNKNOWN; + } +} + +AbstractTextureFormat GetAbstractFormatForDXGIFormat(DXGI_FORMAT format) +{ + switch (format) + { + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + return AbstractTextureFormat::RGBA8; + + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + return AbstractTextureFormat::BGRA8; + + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_TYPELESS: + return AbstractTextureFormat::R16; + + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_TYPELESS: + return AbstractTextureFormat::R32F; + + case DXGI_FORMAT_D16_UNORM: + return AbstractTextureFormat::D16; + + case DXGI_FORMAT_D24_UNORM_S8_UINT: + return AbstractTextureFormat::D24_S8; + + case DXGI_FORMAT_D32_FLOAT: + return AbstractTextureFormat::D32F; + + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + return AbstractTextureFormat::D32F_S8; + + case DXGI_FORMAT_BC1_UNORM: + return AbstractTextureFormat::DXT1; + case DXGI_FORMAT_BC2_UNORM: + return AbstractTextureFormat::DXT3; + case DXGI_FORMAT_BC3_UNORM: + return AbstractTextureFormat::DXT5; + case DXGI_FORMAT_BC7_UNORM: + return AbstractTextureFormat::BPTC; + + default: + return AbstractTextureFormat::Undefined; + } +} + +void SetDebugObjectName(IUnknown* resource, const char* format, ...) +{ + if (!g_ActiveConfig.bEnableValidationLayer) + return; + + std::va_list ap; + va_start(ap, format); + std::string name = StringFromFormatV(format, ap); + va_end(ap); + + Microsoft::WRL::ComPtr child11; + Microsoft::WRL::ComPtr child12; + if (SUCCEEDED(resource->QueryInterface(IID_PPV_ARGS(&child11)))) + { + child11->SetPrivateData(WKPDID_D3DDebugObjectName, static_cast(name.length()), + name.c_str()); + } + else if (SUCCEEDED(resource->QueryInterface(IID_PPV_ARGS(&child12)))) + { + child12->SetPrivateData(WKPDID_D3DDebugObjectName, static_cast(name.length()), + name.c_str()); + } +} + +std::string GetDebugObjectName(IUnknown* resource) +{ + if (!g_ActiveConfig.bEnableValidationLayer) + return {}; + + std::string name; + UINT size = 0; + + Microsoft::WRL::ComPtr child11; + Microsoft::WRL::ComPtr child12; + if (SUCCEEDED(resource->QueryInterface(IID_PPV_ARGS(&child11)))) + { + child11->GetPrivateData(WKPDID_D3DDebugObjectName, &size, nullptr); + name.resize(size); + child11->GetPrivateData(WKPDID_D3DDebugObjectName, &size, name.data()); + } + else if (SUCCEEDED(resource->QueryInterface(IID_PPV_ARGS(&child12)))) + { + child12->GetPrivateData(WKPDID_D3DDebugObjectName, &size, nullptr); + name.resize(size); + child12->GetPrivateData(WKPDID_D3DDebugObjectName, &size, name.data()); + } + + return name; +} +} // namespace D3DCommon diff --git a/Source/Core/VideoBackends/D3DCommon/Common.h b/Source/Core/VideoBackends/D3DCommon/Common.h new file mode 100644 index 0000000000..3fd5710b05 --- /dev/null +++ b/Source/Core/VideoBackends/D3DCommon/Common.h @@ -0,0 +1,46 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include + +#include "Common/CommonTypes.h" +#include "VideoCommon/VideoCommon.h" + +struct IDXGIFactory2; + +enum class AbstractTextureFormat : u32; + +namespace D3DCommon +{ +// Loading dxgi.dll and d3dcompiler.dll +bool LoadLibraries(); +void UnloadLibraries(); + +// Returns a list of D3D device names. +std::vector GetAdapterNames(); + +// Helper function which creates a DXGI factory. +IDXGIFactory2* CreateDXGIFactory(bool debug_device); + +// Globally-accessible D3DCompiler function. +extern pD3DCompile d3d_compile; + +// Helpers for texture format conversion. +DXGI_FORMAT GetDXGIFormatForAbstractFormat(AbstractTextureFormat format, bool typeless); +DXGI_FORMAT GetSRVFormatForAbstractFormat(AbstractTextureFormat format); +DXGI_FORMAT GetRTVFormatForAbstractFormat(AbstractTextureFormat format, bool integer); +DXGI_FORMAT GetDSVFormatForAbstractFormat(AbstractTextureFormat format); +AbstractTextureFormat GetAbstractFormatForDXGIFormat(DXGI_FORMAT format); + +// This function will assign a name to the given resource. +// The DirectX debug layer will make it easier to identify resources that way, +// e.g. when listing up all resources who have unreleased references. +void SetDebugObjectName(IUnknown* resource, const char* format, ...); +std::string GetDebugObjectName(IUnknown* resource); +} // namespace D3DCommon diff --git a/Source/Core/VideoBackends/D3DCommon/D3DCommon.vcxproj b/Source/Core/VideoBackends/D3DCommon/D3DCommon.vcxproj new file mode 100644 index 0000000000..7b94ad2b97 --- /dev/null +++ b/Source/Core/VideoBackends/D3DCommon/D3DCommon.vcxproj @@ -0,0 +1,68 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {DEA96CF2-F237-4A1A-B32F-C916769EFB50} + 10.0.17134.0 + + + + StaticLibrary + v141 + Unicode + + + true + + + false + + + + + + + + + + + + + NotUsing + + + + + + NotUsing + + + + + + + + + + + + + + + + {3de9ee35-3e91-4f27-a014-2866ad8c3fe3} + + + + + + \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3DCommon/D3DCommon.vcxproj.filters b/Source/Core/VideoBackends/D3DCommon/D3DCommon.vcxproj.filters new file mode 100644 index 0000000000..94fb9dd5a9 --- /dev/null +++ b/Source/Core/VideoBackends/D3DCommon/D3DCommon.vcxproj.filters @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Core/VideoBackends/D3DCommon/Shader.cpp b/Source/Core/VideoBackends/D3DCommon/Shader.cpp new file mode 100644 index 0000000000..d53c5ab2e4 --- /dev/null +++ b/Source/Core/VideoBackends/D3DCommon/Shader.cpp @@ -0,0 +1,145 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include + +#include "Common/Assert.h" +#include "Common/FileUtil.h" +#include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" +#include "Common/StringUtil.h" + +#include "VideoBackends/D3DCommon/Shader.h" +#include "VideoCommon/VideoConfig.h" + +namespace D3DCommon +{ +Shader::Shader(ShaderStage stage, BinaryData bytecode) + : AbstractShader(stage), m_bytecode(std::move(bytecode)) +{ +} + +Shader::~Shader() = default; + +bool Shader::HasBinary() const +{ + return true; +} + +AbstractShader::BinaryData Shader::GetBinary() const +{ + return m_bytecode; +} + +static const char* GetCompileTarget(D3D_FEATURE_LEVEL feature_level, ShaderStage stage) +{ + switch (stage) + { + case ShaderStage::Vertex: + { + switch (feature_level) + { + case D3D_FEATURE_LEVEL_10_0: + return "vs_4_0"; + case D3D_FEATURE_LEVEL_10_1: + return "vs_4_1"; + default: + return "vs_5_0"; + } + } + + case ShaderStage::Geometry: + { + switch (feature_level) + { + case D3D_FEATURE_LEVEL_10_0: + return "gs_4_0"; + case D3D_FEATURE_LEVEL_10_1: + return "gs_4_1"; + default: + return "gs_5_0"; + } + } + + case ShaderStage::Pixel: + { + switch (feature_level) + { + case D3D_FEATURE_LEVEL_10_0: + return "ps_4_0"; + case D3D_FEATURE_LEVEL_10_1: + return "ps_4_1"; + default: + return "ps_5_0"; + } + } + + case ShaderStage::Compute: + { + switch (feature_level) + { + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_10_1: + return ""; + + default: + return "cs_5_0"; + } + } + + default: + return ""; + } +} + +bool Shader::CompileShader(D3D_FEATURE_LEVEL feature_level, BinaryData* out_bytecode, + ShaderStage stage, const char* source, size_t length) +{ + static constexpr D3D_SHADER_MACRO macros[] = {{"API_D3D", "1"}, {nullptr, nullptr}}; + const UINT flags = g_ActiveConfig.bEnableValidationLayer ? + (D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION) : + (D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_SKIP_VALIDATION); + const char* target = GetCompileTarget(feature_level, stage); + + Microsoft::WRL::ComPtr code; + Microsoft::WRL::ComPtr errors; + HRESULT hr = d3d_compile(source, length, nullptr, macros, nullptr, "main", target, flags, 0, + &code, &errors); + if (FAILED(hr)) + { + static int num_failures = 0; + std::string filename = StringFromFormat( + "%sbad_%s_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), target, num_failures++); + std::ofstream file; + File::OpenFStream(file, filename, std::ios_base::out); + file.write(source, length); + file << "\n"; + file.write(static_cast(errors->GetBufferPointer()), errors->GetBufferSize()); + file.close(); + + PanicAlert("Failed to compile %s:\nDebug info (%s):\n%s", filename.c_str(), target, + static_cast(errors->GetBufferPointer())); + return false; + } + + if (errors && errors->GetBufferSize() > 0) + { + WARN_LOG(VIDEO, "%s compilation succeeded with warnings:\n%s", target, + static_cast(errors->GetBufferPointer())); + } + + out_bytecode->resize(code->GetBufferSize()); + std::memcpy(out_bytecode->data(), code->GetBufferPointer(), code->GetBufferSize()); + return true; +} + +AbstractShader::BinaryData Shader::CreateByteCode(const void* data, size_t length) +{ + BinaryData bytecode(length); + std::memcpy(bytecode.data(), data, length); + return bytecode; +} + +} // namespace D3DCommon diff --git a/Source/Core/VideoBackends/D3DCommon/Shader.h b/Source/Core/VideoBackends/D3DCommon/Shader.h new file mode 100644 index 0000000000..6513cd11fe --- /dev/null +++ b/Source/Core/VideoBackends/D3DCommon/Shader.h @@ -0,0 +1,33 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once +#include +#include "VideoBackends/D3DCommon/Common.h" +#include "VideoCommon/AbstractShader.h" + +namespace D3DCommon +{ +class Shader : public AbstractShader +{ +public: + virtual ~Shader() override; + + const BinaryData& GetByteCode() const { return m_bytecode; } + + bool HasBinary() const override; + BinaryData GetBinary() const override; + + static bool CompileShader(D3D_FEATURE_LEVEL feature_level, BinaryData* out_bytecode, + ShaderStage stage, const char* source, size_t length); + + static BinaryData CreateByteCode(const void* data, size_t length); + +protected: + Shader(ShaderStage stage, BinaryData bytecode); + + BinaryData m_bytecode; +}; + +} // namespace D3DCommon diff --git a/Source/Core/VideoBackends/D3DCommon/SwapChain.cpp b/Source/Core/VideoBackends/D3DCommon/SwapChain.cpp new file mode 100644 index 0000000000..376f891a96 --- /dev/null +++ b/Source/Core/VideoBackends/D3DCommon/SwapChain.cpp @@ -0,0 +1,232 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "VideoBackends/D3DCommon/SwapChain.h" + +#include +#include + +#include "Common/Assert.h" +#include "Common/CommonFuncs.h" +#include "Common/Logging/Log.h" +#include "Common/MsgHandler.h" +#include "VideoCommon/VideoConfig.h" + +static bool IsTearingSupported(IDXGIFactory2* dxgi_factory) +{ + Microsoft::WRL::ComPtr factory5; + if (FAILED(dxgi_factory->QueryInterface(IID_PPV_ARGS(&factory5)))) + return false; + + UINT allow_tearing = 0; + return SUCCEEDED(factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing, + sizeof(allow_tearing))) && + allow_tearing != 0; +} + +static bool GetFullscreenState(IDXGISwapChain1* swap_chain) +{ + BOOL fs = FALSE; + return SUCCEEDED(swap_chain->GetFullscreenState(&fs, nullptr)) && fs; +} + +namespace D3DCommon +{ +SwapChain::SwapChain(const WindowSystemInfo& wsi, IDXGIFactory2* dxgi_factory, IUnknown* d3d_device) + : m_wsi(wsi), m_dxgi_factory(dxgi_factory), m_d3d_device(d3d_device), + m_allow_tearing_supported(IsTearingSupported(dxgi_factory)) +{ +} + +SwapChain::~SwapChain() +{ + // Can't destroy swap chain while it's fullscreen. + if (m_swap_chain && GetFullscreenState(m_swap_chain.Get())) + m_swap_chain->SetFullscreenState(FALSE, nullptr); +} + +bool SwapChain::WantsStereo() +{ + return g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer; +} + +u32 SwapChain::GetSwapChainFlags() const +{ + // This flag is necessary if we want to use a flip-model swapchain without locking the framerate + return m_allow_tearing_supported ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0; +} + +bool SwapChain::CreateSwapChain(bool stereo) +{ + RECT client_rc; + if (GetClientRect(static_cast(m_wsi.render_surface), &client_rc)) + { + m_width = client_rc.right - client_rc.left; + m_height = client_rc.bottom - client_rc.top; + } + + DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {}; + swap_chain_desc.Width = m_width; + swap_chain_desc.Height = m_height; + swap_chain_desc.BufferCount = SWAP_CHAIN_BUFFER_COUNT; + swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swap_chain_desc.SampleDesc.Count = 1; + swap_chain_desc.SampleDesc.Quality = 0; + swap_chain_desc.Format = GetDXGIFormatForAbstractFormat(m_texture_format, false); + swap_chain_desc.Scaling = DXGI_SCALING_STRETCH; + swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + swap_chain_desc.Stereo = stereo; + swap_chain_desc.Flags = GetSwapChainFlags(); + + HRESULT hr = m_dxgi_factory->CreateSwapChainForHwnd( + m_d3d_device.Get(), static_cast(m_wsi.render_surface), &swap_chain_desc, nullptr, + nullptr, &m_swap_chain); + if (FAILED(hr)) + { + // Flip-model discard swapchains aren't supported on Windows 8, so here we fall back to + // a sequential swapchain + swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + hr = m_dxgi_factory->CreateSwapChainForHwnd(m_d3d_device.Get(), + static_cast(m_wsi.render_surface), + &swap_chain_desc, nullptr, nullptr, &m_swap_chain); + } + + if (FAILED(hr)) + { + // Flip-model swapchains aren't supported on Windows 7, so here we fall back to a legacy + // BitBlt-model swapchain + swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + hr = m_dxgi_factory->CreateSwapChainForHwnd(m_d3d_device.Get(), + static_cast(m_wsi.render_surface), + &swap_chain_desc, nullptr, nullptr, &m_swap_chain); + } + + if (FAILED(hr)) + { + PanicAlert("Failed to create swap chain with HRESULT %08X", hr); + return false; + } + + // We handle fullscreen ourselves. + hr = m_dxgi_factory->MakeWindowAssociation(static_cast(m_wsi.render_surface), + DXGI_MWA_NO_WINDOW_CHANGES | DXGI_MWA_NO_ALT_ENTER); + if (FAILED(hr)) + WARN_LOG(VIDEO, "MakeWindowAssociation() failed with HRESULT %08X", hr); + + m_stereo = stereo; + if (!CreateSwapChainBuffers()) + { + PanicAlert("Failed to create swap chain buffers"); + DestroySwapChainBuffers(); + m_swap_chain.Reset(); + return false; + } + + return true; +} + +void SwapChain::DestroySwapChain() +{ + DestroySwapChainBuffers(); + + // Can't destroy swap chain while it's fullscreen. + if (m_swap_chain && GetFullscreenState(m_swap_chain.Get())) + m_swap_chain->SetFullscreenState(FALSE, nullptr); + + m_swap_chain.Reset(); +} + +bool SwapChain::ResizeSwapChain() +{ + DestroySwapChainBuffers(); + + HRESULT hr = m_swap_chain->ResizeBuffers(SWAP_CHAIN_BUFFER_COUNT, 0, 0, + GetDXGIFormatForAbstractFormat(m_texture_format, false), + GetSwapChainFlags()); + if (FAILED(hr)) + WARN_LOG(VIDEO, "ResizeBuffers() failed with HRESULT %08X", hr); + + DXGI_SWAP_CHAIN_DESC1 desc; + if (SUCCEEDED(m_swap_chain->GetDesc1(&desc))) + { + m_width = desc.Width; + m_height = desc.Height; + } + + return CreateSwapChainBuffers(); +} + +void SwapChain::SetStereo(bool stereo) +{ + if (m_stereo == stereo) + return; + + DestroySwapChain(); + if (!CreateSwapChain(stereo)) + { + PanicAlert("Failed to switch swap chain stereo mode"); + CreateSwapChain(false); + } +} + +bool SwapChain::GetFullscreen() const +{ + return GetFullscreenState(m_swap_chain.Get()); +} + +void SwapChain::SetFullscreen(bool request) +{ + m_swap_chain->SetFullscreenState(request, nullptr); +} + +bool SwapChain::CheckForFullscreenChange() +{ + if (m_fullscreen_request != m_has_fullscreen) + { + HRESULT hr = m_swap_chain->SetFullscreenState(m_fullscreen_request, nullptr); + if (SUCCEEDED(hr)) + { + m_has_fullscreen = m_fullscreen_request; + return true; + } + } + + const bool new_fullscreen_state = GetFullscreenState(m_swap_chain.Get()); + if (new_fullscreen_state != m_has_fullscreen) + { + m_has_fullscreen = new_fullscreen_state; + m_fullscreen_request = new_fullscreen_state; + return true; + } + + return false; +} + +bool SwapChain::Present() +{ + // When using sync interval 0, it is recommended to always pass the tearing flag when it is + // supported, even when presenting in windowed mode. However, this flag cannot be used if the app + // is in fullscreen mode as a result of calling SetFullscreenState. + UINT present_flags = 0; + if (m_allow_tearing_supported && !g_ActiveConfig.bVSyncActive && !m_has_fullscreen) + present_flags |= DXGI_PRESENT_ALLOW_TEARING; + + HRESULT hr = m_swap_chain->Present(static_cast(g_ActiveConfig.bVSyncActive), present_flags); + if (FAILED(hr)) + { + WARN_LOG(VIDEO, "Swap chain present failed with HRESULT %08X", hr); + return false; + } + + return true; +} + +bool SwapChain::ChangeSurface(void* native_handle) +{ + DestroySwapChain(); + m_wsi.render_surface = native_handle; + return CreateSwapChain(m_stereo); +} + +} // namespace D3DCommon diff --git a/Source/Core/VideoBackends/D3DCommon/SwapChain.h b/Source/Core/VideoBackends/D3DCommon/SwapChain.h new file mode 100644 index 0000000000..b84c1a95c3 --- /dev/null +++ b/Source/Core/VideoBackends/D3DCommon/SwapChain.h @@ -0,0 +1,74 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "Common/CommonTypes.h" +#include "Common/WindowSystemInfo.h" +#include "VideoBackends/D3DCommon/Common.h" +#include "VideoCommon/TextureConfig.h" + +namespace D3DCommon +{ +class SwapChain +{ +public: + SwapChain(const WindowSystemInfo& wsi, IDXGIFactory2* dxgi_factory, IUnknown* d3d_device); + virtual ~SwapChain(); + + // Sufficient buffers for triple buffering. + static const u32 SWAP_CHAIN_BUFFER_COUNT = 3; + + // Returns true if the stereo mode is quad-buffering. + static bool WantsStereo(); + + IDXGISwapChain1* GetDXGISwapChain() const { return m_swap_chain.Get(); } + AbstractTextureFormat GetFormat() const { return m_texture_format; } + u32 GetWidth() const { return m_width; } + u32 GetHeight() const { return m_height; } + u32 GetLayers() const { return m_stereo ? 2u : 1u; } + bool IsStereoEnabled() const { return m_stereo; } + bool HasExclusiveFullscreen() const { return m_has_fullscreen; } + + // Mode switches. + bool GetFullscreen() const; + void SetFullscreen(bool request); + + // Checks for loss of exclusive fullscreen. + bool CheckForFullscreenChange(); + + // Presents the swap chain to the screen. + virtual bool Present(); + + bool ChangeSurface(void* native_handle); + bool ResizeSwapChain(); + void SetStereo(bool stereo); + +protected: + u32 GetSwapChainFlags() const; + bool CreateSwapChain(bool stereo); + void DestroySwapChain(); + + virtual bool CreateSwapChainBuffers() = 0; + virtual void DestroySwapChainBuffers() = 0; + + WindowSystemInfo m_wsi; + Microsoft::WRL::ComPtr m_dxgi_factory; + Microsoft::WRL::ComPtr m_swap_chain; + Microsoft::WRL::ComPtr m_d3d_device; + AbstractTextureFormat m_texture_format = AbstractTextureFormat::RGBA8; + + u32 m_width = 1; + u32 m_height = 1; + + bool m_stereo = false; + bool m_allow_tearing_supported = false; + bool m_has_fullscreen = false; + bool m_fullscreen_request = false; +}; + +} // namespace D3DCommon diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp index 2dc1ef318c..61cd953b69 100644 --- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp +++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp @@ -39,8 +39,6 @@ namespace OGL { -static constexpr u32 UBO_LENGTH = 32 * 1024 * 1024; - u32 ProgramShaderCache::s_ubo_buffer_size; s32 ProgramShaderCache::s_ubo_align; GLuint ProgramShaderCache::s_attributeless_VBO = 0; @@ -497,7 +495,7 @@ void ProgramShaderCache::Init() // We multiply by *4*4 because we need to get down to basic machine units. // So multiply by four to get how many floats we have from vec4s // Then once more to get bytes - s_buffer = StreamBuffer::Create(GL_UNIFORM_BUFFER, UBO_LENGTH); + s_buffer = StreamBuffer::Create(GL_UNIFORM_BUFFER, VertexManagerBase::UNIFORM_STREAM_BUFFER_SIZE); CreateHeader(); CreateAttributelessVAO(); diff --git a/Source/Core/VideoBackends/OGL/main.cpp b/Source/Core/VideoBackends/OGL/main.cpp index 22dba1a21f..3ca016556b 100644 --- a/Source/Core/VideoBackends/OGL/main.cpp +++ b/Source/Core/VideoBackends/OGL/main.cpp @@ -135,6 +135,8 @@ bool VideoBackend::InitializeGLExtensions(GLContext* context) bool VideoBackend::FillBackendInfo() { + InitBackendInfo(); + // check for the max vertex attributes GLint numvertexattribs = 0; glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &numvertexattribs); @@ -162,10 +164,8 @@ bool VideoBackend::FillBackendInfo() bool VideoBackend::Initialize(const WindowSystemInfo& wsi) { - InitializeShared(); - std::unique_ptr main_gl_context = - GLContext::Create(wsi, g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer, true, false, + GLContext::Create(wsi, g_Config.stereo_mode == StereoMode::QuadBuffer, true, false, Config::Get(Config::GFX_PREFER_GLES)); if (!main_gl_context) return false; @@ -173,6 +173,7 @@ bool VideoBackend::Initialize(const WindowSystemInfo& wsi) if (!InitializeGLExtensions(main_gl_context.get()) || !FillBackendInfo()) return false; + InitializeShared(); g_renderer = std::make_unique(std::move(main_gl_context), wsi.render_surface_scale); ProgramShaderCache::Init(); g_vertex_manager = std::make_unique(); diff --git a/Source/Core/VideoBackends/Vulkan/VulkanLoader.cpp b/Source/Core/VideoBackends/Vulkan/VulkanLoader.cpp index d8d1e99d0c..bfc8b5673e 100644 --- a/Source/Core/VideoBackends/Vulkan/VulkanLoader.cpp +++ b/Source/Core/VideoBackends/Vulkan/VulkanLoader.cpp @@ -7,18 +7,13 @@ #include #include "Common/CommonFuncs.h" +#include "Common/DynamicLibrary.h" #include "Common/FileUtil.h" #include "Common/Logging/Log.h" #include "Common/StringUtil.h" #include "VideoBackends/Vulkan/VulkanLoader.h" -#if defined(_WIN32) -#include -#else -#include -#endif - #define VULKAN_MODULE_ENTRY_POINT(name, required) PFN_##name name; #define VULKAN_INSTANCE_ENTRY_POINT(name, required) PFN_##name name; #define VULKAN_DEVICE_ENTRY_POINT(name, required) PFN_##name name; @@ -40,145 +35,56 @@ static void ResetVulkanLibraryFunctionPointers() #undef VULKAN_MODULE_ENTRY_POINT } -#if defined(_WIN32) +static Common::DynamicLibrary s_vulkan_module; -static HMODULE vulkan_module; -static std::atomic_int vulkan_module_ref_count = {0}; - -bool LoadVulkanLibrary() +static std::string GetVulkanLibraryFilename() { - // Not thread safe if a second thread calls the loader whilst the first is still in-progress. - if (vulkan_module) - { - vulkan_module_ref_count++; - return true; - } - - vulkan_module = LoadLibraryA("vulkan-1.dll"); - if (!vulkan_module) - { - ERROR_LOG(VIDEO, "Failed to load vulkan-1.dll"); - return false; - } - - bool required_functions_missing = false; - auto LoadFunction = [&](FARPROC* func_ptr, const char* name, bool is_required) { - *func_ptr = GetProcAddress(vulkan_module, name); - if (!(*func_ptr) && is_required) - { - ERROR_LOG(VIDEO, "Vulkan: Failed to load required module function %s", name); - required_functions_missing = true; - } - }; - -#define VULKAN_MODULE_ENTRY_POINT(name, required) \ - LoadFunction(reinterpret_cast(&name), #name, required); -#include "VideoBackends/Vulkan/VulkanEntryPoints.inl" -#undef VULKAN_MODULE_ENTRY_POINT - - if (required_functions_missing) - { - ResetVulkanLibraryFunctionPointers(); - FreeLibrary(vulkan_module); - vulkan_module = nullptr; - return false; - } - - vulkan_module_ref_count++; - return true; -} - -void UnloadVulkanLibrary() -{ - if ((--vulkan_module_ref_count) > 0) - return; - - ResetVulkanLibraryFunctionPointers(); - FreeLibrary(vulkan_module); - vulkan_module = nullptr; -} - -#else - -static void* vulkan_module; -static std::atomic_int vulkan_module_ref_count = {0}; - -bool LoadVulkanLibrary() -{ - // Not thread safe if a second thread calls the loader whilst the first is still in-progress. - if (vulkan_module) - { - vulkan_module_ref_count++; - return true; - } - -#if defined(__APPLE__) +#ifdef __APPLE__ // Check if a path to a specific Vulkan library has been specified. char* libvulkan_env = getenv("LIBVULKAN_PATH"); if (libvulkan_env) - vulkan_module = dlopen(libvulkan_env, RTLD_NOW); - if (!vulkan_module) - { - // Use the libvulkan.dylib from the application bundle. - std::string path = File::GetBundleDirectory() + "/Contents/Frameworks/libvulkan.dylib"; - vulkan_module = dlopen(path.c_str(), RTLD_NOW); - } + return std::string(libvulkan_env); + + // Use the libvulkan.dylib from the application bundle. + return File::GetBundleDirectory() + "/Contents/Frameworks/libvulkan.dylib"; #else - // Names of libraries to search. Desktop should use libvulkan.so.1 or libvulkan.so. - static const char* search_lib_names[] = {"libvulkan.so.1", "libvulkan.so"}; - for (size_t i = 0; i < ArraySize(search_lib_names); i++) - { - vulkan_module = dlopen(search_lib_names[i], RTLD_NOW); - if (vulkan_module) - break; - } + return Common::DynamicLibrary::GetVersionedFilename("vulkan", 1); #endif +} - if (!vulkan_module) +bool LoadVulkanLibrary() +{ + if (!s_vulkan_module.IsOpen()) { - ERROR_LOG(VIDEO, "Failed to load or locate libvulkan.so"); - return false; - } - - bool required_functions_missing = false; - auto LoadFunction = [&](void** func_ptr, const char* name, bool is_required) { - *func_ptr = dlsym(vulkan_module, name); - if (!(*func_ptr) && is_required) + const std::string filename = GetVulkanLibraryFilename(); + if (!s_vulkan_module.Open(filename.c_str())) { - ERROR_LOG(VIDEO, "Vulkan: Failed to load required module function %s", name); - required_functions_missing = true; + ERROR_LOG(VIDEO, "Failed to load %s", filename.c_str()); + return false; } - }; + } #define VULKAN_MODULE_ENTRY_POINT(name, required) \ - LoadFunction(reinterpret_cast(&name), #name, required); + if (!s_vulkan_module.GetSymbol(#name, &name) && required) \ + { \ + ERROR_LOG(VIDEO, "Vulkan: Failed to load required module function %s", #name); \ + ResetVulkanLibraryFunctionPointers(); \ + s_vulkan_module.Close(); \ + return false; \ + } #include "VideoBackends/Vulkan/VulkanEntryPoints.inl" #undef VULKAN_MODULE_ENTRY_POINT - if (required_functions_missing) - { - ResetVulkanLibraryFunctionPointers(); - dlclose(vulkan_module); - vulkan_module = nullptr; - return false; - } - - vulkan_module_ref_count++; return true; } void UnloadVulkanLibrary() { - if ((--vulkan_module_ref_count) > 0) - return; - - ResetVulkanLibraryFunctionPointers(); - dlclose(vulkan_module); - vulkan_module = nullptr; + s_vulkan_module.Close(); + if (!s_vulkan_module.IsOpen()) + ResetVulkanLibraryFunctionPointers(); } -#endif - bool LoadVulkanInstanceFunctions(VkInstance instance) { bool required_functions_missing = false; diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index 1a15f0aec0..688c7fc43b 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -151,6 +151,11 @@ std::unique_ptr Renderer::CreateShaderFromSource(ShaderStage sta return CreateShaderFromSource(stage, source.c_str(), source.size()); } +bool Renderer::EFBHasAlphaChannel() const +{ + return m_prev_efb_format == PEControl::RGBA6_Z24; +} + void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) { diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index 6ee03a9156..af9c1a8972 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -224,6 +224,7 @@ public: PEControl::PixelFormat GetPrevPixelFormat() const { return m_prev_efb_format; } void StorePixelFormat(PEControl::PixelFormat new_format) { m_prev_efb_format = new_format; } + bool EFBHasAlphaChannel() const; VideoCommon::PostProcessing* GetPostProcessor() const { return m_post_processor.get(); } // Final surface changing // This is called when the surface is resized (WX) or the window changes (Android). diff --git a/Source/Core/VideoCommon/ShaderCache.cpp b/Source/Core/VideoCommon/ShaderCache.cpp index b42587a2d4..8f9c99d39d 100644 --- a/Source/Core/VideoCommon/ShaderCache.cpp +++ b/Source/Core/VideoCommon/ShaderCache.cpp @@ -966,10 +966,16 @@ void ShaderCache::QueueUberShaderPipelines() config.vs_uid = vs_uid; config.gs_uid = gs_uid; config.ps_uid = ps_uid; - config.rasterization_state = - RenderState::GetCullBackFaceRasterizationState(PrimitiveType::TriangleStrip); + config.rasterization_state = RenderState::GetCullBackFaceRasterizationState( + static_cast(gs_uid.GetUidData()->primitive_type)); config.depth_state = RenderState::GetNoDepthTestingDepthState(); config.blending_state = RenderState::GetNoBlendingBlendState(); + if (ps_uid.GetUidData()->uint_output) + { + // uint_output is only ever enabled when logic ops are enabled. + config.blending_state.logicopenable = true; + config.blending_state.logicmode = BlendMode::AND; + } auto iter = m_gx_uber_pipeline_cache.find(config); if (iter != m_gx_uber_pipeline_cache.end()) @@ -986,13 +992,15 @@ void ShaderCache::QueueUberShaderPipelines() if (vuid.GetUidData()->num_texgens != puid.GetUidData()->num_texgens) return; + UberShader::PixelShaderUid cleared_puid = puid; + UberShader::ClearUnusedPixelShaderUidBits(m_api_type, m_host_config, &cleared_puid); EnumerateGeometryShaderUids([&](const GeometryShaderUid& guid) { if (guid.GetUidData()->numTexGens != vuid.GetUidData()->num_texgens || (!guid.GetUidData()->IsPassthrough() && !m_host_config.backend_geometry_shaders)) { return; } - QueueDummyPipeline(vuid, guid, puid); + QueueDummyPipeline(vuid, guid, cleared_puid); }); }); }); diff --git a/Source/Core/VideoCommon/VertexManagerBase.h b/Source/Core/VideoCommon/VertexManagerBase.h index 9a657bd7f3..ba1d98c236 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.h +++ b/Source/Core/VideoCommon/VertexManagerBase.h @@ -54,9 +54,9 @@ public: // Streaming buffer sizes. // Texel buffer will fit the maximum size of an encoded GX texture. 1024x1024, RGBA8 = 4MB. - static constexpr u32 VERTEX_STREAM_BUFFER_SIZE = 40 * 1024 * 1024; - static constexpr u32 INDEX_STREAM_BUFFER_SIZE = 4 * 1024 * 1024; - static constexpr u32 UNIFORM_STREAM_BUFFER_SIZE = 16 * 1024 * 1024; + static constexpr u32 VERTEX_STREAM_BUFFER_SIZE = 48 * 1024 * 1024; + static constexpr u32 INDEX_STREAM_BUFFER_SIZE = 8 * 1024 * 1024; + static constexpr u32 UNIFORM_STREAM_BUFFER_SIZE = 32 * 1024 * 1024; static constexpr u32 TEXEL_STREAM_BUFFER_SIZE = 16 * 1024 * 1024; VertexManagerBase(); diff --git a/Source/Core/VideoCommon/VideoBackendBase.cpp b/Source/Core/VideoCommon/VideoBackendBase.cpp index 268a3b70b7..f310f68920 100644 --- a/Source/Core/VideoCommon/VideoBackendBase.cpp +++ b/Source/Core/VideoCommon/VideoBackendBase.cpp @@ -294,6 +294,7 @@ void VideoBackendBase::InitializeShared() GeometryShaderManager::Init(); PixelShaderManager::Init(); + g_Config.VerifyValidity(); UpdateActiveConfig(); } diff --git a/Source/dolphin-emu.sln b/Source/dolphin-emu.sln index 20b4d9d146..0e4ef7ca99 100644 --- a/Source/dolphin-emu.sln +++ b/Source/dolphin-emu.sln @@ -93,6 +93,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imgui", "..\Externals\imgui EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UpdaterCommon", "Core\UpdaterCommon\UpdaterCommon.vcxproj", "{B001D13E-7EAB-4689-842D-801E5ACFFAC5}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "D3DCommon", "Core\VideoBackends\D3DCommon\D3DCommon.vcxproj", "{DEA96CF2-F237-4A1A-B32F-C916769EFB50}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -353,6 +355,12 @@ Global {B001D13E-7EAB-4689-842D-801E5ACFFAC5}.Release|x64.ActiveCfg = Release|x64 {B001D13E-7EAB-4689-842D-801E5ACFFAC5}.Release|x64.Build.0 = Release|x64 {B001D13E-7EAB-4689-842D-801E5ACFFAC5}.Release|x86.ActiveCfg = Release|x64 + {DEA96CF2-F237-4A1A-B32F-C916769EFB50}.Debug|x64.ActiveCfg = Debug|x64 + {DEA96CF2-F237-4A1A-B32F-C916769EFB50}.Debug|x64.Build.0 = Debug|x64 + {DEA96CF2-F237-4A1A-B32F-C916769EFB50}.Debug|x86.ActiveCfg = Debug|x64 + {DEA96CF2-F237-4A1A-B32F-C916769EFB50}.Release|x64.ActiveCfg = Release|x64 + {DEA96CF2-F237-4A1A-B32F-C916769EFB50}.Release|x64.Build.0 = Release|x64 + {DEA96CF2-F237-4A1A-B32F-C916769EFB50}.Release|x86.ActiveCfg = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -394,6 +402,7 @@ Global {4482FD2A-EC43-3FFB-AC20-2E5C54B05EAD} = {87ADDFF9-5768-4DA2-A33B-2477593D6677} {23114507-079A-4418-9707-CFA81A03CA99} = {87ADDFF9-5768-4DA2-A33B-2477593D6677} {4C3B2264-EA73-4A7B-9CFE-65B0FD635EBB} = {87ADDFF9-5768-4DA2-A33B-2477593D6677} + {DEA96CF2-F237-4A1A-B32F-C916769EFB50} = {AAD1BCD6-9804-44A5-A5FC-4782EA00E9D4} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {710976F2-1BC7-4F2A-B32D-5DD2BBCB44E1}