mirror of
https://github.com/libretro/mgba.git
synced 2024-11-26 17:50:26 +00:00
Core: Improve OpenGL integration, update Qt to use improvements
This commit is contained in:
parent
49a9da3e5c
commit
8450417086
@ -57,7 +57,7 @@ if(NOT LIBMGBA_ONLY)
|
||||
set(BUILD_SHARED ON CACHE BOOL "Build a shared library")
|
||||
set(SKIP_LIBRARY OFF CACHE BOOL "Skip building the library (useful for only building libretro or OpenEmu cores)")
|
||||
set(BUILD_GL ON CACHE BOOL "Build with OpenGL")
|
||||
set(BUILD_GLES2 OFF CACHE BOOL "Build with OpenGL|ES 2")
|
||||
set(BUILD_GLES2 ON CACHE BOOL "Build with OpenGL|ES 2")
|
||||
set(BUILD_GLES3 OFF CACHE BOOL "Build with OpenGL|ES 3")
|
||||
set(USE_EPOXY ON CACHE STRING "Build with libepoxy")
|
||||
set(DISABLE_DEPS OFF CACHE BOOL "Build without dependencies")
|
||||
@ -447,7 +447,7 @@ set(FEATURE_DEFINES)
|
||||
set(FEATURE_FLAGS)
|
||||
set(FEATURES)
|
||||
set(ENABLES)
|
||||
if(CMAKE_SYSTEM_NAME MATCHES .*BSD)
|
||||
if(CMAKE_SYSTEM_NAME MATCHES ".*BSD|DragonFly")
|
||||
set(LIBEDIT_LIBRARIES -ledit)
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL OpenBSD)
|
||||
list(APPEND LIBEDIT_LIBRARIES -ltermcap)
|
||||
@ -462,9 +462,9 @@ if(BUILD_GL)
|
||||
endif()
|
||||
endif()
|
||||
if(NOT BUILD_GL)
|
||||
set(OPENGLE_LIBRARY "" CACHE PATH "" FORCE)
|
||||
set(OPENGL_LIBRARY "" CACHE PATH "" FORCE)
|
||||
endif()
|
||||
if(BUILD_GLES2 AND NOT BUILD_RASPI)
|
||||
if(BUILD_GLES2 AND NOT BUILD_RASPI AND NOT CMAKE_SYSTEM_NAME MATCHES "^(Windows|Darwin|Linux|.*BSD|DragonFly|Haiku)$")
|
||||
find_path(OPENGLES2_INCLUDE_DIR NAMES GLES2/gl2.h)
|
||||
find_library(OPENGLES2_LIBRARY NAMES GLESv2 GLESv2_CM)
|
||||
if(NOT OPENGLES2_INCLUDE_DIR OR NOT OPENGLES2_LIBRARY)
|
||||
@ -474,6 +474,16 @@ endif()
|
||||
if(NOT BUILD_GLES2)
|
||||
set(OPENGLES2_LIBRARY "" CACHE PATH "" FORCE)
|
||||
endif()
|
||||
if(BUILD_GL)
|
||||
list(APPEND OS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/opengl/gl.c)
|
||||
list(APPEND OS_LIB ${OPENGL_LIBRARY})
|
||||
include_directories(${OPENGL_INCLUDE_DIR})
|
||||
endif()
|
||||
if(BUILD_GLES2)
|
||||
list(APPEND OS_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/platform/opengl/gles2.c)
|
||||
list(APPEND OS_LIB ${OPENGLES2_LIBRARY})
|
||||
include_directories(${OPENGLES2_INCLUDE_DIR})
|
||||
endif()
|
||||
if(BUILD_GLES3)
|
||||
find_path(OPENGLES3_INCLUDE_DIR NAMES GLES3/gl3.h)
|
||||
find_library(OPENGLES3_LIBRARY NAMES GLESv3 GLESv2)
|
||||
@ -733,6 +743,10 @@ if(USE_EPOXY)
|
||||
link_directories(${EPOXY_LIBRARY_DIRS})
|
||||
set(OPENGLES2_LIBRARY ${EPOXY_LIBRARIES})
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libepoxy0")
|
||||
elseif(BUILD_GL)
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libgl1|libgles2")
|
||||
elseif(BUILD_GLES2)
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS},libgles2")
|
||||
endif()
|
||||
|
||||
if(USE_SQLITE3)
|
||||
|
@ -64,6 +64,7 @@ struct mCore {
|
||||
void (*deinit)(struct mCore*);
|
||||
|
||||
enum mPlatform (*platform)(const struct mCore*);
|
||||
bool (*supportsFeature)(const struct mCore*, enum mCoreFeature);
|
||||
|
||||
void (*setSync)(struct mCore*, struct mCoreSync*);
|
||||
void (*loadConfig)(struct mCore*, const struct mCoreConfig*);
|
||||
|
@ -80,6 +80,10 @@ enum mColorFormat {
|
||||
mCOLOR_ANY = -1
|
||||
};
|
||||
|
||||
enum mCoreFeature {
|
||||
mCORE_FEATURE_OPENGL = 1,
|
||||
};
|
||||
|
||||
struct mCoreCallbacks {
|
||||
void* context;
|
||||
void (*videoFrameStarted)(void* context);
|
||||
|
@ -16,6 +16,8 @@ CXX_GUARD_START
|
||||
#include <mgba/internal/gba/renderers/common.h>
|
||||
#include <mgba/internal/gba/video.h>
|
||||
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
|
||||
#ifdef USE_EPOXY
|
||||
#include <epoxy/gl.h>
|
||||
#elif defined(BUILD_GL)
|
||||
@ -27,7 +29,7 @@ CXX_GUARD_START
|
||||
#include <GL/glext.h>
|
||||
#endif
|
||||
#else
|
||||
#include <GLES2/gl2.h>
|
||||
#include <GLES3/gl3.h>
|
||||
#endif
|
||||
|
||||
struct GBAVideoGLAffine {
|
||||
@ -137,6 +139,9 @@ struct GBAVideoGLRenderer {
|
||||
|
||||
GLuint outputTex;
|
||||
|
||||
#ifdef BUILD_GLES3
|
||||
uint16_t shadowPalette[512];
|
||||
#endif
|
||||
GLuint paletteTex;
|
||||
bool paletteDirty;
|
||||
|
||||
@ -182,6 +187,8 @@ struct GBAVideoGLRenderer {
|
||||
|
||||
void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer);
|
||||
|
||||
#endif
|
||||
|
||||
CXX_GUARD_END
|
||||
|
||||
#endif
|
@ -138,6 +138,14 @@ static enum mPlatform _GBCorePlatform(const struct mCore* core) {
|
||||
return PLATFORM_GB;
|
||||
}
|
||||
|
||||
static bool _GBCoreSupportsFeature(const struct mCore* core, enum mCoreFeature feature) {
|
||||
UNUSED(core);
|
||||
switch (feature) {
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void _GBCoreSetSync(struct mCore* core, struct mCoreSync* sync) {
|
||||
struct GB* gb = core->board;
|
||||
gb->sync = sync;
|
||||
@ -888,6 +896,7 @@ struct mCore* GBCoreCreate(void) {
|
||||
core->init = _GBCoreInit;
|
||||
core->deinit = _GBCoreDeinit;
|
||||
core->platform = _GBCorePlatform;
|
||||
core->supportsFeature = _GBCoreSupportsFeature;
|
||||
core->setSync = _GBCoreSetSync;
|
||||
core->loadConfig = _GBCoreLoadConfig;
|
||||
core->desiredVideoDimensions = _GBCoreDesiredVideoDimensions;
|
||||
|
@ -17,7 +17,9 @@
|
||||
#ifndef DISABLE_THREADING
|
||||
#include <mgba/feature/thread-proxy.h>
|
||||
#endif
|
||||
#ifdef BUILD_GLES2
|
||||
#include <mgba/internal/gba/renderers/gl.h>
|
||||
#endif
|
||||
#include <mgba/internal/gba/renderers/proxy.h>
|
||||
#include <mgba/internal/gba/renderers/video-software.h>
|
||||
#include <mgba/internal/gba/savedata.h>
|
||||
@ -124,7 +126,9 @@ struct mVideoLogContext;
|
||||
struct GBACore {
|
||||
struct mCore d;
|
||||
struct GBAVideoSoftwareRenderer renderer;
|
||||
#ifdef BUILD_GLES2
|
||||
struct GBAVideoGLRenderer glRenderer;
|
||||
#endif
|
||||
struct GBAVideoProxyRenderer proxyRenderer;
|
||||
struct mVideoLogContext* logContext;
|
||||
struct mCoreCallbacks logCallbacks;
|
||||
@ -170,8 +174,10 @@ static bool _GBACoreInit(struct mCore* core) {
|
||||
GBAVideoSoftwareRendererCreate(&gbacore->renderer);
|
||||
gbacore->renderer.outputBuffer = NULL;
|
||||
|
||||
#ifdef BUILD_GLES2
|
||||
GBAVideoGLRendererCreate(&gbacore->glRenderer);
|
||||
gbacore->glRenderer.outputTex = -1;
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_THREADING
|
||||
mVideoThreadProxyCreate(&gbacore->threadProxy);
|
||||
@ -212,6 +218,20 @@ static enum mPlatform _GBACorePlatform(const struct mCore* core) {
|
||||
return PLATFORM_GBA;
|
||||
}
|
||||
|
||||
static bool _GBACoreSupportsFeature(const struct mCore* core, enum mCoreFeature feature) {
|
||||
UNUSED(core);
|
||||
switch (feature) {
|
||||
case mCORE_FEATURE_OPENGL:
|
||||
#ifdef BUILD_GLES2
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void _GBACoreSetSync(struct mCore* core, struct mCoreSync* sync) {
|
||||
struct GBA* gba = core->board;
|
||||
gba->sync = sync;
|
||||
@ -261,9 +281,12 @@ static void _GBACoreLoadConfig(struct mCore* core, const struct mCoreConfig* con
|
||||
}
|
||||
|
||||
static void _GBACoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) {
|
||||
#ifdef BUILD_GLES2
|
||||
struct GBACore* gbacore = (struct GBACore*) core;
|
||||
int fakeBool;
|
||||
int scale = gbacore->glRenderer.scale;
|
||||
#else
|
||||
int scale = 1;
|
||||
#endif
|
||||
|
||||
*width = GBA_VIDEO_HORIZONTAL_PIXELS * scale;
|
||||
*height = GBA_VIDEO_VERTICAL_PIXELS * scale;
|
||||
@ -277,8 +300,13 @@ static void _GBACoreSetVideoBuffer(struct mCore* core, color_t* buffer, size_t s
|
||||
}
|
||||
|
||||
static void _GBACoreSetVideoGLTex(struct mCore* core, unsigned texid) {
|
||||
#ifdef BUILD_GLES2
|
||||
struct GBACore* gbacore = (struct GBACore*) core;
|
||||
gbacore->glRenderer.outputTex = texid;
|
||||
#else
|
||||
UNUSED(core);
|
||||
UNUSED(texid);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void _GBACoreGetPixels(struct mCore* core, const void** buffer, size_t* stride) {
|
||||
@ -403,16 +431,22 @@ static void _GBACoreChecksum(const struct mCore* core, void* data, enum mCoreChe
|
||||
static void _GBACoreReset(struct mCore* core) {
|
||||
struct GBACore* gbacore = (struct GBACore*) core;
|
||||
struct GBA* gba = (struct GBA*) core->board;
|
||||
if (gbacore->renderer.outputBuffer || gbacore->glRenderer.outputTex != (unsigned) -1) {
|
||||
if (gbacore->renderer.outputBuffer
|
||||
#ifdef BUILD_GLES2
|
||||
|| gbacore->glRenderer.outputTex != (unsigned) -1
|
||||
#endif
|
||||
) {
|
||||
struct GBAVideoRenderer* renderer;
|
||||
if (gbacore->renderer.outputBuffer) {
|
||||
renderer = &gbacore->renderer.d;
|
||||
}
|
||||
int fakeBool;
|
||||
#ifdef BUILD_GLES2
|
||||
if (gbacore->glRenderer.outputTex != (unsigned) -1 && mCoreConfigGetIntValue(&core->config, "hwaccelVideo", &fakeBool) && fakeBool) {
|
||||
renderer = &gbacore->glRenderer.d;
|
||||
mCoreConfigGetIntValue(&core->config, "videoScale", &gbacore->glRenderer.scale);
|
||||
}
|
||||
#endif
|
||||
#ifndef DISABLE_THREADING
|
||||
if (mCoreConfigGetIntValue(&core->config, "threadedVideo", &fakeBool) && fakeBool) {
|
||||
if (!core->videoLogger) {
|
||||
@ -952,6 +986,7 @@ struct mCore* GBACoreCreate(void) {
|
||||
core->init = _GBACoreInit;
|
||||
core->deinit = _GBACoreDeinit;
|
||||
core->platform = _GBACorePlatform;
|
||||
core->supportsFeature = _GBACoreSupportsFeature;
|
||||
core->setSync = _GBACoreSetSync;
|
||||
core->loadConfig = _GBACoreLoadConfig;
|
||||
core->desiredVideoDimensions = _GBACoreDesiredVideoDimensions;
|
||||
|
@ -5,6 +5,8 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include <mgba/internal/gba/renderers/gl.h>
|
||||
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
|
||||
#include <mgba/core/cache-set.h>
|
||||
#include <mgba/internal/arm/macros.h>
|
||||
#include <mgba/internal/gba/io.h>
|
||||
@ -90,7 +92,7 @@ static const char* const _renderTile256 =
|
||||
" return color;\n"
|
||||
"}";
|
||||
|
||||
const static struct GBAVideoGLUniform _uniformsMode0[] = {
|
||||
static const struct GBAVideoGLUniform _uniformsMode0[] = {
|
||||
{ "loc", GBA_GL_VS_LOC, },
|
||||
{ "maxPos", GBA_GL_VS_MAXPOS, },
|
||||
{ "vram", GBA_GL_BG_VRAM, },
|
||||
@ -155,7 +157,7 @@ static const char* const _fetchTileNoOverflow =
|
||||
" return renderTile(coord);\n"
|
||||
"}";
|
||||
|
||||
const static struct GBAVideoGLUniform _uniformsMode2[] = {
|
||||
static const struct GBAVideoGLUniform _uniformsMode2[] = {
|
||||
{ "loc", GBA_GL_VS_LOC, },
|
||||
{ "maxPos", GBA_GL_VS_MAXPOS, },
|
||||
{ "vram", GBA_GL_BG_VRAM, },
|
||||
@ -221,7 +223,7 @@ static const char* const _renderMode2 =
|
||||
" flags = inflags / flagCoeff;\n"
|
||||
"}";
|
||||
|
||||
const static struct GBAVideoGLUniform _uniformsObj[] = {
|
||||
static const struct GBAVideoGLUniform _uniformsObj[] = {
|
||||
{ "loc", GBA_GL_VS_LOC, },
|
||||
{ "maxPos", GBA_GL_VS_MAXPOS, },
|
||||
{ "vram", GBA_GL_OBJ_VRAM, },
|
||||
@ -268,7 +270,7 @@ static const char* const _renderObj =
|
||||
" window = objwin.yz;\n"
|
||||
"}";
|
||||
|
||||
const static struct GBAVideoGLUniform _uniformsComposite[] = {
|
||||
static const struct GBAVideoGLUniform _uniformsComposite[] = {
|
||||
{ "loc", GBA_GL_VS_LOC, },
|
||||
{ "maxPos", GBA_GL_VS_MAXPOS, },
|
||||
{ "scale", GBA_GL_COMPOSITE_SCALE, },
|
||||
@ -329,7 +331,7 @@ static const char* const _composite =
|
||||
" }\n"
|
||||
"}";
|
||||
|
||||
const static struct GBAVideoGLUniform _uniformsFinalize[] = {
|
||||
static const struct GBAVideoGLUniform _uniformsFinalize[] = {
|
||||
{ "loc", GBA_GL_VS_LOC, },
|
||||
{ "maxPos", GBA_GL_VS_MAXPOS, },
|
||||
{ "scale", GBA_GL_FINALIZE_SCALE, },
|
||||
@ -413,8 +415,10 @@ void _compileShader(struct GBAVideoGLRenderer* glRenderer, GLuint program, const
|
||||
mLOG(GBA_VIDEO, ERROR, "Program link failure: %s", log);
|
||||
}
|
||||
glDeleteShader(fs);
|
||||
#ifndef BUILD_GLES3
|
||||
glBindFragDataLocation(program, 0, "color");
|
||||
glBindFragDataLocation(program, 1, "flags");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void _initFramebufferTexture(GLuint tex, GLenum format, GLenum attachment, int scale) {
|
||||
@ -550,18 +554,24 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) {
|
||||
shaderBuffer[2] = _renderTile16;
|
||||
_compileShader(glRenderer, glRenderer->objProgram[0], shaderBuffer, 3, vs, log);
|
||||
_lookupUniforms(glRenderer->objProgram[0], glRenderer->objUniforms[0], _uniformsObj);
|
||||
#ifndef BUILD_GLES3
|
||||
glBindFragDataLocation(glRenderer->objProgram[0], 2, "window");
|
||||
#endif
|
||||
|
||||
shaderBuffer[2] = _renderTile256;
|
||||
_compileShader(glRenderer, glRenderer->objProgram[1], shaderBuffer, 3, vs, log);
|
||||
_lookupUniforms(glRenderer->objProgram[1], glRenderer->objUniforms[1], _uniformsObj);
|
||||
#ifndef BUILD_GLES3
|
||||
glBindFragDataLocation(glRenderer->objProgram[1], 2, "window");
|
||||
#endif
|
||||
|
||||
shaderBuffer[1] = _composite;
|
||||
_compileShader(glRenderer, glRenderer->compositeProgram, shaderBuffer, 2, vs, log);
|
||||
_lookupUniforms(glRenderer->compositeProgram, glRenderer->compositeUniforms, _uniformsComposite);
|
||||
#ifndef BUILD_GLES3
|
||||
glBindFragDataLocation(glRenderer->compositeProgram, 2, "oldColor");
|
||||
glBindFragDataLocation(glRenderer->compositeProgram, 3, "oldFlags");
|
||||
#endif
|
||||
|
||||
shaderBuffer[1] = _finalize;
|
||||
_compileShader(glRenderer, glRenderer->finalizeProgram, shaderBuffer, 2, vs, log);
|
||||
@ -585,7 +595,6 @@ void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) {
|
||||
glDeleteProgram(glRenderer->bgProgram[3]);
|
||||
glDeleteProgram(glRenderer->bgProgram[4]);
|
||||
glDeleteProgram(glRenderer->bgProgram[5]);
|
||||
glDeleteProgram(glRenderer->bgProgram[6]);
|
||||
glDeleteProgram(glRenderer->objProgram[0]);
|
||||
glDeleteProgram(glRenderer->objProgram[1]);
|
||||
glDeleteProgram(glRenderer->compositeProgram);
|
||||
@ -611,9 +620,13 @@ void GBAVideoGLRendererWriteOAM(struct GBAVideoRenderer* renderer, uint32_t oam)
|
||||
}
|
||||
|
||||
void GBAVideoGLRendererWritePalette(struct GBAVideoRenderer* renderer, uint32_t address, uint16_t value) {
|
||||
struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
|
||||
#ifdef BUILD_GLES3
|
||||
glRenderer->shadowPalette[address >> 1] = (value & 0x3F) | ((value & 0x7FE0) << 1);
|
||||
#else
|
||||
UNUSED(address);
|
||||
UNUSED(value);
|
||||
struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
|
||||
#endif
|
||||
glRenderer->paletteDirty = true;
|
||||
}
|
||||
|
||||
@ -822,7 +835,11 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
|
||||
struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer;
|
||||
if (glRenderer->paletteDirty) {
|
||||
glBindTexture(GL_TEXTURE_2D, glRenderer->paletteTex);
|
||||
#ifdef BUILD_GLES3
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB565, 16, 32, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_6_5, glRenderer->shadowPalette);
|
||||
#else
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 16, 32, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, glRenderer->d.palette);
|
||||
#endif
|
||||
glRenderer->paletteDirty = false;
|
||||
}
|
||||
int i;
|
||||
@ -841,33 +858,33 @@ void GBAVideoGLRendererDrawScanline(struct GBAVideoRenderer* renderer, int y) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_COMPOSITE]);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glScissor(0, y * glRenderer->scale, GBA_VIDEO_HORIZONTAL_PIXELS * glRenderer->scale, glRenderer->scale);
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
||||
glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
if (y == 0) {
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT1);
|
||||
glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT1 });
|
||||
glClearColor(1, (glRenderer->target1Bd | (glRenderer->target2Bd * 2) | (glRenderer->blendEffect * 4)) / 32.f,
|
||||
(glRenderer->blendEffect == BLEND_ALPHA ? glRenderer->blda : glRenderer->bldy) / 16.f, glRenderer->bldb / 16.f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT3);
|
||||
glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT3 });
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]);
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
||||
glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT1);
|
||||
glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT1 });
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->bg[i].fbo);
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
||||
glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT1);
|
||||
glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT1 });
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
}
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
||||
glDrawBuffers(1, (GLenum[]) { GL_COLOR_ATTACHMENT0 });
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
@ -1310,3 +1327,5 @@ void GBAVideoGLRendererDrawWindow(struct GBAVideoGLRenderer* renderer, int y) {
|
||||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -47,17 +47,6 @@ if(APPLE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(BUILD_GL)
|
||||
list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gl.c)
|
||||
if(NOT WIN32 OR USE_EPOXY)
|
||||
list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gles2.c)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(BUILD_GLES2)
|
||||
list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gles2.c)
|
||||
endif()
|
||||
|
||||
get_target_property(QT_TYPE Qt5::Core TYPE)
|
||||
if(QT_TYPE STREQUAL STATIC_LIBRARY)
|
||||
set(QT_STATIC ON)
|
||||
@ -245,7 +234,7 @@ if(NOT DEFINED DATADIR)
|
||||
set(DATADIR ${CMAKE_INSTALL_DATADIR}/${BINARY_NAME})
|
||||
endif()
|
||||
endif()
|
||||
if(BUILD_GL OR BUILD_GLES2)
|
||||
if(BUILD_GL OR BUILD_GLES2 OR BUILD_EPOXY)
|
||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/res/shaders DESTINATION ${DATADIR} COMPONENT ${BINARY_NAME}-qt)
|
||||
endif()
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/res/nointro.dat DESTINATION ${DATADIR} COMPONENT ${BINARY_NAME}-qt)
|
||||
@ -291,7 +280,7 @@ add_executable(${BINARY_NAME}-qt WIN32 MACOSX_BUNDLE main.cpp ${CMAKE_SOURCE_DIR
|
||||
set_target_properties(${BINARY_NAME}-qt PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/res/info.plist.in COMPILE_DEFINITIONS "${FEATURE_DEFINES};${FUNCTION_DEFINES};${OS_DEFINES};${QT_DEFINES}" COMPILE_OPTIONS "${FEATURE_FLAGS}")
|
||||
|
||||
list(APPEND QT_LIBRARIES Qt5::Widgets)
|
||||
if(BUILD_GL OR BUILD_GLES2)
|
||||
if(BUILD_GL OR BUILD_GLES2 OR BUILD_EPOXY)
|
||||
list(APPEND QT_LIBRARIES Qt5::OpenGL ${OPENGL_LIBRARY} ${OPENGLES2_LIBRARY})
|
||||
endif()
|
||||
if(QT_STATIC)
|
||||
|
@ -40,16 +40,6 @@ CoreController::CoreController(mCore* core, QObject* parent)
|
||||
m_threadContext.core = core;
|
||||
m_threadContext.userData = this;
|
||||
|
||||
QSize size(1024, 2048);
|
||||
m_buffers[0].resize(size.width() * size.height() * sizeof(color_t));
|
||||
m_buffers[1].resize(size.width() * size.height() * sizeof(color_t));
|
||||
m_buffers[0].fill(0xFF);
|
||||
m_buffers[1].fill(0xFF);
|
||||
m_activeBuffer = &m_buffers[0];
|
||||
m_completeBuffer = m_buffers[0];
|
||||
|
||||
m_threadContext.core->setVideoBuffer(m_threadContext.core, reinterpret_cast<color_t*>(m_activeBuffer->data()), size.width());
|
||||
|
||||
m_resetActions.append([this]() {
|
||||
if (m_autoload) {
|
||||
mCoreLoadState(m_threadContext.core, 0, m_loadStateFlags);
|
||||
@ -91,8 +81,10 @@ CoreController::CoreController(mCore* core, QObject* parent)
|
||||
|
||||
controller->m_resetActions.clear();
|
||||
|
||||
controller->m_activeBuffer = &controller->m_buffers[0];
|
||||
context->core->setVideoBuffer(context->core, reinterpret_cast<color_t*>(controller->m_activeBuffer->data()), controller->screenDimensions().width());
|
||||
if (!controller->m_hwaccel) {
|
||||
controller->m_activeBuffer = &controller->m_buffers[0];
|
||||
context->core->setVideoBuffer(context->core, reinterpret_cast<color_t*>(controller->m_activeBuffer->data()), controller->screenDimensions().width());
|
||||
}
|
||||
|
||||
controller->finishFrame();
|
||||
};
|
||||
@ -211,6 +203,9 @@ CoreController::~CoreController() {
|
||||
|
||||
const color_t* CoreController::drawContext() {
|
||||
QMutexLocker locker(&m_mutex);
|
||||
if (m_hwaccel) {
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<const color_t*>(m_completeBuffer.constData());
|
||||
}
|
||||
|
||||
@ -340,6 +335,18 @@ void CoreController::setLogger(LogController* logger) {
|
||||
}
|
||||
|
||||
void CoreController::start() {
|
||||
if (!m_hwaccel) {
|
||||
QSize size(1024, 2048);
|
||||
m_buffers[0].resize(size.width() * size.height() * sizeof(color_t));
|
||||
m_buffers[1].resize(size.width() * size.height() * sizeof(color_t));
|
||||
m_buffers[0].fill(0xFF);
|
||||
m_buffers[1].fill(0xFF);
|
||||
m_activeBuffer = &m_buffers[0];
|
||||
m_completeBuffer = m_buffers[0];
|
||||
|
||||
m_threadContext.core->setVideoBuffer(m_threadContext.core, reinterpret_cast<color_t*>(m_activeBuffer->data()), size.width());
|
||||
}
|
||||
|
||||
if (!m_patched) {
|
||||
mCoreAutoloadPatch(m_threadContext.core);
|
||||
}
|
||||
@ -800,6 +807,16 @@ void CoreController::endVideoLog() {
|
||||
m_vl = nullptr;
|
||||
}
|
||||
|
||||
void CoreController::setFramebufferHandle(int fb) {
|
||||
Interrupter interrupter(this);
|
||||
if (fb < 0) {
|
||||
m_hwaccel = false;
|
||||
} else {
|
||||
m_threadContext.core->setVideoGLTex(m_threadContext.core, fb);
|
||||
m_hwaccel = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CoreController::updateKeys() {
|
||||
int activeKeys = m_activeKeys | updateAutofire() | m_inputController->pollEvents();
|
||||
m_threadContext.core->setKeys(m_threadContext.core, activeKeys);
|
||||
@ -823,17 +840,18 @@ int CoreController::updateAutofire() {
|
||||
|
||||
void CoreController::finishFrame() {
|
||||
QMutexLocker locker(&m_mutex);
|
||||
memcpy(m_completeBuffer.data(), m_activeBuffer->constData(), m_activeBuffer->size());
|
||||
if (!m_hwaccel) {
|
||||
memcpy(m_completeBuffer.data(), m_activeBuffer->constData(), m_activeBuffer->size());
|
||||
|
||||
// TODO: Generalize this to triple buffering?
|
||||
m_activeBuffer = &m_buffers[0];
|
||||
if (m_activeBuffer == m_completeBuffer) {
|
||||
m_activeBuffer = &m_buffers[1];
|
||||
// TODO: Generalize this to triple buffering?
|
||||
m_activeBuffer = &m_buffers[0];
|
||||
if (m_activeBuffer == m_completeBuffer) {
|
||||
m_activeBuffer = &m_buffers[1];
|
||||
}
|
||||
// Copy contents to avoid issues when doing frameskip
|
||||
memcpy(m_activeBuffer->data(), m_completeBuffer.constData(), m_activeBuffer->size());
|
||||
m_threadContext.core->setVideoBuffer(m_threadContext.core, reinterpret_cast<color_t*>(m_activeBuffer->data()), screenDimensions().width());
|
||||
}
|
||||
// Copy contents to avoid issues when doing frameskip
|
||||
memcpy(m_activeBuffer->data(), m_completeBuffer.constData(), m_activeBuffer->size());
|
||||
m_threadContext.core->setVideoBuffer(m_threadContext.core, reinterpret_cast<color_t*>(m_activeBuffer->data()), screenDimensions().width());
|
||||
|
||||
for (auto& action : m_frameActions) {
|
||||
action();
|
||||
}
|
||||
|
@ -46,6 +46,10 @@ public:
|
||||
static const bool VIDEO_SYNC = false;
|
||||
static const bool AUDIO_SYNC = true;
|
||||
|
||||
enum class Feature {
|
||||
OPENGL = mCORE_FEATURE_OPENGL,
|
||||
};
|
||||
|
||||
class Interrupter {
|
||||
public:
|
||||
Interrupter(CoreController*, bool fromThread = false);
|
||||
@ -69,6 +73,8 @@ public:
|
||||
|
||||
mPlatform platform() const;
|
||||
QSize screenDimensions() const;
|
||||
bool supportsFeature(Feature feature) const { return m_threadContext.core->supportsFeature(m_threadContext.core, static_cast<mCoreFeature>(feature)); }
|
||||
bool hardwareAccelerated() const { return m_hwaccel; }
|
||||
|
||||
void loadConfig(ConfigController*);
|
||||
|
||||
@ -154,6 +160,8 @@ public slots:
|
||||
void startVideoLog(const QString& path);
|
||||
void endVideoLog();
|
||||
|
||||
void setFramebufferHandle(int fb);
|
||||
|
||||
signals:
|
||||
void started();
|
||||
void paused();
|
||||
@ -188,6 +196,7 @@ private:
|
||||
QByteArray m_buffers[2];
|
||||
QByteArray* m_activeBuffer;
|
||||
QByteArray m_completeBuffer;
|
||||
bool m_hwaccel = false;
|
||||
|
||||
std::unique_ptr<mCacheSet> m_cacheSet;
|
||||
std::unique_ptr<Override> m_override;
|
||||
|
@ -49,6 +49,7 @@ public:
|
||||
virtual bool supportsShaders() const = 0;
|
||||
virtual VideoShader* shaders() = 0;
|
||||
virtual VideoProxy* videoProxy() { return nullptr; }
|
||||
virtual int framebufferHandle() { return -1; }
|
||||
|
||||
signals:
|
||||
void showCursor();
|
||||
|
@ -18,7 +18,7 @@
|
||||
#ifdef BUILD_GL
|
||||
#include "platform/opengl/gl.h"
|
||||
#endif
|
||||
#if !defined(_WIN32) || defined(USE_EPOXY)
|
||||
#ifdef BUILD_GLES2
|
||||
#include "platform/opengl/gles2.h"
|
||||
#ifdef _WIN32
|
||||
#include <epoxy/wgl.h>
|
||||
@ -195,6 +195,10 @@ VideoProxy* DisplayGL::videoProxy() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int DisplayGL::framebufferHandle() {
|
||||
return m_painter->glTex();
|
||||
}
|
||||
|
||||
PainterGL::PainterGL(int majorVersion, VideoProxy* proxy, QGLWidget* parent)
|
||||
: m_gl(parent)
|
||||
, m_videoProxy(proxy)
|
||||
@ -202,7 +206,7 @@ PainterGL::PainterGL(int majorVersion, VideoProxy* proxy, QGLWidget* parent)
|
||||
#ifdef BUILD_GL
|
||||
mGLContext* glBackend;
|
||||
#endif
|
||||
#if !defined(_WIN32) || defined(USE_EPOXY)
|
||||
#ifdef BUILD_GLES2
|
||||
mGLES2Context* gl2Backend;
|
||||
#endif
|
||||
|
||||
@ -213,7 +217,7 @@ PainterGL::PainterGL(int majorVersion, VideoProxy* proxy, QGLWidget* parent)
|
||||
|
||||
QStringList extensions = QString(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS))).split(' ');
|
||||
|
||||
#if !defined(_WIN32) || defined(USE_EPOXY)
|
||||
#ifdef BUILD_GLES2
|
||||
if (extensions.contains("GL_ARB_framebuffer_object") && majorVersion >= 2) {
|
||||
gl2Backend = static_cast<mGLES2Context*>(malloc(sizeof(mGLES2Context)));
|
||||
mGLES2ContextCreate(gl2Backend);
|
||||
@ -239,7 +243,7 @@ PainterGL::PainterGL(int majorVersion, VideoProxy* proxy, QGLWidget* parent)
|
||||
};
|
||||
|
||||
m_backend->init(m_backend, reinterpret_cast<WHandle>(m_gl->winId()));
|
||||
#if !defined(_WIN32) || defined(USE_EPOXY)
|
||||
#ifdef BUILD_GLES2
|
||||
if (m_supportsShaders) {
|
||||
m_shader.preprocessShader = static_cast<void*>(&reinterpret_cast<mGLES2Context*>(m_backend)->initialShader);
|
||||
}
|
||||
@ -266,7 +270,7 @@ PainterGL::~PainterGL() {
|
||||
#if defined(_WIN32) && defined(USE_EPOXY)
|
||||
epoxy_handle_external_wglMakeCurrent();
|
||||
#endif
|
||||
#if !defined(_WIN32) || defined(USE_EPOXY)
|
||||
#ifdef BUILD_GLES2
|
||||
if (m_shader.passes) {
|
||||
mGLES2ShaderFree(&m_shader);
|
||||
}
|
||||
@ -339,7 +343,7 @@ void PainterGL::start() {
|
||||
epoxy_handle_external_wglMakeCurrent();
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) || defined(USE_EPOXY)
|
||||
#ifdef BUILD_GLES2
|
||||
if (m_supportsShaders && m_shader.passes) {
|
||||
mGLES2ShaderAttach(reinterpret_cast<mGLES2Context*>(m_backend), static_cast<mGLES2Shader*>(m_shader.passes), m_shader.nPasses);
|
||||
}
|
||||
@ -422,14 +426,16 @@ void PainterGL::performDraw() {
|
||||
|
||||
void PainterGL::enqueue(const uint32_t* backing) {
|
||||
m_mutex.lock();
|
||||
uint32_t* buffer;
|
||||
if (m_free.isEmpty()) {
|
||||
buffer = m_queue.dequeue();
|
||||
} else {
|
||||
buffer = m_free.takeLast();
|
||||
uint32_t* buffer = nullptr;
|
||||
if (backing) {
|
||||
if (m_free.isEmpty()) {
|
||||
buffer = m_queue.dequeue();
|
||||
} else {
|
||||
buffer = m_free.takeLast();
|
||||
}
|
||||
QSize size = m_context->screenDimensions();
|
||||
memcpy(buffer, backing, size.width() * size.height() * BYTES_PER_PIXEL);
|
||||
}
|
||||
QSize size = m_context->screenDimensions();
|
||||
memcpy(buffer, backing, size.width() * size.height() * BYTES_PER_PIXEL);
|
||||
m_queue.enqueue(buffer);
|
||||
m_mutex.unlock();
|
||||
}
|
||||
@ -441,8 +447,10 @@ void PainterGL::dequeue() {
|
||||
return;
|
||||
}
|
||||
uint32_t* buffer = m_queue.dequeue();
|
||||
m_backend->postFrame(m_backend, buffer);
|
||||
m_free.append(buffer);
|
||||
if (buffer) {
|
||||
m_backend->postFrame(m_backend, buffer);
|
||||
m_free.append(buffer);
|
||||
}
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
@ -451,7 +459,9 @@ void PainterGL::dequeueAll() {
|
||||
m_mutex.lock();
|
||||
while (!m_queue.isEmpty()) {
|
||||
buffer = m_queue.dequeue();
|
||||
m_free.append(buffer);
|
||||
if (buffer) {
|
||||
m_free.append(buffer);
|
||||
}
|
||||
}
|
||||
if (buffer) {
|
||||
m_backend->postFrame(m_backend, buffer);
|
||||
@ -464,7 +474,7 @@ void PainterGL::setShaders(struct VDir* dir) {
|
||||
return;
|
||||
}
|
||||
if (!m_active) {
|
||||
#if !defined(_WIN32) || defined(USE_EPOXY)
|
||||
#ifdef BUILD_GLES2
|
||||
m_gl->makeCurrent();
|
||||
#if defined(_WIN32) && defined(USE_EPOXY)
|
||||
epoxy_handle_external_wglMakeCurrent();
|
||||
@ -489,7 +499,7 @@ void PainterGL::clearShaders() {
|
||||
return;
|
||||
}
|
||||
if (!m_active) {
|
||||
#if !defined(_WIN32) || defined(USE_EPOXY)
|
||||
#ifdef BUILD_GLES2
|
||||
m_gl->makeCurrent();
|
||||
#if defined(_WIN32) && defined(USE_EPOXY)
|
||||
epoxy_handle_external_wglMakeCurrent();
|
||||
@ -509,4 +519,19 @@ VideoShader* PainterGL::shaders() {
|
||||
return &m_shader;
|
||||
}
|
||||
|
||||
int PainterGL::glTex() {
|
||||
#ifdef BUILD_GLES2
|
||||
if (supportsShaders()) {
|
||||
mGLES2Context* gl2Backend = reinterpret_cast<mGLES2Context*>(m_backend);
|
||||
return gl2Backend->tex;
|
||||
}
|
||||
#endif
|
||||
#ifdef BUILD_GL
|
||||
mGLContext* glBackend = reinterpret_cast<mGLContext*>(m_backend);
|
||||
return glBackend->tex;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -52,6 +52,7 @@ public:
|
||||
bool supportsShaders() const override;
|
||||
VideoShader* shaders() override;
|
||||
VideoProxy* videoProxy() override;
|
||||
int framebufferHandle() override;
|
||||
|
||||
public slots:
|
||||
void stopDrawing() override;
|
||||
@ -111,6 +112,8 @@ public slots:
|
||||
void clearShaders();
|
||||
VideoShader* shaders();
|
||||
|
||||
int glTex();
|
||||
|
||||
private:
|
||||
void performDraw();
|
||||
void dequeue();
|
||||
|
@ -851,6 +851,10 @@ void Window::unimplementedBiosCall(int call) {
|
||||
|
||||
void Window::reloadDisplayDriver() {
|
||||
if (m_controller) {
|
||||
if (m_controller->hardwareAccelerated()) {
|
||||
mustRestart();
|
||||
return;
|
||||
}
|
||||
m_display->stopDrawing();
|
||||
detachWidget(m_display.get());
|
||||
}
|
||||
@ -1715,8 +1719,15 @@ void Window::setController(CoreController* controller, const QString& fname) {
|
||||
reloadDisplayDriver();
|
||||
}
|
||||
|
||||
if (m_display->videoProxy()) {
|
||||
m_display->videoProxy()->attach(controller);
|
||||
if (m_config->getOption("hwaccelVideo").toInt() && m_display->supportsShaders() && controller->supportsFeature(CoreController::Feature::OPENGL)) {
|
||||
if (m_display->videoProxy()) {
|
||||
m_display->videoProxy()->attach(controller);
|
||||
}
|
||||
|
||||
int fb = m_display->framebufferHandle();
|
||||
if (fb >= 0) {
|
||||
controller->setFramebufferHandle(fb);
|
||||
}
|
||||
}
|
||||
|
||||
m_controller = std::shared_ptr<CoreController>(controller);
|
||||
|
@ -77,12 +77,11 @@ if(BUILD_PANDORA)
|
||||
else()
|
||||
if(BUILD_GL)
|
||||
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-sdl.c)
|
||||
list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gl.c ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-common.c)
|
||||
include_directories(${OPENGL_INCLUDE_DIR})
|
||||
list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-common.c)
|
||||
endif()
|
||||
if(BUILD_GLES2)
|
||||
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gles2-sdl.c)
|
||||
list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gles2.c ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-common.c)
|
||||
list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-common.c)
|
||||
include_directories(${OPENGLES2_INCLUDE_DIR})
|
||||
endif()
|
||||
if(NOT BUILD_GL AND NOT BUILD_GLES2)
|
||||
|
@ -35,7 +35,9 @@ bool mSDLGLES2Init(struct mSDLRenderer* renderer) {
|
||||
#endif
|
||||
|
||||
size_t size = renderer->width * renderer->height * BYTES_PER_PIXEL;
|
||||
#ifndef __APPLE__
|
||||
#ifdef _WIN32
|
||||
renderer->outputBuffer = _aligned_malloc(size, 16);
|
||||
#elif !defined(__APPLE__)
|
||||
renderer->outputBuffer = memalign(16, size);
|
||||
#else
|
||||
posix_memalign((void**) &renderer->outputBuffer, 16, size);
|
||||
|
@ -31,6 +31,7 @@ while [ $# -gt 0 ]; do
|
||||
rmdep libav
|
||||
rmdep libedit
|
||||
rmdep libelf
|
||||
rmdep libgl
|
||||
rmdep libpng
|
||||
rmdep libzip
|
||||
rmdep libmagickwand
|
||||
@ -45,6 +46,7 @@ while [ $# -gt 0 ]; do
|
||||
rmdep libav
|
||||
rmdep libedit
|
||||
rmdep libelf
|
||||
rmdep libgl
|
||||
rmdep libpng
|
||||
rmdep qt
|
||||
rmdep libzip
|
||||
|
Loading…
Reference in New Issue
Block a user