mirror of https://github.com/mgba-emu/mgba.git
OpenGL: Add basic border rendering to GL 1.x driver
This commit is contained in:
parent
efbc4a49ce
commit
09a53abe99
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue