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
This commit is contained in:
Patrick Mours 2022-06-01 15:26:55 +02:00 committed by Brecht Van Lommel
parent 7f7ed8e098
commit 34f94a02f3
5 changed files with 80 additions and 44 deletions

View File

@ -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 &params,
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 &params,
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 &params)
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 &params)
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
gl_render_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
glFlush();
need_update_ = false;

View File

@ -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 &params, int texture_width, int texture_height) override;
@ -41,6 +38,11 @@ class HdCyclesDisplayDriver final : public CCL_NS::DisplayDriver {
void draw(const Params &params) 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_;

View File

@ -30,11 +30,11 @@ bool HdCyclesOutputDriver::update_render_tile(const Tile &tile)
std::vector<float> 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<HdCyclesRenderBuffer *>(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

View File

@ -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;
}

View File

@ -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<uint8_t> _data;
PXR_NS::VtValue _resource;
mutable std::atomic_bool _resourceUsed = false;
std::atomic_int _mapped = 0;
std::atomic_bool _converged = false;