@ -14,6 +14,7 @@
// CHANGELOG
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// (minor and older changes stripped away, please see git history for details)
// 2022-09-27: OpenGL: Added ability to '#define IMGUI_IMPL_OPENGL_DEBUG'.
// 2022-05-23: OpenGL: Reworking 2021-12-15 "Using buffer orphaning" so it only happens on Intel GPU, seems to cause problems otherwise. (#4468, #4825, #4832, #5127).
// 2022-05-23: OpenGL: Reworking 2021-12-15 "Using buffer orphaning" so it only happens on Intel GPU, seems to cause problems otherwise. (#4468, #4825, #4832, #5127).
// 2022-05-13: OpenGL: Fix state corruption on OpenGL ES 2.0 due to not preserving GL_ELEMENT_ARRAY_BUFFER_BINDING and vertex attribute states.
// 2022-05-13: OpenGL: Fix state corruption on OpenGL ES 2.0 due to not preserving GL_ELEMENT_ARRAY_BUFFER_BINDING and vertex attribute states.
// 2021-12-15: OpenGL: Using buffer orphaning + glBufferSubData(), seems to fix leaks with multi-viewports with some Intel HD drivers.
// 2021-12-15: OpenGL: Using buffer orphaning + glBufferSubData(), seems to fix leaks with multi-viewports with some Intel HD drivers.
@ -178,6 +179,15 @@
# define IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS
# define IMGUI_IMPL_OPENGL_MAY_HAVE_EXTENSIONS
# endif
# endif
// [Debugging]
//#define IMGUI_IMPL_OPENGL_DEBUG
# ifdef IMGUI_IMPL_OPENGL_DEBUG
# include <stdio.h>
# define GL_CALL(_CALL) do { _CALL; GLenum gl_err = glGetError(); if (gl_err != 0) fprintf(stderr, "GL error 0x%x returned from '%s'.\n", gl_err, #_CALL); } while (0) // Call with error check
# else
# define GL_CALL(_CALL) _CALL // Call without error check
# endif
// OpenGL Data
// OpenGL Data
struct ImGui_ImplOpenGL3_Data
struct ImGui_ImplOpenGL3_Data
{
{
@ -270,11 +280,14 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
if ( strncmp ( vendor , " Intel " , 5 ) = = 0 )
if ( strncmp ( vendor , " Intel " , 5 ) = = 0 )
bd - > UseBufferSubData = true ;
bd - > UseBufferSubData = true ;
# endif
# endif
//printf("GL_MAJOR_VERSION = %d\nGL_MINOR_VERSION = %d\nGL_VENDOR = '%s'\nGL_RENDERER = '%s'\n", major, minor, (const char*)glGetString(GL_VENDOR), (const char*)glGetString(GL_RENDERER)); // [DEBUG]
# else
# else
bd - > GlVersion = 200 ; // GLES 2
bd - > GlVersion = 200 ; // GLES 2
# endif
# endif
# ifdef IMGUI_IMPL_OPENGL_DEBUG
printf ( " GL_MAJOR_VERSION = %d \n GL_MINOR_VERSION = %d \n GL_VENDOR = '%s' \n GL_RENDERER = '%s' \n " , major , minor , ( const char * ) glGetString ( GL_VENDOR ) , ( const char * ) glGetString ( GL_RENDERER ) ) ; // [DEBUG]
# endif
# ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
# ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
if ( bd - > GlVersion > = 320 )
if ( bd - > GlVersion > = 320 )
io . BackendFlags | = ImGuiBackendFlags_RendererHasVtxOffset ; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
io . BackendFlags | = ImGuiBackendFlags_RendererHasVtxOffset ; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
@ -373,7 +386,7 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid
// Setup viewport, orthographic projection matrix
// Setup viewport, orthographic projection matrix
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
glViewport ( 0 , 0 , ( GLsizei ) fb_width , ( GLsizei ) fb_height ) ;
GL_CALL ( glViewport ( 0 , 0 , ( GLsizei ) fb_width , ( GLsizei ) fb_height ) ) ;
float L = draw_data - > DisplayPos . x ;
float L = draw_data - > DisplayPos . x ;
float R = draw_data - > DisplayPos . x + draw_data - > DisplaySize . x ;
float R = draw_data - > DisplayPos . x + draw_data - > DisplaySize . x ;
float T = draw_data - > DisplayPos . y ;
float T = draw_data - > DisplayPos . y ;
@ -403,14 +416,14 @@ static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_wid
# endif
# endif
// Bind vertex/index buffers and setup attributes for ImDrawVert
// Bind vertex/index buffers and setup attributes for ImDrawVert
glBindBuffer ( GL_ARRAY_BUFFER , bd - > VboHandle ) ;
GL_CALL ( glBindBuffer ( GL_ARRAY_BUFFER , bd - > VboHandle ) ) ;
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , bd - > ElementsHandle ) ;
GL_CALL ( glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , bd - > ElementsHandle ) ) ;
glEnableVertexAttribArray ( bd - > AttribLocationVtxPos ) ;
GL_CALL ( glEnableVertexAttribArray ( bd - > AttribLocationVtxPos ) ) ;
glEnableVertexAttribArray ( bd - > AttribLocationVtxUV ) ;
GL_CALL ( glEnableVertexAttribArray ( bd - > AttribLocationVtxUV ) ) ;
glEnableVertexAttribArray ( bd - > AttribLocationVtxColor ) ;
GL_CALL ( glEnableVertexAttribArray ( bd - > AttribLocationVtxColor ) ) ;
glVertexAttribPointer ( bd - > AttribLocationVtxPos , 2 , GL_FLOAT , GL_FALSE , sizeof ( ImDrawVert ) , ( GLvoid * ) IM_OFFSETOF ( ImDrawVert , pos ) ) ;
GL_CALL ( glVertexAttribPointer ( bd - > AttribLocationVtxPos , 2 , GL_FLOAT , GL_FALSE , sizeof ( ImDrawVert ) , ( GLvoid * ) IM_OFFSETOF ( ImDrawVert , pos ) ) ) ;
glVertexAttribPointer ( bd - > AttribLocationVtxUV , 2 , GL_FLOAT , GL_FALSE , sizeof ( ImDrawVert ) , ( GLvoid * ) IM_OFFSETOF ( ImDrawVert , uv ) ) ;
GL_CALL ( glVertexAttribPointer ( bd - > AttribLocationVtxUV , 2 , GL_FLOAT , GL_FALSE , sizeof ( ImDrawVert ) , ( GLvoid * ) IM_OFFSETOF ( ImDrawVert , uv ) ) ) ;
glVertexAttribPointer ( bd - > AttribLocationVtxColor , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( ImDrawVert ) , ( GLvoid * ) IM_OFFSETOF ( ImDrawVert , col ) ) ;
GL_CALL ( glVertexAttribPointer ( bd - > AttribLocationVtxColor , 4 , GL_UNSIGNED_BYTE , GL_TRUE , sizeof ( ImDrawVert ) , ( GLvoid * ) IM_OFFSETOF ( ImDrawVert , col ) ) ) ;
}
}
// OpenGL3 Render function.
// OpenGL3 Render function.
@ -470,7 +483,7 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
// The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
// The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
GLuint vertex_array_object = 0 ;
GLuint vertex_array_object = 0 ;
# ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
# ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
glGenVertexArrays ( 1 , & vertex_array_object ) ;
GL_CALL ( glGenVertexArrays ( 1 , & vertex_array_object ) ) ;
# endif
# endif
ImGui_ImplOpenGL3_SetupRenderState ( draw_data , fb_width , fb_height , vertex_array_object ) ;
ImGui_ImplOpenGL3_SetupRenderState ( draw_data , fb_width , fb_height , vertex_array_object ) ;
@ -494,20 +507,20 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
if ( bd - > VertexBufferSize < vtx_buffer_size )
if ( bd - > VertexBufferSize < vtx_buffer_size )
{
{
bd - > VertexBufferSize = vtx_buffer_size ;
bd - > VertexBufferSize = vtx_buffer_size ;
glBufferData ( GL_ARRAY_BUFFER , bd - > VertexBufferSize , NULL , GL_STREAM_DRAW ) ;
GL_CALL ( glBufferData ( GL_ARRAY_BUFFER , bd - > VertexBufferSize , NULL , GL_STREAM_DRAW ) ) ;
}
}
if ( bd - > IndexBufferSize < idx_buffer_size )
if ( bd - > IndexBufferSize < idx_buffer_size )
{
{
bd - > IndexBufferSize = idx_buffer_size ;
bd - > IndexBufferSize = idx_buffer_size ;
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , bd - > IndexBufferSize , NULL , GL_STREAM_DRAW ) ;
GL_CALL ( glBufferData ( GL_ELEMENT_ARRAY_BUFFER , bd - > IndexBufferSize , NULL , GL_STREAM_DRAW ) ) ;
}
}
glBufferSubData ( GL_ARRAY_BUFFER , 0 , vtx_buffer_size , ( const GLvoid * ) cmd_list - > VtxBuffer . Data ) ;
GL_CALL ( glBufferSubData ( GL_ARRAY_BUFFER , 0 , vtx_buffer_size , ( const GLvoid * ) cmd_list - > VtxBuffer . Data ) ) ;
glBufferSubData ( GL_ELEMENT_ARRAY_BUFFER , 0 , idx_buffer_size , ( const GLvoid * ) cmd_list - > IdxBuffer . Data ) ;
GL_CALL ( glBufferSubData ( GL_ELEMENT_ARRAY_BUFFER , 0 , idx_buffer_size , ( const GLvoid * ) cmd_list - > IdxBuffer . Data ) ) ;
}
}
else
else
{
{
glBufferData ( GL_ARRAY_BUFFER , vtx_buffer_size , ( const GLvoid * ) cmd_list - > VtxBuffer . Data , GL_STREAM_DRAW ) ;
GL_CALL ( glBufferData ( GL_ARRAY_BUFFER , vtx_buffer_size , ( const GLvoid * ) cmd_list - > VtxBuffer . Data , GL_STREAM_DRAW ) ) ;
glBufferData ( GL_ELEMENT_ARRAY_BUFFER , idx_buffer_size , ( const GLvoid * ) cmd_list - > IdxBuffer . Data , GL_STREAM_DRAW ) ;
GL_CALL ( glBufferData ( GL_ELEMENT_ARRAY_BUFFER , idx_buffer_size , ( const GLvoid * ) cmd_list - > IdxBuffer . Data , GL_STREAM_DRAW ) ) ;
}
}
for ( int cmd_i = 0 ; cmd_i < cmd_list - > CmdBuffer . Size ; cmd_i + + )
for ( int cmd_i = 0 ; cmd_i < cmd_list - > CmdBuffer . Size ; cmd_i + + )
@ -531,23 +544,23 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
continue ;
continue ;
// Apply scissor/clipping rectangle (Y is inverted in OpenGL)
// Apply scissor/clipping rectangle (Y is inverted in OpenGL)
glScissor ( ( int ) clip_min . x , ( int ) ( ( float ) fb_height - clip_max . y ) , ( int ) ( clip_max . x - clip_min . x ) , ( int ) ( clip_max . y - clip_min . y ) ) ;
GL_CALL ( glScissor ( ( int ) clip_min . x , ( int ) ( ( float ) fb_height - clip_max . y ) , ( int ) ( clip_max . x - clip_min . x ) , ( int ) ( clip_max . y - clip_min . y ) ) ) ;
// Bind texture, Draw
// Bind texture, Draw
glBindTexture ( GL_TEXTURE_2D , ( GLuint ) ( intptr_t ) pcmd - > GetTexID ( ) ) ;
GL_CALL ( glBindTexture ( GL_TEXTURE_2D , ( GLuint ) ( intptr_t ) pcmd - > GetTexID ( ) ) ) ;
# ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
# ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
if ( bd - > GlVersion > = 320 )
if ( bd - > GlVersion > = 320 )
glDrawElementsBaseVertex ( GL_TRIANGLES , ( GLsizei ) pcmd - > ElemCount , sizeof ( ImDrawIdx ) = = 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT , ( void * ) ( intptr_t ) ( pcmd - > IdxOffset * sizeof ( ImDrawIdx ) ) , ( GLint ) pcmd - > VtxOffset ) ;
GL_CALL ( glDrawElementsBaseVertex ( GL_TRIANGLES , ( GLsizei ) pcmd - > ElemCount , sizeof ( ImDrawIdx ) = = 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT , ( void * ) ( intptr_t ) ( pcmd - > IdxOffset * sizeof ( ImDrawIdx ) ) , ( GLint ) pcmd - > VtxOffset ) ) ;
else
else
# endif
# endif
glDrawElements ( GL_TRIANGLES , ( GLsizei ) pcmd - > ElemCount , sizeof ( ImDrawIdx ) = = 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT , ( void * ) ( intptr_t ) ( pcmd - > IdxOffset * sizeof ( ImDrawIdx ) ) ) ;
GL_CALL ( glDrawElements ( GL_TRIANGLES , ( GLsizei ) pcmd - > ElemCount , sizeof ( ImDrawIdx ) = = 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT , ( void * ) ( intptr_t ) ( pcmd - > IdxOffset * sizeof ( ImDrawIdx ) ) ) ) ;
}
}
}
}
}
}
// Destroy the temporary VAO
// Destroy the temporary VAO
# ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
# ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
glDeleteVertexArrays ( 1 , & vertex_array_object ) ;
GL_CALL ( glDeleteVertexArrays ( 1 , & vertex_array_object ) ) ;
# endif
# endif
// Restore modified GL state
// Restore modified GL state
@ -600,21 +613,21 @@ bool ImGui_ImplOpenGL3_CreateFontsTexture()
// Upload texture to graphics system
// Upload texture to graphics system
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
GLint last_texture ;
GLint last_texture ;
glGetIntegerv ( GL_TEXTURE_BINDING_2D , & last_texture ) ;
GL_CALL ( glGetIntegerv ( GL_TEXTURE_BINDING_2D , & last_texture ) ) ;
glGenTextures ( 1 , & bd - > FontTexture ) ;
GL_CALL ( glGenTextures ( 1 , & bd - > FontTexture ) ) ;
glBindTexture ( GL_TEXTURE_2D , bd - > FontTexture ) ;
GL_CALL ( glBindTexture ( GL_TEXTURE_2D , bd - > FontTexture ) ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
GL_CALL ( glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
GL_CALL ( glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ) ;
# ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES
# ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES
glPixelStorei ( GL_UNPACK_ROW_LENGTH , 0 ) ;
GL_CALL ( glPixelStorei ( GL_UNPACK_ROW_LENGTH , 0 ) ) ;
# endif
# endif
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , width , height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , pixels ) ;
GL_CALL ( glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , width , height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , pixels ) ) ;
// Store our identifier
// Store our identifier
io . Fonts - > SetTexID ( ( ImTextureID ) ( intptr_t ) bd - > FontTexture ) ;
io . Fonts - > SetTexID ( ( ImTextureID ) ( intptr_t ) bd - > FontTexture ) ;
// Restore state
// Restore state
glBindTexture ( GL_TEXTURE_2D , last_texture ) ;
GL_CALL ( glBindTexture ( GL_TEXTURE_2D , last_texture ) ) ;
return true ;
return true ;
}
}