From 34f94a02f37005210f629f04635c457d98ff5f91 Mon Sep 17 00:00:00 2001 From: Patrick Mours Date: Wed, 1 Jun 2022 15:26:55 +0200 Subject: Fix use of OpenGL interop breaking in Hydra viewports that do not support it Rendering directly to a resource using OpenGL interop and Hgi doesn't work in Houdini, since it never uses the resulting resource (it does not call `HdRenderBuffer::GetResource`). But since doing that simultaneously disables mapping (`HdRenderBuffer::Map` is not implemented then), nothing was displayed. To fix this, keep track of whether a Hydra viewport does support displaying a Hgi resource directly, by checking whether `HdRenderBuffer::GetResource` is ever called and only enable use of OpenGL interop if that is the case. Differential Revision: https://developer.blender.org/D15090 --- intern/cycles/hydra/display_driver.cpp | 85 +++++++++++++++++++++------------- intern/cycles/hydra/display_driver.h | 9 ++-- intern/cycles/hydra/output_driver.cpp | 8 ++-- intern/cycles/hydra/render_buffer.cpp | 18 +++++-- intern/cycles/hydra/render_buffer.h | 4 ++ 5 files changed, 80 insertions(+), 44 deletions(-) diff --git a/intern/cycles/hydra/display_driver.cpp b/intern/cycles/hydra/display_driver.cpp index a809ace63e2..0c0b577c358 100644 --- a/intern/cycles/hydra/display_driver.cpp +++ b/intern/cycles/hydra/display_driver.cpp @@ -23,10 +23,18 @@ HdCyclesDisplayDriver::HdCyclesDisplayDriver(HdCyclesSession *renderParam, Hgi * HdCyclesDisplayDriver::~HdCyclesDisplayDriver() { - deinit(); + if (texture_) { + _hgi->DestroyTexture(&texture_); + } + + if (gl_pbo_id_) { + glDeleteBuffers(1, &gl_pbo_id_); + } + + gl_context_dispose(); } -void HdCyclesDisplayDriver::init() +void HdCyclesDisplayDriver::gl_context_create() { #ifdef _WIN32 if (!gl_context_) { @@ -64,16 +72,42 @@ void HdCyclesDisplayDriver::init() } } -void HdCyclesDisplayDriver::deinit() +bool HdCyclesDisplayDriver::gl_context_enable() { - if (texture_) { - _hgi->DestroyTexture(&texture_); +#ifdef _WIN32 + if (!hdc_ || !gl_context_) { + return false; } - if (gl_pbo_id_) { - glDeleteBuffers(1, &gl_pbo_id_); + mutex_.lock(); + + // Do not change context if this is called in the main thread + if (wglGetCurrentContext() == nullptr) { + if (!TF_VERIFY(wglMakeCurrent((HDC)hdc_, (HGLRC)gl_context_))) { + mutex_.unlock(); + return false; + } + } + + return true; +#else + return false; +#endif +} + +void HdCyclesDisplayDriver::gl_context_disable() +{ +#ifdef _WIN32 + if (wglGetCurrentContext() == gl_context_) { + TF_VERIFY(wglMakeCurrent(nullptr, nullptr)); } + mutex_.unlock(); +#endif +} + +void HdCyclesDisplayDriver::gl_context_dispose() +{ #ifdef _WIN32 if (gl_context_) { TF_VERIFY(wglDeleteContext((HGLRC)gl_context_)); @@ -90,13 +124,9 @@ bool HdCyclesDisplayDriver::update_begin(const Params ¶ms, int texture_width, int texture_height) { -#ifdef _WIN32 - if (!hdc_ || !gl_context_) { + if (!gl_context_enable()) { return false; } -#endif - - graphics_interop_activate(); if (gl_render_sync_) { glWaitSync((GLsync)gl_render_sync_, 0, GL_TIMEOUT_IGNORED); @@ -121,15 +151,14 @@ bool HdCyclesDisplayDriver::update_begin(const Params ¶ms, void HdCyclesDisplayDriver::update_end() { gl_upload_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - glFlush(); - graphics_interop_deactivate(); + gl_context_disable(); } void HdCyclesDisplayDriver::flush() { - graphics_interop_activate(); + gl_context_enable(); if (gl_upload_sync_) { glWaitSync((GLsync)gl_upload_sync_, 0, GL_TIMEOUT_IGNORED); @@ -139,7 +168,7 @@ void HdCyclesDisplayDriver::flush() glWaitSync((GLsync)gl_render_sync_, 0, GL_TIMEOUT_IGNORED); } - graphics_interop_deactivate(); + gl_context_disable(); } half4 *HdCyclesDisplayDriver::map_texture_buffer() @@ -179,25 +208,12 @@ DisplayDriver::GraphicsInterop HdCyclesDisplayDriver::graphics_interop_get() void HdCyclesDisplayDriver::graphics_interop_activate() { - mutex_.lock(); - -#ifdef _WIN32 - // Do not change context if this is called in the main thread - if (wglGetCurrentContext() == nullptr) { - TF_VERIFY(wglMakeCurrent((HDC)hdc_, (HGLRC)gl_context_)); - } -#endif + gl_context_enable(); } void HdCyclesDisplayDriver::graphics_interop_deactivate() { -#ifdef _WIN32 - if (wglGetCurrentContext() == gl_context_) { - TF_VERIFY(wglMakeCurrent(nullptr, nullptr)); - } -#endif - - mutex_.unlock(); + gl_context_disable(); } void HdCyclesDisplayDriver::clear() @@ -214,7 +230,11 @@ void HdCyclesDisplayDriver::draw(const Params ¶ms) return; } - init(); + if (!renderBuffer->IsResourceUsed()) { + return; + } + + gl_context_create(); // Cycles 'DisplayDriver' only supports 'half4' format TF_VERIFY(renderBuffer->GetFormat() == HdFormatFloat16Vec4); @@ -255,7 +275,6 @@ void HdCyclesDisplayDriver::draw(const Params ¶ms) glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); gl_render_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - glFlush(); need_update_ = false; diff --git a/intern/cycles/hydra/display_driver.h b/intern/cycles/hydra/display_driver.h index 20086830e6a..2a05397c325 100644 --- a/intern/cycles/hydra/display_driver.h +++ b/intern/cycles/hydra/display_driver.h @@ -19,9 +19,6 @@ class HdCyclesDisplayDriver final : public CCL_NS::DisplayDriver { ~HdCyclesDisplayDriver(); private: - void init(); - void deinit(); - void next_tile_begin() override; bool update_begin(const Params ¶ms, int texture_width, int texture_height) override; @@ -41,6 +38,11 @@ class HdCyclesDisplayDriver final : public CCL_NS::DisplayDriver { void draw(const Params ¶ms) override; + void gl_context_create(); + bool gl_context_enable(); + void gl_context_disable(); + void gl_context_dispose(); + HdCyclesSession *const _renderParam; Hgi *const _hgi; @@ -48,7 +50,6 @@ class HdCyclesDisplayDriver final : public CCL_NS::DisplayDriver { void *hdc_ = nullptr; void *gl_context_ = nullptr; #endif - CCL_NS::thread_mutex mutex_; PXR_NS::HgiTextureHandle texture_; diff --git a/intern/cycles/hydra/output_driver.cpp b/intern/cycles/hydra/output_driver.cpp index c5f64ac1c18..f4ea853f243 100644 --- a/intern/cycles/hydra/output_driver.cpp +++ b/intern/cycles/hydra/output_driver.cpp @@ -30,11 +30,11 @@ bool HdCyclesOutputDriver::update_render_tile(const Tile &tile) std::vector pixels; for (const HdRenderPassAovBinding &aovBinding : _renderParam->GetAovBindings()) { - if (aovBinding == _renderParam->GetDisplayAovBinding()) { - continue; // Display AOV binding is already updated by Cycles display driver - } - if (const auto renderBuffer = static_cast(aovBinding.renderBuffer)) { + if (aovBinding == _renderParam->GetDisplayAovBinding() && renderBuffer->IsResourceUsed()) { + continue; // Display AOV binding is already updated by Cycles display driver + } + const HdFormat format = renderBuffer->GetFormat(); if (format == HdFormatInvalid) { continue; // Skip invalid AOV bindings diff --git a/intern/cycles/hydra/render_buffer.cpp b/intern/cycles/hydra/render_buffer.cpp index 4867def0624..4d8b21d1e61 100644 --- a/intern/cycles/hydra/render_buffer.cpp +++ b/intern/cycles/hydra/render_buffer.cpp @@ -35,7 +35,7 @@ bool HdCyclesRenderBuffer::Allocate(const GfVec3i &dimensions, HdFormat format, return false; } - const size_t oldSize = _data.size(); + const size_t oldSize = _dataSize; const size_t newSize = dimensions[0] * dimensions[1] * HdDataSizeOfFormat(format); if (oldSize == newSize) { return true; @@ -49,8 +49,8 @@ bool HdCyclesRenderBuffer::Allocate(const GfVec3i &dimensions, HdFormat format, _width = dimensions[0]; _height = dimensions[1]; _format = format; - - _data.resize(newSize); + _dataSize = newSize; + _resourceUsed = false; return true; } @@ -63,6 +63,7 @@ void HdCyclesRenderBuffer::_Deallocate() _data.clear(); _data.shrink_to_fit(); + _dataSize = 0; _resource = VtValue(); } @@ -74,6 +75,10 @@ void *HdCyclesRenderBuffer::Map() return nullptr; } + if (_data.size() != _dataSize) { + _data.resize(_dataSize); + } + ++_mapped; return _data.data(); @@ -103,10 +108,17 @@ void HdCyclesRenderBuffer::SetConverged(bool converged) _converged = converged; } +bool HdCyclesRenderBuffer::IsResourceUsed() const +{ + return _resourceUsed; +} + VtValue HdCyclesRenderBuffer::GetResource(bool multiSampled) const { TF_UNUSED(multiSampled); + _resourceUsed = true; + return _resource; } diff --git a/intern/cycles/hydra/render_buffer.h b/intern/cycles/hydra/render_buffer.h index 8eb874f0068..90629d4aee0 100644 --- a/intern/cycles/hydra/render_buffer.h +++ b/intern/cycles/hydra/render_buffer.h @@ -58,6 +58,8 @@ class HdCyclesRenderBuffer final : public PXR_NS::HdRenderBuffer { void SetConverged(bool converged); + bool IsResourceUsed() const; + PXR_NS::VtValue GetResource(bool multiSampled = false) const override; void SetResource(const PXR_NS::VtValue &resource); @@ -74,9 +76,11 @@ class HdCyclesRenderBuffer final : public PXR_NS::HdRenderBuffer { unsigned int _width = 0u; unsigned int _height = 0u; PXR_NS::HdFormat _format = PXR_NS::HdFormatInvalid; + size_t _dataSize = 0; std::vector _data; PXR_NS::VtValue _resource; + mutable std::atomic_bool _resourceUsed = false; std::atomic_int _mapped = 0; std::atomic_bool _converged = false; -- cgit v1.2.3