mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
nv2a: Move primitive rewriting to client
This commit is contained in:
committed by
izzy2lost
parent
eadaffbd50
commit
2a0b800dcd
+104
-33
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "qemu/fast-hash.h"
|
||||
#include "hw/xbox/nv2a/nv2a_int.h"
|
||||
#include "hw/xbox/nv2a/pgraph/prim_rewrite.h"
|
||||
#include "debug.h"
|
||||
#include "renderer.h"
|
||||
|
||||
@@ -401,6 +402,19 @@ void pgraph_gl_flush_draw(NV2AState *d)
|
||||
}
|
||||
assert(r->shader_binding);
|
||||
|
||||
PrimAssemblyState assembly = {
|
||||
.primitive_mode = pg->primitive_mode,
|
||||
.polygon_mode = (enum ShaderPolygonMode)GET_MASK(
|
||||
pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER),
|
||||
NV_PGRAPH_SETUPRASTER_FRONTFACEMODE),
|
||||
.last_provoking = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_3),
|
||||
NV_PGRAPH_CONTROL_3_PROVOKING_VERTEX) ==
|
||||
NV_PGRAPH_CONTROL_3_PROVOKING_VERTEX_LAST,
|
||||
.flat_shading = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_3),
|
||||
NV_PGRAPH_CONTROL_3_SHADEMODE) ==
|
||||
NV_PGRAPH_CONTROL_3_SHADEMODE_FLAT,
|
||||
};
|
||||
|
||||
if (pg->draw_arrays_length) {
|
||||
NV2A_GL_DPRINTF(false, "Draw Arrays");
|
||||
nv2a_profile_inc_counter(NV2A_PROF_DRAW_ARRAYS);
|
||||
@@ -412,51 +426,83 @@ void pgraph_gl_flush_draw(NV2AState *d)
|
||||
pg->draw_arrays_max_count - 1,
|
||||
false, 0,
|
||||
pg->draw_arrays_max_count - 1);
|
||||
glMultiDrawArrays(r->shader_binding->gl_primitive_mode,
|
||||
pg->draw_arrays_start,
|
||||
pg->draw_arrays_count,
|
||||
pg->draw_arrays_length);
|
||||
|
||||
PrimRewrite prim_rw = pgraph_prim_rewrite_ranges(
|
||||
&r->prim_rewrite_buf, assembly, pg->draw_arrays_start,
|
||||
pg->draw_arrays_count, pg->draw_arrays_length);
|
||||
|
||||
if (prim_rw.num_indices > 0) {
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, r->gl_prim_rewrite_buffer);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
prim_rw.num_indices * sizeof(uint32_t),
|
||||
prim_rw.indices, GL_STREAM_DRAW);
|
||||
glDrawElements(r->shader_binding->gl_primitive_mode,
|
||||
prim_rw.num_indices, GL_UNSIGNED_INT, (void *)0);
|
||||
} else {
|
||||
glMultiDrawArrays(r->shader_binding->gl_primitive_mode,
|
||||
pg->draw_arrays_start, pg->draw_arrays_count,
|
||||
pg->draw_arrays_length);
|
||||
}
|
||||
} else if (pg->inline_elements_length) {
|
||||
NV2A_GL_DPRINTF(false, "Inline Elements");
|
||||
nv2a_profile_inc_counter(NV2A_PROF_INLINE_ELEMENTS);
|
||||
assert(pg->inline_buffer_length == 0);
|
||||
assert(pg->inline_array_length == 0);
|
||||
|
||||
uint32_t *draw_indices = pg->inline_elements;
|
||||
unsigned int draw_index_count = pg->inline_elements_length;
|
||||
PrimRewrite prim_rw = pgraph_prim_rewrite_indexed(
|
||||
&r->prim_rewrite_buf, assembly, pg->inline_elements,
|
||||
pg->inline_elements_length);
|
||||
if (prim_rw.num_indices > 0) {
|
||||
draw_indices = prim_rw.indices;
|
||||
draw_index_count = prim_rw.num_indices;
|
||||
}
|
||||
|
||||
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);
|
||||
for (unsigned int i = 0; i < draw_index_count; i++) {
|
||||
max_element = MAX(draw_indices[i], max_element);
|
||||
min_element = MIN(draw_indices[i], min_element);
|
||||
}
|
||||
|
||||
pgraph_gl_bind_vertex_attributes(
|
||||
d, min_element, max_element, false, 0,
|
||||
pg->inline_elements[pg->inline_elements_length - 1]);
|
||||
draw_indices[draw_index_count - 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(&r->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);
|
||||
if (prim_rw.num_indices > 0) {
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, r->gl_prim_rewrite_buffer);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
pg->inline_elements_length * 4,
|
||||
pg->inline_elements, GL_STATIC_DRAW);
|
||||
found->initialized = true;
|
||||
draw_index_count * sizeof(uint32_t), draw_indices,
|
||||
GL_STREAM_DRAW);
|
||||
glDrawElements(r->shader_binding->gl_primitive_mode,
|
||||
draw_index_count, GL_UNSIGNED_INT, (void *)0);
|
||||
} else {
|
||||
nv2a_profile_inc_counter(NV2A_PROF_GEOM_BUFFER_UPDATE_4_NOTDIRTY);
|
||||
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(&r->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(r->shader_binding->gl_primitive_mode,
|
||||
pg->inline_elements_length, GL_UNSIGNED_INT,
|
||||
(void *)0);
|
||||
}
|
||||
glDrawElements(r->shader_binding->gl_primitive_mode,
|
||||
pg->inline_elements_length, GL_UNSIGNED_INT,
|
||||
(void *)0);
|
||||
} else if (pg->inline_buffer_length) {
|
||||
NV2A_GL_DPRINTF(false, "Inline Buffer");
|
||||
nv2a_profile_inc_counter(NV2A_PROF_INLINE_BUFFERS);
|
||||
@@ -487,15 +533,40 @@ void pgraph_gl_flush_draw(NV2AState *d)
|
||||
}
|
||||
}
|
||||
|
||||
glDrawArrays(r->shader_binding->gl_primitive_mode,
|
||||
0, pg->inline_buffer_length);
|
||||
PrimRewrite prim_rw = pgraph_prim_rewrite_sequential(
|
||||
&r->prim_rewrite_buf, assembly, 0, pg->inline_buffer_length);
|
||||
|
||||
if (prim_rw.num_indices > 0) {
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, r->gl_prim_rewrite_buffer);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
prim_rw.num_indices * sizeof(uint32_t),
|
||||
prim_rw.indices, GL_STREAM_DRAW);
|
||||
glDrawElements(r->shader_binding->gl_primitive_mode,
|
||||
prim_rw.num_indices, GL_UNSIGNED_INT, (void *)0);
|
||||
} else {
|
||||
glDrawArrays(r->shader_binding->gl_primitive_mode,
|
||||
0, pg->inline_buffer_length);
|
||||
}
|
||||
} else if (pg->inline_array_length) {
|
||||
NV2A_GL_DPRINTF(false, "Inline Array");
|
||||
nv2a_profile_inc_counter(NV2A_PROF_INLINE_ARRAYS);
|
||||
|
||||
unsigned int index_count = pgraph_gl_bind_inline_array(d);
|
||||
glDrawArrays(r->shader_binding->gl_primitive_mode,
|
||||
0, index_count);
|
||||
|
||||
PrimRewrite prim_rw = pgraph_prim_rewrite_sequential(
|
||||
&r->prim_rewrite_buf, assembly, 0, index_count);
|
||||
|
||||
if (prim_rw.num_indices > 0) {
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, r->gl_prim_rewrite_buffer);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
||||
prim_rw.num_indices * sizeof(uint32_t),
|
||||
prim_rw.indices, GL_STREAM_DRAW);
|
||||
glDrawElements(r->shader_binding->gl_primitive_mode,
|
||||
prim_rw.num_indices, GL_UNSIGNED_INT, (void *)0);
|
||||
} else {
|
||||
glDrawArrays(r->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");
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "qemu/lru.h"
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/xbox/nv2a/pgraph/prim_rewrite.h"
|
||||
|
||||
#include "hw/xbox/nv2a/nv2a_int.h"
|
||||
#include "hw/xbox/nv2a/nv2a_regs.h"
|
||||
@@ -182,6 +183,8 @@ typedef struct PGRAPHGLState {
|
||||
GLuint gl_memory_buffer;
|
||||
GLuint gl_vertex_array;
|
||||
GLuint gl_inline_buffer[NV2A_VERTEXSHADER_ATTRIBUTES];
|
||||
GLuint gl_prim_rewrite_buffer;
|
||||
PrimRewriteBuf prim_rewrite_buf;
|
||||
|
||||
QTAILQ_HEAD(, SurfaceBinding) surfaces;
|
||||
SurfaceBinding *color_binding, *zeta_binding;
|
||||
|
||||
@@ -29,27 +29,12 @@
|
||||
#include "debug.h"
|
||||
#include "renderer.h"
|
||||
|
||||
static GLenum get_gl_primitive_mode(enum ShaderPolygonMode polygon_mode, enum ShaderPrimitiveMode primitive_mode)
|
||||
static GLenum get_gl_primitive_mode(enum ShaderPrimitiveMode primitive_mode)
|
||||
{
|
||||
switch (primitive_mode) {
|
||||
case PRIM_TYPE_POINTS: return GL_POINTS;
|
||||
case PRIM_TYPE_LINES: return GL_LINES;
|
||||
case PRIM_TYPE_LINE_LOOP: return GL_LINE_LOOP;
|
||||
case PRIM_TYPE_LINE_STRIP: return GL_LINE_STRIP;
|
||||
case PRIM_TYPE_TRIANGLES: return GL_TRIANGLES;
|
||||
case PRIM_TYPE_TRIANGLE_STRIP: return GL_TRIANGLE_STRIP;
|
||||
case PRIM_TYPE_TRIANGLE_FAN: return GL_TRIANGLE_FAN;
|
||||
case PRIM_TYPE_QUADS: return GL_LINES_ADJACENCY;
|
||||
case PRIM_TYPE_QUAD_STRIP: return GL_LINE_STRIP_ADJACENCY;
|
||||
case PRIM_TYPE_POLYGON:
|
||||
if (polygon_mode == POLY_MODE_LINE) {
|
||||
return GL_LINE_LOOP;
|
||||
} else if (polygon_mode == POLY_MODE_FILL) {
|
||||
return GL_TRIANGLE_FAN;
|
||||
}
|
||||
|
||||
assert(!"PRIM_TYPE_POLYGON with invalid polygon_mode");
|
||||
return 0;
|
||||
default:
|
||||
assert(!"Invalid primitive_mode");
|
||||
return 0;
|
||||
@@ -244,8 +229,8 @@ static void generate_shaders(PGRAPHGLState *r, ShaderBinding *binding)
|
||||
glUseProgram(program);
|
||||
|
||||
binding->gl_program = program;
|
||||
binding->gl_primitive_mode = get_gl_primitive_mode(
|
||||
state->geom.polygon_front_mode, state->geom.primitive_mode);
|
||||
binding->gl_primitive_mode =
|
||||
get_gl_primitive_mode(state->geom.primitive_mode);
|
||||
binding->initialized = true;
|
||||
|
||||
set_texture_sampler_uniforms(binding);
|
||||
@@ -359,8 +344,7 @@ bool pgraph_gl_shader_load_from_memory(ShaderBinding *binding)
|
||||
binding->program = NULL;
|
||||
binding->gl_program = gl_program;
|
||||
binding->gl_primitive_mode =
|
||||
get_gl_primitive_mode(binding->state.geom.polygon_front_mode,
|
||||
binding->state.geom.primitive_mode);
|
||||
get_gl_primitive_mode(binding->state.geom.primitive_mode);
|
||||
binding->initialized = true;
|
||||
|
||||
set_texture_sampler_uniforms(binding);
|
||||
|
||||
@@ -271,6 +271,8 @@ void pgraph_gl_init_buffers(NV2AState *d)
|
||||
|
||||
glGenBuffers(NV2A_VERTEXSHADER_ATTRIBUTES, r->gl_inline_buffer);
|
||||
glGenBuffers(1, &r->gl_inline_array_buffer);
|
||||
glGenBuffers(1, &r->gl_prim_rewrite_buffer);
|
||||
pgraph_prim_rewrite_init(&r->prim_rewrite_buf);
|
||||
|
||||
glGenBuffers(1, &r->gl_memory_buffer);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, r->gl_memory_buffer);
|
||||
@@ -303,6 +305,10 @@ void pgraph_gl_finalize_buffers(PGRAPHState *pg)
|
||||
glDeleteBuffers(1, &r->gl_inline_array_buffer);
|
||||
r->gl_inline_array_buffer = 0;
|
||||
|
||||
glDeleteBuffers(1, &r->gl_prim_rewrite_buffer);
|
||||
r->gl_prim_rewrite_buffer = 0;
|
||||
pgraph_prim_rewrite_finalize(&r->prim_rewrite_buf);
|
||||
|
||||
glDeleteBuffers(1, &r->gl_memory_buffer);
|
||||
r->gl_memory_buffer = 0;
|
||||
|
||||
|
||||
+17
-235
@@ -21,12 +21,11 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/xbox/nv2a/pgraph/pgraph.h"
|
||||
#include "hw/xbox/nv2a/pgraph/prim_rewrite.h"
|
||||
#include "geom.h"
|
||||
|
||||
void pgraph_glsl_set_geom_state(PGRAPHState *pg, GeomState *state)
|
||||
{
|
||||
state->primitive_mode = (enum ShaderPrimitiveMode)pg->primitive_mode;
|
||||
|
||||
state->polygon_front_mode = (enum ShaderPolygonMode)GET_MASK(
|
||||
pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER),
|
||||
NV_PGRAPH_SETUPRASTER_FRONTFACEMODE);
|
||||
@@ -34,75 +33,26 @@ void pgraph_glsl_set_geom_state(PGRAPHState *pg, GeomState *state)
|
||||
pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER),
|
||||
NV_PGRAPH_SETUPRASTER_BACKFACEMODE);
|
||||
|
||||
state->primitive_mode = pgraph_prim_rewrite_get_output_mode(
|
||||
(enum ShaderPrimitiveMode)pg->primitive_mode,
|
||||
state->polygon_front_mode);
|
||||
|
||||
state->smooth_shading = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_3),
|
||||
NV_PGRAPH_CONTROL_3_SHADEMODE) ==
|
||||
NV_PGRAPH_CONTROL_3_SHADEMODE_SMOOTH;
|
||||
|
||||
state->first_vertex_is_provoking =
|
||||
GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_3),
|
||||
NV_PGRAPH_CONTROL_3_PROVOKING_VERTEX) ==
|
||||
NV_PGRAPH_CONTROL_3_PROVOKING_VERTEX_FIRST;
|
||||
|
||||
state->z_perspective = pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0) &
|
||||
NV_PGRAPH_CONTROL_0_Z_PERSPECTIVE_ENABLE;
|
||||
|
||||
if (pg->renderer->ops.get_gpu_properties) {
|
||||
GPUProperties *gpu_props = pg->renderer->ops.get_gpu_properties();
|
||||
|
||||
switch (state->primitive_mode) {
|
||||
case PRIM_TYPE_TRIANGLES:
|
||||
state->tri_rot0 = gpu_props->geom_shader_winding.tri;
|
||||
state->tri_rot1 = state->tri_rot0;
|
||||
break;
|
||||
case PRIM_TYPE_TRIANGLE_STRIP:
|
||||
state->tri_rot0 = gpu_props->geom_shader_winding.tri_strip0;
|
||||
state->tri_rot1 = gpu_props->geom_shader_winding.tri_strip1;
|
||||
break;
|
||||
case PRIM_TYPE_TRIANGLE_FAN:
|
||||
case PRIM_TYPE_POLYGON:
|
||||
state->tri_rot0 = gpu_props->geom_shader_winding.tri_fan;
|
||||
state->tri_rot1 = state->tri_rot0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char *get_vertex_order(int rot)
|
||||
{
|
||||
if (rot == 0) {
|
||||
return "ivec3(0, 1, 2)";
|
||||
} else if (rot == 1) {
|
||||
return "ivec3(2, 0, 1)";
|
||||
} else {
|
||||
return "ivec3(1, 2, 0)";
|
||||
}
|
||||
}
|
||||
|
||||
bool pgraph_glsl_need_geom(const GeomState *state)
|
||||
{
|
||||
/* FIXME: Missing support for 2-sided-poly mode */
|
||||
assert(state->polygon_front_mode == state->polygon_back_mode);
|
||||
enum ShaderPolygonMode polygon_mode = state->polygon_front_mode;
|
||||
|
||||
switch (state->primitive_mode) {
|
||||
case PRIM_TYPE_POINTS:
|
||||
return false;
|
||||
case PRIM_TYPE_LINES:
|
||||
case PRIM_TYPE_LINE_LOOP:
|
||||
case PRIM_TYPE_LINE_STRIP:
|
||||
case PRIM_TYPE_TRIANGLES:
|
||||
case PRIM_TYPE_TRIANGLE_STRIP:
|
||||
case PRIM_TYPE_TRIANGLE_FAN:
|
||||
case PRIM_TYPE_QUADS:
|
||||
case PRIM_TYPE_QUAD_STRIP:
|
||||
return true;
|
||||
case PRIM_TYPE_POLYGON:
|
||||
if (polygon_mode == POLY_MODE_POINT) {
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -116,184 +66,54 @@ MString *pgraph_glsl_gen_geom(const GeomState *state, GenGeomGlslOptions opts)
|
||||
enum ShaderPolygonMode polygon_mode = state->polygon_front_mode;
|
||||
|
||||
bool need_triz = false;
|
||||
bool need_quadz = false;
|
||||
bool need_linez = false;
|
||||
const char *layout_in = NULL;
|
||||
const char *layout_out = NULL;
|
||||
const char *body = NULL;
|
||||
const char *provoking_index = "0";
|
||||
const char *provoking_index = state->smooth_shading ? "index" : "0";
|
||||
|
||||
/* TODO: frontface/backface culling for polygon modes POLY_MODE_LINE and
|
||||
* POLY_MODE_POINT.
|
||||
*/
|
||||
switch (state->primitive_mode) {
|
||||
case PRIM_TYPE_POINTS: return NULL;
|
||||
case PRIM_TYPE_LINES:
|
||||
case PRIM_TYPE_LINE_LOOP:
|
||||
case PRIM_TYPE_LINE_STRIP:
|
||||
provoking_index = state->first_vertex_is_provoking ? "0" : "1";
|
||||
need_linez = true;
|
||||
layout_in = "layout(lines) in;\n";
|
||||
layout_out = "layout(line_strip, max_vertices = 2) out;\n";
|
||||
body = " emit_line(0, 1, 0.0);\n";
|
||||
break;
|
||||
case PRIM_TYPE_TRIANGLES:
|
||||
case PRIM_TYPE_TRIANGLE_STRIP:
|
||||
case PRIM_TYPE_TRIANGLE_FAN:
|
||||
if (state->first_vertex_is_provoking) {
|
||||
provoking_index = "v[0]";
|
||||
} else if (state->primitive_mode == PRIM_TYPE_TRIANGLE_STRIP) {
|
||||
provoking_index = "v[2 - (gl_PrimitiveIDIn & 1)]";
|
||||
} else if (state->primitive_mode == PRIM_TYPE_TRIANGLE_FAN) {
|
||||
provoking_index = "v[1]";
|
||||
} else {
|
||||
provoking_index = "v[2]";
|
||||
}
|
||||
need_triz = true;
|
||||
layout_in = "layout(triangles) in;\n";
|
||||
if (polygon_mode == POLY_MODE_FILL) {
|
||||
layout_out = "layout(triangle_strip, max_vertices = 3) out;\n";
|
||||
body = " mat4 pz = calc_triz(v[0], v[1], v[2]);\n"
|
||||
" emit_vertex(v[0], pz);\n"
|
||||
" emit_vertex(v[1], pz);\n"
|
||||
" emit_vertex(v[2], pz);\n"
|
||||
body = " mat4 pz = calc_triz(0, 1, 2);\n"
|
||||
" emit_vertex(0, pz);\n"
|
||||
" emit_vertex(1, pz);\n"
|
||||
" emit_vertex(2, pz);\n"
|
||||
" EndPrimitive();\n";
|
||||
} else if (polygon_mode == POLY_MODE_LINE) {
|
||||
need_linez = true;
|
||||
layout_out = "layout(line_strip, max_vertices = 6) out;\n";
|
||||
body = " float dz = calc_triz(v[0], v[1], v[2])[3].x;\n"
|
||||
" emit_line(v[0], v[1], dz);\n"
|
||||
" emit_line(v[1], v[2], dz);\n"
|
||||
" emit_line(v[2], v[0], dz);\n";
|
||||
body = " float dz = calc_triz(0, 1, 2)[3].x;\n"
|
||||
" emit_line(0, 1, dz);\n"
|
||||
" emit_line(1, 2, dz);\n"
|
||||
" emit_line(2, 0, dz);\n";
|
||||
} else {
|
||||
assert(polygon_mode == POLY_MODE_POINT);
|
||||
layout_out = "layout(points, max_vertices = 3) out;\n";
|
||||
body = " mat4 pz = calc_triz(v[0], v[1], v[2]);\n"
|
||||
" emit_vertex(v[0], mat4(pz[0], pz[0], pz[0], pz[3]));\n"
|
||||
" EndPrimitive();\n"
|
||||
" emit_vertex(v[1], mat4(pz[1], pz[1], pz[1], pz[3]));\n"
|
||||
" EndPrimitive();\n"
|
||||
" emit_vertex(v[2], mat4(pz[2], pz[2], pz[2], pz[3]));\n"
|
||||
" EndPrimitive();\n";
|
||||
}
|
||||
break;
|
||||
case PRIM_TYPE_QUADS:
|
||||
provoking_index = "3";
|
||||
need_quadz = true;
|
||||
layout_in = "layout(lines_adjacency) in;\n";
|
||||
if (polygon_mode == POLY_MODE_FILL) {
|
||||
layout_out = "layout(triangle_strip, max_vertices = 6) out;\n";
|
||||
body = " mat4 pz, pz2;\n"
|
||||
" calc_quadz(0, 1, 2, 3, pz, pz2);\n"
|
||||
" emit_vertex(1, pz);\n"
|
||||
" emit_vertex(2, pz);\n"
|
||||
" emit_vertex(0, pz);\n"
|
||||
" EndPrimitive();\n"
|
||||
" emit_vertex(2, pz2);\n"
|
||||
" emit_vertex(3, pz2);\n"
|
||||
" emit_vertex(0, pz2);\n"
|
||||
" EndPrimitive();\n";
|
||||
} else if (polygon_mode == POLY_MODE_LINE) {
|
||||
need_linez = true;
|
||||
layout_out = "layout(line_strip, max_vertices = 8) out;\n";
|
||||
body = " mat4 pz, pzs;\n"
|
||||
" calc_quadz(0, 1, 2, 3, pz, pzs);\n"
|
||||
" emit_line(0, 1, pz[3].x);\n"
|
||||
" emit_line(1, 2, pz[3].x);\n"
|
||||
" emit_line(2, 3, pzs[3].x);\n"
|
||||
" emit_line(3, 0, pzs[3].x);\n";
|
||||
} else {
|
||||
assert(polygon_mode == POLY_MODE_POINT);
|
||||
layout_out = "layout(points, max_vertices = 4) out;\n";
|
||||
body = " mat4 pz, pz2;\n"
|
||||
" calc_quadz(0, 1, 2, 3, pz, pz2);\n"
|
||||
body = " mat4 pz = calc_triz(0, 1, 2);\n"
|
||||
" emit_vertex(0, mat4(pz[0], pz[0], pz[0], pz[3]));\n"
|
||||
" EndPrimitive();\n"
|
||||
" emit_vertex(1, mat4(pz[1], pz[1], pz[1], pz[3]));\n"
|
||||
" EndPrimitive();\n"
|
||||
" emit_vertex(2, mat4(pz[2], pz[2], pz[2], pz[3]));\n"
|
||||
" EndPrimitive();\n"
|
||||
" emit_vertex(3, mat4(pz2[2], pz2[2], pz2[2], pz2[3]));\n"
|
||||
" EndPrimitive();\n";
|
||||
}
|
||||
break;
|
||||
case PRIM_TYPE_QUAD_STRIP:
|
||||
provoking_index = "3";
|
||||
need_quadz = true;
|
||||
layout_in = "layout(lines_adjacency) in;\n";
|
||||
if (polygon_mode == POLY_MODE_FILL) {
|
||||
layout_out = "layout(triangle_strip, max_vertices = 6) out;\n";
|
||||
body = " if ((gl_PrimitiveIDIn & 1) != 0) { return; }\n"
|
||||
" mat4 pz, pz2;\n"
|
||||
" calc_quadz(2, 0, 1, 3, pz, pz2);\n"
|
||||
" emit_vertex(0, pz);\n"
|
||||
" emit_vertex(1, pz);\n"
|
||||
" emit_vertex(2, pz);\n"
|
||||
" EndPrimitive();\n"
|
||||
" emit_vertex(2, pz2);\n"
|
||||
" emit_vertex(1, pz2);\n"
|
||||
" emit_vertex(3, pz2);\n"
|
||||
" EndPrimitive();\n";
|
||||
} else if (polygon_mode == POLY_MODE_LINE) {
|
||||
need_linez = true;
|
||||
layout_out = "layout(line_strip, max_vertices = 8) out;\n";
|
||||
body = " if ((gl_PrimitiveIDIn & 1) != 0) { return; }\n"
|
||||
" mat4 pz, pzs;\n"
|
||||
" calc_quadz(2, 0, 1, 3, pz, pzs);\n"
|
||||
" emit_line(0, 1, pz[3].x);\n"
|
||||
" emit_line(1, 3, pzs[3].x);\n"
|
||||
" emit_line(3, 2, pzs[3].x);\n"
|
||||
" emit_line(2, 0, pz[3].x);\n";
|
||||
} else {
|
||||
assert(polygon_mode == POLY_MODE_POINT);
|
||||
layout_out = "layout(points, max_vertices = 4) out;\n";
|
||||
body = " if ((gl_PrimitiveIDIn & 1) != 0) { return; }\n"
|
||||
" mat4 pz, pz2;\n"
|
||||
" calc_quadz(2, 0, 1, 3, pz, pz2);\n"
|
||||
" emit_vertex(0, mat4(pz[1], pz[1], pz[1], pz[3]));\n"
|
||||
" EndPrimitive();\n"
|
||||
" emit_vertex(1, mat4(pz[2], pz[2], pz[2], pz[3]));\n"
|
||||
" EndPrimitive();\n"
|
||||
" emit_vertex(2, mat4(pz[0], pz[0], pz[0], pz[3]));\n"
|
||||
" EndPrimitive();\n"
|
||||
" emit_vertex(3, mat4(pz2[2], pz2[2], pz2[2], pz2[3]));\n"
|
||||
" EndPrimitive();\n";
|
||||
}
|
||||
break;
|
||||
case PRIM_TYPE_POLYGON:
|
||||
if (polygon_mode == POLY_MODE_FILL) {
|
||||
provoking_index = "v[2]";
|
||||
need_triz = true;
|
||||
layout_in = "layout(triangles) in;\n";
|
||||
layout_out = "layout(triangle_strip, max_vertices = 3) out;\n";
|
||||
body = " mat4 pz = calc_triz(v[0], v[1], v[2]);\n"
|
||||
" emit_vertex(v[0], pz);\n"
|
||||
" emit_vertex(v[1], pz);\n"
|
||||
" emit_vertex(v[2], pz);\n"
|
||||
" EndPrimitive();\n";
|
||||
} else if (polygon_mode == POLY_MODE_LINE) {
|
||||
provoking_index = "0";
|
||||
need_linez = true;
|
||||
/* FIXME: input here is lines and not triangles so we cannot
|
||||
* calculate triangle plane slope. Also, the first vertex of the
|
||||
* polygon is unavailable so flat shading provoking vertex is
|
||||
* wrong.
|
||||
*/
|
||||
layout_in = "layout(lines) in;\n";
|
||||
layout_out = "layout(line_strip, max_vertices = 2) out;\n";
|
||||
body = " emit_line(0, 1, 0.0);\n";
|
||||
} else {
|
||||
assert(false);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* generate a geometry shader to support deprecated primitive types */
|
||||
assert(layout_in);
|
||||
assert(layout_out);
|
||||
assert(body);
|
||||
@@ -312,34 +132,6 @@ MString *pgraph_glsl_gen_geom(const GeomState *state, GenGeomGlslOptions opts)
|
||||
pgraph_glsl_get_vtx_header(output, opts.vulkan, state->smooth_shading,
|
||||
false, false, false);
|
||||
|
||||
char vertex_order_buf[80];
|
||||
const char *vertex_order_body = "";
|
||||
|
||||
if (need_triz) {
|
||||
/* Input triangle absolute vertex order is not guaranteed by OpenGL
|
||||
* or Vulkan, only winding order is. Reorder vertices here to first
|
||||
* vertex convention which we assumed above when setting
|
||||
* provoking_index. This mostly only matters with flat shading, but
|
||||
* we reorder always to get consistent results across GPU vendors
|
||||
* regarding floating-point rounding when calculating with vtxPos0/1/2.
|
||||
*/
|
||||
mstring_append(output, "ivec3 v;\n");
|
||||
if (state->tri_rot0 == state->tri_rot1) {
|
||||
snprintf(vertex_order_buf, sizeof(vertex_order_buf), " v = %s;\n",
|
||||
get_vertex_order(state->tri_rot0));
|
||||
} else {
|
||||
snprintf(vertex_order_buf, sizeof(vertex_order_buf),
|
||||
" v = (gl_PrimitiveIDIn & 1) == 0 ? %s : %s;\n",
|
||||
get_vertex_order(state->tri_rot0),
|
||||
get_vertex_order(state->tri_rot1));
|
||||
}
|
||||
vertex_order_body = vertex_order_buf;
|
||||
}
|
||||
|
||||
if (state->smooth_shading) {
|
||||
provoking_index = "index";
|
||||
}
|
||||
|
||||
const char *point_size_expr =
|
||||
opts.gles ? "v_vtxPointSize[index]" : "gl_in[index].gl_PointSize";
|
||||
mstring_append_fmt(
|
||||
@@ -369,7 +161,7 @@ MString *pgraph_glsl_gen_geom(const GeomState *state, GenGeomGlslOptions opts)
|
||||
provoking_index,
|
||||
provoking_index);
|
||||
|
||||
if (need_triz || need_quadz) {
|
||||
if (need_triz) {
|
||||
mstring_append(
|
||||
output,
|
||||
// Kahan's algorithm for computing a*b - c*d using FMA for higher
|
||||
@@ -438,22 +230,12 @@ MString *pgraph_glsl_gen_geom(const GeomState *state, GenGeomGlslOptions opts)
|
||||
"}\n");
|
||||
}
|
||||
|
||||
if (need_quadz) {
|
||||
mstring_append(
|
||||
output,
|
||||
"void calc_quadz(int i0, int i1, int i2, int i3, out mat4 triz1, out mat4 triz2) {\n"
|
||||
" triz1 = calc_triz(i0, i1, i2);\n"
|
||||
" triz2 = calc_triz(i0, i2, i3);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
mstring_append_fmt(output,
|
||||
"\n"
|
||||
"void main() {\n"
|
||||
"%s"
|
||||
"%s"
|
||||
"}\n",
|
||||
vertex_order_body, body);
|
||||
body);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -30,10 +30,7 @@ typedef struct {
|
||||
enum ShaderPolygonMode polygon_front_mode;
|
||||
enum ShaderPolygonMode polygon_back_mode;
|
||||
bool smooth_shading;
|
||||
bool first_vertex_is_provoking;
|
||||
bool z_perspective;
|
||||
short tri_rot0;
|
||||
short tri_rot1;
|
||||
} GeomState;
|
||||
|
||||
typedef struct GenGeomGlslOptions {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
specific_ss.add(files(
|
||||
'prim_rewrite.c',
|
||||
'pgraph.c',
|
||||
'profile.c',
|
||||
'rdi.c',
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Geforce NV2A PGRAPH Primitive Index Rewrite
|
||||
*
|
||||
* Rewrites NV2A primitive types to triangle/line/point lists on CPU.
|
||||
* Handles provoking vertex placement for flat shading correctness.
|
||||
*
|
||||
* Copyright (c) 2026 Matt Borgerson
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef HW_XBOX_NV2A_PGRAPH_PRIM_REWRITE_H
|
||||
#define HW_XBOX_NV2A_PGRAPH_PRIM_REWRITE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "vsh_regs.h"
|
||||
|
||||
typedef struct PrimRewriteBuf {
|
||||
uint32_t *data;
|
||||
unsigned int capacity; /* in elements */
|
||||
} PrimRewriteBuf;
|
||||
|
||||
typedef struct PrimRewrite {
|
||||
uint32_t *indices; /* points into PrimRewriteBuf; do NOT free */
|
||||
unsigned int num_indices;
|
||||
} PrimRewrite;
|
||||
|
||||
typedef struct PrimAssemblyState {
|
||||
enum ShaderPrimitiveMode primitive_mode;
|
||||
enum ShaderPolygonMode polygon_mode;
|
||||
bool last_provoking;
|
||||
bool flat_shading;
|
||||
} PrimAssemblyState;
|
||||
|
||||
void pgraph_prim_rewrite_init(PrimRewriteBuf *buf);
|
||||
void pgraph_prim_rewrite_finalize(PrimRewriteBuf *buf);
|
||||
enum ShaderPrimitiveMode
|
||||
pgraph_prim_rewrite_get_output_mode(enum ShaderPrimitiveMode primitive_mode,
|
||||
enum ShaderPolygonMode polygon_mode);
|
||||
|
||||
PrimRewrite pgraph_prim_rewrite_indexed(PrimRewriteBuf *buf,
|
||||
PrimAssemblyState mode,
|
||||
const uint32_t *input_indices,
|
||||
unsigned int num_input_indices);
|
||||
|
||||
PrimRewrite pgraph_prim_rewrite_ranges(PrimRewriteBuf *buf,
|
||||
PrimAssemblyState mode,
|
||||
const int32_t *starts,
|
||||
const int32_t *counts,
|
||||
unsigned int num_ranges);
|
||||
|
||||
static inline PrimRewrite pgraph_prim_rewrite_sequential(PrimRewriteBuf *buf,
|
||||
PrimAssemblyState mode,
|
||||
int32_t start,
|
||||
int32_t count)
|
||||
{
|
||||
return pgraph_prim_rewrite_ranges(buf, mode, &start, &count, 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -153,6 +153,8 @@ void pgraph_vk_init_buffers(NV2AState *d)
|
||||
r->allocator, r->storage_buffers[buffers_to_map[i]].allocation,
|
||||
(void **)&r->storage_buffers[buffers_to_map[i]].mapped));
|
||||
}
|
||||
|
||||
pgraph_prim_rewrite_init(&r->prim_rewrite_buf);
|
||||
}
|
||||
|
||||
void pgraph_vk_finalize_buffers(NV2AState *d)
|
||||
@@ -167,6 +169,8 @@ void pgraph_vk_finalize_buffers(NV2AState *d)
|
||||
destroy_buffer(pg, &r->storage_buffers[i]);
|
||||
}
|
||||
|
||||
pgraph_prim_rewrite_finalize(&r->prim_rewrite_buf);
|
||||
|
||||
g_free(r->uploaded_bitmap);
|
||||
r->uploaded_bitmap = NULL;
|
||||
}
|
||||
|
||||
+102
-39
@@ -20,6 +20,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/fast-hash.h"
|
||||
#include "renderer.h"
|
||||
#include "hw/xbox/nv2a/pgraph/prim_rewrite.h"
|
||||
#include <math.h>
|
||||
|
||||
void pgraph_vk_draw_begin(NV2AState *d)
|
||||
@@ -51,38 +52,15 @@ static VkPrimitiveTopology get_primitive_topology(PGRAPHState *pg)
|
||||
{
|
||||
PGRAPHVkState *r = pg->vk_renderer_state;
|
||||
|
||||
int polygon_mode = r->shader_binding->state.geom.polygon_front_mode;
|
||||
int primitive_mode = r->shader_binding->state.geom.primitive_mode;
|
||||
|
||||
// FIXME: Replace with LUT
|
||||
switch (primitive_mode) {
|
||||
case PRIM_TYPE_POINTS:
|
||||
return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
|
||||
case PRIM_TYPE_LINES:
|
||||
return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
|
||||
case PRIM_TYPE_LINE_LOOP:
|
||||
// FIXME: line strips, except that the first and last vertices are also used as a line
|
||||
return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
|
||||
case PRIM_TYPE_LINE_STRIP:
|
||||
return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
|
||||
case PRIM_TYPE_TRIANGLES:
|
||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
case PRIM_TYPE_TRIANGLE_STRIP:
|
||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
|
||||
case PRIM_TYPE_TRIANGLE_FAN:
|
||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
|
||||
case PRIM_TYPE_QUADS:
|
||||
return VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY;
|
||||
case PRIM_TYPE_QUAD_STRIP:
|
||||
return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY;
|
||||
case PRIM_TYPE_POLYGON:
|
||||
if (polygon_mode == POLY_MODE_LINE) {
|
||||
return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; // FIXME
|
||||
} else if (polygon_mode == POLY_MODE_FILL) {
|
||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
|
||||
}
|
||||
assert(!"PRIM_TYPE_POLYGON with invalid polygon_mode");
|
||||
return 0;
|
||||
default:
|
||||
assert(!"Invalid primitive_mode");
|
||||
return 0;
|
||||
@@ -2041,6 +2019,19 @@ void pgraph_vk_flush_draw(NV2AState *d)
|
||||
|
||||
r->num_vertex_ram_buffer_syncs = 0;
|
||||
|
||||
PrimAssemblyState assembly = {
|
||||
.primitive_mode = pg->primitive_mode,
|
||||
.polygon_mode = (enum ShaderPolygonMode)GET_MASK(
|
||||
pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER),
|
||||
NV_PGRAPH_SETUPRASTER_FRONTFACEMODE),
|
||||
.last_provoking = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_3),
|
||||
NV_PGRAPH_CONTROL_3_PROVOKING_VERTEX) ==
|
||||
NV_PGRAPH_CONTROL_3_PROVOKING_VERTEX_LAST,
|
||||
.flat_shading = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_3),
|
||||
NV_PGRAPH_CONTROL_3_SHADEMODE) ==
|
||||
NV_PGRAPH_CONTROL_3_SHADEMODE_FLAT,
|
||||
};
|
||||
|
||||
if (pg->draw_arrays_length) {
|
||||
NV2A_VK_DGROUP_BEGIN("Draw Arrays");
|
||||
nv2a_profile_inc_counter(NV2A_PROF_DRAW_ARRAYS);
|
||||
@@ -2061,18 +2052,42 @@ void pgraph_vk_flush_draw(NV2AState *d)
|
||||
sync_vertex_ram_buffer(pg);
|
||||
VertexBufferRemap remap = remap_unaligned_attributes(pg, max_element);
|
||||
|
||||
PrimRewrite prim_rw = pgraph_prim_rewrite_ranges(
|
||||
&r->prim_rewrite_buf, assembly,
|
||||
pg->draw_arrays_start, pg->draw_arrays_count,
|
||||
pg->draw_arrays_length);
|
||||
|
||||
if (prim_rw.num_indices > 0) {
|
||||
size_t rewrite_size =
|
||||
prim_rw.num_indices * sizeof(uint32_t);
|
||||
ensure_buffer_space(pg, BUFFER_INDEX_STAGING, rewrite_size);
|
||||
}
|
||||
|
||||
begin_pre_draw(pg);
|
||||
copy_remapped_attributes_to_inline_buffer(pg, remap, 0, max_element);
|
||||
pgraph_vk_begin_debug_marker(r, r->command_buffer, RGBA_BLUE,
|
||||
"Draw Arrays");
|
||||
begin_draw(pg);
|
||||
bind_vertex_buffer(pg, remap.attributes, 0);
|
||||
for (int i = 0; i < pg->draw_arrays_length; i++) {
|
||||
uint32_t start = pg->draw_arrays_start[i],
|
||||
count = pg->draw_arrays_count[i];
|
||||
NV2A_VK_DPRINTF("- [%d] Start:%d Count:%d", i, start, count);
|
||||
vkCmdDraw(r->command_buffer, count, 1, start, 0);
|
||||
|
||||
if (prim_rw.num_indices > 0) {
|
||||
size_t rewrite_size = prim_rw.num_indices * sizeof(uint32_t);
|
||||
VkDeviceSize buffer_offset = pgraph_vk_update_index_buffer(
|
||||
pg, prim_rw.indices, rewrite_size);
|
||||
vkCmdBindIndexBuffer(r->command_buffer,
|
||||
r->storage_buffers[BUFFER_INDEX].buffer,
|
||||
buffer_offset, VK_INDEX_TYPE_UINT32);
|
||||
vkCmdDrawIndexed(r->command_buffer, prim_rw.num_indices, 1, 0, 0,
|
||||
0);
|
||||
} else {
|
||||
for (int i = 0; i < pg->draw_arrays_length; i++) {
|
||||
uint32_t start = pg->draw_arrays_start[i],
|
||||
count = pg->draw_arrays_count[i];
|
||||
NV2A_VK_DPRINTF("- [%d] Start:%d Count:%d", i, start, count);
|
||||
vkCmdDraw(r->command_buffer, count, 1, start, 0);
|
||||
}
|
||||
}
|
||||
|
||||
end_draw(pg);
|
||||
pgraph_vk_end_debug_marker(r, r->command_buffer);
|
||||
|
||||
@@ -2084,27 +2099,35 @@ void pgraph_vk_flush_draw(NV2AState *d)
|
||||
|
||||
nv2a_profile_inc_counter(NV2A_PROF_INLINE_ELEMENTS);
|
||||
|
||||
size_t index_data_size =
|
||||
pg->inline_elements_length * sizeof(pg->inline_elements[0]);
|
||||
uint32_t *draw_indices = pg->inline_elements;
|
||||
unsigned int draw_index_count = pg->inline_elements_length;
|
||||
PrimRewrite prim_rw = pgraph_prim_rewrite_indexed(
|
||||
&r->prim_rewrite_buf, assembly, pg->inline_elements,
|
||||
pg->inline_elements_length);
|
||||
if (prim_rw.num_indices > 0) {
|
||||
draw_indices = prim_rw.indices;
|
||||
draw_index_count = prim_rw.num_indices;
|
||||
}
|
||||
|
||||
size_t index_data_size = draw_index_count * sizeof(uint32_t);
|
||||
ensure_buffer_space(pg, BUFFER_INDEX_STAGING, index_data_size);
|
||||
|
||||
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);
|
||||
for (unsigned int i = 0; i < draw_index_count; i++) {
|
||||
max_element = MAX(draw_indices[i], max_element);
|
||||
min_element = MIN(draw_indices[i], min_element);
|
||||
}
|
||||
pgraph_vk_bind_vertex_attributes(
|
||||
d, min_element, max_element, false, 0,
|
||||
pg->inline_elements[pg->inline_elements_length - 1]);
|
||||
draw_indices[draw_index_count - 1]);
|
||||
sync_vertex_ram_buffer(pg);
|
||||
VertexBufferRemap remap = remap_unaligned_attributes(pg, max_element + 1);
|
||||
|
||||
begin_pre_draw(pg);
|
||||
copy_remapped_attributes_to_inline_buffer(pg, remap, 0, max_element + 1);
|
||||
VkDeviceSize buffer_offset = pgraph_vk_update_index_buffer(
|
||||
pg, pg->inline_elements, index_data_size);
|
||||
pg, draw_indices, index_data_size);
|
||||
pgraph_vk_begin_debug_marker(r, r->command_buffer, RGBA_BLUE,
|
||||
"Inline Elements");
|
||||
begin_draw(pg);
|
||||
@@ -2112,8 +2135,7 @@ void pgraph_vk_flush_draw(NV2AState *d)
|
||||
vkCmdBindIndexBuffer(r->command_buffer,
|
||||
r->storage_buffers[BUFFER_INDEX].buffer,
|
||||
buffer_offset, VK_INDEX_TYPE_UINT32);
|
||||
vkCmdDrawIndexed(r->command_buffer, pg->inline_elements_length, 1, 0, 0,
|
||||
0);
|
||||
vkCmdDrawIndexed(r->command_buffer, draw_index_count, 1, 0, 0, 0);
|
||||
end_draw(pg);
|
||||
pgraph_vk_end_debug_marker(r, r->command_buffer);
|
||||
|
||||
@@ -2141,7 +2163,14 @@ void pgraph_vk_flush_draw(NV2AState *d)
|
||||
attr->inline_buffer_populated = false;
|
||||
offset += vertex_data_size;
|
||||
}
|
||||
PrimRewrite prim_rw = pgraph_prim_rewrite_sequential(
|
||||
&r->prim_rewrite_buf, assembly, 0, pg->inline_buffer_length);
|
||||
|
||||
ensure_buffer_space(pg, BUFFER_VERTEX_INLINE_STAGING, offset);
|
||||
if (prim_rw.num_indices > 0) {
|
||||
size_t rewrite_size = prim_rw.num_indices * sizeof(uint32_t);
|
||||
ensure_buffer_space(pg, BUFFER_INDEX_STAGING, rewrite_size);
|
||||
}
|
||||
|
||||
begin_pre_draw(pg);
|
||||
VkDeviceSize buffer_offset = pgraph_vk_update_vertex_inline_buffer(
|
||||
@@ -2150,7 +2179,20 @@ void pgraph_vk_flush_draw(NV2AState *d)
|
||||
"Inline Buffer");
|
||||
begin_draw(pg);
|
||||
bind_inline_vertex_buffer(pg, buffer_offset);
|
||||
vkCmdDraw(r->command_buffer, pg->inline_buffer_length, 1, 0, 0);
|
||||
|
||||
if (prim_rw.num_indices > 0) {
|
||||
size_t rewrite_size = prim_rw.num_indices * sizeof(uint32_t);
|
||||
VkDeviceSize idx_offset = pgraph_vk_update_index_buffer(
|
||||
pg, prim_rw.indices, rewrite_size);
|
||||
vkCmdBindIndexBuffer(r->command_buffer,
|
||||
r->storage_buffers[BUFFER_INDEX].buffer,
|
||||
idx_offset, VK_INDEX_TYPE_UINT32);
|
||||
vkCmdDrawIndexed(r->command_buffer, prim_rw.num_indices, 1, 0, 0,
|
||||
0);
|
||||
} else {
|
||||
vkCmdDraw(r->command_buffer, pg->inline_buffer_length, 1, 0, 0);
|
||||
}
|
||||
|
||||
end_draw(pg);
|
||||
pgraph_vk_end_debug_marker(r, r->command_buffer);
|
||||
|
||||
@@ -2186,6 +2228,14 @@ void pgraph_vk_flush_draw(NV2AState *d)
|
||||
pgraph_vk_bind_vertex_attributes(d, 0, index_count - 1, true,
|
||||
vertex_size, index_count - 1);
|
||||
|
||||
PrimRewrite prim_rw = pgraph_prim_rewrite_sequential(
|
||||
&r->prim_rewrite_buf, assembly, 0, index_count);
|
||||
|
||||
if (prim_rw.num_indices > 0) {
|
||||
size_t rewrite_size = prim_rw.num_indices * sizeof(uint32_t);
|
||||
ensure_buffer_space(pg, BUFFER_INDEX_STAGING, rewrite_size);
|
||||
}
|
||||
|
||||
begin_pre_draw(pg);
|
||||
void *inline_array_data = pg->inline_array;
|
||||
VkDeviceSize buffer_offset = pgraph_vk_update_vertex_inline_buffer(
|
||||
@@ -2194,7 +2244,20 @@ void pgraph_vk_flush_draw(NV2AState *d)
|
||||
"Inline Array");
|
||||
begin_draw(pg);
|
||||
bind_inline_vertex_buffer(pg, buffer_offset);
|
||||
vkCmdDraw(r->command_buffer, index_count, 1, 0, 0);
|
||||
|
||||
if (prim_rw.num_indices > 0) {
|
||||
size_t rewrite_size = prim_rw.num_indices * sizeof(uint32_t);
|
||||
VkDeviceSize idx_offset = pgraph_vk_update_index_buffer(
|
||||
pg, prim_rw.indices, rewrite_size);
|
||||
vkCmdBindIndexBuffer(r->command_buffer,
|
||||
r->storage_buffers[BUFFER_INDEX].buffer,
|
||||
idx_offset, VK_INDEX_TYPE_UINT32);
|
||||
vkCmdDrawIndexed(r->command_buffer, prim_rw.num_indices, 1, 0, 0,
|
||||
0);
|
||||
} else {
|
||||
vkCmdDraw(r->command_buffer, index_count, 1, 0, 0);
|
||||
}
|
||||
|
||||
end_draw(pg);
|
||||
pgraph_vk_end_debug_marker(r, r->command_buffer);
|
||||
NV2A_VK_DGROUP_END();
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "hw/hw.h"
|
||||
#include "hw/xbox/nv2a/nv2a_int.h"
|
||||
#include "hw/xbox/nv2a/nv2a_regs.h"
|
||||
#include "hw/xbox/nv2a/pgraph/prim_rewrite.h"
|
||||
#include "hw/xbox/nv2a/pgraph/surface.h"
|
||||
#include "hw/xbox/nv2a/pgraph/texture.h"
|
||||
#include "hw/xbox/nv2a/pgraph/glsl/shaders.h"
|
||||
@@ -370,6 +371,7 @@ typedef struct PGRAPHVkState {
|
||||
int descriptor_set_index;
|
||||
|
||||
StorageBuffer storage_buffers[BUFFER_COUNT];
|
||||
PrimRewriteBuf prim_rewrite_buf;
|
||||
|
||||
MemorySyncRequirement vertex_ram_buffer_syncs[NV2A_VERTEXSHADER_ATTRIBUTES];
|
||||
size_t num_vertex_ram_buffer_syncs;
|
||||
|
||||
Reference in New Issue
Block a user