mirror of https://github.com/PCSX2/pcsx2.git
GS: Add secondary vertex buffer for copy/modifying vertices.
Currently only used in HW renderer to fix vertices for provoking-first-vertex APIs.
This commit is contained in:
parent
14c7f959f5
commit
08ede10204
|
@ -125,6 +125,8 @@ GSState::~GSState()
|
||||||
{
|
{
|
||||||
if (m_vertex.buff)
|
if (m_vertex.buff)
|
||||||
_aligned_free(m_vertex.buff);
|
_aligned_free(m_vertex.buff);
|
||||||
|
if (m_vertex.buff_copy)
|
||||||
|
_aligned_free(m_vertex.buff_copy);
|
||||||
if (m_index.buff)
|
if (m_index.buff)
|
||||||
_aligned_free(m_index.buff);
|
_aligned_free(m_index.buff);
|
||||||
if (m_draw_vertex.buff)
|
if (m_draw_vertex.buff)
|
||||||
|
@ -2859,56 +2861,53 @@ void GSState::UpdateVertexKick()
|
||||||
void GSState::GrowVertexBuffer()
|
void GSState::GrowVertexBuffer()
|
||||||
{
|
{
|
||||||
const u32 maxcount = std::max<u32>(m_vertex.maxcount * 3 / 2, 10000);
|
const u32 maxcount = std::max<u32>(m_vertex.maxcount * 3 / 2, 10000);
|
||||||
|
const u32 old_vertex_size = sizeof(GSVertex) * m_vertex.tail;
|
||||||
|
const u32 new_vertex_size = sizeof(GSVertex) * maxcount;
|
||||||
|
const u32 old_index_size = sizeof(u16) * m_index.tail;
|
||||||
|
const u32 new_index_size = sizeof(u16) * maxcount * 6; // Worst case index list is a list of points with vs expansion, 6 indices per point
|
||||||
|
|
||||||
GSVertex* vertex = static_cast<GSVertex*>(_aligned_malloc(sizeof(GSVertex) * maxcount, 32));
|
// Structure describing buffers to reallocate
|
||||||
GSVertex* draw_vertex = static_cast<GSVertex*>(_aligned_malloc(sizeof(GSVertex) * maxcount, 32));
|
struct AllocDesc
|
||||||
// Worst case index list is a list of points with vs expansion, 6 indices per point
|
|
||||||
u16* index = static_cast<u16*>(_aligned_malloc(sizeof(u16) * maxcount * 6, 32));
|
|
||||||
u16* draw_index = static_cast<u16*>(_aligned_malloc(sizeof(u16) * maxcount * 6, 32));
|
|
||||||
|
|
||||||
if (!vertex || !index)
|
|
||||||
{
|
{
|
||||||
const u32 vert_byte_count = sizeof(GSVertex) * maxcount;
|
void** pbuff;
|
||||||
const u32 idx_byte_count = sizeof(u16) * maxcount * 3;
|
u32 old_size;
|
||||||
|
u32 new_size;
|
||||||
|
};
|
||||||
|
std::vector<AllocDesc> alloc_desc = {
|
||||||
|
{reinterpret_cast<void**>(&m_vertex.buff), old_vertex_size, new_vertex_size},
|
||||||
|
// discard contents of buff_copy by setting old_size = 0
|
||||||
|
{reinterpret_cast<void**>(&m_vertex.buff_copy), 0, new_vertex_size},
|
||||||
|
{reinterpret_cast<void**>(&m_draw_vertex.buff), old_vertex_size, new_vertex_size},
|
||||||
|
{reinterpret_cast<void**>(&m_index.buff), old_index_size, new_index_size},
|
||||||
|
{reinterpret_cast<void**>(&m_draw_index.buff), old_index_size, new_index_size}
|
||||||
|
};
|
||||||
|
|
||||||
Console.Error("GS: failed to allocate %zu bytes for vertices and %zu for indices.",
|
// For logging
|
||||||
vert_byte_count, idx_byte_count);
|
u32 total_size = 0;
|
||||||
pxFailRel("Memory allocation failed");
|
for (const auto& desc : alloc_desc)
|
||||||
|
total_size += desc.new_size;
|
||||||
|
|
||||||
|
// Reallocate each of the needed buffers
|
||||||
|
for (const auto [pbuff, old_size, new_size] : alloc_desc)
|
||||||
|
{
|
||||||
|
void* new_buff = _aligned_malloc(new_size, 32);
|
||||||
|
if (!new_buff)
|
||||||
|
{
|
||||||
|
Console.Error("GS: failed to allocate %zu bytes for vertices and indices.", total_size);
|
||||||
|
pxFailRel("Memory allocation failed");
|
||||||
|
}
|
||||||
|
if (*pbuff)
|
||||||
|
{
|
||||||
|
if (old_size)
|
||||||
|
{
|
||||||
|
std::memcpy(new_buff, *pbuff, old_size);
|
||||||
|
}
|
||||||
|
_aligned_free(*pbuff);
|
||||||
|
}
|
||||||
|
*pbuff = new_buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_vertex.buff)
|
|
||||||
{
|
|
||||||
std::memcpy(vertex, m_vertex.buff, sizeof(GSVertex) * m_vertex.tail);
|
|
||||||
|
|
||||||
_aligned_free(m_vertex.buff);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_index.buff)
|
|
||||||
{
|
|
||||||
std::memcpy(index, m_index.buff, sizeof(u16) * m_index.tail);
|
|
||||||
|
|
||||||
_aligned_free(m_index.buff);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_draw_vertex.buff)
|
|
||||||
{
|
|
||||||
std::memcpy(draw_vertex, m_draw_vertex.buff, sizeof(GSVertex) * m_vertex.tail);
|
|
||||||
|
|
||||||
_aligned_free(m_draw_vertex.buff);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_draw_index.buff)
|
|
||||||
{
|
|
||||||
std::memcpy(draw_index, m_draw_index.buff, sizeof(u16) * m_index.tail);
|
|
||||||
|
|
||||||
_aligned_free(m_draw_index.buff);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_draw_vertex.buff = draw_vertex;
|
|
||||||
m_draw_index.buff = draw_index;
|
|
||||||
m_vertex.buff = vertex;
|
|
||||||
m_vertex.maxcount = maxcount - 3; // -3 to have some space at the end of the buffer before DrawingKick can grow it
|
m_vertex.maxcount = maxcount - 3; // -3 to have some space at the end of the buffer before DrawingKick can grow it
|
||||||
m_index.buff = index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GSState::TrianglesAreQuads(bool shuffle_check)
|
bool GSState::TrianglesAreQuads(bool shuffle_check)
|
||||||
|
|
|
@ -136,6 +136,7 @@ protected:
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
GSVertex* buff;
|
GSVertex* buff;
|
||||||
|
GSVertex* buff_copy; // same size buffer to copy/modify the original buffer
|
||||||
u32 head, tail, next, maxcount; // head: first vertex, tail: last vertex + 1, next: last indexed + 1
|
u32 head, tail, next, maxcount; // head: first vertex, tail: last vertex + 1, next: last indexed + 1
|
||||||
u32 xy_tail;
|
u32 xy_tail;
|
||||||
GSVector4i xy[4];
|
GSVector4i xy[4];
|
||||||
|
|
|
@ -4834,34 +4834,15 @@ void GSRendererHW::HandleProvokingVertexFirst()
|
||||||
if (first_eq_last)
|
if (first_eq_last)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// De-index the vertices either in place or by reallocating the vertex buffer.
|
// De-index the vertices using the copy buffer
|
||||||
if (m_vertex.next <= m_index.tail && m_index.tail <= m_vertex.maxcount)
|
while (m_vertex.maxcount < m_index.tail)
|
||||||
|
GrowVertexBuffer();
|
||||||
|
for (int i = static_cast<int>(m_index.tail) - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
// De-index in place
|
m_vertex.buff_copy[i] = m_vertex.buff[m_index.buff[i]];
|
||||||
for (int i = static_cast<int>(m_index.tail) - 1; i >= 0; i--)
|
m_index.buff[i] = static_cast<u16>(i);
|
||||||
{
|
|
||||||
// FIXME: This might not hold with a large triangle fan with gaps (since gaps are not
|
|
||||||
// yet removed)!
|
|
||||||
pxAssert(m_index.buff[i] <= i); // At any point, there can never be more vertices than indices
|
|
||||||
m_vertex.buff[i] = m_vertex.buff[m_index.buff[i]];
|
|
||||||
m_index.buff[i] = static_cast<u16>(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Reallocate the vertex buffer
|
|
||||||
m_vertex.maxcount = std::max(m_vertex.maxcount, m_index.tail);
|
|
||||||
GSVertex* vert_buff = static_cast<GSVertex*>(_aligned_malloc(sizeof(GSVertex) * m_vertex.maxcount, 32));
|
|
||||||
|
|
||||||
// De-index and copy the vertices
|
|
||||||
for (u32 i = 0; i < m_index.tail; i++)
|
|
||||||
{
|
|
||||||
vert_buff[i] = m_vertex.buff[m_index.buff[i]];
|
|
||||||
m_index.buff[i] = static_cast<u16>(i);
|
|
||||||
}
|
|
||||||
std::swap(vert_buff, m_vertex.buff);
|
|
||||||
_aligned_free(vert_buff);
|
|
||||||
}
|
}
|
||||||
|
std::swap(m_vertex.buff, m_vertex.buff_copy);
|
||||||
m_vertex.head = m_vertex.next = m_vertex.tail = m_index.tail;
|
m_vertex.head = m_vertex.next = m_vertex.tail = m_index.tail;
|
||||||
|
|
||||||
// Put correct color in the first vertex
|
// Put correct color in the first vertex
|
||||||
|
|
Loading…
Reference in New Issue