Video: Start revising VideoBackend API

This commit is contained in:
Vicki Pfau 2023-02-12 17:33:44 -08:00
parent dd531637c2
commit d6c3b012d1
10 changed files with 219 additions and 122 deletions

View File

@ -0,0 +1,22 @@
/* Copyright (c) 2013-2023 Jeffrey Pfau
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef GEOMETRY_H
#define GEOMETRY_H
#include <mgba-util/common.h>
CXX_GUARD_START
struct Rectangle {
int x;
int y;
unsigned width;
unsigned height;
};
CXX_GUARD_END
#endif

View File

@ -21,76 +21,95 @@ static const GLint _glTexCoords[] = {
0, 1
};
static inline void _initTex(void) {
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
#ifndef _WIN32
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#endif
}
static void mGLContextInit(struct VideoBackend* v, WHandle handle) {
UNUSED(handle);
struct mGLContext* context = (struct mGLContext*) v;
v->width = 1;
v->height = 1;
memset(context->layerDims, 0, sizeof(context->layerDims));
glGenTextures(2, context->tex);
glBindTexture(GL_TEXTURE_2D, context->tex[0]);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
#ifndef _WIN32
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#endif
_initTex();
glBindTexture(GL_TEXTURE_2D, context->tex[1]);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
#ifndef _WIN32
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#endif
_initTex();
context->activeTex = 0;
glGenTextures(VIDEO_LAYER_MAX, context->tex);
int i;
for (i = 0; i < VIDEO_LAYER_MAX; ++i) {
glBindTexture(GL_TEXTURE_2D, context->layers[i]);
_initTex();
}
}
static void mGLContextSetDimensions(struct VideoBackend* v, unsigned width, unsigned height) {
static inline void _setTexDims(const struct Rectangle* dims) {
#ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(dims->width), toPow2(dims->height), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(dims->width), toPow2(dims->height), 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0);
#endif
#elif defined(__BIG_ENDIAN__)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(dims->width), toPow2(dims->height), 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(dims->width), toPow2(dims->height), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
#endif
}
static void mGLContextSetLayerDimensions(struct VideoBackend* v, enum VideoLayer layer, const struct Rectangle* dims) {
struct mGLContext* context = (struct mGLContext*) v;
if (width == v->width && height == v->height) {
if (layer >= VIDEO_LAYER_MAX) {
return;
}
v->width = width;
v->height = height;
context->layerDims[layer].x = dims->x;
context->layerDims[layer].y = dims->y;
if (dims->width == context->layerDims[layer].width && dims->height == context->layerDims[layer].height) {
return;
}
context->layerDims[layer].width = dims->width;
context->layerDims[layer].height = dims->height;
glBindTexture(GL_TEXTURE_2D, context->tex[0]);
#ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0);
#endif
#elif defined(__BIG_ENDIAN__)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
#endif
if (layer == VIDEO_LAYER_IMAGE) {
glBindTexture(GL_TEXTURE_2D, context->tex[0]);
_setTexDims(dims);
glBindTexture(GL_TEXTURE_2D, context->tex[1]);
_setTexDims(dims);
} else {
glBindTexture(GL_TEXTURE_2D, context->layers[layer]);
_setTexDims(dims);
}
}
glBindTexture(GL_TEXTURE_2D, context->tex[1]);
#ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0);
#endif
#elif defined(__BIG_ENDIAN__)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, toPow2(width), toPow2(height), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
#endif
static void mGLContextLayerDimensions(const struct VideoBackend* v, enum VideoLayer layer, struct Rectangle* dims) {
struct mGLContext* context = (struct mGLContext*) v;
if (layer >= VIDEO_LAYER_MAX) {
return;
}
memcpy(dims, &context->layerDims[layer], sizeof(*dims));
}
static void mGLContextDeinit(struct VideoBackend* v) {
struct mGLContext* context = (struct mGLContext*) v;
glDeleteTextures(2, context->tex);
glDeleteTextures(VIDEO_LAYER_MAX, context->layers);
}
static void mGLContextResized(struct VideoBackend* v, unsigned w, unsigned h) {
struct mGLContext* context = (struct mGLContext*) v;
unsigned drawW = w;
unsigned drawH = h;
if (v->lockAspectRatio) {
lockAspectRatioUInt(v->width, v->height, &drawW, &drawH);
lockAspectRatioUInt(context->layerDims[VIDEO_LAYER_IMAGE].width, context->layerDims[VIDEO_LAYER_IMAGE].height, &drawW, &drawH);
}
if (v->lockIntegerScaling) {
lockIntegerRatioUInt(v->width, &drawW);
lockIntegerRatioUInt(v->height, &drawH);
lockIntegerRatioUInt(context->layerDims[VIDEO_LAYER_IMAGE].width, &drawW);
lockIntegerRatioUInt(context->layerDims[VIDEO_LAYER_IMAGE].height, &drawH);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
@ -114,7 +133,7 @@ void mGLContextDrawFrame(struct VideoBackend* v) {
glTexCoordPointer(2, GL_INT, 0, _glTexCoords);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, v->width, v->height, 0, 0, 1);
glOrtho(0, context->layerDims[VIDEO_LAYER_IMAGE].width, context->layerDims[VIDEO_LAYER_IMAGE].height, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if (v->interframeBlending) {
@ -143,32 +162,38 @@ void mGLContextDrawFrame(struct VideoBackend* v) {
glDisable(GL_BLEND);
}
void mGLContextPostFrame(struct VideoBackend* v, const void* frame) {
void mGLContextPostFrame(struct VideoBackend* v, enum VideoLayer layer, const void* frame) {
struct mGLContext* context = (struct mGLContext*) v;
context->activeTex ^= 1;
glBindTexture(GL_TEXTURE_2D, context->tex[context->activeTex]);
if (layer >= VIDEO_LAYER_MAX) {
return;
}
if (layer == VIDEO_LAYER_IMAGE) {
context->activeTex ^= 1;
glBindTexture(GL_TEXTURE_2D, context->tex[context->activeTex]);
} else {
glBindTexture(GL_TEXTURE_2D, context->layers[layer]);
}
#ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, v->width, v->height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, context->layerDims[layer].width, context->layerDims[layer].height, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame);
#else
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, v->width, v->height, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, context->layerDims[layer].width, context->layerDims[layer].height, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame);
#endif
#elif defined(__BIG_ENDIAN__)
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, v->width, v->height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, frame);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, context->layerDims[layer].width, context->layerDims[layer].height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, frame);
#else
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, v->width, v->height, GL_RGBA, GL_UNSIGNED_BYTE, frame);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, context->layerDims[layer].width, context->layerDims[layer].height, GL_RGBA, GL_UNSIGNED_BYTE, frame);
#endif
}
void mGLContextCreate(struct mGLContext* context) {
context->d.init = mGLContextInit;
context->d.deinit = mGLContextDeinit;
context->d.setDimensions = mGLContextSetDimensions;
context->d.resized = mGLContextResized;
context->d.swap = 0;
context->d.setLayerDimensions = mGLContextSetLayerDimensions;
context->d.layerDimensions = mGLContextLayerDimensions;
context->d.contextResized = mGLContextResized;
context->d.swap = NULL;
context->d.clear = mGLContextClear;
context->d.postFrame = mGLContextPostFrame;
context->d.setImage = mGLContextPostFrame;
context->d.drawFrame = mGLContextDrawFrame;
context->d.setMessage = 0;
context->d.clearMessage = 0;
}

View File

@ -26,8 +26,10 @@ CXX_GUARD_START
struct mGLContext {
struct VideoBackend d;
GLuint tex[2];
int activeTex;
GLuint tex[2];
GLuint layers[VIDEO_LAYER_MAX];
struct Rectangle layerDims[VIDEO_LAYER_MAX];
};
void mGLContextCreate(struct mGLContext*);

View File

@ -101,12 +101,15 @@ static const GLfloat _vertices[] = {
static void mGLES2ContextInit(struct VideoBackend* v, WHandle handle) {
UNUSED(handle);
struct mGLES2Context* context = (struct mGLES2Context*) v;
v->width = 1;
v->height = 1;
glGenTextures(1, &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_T, GL_CLAMP_TO_EDGE);
memset(context->layerDims, 0, sizeof(context->layerDims));
glGenTextures(VIDEO_LAYER_MAX, context->tex);
int i;
for (i = 0; i < VIDEO_LAYER_MAX; ++i) {
glBindTexture(GL_TEXTURE_2D, context->tex[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
glGenBuffers(1, &context->vbo);
glBindBuffer(GL_ARRAY_BUFFER, context->vbo);
@ -177,40 +180,55 @@ static void mGLES2ContextInit(struct VideoBackend* v, WHandle handle) {
context->finalShader.tex = 0;
}
static void mGLES2ContextSetDimensions(struct VideoBackend* v, unsigned width, unsigned height) {
static void mGLES2ContextSetLayerDimensions(struct VideoBackend* v, enum VideoLayer layer, const struct Rectangle* dims) {
struct mGLES2Context* context = (struct mGLES2Context*) v;
if (width == v->width && height == v->height) {
if (layer >= VIDEO_LAYER_MAX) {
return;
}
v->width = width;
v->height = height;
context->layerDims[layer].x = dims->x;
context->layerDims[layer].y = dims->y;
if (dims->width == context->layerDims[layer].width && dims->height == context->layerDims[layer].height) {
return;
}
context->layerDims[layer].width = dims->width;
context->layerDims[layer].height = dims->height;
glBindTexture(GL_TEXTURE_2D, context->tex);
glBindTexture(GL_TEXTURE_2D, context->tex[layer]);
#ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dims->width, dims->height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 0);
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dims->width, dims->height, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 0);
#endif
#elif defined(__BIG_ENDIAN__)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dims->width, dims->height, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, dims->width, dims->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
#endif
size_t n;
for (n = 0; n < context->nShaders; ++n) {
if (context->shaders[n].width < 0 || context->shaders[n].height < 0) {
context->shaders[n].dirty = true;
if (layer == VIDEO_LAYER_BACKGROUND) {
size_t n;
for (n = 0; n < context->nShaders; ++n) {
if (context->shaders[n].width < 0 || context->shaders[n].height < 0) {
context->shaders[n].dirty = true;
}
}
context->initialShader.dirty = true;
context->interframeShader.dirty = true;
}
context->initialShader.dirty = true;
context->interframeShader.dirty = true;
}
static void mGLES2ContextLayerDimensions(const struct VideoBackend* v, enum VideoLayer layer, struct Rectangle* dims) {
struct mGLES2Context* context = (struct mGLES2Context*) v;
if (layer >= VIDEO_LAYER_MAX) {
return;
}
memcpy(dims, &context->layerDims[layer], sizeof(*dims));
}
static void mGLES2ContextDeinit(struct VideoBackend* v) {
struct mGLES2Context* context = (struct mGLES2Context*) v;
glDeleteTextures(1, &context->tex);
glDeleteTextures(VIDEO_LAYER_MAX, context->tex);
glDeleteBuffers(1, &context->vbo);
mGLES2ShaderDeinit(&context->initialShader);
mGLES2ShaderDeinit(&context->finalShader);
@ -223,11 +241,11 @@ static void mGLES2ContextResized(struct VideoBackend* v, unsigned w, unsigned h)
unsigned drawW = w;
unsigned drawH = h;
if (v->lockAspectRatio) {
lockAspectRatioUInt(v->width, v->height, &drawW, &drawH);
lockAspectRatioUInt(context->layerDims[VIDEO_LAYER_IMAGE].width, context->layerDims[VIDEO_LAYER_IMAGE].height, &drawW, &drawH);
}
if (v->lockIntegerScaling) {
lockIntegerRatioUInt(v->width, &drawW);
lockIntegerRatioUInt(v->height, &drawH);
lockIntegerRatioUInt(context->layerDims[VIDEO_LAYER_IMAGE].width, &drawW);
lockIntegerRatioUInt(context->layerDims[VIDEO_LAYER_IMAGE].height, &drawH);
}
size_t n;
for (n = 0; n < context->nShaders; ++n) {
@ -260,19 +278,19 @@ void _drawShader(struct mGLES2Context* context, struct mGLES2Shader* shader) {
drawW = viewport[2];
padW = viewport[0];
} else if (shader->width < 0) {
drawW = context->d.width * -shader->width;
drawW = context->layerDims[VIDEO_LAYER_IMAGE].width * -shader->width;
}
if (!drawH) {
drawH = viewport[3];
padH = viewport[1];
} else if (shader->height < 0) {
drawH = context->d.height * -shader->height;
drawH = context->layerDims[VIDEO_LAYER_IMAGE].height * -shader->height;
}
if (shader->integerScaling) {
padW = 0;
padH = 0;
drawW -= drawW % context->d.width;
drawH -= drawH % context->d.height;
drawW -= drawW % context->layerDims[VIDEO_LAYER_IMAGE].width;
drawH -= drawH % context->layerDims[VIDEO_LAYER_IMAGE].height;
}
if (shader->dirty) {
@ -301,7 +319,7 @@ void _drawShader(struct mGLES2Context* context, struct mGLES2Shader* shader) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, shader->filter ? GL_LINEAR : GL_NEAREST);
glUseProgram(shader->program);
glUniform1i(shader->texLocation, 0);
glUniform2f(shader->texSizeLocation, context->d.width, context->d.height);
glUniform2f(shader->texSizeLocation, context->layerDims[VIDEO_LAYER_IMAGE].width, context->layerDims[VIDEO_LAYER_IMAGE].height);
glUniform2f(shader->outputSizeLocation, drawW, drawH);
#ifdef BUILD_GLES3
if (shader->vao != (GLuint) -1) {
@ -371,7 +389,7 @@ void _drawShader(struct mGLES2Context* context, struct mGLES2Shader* shader) {
void mGLES2ContextDrawFrame(struct VideoBackend* v) {
struct mGLES2Context* context = (struct mGLES2Context*) v;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, context->tex);
glBindTexture(GL_TEXTURE_2D, context->tex[VIDEO_LAYER_IMAGE]);
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
@ -392,7 +410,7 @@ void mGLES2ContextDrawFrame(struct VideoBackend* v) {
_drawShader(context, &context->finalShader);
if (v->interframeBlending) {
context->interframeShader.blend = false;
glBindTexture(GL_TEXTURE_2D, context->tex);
glBindTexture(GL_TEXTURE_2D, context->tex[VIDEO_LAYER_IMAGE]);
_drawShader(context, &context->initialShader);
glViewport(0, 0, viewport[2], viewport[3]);
_drawShader(context, &context->interframeShader);
@ -406,33 +424,35 @@ void mGLES2ContextDrawFrame(struct VideoBackend* v) {
#endif
}
void mGLES2ContextPostFrame(struct VideoBackend* v, const void* frame) {
void mGLES2ContextPostFrame(struct VideoBackend* v, enum VideoLayer layer, const void* frame) {
struct mGLES2Context* context = (struct mGLES2Context*) v;
glBindTexture(GL_TEXTURE_2D, context->tex);
if (layer >= VIDEO_LAYER_MAX) {
return;
}
glBindTexture(GL_TEXTURE_2D, context->tex[layer]);
#ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, v->width, v->height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, context->layerDims[layer].width, context->layerDims[layer].height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, frame);
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, v->width, v->height, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, context->layerDims[layer].width, context->layerDims[layer].height, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame);
#endif
#elif defined(__BIG_ENDIAN__)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, v->width, v->height, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, frame);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, context->layerDims[layer].width, context->layerDims[layer].height, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, frame);
#else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, v->width, v->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, context->layerDims[layer].width, context->layerDims[layer].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame);
#endif
}
void mGLES2ContextCreate(struct mGLES2Context* context) {
context->d.init = mGLES2ContextInit;
context->d.deinit = mGLES2ContextDeinit;
context->d.setDimensions = mGLES2ContextSetDimensions;
context->d.resized = mGLES2ContextResized;
context->d.swap = 0;
context->d.setLayerDimensions = mGLES2ContextSetLayerDimensions;
context->d.layerDimensions = mGLES2ContextLayerDimensions;
context->d.contextResized = mGLES2ContextResized;
context->d.swap = NULL;
context->d.clear = mGLES2ContextClear;
context->d.postFrame = mGLES2ContextPostFrame;
context->d.setImage = mGLES2ContextPostFrame;
context->d.drawFrame = mGLES2ContextDrawFrame;
context->d.setMessage = 0;
context->d.clearMessage = 0;
context->shaders = 0;
context->nShaders = 0;
}

View File

@ -79,9 +79,11 @@ struct mGLES2Shader {
struct mGLES2Context {
struct VideoBackend d;
GLuint tex;
GLuint tex[VIDEO_LAYER_MAX];
GLuint vbo;
struct Rectangle layerDims[VIDEO_LAYER_MAX];
struct mGLES2Shader initialShader;
struct mGLES2Shader finalShader;
struct mGLES2Shader interframeShader;

View File

@ -624,7 +624,9 @@ void PainterGL::resizeContext() {
return;
}
dequeueAll(false);
m_backend->setDimensions(m_backend, size.width(), size.height());
Rectangle dims = {0, 0, size.width(), size.height()};
m_backend->setLayerDimensions(m_backend, VIDEO_LAYER_IMAGE, &dims);
}
void PainterGL::setMessagePainter(MessagePainter* messagePainter) {
@ -797,9 +799,9 @@ void PainterGL::unpause() {
void PainterGL::performDraw() {
float r = m_window->devicePixelRatio();
m_backend->resized(m_backend, m_size.width() * r, m_size.height() * r);
m_backend->contextResized(m_backend, m_size.width() * r, m_size.height() * r);
if (m_buffer) {
m_backend->postFrame(m_backend, m_buffer);
m_backend->setImage(m_backend, VIDEO_LAYER_IMAGE, m_buffer);
}
m_backend->drawFrame(m_backend);
if (m_showOSD && m_messagePainter && !glContextHasBug(OpenGLBug::IG4ICD_CRASH)) {
@ -855,7 +857,7 @@ void PainterGL::dequeue() {
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
if (supportsShaders()) {
mGLES2Context* gl2Backend = reinterpret_cast<mGLES2Context*>(m_backend);
gl2Backend->tex = m_bridgeTexOut;
gl2Backend->tex[VIDEO_LAYER_IMAGE] = m_bridgeTexOut;
}
#endif
}
@ -953,7 +955,7 @@ int PainterGL::glTex() {
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
if (supportsShaders()) {
mGLES2Context* gl2Backend = reinterpret_cast<mGLES2Context*>(m_backend);
return gl2Backend->tex;
return gl2Backend->tex[VIDEO_LAYER_IMAGE];
}
#endif
#ifdef BUILD_GL

View File

@ -8,7 +8,7 @@
#include <mgba/core/version.h>
void mSDLGLDoViewport(int w, int h, struct VideoBackend* v) {
v->resized(v, w, h);
v->contextResized(v, w, h);
v->clear(v);
v->swap(v);
v->clear(v);

View File

@ -37,7 +37,13 @@ bool mSDLGLInit(struct mSDLRenderer* renderer) {
renderer->gl.d.filter = renderer->filter;
renderer->gl.d.swap = mSDLGLCommonSwap;
renderer->gl.d.init(&renderer->gl.d, 0);
renderer->gl.d.setDimensions(&renderer->gl.d, renderer->width, renderer->height);
struct Rectangle dims = {
.x = 0,
.y = 0,
.width = renderer->width,
.height = renderer->height
};
renderer->gl.d.setLayerDimensions(&renderer->gl.d, VIDEO_LAYER_IMAGE, &dims);
mSDLGLDoViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl.d);
return true;
@ -65,13 +71,17 @@ void mSDLGLRunloop(struct mSDLRenderer* renderer, void* user) {
}
}
renderer->core->currentVideoSize(renderer->core, &renderer->width, &renderer->height);
if (renderer->width != v->width || renderer->height != v->height) {
struct Rectangle dims;
v->layerDimensions(v, VIDEO_LAYER_IMAGE, &dims);
if (renderer->width != dims.width || renderer->height != dims.height) {
renderer->core->setVideoBuffer(renderer->core, renderer->outputBuffer, renderer->width);
v->setDimensions(v, renderer->width, renderer->height);
dims.width = renderer->width;
dims.height = renderer->height;
v->setLayerDimensions(v, VIDEO_LAYER_IMAGE, &dims);
}
if (mCoreSyncWaitFrameStart(&context->impl->sync)) {
v->postFrame(v, renderer->outputBuffer);
v->setImage(v, VIDEO_LAYER_IMAGE, renderer->outputBuffer);
}
mCoreSyncWaitFrameEnd(&context->impl->sync);
v->drawFrame(v);

View File

@ -50,7 +50,14 @@ bool mSDLGLES2Init(struct mSDLRenderer* renderer) {
renderer->gl2.d.swap = mSDLGLCommonSwap;
#endif
renderer->gl2.d.init(&renderer->gl2.d, 0);
renderer->gl2.d.setDimensions(&renderer->gl2.d, renderer->width, renderer->height);
struct Rectangle dims = {
.x = 0,
.y = 0,
.width = renderer->width,
.height = renderer->height
};
renderer->gl2.d.setLayerDimensions(&renderer->gl2.d, VIDEO_LAYER_IMAGE, &dims);
mSDLGLDoViewport(renderer->viewportWidth, renderer->viewportHeight, &renderer->gl2.d);
return true;
@ -79,7 +86,7 @@ void mSDLGLES2Runloop(struct mSDLRenderer* renderer, void* user) {
}
if (mCoreSyncWaitFrameStart(&context->impl->sync)) {
v->postFrame(v, renderer->outputBuffer);
v->setImage(v, VIDEO_LAYER_IMAGE, renderer->outputBuffer);
}
mCoreSyncWaitFrameEnd(&context->impl->sync);
v->drawFrame(v);

View File

@ -10,6 +10,8 @@
CXX_GUARD_START
#include <mgba-util/geometry.h>
#ifdef _WIN32
#include <windows.h>
typedef HWND WHandle;
@ -17,26 +19,31 @@ typedef HWND WHandle;
typedef void* WHandle;
#endif
enum VideoLayer {
VIDEO_LAYER_BACKGROUND = 0,
VIDEO_LAYER_IMAGE,
VIDEO_LAYER_OVERLAY,
VIDEO_LAYER_MAX
};
struct VideoBackend {
void (*init)(struct VideoBackend*, WHandle handle);
void (*deinit)(struct VideoBackend*);
void (*setDimensions)(struct VideoBackend*, unsigned width, unsigned height);
void (*setLayerDimensions)(struct VideoBackend*, enum VideoLayer, const struct Rectangle*);
void (*layerDimensions)(const struct VideoBackend*, enum VideoLayer, struct Rectangle*);
void (*swap)(struct VideoBackend*);
void (*clear)(struct VideoBackend*);
void (*resized)(struct VideoBackend*, unsigned w, unsigned h);
void (*postFrame)(struct VideoBackend*, const void* frame);
void (*contextResized)(struct VideoBackend*, unsigned w, unsigned h);
void (*setImage)(struct VideoBackend*, enum VideoLayer, const void* frame);
void (*drawFrame)(struct VideoBackend*);
void (*setMessage)(struct VideoBackend*, const char* message);
void (*clearMessage)(struct VideoBackend*);
void* user;
unsigned width;
unsigned height;
bool filter;
bool lockAspectRatio;
bool lockIntegerScaling;
bool interframeBlending;
enum VideoLayer cropToLayer;
};
struct VideoShader {