OpenGL: Add basic border rendering to GL 1.x driver

This commit is contained in:
Vicki Pfau 2023-02-20 23:12:30 -08:00
parent efbc4a49ce
commit 09a53abe99
7 changed files with 152 additions and 39 deletions

View File

@ -738,6 +738,11 @@ elseif(BUILD_GLES2)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libgles2")
endif()
if(USE_EPOXY OR BUILD_GL OR BUILD_GLES2)
# This file should probably go somewhere else
list(APPEND FEATURE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/video-backend.c)
endif()
if(WIN32 AND NOT (LIBMGBA_ONLY OR SKIP_LIBRARY OR USE_EPOXY))
message(FATAL_ERROR "Windows requires epoxy module!")
endif()

View File

@ -9,9 +9,9 @@
static const GLint _glVertices[] = {
0, 0,
256, 0,
256, 256,
0, 256
1, 0,
1, 1,
0, 1
};
static const GLint _glTexCoords[] = {
@ -101,15 +101,19 @@ static void mGLContextDeinit(struct VideoBackend* v) {
}
static void mGLContextResized(struct VideoBackend* v, unsigned w, unsigned h) {
struct mGLContext* context = (struct mGLContext*) v;
unsigned drawW = w;
unsigned drawH = h;
unsigned maxW;
unsigned maxH;
VideoBackendGetFrameSize(v, &maxW, &maxH);
if (v->lockAspectRatio) {
lockAspectRatioUInt(context->layerDims[VIDEO_LAYER_IMAGE].width, context->layerDims[VIDEO_LAYER_IMAGE].height, &drawW, &drawH);
lockAspectRatioUInt(maxW, maxH, &drawW, &drawH);
}
if (v->lockIntegerScaling) {
lockIntegerRatioUInt(context->layerDims[VIDEO_LAYER_IMAGE].width, &drawW);
lockIntegerRatioUInt(context->layerDims[VIDEO_LAYER_IMAGE].height, &drawH);
lockIntegerRatioUInt(maxW, &drawW);
lockIntegerRatioUInt(maxH, &drawH);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
@ -124,33 +128,7 @@ static void mGLContextClear(struct VideoBackend* v) {
glClear(GL_COLOR_BUFFER_BIT);
}
void mGLContextDrawFrame(struct VideoBackend* v) {
struct mGLContext* context = (struct mGLContext*) v;
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_INT, 0, _glVertices);
glTexCoordPointer(2, GL_INT, 0, _glTexCoords);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, context->layerDims[VIDEO_LAYER_IMAGE].width, context->layerDims[VIDEO_LAYER_IMAGE].height, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if (v->interframeBlending) {
glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
glBlendColor(1, 1, 1, 0.5);
glBindTexture(GL_TEXTURE_2D, context->tex[context->activeTex ^ 1]);
if (v->filter) {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
} else {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glEnable(GL_BLEND);
}
glBindTexture(GL_TEXTURE_2D, context->tex[context->activeTex]);
static void _setFilter(struct VideoBackend* v) {
if (v->filter) {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@ -158,6 +136,61 @@ void mGLContextDrawFrame(struct VideoBackend* v) {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
}
static void _setFrame(struct Rectangle* dims, int frameW, int frameH) {
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
glScissor(viewport[0] + dims->x * viewport[2] / frameW,
viewport[1] + dims->y * viewport[3] / frameH,
dims->width * viewport[2] / frameW,
dims->height * viewport[3] / frameH);
glTranslatef(dims->x, dims->y, 0);
glScalef(toPow2(dims->width), toPow2(dims->height), 1);
}
void mGLContextDrawFrame(struct VideoBackend* v) {
struct mGLContext* context = (struct mGLContext*) v;
glEnable(GL_TEXTURE_2D);
glEnable(GL_SCISSOR_TEST);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_INT, 0, _glVertices);
glTexCoordPointer(2, GL_INT, 0, _glTexCoords);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
unsigned frameW, frameH;
VideoBackendGetFrameSize(v, &frameW, &frameH);
glOrtho(0, frameW, frameH, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
int layer;
for (layer = 0; layer < VIDEO_LAYER_IMAGE; ++layer) {
if (context->layerDims[layer].width < 1 || context->layerDims[layer].height < 1) {
continue;
}
glDisable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, context->layers[layer]);
_setFilter(v);
glPushMatrix();
_setFrame(&context->layerDims[layer], frameW, frameH);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glPopMatrix();
}
_setFrame(&context->layerDims[VIDEO_LAYER_IMAGE], frameW, frameH);
if (v->interframeBlending) {
glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
glBlendColor(1, 1, 1, 0.5);
glBindTexture(GL_TEXTURE_2D, context->tex[context->activeTex ^ 1]);
_setFilter(v);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glEnable(GL_BLEND);
}
glBindTexture(GL_TEXTURE_2D, context->tex[context->activeTex]);
_setFilter(v);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisable(GL_BLEND);
}

View File

@ -240,12 +240,17 @@ static void mGLES2ContextResized(struct VideoBackend* v, unsigned w, unsigned h)
struct mGLES2Context* context = (struct mGLES2Context*) v;
unsigned drawW = w;
unsigned drawH = h;
unsigned maxW;
unsigned maxH;
VideoBackendGetFrameSize(v, &maxW, &maxH);
if (v->lockAspectRatio) {
lockAspectRatioUInt(context->layerDims[VIDEO_LAYER_IMAGE].width, context->layerDims[VIDEO_LAYER_IMAGE].height, &drawW, &drawH);
lockAspectRatioUInt(maxW, maxH, &drawW, &drawH);
}
if (v->lockIntegerScaling) {
lockIntegerRatioUInt(context->layerDims[VIDEO_LAYER_IMAGE].width, &drawW);
lockIntegerRatioUInt(context->layerDims[VIDEO_LAYER_IMAGE].height, &drawH);
lockIntegerRatioUInt(maxW, &drawW);
lockIntegerRatioUInt(maxH, &drawH);
}
size_t n;
for (n = 0; n < context->nShaders; ++n) {

View File

@ -397,7 +397,7 @@ void DisplayGL::setVideoScale(int scale) {
}
void DisplayGL::setBackgroundImage(const QImage& image) {
// TODO
QMetaObject::invokeMethod(m_painter.get(), "setBackgroundImage", Q_ARG(const QImage&, image));
}
void DisplayGL::resizeEvent(QResizeEvent* event) {
@ -631,12 +631,29 @@ void PainterGL::resizeContext() {
Rectangle dims = {0, 0, size.width(), size.height()};
m_backend->setLayerDimensions(m_backend, VIDEO_LAYER_IMAGE, &dims);
recenterLayers();
}
void PainterGL::setMessagePainter(MessagePainter* messagePainter) {
m_messagePainter = messagePainter;
}
void PainterGL::recenterLayers() {
const static std::initializer_list<VideoLayer> centeredLayers{VIDEO_LAYER_BACKGROUND, VIDEO_LAYER_IMAGE};
Rectangle frame = {0};
for (VideoLayer l : centeredLayers) {
Rectangle dims;
m_backend->layerDimensions(m_backend, l, &dims);
RectangleUnion(&frame, &dims);
}
for (VideoLayer l : centeredLayers) {
Rectangle dims;
m_backend->layerDimensions(m_backend, l, &dims);
RectangleCenter(&frame, &dims);
m_backend->setLayerDimensions(m_backend, l, &dims);
}
}
void PainterGL::resize(const QSize& size) {
qreal r = m_window->devicePixelRatio();
m_size = size;
@ -995,6 +1012,32 @@ void PainterGL::updateFramebufferHandle() {
m_context->setFramebufferHandle(m_bridgeTexIn);
}
void PainterGL::setBackgroundImage(const QImage& image) {
if (!m_started) {
makeCurrent();
}
Rectangle dims = {0, 0, 0, 0};
if (!image.isNull()) {
dims.width = static_cast<unsigned>(image.width());
dims.height = static_cast<unsigned>(image.height());
}
m_backend->setLayerDimensions(m_backend, VIDEO_LAYER_BACKGROUND, &dims);
recenterLayers();
if (!image.isNull()) {
m_background = image.convertToFormat(QImage::Format_RGB32);
m_background = m_background.rgbSwapped();
m_backend->setImage(m_backend, VIDEO_LAYER_BACKGROUND, m_background.constBits());
} else {
m_background = QImage();
}
if (!m_started) {
m_gl->doneCurrent();
}
}
void PainterGL::swapTex() {
if (!m_started) {
return;

View File

@ -109,7 +109,6 @@ public slots:
void setVideoScale(int scale) override;
void setBackgroundImage(const QImage&) override;
protected:
virtual void paintEvent(QPaintEvent*) override { forceDraw(); }
virtual void resizeEvent(QResizeEvent*) override;
@ -178,6 +177,7 @@ public slots:
void filter(bool filter);
void resizeContext();
void updateFramebufferHandle();
void setBackgroundImage(const QImage&);
void setShaders(struct VDir*);
void clearShaders();
@ -196,6 +196,7 @@ private:
void performDraw();
void dequeue();
void dequeueAll(bool keep = false);
void recenterLayers();
std::array<std::array<uint32_t, 0x100000>, 3> m_buffers;
QList<uint32_t*> m_free;
@ -214,6 +215,7 @@ private:
QWindow* m_window;
QSurface* m_surface;
QSurfaceFormat m_format;
QImage m_background;
std::unique_ptr<QOpenGLPaintDevice> m_paintDev;
std::unique_ptr<QOpenGLContext> m_gl;
int m_finalTexIdx = 0;

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/. */
#include "video-backend.h"
void VideoBackendGetFrameSize(const struct VideoBackend* v, unsigned* width, unsigned* height) {
*width = 0;
*height = 0;
int i;
for (i = 0; i < VIDEO_LAYER_MAX; ++i) {
struct Rectangle dims;
v->layerDimensions(v, i, &dims);
if (dims.x + dims.width > *width) {
*width = dims.x + dims.width;
}
if (dims.y + dims.height > *height) {
*height = dims.y + dims.height;
}
}
}

View File

@ -21,6 +21,7 @@ typedef void* WHandle;
enum VideoLayer {
VIDEO_LAYER_BACKGROUND = 0,
VIDEO_LAYER_BEZEL,
VIDEO_LAYER_IMAGE,
VIDEO_LAYER_OVERLAY,
VIDEO_LAYER_MAX
@ -55,6 +56,8 @@ struct VideoShader {
size_t nPasses;
};
void VideoBackendGetFrameSize(const struct VideoBackend*, unsigned* width, unsigned* height);
CXX_GUARD_END
#endif