diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f7f87a..e416cdd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,7 @@ string(TOUPPER ${BACKEND} BACKEND_UPPER) add_definitions(-DBACKEND_${BACKEND_UPPER}) set(CMAKE_C_STANDARD 99) -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 14) include_directories(include) @@ -68,6 +68,7 @@ set( containers/aligned_vector.c containers/named_array.c containers/stack.c + GL/attributes.c GL/draw.c GL/error.c GL/flush.c @@ -209,6 +210,7 @@ gen_sample(scissor samples/scissor/main.c) gen_sample(polymark samples/polymark/main.c) gen_sample(cubes samples/cubes/main.cpp) gen_sample(zclip_test tests/zclip/main.cpp) +gen_sample(primitive_modes samples/primitive_modes/main.c) if(PLATFORM_DREAMCAST) gen_sample(trimark samples/trimark/main.c) diff --git a/GL/alloc/alloc.c b/GL/alloc/alloc.c index 6760ff4..defc220 100644 --- a/GL/alloc/alloc.c +++ b/GL/alloc/alloc.c @@ -244,13 +244,17 @@ int alloc_init(void* pool, size_t size) { memset(pool_header.block_usage, 0, BLOCK_COUNT); pool_header.pool = pool; - pool_header.pool_size = size; intptr_t base_address = (intptr_t) pool_header.pool; base_address = round_up(base_address, 2048); pool_header.base_address = (uint8_t*) base_address; pool_header.block_count = ((p + size) - pool_header.base_address) / 2048; + + /* The pool size might be less than the passed size if the memory + * wasn't aligned to 2048 */ + pool_header.pool_size = pool_header.block_count * 2048; + pool_header.allocations = NULL; assert(((uintptr_t) pool_header.base_address) % 2048 == 0); @@ -292,7 +296,7 @@ static inline void block_and_offset_from_subblock(size_t sb, size_t* b, uint8_t* *off = (sb % 8); } -void* alloc_malloc(void* pool, size_t size) { +static void* alloc_malloc_internal(void* pool, size_t size, bool for_defrag) { DBG_MSG("Allocating: %d\n", size); size_t start_subblock, required_subblocks; @@ -335,6 +339,11 @@ void* alloc_malloc(void* pool, size_t size) { pool_header.block_usage[block++] |= mask; } + // defrag allocations don't create new entries, they reuse old ones + if(for_defrag) { + return ret; + } + /* Insert allocations in the list by size descending so that when we * defrag we can move the larger blocks before the smaller ones without * much effort */ @@ -376,6 +385,10 @@ void* alloc_malloc(void* pool, size_t size) { return ret; } +void* alloc_malloc(void* pool, size_t size) { + return alloc_malloc_internal(pool, size, false); +} + static void alloc_release_blocks(struct AllocEntry* it) { size_t used_subblocks = size_to_subblock_count(it->size); size_t subblock = subblock_from_pointer(it->pointer); @@ -433,14 +446,14 @@ void alloc_free(void* pool, void* p) { DBG_MSG("Freed: size: %d, us: %d, sb: %d, off: %d\n", it->size, used_subblocks, block, offset); free(it); - break; + return; } last = it; it = it->next; } - DBG_MSG("Free done\n"); + assert("Freed pointer not found, heap corruption?" && 0); } void alloc_run_defrag(void* pool, defrag_address_move callback, int max_iterations, void* user_data) { @@ -456,8 +469,8 @@ void alloc_run_defrag(void* pool, defrag_address_move callback, int max_iteratio while(it) { void* potential_dest = alloc_next_available(pool, it->size); - if(potential_dest < it->pointer) { - potential_dest = alloc_malloc(pool, it->size); + if(potential_dest && potential_dest < it->pointer) { + potential_dest = alloc_malloc_internal(pool, it->size, true); memcpy(potential_dest, it->pointer, it->size); /* Mark this block as now free, but don't fiddle with the @@ -490,45 +503,39 @@ static inline uint8_t count_ones(uint8_t byte) { size_t alloc_count_free(void* pool) { (void) pool; - uint8_t* it = pool_header.block_usage; - uint8_t* end = it + pool_header.block_count; + size_t total_used = 0; - size_t total_free = 0; - - while(it < end) { - total_free += count_ones(*it) * 256; - ++it; + for(size_t i = 0; i < pool_header.block_count; ++i) { + total_used += count_ones(pool_header.block_usage[i]) * 256; } - return total_free; + return pool_header.pool_size - total_used; } size_t alloc_count_continuous(void* pool) { (void) pool; - size_t largest_block = 0; + size_t contiguous_free = 0; + size_t most_contiguous = 0; - uint8_t* it = pool_header.block_usage; - uint8_t* end = it + pool_header.block_count; + for(size_t i = 0; i < pool_header.block_count; ++i) { + uint8_t t = pool_header.block_usage[i]; - size_t current_block = 0; - while(it < end) { - uint8_t t = *it++; - if(!t) { - current_block += 2048; - } else { - for(int i = 7; i >= 0; --i) { - bool bitset = (t & (1 << i)); - if(bitset) { - current_block += (7 - i) * 256; - if(largest_block < current_block) { - largest_block = current_block; - current_block = 0; - } + for(int i = 7; i >= 0; --i) { + bool bitset = (t & (1 << i)); + if(!bitset) { + ++contiguous_free; + } else { + if(contiguous_free > most_contiguous) { + most_contiguous = contiguous_free; } + contiguous_free = 0; } } } - return largest_block; + if(contiguous_free > most_contiguous) { + most_contiguous = contiguous_free; + } + return most_contiguous * 256; } diff --git a/GL/attributes.c b/GL/attributes.c new file mode 100644 index 0000000..f12f1ed --- /dev/null +++ b/GL/attributes.c @@ -0,0 +1,675 @@ +#include +#include +#include +#include +#include +#include + +#include "private.h" +#include "platform.h" + +AttribPointerList ATTRIB_LIST; +static const float ONE_OVER_TWO_FIVE_FIVE = 1.0f / 255.0f; + +GL_FORCE_INLINE GLsizei byte_size(GLenum type) { + switch(type) { + case GL_BYTE: return sizeof(GLbyte); + case GL_UNSIGNED_BYTE: return sizeof(GLubyte); + case GL_SHORT: return sizeof(GLshort); + case GL_UNSIGNED_SHORT: return sizeof(GLushort); + case GL_INT: return sizeof(GLint); + case GL_UNSIGNED_INT: return sizeof(GLuint); + case GL_DOUBLE: return sizeof(GLdouble); + case GL_UNSIGNED_INT_2_10_10_10_REV: return sizeof(GLuint); + case GL_FLOAT: + default: return sizeof(GLfloat); + } +} + +// Used to avoid checking and updating attribute related state unless necessary +GL_FORCE_INLINE GLboolean _glStateUnchanged(AttribPointer* p, GLint size, GLenum type, GLsizei stride) { + return (p->size == size && p->type == type && p->stride == stride); +} + +GLuint* _glGetEnabledAttributes() { + return &ATTRIB_LIST.enabled; +} + + +static void _readPosition3f3f(const GLubyte* __restrict__ in, GLubyte* __restrict__ out) { + const float* input = (const float*) in; + Vertex* it = (Vertex*) out; + + float x = input[0]; + float y = input[1]; + float z = input[2]; + float w = 1.0f; + TransformVertex(x, y, z, w, it->xyz, &it->w); +} + +static void _readPosition3ub3f(const GLubyte* input, GLubyte* out) { + Vertex* it = (Vertex*)out; + + float x = input[0] * ONE_OVER_TWO_FIVE_FIVE; + float y = input[1] * ONE_OVER_TWO_FIVE_FIVE; + float z = input[2] * ONE_OVER_TWO_FIVE_FIVE; + float w = 1.0f; + TransformVertex(x, y, z, w, it->xyz, &it->w); +} + +static void _readPosition3us3f(const GLubyte* in, GLubyte* out) { + const GLushort* input = (const GLushort*) in; + Vertex* it = (Vertex*) out; + + float x = input[0]; + float y = input[1]; + float z = input[2]; + float w = 1.0f; + TransformVertex(x, y, z, w, it->xyz, &it->w); +} + +static void _readPosition3ui3f(const GLubyte* in, GLubyte* out) { + const GLuint* input = (const GLuint*) in; + Vertex* it = (Vertex*) out; + + float x = input[0]; + float y = input[1]; + float z = input[2]; + float w = 1.0f; + TransformVertex(x, y, z, w, it->xyz, &it->w); +} + +static void _readPosition2f3f(const GLubyte* in, GLubyte* out) { + const float* input = (const float*) in; + Vertex* it = (Vertex*) out; + + float x = input[0]; + float y = input[1]; + float z = 0.0f; + float w = 1.0f; + TransformVertex(x, y, z, w, it->xyz, &it->w); +} + +static void _readPosition2ub3f(const GLubyte* input, GLubyte* out) { + Vertex* it = (Vertex*) out; + + float x = input[0] * ONE_OVER_TWO_FIVE_FIVE; + float y = input[1] * ONE_OVER_TWO_FIVE_FIVE; + float z = 0.0f; + float w = 1.0f; + TransformVertex(x, y, z, w, it->xyz, &it->w); +} + +static void _readPosition2us3f(const GLubyte* in, GLubyte* out) { + const GLushort* input = (const GLushort*) in; + Vertex* it = (Vertex*) out; + + float x = input[0]; + float y = input[1]; + float z = 0.0f; + float w = 1.0f; + TransformVertex(x, y, z, w, it->xyz, &it->w); +} + +static void _readPosition2ui3f(const GLubyte* in, GLubyte* out) { + const GLuint* input = (const GLuint*) in; + Vertex* it = (Vertex*)out; + + float x = input[0]; + float y = input[1]; + float z = 0.0f; + float w = 1.0f; + TransformVertex(x, y, z, w, it->xyz, &it->w); +} + +static ReadAttributeFunc calcReadPositionFunc() { + switch(ATTRIB_LIST.vertex.type) { + default: + case GL_DOUBLE: + case GL_FLOAT: + return (ATTRIB_LIST.vertex.size == 3) ? _readPosition3f3f: + _readPosition2f3f; + case GL_BYTE: + case GL_UNSIGNED_BYTE: + return (ATTRIB_LIST.vertex.size == 3) ? _readPosition3ub3f: + _readPosition2ub3f; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + return (ATTRIB_LIST.vertex.size == 3) ? _readPosition3us3f: + _readPosition2us3f; + case GL_INT: + case GL_UNSIGNED_INT: + return (ATTRIB_LIST.vertex.size == 3) ? _readPosition3ui3f: + _readPosition2ui3f; + } +} + + +static void _fillWhiteARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { + _GL_UNUSED(input); + *((uint32_t*) output) = ~0; +} + +static void _readColour4ubARGB(const GLubyte* input, GLubyte* output) { + output[R8IDX] = input[0]; + output[G8IDX] = input[1]; + output[B8IDX] = input[2]; + output[A8IDX] = input[3]; +} + +static void _readColour4fARGB(const GLubyte* in, GLubyte* output) { + const float* input = (const float*) in; + + output[R8IDX] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); + output[G8IDX] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); + output[B8IDX] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); + output[A8IDX] = (GLubyte) clamp(input[3] * 255.0f, 0, 255); +} + +static void _readColour3fARGB(const GLubyte* in, GLubyte* output) { + const float* input = (const float*) in; + + output[R8IDX] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); + output[G8IDX] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); + output[B8IDX] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); + output[A8IDX] = 255; +} + +static void _readColour3ubARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { + output[R8IDX] = input[0]; + output[G8IDX] = input[1]; + output[B8IDX] = input[2]; + output[A8IDX] = 255; +} + +static void _readColour4ubRevARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { + argbcpy(output, input); +} + +static void _readColour4fRevARGB(const GLubyte* __restrict__ in, GLubyte* __restrict__ output) { + const float* input = (const float*) in; + + output[0] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); + output[1] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); + output[2] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); + output[3] = (GLubyte) clamp(input[3] * 255.0f, 0, 255); +} + +static void _readColour3usARGB(const GLubyte* input, GLubyte* output) { + _GL_UNUSED(input); + _GL_UNUSED(output); + gl_assert(0 && "Not Implemented"); +} + +static void _readColour3uiARGB(const GLubyte* input, GLubyte* output) { + _GL_UNUSED(input); + _GL_UNUSED(output); + gl_assert(0 && "Not Implemented"); +} + +static void _readColour4usARGB(const GLubyte* input, GLubyte* output) { + _GL_UNUSED(input); + _GL_UNUSED(output); + gl_assert(0 && "Not Implemented"); +} + +static void _readColour4uiARGB(const GLubyte* input, GLubyte* output) { + _GL_UNUSED(input); + _GL_UNUSED(output); + gl_assert(0 && "Not Implemented"); +} + +static void _readColour4usRevARGB(const GLubyte* input, GLubyte* output) { + _GL_UNUSED(input); + _GL_UNUSED(output); + gl_assert(0 && "Not Implemented"); +} + +static void _readColour4uiRevARGB(const GLubyte* input, GLubyte* output) { + _GL_UNUSED(input); + _GL_UNUSED(output); + gl_assert(0 && "Not Implemented"); +} + +static ReadAttributeFunc calcReadDiffuseFunc() { + if((ATTRIB_LIST.enabled & DIFFUSE_ENABLED_FLAG) != DIFFUSE_ENABLED_FLAG) { + /* Just fill the whole thing white if the attribute is disabled */ + return _fillWhiteARGB; + } + + switch(ATTRIB_LIST.colour.type) { + default: + case GL_DOUBLE: + case GL_FLOAT: + return (ATTRIB_LIST.colour.size == 3) ? _readColour3fARGB: + (ATTRIB_LIST.colour.size == 4) ? _readColour4fARGB: + _readColour4fRevARGB; + case GL_BYTE: + case GL_UNSIGNED_BYTE: + return (ATTRIB_LIST.colour.size == 3) ? _readColour3ubARGB: + (ATTRIB_LIST.colour.size == 4) ? _readColour4ubARGB: + _readColour4ubRevARGB; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + return (ATTRIB_LIST.colour.size == 3) ? _readColour3usARGB: + (ATTRIB_LIST.colour.size == 4) ? _readColour4usARGB: + _readColour4usRevARGB; + case GL_INT: + case GL_UNSIGNED_INT: + return (ATTRIB_LIST.colour.size == 3) ? _readColour3uiARGB: + (ATTRIB_LIST.colour.size == 4) ? _readColour4uiARGB: + _readColour4uiRevARGB; + } +} + + +static void _fillZero2f(const GLubyte* __restrict__ input, GLubyte* __restrict__ out) { + _GL_UNUSED(input); + //memset(out, 0, sizeof(float) * 2); + // memset does 8 byte writes - faster to manually write as uint32 + uint32_t* dst = (uint32_t*)out; + dst[0] = 0; + dst[1] = 0; +} + +static void _readTexcoord2f2f(const GLubyte* in, GLubyte* out) { + vec2cpy(out, in); +} + +static void _readTexcoord2ub2f(const GLubyte* input, GLubyte* out) { + float* output = (float*) out; + + output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; + output[1] = input[1] * ONE_OVER_TWO_FIVE_FIVE; +} + +static void _readTexcoord2us2f(const GLubyte* in, GLubyte* out) { + const GLushort* input = (const GLushort*) in; + float* output = (float*) out; + + output[0] = (float)input[0] / SHRT_MAX; + output[1] = (float)input[1] / SHRT_MAX; +} + +static void _readTexcoord2ui2f(const GLubyte* in, GLubyte* out) { + const GLuint* input = (const GLuint*) in; + float* output = (float*) out; + + output[0] = input[0]; + output[1] = input[1]; +} + +static ReadAttributeFunc calcReadUVFunc() { + if((ATTRIB_LIST.enabled & UV_ENABLED_FLAG) != UV_ENABLED_FLAG) { + return _fillZero2f; + } + + switch(ATTRIB_LIST.uv.type) { + default: + case GL_DOUBLE: + case GL_FLOAT: + return _readTexcoord2f2f; + case GL_BYTE: + case GL_UNSIGNED_BYTE: + return _readTexcoord2ub2f; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + return _readTexcoord2us2f; + case GL_INT: + case GL_UNSIGNED_INT: + return _readTexcoord2ui2f; + } +} + +static ReadAttributeFunc calcReadSTFunc() { + if((ATTRIB_LIST.enabled & ST_ENABLED_FLAG) != ST_ENABLED_FLAG) { + return _fillZero2f; + } + + switch(ATTRIB_LIST.st.type) { + default: + case GL_DOUBLE: + case GL_FLOAT: + return _readTexcoord2f2f; + case GL_BYTE: + case GL_UNSIGNED_BYTE: + return _readTexcoord2ub2f; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + return _readTexcoord2us2f; + case GL_INT: + case GL_UNSIGNED_INT: + return _readTexcoord2ui2f; + } +} + + +static void _fillWithNegZVE(const GLubyte* __restrict__ input, GLubyte* __restrict__ out) { + _GL_UNUSED(input); + typedef struct { float x, y, z; } V; + + static const V NegZ = {0.0f, 0.0f, -1.0f}; + + *((V*) out) = NegZ; +} + +static void _readNormal3f3f(const GLubyte* __restrict__ in, GLubyte* __restrict__ out) { + vec3cpy(out, in); +} + +static void _readNormal3ub3f(const GLubyte* input, GLubyte* out) { + float* output = (float*) out; + + output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; + output[1] = input[1] * ONE_OVER_TWO_FIVE_FIVE; + output[2] = input[2] * ONE_OVER_TWO_FIVE_FIVE; +} + +static void _readNormal3us3f(const GLubyte* in, GLubyte* out) { + const GLushort* input = (const GLushort*) in; + float* output = (float*) out; + + output[0] = input[0]; + output[1] = input[1]; + output[2] = input[2]; +} + +static void _readNormal3ui3f(const GLubyte* in, GLubyte* out) { + const GLuint* input = (const GLuint*) in; + float* output = (float*) out; + + output[0] = input[0]; + output[1] = input[1]; + output[2] = input[2]; +} + +// 10:10:10:2REV format +static void _readNormal1i3f(const GLubyte* in, GLubyte* out) { + static const float MULTIPLIER = 1.0f / 1023.0f; + + GLfloat* output = (GLfloat*) out; + + union { + int value; + struct { + signed int x: 10; + signed int y: 10; + signed int z: 10; + signed int w: 2; + } bits; + } input; + + input.value = *((const GLint*) in); + + output[0] = (2.0f * (float) input.bits.x + 1.0f) * MULTIPLIER; + output[1] = (2.0f * (float) input.bits.y + 1.0f) * MULTIPLIER; + output[2] = (2.0f * (float) input.bits.z + 1.0f) * MULTIPLIER; +} + +static ReadAttributeFunc calcReadNormalFunc() { + if((ATTRIB_LIST.enabled & NORMAL_ENABLED_FLAG) != NORMAL_ENABLED_FLAG) { + return _fillWithNegZVE; + } + + switch(ATTRIB_LIST.normal.type) { + default: + case GL_DOUBLE: + case GL_FLOAT: + return _readNormal3f3f; + break; + case GL_BYTE: + case GL_UNSIGNED_BYTE: + return _readNormal3ub3f; + break; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + return _readNormal3us3f; + break; + case GL_INT: + case GL_UNSIGNED_INT: + return _readNormal3ui3f; + break; + case GL_UNSIGNED_INT_2_10_10_10_REV: + return _readNormal1i3f; + break; + } +} + + +void APIENTRY glEnableClientState(GLenum cap) { + TRACE(); + + switch(cap) { + case GL_VERTEX_ARRAY: + ATTRIB_LIST.enabled |= VERTEX_ENABLED_FLAG; + ATTRIB_LIST.dirty |= VERTEX_ENABLED_FLAG; + break; + case GL_COLOR_ARRAY: + ATTRIB_LIST.enabled |= DIFFUSE_ENABLED_FLAG; + ATTRIB_LIST.dirty |= DIFFUSE_ENABLED_FLAG; + break; + case GL_NORMAL_ARRAY: + ATTRIB_LIST.enabled |= NORMAL_ENABLED_FLAG; + ATTRIB_LIST.dirty |= NORMAL_ENABLED_FLAG; + break; + case GL_TEXTURE_COORD_ARRAY: + (ACTIVE_CLIENT_TEXTURE) ? + (ATTRIB_LIST.enabled |= ST_ENABLED_FLAG): + (ATTRIB_LIST.enabled |= UV_ENABLED_FLAG); + + (ACTIVE_CLIENT_TEXTURE) ? + (ATTRIB_LIST.dirty |= ST_ENABLED_FLAG): + (ATTRIB_LIST.dirty |= UV_ENABLED_FLAG); + break; + default: + _glKosThrowError(GL_INVALID_ENUM, __func__); + } +} + +void APIENTRY glDisableClientState(GLenum cap) { + TRACE(); + + switch(cap) { + case GL_VERTEX_ARRAY: + ATTRIB_LIST.enabled &= ~VERTEX_ENABLED_FLAG; + ATTRIB_LIST.dirty |= VERTEX_ENABLED_FLAG; + break; + case GL_COLOR_ARRAY: + ATTRIB_LIST.enabled &= ~DIFFUSE_ENABLED_FLAG; + ATTRIB_LIST.dirty |= DIFFUSE_ENABLED_FLAG; + break; + case GL_NORMAL_ARRAY: + ATTRIB_LIST.enabled &= ~NORMAL_ENABLED_FLAG; + ATTRIB_LIST.dirty |= NORMAL_ENABLED_FLAG; + break; + case GL_TEXTURE_COORD_ARRAY: + (ACTIVE_CLIENT_TEXTURE) ? + (ATTRIB_LIST.enabled &= ~ST_ENABLED_FLAG): + (ATTRIB_LIST.enabled &= ~UV_ENABLED_FLAG); + + (ACTIVE_CLIENT_TEXTURE) ? + (ATTRIB_LIST.dirty |= ST_ENABLED_FLAG): + (ATTRIB_LIST.dirty |= UV_ENABLED_FLAG); + break; + default: + _glKosThrowError(GL_INVALID_ENUM, __func__); + } +} + + +void APIENTRY glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { + TRACE(); + + stride = (stride) ? stride : size * byte_size(type); + AttribPointer* tointer = (ACTIVE_CLIENT_TEXTURE == 0) ? &ATTRIB_LIST.uv : &ATTRIB_LIST.st; + tointer->ptr = pointer; + + if(_glStateUnchanged(tointer, size, type, stride)) return; + + if(size < 1 || size > 4) { + _glKosThrowError(GL_INVALID_VALUE, __func__); + return; + } + + tointer->stride = stride; + tointer->type = type; + tointer->size = size; + + (ACTIVE_CLIENT_TEXTURE) ? + (ATTRIB_LIST.dirty |= ST_ENABLED_FLAG): + (ATTRIB_LIST.dirty |= UV_ENABLED_FLAG); +} + +void APIENTRY glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { + TRACE(); + + stride = (stride) ? stride : (size * byte_size(type)); + ATTRIB_LIST.vertex.ptr = pointer; + + if(_glStateUnchanged(&ATTRIB_LIST.vertex, size, type, stride)) return; + + if(size < 2 || size > 4) { + _glKosThrowError(GL_INVALID_VALUE, __func__); + return; + } + + ATTRIB_LIST.vertex.stride = stride; + ATTRIB_LIST.vertex.type = type; + ATTRIB_LIST.vertex.size = size; + + ATTRIB_LIST.dirty |= VERTEX_ENABLED_FLAG; +} + +void APIENTRY glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { + TRACE(); + + stride = (stride) ? stride : ((size == GL_BGRA) ? 4 : size) * byte_size(type); + ATTRIB_LIST.colour.ptr = pointer; + + if(_glStateUnchanged(&ATTRIB_LIST.colour, size, type, stride)) return; + + if(size != 3 && size != 4 && size != GL_BGRA) { + _glKosThrowError(GL_INVALID_VALUE, __func__); + return; + } + + ATTRIB_LIST.colour.type = type; + ATTRIB_LIST.colour.size = size; + ATTRIB_LIST.colour.stride = stride; + + ATTRIB_LIST.dirty |= DIFFUSE_ENABLED_FLAG; +} + +void APIENTRY glNormalPointer(GLenum type, GLsizei stride, const GLvoid * pointer) { + TRACE(); + + GLint validTypes[] = { + GL_DOUBLE, + GL_FLOAT, + GL_BYTE, + GL_UNSIGNED_BYTE, + GL_INT, + GL_UNSIGNED_INT, + GL_UNSIGNED_INT_2_10_10_10_REV, + 0 + }; + + stride = (stride) ? stride : ATTRIB_LIST.normal.size * byte_size(type); + ATTRIB_LIST.normal.ptr = pointer; + + if(_glStateUnchanged(&ATTRIB_LIST.normal, 3, type, stride)) return; + + if(_glCheckValidEnum(type, validTypes, __func__) != 0) { + return; + } + + ATTRIB_LIST.normal.size = (type == GL_UNSIGNED_INT_2_10_10_10_REV) ? 1 : 3; + ATTRIB_LIST.normal.stride = stride; + ATTRIB_LIST.normal.type = type; + + ATTRIB_LIST.dirty |= NORMAL_ENABLED_FLAG; +} + + +void _glInitAttributePointers() { + TRACE(); + ATTRIB_LIST.dirty = ~0; // all attributes dirty + + glVertexPointer(3, GL_FLOAT, 0, NULL); + glTexCoordPointer(2, GL_FLOAT, 0, NULL); + glColorPointer(4, GL_FLOAT, 0, NULL); + glNormalPointer(GL_FLOAT, 0, NULL); +} + +GL_FORCE_INLINE GLuint _glIsVertexDataFastPathCompatible() { + /* The fast path is enabled when all enabled elements of the vertex + * match the output format. This means: + * + * xyz == 3f + * uv == 2f + * rgba == argb4444 + * st == 2f + * normal == 3f + * + * When this happens we do inline straight copies of the enabled data + * and transforms for positions and normals happen while copying. + */ + + if((ATTRIB_LIST.enabled & VERTEX_ENABLED_FLAG)) { + if(ATTRIB_LIST.vertex.size != 3 || ATTRIB_LIST.vertex.type != GL_FLOAT) { + return GL_FALSE; + } + } + + if((ATTRIB_LIST.enabled & UV_ENABLED_FLAG)) { + if(ATTRIB_LIST.uv.size != 2 || ATTRIB_LIST.uv.type != GL_FLOAT) { + return GL_FALSE; + } + } + + if((ATTRIB_LIST.enabled & DIFFUSE_ENABLED_FLAG)) { + /* FIXME: Shouldn't this be a reversed format? */ + if(ATTRIB_LIST.colour.size != GL_BGRA || ATTRIB_LIST.colour.type != GL_UNSIGNED_BYTE) { + return GL_FALSE; + } + } + + if((ATTRIB_LIST.enabled & ST_ENABLED_FLAG)) { + if(ATTRIB_LIST.st.size != 2 || ATTRIB_LIST.st.type != GL_FLOAT) { + return GL_FALSE; + } + } + + if((ATTRIB_LIST.enabled & NORMAL_ENABLED_FLAG)) { + if(ATTRIB_LIST.normal.size != 3 || ATTRIB_LIST.normal.type != GL_FLOAT) { + return GL_FALSE; + } + } + + return GL_TRUE; +} + +void _glUpdateAttributes() { + if(ATTRIB_LIST.dirty & VERTEX_ENABLED_FLAG) { + ATTRIB_LIST.vertex_func = calcReadPositionFunc(); + } + + if(ATTRIB_LIST.dirty & UV_ENABLED_FLAG) { + ATTRIB_LIST.uv_func = calcReadUVFunc(); + } + + if(ATTRIB_LIST.dirty & DIFFUSE_ENABLED_FLAG) { + ATTRIB_LIST.colour_func = calcReadDiffuseFunc(); + } + + if(ATTRIB_LIST.dirty & ST_ENABLED_FLAG) { + ATTRIB_LIST.st_func = calcReadSTFunc(); + } + + if(ATTRIB_LIST.dirty & NORMAL_ENABLED_FLAG) { + ATTRIB_LIST.normal_func = calcReadNormalFunc(); + } + + ATTRIB_LIST.fast_path = _glIsVertexDataFastPathCompatible(); + ATTRIB_LIST.dirty = 0; +} diff --git a/GL/draw.c b/GL/draw.c index 01d9cf7..f39e00e 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -8,15 +8,7 @@ #include "private.h" #include "platform.h" - -AttribPointerList ATTRIB_POINTERS; -GLuint ENABLED_VERTEX_ATTRIBUTES = 0; -GLuint FAST_PATH_ENABLED = GL_FALSE; - -static GLubyte ACTIVE_CLIENT_TEXTURE = 0; -static const float ONE_OVER_TWO_FIVE_FIVE = 1.0f / 255.0f; - -extern inline GLuint _glRecalcFastPath(); +GLubyte ACTIVE_CLIENT_TEXTURE; extern GLboolean AUTOSORT_ENABLED; @@ -25,296 +17,6 @@ extern GLboolean AUTOSORT_ENABLED; while(i--) -void _glInitAttributePointers() { - TRACE(); - - ATTRIB_POINTERS.vertex.ptr = NULL; - ATTRIB_POINTERS.vertex.stride = 0; - ATTRIB_POINTERS.vertex.type = GL_FLOAT; - ATTRIB_POINTERS.vertex.size = 4; - - ATTRIB_POINTERS.colour.ptr = NULL; - ATTRIB_POINTERS.colour.stride = 0; - ATTRIB_POINTERS.colour.type = GL_FLOAT; - ATTRIB_POINTERS.colour.size = 4; - - ATTRIB_POINTERS.uv.ptr = NULL; - ATTRIB_POINTERS.uv.stride = 0; - ATTRIB_POINTERS.uv.type = GL_FLOAT; - ATTRIB_POINTERS.uv.size = 4; - - ATTRIB_POINTERS.st.ptr = NULL; - ATTRIB_POINTERS.st.stride = 0; - ATTRIB_POINTERS.st.type = GL_FLOAT; - ATTRIB_POINTERS.st.size = 4; - - ATTRIB_POINTERS.normal.ptr = NULL; - ATTRIB_POINTERS.normal.stride = 0; - ATTRIB_POINTERS.normal.type = GL_FLOAT; - ATTRIB_POINTERS.normal.size = 3; -} - -GL_FORCE_INLINE GLsizei byte_size(GLenum type) { - switch(type) { - case GL_BYTE: return sizeof(GLbyte); - case GL_UNSIGNED_BYTE: return sizeof(GLubyte); - case GL_SHORT: return sizeof(GLshort); - case GL_UNSIGNED_SHORT: return sizeof(GLushort); - case GL_INT: return sizeof(GLint); - case GL_UNSIGNED_INT: return sizeof(GLuint); - case GL_DOUBLE: return sizeof(GLdouble); - case GL_UNSIGNED_INT_2_10_10_10_REV: return sizeof(GLuint); - case GL_FLOAT: - default: return sizeof(GLfloat); - } -} - -typedef void (*FloatParseFunc)(GLfloat* out, const GLubyte* in); -typedef void (*ByteParseFunc)(GLubyte* out, const GLubyte* in); -typedef void (*PolyBuildFunc)(Vertex* first, Vertex* previous, Vertex* vertex, Vertex* next, const GLsizei i); - -static void _readVertexData3f3f(const GLubyte* __restrict__ in, GLubyte* __restrict__ out) { - vec3cpy(out, in); -} - -// 10:10:10:2REV format -static void _readVertexData1i3f(const GLubyte* in, GLubyte* out) { - static const float MULTIPLIER = 1.0f / 1023.0f; - - GLfloat* output = (GLfloat*) out; - - union { - int value; - struct { - signed int x: 10; - signed int y: 10; - signed int z: 10; - signed int w: 2; - } bits; - } input; - - input.value = *((const GLint*) in); - - output[0] = (2.0f * (float) input.bits.x + 1.0f) * MULTIPLIER; - output[1] = (2.0f * (float) input.bits.y + 1.0f) * MULTIPLIER; - output[2] = (2.0f * (float) input.bits.z + 1.0f) * MULTIPLIER; -} - -static void _readVertexData3us3f(const GLubyte* in, GLubyte* out) { - const GLushort* input = (const GLushort*) in; - float* output = (float*) out; - - output[0] = input[0]; - output[1] = input[1]; - output[2] = input[2]; -} - -static void _readVertexData3ui3f(const GLubyte* in, GLubyte* out) { - const GLuint* input = (const GLuint*) in; - float* output = (float*) out; - - output[0] = input[0]; - output[1] = input[1]; - output[2] = input[2]; -} - - -static void _readVertexData3ub3f(const GLubyte* input, GLubyte* out) { - float* output = (float*) out; - - output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; - output[1] = input[1] * ONE_OVER_TWO_FIVE_FIVE; - output[2] = input[2] * ONE_OVER_TWO_FIVE_FIVE; -} - -static void _readVertexData2f2f(const GLubyte* in, GLubyte* out) { - vec2cpy(out, in); -} - -static void _readVertexData2f3f(const GLubyte* in, GLubyte* out) { - const float* input = (const float*) in; - float* output = (float*) out; - - vec2cpy(output, input); - output[2] = 0.0f; -} - -static void _readVertexData2ub3f(const GLubyte* input, GLubyte* out) { - float* output = (float*) out; - - output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; - output[1] = input[1] * ONE_OVER_TWO_FIVE_FIVE; - output[2] = 0.0f; -} - -static void _readVertexData2us3f(const GLubyte* in, GLubyte* out) { - const GLushort* input = (const GLushort*) in; - float* output = (float*) out; - - output[0] = input[0]; - output[1] = input[1]; - output[2] = 0.0f; -} - -static void _readVertexData2us2f(const GLubyte* in, GLubyte* out) { - const GLushort* input = (const GLushort*) in; - float* output = (float*) out; - - output[0] = (float)input[0] / SHRT_MAX; - output[1] = (float)input[1] / SHRT_MAX; -} - -static void _readVertexData2ui2f(const GLubyte* in, GLubyte* out) { - const GLuint* input = (const GLuint*) in; - float* output = (float*) out; - - output[0] = input[0]; - output[1] = input[1]; -} - -static void _readVertexData2ub2f(const GLubyte* input, GLubyte* out) { - float* output = (float*) out; - - output[0] = input[0] * ONE_OVER_TWO_FIVE_FIVE; - output[1] = input[1] * ONE_OVER_TWO_FIVE_FIVE; -} - -static void _readVertexData2ui3f(const GLubyte* in, GLubyte* out) { - const GLuint* input = (const GLuint*) in; - float* output = (float*) out; - - output[0] = input[0]; - output[1] = input[1]; - output[2] = 0.0f; -} - -static void _readVertexData4ubARGB(const GLubyte* input, GLubyte* output) { - output[R8IDX] = input[0]; - output[G8IDX] = input[1]; - output[B8IDX] = input[2]; - output[A8IDX] = input[3]; -} - -static void _readVertexData4fARGB(const GLubyte* in, GLubyte* output) { - const float* input = (const float*) in; - - output[R8IDX] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); - output[G8IDX] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); - output[B8IDX] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); - output[A8IDX] = (GLubyte) clamp(input[3] * 255.0f, 0, 255); -} - -static void _readVertexData3fARGB(const GLubyte* in, GLubyte* output) { - const float* input = (const float*) in; - - output[R8IDX] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); - output[G8IDX] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); - output[B8IDX] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); - output[A8IDX] = 1.0f; -} - -static void _readVertexData3ubARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { - output[R8IDX] = input[0]; - output[G8IDX] = input[1]; - output[B8IDX] = input[2]; - output[A8IDX] = 1.0f; -} - -static void _readVertexData4ubRevARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { - argbcpy(output, input); -} - -static void _readVertexData4fRevARGB(const GLubyte* __restrict__ in, GLubyte* __restrict__ output) { - const float* input = (const float*) in; - - output[0] = (GLubyte) clamp(input[0] * 255.0f, 0, 255); - output[1] = (GLubyte) clamp(input[1] * 255.0f, 0, 255); - output[2] = (GLubyte) clamp(input[2] * 255.0f, 0, 255); - output[3] = (GLubyte) clamp(input[3] * 255.0f, 0, 255); -} - -static void _fillWithNegZVE(const GLubyte* __restrict__ input, GLubyte* __restrict__ out) { - _GL_UNUSED(input); - - typedef struct { - float x, y, z; - } V; - - static const V NegZ = {0.0f, 0.0f, -1.0f}; - - *((V*) out) = NegZ; -} - -static void _fillWhiteARGB(const GLubyte* __restrict__ input, GLubyte* __restrict__ output) { - _GL_UNUSED(input); - *((uint32_t*) output) = ~0; -} - -static void _fillZero2f(const GLubyte* __restrict__ input, GLubyte* __restrict__ out) { - _GL_UNUSED(input); - memset(out, 0, sizeof(float) * 2); -} - -static void _readVertexData3usARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} - -static void _readVertexData3uiARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} - -static void _readVertexData4usARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} - -static void _readVertexData4uiARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} - -static void _readVertexData4usRevARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} - -static void _readVertexData4uiRevARGB(const GLubyte* input, GLubyte* output) { - _GL_UNUSED(input); - _GL_UNUSED(output); - gl_assert(0 && "Not Implemented"); -} - -GLuint* _glGetEnabledAttributes() { - return &ENABLED_VERTEX_ATTRIBUTES; -} - -AttribPointer* _glGetVertexAttribPointer() { - return &ATTRIB_POINTERS.vertex; -} - -AttribPointer* _glGetDiffuseAttribPointer() { - return &ATTRIB_POINTERS.colour; -} - -AttribPointer* _glGetNormalAttribPointer() { - return &ATTRIB_POINTERS.normal; -} - -AttribPointer* _glGetUVAttribPointer() { - return &ATTRIB_POINTERS.uv; -} - -AttribPointer* _glGetSTAttribPointer() { - return &ATTRIB_POINTERS.st; -} - typedef GLuint (*IndexParseFunc)(const GLubyte* in); static inline GLuint _parseUByteIndex(const GLubyte* in) { @@ -329,6 +31,14 @@ static inline GLuint _parseUShortIndex(const GLubyte* in) { return *((GLshort*) in); } +GL_FORCE_INLINE GLsizei index_size(GLenum type) { + switch(type) { + case GL_UNSIGNED_BYTE: return sizeof(GLubyte); + case GL_UNSIGNED_SHORT: return sizeof(GLushort); + case GL_UNSIGNED_INT: return sizeof(GLuint); + default: return sizeof(GLushort); + } +} GL_FORCE_INLINE IndexParseFunc _calcParseIndexFunc(GLenum type) { switch(type) { @@ -380,17 +90,6 @@ GL_FORCE_INLINE IndexParseFunc _calcParseIndexFunc(GLenum type) { x = __x; y = __y; z = __z; \ } - -GL_FORCE_INLINE void transformToEyeSpace(GLfloat* point) { - _glMatrixLoadModelView(); - mat_trans_single3_nodiv(point[0], point[1], point[2]); -} - -GL_FORCE_INLINE void transformNormalToEyeSpace(GLfloat* normal) { - _glMatrixLoadNormal(); - mat_trans_normal3(normal[0], normal[1], normal[2]); -} - GL_FORCE_INLINE PolyHeader *_glSubmissionTargetHeader(SubmissionTarget* target) { gl_assert(target->header_offset < aligned_vector_size(&target->output->vector)); return aligned_vector_at(&target->output->vector, target->header_offset); @@ -435,161 +134,153 @@ GL_FORCE_INLINE void genTriangleStrip(Vertex* output, GLuint count) { output[count - 1].flags = GPU_CMD_VERTEX_EOL; } -static void genTriangleFan(Vertex* output, GLuint count) { - gl_assert(count <= 255); +#define QUADSTRIP_COUNT(count) (((count) - 2) * 2) +static GL_NO_INLINE void genQuadStrip(Vertex* output, GLuint count) { + Vertex* dst = output + QUADSTRIP_COUNT(count) - 1; + Vertex* src = output + count;//(count - 1); - Vertex* dst = output + (((count - 2) * 3) - 1); - Vertex* src = output + (count - 1); + for (; count > 2; count -= 2) { + // Have to copy because of src/dst overlapping on first quad + Vertex src1 = src[-1], src2 = src[-2], src3 = src[-3], src4 = src[-4]; - GLubyte i = count - 2; - while(i--) { - *dst = *src--; + *dst = src3; + (*dst--).flags = GPU_CMD_VERTEX_EOL; + *dst-- = src4; + *dst-- = src1; + *dst-- = src2; + src -= 2; + } +} + +#define TRIFAN_COUNT(count) (((count) - 2) * 3) +static GL_NO_INLINE void genTriangleFan(Vertex* output, GLuint count) { + Vertex* dst = output + TRIFAN_COUNT(count) - 1; + Vertex* src = output + count - 1; + + // Triangles generated as {first vertex, prior vertex, current vertex} + // e.g. {v1, v2, v3, v4} produces {v1, v2, v3}, {v1, v3, v4} + for (; count > 2; count--) { + *dst = *src--; (*dst--).flags = GPU_CMD_VERTEX_EOL; *dst-- = *src; *dst-- = *output; } } -typedef void (*ReadPositionFunc)(const GLubyte*, GLubyte*); -typedef void (*ReadDiffuseFunc)(const GLubyte*, GLubyte*); -typedef void (*ReadUVFunc)(const GLubyte*, GLubyte*); -typedef void (*ReadNormalFunc)(const GLubyte*, GLubyte*); +#define POINTS_COUNT(count) ((count) * 4) +static GL_NO_INLINE void genPoints(Vertex* output, GLuint count) { + Vertex* dst = output + POINTS_COUNT(count) - 1; + Vertex* src = output + count - 1; + float half_size = HALF_POINT_SIZE; -ReadPositionFunc calcReadDiffuseFunc() { - if((ENABLED_VERTEX_ATTRIBUTES & DIFFUSE_ENABLED_FLAG) != DIFFUSE_ENABLED_FLAG) { - /* Just fill the whole thing white if the attribute is disabled */ - return _fillWhiteARGB; - } + // Expands v to { v + (S/2,-S/2), v + (S/2,S/2), v + (-S/2,-S/2), (-S/2,S/2) } + for (; count > 0; count--, src--) { + *dst = *src; + dst->flags = GPU_CMD_VERTEX_EOL; + dst->xyz[0] -= half_size; dst->xyz[1] += half_size; + dst--; - switch(ATTRIB_POINTERS.colour.type) { - default: - case GL_DOUBLE: - case GL_FLOAT: - return (ATTRIB_POINTERS.colour.size == 3) ? _readVertexData3fARGB: - (ATTRIB_POINTERS.colour.size == 4) ? _readVertexData4fARGB: - _readVertexData4fRevARGB; - case GL_BYTE: - case GL_UNSIGNED_BYTE: - return (ATTRIB_POINTERS.colour.size == 3) ? _readVertexData3ubARGB: - (ATTRIB_POINTERS.colour.size == 4) ? _readVertexData4ubARGB: - _readVertexData4ubRevARGB; - case GL_SHORT: - case GL_UNSIGNED_SHORT: - return (ATTRIB_POINTERS.colour.size == 3) ? _readVertexData3usARGB: - (ATTRIB_POINTERS.colour.size == 4) ? _readVertexData4usARGB: - _readVertexData4usRevARGB; - case GL_INT: - case GL_UNSIGNED_INT: - return (ATTRIB_POINTERS.colour.size == 3) ? _readVertexData3uiARGB: - (ATTRIB_POINTERS.colour.size == 4) ? _readVertexData4uiARGB: - _readVertexData4uiRevARGB; + *dst = *src; + dst->xyz[0] += half_size; dst->xyz[1] += half_size; + dst--; + + *dst = *src; + dst->xyz[0] -= half_size; dst->xyz[1] -= half_size; + dst--; + + *dst = *src; + dst->xyz[0] += half_size; dst->xyz[1] -= half_size; + dst--; } } -ReadPositionFunc calcReadPositionFunc() { - switch(ATTRIB_POINTERS.vertex.type) { - default: - case GL_DOUBLE: - case GL_FLOAT: - return (ATTRIB_POINTERS.vertex.size == 3) ? _readVertexData3f3f: - _readVertexData2f3f; - case GL_BYTE: - case GL_UNSIGNED_BYTE: - return (ATTRIB_POINTERS.vertex.size == 3) ? _readVertexData3ub3f: - _readVertexData2ub3f; - case GL_SHORT: - case GL_UNSIGNED_SHORT: - return (ATTRIB_POINTERS.vertex.size == 3) ? _readVertexData3us3f: - _readVertexData2us3f; - case GL_INT: - case GL_UNSIGNED_INT: - return (ATTRIB_POINTERS.vertex.size == 3) ? _readVertexData3ui3f: - _readVertexData2ui3f; +// Heavily based on the pvrline example by jnmartin84 +// Which is based on https://devcry.heiho.net/html/2017/20170820-opengl-line-drawing.html +static Vertex* draw_line(Vertex* dst, Vertex* v1, Vertex* v2) { + Vertex ov1 = *v1; + Vertex ov2 = *v2; + // TODO don't copy unless dst might overlap v1/v2 + + // Essentially "expands" a line into a quad by + // 1) Calculating normal of the line from v1 to v2 + // 2) Scaling normal by the line width + // 3) Offseting the endpoints wrt the scaled normal + float dx = ov2.xyz[0] - ov1.xyz[0]; + float dy = ov2.xyz[1] - ov1.xyz[1]; + + float inverse_mag = fast_rsqrt((dx*dx) + (dy*dy)) * HALF_LINE_WIDTH; + float nx = -dy * inverse_mag; + float ny = dx * inverse_mag; + + *dst = ov2; + dst->flags = GPU_CMD_VERTEX_EOL; + dst->xyz[0] -= nx; + dst->xyz[1] -= ny; + dst--; + + *dst = ov1; + dst->xyz[0] -= nx; + dst->xyz[1] -= ny; + dst--; + + *dst = ov2; + dst->xyz[0] += nx; + dst->xyz[1] += ny; + dst--; + + *dst = ov1; + dst->xyz[0] += nx; + dst->xyz[1] += ny; + dst--; + + return dst; +} + +#define LINES_COUNT(count) (((count) / 2) * 4) +static GL_NO_INLINE void genLines(Vertex* output, GLuint count) { + Vertex* dst = output + LINES_COUNT(count) - 1; + Vertex* src = output + count - 1; + + // Draws line using two vertices + for (; count >= 2; count -= 2, src -= 2) { + dst = draw_line(dst, src, src - 1); } } -ReadUVFunc calcReadUVFunc() { - if((ENABLED_VERTEX_ATTRIBUTES & UV_ENABLED_FLAG) != UV_ENABLED_FLAG) { - return _fillZero2f; - } +#define LINE_STRIP_COUNT(count) (((count) - 1) * 4) +static GL_NO_INLINE void genLineStrip(Vertex* output, GLuint count) { + Vertex* dst = output + LINE_STRIP_COUNT(count) - 1; + Vertex* src = output + count - 1; - switch(ATTRIB_POINTERS.uv.type) { - default: - case GL_DOUBLE: - case GL_FLOAT: - return _readVertexData2f2f; - case GL_BYTE: - case GL_UNSIGNED_BYTE: - return _readVertexData2ub2f; - case GL_SHORT: - case GL_UNSIGNED_SHORT: - return _readVertexData2us2f; - case GL_INT: - case GL_UNSIGNED_INT: - return _readVertexData2ui2f; + // Draws line using current and prior vertex + for (; count > 1; count--, src--) { + dst = draw_line(dst, src, src - 1); } } -ReadUVFunc calcReadSTFunc() { - if((ENABLED_VERTEX_ATTRIBUTES & ST_ENABLED_FLAG) != ST_ENABLED_FLAG) { - return _fillZero2f; +#define LINE_LOOP_COUNT(count) ((count) * 4) +static GL_NO_INLINE void genLineLoop(Vertex* output, GLuint count) { + Vertex* dst = output + LINE_LOOP_COUNT(count) - 1; + Vertex* src = output + count - 1; + Vertex last = *src, first = *output; + + // Draws line using current and prior vertex + for (; count > 1; count--, src--) { + dst = draw_line(dst, src, src - 1); } - switch(ATTRIB_POINTERS.st.type) { - default: - case GL_DOUBLE: - case GL_FLOAT: - return _readVertexData2f2f; - case GL_BYTE: - case GL_UNSIGNED_BYTE: - return _readVertexData2ub2f; - case GL_SHORT: - case GL_UNSIGNED_SHORT: - return _readVertexData2us2f; - case GL_INT: - case GL_UNSIGNED_INT: - return _readVertexData2ui2f; - } + // Connect first and last vertex + draw_line(dst, &first, &last); } -ReadNormalFunc calcReadNormalFunc() { - if((ENABLED_VERTEX_ATTRIBUTES & NORMAL_ENABLED_FLAG) != NORMAL_ENABLED_FLAG) { - return _fillWithNegZVE; - } - - switch(ATTRIB_POINTERS.normal.type) { - default: - case GL_DOUBLE: - case GL_FLOAT: - return _readVertexData3f3f; - break; - case GL_BYTE: - case GL_UNSIGNED_BYTE: - return _readVertexData3ub3f; - break; - case GL_SHORT: - case GL_UNSIGNED_SHORT: - return _readVertexData3us3f; - break; - case GL_INT: - case GL_UNSIGNED_INT: - return _readVertexData3ui3f; - break; - case GL_UNSIGNED_INT_2_10_10_10_REV: - return _readVertexData1i3f; - break; - } -} - -static void _readPositionData(ReadDiffuseFunc func, const GLuint first, const GLuint count, Vertex* it) { - const GLsizei vstride = ATTRIB_POINTERS.vertex.stride; - const GLubyte* vptr = ((GLubyte*) ATTRIB_POINTERS.vertex.ptr + (first * vstride)); - - float pos[3]; +static void _readPositionData(const GLuint first, const GLuint count, Vertex* it) { + const ReadAttributeFunc func = ATTRIB_LIST.vertex_func; + const GLsizei vstride = ATTRIB_LIST.vertex.stride; + const GLubyte* vptr = ((GLubyte*) ATTRIB_LIST.vertex.ptr + (first * vstride)); ITERATE(count) { PREFETCH(vptr + vstride); - func(vptr, (GLubyte*) pos); + func(vptr, (GLubyte*) it); it->flags = GPU_CMD_VERTEX; vptr += vstride; @@ -597,9 +288,10 @@ static void _readPositionData(ReadDiffuseFunc func, const GLuint first, const GL } } -static void _readUVData(ReadUVFunc func, const GLuint first, const GLuint count, Vertex* it) { - const GLsizei uvstride = ATTRIB_POINTERS.uv.stride; - const GLubyte* uvptr = ((GLubyte*) ATTRIB_POINTERS.uv.ptr + (first * uvstride)); +static void _readUVData(const GLuint first, const GLuint count, Vertex* it) { + const ReadAttributeFunc func = ATTRIB_LIST.uv_func; + const GLsizei uvstride = ATTRIB_LIST.uv.stride; + const GLubyte* uvptr = ((GLubyte*) ATTRIB_LIST.uv.ptr + (first * uvstride)); ITERATE(count) { PREFETCH(uvptr + uvstride); @@ -610,9 +302,10 @@ static void _readUVData(ReadUVFunc func, const GLuint first, const GLuint count, } } -static void _readSTData(ReadUVFunc func, const GLuint first, const GLuint count, VertexExtra* it) { - const GLsizei ststride = ATTRIB_POINTERS.st.stride; - const GLubyte* stptr = ((GLubyte*) ATTRIB_POINTERS.st.ptr + (first * ststride)); +static void _readSTData(const GLuint first, const GLuint count, VertexExtra* it) { + const ReadAttributeFunc func = ATTRIB_LIST.st_func; + const GLsizei ststride = ATTRIB_LIST.st.stride; + const GLubyte* stptr = ((GLubyte*) ATTRIB_LIST.st.ptr + (first * ststride)); ITERATE(count) { PREFETCH(stptr + ststride); @@ -622,9 +315,10 @@ static void _readSTData(ReadUVFunc func, const GLuint first, const GLuint count, } } -static void _readNormalData(ReadNormalFunc func, const GLuint first, const GLuint count, VertexExtra* it) { - const GLsizei nstride = ATTRIB_POINTERS.normal.stride; - const GLubyte* nptr = ((GLubyte*) ATTRIB_POINTERS.normal.ptr + (first * nstride)); +static void _readNormalData(const GLuint first, const GLuint count, VertexExtra* it) { + const ReadAttributeFunc func = ATTRIB_LIST.normal_func; + const GLsizei nstride = ATTRIB_LIST.normal.stride; + const GLubyte* nptr = ((GLubyte*) ATTRIB_LIST.normal.ptr + (first * nstride)); ITERATE(count) { func(nptr, (GLubyte*) it->nxyz); @@ -632,9 +326,7 @@ static void _readNormalData(ReadNormalFunc func, const GLuint first, const GLuin if(_glIsNormalizeEnabled()) { GLfloat* n = (GLfloat*) it->nxyz; - float temp = n[0] * n[0]; - temp = MATH_fmac(n[1], n[1], temp); - temp = MATH_fmac(n[2], n[2], temp); + float temp = n[0] * n[0] + n[1] * n[1] + n[2] * n[2]; float ilength = MATH_fsrra(temp); n[0] *= ilength; @@ -646,13 +338,10 @@ static void _readNormalData(ReadNormalFunc func, const GLuint first, const GLuin } } -GL_FORCE_INLINE GLuint diffusePointerSize() { - return (ATTRIB_POINTERS.colour.size == GL_BGRA) ? 4 : ATTRIB_POINTERS.colour.size; -} - -static void _readDiffuseData(ReadDiffuseFunc func, const GLuint first, const GLuint count, Vertex* it) { - const GLuint cstride = ATTRIB_POINTERS.colour.stride; - const GLubyte* cptr = ((GLubyte*) ATTRIB_POINTERS.colour.ptr) + (first * cstride); +static void _readDiffuseData(const GLuint first, const GLuint count, Vertex* it) { + const ReadAttributeFunc func = ATTRIB_LIST.colour_func; + const GLuint cstride = ATTRIB_LIST.colour.stride; + const GLubyte* cptr = ((GLubyte*) ATTRIB_LIST.colour.ptr) + (first * cstride); ITERATE(count) { PREFETCH(cptr + cstride); @@ -666,7 +355,7 @@ static void generateElements( SubmissionTarget* target, const GLsizei first, const GLuint count, const GLubyte* indices, const GLenum type) { - const GLsizei istride = byte_size(type); + const GLsizei istride = index_size(type); const IndexParseFunc IndexFunc = _calcParseIndexFunc(type); GLubyte* xyz; @@ -678,34 +367,35 @@ static void generateElements( Vertex* output = _glSubmissionTargetStart(target); VertexExtra* ve = aligned_vector_at(target->extras, 0); + float pos[3], w = 1.0f; uint32_t i = first; uint32_t idx = 0; - const ReadPositionFunc pos_func = calcReadPositionFunc(); - const GLsizei vstride = ATTRIB_POINTERS.vertex.stride; + const ReadAttributeFunc pos_func = ATTRIB_LIST.vertex_func; + const GLsizei vstride = ATTRIB_LIST.vertex.stride; - const ReadUVFunc uv_func = calcReadUVFunc(); - const GLuint uvstride = ATTRIB_POINTERS.uv.stride; + const ReadAttributeFunc uv_func = ATTRIB_LIST.uv_func; + const GLuint uvstride = ATTRIB_LIST.uv.stride; - const ReadUVFunc st_func = calcReadSTFunc(); - const GLuint ststride = ATTRIB_POINTERS.st.stride; + const ReadAttributeFunc st_func = ATTRIB_LIST.st_func; + const GLuint ststride = ATTRIB_LIST.st.stride; - const ReadDiffuseFunc diffuse_func = calcReadDiffuseFunc(); - const GLuint dstride = ATTRIB_POINTERS.colour.stride; + const ReadAttributeFunc diffuse_func = ATTRIB_LIST.colour_func; + const GLuint dstride = ATTRIB_LIST.colour.stride; - const ReadNormalFunc normal_func = calcReadNormalFunc(); - const GLuint nstride = ATTRIB_POINTERS.normal.stride; + const ReadAttributeFunc normal_func = ATTRIB_LIST.normal_func; + const GLuint nstride = ATTRIB_LIST.normal.stride; for(; i < first + count; ++i) { idx = IndexFunc(indices + (i * istride)); - xyz = (GLubyte*) ATTRIB_POINTERS.vertex.ptr + (idx * vstride); - uv = (GLubyte*) ATTRIB_POINTERS.uv.ptr + (idx * uvstride); - bgra = (GLubyte*) ATTRIB_POINTERS.colour.ptr + (idx * dstride); - st = (GLubyte*) ATTRIB_POINTERS.st.ptr + (idx * ststride); - nxyz = (GLubyte*) ATTRIB_POINTERS.normal.ptr + (idx * nstride); + xyz = (GLubyte*) ATTRIB_LIST.vertex.ptr + (idx * vstride); + uv = (GLubyte*) ATTRIB_LIST.uv.ptr + (idx * uvstride); + bgra = (GLubyte*) ATTRIB_LIST.colour.ptr + (idx * dstride); + st = (GLubyte*) ATTRIB_LIST.st.ptr + (idx * ststride); + nxyz = (GLubyte*) ATTRIB_LIST.normal.ptr + (idx * nstride); - pos_func(xyz, (GLubyte*) output->xyz); + pos_func(xyz, (GLubyte*) output); uv_func(uv, (GLubyte*) output->uv); diffuse_func(bgra, output->bgra); st_func(st, (GLubyte*) ve->st); @@ -734,27 +424,25 @@ static void generateElementsFastPath( Vertex* start = _glSubmissionTargetStart(target); - const GLuint vstride = ATTRIB_POINTERS.vertex.stride; - const GLuint uvstride = ATTRIB_POINTERS.uv.stride; - const GLuint ststride = ATTRIB_POINTERS.st.stride; - const GLuint dstride = ATTRIB_POINTERS.colour.stride; - const GLuint nstride = ATTRIB_POINTERS.normal.stride; + const GLuint vstride = ATTRIB_LIST.vertex.stride; + const GLuint uvstride = ATTRIB_LIST.uv.stride; + const GLuint ststride = ATTRIB_LIST.st.stride; + const GLuint dstride = ATTRIB_LIST.colour.stride; + const GLuint nstride = ATTRIB_LIST.normal.stride; - const GLsizei istride = byte_size(type); + const GLsizei istride = index_size(type); const IndexParseFunc IndexFunc = _calcParseIndexFunc(type); /* Copy the pos, uv and color directly in one go */ - const GLubyte* pos = (ENABLED_VERTEX_ATTRIBUTES & VERTEX_ENABLED_FLAG) ? ATTRIB_POINTERS.vertex.ptr : NULL; - const GLubyte* uv = (ENABLED_VERTEX_ATTRIBUTES & UV_ENABLED_FLAG) ? ATTRIB_POINTERS.uv.ptr : NULL; - const GLubyte* col = (ENABLED_VERTEX_ATTRIBUTES & DIFFUSE_ENABLED_FLAG) ? ATTRIB_POINTERS.colour.ptr : NULL; - const GLubyte* st = (ENABLED_VERTEX_ATTRIBUTES & ST_ENABLED_FLAG) ? ATTRIB_POINTERS.st.ptr : NULL; - const GLubyte* n = (ENABLED_VERTEX_ATTRIBUTES & NORMAL_ENABLED_FLAG) ? ATTRIB_POINTERS.normal.ptr : NULL; + const GLubyte* pos = (ATTRIB_LIST.enabled & VERTEX_ENABLED_FLAG) ? ATTRIB_LIST.vertex.ptr : NULL; + const GLubyte* uv = (ATTRIB_LIST.enabled & UV_ENABLED_FLAG) ? ATTRIB_LIST.uv.ptr : NULL; + const GLubyte* col = (ATTRIB_LIST.enabled & DIFFUSE_ENABLED_FLAG) ? ATTRIB_LIST.colour.ptr : NULL; + const GLubyte* st = (ATTRIB_LIST.enabled & ST_ENABLED_FLAG) ? ATTRIB_LIST.st.ptr : NULL; + const GLubyte* n = (ATTRIB_LIST.enabled & NORMAL_ENABLED_FLAG) ? ATTRIB_LIST.normal.ptr : NULL; VertexExtra* ve = aligned_vector_at(target->extras, 0); Vertex* it = start; - const float w = 1.0f; - if(!pos) { return; } @@ -764,32 +452,32 @@ static void generateElementsFastPath( it->flags = GPU_CMD_VERTEX; - pos = (GLubyte*) ATTRIB_POINTERS.vertex.ptr + (idx * vstride); - TransformVertex((const float*) pos, &w, it->xyz, &it->w); + pos = (GLubyte*) ATTRIB_LIST.vertex.ptr + (idx * vstride); + TransformVertex(((float*) pos)[0], ((float*) pos)[1], ((float*) pos)[2], 1.0f, it->xyz, &it->w); if(uv) { - uv = (GLubyte*) ATTRIB_POINTERS.uv.ptr + (idx * uvstride); + uv = (GLubyte*) ATTRIB_LIST.uv.ptr + (idx * uvstride); MEMCPY4(it->uv, uv, sizeof(float) * 2); } else { *((Float2*) it->uv) = F2ZERO; } if(col) { - col = (GLubyte*) ATTRIB_POINTERS.colour.ptr + (idx * dstride); + col = (GLubyte*) ATTRIB_LIST.colour.ptr + (idx * dstride); MEMCPY4(it->bgra, col, sizeof(uint32_t)); } else { *((uint32_t*) it->bgra) = ~0; } if(st) { - st = (GLubyte*) ATTRIB_POINTERS.st.ptr + (idx * ststride); + st = (GLubyte*) ATTRIB_LIST.st.ptr + (idx * ststride); MEMCPY4(ve->st, st, sizeof(float) * 2); } else { *((Float2*) ve->st) = F2ZERO; } if(n) { - n = (GLubyte*) ATTRIB_POINTERS.normal.ptr + (idx * nstride); + n = (GLubyte*) ATTRIB_LIST.normal.ptr + (idx * nstride); MEMCPY4(ve->nxyz, n, sizeof(float) * 3); } else { *((Float3*) ve->nxyz) = F3Z; @@ -838,17 +526,11 @@ static void generateArrays(SubmissionTarget* target, const GLsizei first, const Vertex* start = _glSubmissionTargetStart(target); VertexExtra* ve = aligned_vector_at(target->extras, 0); - const ReadPositionFunc pfunc = calcReadPositionFunc(); - const ReadDiffuseFunc dfunc = calcReadDiffuseFunc(); - const ReadUVFunc uvfunc = calcReadUVFunc(); - const ReadNormalFunc nfunc = calcReadNormalFunc(); - const ReadUVFunc stfunc = calcReadSTFunc(); - - _readPositionData(pfunc, first, count, start); - _readDiffuseData(dfunc, first, count, start); - _readUVData(uvfunc, first, count, start); - _readNormalData(nfunc, first, count, ve); - _readSTData(stfunc, first, count, ve); + _readPositionData(first, count, start); + _readDiffuseData(first, count, start); + _readUVData(first, count, start); + _readNormalData(first, count, ve); + _readSTData(first, count, ve); } static void generate(SubmissionTarget* target, const GLenum mode, const GLsizei first, const GLuint count, @@ -856,7 +538,7 @@ static void generate(SubmissionTarget* target, const GLenum mode, const GLsizei /* Read from the client buffers and generate an array of ClipVertices */ TRACE(); - if(FAST_PATH_ENABLED) { + if(ATTRIB_LIST.fast_path) { if(indices) { generateElementsFastPath(target, first, count, indices, type); } else { @@ -888,11 +570,28 @@ static void generate(SubmissionTarget* target, const GLenum mode, const GLsizei case GL_QUADS: genQuads(it, count); break; + case GL_TRIANGLE_STRIP: + genTriangleStrip(it, count); + break; + + case GL_QUAD_STRIP: + genQuadStrip(it, count); + break; case GL_TRIANGLE_FAN: genTriangleFan(it, count); break; - case GL_TRIANGLE_STRIP: - genTriangleStrip(it, count); + + case GL_POINTS: + genPoints(it, count); + break; + case GL_LINES: + genLines(it, count); + break; + case GL_LINE_STRIP: + genLineStrip(it, count); + break; + case GL_LINE_LOOP: + genLineLoop(it, count); break; default: gl_assert(0 && "Not Implemented"); @@ -903,76 +602,31 @@ static void transform(SubmissionTarget* target) { TRACE(); /* Perform modelview transform, storing W */ - Vertex* vertex = _glSubmissionTargetStart(target); + Vertex* it = _glSubmissionTargetStart(target); + int count = target->count; - TransformVertices(vertex, target->count); + for(int i = 0; i < count; ++i, ++it) { + TransformVertex(it->xyz[0], it->xyz[1], it->xyz[2], it->w, + it->xyz, &it->w); + } } -static void mat_transform_normal3(const float* xyz, const float* xyzOut, const uint32_t count, const uint32_t inStride, const uint32_t outStride) { - const uint8_t* dataIn = (const uint8_t*) xyz; - uint8_t* dataOut = (uint8_t*) xyzOut; - +static void mat_transform_normal3(VertexExtra* extra, const uint32_t count) { ITERATE(count) { - const float* in = (const float*) dataIn; - float* out = (float*) dataOut; - - TransformNormalNoMod(in, out); - - dataIn += inStride; - dataOut += outStride; + TransformNormalNoMod(extra->nxyz, extra->nxyz); + extra++; } } static void light(SubmissionTarget* target) { - - static AlignedVector* eye_space_data = NULL; - - if(!eye_space_data) { - eye_space_data = (AlignedVector*) malloc(sizeof(AlignedVector)); - aligned_vector_init(eye_space_data, sizeof(EyeSpaceData)); - } - - aligned_vector_resize(eye_space_data, target->count); - /* Perform lighting calculations and manipulate the colour */ Vertex* vertex = _glSubmissionTargetStart(target); VertexExtra* extra = aligned_vector_at(target->extras, 0); - EyeSpaceData* eye_space = (EyeSpaceData*) eye_space_data->data; _glMatrixLoadNormal(); - mat_transform_normal3(extra->nxyz, eye_space->n, target->count, sizeof(VertexExtra), sizeof(EyeSpaceData)); + mat_transform_normal3(extra, target->count); - EyeSpaceData* ES = aligned_vector_at(eye_space_data, 0); - _glPerformLighting(vertex, ES, target->count); -} - -GL_FORCE_INLINE void divide(SubmissionTarget* target) { - TRACE(); - - /* Perform perspective divide on each vertex */ - Vertex* vertex = _glSubmissionTargetStart(target); - - const float h = GetVideoMode()->height; - - ITERATE(target->count) { - const float f = MATH_Fast_Invert(vertex->w); - - /* Convert to NDC and apply viewport */ - vertex->xyz[0] = MATH_fmac( - VIEWPORT.hwidth, vertex->xyz[0] * f, VIEWPORT.x_plus_hwidth - ); - vertex->xyz[1] = h - MATH_fmac( - VIEWPORT.hheight, vertex->xyz[1] * f, VIEWPORT.y_plus_hheight - ); - - /* Apply depth range */ - vertex->xyz[2] = MAX( - 1.0f - MATH_fmac(vertex->xyz[2] * f, 0.5f, 0.5f), - PVR_MIN_Z - ); - - ++vertex; - } + _glPerformLighting(vertex, extra, target->count); } GL_FORCE_INLINE int _calc_pvr_face_culling() { @@ -1014,42 +668,6 @@ GL_FORCE_INLINE int _calc_pvr_depth_test() { } } -GL_FORCE_INLINE int _calcPVRBlendFactor(GLenum factor) { - switch(factor) { - case GL_ZERO: - return GPU_BLEND_ZERO; - case GL_SRC_ALPHA: - return GPU_BLEND_SRCALPHA; - case GL_DST_COLOR: - return GPU_BLEND_DESTCOLOR; - case GL_DST_ALPHA: - return GPU_BLEND_DESTALPHA; - case GL_ONE_MINUS_DST_COLOR: - return GPU_BLEND_INVDESTCOLOR; - case GL_ONE_MINUS_SRC_ALPHA: - return GPU_BLEND_INVSRCALPHA; - case GL_ONE_MINUS_DST_ALPHA: - return GPU_BLEND_INVDESTALPHA; - case GL_ONE: - return GPU_BLEND_ONE; - default: - fprintf(stderr, "Invalid blend mode: %u\n", (unsigned int) factor); - return GPU_BLEND_ONE; - } -} - - -GL_FORCE_INLINE void _updatePVRBlend(PolyContext* context) { - if(_glIsBlendingEnabled() || _glIsAlphaTestEnabled()) { - context->gen.alpha = GPU_ALPHA_ENABLE; - } else { - context->gen.alpha = GPU_ALPHA_DISABLE; - } - - context->blend.src = _calcPVRBlendFactor(_glGetBlendSourceFactor()); - context->blend.dst = _calcPVRBlendFactor(_glGetBlendDestFactor()); -} - GL_FORCE_INLINE void apply_poly_header(PolyHeader* header, GLboolean multiTextureHeader, PolyList* activePolyList, GLshort textureUnit) { TRACE(); @@ -1080,7 +698,11 @@ GL_FORCE_INLINE void apply_poly_header(PolyHeader* header, GLboolean multiTextur ctx.gen.fog_type = GPU_FOG_DISABLE; } - _updatePVRBlend(&ctx); + if(_glIsBlendingEnabled() || _glIsAlphaTestEnabled()) { + ctx.gen.alpha = GPU_ALPHA_ENABLE; + } else { + ctx.gen.alpha = GPU_ALPHA_DISABLE; + } if(ctx.list_type == GPU_LIST_OP_POLY) { /* Opaque polys are always one/zero */ @@ -1091,9 +713,14 @@ GL_FORCE_INLINE void apply_poly_header(PolyHeader* header, GLboolean multiTextur ctx.blend.src = GPU_BLEND_SRCALPHA; ctx.blend.dst = GPU_BLEND_INVSRCALPHA; ctx.depth.comparison = GPU_DEPTHCMP_LEQUAL; - } else if(ctx.list_type == GPU_LIST_TR_POLY && AUTOSORT_ENABLED) { - /* Autosort mode requires this mode for transparent polys */ - ctx.depth.comparison = GPU_DEPTHCMP_GEQUAL; + } else { + ctx.blend.src = _glGetGpuBlendSrcFactor(); + ctx.blend.dst = _glGetGpuBlendDstFactor(); + + if(ctx.list_type == GPU_LIST_TR_POLY && AUTOSORT_ENABLED) { + /* Autosort mode requires this mode for transparent polys */ + ctx.depth.comparison = GPU_DEPTHCMP_GEQUAL; + } } _glUpdatePVRTextureContext(&ctx, textureUnit); @@ -1146,23 +773,36 @@ void _glInitSubmissionTarget() { target->extras = &VERTEX_EXTRAS; } +GL_FORCE_INLINE GLuint calcFinalVertices(GLenum mode, GLuint count) { + switch (mode) { + case GL_POINTS: + return POINTS_COUNT(count); + case GL_LINE_LOOP: + return LINE_LOOP_COUNT(count); + case GL_LINE_STRIP: + return LINE_STRIP_COUNT(count); + case GL_LINES: + return LINES_COUNT(count); + case GL_TRIANGLE_FAN: + return TRIFAN_COUNT(count); + case GL_QUAD_STRIP: + return QUADSTRIP_COUNT(count); + } + return count; +} GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GLenum type, const GLvoid* indices) { - SubmissionTarget* const target = &SUBMISSION_TARGET; AlignedVector* const extras = target->extras; TRACE(); /* Do nothing if vertices aren't enabled */ - if(!(ENABLED_VERTEX_ATTRIBUTES & VERTEX_ENABLED_FLAG)) { - return; - } + if(!(ATTRIB_LIST.enabled & VERTEX_ENABLED_FLAG)) return; + if(ATTRIB_LIST.dirty) _glUpdateAttributes(); /* No vertices? Do nothing */ - if(!count) { - return; - } + if(!count) return; /* Polygons are treated as triangle fans, the only time this would be a * problem is if we supported glPolygonMode(..., GL_LINE) but we don't. @@ -1184,14 +824,6 @@ GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GL } } - if(mode == GL_LINE_STRIP || mode == GL_LINES) { - fprintf(stderr, "Line drawing is currently unsupported\n"); - return; - } - - // We don't handle this any further, so just make sure we never pass it down */ - gl_assert(mode != GL_POLYGON); - target->output = _glActivePolyList(); gl_assert(target->output); gl_assert(extras); @@ -1200,7 +832,7 @@ GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GL GLboolean header_required = (vector_size == 0) || _glGPUStateIsDirty(); - target->count = (mode == GL_TRIANGLE_FAN) ? ((count - 2) * 3) : count; + target->count = calcFinalVertices(mode, count); target->header_offset = vector_size; target->start_offset = target->header_offset + (header_required ? 1 : 0); @@ -1231,15 +863,8 @@ GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GL _glMatrixLoadModelViewProjection(); } - /* If we're FAST_PATH_ENABLED, then this will do the transform for us */ generate(target, mode, first, count, (GLubyte*) indices, type); - /* No fast path, then we have to do another iteration :( */ - if(!FAST_PATH_ENABLED) { - /* Multiply by modelview */ - transform(target); - } - if(_glIsLightingEnabled()){ light(target); @@ -1264,7 +889,7 @@ GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GL // TextureObject* texture1 = _glGetTexture1(); // /* Multitexture implicitly disabled */ - // if(!texture1 || ((ENABLED_VERTEX_ATTRIBUTES & ST_ENABLED_FLAG) != ST_ENABLED_FLAG)) { + // if(!texture1 || ((ATTRIB_LIST.enabled & ST_ENABLED_FLAG) != ST_ENABLED_FLAG)) { // /* Multitexture actively disabled */ // return; // } @@ -1312,60 +937,6 @@ void APIENTRY glDrawArrays(GLenum mode, GLint first, GLsizei count) { submitVertices(mode, first, count, GL_UNSIGNED_INT, NULL); } -void APIENTRY glEnableClientState(GLenum cap) { - TRACE(); - - switch(cap) { - case GL_VERTEX_ARRAY: - ENABLED_VERTEX_ATTRIBUTES |= VERTEX_ENABLED_FLAG; - break; - case GL_COLOR_ARRAY: - ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG; - break; - case GL_NORMAL_ARRAY: - ENABLED_VERTEX_ATTRIBUTES |= NORMAL_ENABLED_FLAG; - break; - case GL_TEXTURE_COORD_ARRAY: - (ACTIVE_CLIENT_TEXTURE) ? - (ENABLED_VERTEX_ATTRIBUTES |= ST_ENABLED_FLAG): - (ENABLED_VERTEX_ATTRIBUTES |= UV_ENABLED_FLAG); - break; - default: - _glKosThrowError(GL_INVALID_ENUM, __func__); - } - - /* It's possible that we called glVertexPointer and friends before - * calling glEnableClientState, so we should recheck to make sure - * everything is in the right format with this new information */ - _glRecalcFastPath(); -} - -void APIENTRY glDisableClientState(GLenum cap) { - TRACE(); - - switch(cap) { - case GL_VERTEX_ARRAY: - ENABLED_VERTEX_ATTRIBUTES &= ~VERTEX_ENABLED_FLAG; - break; - case GL_COLOR_ARRAY: - ENABLED_VERTEX_ATTRIBUTES &= ~DIFFUSE_ENABLED_FLAG; - break; - case GL_NORMAL_ARRAY: - ENABLED_VERTEX_ATTRIBUTES &= ~NORMAL_ENABLED_FLAG; - break; - case GL_TEXTURE_COORD_ARRAY: - (ACTIVE_CLIENT_TEXTURE) ? - (ENABLED_VERTEX_ATTRIBUTES &= ~ST_ENABLED_FLAG): - (ENABLED_VERTEX_ATTRIBUTES &= ~UV_ENABLED_FLAG); - break; - default: - _glKosThrowError(GL_INVALID_ENUM, __func__); - } - - /* State changed, recalculate */ - _glRecalcFastPath(); -} - GLuint _glGetActiveClientTexture() { return ACTIVE_CLIENT_TEXTURE; } @@ -1380,111 +951,3 @@ void APIENTRY glClientActiveTextureARB(GLenum texture) { ACTIVE_CLIENT_TEXTURE = (texture == GL_TEXTURE1_ARB) ? 1 : 0; } - -GL_FORCE_INLINE GLboolean _glComparePointers(AttribPointer* p, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer) { - return (p->size == size && p->type == type && p->stride == stride && p->ptr == pointer); -} - -void APIENTRY glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { - TRACE(); - - if(size < 1 || size > 4) { - _glKosThrowError(GL_INVALID_VALUE, __func__); - return; - } - - stride = (stride) ? stride : size * byte_size(type); - - AttribPointer* tointer = (ACTIVE_CLIENT_TEXTURE == 0) ? &ATTRIB_POINTERS.uv : &ATTRIB_POINTERS.st; - - if(_glComparePointers(tointer, size, type, stride, pointer)) { - // No Change - return; - } - - tointer->ptr = pointer; - tointer->stride = stride; - tointer->type = type; - tointer->size = size; - - _glRecalcFastPath(); -} - -void APIENTRY glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { - TRACE(); - - if(size < 2 || size > 4) { - _glKosThrowError(GL_INVALID_VALUE, __func__); - return; - } - - stride = (stride) ? stride : (size * byte_size(ATTRIB_POINTERS.vertex.type)); - - if(_glComparePointers(&ATTRIB_POINTERS.vertex, size, type, stride, pointer)) { - // No Change - return; - } - - ATTRIB_POINTERS.vertex.ptr = pointer; - ATTRIB_POINTERS.vertex.stride = stride; - ATTRIB_POINTERS.vertex.type = type; - ATTRIB_POINTERS.vertex.size = size; - - _glRecalcFastPath(); -} - -void APIENTRY glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { - TRACE(); - - if(size != 3 && size != 4 && size != GL_BGRA) { - _glKosThrowError(GL_INVALID_VALUE, __func__); - return; - } - - stride = (stride) ? stride : ((size == GL_BGRA) ? 4 : size) * byte_size(type); - - if(_glComparePointers(&ATTRIB_POINTERS.colour, size, type, stride, pointer)) { - // No Change - return; - } - - ATTRIB_POINTERS.colour.ptr = pointer; - ATTRIB_POINTERS.colour.type = type; - ATTRIB_POINTERS.colour.size = size; - ATTRIB_POINTERS.colour.stride = stride; - - _glRecalcFastPath(); -} - -void APIENTRY glNormalPointer(GLenum type, GLsizei stride, const GLvoid * pointer) { - TRACE(); - - GLint validTypes[] = { - GL_DOUBLE, - GL_FLOAT, - GL_BYTE, - GL_UNSIGNED_BYTE, - GL_INT, - GL_UNSIGNED_INT, - GL_UNSIGNED_INT_2_10_10_10_REV, - 0 - }; - - if(_glCheckValidEnum(type, validTypes, __func__) != 0) { - return; - } - - stride = (stride) ? stride : ATTRIB_POINTERS.normal.size * byte_size(type); - - if(_glComparePointers(&ATTRIB_POINTERS.normal, 3, type, stride, pointer)) { - // No Change - return; - } - - ATTRIB_POINTERS.normal.ptr = pointer; - ATTRIB_POINTERS.normal.size = (type == GL_UNSIGNED_INT_2_10_10_10_REV) ? 1 : 3; - ATTRIB_POINTERS.normal.stride = stride; - ATTRIB_POINTERS.normal.type = type; - - _glRecalcFastPath(); -} diff --git a/GL/draw_fastpath.inc b/GL/draw_fastpath.inc index 8ea3514..fe3b527 100644 --- a/GL/draw_fastpath.inc +++ b/GL/draw_fastpath.inc @@ -5,8 +5,7 @@ MAKE_FUNC(POLYMODE) { - static const float w = 1.0f; - if(!(ENABLED_VERTEX_ATTRIBUTES & VERTEX_ENABLED_FLAG)) { + if(!(ATTRIB_LIST.enabled & VERTEX_ENABLED_FLAG)) { /* If we don't have vertices, do nothing */ return; } @@ -29,8 +28,8 @@ MAKE_FUNC(POLYMODE) const int_fast32_t loop = ((min + BATCH_SIZE) > count) ? count - min : BATCH_SIZE; const int offset = (first + min); - stride = ATTRIB_POINTERS.uv.stride; - ptr = (ENABLED_VERTEX_ATTRIBUTES & UV_ENABLED_FLAG) ? ATTRIB_POINTERS.uv.ptr + ((first + min) * stride) : NULL; + stride = ATTRIB_LIST.uv.stride; + ptr = (ATTRIB_LIST.enabled & UV_ENABLED_FLAG) ? ATTRIB_LIST.uv.ptr + ((first + min) * stride) : NULL; it = (Vertex*) start; if(ptr) { @@ -48,8 +47,8 @@ MAKE_FUNC(POLYMODE) } } - stride = ATTRIB_POINTERS.colour.stride; - ptr = (ENABLED_VERTEX_ATTRIBUTES & DIFFUSE_ENABLED_FLAG) ? ATTRIB_POINTERS.colour.ptr + (offset * stride) : NULL; + stride = ATTRIB_LIST.colour.stride; + ptr = (ATTRIB_LIST.enabled & DIFFUSE_ENABLED_FLAG) ? ATTRIB_LIST.colour.ptr + (offset * stride) : NULL; it = (Vertex*) start; if(ptr) { @@ -68,22 +67,22 @@ MAKE_FUNC(POLYMODE) } } - stride = ATTRIB_POINTERS.vertex.stride; - ptr = ATTRIB_POINTERS.vertex.ptr + (offset * stride); + stride = ATTRIB_LIST.vertex.stride; + ptr = ATTRIB_LIST.vertex.ptr + (offset * stride); it = (Vertex*) start; PREFETCH(ptr); for(int_fast32_t i = 0; i < loop; ++i, ++it) { PREFETCH(ptr + stride); - TransformVertex((const float*) ptr, &w, it->xyz, &it->w); + TransformVertex(((float*) ptr)[0], ((float*) ptr)[1], ((float*) ptr)[2], 1.0f, it->xyz, &it->w); PROCESS_VERTEX_FLAGS(it, min + i); ptr += stride; } start = aligned_vector_at(target->extras, min); - stride = ATTRIB_POINTERS.st.stride; - ptr = (ENABLED_VERTEX_ATTRIBUTES & ST_ENABLED_FLAG) ? ATTRIB_POINTERS.st.ptr + (offset * stride) : NULL; + stride = ATTRIB_LIST.st.stride; + ptr = (ATTRIB_LIST.enabled & ST_ENABLED_FLAG) ? ATTRIB_LIST.st.ptr + (offset * stride) : NULL; ve = (VertexExtra*) start; if(ptr) { @@ -102,8 +101,8 @@ MAKE_FUNC(POLYMODE) } } - stride = ATTRIB_POINTERS.normal.stride; - ptr = (ENABLED_VERTEX_ATTRIBUTES & NORMAL_ENABLED_FLAG) ? ATTRIB_POINTERS.normal.ptr + (offset * stride) : NULL; + stride = ATTRIB_LIST.normal.stride; + ptr = (ATTRIB_LIST.enabled & NORMAL_ENABLED_FLAG) ? ATTRIB_LIST.normal.ptr + (offset * stride) : NULL; ve = (VertexExtra*) start; if(ptr) { diff --git a/GL/error.c b/GL/error.c index 4eb180d..4fe965e 100644 --- a/GL/error.c +++ b/GL/error.c @@ -12,8 +12,31 @@ #include "private.h" -GLenum LAST_ERROR = GL_NO_ERROR; -char ERROR_FUNCTION[64] = { '\0' }; +static GLenum LAST_ERROR = GL_NO_ERROR; +static char ERROR_FUNCTION[64] = { '\0' }; + +GL_FORCE_INLINE const char* _glErrorEnumAsString(GLenum error) { + switch(error) { + case GL_INVALID_ENUM: return "GL_INVALID_ENUM"; + case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY"; + case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION"; + case GL_INVALID_VALUE: return "GL_INVALID_VALUE"; + default: + return "GL_UNKNOWN_ERROR"; + } +} + +void _glKosThrowError(GLenum error, const char *function) { + if(LAST_ERROR == GL_NO_ERROR) { + LAST_ERROR = error; + sprintf(ERROR_FUNCTION, "%s\n", function); + fprintf(stderr, "GL ERROR: %s when calling %s\n", _glErrorEnumAsString(LAST_ERROR), ERROR_FUNCTION); + } +} + +GL_FORCE_INLINE void _glKosResetError() { + LAST_ERROR = GL_NO_ERROR; +} /* Quoth the GL Spec: When an error occurs, the error flag is set to the appropriate error code diff --git a/GL/glu.c b/GL/glu.c index 717b273..9b2f48d 100644 --- a/GL/glu.c +++ b/GL/glu.c @@ -2,11 +2,11 @@ #include "private.h" /* Set the Perspective */ -void APIENTRY gluPerspective(GLfloat angle, GLfloat aspect, - GLfloat znear, GLfloat zfar) { - GLfloat fW, fH; +void APIENTRY gluPerspective(GLdouble angle, GLdouble aspect, + GLdouble znear, GLdouble zfar) { + GLdouble fW, fH; - fH = tanf(angle * (M_PI / 360.0f)) * znear; + fH = tan(angle * (M_PI / 360.0)) * znear; fW = fH * aspect; glFrustum(-fW, fW, -fH, fH, znear, zfar); diff --git a/GL/immediate.c b/GL/immediate.c index afe80c5..971d92d 100644 --- a/GL/immediate.c +++ b/GL/immediate.c @@ -12,8 +12,6 @@ #include "private.h" -extern inline GLuint _glRecalcFastPath(); - GLboolean IMMEDIATE_MODE_ACTIVE = GL_FALSE; static GLenum ACTIVE_POLYGON_MODE = GL_TRIANGLES; @@ -49,6 +47,7 @@ typedef struct __attribute__((aligned(32))) { void _glInitImmediateMode(GLuint initial_size) { aligned_vector_init(&VERTICES, sizeof(IMVertex)); aligned_vector_reserve(&VERTICES, initial_size); + IM_ATTRIBS.fast_path = GL_TRUE; IM_ATTRIBS.vertex.ptr = aligned_vector_front(&VERTICES); IM_ATTRIBS.vertex.size = 3; @@ -87,7 +86,7 @@ void APIENTRY glBegin(GLenum mode) { } void APIENTRY glColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { - IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG; + IM_ATTRIBS.enabled |= DIFFUSE_ENABLED_FLAG; COLOR[A8IDX] = (GLubyte)(a * 255.0f); COLOR[R8IDX] = (GLubyte)(r * 255.0f); @@ -96,7 +95,7 @@ void APIENTRY glColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { } void APIENTRY glColor4ub(GLubyte r, GLubyte g, GLubyte b, GLubyte a) { - IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG; + IM_ATTRIBS.enabled |= DIFFUSE_ENABLED_FLAG; COLOR[A8IDX] = a; COLOR[R8IDX] = r; @@ -105,7 +104,7 @@ void APIENTRY glColor4ub(GLubyte r, GLubyte g, GLubyte b, GLubyte a) { } void APIENTRY glColor4ubv(const GLubyte *v) { - IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG; + IM_ATTRIBS.enabled |= DIFFUSE_ENABLED_FLAG; COLOR[A8IDX] = v[3]; COLOR[R8IDX] = v[0]; @@ -114,7 +113,7 @@ void APIENTRY glColor4ubv(const GLubyte *v) { } void APIENTRY glColor4fv(const GLfloat* v) { - IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG; + IM_ATTRIBS.enabled |= DIFFUSE_ENABLED_FLAG; COLOR[B8IDX] = (GLubyte)(v[2] * 255); COLOR[G8IDX] = (GLubyte)(v[1] * 255); @@ -123,7 +122,7 @@ void APIENTRY glColor4fv(const GLfloat* v) { } void APIENTRY glColor3f(GLfloat r, GLfloat g, GLfloat b) { - IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG; + IM_ATTRIBS.enabled |= DIFFUSE_ENABLED_FLAG; COLOR[B8IDX] = (GLubyte)(b * 255.0f); COLOR[G8IDX] = (GLubyte)(g * 255.0f); @@ -132,7 +131,7 @@ void APIENTRY glColor3f(GLfloat r, GLfloat g, GLfloat b) { } void APIENTRY glColor3ub(GLubyte red, GLubyte green, GLubyte blue) { - IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG; + IM_ATTRIBS.enabled |= DIFFUSE_ENABLED_FLAG; COLOR[A8IDX] = 255; COLOR[R8IDX] = red; @@ -141,7 +140,7 @@ void APIENTRY glColor3ub(GLubyte red, GLubyte green, GLubyte blue) { } void APIENTRY glColor3ubv(const GLubyte *v) { - IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG; + IM_ATTRIBS.enabled |= DIFFUSE_ENABLED_FLAG; COLOR[A8IDX] = 255; COLOR[R8IDX] = v[0]; @@ -150,7 +149,7 @@ void APIENTRY glColor3ubv(const GLubyte *v) { } void APIENTRY glColor3fv(const GLfloat* v) { - IM_ENABLED_VERTEX_ATTRIBUTES |= DIFFUSE_ENABLED_FLAG; + IM_ATTRIBS.enabled |= DIFFUSE_ENABLED_FLAG; COLOR[A8IDX] = 255; COLOR[R8IDX] = (GLubyte)(v[0] * 255); @@ -158,30 +157,31 @@ void APIENTRY glColor3fv(const GLfloat* v) { COLOR[B8IDX] = (GLubyte)(v[2] * 255); } +typedef union punned { + GLubyte* byte; + GLfloat* flt; + uint32_t* u32; + void* vptr; + uintptr_t uptr; +} punned_t; + void APIENTRY glVertex3f(GLfloat x, GLfloat y, GLfloat z) { - IM_ENABLED_VERTEX_ATTRIBUTES |= VERTEX_ENABLED_FLAG; + IM_ATTRIBS.enabled |= VERTEX_ENABLED_FLAG; IMVertex* vert = aligned_vector_extend(&VERTICES, 1); - /* Resizing could've invalidated the pointers */ - IM_ATTRIBS.vertex.ptr = VERTICES.data; - IM_ATTRIBS.uv.ptr = IM_ATTRIBS.vertex.ptr + 12; - IM_ATTRIBS.st.ptr = IM_ATTRIBS.uv.ptr + 8; - IM_ATTRIBS.colour.ptr = IM_ATTRIBS.st.ptr + 8; - IM_ATTRIBS.normal.ptr = IM_ATTRIBS.colour.ptr + 4; - - uint32_t* dest = (uint32_t*) &vert->x; - *(dest++) = *((uint32_t*) &x); - *(dest++) = *((uint32_t*) &y); - *(dest++) = *((uint32_t*) &z); - *(dest++) = *((uint32_t*) &UV_COORD[0]); - *(dest++) = *((uint32_t*) &UV_COORD[1]); - *(dest++) = *((uint32_t*) &ST_COORD[0]); - *(dest++) = *((uint32_t*) &ST_COORD[1]); - *(dest++) = *((uint32_t*) COLOR); - *(dest++) = *((uint32_t*) &NORMAL[0]); - *(dest++) = *((uint32_t*) &NORMAL[1]); - *(dest++) = *((uint32_t*) &NORMAL[2]); + punned_t dest = { .flt = &vert->x }; + *(dest.flt++) = x; + *(dest.flt++) = y; + *(dest.flt++) = z; + *(dest.flt++) = UV_COORD[0]; + *(dest.flt++) = UV_COORD[1]; + *(dest.flt++) = ST_COORD[0]; + *(dest.flt++) = ST_COORD[1]; + *(dest.u32++) = *((uint32_t*)(void*) COLOR); + *(dest.flt++) = NORMAL[0]; + *(dest.flt++) = NORMAL[1]; + *(dest.flt++) = NORMAL[2]; } void APIENTRY glVertex3fv(const GLfloat* v) { @@ -207,11 +207,11 @@ void APIENTRY glVertex4fv(const GLfloat* v) { void APIENTRY glMultiTexCoord2fARB(GLenum target, GLfloat s, GLfloat t) { if(target == GL_TEXTURE0) { - IM_ENABLED_VERTEX_ATTRIBUTES |= UV_ENABLED_FLAG; + IM_ATTRIBS.enabled |= UV_ENABLED_FLAG; UV_COORD[0] = s; UV_COORD[1] = t; } else if(target == GL_TEXTURE1) { - IM_ENABLED_VERTEX_ATTRIBUTES |= ST_ENABLED_FLAG; + IM_ATTRIBS.enabled |= ST_ENABLED_FLAG; ST_COORD[0] = s; ST_COORD[1] = t; } else { @@ -221,7 +221,7 @@ void APIENTRY glMultiTexCoord2fARB(GLenum target, GLfloat s, GLfloat t) { } void APIENTRY glTexCoord1f(GLfloat u) { - IM_ENABLED_VERTEX_ATTRIBUTES |= UV_ENABLED_FLAG; + IM_ATTRIBS.enabled |= UV_ENABLED_FLAG; UV_COORD[0] = u; UV_COORD[1] = 0.0f; } @@ -231,7 +231,7 @@ void APIENTRY glTexCoord1fv(const GLfloat* v) { } void APIENTRY glTexCoord2f(GLfloat u, GLfloat v) { - IM_ENABLED_VERTEX_ATTRIBUTES |= UV_ENABLED_FLAG; + IM_ATTRIBS.enabled |= UV_ENABLED_FLAG; UV_COORD[0] = u; UV_COORD[1] = v; } @@ -241,7 +241,7 @@ void APIENTRY glTexCoord2fv(const GLfloat* v) { } void APIENTRY glNormal3f(GLfloat x, GLfloat y, GLfloat z) { - IM_ENABLED_VERTEX_ATTRIBUTES |= NORMAL_ENABLED_FLAG; + IM_ATTRIBS.enabled |= NORMAL_ENABLED_FLAG; NORMAL[0] = x; NORMAL[1] = y; NORMAL[2] = z; @@ -254,38 +254,22 @@ void APIENTRY glNormal3fv(const GLfloat* v) { void APIENTRY glEnd() { IMMEDIATE_MODE_ACTIVE = GL_FALSE; - GLuint* attrs = &ENABLED_VERTEX_ATTRIBUTES; - - /* Redirect attrib pointers */ - AttribPointerList stashed_attrib_pointers = ATTRIB_POINTERS; - ATTRIB_POINTERS = IM_ATTRIBS; - - GLuint prevAttrs = *attrs; - - *attrs = IM_ENABLED_VERTEX_ATTRIBUTES; - - /* Store the fast path enabled setting so we can restore it - * after drawing */ - const GLboolean fp_was_enabled = FAST_PATH_ENABLED; - -#ifndef NDEBUG - // Immediate mode should always activate the fast path - GLuint fastPathEnabled = _glRecalcFastPath(); - gl_assert(fastPathEnabled); -#else - /* If we're not debugging, set to true - we assume we haven't broken it! */ - FAST_PATH_ENABLED = GL_TRUE; -#endif + /* Resizing could've invalidated the pointers */ + IM_ATTRIBS.vertex.ptr = VERTICES.data; + IM_ATTRIBS.uv.ptr = IM_ATTRIBS.vertex.ptr + 12; + IM_ATTRIBS.st.ptr = IM_ATTRIBS.uv.ptr + 8; + IM_ATTRIBS.colour.ptr = IM_ATTRIBS.st.ptr + 8; + IM_ATTRIBS.normal.ptr = IM_ATTRIBS.colour.ptr + 4; + /* Redirect attrib state */ + AttribPointerList stashed_state = ATTRIB_LIST; + ATTRIB_LIST = IM_ATTRIBS; + glDrawArrays(ACTIVE_POLYGON_MODE, 0, aligned_vector_header(&VERTICES)->size); - ATTRIB_POINTERS = stashed_attrib_pointers; - - *attrs = prevAttrs; + ATTRIB_LIST = stashed_state; aligned_vector_clear(&VERTICES); - - FAST_PATH_ENABLED = fp_was_enabled; } void APIENTRY glRectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) { diff --git a/GL/lighting.c b/GL/lighting.c index b675a92..806ed61 100644 --- a/GL/lighting.c +++ b/GL/lighting.c @@ -58,10 +58,10 @@ void _glPrecalcLightingValues(GLuint mask) { if((mask & AMBIENT_MASK) || (mask & EMISSION_MASK) || (mask & SCENE_AMBIENT_MASK)) { GLfloat* scene_ambient = _glLightModelSceneAmbient(); - material->baseColour[0] = MATH_fmac(scene_ambient[0], material->ambient[0], material->emissive[0]); - material->baseColour[1] = MATH_fmac(scene_ambient[1], material->ambient[1], material->emissive[1]); - material->baseColour[2] = MATH_fmac(scene_ambient[2], material->ambient[2], material->emissive[2]); - material->baseColour[3] = MATH_fmac(scene_ambient[3], material->ambient[3], material->emissive[3]); + material->baseColour[0] = scene_ambient[0] * material->ambient[0] + material->emissive[0]; + material->baseColour[1] = scene_ambient[1] * material->ambient[1] + material->emissive[1]; + material->baseColour[2] = scene_ambient[2] * material->ambient[2] + material->emissive[2]; + material->baseColour[3] = scene_ambient[3] * material->ambient[3] + material->emissive[3]; } } @@ -499,14 +499,14 @@ GL_FORCE_INLINE void _glLightVertexPoint( #undef _PROCESS_COMPONENT } -void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count) { +void _glPerformLighting(Vertex* vertices, VertexExtra* extra, const uint32_t count) { GLubyte i; GLuint j; Material* material = _glActiveMaterial(); Vertex* vertex = vertices; - EyeSpaceData* data = es; + VertexExtra* data = extra; /* Calculate the colour material function once */ void (*updateColourMaterial)(const GLubyte*) = NULL; @@ -529,32 +529,29 @@ void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count } } - /* Calculate the ambient lighting and set up colour material */ + if(!_glEnabledLightCount()) { + return; + } + for(j = 0; j < count; ++j, ++vertex, ++data) { + /* Calculate the ambient lighting and set up colour material */ if(updateColourMaterial) { updateColourMaterial(vertex->bgra); } /* Copy the base colour across */ - vec4cpy(data->finalColour, material->baseColour); - } + float finalColour[4]; + vec4cpy(finalColour, material->baseColour); - if(!_glEnabledLightCount()) { - return; - } - - vertex = vertices; - data = es; - for(j = 0; j < count; ++j, ++vertex, ++data) { /* Direction to vertex in eye space */ float Vx = -vertex->xyz[0]; float Vy = -vertex->xyz[1]; float Vz = -vertex->xyz[2]; VEC3_NORMALIZE(Vx, Vy, Vz); - const float Nx = data->n[0]; - const float Ny = data->n[1]; - const float Nz = data->n[2]; + const float Nx = data->nxyz[0]; + const float Ny = data->nxyz[1]; + const float Nz = data->nxyz[2]; for(i = 0; i < MAX_GLDC_LIGHTS; ++i) { LightSource* light = _glLightAt(i); @@ -588,7 +585,7 @@ void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count if(NdotH < 0.0f) NdotH = 0.0f; _glLightVertexDirectional( - data->finalColour, + finalColour, i, LdotN, NdotH ); } else { @@ -627,17 +624,17 @@ void _glPerformLighting(Vertex* vertices, EyeSpaceData* es, const uint32_t count if(NdotH < 0.0f) NdotH = 0.0f; _glLightVertexPoint( - data->finalColour, + finalColour, i, LdotN, NdotH, att ); } } } - vertex->bgra[R8IDX] = clamp(data->finalColour[0] * 255.0f, 0, 255); - vertex->bgra[G8IDX] = clamp(data->finalColour[1] * 255.0f, 0, 255); - vertex->bgra[B8IDX] = clamp(data->finalColour[2] * 255.0f, 0, 255); - vertex->bgra[A8IDX] = clamp(data->finalColour[3] * 255.0f, 0, 255); + vertex->bgra[R8IDX] = clamp(finalColour[0] * 255.0f, 0, 255); + vertex->bgra[G8IDX] = clamp(finalColour[1] * 255.0f, 0, 255); + vertex->bgra[B8IDX] = clamp(finalColour[2] * 255.0f, 0, 255); + vertex->bgra[A8IDX] = clamp(finalColour[3] * 255.0f, 0, 255); } } diff --git a/GL/matrix.c b/GL/matrix.c index 2744cb9..683d83f 100644 --- a/GL/matrix.c +++ b/GL/matrix.c @@ -15,13 +15,12 @@ GLfloat DEPTH_RANGE_MULTIPLIER_H = (0 + 1) / 2; static Stack __attribute__((aligned(32))) MATRIX_STACKS[4]; // modelview, projection, texture static Matrix4x4 __attribute__((aligned(32))) NORMAL_MATRIX; - -Viewport VIEWPORT = { - 0, 0, 640, 480, 320.0f, 240.0f, 320.0f, 240.0f -}; +static Matrix4x4 __attribute__((aligned(32))) VIEWPORT_MATRIX; +static Matrix4x4 __attribute__((aligned(32))) PROJECTION_MATRIX; static GLenum MATRIX_MODE = GL_MODELVIEW; static GLubyte MATRIX_IDX = 0; +static GLboolean NORMAL_DIRTY, PROJECTION_DIRTY; static const Matrix4x4 __attribute__((aligned(32))) IDENTITY = { 1.0f, 0.0f, 0.0f, 0.0f, @@ -94,12 +93,28 @@ static void transpose(GLfloat* m) { swap(m[11], m[14]); } -static void recalculateNormalMatrix() { +/* When projection matrix changes, need to pre-multiply with viewport transform matrix */ +static void UpdateProjectionMatrix() { + PROJECTION_DIRTY = false; + UploadMatrix4x4(&VIEWPORT_MATRIX); + MultiplyMatrix4x4(stack_top(MATRIX_STACKS + (GL_PROJECTION & 0xF))); + DownloadMatrix4x4(&PROJECTION_MATRIX); +} + +/* When modelview matrix changes, need to re-compute normal matrix */ +static void UpdateNormalMatrix() { + NORMAL_DIRTY = false; MEMCPY4(NORMAL_MATRIX, stack_top(MATRIX_STACKS + (GL_MODELVIEW & 0xF)), sizeof(Matrix4x4)); inverse((GLfloat*) NORMAL_MATRIX); transpose((GLfloat*) NORMAL_MATRIX); } +static void OnMatrixChanged() { + if(MATRIX_MODE == GL_MODELVIEW) NORMAL_DIRTY = true; + if(MATRIX_MODE == GL_PROJECTION) PROJECTION_DIRTY = true; +} + + void APIENTRY glMatrixMode(GLenum mode) { MATRIX_MODE = mode; MATRIX_IDX = mode & 0xF; @@ -111,17 +126,26 @@ void APIENTRY glPushMatrix() { void* ret = stack_push(MATRIX_STACKS + MATRIX_IDX, top); (void) ret; assert(ret); + OnMatrixChanged(); } void APIENTRY glPopMatrix() { stack_pop(MATRIX_STACKS + MATRIX_IDX); - if(MATRIX_MODE == GL_MODELVIEW) { - recalculateNormalMatrix(); - } + OnMatrixChanged(); } void APIENTRY glLoadIdentity() { stack_replace(MATRIX_STACKS + MATRIX_IDX, IDENTITY); + OnMatrixChanged(); +} + +void GL_FORCE_INLINE _glMultMatrix(const Matrix4x4* mat) { + void* top = stack_top(MATRIX_STACKS + MATRIX_IDX); + + UploadMatrix4x4(top); + MultiplyMatrix4x4(mat); + DownloadMatrix4x4(top); + OnMatrixChanged(); } void APIENTRY glTranslatef(GLfloat x, GLfloat y, GLfloat z) { @@ -131,20 +155,7 @@ void APIENTRY glTranslatef(GLfloat x, GLfloat y, GLfloat z) { 0.0f, 0.0f, 1.0f, 0.0f, x, y, z, 1.0f }; - void* top = stack_top(MATRIX_STACKS + MATRIX_IDX); - assert(top); - - UploadMatrix4x4(top); - MultiplyMatrix4x4(&trn); - - top = stack_top(MATRIX_STACKS + MATRIX_IDX); - assert(top); - - DownloadMatrix4x4(top); - - if(MATRIX_MODE == GL_MODELVIEW) { - recalculateNormalMatrix(); - } + _glMultMatrix(&trn); } @@ -155,14 +166,7 @@ void APIENTRY glScalef(GLfloat x, GLfloat y, GLfloat z) { 0.0f, 0.0f, z, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; - - UploadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - MultiplyMatrix4x4(&scale); - DownloadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - - if(MATRIX_MODE == GL_MODELVIEW) { - recalculateNormalMatrix(); - } + _glMultMatrix(&scale); } void APIENTRY glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { @@ -174,8 +178,13 @@ void APIENTRY glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { }; float r = DEG2RAD * angle; +#ifdef __DREAMCAST__ + float s, c; + fsincos(r, &s, &c); +#else float c = cosf(r); float s = sinf(r); +#endif VEC3_NORMALIZE(x, y, z); @@ -199,13 +208,7 @@ void APIENTRY glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { rotate[M9] = yz * invc - xs; rotate[M10] = (z * z) * invc + c; - UploadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - MultiplyMatrix4x4((const Matrix4x4*) &rotate); - DownloadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - - if(MATRIX_MODE == GL_MODELVIEW) { - recalculateNormalMatrix(); - } + _glMultMatrix(&rotate); } /* Load an arbitrary matrix */ @@ -214,47 +217,39 @@ void APIENTRY glLoadMatrixf(const GLfloat *m) { memcpy(TEMP, m, sizeof(float) * 16); stack_replace(MATRIX_STACKS + MATRIX_IDX, TEMP); - - if(MATRIX_MODE == GL_MODELVIEW) { - recalculateNormalMatrix(); - } + OnMatrixChanged(); } /* Ortho */ -void APIENTRY glOrtho(GLfloat left, GLfloat right, - GLfloat bottom, GLfloat top, - GLfloat znear, GLfloat zfar) { +void APIENTRY glOrtho(GLdouble left, GLdouble right, + GLdouble bottom, GLdouble top, + GLdouble znear, GLdouble zfar) { - /* Ortho Matrix */ - Matrix4x4 OrthoMatrix __attribute__((aligned(32))) = { + Matrix4x4 ortho __attribute__((aligned(32))) = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; - OrthoMatrix[M0] = 2.0f / (right - left); - OrthoMatrix[M5] = 2.0f / (top - bottom); - OrthoMatrix[M10] = -2.0f / (zfar - znear); - OrthoMatrix[M12] = -(right + left) / (right - left); - OrthoMatrix[M13] = -(top + bottom) / (top - bottom); - OrthoMatrix[M14] = -(zfar + znear) / (zfar - znear); + ortho[M0] = 2.0f / (right - left); + ortho[M5] = 2.0f / (top - bottom); + ortho[M10] = -2.0f / (zfar - znear); + ortho[M12] = -(right + left) / (right - left); + ortho[M13] = -(top + bottom) / (top - bottom); + ortho[M14] = -(zfar + znear) / (zfar - znear); - UploadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - MultiplyMatrix4x4((const Matrix4x4*) &OrthoMatrix); - DownloadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); + _glMultMatrix(&ortho); } /* Set the GL frustum */ -void APIENTRY glFrustum(GLfloat left, GLfloat right, - GLfloat bottom, GLfloat top, - GLfloat znear, GLfloat zfar) { +void APIENTRY glFrustum(GLdouble left, GLdouble right, + GLdouble bottom, GLdouble top, + GLdouble znear, GLdouble zfar) { - /* Frustum Matrix */ - Matrix4x4 FrustumMatrix __attribute__((aligned(32))); - - MEMSET(FrustumMatrix, 0, sizeof(float) * 16); + Matrix4x4 frustum __attribute__((aligned(32))); + MEMSET(frustum, 0, sizeof(float) * 16); const float near2 = 2.0f * znear; const float A = (right + left) / (right - left); @@ -262,33 +257,25 @@ void APIENTRY glFrustum(GLfloat left, GLfloat right, const float C = -((zfar + znear) / (zfar - znear)); const float D = -((2.0f * zfar * znear) / (zfar - znear)); - FrustumMatrix[M0] = near2 / (right - left); - FrustumMatrix[M5] = near2 / (top - bottom); + frustum[M0] = near2 / (right - left); + frustum[M5] = near2 / (top - bottom); - FrustumMatrix[M8] = A; - FrustumMatrix[M9] = B; - FrustumMatrix[M10] = C; - FrustumMatrix[M11] = -1.0f; - FrustumMatrix[M14] = D; + frustum[M8] = A; + frustum[M9] = B; + frustum[M10] = C; + frustum[M11] = -1.0f; + frustum[M14] = D; - UploadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - MultiplyMatrix4x4((const Matrix4x4*) &FrustumMatrix); - DownloadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); + _glMultMatrix(&frustum); } /* Multiply the current matrix by an arbitrary matrix */ void glMultMatrixf(const GLfloat *m) { - Matrix4x4 TEMP __attribute__((aligned(32))); - MEMCPY4(TEMP, m, sizeof(Matrix4x4)); + Matrix4x4 tmp __attribute__((aligned(32))); + MEMCPY4(tmp, m, sizeof(Matrix4x4)); - UploadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - MultiplyMatrix4x4(&TEMP); - DownloadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - - if(MATRIX_MODE == GL_MODELVIEW) { - recalculateNormalMatrix(); - } + _glMultMatrix(&tmp); } /* Load an arbitrary transposed matrix */ @@ -319,55 +306,46 @@ void glLoadTransposeMatrixf(const GLfloat *m) { TEMP[M15] = m[15]; stack_replace(MATRIX_STACKS + MATRIX_IDX, TEMP); - - if(MATRIX_MODE == GL_MODELVIEW) { - recalculateNormalMatrix(); - } + OnMatrixChanged(); } /* Multiply the current matrix by an arbitrary transposed matrix */ void glMultTransposeMatrixf(const GLfloat *m) { - static Matrix4x4 TEMP __attribute__((aligned(32))); + static Matrix4x4 tmp __attribute__((aligned(32))); - TEMP[M0] = m[0]; - TEMP[M1] = m[4]; - TEMP[M2] = m[8]; - TEMP[M3] = m[12]; + tmp[M0] = m[0]; + tmp[M1] = m[4]; + tmp[M2] = m[8]; + tmp[M3] = m[12]; - TEMP[M4] = m[1]; - TEMP[M5] = m[5]; - TEMP[M6] = m[9]; - TEMP[M7] = m[13]; + tmp[M4] = m[1]; + tmp[M5] = m[5]; + tmp[M6] = m[9]; + tmp[M7] = m[13]; - TEMP[M8] = m[3]; - TEMP[M9] = m[6]; - TEMP[M10] = m[10]; - TEMP[M11] = m[14]; + tmp[M8] = m[3]; + tmp[M9] = m[6]; + tmp[M10] = m[10]; + tmp[M11] = m[14]; - TEMP[M12] = m[4]; - TEMP[M13] = m[7]; - TEMP[M14] = m[11]; - TEMP[M15] = m[15]; + tmp[M12] = m[4]; + tmp[M13] = m[7]; + tmp[M14] = m[11]; + tmp[M15] = m[15]; - UploadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - MultiplyMatrix4x4((const Matrix4x4*) &TEMP); - DownloadMatrix4x4(stack_top(MATRIX_STACKS + MATRIX_IDX)); - - if(MATRIX_MODE == GL_MODELVIEW) { - recalculateNormalMatrix(); - } + _glMultMatrix(&tmp); } /* Set the GL viewport */ void APIENTRY glViewport(GLint x, GLint y, GLsizei width, GLsizei height) { - VIEWPORT.x = x; - VIEWPORT.y = y; - VIEWPORT.width = width; - VIEWPORT.height = height; - VIEWPORT.hwidth = ((GLfloat) VIEWPORT.width) * 0.5f; - VIEWPORT.hheight = ((GLfloat) VIEWPORT.height) * 0.5f; - VIEWPORT.x_plus_hwidth = VIEWPORT.x + VIEWPORT.hwidth; - VIEWPORT.y_plus_hheight = VIEWPORT.y + VIEWPORT.hheight; + VIEWPORT_MATRIX[M0] = width * 0.5f; + VIEWPORT_MATRIX[M5] = height * -0.5f; + VIEWPORT_MATRIX[M10] = 1.0f; + VIEWPORT_MATRIX[M15] = 1.0f; + + VIEWPORT_MATRIX[M12] = x + width * 0.5f; + VIEWPORT_MATRIX[M13] = GetVideoMode()->height - (y + height * 0.5f); + PROJECTION_DIRTY = true; } /* Set the depth range */ @@ -382,7 +360,7 @@ void APIENTRY glDepthRangef(GLclampf n, GLclampf f) { DEPTH_RANGE_MULTIPLIER_H = (n + f) / 2.0f; } -void APIENTRY glDepthRange(GLclampf n, GLclampf f){ +void APIENTRY glDepthRange(GLdouble n, GLdouble f){ glDepthRangef(n,f); } @@ -394,11 +372,12 @@ static inline void vec3f_cross(const GLfloat* v1, const GLfloat* v2, GLfloat* re } GL_FORCE_INLINE void vec3f_normalize_sh4(float *v){ - float length, ilength; + float lengthSq, ilength; - ilength = MATH_fsrra(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); - length = MATH_Fast_Invert(ilength); - if (length) + lengthSq = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; + ilength = MATH_fsrra(lengthSq); + + if (lengthSq) { v[0] *= ilength; v[1] *= ilength; @@ -406,9 +385,9 @@ GL_FORCE_INLINE void vec3f_normalize_sh4(float *v){ } } -void gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, GLfloat centerx, - GLfloat centery, GLfloat centerz, GLfloat upx, GLfloat upy, - GLfloat upz) { +void gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx, + GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy, + GLdouble upz) { GLfloat m [16] __attribute__((aligned(32))); GLfloat f [3]; GLfloat u [3]; @@ -459,14 +438,17 @@ void _glMatrixLoadModelView() { } void _glMatrixLoadProjection() { - UploadMatrix4x4((const Matrix4x4*) stack_top(MATRIX_STACKS + (GL_PROJECTION & 0xF))); + if (PROJECTION_DIRTY) UpdateProjectionMatrix(); + UploadMatrix4x4(&PROJECTION_MATRIX); } void _glMatrixLoadModelViewProjection() { - UploadMatrix4x4((const Matrix4x4*) stack_top(MATRIX_STACKS + (GL_PROJECTION & 0xF))); + if (PROJECTION_DIRTY) UpdateProjectionMatrix(); + UploadMatrix4x4(&PROJECTION_MATRIX); MultiplyMatrix4x4((const Matrix4x4*) stack_top(MATRIX_STACKS + (GL_MODELVIEW & 0xF))); } void _glMatrixLoadNormal() { + if (NORMAL_DIRTY) UpdateNormalMatrix(); UploadMatrix4x4((const Matrix4x4*) &NORMAL_MATRIX); } diff --git a/GL/platforms/sh4.c b/GL/platforms/sh4.c index 2c16cdc..26d7f88 100644 --- a/GL/platforms/sh4.c +++ b/GL/platforms/sh4.c @@ -1,5 +1,7 @@ #include +#include + #include "../platform.h" #include "sh4.h" @@ -7,12 +9,11 @@ #define CLIP_DEBUG 0 #define PVR_VERTEX_BUF_SIZE 2560 * 256 +#define PVR_OPB_COUNT 2 #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) -#define SQ_BASE_ADDRESS (void*) 0xe0000000 - GL_FORCE_INLINE bool glIsVertex(const float flags) { return flags == GPU_CMD_VERTEX_EOL || flags == GPU_CMD_VERTEX; @@ -29,18 +30,10 @@ void InitGPU(_Bool autosort, _Bool fsaa) { PVR_VERTEX_BUF_SIZE, /* Vertex buffer size */ 0, /* No DMA */ fsaa, /* No FSAA */ - (autosort) ? 0 : 1 /* Disable translucent auto-sorting to match traditional GL */ + (autosort) ? 0 : 1, /* Disable translucent auto-sorting to match traditional GL */ + PVR_OPB_COUNT /* Number of tile object pointer overflow bins. */ }; - /* Newer versions of KOS add an extra parameter to pvr_init_params_t - * called opb_overflow_count. To remain compatible we set that last - * parameter to something only if it exists */ - const int opb_offset = offsetof(pvr_init_params_t, autosort_disabled) + 4; - if(sizeof(pvr_init_params_t) > opb_offset) { - int* opb_count = (int*)(((char*)¶ms) + opb_offset); - *opb_count = 2; // Two should be enough for anybody.. right? - } - pvr_init(¶ms); #ifndef _arch_sub_naomi @@ -60,69 +53,44 @@ void InitGPU(_Bool autosort, _Bool fsaa) { #endif } -void SceneBegin() { - pvr_wait_ready(); - pvr_scene_begin(); -} - -void SceneListBegin(GPUList list) { - pvr_list_begin(list); -} - GL_FORCE_INLINE float _glFastInvert(float x) { - return (1.f / __builtin_sqrtf(x * x)); + return (1.0f / __builtin_sqrtf(x * x)); } -GL_FORCE_INLINE void _glPerspectiveDivideVertex(Vertex* vertex, const float h) { +GL_FORCE_INLINE void _glPerspectiveDivideVertex(Vertex* vertex, int count) { TRACE(); - const float f = _glFastInvert(vertex->w); + for(int v = 0; v < count; ++v) { + const float f = _glFastInvert(vertex[v].w); - /* Convert to NDC and apply viewport */ - vertex->xyz[0] = (vertex->xyz[0] * f * 320) + 320; - vertex->xyz[1] = (vertex->xyz[1] * f * -240) + 240; + /* Convert to screenspace */ + /* (note that vertices have already been viewport transformed) */ + vertex[v].xyz[0] *= f; + vertex[v].xyz[1] *= f; - /* Orthographic projections need to use invZ otherwise we lose - the depth information. As w == 1, and clip-space range is -w to +w - we add 1.0 to the Z to bring it into range. We add a little extra to - avoid a divide by zero. - */ - if(vertex->w == 1.0f) { - vertex->xyz[2] = _glFastInvert(1.0001f + vertex->xyz[2]); - } else { - vertex->xyz[2] = f; + /* Orthographic projections need to use invZ otherwise we lose + the depth information. As w == 1, and clip-space range is -w to +w + we add 1.0 to the Z to bring it into range. We add a little extra to + avoid a divide by zero. + */ + if(vertex[v].w == 1.0f) { + vertex[v].xyz[2] = _glFastInvert(1.0001f + vertex[v].xyz[2]); + } else { + vertex[v].xyz[2] = f; + } } } +static uintptr_t sq_dest_addr = 0; -volatile uint32_t *sq = SQ_BASE_ADDRESS; - -static inline void _glFlushBuffer() { - TRACE(); - - /* Wait for both store queues to complete */ - sq = (uint32_t*) 0xe0000000; - sq[0] = sq[8] = 0; -} - -static inline void _glPushHeaderOrVertex(Vertex* v) { +static inline void _glPushHeaderOrVertex(Vertex* v, size_t count) { TRACE(); #if CLIP_DEBUG fprintf(stderr, "{%f, %f, %f, %f}, // %x (%x)\n", v->xyz[0], v->xyz[1], v->xyz[2], v->w, v->flags, v); #endif - uint32_t* s = (uint32_t*) v; - sq[0] = *(s++); - sq[1] = *(s++); - sq[2] = *(s++); - sq[3] = *(s++); - sq[4] = *(s++); - sq[5] = *(s++); - sq[6] = *(s++); - sq[7] = *(s++); - __asm__("pref @%0" : : "r"(sq)); - sq += 8; + sq_fast_cpy((void *)sq_dest_addr, v, count); } static inline void _glClipEdge(const Vertex* const v1, const Vertex* const v2, Vertex* vout) { @@ -150,7 +118,6 @@ static inline void _glClipEdge(const Vertex* const v1, const Vertex* const v2, V #define SPAN_SORT_CFG 0x005F8030 static volatile uint32_t* PVR_LMMODE0 = (uint32_t*) 0xA05F6884; static volatile uint32_t *PVR_LMMODE1 = (uint32_t*) 0xA05F6888; -static volatile uint32_t *QACR = (uint32_t*) 0xFF000038; enum Visible { NONE_VISIBLE = 0, @@ -175,17 +142,12 @@ void SceneListSubmit(Vertex* vertices, int n) { return; } - const float h = GetVideoMode()->height; - PVR_SET(SPAN_SORT_CFG, 0x0); //Set PVR DMA registers *PVR_LMMODE0 = 0; *PVR_LMMODE1 = 0; - //Set QACR registers - QACR[1] = QACR[0] = 0x11; - #if CLIP_DEBUG fprintf(stderr, "----\n"); @@ -210,16 +172,15 @@ void SceneListSubmit(Vertex* vertices, int n) { do { queued_vertex = &qv; *queued_vertex = *(v); } while(0) #define SUBMIT_QUEUED_VERTEX(sflags) \ - do { if(queued_vertex) { queued_vertex->flags = (sflags); _glPushHeaderOrVertex(queued_vertex); queued_vertex = NULL; } } while(0) + do { if(queued_vertex) { queued_vertex->flags = (sflags); _glPushHeaderOrVertex(queued_vertex, 1); queued_vertex = NULL; } } while(0) int visible_mask = 0; - - sq = SQ_BASE_ADDRESS; + sq_dest_addr = (uintptr_t)SQ_MASK_DEST(PVR_TA_INPUT); Vertex* v0 = vertices; for(int i = 0; i < n - 1; ++i, ++v0) { if(is_header(v0)) { - _glPushHeaderOrVertex(v0); + _glPushHeaderOrVertex(v0, 1); visible_mask = 0; continue; } @@ -229,7 +190,7 @@ void SceneListSubmit(Vertex* vertices, int n) { assert(!is_header(v1)); - // We are trailing if we're on the penultimate vertex, or the next but one vertex is + // We are trailing if we're on the penultimate vertex, or the next but one vertex is // an EOL, or v1 is an EOL (FIXME: possibly unnecessary and coverted by the other case?) bool is_trailing = (v1->flags == GPU_CMD_VERTEX_EOL) || ((v2) ? is_header(v2) : true); @@ -239,25 +200,21 @@ void SceneListSubmit(Vertex* vertices, int n) { // If the last triangle was all visible, we need // to submit the last two vertices, any clipped triangles - // would've + // would've if(visible_mask == ALL_VISIBLE) { SUBMIT_QUEUED_VERTEX(qv.flags); - _glPerspectiveDivideVertex(v0, h); - _glPushHeaderOrVertex(v0); - + _glPerspectiveDivideVertex(v0, 2); v1->flags = GPU_CMD_VERTEX_EOL; - - _glPerspectiveDivideVertex(v1, h); - _glPushHeaderOrVertex(v1); + _glPushHeaderOrVertex(v0, 2); } else { - // If the previous triangle wasn't all visible, and we + // If the previous triangle wasn't all visible, and we // queued a vertex - we force it to be EOL and submit SUBMIT_QUEUED_VERTEX(GPU_CMD_VERTEX_EOL); } i++; - v0++; + v0++; visible_mask = 0; continue; } @@ -285,7 +242,7 @@ void SceneListSubmit(Vertex* vertices, int n) { switch(visible_mask) { case ALL_VISIBLE: - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0, 1); QUEUE_VERTEX(v0); break; case NONE_VISIBLE: @@ -298,14 +255,11 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v2, v0, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(v0, h); - _glPushHeaderOrVertex(v0); + _glPerspectiveDivideVertex(v0, 1); + _glPushHeaderOrVertex(v0, 1); - _glPerspectiveDivideVertex(a, h); - _glPushHeaderOrVertex(a); - - _glPerspectiveDivideVertex(b, h); - _glPushHeaderOrVertex(b); + _glPerspectiveDivideVertex(a, 2); + _glPushHeaderOrVertex(a, 2); QUEUE_VERTEX(b); break; @@ -318,13 +272,11 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v1, v2, b); b->flags = v2->flags; - _glPerspectiveDivideVertex(a, h); - _glPushHeaderOrVertex(a); + _glPerspectiveDivideVertex(a, 3); + _glPushHeaderOrVertex(a, 1); - _glPerspectiveDivideVertex(c, h); - _glPushHeaderOrVertex(c); + _glPushHeaderOrVertex(c, 1); - _glPerspectiveDivideVertex(b, h); QUEUE_VERTEX(b); break; case THIRD_VISIBLE: @@ -336,14 +288,9 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v1, v2, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(a, h); - //_glPushHeaderOrVertex(a); - _glPushHeaderOrVertex(a); + _glPerspectiveDivideVertex(a, 3); + _glPushHeaderOrVertex(a, 2); - _glPerspectiveDivideVertex(b, h); - _glPushHeaderOrVertex(b); - - _glPerspectiveDivideVertex(c, h); QUEUE_VERTEX(c); break; case FIRST_AND_SECOND_VISIBLE: @@ -352,20 +299,17 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v2, v0, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(v0, h); - _glPushHeaderOrVertex(v0); + _glPerspectiveDivideVertex(v0, 1); + _glPushHeaderOrVertex(v0, 1); _glClipEdge(v1, v2, a); a->flags = v2->flags; - _glPerspectiveDivideVertex(c, h); - _glPushHeaderOrVertex(c); + _glPerspectiveDivideVertex(a, 3); - _glPerspectiveDivideVertex(b, h); - _glPushHeaderOrVertex(b); + _glPushHeaderOrVertex(c, 1); - _glPerspectiveDivideVertex(a, h); - _glPushHeaderOrVertex(c); + _glPushHeaderOrVertex(b, 2); QUEUE_VERTEX(a); break; @@ -379,17 +323,13 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v2, v0, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(a, h); - _glPushHeaderOrVertex(a); + _glPerspectiveDivideVertex(a, 4); + _glPushHeaderOrVertex(a, 1); - _glPerspectiveDivideVertex(c, h); - _glPushHeaderOrVertex(c); + _glPushHeaderOrVertex(c, 1); - _glPerspectiveDivideVertex(b, h); - _glPushHeaderOrVertex(b); - _glPushHeaderOrVertex(c); + _glPushHeaderOrVertex(b, 2); - _glPerspectiveDivideVertex(d, h); QUEUE_VERTEX(d); break; case FIRST_AND_THIRD_VISIBLE: @@ -402,16 +342,16 @@ void SceneListSubmit(Vertex* vertices, int n) { _glClipEdge(v1, v2, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(v0, h); - _glPushHeaderOrVertex(v0); + _glPerspectiveDivideVertex(v0, 1); + _glPushHeaderOrVertex(v0, 1); - _glPerspectiveDivideVertex(a, h); - _glPushHeaderOrVertex(a); + _glPerspectiveDivideVertex(a, 3); + _glPushHeaderOrVertex(a, 1); - _glPerspectiveDivideVertex(c, h); - _glPushHeaderOrVertex(c); - _glPerspectiveDivideVertex(b, h); - _glPushHeaderOrVertex(b); + _glPushHeaderOrVertex(c, 1); + + _glPushHeaderOrVertex(b, 1); + QUEUE_VERTEX(c); break; default: @@ -421,7 +361,19 @@ void SceneListSubmit(Vertex* vertices, int n) { SUBMIT_QUEUED_VERTEX(GPU_CMD_VERTEX_EOL); - _glFlushBuffer(); + sq_wait(); +} + +void SceneBegin() { + pvr_wait_ready(); + pvr_scene_begin(); +} + +static pvr_dr_state_t dr_state; +void SceneListBegin(GPUList list) { + pvr_list_begin(list); + /* Direct rendering auto acquires/releases store queue */ + pvr_dr_init(&dr_state); } void SceneListFinish() { diff --git a/GL/platforms/sh4.h b/GL/platforms/sh4.h index 46c3513..c91b34c 100644 --- a/GL/platforms/sh4.h +++ b/GL/platforms/sh4.h @@ -10,8 +10,6 @@ #include "../types.h" #include "../private.h" -#include "sh4_math.h" - #ifndef NDEBUG #define PERF_WARNING(msg) printf("[PERF] %s\n", msg) #else @@ -24,6 +22,42 @@ #define GL_FORCE_INLINE static GL_INLINE_DEBUG #endif + +// ---- sh4_math.h - SH7091 Math Module ---- +// +// This file is part of the DreamHAL project, a hardware abstraction library +// primarily intended for use on the SH7091 found in hardware such as the SEGA +// Dreamcast game console. +// +// This math module is hereby released into the public domain in the hope that it +// may prove useful. Now go hit 60 fps! :) +// +// --Moopthehedgehog + +// 1/sqrt(x) +GL_FORCE_INLINE float MATH_fsrra(float x) +{ + asm volatile ("fsrra %[one_div_sqrt]\n" + : [one_div_sqrt] "+f" (x) // outputs, "+" means r/w + : // no inputs + : // no clobbers + ); + + return x; +} + +// 1/x = 1 / sqrt(x^2) +GL_FORCE_INLINE float MATH_Fast_Invert(float x) +{ + int neg = x < 0.0f; + + x = MATH_fsrra(x * x); + + if (neg) x = -x; + return x; +} +// end of ---- sh4_math.h ---- + #define PREFETCH(addr) __builtin_prefetch((addr)) GL_FORCE_INLINE void* memcpy_fast(void *dest, const void *src, size_t len) { @@ -69,7 +103,7 @@ GL_FORCE_INLINE void* memcpy_fast(void *dest, const void *src, size_t len) { #define MEMCPY4(dst, src, bytes) memcpy_fast(dst, src, bytes) -#define MEMSET4(dst, v, size) memset4((dst), (v), (size)) +#define MEMSET4(dst, v, size) memset((dst), (v), (size)) #define VEC3_NORMALIZE(x, y, z) vec3f_normalize((x), (y), (z)) #define VEC3_LENGTH(x, y, z, l) vec3f_length((x), (y), (z), (l)) @@ -106,15 +140,14 @@ inline void TransformVec4(float* x) { } -GL_FORCE_INLINE void TransformVertex(const float* xyz, const float* w, float* oxyz, float* ow) { - register float __x __asm__("fr12") = (xyz[0]); - register float __y __asm__("fr13") = (xyz[1]); - register float __z __asm__("fr14") = (xyz[2]); - register float __w __asm__("fr15") = (*w); +GL_FORCE_INLINE void TransformVertex(float x, float y, float z, float w, float* oxyz, float* ow) { + register float __x __asm__("fr4") = x; + register float __y __asm__("fr5") = y; + register float __z __asm__("fr6") = z; + register float __w __asm__("fr7") = w; __asm__ __volatile__( - "fldi1 fr15\n" - "ftrv xmtrx,fv12\n" + "ftrv xmtrx,fv4\n" : "=f" (__x), "=f" (__y), "=f" (__z), "=f" (__w) : "0" (__x), "1" (__y), "2" (__z), "3" (__w) ); @@ -125,28 +158,6 @@ GL_FORCE_INLINE void TransformVertex(const float* xyz, const float* w, float* ox *ow = __w; } -static inline void TransformVertices(Vertex* vertices, const int count) { - Vertex* it = vertices; - for(int i = 0; i < count; ++i, ++it) { - register float __x __asm__("fr12") = (it->xyz[0]); - register float __y __asm__("fr13") = (it->xyz[1]); - register float __z __asm__("fr14") = (it->xyz[2]); - register float __w __asm__("fr15") = (it->w); - - __asm__ __volatile__( - "fldi1 fr15\n" - "ftrv xmtrx,fv12\n" - : "=f" (__x), "=f" (__y), "=f" (__z), "=f" (__w) - : "0" (__x), "1" (__y), "2" (__z), "3" (__w) - ); - - it->xyz[0] = __x; - it->xyz[1] = __y; - it->xyz[2] = __z; - it->w = __w; - } -} - void InitGPU(_Bool autosort, _Bool fsaa); static inline size_t GPUMemoryAvailable() { diff --git a/GL/platforms/sh4_math.h b/GL/platforms/sh4_math.h deleted file mode 100644 index 4dbf727..0000000 --- a/GL/platforms/sh4_math.h +++ /dev/null @@ -1,2139 +0,0 @@ -// ---- sh4_math.h - SH7091 Math Module ---- -// -// Version 1.1.3 -// -// This file is part of the DreamHAL project, a hardware abstraction library -// primarily intended for use on the SH7091 found in hardware such as the SEGA -// Dreamcast game console. -// -// This math module is hereby released into the public domain in the hope that it -// may prove useful. Now go hit 60 fps! :) -// -// --Moopthehedgehog -// - -// Notes: -// - GCC 4 users have a different return type for the fsca functions due to an -// internal compiler error regarding complex numbers; no issue under GCC 9.2.0 -// - Using -m4 instead of -m4-single-only completely breaks the matrix and -// vector operations -// - Function inlining must be enabled and not blocked by compiler options such -// as -ffunction-sections, as blocking inlining will result in significant -// performance degradation for the vector and matrix functions employing a -// RETURN_VECTOR_STRUCT return type. I have added compiler hints and attributes -// "static inline __attribute__((always_inline))" to mitigate this, so in most -// cases the functions should be inlined regardless. If in doubt, check the -// compiler asm output! -// - -#ifndef __SH4_MATH_H_ -#define __SH4_MATH_H_ - -#define GNUC_FSCA_ERROR_VERSION 4 - -// -// Fast SH4 hardware math functions -// -// -// High-accuracy users beware, the fsrra functions have an error of +/- 2^-21 -// per http://www.shared-ptr.com/sh_insns.html -// - -//============================================================================== -// Definitions -//============================================================================== -// -// Structures, useful definitions, and reference comments -// - -// Front matrix format: -// -// FV0 FV4 FV8 FV12 -// --- --- --- ---- -// [ fr0 fr4 fr8 fr12 ] -// [ fr1 fr5 fr9 fr13 ] -// [ fr2 fr6 fr10 fr14 ] -// [ fr3 fr7 fr11 fr15 ] -// -// Back matrix, XMTRX, is similar, although it has no FVn vector groups: -// -// [ xf0 xf4 xf8 xf12 ] -// [ xf1 xf5 xf9 xf13 ] -// [ xf2 xf6 xf10 xf14 ] -// [ xf3 xf7 xf11 xf15 ] -// - -typedef struct __attribute__((aligned(32))) { - float fr0; - float fr1; - float fr2; - float fr3; - float fr4; - float fr5; - float fr6; - float fr7; - float fr8; - float fr9; - float fr10; - float fr11; - float fr12; - float fr13; - float fr14; - float fr15; -} ALL_FLOATS_STRUCT; - -// Return structs should be defined locally so that GCC optimizes them into -// register usage instead of memory accesses. -typedef struct { - float z1; - float z2; - float z3; - float z4; -} RETURN_VECTOR_STRUCT; - -#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION -typedef struct { - float sine; - float cosine; -} RETURN_FSCA_STRUCT; -#endif - -// Identity Matrix -// -// FV0 FV4 FV8 FV12 -// --- --- --- ---- -// [ 1 0 0 0 ] -// [ 0 1 0 0 ] -// [ 0 0 1 0 ] -// [ 0 0 0 1 ] -// - -static const ALL_FLOATS_STRUCT MATH_identity_matrix = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; - -// Constants -#define MATH_pi 3.14159265358979323846264338327950288419716939937510f -#define MATH_e 2.71828182845904523536028747135266249775724709369995f -#define MATH_phi 1.61803398874989484820458683436563811772030917980576f - -//============================================================================== -// Basic math functions -//============================================================================== -// -// The following functions are available. -// Please see their definitions for other usage info, otherwise they may not -// work for you. -// -/* - // |x| - float MATH_fabs(float x) - - // sqrt(x) - float MATH_fsqrt(float x) - - // a*b+c - float MATH_fmac(float a, float b, float c) - - // a*b-c - float MATH_fmac_Dec(float a, float b, float c) - - // fminf() - return the min of two floats - // This doesn't check for NaN - float MATH_Fast_Fminf(float a, float b) - - // fmaxf() - return the max of two floats - // This doesn't check for NaN - float MATH_Fast_Fmaxf(float a, float b) - - // Fast floorf() - return the nearest integer <= x as a float - // This doesn't check for NaN - float MATH_Fast_Floorf(float x) - - // Fast ceilf() - return the nearest integer >= x as a float - // This doesn't check for NaN - float MATH_Fast_Ceilf(float x) - - // Very fast floorf() - return the nearest integer <= x as a float - // Inspired by a cool trick I came across here: - // https://www.codeproject.com/Tips/700780/Fast-floor-ceiling-functions - // This doesn't check for NaN - float MATH_Very_Fast_Floorf(float x) - - // Very fast ceilf() - return the nearest integer >= x as a float - // Inspired by a cool trick I came across here: - // https://www.codeproject.com/Tips/700780/Fast-floor-ceiling-functions - // This doesn't check for NaN - float MATH_Very_Fast_Ceilf(float x) -*/ - -// |x| -// This one works on ARM and x86, too! -static inline __attribute__((always_inline)) float MATH_fabs(float x) -{ - asm volatile ("fabs %[floatx]\n" - : [floatx] "+f" (x) // outputs, "+" means r/w - : // no inputs - : // no clobbers - ); - - return x; -} - -// sqrt(x) -// This one works on ARM and x86, too! -// NOTE: There is a much faster version (MATH_Fast_Sqrt()) in the fsrra section of -// this file. Chances are you probably want that one. -static inline __attribute__((always_inline)) float MATH_fsqrt(float x) -{ - asm volatile ("fsqrt %[floatx]\n" - : [floatx] "+f" (x) // outputs, "+" means r/w - : // no inputs - : // no clobbers - ); - - return x; -} - -// a*b+c -static inline __attribute__((always_inline)) float MATH_fmac(float a, float b, float c) -{ - asm volatile ("fmac fr0, %[floatb], %[floatc]\n" - : [floatc] "+f" (c) // outputs, "+" means r/w - : "w" (a), [floatb] "f" (b) // inputs - : // no clobbers - ); - - return c; -} - -// a*b-c -static inline __attribute__((always_inline)) float MATH_fmac_Dec(float a, float b, float c) -{ - asm volatile ("fneg %[floatc]\n\t" - "fmac fr0, %[floatb], %[floatc]\n" - : [floatc] "+&f" (c) // outputs, "+" means r/w, "&" means it's written to before all inputs are consumed - : "w" (a), [floatb] "f" (b) // inputs - : // no clobbers - ); - - return c; -} - -// Fast fminf() - return the min of two floats -// This doesn't check for NaN -static inline __attribute__((always_inline)) float MATH_Fast_Fminf(float a, float b) -{ - float output_float; - - asm volatile ( - "fcmp/gt %[floata], %[floatb]\n\t" // b > a (NaN evaluates to !GT; 0 -> T) - "bt.s 1f\n\t" // yes, a is smaller - " fmov %[floata], %[float_out]\n\t" // so return a - "fmov %[floatb], %[float_out]\n" // no, either b is smaller or they're equal and it doesn't matter - "1:\n" - : [float_out] "=&f" (output_float) // outputs - : [floata] "f" (a), [floatb] "f" (b) // inputs - : "t" // clobbers - ); - - return output_float; -} - -// Fast fmaxf() - return the max of two floats -// This doesn't check for NaN -static inline __attribute__((always_inline)) float MATH_Fast_Fmaxf(float a, float b) -{ - float output_float; - - asm volatile ( - "fcmp/gt %[floata], %[floatb]\n\t" // b > a (NaN evaluates to !GT; 0 -> T) - "bt.s 1f\n\t" // yes, a is smaller - " fmov %[floatb], %[float_out]\n\t" // so return b - "fmov %[floata], %[float_out]\n" // no, either a is bigger or they're equal and it doesn't matter - "1:\n" - : [float_out] "=&f" (output_float) // outputs - : [floata] "f" (a), [floatb] "f" (b) // inputs - : "t" // clobbers - ); - - return output_float; -} - -// Fast floorf() - return the nearest integer <= x as a float -// This doesn't check for NaN -static inline __attribute__((always_inline)) float MATH_Fast_Floorf(float x) -{ - float output_float; - - // To hold -1.0f - float minus_one; - - asm volatile ( - "fldi1 %[minus_1]\n\t" - "fneg %[minus_1]\n\t" - "fcmp/gt %[minus_1], %[floatx]\n\t" // x >= 0 - "ftrc %[floatx], fpul\n\t" // convert float to int - "bt.s 1f\n\t" - " float fpul, %[float_out]\n\t" // convert int to float - "fadd %[minus_1], %[float_out]\n" // if input x < 0, subtract 1.0 - "1:\n" - : [minus_1] "=&f" (minus_one), [float_out] "=f" (output_float) - : [floatx] "f" (x) - : "fpul", "t" - ); - - return output_float; -} - -// Fast ceilf() - return the nearest integer >= x as a float -// This doesn't check for NaN -static inline __attribute__((always_inline)) float MATH_Fast_Ceilf(float x) -{ - float output_float; - - // To hold 0.0f and 1.0f - float zero_one; - - asm volatile ( - "fldi0 %[zero_1]\n\t" - "fcmp/gt %[zero_1], %[floatx]\n\t" // x > 0 - "ftrc %[floatx], fpul\n\t" // convert float to int - "bf.s 1f\n\t" - " float fpul, %[float_out]\n\t" // convert int to float - "fldi1 %[zero_1]\n\t" - "fadd %[zero_1], %[float_out]\n" // if input x > 0, add 1.0 - "1:\n" - : [zero_1] "=&f" (zero_one), [float_out] "=f" (output_float) - : [floatx] "f" (x) - : "fpul", "t" - ); - - return output_float; -} - -// Very fast floorf() - return the nearest integer <= x as a float -// Inspired by a cool trick I came across here: -// https://www.codeproject.com/Tips/700780/Fast-floor-ceiling-functions -// This doesn't check for NaN -static inline __attribute__((always_inline)) float MATH_Very_Fast_Floorf(float x) -{ - float output_float; - unsigned int scratch_reg; - unsigned int scratch_reg2; - - // 0x4f000000 == 2^31 in float -- 0x4f << 24 is INT_MAX + 1.0f - // 0x80000000 == -2^31 == INT_MIN == -(INT_MAX + 1.0f) - - // floor = (float)( (int)(x + (float)2^31) - 2^31) - - asm volatile ( - "mov #0x4f, %[scratch]\n\t" // Build float INT_MAX + 1 as a float using only regs (EX) - "shll16 %[scratch]\n\t" // (EX) - "shll8 %[scratch]\n\t" // (EX) - "lds %[scratch], fpul\n\t" // move float INT_MAX + 1 to float regs (LS) - "mov #1, %[scratch2]\n\t" // Build INT_MIN from scratch in parallel (EX) - "fsts fpul, %[float_out]\n\t" // (LS) - "fadd %[floatx], %[float_out]\n\t" // float-add float INT_MAX + 1 to x (FE) - "rotr %[scratch2]\n\t" // rotate the 1 in bit 0 from LSB to MSB for INT_MIN, clobber T (EX) - "ftrc %[float_out], fpul\n\t" // convert float to int (FE) -- ftrc -> sts is special combo - "sts fpul, %[scratch]\n\t" // move back to int regs (LS) - "add %[scratch2], %[scratch]\n\t" // Add INT_MIN to int (EX) - "lds %[scratch], fpul\n\t" // (LS) -- lds -> float is a special combo - "float fpul, %[float_out]\n" // convert back to float (FE) - : [scratch] "=&r" (scratch_reg), [scratch2] "=&r" (scratch_reg2), [float_out] "=&f" (output_float) - : [floatx] "f" (x) - : "fpul", "t" - ); - - return output_float; -} - -// Very fast ceilf() - return the nearest integer >= x as a float -// Inspired by a cool trick I came across here: -// https://www.codeproject.com/Tips/700780/Fast-floor-ceiling-functions -// This doesn't check for NaN -static inline __attribute__((always_inline)) float MATH_Very_Fast_Ceilf(float x) -{ - float output_float; - unsigned int scratch_reg; - unsigned int scratch_reg2; - - // 0x4f000000 == 2^31 in float -- 0x4f << 24 is INT_MAX + 1.0f - // 0x80000000 == -2^31 == INT_MIN == -(INT_MAX + 1.0f) - - // Ceiling is the inverse of floor such that f^-1(x) = -f(-x) - // To make very fast ceiling have as wide a range as very fast floor, - // use this property to subtract x from INT_MAX + 1 and get the negative of the - // ceiling, and then negate the final output. This allows ceiling to use - // -2^31 and have the same range as very fast floor. - - // Given: - // floor = (float)( (int)(x + (float)2^31) - 2^31 ) - // We can do: - // ceiling = -( (float)( (int)((float)2^31 - x) - 2^31 ) ) - // or (slower on SH4 since 'fneg' is faster than 'neg'): - // ceiling = (float) -( (int)((float)2^31 - x) - 2^31 ) - // Since mathematically these functions are related by f^-1(x) = -f(-x). - - asm volatile ( - "mov #0x4f, %[scratch]\n\t" // Build float INT_MAX + 1 as a float using only regs (EX) - "shll16 %[scratch]\n\t" // (EX) - "shll8 %[scratch]\n\t" // (EX) - "lds %[scratch], fpul\n\t" // move float INT_MAX + 1 to float regs (LS) - "mov #1, %[scratch2]\n\t" // Build INT_MIN from scratch in parallel (EX) - "fsts fpul, %[float_out]\n\t" // (LS) - "fsub %[floatx], %[float_out]\n\t" // float-sub x from float INT_MAX + 1 (FE) - "rotr %[scratch2]\n\t" // rotate the 1 in bit 0 from LSB to MSB for INT_MIN, clobber T (EX) - "ftrc %[float_out], fpul\n\t" // convert float to int (FE) -- ftrc -> sts is special combo - "sts fpul, %[scratch]\n\t" // move back to int regs (LS) - "add %[scratch2], %[scratch]\n\t" // Add INT_MIN to int (EX) - "lds %[scratch], fpul\n\t" // (LS) -- lds -> float is a special combo - "float fpul, %[float_out]\n\t" // convert back to float (FE) - "fneg %[float_out]\n" - : [scratch] "=&r" (scratch_reg), [scratch2] "=&r" (scratch_reg2), [float_out] "=&f" (output_float) - : [floatx] "f" (x) - : "fpul", "t" - ); - - return output_float; -} - -//============================================================================== -// Fun with fsrra, which does 1/sqrt(x) in one cycle -//============================================================================== -// -// Error of 'fsrra' is +/- 2^-21 per http://www.shared-ptr.com/sh_insns.html -// -// The following functions are available. -// Please see their definitions for other usage info, otherwise they may not -// work for you. -// -/* - // 1/sqrt(x) - float MATH_fsrra(float x) - - // 1/x - float MATH_Fast_Invert(float x) - - // A faster divide than the 'fdiv' instruction - float MATH_Fast_Divide(float numerator, float denominator) - - // A faster square root then the 'fsqrt' instruction - float MATH_Fast_Sqrt(float x) - - // Standard, accurate, and slow float divide. Use this if MATH_Fast_Divide() gives you issues. - float MATH_Slow_Divide(float numerator, float denominator) -*/ - -// 1/sqrt(x) -static inline __attribute__((always_inline)) float MATH_fsrra(float x) -{ - asm volatile ("fsrra %[one_div_sqrt]\n" - : [one_div_sqrt] "+f" (x) // outputs, "+" means r/w - : // no inputs - : // no clobbers - ); - - return x; -} - -// 1/x -// 1.0f / sqrt(x^2) -static inline __attribute__((always_inline)) float MATH_Fast_Invert(float x) -{ - int neg = 0; - - if(x < 0.0f) - { - neg = 1; - } - - x = MATH_fsrra(x*x); // 1.0f / sqrt(x^2) - - if(neg) - { - return -x; - } - else - { - return x; - } -} - -// It's faster to do this than to use 'fdiv'. -// Only fdiv can do doubles, however. -// Of course, not having to divide at all is generally the best way to go. :P -static inline __attribute__((always_inline)) float MATH_Fast_Divide(float numerator, float denominator) -{ - denominator = MATH_Fast_Invert(denominator); - return numerator * denominator; -} - -// fast sqrt(x) -// Crazy thing: invert(fsrra(x)) is actually about 3x faster than fsqrt. -static inline __attribute__((always_inline)) float MATH_Fast_Sqrt(float x) -{ - return MATH_Fast_Invert(MATH_fsrra(x)); -} - -// Standard, accurate, and slow float divide. Use this if MATH_Fast_Divide() gives you issues. -// This DOES work on negatives. -static inline __attribute__((always_inline)) float MATH_Slow_Divide(float numerator, float denominator) -{ - asm volatile ("fdiv %[div_denom], %[div_numer]\n" - : [div_numer] "+f" (numerator) // outputs, "+" means r/w - : [div_denom] "f" (denominator) // inputs - : // clobbers - ); - - return numerator; -} - -//============================================================================== -// Fun with fsca, which does simultaneous sine and cosine in 3 cycles -//============================================================================== -// -// NOTE: GCC 4.7 has a bug that prevents it from working with fsca and complex -// numbers in m4-single-only mode, so GCC 4 users will get a RETURN_FSCA_STRUCT -// instead of a _Complex float. This may be much slower in some instances. -// -// VERY IMPORTANT USAGE INFORMATION (sine and cosine functions): -// -// Due to the nature in which the fsca instruction behaves, you MUST do the -// following in your code to get sine and cosine from these functions: -// -// _Complex float sine_cosine = [Call the fsca function here] -// float sine_value = __real__ sine_cosine; -// float cosine_value = __imag__ sine_cosine; -// Your output is now in sine_value and cosine_value. -// -// This is necessary because fsca outputs both sine and cosine simultaneously -// and uses a double register to do so. The fsca functions do not actually -// return a double--they return two floats--and using a complex float here is -// just a bit of hacking the C language to make GCC do something that's legal in -// assembly according to the SH4 calling convention (i.e. multiple return values -// stored in floating point registers FR0-FR3). This is better than using a -// struct of floats for optimization purposes--this will operate at peak -// performance even at -O0, whereas a struct will not be fast at low -// optimization levels due to memory accesses. -// -// Technically you may be able to use the complex return values as a complex -// number if you wanted to, but that's probably not what you're after and they'd -// be flipped anyways (in mathematical convention, sine is the imaginary part). -// - -// Notes: -// - From http://www.shared-ptr.com/sh_insns.html: -// The input angle is specified as a signed fraction in twos complement. -// The result of sin and cos is a single-precision floating-point number. -// 0x7FFFFFFF to 0x00000001: 360×2^15−360/2^16 to 360/2^16 degrees -// 0x00000000: 0 degree -// 0xFFFFFFFF to 0x80000000: −360/2^16 to −360×2^15 degrees -// - fsca format is 2^16 is 360 degrees, so a value of 1 is actually -// 1/182.044444444 of a degree or 1/10430.3783505 of a radian -// - fsca does a %360 automatically for values over 360 degrees -// -// Also: -// In order to make the best use of fsca units, a program must expect them from -// the outset and not "make them" by dividing radians or degrees to get them, -// otherwise it's just giving the 'fsca' instruction radians or degrees! -// - -// The following functions are available. -// Please see their definitions for other usage info, otherwise they may not -// work for you. -// -/* - // For integer input in native fsca units (fastest) - _Complex float MATH_fsca_Int(unsigned int input_int) - - // For integer input in degrees - _Complex float MATH_fsca_Int_Deg(unsigned int input_int) - - // For integer input in radians - _Complex float MATH_fsca_Int_Rad(unsigned int input_int) - - // For float input in native fsca units - _Complex float MATH_fsca_Float(float input_float) - - // For float input in degrees - _Complex float MATH_fsca_Float_Deg(float input_float) - - // For float input in radians - _Complex float MATH_fsca_Float_Rad(float input_float) -*/ - -//------------------------------------------------------------------------------ -#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION -//------------------------------------------------------------------------------ -// -// This set of fsca functions is specifically for old versions of GCC. -// See later for functions for newer versions of GCC. -// - -// -// Integer input (faster) -// - -// For int input, input_int is in native fsca units (fastest) -static inline __attribute__((always_inline)) RETURN_FSCA_STRUCT MATH_fsca_Int(unsigned int input_int) -{ - register float __sine __asm__("fr0"); - register float __cosine __asm__("fr1"); - - asm volatile ("lds %[input_number], FPUL\n\t" // load int from register (1 cycle) - "fsca FPUL, DR0\n" // 3 cycle simultaneous sine/cosine - : "=w" (__sine), "=f" (__cosine) // outputs - : [input_number] "r" (input_int) // inputs - : "fpul" // clobbers - ); - - RETURN_FSCA_STRUCT output = {__sine, __cosine}; - return output; -} - -// For int input, input_int is in degrees -static inline __attribute__((always_inline)) RETURN_FSCA_STRUCT MATH_fsca_Int_Deg(unsigned int input_int) -{ - // normalize whole number input degrees to fsca format - input_int = ((1527099483ULL * input_int) >> 23); - - register float __sine __asm__("fr0"); - register float __cosine __asm__("fr1"); - - asm volatile ("lds %[input_number], FPUL\n\t" // load int from register (1 cycle) - "fsca FPUL, DR0\n" // 3 cycle simultaneous sine/cosine - : "=w" (__sine), "=f" (__cosine) // outputs - : [input_number] "r" (input_int) // inputs - : "fpul" // clobbers - ); - - RETURN_FSCA_STRUCT output = {__sine, __cosine}; - return output; -} - -// For int input, input_int is in radians -static inline __attribute__((always_inline)) RETURN_FSCA_STRUCT MATH_fsca_Int_Rad(unsigned int input_int) -{ - // normalize whole number input rads to fsca format - input_int = ((2734261102ULL * input_int) >> 18); - - register float __sine __asm__("fr0"); - register float __cosine __asm__("fr1"); - - asm volatile ("lds %[input_number], FPUL\n\t" // load int from register (1 cycle) - "fsca FPUL, DR0\n" // 3 cycle simultaneous sine/cosine - : "=w" (__sine), "=f" (__cosine) // outputs - : [input_number] "r" (input_int) // inputs - : "fpul" // clobbers - ); - - RETURN_FSCA_STRUCT output = {__sine, __cosine}; - return output; -} - -// -// Float input (slower) -// - -// For float input, input_float is in native fsca units -static inline __attribute__((always_inline)) RETURN_FSCA_STRUCT MATH_fsca_Float(float input_float) -{ - register float __sine __asm__("fr0"); - register float __cosine __asm__("fr1"); - - asm volatile ("ftrc %[input_number], FPUL\n\t" // convert float to int. takes 3 cycles - "fsca FPUL, DR0\n" // 3 cycle simultaneous sine/cosine - : "=w" (__sine), "=f" (__cosine) // outputs - : [input_number] "f" (input_float) // inputs - : "fpul" // clobbers - ); - - RETURN_FSCA_STRUCT output = {__sine, __cosine}; - return output; -} - -// For float input, input_float is in degrees -static inline __attribute__((always_inline)) RETURN_FSCA_STRUCT MATH_fsca_Float_Deg(float input_float) -{ - input_float *= 182.044444444f; - - register float __sine __asm__("fr0"); - register float __cosine __asm__("fr1"); - - asm volatile ("ftrc %[input_number], FPUL\n\t" // convert float to int. takes 3 cycles - "fsca FPUL, DR0\n" // 3 cycle simultaneous sine/cosine - : "=w" (__sine), "=f" (__cosine) // outputs - : [input_number] "f" (input_float) // inputs - : "fpul" // clobbers - ); - - RETURN_FSCA_STRUCT output = {__sine, __cosine}; - return output; -} - -// For float input, input_float is in radians -static inline __attribute__((always_inline)) RETURN_FSCA_STRUCT MATH_fsca_Float_Rad(float input_float) -{ - input_float *= 10430.3783505f; - - register float __sine __asm__("fr0"); - register float __cosine __asm__("fr1"); - - asm volatile ("ftrc %[input_number], FPUL\n\t" // convert float to int. takes 3 cycles - "fsca FPUL, DR0\n" // 3 cycle simultaneous sine/cosine - : "=w" (__sine), "=f" (__cosine) // outputs - : [input_number] "f" (input_float) // inputs - : "fpul" // clobbers - ); - - RETURN_FSCA_STRUCT output = {__sine, __cosine}; - return output; -} - -//------------------------------------------------------------------------------ -#else -//------------------------------------------------------------------------------ -// -// This set of fsca functions is specifically for newer versions of GCC. They -// work fine under GCC 9.2.0. -// - -// -// Integer input (faster) -// - -// For int input, input_int is in native fsca units (fastest) -static inline __attribute__((always_inline)) _Complex float MATH_fsca_Int(unsigned int input_int) -{ - _Complex float output; - - asm volatile ("lds %[input_number], FPUL\n\t" // load int from register (1 cycle) - "fsca FPUL, %[out]\n" // 3 cycle simultaneous sine/cosine - : [out] "=d" (output) // outputs - : [input_number] "r" (input_int) // inputs - : "fpul" // clobbers - ); - - return output; -} - -// For int input, input_int is in degrees -static inline __attribute__((always_inline)) _Complex float MATH_fsca_Int_Deg(unsigned int input_int) -{ - // normalize whole number input degrees to fsca format - input_int = ((1527099483ULL * input_int) >> 23); - - _Complex float output; - - asm volatile ("lds %[input_number], FPUL\n\t" // load int from register (1 cycle) - "fsca FPUL, %[out]\n" // 3 cycle simultaneous sine/cosine - : [out] "=d" (output) // outputs - : [input_number] "r" (input_int) // inputs - : "fpul" // clobbers - ); - - return output; -} - -// For int input, input_int is in radians -static inline __attribute__((always_inline)) _Complex float MATH_fsca_Int_Rad(unsigned int input_int) -{ - // normalize whole number input rads to fsca format - input_int = ((2734261102ULL * input_int) >> 18); - - _Complex float output; - - asm volatile ("lds %[input_number], FPUL\n\t" // load int from register (1 cycle) - "fsca FPUL, %[out]\n" // 3 cycle simultaneous sine/cosine - : [out] "=d" (output) // outputs - : [input_number] "r" (input_int) // inputs - : "fpul" // clobbers - ); - - return output; -} - -// -// Float input (slower) -// - -// For float input, input_float is in native fsca units -static inline __attribute__((always_inline)) _Complex float MATH_fsca_Float(float input_float) -{ - _Complex float output; - - asm volatile ("ftrc %[input_number], FPUL\n\t" // convert float to int. takes 3 cycles - "fsca FPUL, %[out]\n" // 3 cycle simultaneous sine/cosine - : [out] "=d" (output) // outputs - : [input_number] "f" (input_float) // inputs - : "fpul" // clobbers - ); - - return output; -} - -// For float input, input_float is in degrees -static inline __attribute__((always_inline)) _Complex float MATH_fsca_Float_Deg(float input_float) -{ - input_float *= 182.044444444f; - - _Complex float output; - - asm volatile ("ftrc %[input_number], FPUL\n\t" // convert float to int. takes 3 cycles - "fsca FPUL, %[out]\n" // 3 cycle simultaneous sine/cosine - : [out] "=d" (output) // outputs - : [input_number] "f" (input_float) // inputs - : "fpul" // clobbers - ); - - return output; -} - -// For float input, input_float is in radians -static inline __attribute__((always_inline)) _Complex float MATH_fsca_Float_Rad(float input_float) -{ - input_float *= 10430.3783505f; - - _Complex float output; - - asm volatile ("ftrc %[input_number], FPUL\n\t" // convert float to int. takes 3 cycles - "fsca FPUL, %[out]\n" // 3 cycle simultaneous sine/cosine - : [out] "=d" (output) // outputs - : [input_number] "f" (input_float) // inputs - : "fpul" // clobbers - ); - - return output; -} - -//------------------------------------------------------------------------------ -#endif -//------------------------------------------------------------------------------ - -//============================================================================== -// Hardware vector and matrix operations -//============================================================================== -// -// These functions each have very specific usage instructions. Please be sure to -// read them before use or else they won't seem to work right! -// -// The following functions are available. -// Please see their definitions for important usage info, otherwise they may not -// work for you. -// -/* - - //------------------------------------------------------------------------------ - // Vector and matrix math operations - //------------------------------------------------------------------------------ - - // Inner/dot product (4x1 vec . 4x1 vec = scalar) - float MATH_fipr(float x1, float x2, float x3, float x4, float y1, float y2, float y3, float y4) - - // Sum of Squares (w^2 + x^2 + y^2 + z^2) - float MATH_Sum_of_Squares(float w, float x, float y, float z) - - // Cross product with bonus multiply (vec X vec = orthogonal vec, with an extra a*b=c) - RETURN_VECTOR_STRUCT MATH_Cross_Product_with_Mult(float x1, float x2, float x3, float y1, float y2, float y3, float a, float b) - - // Cross product (vec X vec = orthogonal vec) - RETURN_VECTOR_STRUCT MATH_Cross_Product(float x1, float x2, float x3, float y1, float y2, float y3) - - // Outer product (vec (X) vec = 4x4 matrix) - void MATH_Outer_Product(float x1, float x2, float x3, float x4, float y1, float y2, float y3, float y4) - - // Matrix transform (4x4 matrix * 4x1 vec = 4x1 vec) - RETURN_VECTOR_STRUCT MATH_Matrix_Transform(float x1, float x2, float x3, float x4) - - // 4x4 Matrix transpose (XMTRX^T) - void MATH_Matrix_Transpose(void) - - // 4x4 Matrix product (XMTRX and one from memory) - void MATH_Matrix_Product(ALL_FLOATS_STRUCT * front_matrix) - - // 4x4 Matrix product (two from memory) - void MATH_Load_Matrix_Product(ALL_FLOATS_STRUCT * matrix1, ALL_FLOATS_STRUCT * matrix2) - - //------------------------------------------------------------------------------ - // Matrix load and store operations - //------------------------------------------------------------------------------ - - // Load 4x4 XMTRX from memory - void MATH_Load_XMTRX(ALL_FLOATS_STRUCT * back_matrix) - - // Store 4x4 XMTRX to memory - ALL_FLOATS_STRUCT * MATH_Store_XMTRX(ALL_FLOATS_STRUCT * destination) - - // Get 4x1 column vector from XMTRX - RETURN_VECTOR_STRUCT MATH_Get_XMTRX_Vector(unsigned int which) - - // Get 2x2 matrix from XMTRX quadrant - RETURN_VECTOR_STRUCT MATH_Get_XMTRX_2x2(unsigned int which) -*/ - -//------------------------------------------------------------------------------ -// Vector and matrix math operations -//------------------------------------------------------------------------------ - -// Inner/dot product: vec . vec = scalar -// _ _ -// | y1 | -// [ x1 x2 x3 x4 ] . | y2 | = scalar -// | y3 | -// |_ y4 _| -// -// SH4 calling convention states we get 8 float arguments. Perfect! -static inline __attribute__((always_inline)) float MATH_fipr(float x1, float x2, float x3, float x4, float y1, float y2, float y3, float y4) -{ - // FR4-FR11 are the regs that are passed in, aka vectors FV4 and FV8. - // Just need to make sure GCC doesn't modify anything, and these register vars do that job. - - // Temporary variables are necessary per GCC to avoid clobbering: - // https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables - - float tx1 = x1; - float tx2 = x2; - float tx3 = x3; - float tx4 = x4; - - float ty1 = y1; - float ty2 = y2; - float ty3 = y3; - float ty4 = y4; - - // vector FV4 - register float __x1 __asm__("fr4") = tx1; - register float __x2 __asm__("fr5") = tx2; - register float __x3 __asm__("fr6") = tx3; - register float __x4 __asm__("fr7") = tx4; - - // vector FV8 - register float __y1 __asm__("fr8") = ty1; - register float __y2 __asm__("fr9") = ty2; - register float __y3 __asm__("fr10") = ty3; - register float __y4 __asm__("fr11") = ty4; - - // take care of all the floats in one fell swoop - asm volatile ("fipr FV4, FV8\n" - : "+f" (__y4) // output (gets written to FR11) - : "f" (__x1), "f" (__x2), "f" (__x3), "f" (__x4), "f" (__y1), "f" (__y2), "f" (__y3) // inputs - : // clobbers - ); - - return __y4; -} - -// Sum of Squares -// _ _ -// | w | -// [ w x y z ] . | x | = w^2 + x^2 + y^2 + z^2 = scalar -// | y | -// |_ z _| -// -static inline __attribute__((always_inline)) float MATH_Sum_of_Squares(float w, float x, float y, float z) -{ - // FR4-FR7 are the regs that are passed in, aka vector FV4. - // Just need to make sure GCC doesn't modify anything, and these register vars do that job. - - // Temporary variables are necessary per GCC to avoid clobbering: - // https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables - - float tw = w; - float tx = x; - float ty = y; - float tz = z; - - // vector FV4 - register float __w __asm__("fr4") = tw; - register float __x __asm__("fr5") = tx; - register float __y __asm__("fr6") = ty; - register float __z __asm__("fr7") = tz; - - // take care of all the floats in one fell swoop - asm volatile ("fipr FV4, FV4\n" - : "+f" (__z) // output (gets written to FR7) - : "f" (__w), "f" (__x), "f" (__y) // inputs - : // clobbers - ); - - return __z; -} - -// Cross product: vec X vec = orthogonal vec -// _ _ _ _ _ _ -// | x1 | | y1 | | z1 | -// | x2 | X | y2 | = | z2 | -// |_ x3 _| |_ y3 _| |_ z3 _| -// -// With bonus multiply: -// -// a * b = c -// -// IMPORTANT USAGE INFORMATION (cross product): -// -// Return vector struct maps as below to the above diagram: -// -// typedef struct { -// float z1; -// float z2; -// float z3; -// float z4; // c is stored in z4, and c = a*b if using 'with mult' version (else c = 0) -// } RETURN_VECTOR_STRUCT; -// -// For people familiar with the unit vector notation, z1 == 'i', z2 == 'j', -// and z3 == 'k'. -// -// The cross product matrix will also be stored in XMTRX after this, so calling -// MATH_Matrix_Transform() on a vector after using this function will do a cross -// product with the same x1-x3 values and a multiply with the same 'a' value -// as used in this function. In this a situation, 'a' will be multiplied with -// the x4 parameter of MATH_Matrix_Transform(). a = 0 if not using the 'with mult' -// version of the cross product function. -// -// For reference, XMTRX will look like this: -// -// [ 0 -x3 x2 0 ] -// [ x3 0 -x1 0 ] -// [ -x2 x1 0 0 ] -// [ 0 0 0 a ] (<-- a = 0 if not using 'with mult') -// -// Similarly to how the sine and cosine functions use fsca and return 2 floats, -// the cross product functions actually return 4 floats. The first 3 are the -// cross product output, and the 4th is a*b. The SH4 only multiplies 4x4 -// matrices with 4x1 vectors, which is why the output is like that--but it means -// we also get a bonus float multiplication while we do our cross product! -// - -// Please do not call this function directly (notice the weird syntax); call -// MATH_Cross_Product() or MATH_Cross_Product_with_Mult() instead. -static inline __attribute__((always_inline)) RETURN_VECTOR_STRUCT xMATH_do_Cross_Product_with_Mult(float x3, float a, float y3, float b, float x2, float x1, float y1, float y2) -{ - // FR4-FR11 are the regs that are passed in, in that order. - // Just need to make sure GCC doesn't modify anything, and these register vars do that job. - - // Temporary variables are necessary per GCC to avoid clobbering: - // https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables - - float tx1 = x1; - float tx2 = x2; - float tx3 = x3; - float ta = a; - - float ty1 = y1; - float ty2 = y2; - float ty3 = y3; - float tb = b; - - register float __x1 __asm__("fr9") = tx1; // need to negate (need to move to fr6, then negate fr9) - register float __x2 __asm__("fr8") = tx2; // in place for matrix (need to move to fr2 then negate fr2) - register float __x3 __asm__("fr4") = tx3; // need to negate (move to fr1 first, then negate fr4) - register float __a __asm__("fr5") = ta; - - register float __y1 __asm__("fr10") = ty1; - register float __y2 __asm__("fr11") = ty2; - register float __y3 __asm__("fr6") = ty3; - register float __b __asm__("fr7") = tb; - - register float __z1 __asm__("fr0") = 0.0f; // z1 - register float __z2 __asm__("fr1") = 0.0f; // z2 (not moving x3 here yet since a double 0 is needed) - register float __z3 __asm__("fr2") = tx2; // z3 (this handles putting x2 in fr2) - register float __c __asm__("fr3") = 0.0f; // c - - // This actually does a matrix transform to do the cross product. - // It's this: - // _ _ _ _ - // [ 0 -x3 x2 0 ] | y1 | | -x3y2 + x2y3 | - // [ x3 0 -x1 0 ] | y2 | = | x3y1 - x1y3 | - // [ -x2 x1 0 0 ] | y3 | | -x2y1 + x1y2 | - // [ 0 0 0 a ] |_ b _| |_ c _| - // - - asm volatile ( - // set up back bank's FV0 - "fschg\n\t" // switch fmov to paired moves (note: only paired moves can access XDn regs) - - // Save FR12-FR15, which are supposed to be preserved across functions calls. - // This stops them from getting clobbered and saves 4 stack pushes (memory accesses). - "fmov DR12, XD12\n\t" - "fmov DR14, XD14\n\t" - - "fmov DR10, XD0\n\t" // fmov 'y1' and 'y2' from FR10, FR11 into position (XF0, XF1) - "fmov DR6, XD2\n\t" // fmov 'y3' and 'b' from FR6, FR7 into position (XF2, XF3) - - // pair move zeros for some speed in setting up front bank for matrix - "fmov DR0, DR10\n\t" // clear FR10, FR11 - "fmov DR0, DR12\n\t" // clear FR12, FR13 - "fschg\n\t" // switch back to single moves - // prepare front bank for XMTRX - "fmov FR5, FR15\n\t" // fmov 'a' into position - "fmov FR0, FR14\n\t" // clear out FR14 - "fmov FR0, FR7\n\t" // clear out FR7 - "fmov FR0, FR5\n\t" // clear out FR5 - - "fneg FR2\n\t" // set up 'x2' - "fmov FR9, FR6\n\t" // set up 'x1' - "fneg FR9\n\t" - "fmov FR4, FR1\n\t" // set up 'x3' - "fneg FR4\n\t" - // flip banks and matrix multiply - "frchg\n\t" - "ftrv XMTRX, FV0\n" - : "+&w" (__z1), "+&f" (__z2), "+&f" (__z3), "+&f" (__c) // output (using FV0) - : "f" (__x1), "f" (__x2), "f" (__x3), "f" (__y1), "f" (__y2), "f" (__y3), "f" (__a), "f" (__b) // inputs - : // clobbers (all of the float regs get clobbered, except for FR12-FR15 which were specially preserved) - ); - - RETURN_VECTOR_STRUCT output = {__z1, __z2, __z3, __c}; - return output; -} - -// Please do not call this function directly (notice the weird syntax); call -// MATH_Cross_Product() or MATH_Cross_Product_with_Mult() instead. -static inline __attribute__((always_inline)) RETURN_VECTOR_STRUCT xMATH_do_Cross_Product(float x3, float zero, float x1, float y3, float x2, float x1_2, float y1, float y2) -{ - // FR4-FR11 are the regs that are passed in, in that order. - // Just need to make sure GCC doesn't modify anything, and these register vars do that job. - - // Temporary variables are necessary per GCC to avoid clobbering: - // https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables - - float tx1 = x1; - float tx2 = x2; - float tx3 = x3; - float tx1_2 = x1_2; - - float ty1 = y1; - float ty2 = y2; - float ty3 = y3; - float tzero = zero; - - register float __x1 __asm__("fr6") = tx1; // in place - register float __x2 __asm__("fr8") = tx2; // in place (fmov to fr2, negate fr2) - register float __x3 __asm__("fr4") = tx3; // need to negate (fmov to fr1, negate fr4) - - register float __zero __asm__("fr5") = tzero; // in place - register float __x1_2 __asm__("fr9") = tx1_2; // need to negate - - register float __y1 __asm__("fr10") = ty1; - register float __y2 __asm__("fr11") = ty2; - // no __y3 needed in this function - - register float __z1 __asm__("fr0") = tzero; // z1 - register float __z2 __asm__("fr1") = tzero; // z2 - register float __z3 __asm__("fr2") = ty3; // z3 - register float __c __asm__("fr3") = tzero; // c - - // This actually does a matrix transform to do the cross product. - // It's this: - // _ _ _ _ - // [ 0 -x3 x2 0 ] | y1 | | -x3y2 + x2y3 | - // [ x3 0 -x1 0 ] | y2 | = | x3y1 - x1y3 | - // [ -x2 x1 0 0 ] | y3 | | -x2y1 + x1y2 | - // [ 0 0 0 0 ] |_ 0 _| |_ 0 _| - // - - asm volatile ( - // zero out FR7. For some reason, if this is done in C after __z3 is set: - // register float __y3 __asm__("fr7") = tzero; - // then GCC will emit a spurious stack push (pushing FR12). So just zero it here. - "fmov FR5, FR7\n\t" - // set up back bank's FV0 - "fschg\n\t" // switch fmov to paired moves (note: only paired moves can access XDn regs) - - // Save FR12-FR15, which are supposed to be preserved across functions calls. - // This stops them from getting clobbered and saves 4 stack pushes (memory accesses). - "fmov DR12, XD12\n\t" - "fmov DR14, XD14\n\t" - - "fmov DR10, XD0\n\t" // fmov 'y1' and 'y2' from FR10, FR11 into position (XF0, XF1) - "fmov DR2, XD2\n\t" // fmov 'y3' and '0' from FR2, FR3 into position (XF2, XF3) - - // pair move zeros for some speed in setting up front bank for matrix - "fmov DR0, DR10\n\t" // clear FR10, FR11 - "fmov DR0, DR12\n\t" // clear FR12, FR13 - "fmov DR0, DR14\n\t" // clear FR14, FR15 - "fschg\n\t" // switch back to single moves - // prepare front bank for XMTRX - "fneg FR9\n\t" // set up 'x1' - "fmov FR8, FR2\n\t" // set up 'x2' - "fneg FR2\n\t" - "fmov FR4, FR1\n\t" // set up 'x3' - "fneg FR4\n\t" - // flip banks and matrix multiply - "frchg\n\t" - "ftrv XMTRX, FV0\n" - : "+&w" (__z1), "+&f" (__z2), "+&f" (__z3), "+&f" (__c) // output (using FV0) - : "f" (__x1), "f" (__x2), "f" (__x3), "f" (__y1), "f" (__y2), "f" (__zero), "f" (__x1_2) // inputs - : "fr7" // clobbers (all of the float regs get clobbered, except for FR12-FR15 which were specially preserved) - ); - - RETURN_VECTOR_STRUCT output = {__z1, __z2, __z3, __c}; - return output; -} - -//------------------------------------------------------------------------------ -// Functions that wrap the xMATH_do_Cross_Product[_with_Mult]() functions to make -// it easier to organize parameters -//------------------------------------------------------------------------------ - -// Cross product with a bonus float multiply (c = a * b) -static inline __attribute__((always_inline)) RETURN_VECTOR_STRUCT MATH_Cross_Product_with_Mult(float x1, float x2, float x3, float y1, float y2, float y3, float a, float b) -{ - return xMATH_do_Cross_Product_with_Mult(x3, a, y3, b, x2, x1, y1, y2); -} - -// Plain cross product; does not use the bonus float multiply (c = 0 and a in the cross product matrix will be 0) -// This is a tiny bit faster than 'with_mult' (about 2 cycles faster) -static inline __attribute__((always_inline)) RETURN_VECTOR_STRUCT MATH_Cross_Product(float x1, float x2, float x3, float y1, float y2, float y3) -{ - return xMATH_do_Cross_Product(x3, 0.0f, x1, y3, x2, x1, y1, y2); -} - -// Outer product: vec (X) vec = matrix -// _ _ -// | x1 | -// | x2 | (X) [ y1 y2 y3 y4 ] = 4x4 matrix -// | x3 | -// |_ x4 _| -// -// This returns the floats in the back bank (XF0-15), which are inaccessible -// outside of using frchg or paired-move fmov. It's meant to set up a matrix for -// use with other matrix functions. GCC also does not touch the XFn bank. -// This will also wipe out anything stored in the float registers, as it uses the -// whole FPU register file (all 32 of the float registers). -static inline __attribute__((always_inline)) void MATH_Outer_Product(float x1, float x2, float x3, float x4, float y1, float y2, float y3, float y4) -{ - // FR4-FR11 are the regs that are passed in, in that order. - // Just need to make sure GCC doesn't modify anything, and these register vars do that job. - - // Temporary variables are necessary per GCC to avoid clobbering: - // https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables - - float tx1 = x1; - float tx2 = x2; - float tx3 = x3; - float tx4 = x4; - - float ty1 = y1; - float ty2 = y2; - float ty3 = y3; - float ty4 = y4; - - // vector FV4 - register float __x1 __asm__("fr4") = tx1; - register float __x2 __asm__("fr5") = tx2; - register float __x3 __asm__("fr6") = tx3; - register float __x4 __asm__("fr7") = tx4; - - // vector FV8 - register float __y1 __asm__("fr8") = ty1; - register float __y2 __asm__("fr9") = ty2; - register float __y3 __asm__("fr10") = ty3; // in place already - register float __y4 __asm__("fr11") = ty4; - - // This actually does a 4x4 matrix multiply to do the outer product. - // It's this: - // - // [ x1 x1 x1 x1 ] [ y1 0 0 0 ] [ x1y1 x1y2 x1y3 x1y4 ] - // [ x2 x2 x2 x2 ] [ 0 y2 0 0 ] = [ x2y1 x2y2 x2y3 x2y4 ] - // [ x3 x3 x3 x3 ] [ 0 0 y3 0 ] [ x3y1 x3y2 x3y3 x3y4 ] - // [ x4 x4 x4 x4 ] [ 0 0 0 y4 ] [ x4y1 x4y2 x4y3 x4y4 ] - // - - asm volatile ( - // zero out unoccupied front floats to make a double 0 in DR2 - "fldi0 FR2\n\t" - "fmov FR2, FR3\n\t" - "fschg\n\t" // switch fmov to paired moves (note: only paired moves can access XDn regs) - // fmov 'x1' and 'x2' from FR4, FR5 into position (XF0,4,8,12, XF1,5,9,13) - "fmov DR4, XD0\n\t" - "fmov DR4, XD4\n\t" - "fmov DR4, XD8\n\t" - "fmov DR4, XD12\n\t" - // fmov 'x3' and 'x4' from FR6, FR7 into position (XF2,6,10,14, XF3,7,11,15) - "fmov DR6, XD2\n\t" - "fmov DR6, XD6\n\t" - "fmov DR6, XD10\n\t" - "fmov DR6, XD14\n\t" - // set up front floats (y1-y4) - "fmov DR8, DR0\n\t" - "fmov DR8, DR4\n\t" - "fmov DR10, DR14\n\t" - // finish zeroing out front floats - "fmov DR2, DR6\n\t" - "fmov DR2, DR8\n\t" - "fmov DR2, DR12\n\t" - "fschg\n\t" // switch back to single-move mode - // zero out remaining values and matrix multiply 4x4 - "fmov FR2, FR1\n\t" - "ftrv XMTRX, FV0\n\t" - - "fmov FR6, FR4\n\t" - "ftrv XMTRX, FV4\n\t" - - "fmov FR8, FR11\n\t" - "ftrv XMTRX, FV8\n\t" - - "fmov FR12, FR14\n\t" - "ftrv XMTRX, FV12\n\t" - // Save output in XF regs - "frchg\n" - : // no outputs - : "f" (__x1), "f" (__x2), "f" (__x3), "f" (__x4), "f" (__y1), "f" (__y2), "f" (__y3), "f" (__y4) // inputs - : "fr0", "fr1", "fr2", "fr3", "fr12", "fr13", "fr14", "fr15" // clobbers, can't avoid it - ); - // GCC will restore FR12-FR15 from the stack after this, so we really can't keep the output in the front bank. -} - -// Matrix transform: matrix * vector = vector -// _ _ _ _ -// [ ----------- ] | x1 | | z1 | -// [ ---XMTRX--- ] | x2 | = | z2 | -// [ ----------- ] | x3 | | z3 | -// [ ----------- ] |_ x4 _| |_ z4 _| -// -// IMPORTANT USAGE INFORMATION (matrix transform): -// -// Return vector struct maps 1:1 to the above diagram: -// -// typedef struct { -// float z1; -// float z2; -// float z3; -// float z4; -// } RETURN_VECTOR_STRUCT; -// -// Similarly to how the sine and cosine functions use fsca and return 2 floats, -// the matrix transform function actually returns 4 floats. The SH4 only multiplies -// 4x4 matrices with 4x1 vectors, which is why the output is like that. -// -// Multiply a matrix stored in the back bank (XMTRX) with an input vector -static inline __attribute__((always_inline)) RETURN_VECTOR_STRUCT MATH_Matrix_Transform(float x1, float x2, float x3, float x4) -{ - // The floats comprising FV4 are the regs that are passed in. - // Just need to make sure GCC doesn't modify anything, and these register vars do that job. - - // Temporary variables are necessary per GCC to avoid clobbering: - // https://gcc.gnu.org/onlinedocs/gcc/Local-Register-Variables.html#Local-Register-Variables - - float tx1 = x1; - float tx2 = x2; - float tx3 = x3; - float tx4 = x4; - - // output vector FV0 - register float __z1 __asm__("fr0") = tx1; - register float __z2 __asm__("fr1") = tx2; - register float __z3 __asm__("fr2") = tx3; - register float __z4 __asm__("fr3") = tx4; - - asm volatile ("ftrv XMTRX, FV0\n\t" - // have to do this to obey SH4 calling convention--output returned in FV0 - : "+w" (__z1), "+f" (__z2), "+f" (__z3), "+f" (__z4) // outputs, "+" means r/w - : // no inputs - : // no clobbers - ); - - RETURN_VECTOR_STRUCT output = {__z1, __z2, __z3, __z4}; - return output; -} - -// Matrix Transpose -// -// This does a matrix transpose on the matrix in XMTRX, which swaps rows with -// columns as follows (math notation is [XMTRX]^T): -// -// [ a b c d ] T [ a e i m ] -// [ e f g h ] = [ b f j n ] -// [ i j k l ] [ c g k o ] -// [ m n o p ] [ d h l p ] -// -// PLEASE NOTE: It is faster to avoid the need for a transpose altogether by -// structuring matrices and vectors accordingly. -static inline __attribute__((always_inline)) void MATH_Matrix_Transpose(void) -{ - asm volatile ( - "frchg\n\t" // fmov for singles only works on front bank - // FR0, FR5, FR10, and FR15 are already in place - // swap FR1 and FR4 - "flds FR1, FPUL\n\t" - "fmov FR4, FR1\n\t" - "fsts FPUL, FR4\n\t" - // swap FR2 and FR8 - "flds FR2, FPUL\n\t" - "fmov FR8, FR2\n\t" - "fsts FPUL, FR8\n\t" - // swap FR3 and FR12 - "flds FR3, FPUL\n\t" - "fmov FR12, FR3\n\t" - "fsts FPUL, FR12\n\t" - // swap FR6 and FR9 - "flds FR6, FPUL\n\t" - "fmov FR9, FR6\n\t" - "fsts FPUL, FR9\n\t" - // swap FR7 and FR13 - "flds FR7, FPUL\n\t" - "fmov FR13, FR7\n\t" - "fsts FPUL, FR13\n\t" - // swap FR11 and FR14 - "flds FR11, FPUL\n\t" - "fmov FR14, FR11\n\t" - "fsts FPUL, FR14\n\t" - // restore XMTRX to back bank - "frchg\n" - : // no outputs - : // no inputs - : "fpul" // clobbers - ); -} - -// Matrix product: matrix * matrix = matrix -// -// These use the whole dang floating point unit. -// -// [ ----------- ] [ ----------- ] [ ----------- ] -// [ ---Back---- ] [ ---Front--- ] = [ ---XMTRX--- ] -// [ ---Matrix-- ] [ ---Matrix-- ] [ ----------- ] -// [ --(XMTRX)-- ] [ ----------- ] [ ----------- ] -// -// Multiply a matrix stored in the back bank with a matrix loaded from memory -// Output is stored in the back bank (XMTRX) -static inline __attribute__((always_inline)) void MATH_Matrix_Product(ALL_FLOATS_STRUCT * front_matrix) -{ - /* - // This prefetching should help a bit if placed suitably far enough in advance (not here) - // Possibly right before this function call. Change the "front_matrix" variable appropriately. - // SH4 does not support r/w or temporal prefetch hints, so we only need to pass in an address. - __builtin_prefetch(front_matrix); - */ - - unsigned int prefetch_scratch; - - asm volatile ( - "mov %[fmtrx], %[pref_scratch]\n\t" // parallel-load address for prefetching (MT) - "add #32, %[pref_scratch]\n\t" // offset by 32 (EX - flow dependency, but 'add' is actually parallelized since 'mov Rm, Rn' is 0-cycle) - "fschg\n\t" // switch fmov to paired moves (FE) - "pref @%[pref_scratch]\n\t" // Get a head start prefetching the second half of the 64-byte data (LS) - // interleave loads and matrix multiply 4x4 - "fmov.d @%[fmtrx]+, DR0\n\t" // (LS) - "fmov.d @%[fmtrx]+, DR2\n\t" - "fmov.d @%[fmtrx]+, DR4\n\t" // (LS) want to issue the next one before 'ftrv' for parallel exec - "ftrv XMTRX, FV0\n\t" // (FE) - - "fmov.d @%[fmtrx]+, DR6\n\t" - "fmov.d @%[fmtrx]+, DR8\n\t" // prefetch should work for here - "ftrv XMTRX, FV4\n\t" - - "fmov.d @%[fmtrx]+, DR10\n\t" - "fmov.d @%[fmtrx]+, DR12\n\t" - "ftrv XMTRX, FV8\n\t" - - "fmov.d @%[fmtrx], DR14\n\t" // (LS, but this will stall 'ftrv' for 3 cycles) - "fschg\n\t" // switch back to single moves (and avoid stalling 'ftrv') (FE) - "ftrv XMTRX, FV12\n\t" // (FE) - // Save output in XF regs - "frchg\n" - : [fmtrx] "+r" ((unsigned int)front_matrix), [pref_scratch] "=&r" (prefetch_scratch) // outputs, "+" means r/w - : // no inputs - : "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7", "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15" // clobbers (GCC doesn't know about back bank, so writing to it isn't clobbered) - ); -} - -// Load two 4x4 matrices and multiply them, storing the output into the back bank (XMTRX) -// -// MATH_Load_Matrix_Product() is slightly faster than doing this: -// MATH_Load_XMTRX(matrix1) -// MATH_Matrix_Product(matrix2) -// as it saves having to do 2 extraneous 'fschg' instructions. -// -static inline __attribute__((always_inline)) void MATH_Load_Matrix_Product(ALL_FLOATS_STRUCT * matrix1, ALL_FLOATS_STRUCT * matrix2) -{ - /* - // This prefetching should help a bit if placed suitably far enough in advance (not here) - // Possibly right before this function call. Change the "matrix1" variable appropriately. - // SH4 does not support r/w or temporal prefetch hints, so we only need to pass in an address. - __builtin_prefetch(matrix1); - */ - - unsigned int prefetch_scratch; - - asm volatile ( - "mov %[bmtrx], %[pref_scratch]\n\t" // (MT) - "add #32, %[pref_scratch]\n\t" // offset by 32 (EX - flow dependency, but 'add' is actually parallelized since 'mov Rm, Rn' is 0-cycle) - "fschg\n\t" // switch fmov to paired moves (note: only paired moves can access XDn regs) (FE) - "pref @%[pref_scratch]\n\t" // Get a head start prefetching the second half of the 64-byte data (LS) - // back matrix - "fmov.d @%[bmtrx]+, XD0\n\t" // (LS) - "fmov.d @%[bmtrx]+, XD2\n\t" - "fmov.d @%[bmtrx]+, XD4\n\t" - "fmov.d @%[bmtrx]+, XD6\n\t" - "pref @%[fmtrx]\n\t" // prefetch fmtrx now while we wait (LS) - "fmov.d @%[bmtrx]+, XD8\n\t" // bmtrx prefetch should work for here - "fmov.d @%[bmtrx]+, XD10\n\t" - "fmov.d @%[bmtrx]+, XD12\n\t" - "mov %[fmtrx], %[pref_scratch]\n\t" // (MT) - "add #32, %[pref_scratch]\n\t" // store offset by 32 in r0 (EX - flow dependency, but 'add' is actually parallelized since 'mov Rm, Rn' is 0-cycle) - "fmov.d @%[bmtrx], XD14\n\t" - "pref @%[pref_scratch]\n\t" // Get a head start prefetching the second half of the 64-byte data (LS) - // front matrix - // interleave loads and matrix multiply 4x4 - "fmov.d @%[fmtrx]+, DR0\n\t" - "fmov.d @%[fmtrx]+, DR2\n\t" - "fmov.d @%[fmtrx]+, DR4\n\t" // (LS) want to issue the next one before 'ftrv' for parallel exec - "ftrv XMTRX, FV0\n\t" // (FE) - - "fmov.d @%[fmtrx]+, DR6\n\t" - "fmov.d @%[fmtrx]+, DR8\n\t" - "ftrv XMTRX, FV4\n\t" - - "fmov.d @%[fmtrx]+, DR10\n\t" - "fmov.d @%[fmtrx]+, DR12\n\t" - "ftrv XMTRX, FV8\n\t" - - "fmov.d @%[fmtrx], DR14\n\t" // (LS, but this will stall 'ftrv' for 3 cycles) - "fschg\n\t" // switch back to single moves (and avoid stalling 'ftrv') (FE) - "ftrv XMTRX, FV12\n\t" // (FE) - // Save output in XF regs - "frchg\n" - : [bmtrx] "+&r" ((unsigned int)matrix1), [fmtrx] "+r" ((unsigned int)matrix2), [pref_scratch] "=&r" (prefetch_scratch) // outputs, "+" means r/w, "&" means it's written to before all inputs are consumed - : // no inputs - : "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7", "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15" // clobbers (GCC doesn't know about back bank, so writing to it isn't clobbered) - ); -} - -//------------------------------------------------------------------------------ -// Matrix load and store operations -//------------------------------------------------------------------------------ - -// Load a matrix from memory into the back bank (XMTRX) -static inline __attribute__((always_inline)) void MATH_Load_XMTRX(ALL_FLOATS_STRUCT * back_matrix) -{ - /* - // This prefetching should help a bit if placed suitably far enough in advance (not here) - // Possibly right before this function call. Change the "back_matrix" variable appropriately. - // SH4 does not support r/w or temporal prefetch hints, so we only need to pass in an address. - __builtin_prefetch(back_matrix); - */ - - unsigned int prefetch_scratch; - - asm volatile ( - "mov %[bmtrx], %[pref_scratch]\n\t" // (MT) - "add #32, %[pref_scratch]\n\t" // offset by 32 (EX - flow dependency, but 'add' is actually parallelized since 'mov Rm, Rn' is 0-cycle) - "fschg\n\t" // switch fmov to paired moves (note: only paired moves can access XDn regs) (FE) - "pref @%[pref_scratch]\n\t" // Get a head start prefetching the second half of the 64-byte data (LS) - "fmov.d @%[bmtrx]+, XD0\n\t" - "fmov.d @%[bmtrx]+, XD2\n\t" - "fmov.d @%[bmtrx]+, XD4\n\t" - "fmov.d @%[bmtrx]+, XD6\n\t" - "fmov.d @%[bmtrx]+, XD8\n\t" - "fmov.d @%[bmtrx]+, XD10\n\t" - "fmov.d @%[bmtrx]+, XD12\n\t" - "fmov.d @%[bmtrx], XD14\n\t" - "fschg\n" // switch back to single moves - : [bmtrx] "+r" ((unsigned int)back_matrix), [pref_scratch] "=&r" (prefetch_scratch) // outputs, "+" means r/w - : // no inputs - : // clobbers (GCC doesn't know about back bank, so writing to it isn't clobbered) - ); -} - -// Store XMTRX to memory -static inline __attribute__((always_inline)) ALL_FLOATS_STRUCT * MATH_Store_XMTRX(ALL_FLOATS_STRUCT * destination) -{ - /* - // This prefetching should help a bit if placed suitably far enough in advance (not here) - // Possibly right before this function call. Change the "destination" variable appropriately. - // SH4 does not support r/w or temporal prefetch hints, so we only need to pass in an address. - __builtin_prefetch( (ALL_FLOATS_STRUCT*)((unsigned char*)destination + 32) ); // Store works backwards, so note the '+32' here - */ - - char * output = ((char*)destination) + sizeof(ALL_FLOATS_STRUCT) + 8; // ALL_FLOATS_STRUCT should be 64 bytes - - asm volatile ( - "fschg\n\t" // switch fmov to paired moves (note: only paired moves can access XDn regs) (FE) - "pref @%[dest_base]\n\t" // Get a head start prefetching the second half of the 64-byte data (LS) - "fmov.d XD0, @-%[out_mtrx]\n\t" // These do *(--output) = XDn (LS) - "fmov.d XD2, @-%[out_mtrx]\n\t" - "fmov.d XD4, @-%[out_mtrx]\n\t" - "fmov.d XD6, @-%[out_mtrx]\n\t" - "fmov.d XD8, @-%[out_mtrx]\n\t" - "fmov.d XD10, @-%[out_mtrx]\n\t" - "fmov.d XD12, @-%[out_mtrx]\n\t" - "fmov.d XD14, @-%[out_mtrx]\n\t" - "fschg\n" // switch back to single moves - : [out_mtrx] "+&r" ((unsigned int)output) // outputs, "+" means r/w, "&" means it's written to before all inputs are consumed - : [dest_base] "r" ((unsigned int)destination) // inputs - : "memory" // clobbers - ); - - return destination; -} - -// Returns FV0, 4, 8, or 12 from XMTRX -// -// Sorry, it has to be done 4 at a time like this due to calling convention -// limits; under optimal optimization conditions, we only get 4 float registers -// for return values; any more and they get pushed to memory. -// -// IMPORTANT USAGE INFORMATION (get XMTRX vector) -// -// XMTRX format, using the front bank's FVn notation: -// -// FV0 FV4 FV8 FV12 -// --- --- --- ---- -// [ xf0 xf4 xf8 xf12 ] -// [ xf1 xf5 xf9 xf13 ] -// [ xf2 xf6 xf10 xf14 ] -// [ xf3 xf7 xf11 xf15 ] -// -// Return vector maps to XMTRX as below depending on the FVn value passed in: -// -// typedef struct { -// float z1; // will contain xf0, 4, 8 or 12 -// float z2; // will contain xf1, 5, 9, or 13 -// float z3; // will contain xf2, 6, 10, or 14 -// float z4; // will contain xf3, 7, 11, or 15 -// } RETURN_VECTOR_STRUCT; -// -// Valid values of 'which' are 0, 4, 8, or 12, corresponding to FV0, FV4, FV8, -// or FV12, respectively. Other values will return 0 in all four return values. -static inline __attribute__((always_inline)) RETURN_VECTOR_STRUCT MATH_Get_XMTRX_Vector(unsigned int which) -{ - register float __z1 __asm__("fr0"); - register float __z2 __asm__("fr1"); - register float __z3 __asm__("fr2"); - register float __z4 __asm__("fr3"); - - // Note: only paired moves can access XDn regs - asm volatile ("cmp/eq #0, %[select]\n\t" // if(which == 0), 1 -> T else 0 -> T - "bt.s 0f\n\t" // do FV0 - " cmp/eq #4, %[select]\n\t" // if(which == 4), 1 -> T else 0 -> T - "bt.s 4f\n\t" // do FV4 - " cmp/eq #8, %[select]\n\t" // if(which == 8), 1 -> T else 0 -> T - "bt.s 8f\n\t" // do FV8 - " cmp/eq #12, %[select]\n\t" // if(which == 12), 1 -> T else 0 -> T - "bf.s 1f\n" // exit if not even FV12 was true, otherwise do FV12 - "12:\n\t" - " fschg\n\t" // paired moves for FV12 (and exit case) - "fmov XD14, DR2\n\t" - "fmov XD12, DR0\n\t" - "bt.s 2f\n" // done - "8:\n\t" - " fschg\n\t" // paired moves for FV8, back to singles for FV12 - "fmov XD10, DR2\n\t" - "fmov XD8, DR0\n\t" - "bf.s 2f\n" // done - "4:\n\t" - " fschg\n\t" // paired moves for FV4, back to singles for FV8 - "fmov XD6, DR2\n\t" - "fmov XD4, DR0\n\t" - "bf.s 2f\n" // done - "0:\n\t" - " fschg\n\t" // paired moves for FV0, back to singles for FV4 - "fmov XD2, DR2\n\t" - "fmov XD0, DR0\n\t" - "bf.s 2f\n" // done - "1:\n\t" - " fschg\n\t" // back to singles for FV0 and exit case - "fldi0 FR0\n\t" // FR0-3 get zeroed out, then - "fmov FR0, FR1\n\t" - "fmov FR0, FR2\n\t" - "fmov FR0, FR3\n" - "2:\n" - : "=w" (__z1), "=f" (__z2), "=f" (__z3), "=f" (__z4) // outputs - : [select] "z" (which) // inputs - : "t" // clobbers - ); - - RETURN_VECTOR_STRUCT output = {__z1, __z2, __z3, __z4}; - return output; -} - -// Returns a 2x2 matrix from a quadrant of XMTRX -// -// Sorry, it has to be done 4 at a time like this due to calling convention -// limits; under optimal optimization conditions, we only get 4 float registers -// for return values; any more and they get pushed to memory. -// -// IMPORTANT USAGE INFORMATION (get XMTRX 2x2) -// -// Each 2x2 quadrant is of the form: -// -// [ a b ] -// [ c d ] -// -// Return vector maps to the 2x2 matrix as below: -// -// typedef struct { -// float z1; // a -// float z2; // c -// float z3; // b -// float z4; // d -// } RETURN_VECTOR_STRUCT; -// -// (So the function does a 2x2 transpose in storing the values relative to the -// order stored in XMTRX.) -// -// Valid values of 'which' are 1, 2, 3, or 4, corresponding to the following -// quadrants of XMTRX: -// -// 1 2 -// [ xf0 xf4 ] | [ xf8 xf12 ] -// [ xf1 xf5 ] | [ xf9 xf13 ] -// -- 3 -- | -- 4 -- -// [ xf2 xf6 ] | [ xf10 xf14 ] -// [ xf3 xf7 ] | [ xf11 xf15 ] -// -// Other input values will return 0 in all four return floats. -static inline __attribute__((always_inline)) RETURN_VECTOR_STRUCT MATH_Get_XMTRX_2x2(unsigned int which) -{ - register float __z1 __asm__("fr0"); - register float __z2 __asm__("fr1"); - register float __z3 __asm__("fr2"); - register float __z4 __asm__("fr3"); - - // Note: only paired moves can access XDn regs - asm volatile ("cmp/eq #1, %[select]\n\t" // if(which == 1), 1 -> T else 0 -> T - "bt.s 1f\n\t" // do quadrant 1 - " cmp/eq #2, %[select]\n\t" // if(which == 2), 1 -> T else 0 -> T - "bt.s 2f\n\t" // do quadrant 2 - " cmp/eq #3, %[select]\n\t" // if(which == 3), 1 -> T else 0 -> T - "bt.s 3f\n\t" // do quadrant 3 - " cmp/eq #4, %[select]\n\t" // if(which == 4), 1 -> T else 0 -> T - "bf.s 0f\n" // exit if nothing was true, otherwise do quadrant 4 - "4:\n\t" - " fschg\n\t" // paired moves for quadrant 4 (and exit case) - "fmov XD14, DR2\n\t" - "fmov XD10, DR0\n\t" - "bt.s 5f\n" // done - "3:\n\t" - " fschg\n\t" // paired moves for quadrant 3, back to singles for 4 - "fmov XD6, DR2\n\t" - "fmov XD2, DR0\n\t" - "bf.s 5f\n" // done - "2:\n\t" - " fschg\n\t" // paired moves for quadrant 2, back to singles for 3 - "fmov XD12, DR2\n\t" - "fmov XD8, DR0\n\t" - "bf.s 5f\n" // done - "1:\n\t" - " fschg\n\t" // paired moves for quadrant 1, back to singles for 2 - "fmov XD4, DR2\n\t" - "fmov XD0, DR0\n\t" - "bf.s 5f\n" // done - "0:\n\t" - " fschg\n\t" // back to singles for quadrant 1 and exit case - "fldi0 FR0\n\t" // FR0-3 get zeroed out, then - "fmov FR0, FR1\n\t" - "fmov FR0, FR2\n\t" - "fmov FR0, FR3\n" - "5:\n" - : "=w" (__z1), "=f" (__z2), "=f" (__z3), "=f" (__z4) // outputs - : [select] "z" (which) // inputs - : "t" // clobbers - ); - - RETURN_VECTOR_STRUCT output = {__z1, __z2, __z3, __z4}; - return output; -} - -// It is not possible to return an entire 4x4 matrix in registers, as the only -// registers allowed for return values are R0-R3 and FR0-FR3. All others are -// marked caller save, which means they could be restored from stack and clobber -// anything returned in them. -// -// In general, writing the entire required math routine in one asm function is -// the best way to go for performance reasons anyways, and in that situation one -// can just throw calling convention to the wind until returning back to C. - -//============================================================================== -// Miscellaneous Functions -//============================================================================== -// -// The following functions are provided as examples of ways in which these math -// functions can be used. -// -// Reminder: 1 fsca unit = 1/182.044444444 of a degree or 1/10430.3783505 of a radian -// In order to make the best use of fsca units, a program must expect them from -// the outset and not "make them" by dividing radians or degrees to get them, -// otherwise it's just giving the 'fsca' instruction radians or degrees! -// -/* - - //------------------------------------------------------------------------------ - // Commonly useful functions - //------------------------------------------------------------------------------ - - // Returns 1 if point 't' is inside triangle with vertices 'v0', 'v1', and 'v2', and 0 if not - int MATH_Is_Point_In_Triangle(float v0x, float v0y, float v1x, float v1y, float v2x, float v2y, float ptx, float pty) - - //------------------------------------------------------------------------------ - // Interpolation - //------------------------------------------------------------------------------ - - // Linear interpolation - float MATH_Lerp(float a, float b, float t) - - // Speherical interpolation ('theta' in fsca units) - float MATH_Slerp(float a, float b, float t, float theta) - - //------------------------------------------------------------------------------ - // Fast Sinc functions (unnormalized, sin(x)/x version) - //------------------------------------------------------------------------------ - // Just pass in MATH_pi * x for normalized versions :) - - // Sinc function (fsca units) - float MATH_Fast_Sincf(float x) - - // Sinc function (degrees) - float MATH_Fast_Sincf_Deg(float x) - - // Sinc function (rads) - float MATH_Fast_Sincf_Rad(float x) - - //------------------------------------------------------------------------------ - // Kaiser Window - //------------------------------------------------------------------------------ - - // Generates mipmaps. Angle 'x' in radians. - float MATH_Kaiser_Window_Rad(float x, float alpha, float stretch, float m_width) - - // Generates mipmaps. Angle 'x' in fsca units. - float MATH_Kaiser_Window(float x, float alpha, float stretch, float m_width) - -*/ - -//------------------------------------------------------------------------------ -// Commonly useful functions -//------------------------------------------------------------------------------ - -// Returns 1 if point 'pt' is inside triangle with vertices 'v0', 'v1', and 'v2', and 0 if not -// Determines triangle center using barycentric coordinate transformation -// Adapted from: https://stackoverflow.com/questions/2049582/how-to-determine-if-a-point-is-in-a-2d-triangle -// Specifically the answer by user 'adreasdr' in addition to the comment by user 'urraka' on the answer from user 'Andreas Brinck' -// -// The notation here assumes v0x is the x-component of v0, v0y is the y-component of v0, etc. -// -static inline __attribute__((always_inline)) int MATH_Is_Point_In_Triangle(float v0x, float v0y, float v1x, float v1y, float v2x, float v2y, float ptx, float pty) -{ - float sdot = MATH_fipr(v0y, -v0x, v2y - v0y, v0x - v2x, v2x, v2y, ptx, pty); - float tdot = MATH_fipr(v0x, -v0y, v0y - v1y, v1x - v0x, v1y, v1x, ptx, pty); - - float areadot = MATH_fipr(-v1y, v0y, v0x, v1x, v2x, -v1x + v2x, v1y - v2y, v2y); - - // 'areadot' could be negative depending on the winding of the triangle - if(areadot < 0.0f) - { - sdot *= -1.0f; - tdot *= -1.0f; - areadot *= -1.0f; - } - - if( (sdot > 0.0f) && (tdot > 0.0f) && (areadot > (sdot + tdot)) ) - { - return 1; - } - - return 0; -} - -//------------------------------------------------------------------------------ -// Interpolation -//------------------------------------------------------------------------------ - -// Linear interpolation -static inline __attribute__((always_inline)) float MATH_Lerp(float a, float b, float t) -{ - return MATH_fmac(t, (b-a), a); -} - -// Speherical interpolation ('theta' in fsca units) -static inline __attribute__((always_inline)) float MATH_Slerp(float a, float b, float t, float theta) -{ - // a is an element of v0, b is an element of v1 - // v = ( v0 * sin(theta - t * theta) + v1 * sin(t * theta) ) / sin(theta) - // by using sine/cosine identities and properties, this can be optimized to: - // v = v0 * cos(-t * theta) + ( v0 * ( cos(theta) * sin(-t * theta) ) - sin(-t * theta) * v1 ) / sin(theta) - // which only requires two calls to fsca. - // Specifically, sin(a + b) = sin(a)cos(b) + cos(a)sin(b) & sin(-a) = -sin(a) - - // MATH_fsca_* functions return reverse-ordered complex numbers for speed reasons (i.e. normally sine is the imaginary part) - // This could be made even faster by using MATH_fsca_Int() with 'theta' and 't' as unsigned ints - -#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION - - RETURN_FSCA_STRUCT sine_cosine = MATH_fsca_Float(theta); - float sine_value_theta = sine_cosine.sine; - float cosine_value_theta = sine_cosine.cosine; - - RETURN_FSCA_STRUCT sine_cosine2 = MATH_fsca_Float(-t * theta); - float sine_value_minus_t_theta = sine_cosine2.sine; - float cosine_value_minus_t_theta = sine_cosine2.cosine; - -#else - - _Complex float sine_cosine = MATH_fsca_Float(theta); - float sine_value_theta = __real__ sine_cosine; - float cosine_value_theta = __imag__ sine_cosine; - - _Complex float sine_cosine2 = MATH_fsca_Float(-t * theta); - float sine_value_minus_t_theta = __real__ sine_cosine2; - float cosine_value_minus_t_theta = __imag__ sine_cosine2; - -#endif - - float numer = a * cosine_value_theta * sine_value_minus_t_theta - sine_value_minus_t_theta * b; - float output_float = a * cosine_value_minus_t_theta + MATH_Fast_Divide(numer, sine_value_theta); - - return output_float; -} - -//------------------------------------------------------------------------------ -// Fast Sinc (unnormalized, sin(x)/x version) -//------------------------------------------------------------------------------ -// -// Just pass in MATH_pi * x for normalized versions :) -// - -// Sinc function (fsca units) -static inline __attribute__((always_inline)) float MATH_Fast_Sincf(float x) -{ - if(x == 0.0f) - { - return 1.0f; - } - -#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION - - RETURN_FSCA_STRUCT sine_cosine = MATH_fsca_Float(x); - float sine_value = sine_cosine.sine; - -#else - - _Complex float sine_cosine = MATH_fsca_Float(x); - float sine_value = __real__ sine_cosine; - -#endif - - return MATH_Fast_Divide(sine_value, x); -} - -// Sinc function (degrees) -static inline __attribute__((always_inline)) float MATH_Fast_Sincf_Deg(float x) -{ - if(x == 0.0f) - { - return 1.0f; - } - -#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION - - RETURN_FSCA_STRUCT sine_cosine = MATH_fsca_Float_Deg(x); - float sine_value = sine_cosine.sine; - -#else - - _Complex float sine_cosine = MATH_fsca_Float_Deg(x); - float sine_value = __real__ sine_cosine; - -#endif - - return MATH_Fast_Divide(sine_value, x); -} - -// Sinc function (rads) -static inline __attribute__((always_inline)) float MATH_Fast_Sincf_Rad(float x) -{ - if(x == 0.0f) - { - return 1.0f; - } - -#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION - - RETURN_FSCA_STRUCT sine_cosine = MATH_fsca_Float_Rad(x); - float sine_value = sine_cosine.sine; - -#else - - _Complex float sine_cosine = MATH_fsca_Float_Rad(x); - float sine_value = __real__ sine_cosine; - -#endif - - return MATH_Fast_Divide(sine_value, x); -} - -//------------------------------------------------------------------------------ -// Kaiser Window -//------------------------------------------------------------------------------ -// -// These use regular divides because they only need to be run once during loads, -// not during runtime. -// -// Adapted from public domain NVidia Filter.cpp: -// https://github.com/castano/nvidia-texture-tools/blob/master/src/nvimage/Filter.cpp -// (as of 3/23/2020) -// - -// -// Kaiser window utility functions -// - -// Utility function for 0th-order bessel function -static inline __attribute__((always_inline)) float MATH_Bessel0(float x) -{ - const float EPSILON_RATIO = 1e-6f; - float xh, sum, power, ds, k; - // int k; - - xh = 0.5f * x; - sum = 1.0f; - power = 1.0f; - k = 0.0f; // k = 0; - ds = 1.0; - while (ds > (sum * EPSILON_RATIO)) - { - k += 1.0f; // ++k; - power = power * (xh / k); - ds = power * power; - sum = sum + ds; - } - - return sum; -} - -// Utility for kaiser window's expected sincf() format (radians) -static inline __attribute__((always_inline)) float MATH_NV_Sincf_Rad(const float x) -{ - // Does SH4 need this correction term? x86's sinf() definitely does, - // but SH4 might be ok with if(x == 0.0f) return 1.0f; Not sure. - if (MATH_fabs(x) < 0.0001f) // NV_EPSILON is 0.0001f - { - return 1.0f + x*x*(-1.0f/6.0f + (x*x)/120.0f); // 1.0 + x^2 * (-1/6 + x^2/120) - } - else - { - -#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION - - RETURN_FSCA_STRUCT sine_cosine = MATH_fsca_Float_Rad(x); - float sine_value = sine_cosine.sine; - -#else - - _Complex float sine_cosine = MATH_fsca_Float_Rad(x); - float sine_value = __real__ sine_cosine; - -#endif - - return sine_value / x; - } -} - -// Utility for kaiser window's expected sincf() format (fsca units) -static inline __attribute__((always_inline)) float MATH_NV_Sincf(const float x) -{ - // Does SH4 need this correction term? x86's sinf() definitely does, - // but SH4 might be ok with if(x == 0.0f) return 1.0f; Not sure. - if (MATH_fabs(x) < 0.0001f) // NV_EPSILON is 0.0001f - { - return 1.0f + x*x*(-1.0f/6.0f + (x*x)/120.0f); // 1.0 + x^2 * (-1/6 + x^2/120) - } - else - { - -#if __GNUC__ <= GNUC_FSCA_ERROR_VERSION - - RETURN_FSCA_STRUCT sine_cosine = MATH_fsca_Float(x); - float sine_value = sine_cosine.sine; - -#else - - _Complex float sine_cosine = MATH_fsca_Float(x); - float sine_value = __real__ sine_cosine; - -#endif - - return sine_value / x; - } -} - -// -// Kaiser window mipmap generator main functions -// - -// Generates mipmaps. Angle 'x' in radians. -static inline __attribute__((always_inline)) float MATH_Kaiser_Window_Rad(float x, float alpha, float stretch, float m_width) -{ - const float sinc_value = MATH_NV_Sincf_Rad(MATH_pi * x * stretch); - const float t = x / m_width; - - if ((1 - t * t) >= 0) - { - return sinc_value * MATH_Bessel0(alpha * MATH_fsqrt(1 - t * t)) / MATH_Bessel0(alpha); - } - else - { - return 0; - } -} - -// Generates mipmaps. Angle 'x' in fsca units. -static inline __attribute__((always_inline)) float MATH_Kaiser_Window(float x, float alpha, float stretch, float m_width) -{ - const float sinc_value = MATH_NV_Sincf(MATH_pi * x * stretch); - const float t = x / m_width; - - if ((1 - t * t) >= 0) - { - return sinc_value * MATH_Bessel0(alpha * MATH_fsqrt(1 - t * t)) / MATH_Bessel0(alpha); - } - else - { - return 0; - } -} - -//============================================================================== -// Miscellaneous Snippets -//============================================================================== -// -// The following snippets are best implemented manually in user code (they can't -// be put into their own functions without incurring performance penalties). -// -// They also serve as examples of how one might use the functions in this header. -// -/* - Normalize a vector (x, y, z) and get its pre-normalized magnitude (length) -*/ - -// -// Normalize a vector (x, y, z) and get its pre-normalized magnitude (length) -// -// magnitude = sqrt(x^2 + y^2 + z^2) -// (x, y, z) = 1/magnitude * (x, y, z) -// -// x, y, z, and magnitude are assumed already existing floats -// - -/* -- start -- - - // Don't need an 'else' with this (if length is 0, x = y = z = 0) - magnitude = 0; - - if(__builtin_expect(x || y || z, 1)) - { - temp = MATH_Sum_of_Squares(x, y, z, 0); // temp = x^2 + y^2 + z^2 + 0^2 - float normalizer = MATH_fsrra(temp); // 1/sqrt(temp) - x = normalizer * x; - y = normalizer * y; - z = normalizer * z; - magnitude = MATH_Fast_Invert(normalizer); - } - --- end -- */ - - -#endif /* __SH4_MATH_H_ */ - diff --git a/GL/platforms/software.c b/GL/platforms/software.c index 4245930..57940b6 100644 --- a/GL/platforms/software.c +++ b/GL/platforms/software.c @@ -75,17 +75,13 @@ void SceneListBegin(GPUList list) { vertex_counter = 0; } -GL_FORCE_INLINE void _glPerspectiveDivideVertex(Vertex* vertex, const float h) { +GL_FORCE_INLINE void _glPerspectiveDivideVertex(Vertex* vertex) { const float f = 1.0f / (vertex->w); - /* Convert to NDC and apply viewport */ - vertex->xyz[0] = __builtin_fmaf( - VIEWPORT.hwidth, vertex->xyz[0] * f, VIEWPORT.x_plus_hwidth - ); - - vertex->xyz[1] = h - __builtin_fmaf( - VIEWPORT.hheight, vertex->xyz[1] * f, VIEWPORT.y_plus_hheight - ); + /* Convert to screenspace */ + /* (note that vertices have already been viewport transformed) */ + vertex->xyz[0] = vertex->xyz[0] * f; + vertex->xyz[1] = vertex->xyz[1] * f; if(vertex->w == 1.0f) { vertex->xyz[2] = 1.0f / (1.0001f + vertex->xyz[2]); @@ -143,8 +139,6 @@ void SceneListSubmit(Vertex* v2, int n) { return; } - const float h = GetVideoMode()->height; - uint8_t visible_mask = 0; uint8_t counter = 0; @@ -182,19 +176,19 @@ void SceneListSubmit(Vertex* v2, int n) { switch(visible_mask) { case 15: /* All visible, but final vertex in strip */ { - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0); _glPushHeaderOrVertex(v0); - _glPerspectiveDivideVertex(v1, h); + _glPerspectiveDivideVertex(v1); _glPushHeaderOrVertex(v1); - _glPerspectiveDivideVertex(v2, h); + _glPerspectiveDivideVertex(v2); _glPushHeaderOrVertex(v2); } break; case 7: /* All visible, push the first vertex and move on */ - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0); _glPushHeaderOrVertex(v0); break; case 9: @@ -210,13 +204,13 @@ void SceneListSubmit(Vertex* v2, int n) { _glClipEdge(v2, v0, b); b->flags = GPU_CMD_VERTEX_EOL; - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0); _glPushHeaderOrVertex(v0); - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a); _glPushHeaderOrVertex(a); - _glPerspectiveDivideVertex(b, h); + _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); } break; @@ -233,13 +227,13 @@ void SceneListSubmit(Vertex* v2, int n) { _glClipEdge(v2, v0, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0); _glPushHeaderOrVertex(v0); - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a); _glPushHeaderOrVertex(a); - _glPerspectiveDivideVertex(b, h); + _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); _glPushHeaderOrVertex(b); } @@ -262,13 +256,13 @@ void SceneListSubmit(Vertex* v2, int n) { _glClipEdge(v1, v2, b); b->flags = v2->flags; - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a); _glPushHeaderOrVertex(a); - _glPerspectiveDivideVertex(c, h); + _glPerspectiveDivideVertex(c); _glPushHeaderOrVertex(c); - _glPerspectiveDivideVertex(b, h); + _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); } break; @@ -285,19 +279,19 @@ void SceneListSubmit(Vertex* v2, int n) { _glClipEdge(v2, v0, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0); _glPushHeaderOrVertex(v0); _glClipEdge(v1, v2, a); a->flags = v2->flags; - _glPerspectiveDivideVertex(c, h); + _glPerspectiveDivideVertex(c); _glPushHeaderOrVertex(c); - _glPerspectiveDivideVertex(b, h); + _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a); _glPushHeaderOrVertex(c); _glPushHeaderOrVertex(a); } @@ -319,17 +313,17 @@ void SceneListSubmit(Vertex* v2, int n) { _glClipEdge(v1, v2, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a); _glPushHeaderOrVertex(a); if(counter % 2 == 1) { _glPushHeaderOrVertex(a); } - _glPerspectiveDivideVertex(b, h); + _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); - _glPerspectiveDivideVertex(c, h); + _glPerspectiveDivideVertex(c); _glPushHeaderOrVertex(c); } break; @@ -349,15 +343,15 @@ void SceneListSubmit(Vertex* v2, int n) { _glClipEdge(v1, v2, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0); _glPushHeaderOrVertex(v0); - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a); _glPushHeaderOrVertex(a); - _glPerspectiveDivideVertex(c, h); + _glPerspectiveDivideVertex(c); _glPushHeaderOrVertex(c); - _glPerspectiveDivideVertex(b, h); + _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); c->flags = GPU_CMD_VERTEX_EOL; @@ -380,15 +374,15 @@ void SceneListSubmit(Vertex* v2, int n) { _glClipEdge(v1, v2, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(v0, h); + _glPerspectiveDivideVertex(v0); _glPushHeaderOrVertex(v0); - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a); _glPushHeaderOrVertex(a); - _glPerspectiveDivideVertex(c, h); + _glPerspectiveDivideVertex(c); _glPushHeaderOrVertex(c); - _glPerspectiveDivideVertex(b, h); + _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); _glPushHeaderOrVertex(c); } @@ -411,17 +405,17 @@ void SceneListSubmit(Vertex* v2, int n) { _glClipEdge(v2, v0, b); b->flags = GPU_CMD_VERTEX; - _glPerspectiveDivideVertex(a, h); + _glPerspectiveDivideVertex(a); _glPushHeaderOrVertex(a); - _glPerspectiveDivideVertex(c, h); + _glPerspectiveDivideVertex(c); _glPushHeaderOrVertex(c); - _glPerspectiveDivideVertex(b, h); + _glPerspectiveDivideVertex(b); _glPushHeaderOrVertex(b); _glPushHeaderOrVertex(c); - _glPerspectiveDivideVertex(d, h); + _glPerspectiveDivideVertex(d); _glPushHeaderOrVertex(d); } break; @@ -625,34 +619,17 @@ void TransformVec4(float* v) { FASTCPY(v, ret, sizeof(float) * 4); } -void TransformVertices(Vertex* vertices, const int count) { - float ret[4]; - for(int i = 0; i < count; ++i, ++vertices) { - ret[0] = vertices->xyz[0]; - ret[1] = vertices->xyz[1]; - ret[2] = vertices->xyz[2]; - ret[3] = 1.0f; +void TransformVertex(float x, float y, float z, float w, float* oxyz, float* ow) { + float vec[4], ret[4]; + vec[0] = x; + vec[1] = y; + vec[2] = z; + vec[3] = w; - TransformVec4(ret); - - vertices->xyz[0] = ret[0]; - vertices->xyz[1] = ret[1]; - vertices->xyz[2] = ret[2]; - vertices->w = ret[3]; - } -} - -void TransformVertex(const float* xyz, const float* w, float* oxyz, float* ow) { - float ret[4]; - ret[0] = xyz[0]; - ret[1] = xyz[1]; - ret[2] = xyz[2]; - ret[3] = *w; - - TransformVec4(ret); + TransformVec4NoMod(vec, ret); oxyz[0] = ret[0]; oxyz[1] = ret[1]; oxyz[2] = ret[2]; - *ow = ret[3]; + *ow = ret[3]; } diff --git a/GL/platforms/software.h b/GL/platforms/software.h index 5fee317..d797ce3 100644 --- a/GL/platforms/software.h +++ b/GL/platforms/software.h @@ -7,9 +7,6 @@ #define PREFETCH(addr) do {} while(0) -#define MATH_Fast_Divide(n, d) (n / d) -#define MATH_fmac(a, b, c) (a * b + c) -#define MATH_Fast_Sqrt(x) sqrtf((x)) #define MATH_fsrra(x) (1.0f / sqrtf((x))) #define MATH_Fast_Invert(x) (1.0f / (x)) @@ -28,7 +25,7 @@ } while(0) #define VEC3_LENGTH(x, y, z, d) \ - d = MATH_Fast_Sqrt((x) * (x) + (y) * (y) + (z) * (z)) + d = sqrtf((x) * (x) + (y) * (y) + (z) * (z)) #define VEC3_DOT(x1, y1, z1, x2, y2, z2, d) \ d = (x1 * x2) + (y1 * y2) + (z1 * z2) @@ -52,8 +49,7 @@ static inline void TransformNormalNoMod(const float* xIn, float* xOut) { (void) xOut; } -void TransformVertices(Vertex* vertices, const int count); -void TransformVertex(const float* xyz, const float* w, float* oxyz, float* ow); +void TransformVertex(float x, float y, float z, float w, float* oxyz, float* ow); void InitGPU(_Bool autosort, _Bool fsaa); diff --git a/GL/private.h b/GL/private.h index 5b11c52..cc42dae 100644 --- a/GL/private.h +++ b/GL/private.h @@ -25,6 +25,7 @@ extern void* memcpy4 (void *dest, const void *src, size_t count); #define GL_NO_INSTRUMENT inline __attribute__((no_instrument_function)) #define GL_INLINE_DEBUG GL_NO_INSTRUMENT __attribute__((always_inline)) #define GL_FORCE_INLINE static GL_INLINE_DEBUG +#define GL_NO_INLINE __attribute__((noinline)) #define _GL_UNUSED(x) (void)(x) #define _PACK4(v) ((v * 0xF) / 0xFF) @@ -104,20 +105,6 @@ typedef struct { AlignedVector vector; } PolyList; -typedef struct { - GLint x; - GLint y; - GLint width; - GLint height; - - float x_plus_hwidth; - float y_plus_hheight; - float hwidth; /* width * 0.5f */ - float hheight; /* height * 0.5f */ -} Viewport; - -extern Viewport VIEWPORT; - typedef struct { /* Palette data is always stored in RAM as RGBA8888 and packed as ARGB8888 * when uploaded to the PVR */ @@ -273,6 +260,12 @@ do { \ memcpy_vertex(b, &c); \ } while(0) +#ifdef __DREAMCAST__ +#define fast_rsqrt(x) frsqrt(x) +#else +#define fast_rsqrt(x) (1.0f / __builtin_sqrtf(x)) +#endif + /* ClipVertex doesn't have room for these, so we need to parse them * out separately. Potentially 'w' will be housed here if we support oargb */ typedef struct { @@ -334,6 +327,9 @@ void _glMatrixLoadModelViewProjection(); extern GLfloat DEPTH_RANGE_MULTIPLIER_L; extern GLfloat DEPTH_RANGE_MULTIPLIER_H; +extern GLfloat HALF_LINE_WIDTH; +extern GLfloat HALF_POINT_SIZE; + Matrix4x4* _glGetProjectionMatrix(); Matrix4x4* _glGetModelViewMatrix(); @@ -350,6 +346,7 @@ typedef struct { GLsizei stride; // 4 GLint size; // 4 } AttribPointer; +typedef void (*ReadAttributeFunc)(const GLubyte*, GLubyte*); typedef struct { AttribPointer vertex; // 16 @@ -357,25 +354,33 @@ typedef struct { AttribPointer uv; // 48 AttribPointer st; // 64 AttribPointer normal; // 80 - AttribPointer padding; // 96 + + GLuint enabled; // list of currently enabled/used attributes + GLuint dirty; // list of attributes that need state recalculating + GLboolean fast_path; + + ReadAttributeFunc vertex_func; + ReadAttributeFunc colour_func; + ReadAttributeFunc uv_func; + ReadAttributeFunc st_func; + ReadAttributeFunc normal_func; } AttribPointerList; +extern AttribPointerList ATTRIB_LIST; + GLboolean _glCheckValidEnum(GLint param, GLint* values, const char* func); GLuint* _glGetEnabledAttributes(); -AttribPointer* _glGetVertexAttribPointer(); -AttribPointer* _glGetDiffuseAttribPointer(); -AttribPointer* _glGetNormalAttribPointer(); -AttribPointer* _glGetUVAttribPointer(); -AttribPointer* _glGetSTAttribPointer(); -GLenum _glGetShadeModel(); +GL_NO_INLINE void _glUpdateAttributes(); +GLenum _glGetShadeModel(); TextureObject* _glGetTexture0(); TextureObject* _glGetTexture1(); TextureObject* _glGetBoundTexture(); extern GLubyte ACTIVE_TEXTURE; extern GLboolean TEXTURES_ENABLED[]; +extern GLubyte ACTIVE_CLIENT_TEXTURE; GLubyte _glGetActiveTexture(); GLint _glGetTextureInternalFormat(); @@ -399,8 +404,8 @@ GLboolean _glIsFogEnabled(); GLenum _glGetDepthFunc(); GLenum _glGetCullFace(); GLenum _glGetFrontFace(); -GLenum _glGetBlendSourceFactor(); -GLenum _glGetBlendDestFactor(); +GLenum _glGetGpuBlendSrcFactor(); +GLenum _glGetGpuBlendDstFactor(); extern PolyList OP_LIST; extern PolyList PT_LIST; @@ -426,98 +431,9 @@ GLboolean _glIsColorMaterialEnabled(); GLboolean _glIsNormalizeEnabled(); -extern AttribPointerList ATTRIB_POINTERS; - -extern GLuint ENABLED_VERTEX_ATTRIBUTES; -extern GLuint FAST_PATH_ENABLED; - -GL_FORCE_INLINE GLuint _glIsVertexDataFastPathCompatible() { - /* The fast path is enabled when all enabled elements of the vertex - * match the output format. This means: - * - * xyz == 3f - * uv == 2f - * rgba == argb4444 - * st == 2f - * normal == 3f - * - * When this happens we do inline straight copies of the enabled data - * and transforms for positions and normals happen while copying. - */ - - - - if((ENABLED_VERTEX_ATTRIBUTES & VERTEX_ENABLED_FLAG)) { - if(ATTRIB_POINTERS.vertex.size != 3 || ATTRIB_POINTERS.vertex.type != GL_FLOAT) { - return GL_FALSE; - } - } - - if((ENABLED_VERTEX_ATTRIBUTES & UV_ENABLED_FLAG)) { - if(ATTRIB_POINTERS.uv.size != 2 || ATTRIB_POINTERS.uv.type != GL_FLOAT) { - return GL_FALSE; - } - } - - if((ENABLED_VERTEX_ATTRIBUTES & DIFFUSE_ENABLED_FLAG)) { - /* FIXME: Shouldn't this be a reversed format? */ - if(ATTRIB_POINTERS.colour.size != GL_BGRA || ATTRIB_POINTERS.colour.type != GL_UNSIGNED_BYTE) { - return GL_FALSE; - } - } - - if((ENABLED_VERTEX_ATTRIBUTES & ST_ENABLED_FLAG)) { - if(ATTRIB_POINTERS.st.size != 2 || ATTRIB_POINTERS.st.type != GL_FLOAT) { - return GL_FALSE; - } - } - - if((ENABLED_VERTEX_ATTRIBUTES & NORMAL_ENABLED_FLAG)) { - if(ATTRIB_POINTERS.normal.size != 3 || ATTRIB_POINTERS.normal.type != GL_FLOAT) { - return GL_FALSE; - } - } - - return GL_TRUE; -} - -GL_FORCE_INLINE GLuint _glRecalcFastPath() { - FAST_PATH_ENABLED = _glIsVertexDataFastPathCompatible(); - return FAST_PATH_ENABLED; -} - extern GLboolean IMMEDIATE_MODE_ACTIVE; -extern GLenum LAST_ERROR; -extern char ERROR_FUNCTION[64]; - -GL_FORCE_INLINE const char* _glErrorEnumAsString(GLenum error) { - switch(error) { - case GL_INVALID_ENUM: return "GL_INVALID_ENUM"; - case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY"; - case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION"; - case GL_INVALID_VALUE: return "GL_INVALID_VALUE"; - default: - return "GL_UNKNOWN_ERROR"; - } -} - -GL_FORCE_INLINE void _glKosThrowError(GLenum error, const char *function) { - if(LAST_ERROR == GL_NO_ERROR) { - LAST_ERROR = error; - sprintf(ERROR_FUNCTION, "%s\n", function); - fprintf(stderr, "GL ERROR: %s when calling %s\n", _glErrorEnumAsString(LAST_ERROR), ERROR_FUNCTION); - } -} - -GL_FORCE_INLINE GLubyte _glKosHasError() { - return (LAST_ERROR != GL_NO_ERROR) ? GL_TRUE : GL_FALSE; -} - -GL_FORCE_INLINE void _glKosResetError() { - LAST_ERROR = GL_NO_ERROR; - sprintf(ERROR_FUNCTION, "\n"); -} +GL_NO_INLINE void _glKosThrowError(GLenum error, const char *function); GL_FORCE_INLINE GLboolean _glCheckImmediateModeInactive(const char* func) { /* Returns 1 on error */ @@ -529,13 +445,7 @@ GL_FORCE_INLINE GLboolean _glCheckImmediateModeInactive(const char* func) { return GL_FALSE; } -typedef struct { - float n[3]; // 12 bytes - float finalColour[4]; //28 bytes - uint32_t padding; // 32 bytes -} EyeSpaceData; - -extern void _glPerformLighting(Vertex* vertices, EyeSpaceData *es, const uint32_t count); +extern void _glPerformLighting(Vertex* vertices, VertexExtra* extra, const uint32_t count); unsigned char _glIsClippingEnabled(); void _glEnableClipping(unsigned char v); diff --git a/GL/state.c b/GL/state.c index 52f2656..04003f4 100644 --- a/GL/state.c +++ b/GL/state.c @@ -3,7 +3,8 @@ #include #include "private.h" - +GLfloat HALF_LINE_WIDTH = 1.0f / 2.0f; +GLfloat HALF_POINT_SIZE = 1.0f / 2.0f; static struct { GLboolean is_dirty; @@ -80,9 +81,7 @@ static struct { .color_control = GL_SINGLE_COLOR, .color_material_mode = GL_AMBIENT_AND_DIFFUSE, .color_material_mask = AMBIENT_MASK | DIFFUSE_MASK, - .lights = {0}, .enabled_light_count = 0, - .material = {0}, .shade_model = GL_SMOOTH }; @@ -218,12 +217,54 @@ GLboolean _glIsNormalizeEnabled() { return GPUState.normalize_enabled; } -GLenum _glGetBlendSourceFactor() { - return GPUState.blend_sfactor; +GLenum _glGetGpuBlendSrcFactor() { + switch(GPUState.blend_sfactor) { + case GL_ZERO: + return GPU_BLEND_ZERO; + case GL_SRC_ALPHA: + return GPU_BLEND_SRCALPHA; + case GL_DST_COLOR: + return GPU_BLEND_DESTCOLOR; + case GL_DST_ALPHA: + return GPU_BLEND_DESTALPHA; + case GL_ONE_MINUS_DST_COLOR: + return GPU_BLEND_INVDESTCOLOR; + case GL_ONE_MINUS_SRC_ALPHA: + return GPU_BLEND_INVSRCALPHA; + case GL_ONE_MINUS_DST_ALPHA: + return GPU_BLEND_INVDESTALPHA; + case GL_ONE: + return GPU_BLEND_ONE; + default: + fprintf(stderr, "Invalid src blend mode: %u\n", (unsigned int)GPUState.blend_sfactor); + return GPU_BLEND_ONE; + } } -GLenum _glGetBlendDestFactor() { - return GPUState.blend_dfactor; +GLenum _glGetGpuBlendDstFactor() { + switch(GPUState.blend_dfactor) { + case GL_ZERO: + return GPU_BLEND_ZERO; + case GL_SRC_ALPHA: + return GPU_BLEND_SRCALPHA; + case GL_SRC_COLOR: + // actually 'src' color in PVR2 when used as dst blend factor + return GPU_BLEND_DESTCOLOR; + case GL_DST_ALPHA: + return GPU_BLEND_DESTALPHA; + case GL_ONE_MINUS_SRC_COLOR: + // actually 'src' color in PVR2 when used as dst blend factor + return GPU_BLEND_INVDESTCOLOR; + case GL_ONE_MINUS_SRC_ALPHA: + return GPU_BLEND_INVSRCALPHA; + case GL_ONE_MINUS_DST_ALPHA: + return GPU_BLEND_INVDESTALPHA; + case GL_ONE: + return GPU_BLEND_ONE; + default: + fprintf(stderr, "Invalid dst blend mode: %u\n", (unsigned int)GPUState.blend_dfactor); + return GPU_BLEND_ONE; + } } @@ -497,9 +538,12 @@ GLAPI void APIENTRY glEnable(GLenum cap) { case GL_TEXTURE_TWIDDLE_KOS: _glSetTextureTwiddle(GL_TRUE); break; - default: - _glKosThrowError(GL_INVALID_VALUE, __func__); - break; + case GL_MULTISAMPLE: + // Not supported, but not an error + break; + default: + _glKosThrowError(GL_INVALID_VALUE, __func__); + break; } } @@ -603,9 +647,12 @@ GLAPI void APIENTRY glDisable(GLenum cap) { case GL_TEXTURE_TWIDDLE_KOS: _glSetTextureTwiddle(GL_FALSE); break; - default: - _glKosThrowError(GL_INVALID_VALUE, __func__); - break; + case GL_MULTISAMPLE: + // Not supported, but not an error + break; + default: + _glKosThrowError(GL_INVALID_VALUE, __func__); + break; } } @@ -632,14 +679,14 @@ GLAPI void APIENTRY glClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { /* Depth Testing */ GLAPI void APIENTRY glClearDepthf(GLfloat depth) { - glClearDepth(depth); -} - -GLAPI void APIENTRY glClearDepth(GLfloat depth) { /* We reverse because using invW means that farther Z == lower number */ GPUSetClearDepth(MIN(1.0f - depth, PVR_MIN_Z)); } +GLAPI void APIENTRY glClearDepth(GLdouble depth) { + glClearDepthf(depth); +} + GLAPI void APIENTRY glDrawBuffer(GLenum mode) { _GL_UNUSED(mode); @@ -727,7 +774,11 @@ GLAPI void APIENTRY glAlphaFunc(GLenum func, GLclampf ref) { } void glLineWidth(GLfloat width) { - _GL_UNUSED(width); + HALF_LINE_WIDTH = width / 2.0f; +} + +void glPointSize(GLfloat size) { + HALF_POINT_SIZE = size / 2.0f; } void glPolygonOffset(GLfloat factor, GLfloat units) { diff --git a/GL/texture.c b/GL/texture.c index 35ad164..6bcfae1 100644 --- a/GL/texture.c +++ b/GL/texture.c @@ -78,15 +78,16 @@ void build_twiddle_table(int32_t w, int32_t h) { } } -/* Given a 0-based texel location, and an image width/height. Return the - * new 0-based texel location */ -GL_FORCE_INLINE uint32_t twid_location(uint32_t i, uint32_t w, uint32_t h) { +static void twid_prepare_table(uint32_t w, uint32_t h) { if(TWIDDLE_TABLE.width != w || TWIDDLE_TABLE.height != h || !TWIDDLE_TABLE.table) { build_twiddle_table(w, h); } +} - uint32_t ret = TWIDDLE_TABLE.table[i]; - return ret; +/* Given a 0-based texel location, returns new 0-based texel location */ +/* NOTE: twid_prepare_table must have been called beforehand for correct behaviour */ +GL_FORCE_INLINE uint32_t twid_location(uint32_t i) { + return TWIDDLE_TABLE.table[i]; } @@ -1228,55 +1229,69 @@ static int _determineConversion(GLint internalFormat, GLenum format, GLenum type bool twiddle; bool pack; // If true, each value is packed after conversion into half-bytes } conversions [] = { - {_a8_to_argb4444, GL_ARGB4444_KOS, GL_ALPHA, GL_UNSIGNED_BYTE, false, false}, - {_rgba8888_to_argb4444, GL_ARGB4444_KOS, GL_RGBA, GL_UNSIGNED_BYTE, false, false}, - {_rgba4444_to_argb4444, GL_ARGB4444_KOS, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, false, false}, - {_rgba4444_to_argb4444, GL_ARGB4444_TWID_KOS, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, true, false}, - {NULL, GL_ARGB4444_KOS, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, false, false}, - {NULL, GL_ARGB4444_TWID_KOS, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV_TWID_KOS, false, false}, - {_rgba8888_to_argb4444, GL_ARGB4444_TWID_KOS, GL_RGBA, GL_UNSIGNED_BYTE, true, false}, - {NULL, GL_ARGB1555_KOS, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, false, false}, - {_argb1555_to_argb4444, GL_ARGB4444_TWID_KOS, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, true, false}, - {NULL, GL_ARGB1555_TWID_KOS, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV_TWID_KOS, false, false}, - {_rgba8888_to_rgb565, GL_RGB565_KOS, GL_RGBA, GL_UNSIGNED_BYTE, false, false}, - {_r8_to_rgb565, GL_RGB565_KOS, GL_RED, GL_UNSIGNED_BYTE, false, false}, - {_rgb888_to_rgb565, GL_RGB565_KOS, GL_RGB, GL_UNSIGNED_BYTE, false, false}, - {_rgba8888_to_rgb565, GL_RGB565_KOS, GL_RGBA, GL_UNSIGNED_BYTE, false, false}, - {_r8_to_rgb565, GL_RGB565_KOS, GL_RED, GL_UNSIGNED_BYTE, false, false}, - {NULL, GL_RGB565_KOS, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, false, false}, - {NULL, GL_RGB565_TWID_KOS, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_TWID_KOS, false, false}, - {NULL, GL_RGB565_TWID_KOS, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, true, false}, - {_rgb888_to_rgb565, GL_RGB565_TWID_KOS, GL_RGB, GL_UNSIGNED_BYTE, true, false}, - {NULL, GL_COLOR_INDEX8_EXT, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, false, false}, - {NULL, GL_COLOR_INDEX8_EXT, GL_COLOR_INDEX, GL_BYTE, false, false}, - {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, true, false}, - {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX, GL_BYTE, true, false}, - {NULL, GL_COLOR_INDEX4_EXT, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, false, true}, - {NULL, GL_COLOR_INDEX4_EXT, GL_COLOR_INDEX, GL_BYTE, false, true}, + {_rgba8888_to_argb4444, GL_ARGB4444_KOS, GL_RGBA, GL_UNSIGNED_BYTE, false, false}, + {_rgba8888_to_argb4444, GL_ARGB4444_TWID_KOS, GL_RGBA, GL_UNSIGNED_BYTE, true, false}, + {_a8_to_argb4444, GL_ARGB4444_KOS, GL_ALPHA, GL_UNSIGNED_BYTE, false, false}, + {_a8_to_argb4444, GL_ARGB4444_TWID_KOS, GL_ALPHA, GL_UNSIGNED_BYTE, true, false}, - {NULL, GL_COLOR_INDEX4_EXT, GL_COLOR_INDEX4_EXT, GL_UNSIGNED_BYTE, false, false}, - {NULL, GL_COLOR_INDEX4_EXT, GL_COLOR_INDEX4_EXT, GL_BYTE, false, false}, - {NULL, GL_COLOR_INDEX4_TWID_KOS, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, true, true}, - {NULL, GL_COLOR_INDEX4_TWID_KOS, GL_COLOR_INDEX, GL_BYTE, true, true}, + {_rgba4444_to_argb4444, GL_ARGB4444_KOS, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, false, false}, + {_rgba4444_to_argb4444, GL_ARGB4444_TWID_KOS, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, true, false}, + {NULL, GL_ARGB4444_KOS, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, false, false}, + {NULL, GL_ARGB4444_TWID_KOS, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, true, false}, - {NULL, GL_COLOR_INDEX4_TWID_KOS, GL_COLOR_INDEX4_EXT, GL_UNSIGNED_BYTE, true, false}, - {NULL, GL_COLOR_INDEX4_TWID_KOS, GL_COLOR_INDEX4_EXT, GL_BYTE, true, false}, + {NULL, GL_ARGB4444_TWID_KOS, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV_TWID_KOS, false, false}, + + {_argb1555_to_argb4444, GL_ARGB4444_KOS, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, false, false}, + {_argb1555_to_argb4444, GL_ARGB4444_TWID_KOS, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, true, false}, + + {NULL, GL_ARGB1555_KOS, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, false, false}, + {NULL, GL_ARGB1555_TWID_KOS, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, true, false}, + + {NULL, GL_ARGB1555_TWID_KOS, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV_TWID_KOS, false, false}, + + {_r8_to_rgb565, GL_RGB565_KOS, GL_RED, GL_UNSIGNED_BYTE, false, false}, + {_r8_to_rgb565, GL_RGB565_TWID_KOS, GL_RED, GL_UNSIGNED_BYTE, true, false}, + {_rgb888_to_rgb565, GL_RGB565_KOS, GL_RGB, GL_UNSIGNED_BYTE, false, false}, + {_rgb888_to_rgb565, GL_RGB565_TWID_KOS, GL_RGB, GL_UNSIGNED_BYTE, true, false}, + {_rgba8888_to_rgb565, GL_RGB565_KOS, GL_RGBA, GL_UNSIGNED_BYTE, false, false}, + {_rgba8888_to_rgb565, GL_RGB565_TWID_KOS, GL_RGBA, GL_UNSIGNED_BYTE, true, false}, + + {NULL, GL_RGB565_KOS, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, false, false}, + {NULL, GL_RGB565_TWID_KOS, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, true, false}, + {NULL, GL_RGB565_TWID_KOS, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_TWID_KOS, false, false}, + + {NULL, GL_COLOR_INDEX8_EXT, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, false, false}, + {NULL, GL_COLOR_INDEX8_EXT, GL_COLOR_INDEX, GL_BYTE, false, false}, + {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, true, false}, + {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX, GL_BYTE, true, false}, + + {NULL, GL_COLOR_INDEX8_EXT, GL_COLOR_INDEX8_EXT, GL_UNSIGNED_BYTE, false, false}, + {NULL, GL_COLOR_INDEX8_EXT, GL_COLOR_INDEX8_EXT, GL_BYTE, false, false}, + {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX8_EXT, GL_UNSIGNED_BYTE, true, false}, + {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX8_EXT, GL_BYTE, true, false}, - {NULL, GL_COLOR_INDEX8_EXT, GL_COLOR_INDEX8_EXT, GL_UNSIGNED_BYTE, false, false}, - {NULL, GL_COLOR_INDEX8_EXT, GL_COLOR_INDEX8_EXT, GL_BYTE, false, false}, {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX8_TWID_KOS, GL_UNSIGNED_BYTE, false, false}, - {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX8_TWID_KOS, GL_BYTE, false, false}, - {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX8_EXT, GL_UNSIGNED_BYTE, true, false}, - {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX8_EXT, GL_BYTE, true, false}, + {NULL, GL_COLOR_INDEX8_TWID_KOS, GL_COLOR_INDEX8_TWID_KOS, GL_BYTE, false, false}, - {NULL, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false, false}, - {NULL, GL_RGBA8, GL_RGBA, GL_BYTE, false, false}, - {_rgb888_to_rgba8888, GL_RGBA8, GL_RGB, GL_UNSIGNED_BYTE, false, false}, - {_rgb888_to_rgba8888, GL_RGBA8, GL_RGB, GL_BYTE, false, false}, - {_rgb888_to_argb4444, GL_RGBA4, GL_RGB, GL_UNSIGNED_BYTE, false, false}, - {_rgb888_to_argb4444, GL_RGBA4, GL_RGB, GL_BYTE, false, false}, + {NULL, GL_COLOR_INDEX4_EXT, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, false, true}, + {NULL, GL_COLOR_INDEX4_EXT, GL_COLOR_INDEX, GL_BYTE, false, true}, + {NULL, GL_COLOR_INDEX4_TWID_KOS, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, true, true}, + {NULL, GL_COLOR_INDEX4_TWID_KOS, GL_COLOR_INDEX, GL_BYTE, true, true}, + + {NULL, GL_COLOR_INDEX4_EXT, GL_COLOR_INDEX4_EXT, GL_UNSIGNED_BYTE, false, false}, + {NULL, GL_COLOR_INDEX4_EXT, GL_COLOR_INDEX4_EXT, GL_BYTE, false, false}, + {NULL, GL_COLOR_INDEX4_TWID_KOS, GL_COLOR_INDEX4_EXT, GL_UNSIGNED_BYTE, true, false}, + {NULL, GL_COLOR_INDEX4_TWID_KOS, GL_COLOR_INDEX4_EXT, GL_BYTE, true, false}, + + {NULL, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false, false}, + {NULL, GL_RGBA8, GL_RGBA, GL_BYTE, false, false}, + {_rgb888_to_rgba8888, GL_RGBA8, GL_RGB, GL_UNSIGNED_BYTE, false, false}, + {_rgb888_to_rgba8888, GL_RGBA8, GL_RGB, GL_BYTE, false, false}, + + {_rgb888_to_argb4444, GL_RGBA4, GL_RGB, GL_UNSIGNED_BYTE, false, false}, + {_rgb888_to_argb4444, GL_RGBA4, GL_RGB, GL_BYTE, false, false}, {_rgba8888_to_argb4444, GL_RGBA4, GL_RGBA, GL_UNSIGNED_BYTE, false, false}, - {_rgba8888_to_argb4444, GL_RGBA4, GL_RGBA, GL_BYTE, false, false}, + {_rgba8888_to_argb4444, GL_RGBA4, GL_RGBA, GL_BYTE, false, false}, }; for(size_t i = 0; i < sizeof(conversions) / sizeof(struct Entry); ++i) { @@ -1465,6 +1480,79 @@ static bool _glTexImage2DValidate(GLenum target, GLint level, GLint internalForm return true; } +static bool _glTexSubImage2DValidate(GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, GLenum format, GLenum type, + GLsizei textureWidth, GLsizei textureHeight) { + if (target != GL_TEXTURE_2D) { + INFO_MSG("Invalid target. Only GL_TEXTURE_2D is supported."); + _glKosThrowError(GL_INVALID_ENUM, __func__); + return false; + } + + if (width > 1024 || height > 1024) { + INFO_MSG("Invalid subimage size. Maximum 1024x1024."); + _glKosThrowError(GL_INVALID_VALUE, __func__); + return false; + } + + // Ensure format is valid + GLint validFormats[] = { + GL_ALPHA, + GL_LUMINANCE, + GL_INTENSITY, + GL_LUMINANCE_ALPHA, + GL_RED, + GL_RGB, + GL_RGBA, + GL_BGRA, + GL_COLOR_INDEX, + GL_COLOR_INDEX4_EXT, /* Extension, for glCompressedTexImage pass-thru */ + GL_COLOR_INDEX8_EXT, /* Extension, for glCompressedTexImage pass-thru */ + GL_COLOR_INDEX4_TWID_KOS, /* Extension, for glCompressedTexImage pass-thru */ + GL_COLOR_INDEX8_TWID_KOS, /* Extension, for glCompressedTexImage pass-thru */ + 0 + }; + + if (_glCheckValidEnum(format, validFormats, __func__) != 0) { + return false; + } + + // Validate type + if (format != GL_COLOR_INDEX4_EXT && format != GL_COLOR_INDEX4_TWID_KOS) { + /* Use determineStride to see if type is valid */ + if (_determineStride(GL_RGBA, type) == -1) { + INFO_MSG("Invalid pixel data type."); + _glKosThrowError(GL_INVALID_ENUM, __func__); + return false; + } + } + + // Validate offsets and dimensions using the underlying texture size + if (xoffset < 0 || yoffset < 0 || + (xoffset + width) > textureWidth || + (yoffset + height) > textureHeight) { + INFO_MSG("Subimage exceeds the dimensions of the texture."); + _glKosThrowError(GL_INVALID_VALUE, __func__); + return false; + } + + if (level < 0) { + INFO_MSG("Invalid mipmap level."); + _glKosThrowError(GL_INVALID_VALUE, __func__); + return false; + } + + // Ensure no border (since glTexSubImage2D doesn't allow it) + GLint border = 0; // No border allowed + if (border != 0) { + INFO_MSG("Border must be zero for glTexSubImage2D."); + _glKosThrowError(GL_INVALID_VALUE, __func__); + return false; + } + + return true; +} + static inline GLboolean is4BPPFormat(GLenum format) { return format == GL_COLOR_INDEX4_EXT || format == GL_COLOR_INDEX4_TWID_KOS; } @@ -1620,8 +1708,10 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, if(is4BPPFormat(internalFormat) && is4BPPFormat(format)) { // Special case twiddling. We have to unpack each src value // and repack into the right place + twid_prepare_table(width, height); + for(uint32_t i = 0; i < (width * height); ++i) { - uint32_t newLocation = twid_location(i, width, height); + uint32_t newLocation = twid_location(i); assert(newLocation < (width * height)); assert((newLocation / 2) < destBytes); @@ -1641,8 +1731,10 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, } } } else { + twid_prepare_table(width, height); + for(uint32_t i = 0; i < (width * height); ++i) { - uint32_t newLocation = twid_location(i, width, height); + uint32_t newLocation = twid_location(i); dst = conversionBuffer + (destStride * newLocation); for(int j = 0; j < destStride; ++j) @@ -1653,8 +1745,10 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat, } } else if(needs_conversion == 3) { // Convert + twiddle + twid_prepare_table(width, height); + for(uint32_t i = 0; i < (width * height); ++i) { - uint32_t newLocation = twid_location(i, width, height); + uint32_t newLocation = twid_location(i); dst = conversionBuffer + (destStride * newLocation); src = data + (sourceStride * i); conversion(src, dst); @@ -1977,19 +2071,139 @@ GLAPI void APIENTRY glGetColorTableParameterfvEXT(GLenum target, GLenum pname, G _glKosThrowError(GL_INVALID_OPERATION, __func__); } -GLAPI void APIENTRY glTexSubImage2D( - GLenum target, GLint level, GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) { - _GL_UNUSED(target); - _GL_UNUSED(level); - _GL_UNUSED(xoffset); - _GL_UNUSED(yoffset); - _GL_UNUSED(width); - _GL_UNUSED(height); - _GL_UNUSED(format); - _GL_UNUSED(type); - _GL_UNUSED(pixels); - gl_assert(0 && "Not Implemented"); +void APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, GLenum format, + GLenum type, const GLvoid *data) { + TRACE(); + + gl_assert(ACTIVE_TEXTURE < MAX_GLDC_TEXTURE_UNITS); + TextureObject* active = TEXTURE_UNITS[ACTIVE_TEXTURE]; + + if (!active || !active->data) { + INFO_MSG("Called glTexSubImage2D on unbound or uninitialized texture"); + _glKosThrowError(GL_INVALID_OPERATION, __func__); + return; + } + + // Retrieve the dimensions of the currently bound texture + GLsizei textureWidth = active->width; + GLsizei textureHeight = active->height; + + if (!_glTexSubImage2DValidate(target, level, xoffset, yoffset, width, height, format, type, textureWidth, textureHeight)) { + INFO_MSG("Error: _glTexSubImage2DValidate failed\n"); + return; + } + + GLboolean isPaletted = ( + active->internalFormat == GL_COLOR_INDEX8_EXT || + active->internalFormat == GL_COLOR_INDEX4_EXT || + active->internalFormat == GL_COLOR_INDEX4_TWID_KOS || + active->internalFormat == GL_COLOR_INDEX8_TWID_KOS + ) ? GL_TRUE : GL_FALSE; + + GLenum cleanInternalFormat = _cleanInternalFormat(active->internalFormat); + + // Determine source stride + GLint sourceStride = _determineStride(format, type); + GLuint srcBytes = (width * height * sourceStride); + + // Calculate destination stride (this accounts for both POT and NPOT) + GLint destStride = _determineStrideInternal(cleanInternalFormat); + + // Calculate destBytes using the texture's full dimensions + GLuint destBytes = (textureWidth * textureHeight * destStride); + + TextureConversionFunc conversion; + int needs_conversion = _determineConversion(cleanInternalFormat, format, type, &conversion); + + // Adjust source bytes for 4bpp formats + if (format == GL_COLOR_INDEX4_EXT || format == GL_COLOR_INDEX4_TWID_KOS) { + srcBytes /= 2; + } + + if ((needs_conversion & CONVERSION_TYPE_PACK) == CONVERSION_TYPE_PACK) { + destBytes /= 2; + } else if (active->internalFormat == GL_COLOR_INDEX4_EXT || active->internalFormat == GL_COLOR_INDEX4_TWID_KOS) { + destBytes /= 2; + } + + if (needs_conversion < 0) { + _glKosThrowError(GL_INVALID_VALUE, __func__); + INFO_MSG("Couldn't find necessary texture conversion\n"); + return; + } + + // Calculate the starting point for the subregion in the texture data + GLubyte* targetData = active->data; + if (needs_conversion > 0) { + GLubyte* conversionBuffer = (GLubyte*) memalign(32, destBytes); + + const GLubyte* src = data; + GLubyte* dst = conversionBuffer; + + bool pack = (needs_conversion & CONVERSION_TYPE_PACK) == CONVERSION_TYPE_PACK; + needs_conversion &= ~CONVERSION_TYPE_PACK; + + // Only initialize the buffer with zeros if it's a partial update + if (xoffset != 0 || yoffset != 0 || width != textureWidth || height != textureHeight) { + memset(conversionBuffer, 0, destBytes); + } + if (needs_conversion == CONVERSION_TYPE_CONVERT) { + for (uint32_t y = 0; y < height; ++y) { + dst = conversionBuffer + ((y + yoffset) * textureWidth + xoffset) * destStride; + for (uint32_t x = 0; x < width; ++x) { + conversion(src, dst); + dst += destStride; + src += sourceStride; + } + } + } else if (needs_conversion == 2 || needs_conversion == 3) { + twid_prepare_table(textureWidth, textureHeight); + + for (uint32_t y = yoffset; y < yoffset + height; ++y) { + for (uint32_t x = xoffset; x < xoffset + width; ++x) { + uint32_t srcIndex = (y - yoffset) * width + (x - xoffset); + uint32_t newLocation = twid_location(y * textureWidth + x); + dst = conversionBuffer + (destStride * newLocation); + + if (needs_conversion == 3) { + conversion(src + srcIndex * sourceStride, dst); + } else { + memcpy(dst, src + srcIndex * sourceStride, destStride); + } + } + } + } + + if (pack) { + assert(isPaletted); + size_t dst_byte = 0; + for (size_t src_byte = 0; src_byte < destBytes; ++src_byte) { + uint8_t v = conversionBuffer[src_byte]; + + if (src_byte % 2 == 0) { + conversionBuffer[dst_byte] = (conversionBuffer[dst_byte] & 0xF) | ((v & 0xF) << 4); + } else { + conversionBuffer[dst_byte] = (conversionBuffer[dst_byte] & 0xF0) | (v & 0xF); + dst_byte++; + } + } + } + + // Copy the converted data to the texture + FASTCPY(targetData, conversionBuffer, destBytes); + + free(conversionBuffer); + } else { + // No conversion necessary, we can update data directly + for (GLsizei y = 0; y < height; ++y) { + GLsizei srcRowWidth = width * sourceStride; + GLubyte* destRow = targetData + ((y + yoffset) * textureWidth + xoffset) * destStride; + FASTCPY(destRow, (GLubyte*)data + y * srcRowWidth, srcRowWidth); + } + } + + _glGPUStateMarkDirty(); } GLAPI void APIENTRY glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { diff --git a/containers/aligned_vector.c b/containers/aligned_vector.c index f75459a..7048219 100644 --- a/containers/aligned_vector.c +++ b/containers/aligned_vector.c @@ -14,7 +14,6 @@ extern inline void* aligned_vector_resize(AlignedVector* vector, const uint32_t element_count); extern inline void* aligned_vector_extend(AlignedVector* vector, const uint32_t additional_count); -extern inline void* aligned_vector_reserve(AlignedVector* vector, uint32_t element_count); extern inline void* aligned_vector_push_back(AlignedVector* vector, const void* objs, uint32_t count); void aligned_vector_init(AlignedVector* vector, uint32_t element_size) { @@ -31,6 +30,31 @@ void aligned_vector_init(AlignedVector* vector, uint32_t element_size) { (void) ptr; } +void* aligned_vector_reserve(AlignedVector* vector, uint32_t element_count) { + AlignedVectorHeader* hdr = &vector->hdr; + + if(element_count < hdr->capacity) { + return aligned_vector_at(vector, element_count); + } + + uint32_t original_byte_size = (hdr->size * hdr->element_size); + + /* We overallocate so that we don't make small allocations during push backs */ + element_count = ROUND_TO_CHUNK_SIZE(element_count); + + uint32_t new_byte_size = (element_count * hdr->element_size); + uint8_t* original_data = vector->data; + + vector->data = (uint8_t*) memalign(0x20, new_byte_size); + assert(vector->data); + + AV_MEMCPY4(vector->data, original_data, original_byte_size); + free(original_data); + + hdr->capacity = element_count; + return vector->data + original_byte_size; +} + void aligned_vector_shrink_to_fit(AlignedVector* vector) { AlignedVectorHeader* const hdr = &vector->hdr; if(hdr->size == 0) { diff --git a/containers/aligned_vector.h b/containers/aligned_vector.h index d700b86..5d50956 100644 --- a/containers/aligned_vector.h +++ b/containers/aligned_vector.h @@ -27,10 +27,10 @@ static inline void* memalign(size_t alignment, size_t size) { #define AV_INLINE_DEBUG AV_NO_INSTRUMENT __attribute__((always_inline)) #define AV_FORCE_INLINE static AV_INLINE_DEBUG #endif +#define AV_NO_INLINE __attribute__((noinline)) #ifdef __DREAMCAST__ -#include AV_FORCE_INLINE void *AV_MEMCPY4(void *dest, const void *src, size_t len) { @@ -86,37 +86,16 @@ typedef struct { void aligned_vector_init(AlignedVector* vector, uint32_t element_size); +/* Resizes the backing array if necessary so that element_count elements can fit in the array */ +/* (note that only capacity is potentially changed, size is never changed) */ +AV_NO_INLINE void* aligned_vector_reserve(AlignedVector* vector, uint32_t element_count); + AV_FORCE_INLINE void* aligned_vector_at(const AlignedVector* vector, const uint32_t index) { const AlignedVectorHeader* hdr = &vector->hdr; assert(index < hdr->size); return vector->data + (index * hdr->element_size); } -AV_FORCE_INLINE void* aligned_vector_reserve(AlignedVector* vector, uint32_t element_count) { - AlignedVectorHeader* hdr = &vector->hdr; - - if(element_count < hdr->capacity) { - return aligned_vector_at(vector, element_count); - } - - uint32_t original_byte_size = (hdr->size * hdr->element_size); - - /* We overallocate so that we don't make small allocations during push backs */ - element_count = ROUND_TO_CHUNK_SIZE(element_count); - - uint32_t new_byte_size = (element_count * hdr->element_size); - uint8_t* original_data = vector->data; - - vector->data = (uint8_t*) memalign(0x20, new_byte_size); - assert(vector->data); - - AV_MEMCPY4(vector->data, original_data, original_byte_size); - free(original_data); - - hdr->capacity = element_count; - return vector->data + original_byte_size; -} - AV_FORCE_INLINE AlignedVectorHeader* aligned_vector_header(const AlignedVector* vector) { return (AlignedVectorHeader*) &vector->hdr; } diff --git a/include/GL/gl.h b/include/GL/gl.h index 028f900..c26f456 100644 --- a/include/GL/gl.h +++ b/include/GL/gl.h @@ -55,7 +55,7 @@ __BEGIN_DECLS #define GL_FRONT_FACE 0x0B46 /* Scissor box */ -#define GL_SCISSOR_TEST 0x0008 /* capability bit */ +#define GL_SCISSOR_TEST 0x0C11 #define GL_SCISSOR_BOX 0x0C10 /* Stencil actions */ @@ -109,7 +109,7 @@ __BEGIN_DECLS #define GL_SRC_ALPHA_SATURATE 0x0308 /* Misc texture constants */ -#define GL_TEXTURE_2D 0x0001 /* capability bit */ +#define GL_TEXTURE_2D 0x0DE1 #define GL_TEXTURE_WRAP_S 0x2802 #define GL_TEXTURE_WRAP_T 0x2803 #define GL_TEXTURE_MAG_FILTER 0x2800 @@ -204,7 +204,7 @@ __BEGIN_DECLS #define GL_CLIP_PLANE5 0x3005 /* Fog */ -#define GL_FOG 0x0004 /* capability bit */ +#define GL_FOG 0x0B60 #define GL_FOG_MODE 0x0B65 #define GL_FOG_DENSITY 0x0B62 #define GL_FOG_COLOR 0x0B66 @@ -226,7 +226,7 @@ __BEGIN_DECLS #define GL_FOG_HINT 0x0C54 /* Lighting constants */ -#define GL_LIGHTING 0x0b50 +#define GL_LIGHTING 0x0b50 #define GL_LIGHT0 0x4000 #define GL_LIGHT1 0x4001 @@ -446,7 +446,7 @@ __BEGIN_DECLS #define GLshort short #define GLint int #define GLfloat float -#define GLdouble float +#define GLdouble double #define GLvoid void #define GLushort unsigned short #define GLuint unsigned int @@ -454,7 +454,7 @@ __BEGIN_DECLS #define GLsizei unsigned int #define GLfixed const unsigned int #define GLclampf float -#define GLclampd float +#define GLclampd double #define GLubyte unsigned char #define GLbitfield unsigned int #define GLboolean unsigned char @@ -481,6 +481,16 @@ __BEGIN_DECLS #define GL_PACK_SKIP_PIXELS 0x0D04 #define GL_PACK_ALIGNMENT 0x0D05 +#define GL_MULTISAMPLE 0x809D +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_ALPHA_TO_ONE 0x809F +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_MULTISAMPLE_BIT 0x20000000 + #define GLAPI extern #define APIENTRY @@ -542,6 +552,10 @@ GLAPI GLvoid APIENTRY glRecti(GLint x1, GLint y1, GLint x2, GLint y2); GLAPI GLvoid APIENTRY glRectiv(const GLint *v1, const GLint *v2); #define glRectsv glRectiv +/* Primitive configuration */ +GLAPI void APIENTRY glLineWidth(GLfloat width); +GLAPI void APIENTRY glPointSize(GLfloat size); + /* Enable / Disable Capability */ /* Currently Supported Capabilities: GL_TEXTURE_2D @@ -565,12 +579,12 @@ GLAPI void APIENTRY glReadBuffer(GLenum mode); GLAPI void APIENTRY glDrawBuffer(GLenum mode); /* Depth Testing */ -GLAPI void APIENTRY glClearDepth(GLfloat depth); +GLAPI void APIENTRY glClearDepth(GLdouble depth); GLAPI void APIENTRY glClearDepthf(GLfloat depth); GLAPI void APIENTRY glDepthMask(GLboolean flag); GLAPI void APIENTRY glDepthFunc(GLenum func); -GLAPI void APIENTRY glDepthRange(GLclampf n, GLclampf f); -GLAPI void APIENTRY glDepthRangef(GLclampf n, GLclampf f); +GLAPI void APIENTRY glDepthRange(GLdouble n, GLdouble f); +GLAPI void APIENTRY glDepthRangef(GLfloat n, GLfloat f); /* Hints */ /* Currently Supported Capabilities: @@ -682,9 +696,9 @@ GLAPI void APIENTRY glScalef(GLfloat x, GLfloat y, GLfloat z); GLAPI void APIENTRY glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); #define glRotated glRotatef -GLAPI void APIENTRY glOrtho(GLfloat left, GLfloat right, - GLfloat bottom, GLfloat top, - GLfloat znear, GLfloat zfar); +GLAPI void APIENTRY glOrtho(GLdouble left, GLdouble right, + GLdouble bottom, GLdouble top, + GLdouble znear, GLdouble zfar); GLAPI void APIENTRY glViewport(GLint x, GLint y, GLsizei width, GLsizei height); @@ -692,9 +706,9 @@ GLAPI void APIENTRY glScissor(GLint x, GLint y, GLsizei width, GLsizei height); GLAPI void APIENTRY glKosGetMatrix(GLenum mode, GLfloat *params); -GLAPI void APIENTRY glFrustum(GLfloat left, GLfloat right, - GLfloat bottom, GLfloat top, - GLfloat znear, GLfloat zfar); +GLAPI void APIENTRY glFrustum(GLdouble left, GLdouble right, + GLdouble bottom, GLdouble top, + GLdouble znear, GLdouble zfar); /* Fog Functions - client must enable GL_FOG for this to take effect */ GLAPI void APIENTRY glFogi(GLenum pname, GLint param); @@ -732,7 +746,6 @@ GLAPI GLenum APIENTRY glGetError(void); /* Non Operational Stubs for portability */ GLAPI void APIENTRY glAlphaFunc(GLenum func, GLclampf ref); -GLAPI void APIENTRY glLineWidth(GLfloat width); GLAPI void APIENTRY glPolygonMode(GLenum face, GLenum mode); GLAPI void APIENTRY glPolygonOffset(GLfloat factor, GLfloat units); GLAPI void APIENTRY glGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params); diff --git a/include/GL/glext.h b/include/GL/glext.h index acd7763..565ed40 100644 --- a/include/GL/glext.h +++ b/include/GL/glext.h @@ -54,16 +54,6 @@ __BEGIN_DECLS #define GL_TRANSPOSE_TEXTURE_MATRIX_ARB 0x84E5 #define GL_TRANSPOSE_COLOR_MATRIX_ARB 0x84E6 -#define GL_MULTISAMPLE_ARB 0x809D -#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E -#define GL_SAMPLE_ALPHA_TO_ONE_ARB 0x809F -#define GL_SAMPLE_COVERAGE_ARB 0x80A0 -#define GL_SAMPLE_BUFFERS_ARB 0x80A8 -#define GL_SAMPLES_ARB 0x80A9 -#define GL_SAMPLE_COVERAGE_VALUE_ARB 0x80AA -#define GL_SAMPLE_COVERAGE_INVERT_ARB 0x80AB -#define GL_MULTISAMPLE_BIT_ARB 0x20000000 - #define GL_NORMAL_MAP_ARB 0x8511 #define GL_REFLECTION_MAP_ARB 0x8512 #define GL_TEXTURE_CUBE_MAP_ARB 0x8513 diff --git a/include/GL/glu.h b/include/GL/glu.h index 87842ae..7a7c4b5 100644 --- a/include/GL/glu.h +++ b/include/GL/glu.h @@ -30,9 +30,9 @@ GLAPI void APIENTRY gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar); /* gluLookAt - Set Camera Position for Rendering. */ -GLAPI void APIENTRY gluLookAt(GLfloat eyex, GLfloat eyey, GLfloat eyez, - GLfloat centerx, GLfloat centery, GLfloat centerz, - GLfloat upx, GLfloat upy, GLfloat upz); +GLAPI void APIENTRY gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, + GLdouble centerx, GLdouble centery, GLdouble centerz, + GLdouble upx, GLdouble upy, GLdouble upz); /* generate mipmaps for any image provided by the user and then pass them to OpenGL */ GLAPI GLint APIENTRY gluBuild2DMipmaps(GLenum target, GLint internalFormat, diff --git a/samples/blend_test/main.c b/samples/blend_test/main.c index 6fbb795..1303f7f 100644 --- a/samples/blend_test/main.c +++ b/samples/blend_test/main.c @@ -80,7 +80,6 @@ void DrawGLScene() { const float RED [] = {1.0, 0, 0, 0.5}; const float BLUE [] = {0.0, 0, 1, 0.5}; - const float NONE [] = {0, 0, 0, 0}; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer diff --git a/samples/depth_funcs_alpha_testing/gl_png.c b/samples/depth_funcs_alpha_testing/gl_png.c index 686035c..29becd4 100644 --- a/samples/depth_funcs_alpha_testing/gl_png.c +++ b/samples/depth_funcs_alpha_testing/gl_png.c @@ -14,179 +14,172 @@ GLfloat global_diffuse[] = {1.0, 1.0, 1.0, 1.0}; GLfloat global_ambient[] = {1.0, 1.0, 1.0, 1.0}; +static int decode_dtex(Image* image, FILE* file) { + struct { + char id[4]; // 'DTEX' + GLushort width; + GLushort height; + GLuint type; + GLuint size; + } header; + + fread(&header, sizeof(header), 1, file); + + image->twiddled = (header.type & (1 << 26)) < 1; + image->compressed = (header.type & (1 << 30)) > 0; + image->mipmapped = (header.type & (1 << 31)) > 0; + GLuint format = (header.type >> 27) & 0b111; + + image->data = (char *) malloc (header.size); + image->sizeX = header.width; + image->sizeY = header.height; + image->dataSize = header.size; + + fread(image->data, image->dataSize, 1, file); + fclose(file); + + if(image->compressed && image->twiddled) { + switch(format) { + case 0: + puts("Compressed & Twiddled - ARGB 1555"); + if(image->mipmapped) { + image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_TWID_KOS; + } else { + image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_TWID_KOS; + } + return 1; + + case 1: + puts("Compressed & Twiddled - RGB 565"); + if(image->mipmapped) { + image->internalFormat = GL_COMPRESSED_RGB_565_VQ_MIPMAP_TWID_KOS; + } else { + image->internalFormat = GL_COMPRESSED_RGB_565_VQ_TWID_KOS; + } + return 1; + + case 2: + puts("Compressed & Twiddled - ARGB 4444"); + if(image->mipmapped) { + image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_TWID_KOS; + } else { + image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_TWID_KOS; + } + return 1; + + } + } else if (image->compressed) { + switch(format) { + case 0: + puts("Compressed - ARGB 1555"); + if(image->mipmapped) { + image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_KOS; + } else { + image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_KOS; + } + return 1; + + case 1: + puts("Compressed - RGB 565"); + if(image->mipmapped) { + image->internalFormat = GL_COMPRESSED_RGB_565_VQ_MIPMAP_KOS; + } else { + image->internalFormat = GL_COMPRESSED_RGB_565_VQ_KOS; + } + return 1; + + case 2: + puts("Compressed - ARGB 4444"); + if(image->mipmapped) { + image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_KOS; + } else { + image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_KOS; + } + return 1; + } + } else { + switch (format) { + case 0: + puts("Uncompressed - ARGB 1555"); + image->internalFormat = GL_ARGB1555_TWID_KOS; + image->transferFormat = GL_BGRA; + image->transferType = GL_UNSIGNED_SHORT_1_5_5_5_REV_TWID_KOS; + return 1; + + case 1: + puts("Uncompressed - RGB 565"); + image->internalFormat = GL_RGB565_TWID_KOS; + image->transferFormat = GL_RGB; + image->transferType = GL_UNSIGNED_SHORT_5_6_5_TWID_KOS; + return 1; + + case 2: + puts("Uncompressed - ARGB 4444"); + image->internalFormat = GL_ARGB4444_TWID_KOS; + image->transferFormat = GL_BGRA; + image->transferType = GL_UNSIGNED_SHORT_4_4_4_4_REV_TWID_KOS; + return 1; + } + } + + fprintf(stderr, "Invalid texture format %u\n", header.type); + return 0; +} int dtex_to_gl_texture(texture *tex, char* filename) { // Load Texture - Image *image; + Image image = { 0 }; - // allocate space for texture - image = (Image *) malloc(sizeof(Image)); - if (image == NULL) { - printf("No memory for .DTEX file\n"); - return(0); - } + FILE* file = NULL; - FILE* file = NULL; + // make sure the file is there. + if ((file = fopen(filename, "rb")) == NULL) + { + printf("File not found"); + return 0; + } - // make sure the file is there. - if ((file = fopen(filename, "rb")) == NULL) - { - printf("File not found"); - return 0; - } + decode_dtex(&image, file); - struct { - char id[4]; // 'DTEX' - GLushort width; - GLushort height; - GLuint type; - GLuint size; - } header; - - fread(&header, sizeof(header), 1, file); - - GLboolean twiddled = (header.type & (1 << 26)) < 1; - GLboolean compressed = (header.type & (1 << 30)) > 0; - GLboolean mipmapped = (header.type & (1 << 31)) > 0; - GLboolean strided = (header.type & (1 << 25)) > 0; - GLuint format = (header.type >> 27) & 0b111; - - image->data = (char *) malloc (header.size); - image->sizeX = header.width; - image->sizeY = header.height; - image->dataSize = header.size; - - GLuint expected = 2 * header.width * header.height; - GLuint ratio = (GLuint) (((GLfloat) expected) / ((GLfloat) header.size)); - - fread(image->data, image->dataSize, 1, file); - fclose(file); - - if(compressed) { - printf("Compressed - "); - if(twiddled) { - printf("Twiddled - "); - switch(format) { - case 0: { - if(mipmapped) { - image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_TWID_KOS; - } else { - image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_TWID_KOS; - } - } break; - case 1: { - if(mipmapped) { - image->internalFormat = GL_COMPRESSED_RGB_565_VQ_MIPMAP_TWID_KOS; - } else { - image->internalFormat = GL_COMPRESSED_RGB_565_VQ_TWID_KOS; - } - } break; - case 2: { - if(mipmapped) { - image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_TWID_KOS; - } else { - image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_TWID_KOS; - } - } - break; - default: - fprintf(stderr, "Invalid texture format"); - return 0; - } - } else { - switch(format) { - case 0: { - if(mipmapped) { - image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_KOS; - } else { - image->internalFormat = GL_COMPRESSED_ARGB_1555_VQ_KOS; - } - } break; - case 1: { - if(mipmapped) { - image->internalFormat = GL_COMPRESSED_RGB_565_VQ_MIPMAP_KOS; - } else { - image->internalFormat = GL_COMPRESSED_RGB_565_VQ_KOS; - } - } break; - case 2: { - if(mipmapped) { - image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_KOS; - } else { - image->internalFormat = GL_COMPRESSED_ARGB_4444_VQ_KOS; - } - } - break; - default: - fprintf(stderr, "Invalid texture format"); - return 0; - } - } - } else { - printf("Uncompressed - "); - //printf("Color:%u -", format); - switch(format) { - - case 0: - image->internalFormat = GL_UNSIGNED_SHORT_1_5_5_5_REV_TWID_KOS; - //image->internalFormat = GL_UNSIGNED_SHORT_1_5_5_5_REV; - break; - case 1: - image->internalFormat = GL_UNSIGNED_SHORT_5_6_5_REV; - break; - case 2: - image->internalFormat = GL_UNSIGNED_SHORT_4_4_4_4_REV; - break; - } - } - printf("\n"); - - // Create Texture - GLuint texture_id; - glGenTextures(1, &texture_id); - glBindTexture(GL_TEXTURE_2D, texture_id); // 2d texture (x and y size) - - GLint newFormat = format; - GLint colorType = GL_RGB; - - if (image->internalFormat == GL_UNSIGNED_SHORT_1_5_5_5_REV_TWID_KOS || - image->internalFormat == GL_UNSIGNED_SHORT_4_4_4_4_REV){ - newFormat = GL_BGRA; - colorType = GL_RGBA; - printf("Reversing RGBA\n"); - } - - if (image->internalFormat == GL_UNSIGNED_SHORT_5_6_5_REV){ - newFormat = GL_RGB; - colorType = GL_RGB; - printf("Reversing RGB\n"); - } + // Create Texture + GLuint texture_id; + glGenTextures(1, &texture_id); + glBindTexture(GL_TEXTURE_2D, texture_id); // 2d texture (x and y size) + if (image.compressed) { + glCompressedTexImage2D(GL_TEXTURE_2D, 0, + image.internalFormat, image.sizeX, image.sizeY, + 0, image.dataSize, image.data); + } else { glTexImage2D(GL_TEXTURE_2D, 0, - colorType, image->sizeX, image->sizeY, 0, - newFormat, image->internalFormat, image->data); + image.internalFormat, image.sizeX, image.sizeY, 0, + image.transferFormat, image.transferType, image.data); + } - tex->id = texture_id; - tex->w = image->sizeX; - tex->h = image->sizeY; - tex->u = 0.f; - tex->v = 0.f; - tex->a = tex->light = 1; - tex->color[0] = tex->color[1] = tex->color[2] = 1.0f; - tex->uSize = tex->vSize = 1.0f; - tex->xScale = tex->yScale = 1.0f; - tex->format = image->internalFormat; - tex->min_filter = tex->mag_filter = GL_NEAREST; - tex->blend_source = GL_SRC_ALPHA; - tex->blend_dest = GL_ONE_MINUS_SRC_ALPHA; - strcpy(tex->path, filename); + tex->id = texture_id; + tex->w = image.sizeX; + tex->h = image.sizeY; + tex->u = 0.f; + tex->v = 0.f; + tex->a = tex->light = 1; + tex->color[0] = tex->color[1] = tex->color[2] = 1.0f; + tex->uSize = tex->vSize = 1.0f; + tex->xScale = tex->yScale = 1.0f; + tex->format = image.internalFormat; + tex->min_filter = tex->mag_filter = GL_NEAREST; + tex->blend_source = GL_SRC_ALPHA; + tex->blend_dest = GL_ONE_MINUS_SRC_ALPHA; + strcpy(tex->path, filename); + + GLuint expected = 2 * image.sizeX * image.sizeY; + GLuint ratio = (GLuint) (((GLfloat) expected) / ((GLfloat) image.dataSize)); - printf("Texture size: %lu x %lu\n", image->sizeX, image->sizeY); - printf("Texture ratio: %d\n", ratio); - printf("Texture size: %lu x %lu\n", image->sizeX, image->sizeY); - printf("Texture %s loaded\n", tex->path); + printf("Texture size: %lu x %lu\n", image.sizeX, image.sizeY); + printf("Texture ratio: %d\n", ratio); + printf("Texture size: %lu x %lu\n", image.sizeX, image.sizeY); + printf("Texture %s loaded\n", tex->path); - return(1); + return(1); } void draw_textured_quad(texture *tex) { diff --git a/samples/depth_funcs_alpha_testing/gl_png.h b/samples/depth_funcs_alpha_testing/gl_png.h index 29b312f..4b16eec 100644 --- a/samples/depth_funcs_alpha_testing/gl_png.h +++ b/samples/depth_funcs_alpha_testing/gl_png.h @@ -29,8 +29,8 @@ typedef struct Image { unsigned long sizeX; unsigned long sizeY; char *data; - GLenum internalFormat; - GLboolean mipmapped; + GLenum internalFormat, transferFormat, transferType; + unsigned int mipmapped, compressed, twiddled; unsigned int dataSize; } Image; diff --git a/samples/depth_funcs_alpha_testing/main.c b/samples/depth_funcs_alpha_testing/main.c index 517d6a0..257b093 100644 --- a/samples/depth_funcs_alpha_testing/main.c +++ b/samples/depth_funcs_alpha_testing/main.c @@ -88,7 +88,7 @@ void DrawGLScene() glLoadIdentity(); glTranslated(-1 , -1, -5); glDepthFunc(GL_LESS); - glEnable(GL_DEPTH_FUNC); + glEnable(GL_DEPTH_TEST); for (int i = 0; i < 5; i++) { glTranslated(0.5, 0, -0.2); diff --git a/samples/lerabot01/main.c b/samples/lerabot01/main.c index 71ca463..d16c0a5 100644 --- a/samples/lerabot01/main.c +++ b/samples/lerabot01/main.c @@ -26,7 +26,7 @@ KOS_INIT_ROMDISK(romdisk); float xrot, yrot, zrot; /* storage for one texture */ -int texture[1]; +GLuint texture[1]; // Load Bitmaps And Convert To Textures void LoadGLTextures() { @@ -81,7 +81,7 @@ void InitGL(int Width, int Height) // We call this right after our OpenG GLfloat l1_pos[] = {5.0, 0.0, 1.0, 1.0}; GLfloat l1_diff[] = {1.0, 0.0, 0.0, 1.0}; - GLfloat l1_amb[] = {0.5, 0.5, 0.5, 1.0}; + //GLfloat l1_amb[] = {0.5, 0.5, 0.5, 1.0}; //glLightfv(GL_LIGHT1, GL_AMBIENT, l1_amb); glLightfv(GL_LIGHT1, GL_DIFFUSE, l1_diff); @@ -93,7 +93,7 @@ void InitGL(int Width, int Height) // We call this right after our OpenG GLfloat l2_pos[] = {0.0, 15.0, 1.0, 1.0}; GLfloat l2_dir[] = {0.0, -1.0, 0.0}; GLfloat l2_diff[] = {0.5, 0.5, 0.0, 1.0}; - GLfloat l2_amb[] = {0.5, 0.5, 0.5, 1.0}; + //GLfloat l2_amb[] = {0.5, 0.5, 0.5, 1.0}; glEnable(GL_LIGHT2); glLightfv(GL_LIGHT2, GL_DIFFUSE, l2_diff); @@ -145,7 +145,7 @@ void DrawTexturedQuad(int tex, float x, float y, float z) GLfloat y0 = y - texH / 2; GLfloat x1 = x + texW / 2; GLfloat y1 = y + texH / 2; - GLfloat color[] = {1.0f, 1.0f, 1.0f, 1.0f}; + //GLfloat color[] = {1.0f, 1.0f, 1.0f, 1.0f}; GLfloat mat_ambient[] = {1.0f, 1.0f, 1.0f, 1.0f}; GLfloat vertex_data[] = { @@ -172,14 +172,6 @@ void DrawTexturedQuad(int tex, float x, float y, float z) 0.0, 0.0, 1.0 }; - GLfloat color_data[] = { - /* 2D Coordinate, texture coordinate */ - color[0], color[1], color[2], color[3], - color[0], color[1], color[2], color[3], - color[0], color[1], color[2], color[3], - color[0], color[1], color[2], color[3] - }; - //GLint indices[] = {0,1,2,3,2,3}; glEnable(GL_TEXTURE_2D); diff --git a/samples/lights/main.c b/samples/lights/main.c index afd048d..223bd86 100644 --- a/samples/lights/main.c +++ b/samples/lights/main.c @@ -24,8 +24,7 @@ KOS_INIT_ROMDISK(romdisk); #include "../loadbmp.h" float xrot, yrot, zrot; - -int texture[1]; +GLuint texture[1]; void LoadGLTextures() { diff --git a/samples/loadbmp.c b/samples/loadbmp.c index 65bd571..936ba06 100644 --- a/samples/loadbmp.c +++ b/samples/loadbmp.c @@ -35,7 +35,7 @@ int ImageLoad(char *filename, Image *image) { return 0; } image->sizeX = sizeX; - printf("Width of %s: %d\n", filename, sizeX); + printf("Width of %s: %ld\n", filename, sizeX); // read the height if ((i = fread(&sizeY, 4, 1, file)) != 1) { @@ -43,7 +43,7 @@ int ImageLoad(char *filename, Image *image) { return 0; } image->sizeY = sizeY; - printf("Height of %s: %d\n", filename, sizeY); + printf("Height of %s: %ld\n", filename, sizeY); // calculate the size (assuming 24 bits or 3 bytes per pixel). size = image->sizeX * image->sizeY * 3; diff --git a/samples/mipmap/main.c b/samples/mipmap/main.c index ba65d5f..8dc5fca 100644 --- a/samples/mipmap/main.c +++ b/samples/mipmap/main.c @@ -20,9 +20,7 @@ KOS_INIT_ROMDISK(romdisk); #endif #include "../loadbmp.h" - -/* storage for one texture */ -int texture[1]; +GLuint texture[1]; // Load Bitmaps And Convert To Textures void LoadGLTextures() { diff --git a/samples/nehe06/main.c b/samples/nehe06/main.c index 543c3a2..d726289 100644 --- a/samples/nehe06/main.c +++ b/samples/nehe06/main.c @@ -53,8 +53,11 @@ void LoadGLTextures() { // 2d texture, level of detail 0 (normal), 3 components (red, green, blue), x size from image, y size from image, // border 0 (normal), rgb color data, unsigned byte data, and finally the data itself. - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image1->sizeX, image1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->data); + // Create an empty texture first + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image1->sizeX, image1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + // Update the texture with the image data + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image1->sizeX, image1->sizeY, GL_RGB, GL_UNSIGNED_BYTE, image1->data); free(image1); } diff --git a/samples/nehe06_4444twid/main.c b/samples/nehe06_4444twid/main.c index 3cc58d5..f290c6f 100644 --- a/samples/nehe06_4444twid/main.c +++ b/samples/nehe06_4444twid/main.c @@ -62,7 +62,7 @@ int ImageLoad(char *filename, Image *image) { GLboolean twiddled = (header.type & (1 << 26)) < 1; GLboolean compressed = (header.type & (1 << 30)) > 0; GLboolean mipmapped = (header.type & (1 << 31)) > 0; - GLboolean strided = (header.type & (1 << 25)) > 0; + //GLboolean strided = (header.type & (1 << 25)) > 0; GLuint format = (header.type >> 27) & 0b111; image->data = (char *) malloc (header.size); @@ -70,8 +70,8 @@ int ImageLoad(char *filename, Image *image) { image->sizeY = header.height; image->dataSize = header.size; - GLuint expected = 2 * header.width * header.height; - GLuint ratio = (GLuint) (((GLfloat) expected) / ((GLfloat) header.size)); + //GLuint expected = 2 * header.width * header.height; + //GLuint ratio = (GLuint) (((GLfloat) expected) / ((GLfloat) header.size)); fread(image->data, image->dataSize, 1, file); fclose(file); diff --git a/samples/nehe06_vq/main.c b/samples/nehe06_vq/main.c index cf2156e..754f458 100644 --- a/samples/nehe06_vq/main.c +++ b/samples/nehe06_vq/main.c @@ -22,7 +22,7 @@ KOS_INIT_ROMDISK(romdisk); float xrot, yrot, zrot; /* storage for one texture */ -int texture[1]; +GLuint texture[1]; /* Image type - contains height, width, and data */ struct Image { @@ -59,7 +59,7 @@ int ImageLoad(char *filename, Image *image) { GLboolean twiddled = (header.type & (1 << 26)) < 1; GLboolean compressed = (header.type & (1 << 30)) > 0; GLboolean mipmapped = (header.type & (1 << 31)) > 0; - GLboolean strided = (header.type & (1 << 25)) > 0; + //GLboolean strided = (header.type & (1 << 25)) > 0; GLuint format = (header.type >> 27) & 0b111; image->data = (char *) malloc (header.size); @@ -67,8 +67,8 @@ int ImageLoad(char *filename, Image *image) { image->sizeY = header.height; image->dataSize = header.size; - GLuint expected = 2 * header.width * header.height; - GLuint ratio = (GLuint) (((GLfloat) expected) / ((GLfloat) header.size)); + //GLuint expected = 2 * header.width * header.height; + //GLuint ratio = (GLuint) (((GLfloat) expected) / ((GLfloat) header.size)); fread(image->data, image->dataSize, 1, file); fclose(file); diff --git a/samples/nehe08/main.c b/samples/nehe08/main.c index 8d6814d..4048b59 100644 --- a/samples/nehe08/main.c +++ b/samples/nehe08/main.c @@ -11,10 +11,10 @@ #ifdef __DREAMCAST__ #include #endif - #include -#include #include +#include +#include /* Simple OpenGL example to demonstrate blending and lighting. diff --git a/samples/nehe20/main.c b/samples/nehe20/main.c index 8050dbd..bce9182 100644 --- a/samples/nehe20/main.c +++ b/samples/nehe20/main.c @@ -11,6 +11,11 @@ #include #include + +#ifdef __DREAMCAST__ +#include +#endif + #define FPS 60 uint32_t waittime = 1000.0f/FPS; uint32_t framestarttime = 0; @@ -58,8 +63,9 @@ KOS_INIT_ROMDISK(romdisk); #include // Header File For The GLu32 Library #include #else -#include // Header File For The OpenGL32 Library -#include // Header File For The GLu32 Library +#include // Header File For The OpenGL32 Library +#include +#include // Header File For The GLu32 Library #endif #define BOOL int @@ -227,8 +233,6 @@ int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing int main(int argc, char *argv[]) { - BOOL done=FALSE; // Bool Variable To Exit Loop - glKosInit(); InitGL(); diff --git a/samples/paletted/main.c b/samples/paletted/main.c index 7b88cf3..50fbdf3 100644 --- a/samples/paletted/main.c +++ b/samples/paletted/main.c @@ -22,8 +22,7 @@ KOS_INIT_ROMDISK(romdisk); /* floats for x rotation, y rotation, z rotation */ float xrot, yrot, zrot; -/* storage for one texture */ -int texture[1]; +GLuint texture[1]; typedef struct { unsigned int height; diff --git a/samples/paletted_pcx/main.c b/samples/paletted_pcx/main.c index e397ab7..a01744a 100644 --- a/samples/paletted_pcx/main.c +++ b/samples/paletted_pcx/main.c @@ -41,7 +41,7 @@ /* floats for x rotation, y rotation, z rotation */ float xrot, yrot, zrot; -int textures[3]; +GLuint textures[3]; typedef struct { uint32_t height; @@ -272,7 +272,7 @@ int BMP_GetPalette(FILE *pFile) bitCount = BmpInfoHeader.ClrImportant * sizeof(RGB_QUAD); if (fread(BmpRgbQuad, 1, bitCount, pFile) != bitCount){ - fprintf(stderr, "Failed to read palette: %d\n", bitCount); + fprintf(stderr, "Failed to read palette: %ld\n", bitCount); return 0; } @@ -293,7 +293,7 @@ int BMP_GetPalette(FILE *pFile) int BMP_Depack(FILE *pFile,char *pZone) { char PadRead[4]; - int32_t i, j, Offset, PadSize, pix, c; + int32_t i, j, Offset, PadSize, c; if (BmpInfoHeader.Compression != BMP_BI_RGB) return 0; @@ -356,7 +356,7 @@ int LoadPalettedBMP(const char* filename, Image* image) } /* store palette information */ - image->palette = BmpPal; + image->palette = (char*)BmpPal; image->palette_width = 16; diff --git a/samples/primitive_modes/main.c b/samples/primitive_modes/main.c new file mode 100644 index 0000000..5f7acab --- /dev/null +++ b/samples/primitive_modes/main.c @@ -0,0 +1,203 @@ +#include +#include +#include +#include + +#ifndef __DREAMCAST__ +#include +static SDL_Window* win_handle; +#else +#include +#include +#endif + +static void DrawLineLoop(float y) { + glBegin(GL_LINE_LOOP); + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(410.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(490.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(490.0f, y + 90.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(410.0f, y + 90.0f); + glEnd(); +} + +static void DrawLineStrip(float y) { + glBegin(GL_LINE_STRIP); + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(310.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(390.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(390.0f, y + 90.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(310.0f, y + 90.0f); + glEnd(); +} + +static void DrawLine(float y) { + glBegin(GL_LINES); + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(210.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(290.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(290.0f, y + 90.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(210.0f, y + 90.0f); + + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(230.0f, y + 25.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(250.0f, y + 75.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(260.0f, y + 75.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(280.0f, y + 45.0f); + glEnd(); +} + +static void DrawPoint(float y) { + glBegin(GL_POINTS); + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(110.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(190.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(190.0f, y + 90.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(110.0f, y + 90.0f); + glEnd(); +} + +static void DrawQuad(float y) { + glBegin(GL_QUADS); + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(10.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(90.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(90.0f, y + 90.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(10.0f, y + 90.0f); + + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(110.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(190.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(190.0f, y + 90.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(110.0f, y + 90.0f); + glEnd(); +} + +static void DrawQuadStrip(float y) { + glBegin(GL_QUAD_STRIP); + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(210.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(290.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(290.0f, y + 90.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(210.0f, y + 90.0f); + + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(310.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(390.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(390.0f, y + 90.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(310.0f, y + 90.0f); + glEnd(); +} + +static void DrawTriList(float y) { + glBegin(GL_TRIANGLES); + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f( 10.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f( 90.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f( 90.0f, y + 90.0f); + + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(110.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(190.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(190.0f, y + 90.0f); + glEnd(); +} + +static void DrawTriStrip(float y) { + glBegin(GL_TRIANGLE_STRIP); + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(210.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(290.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(290.0f, y + 90.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(210.0f, y + 90.0f); + + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(310.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(390.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(390.0f, y + 90.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(310.0f, y + 90.0f); + glEnd(); +} + + +static void DrawTriFan(float y) { + glBegin(GL_TRIANGLE_FAN); + glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(410.0f, y + 10.0f); + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(490.0f, y + 10.0f); + glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(445.0f, y + 90.0f); + + glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(590.0f, y + 10.0f); + glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(510.0f, y + 45.0f); + glEnd(); +} + +static void sample_init() { +#ifndef __DREAMCAST__ + SDL_Init(SDL_INIT_EVERYTHING); + win_handle = SDL_CreateWindow("Shapes", 0, 0, 640, 480, SDL_WINDOW_OPENGL); + SDL_GL_CreateContext(win_handle); +#else + glKosInit(); +#endif +} + +static int sample_should_exit() { +#ifndef __DREAMCAST__ + SDL_Event event; + while (SDL_PollEvent(&event)) { + if(event.type == SDL_QUIT) return 1; + } + return 0; +#else + maple_device_t *cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); + if (!cont) return 0; + + cont_state_t *state = (cont_state_t *)maple_dev_status(cont); + if (!state) return 0; + + return state->buttons & CONT_START; +#endif +} + +int main(int argc, char *argv[]) { + sample_init(); + glClearColor(0.5f, 0.5f, 0.5f, 1); + glViewport(0, 0, 640, 480); + + float mat[4][4] = { 0 }; + float L = 0, T = 0, R = 640, B = 480, N = -100, F = 100; + mat[0][0] = 2.0f / (R - L); + mat[1][1] = 2.0f / (T - B); + mat[2][2] = -2.0f / (F - N); + mat[3][0] = -(R + L) / (R - L); + mat[3][1] = -(T + B) / (T - B); + mat[3][2] = -(F + N) / (F - N); + mat[3][3] = 1; + glLoadMatrixf(*mat); + + while (!sample_should_exit()) { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + DrawTriStrip(300); + DrawTriFan(300); + DrawTriList(300); + + DrawQuadStrip(200); + DrawQuad(200); + + glPointSize(5); + DrawPoint(100); + glLineWidth(2); + DrawLineLoop(100); + glLineWidth(4); + DrawLineStrip(100); + glLineWidth(10); + DrawLine(100); + + glPointSize(1); + glLineWidth(1); + DrawPoint(0); + DrawLineLoop(0); + DrawLineStrip(0); + DrawLine(0); + + glShadeModel(GL_FLAT); + DrawQuad(400); + DrawTriStrip(400); + glShadeModel(GL_SMOOTH); + +#ifdef SDL2_BUILD + SDL_GL_SwapWindow(win_handle); +#else + glKosSwapBuffers(); +#endif + } + return 0; +} diff --git a/samples/profiler.c b/samples/profiler.c index c44c3c9..cefc81a 100644 --- a/samples/profiler.c +++ b/samples/profiler.c @@ -287,7 +287,7 @@ static bool write_samples(const char* path) { root = ARCS; for(int i = 0; i < BUCKET_SIZE; ++i) { if(root->pc) { - printf("Incrementing %d for %x. ", (root->pc - lowest_address) / bin_size, (unsigned int) root->pc); + printf("Incrementing %ld for %x. ", (root->pc - lowest_address) / bin_size, (unsigned int) root->pc); bins[(root->pc - lowest_address) / bin_size]++; printf("Now: %d\n", (int) bins[(root->pc - lowest_address) / bin_size]); diff --git a/tests/test_allocator.h b/tests/test_allocator.h index 5967983..8aa146f 100644 --- a/tests/test_allocator.h +++ b/tests/test_allocator.h @@ -39,6 +39,42 @@ public: self->defrag_moves.push_back(std::make_pair(src, dst)); } + void test_count_free() { + alloc_init(pool, POOL_SIZE); + + assert_equal(alloc_count_free(pool), POOL_SIZE); + + void* a1 = alloc_malloc(pool, 2048); + assert_equal(alloc_count_free(pool), POOL_SIZE - 2048); + + void* a2 = alloc_malloc(pool, 2048); + assert_equal(alloc_count_free(pool), POOL_SIZE - 4096); + + alloc_free(pool, a1); + assert_equal(alloc_count_free(pool), POOL_SIZE - 2048); + + alloc_free(pool, a2); + assert_equal(alloc_count_free(pool), POOL_SIZE); + } + + void test_count_contiguous() { + alloc_init(pool, POOL_SIZE); + + assert_equal(alloc_count_continuous(pool), POOL_SIZE); + + void* a1 = alloc_malloc(pool, 2048); + assert_equal(alloc_count_continuous(pool), POOL_SIZE - 2048); + + void* a2 = alloc_malloc(pool, 2048); + assert_equal(alloc_count_continuous(pool), POOL_SIZE - 4096); + + alloc_free(pool, a1); + assert_equal(alloc_count_continuous(pool), POOL_SIZE - 4096); + + alloc_free(pool, a2); + assert_equal(alloc_count_continuous(pool), POOL_SIZE); + } + void test_defrag() { alloc_init(pool, POOL_SIZE); diff --git a/tests/zclip/main.cpp b/tests/zclip/main.cpp index adada72..42febee 100644 --- a/tests/zclip/main.cpp +++ b/tests/zclip/main.cpp @@ -435,7 +435,7 @@ bool test_clip_case_001() { SceneListSubmit(&data[0], data.size()); - check_equal(sent.size(), 5); + check_equal(sent.size(), 5u); check_equal(sent[0].flags, GPU_CMD_POLYHDR); check_equal(sent[1].flags, GPU_CMD_VERTEX); check_equal(sent[2].flags, GPU_CMD_VERTEX); @@ -461,7 +461,7 @@ bool test_clip_case_010() { SceneListSubmit(&data[0], data.size()); - check_equal(sent.size(), 4); + check_equal(sent.size(), 4u); check_equal(sent[0].flags, GPU_CMD_POLYHDR); check_equal(sent[1].flags, GPU_CMD_VERTEX); check_equal(sent[2].flags, GPU_CMD_VERTEX); @@ -481,7 +481,7 @@ bool test_clip_case_100() { SceneListSubmit(&data[0], data.size()); - check_equal(sent.size(), 5); + check_equal(sent.size(), 5u); check_equal(sent[0].flags, GPU_CMD_POLYHDR); check_equal(sent[1].flags, GPU_CMD_VERTEX); check_equal(sent[2].flags, GPU_CMD_VERTEX); @@ -507,7 +507,7 @@ bool test_clip_case_110() { SceneListSubmit(&data[0], data.size()); - check_equal(sent.size(), 6); + check_equal(sent.size(), 6u); check_equal(sent[0].flags, GPU_CMD_POLYHDR); check_equal(sent[1].flags, GPU_CMD_VERTEX); check_equal(sent[2].flags, GPU_CMD_VERTEX); @@ -530,7 +530,7 @@ bool test_clip_case_011() { SceneListSubmit(&data[0], data.size()); - check_equal(sent.size(), 6); + check_equal(sent.size(), 6u); check_equal(sent[0].flags, GPU_CMD_POLYHDR); check_equal(sent[1].flags, GPU_CMD_VERTEX); check_equal(sent[2].flags, GPU_CMD_VERTEX); @@ -553,7 +553,7 @@ bool test_clip_case_101() { SceneListSubmit(&data[0], data.size()); - check_equal(sent.size(), 6); + check_equal(sent.size(), 6u); check_equal(sent[0].flags, GPU_CMD_POLYHDR); check_equal(sent[1].flags, GPU_CMD_VERTEX); check_equal(sent[2].flags, GPU_CMD_VERTEX); @@ -576,7 +576,7 @@ bool test_clip_case_111() { SceneListSubmit(&data[0], data.size()); - check_equal(sent.size(), 4); + check_equal(sent.size(), 4u); check_equal(sent[0].flags, GPU_CMD_POLYHDR); check_equal(sent[1].flags, GPU_CMD_VERTEX); check_equal(sent[2].flags, GPU_CMD_VERTEX);