Merge pull request #175 from Splendide-Imaginarius/mkxp-z-downscale

Allow independent upscale/downscale interpolation methods
This commit is contained in:
Splendide Imaginarius 2024-03-21 03:50:33 +00:00 committed by GitHub
commit 487cde38db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 98 additions and 56 deletions

View file

@ -89,8 +89,15 @@
// "smoothScaling": 0, // "smoothScaling": 0,
// Apply smooth interpolation when game screen
// is downscaled (same values as smoothScaling)
// (default: 0)
//
// "smoothScalingDown": 0,
// Apply mipmap interpolation when game screen // Apply mipmap interpolation when game screen
// is downscaled // is downscaled (requires "smoothScalingDown": 1)
// (default: false) // (default: false)
// //
// "smoothScalingMipmaps": false, // "smoothScalingMipmaps": false,

View file

@ -135,6 +135,7 @@ void Config::read(int argc, char *argv[]) {
{"fullscreen", false}, {"fullscreen", false},
{"fixedAspectRatio", true}, {"fixedAspectRatio", true},
{"smoothScaling", 0}, {"smoothScaling", 0},
{"smoothScalingDown", 0},
{"smoothScalingMipmaps", false}, {"smoothScalingMipmaps", false},
{"bicubicSharpness", 100}, {"bicubicSharpness", 100},
#ifdef MKXPZ_SSL #ifdef MKXPZ_SSL
@ -270,6 +271,7 @@ try { exp } catch (...) {}
SET_OPT(fullscreen, boolean); SET_OPT(fullscreen, boolean);
SET_OPT(fixedAspectRatio, boolean); SET_OPT(fixedAspectRatio, boolean);
SET_OPT(smoothScaling, integer); SET_OPT(smoothScaling, integer);
SET_OPT(smoothScalingDown, integer);
SET_OPT(smoothScalingMipmaps, boolean); SET_OPT(smoothScalingMipmaps, boolean);
SET_OPT(bicubicSharpness, integer); SET_OPT(bicubicSharpness, integer);
#ifdef MKXPZ_SSL #ifdef MKXPZ_SSL

View file

@ -44,6 +44,7 @@ struct Config {
bool fullscreen; bool fullscreen;
bool fixedAspectRatio; bool fixedAspectRatio;
int smoothScaling; int smoothScaling;
int smoothScalingDown;
bool smoothScalingMipmaps; bool smoothScalingMipmaps;
int bicubicSharpness; int bicubicSharpness;
#ifdef MKXPZ_SSL #ifdef MKXPZ_SSL

View file

@ -140,7 +140,7 @@ void vaoUnbind(VAO &vao)
#define HAVE_NATIVE_BLIT gl.BlitFramebuffer #define HAVE_NATIVE_BLIT gl.BlitFramebuffer
bool blitScaleIsOne(TEXFBO &target, bool targetPreferHires, const IntRect &targetRect, TEXFBO &source, const IntRect &sourceRect) int blitScaleIsSpecial(TEXFBO &target, bool targetPreferHires, const IntRect &targetRect, TEXFBO &source, const IntRect &sourceRect)
{ {
int targetWidth = targetRect.w; int targetWidth = targetRect.w;
int targetHeight = targetRect.h; int targetHeight = targetRect.h;
@ -166,10 +166,33 @@ bool blitScaleIsOne(TEXFBO &target, bool targetPreferHires, const IntRect &targe
sourceHeight /= source.height; sourceHeight /= source.height;
} }
return targetWidth == sourceWidth && targetHeight == sourceHeight; if (targetWidth == sourceWidth && targetHeight == sourceHeight)
{
return SameScale;
}
if (targetWidth < sourceWidth && targetHeight < sourceHeight)
{
return DownScale;
}
return UpScale;
} }
static void _blitBegin(FBO::ID fbo, const Vec2i &size, bool scaleIsOne) int smoothScalingMethod(int scaleIsSpecial)
{
switch (scaleIsSpecial)
{
case SameScale:
return NearestNeighbor;
case DownScale:
return shState->config().smoothScalingDown;
}
return shState->config().smoothScaling;
}
static void _blitBegin(FBO::ID fbo, const Vec2i &size, int scaleIsSpecial)
{ {
if (HAVE_NATIVE_BLIT) if (HAVE_NATIVE_BLIT)
{ {
@ -181,7 +204,7 @@ static void _blitBegin(FBO::ID fbo, const Vec2i &size, bool scaleIsOne)
FBO::bind(fbo); FBO::bind(fbo);
glState.viewport.pushSet(IntRect(0, 0, size.x, size.y)); glState.viewport.pushSet(IntRect(0, 0, size.x, size.y));
switch (scaleIsOne ? NearestNeighbor : shState->config().smoothScaling) switch (smoothScalingMethod(scaleIsSpecial))
{ {
case Bicubic: case Bicubic:
{ {
@ -239,7 +262,7 @@ int blitSrcWidthHires = 1;
int blitSrcHeightLores = 1; int blitSrcHeightLores = 1;
int blitSrcHeightHires = 1; int blitSrcHeightHires = 1;
void blitBegin(TEXFBO &target, bool preferHires, bool scaleIsOne) void blitBegin(TEXFBO &target, bool preferHires, int scaleIsSpecial)
{ {
blitDstWidthLores = target.width; blitDstWidthLores = target.width;
blitDstHeightLores = target.height; blitDstHeightLores = target.height;
@ -247,26 +270,26 @@ void blitBegin(TEXFBO &target, bool preferHires, bool scaleIsOne)
if (preferHires && target.selfHires != nullptr) { if (preferHires && target.selfHires != nullptr) {
blitDstWidthHires = target.selfHires->width; blitDstWidthHires = target.selfHires->width;
blitDstHeightHires = target.selfHires->height; blitDstHeightHires = target.selfHires->height;
_blitBegin(target.selfHires->fbo, Vec2i(target.selfHires->width, target.selfHires->height), scaleIsOne); _blitBegin(target.selfHires->fbo, Vec2i(target.selfHires->width, target.selfHires->height), scaleIsSpecial);
} }
else { else {
blitDstWidthHires = blitDstWidthLores; blitDstWidthHires = blitDstWidthLores;
blitDstHeightHires = blitDstHeightLores; blitDstHeightHires = blitDstHeightLores;
_blitBegin(target.fbo, Vec2i(target.width, target.height), scaleIsOne); _blitBegin(target.fbo, Vec2i(target.width, target.height), scaleIsSpecial);
} }
} }
void blitBeginScreen(const Vec2i &size, bool scaleIsOne) void blitBeginScreen(const Vec2i &size, int scaleIsSpecial)
{ {
blitDstWidthLores = 1; blitDstWidthLores = 1;
blitDstWidthHires = 1; blitDstWidthHires = 1;
blitDstHeightLores = 1; blitDstHeightLores = 1;
blitDstHeightHires = 1; blitDstHeightHires = 1;
_blitBegin(FBO::ID(0), size, scaleIsOne); _blitBegin(FBO::ID(0), size, scaleIsSpecial);
} }
void blitSource(TEXFBO &source, bool scaleIsOne) void blitSource(TEXFBO &source, int scaleIsSpecial)
{ {
blitSrcWidthLores = source.width; blitSrcWidthLores = source.width;
blitSrcHeightLores = source.height; blitSrcHeightLores = source.height;
@ -285,7 +308,7 @@ void blitSource(TEXFBO &source, bool scaleIsOne)
} }
else else
{ {
switch (scaleIsOne ? NearestNeighbor : shState->config().smoothScaling) switch (smoothScalingMethod(scaleIsSpecial))
{ {
case Bicubic: case Bicubic:
{ {

View file

@ -65,10 +65,11 @@ void vaoBind(VAO &vao);
void vaoUnbind(VAO &vao); void vaoUnbind(VAO &vao);
/* EXT_framebuffer_blit */ /* EXT_framebuffer_blit */
bool blitScaleIsOne(TEXFBO &target, bool targetPreferHires, const IntRect &targetRect, TEXFBO &source, const IntRect &sourceRect); int blitScaleIsSpecial(TEXFBO &target, bool targetPreferHires, const IntRect &targetRect, TEXFBO &source, const IntRect &sourceRect);
void blitBegin(TEXFBO &target, bool preferHires = false, bool scaleIsOne = false); int smoothScalingMethod(int scaleIsSpecial);
void blitBeginScreen(const Vec2i &size, bool scaleIsOne = false); void blitBegin(TEXFBO &target, bool preferHires = false, int scaleIsOne = 0);
void blitSource(TEXFBO &source, bool scaleIsOne = false); void blitBeginScreen(const Vec2i &size, int scaleIsOne = 0);
void blitSource(TEXFBO &source, int scaleIsOne = 0);
void blitRectangle(const IntRect &src, const Vec2i &dstPos); void blitRectangle(const IntRect &src, const Vec2i &dstPos);
void blitRectangle(const IntRect &src, const IntRect &dst, void blitRectangle(const IntRect &src, const IntRect &dst,
bool smooth = false); bool smooth = false);

View file

@ -543,10 +543,10 @@ public:
* be turned on, so turn it off temporarily */ * be turned on, so turn it off temporarily */
glState.scissorTest.pushSet(false); glState.scissorTest.pushSet(false);
bool scaleIsOne = GLMeta::blitScaleIsOne(pp.frontBuffer(), false, geometry.rect, pp.backBuffer(), geometry.rect); int scaleIsSpecial = GLMeta::blitScaleIsSpecial(pp.frontBuffer(), false, geometry.rect, pp.backBuffer(), geometry.rect);
GLMeta::blitBegin(pp.frontBuffer(), false, scaleIsOne); GLMeta::blitBegin(pp.frontBuffer(), false, scaleIsSpecial);
GLMeta::blitSource(pp.backBuffer(), scaleIsOne); GLMeta::blitSource(pp.backBuffer(), scaleIsSpecial);
GLMeta::blitRectangle(geometry.rect, Vec2i()); GLMeta::blitRectangle(geometry.rect, Vec2i());
GLMeta::blitEnd(); GLMeta::blitEnd();
@ -1011,29 +1011,29 @@ struct GraphicsPrivate {
void compositeToBufferScaled(TEXFBO &buffer, int destWidth, int destHeight) { void compositeToBufferScaled(TEXFBO &buffer, int destWidth, int destHeight) {
screen.composite(); screen.composite();
bool scaleIsOne = GLMeta::blitScaleIsOne(buffer, false, IntRect(0, 0, destWidth, destHeight), screen.getPP().frontBuffer(), IntRect(0, 0, scRes.x, scRes.y)); int scaleIsSpecial = GLMeta::blitScaleIsSpecial(buffer, false, IntRect(0, 0, destWidth, destHeight), screen.getPP().frontBuffer(), IntRect(0, 0, scRes.x, scRes.y));
GLMeta::blitBegin(buffer, false, scaleIsOne); GLMeta::blitBegin(buffer, false, scaleIsSpecial);
GLMeta::blitSource(screen.getPP().frontBuffer(), scaleIsOne); GLMeta::blitSource(screen.getPP().frontBuffer(), scaleIsSpecial);
GLMeta::blitRectangle(IntRect(0, 0, scRes.x, scRes.y), IntRect(0, 0, destWidth, destHeight)); GLMeta::blitRectangle(IntRect(0, 0, scRes.x, scRes.y), IntRect(0, 0, destWidth, destHeight));
GLMeta::blitEnd(); GLMeta::blitEnd();
} }
void metaBlitBufferFlippedScaled() { void metaBlitBufferFlippedScaled(int scaleIsSpecial) {
metaBlitBufferFlippedScaled(scRes); metaBlitBufferFlippedScaled(scRes, scaleIsSpecial);
GLMeta::blitRectangle( GLMeta::blitRectangle(
IntRect(0, 0, scRes.x, scRes.y), IntRect(0, 0, scRes.x, scRes.y),
IntRect(scOffset.x, IntRect(scOffset.x,
(scSize.y + scOffset.y), (scSize.y + scOffset.y),
scSize.x, scSize.x,
-scSize.y), -scSize.y),
threadData->config.smoothScaling == Bilinear); GLMeta::smoothScalingMethod(scaleIsSpecial) == Bilinear);
} }
void metaBlitBufferFlippedScaled(const Vec2i &sourceSize, bool forceNearestNeighbor=false) { void metaBlitBufferFlippedScaled(const Vec2i &sourceSize, int scaleIsSpecial, bool forceNearestNeighbor=false) {
GLMeta::blitRectangle(IntRect(0, 0, sourceSize.x, sourceSize.y), GLMeta::blitRectangle(IntRect(0, 0, sourceSize.x, sourceSize.y),
IntRect(scOffset.x, scSize.y+scOffset.y, scSize.x, -scSize.y), IntRect(scOffset.x, scSize.y+scOffset.y, scSize.x, -scSize.y),
!forceNearestNeighbor && threadData->config.smoothScaling == Bilinear); !forceNearestNeighbor && GLMeta::smoothScalingMethod(scaleIsSpecial) == Bilinear);
} }
void redrawScreen() { void redrawScreen() {
@ -1042,13 +1042,13 @@ struct GraphicsPrivate {
// maybe unspaghetti this later // maybe unspaghetti this later
if (integerScaleStepApplicable() && !integerLastMileScaling) if (integerScaleStepApplicable() && !integerLastMileScaling)
{ {
bool scaleIsOne = GLMeta::blitScaleIsOne(integerScaleBuffer, false, IntRect(0, 0, scSize.x, scSize.y), screen.getPP().frontBuffer(), IntRect(0, 0, scRes.x, scRes.y)); int scaleIsSpecial = GLMeta::blitScaleIsSpecial(integerScaleBuffer, false, IntRect(0, 0, scSize.x, scSize.y), screen.getPP().frontBuffer(), IntRect(0, 0, scRes.x, scRes.y));
GLMeta::blitBeginScreen(winSize, scaleIsOne); GLMeta::blitBeginScreen(winSize, scaleIsSpecial);
GLMeta::blitSource(screen.getPP().frontBuffer(), scaleIsOne); GLMeta::blitSource(screen.getPP().frontBuffer(), scaleIsSpecial);
FBO::clear(); FBO::clear();
metaBlitBufferFlippedScaled(scRes, true); metaBlitBufferFlippedScaled(scRes, scaleIsSpecial, true);
GLMeta::blitEnd(); GLMeta::blitEnd();
swapGLBuffer(); swapGLBuffer();
@ -1057,11 +1057,11 @@ struct GraphicsPrivate {
if (integerScaleStepApplicable()) if (integerScaleStepApplicable())
{ {
bool scaleIsOne = GLMeta::blitScaleIsOne(integerScaleBuffer, false, IntRect(0, 0, integerScaleBuffer.width, integerScaleBuffer.height), screen.getPP().frontBuffer(), IntRect(0, 0, scRes.x, scRes.y)); int scaleIsSpecial = GLMeta::blitScaleIsSpecial(integerScaleBuffer, false, IntRect(0, 0, integerScaleBuffer.width, integerScaleBuffer.height), screen.getPP().frontBuffer(), IntRect(0, 0, scRes.x, scRes.y));
assert(integerScaleBuffer.tex != TEX::ID(0)); assert(integerScaleBuffer.tex != TEX::ID(0));
GLMeta::blitBegin(integerScaleBuffer, false, scaleIsOne); GLMeta::blitBegin(integerScaleBuffer, false, scaleIsSpecial);
GLMeta::blitSource(screen.getPP().frontBuffer(), scaleIsOne); GLMeta::blitSource(screen.getPP().frontBuffer(), scaleIsSpecial);
GLMeta::blitRectangle(IntRect(0, 0, scRes.x, scRes.y), GLMeta::blitRectangle(IntRect(0, 0, scRes.x, scRes.y),
IntRect(0, 0, integerScaleBuffer.width, integerScaleBuffer.height), IntRect(0, 0, integerScaleBuffer.width, integerScaleBuffer.height),
@ -1082,22 +1082,22 @@ struct GraphicsPrivate {
sourceSize = scRes; sourceSize = scRes;
} }
bool scaleIsOne = GLMeta::blitScaleIsOne(integerScaleBuffer, false, IntRect(0, 0, scSize.x, scSize.y), integerScaleActive ? integerScaleBuffer : screen.getPP().frontBuffer(), IntRect(0, 0, sourceSize.x, sourceSize.y)); int scaleIsSpecial = GLMeta::blitScaleIsSpecial(integerScaleBuffer, false, IntRect(0, 0, scSize.x, scSize.y), integerScaleActive ? integerScaleBuffer : screen.getPP().frontBuffer(), IntRect(0, 0, sourceSize.x, sourceSize.y));
GLMeta::blitBeginScreen(winSize, scaleIsOne); GLMeta::blitBeginScreen(winSize, scaleIsSpecial);
//GLMeta::blitSource(screen.getPP().frontBuffer(), scaleIsOne); //GLMeta::blitSource(screen.getPP().frontBuffer(), scaleIsSpecial);
if (integerScaleActive) if (integerScaleActive)
{ {
GLMeta::blitSource(integerScaleBuffer, scaleIsOne); GLMeta::blitSource(integerScaleBuffer, scaleIsSpecial);
} }
else else
{ {
GLMeta::blitSource(screen.getPP().frontBuffer(), scaleIsOne); GLMeta::blitSource(screen.getPP().frontBuffer(), scaleIsSpecial);
} }
FBO::clear(); FBO::clear();
metaBlitBufferFlippedScaled(sourceSize); metaBlitBufferFlippedScaled(sourceSize, scaleIsSpecial);
GLMeta::blitEnd(); GLMeta::blitEnd();
@ -1327,11 +1327,11 @@ void Graphics::transition(int duration, const char *filename, int vague) {
FBO::unbind(); FBO::unbind();
FBO::clear(); FBO::clear();
bool scaleIsOne = GLMeta::blitScaleIsOne(p->integerScaleBuffer, false, IntRect(0, 0, p->scSize.x, p->scSize.y), transBuffer, IntRect(0, 0, p->scRes.x, p->scRes.y)); int scaleIsSpecial = GLMeta::blitScaleIsSpecial(p->integerScaleBuffer, false, IntRect(0, 0, p->scSize.x, p->scSize.y), transBuffer, IntRect(0, 0, p->scRes.x, p->scRes.y));
GLMeta::blitBeginScreen(Vec2i(p->winSize), scaleIsOne); GLMeta::blitBeginScreen(Vec2i(p->winSize), scaleIsSpecial);
GLMeta::blitSource(transBuffer, scaleIsOne); GLMeta::blitSource(transBuffer, scaleIsSpecial);
p->metaBlitBufferFlippedScaled(); p->metaBlitBufferFlippedScaled(scaleIsSpecial);
GLMeta::blitEnd(); GLMeta::blitEnd();
p->swapGLBuffer(); p->swapGLBuffer();
@ -1388,13 +1388,13 @@ void Graphics::fadeout(int duration) {
setBrightness(diff + (curr / duration) * i); setBrightness(diff + (curr / duration) * i);
if (p->frozen) { if (p->frozen) {
bool scaleIsOne = GLMeta::blitScaleIsOne(p->integerScaleBuffer, false, IntRect(0, 0, p->scSize.x, p->scSize.y), p->frozenScene, IntRect(0, 0, p->scRes.x, p->scRes.y)); int scaleIsSpecial = GLMeta::blitScaleIsSpecial(p->integerScaleBuffer, false, IntRect(0, 0, p->scSize.x, p->scSize.y), p->frozenScene, IntRect(0, 0, p->scRes.x, p->scRes.y));
GLMeta::blitBeginScreen(p->scSize, scaleIsOne); GLMeta::blitBeginScreen(p->scSize, scaleIsSpecial);
GLMeta::blitSource(p->frozenScene, scaleIsOne); GLMeta::blitSource(p->frozenScene, scaleIsSpecial);
FBO::clear(); FBO::clear();
p->metaBlitBufferFlippedScaled(); p->metaBlitBufferFlippedScaled(scaleIsSpecial);
GLMeta::blitEnd(); GLMeta::blitEnd();
@ -1415,13 +1415,13 @@ void Graphics::fadein(int duration) {
setBrightness(curr + (diff / duration) * i); setBrightness(curr + (diff / duration) * i);
if (p->frozen) { if (p->frozen) {
bool scaleIsOne = GLMeta::blitScaleIsOne(p->integerScaleBuffer, false, IntRect(0, 0, p->scSize.x, p->scSize.y), p->frozenScene, IntRect(0, 0, p->scRes.x, p->scRes.y)); int scaleIsSpecial = GLMeta::blitScaleIsSpecial(p->integerScaleBuffer, false, IntRect(0, 0, p->scSize.x, p->scSize.y), p->frozenScene, IntRect(0, 0, p->scRes.x, p->scRes.y));
GLMeta::blitBeginScreen(p->scSize, scaleIsOne); GLMeta::blitBeginScreen(p->scSize, scaleIsSpecial);
GLMeta::blitSource(p->frozenScene, scaleIsOne); GLMeta::blitSource(p->frozenScene, scaleIsSpecial);
FBO::clear(); FBO::clear();
p->metaBlitBufferFlippedScaled(); p->metaBlitBufferFlippedScaled(scaleIsSpecial);
GLMeta::blitEnd(); GLMeta::blitEnd();
@ -1726,10 +1726,10 @@ void Graphics::repaintWait(const AtomicFlag &exitCond, bool checkReset) {
/* Repaint the screen with the last good frame we drew */ /* Repaint the screen with the last good frame we drew */
TEXFBO &lastFrame = p->screen.getPP().frontBuffer(); TEXFBO &lastFrame = p->screen.getPP().frontBuffer();
bool scaleIsOne = GLMeta::blitScaleIsOne(p->integerScaleBuffer, false, IntRect(0, 0, p->scSize.x, p->scSize.y), lastFrame, IntRect(0, 0, p->scRes.x, p->scRes.y)); int scaleIsSpecial = GLMeta::blitScaleIsSpecial(p->integerScaleBuffer, false, IntRect(0, 0, p->scSize.x, p->scSize.y), lastFrame, IntRect(0, 0, p->scRes.x, p->scRes.y));
GLMeta::blitBeginScreen(p->winSize, scaleIsOne); GLMeta::blitBeginScreen(p->winSize, scaleIsSpecial);
GLMeta::blitSource(lastFrame, scaleIsOne); GLMeta::blitSource(lastFrame, scaleIsSpecial);
while (!exitCond) { while (!exitCond) {
shState->checkShutdown(); shState->checkShutdown();
@ -1738,7 +1738,7 @@ void Graphics::repaintWait(const AtomicFlag &exitCond, bool checkReset) {
shState->checkReset(); shState->checkReset();
FBO::clear(); FBO::clear();
p->metaBlitBufferFlippedScaled(); p->metaBlitBufferFlippedScaled(scaleIsSpecial);
SDL_GL_SwapWindow(p->threadData->window); SDL_GL_SwapWindow(p->threadData->window);
p->fpsLimiter.delay(); p->fpsLimiter.delay();

View file

@ -211,6 +211,14 @@ enum InterpolationMethod
#endif #endif
}; };
enum SpecialScale
{
// If the X and Y scales would yield different results, it's considered UpScale.
UpScale = 0,
SameScale = 1,
DownScale = 2,
};
/* For internal use. /* For internal use.
* All drawable classes have properties of one or more of the above * All drawable classes have properties of one or more of the above
* types, which in an interpreted environment act as independent * types, which in an interpreted environment act as independent