Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-09 07:49:37

0001 #pragma once
0002 /**
0003 SGLDisplay.h : OpenGL shader pipeline that presents PBO to screen
0004 ==================================================================
0005 
0006 
0007 **/
0008 
0009 #include <cstdio>
0010 #include <cstdint>
0011 #include <string>
0012 #include <iostream>
0013 
0014 struct SGLDisplay
0015 {
0016     enum BufferImageFormat
0017     {
0018         UNSIGNED_BYTE4,
0019         FLOAT4,
0020         FLOAT3
0021     };
0022 
0023     static GLuint CreateGLShader( const char* source, GLuint shader_type );
0024     static GLuint CreateGLProgram( const char* vert_source, const char* frag_source ); 
0025     static size_t PixelFormatSize( BufferImageFormat format ); 
0026     static int PixelUnpackAlignment( size_t elmt_size ); 
0027 
0028     SGLDisplay(BufferImageFormat format = UNSIGNED_BYTE4);
0029     void init(); 
0030     std::string desc() const ; 
0031 
0032     void display(
0033             const int32_t  screen_res_x,
0034             const int32_t  screen_res_y,
0035             const int32_t  framebuf_res_x,
0036             const int32_t  framebuf_res_y,
0037             const uint32_t pbo,
0038             bool dump = false 
0039            );
0040 
0041     BufferImageFormat m_image_format;
0042     size_t  m_elmt_size ; 
0043     int     m_unpack_alignment ; 
0044     size_t  m_count ; 
0045 
0046     GLuint   m_render_tex = 0u;
0047     GLuint   m_program = 0u;
0048     GLint    m_render_tex_uniform_loc = -1;
0049     GLuint   m_quad_vertex_buffer = 0;
0050 
0051     static constexpr const char* s_vert_source = R"(
0052 #version 330 core
0053 
0054 // transforms ndc (-1:1,-1:1) "vertexPosition_modelspace"  to tex coords (0:1,0:1 ) "UV"
0055 
0056 layout(location = 0) in vec3 vertexPosition_modelspace;
0057 out vec2 UV;
0058 
0059 void main()
0060 {
0061     gl_Position =  vec4(vertexPosition_modelspace,1);
0062     UV = (vec2( vertexPosition_modelspace.x, vertexPosition_modelspace.y )+vec2(1,1))/2.0;
0063 }
0064 )";
0065 
0066     static constexpr const char* s_frag_source = R"(
0067 #version 330 core
0068 
0069 // samples texture at UV coordinate
0070 
0071 in vec2 UV;
0072 out vec3 color;
0073 
0074 uniform sampler2D render_tex;
0075 
0076 void main()
0077 {
0078     color = texture( render_tex, UV ).xyz;
0079 }
0080 )";
0081 
0082 
0083     static constexpr const char* s_frag_source_with_FragDepth = R"(
0084 #version 330 core
0085 
0086 // samples texture at UV coordinate
0087 
0088 in vec2 UV;
0089 out vec3 color;
0090 
0091 uniform sampler2D render_tex;
0092 
0093 void main()
0094 {
0095     vec4 pixel = texture( render_tex, UV ).xyzw ;
0096     color = pixel.xyz ; 
0097     gl_FragDepth = pixel.w ; 
0098 }
0099 )";
0100 
0101 
0102 
0103 
0104 
0105 
0106 };
0107 
0108 /**
0109 SGLDisplay::CreateGLShader
0110 ---------------------------
0111 
0112 Compile shader from provided source string
0113 
0114 **/
0115 
0116 inline GLuint SGLDisplay::CreateGLShader( const char* source, GLuint shader_type ) // static
0117 {
0118     GLuint shader = glCreateShader( shader_type );
0119     {
0120         const GLchar* source_data= reinterpret_cast<const GLchar*>( source );
0121         glShaderSource( shader, 1, &source_data, nullptr );
0122         glCompileShader( shader );
0123 
0124         GLint is_compiled = 0;
0125         glGetShaderiv( shader, GL_COMPILE_STATUS, &is_compiled );
0126         if( is_compiled == GL_FALSE )
0127         {
0128             GLint max_length = 0;
0129             glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &max_length );
0130             std::string info_log( max_length, '\0' );
0131             GLchar* info_log_data= reinterpret_cast<GLchar*>( &info_log[0]);
0132             glGetShaderInfoLog( shader, max_length, nullptr, info_log_data );
0133 
0134             glDeleteShader(shader);
0135             std::cerr << "Compilation of shader failed: " << info_log << std::endl;
0136 
0137             return 0;
0138         }
0139         GL_CHECK_ERRORS();
0140     } 
0141     return shader;
0142 }
0143 
0144 /**
0145 SGLDisplay::CreateGLProgram
0146 -----------------------------
0147 
0148 Create pipeline from vertex and fragment shader sources
0149 
0150 **/
0151 
0152 
0153 inline GLuint SGLDisplay::CreateGLProgram( const char* vert_source, const char* frag_source ) // static
0154 {
0155     GLuint vert_shader = CreateGLShader( vert_source, GL_VERTEX_SHADER );
0156     if(vert_shader == 0) return 0;
0157 
0158     GLuint frag_shader = CreateGLShader( frag_source, GL_FRAGMENT_SHADER );
0159     if(frag_shader == 0)
0160     {
0161         glDeleteShader( vert_shader );
0162         return 0;
0163     }
0164 
0165     GLuint program = glCreateProgram();
0166     glAttachShader( program, vert_shader );
0167     glAttachShader( program, frag_shader );
0168     glLinkProgram( program );
0169 
0170     GLint is_linked = 0;
0171     glGetProgramiv( program, GL_LINK_STATUS, &is_linked );
0172     if (is_linked == GL_FALSE)
0173     {
0174         GLint max_length = 0;
0175         glGetProgramiv( program, GL_INFO_LOG_LENGTH, &max_length );
0176 
0177         std::string info_log( max_length, '\0' );
0178         GLchar* info_log_data= reinterpret_cast<GLchar*>( &info_log[0]);
0179         glGetProgramInfoLog( program, max_length, nullptr, info_log_data );
0180         std::cerr << "Linking of program failed: " << info_log << std::endl;
0181 
0182         glDeleteProgram( program );
0183         glDeleteShader( vert_shader );
0184         glDeleteShader( frag_shader );
0185 
0186         return 0;
0187     }
0188 
0189     glDetachShader( program, vert_shader );
0190     glDetachShader( program, frag_shader );
0191 
0192     GL_CHECK_ERRORS();
0193 
0194     return program;
0195 }
0196 
0197 
0198 inline size_t SGLDisplay::PixelFormatSize( BufferImageFormat format ) // static
0199 {
0200     switch( format )
0201     {    
0202         case UNSIGNED_BYTE4: return sizeof( char ) * 4; 
0203         case FLOAT3:         return sizeof( float ) * 3; 
0204         case FLOAT4:         return sizeof( float ) * 4; 
0205         default:
0206             throw std::runtime_error( "SGLDisplay::PixelFormatSize: Unrecognized buffer format" );
0207     }    
0208 }
0209 
0210 inline int SGLDisplay::PixelUnpackAlignment( size_t elmt_size ) // static
0211 {
0212     int unpack_alignment = 1 ; 
0213     if      ( elmt_size % 8 == 0) unpack_alignment = 8 ; 
0214     else if ( elmt_size % 4 == 0) unpack_alignment = 4 ; 
0215     else if ( elmt_size % 2 == 0) unpack_alignment = 2 ; 
0216     else                          unpack_alignment = 1 ; 
0217     return unpack_alignment ; 
0218 }
0219 
0220 
0221 
0222 
0223 /**
0224 SGLDisplay::SGLDisplay
0225 -----------------------
0226 
0227 **/
0228 
0229 inline SGLDisplay::SGLDisplay( BufferImageFormat image_format )
0230     : 
0231     m_image_format(image_format),
0232     m_elmt_size(PixelFormatSize( m_image_format )),
0233     m_unpack_alignment(PixelUnpackAlignment( m_elmt_size )),
0234     m_count(0)
0235 {
0236     init(); 
0237 }
0238 
0239 
0240 /**
0241 SGLDisplay::init
0242 -----------------
0243 
0244 1. binds Vertex Array m_vertex_array 
0245 2. creates shader pipeline m_program  
0246 3. binds and configures m_render_tex GL_TEXTURE_2D
0247 4. binds m_quad_vertex_buffer GL_ARRAY_BUFFER 
0248    and uploads vertices of two triangles forming a [-1:1,-1:1] quad
0249 
0250 **/
0251 
0252 inline void SGLDisplay::init()
0253 {
0254     GLuint m_vertex_array;
0255     GL_CHECK( glGenVertexArrays(1, &m_vertex_array ) );
0256     GL_CHECK( glBindVertexArray( m_vertex_array ) );
0257 
0258     //m_program = CreateGLProgram( s_vert_source, s_frag_source );
0259     m_program = CreateGLProgram( s_vert_source, s_frag_source_with_FragDepth );
0260 
0261     m_render_tex_uniform_loc = glGetUniformLocation( m_program, "render_tex" );
0262     assert( m_render_tex_uniform_loc > -1 ); 
0263 
0264     GL_CHECK( glGenTextures( 1, &m_render_tex ) );
0265     GL_CHECK( glBindTexture( GL_TEXTURE_2D, m_render_tex ) );
0266 
0267     GL_CHECK( glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ) );
0268     GL_CHECK( glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ) );
0269     GL_CHECK( glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ) );
0270     GL_CHECK( glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ) );
0271 
0272     static const GLfloat g_quad_vertex_buffer_data[] = {
0273         -1.0f, -1.0f, 0.0f,
0274          1.0f, -1.0f, 0.0f,
0275         -1.0f,  1.0f, 0.0f,
0276 
0277         -1.0f,  1.0f, 0.0f,
0278          1.0f, -1.0f, 0.0f,
0279          1.0f,  1.0f, 0.0f,
0280     };
0281 
0282     GL_CHECK( glGenBuffers( 1, &m_quad_vertex_buffer ) );
0283     GL_CHECK( glBindBuffer( GL_ARRAY_BUFFER, m_quad_vertex_buffer ) );
0284     GL_CHECK( glBufferData( GL_ARRAY_BUFFER,
0285                 sizeof( g_quad_vertex_buffer_data),
0286                 g_quad_vertex_buffer_data,
0287                 GL_STATIC_DRAW
0288                 )
0289             );
0290 
0291     GL_CHECK_ERRORS();
0292 }
0293 
0294 inline std::string SGLDisplay::desc() const
0295 {
0296     std::stringstream ss ; 
0297     ss << "SGLDisplay::desc"
0298        << std::endl 
0299        << " int(m_image_format) " << int(m_image_format)
0300        << std::endl 
0301        << " m_elmt_size " << m_elmt_size 
0302        << std::endl 
0303        << " m_unpack_alignment " << m_unpack_alignment
0304        << std::endl 
0305        << " m_count " << m_count
0306        << std::endl 
0307        << " m_render_tex " << m_render_tex
0308        << std::endl 
0309        << " m_program "
0310        << std::endl 
0311        << " m_render_tex_uniform_loc " << m_render_tex_uniform_loc
0312        << std::endl 
0313        << " m_quad_vertex_buffer " << m_quad_vertex_buffer
0314        << std::endl 
0315        ;
0316     std::string str = ss.str(); 
0317     return str ; 
0318 }
0319 
0320 /**
0321 SGLDisplay::display
0322 --------------------
0323 
0324 Arranges for the PBO buffer contents to be viewed as a texture
0325 and accessed via samplers in shaders.
0326 
0327 1. bind GL_FRAMEBUFFER to 0 (break any bind, return to screen rendering)
0328 2. set viewport to (framebuf_res_x, framebuf_res_y) 
0329 3. bind GL_TEXTURE_2D m_render_tex
0330 4. configure GL_PIXEL_UNPACK_BUFFER unpacking 
0331 5. invoke glTexImage2D using (screen_res_x, screen_res_y) 
0332    which enables shaders to access the texture
0333 
0334    * note that nullptr data, because GL_PIXEL_UNPACK_BUFFER
0335      is bound the pbo acts as the source of the texture data 
0336      and the data arg is just an offset 
0337 
0338 6. configure vertex array access from shader
0339 7. draw the two triangles of the quad displaying PBO data
0340    via viewing it as a texture 
0341 
0342  
0343 glTexImage2D 
0344    specifies mutable texture storage characteristics and provides the data
0345   
0346    *internalFormat* 
0347         format with which OpenGL should store the texels in the texture
0348 
0349    *data*
0350         location of the initial texel data in host memory, 
0351         **if a buffer is bound to the GL_PIXEL_UNPACK_BUFFER binding point, 
0352         texel data is read from that buffer object, and *data* is interpreted 
0353         as an offset into that buffer object from which to read the data**
0354 
0355     *format* and *type*
0356          initial source texel data layout which OpenGL will convert 
0357          to the internalFormat
0358 
0359 **/
0360 
0361 inline void SGLDisplay::display(
0362         const int32_t  screen_res_x,
0363         const int32_t  screen_res_y,
0364         const int32_t  framebuf_res_x,
0365         const int32_t  framebuf_res_y,
0366         const uint32_t pbo,
0367         bool dump
0368         ) 
0369 {
0370     if(dump) printf("[ SGLDisplay::display count %zu framebuf_res_x %d framebuf_res_y %d  \n", m_count,framebuf_res_x, framebuf_res_y  ); 
0371 
0372     GL_CHECK( glBindFramebuffer( GL_FRAMEBUFFER, 0 ) ); 
0373     // "FBO" name:0 means break the bind : so that typically 
0374     // means switch to default rendering to the screen 
0375     // https://learnopengl.com/Advanced-OpenGL/Framebuffers
0376 
0377     GL_CHECK( glViewport( 0, 0, framebuf_res_x, framebuf_res_y ) );
0378     GL_CHECK( glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) );
0379     GL_CHECK( glUseProgram( m_program ) );
0380 
0381     // Bind our texture in Texture Unit 0
0382     GL_CHECK( glActiveTexture( GL_TEXTURE0 ) );
0383     GL_CHECK( glBindTexture( GL_TEXTURE_2D, m_render_tex ) );
0384     GL_CHECK( glBindBuffer( GL_PIXEL_UNPACK_BUFFER, pbo ) );
0385     GL_CHECK( glPixelStorei(GL_UNPACK_ALIGNMENT, m_unpack_alignment ) ); 
0386 
0387     bool convertToSrgb = true;
0388 
0389     if( m_image_format == BufferImageFormat::UNSIGNED_BYTE4 )
0390     {
0391         // input is assumed to be in srgb since it is only 1 byte per channel in size
0392         glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8,   screen_res_x, screen_res_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr );
0393         convertToSrgb = false;
0394     }
0395     else if( m_image_format == BufferImageFormat::FLOAT3 )
0396     {
0397         glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB32F,  screen_res_x, screen_res_y, 0, GL_RGB,  GL_FLOAT,         nullptr );
0398     }
0399     else if( m_image_format == BufferImageFormat::FLOAT4 )
0400     {
0401         glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA32F, screen_res_x, screen_res_y, 0, GL_RGBA, GL_FLOAT,         nullptr );
0402     }
0403     else
0404     {
0405         throw std::runtime_error( "Unknown buffer format" );
0406     }
0407 
0408     GL_CHECK( glBindBuffer( GL_PIXEL_UNPACK_BUFFER, 0 ) );
0409     GL_CHECK( glUniform1i( m_render_tex_uniform_loc , 0 ) );
0410 
0411     // 1st attribute buffer : vertices
0412     GL_CHECK( glEnableVertexAttribArray( 0 ) );
0413     GL_CHECK( glBindBuffer(GL_ARRAY_BUFFER, m_quad_vertex_buffer ) );
0414     GL_CHECK( glVertexAttribPointer(
0415             0,                  // attribute 0. No particular reason for 0, but must match the layout in the shader.
0416             3,                  // size
0417             GL_FLOAT,           // type
0418             GL_FALSE,           // normalized?
0419             0,                  // stride
0420             (void*)0            // array buffer offset
0421             )
0422         );
0423 
0424     if( convertToSrgb )
0425         GL_CHECK( glEnable( GL_FRAMEBUFFER_SRGB ) );
0426     else 
0427         GL_CHECK( glDisable( GL_FRAMEBUFFER_SRGB ) );
0428 
0429     // Draw the triangles !
0430     GL_CHECK( glDrawArrays(GL_TRIANGLES, 0, 6) ); // 2*3 indices starting at 0 -> 2 triangles
0431 
0432     GL_CHECK( glDisableVertexAttribArray(0) );
0433 
0434     GL_CHECK( glDisable( GL_FRAMEBUFFER_SRGB ) );
0435 
0436     if(dump) printf("] SGLDisplay::display %zu \n", m_count ); 
0437     m_count++ ; 
0438     GL_CHECK_ERRORS();
0439 }
0440