File indexing completed on 2026-04-09 07:49:37
0001 #pragma once
0002
0003
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
0110
0111
0112
0113
0114
0115
0116 inline GLuint SGLDisplay::CreateGLShader( const char* source, GLuint shader_type )
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
0146
0147
0148
0149
0150
0151
0152
0153 inline GLuint SGLDisplay::CreateGLProgram( const char* vert_source, const char* frag_source )
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 )
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 )
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
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
0242
0243
0244
0245
0246
0247
0248
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
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
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
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
0374
0375
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
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
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
0412 GL_CHECK( glEnableVertexAttribArray( 0 ) );
0413 GL_CHECK( glBindBuffer(GL_ARRAY_BUFFER, m_quad_vertex_buffer ) );
0414 GL_CHECK( glVertexAttribPointer(
0415 0,
0416 3,
0417 GL_FLOAT,
0418 GL_FALSE,
0419 0,
0420 (void*)0
0421 )
0422 );
0423
0424 if( convertToSrgb )
0425 GL_CHECK( glEnable( GL_FRAMEBUFFER_SRGB ) );
0426 else
0427 GL_CHECK( glDisable( GL_FRAMEBUFFER_SRGB ) );
0428
0429
0430 GL_CHECK( glDrawArrays(GL_TRIANGLES, 0, 6) );
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