mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-07-11 01:34:17 +02:00
GS: Change GSTexture::Type to GSTexture::Usage
Usage fits more cleanly with API flags. Also separates out feedback and write usage from render target. Co-authored-by: TellowKrinkle
This commit is contained in:
@@ -163,6 +163,7 @@
|
||||
<ClInclude Include="WindowInfo.h" />
|
||||
<ClInclude Include="YAML.h" />
|
||||
<ClInclude Include="Threading.h" />
|
||||
<ClInclude Include="EnumOps.h" />
|
||||
<ClInclude Include="emitter\implement\avx.h" />
|
||||
<ClInclude Include="emitter\implement\bmi.h" />
|
||||
<ClInclude Include="emitter\instructions.h" />
|
||||
|
||||
+1
-1
@@ -447,7 +447,7 @@ void GSClut::Read32(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA)
|
||||
if (!dst)
|
||||
{
|
||||
// allocate texture lazily
|
||||
dst = g_gs_device->CreateRenderTarget(dst_size, 1, GSTexture::Format::Color, false);
|
||||
dst = g_gs_device->CreateFeedbackTarget(dst_size, 1, GSTexture::Format::Color, false);
|
||||
is_4bit ? (m_gpu_clut4 = dst) : (m_gpu_clut8 = dst);
|
||||
m_gpu_clut_dirty = true;
|
||||
}
|
||||
|
||||
@@ -144,53 +144,59 @@ enum class TextureLabel
|
||||
|
||||
static std::array<u32, static_cast<u32>(TextureLabel::Last) + 1> s_texture_counts;
|
||||
|
||||
static TextureLabel GetTextureLabel(GSTexture::Type type, GSTexture::Format format)
|
||||
static TextureLabel GetTextureLabel(GSTexture::Usage usage, GSTexture::Format format)
|
||||
{
|
||||
switch (type)
|
||||
if (GSTexture::IsRenderTarget(usage))
|
||||
{
|
||||
case GSTexture::Type::RenderTarget:
|
||||
switch (format)
|
||||
{
|
||||
case GSTexture::Format::Color:
|
||||
return TextureLabel::ColorRT;
|
||||
case GSTexture::Format::ColorHQ:
|
||||
return TextureLabel::ColorHQRT;
|
||||
case GSTexture::Format::ColorHDR:
|
||||
return TextureLabel::ColorHDRRT;
|
||||
case GSTexture::Format::ColorClip:
|
||||
return TextureLabel::ColorClipRT;
|
||||
case GSTexture::Format::UInt16:
|
||||
return TextureLabel::U16RT;
|
||||
case GSTexture::Format::UInt32:
|
||||
return TextureLabel::U32RT;
|
||||
case GSTexture::Format::PrimID:
|
||||
return TextureLabel::PrimIDTexture;
|
||||
default:
|
||||
return TextureLabel::Other;
|
||||
}
|
||||
case GSTexture::Type::Texture:
|
||||
switch (format)
|
||||
{
|
||||
case GSTexture::Format::Color:
|
||||
return TextureLabel::Texture;
|
||||
case GSTexture::Format::UNorm8:
|
||||
return TextureLabel::CLUTTexture;
|
||||
case GSTexture::Format::BC1:
|
||||
case GSTexture::Format::BC2:
|
||||
case GSTexture::Format::BC3:
|
||||
case GSTexture::Format::BC7:
|
||||
case GSTexture::Format::ColorHDR:
|
||||
return TextureLabel::ReplacementTexture;
|
||||
default:
|
||||
return TextureLabel::Other;
|
||||
}
|
||||
case GSTexture::Type::DepthStencil:
|
||||
return TextureLabel::DepthStencil;
|
||||
case GSTexture::Type::RWTexture:
|
||||
return TextureLabel::RWTexture;
|
||||
case GSTexture::Type::Invalid:
|
||||
default:
|
||||
return TextureLabel::Other;
|
||||
switch (format)
|
||||
{
|
||||
case GSTexture::Format::Color:
|
||||
return TextureLabel::ColorRT;
|
||||
case GSTexture::Format::ColorHQ:
|
||||
return TextureLabel::ColorHQRT;
|
||||
case GSTexture::Format::ColorHDR:
|
||||
return TextureLabel::ColorHDRRT;
|
||||
case GSTexture::Format::ColorClip:
|
||||
return TextureLabel::ColorClipRT;
|
||||
case GSTexture::Format::UInt16:
|
||||
return TextureLabel::U16RT;
|
||||
case GSTexture::Format::UInt32:
|
||||
return TextureLabel::U32RT;
|
||||
case GSTexture::Format::PrimID:
|
||||
return TextureLabel::PrimIDTexture;
|
||||
default:
|
||||
return TextureLabel::Other;
|
||||
}
|
||||
}
|
||||
else if (GSTexture::IsTexture(usage))
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case GSTexture::Format::Color:
|
||||
return TextureLabel::Texture;
|
||||
case GSTexture::Format::UNorm8:
|
||||
return TextureLabel::CLUTTexture;
|
||||
case GSTexture::Format::BC1:
|
||||
case GSTexture::Format::BC2:
|
||||
case GSTexture::Format::BC3:
|
||||
case GSTexture::Format::BC7:
|
||||
case GSTexture::Format::ColorHDR:
|
||||
return TextureLabel::ReplacementTexture;
|
||||
default:
|
||||
return TextureLabel::Other;
|
||||
}
|
||||
}
|
||||
else if (GSTexture::IsDepthStencil(usage))
|
||||
{
|
||||
return TextureLabel::DepthStencil;
|
||||
}
|
||||
else if (GSTexture::IsShaderWrite(usage))
|
||||
{
|
||||
return TextureLabel::RWTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
return TextureLabel::Other;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -594,11 +600,16 @@ void GSDevice::TextureRecycleDeleter::operator()(GSTexture* const tex)
|
||||
g_gs_device->Recycle(tex);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format, bool clear, bool prefer_unused_texture)
|
||||
GSTexture* GSDevice::FetchSurface(GSTexture::Usage usage, const GSVector2i& size, int levels, GSTexture::Format format, bool clear, bool prefer_unused_texture)
|
||||
{
|
||||
return FetchSurface(usage, size.x, size.y, levels, format, clear, prefer_unused_texture);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::FetchSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format, bool clear, bool prefer_unused_texture)
|
||||
{
|
||||
const GSVector2i size(std::clamp(width, 1, static_cast<int>(g_gs_device->GetMaxTextureSize())),
|
||||
std::clamp(height, 1, static_cast<int>(g_gs_device->GetMaxTextureSize())));
|
||||
FastList<GSTexture*>& pool = m_pool[type != GSTexture::Type::Texture];
|
||||
FastList<GSTexture*>& pool = m_pool[!GSTexture::IsTexture(usage)];
|
||||
|
||||
GSTexture* t = nullptr;
|
||||
auto fallback = pool.end();
|
||||
@@ -609,7 +620,7 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i
|
||||
|
||||
pxAssert(t);
|
||||
|
||||
if (t->GetType() == type && t->GetFormat() == format && t->GetSize() == size && t->GetMipmapLevels() == levels)
|
||||
if (t->GetUsage() == usage && t->GetFormat() == format && t->GetSize() == size && t->GetMipmapLevels() == levels)
|
||||
{
|
||||
if (!prefer_unused_texture || t->GetLastFrameUsed() != m_frame)
|
||||
{
|
||||
@@ -628,7 +639,7 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i
|
||||
|
||||
if (!t)
|
||||
{
|
||||
if (pool.size() >= ((type == GSTexture::Type::Texture) ? MAX_POOLED_TEXTURES : MAX_POOLED_TARGETS) &&
|
||||
if (pool.size() >= (GSTexture::IsTexture(usage) ? MAX_POOLED_TEXTURES : MAX_POOLED_TARGETS) &&
|
||||
fallback != pool.end())
|
||||
{
|
||||
t = *fallback;
|
||||
@@ -637,12 +648,12 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i
|
||||
}
|
||||
else
|
||||
{
|
||||
t = CreateSurface(type, size.x, size.y, levels, format);
|
||||
t = CreateSurface(usage, size.x, size.y, levels, format);
|
||||
if (!t)
|
||||
{
|
||||
ERROR_LOG("GS: Memory allocation failure for {}x{} texture. Purging pool and retrying.", size.x, size.y);
|
||||
PurgePool();
|
||||
t = CreateSurface(type, size.x, size.y, levels, format);
|
||||
t = CreateSurface(usage, size.x, size.y, levels, format);
|
||||
if (!t)
|
||||
{
|
||||
ERROR_LOG("GS: Memory allocation failure for {}x{} texture after purging pool.", size.x, size.y);
|
||||
@@ -653,7 +664,7 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
if (GSConfig.UseDebugDevice)
|
||||
{
|
||||
const TextureLabel label = GetTextureLabel(type, format);
|
||||
const TextureLabel label = GetTextureLabel(usage, format);
|
||||
const u32 id = ++s_texture_counts[static_cast<u32>(label)];
|
||||
t->SetDebugName(TinyString::from_format("{} {}", TextureLabelString(label), id));
|
||||
}
|
||||
@@ -661,26 +672,19 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i
|
||||
}
|
||||
}
|
||||
|
||||
switch (type)
|
||||
if (t->IsRenderTarget())
|
||||
{
|
||||
case GSTexture::Type::RenderTarget:
|
||||
{
|
||||
if (clear)
|
||||
ClearRenderTarget(t, 0);
|
||||
else
|
||||
InvalidateRenderTarget(t);
|
||||
}
|
||||
break;
|
||||
case GSTexture::Type::DepthStencil:
|
||||
{
|
||||
if (clear)
|
||||
ClearDepth(t, 0.0f);
|
||||
else
|
||||
InvalidateRenderTarget(t);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (clear)
|
||||
ClearRenderTarget(t, 0);
|
||||
else
|
||||
InvalidateRenderTarget(t);
|
||||
}
|
||||
else if (t->IsDepthStencil())
|
||||
{
|
||||
if (clear)
|
||||
ClearDepth(t, 0.0f);
|
||||
else
|
||||
InvalidateRenderTarget(t);
|
||||
}
|
||||
|
||||
return t;
|
||||
@@ -762,46 +766,52 @@ void GSDevice::PurgePool()
|
||||
|
||||
GSTexture* GSDevice::CreateRenderTarget(int w, int h, GSTexture::Format format, bool clear, bool prefer_reuse)
|
||||
{
|
||||
return FetchSurface(GSTexture::Type::RenderTarget, w, h, 1, format, clear, !prefer_reuse);
|
||||
return FetchSurface(GSTexture::RenderTarget, w, h, 1, format, clear, !prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::CreateRenderTarget(const GSVector2i& size, GSTexture::Format format, bool clear, bool prefer_reuse)
|
||||
{
|
||||
return FetchSurface(GSTexture::Type::RenderTarget, size.x, size.y, 1, format, clear, !prefer_reuse);
|
||||
return FetchSurface(GSTexture::RenderTarget, size.x, size.y, 1, format, clear, !prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::CreateFeedbackTarget(int w, int h, GSTexture::Format format, bool clear, bool prefer_reuse)
|
||||
{
|
||||
return FetchSurface(GSTexture::FeedbackTarget, w, h, 1, format, clear, !prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::CreateFeedbackTarget(const GSVector2i& size, GSTexture::Format format, bool clear, bool prefer_reuse)
|
||||
{
|
||||
return FetchSurface(GSTexture::FeedbackTarget, size.x, size.y, 1, format, clear, !prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::CreateShaderWriteTarget(int w, int h, GSTexture::Format format, bool clear, bool prefer_reuse)
|
||||
{
|
||||
return FetchSurface(GSTexture::ShaderWriteTarget, w, h, 1, format, clear, !prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::CreateShaderWriteTarget(const GSVector2i& size, GSTexture::Format format, bool clear, bool prefer_reuse)
|
||||
{
|
||||
return FetchSurface(GSTexture::ShaderWriteTarget, size.x, size.y, 1, format, clear, !prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::CreateDepthStencil(int w, int h, bool clear, bool prefer_reuse)
|
||||
{
|
||||
return FetchSurface(GSTexture::Type::DepthStencil, w, h, 1, GSTexture::Format::DepthStencil,
|
||||
clear, !prefer_reuse);
|
||||
return FetchSurface(GSTexture::DepthStencil, w, h, 1, GSTexture::Format::DepthStencil, clear, !prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::CreateDepthStencil(const GSVector2i& size, bool clear, bool prefer_reuse)
|
||||
{
|
||||
return FetchSurface(GSTexture::Type::DepthStencil, size.x, size.y, 1, GSTexture::Format::DepthStencil,
|
||||
clear, !prefer_reuse);
|
||||
return FetchSurface(GSTexture::DepthStencil, size.x, size.y, 1, GSTexture::Format::DepthStencil, clear, !prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::CreateDepthColor(int w, int h, bool clear, bool prefer_reuse)
|
||||
{
|
||||
return FetchSurface(GSTexture::Type::RenderTarget, w, h, 1, GSTexture::Format::DepthColor,
|
||||
clear, !prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::CreateDepthColor(const GSVector2i& size, bool clear, bool prefer_reuse)
|
||||
{
|
||||
return FetchSurface(GSTexture::Type::RenderTarget, size.x, size.y, 1, GSTexture::Format::DepthColor,
|
||||
clear, !prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::CreateTexture(int w, int h, int mipmap_levels, GSTexture::Format format, bool prefer_reuse /* = false */)
|
||||
GSTexture* GSDevice::CreateTexture(int w, int h, int mipmap_levels, GSTexture::Format format, bool prefer_reuse)
|
||||
{
|
||||
pxAssert(mipmap_levels != 0 && (mipmap_levels < 0 || mipmap_levels <= GetMipmapLevelsForSize(w, h)));
|
||||
const int levels = mipmap_levels < 0 ? GetMipmapLevelsForSize(w, h) : mipmap_levels;
|
||||
return FetchSurface(GSTexture::Type::Texture, w, h, levels, format, false, m_features.prefer_new_textures && !prefer_reuse);
|
||||
return FetchSurface(GSTexture::Texture, w, h, levels, format, false, m_features.prefer_new_textures && !prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::CreateTexture(const GSVector2i& size, int mipmap_levels, GSTexture::Format format, bool prefer_reuse /* = false */)
|
||||
GSTexture* GSDevice::CreateTexture(const GSVector2i& size, int mipmap_levels, GSTexture::Format format, bool prefer_reuse)
|
||||
{
|
||||
return CreateTexture(size.x, size.y, mipmap_levels, format, prefer_reuse);
|
||||
}
|
||||
@@ -818,7 +828,7 @@ GSTexture* GSDevice::CreateCompatible(GSTexture* tex, const GSVector2i& size, bo
|
||||
|
||||
GSTexture* GSDevice::CreateCompatible(GSTexture* tex, int w, int h, bool clear, bool prefer_reuse)
|
||||
{
|
||||
return FetchSurface(tex->GetType(), w, h, 1, tex->GetFormat(), clear, !prefer_reuse);
|
||||
return FetchSurface(tex->GetUsage(), w, h, 1, tex->GetFormat(), clear, !prefer_reuse);
|
||||
}
|
||||
|
||||
void GSDevice::DoStretchRectWithAssertions(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex,
|
||||
@@ -1070,8 +1080,9 @@ bool GSDevice::ResizeRenderTarget(GSTexture** t, int w, int h, bool preserve_con
|
||||
}
|
||||
|
||||
const GSTexture::Format fmt = orig_tex ? orig_tex->GetFormat() : GSTexture::Format::Color;
|
||||
const GSTexture::Usage usage = orig_tex ? orig_tex->GetUsage() : GSTexture::RenderTarget;
|
||||
const bool really_preserve_contents = (preserve_contents && orig_tex);
|
||||
GSTexture* new_tex = FetchSurface(GSTexture::Type::RenderTarget, w, h, 1, fmt, !really_preserve_contents, true);
|
||||
GSTexture* new_tex = FetchSurface(usage, w, h, 1, fmt, !really_preserve_contents, true);
|
||||
if (!new_tex)
|
||||
{
|
||||
Console.WriteLn("%dx%d texture allocation failed in ResizeTexture()", w, h);
|
||||
@@ -1102,7 +1113,7 @@ void GSDevice::BeginDSAsRT(GSTexture* ds, const GSVector4i& drawarea)
|
||||
// Create a temporary RT and copy the area needed for the draw.
|
||||
const int w = ds->GetWidth();
|
||||
const int h = ds->GetHeight();
|
||||
m_ds_as_rt = g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::DepthColor, false, true);
|
||||
m_ds_as_rt = g_gs_device->CreateFeedbackTarget(w, h, GSTexture::Format::DepthColor, false, true);
|
||||
const GSVector4 dRect(drawarea);
|
||||
const GSVector4 sRect(dRect.x / w, dRect.y / h, dRect.z / w, dRect.w / h);
|
||||
StretchRectAuto(ds, sRect, m_ds_as_rt, dRect, Nearest);
|
||||
@@ -1158,7 +1169,7 @@ void GSDevice::CAS(GSTexture*& tex, GSVector4i& src_rect, GSVector4& src_uv, con
|
||||
if (!m_cas || m_cas->GetWidth() != dst_width || m_cas->GetHeight() != dst_height)
|
||||
{
|
||||
delete m_cas;
|
||||
m_cas = CreateSurface(GSTexture::Type::RWTexture, dst_width, dst_height, 1, GSTexture::Format::Color);
|
||||
m_cas = CreateSurface(GSTexture::ShaderWriteTexture, dst_width, dst_height, 1, GSTexture::Format::Color);
|
||||
if (!m_cas)
|
||||
{
|
||||
Console.Error("Failed to allocate CAS RW texture.");
|
||||
|
||||
@@ -1482,8 +1482,7 @@ protected:
|
||||
|
||||
bool AcquireWindow(bool recreate_window);
|
||||
|
||||
virtual GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) = 0;
|
||||
GSTexture* FetchSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format, bool clear, bool prefer_unused_texture);
|
||||
virtual GSTexture* CreateSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format) = 0;
|
||||
|
||||
virtual void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const Filter filter) = 0;
|
||||
virtual void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, Filter filter, const InterlaceConstantBuffer& cb) = 0;
|
||||
@@ -1626,13 +1625,17 @@ public:
|
||||
virtual void PopDebugGroup() = 0;
|
||||
virtual void InsertDebugMessage(DebugMessageCategory category, const char* fmt, ...) = 0;
|
||||
|
||||
GSTexture* FetchSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format, bool clear, bool prefer_unused_texture);
|
||||
GSTexture* FetchSurface(GSTexture::Usage usage, const GSVector2i& size, int levels, GSTexture::Format format, bool clear, bool prefer_unused_texture);
|
||||
GSTexture* CreateRenderTarget(int w, int h, GSTexture::Format format, bool clear = true, bool prefer_reuse = true);
|
||||
GSTexture* CreateDepthStencil(int w, int h, bool clear = true, bool prefer_reuse = true);
|
||||
GSTexture* CreateDepthColor(int w, int h, bool clear = true, bool prefer_reuse = true);
|
||||
GSTexture* CreateTexture(int w, int h, int mipmap_levels, GSTexture::Format format, bool prefer_reuse = false);
|
||||
GSTexture* CreateRenderTarget(const GSVector2i& size, GSTexture::Format format, bool clear = true, bool prefer_reuse = true);
|
||||
GSTexture* CreateFeedbackTarget(int w, int h, GSTexture::Format format, bool clear = true, bool prefer_reuse = true);
|
||||
GSTexture* CreateFeedbackTarget(const GSVector2i& size, GSTexture::Format format, bool clear = true, bool prefer_reuse = true);
|
||||
GSTexture* CreateShaderWriteTarget(int w, int h, GSTexture::Format format, bool clear = true, bool prefer_reuse = true);
|
||||
GSTexture* CreateShaderWriteTarget(const GSVector2i& size, GSTexture::Format format, bool clear = true, bool prefer_reuse = true);
|
||||
GSTexture* CreateDepthStencil(int w, int h, bool clear = true, bool prefer_reuse = true);
|
||||
GSTexture* CreateDepthStencil(const GSVector2i& size, bool clear = true, bool prefer_reuse = true);
|
||||
GSTexture* CreateDepthColor(const GSVector2i& size, bool clear = true, bool prefer_reuse = true);
|
||||
GSTexture* CreateTexture(int w, int h, int mipmap_levels, GSTexture::Format format, bool prefer_reuse = false);
|
||||
GSTexture* CreateTexture(const GSVector2i& size, int mipmap_levels, GSTexture::Format format, bool prefer_reuse = false);
|
||||
GSTexture* CreateCompatible(GSTexture* tex, bool clear = true, bool prefer_reuse = true);
|
||||
GSTexture* CreateCompatible(GSTexture* tex, const GSVector2i& size, bool clear = true, bool prefer_reuse = true);
|
||||
|
||||
@@ -16,6 +16,30 @@ GSTexture::GSTexture() = default;
|
||||
|
||||
GSTexture::~GSTexture() = default;
|
||||
|
||||
bool GSTexture::ValidateUsageAndFormat(Usage usage, Format format)
|
||||
{
|
||||
if (IsDepthStencil(usage) && (usage & (Usage::ShaderWrite | Usage::RenderTarget)))
|
||||
return false; // DS is not compatible with Write or RT
|
||||
if (IsFeedback(usage) && !(usage & (Usage::DepthStencil | Usage::RenderTarget)))
|
||||
return false; // Feedback requires RT or DS
|
||||
if (usage == (Usage::ShaderWrite | Usage::RenderTarget))
|
||||
return false; // We always include Feedback for RT+Write
|
||||
if (format == Format::UNorm8 && !IsTexture(usage)) // Unorm8 only used for sampling
|
||||
return false;
|
||||
if (IsFeedback(usage) && !IsFeedbackFormat(format)) // Only some formats used with feedback
|
||||
return false;
|
||||
if (IsShaderWrite(usage) && !IsShaderWriteFormat(format)) // Only some formats used with shader write
|
||||
return false;
|
||||
if (IsDepthStencil(usage) && (format != Format::DepthStencil)) // Only use DepthStencil format with DepthStencil usage
|
||||
return false;
|
||||
if (!g_gs_device->Features().depth_feedback)
|
||||
{
|
||||
if (IsDepthStencil(usage) && IsFeedback(usage))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSTexture::Save(const std::string& fn)
|
||||
{
|
||||
// Depth textures need special treatment - we have a stencil component.
|
||||
@@ -174,6 +198,17 @@ u32 GSTexture::CalcUploadSize(Format format, u32 height, u32 pitch)
|
||||
return pitch * ((static_cast<u32>(height) + (block_size - 1)) / block_size);
|
||||
}
|
||||
|
||||
bool GSTexture::IsFeedbackFormat(Format format)
|
||||
{
|
||||
return format == Format::Color || format == Format::ColorClip ||
|
||||
format == Format::DepthColor || format == Format::DepthStencil;
|
||||
}
|
||||
|
||||
bool GSTexture::IsShaderWriteFormat(Format format)
|
||||
{
|
||||
return format == Format::Color || format == Format::DepthColor;
|
||||
}
|
||||
|
||||
void GSTexture::GenerateMipmapsIfNeeded()
|
||||
{
|
||||
if (!m_needs_mipmaps_generated || m_mipmap_levels <= 1 || IsCompressedFormat())
|
||||
|
||||
@@ -3,11 +3,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/EnumOps.h"
|
||||
#include "GS/GSVector.h"
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
enum class TextureUsage : u8
|
||||
{
|
||||
Texture = 0,
|
||||
DepthStencil = 1,
|
||||
RenderTarget = 2,
|
||||
Feedback = 4,
|
||||
ShaderWrite = 8,
|
||||
};
|
||||
|
||||
MARK_ENUM_AS_FLAGS(TextureUsage);
|
||||
|
||||
class GSTexture
|
||||
{
|
||||
public:
|
||||
@@ -17,14 +29,21 @@ public:
|
||||
int pitch;
|
||||
};
|
||||
|
||||
enum class Type : u8
|
||||
{
|
||||
Invalid = 0,
|
||||
RenderTarget = 1,
|
||||
DepthStencil,
|
||||
Texture, // Generic texture (usually is color textures loaded by the game)
|
||||
RWTexture, // UAV
|
||||
};
|
||||
using Usage = TextureUsage;
|
||||
|
||||
// Flags that shouldn't be used alone
|
||||
static constexpr Usage ShaderWrite = Usage::ShaderWrite;
|
||||
static constexpr Usage Feedback = Usage::Feedback;
|
||||
static constexpr Usage FeedbackOrShaderWrite = Usage::Feedback | Usage::ShaderWrite;
|
||||
|
||||
// All valid combinations
|
||||
static constexpr Usage Texture = Usage::Texture;
|
||||
static constexpr Usage RenderTarget = Usage::RenderTarget;
|
||||
static constexpr Usage DepthStencil = Usage::DepthStencil;
|
||||
static constexpr Usage FeedbackTarget = Usage::RenderTarget | Usage::Feedback | Usage::ShaderWrite;
|
||||
static constexpr Usage FeedbackDepth = Usage::DepthStencil | Usage::Feedback;
|
||||
static constexpr Usage ShaderWriteTarget = Usage::RenderTarget | Usage::Feedback | Usage::ShaderWrite;
|
||||
static constexpr Usage ShaderWriteTexture = Usage::Texture | Usage::ShaderWrite;
|
||||
|
||||
enum class Format : u8
|
||||
{
|
||||
@@ -34,7 +53,7 @@ public:
|
||||
ColorHDR, ///< High dynamic range (RGBA16F) color texture
|
||||
ColorClip, ///< Color texture with more bits for colclip (wrap) emulation, given that blending requires 9bpc (RGBA16Unorm)
|
||||
DepthStencil, ///< Depth stencil texture
|
||||
DepthColor, ///< For treating depth texture as RT
|
||||
DepthColor, ///< For treating depth texture as RT
|
||||
UNorm8, ///< A8UNorm texture for paletted textures and the OSD font
|
||||
UInt16, ///< UInt16 texture for reading back 16-bit depth
|
||||
UInt32, ///< UInt32 texture for reading back 24 and 32-bit depth
|
||||
@@ -46,6 +65,8 @@ public:
|
||||
Last = BC7,
|
||||
};
|
||||
|
||||
static bool ValidateUsageAndFormat(Usage usage, Format format);
|
||||
|
||||
enum class State : u8
|
||||
{
|
||||
Dirty,
|
||||
@@ -62,7 +83,7 @@ public:
|
||||
protected:
|
||||
GSVector2i m_size{};
|
||||
int m_mipmap_levels = 0;
|
||||
Type m_type = Type::Invalid;
|
||||
Usage m_usage = Usage::Texture;
|
||||
Format m_format = Format::Invalid;
|
||||
State m_state = State::Dirty;
|
||||
|
||||
@@ -107,7 +128,7 @@ public:
|
||||
__fi int GetMipmapLevels() const { return m_mipmap_levels; }
|
||||
__fi bool IsMipmap() const { return m_mipmap_levels > 1; }
|
||||
|
||||
__fi Type GetType() const { return m_type; }
|
||||
__fi Usage GetUsage() const { return m_usage; }
|
||||
__fi Format GetFormat() const { return m_format; }
|
||||
__fi bool IsCompressedFormat() const { return IsCompressedFormat(m_format); }
|
||||
|
||||
@@ -118,6 +139,8 @@ public:
|
||||
static u32 CalcUploadPitch(Format format, u32 width);
|
||||
static u32 CalcUploadRowLengthFromPitch(Format format, u32 pitch);
|
||||
static u32 CalcUploadSize(Format format, u32 height, u32 pitch);
|
||||
static bool IsFeedbackFormat(Format format);
|
||||
static bool IsShaderWriteFormat(Format format);
|
||||
|
||||
u32 GetCompressedBytesPerBlock() const;
|
||||
u32 GetCompressedBlockSize() const;
|
||||
@@ -125,29 +148,79 @@ public:
|
||||
u32 CalcUploadRowLengthFromPitch(u32 pitch) const;
|
||||
u32 CalcUploadSize(u32 height, u32 pitch) const;
|
||||
|
||||
static __fi bool IsRenderTarget(Usage usage)
|
||||
{
|
||||
return (usage & RenderTarget);
|
||||
}
|
||||
static __fi bool IsDepthStencil(Usage usage)
|
||||
{
|
||||
return (usage & DepthStencil);
|
||||
}
|
||||
static __fi bool IsRenderTargetOrDepthStencil(Usage usage)
|
||||
{
|
||||
return IsRenderTarget(usage) || IsDepthStencil(usage);
|
||||
}
|
||||
static __fi bool IsDepthColor(Usage usage, Format format)
|
||||
{
|
||||
return IsRenderTarget(usage) && (format == Format::DepthColor);
|
||||
}
|
||||
static __fi bool IsTexture(Usage usage)
|
||||
{
|
||||
return usage == Texture;
|
||||
}
|
||||
static __fi bool IsDepthLike(Usage usage, Format format)
|
||||
{
|
||||
return IsDepthStencil(usage) || IsDepthColor(usage, format);
|
||||
}
|
||||
static __fi bool IsFeedback(Usage usage)
|
||||
{
|
||||
return (usage & Feedback);
|
||||
}
|
||||
static __fi bool IsShaderWrite(Usage usage)
|
||||
{
|
||||
return (usage & ShaderWrite);
|
||||
}
|
||||
static __fi bool IsFeedbackOrShaderWrite(Usage usage)
|
||||
{
|
||||
return IsFeedback(usage) || IsShaderWrite(usage);
|
||||
}
|
||||
|
||||
|
||||
__fi bool IsRenderTargetOrDepthStencil() const
|
||||
{
|
||||
return (m_type >= Type::RenderTarget && m_type <= Type::DepthStencil);
|
||||
return IsRenderTargetOrDepthStencil(m_usage);
|
||||
}
|
||||
__fi bool IsRenderTarget() const
|
||||
{
|
||||
return (m_type == Type::RenderTarget);
|
||||
return IsRenderTarget(m_usage);
|
||||
}
|
||||
__fi bool IsDepthStencil() const
|
||||
{
|
||||
return (m_type == Type::DepthStencil);
|
||||
return IsDepthStencil(m_usage);
|
||||
}
|
||||
__fi bool IsDepthColor() const
|
||||
{
|
||||
return (m_type == Type::RenderTarget && m_format == Format::DepthColor);
|
||||
return IsDepthColor(m_usage, m_format);
|
||||
}
|
||||
__fi bool IsTexture() const
|
||||
{
|
||||
return (m_type == Type::Texture);
|
||||
return IsTexture(m_usage);
|
||||
}
|
||||
__fi bool IsDepthLike() const
|
||||
{
|
||||
return IsDepthStencil() || IsDepthColor();
|
||||
return IsDepthLike(m_usage, m_format);
|
||||
}
|
||||
__fi bool IsFeedback() const
|
||||
{
|
||||
return IsFeedback(m_usage);
|
||||
}
|
||||
__fi bool IsShaderWrite() const
|
||||
{
|
||||
return IsShaderWrite(m_usage);
|
||||
}
|
||||
__fi bool IsFeedbackOrShaderWrite() const
|
||||
{
|
||||
return IsFeedbackOrShaderWrite(m_usage);
|
||||
}
|
||||
|
||||
__fi State GetState() const { return m_state; }
|
||||
|
||||
@@ -594,7 +594,7 @@ bool GSDevice11::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
}
|
||||
|
||||
// 1x1 dummy texture.
|
||||
m_null_texture = CreateSurface(GSTexture::Type::RenderTarget, 1, 1, 1, GSTexture::Format::Color);
|
||||
m_null_texture = CreateSurface(GSTexture::ShaderWriteTarget, 1, 1, 1, GSTexture::Format::Color);
|
||||
if (!m_null_texture)
|
||||
return false;
|
||||
|
||||
@@ -1342,8 +1342,10 @@ void GSDevice11::InsertDebugMessage(DebugMessageCategory category, const char* f
|
||||
m_annotation->SetMarker(StringUtil::UTF8StringToWideString(str).c_str());
|
||||
}
|
||||
|
||||
GSTexture* GSDevice11::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format)
|
||||
GSTexture* GSDevice11::CreateSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format)
|
||||
{
|
||||
pxAssert(GSTexture::ValidateUsageAndFormat(usage, format));
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc = {};
|
||||
desc.Width = width;
|
||||
desc.Height = height;
|
||||
@@ -1354,26 +1356,27 @@ GSTexture* GSDevice11::CreateSurface(GSTexture::Type type, int width, int height
|
||||
desc.SampleDesc.Quality = 0;
|
||||
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
|
||||
switch (type)
|
||||
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||
|
||||
if (GSTexture::IsTexture(usage))
|
||||
{
|
||||
case GSTexture::Type::RenderTarget:
|
||||
desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
|
||||
if (m_uav_texture)
|
||||
desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS;
|
||||
break;
|
||||
case GSTexture::Type::DepthStencil:
|
||||
desc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
|
||||
break;
|
||||
case GSTexture::Type::Texture:
|
||||
desc.BindFlags = (levels > 1 && !GSTexture::IsCompressedFormat(format)) ? (D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE) : D3D11_BIND_SHADER_RESOURCE;
|
||||
desc.MiscFlags = (levels > 1 && !GSTexture::IsCompressedFormat(format)) ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0;
|
||||
break;
|
||||
case GSTexture::Type::RWTexture:
|
||||
pxAssert(m_uav_texture);
|
||||
desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
desc.BindFlags |= (levels > 1 && !GSTexture::IsCompressedFormat(format)) ? D3D11_BIND_RENDER_TARGET : 0;
|
||||
desc.MiscFlags |= (levels > 1 && !GSTexture::IsCompressedFormat(format)) ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0;
|
||||
}
|
||||
|
||||
if (GSTexture::IsRenderTarget(usage))
|
||||
{
|
||||
desc.BindFlags |= D3D11_BIND_RENDER_TARGET;
|
||||
}
|
||||
|
||||
if (GSTexture::IsDepthStencil(usage))
|
||||
{
|
||||
desc.BindFlags |= D3D11_BIND_DEPTH_STENCIL;
|
||||
}
|
||||
|
||||
if (GSTexture::IsShaderWrite(usage))
|
||||
{
|
||||
desc.BindFlags |= D3D11_BIND_UNORDERED_ACCESS;
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<ID3D11Texture2D> texture;
|
||||
@@ -1384,7 +1387,7 @@ GSTexture* GSDevice11::CreateSurface(GSTexture::Type type, int width, int height
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new GSTexture11(std::move(texture), desc, type, format);
|
||||
return new GSTexture11(std::move(texture), desc, usage, format);
|
||||
}
|
||||
|
||||
std::unique_ptr<GSDownloadTexture> GSDevice11::CreateDownloadTexture(u32 width, u32 height, GSTexture::Format format)
|
||||
@@ -2973,7 +2976,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
|
||||
{
|
||||
config.colclip_update_area = config.drawarea;
|
||||
|
||||
colclip_rt = CreateRenderTarget(rtsize.x, rtsize.y, m_rgba16_unorm_hw_blend ? GSTexture::Format::ColorClip : GSTexture::Format::ColorHDR, false);
|
||||
colclip_rt = CreateFeedbackTarget(rtsize.x, rtsize.y, m_rgba16_unorm_hw_blend ? GSTexture::Format::ColorClip : GSTexture::Format::ColorHDR, false);
|
||||
if (!colclip_rt)
|
||||
{
|
||||
Console.Warning("D3D11: Failed to allocate ColorClip render target, aborting draw.");
|
||||
|
||||
@@ -339,7 +339,7 @@ public:
|
||||
void PopDebugGroup() override;
|
||||
void InsertDebugMessage(DebugMessageCategory category, const char* fmt, ...) override;
|
||||
|
||||
GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
|
||||
GSTexture* CreateSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format) override;
|
||||
std::unique_ptr<GSDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GSTexture::Format format) override;
|
||||
|
||||
void CommitClear(GSTexture* t);
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
#include "fmt/format.h"
|
||||
|
||||
GSTexture11::GSTexture11(wil::com_ptr_nothrow<ID3D11Texture2D> texture, const D3D11_TEXTURE2D_DESC& desc,
|
||||
GSTexture::Type type, GSTexture::Format format)
|
||||
Usage usage, Format format)
|
||||
: m_texture(std::move(texture))
|
||||
, m_desc(desc)
|
||||
{
|
||||
m_size.x = static_cast<int>(desc.Width);
|
||||
m_size.y = static_cast<int>(desc.Height);
|
||||
m_type = type;
|
||||
m_usage = usage;
|
||||
m_format = format;
|
||||
m_mipmap_levels = static_cast<int>(desc.MipLevels);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ class GSTexture11 final : public GSTexture
|
||||
D3D11_TEXTURE2D_DESC m_desc;
|
||||
public:
|
||||
explicit GSTexture11(wil::com_ptr_nothrow<ID3D11Texture2D> texture, const D3D11_TEXTURE2D_DESC& desc,
|
||||
GSTexture::Type type, GSTexture::Format format);
|
||||
Usage usage, Format format);
|
||||
|
||||
static DXGI_FORMAT GetDXGIFormat(Format format);
|
||||
|
||||
|
||||
@@ -1093,7 +1093,7 @@ bool GSDevice12::CreateSwapChainRTV()
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<GSTexture12> tex = GSTexture12::Adopt(std::move(backbuffer), GSTexture::Type::RenderTarget,
|
||||
std::unique_ptr<GSTexture12> tex = GSTexture12::Adopt(std::move(backbuffer), GSTexture::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, GSTexture12::ResourceState::Present);
|
||||
@@ -1539,22 +1539,22 @@ void GSDevice12::LookupNativeFormat(GSTexture::Format format, DXGI_FORMAT* d3d_f
|
||||
*uav_format = mapping[4];
|
||||
}
|
||||
|
||||
GSTexture* GSDevice12::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format)
|
||||
GSTexture* GSDevice12::CreateSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format)
|
||||
{
|
||||
DXGI_FORMAT dxgi_format, srv_format, rtv_format, dsv_format, uav_format;
|
||||
LookupNativeFormat(format, &dxgi_format, &srv_format, &rtv_format, &dsv_format, &uav_format);
|
||||
|
||||
if (type != GSTexture::Type::RWTexture && type != GSTexture::Type::RenderTarget)
|
||||
if (!GSTexture::IsShaderWrite(usage))
|
||||
uav_format = DXGI_FORMAT_UNKNOWN; // We don't need the UAV descriptor.
|
||||
|
||||
std::unique_ptr<GSTexture12> tex(GSTexture12::Create(type, format, width, height, levels,
|
||||
std::unique_ptr<GSTexture12> tex(GSTexture12::Create(usage, format, width, 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, format, width, height, levels, dxgi_format, srv_format,
|
||||
tex = GSTexture12::Create(usage, format, width, height, levels, dxgi_format, srv_format,
|
||||
rtv_format, dsv_format, uav_format);
|
||||
}
|
||||
|
||||
@@ -1603,7 +1603,7 @@ void GSDevice12::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
|
||||
|
||||
dTex12->SetState(GSTexture::State::Dirty);
|
||||
|
||||
if (dTex12->GetType() != GSTexture::Type::DepthStencil)
|
||||
if (!dTex12->IsDepthStencil())
|
||||
{
|
||||
dTex12->TransitionToState(GSTexture12::ResourceState::RenderTarget);
|
||||
GetCommandList().list4->ClearRenderTargetView(
|
||||
@@ -1891,7 +1891,7 @@ void GSDevice12::BeginRenderPassForStretchRect(
|
||||
GetLoadOpForTexture(dTex);
|
||||
dTex->SetState(GSTexture::State::Dirty);
|
||||
|
||||
if (dTex->GetType() != GSTexture::Type::DepthStencil)
|
||||
if (!dTex->IsDepthStencil())
|
||||
{
|
||||
BeginRenderPass(load_op, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE,
|
||||
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||
@@ -1922,7 +1922,7 @@ void GSDevice12::DoStretchRect(GSTexture12* sTex, const GSVector4& sRect, GSText
|
||||
SetPipeline(pipeline);
|
||||
|
||||
const bool is_present = (!dTex);
|
||||
const bool depth = (dTex && dTex->GetType() == GSTexture::Type::DepthStencil);
|
||||
const bool depth = (dTex && dTex->IsDepthStencil());
|
||||
const GSVector2i size(is_present ? GSVector2i(GetWindowWidth(), GetWindowHeight()) : dTex->GetSize());
|
||||
const GSVector4i dtex_rc(0, 0, size.x, size.y);
|
||||
const GSVector4i dst_rc(GSVector4i(dRect).rintersect(dtex_rc));
|
||||
@@ -2606,7 +2606,7 @@ GSDevice12::ComPtr<ID3DBlob> GSDevice12::GetUtilityPixelShader(const std::string
|
||||
bool GSDevice12::CreateNullTexture()
|
||||
{
|
||||
m_null_texture =
|
||||
GSTexture12::Create(GSTexture::Type::RenderTarget, GSTexture::Format::Color, 1, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
GSTexture12::Create(GSTexture::ShaderWriteTarget, GSTexture::Format::Color, 1, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
if (!m_null_texture)
|
||||
return false;
|
||||
@@ -4373,7 +4373,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
|
||||
EndRenderPass();
|
||||
|
||||
colclip_rt = static_cast<GSTexture12*>(CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::ColorClip, false));
|
||||
colclip_rt = static_cast<GSTexture12*>(CreateFeedbackTarget(rtsize.x, rtsize.y, GSTexture::Format::ColorClip, false));
|
||||
if (!colclip_rt)
|
||||
{
|
||||
Console.Warning("D3D12: Failed to allocate ColorClip render target, aborting draw.");
|
||||
|
||||
@@ -431,8 +431,7 @@ private:
|
||||
void DestroySwapChainRTVs();
|
||||
void DestroySwapChain();
|
||||
|
||||
GSTexture* CreateSurface(
|
||||
GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
|
||||
GSTexture* CreateSurface(GSTexture::Usage usage, 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, u32 c, const Filter filter) final;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#include "D3D12MemAlloc.h"
|
||||
|
||||
GSTexture12::GSTexture12(Type type, Format format, int width, int height, int levels, DXGI_FORMAT dxgi_format,
|
||||
GSTexture12::GSTexture12(Usage usage, Format format, int width, int height, int levels, DXGI_FORMAT dxgi_format,
|
||||
wil::com_ptr_nothrow<ID3D12Resource> resource, wil::com_ptr_nothrow<ID3D12Resource> resource_fbl,
|
||||
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation, const D3D12DescriptorHandle& srv_descriptor,
|
||||
const D3D12DescriptorHandle& write_descriptor, const D3D12DescriptorHandle& ro_dsv_descriptor,
|
||||
@@ -33,7 +33,7 @@ GSTexture12::GSTexture12(Type type, Format format, int width, int height, int le
|
||||
, m_resource_state(resource_state)
|
||||
, m_simultaneous_tex(simultaneous_texture)
|
||||
{
|
||||
m_type = type;
|
||||
m_usage = usage;
|
||||
m_format = format;
|
||||
m_size.x = width;
|
||||
m_size.y = height;
|
||||
@@ -175,10 +175,12 @@ static D3D12_RESOURCE_STATES GetD3D12ResourceState(GSTexture12::ResourceState st
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int width, int height, int levels,
|
||||
std::unique_ptr<GSTexture12> GSTexture12::Create(Usage usage, 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)
|
||||
{
|
||||
pxAssert(ValidateUsageAndFormat(usage, format));
|
||||
|
||||
GSDevice12* const dev = GSDevice12::GetInstance();
|
||||
|
||||
GSDevice12::D3D12_RESOURCE_DESCU desc = {};
|
||||
@@ -198,67 +200,55 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
D3D12_CLEAR_VALUE optimized_clear_value = {};
|
||||
ResourceState state;
|
||||
|
||||
switch (type)
|
||||
if (IsTexture(usage))
|
||||
{
|
||||
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.
|
||||
desc.desc1.Flags = (levels > 1 && !IsCompressedFormat(format)) ? D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET :
|
||||
D3D12_RESOURCE_FLAG_NONE;
|
||||
state = ResourceState::CopyDst;
|
||||
pxAssert(uav_format == DXGI_FORMAT_UNKNOWN);
|
||||
}
|
||||
break;
|
||||
// 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.
|
||||
desc.desc1.Flags |= (levels > 1 && !IsCompressedFormat(format)) ? D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET :
|
||||
D3D12_RESOURCE_FLAG_NONE;
|
||||
state = ResourceState::CopyDst;
|
||||
}
|
||||
else
|
||||
{
|
||||
allocationDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED;
|
||||
}
|
||||
|
||||
case Type::RenderTarget:
|
||||
{
|
||||
// RT's tend to be larger, so we'll keep them committed for speed.
|
||||
pxAssert(levels == 1);
|
||||
allocationDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED;
|
||||
allocationDesc.ExtraHeapFlags = D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
|
||||
desc.desc1.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS;
|
||||
if (!dev->UseEnhancedBarriers())
|
||||
desc.desc1.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE;
|
||||
optimized_clear_value.Format = rtv_format;
|
||||
state = ResourceState::RenderTarget;
|
||||
if (uav_format != DXGI_FORMAT_UNKNOWN)
|
||||
{
|
||||
desc.desc1.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
if (IsRenderTarget(usage))
|
||||
{
|
||||
// RT's tend to be larger, so we'll keep them committed for speed.
|
||||
pxAssert(levels == 1);
|
||||
desc.desc1.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
||||
optimized_clear_value.Format = rtv_format;
|
||||
state = ResourceState::RenderTarget;
|
||||
}
|
||||
|
||||
case Type::DepthStencil:
|
||||
{
|
||||
pxAssert(levels == 1);
|
||||
allocationDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED;
|
||||
desc.desc1.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
||||
optimized_clear_value.Format = dsv_format;
|
||||
state = ResourceState::DepthWriteStencil;
|
||||
pxAssert(uav_format == DXGI_FORMAT_UNKNOWN);
|
||||
}
|
||||
break;
|
||||
if (IsFeedback(usage))
|
||||
{
|
||||
allocationDesc.ExtraHeapFlags |= D3D12_HEAP_FLAG_DENY_BUFFERS | D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
|
||||
desc.desc1.Flags |= D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS;
|
||||
if (!dev->UseEnhancedBarriers())
|
||||
desc.desc1.Layout = D3D12_TEXTURE_LAYOUT_64KB_UNDEFINED_SWIZZLE;
|
||||
}
|
||||
|
||||
case Type::RWTexture:
|
||||
{
|
||||
pxAssert(levels == 1);
|
||||
allocationDesc.Flags |= D3D12MA::ALLOCATION_FLAG_COMMITTED;
|
||||
state = ResourceState::PixelShaderResource;
|
||||
pxAssert(uav_format != DXGI_FORMAT_UNKNOWN);
|
||||
desc.desc1.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
}
|
||||
break;
|
||||
if (IsDepthStencil(usage))
|
||||
{
|
||||
pxAssert(levels == 1);
|
||||
desc.desc1.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
||||
optimized_clear_value.Format = dsv_format;
|
||||
state = ResourceState::DepthWriteStencil;
|
||||
}
|
||||
|
||||
default:
|
||||
return {};
|
||||
if (IsShaderWrite(usage))
|
||||
{
|
||||
desc.desc1.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
state = ResourceState::PixelShaderResource;
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<ID3D12Resource> resource;
|
||||
wil::com_ptr_nothrow<ID3D12Resource> resource_fbl;
|
||||
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation;
|
||||
|
||||
if (type == Type::RenderTarget && !dev->UseEnhancedBarriers())
|
||||
if (IsFeedback(usage) && !dev->UseEnhancedBarriers())
|
||||
{
|
||||
// We need to use an aliased resource for feedback with legacy barriers.
|
||||
const D3D12_RESOURCE_ALLOCATION_INFO allocInfo = dev->GetDevice()->GetResourceAllocationInfo(0, 1, &desc.desc);
|
||||
@@ -301,14 +291,14 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
if (dev->UseEnhancedBarriers())
|
||||
{
|
||||
hr = dev->GetAllocator()->CreateResource3(&allocationDesc, &desc.desc1,
|
||||
type == Type::RenderTarget ? D3D12_BARRIER_LAYOUT_COMMON : GetD3D12BarrierLayout(state),
|
||||
(type == Type::RenderTarget || type == Type::DepthStencil) ? &optimized_clear_value : nullptr,
|
||||
IsFeedback(usage) ? D3D12_BARRIER_LAYOUT_COMMON : GetD3D12BarrierLayout(state),
|
||||
IsRenderTargetOrDepthStencil(usage) ? &optimized_clear_value : nullptr,
|
||||
0, nullptr, allocation.put(), IID_PPV_ARGS(resource.put()));
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = dev->GetAllocator()->CreateResource(&allocationDesc, &desc.desc, GetD3D12ResourceState(state),
|
||||
(type == Type::RenderTarget || type == Type::DepthStencil) ? &optimized_clear_value : nullptr, allocation.put(),
|
||||
IsRenderTargetOrDepthStencil(usage) ? &optimized_clear_value : nullptr, allocation.put(),
|
||||
IID_PPV_ARGS(resource.put()));
|
||||
}
|
||||
if (FAILED(hr))
|
||||
@@ -329,51 +319,39 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
return {};
|
||||
}
|
||||
|
||||
switch (type)
|
||||
if (IsRenderTarget(usage))
|
||||
{
|
||||
case Type::RenderTarget:
|
||||
write_descriptor_type = WriteDescriptorType::RTV;
|
||||
if (!CreateRTVDescriptor(resource.get(), rtv_format, &write_descriptor))
|
||||
{
|
||||
write_descriptor_type = WriteDescriptorType::RTV;
|
||||
if (!CreateRTVDescriptor(resource.get(), rtv_format, &write_descriptor))
|
||||
{
|
||||
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
|
||||
return {};
|
||||
}
|
||||
if (uav_format != DXGI_FORMAT_UNKNOWN && !CreateUAVDescriptor(resource.get(), uav_format, &uav_descriptor))
|
||||
{
|
||||
dev->GetRTVHeapManager().Free(&write_descriptor);
|
||||
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
|
||||
return {};
|
||||
}
|
||||
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
|
||||
return {};
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::DepthStencil:
|
||||
if (IsDepthStencil(usage))
|
||||
{
|
||||
write_descriptor_type = WriteDescriptorType::DSV;
|
||||
if (!CreateDSVDescriptor(resource.get(), dsv_format, &write_descriptor, false))
|
||||
{
|
||||
write_descriptor_type = WriteDescriptorType::DSV;
|
||||
if (!CreateDSVDescriptor(resource.get(), dsv_format, &write_descriptor, false))
|
||||
{
|
||||
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
|
||||
return {};
|
||||
}
|
||||
if (!CreateDSVDescriptor(resource.get(), dsv_format, &ro_dsv_descriptor, true))
|
||||
{
|
||||
dev->GetDSVHeapManager().Free(&write_descriptor);
|
||||
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
|
||||
return {};
|
||||
}
|
||||
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
|
||||
return {};
|
||||
}
|
||||
break;
|
||||
if (!CreateDSVDescriptor(resource.get(), dsv_format, &ro_dsv_descriptor, true))
|
||||
{
|
||||
dev->GetDSVHeapManager().Free(&write_descriptor);
|
||||
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
case Type::RWTexture:
|
||||
{
|
||||
if (uav_format != DXGI_FORMAT_UNKNOWN && !CreateUAVDescriptor(resource.get(), uav_format, &uav_descriptor))
|
||||
{
|
||||
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
break;
|
||||
pxAssert(IsShaderWrite(usage) == (uav_format != DXGI_FORMAT_UNKNOWN));
|
||||
if (IsShaderWrite(usage) && !CreateUAVDescriptor(resource.get(), uav_format, &uav_descriptor))
|
||||
{
|
||||
if (IsRenderTarget(usage))
|
||||
dev->GetRTVHeapManager().Free(&write_descriptor);
|
||||
dev->GetDescriptorHeapManager().Free(&srv_descriptor);
|
||||
return {};
|
||||
}
|
||||
|
||||
// Feedback descriptor used with legacy barriers
|
||||
@@ -401,11 +379,11 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
|
||||
}
|
||||
|
||||
return std::unique_ptr<GSTexture12>(
|
||||
new GSTexture12(type, format, width, height, levels, dxgi_format, std::move(resource), std::move(resource_fbl), std::move(allocation),
|
||||
srv_descriptor, write_descriptor, ro_dsv_descriptor, uav_descriptor, fbl_descriptor, write_descriptor_type, type == Type::RenderTarget, state));
|
||||
new GSTexture12(usage, format, width, height, levels, dxgi_format, std::move(resource), std::move(resource_fbl), std::move(allocation),
|
||||
srv_descriptor, write_descriptor, ro_dsv_descriptor, uav_descriptor, fbl_descriptor, write_descriptor_type, IsFeedback(usage), state));
|
||||
}
|
||||
|
||||
std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resource> resource, Type type, Format format,
|
||||
std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resource> resource, Usage usage, 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, ResourceState resource_state)
|
||||
{
|
||||
@@ -419,7 +397,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
|
||||
return {};
|
||||
}
|
||||
|
||||
if (type == Type::RenderTarget)
|
||||
if (IsRenderTarget(usage))
|
||||
{
|
||||
write_descriptor_type = WriteDescriptorType::RTV;
|
||||
if (!CreateRTVDescriptor(resource.get(), rtv_format, &write_descriptor))
|
||||
@@ -428,7 +406,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
|
||||
return {};
|
||||
}
|
||||
}
|
||||
else if (type == Type::DepthStencil)
|
||||
else if (IsDepthStencil(usage))
|
||||
{
|
||||
write_descriptor_type = WriteDescriptorType::DSV;
|
||||
if (!CreateDSVDescriptor(resource.get(), dsv_format, &write_descriptor, false))
|
||||
@@ -444,7 +422,8 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
|
||||
}
|
||||
}
|
||||
|
||||
if (uav_format != DXGI_FORMAT_UNKNOWN)
|
||||
pxAssert(IsShaderWrite(usage) == (uav_format != DXGI_FORMAT_UNKNOWN));
|
||||
if (IsShaderWrite(usage))
|
||||
{
|
||||
if (!CreateUAVDescriptor(resource.get(), uav_format, &uav_descriptor))
|
||||
{
|
||||
@@ -466,7 +445,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Adopt(wil::com_ptr_nothrow<ID3D12Resou
|
||||
}
|
||||
}
|
||||
|
||||
return std::unique_ptr<GSTexture12>(new GSTexture12(type, format, static_cast<u32>(desc.Width), desc.Height,
|
||||
return std::unique_ptr<GSTexture12>(new GSTexture12(usage, format, static_cast<u32>(desc.Width), desc.Height,
|
||||
desc.MipLevels, desc.Format, std::move(resource), {}, {}, srv_descriptor, write_descriptor, {}, uav_descriptor,
|
||||
{}, write_descriptor_type, false, resource_state));
|
||||
}
|
||||
@@ -535,7 +514,7 @@ void* GSTexture12::GetNativeHandle() const
|
||||
const D3D12CommandList& GSTexture12::GetCommandBufferForUpdate()
|
||||
{
|
||||
GSDevice12* const dev = GSDevice12::GetInstance();
|
||||
if (m_type != Type::Texture || m_use_fence_counter == dev->GetCurrentFenceValue())
|
||||
if (!IsTexture() || m_use_fence_counter == dev->GetCurrentFenceValue())
|
||||
{
|
||||
// Console.WriteLn("Texture update within frame, can't use do beforehand");
|
||||
GSDevice12::GetInstance()->EndRenderPass();
|
||||
@@ -661,7 +640,7 @@ bool GSTexture12::Update(const GSVector4i& r, const void* data, int pitch, int l
|
||||
TransitionSubresourceToState(cmdlist, layer, m_resource_state, GSTexture12::ResourceState::CopyDst);
|
||||
|
||||
// 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)
|
||||
if (IsRenderTarget())
|
||||
{
|
||||
if (!r.eq(GSVector4i(0, 0, m_size.x, m_size.y)))
|
||||
CommitClear(cmdlist);
|
||||
@@ -681,7 +660,7 @@ bool GSTexture12::Update(const GSVector4i& r, const void* data, int pitch, int l
|
||||
if (m_resource_state != GSTexture12::ResourceState::CopyDst)
|
||||
TransitionSubresourceToState(cmdlist, layer, GSTexture12::ResourceState::CopyDst, m_resource_state);
|
||||
|
||||
if (m_type == Type::Texture)
|
||||
if (IsTexture())
|
||||
m_needs_mipmaps_generated |= (layer == 0);
|
||||
|
||||
return true;
|
||||
@@ -740,7 +719,7 @@ void GSTexture12::Unmap()
|
||||
TransitionSubresourceToState(cmdlist, m_map_level, m_resource_state, ResourceState::CopyDst);
|
||||
|
||||
// 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)
|
||||
if (IsRenderTarget())
|
||||
{
|
||||
if (!m_map_area.eq(GSVector4i(0, 0, m_size.x, m_size.y)))
|
||||
CommitClear(cmdlist);
|
||||
@@ -769,7 +748,7 @@ void GSTexture12::Unmap()
|
||||
if (m_resource_state != ResourceState::CopyDst)
|
||||
TransitionSubresourceToState(cmdlist, m_map_level, ResourceState::CopyDst, m_resource_state);
|
||||
|
||||
if (m_type == Type::Texture)
|
||||
if (IsTexture())
|
||||
m_needs_mipmaps_generated |= (m_map_level == 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,10 +39,10 @@ public:
|
||||
|
||||
~GSTexture12() override;
|
||||
|
||||
static std::unique_ptr<GSTexture12> Create(Type type, Format format, int width, int height, int levels,
|
||||
static std::unique_ptr<GSTexture12> Create(Usage usage, 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,
|
||||
static std::unique_ptr<GSTexture12> Adopt(wil::com_ptr_nothrow<ID3D12Resource> resource, Usage usage, 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, ResourceState resource_state);
|
||||
|
||||
@@ -90,7 +90,7 @@ private:
|
||||
DSV
|
||||
};
|
||||
|
||||
GSTexture12(Type type, Format format, int width, int height, int levels, DXGI_FORMAT dxgi_format,
|
||||
GSTexture12(Usage usage, Format format, int width, int height, int levels, DXGI_FORMAT dxgi_format,
|
||||
wil::com_ptr_nothrow<ID3D12Resource> resource, wil::com_ptr_nothrow<ID3D12Resource> resource_fbl,
|
||||
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation, const D3D12DescriptorHandle& srv_descriptor,
|
||||
const D3D12DescriptorHandle& write_descriptor, const D3D12DescriptorHandle& ro_dsv_descriptor,
|
||||
|
||||
@@ -7853,7 +7853,7 @@ void GSRendererHW::ConvertDepthFormatROV(GSTextureCache::Target* ds)
|
||||
if (m_conf.ps.HasDepthROV() && !ds_tex_old->IsDepthColor())
|
||||
{
|
||||
depth_to_color = true;
|
||||
ds_tex_new = g_gs_device->CreateDepthColor(ds_tex_old->GetSize(), false, true);
|
||||
ds_tex_new = g_gs_device->CreateShaderWriteTarget(ds_tex_old->GetSize(), GSTexture::Format::DepthColor, false, true);
|
||||
}
|
||||
else if (!m_conf.ps.HasDepthROV() && ds_tex_old->IsDepthColor())
|
||||
{
|
||||
@@ -10517,7 +10517,7 @@ bool GSRendererHW::OI_BlitFMV(GSTextureCache::Target* _rt, GSTextureCache::Sourc
|
||||
|
||||
if (temp_tex)
|
||||
{
|
||||
if (GSTexture* rt = g_gs_device->CreateRenderTarget(tw, new_height, GSTexture::Format::Color))
|
||||
if (GSTexture* rt = g_gs_device->CreateFeedbackTarget(tw, new_height, GSTexture::Format::Color))
|
||||
{
|
||||
// sRect is the top of texture
|
||||
// Need to half pixel offset the dest tex coordinates as draw pixels are top left instead of centre for texel reads.
|
||||
|
||||
@@ -6067,10 +6067,9 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
|
||||
{
|
||||
// If we have a source larger than the target, we need to clear it, otherwise we'll read junk
|
||||
const bool outside_target = ((x + w) > dst->m_texture->GetWidth() || (y + h) > dst->m_texture->GetHeight());
|
||||
GSTexture::Usage usage = outside_target ? dst->m_texture->GetUsage() : GSTexture::Texture;
|
||||
GSTexture* sTex = dst->m_texture;
|
||||
GSTexture* dTex = outside_target ?
|
||||
g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::Color, true, PreferReusedLabelledTexture()) :
|
||||
g_gs_device->CreateTexture(w, h, tlevels, GSTexture::Format::Color, PreferReusedLabelledTexture());
|
||||
GSTexture* dTex = g_gs_device->FetchSurface(usage, w, h, outside_target ? 1 : tlevels, sTex->GetFormat(), true, !PreferReusedLabelledTexture());
|
||||
if (!dTex) [[unlikely]]
|
||||
{
|
||||
Console.Error("Failed to allocate %dx%d texture for offset source", w, h);
|
||||
@@ -6378,10 +6377,9 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
|
||||
{
|
||||
// Don't be fooled by the name. 'dst' is the old target (hence the input)
|
||||
// 'src' is the new texture cache entry (hence the output)
|
||||
GSTexture::Usage usage = use_texture ? GSTexture::Texture : dst->m_texture->GetUsage();
|
||||
GSTexture* sTex = dst->m_texture;
|
||||
GSTexture* dTex = use_texture ?
|
||||
g_gs_device->CreateTexture(new_size, 1, GSTexture::Format::Color, PreferReusedLabelledTexture()) :
|
||||
g_gs_device->CreateRenderTarget(new_size, GSTexture::Format::Color, source_rect_empty || destX != 0 || destY != 0, PreferReusedLabelledTexture());
|
||||
GSTexture* dTex = g_gs_device->FetchSurface(usage, new_size, 1, sTex->GetFormat(), source_rect_empty || destX != 0 || destY != 0, !PreferReusedLabelledTexture());
|
||||
if (!dTex) [[unlikely]]
|
||||
{
|
||||
Console.Error("Failed to allocate %dx%d texture for target copy to source", new_size.x, new_size.y);
|
||||
@@ -6426,9 +6424,8 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
|
||||
const u32 destination_tbw = (dst->m_TEX0.TBP0 == TEX0.TBP0) ? (std::max<u32>(TEX0.TBW, 1u) * 64) : std::max<u32>(dst->m_TEX0.TBW, 1u) * 128;
|
||||
if (!GSConfig.UserHacks_NativePaletteDraw && dst->GetScale() > 1.0f)
|
||||
{
|
||||
GSTexture* tmpTex = use_texture ?
|
||||
g_gs_device->CreateTexture(dst->m_unscaled_size, 1, GSTexture::Format::Color, PreferReusedLabelledTexture()) :
|
||||
g_gs_device->CreateRenderTarget(dst->m_unscaled_size, GSTexture::Format::Color, false, PreferReusedLabelledTexture());
|
||||
GSTexture::Usage usage = use_texture ? GSTexture::Texture : dst->m_texture->GetUsage();
|
||||
GSTexture* tmpTex = g_gs_device->FetchSurface(usage, dst->m_unscaled_size, 1, dst->m_texture->GetFormat(), false, !PreferReusedLabelledTexture());
|
||||
|
||||
const GSVector4 dRect = GSVector4(GSVector4i::loadh(dst->m_unscaled_size));
|
||||
|
||||
@@ -6909,7 +6906,7 @@ GSTextureCache::Source* GSTextureCache::CreateMergedSource(GIFRegTEX0 TEX0, GIFR
|
||||
lmtex->Unmap();
|
||||
|
||||
// Allocate our render target for drawing everything to.
|
||||
GSTexture* dtex = g_gs_device->CreateRenderTarget(scaled_width, scaled_height, GSTexture::Format::Color, true);
|
||||
GSTexture* dtex = g_gs_device->CreateFeedbackTarget(scaled_width, scaled_height, GSTexture::Format::Color, true);
|
||||
if (!dtex) [[unlikely]]
|
||||
{
|
||||
Console.Error("Failed to allocate %dx%d merged dest texture", scaled_width, scaled_height);
|
||||
@@ -7167,9 +7164,10 @@ GSTextureCache::Target* GSTextureCache::Target::Create(GIFRegTEX0 TEX0, int w, i
|
||||
|
||||
const int scaled_w = static_cast<int>(std::ceil(static_cast<float>(w) * scale));
|
||||
const int scaled_h = static_cast<int>(std::ceil(static_cast<float>(h) * scale));
|
||||
GSTexture* texture = (type == RenderTarget) ?
|
||||
g_gs_device->CreateRenderTarget(scaled_w, scaled_h, GSTexture::Format::Color, clear, PreferReusedLabelledTexture()) :
|
||||
g_gs_device->CreateDepthStencil(scaled_w, scaled_h, clear, PreferReusedLabelledTexture());
|
||||
GSTexture::Usage usage = type == RenderTarget ? GSTexture::FeedbackTarget :
|
||||
(g_gs_device->Features().depth_feedback ? GSTexture::FeedbackDepth : GSTexture::DepthStencil);
|
||||
GSTexture::Format format = type == RenderTarget ? GSTexture::Format::Color : GSTexture::Format::DepthStencil;
|
||||
GSTexture* texture = g_gs_device->FetchSurface(usage, scaled_w, scaled_h, 1, format, clear, !PreferReusedLabelledTexture());
|
||||
if (!texture)
|
||||
return nullptr;
|
||||
|
||||
|
||||
@@ -377,7 +377,7 @@ public:
|
||||
/// Call at the end of each frame
|
||||
void FrameCompleted();
|
||||
|
||||
GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
|
||||
GSTexture* CreateSurface(GSTexture::Usage usage, 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, u32 c, const Filter filter) override;
|
||||
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, Filter filter, const InterlaceConstantBuffer& cb) override;
|
||||
|
||||
@@ -545,8 +545,10 @@ static constexpr MTLPixelFormat ConvertPixelFormat(GSTexture::Format format)
|
||||
}
|
||||
}
|
||||
|
||||
GSTexture* GSDeviceMTL::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format)
|
||||
GSTexture* GSDeviceMTL::CreateSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format)
|
||||
{ @autoreleasepool {
|
||||
pxAssert(GSTexture::ValidateUsageAndFormat(usage, format));
|
||||
|
||||
MTLPixelFormat fmt = ConvertPixelFormat(format);
|
||||
pxAssertRel(format != GSTexture::Format::Invalid, "Can't create surface of this format!");
|
||||
|
||||
@@ -560,38 +562,38 @@ GSTexture* GSDeviceMTL::CreateSurface(GSTexture::Type type, int width, int heigh
|
||||
[desc setMipmapLevelCount:levels];
|
||||
|
||||
[desc setStorageMode:MTLStorageModePrivate];
|
||||
switch (type)
|
||||
|
||||
MTLTextureUsage mtl_usage = MTLTextureUsageShaderRead;
|
||||
|
||||
if (GSTexture::IsRenderTarget(usage))
|
||||
{
|
||||
case GSTexture::Type::Texture:
|
||||
[desc setUsage:MTLTextureUsageShaderRead];
|
||||
break;
|
||||
case GSTexture::Type::RenderTarget:
|
||||
if (m_dev.features.slow_color_compression)
|
||||
[desc setUsage:MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget | MTLTextureUsagePixelFormatView]; // Force color compression off by including PixelFormatView
|
||||
else
|
||||
[desc setUsage:MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget];
|
||||
break;
|
||||
case GSTexture::Type::RWTexture:
|
||||
[desc setUsage:MTLTextureUsageShaderRead | MTLTextureUsageShaderWrite];
|
||||
break;
|
||||
default:
|
||||
[desc setUsage:MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget];
|
||||
mtl_usage |= MTLTextureUsageRenderTarget;
|
||||
}
|
||||
|
||||
if ((usage & GSTexture::FeedbackTarget) == GSTexture::FeedbackTarget)
|
||||
{
|
||||
if (m_dev.features.slow_color_compression)
|
||||
mtl_usage |= MTLTextureUsagePixelFormatView; // Force color compression off by including PixelFormatView
|
||||
}
|
||||
|
||||
if (GSTexture::IsShaderWrite(usage))
|
||||
{
|
||||
mtl_usage |= MTLTextureUsageShaderWrite;
|
||||
}
|
||||
|
||||
[desc setUsage:mtl_usage];
|
||||
|
||||
MRCOwned<id<MTLTexture>> tex = MRCTransfer([m_dev.dev newTextureWithDescriptor:desc]);
|
||||
if (tex)
|
||||
{
|
||||
GSTextureMTL* t = new GSTextureMTL(this, tex, type, format);
|
||||
switch (type)
|
||||
GSTextureMTL* t = new GSTextureMTL(this, tex, usage, format);
|
||||
if (GSTexture::IsRenderTarget(usage))
|
||||
{
|
||||
case GSTexture::Type::RenderTarget:
|
||||
ClearRenderTarget(t, 0);
|
||||
break;
|
||||
case GSTexture::Type::DepthStencil:
|
||||
ClearDepth(t, 0.0f);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
ClearRenderTarget(t, 0);
|
||||
}
|
||||
else if (GSTexture::IsDepthStencil(usage))
|
||||
{
|
||||
ClearDepth(t, 0.0f);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
@@ -2290,7 +2292,7 @@ void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
|
||||
config.colclip_update_area = config.drawarea;
|
||||
|
||||
GSVector2i size = config.rt->GetSize();
|
||||
rt = colclip_rt = CreateRenderTarget(size.x, size.y, GSTexture::Format::ColorClip, false);
|
||||
rt = colclip_rt = CreateFeedbackTarget(size.x, size.y, GSTexture::Format::ColorClip, false);
|
||||
|
||||
g_gs_device->SetColorClipTexture(colclip_rt);
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ class GSTextureMTL : public GSTexture
|
||||
public:
|
||||
u64 m_last_read = 0; ///< Last time this texture was read by a draw
|
||||
u64 m_last_write = 0; ///< Last time this texture was written by a draw
|
||||
GSTextureMTL(GSDeviceMTL* dev, MRCOwned<id<MTLTexture>> texture, Type type, Format format);
|
||||
GSTextureMTL(GSDeviceMTL* dev, MRCOwned<id<MTLTexture>> texture, Usage usage, Format format);
|
||||
~GSTextureMTL();
|
||||
|
||||
/// For making fake backbuffers
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
// Uploads/downloads need 32-byte alignment for AVX2.
|
||||
static constexpr u32 PITCH_ALIGNMENT = 32;
|
||||
|
||||
GSTextureMTL::GSTextureMTL(GSDeviceMTL* dev, MRCOwned<id<MTLTexture>> texture, Type type, Format format)
|
||||
GSTextureMTL::GSTextureMTL(GSDeviceMTL* dev, MRCOwned<id<MTLTexture>> texture, Usage usage, Format format)
|
||||
: m_dev(dev)
|
||||
, m_texture(std::move(texture))
|
||||
{
|
||||
m_type = type;
|
||||
m_usage = usage;
|
||||
m_format = format;
|
||||
m_size.x = [m_texture width];
|
||||
m_size.y = [m_texture height];
|
||||
@@ -142,6 +142,8 @@ void GSTextureMTL::SetDebugName(std::string_view name)
|
||||
encoding:NSUTF8StringEncoding];
|
||||
[m_texture setLabel:label];
|
||||
}
|
||||
|
||||
m_debug_name = std::move(name);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -213,10 +213,11 @@ std::vector<GSAdapterInfo> GSDeviceOGL::GetAdapterInfo()
|
||||
return ret;
|
||||
}
|
||||
|
||||
GSTexture* GSDeviceOGL::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format)
|
||||
GSTexture* GSDeviceOGL::CreateSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format)
|
||||
{
|
||||
GL_PUSH("Create surface");
|
||||
return new GSTextureOGL(type, width, height, levels, format);
|
||||
pxAssert(GLAD_GL_ARB_shader_image_load_store || !GSTexture::IsShaderWrite(usage));
|
||||
return new GSTextureOGL(usage, width, height, levels, format);
|
||||
}
|
||||
|
||||
RenderAPI GSDeviceOGL::GetRenderAPI() const
|
||||
@@ -1259,14 +1260,14 @@ void GSDeviceOGL::CommitClear(GSTexture* t, bool use_write_fbo)
|
||||
{
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_write);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||
(t->GetType() == GSTexture::Type::RenderTarget) ? static_cast<GSTextureOGL*>(t)->GetID() : 0, 0);
|
||||
t->IsRenderTarget() ? static_cast<GSTextureOGL*>(t)->GetID() : 0, 0);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, m_features.framebuffer_fetch ? GL_DEPTH_ATTACHMENT : GL_DEPTH_STENCIL_ATTACHMENT,
|
||||
GL_TEXTURE_2D, (t->GetType() == GSTexture::Type::DepthStencil) ? static_cast<GSTextureOGL*>(t)->GetID() : 0, 0);
|
||||
GL_TEXTURE_2D, t->IsDepthStencil() ? static_cast<GSTextureOGL*>(t)->GetID() : 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
OMSetFBO(m_fbo);
|
||||
if (T->GetType() == GSTexture::Type::DepthStencil)
|
||||
if (T->IsDepthStencil())
|
||||
{
|
||||
if (GLState::rt && GLState::rt->GetSize() != T->GetSize())
|
||||
OMAttachRt(nullptr);
|
||||
@@ -1284,7 +1285,7 @@ void GSDeviceOGL::CommitClear(GSTexture* t, bool use_write_fbo)
|
||||
{
|
||||
if (GLAD_GL_VERSION_4_3)
|
||||
{
|
||||
if (T->GetType() == GSTexture::Type::DepthStencil)
|
||||
if (T->IsDepthStencil())
|
||||
{
|
||||
const GLenum attachments[] = {GL_DEPTH_STENCIL_ATTACHMENT};
|
||||
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, std::size(attachments), attachments);
|
||||
@@ -1344,7 +1345,7 @@ void GSDeviceOGL::CommitClear(GSTexture* t, bool use_write_fbo)
|
||||
if (use_write_fbo)
|
||||
{
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
|
||||
(t->GetType() == GSTexture::Type::RenderTarget) ?
|
||||
t->IsRenderTarget() ?
|
||||
GL_COLOR_ATTACHMENT0 :
|
||||
(m_features.framebuffer_fetch ? GL_DEPTH_ATTACHMENT : GL_DEPTH_STENCIL_ATTACHMENT),
|
||||
GL_TEXTURE_2D, 0, 0);
|
||||
@@ -2792,7 +2793,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||
{
|
||||
config.colclip_update_area = config.drawarea;
|
||||
|
||||
colclip_rt = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::ColorClip, false);
|
||||
colclip_rt = CreateFeedbackTarget(rtsize.x, rtsize.y, GSTexture::Format::ColorClip, false);
|
||||
|
||||
if (!colclip_rt)
|
||||
{
|
||||
|
||||
@@ -270,7 +270,7 @@ private:
|
||||
void PopTimestampQuery();
|
||||
void KickTimestampQuery();
|
||||
|
||||
GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
|
||||
GSTexture* CreateSurface(GSTexture::Usage usage, 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, u32 c, const Filter filter) override;
|
||||
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, Filter filter, const InterlaceConstantBuffer& cb) override;
|
||||
|
||||
@@ -21,13 +21,13 @@ static constexpr u32 TEXTURE_UPLOAD_ALIGNMENT = 64;
|
||||
// We need 32 here for AVX2, so 64 is also fine.
|
||||
static constexpr u32 TEXTURE_UPLOAD_PITCH_ALIGNMENT = 64;
|
||||
|
||||
GSTextureOGL::GSTextureOGL(Type type, int width, int height, int levels, Format format)
|
||||
GSTextureOGL::GSTextureOGL(Usage usage, int width, int height, int levels, Format format)
|
||||
{
|
||||
// OpenGL didn't like dimensions of size 0
|
||||
m_size.x = std::max(1, width);
|
||||
m_size.y = std::max(1, height);
|
||||
m_usage = usage;
|
||||
m_format = format;
|
||||
m_type = type;
|
||||
m_texture_id = 0;
|
||||
m_mipmap_levels = 1;
|
||||
|
||||
@@ -144,7 +144,7 @@ GSTextureOGL::GSTextureOGL(Type type, int width, int height, int levels, Format
|
||||
}
|
||||
|
||||
// Only 32 bits input texture will be supported for mipmap
|
||||
if (m_type == Type::Texture)
|
||||
if (IsTexture())
|
||||
m_mipmap_levels = levels;
|
||||
|
||||
// Create a gl object (texture isn't allocated here)
|
||||
@@ -181,7 +181,7 @@ void* GSTextureOGL::GetNativeHandle() const
|
||||
|
||||
bool GSTextureOGL::Update(const GSVector4i& r, const void* data, int pitch, int layer)
|
||||
{
|
||||
pxAssert(m_type != Type::DepthStencil);
|
||||
pxAssert(!IsDepthStencil());
|
||||
|
||||
if (layer >= m_mipmap_levels)
|
||||
return true;
|
||||
@@ -263,7 +263,7 @@ bool GSTextureOGL::Map(GSMap& m, const GSVector4i* _r, int layer)
|
||||
const u32 pitch = Common::AlignUpPow2(r.width() << m_int_shift, TEXTURE_UPLOAD_PITCH_ALIGNMENT);
|
||||
m.pitch = pitch;
|
||||
|
||||
if (m_type == Type::Texture || m_type == Type::RenderTarget)
|
||||
if (IsTexture() || IsRenderTarget())
|
||||
{
|
||||
const u32 upload_size = CalcUploadSize(r.height(), pitch);
|
||||
GLStreamBuffer* sb = GSDeviceOGL::GetInstance()->GetTextureUploadBuffer();
|
||||
@@ -292,7 +292,7 @@ bool GSTextureOGL::Map(GSMap& m, const GSVector4i* _r, int layer)
|
||||
|
||||
void GSTextureOGL::Unmap()
|
||||
{
|
||||
if (m_type == Type::Texture || m_type == Type::RenderTarget)
|
||||
if (IsTexture() || IsRenderTarget())
|
||||
{
|
||||
GSDeviceOGL::GetInstance()->CommitClear(this, true);
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ private:
|
||||
u32 m_int_shift = 0;
|
||||
|
||||
public:
|
||||
explicit GSTextureOGL(Type type, int width, int height, int levels, Format format);
|
||||
explicit GSTextureOGL(Usage usage, int width, int height, int levels, Format format);
|
||||
~GSTextureOGL() override;
|
||||
|
||||
__fi GLenum GetIntFormat() const { return m_int_format; }
|
||||
|
||||
@@ -2853,15 +2853,15 @@ VkFormat GSDeviceVK::LookupNativeFormat(GSTexture::Format format) const
|
||||
VK_FORMAT_D32_SFLOAT;
|
||||
}
|
||||
|
||||
GSTexture* GSDeviceVK::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format)
|
||||
GSTexture* GSDeviceVK::CreateSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format)
|
||||
{
|
||||
std::unique_ptr<GSTexture> tex = GSTextureVK::Create(type, format, width, height, levels);
|
||||
std::unique_ptr<GSTexture> tex = GSTextureVK::Create(usage, format, width, 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, format, width, height, levels);
|
||||
tex = GSTextureVK::Create(usage, format, width, height, levels);
|
||||
}
|
||||
|
||||
return tex.release();
|
||||
@@ -2895,7 +2895,7 @@ void GSDeviceVK::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
|
||||
return;
|
||||
|
||||
// Do an attachment clear.
|
||||
const bool depth = (dTexVK->GetType() == GSTexture::Type::DepthStencil);
|
||||
const bool depth = dTexVK->IsDepthStencil();
|
||||
OMSetRenderTargets(depth ? nullptr : dTexVK, depth ? dTexVK : nullptr, dst_rect);
|
||||
BeginRenderPassForStretchRect(
|
||||
dTexVK, dst_rect, GSVector4i(destX, destY, destX + r.width(), destY + r.height()));
|
||||
@@ -3106,14 +3106,13 @@ void GSDeviceVK::BeginRenderPassForStretchRect(
|
||||
(allow_discard && dst_rc.eq(dtex_rc)) ? VK_ATTACHMENT_LOAD_OP_DONT_CARE : GetLoadOpForTexture(dTex);
|
||||
dTex->SetState(GSTexture::State::Dirty);
|
||||
|
||||
if (dTex->GetType() == GSTexture::Type::DepthStencil)
|
||||
if (dTex->IsDepthStencil())
|
||||
{
|
||||
if (load_op == VK_ATTACHMENT_LOAD_OP_CLEAR)
|
||||
BeginClearRenderPass(m_utility_depth_render_pass_clear, dtex_rc, dTex->GetClearDepth(), 0);
|
||||
else
|
||||
BeginRenderPass((load_op == VK_ATTACHMENT_LOAD_OP_DONT_CARE) ? m_utility_depth_render_pass_discard :
|
||||
m_utility_depth_render_pass_load,
|
||||
dtex_rc);
|
||||
m_utility_depth_render_pass_load, dtex_rc);
|
||||
}
|
||||
else if (dTex->GetFormat() == GSTexture::Format::Color)
|
||||
{
|
||||
@@ -3121,8 +3120,7 @@ void GSDeviceVK::BeginRenderPassForStretchRect(
|
||||
BeginClearRenderPass(m_utility_color_render_pass_clear, dtex_rc, dTex->GetClearColor());
|
||||
else
|
||||
BeginRenderPass((load_op == VK_ATTACHMENT_LOAD_OP_DONT_CARE) ? m_utility_color_render_pass_discard :
|
||||
m_utility_color_render_pass_load,
|
||||
dtex_rc);
|
||||
m_utility_color_render_pass_load, dtex_rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3154,7 +3152,7 @@ void GSDeviceVK::DoStretchRect(GSTextureVK* sTex, const GSVector4& sRect, GSText
|
||||
SetPipeline(pipeline);
|
||||
|
||||
const bool is_present = (!dTex);
|
||||
const bool depth = (dTex && dTex->GetType() == GSTexture::Type::DepthStencil);
|
||||
const bool depth = (dTex && dTex->IsDepthStencil());
|
||||
const GSVector2i size(is_present ? GSVector2i(GetWindowWidth(), GetWindowHeight()) : dTex->GetSize());
|
||||
const GSVector4i dtex_rc(0, 0, size.x, size.y);
|
||||
const GSVector4i dst_rc(GSVector4i(dRect).rintersect(dtex_rc));
|
||||
@@ -3218,10 +3216,9 @@ void GSDeviceVK::BlitRect(GSTexture* sTex, const GSVector4i& sRect, u32 sLevel,
|
||||
if (m_tfx_textures[0] == sTexVK)
|
||||
PSSetShaderResource(0, nullptr, false);
|
||||
|
||||
pxAssert(
|
||||
(sTexVK->GetType() == GSTexture::Type::DepthStencil) == (dTexVK->GetType() == GSTexture::Type::DepthStencil));
|
||||
pxAssert(sTexVK->IsDepthStencil() == dTexVK->IsDepthStencil());
|
||||
const VkImageAspectFlags aspect =
|
||||
(sTexVK->GetType() == GSTexture::Type::DepthStencil) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
sTexVK->IsDepthStencil() ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
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}}};
|
||||
|
||||
@@ -3825,7 +3822,7 @@ VkShaderModule GSDeviceVK::GetUtilityFragmentShader(const std::string& source, c
|
||||
|
||||
bool GSDeviceVK::CreateNullTexture()
|
||||
{
|
||||
m_null_texture = GSTextureVK::Create(GSTexture::Type::RenderTarget, GSTexture::Format::Color, 1, 1, 1);
|
||||
m_null_texture = GSTextureVK::Create(GSTexture::ShaderWriteTarget, GSTexture::Format::Color, 1, 1, 1);
|
||||
if (!m_null_texture)
|
||||
return false;
|
||||
|
||||
@@ -6030,7 +6027,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
||||
{
|
||||
config.colclip_update_area = config.drawarea;
|
||||
EndRenderPass();
|
||||
colclip_rt = static_cast<GSTextureVK*>(CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::ColorClip, false));
|
||||
colclip_rt = static_cast<GSTextureVK*>(CreateFeedbackTarget(rtsize.x, rtsize.y, GSTexture::Format::ColorClip, false));
|
||||
if (!colclip_rt)
|
||||
{
|
||||
Console.Warning("VK: Failed to allocate ColorClip render target, aborting draw.");
|
||||
|
||||
@@ -468,8 +468,7 @@ private:
|
||||
|
||||
std::string m_tfx_source;
|
||||
|
||||
GSTexture* CreateSurface(
|
||||
GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
|
||||
GSTexture* CreateSurface(GSTexture::Usage usage, 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, u32 c, const Filter filter) final;
|
||||
|
||||
@@ -61,7 +61,7 @@ static VkAccessFlagBits GetFeedbackLoopInputAccessBits()
|
||||
VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
|
||||
}
|
||||
|
||||
GSTextureVK::GSTextureVK(Type type, Format format, int width, int height, int levels, VkImage image,
|
||||
GSTextureVK::GSTextureVK(Usage usage, Format format, int width, int height, int levels, VkImage image,
|
||||
VmaAllocation allocation, VkImageView view, VkFormat vk_format)
|
||||
: GSTexture()
|
||||
, m_image(image)
|
||||
@@ -69,7 +69,7 @@ GSTextureVK::GSTextureVK(Type type, Format format, int width, int height, int le
|
||||
, m_view(view)
|
||||
, m_vk_format(vk_format)
|
||||
{
|
||||
m_type = type;
|
||||
m_usage = usage;
|
||||
m_format = format;
|
||||
m_size.x = width;
|
||||
m_size.y = height;
|
||||
@@ -81,8 +81,10 @@ GSTextureVK::~GSTextureVK()
|
||||
Destroy(true);
|
||||
}
|
||||
|
||||
std::unique_ptr<GSTextureVK> GSTextureVK::Create(Type type, Format format, int width, int height, int levels)
|
||||
std::unique_ptr<GSTextureVK> GSTextureVK::Create(Usage usage, Format format, int width, int height, int levels)
|
||||
{
|
||||
pxAssert(ValidateUsageAndFormat(usage, format));
|
||||
|
||||
const VkFormat vk_format = GSDeviceVK::GetInstance()->LookupNativeFormat(format);
|
||||
|
||||
VkImageCreateInfo ici = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, nullptr, 0, VK_IMAGE_TYPE_2D, vk_format,
|
||||
@@ -98,59 +100,42 @@ std::unique_ptr<GSTextureVK> GSTextureVK::Create(Type type, Format format, int w
|
||||
VK_IMAGE_VIEW_TYPE_2D, vk_format, s_identity_swizzle,
|
||||
{VK_IMAGE_ASPECT_COLOR_BIT, 0, static_cast<u32>(levels), 0, 1}};
|
||||
|
||||
switch (type)
|
||||
ici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
|
||||
if (format == Format::UNorm8)
|
||||
{
|
||||
case Type::Texture:
|
||||
{
|
||||
ici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
// 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;
|
||||
}
|
||||
|
||||
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;
|
||||
if (IsRenderTarget(usage))
|
||||
{
|
||||
pxAssert(levels == 1);
|
||||
ici.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
}
|
||||
|
||||
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_STORAGE_BIT |
|
||||
(GSDeviceVK::GetInstance()->UseFeedbackLoopLayout() ? VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT
|
||||
: VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
|
||||
}
|
||||
break;
|
||||
if (IsFeedback(usage))
|
||||
{
|
||||
ici.usage |= GSDeviceVK::GetInstance()->UseFeedbackLoopLayout() ?
|
||||
VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT :
|
||||
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
|
||||
}
|
||||
|
||||
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 |
|
||||
(GSDeviceVK::GetInstance()->UseFeedbackLoopLayout() ? VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT
|
||||
: VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
|
||||
vci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
}
|
||||
break;
|
||||
if (IsDepthStencil(usage))
|
||||
{
|
||||
ici.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
vci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
}
|
||||
|
||||
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 {};
|
||||
if (IsShaderWrite(usage))
|
||||
{
|
||||
ici.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
|
||||
}
|
||||
|
||||
// Use dedicated allocations for typical RT size
|
||||
if ((type == Type::RenderTarget || type == Type::DepthStencil) && width >= 512 && height >= 448)
|
||||
if (IsRenderTargetOrDepthStencil(usage) && width >= 512 && height >= 448)
|
||||
aci.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
|
||||
|
||||
VkImage image = VK_NULL_HANDLE;
|
||||
@@ -184,17 +169,18 @@ std::unique_ptr<GSTextureVK> GSTextureVK::Create(Type type, Format format, int w
|
||||
}
|
||||
|
||||
return std::unique_ptr<GSTextureVK>(
|
||||
new GSTextureVK(type, format, width, height, levels, image, allocation, view, vk_format));
|
||||
new GSTextureVK(usage, 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)
|
||||
VkImage image, Usage usage, 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),
|
||||
{IsDepthStencil(usage) ?
|
||||
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.
|
||||
@@ -207,14 +193,14 @@ std::unique_ptr<GSTextureVK> GSTextureVK::Adopt(
|
||||
}
|
||||
|
||||
return std::unique_ptr<GSTextureVK>(
|
||||
new GSTextureVK(type, format, width, height, levels, image, VK_NULL_HANDLE, view, vk_format));
|
||||
new GSTextureVK(usage, format, width, height, levels, image, VK_NULL_HANDLE, view, vk_format));
|
||||
}
|
||||
|
||||
void GSTextureVK::Destroy(bool defer)
|
||||
{
|
||||
GSDeviceVK::GetInstance()->UnbindTexture(this);
|
||||
|
||||
if (m_type == Type::RenderTarget || m_type == Type::DepthStencil)
|
||||
if (IsRenderTargetOrDepthStencil())
|
||||
{
|
||||
for (const auto& [other_tex, fb, feedback_color, feedback_depth] : m_framebuffers)
|
||||
{
|
||||
@@ -275,7 +261,7 @@ void* GSTextureVK::GetNativeHandle() const
|
||||
|
||||
VkCommandBuffer GSTextureVK::GetCommandBufferForUpdate()
|
||||
{
|
||||
if (m_type != Type::Texture || m_use_fence_counter == GSDeviceVK::GetInstance()->GetCurrentFenceCounter())
|
||||
if (!IsTexture() || m_use_fence_counter == GSDeviceVK::GetInstance()->GetCurrentFenceCounter())
|
||||
{
|
||||
// Console.WriteLn("Texture update within frame, can't use do beforehand");
|
||||
GSDeviceVK::GetInstance()->EndRenderPass();
|
||||
@@ -404,7 +390,7 @@ bool GSTextureVK::Update(const GSVector4i& r, const void* data, int pitch, int l
|
||||
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)
|
||||
if (IsRenderTarget())
|
||||
{
|
||||
if (!r.eq(GSVector4i(0, 0, m_size.x, m_size.y)))
|
||||
CommitClear(cmdbuf);
|
||||
@@ -416,7 +402,7 @@ bool GSTextureVK::Update(const GSVector4i& r, const void* data, int pitch, int l
|
||||
CalcUploadRowLengthFromPitch(upload_pitch), buffer, buffer_offset);
|
||||
TransitionToLayout(cmdbuf, Layout::ShaderReadOnly);
|
||||
|
||||
if (m_type == Type::Texture)
|
||||
if (IsTexture())
|
||||
m_needs_mipmaps_generated |= (layer == 0);
|
||||
|
||||
return true;
|
||||
@@ -486,7 +472,7 @@ void GSTextureVK::Unmap()
|
||||
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)
|
||||
if (IsRenderTarget())
|
||||
{
|
||||
if (!m_map_area.eq(GSVector4i(0, 0, m_size.x, m_size.y)))
|
||||
CommitClear(cmdbuf);
|
||||
@@ -499,7 +485,7 @@ void GSTextureVK::Unmap()
|
||||
buffer_offset);
|
||||
TransitionToLayout(cmdbuf, Layout::ShaderReadOnly);
|
||||
|
||||
if (m_type == Type::Texture)
|
||||
if (IsTexture())
|
||||
m_needs_mipmaps_generated |= (m_map_level == 0);
|
||||
}
|
||||
|
||||
@@ -813,7 +799,7 @@ VkFramebuffer GSTextureVK::GetFramebuffer(bool feedback_loop)
|
||||
|
||||
VkFramebuffer GSTextureVK::GetLinkedFramebuffer(GSTextureVK* depth_texture, bool feedback_loop_color, bool feedback_loop_depth)
|
||||
{
|
||||
pxAssertRel(m_type != Type::Texture, "Texture is a render target");
|
||||
pxAssertRel(!IsTexture(), "Texture is a render target");
|
||||
|
||||
for (const auto& [other_tex, fb, other_feedback_loop_color, other_feedback_loop_depth] : m_framebuffers)
|
||||
{
|
||||
@@ -822,9 +808,8 @@ VkFramebuffer GSTextureVK::GetLinkedFramebuffer(GSTextureVK* depth_texture, bool
|
||||
}
|
||||
|
||||
const VkRenderPass rp = GSDeviceVK::GetInstance()->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,
|
||||
!IsDepthStencil() ? m_vk_format : VK_FORMAT_UNDEFINED,
|
||||
!IsDepthStencil() ? (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_color, feedback_loop_depth);
|
||||
if (!rp)
|
||||
|
||||
@@ -33,9 +33,9 @@ public:
|
||||
|
||||
~GSTextureVK() override;
|
||||
|
||||
static std::unique_ptr<GSTextureVK> Create(Type type, Format format, int width, int height, int levels);
|
||||
static std::unique_ptr<GSTextureVK> Create(Usage usage, 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);
|
||||
VkImage image, Usage usage, Format format, int width, int height, int levels, VkFormat vk_format);
|
||||
|
||||
void Destroy(bool defer);
|
||||
|
||||
@@ -83,7 +83,7 @@ public:
|
||||
__fi void SetUseFenceCounter(u64 counter) { m_use_fence_counter = counter; }
|
||||
|
||||
private:
|
||||
GSTextureVK(Type type, Format format, int width, int height, int levels, VkImage image, VmaAllocation allocation,
|
||||
GSTextureVK(Usage usage, Format format, int width, int height, int levels, VkImage image, VmaAllocation allocation,
|
||||
VkImageView view, VkFormat vk_format);
|
||||
|
||||
VkCommandBuffer GetCommandBufferForUpdate();
|
||||
|
||||
@@ -463,7 +463,7 @@ bool VKSwapChain::CreateSwapChain()
|
||||
for (u32 i = 0; i < image_count; i++)
|
||||
{
|
||||
std::unique_ptr<GSTextureVK> texture =
|
||||
GSTextureVK::Adopt(images[i], GSTexture::Type::RenderTarget, GSTexture::Format::Color,
|
||||
GSTextureVK::Adopt(images[i], GSTexture::RenderTarget, GSTexture::Format::Color,
|
||||
m_window_info.surface_width, m_window_info.surface_height, 1, surface_format->format);
|
||||
if (!texture)
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user