optimize libibl for smaller workloads
We now never process mirroring or mipmaping with multithreading it's just not worth it given the overhead of the jobsystem. We also require 64 lines per job, below that, we only multithread per face (6 threads). This should probably depends on the sample count, but we don't have this facility yet. Special case downsampling for mipmaping. This alone improves performance by 2x for small cubemaps (e.g. 16x16).
This commit is contained in:
committed by
Mathias Agopian
parent
56e9d8eda5
commit
bc01475920
@@ -99,7 +99,8 @@ public:
|
||||
inline Texel filterAt(const filament::math::double3& direction) const;
|
||||
|
||||
//! samples an image at the given location in pixel using bilinear filtering
|
||||
static Texel filterAt(const Image& image, double x, double y);
|
||||
static Texel filterAt(const Image& image, float x, float y);
|
||||
static Texel filterAtCenter(const Image& image, size_t x, size_t y);
|
||||
|
||||
//! samples two cubemaps in a given direction and lerps the result by a given lerp factor
|
||||
static Texel trilinearFilterAt(const Cubemap& c0, const Cubemap& c1, double lerp,
|
||||
|
||||
@@ -55,6 +55,14 @@ public:
|
||||
ReduceProc<STATE> reduce = [](STATE&) {},
|
||||
const STATE& prototype = STATE());
|
||||
|
||||
//! process the cubemap
|
||||
template<typename STATE>
|
||||
static void processSingleThreaded(Cubemap& cm,
|
||||
utils::JobSystem& js,
|
||||
ScanlineProc<STATE> proc,
|
||||
ReduceProc<STATE> reduce = [](STATE&) {},
|
||||
const STATE& prototype = STATE());
|
||||
|
||||
//! Converts equirectangular Image to a Cubemap
|
||||
static void equirectangularToCubemap(utils::JobSystem& js, Cubemap& dst, const Image& src);
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ void Cubemap::makeSeamless() {
|
||||
corners(Face::NY);
|
||||
}
|
||||
|
||||
Cubemap::Texel Cubemap::filterAt(const Image& image, double x, double y) {
|
||||
Cubemap::Texel Cubemap::filterAt(const Image& image, float x, float y) {
|
||||
const size_t x0 = size_t(x);
|
||||
const size_t y0 = size_t(y);
|
||||
// we allow ourselves to read past the width/height of the Image because the data is valid
|
||||
@@ -188,6 +188,18 @@ Cubemap::Texel Cubemap::filterAt(const Image& image, double x, double y) {
|
||||
return (one_minus_u*one_minus_v)*c0 + (u*one_minus_v)*c1 + (one_minus_u*v)*c2 + (u*v)*c3;
|
||||
}
|
||||
|
||||
Cubemap::Texel Cubemap::filterAtCenter(const Image& image, size_t x0, size_t y0) {
|
||||
// we allow ourselves to read past the width/height of the Image because the data is valid
|
||||
// and contain the "seamless" data.
|
||||
size_t x1 = x0 + 1;
|
||||
size_t y1 = y0 + 1;
|
||||
const Texel& c0 = sampleAt(image.getPixelRef(x0, y0));
|
||||
const Texel& c1 = sampleAt(image.getPixelRef(x1, y0));
|
||||
const Texel& c2 = sampleAt(image.getPixelRef(x0, y1));
|
||||
const Texel& c3 = sampleAt(image.getPixelRef(x1, y1));
|
||||
return (c0 + c1 + c2 + c3) * 0.25f;
|
||||
}
|
||||
|
||||
Cubemap::Texel Cubemap::trilinearFilterAt(const Cubemap& l0, const Cubemap& l1, double lerp,
|
||||
const double3& L)
|
||||
{
|
||||
|
||||
@@ -229,13 +229,13 @@ void CubemapUtils::crossToCubemap(JobSystem& js, Cubemap& dst, const Image& src)
|
||||
|
||||
void CubemapUtils::downsampleCubemapLevelBoxFilter(JobSystem& js, Cubemap& dst, const Cubemap& src) {
|
||||
size_t scale = src.getDimensions() / dst.getDimensions();
|
||||
process<EmptyState>(dst, js,
|
||||
processSingleThreaded<EmptyState>(dst, js,
|
||||
[&](EmptyState&, size_t y, Cubemap::Face f, Cubemap::Texel* data, size_t dim) {
|
||||
const Image& image(src.getImageForFace(f));
|
||||
for (size_t x=0 ; x<dim ; ++x, ++data) {
|
||||
Cubemap::writeAt(data, Cubemap::filterAt(image, x*scale+0.5, y*scale+0.5));
|
||||
}
|
||||
});
|
||||
const Image& image(src.getImageForFace(f));
|
||||
for (size_t x = 0; x < dim; ++x, ++data) {
|
||||
Cubemap::writeAt(data, Cubemap::filterAtCenter(image, x * scale, y * scale));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -311,7 +311,7 @@ Cubemap CubemapUtils::create(Image& image, size_t dim, bool horizontal) {
|
||||
}
|
||||
|
||||
void CubemapUtils::mirrorCubemap(JobSystem& js, Cubemap& dst, const Cubemap& src) {
|
||||
process<EmptyState>(dst, js,
|
||||
processSingleThreaded<EmptyState>(dst, js,
|
||||
[&](EmptyState&, size_t y, Cubemap::Face f, Cubemap::Texel* data, size_t dim) {
|
||||
for (size_t x=0 ; x<dim ; ++x, ++data) {
|
||||
const double3 N(dst.getDirectionFor(f, x, y));
|
||||
|
||||
@@ -36,6 +36,22 @@ void CubemapUtils::process(
|
||||
const size_t dim = cm.getDimensions();
|
||||
|
||||
// multithread only on large-ish cubemaps
|
||||
if (dim < 64) {
|
||||
// 64 pixels occupies 12 cache lines exactly
|
||||
STATE s;
|
||||
for (size_t faceIndex = 0; faceIndex < 6; faceIndex++) {
|
||||
const Cubemap::Face f = (Cubemap::Face)faceIndex;
|
||||
Image& image(cm.getImageForFace(f));
|
||||
for (size_t y = 0; y < dim; y++) {
|
||||
Cubemap::Texel* data = static_cast<Cubemap::Texel*>(image.getPixelRef(0, y));
|
||||
proc(s, y, f, data, dim);
|
||||
}
|
||||
}
|
||||
reduce(s);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
STATE states[6];
|
||||
for (STATE& s : states) {
|
||||
s = prototype;
|
||||
@@ -60,7 +76,7 @@ void CubemapUtils::process(
|
||||
|
||||
if (std::is_same<STATE, CubemapUtils::EmptyState>::value) {
|
||||
auto job = jobs::parallel_for(js, parent, 0, uint32_t(dim),
|
||||
std::ref(parallelJobTask), jobs::CountSplitter<1, 8>());
|
||||
std::ref(parallelJobTask), jobs::CountSplitter<64, 8>());
|
||||
|
||||
// we need to wait here because parallelJobTask is passed by reference
|
||||
js.runAndWait(job);
|
||||
@@ -79,6 +95,30 @@ void CubemapUtils::process(
|
||||
}
|
||||
}
|
||||
|
||||
template<typename STATE>
|
||||
void CubemapUtils::processSingleThreaded(
|
||||
Cubemap& cm,
|
||||
utils::JobSystem& js,
|
||||
CubemapUtils::ScanlineProc<STATE> proc,
|
||||
ReduceProc<STATE> reduce,
|
||||
const STATE& prototype) {
|
||||
using namespace utils;
|
||||
|
||||
const size_t dim = cm.getDimensions();
|
||||
|
||||
STATE s;
|
||||
for (size_t faceIndex = 0; faceIndex < 6; faceIndex++) {
|
||||
const Cubemap::Face f = (Cubemap::Face)faceIndex;
|
||||
Image& image(cm.getImageForFace(f));
|
||||
for (size_t y = 0; y < dim; y++) {
|
||||
Cubemap::Texel* data = static_cast<Cubemap::Texel*>(image.getPixelRef(0, y));
|
||||
proc(s, y, f, data, dim);
|
||||
}
|
||||
}
|
||||
reduce(s);
|
||||
}
|
||||
|
||||
|
||||
} // namespace ibl
|
||||
} // namespace filament
|
||||
|
||||
|
||||
Reference in New Issue
Block a user