Skip to content

Commit d8a2f78

Browse files
committed
OIDN: acceleration (multithreading)
1 parent 46a30c3 commit d8a2f78

File tree

2 files changed

+113
-47
lines changed

2 files changed

+113
-47
lines changed

include/slg/film/imagepipeline/plugins/intel_oidn.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <string>
2626

2727
#include <boost/serialization/export.hpp>
28+
#include <tbb/scalable_allocator.h>
2829

2930
//#include <OpenImageDenoise/oidn.hpp>
3031

@@ -55,7 +56,16 @@ class IntelOIDN : public ImagePipelinePlugin {
5556
// Used by serialization
5657
IntelOIDN();
5758

58-
void FilterImage(const std::string &imageName,
59+
using float_buffer = std::vector<float, tbb::scalable_allocator<float>>;
60+
61+
float_buffer PrepareBuffer (
62+
const std::string& imageName,
63+
const GenericFrameBuffer<4, 1, float>& channel,
64+
const u_int width,
65+
const u_int height,
66+
bool enablePrefiltering
67+
) const;
68+
void FilterImage (const std::string &imageName,
5969
const float *srcBuffer, float *dstBuffer,
6070
const float *albedoBuffer, const float *normalBuffer,
6171
const u_int width, const u_int height,

src/slg/film/imagepipeline/plugins/intel_oidn.cpp

Lines changed: 102 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,15 @@
2323
#include <boost/format.hpp>
2424

2525
#include <OpenImageDenoise/oidn.hpp>
26+
#include <oneapi/tbb.h>
2627

2728
#include "slg/film/imagepipeline/plugins/intel_oidn.h"
2829
#include "slg/film/framebuffer.h"
2930

3031
using namespace std;
3132
using namespace luxrays;
3233
using namespace slg;
34+
using namespace oneapi::tbb;
3335

3436
//------------------------------------------------------------------------------
3537
//Intel Open Image Denoise
@@ -89,7 +91,7 @@ void IntelOIDN::FilterImage(const string &imageName,
8991
filter.set("cleanAux", cleanAux);
9092
filter.set("maxMemoryMB", oidnMemLimit);
9193
filter.setImage("color", colorBuf, oidn::Format::Float3, width, height);
92-
if (albedoBuffer) {
94+
if (albedoBuffer) {
9395
filter.setImage("albedo", albedoBuf, oidn::Format::Float3, width, height);
9496

9597
// Normals can only be used if albedo is supplied as well
@@ -110,6 +112,49 @@ void IntelOIDN::FilterImage(const string &imageName,
110112
SLG_LOG("IntelOIDNPlugin " + imageName + " filtering error: " << errorMessage);
111113
}
112114

115+
116+
IntelOIDN::float_buffer IntelOIDN::PrepareBuffer (
117+
const std::string& imageName,
118+
const GenericFrameBuffer<4, 1, float>& channel,
119+
const u_int width,
120+
const u_int height,
121+
bool enablePrefiltering
122+
) const {
123+
IntelOIDN::float_buffer outBuffer(width * height * 3);
124+
IntelOIDN::float_buffer tmpBuffer(outBuffer.size());
125+
IntelOIDN::float_buffer dummy1(outBuffer.size());
126+
IntelOIDN::float_buffer dummy2(outBuffer.size());
127+
128+
// Extract channel
129+
tbb::parallel_for(
130+
tbb::blocked_range<u_int>(0, width * height),
131+
[&](tbb::blocked_range<u_int>& r) {
132+
for (u_int i = r.begin(); i < r.end(); ++i)
133+
channel.GetWeightedPixel(i, &tmpBuffer[i * 3]);
134+
}
135+
);
136+
137+
// Prefilter
138+
if (enablePrefiltering) {
139+
FilterImage(
140+
imageName,
141+
&tmpBuffer[0],
142+
&outBuffer[0],
143+
&dummy1[0],
144+
&dummy2[0],
145+
width, height,
146+
false
147+
);
148+
} else {
149+
return tmpBuffer;
150+
}
151+
152+
return outBuffer;
153+
154+
}
155+
156+
157+
113158
void IntelOIDN::Apply(Film &film, const u_int index) {
114159
const double totalStartTime = WallClockTime();
115160

@@ -121,61 +166,72 @@ void IntelOIDN::Apply(Film &film, const u_int index) {
121166
const u_int height = film.GetHeight();
122167
const u_int pixelCount = width * height;
123168

124-
vector<float> outputBuffer(3 * pixelCount);
125-
vector<float> albedoBuffer(3 * pixelCount);
126-
vector<float> normalBuffer(3 * pixelCount), dummy1(3 * pixelCount), dummy2(3 * pixelCount);
127-
169+
float_buffer outputBuffer(3 * pixelCount);
170+
float_buffer albedoBuffer;
171+
float_buffer normalBuffer;
172+
173+
// Prepare functions
174+
auto prepareAlbedo = [&]() {
175+
albedoBuffer = PrepareBuffer(
176+
"Albedo",
177+
*film.channel_ALBEDO,
178+
width,
179+
height,
180+
enablePrefiltering
181+
);
182+
};
183+
184+
auto prepareNormal = [&]() {
185+
normalBuffer = PrepareBuffer(
186+
"Normal",
187+
*film.channel_AVG_SHADING_NORMAL,
188+
width,
189+
height,
190+
enablePrefiltering
191+
);
192+
};
193+
194+
SLG_LOG("IntelOIDNPlugin preparing inputs");
128195
if (film.HasChannel(Film::ALBEDO)) {
129-
albedoBuffer.resize(3 * pixelCount);
130-
for (u_int i = 0; i < pixelCount; ++i)
131-
film.channel_ALBEDO->GetWeightedPixel(i, &albedoBuffer[i * 3]);
132-
133-
//GenericFrameBuffer<3, 0, float>::SaveHDR("debug-albedo0.exr", albedoBuffer, width, height);
134-
135-
if (enablePrefiltering) {
136-
vector<float> albedoBufferTmp(3 * pixelCount);
137-
FilterImage("Albedo", &albedoBuffer[0], &albedoBufferTmp[0],
138-
&dummy1[0], &dummy2[0], width, height, false);
139-
for (u_int i = 0; i < albedoBuffer.size(); ++i)
140-
albedoBuffer[i] = albedoBufferTmp[i];
141-
142-
//GenericFrameBuffer<3, 0, float>::SaveHDR("debug-albedo1.exr", albedoBuffer, width, height);
143-
}
144-
145-
// Normals can only be used if albedo is supplied as well
146196
if (film.HasChannel(Film::AVG_SHADING_NORMAL)) {
147-
normalBuffer.resize(3 * pixelCount);
148-
for (u_int i = 0; i < pixelCount; ++i)
149-
film.channel_AVG_SHADING_NORMAL->GetWeightedPixel(i, &normalBuffer[i * 3]);
150-
151-
//GenericFrameBuffer<3, 0, float>::SaveHDR("debug-normal.exr", normalBuffer, width, height);
152-
153-
if (enablePrefiltering) {
154-
vector<float> normalBufferTmp(3 * pixelCount);
155-
FilterImage("Normal", &normalBuffer[0], &normalBufferTmp[0],
156-
&dummy1[0], &dummy2[0], width, height, false);
157-
for (u_int i = 0; i < normalBuffer.size(); ++i)
158-
normalBuffer[i] = normalBufferTmp[i];
159-
160-
//GenericFrameBuffer<3, 0, float>::SaveHDR("debug-normal1.exr", normalBuffer, width, height);
161-
}
162-
} else
163-
SLG_LOG("[IntelOIDNPlugin] Warning: AVG_SHADING_NORMAL AOV not found");
164-
} else
197+
// Prepare both (and parallelize)
198+
tbb::parallel_invoke(prepareAlbedo, prepareNormal);
199+
} else {
200+
// Prepare only albedo
201+
SLG_LOG("[IntelOIDNPlugin] Warning: AVG_SHADING_NORMAL AOV not found");
202+
prepareAlbedo();
203+
normalBuffer = float_buffer(3 * pixelCount);
204+
}
205+
} else {
165206
SLG_LOG("[IntelOIDNPlugin] Warning: ALBEDO AOV not found");
207+
albedoBuffer = float_buffer(3 * pixelCount);
208+
normalBuffer = float_buffer(3 * pixelCount);
209+
}
166210

211+
212+
SLG_LOG("IntelOIDNPlugin filtering image");
167213
FilterImage("Image Pipeline", (float *)pixels, &outputBuffer[0],
168214
(albedoBuffer.size() > 0) ? &albedoBuffer[0] : nullptr,
169215
(normalBuffer.size() > 0) ? &normalBuffer[0] : nullptr,
170216
width, height, enablePrefiltering);
171217

172218
SLG_LOG("IntelOIDNPlugin copying output buffer");
173-
for (u_int i = 0; i < pixelCount; ++i) {
174-
const u_int i3 = i * 3;
175-
pixels[i].c[0] = Lerp(sharpness, outputBuffer[i3], pixels[i].c[0]);
176-
pixels[i].c[1] = Lerp(sharpness, outputBuffer[i3 + 1], pixels[i].c[1]);
177-
pixels[i].c[2] = Lerp(sharpness, outputBuffer[i3 + 2], pixels[i].c[2]);
178-
}
219+
tbb::affinity_partitioner aff_p;
220+
tbb::parallel_for(
221+
tbb::blocked_range2d<size_t, size_t>(0, pixelCount, 0, 3),
222+
[&](const blocked_range2d<size_t, size_t>& r) {
223+
for (size_t i = r.rows().begin(); i < r.rows().end(); ++i) {
224+
for (size_t j = r.cols().begin(); j < r.cols().end(); ++j) {
225+
pixels[i].c[j] = std::lerp(
226+
outputBuffer[i * 3 + j],
227+
pixels[i].c[j],
228+
sharpness
229+
);
230+
}
231+
}
232+
},
233+
aff_p
234+
);
179235

180236
SLG_LOG("IntelOIDNPlugin single execution took a total of " << (boost::format("%.3f") % (WallClockTime() - totalStartTime)) << "secs");
181237
}

0 commit comments

Comments
 (0)