111 lines
3.3 KiB
C++
111 lines
3.3 KiB
C++
/*
|
|
* Shared test fixture for GLdc tests that drive the GL API.
|
|
*
|
|
* On the Dreamcast the GPU/PVR (and the display) must be initialised exactly
|
|
* once: InitGPU() calls pvr_init() and ShutdownGPU() calls pvr_shutdown(), and
|
|
* tearing those down and back up between every test is both slow and fragile on
|
|
* real hardware / emulators. So this fixture:
|
|
*
|
|
* - initialises the GPU lazily on the first test and registers an atexit()
|
|
* handler to shut it down once, at program exit (window opens at start,
|
|
* closes at the end);
|
|
* - resets the mutable GL state to a known baseline before each test, without
|
|
* re-initialising the GPU.
|
|
*
|
|
* GL-driving test suites should derive from GLTestCase (instead of
|
|
* test::TestCase). If a suite needs extra per-test setup it should override
|
|
* set_up()/tear_down() and call GLTestCase::set_up()/tear_down() first.
|
|
*/
|
|
#pragma once
|
|
|
|
#include <cstdlib>
|
|
|
|
#include "tools/test.h"
|
|
|
|
#include <GL/gl.h>
|
|
#include <GL/glkos.h>
|
|
|
|
#include "GL/private.h"
|
|
#include "GL/state.h"
|
|
#include "containers/aligned_vector.h"
|
|
|
|
class GLTestCase : public test::TestCase {
|
|
public:
|
|
/* One-shot init flag (function-local static to keep this header-only). */
|
|
static bool& gpu_initialized() {
|
|
static bool v = false;
|
|
return v;
|
|
}
|
|
|
|
static void shutdown_gpu_at_exit() {
|
|
glKosShutdown();
|
|
}
|
|
|
|
static void ensure_gpu_initialized() {
|
|
if(gpu_initialized()) {
|
|
return;
|
|
}
|
|
|
|
GLdcConfig config;
|
|
glKosInitConfig(&config);
|
|
config.texture_twiddle = GL_FALSE;
|
|
glKosInitEx(&config);
|
|
|
|
gpu_initialized() = true;
|
|
|
|
/* Close the window / shut the PVR down once, when the process exits. */
|
|
atexit(GLTestCase::shutdown_gpu_at_exit);
|
|
}
|
|
|
|
/* Return all GL state to a predictable baseline. This deliberately avoids
|
|
* the allocating _glInit* helpers (immediate-mode buffer, texture/named
|
|
* arrays, framebuffers) so it is safe to call repeatedly. */
|
|
void reset_gl_state() {
|
|
aligned_vector_clear(&OP_LIST.vector);
|
|
aligned_vector_clear(&PT_LIST.vector);
|
|
aligned_vector_clear(&TR_LIST.vector);
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
glDisable(GL_BLEND);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDisable(GL_CULL_FACE);
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_FOG);
|
|
glDisable(GL_SCISSOR_TEST);
|
|
glDisable(GL_TEXTURE_TWIDDLE_KOS);
|
|
|
|
glBlendFunc(GL_ONE, GL_ZERO);
|
|
glDepthFunc(GL_LESS);
|
|
glShadeModel(GL_SMOOTH);
|
|
|
|
/* Restore the spec default so a test that changes pixel-store state
|
|
* doesn't leak into the next (we no longer re-init per test). */
|
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
glMatrixMode(GL_PROJECTION); glLoadIdentity();
|
|
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
|
|
glViewport(0, 0, 640, 480);
|
|
|
|
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
|
glTexCoord2f(0.0f, 0.0f);
|
|
glNormal3f(0.0f, 0.0f, 1.0f);
|
|
|
|
ATTRIB_LIST.enabled = 0;
|
|
ATTRIB_LIST.dirty = ~0u;
|
|
|
|
_glGPUStateMarkDirty();
|
|
|
|
/* Drain any error raised while resetting. */
|
|
while(glGetError() != GL_NO_ERROR) {}
|
|
}
|
|
|
|
void set_up() {
|
|
ensure_gpu_initialized();
|
|
reset_gl_state();
|
|
}
|
|
|
|
void tear_down() {}
|
|
};
|