diff --git a/core/hw/pvr/Renderer_if.cpp b/core/hw/pvr/Renderer_if.cpp index e9cfc1da1..f4221d417 100644 --- a/core/hw/pvr/Renderer_if.cpp +++ b/core/hw/pvr/Renderer_if.cpp @@ -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; diff --git a/core/hw/pvr/Renderer_if.h b/core/hw/pvr/Renderer_if.h index 8298a9f91..833e94d5b 100644 --- a/core/hw/pvr/Renderer_if.h +++ b/core/hw/pvr/Renderer_if.h @@ -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; diff --git a/core/rend/gl4/abuffer.cpp b/core/rend/gl4/abuffer.cpp index 81ca7b103..4fb2b26a2 100644 --- a/core/rend/gl4/abuffer.cpp +++ b/core/rend/gl4/abuffer.cpp @@ -4,6 +4,7 @@ * Created on: May 26, 2018 * Author: raph */ +#include #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); diff --git a/core/rend/gl4/gl4.h b/core/rend/gl4/gl4.h index 73c72cc0c..56870b134 100755 --- a/core/rend/gl4/gl4.h +++ b/core/rend/gl4/gl4.h @@ -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); diff --git a/core/rend/gl4/gldraw.cpp b/core/rend/gl4/gldraw.cpp index bc3adde5e..4f09a5f38 100644 --- a/core/rend/gl4/gldraw.cpp +++ b/core/rend/gl4/gldraw.cpp @@ -1,3 +1,4 @@ +#include #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; } diff --git a/core/rend/gl4/gles.cpp b/core/rend/gl4/gles.cpp index d2e69d82e..1ac62b54f 100644 --- a/core/rend/gl4/gles.cpp +++ b/core/rend/gl4/gles.cpp @@ -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(); } diff --git a/core/rend/gles/gldraw.cpp b/core/rend/gles/gldraw.cpp index c740dedbe..4fe0d8fe1 100644 --- a/core/rend/gles/gldraw.cpp +++ b/core/rend/gles/gldraw.cpp @@ -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; } diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index c99853032..e677405ce 100644 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -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); } diff --git a/core/rend/gles/gles.h b/core/rend/gles/gles.h index 5204cf414..c65816fa5 100755 --- a/core/rend/gles/gles.h +++ b/core/rend/gles/gles.h @@ -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); diff --git a/core/rend/gles/gltex.cpp b/core/rend/gles/gltex.cpp index 0e0af9607..25bb77867 100644 --- a/core/rend/gles/gltex.cpp +++ b/core/rend/gles/gltex.cpp @@ -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; + } }