From 1a6958190f0761e56aebd4eb4ddf18c46288c3b4 Mon Sep 17 00:00:00 2001 From: Paul Molodowitch Date: Tue, 10 Dec 2024 11:48:57 -0800 Subject: [PATCH] [hdx] add HdxExposureScaleTask --- pxr/imaging/hdx/CMakeLists.txt | 2 + pxr/imaging/hdx/exposureScaleTask.cpp | 174 +++++++++++++++++++ pxr/imaging/hdx/exposureScaleTask.h | 102 +++++++++++ pxr/imaging/hdx/package.cpp | 7 + pxr/imaging/hdx/package.h | 1 + pxr/imaging/hdx/shaders/exposureScale.glslfx | 34 ++++ pxr/imaging/hdx/taskController.cpp | 46 +++++ pxr/imaging/hdx/taskController.h | 3 + pxr/imaging/hdx/tokens.h | 1 + 9 files changed, 370 insertions(+) create mode 100644 pxr/imaging/hdx/exposureScaleTask.cpp create mode 100644 pxr/imaging/hdx/exposureScaleTask.h create mode 100644 pxr/imaging/hdx/shaders/exposureScale.glslfx diff --git a/pxr/imaging/hdx/CMakeLists.txt b/pxr/imaging/hdx/CMakeLists.txt index e50aacf469..ed56ffd34a 100644 --- a/pxr/imaging/hdx/CMakeLists.txt +++ b/pxr/imaging/hdx/CMakeLists.txt @@ -44,6 +44,7 @@ pxr_library(hdx colorCorrectionTask drawTargetTask effectsShader + exposureScaleTask freeCameraSceneDelegate fullscreenShader hgiConversions @@ -86,6 +87,7 @@ pxr_library(hdx shaders/boundingBox.glslfx shaders/colorChannel.glslfx shaders/colorCorrection.glslfx + shaders/exposureScale.glslfx shaders/fullscreen.glslfx shaders/oitResolveImageShader.glslfx shaders/outline.glslfx diff --git a/pxr/imaging/hdx/exposureScaleTask.cpp b/pxr/imaging/hdx/exposureScaleTask.cpp new file mode 100644 index 0000000000..dbd855eb44 --- /dev/null +++ b/pxr/imaging/hdx/exposureScaleTask.cpp @@ -0,0 +1,174 @@ +// +// Copyright 2024 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// +#include "pxr/imaging/hdx/exposureScaleTask.h" +#include "pxr/imaging/hdx/fullscreenShader.h" +#include "pxr/imaging/hdx/package.h" + +#include "pxr/imaging/hd/camera.h" +#include "pxr/imaging/hd/perfLog.h" +#include "pxr/imaging/hd/tokens.h" + +#include "pxr/imaging/hf/perfLog.h" +#include "pxr/imaging/hio/glslfx.h" + +#include "pxr/imaging/hgi/blitCmds.h" +#include "pxr/imaging/hgi/blitCmdsOps.h" +#include "pxr/imaging/hgi/hgi.h" +#include "pxr/imaging/hgi/tokens.h" + +PXR_NAMESPACE_OPEN_SCOPE + +TF_DEFINE_PRIVATE_TOKENS( + _tokens, + ((exposureScaleFrag, "ExposureScaleFragment")) +); + +HdxExposureScaleTask::HdxExposureScaleTask( + HdSceneDelegate* delegate, + SdfPath const& id) + : HdxTask(id) +{ +} + +HdxExposureScaleTask::~HdxExposureScaleTask() = default; + +void +HdxExposureScaleTask::_Sync(HdSceneDelegate* delegate, + HdTaskContext* ctx, + HdDirtyBits* dirtyBits) +{ + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + if (!_compositor) { + _compositor = std::make_unique( + _GetHgi(), "ExposureScale"); + } + + if ((*dirtyBits) & HdChangeTracker::DirtyParams) { + HdxExposureScaleTaskParams params; + + if (_GetTaskParams(delegate, ¶ms)) { + _cameraPath = params.cameraPath; + } + } + + // Currently, we're querying GetExposureScale() every frame - not + // sure if there's a better way to detect if this is dirty? + if (_cameraPath.IsEmpty()) { + _exposureScale = 1.0f; + } else { + HdRenderIndex &renderIndex = delegate->GetRenderIndex(); + const HdCamera *camera = static_cast( + renderIndex.GetSprim(HdPrimTypeTokens->camera, _cameraPath)); + if (!TF_VERIFY(camera)) { + return; + } + + _exposureScale = camera->GetExposureScale(); + } + + *dirtyBits = HdChangeTracker::Clean; +} + +void +HdxExposureScaleTask::Prepare(HdTaskContext* ctx, + HdRenderIndex* renderIndex) +{ +} + +void +HdxExposureScaleTask::Execute(HdTaskContext* ctx) +{ + HD_TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + HgiTextureHandle aovTexture; + _GetTaskContextData(ctx, HdAovTokens->color, &aovTexture); + + HgiShaderFunctionDesc fragDesc; + fragDesc.debugName = _tokens->exposureScaleFrag.GetString(); + fragDesc.shaderStage = HgiShaderStageFragment; + HgiShaderFunctionAddStageInput( + &fragDesc, "uvOut", "vec2"); + HgiShaderFunctionAddTexture( + &fragDesc, "colorIn"); + HgiShaderFunctionAddStageOutput( + &fragDesc, "hd_FragColor", "vec4", "color"); + + // The order of the constant parameters has to match the order in the + // _ParameterBuffer struct + HgiShaderFunctionAddConstantParam( + &fragDesc, "screenSize", "vec2"); + HgiShaderFunctionAddConstantParam( + &fragDesc, "exposureScale", "float"); + + _compositor->SetProgram( + HdxPackageExposureScaleShader(), + _tokens->exposureScaleFrag, + fragDesc); + const auto &aovDesc = aovTexture->GetDescriptor(); + if (_UpdateParameterBuffer( + static_cast(aovDesc.dimensions[0]), + static_cast(aovDesc.dimensions[1]))) { + size_t byteSize = sizeof(_ParameterBuffer); + _compositor->SetShaderConstants(byteSize, &_parameterData); + } + + _compositor->BindTextures({aovTexture}); + + _compositor->Draw(aovTexture, /*no depth*/HgiTextureHandle()); +} + +bool +HdxExposureScaleTask::_UpdateParameterBuffer( + float screenSizeX, float screenSizeY) +{ + _ParameterBuffer pb; + + pb.exposureScale = _exposureScale; + pb.screenSize[0] = screenSizeX; + pb.screenSize[1] = screenSizeY; + + // All data is still the same, no need to update the storage buffer + if (pb == _parameterData) { + return false; + } + + _parameterData = pb; + + return true; +} + + +// -------------------------------------------------------------------------- // +// VtValue Requirements +// -------------------------------------------------------------------------- // + +std::ostream& operator<<( + std::ostream& out, + const HdxExposureScaleTaskParams& pv) +{ + out << "ExposureScaleTask Params: (...) " + << pv.cameraPath << " " + ; + return out; +} + +bool operator==(const HdxExposureScaleTaskParams& lhs, + const HdxExposureScaleTaskParams& rhs) +{ + return lhs.cameraPath == rhs.cameraPath; +} + +bool operator!=(const HdxExposureScaleTaskParams& lhs, + const HdxExposureScaleTaskParams& rhs) +{ + return !(lhs == rhs); +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/hdx/exposureScaleTask.h b/pxr/imaging/hdx/exposureScaleTask.h new file mode 100644 index 0000000000..cc266378bf --- /dev/null +++ b/pxr/imaging/hdx/exposureScaleTask.h @@ -0,0 +1,102 @@ +// +// Copyright 2024 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// +#ifndef HDX_EXPOSURESCALE_TASK_H +#define HDX_EXPOSURESCALE_TASK_H + +#include "pxr/pxr.h" +#include "pxr/usd/sdf/path.h" +#include "pxr/imaging/hdx/api.h" +#include "pxr/imaging/hdx/task.h" +#include "pxr/imaging/hdx/tokens.h" +#include "pxr/imaging/hgi/graphicsCmds.h" + +PXR_NAMESPACE_OPEN_SCOPE + +/// \class HdxExposureScaleTask +/// +/// A task for applying an exposure scale for display. +/// +class HdxExposureScaleTask : public HdxTask +{ +public: + HDX_API + HdxExposureScaleTask(HdSceneDelegate* delegate, SdfPath const& id); + + HDX_API + ~HdxExposureScaleTask() override; + + /// Prepare the tasks resources + HDX_API + void Prepare(HdTaskContext* ctx, + HdRenderIndex* renderIndex) override; + + /// Execute the exposure scale task + HDX_API + void Execute(HdTaskContext* ctx) override; + +protected: + /// Sync the render pass resources + HDX_API + void _Sync(HdSceneDelegate* delegate, + HdTaskContext* ctx, + HdDirtyBits* dirtyBits) override; + +private: + HdxExposureScaleTask() = delete; + HdxExposureScaleTask(const HdxExposureScaleTask &) = delete; + HdxExposureScaleTask &operator =(const HdxExposureScaleTask &) = delete; + + // Utility function to update the shader uniform parameters. + // Returns true if the values were updated. False if unchanged. + bool _UpdateParameterBuffer(float screenSizeX, float screenSizeY); + + // This struct must match ParameterBuffer in exposureScale.glslfx. + // Be careful to remember the std430 rules. + struct _ParameterBuffer + { + float screenSize[2]; + float exposureScale; + bool operator==(const _ParameterBuffer& other) const { + return exposureScale == other.exposureScale && + screenSize[0] == other.screenSize[0] && + screenSize[1] == other.screenSize[1]; + } + }; + + std::unique_ptr _compositor; + _ParameterBuffer _parameterData; + + SdfPath _cameraPath; + + // The multiplier to be applied to the displayed pixels + float _exposureScale = 1.0f; +}; + + +/// \class HdxExposureScaleTaskParams +/// +/// ExposureScaleTask parameters. +/// +struct HdxExposureScaleTaskParams +{ + SdfPath cameraPath; +}; + +// VtValue requirements +HDX_API +std::ostream& operator<<(std::ostream& out, const HdxExposureScaleTaskParams& pv); +HDX_API +bool operator==(const HdxExposureScaleTaskParams& lhs, + const HdxExposureScaleTaskParams& rhs); +HDX_API +bool operator!=(const HdxExposureScaleTaskParams& lhs, + const HdxExposureScaleTaskParams& rhs); + + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif diff --git a/pxr/imaging/hdx/package.cpp b/pxr/imaging/hdx/package.cpp index ea5c1f8f14..817c202aa8 100644 --- a/pxr/imaging/hdx/package.cpp +++ b/pxr/imaging/hdx/package.cpp @@ -90,6 +90,13 @@ HdxPackageRenderPassShadowShader() return shader; } +TfToken +HdxPackageExposureScaleShader() +{ + static TfToken shader = _GetShaderPath("exposureScale.glslfx"); + return shader; +} + TfToken HdxPackageColorChannelShader() { diff --git a/pxr/imaging/hdx/package.h b/pxr/imaging/hdx/package.h index cf65d649d4..e8880d6ff5 100644 --- a/pxr/imaging/hdx/package.h +++ b/pxr/imaging/hdx/package.h @@ -21,6 +21,7 @@ TfToken HdxPackageRenderPassColorWithOccludedSelectionShader(); TfToken HdxPackageRenderPassIdShader(); TfToken HdxPackageRenderPassPickingShader(); TfToken HdxPackageRenderPassShadowShader(); +TfToken HdxPackageExposureScaleShader(); TfToken HdxPackageColorChannelShader(); TfToken HdxPackageColorCorrectionShader(); TfToken HdxPackageVisualizeAovShader(); diff --git a/pxr/imaging/hdx/shaders/exposureScale.glslfx b/pxr/imaging/hdx/shaders/exposureScale.glslfx new file mode 100644 index 0000000000..07870ae5ea --- /dev/null +++ b/pxr/imaging/hdx/shaders/exposureScale.glslfx @@ -0,0 +1,34 @@ +-- glslfx version 0.1 + +// +// Copyright 2024 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +-- configuration +{ + "techniques": { + "default": { + "ExposureScaleFragment": { + "source": [ "ExposureScale.Fragment" ] + } + } + } +} + + +-- glsl ExposureScale.Fragment + + +void main(void) +{ + vec2 fragCoord = uvOut * screenSize; + vec4 color = HgiTexelFetch_colorIn(ivec2(fragCoord)); + + // Only color, not alpha is exposure scaled! + color.rgb *= exposureScale; + + hd_FragColor = color; +} diff --git a/pxr/imaging/hdx/taskController.cpp b/pxr/imaging/hdx/taskController.cpp index 4bc82e2ff5..789852fc00 100644 --- a/pxr/imaging/hdx/taskController.cpp +++ b/pxr/imaging/hdx/taskController.cpp @@ -14,6 +14,7 @@ #include "pxr/imaging/hdx/boundingBoxTask.h" #include "pxr/imaging/hdx/colorizeSelectionTask.h" #include "pxr/imaging/hdx/colorCorrectionTask.h" +#include "pxr/imaging/hdx/exposureScaleTask.h" #include "pxr/imaging/hdx/freeCameraSceneDelegate.h" #include "pxr/imaging/hdx/oitRenderTask.h" #include "pxr/imaging/hdx/oitResolveTask.h" @@ -47,6 +48,7 @@ TF_DEFINE_PRIVATE_TOKENS( (shadowTask) (aovInputTask) (selectionTask) + (exposureScaleTask) (colorizeSelectionTask) (oitResolveTask) (colorCorrectionTask) @@ -200,6 +202,7 @@ HdxTaskController::~HdxTaskController() _selectionTaskId, _simpleLightTaskId, _shadowTaskId, + _exposureScaleTaskId, _colorizeSelectionTaskId, _colorCorrectionTaskId, _pickTaskId, @@ -257,10 +260,12 @@ HdxTaskController::_CreateRenderGraph() _renderTaskIds.push_back(_CreateRenderTask( HdStMaterialTagTokens->volume)); + if (_AovsSupported()) { _CreateAovInputTask(); _CreateOitResolveTask(); _CreateSelectionTask(); + _CreateExposureScaleTask(); _CreateColorCorrectionTask(); _CreateVisualizeAovTask(); _CreatePresentTask(); @@ -281,6 +286,7 @@ HdxTaskController::_CreateRenderGraph() if (_AovsSupported()) { if (_gpuEnabled) { _CreateAovInputTask(); + _CreateExposureScaleTask(); _CreateColorizeSelectionTask(); _CreateColorCorrectionTask(); _CreateVisualizeAovTask(); @@ -442,6 +448,23 @@ HdxTaskController::_CreateSelectionTask() selectionParams); } +void +HdxTaskController::_CreateExposureScaleTask() +{ + // Create a post-process exposure scaling task. + _exposureScaleTaskId = GetControllerId().AppendChild( + _tokens->exposureScaleTask); + + HdxExposureScaleTaskParams exposureScaleParams; + + GetRenderIndex()->InsertTask(&_delegate, + _exposureScaleTaskId); + + _delegate.SetParameter(_exposureScaleTaskId, HdTokens->params, + exposureScaleParams); +} + + void HdxTaskController::_CreateColorizeSelectionTask() { @@ -645,6 +668,12 @@ HdxTaskController::_SelectionEnabled() const return !renderTaskParams.enableIdRender; } +bool +HdxTaskController::_ExposureScaleEnabled() const +{ + return _viewportAov == HdAovTokens->color; +} + bool HdxTaskController::_ColorizeSelectionEnabled() const { @@ -699,6 +728,7 @@ HdxTaskController::GetRenderingTasks() const * - aovInputTaskId * - boundingBoxTaskId * - selectionTaskId + * - exposureScaleTaskId * - colorizeSelectionTaskId * - colorCorrectionTaskId * - visualizeAovTaskId @@ -758,6 +788,10 @@ HdxTaskController::GetRenderingTasks() const tasks.push_back(GetRenderIndex()->GetTask(_selectionTaskId)); } + if (!_exposureScaleTaskId.IsEmpty() && _ExposureScaleEnabled()) { + tasks.push_back(GetRenderIndex()->GetTask(_exposureScaleTaskId)); + } + if (!_colorizeSelectionTaskId.IsEmpty() && _ColorizeSelectionEnabled()) { tasks.push_back(GetRenderIndex()->GetTask(_colorizeSelectionTaskId)); } @@ -2031,6 +2065,18 @@ HdxTaskController::_SetCameraParamForTasks(SdfPath const& id) GetRenderIndex()->GetChangeTracker().MarkTaskDirty( _pickFromRenderBufferTaskId, HdChangeTracker::DirtyParams); } + + if (!_exposureScaleTaskId.IsEmpty()) { + HdxExposureScaleTaskParams params = + _delegate.GetParameter( + _exposureScaleTaskId, HdTokens->params); + params.cameraPath = _activeCameraId; + _delegate.SetParameter(_exposureScaleTaskId, HdTokens->params, + params); + GetRenderIndex()->GetChangeTracker().MarkTaskDirty( + _exposureScaleTaskId, HdChangeTracker::DirtyParams); + } + } } diff --git a/pxr/imaging/hdx/taskController.h b/pxr/imaging/hdx/taskController.h index 839916d3c2..82fc6bdf08 100644 --- a/pxr/imaging/hdx/taskController.h +++ b/pxr/imaging/hdx/taskController.h @@ -267,6 +267,7 @@ class HdxTaskController final SdfPath _CreateRenderTask(TfToken const& materialTag); void _CreateOitResolveTask(); void _CreateSelectionTask(); + void _CreateExposureScaleTask(); void _CreateColorizeSelectionTask(); void _CreateColorCorrectionTask(); void _CreateVisualizeAovTask(); @@ -287,6 +288,7 @@ class HdxTaskController final bool _ShadowsEnabled() const; bool _SelectionEnabled() const; bool _ColorizeSelectionEnabled() const; + bool _ExposureScaleEnabled() const; bool _ColorCorrectionEnabled() const; bool _VisualizeAovEnabled() const; bool _ColorizeQuantizationEnabled() const; @@ -381,6 +383,7 @@ class HdxTaskController final SdfPath _aovInputTaskId; SdfPath _oitResolveTaskId; SdfPath _selectionTaskId; + SdfPath _exposureScaleTaskId; SdfPath _colorizeSelectionTaskId; SdfPath _colorCorrectionTaskId; SdfPath _visualizeAovTaskId; diff --git a/pxr/imaging/hdx/tokens.h b/pxr/imaging/hdx/tokens.h index 9fd7ff347e..e10042c524 100644 --- a/pxr/imaging/hdx/tokens.h +++ b/pxr/imaging/hdx/tokens.h @@ -63,6 +63,7 @@ TF_DECLARE_PUBLIC_TOKENS(HdxTokens, HDX_API, HDX_TOKENS); (colorizeSelectionTask) \ (drawTargetTask) \ (drawTargetResolveTask) \ + (exposureScaleTask) \ (oitRenderTask) \ (oitResolveTask) \ (oitVolumeRenderTask) \