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:
TJnotJT
2026-06-21 00:17:51 -05:00
committed by Ty
parent c7042e1877
commit b11a406519
29 changed files with 502 additions and 414 deletions
+1
View File
@@ -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
View File
@@ -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;
}
+107 -96
View File
@@ -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.");
+9 -6
View File
@@ -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);
+35
View File
@@ -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())
+90 -17
View File
@@ -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; }
+26 -23
View File
@@ -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.");
+1 -1
View File
@@ -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);
+2 -2
View File
@@ -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);
}
+1 -1
View File
@@ -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);
+10 -10
View File
@@ -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.");
+1 -2
View File
@@ -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;
+85 -106
View File
@@ -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);
}
+3 -3
View File
@@ -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,
+2 -2
View File
@@ -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.
+11 -13
View File
@@ -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;
+1 -1
View File
@@ -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;
+29 -27
View File
@@ -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);
+1 -1
View File
@@ -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
+4 -2
View File
@@ -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
+9 -8
View File
@@ -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)
{
+1 -1
View File
@@ -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;
+6 -6
View File
@@ -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);
+1 -1
View File
@@ -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; }
+12 -15
View File
@@ -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.");
+1 -2
View File
@@ -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;
+48 -63
View File
@@ -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)
+3 -3
View File
@@ -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();
+1 -1
View File
@@ -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;