From 20c8f6d463dca67671bb80bad0ef32ec83d59e18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E7=9A=93?= Date: Wed, 19 Feb 2025 18:16:08 -0500 Subject: [PATCH] Get `Graphics::update()` working (probably) in libretro builds --- meson.build | 1 + src/core.cpp | 13 +-- src/display/bitmap.cpp | 129 +++++---------------------- src/display/gl/gl-meta.cpp | 29 +++---- src/display/gl/gl-util.h | 12 ++- src/display/graphics.cpp | 173 ++++++++++++++++++++++++++++++++++--- src/sharedstate.cpp | 10 +-- src/util/sdl-util.h | 32 +++++++ 8 files changed, 248 insertions(+), 151 deletions(-) diff --git a/meson.build b/meson.build index f971cd20..11c0e6eb 100644 --- a/meson.build +++ b/meson.build @@ -387,6 +387,7 @@ if is_libretro 'src/display/gl/texpool.cpp', 'src/display/gl/tileatlas.cpp', 'src/display/gl/vertex.cpp', + 'src/display/graphics.cpp', 'src/etc/etc.cpp', 'src/etc/table.cpp', 'src/filesystem/filesystem.cpp', diff --git a/src/core.cpp b/src/core.cpp index de62641e..ed9eff4a 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -35,7 +35,6 @@ #include "core.h" #include "filesystem.h" #include "gl-fun.h" -#include "gl-meta.h" using namespace mkxp_retro; using namespace mkxp_sandbox; @@ -381,10 +380,6 @@ extern "C" RETRO_API void retro_run() { shared_state_initialized = true; } - if (hw_render.context_type != RETRO_HW_CONTEXT_NONE) { - GLMeta::blitBeginScreen({640, 480}); - } - if (mkxp_retro::sandbox.has_value()) { try { if (sb().run()) { @@ -399,6 +394,10 @@ extern "C" RETRO_API void retro_run() { } } + if (mkxp_retro::sandbox.has_value()) { + shState->graphics().update(); + } + void *fb; if (hw_render.context_type != RETRO_HW_CONTEXT_NONE) { fb = RETRO_HW_FRAME_BUFFER_VALID; @@ -415,10 +414,6 @@ extern "C" RETRO_API void retro_run() { } video_refresh(fb, 640, 480, 640 * 4); - if (hw_render.context_type != RETRO_HW_CONTEXT_NONE) { - GLMeta::blitEnd(); - } - if (mkxp_retro::sandbox.has_value()) { audio->render(); alcRenderSamplesSOFT(al_device, sound_buf, 735); diff --git a/src/display/bitmap.cpp b/src/display/bitmap.cpp index 86387f3d..510c96e1 100644 --- a/src/display/bitmap.cpp +++ b/src/display/bitmap.cpp @@ -171,9 +171,7 @@ struct BitmapPrivate bool playing; bool needsReset; bool loop; -#ifndef MKXPZ_RETRO std::vector frames; -#endif // MKXPZ_RETRO float fps; int lastFrame; double startTime, playTime; @@ -183,7 +181,6 @@ struct BitmapPrivate return floor(lastFrame + (playTime / (1 / fps))); } -#ifndef MKXPZ_RETRO unsigned int currentFrameI() { if (!playing || needsReset) return lastFrame; int i = currentFrameIRaw(); @@ -194,7 +191,6 @@ struct BitmapPrivate int i = currentFrameI(); return frames[i]; } -#endif // MKXPZ_RETRO inline void play() { playing = true; @@ -202,23 +198,17 @@ struct BitmapPrivate } inline void stop() { -#ifndef MKXPZ_RETRO lastFrame = currentFrameI(); -#endif // MKXPZ_RETRO playing = false; } inline void seek(int frame) { -#ifndef MKXPZ_RETRO lastFrame = clamp(frame, 0, (int)frames.size()); -#endif // MKXPZ_RETRO } void updateTimer() { if (needsReset) { -#ifndef MKXPZ_RETRO lastFrame = currentFrameI(); -#endif // MKXPZ_RETRO playTime = 0; startTime = shState->runTime(); needsReset = false; @@ -303,11 +293,7 @@ struct BitmapPrivate } TEXFBO &getGLTypes() { -#ifdef MKXPZ_RETRO - return gl; // TODO -#else return (animation.enabled) ? animation.currentFrame() : gl; -#endif // MKXPZ_RETRO } void prepare() @@ -388,14 +374,11 @@ struct BitmapPrivate Debug() << "BUG: High-res BitmapPrivate bindTexture for animations not implemented"; } -#ifndef MKXPZ_RETRO TEXFBO cframe = animation.currentFrame(); TEX::bind(cframe.tex); shader.setTexSize(Vec2i(cframe.width, cframe.height)); -#endif // MKXPZ_RETRO return; } -#ifndef MKXPZ_RETRO TEX::bind(gl.tex); if (selfLores && substituteLoresSize) { shader.setTexSize(Vec2i(selfLores->width(), selfLores->height())); @@ -403,22 +386,17 @@ struct BitmapPrivate else { shader.setTexSize(Vec2i(gl.width, gl.height)); } -#endif // MKXPZ_RETRO } void bindFBO() { -#ifndef MKXPZ_RETRO FBO::bind((animation.enabled) ? animation.currentFrame().fbo : gl.fbo); -#endif // MKXPZ_RETRO } void pushSetViewport(ShaderBase &shader) const { -#ifndef MKXPZ_RETRO glState.viewport.pushSet(IntRect(0, 0, gl.width, gl.height)); shader.applyViewportProj(); -#endif // MKXPZ_RETRO } void popViewport() const @@ -429,9 +407,7 @@ struct BitmapPrivate void blitQuad(Quad &quad) { glState.blend.pushSet(false); -#ifndef MKXPZ_RETRO quad.draw(); -#endif // MKXPZ_RETRO glState.blend.pop(); } @@ -440,7 +416,6 @@ struct BitmapPrivate { bindFBO(); -#ifndef MKXPZ_RETRO glState.scissorTest.pushSet(true); glState.scissorBox.pushSet(normalizedRect(rect)); glState.clearColor.pushSet(color); @@ -450,7 +425,6 @@ struct BitmapPrivate glState.clearColor.pop(); glState.scissorBox.pop(); glState.scissorTest.pop(); -#endif // MKXPZ_RETRO } #ifndef MKXPZ_RETRO @@ -714,6 +688,7 @@ Bitmap::Bitmap(int width, int height, bool isHires) hiresBitmap = new Bitmap(hiresWidth, hiresHeight, true); hiresBitmap->setLores(this); } +#endif // MKXPZ_RETRO TEXFBO tex; try { @@ -723,16 +698,13 @@ Bitmap::Bitmap(int width, int height, bool isHires) delete hiresBitmap; throw e; } -#endif // MKXPZ_RETRO p = new BitmapPrivate(this); -#ifndef MKXPZ_RETRO p->gl = tex; p->selfHires = hiresBitmap; if (p->selfHires != nullptr) { p->gl.selfHires = &p->selfHires->getGLTypes(); } -#endif // MKXPZ_RETRO clear(); } @@ -802,7 +774,6 @@ Bitmap::Bitmap(const Bitmap &other, int frame) // TODO: Clean me up if (!other.isAnimated() || frame >= -1) { -#ifndef MKXPZ_RETRO try { p->gl = shState->texPool().request(other.width(), other.height()); } catch (const Exception &e) { @@ -821,7 +792,6 @@ Bitmap::Bitmap(const Bitmap &other, int frame) } GLMeta::blitRectangle(rect(), rect()); GLMeta::blitEnd(); -#endif // MKXPZ_RETRO } else { p->animation.enabled = true; @@ -833,7 +803,6 @@ Bitmap::Bitmap(const Bitmap &other, int frame) p->animation.startTime = 0; p->animation.loop = other.getLooping(); -#ifndef MKXPZ_RETRO for (TEXFBO &sourceframe : other.getFrames()) { TEXFBO newframe; try { @@ -850,7 +819,6 @@ Bitmap::Bitmap(const Bitmap &other, int frame) p->animation.frames.push_back(newframe); } -#endif // MKXPZ_RETRO } p->addTaintedArea(rect()); @@ -860,18 +828,15 @@ Bitmap::Bitmap(TEXFBO &other) { Bitmap *hiresBitmap = nullptr; -#ifndef MKXPZ_RETRO if (other.selfHires != nullptr) { // Create a high-res version as well. hiresBitmap = new Bitmap(*other.selfHires); hiresBitmap->setLores(this); } -#endif // MKXPZ_RETRO p = new BitmapPrivate(this); p->selfHires = hiresBitmap; -#ifndef MKXPZ_RETRO try { p->gl = shState->texPool().request(other.width, other.height); } catch (const Exception &e) { @@ -890,7 +855,6 @@ Bitmap::Bitmap(TEXFBO &other) GLMeta::blitRectangle(rect(), rect()); GLMeta::blitEnd(); } -#endif // MKXPZ_RETRO p->addTaintedArea(rect()); } @@ -919,6 +883,7 @@ void Bitmap::initFromSurface(SDL_Surface *imgSurf, Bitmap *hiresBitmap, bool for { #ifndef MKXPZ_RETRO p->ensureFormat(imgSurf, SDL_PIXELFORMAT_ABGR8888); +#endif // MKXPZ_RETRO if (imgSurf->w > glState.caps.maxTexSize || imgSurf->h > glState.caps.maxTexSize || forceMega) { @@ -927,7 +892,9 @@ void Bitmap::initFromSurface(SDL_Surface *imgSurf, Bitmap *hiresBitmap, bool for p = new BitmapPrivate(this); p->selfHires = hiresBitmap; p->megaSurface = imgSurf; +#ifndef MKXPZ_RETRO SDL_SetSurfaceBlendMode(p->megaSurface, SDL_BLENDMODE_NONE); +#endif // MKXPZ_RETRO } else { @@ -942,14 +909,14 @@ void Bitmap::initFromSurface(SDL_Surface *imgSurf, Bitmap *hiresBitmap, bool for { if (hiresBitmap) delete hiresBitmap; +#ifndef MKXPZ_RETRO SDL_FreeSurface(imgSurf); +#endif // MKXPZ_RETRO throw e; } -#endif // MKXPZ_RETRO p = new BitmapPrivate(this); p->selfHires = hiresBitmap; -#ifndef MKXPZ_RETRO p->gl = tex; if (p->selfHires != nullptr) { p->gl.selfHires = &p->selfHires->getGLTypes(); @@ -958,9 +925,10 @@ void Bitmap::initFromSurface(SDL_Surface *imgSurf, Bitmap *hiresBitmap, bool for TEX::bind(p->gl.tex); TEX::uploadImage(p->gl.width, p->gl.height, imgSurf->pixels, GL_RGBA); +#ifndef MKXPZ_RETRO SDL_FreeSurface(imgSurf); - } #endif // MKXPZ_RETRO + } p->addTaintedArea(rect()); } @@ -969,9 +937,6 @@ int Bitmap::width() const { guardDisposed(); -#ifdef MKXPZ_RETRO - return 32; // TODO: implement -#else if (p->megaSurface) { return p->megaSurface->w; } @@ -981,16 +946,12 @@ int Bitmap::width() const } return p->gl.width; -#endif // MKXPZ_RETRO } int Bitmap::height() const { guardDisposed(); -#ifdef MKXPZ_RETRO - return 32; // TODO: implement -#else if (p->megaSurface) return p->megaSurface->h; @@ -998,7 +959,6 @@ int Bitmap::height() const return p->animation.height; return p->gl.height; -#endif // MKXPZ_RETRO } bool Bitmap::hasHires() const{ @@ -1479,7 +1439,6 @@ void Bitmap::gradientFillRect(const IntRect &rect, p->selfHires->gradientFillRect(IntRect(destX, destY, destWidth, destHeight), color1, color2, vertical); } -#ifndef MKXPZ_RETRO SimpleColorShader &shader = shState->shaders().simpleColor; shader.bind(); shader.setTranslation(Vec2i()); @@ -1509,7 +1468,6 @@ void Bitmap::gradientFillRect(const IntRect &rect, p->blitQuad(quad); p->popViewport(); -#endif // MKXPZ_RETRO p->addTaintedArea(rect); @@ -1556,7 +1514,6 @@ void Bitmap::blur() // TODO: Is there some kind of blur radius that we need to handle for high-res mode? -#ifndef MKXPZ_RETRO Quad &quad = shState->gpQuad(); FloatRect rect(0, 0, width(), height()); quad.setTexPosRect(rect, rect); @@ -1592,7 +1549,6 @@ void Bitmap::blur() glState.blend.pop(); shState->texPool().release(auxTex); -#endif // MKXPZ_RETRO p->onModified(); } @@ -1619,7 +1575,6 @@ void Bitmap::radialBlur(int angle, int divisions) float opacity = 1.0f / divisions; float baseAngle = -((float) angle / 2); -#ifndef MKXPZ_RETRO ColorQuadArray qArray; qArray.resize(5); @@ -1696,7 +1651,6 @@ void Bitmap::radialBlur(int angle, int divisions) shState->texPool().release(p->gl); p->gl = newTex; -#endif // MKXPZ_RETRO p->onModified(); } @@ -1713,20 +1667,17 @@ void Bitmap::clear() p->bindFBO(); -#ifndef MKXPZ_RETRO glState.clearColor.pushSet(Vec4()); FBO::clear(); glState.clearColor.pop(); -#endif // MKXPZ_RETRO p->clearTaintedArea(); p->onModified(); } -#ifndef MKXPZ_RETRO static uint32_t &getPixelAt(SDL_Surface *surf, SDL_PixelFormat *form, int x, int y) { size_t offset = x*form->BytesPerPixel + y*surf->pitch; @@ -1734,7 +1685,6 @@ static uint32_t &getPixelAt(SDL_Surface *surf, SDL_PixelFormat *form, int x, int return *((uint32_t*) bytes); } -#endif // MKXPZ_RETRO Color Bitmap::getPixel(int x, int y) const { @@ -1793,7 +1743,6 @@ Color Bitmap::getPixel(int x, int y) const { p->allocSurface(); -#ifndef MKXPZ_RETRO FBO::bind(p->gl.fbo); glState.viewport.pushSet(IntRect(0, 0, width(), height())); @@ -1801,7 +1750,6 @@ Color Bitmap::getPixel(int x, int y) const gl.ReadPixels(0, 0, width(), height(), GL_RGBA, GL_UNSIGNED_BYTE, p->surface->pixels); glState.viewport.pop(); -#endif // MKXPZ_RETRO } #ifdef MKXPZ_RETRO @@ -1849,10 +1797,8 @@ void Bitmap::setPixel(int x, int y, const Color &color) (uint8_t) clamp(color.alpha, 0, 255) }; -#ifndef MKXPZ_RETRO TEX::bind(p->gl.tex); TEX::uploadSubImage(x, y, 1, 1, &pixel, GL_RGBA); -#endif // MKXPZ_RETRO p->addTaintedArea(IntRect(x, y, 1, 1)); @@ -1880,18 +1826,14 @@ bool Bitmap::getRaw(void *output, int output_size) Debug() << "GAME BUG: Game is calling getRaw on low-res Bitmap; you may want to patch the game to improve graphics quality."; } -#ifndef MKXPZ_RETRO if (!p->animation.enabled && (p->surface || p->megaSurface)) { void *src = (p->megaSurface) ? p->megaSurface->pixels : p->surface->pixels; memcpy(output, src, output_size); } else { -#endif // MKXPZ_RETRO FBO::bind(getGLTypes().fbo); gl.ReadPixels(0,0,width(),height(),GL_RGBA,GL_UNSIGNED_BYTE,output); -#ifndef MKXPZ_RETRO } -#endif // MKXPZ_RETRO return true; } @@ -1998,7 +1940,6 @@ void Bitmap::hueChange(int hue) if ((hue % 360) == 0) return; -#ifndef MKXPZ_RETRO TEXFBO newTex = shState->texPool().request(width(), height()); FloatRect texRect(rect()); @@ -2024,7 +1965,6 @@ void Bitmap::hueChange(int hue) shState->texPool().release(p->gl); p->gl = newTex; -#endif // MKXPZ_RETRO p->onModified(); } @@ -2051,7 +1991,6 @@ static std::string fixupString(const char *str) return s; } -#ifndef MKXPZ_RETRO static void applyShadow(SDL_Surface *&in, const SDL_PixelFormat &fm, const SDL_Color &c) { SDL_Surface *out = SDL_CreateRGBSurface @@ -2138,7 +2077,6 @@ static void applyShadow(SDL_Surface *&in, const SDL_PixelFormat &fm, const SDL_C SDL_FreeSurface(in); in = out; } -#endif // MKXPZ_RETRO void Bitmap::drawText(const IntRect &rect, const char *str, int align) { @@ -2169,7 +2107,6 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align) return; } -#endif // MKXPZ_RETRO std::string fixed = fixupString(str); str = fixed.c_str(); @@ -2180,7 +2117,6 @@ void Bitmap::drawText(const IntRect &rect, const char *str, int align) if (str[0] == ' ' && str[1] == '\0') return; -#ifndef MKXPZ_RETRO TTF_Font *font = p->font->getSdlFont(); const Color &fontColor = p->font->getColor(); const Color &outColor = p->font->getOutColor(); @@ -2358,24 +2294,24 @@ DEF_ATTR_RD_SIMPLE(Bitmap, Font, Font&, *p->font) void Bitmap::setFont(Font &value) { - // High-res support handled in drawText, not here. #ifndef MKXPZ_RETRO + // High-res support handled in drawText, not here. *p->font = value; #endif // MKXPZ_RETRO } void Bitmap::setInitFont(Font *value) { +#ifndef MKXPZ_RETRO if (hasHires()) { Font *hiresFont = p->selfHires->p->font; -#ifndef MKXPZ_RETRO if (hiresFont && hiresFont != &shState->defaultFont()) { // Disable the illegal font size check when creating a high-res font. hiresFont->setSize(hiresFont->getSize() * p->selfHires->width() / width(), false); } -#endif // MKXPZ_RETRO } +#endif // MKXPZ_RETRO p->font = value; } @@ -2474,11 +2410,7 @@ bool Bitmap::isPlaying() const if (p->animation.loop) return true; -#ifdef MKXPZ_RETRO - return false; // TODO: implement -#else return p->animation.currentFrameIRaw() < p->animation.frames.size(); -#endif // MKXPZ_RETRO } void Bitmap::gotoAndStop(int frame) @@ -2518,14 +2450,9 @@ int Bitmap::numFrames() const } if (!p->animation.enabled) return 1; -#ifdef MKXPZ_RETRO - return 0; // TODO: implement -#else return (int)p->animation.frames.size(); -#endif // MKXPZ_RETRO } -#ifndef MKXPZ_RETRO int Bitmap::currentFrameI() const { guardDisposed(); @@ -2537,7 +2464,6 @@ int Bitmap::currentFrameI() const if (!p->animation.enabled) return 0; return p->animation.currentFrameI(); } -#endif // MKXPZ_RETRO int Bitmap::addFrame(Bitmap &source, int position) { @@ -2558,7 +2484,6 @@ int Bitmap::addFrame(Bitmap &source, int position) throw Exception(Exception::MKXPError, "Animations with varying dimensions are not supported (%ix%i vs %ix%i)", source.width(), source.height(), width(), height()); -#ifndef MKXPZ_RETRO TEXFBO newframe = shState->texPool().request(source.width(), source.height()); // Convert the bitmap into an animated bitmap if it isn't already one @@ -2571,19 +2496,27 @@ int Bitmap::addFrame(Bitmap &source, int position) p->animation.startTime = 0; if (p->animation.fps <= 0) +#ifdef MKXPZ_RETRO // TODO: use actual FPS + p->animation.fps = 60.0; +#else p->animation.fps = shState->graphics().getFrameRate(); +#endif // MKXPZ_RETRO p->animation.frames.push_back(p->gl); +#ifndef MKXPZ_RETRO if (p->surface) SDL_FreeSurface(p->surface); +#endif // MKXPZ_RETRO p->gl = TEXFBO(); } if (source.surface()) { TEX::bind(newframe.tex); TEX::uploadImage(source.width(), source.height(), source.surface()->pixels, GL_RGBA); +#ifndef MKXPZ_RETRO SDL_FreeSurface(p->surface); +#endif // MKXPZ_RETRO p->surface = 0; } else { @@ -2593,23 +2526,14 @@ int Bitmap::addFrame(Bitmap &source, int position) GLMeta::blitEnd(); } -#endif // MKXPZ_RETRO int ret; if (position < 0) { -#ifndef MKXPZ_RETRO p->animation.frames.push_back(newframe); -#endif // MKXPZ_RETRO -#ifdef MKXPZ_RETRO - ret = 0; // TODO: implement -#else ret = (int)p->animation.frames.size(); -#endif // MKXPZ_RETRO } else { -#ifndef MKXPZ_RETRO p->animation.frames.insert(p->animation.frames.begin() + clamp(position, 0, (int)p->animation.frames.size()), newframe); -#endif // MKXPZ_RETRO ret = position; } @@ -2625,7 +2549,6 @@ void Bitmap::removeFrame(int position) { Debug() << "BUG: High-res Bitmap removeFrame not implemented"; } -#ifndef MKXPZ_RETRO int pos = (position < 0) ? (int)p->animation.frames.size() - 1 : clamp(position, 0, (int)(p->animation.frames.size() - 1)); shState->texPool().release(p->animation.frames[pos]); p->animation.frames.erase(p->animation.frames.begin() + pos); @@ -2645,7 +2568,6 @@ void Bitmap::removeFrame(int position) { FBO::bind(p->gl.fbo); taintArea(rect()); } -#endif // MKXPZ_RETRO } void Bitmap::nextFrame() @@ -2659,13 +2581,11 @@ void Bitmap::nextFrame() } stop(); -#ifndef MKXPZ_RETRO if ((uint32_t)p->animation.lastFrame >= p->animation.frames.size() - 1) { if (!p->animation.loop) return; p->animation.lastFrame = 0; return; } -#endif // MKXPZ_RETRO p->animation.lastFrame++; } @@ -2686,9 +2606,7 @@ void Bitmap::previousFrame() p->animation.lastFrame = 0; return; } -#ifndef MKXPZ_RETRO p->animation.lastFrame = (int)p->animation.frames.size() - 1; -#endif // MKXPZ_RETRO return; } @@ -2711,7 +2629,6 @@ void Bitmap::setAnimationFPS(float FPS) if (restart) p->animation.play(); } -#ifndef MKXPZ_RETRO std::vector &Bitmap::getFrames() const { if (hasHires()) { @@ -2720,7 +2637,6 @@ std::vector &Bitmap::getFrames() const return p->animation.frames; } -#endif // MKXPZ_RETRO float Bitmap::getAnimationFPS() const { @@ -2783,11 +2699,9 @@ void Bitmap::taintArea(const IntRect &rect) p->addTaintedArea(rect); } -#ifndef MKXPZ_RETRO int Bitmap::maxSize(){ return glState.caps.maxTexSize; } -#endif // MKXPZ_RETRO void Bitmap::assumeRubyGC() { @@ -2803,7 +2717,9 @@ void Bitmap::releaseResources() #ifndef MKXPZ_RETRO if (p->megaSurface) SDL_FreeSurface(p->megaSurface); - else if (p->animation.enabled) { + else +#endif // MKXPZ_RETRO + if (p->animation.enabled) { p->animation.enabled = false; p->animation.playing = false; for (TEXFBO &tex : p->animation.frames) @@ -2811,7 +2727,6 @@ void Bitmap::releaseResources() } else shState->texPool().release(p->gl); -#endif // MKXPZ_RETRO delete p; } diff --git a/src/display/gl/gl-meta.cpp b/src/display/gl/gl-meta.cpp index 0232c23f..01d191f3 100644 --- a/src/display/gl/gl-meta.cpp +++ b/src/display/gl/gl-meta.cpp @@ -211,14 +211,10 @@ int smoothScalingMethod(int scaleIsSpecial) static void _blitBegin(FBO::ID fbo, const Vec2i &size, int scaleIsSpecial) { - if (HAVE_NATIVE_BLIT) + FBO::bind(fbo); + + if (!HAVE_NATIVE_BLIT) { - FBO::boundFramebufferID = fbo; - gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo.gl); - } - else - { - FBO::bind(fbo); glState.viewport.pushSet(IntRect(0, 0, size.x, size.y)); switch (smoothScalingMethod(scaleIsSpecial)) @@ -303,15 +299,7 @@ void blitBeginScreen(const Vec2i &size, int scaleIsSpecial) blitDstHeightLores = 1; blitDstHeightHires = 1; - _blitBegin( -#ifdef MKXPZ_RETRO - FBO::ID(mkxp_retro::hw_render.get_current_framebuffer()), -#else - FBO::ID(0), -#endif // MKXPZ_RETRO - size, - scaleIsSpecial - ); + _blitBegin(FBO::ID(0), size, scaleIsSpecial); } void blitSource(TEXFBO &source, int scaleIsSpecial) @@ -329,7 +317,14 @@ void blitSource(TEXFBO &source, int scaleIsSpecial) if (HAVE_NATIVE_BLIT) { - gl.BindFramebuffer(GL_READ_FRAMEBUFFER, source.fbo.gl); + gl.BindFramebuffer( + GL_READ_FRAMEBUFFER, +#ifdef MKXPZ_RETRO + source.fbo.gl || mkxp_retro::hw_render.get_current_framebuffer() +#else + source.fbo.gl +#endif // MKXPZ_RETRO + ); } else { diff --git a/src/display/gl/gl-util.h b/src/display/gl/gl-util.h index ba145116..8573551d 100644 --- a/src/display/gl/gl-util.h +++ b/src/display/gl/gl-util.h @@ -26,6 +26,9 @@ #include "etc-internal.h" #include "sharedstate.h" #include "config.h" +#ifdef MKXPZ_RETRO +# include "core.h" +#endif // MKXPZ_RETRO /* Struct wrapping GLuint for some light type safety */ #define DEF_GL_ID \ @@ -139,7 +142,14 @@ namespace FBO static inline void bind(ID id) { boundFramebufferID = id; - gl.BindFramebuffer(GL_FRAMEBUFFER, id.gl); + gl.BindFramebuffer( + GL_FRAMEBUFFER, +#ifdef MKXPZ_RETRO + id.gl || mkxp_retro::hw_render.get_current_framebuffer() +#else + id.gl +#endif // MKXPZ_RETRO + ); } static inline void unbind() diff --git a/src/display/graphics.cpp b/src/display/graphics.cpp index 0f3c880e..b50cd8d7 100644 --- a/src/display/graphics.cpp +++ b/src/display/graphics.cpp @@ -41,17 +41,21 @@ #include "shader.h" #include "sharedstate.h" #include "texpool.h" -#include "theoraplay/theoraplay.h" +#ifndef MKXPZ_RETRO +# include "theoraplay/theoraplay.h" +#endif // MKXPZ_RETRO #include "util.h" #include "input.h" #include "sprite.h" -#include -#include -#include -#include -#include -#include +#ifndef MKXPZ_RETRO +# include +# include +# include +# include +# include +# include +#endif // MKXPZ_RETRO #ifdef MKXPZ_STEAM #include "steamshim_child.h" @@ -76,6 +80,7 @@ #define MOVIE_AUDIO_BUFFER_SIZE 2048 #define AUDIO_BUFFER_LEN_MS 2000 +#ifndef MKXPZ_RETRO typedef struct AudioQueue { const THEORAPLAY_AudioPacket *audio; @@ -437,6 +442,7 @@ struct MovieOpenHandler : FileSystem::OpenHandler return true; } }; +#endif // MKXPZ_RETRO struct PingPong { TEXFBO rt[2]; @@ -508,7 +514,9 @@ public: const int w = geometry.rect.w; const int h = geometry.rect.h; +#ifndef MKXPZ_RETRO shState->prepareDraw(); +#endif // MKXPZ_RETRO pp.startRender(); @@ -665,6 +673,7 @@ private: /* Nanoseconds per second */ #define NS_PER_S 1000000000 +#ifndef MKXPZ_RETRO struct FPSLimiter { uint64_t lastTickCount; @@ -774,6 +783,7 @@ private: #endif } }; +#endif // MKXPZ_RETRO struct GraphicsPrivate { /* Screen resolution, ie. the resolution at which @@ -800,7 +810,9 @@ struct GraphicsPrivate { ScreenScene screen; RGSSThreadData *threadData; +#ifndef MKXPZ_RETRO SDL_GLContext glCtx; +#endif // MKXPZ_RETRO int frameRate; int frameCount; @@ -809,7 +821,9 @@ struct GraphicsPrivate { double last_update; +#ifndef MKXPZ_RETRO FPSLimiter fpsLimiter; +#endif // MKXPZ_RETRO // Can be set from Ruby. Takes priority over config setting. bool useFrameSkip; @@ -827,9 +841,11 @@ struct GraphicsPrivate { std::vector avgFPSData; double last_avg_update; +#ifndef MKXPZ_RETRO SDL_mutex *avgFPSLock; SDL_mutex *glResourceLock; +#endif // MKXPZ_RETRO bool multithreadedMode; /* Global list of all live Disposables @@ -838,27 +854,58 @@ struct GraphicsPrivate { GraphicsPrivate(RGSSThreadData *rtData) : scResLores(DEF_SCREEN_W, DEF_SCREEN_H), +#ifdef MKXPZ_RETRO + scRes(DEF_SCREEN_W, DEF_SCREEN_H), // TODO: get from config +#else scRes(rtData->config.enableHires ? (int)lround(rtData->config.framebufferScalingFactor * DEF_SCREEN_W) : DEF_SCREEN_W, rtData->config.enableHires ? (int)lround(rtData->config.framebufferScalingFactor * DEF_SCREEN_H) : DEF_SCREEN_H), +#endif // MKXPZ_RETRO scSize(scRes), +#ifdef MKXPZ_RETRO + winSize(640, 480), // TODO: use actual screen size +#else winSize(rtData->config.defScreenW, rtData->config.defScreenH), +#endif // MKXPZ_RETRO screen(scRes.x, scRes.y), threadData(rtData), - glCtx(SDL_GL_GetCurrentContext()), multithreadedMode(true), +#ifndef MKXPZ_RETRO + glCtx(SDL_GL_GetCurrentContext()), +#endif // MKXPZ_RETRO + multithreadedMode(true), frameRate(DEF_FRAMERATE), frameCount(0), brightness(255), - fpsLimiter(frameRate), useFrameSkip(rtData->config.frameSkip), frozen(false), +#ifndef MKXPZ_RETRO + fpsLimiter(frameRate), +#endif // MKXPZ_RETRO +#ifdef MKXPZ_RETRO + useFrameSkip(false), // TODO: get from config +#else + useFrameSkip(rtData->config.frameSkip), +#endif // MKXPZ_RETRO + frozen(false), last_update(0), last_avg_update(0), backingScaleFactor(1), integerScaleFactor(0, 0), +#ifdef MKXPZ_RETRO + integerScaleActive(false), + integerLastMileScaling(false) +#else integerScaleActive(rtData->config.integerScaling.active), - integerLastMileScaling(rtData->config.integerScaling.lastMileScaling) { + integerLastMileScaling(rtData->config.integerScaling.lastMileScaling) +#endif // MKXPZ_RETRO +{ avgFPSData = std::vector(); +#ifndef MKXPZ_RETRO avgFPSLock = SDL_CreateMutex(); glResourceLock = SDL_CreateMutex(); +#endif // MKXPZ_RETRO if (integerScaleActive) { integerScaleFactor = Vec2i(0, 0); rebuildIntegerScaleBuffer(); } +#ifdef MKXPZ_RETRO + recalculateScreenSize(true); // TODO: get from config +#else recalculateScreenSize(rtData->config.fixedAspectRatio); +#endif // MKXPZ_RETRO updateScreenResoRatio(rtData); TEXFBO::init(frozenScene); @@ -868,22 +915,28 @@ struct GraphicsPrivate { FloatRect screenRect(0, 0, scRes.x, scRes.y); screenQuad.setTexPosRect(screenRect, screenRect); +#ifndef MKXPZ_RETRO fpsLimiter.resetFrameAdjust(); +#endif // MKXPZ_RETRO } ~GraphicsPrivate() { TEXFBO::fini(frozenScene); TEXFBO::fini(integerScaleBuffer); +#ifndef MKXPZ_RETRO SDL_DestroyMutex(avgFPSLock); SDL_DestroyMutex(glResourceLock); +#endif // MKXPZ_RETRO } void updateScreenResoRatio(RGSSThreadData *rtData) { +#ifndef MKXPZ_RETRO Vec2 &ratio = rtData->sizeResoRatio; ratio.x = (float)scRes.x / scSize.x * backingScaleFactor; ratio.y = (float)scRes.y / scSize.y * backingScaleFactor; rtData->screenOffset = scOffset / backingScaleFactor; +#endif // MKXPZ_RETRO } /* Enforces fixed aspect ratio, if desired */ @@ -966,6 +1019,7 @@ struct GraphicsPrivate { } void checkResize(bool skipIntScaleBuffer = false) { +#ifndef MKXPZ_RETRO if (threadData->windowSizeMsg.poll(winSize)) { /* Query the actual size in pixels, not units */ Vec2i drawableSize(winSize); @@ -987,6 +1041,7 @@ struct GraphicsPrivate { SDL_Rect screen = {scOffset.x, scOffset.y, scSize.x, scSize.y}; threadData->ethread->notifyGameScreenChange(screen); } +#endif // MKXPZ_RETRO } void checkShutDownReset() { @@ -1002,12 +1057,16 @@ struct GraphicsPrivate { } void swapGLBuffer() { +#ifndef MKXPZ_RETRO fpsLimiter.delay(); SDL_GL_SwapWindow(threadData->window); +#endif // MKXPZ_RETRO ++frameCount; +#ifndef MKXPZ_RETRO threadData->ethread->notifyFrame(); +#endif // MKXPZ_RETRO } void compositeToBuffer(TEXFBO &buffer) { @@ -1113,6 +1172,7 @@ struct GraphicsPrivate { } void checkSyncLock() { +#ifndef MKXPZ_RETRO if (!threadData->syncPoint.mainSyncLocked()) return; @@ -1124,46 +1184,60 @@ struct GraphicsPrivate { SDL_GL_MakeCurrent(threadData->window, glCtx); fpsLimiter.resetFrameAdjust(); +#endif // MKXPZ_RETRO } double averageFPS() { double ret = 0; +#ifndef MKXPZ_RETRO SDL_LockMutex(avgFPSLock); +#endif // MKXPZ_RETRO for (double times : avgFPSData) ret += times; ret = 1 / (ret / avgFPSData.size()); +#ifndef MKXPZ_RETRO SDL_UnlockMutex(avgFPSLock); +#endif // MKXPZ_RETRO return ret; } void setLock(bool force = false) { if (!(force || multithreadedMode)) return; +#ifndef MKXPZ_RETRO SDL_LockMutex(glResourceLock); SDL_GL_MakeCurrent(threadData->window, threadData->glContext); +#endif // MKXPZ_RETRO } void releaseLock(bool force = false) { if (!(force || multithreadedMode)) return; +#ifndef MKXPZ_RETRO SDL_UnlockMutex(glResourceLock); +#endif // MKXPZ_RETRO } void updateAvgFPS() { +#ifndef MKXPZ_RETRO SDL_LockMutex(avgFPSLock); +#endif // MKXPZ_RETRO if (avgFPSData.size() > 40) avgFPSData.erase(avgFPSData.begin()); double time = shState->runTime(); avgFPSData.push_back(time - last_avg_update); last_avg_update = time; +#ifndef MKXPZ_RETRO SDL_UnlockMutex(avgFPSLock); +#endif // MKXPZ_RETRO } }; Graphics::Graphics(RGSSThreadData *data) { p = new GraphicsPrivate(data); +#ifndef MKXPZ_RETRO if (data->config.syncToRefreshrate) { p->frameRate = data->refreshRate; p->fpsLimiter.disabled = true; @@ -1172,6 +1246,7 @@ Graphics::Graphics(RGSSThreadData *data) { } else if (data->config.fixedFramerate < 0) { p->fpsLimiter.disabled = true; } +#endif // MKXPZ_RETRO } Graphics::~Graphics() { delete p; } @@ -1185,6 +1260,7 @@ double Graphics::lastUpdate() { } void Graphics::update(bool checkForShutdown) { +#ifndef MKXPZ_RETRO p->threadData->rqWindowAdjust.wait(); p->last_update = shState->runTime(); @@ -1226,6 +1302,7 @@ void Graphics::update(bool checkForShutdown) { } p->checkResize(); +#endif // MKXPZ_RETRO p->redrawScreen(); } @@ -1292,6 +1369,7 @@ void Graphics::transition(int duration, const char *filename, int vague) { glState.blend.pushSet(false); for (int i = 0; i < duration; ++i) { +#ifndef MKXPZ_RETRO /* We need to clean up transMap properly before * a possible longjmp, so we manually test for * shutdown/reset here */ @@ -1308,6 +1386,7 @@ void Graphics::transition(int duration, const char *filename, int vague) { scriptBinding->reset(); return; } +#endif // MKXPZ_RETRO p->checkSyncLock(); @@ -1352,7 +1431,11 @@ void Graphics::transition(int duration, const char *filename, int vague) { p->frozen = false; } -void Graphics::frameReset() {p->fpsLimiter.resetFrameAdjust();} +void Graphics::frameReset() { +#ifndef MKXPZ_RETRO + p->fpsLimiter.resetFrameAdjust(); +#endif // MKXPZ_RETRO +} static void guardDisposed() {} @@ -1369,7 +1452,9 @@ void Graphics::setFrameRate(int value) { if (p->threadData->config.fixedFramerate > 0) return; +#ifndef MKXPZ_RETRO p->fpsLimiter.setDesiredFPS(p->frameRate); +#endif // MKXPZ_RETRO //shState->input().recalcRepeat((unsigned int)p->frameRate); } @@ -1441,6 +1526,7 @@ void Graphics::fadein(int duration) { Bitmap *Graphics::snapToBitmap() { p->screen.composite(); +#ifndef MKXPZ_RETRO if (shState->config().enableHires) { // TODO: Maybe don't reconstruct this struct every time? TEXFBO tf; @@ -1450,6 +1536,7 @@ Bitmap *Graphics::snapToBitmap() { return new Bitmap(tf); } +#endif // MKXPZ_RETRO return new Bitmap(p->screen.getPP().frontBuffer()); } @@ -1475,28 +1562,40 @@ int Graphics::displayContentHeight() const { } int Graphics::displayWidth() const { +#ifdef MKXPZ_RETRO + return 640; // TODO: use actual width +#else SDL_DisplayMode dm{}; SDL_GetCurrentDisplayMode(SDL_GetWindowDisplayIndex(shState->sdlWindow()), &dm); return dm.w / p->backingScaleFactor; +#endif // MKXPZ_RETRO } int Graphics::displayHeight() const { +#ifdef MKXPZ_RETRO + return 480; // TODO: use actual height +#else SDL_DisplayMode dm{}; SDL_GetCurrentDisplayMode(SDL_GetWindowDisplayIndex(shState->sdlWindow()), &dm); return dm.h / p->backingScaleFactor; +#endif // MKXPZ_RETRO } void Graphics::resizeScreen(int width, int height) { +#ifndef MKXPZ_RETRO p->threadData->rqWindowAdjust.wait(); +#endif // MKXPZ_RETRO p->checkResize(true); Vec2i sizeLores(width, height); +#ifndef MKXPZ_RETRO if (shState->config().enableHires) { double framebufferScalingFactor = shState->config().framebufferScalingFactor; width = (int)lround(framebufferScalingFactor * width); height = (int)lround(framebufferScalingFactor * height); } +#endif // MKXPZ_RETRO Vec2i size(width, height); @@ -1518,28 +1617,39 @@ void Graphics::resizeScreen(int width, int height) { glState.scissorBox.set(IntRect(0, 0, p->scRes.x, p->scRes.y)); +#ifndef MKXPZ_RETRO shState->eThread().requestWindowResize(width, height); +#endif // MKXPZ_RETRO } void Graphics::resizeWindow(int width, int height, bool center) { +#ifndef MKXPZ_RETRO p->threadData->rqWindowAdjust.wait(); +#endif // MKXPZ_RETRO p->checkResize(); if (width == p->winSize.x / p->backingScaleFactor && height == p->winSize.y / p->backingScaleFactor) return; +#ifndef MKXPZ_RETRO shState->eThread().requestWindowResize(width, height); +#endif // MKXPZ_RETRO if (center) this->center(); } bool Graphics::updateMovieInput(Movie *movie) { +#ifdef MKXPZ_RETRO + return false; // TODO +#else return p->threadData->rqTerm || p->threadData->rqReset; +#endif // MKXPZ_RETRO } void Graphics::playMovie(const char *filename, int volume_, bool skippable) { +#ifndef MKXPZ_RETRO if (shState->config().enableHires) { Debug() << "BUG: High-res Graphics playMovie not implemented"; } @@ -1572,10 +1682,13 @@ void Graphics::playMovie(const char *filename, int volume_, bool skippable) { } delete movie; +#endif // MKXPZ_RETRO } void Graphics::screenshot(const char *filename) { +#ifndef MKXPZ_RETRO p->threadData->rqWindowAdjust.wait(); +#endif // MKXPZ_RETRO Bitmap *ss = snapToBitmap(); ss->saveToFile(filename); ss->dispose(); @@ -1606,55 +1719,81 @@ void Graphics::reset() { p->dispList.clear(); /* Reset attributes (frame count not included) */ +#ifndef MKXPZ_RETRO p->fpsLimiter.resetFrameAdjust(); +#endif // MKXPZ_RETRO p->frozen = false; p->screen.getPP().clearBuffers(); setFrameRate(DEF_FRAMERATE); setBrightness(255); +#ifndef MKXPZ_RETRO // Always update at least once to clear the screen if (p->threadData->rqResetFinish) +#endif // MKXPZ_RETRO update(); +#ifndef MKXPZ_RETRO else repaintWait(p->threadData->rqResetFinish, false); p->threadData->rqReset.clear(); +#endif // MKXPZ_RETRO } void Graphics::center() { +#ifndef MKXPZ_RETRO p->threadData->rqWindowAdjust.wait(); if (getFullscreen()) return; p->threadData->ethread->requestWindowCenter(); +#endif // MKXPZ_RETRO } bool Graphics::getFullscreen() const { +#ifdef MKXPZ_RETRO + return false; // TODO +#else return p->threadData->ethread->getFullscreen(); +#endif // MKXPZ_RETRO } void Graphics::setFullscreen(bool value) { +#ifndef MKXPZ_RETRO p->threadData->ethread->requestFullscreenMode(value); +#endif // MKXPZ_RETRO } bool Graphics::getShowCursor() const { +#ifdef MKXPZ_RETRO + return true; // TODO +#else return p->threadData->ethread->getShowCursor(); +#endif // MKXPZ_RETRO } void Graphics::setShowCursor(bool value) { +#ifndef MKXPZ_RETRO p->threadData->ethread->requestShowCursor(value); +#endif // MKXPZ_RETRO } bool Graphics::getFixedAspectRatio() const { // It's a bit hacky to expose config values as a Graphics // attribute, but there's really no point in state duplication +#ifdef MKXPZ_RETRO + return true; // TODO: get from config +#else return shState->config().fixedAspectRatio; +#endif // MKXPZ_RETRO } void Graphics::setFixedAspectRatio(bool value) { +#ifndef MKXPZ_RETRO shState->config().fixedAspectRatio = value; +#endif // MKXPZ_RETRO p->recalculateScreenSize(p->threadData->config.fixedAspectRatio); p->findHighestIntegerScale(); p->recalculateScreenSize(p->threadData->config.fixedAspectRatio); @@ -1664,12 +1803,18 @@ void Graphics::setFixedAspectRatio(bool value) int Graphics::getSmoothScaling() const { // Same deal as with fixed aspect ratio +#ifdef MKXPZ_RETRO + return 0; // TODO: get from config +#else return shState->config().smoothScaling; +#endif // MKXPZ_RETRO } void Graphics::setSmoothScaling(int value) { +#ifndef MKXPZ_RETRO shState->config().smoothScaling = value; +#endif // MKXPZ_RETRO } bool Graphics::getIntegerScaling() const @@ -1716,7 +1861,9 @@ double Graphics::getScale() const { } void Graphics::setScale(double factor) { +#ifndef MKXPZ_RETRO p->threadData->rqWindowAdjust.wait(); +#endif // MKXPZ_RETRO factor = clamp(factor, 0.5, 4.0); if (factor == getScale()) @@ -1725,7 +1872,9 @@ void Graphics::setScale(double factor) { int widthpx = p->scRes.x * factor; int heightpx = p->scRes.y * factor; +#ifndef MKXPZ_RETRO shState->eThread().requestWindowResize(widthpx, heightpx); +#endif // MKXPZ_RETRO } bool Graphics::getFrameskip() const { return p->useFrameSkip; } @@ -1754,10 +1903,12 @@ void Graphics::repaintWait(const AtomicFlag &exitCond, bool checkReset) { FBO::clear(); p->metaBlitBufferFlippedScaled(scaleIsSpecial); +#ifndef MKXPZ_RETRO SDL_GL_SwapWindow(p->threadData->window); p->fpsLimiter.delay(); p->threadData->ethread->notifyFrame(); +#endif // MKXPZ_RETRO } GLMeta::blitEnd(); diff --git a/src/sharedstate.cpp b/src/sharedstate.cpp index d1fc888c..53a67566 100644 --- a/src/sharedstate.cpp +++ b/src/sharedstate.cpp @@ -82,8 +82,8 @@ struct SharedStatePrivate #endif // MKXPZ_RETRO SharedMidiState midiState; -#ifndef MKXPZ_RETRO Graphics graphics; +#ifndef MKXPZ_RETRO Input input; Audio audio; #endif // MKXPZ_RETRO @@ -127,8 +127,8 @@ struct SharedStatePrivate #else midiState(threadData->config), #endif // MKXPZ_RETRO -#ifndef MKXPZ_RETRO graphics(threadData), +#ifndef MKXPZ_RETRO input(*threadData), audio(*threadData), #endif // MKXPZ_RETRO @@ -276,7 +276,9 @@ GSATT(FileSystem&, fileSystem) GSATT(EventThread&, eThread) GSATT(RGSSThreadData&, rtData) GSATT(Config&, config) +#endif // MKXPZ_RETRO GSATT(Graphics&, graphics) +#ifndef MKXPZ_RETRO GSATT(Input&, input) GSATT(Audio&, audio) #endif // MKXPZ_RETRO @@ -435,11 +437,7 @@ SharedState::SharedState(RGSSThreadData *threadData) try { p->init(threadData); -#ifdef MKXPZ_RETRO - p->screen = new Scene(); // TODO: implement -#else p->screen = p->graphics.getScreen(); -#endif // MKXPZ_RETRO } catch (const Exception &exc) { diff --git a/src/util/sdl-util.h b/src/util/sdl-util.h index 2f0fa345..900f9f64 100644 --- a/src/util/sdl-util.h +++ b/src/util/sdl-util.h @@ -9,6 +9,37 @@ #include #include +#ifdef MKXPZ_RETRO +struct AtomicFlag +{ + AtomicFlag() : atom(false) {} + + void set() + { + atom = true; + } + + void clear() + { + atom = false; + } + + void wait() {} + + void reset() + { + set(); + } + + operator bool() const + { + return atom; + } + +private: + mutable bool atom; +}; +#else struct AtomicFlag { AtomicFlag() @@ -45,6 +76,7 @@ struct AtomicFlag private: mutable SDL_atomic_t atom; }; +#endif // MKXPZ_RETRO template int __sdlThreadFun(void *obj)