From af1daf2f66072ae6f9a25524b718e6f1cb282c7d Mon Sep 17 00:00:00 2001 From: Dave Pugmire Date: Wed, 15 Jun 2016 09:48:45 -0400 Subject: [PATCH] Add support for offscreen rendering with EGL. Added new class CanvasEGL, and a test. --- CMake/FindEGL.cmake | 92 ++++++++++++ CMakeLists.txt | 1 + vtkm/rendering/CMakeLists.txt | 3 + vtkm/rendering/CanvasEGL.h | 114 +++++++++++++++ vtkm/rendering/testing/CMakeLists.txt | 7 + vtkm/rendering/testing/UnitTestMapperEGL.cxx | 143 +++++++++++++++++++ 6 files changed, 360 insertions(+) create mode 100644 CMake/FindEGL.cmake create mode 100644 vtkm/rendering/CanvasEGL.h create mode 100644 vtkm/rendering/testing/UnitTestMapperEGL.cxx diff --git a/CMake/FindEGL.cmake b/CMake/FindEGL.cmake new file mode 100644 index 000000000..6809e7b8b --- /dev/null +++ b/CMake/FindEGL.cmake @@ -0,0 +1,92 @@ +# Try to find EGL library and include dir. +# Once done this will define +# +# EGL_FOUND - true if EGL has been found +# EGL_INCLUDE_DIR - where the EGL/egl.h and KHR/khrplatform.h can be found +# EGL_LIBRARY - link this to use libEGL.so.1 +# EGL_opengl_LIBRARY - link with these two libraries instead of the gl library +# EGL_gldispatch_LIBRARY for full OpenGL support through EGL +# EGL_LIBRARIES - all EGL related libraries: EGL, OpenGL, GLdispatch + + +if(NOT EGL_INCLUDE_DIR) + + # If we have a root defined look there first + if(EGL_ROOT) + find_path(EGL_INCLUDE_DIR EGL/egl.h PATHS ${EGL_ROOT}/include + NO_DEFAULT_PATH + ) + endif() + + if(NOT EGL_INCLUDE_DIR) + find_path(EGL_INCLUDE_DIR EGL/egl.h PATHS + /usr/local/include + /usr/include + ) + endif() +endif() + +if(NOT EGL_LIBRARY) + # If we have a root defined look there first + if(EGL_ROOT) + find_library(EGL_LIBRARY EGL PATHS ${EGL_ROOT}/lib + NO_DEFAULT_PATH + ) + endif() + + if(NOT EGL_LIBRARY) + find_library(EGL_LIBRARY EGL PATHS + /usr/local/lib + /usr/lib + ) + endif() +endif() + +if(NOT EGL_opengl_LIBRARY) + # If we have a root defined look there first + if(EGL_ROOT) + find_library(EGL_opengl_LIBRARY OpenGL PATHS ${EGL_ROOT}/lib + NO_DEFAULT_PATH + ) + endif() + + if(NOT EGL_opengl_LIBRARY) + find_library(EGL_opengl_LIBRARY OpenGL PATHS + /usr/local/lib + /usr/lib + ) + endif() +endif() + +if(NOT EGL_gldispatch_LIBRARY) + # If we have a root defined look there first + if(EGL_ROOT) + find_library(EGL_gldispatch_LIBRARY GLdispatch PATHS ${EGL_ROOT}/lib + NO_DEFAULT_PATH + ) + endif() + + if(NOT EGL_gldispatch_LIBRARY) + find_library(EGL_gldispatch_LIBRARY GLdispatch PATHS + /usr/local/lib + /usr/lib + ) + endif() + + # For the NVIDIA 358 drivers there isn't a libGLdispath.so. The + # proper one gets installed as libGLdispatch.so.0. + if(NOT EGL_gldispatch_LIBRARY) + find_library(EGL_gldispatch_LIBRARY libGLdispatch.so.0 PATHS + /usr/local/lib + /usr/lib + ) + endif() +endif() + +set(EGL_LIBRARIES ${EGL_LIBRARY} ${EGL_opengl_LIBRARY} ${EGL_gldispatch_LIBRARY}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(EGL DEFAULT_MSG + EGL_LIBRARY EGL_opengl_LIBRARY EGL_gldispatch_LIBRARY EGL_INCLUDE_DIR) + +mark_as_advanced(EGL_DIR EGL_INCLUDE_DIR EGL_LIBRARY EGL_opengl_LIBRARY EGL_gldispatch_LIBRARY) diff --git a/CMakeLists.txt b/CMakeLists.txt index b682596bd..7bf60d031 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,6 +186,7 @@ include(CMakeDependentOption) find_package(OpenGL) find_package(GLEW) find_package(GLUT) +find_package(EGL) #dependent option reads, value to set, if condition is true, otherwise #use last value diff --git a/vtkm/rendering/CMakeLists.txt b/vtkm/rendering/CMakeLists.txt index 9e7802f77..fd731f404 100644 --- a/vtkm/rendering/CMakeLists.txt +++ b/vtkm/rendering/CMakeLists.txt @@ -49,6 +49,9 @@ set(opengl_headers TextureGL.h WorldAnnotatorGL.h ) +set(egl_headers + CanvasEGL.h +) set(osmesa_headers CanvasOSMesa.h diff --git a/vtkm/rendering/CanvasEGL.h b/vtkm/rendering/CanvasEGL.h new file mode 100644 index 000000000..4ce7dedb9 --- /dev/null +++ b/vtkm/rendering/CanvasEGL.h @@ -0,0 +1,114 @@ +//============================================================================ +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +// +// Copyright 2015 Sandia Corporation. +// Copyright 2015 UT-Battelle, LLC. +// Copyright 2015 Los Alamos National Security. +// +// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// the U.S. Government retains certain rights in this software. +// +// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National +// Laboratory (LANL), the U.S. Government retains certain rights in +// this software. +//============================================================================ +#ifndef vtk_m_rendering_CanvasEGL_h +#define vtk_m_rendering_CanvasEGL_h + +#include +#include +#include +#include + +#include +//#include +#include +#include + +namespace vtkm { +namespace rendering { + +class CanvasEGL : public CanvasGL +{ +public: + VTKM_CONT_EXPORT + CanvasEGL(vtkm::Id width=1024, + vtkm::Id height=1024) + : CanvasGL() + { + ctx = NULL; + this->ResizeBuffers(width, height); + } + + VTKM_CONT_EXPORT + virtual void Initialize() + { + if (!(dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY))) + throw vtkm::cont::ErrorControlBadValue("Failed to get EGL display"); + EGLint major, minor; + if (!(eglInitialize(dpy, &major, &minor))) + throw vtkm::cont::ErrorControlBadValue("Failed to initialize EGL display"); + + const EGLint cfgAttrs[] = + { + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_BLUE_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_RED_SIZE, 8, + EGL_DEPTH_SIZE, 8, + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, + EGL_NONE + }; + + EGLint nCfgs; + EGLConfig cfg; + if (!(eglChooseConfig(dpy, cfgAttrs, &cfg, 1, &nCfgs)) || nCfgs == 0) + throw vtkm::cont::ErrorControlBadValue("Failed to get EGL config"); + + const EGLint pbAttrs[] = + { + EGL_WIDTH, static_cast(this->GetWidth()), + EGL_HEIGHT, static_cast(this->GetHeight()), + EGL_NONE, + }; + + if (!(surf = eglCreatePbufferSurface(dpy, cfg, pbAttrs))) + throw vtkm::cont::ErrorControlBadValue("Failed to create EGL PBuffer surface"); + eglBindAPI(EGL_OPENGL_API); + if (!(ctx = eglCreateContext(dpy, cfg, EGL_NO_CONTEXT, NULL))) + throw vtkm::cont::ErrorControlBadValue("Failed to create EGL context"); + if (!(eglMakeCurrent(dpy, surf, surf, ctx))) + throw vtkm::cont::ErrorControlBadValue("Failed to create EGL context current"); + } + + VTKM_CONT_EXPORT + virtual void Activate() + { + glEnable(GL_DEPTH_TEST); + } + + VTKM_CONT_EXPORT + virtual void Clear() + { + vtkm::rendering::Color backgroundColor = this->GetBackgroundColor(); + glClearColor(backgroundColor.Components[0], + backgroundColor.Components[1], + backgroundColor.Components[2], + 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + +private: + EGLContext ctx; + EGLDisplay dpy; + EGLSurface surf; +}; + +}} //namespace vtkm::rendering + +#endif //vtk_m_rendering_CanvasEGL_h diff --git a/vtkm/rendering/testing/CMakeLists.txt b/vtkm/rendering/testing/CMakeLists.txt index dd0caaa03..bb9e31974 100644 --- a/vtkm/rendering/testing/CMakeLists.txt +++ b/vtkm/rendering/testing/CMakeLists.txt @@ -26,6 +26,13 @@ set(unit_tests set(libs) if (OPENGL_FOUND) list(APPEND libs ${OPENGL_LIBRARIES}) + if (EGL_FOUND) + set(unit_tests ${unit_tests} + UnitTestMapperEGL.cxx + ) + list(APPEND libs ${EGL_LIBRARIES}) + endif() + if (OSMESA_FOUND) set(unit_tests ${unit_tests} diff --git a/vtkm/rendering/testing/UnitTestMapperEGL.cxx b/vtkm/rendering/testing/UnitTestMapperEGL.cxx new file mode 100644 index 000000000..08eb73ede --- /dev/null +++ b/vtkm/rendering/testing/UnitTestMapperEGL.cxx @@ -0,0 +1,143 @@ +//============================================================================ +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notice for more information. +// +// Copyright 2015 Sandia Corporation. +// Copyright 2015 UT-Battelle, LLC. +// Copyright 2015 Los Alamos National Security. +// +// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// the U.S. Government retains certain rights in this software. +// +// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National +// Laboratory (LANL), the U.S. Government retains certain rights in +// this software. +//============================================================================ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +void Set3DView(vtkm::rendering::Camera &camera, + const vtkm::cont::CoordinateSystem &coords) +{ + vtkm::Bounds coordsBounds = coords.GetBounds(VTKM_DEFAULT_DEVICE_ADAPTER_TAG()); + //set up a default view + camera = vtkm::rendering::Camera(); + camera.ResetToBounds(coordsBounds); + camera.Azimuth(static_cast(vtkm::Pi_4())); + camera.Elevation(static_cast(vtkm::Pi_4())); + + std::cout << "Camera3d: pos: " << camera.GetPosition() << std::endl; + std::cout << " lookAt: " << camera.GetLookAt() << std::endl; + std::cout << " up: " << camera.GetViewUp() << std::endl; + std::cout << " near/far: " << camera.GetClippingRange() << std::endl; + std::cout << " fieldOfView: " << camera.GetFieldOfView() << std::endl; +} + +void Set2DView(vtkm::rendering::Camera &camera, + const vtkm::cont::CoordinateSystem &coords) +{ + vtkm::Bounds coordsBounds = coords.GetBounds(VTKM_DEFAULT_DEVICE_ADAPTER_TAG()); + //set up a default view + + camera = vtkm::rendering::Camera(vtkm::rendering::Camera::MODE_2D); + camera.SetViewRange2D(coordsBounds); + camera.SetClippingRange(1.f, 100.f); + + // Give it some space for other annotations like a color bar + camera.SetViewport(-0.7f, +0.7f, -0.7f, +0.7f); + + std::cout << "Camera2D: Viewport: " << camera.GetViewport() << std::endl; + std::cout << " ClippingRange: " << camera.GetClippingRange() << std::endl; +} + +void Render3D(const vtkm::cont::DataSet &ds, + const std::string &fieldNm, + const std::string &ctName, + const std::string &outputFile) +{ + const vtkm::Int32 W = 512, H = 512; + const vtkm::cont::CoordinateSystem coords = ds.GetCoordinateSystem(); + vtkm::rendering::MapperGL mapper; + + vtkm::rendering::Camera camera; + Set3DView(camera, coords); + + vtkm::rendering::Scene scene; + vtkm::rendering::Color bg(0.2f, 0.2f, 0.2f, 1.0f); + vtkm::rendering::CanvasEGL canvas(W,H); + + scene.AddActor(vtkm::rendering::Actor(ds.GetCellSet(), + ds.GetCoordinateSystem(), + ds.GetField(fieldNm), + vtkm::rendering::ColorTable(ctName))); + + //TODO: W/H in view. bg in view (view sets canvas/renderer). + vtkm::rendering::View3D view(scene, mapper, canvas, camera, bg); + + view.Initialize(); + view.Paint(); + view.SaveAs(outputFile); +} + +void Render2D(const vtkm::cont::DataSet &ds, + const std::string &fieldNm, + const std::string &ctName, + const std::string &outputFile) +{ + const vtkm::Int32 W = 512, H = 512; + const vtkm::cont::CoordinateSystem coords = ds.GetCoordinateSystem(); + vtkm::rendering::MapperGL mapper; + + vtkm::rendering::Camera camera; + Set2DView(camera, coords); + + vtkm::rendering::Scene scene; + vtkm::rendering::Color bg(0.2f, 0.2f, 0.2f, 1.0f); + vtkm::rendering::CanvasEGL canvas(W,H); + + scene.AddActor(vtkm::rendering::Actor(ds.GetCellSet(), + ds.GetCoordinateSystem(), + ds.GetField(fieldNm), + vtkm::rendering::ColorTable(ctName))); + vtkm::rendering::View2D view(scene, mapper, canvas, camera, bg); + + view.Initialize(); + view.Paint(); + view.SaveAs(outputFile); +} + +void RenderTests() +{ + vtkm::cont::testing::MakeTestDataSet maker; + + //3D tests. + Render3D(maker.Make3DRegularDataSet0(), + "pointvar", "thermal", "reg3D.pnm"); + Render3D(maker.Make3DRectilinearDataSet0(), + "pointvar", "thermal", "rect3D.pnm"); + Render3D(maker.Make3DExplicitDataSet4(), + "pointvar", "thermal", "expl3D.pnm"); + + //2D tests. + Render2D(maker.Make2DRectilinearDataSet0(), + "pointvar", "thermal", "rect2D.pnm"); +} +} //namespace + +int UnitTestMapperEGL(int, char *[]) +{ + return vtkm::cont::testing::Testing::Run(RenderTests); +}