diff --git a/examples/gldemo/plane.h b/examples/gldemo/plane.h index 17898b53cf..21f952ca0b 100644 --- a/examples/gldemo/plane.h +++ b/examples/gldemo/plane.h @@ -34,6 +34,8 @@ void setup_plane() glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, plane_buffers[1]); + glBindVertexArray(0); } @@ -103,13 +105,9 @@ void make_plane_mesh() void draw_plane() { - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, plane_buffers[1]); glBindVertexArray(plane_array); - glDrawElements(GL_TRIANGLES, plane_index_count, GL_UNSIGNED_SHORT, 0); - glBindVertexArray(0); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); } void render_plane() diff --git a/examples/gldemo/sphere.h b/examples/gldemo/sphere.h index 8597a76d3f..d0bd2866f3 100644 --- a/examples/gldemo/sphere.h +++ b/examples/gldemo/sphere.h @@ -42,6 +42,8 @@ void setup_sphere() glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, sphere_buffers[1]); + glBindVertexArray(0); sphere_list = glGenLists(1); @@ -77,7 +79,6 @@ void make_sphere_vertex(vertex_t *dst, uint32_t ring, uint32_t segment) void draw_sphere_internal() { - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, sphere_buffers[1]); glBindVertexArray(sphere_array); glDrawElements(GL_TRIANGLE_FAN, sphere_segments + 2, GL_UNSIGNED_SHORT, 0); @@ -85,7 +86,6 @@ void draw_sphere_internal() glDrawElements(GL_TRIANGLES, (sphere_rings - 1) * (sphere_segments * 6), GL_UNSIGNED_SHORT, (void*)((sphere_segments + 2) * 2 * sizeof(uint16_t))); glBindVertexArray(0); - glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); } void make_sphere_mesh() diff --git a/include/GL/gl_enums.h b/include/GL/gl_enums.h index e8b543ae18..731ee32c86 100644 --- a/include/GL/gl_enums.h +++ b/include/GL/gl_enums.h @@ -15,6 +15,7 @@ #define GL_FLOAT 0x1406 #define GL_DOUBLE 0x140A #define GL_HALF_FIXED_N64 0x6F00 +#define GL_SHORT_5_6_5_N64 0x6F01 #define GL_NO_ERROR 0 #define GL_INVALID_ENUM 0x0500 diff --git a/src/GL/array.h b/src/GL/array.h new file mode 100644 index 0000000000..73ea2e615b --- /dev/null +++ b/src/GL/array.h @@ -0,0 +1,81 @@ +#ifndef __ARRAY_H +#define __ARRAY_H + +#include +#include "GL/gl.h" + +typedef enum { + ARRAY_VERTEX, + ARRAY_NORMAL, + ARRAY_COLOR, + ARRAY_TEXCOORD, + ARRAY_MTX_INDEX, + ARRAY_COUNT +} array_type_t; + +typedef struct gl_buffer_object_s gl_buffer_object_t; + +typedef void (*cpu_read_attrib_func)(void*,const void*,uint32_t); +typedef void (*rsp_read_attrib_func)(void*,const void*,uint32_t); + +typedef struct array_s { + GLint size; + GLenum type; + GLsizei stride; + const GLvoid *pointer; + gl_buffer_object_t *binding; + bool normalize; + bool enabled; + + const GLvoid *final_pointer; + uint16_t final_stride; + cpu_read_attrib_func cpu_read_func; + rsp_read_attrib_func rsp_read_func; +} array_t; + +#ifdef __cplusplus +extern "C" { +#endif + +inline uint32_t array_type_get_stride(array_type_t type) +{ + switch (type) + { + case ARRAY_VERTEX: + return sizeof(int16_t) * 3; + case ARRAY_NORMAL: + return sizeof(uint16_t); + case ARRAY_COLOR: + return sizeof(uint32_t); + case ARRAY_TEXCOORD: + return sizeof(int16_t) * 2; + case ARRAY_MTX_INDEX: + return sizeof(uint8_t); + default: + return 0; + } +} + +inline uint32_t array_type_get_alignment(array_type_t type) +{ + switch (type) + { + case ARRAY_VERTEX: + return 8; + case ARRAY_NORMAL: + return 2; + case ARRAY_COLOR: + return 4; + case ARRAY_TEXCOORD: + return 4; + case ARRAY_MTX_INDEX: + default: + return 1; + } +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/GL/array_convert.c b/src/GL/array_convert.c new file mode 100644 index 0000000000..5f6bf95564 --- /dev/null +++ b/src/GL/array_convert.c @@ -0,0 +1,15 @@ +#include "array_convert.h" + +void array_convert(array_convert_parms_t *parms) +{ + for (size_t i = 0; i < parms->range.count; i++) + { + for (size_t j = 0; j < parms->array_count; j++) + { + uint8_t *dst = ((uint8_t*)parms->out_buffer) + parms->out_layout->offsets[j] + i * parms->out_layout->stride; + const array_t *array = parms->arrays[j]; + const uint8_t *src = ((const uint8_t*)array->final_pointer) + (i+parms->range.first) * array->final_stride; + array->rsp_read_func(dst, src, array->size); + } + } +} diff --git a/src/GL/array_convert.h b/src/GL/array_convert.h new file mode 100644 index 0000000000..399d5235f5 --- /dev/null +++ b/src/GL/array_convert.h @@ -0,0 +1,26 @@ +#ifndef __ARRAY_CONVERT_H +#define __ARRAY_CONVERT_H + +#include "indices.h" +#include "array.h" +#include "data_source.h" + +typedef struct array_convert_parms_s { + const array_t *arrays[ARRAY_COUNT]; + uint32_t array_count; + const data_layout_t *out_layout; + index_bounds_t range; + void *out_buffer; +} array_convert_parms_t; + +#ifdef __cplusplus +extern "C" { +#endif + +void array_convert(array_convert_parms_t *parms); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/GL/array.c b/src/GL/array_module.c similarity index 66% rename from src/GL/array.c rename to src/GL/array_module.c index f7ffce03a6..17a328ddd0 100644 --- a/src/GL/array.c +++ b/src/GL/array_module.c @@ -1,10 +1,13 @@ /** - * @file array.c + * @file array_module.c * @author Dennis Heinze * @brief OpenGL array and attribute pointer management for vertex data. */ #include "gl_internal.h" #include "debug.h" +#include "array_object.h" +#include "draw_call_cache.h" +#include "buffer.h" #include extern gl_state_t *state; @@ -37,133 +40,45 @@ static const gl_interleaved_array_t interleaved_arrays[] = { /* GL_T4F_C4F_N3F_V4F */ { .et = true, .ec = true, .en = true, .st = 4, .sc = 4, .sv = 4, .tc = GL_FLOAT, .pc = 4*ILA_F, .pn = 8*ILA_F, .pv = 11*ILA_F, .s = 15*ILA_F }, }; -extern const cpu_read_attrib_func cpu_read_funcs[ATTRIB_COUNT][ATTRIB_TYPE_COUNT]; -extern const rsp_read_attrib_func rsp_read_funcs[ATTRIB_COUNT][ATTRIB_TYPE_COUNT]; - -gl_array_type_t gl_array_type_from_enum(GLenum array) +static array_type_t gl_array_type_from_enum(GLenum array) { switch (array) { case GL_VERTEX_ARRAY: - return ATTRIB_VERTEX; - case GL_TEXTURE_COORD_ARRAY: - return ATTRIB_TEXCOORD; + return ARRAY_VERTEX; case GL_NORMAL_ARRAY: - return ATTRIB_NORMAL; + return ARRAY_NORMAL; case GL_COLOR_ARRAY: - return ATTRIB_COLOR; + return ARRAY_COLOR; + case GL_TEXTURE_COORD_ARRAY: + return ARRAY_TEXCOORD; case GL_MATRIX_INDEX_ARRAY_ARB: - return ATTRIB_MTX_INDEX; + return ARRAY_MTX_INDEX; default: - return -1; + assertf(0, "Invalid array type!"); } } -void gl_update_array(gl_array_t *array, gl_array_type_t array_type) +void array_module_init() { - uint32_t size_shift = 0; - - switch (array->type) { - case GL_BYTE: - case GL_UNSIGNED_BYTE: - size_shift = 0; - break; - case GL_SHORT: - case GL_UNSIGNED_SHORT: - case GL_HALF_FIXED_N64: - size_shift = 1; - break; - case GL_INT: - case GL_UNSIGNED_INT: - case GL_FLOAT: - size_shift = 2; - break; - case GL_DOUBLE: - size_shift = 3; - break; - } - - array->final_stride = array->stride == 0 ? array->size << size_shift : array->stride; - - uint32_t func_index = gl_type_to_index(array->type); - array->cpu_read_func = cpu_read_funcs[array_type][func_index]; - array->rsp_read_func = rsp_read_funcs[array_type][func_index]; - - assertf(array->cpu_read_func != NULL, "CPU read function is missing"); - assertf(array->rsp_read_func != NULL, "RSP read function is missing"); + array_object_init(&state->default_array_object); + glBindVertexArray(0); } -void gl_update_array_pointer(gl_array_t *array) +void array_module_close() { - if (array->binding != NULL) { - array->final_pointer = array->binding->storage.data + (uint32_t)array->pointer; - } else { - array->final_pointer = array->pointer; - } -} - -void gl_update_array_pointers(gl_array_object_t *obj) -{ - for (uint32_t i = 0; i < ATTRIB_COUNT; i++) - { - gl_update_array_pointer(&obj->arrays[i]); - } -} - -void gl_array_object_init(gl_array_object_t *obj) -{ - obj->arrays[ATTRIB_VERTEX].size = 4; - obj->arrays[ATTRIB_VERTEX].type = GL_FLOAT; - obj->arrays[ATTRIB_COLOR].size = 4; - obj->arrays[ATTRIB_COLOR].type = GL_FLOAT; - obj->arrays[ATTRIB_COLOR].normalize = true; - obj->arrays[ATTRIB_TEXCOORD].size = 4; - obj->arrays[ATTRIB_TEXCOORD].type = GL_FLOAT; - obj->arrays[ATTRIB_NORMAL].size = 3; - obj->arrays[ATTRIB_NORMAL].type = GL_FLOAT; - obj->arrays[ATTRIB_NORMAL].normalize = true; - obj->arrays[ATTRIB_MTX_INDEX].size = 0; - obj->arrays[ATTRIB_MTX_INDEX].type = GL_UNSIGNED_BYTE; - - for (uint32_t i = 0; i < ATTRIB_COUNT; i++) - { - gl_update_array(&obj->arrays[i], i); - } + glBindVertexArray(0); + array_object_destroy(&state->default_array_object); } -void gl_array_init() +static void assert_valid_array(GLuint array) { - gl_array_object_init(&state->default_array_object); - state->array_object = &state->default_array_object; + assertf(array == 0 || is_valid_object_id(array), + "Not a valid array object: %#lx. Make sure to allocate IDs via glGenVertexArray", array); } -void gl_set_array(gl_array_type_t array_type, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +static void set_array_parms(array_type_t array_type, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) { - if (stride < 0) { - gl_set_error(GL_INVALID_VALUE, "Stride must not be negative"); - return; - } - - // From the spec (https://registry.khronos.org/OpenGL/extensions/ARB/ARB_vertex_array_object.txt): - // An INVALID_OPERATION error is generated if any of the *Pointer commands - // specifying the location and organization of vertex data are called while - // a non-zero vertex array object is bound, zero is bound to the - // ARRAY_BUFFER buffer object, and the pointer is not NULL[fn]. - // [fn: This error makes it impossible to create a vertex array - // object containing client array pointers.] - if (state->array_object != &state->default_array_object && state->array_buffer == NULL && pointer != NULL) { - gl_set_error(GL_INVALID_OPERATION, "Vertex array objects can only be used in conjunction with vertex buffer objects"); - return; - } - - gl_array_t *array = &state->array_object->arrays[array_type]; - - array->size = size; - array->type = type; - array->stride = stride; - array->pointer = pointer; - array->binding = state->array_buffer; - - gl_update_array(array, array_type); + array_object_set_array_params(state->array_object, array_type, size, type, stride, pointer); } void glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) @@ -192,7 +107,7 @@ void glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *poin return; } - gl_set_array(ATTRIB_VERTEX, size, type, stride, pointer); + set_array_parms(ARRAY_VERTEX, size, type, stride, pointer); } void glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) @@ -222,7 +137,7 @@ void glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *po return; } - gl_set_array(ATTRIB_TEXCOORD, size, type, stride, pointer); + set_array_parms(ARRAY_TEXCOORD, size, type, stride, pointer); } void glNormalPointer(GLenum type, GLsizei stride, const GLvoid *pointer) @@ -235,13 +150,14 @@ void glNormalPointer(GLenum type, GLsizei stride, const GLvoid *pointer) case GL_INT: case GL_FLOAT: case GL_DOUBLE: + case GL_SHORT_5_6_5_N64: break; default: gl_set_error(GL_INVALID_ENUM, "%#04lx is not a valid normal data type", type); return; } - gl_set_array(ATTRIB_NORMAL, 3, type, stride, pointer); + set_array_parms(ARRAY_NORMAL, 3, type, stride, pointer); } void glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) @@ -272,7 +188,7 @@ void glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *point return; } - gl_set_array(ATTRIB_COLOR, size, type, stride, pointer); + set_array_parms(ARRAY_COLOR, size, type, stride, pointer); } void glMatrixIndexPointerARB(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) @@ -294,13 +210,12 @@ void glMatrixIndexPointerARB(GLint size, GLenum type, GLsizei stride, const GLvo return; } - gl_set_array(ATTRIB_MTX_INDEX, size, type, stride, pointer); + set_array_parms(ARRAY_MTX_INDEX, size, type, stride, pointer); } -void gl_set_array_enabled(gl_array_type_t array_type, bool enabled) +static void set_array_enabled(array_type_t array_type, bool enabled) { - gl_array_t *array = &state->array_object->arrays[array_type]; - array->enabled = enabled; + array_object_set_array_enabled(state->array_object, array_type, enabled); } void glEnableClientState(GLenum array) @@ -313,7 +228,7 @@ void glEnableClientState(GLenum array) case GL_NORMAL_ARRAY: case GL_COLOR_ARRAY: case GL_MATRIX_INDEX_ARRAY_ARB: - gl_set_array_enabled(gl_array_type_from_enum(array), true); + set_array_enabled(gl_array_type_from_enum(array), true); break; case GL_EDGE_FLAG_ARRAY: case GL_INDEX_ARRAY: @@ -333,7 +248,7 @@ void glDisableClientState(GLenum array) case GL_NORMAL_ARRAY: case GL_COLOR_ARRAY: case GL_MATRIX_INDEX_ARRAY_ARB: - gl_set_array_enabled(gl_array_type_from_enum(array), false); + set_array_enabled(gl_array_type_from_enum(array), false); break; case GL_EDGE_FLAG_ARRAY: case GL_INDEX_ARRAY: @@ -406,9 +321,9 @@ void glGenVertexArrays(GLsizei n, GLuint *arrays) for (GLsizei i = 0; i < n; i++) { - gl_array_object_t *new_obj = calloc(sizeof(gl_array_object_t), 1); + gl_array_object_t *new_obj = calloc(1, sizeof(gl_array_object_t)); assertf(new_obj, "Out of memory"); - gl_array_object_init(new_obj); + array_object_init(new_obj); arrays[i] = (GLuint)new_obj; } } @@ -419,8 +334,7 @@ void glDeleteVertexArrays(GLsizei n, const GLuint *arrays) for (GLsizei i = 0; i < n; i++) { - assertf(arrays[i] == 0 || is_valid_object_id(arrays[i]), - "Not a valid array object: %#lx. Make sure to allocate IDs via glGenVertexArray", arrays[i]); + assert_valid_array(arrays[i]); gl_array_object_t *obj = (gl_array_object_t*)arrays[i]; if (obj == NULL) { @@ -431,6 +345,7 @@ void glDeleteVertexArrays(GLsizei n, const GLuint *arrays) glBindVertexArray(0); } + array_object_destroy(obj); free(obj); } } @@ -438,8 +353,7 @@ void glDeleteVertexArrays(GLsizei n, const GLuint *arrays) void glBindVertexArray(GLuint array) { if (!gl_ensure_no_begin_end()) return; - assertf(array == 0 || is_valid_object_id(array), - "Not a valid array object: %#lx. Make sure to allocate IDs via glGenVertexArray", array); + assert_valid_array(array); gl_array_object_t *obj = (gl_array_object_t*)array; diff --git a/src/GL/array_module.h b/src/GL/array_module.h new file mode 100644 index 0000000000..00a14db51d --- /dev/null +++ b/src/GL/array_module.h @@ -0,0 +1,15 @@ +#ifndef __ARRAY_MODULE_H +#define __ARRAY_MODULE_H + +#ifdef __cplusplus +extern "C" { +#endif + +void array_module_init(); +void array_module_close(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/GL/array_object.c b/src/GL/array_object.c new file mode 100644 index 0000000000..038a578aa6 --- /dev/null +++ b/src/GL/array_object.c @@ -0,0 +1,346 @@ +#include "array_object.h" +#include +#include "gl_internal.h" +#include "buffer.h" +#include "pipelines.h" +#include "draw_call_cache.h" + +extern gl_state_t *state; + +extern const cpu_read_attrib_func cpu_read_funcs[ARRAY_COUNT][ATTRIB_TYPE_COUNT]; +extern const rsp_read_attrib_func rsp_read_funcs[ARRAY_COUNT][ATTRIB_TYPE_COUNT]; + +static uint16_t get_stride_from_size_and_type(GLint size, GLenum type) +{ + if (type == GL_SHORT_5_6_5_N64) { + return sizeof(GLshort); + } + + uint32_t size_shift = 0; + + switch (type) { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + size_shift = 0; + break; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_HALF_FIXED_N64: + size_shift = 1; + break; + case GL_INT: + case GL_UNSIGNED_INT: + case GL_FLOAT: + size_shift = 2; + break; + case GL_DOUBLE: + size_shift = 3; + break; + } + + return size << size_shift; +} + +static void update_array(array_t *array, array_type_t array_type) +{ + array->final_stride = array->stride == 0 ? get_stride_from_size_and_type(array->size, array->type) : array->stride; + + uint32_t func_index = gl_type_to_index(array->type); + array->cpu_read_func = cpu_read_funcs[array_type][func_index]; + array->rsp_read_func = rsp_read_funcs[array_type][func_index]; + + assertf(array->cpu_read_func != NULL, "CPU read function is missing"); + assertf(array->rsp_read_func != NULL, "RSP read function is missing"); +} + +void array_object_init(gl_array_object_t *array_object) +{ + array_object->arrays[ARRAY_VERTEX].size = 4; + array_object->arrays[ARRAY_VERTEX].type = GL_FLOAT; + array_object->arrays[ARRAY_NORMAL].size = 3; + array_object->arrays[ARRAY_NORMAL].type = GL_FLOAT; + array_object->arrays[ARRAY_NORMAL].normalize = true; + array_object->arrays[ARRAY_COLOR].size = 4; + array_object->arrays[ARRAY_COLOR].type = GL_FLOAT; + array_object->arrays[ARRAY_COLOR].normalize = true; + array_object->arrays[ARRAY_TEXCOORD].size = 4; + array_object->arrays[ARRAY_TEXCOORD].type = GL_FLOAT; + array_object->arrays[ARRAY_MTX_INDEX].size = 0; + array_object->arrays[ARRAY_MTX_INDEX].type = GL_UNSIGNED_BYTE; + + for (array_type_t i = 0; i < ARRAY_COUNT; i++) + { + update_array(&array_object->arrays[i], i); + } + + data_source_init(&array_object->vertex_data_source, array_object->arrays, ARRAY_MASK_VERTEX | ARRAY_MASK_NORMAL | ARRAY_MASK_COLOR | ARRAY_MASK_TEXCOORD); + data_source_init(&array_object->mtx_index_data_source, array_object->arrays, ARRAY_MASK_MTX_INDEX); + + data_cache_init(&array_object->vertex_data_cache, &array_object->vertex_data_source); + data_cache_init(&array_object->mtx_index_data_cache, &array_object->mtx_index_data_source); + + vertex_layout_cache_init(&array_object->layout_cache); +} + +void array_object_destroy(gl_array_object_t *array_object) +{ + if (array_object->draw_call_cache != NULL) { + draw_call_cache_free(array_object->draw_call_cache); + } + + data_cache_destroy(&array_object->mtx_index_data_cache); + data_cache_destroy(&array_object->vertex_data_cache); + + array_object_set_element_buffer_binding(array_object, NULL); + + for (array_type_t i = 0; i < ARRAY_COUNT; i++) + { + array_object_set_buffer_binding(array_object, i, NULL); + } +} + +static data_source_t *get_data_source(gl_array_object_t *array_object, array_type_t array_type) +{ + switch (array_type) + { + case ARRAY_VERTEX: + case ARRAY_NORMAL: + case ARRAY_COLOR: + case ARRAY_TEXCOORD: + return &array_object->vertex_data_source; + case ARRAY_MTX_INDEX: + return &array_object->mtx_index_data_source; + default: + assertf(0, "invalid array type"); + } +} + +static data_cache_t *get_data_cache(gl_array_object_t *array_object, array_type_t array_type) +{ + switch (array_type) + { + case ARRAY_VERTEX: + case ARRAY_NORMAL: + case ARRAY_COLOR: + case ARRAY_TEXCOORD: + return &array_object->vertex_data_cache; + case ARRAY_MTX_INDEX: + return &array_object->mtx_index_data_cache; + default: + assertf(0, "invalid array type"); + } +} + +static void invalidate_array_data(gl_array_object_t *array_object, array_type_t array_type) +{ + data_cache_t *data_cache = get_data_cache(array_object, array_type); + data_cache_invalidate(data_cache); + + if (data_cache == &array_object->mtx_index_data_cache && array_object->draw_call_cache != NULL) { + draw_call_cache_invalidate_mtx_indices(array_object->draw_call_cache); + } +} + +static void invalidate_array(gl_array_object_t *array_object, array_type_t array_type) +{ + data_source_t *data_source = get_data_source(array_object, array_type); + data_source_invalidate_arrays(data_source); + + invalidate_array_data(array_object, array_type); +} + +void array_object_set_array_enabled(gl_array_object_t *array_object, array_type_t array_type, bool enabled) +{ + array_t *array = &array_object->arrays[array_type]; + if (array->enabled != enabled) { + array->enabled = enabled; + invalidate_array(array_object, array_type); + vertex_layout_cache_invalidate(&array_object->layout_cache); + } +} + +void array_object_set_array_params(gl_array_object_t *array_object, array_type_t array_type, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) +{ + if (stride < 0) { + gl_set_error(GL_INVALID_VALUE, "Stride must not be negative"); + return; + } + + // From the spec (https://registry.khronos.org/OpenGL/extensions/ARB/ARB_vertex_array_object.txt): + // An INVALID_OPERATION error is generated if any of the *Pointer commands + // specifying the location and organization of vertex data are called while + // a non-zero vertex array object is bound, zero is bound to the + // ARRAY_BUFFER buffer object, and the pointer is not NULL[fn]. + // [fn: This error makes it impossible to create a vertex array + // object containing client array pointers.] + if (array_object != &state->default_array_object && state->array_buffer == NULL && pointer != NULL) { + gl_set_error(GL_INVALID_OPERATION, "Vertex array objects can only be used in conjunction with vertex buffer objects"); + return; + } + + array_t *array = &array_object->arrays[array_type]; + + array->size = size; + array->type = type; + array->stride = stride; + array->pointer = pointer; + array_object_set_buffer_binding(array_object, array_type, state->array_buffer); + + update_array(array, array_type); + invalidate_array(array_object, array_type); +} + +static bool set_buffer_binding(gl_array_object_t *array_object, gl_buffer_object_t **binding, gl_buffer_object_t *buffer) +{ + if (*binding == buffer) return false; + + if (*binding != NULL) { + gl_buffer_remove_array_ref(*binding, array_object); + } + if (buffer != NULL) { + gl_buffer_add_array_ref(buffer, array_object); + } + *binding = buffer; + + return true; +} + +void array_object_set_buffer_binding(gl_array_object_t *array_object, array_type_t array_type, gl_buffer_object_t *buffer) +{ + if (set_buffer_binding(array_object, &array_object->arrays[array_type].binding, buffer)) { + invalidate_array(array_object, array_type); + } +} + +static void invalidate_indices(gl_array_object_t *array_object) +{ + if (array_object->draw_call_cache != NULL) { + draw_call_cache_invalidate_indices(array_object->draw_call_cache); + } +} + +void array_object_set_element_buffer_binding(gl_array_object_t *array_object, gl_buffer_object_t *buffer) +{ + if (set_buffer_binding(array_object, &array_object->element_array_buffer, buffer)) { + invalidate_indices(array_object); + } +} + +void array_object_invalidate_buffer_data(gl_array_object_t *array_object, gl_buffer_object_t *buffer) +{ + for (array_type_t i = 0; i < ARRAY_COUNT; i++) + { + if (array_object->arrays[i].binding == buffer) { + invalidate_array_data(array_object, i); + } + } + + if (array_object->element_array_buffer == buffer) { + invalidate_indices(array_object); + } +} + +void array_object_validate_drawing(gl_array_object_t *array_object, bool indexed) +{ + for (array_type_t i = 0; i < ARRAY_COUNT; i++) + { + array_t *array = &array_object->arrays[i]; + if (array->enabled && array->binding != NULL) { + buffer_object_validate_not_mapped(array_object->arrays[i].binding); + } + } + + if (indexed && array_object->element_array_buffer != NULL) { + buffer_object_validate_not_mapped(array_object->element_array_buffer); + } +} + +static void update_array_pointer(array_t *array) +{ + if (array->binding != NULL) { + array->final_pointer = array->binding->storage.data + (uint32_t)array->pointer; + } else { + array->final_pointer = array->pointer; + } +} + +void array_object_update_pointers(gl_array_object_t *array_object) +{ + for (array_type_t i = 0; i < ARRAY_COUNT; i++) + { + update_array_pointer(&array_object->arrays[i]); + } +} + +static draw_call_cache_t **get_current_draw_call_cache_pointer(gl_array_object_t *array_object) +{ + bool is_matrix_index_array_enabled = array_object->arrays[ARRAY_MTX_INDEX].enabled; + if (is_matrix_index_array_enabled) { + return &array_object->draw_call_cache; + } + + assertf(array_object->element_array_buffer != NULL, "element array buffer is not bound!"); + return &array_object->element_array_buffer->element_cache; +} + +draw_call_cache_t *array_object_get_draw_call_cache(gl_array_object_t *array_object) +{ + draw_call_cache_t **draw_call_cache = get_current_draw_call_cache_pointer(array_object); + if (*draw_call_cache == NULL) { + *draw_call_cache = draw_call_cache_create(); + } + return *draw_call_cache; +} + +static mg_primitive_topology_t get_primitive_topology(GLenum mode) +{ + switch (mode) + { + case GL_TRIANGLES: + return MG_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + case GL_TRIANGLE_STRIP: + case GL_QUAD_STRIP: + return MG_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + case GL_TRIANGLE_FAN: + case GL_QUADS: + case GL_POLYGON: + return MG_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN; + + case GL_POINTS: + case GL_LINES: + case GL_LINE_LOOP: + case GL_LINE_STRIP: + assertf(0, "Draw mode %ld is not supported", mode); + default: + gl_set_error(GL_INVALID_ENUM, "%#04lx is not a valid primitive mode", mode); + return -1; + } +} + +static bool get_is_restart_enabled(GLenum mode) +{ + return mode == GL_QUADS; +} + +mg_input_assembly_parms_t array_object_get_input_assembly_parms(gl_array_object_t *array_object, GLenum mode, index_bounds_t bounds) +{ + mg_input_assembly_parms_t parms; + + parms.primitive_topology = get_primitive_topology(mode); + parms.primitive_restart_enabled = get_is_restart_enabled(mode); + + array_t *mtx_index_array = &array_object->arrays[ARRAY_MTX_INDEX]; + if (mtx_index_array->enabled) { + data_view_t mtx_index_data = data_cache_prepare_at_bounds(&array_object->mtx_index_data_cache, bounds); + + parms.mtx_indices = mtx_index_data.pointer; + parms.mtx_indices_stride = mtx_index_data.stride; + parms.matrices = state->matrix_palette; + parms.matrices_stride = sizeof(state->matrix_palette[0]); + parms.matrix_uniform = *get_matrices_uniform(); + } else { + parms.mtx_indices = NULL; + } + + return parms; +} diff --git a/src/GL/array_object.h b/src/GL/array_object.h new file mode 100644 index 0000000000..5d56b877fd --- /dev/null +++ b/src/GL/array_object.h @@ -0,0 +1,45 @@ +#ifndef __ARRAY_OBJECT_H +#define __ARRAY_OBJECT_H + +#include "array.h" +#include "data_source.h" +#include "data_cache.h" +#include "vertex_layout_cache.h" + +typedef struct gl_buffer_object_s gl_buffer_object_t; +typedef struct draw_call_cache_s draw_call_cache_t; + +typedef struct gl_array_object_s { + array_t arrays[ARRAY_COUNT]; + gl_buffer_object_t *element_array_buffer; + vertex_layout_cache_t layout_cache; + data_source_t vertex_data_source, mtx_index_data_source; + data_cache_t vertex_data_cache, mtx_index_data_cache; + draw_call_cache_t *draw_call_cache; +} gl_array_object_t; + +#ifdef __cplusplus +extern "C" { +#endif + +void array_object_init(gl_array_object_t *array_object); +void array_object_destroy(gl_array_object_t *array_object); + +void array_object_set_array_enabled(gl_array_object_t *array_object, array_type_t array_type, bool enabled); +void array_object_set_array_params(gl_array_object_t *array_object, array_type_t array_type, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); + +void array_object_set_buffer_binding(gl_array_object_t *array_object, array_type_t array_type, gl_buffer_object_t *buffer); +void array_object_set_element_buffer_binding(gl_array_object_t *array_object, gl_buffer_object_t *buffer); +void array_object_invalidate_buffer_data(gl_array_object_t *array_object, gl_buffer_object_t *buffer); +void array_object_validate_drawing(gl_array_object_t *array_object, bool indexed); + +void array_object_update_pointers(gl_array_object_t *array_object); + +draw_call_cache_t *array_object_get_draw_call_cache(gl_array_object_t *array_object); +mg_input_assembly_parms_t array_object_get_input_assembly_parms(gl_array_object_t *array_object, GLenum mode, index_bounds_t bounds); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/GL/buffer.c b/src/GL/buffer.c index 1866660743..3333cc52db 100644 --- a/src/GL/buffer.c +++ b/src/GL/buffer.c @@ -3,7 +3,10 @@ * @author Dennis Heinze * @brief OpenGL buffer object management and data transfer. */ +#include "buffer.h" #include "gl_internal.h" +#include "array_object.h" +#include "draw_call_cache.h" #include #include #include @@ -19,6 +22,54 @@ GLboolean glIsBufferARB(GLuint buffer) return is_valid_object_id(buffer); } +static void buffer_object_free(gl_buffer_object_t *obj) +{ + gl_storage_free(&obj->storage); + + if (obj->element_cache != NULL) + { + draw_call_cache_free(obj->element_cache); + } + + assertf(obj->array_obj_ref == NULL, "Freeing a buffer object that still had references to array objects: %p", obj); + + free(obj); +} + +void buffer_object_refcount_incr(gl_buffer_object_t *obj) +{ + ++obj->ref_count; +} + +void buffer_object_refcount_decr(gl_buffer_object_t *obj) +{ + assertf(obj->ref_count > 0, "Decreasing reference count of a buffer object that already has 0 references: %p", obj); + + if (--obj->ref_count == 0) { + buffer_object_free(obj); + } +} + +void buffer_object_validate_not_mapped(gl_buffer_object_t *obj) +{ + if (obj->mapped) { + gl_set_error(GL_INVALID_OPERATION, "Accessing buffer object for drawing while it is mapped: %p", obj); + } +} + +static void set_array_buffer_binding(gl_buffer_object_t *obj) +{ + if (obj == state->array_buffer) return; + + if (state->array_buffer != NULL) { + buffer_object_refcount_decr(state->array_buffer); + } + if (obj != NULL) { + buffer_object_refcount_incr(obj); + } + state->array_buffer = obj; +} + void glBindBufferARB(GLenum target, GLuint buffer) { if (!gl_ensure_no_begin_end()) return; @@ -29,10 +80,10 @@ void glBindBufferARB(GLenum target, GLuint buffer) switch (target) { case GL_ARRAY_BUFFER_ARB: - state->array_buffer = obj; + set_array_buffer_binding(obj); break; case GL_ELEMENT_ARRAY_BUFFER_ARB: - state->element_array_buffer = obj; + array_object_set_element_buffer_binding(state->array_object, obj); break; default: gl_set_error(GL_INVALID_ENUM, "%#04lx is not a valid buffer target", target); @@ -40,13 +91,6 @@ void glBindBufferARB(GLenum target, GLuint buffer) } } -void gl_unbind_buffer(gl_buffer_object_t *obj, gl_buffer_object_t **binding) -{ - if (*binding == obj) { - *binding = NULL; - } -} - void glDeleteBuffersARB(GLsizei n, const GLuint *buffers) { if (!gl_ensure_no_begin_end()) return; @@ -61,29 +105,23 @@ void glDeleteBuffersARB(GLsizei n, const GLuint *buffers) continue; } - gl_unbind_buffer(obj, &state->array_buffer); - gl_unbind_buffer(obj, &state->element_array_buffer); - - for (uint32_t a = 0; a < ATTRIB_COUNT; a++) - { - // FIXME: From the spec: - // (2) What happens when a buffer object that is attached to a non-current - // VAO is deleted? - // RESOLUTION: Nothing (though a reference count may be decremented). - // A buffer object that is deleted while attached to a non-current VAO - // is treated just like a buffer object bound to another context (or to - // a current VAO in another context). - gl_unbind_buffer(obj, &state->array_object->arrays[a].binding); + // Deleting a buffer object will automatically unbind it from GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER + if (state->array_buffer == obj) { + set_array_buffer_binding(NULL); + } + if (state->array_object->element_array_buffer == obj) { + array_object_set_element_buffer_binding(state->array_object, NULL); } - // TODO: keep alive until no longer in use - - if (obj->storage.data != NULL) - { - free_uncached(obj->storage.data); + // Deleting a buffer object will automatically unbind it from all arrays in the currently bound VAO + for (array_type_t a = 0; a < ARRAY_COUNT; a++) { + if (state->array_object->arrays[a].binding == obj) { + array_object_set_buffer_binding(state->array_object, a, NULL); + } } - free(obj); + // Remove the reference that corresponds to the name that is being deleted + buffer_object_refcount_decr(obj); } } @@ -93,10 +131,13 @@ void glGenBuffersARB(GLsizei n, GLuint *buffers) for (GLsizei i = 0; i < n; i++) { - gl_buffer_object_t *new_obj = calloc(sizeof(gl_buffer_object_t), 1); + gl_buffer_object_t *new_obj = calloc(1, sizeof(gl_buffer_object_t)); assertf(new_obj, "Out of memory"); new_obj->usage = GL_STATIC_DRAW_ARB; new_obj->access = GL_READ_WRITE_ARB; + // Being assigned a "name" (the ID returned by this function) counts as a reference. + // Deleting the name using glDeleteBuffersARB removes that reference. + new_obj->ref_count = 1; buffers[i] = (GLuint)new_obj; } } @@ -108,7 +149,7 @@ bool gl_get_buffer_object(GLenum target, gl_buffer_object_t **obj) *obj = state->array_buffer; break; case GL_ELEMENT_ARRAY_BUFFER_ARB: - *obj = state->element_array_buffer; + *obj = state->array_object->element_array_buffer; break; default: gl_set_error(GL_INVALID_ENUM, "%#04lx is not a valid buffer target", target); @@ -123,6 +164,20 @@ bool gl_get_buffer_object(GLenum target, gl_buffer_object_t **obj) return true; } +static void invalidate_data(gl_buffer_object_t *obj) +{ + if (obj->element_cache != NULL) { + draw_call_cache_invalidate_indices(obj->element_cache); + } + + // Inform all array objects that are bound to this buffer + gl_array_object_ref_t *array_ref = obj->array_obj_ref; + while (array_ref != NULL) { + array_object_invalidate_buffer_data(array_ref->array_object, obj); + array_ref = array_ref->next; + } +} + void glBufferDataARB(GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage) { if (!gl_ensure_no_begin_end()) return; @@ -166,6 +221,8 @@ void glBufferDataARB(GLenum target, GLsizeiptrARB size, const GLvoid *data, GLen obj->access = GL_READ_WRITE_ARB; obj->mapped = false; obj->pointer = NULL; + + invalidate_data(obj); } void glBufferSubDataARB(GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data) @@ -193,6 +250,8 @@ void glBufferSubDataARB(GLenum target, GLintptrARB offset, GLsizeiptrARB size, c } memcpy(obj->storage.data + offset, data, size); + + invalidate_data(obj); } void glGetBufferSubDataARB(GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data) @@ -270,6 +329,9 @@ GLboolean glUnmapBufferARB(GLenum target) obj->mapped = false; obj->pointer = NULL; + if (obj->access != GL_READ_ONLY_ARB) { + invalidate_data(obj); + } return GL_TRUE; } @@ -317,3 +379,48 @@ void glGetBufferPointervARB(GLenum target, GLenum pname, GLvoid **params) *params = obj->pointer; } + +void gl_buffer_add_array_ref(gl_buffer_object_t *buffer, gl_array_object_t *array) +{ + // Add to linked list of references, if not already present + gl_array_object_ref_t **ref = &buffer->array_obj_ref; + + while (*ref != NULL) { + // array object is already in the list -> increase reference count + if ((*ref)->array_object == array) { + (*ref)->refcount++; + return; + } + ref = &(*ref)->next; + } + + // Append to the end of the list and set reference count to 1 + *ref = malloc(sizeof(gl_array_object_ref_t)); + (*ref)->array_object = array; + (*ref)->next = NULL; + (*ref)->refcount = 1; + + buffer_object_refcount_incr(buffer); +} + +void gl_buffer_remove_array_ref(gl_buffer_object_t *buffer, gl_array_object_t *array) +{ + // Remove from linked list of references + gl_array_object_ref_t **ref = &buffer->array_obj_ref; + + while (*ref != NULL) { + if ((*ref)->array_object == array) { + // If found, decrease reference count + if (--(*ref)->refcount > 0) { + return; + } + // If reference count reached zero, remove item + gl_array_object_ref_t *current = *ref; + *ref = current->next; + free(current); + buffer_object_refcount_decr(buffer); + break; + } + ref = &(*ref)->next; + } +} diff --git a/src/GL/buffer.h b/src/GL/buffer.h new file mode 100644 index 0000000000..6e0fb72104 --- /dev/null +++ b/src/GL/buffer.h @@ -0,0 +1,50 @@ +#ifndef __BUFFER_H +#define __BUFFER_H + +#include +#include +#include "GL/gl.h" + +typedef struct { + GLvoid *data; + uint32_t size; +} gl_storage_t; + +typedef struct gl_array_object_s gl_array_object_t; +typedef struct gl_array_object_ref_s gl_array_object_ref_t; +typedef struct draw_call_cache_s draw_call_cache_t; + +typedef struct gl_array_object_ref_s { + gl_array_object_t *array_object; + gl_array_object_ref_t *next; + uint32_t refcount; +} gl_array_object_ref_t; + +typedef struct gl_buffer_object_s { + GLenum usage; + GLenum access; + GLvoid *pointer; + gl_storage_t storage; + bool mapped; + gl_array_object_ref_t *array_obj_ref; + draw_call_cache_t *element_cache; + uint32_t ref_count; +} gl_buffer_object_t; + +#ifdef __cplusplus +extern "C" { +#endif + +bool gl_storage_alloc(gl_storage_t *storage, uint32_t size); +void gl_storage_free(gl_storage_t *storage); +bool gl_storage_resize(gl_storage_t *storage, uint32_t new_size); + +void gl_buffer_add_array_ref(gl_buffer_object_t *buffer, gl_array_object_t *array); +void gl_buffer_remove_array_ref(gl_buffer_object_t *buffer, gl_array_object_t *array); +void buffer_object_validate_not_mapped(gl_buffer_object_t *obj); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/GL/cpu_pipeline.c b/src/GL/cpu_pipeline.c index 189a8e78b5..adb5791afb 100644 --- a/src/GL/cpu_pipeline.c +++ b/src/GL/cpu_pipeline.c @@ -8,6 +8,11 @@ extern gl_state_t *state; +#define VTX_SCREEN_POS_OFFSET (offsetof(gl_vtx_t, screen_pos) / sizeof(float)) +#define VTX_SHADE_OFFSET (offsetof(gl_vtx_t, shade) / sizeof(float)) +#define VTX_TEXCOORD_OFFSET (offsetof(gl_vtx_t, texcoord) / sizeof(float)) +#define VTX_DEPTH_OFFSET (offsetof(gl_vtx_t, depth) / sizeof(float)) + static const float clip_planes[CLIPPING_PLANE_COUNT][4] = { { 1, 0, 0, GUARD_BAND_FACTOR }, { 0, 1, 0, GUARD_BAND_FACTOR }, @@ -97,7 +102,15 @@ static void read_u32_i(GLubyte *dst, const uint32u_t *src, uint32_t count) for (uint32_t i = 0; i < count; i++) dst[i] = src[i]; } -const cpu_read_attrib_func cpu_read_funcs[ATTRIB_COUNT][ATTRIB_TYPE_COUNT] = { +static void read_packed565n(GLfloat *dst, const uint16u_t *src, uint32_t count) +{ + uint16_t v = *src; + dst[0] = ((v>>11)&0x1F) / 15.5f; + dst[1] = ((v>>5)&0x3F) / 31.5f; + dst[2] = ((v>>0)&0x1F) / 15.5f; +} + +const cpu_read_attrib_func cpu_read_funcs[ARRAY_COUNT][ATTRIB_TYPE_COUNT] = { { (cpu_read_attrib_func)read_i8, NULL, @@ -108,6 +121,19 @@ const cpu_read_attrib_func cpu_read_funcs[ATTRIB_COUNT][ATTRIB_TYPE_COUNT] = { (cpu_read_attrib_func)read_f32, (cpu_read_attrib_func)read_f64, (cpu_read_attrib_func)read_x16_vtx, + NULL, + }, + { + (cpu_read_attrib_func)read_i8n, + NULL, + (cpu_read_attrib_func)read_i16n, + NULL, + (cpu_read_attrib_func)read_i32n, + NULL, + (cpu_read_attrib_func)read_f32, + (cpu_read_attrib_func)read_f64, + NULL, + (cpu_read_attrib_func)read_packed565n, }, { (cpu_read_attrib_func)read_i8n, @@ -119,6 +145,7 @@ const cpu_read_attrib_func cpu_read_funcs[ATTRIB_COUNT][ATTRIB_TYPE_COUNT] = { (cpu_read_attrib_func)read_f32, (cpu_read_attrib_func)read_f64, NULL, + NULL, }, { (cpu_read_attrib_func)read_i8, @@ -130,16 +157,6 @@ const cpu_read_attrib_func cpu_read_funcs[ATTRIB_COUNT][ATTRIB_TYPE_COUNT] = { (cpu_read_attrib_func)read_f32, (cpu_read_attrib_func)read_f64, (cpu_read_attrib_func)read_x16_tex, - }, - { - (cpu_read_attrib_func)read_i8n, - NULL, - (cpu_read_attrib_func)read_i16n, - NULL, - (cpu_read_attrib_func)read_i32n, - NULL, - (cpu_read_attrib_func)read_f32, - (cpu_read_attrib_func)read_f64, NULL, }, { @@ -152,13 +169,212 @@ const cpu_read_attrib_func cpu_read_funcs[ATTRIB_COUNT][ATTRIB_TYPE_COUNT] = { NULL, NULL, NULL, + NULL, }, }; +uint8_t gl_points(); +uint8_t gl_lines(); +uint8_t gl_line_strip(); +uint8_t gl_triangles(); +uint8_t gl_triangle_strip(); +uint8_t gl_triangle_fan(); +uint8_t gl_quads(); + +void gl_reset_vertex_cache(); + static void gl_clip_triangle(); static void gl_clip_line(); static void gl_clip_point(); +bool gl_init_prim_assembly(GLenum mode) +{ + state->lock_next_vertex = false; + + switch (mode) { + case GL_POINTS: + state->prim_func = gl_points; + state->prim_size = 1; + break; + case GL_LINES: + state->prim_func = gl_lines; + state->prim_size = 2; + break; + case GL_LINE_LOOP: + // Line loop is equivalent to line strip, except for special case handled in glEnd + state->prim_func = gl_line_strip; + state->prim_size = 2; + state->lock_next_vertex = true; + break; + case GL_LINE_STRIP: + state->prim_func = gl_line_strip; + state->prim_size = 2; + break; + case GL_TRIANGLES: + state->prim_func = gl_triangles; + state->prim_size = 3; + break; + case GL_TRIANGLE_STRIP: + state->prim_func = gl_triangle_strip; + state->prim_size = 3; + break; + case GL_TRIANGLE_FAN: + state->prim_func = gl_triangle_fan; + state->prim_size = 3; + state->lock_next_vertex = true; + break; + case GL_QUADS: + state->prim_func = gl_quads; + state->prim_size = 3; + break; + case GL_QUAD_STRIP: + // Quad strip is equivalent to triangle strip + state->prim_func = gl_triangle_strip; + state->prim_size = 3; + break; + case GL_POLYGON: + // Polygon is equivalent to triangle fan + state->prim_func = gl_triangle_fan; + state->prim_size = 3; + state->lock_next_vertex = true; + break; + default: + gl_set_error(GL_INVALID_ENUM, "%#04lx is not a valid primitive mode", mode); + return false; + } + + state->primitive_mode = mode; + state->prim_progress = 0; + state->prim_counter = 0; + state->prim_id = 0x80000000; + + return true; +} + +void gl_reset_vertex_cache() +{ + memset(state->vertex_cache_ids, 0, sizeof(state->vertex_cache_ids)); + memset(state->lru_age_table, 0, sizeof(state->lru_age_table)); + state->lru_next_age = 1; +} + +bool gl_check_vertex_cache(uint32_t id, uint8_t *cache_index, bool lock) +{ + const uint32_t INFINITE_AGE = 0xFFFFFFFF; // infinitely recent + + bool miss = true; + + uint32_t min_age = INFINITE_AGE; + for (uint8_t ci = 0; ci < VERTEX_CACHE_SIZE; ci++) + { + if (state->vertex_cache_ids[ci] == id) { + miss = false; + *cache_index = ci; + break; + } + + if (state->lru_age_table[ci] < min_age) { + min_age = state->lru_age_table[ci]; + *cache_index = ci; + } + } + + uint32_t age = lock ? INFINITE_AGE : state->lru_next_age++; + state->lru_age_table[*cache_index] = age; + state->vertex_cache_ids[*cache_index] = id; + + return miss; +} + +bool gl_get_cache_index(uint32_t vertex_id, uint8_t *cache_index) +{ + bool result = gl_check_vertex_cache(vertex_id + 1, cache_index, state->lock_next_vertex); + + if (state->lock_next_vertex) { + state->lock_next_vertex = false; + state->locked_vertex = *cache_index; + } + + return result; +} + +uint8_t gl_points() +{ + // Reset the progress to zero since we start with a completely new primitive that + // won't share any vertices with the previous ones + return 0; +} + +uint8_t gl_lines() +{ + // Reset the progress to zero since we start with a completely new primitive that + // won't share any vertices with the previous ones + return 0; +} + +uint8_t gl_line_strip() +{ + state->prim_indices[0] = state->prim_indices[1]; + + return 1; +} + +uint8_t gl_triangles() +{ + // Reset the progress to zero since we start with a completely new primitive that + // won't share any vertices with the previous ones + return 0; +} + +uint8_t gl_triangle_strip() +{ + // Which vertices are shared depends on whether the primitive counter is odd or even + state->prim_indices[state->prim_counter] = state->prim_indices[2]; + state->prim_counter ^= 1; + + // The next triangle will share two vertices with the previous one, so reset progress to 2 + return 2; +} + +uint8_t gl_triangle_fan() +{ + state->prim_indices[1] = state->prim_indices[2]; + + // The next triangle will share two vertices with the previous one, so reset progress to 2 + // It will always share the last one and the very first vertex that was specified. + // To make sure the first vertex is not overwritten it was locked earlier (see glBegin) + return 2; +} + +uint8_t gl_quads() +{ + state->prim_indices[1] = state->prim_indices[2]; + + state->prim_counter ^= 1; + return state->prim_counter << 1; +} + +bool gl_prim_assembly(uint8_t cache_index, uint8_t *indices) +{ + if (state->lock_next_vertex) { + state->lock_next_vertex = false; + state->locked_vertex = cache_index; + } + + state->prim_indices[state->prim_progress] = cache_index; + state->prim_progress++; + + if (state->prim_progress < state->prim_size) { + return false; + } + + memcpy(indices, state->prim_indices, state->prim_size * sizeof(uint8_t)); + + assert(state->prim_func != NULL); + state->prim_progress = state->prim_func(); + return true; +} + static void gl_init_cpu_pipe() { gl_texture_object_t *tex_obj = gl_get_active_texture(); @@ -757,7 +973,7 @@ static void submit_vertex(uint32_t cache_index) } } -static void draw_vertex_from_arrays(const gl_array_t *arrays, uint32_t id, uint32_t index) +static void draw_vertex_from_arrays(const array_t *arrays, uint32_t id, uint32_t index) { uint8_t cache_index; if (gl_get_cache_index(id, &cache_index)) @@ -769,8 +985,14 @@ static void draw_vertex_from_arrays(const gl_array_t *arrays, uint32_t id, uint3 submit_vertex(cache_index); } -static void gl_cpu_begin() +static void gl_cpu_begin(GLenum mode) { + // FIXME: This is pessimistically marking everything as used, even if textures are turned off + // CAUTION: texture state is owned by the RSP currently, so how can we determine this? + __rdpq_autosync_use(AUTOSYNC_PIPE | AUTOSYNC_TILES | AUTOSYNC_TMEM(0)); + + gl_init_prim_assembly(mode); + gl_reset_vertex_cache(); gl_init_cpu_pipe(); } @@ -790,12 +1012,12 @@ static void gl_cpu_end() gl_set_current_mtx_index(state->current_attributes.mtx_index); } -void gl_read_attrib(gl_array_type_t array_type, const void *value, GLenum type, uint32_t size) +void gl_read_attrib(array_type_t array_type, const void *value, GLenum type, uint32_t size) { cpu_read_attrib_func read_func = cpu_read_funcs[array_type][gl_type_to_index(type)]; void *dst = gl_get_attrib_pointer(&state->current_attributes, array_type); read_func(dst, value, size); - if (array_type != ATTRIB_MTX_INDEX) { + if (array_type != ARRAY_MTX_INDEX) { gl_fill_attrib_defaults(array_type, size); } } @@ -805,32 +1027,17 @@ static void gl_cpu_vertex(const void *value, GLenum type, uint32_t size) uint8_t cache_index; if (gl_get_cache_index(next_prim_id(), &cache_index)) { - gl_fill_attrib_defaults(ATTRIB_VERTEX, size); - gl_read_attrib(ATTRIB_VERTEX, value, type, size); + gl_fill_attrib_defaults(ARRAY_VERTEX, size); + gl_read_attrib(ARRAY_VERTEX, value, type, size); gl_vertex_pre_tr(cache_index); } submit_vertex(cache_index); } -static void gl_cpu_color(const void *value, GLenum type, uint32_t size) -{ - gl_read_attrib(ATTRIB_COLOR, value, type, size); -} - -static void gl_cpu_tex_coord(const void *value, GLenum type, uint32_t size) +static void gl_cpu_mtx_index(const uint8_t *mtx_index) { - gl_read_attrib(ATTRIB_TEXCOORD, value, type, size); -} - -static void gl_cpu_normal(const void *value, GLenum type, uint32_t size) -{ - gl_read_attrib(ATTRIB_NORMAL, value, type, size); -} - -static void gl_cpu_mtx_index(const void *value, GLenum type, uint32_t size) -{ - gl_read_attrib(ATTRIB_MTX_INDEX, value, type, size); + // do nothing } static void gl_cpu_array_element(uint32_t index) @@ -839,11 +1046,13 @@ static void gl_cpu_array_element(uint32_t index) draw_vertex_from_arrays(state->array_object->arrays, index, index); } -static void gl_cpu_draw_arrays(uint32_t first, uint32_t count) +static void gl_cpu_draw_arrays(GLenum mode, uint32_t first, uint32_t count) { + gl_cpu_begin(mode); + gl_fill_all_attrib_defaults(state->array_object->arrays); - if (state->array_object->arrays[ATTRIB_VERTEX].enabled) { + if (state->array_object->arrays[ARRAY_VERTEX].enabled) { for (uint32_t i = 0; i < count; i++) { draw_vertex_from_arrays(state->array_object->arrays, next_prim_id(), first + i); @@ -853,13 +1062,53 @@ static void gl_cpu_draw_arrays(uint32_t first, uint32_t count) // So in effect, we just need to load the last set of attributes. gl_load_attribs(state->array_object->arrays, first + count - 1); } + + gl_cpu_end(); } -static void gl_cpu_draw_elements(uint32_t count, const void* indices, read_index_func read_index) +uint32_t read_index_8(const uint8_t *src, uint32_t i) { + return src[i]; +} + +uint32_t read_index_16(const uint16_t *src, uint32_t i) +{ + return src[i]; +} + +uint32_t read_index_32(const uint32_t *src, uint32_t i) +{ + return src[i]; +} + +static void gl_cpu_draw_elements(GLenum mode, uint32_t count, const void* indices, GLenum type) +{ + read_index_func read_index; + + switch (type) { + case GL_UNSIGNED_BYTE: + read_index = (read_index_func)read_index_8; + break; + case GL_UNSIGNED_SHORT: + read_index = (read_index_func)read_index_16; + break; + case GL_UNSIGNED_INT: + read_index = (read_index_func)read_index_32; + break; + default: + gl_set_error(GL_INVALID_ENUM, "%#04lx is not a valid index type", type); + return; + } + + if (state->array_object->element_array_buffer != NULL) { + indices = state->array_object->element_array_buffer->storage.data + (uint32_t)indices; + } + + gl_cpu_begin(mode); + gl_fill_all_attrib_defaults(state->array_object->arrays); - if (state->array_object->arrays[ATTRIB_VERTEX].enabled) { + if (state->array_object->arrays[ARRAY_VERTEX].enabled) { for (uint32_t i = 0; i < count; i++) { uint32_t index = read_index(indices, i); @@ -870,15 +1119,14 @@ static void gl_cpu_draw_elements(uint32_t count, const void* indices, read_index // So in effect, we just need to load the last set of attributes. gl_load_attribs(state->array_object->arrays, read_index(indices, count - 1)); } + + gl_cpu_end(); } const gl_pipeline_t gl_cpu_pipeline = (gl_pipeline_t) { .begin = gl_cpu_begin, .end = gl_cpu_end, .vertex = gl_cpu_vertex, - .color = gl_cpu_color, - .tex_coord = gl_cpu_tex_coord, - .normal = gl_cpu_normal, .mtx_index = gl_cpu_mtx_index, .array_element = gl_cpu_array_element, .draw_arrays = gl_cpu_draw_arrays, diff --git a/src/GL/data_cache.c b/src/GL/data_cache.c new file mode 100644 index 0000000000..b92c794ca5 --- /dev/null +++ b/src/GL/data_cache.c @@ -0,0 +1,91 @@ +#include "data_cache.h" +#include "data_source.h" +#include "rspq.h" + +void data_cache_init(data_cache_t *cache, data_source_t *source) +{ + *cache = (data_cache_t){0}; + cache->source = source; + data_cache_invalidate(cache); +} + +static void free_buffer(data_cache_t *cache) +{ + if (cache->buffer != NULL) { + rspq_call_deferred(free_uncached, cache->buffer); + } +} + +void data_cache_destroy(data_cache_t *cache) +{ + free_buffer(cache); +} + +void data_cache_invalidate(data_cache_t *cache) +{ + cache->is_data_dirty = true; +} + +static bool are_cached_bounds_too_small(data_cache_t *cache, index_bounds_t bounds) { + return !are_bounds_included(cache->bounds, bounds); +} + +static bool is_pull_required_for_bounds(data_cache_t *cache, index_bounds_t bounds) +{ + return cache->is_data_dirty || + are_cached_bounds_too_small(cache, bounds) || + !data_source_is_fully_internal(cache->source); +} + +static void set_bounds(data_cache_t *cache, index_bounds_t bounds) +{ + cache->bounds = bounds; +} + +static void update_stride_from_data_source(data_cache_t *cache) +{ + cache->stride = data_source_get_stride(cache->source); +} + +static void reallocate_buffer(data_cache_t *cache, uint32_t new_size) +{ + free_buffer(cache); + // TODO: use allocator abstraction? + cache->buffer = malloc_uncached(new_size); +} + +static void prepare_buffer(data_cache_t *cache) +{ + uint32_t new_size = cache->bounds.count * cache->stride; + reallocate_buffer(cache, new_size); +} + +static void pull_data_into_buffer(data_cache_t *cache, index_bounds_t bounds) +{ + set_bounds(cache, bounds); + update_stride_from_data_source(cache); + prepare_buffer(cache); + data_source_pull(cache->source, cache->buffer, cache->bounds); + + cache->is_data_dirty = false; +} + +static data_view_t get_data_view(data_cache_t *cache, index_bounds_t bounds) +{ + uint32_t offset_from_cached = bounds.first - cache->bounds.first; + uint8_t *buffer = cache->buffer; + + return (data_view_t) { + .pointer = buffer + offset_from_cached * cache->stride, + .stride = cache->stride + }; +} + +data_view_t data_cache_prepare_at_bounds(data_cache_t *cache, index_bounds_t bounds) +{ + if (is_pull_required_for_bounds(cache, bounds)) { + pull_data_into_buffer(cache, bounds); + } + + return get_data_view(cache, bounds); +} diff --git a/src/GL/data_cache.h b/src/GL/data_cache.h new file mode 100644 index 0000000000..cdcc33792e --- /dev/null +++ b/src/GL/data_cache.h @@ -0,0 +1,31 @@ +#ifndef __DATA_CACHE_H +#define __DATA_CACHE_H + +#include +#include "indices.h" +#include "data_view.h" + +typedef struct data_source_s data_source_t; + +typedef struct data_cache_s { + data_source_t *source; + void *buffer; + uint32_t stride; + index_bounds_t bounds; + bool is_data_dirty; +} data_cache_t; + +#ifdef __cplusplus +extern "C" { +#endif + +void data_cache_init(data_cache_t *cache, data_source_t *source); +void data_cache_destroy(data_cache_t *cache); +void data_cache_invalidate(data_cache_t *cache); +data_view_t data_cache_prepare_at_bounds(data_cache_t *cache, index_bounds_t bounds); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/GL/data_source.c b/src/GL/data_source.c new file mode 100644 index 0000000000..7327456ea2 --- /dev/null +++ b/src/GL/data_source.c @@ -0,0 +1,121 @@ +#include "data_source.h" +#include "gl_internal.h" +#include "array.h" +#include "array_object.h" +#include "array_convert.h" + +void data_source_init(data_source_t *data_source, const array_t *arrays, array_mask_t array_mask) +{ + *data_source = (data_source_t){0}; + data_source->arrays = arrays; + data_source->array_mask = array_mask; + data_source->arrays_dirty = true; +} + +void data_source_invalidate_arrays(data_source_t *data_source) +{ + data_source->arrays_dirty = true; +} + +static bool is_array_included(data_source_t *data_source, array_type_t type) +{ + return (data_source->array_mask & (1<arrays[type].enabled; +} + +static bool is_array_external(const array_t *array) { + return array->binding == NULL; +} + +static bool calculate_is_fully_internal(data_source_t *data_source) +{ + for (array_type_t i = 0; i < ARRAY_COUNT; i++) + { + if (!is_array_used(data_source, i)) continue; + + if (is_array_external(&data_source->arrays[i])) { + return false; + } + } + + return true; +} + +static void update_is_fully_internal(data_source_t *data_source) +{ + data_source->is_fully_internal = calculate_is_fully_internal(data_source); +} + +static void update_layout(data_source_t *data_source) +{ + uint32_t stride = 0; + uint32_t array_count = 0; + + for (array_type_t i = 0; i < ARRAY_COUNT; i++) + { + if (!is_array_used(data_source, i)) continue; + + uint32_t alignment = array_type_get_alignment(i); + stride = ROUND_UP(stride, alignment); + + uint32_t offset = stride; + + data_source->layout.offsets[array_count++] = offset; + stride += array_type_get_stride(i); + } + + data_source->layout.stride = stride; +} + +static void update_state_from_arrays(data_source_t *data_source) +{ + if (!data_source->arrays_dirty) { + return; + } + + update_is_fully_internal(data_source); + update_layout(data_source); + + data_source->arrays_dirty = false; +} + +bool data_source_is_fully_internal(data_source_t *data_source) +{ + update_state_from_arrays(data_source); + return data_source->is_fully_internal; +} + +static void get_array_convert_parms(array_convert_parms_t *parms, data_source_t *data_source, void *buffer, index_bounds_t bounds) +{ + parms->array_count = 0; + + for (array_type_t i = 0; i < ARRAY_COUNT; i++) + { + if (!is_array_used(data_source, i)) continue; + + parms->arrays[parms->array_count++] = &data_source->arrays[i]; + } + + parms->out_layout = &data_source->layout; + parms->range = bounds; + parms->out_buffer = buffer; +} + +void data_source_pull(data_source_t *data_source, void *buffer, index_bounds_t bounds) +{ + update_state_from_arrays(data_source); + + array_convert_parms_t convert_parms; + get_array_convert_parms(&convert_parms, data_source, buffer, bounds); + array_convert(&convert_parms); +} + +uint32_t data_source_get_stride(data_source_t *data_source) +{ + update_state_from_arrays(data_source); + return data_source->layout.stride; +} diff --git a/src/GL/data_source.h b/src/GL/data_source.h new file mode 100644 index 0000000000..f1daa6c505 --- /dev/null +++ b/src/GL/data_source.h @@ -0,0 +1,44 @@ +#ifndef __DATA_SOURCE_H +#define __DATA_SOURCE_H + +#include +#include +#include "indices.h" +#include "array.h" + +typedef enum { + ARRAY_MASK_VERTEX = 1 << ARRAY_VERTEX, + ARRAY_MASK_NORMAL = 1 << ARRAY_NORMAL, + ARRAY_MASK_COLOR = 1 << ARRAY_COLOR, + ARRAY_MASK_TEXCOORD = 1 << ARRAY_TEXCOORD, + ARRAY_MASK_MTX_INDEX = 1 << ARRAY_MTX_INDEX, +} array_mask_t; + +typedef struct { + uint32_t offsets[ARRAY_COUNT]; + uint32_t stride; +} data_layout_t; + +typedef struct data_source_s { + const array_t *arrays; + array_mask_t array_mask; + data_layout_t layout; + bool arrays_dirty; + bool is_fully_internal; +} data_source_t; + +#ifdef __cplusplus +extern "C" { +#endif + +void data_source_init(data_source_t *data_source, const array_t *arrays, array_mask_t array_mask); +void data_source_invalidate_arrays(data_source_t *data_source); +bool data_source_is_fully_internal(data_source_t *data_source); +void data_source_pull(data_source_t *data_source, void *buffer, index_bounds_t bounds); +uint32_t data_source_get_stride(data_source_t *data_source); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/GL/data_view.h b/src/GL/data_view.h new file mode 100644 index 0000000000..f5aaf30f7d --- /dev/null +++ b/src/GL/data_view.h @@ -0,0 +1,11 @@ +#ifndef __DATA_VIEW_H +#define __DATA_VIEW_H + +#include + +typedef struct data_view_s { + void *pointer; + uint32_t stride; +} data_view_t; + +#endif diff --git a/src/GL/draw_call_cache.c b/src/GL/draw_call_cache.c new file mode 100644 index 0000000000..d9ad94c660 --- /dev/null +++ b/src/GL/draw_call_cache.c @@ -0,0 +1,121 @@ +#include "draw_call_cache.h" +#include "gl_internal.h" +#include "array_object.h" +#include "fnv1a.h" +#include "mg_ex.h" + +#define MAX_CACHED_DRAW_CALL_COUNT 8 + +extern gl_state_t *state; + +draw_call_cache_t *draw_call_cache_create() +{ + draw_call_cache_t *cache = malloc(sizeof(draw_call_cache_t)); + hashtable_init(&cache->cached_draw_calls, 4, NULL); + return cache; +} + +static void free_block(cached_draw_call_t *draw_call) +{ + if (draw_call->block != NULL) { + rspq_call_deferred((void(*)(void*))rspq_block_free, draw_call->block); + draw_call->block = NULL; + } +} + +static void free_draw_call(cached_draw_call_t *draw_call) +{ + free_block(draw_call); + free(draw_call); +} + +static void free_visitor(uint32_t key, void *value, int refcount) +{ + cached_draw_call_t *draw_call = value; + free_draw_call(draw_call); +} + +static void free_all(draw_call_cache_t *cache) +{ + hashtable_visit(&cache->cached_draw_calls, free_visitor); +} + +void draw_call_cache_free(draw_call_cache_t *cache) +{ + free_all(cache); + hashtable_free(&cache->cached_draw_calls); + free(cache); +} + +void draw_call_cache_invalidate_indices(draw_call_cache_t *cache) +{ + // All cached data is now obsolete -> free everything + free_all(cache); + hashtable_clear(&cache->cached_draw_calls); +} + +static void free_block_visitor(uint32_t key, void *value, int refcount) +{ + cached_draw_call_t *draw_call = value; + free_block(draw_call); +} + +void draw_call_cache_invalidate_mtx_indices(draw_call_cache_t *cache) +{ + // Index ranges are still valid, but blocks are obsolete + hashtable_visit(&cache->cached_draw_calls, free_block_visitor); +} + +static uint32_t get_draw_call_key(const draw_call_parms_t *parms) +{ + uint32_t key = fnv1a_init(); + fnv1a_step(&key, parms->offset); + fnv1a_step(&key, parms->count); + fnv1a_step(&key, parms->mode); + return key; +} + +static cached_draw_call_t *create_draw_call(draw_call_cache_t *cache, const draw_call_parms_t *parms, const void *index_data) +{ + cached_draw_call_t *draw_call = malloc(sizeof(cached_draw_call_t)); + draw_call->index_range = find_index_bounds(index_data, parms->count); + draw_call->block = NULL; + return draw_call; +} + +static rspq_block_t *create_block(const draw_call_parms_t *parms, const void *index_data, gl_array_object_t *array_object, index_bounds_t index_range) +{ + mg_input_assembly_parms_t input_assembly_parms = array_object_get_input_assembly_parms(array_object, parms->mode, index_range); + rspq_block_begin(); + mg_ex_draw_indexed(&input_assembly_parms, index_data, parms->count, -index_range.first, parms->mode); + return rspq_block_end(); +} + +static void update_draw_call(cached_draw_call_t *draw_call, const draw_call_parms_t *parms, const void *index_data, gl_array_object_t *array_object) +{ + if (draw_call->block == NULL) { + draw_call->block = create_block(parms, index_data, array_object, draw_call->index_range); + } +} + +cached_draw_call_t *draw_call_cache_get_or_create(draw_call_cache_t *cache, const draw_call_parms_t *parms, const void *index_data, gl_array_object_t *array_object) +{ + uint32_t key = get_draw_call_key(parms); + + cached_draw_call_t *draw_call = hashtable_lookup(&cache->cached_draw_calls, key); + if (draw_call == NULL) { + draw_call = create_draw_call(cache, parms, index_data); + hashtable_insert(&cache->cached_draw_calls, key, draw_call); + } + + update_draw_call(draw_call, parms, index_data, array_object); + + return draw_call; +} + +void draw_call_run(cached_draw_call_t *draw_call) +{ + assertf(draw_call->block != NULL, "Tried to run a draw call with missing block"); + + rspq_block_run(draw_call->block); +} diff --git a/src/GL/draw_call_cache.h b/src/GL/draw_call_cache.h new file mode 100644 index 0000000000..a96f817ea8 --- /dev/null +++ b/src/GL/draw_call_cache.h @@ -0,0 +1,47 @@ +#ifndef __DRAW_CALL_CACHE_H +#define __DRAW_CALL_CACHE_H + +#include +#include "rspq.h" +#include "GL/gl.h" +#include "hashtable_internal.h" +#include "indices.h" + +#define MAX_CACHED_DRAW_CALLS 8 + +typedef struct draw_call_parms_s { + uint32_t offset; + uint32_t count; + GLenum mode; +} draw_call_parms_t; + +typedef struct cached_draw_call_s { + index_bounds_t index_range; + rspq_block_t *block; +} cached_draw_call_t; + +typedef struct draw_call_cache_s { + hashtable_t cached_draw_calls; +} draw_call_cache_t; + +typedef struct gl_array_object_s gl_array_object_t; + +#ifdef __cplusplus +extern "C" { +#endif + +draw_call_cache_t *draw_call_cache_create(); +void draw_call_cache_free(draw_call_cache_t *cache); + +void draw_call_cache_invalidate_indices(draw_call_cache_t *cache); +void draw_call_cache_invalidate_mtx_indices(draw_call_cache_t *cache); + +cached_draw_call_t *draw_call_cache_get_or_create(draw_call_cache_t *cache, const draw_call_parms_t *parms, const void *index_data, gl_array_object_t *array_object); + +void draw_call_run(cached_draw_call_t *draw_call); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/GL/fnv1a.h b/src/GL/fnv1a.h new file mode 100644 index 0000000000..4a4510ff5b --- /dev/null +++ b/src/GL/fnv1a.h @@ -0,0 +1,17 @@ +#ifndef __FNV1A_H +#define __FNV1A_H + +#include + +inline uint32_t fnv1a_init() +{ + return 0x811c9dc5; // FNV offset basis +} + +inline void fnv1a_step(uint32_t *hash, uint32_t v) +{ + *hash ^= v; + *hash *= 0x01000193; // FNV prime +} + +#endif diff --git a/src/GL/gl.c b/src/GL/gl.c index 249eb72ad5..a514805c64 100644 --- a/src/GL/gl.c +++ b/src/GL/gl.c @@ -16,13 +16,15 @@ #include #include #include "gl_internal.h" +#include "buffer.h" +#include "array_module.h" +#include "../magma/magma_internal.h" DEFINE_RSP_UCODE(rsp_gl); -DEFINE_RSP_UCODE(rsp_gl_pipeline); +DEFINE_RSP_UCODE(rsp_gl2); uint32_t gl_overlay_id; -uint32_t glp_overlay_id; -uint32_t gl_rsp_state; +uint32_t gl2_overlay_id; gl_state_t *state; @@ -55,13 +57,16 @@ uint32_t gl_get_type_size(GLenum type) void gl_init() { rdpq_init(); + mg_init(); state = calloc(1, sizeof(gl_state_t)); assertf(state, "Out of memory"); gl_texture_init(); - gl_server_state_t *server_state = UncachedAddr(rspq_overlay_get_state(&rsp_gl)); + void *gl_overlay_state = rspq_overlay_get_state(&rsp_gl); + + gl_server_state_t *server_state = UncachedAddr(gl_overlay_state); memset(server_state, 0, sizeof(gl_server_state_t)); memcpy(&server_state->bound_textures[0], state->default_textures[0].srv_object, sizeof(gl_srv_texture_object_t)); @@ -95,20 +100,20 @@ void gl_init() server_state->tex_gen.integer[1][0][1] = 1; server_state->tex_gen.integer[1][1][1] = 1; - state->matrix_stacks[0] = malloc_uncached(sizeof(gl_matrix_srv_t) * MODELVIEW_STACK_SIZE); - state->matrix_stacks[1] = malloc_uncached(sizeof(gl_matrix_srv_t) * PROJECTION_STACK_SIZE); - state->matrix_stacks[2] = malloc_uncached(sizeof(gl_matrix_srv_t) * TEXTURE_STACK_SIZE); - state->matrix_palette = malloc_uncached(sizeof(gl_matrix_srv_t) * MATRIX_PALETTE_SIZE * 2); // Double size for mvp-matrices + state->matrix_stacks[0] = malloc_uncached(sizeof(gl_pipeline_matrix_t) * MODELVIEW_STACK_SIZE); + state->matrix_stacks[1] = malloc_uncached(sizeof(gl_pipeline_matrix_t) * PROJECTION_STACK_SIZE); + state->matrix_stacks[2] = malloc_uncached(sizeof(gl_pipeline_matrix_t) * TEXTURE_STACK_SIZE); + state->matrix_palette = malloc_uncached(sizeof(gl_pipeline_matrices_t) * MATRIX_PALETTE_SIZE); assertf(state->matrix_stacks[0] && state->matrix_stacks[1] && state->matrix_stacks[2] && state->matrix_palette, "Out of memory"); + memset(state->matrix_palette, 0xff, sizeof(gl_pipeline_matrices_t) * MATRIX_PALETTE_SIZE); server_state->matrix_pointers[0] = PhysicalAddr(state->matrix_stacks[0]); server_state->matrix_pointers[1] = PhysicalAddr(state->matrix_stacks[1]); server_state->matrix_pointers[2] = PhysicalAddr(state->matrix_stacks[2]); server_state->matrix_pointers[3] = PhysicalAddr(state->matrix_palette); - server_state->matrix_pointers[4] = PhysicalAddr(state->matrix_palette + MATRIX_PALETTE_SIZE); - server_state->loaded_mtx_index[0] = -1; - server_state->loaded_mtx_index[1] = -1; + + server_state->palette_index = offsetof(gl_pipeline_matrices_t, mv); server_state->flags |= FLAG_FINAL_MTX_DIRTY; @@ -122,15 +127,11 @@ void gl_init() server_state->mat_diffuse[3] = 0x7FFF; // 1.0 server_state->mat_specular[3] = 0x7FFF; // 1.0 server_state->mat_emissive[3] = 0x7FFF; // 1.0 - server_state->mat_color_target[0] = 1; - server_state->mat_color_target[1] = 1; for (uint32_t i = 0; i < LIGHT_COUNT; i++) { - server_state->lights.position[i][2] = 0x7FFF; // 1.0 - server_state->lights.ambient[i][3] = 0x7FFF; // 1.0 - server_state->lights.diffuse[i][3] = 0x7FFF; // 1.0 - server_state->lights.attenuation_frac[i][0] = 1 << 15; // 1.0 + server_state->lights[i].position[2] = 0x7FFF; // 1.0 + server_state->lights[i].attenuation_frac[0] = 1 << 15; // 1.0 } server_state->light_ambient[0] = 0x1999; // 0.2 @@ -139,15 +140,15 @@ void gl_init() server_state->light_ambient[3] = 0x7FFF; // 1.0 server_state->dither_mode = DITHER_SQUARE_SQUARE << (SOM_ALPHADITHER_SHIFT - 32); - + gl_overlay_id = rspq_overlay_register(&rsp_gl); - glp_overlay_id = rspq_overlay_register(&rsp_gl_pipeline); - gl_rsp_state = PhysicalAddr(rspq_overlay_get_state(&rsp_gl)); + gl2_overlay_id = rspq_overlay_register(&rsp_gl2); + rspq_overlay_share_state(&rsp_gl2, &rsp_gl); gl_matrix_init(); gl_lighting_init(); gl_rendermode_init(); - gl_array_init(); + array_module_init(); gl_primitive_init(); gl_pixel_init(); gl_list_init(); @@ -164,9 +165,10 @@ void gl_close() gl_list_close(); gl_primitive_close(); + array_module_close(); gl_texture_close(); + rspq_overlay_unregister(gl2_overlay_id); rspq_overlay_unregister(gl_overlay_id); - rspq_overlay_unregister(glp_overlay_id); // FIXME: some of the above do deferred deletions, others don't. // So we need another rspq_wait. @@ -520,11 +522,24 @@ bool gl_storage_resize(gl_storage_t *storage, uint32_t new_size) void glTexSizeN64(GLushort width, GLushort height) { - width <<= TEX_COORD_SHIFT; - height <<= TEX_COORD_SHIFT; gl_set_word(GL_UPDATE_NONE, offsetof(gl_server_state_t, tex_size[0]), (width << 16) | height); } +void gl_pre_init_pipe(GLenum primitive_mode) +{ + __rdpq_autosync_change(AUTOSYNC_PIPE | AUTOSYNC_TILES | AUTOSYNC_TMEMS); + + // PreInitPipeTex will run a block with nesting level 1 for texture upload. + // The command itself does not emit RDP commands (the block does that, so + // we use a plain gl_write() for it. + rspq_block_run_rsp(1); + gl2_write(GL_CMD_PRE_INIT_PIPE_TEX); + + // PreInitPipe is similar to rdpq_set_mode_standard wrt RDP commands. + // It issues SET_SCISSOR + CC + SOM. + gl2_write_rdp(3, GL_CMD_PRE_INIT_PIPE, primitive_mode); +} + extern inline uint32_t next_pow2(uint32_t v); extern inline bool is_in_heap_memory(void *ptr); extern inline void gl_set_flag_raw(gl_update_func_t update_func, uint32_t offset, uint32_t flag, bool value); @@ -543,15 +558,7 @@ extern inline void gl_set_current_color(GLfloat *color); extern inline void gl_set_current_texcoords(GLfloat *texcoords); extern inline void gl_set_current_normal(GLfloat *normal); extern inline void gl_pre_init_pipe(GLenum primitive_mode); -extern inline void glpipe_init(); -extern inline void glpipe_draw_triangle(int i0, int i1, int i2); extern inline int gl_get_rdpcmds_for_update_func(gl_update_func_t update_func); -extern inline void* gl_get_attrib_pointer(gl_obj_attributes_t *attribs, gl_array_type_t array_type); +extern inline void* gl_get_attrib_pointer(gl_obj_attributes_t *attribs, array_type_t array_type); extern inline uint32_t gl_type_to_index(GLenum type); extern inline void gl_set_current_mtx_index(GLubyte *index); -extern inline gl_cmd_stream_t gl_cmd_stream_begin(uint32_t ovl_id, uint32_t cmd_id, int size); -extern inline void gl_cmd_stream_commit(gl_cmd_stream_t *s); -extern inline void gl_cmd_stream_put_byte(gl_cmd_stream_t *s, uint8_t v); -extern inline void gl_cmd_stream_put_half(gl_cmd_stream_t *s, uint16_t v); -extern inline void gl_cmd_stream_end(gl_cmd_stream_t *s); -extern inline void glpipe_set_vtx_cmd_size(uint16_t patched_cmd_descriptor, uint16_t *cmd_descriptor); diff --git a/src/GL/gl_constants.h b/src/GL/gl_constants.h index 131f0b1c7b..836413dbe4 100644 --- a/src/GL/gl_constants.h +++ b/src/GL/gl_constants.h @@ -5,6 +5,11 @@ #ifndef __GL_CONSTANTS #define __GL_CONSTANTS +#include "../../include/mgfx_constants.h" + +#define PIPELINE_FEATURE_COUNT 2 +#define PIPELINE_COUNT (1<>32) #define PALETTE_MATRIX_INDEX 3 #define PALETTE_DIRTY_FLAGS_SIZE ((MATRIX_PALETTE_SIZE+7)>>3) -#define PRIM_VTX_CS_POSi 0 // X, Y, Z, W (all 32-bit) -#define PRIM_VTX_CS_POSf 8 // X, Y, Z, W (all 32-bit) -#define PRIM_VTX_X 16 // Object space position (16-bit) -#define PRIM_VTX_Y 18 // Object space position (16-bit) -#define PRIM_VTX_Z 20 // Object space position (16-bit) -#define PRIM_VTX_W 22 // Object space position (16-bit) -#define PRIM_VTX_R 24 -#define PRIM_VTX_G 26 -#define PRIM_VTX_B 28 -#define PRIM_VTX_A 30 -#define PRIM_VTX_TEX_S 32 -#define PRIM_VTX_TEX_T 34 -#define PRIM_VTX_TEX_R 36 -#define PRIM_VTX_TEX_Q 38 -#define PRIM_VTX_NORMAL 40 // Normal X,Y,Z (8 bit) -#define PRIM_VTX_MTX_INDEX 43 -#define PRIM_VTX_TRCODE 44 // trivial-reject clipping flags (against -w/+w) -#define PRIM_VTX_SIZE 45 +#define GLP_LIGHT_POSITION 0 +#define GLP_LIGHT_POSITIONW 6 +#define GLP_LIGHT_DIFFUSE 8 +#define GLP_LIGHT_AMBIENT 14 +#define GLP_LIGHT_ATT_INT 20 +#define GLP_LIGHT_ATT_FRAC 26 +#define GLP_LIGHT_SIZE 32 + +#define GLP_ATTRIBUTE_POSITION 0 +#define GLP_ATTRIBUTE_NORMAL 1 +#define GLP_ATTRIBUTE_COLOR 2 +#define GLP_ATTRIBUTE_TEXCOORD 3 + +#define GLP_BINDING_MATRICES 0 +#define GLP_BINDING_TEXTURING 1 +#define GLP_BINDING_LIGHTING 2 +#define GLP_BINDING_FOG 3 + +#define GLP_VTX_POS_SHIFT 5 +#define GLP_VTX_TEX_SHIFT 8 + +#define GLP_MATERIAL_FLAG_DIFFUSE 0x1 +#define GLP_MATERIAL_FLAG_AMBIENT 0x2 +#define GLP_MATERIAL_FLAG_EMISSIVE 0x4 #endif diff --git a/src/GL/gl_internal.h b/src/GL/gl_internal.h index e8b2b7480f..27e29bc162 100644 --- a/src/GL/gl_internal.h +++ b/src/GL/gl_internal.h @@ -7,7 +7,6 @@ #include "GL/gl.h" #include "GL/gl_integration.h" -#include "obj_map.h" #include "surface.h" #include "../utils.h" #include @@ -17,6 +16,17 @@ #include "rdpq.h" #include "../rdpq/rdpq_internal.h" #include "rdpq_tri.h" +#include "vertex_layout.h" +#include "../hashtable_internal.h" +#include "ringbuffer.h" +#include "array_object.h" +#include "buffer.h" + +#define MAX_PIPELINE_COUNT (1<<4) + +#define BEGIN_END_BUFFER_COUNT 2 +// divisible by 2, 3, 4, which are all possible required multiples of vertices (see get_begin_end_multiple) +#define BEGIN_END_BUFFER_SIZE 36 #define RADIANS(x) ((x) * (float)M_PI / 180.0f) @@ -67,6 +77,14 @@ #define gl_assert_no_display_list() assertf(state->current_list == 0, "%s cannot be recorded into a display list", __func__) +extern uint32_t gl_overlay_id; +extern uint32_t gl2_overlay_id; + +#define gl_write(cmd_id, ...) rspq_write(gl_overlay_id, cmd_id, ##__VA_ARGS__) +#define gl2_write(cmd_id, ...) rspq_write(gl2_overlay_id, cmd_id, ##__VA_ARGS__) +#define gl_write_rdp(rdpcmds, cmd_id, ...) rdpq_write(rdpcmds, gl_overlay_id, cmd_id, ##__VA_ARGS__) +#define gl2_write_rdp(rdpcmds, cmd_id, ...) rdpq_write(rdpcmds, gl2_overlay_id, cmd_id, ##__VA_ARGS__) + typedef int16_t int16u_t __attribute__((aligned(1))); typedef uint16_t uint16u_t __attribute__((aligned(1))); typedef int32_t int32u_t __attribute__((aligned(1))); @@ -74,16 +92,6 @@ typedef uint32_t uint32u_t __attribute__((aligned(1))); typedef float floatu __attribute__((aligned(1))); typedef double doubleu __attribute__((aligned(1))); -extern uint32_t gl_overlay_id; -extern uint32_t glp_overlay_id; -extern uint32_t gl_rsp_state; - -#define gl_write(cmd_id, ...) rspq_write(gl_overlay_id, cmd_id, ##__VA_ARGS__) -#define glp_write(cmd_id, ...) rspq_write(glp_overlay_id, cmd_id, ##__VA_ARGS__) -#define gl_write_rdp(rdpcmds, cmd_id, ...) rdpq_write(rdpcmds, gl_overlay_id, cmd_id, ##__VA_ARGS__) -#define glp_write_rdp(rdpcmds, cmd_id, ...) rdpq_write(rdpcmds, glp_overlay_id, cmd_id, ##__VA_ARGS__) - - typedef enum { GL_CMD_SET_FLAG = 0x0, GL_CMD_SET_BYTE = 0x1, @@ -98,22 +106,16 @@ typedef enum { GL_CMD_MATRIX_PUSH = 0xA, GL_CMD_MATRIX_POP = 0xB, GL_CMD_MATRIX_LOAD = 0xC, - GL_CMD_PRE_INIT_PIPE = 0xD, - GL_CMD_PRE_INIT_PIPE_TEX= 0xE, - GL_CMD_SET_PALETTE_IDX = 0xF, - GL_CMD_MATRIX_COPY = 0x10, + GL_CMD_SET_PALETTE_IDX = 0xD, + GL_CMD_MATRIX_COPY = 0xE, } gl_command_t; typedef enum { - GLP_CMD_INIT_PIPE = 0x0, - GLP_CMD_SET_VTX_LOADER = 0x1, - GLP_CMD_SET_VTX_CMD_SIZE = 0x2, - GLP_CMD_DRAW_TRI = 0x3, - GLP_CMD_SET_PRIM_VTX = 0x4, - GLP_CMD_SET_BYTE = 0x5, - GLP_CMD_SET_WORD = 0x6, - GLP_CMD_SET_LONG = 0x7, -} glp_command_t; + GL_CMD_PRE_INIT_PIPE = 0x0, + GL_CMD_PRE_INIT_PIPE_TEX= 0x1, + GL_CMD_SET_PIPELINE = 0x2, + GL_CMD_PRE_INIT_MAGMA = 0x3, +} gl2_command_t; typedef enum { GL_UPDATE_NONE = 0x0, @@ -122,15 +124,6 @@ typedef enum { GL_UPDATE_TEXTURE_OBJECTS = 0x3, } gl_update_func_t; -typedef enum { - ATTRIB_VERTEX, - ATTRIB_COLOR, - ATTRIB_TEXCOORD, - ATTRIB_NORMAL, - ATTRIB_MTX_INDEX, - ATTRIB_COUNT -} gl_array_type_t; - typedef struct { GLfloat position[4]; GLfloat color[4]; @@ -152,16 +145,12 @@ typedef struct { uint8_t t_l_applied; } gl_vtx_t; -#define VTX_SCREEN_POS_OFFSET (offsetof(gl_vtx_t, screen_pos) / sizeof(float)) -#define VTX_SHADE_OFFSET (offsetof(gl_vtx_t, shade) / sizeof(float)) -#define VTX_TEXCOORD_OFFSET (offsetof(gl_vtx_t, texcoord) / sizeof(float)) -#define VTX_DEPTH_OFFSET (offsetof(gl_vtx_t, depth) / sizeof(float)) - typedef struct { GLfloat m[4][4]; } gl_matrix_t; typedef struct { + GLfloat x, y, w, h, n, f; GLfloat scale[3]; GLfloat offset[3]; } gl_viewport_t; @@ -181,8 +170,16 @@ typedef struct { typedef struct { int16_t i[4][4]; uint16_t f[4][4]; -} gl_matrix_srv_t; -_Static_assert(sizeof(gl_matrix_srv_t) == MATRIX_SIZE, "Matrix size does not match"); +} gl_pipeline_matrix_t; +_Static_assert(sizeof(gl_pipeline_matrix_t) == MATRIX_SIZE, "Matrix size does not match"); + +typedef struct +{ + gl_pipeline_matrix_t mvp; + gl_pipeline_matrix_t mv; + int16_t normal[16]; +} gl_pipeline_matrices_t; +_Static_assert(sizeof(gl_pipeline_matrices_t) == MATRICES_SIZE, "Matrices size doesn't match!"); typedef struct { uint16_t width; @@ -259,64 +256,6 @@ typedef struct { bool enabled; } gl_light_t; -typedef struct { - int16_t position[LIGHT_COUNT][4]; - int16_t ambient[LIGHT_COUNT][4]; - int16_t diffuse[LIGHT_COUNT][4]; - int16_t attenuation_int[LIGHT_COUNT][4]; - uint16_t attenuation_frac[LIGHT_COUNT][4]; -} __attribute__((packed)) gl_lights_soa_t; -_Static_assert(sizeof(gl_lights_soa_t) == LIGHT_STRUCT_SIZE); -_Static_assert(offsetof(gl_lights_soa_t, position) == LIGHT_POSITION_OFFSET); -_Static_assert(offsetof(gl_lights_soa_t, ambient) == LIGHT_AMBIENT_OFFSET); -_Static_assert(offsetof(gl_lights_soa_t, diffuse) == LIGHT_DIFFUSE_OFFSET); -_Static_assert(offsetof(gl_lights_soa_t, attenuation_int) == LIGHT_ATTENUATION_INT_OFFSET); -_Static_assert(offsetof(gl_lights_soa_t, attenuation_frac) == LIGHT_ATTENUATION_FRAC_OFFSET); - -typedef struct { - GLvoid *data; - uint32_t size; -} gl_storage_t; - -typedef struct { - GLenum usage; - GLenum access; - GLvoid *pointer; - gl_storage_t storage; - bool mapped; -} gl_buffer_object_t; - -typedef struct { - rspq_write_t w; - union { - uint8_t bytes[4]; - uint32_t word; - }; - uint32_t buffer_head; -} gl_cmd_stream_t; - -typedef void (*cpu_read_attrib_func)(void*,const void*,uint32_t); -typedef void (*rsp_read_attrib_func)(gl_cmd_stream_t*,const void*,uint32_t); - -typedef struct { - GLint size; - GLenum type; - GLsizei stride; - const GLvoid *pointer; - gl_buffer_object_t *binding; - bool normalize; - bool enabled; - - const GLvoid *final_pointer; - uint16_t final_stride; - cpu_read_attrib_func cpu_read_func; - rsp_read_attrib_func rsp_read_func; -} gl_array_t; - -typedef struct { - gl_array_t arrays[ATTRIB_COUNT]; -} gl_array_object_t; - typedef uint32_t (*read_index_func)(const void*,uint32_t); typedef struct { @@ -338,10 +277,24 @@ _Static_assert(offsetof(gl_tex_gen_soa_t, fraction) == TEX_GEN_FRACTION_OFFSET); _Static_assert(offsetof(gl_tex_gen_soa_t, mode) == TEX_GEN_MODE_OFFSET); typedef struct { - int16_t factor_int; - int16_t offset_int; - uint16_t factor_frac; - uint16_t offset_frac; + int16_t position[4]; + int16_t diffuse[3]; + int16_t ambient[3]; + int16_t attenuation_int[3]; + uint16_t attenuation_frac[3]; +} gl_pipeline_light_t; +_Static_assert(sizeof(gl_pipeline_light_t) == GLP_LIGHT_SIZE); +_Static_assert(offsetof(gl_pipeline_light_t, position) == GLP_LIGHT_POSITION); +_Static_assert(offsetof(gl_pipeline_light_t, diffuse) == GLP_LIGHT_DIFFUSE); +_Static_assert(offsetof(gl_pipeline_light_t, ambient) == GLP_LIGHT_AMBIENT); +_Static_assert(offsetof(gl_pipeline_light_t, attenuation_int) == GLP_LIGHT_ATT_INT); +_Static_assert(offsetof(gl_pipeline_light_t, attenuation_frac) == GLP_LIGHT_ATT_FRAC); + +typedef struct { + int16_t start_int; + int16_t end_int; + uint16_t start_frac; + uint16_t end_frac; } gl_fog_params_t; typedef struct { @@ -350,16 +303,13 @@ typedef struct { } gl_pixel_map_t; typedef struct { - void (*begin)(); + void (*begin)(GLenum); void (*end)(); void (*vertex)(const void*,GLenum,uint32_t); - void (*color)(const void*,GLenum,uint32_t); - void (*tex_coord)(const void*,GLenum,uint32_t); - void (*normal)(const void*,GLenum,uint32_t); - void (*mtx_index)(const void*,GLenum,uint32_t); + void (*mtx_index)(const uint8_t*); void (*array_element)(uint32_t); - void (*draw_arrays)(uint32_t,uint32_t); - void (*draw_elements)(uint32_t,const void*,read_index_func); + void (*draw_arrays)(GLenum,uint32_t,uint32_t); + void (*draw_elements)(GLenum,uint32_t,const void*,GLenum); } gl_pipeline_t; typedef struct { @@ -369,6 +319,14 @@ typedef struct { GLfloat to_float_factor; } gl_fixed_precision_t; +typedef struct { + int16_t position[3]; + uint16_t normal; + uint32_t color; + int16_t texcoord[2]; + uint8_t mtx_index[VERTEX_UNIT_COUNT]; +} native_vertex_t; + typedef struct { // Pipeline state @@ -430,7 +388,16 @@ typedef struct { gl_matrix_target_t *current_matrix_target; bool begin_end_active; - + native_vertex_t current_attribs; + native_vertex_t begin_end_saved_vtx; + ringbuffer begin_end_buffer; + native_vertex_t *begin_end_current_buffer; + uint32_t begin_end_index; + uint32_t begin_end_load_index; + uint32_t begin_end_multiple; + bool begin_end_need_save; + bool begin_end_restore; + vertex_layout_t begin_end_layout; gl_texture_object_t *texture_1d_object; gl_texture_object_t *texture_2d_object; @@ -475,16 +442,16 @@ typedef struct { gl_texture_object_t *default_textures; - obj_map_t list_objects; + hashtable_t lists; GLuint next_list_name; GLuint list_base; GLuint current_list; gl_buffer_object_t *array_buffer; - gl_buffer_object_t *element_array_buffer; - gl_matrix_srv_t *matrix_stacks[3]; - gl_matrix_srv_t *matrix_palette; + gl_pipeline_matrix_t *matrix_stacks[3]; + gl_pipeline_matrices_t *matrix_palette; + const mg_uniform_t *matrices_uniform; GLboolean unpack_swap_bytes; GLboolean unpack_lsb_first; @@ -504,6 +471,8 @@ typedef struct { gl_fixed_precision_t vertex_halfx_precision; gl_fixed_precision_t texcoord_halfx_precision; + hashtable_t pipeline_cache; + bool can_use_rsp; bool can_use_rsp_dirty; @@ -511,24 +480,29 @@ typedef struct { } gl_state_t; typedef struct { - gl_matrix_srv_t matrices[5]; - gl_lights_soa_t lights; + phys_addr_t text; + uint32_t text_size; +} gl_pipeline_data_t; + +typedef struct { + gl_pipeline_matrix_t matrices[4]; + gl_pipeline_light_t lights[LIGHT_COUNT]; gl_tex_gen_soa_t tex_gen; int16_t viewport_scale[4]; int16_t viewport_offset[4]; + gl_pipeline_data_t pipelines[PIPELINE_COUNT]; int16_t light_ambient[4]; int16_t mat_ambient[4]; int16_t mat_diffuse[4]; int16_t mat_specular[4]; int16_t mat_emissive[4]; - uint16_t mat_color_target[3]; + uint16_t mat_color_target; uint16_t mat_shininess; int16_t color[4]; int16_t tex_coords[4]; int8_t normal[3]; uint8_t mtx_index; - uint32_t matrix_pointers[5]; - uint32_t loaded_mtx_index[2]; + phys_addr_t matrix_pointers[4]; uint32_t flags; gl_fog_params_t fog_params; uint16_t tex_size[2]; @@ -544,12 +518,12 @@ typedef struct { uint16_t tri_cmd; uint8_t tri_cull[2]; - gl_srv_texture_object_t bound_textures[2]; + gl_srv_texture_object_t __attribute__((aligned(8))) bound_textures[2]; uint16_t scissor_rect[4]; uint32_t blend_cycle; uint32_t fog_color; uint32_t flags2; - uint32_t texture_ids[2]; + phys_addr_t texture_ids[2]; uint32_t uploaded_tex; uint32_t clear_color; uint32_t clear_depth; @@ -571,7 +545,6 @@ void gl_matrix_init(); void gl_texture_init(); void gl_lighting_init(); void gl_rendermode_init(); -void gl_array_init(); void gl_primitive_init(); void gl_pixel_init(); void gl_list_init(); @@ -598,20 +571,17 @@ void gl_normalize(GLfloat *d, const GLfloat *v); uint32_t gl_get_type_size(GLenum type); -bool gl_storage_alloc(gl_storage_t *storage, uint32_t size); -void gl_storage_free(gl_storage_t *storage); -bool gl_storage_resize(gl_storage_t *storage, uint32_t new_size); - void set_can_use_rsp_dirty(); -void gl_update_array_pointers(gl_array_object_t *obj); - -void gl_fill_attrib_defaults(gl_array_type_t array_type, uint32_t size); -void gl_fill_all_attrib_defaults(const gl_array_t *arrays); -void gl_load_attribs(const gl_array_t *arrays, uint32_t index); +void gl_fill_attrib_defaults(array_type_t array_type, uint32_t size); +void gl_fill_all_attrib_defaults(const array_t *arrays); +void gl_load_attribs(const array_t *arrays, uint32_t index); bool gl_get_cache_index(uint32_t vertex_id, uint8_t *cache_index); bool gl_prim_assembly(uint8_t cache_index, uint8_t *indices); -void gl_read_attrib(gl_array_type_t array_type, const void *value, GLenum type, uint32_t size); +void gl_read_attrib(array_type_t array_type, const void *value, GLenum type, uint32_t size); +void rsp_read_attrib(array_type_t array_type, GLenum type, const void *value, uint32_t size); + +void gl_pre_init_pipe(GLenum primitive_mode); inline uint32_t next_pow2(uint32_t v) { @@ -640,6 +610,8 @@ inline uint32_t gl_type_to_index(GLenum type) return 7; case GL_HALF_FIXED_N64: return 8; + case GL_SHORT_5_6_5_N64: + return 9; default: return -1; } @@ -647,54 +619,11 @@ inline uint32_t gl_type_to_index(GLenum type) #define next_prim_id() (state->prim_id++) -inline const void *gl_get_attrib_element(const gl_array_t *src, uint32_t index) +inline const void *gl_get_attrib_element(const array_t *src, uint32_t index) { return src->final_pointer + index * src->final_stride; } -inline gl_cmd_stream_t gl_cmd_stream_begin(uint32_t ovl_id, uint32_t cmd_id, int size) -{ - return (gl_cmd_stream_t) { - .w = rspq_write_begin(ovl_id, cmd_id, size), - .buffer_head = 2, - }; -} - -inline void gl_cmd_stream_commit(gl_cmd_stream_t *s) -{ - rspq_write_arg(&s->w, s->word); - s->buffer_head = 0; - s->word = 0; -} - -inline void gl_cmd_stream_put_byte(gl_cmd_stream_t *s, uint8_t v) -{ - s->bytes[s->buffer_head++] = v; - - if (s->buffer_head == sizeof(uint32_t)) { - gl_cmd_stream_commit(s); - } -} - -inline void gl_cmd_stream_put_half(gl_cmd_stream_t *s, uint16_t v) -{ - s->bytes[s->buffer_head++] = v >> 8; - s->bytes[s->buffer_head++] = v & 0xFF; - - if (s->buffer_head == sizeof(uint32_t)) { - gl_cmd_stream_commit(s); - } -} - -inline void gl_cmd_stream_end(gl_cmd_stream_t *s) -{ - if (s->buffer_head > 0) { - gl_cmd_stream_commit(s); - } - - rspq_write_end(&s->w); -} - inline bool is_in_heap_memory(void *ptr) { ptr = CachedAddr(ptr); @@ -800,18 +729,18 @@ inline void gl_update_texture_completeness(uint32_t offset) gl_write(GL_CMD_UPDATE, _carg(GL_UPDATE_TEXTURE_COMPLETENESS, 0x7FF, 13) | (offset - offsetof(gl_server_state_t, bound_textures))); } -inline void* gl_get_attrib_pointer(gl_obj_attributes_t *attribs, gl_array_type_t array_type) +inline void* gl_get_attrib_pointer(gl_obj_attributes_t *attribs, array_type_t array_type) { switch (array_type) { - case ATTRIB_VERTEX: + case ARRAY_VERTEX: return attribs->position; - case ATTRIB_COLOR: + case ARRAY_NORMAL: + return attribs->normal; + case ARRAY_COLOR: return attribs->color; - case ATTRIB_TEXCOORD: + case ARRAY_TEXCOORD: return attribs->texcoord; - case ATTRIB_NORMAL: - return attribs->normal; - case ATTRIB_MTX_INDEX: + case ARRAY_MTX_INDEX: return attribs->mtx_index; default: assert(0); @@ -861,43 +790,25 @@ inline void gl_set_current_mtx_index(GLubyte *index) inline void gl_set_palette_idx(uint32_t index) { - gl_write(GL_CMD_SET_PALETTE_IDX, index * sizeof(gl_matrix_srv_t)); + gl_write(GL_CMD_SET_PALETTE_IDX, index * sizeof(gl_pipeline_matrices_t) + offsetof(gl_pipeline_matrices_t, mv)); } -inline void gl_pre_init_pipe(GLenum primitive_mode) +inline color_t color_from_floats(const float color[4]) { - // PreInitPipeTex will run a block with nesting level 1 for texture upload. - // The command itself does not emit RDP commands (the block does that, so - // we use a plain gl_write() for it. - rspq_block_run_rsp(1); - gl_write(GL_CMD_PRE_INIT_PIPE_TEX); - - // PreInitPipe is similar to rdpq_set_mode_standard wrt RDP commands. - // It issues SET_SCISSOR + CC + SOM. - gl_write_rdp(3, GL_CMD_PRE_INIT_PIPE, primitive_mode); -} - -inline void glpipe_init() -{ - glp_write(GLP_CMD_INIT_PIPE, gl_rsp_state); + return RGBA32( + FLOAT_TO_U8(color[0]), + FLOAT_TO_U8(color[1]), + FLOAT_TO_U8(color[2]), + FLOAT_TO_U8(color[3]) + ); } -inline void glpipe_set_vtx_cmd_size(uint16_t patched_cmd_descriptor, uint16_t *cmd_descriptor) -{ - glp_write(GLP_CMD_SET_VTX_CMD_SIZE, patched_cmd_descriptor, PhysicalAddr(cmd_descriptor)); -} +#define gl_require_color_buffer() ({\ + assertf(state->color_buffer != NULL, "gl_context_begin() not called"); \ + state->color_buffer; \ +}) #define TEX_SCALE 32.0f #define OBJ_SCALE 32.0f -inline void glpipe_draw_triangle(int i0, int i1, int i2) -{ - // We pass -1 because the triangle can be clipped and split into multiple - // triangles. - glp_write_rdp(-1, GLP_CMD_DRAW_TRI, - (i0*PRIM_VTX_SIZE), - ((i1*PRIM_VTX_SIZE)<<16) | (i2*PRIM_VTX_SIZE) - ); -} - #endif diff --git a/src/GL/indices.c b/src/GL/indices.c new file mode 100644 index 0000000000..4ff670472d --- /dev/null +++ b/src/GL/indices.c @@ -0,0 +1,15 @@ +#include "indices.h" + +index_bounds_t find_index_bounds(const uint16_t *indices, uint32_t count) +{ + uint16_t min = USHRT_MAX; + uint16_t max = 0; + + for (size_t i = 0; i < count; i++) + { + if (indices[i] < min) min = indices[i]; + if (indices[i] > max) max = indices[i]; + } + + return (index_bounds_t) { min, max - min + 1 }; +} diff --git a/src/GL/indices.h b/src/GL/indices.h new file mode 100644 index 0000000000..6281ca6fef --- /dev/null +++ b/src/GL/indices.h @@ -0,0 +1,32 @@ +#ifndef __INDICES_H +#define __INDICES_H + +#include +#include +#include +#include + +typedef struct { + uint16_t first; + uint16_t count; +} index_bounds_t; + +index_bounds_t find_index_bounds(const uint16_t *indices, uint32_t count); + +inline uint16_t bounds_get_lower_inclusive(index_bounds_t bounds) +{ + return bounds.first; +} + +inline uint16_t bounds_get_upper_exclusive(index_bounds_t bounds) +{ + return bounds.first + bounds.count; +} + +inline bool are_bounds_included(index_bounds_t a, index_bounds_t b) +{ + return bounds_get_lower_inclusive(a) <= bounds_get_lower_inclusive(b) && + bounds_get_upper_exclusive(a) >= bounds_get_upper_exclusive(b); +} + +#endif diff --git a/src/GL/libdragon.mk b/src/GL/libdragon.mk index b6af1d7c9b..91a44dfb39 100644 --- a/src/GL/libdragon.mk +++ b/src/GL/libdragon.mk @@ -1,18 +1,32 @@ LIBDRAGON_OBJS += \ + $(BUILD_DIR)/GL/array_convert.o \ + $(BUILD_DIR)/GL/array_module.o \ + $(BUILD_DIR)/GL/array_object.o \ + $(BUILD_DIR)/GL/buffer.o \ + $(BUILD_DIR)/GL/cpu_pipeline.o \ + $(BUILD_DIR)/GL/data_cache.o \ + $(BUILD_DIR)/GL/data_source.o \ + $(BUILD_DIR)/GL/draw_call_cache.o \ $(BUILD_DIR)/GL/gl.o \ + $(BUILD_DIR)/GL/glu.o \ + $(BUILD_DIR)/GL/indices.o \ $(BUILD_DIR)/GL/lighting.o \ + $(BUILD_DIR)/GL/list.o \ $(BUILD_DIR)/GL/matrix.o \ + $(BUILD_DIR)/GL/mg_ex.o \ + $(BUILD_DIR)/GL/pipelines.o \ + $(BUILD_DIR)/GL/pixelrect.o \ $(BUILD_DIR)/GL/primitive.o \ $(BUILD_DIR)/GL/query.o \ $(BUILD_DIR)/GL/rendermode.o \ - $(BUILD_DIR)/GL/texture.o \ - $(BUILD_DIR)/GL/array.o \ - $(BUILD_DIR)/GL/pixelrect.o \ - $(BUILD_DIR)/GL/obj_map.o \ - $(BUILD_DIR)/GL/list.o \ - $(BUILD_DIR)/GL/buffer.o \ + $(BUILD_DIR)/GL/ringbuffer.o \ $(BUILD_DIR)/GL/rsp_gl.o \ + $(BUILD_DIR)/GL/rsp_gl2.o \ + $(BUILD_DIR)/GL/rsp_gl_pipeline_env_nrm.o \ + $(BUILD_DIR)/GL/rsp_gl_pipeline_env.o \ + $(BUILD_DIR)/GL/rsp_gl_pipeline_nrm.o \ $(BUILD_DIR)/GL/rsp_gl_pipeline.o \ - $(BUILD_DIR)/GL/glu.o \ - $(BUILD_DIR)/GL/cpu_pipeline.o \ - $(BUILD_DIR)/GL/rsp_pipeline.o \ No newline at end of file + $(BUILD_DIR)/GL/rsp_pipeline.o \ + $(BUILD_DIR)/GL/texture.o \ + $(BUILD_DIR)/GL/vertex_layout_cache.o \ + $(BUILD_DIR)/GL/vertex_layout.o \ No newline at end of file diff --git a/src/GL/lighting.c b/src/GL/lighting.c index 822c7779a6..6c970fb90c 100644 --- a/src/GL/lighting.c +++ b/src/GL/lighting.c @@ -63,6 +63,8 @@ void gl_lighting_init() state->light_model_ambient[2] = 0.2f; state->light_model_ambient[3] = 1.0f; state->light_model_local_viewer = false; + + glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); } float gl_mag2(const GLfloat *v) @@ -77,7 +79,8 @@ float gl_mag(const GLfloat *v) void gl_normalize(GLfloat *d, const GLfloat *v) { - float inv_mag = 1.0f / gl_mag(v); + float mag = gl_mag(v); + float inv_mag = mag < FM_EPSILON ? 0.0f : 1.0f / mag; d[0] = v[0] * inv_mag; d[1] = v[1] * inv_mag; @@ -460,7 +463,7 @@ void glMaterialfv(GLenum face, GLenum pname, const GLfloat *params) uint32_t gl_get_light_offset(GLenum light) { uint32_t light_index = light - GL_LIGHT0; - return offsetof(gl_server_state_t, lights) + light_index * sizeof(int16_t) * 4; + return offsetof(gl_server_state_t, lights) + light_index * sizeof(gl_pipeline_light_t); } gl_light_t * gl_get_light(GLenum light) @@ -473,14 +476,27 @@ gl_light_t * gl_get_light(GLenum light) return &state->lights[light - GL_LIGHT0]; } +static void set_rsp_light_color(uint32_t offset, GLfloat r, GLfloat g, GLfloat b, GLfloat a) +{ + int16_t r_fx = FLOAT_TO_I16(r); + int16_t g_fx = FLOAT_TO_I16(g); + int16_t b_fx = FLOAT_TO_I16(b); + + uint64_t packed = ((uint32_t)r_fx << 16) | (uint32_t)g_fx; + gl_set_word(GL_UPDATE_NONE, offset, packed); + gl_set_short(GL_UPDATE_NONE, offset + sizeof(int16_t)*2, b_fx); +} + void gl_light_set_ambient(gl_light_t *light, uint32_t offset, GLfloat r, GLfloat g, GLfloat b, GLfloat a) { - gl_set_color(light->ambient, offset + offsetof(gl_lights_soa_t, ambient), r, g, b, a); + set_rsp_light_color(offset + offsetof(gl_pipeline_light_t, ambient), r, g, b, a); + gl_set_color_cpu(light->ambient, r, g, b, a); } void gl_light_set_diffuse(gl_light_t *light, uint32_t offset, GLfloat r, GLfloat g, GLfloat b, GLfloat a) { - gl_set_color(light->diffuse, offset + offsetof(gl_lights_soa_t, diffuse), r, g, b, a); + set_rsp_light_color(offset + offsetof(gl_pipeline_light_t, diffuse), r, g, b, a); + gl_set_color_cpu(light->diffuse, r, g, b, a); } void gl_light_set_specular(gl_light_t *light, uint32_t offset, GLfloat r, GLfloat g, GLfloat b, GLfloat a) @@ -498,17 +514,17 @@ void gl_light_set_position(gl_light_t *light, uint32_t offset, const GLfloat *po // Light is directional // -> Pre-normalize so the ucode doesn't need to float mag = gl_mag(pos); - x = (pos[0] / mag) * 0x7FFF; - y = (pos[1] / mag) * 0x7FFF; - z = (pos[2] / mag) * 0x7FFF; + x = FLOAT_TO_I16(pos[0] / mag); + y = FLOAT_TO_I16(pos[1] / mag); + z = FLOAT_TO_I16(pos[2] / mag); w = 0; } else { // Light is positional // -> Convert to s10.5 to match with object space position - x = pos[0] * 32.f; - y = pos[1] * 32.f; - z = pos[2] * 32.f; - w = 32.f; + x = pos[0] * (1<<5); + y = pos[1] * (1<<5); + z = pos[2] * (1<<5); + w = (1<<5); } uint32_t packed0 = ((uint32_t)x) << 16 | (uint32_t)y; @@ -520,29 +536,16 @@ void gl_light_set_position(gl_light_t *light, uint32_t offset, const GLfloat *po void gl_light_set_direction(gl_light_t *light, uint32_t offset, const GLfloat *dir) { gl_matrix_mult3x3(light->direction, gl_matrix_stack_get_matrix(&state->modelview_stack), dir); - -/* - int16_t x = dir[0] * 0x7FFF; - int16_t y = dir[1] * 0x7FFF; - int16_t z = dir[2] * 0x7FFF; - - uint32_t packed0 = ((uint32_t)x) << 16 | (uint32_t)y; - uint32_t packed1 = ((uint32_t)z) << 16; - - gl_write(GL_CMD_SET_LIGHT_DIR, offset, packed0, packed1); -*/ } void gl_light_set_spot_exponent(gl_light_t *light, uint32_t offset, float param) { light->spot_exponent = param; - //gl_set_byte(GL_UPDATE_NONE, offset + offsetof(gl_light_srv_t, spot_exponent), param); } void gl_light_set_spot_cutoff(gl_light_t *light, uint32_t offset, float param) { light->spot_cutoff_cos = cosf(RADIANS(param)); - //gl_set_short(GL_UPDATE_NONE, offset + offsetof(gl_light_srv_t, spot_cutoff_cos), light->spot_cutoff_cos * 0x7FFF); set_can_use_rsp_dirty(); } @@ -551,8 +554,8 @@ void gl_light_set_constant_attenuation(gl_light_t *light, uint32_t offset, float light->constant_attenuation = param; // Shifted right by 1 to compensate for vrcp uint32_t fx = param * (1<<15); - gl_set_short(GL_UPDATE_NONE, offset + offsetof(gl_lights_soa_t, attenuation_int) + 0, fx >> 16); - gl_set_short(GL_UPDATE_NONE, offset + offsetof(gl_lights_soa_t, attenuation_frac) + 0, fx & 0xFFFF); + gl_set_short(GL_UPDATE_NONE, offset + offsetof(gl_pipeline_light_t, attenuation_int) + 0, fx >> 16); + gl_set_short(GL_UPDATE_NONE, offset + offsetof(gl_pipeline_light_t, attenuation_frac) + 0, fx & 0xFFFF); } void gl_light_set_linear_attenuation(gl_light_t *light, uint32_t offset, float param) @@ -562,8 +565,8 @@ void gl_light_set_linear_attenuation(gl_light_t *light, uint32_t offset, float p // Shifted right by 1 to compensate for vrcp // Result: Shifted right by 5 uint32_t fx = param * (1 << (16 - 5)); - gl_set_short(GL_UPDATE_NONE, offset + offsetof(gl_lights_soa_t, attenuation_int) + 2, fx >> 16); - gl_set_short(GL_UPDATE_NONE, offset + offsetof(gl_lights_soa_t, attenuation_frac) + 2, fx & 0xFFFF); + gl_set_short(GL_UPDATE_NONE, offset + offsetof(gl_pipeline_light_t, attenuation_int) + 2, fx >> 16); + gl_set_short(GL_UPDATE_NONE, offset + offsetof(gl_pipeline_light_t, attenuation_frac) + 2, fx & 0xFFFF); } void gl_light_set_quadratic_attenuation(gl_light_t *light, uint32_t offset, float param) @@ -573,8 +576,8 @@ void gl_light_set_quadratic_attenuation(gl_light_t *light, uint32_t offset, floa // Shifted right by 1 to compensate for vrcp // Result: Shifted left by 5 uint32_t fx = param * (1 << (16 + 5)); - gl_set_short(GL_UPDATE_NONE, offset + offsetof(gl_lights_soa_t, attenuation_int) + 4, fx >> 16); - gl_set_short(GL_UPDATE_NONE, offset + offsetof(gl_lights_soa_t, attenuation_frac) + 4, fx & 0xFFFF); + gl_set_short(GL_UPDATE_NONE, offset + offsetof(gl_pipeline_light_t, attenuation_int) + 4, fx >> 16); + gl_set_short(GL_UPDATE_NONE, offset + offsetof(gl_pipeline_light_t, attenuation_frac) + 4, fx & 0xFFFF); } void glLightf(GLenum light, GLenum pname, GLfloat param) @@ -819,29 +822,29 @@ void glColorMaterial(GLenum face, GLenum mode) return; } - uint64_t color_target = 0; + uint16_t flags = 0; switch (mode) { case GL_AMBIENT: - color_target |= 1ULL << 48; + flags = GLP_MATERIAL_FLAG_AMBIENT; break; case GL_DIFFUSE: - color_target |= 1ULL << 32; + flags = GLP_MATERIAL_FLAG_DIFFUSE; break; - case GL_SPECULAR: case GL_EMISSION: - color_target |= 1ULL << 16; + flags = GLP_MATERIAL_FLAG_EMISSIVE; break; case GL_AMBIENT_AND_DIFFUSE: - color_target |= 1ULL << 48; - color_target |= 1ULL << 32; + flags = GLP_MATERIAL_FLAG_AMBIENT | GLP_MATERIAL_FLAG_DIFFUSE; + break; + case GL_SPECULAR: break; default: gl_set_error(GL_INVALID_ENUM, "%#04lx is not a valid color material mode", mode); return; } - gl_set_long(GL_UPDATE_NONE, offsetof(gl_server_state_t, mat_color_target), color_target); + gl_set_short(GL_UPDATE_NONE, offsetof(gl_server_state_t, mat_color_target), flags); state->material.color_target = mode; } diff --git a/src/GL/list.c b/src/GL/list.c index f6bf4e1199..d4a107f318 100644 --- a/src/GL/list.c +++ b/src/GL/list.c @@ -6,7 +6,7 @@ #include "gl_internal.h" #include "rspq.h" -#define EMPTY_LIST ((rspq_block_t*)1) +#define EMPTY_LIST ((rspq_block_t*)VirtualCachedAddr(1)) extern gl_state_t *state; @@ -17,7 +17,7 @@ inline bool is_non_empty_list(rspq_block_t *block) return block != NULL && block != EMPTY_LIST; } -void block_free_safe(rspq_block_t *block) +void list_free(rspq_block_t *block) { // Silently ignore NULL and EMPTY_LIST if (!is_non_empty_list(block)) return; @@ -26,19 +26,19 @@ void block_free_safe(rspq_block_t *block) void gl_list_init() { - // TODO: Get rid of the hash map. This will be difficult due to the semantics of glGenLists (it's guaranteed to generate consecutive IDs) - obj_map_new(&state->list_objects); + hashtable_init(&state->lists, 8, NULL); state->next_list_name = 1; } -void gl_list_close() +static void list_free_visitor(uint32_t key, void *value, int refcount) { - obj_map_iter_t list_iter = obj_map_iterator(&state->list_objects); - while (obj_map_iterator_next(&list_iter)) { - block_free_safe((rspq_block_t*)list_iter.value); - } + list_free((rspq_block_t*)value); +} - obj_map_free(&state->list_objects); +void gl_list_close() +{ + hashtable_visit(&state->lists, list_free_visitor); + hashtable_free(&state->lists); } void glNewList(GLuint n, GLenum mode) @@ -82,8 +82,8 @@ void glEndList(void) rspq_block_t *block = rspq_block_end(); - block = obj_map_set(&state->list_objects, state->current_list, block); - block_free_safe(block); + list_free(hashtable_remove(&state->lists, state->current_list)); + hashtable_insert(&state->lists, state->current_list, block); state->current_list = 0; } @@ -94,7 +94,7 @@ void glCallList(GLuint n) // During display list recording, we cannot anticipate whether it will be called within a glBegin/glEnd pair or not. assertf(!state->begin_end_active, "glCallList between glBegin/glEnd is not supported!"); - rspq_block_t *block = obj_map_get(&state->list_objects, n); + rspq_block_t *block = hashtable_lookup(&state->lists, n); // Silently ignore NULL and EMPTY_LIST if (is_non_empty_list(block)) { rspq_block_run(block); @@ -222,7 +222,7 @@ GLuint glGenLists(GLsizei s) // Set newly used indices to empty lists (which marks them as used without actually creating a block) for (size_t i = 0; i < s; i++) { - obj_map_set(&state->list_objects, state->next_list_name++, EMPTY_LIST); + hashtable_insert(&state->lists, state->next_list_name++, EMPTY_LIST); } return result; @@ -233,7 +233,7 @@ GLboolean glIsList(GLuint list) if (!gl_ensure_no_begin_end()) return 0; // We do not check for EMPTY_LIST here because that also denotes a used list index - return obj_map_get(&state->list_objects, list) != NULL; + return hashtable_lookup(&state->lists, list) != NULL; } void glDeleteLists(GLuint list, GLsizei range) @@ -242,7 +242,6 @@ void glDeleteLists(GLuint list, GLsizei range) for (GLuint i = 0; i < range; i++) { - rspq_block_t *block = obj_map_remove(&state->list_objects, list + i); - block_free_safe(block); + list_free(hashtable_remove(&state->lists, list + i)); } } diff --git a/src/GL/matrix.c b/src/GL/matrix.c index 4ed70ad9be..f3c494977f 100644 --- a/src/GL/matrix.c +++ b/src/GL/matrix.c @@ -462,4 +462,4 @@ void glCopyMatrixN64(GLenum source) memcpy(state->current_matrix, gl_matrix_stack_get_matrix(matrix_stack), sizeof(gl_matrix_t)); gl_mark_matrix_target_dirty(); gl_write(GL_CMD_MATRIX_COPY, src_id << 6); -} \ No newline at end of file +} diff --git a/src/GL/mg_ex.c b/src/GL/mg_ex.c new file mode 100644 index 0000000000..42a0bd4784 --- /dev/null +++ b/src/GL/mg_ex.c @@ -0,0 +1,82 @@ +#include "mg_ex.h" +#include "magma_constants.h" + +#define MAX_QUADS_IN_BATCH_COUNT (MG_VERTEX_CACHE_COUNT/4) +#define QUAD_BATCH_SIZE (MAX_QUADS_IN_BATCH_COUNT*5) + +static void mg_ex_draw_quads(const mg_input_assembly_parms_t *input_assembly_parms, uint32_t count, uint32_t first) +{ + uint16_t batch_indices[QUAD_BATCH_SIZE]; + + const uint32_t prim_count = count / 4; + for (uint32_t prim_index = 0; prim_index < prim_count; prim_index += MAX_QUADS_IN_BATCH_COUNT) + { + uint32_t prims_in_batch_count = MIN(prim_count - prim_index, MAX_QUADS_IN_BATCH_COUNT); + for (uint32_t i = 0; i < prims_in_batch_count; i++) + { + for (uint32_t j = 0; j < 4; j++) + batch_indices[i*5 + j] = first + (prim_index+i)*4 + j; + + batch_indices[i*5 + 4] = -1; + } + + mg_draw_indexed(input_assembly_parms, batch_indices, prims_in_batch_count*5, 0); + } +} + +void mg_ex_draw(const mg_input_assembly_parms_t *input_assembly_parms, uint32_t count, uint32_t first, GLenum mode) +{ + switch (mode) + { + case GL_QUADS: + // Quads need special handling + mg_ex_draw_quads(input_assembly_parms, count, first); + break; + case GL_QUAD_STRIP: + // Quad strips are equivalent to triangle strips, except that only every 2 vertices form a new quad. + // -> Round down to nearest multiple of 2 to avoid "half" a quad being drawn. + mg_draw(input_assembly_parms, ROUND_DOWN(count, 2), first); + break; + default: + // Everything else is supported as-is, just pass through. + mg_draw(input_assembly_parms, count, first); + break; + } +} + +static void mg_ex_draw_quads_indexed(const mg_input_assembly_parms_t *input_assembly_parms, const uint16_t *indices, uint32_t count, int32_t offset) +{ + uint16_t batch_indices[QUAD_BATCH_SIZE]; + + const uint32_t prim_count = count / 4; + for (uint32_t prim_index = 0; prim_index < prim_count; prim_index += MAX_QUADS_IN_BATCH_COUNT) + { + uint32_t prims_in_batch_count = MIN(prim_count - prim_index, MAX_QUADS_IN_BATCH_COUNT); + for (uint32_t i = 0; i < prims_in_batch_count; i++) + { + memcpy(batch_indices + i*5, indices + (prim_index+i)*4, sizeof(uint16_t)*4); + batch_indices[i*5 + 4] = -1; + } + + mg_draw_indexed(input_assembly_parms, batch_indices, prims_in_batch_count*5, offset); + } +} + +void mg_ex_draw_indexed(const mg_input_assembly_parms_t *input_assembly_parms, const uint16_t *indices, uint32_t count, int32_t offset, GLenum mode) +{ + switch (mode) + { + case GL_QUADS: + mg_ex_draw_quads_indexed(input_assembly_parms, indices, count, offset); + break; + case GL_QUAD_STRIP: + // Quad strips are equivalent to triangle strips, except that only every 2 vertices form a new quad. + // -> Round down to nearest multiple of 2 to avoid "half" a quad being drawn. + mg_draw_indexed(input_assembly_parms, indices, ROUND_DOWN(count, 2), offset); + break; + default: + // Everything else is supported as-is, just pass through. + mg_draw_indexed(input_assembly_parms, indices, count, offset); + break; + } +} diff --git a/src/GL/mg_ex.h b/src/GL/mg_ex.h new file mode 100644 index 0000000000..702b92104b --- /dev/null +++ b/src/GL/mg_ex.h @@ -0,0 +1,18 @@ +#ifndef __MG_EX_H +#define __MG_EX_H + +#include "gl_internal.h" +#include "magma.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void mg_ex_draw(const mg_input_assembly_parms_t *input_assembly_parms, uint32_t count, uint32_t first, GLenum mode); +void mg_ex_draw_indexed(const mg_input_assembly_parms_t *input_assembly_parms, const uint16_t *indices, uint32_t count, int32_t offset, GLenum mode); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/GL/obj_map.c b/src/GL/obj_map.c deleted file mode 100644 index da4290d86c..0000000000 --- a/src/GL/obj_map.c +++ /dev/null @@ -1,176 +0,0 @@ -/** - * @file obj_map.c - * @author Dennis Heinze - * @brief Simple hash map implementation for OpenGL object management. - * - * This is a very simple hash map that uses open adressing (linear probing). - * The hash function is the identity for now, since it uses integer keys. - */ - -#include "obj_map.h" - -#include -#include -#include - -#define OBJ_MAP_MIN_CAPACITY 32 -#define OBJ_MAP_DELETED_KEY 0xFFFFFFFF - -void obj_map_new(obj_map_t *map) -{ - assertf(map->entries == NULL, "Map has not been freed!"); - - map->entries = calloc(OBJ_MAP_MIN_CAPACITY, sizeof(obj_map_entry_t)); - assertf(map->entries != NULL, "Out of memory"); - map->capacity = OBJ_MAP_MIN_CAPACITY; - map->count = 0; -} - -void obj_map_free(obj_map_t *map) -{ - assertf(map->entries != NULL, "Map is not initialized!"); - - free(map->entries); - map->entries = NULL; -} - -obj_map_entry_t * obj_map_find_entry(const obj_map_t *map, uint32_t key) -{ - uint32_t mask = (map->capacity - 1); - - for (uint32_t i = 0; i < map->capacity; i++) { - obj_map_entry_t *entry = &map->entries[(key + i) & mask]; - - if (entry->key == key) { - return entry; - } - - if (entry->value == NULL && entry->key != OBJ_MAP_DELETED_KEY) { - // Stop probing when unused entry is found. - // However, keep searching if the entry has been deleted - break; - } - } - - return NULL; -} - -void * obj_map_set_without_expanding(obj_map_t *map, uint32_t key, void *value) -{ - uint32_t mask = (map->capacity - 1); - - for (uint32_t i = 0; i < map->capacity; i++) { - obj_map_entry_t *e = &map->entries[(key + i) & mask]; - - if (e->value == NULL) { - // Entry is unused or has been deleted - // -> New entry is added - e->key = key; - e->value = value; - map->count++; - return NULL; - } - - if (e->key == key) { - // Key is already present - // -> Value is changed, but no new entry is added - void *old_value = e->value; - e->value = value; - return old_value; - } - } - - assertf(0, "Map is full!"); - abort(); -} - -void obj_map_expand(obj_map_t *map) -{ - obj_map_entry_t *old_entries = map->entries; - uint32_t old_capacity = map->capacity; - - map->capacity = old_capacity << 1; - map->entries = calloc(map->capacity, sizeof(obj_map_entry_t)); - assertf(map->entries != NULL, "Out of memory"); - map->count = 0; - - // Re-populate the map with all used entries - for (uint32_t i = 0; i < old_capacity; i++) { - obj_map_entry_t *entry = &old_entries[i]; - if (entry->value != NULL) { - obj_map_set_without_expanding(map, entry->key, entry->value); - } - } - - free(old_entries); -} - -void * obj_map_get(const obj_map_t *map, uint32_t key) -{ - assertf(map->entries != NULL, "Map is not initialized!"); - - obj_map_entry_t *entry = obj_map_find_entry(map, key); - return entry == NULL ? NULL : entry->value; -} - -void * obj_map_set(obj_map_t *map, uint32_t key, void *value) -{ - assertf(map->entries != NULL, "Map is not initialized!"); - assertf(value != NULL, "Can't insert NULL into map!"); - - if (map->count * 2 > map->capacity) { - // If more than half the capacity is used, expand the map - obj_map_expand(map); - } - - return obj_map_set_without_expanding(map, key, value); -} - -void * obj_map_remove(obj_map_t *map, uint32_t key) -{ - assertf(map->entries != NULL, "Map is not initialized!"); - - obj_map_entry_t *entry = obj_map_find_entry(map, key); - - if (entry != NULL) { - void *v = entry->value; - entry->value = NULL; - // Mark the entry as deleted with magic value - entry->key = OBJ_MAP_DELETED_KEY; - map->count--; - return v; - } - - return NULL; -} - -obj_map_iter_t obj_map_iterator(obj_map_t *map) -{ - assertf(map->entries != NULL, "Map is not initialized!"); - - return (obj_map_iter_t) { - ._map = map, - ._index = 0 - }; -} - -bool obj_map_iterator_next(obj_map_iter_t *iter) -{ - assertf(iter->_map != NULL, "Map iterator is not initialized!"); - - uint32_t cur_index = iter->_index; - - while (cur_index < iter->_map->capacity) { - obj_map_entry_t *cur_entry = &iter->_map->entries[cur_index]; - cur_index++; - - if (cur_entry->value != NULL) { - iter->key = cur_entry->key; - iter->value = cur_entry->value; - iter->_index = cur_index; - return true; - } - } - - return false; -} diff --git a/src/GL/obj_map.h b/src/GL/obj_map.h deleted file mode 100644 index a3181262fc..0000000000 --- a/src/GL/obj_map.h +++ /dev/null @@ -1,57 +0,0 @@ -/** - * @file obj_map.h - * @author Dennis Heinze - */ -#ifndef _GL_OBJ_MAP_H -#define _GL_OBJ_MAP_H - -#include -#include -#include - -typedef struct { - uint32_t key; - void *value; -} obj_map_entry_t; - -typedef struct { - obj_map_entry_t *entries; - uint32_t capacity; - uint32_t count; -} obj_map_t; - -typedef struct { - uint32_t key; - void *value; - - obj_map_t *_map; - uint32_t _index; -} obj_map_iter_t; - -#ifdef __cplusplus -extern "C" { -#endif - -void obj_map_new(obj_map_t *map); -void obj_map_free(obj_map_t *map); - -inline uint32_t obj_map_count(const obj_map_t *map) -{ - assertf(map->entries != NULL, "Map is not initialized!"); - - return map->count; -} - -void * obj_map_get(const obj_map_t *map, uint32_t key); -void * obj_map_set(obj_map_t *map, uint32_t key, void *value); -void * obj_map_remove(obj_map_t *map, uint32_t key); - -obj_map_iter_t obj_map_iterator(obj_map_t *map); -bool obj_map_iterator_next(obj_map_iter_t *iter); - -#ifdef __cplusplus -} -#endif - - -#endif diff --git a/src/GL/pipelines.c b/src/GL/pipelines.c new file mode 100644 index 0000000000..84a40d88b1 --- /dev/null +++ b/src/GL/pipelines.c @@ -0,0 +1,82 @@ +#include "pipelines.h" +#include "gl_constants.h" +#include "gl_internal.h" +#include "utils.h" +#include "../magma/magma_internal.h" + +extern gl_state_t *state; + +DEFINE_RSP_UCODE(rsp_gl_pipeline); +DEFINE_RSP_UCODE(rsp_gl_pipeline_env); +DEFINE_RSP_UCODE(rsp_gl_pipeline_nrm); +DEFINE_RSP_UCODE(rsp_gl_pipeline_env_nrm); + +static rsp_ucode_t *pipeline_ucodes[] = { + &rsp_gl_pipeline, + &rsp_gl_pipeline_env, + &rsp_gl_pipeline_nrm, + &rsp_gl_pipeline_env_nrm +}; + +static rsp_ucode_t *get_pipeline_ucode(uint32_t features) +{ + return pipeline_ucodes[features]; +} + +static mg_pipeline_t **create_pipelines(const vertex_layout_t *layout) +{ + mg_pipeline_t **pipelines = calloc(PIPELINE_COUNT, sizeof(mg_pipeline_t*)); + + // This will iterate over all possible combinations of features + for (size_t i = 0; i < PIPELINE_COUNT; i++) + { + pipelines[i] = mg_pipeline_create(&(mg_pipeline_parms_t) { + .vertex_shader_ucode = get_pipeline_ucode(i), + .vertex_layout = layout->vertex_layout + }); + } + + return pipelines; +} + +static mg_pipeline_t **get_or_create_pipelines(const vertex_layout_t *layout) +{ + uint32_t key = vertex_layout_get_hash(layout); + + mg_pipeline_t **pipelines = hashtable_lookup(&state->pipeline_cache, key); + if (pipelines == NULL) { + pipelines = create_pipelines(layout); + hashtable_insert(&state->pipeline_cache, key, pipelines); + } + + return pipelines; +} + +static void assign_pipelines(mg_pipeline_t **pipelines) +{ + for (size_t i = 0; i < PIPELINE_COUNT; i++) + { + uint32_t packed = ((sizeof(gl_pipeline_data_t)*i) << 16) | (ROUND_UP(pipelines[i]->shader_code_size, 8) - 1); + gl2_write(GL_CMD_SET_PIPELINE, PhysicalAddr(pipelines[i]->shader_code), packed); + } +} + +void update_pipelines_from_layout(const vertex_layout_t *vertex_layout) +{ + mg_pipeline_t **pipelines = get_or_create_pipelines(vertex_layout); + assign_pipelines(pipelines); +} + +static const mg_uniform_t *get_matrices_uniform_from_pipelines(mg_pipeline_t **pipelines) +{ + return mg_pipeline_get_uniform(pipelines[0], GLP_BINDING_MATRICES); +} + +const mg_uniform_t *get_matrices_uniform() +{ + if (state->matrices_uniform == NULL) { + mg_pipeline_t **pipelines = get_or_create_pipelines(&state->begin_end_layout); + state->matrices_uniform = get_matrices_uniform_from_pipelines(pipelines); + } + return state->matrices_uniform; +} diff --git a/src/GL/pipelines.h b/src/GL/pipelines.h new file mode 100644 index 0000000000..1b04e66f59 --- /dev/null +++ b/src/GL/pipelines.h @@ -0,0 +1,18 @@ +#ifndef __PIPELINES_H +#define __PIPELINES_H + +#include "vertex_layout.h" +#include "magma.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void update_pipelines_from_layout(const vertex_layout_t *vertex_layout); +const mg_uniform_t *get_matrices_uniform(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/GL/primitive.c b/src/GL/primitive.c index 3c689a95cc..0bcd45df41 100644 --- a/src/GL/primitive.c +++ b/src/GL/primitive.c @@ -13,6 +13,8 @@ #include "../rdpq/rdpq_internal.h" #include #include +#include "array.h" +#include "rsp_pipeline.h" _Static_assert(((RDPQ_CMD_TRI << 8) | (FLAG_DEPTH_TEST >> TRICMD_ATTR_SHIFT)) == (RDPQ_CMD_TRI_ZBUF << 8)); _Static_assert(((RDPQ_CMD_TRI << 8) | (FLAG_TEXTURE_ACTIVE >> TRICMD_ATTR_SHIFT)) == (RDPQ_CMD_TRI_TEX << 8)); @@ -21,22 +23,10 @@ _Static_assert(((FLAG_DEPTH_TEST | FLAG_TEXTURE_ACTIVE) >> TRICMD_ATTR_SHIFT) == extern gl_state_t *state; -uint8_t gl_points(); -uint8_t gl_lines(); -uint8_t gl_line_strip(); -uint8_t gl_triangles(); -uint8_t gl_triangle_strip(); -uint8_t gl_triangle_fan(); -uint8_t gl_quads(); - -void gl_reset_vertex_cache(); - -void gl_init_cpu_pipe(); -void gl_vertex_pre_tr(uint8_t cache_index); -void gl_draw_primitive(const uint8_t *indices); - void gl_primitive_init() { + rsp_pipeline_init(); + state->tex_gen[0].mode = GL_EYE_LINEAR; state->tex_gen[0].object_plane[0] = 1; state->tex_gen[0].eye_plane[0] = 1; @@ -51,18 +41,15 @@ void gl_primitive_init() state->point_size = 1; state->line_width = 1; - state->current_attributes.color[0] = 1; - state->current_attributes.color[1] = 1; - state->current_attributes.color[2] = 1; - state->current_attributes.color[3] = 1; - state->current_attributes.texcoord[3] = 1; - state->current_attributes.normal[2] = 1; + glNormal3f(0, 0, 1); + glColor4f(1, 1, 1, 1); + glTexCoord4f(0, 0, 0, 1); - state->vertex_halfx_precision.target_precision = VTX_SHIFT; - state->texcoord_halfx_precision.target_precision = TEX_SHIFT; + state->vertex_halfx_precision.target_precision = GLP_VTX_POS_SHIFT; + state->texcoord_halfx_precision.target_precision = GLP_VTX_TEX_SHIFT; - glVertexHalfFixedPrecisionN64(VTX_SHIFT); - glTexCoordHalfFixedPrecisionN64(TEX_SHIFT); + glVertexHalfFixedPrecisionN64(GLP_VTX_POS_SHIFT); + glTexCoordHalfFixedPrecisionN64(GLP_VTX_TEX_SHIFT); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); @@ -71,9 +58,10 @@ void gl_primitive_init() void gl_primitive_close() { + rsp_pipeline_close(); } -bool gl_can_use_rsp_pipeline() +bool gl_can_use_rsp_pipeline(GLenum mode) { #define WARN_CPU_REQUIRED(msg) ({ \ static bool warn_state ## __LINE__; \ @@ -83,6 +71,23 @@ bool gl_can_use_rsp_pipeline() } \ }) + switch (mode) { + case GL_TRIANGLES: + case GL_TRIANGLE_STRIP: + case GL_TRIANGLE_FAN: + case GL_QUADS: + case GL_QUAD_STRIP: + case GL_POLYGON: + break; + case GL_POINTS: + case GL_LINES: + case GL_LINE_LOOP: + case GL_LINE_STRIP: + default: + WARN_CPU_REQUIRED("primitive mode"); + return false; + } + // Points and lines are not implemented if (state->polygon_mode != GL_FILL) { WARN_CPU_REQUIRED("polygon mode"); @@ -114,6 +119,20 @@ bool gl_can_use_rsp_pipeline() } } + for (size_t i = 0; i < TEX_GEN_COUNT; i++) + { + if (state->tex_gen[i].enabled) { + if (state->tex_gen[i].mode == GL_OBJECT_LINEAR) { + WARN_CPU_REQUIRED("tex gen object linear"); + return false; + } + if (state->tex_gen[i].mode == GL_EYE_LINEAR) { + WARN_CPU_REQUIRED("tex gen eye linear"); + return false; + } + } + } + return true; #undef WARN_CPU_REQUIRED @@ -124,118 +143,46 @@ void set_can_use_rsp_dirty() state->can_use_rsp_dirty = true; } -bool gl_init_prim_assembly(GLenum mode) +extern const gl_pipeline_t gl_cpu_pipeline; +extern const gl_pipeline_t gl_rsp_pipeline; + +static void prepare_drawing(GLenum mode) { + state->can_use_rsp = gl_can_use_rsp_pipeline(mode); + state->current_pipeline = state->can_use_rsp ? &gl_rsp_pipeline : &gl_cpu_pipeline; - state->lock_next_vertex = false; + gl_pre_init_pipe(mode); + array_object_update_pointers(state->array_object); +} +static bool validate_mode(GLenum mode) +{ switch (mode) { case GL_POINTS: - state->prim_func = gl_points; - state->prim_size = 1; - break; case GL_LINES: - state->prim_func = gl_lines; - state->prim_size = 2; - break; case GL_LINE_LOOP: - // Line loop is equivalent to line strip, except for special case handled in glEnd - state->prim_func = gl_line_strip; - state->prim_size = 2; - state->lock_next_vertex = true; - break; case GL_LINE_STRIP: - state->prim_func = gl_line_strip; - state->prim_size = 2; - break; case GL_TRIANGLES: - state->prim_func = gl_triangles; - state->prim_size = 3; - break; case GL_TRIANGLE_STRIP: - state->prim_func = gl_triangle_strip; - state->prim_size = 3; - break; case GL_TRIANGLE_FAN: - state->prim_func = gl_triangle_fan; - state->prim_size = 3; - state->lock_next_vertex = true; - break; case GL_QUADS: - state->prim_func = gl_quads; - state->prim_size = 3; - break; case GL_QUAD_STRIP: - // Quad strip is equivalent to triangle strip - state->prim_func = gl_triangle_strip; - state->prim_size = 3; - break; case GL_POLYGON: - // Polygon is equivalent to triangle fan - state->prim_func = gl_triangle_fan; - state->prim_size = 3; - state->lock_next_vertex = true; - break; + return true; default: gl_set_error(GL_INVALID_ENUM, "%#04lx is not a valid primitive mode", mode); return false; } - - state->primitive_mode = mode; - state->prim_progress = 0; - state->prim_counter = 0; - state->prim_id = 0x80000000; - - return true; -} - -extern const gl_pipeline_t gl_cpu_pipeline; -extern const gl_pipeline_t gl_rsp_pipeline; - -bool gl_begin(GLenum mode) -{ - if (state->can_use_rsp_dirty) { - state->can_use_rsp = gl_can_use_rsp_pipeline(); - state->can_use_rsp_dirty = false; - } - - if (!gl_init_prim_assembly(mode)) { - return false; - } - - gl_reset_vertex_cache(); - - __rdpq_autosync_change(AUTOSYNC_PIPE | AUTOSYNC_TILES | AUTOSYNC_TMEM(0)); - - gl_pre_init_pipe(mode); - - // FIXME: This is pessimistically marking everything as used, even if textures are turned off - // CAUTION: texture state is owned by the RSP currently, so how can we determine this? - __rdpq_autosync_use(AUTOSYNC_PIPE | AUTOSYNC_TILES | AUTOSYNC_TMEM(0)); - - gl_update_array_pointers(state->array_object); - - // Only triangles are implemented on RSP - bool rsp_pipeline_enabled = state->can_use_rsp && state->prim_size == 3; - state->current_pipeline = rsp_pipeline_enabled ? &gl_rsp_pipeline : &gl_cpu_pipeline; - - state->current_pipeline->begin(); - - return true; -} - -void gl_end() -{ - state->current_pipeline->end(); } void glBegin(GLenum mode) { if (!gl_ensure_no_begin_end()) return; + if (!validate_mode(mode)) return; - if (gl_begin(mode)) { - state->begin_end_active = true; - } + prepare_drawing(mode); + state->begin_end_active = true; + state->current_pipeline->begin(mode); } void glEnd(void) @@ -244,63 +191,15 @@ void glEnd(void) gl_set_error(GL_INVALID_OPERATION, "glEnd must be called after glBegin"); } - gl_end(); - + state->current_pipeline->end(); state->begin_end_active = false; } -void gl_reset_vertex_cache() -{ - memset(state->vertex_cache_ids, 0, sizeof(state->vertex_cache_ids)); - memset(state->lru_age_table, 0, sizeof(state->lru_age_table)); - state->lru_next_age = 1; -} - -bool gl_check_vertex_cache(uint32_t id, uint8_t *cache_index, bool lock) +void gl_load_attribs(const array_t *arrays, uint32_t index) { - const uint32_t INFINITE_AGE = 0xFFFFFFFF; // infinitely recent - - bool miss = true; - - uint32_t min_age = INFINITE_AGE; - for (uint8_t ci = 0; ci < VERTEX_CACHE_SIZE; ci++) + for (uint32_t i = 0; i < ARRAY_COUNT; i++) { - if (state->vertex_cache_ids[ci] == id) { - miss = false; - *cache_index = ci; - break; - } - - if (state->lru_age_table[ci] < min_age) { - min_age = state->lru_age_table[ci]; - *cache_index = ci; - } - } - - uint32_t age = lock ? INFINITE_AGE : state->lru_next_age++; - state->lru_age_table[*cache_index] = age; - state->vertex_cache_ids[*cache_index] = id; - - return miss; -} - -bool gl_get_cache_index(uint32_t vertex_id, uint8_t *cache_index) -{ - bool result = gl_check_vertex_cache(vertex_id + 1, cache_index, state->lock_next_vertex); - - if (state->lock_next_vertex) { - state->lock_next_vertex = false; - state->locked_vertex = *cache_index; - } - - return result; -} - -void gl_load_attribs(const gl_array_t *arrays, uint32_t index) -{ - for (uint32_t i = 0; i < ATTRIB_COUNT; i++) - { - const gl_array_t *array = &arrays[i]; + const array_t *array = &arrays[i]; if (!array->enabled) { continue; } @@ -312,15 +211,15 @@ void gl_load_attribs(const gl_array_t *arrays, uint32_t index) } } -void gl_fill_attrib_defaults(gl_array_type_t array_type, uint32_t size) +void gl_fill_attrib_defaults(array_type_t array_type, uint32_t size) { static const GLfloat default_attribute_value[] = {0.0f, 0.0f, 0.0f, 1.0f}; uint32_t element_size = sizeof(GLfloat); switch (array_type) { - case ATTRIB_VERTEX: - case ATTRIB_COLOR: - case ATTRIB_TEXCOORD: + case ARRAY_VERTEX: + case ARRAY_COLOR: + case ARRAY_TEXCOORD: break; default: return; @@ -331,12 +230,12 @@ void gl_fill_attrib_defaults(gl_array_type_t array_type, uint32_t size) memcpy(dst, src, (4 - size) * element_size); } -void gl_fill_all_attrib_defaults(const gl_array_t *arrays) +void gl_fill_all_attrib_defaults(const array_t *arrays) { // There are no default values for the matrix index because it is always specified fully. - for (uint32_t i = 0; i < ATTRIB_COUNT; i++) + for (uint32_t i = 0; i < ARRAY_COUNT; i++) { - const gl_array_t *array = &arrays[i]; + const array_t *array = &arrays[i]; if (!arrays[i].enabled) { continue; } @@ -345,184 +244,41 @@ void gl_fill_all_attrib_defaults(const gl_array_t *arrays) } } -uint8_t gl_points() -{ - // Reset the progress to zero since we start with a completely new primitive that - // won't share any vertices with the previous ones - return 0; -} - -uint8_t gl_lines() -{ - // Reset the progress to zero since we start with a completely new primitive that - // won't share any vertices with the previous ones - return 0; -} - -uint8_t gl_line_strip() -{ - state->prim_indices[0] = state->prim_indices[1]; - - return 1; -} - -uint8_t gl_triangles() -{ - // Reset the progress to zero since we start with a completely new primitive that - // won't share any vertices with the previous ones - return 0; -} - -uint8_t gl_triangle_strip() -{ - // Which vertices are shared depends on whether the primitive counter is odd or even - state->prim_indices[state->prim_counter] = state->prim_indices[2]; - state->prim_counter ^= 1; - - // The next triangle will share two vertices with the previous one, so reset progress to 2 - return 2; -} - -uint8_t gl_triangle_fan() -{ - state->prim_indices[1] = state->prim_indices[2]; - - // The next triangle will share two vertices with the previous one, so reset progress to 2 - // It will always share the last one and the very first vertex that was specified. - // To make sure the first vertex is not overwritten it was locked earlier (see glBegin) - return 2; -} - -uint8_t gl_quads() -{ - state->prim_indices[1] = state->prim_indices[2]; - - state->prim_counter ^= 1; - return state->prim_counter << 1; -} - -bool gl_prim_assembly(uint8_t cache_index, uint8_t *indices) -{ - if (state->lock_next_vertex) { - state->lock_next_vertex = false; - state->locked_vertex = cache_index; - } - - state->prim_indices[state->prim_progress] = cache_index; - state->prim_progress++; - - if (state->prim_progress < state->prim_size) { - return false; - } - - memcpy(indices, state->prim_indices, state->prim_size * sizeof(uint8_t)); - - assert(state->prim_func != NULL); - state->prim_progress = state->prim_func(); - return true; -} - void glDrawArrays(GLenum mode, GLint first, GLsizei count) { if (!gl_ensure_no_begin_end()) return; - - switch (mode) { - case GL_POINTS: - case GL_LINES: - case GL_LINE_LOOP: - case GL_LINE_STRIP: - case GL_TRIANGLES: - case GL_TRIANGLE_STRIP: - case GL_TRIANGLE_FAN: - case GL_QUADS: - case GL_QUAD_STRIP: - case GL_POLYGON: - break; - default: - gl_set_error(GL_INVALID_ENUM, "%#04lx is not a valid primitive mode", mode); - return; - } + if (!validate_mode(mode)) return; if (count == 0) { return; } - gl_begin(mode); - state->current_pipeline->draw_arrays(first, count); - gl_end(); -} - -uint32_t read_index_8(const uint8_t *src, uint32_t i) -{ - return src[i]; -} - -uint32_t read_index_16(const uint16_t *src, uint32_t i) -{ - return src[i]; -} + array_object_validate_drawing(state->array_object, false); -uint32_t read_index_32(const uint32_t *src, uint32_t i) -{ - return src[i]; + prepare_drawing(mode); + state->current_pipeline->draw_arrays(mode, first, count); } void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) { if (!gl_ensure_no_begin_end()) return; - - switch (mode) { - case GL_POINTS: - case GL_LINES: - case GL_LINE_LOOP: - case GL_LINE_STRIP: - case GL_TRIANGLES: - case GL_TRIANGLE_STRIP: - case GL_TRIANGLE_FAN: - case GL_QUADS: - case GL_QUAD_STRIP: - case GL_POLYGON: - break; - default: - gl_set_error(GL_INVALID_ENUM, "%#04lx is not a valid primitive mode", mode); - return; - } - - read_index_func read_index; - - switch (type) { - case GL_UNSIGNED_BYTE: - read_index = (read_index_func)read_index_8; - break; - case GL_UNSIGNED_SHORT: - read_index = (read_index_func)read_index_16; - break; - case GL_UNSIGNED_INT: - read_index = (read_index_func)read_index_32; - break; - default: - gl_set_error(GL_INVALID_ENUM, "%#04lx is not a valid index type", type); - return; - } + if (!validate_mode(mode)) return; if (count == 0) { return; } - if (state->element_array_buffer != NULL) { - indices = state->element_array_buffer->storage.data + (uint32_t)indices; - } + array_object_validate_drawing(state->array_object, true); - gl_begin(mode); - state->current_pipeline->draw_elements(count, indices, read_index); - gl_end(); + prepare_drawing(mode); + state->current_pipeline->draw_elements(mode, count, indices, type); } void glArrayElement(GLint i) { // Calling glArrayElement while the vertex array is enabled has, among other things, // the same effect as glVertex. See __gl_vertex for that function's behavior. - assertf(!state->array_object->arrays[ATTRIB_VERTEX].enabled || state->begin_end_active, + assertf(!state->array_object->arrays[ARRAY_VERTEX].enabled || state->begin_end_active, "glArrayElement was called outside of glBegin/glEnd while vertex array was enabled"); if (i < 0) { @@ -530,6 +286,8 @@ void glArrayElement(GLint i) return; } + array_object_validate_drawing(state->array_object, false); + state->current_pipeline->array_element(i); } @@ -541,33 +299,33 @@ void __gl_vertex(GLenum type, const void *value, uint32_t size) state->current_pipeline->vertex(value, type, size); } -void __gl_color(GLenum type, const void *value, uint32_t size) +static void read_attrib(array_type_t array_type, const void *value, GLenum type, uint32_t size) { - if (state->begin_end_active) { - state->current_pipeline->color(value, type, size); - } else { - gl_read_attrib(ATTRIB_COLOR, value, type, size); - gl_set_current_color(state->current_attributes.color); + gl_read_attrib(array_type, value, type, size); + rsp_read_attrib(array_type, type, value, size); +} + +void __gl_normal(GLenum type, const void *value, uint32_t size) +{ + read_attrib(ARRAY_NORMAL, value, type, size); + if (!state->begin_end_active) { + gl_set_current_normal(state->current_attributes.normal); } } -void __gl_tex_coord(GLenum type, const void *value, uint32_t size) +void __gl_color(GLenum type, const void *value, uint32_t size) { - if (state->begin_end_active) { - state->current_pipeline->tex_coord(value, type, size); - } else { - gl_read_attrib(ATTRIB_TEXCOORD, value, type, size); - gl_set_current_texcoords(state->current_attributes.texcoord); + read_attrib(ARRAY_COLOR, value, type, size); + if (!state->begin_end_active) { + gl_set_current_color(state->current_attributes.color); } } -void __gl_normal(GLenum type, const void *value, uint32_t size) +void __gl_tex_coord(GLenum type, const void *value, uint32_t size) { - if (state->begin_end_active) { - state->current_pipeline->normal(value, type, size); - } else { - gl_read_attrib(ATTRIB_NORMAL, value, type, size); - gl_set_current_normal(state->current_attributes.normal); + read_attrib(ARRAY_TEXCOORD, value, type, size); + if (!state->begin_end_active) { + gl_set_current_texcoords(state->current_attributes.texcoord); } } @@ -578,12 +336,11 @@ void __gl_mtx_index(GLenum type, const void *value, uint32_t size) return; } - if (state->begin_end_active) { - state->current_pipeline->mtx_index(value, type, size); - } else { - gl_read_attrib(ATTRIB_MTX_INDEX, value, type, size); + read_attrib(ARRAY_MTX_INDEX, value, type, size); + if (!state->begin_end_active) { gl_set_current_mtx_index(state->current_attributes.mtx_index); } + state->current_pipeline->mtx_index(state->current_attributes.mtx_index); } #define __ATTR_IMPL(func, argtype, enumtype, ...) ({\ @@ -761,9 +518,9 @@ void glRectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) { __RECT_IMP void glRectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2) { __RECT_IMPL(glVertex2d, x1, y1, x2, y2); } void glRectsv(const GLshort *v1, const GLshort *v2) { __RECT_IMPL(glVertex2s, v1[0], v1[1], v2[0], v2[1]); } -void glRectiv(const GLint *v1, const GLint *v2) { __RECT_IMPL(glVertex2s, v1[0], v1[1], v2[0], v2[1]); } -void glRectfv(const GLfloat *v1, const GLfloat *v2) { __RECT_IMPL(glVertex2s, v1[0], v1[1], v2[0], v2[1]); } -void glRectdv(const GLdouble *v1, const GLdouble *v2) { __RECT_IMPL(glVertex2s, v1[0], v1[1], v2[0], v2[1]); } +void glRectiv(const GLint *v1, const GLint *v2) { __RECT_IMPL(glVertex2i, v1[0], v1[1], v2[0], v2[1]); } +void glRectfv(const GLfloat *v1, const GLfloat *v2) { __RECT_IMPL(glVertex2f, v1[0], v1[1], v2[0], v2[1]); } +void glRectdv(const GLdouble *v1, const GLdouble *v2) { __RECT_IMPL(glVertex2d, v1[0], v1[1], v2[0], v2[1]); } void glPointSize(GLfloat size) { @@ -825,6 +582,9 @@ void glPolygonMode(GLenum face, GLenum mode) void glDepthRange(GLclampd n, GLclampd f) { if (!gl_ensure_no_begin_end()) return; + + state->current_viewport.n = n; + state->current_viewport.f = f; state->current_viewport.scale[2] = (f - n) * 0.5f; state->current_viewport.offset[2] = n + (f - n) * 0.5f; @@ -840,6 +600,11 @@ void glDepthRange(GLclampd n, GLclampd f) void glViewport(GLint x, GLint y, GLsizei w, GLsizei h) { if (!gl_ensure_no_begin_end()) return; + + state->current_viewport.x = x; + state->current_viewport.y = y; + state->current_viewport.w = w; + state->current_viewport.h = h; uint32_t fbh = state->color_buffer->height; diff --git a/src/GL/query.c b/src/GL/query.c index e1d6be2763..8ba462abbd 100644 --- a/src/GL/query.c +++ b/src/GL/query.c @@ -149,82 +149,82 @@ static bool gl_query_get_value_source(GLenum value, const void **src, uint32_t * SET_RESULT(&state->texcoord_halfx_precision.precision, 1, &from_u32); break; case GL_VERTEX_ARRAY: - SET_RESULT(&state->array_object->arrays[ATTRIB_VERTEX].enabled, 1, &from_bool); + SET_RESULT(&state->array_object->arrays[ARRAY_VERTEX].enabled, 1, &from_bool); break; case GL_VERTEX_ARRAY_SIZE: - SET_RESULT(&state->array_object->arrays[ATTRIB_VERTEX].size, 1, &from_i32); + SET_RESULT(&state->array_object->arrays[ARRAY_VERTEX].size, 1, &from_i32); break; case GL_VERTEX_ARRAY_STRIDE: - SET_RESULT(&state->array_object->arrays[ATTRIB_VERTEX].stride, 1, &from_u32); + SET_RESULT(&state->array_object->arrays[ARRAY_VERTEX].stride, 1, &from_u32); break; case GL_VERTEX_ARRAY_TYPE: - SET_RESULT(&state->array_object->arrays[ATTRIB_VERTEX].type, 1, &from_u32); + SET_RESULT(&state->array_object->arrays[ARRAY_VERTEX].type, 1, &from_u32); break; case GL_VERTEX_ARRAY_BUFFER_BINDING_ARB: - SET_RESULT(&state->array_object->arrays[ATTRIB_VERTEX].binding, 1, &from_u32); + SET_RESULT(&state->array_object->arrays[ARRAY_VERTEX].binding, 1, &from_u32); break; case GL_NORMAL_ARRAY: - SET_RESULT(&state->array_object->arrays[ATTRIB_NORMAL].enabled, 1, &from_bool); + SET_RESULT(&state->array_object->arrays[ARRAY_NORMAL].enabled, 1, &from_bool); break; case GL_NORMAL_ARRAY_STRIDE: - SET_RESULT(&state->array_object->arrays[ATTRIB_NORMAL].stride, 1, &from_u32); + SET_RESULT(&state->array_object->arrays[ARRAY_NORMAL].stride, 1, &from_u32); break; case GL_NORMAL_ARRAY_TYPE: - SET_RESULT(&state->array_object->arrays[ATTRIB_NORMAL].type, 1, &from_u32); + SET_RESULT(&state->array_object->arrays[ARRAY_NORMAL].type, 1, &from_u32); break; case GL_NORMAL_ARRAY_BUFFER_BINDING_ARB: - SET_RESULT(&state->array_object->arrays[ATTRIB_NORMAL].binding, 1, &from_u32); + SET_RESULT(&state->array_object->arrays[ARRAY_NORMAL].binding, 1, &from_u32); break; case GL_COLOR_ARRAY: - SET_RESULT(&state->array_object->arrays[ATTRIB_COLOR].enabled, 1, &from_bool); + SET_RESULT(&state->array_object->arrays[ARRAY_COLOR].enabled, 1, &from_bool); break; case GL_COLOR_ARRAY_SIZE: - SET_RESULT(&state->array_object->arrays[ATTRIB_COLOR].size, 1, &from_i32); + SET_RESULT(&state->array_object->arrays[ARRAY_COLOR].size, 1, &from_i32); break; case GL_COLOR_ARRAY_STRIDE: - SET_RESULT(&state->array_object->arrays[ATTRIB_COLOR].stride, 1, &from_u32); + SET_RESULT(&state->array_object->arrays[ARRAY_COLOR].stride, 1, &from_u32); break; case GL_COLOR_ARRAY_TYPE: - SET_RESULT(&state->array_object->arrays[ATTRIB_COLOR].type, 1, &from_u32); + SET_RESULT(&state->array_object->arrays[ARRAY_COLOR].type, 1, &from_u32); break; case GL_COLOR_ARRAY_BUFFER_BINDING_ARB: - SET_RESULT(&state->array_object->arrays[ATTRIB_COLOR].binding, 1, &from_u32); + SET_RESULT(&state->array_object->arrays[ARRAY_COLOR].binding, 1, &from_u32); break; case GL_TEXTURE_COORD_ARRAY: - SET_RESULT(&state->array_object->arrays[ATTRIB_TEXCOORD].enabled, 1, &from_bool); + SET_RESULT(&state->array_object->arrays[ARRAY_TEXCOORD].enabled, 1, &from_bool); break; case GL_TEXTURE_COORD_ARRAY_SIZE: - SET_RESULT(&state->array_object->arrays[ATTRIB_TEXCOORD].size, 1, &from_i32); + SET_RESULT(&state->array_object->arrays[ARRAY_TEXCOORD].size, 1, &from_i32); break; case GL_TEXTURE_COORD_ARRAY_STRIDE: - SET_RESULT(&state->array_object->arrays[ATTRIB_TEXCOORD].stride, 1, &from_u32); + SET_RESULT(&state->array_object->arrays[ARRAY_TEXCOORD].stride, 1, &from_u32); break; case GL_TEXTURE_COORD_ARRAY_TYPE: - SET_RESULT(&state->array_object->arrays[ATTRIB_TEXCOORD].type, 1, &from_u32); + SET_RESULT(&state->array_object->arrays[ARRAY_TEXCOORD].type, 1, &from_u32); break; case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB: - SET_RESULT(&state->array_object->arrays[ATTRIB_TEXCOORD].binding, 1, &from_u32); + SET_RESULT(&state->array_object->arrays[ARRAY_TEXCOORD].binding, 1, &from_u32); break; case GL_MATRIX_INDEX_ARRAY_ARB: - SET_RESULT(&state->array_object->arrays[ATTRIB_MTX_INDEX].enabled, 1, &from_bool); + SET_RESULT(&state->array_object->arrays[ARRAY_MTX_INDEX].enabled, 1, &from_bool); break; case GL_MATRIX_INDEX_ARRAY_SIZE_ARB: - SET_RESULT(&state->array_object->arrays[ATTRIB_MTX_INDEX].size, 1, &from_i32); + SET_RESULT(&state->array_object->arrays[ARRAY_MTX_INDEX].size, 1, &from_i32); break; case GL_MATRIX_INDEX_ARRAY_STRIDE_ARB: - SET_RESULT(&state->array_object->arrays[ATTRIB_MTX_INDEX].stride, 1, &from_u32); + SET_RESULT(&state->array_object->arrays[ARRAY_MTX_INDEX].stride, 1, &from_u32); break; case GL_MATRIX_INDEX_ARRAY_TYPE_ARB: - SET_RESULT(&state->array_object->arrays[ATTRIB_MTX_INDEX].type, 1, &from_u32); + SET_RESULT(&state->array_object->arrays[ARRAY_MTX_INDEX].type, 1, &from_u32); break; case GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_ARB: - SET_RESULT(&state->array_object->arrays[ATTRIB_MTX_INDEX].binding, 1, &from_u32); + SET_RESULT(&state->array_object->arrays[ARRAY_MTX_INDEX].binding, 1, &from_u32); break; case GL_ARRAY_BUFFER_BINDING_ARB: SET_RESULT(&state->array_buffer, 1, &from_u32); break; case GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB: - SET_RESULT(&state->element_array_buffer, 1, &from_u32); + SET_RESULT(&state->array_object->element_array_buffer, 1, &from_u32); break; case GL_VERTEX_ARRAY_BINDING: SET_RESULT(&state->array_object, 1, &from_u32); @@ -511,15 +511,15 @@ GLboolean glIsEnabled(GLenum value) { switch (value) { case GL_VERTEX_ARRAY: - return state->array_object->arrays[ATTRIB_VERTEX].enabled; + return state->array_object->arrays[ARRAY_VERTEX].enabled; case GL_NORMAL_ARRAY: - return state->array_object->arrays[ATTRIB_NORMAL].enabled; + return state->array_object->arrays[ARRAY_NORMAL].enabled; case GL_COLOR_ARRAY: - return state->array_object->arrays[ATTRIB_COLOR].enabled; + return state->array_object->arrays[ARRAY_COLOR].enabled; case GL_TEXTURE_COORD_ARRAY: - return state->array_object->arrays[ATTRIB_TEXCOORD].enabled; + return state->array_object->arrays[ARRAY_TEXCOORD].enabled; case GL_MATRIX_INDEX_ARRAY_ARB: - return state->array_object->arrays[ATTRIB_MTX_INDEX].enabled; + return state->array_object->arrays[ARRAY_MTX_INDEX].enabled; case GL_ALPHA_TEST: case GL_AUTO_NORMAL: case GL_BLEND: @@ -590,19 +590,19 @@ void glGetPointerv(GLenum pname, GLvoid **params) { switch (pname) { case GL_VERTEX_ARRAY_POINTER: - *params = (GLvoid*)state->array_object->arrays[ATTRIB_VERTEX].pointer; + *params = (GLvoid*)state->array_object->arrays[ARRAY_VERTEX].pointer; break; case GL_NORMAL_ARRAY_POINTER: - *params = (GLvoid*)state->array_object->arrays[ATTRIB_NORMAL].pointer; + *params = (GLvoid*)state->array_object->arrays[ARRAY_NORMAL].pointer; break; case GL_COLOR_ARRAY_POINTER: - *params = (GLvoid*)state->array_object->arrays[ATTRIB_COLOR].pointer; + *params = (GLvoid*)state->array_object->arrays[ARRAY_COLOR].pointer; break; case GL_TEXTURE_COORD_ARRAY_POINTER: - *params = (GLvoid*)state->array_object->arrays[ATTRIB_TEXCOORD].pointer; + *params = (GLvoid*)state->array_object->arrays[ARRAY_TEXCOORD].pointer; break; case GL_MATRIX_INDEX_ARRAY_POINTER_ARB: - *params = (GLvoid*)state->array_object->arrays[ATTRIB_MTX_INDEX].pointer; + *params = (GLvoid*)state->array_object->arrays[ARRAY_MTX_INDEX].pointer; break; case GL_EDGE_FLAG_ARRAY_POINTER: case GL_INDEX_ARRAY_POINTER: diff --git a/src/GL/rendermode.c b/src/GL/rendermode.c index 98bfbc3d63..00ced55896 100644 --- a/src/GL/rendermode.c +++ b/src/GL/rendermode.c @@ -96,29 +96,28 @@ void gl_update_fog() // start == end is undefined, so disable fog by setting the factor to 0 state->fog_factor = fabsf(fog_diff) < FLT_MIN ? 0.0f : 1.0f / fog_diff; state->fog_offset = state->fog_start; - - // Convert to s15.16 and premultiply with 1.15 conversion factor - int32_t factor_fx = state->fog_factor * (1<<(16 + 7 + (8 - VTX_SHIFT))); - int16_t offset_fx = state->fog_offset * (1<> 16; - uint16_t factor_f = factor_fx & 0xFFFF; - - uint64_t packed = (((uint64_t)factor_i) << 48) | (((uint64_t)offset_fx) << 32) | (((uint64_t)factor_f) << 16); - - gl_set_long(GL_UPDATE_NONE, offsetof(gl_server_state_t, fog_params), packed); } void gl_set_fog_start(GLfloat param) { state->fog_start = param; gl_update_fog(); + int32_t start_fx = param * (1<<16); + int16_t start_int = start_fx >> 16; + uint16_t start_frac = start_fx & 0xFFFF; + gl_set_short(GL_UPDATE_NONE, offsetof(gl_server_state_t, fog_params) + offsetof(gl_fog_params_t, start_int), start_int); + gl_set_short(GL_UPDATE_NONE, offsetof(gl_server_state_t, fog_params) + offsetof(gl_fog_params_t, start_frac), start_frac); } void gl_set_fog_end(GLfloat param) { state->fog_end = param; gl_update_fog(); + int32_t end_fx = param * (1<<16); + int16_t end_int = end_fx >> 16; + uint16_t end_frac = end_fx & 0xFFFF; + gl_set_short(GL_UPDATE_NONE, offsetof(gl_server_state_t, fog_params) + offsetof(gl_fog_params_t, end_int), end_int); + gl_set_short(GL_UPDATE_NONE, offsetof(gl_server_state_t, fog_params) + offsetof(gl_fog_params_t, end_frac), end_frac); } void glFogi(GLenum pname, GLint param) diff --git a/src/GL/ringbuffer.c b/src/GL/ringbuffer.c new file mode 100644 index 0000000000..aea520fca6 --- /dev/null +++ b/src/GL/ringbuffer.c @@ -0,0 +1,35 @@ +#include "ringbuffer.h" + +void ringbuffer_init(ringbuffer *buf, uint32_t entry_size, uint32_t entry_count) +{ + buf->entry_size = entry_size; + buf->entry_count = entry_count; + buf->current_index = 0; + buf->buffer = malloc_uncached(entry_size * entry_count); + buf->syncpoints = calloc(entry_count, sizeof(rspq_syncpoint_t)); +} + +void ringbuffer_free(ringbuffer *buf) +{ + free(buf->syncpoints); + free_uncached(buf->buffer); +} + +void *ringbuffer_alloc_next(ringbuffer *buf) +{ + uint32_t next_index = (buf->current_index + 1) % buf->entry_count; + rspq_syncpoint_wait(buf->syncpoints[next_index]); + + buf->current_index = next_index; + return ringbuffer_get_current(buf); +} + +void ringbuffer_release_current(ringbuffer *buf) +{ + buf->syncpoints[buf->current_index] = rspq_syncpoint_new(); +} + +void *ringbuffer_get_current(ringbuffer *buf) +{ + return buf->buffer + (buf->entry_size * buf->current_index); +} diff --git a/src/GL/ringbuffer.h b/src/GL/ringbuffer.h new file mode 100644 index 0000000000..856fe45f54 --- /dev/null +++ b/src/GL/ringbuffer.h @@ -0,0 +1,34 @@ +/** + * @file ringbuffer.h + * @author Dennis Heinze + */ +#ifndef __GL_RINGBUFFER +#define __GL_RINGBUFFER + +#include +#include + +typedef struct { + uint8_t *buffer; + rspq_syncpoint_t *syncpoints; + uint32_t entry_size; + uint32_t entry_count; + uint32_t current_index; +} ringbuffer; + + +#ifdef __cplusplus +extern "C" { +#endif + +void ringbuffer_init(ringbuffer *buf, uint32_t entry_size, uint32_t entry_count); +void ringbuffer_free(ringbuffer *buf); +void *ringbuffer_alloc_next(ringbuffer *buf); +void ringbuffer_release_current(ringbuffer *buf); +void *ringbuffer_get_current(ringbuffer *buf); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/GL/rsp_gl.S b/src/GL/rsp_gl.S index f8ac61506a..2abe19f8b3 100644 --- a/src/GL/rsp_gl.S +++ b/src/GL/rsp_gl.S @@ -1,7 +1,8 @@ ############################################################ # rsp_gl.S # -# Authors: Dennis Heinze +# Authors: Giovanni Bajo +# Dennis Heinze ############################################################ #include #include @@ -24,76 +25,20 @@ RSPQ_DefineCommand GLCmd_MatrixPush, 4 # 0xA RSPQ_DefineCommand GLCmd_MatrixPop, 4 # 0xB RSPQ_DefineCommand GLCmd_MatrixLoad, 68 # 0xC - RSPQ_DefineCommand GLCmd_PreInitPipe, 4 # 0xD - RSPQ_DefineCommand GLCmd_PreInitPipeTex,4 # 0xE - RSPQ_DefineCommand GLCmd_SetPaletteIdx, 4 # 0xF - RSPQ_DefineCommand GLCmd_MatrixCopy, 4 # 0x10 + RSPQ_DefineCommand GLCmd_SetPaletteIdx, 4 # 0xD + RSPQ_DefineCommand GLCmd_MatrixCopy, 4 # 0xE RSPQ_EndOverlayHeader RSPQ_BeginSavedState #include "rsp_gl_state.inc" - - # These are only required for RDP state changes - GL_BOUND_TEXTURES: - GL_BOUND_TEXTURE_1D: .ds.b TEXTURE_OBJECT_SIZE - GL_BOUND_TEXTURE_2D: .ds.b TEXTURE_OBJECT_SIZE - GL_STATE_SCISSOR_RECT: .half 0, 0, 0, 0 - GL_STATE_BLEND_CYCLE: .word 0 - GL_STATE_FOG_COLOR: .word 0 - GL_STATE_FLAGS2: .word 0 - GL_STATE_TEXTURE_IDS: .word 0, 0 - GL_STATE_UPLOADED_TEX: .word 0 - GL_STATE_FILL_COLOR: .word 0 - GL_STATE_FILL_DEPTH: .word 0 - GL_STATE_PALETTE_INDEX: .word 0 - GL_STATE_DITHER_MODE: .word 0 - GL_STATE_FB_SIZE: .half 0, 0 - GL_STATE_DEPTH_FUNC: .half 0 - GL_STATE_ALPHA_FUNC: .half 0 - GL_STATE_BLEND_SRC: .half 0 - GL_STATE_BLEND_DST: .half 0 - GL_STATE_TEX_ENV_MODE: .half 0 - GL_STATE_ALPHA_REF: .byte 0 - GL_STATE_PALETTE_DIRTY: .ds.b PALETTE_DIRTY_FLAGS_SIZE RSPQ_EndSavedState -COMBINER_TABLE: - # No texture - .quad RDPQ_COMBINER1((0, 0, 0, SHADE), (0, 0, 0, SHADE)) # "modulate" - .quad RDPQ_COMBINER1((0, 0, 0, PRIM), (0, 0, 0, PRIM)) # constant "modulate" - .quad RDPQ_COMBINER1((0, 0, 0, SHADE), (0, 0, 0, SHADE)) # "replace" - .quad RDPQ_COMBINER1((0, 0, 0, PRIM), (0, 0, 0, PRIM)) # constant "replace" - - # Texture enabled - .quad RDPQ_COMBINER1((TEX0, 0, SHADE, 0), (TEX0, 0, SHADE, 0)) # modulate - .quad RDPQ_COMBINER1((TEX0, 0, PRIM, 0), (TEX0, 0, PRIM, 0)) # constant modulate - .quad RDPQ_COMBINER1((0, 0, 0, TEX0), (0, 0, 0, TEX0)) # replace - .quad RDPQ_COMBINER1((0, 0, 0, TEX0), (0, 0, 0, TEX0)) # constant replace - -COMBINER_MIPMAPMASK_TABLE: - .quad RDPQ_COMB1_MASK - .quad RDPQ_COMB1_MASK - .quad RDPQ_COMB1_MASK - .quad RDPQ_COMB1_MASK - - .quad RDPQ_COMB1_MASK ^ (1<<37) ^ (1<<21) - .quad RDPQ_COMB1_MASK ^ (1<<37) ^ (1<<21) - .quad RDPQ_COMB1_MASK ^ (1<<6) ^ (1<<0) - .quad RDPQ_COMB1_MASK ^ (1<<6) ^ (1<<0) - UPDATE_FUNCTIONS: .short RSPQ_Loop - _start # Do nothing .short GL_UpdateScissor - _start .short GL_UpdateTextureCompleteness - _start .short GL_UpdateTextureObjects - _start -CONVERT_CONST: .half 1, 2, 0x8000, 0x200, 0xFF, 134, 0x7F, 0x80 - - .bss - - .align 3 -TEX_UPLOAD_STAGING: .ds.b 0x150 - .text ############################################################# @@ -230,7 +175,7 @@ GLCmd_SetLightPos: vmadn v___, vmtx3_f, vpos.e3 vmadh vpos, vmtx3_i, vpos.e3 - addi s0, a0, %lo(GL_STATE) + LIGHT_POSITION_OFFSET + addi s0, a0, %lo(GL_STATE) + GLP_LIGHT_POSITION jr ra sdv vpos, 0x00,s0 @@ -543,636 +488,6 @@ GLCmd_SetPaletteIdx: jal_and_j DMAIn, RSPQ_Loop .endfunc - .func GLCmd_PreInitPipe -GLCmd_PreInitPipe: - sh a0, %lo(GL_STATE_PRIM_TYPE) - - #define state_flags k1 - #define state_flags2 k0 - - lw state_flags, %lo(GL_STATE_FLAGS) - lw state_flags2, %lo(GL_STATE_FLAGS2) - - # Update matrix if required - - andi t0, state_flags, FLAG_MATRIX_PALETTE - beqz t0, 1f - li v1, 1 - - #define mtx_dirty t1 - #define mtx_offset t3 - #define palette_size t4 - #define palette_index t5 - #define dirty_flags t6 - #define cur_flag t7 - #define palette_dram s1 - #define mvp_dram s2 - #define flag_offset s3 - #define mtx_lhs s5 - #define mtx_rhs s6 - #define mtx_dst s7 - - lw palette_dram, %lo(GL_PALETTE_PTR) - lw palette_index, %lo(GL_STATE_PALETTE_INDEX) - - # Write back current palette matrix to the palette storage - li s4, %lo(GL_MATRIX_PALETTE) - li t0, DMA_SIZE(MATRIX_SIZE, 1) - jal DMAOutAsync - add s0, palette_dram, palette_index - - lw mvp_dram, %lo(GL_MVP_PTR) - li mtx_lhs, %lo(GL_MATRIX_PROJECTION) - li mtx_rhs, %lo(GL_MATRIX_PALETTE) - li mtx_dst, %lo(GL_MATRIX_MVP) - li palette_index, 0 - li palette_size, MATRIX_PALETTE_SIZE - - # TODO: Load projection matrix into vector regs only once -gl_matrix_palette_loop: - beq palette_index, palette_size, 2f - srl flag_offset, palette_index, 3 - - lbu dirty_flags, %lo(GL_STATE_PALETTE_DIRTY)(flag_offset) - and cur_flag, palette_index, 0x7 - sllv cur_flag, v1, cur_flag - and mtx_dirty, dirty_flags, cur_flag - sll mtx_offset, palette_index, 6 - beqz mtx_dirty, gl_matrix_palette_loop - addi palette_index, 1 - - xor dirty_flags, mtx_dirty - sb dirty_flags, %lo(GL_STATE_PALETTE_DIRTY)(flag_offset) - - move s4, mtx_rhs - jal DMAIn - add s0, palette_dram, mtx_offset - - jal GL_MtxMult - move s4, mtx_dst - - add s0, mvp_dram, mtx_offset - jal_and_j DMAOutAsync, gl_matrix_palette_loop - -1: - and mtx_dirty, state_flags, FLAG_FINAL_MTX_DIRTY - beqz mtx_dirty, 2f - li mtx_lhs, %lo(GL_MATRIX_PROJECTION) - li mtx_rhs, %lo(GL_MATRIX_MODELVIEW) - jal GL_MtxMult - li mtx_dst, %lo(GL_MATRIX_MVP) - and state_flags, ~FLAG_FINAL_MTX_DIRTY - - #undef mtx_dirty - #undef mtx_offset - #undef palette_size - #undef palette_index - #undef dirty_flags - #undef cur_flag - #undef palette_dram - #undef mvp_dram - #undef flag_offset - #undef mtx_lhs - #undef mtx_rhs - #undef mtx_dst - -2: - - # Determine Culling mode - - #define cull_mode t1 - #define front_face t2 - #define cull_enabled t3 - #define tri_cull t4 - - andi cull_enabled, state_flags, FLAG_CULL_FACE - beqz cull_enabled, 1f - # Any non-negative value other than 0 or 1 signifies that no faces should be culled - li tri_cull, 2 - - lhu cull_mode, %lo(GL_STATE_CULL_MODE) - lhu front_face, %lo(GL_STATE_FRONT_FACE) - - # Set TRI_CULL to a negative number to cull all faces - beq cull_mode, GL_FRONT_AND_BACK, 1f - li tri_cull, -1 - - # tri_cull = (cull_mode == GL_BACK) ^ (front_face == GL_CW) - xori cull_mode, GL_FRONT - sltu tri_cull, zero, cull_mode - xori front_face, GL_CCW - sltu front_face, zero, front_face - xor tri_cull, front_face - -1: - sb tri_cull, %lo(GL_TRI_CULL) - - #undef cull_mode - #undef front_face - #undef cull_enabled - #undef tri_cull - - #define modes0 t8 - #define modes1 t9 - #define is_points v0 - #define active_tex s7 - - # Get Active texture - - andi t1, state_flags, FLAG_TEXTURE_2D - bnez t1, 1f - li active_tex, %lo(GL_BOUND_TEXTURE_2D) - andi t1, state_flags, FLAG_TEXTURE_1D - bnez t1, 1f - li active_tex, %lo(GL_BOUND_TEXTURE_1D) - move active_tex, zero -1: - #define tri_cmd t4 - srl tri_cmd, state_flags, TRICMD_ATTR_SHIFT - andi tri_cmd, TRICMD_ATTR_MASK - ori tri_cmd, 0xCC00 - sh tri_cmd, %lo(GL_TRI_CMD) - - #undef tri_cmd - - # Check if eye space transformation is needed in T&L - and t1, state_flags, FLAG_LIGHTING | FLAG_FOG | FLAG_TEXTURE_ACTIVE - sltu t1, zero, t1 - sll t1, NEED_EYE_SPACE_SHIFT - and t2, state_flags, ~FLAG_NEED_EYE_SPACE - or state_flags, t2, t1 - - #define vmodes $v01 - #define vsphere $v02 - #define v___ $v29 - - # Check which tex gen modes are active - srl t0, state_flags, TEX_GEN_S_SHIFT - andi t0, 0xF - ctc2 t0, COP2_CTRL_VCC - li s1, %lo(GL_TEX_GEN) - lqv vmodes, TEX_GEN_MODE_OFFSET, s1 - vmrg vmodes, vzero - vand vsphere, vmodes, K2 - veq v___, vsphere, vzero - vmrg vmodes, vzero - vor vsphere, vsphere.q1 - vor vsphere, vsphere.e2 - vor vmodes, vmodes.q1 - vor vmodes, vmodes.e2 - mfc2 t0, vsphere.e0 - mfc2 t1, vmodes.e0 - sltu t0, zero, t0 - sltu t1, zero, t1 - sll t0, TEX_GEN_SPHERICAL_FLAG_SHIFT - sll t1, TEX_GEN_LINEAR_FLAG_SHIFT - or t0, t1 - and t2, state_flags, ~(FLAG_TEX_GEN_LINEAR | FLAG_TEX_GEN_SPHERICAL) - or state_flags, t2, t0 - - #undef vmodes - #undef vsphere - #undef v___ - - # Multisampling - and t0, state_flags2, FLAG2_REDUCED_ALIASING - or modes0, t0, (SOM_TF0_RGB | SOM_TF1_RGB) >> 32 - and modes1, state_flags2, FLAG2_MULTISAMPLE - - # Alpha test - andi t0, state_flags, FLAG_ALPHA_TEST - beqz t0, 1f - lhu t1, %lo(GL_STATE_ALPHA_FUNC) - xori t1, GL_GREATER - sltu t0, t1, 1 - or modes1, t0 -1: - - # Depth mask - and t0, state_flags, FLAG_DEPTH_TEST | FLAG_DEPTH_MASK - xor t0, FLAG_DEPTH_TEST | FLAG_DEPTH_MASK - sltu t0, 1 - sll t0, SOM_Z_WRITE_SHIFT - or modes1, t0 - - #define depth_func t3 - - # Depth test - and t0, state_flags, FLAG_DEPTH_TEST - beqz t0, 1f - lhu depth_func, %lo(GL_STATE_DEPTH_FUNC) - xori t1, depth_func, GL_ALWAYS - sltu t1, zero, t1 - sll t0, t1, SOM_Z_COMPARE_SHIFT - or modes1, t0 -1: - - # Z mode - xori t1, depth_func, GL_EQUAL - beqz t1, 1f - li t0, SOM_ZMODE_DECAL - xori t1, depth_func, GL_LESS_INTERPENETRATING_N64 - beqz t1, 1f - li t0, SOM_ZMODE_INTERPENETRATING - andi t0, state_flags, FLAG_BLEND - # t0 = (state_flags & FLAG_BLEND) ? SOM_ZMODE_TRANSPARENT : SOM_ZMODE_OPAQUE - sll t0, ZMODE_BLEND_FLAG_SHIFT -1: - or modes1, t0 - - #undef depth_func - - # Dither - andi t1, state_flags, FLAG_DITHER - beqz t1, 1f - li t0, (SOM_RGBDITHER_NONE | SOM_ALPHADITHER_NONE) >> 32 - lw t0, %lo(GL_STATE_DITHER_MODE) -1: - or modes0, t0 - - # Points - lhu t0, %lo(GL_STATE_PRIM_TYPE) - beqz t0, 1f # prim_type == GL_POINTS - li is_points, 1 - - addi t0, -1 - sltu t0, (GL_TRIANGLES - 1) - bne t0, zero, 1f # prim_type == GL_LINES || prim_type == GL_LINE_LOOP || prim_type == GL_LINE_STRIP - move is_points, zero - - lhu t0, %lo(GL_STATE_POLYGON_MODE) - xori t0, GL_POINT - sltu is_points, t0, 1 # polygon_mode == GL_POINT - -1: - bnez is_points, 1f - sll t3, is_points, SOM_ZSOURCE_SHIFT - or modes0, SOM_TEXTURE_PERSP >> 32 -1: - or modes1, t3 - - # * Skip construction of CC/CB if FLAG2_USE_RDPQ_MATERIAL is active - andi t1, state_flags2, FLAG2_USE_RDPQ_MATERIAL - bnez t1, gl_skipcombinerblender - - # Blend cycle - andi t0, state_flags, FLAG_BLEND - beqz t0, 1f - move t1, zero - lw t1, %lo(GL_STATE_BLEND_CYCLE) -1: - sw t1, %lo(RDPQ_MODE_BLENDER_STEPS) + 0x4 - - # Fog cycle - andi t0, state_flags, FLAG_FOG - beqz t0, 1f - sltu t2, zero, t0 - li t0, RDPQ_BLENDER((FOG_RGB, SHADE_ALPHA, IN_RGB, INV_MUX_ALPHA)) | SOM_BLENDING -1: - sw t0, %lo(RDPQ_MODE_BLENDER_STEPS) + 0x0 - or modes0, t2 - - # Combiner - move t5, is_points - lw t3, %lo(GL_STATE_TEX_ENV_MODE) - - li t4, GL_REPLACE - bne t3, t4, 1f - nop - ori t5, COMBINER_FLAG_REPLACE -1: - srl t0, state_flags, TEX_ACTIVE_COMBINER_SHIFT - andi t0, COMBINER_FLAG_TEXTURE - or t5, t0 - - sll t5, 3 - lw t0, %lo(COMBINER_TABLE) + 0x0(t5) - lw t1, %lo(COMBINER_TABLE) + 0x4(t5) - lw t2, %lo(COMBINER_MIPMAPMASK_TABLE) + 0x0(t5) - lw t3, %lo(COMBINER_MIPMAPMASK_TABLE) + 0x4(t5) - - # TODO: The following is sort of equivalent to RDPQCmd_ResetMode. Maybe make that callable from ucode? - - sw t0, %lo(RDPQ_COMBINER) + 0x0 - sw t1, %lo(RDPQ_COMBINER) + 0x4 - sw t2, %lo(RDPQ_COMBINER_MIPMAPMASK) + 0x0 - sw t3, %lo(RDPQ_COMBINER_MIPMAPMASK) + 0x4 - -gl_skipcombinerblender: - - # * Skip specific GL texture flags if FLAG2_USE_RDPQ_TEXTURING is active and instead apply RDPQ ones - - andi t1, state_flags2, FLAG2_USE_RDPQ_TEXTURING - bnez t1, gl_mergemask - nop - - # Texture - beqz active_tex, 2f - lw t4, TEXTURE_FLAGS_OFFSET(active_tex) - - andi t5, t4, TEX_FLAG_COMPLETE - beqz t5, 2f - lhu t3, TEXTURE_MIN_FILTER_OFFSET(active_tex) - lhu t2, TEXTURE_MAG_FILTER_OFFSET(active_tex) - - andi t5, t3, TEXTURE_MIPMAP_MASK - or t2, t3 - andi t2, TEXTURE_BILINEAR_MASK - - # If bilinear sampling is active, texture coords need to be offset by half a texel, - # which is 0x10 in s10.5 - andi t7, state_flags2, FLAG2_TEX_FLIP_T - lh t6, %lo(GL_STATE_TEX_SIZE) + 2 - sll t1, t2, TEX_BILINEAR_OFFSET_SHIFT - neg t1, t1 - beqz t7, 1f - sh t1, %lo(GL_STATE_TEX_OFFSET) + 0 - sra t6, 1 - sub t1, t6 -1: - sh t1, %lo(GL_STATE_TEX_OFFSET) + 2 - - beqz t5, 1f - sll t2, TEX_BILINEAR_SHIFT - or t2, SOM_TEXTURE_LOD >> 32 - - andi t5, t4, TEX_FLAG_DETAIL - sll t5, TEX_DETAIL_SHIFT - or t2, t5 - -1: - andi t3, TEXTURE_INTERPOLATE_MASK - beqz t3, 1f - nop # :( - ori t2, SOMX_LOD_INTERPOLATE >> 32 - -1: - # TODO: Combine into a single field? - lbu t0, TEXTURE_LEVELS_COUNT_OFFSET(active_tex) - lbu t1, TEXTURE_TLUT_MODE_OFFSET(active_tex) - - sll t0, SOMX_NUMLODS_SHIFT - 32 - sll t1, SOM_TLUT_SHIFT - 32 - - or t0, t1 - or t7, t0, t2 - or modes0, t7 -2: - - j 1f - nop # :( -gl_mergemask: - # If we have FLAG2_USE_RDPQ_TEXTURING active, we need to use some of the RDPQ params instead of GL's - - lw t1, %lo(RDPQ_OTHER_MODES) + 0x0 - and t1, RDPQ_TEXTURING_MASK - and t2, modes0, ~(RDPQ_TEXTURING_MASK) - or modes0, t1, t2 - - -1: - - lw t0, %lo(RDPQ_OTHER_MODES) + 0x0 - - sw modes0, %lo(RDPQ_OTHER_MODES) + 0x0 - sw modes1, %lo(RDPQ_OTHER_MODES) + 0x4 - - # If cycle mode was copy or fill, update scissor rect - sll t0, ((64-2)-SOM_CYCLE_SHIFT) - bgez t0, 1f - lw a0, %lo(RDPQ_SCISSOR_RECT) + 0x0 - jal RDPQ_WriteSetScissor - lw a1, %lo(RDPQ_SCISSOR_RECT) + 0x4 - -1: - - j RDPQ_UpdateRenderMode - sw state_flags, %lo(GL_STATE_FLAGS) - - #undef modes0 - #undef modes1 - #undef is_points - #undef active_tex - #undef state_flags - .endfunc - - .func GLCmd_PreInitPipeTex -GLCmd_PreInitPipeTex: - #define tex_id s0 - #define uploaded_tex s1 - #define active_tex s7 - #define active_tex_id s6 - #define tex_flags t7 - #define state_flags k1 - #define state_flags2 k0 - - # Skip processing textutre state if we are using rdpq API for texturing - # (FLAG2_USE_RDPQ_TEXTURING) - lw state_flags2, %lo(GL_STATE_FLAGS2) - andi t1, state_flags2, FLAG2_USE_RDPQ_TEXTURING - beqz t1, 2f - lw state_flags, %lo(GL_STATE_FLAGS) - - or state_flags, FLAG_TEXTURE_ACTIVE - sw state_flags, %lo(GL_STATE_FLAGS) - - # If bilinear sampling is active, texture coords need to be offset by half a texel, - # which is 0x10 in s10.5 - lw t2, %lo(RDPQ_OTHER_MODES) + 0x4 - and t2, (SOM_SAMPLE_BILINEAR >> 32) - sll t2, t2, (SOM_SAMPLE_SHIFT - 32 + 1) - - andi t3, state_flags2, FLAG2_TEX_FLIP_T - lh t6, %lo(GL_STATE_TEX_SIZE) + 2 - sll t1, t2, TEX_BILINEAR_OFFSET_SHIFT - neg t1, t1 - beqz t7, 1f - sh t1, %lo(GL_STATE_TEX_OFFSET) + 0 - sra t6, 1 - sub t1, t6 - -1: - sh t1, %lo(GL_STATE_TEX_OFFSET) + 2 - j RSPQ_Loop - -2: - # Get pointer to active texture state in DMEM - li active_tex_id, %lo(GL_STATE_TEXTURE_IDS) + 0x4 - andi t1, state_flags, FLAG_TEXTURE_2D - bnez t1, 1f - li active_tex, %lo(GL_BOUND_TEXTURE_2D) - andi t1, state_flags, FLAG_TEXTURE_1D - li active_tex_id, %lo(GL_STATE_TEXTURE_IDS) + 0x0 - bnez t1, 1f - li active_tex, %lo(GL_BOUND_TEXTURE_1D) - j gl_set_texture_not_active -1: - lw uploaded_tex, %lo(GL_STATE_UPLOADED_TEX) - - # CHeck if the texture is complete (that is, all mipmaps have been loaded) - # otherwise, we consider it not complete and avoid displaying it - lw tex_flags, TEXTURE_FLAGS_OFFSET(active_tex) - andi t0, tex_flags, TEX_FLAG_COMPLETE - beqz t0, gl_set_texture_not_active - - # Copy width/height of the active texture into the state - lh t0, IMAGE_WIDTH_OFFSET(active_tex) - lh t1, IMAGE_HEIGHT_OFFSET(active_tex) - sll t0, TEX_COORD_SHIFT - sll t1, TEX_COORD_SHIFT - andi t2, state_flags2, FLAG2_TEX_FLIP_T - beqz t2, 1f - sh t0, %lo(GL_STATE_TEX_SIZE) + 0 - neg t1, t1 -1: - sh t1, %lo(GL_STATE_TEX_SIZE) + 2 - - # Make sure FLAG_TEXTURE_ACTIVE is set - or state_flags, FLAG_TEXTURE_ACTIVE - sw state_flags, %lo(GL_STATE_FLAGS) - - # Load ID of active texture (that is, RDRAM pointer) - lw tex_id, (active_tex_id) - - # Proceed with the upload if: - # * the requested texture ID is different from the one currently uploaded to TMEM - # * the dirty flag is set - bne tex_id, uploaded_tex, 1f - andi t0, tex_flags, TEX_FLAG_UPLOAD_DIRTY - beqz t0, RSPQ_Loop -# nop - -1: - # OK we are going to do the upload. Update the state: clear dirty flag and - # set the current texture ID. - li t0, ~TEX_FLAG_UPLOAD_DIRTY - and tex_flags, t0 - sw tex_flags, TEXTURE_FLAGS_OFFSET(active_tex) - sw tex_id, %lo(GL_STATE_UPLOADED_TEX) - - # Do the upload: we tail call to the RSPQ block that is within - # the texture state (at offset TEXTURE_LEVELS_BLOCK_OFFSET). This - # block was recorded by glTexImageN64 and contains the commands - # necessary to upload the texture(s) to TMEM. - addi a0, tex_id, TEXTURE_LEVELS_BLOCK_OFFSET - j RSPQCmd_Call - li a1, 1<<2 # nesting level 1 - -gl_set_texture_not_active: - and state_flags, ~FLAG_TEXTURE_ACTIVE - j RSPQ_Loop - sw state_flags, %lo(GL_STATE_FLAGS) - - #undef active_tex - #undef uploaded_tex - #undef tex_id - #undef tex_flags - #undef state_flags - #undef state_flags2 - .endfunc - -/* - ############################################################# - # Vec_Convert - # - # Converts a list of floats to fixed point (in-place) - # - # ARGS: - # s4: Address in DMEM of float list - # t0: Length - ############################################################# -Vec_Convert: - #define mant_i $v01 - #define mant_f $v02 - - #define exp $v03 - #define nexp $v04 - #define bit $v05 - #define sign $v06 - - #define step_i $v07 - #define step_f $v08 - #define fact_i $v09 - #define fact_f $v10 - - #define vconst $v11 - #define vhalf $v12 - #define vtmp $v13 - - li t1, %lo(CONVERT_CONST) - lqv vconst,0, 0,t1 - vor vhalf, vzero, vconst,e(2) - add s1, s4, t0 - -convert_loop: - lsv mant_i,0x0, 0x00,s4 - lsv mant_i,0x2, 0x04,s4 - lsv mant_i,0x4, 0x08,s4 - lsv mant_i,0x6, 0x0C,s4 - lsv mant_i,0x8, 0x10,s4 - lsv mant_i,0xA, 0x14,s4 - lsv mant_i,0xC, 0x18,s4 - lsv mant_i,0xE, 0x1C,s4 - lsv mant_f,0x0, 0x02,s4 - lsv mant_f,0x2, 0x06,s4 - lsv mant_f,0x4, 0x0A,s4 - lsv mant_f,0x6, 0x0E,s4 - lsv mant_f,0x8, 0x12,s4 - lsv mant_f,0xA, 0x16,s4 - lsv mant_f,0xC, 0x1A,s4 - lsv mant_f,0xE, 0x1E,s4 - - vmudm exp, mant_i, vconst,e(3) # exp = ((mant_i >> 7) & 0xFF) - vand exp, exp, vconst,e(4) - - vsub sign, vzero, vconst,e(0) # sign = mant_i < 0 ? -1 : 1 - vlt vtmp, mant_i, vzero - vmrg sign, sign, vconst,e(0) - - veq vtmp, exp, vzero # sign = exp == 0 ? 0 : sign - vmrg sign, vzero, sign - - vsub exp, exp, vconst,e(5) # exp -= 134 - - vsub nexp, vzero, exp # nexp = -exp - vlt vtmp, exp, vzero # c = exp < 0 - vmrg exp, nexp, exp # exp = c ? nexp : exp - vmrg step_i, vzero, vconst,e(1) # step = c ? 0.5 : 2 - vmrg step_f, vhalf, vzero - - vand mant_i, mant_i, vconst,e(6) # mant = (mant & 0x7F) | (1<<7) - vor mant_i, mant_i, vconst,e(7) - - li t0, 5 - -flt_2_fxd_loop: - vand bit, exp, vconst,e(0) # bit = exp & 1 - vlt vtmp, vzero, bit # c = 0 < bit - vmrg fact_i, step_i, vconst,e(0) # fact = c ? step : 1 - vmrg fact_f, step_f, vzero - - vmudl vtmp, mant_f, fact_f # mant *= fact - vmadm vtmp, mant_i, fact_f - vmadn mant_f, mant_f, fact_i - vmadh mant_i, mant_i, fact_i - - vmudl vtmp, step_f, step_f # step *= step - vmadm vtmp, step_i, step_f - vmadn step_f, step_f, step_i; addi t0, -1 - vmadh step_i, step_i, step_i; bgtz t0, flt_2_fxd_loop - - vmudm exp, exp, vhalf # exp = exp >> 1 - - vmudn vtmp, mant_f, sign # mant *= sign - vmadh mant_i, mant_i, sign - vmadn vtmp, mant_f, vzero; addi s4, 0x20 - - sqv mant_i,0, -0x20,s4; blt s4, s1, convert_loop - sqv mant_f,0, -0x10,s4 - - jr ra - nop -*/ /* GLCmd_SetLightDir: #define v___ $v01 diff --git a/src/GL/rsp_gl2.S b/src/GL/rsp_gl2.S new file mode 100644 index 0000000000..23751bd19c --- /dev/null +++ b/src/GL/rsp_gl2.S @@ -0,0 +1,901 @@ +#include +#include +#include "gl_constants.h" +#include "GL/gl_enums.h" +#include + + .data + + RSPQ_BeginOverlayHeader + RSPQ_DefineCommand GLCmd_PreInitPipe, 4 # 0x0 + RSPQ_DefineCommand GLCmd_PreInitPipeTex,4 # 0x1 + RSPQ_DefineCommand GLCmd_SetPipeline, 8 # 0x2 + RSPQ_DefineCommand GLCmd_PreInitMagma, 8 # 0x3 + RSPQ_EndOverlayHeader + + RSPQ_BeginSavedState + #include "rsp_gl_state.inc" + RSPQ_EndSavedState + +COMBINER_TABLE: + # No texture + .quad RDPQ_COMBINER1((0, 0, 0, SHADE), (0, 0, 0, SHADE)) # "modulate" + .quad RDPQ_COMBINER1((0, 0, 0, PRIM), (0, 0, 0, PRIM)) # constant "modulate" + .quad RDPQ_COMBINER1((0, 0, 0, SHADE), (0, 0, 0, SHADE)) # "replace" + .quad RDPQ_COMBINER1((0, 0, 0, PRIM), (0, 0, 0, PRIM)) # constant "replace" + + # Texture enabled + .quad RDPQ_COMBINER1((TEX0, 0, SHADE, 0), (TEX0, 0, SHADE, 0)) # modulate + .quad RDPQ_COMBINER1((TEX0, 0, PRIM, 0), (TEX0, 0, PRIM, 0)) # constant modulate + .quad RDPQ_COMBINER1((0, 0, 0, TEX0), (0, 0, 0, TEX0)) # replace + .quad RDPQ_COMBINER1((0, 0, 0, TEX0), (0, 0, 0, TEX0)) # constant replace + +COMBINER_MIPMAPMASK_TABLE: + .quad RDPQ_COMB1_MASK + .quad RDPQ_COMB1_MASK + .quad RDPQ_COMB1_MASK + .quad RDPQ_COMB1_MASK + + .quad RDPQ_COMB1_MASK ^ (1<<37) ^ (1<<21) + .quad RDPQ_COMB1_MASK ^ (1<<37) ^ (1<<21) + .quad RDPQ_COMB1_MASK ^ (1<<6) ^ (1<<0) + .quad RDPQ_COMB1_MASK ^ (1<<6) ^ (1<<0) + + .align 4 +MG_STATE_STAGING: + _MgState 1 + .align 4 + MATRICES_MVP: .ds.b 64 + .align 4 + MATRICES_MV: .ds.b 64 + .align 4 + MATRICES_NORMAL: .ds.b 32 + .align 4 + TEXTURE_MATRIX: .ds.b 48 + TEXTURE_SIZE: .ds.b 4 + TEXTURE_OFFSET: .ds.b 4 + .align 3 + LIGHTING_LIGHTS: .ds.b 256 + .align 1 + LIGHTING_AMBIENT: .ds.b 6 + LIGHTING_HAS_POINTS: .ds.b 1 + LIGHTING_COUNT: .ds.b 1 + MATERIAL_DIFFUSE: .ds.b 8 + MATERIAL_AMBIENT: .ds.b 6 + MATERIAL_FLAGS: .ds.b 2 + MATERIAL_EMISSIVE: .ds.b 6 + .align 3 + FOG_PARAMS: .ds.b 6 + FOG_MASK: .ds.b 1 + .align 3 +MG_STATE_STAGING_END: + + .text + + .func GLCmd_PreInitPipe +GLCmd_PreInitPipe: + sh a0, %lo(GL_STATE_PRIM_TYPE) + + #define state_flags k1 + #define state_flags2 k0 + + lw state_flags, %lo(GL_STATE_FLAGS) + lw state_flags2, %lo(GL_STATE_FLAGS2) + + # Determine Culling mode + + #define cull_mode t1 + #define front_face t2 + #define cull_enabled t3 + #define tri_cull t4 + + andi cull_enabled, state_flags, FLAG_CULL_FACE + beqz cull_enabled, 1f + # Any non-negative value other than 0 or 1 signifies that no faces should be culled + li tri_cull, 2 + + lhu cull_mode, %lo(GL_STATE_CULL_MODE) + lhu front_face, %lo(GL_STATE_FRONT_FACE) + + # Set TRI_CULL to a negative number to cull all faces + beq cull_mode, GL_FRONT_AND_BACK, 1f + li tri_cull, -1 + + # tri_cull = (cull_mode == GL_BACK) ^ (front_face == GL_CW) + xori cull_mode, GL_FRONT + sltu tri_cull, zero, cull_mode + xori front_face, GL_CCW + sltu front_face, zero, front_face + xor tri_cull, front_face + +1: + sb tri_cull, %lo(GL_TRI_CULL) + + #undef cull_mode + #undef front_face + #undef cull_enabled + #undef tri_cull + + #define modes0 t8 + #define modes1 t9 + #define is_points v0 + #define active_tex s7 + + # Get Active texture + + andi t1, state_flags, FLAG_TEXTURE_2D + bnez t1, 1f + li active_tex, %lo(GL_BOUND_TEXTURE_2D) + andi t1, state_flags, FLAG_TEXTURE_1D + bnez t1, 1f + li active_tex, %lo(GL_BOUND_TEXTURE_1D) + move active_tex, zero +1: + #define tri_cmd t4 + srl tri_cmd, state_flags, TRICMD_ATTR_SHIFT + andi tri_cmd, TRICMD_ATTR_MASK + ori tri_cmd, 0xCC00 + sh tri_cmd, %lo(GL_TRI_CMD) + + #undef tri_cmd + + # Multisampling + and t0, state_flags2, FLAG2_REDUCED_ALIASING + or modes0, t0, (SOM_TF0_RGB | SOM_TF1_RGB) >> 32 + and modes1, state_flags2, FLAG2_MULTISAMPLE + + # Alpha test + andi t0, state_flags, FLAG_ALPHA_TEST + beqz t0, 1f + lhu t1, %lo(GL_STATE_ALPHA_FUNC) + xori t1, GL_GREATER + sltu t0, t1, 1 + or modes1, t0 +1: + + # Depth mask + and t0, state_flags, FLAG_DEPTH_TEST | FLAG_DEPTH_MASK + xor t0, FLAG_DEPTH_TEST | FLAG_DEPTH_MASK + sltu t0, 1 + sll t0, SOM_Z_WRITE_SHIFT + or modes1, t0 + + #define depth_func t3 + + # Depth test + and t0, state_flags, FLAG_DEPTH_TEST + beqz t0, 1f + lhu depth_func, %lo(GL_STATE_DEPTH_FUNC) + xori t1, depth_func, GL_ALWAYS + sltu t1, zero, t1 + sll t0, t1, SOM_Z_COMPARE_SHIFT + or modes1, t0 +1: + + # Z mode + xori t1, depth_func, GL_EQUAL + beqz t1, 1f + li t0, SOM_ZMODE_DECAL + xori t1, depth_func, GL_LESS_INTERPENETRATING_N64 + beqz t1, 1f + li t0, SOM_ZMODE_INTERPENETRATING + andi t0, state_flags, FLAG_BLEND + # t0 = (state_flags & FLAG_BLEND) ? SOM_ZMODE_TRANSPARENT : SOM_ZMODE_OPAQUE + sll t0, ZMODE_BLEND_FLAG_SHIFT +1: + or modes1, t0 + + #undef depth_func + + # Dither + andi t1, state_flags, FLAG_DITHER + beqz t1, 1f + li t0, (SOM_RGBDITHER_NONE | SOM_ALPHADITHER_NONE) >> 32 + lw t0, %lo(GL_STATE_DITHER_MODE) +1: + or modes0, t0 + + # Points + lhu t0, %lo(GL_STATE_PRIM_TYPE) + beqz t0, 1f # prim_type == GL_POINTS + li is_points, 1 + + addi t0, -1 + sltu t0, (GL_TRIANGLES - 1) + bne t0, zero, 1f # prim_type == GL_LINES || prim_type == GL_LINE_LOOP || prim_type == GL_LINE_STRIP + move is_points, zero + + lhu t0, %lo(GL_STATE_POLYGON_MODE) + xori t0, GL_POINT + sltu is_points, t0, 1 # polygon_mode == GL_POINT + +1: + bnez is_points, 1f + sll t3, is_points, SOM_ZSOURCE_SHIFT + or modes0, SOM_TEXTURE_PERSP >> 32 +1: + or modes1, t3 + + # * Skip construction of CC/CB if FLAG2_USE_RDPQ_MATERIAL is active + andi t1, state_flags2, FLAG2_USE_RDPQ_MATERIAL + bnez t1, gl_skipcombinerblender + + # Blend cycle + andi t0, state_flags, FLAG_BLEND + beqz t0, 1f + move t1, zero + lw t1, %lo(GL_STATE_BLEND_CYCLE) +1: + sw t1, %lo(RDPQ_MODE_BLENDER_STEPS) + 0x4 + + # Fog cycle + andi t0, state_flags, FLAG_FOG + beqz t0, 1f + move t2, zero + li t2, RDPQ_BLENDER((FOG_RGB, SHADE_ALPHA, IN_RGB, INV_MUX_ALPHA)) | SOM_BLENDING +1: + sw t2, %lo(RDPQ_MODE_BLENDER_STEPS) + 0x0 + + # Combiner + move t5, is_points + lw t3, %lo(GL_STATE_TEX_ENV_MODE) + + li t4, GL_REPLACE + bne t3, t4, 1f + nop + ori t5, COMBINER_FLAG_REPLACE +1: + srl t0, state_flags, TEX_ACTIVE_COMBINER_SHIFT + andi t0, COMBINER_FLAG_TEXTURE + or t5, t0 + + sll t5, 3 + lw t0, %lo(COMBINER_TABLE) + 0x0(t5) + lw t1, %lo(COMBINER_TABLE) + 0x4(t5) + lw t2, %lo(COMBINER_MIPMAPMASK_TABLE) + 0x0(t5) + lw t3, %lo(COMBINER_MIPMAPMASK_TABLE) + 0x4(t5) + + # TODO: The following is sort of equivalent to RDPQCmd_ResetMode. Maybe make that callable from ucode? + + sw t0, %lo(RDPQ_COMBINER) + 0x0 + sw t1, %lo(RDPQ_COMBINER) + 0x4 + sw t2, %lo(RDPQ_COMBINER_MIPMAPMASK) + 0x0 + sw t3, %lo(RDPQ_COMBINER_MIPMAPMASK) + 0x4 + +gl_skipcombinerblender: + + # * Skip specific GL texture flags if FLAG2_USE_RDPQ_TEXTURING is active and instead apply RDPQ ones + + andi t1, state_flags2, FLAG2_USE_RDPQ_TEXTURING + bnez t1, gl_mergemask + nop + + # Texture + beqz active_tex, 2f + lw t4, TEXTURE_FLAGS_OFFSET(active_tex) + + andi t5, t4, TEX_FLAG_COMPLETE + beqz t5, 2f + lhu t3, TEXTURE_MIN_FILTER_OFFSET(active_tex) + lhu t2, TEXTURE_MAG_FILTER_OFFSET(active_tex) + + andi t5, t3, TEXTURE_MIPMAP_MASK + or t2, t3 + andi t2, TEXTURE_BILINEAR_MASK + + # If bilinear sampling is active, texture coords need to be offset by half a texel, + # which is 0x10 in s10.5 + andi t7, state_flags2, FLAG2_TEX_FLIP_T + lh t6, %lo(GL_STATE_TEX_SIZE) + 2 + sll t1, t2, TEX_BILINEAR_OFFSET_SHIFT + neg t1, t1 + beqz t7, 1f + sh t1, %lo(GL_STATE_TEX_OFFSET) + 0 + sra t6, 1 + sub t1, t6 +1: + sh t1, %lo(GL_STATE_TEX_OFFSET) + 2 + + beqz t5, 1f + sll t2, TEX_BILINEAR_SHIFT + or t2, SOM_TEXTURE_LOD >> 32 + + andi t5, t4, TEX_FLAG_DETAIL + sll t5, TEX_DETAIL_SHIFT + or t2, t5 + +1: + andi t3, TEXTURE_INTERPOLATE_MASK + beqz t3, 1f + nop # :( + ori t2, SOMX_LOD_INTERPOLATE >> 32 + +1: + # TODO: Combine into a single field? + lbu t0, TEXTURE_LEVELS_COUNT_OFFSET(active_tex) + lbu t1, TEXTURE_TLUT_MODE_OFFSET(active_tex) + + sll t0, SOMX_NUMLODS_SHIFT - 32 + sll t1, SOM_TLUT_SHIFT - 32 + + or t0, t1 + or t7, t0, t2 + or modes0, t7 +2: + + j 1f + nop # :( +gl_mergemask: + # If we have FLAG2_USE_RDPQ_TEXTURING active, we need to use some of the RDPQ params instead of GL's + + lw t1, %lo(RDPQ_OTHER_MODES) + 0x0 + and t1, RDPQ_TEXTURING_MASK + and t2, modes0, ~(RDPQ_TEXTURING_MASK) + or modes0, t1, t2 + + +1: + + lw t0, %lo(RDPQ_OTHER_MODES) + 0x0 + + sw modes0, %lo(RDPQ_OTHER_MODES) + 0x0 + sw modes1, %lo(RDPQ_OTHER_MODES) + 0x4 + + # If cycle mode was copy or fill, update scissor rect + sll t0, ((64-2)-SOM_CYCLE_SHIFT) + bgez t0, 1f + lw a0, %lo(RDPQ_SCISSOR_RECT) + 0x0 + jal RDPQ_WriteSetScissor + lw a1, %lo(RDPQ_SCISSOR_RECT) + 0x4 + +1: + + j RDPQ_UpdateRenderMode + sw state_flags, %lo(GL_STATE_FLAGS) + + #undef modes0 + #undef modes1 + #undef is_points + #undef active_tex + #undef state_flags + .endfunc + + .func GLCmd_PreInitPipeTex +GLCmd_PreInitPipeTex: + #define tex_id s0 + #define uploaded_tex s1 + #define active_tex s7 + #define active_tex_id s6 + #define tex_flags t7 + #define state_flags k1 + #define state_flags2 k0 + + # Skip processing texture state if we are using rdpq API for texturing + # (FLAG2_USE_RDPQ_TEXTURING) + lw state_flags2, %lo(GL_STATE_FLAGS2) + andi t1, state_flags2, FLAG2_USE_RDPQ_TEXTURING + beqz t1, 2f + lw state_flags, %lo(GL_STATE_FLAGS) + + or state_flags, FLAG_TEXTURE_ACTIVE + sw state_flags, %lo(GL_STATE_FLAGS) + + # If bilinear sampling is active, texture coords need to be offset by half a texel, + # which is 0x10 in s10.5 + lw t2, %lo(RDPQ_OTHER_MODES) + 0x4 + and t2, (SOM_SAMPLE_BILINEAR >> 32) + sll t2, t2, (SOM_SAMPLE_SHIFT - 32 + 1) + + andi t3, state_flags2, FLAG2_TEX_FLIP_T + lh t6, %lo(GL_STATE_TEX_SIZE) + 2 + sll t1, t2, TEX_BILINEAR_OFFSET_SHIFT + neg t1, t1 + beqz t7, 1f + sh t1, %lo(GL_STATE_TEX_OFFSET) + 0 + sra t6, 1 + sub t1, t6 + +1: + sh t1, %lo(GL_STATE_TEX_OFFSET) + 2 + j RSPQ_Loop + +2: + # Get pointer to active texture state in DMEM + li active_tex_id, %lo(GL_STATE_TEXTURE_IDS) + 0x4 + andi t1, state_flags, FLAG_TEXTURE_2D + bnez t1, 1f + li active_tex, %lo(GL_BOUND_TEXTURE_2D) + andi t1, state_flags, FLAG_TEXTURE_1D + li active_tex_id, %lo(GL_STATE_TEXTURE_IDS) + 0x0 + bnez t1, 1f + li active_tex, %lo(GL_BOUND_TEXTURE_1D) + j gl_set_texture_not_active +1: + lw uploaded_tex, %lo(GL_STATE_UPLOADED_TEX) + + # CHeck if the texture is complete (that is, all mipmaps have been loaded) + # otherwise, we consider it not complete and avoid displaying it + lw tex_flags, TEXTURE_FLAGS_OFFSET(active_tex) + andi t0, tex_flags, TEX_FLAG_COMPLETE + beqz t0, gl_set_texture_not_active + + # Copy width/height of the active texture into the state + lh t0, IMAGE_WIDTH_OFFSET(active_tex) + lh t1, IMAGE_HEIGHT_OFFSET(active_tex) + andi t2, state_flags2, FLAG2_TEX_FLIP_T + beqz t2, 1f + sh t0, %lo(GL_STATE_TEX_SIZE) + 0 + neg t1, t1 +1: + sh t1, %lo(GL_STATE_TEX_SIZE) + 2 + + # Make sure FLAG_TEXTURE_ACTIVE is set + or state_flags, FLAG_TEXTURE_ACTIVE + sw state_flags, %lo(GL_STATE_FLAGS) + + # Load ID of active texture (that is, RDRAM pointer) + lw tex_id, (active_tex_id) + + # Proceed with the upload if: + # * the requested texture ID is different from the one currently uploaded to TMEM + # * the dirty flag is set + bne tex_id, uploaded_tex, 1f + andi t0, tex_flags, TEX_FLAG_UPLOAD_DIRTY + beqz t0, RSPQ_Loop +# nop + +1: + # OK we are going to do the upload. Update the state: clear dirty flag and + # set the current texture ID. + li t0, ~TEX_FLAG_UPLOAD_DIRTY + and tex_flags, t0 + sw tex_flags, TEXTURE_FLAGS_OFFSET(active_tex) + sw tex_id, %lo(GL_STATE_UPLOADED_TEX) + + # Do the upload: we tail call to the RSPQ block that is within + # the texture state (at offset TEXTURE_LEVELS_BLOCK_OFFSET). This + # block was recorded by glTexImageN64 and contains the commands + # necessary to upload the texture(s) to TMEM. + addi a0, tex_id, TEXTURE_LEVELS_BLOCK_OFFSET + j RSPQCmd_Call + li a1, 1<<2 # nesting level 1 + +gl_set_texture_not_active: + and state_flags, ~FLAG_TEXTURE_ACTIVE + j RSPQ_Loop + sw state_flags, %lo(GL_STATE_FLAGS) + + #undef active_tex + #undef uploaded_tex + #undef tex_id + #undef tex_flags + #undef state_flags + #undef state_flags2 + .endfunc + + ############################################################# + # GLCmd_SetPipeline + # + # ARGS: + # a0: Bit 31..24: Command id + # Bit 23..0: RDRAM pointer to shader text + # a1: Bit 31..16: Offset into GL_PIPELINES + # Bit 15..0: shader text size + ############################################################# + .func GLCmd_SetPipeline +GLCmd_SetPipeline: + srl t0, a1, 16 + sw a0, %lo(GL_PIPELINES) + 0(t0) + jr ra + sh a1, %lo(GL_PIPELINES) + 6(t0) + .endfunc + +.set noreorder +.set noat +.set nomacro + +#undef zero +#undef at +#undef v0 +#undef v1 +#undef a0 +#undef a1 +#undef a2 +#undef a3 +#undef t0 +#undef t1 +#undef t2 +#undef t3 +#undef t4 +#undef t5 +#undef t6 +#undef t7 +#undef s0 +#undef s1 +#undef s2 +#undef s3 +#undef s4 +#undef s5 +#undef s6 +#undef s7 +#undef t8 +#undef t9 +#undef k0 +#undef k1 +#undef gp +#undef sp +#undef fp +#undef ra +.equ hex.$zero, 0 +.equ hex.$at, 1 +.equ hex.$v0, 2 +.equ hex.$v1, 3 +.equ hex.$a0, 4 +.equ hex.$a1, 5 +.equ hex.$a2, 6 +.equ hex.$a3, 7 +.equ hex.$t0, 8 +.equ hex.$t1, 9 +.equ hex.$t2, 10 +.equ hex.$t3, 11 +.equ hex.$t4, 12 +.equ hex.$t5, 13 +.equ hex.$t6, 14 +.equ hex.$t7, 15 +.equ hex.$s0, 16 +.equ hex.$s1, 17 +.equ hex.$s2, 18 +.equ hex.$s3, 19 +.equ hex.$s4, 20 +.equ hex.$s5, 21 +.equ hex.$s6, 22 +.equ hex.$s7, 23 +.equ hex.$t8, 24 +.equ hex.$t9, 25 +.equ hex.$k0, 26 +.equ hex.$k1, 27 +.equ hex.$gp, 28 +.equ hex.$sp, 29 +.equ hex.$fp, 30 +.equ hex.$ra, 31 +#define vco 0 +#define vcc 1 +#define vce 2 + +GLCmd_PreInitMagma: + lw $k0, %lo(GL_STATE_FLAGS + 0) ## L:1105 | ^ | u32<$k0> flags = load(GL_STATE_FLAGS, 0); + lui $s6, 0x3000 ## L:1111 | 2 | u32 env_mask = 0x30000000; + and $s5, $k0, $s6 ## L:1112 | *4 | u32 tmp = flags & env_mask; + bne $s5, $s6, LABEL_GLCmd_PreInitMagma_0001 ## L:1113 | 5 | if (tmp == env_mask) + or $s7, $zero, $zero ## L:1109 | *7 | u32 features = 0; + lhu $s3, %lo(GL_TEX_GEN + 128) ## L:1116 | 8 | u16 mode_s = load(GL_TEX_GEN, 128); + addiu $s4, $zero, 9218 ## L:1115 | 9 | u16 sphere_map = 0x2402; + lhu $s2, %lo(GL_TEX_GEN + 130) ## L:1117 | 10 | u16 mode_t = load(GL_TEX_GEN, 130); + bne $s3, $s4, LABEL_GLCmd_PreInitMagma_0001 ## L:1118 | 11 | if (mode_s == sphere_map) + nop ## L:1118 | *13 | if (mode_s == sphere_map) + bne $s2, $s4, LABEL_GLCmd_PreInitMagma_0001 ## L:1120 | 14 | if (mode_t == sphere_map) + nop ## L:1120 | *16 | if (mode_t == sphere_map) + ori $s7, $s7, 1 ## L:1122 | 17 | features |= 1; + LABEL_GLCmd_PreInitMagma_0001: + andi $s4, $k0, 4096 ## L:1127 | 18 | u32 normalize_enabled = flags & 0x1000; + beq $s4, $zero, LABEL_GLCmd_PreInitMagma_0004 ## L:1128 | 19 | if (normalize_enabled != 0) + nop ## L:1128 | *21 | if (normalize_enabled != 0) + ori $s7, $s7, 2 ## L:1130 | 22 | features |= 2; + LABEL_GLCmd_PreInitMagma_0004: + sll $s7, $s7, 3 ## L:1133 | 23 | features = features << 3; + addiu $at, $s7, GL_PIPELINES ## L:1135 | 24 | vec16 pipeline = load(features, GL_PIPELINES).xyzw; + ldv $v28, 0, 0, $at ## L:1135 | 25 | vec16 pipeline = load(features, GL_PIPELINES).xyzw; + lh $s7, %lo(GL_MATRIX_PROJECTION + 22) ## L:1148 | 26 | s16 m23i = load(GL_MATRIX_PROJECTION, 0x16); + ori $at, $zero, %lo(MG_SHADER_TEXT) ## L:1136 | 27 | store(pipeline.xyzw, MG_SHADER_TEXT); + lhu $s6, %lo(GL_MATRIX_PROJECTION + 54) ## L:1149 | 28 | u16 m23f = load(GL_MATRIX_PROJECTION, 0x36); + sdv $v28, 0, 0, $at ## L:1136 | 29 | store(pipeline.xyzw, MG_SHADER_TEXT); + ori $at, $zero, %lo(GL_VIEWPORT_SCALE) ## L:1141 | 30 | vec16 viewport = load(GL_VIEWPORT_SCALE, 0); + lqv $v28, 0, 0, $at ## L:1141 | 31 | vec16 viewport = load(GL_VIEWPORT_SCALE, 0); + or $s5, $s7, $s6 ## L:1150 | 32 | u16 m23 = m23i | m23f; + ori $at, $zero, %lo(MG_VIEWPORT) ## L:1142 | 33 | store(viewport, MG_VIEWPORT, 0); + bne $s5, $zero, LABEL_GLCmd_PreInitMagma_0005 ## L:1151 | 34 | if (m23 == 0) + sqv $v28, 0, 0, $at ## L:1142 | *36 | store(viewport, MG_VIEWPORT, 0); + ori $s4, $zero, 0xFFFF ## L:1155 | 37 | u16 norm_factor = 0xFFFF; + beq $zero, $zero, LABEL_GLCmd_PreInitMagma_0006 ## L:1156 | 38 | store(norm_factor, MG_VIEWPORT, 0x6); + sh $s4, %lo(6 + MG_VIEWPORT)($zero) ## L:1156 | *40 | store(norm_factor, MG_VIEWPORT, 0x6); + LABEL_GLCmd_PreInitMagma_0005: + ori $at, $zero, %lo(GL_MATRIX_PROJECTION) ## L:1178 | 41 | m:sint = load(GL_MATRIX_PROJECTION, 0x10); + lqv $v28, 0, 48, $at ## L:1179 | 42 | m:ufract = load(GL_MATRIX_PROJECTION, 0x30); + lqv $v27, 0, 16, $at ## L:1178 | 43 | m:sint = load(GL_MATRIX_PROJECTION, 0x10); + ori $at, $zero, %lo(MG_VIEWPORT) ## L:1191 | **46 | store(a:sfract.x, MG_VIEWPORT, 0x6); + vmudl $v29, $v28, $v28.e2 ## L:1182 | ^ | vec32 a = m * m.z; + vmadm $v29, $v27, $v28.e2 ## L:1182 | 47 | vec32 a = m * m.z; + vmadn $v26, $v28, $v27.e2 ## L:1182 | 48 | vec32 a = m * m.z; + vmadh $v25, $v27, $v27.e2 ## L:1182 | 49 | vec32 a = m * m.z; + vsubc $v24, $v26, $v00.e7 ## L:1184 | **52 | vec32 b = a - 1; + vsub $v23, $v25, $v30.e7 ## L:1184 | 53 | vec32 b = a - 1; + vrcph $v25.e0, $v25.e6 ## L:1186 | 54 | a.x = invert_half(a).Z; + vrcpl $v26.e0, $v26.e6 ## L:1186 | 55 | a.x = invert_half(a).Z; + vrcph $v25.e0, $v00.e6 ## L:1186 | 56 | a.x = invert_half(a).Z; + vmudl $v29, $v26, $v24.e2 ## L:1188 | **59 | a *= b.z; + vmadm $v29, $v25, $v24.e2 ## L:1188 | 60 | a *= b.z; + vmadn $v26, $v26, $v23.e2 ## L:1188 | 61 | a *= b.z; + vmadh $v25, $v25, $v23.e2 ## L:1188 | 62 | a *= b.z; + vmudn $v26, $v26, $v30.e6 ## L:1189 | **65 | a *= 2; + ssv $v26, 0, 6, $at ## L:1191 | ***69 | store(a:sfract.x, MG_VIEWPORT, 0x6); + vmadh $v25, $v25, $v30.e6 ## L:1189 | ^ | a *= 2; + LABEL_GLCmd_PreInitMagma_0006: + lhu $s7, %lo(GL_TRI_CMD + 0) ## L:1197 | 70 | u16 tri_cmd = load(GL_TRI_CMD, 0); + andi $s3, $k0, 16384 ## L:1218 | 71 | u32 palette_enabled = flags & 0x4000; + ori $s5, $zero, %lo(GL_MATRIX_PROJECTION) ## L:1215 | 72 | mtx_lhs = GL_MATRIX_PROJECTION; + sh $s7, %lo(0 + MG_TRI_CMD)($zero) ## L:1198 | 73 | store(tri_cmd, MG_TRI_CMD, 0); + lbu $s7, %lo(GL_TRI_CULL + 0) ## L:1203 | 74 | u8 cull = load(GL_TRI_CULL, 0); + sb $s7, %lo(0 + MG_CULL_MODE)($zero) ## L:1204 | **77 | store(cull, MG_CULL_MODE, 0); + ori $s7, $zero, %lo(MATRICES_MVP) ## L:1216 | 78 | mtx_dst = MATRICES_MVP; + beq $s3, $zero, LABEL_GLCmd_PreInitMagma_0007 ## L:1219 | 79 | if (palette_enabled != 0) + nop ## L:1224 | *81 | dmem_ptr = GL_MATRIX_PALETTE; + lw $s2, %lo(GL_STATE_PALETTE_INDEX + 0) ## L:1221 | 82 | u32 palette_index = load(GL_STATE_PALETTE_INDEX); + lw $s0, %lo(GL_PALETTE_PTR + 0) ## L:1222 | 83 | rdram_ptr = load(GL_PALETTE_PTR); + ori $s4, $zero, %lo(GL_MATRIX_PALETTE) ## L:1224 | 84 | dmem_ptr = GL_MATRIX_PALETTE; + ori $t0, $zero, 63 ## L:1225 | 85 | dma_out_async(dmem_ptr, rdram_ptr, 64); + addiu $t2, $zero, -32768 ## L:1225 | 86 | dma_out_async(dmem_ptr, rdram_ptr, 64); + jal DMAExec ## L:1225 | 87 | dma_out_async(dmem_ptr, rdram_ptr, 64); ## Args: $t0, $t1, $s0, $s4, $t2 + addu $s0, $s0, $s2 ## L:1223 | *89 | rdram_ptr += palette_index; + ori $s6, $zero, %lo(MATRICES_MV) ## L:1227 | 90 | mtx_rhs = MATRICES_MV; + or $s1, $zero, $zero ## L:1231 | 91 | u16 i = 0; + lw $s0, %lo(GL_PALETTE_PTR + 0) ## L:1230 | 92 | rdram_ptr = load(GL_PALETTE_PTR); + ori $s4, $zero, %lo(MATRICES_MVP) ## L:1229 | 93 | dmem_ptr = MATRICES_MVP; + LABEL_GLCmd_PreInitMagma_0009: + sltiu $at, $s1, 32 ## L:1232 | 94 | while (i < 32) { + beq $at, $zero, LABEL_GLCmd_PreInitMagma_000A ## L:1232 | 95 | while (i < 32) { + nop ## L:1232 | *97 | while (i < 32) { + ori $t0, $zero, 159 ## L:1233 | 98 | dma_in(dmem_ptr, rdram_ptr, 160); + jal DMAExec ## L:1233 | 99 | dma_in(dmem_ptr, rdram_ptr, 160); ## Args: $t0, $t1, $s0, $s4, $t2 + addiu $t2, $zero, 12 ## L:1233 | *101 | dma_in(dmem_ptr, rdram_ptr, 160); + ori $at, $zero, %lo(MATRICES_MV) ## L:1237 | 102 | m0:sint = load(MATRICES_MV, 0x00); + lqv $v28, 0, 32, $at ## L:1239 | 103 | m0:ufract = load(MATRICES_MV, 0x20); + lqv $v26, 0, 48, $at ## L:1240 | 104 | m1:ufract = load(MATRICES_MV, 0x30); + lqv $v27, 0, 0, $at ## L:1237 | 105 | m0:sint = load(MATRICES_MV, 0x00); + lqv $v25, 0, 16, $at ## L:1238 | 106 | m1:sint = load(MATRICES_MV, 0x10); + addiu $at, $zero, 32767 ## L:1095 | 107 | c.x = 0x7FFF; + mtc2 $at, $v24.e0 ## L:1095 | *109 | c.x = 0x7FFF; + ori $at, $zero, %lo(MATRICES_NORMAL) ## L:1099 | ***113 | store(m0:sint, MATRICES_NORMAL, 0x00); + vmudn $v28, $v28, $v24.e0 ## L:1096 | ^ | m0 = m0 * c.x; + vmadh $v27, $v27, $v24.e0 ## L:1096 | 114 | m0 = m0 * c.x; + vmudn $v26, $v26, $v24.e0 ## L:1097 | 115 | m1 = m1 * c.x; + vmadh $v25, $v25, $v24.e0 ## L:1097 | 116 | m1 = m1 * c.x; + sqv $v25, 0, 16, $at ## L:1100 | ***120 | store(m1:sint, MATRICES_NORMAL, 0x10); + jal GL_MtxMult ## L:1245 | 121 | GL_MtxMult(); + sqv $v27, 0, 0, $at ## L:1099 | *123 | store(m0:sint, MATRICES_NORMAL, 0x00); + ori $t0, $zero, 159 ## L:1246 | 124 | dma_out_async(dmem_ptr, rdram_ptr, 160); + jal DMAExec ## L:1246 | 125 | dma_out_async(dmem_ptr, rdram_ptr, 160); ## Args: $t0, $t1, $s0, $s4, $t2 + addiu $t2, $zero, -32768 ## L:1246 | *127 | dma_out_async(dmem_ptr, rdram_ptr, 160); + addiu $s1, $s1, 1 ## L:1248 | 128 | i += 1; + j LABEL_GLCmd_PreInitMagma_0009 ## L:1248 | 129 | i += 1; + addiu $s0, $s0, 160 ## L:1247 | *131 | rdram_ptr += 160; + LABEL_GLCmd_PreInitMagma_000A: + lw $s0, %lo(GL_PALETTE_PTR + 0) ## L:1256 | 132 | rdram_ptr = load(GL_PALETTE_PTR); + lbu $fp, %lo(GL_CUR_MTX_INDEX + 0) ## L:1251 | 133 | u8 cur_mtx_index = load(GL_CUR_MTX_INDEX); + addiu $t2, $zero, 12 ## L:1258 | 134 | dma_in(dmem_ptr, rdram_ptr, 160); + ori $t0, $zero, 159 ## L:1258 | 135 | dma_in(dmem_ptr, rdram_ptr, 160); + sll $sp, $fp, 7 ## L:1252 | 136 | u32 tmp = cur_mtx_index << 7; + sll $s2, $fp, 5 ## L:1253 | 137 | palette_index = cur_mtx_index << 5; + addu $s2, $s2, $sp ## L:1254 | 138 | palette_index += tmp; + jal DMAExec ## L:1258 | 139 | dma_in(dmem_ptr, rdram_ptr, 160); ## Args: $t0, $t1, $s0, $s4, $t2 + addu $s0, $s0, $s2 ## L:1257 | *141 | rdram_ptr += palette_index; + beq $zero, $zero, LABEL_GLCmd_PreInitMagma_0008 ## L:1258 | 142 | dma_in(dmem_ptr, rdram_ptr, 160); + nop ## L:1258 | *144 | dma_in(dmem_ptr, rdram_ptr, 160); + LABEL_GLCmd_PreInitMagma_0007: + jal GL_MtxMult ## L:1263 | 145 | GL_MtxMult(); + ori $s6, $zero, %lo(GL_MATRIX_MODELVIEW) ## L:1262 | *147 | mtx_rhs = GL_MATRIX_MODELVIEW; + ori $at, $zero, %lo(GL_MATRIX_MODELVIEW) ## L:1267 | 148 | m0:sint = load(GL_MATRIX_MODELVIEW, 0x00); + lqv $v28, 0, 32, $at ## L:1269 | 149 | m0:ufract = load(GL_MATRIX_MODELVIEW, 0x20); + lqv $v27, 0, 0, $at ## L:1267 | 150 | m0:sint = load(GL_MATRIX_MODELVIEW, 0x00); + lqv $v25, 0, 16, $at ## L:1268 | 151 | m1:sint = load(GL_MATRIX_MODELVIEW, 0x10); + lqv $v26, 0, 48, $at ## L:1270 | 152 | m1:ufract = load(GL_MATRIX_MODELVIEW, 0x30); + ori $at, $zero, %lo(MATRICES_MV) ## L:1272 | 153 | store(m0:sint, MATRICES_MV, 0x00); + sqv $v25, 0, 16, $at ## L:1273 | *155 | store(m1:sint, MATRICES_MV, 0x10); + sqv $v28, 0, 32, $at ## L:1274 | 156 | store(m0:ufract, MATRICES_MV, 0x20); + sqv $v26, 0, 48, $at ## L:1275 | 157 | store(m1:ufract, MATRICES_MV, 0x30); + sqv $v27, 0, 0, $at ## L:1272 | 158 | store(m0:sint, MATRICES_MV, 0x00); + addiu $at, $zero, 32767 ## L:1095 | 159 | c.x = 0x7FFF; + mtc2 $at, $v24.e0 ## L:1095 | 160 | c.x = 0x7FFF; + vmudn $v28, $v28, $v24.e0 ## L:1096 | ***164 | m0 = m0 * c.x; + vmadh $v27, $v27, $v24.e0 ## L:1096 | 165 | m0 = m0 * c.x; + vmudn $v26, $v26, $v24.e0 ## L:1097 | 166 | m1 = m1 * c.x; + vmadh $v25, $v25, $v24.e0 ## L:1097 | 167 | m1 = m1 * c.x; + ori $at, $zero, %lo(MATRICES_NORMAL) ## L:1099 | ^ | store(m0:sint, MATRICES_NORMAL, 0x00); + sqv $v27, 0, 0, $at ## L:1099 | *169 | store(m0:sint, MATRICES_NORMAL, 0x00); + sqv $v25, 0, 16, $at ## L:1100 | *171 | store(m1:sint, MATRICES_NORMAL, 0x10); + LABEL_GLCmd_PreInitMagma_0008: + ori $at, $zero, %lo(GL_MATRIX_TEXTURE) ## L:1286 | 172 | tm0:sint = load(GL_MATRIX_TEXTURE, 0x00).xyzw; + ldv $v25, 0, 8, $at ## L:1288 | 173 | tm1:sint = load(GL_MATRIX_TEXTURE, 0x08).xyzw; + ldv $v23, 0, 24, $at ## L:1290 | 174 | tm3:sint = load(GL_MATRIX_TEXTURE, 0x18).xyzw; + ldv $v26, 0, 40, $at ## L:1289 | 175 | tm1:ufract = load(GL_MATRIX_TEXTURE, 0x28).xyzw; + ldv $v27, 0, 0, $at ## L:1286 | 176 | tm0:sint = load(GL_MATRIX_TEXTURE, 0x00).xyzw; + ldv $v28, 0, 32, $at ## L:1287 | 177 | tm0:ufract = load(GL_MATRIX_TEXTURE, 0x20).xyzw; + ldv $v24, 0, 56, $at ## L:1291 | 178 | tm3:ufract = load(GL_MATRIX_TEXTURE, 0x38).xyzw; + ori $at, $zero, %lo(GL_STATE_TEX_SIZE) ## L:1293 | 179 | vec16 tex_size = load(GL_STATE_TEX_SIZE, 0).xy; + llv $v22, 0, 0, $at ## L:1293 | 180 | vec16 tex_size = load(GL_STATE_TEX_SIZE, 0).xy; + llv $v21, 0, 4, $at ## L:1294 | 181 | vec16 tex_offset = load(GL_STATE_TEX_SIZE, 4).xy; + ori $at, $zero, %lo(TEXTURE_MATRIX) ## L:1296 | 182 | store(tm0:sint.xyzw, TEXTURE_MATRIX, 0x00); + sdv $v27, 0, 0, $at ## L:1296 | *184 | store(tm0:sint.xyzw, TEXTURE_MATRIX, 0x00); + sdv $v25, 0, 8, $at ## L:1298 | 185 | store(tm1:sint.xyzw, TEXTURE_MATRIX, 0x08); + sdv $v23, 0, 16, $at ## L:1300 | 186 | store(tm3:sint.xyzw, TEXTURE_MATRIX, 0x10); + sdv $v24, 0, 40, $at ## L:1301 | 187 | store(tm3:ufract.xyzw, TEXTURE_MATRIX, 0x28); + sdv $v26, 0, 32, $at ## L:1299 | 188 | store(tm1:ufract.xyzw, TEXTURE_MATRIX, 0x20); + sdv $v28, 0, 24, $at ## L:1297 | 189 | store(tm0:ufract.xyzw, TEXTURE_MATRIX, 0x18); + ori $at, $zero, %lo(GL_STATE_TEX_SIZE) ## L:1303 | 190 | vec16 tex_size = load(GL_STATE_TEX_SIZE, 0).xy; + llv $v20, 0, 0, $at ## L:1303 | 191 | vec16 tex_size = load(GL_STATE_TEX_SIZE, 0).xy; + vmudn $v20, $v20, $v30.e1 ## L:1306 | ***195 | tex_size = tex_size << 6; + llv $v19, 0, 4, $at ## L:1304 | ^ | vec16 tex_offset = load(GL_STATE_TEX_SIZE, 4).xy; + ori $at, $zero, %lo(TEXTURE_SIZE) ## L:1308 | 196 | store(tex_size.xy, TEXTURE_SIZE); + or $s7, $zero, $zero ## L:1314 | 197 | u32 color_constant = 0; + slv $v20, 0, 0, $at ## L:1308 | *199 | store(tex_size.xy, TEXTURE_SIZE); + ori $at, $zero, %lo(TEXTURE_OFFSET) ## L:1309 | 200 | store(tex_offset.xy, TEXTURE_OFFSET); + bne $a1, $zero, LABEL_GLCmd_PreInitMagma_000B ## L:1315 | 201 | if (client_flags == 0) { + slv $v19, 0, 0, $at ## L:1309 | *203 | store(tex_offset.xy, TEXTURE_OFFSET); + addiu $s7, $zero, 1 ## L:1316 | 204 | color_constant = 1; + LABEL_GLCmd_PreInitMagma_000B: + or $s4, $zero, $zero ## L:1326 | 205 | u16 color_material = 0; + andi $s3, $k0, 1024 ## L:1328 | 206 | u32 enabled = flags & 0x400; + or $s5, $zero, $zero ## L:1324 | 207 | u8 point_count = 0; + beq $s3, $zero, LABEL_GLCmd_PreInitMagma_000C ## L:1329 | 208 | if (enabled != 0) + or $s6, $zero, $zero ## L:1323 | *210 | u8 light_count = 0; + ori $at, $zero, %lo(GL_STATE_LIGHT_AMBIENT) ## L:1331 | 211 | light_ambient.xyzw = load(GL_STATE_LIGHT_AMBIENT, 0); + lqv $v28, 0, 0, $at ## L:1331 | 212 | light_ambient.xyzw = load(GL_STATE_LIGHT_AMBIENT, 0); + ori $at, $zero, %lo(GL_MAT_AMBIENT) ## L:1332 | 213 | ambient.xyzw = load(GL_MAT_AMBIENT, 0); + lqv $v27, 0, 0, $at ## L:1332 | 214 | ambient.xyzw = load(GL_MAT_AMBIENT, 0); + ori $at, $zero, %lo(GL_MAT_DIFFUSE) ## L:1333 | 215 | diffuse.xyzw = load(GL_MAT_DIFFUSE, 0); + andi $s2, $k0, 2048 ## L:1337 | 216 | u32 color_material_enabled = flags & 0x800; + lqv $v26, 0, 0, $at ## L:1333 | 217 | diffuse.xyzw = load(GL_MAT_DIFFUSE, 0); + ori $at, $zero, %lo(GL_MAT_EMISSIVE) ## L:1334 | 218 | emissive.xyzw = load(GL_MAT_EMISSIVE, 0); + beq $s2, $zero, LABEL_GLCmd_PreInitMagma_000E ## L:1338 | 219 | if (color_material_enabled != 0) { + lqv $v25, 0, 0, $at ## L:1334 | *221 | emissive.xyzw = load(GL_MAT_EMISSIVE, 0); + bne $a1, $zero, LABEL_GLCmd_PreInitMagma_000E ## L:1340 | 222 | if (client_flags == 0) { + lhu $s4, %lo(GL_MAT_COLOR_TARGET + 0) ## L:1339 | *224 | color_material = load(GL_MAT_COLOR_TARGET); + ori $at, $zero, %lo(GL_CUR_COLOR) ## L:1341 | 225 | vec16 color = load(GL_CUR_COLOR).xyzw; + ldv $v23, 0, 0, $at ## L:1341 | 226 | vec16 color = load(GL_CUR_COLOR).xyzw; + andi $s1, $s4, 1 ## L:1342 | 227 | u16 tmp = color_material & 0x1; + beq $s1, $zero, LABEL_GLCmd_PreInitMagma_0010 ## L:1343 | 228 | if (tmp != 0) { + nop ## L:1343 | *230 | if (tmp != 0) { + vor $v26, $v00, $v23 ## L:1344 | 231 | diffuse = color; + LABEL_GLCmd_PreInitMagma_0010: + andi $s1, $s4, 2 ## L:1346 | ^ | tmp = color_material & 0x2; + beq $s1, $zero, LABEL_GLCmd_PreInitMagma_0011 ## L:1347 | 232 | if (tmp != 0) { + nop ## L:1347 | *234 | if (tmp != 0) { + vor $v27, $v00, $v23 ## L:1348 | 235 | ambient = color; + LABEL_GLCmd_PreInitMagma_0011: + andi $s1, $s4, 4 ## L:1350 | ^ | tmp = color_material & 0x4; + beq $s1, $zero, LABEL_GLCmd_PreInitMagma_0012 ## L:1351 | 236 | if (tmp != 0) { + nop ## L:1351 | *238 | if (tmp != 0) { + vor $v25, $v00, $v23 ## L:1352 | 239 | emissive = color; + LABEL_GLCmd_PreInitMagma_0012: + or $s4, $zero, $zero ## L:1355 | ^ | color_material = 0; + LABEL_GLCmd_PreInitMagma_000E: + ori $fp, $zero, %lo(GL_TEX_GEN) ## L:1361 | 240 | u16 light_end = GL_TEX_GEN; + ori $sp, $zero, %lo(LIGHTING_LIGHTS) ## L:1362 | 241 | u16 out_ptr = LIGHTING_LIGHTS; + ori $s0, $zero, %lo(GL_LIGHTS) ## L:1360 | 242 | u16 light_ptr = GL_LIGHTS; + lui $s1, 0x10 ## L:1359 | 243 | u32 light_flag = 0x100000; + LABEL_GLCmd_PreInitMagma_0013: + sltu $at, $s0, $fp ## L:1363 | 244 | while (light_ptr < light_end) + beq $at, $zero, LABEL_GLCmd_PreInitMagma_0014 ## L:1363 | 245 | while (light_ptr < light_end) + nop ## L:1363 | *247 | while (light_ptr < light_end) + and $k1, $k0, $s1 ## L:1365 | 248 | u32 light_enabled = flags & light_flag; + beq $k1, $zero, LABEL_GLCmd_PreInitMagma_0015 ## L:1366 | 249 | if (light_enabled != 0) { + nop ## L:1366 | *251 | if (light_enabled != 0) { + lh $t9, 6($s0) ## L:1375 | 252 | s16 w = load(light_ptr, 6); + lqv $v22, 0, 16, $s0 ## L:1368 | 253 | vec16 light_props1 = load(light_ptr, 0x10); + lqv $v23, 0, 0, $s0 ## L:1367 | 254 | vec16 light_props0 = load(light_ptr, 0x00); + sdv $v22, 8, 24, $sp ## L:1373 | **257 | store(light_props1.XYZW, out_ptr, 0x18); + sdv $v23, 0, 0, $sp ## L:1370 | 258 | store(light_props0.xyzw, out_ptr, 0x00); + sdv $v23, 8, 8, $sp ## L:1371 | 259 | store(light_props0.XYZW, out_ptr, 0x08); + beq $t9, $zero, LABEL_GLCmd_PreInitMagma_0016 ## L:1376 | 260 | if (w != 0) { + sdv $v22, 0, 16, $sp ## L:1372 | *262 | store(light_props1.xyzw, out_ptr, 0x10); + addiu $s5, $s5, 1 ## L:1377 | 263 | point_count += 1; + LABEL_GLCmd_PreInitMagma_0016: + addiu $sp, $sp, 32 ## L:1381 | 264 | out_ptr += 32; + addiu $s6, $s6, 1 ## L:1380 | 265 | light_count += 1; + LABEL_GLCmd_PreInitMagma_0015: + addiu $s0, $s0, 32 ## L:1383 | 266 | light_ptr += 32; + j LABEL_GLCmd_PreInitMagma_0013 ## L:1384 | 267 | light_flag = light_flag << 1; + sll $s1, $s1, 1 ## L:1384 | *269 | light_flag = light_flag << 1; + LABEL_GLCmd_PreInitMagma_0014: + beq $zero, $zero, LABEL_GLCmd_PreInitMagma_000D ## L:1384 | 270 | light_flag = light_flag << 1; + nop ## L:1384 | *272 | light_flag = light_flag << 1; + LABEL_GLCmd_PreInitMagma_000C: + vor $v25, $v00, $v00 ## L:1387 | 273 | emissive = VZERO; + addiu $at, $zero, 32767 ## L:1388 | ^ | light_ambient.x = 0x7FFF; + mtc2 $at, $v28.e0 ## L:1388 | 274 | light_ambient.x = 0x7FFF; + beq $a1, $zero, LABEL_GLCmd_PreInitMagma_0017 ## L:1391 | 275 | if (client_flags != 0) { + vor $v28, $v00, $v28.e0 ## L:1389 | ***279 | light_ambient = light_ambient.x; + beq $zero, $zero, LABEL_GLCmd_PreInitMagma_000D ## L:1392 | 280 | color_material = 0x1 | 0x2; + addiu $s4, $zero, 3 ## L:1392 | *282 | color_material = 0x1 | 0x2; + LABEL_GLCmd_PreInitMagma_0017: + ori $at, $zero, %lo(GL_CUR_COLOR) ## L:1394 | 283 | ambient = load(GL_CUR_COLOR).xyzw; + ldv $v27, 0, 0, $at ## L:1394 | 284 | ambient = load(GL_CUR_COLOR).xyzw; + vor $v26, $v00, $v27 ## L:1395 | ***288 | diffuse = ambient; + LABEL_GLCmd_PreInitMagma_000D: + ori $at, $zero, %lo(LIGHTING_AMBIENT) ## L:1399 | ^ | @Barrier("store_lighting") store(light_ambient.xyzw, LIGHTING_AMBIENT, 0); ## Barrier: 0x1 + sdv $v28, 0, 0, $at ## L:1399 | 289 | @Barrier("store_lighting") store(light_ambient.xyzw, LIGHTING_AMBIENT, 0); ## Barrier: 0x1 + sb $s5, %lo(0 + LIGHTING_HAS_POINTS)($zero) ## L:1400 | 290 | @Barrier("store_lighting") store(point_count, LIGHTING_HAS_POINTS, 0); ## Barrier: 0x1 + sb $s6, %lo(0 + LIGHTING_COUNT)($zero) ## L:1401 | 291 | @Barrier("store_lighting") store(light_count, LIGHTING_COUNT, 0); ## Barrier: 0x1 + ori $at, $zero, %lo(MATERIAL_DIFFUSE) ## L:1402 | 292 | @Barrier("store_lighting") store(diffuse.xyzw, MATERIAL_DIFFUSE, 0); ## Barrier: 0x1 + sdv $v26, 0, 0, $at ## L:1402 | 293 | @Barrier("store_lighting") store(diffuse.xyzw, MATERIAL_DIFFUSE, 0); ## Barrier: 0x1 + ori $at, $zero, %lo(MATERIAL_AMBIENT) ## L:1403 | 294 | @Barrier("store_lighting") store(ambient.xyzw, MATERIAL_AMBIENT, 0); ## Barrier: 0x1 + sdv $v27, 0, 0, $at ## L:1403 | 295 | @Barrier("store_lighting") store(ambient.xyzw, MATERIAL_AMBIENT, 0); ## Barrier: 0x1 + sh $s4, %lo(0 + MATERIAL_FLAGS)($zero) ## L:1404 | 296 | @Barrier("store_lighting") store(color_material, MATERIAL_FLAGS, 0); ## Barrier: 0x1 + ori $at, $zero, %lo(MATERIAL_EMISSIVE) ## L:1405 | 297 | @Barrier("store_lighting") store(emissive.xyzw, MATERIAL_EMISSIVE, 0); ## Barrier: 0x1 + sdv $v25, 0, 0, $at ## L:1405 | 298 | @Barrier("store_lighting") store(emissive.xyzw, MATERIAL_EMISSIVE, 0); ## Barrier: 0x1 + ori $at, $zero, %lo(GL_STATE_FOG_PARAMS) ## L:1410 | 299 | vec32 fog_parms = load(GL_STATE_FOG_PARAMS, 0).xy; + llv $v27, 0, 0, $at ## L:1410 | 300 | vec32 fog_parms = load(GL_STATE_FOG_PARAMS, 0).xy; + llv $v28, 0, 4, $at ## L:1410 | 301 | vec32 fog_parms = load(GL_STATE_FOG_PARAMS, 0).xy; + vsubc $v26, $v28, $v28.e0 ## L:1411 | ***305 | vec32 diff = fog_parms - fog_parms.x; + vsub $v25, $v27, $v27.e0 ## L:1411 | 306 | vec32 diff = fog_parms - fog_parms.x; + vrcph $v23.e0, $v25.e1 ## L:1413 | ***310 | factor.x = invert_half(diff).y; + vrcpl $v24.e0, $v26.e1 ## L:1413 | 311 | factor.x = invert_half(diff).y; + vrcph $v23.e0, $v00.e1 ## L:1413 | 312 | factor.x = invert_half(diff).y; + vmudl $v22, $v24, $v31.e4 ## L:1414 | **315 | vec16 factor_f = factor << 11; + vmadn $v22, $v23, $v31.e4 ## L:1414 | 316 | vec16 factor_f = factor << 11; + vsubc $v21, $v00, $v28.e0 ## L:1415 | 317 | vec32 offset = VZERO - fog_parms.x; + andi $s7, $k0, 8 ## L:1418 | ^ | u32 enabled = flags & 0x8; + vsub $v20, $v00, $v27.e0 ## L:1415 | 318 | vec32 offset = VZERO - fog_parms.x; + vmudl $v29, $v21, $v30.e2 ## L:1416 | **321 | offset = offset << 5; + addiu $s6, $zero, 119 ## L:1419 | ^ | u8 mask = 0x77; + vmadn $v20, $v20, $v30.e2 ## L:1416 | 322 | offset = offset << 5; + bne $s7, $zero, LABEL_GLCmd_PreInitMagma_0019 ## L:1420 | ^ | if (enabled == 0) { + vmudn $v21, $v21, $v30.e2 ## L:1416 | *324 | offset = offset << 5; + addiu $s6, $zero, 255 ## L:1421 | 325 | mask = 0xFF; + LABEL_GLCmd_PreInitMagma_0019: + ori $at, $zero, %lo(FOG_PARAMS) ## L:1424 | 326 | store(offset:sint.x, FOG_PARAMS, 0x0); + ssv $v20, 0, 0, $at ## L:1424 | 327 | store(offset:sint.x, FOG_PARAMS, 0x0); + ssv $v21, 0, 2, $at ## L:1425 | 328 | store(offset:ufract.x, FOG_PARAMS, 0x2); + ssv $v22, 0, 4, $at ## L:1426 | 329 | store(factor_f.x, FOG_PARAMS, 0x4); + jal DmaMagmaState ## L:1430 | 330 | DmaMagmaState(); + sb $s6, %lo(0 + FOG_MASK)($zero) ## L:1427 | *332 | store(mask, FOG_MASK, 0); + j RSPQ_Loop ## L:1431 | 333 | } + nop ## L:1431 | *335 | } + +GLCmd_PreInitMagma_end: + +#define zero $0 +#define v0 $2 +#define v1 $3 +#define a0 $4 +#define a1 $5 +#define a2 $6 +#define a3 $7 +#define t0 $8 +#define t1 $9 +#define t2 $10 +#define t3 $11 +#define t4 $12 +#define t5 $13 +#define t6 $14 +#define t7 $15 +#define s0 $16 +#define s1 $17 +#define s2 $18 +#define s3 $19 +#define s4 $20 +#define s5 $21 +#define s6 $22 +#define s7 $23 +#define t8 $24 +#define t9 $25 +#define k0 $26 +#define k1 $27 +#define gp $28 +#define sp $29 +#define fp $30 +#define ra $31 + +.set at +.set macro + +DmaMagmaState: + li t0, MG_STATE_STAGING_END - MG_STATE_STAGING + addi t0, 0x7 + andi t0, 0xFFF8 + addi t0, -1 + li s4, %lo(MG_STATE_STAGING) + j DMAOut + move s0, a0 + +#include "rsp_gl_common.inc" +#include diff --git a/src/GL/rsp_gl2.rspl b/src/GL/rsp_gl2.rspl new file mode 100644 index 0000000000..b338726f84 --- /dev/null +++ b/src/GL/rsp_gl2.rspl @@ -0,0 +1,411 @@ +#include "../../include/magma_constants.h" +#include "gl_constants.h" +#include "../../include/GL/gl_enums.h" + +state { + extern vec16 GL_MATRIX_MODELVIEW[4]; + extern vec16 GL_MATRIX_PROJECTION[4]; + extern vec16 GL_MATRIX_TEXTURE[4]; + extern vec16 GL_MATRIX_PALETTE[4]; + extern u32 GL_PALETTE_PTR; + extern u32 GL_STATE_PALETTE_INDEX; + extern u8 GL_LIGHTS; + extern u8 GL_TEX_GEN; + extern u16 GL_VIEWPORT_SCALE[4]; + extern u8 GL_PIPELINES; + extern s16 GL_STATE_LIGHT_AMBIENT[4]; + extern s16 GL_MAT_AMBIENT[4]; + extern s16 GL_MAT_DIFFUSE[4]; + extern s16 GL_MAT_EMISSIVE[4]; + extern u16 GL_MAT_COLOR_TARGET; + extern u32 GL_STATE_FLAGS; + extern u16 GL_STATE_FOG_PARAMS[4]; + extern s16 GL_STATE_TEX_SIZE[2]; + extern s16 GL_STATE_TEX_OFFSET[2]; + extern s16 GL_CUR_COLOR[4]; + extern u8 GL_CUR_MTX_INDEX; + extern u16 GL_TRI_CMD; + extern u8 GL_TRI_CULL; +} + +temp_state { + extern u8 MG_STATE_STAGING; + extern u8 MG_STATE_STAGING_END; + + u16 MG_VIEWPORT[8]; + u16 MG_CLIP_FACTORS[4]; + u16 MG_VERTEX_SIZE[4]; + u32 MG_SHADER_TEXT; + u32 MG_SHADER_TEXT_SIZE; + u32 MG_VERTEX_BUFFER; + u16 MG_TRI_CMD; + u8 MG_CULL_MODE; + u8 MG_OUTPUT_OFFSET; + + vec16 MATRICES_MVP[4]; + vec16 MATRICES_MV[4]; + vec16 MATRICES_NORMAL[2]; + + vec16 TEXTURE_MATRIX[3]; + s16 TEXTURE_SIZE[2]; + s16 TEXTURE_OFFSET[2]; + + u8 LIGHTING_LIGHTS[GLP_LIGHT_SIZE][LIGHT_COUNT]; + s16 LIGHTING_AMBIENT[3]; + u8 LIGHTING_HAS_POINTS; + u8 LIGHTING_COUNT; + s16 MATERIAL_DIFFUSE[4]; + s16 MATERIAL_AMBIENT[3]; + u16 MATERIAL_FLAGS; + s16 MATERIAL_EMISSIVE[3]; + + s16 FOG_PARAMS[3]; + u8 FOG_MASK; +} + +function DmaMagmaState(); +function GL_MtxMult(); + +macro MakeNormalMatrix(vec32 m0, vec32 m1) +{ + // TODO: transpose inverse + + // Multiply by 0x7FFF to convert to s0.15 with proper saturation + vec16 c; + c.x = 0x7FFF; + m0 = m0 * c.x; + m1 = m1 * c.x; + + store(m0:sint, MATRICES_NORMAL, 0x00); + store(m1:sint, MATRICES_NORMAL, 0x10); +} + +command<8> GLCmd_PreInitMagma(u32 statePtr, u32 client_flags) +{ + u32<$k0> flags = load(GL_STATE_FLAGS, 0); + + // Pipeline + { + u32 features = 0; + + u32 env_mask = 0x30000000; // FLAG_TEX_GEN_S | FLAG_TEX_GEN_T + u32 tmp = flags & env_mask; + if (tmp == env_mask) + { + u16 sphere_map = GL_SPHERE_MAP; + u16 mode_s = load(GL_TEX_GEN, TEX_GEN_MODE_OFFSET); + u16 mode_t = load(GL_TEX_GEN, TEX_GEN_MODE_T_OFFSET); + if (mode_s == sphere_map) + { + if (mode_t == sphere_map) + { + features |= 1; + } + } + } + + u32 normalize_enabled = flags & 0x1000; // FLAG_NORMALIZE + if (normalize_enabled != 0) + { + features |= 2; + } + + features = features << 3; + + vec16 pipeline = load(features, GL_PIPELINES).xyzw; + store(pipeline.xyzw, MG_SHADER_TEXT); + } + + // Viewport + { + vec16 viewport = load(GL_VIEWPORT_SCALE, 0); + store(viewport, MG_VIEWPORT, 0); + } + + // W normalization factor + { + // Check m[2][3] == 0 + s16 m23i = load(GL_MATRIX_PROJECTION, 0x16); + u16 m23f = load(GL_MATRIX_PROJECTION, 0x36); + u16 m23 = m23i | m23f; + if (m23 == 0) + { + // If so, the projection matrix is not a perspective, so we set the + // normalization factor to 1 + u16 norm_factor = 0xFFFF; // 1 as 0.16 + store(norm_factor, MG_VIEWPORT, 0x6); + } + else + { + /* + If it is not zero, then the projection matrix is a perspective + The normalization factor is defined as: + + factor = 2 / (near_plane + far_plane) + + That means we need to extract the Z-planes from the projection matrix, like so: + + near_plane = m[3][2] / (m[2][2] - 1) + far_plane = m[3][2] / (m[2][2] + 1) + + If we substitute these in the first equation and simplify, we get: + + factor = (m[2][2]*m[2][2] - 1) / (m[3][2]*m[2][2]) + */ + + // m20 | m21 | m22 | m23 | m30 | m31 | m32 | m33 + vec32 m; + m:sint = load(GL_MATRIX_PROJECTION, 0x10); + m:ufract = load(GL_MATRIX_PROJECTION, 0x30); + + // Get m22^2 and m32*m22 + vec32 a = m * m.z; + // m22^2 - 1 + vec32 b = a - 1; + // 1 / 2*m32*m22 + a.x = invert_half(a).Z; + // (m22^2 - 1) / m32*m22 + a *= b.z; + a *= 2; + + store(a:sfract.x, MG_VIEWPORT, 0x6); + } + } + + // Geometry flags + { + u16 tri_cmd = load(GL_TRI_CMD, 0); + store(tri_cmd, MG_TRI_CMD, 0); + } + + // Cull mode + { + u8 cull = load(GL_TRI_CULL, 0); + store(cull, MG_CULL_MODE, 0); + } + + // Matrices + { + u32<$s0> rdram_ptr; + u16<$s4> dmem_ptr; + u16<$s5> mtx_lhs; + u16<$s6> mtx_rhs; + u16<$s7> mtx_dst; + + mtx_lhs = GL_MATRIX_PROJECTION; + mtx_dst = MATRICES_MVP; + + u32 palette_enabled = flags & 0x4000; // FLAG_MATRIX_PALETTE + if (palette_enabled != 0) + { + u32 palette_index = load(GL_STATE_PALETTE_INDEX); + rdram_ptr = load(GL_PALETTE_PTR); + rdram_ptr += palette_index; + dmem_ptr = GL_MATRIX_PALETTE; + dma_out_async(dmem_ptr, rdram_ptr, MATRIX_SIZE); + + mtx_rhs = MATRICES_MV; + + dmem_ptr = MATRICES_MVP; + rdram_ptr = load(GL_PALETTE_PTR); + u16 i = 0; + while (i < MATRIX_PALETTE_SIZE) { + dma_in(dmem_ptr, rdram_ptr, MATRICES_SIZE); + + vec32 m0; + vec32 m1; + m0:sint = load(MATRICES_MV, 0x00); + m1:sint = load(MATRICES_MV, 0x10); + m0:ufract = load(MATRICES_MV, 0x20); + m1:ufract = load(MATRICES_MV, 0x30); + + MakeNormalMatrix(m0, m1); + + // TODO: reuse modelview matrix already loaded into registers + GL_MtxMult(); + dma_out_async(dmem_ptr, rdram_ptr, MATRICES_SIZE); + rdram_ptr += MATRICES_SIZE; + i += 1; + } + + u8 cur_mtx_index = load(GL_CUR_MTX_INDEX); + u32 tmp = cur_mtx_index << 7; + palette_index = cur_mtx_index << 5; + palette_index += tmp; // cur_mtx_index * (128 + 32) + + rdram_ptr = load(GL_PALETTE_PTR); + rdram_ptr += palette_index; + dma_in(dmem_ptr, rdram_ptr, MATRICES_SIZE); + } + else + { + mtx_rhs = GL_MATRIX_MODELVIEW; + GL_MtxMult(); + + vec32 m0; + vec32 m1; + m0:sint = load(GL_MATRIX_MODELVIEW, 0x00); + m1:sint = load(GL_MATRIX_MODELVIEW, 0x10); + m0:ufract = load(GL_MATRIX_MODELVIEW, 0x20); + m1:ufract = load(GL_MATRIX_MODELVIEW, 0x30); + + store(m0:sint, MATRICES_MV, 0x00); + store(m1:sint, MATRICES_MV, 0x10); + store(m0:ufract, MATRICES_MV, 0x20); + store(m1:ufract, MATRICES_MV, 0x30); + + MakeNormalMatrix(m0, m1); + } + } + + // Texturing + { + vec32 tm0; + vec32 tm1; + vec32 tm3; + tm0:sint = load(GL_MATRIX_TEXTURE, 0x00).xyzw; + tm0:ufract = load(GL_MATRIX_TEXTURE, 0x20).xyzw; + tm1:sint = load(GL_MATRIX_TEXTURE, 0x08).xyzw; + tm1:ufract = load(GL_MATRIX_TEXTURE, 0x28).xyzw; + tm3:sint = load(GL_MATRIX_TEXTURE, 0x18).xyzw; + tm3:ufract = load(GL_MATRIX_TEXTURE, 0x38).xyzw; + + vec16 tex_size = load(GL_STATE_TEX_SIZE, 0).xy; + vec16 tex_offset = load(GL_STATE_TEX_SIZE, 4).xy; + + store(tm0:sint.xyzw, TEXTURE_MATRIX, 0x00); + store(tm0:ufract.xyzw, TEXTURE_MATRIX, 0x18); + store(tm1:sint.xyzw, TEXTURE_MATRIX, 0x08); + store(tm1:ufract.xyzw, TEXTURE_MATRIX, 0x20); + store(tm3:sint.xyzw, TEXTURE_MATRIX, 0x10); + store(tm3:ufract.xyzw, TEXTURE_MATRIX, 0x28); + + vec16 tex_size = load(GL_STATE_TEX_SIZE, 0).xy; + vec16 tex_offset = load(GL_STATE_TEX_SIZE, 4).xy; + + tex_size = tex_size << TEX_SIZE_SHIFT; + + store(tex_size.xy, TEXTURE_SIZE); + store(tex_offset.xy, TEXTURE_OFFSET); + } + + // Lighting + { + u32 color_constant = 0; + if (client_flags == 0) { + color_constant = 1; + } + + vec16 light_ambient; + vec16 ambient; + vec16 diffuse; + vec16 emissive; + u8 light_count = 0; + u8 point_count = 0; + + u16 color_material = 0; + + u32 enabled = flags & 0x400; // FLAG_LIGHTING + if (enabled != 0) + { + light_ambient.xyzw = load(GL_STATE_LIGHT_AMBIENT, 0); + ambient.xyzw = load(GL_MAT_AMBIENT, 0); + diffuse.xyzw = load(GL_MAT_DIFFUSE, 0); + emissive.xyzw = load(GL_MAT_EMISSIVE, 0); + + vec16 color; + u32 color_material_enabled = flags & 0x800; // FLAG_COLOR_MATERIAL; + if (color_material_enabled != 0) { + color_material = load(GL_MAT_COLOR_TARGET); + if (client_flags == 0) { + vec16 color = load(GL_CUR_COLOR).xyzw; + u16 tmp = color_material & GLP_MATERIAL_FLAG_DIFFUSE; + if (tmp != 0) { + diffuse = color; + } + tmp = color_material & GLP_MATERIAL_FLAG_AMBIENT; + if (tmp != 0) { + ambient = color; + } + tmp = color_material & GLP_MATERIAL_FLAG_EMISSIVE; + if (tmp != 0) { + emissive = color; + } + + color_material = 0; + } + } + + u32 light_flag = 0x100000; // FLAG_LIGHT0 + u16 light_ptr = GL_LIGHTS; + u16 light_end = GL_TEX_GEN; + u16 out_ptr = LIGHTING_LIGHTS; + while (light_ptr < light_end) + { + u32 light_enabled = flags & light_flag; + if (light_enabled != 0) { + vec16 light_props0 = load(light_ptr, 0x00); + vec16 light_props1 = load(light_ptr, 0x10); + + store(light_props0.xyzw, out_ptr, 0x00); + store(light_props0.XYZW, out_ptr, 0x08); + store(light_props1.xyzw, out_ptr, 0x10); + store(light_props1.XYZW, out_ptr, 0x18); + + s16 w = load(light_ptr, GLP_LIGHT_POSITIONW); + if (w != 0) { + point_count += 1; + } + + light_count += 1; + out_ptr += GLP_LIGHT_SIZE; + } + light_ptr += GLP_LIGHT_SIZE; + light_flag = light_flag << 1; + } + } else { + emissive = VZERO; + light_ambient.x = 0x7FFF; + light_ambient = light_ambient.x; + + if (client_flags != 0) { + color_material = GLP_MATERIAL_FLAG_DIFFUSE | GLP_MATERIAL_FLAG_AMBIENT; + } else { + ambient = load(GL_CUR_COLOR).xyzw; + diffuse = ambient; + } + } + + @Barrier("store_lighting") store(light_ambient.xyzw, LIGHTING_AMBIENT, 0); + @Barrier("store_lighting") store(point_count, LIGHTING_HAS_POINTS, 0); + @Barrier("store_lighting") store(light_count, LIGHTING_COUNT, 0); + @Barrier("store_lighting") store(diffuse.xyzw, MATERIAL_DIFFUSE, 0); + @Barrier("store_lighting") store(ambient.xyzw, MATERIAL_AMBIENT, 0); + @Barrier("store_lighting") store(color_material, MATERIAL_FLAGS, 0); + @Barrier("store_lighting") store(emissive.xyzw, MATERIAL_EMISSIVE, 0); + } + + // Fog + { + vec32 fog_parms = load(GL_STATE_FOG_PARAMS, 0).xy; + vec32 diff = fog_parms - fog_parms.x; + vec32 factor; + factor.x = invert_half(diff).y; + vec16 factor_f = factor << 11; + vec32 offset = VZERO - fog_parms.x; + offset = offset << GLP_VTX_POS_SHIFT; + + u32 enabled = flags & 0x8; // FLAG_FOG + u8 mask = 0x77; + if (enabled == 0) { + mask = 0xFF; + } + + store(offset:sint.x, FOG_PARAMS, 0x0); + store(offset:ufract.x, FOG_PARAMS, 0x2); + store(factor_f.x, FOG_PARAMS, 0x4); + store(mask, FOG_MASK, 0); + } + + DmaMagmaState(); +} \ No newline at end of file diff --git a/src/GL/rsp_gl_clipping.inc b/src/GL/rsp_gl_clipping.inc deleted file mode 100644 index 1c929ab09d..0000000000 --- a/src/GL/rsp_gl_clipping.inc +++ /dev/null @@ -1,379 +0,0 @@ -############################################################ -# rsp_gl_clipping.inc -# -# Authors: Giovanni Bajo -############################################################ - - .section .data.gl_clipping - - .align 4 -CLIP_PLANES: - .half 1, 0, 0, GUARD_BAND_FACTOR - .half 0, 1, 0, GUARD_BAND_FACTOR - .half 0, 0, 1, 1 - .half 1, 0, 0, -GUARD_BAND_FACTOR - .half 0, 1, 0, -GUARD_BAND_FACTOR - .half 0, 0, 1, -1 - - .section .bss.gl_clipping - -CLIP_CACHE: .dcb.b SCREEN_VTX_SIZE * CLIPPING_CACHE_SIZE -CLIP_CACHE_END: - -CLIP_LISTS: - CLIP_LIST0: .dcb.w CLIPPING_CACHE_SIZE - CLIP_LIST1: .dcb.w CLIPPING_CACHE_SIZE - - - .section .text.gl_clipping - - ################################################################ - # GL_ClipTriangle - # Clip a triangle against the view-frustum by using the Sutherland-Hodgman algorithm - # https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm - # Args: - # a1-a3 = Vertices - # t5 = OR'd clip flags of the triangle's vertices - # Returns: - # s1 = Pointer to list of output vertices - # s2 = Pointer to end of list - ################################################################ - .func GL_ClipTriangle -GL_ClipTriangle: - #define out_count v1 - #define clip_flags t5 - #define plane_flag t6 - #define in_count t7 - #define in_end t8 - #define in_list s0 - #define out_list s1 - #define plane s2 - #define intersection s3 - #define cur_ptr s4 - #define prev_ptr s5 - #define cur_vtx s6 - #define prev_vtx s7 - #define p0 k0 - #define p1 k1 - #define vtx1 a1 - #define vtx2 a2 - #define vtx3 a3 - - #define vplane $v01 - #define vint_f $v02 - #define vint_i $v03 - #define vdot_i $v04 - #define vdot_f $v05 - #define vdiff_i $v06 - #define vdiff_f $v07 - #define va_i $v08 - #define va_f $v09 - #define vpos_i $v10 - #define vpos_f $v11 - #define vattr0 $v12 - #define vattr1 $v13 - #define voff0 $v14 - #define voff1 $v15 - #define vcache0 $v16 - #define vcache1 $v17 - #define v__ $v29 - - move ra2, ra - - # Init in_list as empty - li in_list, %lo(CLIP_LIST0) - move in_count, zero - - # Put three original vertices in the out_list - # (So after the initial swap they will be in the in_list) - li out_list, %lo(CLIP_LIST1) - sh vtx1, 0(out_list) - sh vtx2, 2(out_list) - sh vtx3, 4(out_list) - li out_count, 3*2 - - li plane, %lo(CLIP_PLANES) - li plane_flag, 1 - - # Load cache offsets - li t0, %lo(CACHE_OFFSETS) - vxor voff1, voff1 - lqv voff0, 0,t0 - lsv voff1, 16,t0 - - # Temporarily use the RDP staging area as a map of which cache slots are used - # Init to zero - li t0, %lo(RDPQ_CMD_STAGING) - sqv vzero, 0,t0 - sqv vzero, 16,t0 - - # Iterate over the 6 clipping planes -gl_clip_plane_loop: - and t0, clip_flags, plane_flag - beqz t0, gl_clip_plane_loop_end - move t1, in_list - - # Swap in and out lists - - # If the out list is empty from the last iteration, - # the triangle has no visible points and we are done - beqz out_count, gl_clip_return - move in_list, out_list - move out_list, t1 - move in_count, out_count - move out_count, zero - - # Iterate over the egdes of the polygon in the input list - # The current edge is between cur_vtx and prev_vtx - move cur_ptr, in_list - add in_end, in_list, in_count - # Init the "previous" vertex to the last in the list for the wrap-around - addi prev_ptr, in_end, -2 - -gl_clip_edge_loop: - #define cur_flag t3 - #define prev_flag t4 - - # Check which side of the plane the two vertices are on - lhu cur_vtx, 0(cur_ptr) - lhu prev_vtx, 0(prev_ptr) - lbu cur_flag, SCREEN_VTX_CLIP_CODE(cur_vtx) - lbu prev_flag, SCREEN_VTX_CLIP_CODE(prev_vtx) - and cur_flag, plane_flag - and prev_flag, plane_flag - - # If they are on opposite sides, there is an intersection - xor t0, cur_flag, prev_flag - beqz t0, gl_clip_no_intersection - move p0, cur_vtx - - # Swap the two points if necessary to make intersection calculation consistent - # This will make sure p0 is always inside and p1 is always outside - bnez prev_flag, gl_clip_no_swap - move p1, prev_vtx - xor p0, p0, p1 - xor p1, p0, p1 - xor p0, p0, p1 - - #undef prev_flag - -gl_clip_no_swap: - # Calculate intersection of the line segment and the plane - - li t0, %lo(RDPQ_CMD_STAGING) - lqv vcache0, 0,t0 - lqv vcache1, 16,t0 - - # Repeat plane coefficients twice - ldv vplane.e0, 0,plane - ldv vplane.e4, 0,plane - - # vpos: x0 y0 z0 w0 x1 y1 z1 w1 - ldv vpos_i.e0, SCREEN_VTX_CS_POSi,p0 - ldv vpos_f.e0, SCREEN_VTX_CS_POSf,p0 - ldv vpos_i.e4, SCREEN_VTX_CS_POSi,p1 - ldv vpos_f.e4, SCREEN_VTX_CS_POSf,p1 - - # vint: x1 y1 z1 w1 - ldv vint_i.e0, SCREEN_VTX_CS_POSi,p1 - ldv vint_f.e0, SCREEN_VTX_CS_POSf,p1 - - # vattr0: r0 g0 b0 a0 s0 t0 - luv vattr0.e0, SCREEN_VTX_RGBA ,p0 - llv vattr0.e4, SCREEN_VTX_S ,p0 - - # vattr1: r1 g1 b1 a1 s1 t1 - luv vattr1.e0, SCREEN_VTX_RGBA ,p1 - llv vattr1.e4, SCREEN_VTX_S ,p1 - - # Find first free slot in clip cache - - # Add the values from the "used slots map" to the cache offsets - # After this, each lane will contain the offset of its corresponding cache slot, - # but only if the slot is not used. If it is used, it will contain some large value. - vaddc vcache0, voff0 - vaddc vcache1, voff1 - - # Look for the smallest value, which will end up in vcache.e0 - # Because used slots are marked as large values, they will never be found. - vlt vcache0, vcache0.q1 - vlt vcache0, vcache0.h2 - vlt vcache0, vcache0.e4 - vlt vcache0, vcache1.e0 - - mfc2 t0, vcache0.e0 - - # Mark slot as used by storing some large value (careful of overflows!) - li t1, 0xFF - sh t1, %lo(RDPQ_CMD_STAGING)-2(t0) - - # t0 is the index multiplied by 2 - # intersection = t0 * 20 = t0 * 16 + t0 * 4 - sll intersection, t0, 4 - sll t1, t0, 2 - add intersection, t1 - - # CAUTION: intersection might point to the same address as either p0 or p1, - # because one of them is the previous point, which could have been marked unused - # in the previous iteration. As long as we don't access p0 or p1 after writing to - # intersection, this is fine. - addi intersection, %lo(CLIP_CACHE) - SCREEN_VTX_SIZE - - # Store the cache offset in unused memory (used later when finding the cache slot to mark as unused) - sb t0, SCREEN_VTX_PADDING(intersection) - - # Compute dot products of both positions with the clip plane - # vdot.e0: d0 = dot(p0, plane) - # vdot.e4: d1 = dot(p1, plane) - vmudn vdot_f, vpos_f, vplane - vmadh vdot_i, vpos_i, vplane - vaddc vdot_f, vdot_f.q1 - vadd vdot_i, vdot_i.q1 - vaddc vdot_f, vdot_f.h2 - vadd vdot_i, vdot_i.h2 - - # d0 - d1 - vsubc vdiff_f, vdot_f, vdot_f.e4 - vsub vdiff_i, vdot_i, vdot_i.e4 - - # 1 / (d0 - d1) - vrcph v__.e0, vdiff_i.e0 - vrcpl va_f.e0, vdiff_f.e0 - vrcph va_i.e0, vzero.e0 - - # a = d0 / (d0 - d1) - vmudl v__, va_f, vdot_f.e0 - vmadm v__, va_i, vdot_f.e0 - vmadn va_f, va_f, vdot_i.e0 - - # Prepare 0x7FFF in va_i.e0 - vsubc va_i, vshift8, K1 - - # a = min(a, 1) - vge v__, va_f, vzero - vmrg va_f, va_f, va_i.e0 - - # Account for right shift introduced by vrcp - vmudn va_f, va_f, K2 - - # p1 - p0 - vsubc vint_f, vpos_f - vsub vint_i, vpos_i - # attr1 - attr0 - vsubc vattr1, vattr0 - - # Result of linear interpolation: - # p0 + a * (p1 - p0) - vmudl v__, vint_f, va_f.e0 - vmadm v__, vint_i, va_f.e0 - vmadn vint_f, vpos_f, K1 - vmadh vint_i, vpos_i, K1 - - # a * (attr1 - attr0) - vmudm vattr1, vattr1, va_f.e0 - - # attr0 + a * (attr1 - attr0) - vaddc vattr0, vattr1 - - # Store results - sdv vint_i.e0, SCREEN_VTX_CS_POSi,intersection - sdv vint_f.e0, SCREEN_VTX_CS_POSf,intersection - suv vattr0.e0, SCREEN_VTX_RGBA ,intersection - jal GL_CalcClipCodes - slv vattr0.e4, SCREEN_VTX_S ,intersection - - # Add intersection to the output list - add t0, out_list, out_count - sh intersection, 0(t0) - addi out_count, 2 - -gl_clip_no_intersection: - # If cur_vtx is inside, add it to the output list - bnez cur_flag, gl_clip_no_current - add t0, out_list, out_count - sh cur_vtx, 0(t0) - b gl_clip_edge_loop_end - addi out_count, 2 - - #undef cur_flag - -gl_clip_no_current: - # Check if the vertex is stored in the clip cache - lbu t0, SCREEN_VTX_PADDING(cur_vtx) - beqz t0, gl_clip_edge_loop_end - # Reset the padding field to zero, so the screen space values won't be recalculated below - sb zero, SCREEN_VTX_PADDING(cur_vtx) - # If so, mark it as unused - sh zero, %lo(RDPQ_CMD_STAGING)-2(t0) - -gl_clip_edge_loop_end: - # Advance to the next edge - addi cur_ptr, 2 - blt cur_ptr, in_end, gl_clip_edge_loop - addi prev_ptr, cur_ptr, -2 - -gl_clip_plane_loop_end: - # Advance to the next clipping plane - sll plane_flag, 1 - blt plane_flag, (1< -############################################################ - - .section .text.gl_lighting - - ################################################################ - # GL_VtxLighting - # Perform lighting for a single vertex - # Args: - # $v28 = Eye space position - # $v03 = Eye space normal - # $v04 = Vertex color RGBA - # Returns: - # $v04 = Calculated RGBA - ################################################################ - .func GL_VtxLighting -GL_VtxLighting: - #define v___ $v01 - #define veyepos $v28 - #define veyenormal $v03 - #define vcolor $v04 - #define vmemissive $v05 - #define vmambient $v06 - #define vmdiffuse $v07 - #define vldiffuse $v08 - #define vlout $v09 - #define vlightdir $v10 - #define vlightvec $v11 - #define vsqdist_f $v12 - #define vsqdist_i $v13 - #define vdist_f $v14 - #define vdist_i $v15 - #define vinvdist_f $v16 - #define vinvdist_i $v17 - #define vndl $v18 - #define vattenuation_f $v19 - #define vattenuation_i $v20 - #define venable $v21 - #define vlmambient $v22 - #define vcolortarget $v23 - - #define light_flags t9 - #define light s0 - #define light_end s1 - - #define r e0 - #define g e1 - #define b e2 - #define a e3 - - - li s0, %lo(GL_STATE_LIGHT_AMBIENT) - - vxor vlmambient, vlmambient - ldv vlmambient, 0x00,s0 - - # TODO: Prepare in DMEM? - ldv vmambient.e0, 0x08,s0 - ldv vmambient.e4, 0x08,s0 - ldv vmdiffuse.e0, 0x10,s0 - ldv vmdiffuse.e4, 0x10,s0 - - vxor vmemissive, vmemissive - ldv vmemissive, 0x20,s0 - - vxor vcolortarget, vcolortarget - ldv vcolortarget, 0x28,s0 - - lw light_flags, %lo(GL_STATE_FLAGS) - - # Initialize the third lane of vinvdist to 1.0 - vxor vinvdist_f, vinvdist_f - vmov vinvdist_i.e2, K1 - vmov vinvdist_i.e6, K1 - - andi t0, light_flags, FLAG_COLOR_MATERIAL - beqz t0, gl_light_color_target_disabled - veq v___, vzero, vcolortarget.e0 - vmrg vmambient, vcolor - veq v___, vzero, vcolortarget.e1 - vmrg vmdiffuse, vcolor - veq v___, vzero, vcolortarget.h2 - vmrg vmemissive, vcolor - -gl_light_color_target_disabled: - - li light, %lo(GL_LIGHTS) - addi light_end, light, LIGHT_ATTR_SIZE * LIGHT_COUNT - srl light_flags, LIGHT0_SHIFT - - vmulf vcolor, vlmambient, vmambient - vadd vcolor, vmemissive - -gl_light_loop: - andi t0, light_flags, 3 - beqz t0, gl_light_loop_end - andi t1, t0, 1 - andi t2, t0, 2 - - beqz t1, light0_disabled - mtc2 t1, venable.e0 - lh t1, LIGHT_POSITION_OFFSET+6(light) - -light0_disabled: - beqz t2, light1_disabled - mtc2 t2, venable.e4 - lh t2, LIGHT_POSITION_OFFSET+LIGHT_ATTR_SIZE+6(light) - -light1_disabled: - # If the light is directional, the light vector is simply a direction (pre-normalized on CPU) - lqv vlightdir, LIGHT_POSITION_OFFSET,light - lqv vlout, LIGHT_AMBIENT_OFFSET,light - add t1, t2 - beqz t1, gl_light_directional - lqv vldiffuse, LIGHT_DIFFUSE_OFFSET,light - - # Light is positional: We need to compute light vector, normalize it, and apply attenuation - - # Load attenuation coefficients k0, k1, k2 (constant, linear, quadratic) - # vattenuation: k0 k1 k2 -- -- -- -- -- - lqv vattenuation_i, LIGHT_ATTENUATION_INT_OFFSET,light - lqv vattenuation_f, LIGHT_ATTENUATION_FRAC_OFFSET,light - - # If light is positional, the light vector points from the vertex to the light position - # This is shifted left by 5 because both values are in s10.5 format - vsub vlightvec, vlightdir, veyepos - - # Dot product of light vector with itself - # Product is shifted left by 10 because two s10.5 values were multiplied, - # and then shifted right by 16 because of vsar. - # This means the result is shifted right by 6 - vmudh v___, vlightvec, vlightvec - vsar vsqdist_f, COP2_ACC_MD - vsar vsqdist_i, COP2_ACC_HI - vaddc vdist_f, vsqdist_f, vsqdist_f.h1 - vadd vdist_i, vsqdist_i, vsqdist_i.h1 - vaddc vsqdist_f, vdist_f, vsqdist_f.h2 - vadd vsqdist_i, vdist_i, vsqdist_i.h2 - - # Compute inverse distance (reciprocal square root) - # Result is shifted left by 10: - # - Taking the square root halves the bit-shift, and the reciprocal then inverts it. - # So the original (right) shift of -6 becomes -(-6/2) = 3 - # - vrsq additionally shifts left by 7 - # vinvdist: -- 1/d0 1.0 -- -- 1/d1 1.0 -- - vrsqh v___.e0, vsqdist_i.e0 - vrsql vinvdist_f.e1, vsqdist_f.e0 - vrsqh vinvdist_i.e1, vsqdist_i.e4 - vrsql vinvdist_f.e5, vsqdist_f.e4 - vrsqh vinvdist_i.e5, vzero.e0 - - # Get actual distance by multiplying the inverse with the squared distance: d^-1 * d^2 = d^(2-1) = d - # Because vinvdist.e2 is initialized to 1, the squared distance will be in vdist.e2 - # d is shifted left by 4, d^2 is still shifted right by 6 - # vdist: -- d0 d0^2 -- -- d1 d1^2 -- - vmudl v___, vinvdist_f, vsqdist_f.h0 - vmadm v___, vinvdist_i, vsqdist_f.h0 - vmadn vdist_f, vinvdist_f, vsqdist_i.h0 - vmadh vdist_i, vinvdist_i, vsqdist_i.h0 - - # Multiply with attenuation coefficients - # The coefficients are pre-shifted in such a way that all values end up being shifted right by 1, - # so the final result ends up non-shifted after the reciprocal below. - # - d is shifted left by 4, so k1 is pre-shifted right by 4 on CPU - # - d^2 is shifted right by 6, so k2 is pre-shifted left by 6 on CPU - # vdist: -- k1*d0 k2*d0^2 -- -- k1*d1 k2*d1^2 -- - vmudl v___, vdist_f, vattenuation_f - vmadm v___, vdist_i, vattenuation_f - vmadn vdist_f, vdist_f, vattenuation_i - vmadh vdist_i, vdist_i, vattenuation_i - - # Compute final attenuation factor - # Sum is shifted right by 1 - # k0 + k1*d + k2*d^2 - vaddc vattenuation_f, vdist_f.h1 - vadd vattenuation_i, vdist_i.h1 - vaddc vattenuation_f, vdist_f.h2 - vadd vattenuation_i, vdist_i.h2 - # Final factor is not shifted - # 1 / (k0 + k1*d + k2*d^2) - vrcph v___.e0, vattenuation_i.e0 - vrcpl vattenuation_f.e0, vattenuation_f.e0 - vrcph vattenuation_i.e0, vattenuation_i.e4 - vrcpl vattenuation_f.e4, vattenuation_f.e4 - vrcph vattenuation_i.e4, vzero.e0 - - # Normalize light vector by multiplying the reciprocal distance. - # Light vector is shifted left by 5 and inverse distance is shifted left by 10. - # This means the result is shifted left by 15, which makes the result in vlightdir a signed fraction. - # This happens to match perfectly so we can continue the following calculations without any adjustment. - vmudm v___, vlightvec, vinvdist_f.h1 - vmadh vlightvec, vlightvec, vinvdist_i.h1 - -gl_light_directional: - - vne v___, vzero, vlightdir.h3 - vmrg vlightdir, vlightvec, vlightdir - vmrg vattenuation_i, vattenuation_i, K1 - vmrg vattenuation_f, vattenuation_f, vzero - - # Dot product of light vector with vertex normal - # Both are a signed fraction, so we can just use vmulf - vmulf vndl, veyenormal, vlightdir - vadd v___, vndl, vndl.h1 - vadd vndl, v___, vndl.h2 - vge vndl, vzero - - # Compute diffuse light - vmulf vldiffuse, vndl.h0 - vmulf vldiffuse, vmdiffuse - - # Compute ambient light - vmulf vlout, vmambient - - vadd vlout, vldiffuse - - # If light is positional, apply attenuation factor - vmudm v___, vlout, vattenuation_f.h0 - vmadh vlout, vlout, vattenuation_i.h0 - - # Add final light to output (only those that are enabled) - vne v___, vzero, venable.h0 - vmrg vlout, vzero - vadd vcolor, vlout - -gl_light_loop_end: - addi light, LIGHT_ATTR_SIZE*2 - blt light, light_end, gl_light_loop - srl light_flags, 2 - - vmov v___.e0, vcolor.e4 - vmov v___.e1, vcolor.e5 - vmov v___.e2, vcolor.e6 - vadd vcolor, v___ - - jr ra - vmov vcolor.a, vmdiffuse.a - - #undef v___ - #undef veyepos - #undef veyenormal - #undef vcolor - #undef vmemissive - #undef vmambient - #undef vmdiffuse - #undef vldiffuse - #undef vlout - #undef vlightdir - #undef vlightvec - #undef vsqdist_f - #undef vsqdist_i - #undef vdist_f - #undef vdist_i - #undef vinvdist_f - #undef vinvdist_i - #undef vndl - #undef vattenuation_f - #undef vattenuation_i - #undef venable - #undef vlmambient - #undef vcolortarget - #undef light_flags - #undef light - #undef light_end - #undef r - #undef g - #undef b - #undef a - .endfunc \ No newline at end of file diff --git a/src/GL/rsp_gl_pipeline.S b/src/GL/rsp_gl_pipeline.S index 24cf7d878e..b6cd4e01d7 100644 --- a/src/GL/rsp_gl_pipeline.S +++ b/src/GL/rsp_gl_pipeline.S @@ -1,870 +1,740 @@ -############################################################ -# rsp_gl_pipeline.S -# -# Authors: Giovanni Bajo -# Dennis Heinze -############################################################ -#include -#include -#include "gl_constants.h" -#include "GL/gl_enums.h" - - .data - - RSPQ_BeginOverlayHeader - RSPQ_DefineCommand GLCmd_InitPipe, 4 - RSPQ_DefineCommand GLCmd_SetVtxLoader, 12 + VTX_LOADER_MAX_SIZE - RSPQ_DefineCommand GLCmd_SetVtxCmdSize, 8 - RSPQ_DefineCommand GLCmd_DrawTriangle, 8 - RSPQ_DefineCommand GLCmd_SetPrimVertex, 32 - RSPQ_DefineCommand GLCmd_SetByte, 8 - RSPQ_DefineCommand GLCmd_SetWord, 8 - RSPQ_DefineCommand GLCmd_SetLong, 12 - RSPQ_EndOverlayHeader - +## Auto-generated file, transpiled with RSPL +#define __MAGMA_CONSTANTS +#define MG_VERTEX_CACHE_COUNT 48 +#define MG_DEFAULT_GUARD_BAND 2 +#define MG_INLINE_UNIFORM_HEADER 12 +#define MG_MAX_UNIFORM_PAYLOAD_SIZE (RSPQ_MAX_COMMAND_SIZE*4 - 12) +#define MG_CLIP_PLANE_COUNT 6 +#define MG_CLIP_PLANE_SIZE 8 +#define MG_CLIP_CACHE_SIZE 9 +#define MG_VTX_XYZ 0 +#define MG_VTX_CLIP_CODE 6 +#define MG_VTX_TR_CODE 7 +#define MG_VTX_RGBA 8 +#define MG_VTX_ST 12 +#define MG_VTX_Wi 16 +#define MG_VTX_Wf 18 +#define MG_VTX_INVWi 20 +#define MG_VTX_INVWf 22 +#define MG_VTX_CS_POSi 24 +#define MG_VTX_CS_POSf 32 +#define MG_VTX_SIZE 40 +#define MG_VTX_SIZE2 80 +#define MG_MAX_UNIFORMS_SIZE 0x200 +#define __GL_CONSTANTS +#define __MGFX_CONSTANTS +#define MGFX_ATTRIBUTE_POSITION 0 +#define MGFX_ATTRIBUTE_NORMAL 1 +#define MGFX_ATTRIBUTE_COLOR 2 +#define MGFX_ATTRIBUTE_TEXCOORD 3 +#define MGFX_BINDING_MATRICES 0 +#define MGFX_BINDING_TEXTURING 1 +#define MGFX_BINDING_LIGHTING 2 +#define MGFX_BINDING_FOG 3 +#define MGFX_LIGHT_COUNT_MAX 8 +#define MGFX_LIGHT_POSITION 0 +#define MGFX_LIGHT_POSITIONW 6 +#define MGFX_LIGHT_COLOR 8 +#define MGFX_LIGHT_INTENSITY 14 +#define MGFX_LIGHT_SIZE 16 +#define MGFX_MATRIX_SIZE 64 +#define MGFX_VTX_TEX_SHIFT 5 +#define PIPELINE_FEATURE_COUNT 2 +#define PIPELINE_COUNT (1<<2) +#define MODELVIEW_STACK_SIZE 32 +#define PROJECTION_STACK_SIZE 2 +#define TEXTURE_STACK_SIZE 2 +#define PALETTE_STACK_SIZE 1 +#define VERTEX_UNIT_COUNT 1 +#define MATRIX_PALETTE_SIZE 32 +#define MATRICES_SIZE 160 +#define VERTEX_CACHE_SIZE 32 +#define CLIPPING_PLANE_COUNT 6 +#define CLIPPING_CACHE_SIZE 9 +#define CLIPPING_PLANE_SIZE 8 +#define MATRIX_SIZE 64 +#define TEX_COORD_COUNT 4 +#define TEX_GEN_COUNT 4 +#define TEX_GEN_PLANE_COUNT 2 +#define TEX_GEN_SIZE 34 +#define TEX_GEN_STRUCT_SIZE 144 +#define TEX_GEN_INTEGER_OFFSET 0 +#define TEX_GEN_FRACTION_OFFSET 64 +#define TEX_GEN_MODE_OFFSET 128 +#define TEX_GEN_MODE_T_OFFSET 130 +#define TEX_GEN_CONST_SIZE (4*2) +#define TEX_SIZE_SHIFT 6 +#define LIGHT_COUNT 8 +#define MAX_TEXTURE_SIZE 64 +#define MAX_TEXTURE_LEVELS 7 +#define TEXTURE_IMAGE_SIZE 6 +#define TEXTURE_OBJECT_PROPS_OFFSET (6 * 7) +#define TEXTURE_LEVELS_COUNT_OFFSET ((6 * 7) + 0) +#define TEXTURE_TLUT_MODE_OFFSET ((6 * 7) + 1) +#define TEXTURE_LEVELS_BLOCK_OFFSET ((6 * 7) + 2) +#define TEXTURE_FLAGS_OFFSET ((6 * 7) + 62) +#define TEXTURE_MIN_FILTER_OFFSET ((6 * 7) + 66) +#define TEXTURE_MAG_FILTER_OFFSET ((6 * 7) + 68) +#define TEXTURE_OBJECT_SIZE ((6 * 7) + 70) +#define IMAGE_WIDTH_OFFSET 0 +#define IMAGE_HEIGHT_OFFSET 2 +#define IMAGE_INTERNAL_FORMAT_OFFSET 4 +#define TEXTURE_BILINEAR_MASK 0x001 +#define TEXTURE_INTERPOLATE_MASK 0x002 +#define TEXTURE_MIPMAP_MASK 0x100 +#define MAX_PIXEL_MAP_SIZE 32 +#define ATTRIB_TYPE_COUNT 10 +#define FLAG_DITHER (1 << 0) +#define FLAG_BLEND (1 << 1) +#define FLAG_ALPHA_TEST (1 << 2) +#define FLAG_FOG (1 << 3) +#define FLAG_SCISSOR_TEST (1 << 4) +#define FLAG_TEXTURE_1D (1 << 5) +#define FLAG_TEXTURE_2D (1 << 6) +#define FLAG_CULL_FACE (1 << 7) +#define FLAG_LIGHTING (1 << 10) +#define FLAG_COLOR_MATERIAL (1 << 11) +#define FLAG_NORMALIZE (1 << 12) +#define FLAG_MATRIX_PALETTE (1 << 14) +#define FLAG_DEPTH_TEST (1 << 16) +#define FLAG_TEXTURE_ACTIVE (1 << 17) +#define FLAG_DEPTH_MASK (1 << 18) +#define FLAG_FINAL_MTX_DIRTY (1 << 19) +#define FLAG_LIGHT0 (1 << 20) +#define FLAG_LIGHT1 (1 << 21) +#define FLAG_LIGHT2 (1 << 22) +#define FLAG_LIGHT3 (1 << 23) +#define FLAG_LIGHT4 (1 << 24) +#define FLAG_LIGHT5 (1 << 25) +#define FLAG_LIGHT6 (1 << 26) +#define FLAG_LIGHT7 (1 << 27) +#define FLAG_TEX_GEN_S (1 << 28) +#define FLAG_TEX_GEN_T (1 << 29) +#define FLAG_TEX_GEN_R (1 << 30) +#define FLAG_TEX_GEN_Q (1 << 31) +#define FLAG2_USE_RDPQ_MATERIAL (1 << 0) +#define FLAG2_USE_RDPQ_TEXTURING (1 << 1) +#define FLAG2_REDUCED_ALIASING (1 << 2) +#define FLAG2_MULTISAMPLE (1 << 3) +#define FLAG2_TEX_FLIP_T (1 << 4) +#define CLIENT_FLAG_BEGIN_END (1 << 0) +#define CLIENT_FLAG_COLOR_ARRAY (1 << 1) +#define TEX_FLAG_COMPLETE (1 << 0) +#define TEX_FLAG_UPLOAD_DIRTY (1 << 1) +#define TEX_FLAG_FORCE_COMPLETE (1 << 2) +#define TEX_FLAG_DETAIL (1 << 3) +#define DITHER_MASK (SOM_RGBDITHER_MASK | SOM_ALPHADITHER_MASK) +#define BLEND_MASK SOM_ZMODE_MASK +#define DEPTH_TEST_MASK SOM_Z_COMPARE +#define DEPTH_MASK_MASK SOM_Z_WRITE +#define POINTS_MASK (SOM_ZSOURCE_MASK | SOM_TEXTURE_PERSP) +#define ALPHA_TEST_MASK SOM_ALPHACOMPARE_MASK +#define LOAD_TILE 7 +#define GUARD_BAND_FACTOR 2 +#define MULTISAMPLE_FLAG_SHIFT 2 +#define ZMODE_BLEND_FLAG_SHIFT 10 +#define COMBINER_FLAG_CONSTANT (1 << 0) +#define COMBINER_FLAG_REPLACE (1 << 1) +#define COMBINER_FLAG_TEXTURE (1 << 2) +#define TEXTURE_ACTIVE_SHIFT 17 +#define TEX_ACTIVE_COMBINER_SHIFT (17 - 2) +#define TEX_COORD_SHIFT 3 +#define HALF_TEXEL 0x0010 +#define TEX_BILINEAR_SHIFT 13 +#define TEX_BILINEAR_OFFSET_SHIFT 4 +#define TEX_DETAIL_SHIFT 15 +#define BILINEAR_TEX_OFFSET_SHIFT 9 +#define TRICMD_ATTR_SHIFT 8 +#define TRICMD_ATTR_MASK 0x300 +#define LIGHT0_SHIFT 20 +#define TEX_GEN_S_SHIFT 28 +#define TEX_GEN_LINEAR_FLAG_SHIFT 8 +#define TEX_GEN_SPHERICAL_FLAG_SHIFT 9 +#define NEED_EYE_SPACE_SHIFT 13 +#define RDPQ_TEXTURING_MASK ((SOM_SAMPLE_MASK | SOM_TEXTURE_LOD | SOMX_LOD_INTERPOLATE | SOMX_NUMLODS_MASK | SOM_TLUT_MASK)>>32) +#define PALETTE_MATRIX_INDEX 3 +#define PALETTE_DIRTY_FLAGS_SIZE ((32+7)>>3) +#define GLP_LIGHT_POSITION 0 +#define GLP_LIGHT_POSITIONW 6 +#define GLP_LIGHT_DIFFUSE 8 +#define GLP_LIGHT_AMBIENT 14 +#define GLP_LIGHT_ATT_INT 20 +#define GLP_LIGHT_ATT_FRAC 26 +#define GLP_LIGHT_SIZE 32 +#define GLP_ATTRIBUTE_POSITION 0 +#define GLP_ATTRIBUTE_NORMAL 1 +#define GLP_ATTRIBUTE_COLOR 2 +#define GLP_ATTRIBUTE_TEXCOORD 3 +#define GLP_BINDING_MATRICES 0 +#define GLP_BINDING_TEXTURING 1 +#define GLP_BINDING_LIGHTING 2 +#define GLP_BINDING_FOG 3 +#define GLP_VTX_POS_SHIFT 5 +#define GLP_VTX_TEX_SHIFT 8 +#define GLP_MATERIAL_FLAG_DIFFUSE 0x1 +#define GLP_MATERIAL_FLAG_AMBIENT 0x2 +#define GLP_MATERIAL_FLAG_EMISSIVE 0x4 +#define SCRATCH_MAT_DIFFUSE 0x30 +#define SCRATCH_MAT_AMBIENT 0x40 +#define SCRATCH_MAT_EMISSIVE 0x50 +#define SCRATCH_RGBA_IN 0x60 +#include + +.set noreorder +.set noat +.set nomacro + +#undef zero +#undef at +#undef v0 +#undef v1 +#undef a0 +#undef a1 +#undef a2 +#undef a3 +#undef t0 +#undef t1 +#undef t2 +#undef t3 +#undef t4 +#undef t5 +#undef t6 +#undef t7 +#undef s0 +#undef s1 +#undef s2 +#undef s3 +#undef s4 +#undef s5 +#undef s6 +#undef s7 +#undef t8 +#undef t9 +#undef k0 +#undef k1 +#undef gp +#undef sp +#undef fp +#undef ra +.equ hex.$zero, 0 +.equ hex.$at, 1 +.equ hex.$v0, 2 +.equ hex.$v1, 3 +.equ hex.$a0, 4 +.equ hex.$a1, 5 +.equ hex.$a2, 6 +.equ hex.$a3, 7 +.equ hex.$t0, 8 +.equ hex.$t1, 9 +.equ hex.$t2, 10 +.equ hex.$t3, 11 +.equ hex.$t4, 12 +.equ hex.$t5, 13 +.equ hex.$t6, 14 +.equ hex.$t7, 15 +.equ hex.$s0, 16 +.equ hex.$s1, 17 +.equ hex.$s2, 18 +.equ hex.$s3, 19 +.equ hex.$s4, 20 +.equ hex.$s5, 21 +.equ hex.$s6, 22 +.equ hex.$s7, 23 +.equ hex.$t8, 24 +.equ hex.$t9, 25 +.equ hex.$k0, 26 +.equ hex.$k1, 27 +.equ hex.$gp, 28 +.equ hex.$sp, 29 +.equ hex.$fp, 30 +.equ hex.$ra, 31 +#define vco 0 +#define vcc 1 +#define vce 2 + +MgBeginShaderUniforms + MgBeginUniform MATRICES, 0 .align 4 -BANNER0: .ascii " RSP OpenGL T&L " -BANNER1: .ascii "Rasky & Snacchus" - - RSPQ_BeginSavedState - #include "rsp_gl_state.inc" - -#define SCREEN_VTX_CS_POSi 0 // X, Y, Z, W (all 32-bit) -#define SCREEN_VTX_CS_POSf 8 // X, Y, Z, W (all 32-bit) -#define SCREEN_VTX_X 16 -#define SCREEN_VTX_Y 18 -#define SCREEN_VTX_Z 20 -#define SCREEN_VTX_CLIP_CODE 22 -#define SCREEN_VTX_PADDING 23 -#define SCREEN_VTX_RGBA 24 -#define SCREEN_VTX_S 28 -#define SCREEN_VTX_T 30 -#define SCREEN_VTX_W 32 // FIXME: this is duplicated in CS_POS -#define SCREEN_VTX_INVW 36 // 32-bit -#define SCREEN_VTX_SIZE 40 - - .align 3 -VERTEX_CACHE: .dcb.b PRIM_VTX_SIZE * VERTEX_CACHE_SIZE - - RSPQ_EndSavedState - + MATRICES_MVP: .ds.b 64 .align 4 -DEFAULT_ATTRIBUTES: .half 0, 0, 0, 1<<5, 0, 0, 0, 0x7FFF, 0, 0, 0, 1<<8 - + MATRICES_MV: .ds.b 64 .align 4 -CACHE_OFFSETS: .half 2,4,6,8,10,12,14,16,18 - -CLIP_CODE_FACTORS: .half 1, 1, GUARD_BAND_FACTOR, GUARD_BAND_FACTOR - - - .text - - .func GLCmd_InitPipe -GLCmd_InitPipe: - move s0, a0 - li s4, %lo(GL_STATE) - j DMAIn - li t0, DMA_SIZE(GL_STATE_SIZE, 1) - .endfunc - - .func GLCmd_SetVtxLoader -GLCmd_SetVtxLoader: - move s0, a1 - li s4, %lo(gl_vtx_loader) - jal DMAInAsync - li t0, DMA_SIZE(VTX_LOADER_MAX_SIZE, 1) - add s0, a0, s4 - jal_and_j DMAOutAsync, RSPQ_Loop - .endfunc - - .func GLCmd_SetVtxCmdSize -GLCmd_SetVtxCmdSize: - li s4, %lo(_RSPQ_OVERLAY_COMMAND_TABLE) + 8 - sh a0, 0(s4) - move s0, a1 - j DMAOutAsync - li t0, DMA_SIZE(8, 1) - .endfunc - - .func GLCmd_SetByte -GLCmd_SetByte: - jr ra - sb a1, %lo(GL_STATE)(a0) - .endfunc - - .func GLCmd_SetLong -GLCmd_SetLong: - sw a2, %lo(GL_STATE) + 4(a0) -GLCmd_SetWord: - jr ra - sw a1, %lo(GL_STATE)(a0) - .endfunc - - ######################################## - # GL_HandleMatrixPalette - # - # Args: - # v1 = Matrix index - # t5 = State flags - # s1 = Matrix pointer offset - # - ######################################## - .func GL_HandleMatrixPalette -GL_HandleMatrixPalette: - #define mtx_index v1 - #define state_flags t5 - #define mtx_pointer s1 - andi t0, state_flags, FLAG_MATRIX_PALETTE - beqz t0, JrRa - lw t0, %lo(GL_LOADED_MTX_INDEX) - 0xC(mtx_pointer) - - lw s0, %lo(GL_MATRIX_POINTERS)(mtx_pointer) - - # Check if this matrix is already loaded - beq t0, mtx_index, JrRa - sw mtx_index, %lo(GL_LOADED_MTX_INDEX) - 0xC(mtx_pointer) - - sll t0, mtx_index, 6 - add s0, t0 - j DMAIn - li t0, DMA_SIZE(MATRIX_SIZE, 1) - #undef mtx_index - #undef state_flags - #undef mtx_pointer - .endfunc - - ######################################## - # GLCmd_SetPrimVertex - # - # Arguments: - # * 0x00 (a0): offset within VERTEX_CACHE - # * 0x04 (a1): object space X, Y (16-bit) - # * 0x08 (a2): object space Z, W (16-bit) - # * 0x0C (a3): RGBA (8-bit each one) - # * 0x10: S, T (16-bit) - # * 0x14: normal X, Y, Z (8-bit each one) (LSB must be 0) - # - ######################################## - .align 3 - .func GLCmd_SetPrimVertex -GLCmd_SetPrimVertex: - #define vtx a0 - #define default s0 - #define current s1 - #define cmd_ptr s4 - #define norm v0 - #define mtxi v1 - #define state_flags t5 - - #define v___ $v01 - - #define vmtx0_i $v16 // m00 m01 m02 m03 - #define vmtx0_f $v17 - #define vmtx1_i $v18 // m10 m11 m12 m13 - #define vmtx1_f $v19 - #define vmtx2_i $v20 // m20 m21 m22 m23 - #define vmtx2_f $v21 - #define vmtx3_i $v22 // m30 m31 m32 m03 - #define vmtx3_f $v23 - - #define vpos $v24 - #define vcol $v25 - #define vtex $v26 - #define vdefault $v27 - #define vcspos_i $v28 - #define vcspos_f $v29 - - #define x e0 - #define y e1 - #define z e2 - #define w e3 - - addi cmd_ptr, rspq_dmem_buf_ptr, %lo(RSPQ_DMEM_BUFFER) + 4 - sub cmd_ptr, rspq_cmd_size - - li default, %lo(DEFAULT_ATTRIBUTES) - li current, %lo(GL_CURRENT_ATTRIBUTES) - - .align 3 -gl_vtx_loader: - .ds.l VTX_LOADER_MAX_COMMANDS - .align 3 - - addi vtx, %lo(VERTEX_CACHE) - sdv vpos, PRIM_VTX_X ,vtx - sdv vcol, PRIM_VTX_R ,vtx - sdv vtex, PRIM_VTX_TEX_S ,vtx - sw norm, PRIM_VTX_NORMAL(vtx) - - move ra2, ra - lw state_flags, %lo(GL_STATE_FLAGS) - - li s4, %lo(GL_MATRIX_MVP) - sb mtxi, PRIM_VTX_MTX_INDEX(vtx) - jal GL_HandleMatrixPalette - li s1, 0x10 - - jal GL_MtxTransformSingle - vcopy $v27, vpos - - # 32-bit right shift by 5, to keep the clip space coordinates unscaled - vmudm vcspos_i, vcspos_i, vshift8.e4 - vmadl vcspos_f, vcspos_f, vshift8.e4 - - sdv vcspos_i, PRIM_VTX_CS_POSi,vtx - sdv vcspos_f, PRIM_VTX_CS_POSf,vtx - - # Calculate and store clipping flags against CS.W. These - # will be used for trivial rejections. - vch v___, vcspos_i, vcspos_i.w - vcl v___, vcspos_f, vcspos_f.w - cfc2 t0, COP2_CTRL_VCC - andi t0, 0x707 # Isolate X/Y/Z flags - # Compress flags to 8 bit - srl t1, t0, 5 - andi t0, 0x7 - or t0, t1 - jr ra2 - sb t0, PRIM_VTX_TRCODE(vtx) - - # FIXME: in a glBegin/glEnd pair, we should also cache the per-vertex material. - - #undef cmd_ptr - #undef vtx - #undef in_xy - #undef in_zw - #undef in_rgba - #undef vtx_id - - #undef x - #undef y - #undef z - #undef w - - #undef v___ - - #undef vmtx0_i - #undef vmtx0_f - #undef vmtx1_i - #undef vmtx1_f - #undef vmtx2_i - #undef vmtx2_f - #undef vmtx3_i - #undef vmtx3_f - - #undef vpos - #undef vcspos_i - #undef vcspos_f - - .endfunc - - ################################################################ - # GL_CalcScreenSpace - # - # Args: - # s3 = Destination vertex address - # $v02 = Clip space position (fractional part) - # $v03 = Clip space position (integer part) - # - ################################################################ - .func GL_CalcScreenSpace -GL_CalcScreenSpace: - #define dst s3 - #define vcspos_f $v02 - #define vcspos_i $v03 - #define vinvw_f $v23 - #define vinvw_i $v24 - #define vviewscale $v25 - #define vviewoff $v26 - #define vscreenpos_i $v27 - #define vscreenpos_f $v28 - #define v___ $v29 - #define w e3 - - # Calculate 32-bit inverse W - # TODO: NR? - vrcph vinvw_i.w, vcspos_i.w - vrcpl vinvw_f.w, vcspos_f.w - vrcph vinvw_i.w, vzero.e0 - - # Calculate screenspace coords - li t0, %lo(GL_VIEWPORT_SCALE) - ldv vviewscale, 0,t0 - ldv vviewoff, 8,t0 - - vmudl v___, vcspos_f, vinvw_f.w - vmadm v___, vcspos_i, vinvw_f.w - vmadn vscreenpos_f, vcspos_f, vinvw_i.w - vmadh vscreenpos_i, vcspos_i, vinvw_i.w - - vmudn vscreenpos_f, vscreenpos_f, vviewscale - vmadh vscreenpos_i, vscreenpos_i, vviewscale - vadd vscreenpos_i, vviewoff - - sdv vscreenpos_i, SCREEN_VTX_X ,dst - ssv vcspos_i.w, SCREEN_VTX_W+0 ,dst - ssv vcspos_f.w, SCREEN_VTX_W+2 ,dst - ssv vinvw_i.w, SCREEN_VTX_INVW+0,dst - ssv vinvw_f.w, SCREEN_VTX_INVW+2,dst - jr ra - sb zero, SCREEN_VTX_PADDING(dst) - - #undef dst - #undef vcspos_f - #undef vcspos_i - #undef vinvw_f - #undef vinvw_i - #undef vviewscale - #undef vviewoff - #undef vscreenpos_i - #undef vscreenpos_f - #undef v___ - #undef w - - .endfunc - - ################################################################ - # GL_CalcClipCodes - # - # Args: - # s3 = Destination vertex address - # $v02 = Clip space position (fractional part) - # $v03 = Clip space position (integer part) - # - ################################################################ - .func GL_CalcClipCodes -GL_CalcClipCodes: - #define dst s3 - #define vcspos_f $v02 - #define vcspos_i $v03 - #define vguard_f $v27 - #define vguard_i $v28 - #define v___ $v29 - #define w e3 - - li t0, %lo(CLIP_CODE_FACTORS) - ldv vguard_i, 0,t0 - - vmudn vguard_f, vcspos_f, vguard_i - vmadh vguard_i, vcspos_i, vguard_i - - vch v___, vguard_i, vguard_i.w - vcl v___, vguard_f, vguard_f.w - cfc2 t0, COP2_CTRL_VCC - andi t0, 0x707 - srl t1, t0, 5 - andi t0, 0x7 - or t0, t1 - jr ra - sb t0, SCREEN_VTX_CLIP_CODE(dst) - - #undef dst - #undef vcspos_i - #undef vcspos_f - #undef vguard_i - #undef vguard_f - #undef v___ - #undef w - - .endfunc - - ################################################################ - # GL_TnL - # - # Args: - # s3 = address of the vertex in DMEM (usually within VERTEX_CACHE) - # - ################################################################ - .func GL_TnL -GL_TnL: - #define tmp_ptr s2 - #define vtx s3 - #define state_flags t5 - #define s e0 - move ra2, ra - - lw state_flags, %lo(GL_STATE_FLAGS) - - #define v___ $v01 - #define veyenormal $v03 - #define vrgba $v04 - #define vobjpos $v27 - #define veyepos $v28 - - ldv vrgba.e0, PRIM_VTX_R, vtx # R + G + B + A - ldv vrgba.e4, PRIM_VTX_R, vtx # R + G + B + A - - andi t0, state_flags, FLAG_NEED_EYE_SPACE - beqz t0, 2f - li s4, %lo(GL_MATRIX_MODELVIEW) - - lbu v1, PRIM_VTX_MTX_INDEX(vtx) - jal GL_HandleMatrixPalette - li s1, 0xC - - addi s5, vtx, PRIM_VTX_NORMAL-4 - lpv vobjpos.e0, 0,s5 # loads NX + NY + NZ into lanes 4-7 - ldv vobjpos.e0, PRIM_VTX_X,vtx # loads X + Y + Z + W into lanes 0-3 - - # TODO: technically we need the inverse transpose matrix, - # but for rigid matrices (translation, rotation, uniform scale) this is fine - - # Transform vertex pos and normal into eye space - jal GL_MtxTransformDouble - vmov vobjpos.e7, vzero.e0 - - li tmp_ptr, %lo(RDPQ_CMD_STAGING) - sqv veyepos, 0,tmp_ptr - ldv veyenormal.e0, 8,tmp_ptr - ldv veyenormal.e4, 8,tmp_ptr - - #define vsqdist_f $v10 - #define vsqdist_i $v11 - #define vtmp_f $v12 - #define vtmp_i $v13 - #define vinvdist_f $v14 - #define vinvdist_i $v15 - - # Re-normalize transformed normal - - andi t0, state_flags, FLAG_NORMALIZE - beqz t0, 1f - vmudh v___, veyenormal, veyenormal - vsar vsqdist_f, COP2_ACC_MD - vsar vsqdist_i, COP2_ACC_HI - vaddc vtmp_f, vsqdist_f, vsqdist_f.h1 - vadd vtmp_i, vsqdist_i, vsqdist_i.h1 - vaddc vsqdist_f, vtmp_f, vsqdist_f.h2 - vadd vsqdist_i, vtmp_i, vsqdist_i.h2 - - vrsqh v___.e0, vsqdist_i.e0 - vrsql vinvdist_f.e0, vsqdist_f.e0 - vrsqh vinvdist_i.e0, vzero.e0 - - vmudm v___, veyenormal, vinvdist_f.e0 - vmadh veyenormal, veyenormal, vinvdist_i.e0 - - #undef vsqdist_f - #undef vsqdist_i - #undef vtmp_f - #undef vtmp_i - #undef vinvdist_f - #undef vinvdist_i - -1: - ldv veyepos.e4, 0,tmp_ptr - -2: + MATRICES_NORMAL: .ds.b 32 + MgEndUniform - andi t0, state_flags, FLAG_LIGHTING - bnez t0, GL_VtxLighting - li ra, %lo(1f) -1: - - #define vtmp $v06 - #define vfog_i $v07 - #define vfog_f $v08 - andi t0, state_flags, FLAG_FOG - beqz t0, 1f - li s1, %lo(GL_STATE_FOG_PARAMS) - llv vfog_i, 0,s1 - llv vfog_f, 4,s1 - - # Note that the GL spec says the correct formula is - # f = (fog_end - abs(veyepos.z)) / (fog_end - fog_start) - # And the final fogged color is calculated as - # C = f * Ci + (1 - f) * Cf - # Where Ci is the incoming fragment color and Cf is the fog color. - - # However, there is a problem with translating this formula directly to a blender configuration: - # RDPQ_BLENDER((IN_RGB, SHADE_ALPHA, FOG_RGB, INV_MUX_ALPHA)) - # This would mean that a shade alpha of 1 represents "no fog" and a value of 0 is "full fog". - # Because shade alpha is internally an 8 bit fixed point value (0-255), it's not possible to represent - # a value of 1.0 exactly, only just below it. This leads to triangles that are completely outside of - # the fog area to still be tinted slightly with the fog color. - - # To avoid this, we turn the formula around, so that shade alpha 0 (which is exactly representable) - # corresponds to "no fog". - # This means we have to compute 1-f instead of f. If we rearrange the formula, we get - # (abs(veyepos.z) - fog_start) / (fog_end - fog_start) - # instead. - - # Compute abs(veyepos.z). - # abs(veyepos.z) is an approximation for the distance between the - # vertex and the origin in eye space, as recommended by the GL spec. - vsubc vtmp, vzero, veyepos.e2 - vge vtmp, veyepos.e2 - - # vtmp.e0 = abs(veyepos.z) - fog_start - # Note that fog_start might be negative. In practice this would - # rarely be the case, but it is not forbidden by the GL spec. - vsubc vtmp, vfog_i.e1 - - # vtmp.e0 = (abs(veyepos.z) - fog_start) / (fog_end - fog_start) - # The factor is premultiplied so that combined with VTX_SHIFT - # the product will be in 1.15 precision and saturated to 0x7FFF. - vmudm v___, vtmp, vfog_f.e0 - vmadh vtmp, vtmp, vfog_i.e0 - - # Clamp negative values to 0 - vge vtmp, vzero - - # Save the alpha factor in the vertex color, overwriting the alpha component. - vmov vrgba.e3, vtmp.e0 - #undef vtmp - #undef vfog -1: - - #define vtexsize $v06 - #define vtexoffset $v07 - #define vstrq $v08 - - ldv vstrq, PRIM_VTX_TEX_S,vtx # S + T + R + Q - suv vrgba, SCREEN_VTX_RGBA,vtx - - li s1, %lo(GL_STATE_TEX_SIZE) - llv vtexsize.s, 0,s1 - llv vtexoffset.s, 4,s1 - - #define vmodes $v09 - #define vobjlin $v10 - #define veyelin $v11 - #define vsphmap $v12 - - srl t0, state_flags, TEX_GEN_S_SHIFT - andi t0, 0xF - beqz t0, 2f - ldv vobjpos.e4, 0,tmp_ptr - - # Fill VCC with enable-flags - # We need to OR with 0xF0 so that the mode constants stay in the vmodes register - ori t0, 0x70 - ctc2 t0, COP2_CTRL_VCC - - li s1, %lo(GL_TEX_GEN) - - #define vplanes_s_i $v13 - #define vplanes_s_f $v14 - #define vplanes_t_i $v15 - #define vplanes_t_f $v16 - #define vplanes_r_i $v17 - #define vplanes_r_f $v18 - #define vplanes_q_i $v19 - #define vplanes_q_f $v20 - - lqv vmodes, TEX_GEN_MODE_OFFSET, s1 - lqv vplanes_s_i, TEX_GEN_INTEGER_OFFSET+0x00, s1 - - # If profiling is enabled, this ucode won't fit into IMEM in its entirety. - # In that case, sacrifice linear tex coord generation, a rarely used feature. -#if !RSPQ_PROFILE - # Check if linear tex gen is active for any coordinate - andi t0, state_flags, FLAG_TEX_GEN_LINEAR - beqz t0, 1f - # Select which coords to enable based on the enable-flags that were loaded into VCC above - vmrg vmodes, vmodes, vzero - lqv vplanes_s_f, TEX_GEN_FRACTION_OFFSET+0x00,s1 - lqv vplanes_t_i, TEX_GEN_INTEGER_OFFSET+0x10, s1 - lqv vplanes_t_f, TEX_GEN_FRACTION_OFFSET+0x10,s1 - lqv vplanes_r_i, TEX_GEN_INTEGER_OFFSET+0x20, s1 - lqv vplanes_r_f, TEX_GEN_FRACTION_OFFSET+0x20,s1 - lqv vplanes_q_i, TEX_GEN_INTEGER_OFFSET+0x30, s1 - lqv vplanes_q_f, TEX_GEN_FRACTION_OFFSET+0x30,s1 - - vmudn v___, vplanes_s_f, vobjpos.h0 - vmadh v___, vplanes_s_i, vobjpos.h0 - vmadn v___, vplanes_t_f, vobjpos.h1 - vmadh v___, vplanes_t_i, vobjpos.h1 - vmadn v___, vplanes_r_f, vobjpos.h2 - vmadh v___, vplanes_r_i, vobjpos.h2 - vmadn v___, vplanes_q_f, vobjpos.h3 - vmadh vobjlin, vplanes_q_i, vobjpos.h3 - - sdv vobjlin.e4, 0,tmp_ptr - ldv veyelin.e0, 0,tmp_ptr - - #undef vplanes_s_i - #undef vplanes_s_f - #undef vplanes_t_i - #undef vplanes_t_f - #undef vplanes_r_i - #undef vplanes_r_f - #undef vplanes_q_i - #undef vplanes_q_f - -1: -#endif - - #define vsqdist_i $v13 - #define vsqdist_f $v14 - #define vtmp_i $v15 - #define vtmp_f $v16 - #define vinvdist_i $v17 - #define vinvdist_f $v18 - #define veposnorm $v19 - #define vdot $v20 - #define refl_i $v21 - #define refl_f $v22 - - # Check if spherical tex gen is enabled for any coordinate - andi t0, state_flags, FLAG_TEX_GEN_SPHERICAL - beqz t0, 1f - # veposnorm = normalize(veyepos) - vmudh v___, veyepos, veyepos - vsar vsqdist_f, COP2_ACC_MD - vsar vsqdist_i, COP2_ACC_HI - vaddc vtmp_f, vsqdist_f, vsqdist_f.h1 - vadd vtmp_i, vsqdist_i, vsqdist_i.h1 - vaddc vsqdist_f, vtmp_f, vsqdist_f.h2 - vadd vsqdist_i, vtmp_i, vsqdist_i.h2 - - vrsqh v___.e0, vsqdist_i.e0 - vrsql vinvdist_f.e0, vsqdist_f.e0 - vrsqh vinvdist_i.e0, vzero.e0 - - vmudm v___, veyepos, vinvdist_f.e0 - vmadh veposnorm, veyepos, vinvdist_i.e0 - - # vdot = dot(veposnorm, veyenormal) - vmulf vdot, veposnorm, veyenormal - vaddc vtmp_f, vdot, vdot.h1 - vaddc vdot, vtmp_f, vdot.h2 - - # negate - vsubc vdot, vzero, vdot - - vcopy vtmp_i, vzero - vmov vtmp_i.e2, K16384 - - # refl = veposnorm - 2 * vdot * veyenormal + (0, 0, 1) - vmulf v___, veyenormal, vdot.e0 - vmacf v___, veyenormal, vdot.e0 # Add twice to account for multiplication by 2 - vmadh v___, veposnorm, K1 - vmadh v___, vtmp_i, K2 - - vsar refl_f, COP2_ACC_MD - vsar refl_i, COP2_ACC_HI - - # m = 1 / 2 * sqrt(dot(refl, refl)) - vmudl v___, refl_f, refl_f - vmadm v___, refl_i, refl_f - vmadn vsqdist_f, refl_f, refl_i - vmadh vsqdist_i, refl_i, refl_i - - vaddc vtmp_f, vsqdist_f, vsqdist_f.h1 - vadd vtmp_i, vsqdist_i, vsqdist_i.h1 - vaddc vsqdist_f, vtmp_f, vsqdist_f.h2 - vadd vsqdist_i, vtmp_i, vsqdist_i.h2 - - vaddc vtmp_i, vzero, K128 - - vrsqh v___.e0, vsqdist_i.e0 - vrsql vinvdist_f.e0, vsqdist_f.e0 - vrsqh vinvdist_i.e0, vzero.e0 - - # vshmap = refl * m + 0.5 - vmudh v___, vtmp_i, K1 - vmadl v___, refl_f, vinvdist_f.e0 - vmadm v___, refl_i, vinvdist_f.e0 - vmadn v___, refl_f, vinvdist_i.e0 - vmadh vsphmap, refl_i, vinvdist_i.e0 - -1: - veq v___, vmodes, vmodes.e4 - vmrg vstrq, vobjlin, vstrq - veq v___, vmodes, vmodes.e5 - vmrg vstrq, veyelin, vstrq - veq v___, vmodes, vmodes.e6 - vmrg vstrq, vsphmap, vstrq - - #undef vsqdist_i - #undef vsqdist_f - #undef vtmp_i - #undef vtmp_f - #undef vinvdist_i - #undef vinvdist_f - #undef veposnorm - #undef vdot - #undef refl_i - #undef refl_f - #undef vobjlin - #undef veyelin - #undef vmodes - -2: - #define vinvq_i $v26 - #define vinvq_f $v27 - #define vstrq_i $v28 - #define vstrq_f $v29 - #define q e3 - - # Apply texture matrix - vcopy $v27, vstrq - jal GL_MtxTransformSingle - li s4, %lo(GL_MATRIX_TEXTURE) - - # Perform perspective division - vrcph vinvq_i.q, vstrq_i.q - vrcpl vinvq_f.q, vstrq_f.q - vrcph vinvq_i.q, vzero.e0 - - vmudl v___, vstrq_f, vinvq_f.q - vmadm v___, vstrq_i, vinvq_f.q - vmadn vstrq_f, vstrq_f, vinvq_i.q - vmadh vstrq_i, vstrq_i, vinvq_i.q - - # vmudm vstrq_i, vstrq, K256 # >> 8 - # vmadl vstrq_f, vzero, vzero - - # Scale texcoord by texsize and subtract offset (to correct for bilinear sampling if active) - vmudn v___, vstrq_f, vtexsize - vmadh v___, vstrq_i, vtexsize - vmadh vstrq, vtexoffset, K1 - - #undef vinvq_i - #undef vinvq_f - #undef vstrq_i - #undef vstrq_f - #undef q - - lbu t0, PRIM_VTX_TRCODE(vtx) - - #define vcspos_f $v02 - #define vcspos_i $v03 - - ldv vcspos_f, PRIM_VTX_CS_POSf,vtx - ldv vcspos_i, PRIM_VTX_CS_POSi,vtx - - # Mark this vertex as having T&L applied - ori t0, 0x80 - sb t0, PRIM_VTX_TRCODE(vtx) - - jal GL_CalcScreenSpace - slv vstrq.s, SCREEN_VTX_S,vtx - - j GL_CalcClipCodes - move ra, ra2 - - #undef vcspos_f - #undef vcspos_i - #undef vtexsize - #undef vtexoffset - - #undef state_flags - #undef vtx - #undef vtx - - #undef v___ - #undef vrgba - #undef vst - #undef s - #undef vobjpos - #undef veyepos - #undef veyenormal - - .endfunc - - - ################################################################ - # GLCmd_DrawTriangle - # - # Arguments: - # a0: Bit 31..24: Command id - # Bit 11..0: Offset into vertex cache of vtx1 - # a1: Bit 27..16: Offset into vertex cache of vtx2 - # Bit 11..0: Offset into vertex cache of vtx3 - # - ################################################################ - .func GLCmd_DrawTriangle -GLCmd_DrawTriangle: - #define vtx1 a1 - #define vtx2 a2 - #define vtx3 a3 - #define trcode1 t6 - #define trcode2 t7 - #define trcode3 t8 - - # If GL_FONT_AND_BACK is set (GL_TRI_CULL==-1), there's nothing to do - lb v0, %lo(GL_TRI_CULL) - bltz v0, RSPQ_Loop - - addi vtx3, a1, %lo(VERTEX_CACHE) - srl vtx2, a1, 16 - addi vtx2, %lo(VERTEX_CACHE) - addi vtx1, a0, %lo(VERTEX_CACHE) - - # Trivial reject: if all the vertices are out of the same plane (at least one), - # the triangle is out of the viewport. - # NOTE: This deliberately uses lb instead of lbu so the sign bit is extended. - # The MSB of each TR-code is a bit flag that is set if the vertex has already - # had T&L applied once. - lb trcode1, PRIM_VTX_TRCODE(vtx1) - lb trcode2, PRIM_VTX_TRCODE(vtx2) - lb trcode3, PRIM_VTX_TRCODE(vtx3) - and t0, trcode1, trcode2 - and t0, trcode3 - andi t0, 0x3F - bnez t0, JrRa - nop - - # Perform T&L for each vertex if we haven't already - bgezal trcode1, GL_TnL - move s3, vtx1 - - bgezal trcode2, GL_TnL - move s3, vtx2 - - bgezal trcode3, GL_TnL - move s3, vtx3 - - lbu t0, SCREEN_VTX_CLIP_CODE(vtx1) - lbu t1, SCREEN_VTX_CLIP_CODE(vtx2) - lbu t2, SCREEN_VTX_CLIP_CODE(vtx3) - or t5, t0, t1 - or t5, t2 - - move s1, zero - beqz t5, gl_draw_single_triangle - move s2, zero - - jal GL_ClipTriangle - nop - - beqz v1, gl_draw_triangle_end - addi s2, -6 - lhu s5, 0(s1) -gl_draw_clipped_triangles_loop: - move vtx1, s5 - lhu vtx2, 2(s1) - lhu vtx3, 4(s1) - -gl_draw_single_triangle: - addi vtx1, SCREEN_VTX_X - addi vtx2, SCREEN_VTX_X - addi vtx3, SCREEN_VTX_X - - lhu a0, %lo(GL_TRI_CMD) - lb v0, %lo(GL_TRI_CULL) - jal RDPQ_Triangle - li s3, %lo(RDPQ_CMD_STAGING) - - jal RDPQ_Send - li s4, %lo(RDPQ_CMD_STAGING) - - blt s1, s2, gl_draw_clipped_triangles_loop - addi s1, 2 - -gl_draw_triangle_end: - j RSPQ_Loop - nop - - #undef vtx1 - #undef vtx2 - #undef vtx3 - - .endfunc - -#include "rsp_gl_common.inc" -#include "rsp_gl_lighting.inc" -#include "rsp_gl_clipping.inc" -#include + MgBeginUniform TEXTURING, 1 + .align 4 + TEXTURE_MATRIX: .ds.b 48 + .align 1 + TEXTURE_SIZE: .ds.b 4 + .align 1 + TEXTURE_OFFSET: .ds.b 4 + MgEndUniform + + MgBeginUniform LIGHTING, 2 + LIGHTING_LIGHTS: .ds.b 256 + .align 1 + LIGHTING_AMBIENT: .ds.b 6 + LIGHTING_HAS_POINTS: .ds.b 1 + LIGHTING_COUNT: .ds.b 1 + .align 1 + MATERIAL_DIFFUSE: .ds.b 8 + .align 1 + MATERIAL_AMBIENT: .ds.b 6 + .align 1 + MATERIAL_FLAGS: .ds.b 2 + .align 1 + MATERIAL_EMISSIVE: .ds.b 6 + MgEndUniform + + MgBeginUniform FOG, 3 + .align 1 + FOG_PARAMS: .ds.b 6 + FOG_MASK: .ds.b 1 + MgEndUniform + +MgEndShaderUniforms + +MgBeginVertexInput + MgBeginVertexAttribute 0, 0 + MgVertexAttributeLoaders LOAD_POSITION589, LOAD_POSITION590, LOAD_POSITION914, LOAD_POSITION913 + MgEndVertexAttribute + + MgBeginVertexAttribute 1, 1 + MgVertexAttributeLoaders LOAD_NORMAL587, LOAD_NORMAL588, LOAD_NORMAL912, LOAD_NORMAL911 + MgEndVertexAttribute + + MgBeginVertexAttribute 2, 1 + MgVertexAttributeLoaders LOAD_COLOR591, LOAD_COLOR592, LOAD_COLOR916, LOAD_COLOR915 + MgEndVertexAttribute + + MgBeginVertexAttribute 3, 1 + MgVertexAttributeLoaders LOAD_TEXCOORD620, LOAD_TEXCOORD623 + MgEndVertexAttribute + +MgEndVertexInput + +MgBeginShader + ori $at, $zero, %lo(MG_VERTEX_SIZE) ## L:486 | ^ | vec16 vvtx_size = load(MG_VERTEX_SIZE).xyzw; + ldv $v01, 0, 0, $at ## L:486 | 2 | vec16 vvtx_size = load(MG_VERTEX_SIZE).xyzw; + addiu $t0, $gp, %lo(RSPQ_DMEM_BUFFER) -6 ## L:485 | 3 | u32 inputs_ptr = get_cmd_address(0x2); + ldv $v02, 0, 0, $t0 ## L:487 | 4 | vec16 vinputs = load(inputs_ptr).xyzw; + vmudh $v04, $v02, $v01.v ## L:489 | ***8 | vec32 vproducts = vinputs * vvtx_size; + ori $s4, $zero, %lo(MG_VERTEX_CACHE_END) ## L:511 | ^ | vtx_in0_ptr = MG_VERTEX_CACHE_END; + vsar $v03, COP2_ACC_HI ## L:489 | 9 | vec32 vproducts = vinputs * vvtx_size; + lw $s0, %lo(MG_VERTEX_BUFFER + 0) ## L:503 | ^ | u32<$s0> vtx_buffer = load(MG_VERTEX_BUFFER); + vsar $v04, COP2_ACC_MD ## L:489 | 10 | vec32 vproducts = vinputs * vvtx_size; + ori $at, $zero, %lo(RSPQ_SCRATCH_MEM) ## L:490 | ^ | @Barrier("inputs0") store(vproducts:ufract.xyzw, RSPQ_SCRATCH_MEM); ## Barrier: 0x1 + ssv $v03, 0, 8, $at ## L:491 | **13 | @Barrier("inputs1") store(vproducts.x, RSPQ_SCRATCH_MEM, 0x8); ## Barrier: 0x2 + ssv $v04, 0, 10, $at ## L:491 | 14 | @Barrier("inputs1") store(vproducts.x, RSPQ_SCRATCH_MEM, 0x8); ## Barrier: 0x2 + lw $t2, %lo(RSPQ_SCRATCH_MEM + 8) ## L:501 | 15 | @Barrier("inputs1") buffer_offset = load(RSPQ_SCRATCH_MEM, 0x8); ## Barrier: 0x2 + sdv $v04, 0, 0, $at ## L:490 | 16 | @Barrier("inputs0") store(vproducts:ufract.xyzw, RSPQ_SCRATCH_MEM); ## Barrier: 0x1 + lhu $s7, %lo(RSPQ_SCRATCH_MEM + 2) ## L:497 | 17 | @Barrier("inputs0") vtx_out0_ptr = load(RSPQ_SCRATCH_MEM, 0x2); ## Barrier: 0x1 + andi $t3, $t2, 7 ## L:506 | 18 | u32 misalignment = buffer_offset & 0x7; + lhu $t1, %lo(RSPQ_SCRATCH_MEM + 4) ## L:499 | 19 | @Barrier("inputs0") vertices_size = load(RSPQ_SCRATCH_MEM, 0x4); ## Barrier: 0x1 + addu $s0, $s0, $t2 ## L:504 | 20 | vtx_buffer += buffer_offset; + addiu $t2, $zero, 12 ## L:514 | 21 | dma_in(vtx_in0_ptr, vtx_buffer, dma_size); + addu $t0, $t1, $t3 ## L:507 | 22 | dma_size = vertices_size + misalignment; + addiu $t0, $t0, 7 ## L:508 | 23 | dma_size += 0x7; + andi $t0, $t0, 4088 ## L:509 | 24 | dma_size &= 0xFF8; + subu $s4, $s4, $t0 ## L:512 | 25 | vtx_in0_ptr -= dma_size; + jal DMAExec ## L:514 | 26 | dma_in(vtx_in0_ptr, vtx_buffer, dma_size); ## Args: $t0, $t1, $s0, $s4, $t2 + addiu $t0, $t0, -1 ## L:514 | *28 | dma_in(vtx_in0_ptr, vtx_buffer, dma_size); + ori $at, $zero, %lo(MATRICES_NORMAL) ## L:533 | 29 | vmn0 = load(MATRICES_NORMAL, 0x00).xyzwxyzw; + ldv $v11, 0, 16, $at ## L:535 | 30 | vmn2 = load(MATRICES_NORMAL, 0x10).xyzwxyzw; + ldv $v11, 8, 16, $at ## L:535 | 31 | vmn2 = load(MATRICES_NORMAL, 0x10).xyzwxyzw; + ori $t0, $zero, %lo(MATRICES_MVP) ## L:528 | 32 | u16 mvpaddr = MATRICES_MVP; + ldv $v10, 0, 8, $at ## L:534 | 33 | vmn1 = load(MATRICES_NORMAL, 0x08).xyzwxyzw; + ldv $v09, 0, 0, $at ## L:533 | 34 | vmn0 = load(MATRICES_NORMAL, 0x00).xyzwxyzw; + ldv $v10, 8, 8, $at ## L:534 | 35 | vmn1 = load(MATRICES_NORMAL, 0x08).xyzwxyzw; + ldv $v09, 8, 0, $at ## L:533 | 36 | vmn0 = load(MATRICES_NORMAL, 0x00).xyzwxyzw; + ori $at, $zero, %lo(MG_NORMAL_MASK) ## L:537 | 37 | vec16 vnormmask = load(MG_NORMAL_MASK,0x0).xyzwxyzw; + ldv $v12, 0, 0, $at ## L:537 | 38 | vec16 vnormmask = load(MG_NORMAL_MASK,0x0).xyzwxyzw; + lhu $t8, %lo(MG_VERTEX_SIZE + 0) ## L:516 | 39 | vtx_size = load(MG_VERTEX_SIZE); + lhu $s0, %lo(MATERIAL_FLAGS + 0) ## L:572 | 40 | u16 mat_flags = load(MATERIAL_FLAGS); + addu $s6, $s4, $t1 ## L:519 | 41 | vtx_in_end = vtx_in0_ptr + vertices_size; + ldv $v01, 0, 0, $t0 ## L:466 | 42 | m0:sint = load(address, 0x00).xyzwxyzw; + ori $t3, $zero, %lo(MG_SCRATCH_MEM) ## L:547 | 43 | u16 prev_out0 = MG_SCRATCH_MEM; + ldv $v07, 0, 24, $t0 ## L:472 | 44 | m3:sint = load(address, 0x18).xyzwxyzw; + addiu $s7, $s7, %lo(MG_VERTEX_CACHE) ## L:520 | 45 | vtx_out0_ptr += MG_VERTEX_CACHE; + ldv $v03, 0, 8, $t0 ## L:468 | 46 | m1:sint = load(address, 0x08).xyzwxyzw; + addiu $t2, $s7, 40 ## L:545 | 47 | u16 vtx_out1_ptr = vtx_out0_ptr + 40; + sll $t9, $t8, 1 ## L:517 | 48 | vtx_size2 = vtx_size * 2; + ldv $v05, 0, 16, $t0 ## L:470 | 49 | m2:sint = load(address, 0x10).xyzwxyzw; + ldv $v01, 8, 0, $t0 ## L:466 | 50 | m0:sint = load(address, 0x00).xyzwxyzw; + addiu $fp, $zero, 80 ## L:561 | 51 | u16 mat_ptr_emissive = 0x50; + ldv $v13, 0, 8, $at ## L:538 | 52 | vec16 vnormfactor = load(MG_NORMAL_MASK,0x8).xyzwxyzw; + andi $s1, $s0, 1 ## L:573 | 53 | u16 tmp = mat_flags & 0x1; + ldv $v12, 8, 0, $at ## L:537 | 54 | vec16 vnormmask = load(MG_NORMAL_MASK,0x0).xyzwxyzw; + addiu $sp, $zero, 64 ## L:560 | 55 | u16 mat_ptr_ambient = 0x40; + addu $t1, $s4, $t8 ## L:544 | 56 | u16 vtx_in1_ptr = vtx_in0_ptr + vtx_size; + ldv $v13, 8, 8, $at ## L:538 | 57 | vec16 vnormfactor = load(MG_NORMAL_MASK,0x8).xyzwxyzw; + ldv $v02, 0, 32, $t0 ## L:467 | 58 | m0:ufract = load(address, 0x20).xyzwxyzw; + ori $at, $zero, %lo(MATERIAL_DIFFUSE) ## L:564 | 59 | vec16 vdiffuse = load(MATERIAL_DIFFUSE).xyzwxyzw; + ldv $v21, 0, 0, $at ## L:564 | 60 | vec16 vdiffuse = load(MATERIAL_DIFFUSE).xyzwxyzw; + ldv $v04, 0, 40, $t0 ## L:469 | 61 | m1:ufract = load(address, 0x28).xyzwxyzw; + ldv $v06, 0, 48, $t0 ## L:471 | 62 | m2:ufract = load(address, 0x30).xyzwxyzw; + ldv $v02, 8, 32, $t0 ## L:467 | 63 | m0:ufract = load(address, 0x20).xyzwxyzw; + ldv $v21, 8, 0, $at ## L:564 | 64 | vec16 vdiffuse = load(MATERIAL_DIFFUSE).xyzwxyzw; + ori $at, $zero, %lo(MATERIAL_AMBIENT) ## L:565 | 65 | vec16 vambient = load(MATERIAL_AMBIENT).xyzwxyzw; + ldv $v08, 0, 56, $t0 ## L:473 | 66 | m3:ufract = load(address, 0x38).xyzwxyzw; + ldv $v08, 8, 56, $t0 ## L:473 | 67 | m3:ufract = load(address, 0x38).xyzwxyzw; + ldv $v22, 0, 0, $at ## L:565 | 68 | vec16 vambient = load(MATERIAL_AMBIENT).xyzwxyzw; + ldv $v22, 8, 0, $at ## L:565 | 69 | vec16 vambient = load(MATERIAL_AMBIENT).xyzwxyzw; + ori $at, $zero, %lo(MATERIAL_EMISSIVE) ## L:566 | 70 | vec16 vemissive = load(MATERIAL_EMISSIVE).xyzwxyzw; + ldv $v07, 8, 24, $t0 ## L:472 | 71 | m3:sint = load(address, 0x18).xyzwxyzw; + ldv $v23, 0, 0, $at ## L:566 | 72 | vec16 vemissive = load(MATERIAL_EMISSIVE).xyzwxyzw; + ldv $v06, 8, 48, $t0 ## L:471 | 73 | m2:ufract = load(address, 0x30).xyzwxyzw; + ldv $v03, 8, 8, $t0 ## L:468 | 74 | m1:sint = load(address, 0x08).xyzwxyzw; + ldv $v04, 8, 40, $t0 ## L:469 | 75 | m1:ufract = load(address, 0x28).xyzwxyzw; + ldv $v23, 8, 0, $at ## L:566 | 76 | vec16 vemissive = load(MATERIAL_EMISSIVE).xyzwxyzw; + ldv $v05, 8, 16, $t0 ## L:470 | 77 | m2:sint = load(address, 0x10).xyzwxyzw; + ori $t4, $zero, %lo(MG_SCRATCH_MEM) ## L:548 | 78 | u16 prev_out1 = MG_SCRATCH_MEM; + addiu $k1, $zero, 48 ## L:559 | 79 | u16 mat_ptr_diffuse = 0x30; + ori $at, $zero, %lo(MG_SCRATCH_MEM) ## L:568 | 80 | store(vdiffuse, MG_SCRATCH_MEM, 0x30); + sqv $v22, 0, 64, $at ## L:569 | 81 | store(vambient, MG_SCRATCH_MEM, 0x40); + lbu $t0, %lo(LIGHTING_HAS_POINTS + 0) ## L:541 | 82 | u8 has_points = load(LIGHTING_HAS_POINTS); + sqv $v23, 0, 80, $at ## L:570 | 83 | store(vemissive, MG_SCRATCH_MEM, 0x50); + beq $s1, $zero, LABEL_gl_pipeline_0001 ## L:574 | 84 | if (tmp != 0) { + sqv $v21, 0, 48, $at ## L:568 | *86 | store(vdiffuse, MG_SCRATCH_MEM, 0x30); + addiu $k1, $zero, 96 ## L:575 | 87 | mat_ptr_diffuse = 0x60; + LABEL_gl_pipeline_0001: + andi $s1, $s0, 2 ## L:577 | 88 | tmp = mat_flags & 0x2; + beq $s1, $zero, LABEL_gl_pipeline_0002 ## L:578 | 89 | if (tmp != 0 ) { + nop ## L:578 | *91 | if (tmp != 0 ) { + addiu $sp, $zero, 96 ## L:579 | 92 | mat_ptr_ambient = 0x60; + LABEL_gl_pipeline_0002: + andi $s1, $s0, 4 ## L:581 | 93 | tmp = mat_flags & 0x4; + beq $s1, $zero, LABEL_gl_pipeline_0003 ## L:582 | 94 | if (tmp != 0) { + nop ## L:582 | *96 | if (tmp != 0) { + addiu $fp, $zero, 96 ## L:583 | 97 | mat_ptr_emissive = 0x60; + LABEL_gl_pipeline_0003: + LOAD_NORMAL587: lsv $v15, 0, 0, $s4 ## L:587 | 98 | @AttrLoader("NORMAL") vnorm.x = load(vtx_in0_ptr).x; + LOAD_NORMAL588: lsv $v15, 8, 0, $t1 ## L:588 | 99 | @AttrLoader("NORMAL") vnorm.X = load(vtx_in1_ptr).x; + LOAD_COLOR591: llv $v18, 0, 0, $s4 ## L:591 | 100 | @AttrLoader("COLOR") vrgba_in.xy = load(vtx_in0_ptr).xy; + LOAD_COLOR592: llv $v18, 4, 0, $t1 ## L:592 | 101 | @AttrLoader("COLOR") vrgba_in.zw = load(vtx_in1_ptr).xy; + LOAD_POSITION589: ldv $v14, 0, 0, $s4 ## L:589 | 102 | @AttrLoader("POSITION") vpos.xyzw = load(vtx_in0_ptr).xyzw; + LOAD_POSITION590: ldv $v14, 8, 0, $t1 ## L:590 | 103 | @AttrLoader("POSITION") vpos.XYZW = load(vtx_in1_ptr).xyzw; + VERTEX_LOOP: + vand $v15, $v12, $v15.h0 ## L:627 | ^ | vnorm = vnormmask & vnorm.xxxxXXXX; + ori $at, $zero, %lo(RSPQ_SCRATCH_MEM) ## L:614 | 104 | @Barrier("unpack_col") store(vrgba_in.xyzw, RSPQ_SCRATCH_MEM); ## Barrier: 0x100 + suv $v17, 4, 8, $t4 ## L:609 | *106 | @Barrier("st_tex1") store_vec_u8(vrgba.X, prev_out1, 8); ## Barrier: 0x80 + sdv $v18, 0, 0, $at ## L:614 | 107 | @Barrier("unpack_col") store(vrgba_in.xyzw, RSPQ_SCRATCH_MEM); ## Barrier: 0x100 + suv $v17, 0, 8, $t3 ## L:608 | 108 | @Barrier("st_tex0") store_vec_u8(vrgba.x, prev_out0, 8); ## Barrier: 0x40 + vmudn $v15, $v15, $v13.v ## L:628 | ^ | vnorm *= vnormfactor; + luv $v18, 0, 0, $at ## L:615 | 109 | @Barrier("unpack_col") vrgba_in = load_vec_u8(RSPQ_SCRATCH_MEM); ## Barrier: 0x100 + vmudn $v29, $v02, $v14.h0 ## L:631 | ^ | VTEMP = vmvp0 * vpos.xxxxXXXX; + vmadh $v29, $v01, $v14.h0 ## L:631 | 110 | VTEMP = vmvp0 * vpos.xxxxXXXX; + sdv $v19, 8, 0, $t4 ## L:601 | ^ | @Barrier("st_c1") @Barrier("st_tr1") store(vpos_clip:sint.XYZW, prev_out1, 0); ## Barrier: 0x30 + vmadn $v29, $v04, $v14.h1 ## L:632 | 111 | VTEMP = vmvp1 +* vpos.yyyyYYYY; + ori $at, $zero, %lo(MG_SCRATCH_MEM) ## L:616 | ^ | store(vrgba_in, MG_SCRATCH_MEM, 0x60); + vmadh $v29, $v03, $v14.h1 ## L:632 | 112 | VTEMP = vmvp1 +* vpos.yyyyYYYY; + sdv $v19, 0, 0, $t3 ## L:600 | ^ | @Barrier("st_c0") @Barrier("st_tr0") store(vpos_clip:sint.xyzw, prev_out0, 0); ## Barrier: 0xC + sqv $v18, 0, 96, $at ## L:616 | 113 | store(vrgba_in, MG_SCRATCH_MEM, 0x60); + vmadn $v29, $v06, $v14.h2 ## L:633 | ^ | VTEMP = vmvp2 +* vpos.zzzzZZZZ; + ori $at, $zero, %lo(MG_CLIP_FACTORS) ## L:656 | 114 | vec16 vclip_factors = load(MG_CLIP_FACTORS).xyzwxyzw; + vmadh $v29, $v05, $v14.h2 ## L:633 | ^ | VTEMP = vmvp2 +* vpos.zzzzZZZZ; + ldv $v21, 0, 0, $at ## L:656 | 115 | vec16 vclip_factors = load(MG_CLIP_FACTORS).xyzwxyzw; + vmadn $v20, $v08, $v30.e2 ## L:634 | ^ | vpos_clip = vmvp3 +* 0x20; + sb $t7, 7($t3) ## L:605 | 116 | @Barrier("st_tr0") store(tr0, prev_out0, 7); ## Barrier: 0x8 + vmadh $v19, $v07, $v30.e2 ## L:634 | ^ | vpos_clip = vmvp3 +* 0x20; + vmulf $v29, $v09, $v15.h0 ## L:636 | 117 | VTEMP = vmn0:sfract * vnorm:sfract.xxxxXXXX; + ldv $v21, 8, 0, $at ## L:656 | ^ | vec16 vclip_factors = load(MG_CLIP_FACTORS).xyzwxyzw; + slv $v16, 0, 12, $t3 ## L:611 | 118 | @Barrier("st_tex0") store(vtex.xy, prev_out0, 12); ## Barrier: 0x40 + ori $at, $zero, %lo(FOG_PARAMS) ## L:671 | 119 | vec16 vfog_parms = load(FOG_PARAMS).xyzwxyzw; + vmacf $v29, $v10, $v15.h1 ## L:637 | ^ | VTEMP = vmn1:sfract +* vnorm:sfract.yyyyYYYY; + vmacf $v15, $v11, $v15.h2 ## L:638 | 120 | vnorm = vmn2:sfract +* vnorm:sfract.zzzzZZZZ; + slv $v16, 8, 12, $t4 ## L:612 | ^ | @Barrier("st_tex1") store(vtex.XY, prev_out1, 12); ## Barrier: 0x80 + vmudn $v23, $v20, $v21.v ## L:657 | 121 | vec32 vguard = vpos_clip * vclip_factors; + LOAD_TEXCOORD620: llv $v16, 0, 0, $s4 ## L:620 | ^ | @AttrLoader("TEXCOORD") vtex.xy = load(vtx_in0_ptr).xy; ## Barrier: 0x7E00 + sb $t5, 6($t3) ## L:603 | 122 | @Barrier("st_c0") store(c0, prev_out0, 6); ## Barrier: 0x4 + vmadh $v22, $v19, $v21.v ## L:657 | ^ | vec32 vguard = vpos_clip * vclip_factors; + LOAD_TEXCOORD623: llv $v16, 8, 0, $t1 ## L:623 | 123 | @AttrLoader("TEXCOORD") vtex.XY = load(vtx_in1_ptr).xy; ## Barrier: 0x7E00 + sb $t6, 6($t4) ## L:604 | 124 | @Barrier("st_c1") store(c1, prev_out1, 6); ## Barrier: 0x10 + sdv $v19, 0, 24, $s7 ## L:666 | *126 | @Barrier("st_cp0") store(vpos_clip.xyzw, vtx_out0_ptr, 24); ## Barrier: 0x200 + vch $v29, $v22, $v22.h3 ## L:658 | ^ | u16 clip_codes = clip(vguard, vguard.wwwwWWWW); + sdv $v20, 0, 32, $s7 ## L:666 | 127 | @Barrier("st_cp0") store(vpos_clip.xyzw, vtx_out0_ptr, 24); ## Barrier: 0x200 + vcl $v29, $v23, $v23.h3 ## L:658 | ^ | u16 clip_codes = clip(vguard, vguard.wwwwWWWW); + cfc2 $s0, $vcc ## L:658 | 128 | u16 clip_codes = clip(vguard, vguard.wwwwWWWW); + vch $v29, $v19, $v19.h3 ## L:662 | ^ | u16 tr_codes = clip(vpos_clip, vpos_clip.wwwwWWWW); + ldv $v22, 0, 0, $at ## L:671 | 129 | vec16 vfog_parms = load(FOG_PARAMS).xyzwxyzw; + ldv $v22, 8, 0, $at ## L:671 | 130 | vec16 vfog_parms = load(FOG_PARAMS).xyzwxyzw; + srl $s1, $s0, 4 ## L:452 | 131 | u16 codes2 = codes >> 4; + andi $s2, $s0, 1799 ## L:432 | 132 | t0 = codes & 0x707; + vcl $v29, $v20, $v20.h3 ## L:662 | ^ | u16 tr_codes = clip(vpos_clip, vpos_clip.wwwwWWWW); + sdv $v19, 8, 24, $t2 ## L:667 | 133 | @Barrier("st_cp1") store(vpos_clip.XYZW, vtx_out1_ptr, 24); ## Barrier: 0x400 + srl $s3, $s2, 5 ## L:433 | 134 | t1 = t0 >> 5; + vaddc $v23, $v20, $v22.h1 ## L:672 | ^ | vec16 vtmp:ufract = vpos_clip:ufract + vfog_parms:ufract.yyyyYYYY; + vadd $v21, $v19, $v22.h0 ## L:673 | 135 | vfog:sint = vpos_clip:sint + vfog_parms:sint.xxxxXXXX; + or $t5, $s2, $s3 ## L:440 | ^ | result = t0 | t1; + andi $s2, $s1, 1799 ## L:432 | 136 | t0 = codes & 0x707; + cfc2 $s1, $vcc ## L:662 | 137 | u16 tr_codes = clip(vpos_clip, vpos_clip.wwwwWWWW); + ori $at, $zero, %lo(MG_VIEWPORT) ## L:680 | 138 | vec16 vviewscale = load(MG_VIEWPORT, 0).xyzwxyzw; + vmudn $v29, $v23, $v22.h2 ## L:675 | ^ | VTEMP = vtmp:ufract * vfog_parms:sint.zzzzZZZZ; + vmadh $v21, $v21, $v22.h2 ## L:676 | 139 | vfog = vfog:sint +* vfog_parms:sint.zzzzZZZZ; + ldv $v22, 0, 0, $at ## L:680 | ^ | vec16 vviewscale = load(MG_VIEWPORT, 0).xyzwxyzw; + ldv $v22, 8, 0, $at ## L:680 | 140 | vec16 vviewscale = load(MG_VIEWPORT, 0).xyzwxyzw; + srl $s3, $s2, 5 ## L:433 | 141 | t1 = t0 >> 5; + or $t6, $s2, $s3 ## L:440 | 142 | result = t0 | t1; + sdv $v20, 8, 32, $t2 ## L:667 | 143 | @Barrier("st_cp1") store(vpos_clip.XYZW, vtx_out1_ptr, 24); ## Barrier: 0x400 + vge $v21, $v00, $v21.h2 ## L:677 | ^ | vfog = max(VZERO, vfog.zzzzZZZZ); + vmudl $v20, $v20, $v22.h3 ## L:683 | 144 | vpos_clip *= vviewscale:sfract.wwwwWWWW; + andi $s3, $s1, 1799 ## L:432 | ^ | t0 = codes & 0x707; + srl $s2, $s1, 4 ## L:459 | 145 | u16 codes2 = codes >> 4; + vmadm $v19, $v19, $v22.h3 ## L:683 | ^ | vpos_clip *= vviewscale:sfract.wwwwWWWW; + ldv $v23, 0, 8, $at ## L:681 | 146 | vec16 vviewoff = load(MG_VIEWPORT, 8).xyzwxyzw; + srl $s5, $s3, 5 ## L:433 | 147 | t1 = t0 >> 5; + vmadn $v20, $v00, $v00 ## L:683 | ^ | vpos_clip *= vviewscale:sfract.wwwwWWWW; + vrcph $v24.e3, $v19.e3 ## L:690 | *149 | vinvw.w = invert_half(vpos_clip).w; + nor $t7, $s3, $s5 ## L:447 | ^ | result = t0 ~| t1; + ssv $v19, 6, 16, $s7 ## L:686 | 150 | @Barrier("st_w0") store(vpos_clip.w, vtx_out0_ptr, 16); ## Barrier: 0x800 + ldv $v23, 8, 8, $at ## L:681 | 151 | vec16 vviewoff = load(MG_VIEWPORT, 8).xyzwxyzw; + vrcpl $v25.e3, $v20.e3 ## L:690 | ^ | vinvw.w = invert_half(vpos_clip).w; + sb $k0, 7($t4) ## L:606 | 152 | @Barrier("st_tr1") store(tr1, prev_out1, 7); ## Barrier: 0x20 + vrcph $v24.e3, $v19.e7 ## L:691 | ^ | vinvw.W = invert_half(vpos_clip).W; + andi $s3, $s2, 1799 ## L:432 | 153 | t0 = codes & 0x707; + vrcpl $v25.e7, $v20.e7 ## L:691 | ^ | vinvw.W = invert_half(vpos_clip).W; + srl $s5, $s3, 5 ## L:433 | 154 | t1 = t0 >> 5; + vrcph $v24.e7, $v00.e7 ## L:691 | ^ | vinvw.W = invert_half(vpos_clip).W; + nor $k0, $s3, $s5 ## L:447 | 155 | result = t0 ~| t1; + ssv $v20, 6, 18, $s7 ## L:686 | 156 | @Barrier("st_w0") store(vpos_clip.w, vtx_out0_ptr, 16); ## Barrier: 0x800 + ssv $v19, 14, 16, $t2 ## L:687 | 157 | @Barrier("st_w1") store(vpos_clip.W, vtx_out1_ptr, 16); ## Barrier: 0x1000 + vmudl $v29, $v20, $v25.h3 ## L:696 | ^ | vpos_clip *= vinvw.wwwwWWWW; + ssv $v24, 6, 20, $s7 ## L:693 | 158 | @Barrier("st_iw0") store(vinvw.w, vtx_out0_ptr, 20); ## Barrier: 0x2000 + vmadm $v29, $v19, $v25.h3 ## L:696 | ^ | vpos_clip *= vinvw.wwwwWWWW; + ssv $v20, 14, 18, $t2 ## L:687 | 159 | @Barrier("st_w1") store(vpos_clip.W, vtx_out1_ptr, 16); ## Barrier: 0x1000 + vmadn $v20, $v20, $v24.h3 ## L:696 | ^ | vpos_clip *= vinvw.wwwwWWWW; + ssv $v25, 6, 22, $s7 ## L:693 | 160 | @Barrier("st_iw0") store(vinvw.w, vtx_out0_ptr, 20); ## Barrier: 0x2000 + vmadh $v19, $v19, $v24.h3 ## L:696 | ^ | vpos_clip *= vinvw.wwwwWWWW; + ssv $v24, 14, 20, $t2 ## L:694 | 161 | @Barrier("st_iw1") store(vinvw.W, vtx_out1_ptr, 20); ## Barrier: 0x4000 + ssv $v25, 14, 22, $t2 ## L:694 | 162 | @Barrier("st_iw1") store(vinvw.W, vtx_out1_ptr, 20); ## Barrier: 0x4000 + vmudh $v29, $v23, $v30.e7 ## L:700 | ^ | VTEMP = vviewoff:sint * 1; + vmadn $v20, $v20, $v22.v ## L:701 | 163 | vpos_clip = vpos_clip +* vviewscale; + beq $t0, $zero, LABEL_gl_pipeline_0004 ## L:707 | ^ | if (has_points != 0) + vmadh $v19, $v19, $v22.v ## L:701 | *165 | vpos_clip = vpos_clip +* vviewscale; + ori $s0, $zero, %lo(MATRICES_MV) ## L:710 | 166 | u16 addr = MATRICES_MV; + ldv $v02, 0, 32, $s0 ## L:467 | 167 | m0:ufract = load(address, 0x20).xyzwxyzw; + ldv $v01, 0, 0, $s0 ## L:466 | 168 | m0:sint = load(address, 0x00).xyzwxyzw; + ldv $v04, 0, 40, $s0 ## L:469 | 169 | m1:ufract = load(address, 0x28).xyzwxyzw; + ldv $v02, 8, 32, $s0 ## L:467 | 170 | m0:ufract = load(address, 0x20).xyzwxyzw; + ldv $v01, 8, 0, $s0 ## L:466 | 171 | m0:sint = load(address, 0x00).xyzwxyzw; + ldv $v06, 0, 48, $s0 ## L:471 | 172 | m2:ufract = load(address, 0x30).xyzwxyzw; + ldv $v06, 8, 48, $s0 ## L:471 | 173 | m2:ufract = load(address, 0x30).xyzwxyzw; + ldv $v08, 0, 56, $s0 ## L:473 | 174 | m3:ufract = load(address, 0x38).xyzwxyzw; + vmudn $v29, $v02, $v14.h0 ## L:713 | ^ | VTEMP = vmvp0 * vpos.xxxxXXXX; + ldv $v04, 8, 40, $s0 ## L:469 | 175 | m1:ufract = load(address, 0x28).xyzwxyzw; + ldv $v03, 0, 8, $s0 ## L:468 | 176 | m1:sint = load(address, 0x08).xyzwxyzw; + ldv $v03, 8, 8, $s0 ## L:468 | 177 | m1:sint = load(address, 0x08).xyzwxyzw; + ldv $v08, 8, 56, $s0 ## L:473 | 178 | m3:ufract = load(address, 0x38).xyzwxyzw; + ldv $v05, 0, 16, $s0 ## L:470 | 179 | m2:sint = load(address, 0x10).xyzwxyzw; + ldv $v05, 8, 16, $s0 ## L:470 | 180 | m2:sint = load(address, 0x10).xyzwxyzw; + vmadh $v29, $v01, $v14.h0 ## L:713 | ^ | VTEMP = vmvp0 * vpos.xxxxXXXX; + ldv $v07, 0, 24, $s0 ## L:472 | 181 | m3:sint = load(address, 0x18).xyzwxyzw; + vmadn $v29, $v04, $v14.h1 ## L:714 | ^ | VTEMP = vmvp1 +* vpos.yyyyYYYY; + ldv $v07, 8, 24, $s0 ## L:472 | 182 | m3:sint = load(address, 0x18).xyzwxyzw; + vmadh $v29, $v03, $v14.h1 ## L:714 | ^ | VTEMP = vmvp1 +* vpos.yyyyYYYY; + vmadn $v29, $v06, $v14.h2 ## L:715 | 183 | VTEMP = vmvp2 +* vpos.zzzzZZZZ; + vmadh $v29, $v05, $v14.h2 ## L:715 | 184 | VTEMP = vmvp2 +* vpos.zzzzZZZZ; + vmadn $v29, $v08, $v30.e2 ## L:716 | 185 | vpos = vmvp3 +* 0x20; + vmadh $v14, $v07, $v30.e2 ## L:716 | 186 | vpos = vmvp3 +* 0x20; + LABEL_gl_pipeline_0004: + ori $at, $zero, %lo(LIGHTING_AMBIENT) ## L:719 | ^ | vrgba = load(LIGHTING_AMBIENT).xyzwxyzw; + ldv $v17, 0, 0, $at ## L:719 | 187 | vrgba = load(LIGHTING_AMBIENT).xyzwxyzw; + ldv $v17, 8, 0, $at ## L:719 | 188 | vrgba = load(LIGHTING_AMBIENT).xyzwxyzw; + addiu $at, $k1, MG_SCRATCH_MEM ## L:721 | 189 | vec16 vdiffuse = load(mat_ptr_diffuse, MG_SCRATCH_MEM); + lqv $v22, 0, 0, $at ## L:721 | 190 | vec16 vdiffuse = load(mat_ptr_diffuse, MG_SCRATCH_MEM); + addiu $at, $sp, MG_SCRATCH_MEM ## L:722 | 191 | vec16 vambient = load(mat_ptr_ambient, MG_SCRATCH_MEM); + lqv $v23, 0, 0, $at ## L:722 | 192 | vec16 vambient = load(mat_ptr_ambient, MG_SCRATCH_MEM); + addiu $at, $fp, MG_SCRATCH_MEM ## L:723 | 193 | vec16 vemissive = load(mat_ptr_emissive, MG_SCRATCH_MEM); + lqv $v24, 0, 0, $at ## L:723 | 194 | vec16 vemissive = load(mat_ptr_emissive, MG_SCRATCH_MEM); + lbu $s0, %lo(LIGHTING_COUNT + 0) ## L:730 | 195 | u8 light_count = load(LIGHTING_COUNT); + ori $s1, $zero, %lo(LIGHTING_LIGHTS) ## L:732 | **198 | u16 light_ptr = LIGHTING_LIGHTS; + vmudh $v29, $v24, $v30.e7 ## L:725 | ^ | VTEMP = vemissive:sint * 1; + beq $s0, $zero, LIGHT_END ## L:733 | 199 | if (light_count == 0) goto LIGHT_END; + vmacf $v17, $v17, $v23.v ## L:726 | *201 | vrgba:sfract = vrgba:sfract +* vambient:sfract; + LIGHT_LOOP: + addiu $s2, $s1, 14 ## L:736 | 202 | u16 amb_ptr = light_ptr + 14; + ldv $v25, 0, 8, $s1 ## L:738 | 203 | vec16 vlcol = load(light_ptr, 8).xyzwxyzw; + ldv $v24, 0, 0, $s2 ## L:737 | 204 | vec16 vlambient = load(amb_ptr, 0).xyzwxyzw; + lh $s3, 6($s1) ## L:743 | 205 | s16 light_w = load(light_ptr, 6); + ldv $v24, 8, 0, $s2 ## L:737 | 206 | vec16 vlambient = load(amb_ptr, 0).xyzwxyzw; + ldv $v25, 8, 8, $s1 ## L:738 | 207 | vec16 vlcol = load(light_ptr, 8).xyzwxyzw; + ldv $v26, 0, 0, $s1 ## L:739 | 208 | vec16 vlpos = load(light_ptr, 0).xyzwxyzw; + ldv $v26, 8, 0, $s1 ## L:739 | 209 | vec16 vlpos = load(light_ptr, 0).xyzwxyzw; + beq $s3, $zero, LABEL_gl_pipeline_0006 ## L:744 | 210 | if (light_w != 0) + vmulf $v25, $v25, $v22.v ## L:741 | *212 | vlcol:sfract *= vdiffuse; + vsubc $v26, $v26, $v14.v ## L:758 | 213 | vlpos -= vpos; + vmudh $v04, $v26, $v26.v ## L:759 | ***217 | vec32 vsqdist = vlpos * vlpos; + vsar $v04, COP2_ACC_MD ## L:759 | 218 | vec32 vsqdist = vlpos * vlpos; + vsar $v03, COP2_ACC_HI ## L:759 | 219 | vec32 vsqdist = vlpos * vlpos; + vaddc $v06, $v04, $v04.h1 ## L:760 | **222 | vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + vadd $v05, $v03, $v03.h1 ## L:760 | 223 | vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + vaddc $v04, $v06, $v04.h2 ## L:761 | **226 | vsqdist = vtmp + vsqdist.zzzzZZZZ; + addiu $s5, $s1, 20 ## L:752 | ^ | u16 att_ptr = light_ptr + 20; + ldv $v01, 0, 0, $s5 ## L:754 | 227 | vatten:sint = load(att_ptr, 0).xyzwxyzw; + vadd $v03, $v05, $v03.h2 ## L:761 | ^ | vsqdist = vtmp + vsqdist.zzzzZZZZ; + vrsqh $v05.e0, $v03.e0 ## L:763 | ***231 | vtmp.x = invert_half_sqrt(vsqdist).x; + ldv $v01, 8, 0, $s5 ## L:754 | ^ | vatten:sint = load(att_ptr, 0).xyzwxyzw; + addiu $s5, $s5, 6 ## L:755 | 232 | att_ptr += 6; + vrsql $v06.e0, $v04.e0 ## L:763 | ^ | vtmp.x = invert_half_sqrt(vsqdist).x; + ldv $v02, 0, 0, $s5 ## L:756 | 233 | vatten:ufract = load(att_ptr, 0).xyzwxyzw; + vrsqh $v05.e0, $v03.e4 ## L:764 | ^ | vtmp.X = invert_half_sqrt(vsqdist).X; + vrsql $v06.e4, $v04.e4 ## L:764 | 234 | vtmp.X = invert_half_sqrt(vsqdist).X; + vrsqh $v05.e4, $v00.e0 ## L:764 | 235 | vtmp.X = invert_half_sqrt(vsqdist).X; + vmudl $v29, $v06, $v04.v ## L:766 | **238 | vec32 vdist = vtmp * vsqdist; + ldv $v02, 8, 0, $s5 ## L:756 | ^ | vatten:ufract = load(att_ptr, 0).xyzwxyzw; + ori $s5, $zero, %lo(MATRICES_MVP) ## L:786 | 239 | u16 addr = MATRICES_MVP; + vmadm $v29, $v05, $v04.v ## L:766 | ^ | vec32 vdist = vtmp * vsqdist; + vmadn $v08, $v06, $v03.v ## L:766 | 240 | vec32 vdist = vtmp * vsqdist; + vmadh $v07, $v05, $v03.v ## L:766 | 241 | vec32 vdist = vtmp * vsqdist; + vmudm $v29, $v26, $v06.h0 ## L:768 | 242 | vlpos *= vtmp.xxxxXXXX; + vmadh $v26, $v26, $v05.h0 ## L:768 | 243 | vlpos *= vtmp.xxxxXXXX; + ldv $v05, 0, 16, $s5 ## L:470 | ^ | m2:sint = load(address, 0x10).xyzwxyzw; + ldv $v06, 0, 48, $s5 ## L:471 | 244 | m2:ufract = load(address, 0x30).xyzwxyzw; + vmudn $v29, $v02, $v30.e7 ## L:770 | ^ | VTEMP = vatten * 1; + ldv $v05, 8, 16, $s5 ## L:470 | 245 | m2:sint = load(address, 0x10).xyzwxyzw; + vmadh $v29, $v01, $v30.e7 ## L:770 | ^ | VTEMP = vatten * 1; + vmadl $v29, $v08, $v02.h1 ## L:771 | 246 | VTEMP = vdist +* vatten.yyyyYYYY; + vmadm $v29, $v07, $v02.h1 ## L:771 | 247 | VTEMP = vdist +* vatten.yyyyYYYY; + vmadn $v29, $v08, $v01.h1 ## L:771 | 248 | VTEMP = vdist +* vatten.yyyyYYYY; + vmadh $v29, $v07, $v01.h1 ## L:771 | 249 | VTEMP = vdist +* vatten.yyyyYYYY; + ldv $v07, 0, 24, $s5 ## L:472 | ^ | m3:sint = load(address, 0x18).xyzwxyzw; + vmadl $v29, $v04, $v02.h2 ## L:772 | 250 | vatten = vsqdist +* vatten.zzzzZZZZ; + ldv $v08, 8, 56, $s5 ## L:473 | ^ | m3:ufract = load(address, 0x38).xyzwxyzw; + vmadm $v29, $v03, $v02.h2 ## L:772 | 251 | vatten = vsqdist +* vatten.zzzzZZZZ; + ldv $v07, 8, 24, $s5 ## L:472 | ^ | m3:sint = load(address, 0x18).xyzwxyzw; + vmadn $v02, $v04, $v01.h2 ## L:772 | 252 | vatten = vsqdist +* vatten.zzzzZZZZ; + ldv $v08, 0, 56, $s5 ## L:473 | ^ | m3:ufract = load(address, 0x38).xyzwxyzw; + vmadh $v01, $v03, $v01.h2 ## L:772 | 253 | vatten = vsqdist +* vatten.zzzzZZZZ; + vrcph $v01.e0, $v01.e0 ## L:774 | ***257 | vatten.x = invert_half(vatten).x; + ldv $v06, 8, 48, $s5 ## L:471 | ^ | m2:ufract = load(address, 0x30).xyzwxyzw; + ldv $v04, 8, 40, $s5 ## L:469 | 258 | m1:ufract = load(address, 0x28).xyzwxyzw; + vrcpl $v02.e0, $v02.e0 ## L:774 | ^ | vatten.x = invert_half(vatten).x; + vrcph $v01.e0, $v01.e4 ## L:775 | **261 | vatten.X = invert_half(vatten).X; + ldv $v03, 8, 8, $s5 ## L:468 | ^ | m1:sint = load(address, 0x08).xyzwxyzw; + vrcpl $v02.e4, $v02.e4 ## L:775 | 262 | vatten.X = invert_half(vatten).X; + ldv $v04, 0, 40, $s5 ## L:469 | ^ | m1:ufract = load(address, 0x28).xyzwxyzw; + vrcph $v01.e4, $v00.e4 ## L:775 | 263 | vatten.X = invert_half(vatten).X; + ldv $v03, 0, 8, $s5 ## L:468 | ^ | m1:sint = load(address, 0x08).xyzwxyzw; + vmudm $v29, $v25, $v02.h0 ## L:777 | **266 | vlcol *= vatten.xxxxXXXX; + ldv $v02, 0, 32, $s5 ## L:467 | ^ | m0:ufract = load(address, 0x20).xyzwxyzw; + vmadh $v25, $v25, $v01.h0 ## L:777 | 267 | vlcol *= vatten.xxxxXXXX; + ldv $v01, 0, 0, $s5 ## L:466 | ^ | m0:sint = load(address, 0x00).xyzwxyzw; + ldv $v02, 8, 32, $s5 ## L:467 | 268 | m0:ufract = load(address, 0x20).xyzwxyzw; + ldv $v01, 8, 0, $s5 ## L:466 | 269 | m0:sint = load(address, 0x00).xyzwxyzw; + LABEL_gl_pipeline_0006: + vmulf $v26, $v26, $v15.v ## L:791 | ^ | vlpos *= vnorm:sfract; + addiu $s1, $s1, 32 ## L:800 | 270 | light_ptr += 32; + vmudn $v29, $v24, $v23.v ## L:792 | ^ | VTEMP = vlambient * vambient; + addiu $s0, $s0, 65535 ## L:801 | **273 | light_count -= 1; + vmacf $v29, $v25, $v26.h0 ## L:793 | ^ | VTEMP = vlcol:sfract +* vlpos:sfract.xxxxXXXX; + vmacf $v29, $v25, $v26.h1 ## L:794 | 274 | VTEMP = vlcol:sfract +* vlpos:sfract.yyyyYYYY; + vmacf $v25, $v25, $v26.h2 ## L:795 | 275 | vlcol = vlcol:sfract +* vlpos:sfract.zzzzZZZZ; + vge $v25, $v25, $v00 ## L:796 | ***279 | vlcol = max(vlcol, VZERO); + bne $s0, $zero, LIGHT_LOOP ## L:802 | ^ | if (light_count != 0) goto LIGHT_LOOP; + vadd $v17, $v17, $v25.v ## L:798 | ****284 | vrgba:sint += vlcol; + LIGHT_END: + vmov $v17.e3, $v22.e3 ## L:806 | 285 | vrgba.w = vdiffuse.w; + ori $at, $zero, %lo(TEXTURE_MATRIX) ## L:875 | ^ | vmt0:sint = load(TEXTURE_MATRIX, 0x00).xyzwxyzw; + vmov $v17.e7, $v22.e7 ## L:807 | 286 | vrgba.W = vdiffuse.W; + ldv $v24, 0, 24, $at ## L:876 | ^ | vmt0:ufract = load(TEXTURE_MATRIX, 0x18).xyzwxyzw; + lbu $s2, %lo(FOG_MASK + 0) ## L:813 | 287 | u8 fog_mask = load(FOG_MASK); + addu $t1, $t1, $t9 ## L:907 | 288 | vtx_in1_ptr += vtx_size2; + ldv $v25, 0, 8, $at ## L:877 | 289 | vmt1:sint = load(TEXTURE_MATRIX, 0x08).xyzwxyzw; + ctc2 $s2, $vcc ## L:814 | 290 | set_vcc(fog_mask); + vmrg $v17, $v17, $v21.h2 ## L:815 | ^ | vrgba = select(vrgba, vfog.zzzzZZZZ); + ldv $v26, 0, 32, $at ## L:878 | 291 | vmt1:ufract = load(TEXTURE_MATRIX, 0x20).xyzwxyzw; + ldv $v23, 0, 0, $at ## L:875 | 292 | vmt0:sint = load(TEXTURE_MATRIX, 0x00).xyzwxyzw; + ldv $v24, 8, 24, $at ## L:876 | 293 | vmt0:ufract = load(TEXTURE_MATRIX, 0x18).xyzwxyzw; + ldv $v27, 0, 16, $at ## L:879 | 294 | vmt3:sint = load(TEXTURE_MATRIX, 0x10).xyzwxyzw; + ldv $v23, 8, 0, $at ## L:875 | 295 | vmt0:sint = load(TEXTURE_MATRIX, 0x00).xyzwxyzw; + ldv $v26, 8, 32, $at ## L:878 | 296 | vmt1:ufract = load(TEXTURE_MATRIX, 0x20).xyzwxyzw; + ldv $v25, 8, 8, $at ## L:877 | 297 | vmt1:sint = load(TEXTURE_MATRIX, 0x08).xyzwxyzw; + ldv $v28, 0, 40, $at ## L:880 | 298 | vmt3:ufract = load(TEXTURE_MATRIX, 0x28).xyzwxyzw; + ldv $v28, 8, 40, $at ## L:880 | 299 | vmt3:ufract = load(TEXTURE_MATRIX, 0x28).xyzwxyzw; + vmudn $v29, $v24, $v16.h0 ## L:882 | ^ | VTEMP = vmt0 * vtex.xxxxXXXX; + vmadh $v29, $v23, $v16.h0 ## L:882 | 300 | VTEMP = vmt0 * vtex.xxxxXXXX; + ldv $v27, 8, 16, $at ## L:879 | ^ | vmt3:sint = load(TEXTURE_MATRIX, 0x10).xyzwxyzw; + or $t3, $zero, $s7 ## L:904 | 301 | prev_out0 = vtx_out0_ptr; + vmadn $v29, $v26, $v16.h1 ## L:883 | ^ | VTEMP = vmt1 +* vtex.yyyyYYYY; + vmadh $v29, $v25, $v16.h1 ## L:883 | 302 | VTEMP = vmt1 +* vtex.yyyyYYYY; + ori $at, $zero, %lo(TEXTURE_SIZE) ## L:896 | ^ | vtex_size.xy = load(TEXTURE_SIZE).xy; + vmadn $v22, $v28, $v31.e7 ## L:884 | 303 | vtex_transformed = vmt3 +* 0x100; + LOAD_POSITION914: ldv $v14, 8, 0, $t1 ## L:914 | ^ | @AttrLoader("POSITION") vpos.XYZW = load(vtx_in1_ptr).xyzw; + vmadh $v21, $v27, $v31.e7 ## L:884 | 304 | vtex_transformed = vmt3 +* 0x100; + LOAD_COLOR916: llv $v18, 4, 0, $t1 ## L:916 | ^ | @AttrLoader("COLOR") vrgba_in.zw = load(vtx_in1_ptr).xy; + LOAD_NORMAL912: lsv $v15, 8, 0, $t1 ## L:912 | ***308 | @AttrLoader("NORMAL") vnorm.X = load(vtx_in1_ptr).x; + vrcph $v23.e0, $v21.e3 ## L:889 | ^ | vinv_tex.x = invert_half(vtex_transformed).w; + addu $s4, $s4, $t9 ## L:906 | 309 | vtx_in0_ptr += vtx_size2; + vrcpl $v24.e0, $v22.e3 ## L:889 | ^ | vinv_tex.x = invert_half(vtex_transformed).w; + LOAD_POSITION913: ldv $v14, 0, 0, $s4 ## L:913 | 310 | @AttrLoader("POSITION") vpos.xyzw = load(vtx_in0_ptr).xyzw; + vrcph $v23.e0, $v21.e7 ## L:890 | ^ | vinv_tex.X = invert_half(vtex_transformed).W; + or $t4, $zero, $t2 ## L:905 | 311 | prev_out1 = vtx_out1_ptr; + vrcpl $v24.e4, $v22.e7 ## L:890 | ^ | vinv_tex.X = invert_half(vtex_transformed).W; + LOAD_NORMAL911: lsv $v15, 0, 0, $s4 ## L:911 | 312 | @AttrLoader("NORMAL") vnorm.x = load(vtx_in0_ptr).x; + vrcph $v23.e4, $v00.e7 ## L:890 | ^ | vinv_tex.X = invert_half(vtex_transformed).W; + addiu $s7, $s7, 80 ## L:908 | **315 | vtx_out0_ptr += 80; + vmudl $v29, $v22, $v24.h0 ## L:892 | ^ | vtex_transformed *= vinv_tex.xxxxXXXX; + vmadm $v29, $v21, $v24.h0 ## L:892 | 316 | vtex_transformed *= vinv_tex.xxxxXXXX; + LOAD_COLOR915: llv $v18, 0, 0, $s4 ## L:915 | ^ | @AttrLoader("COLOR") vrgba_in.xy = load(vtx_in0_ptr).xy; + vmadn $v22, $v22, $v23.h0 ## L:892 | 317 | vtex_transformed *= vinv_tex.xxxxXXXX; + addiu $t2, $t2, 80 ## L:909 | ^ | vtx_out1_ptr += 80; + vmadh $v21, $v21, $v23.h0 ## L:892 | 318 | vtex_transformed *= vinv_tex.xxxxXXXX; + llv $v23, 0, 0, $at ## L:896 | ^ | vtex_size.xy = load(TEXTURE_SIZE).xy; + llv $v23, 8, 0, $at ## L:897 | 319 | vtex_size.XY = load(TEXTURE_SIZE).xy; + ori $at, $zero, %lo(TEXTURE_OFFSET) ## L:898 | 320 | vtex_offset.xy = load(TEXTURE_OFFSET).xy; + llv $v24, 0, 0, $at ## L:898 | 321 | vtex_offset.xy = load(TEXTURE_OFFSET).xy; + llv $v24, 8, 0, $at ## L:899 | 322 | vtex_offset.XY = load(TEXTURE_OFFSET).xy; + sltu $at, $s4, $s6 ## L:918 | ***326 | if (vtx_in0_ptr < vtx_in_end) goto VERTEX_LOOP; + vmudh $v29, $v24, $v30.e7 ## L:901 | ^ | VTEMP = vtex_offset:sint * 1; + vmadn $v29, $v22, $v23.v ## L:902 | 327 | vtex = vtex_transformed +* vtex_size; + bne $at, $zero, VERTEX_LOOP ## L:918 | ^ | if (vtx_in0_ptr < vtx_in_end) goto VERTEX_LOOP; + vmadh $v16, $v21, $v23.v ## L:902 | *329 | vtex = vtex_transformed +* vtex_size; + sdv $v19, 8, 0, $t4 ## L:925 | 330 | @Barrier("st_c1") @Barrier("st_tr1") store(vpos_clip:sint.XYZW, prev_out1, 0); ## Barrier: 0x30 + sb $t6, 6($t4) ## L:928 | 331 | @Barrier("st_c1") store(c1, prev_out1, 6); ## Barrier: 0x10 + suv $v17, 4, 8, $t4 ## L:933 | 332 | @Barrier("st_tex1") store_vec_u8(vrgba.X, prev_out1, 8); ## Barrier: 0x80 + sb $k0, 7($t4) ## L:930 | 333 | @Barrier("st_tr1") store(tr1, prev_out1, 7); ## Barrier: 0x20 + sdv $v19, 0, 0, $t3 ## L:924 | 334 | @Barrier("st_c0") @Barrier("st_tr0") store(vpos_clip:sint.xyzw, prev_out0, 0); ## Barrier: 0xC + suv $v17, 0, 8, $t3 ## L:932 | 335 | @Barrier("st_tex0") store_vec_u8(vrgba.x, prev_out0, 8); ## Barrier: 0x40 + sb $t7, 7($t3) ## L:929 | 336 | @Barrier("st_tr0") store(tr0, prev_out0, 7); ## Barrier: 0x8 + sb $t5, 6($t3) ## L:927 | 337 | @Barrier("st_c0") store(c0, prev_out0, 6); ## Barrier: 0x4 + slv $v16, 8, 12, $t4 ## L:936 | 338 | @Barrier("st_tex1") store(vtex.XY, prev_out1, 12); ## Barrier: 0x80 + j RSPQ_Loop ## L:937 | 339 | } + slv $v16, 0, 12, $t3 ## L:935 | *341 | @Barrier("st_tex0") store(vtex.xy, prev_out0, 12); ## Barrier: 0x40 + +MgEndShader + +#define zero $0 +#define v0 $2 +#define v1 $3 +#define a0 $4 +#define a1 $5 +#define a2 $6 +#define a3 $7 +#define t0 $8 +#define t1 $9 +#define t2 $10 +#define t3 $11 +#define t4 $12 +#define t5 $13 +#define t6 $14 +#define t7 $15 +#define s0 $16 +#define s1 $17 +#define s2 $18 +#define s3 $19 +#define s4 $20 +#define s5 $21 +#define s6 $22 +#define s7 $23 +#define t8 $24 +#define t9 $25 +#define k0 $26 +#define k1 $27 +#define gp $28 +#define sp $29 +#define fp $30 +#define ra $31 + +.set at +.set macro \ No newline at end of file diff --git a/src/GL/rsp_gl_pipeline.rspl b/src/GL/rsp_gl_pipeline.rspl new file mode 100644 index 0000000000..a6ff4ef1d8 --- /dev/null +++ b/src/GL/rsp_gl_pipeline.rspl @@ -0,0 +1,573 @@ +include "rsp_magma.inc" +#include "../../include/magma_constants.h" +#include "gl_constants.h" + +//#define TRACE_VTX_LOOP 1 + +#define SCRATCH_MAT_DIFFUSE 0x30 +#define SCRATCH_MAT_AMBIENT 0x40 +#define SCRATCH_MAT_EMISSIVE 0x50 +#define SCRATCH_RGBA_IN 0x60 + +state +{ + extern u16 RSPQ_SCRATCH_MEM; + extern u16 MG_SCRATCH_MEM; + + extern vec16 MG_NORMAL_MASK[8]; + + extern u16 MG_VERTEX_CACHE; + extern u16 MG_VERTEX_CACHE_END; + + extern vec16 MG_VIEWPORT[8]; + extern vec16 MG_CLIP_FACTORS[4]; + extern vec16 MG_VERTEX_SIZE[4]; + extern u32 MG_VERTEX_BUFFER; +} + +uniform MATRICES +{ + vec16 MATRICES_MVP[4]; + vec16 MATRICES_MV[4]; + vec16 MATRICES_NORMAL[2]; +} + +uniform TEXTURING +{ + vec16 TEXTURE_MATRIX[3]; + s16 TEXTURE_SIZE[2]; + s16 TEXTURE_OFFSET[2]; +} + +uniform LIGHTING +{ + u8 LIGHTING_LIGHTS[GLP_LIGHT_SIZE][LIGHT_COUNT]; + s16 LIGHTING_AMBIENT[3]; + u8 LIGHTING_HAS_POINTS; + u8 LIGHTING_COUNT; + s16 MATERIAL_DIFFUSE[4]; + s16 MATERIAL_AMBIENT[3]; + u16 MATERIAL_FLAGS; + s16 MATERIAL_EMISSIVE[3]; +} + +uniform FOG +{ + s16 FOG_PARAMS[3]; + u8 FOG_MASK; +} + +attribute s16 POSITION[3]; +attribute s16 NORMAL?; +attribute u32 COLOR?; +attribute s16 TEXCOORD[2]?; + +macro __pack_clip_codes(u16 codes, u16 t0, u16 t1) +{ + t0 = codes & 0x707; + t1 = t0 >> 5; +} + +macro pack_clip_codes(u8 result, u16 codes) +{ + u16 t0, t1; + __pack_clip_codes(codes, t0, t1); + result = t0 | t1; +} + +macro pack_clip_codes_inv(u8 result, u16 codes) +{ + u16 t0, t1; + __pack_clip_codes(codes, t0, t1); + result = t0 ~| t1; +} + +macro pack_clip_codes2(u8 result0, u8 result1, u16 codes) +{ + u16 codes2 = codes >> 4; + pack_clip_codes(result0, codes); + pack_clip_codes(result1, codes2); +} + +macro pack_clip_codes2_inv(u8 result0, u8 result1, u16 codes) +{ + u16 codes2 = codes >> 4; + pack_clip_codes_inv(result0, codes); + pack_clip_codes_inv(result1, codes2); +} + +macro load_mat4x4(vec32 m0, vec32 m1, vec32 m2, vec32 m3, u16 address) +{ + m0:sint = load(address, 0x00).xyzwxyzw; + m0:ufract = load(address, 0x20).xyzwxyzw; + m1:sint = load(address, 0x08).xyzwxyzw; + m1:ufract = load(address, 0x28).xyzwxyzw; + m2:sint = load(address, 0x10).xyzwxyzw; + m2:ufract = load(address, 0x30).xyzwxyzw; + m3:sint = load(address, 0x18).xyzwxyzw; + m3:ufract = load(address, 0x38).xyzwxyzw; +} + +shader gl_pipeline() +{ + u16<$t8> vtx_size; + u16<$t9> vtx_size2; + u16<$s4> vtx_in0_ptr; + u16<$s6> vtx_in_end; + u16<$s7> vtx_out0_ptr; + + { + u32 inputs_ptr = get_cmd_address(0x2); + vec16 vvtx_size = load(MG_VERTEX_SIZE).xyzw; + vec16 vinputs = load(inputs_ptr).xyzw; + + vec32 vproducts = vinputs * vvtx_size; + @Barrier("inputs0") store(vproducts:ufract.xyzw, RSPQ_SCRATCH_MEM); + @Barrier("inputs1") store(vproducts.x, RSPQ_SCRATCH_MEM, 0x8); + } + + { + s16<$t0> dma_size; + + @Barrier("inputs0") vtx_out0_ptr = load(RSPQ_SCRATCH_MEM, 0x2); + u16 vertices_size; + @Barrier("inputs0") vertices_size = load(RSPQ_SCRATCH_MEM, 0x4); + u32 buffer_offset; + @Barrier("inputs1") buffer_offset = load(RSPQ_SCRATCH_MEM, 0x8); + + u32<$s0> vtx_buffer = load(MG_VERTEX_BUFFER); + vtx_buffer += buffer_offset; + + u32 misalignment = buffer_offset & 0x7; + dma_size = vertices_size + misalignment; + dma_size += 0x7; + dma_size &= 0xFF8; + + vtx_in0_ptr = MG_VERTEX_CACHE_END; + vtx_in0_ptr -= dma_size; + + dma_in(vtx_in0_ptr, vtx_buffer, dma_size); + + vtx_size = load(MG_VERTEX_SIZE); + vtx_size2 = vtx_size * 2; + + vtx_in_end = vtx_in0_ptr + vertices_size; + vtx_out0_ptr += MG_VERTEX_CACHE; + } + + vec32<$v01> vmvp0; + vec32<$v03> vmvp1; + vec32<$v05> vmvp2; + vec32<$v07> vmvp3; + { + u16 mvpaddr = MATRICES_MVP; + load_mat4x4(vmvp0, vmvp1, vmvp2, vmvp3, mvpaddr); + } + + vec16 vmn0, vmn1, vmn2; + vmn0 = load(MATRICES_NORMAL, 0x00).xyzwxyzw; + vmn1 = load(MATRICES_NORMAL, 0x08).xyzwxyzw; + vmn2 = load(MATRICES_NORMAL, 0x10).xyzwxyzw; + + vec16 vnormmask = load(MG_NORMAL_MASK,0x0).xyzwxyzw; + vec16 vnormfactor = load(MG_NORMAL_MASK,0x8).xyzwxyzw; + + #ifndef ENABLE_ENV_MAP + u8 has_points = load(LIGHTING_HAS_POINTS); + #endif + + u16 vtx_in1_ptr = vtx_in0_ptr + vtx_size; + u16 vtx_out1_ptr = vtx_out0_ptr + MG_VTX_SIZE; + + u16 prev_out0 = MG_SCRATCH_MEM; + u16 prev_out1 = MG_SCRATCH_MEM; + + u8 c0, c1, tr0, tr1; + + vec16 vpos; + vec16 vnorm; + vec16 vtex; + vec16 vrgba; + vec16 vrgba_in; + vec32 vpos_clip; + + u16 mat_ptr_diffuse = SCRATCH_MAT_DIFFUSE; + u16 mat_ptr_ambient = SCRATCH_MAT_AMBIENT; + u16 mat_ptr_emissive = SCRATCH_MAT_EMISSIVE; + + { + vec16 vdiffuse = load(MATERIAL_DIFFUSE).xyzwxyzw; + vec16 vambient = load(MATERIAL_AMBIENT).xyzwxyzw; + vec16 vemissive = load(MATERIAL_EMISSIVE).xyzwxyzw; + + store(vdiffuse, MG_SCRATCH_MEM, SCRATCH_MAT_DIFFUSE); + store(vambient, MG_SCRATCH_MEM, SCRATCH_MAT_AMBIENT); + store(vemissive, MG_SCRATCH_MEM, SCRATCH_MAT_EMISSIVE); + + u16 mat_flags = load(MATERIAL_FLAGS); + u16 tmp = mat_flags & GLP_MATERIAL_FLAG_DIFFUSE; + if (tmp != 0) { + mat_ptr_diffuse = SCRATCH_RGBA_IN; + } + tmp = mat_flags & GLP_MATERIAL_FLAG_AMBIENT; + if (tmp != 0 ) { + mat_ptr_ambient = SCRATCH_RGBA_IN; + } + tmp = mat_flags & GLP_MATERIAL_FLAG_EMISSIVE; + if (tmp != 0) { + mat_ptr_emissive = SCRATCH_RGBA_IN; + } + } + + @AttrLoader("NORMAL") vnorm.x = load(vtx_in0_ptr).x; + @AttrLoader("NORMAL") vnorm.X = load(vtx_in1_ptr).x; + @AttrLoader("POSITION") vpos.xyzw = load(vtx_in0_ptr).xyzw; + @AttrLoader("POSITION") vpos.XYZW = load(vtx_in1_ptr).xyzw; + @AttrLoader("COLOR") vrgba_in.xy = load(vtx_in0_ptr).xy; + @AttrLoader("COLOR") vrgba_in.zw = load(vtx_in1_ptr).xy; + + #ifdef TRACE_VTX_LOOP + asm("emux_trace_start"); + #endif + { + VERTEX_LOOP: + + @Barrier("st_c0") @Barrier("st_tr0") store(vpos_clip:sint.xyzw, prev_out0, MG_VTX_XYZ); + @Barrier("st_c1") @Barrier("st_tr1") store(vpos_clip:sint.XYZW, prev_out1, MG_VTX_XYZ); + + @Barrier("st_c0") store(c0, prev_out0, MG_VTX_CLIP_CODE); + @Barrier("st_c1") store(c1, prev_out1, MG_VTX_CLIP_CODE); + @Barrier("st_tr0") store(tr0, prev_out0, MG_VTX_TR_CODE); + @Barrier("st_tr1") store(tr1, prev_out1, MG_VTX_TR_CODE); + + @Barrier("st_tex0") store_vec_u8(vrgba.x, prev_out0, MG_VTX_RGBA); + @Barrier("st_tex1") store_vec_u8(vrgba.X, prev_out1, MG_VTX_RGBA); + + @Barrier("st_tex0") store(vtex.xy, prev_out0, MG_VTX_ST); + @Barrier("st_tex1") store(vtex.XY, prev_out1, MG_VTX_ST); + + @Barrier("unpack_col") store(vrgba_in.xyzw, RSPQ_SCRATCH_MEM); + @Barrier("unpack_col") vrgba_in = load_vec_u8(RSPQ_SCRATCH_MEM); + store(vrgba_in, MG_SCRATCH_MEM, SCRATCH_RGBA_IN); + + #ifndef ENABLE_ENV_MAP + @Barrier("st_cp0") @Barrier("st_cp1") @Barrier("st_w0") @Barrier("st_w1") @Barrier("st_iw0") @Barrier("st_iw1") + @AttrLoader("TEXCOORD") vtex.xy = load(vtx_in0_ptr).xy; + + @Barrier("st_cp0") @Barrier("st_cp1") @Barrier("st_w0") @Barrier("st_w1") @Barrier("st_iw0") @Barrier("st_iw1") + @AttrLoader("TEXCOORD") vtex.XY = load(vtx_in1_ptr).xy; + #endif + + // Eye space normals + vnorm = vnormmask & vnorm.xxxxXXXX; + vnorm *= vnormfactor; + + // Clip space position + VTEMP = vmvp0 * vpos.xxxxXXXX; + VTEMP = vmvp1 +* vpos.yyyyYYYY; + VTEMP = vmvp2 +* vpos.zzzzZZZZ; + vpos_clip = vmvp3 +* 0x20; + + VTEMP = vmn0:sfract * vnorm:sfract.xxxxXXXX; + VTEMP = vmn1:sfract +* vnorm:sfract.yyyyYYYY; + vnorm = vmn2:sfract +* vnorm:sfract.zzzzZZZZ; + + #ifdef ENABLE_NORMALIZE + { + vec32 vsqdist = vnorm * vnorm; + vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + vsqdist = vtmp + vsqdist.zzzzZZZZ; + + vec32 vinvdist; + vinvdist.x = invert_half_sqrt(vsqdist).x; + vinvdist.X = invert_half_sqrt(vsqdist).X; + + vnorm *= vinvdist.xxxxXXXX; + } + #endif + + { // Clip codes + + vec16 vclip_factors = load(MG_CLIP_FACTORS).xyzwxyzw; + vec32 vguard = vpos_clip * vclip_factors; + u16 clip_codes = clip(vguard, vguard.wwwwWWWW); + pack_clip_codes2(c0, c1, clip_codes); + + // Trivial reject codes + u16 tr_codes = clip(vpos_clip, vpos_clip.wwwwWWWW); + pack_clip_codes2_inv(tr0, tr1, tr_codes); + } + + @Barrier("st_cp0") store(vpos_clip.xyzw, vtx_out0_ptr, MG_VTX_CS_POSi); + @Barrier("st_cp1") store(vpos_clip.XYZW, vtx_out1_ptr, MG_VTX_CS_POSi); + + vec16 vfog; + { // Fog + vec16 vfog_parms = load(FOG_PARAMS).xyzwxyzw; + vec16 vtmp:ufract = vpos_clip:ufract + vfog_parms:ufract.yyyyYYYY; + vfog:sint = vpos_clip:sint + vfog_parms:sint.xxxxXXXX; + + VTEMP = vtmp:ufract * vfog_parms:sint.zzzzZZZZ; + vfog = vfog:sint +* vfog_parms:sint.zzzzZZZZ; + vfog = max(VZERO, vfog.zzzzZZZZ); + } + + vec16 vviewscale = load(MG_VIEWPORT, 0).xyzwxyzw; + vec16 vviewoff = load(MG_VIEWPORT, 8).xyzwxyzw; + + vpos_clip *= vviewscale:sfract.wwwwWWWW; + + // Screen space position + normalized W + @Barrier("st_w0") store(vpos_clip.w, vtx_out0_ptr, MG_VTX_Wi); + @Barrier("st_w1") store(vpos_clip.W, vtx_out1_ptr, MG_VTX_Wi); + + vec32 vinvw; + vinvw.w = invert_half(vpos_clip).w; + vinvw.W = invert_half(vpos_clip).W; + + @Barrier("st_iw0") store(vinvw.w, vtx_out0_ptr, MG_VTX_INVWi); + @Barrier("st_iw1") store(vinvw.W, vtx_out1_ptr, MG_VTX_INVWi); + + vpos_clip *= vinvw.wwwwWWWW; + + undef vinvw; + + VTEMP = vviewoff:sint * 1; + vpos_clip = vpos_clip +* vviewscale; + + undef vviewscale; + undef vviewoff; + + #ifndef ENABLE_ENV_MAP + if (has_points != 0) + #endif + { + u16 addr = MATRICES_MV; + load_mat4x4(vmvp0, vmvp1, vmvp2, vmvp3, addr); + + VTEMP = vmvp0 * vpos.xxxxXXXX; + VTEMP = vmvp1 +* vpos.yyyyYYYY; + VTEMP = vmvp2 +* vpos.zzzzZZZZ; + vpos = vmvp3 +* 0x20; + } + + vrgba = load(LIGHTING_AMBIENT).xyzwxyzw; + + vec16 vdiffuse = load(mat_ptr_diffuse, MG_SCRATCH_MEM); + vec16 vambient = load(mat_ptr_ambient, MG_SCRATCH_MEM); + vec16 vemissive = load(mat_ptr_emissive, MG_SCRATCH_MEM); + + VTEMP = vemissive:sint * 1; + vrgba:sfract = vrgba:sfract +* vambient:sfract; + + undef vemissive; + + u8 light_count = load(LIGHTING_COUNT); + + u16 light_ptr = LIGHTING_LIGHTS; + if (light_count == 0) goto LIGHT_END; + { + LIGHT_LOOP: + u16 amb_ptr = light_ptr + GLP_LIGHT_AMBIENT; + vec16 vlambient = load(amb_ptr, 0).xyzwxyzw; + vec16 vlcol = load(light_ptr, GLP_LIGHT_DIFFUSE).xyzwxyzw; + vec16 vlpos = load(light_ptr, GLP_LIGHT_POSITION).xyzwxyzw; + + vlcol:sfract *= vdiffuse; + + s16 light_w = load(light_ptr, GLP_LIGHT_POSITIONW); + if (light_w != 0) + { + undef vmvp0; + undef vmvp1; + undef vmvp2; + undef vmvp3; + + { + u16 att_ptr = light_ptr + GLP_LIGHT_ATT_INT; + vec32 vatten; + vatten:sint = load(att_ptr, 0).xyzwxyzw; + att_ptr += 6; + vatten:ufract = load(att_ptr, 0).xyzwxyzw; + + vlpos -= vpos; + vec32 vsqdist = vlpos * vlpos; + vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + vsqdist = vtmp + vsqdist.zzzzZZZZ; + + vtmp.x = invert_half_sqrt(vsqdist).x; + vtmp.X = invert_half_sqrt(vsqdist).X; + + vec32 vdist = vtmp * vsqdist; + + vlpos *= vtmp.xxxxXXXX; + + VTEMP = vatten * 1; + VTEMP = vdist +* vatten.yyyyYYYY; + vatten = vsqdist +* vatten.zzzzZZZZ; + + vatten.x = invert_half(vatten).x; + vatten.X = invert_half(vatten).X; + + vlcol *= vatten.xxxxXXXX; + } + + vec32<$v01> vmvp0; + vec32<$v03> vmvp1; + vec32<$v05> vmvp2; + vec32<$v07> vmvp3; + + #ifndef ENABLE_ENV_MAP + u16 addr = MATRICES_MVP; + load_mat4x4(vmvp0, vmvp1, vmvp2, vmvp3, addr); + #endif + } + + vlpos *= vnorm:sfract; + VTEMP = vlambient * vambient; + VTEMP = vlcol:sfract +* vlpos:sfract.xxxxXXXX; + VTEMP = vlcol:sfract +* vlpos:sfract.yyyyYYYY; + vlcol = vlcol:sfract +* vlpos:sfract.zzzzZZZZ; + vlcol = max(vlcol, VZERO); + + vrgba:sint += vlcol; // Cast to sint to force saturated addition + + light_ptr += GLP_LIGHT_SIZE; + light_count -= 1; + if (light_count != 0) goto LIGHT_LOOP; + } + + LIGHT_END: + vrgba.w = vdiffuse.w; + vrgba.W = vdiffuse.W; + + undef vambient; + undef vdiffuse; + + { + u8 fog_mask = load(FOG_MASK); + set_vcc(fog_mask); + vrgba = select(vrgba, vfog.zzzzZZZZ); + } + + undef vfog; + + #ifdef ENABLE_ENV_MAP + + u16 addr = MATRICES_MVP; + load_mat4x4(vmvp0, vmvp1, vmvp2, vmvp3, addr); + + { // Environment mapping + vec32 vsqdist = vpos * vpos; + vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + vsqdist = vtmp + vsqdist.zzzzZZZZ; + + vtmp.x = invert_half_sqrt(vsqdist).x; + vtmp.X = invert_half_sqrt(vsqdist).X; + + vpos *= vtmp.xxxxXXXX; + undef vtmp; + + vec16 vdot = vpos:sfract * vnorm:sfract; + vec16 vtmp:sint = vdot + vdot.yyyyYYYY; + vdot:sint = vtmp + vdot.zzzzZZZZ; + undef vtmp; + vdot = min(vdot, VZERO); + vdot = VZERO - vdot; + + vec16 vzunit = VZERO; + vzunit.z = vnormmask.w; + vzunit.Z = vnormmask.w; + + VTEMP = vnorm:sfract * vdot.xxxxXXXX; + VTEMP = vnorm:sfract +* vdot.xxxxXXXX; + VTEMP = vpos:sint +* 1; + VTEMP = vzunit:sint +* 1; + undef vzunit; + undef vdot; + vec32 vrefl = get_acc(); + + vsqdist = vrefl * vrefl; + vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + vsqdist = vtmp + vsqdist.zzzzZZZZ; + + vtmp.x = invert_half_sqrt(vsqdist).x; + vtmp.X = invert_half_sqrt(vsqdist).X; + + vtex = 0x80; + VTEMP = vtex:sint * 1; + vtex:sint = vrefl +* vtmp.xxxxXXXX; + } + #endif + + vec32 vtex_transformed; + + { + vec32 vmt0; + vec32 vmt1; + vec32 vmt3; + + vmt0:sint = load(TEXTURE_MATRIX, 0x00).xyzwxyzw; + vmt0:ufract = load(TEXTURE_MATRIX, 0x18).xyzwxyzw; + vmt1:sint = load(TEXTURE_MATRIX, 0x08).xyzwxyzw; + vmt1:ufract = load(TEXTURE_MATRIX, 0x20).xyzwxyzw; + vmt3:sint = load(TEXTURE_MATRIX, 0x10).xyzwxyzw; + vmt3:ufract = load(TEXTURE_MATRIX, 0x28).xyzwxyzw; + + VTEMP = vmt0 * vtex.xxxxXXXX; + VTEMP = vmt1 +* vtex.yyyyYYYY; + vtex_transformed = vmt3 +* 0x100; + } + + { + vec32 vinv_tex; + vinv_tex.x = invert_half(vtex_transformed).w; + vinv_tex.X = invert_half(vtex_transformed).W; + + vtex_transformed *= vinv_tex.xxxxXXXX; + } + + vec16 vtex_size, vtex_offset; + vtex_size.xy = load(TEXTURE_SIZE).xy; + vtex_size.XY = load(TEXTURE_SIZE).xy; + vtex_offset.xy = load(TEXTURE_OFFSET).xy; + vtex_offset.XY = load(TEXTURE_OFFSET).xy; + + VTEMP = vtex_offset:sint * 1; + vtex = vtex_transformed +* vtex_size; + + prev_out0 = vtx_out0_ptr; + prev_out1 = vtx_out1_ptr; + vtx_in0_ptr += vtx_size2; + vtx_in1_ptr += vtx_size2; + vtx_out0_ptr += MG_VTX_SIZE2; + vtx_out1_ptr += MG_VTX_SIZE2; + + @AttrLoader("NORMAL") vnorm.x = load(vtx_in0_ptr).x; + @AttrLoader("NORMAL") vnorm.X = load(vtx_in1_ptr).x; + @AttrLoader("POSITION") vpos.xyzw = load(vtx_in0_ptr).xyzw; + @AttrLoader("POSITION") vpos.XYZW = load(vtx_in1_ptr).xyzw; + @AttrLoader("COLOR") vrgba_in.xy = load(vtx_in0_ptr).xy; + @AttrLoader("COLOR") vrgba_in.zw = load(vtx_in1_ptr).xy; + + if (vtx_in0_ptr < vtx_in_end) goto VERTEX_LOOP; + + #ifdef TRACE_VTX_LOOP + asm("emux_trace_stop"); + #endif + + @Barrier("st_c0") @Barrier("st_tr0") store(vpos_clip:sint.xyzw, prev_out0, MG_VTX_XYZ); + @Barrier("st_c1") @Barrier("st_tr1") store(vpos_clip:sint.XYZW, prev_out1, MG_VTX_XYZ); + + @Barrier("st_c0") store(c0, prev_out0, MG_VTX_CLIP_CODE); + @Barrier("st_c1") store(c1, prev_out1, MG_VTX_CLIP_CODE); + @Barrier("st_tr0") store(tr0, prev_out0, MG_VTX_TR_CODE); + @Barrier("st_tr1") store(tr1, prev_out1, MG_VTX_TR_CODE); + + @Barrier("st_tex0") store_vec_u8(vrgba.x, prev_out0, MG_VTX_RGBA); + @Barrier("st_tex1") store_vec_u8(vrgba.X, prev_out1, MG_VTX_RGBA); + + @Barrier("st_tex0") store(vtex.xy, prev_out0, MG_VTX_ST); + @Barrier("st_tex1") store(vtex.XY, prev_out1, MG_VTX_ST); + } +} diff --git a/src/GL/rsp_gl_pipeline_env.S b/src/GL/rsp_gl_pipeline_env.S new file mode 100644 index 0000000000..b7f676d215 --- /dev/null +++ b/src/GL/rsp_gl_pipeline_env.S @@ -0,0 +1,782 @@ +## Auto-generated file, transpiled with RSPL +#define ENABLE_ENV_MAP +#define __MAGMA_CONSTANTS +#define MG_VERTEX_CACHE_COUNT 48 +#define MG_DEFAULT_GUARD_BAND 2 +#define MG_INLINE_UNIFORM_HEADER 12 +#define MG_MAX_UNIFORM_PAYLOAD_SIZE (RSPQ_MAX_COMMAND_SIZE*4 - 12) +#define MG_CLIP_PLANE_COUNT 6 +#define MG_CLIP_PLANE_SIZE 8 +#define MG_CLIP_CACHE_SIZE 9 +#define MG_VTX_XYZ 0 +#define MG_VTX_CLIP_CODE 6 +#define MG_VTX_TR_CODE 7 +#define MG_VTX_RGBA 8 +#define MG_VTX_ST 12 +#define MG_VTX_Wi 16 +#define MG_VTX_Wf 18 +#define MG_VTX_INVWi 20 +#define MG_VTX_INVWf 22 +#define MG_VTX_CS_POSi 24 +#define MG_VTX_CS_POSf 32 +#define MG_VTX_SIZE 40 +#define MG_VTX_SIZE2 80 +#define MG_MAX_UNIFORMS_SIZE 0x200 +#define __GL_CONSTANTS +#define __MGFX_CONSTANTS +#define MGFX_ATTRIBUTE_POSITION 0 +#define MGFX_ATTRIBUTE_NORMAL 1 +#define MGFX_ATTRIBUTE_COLOR 2 +#define MGFX_ATTRIBUTE_TEXCOORD 3 +#define MGFX_BINDING_MATRICES 0 +#define MGFX_BINDING_TEXTURING 1 +#define MGFX_BINDING_LIGHTING 2 +#define MGFX_BINDING_FOG 3 +#define MGFX_LIGHT_COUNT_MAX 8 +#define MGFX_LIGHT_POSITION 0 +#define MGFX_LIGHT_POSITIONW 6 +#define MGFX_LIGHT_COLOR 8 +#define MGFX_LIGHT_INTENSITY 14 +#define MGFX_LIGHT_SIZE 16 +#define MGFX_MATRIX_SIZE 64 +#define MGFX_VTX_TEX_SHIFT 5 +#define PIPELINE_FEATURE_COUNT 2 +#define PIPELINE_COUNT (1<<2) +#define MODELVIEW_STACK_SIZE 32 +#define PROJECTION_STACK_SIZE 2 +#define TEXTURE_STACK_SIZE 2 +#define PALETTE_STACK_SIZE 1 +#define VERTEX_UNIT_COUNT 1 +#define MATRIX_PALETTE_SIZE 32 +#define MATRICES_SIZE 160 +#define VERTEX_CACHE_SIZE 32 +#define CLIPPING_PLANE_COUNT 6 +#define CLIPPING_CACHE_SIZE 9 +#define CLIPPING_PLANE_SIZE 8 +#define MATRIX_SIZE 64 +#define TEX_COORD_COUNT 4 +#define TEX_GEN_COUNT 4 +#define TEX_GEN_PLANE_COUNT 2 +#define TEX_GEN_SIZE 34 +#define TEX_GEN_STRUCT_SIZE 144 +#define TEX_GEN_INTEGER_OFFSET 0 +#define TEX_GEN_FRACTION_OFFSET 64 +#define TEX_GEN_MODE_OFFSET 128 +#define TEX_GEN_MODE_T_OFFSET 130 +#define TEX_GEN_CONST_SIZE (4*2) +#define TEX_SIZE_SHIFT 6 +#define LIGHT_COUNT 8 +#define MAX_TEXTURE_SIZE 64 +#define MAX_TEXTURE_LEVELS 7 +#define TEXTURE_IMAGE_SIZE 6 +#define TEXTURE_OBJECT_PROPS_OFFSET (6 * 7) +#define TEXTURE_LEVELS_COUNT_OFFSET ((6 * 7) + 0) +#define TEXTURE_TLUT_MODE_OFFSET ((6 * 7) + 1) +#define TEXTURE_LEVELS_BLOCK_OFFSET ((6 * 7) + 2) +#define TEXTURE_FLAGS_OFFSET ((6 * 7) + 62) +#define TEXTURE_MIN_FILTER_OFFSET ((6 * 7) + 66) +#define TEXTURE_MAG_FILTER_OFFSET ((6 * 7) + 68) +#define TEXTURE_OBJECT_SIZE ((6 * 7) + 70) +#define IMAGE_WIDTH_OFFSET 0 +#define IMAGE_HEIGHT_OFFSET 2 +#define IMAGE_INTERNAL_FORMAT_OFFSET 4 +#define TEXTURE_BILINEAR_MASK 0x001 +#define TEXTURE_INTERPOLATE_MASK 0x002 +#define TEXTURE_MIPMAP_MASK 0x100 +#define MAX_PIXEL_MAP_SIZE 32 +#define ATTRIB_TYPE_COUNT 10 +#define FLAG_DITHER (1 << 0) +#define FLAG_BLEND (1 << 1) +#define FLAG_ALPHA_TEST (1 << 2) +#define FLAG_FOG (1 << 3) +#define FLAG_SCISSOR_TEST (1 << 4) +#define FLAG_TEXTURE_1D (1 << 5) +#define FLAG_TEXTURE_2D (1 << 6) +#define FLAG_CULL_FACE (1 << 7) +#define FLAG_LIGHTING (1 << 10) +#define FLAG_COLOR_MATERIAL (1 << 11) +#define FLAG_NORMALIZE (1 << 12) +#define FLAG_MATRIX_PALETTE (1 << 14) +#define FLAG_DEPTH_TEST (1 << 16) +#define FLAG_TEXTURE_ACTIVE (1 << 17) +#define FLAG_DEPTH_MASK (1 << 18) +#define FLAG_FINAL_MTX_DIRTY (1 << 19) +#define FLAG_LIGHT0 (1 << 20) +#define FLAG_LIGHT1 (1 << 21) +#define FLAG_LIGHT2 (1 << 22) +#define FLAG_LIGHT3 (1 << 23) +#define FLAG_LIGHT4 (1 << 24) +#define FLAG_LIGHT5 (1 << 25) +#define FLAG_LIGHT6 (1 << 26) +#define FLAG_LIGHT7 (1 << 27) +#define FLAG_TEX_GEN_S (1 << 28) +#define FLAG_TEX_GEN_T (1 << 29) +#define FLAG_TEX_GEN_R (1 << 30) +#define FLAG_TEX_GEN_Q (1 << 31) +#define FLAG2_USE_RDPQ_MATERIAL (1 << 0) +#define FLAG2_USE_RDPQ_TEXTURING (1 << 1) +#define FLAG2_REDUCED_ALIASING (1 << 2) +#define FLAG2_MULTISAMPLE (1 << 3) +#define FLAG2_TEX_FLIP_T (1 << 4) +#define CLIENT_FLAG_BEGIN_END (1 << 0) +#define CLIENT_FLAG_COLOR_ARRAY (1 << 1) +#define TEX_FLAG_COMPLETE (1 << 0) +#define TEX_FLAG_UPLOAD_DIRTY (1 << 1) +#define TEX_FLAG_FORCE_COMPLETE (1 << 2) +#define TEX_FLAG_DETAIL (1 << 3) +#define DITHER_MASK (SOM_RGBDITHER_MASK | SOM_ALPHADITHER_MASK) +#define BLEND_MASK SOM_ZMODE_MASK +#define DEPTH_TEST_MASK SOM_Z_COMPARE +#define DEPTH_MASK_MASK SOM_Z_WRITE +#define POINTS_MASK (SOM_ZSOURCE_MASK | SOM_TEXTURE_PERSP) +#define ALPHA_TEST_MASK SOM_ALPHACOMPARE_MASK +#define LOAD_TILE 7 +#define GUARD_BAND_FACTOR 2 +#define MULTISAMPLE_FLAG_SHIFT 2 +#define ZMODE_BLEND_FLAG_SHIFT 10 +#define COMBINER_FLAG_CONSTANT (1 << 0) +#define COMBINER_FLAG_REPLACE (1 << 1) +#define COMBINER_FLAG_TEXTURE (1 << 2) +#define TEXTURE_ACTIVE_SHIFT 17 +#define TEX_ACTIVE_COMBINER_SHIFT (17 - 2) +#define TEX_COORD_SHIFT 3 +#define HALF_TEXEL 0x0010 +#define TEX_BILINEAR_SHIFT 13 +#define TEX_BILINEAR_OFFSET_SHIFT 4 +#define TEX_DETAIL_SHIFT 15 +#define BILINEAR_TEX_OFFSET_SHIFT 9 +#define TRICMD_ATTR_SHIFT 8 +#define TRICMD_ATTR_MASK 0x300 +#define LIGHT0_SHIFT 20 +#define TEX_GEN_S_SHIFT 28 +#define TEX_GEN_LINEAR_FLAG_SHIFT 8 +#define TEX_GEN_SPHERICAL_FLAG_SHIFT 9 +#define NEED_EYE_SPACE_SHIFT 13 +#define RDPQ_TEXTURING_MASK ((SOM_SAMPLE_MASK | SOM_TEXTURE_LOD | SOMX_LOD_INTERPOLATE | SOMX_NUMLODS_MASK | SOM_TLUT_MASK)>>32) +#define PALETTE_MATRIX_INDEX 3 +#define PALETTE_DIRTY_FLAGS_SIZE ((32+7)>>3) +#define GLP_LIGHT_POSITION 0 +#define GLP_LIGHT_POSITIONW 6 +#define GLP_LIGHT_DIFFUSE 8 +#define GLP_LIGHT_AMBIENT 14 +#define GLP_LIGHT_ATT_INT 20 +#define GLP_LIGHT_ATT_FRAC 26 +#define GLP_LIGHT_SIZE 32 +#define GLP_ATTRIBUTE_POSITION 0 +#define GLP_ATTRIBUTE_NORMAL 1 +#define GLP_ATTRIBUTE_COLOR 2 +#define GLP_ATTRIBUTE_TEXCOORD 3 +#define GLP_BINDING_MATRICES 0 +#define GLP_BINDING_TEXTURING 1 +#define GLP_BINDING_LIGHTING 2 +#define GLP_BINDING_FOG 3 +#define GLP_VTX_POS_SHIFT 5 +#define GLP_VTX_TEX_SHIFT 8 +#define GLP_MATERIAL_FLAG_DIFFUSE 0x1 +#define GLP_MATERIAL_FLAG_AMBIENT 0x2 +#define GLP_MATERIAL_FLAG_EMISSIVE 0x4 +#define SCRATCH_MAT_DIFFUSE 0x30 +#define SCRATCH_MAT_AMBIENT 0x40 +#define SCRATCH_MAT_EMISSIVE 0x50 +#define SCRATCH_RGBA_IN 0x60 +#include + +.set noreorder +.set noat +.set nomacro + +#undef zero +#undef at +#undef v0 +#undef v1 +#undef a0 +#undef a1 +#undef a2 +#undef a3 +#undef t0 +#undef t1 +#undef t2 +#undef t3 +#undef t4 +#undef t5 +#undef t6 +#undef t7 +#undef s0 +#undef s1 +#undef s2 +#undef s3 +#undef s4 +#undef s5 +#undef s6 +#undef s7 +#undef t8 +#undef t9 +#undef k0 +#undef k1 +#undef gp +#undef sp +#undef fp +#undef ra +.equ hex.$zero, 0 +.equ hex.$at, 1 +.equ hex.$v0, 2 +.equ hex.$v1, 3 +.equ hex.$a0, 4 +.equ hex.$a1, 5 +.equ hex.$a2, 6 +.equ hex.$a3, 7 +.equ hex.$t0, 8 +.equ hex.$t1, 9 +.equ hex.$t2, 10 +.equ hex.$t3, 11 +.equ hex.$t4, 12 +.equ hex.$t5, 13 +.equ hex.$t6, 14 +.equ hex.$t7, 15 +.equ hex.$s0, 16 +.equ hex.$s1, 17 +.equ hex.$s2, 18 +.equ hex.$s3, 19 +.equ hex.$s4, 20 +.equ hex.$s5, 21 +.equ hex.$s6, 22 +.equ hex.$s7, 23 +.equ hex.$t8, 24 +.equ hex.$t9, 25 +.equ hex.$k0, 26 +.equ hex.$k1, 27 +.equ hex.$gp, 28 +.equ hex.$sp, 29 +.equ hex.$fp, 30 +.equ hex.$ra, 31 +#define vco 0 +#define vcc 1 +#define vce 2 + +MgBeginShaderUniforms + MgBeginUniform MATRICES, 0 + .align 4 + MATRICES_MVP: .ds.b 64 + .align 4 + MATRICES_MV: .ds.b 64 + .align 4 + MATRICES_NORMAL: .ds.b 32 + MgEndUniform + + MgBeginUniform TEXTURING, 1 + .align 4 + TEXTURE_MATRIX: .ds.b 48 + .align 1 + TEXTURE_SIZE: .ds.b 4 + .align 1 + TEXTURE_OFFSET: .ds.b 4 + MgEndUniform + + MgBeginUniform LIGHTING, 2 + LIGHTING_LIGHTS: .ds.b 256 + .align 1 + LIGHTING_AMBIENT: .ds.b 6 + LIGHTING_HAS_POINTS: .ds.b 1 + LIGHTING_COUNT: .ds.b 1 + .align 1 + MATERIAL_DIFFUSE: .ds.b 8 + .align 1 + MATERIAL_AMBIENT: .ds.b 6 + .align 1 + MATERIAL_FLAGS: .ds.b 2 + .align 1 + MATERIAL_EMISSIVE: .ds.b 6 + MgEndUniform + + MgBeginUniform FOG, 3 + .align 1 + FOG_PARAMS: .ds.b 6 + FOG_MASK: .ds.b 1 + MgEndUniform + +MgEndShaderUniforms + +MgBeginVertexInput + MgBeginVertexAttribute 0, 0 + MgVertexAttributeLoaders LOAD_POSITION589, LOAD_POSITION590, LOAD_POSITION913, LOAD_POSITION914 + MgEndVertexAttribute + + MgBeginVertexAttribute 1, 1 + MgVertexAttributeLoaders LOAD_NORMAL587, LOAD_NORMAL588, LOAD_NORMAL911, LOAD_NORMAL912 + MgEndVertexAttribute + + MgBeginVertexAttribute 2, 1 + MgVertexAttributeLoaders LOAD_COLOR591, LOAD_COLOR592, LOAD_COLOR916, LOAD_COLOR915 + MgEndVertexAttribute + + MgBeginVertexAttribute 3, 1 + MgEndVertexAttribute + +MgEndVertexInput + +MgBeginShader + ori $at, $zero, %lo(MG_VERTEX_SIZE) ## L:486 | ^ | vec16 vvtx_size = load(MG_VERTEX_SIZE).xyzw; + ldv $v01, 0, 0, $at ## L:486 | 2 | vec16 vvtx_size = load(MG_VERTEX_SIZE).xyzw; + addiu $t0, $gp, %lo(RSPQ_DMEM_BUFFER) -6 ## L:485 | 3 | u32 inputs_ptr = get_cmd_address(0x2); + ldv $v02, 0, 0, $t0 ## L:487 | 4 | vec16 vinputs = load(inputs_ptr).xyzw; + ori $at, $zero, %lo(RSPQ_SCRATCH_MEM) ## L:490 | ***8 | @Barrier("inputs0") store(vproducts:ufract.xyzw, RSPQ_SCRATCH_MEM); ## Barrier: 0x1 + vmudh $v04, $v02, $v01.v ## L:489 | ^ | vec32 vproducts = vinputs * vvtx_size; + lw $s0, %lo(MG_VERTEX_BUFFER + 0) ## L:503 | 9 | u32<$s0> vtx_buffer = load(MG_VERTEX_BUFFER); + vsar $v03, COP2_ACC_HI ## L:489 | ^ | vec32 vproducts = vinputs * vvtx_size; + ori $s4, $zero, %lo(MG_VERTEX_CACHE_END) ## L:511 | 10 | vtx_in0_ptr = MG_VERTEX_CACHE_END; + vsar $v04, COP2_ACC_MD ## L:489 | ^ | vec32 vproducts = vinputs * vvtx_size; + ssv $v03, 0, 8, $at ## L:491 | **13 | @Barrier("inputs1") store(vproducts.x, RSPQ_SCRATCH_MEM, 0x8); ## Barrier: 0x2 + sdv $v04, 0, 0, $at ## L:490 | 14 | @Barrier("inputs0") store(vproducts:ufract.xyzw, RSPQ_SCRATCH_MEM); ## Barrier: 0x1 + ssv $v04, 0, 10, $at ## L:491 | 15 | @Barrier("inputs1") store(vproducts.x, RSPQ_SCRATCH_MEM, 0x8); ## Barrier: 0x2 + lw $t2, %lo(RSPQ_SCRATCH_MEM + 8) ## L:501 | 16 | @Barrier("inputs1") buffer_offset = load(RSPQ_SCRATCH_MEM, 0x8); ## Barrier: 0x2 + lhu $s7, %lo(RSPQ_SCRATCH_MEM + 2) ## L:497 | 17 | @Barrier("inputs0") vtx_out0_ptr = load(RSPQ_SCRATCH_MEM, 0x2); ## Barrier: 0x1 + lhu $t1, %lo(RSPQ_SCRATCH_MEM + 4) ## L:499 | 18 | @Barrier("inputs0") vertices_size = load(RSPQ_SCRATCH_MEM, 0x4); ## Barrier: 0x1 + andi $t3, $t2, 7 ## L:506 | 19 | u32 misalignment = buffer_offset & 0x7; + addu $s0, $s0, $t2 ## L:504 | 20 | vtx_buffer += buffer_offset; + addu $t0, $t1, $t3 ## L:507 | 21 | dma_size = vertices_size + misalignment; + addiu $t0, $t0, 7 ## L:508 | 22 | dma_size += 0x7; + andi $t0, $t0, 4088 ## L:509 | 23 | dma_size &= 0xFF8; + subu $s4, $s4, $t0 ## L:512 | 24 | vtx_in0_ptr -= dma_size; + addiu $t0, $t0, -1 ## L:514 | 25 | dma_in(vtx_in0_ptr, vtx_buffer, dma_size); + jal DMAExec ## L:514 | 26 | dma_in(vtx_in0_ptr, vtx_buffer, dma_size); ## Args: $t0, $t1, $s0, $s4, $t2 + addiu $t2, $zero, 12 ## L:514 | *28 | dma_in(vtx_in0_ptr, vtx_buffer, dma_size); + addiu $k0, $zero, 48 ## L:559 | 29 | u16 mat_ptr_diffuse = 0x30; + addu $s6, $s4, $t1 ## L:519 | 30 | vtx_in_end = vtx_in0_ptr + vertices_size; + addiu $sp, $zero, 80 ## L:561 | 31 | u16 mat_ptr_emissive = 0x50; + ori $t2, $zero, %lo(MG_SCRATCH_MEM) ## L:547 | 32 | u16 prev_out0 = MG_SCRATCH_MEM; + ori $t0, $zero, %lo(MATRICES_MVP) ## L:528 | 33 | u16 mvpaddr = MATRICES_MVP; + ori $at, $zero, %lo(MATRICES_NORMAL) ## L:533 | 34 | vmn0 = load(MATRICES_NORMAL, 0x00).xyzwxyzw; + ldv $v06, 0, 48, $t0 ## L:471 | 35 | m2:ufract = load(address, 0x30).xyzwxyzw; + lhu $t8, %lo(MG_VERTEX_SIZE + 0) ## L:516 | 36 | vtx_size = load(MG_VERTEX_SIZE); + ldv $v09, 0, 0, $at ## L:533 | 37 | vmn0 = load(MATRICES_NORMAL, 0x00).xyzwxyzw; + ldv $v07, 0, 24, $t0 ## L:472 | 38 | m3:sint = load(address, 0x18).xyzwxyzw; + ldv $v08, 0, 56, $t0 ## L:473 | 39 | m3:ufract = load(address, 0x38).xyzwxyzw; + ldv $v10, 0, 8, $at ## L:534 | 40 | vmn1 = load(MATRICES_NORMAL, 0x08).xyzwxyzw; + ldv $v11, 0, 16, $at ## L:535 | 41 | vmn2 = load(MATRICES_NORMAL, 0x10).xyzwxyzw; + ldv $v01, 0, 0, $t0 ## L:466 | 42 | m0:sint = load(address, 0x00).xyzwxyzw; + ldv $v11, 8, 16, $at ## L:535 | 43 | vmn2 = load(MATRICES_NORMAL, 0x10).xyzwxyzw; + ldv $v10, 8, 8, $at ## L:534 | 44 | vmn1 = load(MATRICES_NORMAL, 0x08).xyzwxyzw; + ldv $v04, 0, 40, $t0 ## L:469 | 45 | m1:ufract = load(address, 0x28).xyzwxyzw; + ldv $v01, 8, 0, $t0 ## L:466 | 46 | m0:sint = load(address, 0x00).xyzwxyzw; + ldv $v09, 8, 0, $at ## L:533 | 47 | vmn0 = load(MATRICES_NORMAL, 0x00).xyzwxyzw; + ldv $v08, 8, 56, $t0 ## L:473 | 48 | m3:ufract = load(address, 0x38).xyzwxyzw; + ldv $v05, 0, 16, $t0 ## L:470 | 49 | m2:sint = load(address, 0x10).xyzwxyzw; + ldv $v07, 8, 24, $t0 ## L:472 | 50 | m3:sint = load(address, 0x18).xyzwxyzw; + ori $at, $zero, %lo(MG_NORMAL_MASK) ## L:537 | 51 | vec16 vnormmask = load(MG_NORMAL_MASK,0x0).xyzwxyzw; + ldv $v03, 0, 8, $t0 ## L:468 | 52 | m1:sint = load(address, 0x08).xyzwxyzw; + ori $t3, $zero, %lo(MG_SCRATCH_MEM) ## L:548 | 53 | u16 prev_out1 = MG_SCRATCH_MEM; + ldv $v13, 0, 8, $at ## L:538 | 54 | vec16 vnormfactor = load(MG_NORMAL_MASK,0x8).xyzwxyzw; + lhu $fp, %lo(MATERIAL_FLAGS + 0) ## L:572 | 55 | u16 mat_flags = load(MATERIAL_FLAGS); + ldv $v02, 0, 32, $t0 ## L:467 | 56 | m0:ufract = load(address, 0x20).xyzwxyzw; + ldv $v04, 8, 40, $t0 ## L:469 | 57 | m1:ufract = load(address, 0x28).xyzwxyzw; + addiu $k1, $zero, 64 ## L:560 | 58 | u16 mat_ptr_ambient = 0x40; + ldv $v13, 8, 8, $at ## L:538 | 59 | vec16 vnormfactor = load(MG_NORMAL_MASK,0x8).xyzwxyzw; + ldv $v12, 0, 0, $at ## L:537 | 60 | vec16 vnormmask = load(MG_NORMAL_MASK,0x0).xyzwxyzw; + addiu $s7, $s7, %lo(MG_VERTEX_CACHE) ## L:520 | 61 | vtx_out0_ptr += MG_VERTEX_CACHE; + ldv $v12, 8, 0, $at ## L:537 | 62 | vec16 vnormmask = load(MG_NORMAL_MASK,0x0).xyzwxyzw; + ldv $v03, 8, 8, $t0 ## L:468 | 63 | m1:sint = load(address, 0x08).xyzwxyzw; + ori $at, $zero, %lo(MATERIAL_DIFFUSE) ## L:564 | 64 | vec16 vdiffuse = load(MATERIAL_DIFFUSE).xyzwxyzw; + ldv $v05, 8, 16, $t0 ## L:470 | 65 | m2:sint = load(address, 0x10).xyzwxyzw; + ldv $v21, 0, 0, $at ## L:564 | 66 | vec16 vdiffuse = load(MATERIAL_DIFFUSE).xyzwxyzw; + ldv $v21, 8, 0, $at ## L:564 | 67 | vec16 vdiffuse = load(MATERIAL_DIFFUSE).xyzwxyzw; + ori $at, $zero, %lo(MATERIAL_AMBIENT) ## L:565 | 68 | vec16 vambient = load(MATERIAL_AMBIENT).xyzwxyzw; + ldv $v22, 0, 0, $at ## L:565 | 69 | vec16 vambient = load(MATERIAL_AMBIENT).xyzwxyzw; + ldv $v22, 8, 0, $at ## L:565 | 70 | vec16 vambient = load(MATERIAL_AMBIENT).xyzwxyzw; + addiu $t1, $s7, 40 ## L:545 | 71 | u16 vtx_out1_ptr = vtx_out0_ptr + 40; + ori $at, $zero, %lo(MATERIAL_EMISSIVE) ## L:566 | 72 | vec16 vemissive = load(MATERIAL_EMISSIVE).xyzwxyzw; + ldv $v23, 0, 0, $at ## L:566 | 73 | vec16 vemissive = load(MATERIAL_EMISSIVE).xyzwxyzw; + ldv $v06, 8, 48, $t0 ## L:471 | 74 | m2:ufract = load(address, 0x30).xyzwxyzw; + ldv $v02, 8, 32, $t0 ## L:467 | 75 | m0:ufract = load(address, 0x20).xyzwxyzw; + ldv $v23, 8, 0, $at ## L:566 | 76 | vec16 vemissive = load(MATERIAL_EMISSIVE).xyzwxyzw; + addu $t0, $s4, $t8 ## L:544 | 77 | u16 vtx_in1_ptr = vtx_in0_ptr + vtx_size; + ori $at, $zero, %lo(MG_SCRATCH_MEM) ## L:568 | 78 | store(vdiffuse, MG_SCRATCH_MEM, 0x30); + sqv $v22, 0, 64, $at ## L:569 | 79 | store(vambient, MG_SCRATCH_MEM, 0x40); + sqv $v23, 0, 80, $at ## L:570 | 80 | store(vemissive, MG_SCRATCH_MEM, 0x50); + sqv $v21, 0, 48, $at ## L:568 | 81 | store(vdiffuse, MG_SCRATCH_MEM, 0x30); + andi $s0, $fp, 1 ## L:573 | 82 | u16 tmp = mat_flags & 0x1; + beq $s0, $zero, LABEL_gl_pipeline_0001 ## L:574 | 83 | if (tmp != 0) { + sll $t9, $t8, 1 ## L:517 | *85 | vtx_size2 = vtx_size * 2; + addiu $k0, $zero, 96 ## L:575 | 86 | mat_ptr_diffuse = 0x60; + LABEL_gl_pipeline_0001: + andi $s0, $fp, 2 ## L:577 | 87 | tmp = mat_flags & 0x2; + beq $s0, $zero, LABEL_gl_pipeline_0002 ## L:578 | 88 | if (tmp != 0 ) { + nop ## L:578 | *90 | if (tmp != 0 ) { + addiu $k1, $zero, 96 ## L:579 | 91 | mat_ptr_ambient = 0x60; + LABEL_gl_pipeline_0002: + andi $s0, $fp, 4 ## L:581 | 92 | tmp = mat_flags & 0x4; + beq $s0, $zero, LABEL_gl_pipeline_0003 ## L:582 | 93 | if (tmp != 0) { + nop ## L:582 | *95 | if (tmp != 0) { + addiu $sp, $zero, 96 ## L:583 | 96 | mat_ptr_emissive = 0x60; + LABEL_gl_pipeline_0003: + LOAD_NORMAL587: lsv $v15, 0, 0, $s4 ## L:587 | 97 | @AttrLoader("NORMAL") vnorm.x = load(vtx_in0_ptr).x; + LOAD_POSITION589: ldv $v14, 0, 0, $s4 ## L:589 | 98 | @AttrLoader("POSITION") vpos.xyzw = load(vtx_in0_ptr).xyzw; + LOAD_NORMAL588: lsv $v15, 8, 0, $t0 ## L:588 | 99 | @AttrLoader("NORMAL") vnorm.X = load(vtx_in1_ptr).x; + LOAD_COLOR591: llv $v18, 0, 0, $s4 ## L:591 | 100 | @AttrLoader("COLOR") vrgba_in.xy = load(vtx_in0_ptr).xy; + LOAD_COLOR592: llv $v18, 4, 0, $t0 ## L:592 | 101 | @AttrLoader("COLOR") vrgba_in.zw = load(vtx_in1_ptr).xy; + LOAD_POSITION590: ldv $v14, 8, 0, $t0 ## L:590 | 102 | @AttrLoader("POSITION") vpos.XYZW = load(vtx_in1_ptr).xyzw; + VERTEX_LOOP: + ori $at, $zero, %lo(RSPQ_SCRATCH_MEM) ## L:614 | 103 | @Barrier("unpack_col") store(vrgba_in.xyzw, RSPQ_SCRATCH_MEM); ## Barrier: 0x100 + vand $v15, $v12, $v15.h0 ## L:627 | ^ | vnorm = vnormmask & vnorm.xxxxXXXX; + suv $v17, 4, 8, $t3 ## L:609 | *105 | @Barrier("st_tex1") store_vec_u8(vrgba.X, prev_out1, 8); ## Barrier: 0x80 + sdv $v19, 8, 0, $t3 ## L:601 | 106 | @Barrier("st_c1") @Barrier("st_tr1") store(vpos_clip:sint.XYZW, prev_out1, 0); ## Barrier: 0x30 + sdv $v18, 0, 0, $at ## L:614 | 107 | @Barrier("unpack_col") store(vrgba_in.xyzw, RSPQ_SCRATCH_MEM); ## Barrier: 0x100 + vmudn $v15, $v15, $v13.v ## L:628 | ^ | vnorm *= vnormfactor; + vmudn $v29, $v02, $v14.h0 ## L:631 | 108 | VTEMP = vmvp0 * vpos.xxxxXXXX; + luv $v18, 0, 0, $at ## L:615 | ^ | @Barrier("unpack_col") vrgba_in = load_vec_u8(RSPQ_SCRATCH_MEM); ## Barrier: 0x100 + sdv $v19, 0, 0, $t2 ## L:600 | 109 | @Barrier("st_c0") @Barrier("st_tr0") store(vpos_clip:sint.xyzw, prev_out0, 0); ## Barrier: 0xC + vmadh $v29, $v01, $v14.h0 ## L:631 | ^ | VTEMP = vmvp0 * vpos.xxxxXXXX; + vmadn $v29, $v04, $v14.h1 ## L:632 | 110 | VTEMP = vmvp1 +* vpos.yyyyYYYY; + ori $at, $zero, %lo(MG_SCRATCH_MEM) ## L:616 | ^ | store(vrgba_in, MG_SCRATCH_MEM, 0x60); + vmadh $v29, $v03, $v14.h1 ## L:632 | *112 | VTEMP = vmvp1 +* vpos.yyyyYYYY; + sqv $v18, 0, 96, $at ## L:616 | ^ | store(vrgba_in, MG_SCRATCH_MEM, 0x60); + vmadn $v29, $v06, $v14.h2 ## L:633 | 113 | VTEMP = vmvp2 +* vpos.zzzzZZZZ; + sb $t4, 6($t2) ## L:603 | ^ | @Barrier("st_c0") store(c0, prev_out0, 6); ## Barrier: 0x4 + vmadh $v29, $v05, $v14.h2 ## L:633 | 114 | VTEMP = vmvp2 +* vpos.zzzzZZZZ; + ori $at, $zero, %lo(MG_CLIP_FACTORS) ## L:656 | ^ | vec16 vclip_factors = load(MG_CLIP_FACTORS).xyzwxyzw; + ldv $v21, 0, 0, $at ## L:656 | 115 | vec16 vclip_factors = load(MG_CLIP_FACTORS).xyzwxyzw; + vmadn $v20, $v08, $v30.e2 ## L:634 | ^ | vpos_clip = vmvp3 +* 0x20; + vmadh $v19, $v07, $v30.e2 ## L:634 | 116 | vpos_clip = vmvp3 +* 0x20; + sb $t6, 7($t2) ## L:605 | ^ | @Barrier("st_tr0") store(tr0, prev_out0, 7); ## Barrier: 0x8 + vmulf $v29, $v09, $v15.h0 ## L:636 | 117 | VTEMP = vmn0:sfract * vnorm:sfract.xxxxXXXX; + ldv $v21, 8, 0, $at ## L:656 | ^ | vec16 vclip_factors = load(MG_CLIP_FACTORS).xyzwxyzw; + vmacf $v29, $v10, $v15.h1 ## L:637 | 118 | VTEMP = vmn1:sfract +* vnorm:sfract.yyyyYYYY; + slv $v16, 8, 12, $t3 ## L:612 | ^ | @Barrier("st_tex1") store(vtex.XY, prev_out1, 12); ## Barrier: 0x80 + ori $at, $zero, %lo(FOG_PARAMS) ## L:671 | 119 | vec16 vfog_parms = load(FOG_PARAMS).xyzwxyzw; + sb $t7, 7($t3) ## L:606 | 120 | @Barrier("st_tr1") store(tr1, prev_out1, 7); ## Barrier: 0x20 + vmacf $v15, $v11, $v15.h2 ## L:638 | ^ | vnorm = vmn2:sfract +* vnorm:sfract.zzzzZZZZ; + vmudn $v23, $v20, $v21.v ## L:657 | 121 | vec32 vguard = vpos_clip * vclip_factors; + suv $v17, 0, 8, $t2 ## L:608 | ^ | @Barrier("st_tex0") store_vec_u8(vrgba.x, prev_out0, 8); ## Barrier: 0x40 + sdv $v19, 0, 24, $s7 ## L:666 | 122 | @Barrier("st_cp0") store(vpos_clip.xyzw, vtx_out0_ptr, 24); ## Barrier: 0x200 + vmadh $v22, $v19, $v21.v ## L:657 | ^ | vec32 vguard = vpos_clip * vclip_factors; + slv $v16, 0, 12, $t2 ## L:611 | 123 | @Barrier("st_tex0") store(vtex.xy, prev_out0, 12); ## Barrier: 0x40 + sdv $v19, 8, 24, $t1 ## L:667 | 124 | @Barrier("st_cp1") store(vpos_clip.XYZW, vtx_out1_ptr, 24); ## Barrier: 0x400 + sb $t5, 6($t3) ## L:604 | 125 | @Barrier("st_c1") store(c1, prev_out1, 6); ## Barrier: 0x10 + sdv $v20, 8, 32, $t1 ## L:667 | 126 | @Barrier("st_cp1") store(vpos_clip.XYZW, vtx_out1_ptr, 24); ## Barrier: 0x400 + vch $v29, $v22, $v22.h3 ## L:658 | ^ | u16 clip_codes = clip(vguard, vguard.wwwwWWWW); + sdv $v20, 0, 32, $s7 ## L:666 | 127 | @Barrier("st_cp0") store(vpos_clip.xyzw, vtx_out0_ptr, 24); ## Barrier: 0x200 + vcl $v29, $v23, $v23.h3 ## L:658 | ^ | u16 clip_codes = clip(vguard, vguard.wwwwWWWW); + cfc2 $fp, $vcc ## L:658 | 128 | u16 clip_codes = clip(vguard, vguard.wwwwWWWW); + ldv $v22, 0, 0, $at ## L:671 | 129 | vec16 vfog_parms = load(FOG_PARAMS).xyzwxyzw; + vch $v29, $v19, $v19.h3 ## L:662 | ^ | u16 tr_codes = clip(vpos_clip, vpos_clip.wwwwWWWW); + vcl $v29, $v20, $v20.h3 ## L:662 | 130 | u16 tr_codes = clip(vpos_clip, vpos_clip.wwwwWWWW); + ldv $v22, 8, 0, $at ## L:671 | ^ | vec16 vfog_parms = load(FOG_PARAMS).xyzwxyzw; + andi $s1, $fp, 1799 ## L:432 | 131 | t0 = codes & 0x707; + srl $s2, $s1, 5 ## L:433 | 132 | t1 = t0 >> 5; + or $t4, $s1, $s2 ## L:440 | 133 | result = t0 | t1; + srl $s0, $fp, 4 ## L:452 | 134 | u16 codes2 = codes >> 4; + vaddc $v23, $v20, $v22.h1 ## L:672 | ^ | vec16 vtmp:ufract = vpos_clip:ufract + vfog_parms:ufract.yyyyYYYY; + vadd $v21, $v19, $v22.h0 ## L:673 | 135 | vfog:sint = vpos_clip:sint + vfog_parms:sint.xxxxXXXX; + ori $fp, $zero, %lo(MATRICES_MV) ## L:710 | ^ | u16 addr = MATRICES_MV; + andi $s1, $s0, 1799 ## L:432 | 136 | t0 = codes & 0x707; + cfc2 $s0, $vcc ## L:662 | 137 | u16 tr_codes = clip(vpos_clip, vpos_clip.wwwwWWWW); + srl $s2, $s1, 5 ## L:433 | 138 | t1 = t0 >> 5; + ori $at, $zero, %lo(MG_VIEWPORT) ## L:680 | 139 | vec16 vviewscale = load(MG_VIEWPORT, 0).xyzwxyzw; + vmudn $v29, $v23, $v22.h2 ## L:675 | ^ | VTEMP = vtmp:ufract * vfog_parms:sint.zzzzZZZZ; + vmadh $v21, $v21, $v22.h2 ## L:676 | 140 | vfog = vfog:sint +* vfog_parms:sint.zzzzZZZZ; + ldv $v22, 0, 0, $at ## L:680 | ^ | vec16 vviewscale = load(MG_VIEWPORT, 0).xyzwxyzw; + ldv $v22, 8, 0, $at ## L:680 | 141 | vec16 vviewscale = load(MG_VIEWPORT, 0).xyzwxyzw; + ldv $v23, 0, 8, $at ## L:681 | 142 | vec16 vviewoff = load(MG_VIEWPORT, 8).xyzwxyzw; + ldv $v06, 0, 48, $fp ## L:471 | 143 | m2:ufract = load(address, 0x30).xyzwxyzw; + ldv $v05, 0, 16, $fp ## L:470 | 144 | m2:sint = load(address, 0x10).xyzwxyzw; + vge $v21, $v00, $v21.h2 ## L:677 | ^ | vfog = max(VZERO, vfog.zzzzZZZZ); + ldv $v08, 0, 56, $fp ## L:473 | 145 | m3:ufract = load(address, 0x38).xyzwxyzw; + vmudl $v20, $v20, $v22.h3 ## L:683 | ^ | vpos_clip *= vviewscale:sfract.wwwwWWWW; + vmadm $v19, $v19, $v22.h3 ## L:683 | 146 | vpos_clip *= vviewscale:sfract.wwwwWWWW; + or $t5, $s1, $s2 ## L:440 | ^ | result = t0 | t1; + vmadn $v20, $v00, $v00 ## L:683 | 147 | vpos_clip *= vviewscale:sfract.wwwwWWWW; + ldv $v07, 0, 24, $fp ## L:472 | ^ | m3:sint = load(address, 0x18).xyzwxyzw; + andi $s2, $s0, 1799 ## L:432 | 148 | t0 = codes & 0x707; + srl $s3, $s2, 5 ## L:433 | 149 | t1 = t0 >> 5; + ssv $v19, 14, 16, $t1 ## L:687 | 150 | @Barrier("st_w1") store(vpos_clip.W, vtx_out1_ptr, 16); ## Barrier: 0x1000 + vrcph $v24.e3, $v19.e3 ## L:690 | ^ | vinvw.w = invert_half(vpos_clip).w; + vrcpl $v25.e3, $v20.e3 ## L:690 | 151 | vinvw.w = invert_half(vpos_clip).w; + nor $t6, $s2, $s3 ## L:447 | ^ | result = t0 ~| t1; + ldv $v23, 8, 8, $at ## L:681 | 152 | vec16 vviewoff = load(MG_VIEWPORT, 8).xyzwxyzw; + ldv $v01, 0, 0, $fp ## L:466 | 153 | m0:sint = load(address, 0x00).xyzwxyzw; + vrcph $v24.e3, $v19.e7 ## L:691 | ^ | vinvw.W = invert_half(vpos_clip).W; + ldv $v05, 8, 16, $fp ## L:470 | 154 | m2:sint = load(address, 0x10).xyzwxyzw; + ori $at, $zero, %lo(LIGHTING_AMBIENT) ## L:719 | 155 | vrgba = load(LIGHTING_AMBIENT).xyzwxyzw; + vrcpl $v25.e7, $v20.e7 ## L:691 | ^ | vinvw.W = invert_half(vpos_clip).W; + vrcph $v24.e7, $v00.e7 ## L:691 | 156 | vinvw.W = invert_half(vpos_clip).W; + srl $s1, $s0, 4 ## L:459 | ^ | u16 codes2 = codes >> 4; + ldv $v04, 0, 40, $fp ## L:469 | 157 | m1:ufract = load(address, 0x28).xyzwxyzw; + ssv $v20, 14, 18, $t1 ## L:687 | 158 | @Barrier("st_w1") store(vpos_clip.W, vtx_out1_ptr, 16); ## Barrier: 0x1000 + ldv $v17, 0, 0, $at ## L:719 | 159 | vrgba = load(LIGHTING_AMBIENT).xyzwxyzw; + ssv $v19, 6, 16, $s7 ## L:686 | 160 | @Barrier("st_w0") store(vpos_clip.w, vtx_out0_ptr, 16); ## Barrier: 0x800 + vmudl $v29, $v20, $v25.h3 ## L:696 | ^ | vpos_clip *= vinvw.wwwwWWWW; + vmadm $v29, $v19, $v25.h3 ## L:696 | 161 | vpos_clip *= vinvw.wwwwWWWW; + ldv $v08, 8, 56, $fp ## L:473 | ^ | m3:ufract = load(address, 0x38).xyzwxyzw; + ssv $v20, 6, 18, $s7 ## L:686 | 162 | @Barrier("st_w0") store(vpos_clip.w, vtx_out0_ptr, 16); ## Barrier: 0x800 + ldv $v04, 8, 40, $fp ## L:469 | 163 | m1:ufract = load(address, 0x28).xyzwxyzw; + vmadn $v20, $v20, $v24.h3 ## L:696 | ^ | vpos_clip *= vinvw.wwwwWWWW; + ldv $v17, 8, 0, $at ## L:719 | 164 | vrgba = load(LIGHTING_AMBIENT).xyzwxyzw; + vmadh $v19, $v19, $v24.h3 ## L:696 | ^ | vpos_clip *= vinvw.wwwwWWWW; + vmudh $v29, $v23, $v30.e7 ## L:700 | 165 | VTEMP = vviewoff:sint * 1; + ldv $v02, 0, 32, $fp ## L:467 | ^ | m0:ufract = load(address, 0x20).xyzwxyzw; + ldv $v01, 8, 0, $fp ## L:466 | 166 | m0:sint = load(address, 0x00).xyzwxyzw; + ldv $v02, 8, 32, $fp ## L:467 | 167 | m0:ufract = load(address, 0x20).xyzwxyzw; + andi $s2, $s1, 1799 ## L:432 | 168 | t0 = codes & 0x707; + ldv $v06, 8, 48, $fp ## L:471 | 169 | m2:ufract = load(address, 0x30).xyzwxyzw; + ldv $v03, 0, 8, $fp ## L:468 | 170 | m1:sint = load(address, 0x08).xyzwxyzw; + vmadn $v20, $v20, $v22.v ## L:701 | ^ | vpos_clip = vpos_clip +* vviewscale; + vmadh $v19, $v19, $v22.v ## L:701 | 171 | vpos_clip = vpos_clip +* vviewscale; + addiu $at, $k0, MG_SCRATCH_MEM ## L:721 | ^ | vec16 vdiffuse = load(mat_ptr_diffuse, MG_SCRATCH_MEM); + vmudn $v29, $v02, $v14.h0 ## L:713 | 172 | VTEMP = vmvp0 * vpos.xxxxXXXX; + ldv $v03, 8, 8, $fp ## L:468 | ^ | m1:sint = load(address, 0x08).xyzwxyzw; + srl $s3, $s2, 5 ## L:433 | 173 | t1 = t0 >> 5; + lqv $v22, 0, 0, $at ## L:721 | 174 | vec16 vdiffuse = load(mat_ptr_diffuse, MG_SCRATCH_MEM); + ldv $v07, 8, 24, $fp ## L:472 | 175 | m3:sint = load(address, 0x18).xyzwxyzw; + vmadh $v29, $v01, $v14.h0 ## L:713 | ^ | VTEMP = vmvp0 * vpos.xxxxXXXX; + addiu $at, $k1, MG_SCRATCH_MEM ## L:722 | 176 | vec16 vambient = load(mat_ptr_ambient, MG_SCRATCH_MEM); + vmadn $v29, $v04, $v14.h1 ## L:714 | ^ | VTEMP = vmvp1 +* vpos.yyyyYYYY; + lqv $v23, 0, 0, $at ## L:722 | 177 | vec16 vambient = load(mat_ptr_ambient, MG_SCRATCH_MEM); + ssv $v24, 14, 20, $t1 ## L:694 | 178 | @Barrier("st_iw1") store(vinvw.W, vtx_out1_ptr, 20); ## Barrier: 0x4000 + vmadh $v29, $v03, $v14.h1 ## L:714 | ^ | VTEMP = vmvp1 +* vpos.yyyyYYYY; + vmadn $v29, $v06, $v14.h2 ## L:715 | 179 | VTEMP = vmvp2 +* vpos.zzzzZZZZ; + lbu $fp, %lo(LIGHTING_COUNT + 0) ## L:730 | ^ | u8 light_count = load(LIGHTING_COUNT); + vmadh $v29, $v05, $v14.h2 ## L:715 | 180 | VTEMP = vmvp2 +* vpos.zzzzZZZZ; + ssv $v24, 6, 20, $s7 ## L:693 | ^ | @Barrier("st_iw0") store(vinvw.w, vtx_out0_ptr, 20); ## Barrier: 0x2000 + addiu $at, $sp, MG_SCRATCH_MEM ## L:723 | 181 | vec16 vemissive = load(mat_ptr_emissive, MG_SCRATCH_MEM); + lqv $v24, 0, 0, $at ## L:723 | 182 | vec16 vemissive = load(mat_ptr_emissive, MG_SCRATCH_MEM); + ssv $v25, 14, 22, $t1 ## L:694 | 183 | @Barrier("st_iw1") store(vinvw.W, vtx_out1_ptr, 20); ## Barrier: 0x4000 + ori $s0, $zero, %lo(LIGHTING_LIGHTS) ## L:732 | 184 | u16 light_ptr = LIGHTING_LIGHTS; + vmadn $v29, $v08, $v30.e2 ## L:716 | ^ | vpos = vmvp3 +* 0x20; + ssv $v25, 6, 22, $s7 ## L:693 | 185 | @Barrier("st_iw0") store(vinvw.w, vtx_out0_ptr, 20); ## Barrier: 0x2000 + vmadh $v14, $v07, $v30.e2 ## L:716 | ^ | vpos = vmvp3 +* 0x20; + nor $t7, $s2, $s3 ## L:447 | 186 | result = t0 ~| t1; + vmudh $v29, $v24, $v30.e7 ## L:725 | ^ | VTEMP = vemissive:sint * 1; + beq $fp, $zero, LIGHT_END ## L:733 | 187 | if (light_count == 0) goto LIGHT_END; + vmacf $v17, $v17, $v23.v ## L:726 | *189 | vrgba:sfract = vrgba:sfract +* vambient:sfract; + LIGHT_LOOP: + ldv $v25, 0, 8, $s0 ## L:738 | 190 | vec16 vlcol = load(light_ptr, 8).xyzwxyzw; + ldv $v26, 0, 0, $s0 ## L:739 | 191 | vec16 vlpos = load(light_ptr, 0).xyzwxyzw; + ldv $v26, 8, 0, $s0 ## L:739 | 192 | vec16 vlpos = load(light_ptr, 0).xyzwxyzw; + lh $s2, 6($s0) ## L:743 | 193 | s16 light_w = load(light_ptr, 6); + addiu $s1, $s0, 14 ## L:736 | 194 | u16 amb_ptr = light_ptr + 14; + ldv $v25, 8, 8, $s0 ## L:738 | 195 | vec16 vlcol = load(light_ptr, 8).xyzwxyzw; + ldv $v24, 0, 0, $s1 ## L:737 | 196 | vec16 vlambient = load(amb_ptr, 0).xyzwxyzw; + ldv $v24, 8, 0, $s1 ## L:737 | 197 | vec16 vlambient = load(amb_ptr, 0).xyzwxyzw; + beq $s2, $zero, LABEL_gl_pipeline_0005 ## L:744 | 198 | if (light_w != 0) + vmulf $v25, $v25, $v22.v ## L:741 | *200 | vlcol:sfract *= vdiffuse; + vsubc $v26, $v26, $v14.v ## L:758 | 201 | vlpos -= vpos; + addiu $s3, $s0, 20 ## L:752 | ^ | u16 att_ptr = light_ptr + 20; + vmudh $v04, $v26, $v26.v ## L:759 | ***205 | vec32 vsqdist = vlpos * vlpos; + ldv $v01, 0, 0, $s3 ## L:754 | ^ | vatten:sint = load(att_ptr, 0).xyzwxyzw; + ldv $v01, 8, 0, $s3 ## L:754 | 206 | vatten:sint = load(att_ptr, 0).xyzwxyzw; + vsar $v04, COP2_ACC_MD ## L:759 | ^ | vec32 vsqdist = vlpos * vlpos; + addiu $s3, $s3, 6 ## L:755 | 207 | att_ptr += 6; + vsar $v03, COP2_ACC_HI ## L:759 | ^ | vec32 vsqdist = vlpos * vlpos; + ldv $v02, 0, 0, $s3 ## L:756 | 208 | vatten:ufract = load(att_ptr, 0).xyzwxyzw; + ldv $v02, 8, 0, $s3 ## L:756 | *210 | vatten:ufract = load(att_ptr, 0).xyzwxyzw; + vaddc $v06, $v04, $v04.h1 ## L:760 | ^ | vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + vadd $v05, $v03, $v03.h1 ## L:760 | 211 | vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + vaddc $v04, $v06, $v04.h2 ## L:761 | **214 | vsqdist = vtmp + vsqdist.zzzzZZZZ; + vadd $v03, $v05, $v03.h2 ## L:761 | 215 | vsqdist = vtmp + vsqdist.zzzzZZZZ; + vrsqh $v05.e0, $v03.e0 ## L:763 | ***219 | vtmp.x = invert_half_sqrt(vsqdist).x; + vrsql $v06.e0, $v04.e0 ## L:763 | 220 | vtmp.x = invert_half_sqrt(vsqdist).x; + vrsqh $v05.e0, $v03.e4 ## L:764 | 221 | vtmp.X = invert_half_sqrt(vsqdist).X; + vrsql $v06.e4, $v04.e4 ## L:764 | 222 | vtmp.X = invert_half_sqrt(vsqdist).X; + vrsqh $v05.e4, $v00.e0 ## L:764 | 223 | vtmp.X = invert_half_sqrt(vsqdist).X; + vmudl $v29, $v06, $v04.v ## L:766 | **226 | vec32 vdist = vtmp * vsqdist; + vmadm $v29, $v05, $v04.v ## L:766 | 227 | vec32 vdist = vtmp * vsqdist; + vmadn $v08, $v06, $v03.v ## L:766 | 228 | vec32 vdist = vtmp * vsqdist; + vmadh $v07, $v05, $v03.v ## L:766 | 229 | vec32 vdist = vtmp * vsqdist; + vmudm $v29, $v26, $v06.h0 ## L:768 | 230 | vlpos *= vtmp.xxxxXXXX; + vmadh $v26, $v26, $v05.h0 ## L:768 | 231 | vlpos *= vtmp.xxxxXXXX; + vmudn $v29, $v02, $v30.e7 ## L:770 | 232 | VTEMP = vatten * 1; + vmadh $v29, $v01, $v30.e7 ## L:770 | 233 | VTEMP = vatten * 1; + vmadl $v29, $v08, $v02.h1 ## L:771 | 234 | VTEMP = vdist +* vatten.yyyyYYYY; + vmadm $v29, $v07, $v02.h1 ## L:771 | 235 | VTEMP = vdist +* vatten.yyyyYYYY; + vmadn $v29, $v08, $v01.h1 ## L:771 | 236 | VTEMP = vdist +* vatten.yyyyYYYY; + vmadh $v29, $v07, $v01.h1 ## L:771 | 237 | VTEMP = vdist +* vatten.yyyyYYYY; + vmadl $v29, $v04, $v02.h2 ## L:772 | 238 | vatten = vsqdist +* vatten.zzzzZZZZ; + vmadm $v29, $v03, $v02.h2 ## L:772 | 239 | vatten = vsqdist +* vatten.zzzzZZZZ; + vmadn $v02, $v04, $v01.h2 ## L:772 | 240 | vatten = vsqdist +* vatten.zzzzZZZZ; + vmadh $v01, $v03, $v01.h2 ## L:772 | 241 | vatten = vsqdist +* vatten.zzzzZZZZ; + vrcph $v01.e0, $v01.e0 ## L:774 | ***245 | vatten.x = invert_half(vatten).x; + vrcpl $v02.e0, $v02.e0 ## L:774 | 246 | vatten.x = invert_half(vatten).x; + vrcph $v01.e0, $v01.e4 ## L:775 | **249 | vatten.X = invert_half(vatten).X; + vrcpl $v02.e4, $v02.e4 ## L:775 | 250 | vatten.X = invert_half(vatten).X; + vrcph $v01.e4, $v00.e4 ## L:775 | 251 | vatten.X = invert_half(vatten).X; + vmudm $v29, $v25, $v02.h0 ## L:777 | **254 | vlcol *= vatten.xxxxXXXX; + vmadh $v25, $v25, $v01.h0 ## L:777 | 255 | vlcol *= vatten.xxxxXXXX; + LABEL_gl_pipeline_0005: + addiu $fp, $fp, 65535 ## L:801 | ^ | light_count -= 1; + vmulf $v26, $v26, $v15.v ## L:791 | 256 | vlpos *= vnorm:sfract; + vmudn $v29, $v24, $v23.v ## L:792 | 257 | VTEMP = vlambient * vambient; + vmacf $v29, $v25, $v26.h0 ## L:793 | **260 | VTEMP = vlcol:sfract +* vlpos:sfract.xxxxXXXX; + vmacf $v29, $v25, $v26.h1 ## L:794 | 261 | VTEMP = vlcol:sfract +* vlpos:sfract.yyyyYYYY; + vmacf $v25, $v25, $v26.h2 ## L:795 | 262 | vlcol = vlcol:sfract +* vlpos:sfract.zzzzZZZZ; + addiu $s0, $s0, 32 ## L:800 | ^ | light_ptr += 32; + vge $v25, $v25, $v00 ## L:796 | ***266 | vlcol = max(vlcol, VZERO); + bne $fp, $zero, LIGHT_LOOP ## L:802 | ^ | if (light_count != 0) goto LIGHT_LOOP; + vadd $v17, $v17, $v25.v ## L:798 | ****271 | vrgba:sint += vlcol; + LIGHT_END: + or $t2, $zero, $s7 ## L:904 | 272 | prev_out0 = vtx_out0_ptr; + vmov $v17.e3, $v22.e3 ## L:806 | ^ | vrgba.w = vdiffuse.w; + vmov $v17.e7, $v22.e7 ## L:807 | 273 | vrgba.W = vdiffuse.W; + lbu $s1, %lo(FOG_MASK + 0) ## L:813 | ^ | u8 fog_mask = load(FOG_MASK); + ctc2 $s1, $vcc ## L:814 | **276 | set_vcc(fog_mask); + ori $at, $zero, %lo(TEXTURE_MATRIX) ## L:875 | 277 | vmt0:sint = load(TEXTURE_MATRIX, 0x00).xyzwxyzw; + vmrg $v17, $v17, $v21.h2 ## L:815 | ^ | vrgba = select(vrgba, vfog.zzzzZZZZ); + ldv $v27, 0, 16, $at ## L:879 | 278 | vmt3:sint = load(TEXTURE_MATRIX, 0x10).xyzwxyzw; + vmudh $v22, $v14, $v14.v ## L:826 | ^ | vec32 vsqdist = vpos * vpos; + ori $s1, $zero, %lo(MATRICES_MVP) ## L:822 | 279 | u16 addr = MATRICES_MVP; + vsar $v22, COP2_ACC_MD ## L:826 | ^ | vec32 vsqdist = vpos * vpos; + vsar $v21, COP2_ACC_HI ## L:826 | 280 | vec32 vsqdist = vpos * vpos; + ldv $v07, 8, 24, $s1 ## L:472 | ^ | m3:sint = load(address, 0x18).xyzwxyzw; + vaddc $v24, $v22, $v22.h1 ## L:827 | **283 | vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + vadd $v23, $v21, $v21.h1 ## L:827 | 284 | vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + ldv $v27, 8, 16, $at ## L:879 | ^ | vmt3:sint = load(TEXTURE_MATRIX, 0x10).xyzwxyzw; + addu $t0, $t0, $t9 ## L:907 | **287 | vtx_in1_ptr += vtx_size2; + vaddc $v22, $v24, $v22.h2 ## L:828 | ^ | vsqdist = vtmp + vsqdist.zzzzZZZZ; + or $t3, $zero, $t1 ## L:905 | 288 | prev_out1 = vtx_out1_ptr; + vadd $v21, $v23, $v21.h2 ## L:828 | ^ | vsqdist = vtmp + vsqdist.zzzzZZZZ; + vrsqh $v23.e0, $v21.e0 ## L:830 | ***292 | vtmp.x = invert_half_sqrt(vsqdist).x; + vrsql $v24.e0, $v22.e0 ## L:830 | 293 | vtmp.x = invert_half_sqrt(vsqdist).x; + ldv $v08, 0, 56, $s1 ## L:473 | ^ | m3:ufract = load(address, 0x38).xyzwxyzw; + ldv $v08, 8, 56, $s1 ## L:473 | 294 | m3:ufract = load(address, 0x38).xyzwxyzw; + vrsqh $v23.e0, $v21.e4 ## L:831 | ^ | vtmp.X = invert_half_sqrt(vsqdist).X; + vrsql $v24.e4, $v22.e4 ## L:831 | 295 | vtmp.X = invert_half_sqrt(vsqdist).X; + vrsqh $v23.e4, $v00.e0 ## L:831 | 296 | vtmp.X = invert_half_sqrt(vsqdist).X; + addiu $t1, $t1, 80 ## L:909 | ^ | vtx_out1_ptr += 80; + ldv $v03, 8, 8, $s1 ## L:468 | **299 | m1:sint = load(address, 0x08).xyzwxyzw; + vmudm $v29, $v14, $v24.h0 ## L:833 | ^ | vpos *= vtmp.xxxxXXXX; + vmadh $v14, $v14, $v23.h0 ## L:833 | 300 | vpos *= vtmp.xxxxXXXX; + vmulf $v23, $v14, $v15.v ## L:836 | ***304 | vec16 vdot = vpos:sfract * vnorm:sfract; + ldv $v01, 8, 0, $s1 ## L:466 | ^ | m0:sint = load(address, 0x00).xyzwxyzw; + ldv $v04, 8, 40, $s1 ## L:469 | 305 | m1:ufract = load(address, 0x28).xyzwxyzw; + ldv $v06, 0, 48, $s1 ## L:471 | 306 | m2:ufract = load(address, 0x30).xyzwxyzw; + ldv $v05, 0, 16, $s1 ## L:470 | *308 | m2:sint = load(address, 0x10).xyzwxyzw; + vadd $v24, $v23, $v23.h1 ## L:837 | ^ | vec16 vtmp:sint = vdot + vdot.yyyyYYYY; + vadd $v23, $v24, $v23.h2 ## L:838 | ***312 | vdot:sint = vtmp + vdot.zzzzZZZZ; + vor $v24, $v00, $v00 ## L:843 | 313 | vec16 vzunit = VZERO; + vlt $v23, $v23, $v00 ## L:840 | **316 | vdot = min(vdot, VZERO); + vmov $v24.e2, $v12.e3 ## L:844 | 317 | vzunit.z = vnormmask.w; + vsubc $v23, $v00, $v23.v ## L:841 | **320 | vdot = VZERO - vdot; + ldv $v04, 0, 40, $s1 ## L:469 | ^ | m1:ufract = load(address, 0x28).xyzwxyzw; + ldv $v03, 0, 8, $s1 ## L:468 | 321 | m1:sint = load(address, 0x08).xyzwxyzw; + vmov $v24.e6, $v12.e3 ## L:845 | ^ | vzunit.Z = vnormmask.w; + vmulf $v29, $v15, $v23.h0 ## L:847 | **324 | VTEMP = vnorm:sfract * vdot.xxxxXXXX; + addu $s4, $s4, $t9 ## L:906 | ^ | vtx_in0_ptr += vtx_size2; + vmacf $v29, $v15, $v23.h0 ## L:848 | 325 | VTEMP = vnorm:sfract +* vdot.xxxxXXXX; + LOAD_NORMAL911: lsv $v15, 0, 0, $s4 ## L:911 | ^ | @AttrLoader("NORMAL") vnorm.x = load(vtx_in0_ptr).x; + vmadh $v29, $v14, $v30.e7 ## L:849 | 326 | VTEMP = vpos:sint +* 1; + vmadh $v29, $v24, $v30.e7 ## L:850 | 327 | VTEMP = vzunit:sint +* 1; + LOAD_POSITION913: ldv $v14, 0, 0, $s4 ## L:913 | ^ | @AttrLoader("POSITION") vpos.xyzw = load(vtx_in0_ptr).xyzw; + LOAD_POSITION914: ldv $v14, 8, 0, $t0 ## L:914 | 328 | @AttrLoader("POSITION") vpos.XYZW = load(vtx_in1_ptr).xyzw; + vsar $v24, COP2_ACC_MD ## L:853 | ^ | vec32 vrefl = get_acc(); + vsar $v23, COP2_ACC_HI ## L:853 | 329 | vec32 vrefl = get_acc(); + LOAD_COLOR916: llv $v18, 4, 0, $t0 ## L:916 | ^ | @AttrLoader("COLOR") vrgba_in.zw = load(vtx_in1_ptr).xy; + ldv $v07, 0, 24, $s1 ## L:472 | **332 | m3:sint = load(address, 0x18).xyzwxyzw; + vmudl $v29, $v24, $v24.v ## L:855 | ^ | vsqdist = vrefl * vrefl; + vmadm $v29, $v23, $v24.v ## L:855 | 333 | vsqdist = vrefl * vrefl; + LOAD_NORMAL912: lsv $v15, 8, 0, $t0 ## L:912 | ^ | @AttrLoader("NORMAL") vnorm.X = load(vtx_in1_ptr).x; + vmadn $v22, $v24, $v23.v ## L:855 | 334 | vsqdist = vrefl * vrefl; + vmadh $v21, $v23, $v23.v ## L:855 | 335 | vsqdist = vrefl * vrefl; + ldv $v02, 8, 32, $s1 ## L:467 | ^ | m0:ufract = load(address, 0x20).xyzwxyzw; + LOAD_COLOR915: llv $v18, 0, 0, $s4 ## L:915 | **338 | @AttrLoader("COLOR") vrgba_in.xy = load(vtx_in0_ptr).xy; + vaddc $v26, $v22, $v22.h1 ## L:856 | ^ | vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + vadd $v25, $v21, $v21.h1 ## L:856 | 339 | vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + vaddc $v22, $v26, $v22.h2 ## L:857 | **342 | vsqdist = vtmp + vsqdist.zzzzZZZZ; + vadd $v21, $v25, $v21.h2 ## L:857 | 343 | vsqdist = vtmp + vsqdist.zzzzZZZZ; + vxor $v16, $v00, $v30.e0 ## L:862 | 344 | vtex = 0x80; + vrsqh $v25.e0, $v21.e0 ## L:859 | **347 | vtmp.x = invert_half_sqrt(vsqdist).x; + vrsql $v26.e0, $v22.e0 ## L:859 | 348 | vtmp.x = invert_half_sqrt(vsqdist).x; + ldv $v05, 8, 16, $s1 ## L:470 | ^ | m2:sint = load(address, 0x10).xyzwxyzw; + vrsqh $v25.e0, $v21.e4 ## L:860 | 349 | vtmp.X = invert_half_sqrt(vsqdist).X; + addiu $s7, $s7, 80 ## L:908 | ^ | vtx_out0_ptr += 80; + vrsql $v26.e4, $v22.e4 ## L:860 | 350 | vtmp.X = invert_half_sqrt(vsqdist).X; + vrsqh $v25.e4, $v00.e0 ## L:860 | 351 | vtmp.X = invert_half_sqrt(vsqdist).X; + vmudh $v29, $v16, $v30.e7 ## L:863 | 352 | VTEMP = vtex:sint * 1; + ldv $v28, 0, 40, $at ## L:880 | ^ | vmt3:ufract = load(TEXTURE_MATRIX, 0x28).xyzwxyzw; + vmadl $v29, $v24, $v26.h0 ## L:864 | *354 | vtex:sint = vrefl +* vtmp.xxxxXXXX; + ldv $v28, 8, 40, $at ## L:880 | ^ | vmt3:ufract = load(TEXTURE_MATRIX, 0x28).xyzwxyzw; + vmadm $v29, $v23, $v26.h0 ## L:864 | 355 | vtex:sint = vrefl +* vtmp.xxxxXXXX; + ldv $v26, 0, 32, $at ## L:878 | ^ | vmt1:ufract = load(TEXTURE_MATRIX, 0x20).xyzwxyzw; + vmadn $v29, $v24, $v25.h0 ## L:864 | 356 | vtex:sint = vrefl +* vtmp.xxxxXXXX; + ldv $v24, 0, 24, $at ## L:876 | ^ | vmt0:ufract = load(TEXTURE_MATRIX, 0x18).xyzwxyzw; + vmadh $v16, $v23, $v25.h0 ## L:864 | 357 | vtex:sint = vrefl +* vtmp.xxxxXXXX; + ldv $v24, 8, 24, $at ## L:876 | ^ | vmt0:ufract = load(TEXTURE_MATRIX, 0x18).xyzwxyzw; + ldv $v26, 8, 32, $at ## L:878 | 358 | vmt1:ufract = load(TEXTURE_MATRIX, 0x20).xyzwxyzw; + ldv $v23, 0, 0, $at ## L:875 | 359 | vmt0:sint = load(TEXTURE_MATRIX, 0x00).xyzwxyzw; + ldv $v23, 8, 0, $at ## L:875 | 360 | vmt0:sint = load(TEXTURE_MATRIX, 0x00).xyzwxyzw; + ldv $v25, 0, 8, $at ## L:877 | 361 | vmt1:sint = load(TEXTURE_MATRIX, 0x08).xyzwxyzw; + vmudn $v29, $v24, $v16.h0 ## L:882 | ^ | VTEMP = vmt0 * vtex.xxxxXXXX; + ldv $v25, 8, 8, $at ## L:877 | 362 | vmt1:sint = load(TEXTURE_MATRIX, 0x08).xyzwxyzw; + ori $at, $zero, %lo(TEXTURE_SIZE) ## L:896 | *364 | vtex_size.xy = load(TEXTURE_SIZE).xy; + vmadh $v29, $v23, $v16.h0 ## L:882 | ^ | VTEMP = vmt0 * vtex.xxxxXXXX; + vmadn $v29, $v26, $v16.h1 ## L:883 | 365 | VTEMP = vmt1 +* vtex.yyyyYYYY; + vmadh $v29, $v25, $v16.h1 ## L:883 | 366 | VTEMP = vmt1 +* vtex.yyyyYYYY; + vmadn $v22, $v28, $v31.e7 ## L:884 | 367 | vtex_transformed = vmt3 +* 0x100; + ldv $v01, 0, 0, $s1 ## L:466 | ^ | m0:sint = load(address, 0x00).xyzwxyzw; + vmadh $v21, $v27, $v31.e7 ## L:884 | 368 | vtex_transformed = vmt3 +* 0x100; + vrcph $v23.e0, $v21.e3 ## L:889 | ***372 | vinv_tex.x = invert_half(vtex_transformed).w; + vrcpl $v24.e0, $v22.e3 ## L:889 | 373 | vinv_tex.x = invert_half(vtex_transformed).w; + vrcph $v23.e0, $v21.e7 ## L:890 | 374 | vinv_tex.X = invert_half(vtex_transformed).W; + vrcpl $v24.e4, $v22.e7 ## L:890 | 375 | vinv_tex.X = invert_half(vtex_transformed).W; + ldv $v02, 0, 32, $s1 ## L:467 | ^ | m0:ufract = load(address, 0x20).xyzwxyzw; + vrcph $v23.e4, $v00.e7 ## L:890 | 376 | vinv_tex.X = invert_half(vtex_transformed).W; + vmudl $v29, $v22, $v24.h0 ## L:892 | **379 | vtex_transformed *= vinv_tex.xxxxXXXX; + ldv $v06, 8, 48, $s1 ## L:471 | ^ | m2:ufract = load(address, 0x30).xyzwxyzw; + vmadm $v29, $v21, $v24.h0 ## L:892 | 380 | vtex_transformed *= vinv_tex.xxxxXXXX; + vmadn $v22, $v22, $v23.h0 ## L:892 | 381 | vtex_transformed *= vinv_tex.xxxxXXXX; + vmadh $v21, $v21, $v23.h0 ## L:892 | 382 | vtex_transformed *= vinv_tex.xxxxXXXX; + llv $v23, 0, 0, $at ## L:896 | ^ | vtex_size.xy = load(TEXTURE_SIZE).xy; + llv $v23, 8, 0, $at ## L:897 | 383 | vtex_size.XY = load(TEXTURE_SIZE).xy; + ori $at, $zero, %lo(TEXTURE_OFFSET) ## L:898 | 384 | vtex_offset.xy = load(TEXTURE_OFFSET).xy; + llv $v24, 0, 0, $at ## L:898 | 385 | vtex_offset.xy = load(TEXTURE_OFFSET).xy; + llv $v24, 8, 0, $at ## L:899 | 386 | vtex_offset.XY = load(TEXTURE_OFFSET).xy; + vmudh $v29, $v24, $v30.e7 ## L:901 | ***390 | VTEMP = vtex_offset:sint * 1; + sltu $at, $s4, $s6 ## L:918 | ^ | if (vtx_in0_ptr < vtx_in_end) goto VERTEX_LOOP; + vmadn $v29, $v22, $v23.v ## L:902 | 391 | vtex = vtex_transformed +* vtex_size; + bne $at, $zero, VERTEX_LOOP ## L:918 | ^ | if (vtx_in0_ptr < vtx_in_end) goto VERTEX_LOOP; + vmadh $v16, $v21, $v23.v ## L:902 | *393 | vtex = vtex_transformed +* vtex_size; + suv $v17, 4, 8, $t3 ## L:933 | 394 | @Barrier("st_tex1") store_vec_u8(vrgba.X, prev_out1, 8); ## Barrier: 0x80 + sdv $v19, 8, 0, $t3 ## L:925 | 395 | @Barrier("st_c1") @Barrier("st_tr1") store(vpos_clip:sint.XYZW, prev_out1, 0); ## Barrier: 0x30 + sb $t5, 6($t3) ## L:928 | 396 | @Barrier("st_c1") store(c1, prev_out1, 6); ## Barrier: 0x10 + suv $v17, 0, 8, $t2 ## L:932 | 397 | @Barrier("st_tex0") store_vec_u8(vrgba.x, prev_out0, 8); ## Barrier: 0x40 + sb $t7, 7($t3) ## L:930 | 398 | @Barrier("st_tr1") store(tr1, prev_out1, 7); ## Barrier: 0x20 + slv $v16, 0, 12, $t2 ## L:935 | 399 | @Barrier("st_tex0") store(vtex.xy, prev_out0, 12); ## Barrier: 0x40 + sdv $v19, 0, 0, $t2 ## L:924 | 400 | @Barrier("st_c0") @Barrier("st_tr0") store(vpos_clip:sint.xyzw, prev_out0, 0); ## Barrier: 0xC + slv $v16, 8, 12, $t3 ## L:936 | 401 | @Barrier("st_tex1") store(vtex.XY, prev_out1, 12); ## Barrier: 0x80 + sb $t6, 7($t2) ## L:929 | 402 | @Barrier("st_tr0") store(tr0, prev_out0, 7); ## Barrier: 0x8 + j RSPQ_Loop ## L:937 | 403 | } + sb $t4, 6($t2) ## L:927 | *405 | @Barrier("st_c0") store(c0, prev_out0, 6); ## Barrier: 0x4 + +MgEndShader + +#define zero $0 +#define v0 $2 +#define v1 $3 +#define a0 $4 +#define a1 $5 +#define a2 $6 +#define a3 $7 +#define t0 $8 +#define t1 $9 +#define t2 $10 +#define t3 $11 +#define t4 $12 +#define t5 $13 +#define t6 $14 +#define t7 $15 +#define s0 $16 +#define s1 $17 +#define s2 $18 +#define s3 $19 +#define s4 $20 +#define s5 $21 +#define s6 $22 +#define s7 $23 +#define t8 $24 +#define t9 $25 +#define k0 $26 +#define k1 $27 +#define gp $28 +#define sp $29 +#define fp $30 +#define ra $31 + +.set at +.set macro \ No newline at end of file diff --git a/src/GL/rsp_gl_pipeline_env_nrm.S b/src/GL/rsp_gl_pipeline_env_nrm.S new file mode 100644 index 0000000000..d9ce1a22d8 --- /dev/null +++ b/src/GL/rsp_gl_pipeline_env_nrm.S @@ -0,0 +1,797 @@ +## Auto-generated file, transpiled with RSPL +#define ENABLE_ENV_MAP +#define ENABLE_NORMALIZE +#define __MAGMA_CONSTANTS +#define MG_VERTEX_CACHE_COUNT 48 +#define MG_DEFAULT_GUARD_BAND 2 +#define MG_INLINE_UNIFORM_HEADER 12 +#define MG_MAX_UNIFORM_PAYLOAD_SIZE (RSPQ_MAX_COMMAND_SIZE*4 - 12) +#define MG_CLIP_PLANE_COUNT 6 +#define MG_CLIP_PLANE_SIZE 8 +#define MG_CLIP_CACHE_SIZE 9 +#define MG_VTX_XYZ 0 +#define MG_VTX_CLIP_CODE 6 +#define MG_VTX_TR_CODE 7 +#define MG_VTX_RGBA 8 +#define MG_VTX_ST 12 +#define MG_VTX_Wi 16 +#define MG_VTX_Wf 18 +#define MG_VTX_INVWi 20 +#define MG_VTX_INVWf 22 +#define MG_VTX_CS_POSi 24 +#define MG_VTX_CS_POSf 32 +#define MG_VTX_SIZE 40 +#define MG_VTX_SIZE2 80 +#define MG_MAX_UNIFORMS_SIZE 0x200 +#define __GL_CONSTANTS +#define __MGFX_CONSTANTS +#define MGFX_ATTRIBUTE_POSITION 0 +#define MGFX_ATTRIBUTE_NORMAL 1 +#define MGFX_ATTRIBUTE_COLOR 2 +#define MGFX_ATTRIBUTE_TEXCOORD 3 +#define MGFX_BINDING_MATRICES 0 +#define MGFX_BINDING_TEXTURING 1 +#define MGFX_BINDING_LIGHTING 2 +#define MGFX_BINDING_FOG 3 +#define MGFX_LIGHT_COUNT_MAX 8 +#define MGFX_LIGHT_POSITION 0 +#define MGFX_LIGHT_POSITIONW 6 +#define MGFX_LIGHT_COLOR 8 +#define MGFX_LIGHT_INTENSITY 14 +#define MGFX_LIGHT_SIZE 16 +#define MGFX_MATRIX_SIZE 64 +#define MGFX_VTX_TEX_SHIFT 5 +#define PIPELINE_FEATURE_COUNT 2 +#define PIPELINE_COUNT (1<<2) +#define MODELVIEW_STACK_SIZE 32 +#define PROJECTION_STACK_SIZE 2 +#define TEXTURE_STACK_SIZE 2 +#define PALETTE_STACK_SIZE 1 +#define VERTEX_UNIT_COUNT 1 +#define MATRIX_PALETTE_SIZE 32 +#define MATRICES_SIZE 160 +#define VERTEX_CACHE_SIZE 32 +#define CLIPPING_PLANE_COUNT 6 +#define CLIPPING_CACHE_SIZE 9 +#define CLIPPING_PLANE_SIZE 8 +#define MATRIX_SIZE 64 +#define TEX_COORD_COUNT 4 +#define TEX_GEN_COUNT 4 +#define TEX_GEN_PLANE_COUNT 2 +#define TEX_GEN_SIZE 34 +#define TEX_GEN_STRUCT_SIZE 144 +#define TEX_GEN_INTEGER_OFFSET 0 +#define TEX_GEN_FRACTION_OFFSET 64 +#define TEX_GEN_MODE_OFFSET 128 +#define TEX_GEN_MODE_T_OFFSET 130 +#define TEX_GEN_CONST_SIZE (4*2) +#define TEX_SIZE_SHIFT 6 +#define LIGHT_COUNT 8 +#define MAX_TEXTURE_SIZE 64 +#define MAX_TEXTURE_LEVELS 7 +#define TEXTURE_IMAGE_SIZE 6 +#define TEXTURE_OBJECT_PROPS_OFFSET (6 * 7) +#define TEXTURE_LEVELS_COUNT_OFFSET ((6 * 7) + 0) +#define TEXTURE_TLUT_MODE_OFFSET ((6 * 7) + 1) +#define TEXTURE_LEVELS_BLOCK_OFFSET ((6 * 7) + 2) +#define TEXTURE_FLAGS_OFFSET ((6 * 7) + 62) +#define TEXTURE_MIN_FILTER_OFFSET ((6 * 7) + 66) +#define TEXTURE_MAG_FILTER_OFFSET ((6 * 7) + 68) +#define TEXTURE_OBJECT_SIZE ((6 * 7) + 70) +#define IMAGE_WIDTH_OFFSET 0 +#define IMAGE_HEIGHT_OFFSET 2 +#define IMAGE_INTERNAL_FORMAT_OFFSET 4 +#define TEXTURE_BILINEAR_MASK 0x001 +#define TEXTURE_INTERPOLATE_MASK 0x002 +#define TEXTURE_MIPMAP_MASK 0x100 +#define MAX_PIXEL_MAP_SIZE 32 +#define ATTRIB_TYPE_COUNT 10 +#define FLAG_DITHER (1 << 0) +#define FLAG_BLEND (1 << 1) +#define FLAG_ALPHA_TEST (1 << 2) +#define FLAG_FOG (1 << 3) +#define FLAG_SCISSOR_TEST (1 << 4) +#define FLAG_TEXTURE_1D (1 << 5) +#define FLAG_TEXTURE_2D (1 << 6) +#define FLAG_CULL_FACE (1 << 7) +#define FLAG_LIGHTING (1 << 10) +#define FLAG_COLOR_MATERIAL (1 << 11) +#define FLAG_NORMALIZE (1 << 12) +#define FLAG_MATRIX_PALETTE (1 << 14) +#define FLAG_DEPTH_TEST (1 << 16) +#define FLAG_TEXTURE_ACTIVE (1 << 17) +#define FLAG_DEPTH_MASK (1 << 18) +#define FLAG_FINAL_MTX_DIRTY (1 << 19) +#define FLAG_LIGHT0 (1 << 20) +#define FLAG_LIGHT1 (1 << 21) +#define FLAG_LIGHT2 (1 << 22) +#define FLAG_LIGHT3 (1 << 23) +#define FLAG_LIGHT4 (1 << 24) +#define FLAG_LIGHT5 (1 << 25) +#define FLAG_LIGHT6 (1 << 26) +#define FLAG_LIGHT7 (1 << 27) +#define FLAG_TEX_GEN_S (1 << 28) +#define FLAG_TEX_GEN_T (1 << 29) +#define FLAG_TEX_GEN_R (1 << 30) +#define FLAG_TEX_GEN_Q (1 << 31) +#define FLAG2_USE_RDPQ_MATERIAL (1 << 0) +#define FLAG2_USE_RDPQ_TEXTURING (1 << 1) +#define FLAG2_REDUCED_ALIASING (1 << 2) +#define FLAG2_MULTISAMPLE (1 << 3) +#define FLAG2_TEX_FLIP_T (1 << 4) +#define CLIENT_FLAG_BEGIN_END (1 << 0) +#define CLIENT_FLAG_COLOR_ARRAY (1 << 1) +#define TEX_FLAG_COMPLETE (1 << 0) +#define TEX_FLAG_UPLOAD_DIRTY (1 << 1) +#define TEX_FLAG_FORCE_COMPLETE (1 << 2) +#define TEX_FLAG_DETAIL (1 << 3) +#define DITHER_MASK (SOM_RGBDITHER_MASK | SOM_ALPHADITHER_MASK) +#define BLEND_MASK SOM_ZMODE_MASK +#define DEPTH_TEST_MASK SOM_Z_COMPARE +#define DEPTH_MASK_MASK SOM_Z_WRITE +#define POINTS_MASK (SOM_ZSOURCE_MASK | SOM_TEXTURE_PERSP) +#define ALPHA_TEST_MASK SOM_ALPHACOMPARE_MASK +#define LOAD_TILE 7 +#define GUARD_BAND_FACTOR 2 +#define MULTISAMPLE_FLAG_SHIFT 2 +#define ZMODE_BLEND_FLAG_SHIFT 10 +#define COMBINER_FLAG_CONSTANT (1 << 0) +#define COMBINER_FLAG_REPLACE (1 << 1) +#define COMBINER_FLAG_TEXTURE (1 << 2) +#define TEXTURE_ACTIVE_SHIFT 17 +#define TEX_ACTIVE_COMBINER_SHIFT (17 - 2) +#define TEX_COORD_SHIFT 3 +#define HALF_TEXEL 0x0010 +#define TEX_BILINEAR_SHIFT 13 +#define TEX_BILINEAR_OFFSET_SHIFT 4 +#define TEX_DETAIL_SHIFT 15 +#define BILINEAR_TEX_OFFSET_SHIFT 9 +#define TRICMD_ATTR_SHIFT 8 +#define TRICMD_ATTR_MASK 0x300 +#define LIGHT0_SHIFT 20 +#define TEX_GEN_S_SHIFT 28 +#define TEX_GEN_LINEAR_FLAG_SHIFT 8 +#define TEX_GEN_SPHERICAL_FLAG_SHIFT 9 +#define NEED_EYE_SPACE_SHIFT 13 +#define RDPQ_TEXTURING_MASK ((SOM_SAMPLE_MASK | SOM_TEXTURE_LOD | SOMX_LOD_INTERPOLATE | SOMX_NUMLODS_MASK | SOM_TLUT_MASK)>>32) +#define PALETTE_MATRIX_INDEX 3 +#define PALETTE_DIRTY_FLAGS_SIZE ((32+7)>>3) +#define GLP_LIGHT_POSITION 0 +#define GLP_LIGHT_POSITIONW 6 +#define GLP_LIGHT_DIFFUSE 8 +#define GLP_LIGHT_AMBIENT 14 +#define GLP_LIGHT_ATT_INT 20 +#define GLP_LIGHT_ATT_FRAC 26 +#define GLP_LIGHT_SIZE 32 +#define GLP_ATTRIBUTE_POSITION 0 +#define GLP_ATTRIBUTE_NORMAL 1 +#define GLP_ATTRIBUTE_COLOR 2 +#define GLP_ATTRIBUTE_TEXCOORD 3 +#define GLP_BINDING_MATRICES 0 +#define GLP_BINDING_TEXTURING 1 +#define GLP_BINDING_LIGHTING 2 +#define GLP_BINDING_FOG 3 +#define GLP_VTX_POS_SHIFT 5 +#define GLP_VTX_TEX_SHIFT 8 +#define GLP_MATERIAL_FLAG_DIFFUSE 0x1 +#define GLP_MATERIAL_FLAG_AMBIENT 0x2 +#define GLP_MATERIAL_FLAG_EMISSIVE 0x4 +#define SCRATCH_MAT_DIFFUSE 0x30 +#define SCRATCH_MAT_AMBIENT 0x40 +#define SCRATCH_MAT_EMISSIVE 0x50 +#define SCRATCH_RGBA_IN 0x60 +#include + +.set noreorder +.set noat +.set nomacro + +#undef zero +#undef at +#undef v0 +#undef v1 +#undef a0 +#undef a1 +#undef a2 +#undef a3 +#undef t0 +#undef t1 +#undef t2 +#undef t3 +#undef t4 +#undef t5 +#undef t6 +#undef t7 +#undef s0 +#undef s1 +#undef s2 +#undef s3 +#undef s4 +#undef s5 +#undef s6 +#undef s7 +#undef t8 +#undef t9 +#undef k0 +#undef k1 +#undef gp +#undef sp +#undef fp +#undef ra +.equ hex.$zero, 0 +.equ hex.$at, 1 +.equ hex.$v0, 2 +.equ hex.$v1, 3 +.equ hex.$a0, 4 +.equ hex.$a1, 5 +.equ hex.$a2, 6 +.equ hex.$a3, 7 +.equ hex.$t0, 8 +.equ hex.$t1, 9 +.equ hex.$t2, 10 +.equ hex.$t3, 11 +.equ hex.$t4, 12 +.equ hex.$t5, 13 +.equ hex.$t6, 14 +.equ hex.$t7, 15 +.equ hex.$s0, 16 +.equ hex.$s1, 17 +.equ hex.$s2, 18 +.equ hex.$s3, 19 +.equ hex.$s4, 20 +.equ hex.$s5, 21 +.equ hex.$s6, 22 +.equ hex.$s7, 23 +.equ hex.$t8, 24 +.equ hex.$t9, 25 +.equ hex.$k0, 26 +.equ hex.$k1, 27 +.equ hex.$gp, 28 +.equ hex.$sp, 29 +.equ hex.$fp, 30 +.equ hex.$ra, 31 +#define vco 0 +#define vcc 1 +#define vce 2 + +MgBeginShaderUniforms + MgBeginUniform MATRICES, 0 + .align 4 + MATRICES_MVP: .ds.b 64 + .align 4 + MATRICES_MV: .ds.b 64 + .align 4 + MATRICES_NORMAL: .ds.b 32 + MgEndUniform + + MgBeginUniform TEXTURING, 1 + .align 4 + TEXTURE_MATRIX: .ds.b 48 + .align 1 + TEXTURE_SIZE: .ds.b 4 + .align 1 + TEXTURE_OFFSET: .ds.b 4 + MgEndUniform + + MgBeginUniform LIGHTING, 2 + LIGHTING_LIGHTS: .ds.b 256 + .align 1 + LIGHTING_AMBIENT: .ds.b 6 + LIGHTING_HAS_POINTS: .ds.b 1 + LIGHTING_COUNT: .ds.b 1 + .align 1 + MATERIAL_DIFFUSE: .ds.b 8 + .align 1 + MATERIAL_AMBIENT: .ds.b 6 + .align 1 + MATERIAL_FLAGS: .ds.b 2 + .align 1 + MATERIAL_EMISSIVE: .ds.b 6 + MgEndUniform + + MgBeginUniform FOG, 3 + .align 1 + FOG_PARAMS: .ds.b 6 + FOG_MASK: .ds.b 1 + MgEndUniform + +MgEndShaderUniforms + +MgBeginVertexInput + MgBeginVertexAttribute 0, 0 + MgVertexAttributeLoaders LOAD_POSITION589, LOAD_POSITION590, LOAD_POSITION914, LOAD_POSITION913 + MgEndVertexAttribute + + MgBeginVertexAttribute 1, 1 + MgVertexAttributeLoaders LOAD_NORMAL587, LOAD_NORMAL588, LOAD_NORMAL912, LOAD_NORMAL911 + MgEndVertexAttribute + + MgBeginVertexAttribute 2, 1 + MgVertexAttributeLoaders LOAD_COLOR591, LOAD_COLOR592, LOAD_COLOR916, LOAD_COLOR915 + MgEndVertexAttribute + + MgBeginVertexAttribute 3, 1 + MgEndVertexAttribute + +MgEndVertexInput + +MgBeginShader + ori $at, $zero, %lo(MG_VERTEX_SIZE) ## L:486 | ^ | vec16 vvtx_size = load(MG_VERTEX_SIZE).xyzw; + addiu $t0, $gp, %lo(RSPQ_DMEM_BUFFER) -6 ## L:485 | 2 | u32 inputs_ptr = get_cmd_address(0x2); + ldv $v02, 0, 0, $t0 ## L:487 | 3 | vec16 vinputs = load(inputs_ptr).xyzw; + ldv $v01, 0, 0, $at ## L:486 | 4 | vec16 vvtx_size = load(MG_VERTEX_SIZE).xyzw; + lw $s0, %lo(MG_VERTEX_BUFFER + 0) ## L:503 | ***8 | u32<$s0> vtx_buffer = load(MG_VERTEX_BUFFER); + vmudh $v04, $v02, $v01.v ## L:489 | ^ | vec32 vproducts = vinputs * vvtx_size; + vsar $v03, COP2_ACC_HI ## L:489 | 9 | vec32 vproducts = vinputs * vvtx_size; + ori $at, $zero, %lo(RSPQ_SCRATCH_MEM) ## L:490 | ^ | @Barrier("inputs0") store(vproducts:ufract.xyzw, RSPQ_SCRATCH_MEM); ## Barrier: 0x1 + ori $s4, $zero, %lo(MG_VERTEX_CACHE_END) ## L:511 | 10 | vtx_in0_ptr = MG_VERTEX_CACHE_END; + vsar $v04, COP2_ACC_MD ## L:489 | ^ | vec32 vproducts = vinputs * vvtx_size; + ssv $v03, 0, 8, $at ## L:491 | **13 | @Barrier("inputs1") store(vproducts.x, RSPQ_SCRATCH_MEM, 0x8); ## Barrier: 0x2 + sdv $v04, 0, 0, $at ## L:490 | 14 | @Barrier("inputs0") store(vproducts:ufract.xyzw, RSPQ_SCRATCH_MEM); ## Barrier: 0x1 + ssv $v04, 0, 10, $at ## L:491 | 15 | @Barrier("inputs1") store(vproducts.x, RSPQ_SCRATCH_MEM, 0x8); ## Barrier: 0x2 + lw $t2, %lo(RSPQ_SCRATCH_MEM + 8) ## L:501 | 16 | @Barrier("inputs1") buffer_offset = load(RSPQ_SCRATCH_MEM, 0x8); ## Barrier: 0x2 + lhu $s7, %lo(RSPQ_SCRATCH_MEM + 2) ## L:497 | 17 | @Barrier("inputs0") vtx_out0_ptr = load(RSPQ_SCRATCH_MEM, 0x2); ## Barrier: 0x1 + lhu $t1, %lo(RSPQ_SCRATCH_MEM + 4) ## L:499 | 18 | @Barrier("inputs0") vertices_size = load(RSPQ_SCRATCH_MEM, 0x4); ## Barrier: 0x1 + andi $t3, $t2, 7 ## L:506 | 19 | u32 misalignment = buffer_offset & 0x7; + addu $s0, $s0, $t2 ## L:504 | 20 | vtx_buffer += buffer_offset; + addu $t0, $t1, $t3 ## L:507 | 21 | dma_size = vertices_size + misalignment; + addiu $t2, $zero, 12 ## L:514 | 22 | dma_in(vtx_in0_ptr, vtx_buffer, dma_size); + addiu $t0, $t0, 7 ## L:508 | 23 | dma_size += 0x7; + andi $t0, $t0, 4088 ## L:509 | 24 | dma_size &= 0xFF8; + subu $s4, $s4, $t0 ## L:512 | 25 | vtx_in0_ptr -= dma_size; + jal DMAExec ## L:514 | 26 | dma_in(vtx_in0_ptr, vtx_buffer, dma_size); ## Args: $t0, $t1, $s0, $s4, $t2 + addiu $t0, $t0, -1 ## L:514 | *28 | dma_in(vtx_in0_ptr, vtx_buffer, dma_size); + ori $at, $zero, %lo(MATRICES_NORMAL) ## L:533 | 29 | vmn0 = load(MATRICES_NORMAL, 0x00).xyzwxyzw; + ori $t0, $zero, %lo(MATRICES_MVP) ## L:528 | 30 | u16 mvpaddr = MATRICES_MVP; + ldv $v09, 0, 0, $at ## L:533 | 31 | vmn0 = load(MATRICES_NORMAL, 0x00).xyzwxyzw; + addiu $k0, $zero, 48 ## L:559 | 32 | u16 mat_ptr_diffuse = 0x30; + ldv $v09, 8, 0, $at ## L:533 | 33 | vmn0 = load(MATRICES_NORMAL, 0x00).xyzwxyzw; + ldv $v11, 0, 16, $at ## L:535 | 34 | vmn2 = load(MATRICES_NORMAL, 0x10).xyzwxyzw; + ldv $v02, 0, 32, $t0 ## L:467 | 35 | m0:ufract = load(address, 0x20).xyzwxyzw; + ldv $v10, 0, 8, $at ## L:534 | 36 | vmn1 = load(MATRICES_NORMAL, 0x08).xyzwxyzw; + lhu $t8, %lo(MG_VERTEX_SIZE + 0) ## L:516 | 37 | vtx_size = load(MG_VERTEX_SIZE); + ldv $v10, 8, 8, $at ## L:534 | 38 | vmn1 = load(MATRICES_NORMAL, 0x08).xyzwxyzw; + ldv $v04, 0, 40, $t0 ## L:469 | 39 | m1:ufract = load(address, 0x28).xyzwxyzw; + lhu $fp, %lo(MATERIAL_FLAGS + 0) ## L:572 | 40 | u16 mat_flags = load(MATERIAL_FLAGS); + ldv $v11, 8, 16, $at ## L:535 | 41 | vmn2 = load(MATRICES_NORMAL, 0x10).xyzwxyzw; + ori $at, $zero, %lo(MG_NORMAL_MASK) ## L:537 | 42 | vec16 vnormmask = load(MG_NORMAL_MASK,0x0).xyzwxyzw; + ldv $v03, 0, 8, $t0 ## L:468 | 43 | m1:sint = load(address, 0x08).xyzwxyzw; + ldv $v13, 0, 8, $at ## L:538 | 44 | vec16 vnormfactor = load(MG_NORMAL_MASK,0x8).xyzwxyzw; + addu $s6, $s4, $t1 ## L:519 | 45 | vtx_in_end = vtx_in0_ptr + vertices_size; + ldv $v12, 0, 0, $at ## L:537 | 46 | vec16 vnormmask = load(MG_NORMAL_MASK,0x0).xyzwxyzw; + ldv $v05, 0, 16, $t0 ## L:470 | 47 | m2:sint = load(address, 0x10).xyzwxyzw; + ldv $v02, 8, 32, $t0 ## L:467 | 48 | m0:ufract = load(address, 0x20).xyzwxyzw; + andi $s0, $fp, 1 ## L:573 | 49 | u16 tmp = mat_flags & 0x1; + ldv $v08, 0, 56, $t0 ## L:473 | 50 | m3:ufract = load(address, 0x38).xyzwxyzw; + ldv $v13, 8, 8, $at ## L:538 | 51 | vec16 vnormfactor = load(MG_NORMAL_MASK,0x8).xyzwxyzw; + ldv $v12, 8, 0, $at ## L:537 | 52 | vec16 vnormmask = load(MG_NORMAL_MASK,0x0).xyzwxyzw; + ori $at, $zero, %lo(MATERIAL_DIFFUSE) ## L:564 | 53 | vec16 vdiffuse = load(MATERIAL_DIFFUSE).xyzwxyzw; + ldv $v08, 8, 56, $t0 ## L:473 | 54 | m3:ufract = load(address, 0x38).xyzwxyzw; + ldv $v21, 0, 0, $at ## L:564 | 55 | vec16 vdiffuse = load(MATERIAL_DIFFUSE).xyzwxyzw; + ldv $v21, 8, 0, $at ## L:564 | 56 | vec16 vdiffuse = load(MATERIAL_DIFFUSE).xyzwxyzw; + ldv $v07, 0, 24, $t0 ## L:472 | 57 | m3:sint = load(address, 0x18).xyzwxyzw; + addiu $s7, $s7, %lo(MG_VERTEX_CACHE) ## L:520 | 58 | vtx_out0_ptr += MG_VERTEX_CACHE; + ori $at, $zero, %lo(MATERIAL_AMBIENT) ## L:565 | 59 | vec16 vambient = load(MATERIAL_AMBIENT).xyzwxyzw; + sll $t9, $t8, 1 ## L:517 | 60 | vtx_size2 = vtx_size * 2; + ldv $v22, 0, 0, $at ## L:565 | 61 | vec16 vambient = load(MATERIAL_AMBIENT).xyzwxyzw; + ldv $v04, 8, 40, $t0 ## L:469 | 62 | m1:ufract = load(address, 0x28).xyzwxyzw; + ldv $v07, 8, 24, $t0 ## L:472 | 63 | m3:sint = load(address, 0x18).xyzwxyzw; + ldv $v06, 0, 48, $t0 ## L:471 | 64 | m2:ufract = load(address, 0x30).xyzwxyzw; + ldv $v01, 0, 0, $t0 ## L:466 | 65 | m0:sint = load(address, 0x00).xyzwxyzw; + ldv $v22, 8, 0, $at ## L:565 | 66 | vec16 vambient = load(MATERIAL_AMBIENT).xyzwxyzw; + ldv $v06, 8, 48, $t0 ## L:471 | 67 | m2:ufract = load(address, 0x30).xyzwxyzw; + ori $at, $zero, %lo(MATERIAL_EMISSIVE) ## L:566 | 68 | vec16 vemissive = load(MATERIAL_EMISSIVE).xyzwxyzw; + ldv $v05, 8, 16, $t0 ## L:470 | 69 | m2:sint = load(address, 0x10).xyzwxyzw; + ori $t3, $zero, %lo(MG_SCRATCH_MEM) ## L:548 | 70 | u16 prev_out1 = MG_SCRATCH_MEM; + ldv $v23, 0, 0, $at ## L:566 | 71 | vec16 vemissive = load(MATERIAL_EMISSIVE).xyzwxyzw; + ldv $v23, 8, 0, $at ## L:566 | 72 | vec16 vemissive = load(MATERIAL_EMISSIVE).xyzwxyzw; + ori $t2, $zero, %lo(MG_SCRATCH_MEM) ## L:547 | 73 | u16 prev_out0 = MG_SCRATCH_MEM; + ldv $v03, 8, 8, $t0 ## L:468 | 74 | m1:sint = load(address, 0x08).xyzwxyzw; + ori $at, $zero, %lo(MG_SCRATCH_MEM) ## L:568 | 75 | store(vdiffuse, MG_SCRATCH_MEM, 0x30); + addiu $k1, $zero, 64 ## L:560 | 76 | u16 mat_ptr_ambient = 0x40; + addiu $t1, $s7, 40 ## L:545 | 77 | u16 vtx_out1_ptr = vtx_out0_ptr + 40; + sqv $v22, 0, 64, $at ## L:569 | 78 | store(vambient, MG_SCRATCH_MEM, 0x40); + ldv $v01, 8, 0, $t0 ## L:466 | 79 | m0:sint = load(address, 0x00).xyzwxyzw; + addiu $sp, $zero, 80 ## L:561 | 80 | u16 mat_ptr_emissive = 0x50; + addu $t0, $s4, $t8 ## L:544 | 81 | u16 vtx_in1_ptr = vtx_in0_ptr + vtx_size; + sqv $v21, 0, 48, $at ## L:568 | 82 | store(vdiffuse, MG_SCRATCH_MEM, 0x30); + beq $s0, $zero, LABEL_gl_pipeline_0001 ## L:574 | 83 | if (tmp != 0) { + sqv $v23, 0, 80, $at ## L:570 | *85 | store(vemissive, MG_SCRATCH_MEM, 0x50); + addiu $k0, $zero, 96 ## L:575 | 86 | mat_ptr_diffuse = 0x60; + LABEL_gl_pipeline_0001: + andi $s0, $fp, 2 ## L:577 | 87 | tmp = mat_flags & 0x2; + beq $s0, $zero, LABEL_gl_pipeline_0002 ## L:578 | 88 | if (tmp != 0 ) { + nop ## L:578 | *90 | if (tmp != 0 ) { + addiu $k1, $zero, 96 ## L:579 | 91 | mat_ptr_ambient = 0x60; + LABEL_gl_pipeline_0002: + andi $s0, $fp, 4 ## L:581 | 92 | tmp = mat_flags & 0x4; + beq $s0, $zero, LABEL_gl_pipeline_0003 ## L:582 | 93 | if (tmp != 0) { + nop ## L:582 | *95 | if (tmp != 0) { + addiu $sp, $zero, 96 ## L:583 | 96 | mat_ptr_emissive = 0x60; + LABEL_gl_pipeline_0003: + LOAD_NORMAL587: lsv $v15, 0, 0, $s4 ## L:587 | 97 | @AttrLoader("NORMAL") vnorm.x = load(vtx_in0_ptr).x; + LOAD_NORMAL588: lsv $v15, 8, 0, $t0 ## L:588 | 98 | @AttrLoader("NORMAL") vnorm.X = load(vtx_in1_ptr).x; + LOAD_COLOR591: llv $v18, 0, 0, $s4 ## L:591 | 99 | @AttrLoader("COLOR") vrgba_in.xy = load(vtx_in0_ptr).xy; + LOAD_POSITION589: ldv $v14, 0, 0, $s4 ## L:589 | 100 | @AttrLoader("POSITION") vpos.xyzw = load(vtx_in0_ptr).xyzw; + LOAD_POSITION590: ldv $v14, 8, 0, $t0 ## L:590 | 101 | @AttrLoader("POSITION") vpos.XYZW = load(vtx_in1_ptr).xyzw; + LOAD_COLOR592: llv $v18, 4, 0, $t0 ## L:592 | 102 | @AttrLoader("COLOR") vrgba_in.zw = load(vtx_in1_ptr).xy; + VERTEX_LOOP: + vand $v15, $v12, $v15.h0 ## L:627 | ^ | vnorm = vnormmask & vnorm.xxxxXXXX; + sdv $v19, 0, 0, $t2 ## L:600 | ***106 | @Barrier("st_c0") @Barrier("st_tr0") store(vpos_clip:sint.xyzw, prev_out0, 0); ## Barrier: 0xC + vmudn $v15, $v15, $v13.v ## L:628 | ^ | vnorm *= vnormfactor; + sb $t6, 7($t2) ## L:605 | 107 | @Barrier("st_tr0") store(tr0, prev_out0, 7); ## Barrier: 0x8 + vmudn $v29, $v02, $v14.h0 ## L:631 | ^ | VTEMP = vmvp0 * vpos.xxxxXXXX; + suv $v17, 4, 8, $t3 ## L:609 | 108 | @Barrier("st_tex1") store_vec_u8(vrgba.X, prev_out1, 8); ## Barrier: 0x80 + vmadh $v29, $v01, $v14.h0 ## L:631 | ^ | VTEMP = vmvp0 * vpos.xxxxXXXX; + vmadn $v29, $v04, $v14.h1 ## L:632 | 109 | VTEMP = vmvp1 +* vpos.yyyyYYYY; + suv $v17, 0, 8, $t2 ## L:608 | ^ | @Barrier("st_tex0") store_vec_u8(vrgba.x, prev_out0, 8); ## Barrier: 0x40 + slv $v16, 0, 12, $t2 ## L:611 | 110 | @Barrier("st_tex0") store(vtex.xy, prev_out0, 12); ## Barrier: 0x40 + vmadh $v29, $v03, $v14.h1 ## L:632 | ^ | VTEMP = vmvp1 +* vpos.yyyyYYYY; + vmadn $v29, $v06, $v14.h2 ## L:633 | 111 | VTEMP = vmvp2 +* vpos.zzzzZZZZ; + sdv $v19, 8, 0, $t3 ## L:601 | ^ | @Barrier("st_c1") @Barrier("st_tr1") store(vpos_clip:sint.XYZW, prev_out1, 0); ## Barrier: 0x30 + sb $t7, 7($t3) ## L:606 | 112 | @Barrier("st_tr1") store(tr1, prev_out1, 7); ## Barrier: 0x20 + vmadh $v29, $v05, $v14.h2 ## L:633 | ^ | VTEMP = vmvp2 +* vpos.zzzzZZZZ; + ori $at, $zero, %lo(RSPQ_SCRATCH_MEM) ## L:614 | 113 | @Barrier("unpack_col") store(vrgba_in.xyzw, RSPQ_SCRATCH_MEM); ## Barrier: 0x100 + vmadn $v20, $v08, $v30.e2 ## L:634 | ^ | vpos_clip = vmvp3 +* 0x20; + vmadh $v19, $v07, $v30.e2 ## L:634 | 114 | vpos_clip = vmvp3 +* 0x20; + vmulf $v29, $v09, $v15.h0 ## L:636 | 115 | VTEMP = vmn0:sfract * vnorm:sfract.xxxxXXXX; + vmacf $v29, $v10, $v15.h1 ## L:637 | 116 | VTEMP = vmn1:sfract +* vnorm:sfract.yyyyYYYY; + vmacf $v15, $v11, $v15.h2 ## L:638 | 117 | vnorm = vmn2:sfract +* vnorm:sfract.zzzzZZZZ; + sdv $v18, 0, 0, $at ## L:614 | ^ | @Barrier("unpack_col") store(vrgba_in.xyzw, RSPQ_SCRATCH_MEM); ## Barrier: 0x100 + sdv $v19, 0, 24, $s7 ## L:666 | ***121 | @Barrier("st_cp0") store(vpos_clip.xyzw, vtx_out0_ptr, 24); ## Barrier: 0x200 + vmudh $v22, $v15, $v15.v ## L:642 | ^ | vec32 vsqdist = vnorm * vnorm; + sdv $v20, 0, 32, $s7 ## L:666 | 122 | @Barrier("st_cp0") store(vpos_clip.xyzw, vtx_out0_ptr, 24); ## Barrier: 0x200 + vsar $v22, COP2_ACC_MD ## L:642 | ^ | vec32 vsqdist = vnorm * vnorm; + vsar $v21, COP2_ACC_HI ## L:642 | 123 | vec32 vsqdist = vnorm * vnorm; + vaddc $v24, $v22, $v22.h1 ## L:643 | **126 | vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + luv $v18, 0, 0, $at ## L:615 | ^ | @Barrier("unpack_col") vrgba_in = load_vec_u8(RSPQ_SCRATCH_MEM); ## Barrier: 0x100 + vadd $v23, $v21, $v21.h1 ## L:643 | 127 | vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + ori $at, $zero, %lo(MG_SCRATCH_MEM) ## L:616 | ^ | store(vrgba_in, MG_SCRATCH_MEM, 0x60); + sdv $v19, 8, 24, $t1 ## L:667 | **130 | @Barrier("st_cp1") store(vpos_clip.XYZW, vtx_out1_ptr, 24); ## Barrier: 0x400 + vaddc $v22, $v24, $v22.h2 ## L:644 | ^ | vsqdist = vtmp + vsqdist.zzzzZZZZ; + sqv $v18, 0, 96, $at ## L:616 | 131 | store(vrgba_in, MG_SCRATCH_MEM, 0x60); + vadd $v21, $v23, $v21.h2 ## L:644 | ^ | vsqdist = vtmp + vsqdist.zzzzZZZZ; + ori $at, $zero, %lo(MG_CLIP_FACTORS) ## L:656 | ***135 | vec16 vclip_factors = load(MG_CLIP_FACTORS).xyzwxyzw; + vrsqh $v25.e0, $v21.e0 ## L:647 | ^ | vinvdist.x = invert_half_sqrt(vsqdist).x; + vrsql $v26.e0, $v22.e0 ## L:647 | 136 | vinvdist.x = invert_half_sqrt(vsqdist).x; + sb $t5, 6($t3) ## L:604 | ^ | @Barrier("st_c1") store(c1, prev_out1, 6); ## Barrier: 0x10 + vrsqh $v25.e0, $v21.e4 ## L:648 | 137 | vinvdist.X = invert_half_sqrt(vsqdist).X; + vrsql $v26.e4, $v22.e4 ## L:648 | 138 | vinvdist.X = invert_half_sqrt(vsqdist).X; + ldv $v21, 0, 0, $at ## L:656 | ^ | vec16 vclip_factors = load(MG_CLIP_FACTORS).xyzwxyzw; + vrsqh $v25.e4, $v00.e0 ## L:648 | 139 | vinvdist.X = invert_half_sqrt(vsqdist).X; + ldv $v21, 8, 0, $at ## L:656 | ^ | vec16 vclip_factors = load(MG_CLIP_FACTORS).xyzwxyzw; + vmudm $v29, $v15, $v26.h0 ## L:650 | **142 | vnorm *= vinvdist.xxxxXXXX; + vmadh $v15, $v15, $v25.h0 ## L:650 | 143 | vnorm *= vinvdist.xxxxXXXX; + slv $v16, 8, 12, $t3 ## L:612 | ^ | @Barrier("st_tex1") store(vtex.XY, prev_out1, 12); ## Barrier: 0x80 + vmudn $v23, $v20, $v21.v ## L:657 | 144 | vec32 vguard = vpos_clip * vclip_factors; + ori $at, $zero, %lo(FOG_PARAMS) ## L:671 | ^ | vec16 vfog_parms = load(FOG_PARAMS).xyzwxyzw; + vmadh $v22, $v19, $v21.v ## L:657 | 145 | vec32 vguard = vpos_clip * vclip_factors; + sb $t4, 6($t2) ## L:603 | ^ | @Barrier("st_c0") store(c0, prev_out0, 6); ## Barrier: 0x4 + vch $v29, $v22, $v22.h3 ## L:658 | ***149 | u16 clip_codes = clip(vguard, vguard.wwwwWWWW); + sdv $v20, 8, 32, $t1 ## L:667 | ^ | @Barrier("st_cp1") store(vpos_clip.XYZW, vtx_out1_ptr, 24); ## Barrier: 0x400 + ldv $v22, 0, 0, $at ## L:671 | 150 | vec16 vfog_parms = load(FOG_PARAMS).xyzwxyzw; + vcl $v29, $v23, $v23.h3 ## L:658 | ^ | u16 clip_codes = clip(vguard, vguard.wwwwWWWW); + cfc2 $fp, $vcc ## L:658 | 151 | u16 clip_codes = clip(vguard, vguard.wwwwWWWW); + vch $v29, $v19, $v19.h3 ## L:662 | ^ | u16 tr_codes = clip(vpos_clip, vpos_clip.wwwwWWWW); + vcl $v29, $v20, $v20.h3 ## L:662 | 152 | u16 tr_codes = clip(vpos_clip, vpos_clip.wwwwWWWW); + ldv $v22, 8, 0, $at ## L:671 | ^ | vec16 vfog_parms = load(FOG_PARAMS).xyzwxyzw; + ori $at, $zero, %lo(MG_VIEWPORT) ## L:680 | 153 | vec16 vviewscale = load(MG_VIEWPORT, 0).xyzwxyzw; + andi $s1, $fp, 1799 ## L:432 | 154 | t0 = codes & 0x707; + srl $s0, $fp, 4 ## L:452 | 155 | u16 codes2 = codes >> 4; + srl $s2, $s1, 5 ## L:433 | 156 | t1 = t0 >> 5; + vaddc $v23, $v20, $v22.h1 ## L:672 | ^ | vec16 vtmp:ufract = vpos_clip:ufract + vfog_parms:ufract.yyyyYYYY; + or $t4, $s1, $s2 ## L:440 | 157 | result = t0 | t1; + vadd $v21, $v19, $v22.h0 ## L:673 | ^ | vfog:sint = vpos_clip:sint + vfog_parms:sint.xxxxXXXX; + andi $s1, $s0, 1799 ## L:432 | 158 | t0 = codes & 0x707; + srl $s2, $s1, 5 ## L:433 | 159 | t1 = t0 >> 5; + ori $fp, $zero, %lo(MATRICES_MV) ## L:710 | 160 | u16 addr = MATRICES_MV; + vmudn $v29, $v23, $v22.h2 ## L:675 | ^ | VTEMP = vtmp:ufract * vfog_parms:sint.zzzzZZZZ; + vmadh $v21, $v21, $v22.h2 ## L:676 | 161 | vfog = vfog:sint +* vfog_parms:sint.zzzzZZZZ; + cfc2 $s0, $vcc ## L:662 | ^ | u16 tr_codes = clip(vpos_clip, vpos_clip.wwwwWWWW); + ldv $v22, 0, 0, $at ## L:680 | 162 | vec16 vviewscale = load(MG_VIEWPORT, 0).xyzwxyzw; + ldv $v03, 0, 8, $fp ## L:468 | 163 | m1:sint = load(address, 0x08).xyzwxyzw; + ldv $v23, 0, 8, $at ## L:681 | 164 | vec16 vviewoff = load(MG_VIEWPORT, 8).xyzwxyzw; + ldv $v05, 0, 16, $fp ## L:470 | 165 | m2:sint = load(address, 0x10).xyzwxyzw; + vge $v21, $v00, $v21.h2 ## L:677 | ^ | vfog = max(VZERO, vfog.zzzzZZZZ); + ldv $v06, 0, 48, $fp ## L:471 | 166 | m2:ufract = load(address, 0x30).xyzwxyzw; + ldv $v22, 8, 0, $at ## L:680 | 167 | vec16 vviewscale = load(MG_VIEWPORT, 0).xyzwxyzw; + ldv $v05, 8, 16, $fp ## L:470 | 168 | m2:sint = load(address, 0x10).xyzwxyzw; + ldv $v04, 0, 40, $fp ## L:469 | 169 | m1:ufract = load(address, 0x28).xyzwxyzw; + ldv $v07, 0, 24, $fp ## L:472 | 170 | m3:sint = load(address, 0x18).xyzwxyzw; + ldv $v07, 8, 24, $fp ## L:472 | 171 | m3:sint = load(address, 0x18).xyzwxyzw; + ldv $v02, 0, 32, $fp ## L:467 | 172 | m0:ufract = load(address, 0x20).xyzwxyzw; + or $t5, $s1, $s2 ## L:440 | 173 | result = t0 | t1; + vmudl $v20, $v20, $v22.h3 ## L:683 | ^ | vpos_clip *= vviewscale:sfract.wwwwWWWW; + ldv $v23, 8, 8, $at ## L:681 | 174 | vec16 vviewoff = load(MG_VIEWPORT, 8).xyzwxyzw; + vmadm $v19, $v19, $v22.h3 ## L:683 | ^ | vpos_clip *= vviewscale:sfract.wwwwWWWW; + vmadn $v20, $v00, $v00 ## L:683 | 175 | vpos_clip *= vviewscale:sfract.wwwwWWWW; + ldv $v08, 0, 56, $fp ## L:473 | ^ | m3:ufract = load(address, 0x38).xyzwxyzw; + ldv $v02, 8, 32, $fp ## L:467 | 176 | m0:ufract = load(address, 0x20).xyzwxyzw; + ldv $v01, 0, 0, $fp ## L:466 | 177 | m0:sint = load(address, 0x00).xyzwxyzw; + andi $s2, $s0, 1799 ## L:432 | 178 | t0 = codes & 0x707; + srl $s3, $s2, 5 ## L:433 | 179 | t1 = t0 >> 5; + vrcph $v24.e3, $v19.e3 ## L:690 | ^ | vinvw.w = invert_half(vpos_clip).w; + nor $t6, $s2, $s3 ## L:447 | 180 | result = t0 ~| t1; + vrcpl $v25.e3, $v20.e3 ## L:690 | ^ | vinvw.w = invert_half(vpos_clip).w; + vrcph $v24.e3, $v19.e7 ## L:691 | 181 | vinvw.W = invert_half(vpos_clip).W; + ssv $v19, 14, 16, $t1 ## L:687 | ^ | @Barrier("st_w1") store(vpos_clip.W, vtx_out1_ptr, 16); ## Barrier: 0x1000 + ldv $v01, 8, 0, $fp ## L:466 | 182 | m0:sint = load(address, 0x00).xyzwxyzw; + srl $s1, $s0, 4 ## L:459 | 183 | u16 codes2 = codes >> 4; + andi $s2, $s1, 1799 ## L:432 | 184 | t0 = codes & 0x707; + vrcpl $v25.e7, $v20.e7 ## L:691 | ^ | vinvw.W = invert_half(vpos_clip).W; + ssv $v19, 6, 16, $s7 ## L:686 | 185 | @Barrier("st_w0") store(vpos_clip.w, vtx_out0_ptr, 16); ## Barrier: 0x800 + vrcph $v24.e7, $v00.e7 ## L:691 | ^ | vinvw.W = invert_half(vpos_clip).W; + ssv $v20, 14, 18, $t1 ## L:687 | 186 | @Barrier("st_w1") store(vpos_clip.W, vtx_out1_ptr, 16); ## Barrier: 0x1000 + srl $s3, $s2, 5 ## L:433 | 187 | t1 = t0 >> 5; + ldv $v08, 8, 56, $fp ## L:473 | 188 | m3:ufract = load(address, 0x38).xyzwxyzw; + vmudl $v29, $v20, $v25.h3 ## L:696 | ^ | vpos_clip *= vinvw.wwwwWWWW; + ssv $v20, 6, 18, $s7 ## L:686 | 189 | @Barrier("st_w0") store(vpos_clip.w, vtx_out0_ptr, 16); ## Barrier: 0x800 + vmadm $v29, $v19, $v25.h3 ## L:696 | ^ | vpos_clip *= vinvw.wwwwWWWW; + ldv $v04, 8, 40, $fp ## L:469 | 190 | m1:ufract = load(address, 0x28).xyzwxyzw; + ssv $v24, 14, 20, $t1 ## L:694 | 191 | @Barrier("st_iw1") store(vinvw.W, vtx_out1_ptr, 20); ## Barrier: 0x4000 + vmadn $v20, $v20, $v24.h3 ## L:696 | ^ | vpos_clip *= vinvw.wwwwWWWW; + ldv $v03, 8, 8, $fp ## L:468 | 192 | m1:sint = load(address, 0x08).xyzwxyzw; + ori $at, $zero, %lo(LIGHTING_AMBIENT) ## L:719 | 193 | vrgba = load(LIGHTING_AMBIENT).xyzwxyzw; + vmadh $v19, $v19, $v24.h3 ## L:696 | ^ | vpos_clip *= vinvw.wwwwWWWW; + ldv $v06, 8, 48, $fp ## L:471 | 194 | m2:ufract = load(address, 0x30).xyzwxyzw; + ssv $v24, 6, 20, $s7 ## L:693 | 195 | @Barrier("st_iw0") store(vinvw.w, vtx_out0_ptr, 20); ## Barrier: 0x2000 + vmudh $v29, $v23, $v30.e7 ## L:700 | ^ | VTEMP = vviewoff:sint * 1; + vmadn $v20, $v20, $v22.v ## L:701 | 196 | vpos_clip = vpos_clip +* vviewscale; + lbu $fp, %lo(LIGHTING_COUNT + 0) ## L:730 | ^ | u8 light_count = load(LIGHTING_COUNT); + vmadh $v19, $v19, $v22.v ## L:701 | 197 | vpos_clip = vpos_clip +* vviewscale; + ssv $v25, 6, 22, $s7 ## L:693 | ^ | @Barrier("st_iw0") store(vinvw.w, vtx_out0_ptr, 20); ## Barrier: 0x2000 + vmudn $v29, $v02, $v14.h0 ## L:713 | 198 | VTEMP = vmvp0 * vpos.xxxxXXXX; + ldv $v17, 0, 0, $at ## L:719 | ^ | vrgba = load(LIGHTING_AMBIENT).xyzwxyzw; + ldv $v17, 8, 0, $at ## L:719 | 199 | vrgba = load(LIGHTING_AMBIENT).xyzwxyzw; + addiu $at, $k0, MG_SCRATCH_MEM ## L:721 | 200 | vec16 vdiffuse = load(mat_ptr_diffuse, MG_SCRATCH_MEM); + vmadh $v29, $v01, $v14.h0 ## L:713 | ^ | VTEMP = vmvp0 * vpos.xxxxXXXX; + lqv $v22, 0, 0, $at ## L:721 | 201 | vec16 vdiffuse = load(mat_ptr_diffuse, MG_SCRATCH_MEM); + vmadn $v29, $v04, $v14.h1 ## L:714 | ^ | VTEMP = vmvp1 +* vpos.yyyyYYYY; + vmadh $v29, $v03, $v14.h1 ## L:714 | 202 | VTEMP = vmvp1 +* vpos.yyyyYYYY; + addiu $at, $k1, MG_SCRATCH_MEM ## L:722 | ^ | vec16 vambient = load(mat_ptr_ambient, MG_SCRATCH_MEM); + vmadn $v29, $v06, $v14.h2 ## L:715 | 203 | VTEMP = vmvp2 +* vpos.zzzzZZZZ; + lqv $v23, 0, 0, $at ## L:722 | ^ | vec16 vambient = load(mat_ptr_ambient, MG_SCRATCH_MEM); + vmadh $v29, $v05, $v14.h2 ## L:715 | 204 | VTEMP = vmvp2 +* vpos.zzzzZZZZ; + addiu $at, $sp, MG_SCRATCH_MEM ## L:723 | ^ | vec16 vemissive = load(mat_ptr_emissive, MG_SCRATCH_MEM); + vmadn $v29, $v08, $v30.e2 ## L:716 | 205 | vpos = vmvp3 +* 0x20; + lqv $v24, 0, 0, $at ## L:723 | ^ | vec16 vemissive = load(mat_ptr_emissive, MG_SCRATCH_MEM); + ori $s0, $zero, %lo(LIGHTING_LIGHTS) ## L:732 | 206 | u16 light_ptr = LIGHTING_LIGHTS; + nor $t7, $s2, $s3 ## L:447 | 207 | result = t0 ~| t1; + ssv $v25, 14, 22, $t1 ## L:694 | 208 | @Barrier("st_iw1") store(vinvw.W, vtx_out1_ptr, 20); ## Barrier: 0x4000 + vmadh $v14, $v07, $v30.e2 ## L:716 | ^ | vpos = vmvp3 +* 0x20; + vmudh $v29, $v24, $v30.e7 ## L:725 | 209 | VTEMP = vemissive:sint * 1; + beq $fp, $zero, LIGHT_END ## L:733 | ^ | if (light_count == 0) goto LIGHT_END; + vmacf $v17, $v17, $v23.v ## L:726 | *211 | vrgba:sfract = vrgba:sfract +* vambient:sfract; + LIGHT_LOOP: + ldv $v25, 0, 8, $s0 ## L:738 | 212 | vec16 vlcol = load(light_ptr, 8).xyzwxyzw; + addiu $s1, $s0, 14 ## L:736 | 213 | u16 amb_ptr = light_ptr + 14; + ldv $v24, 0, 0, $s1 ## L:737 | 214 | vec16 vlambient = load(amb_ptr, 0).xyzwxyzw; + lh $s2, 6($s0) ## L:743 | 215 | s16 light_w = load(light_ptr, 6); + ldv $v25, 8, 8, $s0 ## L:738 | 216 | vec16 vlcol = load(light_ptr, 8).xyzwxyzw; + ldv $v26, 0, 0, $s0 ## L:739 | 217 | vec16 vlpos = load(light_ptr, 0).xyzwxyzw; + ldv $v24, 8, 0, $s1 ## L:737 | 218 | vec16 vlambient = load(amb_ptr, 0).xyzwxyzw; + ldv $v26, 8, 0, $s0 ## L:739 | 219 | vec16 vlpos = load(light_ptr, 0).xyzwxyzw; + beq $s2, $zero, LABEL_gl_pipeline_0005 ## L:744 | 220 | if (light_w != 0) + vmulf $v25, $v25, $v22.v ## L:741 | *222 | vlcol:sfract *= vdiffuse; + addiu $s3, $s0, 20 ## L:752 | 223 | u16 att_ptr = light_ptr + 20; + vsubc $v26, $v26, $v14.v ## L:758 | ^ | vlpos -= vpos; + ldv $v01, 0, 0, $s3 ## L:754 | ***227 | vatten:sint = load(att_ptr, 0).xyzwxyzw; + vmudh $v04, $v26, $v26.v ## L:759 | ^ | vec32 vsqdist = vlpos * vlpos; + vsar $v04, COP2_ACC_MD ## L:759 | 228 | vec32 vsqdist = vlpos * vlpos; + ldv $v01, 8, 0, $s3 ## L:754 | ^ | vatten:sint = load(att_ptr, 0).xyzwxyzw; + vsar $v03, COP2_ACC_HI ## L:759 | 229 | vec32 vsqdist = vlpos * vlpos; + vaddc $v06, $v04, $v04.h1 ## L:760 | **232 | vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + vadd $v05, $v03, $v03.h1 ## L:760 | 233 | vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + addiu $s3, $s3, 6 ## L:755 | ^ | att_ptr += 6; + ldv $v02, 0, 0, $s3 ## L:756 | **236 | vatten:ufract = load(att_ptr, 0).xyzwxyzw; + vaddc $v04, $v06, $v04.h2 ## L:761 | ^ | vsqdist = vtmp + vsqdist.zzzzZZZZ; + ldv $v02, 8, 0, $s3 ## L:756 | 237 | vatten:ufract = load(att_ptr, 0).xyzwxyzw; + vadd $v03, $v05, $v03.h2 ## L:761 | ^ | vsqdist = vtmp + vsqdist.zzzzZZZZ; + vrsqh $v05.e0, $v03.e0 ## L:763 | ***241 | vtmp.x = invert_half_sqrt(vsqdist).x; + vrsql $v06.e0, $v04.e0 ## L:763 | 242 | vtmp.x = invert_half_sqrt(vsqdist).x; + vrsqh $v05.e0, $v03.e4 ## L:764 | 243 | vtmp.X = invert_half_sqrt(vsqdist).X; + vrsql $v06.e4, $v04.e4 ## L:764 | 244 | vtmp.X = invert_half_sqrt(vsqdist).X; + vrsqh $v05.e4, $v00.e0 ## L:764 | 245 | vtmp.X = invert_half_sqrt(vsqdist).X; + vmudl $v29, $v06, $v04.v ## L:766 | **248 | vec32 vdist = vtmp * vsqdist; + vmadm $v29, $v05, $v04.v ## L:766 | 249 | vec32 vdist = vtmp * vsqdist; + vmadn $v08, $v06, $v03.v ## L:766 | 250 | vec32 vdist = vtmp * vsqdist; + vmadh $v07, $v05, $v03.v ## L:766 | 251 | vec32 vdist = vtmp * vsqdist; + vmudm $v29, $v26, $v06.h0 ## L:768 | 252 | vlpos *= vtmp.xxxxXXXX; + vmadh $v26, $v26, $v05.h0 ## L:768 | 253 | vlpos *= vtmp.xxxxXXXX; + vmudn $v29, $v02, $v30.e7 ## L:770 | 254 | VTEMP = vatten * 1; + vmadh $v29, $v01, $v30.e7 ## L:770 | 255 | VTEMP = vatten * 1; + vmadl $v29, $v08, $v02.h1 ## L:771 | 256 | VTEMP = vdist +* vatten.yyyyYYYY; + vmadm $v29, $v07, $v02.h1 ## L:771 | 257 | VTEMP = vdist +* vatten.yyyyYYYY; + vmadn $v29, $v08, $v01.h1 ## L:771 | 258 | VTEMP = vdist +* vatten.yyyyYYYY; + vmadh $v29, $v07, $v01.h1 ## L:771 | 259 | VTEMP = vdist +* vatten.yyyyYYYY; + vmadl $v29, $v04, $v02.h2 ## L:772 | 260 | vatten = vsqdist +* vatten.zzzzZZZZ; + vmadm $v29, $v03, $v02.h2 ## L:772 | 261 | vatten = vsqdist +* vatten.zzzzZZZZ; + vmadn $v02, $v04, $v01.h2 ## L:772 | 262 | vatten = vsqdist +* vatten.zzzzZZZZ; + vmadh $v01, $v03, $v01.h2 ## L:772 | 263 | vatten = vsqdist +* vatten.zzzzZZZZ; + vrcph $v01.e0, $v01.e0 ## L:774 | ***267 | vatten.x = invert_half(vatten).x; + vrcpl $v02.e0, $v02.e0 ## L:774 | 268 | vatten.x = invert_half(vatten).x; + vrcph $v01.e0, $v01.e4 ## L:775 | **271 | vatten.X = invert_half(vatten).X; + vrcpl $v02.e4, $v02.e4 ## L:775 | 272 | vatten.X = invert_half(vatten).X; + vrcph $v01.e4, $v00.e4 ## L:775 | 273 | vatten.X = invert_half(vatten).X; + vmudm $v29, $v25, $v02.h0 ## L:777 | **276 | vlcol *= vatten.xxxxXXXX; + vmadh $v25, $v25, $v01.h0 ## L:777 | 277 | vlcol *= vatten.xxxxXXXX; + LABEL_gl_pipeline_0005: + addiu $fp, $fp, 65535 ## L:801 | ^ | light_count -= 1; + vmulf $v26, $v26, $v15.v ## L:791 | 278 | vlpos *= vnorm:sfract; + vmudn $v29, $v24, $v23.v ## L:792 | 279 | VTEMP = vlambient * vambient; + addiu $s0, $s0, 32 ## L:800 | ^ | light_ptr += 32; + vmacf $v29, $v25, $v26.h0 ## L:793 | **282 | VTEMP = vlcol:sfract +* vlpos:sfract.xxxxXXXX; + vmacf $v29, $v25, $v26.h1 ## L:794 | 283 | VTEMP = vlcol:sfract +* vlpos:sfract.yyyyYYYY; + vmacf $v25, $v25, $v26.h2 ## L:795 | 284 | vlcol = vlcol:sfract +* vlpos:sfract.zzzzZZZZ; + vge $v25, $v25, $v00 ## L:796 | ***288 | vlcol = max(vlcol, VZERO); + bne $fp, $zero, LIGHT_LOOP ## L:802 | ^ | if (light_count != 0) goto LIGHT_LOOP; + vadd $v17, $v17, $v25.v ## L:798 | ****293 | vrgba:sint += vlcol; + LIGHT_END: + lbu $s1, %lo(FOG_MASK + 0) ## L:813 | 294 | u8 fog_mask = load(FOG_MASK); + vmov $v17.e3, $v22.e3 ## L:806 | ^ | vrgba.w = vdiffuse.w; + or $t2, $zero, $s7 ## L:904 | 295 | prev_out0 = vtx_out0_ptr; + vmov $v17.e7, $v22.e7 ## L:807 | ^ | vrgba.W = vdiffuse.W; + ctc2 $s1, $vcc ## L:814 | *297 | set_vcc(fog_mask); + ori $s1, $zero, %lo(MATRICES_MVP) ## L:822 | 298 | u16 addr = MATRICES_MVP; + ori $at, $zero, %lo(TEXTURE_MATRIX) ## L:875 | 299 | vmt0:sint = load(TEXTURE_MATRIX, 0x00).xyzwxyzw; + vmrg $v17, $v17, $v21.h2 ## L:815 | ^ | vrgba = select(vrgba, vfog.zzzzZZZZ); + vmudh $v22, $v14, $v14.v ## L:826 | 300 | vec32 vsqdist = vpos * vpos; + addu $t0, $t0, $t9 ## L:907 | ^ | vtx_in1_ptr += vtx_size2; + ldv $v28, 0, 40, $at ## L:880 | 301 | vmt3:ufract = load(TEXTURE_MATRIX, 0x28).xyzwxyzw; + vsar $v22, COP2_ACC_MD ## L:826 | ^ | vec32 vsqdist = vpos * vpos; + ldv $v28, 8, 40, $at ## L:880 | 302 | vmt3:ufract = load(TEXTURE_MATRIX, 0x28).xyzwxyzw; + vsar $v21, COP2_ACC_HI ## L:826 | ^ | vec32 vsqdist = vpos * vpos; + vaddc $v24, $v22, $v22.h1 ## L:827 | **305 | vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + LOAD_COLOR916: llv $v18, 4, 0, $t0 ## L:916 | ^ | @AttrLoader("COLOR") vrgba_in.zw = load(vtx_in1_ptr).xy; + ldv $v04, 8, 40, $s1 ## L:469 | 306 | m1:ufract = load(address, 0x28).xyzwxyzw; + vadd $v23, $v21, $v21.h1 ## L:827 | ^ | vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + ldv $v07, 0, 24, $s1 ## L:472 | **309 | m3:sint = load(address, 0x18).xyzwxyzw; + vaddc $v22, $v24, $v22.h2 ## L:828 | ^ | vsqdist = vtmp + vsqdist.zzzzZZZZ; + ldv $v01, 0, 0, $s1 ## L:466 | 310 | m0:sint = load(address, 0x00).xyzwxyzw; + vadd $v21, $v23, $v21.h2 ## L:828 | ^ | vsqdist = vtmp + vsqdist.zzzzZZZZ; + ldv $v06, 0, 48, $s1 ## L:471 | 311 | m2:ufract = load(address, 0x30).xyzwxyzw; + ldv $v02, 0, 32, $s1 ## L:467 | 312 | m0:ufract = load(address, 0x20).xyzwxyzw; + addu $s4, $s4, $t9 ## L:906 | *314 | vtx_in0_ptr += vtx_size2; + vrsqh $v23.e0, $v21.e0 ## L:830 | ^ | vtmp.x = invert_half_sqrt(vsqdist).x; + vrsql $v24.e0, $v22.e0 ## L:830 | 315 | vtmp.x = invert_half_sqrt(vsqdist).x; + ldv $v08, 8, 56, $s1 ## L:473 | ^ | m3:ufract = load(address, 0x38).xyzwxyzw; + ldv $v27, 0, 16, $at ## L:879 | 316 | vmt3:sint = load(TEXTURE_MATRIX, 0x10).xyzwxyzw; + vrsqh $v23.e0, $v21.e4 ## L:831 | ^ | vtmp.X = invert_half_sqrt(vsqdist).X; + vrsql $v24.e4, $v22.e4 ## L:831 | 317 | vtmp.X = invert_half_sqrt(vsqdist).X; + ldv $v27, 8, 16, $at ## L:879 | ^ | vmt3:sint = load(TEXTURE_MATRIX, 0x10).xyzwxyzw; + ldv $v08, 0, 56, $s1 ## L:473 | 318 | m3:ufract = load(address, 0x38).xyzwxyzw; + vrsqh $v23.e4, $v00.e0 ## L:831 | ^ | vtmp.X = invert_half_sqrt(vsqdist).X; + or $t3, $zero, $t1 ## L:905 | **321 | prev_out1 = vtx_out1_ptr; + vmudm $v29, $v14, $v24.h0 ## L:833 | ^ | vpos *= vtmp.xxxxXXXX; + ldv $v04, 0, 40, $s1 ## L:469 | 322 | m1:ufract = load(address, 0x28).xyzwxyzw; + vmadh $v14, $v14, $v23.h0 ## L:833 | ^ | vpos *= vtmp.xxxxXXXX; + ldv $v03, 8, 8, $s1 ## L:468 | 323 | m1:sint = load(address, 0x08).xyzwxyzw; + addiu $t1, $t1, 80 ## L:909 | **326 | vtx_out1_ptr += 80; + vmulf $v23, $v14, $v15.v ## L:836 | ^ | vec16 vdot = vpos:sfract * vnorm:sfract; + ldv $v07, 8, 24, $s1 ## L:472 | ***330 | m3:sint = load(address, 0x18).xyzwxyzw; + vadd $v24, $v23, $v23.h1 ## L:837 | ^ | vec16 vtmp:sint = vdot + vdot.yyyyYYYY; + vadd $v23, $v24, $v23.h2 ## L:838 | ***334 | vdot:sint = vtmp + vdot.zzzzZZZZ; + ldv $v02, 8, 32, $s1 ## L:467 | ^ | m0:ufract = load(address, 0x20).xyzwxyzw; + addiu $s7, $s7, 80 ## L:908 | 335 | vtx_out0_ptr += 80; + vor $v24, $v00, $v00 ## L:843 | ^ | vec16 vzunit = VZERO; + vlt $v23, $v23, $v00 ## L:840 | **338 | vdot = min(vdot, VZERO); + vsubc $v23, $v00, $v23.v ## L:841 | ***342 | vdot = VZERO - vdot; + vmov $v24.e6, $v12.e3 ## L:845 | 343 | vzunit.Z = vnormmask.w; + ldv $v05, 8, 16, $s1 ## L:470 | ^ | m2:sint = load(address, 0x10).xyzwxyzw; + vmov $v24.e2, $v12.e3 ## L:844 | 344 | vzunit.z = vnormmask.w; + ldv $v01, 8, 0, $s1 ## L:466 | ^ | m0:sint = load(address, 0x00).xyzwxyzw; + vmulf $v29, $v15, $v23.h0 ## L:847 | *346 | VTEMP = vnorm:sfract * vdot.xxxxXXXX; + vmacf $v29, $v15, $v23.h0 ## L:848 | 347 | VTEMP = vnorm:sfract +* vdot.xxxxXXXX; + LOAD_COLOR915: llv $v18, 0, 0, $s4 ## L:915 | ^ | @AttrLoader("COLOR") vrgba_in.xy = load(vtx_in0_ptr).xy; + vmadh $v29, $v14, $v30.e7 ## L:849 | 348 | VTEMP = vpos:sint +* 1; + vmadh $v29, $v24, $v30.e7 ## L:850 | 349 | VTEMP = vzunit:sint +* 1; + LOAD_NORMAL912: lsv $v15, 8, 0, $t0 ## L:912 | ^ | @AttrLoader("NORMAL") vnorm.X = load(vtx_in1_ptr).x; + vsar $v24, COP2_ACC_MD ## L:853 | 350 | vec32 vrefl = get_acc(); + LOAD_POSITION914: ldv $v14, 8, 0, $t0 ## L:914 | ^ | @AttrLoader("POSITION") vpos.XYZW = load(vtx_in1_ptr).xyzw; + vsar $v23, COP2_ACC_HI ## L:853 | 351 | vec32 vrefl = get_acc(); + vmudl $v29, $v24, $v24.v ## L:855 | **354 | vsqdist = vrefl * vrefl; + vmadm $v29, $v23, $v24.v ## L:855 | 355 | vsqdist = vrefl * vrefl; + vmadn $v22, $v24, $v23.v ## L:855 | 356 | vsqdist = vrefl * vrefl; + vmadh $v21, $v23, $v23.v ## L:855 | 357 | vsqdist = vrefl * vrefl; + vaddc $v26, $v22, $v22.h1 ## L:856 | **360 | vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + vadd $v25, $v21, $v21.h1 ## L:856 | 361 | vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + vxor $v16, $v00, $v30.e0 ## L:862 | 362 | vtex = 0x80; + vaddc $v22, $v26, $v22.h2 ## L:857 | *364 | vsqdist = vtmp + vsqdist.zzzzZZZZ; + vadd $v21, $v25, $v21.h2 ## L:857 | 365 | vsqdist = vtmp + vsqdist.zzzzZZZZ; + vrsqh $v25.e0, $v21.e0 ## L:859 | ***369 | vtmp.x = invert_half_sqrt(vsqdist).x; + vrsql $v26.e0, $v22.e0 ## L:859 | 370 | vtmp.x = invert_half_sqrt(vsqdist).x; + vrsqh $v25.e0, $v21.e4 ## L:860 | 371 | vtmp.X = invert_half_sqrt(vsqdist).X; + vrsql $v26.e4, $v22.e4 ## L:860 | 372 | vtmp.X = invert_half_sqrt(vsqdist).X; + vrsqh $v25.e4, $v00.e0 ## L:860 | 373 | vtmp.X = invert_half_sqrt(vsqdist).X; + vmudh $v29, $v16, $v30.e7 ## L:863 | 374 | VTEMP = vtex:sint * 1; + vmadl $v29, $v24, $v26.h0 ## L:864 | *376 | vtex:sint = vrefl +* vtmp.xxxxXXXX; + ldv $v05, 0, 16, $s1 ## L:470 | ^ | m2:sint = load(address, 0x10).xyzwxyzw; + vmadm $v29, $v23, $v26.h0 ## L:864 | 377 | vtex:sint = vrefl +* vtmp.xxxxXXXX; + ldv $v26, 0, 32, $at ## L:878 | ^ | vmt1:ufract = load(TEXTURE_MATRIX, 0x20).xyzwxyzw; + ldv $v26, 8, 32, $at ## L:878 | 378 | vmt1:ufract = load(TEXTURE_MATRIX, 0x20).xyzwxyzw; + vmadn $v29, $v24, $v25.h0 ## L:864 | ^ | vtex:sint = vrefl +* vtmp.xxxxXXXX; + ldv $v24, 0, 24, $at ## L:876 | 379 | vmt0:ufract = load(TEXTURE_MATRIX, 0x18).xyzwxyzw; + ldv $v24, 8, 24, $at ## L:876 | 380 | vmt0:ufract = load(TEXTURE_MATRIX, 0x18).xyzwxyzw; + vmadh $v16, $v23, $v25.h0 ## L:864 | ^ | vtex:sint = vrefl +* vtmp.xxxxXXXX; + ldv $v23, 0, 0, $at ## L:875 | 381 | vmt0:sint = load(TEXTURE_MATRIX, 0x00).xyzwxyzw; + ldv $v23, 8, 0, $at ## L:875 | 382 | vmt0:sint = load(TEXTURE_MATRIX, 0x00).xyzwxyzw; + ldv $v25, 0, 8, $at ## L:877 | 383 | vmt1:sint = load(TEXTURE_MATRIX, 0x08).xyzwxyzw; + ldv $v25, 8, 8, $at ## L:877 | 384 | vmt1:sint = load(TEXTURE_MATRIX, 0x08).xyzwxyzw; + vmudn $v29, $v24, $v16.h0 ## L:882 | ^ | VTEMP = vmt0 * vtex.xxxxXXXX; + ori $at, $zero, %lo(TEXTURE_SIZE) ## L:896 | *386 | vtex_size.xy = load(TEXTURE_SIZE).xy; + vmadh $v29, $v23, $v16.h0 ## L:882 | ^ | VTEMP = vmt0 * vtex.xxxxXXXX; + vmadn $v29, $v26, $v16.h1 ## L:883 | 387 | VTEMP = vmt1 +* vtex.yyyyYYYY; + vmadh $v29, $v25, $v16.h1 ## L:883 | 388 | VTEMP = vmt1 +* vtex.yyyyYYYY; + vmadn $v22, $v28, $v31.e7 ## L:884 | 389 | vtex_transformed = vmt3 +* 0x100; + ldv $v06, 8, 48, $s1 ## L:471 | ^ | m2:ufract = load(address, 0x30).xyzwxyzw; + vmadh $v21, $v27, $v31.e7 ## L:884 | 390 | vtex_transformed = vmt3 +* 0x100; + vrcph $v23.e0, $v21.e3 ## L:889 | ***394 | vinv_tex.x = invert_half(vtex_transformed).w; + vrcpl $v24.e0, $v22.e3 ## L:889 | 395 | vinv_tex.x = invert_half(vtex_transformed).w; + LOAD_POSITION913: ldv $v14, 0, 0, $s4 ## L:913 | ^ | @AttrLoader("POSITION") vpos.xyzw = load(vtx_in0_ptr).xyzw; + vrcph $v23.e0, $v21.e7 ## L:890 | 396 | vinv_tex.X = invert_half(vtex_transformed).W; + vrcpl $v24.e4, $v22.e7 ## L:890 | 397 | vinv_tex.X = invert_half(vtex_transformed).W; + vrcph $v23.e4, $v00.e7 ## L:890 | 398 | vinv_tex.X = invert_half(vtex_transformed).W; + vmudl $v29, $v22, $v24.h0 ## L:892 | **401 | vtex_transformed *= vinv_tex.xxxxXXXX; + LOAD_NORMAL911: lsv $v15, 0, 0, $s4 ## L:911 | ^ | @AttrLoader("NORMAL") vnorm.x = load(vtx_in0_ptr).x; + vmadm $v29, $v21, $v24.h0 ## L:892 | 402 | vtex_transformed *= vinv_tex.xxxxXXXX; + ldv $v03, 0, 8, $s1 ## L:468 | ^ | m1:sint = load(address, 0x08).xyzwxyzw; + vmadn $v22, $v22, $v23.h0 ## L:892 | 403 | vtex_transformed *= vinv_tex.xxxxXXXX; + vmadh $v21, $v21, $v23.h0 ## L:892 | 404 | vtex_transformed *= vinv_tex.xxxxXXXX; + llv $v23, 0, 0, $at ## L:896 | ^ | vtex_size.xy = load(TEXTURE_SIZE).xy; + llv $v23, 8, 0, $at ## L:897 | 405 | vtex_size.XY = load(TEXTURE_SIZE).xy; + ori $at, $zero, %lo(TEXTURE_OFFSET) ## L:898 | 406 | vtex_offset.xy = load(TEXTURE_OFFSET).xy; + llv $v24, 0, 0, $at ## L:898 | 407 | vtex_offset.xy = load(TEXTURE_OFFSET).xy; + llv $v24, 8, 0, $at ## L:899 | 408 | vtex_offset.XY = load(TEXTURE_OFFSET).xy; + sltu $at, $s4, $s6 ## L:918 | ***412 | if (vtx_in0_ptr < vtx_in_end) goto VERTEX_LOOP; + vmudh $v29, $v24, $v30.e7 ## L:901 | ^ | VTEMP = vtex_offset:sint * 1; + vmadn $v29, $v22, $v23.v ## L:902 | 413 | vtex = vtex_transformed +* vtex_size; + bne $at, $zero, VERTEX_LOOP ## L:918 | ^ | if (vtx_in0_ptr < vtx_in_end) goto VERTEX_LOOP; + vmadh $v16, $v21, $v23.v ## L:902 | *415 | vtex = vtex_transformed +* vtex_size; + suv $v17, 0, 8, $t2 ## L:932 | 416 | @Barrier("st_tex0") store_vec_u8(vrgba.x, prev_out0, 8); ## Barrier: 0x40 + sdv $v19, 8, 0, $t3 ## L:925 | 417 | @Barrier("st_c1") @Barrier("st_tr1") store(vpos_clip:sint.XYZW, prev_out1, 0); ## Barrier: 0x30 + sdv $v19, 0, 0, $t2 ## L:924 | 418 | @Barrier("st_c0") @Barrier("st_tr0") store(vpos_clip:sint.xyzw, prev_out0, 0); ## Barrier: 0xC + sb $t4, 6($t2) ## L:927 | 419 | @Barrier("st_c0") store(c0, prev_out0, 6); ## Barrier: 0x4 + sb $t6, 7($t2) ## L:929 | 420 | @Barrier("st_tr0") store(tr0, prev_out0, 7); ## Barrier: 0x8 + slv $v16, 0, 12, $t2 ## L:935 | 421 | @Barrier("st_tex0") store(vtex.xy, prev_out0, 12); ## Barrier: 0x40 + sb $t7, 7($t3) ## L:930 | 422 | @Barrier("st_tr1") store(tr1, prev_out1, 7); ## Barrier: 0x20 + suv $v17, 4, 8, $t3 ## L:933 | 423 | @Barrier("st_tex1") store_vec_u8(vrgba.X, prev_out1, 8); ## Barrier: 0x80 + sb $t5, 6($t3) ## L:928 | 424 | @Barrier("st_c1") store(c1, prev_out1, 6); ## Barrier: 0x10 + j RSPQ_Loop ## L:937 | 425 | } + slv $v16, 8, 12, $t3 ## L:936 | *427 | @Barrier("st_tex1") store(vtex.XY, prev_out1, 12); ## Barrier: 0x80 + +MgEndShader + +#define zero $0 +#define v0 $2 +#define v1 $3 +#define a0 $4 +#define a1 $5 +#define a2 $6 +#define a3 $7 +#define t0 $8 +#define t1 $9 +#define t2 $10 +#define t3 $11 +#define t4 $12 +#define t5 $13 +#define t6 $14 +#define t7 $15 +#define s0 $16 +#define s1 $17 +#define s2 $18 +#define s3 $19 +#define s4 $20 +#define s5 $21 +#define s6 $22 +#define s7 $23 +#define t8 $24 +#define t9 $25 +#define k0 $26 +#define k1 $27 +#define gp $28 +#define sp $29 +#define fp $30 +#define ra $31 + +.set at +.set macro \ No newline at end of file diff --git a/src/GL/rsp_gl_pipeline_nrm.S b/src/GL/rsp_gl_pipeline_nrm.S new file mode 100644 index 0000000000..c3716c381a --- /dev/null +++ b/src/GL/rsp_gl_pipeline_nrm.S @@ -0,0 +1,755 @@ +## Auto-generated file, transpiled with RSPL +#define ENABLE_NORMALIZE +#define __MAGMA_CONSTANTS +#define MG_VERTEX_CACHE_COUNT 48 +#define MG_DEFAULT_GUARD_BAND 2 +#define MG_INLINE_UNIFORM_HEADER 12 +#define MG_MAX_UNIFORM_PAYLOAD_SIZE (RSPQ_MAX_COMMAND_SIZE*4 - 12) +#define MG_CLIP_PLANE_COUNT 6 +#define MG_CLIP_PLANE_SIZE 8 +#define MG_CLIP_CACHE_SIZE 9 +#define MG_VTX_XYZ 0 +#define MG_VTX_CLIP_CODE 6 +#define MG_VTX_TR_CODE 7 +#define MG_VTX_RGBA 8 +#define MG_VTX_ST 12 +#define MG_VTX_Wi 16 +#define MG_VTX_Wf 18 +#define MG_VTX_INVWi 20 +#define MG_VTX_INVWf 22 +#define MG_VTX_CS_POSi 24 +#define MG_VTX_CS_POSf 32 +#define MG_VTX_SIZE 40 +#define MG_VTX_SIZE2 80 +#define MG_MAX_UNIFORMS_SIZE 0x200 +#define __GL_CONSTANTS +#define __MGFX_CONSTANTS +#define MGFX_ATTRIBUTE_POSITION 0 +#define MGFX_ATTRIBUTE_NORMAL 1 +#define MGFX_ATTRIBUTE_COLOR 2 +#define MGFX_ATTRIBUTE_TEXCOORD 3 +#define MGFX_BINDING_MATRICES 0 +#define MGFX_BINDING_TEXTURING 1 +#define MGFX_BINDING_LIGHTING 2 +#define MGFX_BINDING_FOG 3 +#define MGFX_LIGHT_COUNT_MAX 8 +#define MGFX_LIGHT_POSITION 0 +#define MGFX_LIGHT_POSITIONW 6 +#define MGFX_LIGHT_COLOR 8 +#define MGFX_LIGHT_INTENSITY 14 +#define MGFX_LIGHT_SIZE 16 +#define MGFX_MATRIX_SIZE 64 +#define MGFX_VTX_TEX_SHIFT 5 +#define PIPELINE_FEATURE_COUNT 2 +#define PIPELINE_COUNT (1<<2) +#define MODELVIEW_STACK_SIZE 32 +#define PROJECTION_STACK_SIZE 2 +#define TEXTURE_STACK_SIZE 2 +#define PALETTE_STACK_SIZE 1 +#define VERTEX_UNIT_COUNT 1 +#define MATRIX_PALETTE_SIZE 32 +#define MATRICES_SIZE 160 +#define VERTEX_CACHE_SIZE 32 +#define CLIPPING_PLANE_COUNT 6 +#define CLIPPING_CACHE_SIZE 9 +#define CLIPPING_PLANE_SIZE 8 +#define MATRIX_SIZE 64 +#define TEX_COORD_COUNT 4 +#define TEX_GEN_COUNT 4 +#define TEX_GEN_PLANE_COUNT 2 +#define TEX_GEN_SIZE 34 +#define TEX_GEN_STRUCT_SIZE 144 +#define TEX_GEN_INTEGER_OFFSET 0 +#define TEX_GEN_FRACTION_OFFSET 64 +#define TEX_GEN_MODE_OFFSET 128 +#define TEX_GEN_MODE_T_OFFSET 130 +#define TEX_GEN_CONST_SIZE (4*2) +#define TEX_SIZE_SHIFT 6 +#define LIGHT_COUNT 8 +#define MAX_TEXTURE_SIZE 64 +#define MAX_TEXTURE_LEVELS 7 +#define TEXTURE_IMAGE_SIZE 6 +#define TEXTURE_OBJECT_PROPS_OFFSET (6 * 7) +#define TEXTURE_LEVELS_COUNT_OFFSET ((6 * 7) + 0) +#define TEXTURE_TLUT_MODE_OFFSET ((6 * 7) + 1) +#define TEXTURE_LEVELS_BLOCK_OFFSET ((6 * 7) + 2) +#define TEXTURE_FLAGS_OFFSET ((6 * 7) + 62) +#define TEXTURE_MIN_FILTER_OFFSET ((6 * 7) + 66) +#define TEXTURE_MAG_FILTER_OFFSET ((6 * 7) + 68) +#define TEXTURE_OBJECT_SIZE ((6 * 7) + 70) +#define IMAGE_WIDTH_OFFSET 0 +#define IMAGE_HEIGHT_OFFSET 2 +#define IMAGE_INTERNAL_FORMAT_OFFSET 4 +#define TEXTURE_BILINEAR_MASK 0x001 +#define TEXTURE_INTERPOLATE_MASK 0x002 +#define TEXTURE_MIPMAP_MASK 0x100 +#define MAX_PIXEL_MAP_SIZE 32 +#define ATTRIB_TYPE_COUNT 10 +#define FLAG_DITHER (1 << 0) +#define FLAG_BLEND (1 << 1) +#define FLAG_ALPHA_TEST (1 << 2) +#define FLAG_FOG (1 << 3) +#define FLAG_SCISSOR_TEST (1 << 4) +#define FLAG_TEXTURE_1D (1 << 5) +#define FLAG_TEXTURE_2D (1 << 6) +#define FLAG_CULL_FACE (1 << 7) +#define FLAG_LIGHTING (1 << 10) +#define FLAG_COLOR_MATERIAL (1 << 11) +#define FLAG_NORMALIZE (1 << 12) +#define FLAG_MATRIX_PALETTE (1 << 14) +#define FLAG_DEPTH_TEST (1 << 16) +#define FLAG_TEXTURE_ACTIVE (1 << 17) +#define FLAG_DEPTH_MASK (1 << 18) +#define FLAG_FINAL_MTX_DIRTY (1 << 19) +#define FLAG_LIGHT0 (1 << 20) +#define FLAG_LIGHT1 (1 << 21) +#define FLAG_LIGHT2 (1 << 22) +#define FLAG_LIGHT3 (1 << 23) +#define FLAG_LIGHT4 (1 << 24) +#define FLAG_LIGHT5 (1 << 25) +#define FLAG_LIGHT6 (1 << 26) +#define FLAG_LIGHT7 (1 << 27) +#define FLAG_TEX_GEN_S (1 << 28) +#define FLAG_TEX_GEN_T (1 << 29) +#define FLAG_TEX_GEN_R (1 << 30) +#define FLAG_TEX_GEN_Q (1 << 31) +#define FLAG2_USE_RDPQ_MATERIAL (1 << 0) +#define FLAG2_USE_RDPQ_TEXTURING (1 << 1) +#define FLAG2_REDUCED_ALIASING (1 << 2) +#define FLAG2_MULTISAMPLE (1 << 3) +#define FLAG2_TEX_FLIP_T (1 << 4) +#define CLIENT_FLAG_BEGIN_END (1 << 0) +#define CLIENT_FLAG_COLOR_ARRAY (1 << 1) +#define TEX_FLAG_COMPLETE (1 << 0) +#define TEX_FLAG_UPLOAD_DIRTY (1 << 1) +#define TEX_FLAG_FORCE_COMPLETE (1 << 2) +#define TEX_FLAG_DETAIL (1 << 3) +#define DITHER_MASK (SOM_RGBDITHER_MASK | SOM_ALPHADITHER_MASK) +#define BLEND_MASK SOM_ZMODE_MASK +#define DEPTH_TEST_MASK SOM_Z_COMPARE +#define DEPTH_MASK_MASK SOM_Z_WRITE +#define POINTS_MASK (SOM_ZSOURCE_MASK | SOM_TEXTURE_PERSP) +#define ALPHA_TEST_MASK SOM_ALPHACOMPARE_MASK +#define LOAD_TILE 7 +#define GUARD_BAND_FACTOR 2 +#define MULTISAMPLE_FLAG_SHIFT 2 +#define ZMODE_BLEND_FLAG_SHIFT 10 +#define COMBINER_FLAG_CONSTANT (1 << 0) +#define COMBINER_FLAG_REPLACE (1 << 1) +#define COMBINER_FLAG_TEXTURE (1 << 2) +#define TEXTURE_ACTIVE_SHIFT 17 +#define TEX_ACTIVE_COMBINER_SHIFT (17 - 2) +#define TEX_COORD_SHIFT 3 +#define HALF_TEXEL 0x0010 +#define TEX_BILINEAR_SHIFT 13 +#define TEX_BILINEAR_OFFSET_SHIFT 4 +#define TEX_DETAIL_SHIFT 15 +#define BILINEAR_TEX_OFFSET_SHIFT 9 +#define TRICMD_ATTR_SHIFT 8 +#define TRICMD_ATTR_MASK 0x300 +#define LIGHT0_SHIFT 20 +#define TEX_GEN_S_SHIFT 28 +#define TEX_GEN_LINEAR_FLAG_SHIFT 8 +#define TEX_GEN_SPHERICAL_FLAG_SHIFT 9 +#define NEED_EYE_SPACE_SHIFT 13 +#define RDPQ_TEXTURING_MASK ((SOM_SAMPLE_MASK | SOM_TEXTURE_LOD | SOMX_LOD_INTERPOLATE | SOMX_NUMLODS_MASK | SOM_TLUT_MASK)>>32) +#define PALETTE_MATRIX_INDEX 3 +#define PALETTE_DIRTY_FLAGS_SIZE ((32+7)>>3) +#define GLP_LIGHT_POSITION 0 +#define GLP_LIGHT_POSITIONW 6 +#define GLP_LIGHT_DIFFUSE 8 +#define GLP_LIGHT_AMBIENT 14 +#define GLP_LIGHT_ATT_INT 20 +#define GLP_LIGHT_ATT_FRAC 26 +#define GLP_LIGHT_SIZE 32 +#define GLP_ATTRIBUTE_POSITION 0 +#define GLP_ATTRIBUTE_NORMAL 1 +#define GLP_ATTRIBUTE_COLOR 2 +#define GLP_ATTRIBUTE_TEXCOORD 3 +#define GLP_BINDING_MATRICES 0 +#define GLP_BINDING_TEXTURING 1 +#define GLP_BINDING_LIGHTING 2 +#define GLP_BINDING_FOG 3 +#define GLP_VTX_POS_SHIFT 5 +#define GLP_VTX_TEX_SHIFT 8 +#define GLP_MATERIAL_FLAG_DIFFUSE 0x1 +#define GLP_MATERIAL_FLAG_AMBIENT 0x2 +#define GLP_MATERIAL_FLAG_EMISSIVE 0x4 +#define SCRATCH_MAT_DIFFUSE 0x30 +#define SCRATCH_MAT_AMBIENT 0x40 +#define SCRATCH_MAT_EMISSIVE 0x50 +#define SCRATCH_RGBA_IN 0x60 +#include + +.set noreorder +.set noat +.set nomacro + +#undef zero +#undef at +#undef v0 +#undef v1 +#undef a0 +#undef a1 +#undef a2 +#undef a3 +#undef t0 +#undef t1 +#undef t2 +#undef t3 +#undef t4 +#undef t5 +#undef t6 +#undef t7 +#undef s0 +#undef s1 +#undef s2 +#undef s3 +#undef s4 +#undef s5 +#undef s6 +#undef s7 +#undef t8 +#undef t9 +#undef k0 +#undef k1 +#undef gp +#undef sp +#undef fp +#undef ra +.equ hex.$zero, 0 +.equ hex.$at, 1 +.equ hex.$v0, 2 +.equ hex.$v1, 3 +.equ hex.$a0, 4 +.equ hex.$a1, 5 +.equ hex.$a2, 6 +.equ hex.$a3, 7 +.equ hex.$t0, 8 +.equ hex.$t1, 9 +.equ hex.$t2, 10 +.equ hex.$t3, 11 +.equ hex.$t4, 12 +.equ hex.$t5, 13 +.equ hex.$t6, 14 +.equ hex.$t7, 15 +.equ hex.$s0, 16 +.equ hex.$s1, 17 +.equ hex.$s2, 18 +.equ hex.$s3, 19 +.equ hex.$s4, 20 +.equ hex.$s5, 21 +.equ hex.$s6, 22 +.equ hex.$s7, 23 +.equ hex.$t8, 24 +.equ hex.$t9, 25 +.equ hex.$k0, 26 +.equ hex.$k1, 27 +.equ hex.$gp, 28 +.equ hex.$sp, 29 +.equ hex.$fp, 30 +.equ hex.$ra, 31 +#define vco 0 +#define vcc 1 +#define vce 2 + +MgBeginShaderUniforms + MgBeginUniform MATRICES, 0 + .align 4 + MATRICES_MVP: .ds.b 64 + .align 4 + MATRICES_MV: .ds.b 64 + .align 4 + MATRICES_NORMAL: .ds.b 32 + MgEndUniform + + MgBeginUniform TEXTURING, 1 + .align 4 + TEXTURE_MATRIX: .ds.b 48 + .align 1 + TEXTURE_SIZE: .ds.b 4 + .align 1 + TEXTURE_OFFSET: .ds.b 4 + MgEndUniform + + MgBeginUniform LIGHTING, 2 + LIGHTING_LIGHTS: .ds.b 256 + .align 1 + LIGHTING_AMBIENT: .ds.b 6 + LIGHTING_HAS_POINTS: .ds.b 1 + LIGHTING_COUNT: .ds.b 1 + .align 1 + MATERIAL_DIFFUSE: .ds.b 8 + .align 1 + MATERIAL_AMBIENT: .ds.b 6 + .align 1 + MATERIAL_FLAGS: .ds.b 2 + .align 1 + MATERIAL_EMISSIVE: .ds.b 6 + MgEndUniform + + MgBeginUniform FOG, 3 + .align 1 + FOG_PARAMS: .ds.b 6 + FOG_MASK: .ds.b 1 + MgEndUniform + +MgEndShaderUniforms + +MgBeginVertexInput + MgBeginVertexAttribute 0, 0 + MgVertexAttributeLoaders LOAD_POSITION589, LOAD_POSITION590, LOAD_POSITION914, LOAD_POSITION913 + MgEndVertexAttribute + + MgBeginVertexAttribute 1, 1 + MgVertexAttributeLoaders LOAD_NORMAL587, LOAD_NORMAL588, LOAD_NORMAL912, LOAD_NORMAL911 + MgEndVertexAttribute + + MgBeginVertexAttribute 2, 1 + MgVertexAttributeLoaders LOAD_COLOR591, LOAD_COLOR592, LOAD_COLOR915, LOAD_COLOR916 + MgEndVertexAttribute + + MgBeginVertexAttribute 3, 1 + MgVertexAttributeLoaders LOAD_TEXCOORD620, LOAD_TEXCOORD623 + MgEndVertexAttribute + +MgEndVertexInput + +MgBeginShader + addiu $t0, $gp, %lo(RSPQ_DMEM_BUFFER) -6 ## L:485 | ^ | u32 inputs_ptr = get_cmd_address(0x2); + ori $at, $zero, %lo(MG_VERTEX_SIZE) ## L:486 | 2 | vec16 vvtx_size = load(MG_VERTEX_SIZE).xyzw; + ldv $v01, 0, 0, $at ## L:486 | 3 | vec16 vvtx_size = load(MG_VERTEX_SIZE).xyzw; + ldv $v02, 0, 0, $t0 ## L:487 | 4 | vec16 vinputs = load(inputs_ptr).xyzw; + vmudh $v04, $v02, $v01.v ## L:489 | ***8 | vec32 vproducts = vinputs * vvtx_size; + ori $s4, $zero, %lo(MG_VERTEX_CACHE_END) ## L:511 | ^ | vtx_in0_ptr = MG_VERTEX_CACHE_END; + vsar $v03, COP2_ACC_HI ## L:489 | 9 | vec32 vproducts = vinputs * vvtx_size; + lw $s0, %lo(MG_VERTEX_BUFFER + 0) ## L:503 | ^ | u32<$s0> vtx_buffer = load(MG_VERTEX_BUFFER); + vsar $v04, COP2_ACC_MD ## L:489 | 10 | vec32 vproducts = vinputs * vvtx_size; + ori $at, $zero, %lo(RSPQ_SCRATCH_MEM) ## L:490 | ^ | @Barrier("inputs0") store(vproducts:ufract.xyzw, RSPQ_SCRATCH_MEM); ## Barrier: 0x1 + ssv $v03, 0, 8, $at ## L:491 | **13 | @Barrier("inputs1") store(vproducts.x, RSPQ_SCRATCH_MEM, 0x8); ## Barrier: 0x2 + sdv $v04, 0, 0, $at ## L:490 | 14 | @Barrier("inputs0") store(vproducts:ufract.xyzw, RSPQ_SCRATCH_MEM); ## Barrier: 0x1 + ssv $v04, 0, 10, $at ## L:491 | 15 | @Barrier("inputs1") store(vproducts.x, RSPQ_SCRATCH_MEM, 0x8); ## Barrier: 0x2 + lw $t2, %lo(RSPQ_SCRATCH_MEM + 8) ## L:501 | 16 | @Barrier("inputs1") buffer_offset = load(RSPQ_SCRATCH_MEM, 0x8); ## Barrier: 0x2 + lhu $s7, %lo(RSPQ_SCRATCH_MEM + 2) ## L:497 | 17 | @Barrier("inputs0") vtx_out0_ptr = load(RSPQ_SCRATCH_MEM, 0x2); ## Barrier: 0x1 + lhu $t1, %lo(RSPQ_SCRATCH_MEM + 4) ## L:499 | 18 | @Barrier("inputs0") vertices_size = load(RSPQ_SCRATCH_MEM, 0x4); ## Barrier: 0x1 + addu $s0, $s0, $t2 ## L:504 | 19 | vtx_buffer += buffer_offset; + andi $t3, $t2, 7 ## L:506 | 20 | u32 misalignment = buffer_offset & 0x7; + addiu $t2, $zero, 12 ## L:514 | 21 | dma_in(vtx_in0_ptr, vtx_buffer, dma_size); + addu $t0, $t1, $t3 ## L:507 | 22 | dma_size = vertices_size + misalignment; + addiu $t0, $t0, 7 ## L:508 | 23 | dma_size += 0x7; + andi $t0, $t0, 4088 ## L:509 | 24 | dma_size &= 0xFF8; + subu $s4, $s4, $t0 ## L:512 | 25 | vtx_in0_ptr -= dma_size; + jal DMAExec ## L:514 | 26 | dma_in(vtx_in0_ptr, vtx_buffer, dma_size); ## Args: $t0, $t1, $s0, $s4, $t2 + addiu $t0, $t0, -1 ## L:514 | *28 | dma_in(vtx_in0_ptr, vtx_buffer, dma_size); + ori $t0, $zero, %lo(MATRICES_MVP) ## L:528 | 29 | u16 mvpaddr = MATRICES_MVP; + addu $s6, $s4, $t1 ## L:519 | 30 | vtx_in_end = vtx_in0_ptr + vertices_size; + lhu $t8, %lo(MG_VERTEX_SIZE + 0) ## L:516 | 31 | vtx_size = load(MG_VERTEX_SIZE); + lhu $s0, %lo(MATERIAL_FLAGS + 0) ## L:572 | 32 | u16 mat_flags = load(MATERIAL_FLAGS); + ori $at, $zero, %lo(MATRICES_NORMAL) ## L:533 | 33 | vmn0 = load(MATRICES_NORMAL, 0x00).xyzwxyzw; + ldv $v09, 0, 0, $at ## L:533 | 34 | vmn0 = load(MATRICES_NORMAL, 0x00).xyzwxyzw; + ldv $v10, 0, 8, $at ## L:534 | 35 | vmn1 = load(MATRICES_NORMAL, 0x08).xyzwxyzw; + ldv $v09, 8, 0, $at ## L:533 | 36 | vmn0 = load(MATRICES_NORMAL, 0x00).xyzwxyzw; + ldv $v05, 0, 16, $t0 ## L:470 | 37 | m2:sint = load(address, 0x10).xyzwxyzw; + ldv $v10, 8, 8, $at ## L:534 | 38 | vmn1 = load(MATRICES_NORMAL, 0x08).xyzwxyzw; + ldv $v11, 0, 16, $at ## L:535 | 39 | vmn2 = load(MATRICES_NORMAL, 0x10).xyzwxyzw; + ldv $v11, 8, 16, $at ## L:535 | 40 | vmn2 = load(MATRICES_NORMAL, 0x10).xyzwxyzw; + ori $at, $zero, %lo(MG_NORMAL_MASK) ## L:537 | 41 | vec16 vnormmask = load(MG_NORMAL_MASK,0x0).xyzwxyzw; + ldv $v13, 0, 8, $at ## L:538 | 42 | vec16 vnormfactor = load(MG_NORMAL_MASK,0x8).xyzwxyzw; + ldv $v08, 0, 56, $t0 ## L:473 | 43 | m3:ufract = load(address, 0x38).xyzwxyzw; + addiu $s7, $s7, %lo(MG_VERTEX_CACHE) ## L:520 | 44 | vtx_out0_ptr += MG_VERTEX_CACHE; + ldv $v03, 0, 8, $t0 ## L:468 | 45 | m1:sint = load(address, 0x08).xyzwxyzw; + ldv $v12, 0, 0, $at ## L:537 | 46 | vec16 vnormmask = load(MG_NORMAL_MASK,0x0).xyzwxyzw; + addu $t1, $s4, $t8 ## L:544 | 47 | u16 vtx_in1_ptr = vtx_in0_ptr + vtx_size; + ldv $v08, 8, 56, $t0 ## L:473 | 48 | m3:ufract = load(address, 0x38).xyzwxyzw; + ldv $v13, 8, 8, $at ## L:538 | 49 | vec16 vnormfactor = load(MG_NORMAL_MASK,0x8).xyzwxyzw; + ldv $v12, 8, 0, $at ## L:537 | 50 | vec16 vnormmask = load(MG_NORMAL_MASK,0x0).xyzwxyzw; + ldv $v04, 0, 40, $t0 ## L:469 | 51 | m1:ufract = load(address, 0x28).xyzwxyzw; + ori $at, $zero, %lo(MATERIAL_DIFFUSE) ## L:564 | 52 | vec16 vdiffuse = load(MATERIAL_DIFFUSE).xyzwxyzw; + ldv $v21, 0, 0, $at ## L:564 | 53 | vec16 vdiffuse = load(MATERIAL_DIFFUSE).xyzwxyzw; + ldv $v01, 0, 0, $t0 ## L:466 | 54 | m0:sint = load(address, 0x00).xyzwxyzw; + sll $t9, $t8, 1 ## L:517 | 55 | vtx_size2 = vtx_size * 2; + ldv $v01, 8, 0, $t0 ## L:466 | 56 | m0:sint = load(address, 0x00).xyzwxyzw; + ldv $v05, 8, 16, $t0 ## L:470 | 57 | m2:sint = load(address, 0x10).xyzwxyzw; + ldv $v21, 8, 0, $at ## L:564 | 58 | vec16 vdiffuse = load(MATERIAL_DIFFUSE).xyzwxyzw; + ori $at, $zero, %lo(MATERIAL_AMBIENT) ## L:565 | 59 | vec16 vambient = load(MATERIAL_AMBIENT).xyzwxyzw; + ldv $v07, 0, 24, $t0 ## L:472 | 60 | m3:sint = load(address, 0x18).xyzwxyzw; + ldv $v22, 0, 0, $at ## L:565 | 61 | vec16 vambient = load(MATERIAL_AMBIENT).xyzwxyzw; + ldv $v02, 0, 32, $t0 ## L:467 | 62 | m0:ufract = load(address, 0x20).xyzwxyzw; + ldv $v22, 8, 0, $at ## L:565 | 63 | vec16 vambient = load(MATERIAL_AMBIENT).xyzwxyzw; + ldv $v07, 8, 24, $t0 ## L:472 | 64 | m3:sint = load(address, 0x18).xyzwxyzw; + ori $at, $zero, %lo(MATERIAL_EMISSIVE) ## L:566 | 65 | vec16 vemissive = load(MATERIAL_EMISSIVE).xyzwxyzw; + ldv $v04, 8, 40, $t0 ## L:469 | 66 | m1:ufract = load(address, 0x28).xyzwxyzw; + ldv $v23, 0, 0, $at ## L:566 | 67 | vec16 vemissive = load(MATERIAL_EMISSIVE).xyzwxyzw; + ldv $v03, 8, 8, $t0 ## L:468 | 68 | m1:sint = load(address, 0x08).xyzwxyzw; + ldv $v23, 8, 0, $at ## L:566 | 69 | vec16 vemissive = load(MATERIAL_EMISSIVE).xyzwxyzw; + ldv $v06, 0, 48, $t0 ## L:471 | 70 | m2:ufract = load(address, 0x30).xyzwxyzw; + ori $at, $zero, %lo(MG_SCRATCH_MEM) ## L:568 | 71 | store(vdiffuse, MG_SCRATCH_MEM, 0x30); + addiu $k1, $zero, 48 ## L:559 | 72 | u16 mat_ptr_diffuse = 0x30; + ldv $v02, 8, 32, $t0 ## L:467 | 73 | m0:ufract = load(address, 0x20).xyzwxyzw; + andi $s1, $s0, 1 ## L:573 | 74 | u16 tmp = mat_flags & 0x1; + ldv $v06, 8, 48, $t0 ## L:471 | 75 | m2:ufract = load(address, 0x30).xyzwxyzw; + sqv $v21, 0, 48, $at ## L:568 | 76 | store(vdiffuse, MG_SCRATCH_MEM, 0x30); + lbu $t0, %lo(LIGHTING_HAS_POINTS + 0) ## L:541 | 77 | u8 has_points = load(LIGHTING_HAS_POINTS); + addiu $t2, $s7, 40 ## L:545 | 78 | u16 vtx_out1_ptr = vtx_out0_ptr + 40; + ori $t4, $zero, %lo(MG_SCRATCH_MEM) ## L:548 | 79 | u16 prev_out1 = MG_SCRATCH_MEM; + sqv $v23, 0, 80, $at ## L:570 | 80 | store(vemissive, MG_SCRATCH_MEM, 0x50); + addiu $sp, $zero, 64 ## L:560 | 81 | u16 mat_ptr_ambient = 0x40; + ori $t3, $zero, %lo(MG_SCRATCH_MEM) ## L:547 | 82 | u16 prev_out0 = MG_SCRATCH_MEM; + addiu $fp, $zero, 80 ## L:561 | 83 | u16 mat_ptr_emissive = 0x50; + beq $s1, $zero, LABEL_gl_pipeline_0001 ## L:574 | 84 | if (tmp != 0) { + sqv $v22, 0, 64, $at ## L:569 | *86 | store(vambient, MG_SCRATCH_MEM, 0x40); + addiu $k1, $zero, 96 ## L:575 | 87 | mat_ptr_diffuse = 0x60; + LABEL_gl_pipeline_0001: + andi $s1, $s0, 2 ## L:577 | 88 | tmp = mat_flags & 0x2; + beq $s1, $zero, LABEL_gl_pipeline_0002 ## L:578 | 89 | if (tmp != 0 ) { + nop ## L:578 | *91 | if (tmp != 0 ) { + addiu $sp, $zero, 96 ## L:579 | 92 | mat_ptr_ambient = 0x60; + LABEL_gl_pipeline_0002: + andi $s1, $s0, 4 ## L:581 | 93 | tmp = mat_flags & 0x4; + beq $s1, $zero, LABEL_gl_pipeline_0003 ## L:582 | 94 | if (tmp != 0) { + nop ## L:582 | *96 | if (tmp != 0) { + addiu $fp, $zero, 96 ## L:583 | 97 | mat_ptr_emissive = 0x60; + LABEL_gl_pipeline_0003: + LOAD_NORMAL587: lsv $v15, 0, 0, $s4 ## L:587 | 98 | @AttrLoader("NORMAL") vnorm.x = load(vtx_in0_ptr).x; + LOAD_NORMAL588: lsv $v15, 8, 0, $t1 ## L:588 | 99 | @AttrLoader("NORMAL") vnorm.X = load(vtx_in1_ptr).x; + LOAD_COLOR591: llv $v18, 0, 0, $s4 ## L:591 | 100 | @AttrLoader("COLOR") vrgba_in.xy = load(vtx_in0_ptr).xy; + LOAD_COLOR592: llv $v18, 4, 0, $t1 ## L:592 | 101 | @AttrLoader("COLOR") vrgba_in.zw = load(vtx_in1_ptr).xy; + LOAD_POSITION589: ldv $v14, 0, 0, $s4 ## L:589 | 102 | @AttrLoader("POSITION") vpos.xyzw = load(vtx_in0_ptr).xyzw; + LOAD_POSITION590: ldv $v14, 8, 0, $t1 ## L:590 | 103 | @AttrLoader("POSITION") vpos.XYZW = load(vtx_in1_ptr).xyzw; + VERTEX_LOOP: + vand $v15, $v12, $v15.h0 ## L:627 | ^ | vnorm = vnormmask & vnorm.xxxxXXXX; + ori $at, $zero, %lo(RSPQ_SCRATCH_MEM) ## L:614 | ***107 | @Barrier("unpack_col") store(vrgba_in.xyzw, RSPQ_SCRATCH_MEM); ## Barrier: 0x100 + vmudn $v15, $v15, $v13.v ## L:628 | ^ | vnorm *= vnormfactor; + vmudn $v29, $v02, $v14.h0 ## L:631 | 108 | VTEMP = vmvp0 * vpos.xxxxXXXX; + sdv $v18, 0, 0, $at ## L:614 | ^ | @Barrier("unpack_col") store(vrgba_in.xyzw, RSPQ_SCRATCH_MEM); ## Barrier: 0x100 + vmadh $v29, $v01, $v14.h0 ## L:631 | 109 | VTEMP = vmvp0 * vpos.xxxxXXXX; + vmadn $v29, $v04, $v14.h1 ## L:632 | 110 | VTEMP = vmvp1 +* vpos.yyyyYYYY; + suv $v17, 4, 8, $t4 ## L:609 | ^ | @Barrier("st_tex1") store_vec_u8(vrgba.X, prev_out1, 8); ## Barrier: 0x80 + vmadh $v29, $v03, $v14.h1 ## L:632 | 111 | VTEMP = vmvp1 +* vpos.yyyyYYYY; + sdv $v19, 8, 0, $t4 ## L:601 | ^ | @Barrier("st_c1") @Barrier("st_tr1") store(vpos_clip:sint.XYZW, prev_out1, 0); ## Barrier: 0x30 + vmadn $v29, $v06, $v14.h2 ## L:633 | 112 | VTEMP = vmvp2 +* vpos.zzzzZZZZ; + suv $v17, 0, 8, $t3 ## L:608 | ^ | @Barrier("st_tex0") store_vec_u8(vrgba.x, prev_out0, 8); ## Barrier: 0x40 + vmadh $v29, $v05, $v14.h2 ## L:633 | 113 | VTEMP = vmvp2 +* vpos.zzzzZZZZ; + sdv $v19, 0, 0, $t3 ## L:600 | ^ | @Barrier("st_c0") @Barrier("st_tr0") store(vpos_clip:sint.xyzw, prev_out0, 0); ## Barrier: 0xC + sb $t5, 6($t3) ## L:603 | 114 | @Barrier("st_c0") store(c0, prev_out0, 6); ## Barrier: 0x4 + vmadn $v20, $v08, $v30.e2 ## L:634 | ^ | vpos_clip = vmvp3 +* 0x20; + vmadh $v19, $v07, $v30.e2 ## L:634 | 115 | vpos_clip = vmvp3 +* 0x20; + slv $v16, 0, 12, $t3 ## L:611 | ^ | @Barrier("st_tex0") store(vtex.xy, prev_out0, 12); ## Barrier: 0x40 + slv $v16, 8, 12, $t4 ## L:612 | 116 | @Barrier("st_tex1") store(vtex.XY, prev_out1, 12); ## Barrier: 0x80 + vmulf $v29, $v09, $v15.h0 ## L:636 | ^ | VTEMP = vmn0:sfract * vnorm:sfract.xxxxXXXX; + sb $k0, 7($t4) ## L:606 | 117 | @Barrier("st_tr1") store(tr1, prev_out1, 7); ## Barrier: 0x20 + vmacf $v29, $v10, $v15.h1 ## L:637 | ^ | VTEMP = vmn1:sfract +* vnorm:sfract.yyyyYYYY; + vmacf $v15, $v11, $v15.h2 ## L:638 | 118 | vnorm = vmn2:sfract +* vnorm:sfract.zzzzZZZZ; + LOAD_TEXCOORD620: llv $v16, 0, 0, $s4 ## L:620 | ^ | @AttrLoader("TEXCOORD") vtex.xy = load(vtx_in0_ptr).xy; ## Barrier: 0x7E00 + luv $v18, 0, 0, $at ## L:615 | ***122 | @Barrier("unpack_col") vrgba_in = load_vec_u8(RSPQ_SCRATCH_MEM); ## Barrier: 0x100 + vmudh $v22, $v15, $v15.v ## L:642 | ^ | vec32 vsqdist = vnorm * vnorm; + ori $at, $zero, %lo(MG_SCRATCH_MEM) ## L:616 | 123 | store(vrgba_in, MG_SCRATCH_MEM, 0x60); + vsar $v22, COP2_ACC_MD ## L:642 | ^ | vec32 vsqdist = vnorm * vnorm; + vsar $v21, COP2_ACC_HI ## L:642 | 124 | vec32 vsqdist = vnorm * vnorm; + vaddc $v24, $v22, $v22.h1 ## L:643 | **127 | vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + vadd $v23, $v21, $v21.h1 ## L:643 | 128 | vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + vaddc $v22, $v24, $v22.h2 ## L:644 | **131 | vsqdist = vtmp + vsqdist.zzzzZZZZ; + sqv $v18, 0, 96, $at ## L:616 | ^ | store(vrgba_in, MG_SCRATCH_MEM, 0x60); + sb $t6, 6($t4) ## L:604 | 132 | @Barrier("st_c1") store(c1, prev_out1, 6); ## Barrier: 0x10 + vadd $v21, $v23, $v21.h2 ## L:644 | ^ | vsqdist = vtmp + vsqdist.zzzzZZZZ; + LOAD_TEXCOORD623: llv $v16, 8, 0, $t1 ## L:623 | 133 | @AttrLoader("TEXCOORD") vtex.XY = load(vtx_in1_ptr).xy; ## Barrier: 0x7E00 + sdv $v19, 8, 24, $t2 ## L:667 | **136 | @Barrier("st_cp1") store(vpos_clip.XYZW, vtx_out1_ptr, 24); ## Barrier: 0x400 + vrsqh $v25.e0, $v21.e0 ## L:647 | ^ | vinvdist.x = invert_half_sqrt(vsqdist).x; + vrsql $v26.e0, $v22.e0 ## L:647 | 137 | vinvdist.x = invert_half_sqrt(vsqdist).x; + ori $at, $zero, %lo(MG_CLIP_FACTORS) ## L:656 | ^ | vec16 vclip_factors = load(MG_CLIP_FACTORS).xyzwxyzw; + vrsqh $v25.e0, $v21.e4 ## L:648 | 138 | vinvdist.X = invert_half_sqrt(vsqdist).X; + ldv $v21, 0, 0, $at ## L:656 | ^ | vec16 vclip_factors = load(MG_CLIP_FACTORS).xyzwxyzw; + vrsql $v26.e4, $v22.e4 ## L:648 | 139 | vinvdist.X = invert_half_sqrt(vsqdist).X; + vrsqh $v25.e4, $v00.e0 ## L:648 | 140 | vinvdist.X = invert_half_sqrt(vsqdist).X; + ldv $v21, 8, 0, $at ## L:656 | ^ | vec16 vclip_factors = load(MG_CLIP_FACTORS).xyzwxyzw; + sdv $v19, 0, 24, $s7 ## L:666 | **143 | @Barrier("st_cp0") store(vpos_clip.xyzw, vtx_out0_ptr, 24); ## Barrier: 0x200 + vmudm $v29, $v15, $v26.h0 ## L:650 | ^ | vnorm *= vinvdist.xxxxXXXX; + vmadh $v15, $v15, $v25.h0 ## L:650 | 144 | vnorm *= vinvdist.xxxxXXXX; + sb $t7, 7($t3) ## L:605 | ^ | @Barrier("st_tr0") store(tr0, prev_out0, 7); ## Barrier: 0x8 + ori $at, $zero, %lo(FOG_PARAMS) ## L:671 | 145 | vec16 vfog_parms = load(FOG_PARAMS).xyzwxyzw; + vmudn $v23, $v20, $v21.v ## L:657 | ^ | vec32 vguard = vpos_clip * vclip_factors; + sdv $v20, 8, 32, $t2 ## L:667 | 146 | @Barrier("st_cp1") store(vpos_clip.XYZW, vtx_out1_ptr, 24); ## Barrier: 0x400 + vmadh $v22, $v19, $v21.v ## L:657 | ^ | vec32 vguard = vpos_clip * vclip_factors; + sdv $v20, 0, 32, $s7 ## L:666 | ***150 | @Barrier("st_cp0") store(vpos_clip.xyzw, vtx_out0_ptr, 24); ## Barrier: 0x200 + vch $v29, $v22, $v22.h3 ## L:658 | ^ | u16 clip_codes = clip(vguard, vguard.wwwwWWWW); + ldv $v22, 0, 0, $at ## L:671 | 151 | vec16 vfog_parms = load(FOG_PARAMS).xyzwxyzw; + vcl $v29, $v23, $v23.h3 ## L:658 | ^ | u16 clip_codes = clip(vguard, vguard.wwwwWWWW); + cfc2 $s0, $vcc ## L:658 | 152 | u16 clip_codes = clip(vguard, vguard.wwwwWWWW); + ldv $v22, 8, 0, $at ## L:671 | 153 | vec16 vfog_parms = load(FOG_PARAMS).xyzwxyzw; + ori $at, $zero, %lo(MG_VIEWPORT) ## L:680 | 154 | vec16 vviewscale = load(MG_VIEWPORT, 0).xyzwxyzw; + andi $s2, $s0, 1799 ## L:432 | 155 | t0 = codes & 0x707; + vch $v29, $v19, $v19.h3 ## L:662 | ^ | u16 tr_codes = clip(vpos_clip, vpos_clip.wwwwWWWW); + vcl $v29, $v20, $v20.h3 ## L:662 | 156 | u16 tr_codes = clip(vpos_clip, vpos_clip.wwwwWWWW); + srl $s3, $s2, 5 ## L:433 | ^ | t1 = t0 >> 5; + vaddc $v23, $v20, $v22.h1 ## L:672 | 157 | vec16 vtmp:ufract = vpos_clip:ufract + vfog_parms:ufract.yyyyYYYY; + srl $s1, $s0, 4 ## L:452 | ^ | u16 codes2 = codes >> 4; + or $t5, $s2, $s3 ## L:440 | 158 | result = t0 | t1; + vadd $v21, $v19, $v22.h0 ## L:673 | ^ | vfog:sint = vpos_clip:sint + vfog_parms:sint.xxxxXXXX; + andi $s2, $s1, 1799 ## L:432 | 159 | t0 = codes & 0x707; + srl $s3, $s2, 5 ## L:433 | 160 | t1 = t0 >> 5; + cfc2 $s1, $vcc ## L:662 | 161 | u16 tr_codes = clip(vpos_clip, vpos_clip.wwwwWWWW); + vmudn $v29, $v23, $v22.h2 ## L:675 | ^ | VTEMP = vtmp:ufract * vfog_parms:sint.zzzzZZZZ; + vmadh $v21, $v21, $v22.h2 ## L:676 | 162 | vfog = vfog:sint +* vfog_parms:sint.zzzzZZZZ; + ldv $v22, 0, 0, $at ## L:680 | ^ | vec16 vviewscale = load(MG_VIEWPORT, 0).xyzwxyzw; + ldv $v22, 8, 0, $at ## L:680 | 163 | vec16 vviewscale = load(MG_VIEWPORT, 0).xyzwxyzw; + or $t6, $s2, $s3 ## L:440 | 164 | result = t0 | t1; + andi $s3, $s1, 1799 ## L:432 | 165 | t0 = codes & 0x707; + srl $s5, $s3, 5 ## L:433 | 166 | t1 = t0 >> 5; + vge $v21, $v00, $v21.h2 ## L:677 | ^ | vfog = max(VZERO, vfog.zzzzZZZZ); + srl $s2, $s1, 4 ## L:459 | 167 | u16 codes2 = codes >> 4; + vmudl $v20, $v20, $v22.h3 ## L:683 | ^ | vpos_clip *= vviewscale:sfract.wwwwWWWW; + vmadm $v19, $v19, $v22.h3 ## L:683 | 168 | vpos_clip *= vviewscale:sfract.wwwwWWWW; + nor $t7, $s3, $s5 ## L:447 | ^ | result = t0 ~| t1; + vmadn $v20, $v00, $v00 ## L:683 | 169 | vpos_clip *= vviewscale:sfract.wwwwWWWW; + ldv $v23, 0, 8, $at ## L:681 | ^ | vec16 vviewoff = load(MG_VIEWPORT, 8).xyzwxyzw; + ssv $v19, 14, 16, $t2 ## L:687 | **172 | @Barrier("st_w1") store(vpos_clip.W, vtx_out1_ptr, 16); ## Barrier: 0x1000 + vrcph $v24.e3, $v19.e3 ## L:690 | ^ | vinvw.w = invert_half(vpos_clip).w; + andi $s3, $s2, 1799 ## L:432 | 173 | t0 = codes & 0x707; + vrcpl $v25.e3, $v20.e3 ## L:690 | ^ | vinvw.w = invert_half(vpos_clip).w; + vrcph $v24.e3, $v19.e7 ## L:691 | 174 | vinvw.W = invert_half(vpos_clip).W; + ldv $v23, 8, 8, $at ## L:681 | ^ | vec16 vviewoff = load(MG_VIEWPORT, 8).xyzwxyzw; + ssv $v19, 6, 16, $s7 ## L:686 | 175 | @Barrier("st_w0") store(vpos_clip.w, vtx_out0_ptr, 16); ## Barrier: 0x800 + vrcpl $v25.e7, $v20.e7 ## L:691 | ^ | vinvw.W = invert_half(vpos_clip).W; + vrcph $v24.e7, $v00.e7 ## L:691 | 176 | vinvw.W = invert_half(vpos_clip).W; + srl $s5, $s3, 5 ## L:433 | ^ | t1 = t0 >> 5; + ssv $v20, 6, 18, $s7 ## L:686 | 177 | @Barrier("st_w0") store(vpos_clip.w, vtx_out0_ptr, 16); ## Barrier: 0x800 + nor $k0, $s3, $s5 ## L:447 | 178 | result = t0 ~| t1; + ssv $v20, 14, 18, $t2 ## L:687 | 179 | @Barrier("st_w1") store(vpos_clip.W, vtx_out1_ptr, 16); ## Barrier: 0x1000 + vmudl $v29, $v20, $v25.h3 ## L:696 | ^ | vpos_clip *= vinvw.wwwwWWWW; + ssv $v24, 6, 20, $s7 ## L:693 | 180 | @Barrier("st_iw0") store(vinvw.w, vtx_out0_ptr, 20); ## Barrier: 0x2000 + vmadm $v29, $v19, $v25.h3 ## L:696 | ^ | vpos_clip *= vinvw.wwwwWWWW; + ssv $v25, 6, 22, $s7 ## L:693 | 181 | @Barrier("st_iw0") store(vinvw.w, vtx_out0_ptr, 20); ## Barrier: 0x2000 + vmadn $v20, $v20, $v24.h3 ## L:696 | ^ | vpos_clip *= vinvw.wwwwWWWW; + ssv $v24, 14, 20, $t2 ## L:694 | 182 | @Barrier("st_iw1") store(vinvw.W, vtx_out1_ptr, 20); ## Barrier: 0x4000 + vmadh $v19, $v19, $v24.h3 ## L:696 | ^ | vpos_clip *= vinvw.wwwwWWWW; + vmudh $v29, $v23, $v30.e7 ## L:700 | 183 | VTEMP = vviewoff:sint * 1; + ssv $v25, 14, 22, $t2 ## L:694 | ^ | @Barrier("st_iw1") store(vinvw.W, vtx_out1_ptr, 20); ## Barrier: 0x4000 + vmadn $v20, $v20, $v22.v ## L:701 | *185 | vpos_clip = vpos_clip +* vviewscale; + beq $t0, $zero, LABEL_gl_pipeline_0004 ## L:707 | ^ | if (has_points != 0) + vmadh $v19, $v19, $v22.v ## L:701 | *187 | vpos_clip = vpos_clip +* vviewscale; + ori $s0, $zero, %lo(MATRICES_MV) ## L:710 | 188 | u16 addr = MATRICES_MV; + ldv $v01, 0, 0, $s0 ## L:466 | 189 | m0:sint = load(address, 0x00).xyzwxyzw; + ldv $v04, 0, 40, $s0 ## L:469 | 190 | m1:ufract = load(address, 0x28).xyzwxyzw; + ldv $v01, 8, 0, $s0 ## L:466 | 191 | m0:sint = load(address, 0x00).xyzwxyzw; + ldv $v06, 0, 48, $s0 ## L:471 | 192 | m2:ufract = load(address, 0x30).xyzwxyzw; + ldv $v02, 0, 32, $s0 ## L:467 | 193 | m0:ufract = load(address, 0x20).xyzwxyzw; + ldv $v03, 0, 8, $s0 ## L:468 | 194 | m1:sint = load(address, 0x08).xyzwxyzw; + ldv $v02, 8, 32, $s0 ## L:467 | 195 | m0:ufract = load(address, 0x20).xyzwxyzw; + ldv $v03, 8, 8, $s0 ## L:468 | 196 | m1:sint = load(address, 0x08).xyzwxyzw; + ldv $v08, 0, 56, $s0 ## L:473 | 197 | m3:ufract = load(address, 0x38).xyzwxyzw; + ldv $v04, 8, 40, $s0 ## L:469 | 198 | m1:ufract = load(address, 0x28).xyzwxyzw; + ldv $v08, 8, 56, $s0 ## L:473 | 199 | m3:ufract = load(address, 0x38).xyzwxyzw; + ldv $v06, 8, 48, $s0 ## L:471 | 200 | m2:ufract = load(address, 0x30).xyzwxyzw; + vmudn $v29, $v02, $v14.h0 ## L:713 | ^ | VTEMP = vmvp0 * vpos.xxxxXXXX; + ldv $v05, 0, 16, $s0 ## L:470 | 201 | m2:sint = load(address, 0x10).xyzwxyzw; + vmadh $v29, $v01, $v14.h0 ## L:713 | ^ | VTEMP = vmvp0 * vpos.xxxxXXXX; + ldv $v05, 8, 16, $s0 ## L:470 | 202 | m2:sint = load(address, 0x10).xyzwxyzw; + vmadn $v29, $v04, $v14.h1 ## L:714 | ^ | VTEMP = vmvp1 +* vpos.yyyyYYYY; + vmadh $v29, $v03, $v14.h1 ## L:714 | 203 | VTEMP = vmvp1 +* vpos.yyyyYYYY; + ldv $v07, 0, 24, $s0 ## L:472 | ^ | m3:sint = load(address, 0x18).xyzwxyzw; + ldv $v07, 8, 24, $s0 ## L:472 | 204 | m3:sint = load(address, 0x18).xyzwxyzw; + vmadn $v29, $v06, $v14.h2 ## L:715 | ^ | VTEMP = vmvp2 +* vpos.zzzzZZZZ; + vmadh $v29, $v05, $v14.h2 ## L:715 | *206 | VTEMP = vmvp2 +* vpos.zzzzZZZZ; + vmadn $v29, $v08, $v30.e2 ## L:716 | 207 | vpos = vmvp3 +* 0x20; + vmadh $v14, $v07, $v30.e2 ## L:716 | 208 | vpos = vmvp3 +* 0x20; + LABEL_gl_pipeline_0004: + ori $at, $zero, %lo(LIGHTING_AMBIENT) ## L:719 | ^ | vrgba = load(LIGHTING_AMBIENT).xyzwxyzw; + ldv $v17, 0, 0, $at ## L:719 | 209 | vrgba = load(LIGHTING_AMBIENT).xyzwxyzw; + ldv $v17, 8, 0, $at ## L:719 | 210 | vrgba = load(LIGHTING_AMBIENT).xyzwxyzw; + addiu $at, $k1, MG_SCRATCH_MEM ## L:721 | 211 | vec16 vdiffuse = load(mat_ptr_diffuse, MG_SCRATCH_MEM); + lqv $v22, 0, 0, $at ## L:721 | 212 | vec16 vdiffuse = load(mat_ptr_diffuse, MG_SCRATCH_MEM); + addiu $at, $sp, MG_SCRATCH_MEM ## L:722 | 213 | vec16 vambient = load(mat_ptr_ambient, MG_SCRATCH_MEM); + lqv $v23, 0, 0, $at ## L:722 | 214 | vec16 vambient = load(mat_ptr_ambient, MG_SCRATCH_MEM); + addiu $at, $fp, MG_SCRATCH_MEM ## L:723 | 215 | vec16 vemissive = load(mat_ptr_emissive, MG_SCRATCH_MEM); + lqv $v24, 0, 0, $at ## L:723 | 216 | vec16 vemissive = load(mat_ptr_emissive, MG_SCRATCH_MEM); + lbu $s0, %lo(LIGHTING_COUNT + 0) ## L:730 | 217 | u8 light_count = load(LIGHTING_COUNT); + ori $s1, $zero, %lo(LIGHTING_LIGHTS) ## L:732 | **220 | u16 light_ptr = LIGHTING_LIGHTS; + vmudh $v29, $v24, $v30.e7 ## L:725 | ^ | VTEMP = vemissive:sint * 1; + beq $s0, $zero, LIGHT_END ## L:733 | 221 | if (light_count == 0) goto LIGHT_END; + vmacf $v17, $v17, $v23.v ## L:726 | *223 | vrgba:sfract = vrgba:sfract +* vambient:sfract; + LIGHT_LOOP: + ldv $v26, 0, 0, $s1 ## L:739 | 224 | vec16 vlpos = load(light_ptr, 0).xyzwxyzw; + ldv $v25, 0, 8, $s1 ## L:738 | 225 | vec16 vlcol = load(light_ptr, 8).xyzwxyzw; + addiu $s2, $s1, 14 ## L:736 | 226 | u16 amb_ptr = light_ptr + 14; + ldv $v26, 8, 0, $s1 ## L:739 | 227 | vec16 vlpos = load(light_ptr, 0).xyzwxyzw; + lh $s3, 6($s1) ## L:743 | 228 | s16 light_w = load(light_ptr, 6); + ldv $v25, 8, 8, $s1 ## L:738 | 229 | vec16 vlcol = load(light_ptr, 8).xyzwxyzw; + ldv $v24, 0, 0, $s2 ## L:737 | 230 | vec16 vlambient = load(amb_ptr, 0).xyzwxyzw; + ldv $v24, 8, 0, $s2 ## L:737 | 231 | vec16 vlambient = load(amb_ptr, 0).xyzwxyzw; + beq $s3, $zero, LABEL_gl_pipeline_0006 ## L:744 | 232 | if (light_w != 0) + vmulf $v25, $v25, $v22.v ## L:741 | *234 | vlcol:sfract *= vdiffuse; + vsubc $v26, $v26, $v14.v ## L:758 | 235 | vlpos -= vpos; + addiu $s5, $s1, 20 ## L:752 | ^ | u16 att_ptr = light_ptr + 20; + vmudh $v04, $v26, $v26.v ## L:759 | ***239 | vec32 vsqdist = vlpos * vlpos; + ldv $v01, 0, 0, $s5 ## L:754 | ^ | vatten:sint = load(att_ptr, 0).xyzwxyzw; + ldv $v01, 8, 0, $s5 ## L:754 | 240 | vatten:sint = load(att_ptr, 0).xyzwxyzw; + vsar $v04, COP2_ACC_MD ## L:759 | ^ | vec32 vsqdist = vlpos * vlpos; + vsar $v03, COP2_ACC_HI ## L:759 | 241 | vec32 vsqdist = vlpos * vlpos; + addiu $s5, $s5, 6 ## L:755 | ^ | att_ptr += 6; + ldv $v02, 0, 0, $s5 ## L:756 | 242 | vatten:ufract = load(att_ptr, 0).xyzwxyzw; + ldv $v02, 8, 0, $s5 ## L:756 | *244 | vatten:ufract = load(att_ptr, 0).xyzwxyzw; + vaddc $v06, $v04, $v04.h1 ## L:760 | ^ | vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + ori $s5, $zero, %lo(MATRICES_MVP) ## L:786 | 245 | u16 addr = MATRICES_MVP; + vadd $v05, $v03, $v03.h1 ## L:760 | ^ | vec32 vtmp = vsqdist + vsqdist.yyyyYYYY; + vaddc $v04, $v06, $v04.h2 ## L:761 | **248 | vsqdist = vtmp + vsqdist.zzzzZZZZ; + vadd $v03, $v05, $v03.h2 ## L:761 | 249 | vsqdist = vtmp + vsqdist.zzzzZZZZ; + vrsqh $v05.e0, $v03.e0 ## L:763 | ***253 | vtmp.x = invert_half_sqrt(vsqdist).x; + vrsql $v06.e0, $v04.e0 ## L:763 | 254 | vtmp.x = invert_half_sqrt(vsqdist).x; + vrsqh $v05.e0, $v03.e4 ## L:764 | 255 | vtmp.X = invert_half_sqrt(vsqdist).X; + vrsql $v06.e4, $v04.e4 ## L:764 | 256 | vtmp.X = invert_half_sqrt(vsqdist).X; + vrsqh $v05.e4, $v00.e0 ## L:764 | 257 | vtmp.X = invert_half_sqrt(vsqdist).X; + vmudl $v29, $v06, $v04.v ## L:766 | **260 | vec32 vdist = vtmp * vsqdist; + vmadm $v29, $v05, $v04.v ## L:766 | 261 | vec32 vdist = vtmp * vsqdist; + vmadn $v08, $v06, $v03.v ## L:766 | 262 | vec32 vdist = vtmp * vsqdist; + vmadh $v07, $v05, $v03.v ## L:766 | 263 | vec32 vdist = vtmp * vsqdist; + vmudm $v29, $v26, $v06.h0 ## L:768 | 264 | vlpos *= vtmp.xxxxXXXX; + ldv $v06, 0, 48, $s5 ## L:471 | ^ | m2:ufract = load(address, 0x30).xyzwxyzw; + vmadh $v26, $v26, $v05.h0 ## L:768 | 265 | vlpos *= vtmp.xxxxXXXX; + vmudn $v29, $v02, $v30.e7 ## L:770 | 266 | VTEMP = vatten * 1; + vmadh $v29, $v01, $v30.e7 ## L:770 | 267 | VTEMP = vatten * 1; + vmadl $v29, $v08, $v02.h1 ## L:771 | 268 | VTEMP = vdist +* vatten.yyyyYYYY; + vmadm $v29, $v07, $v02.h1 ## L:771 | 269 | VTEMP = vdist +* vatten.yyyyYYYY; + vmadn $v29, $v08, $v01.h1 ## L:771 | 270 | VTEMP = vdist +* vatten.yyyyYYYY; + vmadh $v29, $v07, $v01.h1 ## L:771 | 271 | VTEMP = vdist +* vatten.yyyyYYYY; + vmadl $v29, $v04, $v02.h2 ## L:772 | 272 | vatten = vsqdist +* vatten.zzzzZZZZ; + ldv $v07, 8, 24, $s5 ## L:472 | ^ | m3:sint = load(address, 0x18).xyzwxyzw; + vmadm $v29, $v03, $v02.h2 ## L:772 | 273 | vatten = vsqdist +* vatten.zzzzZZZZ; + ldv $v06, 8, 48, $s5 ## L:471 | ^ | m2:ufract = load(address, 0x30).xyzwxyzw; + vmadn $v02, $v04, $v01.h2 ## L:772 | 274 | vatten = vsqdist +* vatten.zzzzZZZZ; + ldv $v07, 0, 24, $s5 ## L:472 | ^ | m3:sint = load(address, 0x18).xyzwxyzw; + vmadh $v01, $v03, $v01.h2 ## L:772 | 275 | vatten = vsqdist +* vatten.zzzzZZZZ; + ldv $v08, 0, 56, $s5 ## L:473 | ^ | m3:ufract = load(address, 0x38).xyzwxyzw; + vrcph $v01.e0, $v01.e0 ## L:774 | ***279 | vatten.x = invert_half(vatten).x; + ldv $v03, 8, 8, $s5 ## L:468 | ^ | m1:sint = load(address, 0x08).xyzwxyzw; + ldv $v04, 8, 40, $s5 ## L:469 | 280 | m1:ufract = load(address, 0x28).xyzwxyzw; + vrcpl $v02.e0, $v02.e0 ## L:774 | ^ | vatten.x = invert_half(vatten).x; + ldv $v05, 8, 16, $s5 ## L:470 | 281 | m2:sint = load(address, 0x10).xyzwxyzw; + ldv $v05, 0, 16, $s5 ## L:470 | 282 | m2:sint = load(address, 0x10).xyzwxyzw; + ldv $v03, 0, 8, $s5 ## L:468 | 283 | m1:sint = load(address, 0x08).xyzwxyzw; + vrcph $v01.e0, $v01.e4 ## L:775 | ^ | vatten.X = invert_half(vatten).X; + ldv $v08, 8, 56, $s5 ## L:473 | 284 | m3:ufract = load(address, 0x38).xyzwxyzw; + vrcpl $v02.e4, $v02.e4 ## L:775 | ^ | vatten.X = invert_half(vatten).X; + vrcph $v01.e4, $v00.e4 ## L:775 | 285 | vatten.X = invert_half(vatten).X; + ldv $v04, 0, 40, $s5 ## L:469 | ^ | m1:ufract = load(address, 0x28).xyzwxyzw; + vmudm $v29, $v25, $v02.h0 ## L:777 | **288 | vlcol *= vatten.xxxxXXXX; + ldv $v02, 0, 32, $s5 ## L:467 | ^ | m0:ufract = load(address, 0x20).xyzwxyzw; + vmadh $v25, $v25, $v01.h0 ## L:777 | 289 | vlcol *= vatten.xxxxXXXX; + ldv $v02, 8, 32, $s5 ## L:467 | ^ | m0:ufract = load(address, 0x20).xyzwxyzw; + ldv $v01, 8, 0, $s5 ## L:466 | 290 | m0:sint = load(address, 0x00).xyzwxyzw; + ldv $v01, 0, 0, $s5 ## L:466 | 291 | m0:sint = load(address, 0x00).xyzwxyzw; + LABEL_gl_pipeline_0006: + vmulf $v26, $v26, $v15.v ## L:791 | ^ | vlpos *= vnorm:sfract; + vmudn $v29, $v24, $v23.v ## L:792 | 292 | VTEMP = vlambient * vambient; + vmacf $v29, $v25, $v26.h0 ## L:793 | **295 | VTEMP = vlcol:sfract +* vlpos:sfract.xxxxXXXX; + vmacf $v29, $v25, $v26.h1 ## L:794 | 296 | VTEMP = vlcol:sfract +* vlpos:sfract.yyyyYYYY; + addiu $s0, $s0, 65535 ## L:801 | ^ | light_count -= 1; + vmacf $v25, $v25, $v26.h2 ## L:795 | 297 | vlcol = vlcol:sfract +* vlpos:sfract.zzzzZZZZ; + addiu $s1, $s1, 32 ## L:800 | ^ | light_ptr += 32; + vge $v25, $v25, $v00 ## L:796 | ***301 | vlcol = max(vlcol, VZERO); + bne $s0, $zero, LIGHT_LOOP ## L:802 | ^ | if (light_count != 0) goto LIGHT_LOOP; + vadd $v17, $v17, $v25.v ## L:798 | ****306 | vrgba:sint += vlcol; + LIGHT_END: + ori $at, $zero, %lo(TEXTURE_MATRIX) ## L:875 | 307 | vmt0:sint = load(TEXTURE_MATRIX, 0x00).xyzwxyzw; + ldv $v26, 0, 32, $at ## L:878 | 308 | vmt1:ufract = load(TEXTURE_MATRIX, 0x20).xyzwxyzw; + vmov $v17.e3, $v22.e3 ## L:806 | ^ | vrgba.w = vdiffuse.w; + lbu $s2, %lo(FOG_MASK + 0) ## L:813 | 309 | u8 fog_mask = load(FOG_MASK); + vmov $v17.e7, $v22.e7 ## L:807 | ^ | vrgba.W = vdiffuse.W; + ldv $v24, 0, 24, $at ## L:876 | 310 | vmt0:ufract = load(TEXTURE_MATRIX, 0x18).xyzwxyzw; + or $t4, $zero, $t2 ## L:905 | 311 | prev_out1 = vtx_out1_ptr; + ldv $v24, 8, 24, $at ## L:876 | 312 | vmt0:ufract = load(TEXTURE_MATRIX, 0x18).xyzwxyzw; + ctc2 $s2, $vcc ## L:814 | 313 | set_vcc(fog_mask); + ldv $v26, 8, 32, $at ## L:878 | 314 | vmt1:ufract = load(TEXTURE_MATRIX, 0x20).xyzwxyzw; + vmrg $v17, $v17, $v21.h2 ## L:815 | ^ | vrgba = select(vrgba, vfog.zzzzZZZZ); + ldv $v23, 0, 0, $at ## L:875 | 315 | vmt0:sint = load(TEXTURE_MATRIX, 0x00).xyzwxyzw; + ldv $v25, 0, 8, $at ## L:877 | 316 | vmt1:sint = load(TEXTURE_MATRIX, 0x08).xyzwxyzw; + ldv $v23, 8, 0, $at ## L:875 | 317 | vmt0:sint = load(TEXTURE_MATRIX, 0x00).xyzwxyzw; + ldv $v25, 8, 8, $at ## L:877 | 318 | vmt1:sint = load(TEXTURE_MATRIX, 0x08).xyzwxyzw; + ldv $v28, 0, 40, $at ## L:880 | 319 | vmt3:ufract = load(TEXTURE_MATRIX, 0x28).xyzwxyzw; + ldv $v28, 8, 40, $at ## L:880 | 320 | vmt3:ufract = load(TEXTURE_MATRIX, 0x28).xyzwxyzw; + vmudn $v29, $v24, $v16.h0 ## L:882 | ^ | VTEMP = vmt0 * vtex.xxxxXXXX; + vmadh $v29, $v23, $v16.h0 ## L:882 | 321 | VTEMP = vmt0 * vtex.xxxxXXXX; + ldv $v27, 0, 16, $at ## L:879 | ^ | vmt3:sint = load(TEXTURE_MATRIX, 0x10).xyzwxyzw; + vmadn $v29, $v26, $v16.h1 ## L:883 | 322 | VTEMP = vmt1 +* vtex.yyyyYYYY; + ldv $v27, 8, 16, $at ## L:879 | ^ | vmt3:sint = load(TEXTURE_MATRIX, 0x10).xyzwxyzw; + addu $s4, $s4, $t9 ## L:906 | 323 | vtx_in0_ptr += vtx_size2; + addu $t1, $t1, $t9 ## L:907 | 324 | vtx_in1_ptr += vtx_size2; + vmadh $v29, $v25, $v16.h1 ## L:883 | ^ | VTEMP = vmt1 +* vtex.yyyyYYYY; + ori $at, $zero, %lo(TEXTURE_SIZE) ## L:896 | 325 | vtex_size.xy = load(TEXTURE_SIZE).xy; + vmadn $v22, $v28, $v31.e7 ## L:884 | ^ | vtex_transformed = vmt3 +* 0x100; + or $t3, $zero, $s7 ## L:904 | 326 | prev_out0 = vtx_out0_ptr; + vmadh $v21, $v27, $v31.e7 ## L:884 | ^ | vtex_transformed = vmt3 +* 0x100; + LOAD_NORMAL912: lsv $v15, 8, 0, $t1 ## L:912 | ***330 | @AttrLoader("NORMAL") vnorm.X = load(vtx_in1_ptr).x; + vrcph $v23.e0, $v21.e3 ## L:889 | ^ | vinv_tex.x = invert_half(vtex_transformed).w; + vrcpl $v24.e0, $v22.e3 ## L:889 | 331 | vinv_tex.x = invert_half(vtex_transformed).w; + addiu $t2, $t2, 80 ## L:909 | ^ | vtx_out1_ptr += 80; + LOAD_POSITION914: ldv $v14, 8, 0, $t1 ## L:914 | 332 | @AttrLoader("POSITION") vpos.XYZW = load(vtx_in1_ptr).xyzw; + vrcph $v23.e0, $v21.e7 ## L:890 | ^ | vinv_tex.X = invert_half(vtex_transformed).W; + vrcpl $v24.e4, $v22.e7 ## L:890 | 333 | vinv_tex.X = invert_half(vtex_transformed).W; + LOAD_COLOR915: llv $v18, 0, 0, $s4 ## L:915 | ^ | @AttrLoader("COLOR") vrgba_in.xy = load(vtx_in0_ptr).xy; + addiu $s7, $s7, 80 ## L:908 | 334 | vtx_out0_ptr += 80; + vrcph $v23.e4, $v00.e7 ## L:890 | ^ | vinv_tex.X = invert_half(vtex_transformed).W; + LOAD_NORMAL911: lsv $v15, 0, 0, $s4 ## L:911 | **337 | @AttrLoader("NORMAL") vnorm.x = load(vtx_in0_ptr).x; + vmudl $v29, $v22, $v24.h0 ## L:892 | ^ | vtex_transformed *= vinv_tex.xxxxXXXX; + vmadm $v29, $v21, $v24.h0 ## L:892 | 338 | vtex_transformed *= vinv_tex.xxxxXXXX; + LOAD_POSITION913: ldv $v14, 0, 0, $s4 ## L:913 | ^ | @AttrLoader("POSITION") vpos.xyzw = load(vtx_in0_ptr).xyzw; + LOAD_COLOR916: llv $v18, 4, 0, $t1 ## L:916 | 339 | @AttrLoader("COLOR") vrgba_in.zw = load(vtx_in1_ptr).xy; + vmadn $v22, $v22, $v23.h0 ## L:892 | ^ | vtex_transformed *= vinv_tex.xxxxXXXX; + vmadh $v21, $v21, $v23.h0 ## L:892 | 340 | vtex_transformed *= vinv_tex.xxxxXXXX; + llv $v23, 0, 0, $at ## L:896 | ^ | vtex_size.xy = load(TEXTURE_SIZE).xy; + llv $v23, 8, 0, $at ## L:897 | 341 | vtex_size.XY = load(TEXTURE_SIZE).xy; + ori $at, $zero, %lo(TEXTURE_OFFSET) ## L:898 | 342 | vtex_offset.xy = load(TEXTURE_OFFSET).xy; + llv $v24, 0, 0, $at ## L:898 | 343 | vtex_offset.xy = load(TEXTURE_OFFSET).xy; + llv $v24, 8, 0, $at ## L:899 | 344 | vtex_offset.XY = load(TEXTURE_OFFSET).xy; + vmudh $v29, $v24, $v30.e7 ## L:901 | ***348 | VTEMP = vtex_offset:sint * 1; + sltu $at, $s4, $s6 ## L:918 | ^ | if (vtx_in0_ptr < vtx_in_end) goto VERTEX_LOOP; + vmadn $v29, $v22, $v23.v ## L:902 | 349 | vtex = vtex_transformed +* vtex_size; + bne $at, $zero, VERTEX_LOOP ## L:918 | ^ | if (vtx_in0_ptr < vtx_in_end) goto VERTEX_LOOP; + vmadh $v16, $v21, $v23.v ## L:902 | *351 | vtex = vtex_transformed +* vtex_size; + sdv $v19, 8, 0, $t4 ## L:925 | 352 | @Barrier("st_c1") @Barrier("st_tr1") store(vpos_clip:sint.XYZW, prev_out1, 0); ## Barrier: 0x30 + sb $k0, 7($t4) ## L:930 | 353 | @Barrier("st_tr1") store(tr1, prev_out1, 7); ## Barrier: 0x20 + suv $v17, 4, 8, $t4 ## L:933 | 354 | @Barrier("st_tex1") store_vec_u8(vrgba.X, prev_out1, 8); ## Barrier: 0x80 + suv $v17, 0, 8, $t3 ## L:932 | 355 | @Barrier("st_tex0") store_vec_u8(vrgba.x, prev_out0, 8); ## Barrier: 0x40 + slv $v16, 8, 12, $t4 ## L:936 | 356 | @Barrier("st_tex1") store(vtex.XY, prev_out1, 12); ## Barrier: 0x80 + sdv $v19, 0, 0, $t3 ## L:924 | 357 | @Barrier("st_c0") @Barrier("st_tr0") store(vpos_clip:sint.xyzw, prev_out0, 0); ## Barrier: 0xC + sb $t5, 6($t3) ## L:927 | 358 | @Barrier("st_c0") store(c0, prev_out0, 6); ## Barrier: 0x4 + sb $t6, 6($t4) ## L:928 | 359 | @Barrier("st_c1") store(c1, prev_out1, 6); ## Barrier: 0x10 + sb $t7, 7($t3) ## L:929 | 360 | @Barrier("st_tr0") store(tr0, prev_out0, 7); ## Barrier: 0x8 + j RSPQ_Loop ## L:937 | 361 | } + slv $v16, 0, 12, $t3 ## L:935 | *363 | @Barrier("st_tex0") store(vtex.xy, prev_out0, 12); ## Barrier: 0x40 + +MgEndShader + +#define zero $0 +#define v0 $2 +#define v1 $3 +#define a0 $4 +#define a1 $5 +#define a2 $6 +#define a3 $7 +#define t0 $8 +#define t1 $9 +#define t2 $10 +#define t3 $11 +#define t4 $12 +#define t5 $13 +#define t6 $14 +#define t7 $15 +#define s0 $16 +#define s1 $17 +#define s2 $18 +#define s3 $19 +#define s4 $20 +#define s5 $21 +#define s6 $22 +#define s7 $23 +#define t8 $24 +#define t9 $25 +#define k0 $26 +#define k1 $27 +#define gp $28 +#define sp $29 +#define fp $30 +#define ra $31 + +.set at +.set macro \ No newline at end of file diff --git a/src/GL/rsp_gl_state.inc b/src/GL/rsp_gl_state.inc index ae171c17ba..e3807b7403 100644 --- a/src/GL/rsp_gl_state.inc +++ b/src/GL/rsp_gl_state.inc @@ -1,27 +1,20 @@ -############################################################ -# rsp_gl_state.inc -# -# Authors: Giovanni Bajo -# Dennis Heinze -############################################################ GL_STATE: - # This is the GL state that is also used by the pipeline. GL_MATRICES: GL_MATRIX_MODELVIEW: .ds.b MATRIX_SIZE GL_MATRIX_PROJECTION: .ds.b MATRIX_SIZE GL_MATRIX_TEXTURE: .ds.b MATRIX_SIZE GL_MATRIX_PALETTE: .ds.b MATRIX_SIZE - GL_MATRIX_MVP: .ds.b MATRIX_SIZE - GL_LIGHTS: .ds.b LIGHT_STRUCT_SIZE + GL_LIGHTS: .ds.b GLP_LIGHT_SIZE * LIGHT_COUNT GL_TEX_GEN: .ds.b TEX_GEN_STRUCT_SIZE GL_VIEWPORT_SCALE: .half 0,0,0,0 GL_VIEWPORT_OFFSET: .half 0,0,0,0 + GL_PIPELINES: .ds.d PIPELINE_COUNT GL_STATE_LIGHT_AMBIENT: .half 0,0,0,0 GL_MAT_AMBIENT: .half 0,0,0,0 GL_MAT_DIFFUSE: .half 0,0,0,0 GL_MAT_SPECULAR: .half 0,0,0,0 GL_MAT_EMISSIVE: .half 0,0,0,0 - GL_MAT_COLOR_TARGET: .half 0,0,0 + GL_MAT_COLOR_TARGET: .half 0 GL_MAT_SHININESS: .half 0 GL_CURRENT_ATTRIBUTES: GL_CUR_COLOR: .half 0,0,0,0 @@ -33,8 +26,6 @@ GL_STATE: GL_PROJECTION_PTR: .word 0 GL_TEXTURE_PTR: .word 0 GL_PALETTE_PTR: .word 0 - GL_MVP_PTR: .word 0 - GL_LOADED_MTX_INDEX: .word 0,0 GL_STATE_FLAGS: .word 0 GL_STATE_FOG_PARAMS: .half 0,0,0,0 GL_STATE_TEX_SIZE: .half 0,0 @@ -49,7 +40,27 @@ GL_STATE: GL_STATE_MATRIX_MODE: .half 0 GL_TRI_CMD: .half 0 GL_TRI_CULL: .byte 0,0 + .align 3 + GL_BOUND_TEXTURES: + GL_BOUND_TEXTURE_1D: .ds.b TEXTURE_OBJECT_SIZE + GL_BOUND_TEXTURE_2D: .ds.b TEXTURE_OBJECT_SIZE + GL_STATE_SCISSOR_RECT: .half 0, 0, 0, 0 + GL_STATE_BLEND_CYCLE: .word 0 + GL_STATE_FOG_COLOR: .word 0 + GL_STATE_FLAGS2: .word 0 + GL_STATE_TEXTURE_IDS: .word 0, 0 + GL_STATE_UPLOADED_TEX: .word 0 + GL_STATE_FILL_COLOR: .word 0 + GL_STATE_FILL_DEPTH: .word 0 + GL_STATE_PALETTE_INDEX: .word 0 + GL_STATE_DITHER_MODE: .word 0 + GL_STATE_FB_SIZE: .half 0, 0 + GL_STATE_DEPTH_FUNC: .half 0 + GL_STATE_ALPHA_FUNC: .half 0 + GL_STATE_BLEND_SRC: .half 0 + GL_STATE_BLEND_DST: .half 0 + GL_STATE_TEX_ENV_MODE: .half 0 + GL_STATE_ALPHA_REF: .byte 0 + GL_STATE_PALETTE_DIRTY: .ds.b PALETTE_DIRTY_FLAGS_SIZE GL_STATE_END: - -#define GL_STATE_SIZE (GL_STATE_END - GL_STATE) diff --git a/src/GL/rsp_pipeline.c b/src/GL/rsp_pipeline.c index 901578d240..75739f02f9 100644 --- a/src/GL/rsp_pipeline.c +++ b/src/GL/rsp_pipeline.c @@ -7,102 +7,129 @@ #include "gl_internal.h" #include "rsp_asm.h" +#include "magma_constants.h" +#include "rdpq_debug.h" +#include "../magma/magma_internal.h" +#include "mgfx_macros.h" +#include "indices.h" +#include "draw_call_cache.h" +#include "data_cache.h" +#include "array.h" +#include "array_object.h" +#include "buffer.h" +#include "fnv1a.h" +#include "array_convert.h" +#include "pipelines.h" +#include "mg_ex.h" + +_Static_assert(BEGIN_END_BUFFER_SIZE <= MG_VERTEX_CACHE_COUNT); extern gl_state_t *state; -#define DEFINE_BYTE_READ_FUNC(name, src_type, convert) \ - static void name(gl_cmd_stream_t *s, const src_type *src, uint32_t count) \ +static phys_addr_t magma_rsp_state; + +#define DEFINE_READ_FUNC(name, dst_type, src_type, convert, max_size, default) \ + static void name(dst_type *dst, const src_type *src, uint32_t count) \ { \ - for (uint32_t i = 0; i < count; i++) gl_cmd_stream_put_byte(s, convert(src[i])); \ + uint32_t real_count = MIN(count, max_size); \ + for (uint32_t i = 0; i < real_count; i++) dst[i] = convert(src[i]); \ + for (uint32_t i = count; i < max_size; i++) dst[i] = default[i]; \ } -#define DEFINE_HALF_READ_FUNC(name, src_type, convert) \ - static void name(gl_cmd_stream_t *s, const src_type *src, uint32_t count) \ +#define DEFINE_FIXED_READ_FUNC(name, dst_type, precision, max_size, default) \ + static void name(dst_type *dst, const int16u_t *src, uint32_t count) \ { \ - for (uint32_t i = 0; i < count; i++) gl_cmd_stream_put_half(s, convert(src[i])); \ + int shift = precision.shift_amount; \ + uint32_t real_count = MIN(count, max_size); \ + if (shift < 0) { \ + for (uint32_t i = 0; i < real_count; i++) dst[i] = src[i] >> -shift; \ + } else { \ + for (uint32_t i = 0; i < real_count; i++) { \ + int16_t value = src[i]; \ + assertf(value <= SHRT_MAX>>shift && value >= SHRT_MIN>>shift, "Fixed point overflow: %d << %d", value, shift); \ + dst[i] = value << shift; \ + } \ + } \ + for (uint32_t i = count; i < max_size; i++) dst[i] = default[i]; \ } -static void read_fixed_point(gl_cmd_stream_t *s, const int16u_t *src, uint32_t count, int shift) -{ - if (shift > 0) { - for (uint32_t i = 0; i < count; i++) { - int16_t value = src[i]; - assertf(value <= SHRT_MAX>>shift && value >= SHRT_MIN>>shift, "Fixed point overflow: %d << %d", value, shift); - gl_cmd_stream_put_half(s, value << shift); - } - } else { - for (uint32_t i = 0; i < count; i++) { - gl_cmd_stream_put_half(s, src[i] >> -shift); - } +#define GLP_NRM(x, y, z) MGFX_NRM(x, y, z); + +#define DEFINE_NORMAL_FLT_READ_FUNC(name, src_type) \ + static void name(int16_t *dst, const src_type *src, uint32_t count) \ + { \ + int16_t x = CLAMP(roundf(src[0] * 15.5f), -16.0f, 15.0f); \ + int16_t y = CLAMP(roundf(src[1] * 31.5f), -32.0f, 31.0f); \ + int16_t z = CLAMP(roundf(src[2] * 15.5f), -16.0f, 15.0f); \ + *dst = GLP_NRM(x, y, z); \ } -} -#define DEFINE_HALF_FIXED_READ_FUNC(name, precision) \ - static void name(gl_cmd_stream_t *s, const int16u_t *src, uint32_t count) \ +#define DEFINE_NORMAL_INT_READ_FUNC(name, src_type, shift) \ + static void name(int16_t *dst, const src_type *src, uint32_t count) \ { \ - read_fixed_point(s, src, count, precision.shift_amount); \ + int16_t x = src[0] >> shift; \ + int16_t y = src[1] >> (shift-1); \ + int16_t z = src[2] >> shift; \ + *dst = GLP_NRM(x, y, z); \ } -#define VTX_CONVERT_INT(v) ((v) << VTX_SHIFT) -#define VTX_CONVERT_FLT(v) ((v) * (1<vertex_halfx_precision) - -#define COL_CONVERT_U8(v) ((v) << 7) -#define COL_CONVERT_I8(v) ((v) << 8) -#define COL_CONVERT_U16(v) ((v) >> 1) -#define COL_CONVERT_I16(v) ((v)) -#define COL_CONVERT_U32(v) ((v) >> 17) -#define COL_CONVERT_I32(v) ((v) >> 16) -#define COL_CONVERT_F32(v) (FLOAT_TO_I16(v)) -#define COL_CONVERT_F64(v) (FLOAT_TO_I16(v)) - -DEFINE_HALF_READ_FUNC(col_read_u8, uint8_t, COL_CONVERT_U8) -DEFINE_HALF_READ_FUNC(col_read_i8, int8_t, COL_CONVERT_I8) -DEFINE_HALF_READ_FUNC(col_read_u16, uint16u_t, COL_CONVERT_U16) -DEFINE_HALF_READ_FUNC(col_read_i16, int16u_t, COL_CONVERT_I16) -DEFINE_HALF_READ_FUNC(col_read_u32, uint32u_t, COL_CONVERT_U32) -DEFINE_HALF_READ_FUNC(col_read_i32, int32u_t, COL_CONVERT_I32) -DEFINE_HALF_READ_FUNC(col_read_f32, floatu, COL_CONVERT_F32) -DEFINE_HALF_READ_FUNC(col_read_f64, doubleu, COL_CONVERT_F64) - -#define TEX_CONVERT_INT(v) ((v) << TEX_SHIFT) -#define TEX_CONVERT_FLT(v) ((v) * (1<texcoord_halfx_precision) - -#define NRM_CONVERT_U8(v) ((v) >> 1) -#define NRM_CONVERT_I8(v) ((v)) -#define NRM_CONVERT_U16(v) ((v) >> 9) -#define NRM_CONVERT_I16(v) ((v) >> 8) -#define NRM_CONVERT_U32(v) ((v) >> 25) -#define NRM_CONVERT_I32(v) ((v) >> 24) -#define NRM_CONVERT_F32(v) ((v) * 0x7F) -#define NRM_CONVERT_F64(v) ((v) * 0x7F) - -DEFINE_BYTE_READ_FUNC(nrm_read_i8, int8_t, NRM_CONVERT_I8) -DEFINE_BYTE_READ_FUNC(nrm_read_i16, int16u_t, NRM_CONVERT_I16) -DEFINE_BYTE_READ_FUNC(nrm_read_i32, int32u_t, NRM_CONVERT_I32) -DEFINE_BYTE_READ_FUNC(nrm_read_f32, floatu, NRM_CONVERT_F32) -DEFINE_BYTE_READ_FUNC(nrm_read_f64, doubleu, NRM_CONVERT_F64) +static const int16_t vtx_default[3] = {0, 0, 0}; +static const uint8_t col_default[4] = {0, 0, 0, 255}; + +#define POS_CONVERT(v) MGFX_FIXED_POINT(v, GLP_VTX_POS_SHIFT) + +DEFINE_READ_FUNC(vtx_read_i8, int16_t, int8_t, POS_CONVERT, 3, vtx_default) +DEFINE_READ_FUNC(vtx_read_i16, int16_t, int16u_t, POS_CONVERT, 3, vtx_default) +DEFINE_READ_FUNC(vtx_read_i32, int16_t, int32u_t, POS_CONVERT, 3, vtx_default) +DEFINE_READ_FUNC(vtx_read_f32, int16_t, floatu, POS_CONVERT, 3, vtx_default) +DEFINE_READ_FUNC(vtx_read_f64, int16_t, doubleu, POS_CONVERT, 3, vtx_default) +DEFINE_FIXED_READ_FUNC(vtx_read_x16, int16_t, state->vertex_halfx_precision, 3, vtx_default) + +DEFINE_NORMAL_INT_READ_FUNC(nrm_read_i8, int8_t, 3) +DEFINE_NORMAL_INT_READ_FUNC(nrm_read_i16, int16u_t, 11) +DEFINE_NORMAL_INT_READ_FUNC(nrm_read_i32, int32u_t, 27) +DEFINE_NORMAL_FLT_READ_FUNC(nrm_read_f32, floatu) +DEFINE_NORMAL_FLT_READ_FUNC(nrm_read_f64, doubleu) + +static void nrm_read_packed565(int16_t *dst, const int16_t *src, uint32_t count) +{ + *dst = *src; +} + +#define COL_CONVERT_U8(v) ((v)) +#define COL_CONVERT_I8(v) (MAX(v, 0) << 1) +#define COL_CONVERT_U16(v) ((v) >> 8) +#define COL_CONVERT_I16(v) (MAX(v, 0) >> 7) +#define COL_CONVERT_U32(v) ((v) >> 24) +#define COL_CONVERT_I32(v) (MAX(v, 0) >> 23) +#define COL_CONVERT_F32(v) (FLOAT_TO_U8(v)) +#define COL_CONVERT_F64(v) (FLOAT_TO_U8(v)) + +DEFINE_READ_FUNC(col_read_u8, uint8_t, uint8_t, COL_CONVERT_U8, 4, col_default) +DEFINE_READ_FUNC(col_read_i8, uint8_t, int8_t, COL_CONVERT_I8, 4, col_default) +DEFINE_READ_FUNC(col_read_u16, uint8_t, uint16u_t, COL_CONVERT_U16, 4, col_default) +DEFINE_READ_FUNC(col_read_i16, uint8_t, int16u_t, COL_CONVERT_I16, 4, col_default) +DEFINE_READ_FUNC(col_read_u32, uint8_t, uint32u_t, COL_CONVERT_U32, 4, col_default) +DEFINE_READ_FUNC(col_read_i32, uint8_t, int32u_t, COL_CONVERT_I32, 4, col_default) +DEFINE_READ_FUNC(col_read_f32, uint8_t, floatu, COL_CONVERT_F32, 4, col_default) +DEFINE_READ_FUNC(col_read_f64, uint8_t, doubleu, COL_CONVERT_F64, 4, col_default) + +#define TEX_CONVERT(v) MGFX_FIXED_POINT(v, GLP_VTX_TEX_SHIFT) + +DEFINE_READ_FUNC(tex_read_i8, int16_t, int8_t, TEX_CONVERT, 2, vtx_default) +DEFINE_READ_FUNC(tex_read_i16, int16_t, int16u_t, TEX_CONVERT, 2, vtx_default) +DEFINE_READ_FUNC(tex_read_i32, int16_t, int32u_t, TEX_CONVERT, 2, vtx_default) +DEFINE_READ_FUNC(tex_read_f32, int16_t, floatu, TEX_CONVERT, 2, vtx_default) +DEFINE_READ_FUNC(tex_read_f64, int16_t, doubleu, TEX_CONVERT, 2, vtx_default) +DEFINE_FIXED_READ_FUNC(tex_read_x16, int16_t, state->texcoord_halfx_precision, 2, vtx_default) #define MTX_INDEX_CONVERT(v) (v) -DEFINE_BYTE_READ_FUNC(mtx_index_read_u8, uint8_t, MTX_INDEX_CONVERT) -DEFINE_BYTE_READ_FUNC(mtx_index_read_u16, uint16u_t, MTX_INDEX_CONVERT) -DEFINE_BYTE_READ_FUNC(mtx_index_read_u32, uint32u_t, MTX_INDEX_CONVERT) +DEFINE_READ_FUNC(mtx_index_read_u8, uint8_t, uint8_t, MTX_INDEX_CONVERT, 1, vtx_default) +DEFINE_READ_FUNC(mtx_index_read_u16, uint8_t, uint16u_t, MTX_INDEX_CONVERT, 1, vtx_default) +DEFINE_READ_FUNC(mtx_index_read_u32, uint8_t, uint32u_t, MTX_INDEX_CONVERT, 1, vtx_default) -const rsp_read_attrib_func rsp_read_funcs[ATTRIB_COUNT][ATTRIB_TYPE_COUNT] = { +const rsp_read_attrib_func rsp_read_funcs[ARRAY_COUNT][ATTRIB_TYPE_COUNT] = { { (rsp_read_attrib_func)vtx_read_i8, NULL, @@ -113,6 +140,19 @@ const rsp_read_attrib_func rsp_read_funcs[ATTRIB_COUNT][ATTRIB_TYPE_COUNT] = { (rsp_read_attrib_func)vtx_read_f32, (rsp_read_attrib_func)vtx_read_f64, (rsp_read_attrib_func)vtx_read_x16, + NULL, + }, + { + (rsp_read_attrib_func)nrm_read_i8, + NULL, + (rsp_read_attrib_func)nrm_read_i16, + NULL, + (rsp_read_attrib_func)nrm_read_i32, + NULL, + (rsp_read_attrib_func)nrm_read_f32, + (rsp_read_attrib_func)nrm_read_f64, + NULL, + (rsp_read_attrib_func)nrm_read_packed565, }, { (rsp_read_attrib_func)col_read_i8, @@ -124,6 +164,7 @@ const rsp_read_attrib_func rsp_read_funcs[ATTRIB_COUNT][ATTRIB_TYPE_COUNT] = { (rsp_read_attrib_func)col_read_f32, (rsp_read_attrib_func)col_read_f64, NULL, + NULL, }, { (rsp_read_attrib_func)tex_read_i8, @@ -135,16 +176,6 @@ const rsp_read_attrib_func rsp_read_funcs[ATTRIB_COUNT][ATTRIB_TYPE_COUNT] = { (rsp_read_attrib_func)tex_read_f32, (rsp_read_attrib_func)tex_read_f64, (rsp_read_attrib_func)tex_read_x16, - }, - { - (rsp_read_attrib_func)nrm_read_i8, - NULL, - (rsp_read_attrib_func)nrm_read_i16, - NULL, - (rsp_read_attrib_func)nrm_read_i32, - NULL, - (rsp_read_attrib_func)nrm_read_f32, - (rsp_read_attrib_func)nrm_read_f64, NULL, }, { @@ -157,426 +188,506 @@ const rsp_read_attrib_func rsp_read_funcs[ATTRIB_COUNT][ATTRIB_TYPE_COUNT] = { NULL, NULL, NULL, + NULL, }, }; -static const gl_array_t dummy_arrays[ATTRIB_COUNT] = { - { .enabled = true, .size = 4 } -}; - -typedef enum { - BEGIN_END_INDETERMINATE, - BEGIN_END_VERTEX, - BEGIN_END_ARRAY_ELEMENT, -} begin_end_type_t; - -static begin_end_type_t begin_end_type; -static uint32_t vtx_cmd_size; - -static void upload_current_attributes(const gl_array_t *arrays) +static void create_begin_end_layout(vertex_layout_t *layout) { - if (arrays[ATTRIB_COLOR].enabled) { - gl_set_current_color(state->current_attributes.color); - } - - if (arrays[ATTRIB_TEXCOORD].enabled) { - gl_set_current_texcoords(state->current_attributes.texcoord); - } - - if (arrays[ATTRIB_NORMAL].enabled) { - gl_set_current_normal(state->current_attributes.normal); - } - - if (arrays[ATTRIB_MTX_INDEX].enabled) { - gl_set_current_mtx_index(state->current_attributes.mtx_index); - } + vertex_layout_init(layout); + vertex_layout_add(layout, GLP_ATTRIBUTE_POSITION, offsetof(native_vertex_t, position), sizeof(int16_t)*3); + vertex_layout_add(layout, GLP_ATTRIBUTE_NORMAL, offsetof(native_vertex_t, normal), sizeof(int16_t)); + vertex_layout_add(layout, GLP_ATTRIBUTE_COLOR, offsetof(native_vertex_t, color), sizeof(uint32_t)); + vertex_layout_add(layout, GLP_ATTRIBUTE_TEXCOORD, offsetof(native_vertex_t, texcoord), sizeof(int16_t)*2); + vertex_layout_set_stride(layout, sizeof(native_vertex_t)); + vertex_layout_finalize(layout); } -static void load_attribs_at_index(const gl_array_t *arrays, uint32_t index) +void rsp_pipeline_init() { - gl_fill_all_attrib_defaults(arrays); - gl_load_attribs(arrays, index); + magma_rsp_state = PhysicalAddr(mg_get_rsp_state()); + hashtable_init(&state->pipeline_cache, MAX_PIPELINE_COUNT, NULL); + create_begin_end_layout(&state->begin_end_layout); } -static void load_last_attributes(const gl_array_t *arrays, uint32_t last_index) +static void free_pipeline_visitor(uint32_t key, void *value, int refcount) { - load_attribs_at_index(arrays, last_index); - upload_current_attributes(arrays); + mg_pipeline_t **pipelines = value; + for (size_t i = 0; i < PIPELINE_COUNT; i++) + { + mg_pipeline_free(pipelines[i]); + } + free(pipelines); } -static void glp_set_attrib(gl_array_type_t array_type, const void *value, GLenum type, uint32_t size) +void rsp_pipeline_close() { - static const glp_command_t cmd_table[] = { GLP_CMD_SET_LONG, GLP_CMD_SET_LONG, GLP_CMD_SET_WORD, GLP_CMD_SET_BYTE }; - static const uint32_t cmd_size_table[] = { 3, 3, 2, 2 }; - static const uint32_t offset_table[] = { - offsetof(gl_server_state_t, color), - offsetof(gl_server_state_t, tex_coords), - offsetof(gl_server_state_t, normal), - offsetof(gl_server_state_t, mtx_index) - }; - static const int16_t default_value_table[][4] = { - { 0, 0, 0, 0x7FFF }, - { 0, 0, 0, 1 } - }; - - uint32_t table_index = array_type - 1; - - const uint32_t offset = offset_table[table_index]; - - const rsp_read_attrib_func *read_funcs = rsp_read_funcs[array_type]; - const rsp_read_attrib_func read_func = read_funcs[gl_type_to_index(type)]; + if (state->begin_end_buffer.buffer != NULL) { + ringbuffer_free(&state->begin_end_buffer); + } - gl_cmd_stream_t s = gl_cmd_stream_begin(glp_overlay_id, cmd_table[table_index], cmd_size_table[table_index]); - gl_cmd_stream_put_half(&s, offset); + hashtable_visit(&state->pipeline_cache, free_pipeline_visitor); + hashtable_free(&state->pipeline_cache); +} - switch (array_type) { - case ATTRIB_COLOR: - case ATTRIB_TEXCOORD: - read_func(&s, value, size); - read_funcs[gl_type_to_index(GL_SHORT)](&s, default_value_table[table_index] + size, 4 - size); - break; - case ATTRIB_NORMAL: - read_func(&s, value, size); - break; - case ATTRIB_MTX_INDEX: - for (uint32_t i = 0; i < 3; i++) gl_cmd_stream_put_byte(&s, 0); - read_func(&s, value, size); - break; - default: - assert(!"Unexpected array type"); - break; +static void begin_end_next_buffer() +{ + if (rspq_block_is_recording()) { + state->begin_end_current_buffer = malloc_uncached(sizeof(native_vertex_t) * BEGIN_END_BUFFER_SIZE); + rspq_block_atexit(free_uncached, state->begin_end_current_buffer); + } else { + state->begin_end_current_buffer = ringbuffer_alloc_next(&state->begin_end_buffer); } - - gl_cmd_stream_end(&s); + state->begin_end_index = 0; + state->begin_end_load_index = 0; + mg_bind_vertex_buffer(state->begin_end_current_buffer); } -static void set_attrib(gl_array_type_t array_type, const void *value, GLenum type, uint32_t size) +static native_vertex_t *begin_end_get_current_vertex() { - glp_set_attrib(array_type, value, type, size); - gl_read_attrib(array_type, value, type, size); + return state->begin_end_current_buffer + state->begin_end_index; } -static bool check_last_array_element(int32_t *index) +static uint32_t get_begin_end_multiple(GLenum mode) { - if (state->last_array_element >= 0) { - *index = state->last_array_element; - state->last_array_element = -1; - return true; + switch (mode) + { + case GL_POINTS: + case GL_LINE_LOOP: + case GL_LINE_STRIP: + case GL_TRIANGLE_STRIP: + case GL_TRIANGLE_FAN: + case GL_POLYGON: + return 1; + case GL_LINES: + case GL_QUAD_STRIP: + return 2; + case GL_TRIANGLES: + return 3; + case GL_QUADS: + return 4; + default: + return 0; } - - return false; } -static void require_array_element(const gl_array_t *arrays) +static bool get_begin_end_need_save(GLenum mode) { - int32_t index; - if (check_last_array_element(&index)) { - for (uint32_t i = 0; i < ATTRIB_COUNT; i++) - { - const gl_array_t *array = &arrays[i]; - const void *value = gl_get_attrib_element(array, index); - set_attrib(i, value, array->type, array->size); - } + switch (mode) + { + case GL_LINE_LOOP: + case GL_TRIANGLE_FAN: + case GL_POLYGON: + return true; + case GL_POINTS: + case GL_LINES: + case GL_LINE_STRIP: + case GL_TRIANGLES: + case GL_TRIANGLE_STRIP: + case GL_QUADS: + case GL_QUAD_STRIP: + default: + return false; } } -static inline gl_cmd_stream_t write_vertex_begin(uint32_t cache_index) +static uint32_t get_client_flags() { - gl_cmd_stream_t s = gl_cmd_stream_begin(glp_overlay_id, GLP_CMD_SET_PRIM_VTX, vtx_cmd_size>>2); - gl_cmd_stream_put_half(&s, cache_index * PRIM_VTX_SIZE); - return s; + uint32_t client_flags = 0; + if (state->begin_end_active) client_flags |= CLIENT_FLAG_BEGIN_END; + if (state->array_object->arrays[ARRAY_COLOR].enabled) client_flags |= CLIENT_FLAG_COLOR_ARRAY; + return client_flags; } -static inline void write_vertex_end(gl_cmd_stream_t *s) +static void magma_init() { - gl_cmd_stream_end(s); + uint32_t client_flags = get_client_flags(); + gl2_write(GL_CMD_PRE_INIT_MAGMA, magma_rsp_state, client_flags); } -static void write_vertex_from_arrays(const gl_array_t *arrays, uint32_t index, uint8_t cache_index) +static void gl_rsp_begin(GLenum mode) { - gl_cmd_stream_t s = write_vertex_begin(cache_index); + state->primitive_mode = mode; + state->begin_end_multiple = get_begin_end_multiple(mode); + state->begin_end_need_save = get_begin_end_need_save(mode); - for (uint32_t i = 0; i < ATTRIB_COUNT; i++) - { - const gl_array_t *array = &arrays[i]; - if (!array->enabled) { - continue; - } + update_pipelines_from_layout(&state->begin_end_layout); + magma_init(); + mg_set_vertex_stride(sizeof(native_vertex_t)); + + mg_draw_begin(); - const void *src = gl_get_attrib_element(array, index); - array->rsp_read_func(&s, src, array->size); + if (!rspq_block_is_recording() && state->begin_end_buffer.buffer == NULL) { + ringbuffer_init(&state->begin_end_buffer, sizeof(native_vertex_t) * BEGIN_END_BUFFER_SIZE, BEGIN_END_BUFFER_COUNT); } - write_vertex_end(&s); + begin_end_next_buffer(); } -static void submit_vertex(uint32_t cache_index) +__attribute__((noinline)) +static void begin_end_load() { - uint8_t indices[3]; - if (gl_prim_assembly(cache_index, indices)) - { - glpipe_draw_triangle(indices[0], indices[1], indices[2]); + if (state->begin_end_index > state->begin_end_load_index) { + mg_load_vertices(state->begin_end_load_index, state->begin_end_load_index, state->begin_end_index - state->begin_end_load_index); + state->begin_end_load_index = state->begin_end_index; } } -static void draw_vertex_from_arrays(const gl_array_t *arrays, uint32_t id, uint32_t index) +static uint32_t draw_batch(GLenum mode, uint32_t count, uint32_t cache_offset) { - uint8_t cache_index; - if (gl_get_cache_index(id, &cache_index)) - { - write_vertex_from_arrays(arrays, index, cache_index); + switch (mode) { + case GL_TRIANGLES: + { + size_t prim_count = count / 3; + for (size_t i = 0; i < prim_count; i++) mg_draw_triangle(3*i, 3*i+1, 3*i+2); + return cache_offset; + } + case GL_TRIANGLE_STRIP: + { + size_t prim_count = MAX(0, count - 2); + for (size_t i = 0; i < prim_count; i++) mg_draw_triangle(i, i + 1 + i%2, i + 2 - i%2); + return cache_offset; + } + case GL_TRIANGLE_FAN: + case GL_POLYGON: + { + size_t prim_count = MAX(0, count - 2 + cache_offset); + for (size_t i = 0; i < prim_count; i++) mg_draw_triangle(i+1, i+2, 0); + return 1; + } + case GL_QUADS: + { + size_t prim_count = count / 4; + for (size_t i = 0; i < prim_count; i++) { + size_t o = 4*i; + mg_draw_triangle(o, o+1, o+2); + mg_draw_triangle(o, o+2, o+3); + } + return cache_offset; + + } + case GL_QUAD_STRIP: + { + size_t prim_count = MAX(0, count - 2) / 2; + for (size_t i = 0; i < prim_count; i++) + { + size_t o = 2*i; + mg_draw_triangle(o, o+2, o+1); + mg_draw_triangle(o+1, o+2, o+3); + } + return cache_offset; + } + default: + { + return cache_offset; + } } - - submit_vertex(cache_index); } -static void gl_asm_vtx_loader(const gl_array_t *arrays) +static void begin_end_draw_current_buffer() { - extern uint8_t rsp_gl_pipeline_text_start[]; - - rspq_write_t w = rspq_write_begin(glp_overlay_id, GLP_CMD_SET_VTX_LOADER, 3 + VTX_LOADER_MAX_COMMANDS); - rspq_write_arg(&w, PhysicalAddr(rsp_gl_pipeline_text_start) - 0x1000); + begin_end_load(); + draw_batch(state->primitive_mode, state->begin_end_index, 0); - uint32_t pointer = PhysicalAddr(w.pointer); - bool aligned = (pointer & 0x7) == 0; + if (!rspq_block_is_recording()) ringbuffer_release_current(&state->begin_end_buffer); +} - rspq_write_arg(&w, aligned ? pointer + 8 : pointer + 4); +static void gl_rsp_end() +{ + // TODO: line loops will need special handling (insert saved vtx at the end) - if (aligned) { - rspq_write_arg(&w, 0); + if (state->begin_end_index > 0) { + begin_end_draw_current_buffer(); } - const uint8_t default_reg = 16; - const uint8_t current_reg = 17; - const uint8_t cmd_ptr_reg = 20; - const uint8_t norm_reg = 2; - const uint8_t mtx_index_reg = 3; - const uint8_t dst_vreg_base = 24; - const uint32_t current_normal_offset = offsetof(gl_server_state_t, normal) - offsetof(gl_server_state_t, color); - const uint32_t current_mtx_index_offset = offsetof(gl_server_state_t, mtx_index) - offsetof(gl_server_state_t, color); + mg_draw_end(); +} - uint32_t cmd_offset = 0; +static void begin_end_append_vtx(const native_vertex_t *vtx) +{ + memcpy(begin_end_get_current_vertex(), vtx, sizeof(native_vertex_t)); + state->begin_end_index++; +} - for (uint32_t i = 0; i < ATTRIB_NORMAL; i++) +static void begin_end_prep_next_buffer(const native_vertex_t *prev_end) +{ + // Appending these vertices is guaranteed to not overflow the buffer since we just started a fresh one + switch (state->primitive_mode) { + case GL_TRIANGLE_STRIP: + case GL_QUAD_STRIP: { - const uint32_t dst_vreg = dst_vreg_base + i; - const gl_array_t *array = &arrays[i]; - - if (!array->enabled) { - rspq_write_arg(&w, rsp_asm_lwc2(VLOAD_DOUBLE, dst_vreg, 0, i-1, current_reg)); - } else { - uint32_t cmd_size = array->size * 2; - uint32_t alignment = next_pow2(cmd_size); - if (cmd_offset & (alignment-1)) { - rspq_write_arg(&w, rsp_asm_addi(cmd_ptr_reg, cmd_ptr_reg, cmd_offset)); - cmd_offset = 0; - } - - switch (array->size) - { - case 1: - rspq_write_arg(&w, rsp_asm_lwc2(VLOAD_DOUBLE, dst_vreg, 0, (i*8)>>3, default_reg)); - rspq_write_arg(&w, rsp_asm_lwc2(VLOAD_HALF, dst_vreg, 0, cmd_offset>>1, cmd_ptr_reg)); - break; - case 2: - rspq_write_arg(&w, rsp_asm_lwc2(VLOAD_LONG, dst_vreg, 0, cmd_offset>>2, cmd_ptr_reg)); - rspq_write_arg(&w, rsp_asm_lwc2(VLOAD_LONG, dst_vreg, 4, ((i*8)>>2) + 1, default_reg)); - break; - case 3: - rspq_write_arg(&w, rsp_asm_lwc2(VLOAD_DOUBLE, dst_vreg, 0, cmd_offset>>3, cmd_ptr_reg)); - rspq_write_arg(&w, rsp_asm_lwc2(VLOAD_HALF, dst_vreg, 6, ((i*8)>>1) + 3, default_reg)); - break; - case 4: - rspq_write_arg(&w, rsp_asm_lwc2(VLOAD_DOUBLE, dst_vreg, 0, cmd_offset>>3, cmd_ptr_reg)); - break; - } - - cmd_offset += cmd_size; - } + // The two previous vertices + begin_end_append_vtx(prev_end - 2); + begin_end_append_vtx(prev_end - 1); + break; + } + case GL_TRIANGLE_FAN: + case GL_POLYGON: + { + // The "hub" of the fan + begin_end_append_vtx(&state->begin_end_saved_vtx); + // The previous vertex + begin_end_append_vtx(prev_end - 1); + break; } + } +} - // TODO: optimize for when both normal and matrix index com from the same source (They fit into a single word) +static void begin_end_advance() +{ + begin_end_append_vtx(&state->current_attribs); - if (!arrays[ATTRIB_NORMAL].enabled) { - rspq_write_arg(&w, rsp_asm_lw(norm_reg, current_normal_offset, current_reg)); - } else { - rspq_write_arg(&w, rsp_asm_lw(norm_reg, cmd_offset, cmd_ptr_reg)); - cmd_offset += 3; + // In some cases, we need to save the very first vertex for later (for example triangle fan, line loop) + if (state->begin_end_need_save) { + memcpy(&state->begin_end_saved_vtx, &state->current_attribs, sizeof(native_vertex_t)); + state->begin_end_need_save = false; } - if (!arrays[ATTRIB_MTX_INDEX].enabled) { - rspq_write_arg(&w, rsp_asm_lbu(mtx_index_reg, current_mtx_index_offset, current_reg)); - } else { - rspq_write_arg(&w, rsp_asm_lbu(mtx_index_reg, cmd_offset, cmd_ptr_reg)); + // Check if we have reached the required multiple of vertices and the next multiple would overflow the current buffer + if (state->begin_end_index % state->begin_end_multiple == 0 && + state->begin_end_index + state->begin_end_multiple > BEGIN_END_BUFFER_SIZE) { + begin_end_draw_current_buffer(); + native_vertex_t *prev_end = begin_end_get_current_vertex(); + begin_end_next_buffer(); + begin_end_prep_next_buffer(prev_end); } - - rspq_write_end(&w); } -static uint32_t get_vertex_cmd_size(const gl_array_t *arrays) +static void *get_attrib_dst(array_type_t array_type) { - uint32_t cmd_size = 4; - - for (uint32_t i = 0; i < ATTRIB_NORMAL; i++) + switch (array_type) { - if (arrays[i].enabled) { - cmd_size += arrays[i].size * 2; - } - } - if (arrays[ATTRIB_NORMAL].enabled) { - cmd_size += 3; - } - if (arrays[ATTRIB_MTX_INDEX].enabled) { - cmd_size += 1; + case ARRAY_VERTEX: + return state->current_attribs.position; + case ARRAY_NORMAL: + return &state->current_attribs.normal; + case ARRAY_COLOR: + return &state->current_attribs.color; + case ARRAY_TEXCOORD: + return state->current_attribs.texcoord; + case ARRAY_MTX_INDEX: + return state->current_attribs.mtx_index; + default: + return NULL; } - - return ROUND_UP(cmd_size, 4); } -static void gl_update_vertex_cmd_size(const gl_array_t *arrays) +void rsp_read_attrib(array_type_t array_type, GLenum type, const void *value, uint32_t size) { - vtx_cmd_size = get_vertex_cmd_size(arrays); + rsp_read_attrib_func read_func = rsp_read_funcs[array_type][gl_type_to_index(type)]; + assertf(read_func != NULL, "Could not find read func"); + void *dst = get_attrib_dst(array_type); + assertf(dst != NULL, "Array type not supported"); - // TODO: This is dependent on the layout of data structures internal to rspq. - // How can we make it more robust? + read_func(dst, value, size); +} - extern uint8_t rsp_queue_data_start[]; - extern uint8_t rsp_queue_data_end[0]; - extern uint8_t rsp_gl_pipeline_data_start[]; +static void gl_rsp_vertex(const void *value, GLenum type, uint32_t size) +{ + rsp_read_attrib(ARRAY_VERTEX, type, value, size); + begin_end_advance(); +} - uint32_t ovl_data_offset = rsp_queue_data_end - rsp_queue_data_start; - uint8_t *rsp_gl_pipeline_ovl_header = rsp_gl_pipeline_data_start + ovl_data_offset; +static void load_matrix(uint8_t mtx_index) +{ + const mg_uniform_t *uniform = get_matrices_uniform(); + mg_uniform_load(uniform, state->matrix_palette + mtx_index); +} - #define CMD_DESC_SIZE 2 +static void gl_rsp_mtx_index(const uint8_t *mtx_index) +{ + if (state->begin_end_active) { + begin_end_load(); + load_matrix(*mtx_index); + } +} - uint16_t *cmd_descriptor = (uint16_t*)(rsp_gl_pipeline_ovl_header + RSPQ_OVERLAY_HEADER_SIZE + GLP_CMD_SET_PRIM_VTX*CMD_DESC_SIZE); - uint16_t patched_cmd_descriptor = (*cmd_descriptor & 0x3FF) | ((vtx_cmd_size & 0xFC) << 8); +static void get_array_element_convert_parms(array_convert_parms_t *parms, uint32_t index) +{ + static const data_layout_t layout = { + .offsets = { + offsetof(native_vertex_t, position), + offsetof(native_vertex_t, normal), + offsetof(native_vertex_t, color), + offsetof(native_vertex_t, texcoord), + offsetof(native_vertex_t, mtx_index), + }, + .stride = sizeof(native_vertex_t) + }; + + for (array_type_t i = 0; i < ARRAY_COUNT; i++) + { + parms->arrays[i] = &state->array_object->arrays[i]; + } - data_cache_hit_writeback_invalidate(cmd_descriptor, CMD_DESC_SIZE); - glpipe_set_vtx_cmd_size(patched_cmd_descriptor, cmd_descriptor); + parms->array_count = ARRAY_COUNT; + parms->out_layout = &layout; + parms->out_buffer = &state->current_attribs; + parms->range.first = index; + parms->range.count = 1; } -static void gl_prepare_vtx_cmd(const gl_array_t *arrays) +static bool is_array_enabled(array_type_t type) { - gl_asm_vtx_loader(arrays); - gl_update_vertex_cmd_size(arrays); + return state->array_object->arrays[type].enabled; } -static void gl_rsp_begin() +static bool is_vertex_array_enabled() { - glpipe_init(); - state->last_array_element = -1; - begin_end_type = BEGIN_END_INDETERMINATE; + return is_array_enabled(ARRAY_VERTEX); } -static void gl_rsp_end() +static void gl_rsp_array_element(uint32_t index) { - int32_t index; - if (check_last_array_element(&index)) { - load_last_attributes(state->array_object->arrays, index); + array_convert_parms_t convert_parms; + get_array_element_convert_parms(&convert_parms, index); + array_convert(&convert_parms); + + if (is_array_enabled(ARRAY_MTX_INDEX)) { + gl_rsp_mtx_index(state->current_attribs.mtx_index); } - if (state->begin_end_active) { - // TODO: Load from arrays - gl_set_current_color(state->current_attributes.color); - gl_set_current_texcoords(state->current_attributes.texcoord); - gl_set_current_normal(state->current_attributes.normal); - gl_set_current_mtx_index(state->current_attributes.mtx_index); + if (is_vertex_array_enabled()) { + begin_end_advance(); } + // TODO: if vertex array is not enabled, send attributes to RSP? } -static void gl_rsp_vertex(const void *value, GLenum type, uint32_t size) +static data_view_t get_vertex_data_for_block(gl_array_object_t *array_object, index_bounds_t bounds) { - if (begin_end_type != BEGIN_END_VERTEX) { - gl_prepare_vtx_cmd(dummy_arrays); - begin_end_type = BEGIN_END_VERTEX; - } + uint32_t stride = data_source_get_stride(&array_object->vertex_data_source); - static const int16_t default_values[] = { 0, 0, 0, 1 }; + void *buffer = malloc_uncached(stride * bounds.count); + rspq_block_atexit(free_uncached, buffer); + data_source_pull(&array_object->vertex_data_source, buffer, bounds); - uint8_t cache_index; - if (gl_get_cache_index(next_prim_id(), &cache_index)) - { - require_array_element(state->array_object->arrays); + return (data_view_t) { + .pointer = buffer, + .stride = data_source_get_stride(&array_object->vertex_data_source) + }; +} - rsp_read_attrib_func read_func = rsp_read_funcs[ATTRIB_VERTEX][gl_type_to_index(type)]; +static void update_pipelines(gl_array_object_t *array_object) +{ + vertex_layout_cache_update(&array_object->layout_cache, array_object->arrays); + const vertex_layout_t *vertex_layout = vertex_layout_cache_get_layout(&array_object->layout_cache); + update_pipelines_from_layout(vertex_layout); +} - gl_cmd_stream_t s = write_vertex_begin(cache_index); - read_func(&s, value, size); - vtx_read_i16(&s, default_values + size, 4 - size); - write_vertex_end(&s); +static data_view_t get_vertex_data_view(gl_array_object_t *array_object, index_bounds_t bounds) +{ + if (rspq_block_is_recording()) { + return get_vertex_data_for_block(array_object, bounds); } - submit_vertex(cache_index); + return data_cache_prepare_at_bounds(&array_object->vertex_data_cache, bounds); } -static void gl_rsp_color(const void *value, GLenum type, uint32_t size) +static void prepare_vertex_data(gl_array_object_t *array_object, index_bounds_t bounds) { - set_attrib(ATTRIB_COLOR, value, type, size); + data_view_t vertex_data_view = get_vertex_data_view(state->array_object, bounds); + mg_set_vertex_stride(vertex_data_view.stride); + mg_bind_vertex_buffer(vertex_data_view.pointer); } -static void gl_rsp_tex_coord(const void *value, GLenum type, uint32_t size) +static void prepare_drawing(gl_array_object_t *array_object, index_bounds_t bounds) { - set_attrib(ATTRIB_TEXCOORD, value, type, size); + update_pipelines(array_object); + magma_init(); + prepare_vertex_data(array_object, bounds); } -static void gl_rsp_normal(const void *value, GLenum type, uint32_t size) +static void gl_rsp_draw_arrays(GLenum mode, uint32_t first, uint32_t count) { - set_attrib(ATTRIB_NORMAL, value, type, size); + if (!is_vertex_array_enabled()) { + return; + } + + index_bounds_t range = { + .first = first, + .count = count + }; + + prepare_drawing(state->array_object, range); + + mg_draw_begin(); + mg_input_assembly_parms_t input_assembly_parms = array_object_get_input_assembly_parms(state->array_object, mode, range); + mg_ex_draw(&input_assembly_parms, count, first, mode); + mg_draw_end(); } -static void gl_rsp_mtx_index(const void *value, GLenum type, uint32_t size) +static const uint16_t *get_indices_from_buffer(gl_buffer_object_t *buffer_object, uint32_t offset) { - set_attrib(ATTRIB_MTX_INDEX, value, type, size); + return (const uint16_t*)((const uint8_t*)buffer_object->storage.data + offset); } -static void gl_rsp_array_element(uint32_t index) +static const uint16_t *get_indices(gl_buffer_object_t *element_buffer, const void* indices) { - if (begin_end_type != BEGIN_END_ARRAY_ELEMENT) { - gl_prepare_vtx_cmd(state->array_object->arrays); - begin_end_type = BEGIN_END_ARRAY_ELEMENT; + if (element_buffer == NULL) { + return (const uint16_t*)indices; + } else { + return get_indices_from_buffer(element_buffer, (uint32_t)indices); } +} - draw_vertex_from_arrays(state->array_object->arrays, index, index); - state->last_array_element = index; +static cached_draw_call_t *prepare_draw_call(gl_array_object_t *array_object, const draw_call_parms_t *parms, const void *index_data) +{ + draw_call_cache_t *draw_call_cache = array_object_get_draw_call_cache(array_object); + return draw_call_cache_get_or_create(draw_call_cache, parms, index_data, array_object); } -static void gl_rsp_draw_arrays(uint32_t first, uint32_t count) +static void draw_elements_from_buffer(GLenum mode, uint32_t count, const void* indices, gl_buffer_object_t *element_buffer) { - if (state->array_object->arrays[ATTRIB_VERTEX].enabled) { - gl_prepare_vtx_cmd(state->array_object->arrays); - for (uint32_t i = 0; i < count; i++) - { - draw_vertex_from_arrays(state->array_object->arrays, next_prim_id(), first + i); - } - } + draw_call_parms_t parms = { + .mode = mode, + .offset = (uint32_t)indices, + .count = count + }; + + const void *index_data = get_indices(element_buffer, indices); + cached_draw_call_t *draw_call = prepare_draw_call(state->array_object, &parms, index_data); + + prepare_drawing(state->array_object, draw_call->index_range); - load_last_attributes(state->array_object->arrays, first + count - 1); + mg_draw_begin(); + draw_call_run(draw_call); + mg_draw_end(); } -static void gl_rsp_draw_elements(uint32_t count, const void* indices, read_index_func read_index) +static void draw_elements_from_pointer(GLenum mode, uint32_t count, const void* indices) { - gl_fill_all_attrib_defaults(state->array_object->arrays); + index_bounds_t range = find_index_bounds(indices, count); - if (state->array_object->arrays[ATTRIB_VERTEX].enabled) { - gl_prepare_vtx_cmd(state->array_object->arrays); - for (uint32_t i = 0; i < count; i++) - { - uint32_t index = read_index(indices, i); - draw_vertex_from_arrays(state->array_object->arrays, index, index); - } + prepare_drawing(state->array_object, range); + + mg_draw_begin(); + mg_input_assembly_parms_t input_assembly_parms = array_object_get_input_assembly_parms(state->array_object, mode, range); + mg_ex_draw_indexed(&input_assembly_parms, indices, count, -range.first, mode); + mg_draw_end(); +} + +static void gl_rsp_draw_elements(GLenum mode, uint32_t count, const void* indices, GLenum type) +{ + assertf(type == GL_UNSIGNED_SHORT, "Index type must be GL_UNSIGNED_SHORT"); + + if (!is_vertex_array_enabled()) { + return; } - load_last_attributes(state->array_object->arrays, read_index(indices, count - 1)); + gl_buffer_object_t *element_buffer = state->array_object->element_array_buffer; + + if (element_buffer != NULL && !rspq_block_is_recording()) { + draw_elements_from_buffer(mode, count, indices, element_buffer); + } else { + const void *index_data = get_indices(element_buffer, indices); + draw_elements_from_pointer(mode, count, index_data); + } } const gl_pipeline_t gl_rsp_pipeline = (gl_pipeline_t) { .begin = gl_rsp_begin, .end = gl_rsp_end, .vertex = gl_rsp_vertex, - .color = gl_rsp_color, - .tex_coord = gl_rsp_tex_coord, - .normal = gl_rsp_normal, .mtx_index = gl_rsp_mtx_index, .array_element = gl_rsp_array_element, .draw_arrays = gl_rsp_draw_arrays, diff --git a/src/GL/rsp_pipeline.h b/src/GL/rsp_pipeline.h new file mode 100644 index 0000000000..e0d8fa309c --- /dev/null +++ b/src/GL/rsp_pipeline.h @@ -0,0 +1,15 @@ +#ifndef __RSP_PIPELINE_H +#define __RSP_PIPELINE_H + +#ifdef __cplusplus +extern "C" { +#endif + +void rsp_pipeline_init(); +void rsp_pipeline_close(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/GL/texture.c b/src/GL/texture.c index 8b7d9f4a86..1dc4821734 100644 --- a/src/GL/texture.c +++ b/src/GL/texture.c @@ -20,9 +20,6 @@ _Static_assert(TEXTURE_BILINEAR_MASK << TEX_BILINEAR_SHIFT == SOM_SAMPLE_BILINEAR >> 32); _Static_assert(TEXTURE_BILINEAR_MASK << TEX_BILINEAR_OFFSET_SHIFT == HALF_TEXEL); _Static_assert((1<> 32) >> BILINEAR_TEX_OFFSET_SHIFT == HALF_TEXEL); _Static_assert(TEX_FLAG_DETAIL << TEX_DETAIL_SHIFT == SOM_TEXTURE_DETAIL >> 32); diff --git a/src/GL/vertex_layout.c b/src/GL/vertex_layout.c new file mode 100644 index 0000000000..9ad0a51b0a --- /dev/null +++ b/src/GL/vertex_layout.c @@ -0,0 +1,34 @@ +#include "vertex_layout.h" +#include "fnv1a.h" + +void vertex_layout_init(vertex_layout_t *vl) +{ + vl->vertex_layout.attributes = vl->attributes; + vl->vertex_layout.attribute_count = 0; + vl->vertex_layout.stride = 0; +} + +void vertex_layout_add(vertex_layout_t *vl, uint32_t input, uint32_t offset, uint32_t size) +{ + mg_vertex_attribute_t *attr = &vl->attributes[vl->vertex_layout.attribute_count++]; + attr->input = input; + attr->offset = offset; + vl->vertex_layout.stride = offset + size; +} + +static uint32_t get_hash(const mg_vertex_layout_t *layout) +{ + uint32_t key = fnv1a_init(); + for (size_t i = 0; i < layout->attribute_count; i++) + { + fnv1a_step(&key, layout->attributes[i].input); + fnv1a_step(&key, layout->attributes[i].offset); + } + fnv1a_step(&key, layout->stride); + return key; +} + +void vertex_layout_finalize(vertex_layout_t *vl) +{ + vl->hash = get_hash(&vl->vertex_layout); +} diff --git a/src/GL/vertex_layout.h b/src/GL/vertex_layout.h new file mode 100644 index 0000000000..2fd6b76c6e --- /dev/null +++ b/src/GL/vertex_layout.h @@ -0,0 +1,48 @@ +/** + * @file vertex_layout.h + * @author Dennis Heinze + */ +#ifndef __GL_VERTEX_LAYOUT +#define __GL_VERTEX_LAYOUT + +#include "magma.h" +#include "../utils.h" + +#define MAX_VERTEX_ATTRIBUTE_COUNT 4 + +typedef struct +{ + mg_vertex_attribute_t attributes[MAX_VERTEX_ATTRIBUTE_COUNT]; + mg_vertex_layout_t vertex_layout; + uint32_t hash; +} vertex_layout_t; + +#ifdef __cplusplus +extern "C" { +#endif + +void vertex_layout_init(vertex_layout_t *vl); +void vertex_layout_add(vertex_layout_t *vl, uint32_t input, uint32_t offset, uint32_t size); + +inline void vertex_layout_append(vertex_layout_t *vl, uint32_t input, uint32_t size) +{ + vertex_layout_add(vl, input, vl->vertex_layout.stride, size); +} + +inline void vertex_layout_set_stride(vertex_layout_t *vl, uint32_t stride) +{ + vl->vertex_layout.stride = stride; +} + +void vertex_layout_finalize(vertex_layout_t *vl); + +inline uint32_t vertex_layout_get_hash(const vertex_layout_t *vl) +{ + return vl->hash; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/GL/vertex_layout_cache.c b/src/GL/vertex_layout_cache.c new file mode 100644 index 0000000000..18ae8cf737 --- /dev/null +++ b/src/GL/vertex_layout_cache.c @@ -0,0 +1,49 @@ +#include "vertex_layout_cache.h" +#include "gl_constants.h" + +void vertex_layout_cache_init(vertex_layout_cache_t *cache) +{ + vertex_layout_cache_invalidate(cache); +} + +void vertex_layout_cache_invalidate(vertex_layout_cache_t *cache) +{ + cache->dirty = true; +} + +static void layout_append_aligned(vertex_layout_t *layout, uint32_t input, array_type_t type) +{ + uint32_t aligned_stride = ROUND_UP(layout->vertex_layout.stride, array_type_get_alignment(type)); + vertex_layout_set_stride(layout, aligned_stride); + vertex_layout_append(layout, input, array_type_get_stride(type)); +} + +void vertex_layout_cache_update(vertex_layout_cache_t *cache, const array_t *arrays) +{ + if (!cache->dirty) { + return; + } + + assertf(arrays[ARRAY_VERTEX].enabled, "The vertex array must be enabled!"); + + vertex_layout_t *layout = &cache->layout; + + vertex_layout_init(layout); + layout_append_aligned(layout, GLP_ATTRIBUTE_POSITION, ARRAY_VERTEX); + + if (arrays[ARRAY_NORMAL].enabled) { + layout_append_aligned(layout, GLP_ATTRIBUTE_NORMAL, ARRAY_NORMAL); + } + + if (arrays[ARRAY_COLOR].enabled) { + layout_append_aligned(layout, GLP_ATTRIBUTE_COLOR, ARRAY_COLOR); + } + + if (arrays[ARRAY_TEXCOORD].enabled) { + layout_append_aligned(layout, GLP_ATTRIBUTE_TEXCOORD, ARRAY_TEXCOORD); + } + + vertex_layout_finalize(layout); + + cache->dirty = false; +} \ No newline at end of file diff --git a/src/GL/vertex_layout_cache.h b/src/GL/vertex_layout_cache.h new file mode 100644 index 0000000000..59845c765f --- /dev/null +++ b/src/GL/vertex_layout_cache.h @@ -0,0 +1,30 @@ +#ifndef __VERTEX_LAYOUT_CACHE_H +#define __VERTEX_LAYOUT_CACHE_H + +#include "vertex_layout.h" +#include "array.h" + +typedef struct vertex_layout_cache_s { + vertex_layout_t layout; + bool dirty; +} vertex_layout_cache_t; + +#ifdef __cplusplus +extern "C" { +#endif + +void vertex_layout_cache_init(vertex_layout_cache_t *cache); +void vertex_layout_cache_invalidate(vertex_layout_cache_t *cache); +void vertex_layout_cache_update(vertex_layout_cache_t *cache, const array_t *arrays); + +inline const vertex_layout_t *vertex_layout_cache_get_layout(const vertex_layout_cache_t *cache) +{ + assertf(!cache->dirty, "Vertex layout cache is dirty!"); + return &cache->layout; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/tests/test_gl.c b/tests/test_gl.c index 05e6734ee9..838f029cec 100644 --- a/tests/test_gl.c +++ b/tests/test_gl.c @@ -2,6 +2,7 @@ #include #include #include +#include #undef ABS #include "../src/GL/gl_internal.h" @@ -12,6 +13,8 @@ DEFER(surface_free(&test_surf)); \ surface_t test_z = surface_alloc(FMT_RGBA16, w, h); \ DEFER(surface_free(&test_z)); \ + mg_init(); \ + DEFER(mg_close()); \ gl_init(); \ DEFER(gl_close()); \ rdpq_attach(&test_surf, &test_z); \