Add horizontal screen stretching option

fix scissor test when scaling/stretching
fix infiniloop when starting a game fails
This commit is contained in:
Flyinghead 2019-04-08 00:21:06 +02:00
parent 408d16b299
commit 47bb509f02
9 changed files with 108 additions and 62 deletions

View File

@ -313,7 +313,9 @@ int dc_start_game(const char *path)
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
if (!settings.bios.UseReios)
#endif
LoadRomFiles(get_readonly_data_path(DATA_PATH));
if (!LoadRomFiles(get_readonly_data_path(DATA_PATH)))
return -5;
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
if (path == NULL)
{
@ -513,6 +515,7 @@ void InitSettings()
settings.rend.CustomTextures = false;
settings.rend.DumpTextures = false;
settings.rend.ScreenScaling = 100;
settings.rend.ScreenStretching = 100;
settings.rend.Fog = true;
settings.pvr.ta_skip = 0;
@ -596,6 +599,7 @@ void LoadSettings(bool game_specific)
settings.rend.DumpTextures = cfgLoadBool(config_section, "rend.DumpTextures", settings.rend.DumpTextures);
settings.rend.ScreenScaling = cfgLoadInt(config_section, "rend.ScreenScaling", settings.rend.ScreenScaling);
settings.rend.ScreenScaling = min(max(1, settings.rend.ScreenScaling), 100);
settings.rend.ScreenStretching = cfgLoadInt(config_section, "rend.ScreenStretching", settings.rend.ScreenStretching);
settings.rend.Fog = cfgLoadBool(config_section, "rend.Fog", settings.rend.Fog);
settings.pvr.ta_skip = cfgLoadInt(config_section, "ta.skip", settings.pvr.ta_skip);
@ -720,6 +724,7 @@ void SaveSettings()
cfgSaveBool("config", "rend.CustomTextures", settings.rend.CustomTextures);
cfgSaveBool("config", "rend.DumpTextures", settings.rend.DumpTextures);
cfgSaveInt("config", "rend.ScreenScaling", settings.rend.ScreenScaling);
cfgSaveInt("config", "rend.ScreenStretching", settings.rend.ScreenStretching);
cfgSaveBool("config", "rend.Fog", settings.rend.Fog);
cfgSaveInt("config", "ta.skip", settings.pvr.ta_skip);
cfgSaveInt("config", "pvr.rend", settings.pvr.rend);

View File

@ -697,11 +697,15 @@ void gl4DrawFramebuffer(float w, float h)
bool gl4_render_output_framebuffer()
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, screen_width, screen_height);
if (gl.ofbo.tex == 0)
glcache.Disable(GL_SCISSOR_TEST);
if (gl.ofbo.fbo == 0)
return false;
gl4_draw_quad_texture(gl.ofbo.tex, true);
glBindFramebuffer(GL_READ_FRAMEBUFFER, gl.ofbo.fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, gl.ofbo.width, gl.ofbo.height,
0, 0, screen_width, screen_height,
GL_COLOR_BUFFER_BIT, GL_LINEAR);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return true;
}

View File

@ -662,14 +662,15 @@ static bool RenderFrame()
Handle Dc to screen scaling
*/
float screen_scaling = is_rtt ? 1.f : settings.rend.ScreenScaling / 100.f;
float screen_stretching = settings.rend.ScreenStretching / 100.f;
float dc2s_scale_h = is_rtt ? (screen_width / dc_width) : (screen_height / 480.0);
dc2s_scale_h *= screen_scaling;
float ds2s_offs_x = is_rtt ? 0 : (((screen_width * screen_scaling) - dc2s_scale_h * 640.0) / 2);
float ds2s_offs_x = is_rtt ? 0 : ((screen_width - dc2s_scale_h * 640.0 * screen_stretching) / 2);
//-1 -> too much to left
gl4ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width * screen_scaling / dc2s_scale_h * scale_x);
gl4ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching;
gl4ShaderUniforms.scale_coefs[1] = (is_rtt ? 2 : -2) / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512
gl4ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / (screen_width * screen_scaling);
gl4ShaderUniforms.scale_coefs[2] = 1 - 2 * ds2s_offs_x / screen_width;
gl4ShaderUniforms.scale_coefs[3] = (is_rtt ? 1 : -1);
gl4ShaderUniforms.extra_depth_scale = settings.rend.ExtraDepthScale;
@ -763,7 +764,7 @@ static bool RenderFrame()
{
if (settings.rend.ScreenScaling != 100 || gl.swap_buffer_not_preserved)
{
output_fbo = init_output_framebuffer(screen_width * screen_scaling, screen_height * screen_scaling);
output_fbo = init_output_framebuffer(screen_width * screen_scaling + 0.5f, screen_height * screen_scaling + 0.5f);
}
else
{
@ -826,21 +827,21 @@ static bool RenderFrame()
if (!is_rtt)
{
// Add x offset for aspect ratio > 4/3
min_x = min_x * dc2s_scale_h + ds2s_offs_x;
min_x = min_x * dc2s_scale_h * screen_stretching + ds2s_offs_x * screen_scaling;
// Invert y coordinates when rendering to screen
min_y = screen_height * screen_scaling - (min_y + height) * dc2s_scale_h;
width *= dc2s_scale_h;
height *= dc2s_scale_h;
min_y = (screen_height - (min_y + height) * dc2s_scale_h) * screen_scaling;
width *= dc2s_scale_h * screen_scaling * screen_stretching;
height *= dc2s_scale_h * screen_scaling;
if (ds2s_offs_x > 0)
{
float rounded_offs_x = ds2s_offs_x + 0.5f;
float scaled_offs_x = ds2s_offs_x * screen_scaling;
glcache.ClearColor(0.f, 0.f, 0.f, 0.f);
glcache.Enable(GL_SCISSOR_TEST);
glScissor(0, 0, rounded_offs_x, screen_height);
glScissor(0, 0, scaled_offs_x + 0.5f, screen_height * screen_scaling + 0.5f);
glClear(GL_COLOR_BUFFER_BIT);
glScissor(screen_width - rounded_offs_x, 0, rounded_offs_x, screen_height);
glScissor(screen_width * screen_scaling - scaled_offs_x + 0.5f, 0, scaled_offs_x + 1.f, screen_height * screen_scaling + 0.5f);
glClear(GL_COLOR_BUFFER_BIT);
}
}

View File

@ -1141,17 +1141,27 @@ void DrawFramebuffer(float w, float h)
bool render_output_framebuffer()
{
#if HOST_OS != OS_DARWIN
//Fix this in a proper way
glBindFramebuffer(GL_FRAMEBUFFER, 0);
#endif
glViewport(0, 0, screen_width, screen_height);
if (gl.ofbo.tex == 0)
return false;
float scl = 480.f / screen_height;
float tx = (screen_width * scl - 640.f) / 2;
DrawQuad(gl.ofbo.tex, -tx, 0, 640.f + tx * 2, 480.f, 0, 1, 1, 0);
glcache.Disable(GL_SCISSOR_TEST);
if (gl.gl_major < 3)
{
glViewport(0, 0, screen_width, screen_height);
if (gl.ofbo.tex == 0)
return false;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
float scl = 480.f / screen_height;
float tx = (screen_width * scl - 640.f) / 2;
DrawQuad(gl.ofbo.tex, -tx, 0, 640.f + tx * 2, 480.f, 0, 1, 1, 0);
}
else
{
if (gl.ofbo.fbo == 0)
return false;
glBindFramebuffer(GL_READ_FRAMEBUFFER, gl.ofbo.fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, gl.ofbo.width, gl.ofbo.height,
0, 0, screen_width, screen_height,
GL_COLOR_BUFFER_BIT, GL_LINEAR);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
return true;
}

View File

@ -1678,15 +1678,16 @@ bool RenderFrame()
/*
Handle Dc to screen scaling
*/
float screen_scaling = is_rtt ? 1.f : settings.rend.ScreenScaling / 100.f;
float screen_stretching = settings.rend.ScreenStretching / 100.f;
float screen_scaling = settings.rend.ScreenScaling / 100.f;
float dc2s_scale_h = is_rtt ? (screen_width / dc_width) : (screen_height / 480.0);
dc2s_scale_h *= screen_scaling;
float ds2s_offs_x = is_rtt ? 0 : (((screen_width * screen_scaling) - dc2s_scale_h * 640.0) / 2);
float ds2s_offs_x = is_rtt ? 0 : ((screen_width - dc2s_scale_h * 640.0 * screen_stretching) / 2);
//-1 -> too much to left
ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width * screen_scaling / dc2s_scale_h * scale_x);
ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width / dc2s_scale_h * scale_x) * screen_stretching;
ShaderUniforms.scale_coefs[1]= (is_rtt ? 2 : -2) / dc_height; // FIXME CT2 needs 480 here instead of dc_height=512
ShaderUniforms.scale_coefs[2]= 1 - 2 * ds2s_offs_x / (screen_width * screen_scaling);
ShaderUniforms.scale_coefs[2]= 1 - 2 * ds2s_offs_x / screen_width;
ShaderUniforms.scale_coefs[3]= (is_rtt ? 1 : -1);
@ -1791,7 +1792,7 @@ bool RenderFrame()
{
if (settings.rend.ScreenScaling != 100 || gl.swap_buffer_not_preserved)
{
init_output_framebuffer(screen_width * screen_scaling, screen_height * screen_scaling);
init_output_framebuffer(screen_width * screen_scaling + 0.5f, screen_height * screen_scaling + 0.5f);
}
else
{
@ -1857,21 +1858,21 @@ bool RenderFrame()
if (!is_rtt)
{
// Add x offset for aspect ratio > 4/3
min_x = min_x * dc2s_scale_h + ds2s_offs_x;
min_x = min_x * dc2s_scale_h * screen_stretching + ds2s_offs_x * screen_scaling;
// Invert y coordinates when rendering to screen
min_y = screen_height * screen_scaling - (min_y + height) * dc2s_scale_h;
width *= dc2s_scale_h;
height *= dc2s_scale_h;
min_y = (screen_height - (min_y + height) * dc2s_scale_h) * screen_scaling;
width *= dc2s_scale_h * screen_scaling * screen_stretching;
height *= dc2s_scale_h * screen_scaling;
if (ds2s_offs_x > 0)
{
float rounded_offs_x = ds2s_offs_x + 0.5f;
float scaled_offs_x = ds2s_offs_x * screen_scaling;
glcache.ClearColor(0.f, 0.f, 0.f, 0.f);
glcache.Enable(GL_SCISSOR_TEST);
glScissor(0, 0, rounded_offs_x, screen_height);
glScissor(0, 0, scaled_offs_x + 0.5f, screen_height * screen_scaling + 0.5f);
glClear(GL_COLOR_BUFFER_BIT);
glScissor(screen_width - rounded_offs_x, 0, rounded_offs_x, screen_height);
glScissor(screen_width * screen_scaling - scaled_offs_x + 0.5f, 0, scaled_offs_x + 1.f, screen_height * screen_scaling + 0.5f);
glClear(GL_COLOR_BUFFER_BIT);
}
}

View File

@ -120,6 +120,7 @@ struct gl_ctx
struct
{
GLuint depthb;
GLuint colorb;
GLuint tex;
GLuint fbo;
int width;

View File

@ -996,13 +996,7 @@ GLuint init_output_framebuffer(int width, int height)
{
if (width != gl.ofbo.width || height != gl.ofbo.height)
{
if (gl.ofbo.fbo != 0)
{
glDeleteFramebuffers(1, &gl.ofbo.fbo);
gl.ofbo.fbo = 0;
glDeleteRenderbuffers(1, &gl.ofbo.depthb);
glcache.DeleteTextures(1, &gl.ofbo.tex);
}
free_output_framebuffer();
gl.ofbo.width = width;
gl.ofbo.height = height;
}
@ -1026,15 +1020,25 @@ GLuint init_output_framebuffer(int width, int height)
else
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
// Create a texture for rendering to
gl.ofbo.tex = glcache.GenTexture();
glcache.BindTexture(GL_TEXTURE_2D, gl.ofbo.tex);
if (gl.gl_major < 3)
{
// Create a texture for rendering to
gl.ofbo.tex = glcache.GenTexture();
glcache.BindTexture(GL_TEXTURE_2D, gl.ofbo.tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
else
{
// Use a renderbuffer and glBlitFramebuffer
glGenRenderbuffers(1, &gl.ofbo.colorb);
glBindRenderbuffer(GL_RENDERBUFFER, gl.ofbo.colorb);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
}
// Create the framebuffer
glGenFramebuffers(1, &gl.ofbo.fbo);
@ -1046,13 +1050,20 @@ GLuint init_output_framebuffer(int width, int height)
if (!gl.is_gles || gl.GL_OES_packed_depth_stencil_supported)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, gl.ofbo.depthb);
// Attach the texture to the FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl.ofbo.tex, 0);
// Attach the texture/renderbuffer to the FBO
if (gl.gl_major < 3)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl.ofbo.tex, 0);
else
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, gl.ofbo.colorb);
// Check that our FBO creation was successful
GLuint uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
verify(uStatus == GL_FRAMEBUFFER_COMPLETE);
glcache.Disable(GL_SCISSOR_TEST);
glcache.ClearColor(0.f, 0.f, 0.f, 0.f);
glClear(GL_COLOR_BUFFER_BIT);
}
else
glBindFramebuffer(GL_FRAMEBUFFER, gl.ofbo.fbo);
@ -1071,7 +1082,15 @@ void free_output_framebuffer()
gl.ofbo.fbo = 0;
glDeleteRenderbuffers(1, &gl.ofbo.depthb);
gl.ofbo.depthb = 0;
glcache.DeleteTextures(1, &gl.ofbo.tex);
gl.ofbo.tex = 0;
if (gl.ofbo.tex != 0)
{
glcache.DeleteTextures(1, &gl.ofbo.tex);
gl.ofbo.tex = 0;
}
if (gl.ofbo.colorb != 0)
{
glDeleteRenderbuffers(1, &gl.ofbo.colorb);
gl.ofbo.colorb = 0;
}
}
}

View File

@ -952,6 +952,9 @@ static void gui_display_settings()
ImGui::SliderInt("Scaling", (int *)&settings.rend.ScreenScaling, 1, 100);
ImGui::SameLine();
ShowHelpMarker("Downscaling factor relative to native screen resolution. Higher is better");
ImGui::SliderInt("Horizontal Stretching", (int *)&settings.rend.ScreenStretching, 100, 150);
ImGui::SameLine();
ShowHelpMarker("Stretch the screen horizontally");
ImGui::SliderInt("Frame Skipping", (int *)&settings.pvr.ta_skip, 0, 6);
ImGui::SameLine();
ShowHelpMarker("Number of frames to skip between two actually rendered frames");
@ -1251,6 +1254,7 @@ static void gui_start_game(const std::string& path)
{
gui_state = Main;
game_started = false;
cfgSetVirtual("config", "image", "");
switch (rc) {
case -3:
error_msg = "Audio/video initialization failed";

View File

@ -632,7 +632,8 @@ struct settings_t
f32 ExtraDepthScale;
bool CustomTextures;
bool DumpTextures;
int ScreenScaling; // in percent. 50 means half the native resolution
int ScreenScaling; // in percent. 50 means half the native resolution
int ScreenStretching; // in percent. 150 means stretch from 4/3 to 6/3
bool Fog;
} rend;