Denoiser quality level, HIGH is using cleanAux and prefiltering

This commit is contained in:
Johannes Günther
2024-07-15 19:07:32 +02:00
parent 89dbb1930d
commit f995831810
26 changed files with 513 additions and 248 deletions
+2 -1
View File
@@ -21,7 +21,8 @@ Version History
`targetFrames` parameter at the framebuffer
- Note a maximum of 64k samples is supported
- Improved `denoiser` image operation:
- Optionally denoise alpha channel as well, controlled via
- User-controlled quality levels via parameter `quality`
- Optionally denoise alpha channel as well, enabled via
parameter `denoiseAlpha`
- Removed Intel ISPCRT dependency (ISPC compiler is still needed):
- oneAPI Level Zero Loader is no longer necessary
+21 -4
View File
@@ -100,6 +100,9 @@ static const std::vector<std::string> g_pixelFilterTypes = {
static const std::vector<std::string> g_AOVs = {
"color", "depth", "albedo", "primID", "objID", "instID"};
static const std::vector<std::string> g_denoiserQuality = {
"low", "medium", "high"};
const char *vec_string_getter(void *vec_, int index)
{
auto v = (std::vector<std::string> *)vec_;
@@ -115,13 +118,16 @@ void error_callback(int error, const char *desc)
GLFWOSPRayWindow *GLFWOSPRayWindow::activeWindow = nullptr;
GLFWOSPRayWindow::GLFWOSPRayWindow(const vec2i &windowSize, bool denoiser)
: denoiserAvailable(denoiser)
GLFWOSPRayWindow::GLFWOSPRayWindow(const vec2i &windowSize, bool denoiserAvail)
: denoiserAvailable(denoiserAvail)
{
if (activeWindow != nullptr) {
throw std::runtime_error("Cannot create more than one GLFWOSPRayWindow!");
}
if (denoiserAvailable)
denoiser = cpp::ImageOperation("denoiser");
activeWindow = this;
glfwSetErrorCallback(error_callback);
@@ -643,6 +649,18 @@ void GLFWOSPRayWindow::buildUI()
if (denoiserAvailable) {
if (ImGui::Checkbox("denoiser", &denoiserEnabled))
updateFrameOpsNextFrame = true;
static int whichQuality = 1; // medium
if (denoiserEnabled
&& ImGui::Combo("quality##whichQuality",
&whichQuality,
vec_string_getter,
(void *)&g_denoiserQuality,
g_denoiserQuality.size())) {
denoiser.setParam("quality",
OSPDenoiserQuality::OSP_DENOISER_QUALITY_LOW + whichQuality);
addObjectToCommit(denoiser.handle());
}
}
ImGui::Separator();
@@ -975,8 +993,7 @@ void GLFWOSPRayWindow::refreshFrameOperations()
{
framebuffer.setParam("targetFrames", targetFrames);
if (denoiserEnabled) {
cpp::ImageOperation d("denoiser");
framebuffer.setParam("imageOperation", cpp::CopiedData(d));
framebuffer.setParam("imageOperation", cpp::CopiedData(denoiser));
} else {
framebuffer.removeParam("imageOperation");
}
+1
View File
@@ -94,6 +94,7 @@ class GLFWOSPRayWindow
cpp::FrameBuffer framebuffer;
cpp::Future currentFrame;
cpp::Texture backplateTex{"texture2d"};
cpp::ImageOperation denoiser;
int targetFrames{8};
+14 -19
View File
@@ -29,15 +29,6 @@ PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>
)
if (OSPRAY_ENABLE_VOLUMES)
# We need to know if volumes are enabled at compile time so that
# we can enable/disable the VKL-dependent tests for enum values
target_compile_definitions(ospray_gtest_utils
PUBLIC
OSPRAY_ENABLE_VOLUMES
)
endif()
add_executable(ospTestSuite
${OSPRAY_RESOURCE}
environment.cpp # potentially compile with SYCL, overriding non-SYCL ospray_gtest_utils
@@ -57,27 +48,31 @@ add_executable(ospTestSuite
ospTestSuite.cpp
)
# We need to know if volumes are enabled at compile time so that
# we can enable/disable the VKL-dependent tests for enum values
# Same for OIDN tests
target_compile_definitions(ospTestSuite
PRIVATE
$<$<BOOL:${OSPRAY_ENABLE_VOLUMES}>:OSPRAY_ENABLE_VOLUMES>
$<$<BOOL:${OSPRAY_MODULE_DENOISER}>:OSPRAY_MODULE_DENOISER>
)
target_include_directories(ospTestSuite
PRIVATE
$<$<BOOL:${OSPRAY_ENABLE_VOLUMES}>:$<TARGET_PROPERTY:openvkl::openvkl,INTERFACE_INCLUDE_DIRECTORIES>>
$<$<BOOL:${OSPRAY_MODULE_DENOISER}>:$<TARGET_PROPERTY:OpenImageDenoise,INTERFACE_INCLUDE_DIRECTORIES>>
)
target_link_libraries(ospTestSuite
PRIVATE
ospray_testing
ospray_gtest_utils
embree
$<$<BOOL:${OSPRAY_ENABLE_VOLUMES}>:openvkl::openvkl>
$<$<BOOL:${OSPRAY_APPS_ENABLE_GLM}>:${GLM_TARGET}>
)
if (OSPRAY_MODULE_GPU)
ospray_add_sycl_target(ospTestSuite)
endif()
if (OSPRAY_MODULE_DENOISER)
# Enable OIDN tests
target_compile_definitions(ospTestSuite
PUBLIC
OSPRAY_MODULE_DENOISER
)
endif()
ospray_sign_target(ospTestSuite)
install(TARGETS ospTestSuite
+12
View File
@@ -163,3 +163,15 @@ TEST(Enums, RTCGeometryType)
ASSERT_EQ(OSP_DISC, RTC_GEOMETRY_TYPE_DISC_POINT);
ASSERT_EQ(OSP_ORIENTED_DISC, RTC_GEOMETRY_TYPE_ORIENTED_DISC_POINT);
}
#ifdef OSPRAY_MODULE_DENOISER
#include "OpenImageDenoise/oidn.h"
TEST(Enums, OIDNQuality)
{
ASSERT_LE(sizeof(OSPDenoiserQuality), sizeof(OIDNQuality));
ASSERT_EQ(OSP_DENOISER_QUALITY_LOW, OIDN_QUALITY_FAST);
ASSERT_EQ(OSP_DENOISER_QUALITY_MEDIUM, OIDN_QUALITY_BALANCED);
ASSERT_EQ(OSP_DENOISER_QUALITY_HIGH, OIDN_QUALITY_HIGH);
}
#endif
+17 -3
View File
@@ -36,13 +36,20 @@ void ImageOpBase::SetUp()
camera.setParam("position", vec3f(0.f, 0.f, -2.5f));
imageOp = cpp::ImageOperation(imageOpType);
frames = 1;
framebuffer = cpp::FrameBuffer(imgSize.x,
imgSize.y,
frameBufferFormat,
OSP_FB_COLOR | OSP_FB_ALBEDO | OSP_FB_NORMAL);
framebuffer.setParam("imageOperation", cpp::CopiedData(imageOp));
framebuffer.commit();
}
#ifdef OSPRAY_MODULE_DENOISER
class DenoiserOp : public ImageOpBase,
public ::testing::TestWithParam<bool /*denoiseAlpha*/>
public ::testing::TestWithParam<
std::tuple<bool /*denoiseAlpha*/, OSPDenoiserQuality>>
{
public:
DenoiserOp()
@@ -55,7 +62,9 @@ class DenoiserOp : public ImageOpBase,
void SetUp() override
{
ImageOpBase::SetUp();
imageOp.setParam("denoiseAlpha", GetParam());
auto params = GetParam();
imageOp.setParam("denoiseAlpha", std::get<0>(params));
imageOp.setParam("quality", std::get<1>(params));
imageOp.commit();
}
};
@@ -86,7 +95,12 @@ TEST_P(DenoiserOp, DenoiserOp)
{
PerformRenderTest();
}
INSTANTIATE_TEST_SUITE_P(DenoiserOp, DenoiserOp, ::testing::Bool());
INSTANTIATE_TEST_SUITE_P(DenoiserOp,
DenoiserOp,
::testing::Combine(::testing::Bool(),
::testing::Values(OSP_DENOISER_QUALITY_LOW,
OSP_DENOISER_QUALITY_MEDIUM,
OSP_DENOISER_QUALITY_HIGH)));
#endif
TEST_P(ImageOp, ImageOp)
+1 -1
View File
@@ -15,7 +15,7 @@ set(ISPC_VERSION_REQUIRED 1.23.0)
set(RKCOMMON_VERSION_REQUIRED 1.14.0)
set(EMBREE_VERSION_REQUIRED 4.3.1)
set(OPENVKL_VERSION_REQUIRED 2.0.1)
set(OIDN_VERSION_REQUIRED 2.2.0)
set(OIDN_VERSION_REQUIRED 2.3.0)
set(OSPRAY_IMGUI_GIT_TAG cb16be3a3fc1f9cd146ae24d52b615f8a05fa93d) # v1.90.9
set(OSPRAY_STB_GIT_TAG 013ac3beddff3dbffafd5177e7972067cd2b5083) # v2.30 / v1.16
+18 -4
View File
@@ -3121,10 +3121,24 @@ using a GPU when available. The device selection be overridden by the
environment variable `OIDN_DEFAULT_DEVICE`, possible values are `cpu`,
`sycl`, `cuda`, `hip`, or a physical device ID
Type Name Default Description
----- ------------- -------- ------------------------------------------------
bool denoiseAlpha false whether to denoise the alpha channel as well
----- ------------- -------- ------------------------------------------------
----- ------------- ----------------------------------------------------------
Type Name Description
----- ------------- ----------------------------------------------------------
uint quality `OSPDenoiserQuality` for denoiser quality, default is
`OSP_DENOISER_QUALITY_MEDIUM`: balanced
quality/performance for interactive/real-time rendering;
also allowed are:
`OSP_DENOISER_QUALITY_LOW`: high performance, for
interactive/real-time preview rendering
`OSP_DENOISER_QUALITY_HIGH`: high quality, for final frame
rendering
bool denoiseAlpha whether to denoise the alpha channel as well, default
false
----- ------------- ----------------------------------------------------------
: Parameters accepted by the denoiser.
Rendering
+1 -1
View File
@@ -47,7 +47,7 @@ before you can build OSPRay you need the following prerequisites:
the variable `openvkl_DIR`, or disable `OSPRAY_ENABLE_VOLUMES`.
- OSPRay also provides an optional module implementing the `denoiser`
image operation, which is enabled by `OSPRAY_MODULE_DENOISER`. This
module requires Intel [Open Image Denoise] in version 2.2.0 or
module requires Intel [Open Image Denoise] in version 2.3.0 or
newer. You may need to hint the location of the library with the
CMake variable `OpenImageDenoise_DIR`.
- For the optional MPI modules (enabled by `OSPRAY_MODULE_MPI`), which
+4 -2
View File
@@ -83,8 +83,10 @@ FrameBuffer::FrameBuffer(api::ISPCDevice &device,
void FrameBuffer::commit()
{
imageOpData = getParamDataT<ImageOp *>("imageOperation");
getSh()->targetFrames =
doAccum ? max(0, getParam<int>("targetFrames", 0)) : 1;
// always query `targetFrames` to clear query status
getSh()->targetFrames = max(0, getParam<int>("targetFrames", 0));
if (!doAccum)
getSh()->targetFrames = 1;
}
void FrameBuffer::clear()
+397 -208
View File
@@ -16,7 +16,7 @@ void checkError(void * /*userPtr*/, oidn::Error error, const char *errorMessage)
}
}
void checkError(oidn::DeviceRef oidnDevice)
void checkError(oidn::DeviceRef &oidnDevice)
{
const char *errorMessage = nullptr;
auto error = oidnDevice.getError(errorMessage);
@@ -35,124 +35,199 @@ struct OSPRAY_MODULE_DENOISER_EXPORT LiveDenoiseFrameOp
}
protected:
void createFilterAlpha()
{
filterAlpha = denoiser->oidnDevice.newFilter("RT");
filterAlpha.set("hdr", false);
}
void updateFilters();
virtual void initFilterAlphaImages() = 0;
virtual void initFilterAuxImages() = 0;
virtual void updateFilterInput() = 0;
virtual void updateAuxImages(oidn::FilterRef &) = 0;
Ref<DenoiseFrameOp> denoiser;
FrameBufferView fbView;
oidn::FilterRef filter;
oidn::FilterRef filterAlpha;
oidn::FilterRef filterAlbedo;
oidn::FilterRef filterNormal;
bool prefilter{false};
};
void LiveDenoiseFrameOp::updateFilters()
{
prefilter = denoiser->quality == OIDN_QUALITY_HIGH;
if (prefilter) {
if (fbView.normalBuffer && !filterNormal) {
filterNormal = denoiser->oidnDevice.newFilter("RT");
filterNormal.set("quality", OIDN_QUALITY_HIGH);
}
if (fbView.albedoBuffer && !filterAlbedo) {
filterAlbedo = denoiser->oidnDevice.newFilter("RT");
filterAlbedo.set("quality", OIDN_QUALITY_HIGH);
}
initFilterAuxImages();
if (fbView.normalBuffer)
filterNormal.commit();
if (fbView.albedoBuffer)
filterAlbedo.commit();
}
filter.set("quality", denoiser->quality);
filter.set("cleanAux", prefilter);
updateFilterInput();
updateAuxImages(filter);
if (denoiser->denoiseAlpha) {
if (!filterAlpha) {
filterAlpha = denoiser->oidnDevice.newFilter("RT");
filterAlpha.set("hdr", false);
initFilterAlphaImages();
}
filterAlpha.set("quality", denoiser->quality);
filterAlpha.set("cleanAux", prefilter);
updateAuxImages(filterAlpha);
}
filter.commit();
if (denoiser->denoiseAlpha)
filterAlpha.commit();
}
struct OSPRAY_MODULE_DENOISER_EXPORT LiveDenoiseFrameOpShared
: public LiveDenoiseFrameOp
{
LiveDenoiseFrameOpShared(DenoiseFrameOp *denoiser, FrameBufferView &fbView)
: LiveDenoiseFrameOp(denoiser, fbView),
buffer(denoiser->oidnDevice.newBuffer(fbView.colorBufferOutput,
fbView.viewDims.long_product() * sizeof(vec4f))),
useInput(!denoiser->denoiseAlpha) // negate to trigger syncFilter
{
filter.setImage("output",
buffer,
LiveDenoiseFrameOpShared(DenoiseFrameOp *, FrameBufferView &);
protected:
// when alpha is not denoised we copy input buffer to output and then do
// in-place denoising to preserve alpha
oidn::BufferRef bufferOut; // shared buffer aliasing colorBufferOutput
private:
void initFilterAlphaImages() override;
void initFilterAuxImages() override;
void updateFilterInput() override;
void updateAuxImages(oidn::FilterRef &) override;
oidn::BufferRef bufferAux; // scratch buffer when prefiltering
size_t byteBufferSize;
size_t byteAlbedoOffset;
};
LiveDenoiseFrameOpShared::LiveDenoiseFrameOpShared(
DenoiseFrameOp *denoiser, FrameBufferView &fbView)
: LiveDenoiseFrameOp(denoiser, fbView),
bufferOut(denoiser->oidnDevice.newBuffer(fbView.colorBufferOutput,
fbView.viewDims.long_product() * sizeof(vec4f)))
{
filter.setImage("output",
bufferOut,
oidn::Format::Float3,
fbView.viewDims.x,
fbView.viewDims.y,
0,
4 * sizeof(float));
updateFilters();
}
void LiveDenoiseFrameOpShared::initFilterAlphaImages()
{
filterAlpha.setImage("color",
const_cast<vec4f *>(fbView.colorBufferInput),
oidn::Format::Float,
fbView.viewDims.x,
fbView.viewDims.y,
3 * sizeof(float),
4 * sizeof(float));
filterAlpha.setImage("output",
bufferOut,
oidn::Format::Float,
fbView.viewDims.x,
fbView.viewDims.y,
3 * sizeof(float),
4 * sizeof(float));
}
void LiveDenoiseFrameOpShared::initFilterAuxImages()
{
if (!bufferAux) {
byteBufferSize = 3 * sizeof(float) * fbView.fbDims.product();
size_t sz = 0;
if (fbView.normalBuffer)
sz += byteBufferSize;
if (fbView.albedoBuffer) {
byteAlbedoOffset = sz;
sz += byteBufferSize;
}
bufferAux = denoiser->oidnDevice.newBuffer(sz, oidn::Storage::Device);
}
if (fbView.normalBuffer) {
filterNormal.setImage("normal",
const_cast<vec3f *>(fbView.normalBuffer),
oidn::Format::Float3,
fbView.fbDims.x,
fbView.fbDims.y);
filterNormal.setImage("output",
bufferAux,
oidn::Format::Float3,
fbView.fbDims.x,
fbView.fbDims.y);
}
if (fbView.albedoBuffer) {
filterAlbedo.setImage("albedo",
const_cast<vec3f *>(fbView.albedoBuffer),
oidn::Format::Float3,
fbView.fbDims.x,
fbView.fbDims.y);
filterAlbedo.setImage("output",
bufferAux,
oidn::Format::Float3,
fbView.fbDims.x,
fbView.fbDims.y,
byteAlbedoOffset);
}
}
void LiveDenoiseFrameOpShared::updateFilterInput()
{
if (denoiser->denoiseAlpha)
filter.setImage("color",
const_cast<vec4f *>(fbView.colorBufferInput),
oidn::Format::Float3,
fbView.viewDims.x,
fbView.viewDims.y,
0,
4 * sizeof(float));
syncFilters();
setAuxImagesCommit(filter);
}
devicert::AsyncEvent process() override
{
syncFilters();
// TODO: Remove oidn::Buffer and copying after switching to OIDN 2.2
// when alpha is not denoised we copy input buffer to output and then do
// in-place denoising to preserve alpha
devicert::AsyncEvent event;
if (denoiser->drtDevice.getSyclQueuePtr()) {
if (denoiser->denoiseAlpha)
// Using SYCL call without SYCL, that's supported in C99 API only
oidnExecuteSYCLFilterAsync(
filterAlpha.getHandle(), nullptr, 0, nullptr);
else
buffer.writeAsync(0,
fbView.viewDims.long_product() * sizeof(vec4f),
fbView.colorBufferInput);
event = denoiser->drtDevice.createAsyncEvent();
sycl::event *syclEvent = (sycl::event *)event.getSyclEventPtr();
oidnExecuteSYCLFilterAsync(filter.getHandle(), nullptr, 0, syclEvent);
} else {
event = denoiser->drtDevice.launchHostTask([this]() {
if (denoiser->denoiseAlpha)
filterAlpha.execute();
else
buffer.write(0,
fbView.viewDims.long_product() * sizeof(vec4f),
fbView.colorBufferInput);
filter.execute();
});
}
return event;
}
private:
void initializeFilterAlpha()
{
if (filterAlpha)
return;
createFilterAlpha();
filterAlpha.setImage("color",
const_cast<vec4f *>(fbView.colorBufferInput),
oidn::Format::Float,
else
filter.setImage("color",
bufferOut, // in-place filtering of copied input
oidn::Format::Float3,
fbView.viewDims.x,
fbView.viewDims.y,
3 * sizeof(float),
0,
4 * sizeof(float));
filterAlpha.setImage("output",
buffer,
oidn::Format::Float,
fbView.viewDims.x,
fbView.viewDims.y,
3 * sizeof(float),
4 * sizeof(float));
setAuxImagesCommit(filterAlpha);
}
void syncFilters()
{
if (denoiser->denoiseAlpha)
initializeFilterAlpha();
if (useInput == denoiser->denoiseAlpha)
return;
useInput = denoiser->denoiseAlpha;
if (useInput)
filter.setImage("color",
const_cast<vec4f *>(fbView.colorBufferInput),
}
void LiveDenoiseFrameOpShared::updateAuxImages(oidn::FilterRef &filter)
{
if (prefilter) {
if (fbView.normalBuffer)
filter.setImage("normal",
bufferAux,
oidn::Format::Float3,
fbView.viewDims.x,
fbView.viewDims.y);
if (fbView.albedoBuffer)
filter.setImage("albedo",
bufferAux,
oidn::Format::Float3,
fbView.viewDims.x,
fbView.viewDims.y,
0,
4 * sizeof(float));
else
filter.setImage("color",
buffer,
oidn::Format::Float3,
fbView.viewDims.x,
fbView.viewDims.y,
0,
4 * sizeof(float));
filter.commit();
}
void setAuxImagesCommit(oidn::FilterRef filter)
{
byteAlbedoOffset);
} else {
if (fbView.normalBuffer)
filter.setImage("normal",
const_cast<vec3f *>(fbView.normalBuffer),
@@ -165,122 +240,91 @@ struct OSPRAY_MODULE_DENOISER_EXPORT LiveDenoiseFrameOpShared
oidn::Format::Float3,
fbView.viewDims.x,
fbView.viewDims.y);
filter.commit();
}
}
struct OSPRAY_MODULE_DENOISER_EXPORT LiveDenoiseFrameOpSharedSycl
: public LiveDenoiseFrameOpShared
{
LiveDenoiseFrameOpSharedSycl(
DenoiseFrameOp *denoiser, FrameBufferView &fbView)
: LiveDenoiseFrameOpShared(denoiser, fbView)
{}
devicert::AsyncEvent process() override;
};
devicert::AsyncEvent LiveDenoiseFrameOpSharedSycl::process()
{
updateFilters();
// Using SYCL calls without SYCL, that's supported in C99 API only
if (prefilter) {
if (filterNormal)
oidnExecuteSYCLFilterAsync(filterNormal.getHandle(), nullptr, 0, nullptr);
if (filterAlbedo)
oidnExecuteSYCLFilterAsync(filterAlbedo.getHandle(), nullptr, 0, nullptr);
}
oidn::BufferRef buffer;
bool useInput;
if (denoiser->denoiseAlpha)
oidnExecuteSYCLFilterAsync(filterAlpha.getHandle(), nullptr, 0, nullptr);
else
bufferOut.writeAsync(0,
fbView.viewDims.long_product() * sizeof(vec4f),
fbView.colorBufferInput);
devicert::AsyncEvent event = denoiser->drtDevice.createAsyncEvent();
oidnExecuteSYCLFilterAsync(
filter.getHandle(), nullptr, 0, (sycl::event *)event.getSyclEventPtr());
return event;
}
struct OSPRAY_MODULE_DENOISER_EXPORT LiveDenoiseFrameOpSharedCpu
: public LiveDenoiseFrameOpShared
{
LiveDenoiseFrameOpSharedCpu(DenoiseFrameOp *denoiser, FrameBufferView &fbView)
: LiveDenoiseFrameOpShared(denoiser, fbView)
{}
devicert::AsyncEvent process() override;
};
devicert::AsyncEvent LiveDenoiseFrameOpSharedCpu::process()
{
updateFilters();
devicert::AsyncEvent event = denoiser->drtDevice.launchHostTask([this]() {
if (prefilter) {
if (filterNormal)
filterNormal.execute();
if (filterAlbedo)
filterAlbedo.execute();
}
if (denoiser->denoiseAlpha)
filterAlpha.execute();
else
bufferOut.write(0,
fbView.viewDims.long_product() * sizeof(vec4f),
fbView.colorBufferInput);
filter.execute();
});
return event;
}
struct OSPRAY_MODULE_DENOISER_EXPORT LiveDenoiseFrameOpCopy
: public LiveDenoiseFrameOp
{
LiveDenoiseFrameOpCopy(DenoiseFrameOp *denoiser, FrameBufferView &fbView)
: LiveDenoiseFrameOp(denoiser, fbView)
{
byteFloatBufferSize = sizeof(float) * fbView.fbDims.product();
size_t sz = 4 * byteFloatBufferSize;
LiveDenoiseFrameOpCopy(DenoiseFrameOp *, FrameBufferView &);
if (fbView.normalBuffer) {
byteNormalOffset = sz;
sz += 3 * byteFloatBufferSize;
}
if (fbView.albedoBuffer) {
byteAlbedoOffset = sz;
sz += 3 * byteFloatBufferSize;
}
buffer = denoiser->oidnDevice.newBuffer(sz, oidn::Storage::Device);
filter.setImage("color",
buffer,
oidn::Format::Float3,
fbView.fbDims.x,
fbView.fbDims.y,
0,
sizeof(float) * 4);
filter.setImage("output",
buffer,
oidn::Format::Float3,
fbView.fbDims.x,
fbView.fbDims.y,
0,
sizeof(float) * 4);
setAuxImagesCommit(filter);
if (denoiser->denoiseAlpha)
initializeFilterAlpha();
}
devicert::AsyncEvent process() override
{
if (denoiser->denoiseAlpha)
initializeFilterAlpha();
devicert::AsyncEvent event = denoiser->drtDevice.launchHostTask([this]() {
// As this path is taken when rendering on CPU and denoising on GPU,
// the asynchronous OIDN API is used to reduce the number of CPU - GPU
// synchronization points which would take place on every command in case
// of using synchronous OIDN API.
buffer.writeAsync(0, 4 * byteFloatBufferSize, fbView.colorBufferInput);
if (fbView.normalBuffer)
buffer.writeAsync(
byteNormalOffset, 3 * byteFloatBufferSize, fbView.normalBuffer);
if (fbView.albedoBuffer)
buffer.writeAsync(
byteAlbedoOffset, 3 * byteFloatBufferSize, fbView.albedoBuffer);
filter.executeAsync();
if (denoiser->denoiseAlpha)
filterAlpha.executeAsync();
buffer.readAsync(0, 4 * byteFloatBufferSize, fbView.colorBufferOutput);
denoiser->oidnDevice.sync();
});
return event;
}
devicert::AsyncEvent process() override;
private:
void initializeFilterAlpha()
{
if (filterAlpha)
return;
filterAlpha.setImage("color",
buffer,
oidn::Format::Float,
fbView.fbDims.x,
fbView.fbDims.y,
sizeof(float) * 3,
sizeof(float) * 4);
filterAlpha.setImage("output",
buffer,
oidn::Format::Float,
fbView.fbDims.x,
fbView.fbDims.y,
sizeof(float) * 3,
sizeof(float) * 4);
setAuxImagesCommit(filterAlpha);
}
void setAuxImagesCommit(oidn::FilterRef filter)
{
if (fbView.normalBuffer)
filter.setImage("normal",
buffer,
oidn::Format::Float3,
fbView.fbDims.x,
fbView.fbDims.y,
byteNormalOffset);
if (fbView.albedoBuffer)
filter.setImage("albedo",
buffer,
oidn::Format::Float3,
fbView.fbDims.x,
fbView.fbDims.y,
byteAlbedoOffset);
filter.commit();
}
void initFilterAlphaImages() override;
void initFilterAuxImages() override;
void updateFilterInput() override;
void updateAuxImages(oidn::FilterRef &) override;
oidn::BufferRef buffer;
size_t byteFloatBufferSize;
@@ -288,6 +332,148 @@ struct OSPRAY_MODULE_DENOISER_EXPORT LiveDenoiseFrameOpCopy
size_t byteAlbedoOffset;
};
LiveDenoiseFrameOpCopy::LiveDenoiseFrameOpCopy(
DenoiseFrameOp *denoiser, FrameBufferView &fbView)
: LiveDenoiseFrameOp(denoiser, fbView)
{
byteFloatBufferSize = sizeof(float) * fbView.fbDims.product();
size_t sz = 4 * byteFloatBufferSize;
if (fbView.normalBuffer) {
byteNormalOffset = sz;
sz += 3 * byteFloatBufferSize;
}
if (fbView.albedoBuffer) {
byteAlbedoOffset = sz;
sz += 3 * byteFloatBufferSize;
}
buffer = denoiser->oidnDevice.newBuffer(sz, oidn::Storage::Device);
filter.setImage("output",
buffer,
oidn::Format::Float3,
fbView.fbDims.x,
fbView.fbDims.y,
0,
sizeof(float) * 4);
updateFilters();
}
devicert::AsyncEvent LiveDenoiseFrameOpCopy::process()
{
updateFilters();
// As this path is taken when rendering on CPU and denoising on GPU,
// the asynchronous OIDN API is used to reduce the number of CPU - GPU
// synchronization points which would take place on every command in case
// of using synchronous OIDN API.
devicert::AsyncEvent event = denoiser->drtDevice.launchHostTask([this]() {
buffer.writeAsync(0, 4 * byteFloatBufferSize, fbView.colorBufferInput);
if (fbView.normalBuffer)
buffer.writeAsync(
byteNormalOffset, 3 * byteFloatBufferSize, fbView.normalBuffer);
if (fbView.albedoBuffer)
buffer.writeAsync(
byteAlbedoOffset, 3 * byteFloatBufferSize, fbView.albedoBuffer);
if (prefilter) {
if (filterNormal)
filterNormal.executeAsync();
if (filterAlbedo)
filterAlbedo.executeAsync();
}
filter.executeAsync();
if (denoiser->denoiseAlpha)
filterAlpha.executeAsync();
buffer.readAsync(0, 4 * byteFloatBufferSize, fbView.colorBufferOutput);
denoiser->oidnDevice.sync();
});
return event;
}
void LiveDenoiseFrameOpCopy::initFilterAlphaImages()
{
filterAlpha.setImage("color",
buffer,
oidn::Format::Float,
fbView.fbDims.x,
fbView.fbDims.y,
sizeof(float) * 3,
sizeof(float) * 4);
filterAlpha.setImage("output",
buffer,
oidn::Format::Float,
fbView.fbDims.x,
fbView.fbDims.y,
sizeof(float) * 3,
sizeof(float) * 4);
}
void LiveDenoiseFrameOpCopy::initFilterAuxImages()
{
if (fbView.normalBuffer) {
filterNormal.setImage("normal",
buffer,
oidn::Format::Float3,
fbView.fbDims.x,
fbView.fbDims.y,
byteNormalOffset);
filterNormal.setImage("output",
buffer,
oidn::Format::Float3,
fbView.fbDims.x,
fbView.fbDims.y,
byteNormalOffset);
}
if (fbView.albedoBuffer) {
filterAlbedo.setImage("albedo",
buffer,
oidn::Format::Float3,
fbView.fbDims.x,
fbView.fbDims.y,
byteAlbedoOffset);
filterAlbedo.setImage("output",
buffer,
oidn::Format::Float3,
fbView.fbDims.x,
fbView.fbDims.y,
byteAlbedoOffset);
}
}
void LiveDenoiseFrameOpCopy::updateFilterInput()
{
filter.setImage("color",
buffer,
oidn::Format::Float3,
fbView.fbDims.x,
fbView.fbDims.y,
0,
sizeof(float) * 4);
}
void LiveDenoiseFrameOpCopy::updateAuxImages(oidn::FilterRef &filter)
{
if (fbView.normalBuffer)
filter.setImage("normal",
buffer,
oidn::Format::Float3,
fbView.fbDims.x,
fbView.fbDims.y,
byteNormalOffset);
if (fbView.albedoBuffer)
filter.setImage("albedo",
buffer,
oidn::Format::Float3,
fbView.fbDims.x,
fbView.fbDims.y,
byteAlbedoOffset);
}
DenoiseFrameOp::DenoiseFrameOp(devicert::Device &device) : drtDevice(device)
{
// Get appropriate SYCL command queue for post-processing from device
@@ -305,20 +491,23 @@ DenoiseFrameOp::DenoiseFrameOp(devicert::Device &device) : drtDevice(device)
oidnDevice.set("verbose", 2);
oidnDevice.commit();
sharedMem = syclQueuePtr || oidnDevice.get<bool>("systemMemorySupported");
}
void DenoiseFrameOp::commit()
{
quality = getParam<uint32_t>("quality", OSP_DENOISER_QUALITY_MEDIUM);
denoiseAlpha = getParam<bool>("denoiseAlpha", false);
}
std::unique_ptr<LiveFrameOpInterface> DenoiseFrameOp::attach(
FrameBufferView &fbView)
{
if (sharedMem)
return rkcommon::make_unique<LiveDenoiseFrameOpShared>(this, fbView);
if (drtDevice.getSyclQueuePtr())
return rkcommon::make_unique<LiveDenoiseFrameOpSharedSycl>(this, fbView);
if (oidnDevice.get<bool>("systemMemorySupported"))
return rkcommon::make_unique<LiveDenoiseFrameOpSharedCpu>(this, fbView);
return rkcommon::make_unique<LiveDenoiseFrameOpCopy>(this, fbView);
}
+1 -1
View File
@@ -24,7 +24,7 @@ struct OSPRAY_MODULE_DENOISER_EXPORT DenoiseFrameOp : public FrameOpInterface
devicert::Device &drtDevice;
oidn::DeviceRef oidnDevice;
bool sharedMem{false};
int quality{OSP_DENOISER_QUALITY_MEDIUM};
bool denoiseAlpha{false};
};
+11
View File
@@ -423,3 +423,14 @@ typedef enum
OSP_INTENSITY_QUANTITY_SCALE, // linear scaling factor for the built-in type
OSP_INTENSITY_QUANTITY_UNKNOWN
} OSPIntensityQuantity;
// OSPRay quality levels (used for denoiser), same values as OIDN
typedef enum
#if __cplusplus >= 201103L
: uint32_t
#endif
{
OSP_DENOISER_QUALITY_LOW = 4,
OSP_DENOISER_QUALITY_MEDIUM = 5,
OSP_DENOISER_QUALITY_HIGH = 6
} OSPDenoiserQuality;
@@ -85,6 +85,7 @@ OSPTYPEFOR_SPECIALIZATION(OSPVolumeFormat, OSP_UINT);
OSPTYPEFOR_SPECIALIZATION(OSPPixelFilterType, OSP_UINT);
OSPTYPEFOR_SPECIALIZATION(OSPIntensityQuantity, OSP_UINT);
OSPTYPEFOR_SPECIALIZATION(OSPSphereType, OSP_UINT);
OSPTYPEFOR_SPECIALIZATION(OSPDenoiserQuality, OSP_UINT);
#define OSPTYPEFOR_DEFINITION(type) \
constexpr OSPDataType OSPTypeFor<type>::value
@@ -1 +1 @@
6e6fd579929319e3e2695fadad7b32b1
ded988069e8394b26dbe0ea554b4149b
@@ -1 +1 @@
2deee102aa0f8f803a45b79fd7e2ab73
e9e4a9c5dee535fe8e7996a519b67156
@@ -0,0 +1 @@
c384bd9efbe58c20f14dd01d73f0b069
@@ -0,0 +1 @@
69041af4dcb8bce523679bcb5f7436d4
@@ -0,0 +1 @@
6278286a6b4504277e4420ade3aebc9b
@@ -0,0 +1 @@
c75f4ef7cb81362bdf1f9a37033faf77
@@ -1 +1 @@
6e6fd579929319e3e2695fadad7b32b1
ded988069e8394b26dbe0ea554b4149b
@@ -1 +1 @@
2deee102aa0f8f803a45b79fd7e2ab73
e9e4a9c5dee535fe8e7996a519b67156
@@ -0,0 +1 @@
c384bd9efbe58c20f14dd01d73f0b069
@@ -0,0 +1 @@
69041af4dcb8bce523679bcb5f7436d4
@@ -0,0 +1 @@
6278286a6b4504277e4420ade3aebc9b
@@ -0,0 +1 @@
c75f4ef7cb81362bdf1f9a37033faf77