Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/continuous-integration-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ jobs:
sudo apt-get -y update
sudo apt-get -y install freeglut3-dev
cmake -S . -B cmake_build_dir -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCOIN_BUILD_LEGACY_GL_RENDERER=OFF -DCOIN_BUILD_TESTS=ON -DCOIN_BUILD_EXAMPLES=OFF -DCOIN_BUILD_DOCUMENTATION=OFF
- name: Build core EGL and GLSL tests
run: cmake --build cmake_build_dir --target EGLBindingTest GLSLRuntimeTest --config Release -- -j4
- name: Run core EGL and GLSL tests
run: ctest -C Release -R '^(EGLBindingTest|GLSLRuntimeTest)$' --output-on-failure
- name: Build core EGL, GLSL, and readback tests
run: cmake --build cmake_build_dir --target EGLBindingTest GLSLRuntimeTest OffscreenReadbackTest --config Release -- -j4
- name: Run core EGL, GLSL, and readback tests
run: ctest -C Release -R '^(EGLBindingTest|GLSLRuntimeTest|OffscreenReadbackTest)$' --output-on-failure
working-directory: cmake_build_dir
env:
COIN_EGL: 1
Expand Down
31 changes: 22 additions & 9 deletions src/glue/gl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5321,14 +5321,25 @@ cc_glglue_is_texture_size_legal(const cc_glglue * glw,
GLenum internalformat;
GLenum format;
GLenum type = GL_UNSIGNED_BYTE;
const SbBool legacy = cc_glglue_context_supports_legacy_rendering(glw);

switch (bytespertexel) {
default:
case 1:
format = internalformat = GL_LUMINANCE;
if (legacy) {
format = internalformat = GL_LUMINANCE;
} else {
internalformat = GL_R8;
format = GL_RED;
}
break;
case 2:
format = internalformat = GL_LUMINANCE_ALPHA;
if (legacy) {
format = internalformat = GL_LUMINANCE_ALPHA;
} else {
internalformat = GL_RG8;
format = GL_RG;
}
break;
case 3:
format = internalformat = GL_RGB8;
Expand Down Expand Up @@ -5403,13 +5414,14 @@ GLint coin_glglue_get_internal_texture_format(const cc_glglue * glw,
SbBool compress)
{
GLenum format;
const SbBool legacy = cc_glglue_context_supports_legacy_rendering(glw);
if (compress) {
switch (numcomponents) {
case 1:
format = GL_COMPRESSED_LUMINANCE_ARB;
format = legacy ? GL_COMPRESSED_LUMINANCE_ARB : GL_COMPRESSED_RED;
break;
case 2:
format = GL_COMPRESSED_LUMINANCE_ALPHA_ARB;
format = legacy ? GL_COMPRESSED_LUMINANCE_ALPHA_ARB : GL_COMPRESSED_RG;
break;
case 3:
format = GL_COMPRESSED_RGB_ARB;
Expand All @@ -5424,10 +5436,10 @@ GLint coin_glglue_get_internal_texture_format(const cc_glglue * glw,
SbBool usenewenums = glglue_allow_newer_opengl(glw) && cc_glglue_glversion_matches_at_least(glw,1,1,0);
switch (numcomponents) {
case 1:
format = usenewenums ? GL_LUMINANCE8 : GL_LUMINANCE;
format = legacy ? (usenewenums ? GL_LUMINANCE8 : GL_LUMINANCE) : GL_R8;
break;
case 2:
format = usenewenums ? GL_LUMINANCE8_ALPHA8 : GL_LUMINANCE_ALPHA;
format = legacy ? (usenewenums ? GL_LUMINANCE8_ALPHA8 : GL_LUMINANCE_ALPHA) : GL_RG8;
break;
case 3:
format = usenewenums ? GL_RGB8 : GL_RGB;
Expand All @@ -5445,15 +5457,16 @@ GLint coin_glglue_get_internal_texture_format(const cc_glglue * glw,
Convert from num components to client texture format for use
in glTexImage*D's format parameter.
*/
GLenum coin_glglue_get_texture_format(const cc_glglue * COIN_UNUSED_ARG(glw), int numcomponents)
GLenum coin_glglue_get_texture_format(const cc_glglue * glw, int numcomponents)
{
GLenum format;
const SbBool legacy = cc_glglue_context_supports_legacy_rendering(glw);
switch (numcomponents) {
case 1:
format = GL_LUMINANCE;
format = legacy ? GL_LUMINANCE : GL_RED;
break;
case 2:
format = GL_LUMINANCE_ALPHA;
format = legacy ? GL_LUMINANCE_ALPHA : GL_RG;
break;
case 3:
format = GL_RGB;
Expand Down
222 changes: 128 additions & 94 deletions src/rendering/CoinOffscreenGLCanvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,105 +331,139 @@ CoinOffscreenGLCanvas::readPixels(uint8_t * dst,
unsigned int dstrowsize,
unsigned int nrcomponents) const
{
glPushAttrib(GL_ALL_ATTRIB_BITS);

// First reset all settings that can influence the result of a
// glReadPixels() call, to make sure we get the actual contents of
// the buffer, unmodified.
//
// The values set up below matches the default settings of an
// OpenGL driver.

glPixelStorei(GL_PACK_SWAP_BYTES, 0);
glPixelStorei(GL_PACK_LSB_FIRST, 0);
glPixelStorei(GL_PACK_ROW_LENGTH, (GLint)dstrowsize);
glPixelStorei(GL_PACK_SKIP_ROWS, 0);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);

// FIXME: should use best possible alignment, for speediest
// operation. 20050617 mortene.
// glPixelStorei(GL_PACK_ALIGNMENT, 4);
glPixelStorei(GL_PACK_ALIGNMENT, 1);

glPixelTransferi(GL_MAP_COLOR, 0);
glPixelTransferi(GL_MAP_STENCIL, 0);
glPixelTransferi(GL_INDEX_SHIFT, 0);
glPixelTransferi(GL_INDEX_OFFSET, 0);
glPixelTransferf(GL_RED_SCALE, 1);
glPixelTransferf(GL_RED_BIAS, 0);
glPixelTransferf(GL_GREEN_SCALE, 1);
glPixelTransferf(GL_GREEN_BIAS, 0);
glPixelTransferf(GL_BLUE_SCALE, 1);
glPixelTransferf(GL_BLUE_BIAS, 0);
glPixelTransferf(GL_ALPHA_SCALE, 1);
glPixelTransferf(GL_ALPHA_BIAS, 0);
glPixelTransferf(GL_DEPTH_SCALE, 1);
glPixelTransferf(GL_DEPTH_BIAS, 0);

GLuint i = 0;
GLfloat f = 0.0f;
glPixelMapfv(GL_PIXEL_MAP_I_TO_I, 1, &f);
glPixelMapuiv(GL_PIXEL_MAP_S_TO_S, 1, &i);
glPixelMapfv(GL_PIXEL_MAP_I_TO_R, 1, &f);
glPixelMapfv(GL_PIXEL_MAP_I_TO_G, 1, &f);
glPixelMapfv(GL_PIXEL_MAP_I_TO_B, 1, &f);
glPixelMapfv(GL_PIXEL_MAP_I_TO_A, 1, &f);
glPixelMapfv(GL_PIXEL_MAP_R_TO_R, 1, &f);
glPixelMapfv(GL_PIXEL_MAP_G_TO_G, 1, &f);
glPixelMapfv(GL_PIXEL_MAP_B_TO_B, 1, &f);
glPixelMapfv(GL_PIXEL_MAP_A_TO_A, 1, &f);

// The flushing of the OpenGL pipeline before and after the
// glReadPixels() call is done as a work-around for a reported
// OpenGL driver bug: on a Win2000 system with ATI Radeon graphics
// card, the system would hang hard if the flushing was not done.
//
// This is obviously an OpenGL driver bug, but the workaround of
// doing excessive flushing has no real ill effects, so we just do
// it unconditionally for all drivers. Note that it might not be
// necessary to flush both before and after glReadPixels() to work
// around the bug (this was not established with the external
// reporter), but again it shouldn't matter if we do.
//
// For reference, the specific driver which was reported to fail has
// the following characteristics:
//
// GL_VENDOR="ATI Technologies Inc."
// GL_RENDERER="Radeon 9000 DDR x86/SSE2"
// GL_VERSION="1.3.3446 Win2000 Release"
//
// mortene.

glFlush(); glFinish();

assert((nrcomponents >= 1) && (nrcomponents <= 4));
#if defined(COIN_BUILD_LEGACY_GL_RENDERER)
const cc_glglue * glue = cc_glglue_instance((int) this->renderid);
const SbBool legacyContext = cc_glglue_context_supports_legacy_rendering(glue);
if (legacyContext) {
glPushAttrib(GL_PIXEL_MODE_BIT);
}
#endif

if (nrcomponents < 3) {
unsigned char * tmp = new unsigned char[vpdims[0]*vpdims[1]*4];
glReadPixels(0, 0, vpdims[0], vpdims[1],
nrcomponents == 1 ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, tmp);
GLint packSwapBytes;
GLint packLsbFirst;
GLint packRowLength;
GLint packSkipRows;
GLint packSkipPixels;
GLint packAlignment;
glGetIntegerv(GL_PACK_SWAP_BYTES, &packSwapBytes);
glGetIntegerv(GL_PACK_LSB_FIRST, &packLsbFirst);
glGetIntegerv(GL_PACK_ROW_LENGTH, &packRowLength);
glGetIntegerv(GL_PACK_SKIP_ROWS, &packSkipRows);
glGetIntegerv(GL_PACK_SKIP_PIXELS, &packSkipPixels);
glGetIntegerv(GL_PACK_ALIGNMENT, &packAlignment);

// First reset all settings that can influence the result of a
// glReadPixels() call, to make sure we get the actual contents of
// the buffer, unmodified.
//
// The values set up below matches the default settings of an
// OpenGL driver.

glPixelStorei(GL_PACK_SWAP_BYTES, 0);
glPixelStorei(GL_PACK_LSB_FIRST, 0);
glPixelStorei(GL_PACK_ROW_LENGTH, (GLint)dstrowsize);
glPixelStorei(GL_PACK_SKIP_ROWS, 0);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);

// FIXME: should use best possible alignment, for speediest
// operation. 20050617 mortene.
// glPixelStorei(GL_PACK_ALIGNMENT, 4);
glPixelStorei(GL_PACK_ALIGNMENT, 1);

#if defined(COIN_BUILD_LEGACY_GL_RENDERER)
if (legacyContext) {
glPixelTransferi(GL_MAP_COLOR, 0);
glPixelTransferi(GL_MAP_STENCIL, 0);
glPixelTransferi(GL_INDEX_SHIFT, 0);
glPixelTransferi(GL_INDEX_OFFSET, 0);
glPixelTransferf(GL_RED_SCALE, 1);
glPixelTransferf(GL_RED_BIAS, 0);
glPixelTransferf(GL_GREEN_SCALE, 1);
glPixelTransferf(GL_GREEN_BIAS, 0);
glPixelTransferf(GL_BLUE_SCALE, 1);
glPixelTransferf(GL_BLUE_BIAS, 0);
glPixelTransferf(GL_ALPHA_SCALE, 1);
glPixelTransferf(GL_ALPHA_BIAS, 0);
glPixelTransferf(GL_DEPTH_SCALE, 1);
glPixelTransferf(GL_DEPTH_BIAS, 0);

GLuint i = 0;
GLfloat f = 0.0f;
glPixelMapfv(GL_PIXEL_MAP_I_TO_I, 1, &f);
glPixelMapuiv(GL_PIXEL_MAP_S_TO_S, 1, &i);
glPixelMapfv(GL_PIXEL_MAP_I_TO_R, 1, &f);
glPixelMapfv(GL_PIXEL_MAP_I_TO_G, 1, &f);
glPixelMapfv(GL_PIXEL_MAP_I_TO_B, 1, &f);
glPixelMapfv(GL_PIXEL_MAP_I_TO_A, 1, &f);
glPixelMapfv(GL_PIXEL_MAP_R_TO_R, 1, &f);
glPixelMapfv(GL_PIXEL_MAP_G_TO_G, 1, &f);
glPixelMapfv(GL_PIXEL_MAP_B_TO_B, 1, &f);
glPixelMapfv(GL_PIXEL_MAP_A_TO_A, 1, &f);
}
#endif

const unsigned char * src = tmp;
// manually convert to grayscale
for (short y = 0; y < vpdims[1]; y++) {
for (short x = 0; x < vpdims[0]; x++) {
double v = src[0] * 0.3 + src[1] * 0.59 + src[2] * 0.11;
*dst++ = (unsigned char) v;
if (nrcomponents == 2) {
*dst++ = src[3];
// The flushing of the OpenGL pipeline before and after the
// glReadPixels() call is done as a work-around for a reported
// OpenGL driver bug: on a Win2000 system with ATI Radeon graphics
// card, the system would hang hard if the flushing was not done.
//
// This is obviously an OpenGL driver bug, but the workaround of
// doing excessive flushing has no real ill effects, so we just do
// it unconditionally for all drivers. Note that it might not be
// necessary to flush both before and after glReadPixels() to work
// around the bug (this was not established with the external
// reporter), but again it shouldn't matter if we do.
//
// For reference, the specific driver which was reported to fail has
// the following characteristics:
//
// GL_VENDOR="ATI Technologies Inc."
// GL_RENDERER="Radeon 9000 DDR x86/SSE2"
// GL_VERSION="1.3.3446 Win2000 Release"
//
// mortene.

glFlush(); glFinish();

assert((nrcomponents >= 1) && (nrcomponents <= 4));

if (nrcomponents < 3) {
unsigned char * tmp = new unsigned char[vpdims[0]*vpdims[1]*4];
glReadPixels(0, 0, vpdims[0], vpdims[1],
nrcomponents == 1 ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, tmp);

const unsigned char * src = tmp;
// manually convert to grayscale
for (short y = 0; y < vpdims[1]; y++) {
for (short x = 0; x < vpdims[0]; x++) {
double v = src[0] * 0.3 + src[1] * 0.59 + src[2] * 0.11;
*dst++ = (unsigned char) v;
if (nrcomponents == 2) {
*dst++ = src[3];
}
src += nrcomponents == 1 ? 3 : 4;
}
src += nrcomponents == 1 ? 3 : 4;
}
delete[] tmp;
}
delete[] tmp;
}
else {
glReadPixels(0, 0, vpdims[0], vpdims[1],
nrcomponents == 3 ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, dst);
}
glFlush(); glFinish();

glPopAttrib();
else {
glReadPixels(0, 0, vpdims[0], vpdims[1],
nrcomponents == 3 ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, dst);
}
glFlush(); glFinish();

glPixelStorei(GL_PACK_SWAP_BYTES, packSwapBytes);
glPixelStorei(GL_PACK_LSB_FIRST, packLsbFirst);
glPixelStorei(GL_PACK_ROW_LENGTH, packRowLength);
glPixelStorei(GL_PACK_SKIP_ROWS, packSkipRows);
glPixelStorei(GL_PACK_SKIP_PIXELS, packSkipPixels);
glPixelStorei(GL_PACK_ALIGNMENT, packAlignment);

#if defined(COIN_BUILD_LEGACY_GL_RENDERER)
if (legacyContext) {
glPopAttrib();
}
#endif
}

// *************************************************************************
Expand Down
12 changes: 12 additions & 0 deletions testsuite/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,18 @@ if(HAVE_EGL)
)
add_test(NAME GLSLRuntimeTest COMMAND GLSLRuntimeTest)
set_tests_properties(GLSLRuntimeTest PROPERTIES SKIP_RETURN_CODE 77)

add_executable(OffscreenReadbackTest offscreen-readback-test.cpp)
target_link_libraries(OffscreenReadbackTest Coin ${COIN_TARGET_LINK_LIBRARIES})
target_compile_definitions(OffscreenReadbackTest PRIVATE COIN_INTERNAL)
target_include_directories(OffscreenReadbackTest PRIVATE
${PROJECT_SOURCE_DIR}/src
${PROJECT_SOURCE_DIR}/include
${PROJECT_BINARY_DIR}/include
${COIN_TARGET_INCLUDE_DIRECTORIES}
)
add_test(NAME OffscreenReadbackTest COMMAND OffscreenReadbackTest)
set_tests_properties(OffscreenReadbackTest PROPERTIES SKIP_RETURN_CODE 77)
endif()

# Many warnings are generated from test macros on macOS with Xcode.
Expand Down
Loading
Loading