diff --git a/core/rend/gles/gldraw.cpp b/core/rend/gles/gldraw.cpp index ded55e1d4..96194e51c 100644 --- a/core/rend/gles/gldraw.cpp +++ b/core/rend/gles/gldraw.cpp @@ -1155,3 +1155,89 @@ void DrawStrips() #endif } } + +void fullscreenQuadPrepareFramebuffer(float scale_x, float scale_y) { + // Bind the default framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, screen_width, screen_height); + + glDisable(GL_SCISSOR_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_STENCIL_TEST); + glDisable(GL_BLEND); + + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // Reduce width to keep 4:3 aspect ratio (640x480) + u32 reducedWidth = 4 * screen_height / 3; + u32 reducedWidthOffset = (screen_width - reducedWidth) / 2; + glScissor(reducedWidthOffset, 0, reducedWidth, screen_height); + if (settings.rend.WideScreen && + (pvrrc.fb_X_CLIP.min==0) && ((pvrrc.fb_X_CLIP.max+1)/scale_x==640) && + (pvrrc.fb_Y_CLIP.min==0) && ((pvrrc.fb_Y_CLIP.max+1)/scale_y==480 )) + { + glDisable(GL_SCISSOR_TEST); + } + else + { + glEnable(GL_SCISSOR_TEST); + } +} + +void fullscreenQuadBindVertexData( + float screenToNativeX, float screenToNativeY, GLint &vsPosition, GLint &vsTexcoord, GLint &fsTexture) +{ + u32 quadVerticesNumber = 4; + glUseProgram(gl.fullscreenQuadShader); + + glBindBuffer(GL_ARRAY_BUFFER, fullscreenQuad.positionsBuffer); + glEnableVertexAttribArray( vsPosition ); + glVertexAttribPointer(vsPosition, 3, GL_FLOAT, GL_FALSE, 0, 0); + + glBindBuffer(GL_ARRAY_BUFFER, fullscreenQuad.texcoordsBuffer); + glEnableVertexAttribArray( vsTexcoord ); + const float2 texcoordsArray[] = + { + { screenToNativeX, screenToNativeY }, + { 0.0f, screenToNativeY }, + { 0.0f, 0.0f }, + { screenToNativeX, 0.0f }, + }; + glBufferData(GL_ARRAY_BUFFER, sizeof(float2) * quadVerticesNumber, texcoordsArray, GL_STATIC_DRAW); + glVertexAttribPointer(vsTexcoord, 2, GL_FLOAT, GL_FALSE, 0, 0); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, fullscreenQuad.indexBuffer); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, fullscreenQuad.framebufferTexture); + glUniform1i(fsTexture, 0); +} + +void DrawFullscreenQuad(float screenToNativeX, float screenToNativeY, float scale_x, float scale_y) { + u32 quadIndicesNumber = 6; + GLint boundArrayBuffer = 0; + GLint boundElementArrayBuffer = 0; + GLint vsPosition= glGetAttribLocation(gl.fullscreenQuadShader, "a_position"); + GLint vsTexcoord= glGetAttribLocation(gl.fullscreenQuadShader, "a_texcoord"); + GLint fsTexture = glGetUniformLocation(gl.fullscreenQuadShader, "s_texture"); + + glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &boundArrayBuffer); + glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &boundElementArrayBuffer); + + fullscreenQuadPrepareFramebuffer(scale_x, scale_y); + fullscreenQuadBindVertexData(screenToNativeX, screenToNativeY, vsPosition, vsTexcoord, fsTexture); + + glDrawElements(GL_TRIANGLES, quadIndicesNumber, GL_UNSIGNED_BYTE, 0); + + // Unbind buffers + glBindTexture(GL_TEXTURE_2D, 0); + glBindBuffer(GL_ARRAY_BUFFER, boundArrayBuffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, boundElementArrayBuffer); + glDisableVertexAttribArray( vsPosition ); + glDisableVertexAttribArray( vsTexcoord ); + + // Restore vertex attribute pointers (OSD drawing preparation) + SetupMainVBO(); +} diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index d8ec2823f..95b73edc1 100755 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -386,12 +386,36 @@ void main() \n\ " FRAGCOL "=vtx_base*" TEXLOOKUP "(tex,uv.st); \n\n\ }"; +const char * FullscreenQuadVertexShader = + "attribute vec3 a_position;\n\ + attribute vec2 a_texcoord;\n\ + \n\ + varying vec2 v_texcoord; \n\ + \n\ + void main()\n\ + {\n\ + v_texcoord = a_texcoord;\n\ + gl_Position = vec4(a_position, 1);\n\ + }"; + +const char * FullscreenQuadFragmentShader = + "precision mediump float;\n\ + uniform sampler2D s_texture;\n\ + \n\ + varying vec2 v_texcoord;\n\ + \n\ + void main()\n\ + {\n\ + gl_FragColor = texture2D(s_texture, v_texcoord.st);\n\ + }"; gl_ctx gl; int screen_width; int screen_height; +GLFramebufferData fullscreenQuad; + #if (HOST_OS != OS_DARWIN) && !defined(TARGET_NACL32) #if defined(GLES) && !defined(USE_SDL) // Create a basic GLES context @@ -758,7 +782,10 @@ GLuint gl_CompileShader(const char* shader,GLuint type) return rv; } -GLuint gl_CompileAndLink(const char* VertexShader, const char* FragmentShader) +GLuint gl_CompileAndLink( + const char* VertexShader, + const char* FragmentShader, + void (*bindAttribLocationCallback)(GLuint) = NULL) { //create shaders GLuint vs=gl_CompileShader(VertexShader ,GL_VERTEX_SHADER); @@ -768,15 +795,9 @@ GLuint gl_CompileAndLink(const char* VertexShader, const char* FragmentShader) glAttachShader(program, vs); glAttachShader(program, ps); - //bind vertex attribute to vbo inputs - glBindAttribLocation(program, VERTEX_POS_ARRAY, "in_pos"); - glBindAttribLocation(program, VERTEX_COL_BASE_ARRAY, "in_base"); - glBindAttribLocation(program, VERTEX_COL_OFFS_ARRAY, "in_offs"); - glBindAttribLocation(program, VERTEX_UV_ARRAY, "in_uv"); - -#ifndef GLES - glBindFragDataLocation(program, 0, "FragColor"); -#endif + if (bindAttribLocationCallback != NULL) { + bindAttribLocationCallback(program); + } glLinkProgram(program); @@ -800,6 +821,8 @@ GLuint gl_CompileAndLink(const char* VertexShader, const char* FragmentShader) die("shader compile fail\n"); } + glDetachShader(program, vs); + glDetachShader(program, ps); glDeleteShader(vs); glDeleteShader(ps); @@ -828,6 +851,65 @@ int GetProgramID(u32 cp_AlphaTest, u32 pp_ClipTestMode, return rv; } +void generateFullscreenQuadVertices() { + const u32 verticesNumber = 4; + const u32 indicesNumber = 6; + + const float3 quadPositions[] = + { + { 1.0f, 1.0f, 0.0f }, + { -1.0f, 1.0f, 0.0f }, + { -1.0f, -1.0f, 0.0f }, + { 1.0f, -1.0f, 0.0f }, + }; + if (!fullscreenQuad.positionsBuffer) { + glGenBuffers(1, &fullscreenQuad.positionsBuffer); + } + glBindBuffer(GL_ARRAY_BUFFER, fullscreenQuad.positionsBuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(float3) * verticesNumber, quadPositions, GL_STATIC_DRAW); + + const float2 quadTexcoords[] = + { + { 1.0f, 1.0f }, + { 0.0f, 1.0f }, + { 0.0f, 0.0f }, + { 1.0f, 0.0f }, + }; + if (!fullscreenQuad.texcoordsBuffer) { + glGenBuffers(1, &fullscreenQuad.texcoordsBuffer); + } + glBindBuffer(GL_ARRAY_BUFFER, fullscreenQuad.texcoordsBuffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(float2) * verticesNumber, quadTexcoords, GL_STATIC_DRAW); + + const u8 quadIndices[] = + { + 0, 1, 2, + 0, 2, 3, + }; + if (!fullscreenQuad.indexBuffer) { + glGenBuffers(1, &fullscreenQuad.indexBuffer); + } + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, fullscreenQuad.indexBuffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(u8) * indicesNumber, quadIndices, GL_STATIC_DRAW); + + // Unbind + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} + +void bindDefaultAttribLocations(GLuint program) +{ + //bind vertex attribute to vbo inputs + glBindAttribLocation(program, VERTEX_POS_ARRAY, "in_pos"); + glBindAttribLocation(program, VERTEX_COL_BASE_ARRAY, "in_base"); + glBindAttribLocation(program, VERTEX_COL_OFFS_ARRAY, "in_offs"); + glBindAttribLocation(program, VERTEX_UV_ARRAY, "in_uv"); + +#ifndef GLES + glBindFragDataLocation(program, 0, "FragColor"); +#endif +} + bool CompilePipelineShader( PipelineShader* s) { char pshader[8192]; @@ -836,7 +918,7 @@ bool CompilePipelineShader( PipelineShader* s) s->cp_AlphaTest,s->pp_ClipTestMode,s->pp_UseAlpha, s->pp_Texture,s->pp_IgnoreTexA,s->pp_ShadInstr,s->pp_Offset,s->pp_FogCtrl); - s->program=gl_CompileAndLink(VertexShaderSource,pshader); + s->program = gl_CompileAndLink(VertexShaderSource, pshader, bindDefaultAttribLocations); //setup texture 0 as the input for the shader @@ -940,20 +1022,22 @@ bool gl_create_resources() } } - - - gl.modvol_shader.program=gl_CompileAndLink(VertexShaderSource,ModifierVolumeShader); + gl.modvol_shader.program = gl_CompileAndLink(VertexShaderSource, ModifierVolumeShader, bindDefaultAttribLocations); gl.modvol_shader.scale = glGetUniformLocation(gl.modvol_shader.program, "scale"); gl.modvol_shader.sp_ShaderColor = glGetUniformLocation(gl.modvol_shader.program, "sp_ShaderColor"); gl.modvol_shader.depth_scale = glGetUniformLocation(gl.modvol_shader.program, "depth_scale"); - - gl.OSD_SHADER.program=gl_CompileAndLink(VertexShaderSource,OSD_Shader); + gl.OSD_SHADER.program = gl_CompileAndLink(VertexShaderSource, OSD_Shader, bindDefaultAttribLocations); printf("OSD: %d\n",gl.OSD_SHADER.program); gl.OSD_SHADER.scale=glGetUniformLocation(gl.OSD_SHADER.program, "scale"); gl.OSD_SHADER.depth_scale=glGetUniformLocation(gl.OSD_SHADER.program, "depth_scale"); glUniform1i(glGetUniformLocation(gl.OSD_SHADER.program, "tex"),0); //bind osd texture to slot 0 + if (!gl.fullscreenQuadShader) { + gl.fullscreenQuadShader = gl_CompileAndLink(FullscreenQuadVertexShader, FullscreenQuadFragmentShader); + generateFullscreenQuadVertices(); + } + //#define PRECOMPILE_SHADERS #ifdef PRECOMPILE_SHADERS for (u32 i=0;i