diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 4baa21db47..d1f84e3308 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -179,7 +179,7 @@ endif() if(WIN32) enable_language(ASM_MASM) target_sources(common PRIVATE FastJmp.asm) - target_link_libraries(common PUBLIC WIL::WIL D3D12MemAlloc winmm) + target_link_libraries(common PUBLIC WIL::WIL winmm) target_sources(common PRIVATE CrashHandler.cpp CrashHandler.h @@ -188,24 +188,6 @@ if(WIN32) HTTPDownloaderWinHTTP.h StackWalker.cpp StackWalker.h - D3D11/ShaderCache.cpp - D3D11/ShaderCache.h - D3D11/ShaderCompiler.cpp - D3D11/ShaderCompiler.h - D3D12/Builders.cpp - D3D12/Builders.h - D3D12/Context.cpp - D3D12/Context.h - D3D12/DescriptorHeapManager.cpp - D3D12/DescriptorHeapManager.h - D3D12/ShaderCache.cpp - D3D12/ShaderCache.h - D3D12/StreamBuffer.cpp - D3D12/StreamBuffer.h - D3D12/Texture.cpp - D3D12/Texture.h - D3D12/Util.cpp - D3D12/Util.h ) endif() diff --git a/common/D3D11/ShaderCache.h b/common/D3D11/ShaderCache.h deleted file mode 100644 index 001aa14d94..0000000000 --- a/common/D3D11/ShaderCache.h +++ /dev/null @@ -1,117 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2022 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once -#include "common/Pcsx2Defs.h" -#include "common/HashCombine.h" -#include "common/RedtapeWindows.h" -#include "common/RedtapeWilCom.h" -#include "common/D3D11/ShaderCompiler.h" - -#include -#include -#include -#include -#include - -namespace D3D11 -{ - class ShaderCache - { - public: - ShaderCache(); - ~ShaderCache(); - - D3D_FEATURE_LEVEL GetFeatureLevel() const { return m_feature_level; } - bool UsingDebugShaders() const { return m_debug; } - - bool Open(std::string_view base_path, D3D_FEATURE_LEVEL feature_level, u32 version, bool debug); - void Close(); - - wil::com_ptr_nothrow GetShaderBlob(ShaderCompiler::Type type, const std::string_view& shader_code, - const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main"); - - wil::com_ptr_nothrow GetVertexShader(ID3D11Device* device, const std::string_view& shader_code, - const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main"); - - bool GetVertexShaderAndInputLayout(ID3D11Device* device, - ID3D11VertexShader** vs, ID3D11InputLayout** il, - const D3D11_INPUT_ELEMENT_DESC* layout, size_t layout_size, - const std::string_view& shader_code, const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main"); - - wil::com_ptr_nothrow GetPixelShader(ID3D11Device* device, const std::string_view& shader_code, - const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main"); - - wil::com_ptr_nothrow GetComputeShader(ID3D11Device* device, const std::string_view& shader_code, - const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main"); - - private: - static constexpr u32 FILE_VERSION = 1; - - struct CacheIndexKey - { - u64 source_hash_low; - u64 source_hash_high; - u64 macro_hash_low; - u64 macro_hash_high; - u64 entry_point_low; - u64 entry_point_high; - u32 source_length; - ShaderCompiler::Type shader_type; - - bool operator==(const CacheIndexKey& key) const; - bool operator!=(const CacheIndexKey& key) const; - }; - - struct CacheIndexEntryHasher - { - std::size_t operator()(const CacheIndexKey& e) const noexcept - { - std::size_t h = 0; - HashCombine(h, e.entry_point_low, e.entry_point_high, e.macro_hash_low, e.macro_hash_high, - e.source_hash_low, e.source_hash_high, e.source_length, e.shader_type); - return h; - } - }; - - struct CacheIndexData - { - u32 file_offset; - u32 blob_size; - }; - - using CacheIndex = std::unordered_map; - - static std::string GetCacheBaseFileName(const std::string_view& base_path, D3D_FEATURE_LEVEL feature_level, - bool debug); - static CacheIndexKey GetCacheKey(ShaderCompiler::Type type, const std::string_view& shader_code, - const D3D_SHADER_MACRO* macros, const char* entry_point); - - bool CreateNew(const std::string& index_filename, const std::string& blob_filename); - bool ReadExisting(const std::string& index_filename, const std::string& blob_filename); - - wil::com_ptr_nothrow CompileAndAddShaderBlob(const CacheIndexKey& key, const std::string_view& shader_code, - const D3D_SHADER_MACRO* macros, const char* entry_point); - - std::FILE* m_index_file = nullptr; - std::FILE* m_blob_file = nullptr; - - CacheIndex m_index; - - D3D_FEATURE_LEVEL m_feature_level = D3D_FEATURE_LEVEL_11_0; - u32 m_version = 0; - bool m_debug = false; - }; -} // namespace D3D11 diff --git a/common/D3D11/ShaderCompiler.cpp b/common/D3D11/ShaderCompiler.cpp deleted file mode 100644 index 39b78be5a0..0000000000 --- a/common/D3D11/ShaderCompiler.cpp +++ /dev/null @@ -1,186 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2022 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "common/PrecompiledHeader.h" -#include "common/D3D11/ShaderCompiler.h" -#include "common/Console.h" -#include "common/StringUtil.h" -#include -#include -#include - -static unsigned s_next_bad_shader_id = 1; - -wil::com_ptr_nothrow D3D11::ShaderCompiler::CompileShader(Type type, D3D_FEATURE_LEVEL feature_level, bool debug, - const std::string_view& code, const D3D_SHADER_MACRO* macros /* = nullptr */, const char* entry_point /* = "main" */) -{ - const char* target; - switch (feature_level) - { - case D3D_FEATURE_LEVEL_10_0: - { - static constexpr std::array targets = {{"vs_4_0", "ps_4_0", "cs_4_0"}}; - target = targets[static_cast(type)]; - } - break; - - case D3D_FEATURE_LEVEL_10_1: - { - static constexpr std::array targets = {{"vs_4_1", "ps_4_1", "cs_4_1"}}; - target = targets[static_cast(type)]; - } - break; - - case D3D_FEATURE_LEVEL_11_0: - { - static constexpr std::array targets = {{"vs_5_0", "ps_5_0", "cs_5_0"}}; - target = targets[static_cast(type)]; - } - break; - - case D3D_FEATURE_LEVEL_11_1: - default: - { - static constexpr std::array targets = {{"vs_5_1", "ps_5_1", "cs_5_1"}}; - target = targets[static_cast(type)]; - } - break; - } - - static constexpr UINT flags_non_debug = D3DCOMPILE_OPTIMIZATION_LEVEL3; - static constexpr UINT flags_debug = D3DCOMPILE_SKIP_OPTIMIZATION | D3DCOMPILE_DEBUG; - - wil::com_ptr_nothrow blob; - wil::com_ptr_nothrow error_blob; - const HRESULT hr = - D3DCompile(code.data(), code.size(), "0", macros, nullptr, entry_point, target, debug ? flags_debug : flags_non_debug, - 0, blob.put(), error_blob.put()); - - std::string error_string; - if (error_blob) - { - error_string.append(static_cast(error_blob->GetBufferPointer()), error_blob->GetBufferSize()); - error_blob.reset(); - } - - if (FAILED(hr)) - { - Console.WriteLn("Failed to compile '%s':\n%s", target, error_string.c_str()); - - std::ofstream ofs(StringUtil::StdStringFromFormat("pcsx2_bad_shader_%u.txt", s_next_bad_shader_id++).c_str(), - std::ofstream::out | std::ofstream::binary); - if (ofs.is_open()) - { - ofs << code; - ofs << "\n\nCompile as " << target << " failed: " << hr << "\n"; - ofs.write(error_string.c_str(), error_string.size()); - ofs.close(); - } - - return {}; - } - - if (!error_string.empty()) - Console.Warning("'%s' compiled with warnings:\n%s", target, error_string.c_str()); - - return blob; -} - -wil::com_ptr_nothrow D3D11::ShaderCompiler::CompileAndCreateVertexShader(ID3D11Device* device, bool debug, - const std::string_view& code, const D3D_SHADER_MACRO* macros /* = nullptr */, const char* entry_point /* = "main" */) -{ - wil::com_ptr_nothrow blob = CompileShader(Type::Vertex, device->GetFeatureLevel(), debug, code, macros, entry_point); - if (!blob) - return {}; - - return CreateVertexShader(device, blob.get()); -} - -wil::com_ptr_nothrow D3D11::ShaderCompiler::CompileAndCreatePixelShader(ID3D11Device* device, bool debug, - const std::string_view& code, const D3D_SHADER_MACRO* macros /* = nullptr */, const char* entry_point /* = "main" */) -{ - wil::com_ptr_nothrow blob = CompileShader(Type::Pixel, device->GetFeatureLevel(), debug, code, macros, entry_point); - if (!blob) - return {}; - - return CreatePixelShader(device, blob.get()); -} - -wil::com_ptr_nothrow D3D11::ShaderCompiler::CompileAndCreateComputeShader(ID3D11Device* device, bool debug, - const std::string_view& code, const D3D_SHADER_MACRO* macros /* = nullptr */, const char* entry_point /* = "main" */) -{ - wil::com_ptr_nothrow blob = CompileShader(Type::Compute, device->GetFeatureLevel(), debug, code, macros, entry_point); - if (!blob) - return {}; - - return CreateComputeShader(device, blob.get()); -} - -wil::com_ptr_nothrow D3D11::ShaderCompiler::CreateVertexShader(ID3D11Device* device, const void* bytecode, size_t bytecode_length) -{ - wil::com_ptr_nothrow shader; - const HRESULT hr = device->CreateVertexShader(bytecode, bytecode_length, nullptr, shader.put()); - if (FAILED(hr)) - { - Console.Error("Failed to create vertex shader: 0x%08X", hr); - return {}; - } - - return shader; -} - -wil::com_ptr_nothrow D3D11::ShaderCompiler::CreateVertexShader(ID3D11Device* device, const ID3DBlob* blob) -{ - return CreateVertexShader(device, const_cast(blob)->GetBufferPointer(), - const_cast(blob)->GetBufferSize()); -} - -wil::com_ptr_nothrow D3D11::ShaderCompiler::CreatePixelShader(ID3D11Device* device, const void* bytecode, size_t bytecode_length) -{ - wil::com_ptr_nothrow shader; - const HRESULT hr = device->CreatePixelShader(bytecode, bytecode_length, nullptr, shader.put()); - if (FAILED(hr)) - { - Console.Error("Failed to create pixel shader: 0x%08X", hr); - return {}; - } - - return shader; -} - -wil::com_ptr_nothrow D3D11::ShaderCompiler::CreatePixelShader(ID3D11Device* device, const ID3DBlob* blob) -{ - return CreatePixelShader(device, const_cast(blob)->GetBufferPointer(), - const_cast(blob)->GetBufferSize()); -} - -wil::com_ptr_nothrow D3D11::ShaderCompiler::CreateComputeShader(ID3D11Device* device, const void* bytecode, size_t bytecode_length) -{ - wil::com_ptr_nothrow shader; - const HRESULT hr = device->CreateComputeShader(bytecode, bytecode_length, nullptr, shader.put()); - if (FAILED(hr)) - { - Console.Error("Failed to create compute shader: 0x%08X", hr); - return {}; - } - - return shader; -} - -wil::com_ptr_nothrow D3D11::ShaderCompiler::CreateComputeShader(ID3D11Device* device, const ID3DBlob* blob) -{ - return CreateComputeShader(device, const_cast(blob)->GetBufferPointer(), - const_cast(blob)->GetBufferSize()); -} diff --git a/common/D3D11/ShaderCompiler.h b/common/D3D11/ShaderCompiler.h deleted file mode 100644 index fb2be0eb6a..0000000000 --- a/common/D3D11/ShaderCompiler.h +++ /dev/null @@ -1,50 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2022 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once - -#include "common/RedtapeWindows.h" -#include "common/RedtapeWilCom.h" - -#include -#include -#include - -namespace D3D11::ShaderCompiler -{ - enum class Type - { - Vertex, - Pixel, - Compute - }; - - wil::com_ptr_nothrow CompileShader(Type type, D3D_FEATURE_LEVEL feature_level, bool debug, const std::string_view& code, - const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main"); - - wil::com_ptr_nothrow CompileAndCreateVertexShader(ID3D11Device* device, bool debug, const std::string_view& code, - const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main"); - wil::com_ptr_nothrow CompileAndCreatePixelShader(ID3D11Device* device, bool debug, const std::string_view& code, - const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main"); - wil::com_ptr_nothrow CompileAndCreateComputeShader(ID3D11Device* device, bool debug, const std::string_view& code, - const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main"); - - wil::com_ptr_nothrow CreateVertexShader(ID3D11Device* device, const void* bytecode, size_t bytecode_length); - wil::com_ptr_nothrow CreateVertexShader(ID3D11Device* device, const ID3DBlob* blob); - wil::com_ptr_nothrow CreatePixelShader(ID3D11Device* device, const void* bytecode, size_t bytecode_length); - wil::com_ptr_nothrow CreatePixelShader(ID3D11Device* device, const ID3DBlob* blob); - wil::com_ptr_nothrow CreateComputeShader(ID3D11Device* device, const void* bytecode, size_t bytecode_length); - wil::com_ptr_nothrow CreateComputeShader(ID3D11Device* device, const ID3DBlob* blob); -}; // namespace D3D11::ShaderCompiler diff --git a/common/D3D12/Context.h b/common/D3D12/Context.h deleted file mode 100644 index 74c2769978..0000000000 --- a/common/D3D12/Context.h +++ /dev/null @@ -1,219 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2022 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once - -#include "common/Pcsx2Defs.h" -#include "common/RedtapeWindows.h" -#include "common/D3D12/DescriptorHeapManager.h" -#include "common/D3D12/StreamBuffer.h" - -#include -#include -#include -#include -#include -#include - -struct IDXGIAdapter; -struct IDXGIFactory; -namespace D3D12MA -{ - class Allocator; - class Allocation; -} // namespace D3D12MA - -namespace D3D12 -{ - class Context - { - public: - template - using ComPtr = wil::com_ptr_nothrow; - - enum : u32 - { - /// Number of command lists. One is being built while the other(s) are executed. - NUM_COMMAND_LISTS = 3, - - /// Textures that don't fit into this buffer will be uploaded with a staging buffer. - TEXTURE_UPLOAD_BUFFER_SIZE = 64 * 1024 * 1024, - - /// Maximum number of samples in a single allocation group. - SAMPLER_GROUP_SIZE = 2, - - /// Start/End timestamp queries. - NUM_TIMESTAMP_QUERIES_PER_CMDLIST = 2, - }; - - ~Context(); - - /// Creates new device and context. - static bool Create(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool enable_debug_layer); - - /// Destroys active context. - static void Destroy(); - - __fi IDXGIAdapter* GetAdapter() const { return m_adapter.get(); } - __fi ID3D12Device* GetDevice() const { return m_device.get(); } - __fi ID3D12CommandQueue* GetCommandQueue() const { return m_command_queue.get(); } - __fi D3D12MA::Allocator* GetAllocator() const { return m_allocator.get(); } - - /// Returns the PCI vendor ID of the device, if known. - u32 GetAdapterVendorID() const; - - /// Returns the current command list, commands can be recorded directly. - ID3D12GraphicsCommandList4* GetCommandList() const - { - return m_command_lists[m_current_command_list].command_lists[1].get(); - } - - /// Returns the init command list for uploading. - ID3D12GraphicsCommandList4* GetInitCommandList(); - - /// Returns the per-frame SRV/CBV/UAV allocator. - DescriptorAllocator& GetDescriptorAllocator() - { - return m_command_lists[m_current_command_list].descriptor_allocator; - } - - /// Returns the per-frame sampler allocator. - GroupedSamplerAllocator& GetSamplerAllocator() - { - return m_command_lists[m_current_command_list].sampler_allocator; - } - - /// Invalidates GPU-side sampler caches for all command lists. Call after you've freed samplers, - /// and are going to re-use the handles from GetSamplerHeapManager(). - void InvalidateSamplerGroups(); - - // Descriptor manager access. - DescriptorHeapManager& GetDescriptorHeapManager() { return m_descriptor_heap_manager; } - DescriptorHeapManager& GetRTVHeapManager() { return m_rtv_heap_manager; } - DescriptorHeapManager& GetDSVHeapManager() { return m_dsv_heap_manager; } - DescriptorHeapManager& GetSamplerHeapManager() { return m_sampler_heap_manager; } - const DescriptorHandle& GetNullSRVDescriptor() const { return m_null_srv_descriptor; } - StreamBuffer& GetTextureStreamBuffer() { return m_texture_stream_buffer; } - - // Root signature access. - ComPtr SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc); - ComPtr CreateRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc); - - /// Fence value for current command list. - u64 GetCurrentFenceValue() const { return m_current_fence_value; } - - /// Last "completed" fence. - u64 GetCompletedFenceValue() const { return m_completed_fence_value; } - - /// Feature level to use when compiling shaders. - D3D_FEATURE_LEVEL GetFeatureLevel() const { return m_feature_level; } - - /// Test for support for the specified texture format. - bool SupportsTextureFormat(DXGI_FORMAT format); - - enum class WaitType - { - None, ///< Don't wait (async) - Sleep, ///< Wait normally - Spin, ///< Wait by spinning - }; - - /// Executes the current command list. - bool ExecuteCommandList(WaitType wait_for_completion); - - /// Waits for a specific fence. - void WaitForFence(u64 fence, bool spin); - - /// Waits for any in-flight command buffers to complete. - void WaitForGPUIdle(); - - /// Defers destruction of a D3D resource (associates it with the current list). - void DeferObjectDestruction(ID3D12DeviceChild* resource); - - /// Defers destruction of a D3D resource (associates it with the current list). - void DeferResourceDestruction(D3D12MA::Allocation* allocation, ID3D12Resource* resource); - - /// Defers destruction of a descriptor handle (associates it with the current list). - void DeferDescriptorDestruction(DescriptorHeapManager& manager, u32 index); - void DeferDescriptorDestruction(DescriptorHeapManager& manager, DescriptorHandle* handle); - - float GetAndResetAccumulatedGPUTime(); - void SetEnableGPUTiming(bool enabled); - - // Allocates a temporary CPU staging buffer, fires the callback with it to populate, then copies to a GPU buffer. - bool AllocatePreinitializedGPUBuffer(u32 size, ID3D12Resource** gpu_buffer, D3D12MA::Allocation** gpu_allocation, - const std::function& fill_callback); - - private: - struct CommandListResources - { - std::array, 2> command_allocators; - std::array, 2> command_lists; - DescriptorAllocator descriptor_allocator; - GroupedSamplerAllocator sampler_allocator; - std::vector> pending_resources; - std::vector> pending_descriptors; - u64 ready_fence_value = 0; - bool init_command_list_used = false; - bool has_timestamp_query = false; - }; - - Context(); - - bool CreateDevice(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool enable_debug_layer); - bool CreateCommandQueue(); - bool CreateAllocator(); - bool CreateFence(); - bool CreateDescriptorHeaps(); - bool CreateCommandLists(); - bool CreateTextureStreamBuffer(); - bool CreateTimestampQuery(); - void MoveToNextCommandList(); - void DestroyPendingResources(CommandListResources& cmdlist); - void DestroyResources(); - - ComPtr m_adapter; - ComPtr m_debug_interface; - ComPtr m_device; - ComPtr m_command_queue; - ComPtr m_allocator; - - ComPtr m_fence; - HANDLE m_fence_event = {}; - u32 m_current_fence_value = 0; - u64 m_completed_fence_value = 0; - - std::array m_command_lists; - u32 m_current_command_list = NUM_COMMAND_LISTS - 1; - - ComPtr m_timestamp_query_heap; - ComPtr m_timestamp_query_buffer; - ComPtr m_timestamp_query_allocation; - double m_timestamp_frequency = 0.0; - float m_accumulated_gpu_time = 0.0f; - bool m_gpu_timing_enabled = false; - - DescriptorHeapManager m_descriptor_heap_manager; - DescriptorHeapManager m_rtv_heap_manager; - DescriptorHeapManager m_dsv_heap_manager; - DescriptorHeapManager m_sampler_heap_manager; - DescriptorHandle m_null_srv_descriptor; - StreamBuffer m_texture_stream_buffer; - - D3D_FEATURE_LEVEL m_feature_level = D3D_FEATURE_LEVEL_11_0; - }; -} // namespace D3D12 - -extern std::unique_ptr g_d3d12_context; diff --git a/common/D3D12/DescriptorHeapManager.h b/common/D3D12/DescriptorHeapManager.h deleted file mode 100644 index 875ee6cb5f..0000000000 --- a/common/D3D12/DescriptorHeapManager.h +++ /dev/null @@ -1,269 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2022 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once - -#include "common/Pcsx2Defs.h" -#include "common/HashCombine.h" -#include "common/RedtapeWindows.h" -#include "common/RedtapeWilCom.h" - -#include -#include -#include -#include -#include - -namespace D3D12 -{ - // This class provides an abstraction for D3D12 descriptor heaps. - struct DescriptorHandle final - { - enum : u32 - { - INVALID_INDEX = 0xFFFFFFFF - }; - - D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle{}; - D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle{}; - u32 index = INVALID_INDEX; - - __fi operator bool() const { return index != INVALID_INDEX; } - - __fi operator D3D12_CPU_DESCRIPTOR_HANDLE() const { return cpu_handle; } - __fi operator D3D12_GPU_DESCRIPTOR_HANDLE() const { return gpu_handle; } - - __fi bool operator==(const DescriptorHandle& rhs) const { return (index == rhs.index); } - __fi bool operator!=(const DescriptorHandle& rhs) const { return (index != rhs.index); } - __fi bool operator<(const DescriptorHandle& rhs) const { return (index < rhs.index); } - __fi bool operator<=(const DescriptorHandle& rhs) const { return (index <= rhs.index); } - __fi bool operator>(const DescriptorHandle& rhs) const { return (index > rhs.index); } - __fi bool operator>=(const DescriptorHandle& rhs) const { return (index >= rhs.index); } - - __fi void Clear() - { - cpu_handle = {}; - gpu_handle = {}; - index = INVALID_INDEX; - } - }; - - class DescriptorHeapManager final - { - public: - DescriptorHeapManager(); - ~DescriptorHeapManager(); - - ID3D12DescriptorHeap* GetDescriptorHeap() const { return m_descriptor_heap.get(); } - u32 GetDescriptorIncrementSize() const { return m_descriptor_increment_size; } - - bool Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, u32 num_descriptors, bool shader_visible); - void Destroy(); - - bool Allocate(DescriptorHandle* handle); - void Free(DescriptorHandle* handle); - void Free(u32 index); - - private: - wil::com_ptr_nothrow m_descriptor_heap; - u32 m_num_descriptors = 0; - u32 m_descriptor_increment_size = 0; - bool m_shader_visible = false; - - D3D12_CPU_DESCRIPTOR_HANDLE m_heap_base_cpu = {}; - D3D12_GPU_DESCRIPTOR_HANDLE m_heap_base_gpu = {}; - - static constexpr u32 BITSET_SIZE = 1024; - using BitSetType = std::bitset; - std::vector m_free_slots = {}; - }; - - class DescriptorAllocator - { - public: - DescriptorAllocator(); - ~DescriptorAllocator(); - - __fi ID3D12DescriptorHeap* GetDescriptorHeap() const { return m_descriptor_heap.get(); } - __fi u32 GetDescriptorIncrementSize() const { return m_descriptor_increment_size; } - - bool Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, u32 num_descriptors); - void Destroy(); - - bool Allocate(u32 num_handles, DescriptorHandle* out_base_handle); - void Reset(); - - private: - wil::com_ptr_nothrow m_descriptor_heap; - u32 m_descriptor_increment_size = 0; - u32 m_num_descriptors = 0; - u32 m_current_offset = 0; - - D3D12_CPU_DESCRIPTOR_HANDLE m_heap_base_cpu = {}; - D3D12_GPU_DESCRIPTOR_HANDLE m_heap_base_gpu = {}; - }; - - template - class GroupedSamplerAllocator : private DescriptorAllocator - { - struct Key - { - u32 idx[NumSamplers]; - - __fi bool operator==(const Key& rhs) const - { - return (std::memcmp(idx, rhs.idx, sizeof(idx)) == 0); - } - __fi bool operator!=(const Key& rhs) const - { - return (std::memcmp(idx, rhs.idx, sizeof(idx)) != 0); - } - }; - - struct KeyHash - { - __fi std::size_t operator()(const Key& key) const - { - size_t seed = 0; - for (u32 key : key.idx) - HashCombine(seed, key); - return seed; - } - }; - - - public: - GroupedSamplerAllocator(); - ~GroupedSamplerAllocator(); - - using DescriptorAllocator::GetDescriptorHeap; - using DescriptorAllocator::GetDescriptorIncrementSize; - - bool Create(ID3D12Device* device, u32 num_descriptors); - void Destroy(); - - bool LookupSingle(DescriptorHandle* gpu_handle, const DescriptorHandle& cpu_handle); - bool LookupGroup(DescriptorHandle* gpu_handle, const DescriptorHandle* cpu_handles); - - // Clears cache but doesn't reset allocator. - void InvalidateCache(); - - void Reset(); - bool ShouldReset() const; - - private: - wil::com_ptr_nothrow m_device; - std::unordered_map m_groups; - }; - - template - GroupedSamplerAllocator::GroupedSamplerAllocator() = default; - - template - GroupedSamplerAllocator::~GroupedSamplerAllocator() = default; - - template - bool GroupedSamplerAllocator::Create(ID3D12Device* device, u32 num_descriptors) - { - if (!DescriptorAllocator::Create(device, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, num_descriptors)) - return false; - - m_device = device; - return true; - } - - template - void GroupedSamplerAllocator::Destroy() - { - DescriptorAllocator::Destroy(); - m_device.reset(); - } - - template - void GroupedSamplerAllocator::Reset() - { - m_groups.clear(); - DescriptorAllocator::Reset(); - } - - template - void GroupedSamplerAllocator::InvalidateCache() - { - m_groups.clear(); - } - - template - bool GroupedSamplerAllocator::LookupSingle(DescriptorHandle* gpu_handle, const DescriptorHandle& cpu_handle) - { - Key key; - key.idx[0] = cpu_handle.index; - for (u32 i = 1; i < NumSamplers; i++) - key.idx[i] = 0; - - auto it = m_groups.find(key); - if (it != m_groups.end()) - { - *gpu_handle = it->second; - return true; - } - - if (!Allocate(1, gpu_handle)) - return false; - - m_device->CopyDescriptorsSimple(1, *gpu_handle, cpu_handle, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); - m_groups.emplace(key, *gpu_handle); - return true; - } - - template - bool GroupedSamplerAllocator::LookupGroup(DescriptorHandle* gpu_handle, const DescriptorHandle* cpu_handles) - { - Key key; - for (u32 i = 0; i < NumSamplers; i++) - key.idx[i] = cpu_handles[i].index; - - auto it = m_groups.find(key); - if (it != m_groups.end()) - { - *gpu_handle = it->second; - return true; - } - - if (!Allocate(NumSamplers, gpu_handle)) - return false; - - D3D12_CPU_DESCRIPTOR_HANDLE dst_handle = *gpu_handle; - UINT dst_size = NumSamplers; - D3D12_CPU_DESCRIPTOR_HANDLE src_handles[NumSamplers]; - UINT src_sizes[NumSamplers]; - for (u32 i = 0; i < NumSamplers; i++) - { - src_handles[i] = cpu_handles[i]; - src_sizes[i] = 1; - } - m_device->CopyDescriptors(1, &dst_handle, &dst_size, NumSamplers, src_handles, src_sizes, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); - - m_groups.emplace(key, *gpu_handle); - return true; - } - - template - bool GroupedSamplerAllocator::ShouldReset() const - { - // We only reset the sampler heap if more than half of the descriptors are used. - // This saves descriptor copying when there isn't a large number of sampler configs per frame. - return m_groups.size() >= (D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE / 2); - } -} // namespace D3D12 diff --git a/common/D3D12/ShaderCache.h b/common/D3D12/ShaderCache.h deleted file mode 100644 index dfca321829..0000000000 --- a/common/D3D12/ShaderCache.h +++ /dev/null @@ -1,150 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2022 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once - -#include "common/Pcsx2Defs.h" -#include "common/HashCombine.h" -#include "common/RedtapeWindows.h" -#include "common/RedtapeWilCom.h" - -#include -#include -#include -#include -#include - -namespace D3D12 -{ - class ShaderCache - { - public: - template - using ComPtr = wil::com_ptr_nothrow; - - enum class EntryType - { - VertexShader, - PixelShader, - ComputeShader, - GraphicsPipeline, - ComputePipeline, - }; - - ShaderCache(); - ~ShaderCache(); - - __fi D3D_FEATURE_LEVEL GetFeatureLevel() const { return m_feature_level; } - __fi u32 GetDataVersion() const { return m_data_version; } - __fi bool UsingDebugShaders() const { return m_debug; } - - bool Open(std::string_view base_path, D3D_FEATURE_LEVEL feature_level, u32 version, bool debug); - void Close(); - - __fi ComPtr GetVertexShader(std::string_view shader_code, - const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main") - { - return GetShaderBlob(EntryType::VertexShader, shader_code, macros, entry_point); - } - __fi ComPtr GetPixelShader(std::string_view shader_code, - const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main") - { - return GetShaderBlob(EntryType::PixelShader, shader_code, macros, entry_point); - } - __fi ComPtr GetComputeShader(std::string_view shader_code, - const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main") - { - return GetShaderBlob(EntryType::ComputeShader, shader_code, macros, entry_point); - } - - ComPtr GetShaderBlob(EntryType type, std::string_view shader_code, - const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main"); - - ComPtr GetPipelineState(ID3D12Device* device, const D3D12_GRAPHICS_PIPELINE_STATE_DESC& desc); - ComPtr GetPipelineState(ID3D12Device* device, const D3D12_COMPUTE_PIPELINE_STATE_DESC& desc); - - private: - static constexpr u32 FILE_VERSION = 1; - - struct CacheIndexKey - { - u64 source_hash_low; - u64 source_hash_high; - u64 macro_hash_low; - u64 macro_hash_high; - u64 entry_point_low; - u64 entry_point_high; - u32 source_length; - EntryType type; - - bool operator==(const CacheIndexKey& key) const; - bool operator!=(const CacheIndexKey& key) const; - }; - - struct CacheIndexEntryHasher - { - std::size_t operator()(const CacheIndexKey& e) const noexcept - { - std::size_t h = 0; - HashCombine(h, e.entry_point_low, e.entry_point_high, e.macro_hash_low, e.macro_hash_high, - e.source_hash_low, e.source_hash_high, e.source_length, e.type); - return h; - } - }; - - struct CacheIndexData - { - u32 file_offset; - u32 blob_size; - }; - - using CacheIndex = std::unordered_map; - - static std::string GetCacheBaseFileName(const std::string_view& base_path, const std::string_view& type, - D3D_FEATURE_LEVEL feature_level, bool debug); - static CacheIndexKey GetShaderCacheKey(EntryType type, const std::string_view& shader_code, - const D3D_SHADER_MACRO* macros, const char* entry_point); - static CacheIndexKey GetPipelineCacheKey(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& gpdesc); - static CacheIndexKey GetPipelineCacheKey(const D3D12_COMPUTE_PIPELINE_STATE_DESC& gpdesc); - - bool CreateNew(const std::string& index_filename, const std::string& blob_filename, std::FILE*& index_file, - std::FILE*& blob_file); - bool ReadExisting(const std::string& index_filename, const std::string& blob_filename, std::FILE*& index_file, - std::FILE*& blob_file, CacheIndex& index); - void InvalidatePipelineCache(); - - ComPtr CompileAndAddShaderBlob(const CacheIndexKey& key, std::string_view shader_code, - const D3D_SHADER_MACRO* macros, const char* entry_point); - ComPtr CompileAndAddPipeline(ID3D12Device* device, const CacheIndexKey& key, - const D3D12_GRAPHICS_PIPELINE_STATE_DESC& gpdesc); - ComPtr CompileAndAddPipeline(ID3D12Device* device, const CacheIndexKey& key, - const D3D12_COMPUTE_PIPELINE_STATE_DESC& gpdesc); - bool AddPipelineToBlob(const CacheIndexKey& key, ID3D12PipelineState* pso); - - std::string m_base_path; - - std::FILE* m_shader_index_file = nullptr; - std::FILE* m_shader_blob_file = nullptr; - CacheIndex m_shader_index; - - std::FILE* m_pipeline_index_file = nullptr; - std::FILE* m_pipeline_blob_file = nullptr; - CacheIndex m_pipeline_index; - - D3D_FEATURE_LEVEL m_feature_level = D3D_FEATURE_LEVEL_11_0; - u32 m_data_version = 0; - bool m_debug = false; - }; -} // namespace D3D12 diff --git a/common/D3D12/StreamBuffer.h b/common/D3D12/StreamBuffer.h deleted file mode 100644 index 4eb467bc43..0000000000 --- a/common/D3D12/StreamBuffer.h +++ /dev/null @@ -1,77 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2022 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once - -#include "common/Pcsx2Defs.h" -#include "common/RedtapeWindows.h" -#include "common/RedtapeWilCom.h" - -#include -#include -#include - -namespace D3D12MA -{ - class Allocation; -} - -namespace D3D12 -{ - class StreamBuffer - { - public: - StreamBuffer(); - ~StreamBuffer(); - - bool Create(u32 size); - - __fi bool IsValid() const { return static_cast(m_buffer); } - __fi ID3D12Resource* GetBuffer() const { return m_buffer.get(); } - __fi D3D12_GPU_VIRTUAL_ADDRESS GetGPUPointer() const { return m_gpu_pointer; } - __fi void* GetHostPointer() const { return m_host_pointer; } - __fi void* GetCurrentHostPointer() const { return m_host_pointer + m_current_offset; } - __fi D3D12_GPU_VIRTUAL_ADDRESS GetCurrentGPUPointer() const { return m_gpu_pointer + m_current_offset; } - __fi u32 GetSize() const { return m_size; } - __fi u32 GetCurrentOffset() const { return m_current_offset; } - __fi u32 GetCurrentSpace() const { return m_current_space; } - - bool ReserveMemory(u32 num_bytes, u32 alignment); - void CommitMemory(u32 final_num_bytes); - - void Destroy(bool defer = true); - - private: - void UpdateCurrentFencePosition(); - void UpdateGPUPosition(); - - // Waits for as many fences as needed to allocate num_bytes bytes from the buffer. - bool WaitForClearSpace(u32 num_bytes); - - u32 m_size = 0; - u32 m_current_offset = 0; - u32 m_current_space = 0; - u32 m_current_gpu_position = 0; - - wil::com_ptr_nothrow m_buffer; - wil::com_ptr_nothrow m_allocation; - D3D12_GPU_VIRTUAL_ADDRESS m_gpu_pointer = {}; - u8* m_host_pointer = nullptr; - - // List of fences and the corresponding positions in the buffer - std::deque> m_tracked_fences; - }; - -} // namespace D3D12 diff --git a/common/D3D12/Texture.h b/common/D3D12/Texture.h deleted file mode 100644 index 8f936cd195..0000000000 --- a/common/D3D12/Texture.h +++ /dev/null @@ -1,109 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2022 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once - -#include "common/Pcsx2Defs.h" -#include "common/RedtapeWindows.h" -#include "common/D3D12/DescriptorHeapManager.h" - -#include -#include - -namespace D3D12MA -{ -class Allocation; -} - -namespace D3D12 -{ - class StreamBuffer; - - class Texture final - { - public: - template - using ComPtr = wil::com_ptr_nothrow; - - Texture(); - Texture(ID3D12Resource* resource, D3D12_RESOURCE_STATES state); - Texture(Texture&& texture); - Texture(const Texture&) = delete; - ~Texture(); - - __fi ID3D12Resource* GetResource() const { return m_resource.get(); } - __fi D3D12MA::Allocation* GetAllocation() const { return m_allocation.get(); } - __fi const DescriptorHandle& GetSRVDescriptor() const { return m_srv_descriptor; } - __fi const DescriptorHandle& GetWriteDescriptor() const { return m_write_descriptor; } - __fi D3D12_RESOURCE_STATES GetState() const { return m_state; } - - __fi u32 GetWidth() const { return m_width; } - __fi u32 GetHeight() const { return m_height; } - __fi u32 GetLevels() const { return m_levels; } - __fi DXGI_FORMAT GetFormat() const { return m_format; } - - __fi operator ID3D12Resource*() const { return m_resource.get(); } - __fi operator bool() const { return static_cast(m_resource); } - - bool Create(u32 width, u32 height, u32 levels, DXGI_FORMAT format, DXGI_FORMAT srv_format, - DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format, D3D12_RESOURCE_FLAGS flags, u32 alloc_flags = 0); - bool Adopt(ComPtr texture, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format, - D3D12_RESOURCE_STATES state); - - D3D12_RESOURCE_DESC GetDesc() const; - - void Destroy(bool defer = true); - - void TransitionToState(ID3D12GraphicsCommandList* cmdlist, D3D12_RESOURCE_STATES state); - void TransitionSubresourceToState(ID3D12GraphicsCommandList* cmdlist, u32 level, - D3D12_RESOURCE_STATES before_state, D3D12_RESOURCE_STATES after_state) const; - - Texture& operator=(const Texture&) = delete; - Texture& operator=(Texture&& texture); - - // NOTE: Does not handle compressed formats. - ID3D12GraphicsCommandList* BeginStreamUpdate(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height, void** out_data, u32* out_data_pitch); - void EndStreamUpdate(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height); - bool LoadData(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch); - void CopyFromBuffer(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height, u32 pitch, ID3D12Resource* buffer, u32 buffer_offset); - - private: - static bool CreateSRVDescriptor(ID3D12Resource* resource, u32 levels, DXGI_FORMAT format, DescriptorHandle* dh); - static bool CreateRTVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, DescriptorHandle* dh); - static bool CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, DescriptorHandle* dh); - static bool CreateUAVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, DescriptorHandle* dh); - - enum class WriteDescriptorType : u8 - { - None, - RTV, - DSV, - UAV - }; - - ComPtr m_resource; - ComPtr m_allocation; - DescriptorHandle m_srv_descriptor = {}; - DescriptorHandle m_write_descriptor = {}; - u32 m_width = 0; - u32 m_height = 0; - u32 m_levels = 0; - DXGI_FORMAT m_format = DXGI_FORMAT_UNKNOWN; - - D3D12_RESOURCE_STATES m_state = D3D12_RESOURCE_STATE_COMMON; - - WriteDescriptorType m_write_descriptor_type = WriteDescriptorType::None; - }; -} // namespace D3D12 \ No newline at end of file diff --git a/common/D3D12/Util.cpp b/common/D3D12/Util.cpp deleted file mode 100644 index 3c9c1c6ac4..0000000000 --- a/common/D3D12/Util.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2022 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#include "common/PrecompiledHeader.h" - -#include "common/D3D12/Util.h" -#include "common/Assertions.h" -#include "common/StringUtil.h" - -u32 D3D12::GetTexelSize(DXGI_FORMAT format) -{ - switch (format) - { - case DXGI_FORMAT_R32G32B32A32_FLOAT: - case DXGI_FORMAT_BC1_UNORM: - case DXGI_FORMAT_BC2_UNORM: - case DXGI_FORMAT_BC3_UNORM: - case DXGI_FORMAT_BC7_UNORM: - return 16; - - case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: - return 4; - - case DXGI_FORMAT_R8G8B8A8_UNORM: - case DXGI_FORMAT_R8G8B8A8_SNORM: - case DXGI_FORMAT_R8G8B8A8_TYPELESS: - case DXGI_FORMAT_B8G8R8A8_UNORM: - case DXGI_FORMAT_B8G8R8A8_TYPELESS: - case DXGI_FORMAT_R32_UINT: - case DXGI_FORMAT_R32_SINT: - return 4; - - case DXGI_FORMAT_B5G5R5A1_UNORM: - case DXGI_FORMAT_B5G6R5_UNORM: - case DXGI_FORMAT_R16_UINT: - case DXGI_FORMAT_R16_SINT: - return 2; - - case DXGI_FORMAT_A8_UNORM: - case DXGI_FORMAT_R8_UNORM: - return 1; - - default: - pxFailRel("Unknown format"); - return 1; - } -} - -void D3D12::SetDefaultSampler(D3D12_SAMPLER_DESC* desc) -{ - desc->Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; - desc->AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; - desc->AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; - desc->AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; - desc->MipLODBias = 0; - desc->MaxAnisotropy = 1; - desc->ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; - desc->BorderColor[0] = 1.0f; - desc->BorderColor[1] = 1.0f; - desc->BorderColor[2] = 1.0f; - desc->BorderColor[3] = 1.0f; - desc->MinLOD = -3.402823466e+38F; // -FLT_MAX - desc->MaxLOD = 3.402823466e+38F; // FLT_MAX -} - -#ifdef _DEBUG - -void D3D12::SetObjectName(ID3D12Object* object, const char* name) -{ - object->SetName(StringUtil::UTF8StringToWideString(name).c_str()); -} - -void D3D12::SetObjectNameFormatted(ID3D12Object* object, const char* format, ...) -{ - std::va_list ap; - va_start(ap, format); - SetObjectName(object, StringUtil::StdStringFromFormatV(format, ap).c_str()); - va_end(ap); -} - -#endif diff --git a/common/D3D12/Util.h b/common/D3D12/Util.h deleted file mode 100644 index 848805a083..0000000000 --- a/common/D3D12/Util.h +++ /dev/null @@ -1,77 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2022 PCSX2 Dev Team - * - * PCSX2 is free software: you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with PCSX2. - * If not, see . - */ - -#pragma once - -#include "common/Pcsx2Defs.h" -#include "common/RedtapeWindows.h" - -#include -#include - -namespace D3D12 -{ - static inline void ResourceBarrier(ID3D12GraphicsCommandList* cmdlist, ID3D12Resource* resource, - D3D12_RESOURCE_STATES from_state, D3D12_RESOURCE_STATES to_state) - { - const D3D12_RESOURCE_BARRIER barrier = {D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, - D3D12_RESOURCE_BARRIER_FLAG_NONE, - {{resource, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, from_state, to_state}}}; - cmdlist->ResourceBarrier(1, &barrier); - } - - static inline void SetViewport(ID3D12GraphicsCommandList* cmdlist, int x, int y, int width, int height, - float min_depth = 0.0f, float max_depth = 1.0f) - { - const D3D12_VIEWPORT vp{static_cast(x), - static_cast(y), - static_cast(width), - static_cast(height), - min_depth, - max_depth}; - cmdlist->RSSetViewports(1, &vp); - } - - static inline void SetScissor(ID3D12GraphicsCommandList* cmdlist, int x, int y, int width, int height) - { - const D3D12_RECT r{x, y, x + width, y + height}; - cmdlist->RSSetScissorRects(1, &r); - } - - static inline void SetViewportAndScissor(ID3D12GraphicsCommandList* cmdlist, int x, int y, int width, int height, - float min_depth = 0.0f, float max_depth = 1.0f) - { - SetViewport(cmdlist, x, y, width, height, min_depth, max_depth); - SetScissor(cmdlist, x, y, width, height); - } - - u32 GetTexelSize(DXGI_FORMAT format); - - void SetDefaultSampler(D3D12_SAMPLER_DESC* desc); - -#ifdef _DEBUG - - void SetObjectName(ID3D12Object* object, const char* name); - void SetObjectNameFormatted(ID3D12Object* object, const char* format, ...); - -#else - - static inline void SetObjectName(ID3D12Object* object, const char* name) - { - } - static inline void SetObjectNameFormatted(ID3D12Object* object, const char* format, ...) {} - -#endif -} // namespace D3D12 \ No newline at end of file diff --git a/common/common.vcxproj b/common/common.vcxproj index 9c981505a4..de13b778c1 100644 --- a/common/common.vcxproj +++ b/common/common.vcxproj @@ -34,7 +34,7 @@ - $(SolutionDir)3rdparty\d3d12memalloc\include;$(SolutionDir)3rdparty\glad\include;$(SolutionDir)3rdparty\glslang\glslang;%(AdditionalIncludeDirectories) + $(SolutionDir)3rdparty\glad\include;$(SolutionDir)3rdparty\glslang\glslang;%(AdditionalIncludeDirectories) %(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\rapidyaml\rapidyaml\ext\c4core\src\c4\ext\fast_float\include %(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\libpng %(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\jpgd @@ -56,15 +56,6 @@ - - - - - - - - - @@ -138,15 +129,6 @@ - - - - - - - - - @@ -230,9 +212,6 @@ - - {d45cec7a-3171-40dd-975d-e1544cf16139} - {c0293b32-5acf-40f0-aa6c-e6da6f3bf33a} @@ -247,4 +226,4 @@ - \ No newline at end of file + diff --git a/common/common.vcxproj.filters b/common/common.vcxproj.filters index 00a6998d07..120c0d0f22 100644 --- a/common/common.vcxproj.filters +++ b/common/common.vcxproj.filters @@ -154,33 +154,6 @@ Source Files\Vulkan - - Source Files\D3D11 - - - Source Files\D3D11 - - - Source Files\D3D12 - - - Source Files\D3D12 - - - Source Files\D3D12 - - - Source Files\D3D12 - - - Source Files\D3D12 - - - Source Files\D3D12 - - - Source Files\D3D12 - Source Files @@ -421,36 +394,9 @@ Header Files\GL - - Header Files\D3D11 - - - Header Files\D3D11 - Header Files - - Header Files\D3D12 - - - Header Files\D3D12 - - - Header Files\D3D12 - - - Header Files\D3D12 - - - Header Files\D3D12 - - - Header Files\D3D12 - - - Header Files\D3D12 - Header Files @@ -513,18 +459,6 @@ {46f36c68-0e0e-4acd-a621-3365e3167c4f} - - {f428aac0-c9c5-4b66-b218-9829dce45d13} - - - {764ddf71-77a6-41b8-bc65-1eef94b6997b} - - - {96f78eb9-089b-4166-a23e-78c4e7d90b64} - - - {cf37623d-bb05-4c54-8c72-1c20b5331c69} - diff --git a/pcsx2-gsrunner/pcsx2-gsrunner.vcxproj b/pcsx2-gsrunner/pcsx2-gsrunner.vcxproj index 7834626e90..88e6e101ec 100644 --- a/pcsx2-gsrunner/pcsx2-gsrunner.vcxproj +++ b/pcsx2-gsrunner/pcsx2-gsrunner.vcxproj @@ -71,7 +71,7 @@ Console Yes comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;rpcrt4.lib;iphlpapi.lib;dsound.lib;%(AdditionalDependencies) - dxguid.lib;dinput8.lib;hid.lib;PowrProf.lib;d3dcompiler.lib;d3d11.lib;dxgi.lib;strmiids.lib;opengl32.lib;comsuppw.lib;OneCore.lib;%(AdditionalDependencies) + dxguid.lib;dinput8.lib;hid.lib;PowrProf.lib;d3dcompiler.lib;d3d11.lib;d3d12.lib;dxgi.lib;strmiids.lib;opengl32.lib;comsuppw.lib;OneCore.lib;%(AdditionalDependencies) diff --git a/pcsx2-qt/pcsx2-qt.vcxproj b/pcsx2-qt/pcsx2-qt.vcxproj index 42ac55cb57..50a83f7723 100644 --- a/pcsx2-qt/pcsx2-qt.vcxproj +++ b/pcsx2-qt/pcsx2-qt.vcxproj @@ -79,7 +79,7 @@ Windows Yes comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;rpcrt4.lib;iphlpapi.lib;dsound.lib;%(AdditionalDependencies) - dxguid.lib;dinput8.lib;hid.lib;PowrProf.lib;d3dcompiler.lib;d3d11.lib;dxgi.lib;strmiids.lib;opengl32.lib;comsuppw.lib;OneCore.lib;%(AdditionalDependencies) + dxguid.lib;dinput8.lib;hid.lib;PowrProf.lib;d3dcompiler.lib;d3d11.lib;d3d12.lib;dxgi.lib;strmiids.lib;opengl32.lib;comsuppw.lib;OneCore.lib;%(AdditionalDependencies) $(QtEntryPointLib);%(AdditionalDependencies) @@ -443,4 +443,4 @@ - \ No newline at end of file + diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt index 25915587e5..fb8eaf925d 100644 --- a/pcsx2/CMakeLists.txt +++ b/pcsx2/CMakeLists.txt @@ -644,16 +644,30 @@ if(WIN32) list(APPEND pcsx2GSSources GS/Renderers/DX11/D3D.cpp + GS/Renderers/DX11/D3D11ShaderCache.cpp GS/Renderers/DX11/GSDevice11.cpp GS/Renderers/DX11/GSTexture11.cpp GS/Renderers/DX11/GSTextureFX11.cpp + GS/Renderers/DX12/D3D12Builders.cpp + GS/Renderers/DX12/D3D12Context.cpp + GS/Renderers/DX12/D3D12DescriptorHeapManager.cpp + GS/Renderers/DX12/D3D12ShaderCache.cpp + GS/Renderers/DX12/D3D12StreamBuffer.cpp + GS/Renderers/DX12/D3D12Texture.cpp GS/Renderers/DX12/GSDevice12.cpp GS/Renderers/DX12/GSTexture12.cpp ) list(APPEND pcsx2GSHeaders GS/Renderers/DX11/D3D.h + GS/Renderers/DX11/D3D11ShaderCache.h GS/Renderers/DX11/GSDevice11.h GS/Renderers/DX11/GSTexture11.h + GS/Renderers/DX12/D3D12Builders.h + GS/Renderers/DX12/D3D12Context.h + GS/Renderers/DX12/D3D12DescriptorHeapManager.h + GS/Renderers/DX12/D3D12ShaderCache.h + GS/Renderers/DX12/D3D12StreamBuffer.h + GS/Renderers/DX12/D3D12Texture.h GS/Renderers/DX12/GSDevice12.h GS/Renderers/DX12/GSTexture12.h ) @@ -1149,6 +1163,7 @@ if(WIN32) PowrProf.lib d3dcompiler.lib d3d11.lib + d3d12.lib dxgi.lib strmiids.lib opengl32.lib diff --git a/pcsx2/GS/Renderers/DX11/D3D.cpp b/pcsx2/GS/Renderers/DX11/D3D.cpp index fdeef46ce9..6e9272d020 100644 --- a/pcsx2/GS/Renderers/DX11/D3D.cpp +++ b/pcsx2/GS/Renderers/DX11/D3D.cpp @@ -14,17 +14,25 @@ */ #include "PrecompiledHeader.h" + +#include "Config.h" #include "GS/Renderers/Common/GSDevice.h" #include "GS/Renderers/DX11/D3D.h" #include "GS/GSExtra.h" #include "common/Console.h" #include "common/StringUtil.h" +#include "common/Path.h" +#include #include +#include +#include #include "fmt/format.h" +static u32 s_next_bad_shader_id = 1; + wil::com_ptr_nothrow D3D::CreateFactory(bool debug) { UINT flags = 0; @@ -49,7 +57,7 @@ static std::string FixupDuplicateAdapterNames(const std::vector& ad u32 current_extra = 2; do { - adapter_name = StringUtil::StdStringFromFormat("%s (%u)", original_adapter_name.c_str(), current_extra); + adapter_name = fmt::format("{} ({})", original_adapter_name.c_str(), current_extra); current_extra++; } while (std::any_of(adapter_names.begin(), adapter_names.end(), [&adapter_name](const std::string& other) { return (adapter_name == other); })); @@ -405,3 +413,78 @@ GSRendererType D3D::GetPreferredRenderer() } } } + +wil::com_ptr_nothrow D3D::CompileShader(D3D::ShaderType type, D3D_FEATURE_LEVEL feature_level, bool debug, + const std::string_view& code, const D3D_SHADER_MACRO* macros /* = nullptr */, + const char* entry_point /* = "main" */) +{ + const char* target; + switch (feature_level) + { + case D3D_FEATURE_LEVEL_10_0: + { + static constexpr std::array targets = {{"vs_4_0", "ps_4_0", "cs_4_0"}}; + target = targets[static_cast(type)]; + } + break; + + case D3D_FEATURE_LEVEL_10_1: + { + static constexpr std::array targets = {{"vs_4_1", "ps_4_1", "cs_4_1"}}; + target = targets[static_cast(type)]; + } + break; + + case D3D_FEATURE_LEVEL_11_0: + { + static constexpr std::array targets = {{"vs_5_0", "ps_5_0", "cs_5_0"}}; + target = targets[static_cast(type)]; + } + break; + + case D3D_FEATURE_LEVEL_11_1: + default: + { + static constexpr std::array targets = {{"vs_5_1", "ps_5_1", "cs_5_1"}}; + target = targets[static_cast(type)]; + } + break; + } + + static constexpr UINT flags_non_debug = D3DCOMPILE_OPTIMIZATION_LEVEL3; + static constexpr UINT flags_debug = D3DCOMPILE_SKIP_OPTIMIZATION | D3DCOMPILE_DEBUG; + + wil::com_ptr_nothrow blob; + wil::com_ptr_nothrow error_blob; + const HRESULT hr = D3DCompile(code.data(), code.size(), "0", macros, nullptr, entry_point, target, + debug ? flags_debug : flags_non_debug, 0, blob.put(), error_blob.put()); + + std::string error_string; + if (error_blob) + { + error_string.append(static_cast(error_blob->GetBufferPointer()), error_blob->GetBufferSize()); + error_blob.reset(); + } + + if (FAILED(hr)) + { + Console.WriteLn("Failed to compile '%s':\n%s", target, error_string.c_str()); + + std::ofstream ofs(Path::Combine(EmuFolders::Logs, fmt::format("pcsx2_bad_shader_{}.txt", s_next_bad_shader_id++)), + std::ofstream::out | std::ofstream::binary); + if (ofs.is_open()) + { + ofs << code; + ofs << "\n\nCompile as " << target << " failed: " << hr << "\n"; + ofs.write(error_string.c_str(), error_string.size()); + ofs.close(); + } + + return {}; + } + + if (!error_string.empty()) + Console.Warning("'%s' compiled with warnings:\n%s", target, error_string.c_str()); + + return blob; +} diff --git a/pcsx2/GS/Renderers/DX11/D3D.h b/pcsx2/GS/Renderers/DX11/D3D.h index aeb6e1e358..0dcb5ab543 100644 --- a/pcsx2/GS/Renderers/DX11/D3D.h +++ b/pcsx2/GS/Renderers/DX11/D3D.h @@ -20,6 +20,7 @@ #include "pcsx2/Config.h" +#include #include #include #include @@ -67,4 +68,15 @@ namespace D3D VendorID GetVendorID(IDXGIAdapter1* adapter); GSRendererType GetPreferredRenderer(); + + // D3DCompiler wrapper. + enum class ShaderType + { + Vertex, + Pixel, + Compute + }; + + wil::com_ptr_nothrow CompileShader(ShaderType type, D3D_FEATURE_LEVEL feature_level, bool debug, + const std::string_view& code, const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main"); }; // namespace D3D diff --git a/common/D3D11/ShaderCache.cpp b/pcsx2/GS/Renderers/DX11/D3D11ShaderCache.cpp similarity index 63% rename from common/D3D11/ShaderCache.cpp rename to pcsx2/GS/Renderers/DX11/D3D11ShaderCache.cpp index 0f216a16e7..9c6aba8bd3 100644 --- a/common/D3D11/ShaderCache.cpp +++ b/pcsx2/GS/Renderers/DX11/D3D11ShaderCache.cpp @@ -1,5 +1,5 @@ /* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2022 PCSX2 Dev Team + * Copyright (C) 2002-2023 PCSX2 Dev Team * * PCSX2 is free software: you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Found- @@ -13,12 +13,19 @@ * If not, see . */ -#include "common/PrecompiledHeader.h" -#include "common/D3D11/ShaderCache.h" -#include "common/D3D11/ShaderCompiler.h" +#include "PrecompiledHeader.h" + +#include "GS/Renderers/DX11/D3D11ShaderCache.h" +#include "GS/GS.h" + +#include "Config.h" +#include "ShaderCacheVersion.h" + #include "common/FileSystem.h" #include "common/Console.h" #include "common/MD5Digest.h" +#include "common/Path.h" + #include #pragma pack(push, 1) @@ -37,14 +44,14 @@ struct CacheIndexEntry }; #pragma pack(pop) -D3D11::ShaderCache::ShaderCache() = default; +D3D11ShaderCache::D3D11ShaderCache() = default; -D3D11::ShaderCache::~ShaderCache() +D3D11ShaderCache::~D3D11ShaderCache() { Close(); } -bool D3D11::ShaderCache::CacheIndexKey::operator==(const CacheIndexKey& key) const +bool D3D11ShaderCache::CacheIndexKey::operator==(const CacheIndexKey& key) const { return (source_hash_low == key.source_hash_low && source_hash_high == key.source_hash_high && macro_hash_low == key.macro_hash_low && macro_hash_high == key.macro_hash_high && @@ -52,7 +59,7 @@ bool D3D11::ShaderCache::CacheIndexKey::operator==(const CacheIndexKey& key) con shader_type == key.shader_type && source_length == key.source_length); } -bool D3D11::ShaderCache::CacheIndexKey::operator!=(const CacheIndexKey& key) const +bool D3D11ShaderCache::CacheIndexKey::operator!=(const CacheIndexKey& key) const { return (source_hash_low != key.source_hash_low || source_hash_high != key.source_hash_high || macro_hash_low != key.macro_hash_low || macro_hash_high != key.macro_hash_high || @@ -60,15 +67,14 @@ bool D3D11::ShaderCache::CacheIndexKey::operator!=(const CacheIndexKey& key) con shader_type != key.shader_type || source_length != key.source_length); } -bool D3D11::ShaderCache::Open(std::string_view base_path, D3D_FEATURE_LEVEL feature_level, u32 version, bool debug) +bool D3D11ShaderCache::Open(D3D_FEATURE_LEVEL feature_level, bool debug) { m_feature_level = feature_level; - m_version = version; m_debug = debug; - if (!base_path.empty()) + if (!GSConfig.DisableShaderCache) { - const std::string base_filename = GetCacheBaseFileName(base_path, feature_level, debug); + const std::string base_filename = GetCacheBaseFileName(feature_level, debug); const std::string index_filename = base_filename + ".idx"; const std::string blob_filename = base_filename + ".bin"; @@ -79,7 +85,7 @@ bool D3D11::ShaderCache::Open(std::string_view base_path, D3D_FEATURE_LEVEL feat return true; } -void D3D11::ShaderCache::Close() +void D3D11ShaderCache::Close() { if (m_index_file) { @@ -93,7 +99,7 @@ void D3D11::ShaderCache::Close() } } -bool D3D11::ShaderCache::CreateNew(const std::string& index_filename, const std::string& blob_filename) +bool D3D11ShaderCache::CreateNew(const std::string& index_filename, const std::string& blob_filename) { if (FileSystem::FileExists(index_filename.c_str())) { @@ -113,9 +119,8 @@ bool D3D11::ShaderCache::CreateNew(const std::string& index_filename, const std: return false; } - const u32 index_version = FILE_VERSION; - if (std::fwrite(&index_version, sizeof(index_version), 1, m_index_file) != 1 || - std::fwrite(&m_version, sizeof(m_version), 1, m_index_file) != 1) + const u32 file_version = SHADER_CACHE_VERSION; + if (std::fwrite(&file_version, sizeof(file_version), 1, m_index_file) != 1) { Console.Error("Failed to write version to index file '%s'", index_filename.c_str()); std::fclose(m_index_file); @@ -137,7 +142,7 @@ bool D3D11::ShaderCache::CreateNew(const std::string& index_filename, const std: return true; } -bool D3D11::ShaderCache::ReadExisting(const std::string& index_filename, const std::string& blob_filename) +bool D3D11ShaderCache::ReadExisting(const std::string& index_filename, const std::string& blob_filename) { m_index_file = FileSystem::OpenCFile(index_filename.c_str(), "r+b"); if (!m_index_file) @@ -154,9 +159,7 @@ bool D3D11::ShaderCache::ReadExisting(const std::string& index_filename, const s } u32 file_version = 0; - u32 data_version = 0; - if (std::fread(&file_version, sizeof(file_version), 1, m_index_file) != 1 || file_version != FILE_VERSION || - std::fread(&data_version, sizeof(data_version), 1, m_index_file) != 1 || data_version != m_version) + if (std::fread(&file_version, sizeof(file_version), 1, m_index_file) != 1 || file_version != SHADER_CACHE_VERSION) { Console.Error("Bad file/data version in '%s'", index_filename.c_str()); std::fclose(m_index_file); @@ -194,11 +197,9 @@ bool D3D11::ShaderCache::ReadExisting(const std::string& index_filename, const s return false; } - const CacheIndexKey key{ - entry.source_hash_low, entry.source_hash_high, - entry.macro_hash_low, entry.macro_hash_high, - entry.entry_point_low, entry.entry_point_high, - entry.source_length, static_cast(entry.shader_type)}; + const CacheIndexKey key{entry.source_hash_low, entry.source_hash_high, entry.macro_hash_low, + entry.macro_hash_high, entry.entry_point_low, entry.entry_point_high, entry.source_length, + static_cast(entry.shader_type)}; const CacheIndexData data{entry.file_offset, entry.blob_size}; m_index.emplace(key, data); } @@ -210,11 +211,9 @@ bool D3D11::ShaderCache::ReadExisting(const std::string& index_filename, const s return true; } -std::string D3D11::ShaderCache::GetCacheBaseFileName(const std::string_view& base_path, D3D_FEATURE_LEVEL feature_level, - bool debug) +std::string D3D11ShaderCache::GetCacheBaseFileName(D3D_FEATURE_LEVEL feature_level, bool debug) { - std::string base_filename(base_path); - base_filename += FS_OSPATH_SEPARATOR_STR "d3d_shaders_"; + std::string base_filename = "d3d_shaders_"; switch (feature_level) { @@ -235,11 +234,11 @@ std::string D3D11::ShaderCache::GetCacheBaseFileName(const std::string_view& bas if (debug) base_filename += "_debug"; - return base_filename; + return Path::Combine(EmuFolders::Cache, base_filename); } -D3D11::ShaderCache::CacheIndexKey D3D11::ShaderCache::GetCacheKey(ShaderCompiler::Type type, const std::string_view& shader_code, - const D3D_SHADER_MACRO* macros, const char* entry_point) +D3D11ShaderCache::CacheIndexKey D3D11ShaderCache::GetCacheKey( + D3D::ShaderType type, const std::string_view& shader_code, const D3D_SHADER_MACRO* macros, const char* entry_point) { union { @@ -283,8 +282,9 @@ D3D11::ShaderCache::CacheIndexKey D3D11::ShaderCache::GetCacheKey(ShaderCompiler return key; } -wil::com_ptr_nothrow D3D11::ShaderCache::GetShaderBlob(ShaderCompiler::Type type, const std::string_view& shader_code, - const D3D_SHADER_MACRO* macros /* = nullptr */, const char* entry_point /* = "main" */) +wil::com_ptr_nothrow D3D11ShaderCache::GetShaderBlob(D3D::ShaderType type, + const std::string_view& shader_code, const D3D_SHADER_MACRO* macros /* = nullptr */, + const char* entry_point /* = "main" */) { const auto key = GetCacheKey(type, shader_code, macros, entry_point); auto iter = m_index.find(key); @@ -296,37 +296,51 @@ wil::com_ptr_nothrow D3D11::ShaderCache::GetShaderBlob(ShaderCompiler: if (FAILED(hr) || std::fseek(m_blob_file, iter->second.file_offset, SEEK_SET) != 0 || std::fread(blob->GetBufferPointer(), 1, iter->second.blob_size, m_blob_file) != iter->second.blob_size) { - Console.Error("(D3D11::ShaderCache::GetShaderBlob): Read blob from file failed"); + Console.Error("(GSShaderCache11::GetShaderBlob): Read blob from file failed"); return {}; } return blob; } -wil::com_ptr_nothrow D3D11::ShaderCache::GetVertexShader(ID3D11Device* device, - const std::string_view& shader_code, const D3D_SHADER_MACRO* macros /* = nullptr */, const char* entry_point /* = "main" */) +wil::com_ptr_nothrow D3D11ShaderCache::GetVertexShader(ID3D11Device* device, + const std::string_view& shader_code, const D3D_SHADER_MACRO* macros /* = nullptr */, + const char* entry_point /* = "main" */) { - wil::com_ptr_nothrow blob = GetShaderBlob(ShaderCompiler::Type::Vertex, shader_code, macros, entry_point); + wil::com_ptr_nothrow blob = GetShaderBlob(D3D::ShaderType::Vertex, shader_code, macros, entry_point); if (!blob) return {}; - return D3D11::ShaderCompiler::CreateVertexShader(device, blob.get()); + wil::com_ptr_nothrow shader; + const HRESULT hr = + device->CreateVertexShader(blob->GetBufferPointer(), blob->GetBufferSize(), nullptr, shader.put()); + if (FAILED(hr)) + { + Console.Error("Failed to create vertex shader: 0x%08X", hr); + return {}; + } + + return shader; } -bool D3D11::ShaderCache::GetVertexShaderAndInputLayout(ID3D11Device* device, - ID3D11VertexShader** vs, ID3D11InputLayout** il, - const D3D11_INPUT_ELEMENT_DESC* layout, size_t layout_size, const std::string_view& shader_code, - const D3D_SHADER_MACRO* macros /* = nullptr */, const char* entry_point /* = "main" */) +bool D3D11ShaderCache::GetVertexShaderAndInputLayout(ID3D11Device* device, ID3D11VertexShader** vs, + ID3D11InputLayout** il, const D3D11_INPUT_ELEMENT_DESC* layout, size_t layout_size, + const std::string_view& shader_code, const D3D_SHADER_MACRO* macros /* = nullptr */, + const char* entry_point /* = "main" */) { - wil::com_ptr_nothrow blob = GetShaderBlob(ShaderCompiler::Type::Vertex, shader_code, macros, entry_point); + wil::com_ptr_nothrow blob = GetShaderBlob(D3D::ShaderType::Vertex, shader_code, macros, entry_point); if (!blob) return false; - wil::com_ptr_nothrow actual_vs = D3D11::ShaderCompiler::CreateVertexShader(device, blob.get()); - if (!actual_vs) - return false; + wil::com_ptr_nothrow actual_vs; + HRESULT hr = device->CreateVertexShader(blob->GetBufferPointer(), blob->GetBufferSize(), nullptr, actual_vs.put()); + if (FAILED(hr)) + { + Console.Error("Failed to create vertex shader: 0x%08X", hr); + return {}; + } - HRESULT hr = device->CreateInputLayout(layout, layout_size, blob->GetBufferPointer(), blob->GetBufferSize(), il); + hr = device->CreateInputLayout(layout, layout_size, blob->GetBufferPointer(), blob->GetBufferSize(), il); if (FAILED(hr)) { Console.Error("(GetVertexShaderAndInputLayout) Failed to create input layout: %08X", hr); @@ -337,30 +351,51 @@ bool D3D11::ShaderCache::GetVertexShaderAndInputLayout(ID3D11Device* device, return true; } -wil::com_ptr_nothrow D3D11::ShaderCache::GetPixelShader(ID3D11Device* device, - const std::string_view& shader_code, const D3D_SHADER_MACRO* macros /* = nullptr */, const char* entry_point /* = "main" */) +wil::com_ptr_nothrow D3D11ShaderCache::GetPixelShader(ID3D11Device* device, + const std::string_view& shader_code, const D3D_SHADER_MACRO* macros /* = nullptr */, + const char* entry_point /* = "main" */) { - wil::com_ptr_nothrow blob = GetShaderBlob(ShaderCompiler::Type::Pixel, shader_code, macros, entry_point); + wil::com_ptr_nothrow blob = GetShaderBlob(D3D::ShaderType::Pixel, shader_code, macros, entry_point); if (!blob) return {}; - return D3D11::ShaderCompiler::CreatePixelShader(device, blob.get()); + wil::com_ptr_nothrow shader; + const HRESULT hr = + device->CreatePixelShader(blob->GetBufferPointer(), blob->GetBufferSize(), nullptr, shader.put()); + if (FAILED(hr)) + { + Console.Error("Failed to create pixel shader: 0x%08X", hr); + return {}; + } + + return shader; } -wil::com_ptr_nothrow D3D11::ShaderCache::GetComputeShader(ID3D11Device* device, - const std::string_view& shader_code, const D3D_SHADER_MACRO* macros /* = nullptr */, const char* entry_point /* = "main" */) +wil::com_ptr_nothrow D3D11ShaderCache::GetComputeShader(ID3D11Device* device, + const std::string_view& shader_code, const D3D_SHADER_MACRO* macros /* = nullptr */, + const char* entry_point /* = "main" */) { - wil::com_ptr_nothrow blob = GetShaderBlob(ShaderCompiler::Type::Compute, shader_code, macros, entry_point); + wil::com_ptr_nothrow blob = GetShaderBlob(D3D::ShaderType::Compute, shader_code, macros, entry_point); if (!blob) return {}; - return D3D11::ShaderCompiler::CreateComputeShader(device, blob.get()); + wil::com_ptr_nothrow shader; + const HRESULT hr = + device->CreateComputeShader(blob->GetBufferPointer(), blob->GetBufferSize(), nullptr, shader.put()); + if (FAILED(hr)) + { + Console.Error("Failed to create compute shader: 0x%08X", hr); + return {}; + } + + return shader; } -wil::com_ptr_nothrow D3D11::ShaderCache::CompileAndAddShaderBlob(const CacheIndexKey& key, +wil::com_ptr_nothrow D3D11ShaderCache::CompileAndAddShaderBlob(const CacheIndexKey& key, const std::string_view& shader_code, const D3D_SHADER_MACRO* macros, const char* entry_point) { - wil::com_ptr_nothrow blob = ShaderCompiler::CompileShader(key.shader_type, m_feature_level, m_debug, shader_code, macros, entry_point); + wil::com_ptr_nothrow blob = + D3D::CompileShader(key.shader_type, m_feature_level, m_debug, shader_code, macros, entry_point); if (!blob) return {}; @@ -387,7 +422,7 @@ wil::com_ptr_nothrow D3D11::ShaderCache::CompileAndAddShaderBlob(const std::fflush(m_blob_file) != 0 || std::fwrite(&entry, sizeof(entry), 1, m_index_file) != 1 || std::fflush(m_index_file) != 0) { - Console.Error("(D3D11::ShaderCache::CompileAndAddShaderBlob) Failed to write shader blob to file"); + Console.Error("(GSShaderCache11::CompileAndAddShaderBlob) Failed to write shader blob to file"); return blob; } diff --git a/pcsx2/GS/Renderers/DX11/D3D11ShaderCache.h b/pcsx2/GS/Renderers/DX11/D3D11ShaderCache.h new file mode 100644 index 0000000000..825fd91356 --- /dev/null +++ b/pcsx2/GS/Renderers/DX11/D3D11ShaderCache.h @@ -0,0 +1,106 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2023 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#pragma once +#include "GS/Renderers/DX11/D3D.h" + +#include "common/HashCombine.h" + +#include +#include +#include + +class D3D11ShaderCache +{ +public: + D3D11ShaderCache(); + ~D3D11ShaderCache(); + + D3D_FEATURE_LEVEL GetFeatureLevel() const { return m_feature_level; } + bool UsingDebugShaders() const { return m_debug; } + + bool Open(D3D_FEATURE_LEVEL feature_level, bool debug); + void Close(); + + wil::com_ptr_nothrow GetShaderBlob(D3D::ShaderType type, const std::string_view& shader_code, + const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main"); + + wil::com_ptr_nothrow GetVertexShader(ID3D11Device* device, const std::string_view& shader_code, + const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main"); + + bool GetVertexShaderAndInputLayout(ID3D11Device* device, ID3D11VertexShader** vs, ID3D11InputLayout** il, + const D3D11_INPUT_ELEMENT_DESC* layout, size_t layout_size, const std::string_view& shader_code, + const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main"); + + wil::com_ptr_nothrow GetPixelShader(ID3D11Device* device, const std::string_view& shader_code, + const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main"); + + wil::com_ptr_nothrow GetComputeShader(ID3D11Device* device, + const std::string_view& shader_code, const D3D_SHADER_MACRO* macros = nullptr, + const char* entry_point = "main"); + +private: + struct CacheIndexKey + { + u64 source_hash_low; + u64 source_hash_high; + u64 macro_hash_low; + u64 macro_hash_high; + u64 entry_point_low; + u64 entry_point_high; + u32 source_length; + D3D::ShaderType shader_type; + + bool operator==(const CacheIndexKey& key) const; + bool operator!=(const CacheIndexKey& key) const; + }; + + struct CacheIndexEntryHasher + { + std::size_t operator()(const CacheIndexKey& e) const noexcept + { + std::size_t h = 0; + HashCombine(h, e.entry_point_low, e.entry_point_high, e.macro_hash_low, e.macro_hash_high, + e.source_hash_low, e.source_hash_high, e.source_length, e.shader_type); + return h; + } + }; + + struct CacheIndexData + { + u32 file_offset; + u32 blob_size; + }; + + using CacheIndex = std::unordered_map; + + static std::string GetCacheBaseFileName(D3D_FEATURE_LEVEL feature_level, bool debug); + static CacheIndexKey GetCacheKey(D3D::ShaderType type, const std::string_view& shader_code, + const D3D_SHADER_MACRO* macros, const char* entry_point); + + bool CreateNew(const std::string& index_filename, const std::string& blob_filename); + bool ReadExisting(const std::string& index_filename, const std::string& blob_filename); + + wil::com_ptr_nothrow CompileAndAddShaderBlob(const CacheIndexKey& key, + const std::string_view& shader_code, const D3D_SHADER_MACRO* macros, const char* entry_point); + + std::FILE* m_index_file = nullptr; + std::FILE* m_blob_file = nullptr; + + CacheIndex m_index; + + D3D_FEATURE_LEVEL m_feature_level = D3D_FEATURE_LEVEL_11_0; + bool m_debug = false; +}; diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp index 3ecd5cedde..1c6a90b061 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp @@ -21,7 +21,6 @@ #include "GS/GSPerfMon.h" #include "GS/GSUtil.h" #include "Host.h" -#include "ShaderCacheVersion.h" #include "common/Align.h" #include "common/Path.h" @@ -168,18 +167,8 @@ bool GSDevice11::Create() level = m_dev->GetFeatureLevel(); const bool support_feature_level_11_0 = (level >= D3D_FEATURE_LEVEL_11_0); - if (!GSConfig.DisableShaderCache) - { - if (!m_shader_cache.Open(EmuFolders::Cache, m_dev->GetFeatureLevel(), SHADER_CACHE_VERSION, GSConfig.UseDebugDevice)) - { - Console.Warning("Shader cache failed to open."); - } - } - else - { - m_shader_cache.Open({}, m_dev->GetFeatureLevel(), SHADER_CACHE_VERSION, GSConfig.UseDebugDevice); - Console.WriteLn("Not using shader cache."); - } + if (!m_shader_cache.Open(m_dev->GetFeatureLevel(), GSConfig.UseDebugDevice)) + Console.Warning("Shader cache failed to open."); // Set maximum texture size limit based on supported feature level. if (support_feature_level_11_0) diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.h b/pcsx2/GS/Renderers/DX11/GSDevice11.h index 78561ee4de..bcd9ee57e4 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.h +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.h @@ -18,7 +18,7 @@ #include "GSTexture11.h" #include "GS/GSVector.h" #include "GS/Renderers/Common/GSDevice.h" -#include "common/D3D11/ShaderCache.h" +#include "GS/Renderers/DX11/D3D11ShaderCache.h" #include #include #include @@ -272,7 +272,7 @@ private: GSHWDrawConfig::VSConstantBuffer m_vs_cb_cache; GSHWDrawConfig::PSConstantBuffer m_ps_cb_cache; - D3D11::ShaderCache m_shader_cache; + D3D11ShaderCache m_shader_cache; std::string m_tfx_source; public: diff --git a/common/D3D12/Builders.cpp b/pcsx2/GS/Renderers/DX12/D3D12Builders.cpp similarity index 64% rename from common/D3D12/Builders.cpp rename to pcsx2/GS/Renderers/DX12/D3D12Builders.cpp index 7e0431f5f4..0eee7a6eef 100644 --- a/common/D3D12/Builders.cpp +++ b/pcsx2/GS/Renderers/DX12/D3D12Builders.cpp @@ -1,5 +1,5 @@ /* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2022 PCSX2 Dev Team + * Copyright (C) 2002-2023 PCSX2 Dev Team * * PCSX2 is free software: you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Found- @@ -13,24 +13,22 @@ * If not, see . */ -#include "common/PrecompiledHeader.h" +#include "PrecompiledHeader.h" -#include "common/D3D12/Builders.h" -#include "common/D3D12/Context.h" -#include "common/D3D12/ShaderCache.h" +#include "GS/Renderers/DX12/D3D12Builders.h" +#include "GS/Renderers/DX12/D3D12Context.h" +#include "GS/Renderers/DX12/D3D12ShaderCache.h" #include "common/Console.h" #include #include -using namespace D3D12; - -GraphicsPipelineBuilder::GraphicsPipelineBuilder() +D3D12::GraphicsPipelineBuilder::GraphicsPipelineBuilder() { Clear(); } -void GraphicsPipelineBuilder::Clear() +void D3D12::GraphicsPipelineBuilder::Clear() { std::memset(&m_desc, 0, sizeof(m_desc)); std::memset(m_input_elements.data(), 0, sizeof(D3D12_INPUT_ELEMENT_DESC) * m_input_elements.size()); @@ -39,7 +37,8 @@ void GraphicsPipelineBuilder::Clear() m_desc.SampleDesc.Count = 1; } -wil::com_ptr_nothrow GraphicsPipelineBuilder::Create(ID3D12Device* device, bool clear /*= true*/) +wil::com_ptr_nothrow D3D12::GraphicsPipelineBuilder::Create( + ID3D12Device* device, bool clear /*= true*/) { wil::com_ptr_nothrow ps; HRESULT hr = device->CreateGraphicsPipelineState(&m_desc, IID_PPV_ARGS(ps.put())); @@ -55,8 +54,8 @@ wil::com_ptr_nothrow GraphicsPipelineBuilder::Create(ID3D12 return ps; } -wil::com_ptr_nothrow GraphicsPipelineBuilder::Create(ID3D12Device* device, ShaderCache& cache, - bool clear /*= true*/) +wil::com_ptr_nothrow D3D12::GraphicsPipelineBuilder::Create( + ID3D12Device* device, D3D12ShaderCache& cache, bool clear /*= true*/) { wil::com_ptr_nothrow pso = cache.GetPipelineState(device, m_desc); if (!pso) @@ -68,46 +67,49 @@ wil::com_ptr_nothrow GraphicsPipelineBuilder::Create(ID3D12 return pso; } -void GraphicsPipelineBuilder::SetRootSignature(ID3D12RootSignature* rs) +void D3D12::GraphicsPipelineBuilder::SetRootSignature(ID3D12RootSignature* rs) { m_desc.pRootSignature = rs; } -void GraphicsPipelineBuilder::SetVertexShader(const ID3DBlob* blob) +void D3D12::GraphicsPipelineBuilder::SetVertexShader(const ID3DBlob* blob) { - SetVertexShader(const_cast(blob)->GetBufferPointer(), static_cast(const_cast(blob)->GetBufferSize())); + SetVertexShader(const_cast(blob)->GetBufferPointer(), + static_cast(const_cast(blob)->GetBufferSize())); } -void GraphicsPipelineBuilder::SetVertexShader(const void* data, u32 data_size) +void D3D12::GraphicsPipelineBuilder::SetVertexShader(const void* data, u32 data_size) { m_desc.VS.pShaderBytecode = data; m_desc.VS.BytecodeLength = data_size; } -void GraphicsPipelineBuilder::SetGeometryShader(const ID3DBlob* blob) +void D3D12::GraphicsPipelineBuilder::SetGeometryShader(const ID3DBlob* blob) { - SetGeometryShader(const_cast(blob)->GetBufferPointer(), static_cast(const_cast(blob)->GetBufferSize())); + SetGeometryShader(const_cast(blob)->GetBufferPointer(), + static_cast(const_cast(blob)->GetBufferSize())); } -void GraphicsPipelineBuilder::SetGeometryShader(const void* data, u32 data_size) +void D3D12::GraphicsPipelineBuilder::SetGeometryShader(const void* data, u32 data_size) { m_desc.GS.pShaderBytecode = data; m_desc.GS.BytecodeLength = data_size; } -void GraphicsPipelineBuilder::SetPixelShader(const ID3DBlob* blob) +void D3D12::GraphicsPipelineBuilder::SetPixelShader(const ID3DBlob* blob) { - SetPixelShader(const_cast(blob)->GetBufferPointer(), static_cast(const_cast(blob)->GetBufferSize())); + SetPixelShader(const_cast(blob)->GetBufferPointer(), + static_cast(const_cast(blob)->GetBufferSize())); } -void GraphicsPipelineBuilder::SetPixelShader(const void* data, u32 data_size) +void D3D12::GraphicsPipelineBuilder::SetPixelShader(const void* data, u32 data_size) { m_desc.PS.pShaderBytecode = data; m_desc.PS.BytecodeLength = data_size; } -void GraphicsPipelineBuilder::AddVertexAttribute(const char* semantic_name, u32 semantic_index, DXGI_FORMAT format, - u32 buffer, u32 offset) +void D3D12::GraphicsPipelineBuilder::AddVertexAttribute( + const char* semantic_name, u32 semantic_index, DXGI_FORMAT format, u32 buffer, u32 offset) { const u32 index = m_desc.InputLayout.NumElements; m_input_elements[index].SemanticIndex = semantic_index; @@ -122,38 +124,38 @@ void GraphicsPipelineBuilder::AddVertexAttribute(const char* semantic_name, u32 m_desc.InputLayout.NumElements++; } -void GraphicsPipelineBuilder::SetPrimitiveTopologyType(D3D12_PRIMITIVE_TOPOLOGY_TYPE type) +void D3D12::GraphicsPipelineBuilder::SetPrimitiveTopologyType(D3D12_PRIMITIVE_TOPOLOGY_TYPE type) { m_desc.PrimitiveTopologyType = type; } -void GraphicsPipelineBuilder::SetRasterizationState(D3D12_FILL_MODE polygon_mode, D3D12_CULL_MODE cull_mode, - bool front_face_ccw) +void D3D12::GraphicsPipelineBuilder::SetRasterizationState( + D3D12_FILL_MODE polygon_mode, D3D12_CULL_MODE cull_mode, bool front_face_ccw) { m_desc.RasterizerState.FillMode = polygon_mode; m_desc.RasterizerState.CullMode = cull_mode; m_desc.RasterizerState.FrontCounterClockwise = front_face_ccw; } -void GraphicsPipelineBuilder::SetMultisamples(u32 multisamples) +void D3D12::GraphicsPipelineBuilder::SetMultisamples(u32 multisamples) { m_desc.RasterizerState.MultisampleEnable = multisamples > 1; m_desc.SampleDesc.Count = multisamples; } -void GraphicsPipelineBuilder::SetNoCullRasterizationState() +void D3D12::GraphicsPipelineBuilder::SetNoCullRasterizationState() { SetRasterizationState(D3D12_FILL_MODE_SOLID, D3D12_CULL_MODE_NONE, false); } -void GraphicsPipelineBuilder::SetDepthState(bool depth_test, bool depth_write, D3D12_COMPARISON_FUNC compare_op) +void D3D12::GraphicsPipelineBuilder::SetDepthState(bool depth_test, bool depth_write, D3D12_COMPARISON_FUNC compare_op) { m_desc.DepthStencilState.DepthEnable = depth_test; m_desc.DepthStencilState.DepthWriteMask = depth_write ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO; m_desc.DepthStencilState.DepthFunc = compare_op; } -void GraphicsPipelineBuilder::SetStencilState(bool stencil_test, u8 read_mask, u8 write_mask, +void D3D12::GraphicsPipelineBuilder::SetStencilState(bool stencil_test, u8 read_mask, u8 write_mask, const D3D12_DEPTH_STENCILOP_DESC& front, const D3D12_DEPTH_STENCILOP_DESC& back) { m_desc.DepthStencilState.StencilEnable = stencil_test; @@ -163,21 +165,20 @@ void GraphicsPipelineBuilder::SetStencilState(bool stencil_test, u8 read_mask, u m_desc.DepthStencilState.BackFace = back; } -void GraphicsPipelineBuilder::SetNoDepthTestState() +void D3D12::GraphicsPipelineBuilder::SetNoDepthTestState() { SetDepthState(false, false, D3D12_COMPARISON_FUNC_ALWAYS); } -void GraphicsPipelineBuilder::SetNoStencilState() +void D3D12::GraphicsPipelineBuilder::SetNoStencilState() { D3D12_DEPTH_STENCILOP_DESC empty = {}; SetStencilState(false, 0, 0, empty, empty); } -void GraphicsPipelineBuilder::SetBlendState(u32 rt, bool blend_enable, D3D12_BLEND src_factor, D3D12_BLEND dst_factor, - D3D12_BLEND_OP op, D3D12_BLEND alpha_src_factor, - D3D12_BLEND alpha_dst_factor, D3D12_BLEND_OP alpha_op, - u8 write_mask /*= 0xFF*/) +void D3D12::GraphicsPipelineBuilder::SetBlendState(u32 rt, bool blend_enable, D3D12_BLEND src_factor, + D3D12_BLEND dst_factor, D3D12_BLEND_OP op, D3D12_BLEND alpha_src_factor, D3D12_BLEND alpha_dst_factor, + D3D12_BLEND_OP alpha_op, u8 write_mask /*= 0xFF*/) { m_desc.BlendState.RenderTarget[rt].BlendEnable = blend_enable; m_desc.BlendState.RenderTarget[rt].SrcBlend = src_factor; @@ -192,49 +193,49 @@ void GraphicsPipelineBuilder::SetBlendState(u32 rt, bool blend_enable, D3D12_BLE m_desc.BlendState.IndependentBlendEnable = TRUE; } -void GraphicsPipelineBuilder::SetNoBlendingState() +void D3D12::GraphicsPipelineBuilder::SetNoBlendingState() { SetBlendState(0, false, D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, D3D12_COLOR_WRITE_ENABLE_ALL); m_desc.BlendState.IndependentBlendEnable = FALSE; } -void GraphicsPipelineBuilder::ClearRenderTargets() +void D3D12::GraphicsPipelineBuilder::ClearRenderTargets() { m_desc.NumRenderTargets = 0; for (u32 i = 0; i < sizeof(m_desc.RTVFormats) / sizeof(m_desc.RTVFormats[0]); i++) m_desc.RTVFormats[i] = DXGI_FORMAT_UNKNOWN; } -void GraphicsPipelineBuilder::SetRenderTarget(u32 rt, DXGI_FORMAT format) +void D3D12::GraphicsPipelineBuilder::SetRenderTarget(u32 rt, DXGI_FORMAT format) { m_desc.RTVFormats[rt] = format; if (rt >= m_desc.NumRenderTargets) m_desc.NumRenderTargets = rt + 1; } -void GraphicsPipelineBuilder::ClearDepthStencilFormat() +void D3D12::GraphicsPipelineBuilder::ClearDepthStencilFormat() { m_desc.DSVFormat = DXGI_FORMAT_UNKNOWN; } -void GraphicsPipelineBuilder::SetDepthStencilFormat(DXGI_FORMAT format) +void D3D12::GraphicsPipelineBuilder::SetDepthStencilFormat(DXGI_FORMAT format) { m_desc.DSVFormat = format; } - -ComputePipelineBuilder::ComputePipelineBuilder() +D3D12::ComputePipelineBuilder::ComputePipelineBuilder() { Clear(); } -void ComputePipelineBuilder::Clear() +void D3D12::ComputePipelineBuilder::Clear() { std::memset(&m_desc, 0, sizeof(m_desc)); } -wil::com_ptr_nothrow ComputePipelineBuilder::Create(ID3D12Device* device, bool clear /*= true*/) +wil::com_ptr_nothrow D3D12::ComputePipelineBuilder::Create( + ID3D12Device* device, bool clear /*= true*/) { wil::com_ptr_nothrow ps; HRESULT hr = device->CreateComputePipelineState(&m_desc, IID_PPV_ARGS(ps.put())); @@ -250,7 +251,8 @@ wil::com_ptr_nothrow ComputePipelineBuilder::Create(ID3D12D return ps; } -wil::com_ptr_nothrow ComputePipelineBuilder::Create(ID3D12Device* device, ShaderCache& cache, bool clear /*= true*/) +wil::com_ptr_nothrow D3D12::ComputePipelineBuilder::Create( + ID3D12Device* device, D3D12ShaderCache& cache, bool clear /*= true*/) { wil::com_ptr_nothrow pso = cache.GetPipelineState(device, m_desc); if (!pso) @@ -262,23 +264,23 @@ wil::com_ptr_nothrow ComputePipelineBuilder::Create(ID3D12D return pso; } -void ComputePipelineBuilder::SetRootSignature(ID3D12RootSignature* rs) +void D3D12::ComputePipelineBuilder::SetRootSignature(ID3D12RootSignature* rs) { m_desc.pRootSignature = rs; } -void ComputePipelineBuilder::SetShader(const void* data, u32 data_size) +void D3D12::ComputePipelineBuilder::SetShader(const void* data, u32 data_size) { m_desc.CS.pShaderBytecode = data; m_desc.CS.BytecodeLength = data_size; } -RootSignatureBuilder::RootSignatureBuilder() +D3D12::RootSignatureBuilder::RootSignatureBuilder() { Clear(); } -void RootSignatureBuilder::Clear() +void D3D12::RootSignatureBuilder::Clear() { m_desc = {}; m_desc.pParameters = m_params.data(); @@ -287,7 +289,7 @@ void RootSignatureBuilder::Clear() m_num_descriptor_ranges = 0; } -wil::com_ptr_nothrow RootSignatureBuilder::Create(bool clear /*= true*/) +wil::com_ptr_nothrow D3D12::RootSignatureBuilder::Create(bool clear /*= true*/) { wil::com_ptr_nothrow rs = g_d3d12_context->CreateRootSignature(&m_desc); if (!rs) @@ -299,12 +301,12 @@ wil::com_ptr_nothrow RootSignatureBuilder::Create(bool clea return rs; } -void RootSignatureBuilder::SetInputAssemblerFlag() +void D3D12::RootSignatureBuilder::SetInputAssemblerFlag() { m_desc.Flags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; } -u32 RootSignatureBuilder::Add32BitConstants(u32 shader_reg, u32 num_values, D3D12_SHADER_VISIBILITY visibility) +u32 D3D12::RootSignatureBuilder::Add32BitConstants(u32 shader_reg, u32 num_values, D3D12_SHADER_VISIBILITY visibility) { const u32 index = m_desc.NumParameters++; @@ -317,7 +319,7 @@ u32 RootSignatureBuilder::Add32BitConstants(u32 shader_reg, u32 num_values, D3D1 return index; } -u32 RootSignatureBuilder::AddCBVParameter(u32 shader_reg, D3D12_SHADER_VISIBILITY visibility) +u32 D3D12::RootSignatureBuilder::AddCBVParameter(u32 shader_reg, D3D12_SHADER_VISIBILITY visibility) { const u32 index = m_desc.NumParameters++; @@ -329,7 +331,7 @@ u32 RootSignatureBuilder::AddCBVParameter(u32 shader_reg, D3D12_SHADER_VISIBILIT return index; } -u32 RootSignatureBuilder::AddSRVParameter(u32 shader_reg, D3D12_SHADER_VISIBILITY visibility) +u32 D3D12::RootSignatureBuilder::AddSRVParameter(u32 shader_reg, D3D12_SHADER_VISIBILITY visibility) { const u32 index = m_desc.NumParameters++; @@ -341,8 +343,8 @@ u32 RootSignatureBuilder::AddSRVParameter(u32 shader_reg, D3D12_SHADER_VISIBILIT return index; } -u32 RootSignatureBuilder::AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE rt, u32 start_shader_reg, u32 num_shader_regs, - D3D12_SHADER_VISIBILITY visibility) +u32 D3D12::RootSignatureBuilder::AddDescriptorTable( + D3D12_DESCRIPTOR_RANGE_TYPE rt, u32 start_shader_reg, u32 num_shader_regs, D3D12_SHADER_VISIBILITY visibility) { const u32 index = m_desc.NumParameters++; const u32 dr_index = m_num_descriptor_ranges++; diff --git a/common/D3D12/Builders.h b/pcsx2/GS/Renderers/DX12/D3D12Builders.h similarity index 87% rename from common/D3D12/Builders.h rename to pcsx2/GS/Renderers/DX12/D3D12Builders.h index 37356e2c5c..6ece130510 100644 --- a/common/D3D12/Builders.h +++ b/pcsx2/GS/Renderers/DX12/D3D12Builders.h @@ -1,5 +1,5 @@ /* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2022 PCSX2 Dev Team + * Copyright (C) 2002-2023 PCSX2 Dev Team * * PCSX2 is free software: you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Found- @@ -22,10 +22,10 @@ #include #include +class D3D12ShaderCache; + namespace D3D12 { - class ShaderCache; - class RootSignatureBuilder { public: @@ -71,7 +71,8 @@ namespace D3D12 void Clear(); wil::com_ptr_nothrow Create(ID3D12Device* device, bool clear = true); - wil::com_ptr_nothrow Create(ID3D12Device* device, ShaderCache& cache, bool clear = true); + wil::com_ptr_nothrow Create( + ID3D12Device* device, D3D12ShaderCache& cache, bool clear = true); void SetRootSignature(ID3D12RootSignature* rs); @@ -83,7 +84,8 @@ namespace D3D12 void SetGeometryShader(const ID3DBlob* blob); void SetPixelShader(const ID3DBlob* blob); - void AddVertexAttribute(const char* semantic_name, u32 semantic_index, DXGI_FORMAT format, u32 buffer, u32 offset); + void AddVertexAttribute( + const char* semantic_name, u32 semantic_index, DXGI_FORMAT format, u32 buffer, u32 offset); void SetPrimitiveTopologyType(D3D12_PRIMITIVE_TOPOLOGY_TYPE type); @@ -94,7 +96,8 @@ namespace D3D12 void SetNoCullRasterizationState(); void SetDepthState(bool depth_test, bool depth_write, D3D12_COMPARISON_FUNC compare_op); - void SetStencilState(bool stencil_test, u8 read_mask, u8 write_mask, const D3D12_DEPTH_STENCILOP_DESC& front, const D3D12_DEPTH_STENCILOP_DESC& back); + void SetStencilState(bool stencil_test, u8 read_mask, u8 write_mask, const D3D12_DEPTH_STENCILOP_DESC& front, + const D3D12_DEPTH_STENCILOP_DESC& back); void SetNoDepthTestState(); void SetNoStencilState(); @@ -127,11 +130,13 @@ namespace D3D12 void Clear(); wil::com_ptr_nothrow Create(ID3D12Device* device, bool clear = true); - wil::com_ptr_nothrow Create(ID3D12Device* device, ShaderCache& cache, bool clear = true); + wil::com_ptr_nothrow Create( + ID3D12Device* device, D3D12ShaderCache& cache, bool clear = true); void SetRootSignature(ID3D12RootSignature* rs); void SetShader(const void* data, u32 data_size); + private: D3D12_COMPUTE_PIPELINE_STATE_DESC m_desc; }; diff --git a/common/D3D12/Context.cpp b/pcsx2/GS/Renderers/DX12/D3D12Context.cpp similarity index 75% rename from common/D3D12/Context.cpp rename to pcsx2/GS/Renderers/DX12/D3D12Context.cpp index 3f6f93b070..597a6a928e 100644 --- a/common/D3D12/Context.cpp +++ b/pcsx2/GS/Renderers/DX12/D3D12Context.cpp @@ -1,5 +1,5 @@ /* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2022 PCSX2 Dev Team + * Copyright (C) 2002-2023 PCSX2 Dev Team * * PCSX2 is free software: you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Found- @@ -13,9 +13,9 @@ * If not, see . */ -#include "common/PrecompiledHeader.h" +#include "PrecompiledHeader.h" -#include "common/D3D12/Context.h" +#include "GS/Renderers/DX12/D3D12Context.h" #include "common/Assertions.h" #include "common/General.h" #include "common/ScopedGuard.h" @@ -28,64 +28,20 @@ #include #include -std::unique_ptr g_d3d12_context; +std::unique_ptr g_d3d12_context; -using namespace D3D12; +D3D12Context::D3D12Context() = default; -// Private D3D12 state -static HMODULE s_d3d12_library; -static PFN_D3D12_CREATE_DEVICE s_d3d12_create_device; -static PFN_D3D12_GET_DEBUG_INTERFACE s_d3d12_get_debug_interface; -static PFN_D3D12_SERIALIZE_ROOT_SIGNATURE s_d3d12_serialize_root_signature; - -static bool LoadD3D12Library() -{ - if ((s_d3d12_library = LoadLibraryW(L"d3d12.dll")) == nullptr || - (s_d3d12_create_device = - reinterpret_cast(GetProcAddress(s_d3d12_library, "D3D12CreateDevice"))) == nullptr || - (s_d3d12_get_debug_interface = reinterpret_cast( - GetProcAddress(s_d3d12_library, "D3D12GetDebugInterface"))) == nullptr || - (s_d3d12_serialize_root_signature = reinterpret_cast( - GetProcAddress(s_d3d12_library, "D3D12SerializeRootSignature"))) == nullptr) - { - Console.Error("d3d12.dll could not be loaded."); - s_d3d12_create_device = nullptr; - s_d3d12_get_debug_interface = nullptr; - s_d3d12_serialize_root_signature = nullptr; - if (s_d3d12_library) - FreeLibrary(s_d3d12_library); - s_d3d12_library = nullptr; - return false; - } - - return true; -} - -static void UnloadD3D12Library() -{ - s_d3d12_serialize_root_signature = nullptr; - s_d3d12_get_debug_interface = nullptr; - s_d3d12_create_device = nullptr; - if (s_d3d12_library) - { - FreeLibrary(s_d3d12_library); - s_d3d12_library = nullptr; - } -} - -Context::Context() = default; - -Context::~Context() +D3D12Context::~D3D12Context() { DestroyResources(); } -Context::ComPtr Context::SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc) +D3D12Context::ComPtr D3D12Context::SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc) { ComPtr blob; ComPtr error_blob; - const HRESULT hr = s_d3d12_serialize_root_signature(desc, D3D_ROOT_SIGNATURE_VERSION_1, blob.put(), - error_blob.put()); + const HRESULT hr = D3D12SerializeRootSignature(desc, D3D_ROOT_SIGNATURE_VERSION_1, blob.put(), error_blob.put()); if (FAILED(hr)) { Console.Error("D3D12SerializeRootSignature() failed: %08X", hr); @@ -98,7 +54,7 @@ Context::ComPtr Context::SerializeRootSignature(const D3D12_ROOT_SIGNA return blob; } -D3D12::Context::ComPtr Context::CreateRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc) +D3D12Context::ComPtr D3D12Context::CreateRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc) { ComPtr blob = SerializeRootSignature(desc); if (!blob) @@ -116,7 +72,7 @@ D3D12::Context::ComPtr Context::CreateRootSignature(const D return rs; } -bool Context::SupportsTextureFormat(DXGI_FORMAT format) +bool D3D12Context::SupportsTextureFormat(DXGI_FORMAT format) { constexpr u32 required = D3D12_FORMAT_SUPPORT1_TEXTURE2D | D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE; @@ -125,17 +81,11 @@ bool Context::SupportsTextureFormat(DXGI_FORMAT format) (support.Support1 & required) == required; } -bool Context::Create(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool enable_debug_layer) +bool D3D12Context::Create(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool enable_debug_layer) { pxAssertRel(!g_d3d12_context, "No context exists"); - if (!LoadD3D12Library()) - { - Console.Error("Failed to load D3D12 library"); - return false; - } - - g_d3d12_context.reset(new Context()); + g_d3d12_context.reset(new D3D12Context()); if (!g_d3d12_context->CreateDevice(dxgi_factory, adapter, enable_debug_layer) || !g_d3d12_context->CreateCommandQueue() || !g_d3d12_context->CreateAllocator() || !g_d3d12_context->CreateFence() || !g_d3d12_context->CreateDescriptorHeaps() || @@ -149,15 +99,13 @@ bool Context::Create(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool e return true; } -void Context::Destroy() +void D3D12Context::Destroy() { if (g_d3d12_context) g_d3d12_context.reset(); - - UnloadD3D12Library(); } -u32 Context::GetAdapterVendorID() const +u32 D3D12Context::GetAdapterVendorID() const { if (!m_adapter) return 0; @@ -169,14 +117,14 @@ u32 Context::GetAdapterVendorID() const return desc.VendorId; } -bool Context::CreateDevice(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool enable_debug_layer) +bool D3D12Context::CreateDevice(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool enable_debug_layer) { HRESULT hr; // Enabling the debug layer will fail if the Graphics Tools feature is not installed. if (enable_debug_layer) { - hr = s_d3d12_get_debug_interface(IID_PPV_ARGS(&m_debug_interface)); + hr = D3D12GetDebugInterface(IID_PPV_ARGS(&m_debug_interface)); if (SUCCEEDED(hr)) { m_debug_interface->EnableDebugLayer(); @@ -189,7 +137,7 @@ bool Context::CreateDevice(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, } // Create the actual device. - hr = s_d3d12_create_device(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device)); + hr = D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device)); if (FAILED(hr)) { Console.Error("Failed to create D3D12 device: %08X", hr); @@ -229,21 +177,23 @@ bool Context::CreateDevice(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, return true; } -bool Context::CreateCommandQueue() +bool D3D12Context::CreateCommandQueue() { - const D3D12_COMMAND_QUEUE_DESC queue_desc = {D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, - D3D12_COMMAND_QUEUE_FLAG_NONE}; + const D3D12_COMMAND_QUEUE_DESC queue_desc = { + D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL, D3D12_COMMAND_QUEUE_FLAG_NONE}; HRESULT hr = m_device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&m_command_queue)); pxAssertRel(SUCCEEDED(hr), "Create command queue"); return SUCCEEDED(hr); } -bool Context::CreateAllocator() +bool D3D12Context::CreateAllocator() { D3D12MA::ALLOCATOR_DESC allocatorDesc = {}; allocatorDesc.pDevice = m_device.get(); allocatorDesc.pAdapter = m_adapter.get(); - allocatorDesc.Flags = D3D12MA::ALLOCATOR_FLAG_SINGLETHREADED | D3D12MA::ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED /* | D3D12MA::ALLOCATOR_FLAG_ALWAYS_COMMITTED*/; + allocatorDesc.Flags = + D3D12MA::ALLOCATOR_FLAG_SINGLETHREADED | + D3D12MA::ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED /* | D3D12MA::ALLOCATOR_FLAG_ALWAYS_COMMITTED*/; const HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, m_allocator.put()); if (FAILED(hr)) @@ -255,7 +205,7 @@ bool Context::CreateAllocator() return true; } -bool Context::CreateFence() +bool D3D12Context::CreateFence() { HRESULT hr = m_device->CreateFence(m_completed_fence_value, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence)); pxAssertRel(SUCCEEDED(hr), "Create fence"); @@ -270,7 +220,7 @@ bool Context::CreateFence() return true; } -bool Context::CreateDescriptorHeaps() +bool D3D12Context::CreateDescriptorHeaps() { static constexpr size_t MAX_SRVS = 32768; static constexpr size_t MAX_RTVS = 16384; @@ -286,8 +236,8 @@ bool Context::CreateDescriptorHeaps() } // Allocate null SRV descriptor for unbound textures. - constexpr D3D12_SHADER_RESOURCE_VIEW_DESC null_srv_desc = {DXGI_FORMAT_R8G8B8A8_UNORM, D3D12_SRV_DIMENSION_TEXTURE2D, - D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING}; + constexpr D3D12_SHADER_RESOURCE_VIEW_DESC null_srv_desc = { + DXGI_FORMAT_R8G8B8A8_UNORM, D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING}; if (!m_descriptor_heap_manager.Allocate(&m_null_srv_descriptor)) { @@ -299,7 +249,7 @@ bool Context::CreateDescriptorHeaps() return true; } -bool Context::CreateCommandLists() +bool D3D12Context::CreateCommandLists() { static constexpr size_t MAX_GPU_SRVS = 32768; static constexpr size_t MAX_GPU_SAMPLERS = 2048; @@ -311,15 +261,14 @@ bool Context::CreateCommandLists() for (u32 i = 0; i < 2; i++) { - hr = m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, - IID_PPV_ARGS(res.command_allocators[i].put())); + hr = m_device->CreateCommandAllocator( + D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(res.command_allocators[i].put())); pxAssertRel(SUCCEEDED(hr), "Create command allocator"); if (FAILED(hr)) return false; - hr = m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, - res.command_allocators[i].get(), nullptr, - IID_PPV_ARGS(res.command_lists[i].put())); + hr = m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, res.command_allocators[i].get(), + nullptr, IID_PPV_ARGS(res.command_lists[i].put())); if (FAILED(hr)) { Console.Error("Failed to create command list: %08X", hr); @@ -350,12 +299,12 @@ bool Context::CreateCommandLists() return true; } -bool Context::CreateTextureStreamBuffer() +bool D3D12Context::CreateTextureStreamBuffer() { return m_texture_stream_buffer.Create(TEXTURE_UPLOAD_BUFFER_SIZE); } -void Context::MoveToNextCommandList() +void D3D12Context::MoveToNextCommandList() { m_current_command_list = (m_current_command_list + 1) % NUM_COMMAND_LISTS; m_current_fence_value++; @@ -385,7 +334,8 @@ void Context::MoveToNextCommandList() { u64 timestamps[2]; std::memcpy(timestamps, static_cast(map) + offset, sizeof(timestamps)); - m_accumulated_gpu_time += static_cast(static_cast(timestamps[1] - timestamps[0]) / m_timestamp_frequency); + m_accumulated_gpu_time += + static_cast(static_cast(timestamps[1] - timestamps[0]) / m_timestamp_frequency); const D3D12_RANGE write_range = {}; m_timestamp_query_buffer->Unmap(0, &write_range); @@ -403,13 +353,14 @@ void Context::MoveToNextCommandList() m_current_command_list * NUM_TIMESTAMP_QUERIES_PER_CMDLIST); } - ID3D12DescriptorHeap* heaps[2] = {res.descriptor_allocator.GetDescriptorHeap(), res.sampler_allocator.GetDescriptorHeap()}; + ID3D12DescriptorHeap* heaps[2] = { + res.descriptor_allocator.GetDescriptorHeap(), res.sampler_allocator.GetDescriptorHeap()}; res.command_lists[1]->SetDescriptorHeaps(std::size(heaps), heaps); m_allocator->SetCurrentFrameIndex(static_cast(m_current_fence_value)); } -ID3D12GraphicsCommandList4* Context::GetInitCommandList() +ID3D12GraphicsCommandList4* D3D12Context::GetInitCommandList() { CommandListResources& res = m_command_lists[m_current_command_list]; if (!res.init_command_list_used) @@ -425,7 +376,7 @@ ID3D12GraphicsCommandList4* Context::GetInitCommandList() return res.command_lists[0].get(); } -bool Context::ExecuteCommandList(WaitType wait_for_completion) +bool D3D12Context::ExecuteCommandList(WaitType wait_for_completion) { CommandListResources& res = m_command_lists[m_current_command_list]; HRESULT hr; @@ -480,13 +431,13 @@ bool Context::ExecuteCommandList(WaitType wait_for_completion) return true; } -void Context::InvalidateSamplerGroups() +void D3D12Context::InvalidateSamplerGroups() { for (CommandListResources& res : m_command_lists) res.sampler_allocator.InvalidateCache(); } -void Context::DeferObjectDestruction(ID3D12DeviceChild* resource) +void D3D12Context::DeferObjectDestruction(ID3D12DeviceChild* resource) { if (!resource) return; @@ -495,7 +446,7 @@ void Context::DeferObjectDestruction(ID3D12DeviceChild* resource) m_command_lists[m_current_command_list].pending_resources.emplace_back(nullptr, resource); } -void Context::DeferResourceDestruction(D3D12MA::Allocation* allocation, ID3D12Resource* resource) +void D3D12Context::DeferResourceDestruction(D3D12MA::Allocation* allocation, ID3D12Resource* resource) { if (!resource) return; @@ -507,21 +458,21 @@ void Context::DeferResourceDestruction(D3D12MA::Allocation* allocation, ID3D12Re m_command_lists[m_current_command_list].pending_resources.emplace_back(allocation, resource); } -void Context::DeferDescriptorDestruction(DescriptorHeapManager& manager, u32 index) +void D3D12Context::DeferDescriptorDestruction(D3D12DescriptorHeapManager& manager, u32 index) { m_command_lists[m_current_command_list].pending_descriptors.emplace_back(manager, index); } -void Context::DeferDescriptorDestruction(DescriptorHeapManager& manager, DescriptorHandle* handle) +void D3D12Context::DeferDescriptorDestruction(D3D12DescriptorHeapManager& manager, D3D12DescriptorHandle* handle) { - if (handle->index == DescriptorHandle::INVALID_INDEX) + if (handle->index == D3D12DescriptorHandle::INVALID_INDEX) return; m_command_lists[m_current_command_list].pending_descriptors.emplace_back(manager, handle->index); handle->Clear(); } -void Context::DestroyPendingResources(CommandListResources& cmdlist) +void D3D12Context::DestroyPendingResources(CommandListResources& cmdlist) { for (const auto& dd : cmdlist.pending_descriptors) dd.first.Free(dd.second); @@ -536,7 +487,7 @@ void Context::DestroyPendingResources(CommandListResources& cmdlist) cmdlist.pending_resources.clear(); } -void Context::DestroyResources() +void D3D12Context::DestroyResources() { if (m_command_queue) { @@ -568,7 +519,7 @@ void Context::DestroyResources() m_device.reset(); } -void Context::WaitForFence(u64 fence, bool spin) +void D3D12Context::WaitForFence(u64 fence, bool spin) { if (m_completed_fence_value >= fence) return; @@ -607,7 +558,7 @@ void Context::WaitForFence(u64 fence, bool spin) } } -void Context::WaitForGPUIdle() +void D3D12Context::WaitForGPUIdle() { u32 index = (m_current_command_list + 1) % NUM_COMMAND_LISTS; for (u32 i = 0; i < (NUM_COMMAND_LISTS - 1); i++) @@ -617,7 +568,7 @@ void Context::WaitForGPUIdle() } } -bool Context::CreateTimestampQuery() +bool D3D12Context::CreateTimestampQuery() { constexpr u32 QUERY_COUNT = NUM_TIMESTAMP_QUERIES_PER_CMDLIST * NUM_COMMAND_LISTS; constexpr u32 BUFFER_SIZE = sizeof(u64) * QUERY_COUNT; @@ -631,9 +582,8 @@ bool Context::CreateTimestampQuery() } const D3D12MA::ALLOCATION_DESC allocation_desc = {D3D12MA::ALLOCATION_FLAG_NONE, D3D12_HEAP_TYPE_READBACK}; - const D3D12_RESOURCE_DESC resource_desc = { - D3D12_RESOURCE_DIMENSION_BUFFER, 0, BUFFER_SIZE, 1, 1, 1, DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, - D3D12_RESOURCE_FLAG_NONE}; + const D3D12_RESOURCE_DESC resource_desc = {D3D12_RESOURCE_DIMENSION_BUFFER, 0, BUFFER_SIZE, 1, 1, 1, + DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE}; hr = m_allocator->CreateResource(&allocation_desc, &resource_desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, m_timestamp_query_allocation.put(), IID_PPV_ARGS(m_timestamp_query_buffer.put())); if (FAILED(hr)) @@ -654,35 +604,32 @@ bool Context::CreateTimestampQuery() return true; } -float Context::GetAndResetAccumulatedGPUTime() +float D3D12Context::GetAndResetAccumulatedGPUTime() { const float time = m_accumulated_gpu_time; m_accumulated_gpu_time = 0.0f; return time; } -void Context::SetEnableGPUTiming(bool enabled) +void D3D12Context::SetEnableGPUTiming(bool enabled) { m_gpu_timing_enabled = enabled; } -bool Context::AllocatePreinitializedGPUBuffer(u32 size, ID3D12Resource** gpu_buffer, +bool D3D12Context::AllocatePreinitializedGPUBuffer(u32 size, ID3D12Resource** gpu_buffer, D3D12MA::Allocation** gpu_allocation, const std::function& fill_callback) { // Try to place the fixed index buffer in GPU local memory. // Use the staging buffer to copy into it. - const D3D12_RESOURCE_DESC rd = {D3D12_RESOURCE_DIMENSION_BUFFER, 0, size, 1, 1, 1, - DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, - D3D12_RESOURCE_FLAG_NONE}; + const D3D12_RESOURCE_DESC rd = {D3D12_RESOURCE_DIMENSION_BUFFER, 0, size, 1, 1, 1, DXGI_FORMAT_UNKNOWN, {1, 0}, + D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE}; - const D3D12MA::ALLOCATION_DESC cpu_ad = { - D3D12MA::ALLOCATION_FLAG_NONE, - D3D12_HEAP_TYPE_UPLOAD}; + const D3D12MA::ALLOCATION_DESC cpu_ad = {D3D12MA::ALLOCATION_FLAG_NONE, D3D12_HEAP_TYPE_UPLOAD}; ComPtr cpu_buffer; ComPtr cpu_allocation; - HRESULT hr = m_allocator->CreateResource(&cpu_ad, &rd, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, - cpu_allocation.put(), IID_PPV_ARGS(cpu_buffer.put())); + HRESULT hr = m_allocator->CreateResource( + &cpu_ad, &rd, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, cpu_allocation.put(), IID_PPV_ARGS(cpu_buffer.put())); pxAssertMsg(SUCCEEDED(hr), "Allocate CPU buffer"); if (FAILED(hr)) return false; @@ -697,12 +644,10 @@ bool Context::AllocatePreinitializedGPUBuffer(u32 size, ID3D12Resource** gpu_buf fill_callback(mapped); cpu_buffer->Unmap(0, &write_range); - const D3D12MA::ALLOCATION_DESC gpu_ad = { - D3D12MA::ALLOCATION_FLAG_COMMITTED, - D3D12_HEAP_TYPE_DEFAULT}; + const D3D12MA::ALLOCATION_DESC gpu_ad = {D3D12MA::ALLOCATION_FLAG_COMMITTED, D3D12_HEAP_TYPE_DEFAULT}; - hr = m_allocator->CreateResource(&gpu_ad, &rd, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, - gpu_allocation, IID_PPV_ARGS(gpu_buffer)); + hr = m_allocator->CreateResource( + &gpu_ad, &rd, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, gpu_allocation, IID_PPV_ARGS(gpu_buffer)); pxAssertMsg(SUCCEEDED(hr), "Allocate GPU buffer"); if (FAILED(hr)) return false; @@ -719,3 +664,59 @@ bool Context::AllocatePreinitializedGPUBuffer(u32 size, ID3D12Resource** gpu_buf DeferResourceDestruction(cpu_allocation.get(), cpu_buffer.get()); return true; } + +u32 D3D12::GetTexelSize(DXGI_FORMAT format) +{ + switch (format) + { + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC7_UNORM: + return 16; + + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + return 4; + + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_R32_UINT: + case DXGI_FORMAT_R32_SINT: + return 4; + + case DXGI_FORMAT_B5G5R5A1_UNORM: + case DXGI_FORMAT_B5G6R5_UNORM: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_SINT: + return 2; + + case DXGI_FORMAT_A8_UNORM: + case DXGI_FORMAT_R8_UNORM: + return 1; + + default: + pxFailRel("Unknown format"); + return 1; + } +} + +#ifdef _DEBUG + +void D3D12::SetObjectName(ID3D12Object* object, const char* name) +{ + object->SetName(StringUtil::UTF8StringToWideString(name).c_str()); +} + +void D3D12::SetObjectNameFormatted(ID3D12Object* object, const char* format, ...) +{ + std::va_list ap; + va_start(ap, format); + SetObjectName(object, StringUtil::StdStringFromFormatV(format, ap).c_str()); + va_end(ap); +} + +#endif diff --git a/pcsx2/GS/Renderers/DX12/D3D12Context.h b/pcsx2/GS/Renderers/DX12/D3D12Context.h new file mode 100644 index 0000000000..a0fd7f42f7 --- /dev/null +++ b/pcsx2/GS/Renderers/DX12/D3D12Context.h @@ -0,0 +1,237 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2023 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#pragma once + +#include "common/Pcsx2Defs.h" +#include "common/RedtapeWindows.h" +#include "GS/Renderers/DX12/D3D12DescriptorHeapManager.h" +#include "GS/Renderers/DX12/D3D12StreamBuffer.h" + +#include +#include +#include +#include +#include +#include + +struct IDXGIAdapter; +struct IDXGIFactory; +namespace D3D12MA +{ + class Allocator; + class Allocation; +} // namespace D3D12MA + +class D3D12Context +{ +public: + template + using ComPtr = wil::com_ptr_nothrow; + + enum : u32 + { + /// Number of command lists. One is being built while the other(s) are executed. + NUM_COMMAND_LISTS = 3, + + /// Textures that don't fit into this buffer will be uploaded with a staging buffer. + TEXTURE_UPLOAD_BUFFER_SIZE = 64 * 1024 * 1024, + + /// Maximum number of samples in a single allocation group. + SAMPLER_GROUP_SIZE = 2, + + /// Start/End timestamp queries. + NUM_TIMESTAMP_QUERIES_PER_CMDLIST = 2, + }; + + ~D3D12Context(); + + /// Creates new device and context. + static bool Create(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool enable_debug_layer); + + /// Destroys active context. + static void Destroy(); + + __fi IDXGIAdapter* GetAdapter() const { return m_adapter.get(); } + __fi ID3D12Device* GetDevice() const { return m_device.get(); } + __fi ID3D12CommandQueue* GetCommandQueue() const { return m_command_queue.get(); } + __fi D3D12MA::Allocator* GetAllocator() const { return m_allocator.get(); } + + /// Returns the PCI vendor ID of the device, if known. + u32 GetAdapterVendorID() const; + + /// Returns the current command list, commands can be recorded directly. + ID3D12GraphicsCommandList4* GetCommandList() const + { + return m_command_lists[m_current_command_list].command_lists[1].get(); + } + + /// Returns the init command list for uploading. + ID3D12GraphicsCommandList4* GetInitCommandList(); + + /// Returns the per-frame SRV/CBV/UAV allocator. + D3D12DescriptorAllocator& GetDescriptorAllocator() + { + return m_command_lists[m_current_command_list].descriptor_allocator; + } + + /// Returns the per-frame sampler allocator. + D3D12GroupedSamplerAllocator& GetSamplerAllocator() + { + return m_command_lists[m_current_command_list].sampler_allocator; + } + + /// Invalidates GPU-side sampler caches for all command lists. Call after you've freed samplers, + /// and are going to re-use the handles from GetSamplerHeapManager(). + void InvalidateSamplerGroups(); + + // Descriptor manager access. + D3D12DescriptorHeapManager& GetDescriptorHeapManager() { return m_descriptor_heap_manager; } + D3D12DescriptorHeapManager& GetRTVHeapManager() { return m_rtv_heap_manager; } + D3D12DescriptorHeapManager& GetDSVHeapManager() { return m_dsv_heap_manager; } + D3D12DescriptorHeapManager& GetSamplerHeapManager() { return m_sampler_heap_manager; } + const D3D12DescriptorHandle& GetNullSRVDescriptor() const { return m_null_srv_descriptor; } + D3D12StreamBuffer& GetTextureStreamBuffer() { return m_texture_stream_buffer; } + + // Root signature access. + ComPtr SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc); + ComPtr CreateRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc); + + /// Fence value for current command list. + u64 GetCurrentFenceValue() const { return m_current_fence_value; } + + /// Last "completed" fence. + u64 GetCompletedFenceValue() const { return m_completed_fence_value; } + + /// Feature level to use when compiling shaders. + D3D_FEATURE_LEVEL GetFeatureLevel() const { return m_feature_level; } + + /// Test for support for the specified texture format. + bool SupportsTextureFormat(DXGI_FORMAT format); + + enum class WaitType + { + None, ///< Don't wait (async) + Sleep, ///< Wait normally + Spin, ///< Wait by spinning + }; + + /// Executes the current command list. + bool ExecuteCommandList(WaitType wait_for_completion); + + /// Waits for a specific fence. + void WaitForFence(u64 fence, bool spin); + + /// Waits for any in-flight command buffers to complete. + void WaitForGPUIdle(); + + /// Defers destruction of a D3D resource (associates it with the current list). + void DeferObjectDestruction(ID3D12DeviceChild* resource); + + /// Defers destruction of a D3D resource (associates it with the current list). + void DeferResourceDestruction(D3D12MA::Allocation* allocation, ID3D12Resource* resource); + + /// Defers destruction of a descriptor handle (associates it with the current list). + void DeferDescriptorDestruction(D3D12DescriptorHeapManager& manager, u32 index); + void DeferDescriptorDestruction(D3D12DescriptorHeapManager& manager, D3D12DescriptorHandle* handle); + + float GetAndResetAccumulatedGPUTime(); + void SetEnableGPUTiming(bool enabled); + + // Allocates a temporary CPU staging buffer, fires the callback with it to populate, then copies to a GPU buffer. + bool AllocatePreinitializedGPUBuffer(u32 size, ID3D12Resource** gpu_buffer, D3D12MA::Allocation** gpu_allocation, + const std::function& fill_callback); + +private: + struct CommandListResources + { + std::array, 2> command_allocators; + std::array, 2> command_lists; + D3D12DescriptorAllocator descriptor_allocator; + D3D12GroupedSamplerAllocator sampler_allocator; + std::vector> pending_resources; + std::vector> pending_descriptors; + u64 ready_fence_value = 0; + bool init_command_list_used = false; + bool has_timestamp_query = false; + }; + + D3D12Context(); + + bool CreateDevice(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool enable_debug_layer); + bool CreateCommandQueue(); + bool CreateAllocator(); + bool CreateFence(); + bool CreateDescriptorHeaps(); + bool CreateCommandLists(); + bool CreateTextureStreamBuffer(); + bool CreateTimestampQuery(); + void MoveToNextCommandList(); + void DestroyPendingResources(CommandListResources& cmdlist); + void DestroyResources(); + + ComPtr m_adapter; + ComPtr m_debug_interface; + ComPtr m_device; + ComPtr m_command_queue; + ComPtr m_allocator; + + ComPtr m_fence; + HANDLE m_fence_event = {}; + u32 m_current_fence_value = 0; + u64 m_completed_fence_value = 0; + + std::array m_command_lists; + u32 m_current_command_list = NUM_COMMAND_LISTS - 1; + + ComPtr m_timestamp_query_heap; + ComPtr m_timestamp_query_buffer; + ComPtr m_timestamp_query_allocation; + double m_timestamp_frequency = 0.0; + float m_accumulated_gpu_time = 0.0f; + bool m_gpu_timing_enabled = false; + + D3D12DescriptorHeapManager m_descriptor_heap_manager; + D3D12DescriptorHeapManager m_rtv_heap_manager; + D3D12DescriptorHeapManager m_dsv_heap_manager; + D3D12DescriptorHeapManager m_sampler_heap_manager; + D3D12DescriptorHandle m_null_srv_descriptor; + D3D12StreamBuffer m_texture_stream_buffer; + + D3D_FEATURE_LEVEL m_feature_level = D3D_FEATURE_LEVEL_11_0; +}; + +extern std::unique_ptr g_d3d12_context; + +namespace D3D12 +{ + u32 GetTexelSize(DXGI_FORMAT format); + +#ifdef _DEBUG + + void SetObjectName(ID3D12Object* object, const char* name); + void SetObjectNameFormatted(ID3D12Object* object, const char* format, ...); + +#else + + static inline void SetObjectName(ID3D12Object* object, const char* name) + { + } + static inline void SetObjectNameFormatted(ID3D12Object* object, const char* format, ...) + { + } + +#endif +} // namespace D3D12 diff --git a/common/D3D12/DescriptorHeapManager.cpp b/pcsx2/GS/Renderers/DX12/D3D12DescriptorHeapManager.cpp similarity index 69% rename from common/D3D12/DescriptorHeapManager.cpp rename to pcsx2/GS/Renderers/DX12/D3D12DescriptorHeapManager.cpp index 36b96f3b99..d75b2ef606 100644 --- a/common/D3D12/DescriptorHeapManager.cpp +++ b/pcsx2/GS/Renderers/DX12/D3D12DescriptorHeapManager.cpp @@ -1,5 +1,5 @@ /* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2022 PCSX2 Dev Team + * Copyright (C) 2002-2023 PCSX2 Dev Team * * PCSX2 is free software: you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Found- @@ -13,22 +13,19 @@ * If not, see . */ -#include "common/PrecompiledHeader.h" +#include "PrecompiledHeader.h" -#include "common/D3D12/DescriptorHeapManager.h" +#include "GS/Renderers/DX12/D3D12DescriptorHeapManager.h" #include "common/Assertions.h" -using namespace D3D12; +D3D12DescriptorHeapManager::D3D12DescriptorHeapManager() = default; +D3D12DescriptorHeapManager::~D3D12DescriptorHeapManager() = default; -DescriptorHeapManager::DescriptorHeapManager() = default; -DescriptorHeapManager::~DescriptorHeapManager() = default; - -bool DescriptorHeapManager::Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, u32 num_descriptors, - bool shader_visible) +bool D3D12DescriptorHeapManager::Create( + ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, u32 num_descriptors, bool shader_visible) { D3D12_DESCRIPTOR_HEAP_DESC desc = {type, static_cast(num_descriptors), - shader_visible ? D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE : - D3D12_DESCRIPTOR_HEAP_FLAG_NONE}; + shader_visible ? D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE : D3D12_DESCRIPTOR_HEAP_FLAG_NONE}; HRESULT hr = device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(m_descriptor_heap.put())); pxAssertRel(SUCCEEDED(hr), "Create descriptor heap"); @@ -52,7 +49,7 @@ bool DescriptorHeapManager::Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_T return true; } -void DescriptorHeapManager::Destroy() +void D3D12DescriptorHeapManager::Destroy() { for (BitSetType& bs : m_free_slots) { @@ -68,7 +65,7 @@ void DescriptorHeapManager::Destroy() m_free_slots.clear(); } -bool DescriptorHeapManager::Allocate(DescriptorHandle* handle) +bool D3D12DescriptorHeapManager::Allocate(D3D12DescriptorHandle* handle) { // Start past the temporary slots, no point in searching those. for (u32 group = 0; group < m_free_slots.size(); group++) @@ -97,7 +94,7 @@ bool DescriptorHeapManager::Allocate(DescriptorHandle* handle) return false; } -void DescriptorHeapManager::Free(u32 index) +void D3D12DescriptorHeapManager::Free(u32 index) { pxAssert(index < m_num_descriptors); @@ -106,23 +103,22 @@ void DescriptorHeapManager::Free(u32 index) m_free_slots[group][bit] = true; } -void DescriptorHeapManager::Free(DescriptorHandle* handle) +void D3D12DescriptorHeapManager::Free(D3D12DescriptorHandle* handle) { - if (handle->index == DescriptorHandle::INVALID_INDEX) + if (handle->index == D3D12DescriptorHandle::INVALID_INDEX) return; Free(handle->index); handle->Clear(); } -DescriptorAllocator::DescriptorAllocator() = default; -DescriptorAllocator::~DescriptorAllocator() = default; +D3D12DescriptorAllocator::D3D12DescriptorAllocator() = default; +D3D12DescriptorAllocator::~D3D12DescriptorAllocator() = default; -bool DescriptorAllocator::Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, - u32 num_descriptors) +bool D3D12DescriptorAllocator::Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, u32 num_descriptors) { - const D3D12_DESCRIPTOR_HEAP_DESC desc = {type, static_cast(num_descriptors), - D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE}; + const D3D12_DESCRIPTOR_HEAP_DESC desc = { + type, static_cast(num_descriptors), D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE}; const HRESULT hr = device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&m_descriptor_heap)); pxAssertRel(SUCCEEDED(hr), "Creating descriptor heap for linear allocator"); if (FAILED(hr)) @@ -135,7 +131,7 @@ bool DescriptorAllocator::Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYP return true; } -void DescriptorAllocator::Destroy() +void D3D12DescriptorAllocator::Destroy() { m_descriptor_heap.reset(); m_descriptor_increment_size = 0; @@ -145,21 +141,19 @@ void DescriptorAllocator::Destroy() m_heap_base_gpu = {}; } -bool DescriptorAllocator::Allocate(u32 num_handles, DescriptorHandle* out_base_handle) +bool D3D12DescriptorAllocator::Allocate(u32 num_handles, D3D12DescriptorHandle* out_base_handle) { if ((m_current_offset + num_handles) > m_num_descriptors) return false; out_base_handle->index = m_current_offset; - out_base_handle->cpu_handle.ptr = - m_heap_base_cpu.ptr + m_current_offset * m_descriptor_increment_size; - out_base_handle->gpu_handle.ptr = - m_heap_base_gpu.ptr + m_current_offset * m_descriptor_increment_size; + out_base_handle->cpu_handle.ptr = m_heap_base_cpu.ptr + m_current_offset * m_descriptor_increment_size; + out_base_handle->gpu_handle.ptr = m_heap_base_gpu.ptr + m_current_offset * m_descriptor_increment_size; m_current_offset += num_handles; return true; } -void DescriptorAllocator::Reset() +void D3D12DescriptorAllocator::Reset() { m_current_offset = 0; -} \ No newline at end of file +} diff --git a/pcsx2/GS/Renderers/DX12/D3D12DescriptorHeapManager.h b/pcsx2/GS/Renderers/DX12/D3D12DescriptorHeapManager.h new file mode 100644 index 0000000000..cd550858e0 --- /dev/null +++ b/pcsx2/GS/Renderers/DX12/D3D12DescriptorHeapManager.h @@ -0,0 +1,263 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2023 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#pragma once + +#include "common/Pcsx2Defs.h" +#include "common/HashCombine.h" +#include "common/RedtapeWindows.h" +#include "common/RedtapeWilCom.h" + +#include +#include +#include +#include +#include + +// This class provides an abstraction for D3D12 descriptor heaps. +struct D3D12DescriptorHandle final +{ + enum : u32 + { + INVALID_INDEX = 0xFFFFFFFF + }; + + D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle{}; + D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle{}; + u32 index = INVALID_INDEX; + + __fi operator bool() const { return index != INVALID_INDEX; } + + __fi operator D3D12_CPU_DESCRIPTOR_HANDLE() const { return cpu_handle; } + __fi operator D3D12_GPU_DESCRIPTOR_HANDLE() const { return gpu_handle; } + + __fi bool operator==(const D3D12DescriptorHandle& rhs) const { return (index == rhs.index); } + __fi bool operator!=(const D3D12DescriptorHandle& rhs) const { return (index != rhs.index); } + __fi bool operator<(const D3D12DescriptorHandle& rhs) const { return (index < rhs.index); } + __fi bool operator<=(const D3D12DescriptorHandle& rhs) const { return (index <= rhs.index); } + __fi bool operator>(const D3D12DescriptorHandle& rhs) const { return (index > rhs.index); } + __fi bool operator>=(const D3D12DescriptorHandle& rhs) const { return (index >= rhs.index); } + + __fi void Clear() + { + cpu_handle = {}; + gpu_handle = {}; + index = INVALID_INDEX; + } +}; + +class D3D12DescriptorHeapManager final +{ +public: + D3D12DescriptorHeapManager(); + ~D3D12DescriptorHeapManager(); + + ID3D12DescriptorHeap* GetDescriptorHeap() const { return m_descriptor_heap.get(); } + u32 GetDescriptorIncrementSize() const { return m_descriptor_increment_size; } + + bool Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, u32 num_descriptors, bool shader_visible); + void Destroy(); + + bool Allocate(D3D12DescriptorHandle* handle); + void Free(D3D12DescriptorHandle* handle); + void Free(u32 index); + +private: + wil::com_ptr_nothrow m_descriptor_heap; + u32 m_num_descriptors = 0; + u32 m_descriptor_increment_size = 0; + bool m_shader_visible = false; + + D3D12_CPU_DESCRIPTOR_HANDLE m_heap_base_cpu = {}; + D3D12_GPU_DESCRIPTOR_HANDLE m_heap_base_gpu = {}; + + static constexpr u32 BITSET_SIZE = 1024; + using BitSetType = std::bitset; + std::vector m_free_slots = {}; +}; + +class D3D12DescriptorAllocator +{ +public: + D3D12DescriptorAllocator(); + ~D3D12DescriptorAllocator(); + + __fi ID3D12DescriptorHeap* GetDescriptorHeap() const { return m_descriptor_heap.get(); } + __fi u32 GetDescriptorIncrementSize() const { return m_descriptor_increment_size; } + + bool Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, u32 num_descriptors); + void Destroy(); + + bool Allocate(u32 num_handles, D3D12DescriptorHandle* out_base_handle); + void Reset(); + +private: + wil::com_ptr_nothrow m_descriptor_heap; + u32 m_descriptor_increment_size = 0; + u32 m_num_descriptors = 0; + u32 m_current_offset = 0; + + D3D12_CPU_DESCRIPTOR_HANDLE m_heap_base_cpu = {}; + D3D12_GPU_DESCRIPTOR_HANDLE m_heap_base_gpu = {}; +}; + +template +class D3D12GroupedSamplerAllocator : private D3D12DescriptorAllocator +{ + struct Key + { + u32 idx[NumSamplers]; + + __fi bool operator==(const Key& rhs) const { return (std::memcmp(idx, rhs.idx, sizeof(idx)) == 0); } + __fi bool operator!=(const Key& rhs) const { return (std::memcmp(idx, rhs.idx, sizeof(idx)) != 0); } + }; + + struct KeyHash + { + __fi std::size_t operator()(const Key& key) const + { + size_t seed = 0; + for (u32 key : key.idx) + HashCombine(seed, key); + return seed; + } + }; + + +public: + D3D12GroupedSamplerAllocator(); + ~D3D12GroupedSamplerAllocator(); + + using D3D12DescriptorAllocator::GetDescriptorHeap; + using D3D12DescriptorAllocator::GetDescriptorIncrementSize; + + bool Create(ID3D12Device* device, u32 num_descriptors); + void Destroy(); + + bool LookupSingle(D3D12DescriptorHandle* gpu_handle, const D3D12DescriptorHandle& cpu_handle); + bool LookupGroup(D3D12DescriptorHandle* gpu_handle, const D3D12DescriptorHandle* cpu_handles); + + // Clears cache but doesn't reset allocator. + void InvalidateCache(); + + void Reset(); + bool ShouldReset() const; + +private: + wil::com_ptr_nothrow m_device; + std::unordered_map m_groups; +}; + +template +D3D12GroupedSamplerAllocator::D3D12GroupedSamplerAllocator() = default; + +template +D3D12GroupedSamplerAllocator::~D3D12GroupedSamplerAllocator() = default; + +template +bool D3D12GroupedSamplerAllocator::Create(ID3D12Device* device, u32 num_descriptors) +{ + if (!D3D12DescriptorAllocator::Create(device, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, num_descriptors)) + return false; + + m_device = device; + return true; +} + +template +void D3D12GroupedSamplerAllocator::Destroy() +{ + D3D12DescriptorAllocator::Destroy(); + m_device.reset(); +} + +template +void D3D12GroupedSamplerAllocator::Reset() +{ + m_groups.clear(); + D3D12DescriptorAllocator::Reset(); +} + +template +void D3D12GroupedSamplerAllocator::InvalidateCache() +{ + m_groups.clear(); +} + +template +bool D3D12GroupedSamplerAllocator::LookupSingle( + D3D12DescriptorHandle* gpu_handle, const D3D12DescriptorHandle& cpu_handle) +{ + Key key; + key.idx[0] = cpu_handle.index; + for (u32 i = 1; i < NumSamplers; i++) + key.idx[i] = 0; + + auto it = m_groups.find(key); + if (it != m_groups.end()) + { + *gpu_handle = it->second; + return true; + } + + if (!Allocate(1, gpu_handle)) + return false; + + m_device->CopyDescriptorsSimple(1, *gpu_handle, cpu_handle, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); + m_groups.emplace(key, *gpu_handle); + return true; +} + +template +bool D3D12GroupedSamplerAllocator::LookupGroup( + D3D12DescriptorHandle* gpu_handle, const D3D12DescriptorHandle* cpu_handles) +{ + Key key; + for (u32 i = 0; i < NumSamplers; i++) + key.idx[i] = cpu_handles[i].index; + + auto it = m_groups.find(key); + if (it != m_groups.end()) + { + *gpu_handle = it->second; + return true; + } + + if (!Allocate(NumSamplers, gpu_handle)) + return false; + + D3D12_CPU_DESCRIPTOR_HANDLE dst_handle = *gpu_handle; + UINT dst_size = NumSamplers; + D3D12_CPU_DESCRIPTOR_HANDLE src_handles[NumSamplers]; + UINT src_sizes[NumSamplers]; + for (u32 i = 0; i < NumSamplers; i++) + { + src_handles[i] = cpu_handles[i]; + src_sizes[i] = 1; + } + m_device->CopyDescriptors( + 1, &dst_handle, &dst_size, NumSamplers, src_handles, src_sizes, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); + + m_groups.emplace(key, *gpu_handle); + return true; +} + +template +bool D3D12GroupedSamplerAllocator::ShouldReset() const +{ + // We only reset the sampler heap if more than half of the descriptors are used. + // This saves descriptor copying when there isn't a large number of sampler configs per frame. + return m_groups.size() >= (D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE / 2); +} diff --git a/common/D3D12/ShaderCache.cpp b/pcsx2/GS/Renderers/DX12/D3D12ShaderCache.cpp similarity index 77% rename from common/D3D12/ShaderCache.cpp rename to pcsx2/GS/Renderers/DX12/D3D12ShaderCache.cpp index 926d826a1c..8846678aae 100644 --- a/common/D3D12/ShaderCache.cpp +++ b/pcsx2/GS/Renderers/DX12/D3D12ShaderCache.cpp @@ -1,5 +1,5 @@ /* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2022 PCSX2 Dev Team + * Copyright (C) 2002-2023 PCSX2 Dev Team * * PCSX2 is free software: you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Found- @@ -13,18 +13,22 @@ * If not, see . */ -#include "common/PrecompiledHeader.h" +#include "PrecompiledHeader.h" + +#include "GS/Renderers/DX12/D3D12ShaderCache.h" +#include "GS/Renderers/DX11/D3D.h" +#include "GS/GS.h" + +#include "Config.h" +#include "ShaderCacheVersion.h" -#include "common/D3D12/ShaderCache.h" -#include "common/D3D11/ShaderCompiler.h" #include "common/FileSystem.h" #include "common/Console.h" #include "common/MD5Digest.h" +#include "common/Path.h" #include -using namespace D3D12; - #pragma pack(push, 1) struct CacheIndexEntry { @@ -41,60 +45,59 @@ struct CacheIndexEntry }; #pragma pack(pop) -ShaderCache::ShaderCache() = default; +D3D12ShaderCache::D3D12ShaderCache() = default; -ShaderCache::~ShaderCache() +D3D12ShaderCache::~D3D12ShaderCache() { Close(); } -bool ShaderCache::CacheIndexKey::operator==(const CacheIndexKey& key) const +bool D3D12ShaderCache::CacheIndexKey::operator==(const CacheIndexKey& key) const { return (source_hash_low == key.source_hash_low && source_hash_high == key.source_hash_high && macro_hash_low == key.macro_hash_low && macro_hash_high == key.macro_hash_high && - entry_point_low == key.entry_point_low && entry_point_high == key.entry_point_high && - type == key.type && source_length == key.source_length); + entry_point_low == key.entry_point_low && entry_point_high == key.entry_point_high && type == key.type && + source_length == key.source_length); } -bool ShaderCache::CacheIndexKey::operator!=(const CacheIndexKey& key) const +bool D3D12ShaderCache::CacheIndexKey::operator!=(const CacheIndexKey& key) const { return (source_hash_low != key.source_hash_low || source_hash_high != key.source_hash_high || macro_hash_low != key.macro_hash_low || macro_hash_high != key.macro_hash_high || - entry_point_low != key.entry_point_low || entry_point_high != key.entry_point_high || - type != key.type || source_length != key.source_length); + entry_point_low != key.entry_point_low || entry_point_high != key.entry_point_high || type != key.type || + source_length != key.source_length); } -bool ShaderCache::Open(std::string_view base_path, D3D_FEATURE_LEVEL feature_level, u32 version, bool debug) +bool D3D12ShaderCache::Open(D3D_FEATURE_LEVEL feature_level, bool debug) { - m_base_path = base_path; m_feature_level = feature_level; - m_data_version = version; m_debug = debug; bool result = true; - if (!base_path.empty()) + if (!GSConfig.DisableShaderCache) { - const std::string base_shader_filename = GetCacheBaseFileName(base_path, "shaders", feature_level, debug); + const std::string base_shader_filename = GetCacheBaseFileName("shaders", feature_level, debug); const std::string shader_index_filename = base_shader_filename + ".idx"; const std::string shader_blob_filename = base_shader_filename + ".bin"; - if (!ReadExisting(shader_index_filename, shader_blob_filename, m_shader_index_file, m_shader_blob_file, - m_shader_index)) + if (!ReadExisting( + shader_index_filename, shader_blob_filename, m_shader_index_file, m_shader_blob_file, m_shader_index)) { result = CreateNew(shader_index_filename, shader_blob_filename, m_shader_index_file, m_shader_blob_file); } if (result) { - const std::string base_pipelines_filename = GetCacheBaseFileName(base_path, "pipelines", feature_level, debug); + const std::string base_pipelines_filename = GetCacheBaseFileName("pipelines", feature_level, debug); const std::string pipelines_index_filename = base_pipelines_filename + ".idx"; const std::string pipelines_blob_filename = base_pipelines_filename + ".bin"; - if (!ReadExisting(pipelines_index_filename, pipelines_blob_filename, m_pipeline_index_file, m_pipeline_blob_file, - m_pipeline_index)) + if (!ReadExisting(pipelines_index_filename, pipelines_blob_filename, m_pipeline_index_file, + m_pipeline_blob_file, m_pipeline_index)) { - result = CreateNew(pipelines_index_filename, pipelines_blob_filename, m_pipeline_index_file, m_pipeline_blob_file); + result = CreateNew( + pipelines_index_filename, pipelines_blob_filename, m_pipeline_index_file, m_pipeline_blob_file); } } } @@ -102,7 +105,7 @@ bool ShaderCache::Open(std::string_view base_path, D3D_FEATURE_LEVEL feature_lev return result; } -void ShaderCache::Close() +void D3D12ShaderCache::Close() { if (m_pipeline_index_file) { @@ -124,11 +127,9 @@ void ShaderCache::Close() std::fclose(m_shader_blob_file); m_shader_blob_file = nullptr; } - - m_base_path = {}; } -void ShaderCache::InvalidatePipelineCache() +void D3D12ShaderCache::InvalidatePipelineCache() { m_pipeline_index.clear(); if (m_pipeline_blob_file) @@ -143,15 +144,17 @@ void ShaderCache::InvalidatePipelineCache() m_pipeline_index_file = nullptr; } - const std::string base_pipelines_filename = - GetCacheBaseFileName(m_base_path, "pipelines", m_feature_level, m_debug); + if (GSConfig.DisableShaderCache) + return; + + const std::string base_pipelines_filename = GetCacheBaseFileName("pipelines", m_feature_level, m_debug); const std::string pipelines_index_filename = base_pipelines_filename + ".idx"; const std::string pipelines_blob_filename = base_pipelines_filename + ".bin"; CreateNew(pipelines_index_filename, pipelines_blob_filename, m_pipeline_index_file, m_pipeline_blob_file); } -bool ShaderCache::CreateNew(const std::string& index_filename, const std::string& blob_filename, std::FILE*& index_file, - std::FILE*& blob_file) +bool D3D12ShaderCache::CreateNew( + const std::string& index_filename, const std::string& blob_filename, std::FILE*& index_file, std::FILE*& blob_file) { if (FileSystem::FileExists(index_filename.c_str())) { @@ -171,9 +174,8 @@ bool ShaderCache::CreateNew(const std::string& index_filename, const std::string return false; } - const u32 index_version = FILE_VERSION; - if (std::fwrite(&index_version, sizeof(index_version), 1, index_file) != 1 || - std::fwrite(&m_data_version, sizeof(m_data_version), 1, index_file) != 1) + const u32 file_version = SHADER_CACHE_VERSION; + if (std::fwrite(&file_version, sizeof(file_version), 1, index_file) != 1) { Console.Error("Failed to write version to index file '%s'", index_filename.c_str()); std::fclose(index_file); @@ -195,7 +197,7 @@ bool ShaderCache::CreateNew(const std::string& index_filename, const std::string return true; } -bool ShaderCache::ReadExisting(const std::string& index_filename, const std::string& blob_filename, +bool D3D12ShaderCache::ReadExisting(const std::string& index_filename, const std::string& blob_filename, std::FILE*& index_file, std::FILE*& blob_file, CacheIndex& index) { index_file = FileSystem::OpenCFile(index_filename.c_str(), "r+b"); @@ -213,9 +215,7 @@ bool ShaderCache::ReadExisting(const std::string& index_filename, const std::str } u32 file_version; - u32 data_version; - if (std::fread(&file_version, sizeof(file_version), 1, index_file) != 1 || file_version != FILE_VERSION || - std::fread(&data_version, sizeof(data_version), 1, index_file) != 1 || data_version != m_data_version) + if (std::fread(&file_version, sizeof(file_version), 1, index_file) != 1 || file_version != SHADER_CACHE_VERSION) { Console.Error("Bad file version in '%s'", index_filename.c_str()); std::fclose(index_file); @@ -238,7 +238,8 @@ bool ShaderCache::ReadExisting(const std::string& index_filename, const std::str for (;;) { CacheIndexEntry entry; - if (std::fread(&entry, sizeof(entry), 1, index_file) != 1 || (entry.file_offset + entry.blob_size) > blob_file_size) + if (std::fread(&entry, sizeof(entry), 1, index_file) != 1 || + (entry.file_offset + entry.blob_size) > blob_file_size) { if (std::feof(index_file)) break; @@ -252,11 +253,9 @@ bool ShaderCache::ReadExisting(const std::string& index_filename, const std::str return false; } - const CacheIndexKey key{ - entry.source_hash_low, entry.source_hash_high, - entry.macro_hash_low, entry.macro_hash_high, - entry.entry_point_low, entry.entry_point_high, - entry.source_length, static_cast(entry.shader_type)}; + const CacheIndexKey key{entry.source_hash_low, entry.source_hash_high, entry.macro_hash_low, + entry.macro_hash_high, entry.entry_point_low, entry.entry_point_high, entry.source_length, + static_cast(entry.shader_type)}; const CacheIndexData data{entry.file_offset, entry.blob_size}; index.emplace(key, data); } @@ -268,11 +267,9 @@ bool ShaderCache::ReadExisting(const std::string& index_filename, const std::str return true; } -std::string ShaderCache::GetCacheBaseFileName(const std::string_view& base_path, const std::string_view& type, - D3D_FEATURE_LEVEL feature_level, bool debug) +std::string D3D12ShaderCache::GetCacheBaseFileName(const std::string_view& type, D3D_FEATURE_LEVEL feature_level, bool debug) { - std::string base_filename(base_path); - base_filename += FS_OSPATH_SEPARATOR_STR "d3d12_"; + std::string base_filename = "d3d12_"; base_filename += type; base_filename += "_"; @@ -295,7 +292,7 @@ std::string ShaderCache::GetCacheBaseFileName(const std::string_view& base_path, if (debug) base_filename += "_debug"; - return base_filename; + return Path::Combine(EmuFolders::Cache, base_filename); } union MD5Hash @@ -308,8 +305,8 @@ union MD5Hash u8 hash[16]; }; -ShaderCache::CacheIndexKey ShaderCache::GetShaderCacheKey(EntryType type, const std::string_view& shader_code, - const D3D_SHADER_MACRO* macros, const char* entry_point) +D3D12ShaderCache::CacheIndexKey D3D12ShaderCache::GetShaderCacheKey( + EntryType type, const std::string_view& shader_code, const D3D_SHADER_MACRO* macros, const char* entry_point) { union { @@ -353,7 +350,7 @@ ShaderCache::CacheIndexKey ShaderCache::GetShaderCacheKey(EntryType type, const return key; } -ShaderCache::CacheIndexKey ShaderCache::GetPipelineCacheKey(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& gpdesc) +D3D12ShaderCache::CacheIndexKey D3D12ShaderCache::GetPipelineCacheKey(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& gpdesc) { MD5Digest digest; u32 length = sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC); @@ -406,7 +403,7 @@ ShaderCache::CacheIndexKey ShaderCache::GetPipelineCacheKey(const D3D12_GRAPHICS return CacheIndexKey{h.low, h.high, 0, 0, 0, 0, length, EntryType::GraphicsPipeline}; } -ShaderCache::CacheIndexKey ShaderCache::GetPipelineCacheKey(const D3D12_COMPUTE_PIPELINE_STATE_DESC& gpdesc) +D3D12ShaderCache::CacheIndexKey D3D12ShaderCache::GetPipelineCacheKey(const D3D12_COMPUTE_PIPELINE_STATE_DESC& gpdesc) { MD5Digest digest; u32 length = sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC); @@ -423,7 +420,7 @@ ShaderCache::CacheIndexKey ShaderCache::GetPipelineCacheKey(const D3D12_COMPUTE_ return CacheIndexKey{h.low, h.high, 0, 0, 0, 0, length, EntryType::ComputePipeline}; } -ShaderCache::ComPtr ShaderCache::GetShaderBlob(EntryType type, std::string_view shader_code, +D3D12ShaderCache::ComPtr D3D12ShaderCache::GetShaderBlob(EntryType type, std::string_view shader_code, const D3D_SHADER_MACRO* macros /* = nullptr */, const char* entry_point /* = "main" */) { const auto key = GetShaderCacheKey(type, shader_code, macros, entry_point); @@ -443,8 +440,8 @@ ShaderCache::ComPtr ShaderCache::GetShaderBlob(EntryType type, std::st return blob; } -ShaderCache::ComPtr ShaderCache::GetPipelineState(ID3D12Device* device, - const D3D12_GRAPHICS_PIPELINE_STATE_DESC& desc) +D3D12ShaderCache::ComPtr D3D12ShaderCache::GetPipelineState( + ID3D12Device* device, const D3D12_GRAPHICS_PIPELINE_STATE_DESC& desc) { const auto key = GetPipelineCacheKey(desc); @@ -477,8 +474,8 @@ ShaderCache::ComPtr ShaderCache::GetPipelineState(ID3D12Dev return pso; } -ShaderCache::ComPtr ShaderCache::GetPipelineState(ID3D12Device* device, - const D3D12_COMPUTE_PIPELINE_STATE_DESC& desc) +D3D12ShaderCache::ComPtr D3D12ShaderCache::GetPipelineState( + ID3D12Device* device, const D3D12_COMPUTE_PIPELINE_STATE_DESC& desc) { const auto key = GetPipelineCacheKey(desc); @@ -511,21 +508,24 @@ ShaderCache::ComPtr ShaderCache::GetPipelineState(ID3D12Dev return pso; } -ShaderCache::ComPtr ShaderCache::CompileAndAddShaderBlob(const CacheIndexKey& key, std::string_view shader_code, - const D3D_SHADER_MACRO* macros, const char* entry_point) +D3D12ShaderCache::ComPtr D3D12ShaderCache::CompileAndAddShaderBlob( + const CacheIndexKey& key, std::string_view shader_code, const D3D_SHADER_MACRO* macros, const char* entry_point) { ComPtr blob; switch (key.type) { case EntryType::VertexShader: - blob = D3D11::ShaderCompiler::CompileShader(D3D11::ShaderCompiler::Type::Vertex, m_feature_level, m_debug, shader_code, macros, entry_point); + blob = + D3D::CompileShader(D3D::ShaderType::Vertex, m_feature_level, m_debug, shader_code, macros, entry_point); break; case EntryType::PixelShader: - blob = D3D11::ShaderCompiler::CompileShader(D3D11::ShaderCompiler::Type::Pixel, m_feature_level, m_debug, shader_code, macros, entry_point); + blob = + D3D::CompileShader(D3D::ShaderType::Pixel, m_feature_level, m_debug, shader_code, macros, entry_point); break; case EntryType::ComputeShader: - blob = D3D11::ShaderCompiler::CompileShader(D3D11::ShaderCompiler::Type::Compute, m_feature_level, m_debug, shader_code, macros, entry_point); + blob = D3D::CompileShader( + D3D::ShaderType::Compute, m_feature_level, m_debug, shader_code, macros, entry_point); break; default: break; @@ -565,9 +565,8 @@ ShaderCache::ComPtr ShaderCache::CompileAndAddShaderBlob(const CacheIn return blob; } -ShaderCache::ComPtr -ShaderCache::CompileAndAddPipeline(ID3D12Device* device, const CacheIndexKey& key, - const D3D12_GRAPHICS_PIPELINE_STATE_DESC& gpdesc) +D3D12ShaderCache::ComPtr D3D12ShaderCache::CompileAndAddPipeline( + ID3D12Device* device, const CacheIndexKey& key, const D3D12_GRAPHICS_PIPELINE_STATE_DESC& gpdesc) { ComPtr pso; HRESULT hr = device->CreateGraphicsPipelineState(&gpdesc, IID_PPV_ARGS(pso.put())); @@ -581,9 +580,8 @@ ShaderCache::CompileAndAddPipeline(ID3D12Device* device, const CacheIndexKey& ke return pso; } -ShaderCache::ComPtr -ShaderCache::CompileAndAddPipeline(ID3D12Device* device, const CacheIndexKey& key, - const D3D12_COMPUTE_PIPELINE_STATE_DESC& gpdesc) +D3D12ShaderCache::ComPtr D3D12ShaderCache::CompileAndAddPipeline( + ID3D12Device* device, const CacheIndexKey& key, const D3D12_COMPUTE_PIPELINE_STATE_DESC& gpdesc) { ComPtr pso; HRESULT hr = device->CreateComputePipelineState(&gpdesc, IID_PPV_ARGS(pso.put())); @@ -597,7 +595,7 @@ ShaderCache::CompileAndAddPipeline(ID3D12Device* device, const CacheIndexKey& ke return pso; } -bool ShaderCache::AddPipelineToBlob(const CacheIndexKey& key, ID3D12PipelineState* pso) +bool D3D12ShaderCache::AddPipelineToBlob(const CacheIndexKey& key, ID3D12PipelineState* pso) { if (!m_pipeline_blob_file || std::fseek(m_pipeline_blob_file, 0, SEEK_END) != 0) return false; diff --git a/pcsx2/GS/Renderers/DX12/D3D12ShaderCache.h b/pcsx2/GS/Renderers/DX12/D3D12ShaderCache.h new file mode 100644 index 0000000000..6246d5481d --- /dev/null +++ b/pcsx2/GS/Renderers/DX12/D3D12ShaderCache.h @@ -0,0 +1,140 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2023 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#pragma once + +#include "common/Pcsx2Defs.h" +#include "common/HashCombine.h" +#include "common/RedtapeWindows.h" +#include "common/RedtapeWilCom.h" + +#include +#include +#include +#include +#include + +class D3D12ShaderCache +{ +public: + template + using ComPtr = wil::com_ptr_nothrow; + + enum class EntryType + { + VertexShader, + PixelShader, + ComputeShader, + GraphicsPipeline, + ComputePipeline, + }; + + D3D12ShaderCache(); + ~D3D12ShaderCache(); + + __fi D3D_FEATURE_LEVEL GetFeatureLevel() const { return m_feature_level; } + __fi bool UsingDebugShaders() const { return m_debug; } + + bool Open(D3D_FEATURE_LEVEL feature_level, bool debug); + void Close(); + + __fi ComPtr GetVertexShader( + std::string_view shader_code, const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main") + { + return GetShaderBlob(EntryType::VertexShader, shader_code, macros, entry_point); + } + __fi ComPtr GetPixelShader( + std::string_view shader_code, const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main") + { + return GetShaderBlob(EntryType::PixelShader, shader_code, macros, entry_point); + } + __fi ComPtr GetComputeShader( + std::string_view shader_code, const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main") + { + return GetShaderBlob(EntryType::ComputeShader, shader_code, macros, entry_point); + } + + ComPtr GetShaderBlob(EntryType type, std::string_view shader_code, + const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main"); + + ComPtr GetPipelineState(ID3D12Device* device, const D3D12_GRAPHICS_PIPELINE_STATE_DESC& desc); + ComPtr GetPipelineState(ID3D12Device* device, const D3D12_COMPUTE_PIPELINE_STATE_DESC& desc); + +private: + struct CacheIndexKey + { + u64 source_hash_low; + u64 source_hash_high; + u64 macro_hash_low; + u64 macro_hash_high; + u64 entry_point_low; + u64 entry_point_high; + u32 source_length; + EntryType type; + + bool operator==(const CacheIndexKey& key) const; + bool operator!=(const CacheIndexKey& key) const; + }; + + struct CacheIndexEntryHasher + { + std::size_t operator()(const CacheIndexKey& e) const noexcept + { + std::size_t h = 0; + HashCombine(h, e.entry_point_low, e.entry_point_high, e.macro_hash_low, e.macro_hash_high, + e.source_hash_low, e.source_hash_high, e.source_length, e.type); + return h; + } + }; + + struct CacheIndexData + { + u32 file_offset; + u32 blob_size; + }; + + using CacheIndex = std::unordered_map; + + static std::string GetCacheBaseFileName(const std::string_view& type, D3D_FEATURE_LEVEL feature_level, bool debug); + static CacheIndexKey GetShaderCacheKey( + EntryType type, const std::string_view& shader_code, const D3D_SHADER_MACRO* macros, const char* entry_point); + static CacheIndexKey GetPipelineCacheKey(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& gpdesc); + static CacheIndexKey GetPipelineCacheKey(const D3D12_COMPUTE_PIPELINE_STATE_DESC& gpdesc); + + bool CreateNew(const std::string& index_filename, const std::string& blob_filename, std::FILE*& index_file, + std::FILE*& blob_file); + bool ReadExisting(const std::string& index_filename, const std::string& blob_filename, std::FILE*& index_file, + std::FILE*& blob_file, CacheIndex& index); + void InvalidatePipelineCache(); + + ComPtr CompileAndAddShaderBlob(const CacheIndexKey& key, std::string_view shader_code, + const D3D_SHADER_MACRO* macros, const char* entry_point); + ComPtr CompileAndAddPipeline( + ID3D12Device* device, const CacheIndexKey& key, const D3D12_GRAPHICS_PIPELINE_STATE_DESC& gpdesc); + ComPtr CompileAndAddPipeline( + ID3D12Device* device, const CacheIndexKey& key, const D3D12_COMPUTE_PIPELINE_STATE_DESC& gpdesc); + bool AddPipelineToBlob(const CacheIndexKey& key, ID3D12PipelineState* pso); + + std::FILE* m_shader_index_file = nullptr; + std::FILE* m_shader_blob_file = nullptr; + CacheIndex m_shader_index; + + std::FILE* m_pipeline_index_file = nullptr; + std::FILE* m_pipeline_blob_file = nullptr; + CacheIndex m_pipeline_index; + + D3D_FEATURE_LEVEL m_feature_level = D3D_FEATURE_LEVEL_11_0; + bool m_debug = false; +}; diff --git a/common/D3D12/StreamBuffer.cpp b/pcsx2/GS/Renderers/DX12/D3D12StreamBuffer.cpp similarity index 88% rename from common/D3D12/StreamBuffer.cpp rename to pcsx2/GS/Renderers/DX12/D3D12StreamBuffer.cpp index 692e04c620..b232ad19a0 100644 --- a/common/D3D12/StreamBuffer.cpp +++ b/pcsx2/GS/Renderers/DX12/D3D12StreamBuffer.cpp @@ -1,5 +1,5 @@ /* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2022 PCSX2 Dev Team + * Copyright (C) 2002-2023 PCSX2 Dev Team * * PCSX2 is free software: you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Found- @@ -13,32 +13,31 @@ * If not, see . */ -#include "common/PrecompiledHeader.h" +#include "PrecompiledHeader.h" + +#include "GS/Renderers/DX12/D3D12StreamBuffer.h" +#include "GS/Renderers/DX12/D3D12Context.h" -#include "common/D3D12/StreamBuffer.h" -#include "common/D3D12/Context.h" #include "common/Align.h" #include "common/Assertions.h" #include "common/Console.h" + #include "D3D12MemAlloc.h" #include #include -using namespace D3D12; +D3D12StreamBuffer::D3D12StreamBuffer() = default; -StreamBuffer::StreamBuffer() = default; - -StreamBuffer::~StreamBuffer() +D3D12StreamBuffer::~D3D12StreamBuffer() { Destroy(); } -bool StreamBuffer::Create(u32 size) +bool D3D12StreamBuffer::Create(u32 size) { - const D3D12_RESOURCE_DESC resource_desc = { - D3D12_RESOURCE_DIMENSION_BUFFER, 0, size, 1, 1, 1, DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, - D3D12_RESOURCE_FLAG_NONE}; + const D3D12_RESOURCE_DESC resource_desc = {D3D12_RESOURCE_DIMENSION_BUFFER, 0, size, 1, 1, 1, DXGI_FORMAT_UNKNOWN, + {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE}; D3D12MA::ALLOCATION_DESC allocationDesc = {}; allocationDesc.Flags = D3D12MA::ALLOCATION_FLAG_COMMITTED; @@ -46,9 +45,8 @@ bool StreamBuffer::Create(u32 size) wil::com_ptr_nothrow buffer; wil::com_ptr_nothrow allocation; - HRESULT hr = g_d3d12_context->GetAllocator()->CreateResource(&allocationDesc, - &resource_desc, D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr, allocation.put(), IID_PPV_ARGS(buffer.put())); + HRESULT hr = g_d3d12_context->GetAllocator()->CreateResource(&allocationDesc, &resource_desc, + D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, allocation.put(), IID_PPV_ARGS(buffer.put())); pxAssertMsg(SUCCEEDED(hr), "Allocate buffer"); if (FAILED(hr)) return false; @@ -70,7 +68,7 @@ bool StreamBuffer::Create(u32 size) return true; } -bool StreamBuffer::ReserveMemory(u32 num_bytes, u32 alignment) +bool D3D12StreamBuffer::ReserveMemory(u32 num_bytes, u32 alignment) { const u32 required_bytes = num_bytes + alignment; @@ -139,7 +137,7 @@ bool StreamBuffer::ReserveMemory(u32 num_bytes, u32 alignment) return false; } -void StreamBuffer::CommitMemory(u32 final_num_bytes) +void D3D12StreamBuffer::CommitMemory(u32 final_num_bytes) { pxAssert((m_current_offset + final_num_bytes) <= m_size); pxAssert(final_num_bytes <= m_current_space); @@ -147,7 +145,7 @@ void StreamBuffer::CommitMemory(u32 final_num_bytes) m_current_space -= final_num_bytes; } -void StreamBuffer::Destroy(bool defer) +void D3D12StreamBuffer::Destroy(bool defer) { if (m_host_pointer) { @@ -167,7 +165,7 @@ void StreamBuffer::Destroy(bool defer) m_tracked_fences.clear(); } -void StreamBuffer::UpdateCurrentFencePosition() +void D3D12StreamBuffer::UpdateCurrentFencePosition() { // Don't create a tracking entry if the GPU is caught up with the buffer. if (m_current_offset == m_current_gpu_position) @@ -186,7 +184,7 @@ void StreamBuffer::UpdateCurrentFencePosition() m_tracked_fences.emplace_back(fence, m_current_offset); } -void StreamBuffer::UpdateGPUPosition() +void D3D12StreamBuffer::UpdateGPUPosition() { auto start = m_tracked_fences.begin(); auto end = start; @@ -202,7 +200,7 @@ void StreamBuffer::UpdateGPUPosition() m_tracked_fences.erase(start, end); } -bool StreamBuffer::WaitForClearSpace(u32 num_bytes) +bool D3D12StreamBuffer::WaitForClearSpace(u32 num_bytes) { u32 new_offset = 0; u32 new_space = 0; @@ -274,7 +272,8 @@ bool StreamBuffer::WaitForClearSpace(u32 num_bytes) // Wait until this fence is signaled. This will fire the callback, updating the GPU position. g_d3d12_context->WaitForFence(iter->first, false); - m_tracked_fences.erase(m_tracked_fences.begin(), m_current_offset == iter->second ? m_tracked_fences.end() : ++iter); + m_tracked_fences.erase( + m_tracked_fences.begin(), m_current_offset == iter->second ? m_tracked_fences.end() : ++iter); m_current_offset = new_offset; m_current_space = new_space; m_current_gpu_position = new_gpu_position; diff --git a/pcsx2/GS/Renderers/DX12/D3D12StreamBuffer.h b/pcsx2/GS/Renderers/DX12/D3D12StreamBuffer.h new file mode 100644 index 0000000000..24222f659c --- /dev/null +++ b/pcsx2/GS/Renderers/DX12/D3D12StreamBuffer.h @@ -0,0 +1,73 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2023 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#pragma once + +#include "common/Pcsx2Defs.h" +#include "common/RedtapeWindows.h" +#include "common/RedtapeWilCom.h" + +#include +#include +#include + +namespace D3D12MA +{ + class Allocation; +} + +class D3D12StreamBuffer +{ +public: + D3D12StreamBuffer(); + ~D3D12StreamBuffer(); + + bool Create(u32 size); + + __fi bool IsValid() const { return static_cast(m_buffer); } + __fi ID3D12Resource* GetBuffer() const { return m_buffer.get(); } + __fi D3D12_GPU_VIRTUAL_ADDRESS GetGPUPointer() const { return m_gpu_pointer; } + __fi void* GetHostPointer() const { return m_host_pointer; } + __fi void* GetCurrentHostPointer() const { return m_host_pointer + m_current_offset; } + __fi D3D12_GPU_VIRTUAL_ADDRESS GetCurrentGPUPointer() const { return m_gpu_pointer + m_current_offset; } + __fi u32 GetSize() const { return m_size; } + __fi u32 GetCurrentOffset() const { return m_current_offset; } + __fi u32 GetCurrentSpace() const { return m_current_space; } + + bool ReserveMemory(u32 num_bytes, u32 alignment); + void CommitMemory(u32 final_num_bytes); + + void Destroy(bool defer = true); + +private: + void UpdateCurrentFencePosition(); + void UpdateGPUPosition(); + + // Waits for as many fences as needed to allocate num_bytes bytes from the buffer. + bool WaitForClearSpace(u32 num_bytes); + + u32 m_size = 0; + u32 m_current_offset = 0; + u32 m_current_space = 0; + u32 m_current_gpu_position = 0; + + wil::com_ptr_nothrow m_buffer; + wil::com_ptr_nothrow m_allocation; + D3D12_GPU_VIRTUAL_ADDRESS m_gpu_pointer = {}; + u8* m_host_pointer = nullptr; + + // List of fences and the corresponding positions in the buffer + std::deque> m_tracked_fences; +}; diff --git a/common/D3D12/Texture.cpp b/pcsx2/GS/Renderers/DX12/D3D12Texture.cpp similarity index 74% rename from common/D3D12/Texture.cpp rename to pcsx2/GS/Renderers/DX12/D3D12Texture.cpp index 35b080f47d..a7dace9f9d 100644 --- a/common/D3D12/Texture.cpp +++ b/pcsx2/GS/Renderers/DX12/D3D12Texture.cpp @@ -1,5 +1,5 @@ /* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2022 PCSX2 Dev Team + * Copyright (C) 2002-2023 PCSX2 Dev Team * * PCSX2 is free software: you can redistribute it and/or modify it under the terms * of the GNU Lesser General Public License as published by the Free Software Found- @@ -13,22 +13,21 @@ * If not, see . */ -#include "common/PrecompiledHeader.h" +#include "PrecompiledHeader.h" + +#include "GS/Renderers/DX12/D3D12Texture.h" +#include "GS/Renderers/DX12/D3D12Context.h" -#include "common/D3D12/Texture.h" -#include "common/D3D12/Context.h" -#include "common/D3D12/Util.h" #include "common/Align.h" #include "common/Assertions.h" #include "common/Console.h" #include "common/StringUtil.h" + #include "D3D12MemAlloc.h" -using namespace D3D12; +D3D12Texture::D3D12Texture() = default; -Texture::Texture() = default; - -Texture::Texture(ID3D12Resource* resource, D3D12_RESOURCE_STATES state) +D3D12Texture::D3D12Texture(ID3D12Resource* resource, D3D12_RESOURCE_STATES state) : m_resource(std::move(resource)) { const D3D12_RESOURCE_DESC desc = GetDesc(); @@ -38,7 +37,7 @@ Texture::Texture(ID3D12Resource* resource, D3D12_RESOURCE_STATES state) m_format = desc.Format; } -Texture::Texture(Texture&& texture) +D3D12Texture::D3D12Texture(D3D12Texture&& texture) : m_resource(std::move(texture.m_resource)) , m_allocation(std::move(texture.m_allocation)) , m_srv_descriptor(texture.m_srv_descriptor) @@ -60,12 +59,12 @@ Texture::Texture(Texture&& texture) texture.m_write_descriptor_type = WriteDescriptorType::None; } -Texture::~Texture() +D3D12Texture::~D3D12Texture() { Destroy(); } -Texture& Texture::operator=(Texture&& texture) +D3D12Texture& D3D12Texture::operator=(D3D12Texture&& texture) { Destroy(); m_resource = std::move(texture.m_resource); @@ -89,12 +88,12 @@ Texture& Texture::operator=(Texture&& texture) return *this; } -D3D12_RESOURCE_DESC Texture::GetDesc() const +D3D12_RESOURCE_DESC D3D12Texture::GetDesc() const { return m_resource->GetDesc(); } -bool Texture::Create(u32 width, u32 height, u32 levels, DXGI_FORMAT format, DXGI_FORMAT srv_format, +bool D3D12Texture::Create(u32 width, u32 height, u32 levels, DXGI_FORMAT format, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format, D3D12_RESOURCE_FLAGS flags, u32 alloc_flags) { D3D12_RESOURCE_DESC desc = {}; @@ -131,8 +130,7 @@ bool Texture::Create(u32 width, u32 height, u32 levels, DXGI_FORMAT format, DXGI ComPtr resource; ComPtr allocation; - HRESULT hr = g_d3d12_context->GetAllocator()->CreateResource( - &allocationDesc, &desc, state, + HRESULT hr = g_d3d12_context->GetAllocator()->CreateResource(&allocationDesc, &desc, state, (rtv_format != DXGI_FORMAT_UNKNOWN || dsv_format != DXGI_FORMAT_UNKNOWN) ? &optimized_clear_value : nullptr, allocation.put(), IID_PPV_ARGS(resource.put())); if (FAILED(hr)) @@ -144,7 +142,7 @@ bool Texture::Create(u32 width, u32 height, u32 levels, DXGI_FORMAT format, DXGI return false; } - DescriptorHandle srv_descriptor, write_descriptor; + D3D12DescriptorHandle srv_descriptor, write_descriptor; WriteDescriptorType write_descriptor_type = WriteDescriptorType::None; if (srv_format != DXGI_FORMAT_UNKNOWN) { @@ -155,17 +153,16 @@ bool Texture::Create(u32 width, u32 height, u32 levels, DXGI_FORMAT format, DXGI if (rtv_format != DXGI_FORMAT_UNKNOWN) { pxAssert(dsv_format == DXGI_FORMAT_UNKNOWN && !(flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)); - write_descriptor_type = Texture::WriteDescriptorType::RTV; + write_descriptor_type = D3D12Texture::WriteDescriptorType::RTV; if (!CreateRTVDescriptor(resource.get(), rtv_format, &write_descriptor)) { g_d3d12_context->GetRTVHeapManager().Free(&srv_descriptor); return false; } - } else if (dsv_format != DXGI_FORMAT_UNKNOWN && !(flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)) { - write_descriptor_type = Texture::WriteDescriptorType::DSV; + write_descriptor_type = D3D12Texture::WriteDescriptorType::DSV; if (!CreateDSVDescriptor(resource.get(), dsv_format, &write_descriptor)) { g_d3d12_context->GetDSVHeapManager().Free(&srv_descriptor); @@ -174,7 +171,7 @@ bool Texture::Create(u32 width, u32 height, u32 levels, DXGI_FORMAT format, DXGI } else if (flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS) { - write_descriptor_type = Texture::WriteDescriptorType::UAV; + write_descriptor_type = D3D12Texture::WriteDescriptorType::UAV; if (!CreateUAVDescriptor(resource.get(), dsv_format, &write_descriptor)) { g_d3d12_context->GetDescriptorHeapManager().Free(&srv_descriptor); @@ -197,12 +194,12 @@ bool Texture::Create(u32 width, u32 height, u32 levels, DXGI_FORMAT format, DXGI return true; } -bool Texture::Adopt(ComPtr texture, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, +bool D3D12Texture::Adopt(ComPtr texture, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format, D3D12_RESOURCE_STATES state) { const D3D12_RESOURCE_DESC desc(texture->GetDesc()); - DescriptorHandle srv_descriptor, write_descriptor; + D3D12DescriptorHandle srv_descriptor, write_descriptor; WriteDescriptorType write_descriptor_type = WriteDescriptorType::None; if (srv_format != DXGI_FORMAT_UNKNOWN) { @@ -213,7 +210,7 @@ bool Texture::Adopt(ComPtr texture, DXGI_FORMAT srv_format, DXGI if (rtv_format != DXGI_FORMAT_UNKNOWN) { pxAssert(dsv_format == DXGI_FORMAT_UNKNOWN); - write_descriptor_type = Texture::WriteDescriptorType::RTV; + write_descriptor_type = D3D12Texture::WriteDescriptorType::RTV; if (!CreateRTVDescriptor(texture.get(), rtv_format, &write_descriptor)) { g_d3d12_context->GetRTVHeapManager().Free(&srv_descriptor); @@ -222,7 +219,7 @@ bool Texture::Adopt(ComPtr texture, DXGI_FORMAT srv_format, DXGI } else if (dsv_format != DXGI_FORMAT_UNKNOWN) { - write_descriptor_type = Texture::WriteDescriptorType::DSV; + write_descriptor_type = D3D12Texture::WriteDescriptorType::DSV; if (!CreateDSVDescriptor(texture.get(), dsv_format, &write_descriptor)) { g_d3d12_context->GetDSVHeapManager().Free(&srv_descriptor); @@ -231,7 +228,7 @@ bool Texture::Adopt(ComPtr texture, DXGI_FORMAT srv_format, DXGI } else if (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS) { - write_descriptor_type = Texture::WriteDescriptorType::UAV; + write_descriptor_type = D3D12Texture::WriteDescriptorType::UAV; if (!CreateUAVDescriptor(texture.get(), srv_format, &write_descriptor)) { g_d3d12_context->GetDescriptorHeapManager().Free(&srv_descriptor); @@ -252,7 +249,7 @@ bool Texture::Adopt(ComPtr texture, DXGI_FORMAT srv_format, DXGI return true; } -void Texture::Destroy(bool defer /* = true */) +void D3D12Texture::Destroy(bool defer /* = true */) { if (defer) { @@ -260,16 +257,17 @@ void Texture::Destroy(bool defer /* = true */) switch (m_write_descriptor_type) { - case Texture::WriteDescriptorType::RTV: + case D3D12Texture::WriteDescriptorType::RTV: g_d3d12_context->DeferDescriptorDestruction(g_d3d12_context->GetRTVHeapManager(), &m_write_descriptor); break; - case Texture::WriteDescriptorType::DSV: + case D3D12Texture::WriteDescriptorType::DSV: g_d3d12_context->DeferDescriptorDestruction(g_d3d12_context->GetDSVHeapManager(), &m_write_descriptor); break; - case Texture::WriteDescriptorType::UAV: - g_d3d12_context->DeferDescriptorDestruction(g_d3d12_context->GetDescriptorHeapManager(), &m_write_descriptor); + case D3D12Texture::WriteDescriptorType::UAV: + g_d3d12_context->DeferDescriptorDestruction( + g_d3d12_context->GetDescriptorHeapManager(), &m_write_descriptor); break; - case Texture::WriteDescriptorType::None: + case D3D12Texture::WriteDescriptorType::None: default: break; } @@ -284,16 +282,16 @@ void Texture::Destroy(bool defer /* = true */) switch (m_write_descriptor_type) { - case Texture::WriteDescriptorType::RTV: + case D3D12Texture::WriteDescriptorType::RTV: g_d3d12_context->GetRTVHeapManager().Free(&m_write_descriptor); break; - case Texture::WriteDescriptorType::DSV: + case D3D12Texture::WriteDescriptorType::DSV: g_d3d12_context->GetDSVHeapManager().Free(&m_write_descriptor); break; - case Texture::WriteDescriptorType::UAV: + case D3D12Texture::WriteDescriptorType::UAV: g_d3d12_context->GetDescriptorHeapManager().Free(&m_write_descriptor); break; - case Texture::WriteDescriptorType::None: + case D3D12Texture::WriteDescriptorType::None: default: break; } @@ -309,35 +307,36 @@ void Texture::Destroy(bool defer /* = true */) m_write_descriptor_type = WriteDescriptorType::None; } -void Texture::TransitionToState(ID3D12GraphicsCommandList* cmdlist, D3D12_RESOURCE_STATES state) +void D3D12Texture::TransitionToState(ID3D12GraphicsCommandList* cmdlist, D3D12_RESOURCE_STATES state) { if (m_state == state) return; - ResourceBarrier(cmdlist, m_resource.get(), m_state, state); + TransitionSubresourceToState(cmdlist, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, m_state, state); m_state = state; } -void Texture::TransitionSubresourceToState(ID3D12GraphicsCommandList* cmdlist, u32 level, +void D3D12Texture::TransitionSubresourceToState(ID3D12GraphicsCommandList* cmdlist, u32 level, D3D12_RESOURCE_STATES before_state, D3D12_RESOURCE_STATES after_state) const { - const D3D12_RESOURCE_BARRIER barrier = {D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, - D3D12_RESOURCE_BARRIER_FLAG_NONE, + const D3D12_RESOURCE_BARRIER barrier = {D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE, {{m_resource.get(), level, before_state, after_state}}}; cmdlist->ResourceBarrier(1, &barrier); } -ID3D12GraphicsCommandList* Texture::BeginStreamUpdate(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height, void** out_data, u32* out_data_pitch) +ID3D12GraphicsCommandList* D3D12Texture::BeginStreamUpdate(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, + u32 width, u32 height, void** out_data, u32* out_data_pitch) { - const u32 copy_pitch = Common::AlignUpPow2(width * GetTexelSize(m_format), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + const u32 copy_pitch = Common::AlignUpPow2(width * D3D12::GetTexelSize(m_format), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); const u32 upload_size = copy_pitch * height; if (!g_d3d12_context->GetTextureStreamBuffer().ReserveMemory(upload_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT)) { - DevCon.WriteLn("Executing command buffer while waiting for %u bytes (%ux%u) in upload buffer", upload_size, width, - height); - g_d3d12_context->ExecuteCommandList(Context::WaitType::None); - if (!g_d3d12_context->GetTextureStreamBuffer().ReserveMemory(upload_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT)) + DevCon.WriteLn( + "Executing command buffer while waiting for %u bytes (%ux%u) in upload buffer", upload_size, width, height); + g_d3d12_context->ExecuteCommandList(D3D12Context::WaitType::None); + if (!g_d3d12_context->GetTextureStreamBuffer().ReserveMemory( + upload_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT)) { Console.Error("Failed to reserve %u bytes for %ux%u upload", upload_size, width, height); return nullptr; @@ -352,19 +351,20 @@ ID3D12GraphicsCommandList* Texture::BeginStreamUpdate(ID3D12GraphicsCommandList* return cmdlist; } -void Texture::EndStreamUpdate(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height) +void D3D12Texture::EndStreamUpdate(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height) { - const u32 copy_pitch = Common::AlignUpPow2(width * GetTexelSize(m_format), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + const u32 copy_pitch = Common::AlignUpPow2(width * D3D12::GetTexelSize(m_format), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); const u32 upload_size = copy_pitch * height; - StreamBuffer& sb = g_d3d12_context->GetTextureStreamBuffer(); + D3D12StreamBuffer& sb = g_d3d12_context->GetTextureStreamBuffer(); const u32 sb_offset = sb.GetCurrentOffset(); sb.CommitMemory(upload_size); CopyFromBuffer(cmdlist, level, x, y, width, height, copy_pitch, sb.GetBuffer(), sb_offset); } -void Texture::CopyFromBuffer(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height, u32 pitch, ID3D12Resource* buffer, u32 buffer_offset) +void D3D12Texture::CopyFromBuffer(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height, + u32 pitch, ID3D12Resource* buffer, u32 buffer_offset) { D3D12_TEXTURE_COPY_LOCATION src; src.pResource = buffer; @@ -394,11 +394,10 @@ static ID3D12Resource* CreateStagingBuffer(u32 height, const void* data, u32 pit wil::com_ptr_nothrow allocation; const D3D12MA::ALLOCATION_DESC allocation_desc = {D3D12MA::ALLOCATION_FLAG_NONE, D3D12_HEAP_TYPE_UPLOAD}; - const D3D12_RESOURCE_DESC resource_desc = { - D3D12_RESOURCE_DIMENSION_BUFFER, 0, upload_size, 1, 1, 1, DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, - D3D12_RESOURCE_FLAG_NONE}; - HRESULT hr = g_d3d12_context->GetAllocator()->CreateResource(&allocation_desc, &resource_desc, D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr, allocation.put(), IID_PPV_ARGS(resource.put())); + const D3D12_RESOURCE_DESC resource_desc = {D3D12_RESOURCE_DIMENSION_BUFFER, 0, upload_size, 1, 1, 1, + DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE}; + HRESULT hr = g_d3d12_context->GetAllocator()->CreateResource(&allocation_desc, &resource_desc, + D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, allocation.put(), IID_PPV_ARGS(resource.put())); if (FAILED(hr)) { Console.Error("CreateResource() for upload staging buffer failed: %08X", hr); @@ -426,9 +425,10 @@ static ID3D12Resource* CreateStagingBuffer(u32 height, const void* data, u32 pit return resource.get(); } -bool Texture::LoadData(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) +bool D3D12Texture::LoadData( + ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) { - const u32 texel_size = GetTexelSize(m_format); + const u32 texel_size = D3D12::GetTexelSize(m_format); const u32 upload_pitch = Common::AlignUpPow2(width * texel_size, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); const u32 upload_size = upload_pitch * height; if (upload_size >= g_d3d12_context->GetTextureStreamBuffer().GetSize()) @@ -451,7 +451,8 @@ bool Texture::LoadData(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 return true; } -bool Texture::CreateSRVDescriptor(ID3D12Resource* resource, u32 levels, DXGI_FORMAT format, DescriptorHandle* dh) +bool D3D12Texture::CreateSRVDescriptor( + ID3D12Resource* resource, u32 levels, DXGI_FORMAT format, D3D12DescriptorHandle* dh) { if (!g_d3d12_context->GetDescriptorHeapManager().Allocate(dh)) { @@ -459,14 +460,15 @@ bool Texture::CreateSRVDescriptor(ID3D12Resource* resource, u32 levels, DXGI_FOR return false; } - D3D12_SHADER_RESOURCE_VIEW_DESC desc = {format, D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING}; + D3D12_SHADER_RESOURCE_VIEW_DESC desc = { + format, D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING}; desc.Texture2D.MipLevels = levels; g_d3d12_context->GetDevice()->CreateShaderResourceView(resource, &desc, dh->cpu_handle); return true; } -bool Texture::CreateRTVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, DescriptorHandle* dh) +bool D3D12Texture::CreateRTVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh) { if (!g_d3d12_context->GetRTVHeapManager().Allocate(dh)) { @@ -479,7 +481,7 @@ bool Texture::CreateRTVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, return true; } -bool Texture::CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, DescriptorHandle* dh) +bool D3D12Texture::CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh) { if (!g_d3d12_context->GetDSVHeapManager().Allocate(dh)) { @@ -492,7 +494,7 @@ bool Texture::CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, return true; } -bool Texture::CreateUAVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, DescriptorHandle* dh) +bool D3D12Texture::CreateUAVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh) { if (!g_d3d12_context->GetDescriptorHeapManager().Allocate(dh)) { diff --git a/pcsx2/GS/Renderers/DX12/D3D12Texture.h b/pcsx2/GS/Renderers/DX12/D3D12Texture.h new file mode 100644 index 0000000000..6e051d2ce5 --- /dev/null +++ b/pcsx2/GS/Renderers/DX12/D3D12Texture.h @@ -0,0 +1,105 @@ +/* PCSX2 - PS2 Emulator for PCs + * Copyright (C) 2002-2023 PCSX2 Dev Team + * + * PCSX2 is free software: you can redistribute it and/or modify it under the terms + * of the GNU Lesser General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with PCSX2. + * If not, see . + */ + +#pragma once + +#include "GS/Renderers/DX12/D3D12DescriptorHeapManager.h" + +namespace D3D12MA +{ + class Allocation; +} + +class D3D12StreamBuffer; + +class D3D12Texture final +{ +public: + template + using ComPtr = wil::com_ptr_nothrow; + + D3D12Texture(); + D3D12Texture(ID3D12Resource* resource, D3D12_RESOURCE_STATES state); + D3D12Texture(D3D12Texture&& texture); + D3D12Texture(const D3D12Texture&) = delete; + ~D3D12Texture(); + + __fi ID3D12Resource* GetResource() const { return m_resource.get(); } + __fi D3D12MA::Allocation* GetAllocation() const { return m_allocation.get(); } + __fi const D3D12DescriptorHandle& GetSRVDescriptor() const { return m_srv_descriptor; } + __fi const D3D12DescriptorHandle& GetWriteDescriptor() const { return m_write_descriptor; } + __fi D3D12_RESOURCE_STATES GetState() const { return m_state; } + + __fi u32 GetWidth() const { return m_width; } + __fi u32 GetHeight() const { return m_height; } + __fi u32 GetLevels() const { return m_levels; } + __fi DXGI_FORMAT GetFormat() const { return m_format; } + + __fi operator ID3D12Resource*() const { return m_resource.get(); } + __fi operator bool() const { return static_cast(m_resource); } + + bool Create(u32 width, u32 height, u32 levels, DXGI_FORMAT format, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, + DXGI_FORMAT dsv_format, D3D12_RESOURCE_FLAGS flags, u32 alloc_flags = 0); + bool Adopt(ComPtr texture, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format, + D3D12_RESOURCE_STATES state); + + D3D12_RESOURCE_DESC GetDesc() const; + + void Destroy(bool defer = true); + + void TransitionToState(ID3D12GraphicsCommandList* cmdlist, D3D12_RESOURCE_STATES state); + void TransitionSubresourceToState(ID3D12GraphicsCommandList* cmdlist, u32 level, D3D12_RESOURCE_STATES before_state, + D3D12_RESOURCE_STATES after_state) const; + + D3D12Texture& operator=(const D3D12Texture&) = delete; + D3D12Texture& operator=(D3D12Texture&& texture); + + // NOTE: Does not handle compressed formats. + ID3D12GraphicsCommandList* BeginStreamUpdate(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, + u32 height, void** out_data, u32* out_data_pitch); + void EndStreamUpdate(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height); + bool LoadData(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height, const void* data, + u32 pitch); + void CopyFromBuffer(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height, u32 pitch, + ID3D12Resource* buffer, u32 buffer_offset); + +private: + static bool CreateSRVDescriptor( + ID3D12Resource* resource, u32 levels, DXGI_FORMAT format, D3D12DescriptorHandle* dh); + static bool CreateRTVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh); + static bool CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh); + static bool CreateUAVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh); + + enum class WriteDescriptorType : u8 + { + None, + RTV, + DSV, + UAV + }; + + ComPtr m_resource; + ComPtr m_allocation; + D3D12DescriptorHandle m_srv_descriptor = {}; + D3D12DescriptorHandle m_write_descriptor = {}; + u32 m_width = 0; + u32 m_height = 0; + u32 m_levels = 0; + DXGI_FORMAT m_format = DXGI_FORMAT_UNKNOWN; + + D3D12_RESOURCE_STATES m_state = D3D12_RESOURCE_STATE_COMMON; + + WriteDescriptorType m_write_descriptor_type = WriteDescriptorType::None; +}; diff --git a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp index 0e4d176592..8dfcc37b76 100644 --- a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp +++ b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp @@ -21,13 +21,12 @@ #include "GS/GSUtil.h" #include "GS/Renderers/DX11/D3D.h" #include "GS/Renderers/DX12/GSDevice12.h" +#include "GS/Renderers/DX12/D3D12Builders.h" +#include "GS/Renderers/DX12/D3D12Context.h" +#include "GS/Renderers/DX12/D3D12ShaderCache.h" #include "Host.h" #include "ShaderCacheVersion.h" -#include "common/D3D12/Builders.h" -#include "common/D3D12/Context.h" -#include "common/D3D12/ShaderCache.h" -#include "common/D3D12/Util.h" #include "common/Align.h" #include "common/ScopedGuard.h" #include "common/StringUtil.h" @@ -129,7 +128,7 @@ bool GSDevice12::Create() ComPtr dxgi_adapter = D3D::GetAdapterByName(m_dxgi_factory.get(), EmuConfig.GS.Adapter); - if (!D3D12::Context::Create(m_dxgi_factory.get(), dxgi_adapter.get(), EmuConfig.GS.UseDebugDevice)) + if (!D3D12Context::Create(m_dxgi_factory.get(), dxgi_adapter.get(), EmuConfig.GS.UseDebugDevice)) { Console.Error("Failed to create D3D12 context"); return false; @@ -160,18 +159,8 @@ bool GSDevice12::Create() m_tfx_source = std::move(*shader); } - if (!GSConfig.DisableShaderCache) - { - if (!m_shader_cache.Open(EmuFolders::Cache, g_d3d12_context->GetFeatureLevel(), SHADER_CACHE_VERSION, GSConfig.UseDebugDevice)) - { - Console.Warning("Shader cache failed to open."); - } - } - else - { - m_shader_cache.Open({}, g_d3d12_context->GetFeatureLevel(), SHADER_CACHE_VERSION, GSConfig.UseDebugDevice); - Console.WriteLn("Not using shader cache."); - } + if (!m_shader_cache.Open(g_d3d12_context->GetFeatureLevel(), GSConfig.UseDebugDevice)) + Console.Warning("Shader cache failed to open."); // reset stuff in case it was used by a previous device g_d3d12_context->GetSamplerAllocator().Reset(); @@ -332,7 +321,7 @@ bool GSDevice12::CreateSwapChain() // Render a frame as soon as possible to clear out whatever was previously being displayed. EndRenderPass(); - D3D12::Texture& swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer]; + D3D12Texture& swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer]; ID3D12GraphicsCommandList4* cmdlist = g_d3d12_context->GetCommandList(); m_current_swap_chain_buffer = ((m_current_swap_chain_buffer + 1) % static_cast(m_swap_chain_buffers.size())); swap_chain_buf.TransitionToState(cmdlist, D3D12_RESOURCE_STATE_RENDER_TARGET); @@ -361,7 +350,7 @@ bool GSDevice12::CreateSwapChainRTV() return false; } - D3D12::Texture tex; + D3D12Texture tex; if (!tex.Adopt(std::move(backbuffer), DXGI_FORMAT_UNKNOWN, swap_chain_desc.BufferDesc.Format, DXGI_FORMAT_UNKNOWN, D3D12_RESOURCE_STATE_PRESENT)) { @@ -398,7 +387,7 @@ bool GSDevice12::CreateSwapChainRTV() void GSDevice12::DestroySwapChainRTVs() { - for (D3D12::Texture& buffer : m_swap_chain_buffers) + for (D3D12Texture& buffer : m_swap_chain_buffers) buffer.Destroy(false); m_swap_chain_buffers.clear(); m_current_swap_chain_buffer = 0; @@ -533,7 +522,7 @@ GSDevice::PresentResult GSDevice12::BeginPresent(bool frame_skip) return PresentResult::FrameSkipped; } - D3D12::Texture& swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer]; + D3D12Texture& swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer]; ID3D12GraphicsCommandList* cmdlist = g_d3d12_context->GetCommandList(); swap_chain_buf.TransitionToState(cmdlist, D3D12_RESOURCE_STATE_RENDER_TARGET); @@ -554,11 +543,11 @@ void GSDevice12::EndPresent() { RenderImGui(); - D3D12::Texture& swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer]; + D3D12Texture& swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer]; m_current_swap_chain_buffer = ((m_current_swap_chain_buffer + 1) % static_cast(m_swap_chain_buffers.size())); swap_chain_buf.TransitionToState(g_d3d12_context->GetCommandList(), D3D12_RESOURCE_STATE_PRESENT); - if (!g_d3d12_context->ExecuteCommandList(D3D12::Context::WaitType::None)) + if (!g_d3d12_context->ExecuteCommandList(D3D12Context::WaitType::None)) { m_device_lost = true; InvalidateCachedState(); @@ -1115,7 +1104,7 @@ void GSDevice12::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, const bool feedback_write_2 = PMODE.EN2 && sTex[2] != nullptr && EXTBUF.FBIN == 1; const bool feedback_write_1 = PMODE.EN1 && sTex[2] != nullptr && EXTBUF.FBIN == 0; const bool feedback_write_2_but_blend_bg = feedback_write_2 && PMODE.SLBG == 1; - const D3D12::DescriptorHandle& sampler = linear ? m_linear_sampler_cpu : m_point_sampler_cpu; + const D3D12DescriptorHandle& sampler = linear ? m_linear_sampler_cpu : m_point_sampler_cpu; // Merge the 2 source textures (sTex[0],sTex[1]). Final results go to dTex. Feedback write will go to sTex[2]. // If either 2nd output is disabled or SLBG is 1, a background color will be used. // Note: background color is also used when outside of the unit rectangle area @@ -1441,8 +1430,8 @@ void GSDevice12::RenderImGui() SetScissor(GSVector4i(clip)); // Since we don't have the GSTexture... - D3D12::Texture* tex = static_cast(pcmd->GetTexID()); - D3D12::DescriptorHandle handle = tex ? tex->GetSRVDescriptor() : m_null_texture.GetSRVDescriptor(); + D3D12Texture* tex = static_cast(pcmd->GetTexID()); + D3D12DescriptorHandle handle = tex ? tex->GetSRVDescriptor() : m_null_texture.GetSRVDescriptor(); if (m_utility_texture_cpu != handle) { m_utility_texture_cpu = handle; @@ -1472,7 +1461,7 @@ bool GSDevice12::DoCAS(GSTexture* sTex, GSTexture* dTex, bool sharpen_only, cons GSTexture12* const sTex12 = static_cast(sTex); GSTexture12* const dTex12 = static_cast(dTex); - D3D12::DescriptorHandle sTexDH, dTexDH; + D3D12DescriptorHandle sTexDH, dTexDH; if (!GetTextureGroupDescriptors(&sTexDH, &sTex12->GetTexture().GetSRVDescriptor(), 1) || !GetTextureGroupDescriptors(&dTexDH, &dTex12->GetTexture().GetWriteDescriptor(), 1)) { @@ -1573,7 +1562,7 @@ void GSDevice12::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector SetScissor(scissor); } -bool GSDevice12::GetSampler(D3D12::DescriptorHandle* cpu_handle, GSHWDrawConfig::SamplerSelector ss) +bool GSDevice12::GetSampler(D3D12DescriptorHandle* cpu_handle, GSHWDrawConfig::SamplerSelector ss) { const auto it = m_samplers.find(ss.key); if (it != m_samplers.end()) @@ -1636,7 +1625,7 @@ void GSDevice12::ClearSamplerCache() m_dirty_flags |= DIRTY_FLAG_TFX_SAMPLERS; } -bool GSDevice12::GetTextureGroupDescriptors(D3D12::DescriptorHandle* gpu_handle, const D3D12::DescriptorHandle* cpu_handles, u32 count) +bool GSDevice12::GetTextureGroupDescriptors(D3D12DescriptorHandle* gpu_handle, const D3D12DescriptorHandle* cpu_handles, u32 count) { if (!g_d3d12_context->GetDescriptorAllocator().Allocate(count, gpu_handle)) return false; @@ -2082,7 +2071,7 @@ bool GSDevice12::CompilePostProcessingPipelines() void GSDevice12::DestroyResources() { - g_d3d12_context->ExecuteCommandList(D3D12::Context::WaitType::Sleep); + g_d3d12_context->ExecuteCommandList(D3D12Context::WaitType::Sleep); m_convert_vs.reset(); @@ -2370,14 +2359,14 @@ void GSDevice12::InitializeSamplers() pxFailRel("Failed to initialize samplers"); } -static D3D12::Context::WaitType GetWaitType(bool wait, bool spin) +static D3D12Context::WaitType GetWaitType(bool wait, bool spin) { if (!wait) - return D3D12::Context::WaitType::None; + return D3D12Context::WaitType::None; if (spin) - return D3D12::Context::WaitType::Spin; + return D3D12Context::WaitType::Spin; else - return D3D12::Context::WaitType::Sleep; + return D3D12Context::WaitType::Sleep; } void GSDevice12::ExecuteCommandList(bool wait_for_completion) @@ -2491,7 +2480,7 @@ void GSDevice12::SetStencilRef(u8 ref) void GSDevice12::PSSetShaderResource(int i, GSTexture* sr, bool check_state) { - D3D12::DescriptorHandle handle; + D3D12DescriptorHandle handle; if (sr) { GSTexture12* dtex = static_cast(sr); @@ -2541,9 +2530,9 @@ void GSDevice12::SetUtilityRootSignature() g_d3d12_context->GetCommandList()->SetGraphicsRootSignature(m_utility_root_signature.get()); } -void GSDevice12::SetUtilityTexture(GSTexture* dtex, const D3D12::DescriptorHandle& sampler) +void GSDevice12::SetUtilityTexture(GSTexture* dtex, const D3D12DescriptorHandle& sampler) { - D3D12::DescriptorHandle handle; + D3D12DescriptorHandle handle; if (dtex) { GSTexture12* d12tex = static_cast(dtex); @@ -2611,18 +2600,18 @@ void GSDevice12::UnbindTexture(GSTexture12* tex) } } -void GSDevice12::RenderTextureMipmap(const D3D12::Texture& texture, +void GSDevice12::RenderTextureMipmap(const D3D12Texture& texture, u32 dst_level, u32 dst_width, u32 dst_height, u32 src_level, u32 src_width, u32 src_height) { EndRenderPass(); // we need a temporary SRV and RTV for each mip level // Safe to use the init buffer after exec, because everything will be done with the texture. - D3D12::DescriptorHandle rtv_handle; + D3D12DescriptorHandle rtv_handle; while (!g_d3d12_context->GetRTVHeapManager().Allocate(&rtv_handle)) ExecuteCommandList(false); - D3D12::DescriptorHandle srv_handle; + D3D12DescriptorHandle srv_handle; while (!g_d3d12_context->GetDescriptorHeapManager().Allocate(&srv_handle)) ExecuteCommandList(false); diff --git a/pcsx2/GS/Renderers/DX12/GSDevice12.h b/pcsx2/GS/Renderers/DX12/GSDevice12.h index 6169dcffeb..1533df7c08 100644 --- a/pcsx2/GS/Renderers/DX12/GSDevice12.h +++ b/pcsx2/GS/Renderers/DX12/GSDevice12.h @@ -18,8 +18,8 @@ #include "GS/GSVector.h" #include "GS/Renderers/Common/GSDevice.h" #include "GS/Renderers/DX12/GSTexture12.h" -#include "common/D3D12/ShaderCache.h" -#include "common/D3D12/StreamBuffer.h" +#include "GS/Renderers/DX12/D3D12ShaderCache.h" +#include "GS/Renderers/DX12/D3D12StreamBuffer.h" #include "common/HashCombine.h" #include #include @@ -141,7 +141,7 @@ public: private: ComPtr m_dxgi_factory; ComPtr m_swap_chain; - std::vector m_swap_chain_buffers; + std::vector m_swap_chain_buffers; u32 m_current_swap_chain_buffer = 0; bool m_allow_tearing_supported = false; @@ -152,17 +152,17 @@ private: ComPtr m_tfx_root_signature; ComPtr m_utility_root_signature; - D3D12::StreamBuffer m_vertex_stream_buffer; - D3D12::StreamBuffer m_index_stream_buffer; - D3D12::StreamBuffer m_vertex_constant_buffer; - D3D12::StreamBuffer m_pixel_constant_buffer; + D3D12StreamBuffer m_vertex_stream_buffer; + D3D12StreamBuffer m_index_stream_buffer; + D3D12StreamBuffer m_vertex_constant_buffer; + D3D12StreamBuffer m_pixel_constant_buffer; ComPtr m_expand_index_buffer; ComPtr m_expand_index_buffer_allocation; - D3D12::DescriptorHandle m_point_sampler_cpu; - D3D12::DescriptorHandle m_linear_sampler_cpu; + D3D12DescriptorHandle m_point_sampler_cpu; + D3D12DescriptorHandle m_linear_sampler_cpu; - std::unordered_map m_samplers; + std::unordered_map m_samplers; std::array, static_cast(ShaderConvert::Count)> m_convert{}; std::array, static_cast(PresentShader::Count)> m_present{}; @@ -187,7 +187,7 @@ private: GSHWDrawConfig::VSConstantBuffer m_vs_cb_cache; GSHWDrawConfig::PSConstantBuffer m_ps_cb_cache; - D3D12::ShaderCache m_shader_cache; + D3D12ShaderCache m_shader_cache; ComPtr m_convert_vs; std::string m_tfx_source; @@ -208,9 +208,9 @@ private: bool DoCAS(GSTexture* sTex, GSTexture* dTex, bool sharpen_only, const std::array& constants) final; - bool GetSampler(D3D12::DescriptorHandle* cpu_handle, GSHWDrawConfig::SamplerSelector ss); + bool GetSampler(D3D12DescriptorHandle* cpu_handle, GSHWDrawConfig::SamplerSelector ss); void ClearSamplerCache() final; - bool GetTextureGroupDescriptors(D3D12::DescriptorHandle* gpu_handle, const D3D12::DescriptorHandle* cpu_handles, u32 count); + bool GetTextureGroupDescriptors(D3D12DescriptorHandle* gpu_handle, const D3D12DescriptorHandle* cpu_handles, u32 count); const ID3DBlob* GetTFXVertexShader(GSHWDrawConfig::VSSelector sel); const ID3DBlob* GetTFXPixelShader(const GSHWDrawConfig::PSSelector& sel); @@ -341,13 +341,13 @@ public: void SetStencilRef(u8 ref); void SetUtilityRootSignature(); - void SetUtilityTexture(GSTexture* tex, const D3D12::DescriptorHandle& sampler); + void SetUtilityTexture(GSTexture* tex, const D3D12DescriptorHandle& sampler); void SetUtilityPushConstants(const void* data, u32 size); void UnbindTexture(GSTexture12* tex); // Assumes that the previous level has been transitioned to PS resource, // and the current level has been transitioned to RT. - void RenderTextureMipmap(const D3D12::Texture& texture, + void RenderTextureMipmap(const D3D12Texture& texture, u32 dst_level, u32 dst_width, u32 dst_height, u32 src_level, u32 src_width, u32 src_height); // Ends a render pass if we're currently in one. @@ -436,22 +436,22 @@ private: bool m_in_render_pass = false; std::array m_tfx_constant_buffers{}; - std::array m_tfx_textures{}; - D3D12::DescriptorHandle m_tfx_sampler; + std::array m_tfx_textures{}; + D3D12DescriptorHandle m_tfx_sampler; u32 m_tfx_sampler_sel = 0; - D3D12::DescriptorHandle m_tfx_textures_handle_gpu; - D3D12::DescriptorHandle m_tfx_samplers_handle_gpu; - D3D12::DescriptorHandle m_tfx_rt_textures_handle_gpu; + D3D12DescriptorHandle m_tfx_textures_handle_gpu; + D3D12DescriptorHandle m_tfx_samplers_handle_gpu; + D3D12DescriptorHandle m_tfx_rt_textures_handle_gpu; - D3D12::DescriptorHandle m_utility_texture_cpu; - D3D12::DescriptorHandle m_utility_texture_gpu; - D3D12::DescriptorHandle m_utility_sampler_cpu; - D3D12::DescriptorHandle m_utility_sampler_gpu; + D3D12DescriptorHandle m_utility_texture_cpu; + D3D12DescriptorHandle m_utility_texture_gpu; + D3D12DescriptorHandle m_utility_sampler_cpu; + D3D12DescriptorHandle m_utility_sampler_gpu; RootSignature m_current_root_signature = RootSignature::Undefined; const ID3D12PipelineState* m_current_pipeline = nullptr; - D3D12::Texture m_null_texture; + D3D12Texture m_null_texture; // current pipeline selector - we save this in the struct to avoid re-zeroing it every draw PipelineSelector m_pipeline_selector = {}; diff --git a/pcsx2/GS/Renderers/DX12/GSTexture12.cpp b/pcsx2/GS/Renderers/DX12/GSTexture12.cpp index 5af308fca2..c684632a55 100644 --- a/pcsx2/GS/Renderers/DX12/GSTexture12.cpp +++ b/pcsx2/GS/Renderers/DX12/GSTexture12.cpp @@ -14,19 +14,21 @@ */ #include "PrecompiledHeader.h" -#include "GSTexture12.h" -#include "GSDevice12.h" -#include "common/Assertions.h" -#include "common/Align.h" -#include "common/D3D12/Builders.h" -#include "common/D3D12/Context.h" -#include "common/D3D12/Util.h" -#include "common/StringUtil.h" -#include "D3D12MemAlloc.h" + +#include "GS/Renderers/DX12/GSTexture12.h" +#include "GS/Renderers/DX12/D3D12Builders.h" +#include "GS/Renderers/DX12/D3D12Context.h" +#include "GS/Renderers/DX12/GSDevice12.h" #include "GS/GSPerfMon.h" #include "GS/GSGL.h" -GSTexture12::GSTexture12(Type type, Format format, D3D12::Texture texture) +#include "common/Assertions.h" +#include "common/Align.h" +#include "common/StringUtil.h" + +#include "D3D12MemAlloc.h" + +GSTexture12::GSTexture12(Type type, Format format, D3D12Texture texture) : m_texture(std::move(texture)) { m_type = type; @@ -52,11 +54,11 @@ std::unique_ptr GSTexture12::Create(Type type, u32 width, u32 heigh // If it's a compressed texture, we won't be generating mips anyway, so this should be fine. const D3D12_RESOURCE_FLAGS flags = (levels > 1 && !IsCompressedFormat(format)) ? D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET : - D3D12_RESOURCE_FLAG_NONE; + D3D12_RESOURCE_FLAG_NONE; - D3D12::Texture texture; - if (!texture.Create(width, height, levels, d3d_format, srv_format, - DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, flags)) + D3D12Texture texture; + if (!texture.Create( + width, height, levels, d3d_format, srv_format, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, flags)) { return {}; } @@ -70,9 +72,9 @@ std::unique_ptr GSTexture12::Create(Type type, u32 width, u32 heigh pxAssert(levels == 1); // RT's tend to be larger, so we'll keep them committed for speed. - D3D12::Texture texture; - if (!texture.Create(width, height, levels, d3d_format, srv_format, rtv_format, - DXGI_FORMAT_UNKNOWN, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12MA::ALLOCATION_FLAG_COMMITTED)) + D3D12Texture texture; + if (!texture.Create(width, height, levels, d3d_format, srv_format, rtv_format, DXGI_FORMAT_UNKNOWN, + D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12MA::ALLOCATION_FLAG_COMMITTED)) { return {}; } @@ -85,10 +87,9 @@ std::unique_ptr GSTexture12::Create(Type type, u32 width, u32 heigh { pxAssert(levels == 1); - D3D12::Texture texture; - if (!texture.Create(width, height, levels, d3d_format, srv_format, - DXGI_FORMAT_UNKNOWN, dsv_format, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL, - D3D12MA::ALLOCATION_FLAG_COMMITTED)) + D3D12Texture texture; + if (!texture.Create(width, height, levels, d3d_format, srv_format, DXGI_FORMAT_UNKNOWN, dsv_format, + D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL, D3D12MA::ALLOCATION_FLAG_COMMITTED)) { return {}; } @@ -101,9 +102,9 @@ std::unique_ptr GSTexture12::Create(Type type, u32 width, u32 heigh { pxAssert(levels == 1); - D3D12::Texture texture; - if (!texture.Create(width, height, levels, d3d_format, srv_format, DXGI_FORMAT_UNKNOWN, - DXGI_FORMAT_UNKNOWN, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12MA::ALLOCATION_FLAG_COMMITTED)) + D3D12Texture texture; + if (!texture.Create(width, height, levels, d3d_format, srv_format, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, + D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12MA::ALLOCATION_FLAG_COMMITTED)) { return {}; } @@ -117,7 +118,10 @@ std::unique_ptr GSTexture12::Create(Type type, u32 width, u32 heigh } } -void* GSTexture12::GetNativeHandle() const { return const_cast(&m_texture); } +void* GSTexture12::GetNativeHandle() const +{ + return const_cast(&m_texture); +} ID3D12GraphicsCommandList* GSTexture12::GetCommandBufferForUpdate() { @@ -131,18 +135,18 @@ ID3D12GraphicsCommandList* GSTexture12::GetCommandBufferForUpdate() return g_d3d12_context->GetInitCommandList(); } -ID3D12Resource* GSTexture12::AllocateUploadStagingBuffer(const void* data, u32 pitch, u32 upload_pitch, u32 height) const +ID3D12Resource* GSTexture12::AllocateUploadStagingBuffer( + const void* data, u32 pitch, u32 upload_pitch, u32 height) const { const u32 buffer_size = CalcUploadSize(height, upload_pitch); wil::com_ptr_nothrow resource; wil::com_ptr_nothrow allocation; const D3D12MA::ALLOCATION_DESC allocation_desc = {D3D12MA::ALLOCATION_FLAG_NONE, D3D12_HEAP_TYPE_UPLOAD}; - const D3D12_RESOURCE_DESC resource_desc = { - D3D12_RESOURCE_DIMENSION_BUFFER, 0, buffer_size, 1, 1, 1, DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, - D3D12_RESOURCE_FLAG_NONE}; - HRESULT hr = g_d3d12_context->GetAllocator()->CreateResource(&allocation_desc, &resource_desc, D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr, allocation.put(), IID_PPV_ARGS(resource.put())); + const D3D12_RESOURCE_DESC resource_desc = {D3D12_RESOURCE_DIMENSION_BUFFER, 0, buffer_size, 1, 1, 1, + DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE}; + HRESULT hr = g_d3d12_context->GetAllocator()->CreateResource(&allocation_desc, &resource_desc, + D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, allocation.put(), IID_PPV_ARGS(resource.put())); if (FAILED(hr)) { Console.WriteLn("(AllocateUploadStagingBuffer) CreateCommittedResource() failed with %08X", hr); @@ -209,7 +213,7 @@ bool GSTexture12::Update(const GSVector4i& r, const void* data, int pitch, int l } else { - D3D12::StreamBuffer& sbuffer = g_d3d12_context->GetTextureStreamBuffer(); + D3D12StreamBuffer& sbuffer = g_d3d12_context->GetTextureStreamBuffer(); if (!sbuffer.ReserveMemory(required_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT)) { GSDevice12::GetInstance()->ExecuteCommandList( @@ -272,11 +276,12 @@ bool GSTexture12::Map(GSMap& m, const GSVector4i* r, int layer) m_map_area = r ? *r : GSVector4i(0, 0, m_texture.GetWidth(), m_texture.GetHeight()); m_map_level = layer; - m.pitch = Common::AlignUpPow2(m_map_area.width() * D3D12::GetTexelSize(m_texture.GetFormat()), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + m.pitch = Common::AlignUpPow2( + m_map_area.width() * D3D12::GetTexelSize(m_texture.GetFormat()), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); // see note in Update() for the reason why. const u32 required_size = CalcUploadSize(m_map_area.height(), m.pitch); - D3D12::StreamBuffer& buffer = g_d3d12_context->GetTextureStreamBuffer(); + D3D12StreamBuffer& buffer = g_d3d12_context->GetTextureStreamBuffer(); if (required_size >= (buffer.GetSize() / 2)) return false; @@ -301,9 +306,10 @@ void GSTexture12::Unmap() // TODO: non-tightly-packed formats const u32 width = static_cast(m_map_area.width()); const u32 height = static_cast(m_map_area.height()); - const u32 pitch = Common::AlignUpPow2(m_map_area.width() * D3D12::GetTexelSize(m_texture.GetFormat()), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + const u32 pitch = Common::AlignUpPow2( + m_map_area.width() * D3D12::GetTexelSize(m_texture.GetFormat()), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); const u32 required_size = CalcUploadSize(height, pitch); - D3D12::StreamBuffer& buffer = g_d3d12_context->GetTextureStreamBuffer(); + D3D12StreamBuffer& buffer = g_d3d12_context->GetTextureStreamBuffer(); const u32 buffer_offset = buffer.GetCurrentOffset(); buffer.CommitMemory(required_size); @@ -315,7 +321,8 @@ void GSTexture12::Unmap() if (m_texture.GetState() == D3D12_RESOURCE_STATE_COMMON) m_texture.TransitionToState(cmdlist, D3D12_RESOURCE_STATE_COPY_DEST); else if (m_texture.GetState() != D3D12_RESOURCE_STATE_COPY_DEST) - m_texture.TransitionSubresourceToState(cmdlist, m_map_level, m_texture.GetState(), D3D12_RESOURCE_STATE_COPY_DEST); + m_texture.TransitionSubresourceToState( + cmdlist, m_map_level, m_texture.GetState(), D3D12_RESOURCE_STATE_COPY_DEST); // if we're an rt and have been cleared, and the full rect isn't being uploaded, do the clear if (m_type == Type::RenderTarget) @@ -345,7 +352,8 @@ void GSTexture12::Unmap() cmdlist->CopyTextureRegion(&dstloc, m_map_area.x, m_map_area.y, 0, &srcloc, &srcbox); if (m_texture.GetState() != D3D12_RESOURCE_STATE_COPY_DEST) - m_texture.TransitionSubresourceToState(cmdlist, m_map_level, D3D12_RESOURCE_STATE_COPY_DEST, m_texture.GetState()); + m_texture.TransitionSubresourceToState( + cmdlist, m_map_level, D3D12_RESOURCE_STATE_COPY_DEST, m_texture.GetState()); if (m_type == Type::Texture) m_needs_mipmaps_generated |= (m_map_level == 0); @@ -363,8 +371,8 @@ void GSTexture12::GenerateMipmap() const int dst_width = std::max(m_size.x >> dst_level, 1); const int dst_height = std::max(m_size.y >> dst_level, 1); - GSDevice12::GetInstance()->RenderTextureMipmap(m_texture, - dst_level, dst_width, dst_height, src_level, src_width, src_height); + GSDevice12::GetInstance()->RenderTextureMipmap( + m_texture, dst_level, dst_width, dst_height, src_level, src_width, src_height); } SetUsedThisCommandBuffer(); @@ -400,7 +408,8 @@ void GSTexture12::CommitClear(ID3D12GraphicsCommandList* cmdlist) if (IsDepthStencil()) { m_texture.TransitionToState(cmdlist, D3D12_RESOURCE_STATE_DEPTH_WRITE); - cmdlist->ClearDepthStencilView(m_texture.GetWriteDescriptor(), D3D12_CLEAR_FLAG_DEPTH, m_clear_value.depth, 0, 0, nullptr); + cmdlist->ClearDepthStencilView( + m_texture.GetWriteDescriptor(), D3D12_CLEAR_FLAG_DEPTH, m_clear_value.depth, 0, 0, nullptr); } else { @@ -432,14 +441,14 @@ std::unique_ptr GSDownloadTexture12::Create(u32 width, u32 D3D12MA::ALLOCATION_DESC allocation_desc = {}; allocation_desc.HeapType = D3D12_HEAP_TYPE_READBACK; - const D3D12_RESOURCE_DESC resource_desc = {D3D12_RESOURCE_DIMENSION_BUFFER, 0, buffer_size, 1, 1, 1, DXGI_FORMAT_UNKNOWN, {1, 0}, - D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE}; + const D3D12_RESOURCE_DESC resource_desc = {D3D12_RESOURCE_DIMENSION_BUFFER, 0, buffer_size, 1, 1, 1, + DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, D3D12_RESOURCE_FLAG_NONE}; wil::com_ptr_nothrow allocation; wil::com_ptr_nothrow buffer; - HRESULT hr = g_d3d12_context->GetAllocator()->CreateResource( - &allocation_desc, &resource_desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, allocation.put(), IID_PPV_ARGS(buffer.put())); + HRESULT hr = g_d3d12_context->GetAllocator()->CreateResource(&allocation_desc, &resource_desc, + D3D12_RESOURCE_STATE_COPY_DEST, nullptr, allocation.put(), IID_PPV_ARGS(buffer.put())); if (FAILED(hr)) { Console.Error("(GSDownloadTexture12::Create) CreateResource() failed with HRESULT %08X", hr); @@ -466,7 +475,8 @@ void GSDownloadTexture12::CopyFromTexture( pxAssert((drc.left == 0 && drc.top == 0) || !use_transfer_pitch); u32 copy_offset, copy_size, copy_rows; - m_current_pitch = GetTransferPitch(use_transfer_pitch ? static_cast(drc.width()) : m_width, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); + m_current_pitch = GetTransferPitch( + use_transfer_pitch ? static_cast(drc.width()) : m_width, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); GetTransferSize(drc, ©_offset, ©_size, ©_rows); g_perfmon.Put(GSPerfMon::Readbacks, 1); @@ -496,15 +506,17 @@ void GSDownloadTexture12::CopyFromTexture( const D3D12_RESOURCE_STATES old_layout = tex12->GetResourceState(); if (old_layout != D3D12_RESOURCE_STATE_COPY_SOURCE) - tex12->GetTexture().TransitionSubresourceToState(cmdlist, src_level, old_layout, D3D12_RESOURCE_STATE_COPY_SOURCE); + tex12->GetTexture().TransitionSubresourceToState( + cmdlist, src_level, old_layout, D3D12_RESOURCE_STATE_COPY_SOURCE); // TODO: Rules for depth buffers here? - const D3D12_BOX srcbox{ - static_cast(src.left), static_cast(src.top), 0u, static_cast(src.right), static_cast(src.bottom), 1u}; + const D3D12_BOX srcbox{static_cast(src.left), static_cast(src.top), 0u, static_cast(src.right), + static_cast(src.bottom), 1u}; cmdlist->CopyTextureRegion(&dstloc, 0, 0, 0, &srcloc, &srcbox); if (old_layout != D3D12_RESOURCE_STATE_COPY_SOURCE) - tex12->GetTexture().TransitionSubresourceToState(cmdlist, src_level, D3D12_RESOURCE_STATE_COPY_SOURCE, old_layout); + tex12->GetTexture().TransitionSubresourceToState( + cmdlist, src_level, D3D12_RESOURCE_STATE_COPY_SOURCE, old_layout); m_copy_fence_value = g_d3d12_context->GetCurrentFenceValue(); m_needs_flush = true; diff --git a/pcsx2/GS/Renderers/DX12/GSTexture12.h b/pcsx2/GS/Renderers/DX12/GSTexture12.h index 845f9db072..dd5863b403 100644 --- a/pcsx2/GS/Renderers/DX12/GSTexture12.h +++ b/pcsx2/GS/Renderers/DX12/GSTexture12.h @@ -17,21 +17,21 @@ #include "GS/GS.h" #include "GS/Renderers/Common/GSTexture.h" -#include "common/D3D12/Context.h" -#include "common/D3D12/Texture.h" +#include "GS/Renderers/DX12/D3D12Context.h" +#include "GS/Renderers/DX12/D3D12Texture.h" class GSTexture12 final : public GSTexture { public: - GSTexture12(Type type, Format format, D3D12::Texture texture); + GSTexture12(Type type, Format format, D3D12Texture texture); ~GSTexture12() override; static std::unique_ptr Create(Type type, u32 width, u32 height, u32 levels, Format format, DXGI_FORMAT d3d_format, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format); - __fi D3D12::Texture& GetTexture() { return m_texture; } - __fi const D3D12::DescriptorHandle& GetSRVDescriptor() const { return m_texture.GetSRVDescriptor(); } - __fi const D3D12::DescriptorHandle& GetRTVOrDSVHandle() const { return m_texture.GetWriteDescriptor(); } + __fi D3D12Texture& GetTexture() { return m_texture; } + __fi const D3D12DescriptorHandle& GetSRVDescriptor() const { return m_texture.GetSRVDescriptor(); } + __fi const D3D12DescriptorHandle& GetRTVOrDSVHandle() const { return m_texture.GetWriteDescriptor(); } __fi D3D12_RESOURCE_STATES GetResourceState() const { return m_texture.GetState(); } __fi DXGI_FORMAT GetNativeFormat() const { return m_texture.GetFormat(); } __fi ID3D12Resource* GetResource() const { return m_texture.GetResource(); } @@ -49,17 +49,14 @@ public: void CommitClear(ID3D12GraphicsCommandList* cmdlist); // Call when the texture is bound to the pipeline, or read from in a copy. - __fi void SetUsedThisCommandBuffer() - { - m_use_fence_counter = g_d3d12_context->GetCurrentFenceValue(); - } + __fi void SetUsedThisCommandBuffer() { m_use_fence_counter = g_d3d12_context->GetCurrentFenceValue(); } private: ID3D12GraphicsCommandList* GetCommandBufferForUpdate(); ID3D12Resource* AllocateUploadStagingBuffer(const void* data, u32 pitch, u32 upload_pitch, u32 height) const; void CopyTextureDataForUpload(void* dst, const void* src, u32 pitch, u32 upload_pitch, u32 height) const; - D3D12::Texture m_texture; + D3D12Texture m_texture; // Contains the fence counter when the texture was last used. // When this matches the current fence counter, the texture was used this command buffer. @@ -76,7 +73,8 @@ public: static std::unique_ptr Create(u32 width, u32 height, GSTexture::Format format); - void CopyFromTexture(const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch) override; + void CopyFromTexture( + const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch) override; bool Map(const GSVector4i& read_rc) override; void Unmap() override; diff --git a/pcsx2/pcsx2core.vcxproj b/pcsx2/pcsx2core.vcxproj index fcc45e6d0c..5b9b880e26 100644 --- a/pcsx2/pcsx2core.vcxproj +++ b/pcsx2/pcsx2core.vcxproj @@ -199,6 +199,13 @@ + + + + + + + @@ -538,6 +545,13 @@ + + + + + + + @@ -826,6 +840,9 @@ {88fb34ec-845e-4f21-a552-f1573b9ed167} + + {d45cec7a-3171-40dd-975d-e1544cf16139} + {e960dfdf-1bd3-4c29-b251-d1a0919c9b09} @@ -856,4 +873,4 @@ - \ No newline at end of file + diff --git a/pcsx2/pcsx2core.vcxproj.filters b/pcsx2/pcsx2core.vcxproj.filters index 99f7f36d28..d9af7c0a05 100644 --- a/pcsx2/pcsx2core.vcxproj.filters +++ b/pcsx2/pcsx2core.vcxproj.filters @@ -1355,6 +1355,27 @@ System + + System\Ps2\GS\Renderers\Direct3D11 + + + System\Ps2\GS\Renderers\Direct3D12 + + + System\Ps2\GS\Renderers\Direct3D12 + + + System\Ps2\GS\Renderers\Direct3D12 + + + System\Ps2\GS\Renderers\Direct3D12 + + + System\Ps2\GS\Renderers\Direct3D12 + + + System\Ps2\GS\Renderers\Direct3D12 + @@ -2255,6 +2276,27 @@ System + + System\Ps2\GS\Renderers\Direct3D11 + + + System\Ps2\GS\Renderers\Direct3D12 + + + System\Ps2\GS\Renderers\Direct3D12 + + + System\Ps2\GS\Renderers\Direct3D12 + + + System\Ps2\GS\Renderers\Direct3D12 + + + System\Ps2\GS\Renderers\Direct3D12 + + + System\Ps2\GS\Renderers\Direct3D12 +