mirror of
https://github.com/PCSX2/pcsx2.git
synced 2025-12-16 04:08:48 +00:00
GS: Add LOD checking to HandleAutoflush().
Only enabled when the draw might use mipmapping.
This commit is contained in:
parent
0c70cc7e5a
commit
a33ee13bb4
@ -4148,8 +4148,8 @@ __forceinline void GSState::HandleAutoFlush()
|
|||||||
// To briefly explain what's going on here, what we are checking for is draws over a texture when the source and destination are themselves.
|
// To briefly explain what's going on here, what we are checking for is draws over a texture when the source and destination are themselves.
|
||||||
// Because one page of the texture gets buffered in the Texture Cache (the PS2's one) if any of those pixels are overwritten, you still read the old data.
|
// Because one page of the texture gets buffered in the Texture Cache (the PS2's one) if any of those pixels are overwritten, you still read the old data.
|
||||||
// So we need to calculate if a page boundary is being crossed for the format it is in and if the same part of the texture being written and read inside the draw.
|
// So we need to calculate if a page boundary is being crossed for the format it is in and if the same part of the texture being written and read inside the draw.
|
||||||
int lod = 0;
|
int tex_layer = 0;
|
||||||
if (IsAutoFlushDraw(prim, lod))
|
if (IsAutoFlushDraw(prim, tex_layer))
|
||||||
{
|
{
|
||||||
int n = 1;
|
int n = 1;
|
||||||
u32 buff[3];
|
u32 buff[3];
|
||||||
@ -4184,23 +4184,33 @@ __forceinline void GSState::HandleAutoFlush()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool possible_mipmap = m_context->TEX1.MXL > 0 && m_context->TEX1.MMIN >= 2 && m_context->TEX1.MMIN <= 5;
|
||||||
|
const float K = static_cast<float>(m_context->TEX1.K) / 16;
|
||||||
|
const float powL = static_cast<float>(1 << m_context->TEX1.L);
|
||||||
|
|
||||||
GSVector4i tex_coord;
|
GSVector4i tex_coord;
|
||||||
|
float vert_lod = K;
|
||||||
|
|
||||||
// Prepare the currently processed vertex.
|
// Prepare the currently processed vertex.
|
||||||
if (PRIM->FST)
|
if (PRIM->FST)
|
||||||
{
|
{
|
||||||
tex_coord.x = m_v.U >> 4;
|
tex_coord.x = (m_v.U >> 4) >> tex_layer;
|
||||||
tex_coord.y = m_v.V >> 4;
|
tex_coord.y = (m_v.V >> 4) >> tex_layer;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const float s = std::min((m_v.ST.S / m_v.RGBAQ.Q), 1.0f);
|
const float s = std::min((m_v.ST.S / m_v.RGBAQ.Q), 1.0f);
|
||||||
const float t = std::min((m_v.ST.T / m_v.RGBAQ.Q), 1.0f);
|
const float t = std::min((m_v.ST.T / m_v.RGBAQ.Q), 1.0f);
|
||||||
|
|
||||||
tex_coord.x = static_cast<int>((1 << m_context->TEX0.TW) * s);
|
tex_coord.x = static_cast<int>((1 << m_context->TEX0.TW) * s) >> tex_layer;
|
||||||
tex_coord.y = static_cast<int>((1 << m_context->TEX0.TH) * t);
|
tex_coord.y = static_cast<int>((1 << m_context->TEX0.TH) * t) >> tex_layer;
|
||||||
|
|
||||||
|
if (possible_mipmap && !m_context->TEX1.LCM)
|
||||||
|
vert_lod = -std::log2(std::abs(m_v.RGBAQ.Q)) * powL + K;
|
||||||
}
|
}
|
||||||
|
|
||||||
GSVector4i tex_rect = tex_coord.xyxy();
|
GSVector4i tex_rect = tex_coord.xyxy();
|
||||||
|
GSVector2i lod_range = GSVector2i(static_cast<int>(std::floor(vert_lod)), static_cast<int>(std::ceil(vert_lod)));
|
||||||
|
|
||||||
const GSLocalMemory::psm_t tex_psm = GSLocalMemory::m_psm[m_context->TEX0.PSM];
|
const GSLocalMemory::psm_t tex_psm = GSLocalMemory::m_psm[m_context->TEX0.PSM];
|
||||||
const GSLocalMemory::psm_t frame_psm = GSLocalMemory::m_psm[m_context->FRAME.PSM];
|
const GSLocalMemory::psm_t frame_psm = GSLocalMemory::m_psm[m_context->FRAME.PSM];
|
||||||
@ -4211,24 +4221,33 @@ __forceinline void GSState::HandleAutoFlush()
|
|||||||
|
|
||||||
if (PRIM->FST)
|
if (PRIM->FST)
|
||||||
{
|
{
|
||||||
tex_coord.x = v->U >> 4;
|
tex_coord.x = (v->U >> 4) >> tex_layer;
|
||||||
tex_coord.y = v->V >> 4;
|
tex_coord.y = (v->V >> 4) >> tex_layer;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const float s = std::min((v->ST.S / v->RGBAQ.Q), 1.0f);
|
const float s = std::min((v->ST.S / v->RGBAQ.Q), 1.0f);
|
||||||
const float t = std::min((v->ST.T / v->RGBAQ.Q), 1.0f);
|
const float t = std::min((v->ST.T / v->RGBAQ.Q), 1.0f);
|
||||||
|
|
||||||
tex_coord.x = static_cast<int>(std::round((1 << m_context->TEX0.TW) * s));
|
tex_coord.x = static_cast<int>(std::round((1 << m_context->TEX0.TW) * s)) >> tex_layer;
|
||||||
tex_coord.y = static_cast<int>(std::round((1 << m_context->TEX0.TH) * t));
|
tex_coord.y = static_cast<int>(std::round((1 << m_context->TEX0.TH) * t)) >> tex_layer;
|
||||||
|
|
||||||
|
if (possible_mipmap && !m_context->TEX1.LCM)
|
||||||
|
vert_lod = -std::log2(std::abs(v->RGBAQ.Q)) * powL + K;
|
||||||
}
|
}
|
||||||
|
|
||||||
tex_rect.x = std::min(tex_rect.x, tex_coord.x);
|
tex_rect.x = std::min(tex_rect.x, tex_coord.x);
|
||||||
tex_rect.z = std::max(tex_rect.z, tex_coord.x);
|
tex_rect.z = std::max(tex_rect.z, tex_coord.x);
|
||||||
tex_rect.y = std::min(tex_rect.y, tex_coord.y);
|
tex_rect.y = std::min(tex_rect.y, tex_coord.y);
|
||||||
tex_rect.w = std::max(tex_rect.w, tex_coord.y);
|
tex_rect.w = std::max(tex_rect.w, tex_coord.y);
|
||||||
|
lod_range.x = std::min(lod_range.x, static_cast<int>(std::floor(vert_lod)));
|
||||||
|
lod_range.y = std::max(lod_range.y, static_cast<int>(std::ceil(vert_lod)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the current prim does not use the correct mipmap layer then we don't need to flush.
|
||||||
|
if (possible_mipmap && !(lod_range.x <= tex_layer && tex_layer <= lod_range.y))
|
||||||
|
return;
|
||||||
|
|
||||||
// If the draw was 1 line thick, make it larger as rects are exclusive of ends.
|
// If the draw was 1 line thick, make it larger as rects are exclusive of ends.
|
||||||
if (tex_rect.x == tex_rect.z)
|
if (tex_rect.x == tex_rect.z)
|
||||||
tex_rect += GSVector4i::cxpr(0, 0, 1, 0);
|
tex_rect += GSVector4i::cxpr(0, 0, 1, 0);
|
||||||
@ -4240,22 +4259,22 @@ __forceinline void GSState::HandleAutoFlush()
|
|||||||
|
|
||||||
if (PRIM->FST)
|
if (PRIM->FST)
|
||||||
{
|
{
|
||||||
tex_coord.x = v->U >> 4;
|
tex_coord.x = (v->U >> 4) >> tex_layer;
|
||||||
tex_coord.y = v->V >> 4;
|
tex_coord.y = (v->V >> 4) >> tex_layer;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const float s = std::min((v->ST.S / v->RGBAQ.Q), 1.0f);
|
const float s = std::min((v->ST.S / v->RGBAQ.Q), 1.0f);
|
||||||
const float t = std::min((v->ST.T / v->RGBAQ.Q), 1.0f);
|
const float t = std::min((v->ST.T / v->RGBAQ.Q), 1.0f);
|
||||||
|
|
||||||
tex_coord.x = static_cast<int>(std::round((1 << m_context->TEX0.TW) * s));
|
tex_coord.x = static_cast<int>(std::round((1 << m_context->TEX0.TW) * s)) >> tex_layer;
|
||||||
tex_coord.y = static_cast<int>(std::round((1 << m_context->TEX0.TH) * t));
|
tex_coord.y = static_cast<int>(std::round((1 << m_context->TEX0.TH) * t)) >> tex_layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int clamp_minu = m_context->CLAMP.MINU;
|
const int clamp_minu = m_context->CLAMP.MINU >> tex_layer;
|
||||||
const int clamp_maxu = m_context->CLAMP.MAXU;
|
const int clamp_maxu = m_context->CLAMP.MAXU >> tex_layer;
|
||||||
const int clamp_minv = m_context->CLAMP.MINV;
|
const int clamp_minv = m_context->CLAMP.MINV >> tex_layer;
|
||||||
const int clamp_maxv = m_context->CLAMP.MAXV;
|
const int clamp_maxv = m_context->CLAMP.MAXV >> tex_layer;
|
||||||
|
|
||||||
switch (m_context->CLAMP.WMS)
|
switch (m_context->CLAMP.WMS)
|
||||||
{
|
{
|
||||||
@ -4391,7 +4410,7 @@ __forceinline void GSState::HandleAutoFlush()
|
|||||||
const int tex_width = (m_context->TEX0.TBW * 64) / tex_psm.pgs.x;
|
const int tex_width = (m_context->TEX0.TBW * 64) / tex_psm.pgs.x;
|
||||||
if ((frame_width == tex_width) || ((tex_rect.w / tex_psm.pgs.y) <= 1 && frame_width >= tex_width))
|
if ((frame_width == tex_width) || ((tex_rect.w / tex_psm.pgs.y) <= 1 && frame_width >= tex_width))
|
||||||
{
|
{
|
||||||
tex_rect += GSVector4i(0, 0, tex_page_mask.z, tex_page_mask.w); // round up to the next page as we will be comparing by page.
|
tex_rect += GSVector4i(0, 0, tex_psm.pgs.x - 1, tex_psm.pgs.y - 1); // round up to the next page as we will be comparing by page.
|
||||||
//We know we've changed page, so let's set the dimension to cover the page they're in (for different pixel orders)
|
//We know we've changed page, so let's set the dimension to cover the page they're in (for different pixel orders)
|
||||||
tex_rect &= tex_page_mask;
|
tex_rect &= tex_page_mask;
|
||||||
tex_rect = GSVector4i(tex_rect.x / tex_psm.pgs.x, tex_rect.y / tex_psm.pgs.y, tex_rect.z / tex_psm.pgs.x, tex_rect.w / tex_psm.pgs.y);
|
tex_rect = GSVector4i(tex_rect.x / tex_psm.pgs.x, tex_rect.y / tex_psm.pgs.y, tex_rect.z / tex_psm.pgs.x, tex_rect.w / tex_psm.pgs.y);
|
||||||
@ -4400,7 +4419,7 @@ __forceinline void GSState::HandleAutoFlush()
|
|||||||
const int frame_page_mask_y = ~(frame_psm.pgs.y - 1);
|
const int frame_page_mask_y = ~(frame_psm.pgs.y - 1);
|
||||||
const GSVector4i frame_page_mask = { frame_page_mask_x, frame_page_mask_y, frame_page_mask_x, frame_page_mask_y };
|
const GSVector4i frame_page_mask = { frame_page_mask_x, frame_page_mask_y, frame_page_mask_x, frame_page_mask_y };
|
||||||
GSVector4i area_out = temp_draw_rect;
|
GSVector4i area_out = temp_draw_rect;
|
||||||
area_out += GSVector4i(0, 0, frame_page_mask.z, frame_page_mask.w); // round up to the next page as we will be comparing by page.
|
area_out += GSVector4i(0, 0, frame_psm.pgs.x - 1, frame_psm.pgs.y - 1); // round up to the next page as we will be comparing by page.
|
||||||
area_out &= frame_page_mask;
|
area_out &= frame_page_mask;
|
||||||
area_out = GSVector4i(area_out.x / frame_psm.pgs.x, area_out.y / frame_psm.pgs.y, area_out.z / frame_psm.pgs.x, area_out.w / frame_psm.pgs.y);
|
area_out = GSVector4i(area_out.x / frame_psm.pgs.x, area_out.y / frame_psm.pgs.y, area_out.z / frame_psm.pgs.x, area_out.w / frame_psm.pgs.y);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user