mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-07-18 04:55:42 +02:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ade2e456e5 | ||
|
|
e5e1153719 |
+204
-193
@@ -289,55 +289,58 @@ void GSState::ResetDrawBufferIdx()
|
||||
{
|
||||
int entry_ptr = 0;
|
||||
|
||||
for (int i = 0; i < m_used_buffers_idx; i++)
|
||||
if (GSConfig.UserHacks_DrawBuffering && m_used_buffers_idx > 1)
|
||||
{
|
||||
// There can be situations like VSync where it won't purge the draws, this is bad for us!
|
||||
if (m_index_buffers[i].tail > 0 || i == m_current_buffer_idx)
|
||||
for (int i = 0; i < m_used_buffers_idx; i++)
|
||||
{
|
||||
if (m_index_buffers[i].tail == 0)
|
||||
m_env_buffers[i].draw_rect = GSVector4i::zero();
|
||||
|
||||
if (entry_ptr == i && (m_index_buffers[i].tail > 0 || i == m_current_buffer_idx))
|
||||
// There can be situations like VSync where it won't purge the draws, this is bad for us!
|
||||
if (m_index_buffers[i].tail > 0 || i == m_current_buffer_idx)
|
||||
{
|
||||
if (m_index_buffers[i].tail == 0)
|
||||
m_env_buffers[i].draw_rect = GSVector4i::zero();
|
||||
|
||||
if (entry_ptr == i && (m_index_buffers[i].tail > 0 || i == m_current_buffer_idx))
|
||||
{
|
||||
entry_ptr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(m_vertex_buffers[entry_ptr].buff, m_vertex_buffers[i].buff, sizeof(GSVertex) * m_vertex_buffers[i].tail);
|
||||
|
||||
m_vertex_buffers[entry_ptr].head = m_vertex_buffers[i].head;
|
||||
m_vertex_buffers[entry_ptr].tail = m_vertex_buffers[i].tail;
|
||||
m_vertex_buffers[entry_ptr].next = m_vertex_buffers[i].next;
|
||||
|
||||
memcpy(m_index_buffers[entry_ptr].buff, m_index_buffers[i].buff, sizeof(u16) * m_index_buffers[i].tail);
|
||||
m_index_buffers[entry_ptr].tail = m_index_buffers[i].tail;
|
||||
|
||||
if (m_vertex_buffers[entry_ptr].tail != 0)
|
||||
{
|
||||
memcpy(m_vertex_buffers[entry_ptr].xy, m_vertex_buffers[i].xy, sizeof(m_vertex_buffers[i].xy));
|
||||
m_vertex_buffers[entry_ptr].xyhead = m_vertex_buffers[i].xyhead;
|
||||
m_vertex_buffers[entry_ptr].xy_tail = m_vertex_buffers[i].xy_tail;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_vertex_buffers[entry_ptr].xy_tail = 0;
|
||||
}
|
||||
|
||||
memcpy(&m_env_buffers[entry_ptr], &m_env_buffers[i], sizeof(m_env_buffers[i]));
|
||||
|
||||
|
||||
if (i == m_current_buffer_idx)
|
||||
m_current_buffer_idx = entry_ptr;
|
||||
|
||||
entry_ptr++;
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(m_vertex_buffers[entry_ptr].buff, m_vertex_buffers[i].buff, sizeof(GSVertex) * m_vertex_buffers[i].tail);
|
||||
|
||||
m_vertex_buffers[entry_ptr].head = m_vertex_buffers[i].head;
|
||||
m_vertex_buffers[entry_ptr].tail = m_vertex_buffers[i].tail;
|
||||
m_vertex_buffers[entry_ptr].next = m_vertex_buffers[i].next;
|
||||
|
||||
memcpy(m_index_buffers[entry_ptr].buff, m_index_buffers[i].buff, sizeof(u16) * m_index_buffers[i].tail);
|
||||
m_index_buffers[entry_ptr].tail = m_index_buffers[i].tail;
|
||||
|
||||
if (m_vertex_buffers[entry_ptr].tail != 0)
|
||||
if (i != (entry_ptr - 1))
|
||||
{
|
||||
memcpy(m_vertex_buffers[entry_ptr].xy, m_vertex_buffers[i].xy, sizeof(m_vertex_buffers[i].xy));
|
||||
m_vertex_buffers[entry_ptr].xyhead = m_vertex_buffers[i].xyhead;
|
||||
m_vertex_buffers[entry_ptr].xy_tail = m_vertex_buffers[i].xy_tail;
|
||||
m_index_buffers[i].tail = 0;
|
||||
memset(&m_env_buffers[i], 0, sizeof(GSDrawBufferEnv));
|
||||
m_vertex_buffers[i].head = m_vertex_buffers[i].tail = m_vertex_buffers[i].next = 0;
|
||||
m_vertex_buffers[i].xy_tail = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_vertex_buffers[entry_ptr].xy_tail = 0;
|
||||
}
|
||||
|
||||
memcpy(&m_env_buffers[entry_ptr], &m_env_buffers[i], sizeof(m_env_buffers[i]));
|
||||
|
||||
|
||||
if (i == m_current_buffer_idx)
|
||||
m_current_buffer_idx = entry_ptr;
|
||||
|
||||
entry_ptr++;
|
||||
}
|
||||
|
||||
if (i != (entry_ptr - 1))
|
||||
{
|
||||
m_index_buffers[i].tail = 0;
|
||||
memset(&m_env_buffers[i], 0, sizeof(GSDrawBufferEnv));
|
||||
m_vertex_buffers[i].head = m_vertex_buffers[i].tail = m_vertex_buffers[i].next = 0;
|
||||
m_vertex_buffers[i].xy_tail = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,18 +392,11 @@ void GSState::ResetDrawBuffers()
|
||||
// exclude_current is used if there is a flush for a reason other than the normal context change.
|
||||
void GSState::FlushBuffers(bool flush_base_only, bool use_flush_reason, GSFlushReason flush_reason)
|
||||
{
|
||||
const int current_idx = m_current_buffer_idx;
|
||||
bool restore_env = false;
|
||||
|
||||
if (m_used_buffers_idx > 0)
|
||||
if (m_used_buffers_idx > 1)
|
||||
{
|
||||
if (m_used_buffers_idx > 1)
|
||||
{
|
||||
restore_env = true;
|
||||
memcpy(&m_temp_env, &m_env, sizeof(m_env));
|
||||
}
|
||||
else if (m_index_buffers[0].tail == 0)
|
||||
return;
|
||||
const int current_idx = m_current_buffer_idx;
|
||||
bool restore_env = true;
|
||||
memcpy(&m_temp_env, &m_env, sizeof(m_env));
|
||||
|
||||
const int max_flushes = flush_base_only ? 1 : m_used_buffers_idx;
|
||||
for (int i = 0; i < max_flushes; i++)
|
||||
@@ -440,19 +436,26 @@ void GSState::FlushBuffers(bool flush_base_only, bool use_flush_reason, GSFlushR
|
||||
else
|
||||
FlushDraw(GSFlushReason::CONTEXTCHANGE);
|
||||
}
|
||||
|
||||
// Restore the environment
|
||||
m_current_buffer_idx = current_idx;
|
||||
m_index = &m_index_buffers[m_current_buffer_idx];
|
||||
m_vertex = &m_vertex_buffers[m_current_buffer_idx];
|
||||
|
||||
const int ctx = m_env_buffers[m_current_buffer_idx].m_backed_up_ctx;
|
||||
std::memcpy(&m_prev_env, &m_env_buffers[m_current_buffer_idx].m_env, 88);
|
||||
std::memcpy(&m_prev_env.CTXT[0], &m_env_buffers[m_current_buffer_idx].m_env.CTXT[0], 96);
|
||||
std::memcpy(&m_prev_env.CTXT[1], &m_env_buffers[m_current_buffer_idx].m_env.CTXT[1], 96);
|
||||
std::memcpy(&m_prev_env.CTXT[ctx].offset, &m_env_buffers[m_current_buffer_idx].m_env.CTXT[ctx].offset, sizeof(m_env_buffers[m_current_buffer_idx].m_env.CTXT[ctx].offset));
|
||||
std::memcpy(&m_prev_env.CTXT[ctx].scissor, &m_env_buffers[m_current_buffer_idx].m_env.CTXT[ctx].scissor, sizeof(m_env_buffers[m_current_buffer_idx].m_env.CTXT[ctx].scissor));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (use_flush_reason || flush_reason == VSYNC)
|
||||
FlushDraw(flush_reason);
|
||||
else
|
||||
FlushDraw(GSFlushReason::CONTEXTCHANGE);
|
||||
}
|
||||
|
||||
// Restore the environment
|
||||
m_current_buffer_idx = current_idx;
|
||||
m_index = &m_index_buffers[m_current_buffer_idx];
|
||||
m_vertex = &m_vertex_buffers[m_current_buffer_idx];
|
||||
|
||||
const int ctx = m_env_buffers[m_current_buffer_idx].m_backed_up_ctx;
|
||||
std::memcpy(&m_prev_env, &m_env_buffers[m_current_buffer_idx].m_env, 88);
|
||||
std::memcpy(&m_prev_env.CTXT[0], &m_env_buffers[m_current_buffer_idx].m_env.CTXT[0], 96);
|
||||
std::memcpy(&m_prev_env.CTXT[1], &m_env_buffers[m_current_buffer_idx].m_env.CTXT[1], 96);
|
||||
std::memcpy(&m_prev_env.CTXT[ctx].offset, &m_env_buffers[m_current_buffer_idx].m_env.CTXT[ctx].offset, sizeof(m_env_buffers[m_current_buffer_idx].m_env.CTXT[ctx].offset));
|
||||
std::memcpy(&m_prev_env.CTXT[ctx].scissor, &m_env_buffers[m_current_buffer_idx].m_env.CTXT[ctx].scissor, sizeof(m_env_buffers[m_current_buffer_idx].m_env.CTXT[ctx].scissor));
|
||||
}
|
||||
|
||||
void GSState::PushBuffer()
|
||||
@@ -504,6 +507,18 @@ void GSState::PushBuffer()
|
||||
}
|
||||
}
|
||||
|
||||
void GSState::SetDrawBufferEnv()
|
||||
{
|
||||
memcpy(&m_env_buffers[m_current_buffer_idx].m_env, &m_env, sizeof(GSDrawingEnvironment));
|
||||
m_env_buffers[m_current_buffer_idx].m_backed_up_ctx = m_backed_up_ctx;
|
||||
}
|
||||
|
||||
void GSState::SetDrawBuffDirty()
|
||||
{
|
||||
m_env_buffers[m_current_buffer_idx].m_dirty_regs = m_dirty_gs_regs;
|
||||
m_env_buffers[m_current_buffer_idx].draw_rect = temp_draw_rect;
|
||||
}
|
||||
|
||||
bool GSState::CanBufferNewDraw()
|
||||
{
|
||||
if (!GSConfig.UserHacks_DrawBuffering)
|
||||
@@ -692,18 +707,6 @@ bool GSState::CanBufferNewDraw()
|
||||
return true;
|
||||
}
|
||||
|
||||
void GSState::SetDrawBufferEnv()
|
||||
{
|
||||
memcpy(&m_env_buffers[m_current_buffer_idx].m_env, &m_env, sizeof(GSDrawingEnvironment));
|
||||
m_env_buffers[m_current_buffer_idx].m_backed_up_ctx = m_backed_up_ctx;
|
||||
}
|
||||
|
||||
void GSState::SetDrawBuffDirty()
|
||||
{
|
||||
m_env_buffers[m_current_buffer_idx].m_dirty_regs = m_dirty_gs_regs;
|
||||
m_env_buffers[m_current_buffer_idx].draw_rect = temp_draw_rect;
|
||||
}
|
||||
|
||||
void GSState::ResetHandlers()
|
||||
{
|
||||
std::fill(std::begin(m_fpGIFPackedRegHandlers), std::end(m_fpGIFPackedRegHandlers), &GSState::GIFPackedRegHandlerNull);
|
||||
@@ -1673,7 +1676,7 @@ void GSState::ApplyTEX0(GIFRegTEX0& TEX0)
|
||||
{
|
||||
for (int b = 0; b < m_used_buffers_idx; b++)
|
||||
{
|
||||
GSDrawingEnvironment& buffered_env = m_env_buffers[b].m_env;
|
||||
GSDrawingEnvironment& buffered_env = (m_current_buffer_idx == b) ? m_prev_env : m_env_buffers[b].m_env;
|
||||
if ((buffered_env.PRIM.TME && (buffered_env.CTXT[buffered_env.PRIM.CTXT].TEX0.PSM & 0x7) >= 3) || (m_mem.m_clut.IsInvalid() & 2))
|
||||
Flush(GSFlushReason::CLUTCHANGE);
|
||||
}
|
||||
@@ -2561,9 +2564,11 @@ void GSState::FlushPrim()
|
||||
Console.Warning("GS: Possible invalid draw, Frame PSM %x ZPSM %x", m_context->FRAME.PSM, m_context->ZBUF.PSM);
|
||||
}
|
||||
#endif
|
||||
GSVertexBuff& vtx_buff = *m_vertex;
|
||||
GSIndexBuff& idx_buff = *m_index;
|
||||
// Update scissor, it may have been modified by a previous draw
|
||||
m_env.CTXT[PRIM->CTXT].UpdateScissor();
|
||||
m_vt.Update(m_vertex->buff, m_index->buff, m_vertex->tail, m_index->tail, GSUtil::GetPrimClass(PRIM->PRIM));
|
||||
m_vt.Update(vtx_buff.buff, idx_buff.buff, vtx_buff.tail, idx_buff.tail, GSUtil::GetPrimClass(PRIM->PRIM));
|
||||
|
||||
// Texel coordinate rounding
|
||||
// Helps Manhunt (lights shining through objects).
|
||||
@@ -2575,13 +2580,13 @@ void GSState::FlushPrim()
|
||||
{
|
||||
const bool is_sprite = GSUtil::GetPrimClass(PRIM->PRIM) == GS_PRIM_CLASS::GS_SPRITE_CLASS;
|
||||
// ST's have the lowest 9 bits (or greater depending on exponent difference) rounding down (from hardware tests).
|
||||
for (int i = m_index->tail - 1; i >= 0; i--)
|
||||
for (int i = idx_buff.tail - 1; i >= 0; i--)
|
||||
{
|
||||
GSVertex* v = &m_vertex->buff[m_index->buff[i]];
|
||||
GSVertex* v = &vtx_buff.buff[idx_buff.buff[i]];
|
||||
|
||||
// Only Q on the second vertex is valid
|
||||
if (!(i & 1) && is_sprite)
|
||||
v->RGBAQ.Q = m_vertex->buff[m_index->buff[i + 1]].RGBAQ.Q;
|
||||
v->RGBAQ.Q = vtx_buff.buff[idx_buff.buff[i + 1]].RGBAQ.Q;
|
||||
|
||||
int T = std::bit_cast<int>(v->ST.T);
|
||||
int Q = std::bit_cast<int>(v->RGBAQ.Q);
|
||||
@@ -2634,7 +2639,7 @@ void GSState::FlushPrim()
|
||||
Draw();
|
||||
|
||||
g_perfmon.Put(GSPerfMon::Draw, 1);
|
||||
g_perfmon.Put(GSPerfMon::Prim, m_index->tail / GSUtil::GetVertexCount(PRIM->PRIM));
|
||||
g_perfmon.Put(GSPerfMon::Prim, idx_buff.tail / GSUtil::GetVertexCount(PRIM->PRIM));
|
||||
|
||||
if (GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
|
||||
{
|
||||
@@ -2646,15 +2651,15 @@ void GSState::FlushPrim()
|
||||
}
|
||||
}
|
||||
|
||||
m_index->tail = 0;
|
||||
m_vertex->head = 0;
|
||||
idx_buff.tail = 0;
|
||||
vtx_buff.head = 0;
|
||||
|
||||
if (unused > 0)
|
||||
{
|
||||
memcpy(m_vertex->buff, buff, sizeof(GSVertex) * unused);
|
||||
memcpy(vtx_buff.buff, buff, sizeof(GSVertex) * unused);
|
||||
|
||||
m_vertex->tail = unused;
|
||||
m_vertex->next = next > head ? next - head : 0;
|
||||
vtx_buff.tail = unused;
|
||||
vtx_buff.next = next > head ? next - head : 0;
|
||||
|
||||
// If it's a Triangle fan the XY buffer needs to be updated to point to the correct head vert
|
||||
// Jak 3 shadows get spikey (with autoflush) if you don't.
|
||||
@@ -2662,22 +2667,22 @@ void GSState::FlushPrim()
|
||||
{
|
||||
for (u32 i = 0; i < unused; i++)
|
||||
{
|
||||
GSVector4i* RESTRICT vert_ptr = (GSVector4i*)&m_vertex->buff[i];
|
||||
GSVector4i* RESTRICT vert_ptr = (GSVector4i*)&vtx_buff.buff[i];
|
||||
GSVector4i v = vert_ptr[1];
|
||||
v = v.xxxx().u16to32().sub32(m_xyof);
|
||||
m_vertex->xy[i & 3] = v;
|
||||
m_vertex->xy_tail = unused;
|
||||
vtx_buff.xy[i & 3] = v;
|
||||
vtx_buff.xy_tail = unused;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_vertex->tail = 0;
|
||||
m_vertex->next = 0;
|
||||
vtx_buff.tail = 0;
|
||||
vtx_buff.next = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
GSVector4i GSState::GetTEX0Rect(GSDrawingContext prev_ctx)
|
||||
GSVector4i GSState::GetTEX0Rect(const GSDrawingContext& prev_ctx)
|
||||
{
|
||||
GSVector4i ret = GSVector4i::zero();
|
||||
|
||||
@@ -2723,27 +2728,19 @@ void GSState::CheckWriteOverlap(bool req_write, bool req_read)
|
||||
const GIFRegBITBLTBUF& blit = m_env.BITBLTBUF;
|
||||
|
||||
const GSVector4i write_rect = GSVector4i(m_env.TRXPOS.DSAX, m_env.TRXPOS.DSAY, m_env.TRXPOS.DSAX + w, m_env.TRXPOS.DSAY + h);
|
||||
const u32 write_start_bp = GSLocalMemory::GetStartBlockAddress(blit.DBP, blit.DBW, blit.DPSM, write_rect);
|
||||
const u32 write_end_bp = ((GSLocalMemory::GetEndBlockAddress(blit.DBP, blit.DBW, blit.DPSM, write_rect) + 1) + (GS_BLOCKS_PER_PAGE - 1)) & ~(GS_BLOCKS_PER_PAGE - 1);
|
||||
|
||||
for (int i = 0; i < m_used_buffers_idx; i++)
|
||||
{
|
||||
GSIndexBuff* cur_index_buff = &m_index_buffers[i];
|
||||
GSVertexBuff* cur_vertex_buff = &m_vertex_buffers[i];
|
||||
const GSDrawingContext& prev_ctx = m_env_buffers[i].m_env.CTXT[m_env_buffers[i].m_backed_up_ctx];
|
||||
const GSDrawingEnvironment& prev_env = m_env_buffers[i].m_env;
|
||||
GSVector4i tex_rect = prev_env.PRIM.TME ? GetTEX0Rect(prev_ctx) : GSVector4i::zero();
|
||||
const GSDrawingContext& prev_ctx = m_current_buffer_idx == i ? m_prev_env.CTXT[m_backed_up_ctx] :m_env_buffers[i].m_env.CTXT[m_env_buffers[i].m_backed_up_ctx];
|
||||
const GSDrawingEnvironment& prev_env = m_current_buffer_idx == i ? m_prev_env : m_env_buffers[i].m_env;
|
||||
|
||||
if (cur_index_buff->tail > 0)
|
||||
{
|
||||
// Only flush on a NEW transfer if a pending one is using the same address or overlap.
|
||||
// Check Fast & Furious (Hardare mode) and Assault Suits Valken (either renderer) and Tomb Raider - Angel of Darkness menu (TBP != DBP but overlaps).
|
||||
// Cartoon Network overwrites its own Z buffer in the middle of a draw.
|
||||
// Alias wraps its transfers, so be careful
|
||||
const GSVector4i read_rect = GSVector4i(m_env.TRXPOS.SSAX, m_env.TRXPOS.SSAY, m_env.TRXPOS.SSAX + w, m_env.TRXPOS.SSAY + h);
|
||||
|
||||
if (req_write && prev_env.PRIM.TME)
|
||||
{
|
||||
GSVector4i tex_rect = prev_env.PRIM.TME ? GetTEX0Rect(prev_ctx) : GSVector4i::zero();
|
||||
// Tex rect could be invalid showing 1024x1024 when it isn't. If the frame is only 1 page wide, it's either a big strip or a single page draw.
|
||||
// This large texture causes misdetection of overlapping writes, causing our heuristics in the hardware renderer for future draws to be missing.
|
||||
// Either way if we check the queued up coordinates, it should give us a fair idea. (Cabela's Trophy Bucks)
|
||||
@@ -2842,6 +2839,11 @@ void GSState::CheckWriteOverlap(bool req_write, bool req_read)
|
||||
}
|
||||
}
|
||||
|
||||
// Only flush on a NEW transfer if a pending one is using the same address or overlap.
|
||||
// Check Fast & Furious (Hardare mode) and Assault Suits Valken (either renderer) and Tomb Raider - Angel of Darkness menu (TBP != DBP but overlaps).
|
||||
// Cartoon Network overwrites its own Z buffer in the middle of a draw.
|
||||
// Alias wraps its transfers, so be careful
|
||||
const GSVector4i read_rect = GSVector4i(m_env.TRXPOS.SSAX, m_env.TRXPOS.SSAY, m_env.TRXPOS.SSAX + w, m_env.TRXPOS.SSAY + h);
|
||||
const u32 frame_mask = GSLocalMemory::m_psm[prev_ctx.FRAME.PSM].fmsk;
|
||||
const bool frame_required = (!(prev_ctx.TEST.ATE && prev_ctx.TEST.ATST == 0 && (prev_ctx.TEST.AFAIL == 2 || prev_ctx.TEST.AFAIL == 0)) && ((prev_ctx.FRAME.FBMSK & frame_mask) != frame_mask)) || prev_ctx.TEST.DATE;
|
||||
const GSVector4i draw_rect = (m_current_buffer_idx == i) ? temp_draw_rect : m_env_buffers[i].draw_rect;
|
||||
@@ -2874,6 +2876,9 @@ void GSState::CheckWriteOverlap(bool req_write, bool req_read)
|
||||
|
||||
if (req_write)
|
||||
{
|
||||
const u32 write_start_bp = GSLocalMemory::GetStartBlockAddress(blit.DBP, blit.DBW, blit.DPSM, write_rect);
|
||||
const u32 write_end_bp = ((GSLocalMemory::GetEndBlockAddress(blit.DBP, blit.DBW, blit.DPSM, write_rect) + 1) + (GS_BLOCKS_PER_PAGE - 1)) & ~(GS_BLOCKS_PER_PAGE - 1);
|
||||
|
||||
// Invalid the CLUT if it crosses paths.
|
||||
m_mem.m_clut.InvalidateRange(write_start_bp, write_end_bp);
|
||||
}
|
||||
@@ -5405,7 +5410,7 @@ __forceinline void GSState::CheckCLUTValidity(u32 prim)
|
||||
|
||||
for (int i = 0; i < m_used_buffers_idx; i++)
|
||||
{
|
||||
GSDrawingEnvironment& buffered_env = m_env_buffers[i].m_env;
|
||||
GSDrawingEnvironment& buffered_env = (m_current_buffer_idx == i) ? m_prev_env : m_env_buffers[i].m_env;
|
||||
const GSDrawingContext& ctx = buffered_env.CTXT[buffered_env.PRIM.CTXT];
|
||||
if ((m_index_buffers[i].tail > 0 || (m_vertex_buffers[i].tail == n - 1)) && (GSLocalMemory::m_psm[ctx.TEX0.PSM].pal == 0 || !buffered_env.PRIM.TME))
|
||||
{
|
||||
@@ -5421,7 +5426,8 @@ __forceinline void GSState::CheckCLUTValidity(u32 prim)
|
||||
if (prim != GS_POINTLIST || (m_index_buffers[i].tail > 1))
|
||||
endbp = fpsm.info.bn(temp_draw_rect.z - 1, temp_draw_rect.w - 1, ctx.FRAME.Block(), ctx.FRAME.FBW);
|
||||
|
||||
m_mem.m_clut.InvalidateRange(startbp, endbp, true);
|
||||
if (m_mem.m_clut.InvalidateRange(startbp, endbp, true))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5434,6 +5440,8 @@ __forceinline void GSState::HandleAutoFlush()
|
||||
if ((m_index->tail & 1) && (prim == GS_TRIANGLESTRIP || prim == GS_TRIANGLEFAN) && !m_texflush_flag)
|
||||
return;
|
||||
|
||||
GSVertexBuff& vtx_buff = *m_vertex;
|
||||
GSIndexBuff& idx_buff = *m_index;
|
||||
// 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.
|
||||
// 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.
|
||||
@@ -5442,8 +5450,8 @@ __forceinline void GSState::HandleAutoFlush()
|
||||
{
|
||||
int n = 1;
|
||||
u32 buff[3];
|
||||
const u32 head = m_vertex->head;
|
||||
const u32 tail = m_vertex->tail;
|
||||
const u32 head = vtx_buff.head;
|
||||
const u32 tail = vtx_buff.tail;
|
||||
|
||||
switch (prim)
|
||||
{
|
||||
@@ -5510,7 +5518,7 @@ __forceinline void GSState::HandleAutoFlush()
|
||||
// Get the rest of the rect.
|
||||
for (int i = 0; i < (n - 1); i++)
|
||||
{
|
||||
const GSVertex* v = &m_vertex->buff[buff[i]];
|
||||
const GSVertex* v = &vtx_buff.buff[buff[i]];
|
||||
|
||||
xy_coord.x = (static_cast<int>(v->XYZ.X) - static_cast<int>(m_context->XYOFFSET.OFX)) >> 4;
|
||||
xy_coord.y = (static_cast<int>(v->XYZ.Y) - static_cast<int>(m_context->XYOFFSET.OFY)) >> 4;
|
||||
@@ -5562,7 +5570,7 @@ __forceinline void GSState::HandleAutoFlush()
|
||||
return;
|
||||
|
||||
// Get the last texture position from the last draw.
|
||||
const GSVertex* v = &m_vertex->buff[m_index->buff[m_index->tail - 1]];
|
||||
const GSVertex* v = &vtx_buff.buff[idx_buff.buff[idx_buff.tail - 1]];
|
||||
|
||||
if (PRIM->FST)
|
||||
{
|
||||
@@ -5652,13 +5660,13 @@ __forceinline void GSState::HandleAutoFlush()
|
||||
const GSVector2i offset = GSVector2i(m_context->XYOFFSET.OFX, m_context->XYOFFSET.OFY);
|
||||
const GSVector4i scissor = m_context->scissor.in;
|
||||
GSVector4i old_draw_rect = GSVector4i::zero();
|
||||
int current_draw_end = m_index->tail;
|
||||
int current_draw_end = idx_buff.tail;
|
||||
|
||||
while (current_draw_end >= n)
|
||||
{
|
||||
for (int i = current_draw_end - 1; i >= current_draw_end - n; i--)
|
||||
{
|
||||
const GSVertex* v = &m_vertex->buff[m_index->buff[i]];
|
||||
const GSVertex* v = &vtx_buff.buff[idx_buff.buff[i]];
|
||||
|
||||
if (prim == GS_SPRITE && (i & 1))
|
||||
{
|
||||
@@ -5740,18 +5748,18 @@ __forceinline void GSState::HandleAutoFlush()
|
||||
}
|
||||
}
|
||||
|
||||
bool GSState::CheckOverlapVerts(u32 n)
|
||||
__inline bool GSState::CheckOverlapVerts(u32 n)
|
||||
{
|
||||
if (!GSConfig.UserHacks_DrawBuffering)
|
||||
return false;
|
||||
GSVertexBuff& vtx_buff = *m_vertex;
|
||||
GSIndexBuff& idx_buff = *m_index;
|
||||
|
||||
if (m_recent_buffer_switch && ((m_vertex->tail + 1) - m_vertex->head) == n)
|
||||
if (m_recent_buffer_switch && ((vtx_buff.tail + 1) - vtx_buff.head) == n)
|
||||
{
|
||||
m_recent_buffer_switch = false;
|
||||
|
||||
if (m_used_buffers_idx > 1)
|
||||
{
|
||||
const GSVertex* v = &m_vertex->buff[0];
|
||||
const GSVertex* v = &vtx_buff.buff[0];
|
||||
GSVector2i cur_verts[3];
|
||||
|
||||
GSVector4i new_area = GSVector4i(m_v.XYZ.X - m_context->XYOFFSET.OFX, m_v.XYZ.Y - m_context->XYOFFSET.OFY).xyxy();
|
||||
@@ -5759,11 +5767,11 @@ bool GSState::CheckOverlapVerts(u32 n)
|
||||
|
||||
for (u32 i = 0; i < (n - 1); i++)
|
||||
{
|
||||
const int pos = (m_vertex->tail - 1) - i;
|
||||
const int pos = (vtx_buff.tail - 1) - i;
|
||||
|
||||
GSVector2i prev_vert;
|
||||
if (m_env.PRIM.PRIM == GS_TRIANGLEFAN && i == (n - 2))
|
||||
prev_vert = GSVector2i(v[m_vertex->head].XYZ.X - m_context->XYOFFSET.OFX, v[m_vertex->head].XYZ.X - m_context->XYOFFSET.OFY);
|
||||
prev_vert = GSVector2i(v[vtx_buff.head].XYZ.X - m_context->XYOFFSET.OFX, v[vtx_buff.head].XYZ.X - m_context->XYOFFSET.OFY);
|
||||
else
|
||||
prev_vert = GSVector2i(v[pos].XYZ.X - m_context->XYOFFSET.OFX, v[pos].XYZ.Y - m_context->XYOFFSET.OFY);
|
||||
|
||||
@@ -5775,12 +5783,12 @@ bool GSState::CheckOverlapVerts(u32 n)
|
||||
new_area.w = std::max(new_area.w, prev_vert.y);
|
||||
}
|
||||
|
||||
if (m_index->tail > 0)
|
||||
if (idx_buff.tail > 0)
|
||||
{
|
||||
u32 matching_verts = 0;
|
||||
for (u32 i = 0; i < n; i++)
|
||||
{
|
||||
const u32 pos = m_index->buff[(m_index->tail - n) + i];
|
||||
const u32 pos = idx_buff.buff[(idx_buff.tail - n) + i];
|
||||
const GSVector2i prev_vert = GSVector2i(v[pos].XYZ.X - m_context->XYOFFSET.OFX, v[pos].XYZ.Y - m_context->XYOFFSET.OFY);
|
||||
|
||||
for (u32 j = 0; j < n; j++)
|
||||
@@ -5811,12 +5819,12 @@ bool GSState::CheckOverlapVerts(u32 n)
|
||||
}
|
||||
}
|
||||
|
||||
/*const GSVertex* v = &m_vertex->buff[0];
|
||||
/*const GSVertex* v = &vtx_buff.buff[0];
|
||||
|
||||
GSVector4i new_area = GSVector4i(m_v.XYZ.X - m_context->XYOFFSET.OFX, m_v.XYZ.Y - m_context->XYOFFSET.OFY).xyxy();
|
||||
for (u32 i = 0; i < (n - 1); i++)
|
||||
{
|
||||
const int pos = m_index->buff[(m_index->tail - 1) - i];
|
||||
const int pos = idx_buff.buff[(idx_buff.tail - 1) - i];
|
||||
GSVector2i pre_vert = GSVector2i(v[pos].XYZ.X - m_context->XYOFFSET.OFX, v[pos].XYZ.Y - m_context->XYOFFSET.OFY);
|
||||
new_area.x = std::min(new_area.x, pre_vert.x);
|
||||
new_area.z = std::max(new_area.z, pre_vert.x);
|
||||
@@ -5827,11 +5835,11 @@ bool GSState::CheckOverlapVerts(u32 n)
|
||||
|
||||
if (new_area.rintersect(temp_draw_rect).eq(new_area))
|
||||
{
|
||||
const int end_pos = m_index->tail - (n - 1);
|
||||
const int end_pos = idx_buff.tail - (n - 1);
|
||||
//Need to check if it's already drawn at this vector with this setup, if it has, it means one of the other draws might be drawing over it, which is a bad time for us, so best check.
|
||||
for (int j = 0; j < end_pos; j+=n)
|
||||
{
|
||||
if (v[m_index->buff[j]].XYZ.X == m_v.XYZ.X && v[m_index->buff[j]].XYZ.Y == m_v.XYZ.Y)
|
||||
if (v[idx_buff.buff[j]].XYZ.X == m_v.XYZ.X && v[idx_buff.buff[j]].XYZ.Y == m_v.XYZ.Y)
|
||||
{
|
||||
int min_point = std::max(j - 2, 0);
|
||||
int match = 0;
|
||||
@@ -5841,9 +5849,9 @@ bool GSState::CheckOverlapVerts(u32 n)
|
||||
if (k == j)
|
||||
continue;
|
||||
|
||||
if (v[m_index->buff[k]].XYZ.X == v[m_vertex->tail - 2].XYZ.X && v[m_index->buff[k]].XYZ.Y == v[m_vertex->tail - 2].XYZ.Y)
|
||||
if (v[idx_buff.buff[k]].XYZ.X == v[vtx_buff.tail - 2].XYZ.X && v[idx_buff.buff[k]].XYZ.Y == v[vtx_buff.tail - 2].XYZ.Y)
|
||||
match |= 1;
|
||||
if (v[m_index->buff[k]].XYZ.X == v[m_vertex->tail - 1].XYZ.X && v[m_index->buff[k]].XYZ.Y == v[m_vertex->tail - 1].XYZ.Y)
|
||||
if (v[idx_buff.buff[k]].XYZ.X == v[vtx_buff.tail - 1].XYZ.X && v[idx_buff.buff[k]].XYZ.Y == v[vtx_buff.tail - 1].XYZ.Y)
|
||||
match |= 2;
|
||||
}
|
||||
|
||||
@@ -5861,28 +5869,30 @@ __forceinline void GSState::VertexKick(u32 skip)
|
||||
{
|
||||
constexpr u32 n = NumIndicesForPrim(prim);
|
||||
constexpr int primclass = GSUtil::GetPrimClass(prim);
|
||||
GSVertexBuff& vtx_buff = *m_vertex;
|
||||
GSIndexBuff& idx_buff = *m_index;
|
||||
static_assert(n > 0);
|
||||
|
||||
pxAssert(m_vertex->tail < m_vertex->maxcount + 3);
|
||||
pxAssert(vtx_buff.tail < vtx_buff. maxcount + 3);
|
||||
|
||||
if constexpr (prim == GS_INVALID)
|
||||
{
|
||||
m_vertex->tail = m_vertex->head;
|
||||
vtx_buff.tail = vtx_buff.head;
|
||||
return;
|
||||
}
|
||||
|
||||
if (CheckOverlapVerts(n))
|
||||
Flush(CONTEXTCHANGE);
|
||||
if (GSConfig.UserHacks_DrawBuffering)
|
||||
if (CheckOverlapVerts(n))
|
||||
Flush(CONTEXTCHANGE);
|
||||
|
||||
if (auto_flush && skip == 0 && m_index->tail > 0 && ((m_vertex->tail + 1) - m_vertex->head) >= n)
|
||||
if (auto_flush && skip == 0 && idx_buff.tail > 0 && ((vtx_buff.tail + 1) - vtx_buff.head) >= n)
|
||||
{
|
||||
HandleAutoFlush<prim>();
|
||||
}
|
||||
|
||||
u32 head = m_vertex->head;
|
||||
u32 tail = m_vertex->tail;
|
||||
u32 next = m_vertex->next;
|
||||
u32 xy_tail = m_vertex->xy_tail;
|
||||
u32 head = vtx_buff.head;
|
||||
u32 tail = vtx_buff.tail;
|
||||
u32 next = vtx_buff.next;
|
||||
u32 xy_tail = vtx_buff.xy_tail;
|
||||
|
||||
if (GSIsHardwareRenderer() && GSLocalMemory::m_psm[m_context->ZBUF.PSM].bpp == 32)
|
||||
{
|
||||
@@ -5897,7 +5907,7 @@ __forceinline void GSState::VertexKick(u32 skip)
|
||||
const GSVector4i new_v0(m_v.m[0]);
|
||||
const GSVector4i new_v1(m_v.m[1]);
|
||||
|
||||
GSVector4i* RESTRICT tailptr = (GSVector4i*)&m_vertex->buff[tail];
|
||||
GSVector4i* RESTRICT tailptr = (GSVector4i*)&vtx_buff.buff[tail];
|
||||
|
||||
tailptr[0] = new_v0;
|
||||
tailptr[1] = new_v1;
|
||||
@@ -5905,41 +5915,29 @@ __forceinline void GSState::VertexKick(u32 skip)
|
||||
// We maintain the X/Y coordinates for the last 4 vertices, as well as the head for triangle fans, so we can compute
|
||||
// the min/max, and cull degenerate triangles, which saves draws in some cases. Why 4? Mod 4 is cheaper than Mod 3.
|
||||
const GSVector4i xy = new_v1.xxxx().u16to32().sub32(m_xyof);
|
||||
m_vertex->xy[xy_tail & 3] = xy;
|
||||
vtx_buff.xy[xy_tail & 3] = xy;
|
||||
|
||||
// Backup head for triangle fans so we can read it later, otherwise it'll get lost after the 4th vertex.
|
||||
if (prim == GS_TRIANGLEFAN && tail == head)
|
||||
m_vertex->xyhead = xy;
|
||||
vtx_buff.xyhead = xy;
|
||||
|
||||
m_vertex->tail = ++tail;
|
||||
m_vertex->xy_tail = ++xy_tail;
|
||||
vtx_buff.tail = ++tail;
|
||||
vtx_buff.xy_tail = ++xy_tail;
|
||||
|
||||
const u32 m = tail - head;
|
||||
|
||||
if (m < n)
|
||||
return;
|
||||
|
||||
if (m_index->tail == 0/* && ((m_backed_up_ctx != m_env.PRIM.CTXT) || m_dirty_gs_regs)*/)
|
||||
{
|
||||
const int ctx = m_env.PRIM.CTXT;
|
||||
std::memcpy(&m_prev_env, &m_env, 88);
|
||||
std::memcpy(&m_prev_env.CTXT[ctx], &m_env.CTXT[ctx], 96);
|
||||
std::memcpy(&m_prev_env.CTXT[ctx].offset, &m_env.CTXT[ctx].offset, sizeof(m_env.CTXT[ctx].offset));
|
||||
std::memcpy(&m_prev_env.CTXT[ctx].scissor, &m_env.CTXT[ctx].scissor, sizeof(m_env.CTXT[ctx].scissor));
|
||||
m_dirty_gs_regs = 0;
|
||||
m_backed_up_ctx = m_env.PRIM.CTXT;
|
||||
SetDrawBufferEnv();
|
||||
}
|
||||
|
||||
// Skip draws when scissor is out of range (i.e. bottom-right is less than top-left), since everything will get clipped.
|
||||
skip |= static_cast<u32>(m_scissor_invalid);
|
||||
|
||||
GSVector4i bbox;
|
||||
if (skip == 0)
|
||||
{
|
||||
const GSVector4i v0 = m_vertex->xy[(xy_tail - 1) & 3];
|
||||
const GSVector4i v1 = m_vertex->xy[(xy_tail - 2) & 3];
|
||||
const GSVector4i v2 = (prim == GS_TRIANGLEFAN) ? m_vertex->xyhead : m_vertex->xy[(xy_tail - 3) & 3];
|
||||
const GSVector4i v0 = vtx_buff.xy[(xy_tail - 1) & 3];
|
||||
const GSVector4i v1 = vtx_buff.xy[(xy_tail - 2) & 3];
|
||||
const GSVector4i v2 = (prim == GS_TRIANGLEFAN) ? vtx_buff.xyhead : vtx_buff.xy[(xy_tail - 3) & 3];
|
||||
|
||||
if constexpr (n == 1)
|
||||
{
|
||||
@@ -6004,14 +6002,14 @@ __forceinline void GSState::VertexKick(u32 skip)
|
||||
case GS_LINELIST:
|
||||
case GS_TRIANGLELIST:
|
||||
case GS_SPRITE:
|
||||
m_vertex->tail = head; // no need to check or grow the buffer length
|
||||
vtx_buff.tail = head; // no need to check or grow the buffer length
|
||||
break;
|
||||
case GS_LINESTRIP:
|
||||
case GS_TRIANGLESTRIP:
|
||||
m_vertex->head = head + 1;
|
||||
vtx_buff.head = head + 1;
|
||||
[[fallthrough]];
|
||||
case GS_TRIANGLEFAN:
|
||||
if (tail >= m_vertex->maxcount)
|
||||
if (tail >= vtx_buff.maxcount)
|
||||
GrowVertexBuffer(); // in case too many vertices were skipped
|
||||
break;
|
||||
default:
|
||||
@@ -6021,71 +6019,85 @@ __forceinline void GSState::VertexKick(u32 skip)
|
||||
return;
|
||||
}
|
||||
|
||||
if (tail >= m_vertex->maxcount)
|
||||
if (idx_buff.tail == 0 /* && ((m_backed_up_ctx != m_env.PRIM.CTXT) || m_dirty_gs_regs)*/)
|
||||
{
|
||||
const int ctx = m_env.PRIM.CTXT;
|
||||
std::memcpy(&m_prev_env, &m_env, 88);
|
||||
std::memcpy(&m_prev_env.CTXT[ctx], &m_env.CTXT[ctx], 96);
|
||||
std::memcpy(&m_prev_env.CTXT[ctx].offset, &m_env.CTXT[ctx].offset, sizeof(m_env.CTXT[ctx].offset));
|
||||
std::memcpy(&m_prev_env.CTXT[ctx].scissor, &m_env.CTXT[ctx].scissor, sizeof(m_env.CTXT[ctx].scissor));
|
||||
m_dirty_gs_regs = 0;
|
||||
m_backed_up_ctx = m_env.PRIM.CTXT;
|
||||
|
||||
if (GSConfig.UserHacks_DrawBuffering)
|
||||
SetDrawBufferEnv();
|
||||
}
|
||||
|
||||
if (tail >= vtx_buff.maxcount)
|
||||
GrowVertexBuffer();
|
||||
|
||||
u16* RESTRICT buff = &m_index->buff[m_index->tail];
|
||||
u16* RESTRICT buff = &idx_buff.buff[idx_buff.tail];
|
||||
|
||||
switch (prim)
|
||||
{
|
||||
case GS_POINTLIST:
|
||||
buff[0] = static_cast<u16>(head + 0);
|
||||
m_vertex->head = head + 1;
|
||||
m_vertex->next = head + 1;
|
||||
m_index->tail += 1;
|
||||
vtx_buff.head = head + 1;
|
||||
vtx_buff.next = head + 1;
|
||||
idx_buff.tail += 1;
|
||||
break;
|
||||
case GS_LINELIST:
|
||||
buff[0] = static_cast<u16>(head + 0);
|
||||
buff[1] = static_cast<u16>(head + 1);
|
||||
m_vertex->head = head + 2;
|
||||
m_vertex->next = head + 2;
|
||||
m_index->tail += 2;
|
||||
vtx_buff.head = head + 2;
|
||||
vtx_buff.next = head + 2;
|
||||
idx_buff.tail += 2;
|
||||
break;
|
||||
case GS_LINESTRIP:
|
||||
if (next < head)
|
||||
{
|
||||
m_vertex->buff[next + 0] = m_vertex->buff[head + 0];
|
||||
m_vertex->buff[next + 1] = m_vertex->buff[head + 1];
|
||||
vtx_buff.buff[next + 0] = vtx_buff.buff[head + 0];
|
||||
vtx_buff.buff[next + 1] = vtx_buff.buff[head + 1];
|
||||
head = next;
|
||||
m_vertex->tail = next + 2;
|
||||
vtx_buff.tail = next + 2;
|
||||
}
|
||||
buff[0] = static_cast<u16>(head + 0);
|
||||
buff[1] = static_cast<u16>(head + 1);
|
||||
m_vertex->head = head + 1;
|
||||
m_vertex->next = head + 2;
|
||||
m_index->tail += 2;
|
||||
vtx_buff.head = head + 1;
|
||||
vtx_buff.next = head + 2;
|
||||
idx_buff.tail += 2;
|
||||
break;
|
||||
case GS_TRIANGLELIST:
|
||||
buff[0] = static_cast<u16>(head + 0);
|
||||
buff[1] = static_cast<u16>(head + 1);
|
||||
buff[2] = static_cast<u16>(head + 2);
|
||||
m_vertex->head = head + 3;
|
||||
m_vertex->next = head + 3;
|
||||
m_index->tail += 3;
|
||||
vtx_buff.head = head + 3;
|
||||
vtx_buff.next = head + 3;
|
||||
idx_buff.tail += 3;
|
||||
break;
|
||||
case GS_TRIANGLESTRIP:
|
||||
if (next < head)
|
||||
{
|
||||
m_vertex->buff[next + 0] = m_vertex->buff[head + 0];
|
||||
m_vertex->buff[next + 1] = m_vertex->buff[head + 1];
|
||||
m_vertex->buff[next + 2] = m_vertex->buff[head + 2];
|
||||
vtx_buff.buff[next + 0] = vtx_buff.buff[head + 0];
|
||||
vtx_buff.buff[next + 1] = vtx_buff.buff[head + 1];
|
||||
vtx_buff.buff[next + 2] = vtx_buff.buff[head + 2];
|
||||
head = next;
|
||||
m_vertex->tail = next + 3;
|
||||
vtx_buff.tail = next + 3;
|
||||
}
|
||||
buff[0] = static_cast<u16>(head + 0);
|
||||
buff[1] = static_cast<u16>(head + 1);
|
||||
buff[2] = static_cast<u16>(head + 2);
|
||||
m_vertex->head = head + 1;
|
||||
m_vertex->next = head + 3;
|
||||
m_index->tail += 3;
|
||||
vtx_buff.head = head + 1;
|
||||
vtx_buff.next = head + 3;
|
||||
idx_buff.tail += 3;
|
||||
break;
|
||||
case GS_TRIANGLEFAN:
|
||||
// TODO: remove gaps, next == head && head < tail - 3 || next > head && next < tail - 2 (very rare)
|
||||
buff[0] = static_cast<u16>(head + 0);
|
||||
buff[1] = static_cast<u16>(tail - 2);
|
||||
buff[2] = static_cast<u16>(tail - 1);
|
||||
m_vertex->next = tail;
|
||||
m_index->tail += 3;
|
||||
vtx_buff.next = tail;
|
||||
idx_buff.tail += 3;
|
||||
break;
|
||||
case GS_SPRITE:
|
||||
buff[0] = static_cast<u16>(head + 0);
|
||||
@@ -6093,11 +6105,11 @@ __forceinline void GSState::VertexKick(u32 skip)
|
||||
|
||||
// Update the first vert's Q for ease of doing Autoflush
|
||||
if (!m_env.PRIM.FST)
|
||||
m_vertex->buff[buff[0]].RGBAQ.Q = m_vertex->buff[buff[1]].RGBAQ.Q;
|
||||
vtx_buff.buff[buff[0]].RGBAQ.Q = vtx_buff.buff[buff[1]].RGBAQ.Q;
|
||||
|
||||
m_vertex->head = head + 2;
|
||||
m_vertex->next = head + 2;
|
||||
m_index->tail += 2;
|
||||
vtx_buff.head = head + 2;
|
||||
vtx_buff.next = head + 2;
|
||||
idx_buff.tail += 2;
|
||||
break;
|
||||
default:
|
||||
ASSUME(0);
|
||||
@@ -6105,14 +6117,14 @@ __forceinline void GSState::VertexKick(u32 skip)
|
||||
|
||||
// Update rectangle for the current draw. Needs exclusive endpoints.
|
||||
const GSVector4i draw_rect = bbox.sra32<4>() + GSVector4i(0, 0, 1, 1);
|
||||
if (m_index->tail != n)
|
||||
if (idx_buff.tail != n)
|
||||
temp_draw_rect = temp_draw_rect.runion(draw_rect);
|
||||
else
|
||||
temp_draw_rect = draw_rect;
|
||||
temp_draw_rect = temp_draw_rect.rintersect(m_context->scissor.in);
|
||||
|
||||
constexpr u32 max_vertices = MaxVerticesForPrim(prim);
|
||||
if (max_vertices != 0 && m_vertex->tail >= max_vertices)
|
||||
if (max_vertices != 0 && vtx_buff.tail >= max_vertices)
|
||||
Flush(VERTEXCOUNT);
|
||||
}
|
||||
|
||||
@@ -6274,7 +6286,6 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
|
||||
const GSVector4i scissored_rc(int_rc.rintersect(m_context->scissor.in));
|
||||
if (!int_rc.eq(scissored_rc))
|
||||
{
|
||||
|
||||
const GSVertex* vert_first = &m_vertex->buff[m_index->buff[0]];
|
||||
const GSVertex* vert_second = &m_vertex->buff[m_index->buff[1]];
|
||||
const GSVertex* vert_third = &m_vertex->buff[m_index->buff[2]];
|
||||
|
||||
+1
-1
@@ -506,7 +506,7 @@ public:
|
||||
|
||||
virtual void Move();
|
||||
|
||||
GSVector4i GetTEX0Rect(GSDrawingContext prev_ctx);
|
||||
GSVector4i GetTEX0Rect(const GSDrawingContext& prev_ctx);
|
||||
void CheckWriteOverlap(bool req_write, bool req_read);
|
||||
void Write(const u8* mem, int len);
|
||||
void Read(u8* mem, int len);
|
||||
|
||||
@@ -222,7 +222,9 @@ void GSRendererHW::Lines2Sprites()
|
||||
|
||||
// each sprite converted to quad needs twice the space
|
||||
|
||||
while (m_vertex->tail * 2 > m_vertex->maxcount)
|
||||
const int tail = m_vertex->tail * 2;
|
||||
const int max_count = m_vertex->maxcount;
|
||||
while (tail > max_count)
|
||||
{
|
||||
GrowVertexBuffer();
|
||||
}
|
||||
@@ -1428,7 +1430,8 @@ void GSRendererHW::MergeSprite(GSTextureCache::Source* tex)
|
||||
}
|
||||
else
|
||||
{
|
||||
for (u32 i = 2; i < (m_vertex->tail & ~1); i++)
|
||||
const u32 tail = m_vertex->tail & ~1;
|
||||
for (u32 i = 2; i < tail; i++)
|
||||
{
|
||||
bool unique_found = false;
|
||||
|
||||
@@ -1469,7 +1472,8 @@ void GSRendererHW::MergeSprite(GSTextureCache::Source* tex)
|
||||
}
|
||||
else
|
||||
{
|
||||
for (u32 i = 2; i < (m_vertex->tail & ~1); i++)
|
||||
const u32 tail = m_vertex->tail & ~1;
|
||||
for (u32 i = 2; i < tail; i++)
|
||||
{
|
||||
bool unique_found = false;
|
||||
|
||||
@@ -2235,16 +2239,16 @@ void GSRendererHW::HandleManualDeswizzle()
|
||||
// Check if it's doing manual deswizzling first (draws are 32x16), if they are, check if the Z is flat, if not,
|
||||
// we're gonna have to get creative and swap around the quandrants, but that's a TODO.
|
||||
GSVertex* v = &m_vertex->buff[0];
|
||||
|
||||
GSIndexBuff& idx_buff = *m_index;
|
||||
// Check for page quadrant and compare it to the quadrant from the verts, if it does match then we need to do correction.
|
||||
const GSVector2i page_quadrant = GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].pgs / 2;
|
||||
|
||||
if (PRIM->FST)
|
||||
{
|
||||
for (u32 i = 0; i < m_index->tail; i += 2)
|
||||
for (u32 i = 0; i < idx_buff.tail; i += 2)
|
||||
{
|
||||
const u32 index_first = m_index->buff[i];
|
||||
const u32 index_last = m_index->buff[i + 1];
|
||||
const u32 index_first = idx_buff.buff[i];
|
||||
const u32 index_last = idx_buff.buff[i + 1];
|
||||
|
||||
if ((abs((v[index_last].U) - (v[index_first].U)) >> 4) != page_quadrant.x || (abs((v[index_last].V) - (v[index_first].V)) >> 4) != page_quadrant.y)
|
||||
return;
|
||||
@@ -2252,10 +2256,10 @@ void GSRendererHW::HandleManualDeswizzle()
|
||||
}
|
||||
else
|
||||
{
|
||||
for (u32 i = 0; i < m_index->tail; i += 2)
|
||||
for (u32 i = 0; i < idx_buff.tail; i += 2)
|
||||
{
|
||||
const u32 index_first = m_index->buff[i];
|
||||
const u32 index_last = m_index->buff[i + 1];
|
||||
const u32 index_first = idx_buff.buff[i];
|
||||
const u32 index_last = idx_buff.buff[i + 1];
|
||||
const u32 x = abs(((v[index_last].ST.S / v[index_last].RGBAQ.Q) * (1 << m_context->TEX0.TW)) - ((v[index_first].ST.S / v[index_first].RGBAQ.Q) * (1 << m_context->TEX0.TW)));
|
||||
const u32 y = abs(((v[index_last].ST.T / v[index_last].RGBAQ.Q) * (1 << m_context->TEX0.TH)) - ((v[index_first].ST.T / v[index_first].RGBAQ.Q) * (1 << m_context->TEX0.TH)));
|
||||
|
||||
@@ -3830,8 +3834,9 @@ void GSRendererHW::Draw()
|
||||
if (vertical_offset || horizontal_offset)
|
||||
{
|
||||
GSVertex* v = &m_vertex->buff[0];
|
||||
const u32 tail = m_vertex->tail;
|
||||
|
||||
for (u32 i = 0; i < m_vertex->tail; i++)
|
||||
for (u32 i = 0; i < tail; i++)
|
||||
{
|
||||
v[i].XYZ.X += horizontal_offset << 4;
|
||||
v[i].XYZ.Y += vertical_offset << 4;
|
||||
@@ -4127,8 +4132,9 @@ void GSRendererHW::Draw()
|
||||
if (vertical_offset || horizontal_offset)
|
||||
{
|
||||
GSVertex* v = &m_vertex->buff[0];
|
||||
const u32 tail = m_vertex->tail;
|
||||
|
||||
for (u32 i = 0; i < m_vertex->tail; i++)
|
||||
for (u32 i = 0; i < tail; i++)
|
||||
{
|
||||
v[i].XYZ.X += horizontal_offset << 4;
|
||||
v[i].XYZ.Y += vertical_offset << 4;
|
||||
@@ -5304,33 +5310,35 @@ void GSRendererHW::Draw()
|
||||
/// Verifies assumptions we expect to hold about indices
|
||||
bool GSRendererHW::VerifyIndices()
|
||||
{
|
||||
GSIndexBuff& idx_buff = *m_index;
|
||||
|
||||
switch (m_vt.m_primclass)
|
||||
{
|
||||
case GS_SPRITE_CLASS:
|
||||
if (m_index->tail % 2 != 0)
|
||||
if (idx_buff.tail % 2 != 0)
|
||||
return false;
|
||||
[[fallthrough]];
|
||||
case GS_POINT_CLASS:
|
||||
// Expect indices to be flat increasing
|
||||
for (u32 i = 0; i < m_index->tail; i++)
|
||||
for (u32 i = 0; i < idx_buff.tail; i++)
|
||||
{
|
||||
if (m_index->buff[i] != i)
|
||||
if (idx_buff.buff[i] != i)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case GS_LINE_CLASS:
|
||||
if (m_index->tail % 2 != 0)
|
||||
if (idx_buff.tail % 2 != 0)
|
||||
return false;
|
||||
// Expect each line to be a pair next to each other
|
||||
// VS expand relies on this!
|
||||
for (u32 i = 0; i < m_index->tail; i += 2)
|
||||
for (u32 i = 0; i < idx_buff.tail; i += 2)
|
||||
{
|
||||
if (m_index->buff[i] + 1 != m_index->buff[i + 1])
|
||||
if (idx_buff.buff[i] + 1 != idx_buff.buff[i + 1])
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case GS_TRIANGLE_CLASS:
|
||||
if (m_index->tail % 3 != 0)
|
||||
if (idx_buff.tail % 3 != 0)
|
||||
return false;
|
||||
break;
|
||||
case GS_INVALID_CLASS:
|
||||
@@ -5351,15 +5359,17 @@ void GSRendererHW::HandleFlatShadedVertices()
|
||||
if (!maybe_fix_vertices || dont_fix_vertices)
|
||||
return;
|
||||
|
||||
const int n = GSUtil::GetClassVertexCount(m_vt.m_primclass);
|
||||
const u32 n = GSUtil::GetClassVertexCount(m_vt.m_primclass);
|
||||
GSVertexBuff& vtx_buff = *m_vertex;
|
||||
GSIndexBuff& idx_buff = *m_index;
|
||||
|
||||
// If all vertices of each prim have the same color there is nothing to do.
|
||||
bool prims_flat = true;
|
||||
for (u32 i = 0; i < m_index->tail; i += n)
|
||||
for (u32 i = 0; i < idx_buff.tail; i += n)
|
||||
{
|
||||
for (u32 j = 0; j < n - 1; j++)
|
||||
{
|
||||
if (m_vertex->buff[m_index->buff[i + j]].RGBAQ.U32[0] != m_vertex->buff[m_index->buff[i + n - 1]].RGBAQ.U32[0])
|
||||
if (vtx_buff.buff[idx_buff.buff[i + j]].RGBAQ.U32[0] != vtx_buff.buff[idx_buff.buff[i + n - 1]].RGBAQ.U32[0])
|
||||
{
|
||||
prims_flat = false;
|
||||
break;
|
||||
@@ -5372,21 +5382,22 @@ void GSRendererHW::HandleFlatShadedVertices()
|
||||
return;
|
||||
|
||||
// De-index the vertices using the copy buffer
|
||||
while (m_vertex->maxcount < m_index->tail)
|
||||
while (vtx_buff.maxcount < idx_buff.tail)
|
||||
GrowVertexBuffer();
|
||||
for (int i = static_cast<int>(m_index->tail) - 1; i >= 0; i--)
|
||||
|
||||
for (int i = static_cast<int>(idx_buff.tail) - 1; i >= 0; i--)
|
||||
{
|
||||
m_vertex->buff_copy[i] = m_vertex->buff[m_index->buff[i]];
|
||||
m_index->buff[i] = static_cast<u16>(i);
|
||||
vtx_buff.buff_copy[i] = vtx_buff.buff[idx_buff.buff[i]];
|
||||
idx_buff.buff[i] = static_cast<u16>(i);
|
||||
}
|
||||
std::swap(m_vertex->buff, m_vertex->buff_copy);
|
||||
m_vertex->head = m_vertex->next = m_vertex->tail = m_index->tail;
|
||||
std::swap(vtx_buff.buff, vtx_buff.buff_copy);
|
||||
vtx_buff.head = vtx_buff.next = vtx_buff.tail = idx_buff.tail;
|
||||
|
||||
// Make all vertices the same color to simplify handling in expand shaders.
|
||||
for (u32 i = 0; i < m_index->tail; i += n)
|
||||
for (u32 i = 0; i < idx_buff.tail; i += n)
|
||||
{
|
||||
for (u32 j = 0; j < n - 1; j++)
|
||||
m_vertex->buff[i + j].RGBAQ.U32[0] = m_vertex->buff[i + n - 1].RGBAQ.U32[0];
|
||||
vtx_buff.buff[i + j].RGBAQ.U32[0] = vtx_buff.buff[i + n - 1].RGBAQ.U32[0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9869,11 +9880,13 @@ bool GSRendererHW::DetectStripedDoubleClear(bool& no_rt, bool& no_ds)
|
||||
// and I could cheat and stop when we get a size that matches, but that might be a lucky misdetection, I don't wanna risk it.
|
||||
int vertex_offset = 0;
|
||||
int last_vertex = m_vertex->buff[0].XYZ.X;
|
||||
const u32 tail = m_vertex->tail;
|
||||
GSVertexBuff& vtx_buff = *m_vertex;
|
||||
|
||||
for (u32 i = 1; i < m_vertex->tail; i++)
|
||||
for (u32 i = 1; i < tail; i++)
|
||||
{
|
||||
vertex_offset = std::max(static_cast<int>((m_vertex->buff[i].XYZ.X - last_vertex) >> 4), vertex_offset);
|
||||
last_vertex = m_vertex->buff[i].XYZ.X;
|
||||
vertex_offset = std::max(static_cast<int>((vtx_buff.buff[i].XYZ.X - last_vertex) >> 4), vertex_offset);
|
||||
last_vertex = vtx_buff.buff[i].XYZ.X;
|
||||
|
||||
// Found a gap which is much bigger, no point continuing to scan.
|
||||
if (vertex_offset > strip_size)
|
||||
@@ -10888,10 +10901,13 @@ void GSRendererHW::OffsetDraw(s32 fbp_offset, s32 zbp_offset, s32 xoffset, s32 y
|
||||
|
||||
const s32 fp_xoffset = xoffset << 4;
|
||||
const s32 fp_yoffset = yoffset << 4;
|
||||
for (u32 i = 0; i < m_vertex->next; i++)
|
||||
|
||||
GSVertexBuff& vtx_buff = *m_vertex;
|
||||
|
||||
for (u32 i = 0; i < vtx_buff.next; i++)
|
||||
{
|
||||
m_vertex->buff[i].XYZ.X += fp_xoffset;
|
||||
m_vertex->buff[i].XYZ.Y += fp_yoffset;
|
||||
vtx_buff.buff[i].XYZ.X += fp_xoffset;
|
||||
vtx_buff.buff[i].XYZ.Y += fp_yoffset;
|
||||
}
|
||||
|
||||
m_vt.m_min.p.x += static_cast<float>(xoffset);
|
||||
|
||||
Reference in New Issue
Block a user