Video: Remove assumption about video backend dimensions

This commit is contained in:
Jeffrey Pfau 2016-02-04 23:16:50 -08:00
parent 1768721e7e
commit b325376f05
7 changed files with 57 additions and 46 deletions

View File

@ -5,7 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gl.h" #include "gl.h"
#include "gba/video.h" #include "util/math.h"
static const GLint _glVertices[] = { static const GLint _glVertices[] = {
0, 0, 0, 0,
@ -21,7 +21,7 @@ static const GLint _glTexCoords[] = {
0, 1 0, 1
}; };
static void GBAGLContextInit(struct VideoBackend* v, WHandle handle) { static void GBAGLContextInit(struct VideoBackend* v, unsigned width, unsigned height, WHandle handle) {
UNUSED(handle); UNUSED(handle);
struct GBAGLContext* context = (struct GBAGLContext*) v; struct GBAGLContext* context = (struct GBAGLContext*) v;
glGenTextures(1, &context->tex); glGenTextures(1, &context->tex);
@ -31,15 +31,17 @@ static void GBAGLContextInit(struct VideoBackend* v, WHandle handle) {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#endif #endif
v->width = width;
v->height = height;
#ifdef COLOR_16_BIT #ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5 #ifdef COLOR_5_6_5
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
#else #else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0);
#endif #endif
#else #else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
#endif #endif
} }
@ -48,9 +50,9 @@ static void GBAGLContextDeinit(struct VideoBackend* v) {
glDeleteTextures(1, &context->tex); glDeleteTextures(1, &context->tex);
} }
static void GBAGLContextResized(struct VideoBackend* v, int w, int h) { static void GBAGLContextResized(struct VideoBackend* v, unsigned w, unsigned h) {
int drawW = w; unsigned drawW = w;
int drawH = h; unsigned drawH = h;
if (v->lockAspectRatio) { if (v->lockAspectRatio) {
if (w * 2 > h * 3) { if (w * 2 > h * 3) {
drawW = h * 3 / 2; drawW = h * 3 / 2;
@ -80,7 +82,7 @@ void GBAGLContextDrawFrame(struct VideoBackend* v) {
glTexCoordPointer(2, GL_INT, 0, _glTexCoords); glTexCoordPointer(2, GL_INT, 0, _glTexCoords);
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glLoadIdentity(); glLoadIdentity();
glOrtho(0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, 0, 1); glOrtho(0, v->width, v->height, 0, 0, 1);
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); glLoadIdentity();
glBindTexture(GL_TEXTURE_2D, context->tex); glBindTexture(GL_TEXTURE_2D, context->tex);
@ -99,12 +101,12 @@ void GBAGLContextPostFrame(struct VideoBackend* v, const void* frame) {
glBindTexture(GL_TEXTURE_2D, context->tex); glBindTexture(GL_TEXTURE_2D, context->tex);
#ifdef COLOR_16_BIT #ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5 #ifdef COLOR_5_6_5
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, v->width, v->height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame);
#else #else
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, v->width, v->height, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame);
#endif #endif
#else #else
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, GL_RGBA, GL_UNSIGNED_BYTE, frame); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, v->width, v->height, GL_RGBA, GL_UNSIGNED_BYTE, frame);
#endif #endif
} }

View File

@ -5,7 +5,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gles2.h" #include "gles2.h"
#include "gba/video.h"
#include "util/configuration.h" #include "util/configuration.h"
#include "util/formatting.h" #include "util/formatting.h"
#include "util/vector.h" #include "util/vector.h"
@ -72,22 +71,24 @@ static const GLfloat _vertices[] = {
1.f, -1.f, 1.f, -1.f,
}; };
static void GBAGLES2ContextInit(struct VideoBackend* v, WHandle handle) { static void GBAGLES2ContextInit(struct VideoBackend* v, unsigned width, unsigned height, WHandle handle) {
UNUSED(handle); UNUSED(handle);
struct GBAGLES2Context* context = (struct GBAGLES2Context*) v; struct GBAGLES2Context* context = (struct GBAGLES2Context*) v;
glGenTextures(1, &context->tex); glGenTextures(1, &context->tex);
glBindTexture(GL_TEXTURE_2D, context->tex); glBindTexture(GL_TEXTURE_2D, context->tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
v->width = width;
v->height = height;
#ifdef COLOR_16_BIT #ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5 #ifdef COLOR_5_6_5
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
#else #else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0);
#endif #endif
#else #else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
#endif #endif
glClearColor(0.f, 0.f, 0.f, 1.f); glClearColor(0.f, 0.f, 0.f, 1.f);
@ -138,7 +139,9 @@ static void GBAGLES2ContextInit(struct VideoBackend* v, WHandle handle) {
GBAGLES2ShaderInit(&context->initialShader, _vertexShader, _fragmentShader, -1, -1, false, uniforms, 4); GBAGLES2ShaderInit(&context->initialShader, _vertexShader, _fragmentShader, -1, -1, false, uniforms, 4);
GBAGLES2ShaderInit(&context->finalShader, 0, 0, 0, 0, false, 0, 0); GBAGLES2ShaderInit(&context->finalShader, 0, 0, 0, 0, false, 0, 0);
glDeleteFramebuffers(1, &context->finalShader.fbo); glDeleteFramebuffers(1, &context->finalShader.fbo);
glDeleteTextures(1, &context->finalShader.tex);
context->finalShader.fbo = 0; context->finalShader.fbo = 0;
context->finalShader.tex = 0;
} }
static void GBAGLES2ContextDeinit(struct VideoBackend* v) { static void GBAGLES2ContextDeinit(struct VideoBackend* v) {
@ -149,9 +152,9 @@ static void GBAGLES2ContextDeinit(struct VideoBackend* v) {
free(context->initialShader.uniforms); free(context->initialShader.uniforms);
} }
static void GBAGLES2ContextResized(struct VideoBackend* v, int w, int h) { static void GBAGLES2ContextResized(struct VideoBackend* v, unsigned w, unsigned h) {
int drawW = w; unsigned drawW = w;
int drawH = h; unsigned drawH = h;
if (v->lockAspectRatio) { if (v->lockAspectRatio) {
if (w * 2 > h * 3) { if (w * 2 > h * 3) {
drawW = h * 3 / 2; drawW = h * 3 / 2;
@ -159,7 +162,7 @@ static void GBAGLES2ContextResized(struct VideoBackend* v, int w, int h) {
drawH = w * 2 / 3; drawH = w * 2 / 3;
} }
} }
glViewport(0, 0, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS); glViewport(0, 0, v->width, v->height);
glClearColor(0.f, 0.f, 0.f, 1.f); glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
glViewport((w - drawW) / 2, (h - drawH) / 2, drawW, drawH); glViewport((w - drawW) / 2, (h - drawH) / 2, drawW, drawH);
@ -171,7 +174,7 @@ static void GBAGLES2ContextClear(struct VideoBackend* v) {
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
} }
void _drawShader(struct GBAGLES2Shader* shader) { void _drawShader(struct GBAGLES2Context* context, struct GBAGLES2Shader* shader) {
GLint viewport[4]; GLint viewport[4];
glBindFramebuffer(GL_FRAMEBUFFER, shader->fbo); glBindFramebuffer(GL_FRAMEBUFFER, shader->fbo);
if (shader->blend) { if (shader->blend) {
@ -190,19 +193,23 @@ void _drawShader(struct GBAGLES2Shader* shader) {
if (!shader->width) { if (!shader->width) {
drawW = viewport[2]; drawW = viewport[2];
padW = viewport[0]; padW = viewport[0];
} else if (shader->width < 0) {
drawW = context->d.width * -shader->width;
} }
if (!shader->height) { if (!shader->height) {
drawH = viewport[3]; drawH = viewport[3];
padH = viewport[1]; padH = viewport[1];
} else if (shader->height < 0) {
drawH = context->d.height * -shader->height;
} }
if (shader->integerScaling) { if (shader->integerScaling) {
padW = 0; padW = 0;
padH = 0; padH = 0;
drawW -= drawW % VIDEO_HORIZONTAL_PIXELS; drawW -= drawW % context->d.width;
drawH -= drawH % VIDEO_VERTICAL_PIXELS; drawH -= drawH % context->d.height;
} }
glViewport(padW, padH, drawW, drawH); glViewport(padW, padH, drawW, drawH);
if (!shader->width || !shader->height) { if (shader->tex && (shader->width <= 0 || shader->height <= 0)) {
GLint oldTex; GLint oldTex;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTex); glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTex);
glBindTexture(GL_TEXTURE_2D, shader->tex); glBindTexture(GL_TEXTURE_2D, shader->tex);
@ -278,12 +285,12 @@ void GBAGLES2ContextDrawFrame(struct VideoBackend* v) {
glBindTexture(GL_TEXTURE_2D, context->tex); glBindTexture(GL_TEXTURE_2D, context->tex);
context->finalShader.filter = v->filter; context->finalShader.filter = v->filter;
_drawShader(&context->initialShader); _drawShader(context, &context->initialShader);
size_t n; size_t n;
for (n = 0; n < context->nShaders; ++n) { for (n = 0; n < context->nShaders; ++n) {
_drawShader(&context->shaders[n]); _drawShader(context, &context->shaders[n]);
} }
_drawShader(&context->finalShader); _drawShader(context, &context->finalShader);
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
glUseProgram(0); glUseProgram(0);
} }
@ -293,12 +300,12 @@ void GBAGLES2ContextPostFrame(struct VideoBackend* v, const void* frame) {
glBindTexture(GL_TEXTURE_2D, context->tex); glBindTexture(GL_TEXTURE_2D, context->tex);
#ifdef COLOR_16_BIT #ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5 #ifdef COLOR_5_6_5
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, v->width, v->height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame);
#else #else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, v->width, v->height, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame);
#endif #endif
#else #else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, v->width, v->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame);
#endif #endif
} }
@ -317,8 +324,8 @@ void GBAGLES2ContextCreate(struct GBAGLES2Context* context) {
} }
void GBAGLES2ShaderInit(struct GBAGLES2Shader* shader, const char* vs, const char* fs, int width, int height, bool integerScaling, struct GBAGLES2Uniform* uniforms, size_t nUniforms) { void GBAGLES2ShaderInit(struct GBAGLES2Shader* shader, const char* vs, const char* fs, int width, int height, bool integerScaling, struct GBAGLES2Uniform* uniforms, size_t nUniforms) {
shader->width = width >= 0 ? width : VIDEO_HORIZONTAL_PIXELS; shader->width = width;
shader->height = height >= 0 ? height : VIDEO_VERTICAL_PIXELS; shader->height = height;
shader->integerScaling = integerScaling; shader->integerScaling = integerScaling;
shader->filter = false; shader->filter = false;
shader->blend = false; shader->blend = false;
@ -333,7 +340,7 @@ void GBAGLES2ShaderInit(struct GBAGLES2Shader* shader, const char* vs, const cha
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (shader->width && shader->height) { if (shader->width > 0 && shader->height > 0) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, shader->width, shader->height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, shader->width, shader->height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
} }

View File

@ -51,8 +51,8 @@ struct GBAGLES2Uniform {
}; };
struct GBAGLES2Shader { struct GBAGLES2Shader {
unsigned width; int width;
unsigned height; int height;
bool integerScaling; bool integerScaling;
bool filter; bool filter;
bool blend; bool blend;

View File

@ -221,7 +221,7 @@ PainterGL::PainterGL(QGLWidget* parent, QGLFormat::OpenGLVersionFlags glVersion)
#if defined(_WIN32) && defined(USE_EPOXY) #if defined(_WIN32) && defined(USE_EPOXY)
epoxy_handle_external_wglMakeCurrent(); epoxy_handle_external_wglMakeCurrent();
#endif #endif
m_backend->init(m_backend, reinterpret_cast<WHandle>(m_gl->winId())); m_backend->init(m_backend, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, reinterpret_cast<WHandle>(m_gl->winId()));
#if !defined(_WIN32) || defined(USE_EPOXY) #if !defined(_WIN32) || defined(USE_EPOXY)
if (m_supportsShaders) { if (m_supportsShaders) {
m_shader.preprocessShader = static_cast<void*>(&reinterpret_cast<GBAGLES2Context*>(m_backend)->initialShader); m_shader.preprocessShader = static_cast<void*>(&reinterpret_cast<GBAGLES2Context*>(m_backend)->initialShader);

View File

@ -53,7 +53,7 @@ bool mSDLGLInitGBA(struct mSDLRenderer* renderer) {
renderer->gl.d.lockAspectRatio = renderer->lockAspectRatio; renderer->gl.d.lockAspectRatio = renderer->lockAspectRatio;
renderer->gl.d.filter = renderer->filter; renderer->gl.d.filter = renderer->filter;
renderer->gl.d.swap = mSDLGLCommonSwap; renderer->gl.d.swap = mSDLGLCommonSwap;
renderer->gl.d.init(&renderer->gl.d, 0); renderer->gl.d.init(&renderer->gl.d, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS, 0);
_doViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d); _doViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d);
return true; return true;
@ -71,16 +71,16 @@ bool mSDLGLInitGB(struct mSDLRenderer* renderer) {
mSDLGLCommonInit(renderer); mSDLGLCommonInit(renderer);
// TODO: Pass texture size along // TODO: Pass texture size along
renderer->outputBuffer = malloc(VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL); renderer->outputBuffer = malloc(GB_VIDEO_HORIZONTAL_PIXELS * GB_VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL);
memset(renderer->outputBuffer, 0, VIDEO_HORIZONTAL_PIXELS * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL); memset(renderer->outputBuffer, 0, GB_VIDEO_HORIZONTAL_PIXELS * GB_VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL);
renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer + GB_GBA_CENTER, VIDEO_HORIZONTAL_PIXELS); renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, GB_VIDEO_HORIZONTAL_PIXELS);
GBAGLContextCreate(&renderer->gl); GBAGLContextCreate(&renderer->gl);
renderer->gl.d.user = renderer; renderer->gl.d.user = renderer;
renderer->gl.d.lockAspectRatio = renderer->lockAspectRatio; renderer->gl.d.lockAspectRatio = renderer->lockAspectRatio;
renderer->gl.d.filter = renderer->filter; renderer->gl.d.filter = renderer->filter;
renderer->gl.d.swap = mSDLGLCommonSwap; renderer->gl.d.swap = mSDLGLCommonSwap;
renderer->gl.d.init(&renderer->gl.d, 0); renderer->gl.d.init(&renderer->gl.d, GB_VIDEO_HORIZONTAL_PIXELS, GB_VIDEO_VERTICAL_PIXELS, 0);
_doViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d); _doViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d);
return true; return true;

View File

@ -117,10 +117,10 @@ int main(int argc, char** argv) {
else if (GBIsROM(vf)) { else if (GBIsROM(vf)) {
platform = PLATFORM_GB; platform = PLATFORM_GB;
if (!opts.width) { if (!opts.width) {
opts.width = /*GB_*/VIDEO_HORIZONTAL_PIXELS; opts.width = GB_VIDEO_HORIZONTAL_PIXELS;
} }
if (!opts.height) { if (!opts.height) {
opts.height = /*GB_*/VIDEO_VERTICAL_PIXELS; opts.height = GB_VIDEO_VERTICAL_PIXELS;
} }
renderer.core = GBCoreCreate(); renderer.core = GBCoreCreate();
#ifdef BUILD_GL #ifdef BUILD_GL

View File

@ -16,17 +16,19 @@ typedef void* WHandle;
#endif #endif
struct VideoBackend { struct VideoBackend {
void (*init)(struct VideoBackend*, WHandle handle); void (*init)(struct VideoBackend*, unsigned width, unsigned height, WHandle handle);
void (*deinit)(struct VideoBackend*); void (*deinit)(struct VideoBackend*);
void (*swap)(struct VideoBackend*); void (*swap)(struct VideoBackend*);
void (*clear)(struct VideoBackend*); void (*clear)(struct VideoBackend*);
void (*resized)(struct VideoBackend*, int w, int h); void (*resized)(struct VideoBackend*, unsigned w, unsigned h);
void (*postFrame)(struct VideoBackend*, const void* frame); void (*postFrame)(struct VideoBackend*, const void* frame);
void (*drawFrame)(struct VideoBackend*); void (*drawFrame)(struct VideoBackend*);
void (*setMessage)(struct VideoBackend*, const char* message); void (*setMessage)(struct VideoBackend*, const char* message);
void (*clearMessage)(struct VideoBackend*); void (*clearMessage)(struct VideoBackend*);
void* user; void* user;
unsigned width;
unsigned height;
bool filter; bool filter;
bool lockAspectRatio; bool lockAspectRatio;