diff --git a/containers/aligned_vector.h b/containers/aligned_vector.h new file mode 100644 index 0000000..a9c7fef --- /dev/null +++ b/containers/aligned_vector.h @@ -0,0 +1,109 @@ +#ifndef ALIGNED_VECTOR_H +#define ALIGNED_VECTOR_H + +#include +#include +#include +#include + +#define ALIGNED_VECTOR_INITIAL_CAPACITY 256 + +typedef struct { + unsigned int size; + unsigned int capacity; + unsigned char* data; + unsigned int element_size; +} AlignedVector; + + +inline void aligned_vector_reserve(AlignedVector* vector, unsigned int element_count); +inline void aligned_vector_resize(AlignedVector* vector, const unsigned int element_count); + +inline void aligned_vector_init(AlignedVector* vector, unsigned int element_size) { + vector->size = vector->capacity = 0; + vector->element_size = element_size; + vector->data = NULL; + + /* Reserve some initial capacity */ + aligned_vector_reserve(vector, ALIGNED_VECTOR_INITIAL_CAPACITY); +} + +inline void aligned_vector_reserve(AlignedVector* vector, unsigned int element_count) { + if(element_count <= vector->capacity) { + return; + } + + unsigned int original_byte_size = vector->size * vector->element_size; + unsigned int new_byte_size = element_count * vector->element_size; + unsigned char* original_data = vector->data; + vector->data = (unsigned char*) memalign(0x20, new_byte_size); + + if(original_data) { + memcpy(vector->data, original_data, original_byte_size); + free(original_data); + } + + vector->capacity = element_count; +} + +inline void aligned_vector_push_back(AlignedVector* vector, const void* objs, unsigned int count) { + /* Resize enough room */ + + unsigned int initial_size = vector->size; + aligned_vector_resize(vector, vector->size + count); + + unsigned char* dest = vector->data + (vector->element_size * initial_size); + + /* Copy the objects in */ + memcpy(dest, objs, vector->element_size * count); +} + +inline void aligned_vector_resize(AlignedVector* vector, const unsigned int element_count) { + /* Don't change memory when resizing downwards, just change the size */ + if(element_count <= vector->size) { + vector->size = element_count; + return; + } + + if(vector->capacity < element_count) { + /* Reserve more than we need so that a subsequent push_back doesn't trigger yet another + * resize */ + aligned_vector_reserve(vector, (int) ceil(((float)element_count) * 1.5f)); + } + + vector->size = element_count; +} + +inline void* aligned_vector_at(AlignedVector* vector, const unsigned int index) { + return &vector->data[index * vector->element_size]; +} + +inline void aligned_vector_clear(AlignedVector* vector) { + vector->size = 0; +} + +inline void aligned_vector_shrink_to_fit(AlignedVector* vector) { + if(vector->size == 0) { + free(vector->data); + vector->data = NULL; + vector->capacity = 0; + } else { + unsigned int new_byte_size = vector->size * vector->element_size; + unsigned char* original_data = vector->data; + vector->data = (unsigned char*) memalign(0x20, new_byte_size); + + if(original_data) { + memcpy(vector->data, original_data, new_byte_size); + free(original_data); + } + + vector->capacity = vector->size; + } +} + +void aligned_vector_cleanup(AlignedVector* vector) { + aligned_vector_clear(vector); + aligned_vector_shrink_to_fit(vector); +} + +#endif // ALIGNED_VECTOR_H diff --git a/experimental/draw.c b/experimental/draw.c new file mode 100644 index 0000000..c935f18 --- /dev/null +++ b/experimental/draw.c @@ -0,0 +1,212 @@ +#include "../include/gl.h" +#include "private.h" + + +typedef struct { + void* ptr; + GLenum type; + GLsizei stride; + GLint size; +} AttribPointer; + + +static AttribPointer VERTEX_POINTER; +static AttribPointer UV_POINTER; +static AttribPointer ST_POINTER; +static AttribPointer NORMAL_POINTER; +static AttribPointer DIFFUSE_POINTER; + +#define VERTEX_ENABLED_FLAG (1 << 0) +#define UV_ENABLED_FLAG (1 << 1) +#define ST_ENABLED_FLAG (1 << 2) +#define DIFFUSE_ENABLED_FLAG (1 << 3) +#define NORMAL_ENABLED_FLAG (1 << 4) + +static GLuint ENABLED_VERTEX_ATTRIBUTES = 0; +static GLubyte ACTIVE_CLIENT_TEXTURE = 0; + +void initAttributePointers() { + VERTEX_POINTER.ptr = NULL; + VERTEX_POINTER.stride = 0; + VERTEX_POINTER.type = GL_FLOAT; + VERTEX_POINTER.size = 4; +} + +static GLuint 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); + default: return sizeof(GLfloat); + } +} + +static void transformVertex(const GLfloat* src) { + register float __x __asm__("fr12"); + register float __y __asm__("fr13"); + register float __z __asm__("fr14"); + + __x = src[0]; + __y = src[1]; + __z = src[2]; + + mat_trans_fv12() + + src[0] = __x; + src[1] = __y; + src[2] = __z; +} + +static void _parseFloats(GLfloat* out, const GLubyte* in, GLint size, GLenum type) { + switch(type) { + case GL_SHORT: { + GLshort* inp = (GLshort*) in; + for(GLubyte i = 0; i < size; ++i) { + out[i] = (GLfloat) inp[i]; + } + } break; + case GL_INT: { + GLint* inp = (GLint*) in; + for(GLubyte i = 0; i < size; ++i) { + out[i] = (GLfloat) inp[i]; + } + } break; + case GL_FLOAT: + case GL_DOUBLE: /* Double == Float */ + default: + for(GLubyte i = 0; i < size; ++i) out[i] = ((GLfloat*) in)[i]; + } +} + +static void _parseIndex(GLshort* out, const GLubyte* in, GLenum type) { + switch(type) { + case GL_UNSIGNED_BYTE: + *out = (GLshort) *in; + break; + case GL_UNSIGNED_SHORT: + default: + *out = *((GLshort*) in); + } +} + +static void submitVertices(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) { + if(!(ENABLED_VERTEX_ATTRIBUTES & VERTEX_ENABLED_FLAG)) { + return; + } + + _glKosMatrixApplyRender(); /* Apply the Render Matrix Stack */ + + const GLbyte elements = (mode == GL_QUADS) ? 4 : (mode == GL_TRIANGLES) ? 3 : (mode == GL_LINES) ? 2 : count; + + pvr_vertex_t vertex; + vertex.u = vertex.v = 0.0f; + vertex.argb = 0xFFFFFFFF; + + static GLfloat vparts[4]; + + GLubyte vstride = (VERTEX_POINTER.stride) ? VERTEX_POINTER.stride : VERTEX_POINTER.size * byte_size(VERTEX_POINTER.type); + GLubyte* vptr = VERTEX_POINTER.ptr; + + for(GLuint i = 0; i < count; ++i) { + GLshort idx = i; + if(indices) { + _parseIndex(&idx, indices[byte_size(type) * i], type); + } + + _parseFloats(vparts, vptr + (idx * vstride), VERTEX_POINTER.size, VERTEX_POINTER.type); + + vertex.x = vparts[0]; + vertex.y = vparts[1]; + vertex.z = vparts[2]; + + transformVertex(&vertex.x); + } +} + +GLAPI void APIENTRY glDrawElementsExp(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) { + submitVertices(mode, count, type, indices); +} + +GLAPI void APIENTRY glDrawArraysExp(GLenum mode, GLint first, GLsizei count) { + submitVertices(mode, count, type, NULL); +} + +GLAPI void APIENTRY glEnableClientStateExp(GLenum cap) { + 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, "glEnableClientState"); + } +} + +GLAPI void APIENTRY glDisableClientStateExp(GLenum cap) { + 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, "glDisableClientState"); + } +} + +GLAPI void APIENTRY glClientActiveTextureExp(GLenum texture) { + ACTIVE_CLIENT_TEXTURE = (texture == GL_TEXTURE1) ? 1 : 0; +} + +GLAPI void APIENTRY glTexcoordPointerExp(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { + AttribPointer* texpointer = (ACTIVE_CLIENT_TEXTURE == 0) ? &UV_POINTER : &ST_POINTER; + + texpointer->ptr = pointer; + texpointer->stride = stride; + texpointer->type = type; + texpointer->size = size; +} + +GLAPI void APIENTRY glVertexPointerExp(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { + VERTEX_POINTER.ptr = pointer; + VERTEX_POINTER.stride = stride; + VERTEX_POINTER.type = type; + VERTEX_POINTER.size = size; +} + +GLAPI void APIENTRY glColorPointerExp(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer) { + DIFFUSE_POINTER.ptr = pointer; + DIFFUSE_POINTER.stride = stride; + DIFFUSE_POINTER.type = type; + DIFFUSE_POINTER.size = size; +} + +GLAPI void APIENTRY glNormalPointerExp(GLenum type, GLsizei stride, const GLvoid * pointer) { + NORMAL_POINTER.ptr = pointer; + NORMAL_POINTER.stride = stride; + NORMAL_POINTER.type = type; + NORMAL_POINTER.size = 3; +} diff --git a/experimental/flush.c b/experimental/flush.c new file mode 100644 index 0000000..8af8476 --- /dev/null +++ b/experimental/flush.c @@ -0,0 +1,88 @@ + + +#include + +#include "../containers/aligned_vector.h" +#include "private.h" + +#define TA_SQ_ADDR (unsigned int *)(void *) \ + (0xe0000000 | (((unsigned long)0x10000000) & 0x03ffffe0)) + +static AlignedVector OP_LIST; +static AlignedVector PT_LIST; +static AlignedVector TR_LIST; + +typedef struct { + unsigned int cmd[8]; +} PVRCommand; + +static void pvr_list_submit(void *src, int n) { + GLuint *d = TA_SQ_ADDR; + GLuint *s = src; + + /* fill/write queues as many times necessary */ + while(n--) { + __asm__("pref @%0" : : "r"(s + 8)); /* prefetch 32 bytes for next loop */ + d[0] = *(s++); + d[1] = *(s++); + d[2] = *(s++); + d[3] = *(s++); + d[4] = *(s++); + d[5] = *(s++); + d[6] = *(s++); + d[7] = *(s++); + __asm__("pref @%0" : : "r"(d)); + d += 8; + } + + /* Wait for both store queues to complete */ + d = (GLuint *)0xe0000000; + d[0] = d[8] = 0; +} + +static void _initPVR() { + pvr_init_params_t params = { + /* Enable opaque and translucent polygons with size 32 and 32 */ + { PVR_BINSIZE_32, PVR_BINSIZE_0, PVR_BINSIZE_32, PVR_BINSIZE_0, PVR_BINSIZE_32 }, + GL_PVR_VERTEX_BUF_SIZE, /* Vertex buffer size */ + 0, /* No DMA */ + 0, /* No FSAA */ + 1 /* Disable translucent auto-sorting to match traditional GL */ + }; + + pvr_init(¶ms); +} + + +AlignedVector* activePolyList() { + return &OP_LIST; +} + +/* FIXME: Rename to glKosInit when experimental is core */ +void glKosBoot() { + _initPVR(); + initAttributePointers(); + + aligned_vector_init(&OP_LIST, sizeof(PVRCommand)); + aligned_vector_init(&PT_LIST, sizeof(PVRCommand)); + aligned_vector_init(&TR_LIST, sizeof(PVRCommand)); +} + +void glKosSwapBuffers() { + pvr_wait_ready(); + + pvr_scene_begin(); + + pvr_list_begin(PVR_LIST_OP_POLY); + pvr_list_submit(OP_LIST.data, OP_LIST.size); + pvr_list_finish(); + + pvr_list_begin(PVR_LIST_PT_POLY); + pvr_list_submit(PT_LIST.data, PT_LIST.size); + pvr_list_finish(); + + pvr_list_begin(PVR_LIST_TR_POLY); + pvr_list_submit(TR_LIST.data, TR_LIST.size); + pvr_list_finish(); + pvr_scene_finish(); +} diff --git a/experimental/private.h b/experimental/private.h new file mode 100644 index 0000000..a4ea851 --- /dev/null +++ b/experimental/private.h @@ -0,0 +1,25 @@ +#ifndef PRIVATE_H +#define PRIVATE_H + +#include "../include/gl.h" + +struct AlignedVector; + +AlignedVector* activePolyList(); + +void initAttributePointers(); + +#define mat_trans_fv12() { \ + __asm__ __volatile__( \ + "fldi1 fr15\n" \ + "ftrv xmtrx, fv12\n" \ + "fldi1 fr14\n" \ + "fdiv fr15, fr14\n" \ + "fmul fr14, fr12\n" \ + "fmul fr14, fr13\n" \ + : "=f" (__x), "=f" (__y), "=f" (__z) \ + : "0" (__x), "1" (__y), "2" (__z) \ + : "fr15" ); \ + } + +#endif // PRIVATE_H diff --git a/experimental/state.c b/experimental/state.c new file mode 100644 index 0000000..daa1245 --- /dev/null +++ b/experimental/state.c @@ -0,0 +1,175 @@ +#include "../include/gl.h" + +static pvr_poly_cxt_t GL_CONTEXT; + +/* We can't just use the GL_CONTEXT for this state as the two + * GL states are combined, so we store them separately and then + * calculate the appropriate PVR state from them. */ +static GLenum CULL_FACE = GL_BACK; +static GLenum FRONT_FACE = GL_CCW; +static GLboolean CULLING_ENABLED = GL_FALSE; + +static int _calc_pvr_face_culling() { + if(!CULLING_ENABLED) { + return PVR_CULLING_NONE; + } else { + if(CULL_FACE == GL_BACK) { + return (FRONT_FACE == GL_CW) ? PVR_CULLING_CCW : PVR_CULLING_CW; + } else { + return (FRONT_FACE == GL_CCW) ? PVR_CULLING_CCW : PVR_CULLING_CW; + } + } +} + +static GLenum DEPTH_FUNC = GL_LESS; +static GLboolean DEPTH_TEST_ENABLED = GL_FALSE; + +static int _calc_pvr_depth_test() { + if(!DEPTH_TEST_ENABLED) { + return PVR_DEPTH_CMP_ALWAYS; + } + + switch(func) { + case GL_NEVER: + return PVR_DEPTH_CMP_NEVER; + case GL_LESS: + return PVR_DEPTH_CMP_LESS; + case GL_EQUAL: + return PVR_DEPTH_CMP_EQUAL; + case GL_LEQUAL: + return PVR_DEPTH_CMP_LEQUAL; + case GL_GREATER: + return PVR_DEPTH_CMP_GREATER; + case GL_NOTEQUAL: + return PVR_DEPTH_CMP_NOTEQUAL; + case GL_GEQUAL: + return PVR_DEPTH_CMP_GEQUAL; + break; + case GL_ALWAYS: + default: + return PVR_DEPTH_CMP_ALWAYS; + } +} + + +void initContext() { + glDepthFunc(GL_LESS); + glDepthMask(GL_TRUE); + glCullFace(GL_CCW); + + glDisable(GL_ALPHA_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + glDisable(GL_TEXTURE_2D); +} + +GLAPI void APIENTRY glEnable(GLenum cap) { + switch(cap) { + case GL_TEXTURE_2D: + GL_CONTEXT.txr.enable = 1; + break; + case GL_CULL_FACE: { + CULLING_ENABLED = GL_TRUE; + GL_CONTEXT.gen.culling = _calc_pvr_face_culling(); + } break; + case GL_DEPTH_TEST: { + DEPTH_TEST_ENABLED = GL_TRUE; + GL_CONTEXT.depth.comparison = _calc_pvr_depth_test(); + } break; + } +} + +GLAPI void APIENTRY glDisable(GLenum cap) { + switch(cap) { + case GL_TEXTURE_2D: { + GL_CONTEXT.txr.enabled = 0; + } break; + case GL_CULL_FACE: { + CULLING_ENABLED = GL_FALSE; + GL_CONTEXT.gen.culling = _calc_pvr_face_culling(); + } break; + case GL_DEPTH_TEST: { + DEPTH_TEST_ENABLED = GL_FALSE; + GL_CONTEXT.depth.comparison = _calc_pvr_depth_test(); + } break; + } +} + +/* Clear Caps */ +GLAPI void APIENTRY glClear(GLuint mode) { + +} + +GLAPI void APIENTRY glClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { + +} + +/* Depth Testing */ +GLAPI void APIENTRY glClearDepthf(GLfloat depth) { + +} + +GLAPI void APIENTRY glClearDepth(GLfloat depth) { + +} + +GLAPI void APIENTRY glDepthMask(GLboolean flag) { + GL_CONTEXT.depth.write = (flag == GL_TRUE) ? PVR_DEPTHWRITE_ENABLE : PVR_DEPTHWRITE_DISABLE; +} + +GLAPI void APIENTRY glDepthFunc(GLenum func) { + DEPTH_FUNC = func; + GL_CONTEXT.depth.comparison = _calc_pvr_depth_test(); +} + +/* Hints */ +/* Currently Supported Capabilities: + GL_PERSPECTIVE_CORRECTION_HINT - This will Enable Texture Super-Sampling on the PVR */ +GLAPI void APIENTRY glHint(GLenum target, GLenum mode) { + +} + +/* Culling */ +GLAPI void APIENTRY glFrontFace(GLenum mode) { + FRONT_FACE = mode; +} + +GLAPI void APIENTRY glCullFace(GLenum mode) { + CULL_FACE = mode; +} + +/* Shading - Flat or Goraud */ +GLAPI void APIENTRY glShadeModel(GLenum mode) { + +} + +/* Blending */ +GLAPI void APIENTRY glBlendFunc(GLenum sfactor, GLenum dfactor) { + +} + +/* Texturing */ +GLAPI void APIENTRY glTexParameteri(GLenum target, GLenum pname, GLint param) { + +} + +GLAPI void APIENTRY glTexEnvi(GLenum target, GLenum pname, GLint param) { + +} + +GLAPI void APIENTRY glTexEnvf(GLenum target, GLenum pname, GLfloat param) { + +} + +GLAPI void APIENTRY glGenTextures(GLsizei n, GLuint *textures) { + +} + +GLAPI void APIENTRY glDeleteTextures(GLsizei n, GLuint *textures) { + +} + +GLAPI void APIENTRY glBindTexture(GLenum target, GLuint texture) { + +} diff --git a/include/glkos.h b/include/glkos.h new file mode 100644 index 0000000..3bffbe1 --- /dev/null +++ b/include/glkos.h @@ -0,0 +1,6 @@ +#ifndef GLKOS_H +#define GLKOS_H + +void glKosSwapBuffers(); + +#endif // GLKOS_H