texture: fix Dreamcast hardware texture and scissor regressions

Fix several Dreamcast hardware regressions found while testing real PVR behavior.

- Upload the default white texture through the platform texture loader instead of memcpy directly into PVR texture memory.
- Add GPUTextureLoad so SH4 uses pvr_txr_load while the software backend keeps memcpy behavior.
- Track scissor/userclip application per polygon list and invalidate scissor state at buffer swap.
- Submit queued geometry before USERCLIP/header transitions in the SH4 submit path.
- Remove the stale packed 4bpp source-size double-halving in glTexImage2D.
- Add texture regression coverage for packed 4bpp, unpack row length, compressed palette4 forwarding, and 8bpp-to-4bpp packing.
- Update the scissor sample and add polygon_compare as a small hardware comparison sample.

Verified:
- make -C dcbuild gldc_tests scissor polygon_compare
- scissor sample on Dreamcast hardware
- polygon_compare sample on Dreamcast hardware
- existing strided texture sample on Dreamcast hardware
This commit is contained in:
GPF 2026-07-03 09:37:12 -07:00
parent 862bcf70d1
commit f11f7c966a
14 changed files with 424 additions and 77 deletions

View File

@ -181,6 +181,7 @@ if(BUILD_SAMPLES)
gen_sample(zclip_triangle samples/zclip_triangle/main.c)
gen_sample(zclip_trianglestrip samples/zclip_trianglestrip/main.c)
gen_sample(scissor samples/scissor/main.c)
gen_sample(polygon_compare samples/polygon_compare/main.c)
gen_sample(polymark samples/polymark/main.c)
gen_sample(cubes samples/cubes/main.cpp)
gen_sample(zclip_test tests/zclip/main.cpp)

View File

@ -867,8 +867,9 @@ GL_FORCE_INLINE void submitVertices(GLenum mode, GLsizei first, GLuint count, GL
target->output = _glActivePolyList();
gl_assert(target->output);
uint32_t vector_size = aligned_vector_size(&target->output->vector);
_glApplyScissor(false);
uint32_t vector_size = aligned_vector_size(&target->output->vector);
GLboolean header_required = (vector_size == 0) || _glGPUStateIsDirty();
target->count = calcFinalVertices(mode, count);

View File

@ -141,5 +141,5 @@ void APIENTRY glKosSwapBuffers() {
aligned_vector_clear(&PT_LIST.vector);
aligned_vector_clear(&TR_LIST.vector);
_glApplyScissor(true);
_glInvalidateScissor();
}

View File

@ -390,6 +390,7 @@ static inline int DimensionFlag(const int w) {
static uint8_t* DEFAULT_TEXTURE = NULL;
extern void* GPUMemoryAlloc(size_t size);
extern void GPUTextureLoad(const void* src, void* dst, size_t size);
/* Compile a polygon context into a polygon header */
static inline void CompilePolyHeader(PolyHeader *dst, const PolyContext *src) {
@ -437,18 +438,23 @@ static inline void CompilePolyHeader(PolyHeader *dst, const PolyContext *src) {
dst->mode2 |= (src->gen.color_clamp << GPU_TA_PM2_CLAMP_SHIFT) & GPU_TA_PM2_CLAMP_MASK;
dst->mode2 |= (src->gen.alpha << GPU_TA_PM2_ALPHA_SHIFT) & GPU_TA_PM2_ALPHA_MASK;
dst->mode3 = 0;
if(src->txr.enable == GPU_TEXTURE_DISABLE) {
/* Texturing was disabled so we simulate it with a white texture */
if(!DEFAULT_TEXTURE) {
uint16_t texture[8 * 8];
DEFAULT_TEXTURE = (uint8_t*) GPUMemoryAlloc(8 * 8 * 2);
for(int i = 0; i < 8 * 8 * 2; ++i) {
DEFAULT_TEXTURE[i] = 0xff;
for(int i = 0; i < 8 * 8; ++i) {
texture[i] = 0xffff;
}
GPUTextureLoad(texture, DEFAULT_TEXTURE, sizeof(texture));
}
dst->mode2 |= (DimensionFlag(8) << GPU_TA_PM2_USIZE_SHIFT) & GPU_TA_PM2_USIZE_MASK;
dst->mode2 |= (DimensionFlag(8) << GPU_TA_PM2_VSIZE_SHIFT) & GPU_TA_PM2_VSIZE_MASK;
dst->mode2 |= (GPU_TXRENV_MODULATE << GPU_TA_PM2_TXRENV_SHIFT) & GPU_TA_PM2_TXRENV_MASK;
dst->mode3 |= (GPU_TXRFMT_RGB565 << GPU_TA_PM3_TXRFMT_SHIFT) & GPU_TA_PM3_TXRFMT_MASK;
dst->mode3 |= ((GPU_TXRFMT_RGB565 | GPU_TXRFMT_NONTWIDDLED) << GPU_TA_PM3_TXRFMT_SHIFT) & GPU_TA_PM3_TXRFMT_MASK;
/* Convert the texture address */
txr_base = (uint32_t) DEFAULT_TEXTURE;
txr_base = (txr_base & 0x00fffff8) >> 3;

View File

@ -20,6 +20,10 @@ void* GPUMemoryAlloc(size_t size) {
return pvr_mem_malloc(size);
}
void GPUTextureLoad(const void* src, void* dst, size_t size) {
pvr_txr_load(src, dst, size);
}
GL_FORCE_INLINE bool glIsVertex(const float flags) {
return flags == GPU_CMD_VERTEX_EOL || flags == GPU_CMD_VERTEX;
}
@ -199,7 +203,15 @@ void SceneListSubmit(Vertex* vertices, int n) {
Vertex* v0 = vertices;
for(int i = 0; i < n - 1; ++i, ++v0) {
if(v0->flags == GPU_CMD_USERCLIP) {
SUBMIT_QUEUED_VERTEX(GPU_CMD_VERTEX_EOL);
_glPushHeader(v0, 1);
visible_mask = 0;
continue;
}
if(is_header(v0)) {
SUBMIT_QUEUED_VERTEX(GPU_CMD_VERTEX_EOL);
PolyHeader* header = (PolyHeader*) v0;
if(header->meta.texture_is_strided && header->meta.texture_stride != CURRENT_TEXTURE_STRIDE) {
_glPVRSetTextureStride(header->meta.texture_stride);

View File

@ -167,6 +167,7 @@ static inline size_t GPUMemoryAvailable() {
}
void* GPUMemoryAlloc(size_t size);
void GPUTextureLoad(const void* src, void* dst, size_t size);
static inline void GPUSetPaletteFormat(GPUPaletteFormat format) {
pvr_set_pal_format((pvr_palfmt_t) format);
}

View File

@ -569,6 +569,10 @@ void* GPUMemoryAlloc(size_t size) {
}
}
void GPUTextureLoad(const void* src, void* dst, size_t size) {
memcpy(dst, src, size);
}
void GPUSetPaletteFormat(GPUPaletteFormat format) {
}

View File

@ -62,6 +62,7 @@ enum GPUPaletteFormat;
size_t GPUMemoryAvailable();
void* GPUMemoryAlloc(size_t size);
void GPUTextureLoad(const void* src, void* dst, size_t size);
void GPUSetPaletteFormat(GPUPaletteFormat format);
void GPUSetPaletteEntry(uint32_t idx, uint32_t value);
@ -73,4 +74,3 @@ void GPUSetFogLinear(float start, float end);
void GPUSetFogExp(float density);
void GPUSetFogExp2(float density);
void GPUSetFogColor(float r, float g, float b, float a);

View File

@ -441,6 +441,7 @@ GLuint _glUsedTextureMemory();
GLuint _glFreeContiguousTextureMemory();
void _glApplyScissor(bool force);
void _glInvalidateScissor(void);
void _glSetColorMaterialMask(GLenum mask);
void _glSetColorMaterialMode(GLenum mode);
GLenum _glColorMaterialMode();

View File

@ -5,6 +5,10 @@
#include "../include/GL/glext.h"
#include "private.h"
#define SCISSOR_APPLIED_OP 0x1u
#define SCISSOR_APPLIED_PT 0x2u
#define SCISSOR_APPLIED_TR 0x4u
static struct {
GLboolean is_dirty;
@ -33,7 +37,7 @@ static struct {
GLint y;
GLsizei width;
GLsizei height;
GLboolean applied;
unsigned int applied_lists;
} scissor_rect;
GLenum blend_sfactor;
@ -87,7 +91,7 @@ static struct {
.scissor_test_enabled = GL_FALSE,
.fog_enabled = GL_FALSE,
.depth_mask_enabled = GL_FALSE,
.scissor_rect = {0, 0, 640, 480, false},
.scissor_rect = {0, 0, 640, 480, 0},
.blend_sfactor = GL_ONE,
.blend_dfactor = GL_ZERO,
.blend_enabled = GL_FALSE,
@ -553,6 +557,7 @@ GLAPI void APIENTRY glEnable(GLenum cap) {
case GL_SCISSOR_TEST: {
if(GPUState.scissor_test_enabled != GL_TRUE) {
GPUState.scissor_test_enabled = GL_TRUE;
GPUState.scissor_rect.applied_lists = 0;
GPUState.is_dirty = GL_TRUE;
}
} break;
@ -670,6 +675,7 @@ GLAPI void APIENTRY glDisable(GLenum cap) {
case GL_SCISSOR_TEST: {
if(GPUState.scissor_test_enabled != GL_FALSE) {
GPUState.scissor_test_enabled = GL_FALSE;
GPUState.scissor_rect.applied_lists = 0;
GPUState.is_dirty = GL_TRUE;
}
} break;
@ -953,10 +959,8 @@ void APIENTRY glScissor(GLint x, GLint y, GLsizei width, GLsizei height) {
GPUState.scissor_rect.y = y;
GPUState.scissor_rect.width = width;
GPUState.scissor_rect.height = height;
GPUState.scissor_rect.applied = false;
GPUState.scissor_rect.applied_lists = 0;
GPUState.is_dirty = GL_TRUE; // FIXME: do we need this?
_glApplyScissor(false);
}
/* Setup the hardware user clip rectangle.
@ -982,48 +986,88 @@ void APIENTRY glScissor(GLint x, GLint y, GLsizei width, GLsizei height) {
at the right place, either when enabling the scissor test, or
when the scissor test changes.
*/
static unsigned int _glActiveScissorListBit(const PolyList* list) {
if(list == _glOpaquePolyList()) {
return SCISSOR_APPLIED_OP;
}
if(list == _glPunchThruPolyList()) {
return SCISSOR_APPLIED_PT;
}
return SCISSOR_APPLIED_TR;
}
void _glInvalidateScissor(void) {
GPUState.scissor_rect.applied_lists = 0;
}
void _glApplyScissor(bool force) {
/* Don't do anyting if clipping is disabled */
/* Don't do anything if clipping is disabled */
if(!GPUState.scissor_test_enabled) {
return;
}
/* Don't apply if we already applied - nothing changed */
if(GPUState.scissor_rect.applied && !force) {
PolyList* target = _glActivePolyList();
unsigned int active_list_bit = _glActiveScissorListBit(target);
/* Don't apply if this list already has the current clip rectangle. */
if((GPUState.scissor_rect.applied_lists & active_list_bit) && !force) {
return;
}
PVRTileClipCommand c;
GLint miny, maxx, maxy;
typedef union {
Vertex vertex;
PVRTileClipCommand clip;
} ScissorCommand;
ScissorCommand c = {0};
const VideoMode* vid_mode = GetVideoMode();
GLsizei scissor_width = MAX(MIN(GPUState.scissor_rect.width, vid_mode->width), 0);
GLsizei scissor_height = MAX(MIN(GPUState.scissor_rect.height, vid_mode->height), 0);
GLint x0 = GPUState.scissor_rect.x;
GLint y0 = GPUState.scissor_rect.y;
GLint x1 = x0 + GPUState.scissor_rect.width;
GLint y1 = y0 + GPUState.scissor_rect.height;
/* force the origin to the lower left-hand corner of the screen */
miny = (vid_mode->height - scissor_height) - GPUState.scissor_rect.y;
maxx = (scissor_width + GPUState.scissor_rect.x);
maxy = (scissor_height + miny);
/*
* glScissor uses OpenGL window coordinates: lower-left origin,
* x/y inclusive start, width/height extent. Clip to the framebuffer
* before converting to PVR tile coordinates.
*/
x0 = CLAMP(x0, 0, vid_mode->width);
y0 = CLAMP(y0, 0, vid_mode->height);
x1 = CLAMP(x1, 0, vid_mode->width);
y1 = CLAMP(y1, 0, vid_mode->height);
/* load command structure while mapping screen coords to TA tiles */
c.flags = GPU_CMD_USERCLIP;
c.d1 = c.d2 = c.d3 = 0;
uint16_t vw = vid_mode->width >> 5;
uint16_t vh = vid_mode->height >> 5;
uint16_t max_tx = vw - 1;
uint16_t max_ty = vh - 1;
c.sx = CLAMP(GPUState.scissor_rect.x >> 5, 0, vw);
c.sy = CLAMP(miny >> 5, 0, vh);
c.ex = CLAMP((maxx >> 5) - 1, 0, vw);
c.ey = CLAMP((maxy >> 5) - 1, 0, vh);
/* load command structure while mapping screen coords to TA tiles */
c.clip.flags = GPU_CMD_USERCLIP;
c.clip.d1 = c.clip.d2 = c.clip.d3 = 0;
aligned_vector_push_back(&_glOpaquePolyList()->vector, &c, 1);
aligned_vector_push_back(&_glPunchThruPolyList()->vector, &c, 1);
aligned_vector_push_back(&_glTransparentPolyList()->vector, &c, 1);
if(x1 <= x0 || y1 <= y0) {
c.clip.sx = 0;
c.clip.sy = 0;
c.clip.ex = 0;
c.clip.ey = 0;
} else {
GLint pvr_y0 = vid_mode->height - y1;
GLint pvr_y1 = vid_mode->height - y0;
GPUState.scissor_rect.applied = true;
c.clip.sx = CLAMP(x0 >> 5, 0, max_tx);
c.clip.sy = CLAMP(pvr_y0 >> 5, 0, max_ty);
c.clip.ex = CLAMP((x1 - 1) >> 5, 0, max_tx);
c.clip.ey = CLAMP((pvr_y1 - 1) >> 5, 0, max_ty);
}
aligned_vector_push_back(&target->vector, &c.vertex, 1);
GPUState.scissor_rect.applied_lists |= active_list_bit;
GPUState.is_dirty = GL_TRUE;
}
void glStencilFunc(GLenum func, GLint ref, GLuint mask) {

View File

@ -1842,12 +1842,6 @@ void APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalFormat,
TextureConversionFunc conversion = NULL;
int needs_conversion = _determineConversion(cleanInternalFormat, format, type, &conversion);
// Hack: If we're doing a 4bpp source (via glCompressedTexture...)
// halve the srcBytes
if(format == GL_COLOR_INDEX4_EXT || format == GL_COLOR_INDEX4_TWID_KOS) {
srcBytes /= 2;
}
/* If we're packing stuff, then the dest size is half what it would be */
if((needs_conversion & CONVERSION_TYPE_PACK) == CONVERSION_TYPE_PACK) {
destBytes /= 2;

View File

@ -0,0 +1,159 @@
#ifdef _arch_dreamcast
#include <kos.h>
#endif
#include <stdio.h>
#include "GL/gl.h"
#include "GL/glkos.h"
#define SCREEN_W 640
#define SCREEN_H 480
static int check_start(void)
{
#ifdef _arch_dreamcast
static maple_device_t *cont;
cont_state_t *state;
if(!cont || !cont->valid)
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(cont) {
state = (cont_state_t *)maple_dev_status(cont);
if(state)
return state->buttons & CONT_START;
}
#endif
return 0;
}
static void setup(void)
{
glKosInit();
glDisable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glViewport(0, 0, SCREEN_W, SCREEN_H);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, SCREEN_W, SCREEN_H, 0.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDisable(GL_SCISSOR_TEST);
}
static void rect_quad(float x0, float y0, float x1, float y1)
{
glBegin(GL_QUADS);
glVertex2f(x0, y0);
glVertex2f(x1, y0);
glVertex2f(x1, y1);
glVertex2f(x0, y1);
glEnd();
}
static void rect_triangles(float x0, float y0, float x1, float y1)
{
glBegin(GL_TRIANGLES);
glVertex2f(x0, y0);
glVertex2f(x1, y0);
glVertex2f(x1, y1);
glVertex2f(x0, y0);
glVertex2f(x1, y1);
glVertex2f(x0, y1);
glEnd();
}
static void rect_polygon4(float x0, float y0, float x1, float y1)
{
glBegin(GL_POLYGON);
glVertex2f(x0, y0);
glVertex2f(x1, y0);
glVertex2f(x1, y1);
glVertex2f(x0, y1);
glEnd();
}
static void octagon_points(float cx, float cy, float r)
{
glVertex2f(cx + 0.00f * r, cy - 1.00f * r);
glVertex2f(cx + 0.71f * r, cy - 0.71f * r);
glVertex2f(cx + 1.00f * r, cy + 0.00f * r);
glVertex2f(cx + 0.71f * r, cy + 0.71f * r);
glVertex2f(cx + 0.00f * r, cy + 1.00f * r);
glVertex2f(cx - 0.71f * r, cy + 0.71f * r);
glVertex2f(cx - 1.00f * r, cy + 0.00f * r);
glVertex2f(cx - 0.71f * r, cy - 0.71f * r);
}
static void fan8(float cx, float cy, float r)
{
glBegin(GL_TRIANGLE_FAN);
octagon_points(cx, cy, r);
glEnd();
}
static void polygon8(float cx, float cy, float r)
{
glBegin(GL_POLYGON);
octagon_points(cx, cy, r);
glEnd();
}
static void draw_case(float y, void (*draw)(float, float, float, float),
float x0, float y0, float x1, float y1,
GLubyte r, GLubyte g, GLubyte b)
{
glColor4ub(r, g, b, 255);
draw(x0, y0 + y, x1, y1 + y);
}
static void draw_scene(void)
{
static int announced = 0;
if(!announced) {
printf("case 1: GL_QUADS cyan\n");
printf("case 2: GL_POLYGON(4) cyan\n");
printf("case 3: GL_TRIANGLES cyan\n");
printf("case 4: GL_POLYGON(4) blue\n");
printf("case 5: GL_POLYGON(4) magenta\n");
printf("case 6: GL_TRIANGLE_FAN(8) cyan\n");
printf("case 7: GL_POLYGON(8) cyan\n");
announced = 1;
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
draw_case(0.0f, rect_quad, 40.0f, 40.0f, 140.0f, 140.0f, 0, 255, 255);
draw_case(0.0f, rect_polygon4, 180.0f, 40.0f, 280.0f, 140.0f, 0, 255, 255);
draw_case(0.0f, rect_triangles, 320.0f, 40.0f, 420.0f, 140.0f, 0, 255, 255);
draw_case(150.0f, rect_polygon4, 40.0f, 40.0f, 140.0f, 140.0f, 0, 0, 255);
draw_case(150.0f, rect_polygon4, 180.0f, 40.0f, 280.0f, 140.0f, 255, 0, 255);
glColor4ub(0, 255, 255, 255);
fan8(360.0f, 205.0f, 42.0f);
glColor4ub(0, 255, 255, 255);
polygon8(520.0f, 205.0f, 42.0f);
glKosSwapBuffers();
}
int main(void)
{
setup();
while(!check_start()) {
draw_scene();
}
return 0;
}

View File

@ -6,8 +6,30 @@
#include "GL/glu.h"
#include "GL/glkos.h"
#define SCREEN_W 640
#define SCREEN_H 480
void InitGL(int Width, int Height)
#define SCISSOR_X 160
#define SCISSOR_Y 128
#define SCISSOR_W 320
#define SCISSOR_H 224
static void setup_projection(int width, int height)
{
if(height == 0)
height = 1;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
static void init_gl(int width, int height)
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0);
@ -15,39 +37,20 @@ void InitGL(int Width, int Height)
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
setup_projection(width, height);
gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW);
/* We cut out a square in the middle of the viewport to render to */
glEnable(GL_SCISSOR_TEST);
glScissor(160, 120, 320, 240);
glScissor(SCISSOR_X, SCISSOR_Y, SCISSOR_W, SCISSOR_H);
}
/* The function called when our window is resized (which shouldn't happen, because we're fullscreen) */
void ReSizeGLScene(int Width, int Height)
static int check_start(void)
{
if (Height == 0)
Height = 1;
glViewport(0, 0, Width, Height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW);
}
int check_start() {
#ifdef _arch_dreamcast
maple_device_t *cont;
static maple_device_t *cont;
cont_state_t *state;
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(!cont || !cont->valid)
cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
if(cont) {
state = (cont_state_t *)maple_dev_status(cont);
@ -60,14 +63,62 @@ int check_start() {
return 0;
}
/* The main drawing function. */
void DrawGLScene()
static void draw_scissor_outline(void)
{
glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0.0, SCREEN_W, SCREEN_H, 0.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
{
GLfloat x = (GLfloat)SCISSOR_X;
GLfloat y = (GLfloat)(SCREEN_H - SCISSOR_Y - SCISSOR_H);
GLfloat w = (GLfloat)SCISSOR_W;
GLfloat h = (GLfloat)SCISSOR_H;
glDisable(GL_TEXTURE_2D);
glColor4ub(255, 255, 0, 255);
glBegin(GL_LINES);
glVertex2f(x, y);
glVertex2f(x + w, y);
glVertex2f(x + w, y);
glVertex2f(x + w, y + h);
glVertex2f(x + w, y + h);
glVertex2f(x, y + h);
glVertex2f(x, y + h);
glVertex2f(x, y);
glEnd();
}
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glEnable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
}
static void draw_scene_geometry(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(-3.0f, 1.5f, -10.0f);
glColor4ub(255, 0, 0, 255);
glBegin(GL_TRIANGLES);
glVertex3f( 0.0f, 1.0f, 0.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);
@ -76,7 +127,7 @@ void DrawGLScene()
glTranslatef(3.0f, 0.0f, 0.0f);
glColor4ub(0, 255, 0, 255);
glBegin(GL_QUADS);
glVertex3f(-1.0f, 1.0f, 0.0f);
glVertex3f( 1.0f, 1.0f, 0.0f);
@ -86,6 +137,7 @@ void DrawGLScene()
glTranslatef(3.0f, 0.0f, 0.0f);
glColor4ub(0, 0, 255, 255);
glBegin(GL_POLYGON);
glVertex3f(-0.0f, 1.0f, 0.0f);
glVertex3f(-0.75f, 0.75f, 0.0f);
@ -99,8 +151,8 @@ void DrawGLScene()
glTranslatef(-6.0f, -3.0f, 0.0f);
glBegin(GL_POLYGON);
glColor4ub(255, 128, 0, 255);
glBegin(GL_TRIANGLES);
glVertex3f( 0.0f, 1.0f, 0.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f);
@ -108,7 +160,7 @@ void DrawGLScene()
glTranslatef(3.0f, 0.0f, 0.0f);
glColor4ub(0, 255, 255, 255);
glBegin(GL_POLYGON);
glVertex3f(-1.0f, 1.0f, 0.0f);
glVertex3f( 1.0f, 1.0f, 0.0f);
@ -118,6 +170,7 @@ void DrawGLScene()
glTranslatef(3.0f, 0.0f, 0.0f);
glColor4ub(255, 0, 255, 255);
glBegin(GL_POLYGON);
glVertex3f(-0.0f, 1.0f, 0.0f);
glVertex3f(-0.75f, 0.75f, 0.0f);
@ -128,22 +181,36 @@ void DrawGLScene()
glVertex3f( 1.0f, 0.0f, 0.0f);
glVertex3f( 0.75f, 0.75f, 0.0f);
glEnd();
}
static void draw_gl_scene(void)
{
glDisable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
draw_scissor_outline();
glEnable(GL_SCISSOR_TEST);
glScissor(SCISSOR_X, SCISSOR_Y, SCISSOR_W, SCISSOR_H);
draw_scene_geometry();
glKosSwapBuffers();
}
int main(int argc, char **argv)
{
glKosInit();
(void)argc;
(void)argv;
InitGL(640, 480);
ReSizeGLScene(640, 480);
glKosInit();
init_gl(SCREEN_W, SCREEN_H);
while(1) {
if(check_start())
break;
DrawGLScene();
draw_gl_scene();
}
return 0;

View File

@ -251,6 +251,63 @@ public:
assert_is_not_null(t->palette);
}
void test_packed_color_index4_upload_uses_packed_source_size() {
std::vector<uint8_t> img((8 * 8) / 2, 0xaa);
glTexImage2D(GL_TEXTURE_2D, 0, GL_COLOR_INDEX4_EXT, 8, 8, 0,
GL_COLOR_INDEX4_EXT, GL_UNSIGNED_BYTE, img.data());
assert_equal(glGetError(), GL_NO_ERROR);
TextureObject* t = _glGetBoundTexture();
assert_true(t->isPaletted);
assert_equal(t->internalFormat, GL_COLOR_INDEX4_TWID_KOS);
assert_equal(t->baseDataSize, (GLuint)((8 * 8) / 2));
}
void test_packed_color_index4_upload_respects_unpack_row_length() {
std::vector<uint8_t> img(((12 * 8) + 1) / 2, 0xaa);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 12);
glTexImage2D(GL_TEXTURE_2D, 0, GL_COLOR_INDEX4_EXT, 8, 8, 0,
GL_COLOR_INDEX4_EXT, GL_UNSIGNED_BYTE, img.data());
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
assert_equal(glGetError(), GL_NO_ERROR);
TextureObject* t = _glGetBoundTexture();
assert_true(t->isPaletted);
assert_equal(t->internalFormat, GL_COLOR_INDEX4_TWID_KOS);
assert_equal(t->baseDataSize, (GLuint)((8 * 8) / 2));
}
void test_compressed_palette4_upload_uses_packed_source_size() {
std::vector<uint8_t> img((16 * 3) + ((8 * 8) / 2), 0xaa);
glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, GL_PALETTE4_RGB8_OES,
8, 8, 0, (GLsizei)img.size(), img.data());
assert_equal(glGetError(), GL_NO_ERROR);
TextureObject* t = _glGetBoundTexture();
assert_true(t->isPaletted);
assert_equal(t->internalFormat, GL_COLOR_INDEX4_TWID_KOS);
assert_equal(t->baseDataSize, (GLuint)((8 * 8) / 2));
assert_is_not_null(t->palette);
}
void test_color_index8_source_can_pack_to_color_index4() {
std::vector<uint8_t> img(8 * 8, 0x0a);
glTexImage2D(GL_TEXTURE_2D, 0, GL_COLOR_INDEX4_EXT, 8, 8, 0,
GL_COLOR_INDEX, GL_UNSIGNED_BYTE, img.data());
assert_equal(glGetError(), GL_NO_ERROR);
TextureObject* t = _glGetBoundTexture();
assert_true(t->isPaletted);
assert_equal(t->internalFormat, GL_COLOR_INDEX4_TWID_KOS);
assert_equal(t->baseDataSize, (GLuint)((8 * 8) / 2));
}
/* ------------------------------------------------- Error handling */
void test_non_power_of_two_width_raises_invalid_value() {