mirror of https://github.com/mgba-emu/mgba.git
Video: Start revising VideoBackend API
This commit is contained in:
parent
dd531637c2
commit
d6c3b012d1
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue