diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt index 2fe9606318..7dcd0c08ab 100644 --- a/pcsx2/CMakeLists.txt +++ b/pcsx2/CMakeLists.txt @@ -647,7 +647,6 @@ if(USE_VULKAN) GS/Renderers/Vulkan/VKShaderCache.cpp GS/Renderers/Vulkan/VKStreamBuffer.cpp GS/Renderers/Vulkan/VKSwapChain.cpp - GS/Renderers/Vulkan/VKTexture.cpp GS/Renderers/Vulkan/VKUtil.cpp ) list(APPEND pcsx2GSHeaders @@ -661,7 +660,6 @@ if(USE_VULKAN) GS/Renderers/Vulkan/VKShaderCache.h GS/Renderers/Vulkan/VKStreamBuffer.h GS/Renderers/Vulkan/VKSwapChain.h - GS/Renderers/Vulkan/VKTexture.h GS/Renderers/Vulkan/VKUtil.h ) target_link_libraries(PCSX2_FLAGS INTERFACE Vulkan-Headers glslang) @@ -706,7 +704,6 @@ if(WIN32) 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 ) @@ -720,7 +717,6 @@ if(WIN32) 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 ) diff --git a/pcsx2/GS/Renderers/Common/GSTexture.cpp b/pcsx2/GS/Renderers/Common/GSTexture.cpp index d5336a48ce..945180b423 100644 --- a/pcsx2/GS/Renderers/Common/GSTexture.cpp +++ b/pcsx2/GS/Renderers/Common/GSTexture.cpp @@ -76,7 +76,7 @@ u32 GSTexture::GetCompressedBytesPerBlock(Format format) 1, // Invalid 4, // Color/RGBA8 8, // HDRColor/RGBA16 - 32, // DepthStencil + 4, // DepthStencil 1, // UNorm8/R8 2, // UInt16/R16UI 4, // UInt32/R32UI @@ -103,6 +103,19 @@ u32 GSTexture::GetCompressedBlockSize(Format format) return 1; } +u32 GSTexture::CalcUploadPitch(Format format, u32 width) +{ + if (format >= Format::BC1 && format <= Format::BC7) + width = Common::AlignUpPow2(width, 4) / 4; + + return width * GetCompressedBytesPerBlock(format); +} + +u32 GSTexture::CalcUploadPitch(u32 width) const +{ + return CalcUploadPitch(m_format, width); +} + u32 GSTexture::CalcUploadRowLengthFromPitch(u32 pitch) const { return CalcUploadRowLengthFromPitch(m_format, pitch); diff --git a/pcsx2/GS/Renderers/Common/GSTexture.h b/pcsx2/GS/Renderers/Common/GSTexture.h index 9131039a9a..d553797531 100644 --- a/pcsx2/GS/Renderers/Common/GSTexture.h +++ b/pcsx2/GS/Renderers/Common/GSTexture.h @@ -106,11 +106,13 @@ public: static u32 GetCompressedBytesPerBlock(Format format); static u32 GetCompressedBlockSize(Format format); + static u32 CalcUploadPitch(Format format, u32 width); static u32 CalcUploadRowLengthFromPitch(Format format, u32 pitch); static u32 CalcUploadSize(Format format, u32 height, u32 pitch); u32 GetCompressedBytesPerBlock() const; u32 GetCompressedBlockSize() const; + u32 CalcUploadPitch(u32 width) const; u32 CalcUploadRowLengthFromPitch(u32 pitch) const; u32 CalcUploadSize(u32 height, u32 pitch) const; diff --git a/pcsx2/GS/Renderers/DX12/D3D12Context.cpp b/pcsx2/GS/Renderers/DX12/D3D12Context.cpp index 18e11a4425..8da929fa42 100644 --- a/pcsx2/GS/Renderers/DX12/D3D12Context.cpp +++ b/pcsx2/GS/Renderers/DX12/D3D12Context.cpp @@ -668,45 +668,6 @@ bool D3D12Context::AllocatePreinitializedGPUBuffer(u32 size, ID3D12Resource** gp 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) diff --git a/pcsx2/GS/Renderers/DX12/D3D12Context.h b/pcsx2/GS/Renderers/DX12/D3D12Context.h index a0fd7f42f7..abbafbe4c0 100644 --- a/pcsx2/GS/Renderers/DX12/D3D12Context.h +++ b/pcsx2/GS/Renderers/DX12/D3D12Context.h @@ -217,8 +217,6 @@ extern std::unique_ptr g_d3d12_context; namespace D3D12 { - u32 GetTexelSize(DXGI_FORMAT format); - #ifdef _DEBUG void SetObjectName(ID3D12Object* object, const char* name); diff --git a/pcsx2/GS/Renderers/DX12/D3D12Texture.cpp b/pcsx2/GS/Renderers/DX12/D3D12Texture.cpp deleted file mode 100644 index a7dace9f9d..0000000000 --- a/pcsx2/GS/Renderers/DX12/D3D12Texture.cpp +++ /dev/null @@ -1,508 +0,0 @@ -/* 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 . - */ - -#include "PrecompiledHeader.h" - -#include "GS/Renderers/DX12/D3D12Texture.h" -#include "GS/Renderers/DX12/D3D12Context.h" - -#include "common/Align.h" -#include "common/Assertions.h" -#include "common/Console.h" -#include "common/StringUtil.h" - -#include "D3D12MemAlloc.h" - -D3D12Texture::D3D12Texture() = default; - -D3D12Texture::D3D12Texture(ID3D12Resource* resource, D3D12_RESOURCE_STATES state) - : m_resource(std::move(resource)) -{ - const D3D12_RESOURCE_DESC desc = GetDesc(); - m_width = static_cast(desc.Width); - m_height = desc.Height; - m_levels = desc.MipLevels; - m_format = desc.Format; -} - -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) - , m_write_descriptor(texture.m_write_descriptor) - , m_width(texture.m_width) - , m_height(texture.m_height) - , m_levels(texture.m_levels) - , m_format(texture.m_format) - , m_state(texture.m_state) - , m_write_descriptor_type(texture.m_write_descriptor_type) -{ - texture.m_srv_descriptor = {}; - texture.m_write_descriptor = {}; - texture.m_width = 0; - texture.m_height = 0; - texture.m_levels = 0; - texture.m_format = DXGI_FORMAT_UNKNOWN; - texture.m_state = D3D12_RESOURCE_STATE_COMMON; - texture.m_write_descriptor_type = WriteDescriptorType::None; -} - -D3D12Texture::~D3D12Texture() -{ - Destroy(); -} - -D3D12Texture& D3D12Texture::operator=(D3D12Texture&& texture) -{ - Destroy(); - m_resource = std::move(texture.m_resource); - m_allocation = std::move(texture.m_allocation); - m_srv_descriptor = texture.m_srv_descriptor; - m_write_descriptor = texture.m_write_descriptor; - m_width = texture.m_width; - m_height = texture.m_height; - m_levels = texture.m_levels; - m_format = texture.m_format; - m_state = texture.m_state; - m_write_descriptor_type = texture.m_write_descriptor_type; - texture.m_srv_descriptor = {}; - texture.m_write_descriptor = {}; - texture.m_width = 0; - texture.m_height = 0; - texture.m_levels = 0; - texture.m_format = DXGI_FORMAT_UNKNOWN; - texture.m_state = D3D12_RESOURCE_STATE_COMMON; - texture.m_write_descriptor_type = WriteDescriptorType::None; - return *this; -} - -D3D12_RESOURCE_DESC D3D12Texture::GetDesc() const -{ - return m_resource->GetDesc(); -} - -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 = {}; - desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; - desc.Width = width; - desc.Height = height; - desc.DepthOrArraySize = 1; - desc.MipLevels = levels; - desc.Format = format; - desc.SampleDesc.Count = 1; - desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; - desc.Flags = flags; - - D3D12_CLEAR_VALUE optimized_clear_value = {}; - D3D12_RESOURCE_STATES state; - if (rtv_format != DXGI_FORMAT_UNKNOWN) - { - optimized_clear_value.Format = rtv_format; - state = D3D12_RESOURCE_STATE_RENDER_TARGET; - } - else if (dsv_format != DXGI_FORMAT_UNKNOWN) - { - optimized_clear_value.Format = dsv_format; - state = D3D12_RESOURCE_STATE_DEPTH_WRITE; - } - else - { - state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; - } - - D3D12MA::ALLOCATION_DESC allocationDesc = {}; - allocationDesc.Flags = static_cast(alloc_flags) | D3D12MA::ALLOCATION_FLAG_WITHIN_BUDGET; - allocationDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT; - - ComPtr resource; - ComPtr allocation; - 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)) - { - // OOM isn't fatal. - if (hr != E_OUTOFMEMORY) - Console.Error("Create texture failed: 0x%08X", hr); - - return false; - } - - D3D12DescriptorHandle srv_descriptor, write_descriptor; - WriteDescriptorType write_descriptor_type = WriteDescriptorType::None; - if (srv_format != DXGI_FORMAT_UNKNOWN) - { - if (!CreateSRVDescriptor(resource.get(), levels, srv_format, &srv_descriptor)) - return false; - } - - if (rtv_format != DXGI_FORMAT_UNKNOWN) - { - pxAssert(dsv_format == DXGI_FORMAT_UNKNOWN && !(flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)); - 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 = D3D12Texture::WriteDescriptorType::DSV; - if (!CreateDSVDescriptor(resource.get(), dsv_format, &write_descriptor)) - { - g_d3d12_context->GetDSVHeapManager().Free(&srv_descriptor); - return false; - } - } - else if (flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS) - { - write_descriptor_type = D3D12Texture::WriteDescriptorType::UAV; - if (!CreateUAVDescriptor(resource.get(), dsv_format, &write_descriptor)) - { - g_d3d12_context->GetDescriptorHeapManager().Free(&srv_descriptor); - return false; - } - } - - Destroy(true); - - m_resource = std::move(resource); - m_allocation = std::move(allocation); - m_srv_descriptor = std::move(srv_descriptor); - m_write_descriptor = std::move(write_descriptor); - m_width = width; - m_height = height; - m_levels = levels; - m_format = format; - m_state = state; - m_write_descriptor_type = write_descriptor_type; - return true; -} - -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()); - - D3D12DescriptorHandle srv_descriptor, write_descriptor; - WriteDescriptorType write_descriptor_type = WriteDescriptorType::None; - if (srv_format != DXGI_FORMAT_UNKNOWN) - { - if (!CreateSRVDescriptor(texture.get(), desc.MipLevels, srv_format, &srv_descriptor)) - return false; - } - - if (rtv_format != DXGI_FORMAT_UNKNOWN) - { - pxAssert(dsv_format == DXGI_FORMAT_UNKNOWN); - write_descriptor_type = D3D12Texture::WriteDescriptorType::RTV; - if (!CreateRTVDescriptor(texture.get(), rtv_format, &write_descriptor)) - { - g_d3d12_context->GetRTVHeapManager().Free(&srv_descriptor); - return false; - } - } - else if (dsv_format != DXGI_FORMAT_UNKNOWN) - { - write_descriptor_type = D3D12Texture::WriteDescriptorType::DSV; - if (!CreateDSVDescriptor(texture.get(), dsv_format, &write_descriptor)) - { - g_d3d12_context->GetDSVHeapManager().Free(&srv_descriptor); - return false; - } - } - else if (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS) - { - write_descriptor_type = D3D12Texture::WriteDescriptorType::UAV; - if (!CreateUAVDescriptor(texture.get(), srv_format, &write_descriptor)) - { - g_d3d12_context->GetDescriptorHeapManager().Free(&srv_descriptor); - return false; - } - } - - m_resource = std::move(texture); - m_allocation.reset(); - m_srv_descriptor = std::move(srv_descriptor); - m_write_descriptor = std::move(write_descriptor); - m_write_descriptor_type = write_descriptor_type; - m_width = static_cast(desc.Width); - m_height = desc.Height; - m_levels = desc.MipLevels; - m_format = desc.Format; - m_state = state; - return true; -} - -void D3D12Texture::Destroy(bool defer /* = true */) -{ - if (defer) - { - g_d3d12_context->DeferDescriptorDestruction(g_d3d12_context->GetDescriptorHeapManager(), &m_srv_descriptor); - - switch (m_write_descriptor_type) - { - case D3D12Texture::WriteDescriptorType::RTV: - g_d3d12_context->DeferDescriptorDestruction(g_d3d12_context->GetRTVHeapManager(), &m_write_descriptor); - break; - case D3D12Texture::WriteDescriptorType::DSV: - g_d3d12_context->DeferDescriptorDestruction(g_d3d12_context->GetDSVHeapManager(), &m_write_descriptor); - break; - case D3D12Texture::WriteDescriptorType::UAV: - g_d3d12_context->DeferDescriptorDestruction( - g_d3d12_context->GetDescriptorHeapManager(), &m_write_descriptor); - break; - case D3D12Texture::WriteDescriptorType::None: - default: - break; - } - - g_d3d12_context->DeferResourceDestruction(m_allocation.get(), m_resource.get()); - m_resource.reset(); - m_allocation.reset(); - } - else - { - g_d3d12_context->GetDescriptorHeapManager().Free(&m_srv_descriptor); - - switch (m_write_descriptor_type) - { - case D3D12Texture::WriteDescriptorType::RTV: - g_d3d12_context->GetRTVHeapManager().Free(&m_write_descriptor); - break; - case D3D12Texture::WriteDescriptorType::DSV: - g_d3d12_context->GetDSVHeapManager().Free(&m_write_descriptor); - break; - case D3D12Texture::WriteDescriptorType::UAV: - g_d3d12_context->GetDescriptorHeapManager().Free(&m_write_descriptor); - break; - case D3D12Texture::WriteDescriptorType::None: - default: - break; - } - - m_resource.reset(); - m_allocation.reset(); - } - - m_width = 0; - m_height = 0; - m_levels = 0; - m_format = DXGI_FORMAT_UNKNOWN; - m_write_descriptor_type = WriteDescriptorType::None; -} - -void D3D12Texture::TransitionToState(ID3D12GraphicsCommandList* cmdlist, D3D12_RESOURCE_STATES state) -{ - if (m_state == state) - return; - - TransitionSubresourceToState(cmdlist, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, m_state, state); - m_state = state; -} - -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, - {{m_resource.get(), level, before_state, after_state}}}; - cmdlist->ResourceBarrier(1, &barrier); -} - -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 * 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(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; - } - - // cmdlist change - cmdlist = g_d3d12_context->GetInitCommandList(); - } - - *out_data = g_d3d12_context->GetTextureStreamBuffer().GetCurrentHostPointer(); - *out_data_pitch = copy_pitch; - return cmdlist; -} - -void D3D12Texture::EndStreamUpdate(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height) -{ - const u32 copy_pitch = Common::AlignUpPow2(width * D3D12::GetTexelSize(m_format), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); - const u32 upload_size = copy_pitch * height; - - 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 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; - src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - src.PlacedFootprint.Offset = buffer_offset; - src.PlacedFootprint.Footprint.Width = width; - src.PlacedFootprint.Footprint.Height = height; - src.PlacedFootprint.Footprint.Depth = 1; - src.PlacedFootprint.Footprint.RowPitch = pitch; - src.PlacedFootprint.Footprint.Format = m_format; - - D3D12_TEXTURE_COPY_LOCATION dst; - dst.pResource = m_resource.get(); - dst.SubresourceIndex = level; - dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - - const D3D12_BOX src_box{0u, 0u, 0u, width, height, 1u}; - const D3D12_RESOURCE_STATES old_state = m_state; - TransitionToState(cmdlist, D3D12_RESOURCE_STATE_COPY_DEST); - cmdlist->CopyTextureRegion(&dst, x, y, 0, &src, &src_box); - TransitionToState(cmdlist, old_state); -} - -static ID3D12Resource* CreateStagingBuffer(u32 height, const void* data, u32 pitch, u32 upload_pitch, u32 upload_size) -{ - 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, 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); - return nullptr; - } - - void* map; - const D3D12_RANGE read_range = {}; - hr = resource->Map(0, &read_range, &map); - if (FAILED(hr)) - { - Console.Error("Map() for upload staging buffer failed: %08X", hr); - return nullptr; - } - - StringUtil::StrideMemCpy(map, upload_pitch, data, pitch, std::min(pitch, upload_pitch), height); - - const D3D12_RANGE write_range = {0u, upload_size}; - resource->Unmap(0, &write_range); - - // queue them for destruction, since the upload happens in this cmdlist - g_d3d12_context->DeferResourceDestruction(allocation.get(), resource.get()); - - // AddRef()'ed by the defer above. - return resource.get(); -} - -bool D3D12Texture::LoadData( - ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch) -{ - 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()) - { - ID3D12Resource* staging_buffer = CreateStagingBuffer(height, data, pitch, upload_pitch, upload_size); - if (!staging_buffer) - return false; - - CopyFromBuffer(cmdlist, level, x, y, width, height, upload_pitch, staging_buffer, 0); - return true; - } - - void* write_ptr; - u32 write_pitch; - if (!(cmdlist = BeginStreamUpdate(cmdlist, level, x, y, width, height, &write_ptr, &write_pitch))) - return false; - - StringUtil::StrideMemCpy(write_ptr, write_pitch, data, pitch, std::min(pitch, upload_pitch), height); - EndStreamUpdate(cmdlist, level, x, y, width, height); - return true; -} - -bool D3D12Texture::CreateSRVDescriptor( - ID3D12Resource* resource, u32 levels, DXGI_FORMAT format, D3D12DescriptorHandle* dh) -{ - if (!g_d3d12_context->GetDescriptorHeapManager().Allocate(dh)) - { - Console.Error("Failed to allocate SRV descriptor"); - return false; - } - - 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 D3D12Texture::CreateRTVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh) -{ - if (!g_d3d12_context->GetRTVHeapManager().Allocate(dh)) - { - Console.Error("Failed to allocate SRV descriptor"); - return false; - } - - const D3D12_RENDER_TARGET_VIEW_DESC desc = {format, D3D12_RTV_DIMENSION_TEXTURE2D}; - g_d3d12_context->GetDevice()->CreateRenderTargetView(resource, &desc, dh->cpu_handle); - return true; -} - -bool D3D12Texture::CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh) -{ - if (!g_d3d12_context->GetDSVHeapManager().Allocate(dh)) - { - Console.Error("Failed to allocate SRV descriptor"); - return false; - } - - const D3D12_DEPTH_STENCIL_VIEW_DESC desc = {format, D3D12_DSV_DIMENSION_TEXTURE2D, D3D12_DSV_FLAG_NONE}; - g_d3d12_context->GetDevice()->CreateDepthStencilView(resource, &desc, dh->cpu_handle); - return true; -} - -bool D3D12Texture::CreateUAVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh) -{ - if (!g_d3d12_context->GetDescriptorHeapManager().Allocate(dh)) - { - Console.Error("Failed to allocate UAV descriptor"); - return false; - } - - const D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {format, D3D12_UAV_DIMENSION_TEXTURE2D}; - g_d3d12_context->GetDevice()->CreateUnorderedAccessView(resource, nullptr, &desc, dh->cpu_handle); - return true; -} \ No newline at end of file diff --git a/pcsx2/GS/Renderers/DX12/D3D12Texture.h b/pcsx2/GS/Renderers/DX12/D3D12Texture.h deleted file mode 100644 index 6e051d2ce5..0000000000 --- a/pcsx2/GS/Renderers/DX12/D3D12Texture.h +++ /dev/null @@ -1,105 +0,0 @@ -/* 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 a9841e235c..e18c2b297c 100644 --- a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp +++ b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp @@ -37,11 +37,17 @@ #include #include -static bool IsDATMConvertShader(ShaderConvert i) { return (i == ShaderConvert::DATM_0 || i == ShaderConvert::DATM_1); } -static bool IsDATEModePrimIDInit(u32 flag) { return flag == 1 || flag == 2; } +static bool IsDATMConvertShader(ShaderConvert i) +{ + return (i == ShaderConvert::DATM_0 || i == ShaderConvert::DATM_1); +} +static bool IsDATEModePrimIDInit(u32 flag) +{ + return flag == 1 || flag == 2; +} -static constexpr std::array s_primitive_topology_mapping = - {{D3D_PRIMITIVE_TOPOLOGY_POINTLIST, D3D_PRIMITIVE_TOPOLOGY_LINELIST, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST}}; +static constexpr std::array s_primitive_topology_mapping = { + {D3D_PRIMITIVE_TOPOLOGY_POINTLIST, D3D_PRIMITIVE_TOPOLOGY_LINELIST, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST}}; static constexpr std::array s_present_clear_color = {}; @@ -180,9 +186,8 @@ bool GSDevice12::Create() if (!CreateBuffers()) return false; - if (!CompileConvertPipelines() || !CompilePresentPipelines() || - !CompileInterlacePipelines() || !CompileMergePipelines() || - !CompilePostProcessingPipelines()) + if (!CompileConvertPipelines() || !CompilePresentPipelines() || !CompileInterlacePipelines() || + !CompileMergePipelines() || !CompilePostProcessingPipelines()) { Host::ReportErrorAsync("GS", "Failed to compile utility pipelines"); return false; @@ -321,12 +326,12 @@ bool GSDevice12::CreateSwapChain() // Render a frame as soon as possible to clear out whatever was previously being displayed. EndRenderPass(); - D3D12Texture& swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer]; + GSTexture12* swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer].get(); 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); - cmdlist->ClearRenderTargetView(swap_chain_buf.GetWriteDescriptor(), s_present_clear_color.data(), 0, nullptr); - swap_chain_buf.TransitionToState(cmdlist, D3D12_RESOURCE_STATE_PRESENT); + swap_chain_buf->TransitionToState(cmdlist, D3D12_RESOURCE_STATE_RENDER_TARGET); + cmdlist->ClearRenderTargetView(swap_chain_buf->GetWriteDescriptor(), s_present_clear_color.data(), 0, nullptr); + swap_chain_buf->TransitionToState(cmdlist, D3D12_RESOURCE_STATE_PRESENT); ExecuteCommandList(false); m_swap_chain->Present(0, m_using_allow_tearing ? DXGI_PRESENT_ALLOW_TEARING : 0); return true; @@ -350,9 +355,11 @@ bool GSDevice12::CreateSwapChainRTV() return false; } - D3D12Texture tex; - if (!tex.Adopt(std::move(backbuffer), DXGI_FORMAT_UNKNOWN, swap_chain_desc.BufferDesc.Format, - DXGI_FORMAT_UNKNOWN, D3D12_RESOURCE_STATE_PRESENT)) + std::unique_ptr tex = GSTexture12::Adopt(std::move(backbuffer), GSTexture::Type::RenderTarget, + GSTexture::Format::Color, swap_chain_desc.BufferDesc.Width, swap_chain_desc.BufferDesc.Height, 1, + swap_chain_desc.BufferDesc.Format, DXGI_FORMAT_UNKNOWN, swap_chain_desc.BufferDesc.Format, + DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, D3D12_RESOURCE_STATE_COMMON); + if (!tex) { m_swap_chain_buffers.clear(); return false; @@ -387,8 +394,8 @@ bool GSDevice12::CreateSwapChainRTV() void GSDevice12::DestroySwapChainRTVs() { - for (D3D12Texture& buffer : m_swap_chain_buffers) - buffer.Destroy(false); + for (std::unique_ptr& buffer : m_swap_chain_buffers) + buffer->Destroy(false); m_swap_chain_buffers.clear(); m_current_swap_chain_buffer = 0; } @@ -522,12 +529,12 @@ GSDevice::PresentResult GSDevice12::BeginPresent(bool frame_skip) return PresentResult::FrameSkipped; } - D3D12Texture& swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer]; + GSTexture12* swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer].get(); ID3D12GraphicsCommandList* cmdlist = g_d3d12_context->GetCommandList(); - swap_chain_buf.TransitionToState(cmdlist, D3D12_RESOURCE_STATE_RENDER_TARGET); - cmdlist->ClearRenderTargetView(swap_chain_buf.GetWriteDescriptor(), s_present_clear_color.data(), 0, nullptr); - cmdlist->OMSetRenderTargets(1, &swap_chain_buf.GetWriteDescriptor().cpu_handle, FALSE, nullptr); + swap_chain_buf->TransitionToState(cmdlist, D3D12_RESOURCE_STATE_RENDER_TARGET); + cmdlist->ClearRenderTargetView(swap_chain_buf->GetWriteDescriptor(), s_present_clear_color.data(), 0, nullptr); + cmdlist->OMSetRenderTargets(1, &swap_chain_buf->GetWriteDescriptor().cpu_handle, FALSE, nullptr); g_perfmon.Put(GSPerfMon::RenderPasses, 1); const D3D12_VIEWPORT vp{0.0f, 0.0f, static_cast(m_window_info.surface_width), @@ -543,10 +550,10 @@ void GSDevice12::EndPresent() { RenderImGui(); - D3D12Texture& swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer]; + GSTexture12* swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer].get(); 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); + swap_chain_buf->TransitionToState(g_d3d12_context->GetCommandList(), D3D12_RESOURCE_STATE_PRESENT); if (!g_d3d12_context->ExecuteCommandList(D3D12Context::WaitType::None)) { m_device_lost = true; @@ -643,7 +650,10 @@ void GSDevice12::ClearRenderTarget(GSTexture* t, const GSVector4& c) static_cast(t)->SetClearColor(c); } -void GSDevice12::ClearRenderTarget(GSTexture* t, u32 c) { ClearRenderTarget(t, GSVector4::rgba32(c) * (1.0f / 255)); } +void GSDevice12::ClearRenderTarget(GSTexture* t, u32 c) +{ + ClearRenderTarget(t, GSVector4::rgba32(c) * (1.0f / 255)); +} void GSDevice12::InvalidateRenderTarget(GSTexture* t) { @@ -676,25 +686,31 @@ void GSDevice12::ClearStencil(GSTexture* t, u8 c) GSTexture12* dxt = static_cast(t); dxt->TransitionToState(D3D12_RESOURCE_STATE_DEPTH_WRITE); - g_d3d12_context->GetCommandList()->ClearDepthStencilView(dxt->GetRTVOrDSVHandle(), D3D12_CLEAR_FLAG_STENCIL, 0.0f, c, 0, nullptr); + g_d3d12_context->GetCommandList()->ClearDepthStencilView( + dxt->GetWriteDescriptor(), D3D12_CLEAR_FLAG_STENCIL, 0.0f, c, 0, nullptr); } -void GSDevice12::LookupNativeFormat(GSTexture::Format format, DXGI_FORMAT* d3d_format, DXGI_FORMAT* srv_format, DXGI_FORMAT* rtv_format, DXGI_FORMAT* dsv_format) const +void GSDevice12::LookupNativeFormat(GSTexture::Format format, DXGI_FORMAT* d3d_format, DXGI_FORMAT* srv_format, + DXGI_FORMAT* rtv_format, DXGI_FORMAT* dsv_format) const { - static constexpr std::array, static_cast(GSTexture::Format::BC7) + 1> s_format_mapping = {{ - {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN}, // Invalid - {DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN}, // Color - {DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_UNKNOWN}, // HDRColor - {DXGI_FORMAT_D32_FLOAT_S8X24_UINT, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D32_FLOAT_S8X24_UINT}, // DepthStencil - {DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_UNKNOWN}, // UNorm8 - {DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_UNKNOWN}, // UInt16 - {DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_UNKNOWN}, // UInt32 - {DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN}, // Int32 - {DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN}, // BC1 - {DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN}, // BC2 - {DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN}, // BC3 - {DXGI_FORMAT_BC7_UNORM, DXGI_FORMAT_BC7_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN}, // BC7 - }}; + static constexpr std::array, static_cast(GSTexture::Format::BC7) + 1> + s_format_mapping = {{ + {DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN}, // Invalid + {DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_UNKNOWN}, // Color + {DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM, + DXGI_FORMAT_UNKNOWN}, // HDRColor + {DXGI_FORMAT_D32_FLOAT_S8X24_UINT, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, DXGI_FORMAT_UNKNOWN, + DXGI_FORMAT_D32_FLOAT_S8X24_UINT}, // DepthStencil + {DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_UNKNOWN}, // UNorm8 + {DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_UNKNOWN}, // UInt16 + {DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_UNKNOWN}, // UInt32 + {DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN}, // Int32 + {DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN}, // BC1 + {DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN}, // BC2 + {DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN}, // BC3 + {DXGI_FORMAT_BC7_UNORM, DXGI_FORMAT_BC7_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN}, // BC7 + }}; const auto& mapping = s_format_mapping[static_cast(format)]; if (d3d_format) @@ -712,16 +728,20 @@ GSTexture* GSDevice12::CreateSurface(GSTexture::Type type, int width, int height const u32 clamped_width = static_cast(std::clamp(width, 1, D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION)); const u32 clamped_height = static_cast(std::clamp(height, 1, D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION)); - DXGI_FORMAT d3d_format, srv_format, rtv_format, dsv_format; - LookupNativeFormat(format, &d3d_format, &srv_format, &rtv_format, &dsv_format); + DXGI_FORMAT dxgi_format, srv_format, rtv_format, dsv_format; + LookupNativeFormat(format, &dxgi_format, &srv_format, &rtv_format, &dsv_format); - std::unique_ptr tex(GSTexture12::Create(type, clamped_width, clamped_height, levels, format, d3d_format, srv_format, rtv_format, dsv_format)); + const DXGI_FORMAT uav_format = (type == GSTexture::Type::RWTexture) ? dxgi_format : DXGI_FORMAT_UNKNOWN; + + std::unique_ptr tex(GSTexture12::Create(type, format, clamped_width, clamped_height, levels, + dxgi_format, srv_format, rtv_format, dsv_format, uav_format)); if (!tex) { // We're probably out of vram, try flushing the command buffer to release pending textures. PurgePool(); ExecuteCommandListAndRestartRenderPass(true, "Couldn't allocate texture."); - tex = GSTexture12::Create(type, clamped_width, clamped_height, levels, format, d3d_format, srv_format, rtv_format, dsv_format); + tex = GSTexture12::Create(type, format, clamped_width, clamped_height, levels, dxgi_format, srv_format, + rtv_format, dsv_format, uav_format); } return tex.release(); @@ -763,14 +783,14 @@ void GSDevice12::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, if (dTexVK->GetType() != GSTexture::Type::DepthStencil) { dTexVK->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET); - g_d3d12_context->GetCommandList()->ClearRenderTargetView(dTexVK->GetRTVOrDSVHandle(), - sTexVK->GetClearColor().v, 0, nullptr); + g_d3d12_context->GetCommandList()->ClearRenderTargetView( + dTexVK->GetWriteDescriptor(), sTexVK->GetClearColor().v, 0, nullptr); } else { dTexVK->TransitionToState(D3D12_RESOURCE_STATE_DEPTH_WRITE); - g_d3d12_context->GetCommandList()->ClearDepthStencilView(dTexVK->GetRTVOrDSVHandle(), - D3D12_CLEAR_FLAG_DEPTH, sTexVK->GetClearDepth(), 0, 0, nullptr); + g_d3d12_context->GetCommandList()->ClearDepthStencilView( + dTexVK->GetWriteDescriptor(), D3D12_CLEAR_FLAG_DEPTH, sTexVK->GetClearDepth(), 0, 0, nullptr); } return; @@ -806,11 +826,9 @@ void GSDevice12::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, dstloc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; dstloc.SubresourceIndex = 0; - const D3D12_BOX srcbox{static_cast(r.left), static_cast(r.top), 0u, - static_cast(r.right), static_cast(r.bottom), 1u}; - g_d3d12_context->GetCommandList()->CopyTextureRegion( - &dstloc, destX, destY, 0, - &srcloc, &srcbox); + const D3D12_BOX srcbox{static_cast(r.left), static_cast(r.top), 0u, static_cast(r.right), + static_cast(r.bottom), 1u}; + g_d3d12_context->GetCommandList()->CopyTextureRegion(&dstloc, destX, destY, 0, &srcloc, &srcbox); dTexVK->SetState(GSTexture::State::Dirty); } @@ -853,7 +871,8 @@ void GSDevice12::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* m_present[static_cast(shader)].get(), linear, true); } -void GSDevice12::UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize) +void GSDevice12::UpdateCLUTTexture( + GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize) { // match merge cb struct Uniforms @@ -873,7 +892,8 @@ void GSDevice12::UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, u m_convert[static_cast(shader)].get(), false, true); } -void GSDevice12::ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM) +void GSDevice12::ConvertToIndexedTexture( + GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM) { // match merge cb struct Uniforms @@ -1135,9 +1155,10 @@ void GSDevice12::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, static_cast(sTex[1])->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); OMSetRenderTargets(dTex, nullptr, darea); SetUtilityTexture(sTex[1], sampler); - BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE, - D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, - D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, c); + BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR, + D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE, D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, + D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, + D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, c); SetUtilityRootSignature(); SetPipeline(m_convert[static_cast(ShaderConvert::COPY)].get()); DrawStretchRect(sRect[1], PMODE.SLBG ? dRect[2] : dRect[1], dsize); @@ -1186,7 +1207,8 @@ void GSDevice12::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, else if (!InRenderPass()) { OMSetRenderTargets(dTex, nullptr, darea); - BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE); + BeginRenderPass( + D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE); } if (sTex[0] && sTex[0]->GetState() == GSTexture::State::Dirty) @@ -1205,7 +1227,8 @@ void GSDevice12::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, SetPipeline(m_convert[static_cast(ShaderConvert::YUV)].get()); SetUtilityTexture(dTex, sampler); OMSetRenderTargets(sTex[2], nullptr, fbarea); - BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE); + BeginRenderPass( + D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE); DrawStretchRect(full_r, dRect[2], dsize); } @@ -1216,7 +1239,8 @@ void GSDevice12::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, static_cast(dTex)->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); } -void GSDevice12::DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) +void GSDevice12::DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, + ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) { static_cast(dTex)->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET); @@ -1288,9 +1312,7 @@ bool GSDevice12::CompileCASPipelines() if (!cas_source.has_value() || !GetCASShaderSource(&cas_source.value())) return false; - static constexpr D3D_SHADER_MACRO sharpen_only_macros[] = { - {"CAS_SHARPEN_ONLY", "1"}, - {nullptr, nullptr}}; + static constexpr D3D_SHADER_MACRO sharpen_only_macros[] = {{"CAS_SHARPEN_ONLY", "1"}, {nullptr, nullptr}}; const ComPtr cs_upscale(m_shader_cache.GetComputeShader(cas_source.value(), nullptr, "main")); const ComPtr cs_sharpen(m_shader_cache.GetComputeShader(cas_source.value(), sharpen_only_macros, "main")); @@ -1430,8 +1452,8 @@ void GSDevice12::RenderImGui() SetScissor(GSVector4i(clip)); // Since we don't have the GSTexture... - D3D12Texture* tex = static_cast(pcmd->GetTexID()); - D3D12DescriptorHandle handle = tex ? tex->GetSRVDescriptor() : m_null_texture.GetSRVDescriptor(); + GSTexture12* 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; @@ -1455,19 +1477,20 @@ void GSDevice12::RenderImGui() } } -bool GSDevice12::DoCAS(GSTexture* sTex, GSTexture* dTex, bool sharpen_only, const std::array& constants) +bool GSDevice12::DoCAS( + GSTexture* sTex, GSTexture* dTex, bool sharpen_only, const std::array& constants) { EndRenderPass(); GSTexture12* const sTex12 = static_cast(sTex); GSTexture12* const dTex12 = static_cast(dTex); D3D12DescriptorHandle sTexDH, dTexDH; - if (!GetTextureGroupDescriptors(&sTexDH, &sTex12->GetTexture().GetSRVDescriptor(), 1) || - !GetTextureGroupDescriptors(&dTexDH, &dTex12->GetTexture().GetWriteDescriptor(), 1)) + if (!GetTextureGroupDescriptors(&sTexDH, &sTex12->GetSRVDescriptor(), 1) || + !GetTextureGroupDescriptors(&dTexDH, &dTex12->GetUAVDescriptor(), 1)) { ExecuteCommandList(false, "Ran out of descriptors for CAS"); - if (!GetTextureGroupDescriptors(&sTexDH, &sTex12->GetTexture().GetSRVDescriptor(), 1) || - !GetTextureGroupDescriptors(&dTexDH, &dTex12->GetTexture().GetWriteDescriptor(), 1)) + if (!GetTextureGroupDescriptors(&sTexDH, &sTex12->GetSRVDescriptor(), 1) || + !GetTextureGroupDescriptors(&dTexDH, &dTex12->GetUAVDescriptor(), 1)) { Console.Error("Failed to allocate CAS descriptors."); return false; @@ -1475,12 +1498,13 @@ bool GSDevice12::DoCAS(GSTexture* sTex, GSTexture* dTex, bool sharpen_only, cons } ID3D12GraphicsCommandList* const cmdlist = g_d3d12_context->GetCommandList(); - const D3D12_RESOURCE_STATES old_state = sTex12->GetTexture().GetState(); - sTex12->GetTexture().TransitionToState(cmdlist, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); - dTex12->GetTexture().TransitionToState(cmdlist, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + const D3D12_RESOURCE_STATES old_state = sTex12->GetResourceState(); + sTex12->TransitionToState(cmdlist, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE); + dTex12->TransitionToState(cmdlist, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); cmdlist->SetComputeRootSignature(m_cas_root_signature.get()); - cmdlist->SetComputeRoot32BitConstants(CAS_ROOT_SIGNATURE_PARAM_PUSH_CONSTANTS, NUM_CAS_CONSTANTS, constants.data(), 0); + cmdlist->SetComputeRoot32BitConstants( + CAS_ROOT_SIGNATURE_PARAM_PUSH_CONSTANTS, NUM_CAS_CONSTANTS, constants.data(), 0); cmdlist->SetComputeRootDescriptorTable(CAS_ROOT_SIGNATURE_PARAM_SRC_TEXTURE, sTexDH); cmdlist->SetComputeRootDescriptorTable(CAS_ROOT_SIGNATURE_PARAM_DST_TEXTURE, dTexDH); cmdlist->SetPipelineState(sharpen_only ? m_cas_sharpen_pipeline.get() : m_cas_upscale_pipeline.get()); @@ -1491,7 +1515,7 @@ bool GSDevice12::DoCAS(GSTexture* sTex, GSTexture* dTex, bool sharpen_only, cons const int dispatchY = (dTex->GetHeight() + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; cmdlist->Dispatch(dispatchX, dispatchY, 1); - sTex12->GetTexture().TransitionToState(cmdlist, old_state); + sTex12->TransitionToState(cmdlist, old_state); return true; } @@ -1591,8 +1615,7 @@ bool GSDevice12::GetSampler(D3D12DescriptorHandle* cpu_handle, GSHWDrawConfig::S }}; const u8 index = (static_cast(ss.IsMipFilterLinear()) << 2) | - (static_cast(ss.IsMagFilterLinear()) << 1) | - static_cast(ss.IsMinFilterLinear()); + (static_cast(ss.IsMagFilterLinear()) << 1) | static_cast(ss.IsMinFilterLinear()); sd.Filter = filters[index]; } @@ -1625,14 +1648,16 @@ void GSDevice12::ClearSamplerCache() m_dirty_flags |= DIRTY_FLAG_TFX_SAMPLERS; } -bool GSDevice12::GetTextureGroupDescriptors(D3D12DescriptorHandle* gpu_handle, const D3D12DescriptorHandle* 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; if (count == 1) { - g_d3d12_context->GetDevice()->CopyDescriptorsSimple(1, *gpu_handle, cpu_handles[0], D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + g_d3d12_context->GetDevice()->CopyDescriptorsSimple( + 1, *gpu_handle, cpu_handles[0], D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); return true; } @@ -1645,7 +1670,8 @@ bool GSDevice12::GetTextureGroupDescriptors(D3D12DescriptorHandle* gpu_handle, c src_handles[i] = cpu_handles[i]; src_sizes[i] = 1; } - g_d3d12_context->GetDevice()->CopyDescriptors(1, &dst_handle, &count, count, src_handles, src_sizes, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + g_d3d12_context->GetDevice()->CopyDescriptors( + 1, &dst_handle, &count, count, src_handles, src_sizes, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); return true; } @@ -1671,14 +1697,14 @@ GSDevice12::ComPtr GSDevice12::GetUtilityPixelShader(const std::string bool GSDevice12::CreateNullTexture() { - if (!m_null_texture.Create(1, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, - DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, D3D12_RESOURCE_FLAG_NONE)) - { + m_null_texture = + GSTexture12::Create(GSTexture::Type::Texture, GSTexture::Format::Color, 1, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN); + if (!m_null_texture) return false; - } - m_null_texture.TransitionToState(g_d3d12_context->GetCommandList(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); - D3D12::SetObjectName(m_null_texture.GetResource(), "Null texture"); + m_null_texture->TransitionToState(g_d3d12_context->GetCommandList(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + D3D12::SetObjectName(m_null_texture->GetResource(), "Null texture"); return true; } @@ -1838,15 +1864,14 @@ bool GSDevice12::CompileConvertPipelines() for (u32 i = 0; i < 16; i++) { pxAssert(!m_color_copy[i]); - gpb.SetBlendState(0, false, D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, - D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, static_cast(i)); + gpb.SetBlendState(0, false, D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, D3D12_BLEND_ONE, + D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, static_cast(i)); m_color_copy[i] = gpb.Create(g_d3d12_context->GetDevice(), m_shader_cache, false); if (!m_color_copy[i]) return false; - D3D12::SetObjectNameFormatted(m_color_copy[i].get(), - "Color copy pipeline (r=%u, g=%u, b=%u, a=%u)", i & 1u, (i >> 1) & 1u, (i >> 2) & 1u, - (i >> 3) & 1u); + D3D12::SetObjectNameFormatted(m_color_copy[i].get(), "Color copy pipeline (r=%u, g=%u, b=%u, a=%u)", + i & 1u, (i >> 1) & 1u, (i >> 2) & 1u, (i >> 3) & 1u); } } else if (i == ShaderConvert::HDR_INIT || i == ShaderConvert::HDR_RESOLVE) @@ -1863,14 +1888,16 @@ bool GSDevice12::CompileConvertPipelines() if (!arr[ds]) return false; - D3D12::SetObjectNameFormatted(arr[ds].get(), "HDR %s/copy pipeline (ds=%u)", is_setup ? "setup" : "finish", ds); + D3D12::SetObjectNameFormatted( + arr[ds].get(), "HDR %s/copy pipeline (ds=%u)", is_setup ? "setup" : "finish", ds); } } } for (u32 datm = 0; datm < 2; datm++) { - ComPtr ps(GetUtilityPixelShader(*shader, datm ? "ps_stencil_image_init_1" : "ps_stencil_image_init_0")); + ComPtr ps( + GetUtilityPixelShader(*shader, datm ? "ps_stencil_image_init_1" : "ps_stencil_image_init_0")); if (!ps) return false; @@ -1879,8 +1906,8 @@ bool GSDevice12::CompileConvertPipelines() gpb.SetPixelShader(ps.get()); gpb.SetNoDepthTestState(); gpb.SetNoStencilState(); - gpb.SetBlendState(0, false, D3D12_BLEND_ONE, D3D12_BLEND_ONE, D3D12_BLEND_OP_ADD, - D3D12_BLEND_ZERO, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, D3D12_COLOR_WRITE_ENABLE_RED); + gpb.SetBlendState(0, false, D3D12_BLEND_ONE, D3D12_BLEND_ONE, D3D12_BLEND_OP_ADD, D3D12_BLEND_ZERO, + D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, D3D12_COLOR_WRITE_ENABLE_RED); for (u32 ds = 0; ds < 2; ds++) { @@ -1889,7 +1916,8 @@ bool GSDevice12::CompileConvertPipelines() if (!m_date_image_setup_pipelines[ds][datm]) return false; - D3D12::SetObjectNameFormatted(m_date_image_setup_pipelines[ds][datm].get(), "DATE image clear pipeline (ds=%u, datm=%u)", ds, datm); + D3D12::SetObjectNameFormatted( + m_date_image_setup_pipelines[ds][datm].get(), "DATE image clear pipeline (ds=%u, datm=%u)", ds, datm); } } @@ -2000,8 +2028,8 @@ bool GSDevice12::CompileMergePipelines() return false; gpb.SetPixelShader(ps.get()); - gpb.SetBlendState(0, true, D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA, - D3D12_BLEND_OP_ADD, D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD); + gpb.SetBlendState(0, true, D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_OP_ADD, + D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD); m_merge[i] = gpb.Create(g_d3d12_context->GetDevice(), m_shader_cache, false); if (!m_merge[i]) @@ -2115,7 +2143,11 @@ void GSDevice12::DestroyResources() m_utility_root_signature.reset(); m_tfx_root_signature.reset(); - m_null_texture.Destroy(false); + if (m_null_texture) + { + m_null_texture->Destroy(false); + m_null_texture.reset(); + } m_shader_cache.Close(); } @@ -2262,14 +2294,13 @@ GSDevice12::ComPtr GSDevice12::CreateTFXPipeline(const Pipe // DepthStencil if (p.ds) { - static const D3D12_COMPARISON_FUNC ztst[] = { - D3D12_COMPARISON_FUNC_NEVER, D3D12_COMPARISON_FUNC_ALWAYS, D3D12_COMPARISON_FUNC_GREATER_EQUAL, D3D12_COMPARISON_FUNC_GREATER}; + static const D3D12_COMPARISON_FUNC ztst[] = {D3D12_COMPARISON_FUNC_NEVER, D3D12_COMPARISON_FUNC_ALWAYS, + D3D12_COMPARISON_FUNC_GREATER_EQUAL, D3D12_COMPARISON_FUNC_GREATER}; gpb.SetDepthState((p.dss.ztst != ZTST_ALWAYS || p.dss.zwe), p.dss.zwe, ztst[p.dss.ztst]); if (p.dss.date) { const D3D12_DEPTH_STENCILOP_DESC sos{D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, - p.dss.date_one ? D3D12_STENCIL_OP_ZERO : D3D12_STENCIL_OP_KEEP, - D3D12_COMPARISON_FUNC_EQUAL}; + p.dss.date_one ? D3D12_STENCIL_OP_ZERO : D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_EQUAL}; gpb.SetStencilState(true, 1, 1, sos, sos); } } @@ -2304,8 +2335,8 @@ GSDevice12::ComPtr GSDevice12::CreateTFXPipeline(const Pipe } else { - gpb.SetBlendState(0, false, D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, - D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, p.cms.wrgba); + gpb.SetBlendState(0, false, D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, D3D12_BLEND_ONE, + D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, p.cms.wrgba); } ComPtr pipeline(gpb.Create(g_d3d12_context->GetDevice(), m_shader_cache)); @@ -2343,7 +2374,7 @@ bool GSDevice12::BindDrawPipeline(const PipelineSelector& p) void GSDevice12::InitializeState() { for (u32 i = 0; i < NUM_TOTAL_TFX_TEXTURES; i++) - m_tfx_textures[i] = m_null_texture.GetSRVDescriptor(); + m_tfx_textures[i] = m_null_texture->GetSRVDescriptor(); m_tfx_sampler_sel = GSHWDrawConfig::SamplerSelector::Point().key; InvalidateCachedState(); @@ -2403,11 +2434,14 @@ void GSDevice12::ExecuteCommandListAndRestartRenderPass(bool wait_for_completion m_dirty_flags &= ~DIRTY_BASE_STATE; // restart render pass - BeginRenderPass( - m_current_render_target ? D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, - m_current_render_target ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, - m_current_depth_target ? D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, - m_current_depth_target ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS); + BeginRenderPass(m_current_render_target ? D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE : + D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, + m_current_render_target ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : + D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, + m_current_depth_target ? D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE : + D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, + m_current_depth_target ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : + D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS); } } @@ -2431,7 +2465,8 @@ void GSDevice12::InvalidateCachedState() void GSDevice12::SetVertexBuffer(D3D12_GPU_VIRTUAL_ADDRESS buffer, size_t size, size_t stride) { - if (m_vertex_buffer.BufferLocation == buffer && m_vertex_buffer.SizeInBytes == size && m_vertex_buffer.StrideInBytes == stride) + if (m_vertex_buffer.BufferLocation == buffer && m_vertex_buffer.SizeInBytes == size && + m_vertex_buffer.StrideInBytes == stride) return; m_vertex_buffer.BufferLocation = buffer; @@ -2486,9 +2521,9 @@ void GSDevice12::PSSetShaderResource(int i, GSTexture* sr, bool check_state) GSTexture12* dtex = static_cast(sr); if (check_state) { - if (dtex->GetTexture().GetState() != D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE && InRenderPass()) + if (dtex->GetResourceState() != D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE && InRenderPass()) { - // Console.Warning("Ending render pass due to resource transition"); + GL_INS("Ending render pass due to resource transition"); EndRenderPass(); } @@ -2500,7 +2535,7 @@ void GSDevice12::PSSetShaderResource(int i, GSTexture* sr, bool check_state) } else { - handle = m_null_texture.GetSRVDescriptor(); + handle = m_null_texture->GetSRVDescriptor(); } if (m_tfx_textures[i] == handle) @@ -2543,7 +2578,7 @@ void GSDevice12::SetUtilityTexture(GSTexture* dtex, const D3D12DescriptorHandle& } else { - handle = m_null_texture.GetSRVDescriptor(); + handle = m_null_texture->GetSRVDescriptor(); } if (m_utility_texture_cpu != handle) @@ -2575,7 +2610,8 @@ void GSDevice12::SetUtilityTexture(GSTexture* dtex, const D3D12DescriptorHandle& void GSDevice12::SetUtilityPushConstants(const void* data, u32 size) { - g_d3d12_context->GetCommandList()->SetGraphicsRoot32BitConstants(UTILITY_ROOT_SIGNATURE_PARAM_PUSH_CONSTANTS, (size + 3) / sizeof(u32), data, 0); + g_d3d12_context->GetCommandList()->SetGraphicsRoot32BitConstants( + UTILITY_ROOT_SIGNATURE_PARAM_PUSH_CONSTANTS, (size + 3) / sizeof(u32), data, 0); } void GSDevice12::UnbindTexture(GSTexture12* tex) @@ -2584,7 +2620,7 @@ void GSDevice12::UnbindTexture(GSTexture12* tex) { if (m_tfx_textures[i] == tex->GetSRVDescriptor()) { - m_tfx_textures[i] = m_null_texture.GetSRVDescriptor(); + m_tfx_textures[i] = m_null_texture->GetSRVDescriptor(); m_dirty_flags |= DIRTY_FLAG_TFX_TEXTURES; } } @@ -2600,8 +2636,8 @@ void GSDevice12::UnbindTexture(GSTexture12* tex) } } -void GSDevice12::RenderTextureMipmap(const D3D12Texture& texture, - u32 dst_level, u32 dst_width, u32 dst_height, u32 src_level, u32 src_width, u32 src_height) +void GSDevice12::RenderTextureMipmap( + GSTexture12* texture, u32 dst_level, u32 dst_width, u32 dst_height, u32 src_level, u32 src_width, u32 src_height) { EndRenderPass(); @@ -2616,13 +2652,14 @@ void GSDevice12::RenderTextureMipmap(const D3D12Texture& texture, ExecuteCommandList(false); // Setup views. This will be a partial view for the SRV. - D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = {texture.GetFormat(), D3D12_RTV_DIMENSION_TEXTURE2D}; + D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = {texture->GetDXGIFormat(), D3D12_RTV_DIMENSION_TEXTURE2D}; rtv_desc.Texture2D = {dst_level, 0u}; - g_d3d12_context->GetDevice()->CreateRenderTargetView(texture.GetResource(), &rtv_desc, rtv_handle); + g_d3d12_context->GetDevice()->CreateRenderTargetView(texture->GetResource(), &rtv_desc, rtv_handle); - D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {texture.GetFormat(), D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING}; + D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = { + texture->GetDXGIFormat(), D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING}; srv_desc.Texture2D = {src_level, 1u, 0u, 0.0f}; - g_d3d12_context->GetDevice()->CreateShaderResourceView(texture.GetResource(), &srv_desc, srv_handle); + g_d3d12_context->GetDevice()->CreateShaderResourceView(texture->GetResource(), &srv_desc, srv_handle); // We need to set the descriptors up manually, because we're not going through GSTexture. if (!GetTextureGroupDescriptors(&m_utility_texture_gpu, &srv_handle, 1)) @@ -2636,10 +2673,12 @@ void GSDevice12::RenderTextureMipmap(const D3D12Texture& texture, // *now* we don't have to worry about running out of anything. ID3D12GraphicsCommandList* cmdlist = g_d3d12_context->GetCommandList(); - if (texture.GetState() != D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) - texture.TransitionSubresourceToState(cmdlist, src_level, texture.GetState(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); - if (texture.GetState() != D3D12_RESOURCE_STATE_RENDER_TARGET) - texture.TransitionSubresourceToState(cmdlist, dst_level, texture.GetState(), D3D12_RESOURCE_STATE_RENDER_TARGET); + if (texture->GetResourceState() != D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) + texture->TransitionSubresourceToState( + cmdlist, src_level, texture->GetResourceState(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + if (texture->GetResourceState() != D3D12_RESOURCE_STATE_RENDER_TARGET) + texture->TransitionSubresourceToState( + cmdlist, dst_level, texture->GetResourceState(), D3D12_RESOURCE_STATE_RENDER_TARGET); // We set the state directly here. constexpr u32 MODIFIED_STATE = DIRTY_FLAG_VIEWPORT | DIRTY_FLAG_SCISSOR | DIRTY_FLAG_RENDER_TARGET; @@ -2647,7 +2686,7 @@ void GSDevice12::RenderTextureMipmap(const D3D12Texture& texture, // Using a render pass is probably a bit overkill. const D3D12_DISCARD_REGION discard_region = {0u, nullptr, dst_level, 1u}; - cmdlist->DiscardResource(texture.GetResource(), &discard_region); + cmdlist->DiscardResource(texture->GetResource(), &discard_region); cmdlist->OMSetRenderTargets(1, &rtv_handle.cpu_handle, FALSE, nullptr); const D3D12_VIEWPORT vp = {0.0f, 0.0f, static_cast(dst_width), static_cast(dst_height), 0.0f, 1.0f}; @@ -2662,10 +2701,12 @@ void GSDevice12::RenderTextureMipmap(const D3D12Texture& texture, GSVector4(0.0f, 0.0f, static_cast(dst_width), static_cast(dst_height)), GSVector2i(dst_width, dst_height)); - if (texture.GetState() != D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) - texture.TransitionSubresourceToState(cmdlist, src_level, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, texture.GetState()); - if (texture.GetState() != D3D12_RESOURCE_STATE_RENDER_TARGET) - texture.TransitionSubresourceToState(cmdlist, dst_level, D3D12_RESOURCE_STATE_RENDER_TARGET, texture.GetState()); + if (texture->GetResourceState() != D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) + texture->TransitionSubresourceToState( + cmdlist, src_level, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, texture->GetResourceState()); + if (texture->GetResourceState() != D3D12_RESOURCE_STATE_RENDER_TARGET) + texture->TransitionSubresourceToState( + cmdlist, dst_level, D3D12_RESOURCE_STATE_RENDER_TARGET, texture->GetResourceState()); // Must destroy after current cmdlist. g_d3d12_context->DeferDescriptorDestruction(g_d3d12_context->GetDescriptorHeapManager(), &srv_handle); @@ -2680,12 +2721,11 @@ bool GSDevice12::InRenderPass() return m_in_render_pass; } -void GSDevice12::BeginRenderPass( - D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE color_begin, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE color_end, - D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE depth_begin, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE depth_end, - D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE stencil_begin, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE stencil_end, - const GSVector4& clear_color /* = GSVector4::zero() */, float clear_depth /* = 0.0f */, - u8 clear_stencil /* = 0 */) +void GSDevice12::BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE color_begin, + D3D12_RENDER_PASS_ENDING_ACCESS_TYPE color_end, D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE depth_begin, + D3D12_RENDER_PASS_ENDING_ACCESS_TYPE depth_end, D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE stencil_begin, + D3D12_RENDER_PASS_ENDING_ACCESS_TYPE stencil_end, const GSVector4& clear_color /* = GSVector4::zero() */, + float clear_depth /* = 0.0f */, u8 clear_stencil /* = 0 */) { if (m_in_render_pass) EndRenderPass(); @@ -2697,12 +2737,13 @@ void GSDevice12::BeginRenderPass( D3D12_RENDER_PASS_RENDER_TARGET_DESC rt = {}; if (m_current_render_target) { - rt.cpuDescriptor = m_current_render_target->GetRTVOrDSVHandle(); + rt.cpuDescriptor = m_current_render_target->GetWriteDescriptor(); rt.EndingAccess.Type = color_end; rt.BeginningAccess.Type = color_begin; if (color_begin == D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR) { - LookupNativeFormat(m_current_render_target->GetFormat(), nullptr, &rt.BeginningAccess.Clear.ClearValue.Format, nullptr, nullptr); + LookupNativeFormat(m_current_render_target->GetFormat(), nullptr, + &rt.BeginningAccess.Clear.ClearValue.Format, nullptr, nullptr); GSVector4::store(rt.BeginningAccess.Clear.ClearValue.Color, clear_color); } } @@ -2710,26 +2751,27 @@ void GSDevice12::BeginRenderPass( D3D12_RENDER_PASS_DEPTH_STENCIL_DESC ds = {}; if (m_current_depth_target) { - ds.cpuDescriptor = m_current_depth_target->GetRTVOrDSVHandle(); + ds.cpuDescriptor = m_current_depth_target->GetWriteDescriptor(); ds.DepthEndingAccess.Type = depth_end; ds.DepthBeginningAccess.Type = depth_begin; if (depth_begin == D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR) { - LookupNativeFormat(m_current_depth_target->GetFormat(), nullptr, nullptr, nullptr, &ds.DepthBeginningAccess.Clear.ClearValue.Format); + LookupNativeFormat(m_current_depth_target->GetFormat(), nullptr, nullptr, nullptr, + &ds.DepthBeginningAccess.Clear.ClearValue.Format); ds.DepthBeginningAccess.Clear.ClearValue.DepthStencil.Depth = clear_depth; } ds.StencilEndingAccess.Type = stencil_end; ds.StencilBeginningAccess.Type = stencil_begin; if (stencil_begin == D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR) { - LookupNativeFormat(m_current_depth_target->GetFormat(), nullptr, nullptr, nullptr, &ds.StencilBeginningAccess.Clear.ClearValue.Format); + LookupNativeFormat(m_current_depth_target->GetFormat(), nullptr, nullptr, nullptr, + &ds.StencilBeginningAccess.Clear.ClearValue.Format); ds.StencilBeginningAccess.Clear.ClearValue.DepthStencil.Stencil = clear_stencil; } } - g_d3d12_context->GetCommandList()->BeginRenderPass( - m_current_render_target ? 1 : 0, m_current_render_target ? &rt : nullptr, - m_current_depth_target ? &ds : nullptr, D3D12_RENDER_PASS_FLAG_NONE); + g_d3d12_context->GetCommandList()->BeginRenderPass(m_current_render_target ? 1 : 0, + m_current_render_target ? &rt : nullptr, m_current_depth_target ? &ds : nullptr, D3D12_RENDER_PASS_FLAG_NONE); } void GSDevice12::EndRenderPass() @@ -2745,7 +2787,6 @@ void GSDevice12::EndRenderPass() g_perfmon.Put(GSPerfMon::RenderPasses, 1); g_d3d12_context->GetCommandList()->EndRenderPass(); - } void GSDevice12::SetViewport(const D3D12_VIEWPORT& viewport) @@ -2811,12 +2852,12 @@ __ri void GSDevice12::ApplyBaseState(u32 flags, ID3D12GraphicsCommandList* cmdli { if (m_current_render_target) { - cmdlist->OMSetRenderTargets(1, &m_current_render_target->GetRTVOrDSVHandle().cpu_handle, FALSE, - m_current_depth_target ? &m_current_depth_target->GetRTVOrDSVHandle().cpu_handle : nullptr); + cmdlist->OMSetRenderTargets(1, &m_current_render_target->GetWriteDescriptor().cpu_handle, FALSE, + m_current_depth_target ? &m_current_depth_target->GetWriteDescriptor().cpu_handle : nullptr); } else if (m_current_depth_target) { - cmdlist->OMSetRenderTargets(0, nullptr, FALSE, &m_current_depth_target->GetRTVOrDSVHandle().cpu_handle); + cmdlist->OMSetRenderTargets(0, nullptr, FALSE, &m_current_depth_target->GetWriteDescriptor().cpu_handle); } } } @@ -2911,8 +2952,8 @@ bool GSDevice12::ApplyTFXState(bool already_execed) { m_current_root_signature = RootSignature::TFX; flags |= DIRTY_FLAG_VS_CONSTANT_BUFFER_BINDING | DIRTY_FLAG_PS_CONSTANT_BUFFER_BINDING | - DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE | DIRTY_FLAG_SAMPLERS_DESCRIPTOR_TABLE | DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE_2 | - DIRTY_FLAG_PIPELINE; + DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE | DIRTY_FLAG_SAMPLERS_DESCRIPTOR_TABLE | + DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE_2 | DIRTY_FLAG_PIPELINE; cmdlist->SetGraphicsRootSignature(m_tfx_root_signature.get()); } @@ -2998,8 +3039,8 @@ void GSDevice12::SetupDATE(GSTexture* rt, GSTexture* ds, bool datm, const GSVect SetStencilRef(1); BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE, - D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE, - GSVector4::zero(), 0.0f, 0); + D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE, GSVector4::zero(), + 0.0f, 0); if (ApplyUtilityState()) DrawPrimitive(); @@ -3084,9 +3125,8 @@ GSTexture12* GSDevice12::SetupPrimitiveTrackingDATE(GSHWDrawConfig& config, Pipe void GSDevice12::RenderHW(GSHWDrawConfig& config) { // Destination Alpha Setup - const bool stencil_DATE = - (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::Stencil || - config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne); + const bool stencil_DATE = (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::Stencil || + config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne); if (stencil_DATE) SetupDATE(config.rt, config.ds, config.datm, config.drawarea); @@ -3127,7 +3167,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config) const GSVector2i rtsize(config.rt ? config.rt->GetSize() : config.ds->GetSize()); const GSVector4i render_area( config.ps.hdr ? config.drawarea : - GSVector4i(Common::AlignDownPow2(config.scissor.left, render_area_alignment), + GSVector4i(Common::AlignDownPow2(config.scissor.left, render_area_alignment), Common::AlignDownPow2(config.scissor.top, render_area_alignment), std::min(Common::AlignUpPow2(config.scissor.right, render_area_alignment), rtsize.x), std::min(Common::AlignUpPow2(config.scissor.bottom, render_area_alignment), rtsize.y))); @@ -3177,8 +3217,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config) { EndRenderPass(); - GL_PUSH("Copy RT to temp texture for fbmask {%d,%d %dx%d}", - config.drawarea.left, config.drawarea.top, + GL_PUSH("Copy RT to temp texture for fbmask {%d,%d %dx%d}", config.drawarea.left, config.drawarea.top, config.drawarea.width(), config.drawarea.height()); draw_rt_clone->SetState(GSTexture::State::Invalidated); @@ -3218,13 +3257,14 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config) // Begin render pass if new target or out of the area. if (!m_in_render_pass) { - BeginRenderPass( - GetLoadOpForTexture(draw_rt), + BeginRenderPass(GetLoadOpForTexture(draw_rt), draw_rt ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, GetLoadOpForTexture(draw_ds), draw_ds ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, - stencil_DATE ? D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, - stencil_DATE ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, + stencil_DATE ? D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE : + D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, + stencil_DATE ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD : + D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, draw_rt ? draw_rt->GetClearColor() : GSVector4::zero(), draw_ds ? draw_ds->GetClearDepth() : 0.0f, 1); } @@ -3305,7 +3345,8 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config) // if this target was cleared and never drawn to, perform the clear as part of the resolve here. BeginRenderPass(GetLoadOpForTexture(draw_rt), D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE, - GetLoadOpForTexture(draw_ds), draw_ds ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, + GetLoadOpForTexture(draw_ds), + draw_ds ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, draw_rt->GetClearColor(), 0.0f, 0); diff --git a/pcsx2/GS/Renderers/DX12/GSDevice12.h b/pcsx2/GS/Renderers/DX12/GSDevice12.h index 1533df7c08..810870ed4c 100644 --- a/pcsx2/GS/Renderers/DX12/GSDevice12.h +++ b/pcsx2/GS/Renderers/DX12/GSDevice12.h @@ -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; @@ -177,7 +177,8 @@ private: ComPtr m_imgui_pipeline; std::unordered_map> m_tfx_vertex_shaders; - std::unordered_map, GSHWDrawConfig::PSSelectorHash> m_tfx_pixel_shaders; + std::unordered_map, GSHWDrawConfig::PSSelectorHash> + m_tfx_pixel_shaders; std::unordered_map, PipelineSelectorHash> m_tfx_pipelines; ComPtr m_cas_root_signature; @@ -191,26 +192,31 @@ private: ComPtr m_convert_vs; std::string m_tfx_source; - void LookupNativeFormat(GSTexture::Format format, DXGI_FORMAT* d3d_format, DXGI_FORMAT* srv_format, DXGI_FORMAT* rtv_format, DXGI_FORMAT* dsv_format) const; + void LookupNativeFormat(GSTexture::Format format, DXGI_FORMAT* d3d_format, DXGI_FORMAT* srv_format, + DXGI_FORMAT* rtv_format, DXGI_FORMAT* dsv_format) const; bool CreateSwapChain(); bool CreateSwapChainRTV(); void DestroySwapChainRTVs(); void DestroySwapChain(); - GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override; + GSTexture* CreateSurface( + GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override; void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear) final; - void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) final; + void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, + ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) final; void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) final; void DoFXAA(GSTexture* sTex, GSTexture* dTex) final; - bool DoCAS(GSTexture* sTex, GSTexture* dTex, bool sharpen_only, const std::array& constants) final; + bool DoCAS( + GSTexture* sTex, GSTexture* dTex, bool sharpen_only, const std::array& constants) final; bool GetSampler(D3D12DescriptorHandle* cpu_handle, GSHWDrawConfig::SamplerSelector ss); void ClearSamplerCache() final; - bool GetTextureGroupDescriptors(D3D12DescriptorHandle* gpu_handle, const D3D12DescriptorHandle* 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); @@ -289,10 +295,13 @@ public: bool green, bool blue, bool alpha) override; void PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, bool linear) override; - void UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize) override; - void ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM) override; + void UpdateCLUTTexture( + GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize) override; + void ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, + GSTexture* dTex, u32 DBW, u32 DPSM) override; - void DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) override; + void DrawMultiStretchRects( + const MultiStretchRect* rects, u32 num_rects, GSTexture* dTex, ShaderConvert shader) override; void DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, GSTexture12* dTex, ShaderConvert shader); void BeginRenderPassForStretchRect( @@ -347,8 +356,8 @@ public: // Assumes that the previous level has been transitioned to PS resource, // and the current level has been transitioned to RT. - void RenderTextureMipmap(const D3D12Texture& texture, - u32 dst_level, u32 dst_width, u32 dst_height, u32 src_level, u32 src_width, u32 src_height); + void RenderTextureMipmap(GSTexture12* 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. // When Bind() is next called, the pass will be restarted. @@ -401,7 +410,8 @@ private: DIRTY_FLAG_VIEWPORT | DIRTY_FLAG_SCISSOR | DIRTY_FLAG_RENDER_TARGET | DIRTY_FLAG_PIPELINE | DIRTY_FLAG_BLEND_CONSTANTS | DIRTY_FLAG_STENCIL_REF, - DIRTY_TFX_STATE = DIRTY_BASE_STATE | DIRTY_FLAG_TFX_TEXTURES | DIRTY_FLAG_TFX_SAMPLERS | DIRTY_FLAG_TFX_RT_TEXTURES, + DIRTY_TFX_STATE = + DIRTY_BASE_STATE | DIRTY_FLAG_TFX_TEXTURES | DIRTY_FLAG_TFX_SAMPLERS | DIRTY_FLAG_TFX_RT_TEXTURES, DIRTY_UTILITY_STATE = DIRTY_BASE_STATE, DIRTY_CONSTANT_BUFFER_STATE = DIRTY_FLAG_VS_CONSTANT_BUFFER | DIRTY_FLAG_PS_CONSTANT_BUFFER, }; @@ -451,7 +461,7 @@ private: RootSignature m_current_root_signature = RootSignature::Undefined; const ID3D12PipelineState* m_current_pipeline = nullptr; - D3D12Texture m_null_texture; + std::unique_ptr 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 c684632a55..3a1bdf6539 100644 --- a/pcsx2/GS/Renderers/DX12/GSTexture12.cpp +++ b/pcsx2/GS/Renderers/DX12/GSTexture12.cpp @@ -1,5 +1,5 @@ /* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2021 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- @@ -28,99 +28,338 @@ #include "D3D12MemAlloc.h" -GSTexture12::GSTexture12(Type type, Format format, D3D12Texture texture) - : m_texture(std::move(texture)) +GSTexture12::GSTexture12(Type type, Format format, int width, int height, int levels, DXGI_FORMAT dxgi_format, + wil::com_ptr_nothrow resource, wil::com_ptr_nothrow allocation, + const D3D12DescriptorHandle& srv_descriptor, const D3D12DescriptorHandle& write_descriptor, + const D3D12DescriptorHandle& uav_descriptor, WriteDescriptorType wdtype, D3D12_RESOURCE_STATES resource_state) + : m_resource(std::move(resource)) + , m_allocation(std::move(allocation)) + , m_srv_descriptor(srv_descriptor) + , m_write_descriptor(write_descriptor) + , m_uav_descriptor(uav_descriptor) + , m_write_descriptor_type(wdtype) + , m_dxgi_format(dxgi_format) + , m_resource_state(resource_state) { m_type = type; m_format = format; - m_size.x = m_texture.GetWidth(); - m_size.y = m_texture.GetHeight(); - m_mipmap_levels = m_texture.GetLevels(); + m_size.x = width; + m_size.y = height; + m_mipmap_levels = levels; } GSTexture12::~GSTexture12() { - GSDevice12::GetInstance()->UnbindTexture(this); + Destroy(true); } -std::unique_ptr GSTexture12::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) +void GSTexture12::Destroy(bool defer) { + GSDevice12::GetInstance()->UnbindTexture(this); + + if (defer) + { + g_d3d12_context->DeferDescriptorDestruction(g_d3d12_context->GetDescriptorHeapManager(), &m_srv_descriptor); + + switch (m_write_descriptor_type) + { + case WriteDescriptorType::RTV: + g_d3d12_context->DeferDescriptorDestruction(g_d3d12_context->GetRTVHeapManager(), &m_write_descriptor); + break; + case WriteDescriptorType::DSV: + g_d3d12_context->DeferDescriptorDestruction(g_d3d12_context->GetDSVHeapManager(), &m_write_descriptor); + break; + case WriteDescriptorType::None: + default: + break; + } + + if (m_uav_descriptor) + g_d3d12_context->DeferDescriptorDestruction(g_d3d12_context->GetDescriptorHeapManager(), &m_uav_descriptor); + + g_d3d12_context->DeferResourceDestruction(m_allocation.get(), m_resource.get()); + m_resource.reset(); + m_allocation.reset(); + } + else + { + g_d3d12_context->GetDescriptorHeapManager().Free(&m_srv_descriptor); + + switch (m_write_descriptor_type) + { + case WriteDescriptorType::RTV: + g_d3d12_context->GetRTVHeapManager().Free(&m_write_descriptor); + break; + case WriteDescriptorType::DSV: + g_d3d12_context->GetDSVHeapManager().Free(&m_write_descriptor); + break; + case WriteDescriptorType::None: + default: + break; + } + + if (m_uav_descriptor) + g_d3d12_context->GetDescriptorHeapManager().Free(&m_uav_descriptor); + + m_resource.reset(); + m_allocation.reset(); + } + + m_write_descriptor_type = WriteDescriptorType::None; +} + +std::unique_ptr GSTexture12::Create(Type type, Format format, int width, int height, int levels, + DXGI_FORMAT dxgi_format, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format, + DXGI_FORMAT uav_format) +{ + D3D12_RESOURCE_DESC desc = {}; + desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + desc.Width = width; + desc.Height = height; + desc.DepthOrArraySize = 1; + desc.MipLevels = levels; + desc.Format = dxgi_format; + desc.SampleDesc.Count = 1; + desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; + + D3D12MA::ALLOCATION_DESC allocationDesc = {}; + allocationDesc.Flags = D3D12MA::ALLOCATION_FLAG_WITHIN_BUDGET; + allocationDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT; + + D3D12_CLEAR_VALUE optimized_clear_value = {}; + D3D12_RESOURCE_STATES state; + switch (type) { case Type::Texture: { // This is a little annoying. basically, to do mipmap generation, we need to be a render target. // 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; - - D3D12Texture texture; - if (!texture.Create( - width, height, levels, d3d_format, srv_format, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, flags)) - { - return {}; - } - - D3D12::SetObjectNameFormatted(texture.GetResource(), "%ux%u texture", width, height); - return std::make_unique(type, format, std::move(texture)); + desc.Flags = (levels > 1 && !IsCompressedFormat(format)) ? D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET : + D3D12_RESOURCE_FLAG_NONE; + state = D3D12_RESOURCE_STATE_COPY_DEST; } + break; case Type::RenderTarget: { - pxAssert(levels == 1); - // RT's tend to be larger, so we'll keep them committed for speed. - 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 {}; - } - - D3D12::SetObjectNameFormatted(texture.GetResource(), "%ux%u render target", width, height); - return std::make_unique(type, format, std::move(texture)); + pxAssert(levels == 1); + allocationDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED; + desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + optimized_clear_value.Format = rtv_format; + state = D3D12_RESOURCE_STATE_RENDER_TARGET; } + break; case Type::DepthStencil: { pxAssert(levels == 1); - - 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 {}; - } - - D3D12::SetObjectNameFormatted(texture.GetResource(), "%ux%u depth stencil", width, height); - return std::make_unique(type, format, std::move(texture)); + allocationDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED; + desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; + optimized_clear_value.Format = dsv_format; + state = D3D12_RESOURCE_STATE_DEPTH_WRITE; } + break; case Type::RWTexture: { pxAssert(levels == 1); - - 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 {}; - } - - D3D12::SetObjectNameFormatted(texture.GetResource(), "%ux%u RW texture", width, height); - return std::make_unique(type, format, std::move(texture)); + allocationDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED; + state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; } + break; default: return {}; } + + if (uav_format != DXGI_FORMAT_UNKNOWN) + desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + + wil::com_ptr_nothrow resource; + wil::com_ptr_nothrow allocation; + HRESULT hr = g_d3d12_context->GetAllocator()->CreateResource(&allocationDesc, &desc, state, + (type == Type::RenderTarget || type == Type::DepthStencil) ? &optimized_clear_value : nullptr, allocation.put(), + IID_PPV_ARGS(resource.put())); + if (FAILED(hr)) + { + // OOM isn't fatal. + if (hr != E_OUTOFMEMORY) + Console.Error("Create texture failed: 0x%08X", hr); + + return {}; + } + + D3D12DescriptorHandle srv_descriptor, write_descriptor, uav_descriptor; + WriteDescriptorType write_descriptor_type = WriteDescriptorType::None; + if (srv_format != DXGI_FORMAT_UNKNOWN) + { + if (!CreateSRVDescriptor(resource.get(), levels, srv_format, &srv_descriptor)) + return {}; + } + + switch (type) + { + case Type::Texture: + { + D3D12::SetObjectNameFormatted(resource.get(), "%dx%d texture", width, height); + } + break; + + case Type::RenderTarget: + { + D3D12::SetObjectNameFormatted(resource.get(), "%dx%d render target", width, height); + write_descriptor_type = WriteDescriptorType::RTV; + if (!CreateRTVDescriptor(resource.get(), rtv_format, &write_descriptor)) + { + g_d3d12_context->GetRTVHeapManager().Free(&srv_descriptor); + return {}; + } + } + break; + + case Type::DepthStencil: + { + D3D12::SetObjectNameFormatted(resource.get(), "%dx%d depth stencil", width, height); + write_descriptor_type = WriteDescriptorType::DSV; + if (!CreateDSVDescriptor(resource.get(), dsv_format, &write_descriptor)) + { + g_d3d12_context->GetDSVHeapManager().Free(&srv_descriptor); + return {}; + } + } + break; + + case Type::RWTexture: + { + D3D12::SetObjectNameFormatted(resource.get(), "%dx%d RW texture", width, height); + } + break; + + default: + break; + } + + if (uav_format != DXGI_FORMAT_UNKNOWN && !CreateUAVDescriptor(resource.get(), dsv_format, &uav_descriptor)) + { + g_d3d12_context->GetDescriptorHeapManager().Free(&write_descriptor); + g_d3d12_context->GetDescriptorHeapManager().Free(&srv_descriptor); + return {}; + } + + return std::unique_ptr( + new GSTexture12(type, format, width, height, levels, dxgi_format, std::move(resource), std::move(allocation), + srv_descriptor, write_descriptor, uav_descriptor, write_descriptor_type, state)); +} + +std::unique_ptr GSTexture12::Adopt(wil::com_ptr_nothrow resource, Type type, Format format, + int width, int height, int levels, DXGI_FORMAT dxgi_format, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, + DXGI_FORMAT dsv_format, DXGI_FORMAT uav_format, D3D12_RESOURCE_STATES resource_state) +{ + const D3D12_RESOURCE_DESC desc = resource->GetDesc(); + + D3D12DescriptorHandle srv_descriptor, write_descriptor, uav_descriptor; + WriteDescriptorType write_descriptor_type = WriteDescriptorType::None; + if (srv_format != DXGI_FORMAT_UNKNOWN) + { + if (!CreateSRVDescriptor(resource.get(), desc.MipLevels, srv_format, &srv_descriptor)) + return {}; + } + + if (type == Type::RenderTarget) + { + write_descriptor_type = WriteDescriptorType::RTV; + if (!CreateRTVDescriptor(resource.get(), rtv_format, &write_descriptor)) + { + g_d3d12_context->GetRTVHeapManager().Free(&srv_descriptor); + return {}; + } + } + else if (type == Type::DepthStencil) + { + write_descriptor_type = WriteDescriptorType::DSV; + if (!CreateDSVDescriptor(resource.get(), dsv_format, &write_descriptor)) + { + g_d3d12_context->GetDSVHeapManager().Free(&srv_descriptor); + return {}; + } + } + + if (uav_format != DXGI_FORMAT_UNKNOWN) + { + if (!CreateUAVDescriptor(resource.get(), srv_format, &uav_descriptor)) + { + g_d3d12_context->GetDescriptorHeapManager().Free(&write_descriptor); + g_d3d12_context->GetDescriptorHeapManager().Free(&srv_descriptor); + return {}; + } + } + + return std::unique_ptr(new GSTexture12(type, format, static_cast(desc.Width), desc.Height, + desc.MipLevels, desc.Format, std::move(resource), {}, srv_descriptor, write_descriptor, uav_descriptor, + write_descriptor_type, resource_state)); +} + +bool GSTexture12::CreateSRVDescriptor( + ID3D12Resource* resource, u32 levels, DXGI_FORMAT format, D3D12DescriptorHandle* dh) +{ + if (!g_d3d12_context->GetDescriptorHeapManager().Allocate(dh)) + { + Console.Error("Failed to allocate SRV descriptor"); + return false; + } + + 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 GSTexture12::CreateRTVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh) +{ + if (!g_d3d12_context->GetRTVHeapManager().Allocate(dh)) + { + Console.Error("Failed to allocate SRV descriptor"); + return false; + } + + const D3D12_RENDER_TARGET_VIEW_DESC desc = {format, D3D12_RTV_DIMENSION_TEXTURE2D}; + g_d3d12_context->GetDevice()->CreateRenderTargetView(resource, &desc, dh->cpu_handle); + return true; +} + +bool GSTexture12::CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh) +{ + if (!g_d3d12_context->GetDSVHeapManager().Allocate(dh)) + { + Console.Error("Failed to allocate SRV descriptor"); + return false; + } + + const D3D12_DEPTH_STENCIL_VIEW_DESC desc = {format, D3D12_DSV_DIMENSION_TEXTURE2D, D3D12_DSV_FLAG_NONE}; + g_d3d12_context->GetDevice()->CreateDepthStencilView(resource, &desc, dh->cpu_handle); + return true; +} + +bool GSTexture12::CreateUAVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, D3D12DescriptorHandle* dh) +{ + if (!g_d3d12_context->GetDescriptorHeapManager().Allocate(dh)) + { + Console.Error("Failed to allocate UAV descriptor"); + return false; + } + + const D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {format, D3D12_UAV_DIMENSION_TEXTURE2D}; + g_d3d12_context->GetDevice()->CreateUnorderedAccessView(resource, nullptr, &desc, dh->cpu_handle); + return true; } void* GSTexture12::GetNativeHandle() const { - return const_cast(&m_texture); + return const_cast(this); } ID3D12GraphicsCommandList* GSTexture12::GetCommandBufferForUpdate() @@ -198,7 +437,7 @@ bool GSTexture12::Update(const GSVector4i& r, const void* data, int pitch, int l srcloc.PlacedFootprint.Footprint.Width = width; srcloc.PlacedFootprint.Footprint.Height = height; srcloc.PlacedFootprint.Footprint.Depth = 1; - srcloc.PlacedFootprint.Footprint.Format = m_texture.GetFormat(); + srcloc.PlacedFootprint.Footprint.Format = m_dxgi_format; srcloc.PlacedFootprint.Footprint.RowPitch = upload_pitch; // If the texture is larger than half our streaming buffer size, use a separate buffer. @@ -235,10 +474,10 @@ bool GSTexture12::Update(const GSVector4i& r, const void* data, int pitch, int l GL_PUSH("GSTexture12::Update({%d,%d} %dx%d Lvl:%u", r.x, r.y, r.width(), r.height(), layer); // first time the texture is used? don't leave it undefined - 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, layer, m_texture.GetState(), D3D12_RESOURCE_STATE_COPY_DEST); + if (m_resource_state == D3D12_RESOURCE_STATE_COMMON) + TransitionToState(cmdlist, D3D12_RESOURCE_STATE_COPY_DEST); + else if (m_resource_state != D3D12_RESOURCE_STATE_COPY_DEST) + TransitionSubresourceToState(cmdlist, layer, m_resource_state, 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) @@ -250,7 +489,7 @@ bool GSTexture12::Update(const GSVector4i& r, const void* data, int pitch, int l } D3D12_TEXTURE_COPY_LOCATION dstloc; - dstloc.pResource = m_texture.GetResource(); + dstloc.pResource = m_resource.get(); dstloc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; dstloc.SubresourceIndex = layer; @@ -258,8 +497,8 @@ bool GSTexture12::Update(const GSVector4i& r, const void* data, int pitch, int l cmdlist->CopyTextureRegion(&dstloc, Common::AlignDownPow2((u32)r.x, block_size), Common::AlignDownPow2((u32)r.y, block_size), 0, &srcloc, &srcbox); - if (m_texture.GetState() != D3D12_RESOURCE_STATE_COPY_DEST) - m_texture.TransitionSubresourceToState(cmdlist, layer, D3D12_RESOURCE_STATE_COPY_DEST, m_texture.GetState()); + if (m_resource_state != D3D12_RESOURCE_STATE_COPY_DEST) + TransitionSubresourceToState(cmdlist, layer, D3D12_RESOURCE_STATE_COPY_DEST, m_resource_state); if (m_type == Type::Texture) m_needs_mipmaps_generated |= (layer == 0); @@ -273,11 +512,9 @@ bool GSTexture12::Map(GSMap& m, const GSVector4i* r, int layer) return false; // map for writing - m_map_area = r ? *r : GSVector4i(0, 0, m_texture.GetWidth(), m_texture.GetHeight()); + m_map_area = r ? *r : GetRect(); 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(CalcUploadPitch(m_map_area.width()), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); // see note in Update() for the reason why. const u32 required_size = CalcUploadSize(m_map_area.height(), m.pitch); @@ -300,14 +537,12 @@ bool GSTexture12::Map(GSMap& m, const GSVector4i* r, int layer) void GSTexture12::Unmap() { // this can't handle blocks/compressed formats at the moment. - pxAssert(m_map_level < m_texture.GetLevels() && !IsCompressedFormat()); + pxAssert(m_map_level < m_mipmap_levels && !IsCompressedFormat()); g_perfmon.Put(GSPerfMon::TextureUploads, 1); - // 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 width = m_map_area.width(); + const u32 height = m_map_area.height(); + const u32 pitch = Common::AlignUpPow2(CalcUploadPitch(width), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); const u32 required_size = CalcUploadSize(height, pitch); D3D12StreamBuffer& buffer = g_d3d12_context->GetTextureStreamBuffer(); const u32 buffer_offset = buffer.GetCurrentOffset(); @@ -318,11 +553,10 @@ void GSTexture12::Unmap() m_map_area.height(), m_map_level); // first time the texture is used? don't leave it undefined - 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); + if (m_resource_state == D3D12_RESOURCE_STATE_COMMON) + TransitionToState(cmdlist, D3D12_RESOURCE_STATE_COPY_DEST); + else if (m_resource_state != D3D12_RESOURCE_STATE_COPY_DEST) + TransitionSubresourceToState(cmdlist, m_map_level, m_resource_state, 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) @@ -340,20 +574,19 @@ void GSTexture12::Unmap() srcloc.PlacedFootprint.Footprint.Width = width; srcloc.PlacedFootprint.Footprint.Height = height; srcloc.PlacedFootprint.Footprint.Depth = 1; - srcloc.PlacedFootprint.Footprint.Format = m_texture.GetFormat(); + srcloc.PlacedFootprint.Footprint.Format = m_dxgi_format; srcloc.PlacedFootprint.Footprint.RowPitch = pitch; D3D12_TEXTURE_COPY_LOCATION dstloc; - dstloc.pResource = m_texture.GetResource(); + dstloc.pResource = m_resource.get(); dstloc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; dstloc.SubresourceIndex = m_map_level; const D3D12_BOX srcbox{0u, 0u, 0u, width, height, 1}; 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()); + if (m_resource_state != D3D12_RESOURCE_STATE_COPY_DEST) + TransitionSubresourceToState(cmdlist, m_map_level, D3D12_RESOURCE_STATE_COPY_DEST, m_resource_state); if (m_type == Type::Texture) m_needs_mipmaps_generated |= (m_map_level == 0); @@ -372,7 +605,7 @@ void GSTexture12::GenerateMipmap() 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); + this, dst_level, dst_width, dst_height, src_level, src_width, src_height); } SetUsedThisCommandBuffer(); @@ -381,16 +614,39 @@ void GSTexture12::GenerateMipmap() void GSTexture12::Swap(GSTexture* tex) { GSTexture::Swap(tex); - std::swap(m_texture, static_cast(tex)->m_texture); + std::swap(m_resource, static_cast(tex)->m_resource); + std::swap(m_allocation, static_cast(tex)->m_allocation); + std::swap(m_srv_descriptor, static_cast(tex)->m_srv_descriptor); + std::swap(m_write_descriptor, static_cast(tex)->m_write_descriptor); + std::swap(m_write_descriptor_type, static_cast(tex)->m_write_descriptor_type); + std::swap(m_dxgi_format, static_cast(tex)->m_dxgi_format); + std::swap(m_resource_state, static_cast(tex)->m_resource_state); std::swap(m_use_fence_counter, static_cast(tex)->m_use_fence_counter); std::swap(m_clear_value, static_cast(tex)->m_clear_value); - std::swap(m_map_area, static_cast(tex)->m_map_area); std::swap(m_map_level, static_cast(tex)->m_map_level); + std::swap(m_map_area, static_cast(tex)->m_map_area); } void GSTexture12::TransitionToState(D3D12_RESOURCE_STATES state) { - m_texture.TransitionToState(g_d3d12_context->GetCommandList(), state); + TransitionToState(g_d3d12_context->GetCommandList(), state); +} + +void GSTexture12::TransitionToState(ID3D12GraphicsCommandList* cmdlist, D3D12_RESOURCE_STATES state) +{ + if (m_resource_state == state) + return; + + TransitionSubresourceToState(cmdlist, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, m_resource_state, state); + m_resource_state = state; +} + +void GSTexture12::TransitionSubresourceToState(ID3D12GraphicsCommandList* cmdlist, int 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, + {{m_resource.get(), static_cast(level), before_state, after_state}}}; + cmdlist->ResourceBarrier(1, &barrier); } void GSTexture12::CommitClear() @@ -407,14 +663,14 @@ void GSTexture12::CommitClear(ID3D12GraphicsCommandList* cmdlist) { if (IsDepthStencil()) { - m_texture.TransitionToState(cmdlist, D3D12_RESOURCE_STATE_DEPTH_WRITE); + TransitionToState(cmdlist, D3D12_RESOURCE_STATE_DEPTH_WRITE); cmdlist->ClearDepthStencilView( - m_texture.GetWriteDescriptor(), D3D12_CLEAR_FLAG_DEPTH, m_clear_value.depth, 0, 0, nullptr); + GetWriteDescriptor(), D3D12_CLEAR_FLAG_DEPTH, m_clear_value.depth, 0, 0, nullptr); } else { - m_texture.TransitionToState(cmdlist, D3D12_RESOURCE_STATE_RENDER_TARGET); - cmdlist->ClearRenderTargetView(m_texture.GetWriteDescriptor(), m_clear_value.color, 0, nullptr); + TransitionToState(cmdlist, D3D12_RESOURCE_STATE_RENDER_TARGET); + cmdlist->ClearRenderTargetView(GetWriteDescriptor(), m_clear_value.color, 0, nullptr); } SetState(GSTexture::State::Dirty); @@ -498,7 +754,7 @@ void GSDownloadTexture12::CopyFromTexture( dstloc.pResource = m_buffer.get(); dstloc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; dstloc.PlacedFootprint.Offset = copy_offset; - dstloc.PlacedFootprint.Footprint.Format = tex12->GetNativeFormat(); + dstloc.PlacedFootprint.Footprint.Format = tex12->GetDXGIFormat(); dstloc.PlacedFootprint.Footprint.Width = drc.width(); dstloc.PlacedFootprint.Footprint.Height = drc.height(); dstloc.PlacedFootprint.Footprint.Depth = 1; @@ -506,8 +762,7 @@ 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->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), @@ -515,8 +770,7 @@ void GSDownloadTexture12::CopyFromTexture( 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->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 dd5863b403..7ecc511a7a 100644 --- a/pcsx2/GS/Renderers/DX12/GSTexture12.h +++ b/pcsx2/GS/Renderers/DX12/GSTexture12.h @@ -1,5 +1,5 @@ /* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2021 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- @@ -18,23 +18,35 @@ #include "GS/GS.h" #include "GS/Renderers/Common/GSTexture.h" #include "GS/Renderers/DX12/D3D12Context.h" -#include "GS/Renderers/DX12/D3D12Texture.h" +#include "GS/Renderers/DX12/D3D12DescriptorHeapManager.h" + +#include "common/RedtapeWilCom.h" + +#include + +namespace D3D12MA +{ + class Allocation; +} class GSTexture12 final : public GSTexture { public: - 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); + static std::unique_ptr Create(Type type, Format format, int width, int height, int levels, + DXGI_FORMAT dxgi_format, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format, + DXGI_FORMAT uav_format); + static std::unique_ptr Adopt(wil::com_ptr_nothrow resource, Type type, Format format, + int width, int height, int levels, DXGI_FORMAT dxgi_format, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, + DXGI_FORMAT dsv_format, DXGI_FORMAT uav_format, D3D12_RESOURCE_STATES resource_state); - __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(); } + __fi const D3D12DescriptorHandle& GetSRVDescriptor() const { return m_srv_descriptor; } + __fi const D3D12DescriptorHandle& GetWriteDescriptor() const { return m_write_descriptor; } + __fi const D3D12DescriptorHandle& GetUAVDescriptor() const { return m_uav_descriptor; } + __fi D3D12_RESOURCE_STATES GetResourceState() const { return m_resource_state; } + __fi DXGI_FORMAT GetDXGIFormat() const { return m_dxgi_format; } + __fi ID3D12Resource* GetResource() const { return m_resource.get(); } void* GetNativeHandle() const override; @@ -48,22 +60,55 @@ public: void CommitClear(); void CommitClear(ID3D12GraphicsCommandList* cmdlist); + void Destroy(bool defer = true); + + void TransitionToState(ID3D12GraphicsCommandList* cmdlist, D3D12_RESOURCE_STATES state); + void TransitionSubresourceToState(ID3D12GraphicsCommandList* cmdlist, int level, D3D12_RESOURCE_STATES before_state, + D3D12_RESOURCE_STATES after_state) const; + // 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(); } private: + enum class WriteDescriptorType : u8 + { + None, + RTV, + DSV + }; + + GSTexture12(Type type, Format format, int width, int height, int levels, DXGI_FORMAT dxgi_format, + wil::com_ptr_nothrow resource, wil::com_ptr_nothrow allocation, + const D3D12DescriptorHandle& srv_descriptor, const D3D12DescriptorHandle& write_descriptor, + const D3D12DescriptorHandle& uav_descriptor, WriteDescriptorType wdtype, D3D12_RESOURCE_STATES resource_state); + + 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); + 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; - D3D12Texture m_texture; + wil::com_ptr_nothrow m_resource; + wil::com_ptr_nothrow m_allocation; + + D3D12DescriptorHandle m_srv_descriptor = {}; + D3D12DescriptorHandle m_write_descriptor = {}; + D3D12DescriptorHandle m_uav_descriptor = {}; + WriteDescriptorType m_write_descriptor_type = WriteDescriptorType::None; + + DXGI_FORMAT m_dxgi_format = DXGI_FORMAT_UNKNOWN; + D3D12_RESOURCE_STATES m_resource_state = D3D12_RESOURCE_STATE_COMMON; // Contains the fence counter when the texture was last used. // When this matches the current fence counter, the texture was used this command buffer. u64 m_use_fence_counter = 0; + int m_map_level = std::numeric_limits::max(); GSVector4i m_map_area = GSVector4i::zero(); - u32 m_map_level = UINT32_MAX; }; class GSDownloadTexture12 final : public GSDownloadTexture diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp index 60efd2ca6f..e171ecc006 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp @@ -420,19 +420,26 @@ GSDevice::PresentResult GSDeviceVK::BeginPresent(bool frame_skip) VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer(); // Swap chain images start in undefined - VKTexture& swap_chain_texture = m_swap_chain->GetCurrentTexture(); - swap_chain_texture.OverrideImageLayout(VK_IMAGE_LAYOUT_UNDEFINED); - swap_chain_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + GSTextureVK* swap_chain_texture = m_swap_chain->GetCurrentTexture(); + swap_chain_texture->OverrideImageLayout(GSTextureVK::Layout::Undefined); + swap_chain_texture->TransitionToLayout(cmdbuffer, GSTextureVK::Layout::ColorAttachment); + + const VkFramebuffer fb = swap_chain_texture->GetFramebuffer(false); + if (fb == VK_NULL_HANDLE) + return GSDevice::PresentResult::FrameSkipped; const VkRenderPassBeginInfo rp = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, - m_swap_chain->GetClearRenderPass(), m_swap_chain->GetCurrentFramebuffer(), - {{0, 0}, {swap_chain_texture.GetWidth(), swap_chain_texture.GetHeight()}}, 1u, &s_present_clear_color}; + g_vulkan_context->GetRenderPass(swap_chain_texture->GetVkFormat(), VK_FORMAT_UNDEFINED, + VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE), + fb, + {{0, 0}, {static_cast(swap_chain_texture->GetWidth()), static_cast(swap_chain_texture->GetHeight())}}, + 1u, &s_present_clear_color}; vkCmdBeginRenderPass(g_vulkan_context->GetCurrentCommandBuffer(), &rp, VK_SUBPASS_CONTENTS_INLINE); - const VkViewport vp{0.0f, 0.0f, static_cast(swap_chain_texture.GetWidth()), - static_cast(swap_chain_texture.GetHeight()), 0.0f, 1.0f}; + const VkViewport vp{0.0f, 0.0f, static_cast(swap_chain_texture->GetWidth()), + static_cast(swap_chain_texture->GetHeight()), 0.0f, 1.0f}; const VkRect2D scissor{ - {0, 0}, {static_cast(swap_chain_texture.GetWidth()), static_cast(swap_chain_texture.GetHeight())}}; + {0, 0}, {static_cast(swap_chain_texture->GetWidth()), static_cast(swap_chain_texture->GetHeight())}}; vkCmdSetViewport(g_vulkan_context->GetCurrentCommandBuffer(), 0, 1, &vp); vkCmdSetScissor(g_vulkan_context->GetCurrentCommandBuffer(), 0, 1, &scissor); return PresentResult::OK; @@ -444,7 +451,7 @@ void GSDeviceVK::EndPresent() VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer(); vkCmdEndRenderPass(g_vulkan_context->GetCurrentCommandBuffer()); - m_swap_chain->GetCurrentTexture().TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + m_swap_chain->GetCurrentTexture()->TransitionToLayout(cmdbuffer, GSTextureVK::Layout::PresentSrc); g_perfmon.Put(GSPerfMon::RenderPasses, 1); g_vulkan_context->SubmitCommandBuffer(m_swap_chain.get(), !m_swap_chain->IsPresentModeSynchronizing()); @@ -811,7 +818,7 @@ void GSDeviceVK::ClearStencil(GSTexture* t, u8 c) EndRenderPass(); - static_cast(t)->TransitionToLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + static_cast(t)->TransitionToLayout(GSTextureVK::Layout::ClearDst); const VkClearDepthStencilValue dsv{0.0f, static_cast(c)}; const VkImageSubresourceRange srr{VK_IMAGE_ASPECT_STENCIL_BIT, 0u, 1u, 0u, 1u}; @@ -819,7 +826,7 @@ void GSDeviceVK::ClearStencil(GSTexture* t, u8 c) vkCmdClearDepthStencilImage(g_vulkan_context->GetCurrentCommandBuffer(), static_cast(t)->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &dsv, 1, &srr); - static_cast(t)->TransitionToLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + static_cast(t)->TransitionToLayout(GSTextureVK::Layout::DepthStencilAttachment); } VkFormat GSDeviceVK::LookupNativeFormat(GSTexture::Format format) const @@ -849,13 +856,13 @@ GSTexture* GSDeviceVK::CreateSurface(GSTexture::Type type, int width, int height const u32 clamped_width = static_cast(std::clamp(width, 1, g_vulkan_context->GetMaxImageDimension2D())); const u32 clamped_height = static_cast(std::clamp(height, 1, g_vulkan_context->GetMaxImageDimension2D())); - std::unique_ptr tex(GSTextureVK::Create(type, clamped_width, clamped_height, levels, format, LookupNativeFormat(format))); + std::unique_ptr tex(GSTextureVK::Create(type, format, clamped_width, clamped_height, levels)); if (!tex) { // We're probably out of vram, try flushing the command buffer to release pending textures. PurgePool(); ExecuteCommandBufferAndRestartRenderPass(true, "Couldn't allocate texture."); - tex = GSTextureVK::Create(type, clamped_width, clamped_height, levels, format, LookupNativeFormat(format)); + tex = GSTextureVK::Create(type, format, clamped_width, clamped_height, levels); } return tex.release(); @@ -941,15 +948,15 @@ void GSDeviceVK::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, EndRenderPass(); - dTexVK->TransitionToLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + dTexVK->TransitionToLayout(GSTextureVK::Layout::TransferDst); dTexVK->SetUsedThisCommandBuffer(); - sTexVK->TransitionToLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + sTexVK->TransitionToLayout(GSTextureVK::Layout::TransferSrc); sTexVK->SetUsedThisCommandBuffer(); #ifdef PCSX2_DEVBUILD // ensure we don't leave this bound later on, debug layer gets cranky - if (m_tfx_textures[0] == sTexVK->GetTexturePtr()) + if (m_tfx_textures[0] == sTexVK) PSSetShaderResource(0, nullptr, false); #endif @@ -1013,10 +1020,10 @@ void GSDeviceVK::DrawMultiStretchRects( { GSTextureVK* const stex = static_cast(rects[i].src); stex->CommitClear(); - if (stex->GetLayout() != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + if (stex->GetLayout() != GSTextureVK::Layout::ShaderReadOnly) { EndRenderPass(); - stex->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + stex->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly); } } @@ -1140,7 +1147,7 @@ void GSDeviceVK::BeginRenderPassForStretchRect( else { // integer formats, etc - const VkRenderPass rp = g_vulkan_context->GetRenderPass(dTex->GetNativeFormat(), VK_FORMAT_UNDEFINED, + const VkRenderPass rp = g_vulkan_context->GetRenderPass(dTex->GetVkFormat(), VK_FORMAT_UNDEFINED, load_op, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE); if (load_op == VK_ATTACHMENT_LOAD_OP_CLEAR) { @@ -1156,11 +1163,11 @@ void GSDeviceVK::BeginRenderPassForStretchRect( void GSDeviceVK::DoStretchRect(GSTextureVK* sTex, const GSVector4& sRect, GSTextureVK* dTex, const GSVector4& dRect, VkPipeline pipeline, bool linear, bool allow_discard) { - if (sTex->GetLayout() != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + if (sTex->GetLayout() != GSTextureVK::Layout::ShaderReadOnly) { // can't transition in a render pass EndRenderPass(); - sTex->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + sTex->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly); } SetUtilityTexture(sTex, linear ? m_linear_sampler : m_point_sampler); @@ -1220,11 +1227,11 @@ void GSDeviceVK::BlitRect(GSTexture* sTex, const GSVector4i& sRect, u32 sLevel, EndRenderPass(); - sTexVK->TransitionToLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - dTexVK->TransitionToLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + sTexVK->TransitionToLayout(GSTextureVK::Layout::TransferSrc); + dTexVK->TransitionToLayout(GSTextureVK::Layout::TransferDst); // ensure we don't leave this bound later on - if (m_tfx_textures[0] == sTexVK->GetTexturePtr()) + if (m_tfx_textures[0] == sTexVK) PSSetShaderResource(0, nullptr, false); pxAssert( @@ -1234,9 +1241,9 @@ void GSDeviceVK::BlitRect(GSTexture* sTex, const GSVector4i& sRect, u32 sLevel, const VkImageBlit ib{{aspect, sLevel, 0u, 1u}, {{sRect.left, sRect.top, 0}, {sRect.right, sRect.bottom, 1}}, {aspect, dLevel, 0u, 1u}, {{dRect.left, dRect.top, 0}, {dRect.right, dRect.bottom, 1}}}; - vkCmdBlitImage(g_vulkan_context->GetCurrentCommandBuffer(), sTexVK->GetTexture().GetImage(), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dTexVK->GetTexture().GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, - &ib, linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST); + vkCmdBlitImage(g_vulkan_context->GetCurrentCommandBuffer(), sTexVK->GetImage(), + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dTexVK->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &ib, + linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST); } void GSDeviceVK::UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize) @@ -1295,9 +1302,9 @@ void GSDeviceVK::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, EndRenderPass(); // transition everything before starting the new render pass - static_cast(dTex)->TransitionToLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + static_cast(dTex)->TransitionToLayout(GSTextureVK::Layout::ColorAttachment); if (sTex[0]) - static_cast(sTex[0])->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + static_cast(sTex[0])->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly); const GSVector2i dsize(dTex->GetSize()); const GSVector4i darea(0, 0, dsize.x, dsize.y); @@ -1308,7 +1315,7 @@ void GSDeviceVK::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, // Note: value outside of dRect must contains the background color (c) if (sTex[1]->GetState() == GSTexture::State::Dirty) { - static_cast(sTex[1])->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + static_cast(sTex[1])->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly); OMSetRenderTargets(dTex, nullptr, darea); SetUtilityTexture(sTex[1], sampler); BeginClearRenderPass(m_utility_color_render_pass_clear, darea, c); @@ -1341,7 +1348,7 @@ void GSDeviceVK::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, if (sTex[0] == sTex[2]) { // need a barrier here because of the render pass - static_cast(sTex[2])->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + static_cast(sTex[2])->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly); } } @@ -1383,12 +1390,12 @@ void GSDeviceVK::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, // this texture is going to get used as an input, so make sure we don't read undefined data static_cast(dTex)->CommitClear(); - static_cast(dTex)->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + static_cast(dTex)->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly); } void GSDeviceVK::DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) { - static_cast(dTex)->TransitionToLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + static_cast(dTex)->TransitionToLayout(GSTextureVK::Layout::ColorAttachment); const GSVector4i rc = GSVector4i(dRect); const GSVector4i dtex_rc = dTex->GetRect(); @@ -1402,7 +1409,7 @@ void GSDeviceVK::DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* DrawStretchRect(sRect, dRect, dTex->GetSize()); EndRenderPass(); - static_cast(dTex)->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + static_cast(dTex)->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly); } void GSDeviceVK::DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) @@ -1419,7 +1426,7 @@ void GSDeviceVK::DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float para DrawStretchRect(sRect, GSVector4(dRect), dTex->GetSize()); EndRenderPass(); - static_cast(dTex)->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + static_cast(dTex)->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly); } void GSDeviceVK::DoFXAA(GSTexture* sTex, GSTexture* dTex) @@ -1435,7 +1442,7 @@ void GSDeviceVK::DoFXAA(GSTexture* sTex, GSTexture* dTex) DrawStretchRect(sRect, GSVector4(dRect), dTex->GetSize()); EndRenderPass(); - static_cast(dTex)->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + static_cast(dTex)->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly); } void GSDeviceVK::IASetVertexBuffer(const void* vertex, size_t stride, size_t count) @@ -1506,18 +1513,18 @@ void GSDeviceVK::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector if (vkRt) { vkRt->TransitionToLayout((feedback_loop & FeedbackLoopFlag_ReadAndWriteRT) ? - VK_IMAGE_LAYOUT_GENERAL : - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + GSTextureVK::Layout::FeedbackLoop : + GSTextureVK::Layout::ColorAttachment); } if (vkDs) { // need to update descriptors to reflect the new layout - if ((feedback_loop & FeedbackLoopFlag_ReadDS) && vkDs->GetLayout() != VK_IMAGE_LAYOUT_GENERAL) + if ((feedback_loop & FeedbackLoopFlag_ReadDS) && vkDs->GetLayout() != GSTextureVK::Layout::FeedbackLoop) m_dirty_flags |= DIRTY_FLAG_TFX_SAMPLERS_DS; vkDs->TransitionToLayout((feedback_loop & FeedbackLoopFlag_ReadDS) ? - VK_IMAGE_LAYOUT_GENERAL : - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + GSTextureVK::Layout::FeedbackLoop : + GSTextureVK::Layout::DepthStencilAttachment); } } @@ -1653,21 +1660,18 @@ VkShaderModule GSDeviceVK::GetUtilityFragmentShader(const std::string& source, c bool GSDeviceVK::CreateNullTexture() { - if (!m_null_texture.Create(1, 1, 1, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D, - VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) - { + m_null_texture = GSTextureVK::Create(GSTexture::Type::RenderTarget, GSTexture::Format::Color, 1, 1, 1); + if (!m_null_texture) return false; - } const VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer(); const VkImageSubresourceRange srr{VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}; const VkClearColorValue ccv{}; - m_null_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - vkCmdClearColorImage(cmdbuf, m_null_texture.GetImage(), m_null_texture.GetLayout(), &ccv, 1, &srr); - m_null_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_GENERAL); - Vulkan::SetObjectName(g_vulkan_context->GetDevice(), m_null_texture.GetImage(), "Null texture"); - Vulkan::SetObjectName(g_vulkan_context->GetDevice(), m_null_texture.GetView(), "Null texture view"); + m_null_texture->TransitionToLayout(cmdbuf, GSTextureVK::Layout::ClearDst); + vkCmdClearColorImage(cmdbuf, m_null_texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &ccv, 1, &srr); + m_null_texture->TransitionToLayout(cmdbuf, GSTextureVK::Layout::General); + Vulkan::SetObjectName(g_vulkan_context->GetDevice(), m_null_texture->GetImage(), "Null texture"); + Vulkan::SetObjectName(g_vulkan_context->GetDevice(), m_null_texture->GetView(), "Null texture view"); return true; } @@ -2040,9 +2044,8 @@ bool GSDeviceVK::CompileConvertPipelines() bool GSDeviceVK::CompilePresentPipelines() { // we may not have a swap chain if running in headless mode. - m_swap_chain_render_pass = m_swap_chain ? - m_swap_chain->GetClearRenderPass() : - g_vulkan_context->GetRenderPass(VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_UNDEFINED); + m_swap_chain_render_pass = g_vulkan_context->GetRenderPass( + m_swap_chain ? m_swap_chain->GetTextureFormat() : VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_UNDEFINED); if (m_swap_chain_render_pass == VK_NULL_HANDLE) return false; @@ -2439,12 +2442,9 @@ void GSDeviceVK::RenderImGui() SetScissor(GSVector4i(clip).max_i32(GSVector4i::zero())); // Since we don't have the GSTexture... - VKTexture* tex = static_cast(pcmd->GetTexID()); - if (m_utility_texture != tex) - { - m_utility_texture = tex; - m_dirty_flags |= DIRTY_FLAG_UTILITY_TEXTURE; - } + GSTextureVK* tex = static_cast(pcmd->GetTexID()); + if (tex) + SetUtilityTexture(tex, m_linear_sampler); if (ApplyUtilityState()) { @@ -2467,13 +2467,13 @@ void GSDeviceVK::RenderBlankFrame() } VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer(); - VKTexture& sctex = m_swap_chain->GetCurrentTexture(); - sctex.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + GSTextureVK* sctex = m_swap_chain->GetCurrentTexture(); + sctex->TransitionToLayout(cmdbuffer, GSTextureVK::Layout::TransferDst); constexpr VkImageSubresourceRange srr = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; - vkCmdClearColorImage(cmdbuffer, sctex.GetImage(), sctex.GetLayout(), &s_present_clear_color.color, 1, &srr); + vkCmdClearColorImage(cmdbuffer, sctex->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &s_present_clear_color.color, 1, &srr); - m_swap_chain->GetCurrentTexture().TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + m_swap_chain->GetCurrentTexture()->TransitionToLayout(cmdbuffer, GSTextureVK::Layout::PresentSrc); g_vulkan_context->SubmitCommandBuffer(m_swap_chain.get(), !m_swap_chain->IsPresentModeSynchronizing()); g_vulkan_context->MoveToNextCommandBuffer(); @@ -2492,29 +2492,13 @@ bool GSDeviceVK::DoCAS(GSTexture* sTex, GSTexture* dTex, bool sharpen_only, cons GSTextureVK* const dTexVK = static_cast(dTex); VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer(); - sTexVK->GetTexture().TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - // we have to make the barrier explicit here, because there's no free enums for us to use (general already hijacked) - const VkImageMemoryBarrier barrier_to_cs = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - nullptr, - VK_ACCESS_SHADER_READ_BIT, - VK_ACCESS_SHADER_WRITE_BIT, - dTexVK->GetLayout(), - VK_IMAGE_LAYOUT_GENERAL, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED, - dTexVK->GetImage(), - {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}, - }; - vkCmdPipelineBarrier(cmdbuf, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, - 0, 0, nullptr, 0, nullptr, 1, &barrier_to_cs); - dTexVK->GetTexture().OverrideImageLayout(VK_IMAGE_LAYOUT_GENERAL); + sTexVK->TransitionToLayout(cmdbuf, GSTextureVK::Layout::ShaderReadOnly); + dTexVK->TransitionToLayout(cmdbuf, GSTextureVK::Layout::ComputeReadWriteImage); // only happening once a frame, so the update isn't a huge deal. Vulkan::DescriptorSetUpdateBuilder dsub; - dsub.AddImageDescriptorWrite(ds, 0, sTexVK->GetView(), sTexVK->GetLayout()); - dsub.AddStorageImageDescriptorWrite(ds, 1, dTexVK->GetView(), dTexVK->GetLayout()); + dsub.AddImageDescriptorWrite(ds, 0, sTexVK->GetView(), sTexVK->GetVkLayout()); + dsub.AddStorageImageDescriptorWrite(ds, 1, dTexVK->GetView(), dTexVK->GetVkLayout()); dsub.Update(g_vulkan_context->GetDevice(), false); // the actual meat and potatoes! only four commands. @@ -2527,22 +2511,7 @@ bool GSDeviceVK::DoCAS(GSTexture* sTex, GSTexture* dTex, bool sharpen_only, cons vkCmdBindPipeline(cmdbuf, VK_PIPELINE_BIND_POINT_COMPUTE, m_cas_pipelines[static_cast(sharpen_only)]); vkCmdDispatch(cmdbuf, dispatchX, dispatchY, 1); - // and same deal here :( - const VkImageMemoryBarrier barrier_to_fs = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - nullptr, - VK_ACCESS_SHADER_WRITE_BIT, - VK_ACCESS_SHADER_READ_BIT, - VK_IMAGE_LAYOUT_GENERAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_QUEUE_FAMILY_IGNORED, - VK_QUEUE_FAMILY_IGNORED, - dTexVK->GetImage(), - {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}, - }; - vkCmdPipelineBarrier(cmdbuf, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, - 0, 0, nullptr, 0, nullptr, 1, &barrier_to_fs); - dTexVK->GetTexture().OverrideImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + dTexVK->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly); // all done! return true; @@ -2551,8 +2520,8 @@ bool GSDeviceVK::DoCAS(GSTexture* sTex, GSTexture* dTex, bool sharpen_only, cons void GSDeviceVK::DestroyResources() { g_vulkan_context->ExecuteCommandBuffer(VKContext::WaitType::Sleep); - if (m_tfx_descriptor_sets[0] != VK_NULL_HANDLE) - g_vulkan_context->FreeGlobalDescriptorSet(m_tfx_descriptor_sets[0]); + if (m_tfx_ubo_descriptor_set != VK_NULL_HANDLE) + g_vulkan_context->FreeGlobalDescriptorSet(m_tfx_ubo_descriptor_set); for (auto& it : m_tfx_pipelines) Vulkan::SafeDestroyPipeline(it.second); @@ -2627,7 +2596,11 @@ void GSDeviceVK::DestroyResources() Vulkan::SafeDestroyPipelineLayout(m_utility_pipeline_layout); Vulkan::SafeDestroyDescriptorSetLayout(m_utility_ds_layout); - m_null_texture.Destroy(false); + if (m_null_texture) + { + m_null_texture->Destroy(false); + m_null_texture.reset(); + } } VkShaderModule GSDeviceVK::GetTFXVertexShader(GSHWDrawConfig::VSSelector sel) @@ -2882,9 +2855,9 @@ void GSDeviceVK::InitializeState() m_current_render_pass = VK_NULL_HANDLE; for (u32 i = 0; i < NUM_TFX_TEXTURES; i++) - m_tfx_textures[i] = &m_null_texture; + m_tfx_textures[i] = m_null_texture.get(); - m_utility_texture = &m_null_texture; + m_utility_texture = m_null_texture.get(); m_point_sampler = GetSampler(GSHWDrawConfig::SamplerSelector::Point()); if (m_point_sampler) @@ -2905,20 +2878,20 @@ bool GSDeviceVK::CreatePersistentDescriptorSets() Vulkan::DescriptorSetUpdateBuilder dsub; // Allocate UBO descriptor sets for TFX. - m_tfx_descriptor_sets[0] = g_vulkan_context->AllocatePersistentDescriptorSet(m_tfx_ubo_ds_layout); - if (m_tfx_descriptor_sets[0] == VK_NULL_HANDLE) + m_tfx_ubo_descriptor_set = g_vulkan_context->AllocatePersistentDescriptorSet(m_tfx_ubo_ds_layout); + if (m_tfx_ubo_descriptor_set == VK_NULL_HANDLE) return false; - dsub.AddBufferDescriptorWrite(m_tfx_descriptor_sets[0], 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + dsub.AddBufferDescriptorWrite(m_tfx_ubo_descriptor_set, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, m_vertex_uniform_stream_buffer.GetBuffer(), 0, sizeof(GSHWDrawConfig::VSConstantBuffer)); - dsub.AddBufferDescriptorWrite(m_tfx_descriptor_sets[0], 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + dsub.AddBufferDescriptorWrite(m_tfx_ubo_descriptor_set, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, m_fragment_uniform_stream_buffer.GetBuffer(), 0, sizeof(GSHWDrawConfig::PSConstantBuffer)); if (m_features.vs_expand) { - dsub.AddBufferDescriptorWrite(m_tfx_descriptor_sets[0], 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + dsub.AddBufferDescriptorWrite(m_tfx_ubo_descriptor_set, 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, m_vertex_stream_buffer.GetBuffer(), 0, VERTEX_BUFFER_SIZE); } dsub.Update(dev); - Vulkan::SetObjectName(dev, m_tfx_descriptor_sets[0], "Persistent TFX UBO set"); + Vulkan::SetObjectName(dev, m_tfx_ubo_descriptor_set, "Persistent TFX UBO set"); return true; } @@ -3003,16 +2976,16 @@ void GSDeviceVK::InvalidateCachedState() m_dirty_flags |= DIRTY_FLAG_INDEX_BUFFER; for (u32 i = 0; i < NUM_TFX_TEXTURES; i++) - m_tfx_textures[i] = &m_null_texture; - m_utility_texture = &m_null_texture; + m_tfx_textures[i] = m_null_texture.get(); + m_utility_texture = m_null_texture.get(); m_current_framebuffer = VK_NULL_HANDLE; m_current_render_target = nullptr; m_current_depth_target = nullptr; m_current_framebuffer_feedback_loop = FeedbackLoopFlag_None; m_current_pipeline_layout = PipelineLayout::Undefined; - m_tfx_descriptor_sets[1] = VK_NULL_HANDLE; - m_tfx_descriptor_sets[2] = VK_NULL_HANDLE; + m_tfx_texture_descriptor_set = VK_NULL_HANDLE; + m_tfx_rt_descriptor_set = VK_NULL_HANDLE; m_utility_descriptor_set = VK_NULL_HANDLE; } @@ -3048,33 +3021,31 @@ void GSDeviceVK::SetBlendConstants(u8 color) void GSDeviceVK::PSSetShaderResource(int i, GSTexture* sr, bool check_state) { - const VKTexture* tex; - if (sr) + GSTextureVK* vkTex = static_cast(sr); + if (vkTex) { - GSTextureVK* vkTex = static_cast(sr); if (check_state) { - if (vkTex->GetTexture().GetLayout() != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL && InRenderPass()) + if (vkTex->GetLayout() != GSTextureVK::Layout::ShaderReadOnly && InRenderPass()) { GL_INS("Ending render pass due to resource transition"); EndRenderPass(); } vkTex->CommitClear(); - vkTex->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + vkTex->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly); } vkTex->SetUsedThisCommandBuffer(); - tex = vkTex->GetTexturePtr(); } else { - tex = &m_null_texture; + vkTex = m_null_texture.get(); } - if (m_tfx_textures[i] == tex) + if (m_tfx_textures[i] == vkTex) return; - m_tfx_textures[i] = tex; + m_tfx_textures[i] = vkTex; m_dirty_flags |= (i < 2) ? DIRTY_FLAG_TFX_SAMPLERS_DS : DIRTY_FLAG_TFX_RT_TEXTURE_DS; } @@ -3091,24 +3062,22 @@ void GSDeviceVK::PSSetSampler(GSHWDrawConfig::SamplerSelector sel) void GSDeviceVK::SetUtilityTexture(GSTexture* tex, VkSampler sampler) { - const VKTexture* vtex; - if (tex) + GSTextureVK* vkTex = static_cast(tex); + if (vkTex) { - GSTextureVK* vkTex = static_cast(tex); vkTex->CommitClear(); - vkTex->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + vkTex->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly); vkTex->SetUsedThisCommandBuffer(); - vtex = vkTex->GetTexturePtr(); } else { - vtex = &m_null_texture; + vkTex = m_null_texture.get(); } - if (m_utility_texture == vtex && m_utility_sampler == sampler) + if (m_utility_texture == vkTex && m_utility_sampler == sampler) return; - m_utility_texture = vtex; + m_utility_texture = vkTex; m_utility_sampler = sampler; m_dirty_flags |= DIRTY_FLAG_UTILITY_TEXTURE; } @@ -3121,18 +3090,17 @@ void GSDeviceVK::SetUtilityPushConstants(const void* data, u32 size) void GSDeviceVK::UnbindTexture(GSTextureVK* tex) { - const VKTexture* vtex = tex->GetTexturePtr(); for (u32 i = 0; i < NUM_TFX_TEXTURES; i++) { - if (m_tfx_textures[i] == vtex) + if (m_tfx_textures[i] == tex) { - m_tfx_textures[i] = &m_null_texture; + m_tfx_textures[i] = m_null_texture.get(); m_dirty_flags |= (i < 2) ? DIRTY_FLAG_TFX_SAMPLERS_DS : DIRTY_FLAG_TFX_RT_TEXTURE_DS; } } - if (m_utility_texture == vtex) + if (m_utility_texture == tex) { - m_utility_texture = &m_null_texture; + m_utility_texture = m_null_texture.get(); m_dirty_flags |= DIRTY_FLAG_UTILITY_TEXTURE; } if (m_current_render_target == tex || m_current_depth_target == tex) @@ -3333,18 +3301,18 @@ bool GSDeviceVK::ApplyTFXState(bool already_execed) Vulkan::DescriptorSetUpdateBuilder dsub; - u32 dirty_descriptor_set_start = NUM_TFX_DESCRIPTOR_SETS; - u32 dirty_descriptor_set_end = 0; + std::array dsets; + u32 num_dsets = 0; + u32 start_dset = 0; + const bool layout_changed = (m_current_pipeline_layout != PipelineLayout::TFX); - if (flags & DIRTY_FLAG_TFX_DYNAMIC_OFFSETS) - { - dirty_descriptor_set_start = 0; - } + if (!layout_changed && flags & DIRTY_FLAG_TFX_DYNAMIC_OFFSETS) + dsets[num_dsets++] = m_tfx_ubo_descriptor_set; - if ((flags & DIRTY_FLAG_TFX_SAMPLERS_DS) || m_tfx_descriptor_sets[1] == VK_NULL_HANDLE) + if ((flags & DIRTY_FLAG_TFX_SAMPLERS_DS) || m_tfx_texture_descriptor_set == VK_NULL_HANDLE) { - VkDescriptorSet ds = g_vulkan_context->AllocateDescriptorSet(m_tfx_sampler_ds_layout); - if (ds == VK_NULL_HANDLE) + m_tfx_texture_descriptor_set = g_vulkan_context->AllocateDescriptorSet(m_tfx_sampler_ds_layout); + if (m_tfx_texture_descriptor_set == VK_NULL_HANDLE) { if (already_execed) { @@ -3356,20 +3324,23 @@ bool GSDeviceVK::ApplyTFXState(bool already_execed) return ApplyTFXState(true); } - dsub.AddCombinedImageSamplerDescriptorWrite( - ds, 0, m_tfx_textures[0]->GetView(), m_tfx_sampler, m_tfx_textures[0]->GetLayout()); - dsub.AddImageDescriptorWrite(ds, 1, m_tfx_textures[1]->GetView(), m_tfx_textures[1]->GetLayout()); + dsub.AddCombinedImageSamplerDescriptorWrite(m_tfx_texture_descriptor_set, 0, m_tfx_textures[0]->GetView(), + m_tfx_sampler, m_tfx_textures[0]->GetVkLayout()); + dsub.AddImageDescriptorWrite( + m_tfx_texture_descriptor_set, 1, m_tfx_textures[1]->GetView(), m_tfx_textures[1]->GetVkLayout()); dsub.Update(dev); - m_tfx_descriptor_sets[1] = ds; - dirty_descriptor_set_start = std::min(dirty_descriptor_set_start, 1u); - dirty_descriptor_set_end = 1u; + if (!layout_changed) + { + start_dset = (num_dsets == 0) ? TFX_DESCRIPTOR_SET_TEXTURES : start_dset; + dsets[num_dsets++] = m_tfx_texture_descriptor_set; + } } - if ((flags & DIRTY_FLAG_TFX_RT_TEXTURE_DS) || m_tfx_descriptor_sets[2] == VK_NULL_HANDLE) + if ((flags & DIRTY_FLAG_TFX_RT_TEXTURE_DS) || m_tfx_rt_descriptor_set == VK_NULL_HANDLE) { - VkDescriptorSet ds = g_vulkan_context->AllocateDescriptorSet(m_tfx_rt_texture_ds_layout); - if (ds == VK_NULL_HANDLE) + m_tfx_rt_descriptor_set = g_vulkan_context->AllocateDescriptorSet(m_tfx_rt_texture_ds_layout); + if (m_tfx_rt_descriptor_set == VK_NULL_HANDLE) { if (already_execed) { @@ -3384,35 +3355,45 @@ bool GSDeviceVK::ApplyTFXState(bool already_execed) if (m_features.texture_barrier) { dsub.AddInputAttachmentDescriptorWrite( - ds, 0, m_tfx_textures[NUM_TFX_DRAW_TEXTURES]->GetView(), VK_IMAGE_LAYOUT_GENERAL); + m_tfx_rt_descriptor_set, 0, m_tfx_textures[NUM_TFX_DRAW_TEXTURES]->GetView(), VK_IMAGE_LAYOUT_GENERAL); } else { - dsub.AddImageDescriptorWrite(ds, 0, m_tfx_textures[NUM_TFX_DRAW_TEXTURES]->GetView(), - m_tfx_textures[NUM_TFX_DRAW_TEXTURES]->GetLayout()); + dsub.AddImageDescriptorWrite(m_tfx_rt_descriptor_set, 0, m_tfx_textures[NUM_TFX_DRAW_TEXTURES]->GetView(), + m_tfx_textures[NUM_TFX_DRAW_TEXTURES]->GetVkLayout()); } - dsub.AddImageDescriptorWrite(ds, 1, m_tfx_textures[NUM_TFX_DRAW_TEXTURES + 1]->GetView(), - m_tfx_textures[NUM_TFX_DRAW_TEXTURES + 1]->GetLayout()); + dsub.AddImageDescriptorWrite(m_tfx_rt_descriptor_set, 1, m_tfx_textures[NUM_TFX_DRAW_TEXTURES + 1]->GetView(), + m_tfx_textures[NUM_TFX_DRAW_TEXTURES + 1]->GetVkLayout()); dsub.Update(dev); - m_tfx_descriptor_sets[2] = ds; - dirty_descriptor_set_start = std::min(dirty_descriptor_set_start, 2u); - dirty_descriptor_set_end = 2u; + if (!layout_changed) + { + // need to add textures in, can't leave a gap + if (start_dset == TFX_DESCRIPTOR_SET_UBO && num_dsets == 1) + dsets[num_dsets++] = m_tfx_texture_descriptor_set; + else + start_dset = (num_dsets == 0) ? TFX_DESCRIPTOR_SET_RT : start_dset; + + dsets[num_dsets++] = m_tfx_rt_descriptor_set; + } } - if (m_current_pipeline_layout != PipelineLayout::TFX) + if (layout_changed) { m_current_pipeline_layout = PipelineLayout::TFX; + dsets[0] = m_tfx_ubo_descriptor_set; + dsets[1] = m_tfx_texture_descriptor_set; + dsets[2] = m_tfx_rt_descriptor_set; + vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_tfx_pipeline_layout, 0, - NUM_TFX_DESCRIPTOR_SETS, m_tfx_descriptor_sets.data(), NUM_TFX_DYNAMIC_OFFSETS, - m_tfx_dynamic_offsets.data()); + NUM_TFX_DESCRIPTOR_SETS, dsets.data(), NUM_TFX_DYNAMIC_OFFSETS, m_tfx_dynamic_offsets.data()); } - else if (dirty_descriptor_set_start <= dirty_descriptor_set_end) + else if (num_dsets > 0) { u32 dynamic_count; const u32* dynamic_offsets; - if (dirty_descriptor_set_start == 0) + if (start_dset == TFX_DESCRIPTOR_SET_UBO) { dynamic_count = NUM_TFX_DYNAMIC_OFFSETS; dynamic_offsets = m_tfx_dynamic_offsets.data(); @@ -3423,14 +3404,10 @@ bool GSDeviceVK::ApplyTFXState(bool already_execed) dynamic_offsets = nullptr; } - const u32 count = dirty_descriptor_set_end - dirty_descriptor_set_start + 1; - - vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_tfx_pipeline_layout, - dirty_descriptor_set_start, count, &m_tfx_descriptor_sets[dirty_descriptor_set_start], dynamic_count, - dynamic_offsets); + vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_tfx_pipeline_layout, start_dset, num_dsets, + dsets.data(), dynamic_count, dynamic_offsets); } - ApplyBaseState(flags, cmdbuf); return true; } @@ -3464,7 +3441,7 @@ bool GSDeviceVK::ApplyUtilityState(bool already_execed) Vulkan::DescriptorSetUpdateBuilder dsub; dsub.AddCombinedImageSamplerDescriptorWrite(m_utility_descriptor_set, 0, m_utility_texture->GetView(), - m_utility_sampler, m_utility_texture->GetLayout()); + m_utility_sampler, m_utility_texture->GetVkLayout()); dsub.Update(dev); rebind = true; } @@ -3498,7 +3475,7 @@ static void ColorBufferBarrier(GSTextureVK* rt) const VkImageMemoryBarrier barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, nullptr, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, - rt->GetTexture().GetImage(), {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}}; + rt->GetImage(), {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}}; vkCmdPipelineBarrier(g_vulkan_context->GetCurrentCommandBuffer(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, nullptr, 0, nullptr, 1, &barrier); @@ -3609,7 +3586,7 @@ GSTextureVK* GSDeviceVK::SetupPrimitiveTrackingDATE(GSHWDrawConfig& config) config.alpha_second_pass.ps.date = 3; // and bind the image to the primitive sampler - image->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + image->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly); PSSetShaderResource(3, image, false); return image; } @@ -3715,7 +3692,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config) else { hdr_rt->SetState(GSTexture::State::Invalidated); - draw_rt->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + draw_rt->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly); } // we're not drawing to the RT, so we can use it as a source @@ -3742,9 +3719,8 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config) } // clear texture binding when it's bound to RT or DS - if (!config.tex && - ((!pipe.IsRTFeedbackLoop() && static_cast(config.rt)->GetTexturePtr() == m_tfx_textures[0]) || - (config.ds && static_cast(config.ds)->GetTexturePtr() == m_tfx_textures[0]))) + if (!config.tex && ((!pipe.IsRTFeedbackLoop() && static_cast(config.rt) == m_tfx_textures[0]) || + (config.ds && static_cast(config.ds) == m_tfx_textures[0]))) { PSSetShaderResource(0, nullptr, false); } @@ -3777,7 +3753,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config) // We don't need the very first barrier if this is the first draw after switching to feedback loop, // because the layout change in itself enforces the execution dependency. HDR needs a barrier between // setup and the first draw to read it. TODO: Make HDR use subpasses instead. - const bool skip_first_barrier = (draw_rt && draw_rt->GetLayout() != VK_IMAGE_LAYOUT_GENERAL && !pipe.ps.hdr); + const bool skip_first_barrier = (draw_rt && draw_rt->GetLayout() != GSTextureVK::Layout::FeedbackLoop && !pipe.ps.hdr); OMSetRenderTargets(draw_rt, draw_ds, config.scissor, static_cast(pipe.feedback_loop_flags)); if (pipe.IsRTFeedbackLoop()) @@ -3883,7 +3859,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config) GL_INS("Blit HDR back to RT"); EndRenderPass(); - hdr_rt->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + hdr_rt->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly); draw_rt = static_cast(config.rt); OMSetRenderTargets(draw_rt, draw_ds, config.scissor, static_cast(pipe.feedback_loop_flags)); diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h index dcf93818bd..723bc975fa 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h @@ -87,7 +87,6 @@ public: enum : u32 { - NUM_TFX_DESCRIPTOR_SETS = 3, NUM_TFX_DYNAMIC_OFFSETS = 2, NUM_TFX_DRAW_TEXTURES = 2, NUM_TFX_RT_TEXTURES = 2, @@ -103,6 +102,14 @@ public: NUM_CAS_PIPELINES = 2, }; + enum TFX_DESCRIPTOR_SET : u32 + { + TFX_DESCRIPTOR_SET_UBO, + TFX_DESCRIPTOR_SET_TEXTURES, + TFX_DESCRIPTOR_SET_RT, + + NUM_TFX_DESCRIPTOR_SETS, + }; enum DATE_RENDER_PASS : u32 { DATE_RENDER_PASS_NONE = 0, @@ -170,8 +177,6 @@ private: std::string m_tfx_source; - VkFormat LookupNativeFormat(GSTexture::Format format) const; - GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override; void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, @@ -317,6 +322,8 @@ public: ////////////////////////////////////////////////////////////////////////// public: + VkFormat LookupNativeFormat(GSTexture::Format format) const; + __fi VkFramebuffer GetCurrentFramebuffer() const { return m_current_framebuffer; } /// Ends any render pass, executes the command buffer, and invalidates cached state. @@ -412,20 +419,22 @@ private: GSVector4i m_scissor = GSVector4i::zero(); u8 m_blend_constant_color = 0; - std::array m_tfx_textures{}; + std::array m_tfx_textures{}; VkSampler m_tfx_sampler = VK_NULL_HANDLE; u32 m_tfx_sampler_sel = 0; - std::array m_tfx_descriptor_sets{}; + VkDescriptorSet m_tfx_ubo_descriptor_set = VK_NULL_HANDLE; + VkDescriptorSet m_tfx_texture_descriptor_set = VK_NULL_HANDLE; + VkDescriptorSet m_tfx_rt_descriptor_set = VK_NULL_HANDLE; std::array m_tfx_dynamic_offsets{}; - const VKTexture* m_utility_texture = nullptr; + const GSTextureVK* m_utility_texture = nullptr; VkSampler m_utility_sampler = VK_NULL_HANDLE; VkDescriptorSet m_utility_descriptor_set = VK_NULL_HANDLE; PipelineLayout m_current_pipeline_layout = PipelineLayout::Undefined; VkPipeline m_current_pipeline = VK_NULL_HANDLE; - VKTexture m_null_texture; + std::unique_ptr 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/Vulkan/GSTextureVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp index 4174a813e7..0b07d35a2d 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.cpp @@ -26,17 +26,192 @@ #include "common/Align.h" #include "common/Assertions.h" -GSTextureVK::GSTextureVK(Type type, Format format, VKTexture texture) - : m_texture(std::move(texture)) +static constexpr const VkComponentMapping s_identity_swizzle{VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}; + +static constexpr std::array(GSTextureVK::Layout::Count)> s_vk_layout_mapping = {{ + VK_IMAGE_LAYOUT_UNDEFINED, // Undefined + VK_IMAGE_LAYOUT_PREINITIALIZED, // Preinitialized + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // ColorAttachment + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // DepthStencilAttachment + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // ShaderReadOnly + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // ClearDst + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // TransferSrc + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // TransferDst + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // PresentSrc + VK_IMAGE_LAYOUT_GENERAL, // FeedbackLoop + VK_IMAGE_LAYOUT_GENERAL, // ReadWriteImage + VK_IMAGE_LAYOUT_GENERAL, // ComputeReadWriteImage + VK_IMAGE_LAYOUT_GENERAL, // General +}}; + +GSTextureVK::GSTextureVK(Type type, Format format, int width, int height, int levels, VkImage image, + VmaAllocation allocation, VkImageView view, VkFormat vk_format) + : GSTexture() + , m_image(image) + , m_allocation(allocation) + , m_view(view) + , m_vk_format(vk_format) { m_type = type; m_format = format; - m_size.x = m_texture.GetWidth(); - m_size.y = m_texture.GetHeight(); - m_mipmap_levels = m_texture.GetLevels(); + m_size.x = width; + m_size.y = height; + m_mipmap_levels = levels; } GSTextureVK::~GSTextureVK() +{ + Destroy(true); +} + +std::unique_ptr GSTextureVK::Create(Type type, Format format, int width, int height, int levels) +{ + const VkFormat vk_format = GSDeviceVK::GetInstance()->LookupNativeFormat(format); + + VkImageCreateInfo ici = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, nullptr, 0, VK_IMAGE_TYPE_2D, vk_format, + {static_cast(width), static_cast(height), 1}, static_cast(levels), 1, VK_SAMPLE_COUNT_1_BIT, + VK_IMAGE_TILING_OPTIMAL}; + + VmaAllocationCreateInfo aci = {}; + aci.usage = VMA_MEMORY_USAGE_GPU_ONLY; + aci.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT; + aci.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + + VkImageViewCreateInfo vci = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, nullptr, 0, VK_NULL_HANDLE, + VK_IMAGE_VIEW_TYPE_2D, vk_format, s_identity_swizzle, VK_IMAGE_ASPECT_COLOR_BIT, 0, static_cast(levels), 0, + 1}; + + switch (type) + { + case Type::Texture: + { + ici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + + if (format == Format::UNorm8) + { + // for r8 textures, swizzle it across all 4 components. the shaders depend on it being in alpha.. why? + static constexpr const VkComponentMapping r8_swizzle = { + VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R}; + vci.components = r8_swizzle; + } + } + break; + + case Type::RenderTarget: + { + pxAssert(levels == 1); + ici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; + } + break; + + case Type::DepthStencil: + { + pxAssert(levels == 1); + ici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + vci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + } + break; + + case Type::RWTexture: + { + pxAssert(levels == 1); + ici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT; + } + break; + + default: + return {}; + } + + // Use dedicated allocations for typical RT size + if ((type == Type::RenderTarget || type == Type::DepthStencil) && width >= 512 && height >= 448) + aci.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; + + VkImage image = VK_NULL_HANDLE; + VmaAllocation allocation = VK_NULL_HANDLE; + VkResult res = vmaCreateImage(g_vulkan_context->GetAllocator(), &ici, &aci, &image, &allocation, nullptr); + if (aci.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT && res != VK_SUCCESS) + { + // try without dedicated allocation + aci.flags &= ~VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT; + res = vmaCreateImage(g_vulkan_context->GetAllocator(), &ici, &aci, &image, &allocation, nullptr); + } + if (res == VK_ERROR_OUT_OF_DEVICE_MEMORY) + { + DevCon.WriteLn("Failed to allocate device memory for %ux%u texture", width, height); + return {}; + } + else if (res != VK_SUCCESS) + { + LOG_VULKAN_ERROR(res, "vmaCreateImage failed: "); + return {}; + } + + VkImageView view = VK_NULL_HANDLE; + vci.image = image; + res = vkCreateImageView(g_vulkan_context->GetDevice(), &vci, nullptr, &view); + if (res != VK_SUCCESS) + { + LOG_VULKAN_ERROR(res, "vkCreateImageView failed: "); + vmaDestroyImage(g_vulkan_context->GetAllocator(), image, allocation); + return {}; + } + + switch (type) + { + case Type::Texture: + Vulkan::SetObjectName(g_vulkan_context->GetDevice(), image, "%dx%d texture", width, height); + break; + + case Type::RenderTarget: + Vulkan::SetObjectName(g_vulkan_context->GetDevice(), image, "%dx%d render target", width, height); + break; + + case Type::DepthStencil: + Vulkan::SetObjectName(g_vulkan_context->GetDevice(), image, "%dx%d depth stencil", width, height); + break; + + case Type::RWTexture: + Vulkan::SetObjectName(g_vulkan_context->GetDevice(), image, "%dx%d RW texture", width, height); + break; + + default: + break; + } + + return std::unique_ptr( + new GSTextureVK(type, format, width, height, levels, image, allocation, view, vk_format)); +} + +std::unique_ptr GSTextureVK::Adopt( + VkImage image, Type type, Format format, int width, int height, int levels, VkFormat vk_format) +{ + // Only need to create the image view, this is mainly for swap chains. + const VkImageViewCreateInfo view_info = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, nullptr, 0, image, + VK_IMAGE_VIEW_TYPE_2D, vk_format, s_identity_swizzle, + {(type == Type::DepthStencil) ? static_cast(VK_IMAGE_ASPECT_DEPTH_BIT) : + static_cast(VK_IMAGE_ASPECT_COLOR_BIT), + 0u, static_cast(levels), 0u, 1u}}; + + // Memory is managed by the owner of the image. + VkImageView view = VK_NULL_HANDLE; + VkResult res = vkCreateImageView(g_vulkan_context->GetDevice(), &view_info, nullptr, &view); + if (res != VK_SUCCESS) + { + LOG_VULKAN_ERROR(res, "vkCreateImageView failed: "); + return {}; + } + + return std::unique_ptr( + new GSTextureVK(type, format, width, height, levels, image, VK_NULL_HANDLE, view, vk_format)); +} + +void GSTextureVK::Destroy(bool defer) { GSDeviceVK::GetInstance()->UnbindTexture(this); @@ -57,103 +232,43 @@ GSTextureVK::~GSTextureVK() } } - g_vulkan_context->DeferFramebufferDestruction(fb); + if (defer) + g_vulkan_context->DeferFramebufferDestruction(fb); + else + vkDestroyFramebuffer(g_vulkan_context->GetDevice(), fb, nullptr); } + m_framebuffers.clear(); + } + + if (m_view != VK_NULL_HANDLE) + { + if (defer) + g_vulkan_context->DeferImageViewDestruction(m_view); + else + vkDestroyImageView(g_vulkan_context->GetDevice(), m_view, nullptr); + m_view = VK_NULL_HANDLE; + } + + // If we don't have device memory allocated, the image is not owned by us (e.g. swapchain) + if (m_allocation != VK_NULL_HANDLE) + { + if (defer) + g_vulkan_context->DeferImageDestruction(m_image, m_allocation); + else + vmaDestroyImage(g_vulkan_context->GetAllocator(), m_image, m_allocation); + m_image = VK_NULL_HANDLE; + m_allocation = VK_NULL_HANDLE; } } -std::unique_ptr GSTextureVK::Create(Type type, u32 width, u32 height, u32 levels, Format format, VkFormat vk_format) +VkImageLayout GSTextureVK::GetVkLayout() const { - switch (type) - { - case Type::Texture: - { - VkImageUsageFlags usage = - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - const VkComponentMapping* swizzle = nullptr; - if (format == Format::UNorm8) - { - // for r8 textures, swizzle it across all 4 components. the shaders depend on it being in alpha.. why? - static constexpr VkComponentMapping r8_swizzle = { - VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R}; - swizzle = &r8_swizzle; - } - - VKTexture texture; - if (!texture.Create(width, height, levels, 1, vk_format, VK_SAMPLE_COUNT_1_BIT, - VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, usage, swizzle)) - { - return {}; - } - - Vulkan::SetObjectName( - g_vulkan_context->GetDevice(), texture.GetImage(), "%ux%u texture", width, height); - return std::make_unique(type, format, std::move(texture)); - } - - case Type::RenderTarget: - { - pxAssert(levels == 1); - - VKTexture texture; - if (!texture.Create(width, height, levels, 1, vk_format, VK_SAMPLE_COUNT_1_BIT, - VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | - VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) - { - return {}; - } - - Vulkan::SetObjectName( - g_vulkan_context->GetDevice(), texture.GetImage(), "%ux%u render target", width, height); - return std::make_unique(type, format, std::move(texture)); - } - - case Type::DepthStencil: - { - pxAssert(levels == 1); - - VKTexture texture; - if (!texture.Create(width, height, levels, 1, vk_format, VK_SAMPLE_COUNT_1_BIT, - VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)) - { - return {}; - } - - Vulkan::SetObjectName( - g_vulkan_context->GetDevice(), texture.GetImage(), "%ux%u depth stencil", width, height); - return std::make_unique(type, format, std::move(texture)); - } - - case Type::RWTexture: - { - pxAssert(levels == 1); - - VKTexture texture; - if (!texture.Create(width, height, levels, 1, vk_format, VK_SAMPLE_COUNT_1_BIT, - VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)) - { - return {}; - } - - Vulkan::SetObjectName( - g_vulkan_context->GetDevice(), texture.GetImage(), "%ux%u RW texture", width, height); - return std::make_unique(type, format, std::move(texture)); - } - - default: - return {}; - } + return s_vk_layout_mapping[static_cast(m_layout)]; } void* GSTextureVK::GetNativeHandle() const { - return const_cast(&m_texture); + return const_cast(this); } VkCommandBuffer GSTextureVK::GetCommandBufferForUpdate() @@ -178,8 +293,8 @@ void GSTextureVK::CopyTextureDataForUpload(void* dst, const void* src, u32 pitch VkBuffer GSTextureVK::AllocateUploadStagingBuffer(const void* data, u32 pitch, u32 upload_pitch, u32 height) const { const u32 size = upload_pitch * height; - const VkBufferCreateInfo bci = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, nullptr, 0, - static_cast(size), VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_SHARING_MODE_EXCLUSIVE, 0, nullptr}; + const VkBufferCreateInfo bci = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, nullptr, 0, static_cast(size), + VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_SHARING_MODE_EXCLUSIVE, 0, nullptr}; // Don't worry about setting the coherent bit for this upload, the main reason we had // that set in StreamBuffer was for MoltenVK, which would upload the whole buffer on @@ -207,6 +322,23 @@ VkBuffer GSTextureVK::AllocateUploadStagingBuffer(const void* data, u32 pitch, u return buffer; } +void GSTextureVK::UpdateFromBuffer(VkCommandBuffer cmdbuf, int level, u32 x, u32 y, u32 width, u32 height, + u32 buffer_height, u32 row_length, VkBuffer buffer, u32 buffer_offset) +{ + const Layout old_layout = m_layout; + if (old_layout != Layout::TransferDst) + TransitionSubresourcesToLayout(cmdbuf, level, 1, old_layout, Layout::TransferDst); + + const VkBufferImageCopy bic = {static_cast(buffer_offset), row_length, buffer_height, + {VK_IMAGE_ASPECT_COLOR_BIT, static_cast(level), 0u, 1u}, {static_cast(x), static_cast(y), 0}, + {width, height, 1u}}; + + vkCmdCopyBufferToImage(cmdbuf, buffer, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bic); + + if (old_layout != Layout::TransferDst) + TransitionSubresourcesToLayout(cmdbuf, level, 1, Layout::TransferDst, old_layout); +} + bool GSTextureVK::Update(const GSVector4i& r, const void* data, int pitch, int layer) { if (layer >= m_mipmap_levels) @@ -254,8 +386,8 @@ bool GSTextureVK::Update(const GSVector4i& r, const void* data, int pitch, int l GL_PUSH("GSTextureVK::Update({%d,%d} %dx%d Lvl:%u", r.x, r.y, r.width(), r.height(), layer); // first time the texture is used? don't leave it undefined - if (m_texture.GetLayout() == VK_IMAGE_LAYOUT_UNDEFINED) - m_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + if (m_layout == Layout::Undefined) + TransitionToLayout(cmdbuf, Layout::TransferDst); // 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) @@ -266,10 +398,9 @@ bool GSTextureVK::Update(const GSVector4i& r, const void* data, int pitch, int l m_state = State::Dirty; } - m_texture.UpdateFromBuffer(cmdbuf, layer, 0, r.x, r.y, width, height, - Common::AlignUpPow2(height, GetCompressedBlockSize()), + UpdateFromBuffer(cmdbuf, layer, r.x, r.y, width, height, Common::AlignUpPow2(height, GetCompressedBlockSize()), CalcUploadRowLengthFromPitch(upload_pitch), buffer, buffer_offset); - m_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + TransitionToLayout(cmdbuf, Layout::ShaderReadOnly); if (m_type == Type::Texture) m_needs_mipmaps_generated |= (layer == 0); @@ -283,14 +414,14 @@ bool GSTextureVK::Map(GSMap& m, const GSVector4i* r, int layer) return false; // map for writing - m_map_area = r ? *r : GSVector4i(0, 0, m_texture.GetWidth(), m_texture.GetHeight()); + m_map_area = r ? *r : GetRect(); m_map_level = layer; - m.pitch = Common::AlignUpPow2(m_map_area.width() * Vulkan::GetTexelSize(m_texture.GetFormat()), - g_vulkan_context->GetBufferCopyRowPitchAlignment()); + m.pitch = + Common::AlignUpPow2(CalcUploadPitch(m_map_area.width()), g_vulkan_context->GetBufferCopyRowPitchAlignment()); // see note in Update() for the reason why. - const u32 required_size = m.pitch * m_map_area.height(); + const u32 required_size = CalcUploadSize(m_map_area.height(), m.pitch); VKStreamBuffer& buffer = g_vulkan_context->GetTextureUploadBuffer(); if (required_size >= (buffer.GetCurrentSize() / 2)) return false; @@ -310,15 +441,13 @@ bool GSTextureVK::Map(GSMap& m, const GSVector4i* r, int layer) void GSTextureVK::Unmap() { // this can't handle blocks/compressed formats at the moment. - pxAssert(m_map_level < m_texture.GetLevels() && !IsCompressedFormat()); + pxAssert(m_map_level < m_mipmap_levels && !IsCompressedFormat()); g_perfmon.Put(GSPerfMon::TextureUploads, 1); - // 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() * Vulkan::GetTexelSize(m_texture.GetFormat()), - g_vulkan_context->GetBufferCopyRowPitchAlignment()); - const u32 required_size = pitch * height; + const u32 width = m_map_area.width(); + const u32 height = m_map_area.height(); + const u32 pitch = Common::AlignUpPow2(CalcUploadPitch(width), g_vulkan_context->GetBufferCopyRowPitchAlignment()); + const u32 required_size = CalcUploadSize(height, pitch); VKStreamBuffer& buffer = g_vulkan_context->GetTextureUploadBuffer(); const u32 buffer_offset = buffer.GetCurrentOffset(); buffer.CommitMemory(required_size); @@ -328,8 +457,8 @@ void GSTextureVK::Unmap() m_map_area.height(), m_map_level); // first time the texture is used? don't leave it undefined - if (m_texture.GetLayout() == VK_IMAGE_LAYOUT_UNDEFINED) - m_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + if (m_layout == Layout::Undefined) + TransitionToLayout(cmdbuf, Layout::TransferDst); // 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) @@ -340,10 +469,10 @@ void GSTextureVK::Unmap() m_state = State::Dirty; } - m_texture.UpdateFromBuffer(cmdbuf, m_map_level, 0, m_map_area.x, m_map_area.y, width, height, - Common::AlignUpPow2(height, GetCompressedBlockSize()), - CalcUploadRowLengthFromPitch(pitch), buffer.GetBuffer(), buffer_offset); - m_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + UpdateFromBuffer(cmdbuf, m_map_level, m_map_area.x, m_map_area.y, width, height, + Common::AlignUpPow2(height, GetCompressedBlockSize()), CalcUploadRowLengthFromPitch(pitch), buffer.GetBuffer(), + buffer_offset); + TransitionToLayout(cmdbuf, Layout::ShaderReadOnly); if (m_type == Type::Texture) m_needs_mipmaps_generated |= (m_map_level == 0); @@ -361,10 +490,8 @@ void GSTextureVK::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); - m_texture.TransitionSubresourcesToLayout( - cmdbuf, src_level, 1, 0, 1, m_texture.GetLayout(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - m_texture.TransitionSubresourcesToLayout( - cmdbuf, dst_level, 1, 0, 1, m_texture.GetLayout(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + TransitionSubresourcesToLayout(cmdbuf, src_level, 1, m_layout, Layout::TransferSrc); + TransitionSubresourcesToLayout(cmdbuf, dst_level, 1, m_layout, Layout::TransferDst); const VkImageBlit blit = { {VK_IMAGE_ASPECT_COLOR_BIT, static_cast(src_level), 0u, 1u}, // srcSubresource @@ -373,20 +500,22 @@ void GSTextureVK::GenerateMipmap() {{0, 0, 0}, {dst_width, dst_height, 1}} // dstOffsets }; - vkCmdBlitImage(cmdbuf, m_texture.GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_texture.GetImage(), + vkCmdBlitImage(cmdbuf, m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR); - m_texture.TransitionSubresourcesToLayout( - cmdbuf, src_level, 1, 0, 1, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_texture.GetLayout()); - m_texture.TransitionSubresourcesToLayout( - cmdbuf, dst_level, 1, 0, 1, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, m_texture.GetLayout()); + TransitionSubresourcesToLayout(cmdbuf, src_level, 1, Layout::TransferSrc, m_layout); + TransitionSubresourcesToLayout(cmdbuf, dst_level, 1, Layout::TransferDst, m_layout); } } void GSTextureVK::Swap(GSTexture* tex) { GSTexture::Swap(tex); - std::swap(m_texture, static_cast(tex)->m_texture); + std::swap(m_image, static_cast(tex)->m_image); + std::swap(m_allocation, static_cast(tex)->m_allocation); + std::swap(m_view, static_cast(tex)->m_view); + std::swap(m_vk_format, static_cast(tex)->m_vk_format); + std::swap(m_layout, static_cast(tex)->m_layout); std::swap(m_use_fence_counter, static_cast(tex)->m_use_fence_counter); std::swap(m_clear_value, static_cast(tex)->m_clear_value); std::swap(m_map_area, static_cast(tex)->m_map_area); @@ -394,11 +523,6 @@ void GSTextureVK::Swap(GSTexture* tex) std::swap(m_framebuffers, static_cast(tex)->m_framebuffers); } -void GSTextureVK::TransitionToLayout(VkImageLayout layout) -{ - m_texture.TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), layout); -} - void GSTextureVK::CommitClear() { if (m_state != GSTexture::State::Cleared) @@ -411,26 +535,223 @@ void GSTextureVK::CommitClear() void GSTextureVK::CommitClear(VkCommandBuffer cmdbuf) { - m_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + TransitionToLayout(cmdbuf, Layout::ClearDst); if (IsDepthStencil()) { - const VkClearDepthStencilValue cv = { m_clear_value.depth }; - const VkImageSubresourceRange srr = { VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u }; - vkCmdClearDepthStencilImage(cmdbuf, m_texture.GetImage(), m_texture.GetLayout(), &cv, 1, &srr); + const VkClearDepthStencilValue cv = {m_clear_value.depth}; + const VkImageSubresourceRange srr = {VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u}; + vkCmdClearDepthStencilImage(cmdbuf, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &cv, 1, &srr); } else { alignas(16) VkClearColorValue cv; GSVector4::store(cv.float32, GetClearColor()); const VkImageSubresourceRange srr = {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}; - vkCmdClearColorImage(cmdbuf, m_texture.GetImage(), m_texture.GetLayout(), &cv, 1, &srr); + vkCmdClearColorImage(cmdbuf, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &cv, 1, &srr); } SetState(GSTexture::State::Dirty); } -VkFramebuffer GSTextureVK::GetFramebuffer(bool feedback_loop) { return GetLinkedFramebuffer(nullptr, feedback_loop); } +void GSTextureVK::OverrideImageLayout(Layout new_layout) +{ + m_layout = new_layout; +} + +void GSTextureVK::TransitionToLayout(Layout layout) +{ + TransitionToLayout(g_vulkan_context->GetCurrentCommandBuffer(), layout); +} + +void GSTextureVK::TransitionToLayout(VkCommandBuffer command_buffer, Layout new_layout) +{ + if (m_layout == new_layout) + return; + + TransitionSubresourcesToLayout(command_buffer, 0, m_mipmap_levels, m_layout, new_layout); + + m_layout = new_layout; +} + +void GSTextureVK::TransitionSubresourcesToLayout( + VkCommandBuffer command_buffer, int start_level, int num_levels, Layout old_layout, Layout new_layout) +{ + VkImageAspectFlags aspect; + if (m_type == Type::DepthStencil) + { + aspect = g_gs_device->Features().stencil_buffer ? (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) : + VK_IMAGE_ASPECT_DEPTH_BIT; + } + else + { + aspect = VK_IMAGE_ASPECT_COLOR_BIT; + } + + VkImageMemoryBarrier barrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, nullptr, 0, 0, + s_vk_layout_mapping[static_cast(old_layout)], s_vk_layout_mapping[static_cast(new_layout)], + VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, m_image, + {aspect, static_cast(start_level), static_cast(num_levels), 0u, 1u}}; + + // srcStageMask -> Stages that must complete before the barrier + // dstStageMask -> Stages that must wait for after the barrier before beginning + VkPipelineStageFlags srcStageMask, dstStageMask; + switch (old_layout) + { + case Layout::Undefined: + // Layout undefined therefore contents undefined, and we don't care what happens to it. + barrier.srcAccessMask = 0; + srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + break; + + case Layout::Preinitialized: + // Image has been pre-initialized by the host, so ensure all writes have completed. + barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; + srcStageMask = VK_PIPELINE_STAGE_HOST_BIT; + break; + + case Layout::ColorAttachment: + // Image was being used as a color attachment, so ensure all writes have completed. + barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + break; + + case Layout::DepthStencilAttachment: + // Image was being used as a depthstencil attachment, so ensure all writes have completed. + barrier.srcAccessMask = + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + break; + + case Layout::ShaderReadOnly: + // Image was being used as a shader resource, make sure all reads have finished. + barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + break; + + case Layout::ClearDst: + // Image was being used as a clear destination, ensure all writes have finished. + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + + case Layout::TransferSrc: + // Image was being used as a copy source, ensure all reads have finished. + barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + + case Layout::TransferDst: + // Image was being used as a copy destination, ensure all writes have finished. + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + + case Layout::FeedbackLoop: + barrier.srcAccessMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ? + (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT) : + (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT); + srcStageMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ? + (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT) : + (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + break; + + case Layout::ReadWriteImage: + barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + break; + + case Layout::ComputeReadWriteImage: + barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + break; + + case Layout::General: + default: + srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + break; + } + + switch (new_layout) + { + case Layout::Undefined: + barrier.dstAccessMask = 0; + dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + break; + + case Layout::ColorAttachment: + barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + break; + + case Layout::DepthStencilAttachment: + barrier.dstAccessMask = + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + break; + + case Layout::ShaderReadOnly: + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + break; + + case Layout::ClearDst: + barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + + case Layout::TransferSrc: + barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + + case Layout::TransferDst: + barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; + break; + + case Layout::PresentSrc: + srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + break; + + case Layout::FeedbackLoop: + barrier.dstAccessMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ? + (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | + VK_ACCESS_INPUT_ATTACHMENT_READ_BIT) : + (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT); + dstStageMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ? + (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT) : + (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + break; + + case Layout::ReadWriteImage: + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + break; + + case Layout::ComputeReadWriteImage: + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; + dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; + break; + + case Layout::General: + default: + dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + break; + } + vkCmdPipelineBarrier(command_buffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &barrier); +} + +VkFramebuffer GSTextureVK::GetFramebuffer(bool feedback_loop) +{ + return GetLinkedFramebuffer(nullptr, feedback_loop); +} VkFramebuffer GSTextureVK::GetLinkedFramebuffer(GSTextureVK* depth_texture, bool feedback_loop) { @@ -442,21 +763,20 @@ VkFramebuffer GSTextureVK::GetLinkedFramebuffer(GSTextureVK* depth_texture, bool return fb; } - VkRenderPass rp = g_vulkan_context->GetRenderPass( - (m_type != GSTexture::Type::DepthStencil) ? GetNativeFormat() : VK_FORMAT_UNDEFINED, - (m_type != GSTexture::Type::DepthStencil) ? - (depth_texture ? depth_texture->GetNativeFormat() : VK_FORMAT_UNDEFINED) : - GetNativeFormat(), + const VkRenderPass rp = g_vulkan_context->GetRenderPass( + (m_type != GSTexture::Type::DepthStencil) ? m_vk_format : VK_FORMAT_UNDEFINED, + (m_type != GSTexture::Type::DepthStencil) ? (depth_texture ? depth_texture->m_vk_format : VK_FORMAT_UNDEFINED) : + m_vk_format, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, feedback_loop); if (!rp) return VK_NULL_HANDLE; Vulkan::FramebufferBuilder fbb; - fbb.AddAttachment(m_texture.GetView()); + fbb.AddAttachment(m_view); if (depth_texture) - fbb.AddAttachment(depth_texture->m_texture.GetView()); - fbb.SetSize(m_texture.GetWidth(), m_texture.GetHeight(), m_texture.GetLayers()); + fbb.AddAttachment(depth_texture->m_view); + fbb.SetSize(m_size.x, m_size.y, 1); fbb.SetRenderPass(rp); VkFramebuffer fb = fbb.Create(g_vulkan_context->GetDevice()); @@ -485,8 +805,8 @@ std::unique_ptr GSDownloadTextureVK::Create(u32 width, u32 { const u32 buffer_size = GetBufferSize(width, height, format, g_vulkan_context->GetBufferCopyRowPitchAlignment()); - const VkBufferCreateInfo bci = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, nullptr, 0u, buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_SHARING_MODE_EXCLUSIVE, 0u, nullptr}; + const VkBufferCreateInfo bci = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, nullptr, 0u, buffer_size, + VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_SHARING_MODE_EXCLUSIVE, 0u, nullptr}; VmaAllocationCreateInfo aci = {}; aci.usage = VMA_MEMORY_USAGE_GPU_TO_CPU; @@ -503,7 +823,8 @@ std::unique_ptr GSDownloadTextureVK::Create(u32 width, u32 return {}; } - std::unique_ptr tex = std::unique_ptr(new GSDownloadTextureVK(width, height, format)); + std::unique_ptr tex = + std::unique_ptr(new GSDownloadTextureVK(width, height, format)); tex->m_allocation = allocation; tex->m_buffer = buffer; tex->m_buffer_size = buffer_size; @@ -524,8 +845,8 @@ void GSDownloadTextureVK::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, g_vulkan_context->GetBufferCopyRowPitchAlignment()); + m_current_pitch = GetTransferPitch(use_transfer_pitch ? static_cast(drc.width()) : m_width, + g_vulkan_context->GetBufferCopyRowPitchAlignment()); GetTransferSize(drc, ©_offset, ©_size, ©_rows); g_perfmon.Put(GSPerfMon::Readbacks, 1); @@ -535,16 +856,12 @@ void GSDownloadTextureVK::CopyFromTexture( const VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer(); GL_INS("GSDownloadTextureVK::CopyFromTexture: {%d,%d} %ux%u", src.left, src.top, src.width(), src.height()); - VkImageLayout old_layout = vkTex->GetTexture().GetLayout(); - if (old_layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) - { - vkTex->GetTexture().TransitionSubresourcesToLayout(cmdbuf, src_level, 1, 0, 1, old_layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - } + GSTextureVK::Layout old_layout = vkTex->GetLayout(); + if (old_layout != GSTextureVK::Layout::TransferSrc) + vkTex->TransitionSubresourcesToLayout(cmdbuf, src_level, 1, old_layout, GSTextureVK::Layout::TransferSrc); VkBufferImageCopy image_copy = {}; - const VkImageAspectFlags aspect = Vulkan::IsDepthFormat(static_cast(vkTex->GetFormat())) ? - VK_IMAGE_ASPECT_DEPTH_BIT : - VK_IMAGE_ASPECT_COLOR_BIT; + const VkImageAspectFlags aspect = vkTex->IsDepthStencil() ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; image_copy.bufferOffset = copy_offset; image_copy.bufferRowLength = GSTexture::CalcUploadRowLengthFromPitch(m_format, m_current_pitch); image_copy.bufferImageHeight = 0; @@ -553,16 +870,14 @@ void GSDownloadTextureVK::CopyFromTexture( image_copy.imageExtent = {static_cast(src.width()), static_cast(src.height()), 1u}; // do the copy - vkCmdCopyImageToBuffer(cmdbuf, vkTex->GetTexture().GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_buffer, 1, &image_copy); + vkCmdCopyImageToBuffer(cmdbuf, vkTex->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_buffer, 1, &image_copy); // flush gpu cache Vulkan::BufferMemoryBarrier(cmdbuf, m_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, 0, copy_size, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_HOST_BIT); - if (old_layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) - { - vkTex->GetTexture().TransitionSubresourcesToLayout(cmdbuf, src_level, 1, 0, 1, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, old_layout); - } + if (old_layout != GSTextureVK::Layout::TransferSrc) + vkTex->TransitionSubresourcesToLayout(cmdbuf, src_level, 1, GSTextureVK::Layout::TransferSrc, old_layout); m_copy_fence_counter = g_vulkan_context->GetCurrentFenceCounter(); m_needs_cache_invalidate = true; diff --git a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.h b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.h index 9fcee572e5..9b36c8ee72 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSTextureVK.h +++ b/pcsx2/GS/Renderers/Vulkan/GSTextureVK.h @@ -17,23 +17,46 @@ #include "GS/GS.h" #include "GS/Renderers/Common/GSTexture.h" -#include "GS/Renderers/Vulkan/VKTexture.h" #include "GS/Renderers/Vulkan/VKContext.h" +#include "GS/Renderers/Vulkan/VKLoader.h" + +#include class GSTextureVK final : public GSTexture { public: - GSTextureVK(Type type, Format format, VKTexture texture); + enum class Layout : u32 + { + Undefined, + Preinitialized, + ColorAttachment, + DepthStencilAttachment, + ShaderReadOnly, + ClearDst, + TransferSrc, + TransferDst, + PresentSrc, + FeedbackLoop, + ReadWriteImage, + ComputeReadWriteImage, + General, + Count + }; + ~GSTextureVK() override; - static std::unique_ptr Create(Type type, u32 width, u32 height, u32 levels, Format format, VkFormat vk_format); + static std::unique_ptr Create(Type type, Format format, int width, int height, int levels); + static std::unique_ptr Adopt( + VkImage image, Type type, Format format, int width, int height, int levels, VkFormat vk_format); - __fi VKTexture& GetTexture() { return m_texture; } - __fi VKTexture* GetTexturePtr() { return &m_texture; } - __fi VkFormat GetNativeFormat() const { return m_texture.GetFormat(); } - __fi VkImage GetImage() const { return m_texture.GetImage(); } - __fi VkImageView GetView() const { return m_texture.GetView(); } - __fi VkImageLayout GetLayout() const { return m_texture.GetLayout(); } + void Destroy(bool defer); + + __fi VkImage GetImage() const { return m_image; } + __fi VkImageView GetView() const { return m_view; } + __fi Layout GetLayout() const { return m_layout; } + __fi VkFormat GetVkFormat() const { return m_vk_format; } + + VkImageLayout GetVkLayout() const; void* GetNativeHandle() const override; @@ -43,34 +66,49 @@ public: void GenerateMipmap() override; void Swap(GSTexture* tex) override; - void TransitionToLayout(VkImageLayout layout); + void TransitionToLayout(Layout layout); void CommitClear(); void CommitClear(VkCommandBuffer cmdbuf); + // Used when the render pass is changing the image layout, or to force it to + // VK_IMAGE_LAYOUT_UNDEFINED, if the existing contents of the image is + // irrelevant and will not be loaded. + void OverrideImageLayout(Layout new_layout); + + void TransitionToLayout(VkCommandBuffer command_buffer, Layout new_layout); + void TransitionSubresourcesToLayout(VkCommandBuffer command_buffer, int start_level, int num_levels, + Layout old_layout, Layout new_layout); + /// Framebuffers are lazily allocated. VkFramebuffer GetFramebuffer(bool feedback_loop); VkFramebuffer GetLinkedFramebuffer(GSTextureVK* depth_texture, bool feedback_loop); // Call when the texture is bound to the pipeline, or read from in a copy. - __fi void SetUsedThisCommandBuffer() - { - m_use_fence_counter = g_vulkan_context->GetCurrentFenceCounter(); - } + __fi void SetUsedThisCommandBuffer() { m_use_fence_counter = g_vulkan_context->GetCurrentFenceCounter(); } private: + GSTextureVK(Type type, Format format, int width, int height, int levels, VkImage image, VmaAllocation allocation, + VkImageView view, VkFormat vk_format); + VkCommandBuffer GetCommandBufferForUpdate(); void CopyTextureDataForUpload(void* dst, const void* src, u32 pitch, u32 upload_pitch, u32 height) const; VkBuffer AllocateUploadStagingBuffer(const void* data, u32 pitch, u32 upload_pitch, u32 height) const; + void UpdateFromBuffer(VkCommandBuffer cmdbuf, int level, u32 x, u32 y, u32 width, u32 height, u32 buffer_height, + u32 row_length, VkBuffer buffer, u32 buffer_offset); - VKTexture m_texture; + VkImage m_image = VK_NULL_HANDLE; + VmaAllocation m_allocation = VK_NULL_HANDLE; + VkImageView m_view = VK_NULL_HANDLE; + VkFormat m_vk_format = VK_FORMAT_UNDEFINED; + Layout m_layout = Layout::Undefined; // Contains the fence counter when the texture was last used. // When this matches the current fence counter, the texture was used this command buffer. u64 m_use_fence_counter = 0; + int m_map_level = std::numeric_limits::max(); GSVector4i m_map_area = GSVector4i::zero(); - u32 m_map_level = UINT32_MAX; // linked framebuffer is combined with depth texture // list of color textures this depth texture is linked to or vice versa @@ -84,7 +122,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/GS/Renderers/Vulkan/VKSwapChain.cpp b/pcsx2/GS/Renderers/Vulkan/VKSwapChain.cpp index d1d9b1bfc9..d9ad02b005 100644 --- a/pcsx2/GS/Renderers/Vulkan/VKSwapChain.cpp +++ b/pcsx2/GS/Renderers/Vulkan/VKSwapChain.cpp @@ -404,16 +404,9 @@ bool VKSwapChain::SetupSwapChainImages() { SwapChainImage image; image.image = images[i]; - - // Create texture object, which creates a view of the backbuffer - if (!image.texture.Adopt(image.image, VK_IMAGE_VIEW_TYPE_2D, m_window_info.surface_width, - m_window_info.surface_height, 1, 1, m_surface_format.format, VK_SAMPLE_COUNT_1_BIT)) - { - return false; - } - - image.framebuffer = image.texture.CreateFramebuffer(m_load_render_pass); - if (image.framebuffer == VK_NULL_HANDLE) + image.texture = GSTextureVK::Adopt(images[i], GSTexture::Type::RenderTarget, GSTexture::Format::Color, + m_window_info.surface_width, m_window_info.surface_height, 1, m_surface_format.format); + if (!image.texture) return false; m_images.emplace_back(std::move(image)); @@ -452,8 +445,8 @@ void VKSwapChain::DestroySwapChainImages() { for (auto& it : m_images) { - // Images themselves are cleaned up by the swap chain object - vkDestroyFramebuffer(g_vulkan_context->GetDevice(), it.framebuffer, nullptr); + // don't defer view destruction, images are no longer valid + it.texture->Destroy(false); } m_images.clear(); for (auto& it : m_semaphores) diff --git a/pcsx2/GS/Renderers/Vulkan/VKSwapChain.h b/pcsx2/GS/Renderers/Vulkan/VKSwapChain.h index feef396005..28827ad9df 100644 --- a/pcsx2/GS/Renderers/Vulkan/VKSwapChain.h +++ b/pcsx2/GS/Renderers/Vulkan/VKSwapChain.h @@ -15,8 +15,7 @@ #pragma once -#include "GS/Renderers/Vulkan/VKLoader.h" -#include "GS/Renderers/Vulkan/VKTexture.h" +#include "GS/Renderers/Vulkan/GSTextureVK.h" #include "common/WindowInfo.h" @@ -53,11 +52,8 @@ public: __fi const u32* GetCurrentImageIndexPtr() const { return &m_current_image; } __fi u32 GetImageCount() const { return static_cast(m_images.size()); } __fi VkImage GetCurrentImage() const { return m_images[m_current_image].image; } - __fi const VKTexture& GetCurrentTexture() const { return m_images[m_current_image].texture; } - __fi VKTexture& GetCurrentTexture() { return m_images[m_current_image].texture; } - __fi VkFramebuffer GetCurrentFramebuffer() const { return m_images[m_current_image].framebuffer; } - __fi VkRenderPass GetLoadRenderPass() const { return m_load_render_pass; } - __fi VkRenderPass GetClearRenderPass() const { return m_clear_render_pass; } + __fi const GSTextureVK* GetCurrentTexture() const { return m_images[m_current_image].texture.get(); } + __fi GSTextureVK* GetCurrentTexture() { return m_images[m_current_image].texture.get(); } __fi VkSemaphore GetImageAvailableSemaphore() const { return m_semaphores[m_current_semaphore].available_semaphore; @@ -108,8 +104,7 @@ private: struct SwapChainImage { VkImage image; - VKTexture texture; - VkFramebuffer framebuffer; + std::unique_ptr texture; }; struct ImageSemaphores diff --git a/pcsx2/GS/Renderers/Vulkan/VKTexture.cpp b/pcsx2/GS/Renderers/Vulkan/VKTexture.cpp deleted file mode 100644 index 764e744aac..0000000000 --- a/pcsx2/GS/Renderers/Vulkan/VKTexture.cpp +++ /dev/null @@ -1,402 +0,0 @@ -/* 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 . - */ - -#include "PrecompiledHeader.h" - -#include "GS/Renderers/Vulkan/VKTexture.h" -#include "GS/Renderers/Vulkan/VKContext.h" -#include "GS/Renderers/Vulkan/VKUtil.h" - -#include "common/Assertions.h" -#include "common/Console.h" - -#include - -static constexpr VkComponentMapping s_identity_swizzle{VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, - VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}; - -VKTexture::VKTexture() = default; - -VKTexture::VKTexture(VKTexture&& move) - : m_width(move.m_width) - , m_height(move.m_height) - , m_levels(move.m_levels) - , m_layers(move.m_layers) - , m_format(move.m_format) - , m_samples(move.m_samples) - , m_view_type(move.m_view_type) - , m_layout(move.m_layout) - , m_image(move.m_image) - , m_allocation(move.m_allocation) - , m_view(move.m_view) -{ - move.m_width = 0; - move.m_height = 0; - move.m_levels = 0; - move.m_layers = 0; - move.m_format = VK_FORMAT_UNDEFINED; - move.m_samples = VK_SAMPLE_COUNT_1_BIT; - move.m_view_type = VK_IMAGE_VIEW_TYPE_2D; - move.m_layout = VK_IMAGE_LAYOUT_UNDEFINED; - move.m_image = VK_NULL_HANDLE; - move.m_allocation = VK_NULL_HANDLE; - move.m_view = VK_NULL_HANDLE; -} - -VKTexture::~VKTexture() -{ - if (IsValid()) - Destroy(true); -} - -VKTexture& VKTexture::operator=(VKTexture&& move) -{ - if (IsValid()) - Destroy(true); - - std::swap(m_width, move.m_width); - std::swap(m_height, move.m_height); - std::swap(m_levels, move.m_levels); - std::swap(m_layers, move.m_layers); - std::swap(m_format, move.m_format); - std::swap(m_samples, move.m_samples); - std::swap(m_view_type, move.m_view_type); - std::swap(m_layout, move.m_layout); - std::swap(m_image, move.m_image); - std::swap(m_allocation, move.m_allocation); - std::swap(m_view, move.m_view); - - return *this; -} - -bool VKTexture::Create(u32 width, u32 height, u32 levels, u32 layers, VkFormat format, VkSampleCountFlagBits samples, - VkImageViewType view_type, VkImageTiling tiling, VkImageUsageFlags usage, - const VkComponentMapping* swizzle /* = nullptr*/) -{ - const VkImageCreateInfo image_info = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, nullptr, 0, VK_IMAGE_TYPE_2D, format, - {width, height, 1}, levels, layers, samples, tiling, usage, VK_SHARING_MODE_EXCLUSIVE, 0, nullptr, - VK_IMAGE_LAYOUT_UNDEFINED}; - - VmaAllocationCreateInfo aci = {}; - aci.usage = VMA_MEMORY_USAGE_GPU_ONLY; - aci.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT; - aci.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - - VkImage image = VK_NULL_HANDLE; - VmaAllocation allocation = VK_NULL_HANDLE; - VkResult res = vmaCreateImage(g_vulkan_context->GetAllocator(), &image_info, &aci, &image, &allocation, nullptr); - if (res == VK_ERROR_OUT_OF_DEVICE_MEMORY) - { - DevCon.WriteLn("Failed to allocate device memory for %ux%u texture", width, height); - return false; - } - else if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vmaCreateImage failed: "); - return false; - } - - const VkImageViewCreateInfo view_info = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, nullptr, 0, image, view_type, - format, swizzle ? *swizzle : s_identity_swizzle, - {Vulkan::IsDepthFormat(format) ? static_cast(VK_IMAGE_ASPECT_DEPTH_BIT) : - static_cast(VK_IMAGE_ASPECT_COLOR_BIT), - 0, levels, 0, layers}}; - - VkImageView view = VK_NULL_HANDLE; - res = vkCreateImageView(g_vulkan_context->GetDevice(), &view_info, nullptr, &view); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateImageView failed: "); - vmaDestroyImage(g_vulkan_context->GetAllocator(), image, allocation); - return false; - } - - if (IsValid()) - Destroy(true); - - m_width = width; - m_height = height; - m_levels = levels; - m_layers = layers; - m_format = format; - m_samples = samples; - m_view_type = view_type; - m_image = image; - m_allocation = allocation; - m_view = view; - return true; -} - -bool VKTexture::Adopt(VkImage existing_image, VkImageViewType view_type, u32 width, u32 height, u32 levels, u32 layers, - VkFormat format, VkSampleCountFlagBits samples, const VkComponentMapping* swizzle /* = nullptr*/) -{ - // Only need to create the image view, this is mainly for swap chains. - const VkImageViewCreateInfo view_info = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, nullptr, 0, existing_image, - view_type, format, swizzle ? *swizzle : s_identity_swizzle, - {Vulkan::IsDepthFormat(format) ? static_cast(VK_IMAGE_ASPECT_DEPTH_BIT) : - static_cast(VK_IMAGE_ASPECT_COLOR_BIT), - 0, levels, 0, layers}}; - - // Memory is managed by the owner of the image. - VkImageView view = VK_NULL_HANDLE; - VkResult res = vkCreateImageView(g_vulkan_context->GetDevice(), &view_info, nullptr, &view); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateImageView failed: "); - return false; - } - - if (IsValid()) - Destroy(true); - - m_width = width; - m_height = height; - m_levels = levels; - m_layers = layers; - m_format = format; - m_samples = samples; - m_view_type = view_type; - m_image = existing_image; - m_view = view; - return true; -} - -void VKTexture::Destroy(bool defer /* = true */) -{ - if (m_view != VK_NULL_HANDLE) - { - if (defer) - g_vulkan_context->DeferImageViewDestruction(m_view); - else - vkDestroyImageView(g_vulkan_context->GetDevice(), m_view, nullptr); - m_view = VK_NULL_HANDLE; - } - - // If we don't have device memory allocated, the image is not owned by us (e.g. swapchain) - if (m_allocation != VK_NULL_HANDLE) - { - pxAssert(m_image != VK_NULL_HANDLE); - if (defer) - g_vulkan_context->DeferImageDestruction(m_image, m_allocation); - else - vmaDestroyImage(g_vulkan_context->GetAllocator(), m_image, m_allocation); - m_image = VK_NULL_HANDLE; - m_allocation = VK_NULL_HANDLE; - } - - m_width = 0; - m_height = 0; - m_levels = 0; - m_layers = 0; - m_format = VK_FORMAT_UNDEFINED; - m_samples = VK_SAMPLE_COUNT_1_BIT; - m_view_type = VK_IMAGE_VIEW_TYPE_2D; - m_layout = VK_IMAGE_LAYOUT_UNDEFINED; -} - -void VKTexture::OverrideImageLayout(VkImageLayout new_layout) -{ - m_layout = new_layout; -} - -void VKTexture::TransitionToLayout(VkCommandBuffer command_buffer, VkImageLayout new_layout) -{ - if (m_layout == new_layout) - return; - - TransitionSubresourcesToLayout(command_buffer, 0, m_levels, 0, m_layers, m_layout, new_layout); - - m_layout = new_layout; -} - -void VKTexture::TransitionSubresourcesToLayout(VkCommandBuffer command_buffer, u32 start_level, u32 num_levels, - u32 start_layer, u32 num_layers, VkImageLayout old_layout, VkImageLayout new_layout) -{ - VkImageAspectFlags aspect; - if (Vulkan::IsDepthStencilFormat(m_format)) - aspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - else if (Vulkan::IsDepthFormat(m_format)) - aspect = VK_IMAGE_ASPECT_DEPTH_BIT; - else - aspect = VK_IMAGE_ASPECT_COLOR_BIT; - - VkImageMemoryBarrier barrier = { - VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType - nullptr, // const void* pNext - 0, // VkAccessFlags srcAccessMask - 0, // VkAccessFlags dstAccessMask - old_layout, // VkImageLayout oldLayout - new_layout, // VkImageLayout newLayout - VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex - VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex - m_image, // VkImage image - {aspect, start_level, num_levels, start_layer, num_layers} // VkImageSubresourceRange subresourceRange - }; - - // srcStageMask -> Stages that must complete before the barrier - // dstStageMask -> Stages that must wait for after the barrier before beginning - VkPipelineStageFlags srcStageMask, dstStageMask; - switch (old_layout) - { - case VK_IMAGE_LAYOUT_UNDEFINED: - // Layout undefined therefore contents undefined, and we don't care what happens to it. - barrier.srcAccessMask = 0; - srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - break; - - case VK_IMAGE_LAYOUT_PREINITIALIZED: - // Image has been pre-initialized by the host, so ensure all writes have completed. - barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT; - srcStageMask = VK_PIPELINE_STAGE_HOST_BIT; - break; - - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - // Image was being used as a color attachment, so ensure all writes have completed. - barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - break; - - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - // Image was being used as a depthstencil attachment, so ensure all writes have completed. - barrier.srcAccessMask = - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - break; - - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - // Image was being used as a shader resource, make sure all reads have finished. - barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - break; - - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - // Image was being used as a copy source, ensure all reads have finished. - barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - // Image was being used as a copy destination, ensure all writes have finished. - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - - case VK_IMAGE_LAYOUT_GENERAL: - // General is used for feedback loops. - barrier.srcAccessMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ? - (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - VK_ACCESS_INPUT_ATTACHMENT_READ_BIT) : - (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT); - srcStageMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ? - (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT) : - (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - break; - - default: - srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - break; - } - - switch (new_layout) - { - case VK_IMAGE_LAYOUT_UNDEFINED: - barrier.dstAccessMask = 0; - dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - break; - - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - break; - - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - barrier.dstAccessMask = - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - break; - - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - break; - - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; - break; - - case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: - srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; - dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - break; - - case VK_IMAGE_LAYOUT_GENERAL: - // General is used for feedback loops. - barrier.dstAccessMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ? - (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | - VK_ACCESS_INPUT_ATTACHMENT_READ_BIT) : - (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | - VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT); - dstStageMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ? - (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT) : - (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - break; - - default: - dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - break; - } - vkCmdPipelineBarrier(command_buffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &barrier); -} - -VkFramebuffer VKTexture::CreateFramebuffer(VkRenderPass render_pass) -{ - const VkFramebufferCreateInfo ci = { - VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0u, render_pass, 1, &m_view, m_width, m_height, m_layers}; - VkFramebuffer fb = VK_NULL_HANDLE; - VkResult res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &ci, nullptr, &fb); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateFramebuffer() failed: "); - return VK_NULL_HANDLE; - } - - return fb; -} - -void VKTexture::UpdateFromBuffer(VkCommandBuffer cmdbuf, u32 level, u32 layer, u32 x, u32 y, u32 width, u32 height, - u32 buffer_height, u32 row_length, VkBuffer buffer, u32 buffer_offset) -{ - const VkImageLayout old_layout = m_layout; - if (old_layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) - TransitionSubresourcesToLayout(cmdbuf, level, 1, layer, 1, old_layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - const VkBufferImageCopy bic = {static_cast(buffer_offset), row_length, buffer_height, - {VK_IMAGE_ASPECT_COLOR_BIT, level, layer, 1u}, {static_cast(x), static_cast(y), 0}, - {width, height, 1u}}; - - vkCmdCopyBufferToImage(cmdbuf, buffer, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bic); - - if (old_layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) - TransitionSubresourcesToLayout(cmdbuf, level, 1, layer, 1, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, old_layout); -} diff --git a/pcsx2/GS/Renderers/Vulkan/VKTexture.h b/pcsx2/GS/Renderers/Vulkan/VKTexture.h deleted file mode 100644 index e0e77e1ccf..0000000000 --- a/pcsx2/GS/Renderers/Vulkan/VKTexture.h +++ /dev/null @@ -1,89 +0,0 @@ -/* 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/Vulkan/VKLoader.h" - -#include -#include - -class VKTexture -{ -public: - VKTexture(); - VKTexture(VKTexture&& move); - VKTexture(const VKTexture&) = delete; - ~VKTexture(); - - VKTexture& operator=(VKTexture&& move); - VKTexture& operator=(const VKTexture&) = delete; - - __fi bool IsValid() const { return (m_image != VK_NULL_HANDLE); } - - /// An image is considered owned/managed if we control the memory. - __fi bool IsOwned() const { return (m_allocation != VK_NULL_HANDLE); } - - __fi u32 GetWidth() const { return m_width; } - __fi u32 GetHeight() const { return m_height; } - __fi u32 GetLevels() const { return m_levels; } - __fi u32 GetLayers() const { return m_layers; } - __fi u32 GetMipWidth(u32 level) const { return std::max(m_width >> level, 1u); } - __fi u32 GetMipHeight(u32 level) const { return std::max(m_height >> level, 1u); } - __fi VkFormat GetFormat() const { return m_format; } - __fi VkSampleCountFlagBits GetSamples() const { return m_samples; } - __fi VkImageLayout GetLayout() const { return m_layout; } - __fi VkImageViewType GetViewType() const { return m_view_type; } - __fi VkImage GetImage() const { return m_image; } - __fi VmaAllocation GetAllocation() const { return m_allocation; } - __fi VkImageView GetView() const { return m_view; } - - bool Create(u32 width, u32 height, u32 levels, u32 layers, VkFormat format, VkSampleCountFlagBits samples, - VkImageViewType view_type, VkImageTiling tiling, VkImageUsageFlags usage, - const VkComponentMapping* swizzle = nullptr); - - bool Adopt(VkImage existing_image, VkImageViewType view_type, u32 width, u32 height, u32 levels, u32 layers, - VkFormat format, VkSampleCountFlagBits samples, const VkComponentMapping* swizzle = nullptr); - - void Destroy(bool defer = true); - - // Used when the render pass is changing the image layout, or to force it to - // VK_IMAGE_LAYOUT_UNDEFINED, if the existing contents of the image is - // irrelevant and will not be loaded. - void OverrideImageLayout(VkImageLayout new_layout); - - void TransitionToLayout(VkCommandBuffer command_buffer, VkImageLayout new_layout); - void TransitionSubresourcesToLayout(VkCommandBuffer command_buffer, u32 start_level, u32 num_levels, - u32 start_layer, u32 num_layers, VkImageLayout old_layout, VkImageLayout new_layout); - - VkFramebuffer CreateFramebuffer(VkRenderPass render_pass); - - void UpdateFromBuffer(VkCommandBuffer cmdbuf, u32 level, u32 layer, u32 x, u32 y, u32 width, u32 height, - u32 buffer_height, u32 row_length, VkBuffer buffer, u32 buffer_offset); - -private: - u32 m_width = 0; - u32 m_height = 0; - u32 m_levels = 0; - u32 m_layers = 0; - VkFormat m_format = VK_FORMAT_UNDEFINED; - VkSampleCountFlagBits m_samples = VK_SAMPLE_COUNT_1_BIT; - VkImageViewType m_view_type = VK_IMAGE_VIEW_TYPE_2D; - VkImageLayout m_layout = VK_IMAGE_LAYOUT_UNDEFINED; - - VkImage m_image = VK_NULL_HANDLE; - VmaAllocation m_allocation = VK_NULL_HANDLE; - VkImageView m_view = VK_NULL_HANDLE; -}; diff --git a/pcsx2/GS/Renderers/Vulkan/VKUtil.cpp b/pcsx2/GS/Renderers/Vulkan/VKUtil.cpp index 98042bdbe0..c3cdd63897 100644 --- a/pcsx2/GS/Renderers/Vulkan/VKUtil.cpp +++ b/pcsx2/GS/Renderers/Vulkan/VKUtil.cpp @@ -24,34 +24,6 @@ #include -bool Vulkan::IsDepthFormat(VkFormat format) -{ - switch (format) - { - case VK_FORMAT_D16_UNORM: - case VK_FORMAT_D16_UNORM_S8_UINT: - case VK_FORMAT_D24_UNORM_S8_UINT: - case VK_FORMAT_D32_SFLOAT: - case VK_FORMAT_D32_SFLOAT_S8_UINT: - return true; - default: - return false; - } -} - -bool Vulkan::IsDepthStencilFormat(VkFormat format) -{ - switch (format) - { - case VK_FORMAT_D16_UNORM_S8_UINT: - case VK_FORMAT_D24_UNORM_S8_UINT: - case VK_FORMAT_D32_SFLOAT_S8_UINT: - return true; - default: - return false; - } -} - VkFormat Vulkan::GetLinearFormat(VkFormat format) { switch (format) @@ -73,42 +45,6 @@ VkFormat Vulkan::GetLinearFormat(VkFormat format) } } -u32 Vulkan::GetTexelSize(VkFormat format) -{ - // Only contains pixel formats we use. - switch (format) - { - case VK_FORMAT_R8_UNORM: - return 1; - - case VK_FORMAT_R5G5B5A1_UNORM_PACK16: - case VK_FORMAT_A1R5G5B5_UNORM_PACK16: - case VK_FORMAT_R5G6B5_UNORM_PACK16: - case VK_FORMAT_B5G6R5_UNORM_PACK16: - case VK_FORMAT_R16_UINT: - return 2; - - case VK_FORMAT_R8G8B8A8_UNORM: - case VK_FORMAT_B8G8R8A8_UNORM: - case VK_FORMAT_R32_UINT: - case VK_FORMAT_R32_SFLOAT: - case VK_FORMAT_D32_SFLOAT: - return 4; - - case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: - return 8; - - case VK_FORMAT_BC2_UNORM_BLOCK: - case VK_FORMAT_BC3_UNORM_BLOCK: - case VK_FORMAT_BC7_UNORM_BLOCK: - return 16; - - default: - pxFailRel("Unhandled pixel format"); - return 1; - } -} - void Vulkan::SafeDestroyFramebuffer(VkFramebuffer& fb) { if (fb != VK_NULL_HANDLE) diff --git a/pcsx2/GS/Renderers/Vulkan/VKUtil.h b/pcsx2/GS/Renderers/Vulkan/VKUtil.h index 2e5ee981c4..0598dd3150 100644 --- a/pcsx2/GS/Renderers/Vulkan/VKUtil.h +++ b/pcsx2/GS/Renderers/Vulkan/VKUtil.h @@ -26,10 +26,7 @@ namespace Vulkan { - bool IsDepthFormat(VkFormat format); - bool IsDepthStencilFormat(VkFormat format); VkFormat GetLinearFormat(VkFormat format); - u32 GetTexelSize(VkFormat format); // Safe destroy helpers void SafeDestroyFramebuffer(VkFramebuffer& fb); diff --git a/pcsx2/pcsx2core.vcxproj b/pcsx2/pcsx2core.vcxproj index 9ca4bfea12..a40717bde4 100644 --- a/pcsx2/pcsx2core.vcxproj +++ b/pcsx2/pcsx2core.vcxproj @@ -207,13 +207,11 @@ - - @@ -567,14 +565,12 @@ - - @@ -906,4 +902,4 @@ - + \ No newline at end of file diff --git a/pcsx2/pcsx2core.vcxproj.filters b/pcsx2/pcsx2core.vcxproj.filters index f3d6c23ccc..cc611920e7 100644 --- a/pcsx2/pcsx2core.vcxproj.filters +++ b/pcsx2/pcsx2core.vcxproj.filters @@ -1373,9 +1373,6 @@ System\Ps2\GS\Renderers\Direct3D12 - - System\Ps2\GS\Renderers\Direct3D12 - System\Ps2\GS\Renderers\Direct3D12 @@ -1418,9 +1415,6 @@ System\Ps2\GS\Renderers\Vulkan - - System\Ps2\GS\Renderers\Vulkan - @@ -2336,9 +2330,6 @@ System\Ps2\GS\Renderers\Direct3D12 - - System\Ps2\GS\Renderers\Direct3D12 - System\Ps2\GS\Renderers\Direct3D12 @@ -2357,9 +2348,6 @@ System\Ps2\GS\Renderers\OpenGL - - System\Ps2\GS\Renderers\Vulkan - System\Ps2\GS\Renderers\Vulkan