kinda handle immediate-mode vertex stuff; refactoring

This commit is contained in:
espes 2013-11-15 13:45:55 +11:00
parent 7af215ee16
commit ef7f80bb86
2 changed files with 163 additions and 58 deletions

View File

@ -435,6 +435,7 @@
# define NV097_SET_VIEWPORT_SCALE 0x00970AF0
# define NV097_SET_TRANSFORM_PROGRAM 0x00970B00
# define NV097_SET_TRANSFORM_CONSTANT 0x00970B80
# define NV097_SET_VERTEX4F 0x00971518
# define NV097_SET_VERTEX_DATA_ARRAY_OFFSET 0x00971720
# define NV097_SET_VERTEX_DATA_ARRAY_FORMAT 0x00971760
# define NV097_SET_VERTEX_DATA_ARRAY_FORMAT_TYPE 0x0000000F
@ -464,11 +465,16 @@
# define NV097_DRAW_ARRAYS_COUNT 0xFF000000
# define NV097_DRAW_ARRAYS_START_INDEX 0x00FFFFFF
# define NV097_INLINE_ARRAY 0x00971818
# define NV097_SET_VERTEX_DATA4UB 0x00971940
# define NV097_SET_TEXTURE_OFFSET 0x00971B00
# define NV097_SET_TEXTURE_FORMAT 0x00971B04
# define NV097_SET_TEXTURE_FORMAT_CONTEXT_DMA 0x00000003
# define NV097_SET_TEXTURE_FORMAT_DIMENSIONALITY 0x000000F0
# define NV097_SET_TEXTURE_FORMAT_COLOR 0x0000FF00
# define NV097_SET_TEXTURE_FORMAT_COLOR_SZ_A1R5G5B5 0x02
# define NV097_SET_TEXTURE_FORMAT_COLOR_SZ_X1R5G5B5 0x03
# define NV097_SET_TEXTURE_FORMAT_COLOR_SZ_A4R4G4B4 0x04
# define NV097_SET_TEXTURE_FORMAT_COLOR_SZ_R5G6B5 0x05
# define NV097_SET_TEXTURE_FORMAT_COLOR_SZ_A8R8G8B8 0x06
# define NV097_SET_TEXTURE_FORMAT_COLOR_SZ_X8R8G8B8 0x07
# define NV097_SET_TEXTURE_FORMAT_COLOR_L_DXT1_A1R5G5B5 0x0C
@ -507,6 +513,7 @@
# define NV097_CLEAR_SURFACE_A (1 << 7)
# define NV097_SET_CLEAR_RECT_HORIZONTAL 0x00971D98
# define NV097_SET_CLEAR_RECT_VERTICAL 0x00971D9C
# define NV097_SET_SPECULAR_FOG_FACTOR 0x00971E20
# define NV097_SET_COMBINER_COLOR_OCW 0x00971E40
# define NV097_SET_COMBINER_CONTROL 0x00971E60
# define NV097_SET_SHADER_STAGE_PROGRAM 0x00971E70
@ -554,35 +561,59 @@ static const GLenum kelvin_texture_mag_filter_map[] = {
typedef struct ColorFormatInfo {
unsigned int bytes_per_pixel;
bool swizzled;
bool linear;
GLint gl_internal_format;
GLenum gl_format;
GLenum gl_type;
} ColorFormatInfo;
static const ColorFormatInfo kelvin_color_format_map[66] = {
[NV097_SET_TEXTURE_FORMAT_COLOR_SZ_A1R5G5B5] =
{2, true, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV},
[NV097_SET_TEXTURE_FORMAT_COLOR_SZ_X1R5G5B5] =
{2, true, GL_RGB, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV},
[NV097_SET_TEXTURE_FORMAT_COLOR_SZ_A4R4G4B4] =
{2, true, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV},
[NV097_SET_TEXTURE_FORMAT_COLOR_SZ_R5G6B5] =
{2, true, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV},
[NV097_SET_TEXTURE_FORMAT_COLOR_SZ_A8R8G8B8] =
{4, true, false, GL_RGBA, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV},
{4, true, GL_RGBA, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV},
[NV097_SET_TEXTURE_FORMAT_COLOR_SZ_X8R8G8B8] =
{4, true, false, GL_RGB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV},
{4, true, GL_RGB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV},
[NV097_SET_TEXTURE_FORMAT_COLOR_L_DXT1_A1R5G5B5] =
{4, true, false, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0, GL_RGBA},
{4, true, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 0, GL_RGBA},
[NV097_SET_TEXTURE_FORMAT_COLOR_L_DXT23_A8R8G8B8] =
{4, true, false, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0, GL_RGBA},
{4, true, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 0, GL_RGBA},
[NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_A8R8G8B8] =
{4, false, true, GL_RGBA, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV},
{4, false, GL_RGBA, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV},
/* TODO: how do opengl alpha textures work? */
[NV097_SET_TEXTURE_FORMAT_COLOR_SZ_A8] =
{2, true, false, GL_RED, GL_RED, GL_UNSIGNED_BYTE},
{2, true, GL_RED, GL_RED, GL_UNSIGNED_BYTE},
[NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_X8R8G8B8] =
{4, false, true, GL_RGB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV},
{4, false, GL_RGB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV},
[NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_DEPTH_Y16_FIXED] =
{2, false, true, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_SHORT},
{2, false, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_SHORT},
};
#define NV2A_VERTEX_ATTR_POSITION 0
#define NV2A_VERTEX_ATTR_WEIGHT 1
#define NV2A_VERTEX_ATTR_NORMAL 2
#define NV2A_VERTEX_ATTR_DIFFUSE 3
#define NV2A_VERTEX_ATTR_SPECULAR 4
#define NV2A_VERTEX_ATTR_FOG 5
#define NV2A_VERTEX_ATTR_POINT_SIZE 6
#define NV2A_VERTEX_ATTR_BACK_DIFFUSE 7
#define NV2A_VERTEX_ATTR_BACK_SPECULAR 8
#define NV2A_VERTEX_ATTR_TEXTURE0 9
#define NV2A_VERTEX_ATTR_TEXTURE1 10
#define NV2A_VERTEX_ATTR_TEXTURE2 11
#define NV2A_VERTEX_ATTR_TEXTURE3 12
#define NV2A_VERTEX_ATTR_RESERVED1 13
#define NV2A_VERTEX_ATTR_RESERVED2 14
#define NV2A_VERTEX_ATTR_RESERVED3 15
#define NV2A_CRYSTAL_FREQ 13500000
#define NV2A_NUM_CHANNELS 32
@ -644,7 +675,9 @@ typedef struct VertexAttribute {
/* inline arrays are packed in order?
* Need to pass the offset to converted attributes */
unsigned int inline_offset;
unsigned int inline_array_offset;
uint32_t inline_value;
unsigned int format;
unsigned int size; /* size of the data type */
@ -719,6 +752,11 @@ typedef struct Surface {
hwaddr offset;
} Surface;
typedef struct InlineVertexBufferEntry {
uint32_t position[4];
uint32_t diffuse;
} InlineVertexBufferEntry;
typedef struct KelvinState {
hwaddr dma_notifies;
hwaddr dma_state;
@ -738,11 +776,14 @@ typedef struct KelvinState {
VertexAttribute vertex_attributes[NV2A_VERTEXSHADER_ATTRIBUTES];
unsigned int inline_vertex_data_length;
uint32_t inline_vertex_data[NV2A_MAX_BATCH_LENGTH];
unsigned int inline_array_length;
uint32_t inline_array[NV2A_MAX_BATCH_LENGTH];
unsigned int array_batch_length;
uint32_t array_batch[NV2A_MAX_BATCH_LENGTH];
unsigned int inline_elements_length;
uint32_t inline_elements[NV2A_MAX_BATCH_LENGTH];
unsigned int inline_buffer_length;
InlineVertexBufferEntry inline_buffer[NV2A_MAX_BATCH_LENGTH];
bool use_vertex_program;
bool enable_vertex_program_write;
@ -1141,8 +1182,8 @@ static void kelvin_bind_converted_vertex_attributes(NV2AState *d,
uint8_t *data;
if (inline_data) {
data = (uint8_t*)kelvin->inline_vertex_data
+ attribute->inline_offset;
data = (uint8_t*)kelvin->inline_array
+ attribute->inline_array_offset;
} else {
hwaddr dma_len;
if (attribute->dma_select) {
@ -1191,7 +1232,7 @@ static void kelvin_bind_converted_vertex_attributes(NV2AState *d,
}
}
static unsigned int kelvin_bind_inline_vertex_data(KelvinState *kelvin)
static unsigned int kelvin_bind_inline_array(KelvinState *kelvin)
{
int i;
unsigned int offset = 0;
@ -1199,7 +1240,9 @@ static unsigned int kelvin_bind_inline_vertex_data(KelvinState *kelvin)
VertexAttribute *attribute = &kelvin->vertex_attributes[i];
if (attribute->count) {
attribute->inline_offset = offset;
glEnableVertexAttribArray(i);
attribute->inline_array_offset = offset;
if (!attribute->needs_conversion) {
glVertexAttribPointer(i,
@ -1207,20 +1250,16 @@ static unsigned int kelvin_bind_inline_vertex_data(KelvinState *kelvin)
attribute->gl_type,
attribute->gl_normalize,
attribute->stride,
(uint8_t*)kelvin->inline_vertex_data + offset);
(uint8_t*)kelvin->inline_array + offset);
}
glEnableVertexAttribArray(i);
offset += attribute->size * attribute->count;
} else {
glDisableVertexAttribArray(i);
}
}
return offset;
}
static void kelvin_bind_vertex_attribute_offsets(NV2AState *d,
static void kelvin_bind_vertex_attributes(NV2AState *d,
KelvinState *kelvin)
{
int i;
@ -1228,6 +1267,8 @@ static void kelvin_bind_vertex_attribute_offsets(NV2AState *d,
for (i=0; i<NV2A_VERTEXSHADER_ATTRIBUTES; i++) {
VertexAttribute *attribute = &kelvin->vertex_attributes[i];
if (attribute->count) {
glEnableVertexAttribArray(i);
if (!attribute->needs_conversion) {
hwaddr dma_len;
uint8_t *vertex_data;
@ -1248,10 +1289,10 @@ static void kelvin_bind_vertex_attribute_offsets(NV2AState *d,
attribute->stride,
vertex_data);
}
glEnableVertexAttribArray(i);
} else {
glDisableVertexAttribArray(i);
glVertexAttrib4ubv(i, (GLubyte *)&attribute->inline_value);
}
}
}
@ -1289,7 +1330,7 @@ static void kelvin_bind_vertexshader(KelvinState *kelvin)
GLint pos;
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos);
if (pos != -1) {
fprintf(stderr, "nv2a: vertex shader compilation failed:\n"
fprintf(stderr, "nv2a: vertex program compilation failed:\n"
" pos %d, %s\n",
pos, glGetString(GL_PROGRAM_ERROR_STRING_ARB));
fprintf(stderr, "ucode:\n");
@ -1347,7 +1388,7 @@ static void pgraph_bind_textures(NV2AState *d)
GLenum gl_target;
GLuint gl_texture;
unsigned int width, height;
if (f.linear) {
if (!f.swizzled) {
/* linear textures use unnormalised texcoords.
* GL_TEXTURE_RECTANGLE_ARB conveniently also does, but
* does not allow repeat and mirror wrap modes.
@ -1413,7 +1454,7 @@ static void pgraph_bind_textures(NV2AState *d)
width/4 * height/4 * block_size,
texture_data);
} else {
if (f.linear) {
if (!f.swizzled) {
/* Can't handle retarded strides */
assert(texture->pitch % f.bytes_per_pixel == 0);
glPixelStorei(GL_UNPACK_ROW_LENGTH,
@ -1423,7 +1464,7 @@ static void pgraph_bind_textures(NV2AState *d)
width, height, 0,
f.gl_format, f.gl_type,
texture_data);
if (f.linear) {
if (!f.swizzled) {
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
}
@ -1485,7 +1526,7 @@ static void pgraph_bind_fragment_shader(PGRAPHState *pg)
for (i = 0; i < 4; i++) {
state.rect_tex[i] = false;
if (pg->textures[i].enabled
&& kelvin_color_format_map[pg->textures[i].color_format].linear) {
&& !kelvin_color_format_map[pg->textures[i].color_format].swizzled) {
state.rect_tex[i] = true;
}
}
@ -2143,6 +2184,24 @@ static void pgraph_method(NV2AState *d,
constant->dirty = true;
break;
case NV097_SET_VERTEX4F ...
NV097_SET_VERTEX4F + 12: {
slot = (class_method - NV097_SET_VERTEX4F) / 4;
assert(kelvin->inline_buffer_length < NV2A_MAX_BATCH_LENGTH);
InlineVertexBufferEntry *entry =
&kelvin->inline_buffer[kelvin->inline_buffer_length];
entry->position[slot] = parameter;
if (slot == 3) {
entry->diffuse =
kelvin->vertex_attributes[NV2A_VERTEX_ATTR_DIFFUSE].inline_value;
kelvin->inline_buffer_length++;
}
break;
}
case NV097_SET_VERTEX_DATA_ARRAY_FORMAT ...
NV097_SET_VERTEX_DATA_ARRAY_FORMAT + 0x3c:
@ -2225,32 +2284,51 @@ static void pgraph_method(NV2AState *d,
case NV097_SET_BEGIN_END:
if (parameter == NV097_SET_BEGIN_END_OP_END) {
if (kelvin->inline_vertex_data_length) {
if (kelvin->inline_buffer_length) {
glEnableVertexAttribArray(NV2A_VERTEX_ATTR_POSITION);
glVertexAttribPointer(NV2A_VERTEX_ATTR_POSITION,
4,
GL_FLOAT,
GL_FALSE,
sizeof(InlineVertexBufferEntry),
kelvin->inline_buffer);
glEnableVertexAttribArray(NV2A_VERTEX_ATTR_DIFFUSE);
glVertexAttribPointer(NV2A_VERTEX_ATTR_POSITION,
1,
GL_UNSIGNED_INT,
GL_FALSE,
sizeof(InlineVertexBufferEntry),
&kelvin->inline_buffer[0].diffuse);
glDrawArrays(kelvin->gl_primitive_mode,
0, kelvin->inline_buffer_length);
} else if (kelvin->inline_array_length) {
unsigned int vertex_size =
kelvin_bind_inline_vertex_data(kelvin);
kelvin_bind_inline_array(kelvin);
unsigned int index_count =
kelvin->inline_vertex_data_length*4 / vertex_size;
kelvin->inline_array_length*4 / vertex_size;
kelvin_bind_converted_vertex_attributes(d, kelvin,
true, index_count);
glDrawArrays(kelvin->gl_primitive_mode,
0, index_count);
} else if (kelvin->array_batch_length) {
} else if (kelvin->inline_elements_length) {
uint32_t max_element = 0;
uint32_t min_elemenet = (uint32_t)-1;
for (i=0; i<kelvin->array_batch_length; i++) {
max_element = MAX(kelvin->array_batch[i], max_element);
min_elemenet = MIN(kelvin->array_batch[i], min_elemenet);
for (i=0; i<kelvin->inline_elements_length; i++) {
max_element = MAX(kelvin->inline_elements[i], max_element);
min_elemenet = MIN(kelvin->inline_elements[i], min_elemenet);
}
kelvin_bind_converted_vertex_attributes(d, kelvin,
false, max_element+1);
glDrawElements(kelvin->gl_primitive_mode,
kelvin->array_batch_length,
kelvin->inline_elements_length,
GL_UNSIGNED_INT,
kelvin->array_batch);
kelvin->inline_elements);
}/* else {
assert(false);
}*/
@ -2270,13 +2348,14 @@ static void pgraph_method(NV2AState *d,
pgraph_bind_fragment_shader(pg);
pgraph_bind_textures(d);
kelvin_bind_vertex_attribute_offsets(d, kelvin);
kelvin_bind_vertex_attributes(d, kelvin);
kelvin->gl_primitive_mode = kelvin_primitive_map[parameter];
kelvin->array_batch_length = 0;
kelvin->inline_vertex_data_length = 0;
kelvin->inline_elements_length = 0;
kelvin->inline_array_length = 0;
kelvin->inline_buffer_length = 0;
}
pg->surface_color.draw_dirty = true;
break;
@ -2300,6 +2379,7 @@ static void pgraph_method(NV2AState *d,
GET_MASK(parameter, NV097_SET_TEXTURE_FORMAT_BASE_SIZE_V);
pg->textures[slot].dirty = true;
pg->fragment_shader_dirty = true;
break;
CASE_4(NV097_SET_TEXTURE_CONTROL0, 64):
slot = (class_method - NV097_SET_TEXTURE_CONTROL0) / 64;
@ -2310,7 +2390,8 @@ static void pgraph_method(NV2AState *d,
GET_MASK(parameter, NV097_SET_TEXTURE_CONTROL0_MIN_LOD_CLAMP);
pg->textures[slot].max_mipmap_level =
GET_MASK(parameter, NV097_SET_TEXTURE_CONTROL0_MAX_LOD_CLAMP);
pg->fragment_shader_dirty = true;
break;
CASE_4(NV097_SET_TEXTURE_CONTROL1, 64):
slot = (class_method - NV097_SET_TEXTURE_CONTROL1) / 64;
@ -2338,17 +2419,18 @@ static void pgraph_method(NV2AState *d,
pg->textures[slot].dirty = true;
break;
case NV097_ARRAY_ELEMENT16:
assert(kelvin->array_batch_length < NV2A_MAX_BATCH_LENGTH);
kelvin->array_batch[
kelvin->array_batch_length++] = parameter & 0xFFFF;
kelvin->array_batch[
kelvin->array_batch_length++] = parameter >> 16;
assert(kelvin->inline_elements_length < NV2A_MAX_BATCH_LENGTH);
kelvin->inline_elements[
kelvin->inline_elements_length++] = parameter & 0xFFFF;
kelvin->inline_elements[
kelvin->inline_elements_length++] = parameter >> 16;
break;
case NV097_ARRAY_ELEMENT32:
assert(kelvin->array_batch_length < NV2A_MAX_BATCH_LENGTH);
kelvin->array_batch[
kelvin->array_batch_length++] = parameter;
assert(kelvin->inline_elements_length < NV2A_MAX_BATCH_LENGTH);
kelvin->inline_elements[
kelvin->inline_elements_length++] = parameter;
break;
case NV097_DRAW_ARRAYS: {
unsigned int start = GET_MASK(parameter, NV097_DRAW_ARRAYS_START_INDEX);
@ -2362,9 +2444,15 @@ static void pgraph_method(NV2AState *d,
break;
}
case NV097_INLINE_ARRAY:
assert(kelvin->inline_vertex_data_length < NV2A_MAX_BATCH_LENGTH);
kelvin->inline_vertex_data[
kelvin->inline_vertex_data_length++] = parameter;
assert(kelvin->inline_array_length < NV2A_MAX_BATCH_LENGTH);
kelvin->inline_array[
kelvin->inline_array_length++] = parameter;
break;
case NV097_SET_VERTEX_DATA4UB ...
NV097_SET_VERTEX_DATA4UB + 0x3c:
slot = (class_method - NV097_SET_VERTEX_DATA4UB) / 64;
kelvin->vertex_attributes[slot].inline_value = parameter;
break;
case NV097_SET_SEMAPHORE_OFFSET:
@ -2455,6 +2543,13 @@ static void pgraph_method(NV2AState *d,
pg->regs[NV_PGRAPH_CLEARRECTY] = parameter;
break;
case NV097_SET_SPECULAR_FOG_FACTOR ...
NV097_SET_SPECULAR_FOG_FACTOR + 4:
slot = (class_method - NV097_SET_SPECULAR_FOG_FACTOR) / 4;
pg->regs[NV_PGRAPH_SPECFOGFACTOR0 + slot*4] = parameter;
pg->fragment_shader_dirty = true;
break;
case NV097_SET_COMBINER_COLOR_OCW ...
NV097_SET_COMBINER_COLOR_OCW + 28:
slot = (class_method - NV097_SET_COMBINER_COLOR_OCW) / 4;

View File

@ -34,6 +34,16 @@
#include "hw/xbox/nv2a_psh.h"
/*
* This implements translation of register combiners into glsl
* fragment shaders, but all terminology is in terms of Xbox DirectX
* pixel shaders, since I wanted to be lazy while referencing existing
* work / stealing code.
*
* For some background, see the OpenGL extension:
* https://www.opengl.org/registry/specs/NV/register_combiners.txt
*/
enum PS_TEXTUREMODES
{ // valid in stage 0 1 2 3
@ -263,8 +273,8 @@ static QString* get_var(struct PixelShader *ps, int reg, bool is_dest)
}
break;
case PS_REGISTER_FOG: // TODO
assert(false);
break;
//return qstring_from_str("fog");
return qstring_from_str("0.0");
case PS_REGISTER_V0:
return qstring_from_str("v0");
case PS_REGISTER_V1:
@ -491,7 +501,7 @@ static void add_final_stage_code(struct PixelShader *ps, struct FCInputInfo fina
QString *g = get_input_var(ps, final.g, false);
add_var_ref(ps, "r0");
qstring_append_fmt(ps->code, "r0.rgb = (%s * %s) + ((1.0 - %s) * %s) + %s;\n",
qstring_append_fmt(ps->code, "r0.rgb = vec3((%s * %s) + ((1.0 - %s) * %s) + %s);\n",
qstring_get_str(a), qstring_get_str(b),
qstring_get_str(a), qstring_get_str(c), qstring_get_str(d));
qstring_append_fmt(ps->code, "r0.a = %s;\n", qstring_get_str(g));