diff --git a/include/Inventor/SoRenderManager.h b/include/Inventor/SoRenderManager.h index bb0b80a9e56..5cebb77cdad 100644 --- a/include/Inventor/SoRenderManager.h +++ b/include/Inventor/SoRenderManager.h @@ -53,6 +53,11 @@ typedef void SoRenderManagerRenderCB(void * userdata, class SoRenderManager * mg class COIN_DLL_API SoRenderManager { public: + enum class RenderPipeline { + LEGACY_GL, + DRAW_LIST + }; + class COIN_DLL_API Superimposition { public: enum StateFlags { @@ -178,6 +183,8 @@ class COIN_DLL_API SoRenderManager { void getAntialiasing(SbBool & smoothing, int & numPasses) const; void setGLRenderAction(SoGLRenderAction * const action); SoGLRenderAction * getGLRenderAction(void) const; + void setRenderPipeline(RenderPipeline pipeline); + RenderPipeline getRenderPipeline(void) const; void setAudioRenderAction(SoAudioRenderAction * const action); SoAudioRenderAction * getAudioRenderAction(void) const; @@ -211,6 +218,8 @@ class COIN_DLL_API SoRenderManager { SbBool clearwindow, SbBool clearzbuffer); + void renderDrawListPipeline(SbBool clearwindow, SbBool clearzbuffer); + void renderStereo(SoGLRenderAction * action, SbBool initmatrices, SbBool clearwindow, diff --git a/include/Inventor/SoSceneManager.h b/include/Inventor/SoSceneManager.h index e4390ab3128..a562dcf1d01 100644 --- a/include/Inventor/SoSceneManager.h +++ b/include/Inventor/SoSceneManager.h @@ -94,6 +94,8 @@ class COIN_DLL_API SoSceneManager { void getAntialiasing(SbBool & smoothing, int & numPasses) const; void setGLRenderAction(SoGLRenderAction * const action); SoGLRenderAction * getGLRenderAction(void) const; + void setRenderPipeline(SoRenderManager::RenderPipeline pipeline); + SoRenderManager::RenderPipeline getRenderPipeline(void) const; void setAudioRenderAction(SoAudioRenderAction * const action); SoAudioRenderAction * getAudioRenderAction(void) const; void setHandleEventAction(SoHandleEventAction * hea); diff --git a/src/misc/SoSceneManager.cpp b/src/misc/SoSceneManager.cpp index 2be730fbfa6..bbbd29c2aa5 100644 --- a/src/misc/SoSceneManager.cpp +++ b/src/misc/SoSceneManager.cpp @@ -576,6 +576,18 @@ SoSceneManager::getGLRenderAction(void) const return PRIVATE(this)->rendermanager->getGLRenderAction(); } +void +SoSceneManager::setRenderPipeline(const SoRenderManager::RenderPipeline pipeline) +{ + PRIVATE(this)->rendermanager->setRenderPipeline(pipeline); +} + +SoRenderManager::RenderPipeline +SoSceneManager::getRenderPipeline(void) const +{ + return PRIVATE(this)->rendermanager->getRenderPipeline(); +} + /*! Set the \a action to use for rendering audio. Overrides the default action made in the constructor. diff --git a/src/rendering/CMakeLists.txt b/src/rendering/CMakeLists.txt index 213e8ad6954..ccb769e0259 100644 --- a/src/rendering/CMakeLists.txt +++ b/src/rendering/CMakeLists.txt @@ -7,6 +7,8 @@ set(COIN_RENDERING_FILES SoRenderBackend.cpp SoGLRenderBackend.cpp SoIDPickBuffer.cpp + SoRenderManager.cpp + SoRenderManagerP.cpp ) if(COIN_BUILD_LEGACY_GL_RENDERER) @@ -14,8 +16,6 @@ if(COIN_BUILD_LEGACY_GL_RENDERER) SoGLBigImage.cpp SoGLImage.cpp SoGLCubeMapImage.cpp - SoRenderManager.cpp - SoRenderManagerP.cpp SoOffscreenRenderer.cpp SoOffscreenCGData.cpp SoOffscreenGLXData.cpp diff --git a/src/rendering/SoRenderManager.cpp b/src/rendering/SoRenderManager.cpp index db0c1383a15..3152f841492 100644 --- a/src/rendering/SoRenderManager.cpp +++ b/src/rendering/SoRenderManager.cpp @@ -77,7 +77,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -87,6 +89,8 @@ #include "coindefs.h" #include "tidbitsp.h" #include "misc/AudioTools.h" +#include "rendering/SoGLRenderBackend.h" +#include "rendering/SoRenderBackend.h" #include "coindefs.h" #if COIN_WORKAROUND(COIN_MSVC, <= COIN_MSVC_6_0_VERSION) @@ -261,6 +265,16 @@ SoRenderManager::SoRenderManager(void) PRIVATE(this)->stereostencilmask = NULL; PRIVATE(this)->superimpositions = NULL; + PRIVATE(this)->renderPipeline = +#if COIN_BUILD_LEGACY_GL_RENDERER + SoRenderManager::RenderPipeline::LEGACY_GL; +#else + SoRenderManager::RenderPipeline::DRAW_LIST; +#endif + PRIVATE(this)->irAction = NULL; + PRIVATE(this)->renderBackend = NULL; + PRIVATE(this)->renderBackendFrame = 0; + PRIVATE(this)->viewport = SbViewportRegion(SbVec2s(400, 400)); PRIVATE(this)->doublebuffer = TRUE; PRIVATE(this)->deleteaudiorenderaction = TRUE; @@ -285,7 +299,11 @@ SoRenderManager::SoRenderManager(void) new SoOneShotSensor(SoRenderManagerP::redrawshotTriggeredCB, this); PRIVATE(this)->redrawshot->setPriority(PRIVATE(this)->redrawpri); - PRIVATE(this)->glaction = new SoGLRenderAction(SbViewportRegion(400, 400)); +#if COIN_BUILD_LEGACY_GL_RENDERER + PRIVATE(this)->glaction = new SoGLRenderAction(PRIVATE(this)->viewport); +#else + PRIVATE(this)->glaction = NULL; +#endif PRIVATE(this)->audiorenderaction = new SoAudioRenderAction; PRIVATE(this)->clipsensor = NULL; @@ -299,9 +317,17 @@ SoRenderManager::SoRenderManager(void) */ SoRenderManager::~SoRenderManager() { + if (PRIVATE(this)->renderBackend) { + PRIVATE(this)->renderBackend->shutdown(); + delete PRIVATE(this)->renderBackend; + } + delete PRIVATE(this)->irAction; + PRIVATE(this)->dummynode->unref(); +#if COIN_BUILD_LEGACY_GL_RENDERER if (PRIVATE(this)->deleteglaction) delete PRIVATE(this)->glaction; +#endif if (PRIVATE(this)->deleteaudiorenderaction) delete PRIVATE(this)->audiorenderaction; delete PRIVATE(this)->rootsensor; delete PRIVATE(this)->redrawshot; @@ -479,12 +505,18 @@ SoRenderManager::detachClipSensor(void) void SoRenderManager::clearBuffers(SbBool color, SbBool depth) { +#if !COIN_BUILD_LEGACY_GL_RENDERER + (void) color; + (void) depth; + return; +#else GLbitfield mask = 0; if (color) mask |= GL_COLOR_BUFFER_BIT; if (depth) mask |= GL_DEPTH_BUFFER_BIT; const SbColor4f bgcol = PRIVATE(this)->backgroundcolor; glClearColor(bgcol[0], bgcol[1], bgcol[2], bgcol[3]); glClear(mask); +#endif } /* @@ -498,6 +530,11 @@ SoRenderManager::clearBuffers(SbBool color, SbBool depth) void SoRenderManager::prerendercb(void * userdata, SoGLRenderAction * action) { +#if !COIN_BUILD_LEGACY_GL_RENDERER + (void) userdata; + (void) action; + return; +#else // remove callback again action->removePreRenderCallback(prerendercb, userdata); // MSVC7 on 64-bit Windows wants it to go through this cast. @@ -514,6 +551,7 @@ SoRenderManager::prerendercb(void * userdata, SoGLRenderAction * action) // clear the viewport glClear(mask); +#endif } /*! @@ -588,6 +626,10 @@ SoRenderManager::removeSuperimposition(Superimposition * s) void SoRenderManager::render(const SbBool clearwindow, const SbBool clearzbuffer) { + if (PRIVATE(this)->renderPipeline == RenderPipeline::DRAW_LIST) { + this->renderDrawListPipeline(clearwindow, clearzbuffer); + return; + } #if !COIN_BUILD_LEGACY_GL_RENDERER (void) clearwindow; (void) clearzbuffer; @@ -677,6 +719,12 @@ SoRenderManager::render(SoGLRenderAction * action, const SbBool clearwindow, const SbBool clearzbuffer) { + if (PRIVATE(this)->renderPipeline == RenderPipeline::DRAW_LIST) { + (void) action; + (void) initmatrices; + this->renderDrawListPipeline(clearwindow, clearzbuffer); + return; + } #if !COIN_BUILD_LEGACY_GL_RENDERER (void) action; (void) initmatrices; @@ -714,6 +762,66 @@ SoRenderManager::render(SoGLRenderAction * action, #endif // COIN_BUILD_LEGACY_GL_RENDERER } +void +SoRenderManager::renderDrawListPipeline(const SbBool clearwindow, + const SbBool clearzbuffer) +{ + if (!PRIVATE(this)->scene) return; + + const SbViewportRegion viewport = PRIVATE(this)->viewport; + if (!PRIVATE(this)->irAction) { + PRIVATE(this)->irAction = new SoIRRenderAction(viewport); + } + PRIVATE(this)->irAction->setViewportRegion(viewport); + PRIVATE(this)->irAction->setCamera(PRIVATE(this)->camera); + PRIVATE(this)->irAction->apply(PRIVATE(this)->scene); + + SoDrawList & drawlist = PRIVATE(this)->irAction->getMutableDrawList(); + drawlist.buildPickLUT(); + + if (!PRIVATE(this)->renderBackend) { + PRIVATE(this)->renderBackend = new SoGLRenderBackend; + SoRenderBackendInitParams initparams = {}; + initparams.targetInfo.size = viewport.getViewportSizePixels(); + initparams.targetInfo.samples = 1; + if (!PRIVATE(this)->renderBackend->initialize(initparams)) { + delete PRIVATE(this)->renderBackend; + PRIVATE(this)->renderBackend = NULL; +#if COIN_BUILD_LEGACY_GL_RENDERER + SoDebugError::postWarning("SoRenderManager::renderDrawListPipeline", + "DrawList backend initialization failed; " + "falling back to LegacyGL"); + PRIVATE(this)->renderPipeline = RenderPipeline::LEGACY_GL; + this->render(clearwindow, clearzbuffer); + PRIVATE(this)->renderPipeline = RenderPipeline::DRAW_LIST; +#else + SoDebugError::post("SoRenderManager::renderDrawListPipeline", + "DrawList backend initialization failed in a core-only build"); +#endif + return; + } + } + + SoRenderTargetInfo targetinfo = {}; + targetinfo.size = viewport.getViewportSizePixels(); + targetinfo.samples = 1; + PRIVATE(this)->renderBackend->resizeTarget(targetinfo); + + SoRenderParams params = {}; + params.frameIndex = PRIVATE(this)->renderBackendFrame++; + params.time = SbTime::getTimeOfDay().getValue(); + params.viewport = viewport; + params.viewMatrix.makeIdentity(); + params.projMatrix.makeIdentity(); + params.viewProjMatrix.makeIdentity(); + params.clearColor = PRIVATE(this)->backgroundcolor; + params.clearDepth = 1.0f; + params.state = PRIVATE(this)->irAction->getState(); + params.flags = (clearwindow ? SO_PARAM_CLEAR_WINDOW : 0u) | + (clearzbuffer ? SO_PARAM_CLEAR_DEPTH : 0u); + PRIVATE(this)->renderBackend->render(drawlist, params); +} + /*! Convenience function for \ref SoRenderManager::renderScene @@ -1222,7 +1330,9 @@ SoRenderManager::initStencilBufferForInterleavedStereo(void) void SoRenderManager::reinitialize(void) { +#if COIN_BUILD_LEGACY_GL_RENDERER PRIVATE(this)->glaction->invalidateState(); +#endif } /*! @@ -1263,9 +1373,12 @@ SoRenderManager::setWindowSize(const SbVec2s & newsize) "(%d, %d)", newsize[0], newsize[1]); #endif // debug - SbViewportRegion region = PRIVATE(this)->glaction->getViewportRegion(); + SbViewportRegion region = PRIVATE(this)->viewport; region.setWindowSize(newsize[0], newsize[1]); + PRIVATE(this)->viewport = region; +#if COIN_BUILD_LEGACY_GL_RENDERER PRIVATE(this)->glaction->setViewportRegion(region); +#endif } /*! @@ -1276,7 +1389,7 @@ SoRenderManager::setWindowSize(const SbVec2s & newsize) const SbVec2s & SoRenderManager::getWindowSize(void) const { - return PRIVATE(this)->glaction->getViewportRegion().getWindowSize(); + return PRIVATE(this)->viewport.getWindowSize(); } /*! @@ -1291,10 +1404,13 @@ SoRenderManager::setSize(const SbVec2s & newsize) "(%d, %d)", newsize[0], newsize[1]); #endif // debug - SbViewportRegion region = PRIVATE(this)->glaction->getViewportRegion(); + SbViewportRegion region = PRIVATE(this)->viewport; SbVec2s origin = region.getViewportOriginPixels(); region.setViewportPixels(origin, newsize); + PRIVATE(this)->viewport = region; +#if COIN_BUILD_LEGACY_GL_RENDERER PRIVATE(this)->glaction->setViewportRegion(region); +#endif } /*! @@ -1303,7 +1419,7 @@ SoRenderManager::setSize(const SbVec2s & newsize) const SbVec2s & SoRenderManager::getSize(void) const { - return PRIVATE(this)->glaction->getViewportRegion().getViewportSizePixels(); + return PRIVATE(this)->viewport.getViewportSizePixels(); } /*! @@ -1320,10 +1436,13 @@ SoRenderManager::setOrigin(const SbVec2s & newOrigin) "(%d, %d)", newOrigin[0], newOrigin[1]); #endif // debug - SbViewportRegion region = PRIVATE(this)->glaction->getViewportRegion(); + SbViewportRegion region = PRIVATE(this)->viewport; SbVec2s size = region.getViewportSizePixels(); region.setViewportPixels(newOrigin, size); + PRIVATE(this)->viewport = region; +#if COIN_BUILD_LEGACY_GL_RENDERER PRIVATE(this)->glaction->setViewportRegion(region); +#endif } /*! @@ -1334,7 +1453,7 @@ SoRenderManager::setOrigin(const SbVec2s & newOrigin) const SbVec2s & SoRenderManager::getOrigin(void) const { - return PRIVATE(this)->glaction->getViewportRegion().getViewportOriginPixels(); + return PRIVATE(this)->viewport.getViewportOriginPixels(); } /*! @@ -1348,7 +1467,10 @@ SoRenderManager::getOrigin(void) const void SoRenderManager::setViewportRegion(const SbViewportRegion & newregion) { + PRIVATE(this)->viewport = newregion; +#if COIN_BUILD_LEGACY_GL_RENDERER PRIVATE(this)->glaction->setViewportRegion(newregion); +#endif } /*! @@ -1360,7 +1482,7 @@ SoRenderManager::setViewportRegion(const SbViewportRegion & newregion) const SbViewportRegion & SoRenderManager::getViewportRegion(void) const { - return PRIVATE(this)->glaction->getViewportRegion(); + return PRIVATE(this)->viewport; } /*! @@ -1596,8 +1718,13 @@ SoRenderManager::getStereoOffset(void) const void SoRenderManager::setAntialiasing(const SbBool smoothing, const int numpasses) { +#if COIN_BUILD_LEGACY_GL_RENDERER PRIVATE(this)->glaction->setSmoothing(smoothing); PRIVATE(this)->glaction->setNumPasses(numpasses); +#else + (void) smoothing; + (void) numpasses; +#endif this->scheduleRedraw(); } @@ -1609,8 +1736,13 @@ SoRenderManager::setAntialiasing(const SbBool smoothing, const int numpasses) void SoRenderManager::getAntialiasing(SbBool & smoothing, int & numpasses) const { +#if COIN_BUILD_LEGACY_GL_RENDERER smoothing = PRIVATE(this)->glaction->isSmoothing(); numpasses = PRIVATE(this)->glaction->getNumPasses(); +#else + smoothing = FALSE; + numpasses = 1; +#endif } /*! @@ -1620,6 +1752,10 @@ SoRenderManager::getAntialiasing(SbBool & smoothing, int & numpasses) const void SoRenderManager::setGLRenderAction(SoGLRenderAction * const action) { +#if !COIN_BUILD_LEGACY_GL_RENDERER + (void) action; + return; +#else SbBool haveregion = FALSE; SbViewportRegion region; if (PRIVATE(this)->glaction) { // remember existing viewport region @@ -1641,6 +1777,7 @@ SoRenderManager::setGLRenderAction(SoGLRenderAction * const action) PRIVATE(this)->deleteglaction = FALSE; if (PRIVATE(this)->glaction && haveregion) PRIVATE(this)->glaction->setViewportRegion(region); +#endif } /*! @@ -1652,6 +1789,20 @@ SoRenderManager::getGLRenderAction(void) const return PRIVATE(this)->glaction; } +void +SoRenderManager::setRenderPipeline(const RenderPipeline pipeline) +{ + if (PRIVATE(this)->renderPipeline == pipeline) return; + PRIVATE(this)->renderPipeline = pipeline; + this->scheduleRedraw(); +} + +SoRenderManager::RenderPipeline +SoRenderManager::getRenderPipeline(void) const +{ + return PRIVATE(this)->renderPipeline; +} + /*! This method returns the current auto clipping strategy. diff --git a/src/rendering/SoRenderManagerP.cpp b/src/rendering/SoRenderManagerP.cpp index 205b7ffd3ff..7a3985d2667 100644 --- a/src/rendering/SoRenderManagerP.cpp +++ b/src/rendering/SoRenderManagerP.cpp @@ -107,6 +107,9 @@ SoRenderManagerP::updateClippingPlanesCB(void * COIN_UNUSED_ARG(closure), SoSens void SoRenderManagerP::setClippingPlanes(void) { +#if !COIN_BUILD_LEGACY_GL_RENDERER + return; +#else SoCamera * camera = this->camera; SoNode * scene = this->scene; if (!camera || !scene) return; @@ -190,12 +193,17 @@ SoRenderManagerP::setClippingPlanes(void) if (SbAbs(oldfar - newfar) > SbAbs(fareps)) { camera->farDistance = newfar; } +#endif } void SoRenderManagerP::getCameraCoordinateSystem(SbMatrix & matrix, SbMatrix & inverse) { +#if !COIN_BUILD_LEGACY_GL_RENDERER + matrix = inverse = SbMatrix::identity(); + return; +#else SoCamera * camera = this->camera; SoNode * scene = this->scene; assert(camera && scene); @@ -224,6 +232,7 @@ SoRenderManagerP::getCameraCoordinateSystem(SbMatrix & matrix, inverse = this->getmatrixaction->getInverse(); } this->searchaction->reset(); +#endif } //********************************************************************************** @@ -277,6 +286,11 @@ SoRenderManager::Superimposition::getStateFlags(void) const void SoRenderManager::Superimposition::render(SoGLRenderAction * action, SbBool clearcolorbuffer) { +#if !COIN_BUILD_LEGACY_GL_RENDERER + (void) action; + (void) clearcolorbuffer; + return; +#else if (!PRIVATE(this)->enabled) return; SoGLRenderAction::TransparencyType oldttype = action->getTransparencyType(); @@ -303,6 +317,7 @@ SoRenderManager::Superimposition::render(SoGLRenderAction * action, SbBool clear if (PRIVATE(this)->transparencytype != INHERIT_TRANSPARENCY_TYPE) { action->setTransparencyType(oldttype); } +#endif } void diff --git a/src/rendering/SoRenderManagerP.h b/src/rendering/SoRenderManagerP.h index 5ca0f76da13..460dd095f53 100644 --- a/src/rendering/SoRenderManagerP.h +++ b/src/rendering/SoRenderManagerP.h @@ -59,6 +59,8 @@ class SoGetBoundingBoxAction; class SoGetMatrixAction; class SoSearchAction; class SbPList; +class SoIRRenderAction; +class SoRenderBackend; class SoRenderManagerP { public: @@ -110,6 +112,11 @@ class SoRenderManagerP { SoSearchAction * searchaction; SbBool deleteaudiorenderaction; SbBool deleteglaction; + SbViewportRegion viewport; + SoRenderManager::RenderPipeline renderPipeline; + SoIRRenderAction * irAction; + SoRenderBackend * renderBackend; + int renderBackendFrame; SoRenderManager::StereoMode stereostenciltype; SoRenderManager::RenderMode rendermode; diff --git a/src/rendering/all-rendering-cpp.cpp b/src/rendering/all-rendering-cpp.cpp index 95c55f1b27c..f89eea17473 100644 --- a/src/rendering/all-rendering-cpp.cpp +++ b/src/rendering/all-rendering-cpp.cpp @@ -30,6 +30,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \**************************************************************************/ +#define COIN_DRAW_LIST_PICKING 1 +#define COIN_DRAW_LIST_SELECTION 1 + #include "CoinOffscreenGLCanvas.cpp" #include "SoGL.cpp" #if COIN_BUILD_LEGACY_GL_RENDERER @@ -41,16 +44,14 @@ #include "SoOffscreenGLXData.cpp" #include "SoOffscreenRenderer.cpp" #include "SoOffscreenWGLData.cpp" -#include "SoRenderManager.cpp" -#include "SoRenderManagerP.cpp" #include "SoVBO.cpp" #include "SoVertexArrayIndexer.cpp" #endif +#include "SoRenderManager.cpp" +#include "SoRenderManagerP.cpp" #include "SoGLDriverDatabase.cpp" #include "SoRenderIR.cpp" #include "SoRenderBackend.cpp" -#define COIN_DRAW_LIST_PICKING 1 -#define COIN_DRAW_LIST_SELECTION 1 #include "SoGLRenderBackend.cpp" #include "SoIDPickBuffer.cpp" #undef COIN_DRAW_LIST_PICKING diff --git a/testsuite/CMakeLists.txt b/testsuite/CMakeLists.txt index ad304b482fe..3549feefae1 100644 --- a/testsuite/CMakeLists.txt +++ b/testsuite/CMakeLists.txt @@ -143,6 +143,18 @@ if(HAVE_EGL) add_test(NAME DrawListPickingTest COMMAND DrawListPickingTest) set_tests_properties(DrawListPickingTest PROPERTIES SKIP_RETURN_CODE 77) + add_executable(DrawListManagerTest drawlist-manager-test.cpp) + target_link_libraries(DrawListManagerTest Coin ${COIN_TARGET_LINK_LIBRARIES}) + target_compile_definitions(DrawListManagerTest PRIVATE COIN_INTERNAL) + target_include_directories(DrawListManagerTest PRIVATE + ${PROJECT_SOURCE_DIR}/src + ${PROJECT_SOURCE_DIR}/include + ${PROJECT_BINARY_DIR}/include + ${COIN_TARGET_INCLUDE_DIRECTORIES} + ) + add_test(NAME DrawListManagerTest COMMAND DrawListManagerTest) + set_tests_properties(DrawListManagerTest PROPERTIES SKIP_RETURN_CODE 77) + add_executable(EGLBindingTest egl-binding-test.cpp) target_link_libraries(EGLBindingTest Coin ${COIN_TARGET_LINK_LIBRARIES}) target_compile_definitions(EGLBindingTest PRIVATE COIN_INTERNAL) diff --git a/testsuite/drawlist-manager-test.cpp b/testsuite/drawlist-manager-test.cpp new file mode 100644 index 00000000000..bd029f3f5d6 --- /dev/null +++ b/testsuite/drawlist-manager-test.cpp @@ -0,0 +1,70 @@ +#include "rendering/CoinOffscreenGLCanvas.h" + +#include +#include +#include +#include +#include + +#include +#include + +namespace { + +int skip(const char * reason) +{ + std::cout << "SKIP: " << reason << std::endl; + return 77; +} + +void set_environment(const char * name, const char * value) +{ +#ifdef _WIN32 + _putenv_s(name, value); +#else + setenv(name, value, 1); +#endif +} + +} + +int +main() +{ + set_environment("COIN_EGL", "1"); + set_environment("EGL_PLATFORM", "surfaceless"); + set_environment("COIN_EGL_CORE_PROFILE", "1"); + + SoDB::init(); + CoinOffscreenGLCanvas canvas; + canvas.setWantedSize(SbVec2s(32, 32)); + if (canvas.activateGLContext() == 0) { + SoDB::finish(); + return skip("core EGL offscreen context is unavailable"); + } + + SoSeparator * root = new SoSeparator; + SoCube * cube = new SoCube; + root->addChild(cube); + root->ref(); + + uint8_t pixel[4] = {0, 0, 0, 0}; + { + SoRenderManager manager; + manager.setViewportRegion(SbViewportRegion(SbVec2s(32, 32))); + manager.setSceneGraph(root); + manager.setRenderPipeline(SoRenderManager::RenderPipeline::DRAW_LIST); + manager.render(TRUE, TRUE); + canvas.readPixels(pixel, SbVec2s(1, 1), 1, 4); + } + + root->unref(); + canvas.deactivateGLContext(); + SoDB::finish(); + + if (pixel[0] == 0 && pixel[1] == 0 && pixel[2] == 0) { + std::cerr << "FAIL: manager DrawList pipeline produced no pixels" << std::endl; + return 1; + } + return 0; +}