mirror of https://github.com/xemu-project/xemu.git
nv2a: Fix intermixed use of DRAW_ARRAYS and ARRAY_ELEMENTx
Co-authored-by: Matt Borgerson <contact@mborgerson.com>
This commit is contained in:
parent
daa2748a2f
commit
88409a92bf
|
@ -501,10 +501,10 @@ static const VMStateDescription vmstate_nv2a = {
|
|||
VMSTATE_UINT32(pgraph.inline_elements_length, NV2AState), // fixme
|
||||
VMSTATE_UINT32_ARRAY(pgraph.inline_elements, NV2AState, NV2A_MAX_BATCH_LENGTH),
|
||||
VMSTATE_UINT32(pgraph.inline_buffer_length, NV2AState), // fixme
|
||||
VMSTATE_UINT32(pgraph.draw_arrays_length, NV2AState), // fixme
|
||||
VMSTATE_UINT32(pgraph.draw_arrays_max_count, NV2AState), // fixme
|
||||
// GLint gl_draw_arrays_start[1250]; // fixme
|
||||
// GLsizei gl_draw_arrays_count[1250]; // fixme
|
||||
VMSTATE_UINT32(pgraph.draw_arrays_length, NV2AState),
|
||||
VMSTATE_UINT32(pgraph.draw_arrays_max_count, NV2AState),
|
||||
VMSTATE_INT32_ARRAY(pgraph.gl_draw_arrays_start, NV2AState, 1250),
|
||||
VMSTATE_INT32_ARRAY(pgraph.gl_draw_arrays_count, NV2AState, 1250),
|
||||
VMSTATE_UINT32_ARRAY(pgraph.regs, NV2AState, 0x2000),
|
||||
VMSTATE_UINT32(pmc.pending_interrupts, NV2AState),
|
||||
VMSTATE_UINT32(pmc.enabled_interrupts, NV2AState),
|
||||
|
|
|
@ -374,6 +374,7 @@ typedef struct PGRAPHState {
|
|||
unsigned int draw_arrays_min_start;
|
||||
unsigned int draw_arrays_max_count;
|
||||
/* FIXME: Unknown size, possibly endless, 1250 will do for now */
|
||||
/* Keep in sync with size used in nv2a.c */
|
||||
GLint gl_draw_arrays_start[1250];
|
||||
GLsizei gl_draw_arrays_count[1250];
|
||||
bool draw_arrays_prevent_connect;
|
||||
|
|
|
@ -1149,6 +1149,7 @@ int pgraph_method(NV2AState *d, unsigned int subchannel,
|
|||
#define LAMP(i, mthd, prm) (LAM(i, mthd) && LAP(i, prm))
|
||||
|
||||
if (method == NV097_DRAW_ARRAYS && (max_lookahead_words >= 7) &&
|
||||
pg->inline_elements_length == 0 &&
|
||||
pg->draw_arrays_length <
|
||||
(ARRAY_SIZE(pg->gl_draw_arrays_start) - 1) &&
|
||||
LAMP(0, NV097_SET_BEGIN_END, NV097_SET_BEGIN_END_OP_END) &&
|
||||
|
@ -2683,6 +2684,126 @@ DEF_METHOD_INC(NV097, SET_EYE_DIRECTION)
|
|||
pg->ltctxa_dirty[NV_IGRAPH_XF_LTCTXA_EYED] = true;
|
||||
}
|
||||
|
||||
static void pgraph_flush_draw(NV2AState *d)
|
||||
{
|
||||
PGRAPHState *pg = &d->pgraph;
|
||||
if (!(pg->color_binding || pg->zeta_binding)) {
|
||||
return;
|
||||
}
|
||||
assert(pg->shader_binding);
|
||||
|
||||
if (pg->draw_arrays_length) {
|
||||
nv2a_profile_inc_counter(NV2A_PROF_DRAW_ARRAYS);
|
||||
|
||||
NV2A_GL_DPRINTF(false, "Draw Arrays");
|
||||
|
||||
assert(pg->inline_buffer_length == 0);
|
||||
assert(pg->inline_array_length == 0);
|
||||
assert(pg->inline_elements_length == 0);
|
||||
|
||||
pgraph_bind_vertex_attributes(d, pg->draw_arrays_min_start,
|
||||
pg->draw_arrays_max_count - 1,
|
||||
false, 0,
|
||||
pg->draw_arrays_max_count - 1);
|
||||
glMultiDrawArrays(pg->shader_binding->gl_primitive_mode,
|
||||
pg->gl_draw_arrays_start,
|
||||
pg->gl_draw_arrays_count,
|
||||
pg->draw_arrays_length);
|
||||
} else if (pg->inline_elements_length) {
|
||||
nv2a_profile_inc_counter(NV2A_PROF_INLINE_ELEMENTS);
|
||||
|
||||
NV2A_GL_DPRINTF(false, "Inline Elements");
|
||||
|
||||
assert(pg->inline_buffer_length == 0);
|
||||
assert(pg->inline_array_length == 0);
|
||||
|
||||
uint32_t min_element = (uint32_t)-1;
|
||||
uint32_t max_element = 0;
|
||||
for (int i=0; i < pg->inline_elements_length; i++) {
|
||||
max_element = MAX(pg->inline_elements[i], max_element);
|
||||
min_element = MIN(pg->inline_elements[i], min_element);
|
||||
}
|
||||
|
||||
pgraph_bind_vertex_attributes(
|
||||
d, min_element, max_element, false, 0,
|
||||
pg->inline_elements[pg->inline_elements_length - 1]);
|
||||
|
||||
VertexKey k;
|
||||
memset(&k, 0, sizeof(VertexKey));
|
||||
k.count = pg->inline_elements_length;
|
||||
k.gl_type = GL_UNSIGNED_INT;
|
||||
k.gl_normalize = GL_FALSE;
|
||||
k.stride = sizeof(uint32_t);
|
||||
uint64_t h = fast_hash((uint8_t*)pg->inline_elements,
|
||||
pg->inline_elements_length * 4);
|
||||
|
||||
LruNode *node = lru_lookup(&pg->element_cache, h, &k);
|
||||
VertexLruNode *found = container_of(node, VertexLruNode, node);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, found->gl_buffer);
|
||||
if (!found->initialized) {
|
||||
nv2a_profile_inc_counter(NV2A_PROF_GEOM_BUFFER_UPDATE_4);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
pg->inline_elements_length * 4,
|
||||
pg->inline_elements, GL_STATIC_DRAW);
|
||||
found->initialized = true;
|
||||
} else {
|
||||
nv2a_profile_inc_counter(NV2A_PROF_GEOM_BUFFER_UPDATE_4_NOTDIRTY);
|
||||
}
|
||||
glDrawElements(pg->shader_binding->gl_primitive_mode,
|
||||
pg->inline_elements_length, GL_UNSIGNED_INT,
|
||||
(void *)0);
|
||||
} else if (pg->inline_buffer_length) {
|
||||
nv2a_profile_inc_counter(NV2A_PROF_INLINE_BUFFERS);
|
||||
|
||||
NV2A_GL_DPRINTF(false, "Inline Buffer");
|
||||
|
||||
assert(pg->inline_array_length == 0);
|
||||
assert(pg->inline_elements_length == 0);
|
||||
|
||||
if (pg->compressed_attrs) {
|
||||
pg->compressed_attrs = 0;
|
||||
pgraph_bind_shaders(pg);
|
||||
}
|
||||
|
||||
for (int i = 0; i < NV2A_VERTEXSHADER_ATTRIBUTES; i++) {
|
||||
VertexAttribute *attr = &pg->vertex_attributes[i];
|
||||
if (attr->inline_buffer_populated) {
|
||||
nv2a_profile_inc_counter(NV2A_PROF_GEOM_BUFFER_UPDATE_3);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, attr->gl_inline_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER,
|
||||
pg->inline_buffer_length * sizeof(float) * 4,
|
||||
attr->inline_buffer, GL_STREAM_DRAW);
|
||||
glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
glEnableVertexAttribArray(i);
|
||||
attr->inline_buffer_populated = false;
|
||||
memcpy(attr->inline_value,
|
||||
attr->inline_buffer + (pg->inline_buffer_length - 1) * 4,
|
||||
sizeof(attr->inline_value));
|
||||
} else {
|
||||
glDisableVertexAttribArray(i);
|
||||
glVertexAttrib4fv(i, attr->inline_value);
|
||||
}
|
||||
}
|
||||
|
||||
glDrawArrays(pg->shader_binding->gl_primitive_mode,
|
||||
0, pg->inline_buffer_length);
|
||||
} else if (pg->inline_array_length) {
|
||||
nv2a_profile_inc_counter(NV2A_PROF_INLINE_ARRAYS);
|
||||
|
||||
NV2A_GL_DPRINTF(false, "Inline Array");
|
||||
|
||||
assert(pg->inline_buffer_length == 0);
|
||||
assert(pg->inline_elements_length == 0);
|
||||
|
||||
unsigned int index_count = pgraph_bind_inline_array(d);
|
||||
glDrawArrays(pg->shader_binding->gl_primitive_mode,
|
||||
0, index_count);
|
||||
} else {
|
||||
NV2A_GL_DPRINTF(true, "EMPTY NV097_SET_BEGIN_END");
|
||||
NV2A_UNCONFIRMED("EMPTY NV097_SET_BEGIN_END");
|
||||
}
|
||||
}
|
||||
|
||||
DEF_METHOD(NV097, SET_BEGIN_END)
|
||||
{
|
||||
uint32_t control_0 = pg->regs[NV_PGRAPH_CONTROL_0];
|
||||
|
@ -2697,130 +2818,8 @@ DEF_METHOD(NV097, SET_BEGIN_END)
|
|||
pg->regs[NV_PGRAPH_CONTROL_1] & NV_PGRAPH_CONTROL_1_STENCIL_TEST_ENABLE;
|
||||
|
||||
if (parameter == NV097_SET_BEGIN_END_OP_END) {
|
||||
|
||||
nv2a_profile_inc_counter(NV2A_PROF_BEGIN_ENDS);
|
||||
|
||||
if (!(pg->color_binding || pg->zeta_binding)) {
|
||||
// TODO: Factor out the end handling (done in PR #805).
|
||||
NV2A_GL_DGROUP_END();
|
||||
return;
|
||||
}
|
||||
|
||||
assert(pg->shader_binding);
|
||||
|
||||
if (pg->draw_arrays_length) {
|
||||
nv2a_profile_inc_counter(NV2A_PROF_DRAW_ARRAYS);
|
||||
|
||||
NV2A_GL_DPRINTF(false, "Draw Arrays");
|
||||
|
||||
assert(pg->inline_buffer_length == 0);
|
||||
assert(pg->inline_array_length == 0);
|
||||
assert(pg->inline_elements_length == 0);
|
||||
|
||||
pgraph_bind_vertex_attributes(d, pg->draw_arrays_min_start,
|
||||
pg->draw_arrays_max_count - 1,
|
||||
false, 0,
|
||||
pg->draw_arrays_max_count - 1);
|
||||
glMultiDrawArrays(pg->shader_binding->gl_primitive_mode,
|
||||
pg->gl_draw_arrays_start,
|
||||
pg->gl_draw_arrays_count,
|
||||
pg->draw_arrays_length);
|
||||
} else if (pg->inline_buffer_length) {
|
||||
nv2a_profile_inc_counter(NV2A_PROF_INLINE_BUFFERS);
|
||||
|
||||
NV2A_GL_DPRINTF(false, "Inline Buffer");
|
||||
|
||||
assert(pg->draw_arrays_length == 0);
|
||||
assert(pg->inline_array_length == 0);
|
||||
assert(pg->inline_elements_length == 0);
|
||||
|
||||
if (pg->compressed_attrs) {
|
||||
pg->compressed_attrs = 0;
|
||||
pgraph_bind_shaders(pg);
|
||||
}
|
||||
|
||||
for (int i = 0; i < NV2A_VERTEXSHADER_ATTRIBUTES; i++) {
|
||||
VertexAttribute *attr = &pg->vertex_attributes[i];
|
||||
if (attr->inline_buffer_populated) {
|
||||
nv2a_profile_inc_counter(NV2A_PROF_GEOM_BUFFER_UPDATE_3);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, attr->gl_inline_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER,
|
||||
pg->inline_buffer_length * sizeof(float) * 4,
|
||||
attr->inline_buffer, GL_STREAM_DRAW);
|
||||
glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
glEnableVertexAttribArray(i);
|
||||
attr->inline_buffer_populated = false;
|
||||
memcpy(attr->inline_value,
|
||||
attr->inline_buffer + (pg->inline_buffer_length - 1) * 4,
|
||||
sizeof(attr->inline_value));
|
||||
} else {
|
||||
glDisableVertexAttribArray(i);
|
||||
glVertexAttrib4fv(i, attr->inline_value);
|
||||
}
|
||||
}
|
||||
|
||||
glDrawArrays(pg->shader_binding->gl_primitive_mode,
|
||||
0, pg->inline_buffer_length);
|
||||
} else if (pg->inline_array_length) {
|
||||
nv2a_profile_inc_counter(NV2A_PROF_INLINE_ARRAYS);
|
||||
|
||||
NV2A_GL_DPRINTF(false, "Inline Array");
|
||||
|
||||
assert(pg->draw_arrays_length == 0);
|
||||
assert(pg->inline_buffer_length == 0);
|
||||
assert(pg->inline_elements_length == 0);
|
||||
|
||||
unsigned int index_count = pgraph_bind_inline_array(d);
|
||||
glDrawArrays(pg->shader_binding->gl_primitive_mode,
|
||||
0, index_count);
|
||||
} else if (pg->inline_elements_length) {
|
||||
nv2a_profile_inc_counter(NV2A_PROF_INLINE_ELEMENTS);
|
||||
|
||||
NV2A_GL_DPRINTF(false, "Inline Elements");
|
||||
|
||||
assert(pg->draw_arrays_length == 0);
|
||||
assert(pg->inline_buffer_length == 0);
|
||||
assert(pg->inline_array_length == 0);
|
||||
|
||||
uint32_t min_element = (uint32_t)-1;
|
||||
uint32_t max_element = 0;
|
||||
for (int i=0; i < pg->inline_elements_length; i++) {
|
||||
max_element = MAX(pg->inline_elements[i], max_element);
|
||||
min_element = MIN(pg->inline_elements[i], min_element);
|
||||
}
|
||||
|
||||
pgraph_bind_vertex_attributes(
|
||||
d, min_element, max_element, false, 0,
|
||||
pg->inline_elements[pg->inline_elements_length - 1]);
|
||||
|
||||
VertexKey k;
|
||||
memset(&k, 0, sizeof(VertexKey));
|
||||
k.count = pg->inline_elements_length;
|
||||
k.gl_type = GL_UNSIGNED_INT;
|
||||
k.gl_normalize = GL_FALSE;
|
||||
k.stride = sizeof(uint32_t);
|
||||
uint64_t h = fast_hash((uint8_t*)pg->inline_elements,
|
||||
pg->inline_elements_length * 4);
|
||||
|
||||
LruNode *node = lru_lookup(&pg->element_cache, h, &k);
|
||||
VertexLruNode *found = container_of(node, VertexLruNode, node);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, found->gl_buffer);
|
||||
if (!found->initialized) {
|
||||
nv2a_profile_inc_counter(NV2A_PROF_GEOM_BUFFER_UPDATE_4);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
pg->inline_elements_length * 4,
|
||||
pg->inline_elements, GL_STATIC_DRAW);
|
||||
found->initialized = true;
|
||||
} else {
|
||||
nv2a_profile_inc_counter(NV2A_PROF_GEOM_BUFFER_UPDATE_4_NOTDIRTY);
|
||||
}
|
||||
glDrawElements(pg->shader_binding->gl_primitive_mode,
|
||||
pg->inline_elements_length, GL_UNSIGNED_INT,
|
||||
(void *)0);
|
||||
} else {
|
||||
NV2A_GL_DPRINTF(true, "EMPTY NV097_SET_BEGIN_END");
|
||||
NV2A_UNCONFIRMED("EMPTY NV097_SET_BEGIN_END");
|
||||
}
|
||||
pgraph_flush_draw(d);
|
||||
|
||||
/* End of visibility testing */
|
||||
if (pg->zpass_pixel_count_enable) {
|
||||
|
@ -2836,7 +2835,6 @@ DEF_METHOD(NV097, SET_BEGIN_END)
|
|||
pg->zeta_binding->draw_time = pg->draw_time;
|
||||
}
|
||||
|
||||
uint32_t color_write = mask_alpha | mask_red | mask_green | mask_blue;
|
||||
pgraph_set_surface_dirty(pg, color_write, depth_test || stencil_test);
|
||||
|
||||
NV2A_GL_DGROUP_END();
|
||||
|
@ -3048,6 +3046,7 @@ DEF_METHOD(NV097, SET_BEGIN_END)
|
|||
pg->draw_arrays_length = 0;
|
||||
pg->draw_arrays_min_start = -1;
|
||||
pg->draw_arrays_max_count = 0;
|
||||
pg->draw_arrays_prevent_connect = false;
|
||||
|
||||
/* Visibility testing */
|
||||
if (pg->zpass_pixel_count_enable) {
|
||||
|
@ -3197,8 +3196,35 @@ DEF_METHOD(NV097, SET_TEXTURE_SET_BUMP_ENV_OFFSET)
|
|||
pg->regs[NV_PGRAPH_BUMPOFFSET1 + slot * 4] = parameter;
|
||||
}
|
||||
|
||||
static void pgraph_expand_draw_arrays(NV2AState *d)
|
||||
{
|
||||
PGRAPHState *pg = &d->pgraph;
|
||||
GLint start = pg->gl_draw_arrays_start[pg->draw_arrays_length - 1];
|
||||
GLsizei count = pg->gl_draw_arrays_count[pg->draw_arrays_length - 1];
|
||||
|
||||
/* Render any previously squashed DRAW_ARRAYS calls. This case would be
|
||||
* triggered if a set of BEGIN+DA+END triplets is followed by the
|
||||
* BEGIN+DA+ARRAY_ELEMENT+... chain that caused this expansion. */
|
||||
if (pg->draw_arrays_length > 1) {
|
||||
pgraph_flush_draw(d);
|
||||
}
|
||||
|
||||
pg->draw_arrays_length = 0;
|
||||
pg->draw_arrays_min_start = -1;
|
||||
pg->draw_arrays_max_count = 0;
|
||||
pg->draw_arrays_prevent_connect = false;
|
||||
|
||||
assert((pg->inline_elements_length + count) < NV2A_MAX_BATCH_LENGTH);
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
pg->inline_elements[pg->inline_elements_length++] = start + i;
|
||||
}
|
||||
}
|
||||
|
||||
DEF_METHOD_NON_INC(NV097, ARRAY_ELEMENT16)
|
||||
{
|
||||
if (pg->draw_arrays_length) {
|
||||
pgraph_expand_draw_arrays(d);
|
||||
}
|
||||
assert(pg->inline_elements_length < NV2A_MAX_BATCH_LENGTH);
|
||||
pg->inline_elements[pg->inline_elements_length++] = parameter & 0xFFFF;
|
||||
pg->inline_elements[pg->inline_elements_length++] = parameter >> 16;
|
||||
|
@ -3206,6 +3232,9 @@ DEF_METHOD_NON_INC(NV097, ARRAY_ELEMENT16)
|
|||
|
||||
DEF_METHOD_NON_INC(NV097, ARRAY_ELEMENT32)
|
||||
{
|
||||
if (pg->draw_arrays_length) {
|
||||
pgraph_expand_draw_arrays(d);
|
||||
}
|
||||
assert(pg->inline_elements_length < NV2A_MAX_BATCH_LENGTH);
|
||||
pg->inline_elements[pg->inline_elements_length++] = parameter;
|
||||
}
|
||||
|
@ -3213,14 +3242,25 @@ DEF_METHOD_NON_INC(NV097, ARRAY_ELEMENT32)
|
|||
DEF_METHOD(NV097, DRAW_ARRAYS)
|
||||
{
|
||||
unsigned int start = GET_MASK(parameter, NV097_DRAW_ARRAYS_START_INDEX);
|
||||
unsigned int count = GET_MASK(parameter, NV097_DRAW_ARRAYS_COUNT)+1;
|
||||
unsigned int count = GET_MASK(parameter, NV097_DRAW_ARRAYS_COUNT) + 1;
|
||||
|
||||
if (pg->inline_elements_length) {
|
||||
/* FIXME: Determine HW behavior for overflow case. */
|
||||
assert((pg->inline_elements_length + count) < NV2A_MAX_BATCH_LENGTH);
|
||||
assert(!pg->draw_arrays_prevent_connect);
|
||||
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
pg->inline_elements[pg->inline_elements_length++] = start + i;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
pg->draw_arrays_min_start = MIN(pg->draw_arrays_min_start, start);
|
||||
pg->draw_arrays_max_count = MAX(pg->draw_arrays_max_count, start + count);
|
||||
|
||||
assert(pg->draw_arrays_length < ARRAY_SIZE(pg->gl_draw_arrays_start));
|
||||
|
||||
/* Attempt to connect primitives */
|
||||
/* Attempt to connect contiguous primitives */
|
||||
if (!pg->draw_arrays_prevent_connect && pg->draw_arrays_length > 0) {
|
||||
unsigned int last_start =
|
||||
pg->gl_draw_arrays_start[pg->draw_arrays_length - 1];
|
||||
|
|
Loading…
Reference in New Issue