Skip to content

Commit 8d69887

Browse files
authored
Fix CGAL::draw() black rendering on OpenGL < 4.3 (#9399)
## Summary of Changes Fixes `CGAL::draw()` rendering solid black geometry on systems with OpenGL < 4.3 by correcting the compatibility GLSL shaders and improving OpenGL version detection. ### Compatibility shader fixes (`Basic_shaders.h`): - **`VERTEX_SOURCE_COLOR_COMP`**: Changed `varying` to `attribute` for vertex inputs (`a_Pos`, `a_Normal`, `a_Color`). In GLSL 1.10/1.20, vertex shader inputs must use the `attribute` qualifier — `varying` is only for outputs passed to the fragment shader. - **`VERTEX_SOURCE_COLOR_COMP`**: Replaced the undefined `mv_matrix` variable with `mat3(u_Mv) * a_Normal`, using the already-declared `u_Mv` uniform (matching the OpenGL 4.3 shader path). - **`VERTEX_SOURCE_P_L_COMP`**: Changed `varying` to `attribute` for vertex inputs (`a_Pos`, `a_Color`), same fix as above. ### OpenGL version detection fixes (`qglviewer_impl.h`): - **`defaultConstructor()`**: Initialize `is_ogl_4_3` to `false`. Previously uninitialized, leading to undefined behavior. - **`initializeGL()`**: Fixed version check from `format.majorVersion() != 4` to `(format.majorVersion() < 4 || (format.majorVersion() == 4 && format.minorVersion() < 3))`. The old check incorrectly classified OpenGL 4.0–4.2 as 4.3-capable and would have broken on future OpenGL 5+. ### Diagnostic warning (`Basic_viewer.h`): - Added a `std::cerr` warning in `compile_shaders()` when compatibility shaders are selected, to aid debugging on OpenGL < 4.3 systems. ## Release Management * Affected package(s): Basic_viewer, GraphicsView * Issue(s) solved (if any): fix #6754 * Feature/Small Feature (if any): N/A * License and copyright ownership: N/A Fixes #6754 Fixes #9292
2 parents c2e400e + cbcc95a commit 8d69887

4 files changed

Lines changed: 108 additions & 35 deletions

File tree

Basic_viewer/include/CGAL/Basic_shaders.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -721,8 +721,6 @@ const char GEOMETRY_SOURCE_LINE_WIDTH[]=R"DELIM(
721721
layout (lines) in;
722722
layout (triangle_strip, max_vertices = 4) out;
723723
724-
in mediump vec4 g_Color[];
725-
726724
in VS_OUT {
727725
mediump float pointSize;
728726
mediump vec4 color;

Basic_viewer/include/CGAL/Qt/Basic_viewer.h

Lines changed: 81 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ class Basic_viewer : public CGAL::QGLViewer
461461

462462
rendering_program_cylinder.release();
463463
}
464-
else
464+
else if (isOpenGL_3_2())
465465
{
466466
auto renderer = [this, &color, &clipPlane, &plane_point](float rendering_mode) {
467467

@@ -518,6 +518,52 @@ class Basic_viewer : public CGAL::QGLViewer
518518

519519
rendering_program_line.release();
520520
}
521+
else
522+
{
523+
auto renderer = [this, &color, &clipPlane, &plane_point](float rendering_mode) {
524+
rendering_program_p_l.bind();
525+
526+
if (m_use_default_color)
527+
{
528+
auto edge_color = m_scene.get_default_color_segment();
529+
color = QVector3D((double)edge_color.red()/(double)255,
530+
(double)edge_color.green()/(double)255,
531+
(double)edge_color.blue()/(double)255);
532+
rendering_program_p_l.setUniformValue("u_DefaultColor", color);
533+
rendering_program_p_l.setUniformValue("u_UseDefaultColor", static_cast<GLint>(1));
534+
}
535+
else
536+
{
537+
rendering_program_p_l.setUniformValue("u_UseDefaultColor", static_cast<GLint>(0));
538+
}
539+
rendering_program_p_l.setUniformValue("u_PointSize", GLfloat(m_size_edges));
540+
rendering_program_p_l.setUniformValue("u_IsOrthographic", GLint(is_two_dimensional()));
541+
542+
rendering_program_p_l.setUniformValue("u_ClipPlane", clipPlane);
543+
rendering_program_p_l.setUniformValue("u_PointPlane", plane_point);
544+
rendering_program_p_l.setUniformValue("u_RenderingMode", rendering_mode);
545+
546+
vao[VAO_SEGMENTS].bind();
547+
glDrawArrays(GL_LINES, 0, static_cast<GLsizei>(m_scene.number_of_elements(GS::POS_SEGMENTS)));
548+
};
549+
550+
enum {
551+
DRAW_ALL = -1,
552+
DRAW_INSIDE_ONLY,
553+
DRAW_OUTSIDE_ONLY
554+
};
555+
556+
if (m_use_clipping_plane == CLIPPING_PLANE_SOLID_HALF_ONLY)
557+
{
558+
renderer(DRAW_INSIDE_ONLY);
559+
}
560+
else
561+
{
562+
renderer(DRAW_ALL);
563+
}
564+
565+
rendering_program_p_l.release();
566+
}
521567
}
522568

523569
if(m_draw_rays)
@@ -661,7 +707,7 @@ class Basic_viewer : public CGAL::QGLViewer
661707
};
662708

663709
auto renderer_clipping_plane = [this](bool clipping_plane_rendering) {
664-
if (!isOpenGL_4_3()) return;
710+
if (!isOpenGL_3_2()) return;
665711
if (!clipping_plane_rendering) return;
666712
// render clipping plane here
667713
rendering_program_clipping_plane.bind();
@@ -840,6 +886,13 @@ class Basic_viewer : public CGAL::QGLViewer
840886
protected:
841887
void compile_shaders()
842888
{
889+
static bool s_compat_warning_shown = false;
890+
if (!isOpenGL_3_2() && !s_compat_warning_shown)
891+
{
892+
std::cerr<<"CGAL Basic_viewer: OpenGL < 3.2 detected, using compatibility shaders"<<std::endl;
893+
s_compat_warning_shown = true;
894+
}
895+
843896
rendering_program_face.removeAllShaders();
844897
rendering_program_p_l.removeAllShaders();
845898
rendering_program_line.removeAllShaders();
@@ -864,19 +917,19 @@ class Basic_viewer : public CGAL::QGLViewer
864917

865918
// Vertices and segments shader
866919

867-
// const char* source_ = isOpenGL_4_3()
920+
// const char* source_ = isOpenGL_3_2()
868921
// ? VERTEX_SOURCE_P_L
869922
// : VERTEX_SOURCE_P_L_COMP;
870923

871-
const char* source_ = isOpenGL_4_3()
924+
const char* source_ = isOpenGL_3_2()
872925
? VERTEX_SOURCE_P_L
873926
: VERTEX_SOURCE_P_L_COMP;
874927

875928
QOpenGLShader *vertex_shader_p_l = new QOpenGLShader(QOpenGLShader::Vertex);
876929
if(!vertex_shader_p_l->compileSourceCode(source_))
877930
{ std::cerr<<"Compiling vertex source FAILED"<<std::endl; }
878931

879-
source_ = isOpenGL_4_3()
932+
source_ = isOpenGL_3_2()
880933
? FRAGMENT_SOURCE_P_L
881934
: FRAGMENT_SOURCE_P_L_COMP;
882935

@@ -888,20 +941,22 @@ class Basic_viewer : public CGAL::QGLViewer
888941
{ std::cerr<<"adding vertex shader FAILED"<<std::endl; }
889942
if(!rendering_program_p_l.addShader(fragment_shader_p_l))
890943
{ std::cerr<<"adding fragment shader FAILED"<<std::endl; }
944+
rendering_program_p_l.bindAttributeLocation("a_Pos", 0);
945+
rendering_program_p_l.bindAttributeLocation("a_Color", 1);
891946
if(!rendering_program_p_l.link())
892947
{ std::cerr<<"linking Program FAILED"<<std::endl; }
893948

894949
// Faces shader
895950

896-
source_ = isOpenGL_4_3()
951+
source_ = isOpenGL_3_2()
897952
? VERTEX_SOURCE_COLOR
898953
: VERTEX_SOURCE_COLOR_COMP;
899954

900955
QOpenGLShader *vertex_shader_face = new QOpenGLShader(QOpenGLShader::Vertex);
901956
if(!vertex_shader_face->compileSourceCode(source_))
902957
{ std::cerr<<"Compiling vertex source FAILED"<<std::endl; }
903958

904-
source_ = isOpenGL_4_3()
959+
source_ = isOpenGL_3_2()
905960
? FRAGMENT_SOURCE_COLOR
906961
: FRAGMENT_SOURCE_COLOR_COMP;
907962

@@ -916,7 +971,7 @@ class Basic_viewer : public CGAL::QGLViewer
916971
if(!rendering_program_face.link())
917972
{ std::cerr<<"linking Program FAILED"<<std::endl; }
918973

919-
if (isOpenGL_4_3())
974+
if (isOpenGL_3_2())
920975
{
921976
// clipping plane shader
922977
source_ = VERTEX_SOURCE_CLIPPING_PLANE;
@@ -940,15 +995,15 @@ class Basic_viewer : public CGAL::QGLViewer
940995

941996
}
942997

943-
// source_ = isOpenGL_4_3()
998+
// source_ = isOpenGL_3_2()
944999
// ? VERTEX_SOURCE_CLIPPING_PLANE
9451000
// : vertex_source_clipping_plane_comp;
9461001

9471002
// QOpenGLShader *vertex_shader_clipping_plane = new QOpenGLShader(QOpenGLShader::Vertex);
9481003
// if (!vertex_shader_clipping_plane->compileSourceCode(source_))
9491004
// { std::cerr << "Compiling vertex source for clipping plane FAILED" << std::endl; }
9501005

951-
// source_ = isOpenGL_4_3()
1006+
// source_ = isOpenGL_3_2()
9521007
// ? FRAGMENT_SOURCE_CLIPPING_PLANE
9531008
// : fragment_source_clipping_plane_comp;
9541009

@@ -964,7 +1019,7 @@ class Basic_viewer : public CGAL::QGLViewer
9641019
// { std::cerr << "Linking Program for clipping plane FAILED" << std::endl; }
9651020

9661021
// Sphere shader
967-
if (isOpenGL_4_3())
1022+
if (isOpenGL_3_2())
9681023
{
9691024
source_ = VERTEX_SOURCE_SHAPE;
9701025

@@ -996,7 +1051,7 @@ class Basic_viewer : public CGAL::QGLViewer
9961051
}
9971052

9981053
// Cylinder shader
999-
if (isOpenGL_4_3())
1054+
if (isOpenGL_3_2())
10001055
{
10011056
source_ = VERTEX_SOURCE_SHAPE;
10021057

@@ -1023,12 +1078,14 @@ class Basic_viewer : public CGAL::QGLViewer
10231078
{ std::cerr << "Adding geometry shader for cylinder FAILED" << std::endl;}
10241079
if (!rendering_program_cylinder.addShader(fragment_shader_cylinder))
10251080
{ std::cerr << "Adding fragment shader for cylinder FAILED" << std::endl; }
1081+
rendering_program_cylinder.bindAttributeLocation("a_Pos", 0);
1082+
rendering_program_cylinder.bindAttributeLocation("a_Color", 1);
10261083
if (!rendering_program_cylinder.link())
10271084
{ std::cerr << "Linking Program for cylinder FAILED" << std::endl; }
10281085
}
10291086

10301087
// Normal shader
1031-
if (isOpenGL_4_3())
1088+
if (isOpenGL_3_2())
10321089
{
10331090
source_ = VERTEX_SOURCE_NORMAL;
10341091

@@ -1060,7 +1117,7 @@ class Basic_viewer : public CGAL::QGLViewer
10601117
}
10611118

10621119
// Triangle shader
1063-
if (isOpenGL_4_3())
1120+
if (isOpenGL_3_2())
10641121
{
10651122
source_ = VERTEX_SOURCE_TRIANGLE;
10661123

@@ -1092,7 +1149,7 @@ class Basic_viewer : public CGAL::QGLViewer
10921149
}
10931150

10941151
// Line shader
1095-
if (isOpenGL_4_3())
1152+
if (isOpenGL_3_2())
10961153
{
10971154
source_ = VERTEX_SOURCE_LINE_WIDTH;
10981155

@@ -1119,6 +1176,8 @@ class Basic_viewer : public CGAL::QGLViewer
11191176
{ std::cerr << "Adding geometry shader for line FAILED" << std::endl;}
11201177
if (!rendering_program_line.addShader(fragment_shader_line))
11211178
{ std::cerr << "Adding fragment shader for line FAILED" << std::endl; }
1179+
rendering_program_line.bindAttributeLocation("a_Pos", 0);
1180+
rendering_program_line.bindAttributeLocation("a_Color", 1);
11221181
if (!rendering_program_line.link())
11231182
{ std::cerr << "Linking Program for line FAILED" << std::endl; }
11241183
}
@@ -1241,7 +1300,7 @@ class Basic_viewer : public CGAL::QGLViewer
12411300
rendering_program_face.setAttributeBuffer("a_Color",GL_FLOAT,0,3);
12421301

12431302
// 6) clipping plane shader
1244-
if (isOpenGL_4_3())
1303+
if (isOpenGL_3_2())
12451304
{
12461305
generate_clipping_plane();
12471306

@@ -1340,7 +1399,7 @@ class Basic_viewer : public CGAL::QGLViewer
13401399
rendering_program_sphere.setUniformValue(mvpLocation, mvpMatrix);
13411400
rendering_program_sphere.release();
13421401

1343-
if (isOpenGL_4_3())
1402+
if (isOpenGL_3_2())
13441403
{
13451404
QMatrix4x4 clipping_mMatrix;
13461405
clipping_mMatrix.setToIdentity();
@@ -1355,7 +1414,7 @@ class Basic_viewer : public CGAL::QGLViewer
13551414
rendering_program_clipping_plane.release();
13561415
}
13571416

1358-
if (isOpenGL_4_3())
1417+
if (isOpenGL_3_2())
13591418
{
13601419
rendering_program_normal.bind();
13611420

@@ -1374,7 +1433,7 @@ class Basic_viewer : public CGAL::QGLViewer
13741433
rendering_program_normal.release();
13751434
}
13761435

1377-
if (isOpenGL_4_3())
1436+
if (isOpenGL_3_2())
13781437
{
13791438
rendering_program_triangle.bind();
13801439

@@ -1383,7 +1442,7 @@ class Basic_viewer : public CGAL::QGLViewer
13831442
rendering_program_triangle.release();
13841443
}
13851444

1386-
if (isOpenGL_4_3())
1445+
if (isOpenGL_3_2())
13871446
{
13881447
rendering_program_line.bind();
13891448

@@ -1559,7 +1618,7 @@ class Basic_viewer : public CGAL::QGLViewer
15591618
const ::Qt::KeyboardModifiers modifiers = e->modifiers();
15601619
if ((e->key()==::Qt::Key_C) && (modifiers==::Qt::NoButton))
15611620
{
1562-
if (!isOpenGL_4_3()) return;
1621+
if (!isOpenGL_3_2()) return;
15631622
if (!is_two_dimensional())
15641623
{
15651624
// toggle clipping plane
@@ -1583,7 +1642,7 @@ class Basic_viewer : public CGAL::QGLViewer
15831642

15841643
else if ((e->key()==::Qt::Key_C) && (modifiers==::Qt::AltModifier))
15851644
{
1586-
if (!isOpenGL_4_3()) return;
1645+
if (!isOpenGL_3_2()) return;
15871646
if (m_use_clipping_plane!=CLIPPING_PLANE_OFF)
15881647
{
15891648
clipping_plane_rendering = !clipping_plane_rendering;

GraphicsView/include/CGAL/Qt/qglviewer.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,6 +1211,7 @@ private Q_SLOTS:
12111211
qglviewer::Vec _offset;
12121212
//C o n t e x t
12131213
bool is_ogl_4_3;
1214+
bool is_ogl_3_2;
12141215
bool is_sharing;
12151216
bool is_linked;
12161217
QOpenGLContext* shared_context;
@@ -1223,6 +1224,13 @@ private Q_SLOTS:
12231224
//! @returns `false` if the context is ES 2.0.
12241225
bool isOpenGL_4_3()const {return is_ogl_4_3; }
12251226

1227+
//! Is used to know if the openGL context supports GLSL 1.50 (OpenGL 3.2).
1228+
//! This is the requirement for the modern (`#version 150`) shaders, which is
1229+
//! weaker than isOpenGL_4_3(). Use this to select modern vs compatibility
1230+
//! shaders, and isOpenGL_4_3() for the OpenGL 4.3 C++ API.
1231+
//! @returns `true` if the context is at least OpenGL 3.2.
1232+
bool isOpenGL_3_2()const {return is_ogl_3_2; }
1233+
12261234
};
12271235

12281236
} //end CGAL

GraphicsView/include/CGAL/Qt/qglviewer_impl.h

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ void CGAL::QGLViewer::defaultConstructor() {
152152
is_sharing = false;
153153
is_linked = false;
154154
shared_context = nullptr;
155+
is_ogl_4_3 = false;
156+
is_ogl_3_2 = false;
155157
_first_tick = true;
156158
}
157159

@@ -205,17 +207,23 @@ void CGAL::QGLViewer::initializeGL() {
205207
{
206208
QSurfaceFormat format = context()->format();
207209
context()->format().setOption(QSurfaceFormat::DebugContext);
208-
if ( !context()->isValid()
209-
|| format.majorVersion() != 4
210-
|| QCoreApplication::arguments().contains(QStringLiteral("--old")))
211-
212-
{
213-
is_ogl_4_3 = false;
214-
}
215-
else
216-
{
217-
is_ogl_4_3 = true;
218-
}
210+
const bool gl_is_valid = context()->isValid();
211+
const bool force_old =
212+
QCoreApplication::arguments().contains(QStringLiteral("--old"));
213+
const int gl_major = format.majorVersion();
214+
const int gl_minor = format.minorVersion();
215+
216+
// is_ogl_4_3 gates the real OpenGL 4.3 C++ API (QOpenGLFunctions_4_3_Core),
217+
// used e.g. by the CGAL Lab demo. Behaviour unchanged.
218+
is_ogl_4_3 = gl_is_valid && !force_old
219+
&& !(gl_major < 4 || (gl_major == 4 && gl_minor < 3));
220+
221+
// is_ogl_3_2 gates the modern GLSL 1.50 (#version 150) shader path, which
222+
// only needs OpenGL 3.2. Basic_viewer uses this to pick modern vs
223+
// compatibility shaders, so the modern path also works on contexts such as
224+
// macOS 4.1 core profiles.
225+
is_ogl_3_2 = gl_is_valid && !force_old
226+
&& !(gl_major < 3 || (gl_major == 3 && gl_minor < 2));
219227

220228
QSurfaceFormat cur_f = QOpenGLContext::currentContext()->format();
221229
const char* rt =(cur_f.renderableType() == QSurfaceFormat::OpenGLES) ? "GLES" : "GL";

0 commit comments

Comments
 (0)