GS/DX11/GL: Fix sample area calculation for RT/DS sampling hazard.

This commit is contained in:
TJnotJT
2026-06-12 18:58:17 +02:00
committed by lightningterror
parent d5f75c9e42
commit 76f690d96e
7 changed files with 23 additions and 102 deletions
-66
View File
@@ -2615,7 +2615,6 @@ void GSState::FlushPrim()
m_quad_check_valid_shuffle = false;
m_drawlist.clear();
m_drawlist_bbox.clear();
m_drawlist_bbox_tex.clear();
if (GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
{
@@ -4750,71 +4749,6 @@ GSState::PRIM_OVERLAP GSState::GetPrimitiveOverlapDrawlist(bool save_drawlist, b
}
}
template <u32 primclass, bool fst>
void GSState::GetPrimitiveOverlapDrawlistTextureBBoxImpl(float bbox_scale)
{
pxAssert(m_drawlist_bbox_tex.empty()); // Should only call this once per draw.
constexpr int n = GSUtil::GetClassVertexCount(primclass);
const GSVertex* RESTRICT v = m_vertex->buff;
const u16* RESTRICT index = m_index->buff;
const u32 count = m_index->tail;
for (u32 i = 0; i < count; i += n)
{
const float q = primclass == GS_SPRITE_CLASS ? v[index[i + 1]].RGBAQ.Q : v[index[i]].RGBAQ.Q;
GSVector4 bbox = GetTexCoordsImpl<fst>(v[index[i]], q);
for (u32 j = 1; j < n; j++)
{
const GSVector4 tex = GetTexCoordsImpl<fst>(v[index[i + j]]);
bbox = bbox.min(tex).xyzw(bbox.max(tex));
}
bbox = bbox * bbox_scale; // Account for upscaling.
bbox = bbox.floor().xyzw(bbox.ceil()); // Round.
bbox += GSVector4(-1.0f, -1.0f, 1.0f, 1.0f); // +1 on all sides for bilinear.
m_drawlist_bbox_tex.push_back(GSVector4i(bbox));
}
}
void GSState::GetPrimitiveOverlapDrawlistTextureBBox(float bbox_scale)
{
pxAssert(PRIM->TME);
switch (m_vt.m_primclass)
{
case GS_POINT_CLASS:
if (PRIM->FST)
GetPrimitiveOverlapDrawlistTextureBBoxImpl<GS_POINT_CLASS, true>(bbox_scale);
else
GetPrimitiveOverlapDrawlistTextureBBoxImpl<GS_POINT_CLASS, false>(bbox_scale);
break;
case GS_LINE_CLASS:
if (PRIM->FST)
GetPrimitiveOverlapDrawlistTextureBBoxImpl<GS_LINE_CLASS, true>(bbox_scale);
else
GetPrimitiveOverlapDrawlistTextureBBoxImpl<GS_LINE_CLASS, false>(bbox_scale);
break;
case GS_TRIANGLE_CLASS:
if (PRIM->FST)
GetPrimitiveOverlapDrawlistTextureBBoxImpl<GS_TRIANGLE_CLASS, true>(bbox_scale);
else
GetPrimitiveOverlapDrawlistTextureBBoxImpl<GS_TRIANGLE_CLASS, false>(bbox_scale);
break;
case GS_SPRITE_CLASS:
if (PRIM->FST)
GetPrimitiveOverlapDrawlistTextureBBoxImpl<GS_SPRITE_CLASS, true>(bbox_scale);
else
GetPrimitiveOverlapDrawlistTextureBBoxImpl<GS_SPRITE_CLASS, false>(bbox_scale);
break;
default:
pxAssert(false);
return;
}
}
GSState::PRIM_OVERLAP GSState::PrimitiveOverlap(bool save_drawlist)
{
// Assume that 1 triangle, 1 sprite, 1 line, or 3 points can't overlap.
-4
View File
@@ -392,7 +392,6 @@ public:
PRIM_OVERLAP m_prim_overlap = PRIM_OVERLAP_UNKNOW;
std::vector<size_t> m_drawlist;
std::vector<GSVector4i> m_drawlist_bbox;
std::vector<GSVector4i> m_drawlist_bbox_tex;
struct GSPCRTCRegs
{
@@ -538,9 +537,6 @@ public:
PRIM_OVERLAP GetPrimitiveOverlapDrawlist(bool save_drawlist = false, bool save_bbox = false,
float bbox_scale = 1.0f, u32* max_size = nullptr);
PRIM_OVERLAP PrimitiveOverlap(bool save_drawlist = false);
template <u32 primclass, bool fst>
void GetPrimitiveOverlapDrawlistTextureBBoxImpl(float bbox_scale = 1.0f);
void GetPrimitiveOverlapDrawlistTextureBBox(float bbox_scale = 1.0f);
bool SpriteDrawWithoutGaps();
void CalculatePrimitiveCoversWithoutGaps();
GIFRegTEX0 GetTex0Layer(u32 lod);
+11 -12
View File
@@ -1226,18 +1226,17 @@ struct alignas(16) GSHWDrawConfig
EarlyResolve = 4
};
GSTexture* rt; ///< Render target
GSTexture* ds; ///< Depth stencil
GSTexture* tex; ///< Source texture
GSTexture* pal; ///< Palette texture
const GSVertex* verts;///< Vertices to draw
const u16* indices; ///< Indices to draw
u32 nverts; ///< Number of vertices
u32 nindices; ///< Number of indices
u32 indices_per_prim; ///< Number of indices that make up one primitive
const std::vector<size_t>* drawlist; ///< For reducing barriers on sprites
const std::vector<GSVector4i>* drawlist_bbox; ///< For RT copy when barriers not available.
const std::vector<GSVector4i>* drawlist_bbox_tex; ///< Additionally if we need to sample not from the same pixel of the RT.
GSTexture* rt; ///< Render target
GSTexture* ds; ///< Depth stencil
GSTexture* tex; ///< Source texture
GSTexture* pal; ///< Palette texture
const GSVertex* verts; ///< Vertices to draw
const u16* indices; ///< Indices to draw
u32 nverts; ///< Number of vertices
u32 nindices; ///< Number of indices
u32 indices_per_prim; ///< Number of indices that make up one primitive
const std::vector<size_t>* drawlist; ///< For reducing barriers on sprites
const std::vector<GSVector4i>* drawlist_bbox; ///< For RT copy when barriers not available.
GSVector4i scissor; ///< Scissor rect
GSVector4i drawarea; ///< Area in the framebuffer which will be modified.
GSVector4i samplearea; ///< Area in the texture which will be sampled.
+4 -3
View File
@@ -3230,15 +3230,16 @@ void GSDevice11::SendHWDraw(const GSHWDrawConfig& config,
pxAssert(config.drawlist && !config.drawlist->empty());
pxAssert(config.drawlist_bbox && static_cast<u32>(config.drawlist_bbox->size()) == draw_list_size);
if (config.tex_hazard != config.TEX_HAZARD_NONE)
FeedbackCopyAndBind(config, draw_rt, draw_rt_clone, draw_ds, draw_ds_clone, config.samplearea);
for (u32 n = 0, p = 0; n < draw_list_size; n++)
{
const u32 count = config.drawlist->at(n) * indices_per_prim;
const GSVector4i bbox = config.drawlist_bbox->at(n).rintersect(config.drawarea);
const GSVector4i bbox_tex = config.drawlist_bbox_tex ?
config.drawlist_bbox_tex->at(n).rintersect(config.samplearea) : GSVector4i::zero();
FeedbackCopyAndBind(config, draw_rt, draw_rt_clone, draw_ds, draw_ds_clone, bbox, bbox_tex);
FeedbackCopyAndBind(config, draw_rt, draw_rt_clone, draw_ds, draw_ds_clone, bbox);
Draw(config, p, count);
+3 -13
View File
@@ -1358,10 +1358,10 @@ GSVector4i GSRendererHW::ComputeBoundingBoxRT(const GSVector2i& rtsize, float rt
return GSVector4i(box * GSVector4(rtscale)).rintersect(GSVector4i(0, 0, rtsize.x, rtsize.y));
}
GSVector4i GSRendererHW::ComputeBoundingBoxTex(const GSVector2i& texsize, const GSVector4i& region, float texscale)
GSVector4i GSRendererHW::ComputeBoundingBoxTex(const GSVector2i& texsize, const GSVector4i& coverage, const GSVector4i& region, float texscale)
{
const GSVector4 offset = GSVector4(region.xyxy()) + GSVector4(-1.0f, -1.0f, 1.0f, 1.0f); // Region offset + round value
const GSVector4 box = m_vt.m_min.t.upld(m_vt.m_max.t) + offset;
const GSVector4 box = GSVector4(coverage) + offset;
return GSVector4i(box * GSVector4(texscale)).rintersect(GSVector4i(0, 0, texsize.x, texsize.y));
}
@@ -6206,16 +6206,6 @@ void GSRendererHW::DetermineBarriers(GSTextureCache::Target* rt, GSTextureCache:
ComputeDrawlistGetSize(rt->m_scale);
m_conf.drawlist = &m_drawlist;
m_conf.drawlist_bbox = &m_drawlist_bbox;
if (m_conf.tex_hazard != GSHWDrawConfig::TEX_HAZARD_NONE)
{
GetPrimitiveOverlapDrawlistTextureBBox(tex->GetScale());
m_conf.drawlist_bbox_tex = &m_drawlist_bbox_tex;
}
else
{
m_conf.drawlist_bbox_tex = nullptr;
}
}
}
@@ -9462,7 +9452,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
const GSVector4i tex_region = tex ? tex->GetRegionRect() : GSVector4i::zero();
m_conf.samplearea = m_channel_shuffle ? scissor :
GSVector4i::loadh(texsize).rintersect(ComputeBoundingBoxTex(texsize, tex_region, texscale));
GSVector4i::loadh(texsize).rintersect(ComputeBoundingBoxTex(texsize, tmm.coverage, tex_region, texscale));
m_conf.scissor = (date_options.enabled && !date_options.barrier) ? m_conf.drawarea : scissor;
+1 -1
View File
@@ -364,7 +364,7 @@ public:
void ExpandLineIndices();
GSVector4 RealignTargetTextureCoordinate(const GSTextureCache::Source* tex);
GSVector4i ComputeBoundingBoxRT(const GSVector2i& rtsize, float rtscale);
GSVector4i ComputeBoundingBoxTex(const GSVector2i& texsize, const GSVector4i& region, float texscale);
GSVector4i ComputeBoundingBoxTex(const GSVector2i& texsize, const GSVector4i& coverage, const GSVector4i& region, float texscale);
void MergeSprite(GSTextureCache::Source* tex);
float GetTextureScaleFactor() override;
GSVector2i GetValidSize(const GSTextureCache::Source* tex = nullptr, const bool is_shuffle = false);
+4 -3
View File
@@ -3172,6 +3172,9 @@ void GSDeviceOGL::SendHWDraw(const GSHWDrawConfig& config,
else
pxAssert(config.drawlist_bbox && static_cast<u32>(config.drawlist_bbox->size()) == draw_list_size);
if (!m_features.texture_barrier && config.tex_hazard != config.TEX_HAZARD_NONE)
FeedbackCopyAndBind(config, draw_rt, draw_rt_clone, draw_ds, draw_ds_clone, config.samplearea);
for (u32 n = 0, p = 0; n < draw_list_size; n++)
{
const u32 count = config.drawlist->at(n) * indices_per_prim;
@@ -3183,9 +3186,7 @@ void GSDeviceOGL::SendHWDraw(const GSHWDrawConfig& config,
else
{
const GSVector4i bbox = config.drawlist_bbox->at(n).rintersect(config.drawarea);
const GSVector4i bbox_tex = config.drawlist_bbox_tex ?
config.drawlist_bbox_tex->at(n).rintersect(config.samplearea) : GSVector4i::zero();
FeedbackCopyAndBind(config, draw_rt, draw_rt_clone, draw_ds, draw_ds_clone, bbox, bbox_tex);
FeedbackCopyAndBind(config, draw_rt, draw_rt_clone, draw_ds, draw_ds_clone, bbox);
}
Draw(config, p, count);