mirror of https://github.com/PCSX2/pcsx2.git
GS: Combine texture classes and add custom layout for Vulkan
This commit is contained in:
parent
cfdae77331
commit
4a5cf0efb9
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -217,8 +217,6 @@ extern std::unique_ptr<D3D12Context> g_d3d12_context;
|
|||
|
||||
namespace D3D12
|
||||
{
|
||||
u32 GetTexelSize(DXGI_FORMAT format);
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
void SetObjectName(ID3D12Object* object, const char* name);
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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<u32>(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<D3D12MA::ALLOCATION_FLAGS>(alloc_flags) | D3D12MA::ALLOCATION_FLAG_WITHIN_BUDGET;
|
||||
allocationDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
|
||||
|
||||
ComPtr<ID3D12Resource> resource;
|
||||
ComPtr<D3D12MA::Allocation> 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<ID3D12Resource> 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<u32>(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<ID3D12Resource> resource;
|
||||
wil::com_ptr_nothrow<D3D12MA::Allocation> 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;
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GS/Renderers/DX12/D3D12DescriptorHeapManager.h"
|
||||
|
||||
namespace D3D12MA
|
||||
{
|
||||
class Allocation;
|
||||
}
|
||||
|
||||
class D3D12StreamBuffer;
|
||||
|
||||
class D3D12Texture final
|
||||
{
|
||||
public:
|
||||
template <typename T>
|
||||
using ComPtr = wil::com_ptr_nothrow<T>;
|
||||
|
||||
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<bool>(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<ID3D12Resource> 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<ID3D12Resource> m_resource;
|
||||
ComPtr<D3D12MA::Allocation> 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;
|
||||
};
|
|
@ -37,11 +37,17 @@
|
|||
#include <sstream>
|
||||
#include <limits>
|
||||
|
||||
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<D3D12_PRIMITIVE_TOPOLOGY, 3> s_primitive_topology_mapping =
|
||||
{{D3D_PRIMITIVE_TOPOLOGY_POINTLIST, D3D_PRIMITIVE_TOPOLOGY_LINELIST, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST}};
|
||||
static constexpr std::array<D3D12_PRIMITIVE_TOPOLOGY, 3> s_primitive_topology_mapping = {
|
||||
{D3D_PRIMITIVE_TOPOLOGY_POINTLIST, D3D_PRIMITIVE_TOPOLOGY_LINELIST, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST}};
|
||||
|
||||
static constexpr std::array<float, 4> 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<u32>(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<GSTexture12> 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<GSTexture12>& 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<float>(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<u32>(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<GSTexture12*>(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<GSTexture12*>(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<std::array<DXGI_FORMAT, 4>, static_cast<int>(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<std::array<DXGI_FORMAT, 4>, static_cast<int>(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<int>(format)];
|
||||
if (d3d_format)
|
||||
|
@ -712,16 +728,20 @@ GSTexture* GSDevice12::CreateSurface(GSTexture::Type type, int width, int height
|
|||
const u32 clamped_width = static_cast<u32>(std::clamp<int>(width, 1, D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION));
|
||||
const u32 clamped_height = static_cast<u32>(std::clamp<int>(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<GSTexture12> 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<GSTexture12> 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<UINT>(r.left), static_cast<UINT>(r.top), 0u,
|
||||
static_cast<UINT>(r.right), static_cast<UINT>(r.bottom), 1u};
|
||||
g_d3d12_context->GetCommandList()->CopyTextureRegion(
|
||||
&dstloc, destX, destY, 0,
|
||||
&srcloc, &srcbox);
|
||||
const D3D12_BOX srcbox{static_cast<UINT>(r.left), static_cast<UINT>(r.top), 0u, static_cast<UINT>(r.right),
|
||||
static_cast<UINT>(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<int>(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<int>(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<GSTexture12*>(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<int>(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<int>(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<GSTexture12*>(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<GSTexture12*>(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<ID3DBlob> cs_upscale(m_shader_cache.GetComputeShader(cas_source.value(), nullptr, "main"));
|
||||
const ComPtr<ID3DBlob> 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<D3D12Texture*>(pcmd->GetTexID());
|
||||
D3D12DescriptorHandle handle = tex ? tex->GetSRVDescriptor() : m_null_texture.GetSRVDescriptor();
|
||||
GSTexture12* tex = static_cast<GSTexture12*>(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<u32, NUM_CAS_CONSTANTS>& constants)
|
||||
bool GSDevice12::DoCAS(
|
||||
GSTexture* sTex, GSTexture* dTex, bool sharpen_only, const std::array<u32, NUM_CAS_CONSTANTS>& constants)
|
||||
{
|
||||
EndRenderPass();
|
||||
|
||||
GSTexture12* const sTex12 = static_cast<GSTexture12*>(sTex);
|
||||
GSTexture12* const dTex12 = static_cast<GSTexture12*>(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<u8>(ss.IsMipFilterLinear()) << 2) |
|
||||
(static_cast<u8>(ss.IsMagFilterLinear()) << 1) |
|
||||
static_cast<u8>(ss.IsMinFilterLinear());
|
||||
(static_cast<u8>(ss.IsMagFilterLinear()) << 1) | static_cast<u8>(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<ID3DBlob> 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<u8>(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<u8>(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<ID3DBlob> ps(GetUtilityPixelShader(*shader, datm ? "ps_stencil_image_init_1" : "ps_stencil_image_init_0"));
|
||||
ComPtr<ID3DBlob> 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<ID3D12PipelineState> 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<ID3D12PipelineState> 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<ID3D12PipelineState> 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<GSTexture12*>(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<float>(dst_width), static_cast<float>(dst_height), 0.0f, 1.0f};
|
||||
|
@ -2662,10 +2701,12 @@ void GSDevice12::RenderTextureMipmap(const D3D12Texture& texture,
|
|||
GSVector4(0.0f, 0.0f, static_cast<float>(dst_width), static_cast<float>(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<false>(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);
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ public:
|
|||
private:
|
||||
ComPtr<IDXGIFactory5> m_dxgi_factory;
|
||||
ComPtr<IDXGISwapChain1> m_swap_chain;
|
||||
std::vector<D3D12Texture> m_swap_chain_buffers;
|
||||
std::vector<std::unique_ptr<GSTexture12>> m_swap_chain_buffers;
|
||||
u32 m_current_swap_chain_buffer = 0;
|
||||
|
||||
bool m_allow_tearing_supported = false;
|
||||
|
@ -177,7 +177,8 @@ private:
|
|||
ComPtr<ID3D12PipelineState> m_imgui_pipeline;
|
||||
|
||||
std::unordered_map<u32, ComPtr<ID3DBlob>> m_tfx_vertex_shaders;
|
||||
std::unordered_map<GSHWDrawConfig::PSSelector, ComPtr<ID3DBlob>, GSHWDrawConfig::PSSelectorHash> m_tfx_pixel_shaders;
|
||||
std::unordered_map<GSHWDrawConfig::PSSelector, ComPtr<ID3DBlob>, GSHWDrawConfig::PSSelectorHash>
|
||||
m_tfx_pixel_shaders;
|
||||
std::unordered_map<PipelineSelector, ComPtr<ID3D12PipelineState>, PipelineSelectorHash> m_tfx_pipelines;
|
||||
|
||||
ComPtr<ID3D12RootSignature> m_cas_root_signature;
|
||||
|
@ -191,26 +192,31 @@ private:
|
|||
ComPtr<ID3DBlob> 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<u32, NUM_CAS_CONSTANTS>& constants) final;
|
||||
bool DoCAS(
|
||||
GSTexture* sTex, GSTexture* dTex, bool sharpen_only, const std::array<u32, NUM_CAS_CONSTANTS>& 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<GSTexture12> m_null_texture;
|
||||
|
||||
// current pipeline selector - we save this in the struct to avoid re-zeroing it every draw
|
||||
PipelineSelector m_pipeline_selector = {};
|
||||
|
|
|
@ -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<ID3D12Resource> resource, wil::com_ptr_nothrow<D3D12MA::Allocation> 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> 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> 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<GSTexture12>(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<GSTexture12>(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<GSTexture12>(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<GSTexture12>(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<ID3D12Resource> resource;
|
||||
wil::com_ptr_nothrow<D3D12MA::Allocation> 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<GSTexture12>(
|
||||
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> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resource> 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<GSTexture12>(new GSTexture12(type, format, static_cast<u32>(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<D3D12Texture*>(&m_texture);
|
||||
return const_cast<GSTexture12*>(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<u32>(m_map_area.width());
|
||||
const u32 height = static_cast<u32>(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<int>(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<GSTexture12*>(tex)->m_texture);
|
||||
std::swap(m_resource, static_cast<GSTexture12*>(tex)->m_resource);
|
||||
std::swap(m_allocation, static_cast<GSTexture12*>(tex)->m_allocation);
|
||||
std::swap(m_srv_descriptor, static_cast<GSTexture12*>(tex)->m_srv_descriptor);
|
||||
std::swap(m_write_descriptor, static_cast<GSTexture12*>(tex)->m_write_descriptor);
|
||||
std::swap(m_write_descriptor_type, static_cast<GSTexture12*>(tex)->m_write_descriptor_type);
|
||||
std::swap(m_dxgi_format, static_cast<GSTexture12*>(tex)->m_dxgi_format);
|
||||
std::swap(m_resource_state, static_cast<GSTexture12*>(tex)->m_resource_state);
|
||||
std::swap(m_use_fence_counter, static_cast<GSTexture12*>(tex)->m_use_fence_counter);
|
||||
std::swap(m_clear_value, static_cast<GSTexture12*>(tex)->m_clear_value);
|
||||
std::swap(m_map_area, static_cast<GSTexture12*>(tex)->m_map_area);
|
||||
std::swap(m_map_level, static_cast<GSTexture12*>(tex)->m_map_level);
|
||||
std::swap(m_map_area, static_cast<GSTexture12*>(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<u32>(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<UINT>(src.left), static_cast<UINT>(src.top), 0u, static_cast<UINT>(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;
|
||||
|
|
|
@ -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 <limits>
|
||||
|
||||
namespace D3D12MA
|
||||
{
|
||||
class Allocation;
|
||||
}
|
||||
|
||||
class GSTexture12 final : public GSTexture
|
||||
{
|
||||
public:
|
||||
GSTexture12(Type type, Format format, D3D12Texture texture);
|
||||
~GSTexture12() override;
|
||||
|
||||
static 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);
|
||||
static 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);
|
||||
static std::unique_ptr<GSTexture12> Adopt(wil::com_ptr_nothrow<ID3D12Resource> 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<ID3D12Resource> resource, wil::com_ptr_nothrow<D3D12MA::Allocation> 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<ID3D12Resource> m_resource;
|
||||
wil::com_ptr_nothrow<D3D12MA::Allocation> 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<int>::max();
|
||||
GSVector4i m_map_area = GSVector4i::zero();
|
||||
u32 m_map_level = UINT32_MAX;
|
||||
};
|
||||
|
||||
class GSDownloadTexture12 final : public GSDownloadTexture
|
||||
|
|
|
@ -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<u32>(swap_chain_texture->GetWidth()), static_cast<u32>(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<float>(swap_chain_texture.GetWidth()),
|
||||
static_cast<float>(swap_chain_texture.GetHeight()), 0.0f, 1.0f};
|
||||
const VkViewport vp{0.0f, 0.0f, static_cast<float>(swap_chain_texture->GetWidth()),
|
||||
static_cast<float>(swap_chain_texture->GetHeight()), 0.0f, 1.0f};
|
||||
const VkRect2D scissor{
|
||||
{0, 0}, {static_cast<u32>(swap_chain_texture.GetWidth()), static_cast<u32>(swap_chain_texture.GetHeight())}};
|
||||
{0, 0}, {static_cast<u32>(swap_chain_texture->GetWidth()), static_cast<u32>(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<GSTextureVK*>(t)->TransitionToLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
static_cast<GSTextureVK*>(t)->TransitionToLayout(GSTextureVK::Layout::ClearDst);
|
||||
|
||||
const VkClearDepthStencilValue dsv{0.0f, static_cast<u32>(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<GSTextureVK*>(t)->GetImage(),
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &dsv, 1, &srr);
|
||||
|
||||
static_cast<GSTextureVK*>(t)->TransitionToLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||
static_cast<GSTextureVK*>(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<u32>(std::clamp<int>(width, 1, g_vulkan_context->GetMaxImageDimension2D()));
|
||||
const u32 clamped_height = static_cast<u32>(std::clamp<int>(height, 1, g_vulkan_context->GetMaxImageDimension2D()));
|
||||
|
||||
std::unique_ptr<GSTexture> tex(GSTextureVK::Create(type, clamped_width, clamped_height, levels, format, LookupNativeFormat(format)));
|
||||
std::unique_ptr<GSTexture> 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<GSTextureVK*>(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<GSTextureVK*>(dTex)->TransitionToLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
static_cast<GSTextureVK*>(dTex)->TransitionToLayout(GSTextureVK::Layout::ColorAttachment);
|
||||
if (sTex[0])
|
||||
static_cast<GSTextureVK*>(sTex[0])->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
static_cast<GSTextureVK*>(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<GSTextureVK*>(sTex[1])->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
static_cast<GSTextureVK*>(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<GSTextureVK*>(sTex[2])->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
static_cast<GSTextureVK*>(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<GSTextureVK*>(dTex)->CommitClear();
|
||||
static_cast<GSTextureVK*>(dTex)->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
static_cast<GSTextureVK*>(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<GSTextureVK*>(dTex)->TransitionToLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
static_cast<GSTextureVK*>(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<GSTextureVK*>(dTex)->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
static_cast<GSTextureVK*>(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<GSTextureVK*>(dTex)->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
static_cast<GSTextureVK*>(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<GSTextureVK*>(dTex)->TransitionToLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
static_cast<GSTextureVK*>(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<VKTexture*>(pcmd->GetTexID());
|
||||
if (m_utility_texture != tex)
|
||||
{
|
||||
m_utility_texture = tex;
|
||||
m_dirty_flags |= DIRTY_FLAG_UTILITY_TEXTURE;
|
||||
}
|
||||
GSTextureVK* tex = static_cast<GSTextureVK*>(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<GSTextureVK*>(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<u8>(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<GSTextureVK*>(sr);
|
||||
if (vkTex)
|
||||
{
|
||||
GSTextureVK* vkTex = static_cast<GSTextureVK*>(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<GSTextureVK*>(tex);
|
||||
if (vkTex)
|
||||
{
|
||||
GSTextureVK* vkTex = static_cast<GSTextureVK*>(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<VkDescriptorSet, NUM_TFX_DESCRIPTOR_SETS> 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<GSTextureVK*>(config.rt)->GetTexturePtr() == m_tfx_textures[0]) ||
|
||||
(config.ds && static_cast<GSTextureVK*>(config.ds)->GetTexturePtr() == m_tfx_textures[0])))
|
||||
if (!config.tex && ((!pipe.IsRTFeedbackLoop() && static_cast<GSTextureVK*>(config.rt) == m_tfx_textures[0]) ||
|
||||
(config.ds && static_cast<GSTextureVK*>(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<FeedbackLoopFlag>(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<GSTextureVK*>(config.rt);
|
||||
OMSetRenderTargets(draw_rt, draw_ds, config.scissor, static_cast<FeedbackLoopFlag>(pipe.feedback_loop_flags));
|
||||
|
|
|
@ -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<const VKTexture*, NUM_TFX_TEXTURES> m_tfx_textures{};
|
||||
std::array<const GSTextureVK*, NUM_TFX_TEXTURES> m_tfx_textures{};
|
||||
VkSampler m_tfx_sampler = VK_NULL_HANDLE;
|
||||
u32 m_tfx_sampler_sel = 0;
|
||||
std::array<VkDescriptorSet, NUM_TFX_DESCRIPTOR_SETS> 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<u32, NUM_TFX_DYNAMIC_OFFSETS> 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<GSTextureVK> m_null_texture;
|
||||
|
||||
// current pipeline selector - we save this in the struct to avoid re-zeroing it every draw
|
||||
PipelineSelector m_pipeline_selector = {};
|
||||
|
|
|
@ -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<VkImageLayout, static_cast<u32>(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> 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<u32>(width), static_cast<u32>(height), 1}, static_cast<u32>(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<u32>(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<GSTextureVK>(
|
||||
new GSTextureVK(type, format, width, height, levels, image, allocation, view, vk_format));
|
||||
}
|
||||
|
||||
std::unique_ptr<GSTextureVK> 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<VkImageAspectFlags>(VK_IMAGE_ASPECT_DEPTH_BIT) :
|
||||
static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_COLOR_BIT),
|
||||
0u, static_cast<u32>(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<GSTextureVK>(
|
||||
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> 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<GSTextureVK>(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<GSTextureVK>(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<GSTextureVK>(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<GSTextureVK>(type, format, std::move(texture));
|
||||
}
|
||||
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
return s_vk_layout_mapping[static_cast<u32>(m_layout)];
|
||||
}
|
||||
|
||||
void* GSTextureVK::GetNativeHandle() const
|
||||
{
|
||||
return const_cast<VKTexture*>(&m_texture);
|
||||
return const_cast<GSTextureVK*>(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<VkDeviceSize>(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<VkDeviceSize>(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<VkDeviceSize>(buffer_offset), row_length, buffer_height,
|
||||
{VK_IMAGE_ASPECT_COLOR_BIT, static_cast<u32>(level), 0u, 1u}, {static_cast<s32>(x), static_cast<s32>(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<u32>(m_map_area.width());
|
||||
const u32 height = static_cast<u32>(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<int>(m_size.x >> dst_level, 1);
|
||||
const int dst_height = std::max<int>(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<u32>(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<GSTextureVK*>(tex)->m_texture);
|
||||
std::swap(m_image, static_cast<GSTextureVK*>(tex)->m_image);
|
||||
std::swap(m_allocation, static_cast<GSTextureVK*>(tex)->m_allocation);
|
||||
std::swap(m_view, static_cast<GSTextureVK*>(tex)->m_view);
|
||||
std::swap(m_vk_format, static_cast<GSTextureVK*>(tex)->m_vk_format);
|
||||
std::swap(m_layout, static_cast<GSTextureVK*>(tex)->m_layout);
|
||||
std::swap(m_use_fence_counter, static_cast<GSTextureVK*>(tex)->m_use_fence_counter);
|
||||
std::swap(m_clear_value, static_cast<GSTextureVK*>(tex)->m_clear_value);
|
||||
std::swap(m_map_area, static_cast<GSTextureVK*>(tex)->m_map_area);
|
||||
|
@ -394,11 +523,6 @@ void GSTextureVK::Swap(GSTexture* tex)
|
|||
std::swap(m_framebuffers, static_cast<GSTextureVK*>(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<true>(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<u32>(old_layout)], s_vk_layout_mapping[static_cast<u32>(new_layout)],
|
||||
VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, m_image,
|
||||
{aspect, static_cast<u32>(start_level), static_cast<u32>(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> 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> GSDownloadTextureVK::Create(u32 width, u32
|
|||
return {};
|
||||
}
|
||||
|
||||
std::unique_ptr<GSDownloadTextureVK> tex = std::unique_ptr<GSDownloadTextureVK>(new GSDownloadTextureVK(width, height, format));
|
||||
std::unique_ptr<GSDownloadTextureVK> tex =
|
||||
std::unique_ptr<GSDownloadTextureVK>(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<u32>(drc.width()) : m_width, g_vulkan_context->GetBufferCopyRowPitchAlignment());
|
||||
m_current_pitch = GetTransferPitch(use_transfer_pitch ? static_cast<u32>(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<VkFormat>(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<u32>(src.width()), static_cast<u32>(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;
|
||||
|
|
|
@ -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 <limits>
|
||||
|
||||
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<GSTextureVK> Create(Type type, u32 width, u32 height, u32 levels, Format format, VkFormat vk_format);
|
||||
static std::unique_ptr<GSTextureVK> Create(Type type, Format format, int width, int height, int levels);
|
||||
static std::unique_ptr<GSTextureVK> 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<int>::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<GSDownloadTextureVK> 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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<u32>(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<GSTextureVK> texture;
|
||||
};
|
||||
|
||||
struct ImageSemaphores
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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 <algorithm>
|
||||
|
||||
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<VkImageAspectFlags>(VK_IMAGE_ASPECT_DEPTH_BIT) :
|
||||
static_cast<VkImageAspectFlags>(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<VkImageAspectFlags>(VK_IMAGE_ASPECT_DEPTH_BIT) :
|
||||
static_cast<VkImageAspectFlags>(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<VkDeviceSize>(buffer_offset), row_length, buffer_height,
|
||||
{VK_IMAGE_ASPECT_COLOR_BIT, level, layer, 1u}, {static_cast<int32_t>(x), static_cast<int32_t>(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);
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GS/Renderers/Vulkan/VKLoader.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
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<u32>(m_width >> level, 1u); }
|
||||
__fi u32 GetMipHeight(u32 level) const { return std::max<u32>(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;
|
||||
};
|
|
@ -24,34 +24,6 @@
|
|||
|
||||
#include <cmath>
|
||||
|
||||
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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -207,13 +207,11 @@
|
|||
<ClCompile Include="GS\Renderers\DX12\D3D12DescriptorHeapManager.cpp" />
|
||||
<ClCompile Include="GS\Renderers\DX12\D3D12ShaderCache.cpp" />
|
||||
<ClCompile Include="GS\Renderers\DX12\D3D12StreamBuffer.cpp" />
|
||||
<ClCompile Include="GS\Renderers\DX12\D3D12Texture.cpp" />
|
||||
<ClCompile Include="GS\Renderers\OpenGL\GLContext.cpp" />
|
||||
<ClCompile Include="GS\Renderers\OpenGL\GLContextWGL.cpp" />
|
||||
<ClCompile Include="GS\Renderers\OpenGL\GLProgram.cpp" />
|
||||
<ClCompile Include="GS\Renderers\OpenGL\GLShaderCache.cpp" />
|
||||
<ClCompile Include="GS\Renderers\OpenGL\GLStreamBuffer.cpp" />
|
||||
<ClCompile Include="GS\Renderers\Vulkan\VKTexture.cpp" />
|
||||
<ClCompile Include="GS\Renderers\Vulkan\VKBuilders.cpp" />
|
||||
<ClCompile Include="GS\Renderers\Vulkan\VKContext.cpp" />
|
||||
<ClCompile Include="GS\Renderers\Vulkan\VKLoader.cpp" />
|
||||
|
@ -567,14 +565,12 @@
|
|||
<ClInclude Include="GS\Renderers\DX12\D3D12DescriptorHeapManager.h" />
|
||||
<ClInclude Include="GS\Renderers\DX12\D3D12ShaderCache.h" />
|
||||
<ClInclude Include="GS\Renderers\DX12\D3D12StreamBuffer.h" />
|
||||
<ClInclude Include="GS\Renderers\DX12\D3D12Texture.h" />
|
||||
<ClInclude Include="GS\Renderers\HW\GSHwHack.h" />
|
||||
<ClInclude Include="GS\Renderers\OpenGL\GLContext.h" />
|
||||
<ClInclude Include="GS\Renderers\OpenGL\GLContextWGL.h" />
|
||||
<ClInclude Include="GS\Renderers\OpenGL\GLProgram.h" />
|
||||
<ClInclude Include="GS\Renderers\OpenGL\GLShaderCache.h" />
|
||||
<ClInclude Include="GS\Renderers\OpenGL\GLStreamBuffer.h" />
|
||||
<ClInclude Include="GS\Renderers\Vulkan\VKTexture.h" />
|
||||
<ClInclude Include="GS\Renderers\Vulkan\VKBuilders.h" />
|
||||
<ClInclude Include="GS\Renderers\Vulkan\VKContext.h" />
|
||||
<ClInclude Include="GS\Renderers\Vulkan\VKEntryPoints.h" />
|
||||
|
|
|
@ -1373,9 +1373,6 @@
|
|||
<ClCompile Include="GS\Renderers\DX12\D3D12StreamBuffer.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Direct3D12</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\DX12\D3D12Texture.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Direct3D12</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\DX12\D3D12Builders.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Direct3D12</Filter>
|
||||
</ClCompile>
|
||||
|
@ -1418,9 +1415,6 @@
|
|||
<ClCompile Include="GS\Renderers\Vulkan\VKUtil.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Vulkan</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\Vulkan\VKTexture.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Vulkan</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Patch.h">
|
||||
|
@ -2336,9 +2330,6 @@
|
|||
<ClInclude Include="GS\Renderers\DX12\D3D12StreamBuffer.h">
|
||||
<Filter>System\Ps2\GS\Renderers\Direct3D12</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GS\Renderers\DX12\D3D12Texture.h">
|
||||
<Filter>System\Ps2\GS\Renderers\Direct3D12</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GS\Renderers\DX12\D3D12Builders.h">
|
||||
<Filter>System\Ps2\GS\Renderers\Direct3D12</Filter>
|
||||
</ClInclude>
|
||||
|
@ -2357,9 +2348,6 @@
|
|||
<ClInclude Include="GS\Renderers\OpenGL\GLContext.h">
|
||||
<Filter>System\Ps2\GS\Renderers\OpenGL</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GS\Renderers\Vulkan\VKTexture.h">
|
||||
<Filter>System\Ps2\GS\Renderers\Vulkan</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GS\Renderers\Vulkan\VKBuilders.h">
|
||||
<Filter>System\Ps2\GS\Renderers\Vulkan</Filter>
|
||||
</ClInclude>
|
||||
|
|
Loading…
Reference in New Issue