- OUTPUT: Fix aspect ratio correction for Direct3D and OpenGL output modes, fix default window sizing for aspect correction, fix 'jumpy' behavior during window resizing with aspect ratio correction

- OUTPUT: Offload aspect ratio correction for Direct3D and OpenGL output modes from render code (these modes do it themselves)
- xBRZ: Also offload it when xBRZ scaler is enabled (xBRZ does not like line duplication and can do correction itself)
- OUTPUT: Store source aspect ratio translation parameters under 'sdl' structure, this may be used eventually for non-square pixel monitors aspect ratio correction
- xBRZ: Make sure xBRZ scaler honors aspect ratio correction flag in 'surface' mode of operation and controls aspect ratio correction offload when enabling/disabling itself
- xBRZ: Factor out scaling factor setup into its own function
- xBRZ: Fix up duplicated code path breaking 'surface' output
- MAIN: Split 'overlay' mode defaulting from primary 'if' set, making it simply choosing D3D/OGL/surface before primary 'if' goes
- DOC: README.xbrz
- DOC: clarify that SDL structure is initialized to zero in code comment, initialize defaults after memset()
This commit is contained in:
Alex/AT 2018-06-28 18:58:15 +03:00
parent b15fe3aaee
commit b0b406d8e5
4 changed files with 291 additions and 167 deletions

60
README.xbrz Normal file
View File

@ -0,0 +1,60 @@
xBRZ (https://sourceforge.net/projects/xbrz/) scaler is integrated into DOSBox-X.
To enable, use
scaler=xbrz
or
scaler=xbrz_bilinear
option in [render] section.
The difference between two options is in the post-scaling resize method.
xBRZ scaler uses fixed scale factors, 2X to 6X, which are usually not exactly
matching the display window. So nearest size xBRZ scaler output is then
resized (upscaled/dowscaled) using either nearest neighbor ('xbrz') or
bilinear ('xbrz_bilinear') algorithm to match the window size.
It is highly recommended to use 'direct3d' or any of the 'opengl' output modes
with xBRZ because bilinear post-scaler performance is terrible and nearest
neighbor post-scaler does not provide good results.
In 'direct3d' / 'opengl' output modes, there is no difference between
'xbrz' and 'xbrz_bilinear' variants, because software post-scaler is not used
and output is post-scaled by the output interface/hardware.
Differences from reference implementation on xBRZ site / in Daum build:
- DOSBox-X implementation supports 'surface', 'direct3d' and 'opengl' outputs
(including opengl variants 'openglnb' and 'openglhq')
- Windowed mode is fully working with xBRZ scaler enabled
- You can combine xBRZ with 'direct3d' mode post-scalers to get i.e. TV effect
- Enabling xBRZ scaler does not disable 'aspect' option, it is honored
Things to notice:
- The scaler is very CPU intensive so it will run with decent speed for
games and demos only on high-end CPUs. Keep this in mind. You can try
to correct performance for high output resolutions by using either
'xbrz fixed scale factor' or 'xbrz max scale factor' options to limit
xBRZ scale factor (lower factors improve performance), of course this
reduces image quality for higher output resolutions proportionally.
- Using 'direct3d' or 'opengl' mode actually improves performance a lot
because it gets rid of the software post-scaler pass.
- xBRZ scaler code uses parallel processing internally. There is also
'xbrz slice' option that affects parallelism, its default (16) gives
good results on 4-8 core CPUs.
- When xBRZ scaler is enabled, internal DOSBox scaler options are disabled
because any pre-scaling will break xBRZ algorithm. For the same very reason,
'doublescan' option is always turned off internally when xBRZ is enabled.
- When using xBRZ in 'surface' output mode and window/screen sizes less than
2x of the original DOS resolution, 'xbrz' scaler can degrade quality instead
of improving it, use 'direct3d'/'opengl' outputs or 'xbrz_bilinear' scaler
variant to avoid this.
Caveats / issues / things to do / incomplete:
- In case video adapter interface uses non-standard color scheme / byte order,
colors with xBRZ scaler enabled would most probably be garbled.
[YET TO REPRODUCE ANYWHERE]

View File

@ -93,6 +93,7 @@ typedef struct {
bool updating;
bool active;
bool aspect;
bool aspectOffload;
bool fullFrame;
bool forceUpdate;
bool autofit;

View File

@ -339,7 +339,9 @@ void RENDER_Reset( void ) {
Bitu gfx_flags, xscale, yscale;
ScalerSimpleBlock_t *simpleBlock = &ScaleNormal1x;
ScalerComplexBlock_t *complexBlock = 0;
if (render.aspect) {
gfx_scalew = 1;
gfx_scaleh = 1;
if (render.aspect && !render.aspectOffload) {
if (render.src.ratio>1.0) {
gfx_scalew = 1;
gfx_scaleh = render.src.ratio;
@ -347,9 +349,6 @@ void RENDER_Reset( void ) {
gfx_scalew = (1.0/render.src.ratio);
gfx_scaleh = 1;
}
} else {
gfx_scalew = 1;
gfx_scaleh = 1;
}
if ((dblh && dblw) || (render.scale.forced && !dblh && !dblw)) {
/* Initialize always working defaults */
@ -883,14 +882,12 @@ void RENDER_Init() {
#if C_XBRZ
if (render.scale.xBRZ) {
// xBRZ requirements
render.aspect = false;
vga.draw.doublescan_set = false;
}
#endif
render.autofit=section->Get_bool("autofit");
//If something changed that needs a ReInit
// Only ReInit when there is a src.bpp (fixes crashes on startup and directly changing the scaler without a screen specified yet)
if(running && render.src.bpp && ((render.aspect != aspect) || (render.scale.op != scaleOp) ||

View File

@ -474,6 +474,7 @@ CDirect3D* d3d = NULL;
# include <os2.h>
#endif
// do not specify any defaults inside, it is zeroed at start of main()
struct SDL_Block {
bool inited;
bool active; //If this isn't set don't draw
@ -571,18 +572,24 @@ struct SDL_Block {
bool must_redraw_all;
bool deferred_resize;
bool init_ignore;
unsigned int gfx_force_redraw_count = 0;
unsigned int gfx_force_redraw_count;
struct {
int x;
int y;
double xToY;
double yToX;
} srcAspect;
#if C_XBRZ
struct {
bool enable;
bool postscale_bilinear;
int task_granularity = 16;
int fixed_scale_factor = 0;
int max_scale_factor = xbrz::SCALE_FACTOR_MAX;
int task_granularity;
int fixed_scale_factor;
int max_scale_factor;
std::vector<uint32_t> renderbuf;
std::vector<uint32_t> pixbuf;
bool tex_scale_on;
int tex_scale_factor;
bool scale_on;
int scale_factor;
} xBRZ;
#endif
};
@ -1226,32 +1233,48 @@ static SDL_Surface * GFX_SetupSurfaceScaledOpenGL(Bit32u sdl_flags, Bit32u bpp)
sdl.clip.h=windowHeight=(Bit16u)Voodoo_OGL_GetHeight();
}
else if (fixedWidth && fixedHeight) {
if (render.aspect) {
double ratio_w=(double)fixedWidth/(sdl.draw.width*sdl.draw.scalex);
double ratio_h=(double)fixedHeight/(sdl.draw.height*sdl.draw.scaley);
sdl.clip.w = windowWidth = fixedWidth;
sdl.clip.h = windowHeight = fixedHeight;
if (ratio_w < ratio_h) {
sdl.clip.w=(Bit16u)fixedWidth;
sdl.clip.h=(Bit16u)floor((sdl.draw.height*sdl.draw.scaley*ratio_w)+0.5);
} else {
sdl.clip.w=(Bit16u)floor((sdl.draw.width*sdl.draw.scalex*ratio_h)+0.5);
sdl.clip.h=(Bit16u)fixedHeight;
// adjust resulting image aspect ratio
if (render.aspect) {
if (fixedWidth > sdl.srcAspect.xToY * fixedHeight) // output broader than input => black bars left and right
{
sdl.clip.w = static_cast<int>(fixedHeight * sdl.srcAspect.xToY);
}
else // black bars top and bottom
{
sdl.clip.h = static_cast<int>(fixedWidth * sdl.srcAspect.yToX);
}
}
else {
sdl.clip.w=fixedWidth;
sdl.clip.h=fixedHeight;
}
sdl.clip.x = (fixedWidth - sdl.clip.w) / 2;
sdl.clip.y = (fixedHeight - sdl.clip.h) / 2;
windowWidth = fixedWidth;
windowHeight = fixedHeight;
}
else {
sdl.clip.x=0;sdl.clip.y=0;
sdl.clip.w=windowWidth=(Bit16u)(sdl.draw.width*sdl.draw.scalex);
sdl.clip.h=windowHeight=(Bit16u)(sdl.draw.height*sdl.draw.scaley);
sdl.clip.w = windowWidth = (Bit16u)(sdl.draw.width*sdl.draw.scalex);
sdl.clip.h = windowHeight = (Bit16u)(sdl.draw.height*sdl.draw.scaley);
if (render.aspect) {
// we solve problem of aspect ratio based window extension here when window size is not set explicitly
if (windowWidth*sdl.srcAspect.y != windowHeight*sdl.srcAspect.x)
{
// abnormal aspect ratio detected, apply correction
if (windowWidth*sdl.srcAspect.y > windowHeight*sdl.srcAspect.x)
{
// wide pixel ratio, height should be extended to fit
sdl.clip.h = windowHeight = (Bitu)floor((double)windowWidth * sdl.srcAspect.y / sdl.srcAspect.x + 0.5);
}
else
{
// long pixel ratio, width should be extended
sdl.clip.w = windowWidth = (Bitu)floor((double)windowHeight * sdl.srcAspect.x / sdl.srcAspect.y + 0.5);
}
}
}
sdl.clip.x = (windowWidth - sdl.clip.w) / 2;
sdl.clip.y = (windowHeight - sdl.clip.h) / 2;
}
LOG(LOG_MISC,LOG_DEBUG)("GFX_SetSize OpenGL window=%ux%u clip=x,y,w,h=%d,%d,%d,%d",
@ -1760,6 +1783,36 @@ void GFX_DrawSDLMenu(DOSBoxMenu &menu,DOSBoxMenu::displaylist &dl) {
bool initedOpenGL = false;
#endif
#if C_XBRZ
// returns true if scaling possible/enabled, false otherwise
bool xBRZ_SetScaleParameters(int srcWidth, int srcHeight, int dstWidth, int dstHeight) {
sdl.xBRZ.scale_factor = (sdl.xBRZ.fixed_scale_factor == 0) ?
static_cast<int>(std::sqrt((double)dstWidth * dstHeight / (srcWidth * srcHeight)) + 0.5) :
sdl.xBRZ.fixed_scale_factor;
// enable minimal scaling if upscale is still possible but requires post-downscale
// having aspect ratio correction on always implies enabled scaler because it gives better quality than DOSBox own method
if (sdl.xBRZ.scale_factor == 1 && (render.aspect || dstWidth > srcWidth || dstHeight > srcHeight))
sdl.xBRZ.scale_factor = 2;
if (sdl.xBRZ.scale_factor >= 2)
{
// ok to scale, now clamp scale factor if corresponding max option is set
sdl.xBRZ.scale_factor = min(sdl.xBRZ.scale_factor, sdl.xBRZ.max_scale_factor);
sdl.xBRZ.scale_on = true;
}
else
{
// scaling impossible
sdl.xBRZ.scale_on = false;
}
return sdl.xBRZ.scale_on;
}
#endif
void RENDER_Reset(void);
Bitu GFX_SetSize(Bitu width,Bitu height,Bitu flags,double scalex,double scaley,GFX_CallBack_t callback) {
if (width == 0 || height == 0) {
E_Exit("GFX_SetSize with width=%d height=%d zero dimensions not allowed",(int)width,(int)height);
@ -1888,6 +1941,25 @@ dosurface:
}
#endif
// there is a small problem we need to solve here: aspect corrected windows can be smaller than needed due to source with non-4:3 pixel ratio
// if we detect non-4:3 pixel ratio here with aspect correction on, we correct it so original fits into resized window properly
if (render.aspect) {
if (width*sdl.srcAspect.y != height * sdl.srcAspect.x)
{
// abnormal aspect ratio detected, apply correction
if (width*sdl.srcAspect.y > height*sdl.srcAspect.x)
{
// wide pixel ratio, height should be extended to fit
height = (Bitu)floor((double)width * sdl.srcAspect.y / sdl.srcAspect.x + 0.5);
}
else
{
// long pixel ratio, width should be extended
width = (Bitu)floor((double)height * sdl.srcAspect.x / sdl.srcAspect.y + 0.5);
}
}
}
sdl.desktop.type=SCREEN_SURFACE;
sdl.clip.w=width;
sdl.clip.h=height;
@ -2048,6 +2120,34 @@ dosurface:
(Uint32)0u);
/* If this one fails be ready for some flickering... */
}
#if C_XBRZ
if (sdl.xBRZ.enable)
{
// pre-calculate scaling factor and adjust aspect rate correction offload state
int clipWidth = sdl.surface->w;
int clipHeight = sdl.surface->h;
if (render.aspect) {
if (clipWidth > sdl.srcAspect.xToY * clipHeight)
{
clipWidth = static_cast<int>(clipHeight * sdl.srcAspect.xToY);
}
else // black bars top and bottom
{
clipHeight = static_cast<int>(clipWidth * sdl.srcAspect.yToX);
}
}
xBRZ_SetScaleParameters(sdl.draw.width, sdl.draw.height, clipWidth, clipHeight);
if (sdl.xBRZ.scale_on != render.aspectOffload) {
// when we are scaling, we ask render code not to do any aspect correction
// when we are not scaling, render code is allowed to do aspect correction at will
render.aspectOffload = sdl.xBRZ.scale_on;
PIC_AddEvent(VGA_SetupDrawing, 50); // schedule another resize here, render has already been initialized at this point and we have just changed its option
}
}
#endif
}
#if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW
@ -2097,28 +2197,14 @@ dosurface:
//if (!(flags&GFX_CAN_32) || (flags & GFX_RGBONLY)) goto dosurface;
// we do the same as with Direct3D: precreate pixel buffer adjusted for xBRZ
Bitu adjTexWidth = width;
Bitu adjTexHeight = height;
Bitu adjTexWidth = sdl.draw.width;
Bitu adjTexHeight = sdl.draw.height;
#if C_XBRZ
if (sdl.xBRZ.enable)
// we do the same as with Direct3D: precreate pixel buffer adjusted for xBRZ
if (sdl.xBRZ.enable && xBRZ_SetScaleParameters(adjTexWidth, adjTexHeight, sdl.clip.w, sdl.clip.h))
{
sdl.xBRZ.tex_scale_factor = (sdl.xBRZ.fixed_scale_factor == 0) ?
static_cast<int>(std::sqrt(1.0 * sdl.clip.w * sdl.clip.h / (width * height)) + 0.5) :
sdl.xBRZ.fixed_scale_factor;
if (sdl.xBRZ.tex_scale_factor >= 2)
{
sdl.xBRZ.tex_scale_factor = min(sdl.xBRZ.tex_scale_factor, sdl.xBRZ.max_scale_factor);
adjTexWidth = width * sdl.xBRZ.tex_scale_factor;
adjTexHeight = height * sdl.xBRZ.tex_scale_factor;
sdl.xBRZ.tex_scale_on = true;
}
else
{
// we cannot scale, so do not even attempt to
sdl.xBRZ.tex_scale_on = false;
}
adjTexWidth = adjTexWidth * sdl.xBRZ.scale_factor;
adjTexHeight = adjTexHeight * sdl.xBRZ.scale_factor;
}
#endif
int texsize=2 << int_log2(adjTexWidth > adjTexHeight ? adjTexWidth : adjTexHeight);
@ -2334,21 +2420,18 @@ dosurface:
#endif
if (fixedWidth && fixedHeight) {
if (render.aspect) {
double ratio_w=(double)fixedWidth/(sdl.draw.width*sdl.draw.scalex);
double ratio_h=(double)fixedHeight/(sdl.draw.height*sdl.draw.scaley);
sdl.clip.w = fixedWidth;
sdl.clip.h = fixedHeight;
if (ratio_w < ratio_h) {
sdl.clip.w=(Bit16u)fixedWidth;
sdl.clip.h=(Bit16u)floor((sdl.draw.height*sdl.draw.scaley*ratio_w)+0.5);
} else {
sdl.clip.w=(Bit16u)floor((sdl.draw.width*sdl.draw.scalex*ratio_h)+0.5);
sdl.clip.h=(Bit16u)fixedHeight;
if (render.aspect) {
if (fixedWidth > sdl.srcAspect.xToY * fixedHeight) // output broader than input => black bars left and right
{
sdl.clip.w = static_cast<int>(fixedHeight * sdl.srcAspect.xToY);
}
else // black bars top and bottom
{
sdl.clip.h = static_cast<int>(fixedWidth * sdl.srcAspect.yToX);
}
}
else {
sdl.clip.w=fixedWidth;
sdl.clip.h=fixedHeight;
}
sdl.clip.x = (fixedWidth - sdl.clip.w) / 2;
@ -2357,30 +2440,34 @@ dosurface:
windowHeight = fixedHeight;
}
else {
sdl.clip.x=0;sdl.clip.y=0;
sdl.clip.w=windowWidth=(Bit16u)(sdl.draw.width*sdl.draw.scalex);
sdl.clip.h=windowHeight=(Bit16u)(sdl.draw.height*sdl.draw.scaley);
// we solve problem of aspect ratio based window extension here when window size is not set explicitly
if (windowWidth*sdl.srcAspect.y != windowHeight * sdl.srcAspect.x)
{
// abnormal aspect ratio detected, apply correction
if (windowWidth*sdl.srcAspect.y > windowHeight*sdl.srcAspect.x)
{
// wide pixel ratio, height should be extended to fit
sdl.clip.h = windowHeight = (Bitu)floor((double)windowWidth * sdl.srcAspect.y / sdl.srcAspect.x + 0.5);
}
else
{
// long pixel ratio, width should be extended
sdl.clip.w = windowWidth = (Bitu)floor((double)windowHeight * sdl.srcAspect.x / sdl.srcAspect.y + 0.5);
}
}
sdl.clip.x = (windowWidth - sdl.clip.w) / 2;
sdl.clip.y = (windowHeight - sdl.clip.h) / 2;
}
// when xBRZ scaler is used, we can adjust render target size to exactly what xBRZ scaler will output, leaving final scaling to default D3D scaler / shaders
#if C_XBRZ
if (sdl.xBRZ.enable) {
sdl.xBRZ.tex_scale_factor = (sdl.xBRZ.fixed_scale_factor == 0) ?
static_cast<int>(std::sqrt(1.0 * sdl.clip.w * sdl.clip.h / (width * height)) + 0.5) :
sdl.xBRZ.fixed_scale_factor;
if (sdl.xBRZ.tex_scale_factor >= 2)
{
sdl.xBRZ.tex_scale_factor = min(sdl.xBRZ.tex_scale_factor, sdl.xBRZ.max_scale_factor);
adjTexWidth = width * sdl.xBRZ.tex_scale_factor;
adjTexHeight = height * sdl.xBRZ.tex_scale_factor;
sdl.xBRZ.tex_scale_on = true;
}
else
{
// we cannot scale, so do not even attempt to
sdl.xBRZ.tex_scale_on = false;
}
if (sdl.xBRZ.enable && xBRZ_SetScaleParameters(width, height, sdl.clip.w, sdl.clip.h)) {
adjTexWidth = width * sdl.xBRZ.scale_factor;
adjTexHeight = height * sdl.xBRZ.scale_factor;
}
#endif
// Calculate texture size
@ -3218,7 +3305,7 @@ bool GFX_StartUpdate(Bit8u * & pixels,Bitu & pitch) {
switch (sdl.desktop.type) {
case SCREEN_SURFACE:
#if C_XBRZ
if (sdl.xBRZ.enable) {
if (sdl.xBRZ.enable && sdl.xBRZ.scale_on) {
sdl.xBRZ.renderbuf.resize(sdl.draw.width * sdl.draw.height);
pixels = sdl.xBRZ.renderbuf.empty() ? nullptr : reinterpret_cast<Bit8u*>(&sdl.xBRZ.renderbuf[0]);
pitch = sdl.draw.width * sizeof(uint32_t);
@ -3247,7 +3334,7 @@ bool GFX_StartUpdate(Bit8u * & pixels,Bitu & pitch) {
#if C_OPENGL
case SCREEN_OPENGL:
#if C_XBRZ
if (sdl.xBRZ.enable && sdl.xBRZ.tex_scale_on) {
if (sdl.xBRZ.enable && sdl.xBRZ.scale_on) {
sdl.xBRZ.renderbuf.resize(sdl.draw.width * sdl.draw.height);
pixels = sdl.xBRZ.renderbuf.empty() ? nullptr : reinterpret_cast<Bit8u*>(&sdl.xBRZ.renderbuf[0]);
pitch = sdl.draw.width * sizeof(uint32_t);
@ -3270,7 +3357,7 @@ bool GFX_StartUpdate(Bit8u * & pixels,Bitu & pitch) {
#if (HAVE_D3D9_H) && defined(WIN32)
case SCREEN_DIRECT3D:
#if C_XBRZ
if (sdl.xBRZ.enable && sdl.xBRZ.tex_scale_on) {
if (sdl.xBRZ.enable && sdl.xBRZ.scale_on) {
sdl.xBRZ.renderbuf.resize(sdl.draw.width * sdl.draw.height);
pixels = sdl.xBRZ.renderbuf.empty() ? nullptr : reinterpret_cast<Bit8u*>(&sdl.xBRZ.renderbuf[0]);
pitch = sdl.draw.width * sizeof(uint32_t);
@ -3373,67 +3460,43 @@ void GFX_EndUpdate( const Bit16u *changedLines ) {
GFX_DrawSDLMenu(mainMenu,mainMenu.display_list);
#endif
#if C_XBRZ
if (sdl.xBRZ.enable) {
if (sdl.xBRZ.enable && sdl.xBRZ.scale_on) {
const int srcWidth = sdl.draw.width;
const int srcHeight = sdl.draw.height;
if (sdl.xBRZ.renderbuf.size() == srcWidth * srcHeight && srcWidth > 0 && srcHeight > 0)
{
// we assume render buffer is *not* scaled!
const int outputHeight = sdl.surface->h; // in full screen mode surface == screen
const int outputWidth = sdl.surface->w;
// scale to full screen (preserving input aspect)
// aspectOutput = outputWidth / outputHeight;
int clipX = 0;
int clipY = 0;
const int outputHeight = sdl.surface->h;
const int outputWidth = sdl.surface->w;
int clipWidth = outputWidth;
int clipHeight = outputHeight;
// const double srcAspect = 1.0 * srcWidth / srcHeight;
const double srcAspect = 4.0 / 3;
int clipX = 0;
int clipY = 0;
if (outputWidth > srcAspect * outputHeight) // output broader than input => black bars left and right
{
clipWidth = static_cast<int>(outputHeight * srcAspect);
clipX = (outputWidth - clipWidth) / 2;
}
else // black bars top and bottom
{
clipHeight = static_cast<int>(outputWidth / srcAspect);
clipY = (outputHeight - clipHeight) / 2;
if (render.aspect) {
if (outputWidth > sdl.srcAspect.xToY * outputHeight) // output broader than input => black bars left and right
{
clipWidth = static_cast<int>(outputHeight * sdl.srcAspect.xToY);
clipX = (outputWidth - clipWidth) / 2;
}
else // black bars top and bottom
{
clipHeight = static_cast<int>(outputWidth * sdl.srcAspect.yToX);
clipY = (outputHeight - clipHeight) / 2;
}
}
// 1. xBRZ-scale render buffer into xbrz pixel buffer
int scalingFactor = (sdl.xBRZ.fixed_scale_factor == 0) ?
static_cast<int>(std::sqrt(1.0 * clipWidth * clipHeight / (srcWidth * srcHeight)) + 0.5) :
sdl.xBRZ.fixed_scale_factor;
// the ideal scaling factor scales source image to have roughly similar pixel count like target
int xbrzWidth = 0;
int xbrzHeight = 0;
uint32_t* xbrzBuf;
if (scalingFactor >= 2)
{
scalingFactor = min(scalingFactor, sdl.xBRZ.max_scale_factor);
xbrzWidth = srcWidth * sdl.xBRZ.scale_factor;
xbrzHeight = srcHeight * sdl.xBRZ.scale_factor;
sdl.xBRZ.pixbuf.resize(xbrzWidth * xbrzHeight);
xbrzWidth = srcWidth * scalingFactor;
xbrzHeight = srcHeight * scalingFactor;
sdl.xBRZ.pixbuf.resize(xbrzWidth * xbrzHeight);
const uint32_t* renderBuf = &sdl.xBRZ.renderbuf[0]; // help VS compiler a little + support capture by value
xbrzBuf = &sdl.xBRZ.pixbuf[0];
xBRZ_Render(renderBuf, xbrzBuf, changedLines, srcWidth, srcHeight, scalingFactor);
}
else // no scaling
{
xbrzWidth = srcWidth;
xbrzHeight = srcHeight;
xbrzBuf = &sdl.xBRZ.renderbuf[0];
// don't change aspect when showing unscaled image:
clipWidth = min(srcWidth, outputWidth);
clipHeight = min(srcHeight, outputHeight);
clipX = (outputWidth - clipWidth) / 2;
clipY = (outputHeight - clipHeight) / 2;
}
const uint32_t* renderBuf = &sdl.xBRZ.renderbuf[0]; // help VS compiler a little + support capture by value
xbrzBuf = &sdl.xBRZ.pixbuf[0];
xBRZ_Render(renderBuf, xbrzBuf, changedLines, srcWidth, srcHeight, sdl.xBRZ.scale_factor);
// 2. nearest neighbor/bilinear scale xbrz buffer into output surface clipping area
const bool mustLock = SDL_MUSTLOCK(sdl.surface);
@ -3505,25 +3568,6 @@ void GFX_EndUpdate( const Bit16u *changedLines ) {
#if !defined(C_SDL2)
if (changedLines != NULL) SDL_Flip(sdl.surface);
#endif
} else if (changedLines) {
if(changedLines[0] == sdl.draw.height)
return;
if(!menu.hidecycles && !sdl.desktop.fullscreen) frames++;
Bitu y = 0, index = 0, rectCount = 0;
while (y < sdl.draw.height) {
if (!(index & 1)) {
y += changedLines[index];
} else {
SDL_Rect *rect = &sdl.updateRects[rectCount++];
rect->x = sdl.clip.x;
rect->y = (unsigned int)sdl.clip.y + (unsigned int)y;
rect->w = (Bit16u)sdl.draw.width;
rect->h = changedLines[index];
y += changedLines[index];
SDL_rect_cliptoscreen(*rect);
}
index++;
}
} else if (changedLines) {
if (changedLines[0] == sdl.draw.height)
return;
@ -3574,7 +3618,7 @@ void GFX_EndUpdate( const Bit16u *changedLines ) {
}
#if C_XBRZ
if (sdl.xBRZ.enable && sdl.xBRZ.tex_scale_on) {
if (sdl.xBRZ.enable && sdl.xBRZ.scale_on) {
// OpenGL pixel buffer is precreated for direct xBRZ output, while xBRZ render buffer is used for rendering
const int srcWidth = sdl.draw.width;
const int srcHeight = sdl.draw.height;
@ -3592,7 +3636,7 @@ void GFX_EndUpdate( const Bit16u *changedLines ) {
trgTex = reinterpret_cast<uint32_t*>(static_cast<void*>(sdl.opengl.framebuf));
if (trgTex)
xBRZ_Render(renderBuf, trgTex, changedLines, srcWidth, srcHeight, sdl.xBRZ.tex_scale_factor);
xBRZ_Render(renderBuf, trgTex, changedLines, srcWidth, srcHeight, sdl.xBRZ.scale_factor);
}
// and here we go repeating some stuff with xBRZ related modifications
@ -3601,7 +3645,7 @@ void GFX_EndUpdate( const Bit16u *changedLines ) {
glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT);
glBindTexture(GL_TEXTURE_2D, sdl.opengl.texture);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
sdl.draw.width * sdl.xBRZ.tex_scale_factor, sdl.draw.height * sdl.xBRZ.tex_scale_factor, GL_BGRA_EXT,
sdl.draw.width * sdl.xBRZ.scale_factor, sdl.draw.height * sdl.xBRZ.scale_factor, GL_BGRA_EXT,
GL_UNSIGNED_INT_8_8_8_8_REV, 0);
glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_EXT, 0);
}
@ -3609,7 +3653,7 @@ void GFX_EndUpdate( const Bit16u *changedLines ) {
{
glBindTexture(GL_TEXTURE_2D, sdl.opengl.texture);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
sdl.draw.width * sdl.xBRZ.tex_scale_factor, sdl.draw.height * sdl.xBRZ.tex_scale_factor, GL_BGRA_EXT,
sdl.draw.width * sdl.xBRZ.scale_factor, sdl.draw.height * sdl.xBRZ.scale_factor, GL_BGRA_EXT,
#if defined (MACOSX)
// needed for proper looking graphics on macOS 10.12, 10.13
GL_UNSIGNED_INT_8_8_8_8,
@ -3710,23 +3754,20 @@ void GFX_EndUpdate( const Bit16u *changedLines ) {
#if (HAVE_D3D9_H) && defined(WIN32)
case SCREEN_DIRECT3D:
#if C_XBRZ
if (sdl.xBRZ.enable && sdl.xBRZ.tex_scale_on) {
if (sdl.xBRZ.enable && sdl.xBRZ.scale_on) {
// we have xBRZ pseudo render buffer to be output to the pre-sized texture, do the xBRZ part
const int srcWidth = sdl.draw.width;
const int srcHeight = sdl.draw.height;
if (sdl.xBRZ.renderbuf.size() == srcWidth * srcHeight && srcWidth > 0 && srcHeight > 0)
{
// we assume render buffer is *not* scaled!
const int outputHeight = sdl.surface->h; // in full screen mode surface == screen
const int outputWidth = sdl.surface->w;
int xbrzWidth = srcWidth * sdl.xBRZ.tex_scale_factor;
int xbrzHeight = srcHeight * sdl.xBRZ.tex_scale_factor;
int xbrzWidth = srcWidth * sdl.xBRZ.scale_factor;
int xbrzHeight = srcHeight * sdl.xBRZ.scale_factor;
sdl.xBRZ.pixbuf.resize(xbrzWidth * xbrzHeight);
const uint32_t* renderBuf = &sdl.xBRZ.renderbuf[0]; // help VS compiler a little + support capture by value
uint32_t* xbrzBuf = &sdl.xBRZ.pixbuf[0];
xBRZ_Render(renderBuf, xbrzBuf, changedLines, srcWidth, srcHeight, sdl.xBRZ.tex_scale_factor);
xBRZ_Render(renderBuf, xbrzBuf, changedLines, srcWidth, srcHeight, sdl.xBRZ.scale_factor);
// now copy xBRZ buffer to the texture, adjusting for texture pitch
Bit8u *tgtPix;
@ -4064,6 +4105,9 @@ static void GUI_StartUp() {
/* Setup Mouse correctly if fullscreen */
if(sdl.desktop.fullscreen) GFX_CaptureMouse();
// pre-set render aspect offload to false, altered by using xBRZ scaler or Direct3D/OpenGL modes that do aspect correction themselves and don't need render code to mess with it
render.aspectOffload = false;
#if C_XBRZ
// yes, we read render section settings here, because xBRZ is integrated here but has settings in "render"
{
@ -4085,33 +4129,47 @@ static void GUI_StartUp() {
// xBRZ requirements
if ((output != "surface") && (output != "direct3d") && (output != "opengl") && (output != "openglhq") && (output != "openglnb"))
output = "surface";
render.aspectOffload = true; // render aspect ratio correction voids xBRZ algorithm, so scaler does aspect correction itself (and resorts to render code when no scaling is applied)
}
#endif
// output type selection
// "overlay" was removed, pre-map to Direct3D or OpenGL or surface
if (output == "overlay") {
#if (HAVE_D3D9_H) && defined(WIN32)
output = "direct3d";
#elif C_OPENGL
output = "opengl";
#else
output = "surface";
#endif
}
if (output == "surface") {
sdl.desktop.want_type=SCREEN_SURFACE;
} else if (output == "ddraw") {
sdl.desktop.want_type=SCREEN_SURFACE;
} else if (output == "overlay") {
sdl.desktop.want_type=SCREEN_OPENGL; /* "overlay" was removed, map to OpenGL */
#if C_OPENGL
} else if (output == "opengl" || output == "openglhq") {
sdl.desktop.want_type=SCREEN_OPENGL;
sdl.opengl.bilinear=true;
sdl.opengl.bilinear = true;
render.aspectOffload = true; // OpenGL code does aspect correction itself, we don't need render thread to do it
} else if (output == "openglnb") {
sdl.desktop.want_type=SCREEN_OPENGL;
sdl.opengl.bilinear=false;
sdl.opengl.bilinear = false;
render.aspectOffload = true; // OpenGL code does aspect correction itself, we don't need render thread to do it
#endif
#if (HAVE_D3D9_H) && defined(WIN32)
} else if (output == "direct3d") {
sdl.desktop.want_type=SCREEN_DIRECT3D;
render.aspectOffload = true; // Direct3D code does aspect correction itself, we don't need render thread to do it
#if LOG_D3D
LOG_MSG("SDL:Direct3D activated");
#endif
#endif
} else {
LOG_MSG("SDL:Unsupported output device %s, switching back to surface",output.c_str());
sdl.desktop.want_type=SCREEN_SURFACE;//SHOULDN'T BE POSSIBLE anymore
sdl.desktop.want_type=SCREEN_SURFACE; // SHOULDN'T BE POSSIBLE anymore
}
sdl.overscan_width=(unsigned int)section->Get_int("overscan");
// sdl.overscan_color=section->Get_int("overscancolor");
@ -5768,8 +5826,6 @@ static void HandleTouchscreenFinger(SDL_TouchFingerEvent * finger) {
}
#endif
void RENDER_Reset(void);
#if defined(WIN32) && !defined(C_SDL2) && !defined(HX_DOS)
void MSG_WM_COMMAND_handle(SDL_SysWMmsg &Message);
#endif
@ -7851,6 +7907,16 @@ int main(int argc, char* argv[]) SDL_MAIN_NOEXCEPT {
memset(&sdl,0,sizeof(sdl)); // struct sdl isn't initialized anywhere that I can tell
// initialize some defaults in SDL structure here
sdl.srcAspect.x = 4; sdl.srcAspect.y = 3;
sdl.srcAspect.xToY = (double)sdl.srcAspect.x / sdl.srcAspect.y;
sdl.srcAspect.yToX = (double)sdl.srcAspect.y / sdl.srcAspect.x;
#if C_XBRZ
sdl.xBRZ.task_granularity = 16;
sdl.xBRZ.max_scale_factor = xbrz::SCALE_FACTOR_MAX;
#endif
control=&myconf;
#if defined(WIN32) && !defined(HX_DOS)
/* Microsoft's IME does not play nice with DOSBox */