Graphics: PoC integer scaling

This commit is contained in:
Ancurio 2021-10-10 10:07:27 +02:00
parent a91acbe6ef
commit fb16c8e6d0
2 changed files with 126 additions and 5 deletions

View File

@ -477,6 +477,11 @@ struct GraphicsPrivate
TEXFBO frozenScene; TEXFBO frozenScene;
Quad screenQuad; Quad screenQuad;
Vec2i integerScaleFactor;
TEXFBO integerScaleBuffer;
bool integerScaleActive;
bool integerScaleFixedAspectRatio;
/* Global list of all live Disposables /* Global list of all live Disposables
* (disposed on reset) */ * (disposed on reset) */
IntruList<Disposable> dispList; IntruList<Disposable> dispList;
@ -492,7 +497,10 @@ struct GraphicsPrivate
frameCount(0), frameCount(0),
brightness(255), brightness(255),
fpsLimiter(frameRate), fpsLimiter(frameRate),
frozen(false) frozen(false),
integerScaleFactor(0, 0),
integerScaleActive(true),
integerScaleFixedAspectRatio(rtData->config.fixedAspectRatio)
{ {
recalculateScreenSize(rtData); recalculateScreenSize(rtData);
updateScreenResoRatio(rtData); updateScreenResoRatio(rtData);
@ -501,6 +509,12 @@ struct GraphicsPrivate
TEXFBO::allocEmpty(frozenScene, scRes.x, scRes.y); TEXFBO::allocEmpty(frozenScene, scRes.x, scRes.y);
TEXFBO::linkFBO(frozenScene); TEXFBO::linkFBO(frozenScene);
if (integerScaleActive)
{
integerScaleFactor = Vec2i(1, 1);
rebuildIntegerScaleBuffer();
}
FloatRect screenRect(0, 0, scRes.x, scRes.y); FloatRect screenRect(0, 0, scRes.x, scRes.y);
screenQuad.setTexPosRect(screenRect, screenRect); screenQuad.setTexPosRect(screenRect, screenRect);
@ -510,6 +524,7 @@ struct GraphicsPrivate
~GraphicsPrivate() ~GraphicsPrivate()
{ {
TEXFBO::fini(frozenScene); TEXFBO::fini(frozenScene);
TEXFBO::fini(integerScaleBuffer);
} }
void updateScreenResoRatio(RGSSThreadData *rtData) void updateScreenResoRatio(RGSSThreadData *rtData)
@ -544,15 +559,77 @@ struct GraphicsPrivate
scOffset.y = (winSize.y - scSize.y) / 2.f; scOffset.y = (winSize.y - scSize.y) / 2.f;
} }
static int findHighestFittingScale(int base, int target)
{
int scale = 1;
while (base * scale <= target)
scale += 1;
Debug() << base << target << scale - 1;
return scale - 1;
}
/* Returns whether a new scale was found */
bool findHighestIntegerScale()
{
Vec2i newScale(findHighestFittingScale(scRes.x, winSize.x),
findHighestFittingScale(scRes.y, winSize.y));
if (integerScaleFixedAspectRatio)
{
/* Limit both factors to the smaller of the two */
newScale.x = newScale.y = std::min(newScale.x, newScale.y);
}
if (newScale == integerScaleFactor)
return false;
integerScaleFactor = newScale;
Debug() << "Found new scale:" << newScale.x << newScale.y;
return true;
}
void rebuildIntegerScaleBuffer()
{
TEXFBO::fini(integerScaleBuffer);
TEXFBO::init(integerScaleBuffer);
TEXFBO::allocEmpty(integerScaleBuffer, scRes.x * integerScaleFactor.x,
scRes.y * integerScaleFactor.y);
TEXFBO::linkFBO(integerScaleBuffer);
Debug() << "New buffer size:" << integerScaleBuffer.width << integerScaleBuffer.height;
}
bool integerScaleStepApplicable() const
{
if (!integerScaleActive)
return false;
if (integerScaleFactor.x < 1 || integerScaleFactor.y < 1) // XXX should be < 2, this is for testing only
return false;
return true;
}
void checkResize() void checkResize()
{ {
if (threadData->windowSizeMsg.poll(winSize)) if (threadData->windowSizeMsg.poll(winSize))
{ {
/* Query the acutal size in pixels, not units */
SDL_GL_GetDrawableSize(threadData->window, &winSize.x, &winSize.y);
Debug() << "Reported GL drawable size:" << winSize.x << winSize.y;
/* some GL drivers change the viewport on window resize */ /* some GL drivers change the viewport on window resize */
glState.viewport.refresh(); glState.viewport.refresh();
recalculateScreenSize(threadData); recalculateScreenSize(threadData);
updateScreenResoRatio(threadData); updateScreenResoRatio(threadData);
if (integerScaleActive)
if (findHighestIntegerScale())
rebuildIntegerScaleBuffer();
SDL_Rect screen = { scOffset.x, scOffset.y, scSize.x, scSize.y }; SDL_Rect screen = { scOffset.x, scOffset.y, scSize.x, scSize.y };
threadData->ethread->notifyGameScreenChange(screen); threadData->ethread->notifyGameScreenChange(screen);
} }
@ -600,7 +677,12 @@ struct GraphicsPrivate
void metaBlitBufferFlippedScaled() void metaBlitBufferFlippedScaled()
{ {
GLMeta::blitRectangle(IntRect(0, 0, scRes.x, scRes.y), metaBlitBufferFlippedScaled(scRes);
}
void metaBlitBufferFlippedScaled(const Vec2i &sourceSize)
{
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),
threadData->config.smoothScaling); threadData->config.smoothScaling);
} }
@ -609,11 +691,36 @@ struct GraphicsPrivate
{ {
screen.composite(); screen.composite();
GLMeta::blitBeginScreen(winSize); if (integerScaleStepApplicable())
{
assert(integerScaleBuffer.tex != TEX::ID(0));
GLMeta::blitBegin(integerScaleBuffer);
GLMeta::blitSource(screen.getPP().frontBuffer()); GLMeta::blitSource(screen.getPP().frontBuffer());
GLMeta::blitRectangle(IntRect(0, 0, scRes.x, scRes.y),
IntRect(0, 0, integerScaleBuffer.width, integerScaleBuffer.height),
false);
GLMeta::blitEnd();
}
GLMeta::blitBeginScreen(winSize);
Vec2i sourceSize;
if (integerScaleActive)
{
GLMeta::blitSource(integerScaleBuffer);
sourceSize = Vec2i(integerScaleBuffer.width, integerScaleBuffer.height);
}
else
{
GLMeta::blitSource(screen.getPP().frontBuffer());
sourceSize = scRes;
}
FBO::clear(); FBO::clear();
metaBlitBufferFlippedScaled(); metaBlitBufferFlippedScaled(sourceSize);
GLMeta::blitEnd(); GLMeta::blitEnd();

View File

@ -41,6 +41,10 @@
#include "binding.h" #include "binding.h"
#ifdef __WINDOWS__ #ifdef __WINDOWS__
#include <windows.h>
#include <shellscalingapi.h>
#include <comdef.h>
#include "resource.h" #include "resource.h"
// Try to force dedicated GPU // Try to force dedicated GPU
@ -204,6 +208,16 @@ int main(int argc, char *argv[])
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
// SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0"); // SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
#ifdef __WINDOWS__
SetProcessDPIAware();
// HRESULT hr = SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
// if (FAILED(hr))
// {
// _com_error err(hr);
// fwprintf(stderr, L"SetProcessDpiAwareness: %s\n", err.ErrorMessage());
// }
#endif
/* initialize SDL first */ /* initialize SDL first */
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0)
{ {
@ -276,7 +290,7 @@ int main(int argc, char *argv[])
} }
SDL_Window *win; SDL_Window *win;
Uint32 winFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_INPUT_FOCUS; Uint32 winFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_ALLOW_HIGHDPI;
if (conf.winResizable) if (conf.winResizable)
winFlags |= SDL_WINDOW_RESIZABLE; winFlags |= SDL_WINDOW_RESIZABLE;