From 9ab8474298af3073825baa1660ca999cfcd5b83e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 21 Dec 2021 19:09:58 +0100 Subject: [PATCH] [wip] very dirty CUDA hookup VERY --- src/esp/batched_sim/BatchedSimulator.cpp | 41 ++++- src/esp/batched_sim/BatchedSimulator.h | 12 +- src/esp/batched_sim/CMakeLists.txt | 44 ++++- src/esp/batched_sim/MagnumRenderer.cpp | 27 ++- src/esp/batched_sim/MagnumRenderer.h | 3 + src/esp/batched_sim/MagnumRendererDemo.cpp | 17 +- .../batched_sim/MagnumRendererStandalone.cpp | 154 ++++++++++++++++++ .../batched_sim/MagnumRendererStandalone.h | 36 ++++ src/esp/batched_sim/configure.h.cmake | 1 + src/esp/bindings/BatchedSimBindings.cpp | 8 +- src/esp/sim/Simulator.cpp | 8 +- src/tests/BatchedSimTest.cpp | 58 +++++-- src/tests/CMakeLists.txt | 8 +- src/tests/configure.h.cmake | 2 + 14 files changed, 360 insertions(+), 59 deletions(-) create mode 100644 src/esp/batched_sim/MagnumRendererStandalone.cpp create mode 100644 src/esp/batched_sim/MagnumRendererStandalone.h diff --git a/src/esp/batched_sim/BatchedSimulator.cpp b/src/esp/batched_sim/BatchedSimulator.cpp index eb04f59be5..100670741a 100644 --- a/src/esp/batched_sim/BatchedSimulator.cpp +++ b/src/esp/batched_sim/BatchedSimulator.cpp @@ -114,7 +114,7 @@ void BatchedSimulator::randomizeRobotsForCurrentStep() { RobotInstanceSet::RobotInstanceSet(Robot* robot, int numEnvs, #ifdef MAGNUM_RENDERER - MagnumRenderer& renderer, + MagnumRendererStandalone& renderer, #else std::vector* envs, #endif @@ -160,7 +160,8 @@ RobotInstanceSet::RobotInstanceSet(Robot* robot, /* The Magnum renderer contains the dynamic URDF scene already, just reset the link transformations to identities */ #ifdef MAGNUM_RENDERER - renderer.dynamicScenes()[env][i] = Mn::Matrix4{}; + if(i != -1) + renderer.dynamicScenes()[env][i] = Mn::Matrix4{}; #else const std::string linkVisualFilepath = visualAttachments[0].second; const std::string nodeName = @@ -408,9 +409,14 @@ Robot::Robot(const std::string& filepath, esp::sim::Simulator* sim) { artObj = static_cast( managedObj->hackGetBulletObjectReference().get()); + #ifdef MAGNUM_RENDERER + sceneMapping = BpsSceneMapping::loadFromFile( + "combined_Stage_v3_sc0_staging_trimesh.bps.mapping.json"); + #else sceneMapping = BpsSceneMapping::loadFromFile( "../data/bps_data/combined_Stage_v3_sc0_staging/" "combined_Stage_v3_sc0_staging_trimesh.bps.mapping.json"); + #endif jointPositionLimits = artObj->getJointPositionLimits(); @@ -484,8 +490,9 @@ BatchedSimulator::BatchedSimulator(const BatchedSimulatorConfig& config) { config_ = config; #ifdef MAGNUM_RENDERER renderer_.emplace(MagnumRendererConfiguration{} - .setFilename("../data/bps_data/combined_Stage_v3_sc0_staging/" - "combined_Stage_v3_sc0_staging_trimesh.bps"_s) + // TODO Yes, sorry, you have to cd into this dir first, otherwise it won't + // find the ktx files + .setFilename("combined_Stage_v3_sc0_staging_trimesh.bps"_s) .setTileSizeCount({config_.sensor0.width, config_.sensor0.height}, // TODO better way to specify this {16, (config_.numEnvs + 15)/16}) @@ -511,7 +518,11 @@ BatchedSimulator::BatchedSimulator(const BatchedSimulatorConfig& config) { legacySim_ = esp::sim::Simulator::create_unique(simConfig); + #ifdef MAGNUM_RENDERER + const std::string filepath = "../../URDF/opt_fetch/robots/fetch.urdf"; + #else const std::string filepath = "../data/URDF/opt_fetch/robots/fetch.urdf"; + #endif robot_ = Robot(filepath, legacySim_.get()); int numLinks = robot_.artObj->getNumLinks(); @@ -696,7 +707,7 @@ void BatchedSimulator::stepPhysicsWithReferenceActions() { void BatchedSimulator::startRender() { CORRADE_INTERNAL_ASSERT(isOkToRender_); #ifdef MAGNUM_RENDERER - renderer_->draw(Mn::GL::defaultFramebuffer); // TODO nooo need a CUDA texture + renderer_->draw(); #else bpsWrapper_->renderer_->render(bpsWrapper_->envs_.data()); #endif @@ -707,7 +718,8 @@ void BatchedSimulator::startRender() { void BatchedSimulator::waitForFrame() { CORRADE_INTERNAL_ASSERT(isRenderStarted_); #ifdef MAGNUM_RENDERER - Mn::GL::Renderer::finish(); // TODO U sure? + /* Nothing, all blocking will happen when retrieving the CUDA device + pointer */ #else bpsWrapper_->renderer_->waitForFrame(); #endif @@ -715,7 +727,11 @@ void BatchedSimulator::waitForFrame() { isOkToRender_ = true; } -#ifndef MAGNUM_RENDERER +#ifdef MAGNUM_RENDERER +MagnumRendererStandalone& BatchedSimulator::getMagnumRenderer() { + return *renderer_; +} +#else bps3D::Renderer& BatchedSimulator::getBpsRenderer() { CORRADE_INTERNAL_ASSERT(bpsWrapper_->renderer_.get()); return *bpsWrapper_->renderer_.get(); @@ -727,8 +743,13 @@ RewardCalculationContext::RewardCalculationContext(const Robot* robot, RolloutRecord* rollouts) : robot_(robot), numEnvs_(numEnvs), rollouts_(rollouts) { esp::sim::SimulatorConfiguration simConfig{}; + #ifdef MAGNUM_RENDERER + simConfig.activeSceneName = + "../../stages/Stage_v3_sc0_staging_no_textures.glb"; + #else simConfig.activeSceneName = "../data/stages/Stage_v3_sc0_staging_no_textures.glb"; + #endif simConfig.enablePhysics = true; simConfig.createRenderer = false; simConfig.loadRenderAssets = @@ -738,7 +759,13 @@ RewardCalculationContext::RewardCalculationContext(const Robot* robot, legacySim_ = esp::sim::Simulator::create_unique(simConfig); // todo: avoid code duplication with Robot + + #ifdef MAGNUM_RENDERER + const std::string filepath = "../../URDF/opt_fetch/robots/fetch.urdf"; + #else const std::string filepath = "../data/URDF/opt_fetch/robots/fetch.urdf"; + #endif + // todo: delete object on destruction auto managedObj = legacySim_->getArticulatedObjectManager() ->addBulletArticulatedObjectFromURDF(filepath); diff --git a/src/esp/batched_sim/BatchedSimulator.h b/src/esp/batched_sim/BatchedSimulator.h index 7326ce5f51..249214fc05 100644 --- a/src/esp/batched_sim/BatchedSimulator.h +++ b/src/esp/batched_sim/BatchedSimulator.h @@ -12,7 +12,7 @@ #include "esp/sim/Simulator.h" #ifdef MAGNUM_RENDERER -#include "MagnumRenderer.h" +#include "MagnumRendererStandalone.h" #else #include #endif @@ -75,7 +75,7 @@ class RobotInstanceSet { RobotInstanceSet(Robot* robot, int numEnvs, #ifdef MAGNUM_RENDERER - MagnumRenderer& renderer_, + MagnumRendererStandalone& renderer_, #else std::vector* envs, #endif @@ -94,7 +94,7 @@ class RobotInstanceSet { btAlignedObjectArray scratch_m_; #ifdef MAGNUM_RENDERER - MagnumRenderer* renderer_ = nullptr; + MagnumRendererStandalone* renderer_ = nullptr; #else std::vector* envs_; #endif @@ -136,7 +136,9 @@ class BatchedSimulator { void setActions(std::vector&& actions); void autoResetOrStepPhysics(); - #ifndef MAGNUM_RENDERER + #ifdef MAGNUM_RENDERER + MagnumRendererStandalone& getMagnumRenderer(); + #else bps3D::Renderer& getBpsRenderer(); #endif @@ -160,7 +162,7 @@ class BatchedSimulator { RolloutRecord rollouts_; std::unique_ptr legacySim_; #ifdef MAGNUM_RENDERER - Corrade::Containers::Optional renderer_; + Corrade::Containers::Optional renderer_; #else std::unique_ptr bpsWrapper_; #endif diff --git a/src/esp/batched_sim/CMakeLists.txt b/src/esp/batched_sim/CMakeLists.txt index 734ec89e00..959d8d010a 100644 --- a/src/esp/batched_sim/CMakeLists.txt +++ b/src/esp/batched_sim/CMakeLists.txt @@ -1,10 +1,12 @@ option(MAGNUM_RENDERER "Use Magnum renderer instead of BPS3D" ON) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake - ${CMAKE_CURRENT_BINARY_DIR}/configure.h) - +# Required by Magnum +if(MAGNUM_RENDERER) + if(NOT BUILD_WITH_CUDA) + message(FATAL_ERROR "BUILD_WITH_CUDA has to be enabled for the Magnum Batch Renderer") + endif() # Required by BPS3D -if(NOT MAGNUM_RENDERER) +else() set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED 17) endif() @@ -12,7 +14,7 @@ endif() # BpsImporter plugin if(MAGNUM_RENDERER) find_package(Corrade REQUIRED PluginManager) - find_package(Magnum REQUIRED GL GlfwApplication Trade MeshTools Shaders DebugTools) + find_package(Magnum REQUIRED GL GlfwApplication Trade MeshTools Shaders DebugTools WindowlessEglApplication) if(MAGNUM_BUILD_STATIC) find_package(MagnumPlugins REQUIRED BasisImporter) corrade_add_static_plugin(BpsImporter ";" BpsImporter.conf BpsImporter.cpp) @@ -22,6 +24,16 @@ if(MAGNUM_RENDERER) target_link_libraries(BpsImporter PUBLIC Magnum::Trade) endif() +if(MAGNUM_RENDERER AND NOT MAGNUM_BUILD_STATIC) + set(BPSIMPORTER_PLUGIN_FILENAME $) +endif() + +# First replace ${} variables, then $<> generator expressions +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/configure.h.in) +file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/configure.h + INPUT ${CMAKE_CURRENT_BINARY_DIR}/configure.h.in) + # The batched_sim library set(batched_sim_SRCS BatchedSimulator.cpp @@ -33,6 +45,8 @@ if(MAGNUM_RENDERER) list(APPEND batched_sim_SRCS MagnumRenderer.cpp MagnumRenderer.h + MagnumRendererStandalone.cpp + MagnumRendererStandalone.h ) else() list(APPEND batched_sim_SRCS @@ -46,13 +60,25 @@ target_link_libraries( PUBLIC core sim) target_include_directories(batched_sim PRIVATE ${CMAKE_BINARY_DIR}) if(MAGNUM_RENDERER) + target_include_directories(batched_sim PRIVATE + ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES} + ${CMAKE_CURRENT_LIST_DIR}/../gfx/cuda_helpers + ) + target_link_libraries(batched_sim PUBLIC ${CUDART_LIBRARY}) target_link_libraries(batched_sim PRIVATE Magnum::GL Magnum::Magnum Magnum::Shaders Magnum::Trade - Magnum::MeshTools) - add_dependencies(batched_sim BpsImporter) + Magnum::MeshTools + Magnum::WindowlessEglApplication) + if(MAGNUM_BUILD_STATIC) + target_link_libraries(batched_sim PRIVATE + MagnumPlugins::BasisImporter + BpsImporter) + else() + add_dependencies(batched_sim BpsImporter) + endif() else() target_link_libraries( batched_sim @@ -77,7 +103,9 @@ if(MAGNUM_RENDERER) Magnum::Shaders Magnum::Trade Magnum::MeshTools) - + target_include_directories(MagnumRendererDemo PRIVATE + ${PROJECT_BINARY_DIR} + ) if(MAGNUM_BUILD_STATIC) target_link_libraries(MagnumRendererDemo PRIVATE MagnumPlugins::BasisImporter diff --git a/src/esp/batched_sim/MagnumRenderer.cpp b/src/esp/batched_sim/MagnumRenderer.cpp index 937fef1b02..7f9c3adf19 100644 --- a/src/esp/batched_sim/MagnumRenderer.cpp +++ b/src/esp/batched_sim/MagnumRenderer.cpp @@ -30,11 +30,12 @@ #include #include +#include "esp/batched_sim/configure.h" + #ifdef MAGNUM_BUILD_STATIC -int importStaticPlugins() { +void importStaticPlugins() { CORRADE_PLUGIN_IMPORT(BpsImporter) - return 0; -} CORRADE_AUTOMATIC_INITIALIZER(importStaticPlugins); +} #endif namespace Cr = Corrade; @@ -47,7 +48,13 @@ using namespace Cr::Containers::Literals; struct MagnumRendererConfiguration::State { Cr::Containers::String filename; Cr::Containers::String importer = - Cr::Containers::String::nullTerminatedGlobalView("BpsImporter"_s); + Cr::Containers::String::nullTerminatedGlobalView( + #ifdef MAGNUM_BUILD_STATIC + "BpsImporter"_s + #else + BPSIMPORTER_PLUGIN_FILENAME + #endif + ); MagnumRendererFlags flags; Magnum::Vector2i tileSize{128, 128}; Magnum::Vector2i tileCount{16, 12}; @@ -107,6 +114,10 @@ struct MagnumRenderer::State { }; MagnumRenderer::MagnumRenderer(const MagnumRendererConfiguration& configurationWrapper): _state{Cr::InPlaceInit} { + #ifdef MAGNUM_BUILD_STATIC + importStaticPlugins(); + #endif + const MagnumRendererConfiguration::State& configuration = *configurationWrapper.state; _state->tileSize = configuration.tileSize; @@ -308,6 +319,14 @@ Cr::Containers::StridedArrayView2D MagnumRenderer::dynamicScenes() }.suffix({0, _state->staticSceneSize}); } +Mn::Vector2i MagnumRenderer::tileCount() const { + return _state->tileCount; +} + +Mn::Vector2i MagnumRenderer::tileSize() const { + return _state->tileSize; +} + void MagnumRenderer::draw(Mn::GL::AbstractFramebuffer& framebuffer) { /* Upload projection and transformation uniforms, assuming they change every frame */ diff --git a/src/esp/batched_sim/MagnumRenderer.h b/src/esp/batched_sim/MagnumRenderer.h index 8663a8f3cf..19f939fcb2 100644 --- a/src/esp/batched_sim/MagnumRenderer.h +++ b/src/esp/batched_sim/MagnumRenderer.h @@ -38,6 +38,9 @@ class MagnumRenderer { Corrade::Containers::StridedArrayView1D cameras(); Corrade::Containers::StridedArrayView2D dynamicScenes(); + Magnum::Vector2i tileSize() const; + Magnum::Vector2i tileCount() const; + void draw(Magnum::GL::AbstractFramebuffer& framebuffer); private: diff --git a/src/esp/batched_sim/MagnumRendererDemo.cpp b/src/esp/batched_sim/MagnumRendererDemo.cpp index e62013c731..2769cecb1f 100644 --- a/src/esp/batched_sim/MagnumRendererDemo.cpp +++ b/src/esp/batched_sim/MagnumRendererDemo.cpp @@ -33,12 +33,8 @@ class MagnumRendererDemo: public Mn::Platform::Application { MagnumRendererDemo::MagnumRendererDemo(const Arguments& arguments): Mn::Platform::Application{arguments, Mn::NoCreate} { Cr::Utility::Arguments args; args.addArgument("file").setHelp("file", "bps file to load") - #ifdef MAGNUM_BUILD_STATIC - .addOption('I', "importer", "BpsImporter") - #else - .addNamedArgument('I', "importer") - #endif - .setHelp("importer", "path to the bps importer plugin") + .addOption('I', "importer") + .setHelp("importer", "importer plugin to use instead of BpsImporter") .addBooleanOption("profile") .setHelp("profile", "profile frame times") .addOption('S', "size", "128 128") @@ -59,11 +55,14 @@ MagnumRendererDemo::MagnumRendererDemo(const Arguments& arguments): Mn::Platform .setTitle("Magnum Renderer Demo")); /* Create the renderer */ - _renderer.emplace(MagnumRendererConfiguration{} + MagnumRendererConfiguration configuration; + configuration .setFilename(args.value("file")) - .setImporter(args.value("importer")) .setFlags(args.isSet("no-textures") ? MagnumRendererFlag::NoTextures : MagnumRendererFlags{}) - .setTileSizeCount(tileSize, tileCount)); + .setTileSizeCount(tileSize, tileCount); + if(!args.value("importer").empty()) + configuration.setImporter(args.value("importer")); + _renderer.emplace(configuration); /* Hardcode camera position + projection for all views (taken from BatchSimulator.cpp) */ diff --git a/src/esp/batched_sim/MagnumRendererStandalone.cpp b/src/esp/batched_sim/MagnumRendererStandalone.cpp new file mode 100644 index 0000000000..179923d0c6 --- /dev/null +++ b/src/esp/batched_sim/MagnumRendererStandalone.cpp @@ -0,0 +1,154 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#include "MagnumRendererStandalone.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "esp/batched_sim/configure.h" + +namespace Cr = Corrade; +namespace Mn = Magnum; + +namespace esp { namespace batched_sim { + +struct MagnumRendererStandalone::State { + Mn::Platform::WindowlessGLContext context; + Mn::Platform::GLContext magnumContext{Mn::NoCreate}; + Cr::Containers::Optional renderer; + Mn::GL::Renderbuffer color{Mn::NoCreate}, depth{Mn::NoCreate}; + Mn::GL::Framebuffer framebuffer{Mn::NoCreate}; + Mn::GL::BufferImage2D colorBuffer{Mn::NoCreate}; + Mn::GL::BufferImage2D depthBuffer{Mn::NoCreate}; + cudaGraphicsResource* cudaColorBuffer{}; + cudaGraphicsResource* cudaDepthBuffer{}; + + State(): context{Mn::Platform::WindowlessGLContext::Configuration{} + .setCudaDevice(0)} { + context.makeCurrent(); + magnumContext.create(); + color = Mn::GL::Renderbuffer{}; + depth = Mn::GL::Renderbuffer{}; + } + + ~State() { + /* Should be unmapped before the GL object gets destroyed, I guess? */ + if(cudaColorBuffer) + checkCudaErrors(cudaGraphicsUnmapResources(1, &cudaColorBuffer, 0)); + if(cudaDepthBuffer) + checkCudaErrors(cudaGraphicsUnmapResources(1, &cudaDepthBuffer, 0)); + } +}; + +MagnumRendererStandalone::MagnumRendererStandalone(const MagnumRendererConfiguration& configuration): _state{Cr::InPlaceInit} { + /* Create the renderer only once the GL context is ready */ + // TODO make it possible to defer the creation and go back to inheritance, + // this is rather awful + _state->renderer.emplace(configuration); + + const Mn::Vector2i size = _state->renderer->tileSize()*_state->renderer->tileCount(); + _state->color.setStorage(Mn::GL::RenderbufferFormat::RGBA8, size); + _state->depth.setStorage(Mn::GL::RenderbufferFormat::DepthComponent32F, size); + _state->framebuffer = Mn::GL::Framebuffer{Mn::Range2Di{{}, size}}; + _state->framebuffer + .attachRenderbuffer(Mn::GL::Framebuffer::ColorAttachment{0}, _state->color) + // TODO just GL::Framebuffer::DepthAttachment, this is shit + .attachRenderbuffer(Mn::GL::Framebuffer::BufferAttachment::Depth, _state->depth); + /* Defer the buffer initialization to the point when it's actually read + into */ + _state->colorBuffer = Mn::GL::BufferImage2D{framebufferColorFormat()}; + _state->depthBuffer = Mn::GL::BufferImage2D{framebufferDepthFormat()}; +} + +// TODO ugh these proxies are ew +Cr::Containers::StridedArrayView1D MagnumRendererStandalone::cameras() { + return _state->renderer->cameras(); +} + +Cr::Containers::StridedArrayView2D MagnumRendererStandalone::dynamicScenes() { + return _state->renderer->dynamicScenes(); +} + +Mn::Vector2i MagnumRendererStandalone::tileCount() const { + return _state->renderer->tileCount(); +} + +Mn::Vector2i MagnumRendererStandalone::tileSize() const { + return _state->renderer->tileSize(); +} + +Mn::PixelFormat MagnumRendererStandalone::framebufferColorFormat() const { + return Mn::PixelFormat::RGBA8Unorm; +} + +Mn::PixelFormat MagnumRendererStandalone::framebufferDepthFormat() const { + return Mn::PixelFormat::Depth32F; +} + +void MagnumRendererStandalone::draw() { + _state->framebuffer.clear(Mn::GL::FramebufferClear::Color|Mn::GL::FramebufferClear::Depth); + _state->renderer->draw(_state->framebuffer); +} + +const void* MagnumRendererStandalone::cudaColorBufferDevicePointer() { + /* If the CUDA buffer exists already, it's mapped from the previous call. + Unmap it first so we can read into it from GL. */ + if(_state->cudaColorBuffer) + checkCudaErrors(cudaGraphicsUnmapResources(1, &_state->cudaColorBuffer, 0)); + + /* Read to the buffer image, allocating it if it's not already. Can't really + return a pointer directly to the renderbuffer because the returned device + pointer is expected to be linearized. */ + _state->framebuffer.read({{}, tileCount()*tileSize()}, _state->colorBuffer, Mn::GL::BufferUsage::DynamicRead); + + /* Initialize the CUDA buffer from the GL buffer image if it's not already */ + if(!_state->cudaColorBuffer) { + checkCudaErrors(cudaGraphicsGLRegisterBuffer(&_state->cudaColorBuffer, _state->colorBuffer.buffer().id(), cudaGraphicsRegisterFlagsReadOnly)); + } + + /* Map the buffer and return the device pointer */ + checkCudaErrors(cudaGraphicsMapResources(1, &_state->cudaColorBuffer, 0)); + void* pointer; + std::size_t size; + checkCudaErrors(cudaGraphicsResourceGetMappedPointer(&pointer, &size, _state->cudaColorBuffer)); + CORRADE_INTERNAL_ASSERT(size == _state->colorBuffer.size().product()*_state->colorBuffer.pixelSize()); + return pointer; +} + +const void* MagnumRendererStandalone::cudaDepthBufferDevicePointer() { + /* If the CUDA buffer exists already, it's mapped from the previous call. + Unmap it first so we can read into it from GL. */ + if(_state->cudaDepthBuffer) + checkCudaErrors(cudaGraphicsUnmapResources(1, &_state->cudaDepthBuffer, 0)); + + /* Read to the buffer image, allocating it if it's not already. Can't really + return a pointer directly to the renderbuffer because the returned device + pointer is expected to be linearized. */ + _state->framebuffer.read({{}, tileCount()*tileSize()}, _state->depthBuffer, Mn::GL::BufferUsage::DynamicRead); + + /* Initialize the CUDA buffer from the GL buffer image if it's not already */ + if(!_state->cudaDepthBuffer) { + checkCudaErrors(cudaGraphicsGLRegisterBuffer(&_state->cudaDepthBuffer, _state->depthBuffer.buffer().id(), cudaGraphicsRegisterFlagsReadOnly)); + } + + /* Map the buffer and return the device pointer */ + checkCudaErrors(cudaGraphicsMapResources(1, &_state->cudaDepthBuffer, 0)); + void* pointer; + std::size_t size; + checkCudaErrors(cudaGraphicsResourceGetMappedPointer(&pointer, &size, _state->cudaDepthBuffer)); + CORRADE_INTERNAL_ASSERT(size == _state->depthBuffer.size().product()*_state->depthBuffer.pixelSize()); + return pointer; +} + +}} diff --git a/src/esp/batched_sim/MagnumRendererStandalone.h b/src/esp/batched_sim/MagnumRendererStandalone.h new file mode 100644 index 0000000000..41277346ba --- /dev/null +++ b/src/esp/batched_sim/MagnumRendererStandalone.h @@ -0,0 +1,36 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#ifndef ESP_BATCHEDSIM_MAGNUM_RENDERER_STANDALONE_H_ +#define ESP_BATCHEDSIM_MAGNUM_RENDERER_STANDALONE_H_ + +#include "MagnumRenderer.h" + +namespace esp { namespace batched_sim { + +class MagnumRendererStandalone { + public: + explicit MagnumRendererStandalone(const MagnumRendererConfiguration& configuration); + + Corrade::Containers::StridedArrayView1D cameras(); + Corrade::Containers::StridedArrayView2D dynamicScenes(); + + Magnum::Vector2i tileSize() const; + Magnum::Vector2i tileCount() const; + Magnum::PixelFormat framebufferColorFormat() const; + Magnum::PixelFormat framebufferDepthFormat() const; + + void draw(); + + const void* cudaColorBufferDevicePointer(); + const void* cudaDepthBufferDevicePointer(); + + private: + struct State; + Corrade::Containers::Pointer _state; +}; + +}} + +#endif diff --git a/src/esp/batched_sim/configure.h.cmake b/src/esp/batched_sim/configure.h.cmake index b42c4ccfab..16d112136a 100644 --- a/src/esp/batched_sim/configure.h.cmake +++ b/src/esp/batched_sim/configure.h.cmake @@ -1 +1,2 @@ #cmakedefine MAGNUM_RENDERER +#cmakedefine BPSIMPORTER_PLUGIN_FILENAME "${BPSIMPORTER_PLUGIN_FILENAME}"_s diff --git a/src/esp/bindings/BatchedSimBindings.cpp b/src/esp/bindings/BatchedSimBindings.cpp index 509f3f5461..b2bfa8d642 100644 --- a/src/esp/bindings/BatchedSimBindings.cpp +++ b/src/esp/bindings/BatchedSimBindings.cpp @@ -18,10 +18,12 @@ namespace batched_sim { namespace { py::capsule getColorMemory(BatchedSimulator& bsim, const uint32_t groupIdx) { - #ifndef MAGNUM_RENDERER - return py::capsule(bsim.getBpsRenderer().getColorPointer(groupIdx)); + #ifdef MAGNUM_RENDERER + CORRADE_ASSERT(groupIdx == 0, + "esp::batched_sim::getColorMemory(): what is groupIdx" << groupIdx << "for?", py::capsule()); + return py::capsule(bsim.getMagnumRenderer().cudaColorBufferDevicePointer()); #else - CORRADE_ASSERT_UNREACHABLE("Sorry!", py::capsule()); + return py::capsule(bsim.getBpsRenderer().getColorPointer(groupIdx)); #endif } diff --git a/src/esp/sim/Simulator.cpp b/src/esp/sim/Simulator.cpp index 13a15d2f16..9f8bb3c3bb 100644 --- a/src/esp/sim/Simulator.cpp +++ b/src/esp/sim/Simulator.cpp @@ -168,10 +168,10 @@ void Simulator::reconfigure(const SimulatorConfiguration& cfg) { renderer_->acquireGlContext(); } else { - CORRADE_ASSERT( - !Magnum::GL::Context::hasCurrent(), - "Simulator::reconfigure() : Unexpected existing context when " - "createRenderer==false", ); +// CORRADE_ASSERT( +// !Magnum::GL::Context::hasCurrent(), +// "Simulator::reconfigure() : Unexpected existing context when " +// "createRenderer==false", ); } // (re) create scene instance diff --git a/src/tests/BatchedSimTest.cpp b/src/tests/BatchedSimTest.cpp index 423a69c057..cf690e92cf 100644 --- a/src/tests/BatchedSimTest.cpp +++ b/src/tests/BatchedSimTest.cpp @@ -3,16 +3,19 @@ // LICENSE file in the root directory of this source tree. #include "esp/batched_sim/BatchedSimulator.h" -#include "esp/batched_sim/BpsSceneMapping.h" -#include "esp/batched_sim/GlmUtils.h" + +#include #include #ifdef MAGNUM_RENDERER -// TODO +#include +#include #else +#include "esp/batched_sim/BpsSceneMapping.h" +#include "esp/batched_sim/GlmUtils.h" + #include -#include #include // FIXME @@ -22,7 +25,19 @@ using namespace esp::batched_sim; +namespace Cr = Corrade; +namespace Mn = Magnum; + namespace { + +#ifdef MAGNUM_RENDERER +Mn::Image2D copyCudaBufferToImage(const void* devicePointer, Mn::PixelFormat pixelFormat, const Mn::Vector2i& size) { + Mn::Image2D out{Mn::PixelStorage{}.setAlignment(1), pixelFormat, size, Cr::Containers::Array{Cr::NoInit, std::size_t(size.product())*Mn::pixelSize(pixelFormat)}}; + + cudaMemcpy(out.data(), devicePointer, out.data().size(), cudaMemcpyDeviceToHost); + return out; +} +#else template static std::vector copyToHost(const T* dev_ptr, uint32_t width, @@ -32,12 +47,8 @@ static std::vector copyToHost(const T* dev_ptr, std::vector buffer(num_pixels); - #ifdef MAGNUM_RENDERER - CORRADE_ASSERT_UNREACHABLE("Sorry, not done yet!", {}); - #else cudaMemcpy(buffer.data(), dev_ptr, sizeof(T) * num_pixels, cudaMemcpyDeviceToHost); - #endif return buffer; } @@ -59,11 +70,7 @@ void saveFrame(const char* fname, sdr_buffer[i] = v * 255; } - #ifdef MAGNUM_RENDERER - CORRADE_ASSERT_UNREACHABLE("Sorry, not done yet!", {}); - #else stbi_write_bmp(fname, width, height, num_channels, sdr_buffer.data()); - #endif } void saveFrame(const char* fname, @@ -73,12 +80,9 @@ void saveFrame(const char* fname, uint32_t num_channels) { auto buffer = copyToHost(dev_ptr, width, height, num_channels); - #ifdef MAGNUM_RENDERER - CORRADE_ASSERT_UNREACHABLE("Sorry, not done yet!", {}); - #else stbi_write_bmp(fname, width, height, num_channels, buffer.data()); - #endif } +#endif } // namespace @@ -88,7 +92,9 @@ TEST_F(BatchedSimulatorTest, basic) { esp::logging::LoggingContext loggingContext; BatchedSimulatorConfig config{ - .numEnvs = 1, .sensor0 = {.width = 256, .height = 128, .hfov = 45}}; + // TODO this has to be divisible by 16 because the Magnum side puts 16 + // views on a row (sorry) + .numEnvs = 16, .sensor0 = {.width = 256, .height = 128, .hfov = 45}}; BatchedSimulator bsim(config); for (int i = 0; i < 100; i++) { @@ -100,7 +106,23 @@ TEST_F(BatchedSimulatorTest, basic) { bsim.waitForFrame(); #ifdef MAGNUM_RENDERER - CORRADE_ASSERT_UNREACHABLE("Sorry, not done yet!", {}); + Mn::Image2D color = copyCudaBufferToImage(bsim.getMagnumRenderer().cudaColorBufferDevicePointer(), bsim.getMagnumRenderer().framebufferColorFormat(), bsim.getMagnumRenderer().tileSize()*bsim.getMagnumRenderer().tileCount()); + Mn::Image2D depth = copyCudaBufferToImage(bsim.getMagnumRenderer().cudaDepthBufferDevicePointer(), bsim.getMagnumRenderer().framebufferDepthFormat(), bsim.getMagnumRenderer().tileSize()*bsim.getMagnumRenderer().tileCount()); + + Cr::PluginManager::Manager converterManager; + Cr::Containers::Pointer converter = converterManager.loadAndInstantiate("AnyImageConverter"); + + CORRADE_INTERNAL_ASSERT(converter->convertToFile(color, "out_color.png")); + + /* Radiance HDR is used with bundled Magnum instead of EXR. It's awfully + low-precision but at least it doesn't require you to have the full OpenEXR + set up */ + #ifndef MAGNUM_BUILD_STATIC + CORRADE_INTERNAL_ASSERT(converter->convertToFile(depth, "out_depth.exr")); + #else + Mn::ImageView2D redButActuallyDepth{Mn::PixelFormat::R32F, depth.size(), depth.data()}; + CORRADE_INTERNAL_ASSERT(converter->convertToFile(redButActuallyDepth, "out_depth.hdr")); + #endif #else uint8_t* base_color_ptr = bsim.getBpsRenderer().getColorPointer(); float* base_depth_ptr = bsim.getBpsRenderer().getDepthPointer(); diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index f96048f12c..e58d468f59 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -89,7 +89,13 @@ corrade_add_test(SensorTest SensorTest.cpp LIBRARIES sensor sim) target_include_directories(SensorTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) test(BatchedSimTest batched_sim) -target_include_directories(GfxReplayTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +if(MAGNUM_RENDERER) + target_include_directories( + BatchedSimTest PRIVATE ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES} + ${CMAKE_CURRENT_LIST_DIR}/../esp/cuda_helpers + ) + target_link_libraries(BatchedSimTest ${CUDART_LIBRARY}) +endif() # Some tests are LOUD, we don't want to include their full log (but OTOH we # want to have full log from others, so this is a compromise) diff --git a/src/tests/configure.h.cmake b/src/tests/configure.h.cmake index 83b3d384ee..aecb7f8a85 100644 --- a/src/tests/configure.h.cmake +++ b/src/tests/configure.h.cmake @@ -7,3 +7,5 @@ #define DATA_DIR "${DATA_DIR}" #define FILE_THAT_EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/IOTest.cpp" + +#cmakedefine BPS_IMPORTER_PLUGIN_FILENAME "${BPS_IMPORTER_PLUGIN_FILENAME}"