Added RenderLastFrame() to Renderer interface

implement screen scaling for per-pixel renderer
fix output FBO not being freed/recreated when GL context is reset
refactor DrawQuad on per-pixel renderer
This commit is contained in:
Flyinghead 2019-02-19 11:36:59 +01:00
parent 810182c4fe
commit 9526fada5e
10 changed files with 115 additions and 73 deletions

View File

@ -282,7 +282,9 @@ bool rend_single_frame()
}
else
{
render_output_framebuffer();
if (renderer != NULL)
renderer->RenderLastFrame();
#if defined(_ANDROID)
if (!rs.Wait(100))
return false;
@ -297,6 +299,8 @@ bool rend_single_frame()
FinishRender(NULL);
return true;
}
if (renderer != NULL)
renderer->RenderLastFrame();
#endif
if (!renderer_enabled)
return false;

View File

@ -41,6 +41,7 @@ struct Renderer
virtual bool Process(TA_context* ctx)=0;
virtual bool Render()=0;
virtual bool RenderLastFrame() { return false; }
virtual void Present()=0;

View File

@ -4,6 +4,7 @@
* Created on: May 26, 2018
* Author: raph
*/
#include <math.h>
#include "gl4.h"
#include "rend/gles/glcache.h"
@ -277,12 +278,10 @@ void main(void) \n\
} \n\
";
void DrawQuad();
void initABuffer()
{
g_imageWidth = screen_width;
g_imageHeight = screen_height;
g_imageWidth = (int)roundf(screen_width * settings.rend.ScreenScaling / 100.f);
g_imageHeight = (int)roundf(screen_height * settings.rend.ScreenScaling / 100.f);
if (g_imageWidth > 0 && g_imageHeight > 0)
{
@ -363,7 +362,7 @@ void initABuffer()
glcache.UseProgram(g_abuffer_clear_shader.program);
gl4ShaderUniforms.Set(&g_abuffer_clear_shader);
DrawQuad();
abufferDrawQuad();
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
glCheck();
@ -400,6 +399,9 @@ void termABuffer()
void reshapeABuffer(int w, int h)
{
w = (int)roundf(w * settings.rend.ScreenScaling / 100.f);
h = (int)roundf(h * settings.rend.ScreenScaling / 100.f);
if (w != g_imageWidth || h != g_imageHeight) {
if (pixels_pointers != 0)
{
@ -411,25 +413,25 @@ void reshapeABuffer(int w, int h)
}
}
void DrawQuad()
void abufferDrawQuad(bool upsideDown, float x, float y, float w, float h)
{
if (w == 0 || h == 0)
{
float scl = 480.f / screen_height;
float tx = (screen_width * scl - 640.f) / 2;
x = -tx;
y = 0.f;
w = 640.f + tx * 2;
h = 480.f;
}
glBindVertexArray(g_quadVertexArray);
float xmin = (gl4ShaderUniforms.scale_coefs[2] - 1) / gl4ShaderUniforms.scale_coefs[0];
float xmax = (gl4ShaderUniforms.scale_coefs[2] + 1) / gl4ShaderUniforms.scale_coefs[0];
float ymin = (gl4ShaderUniforms.scale_coefs[3] - 1) / gl4ShaderUniforms.scale_coefs[1];
float ymax = (gl4ShaderUniforms.scale_coefs[3] + 1) / gl4ShaderUniforms.scale_coefs[1];
if (ymin > ymax)
{
float t = ymin;
ymin = ymax;
ymax = t;
}
struct Vertex vertices[] = {
{ xmin, ymax, 1, { 255, 255, 255, 255 }, { 0, 0, 0, 0 }, 0, 1 },
{ xmin, ymin, 1, { 255, 255, 255, 255 }, { 0, 0, 0, 0 }, 0, 0 },
{ xmax, ymax, 1, { 255, 255, 255, 255 }, { 0, 0, 0, 0 }, 1, 1 },
{ xmax, ymin, 1, { 255, 255, 255, 255 }, { 0, 0, 0, 0 }, 1, 0 },
{ x, y + h, 1, { 255, 255, 255, 255 }, { 0, 0, 0, 0 }, 0, upsideDown ? 0.f : 1.f },
{ x, y, 1, { 255, 255, 255, 255 }, { 0, 0, 0, 0 }, 0, upsideDown ? 1.f : 0.f },
{ x + w, y + h, 1, { 255, 255, 255, 255 }, { 0, 0, 0, 0 }, 1, upsideDown ? 0.f : 1.f },
{ x + w, y, 1, { 255, 255, 255, 255 }, { 0, 0, 0, 0 }, 1, upsideDown ? 1.f : 0.f },
};
GLushort indices[] = { 0, 1, 2, 1, 3 };
@ -563,7 +565,7 @@ void renderABuffer(bool sortFragments)
glcache.Disable(GL_CULL_FACE);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_BUFFER_UPDATE_BARRIER_BIT);
DrawQuad();
abufferDrawQuad();
glCheck();
@ -572,7 +574,7 @@ void renderABuffer(bool sortFragments)
gl4ShaderUniforms.Set(&g_abuffer_clear_shader);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
DrawQuad();
abufferDrawQuad();
glActiveTexture(GL_TEXTURE0);

View File

@ -76,6 +76,8 @@ extern int screen_height;
GLuint gl4BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt);
void gl4DrawFramebuffer(float w, float h);
bool gl4_render_output_framebuffer();
void abufferDrawQuad(bool upsideDown = false, float x = 0.f, float y = 0.f, float w = 0.f, float h = 0.f);
extern const char *gl4PixelPipelineShader;
bool gl4CompilePipelineShader(gl4PipelineShader* s, const char *source = gl4PixelPipelineShader);

View File

@ -1,3 +1,4 @@
#include <math.h>
#include "gl4.h"
#include "rend/gles/glcache.h"
#include "rend/rend.h"
@ -409,20 +410,20 @@ void renderABuffer(bool sortFragments);
void DrawTranslucentModVols(int first, int count);
void checkOverflowAndReset();
static GLuint CreateColorFBOTexture()
static GLuint CreateColorFBOTexture(int width, int height)
{
GLuint texId = glcache.GenTexture();
glBindTexture(GL_TEXTURE_2D, texId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texId, 0);
glCheck();
return texId;
}
static void CreateTextures()
static void CreateTextures(int width, int height)
{
stencilTexId = glcache.GenTexture();
glBindTexture(GL_TEXTURE_2D, stencilTexId); glCheck();
@ -430,11 +431,11 @@ static void CreateTextures()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Using glTexStorage2D instead of glTexImage2D to satisfy requirement GL_TEXTURE_IMMUTABLE_FORMAT=true, needed for glTextureView below
glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH32F_STENCIL8, screen_width, screen_height);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH32F_STENCIL8, width, height);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, stencilTexId, 0); glCheck();
glCheck();
opaqueTexId = CreateColorFBOTexture();
opaqueTexId = CreateColorFBOTexture(width, height);
depthTexId = glcache.GenTexture();
glTextureView(depthTexId, GL_TEXTURE_2D, stencilTexId, GL_DEPTH32F_STENCIL8, 0, 1, 0, 1);
@ -449,13 +450,15 @@ static void CreateTextures()
void gl4DrawStrips(GLuint output_fbo)
{
checkOverflowAndReset();
int scaled_width = (int)roundf(screen_width * settings.rend.ScreenScaling / 100.f);
int scaled_height = (int)roundf(screen_height * settings.rend.ScreenScaling / 100.f);
if (geom_fbo == 0)
{
glGenFramebuffers(1, &geom_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, geom_fbo);
CreateTextures();
CreateTextures(scaled_width, scaled_height);
GLuint uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
@ -465,7 +468,7 @@ void gl4DrawStrips(GLuint output_fbo)
{
glBindFramebuffer(GL_FRAMEBUFFER, geom_fbo);
if (stencilTexId == 0)
CreateTextures();
CreateTextures(scaled_width, scaled_height);
}
if (texSamplers[0] == 0)
glGenSamplers(2, texSamplers);
@ -531,14 +534,14 @@ void gl4DrawStrips(GLuint output_fbo)
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_DEPTH_COMPONENT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH32F_STENCIL8, screen_width, screen_height, 0, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, NULL); glCheck();
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH32F_STENCIL8, scaled_width, scaled_height, 0, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV, NULL); glCheck();
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthSaveTexId, 0); glCheck();
}
GLuint uStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
verify(uStatus == GL_FRAMEBUFFER_COMPLETE);
glBindFramebuffer(GL_READ_FRAMEBUFFER, geom_fbo);
glBlitFramebuffer(0, 0, screen_width, screen_height, 0, 0, screen_width, screen_height, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
glBlitFramebuffer(0, 0, scaled_width, scaled_height, 0, 0, scaled_width, scaled_height, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
glCheck();
glBindFramebuffer(GL_FRAMEBUFFER, geom_fbo);
@ -570,7 +573,7 @@ void gl4DrawStrips(GLuint output_fbo)
// FIXME This is pretty slow apparently (CS)
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, geom_fbo);
glBindFramebuffer(GL_READ_FRAMEBUFFER, depth_fbo);
glBlitFramebuffer(0, 0, screen_width, screen_height, 0, 0, screen_width, screen_height, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
glBlitFramebuffer(0, 0, scaled_width, scaled_height, 0, 0, scaled_width, scaled_height, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
glCheck();
glBindFramebuffer(GL_FRAMEBUFFER, geom_fbo);
}
@ -638,7 +641,7 @@ void gl4DrawStrips(GLuint output_fbo)
//
// PASS 3c: Render a-buffer to temporary texture
//
GLuint texId = CreateColorFBOTexture();
GLuint texId = CreateColorFBOTexture(scaled_width, scaled_height);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
@ -679,23 +682,15 @@ void gl4DrawStrips(GLuint output_fbo)
SetupMainVBO();
}
void gl4DrawFramebuffer(float w, float h)
static void gl4_draw_quad_texture(GLuint texture, bool upsideDown, float x = 0.f, float y = 0.f, float w = 0.f, float h = 0.f)
{
struct Vertex vertices[] = {
{ 0, h, 1, { 255, 255, 255, 255 }, { 0, 0, 0, 0 }, 0, 1 },
{ 0, 0, 1, { 255, 255, 255, 255 }, { 0, 0, 0, 0 }, 0, 0 },
{ w, h, 1, { 255, 255, 255, 255 }, { 0, 0, 0, 0 }, 1, 1 },
{ w, 0, 1, { 255, 255, 255, 255 }, { 0, 0, 0, 0 }, 1, 0 },
};
GLushort indices[] = { 0, 1, 2, 1, 3 };
glcache.Disable(GL_SCISSOR_TEST);
glcache.Disable(GL_DEPTH_TEST);
glcache.Disable(GL_STENCIL_TEST);
glcache.Disable(GL_CULL_FACE);
glcache.Disable(GL_BLEND);
gl4ShaderUniforms.trilinear_alpha = 1.0;
ShaderUniforms.trilinear_alpha = 1.0;
setCurrentShader(0,
0,
@ -715,17 +710,25 @@ void gl4DrawFramebuffer(float w, float h)
gl4ShaderUniforms.Set(CurrentShader);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, fbTextureId);
glBindTexture(GL_TEXTURE_2D, texture);
SetupMainVBO();
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STREAM_DRAW);
glDrawElements(GL_TRIANGLE_STRIP, 5, GL_UNSIGNED_SHORT, (void *)0);
abufferDrawQuad(upsideDown, x, y, w, h);
}
void gl4DrawFramebuffer(float w, float h)
{
gl4_draw_quad_texture(fbTextureId, false, 0, 0, w, h);
glcache.DeleteTextures(1, &fbTextureId);
fbTextureId = 0;
glBufferData(GL_ARRAY_BUFFER, pvrrc.verts.bytes(), pvrrc.verts.head(), GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, pvrrc.idx.bytes(), pvrrc.idx.head(), GL_STREAM_DRAW);
}
bool gl4_render_output_framebuffer()
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, screen_width, screen_height);
if (gl.ofbo.tex == 0)
return false;
gl4_draw_quad_texture(gl.ofbo.tex, true);
return true;
}

View File

@ -608,11 +608,12 @@ static bool gles_init()
static bool RenderFrame()
{
static int old_screen_width, old_screen_height;
if (screen_width != old_screen_width || screen_height != old_screen_height) {
static int old_screen_width, old_screen_height, old_screen_scaling;
if (screen_width != old_screen_width || screen_height != old_screen_height || settings.rend.ScreenScaling != old_screen_scaling) {
rend_resize(screen_width, screen_height);
old_screen_width = screen_width;
old_screen_height = screen_height;
old_screen_scaling = settings.rend.ScreenScaling;
}
DoCleanup();
@ -673,14 +674,16 @@ static bool RenderFrame()
/*
Handle Dc to screen scaling
*/
float screen_scaling = is_rtt ? 1.f : settings.rend.ScreenScaling / 100.f;
float dc2s_scale_h = is_rtt ? (screen_width / dc_width) : (screen_height / 480.0);
float ds2s_offs_x = is_rtt ? 0 : ((screen_width - dc2s_scale_h * 640.0) / 2);
dc2s_scale_h *= screen_scaling;
float ds2s_offs_x = is_rtt ? 0 : (((screen_width * screen_scaling) - dc2s_scale_h * 640.0) / 2);
//-1 -> too much to left
gl4ShaderUniforms.scale_coefs[0]=2.0f/(screen_width/dc2s_scale_h*scale_x);
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);
gl4ShaderUniforms.scale_coefs[3]=(is_rtt?1:-1);
gl4ShaderUniforms.scale_coefs[0] = 2.0f / (screen_width * screen_scaling / dc2s_scale_h * scale_x);
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[3] = (is_rtt ? 1 : -1);
gl4ShaderUniforms.extra_depth_scale = settings.rend.ExtraDepthScale;
@ -777,12 +780,16 @@ static bool RenderFrame()
}
else
{
#if HOST_OS != OS_DARWIN
//Fix this in a proper way
glBindFramebuffer(GL_FRAMEBUFFER,0);
#endif
glViewport(0, 0, screen_width, screen_height);
output_fbo = 0;
if (settings.rend.ScreenScaling != 100 || gl.swap_buffer_not_preserved)
{
output_fbo = init_output_framebuffer(screen_width * screen_scaling, screen_height * screen_scaling);
}
else
{
glBindFramebuffer(GL_FRAMEBUFFER,0);
glViewport(0, 0, screen_width, screen_height);
output_fbo = 0;
}
}
bool wide_screen_on = !is_rtt && settings.rend.WideScreen
@ -888,6 +895,8 @@ static bool RenderFrame()
if (is_rtt)
ReadRTTBuffer();
else if (settings.rend.ScreenScaling != 100 || gl.swap_buffer_not_preserved)
gl4_render_output_framebuffer();
return !is_rtt;
}
@ -954,10 +963,12 @@ struct gl4rend : Renderer
gl_term();
gl_free_osd_resources();
free_output_framebuffer();
}
bool Process(TA_context* ctx) { return ProcessFrame(ctx); }
bool Render() { return RenderFrame(); }
bool RenderLastFrame() { return gl4_render_output_framebuffer(); }
void Present() { gl_swap(); }

View File

@ -1150,7 +1150,7 @@ void DrawFramebuffer(float w, float h)
fbTextureId = 0;
}
void render_output_framebuffer()
bool render_output_framebuffer()
{
#if HOST_OS != OS_DARWIN
//Fix this in a proper way
@ -1158,9 +1158,11 @@ void render_output_framebuffer()
#endif
glViewport(0, 0, screen_width, screen_height);
if (gl.ofbo.tex == 0)
return;
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);
return true;
}

View File

@ -748,6 +748,7 @@ void gl_term()
glcache.DeleteTextures(1, &fogTextureId);
fogTextureId = 0;
gl_free_osd_resources();
free_output_framebuffer();
memset(gl.pogram_table, 0, sizeof(gl.pogram_table));
@ -1761,7 +1762,7 @@ bool RenderFrame()
{
if (settings.rend.ScreenScaling != 100 || gl.swap_buffer_not_preserved)
{
init_output_framebuffer(screen_width * settings.rend.ScreenScaling / 100, screen_height * settings.rend.ScreenScaling / 100);
init_output_framebuffer(screen_width * screen_scaling, screen_height * screen_scaling);
}
else
{
@ -1908,7 +1909,7 @@ struct glesrend : Renderer
bool Process(TA_context* ctx) { return ProcessFrame(ctx); }
bool Render() { return RenderFrame(); }
bool RenderLastFrame() { return render_output_framebuffer(); }
void Present() { gl_swap(); glViewport(0, 0, screen_width, screen_height); }
void DrawOSD() { OSD_DRAW(gl.OSD_SHADER.program); }

View File

@ -179,8 +179,9 @@ void BindRTT(u32 addy, u32 fbw, u32 fbh, u32 channels, u32 fmt);
void ReadRTTBuffer();
void RenderFramebuffer();
void DrawFramebuffer(float w, float h);
void init_output_framebuffer(int width, int height);
void render_output_framebuffer();
GLuint init_output_framebuffer(int width, int height);
bool render_output_framebuffer();
void free_output_framebuffer();
void HideOSD();
void OSD_DRAW(GLuint shader_program);

View File

@ -1006,7 +1006,7 @@ void RenderFramebuffer()
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pb.data());
}
void init_output_framebuffer(int width, int height)
GLuint init_output_framebuffer(int width, int height)
{
if (width != gl.ofbo.width || height != gl.ofbo.height)
{
@ -1071,4 +1071,19 @@ void init_output_framebuffer(int width, int height)
glViewport(0, 0, width, height);
glCheck();
return gl.ofbo.fbo;
}
void free_output_framebuffer()
{
if (gl.ofbo.fbo != 0)
{
glDeleteFramebuffers(1, &gl.ofbo.fbo);
gl.ofbo.fbo = 0;
glDeleteRenderbuffers(1, &gl.ofbo.depthb);
gl.ofbo.depthb = 0;
glcache.DeleteTextures(1, &gl.ofbo.tex);
gl.ofbo.tex = 0;
}
}