Allow independent upscale/downscale interpolation methods

This commit is contained in:
Splendide Imaginarius 2024-03-21 02:07:12 +00:00
parent d4c20d7720
commit ebcb0e2486
7 changed files with 98 additions and 56 deletions

View file

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

View file

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

View file

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

View file

@ -140,7 +140,7 @@ void vaoUnbind(VAO &vao)
#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 targetHeight = targetRect.h;
@ -166,10 +166,33 @@ bool blitScaleIsOne(TEXFBO &target, bool targetPreferHires, const IntRect &targe
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)
{
@ -181,7 +204,7 @@ static void _blitBegin(FBO::ID fbo, const Vec2i &size, bool scaleIsOne)
FBO::bind(fbo);
glState.viewport.pushSet(IntRect(0, 0, size.x, size.y));
switch (scaleIsOne ? NearestNeighbor : shState->config().smoothScaling)
switch (smoothScalingMethod(scaleIsSpecial))
{
case Bicubic:
{
@ -239,7 +262,7 @@ int blitSrcWidthHires = 1;
int blitSrcHeightLores = 1;
int blitSrcHeightHires = 1;
void blitBegin(TEXFBO &target, bool preferHires, bool scaleIsOne)
void blitBegin(TEXFBO &target, bool preferHires, int scaleIsSpecial)
{
blitDstWidthLores = target.width;
blitDstHeightLores = target.height;
@ -247,26 +270,26 @@ void blitBegin(TEXFBO &target, bool preferHires, bool scaleIsOne)
if (preferHires && target.selfHires != nullptr) {
blitDstWidthHires = target.selfHires->width;
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 {
blitDstWidthHires = blitDstWidthLores;
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;
blitDstWidthHires = 1;
blitDstHeightLores = 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;
blitSrcHeightLores = source.height;
@ -285,7 +308,7 @@ void blitSource(TEXFBO &source, bool scaleIsOne)
}
else
{
switch (scaleIsOne ? NearestNeighbor : shState->config().smoothScaling)
switch (smoothScalingMethod(scaleIsSpecial))
{
case Bicubic:
{

View file

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

View file

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

View file

@ -211,6 +211,14 @@ enum InterpolationMethod
#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.
* All drawable classes have properties of one or more of the above
* types, which in an interpreted environment act as independent