implement openglpp output

This commit is contained in:
Anton Shepelev 2021-01-19 23:36:35 -05:00 committed by Wengier
parent ebb3e54243
commit 5e5d7d1bf4
9 changed files with 161 additions and 61 deletions

View File

@ -1,4 +1,9 @@
0.83.10
- DOSBox-X now natively supports the pixel-perfect
scaling! Set output=openglpp in [sdl] section to
enable this output. Alternatively, the output can
be selected from the menu ("Video" => "Output" =>
"OpenGL perfect") at run-time. (ant_222 & Wengier)
- Added abliity to resolve file paths that include
environment variables on Windows or tildes (~) on
other platforms for various options in the config
@ -61,7 +66,9 @@
"config -set ttf.cols=100". (Wengier)
- You can now supply a ZIP/7Z file as a parameter to
DOSBox-X directly so that it will be mounted as C:
drive when DOSBox-X starts. (Wengeir)
drive when DOSBox-X starts. (Wengier)
- Fixed the DOSBox-X window size when restoring from
a maximized window in SDL2 builds. (Wengier)
- Fixed Ctrl+C not working in GNU ed. (Wengier)
- Fixed large ISO images (>2GB) unable to be mounted
using IMGMOUNT command. (Wengier)

View File

@ -124,6 +124,7 @@ struct SDL_Block {
bool prevent_fullscreen = false;
bool lazy_fullscreen_req = false;
bool doublebuf = false;
bool isperfect = false;
SCREEN_TYPES type = (SCREEN_TYPES)0;
SCREEN_TYPES want_type = (SCREEN_TYPES)0;
} desktop;

View File

@ -1361,7 +1361,7 @@ void DOSBOX_SetupConfigSections(void) {
const char* switchoutputs[] = {
"auto", "surface",
#if C_OPENGL
"opengl", "openglnb", "openglhq",
"opengl", "openglnb", "openglhq", "openglpp",
#endif
#if C_DIRECT3D
"direct3d",
@ -2317,7 +2317,8 @@ void DOSBOX_SetupConfigSections(void) {
Pmulti->Set_help("Scaler used to enlarge/enhance low resolution modes. If 'forced' is appended,\n"
"then the scaler will be used even if the result might not be desired.\n"
"To fit a scaler in the resolution used at full screen may require a border or side bars.\n"
"To fill the screen entirely, depending on your hardware, a different scaler/fullresolution might work.");
"To fill the screen entirely, depending on your hardware, a different scaler/fullresolution might work.\n"
"Scalers should work with most output options, but they are ignored for openglpp and TrueType font output.");
Pmulti->SetBasic(true);
Pstring = Pmulti->GetSection()->Add_string("type",Property::Changeable::Always,"normal2x");
Pstring->Set_values(scalers);

View File

@ -325,6 +325,7 @@ static const char *def_menu_video_output[] =
#if defined(C_OPENGL) && !defined(HX_DOS)
"output_opengl",
"output_openglnb",
"output_openglpp",
#endif
#if defined(USE_TTF)
"output_ttf",

View File

@ -469,6 +469,9 @@ void RENDER_Reset( void ) {
}
}
if( sdl.desktop.isperfect ) /* Handle scaling if no pixel-perfect mode */
goto forcenormal;
if ((dblh && dblw) || (render.scale.forced && dblh == dblw/*this branch works best with equal scaling in both directions*/)) {
/* Initialize always working defaults */
if (render.scale.size == 2)
@ -576,7 +579,8 @@ void RENDER_Reset( void ) {
else
simpleBlock = &ScaleNormalDh;
}
} else {
}
if( simpleBlock == NULL && complexBlock == NULL ) {
forcenormal:
complexBlock = 0;
if(scalerOpGray==render.scale.op){

View File

@ -3541,11 +3541,13 @@ void OUTPUT_TTF_Select(int fsize=-1) {
const char *outputstr=render_section->Get_string("ttf.outputswitch");
#if C_DIRECT3D
if (!strcasecmp(outputstr, "direct3d"))
switchoutput = 5;
switchoutput = 6;
else
#endif
#if C_OPENGL
if (!strcasecmp(outputstr, "openglnb"))
if (!strcasecmp(outputstr, "openglpp"))
switchoutput = 5;
else if (!strcasecmp(outputstr, "openglnb"))
switchoutput = 4;
else if (!strcasecmp(outputstr, "opengl")||!strcasecmp(outputstr, "openglnq"))
switchoutput = 3;
@ -3679,6 +3681,7 @@ void change_output(int output) {
Section_prop * section=static_cast<Section_prop *>(sec);
sdl.overscan_width=(unsigned int)section->Get_int("overscan");
UpdateOverscanMenu();
sdl.desktop.isperfect = false; /* Reset before selection */
switch (output) {
case 0:
@ -3692,37 +3695,41 @@ void change_output(int output) {
case 3:
#if C_OPENGL
change_output(2);
OUTPUT_OPENGL_Select();
sdl_opengl.bilinear = true;
OUTPUT_OPENGL_Select(GLBilinear);
#endif
break;
case 4:
#if C_OPENGL
change_output(2);
OUTPUT_OPENGL_Select();
sdl_opengl.bilinear = false; //NB
OUTPUT_OPENGL_Select(GLNearest);
#endif
break;
#if C_DIRECT3D
case 5:
#if C_OPENGL
change_output(2);
OUTPUT_OPENGL_Select(GLPerfect);
#endif
break;
#if C_DIRECT3D
case 6:
OUTPUT_DIRECT3D_Select();
break;
#endif
case 6:
break;
case 7:
// do not set want_type
break;
case 8:
// do not set want_type
break;
case 9:
#if C_DIRECT3D
if (sdl.desktop.want_type == SCREEN_DIRECT3D)
OUTPUT_DIRECT3D_Select();
#endif
break;
#if defined(USE_TTF)
case 9:
OUTPUT_TTF_Select();
case 10:
OUTPUT_TTF_Select();
case 11:
sdl.desktop.want_type = SCREEN_TTF;
ttf.inUse = true;
break;
@ -5201,7 +5208,7 @@ static void GUI_StartUp() {
if (sdl_xbrz.enable) {
// xBRZ requirements
if ((output != "surface") && (output != "direct3d") && (output != "opengl") && (output != "openglhq") && (output != "openglnb"))
if ((output != "surface") && (output != "direct3d") && (output != "opengl") && (output != "openglhq") && (output != "openglnb") && (output != "openglpp"))
output = "surface";
}
#endif
@ -5219,6 +5226,8 @@ static void GUI_StartUp() {
#endif
}
// FIXME: this selection of output is duplicated in change_output:
sdl.desktop.isperfect = false; /* Reset before selection */
if (output == "surface")
{
OUTPUT_SURFACE_Select();
@ -5230,13 +5239,15 @@ static void GUI_StartUp() {
}
else if (output == "opengl" || output == "openglhq")
{
OUTPUT_OPENGL_Select();
sdl_opengl.bilinear = true;
OUTPUT_OPENGL_Select(GLBilinear);
}
else if (output == "openglnb")
{
OUTPUT_OPENGL_Select();
sdl_opengl.bilinear = false;
OUTPUT_OPENGL_Select(GLNearest);
}
else if (output == "openglpp")
{
OUTPUT_OPENGL_Select(GLPerfect);
#endif
#if C_DIRECT3D
}
@ -5568,6 +5579,10 @@ void GFX_HandleVideoResize(int width, int height) {
}
else {
UpdateWindowDimensions();
if (window_was_maximized && !menu.maxwindow) {
userResizeWindowWidth = currentWindowWidth==sdl.surface->w?0:(unsigned int)currentWindowWidth;
userResizeWindowHeight = currentWindowHeight==sdl.surface->h?0:(unsigned int)currentWindowHeight;
}
}
/* TODO: Only if FULLSCREEN_DESKTOP */
@ -6727,10 +6742,10 @@ void* GetSetSDLValue(int isget, std::string& target, void* setval) {
if (isget) return (void*) sdl.wait_on_error;
else sdl.wait_on_error = setval;
}
else if (target == "opengl.bilinear") {
else if (target == "opengl.kind") {
#if C_OPENGL
if (isget) return (void*) sdl_opengl.bilinear;
else sdl_opengl.bilinear = setval;
if (isget) return (void*) sdl_opengl.kind;
else sdl_opengl.kind = (GLKind)(intptr_t)setval;
#else
if (isget) return (void*) 0;
#endif
@ -7581,7 +7596,7 @@ void SDL_SetupConfigSection() {
const char* outputs[] = {
"default", "surface", "overlay",
#if C_OPENGL
"opengl", "openglnb", "openglhq",
"opengl", "openglnb", "openglhq", "openglpp",
#endif
"ddraw",
#if C_DIRECT3D
@ -10061,7 +10076,7 @@ bool overscan_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const men
sprintf(tmp,"%d",f);
SetVal("sdl", "overscan", tmp);
change_output(7);
change_output(8);
return true;
}
@ -10086,7 +10101,7 @@ bool vsync_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menuit
SetVal("vsync", "vsyncmode", val);
void change_output(int output);
change_output(8);
change_output(9);
VGA_Vsync VGA_Vsync_Decode(const char *vsyncmodestr);
void VGA_VsyncUpdateMode(VGA_Vsync vsyncmode);
@ -10126,20 +10141,26 @@ bool output_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menui
}
else if (!strcmp(what,"opengl")) {
#if C_OPENGL
if (sdl.desktop.want_type == SCREEN_OPENGL && sdl_opengl.bilinear) return true;
if (sdl.desktop.want_type == SCREEN_OPENGL && sdl_opengl.kind == GLBilinear) return true;
change_output(3);
#endif
}
else if (!strcmp(what,"openglnb")) {
#if C_OPENGL
if (sdl.desktop.want_type == SCREEN_OPENGL && !sdl_opengl.bilinear) return true;
if (sdl.desktop.want_type == SCREEN_OPENGL && sdl_opengl.kind == GLNearest) return true;
change_output(4);
#endif
}
else if (!strcmp(what,"openglpp")) {
#if C_OPENGL
if (sdl.desktop.want_type == SCREEN_OPENGL && sdl_opengl.kind == GLPerfect) return true;
change_output(5);
#endif
}
else if (!strcmp(what,"direct3d")) {
#if C_DIRECT3D
if (sdl.desktop.want_type == SCREEN_DIRECT3D) return true;
change_output(5);
change_output(6);
#endif
}
else if (!strcmp(what,"ttf")) {
@ -10162,7 +10183,7 @@ bool output_menu_callback(DOSBoxMenu * const menu,DOSBoxMenu::item * const menui
putenv("SDL_VIDEO_CENTERED=center");
#endif
firstset=false;
change_output(9);
change_output(10);
#endif
}
if (reset) RENDER_Reset();
@ -11150,8 +11171,9 @@ void OutputSettingMenuUpdate(void) {
mainMenu.get_item("output_direct3d").check(sdl.desktop.want_type == SCREEN_DIRECT3D).refresh_item(mainMenu);
#endif
#if C_OPENGL
mainMenu.get_item("output_opengl").check(sdl.desktop.want_type == SCREEN_OPENGL && sdl_opengl.bilinear).refresh_item(mainMenu);
mainMenu.get_item("output_openglnb").check(sdl.desktop.want_type == SCREEN_OPENGL && !sdl_opengl.bilinear).refresh_item(mainMenu);
mainMenu.get_item("output_opengl").check(sdl.desktop.want_type == SCREEN_OPENGL && sdl_opengl.kind == GLBilinear).refresh_item(mainMenu);
mainMenu.get_item("output_openglnb").check(sdl.desktop.want_type == SCREEN_OPENGL && sdl_opengl.kind == GLNearest).refresh_item(mainMenu);
mainMenu.get_item("output_openglpp").check(sdl.desktop.want_type == SCREEN_OPENGL && sdl_opengl.kind == GLPerfect).refresh_item(mainMenu);
#endif
#if defined(USE_TTF)
mainMenu.get_item("output_ttf").check(sdl.desktop.want_type == SCREEN_TTF).refresh_item(mainMenu);
@ -12024,7 +12046,9 @@ int main(int argc, char* argv[]) SDL_MAIN_NOEXCEPT {
set_callback_function(output_menu_callback);
mainMenu.alloc_item(DOSBoxMenu::item_type_id,"output_opengl").set_text("OpenGL").
set_callback_function(output_menu_callback);
mainMenu.alloc_item(DOSBoxMenu::item_type_id,"output_openglnb").set_text("OpenGL NB").
mainMenu.alloc_item(DOSBoxMenu::item_type_id,"output_openglnb").set_text("OpenGL nearest").
set_callback_function(output_menu_callback);
mainMenu.alloc_item(DOSBoxMenu::item_type_id,"output_openglpp").set_text("OpenGL perfect").
set_callback_function(output_menu_callback);
#if defined(USE_TTF)
mainMenu.alloc_item(DOSBoxMenu::item_type_id,"output_ttf").set_text("TrueType font").

View File

@ -1145,14 +1145,16 @@ void ttf_switch_off(bool ss=true) {
output = "opengl";
else if (switchoutput==4)
output = "openglnb";
else if (switchoutput==5)
output = "openglpp";
#endif
#if C_DIRECT3D
else if (switchoutput==5)
else if (switchoutput==6)
output = "direct3d";
#endif
else {
#if C_DIRECT3D
out = 5;
out = 6;
output = "direct3d";
#elif C_OPENGL
out = 3;

View File

@ -7,7 +7,10 @@
#include <sys/types.h>
#include <assert.h>
#include <math.h>
extern "C" {
#include "ppscale.h"
#include "ppscale.c"
}
#include "dosbox.h"
#include <output/output_opengl.h>
@ -94,6 +97,48 @@ int Voodoo_OGL_GetWidth();
int Voodoo_OGL_GetHeight();
bool Voodoo_OGL_Active();
static void PPScale (
uint16_t fixed_w , uint16_t fixed_h,
uint16_t* window_w, uint16_t* window_h )
{
int sx, sy, orig_w, orig_h, min_w, min_h;
double par, par_sq;
orig_w = min_w = render.src.width;
orig_h = min_h = render.src.height;
par = ( double) orig_w / orig_h * 3 / 4;
/* HACK: because REDNER_SetSize() does not set dblw and dblh correctly: */
/* E.g. in 360x360 mode DOXBox will wrongly allocate a 720x360 area. I */
/* therefore calculate square-pixel proportions par_sq myself: */
if( par < 0.707 ) { par_sq = 0.5; min_w *= 2; }
else if( par > 1.414 ) { par_sq = 2.0; min_h *= 2; }
else par_sq = 1.0;
if( !render.aspect ) par = par_sq;
*window_w = fixed_w; *window_h = fixed_h;
/* Handle non-fixed resolutions and ensure a sufficient window size: */
if( fixed_w < min_w ) fixed_w = *window_w = min_w;
if( fixed_h < min_h ) fixed_h = *window_h = min_h;
pp_getscale(
orig_w , orig_h , par ,
fixed_w, fixed_h, 1.14,
&sx , &sy );
sdl.clip.w = orig_w * sx;
sdl.clip.h = orig_h * sy;
sdl.clip.x = (*window_w - sdl.clip.w) / 2;
sdl.clip.y = (*window_h - sdl.clip.h) / 2;
LOG_MSG( "OpenGL PP: [%ix%i]: %ix%i (%3.2f) -> [%ix%i] -> %ix%i (%3.2f)",
fixed_w, fixed_h,
orig_w, orig_h, par,
sx, sy,
sdl.clip.w, sdl.clip.h, (double)sy/sx );
}
static SDL_Surface* SetupSurfaceScaledOpenGL(uint32_t sdl_flags, uint32_t bpp)
{
uint16_t fixedWidth;
@ -161,7 +206,7 @@ retry:
LOG_MSG("menuScale=%d", scale);
mainMenu.setScale((unsigned int)scale);
if (mainMenu.isVisible() && !sdl.desktop.fullscreen)
if (mainMenu.isVisible() && !sdl.desktop.fullscreen && fixedHeight)
fixedHeight -= mainMenu.menuBox.h;
}
#endif
@ -172,20 +217,24 @@ retry:
/* 3Dfx openGL do not allow resize */
sdl.clip.w = windowWidth = (uint16_t)Voodoo_OGL_GetWidth();
sdl.clip.h = windowHeight = (uint16_t)Voodoo_OGL_GetHeight();
}
else if (fixedWidth && fixedHeight)
{
sdl.clip.w = windowWidth = fixedWidth;
sdl.clip.h = windowHeight = fixedHeight;
if (render.aspect) aspectCorrectFitClip(sdl.clip.w, sdl.clip.h, sdl.clip.x, sdl.clip.y, fixedWidth, fixedHeight);
}
else
{
windowWidth = (uint16_t)(sdl.draw.width * sdl.draw.scalex);
windowHeight = (uint16_t)(sdl.draw.height * sdl.draw.scaley);
if (render.aspect) aspectCorrectExtend(windowWidth, windowHeight);
sdl.clip.w = windowWidth; sdl.clip.h = windowHeight;
}
} else if (sdl_opengl.kind == GLPerfect ) {
PPScale( fixedWidth, fixedHeight, &windowWidth, &windowHeight );
} else
if (fixedWidth && fixedHeight)
{
windowWidth = fixedWidth;
windowHeight = fixedHeight;
sdl.clip.w = windowWidth;
sdl.clip.h = windowHeight;
if (render.aspect) aspectCorrectFitClip(sdl.clip.w, sdl.clip.h, sdl.clip.x, sdl.clip.y, fixedWidth, fixedHeight);
}
else
{
windowWidth = (uint16_t)(sdl.draw.width * sdl.draw.scalex);
windowHeight = (uint16_t)(sdl.draw.height * sdl.draw.scaley);
if (render.aspect) aspectCorrectExtend(windowWidth, windowHeight);
sdl.clip.w = windowWidth; sdl.clip.h = windowHeight;
}
LOG(LOG_MISC, LOG_DEBUG)("GFX_SetSize OpenGL window=%ux%u clip=x,y,w,h=%d,%d,%d,%d",
(unsigned int)windowWidth,
@ -257,7 +306,7 @@ void OUTPUT_OPENGL_Initialize()
memset(&sdl_opengl, 0, sizeof(sdl_opengl));
}
void OUTPUT_OPENGL_Select()
void OUTPUT_OPENGL_Select( GLKind kind )
{
sdl.desktop.want_type = SCREEN_OPENGL;
render.aspectOffload = true;
@ -285,6 +334,8 @@ void OUTPUT_OPENGL_Select()
sdl.desktop.want_type = SCREEN_SURFACE;
} else if (initgl!=2) {
initgl = 1;
sdl_opengl.kind = kind;
sdl.desktop.isperfect = true;
sdl_opengl.program_object = 0;
glAttachShader = (PFNGLATTACHSHADERPROC)SDL_GL_GetProcAddress("glAttachShader");
glCompileShader = (PFNGLCOMPILESHADERPROC)SDL_GL_GetProcAddress("glCompileShader");
@ -341,7 +392,7 @@ void OUTPUT_OPENGL_Select()
Bitu OUTPUT_OPENGL_GetBestMode(Bitu flags)
{
if (!(flags & GFX_CAN_32)) return 0; // OpenGL requires 32-bit output mode
flags |= GFX_SCALING;
flags |= GFX_SCALING;
flags &= ~(GFX_CAN_8 | GFX_CAN_15 | GFX_CAN_16);
return flags;
}
@ -364,7 +415,7 @@ static GLuint BuildShader ( GLenum type, const char *shaderSrc ) {
}
top += (type==GL_VERTEX_SHADER) ? "#define VERTEX 1\n":"#define FRAGMENT 1\n";
if (!sdl_opengl.bilinear)
if (sdl_opengl.kind == GLNearest || sdl_opengl.kind == GLPerfect)
top += "#define OPENGLNB 1\n";
src_strings[0] = top.c_str();
@ -632,8 +683,12 @@ Bitu OUTPUT_OPENGL_SetSize()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, sdl_opengl.bilinear ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, sdl_opengl.bilinear ? GL_LINEAR : GL_NEAREST);
GLint interp;
if( sdl_opengl.kind == GLNearest || sdl_opengl.kind == GLPerfect )
interp = GL_NEAREST; else
interp = GL_LINEAR ;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, interp );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, interp );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texsize, texsize, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, 0);

View File

@ -68,6 +68,8 @@ typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size,
# include <SDL_video.h>
#endif
enum GLKind {GLNearest, GLBilinear, GLPerfect};
struct SDL_OpenGL {
bool inited;
Bitu pitch;
@ -76,7 +78,7 @@ struct SDL_OpenGL {
GLuint texture;
GLuint displaylist;
GLint max_texsize;
bool bilinear;
GLKind kind;
bool packed_pixel;
bool paletted_texture;
bool pixel_buffer_object;
@ -121,7 +123,10 @@ extern SDL_OpenGL sdl_opengl;
// output API
void OUTPUT_OPENGL_Initialize();
void OUTPUT_OPENGL_Select();
/* Anton Shepelev: the GLKind parameter violates the generality of the API, */
/* but I think will do until a more useful general API is adopted. One */
/* example of doing it seen in my original Pixel-perfect patch: */
void OUTPUT_OPENGL_Select( GLKind );
Bitu OUTPUT_OPENGL_GetBestMode(Bitu flags);
Bitu OUTPUT_OPENGL_SetSize();
bool OUTPUT_OPENGL_StartUpdate(uint8_t* &pixels, Bitu &pitch);