Denoiser quality level, HIGH is using cleanAux and prefiltering
This commit is contained in:
+2
-1
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -94,6 +94,7 @@ class GLFWOSPRayWindow
|
||||
cpp::FrameBuffer framebuffer;
|
||||
cpp::Future currentFrame;
|
||||
cpp::Texture backplateTex{"texture2d"};
|
||||
cpp::ImageOperation denoiser;
|
||||
|
||||
int targetFrames{8};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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};
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user