Single pass subpixel rendering in OpenGL 2 context.

Fix unit-tests build issue.
This commit is contained in:
Martín Lucas Golini
2026-07-26 01:02:06 -03:00
parent 0bf2b89970
commit fac6c4ab05
10 changed files with 143 additions and 2 deletions
+2
View File
@@ -44,6 +44,8 @@ typedef void( APIENTRY* pglBlendFuncSeparate )( GLenum sfactorRGB, GLenum dfacto
typedef void( APIENTRY* pglDiscardFramebufferEXT )( GLenum target, GLsizei numAttachments,
const GLenum* attachments );
typedef void( APIENTRY* pglBlendEquationSeparate )( GLenum modeRGB, GLenum modeAlpha );
typedef void( APIENTRY* pglBindFragDataLocationIndexed )( GLuint program, GLuint colorNumber,
GLuint index, const GLchar* name );
typedef void( APIENTRY* pglBlitFramebufferEXT )( GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter );
+27
View File
@@ -260,6 +260,8 @@ void Renderer::init() {
writeExtension( EEGL_EXT_blend_func_separate, GLEW_EXT_blend_func_separate );
writeExtension( EEGL_EXT_blend_minmax, GLEW_EXT_blend_minmax );
writeExtension( EEGL_EXT_blend_subtract, GLEW_EXT_blend_subtract );
writeExtension( EEGL_ARB_blend_func_extended,
GLEW_ARB_blend_func_extended || GLEW_VERSION_3_3 );
} else
#endif
{
@@ -296,6 +298,9 @@ void Renderer::init() {
glVersion >= 140 || isExtension( "GL_EXT_blend_minmax" ) );
writeExtension( EEGL_EXT_blend_subtract,
glVersion >= 140 || isExtension( "GL_EXT_blend_subtract" ) );
writeExtension( EEGL_ARB_blend_func_extended,
!is_es &&
( glVersion >= 330 || isExtension( "GL_ARB_blend_func_extended" ) ) );
}
// NVIDIA added support for GL_OES_compressed_ETC1_RGB8_texture in desktop GPUs
@@ -477,6 +482,9 @@ void Renderer::drawArrays( unsigned int mode, int first, int count ) {
}
bool Renderer::drawSubpixelArrays( unsigned int mode, int first, int count ) {
if ( drawSubpixelDualSourceArrays( mode, first, count ) )
return true;
if ( !setTextureColorMode( 1 ) )
return false;
@@ -497,6 +505,10 @@ bool Renderer::drawSubpixelArrays( unsigned int mode, int first, int count ) {
return true;
}
bool Renderer::drawSubpixelDualSourceArrays( unsigned int, int, int ) {
return false;
}
bool Renderer::drawSubpixelFallbackArrays( unsigned int mode, int first, int count ) {
if ( !setTextureColorMode( 4 ) )
return false;
@@ -563,6 +575,21 @@ void Renderer::blendEquationSeparate( unsigned int modeRGB, unsigned int modeAlp
eeglBlendEquationSeparate( modeRGB, modeAlpha );
}
bool Renderer::bindFragDataLocationIndexed( unsigned int program, unsigned int colorNumber,
unsigned int index, const char* name ) {
#ifndef EE_GLES
static pglBindFragDataLocationIndexed bindFragDataLocationIndexed = NULL;
if ( NULL == bindFragDataLocationIndexed )
bindFragDataLocationIndexed =
(pglBindFragDataLocationIndexed)getProcAddress( "glBindFragDataLocationIndexed" );
if ( NULL != bindFragDataLocationIndexed ) {
bindFragDataLocationIndexed( program, colorNumber, index, name );
return true;
}
#endif
return false;
}
void Renderer::blitFrameBuffer( int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0,
int dstX1, int dstY1, unsigned int mask, unsigned int filter ) {
static pglBlitFramebufferEXT eeglBlitFramebufferEXT = NULL;
+68
View File
@@ -1,3 +1,4 @@
#include <eepp/graphics/blendmode.hpp>
#include <eepp/graphics/renderer/openglext.hpp>
#include <eepp/graphics/renderer/renderergl.hpp>
@@ -107,6 +108,73 @@ void main() {
#endif
}
bool RendererGL::ensureSubpixelDualSourceShader() {
#ifndef EE_GLES1
if ( mSubpixelDualSourceShader )
return true;
if ( mSubpixelDualSourceShaderInitializationAttempted ||
!isExtension( EEGL_ARB_blend_func_extended ) || !shadersSupported() )
return false;
mSubpixelDualSourceShaderInitializationAttempted = true;
static const char vertexShader[] = R"(
#version 130
varying vec4 dgl_Color;
varying vec2 dgl_TexCoord;
void main() {
gl_Position = ftransform();
gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;
dgl_Color = gl_Color;
dgl_TexCoord = ( gl_TextureMatrix[0] * gl_MultiTexCoord0 ).xy;
}
)";
static const char fragmentShader[] = R"(
#version 130
uniform sampler2D textureUnit0;
varying vec4 dgl_Color;
varying vec2 dgl_TexCoord;
out vec4 dgl_FragColor;
out vec4 dgl_FragCoverage;
void main() {
vec3 coverage = texture2D( textureUnit0, dgl_TexCoord ).rgb;
float meanCoverage = dot( coverage, vec3( 1.0 / 3.0 ) );
dgl_FragColor = vec4( dgl_Color.rgb, dgl_Color.a * meanCoverage );
dgl_FragCoverage = vec4( dgl_Color.a * coverage, 0.0 );
}
)";
ShaderProgramPtr shader = ShaderProgram::New( "eepp-subpixel-dual-source-text" );
ShaderPtr vs( eeNew( VertexShader, ( vertexShader, sizeof( vertexShader ) - 1 ) ),
ResourceDeleter<Shader>() );
ShaderPtr fs( eeNew( FragmentShader, ( fragmentShader, sizeof( fragmentShader ) - 1 ) ),
ResourceDeleter<Shader>() );
if ( shader && vs->isValid() && fs->isValid() ) {
shader->addShader( std::move( vs ) );
shader->addShader( std::move( fs ) );
if ( shader->bindFragDataLocationIndexed( 0, 0, "dgl_FragColor" ) &&
shader->bindFragDataLocationIndexed( 0, 1, "dgl_FragCoverage" ) && shader->link() ) {
mSubpixelDualSourceShader = std::move( shader );
Renderer::setShader( mSubpixelDualSourceShader.get() );
mSubpixelDualSourceShader->setUniform( "textureUnit0", 0 );
Renderer::setShader( mPreviousShader );
}
}
return !!mSubpixelDualSourceShader;
#else
return false;
#endif
}
bool RendererGL::drawSubpixelDualSourceArrays( unsigned int mode, int first, int count ) {
if ( !ensureSubpixelDualSourceShader() )
return false;
const BlendMode previousBlendMode = BlendMode::getPreBlendFunc();
Renderer::setShader( mSubpixelDualSourceShader.get() );
blendFuncSeparate( GL_SRC1_COLOR, GL_ONE_MINUS_SRC1_COLOR, GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
drawArrays( mode, first, count );
BlendMode::setMode( previousBlendMode, true );
Renderer::setShader( mPreviousShader );
return true;
}
void RendererGL::setShader( ShaderProgram* shader ) {
if ( !mUsingSubpixelShader )
mPreviousShader = shader;
+11
View File
@@ -231,8 +231,19 @@ void ShaderProgram::addShaders( const std::vector<ShaderPtr>& shaders ) {
addShader( shader );
}
bool ShaderProgram::bindFragDataLocationIndexed( Uint32 colorNumber, Uint32 index,
const char* name ) {
if ( !GLi->bindFragDataLocationIndexed( getHandler(), colorNumber, index, name ) )
return false;
mFragmentOutputBindings.push_back( { colorNumber, index, name } );
return true;
}
bool ShaderProgram::link() {
#ifdef EE_SHADERS_SUPPORTED
for ( const auto& binding : mFragmentOutputBindings )
GLi->bindFragDataLocationIndexed( getHandler(), binding.colorNumber, binding.index,
binding.name.c_str() );
GLi->linkProgram( getHandler() );
Int32 linked;
+4 -2
View File
@@ -130,8 +130,10 @@ UTEST( FontRendering, subpixelCoverageCompositesPerChannel ) {
for ( Uint32 y = top; y < bottom; ++y ) {
for ( Uint32 x = 0; x < image.getWidth(); ++x ) {
Color pixel = image.getPixel( x, y );
if ( eeabs( static_cast<Int32>( pixel.r ) - static_cast<Int32>( pixel.g ) ) > 3 ||
eeabs( static_cast<Int32>( pixel.g ) - static_cast<Int32>( pixel.b ) ) > 3 )
const Int32 redGreenDelta = static_cast<Int32>( pixel.r ) - pixel.g;
const Int32 greenBlueDelta = static_cast<Int32>( pixel.g ) - pixel.b;
if ( ( redGreenDelta < 0 ? -redGreenDelta : redGreenDelta ) > 3 ||
( greenBlueDelta < 0 ? -greenBlueDelta : greenBlueDelta ) > 3 )
return true;
}
}