Compare commits

..
Author SHA1 Message Date
Eliza Velasquez ea9fdbeb5c wip: shader compilation benchmark 2024-01-16 17:03:41 -08:00
43 changed files with 454 additions and 302 deletions
+2
View File
@@ -7,3 +7,5 @@ for next branch cut* header.
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut
- Metal: fix some shader artifacts by disabling fast math optimizations.
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.50.1'
implementation 'com.google.android.filament:filament-android:1.49.3'
}
```
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
iOS projects can use CocoaPods to install the latest release:
```shell
pod 'Filament', '~> 1.50.1'
pod 'Filament', '~> 1.49.3'
```
### Snapshots
-6
View File
@@ -7,12 +7,6 @@ A new header is inserted each time a *tag* is created.
Instead, if you are authoring a PR for the main branch, add your release note to
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
## v1.50.1
- Metal: fix some shader artifacts by disabling fast math optimizations.
- backend: remove `atan2` overload which had a typo and wasn't useful. Fixes b/320856413.
- utils: remove usages of `SpinLock`. Fixes b/321101014.
## v1.50.0
- engine: TAA now supports 4x upscaling [BETA] [⚠️ **New Material Version**]
@@ -1882,7 +1882,7 @@ public class View {
* Options for Temporal Anti-aliasing (TAA)
* Most TAA parameters are extremely costly to change, as they will trigger the TAA post-process
* shaders to be recompiled. These options should be changed or set during initialization.
* `filterWidth`, `feedback` and `jitterPattern`, however, can be changed at any time.
* `filterWidth`, `feedback` and `jitterPattern`, however, could be changed at any time.
*
* `feedback` of 0.1 effectively accumulates a maximum of 19 samples in steady state.
* see "A Survey of Temporal Antialiasing Techniques" by Lei Yang and all for more information.
@@ -1925,7 +1925,6 @@ public class View {
UNIFORM_HELIX_X4,
HALTON_23_X8,
HALTON_23_X16,
HALTON_23_X32,
}
/**
@@ -1940,10 +1939,6 @@ public class View {
* texturing lod bias (typically -1 or -2)
*/
public float lodBias = -1.0f;
/**
* post-TAA sharpen, especially useful when upscaling is true.
*/
public float sharpness = 0.0f;
/**
* enables or disables temporal anti-aliasing
*/
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.50.1
VERSION_NAME=1.49.3
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
+4 -10
View File
@@ -41,24 +41,18 @@ public:
struct Stream {};
struct DriverConfig {
/**
* Size of handle arena in bytes. Setting to 0 indicates default value is to be used.
/*
* size of handle arena in bytes. Setting to 0 indicates default value is to be used.
* Driver clamps to valid values.
*/
size_t handleArenaSize = 0;
/**
* This number of most-recently destroyed textures will be tracked for use-after-free.
/*
* this number of most-recently destroyed textures will be tracked for use-after-free.
* Throws an exception when a texture is freed but still bound to a SamplerGroup and used in
* a draw call. 0 disables completely. Currently only respected by the Metal backend.
*/
size_t textureUseAfterFreePoolSize = 0;
/**
* Set to `true` to forcibly disable parallel shader compilation in the backend.
* Currently only honored by the GL backend.
*/
bool disableParallelShaderCompile = false;
};
Platform() noexcept;
-1
View File
@@ -19,7 +19,6 @@
#include <backend/PixelBufferDescriptor.h>
#include <cstring>
#include <stddef.h>
#include <stdint.h>
+3 -4
View File
@@ -147,9 +147,9 @@ Driver* OpenGLDriver::create(OpenGLPlatform* const platform,
#endif
size_t const defaultSize = FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U;
Platform::DriverConfig validConfig{ driverConfig };
Platform::DriverConfig validConfig {driverConfig};
validConfig.handleArenaSize = std::max(driverConfig.handleArenaSize, defaultSize);
OpenGLDriver* const driver = new(std::nothrow) OpenGLDriver(ec, validConfig);
OpenGLDriver* const driver = new OpenGLDriver(ec, validConfig);
return driver;
}
@@ -171,8 +171,7 @@ OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform, const Platform::DriverConfi
mContext(),
mShaderCompilerService(*this),
mHandleAllocator("Handles", driverConfig.handleArenaSize),
mSamplerMap(32),
mDriverConfig(driverConfig) {
mSamplerMap(32) {
std::fill(mSamplerBindings.begin(), mSamplerBindings.end(), nullptr);
@@ -400,9 +400,6 @@ private:
// timer query implementation
OpenGLTimerQueryInterface* mTimerQueryImpl = nullptr;
const Platform::DriverConfig mDriverConfig;
Platform::DriverConfig const& getDriverConfig() const noexcept { return mDriverConfig; }
// for ES2 sRGB support
GLSwapChain* mCurrentDrawSwapChain = nullptr;
bool mRec709OutputColorspace = false;
@@ -151,12 +151,6 @@ bool ShaderCompilerService::isParallelShaderCompileSupported() const noexcept {
}
void ShaderCompilerService::init() noexcept {
if (UTILS_UNLIKELY(mDriver.getDriverConfig().disableParallelShaderCompile)) {
// user disabled parallel shader compile
mMode = Mode::SYNCHRONOUS;
return;
}
// Here we decide which mode we'll be using. We always prefer our own thread-pool if
// that mode is available because, we have no control on how the compilation queues are
// handled if done by the driver (so at the very least we'd need to decode this per-driver).
@@ -109,7 +109,7 @@ private:
};
enum class Mode {
UNDEFINED, // init() has not been called yet.
UNDEFINED, // init() has not beed called yet.
SYNCHRONOUS, // synchronous shader compilation
THREAD_POOL, // asynchronous shader compilation using a thread-pool (most common)
ASYNCHRONOUS // asynchronous shader compilation using KHR_parallel_shader_compile
+1 -3
View File
@@ -438,7 +438,6 @@ struct TemporalAntiAliasingOptions {
float filterWidth = 1.0f; //!< reconstruction filter width typically between 0.2 (sharper, aliased) and 1.5 (smoother)
float feedback = 0.12f; //!< history feedback, between 0 (maximum temporal AA) and 1 (no temporal AA).
float lodBias = -1.0f; //!< texturing lod bias (typically -1 or -2)
float sharpness = 0.0f; //!< post-TAA sharpen, especially useful when upscaling is true.
bool enabled = false; //!< enables or disables temporal anti-aliasing
bool upscaling = false; //!< 4x TAA upscaling. Disables Dynamic Resolution. [BETA]
@@ -458,8 +457,7 @@ struct TemporalAntiAliasingOptions {
RGSS_X4, //! 4-samples, rotated grid sampling
UNIFORM_HELIX_X4, //! 4-samples, uniform grid in helix sequence
HALTON_23_X8, //! 8-samples of halton 2,3
HALTON_23_X16, //! 16-samples of halton 2,3
HALTON_23_X32 //! 32-samples of halton 2,3
HALTON_23_X16 //! 16-samples of halton 2,3
};
bool filterHistory = true; //!< whether to filter the history buffer
+75 -98
View File
@@ -64,7 +64,6 @@
#include <math/mat3.h>
#include <math/mat4.h>
#include <math/scalar.h>
#include <math/vec2.h>
#include <math/vec3.h>
#include <math/vec4.h>
@@ -75,7 +74,6 @@
#include <utils/FixedCapacityVector.h>
#include <algorithm>
#include <array>
#include <cmath>
#include <limits>
#include <string_view>
@@ -115,7 +113,7 @@ PostProcessManager::PostProcessMaterial::PostProcessMaterial() noexcept {
}
PostProcessManager::PostProcessMaterial::PostProcessMaterial(MaterialInfo const& info) noexcept
: PostProcessMaterial() {
: PostProcessMaterial() {
mData = info.data; // aliased to mMaterial
mSize = info.size;
mConstants = info.constants;
@@ -167,7 +165,7 @@ void PostProcessManager::PostProcessMaterial::loadMaterial(FEngine& engine) cons
mHasMaterial = true;
auto builder = Material::Builder();
builder.package(mData, mSize);
for (auto const& constant: mConstants) {
for (auto const& constant : mConstants) {
std::visit([&](auto&& arg) {
builder.constant(constant.name.data(), constant.name.size(), arg);
}, constant.value);
@@ -189,60 +187,63 @@ PipelineState PostProcessManager::PostProcessMaterial::getPipelineState(
FMaterial* const material = getMaterial(engine);
material->prepareProgram(Variant{ variantKey });
return {
.program = material->getProgram(Variant{ variantKey }),
.program = material->getProgram(Variant{variantKey}),
.rasterState = material->getRasterState(),
.scissor = material->getDefaultInstance()->getScissor()
};
}
UTILS_NOINLINE
FMaterialInstance* PostProcessManager::PostProcessMaterial::getMaterialInstance(
FEngine& engine) const noexcept {
FMaterialInstance* PostProcessManager::PostProcessMaterial::getMaterialInstance(FEngine& engine) const noexcept {
FMaterial* const material = getMaterial(engine);
return material->getDefaultInstance();
}
// ------------------------------------------------------------------------------------------------
const PostProcessManager::JitterSequence<4> PostProcessManager::sRGSS4 = {{{
const PostProcessManager::JitterSequence<4> PostProcessManager::sRGSS4 = {{
{ 0.625f, 0.125f },
{ 0.125f, 0.375f },
{ 0.875f, 0.625f },
{ 0.375f, 0.875f }
}}};
}};
const PostProcessManager::JitterSequence<4> PostProcessManager::sUniformHelix4 = {{{
const PostProcessManager::JitterSequence<4> PostProcessManager::sUniformHelix4 = {{
{ 0.25f, 0.25f },
{ 0.75f, 0.75f },
{ 0.25f, 0.75f },
{ 0.75f, 0.25f },
}}};
}};
template<size_t COUNT>
constexpr auto halton() {
std::array<float2, COUNT> h;
for (size_t i = 0; i < COUNT; i++) {
h[i] = {
filament::halton(i, 2),
filament::halton(i, 3) };
}
return h;
}
const PostProcessManager::JitterSequence<32>
PostProcessManager::sHaltonSamples = { halton<32>() };
const PostProcessManager::JitterSequence<16> PostProcessManager::sHaltonSamples = {{
{ filament::halton( 0, 2), filament::halton( 0, 3) },
{ filament::halton( 1, 2), filament::halton( 1, 3) },
{ filament::halton( 2, 2), filament::halton( 2, 3) },
{ filament::halton( 3, 2), filament::halton( 3, 3) },
{ filament::halton( 4, 2), filament::halton( 4, 3) },
{ filament::halton( 5, 2), filament::halton( 5, 3) },
{ filament::halton( 6, 2), filament::halton( 6, 3) },
{ filament::halton( 7, 2), filament::halton( 7, 3) },
{ filament::halton( 8, 2), filament::halton( 8, 3) },
{ filament::halton( 9, 2), filament::halton( 9, 3) },
{ filament::halton(10, 2), filament::halton(10, 3) },
{ filament::halton(11, 2), filament::halton(11, 3) },
{ filament::halton(12, 2), filament::halton(12, 3) },
{ filament::halton(13, 2), filament::halton(13, 3) },
{ filament::halton(14, 2), filament::halton(14, 3) },
{ filament::halton(15, 2), filament::halton(15, 3) }
}};
PostProcessManager::PostProcessManager(FEngine& engine) noexcept
: mEngine(engine),
mWorkaroundSplitEasu(false),
mWorkaroundAllowReadOnlyAncillaryFeedbackLoop(false) {
mWorkaroundSplitEasu(false),
mWorkaroundAllowReadOnlyAncillaryFeedbackLoop(false) {
}
PostProcessManager::~PostProcessManager() noexcept = default;
UTILS_NOINLINE
void PostProcessManager::registerPostProcessMaterial(std::string_view name,
MaterialInfo const& info) {
void PostProcessManager::registerPostProcessMaterial(std::string_view name, MaterialInfo const& info) {
mMaterialRegistry.try_emplace(name, info);
}
@@ -325,13 +326,13 @@ void PostProcessManager::init() noexcept {
driver.isWorkaroundNeeded(Workaround::ALLOW_READ_ONLY_ANCILLARY_FEEDBACK_LOOP);
#pragma nounroll
for (auto const& info: sMaterialListFeatureLevel0) {
for (auto const& info : sMaterialListFeatureLevel0) {
registerPostProcessMaterial(info.name, info);
}
if (mEngine.getActiveFeatureLevel() >= FeatureLevel::FEATURE_LEVEL_1) {
#pragma nounroll
for (auto const& info: sMaterialList) {
for (auto const& info : sMaterialList) {
registerPostProcessMaterial(info.name, info);
}
}
@@ -1682,8 +1683,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
// we assume the width/height is already multiple of 16
assert_invariant(!(colorDesc.width & 0xF) && !(colorDesc.height & 0xF));
const uint32_t tileBufferWidth = width;
const uint32_t tileBufferHeight = height;
const uint32_t tileBufferWidth = colorDesc.width / dofResolution;
const uint32_t tileBufferHeight = colorDesc.height / dofResolution;
const size_t tileReductionCount = ctz(tileSize / dofResolution);
struct PostProcessDofTiling1 {
@@ -2568,8 +2569,6 @@ void PostProcessManager::prepareTaa(FrameGraph& fg,
case JitterPattern::HALTON_23_X8:
return sHaltonSamples(frameIndex % 8);
case JitterPattern::HALTON_23_X16:
return sHaltonSamples(frameIndex % 16);
case JitterPattern::HALTON_23_X32:
return sHaltonSamples(frameIndex);
}
};
@@ -2619,7 +2618,6 @@ void PostProcessManager::configureTemporalAntiAliasingMaterial(
}
};
setConstantParameter(ma, "upscaling", taaOptions.upscaling);
setConstantParameter(ma, "historyReprojection", taaOptions.historyReprojection);
setConstantParameter(ma, "filterHistory", taaOptions.filterHistory);
setConstantParameter(ma, "filterInput", taaOptions.filterInput);
@@ -2769,77 +2767,24 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
});
input = colorGradingConfig.asSubpass ? taaPass->tonemappedOutput : taaPass->output;
auto history = input;
// optional sharpen pass from FSR1
if (taaOptions.sharpness > 0.0f) {
input = rcas(fg, taaOptions.sharpness,
input, fg.getDescriptor(input), colorGradingConfig.translucent);
}
struct ExportColorHistoryData {
FrameGraphId<FrameGraphTexture> color;
};
fg.addPass<ExportColorHistoryData>("Export TAA history",
auto& exportHistoryPass = fg.addPass<ExportColorHistoryData>("Export TAA history",
[&](FrameGraph::Builder& builder, auto& data) {
// We need to use sideEffect here to ensure this pass won't be culled.
// The "output" of this pass is going to be used during the next frame as
// an "import".
builder.sideEffect();
data.color = builder.sample(history); // FIXME: an access must be declared for detach(), why?
}, [&current](FrameGraphResources const& resources, auto const& data, auto&) {
resources.detach(data.color, &current.color, &current.desc);
data.color = builder.sample(input); // FIXME: an access must be declared for detach(), why?
}, [&current](FrameGraphResources const& resources, auto const& data,
backend::DriverApi&) {
resources.detach(data.color,
&current.color, &current.desc);
});
return input;
}
FrameGraphId<FrameGraphTexture> PostProcessManager::rcas(
FrameGraph& fg,
float sharpness,
FrameGraphId<FrameGraphTexture> input,
FrameGraphTexture::Descriptor const& outDesc,
bool translucent) {
struct QuadBlitData {
FrameGraphId<FrameGraphTexture> input;
FrameGraphId<FrameGraphTexture> output;
};
auto& ppFsrRcas = fg.addPass<QuadBlitData>("FidelityFX FSR1 Rcas",
[&](FrameGraph::Builder& builder, auto& data) {
data.input = builder.sample(input);
data.input = builder.createTexture("FFX FSR1 Rcas output", outDesc);
data.input = builder.declareRenderPass(data.input);
},
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
auto input = resources.getTexture(data.input);
auto out = resources.getRenderPassInfo();
auto const& outputDesc = resources.getDescriptor(data.input);
auto& material = getPostProcessMaterial("fsr_rcas");
FMaterialInstance* const mi = material.getMaterialInstance(mEngine);
FSRUniforms uniforms;
FSR_SharpeningSetup(&uniforms, { .sharpness = 2.0f - 2.0f * sharpness });
mi->setParameter("RcasCon", uniforms.RcasCon);
mi->setParameter("color", input, {}); // uses texelFetch
mi->setParameter("resolution", float4{
outputDesc.width, outputDesc.height,
1.0f / outputDesc.width, 1.0f / outputDesc.height });
mi->commit(driver);
mi->use(driver);
const uint8_t variant = uint8_t(
translucent ? PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE);
PipelineState const pipeline(material.getPipelineState(mEngine, variant));
render(out, pipeline, driver);
});
return ppFsrRcas->output;
return exportHistoryPass->color;
}
FrameGraphId<FrameGraphTexture> PostProcessManager::upscale(FrameGraph& fg, bool translucent,
@@ -3002,9 +2947,41 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscale(FrameGraph& fg, bool
auto output = ppQuadBlit->output;
// if we had to take the low quality fallback, we still do the "sharpen pass"
if (dsrOptions.sharpness > 0.0f &&
(dsrOptions.quality != QualityLevel::LOW || lowQualityFallback)) {
output = rcas(fg, dsrOptions.sharpness, output, outDesc, translucent);
if (dsrOptions.sharpness > 0.0f && (dsrOptions.quality != QualityLevel::LOW || lowQualityFallback)) {
auto& ppFsrRcas = fg.addPass<QuadBlitData>("FidelityFX FSR1 Rcas",
[&](FrameGraph::Builder& builder, auto& data) {
data.input = builder.sample(output);
data.output = builder.createTexture("FFX FSR1 Rcas output", outDesc);
data.output = builder.declareRenderPass(data.output);
},
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
auto color = resources.getTexture(data.input);
auto out = resources.getRenderPassInfo();
auto const& outputDesc = resources.getDescriptor(data.output);
auto& material = getPostProcessMaterial("fsr_rcas");
FMaterialInstance* const mi = material.getMaterialInstance(mEngine);
FSRUniforms uniforms;
FSR_SharpeningSetup(&uniforms, { .sharpness = 2.0f - 2.0f * dsrOptions.sharpness });
mi->setParameter("RcasCon", uniforms.RcasCon);
mi->setParameter("color", color, { }); // uses texelFetch
mi->setParameter("resolution", float4{
outputDesc.width, outputDesc.height,
1.0f / outputDesc.width, 1.0f / outputDesc.height });
mi->commit(driver);
mi->use(driver);
const uint8_t variant = uint8_t(translucent ?
PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE);
PipelineState const pipeline(material.getPipelineState(mEngine, variant));
render(out, pipeline, driver);
});
output = ppFsrRcas->output;
}
// we rely on automatic culling of unused render passes
+2 -10
View File
@@ -36,7 +36,6 @@
#include <tsl/robin_map.h>
#include <array>
#include <random>
#include <string_view>
#include <variant>
@@ -242,13 +241,6 @@ public:
filament::Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc,
backend::SamplerMagFilter filter) noexcept;
FrameGraphId<FrameGraphTexture> rcas(
FrameGraph& fg,
float sharpness,
FrameGraphId<FrameGraphTexture> input,
FrameGraphTexture::Descriptor const& outDesc,
bool translucent);
// upscale/downscale blitter using shaders
FrameGraphId<FrameGraphTexture> blit(FrameGraph& fg, bool translucent,
FrameGraphId<FrameGraphTexture> input,
@@ -370,12 +362,12 @@ private:
template<size_t SIZE>
struct JitterSequence {
auto operator()(size_t i) const noexcept { return positions[i % SIZE] - 0.5f; }
const std::array<math::float2, SIZE> positions;
const math::float2 positions[SIZE];
};
static const JitterSequence<4> sRGSS4;
static const JitterSequence<4> sUniformHelix4;
static const JitterSequence<32> sHaltonSamples;
static const JitterSequence<16> sHaltonSamples;
bool mWorkaroundSplitEasu : 1;
bool mWorkaroundAllowReadOnlyAncillaryFeedbackLoop : 1;
+4 -5
View File
@@ -30,12 +30,11 @@
#include <math/vec4.h>
#include <utils/JobSystem.h>
#include <utils/Mutex.h>
#include <utils/SpinLock.h>
#include <utils/Systrace.h>
#include <cmath>
#include <cstdlib>
#include <mutex>
#include <tuple>
namespace filament {
@@ -649,9 +648,9 @@ FColorGrading::FColorGrading(FEngine& engine, const Builder& builder) {
Config c;
// This lock protects the data inside Config, which is written to by the Filament thread,
// and read from multiple Job threads.
utils::Mutex configLock;
utils::SpinLock configLock;
{
std::lock_guard<utils::Mutex> const lock(configLock);
std::lock_guard<utils::SpinLock> lock(configLock);
c.lutDimension = builder->dimension;
c.adaptationTransform = adaptationTransform(builder->whiteBalance);
c.colorGradingIn = selectColorGradingTransformIn(builder->toneMapping);
@@ -688,7 +687,7 @@ FColorGrading::FColorGrading(FEngine& engine, const Builder& builder) {
[data, converted, b, &c, &configLock, builder](JobSystem&, JobSystem::Job*) {
Config config;
{
std::lock_guard<utils::Mutex> lock(configLock);
std::lock_guard<utils::SpinLock> lock(configLock);
config = c;
}
half4* UTILS_RESTRICT p = (half4*) data + b * config.lutDimension * config.lutDimension;
-1
View File
@@ -33,7 +33,6 @@
#include <utils/Mutex.h>
#include <atomic>
#include <optional>
namespace filament {
+2 -1
View File
@@ -985,7 +985,8 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
auto& history = view.getFrameHistory();
auto& current = history.getCurrent();
current.ssr.projection = projection;
resources.detach(data.history, &current.ssr.color, &current.ssr.desc);
resources.detach(data.history,
&current.ssr.color, &current.ssr.desc);
});
}
+1 -1
View File
@@ -132,7 +132,7 @@ public:
Descriptor descriptor;
SubResourceDescriptor subResourceDescriptor;
// whether the resource was detached
// weather the resource was detached
bool detached = false;
// An Edge with added data from this resource
+47 -97
View File
@@ -34,11 +34,6 @@ material {
}
],
constants : [
{
type : bool,
name : upscaling,
default : false
},
{
type : bool,
name : historyReprojection,
@@ -114,41 +109,12 @@ fragment {
// no clipping (for debugging only)
#define BOX_CLIPPING_NONE 2
float rcp(float x) {
return 1.0 / x;
}
float lumaRGB(const vec3 c) {
return luminance(c);
}
float lumaYCoCg(const vec3 c) {
return c.x;
}
float luma(const vec3 c) {
return materialConstants_useYCoCg ? lumaYCoCg(c) : lumaRGB(c);
}
vec3 tonemap(const vec3 c) {
return c * rcp(1.0 + max3(c));
}
vec4 tonemap(const vec4 c) {
return vec4(c.rgb * rcp(1.0 + max3(c.rgb)), c.a);
}
vec3 tonemap(const float w, const vec3 c) {
return c * (w * rcp(1.0 + max3(c)));
}
vec4 tonemap(const float w, const vec4 c) {
return vec4(c.rgb * (w * rcp(1.0 + max3(c.rgb))), c.a);
}
vec3 untonemap(const vec3 c) {
const float epsilon = 1.0 / 65504.0;
return c * rcp(max(epsilon, 1.0 - max3(c)));
float luma(const vec3 color) {
if (materialConstants_useYCoCg) {
return color.x;
} else {
return luminance(color);
}
}
vec3 RGB_YCoCg(const vec3 c) {
@@ -193,16 +159,15 @@ vec4 clipToBox(const int quality,
// Optimized to 5 taps by removing the corner samples
// And modified for mediump support
vec4 sampleTextureCatmullRom(const sampler2D tex, const highp vec2 uv, const highp vec2 texSize) {
// We're going to sample a a 4x4 grid of texels surrounding the target UV coordinate.
// We'll do this by rounding down the sample location to get the exact center of our "starting"
// texel. The starting texel will be at location [1, 1] in the grid, where [0, 0] is the
// top left corner.
// We're going to sample a a 4x4 grid of texels surrounding the target UV coordinate. We'll do this by rounding
// down the sample location to get the exact center of our "starting" texel. The starting texel will be at
// location [1, 1] in the grid, where [0, 0] is the top left corner.
highp vec2 samplePos = uv * texSize;
highp vec2 texPos1 = floor(samplePos - 0.5) + 0.5;
// Compute the fractional offset from our starting texel to our original sample location,
// which we'll feed into the Catmull-Rom spline function to get our filter weights.
// Compute the fractional offset from our starting texel to our original sample location, which we'll
// feed into the Catmull-Rom spline function to get our filter weights.
highp vec2 f = samplePos - texPos1;
highp vec2 f2 = f * f;
highp vec2 f3 = f2 * f;
@@ -235,20 +200,13 @@ vec4 sampleTextureCatmullRom(const sampler2D tex, const highp vec2 uv, const hig
float k3 = w3.x * w12.y;
float k4 = w12.x * w3.y;
vec4 s[5];
s[0] = textureLod(tex, vec2(texPos12.x, texPos0.y), 0.0);
s[1] = textureLod(tex, vec2(texPos0.x, texPos12.y), 0.0);
s[2] = textureLod(tex, vec2(texPos12.x, texPos12.y), 0.0);
s[3] = textureLod(tex, vec2(texPos3.x, texPos12.y), 0.0);
s[4] = textureLod(tex, vec2(texPos12.x, texPos3.y), 0.0);
vec4 result = textureLod(tex, vec2(texPos12.x, texPos0.y), 0.0) * k0
+ textureLod(tex, vec2(texPos0.x, texPos12.y), 0.0) * k1
+ textureLod(tex, vec2(texPos12.x, texPos12.y), 0.0) * k2
+ textureLod(tex, vec2(texPos3.x, texPos12.y), 0.0) * k3
+ textureLod(tex, vec2(texPos12.x, texPos3.y), 0.0) * k4;
vec4 result = k0 * s[0]
+ k1 * s[1]
+ k2 * s[2]
+ k3 * s[3]
+ k4 * s[4];
result *= rcp(k0 + k1 + k2 + k3 + k4);
result *= 1.0 / (k0 + k1 + k2 + k3 + k4);
// we could end-up with negative values
result = max(vec4(0), result);
@@ -284,7 +242,7 @@ void postProcess(inout PostProcessInputs postProcess) {
highp vec2 size = vec2(textureSize(materialParams_color, 0));
highp vec2 p = (floor(uv.xy * size) + 0.5) / size;
vec4 filtered = textureLod(materialParams_color, p, 0.0);
vec4 color = textureLod(materialParams_color, p, 0.0);
vec3 s[9];
if (materialConstants_filterInput || materialConstants_boxClipping != BOX_CLIPPING_NONE) {
@@ -292,12 +250,16 @@ void postProcess(inout PostProcessInputs postProcess) {
s[1] = textureLodOffset(materialParams_color, p, 0.0, ivec2( 0, -1)).rgb;
s[2] = textureLodOffset(materialParams_color, p, 0.0, ivec2( 1, -1)).rgb;
s[3] = textureLodOffset(materialParams_color, p, 0.0, ivec2(-1, 0)).rgb;
s[4] = filtered.rgb;
s[4] = color.rgb;
s[5] = textureLodOffset(materialParams_color, p, 0.0, ivec2( 1, 0)).rgb;
s[6] = textureLodOffset(materialParams_color, p, 0.0, ivec2(-1, 1)).rgb;
s[7] = textureLodOffset(materialParams_color, p, 0.0, ivec2( 0, 1)).rgb;
s[8] = textureLodOffset(materialParams_color, p, 0.0, ivec2( 1, 1)).rgb;
if (materialConstants_useYCoCg) {
}
if (materialConstants_useYCoCg) {
color.rgb = RGB_YCoCg(color.rgb);
if (materialConstants_filterInput || materialConstants_boxClipping != BOX_CLIPPING_NONE) {
for (int i = 0; i < 9; i++) {
s[i] = RGB_YCoCg(s[i]);
}
@@ -305,35 +267,24 @@ void postProcess(inout PostProcessInputs postProcess) {
}
vec2 subPixelOffset = p - uv.xy; // +/- [0.25, 0.25]
float confidence = materialConstants_upscaling ? 0.0 : 1.0;
float confidence = 0.0;
vec4 filtered = color;
if (materialConstants_filterInput) {
// unjitter/filter input
// figure out which set of coeficients to use
filtered = vec4(0, 0, 0, filtered.a);
if (materialConstants_upscaling) {
int jxp = subPixelOffset.y > 0.0 ? 3 : 0;
int jxn = subPixelOffset.y > 0.0 ? 2 : 1;
int j = subPixelOffset.x > 0.0 ? jxp : jxn;
for (int i = 0; i < 9; i++) {
float w = materialParams.filterWeights[i][j];
filtered.rgb += s[i] * w;
confidence = max(confidence, w);
}
} else {
for (int i = 0; i < 9; i++) {
float w = materialParams.filterWeights[i][0];
filtered.rgb += s[i] * w;
}
int jxp = subPixelOffset.y > 0.0 ? 3 : 0;
int jxn = subPixelOffset.y > 0.0 ? 2 : 1;
int j = subPixelOffset.x > 0.0 ? jxp : jxn;
filtered = vec4(0, 0, 0, color.a);
for (int i = 0; i < 9; i++) {
float w = materialParams.filterWeights[i][j];
filtered.rgb += s[i] * w;
confidence = max(confidence, w);
}
} else {
if (materialConstants_useYCoCg) {
filtered.rgb = RGB_YCoCg(filtered.rgb);
}
if (materialConstants_upscaling) {
confidence = float(materialParams.jitter.x * subPixelOffset.x > 0.0 &&
materialParams.jitter.y * subPixelOffset.y > 0.0);
}
confidence = float(materialParams.jitter.x * subPixelOffset.x > 0.0 &&
materialParams.jitter.y * subPixelOffset.y > 0.0);
}
// build the history clamping box
@@ -378,30 +329,29 @@ void postProcess(inout PostProcessInputs postProcess) {
history = clipToBox(materialConstants_boxClipping, boxmin, boxmax, filtered, history);
}
float lumaColor = luma(filtered.rgb);
float lumaHistory = luma(history.rgb);
float alpha = materialParams.alpha * confidence;
if (materialConstants_preventFlickering) {
// [Lottes] prevents flickering by modulating the blend weight by the difference in luma
float lumaColor = luma(filtered.rgb);
float lumaHistory = luma(history.rgb);
float diff = 1.0 - abs(lumaColor - lumaHistory) / (0.001 + max(lumaColor, lumaHistory));
alpha *= diff * diff;
}
// go back to RGB space before tonemapping
if (materialConstants_useYCoCg) {
filtered.rgb = YCoCg_RGB(filtered.rgb);
history.rgb = YCoCg_RGB(history.rgb);
}
// tonemap before mixing
filtered.rgb = tonemap(filtered.rgb);
history.rgb = tonemap(history.rgb);
// tonemapping for handling HDR
filtered.rgb *= 1.0 / (1.0 + lumaColor);
history.rgb *= 1.0 / (1.0 + lumaHistory);
// combine history and current frame
vec4 result = mix(history, filtered, alpha);
// untonemap result
result.rgb = untonemap(result.rgb);
result.rgb *= 1.0 / (1.0 - luma(result.rgb));
if (materialConstants_useYCoCg) {
result.rgb = YCoCg_RGB(result.rgb);
}
#if POST_PROCESS_OPAQUE
// kill the work performed above
-5
View File
@@ -43,8 +43,6 @@ fragment {
#define FSR_RCAS_F 1
#if !POST_PROCESS_OPAQUE
# define FSR_RCAS_PASSTHROUGH_ALPHA
// todo: make this a spec constant
# define FSR_RCAS_DENOISE
#endif
#include "ffx_fsr1.h"
@@ -63,9 +61,6 @@ fragment {
#endif
p, materialParams.RcasCon);
// todo: make this an option
postProcess.color.rgb = max(vec3(0), postProcess.color.rgb);
#if POST_PROCESS_OPAQUE
postProcess.color.a = 1.0;
#endif
+2 -2
View File
@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.50.1"
spec.version = "1.49.3"
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
spec.homepage = "https://google.github.io/filament"
spec.authors = "Google LLC."
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
spec.platform = :ios, "11.0"
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.50.1/filament-v1.50.1-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.49.3/filament-v1.49.3-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {
@@ -28,7 +28,7 @@
namespace filament {
// update this when a new version of filament wouldn't work with older materials
static constexpr size_t MATERIAL_VERSION = 50;
static constexpr size_t MATERIAL_VERSION = 49;
/**
* Supported shading models
@@ -48,7 +48,7 @@ fragment {
void dummy() {}
highp vec2 toEquirect(const highp vec3 s) {
highp float xf = atan(s.x, s.z) * (1.0 / PI); // range [-1.0, 1.0]
highp float xf = atan2(s.x, s.z) * (1.0 / PI); // range [-1.0, 1.0]
highp float yf = asin(s.y) * (2.0 / PI); // range [-1.0, 1.0]
xf = (xf + 1.0) * 0.5; // range [0, 1.0]
yf = (1.0 - yf) * 0.5; // range [0, 1.0]
@@ -62,22 +62,17 @@ mediump vec3 sampleEquirect(mediump sampler2D equirect, const highp vec3 r) {
void postProcess(inout PostProcessInputs postProcess) {
highp vec2 uv = variable_vertex.xy; // interpolated at pixel's center
highp vec2 p = vec2(
uv.x * 2.0 - 1.0,
1.0 - uv.y * 2.0);
highp vec2 p = uv * 2.0 - 1.0;
float side = materialParams.side;
highp float l = inversesqrt(p.x * p.x + p.y * p.y + 1.0);
// compute the view (and normal, since v = n) direction for each face
highp vec3 rx = vec3( side, p.y, side * -p.x);
highp vec3 ry = vec3( p.x, side, side * -p.y);
highp vec3 rz = vec3(side * p.x, p.y, side);
highp vec3 rx = normalize(vec3( side, -p.y, side * -p.x));
highp vec3 ry = normalize(vec3( p.x, side, side * p.y));
highp vec3 rz = normalize(vec3(side * p.x, -p.y, side));
postProcess.outx = sampleEquirect(materialParams_equirect, rx * l);
postProcess.outy = sampleEquirect(materialParams_equirect, ry * l);
postProcess.outz = sampleEquirect(materialParams_equirect, rz * l);
postProcess.outx = sampleEquirect(materialParams_equirect, rx);
postProcess.outy = sampleEquirect(materialParams_equirect, ry);
postProcess.outz = sampleEquirect(materialParams_equirect, rz);
}
}
+1
View File
@@ -37,6 +37,7 @@ set(DIST_HDRS
${PUBLIC_HDR_DIR}/${TARGET}/PrivateImplementation-impl.h
${PUBLIC_HDR_DIR}/${TARGET}/SingleInstanceComponentManager.h
${PUBLIC_HDR_DIR}/${TARGET}/Slice.h
${PUBLIC_HDR_DIR}/${TARGET}/SpinLock.h
${PUBLIC_HDR_DIR}/${TARGET}/StructureOfArrays.h
${PUBLIC_HDR_DIR}/${TARGET}/unwindows.h
)
@@ -38,6 +38,7 @@ protected:
utils::Arena<utils::ObjectPoolAllocator<Payload>, LockingPolicy::NoLock> mPoolAllocatorNoLock;
utils::Arena<utils::ObjectPoolAllocator<Payload>, std::mutex> mPoolAllocatorStdMutex;
utils::Arena<utils::ObjectPoolAllocator<Payload>, utils::Mutex> mPoolAllocatorUtilsMutex;
utils::Arena<utils::ObjectPoolAllocator<Payload>, LockingPolicy::SpinLock> mPoolAllocatorSpinlock;
utils::Arena<utils::ThreadSafeObjectPoolAllocator<Payload>, LockingPolicy::NoLock> mPoolAllocatorAtomic;
};
@@ -47,6 +48,7 @@ Allocators::Allocators()
: mPoolAllocatorNoLock("nolock", POOL_ITEM_COUNT * sizeof(Payload)),
mPoolAllocatorStdMutex("std::mutex", POOL_ITEM_COUNT * sizeof(Payload)),
mPoolAllocatorUtilsMutex("utils::Mutex", POOL_ITEM_COUNT * sizeof(Payload)),
mPoolAllocatorSpinlock("spinlock", POOL_ITEM_COUNT * sizeof(Payload)),
mPoolAllocatorAtomic("atomic", POOL_ITEM_COUNT * sizeof(Payload)) {
}
@@ -79,6 +81,15 @@ BENCHMARK_DEFINE_F(Allocators, poolAllocator_utils_mutex)(benchmark::State& stat
}
}
BENCHMARK_DEFINE_F(Allocators, poolAllocator_spinlock)(benchmark::State& state) {
auto& pool = mPoolAllocatorSpinlock;
PerformanceCounters pc(state);
for (auto _ : state) {
Payload* p = pool.alloc<Payload>(1);
pool.free(p);
}
}
BENCHMARK_DEFINE_F(Allocators, poolAllocator_atomic)(benchmark::State& state) {
auto& pool = mPoolAllocatorAtomic;
PerformanceCounters pc(state);
@@ -96,6 +107,10 @@ BENCHMARK_REGISTER_F(Allocators, poolAllocator_utils_mutex)
->ThreadRange(1, 4)
->Threads(benchmark::CPUInfo::Get().num_cpus * 2);
BENCHMARK_REGISTER_F(Allocators, poolAllocator_spinlock)
->ThreadRange(1, 4)
->Threads(benchmark::CPUInfo::Get().num_cpus * 2);
BENCHMARK_REGISTER_F(Allocators, poolAllocator_atomic)
->ThreadRange(1, 4)
->Threads(benchmark::CPUInfo::Get().num_cpus * 2);
+15
View File
@@ -41,6 +41,15 @@ static void BM_utils_mutex(benchmark::State& state) {
}
}
static void BM_spinlock(benchmark::State& state) {
static LockingPolicy::SpinLock l;
PerformanceCounters pc(state);
for (auto _ : state) {
l.lock();
l.unlock();
}
}
BENCHMARK(BM_std_mutex)
->Threads(1)
->Threads(2)
@@ -52,3 +61,9 @@ BENCHMARK(BM_utils_mutex)
->Threads(2)
->Threads(8)
->ThreadPerCpu();
BENCHMARK(BM_spinlock)
->Threads(1)
->Threads(2)
->Threads(8)
->ThreadPerCpu();
+2
View File
@@ -22,6 +22,7 @@
#include <utils/debug.h>
#include <utils/memalign.h>
#include <utils/Mutex.h>
#include <utils/SpinLock.h>
#include <atomic>
#include <cstddef>
@@ -477,6 +478,7 @@ struct NoLock {
void unlock() noexcept { }
};
using SpinLock = utils::SpinLock;
using Mutex = utils::Mutex;
} // namespace LockingPolicy
+1 -1
View File
@@ -387,7 +387,7 @@ private:
uint8_t mParallelSplitCount = 0; // # of split allowable in parallel_for
Job* mRootJob = nullptr;
utils::Mutex mThreadMapLock; // this should have very little contention
utils::SpinLock mThreadMapLock; // this should have very little contention
tsl::robin_map<std::thread::id, ThreadState *> mThreadMap;
};
+90
View File
@@ -0,0 +1,90 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_UTILS_SPINLOCK_H
#define TNT_UTILS_SPINLOCK_H
#include <utils/compiler.h>
#include <utils/Mutex.h>
#include <atomic>
#include <type_traits>
#include <assert.h>
#include <stddef.h>
namespace utils {
namespace details {
class SpinLock {
std::atomic_flag mLock = ATOMIC_FLAG_INIT;
public:
void lock() noexcept {
UTILS_PREFETCHW(&mLock);
#ifdef __ARM_ACLE
// we signal an event on this CPU, so that the first yield() will be a no-op,
// and falls through the test_and_set(). This is more efficient than a while { }
// construct.
UTILS_SIGNAL_EVENT();
do {
yield();
} while (mLock.test_and_set(std::memory_order_acquire));
#else
goto start;
do {
yield();
start: ;
} while (mLock.test_and_set(std::memory_order_acquire));
#endif
}
void unlock() noexcept {
mLock.clear(std::memory_order_release);
#ifdef __ARM_ARCH_7A__
// on ARMv7a SEL is needed
UTILS_SIGNAL_EVENT();
// as well as a memory barrier is needed
__dsb(0xA); // ISHST = 0xA (b1010)
#else
// on ARMv8 we could avoid the call to SE, but we'd need to write the
// test_and_set() above by hand, so the WFE only happens without a STRX first.
UTILS_BROADCAST_EVENT();
#endif
}
private:
inline void yield() noexcept {
// on x86 call pause instruction, on ARM call WFE
UTILS_WAIT_FOR_EVENT();
}
};
} // namespace details
#if UTILS_HAS_SANITIZE_THREAD
// Active spins with atomics slow down execution too much under ThreadSanitizer.
using SpinLock = Mutex;
#elif defined(__ARM_ARCH_7A__)
// We've had problems with "wfe" on some ARM-V7 devices, causing spurious SIGILL
using SpinLock = Mutex;
#else
using SpinLock = details::SpinLock;
#endif
} // namespace utils
#endif // TNT_UTILS_SPINLOCK_H
+3 -3
View File
@@ -293,7 +293,7 @@ void JobSystem::wakeOne() noexcept {
}
inline JobSystem::ThreadState& JobSystem::getState() noexcept {
std::lock_guard<utils::Mutex> lock(mThreadMapLock);
std::lock_guard<utils::SpinLock> lock(mThreadMapLock);
auto iter = mThreadMap.find(std::this_thread::get_id());
ASSERT_PRECONDITION(iter != mThreadMap.end(), "This thread has not been adopted.");
return *iter->second;
@@ -585,7 +585,7 @@ void JobSystem::runAndWait(JobSystem::Job*& job) noexcept {
void JobSystem::adopt() {
const auto tid = std::this_thread::get_id();
std::unique_lock<utils::Mutex> lock(mThreadMapLock);
std::unique_lock<utils::SpinLock> lock(mThreadMapLock);
auto iter = mThreadMap.find(tid);
ThreadState* const state = iter == mThreadMap.end() ? nullptr : iter->second;
lock.unlock();
@@ -618,7 +618,7 @@ void JobSystem::adopt() {
void JobSystem::emancipate() {
const auto tid = std::this_thread::get_id();
std::lock_guard<utils::Mutex> lock(mThreadMapLock);
std::lock_guard<utils::SpinLock> lock(mThreadMapLock);
auto iter = mThreadMap.find(tid);
ThreadState* const state = iter == mThreadMap.end() ? nullptr : iter->second;
ASSERT_PRECONDITION(state, "this thread is not an adopted thread");
-2
View File
@@ -22,8 +22,6 @@
#include <unistd.h>
#include <sys/stat.h>
#include <cstdint>
namespace utils {
bool Path::mkdir() const {
-5
View File
@@ -693,7 +693,6 @@ int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, TemporalAntiAli
else if (0 == compare(tokens[i], jsonChunk, "UNIFORM_HELIX_X4")) { *out = TemporalAntiAliasingOptions::JitterPattern::UNIFORM_HELIX_X4; }
else if (0 == compare(tokens[i], jsonChunk, "HALTON_23_X8")) { *out = TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X8; }
else if (0 == compare(tokens[i], jsonChunk, "HALTON_23_X16")) { *out = TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X16; }
else if (0 == compare(tokens[i], jsonChunk, "HALTON_23_X32")) { *out = TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X32; }
else {
slog.w << "Invalid TemporalAntiAliasingOptions::JitterPattern: '" << STR(tokens[i], jsonChunk) << "'" << io::endl;
}
@@ -706,7 +705,6 @@ std::ostream& operator<<(std::ostream& out, TemporalAntiAliasingOptions::JitterP
case TemporalAntiAliasingOptions::JitterPattern::UNIFORM_HELIX_X4: return out << "\"UNIFORM_HELIX_X4\"";
case TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X8: return out << "\"HALTON_23_X8\"";
case TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X16: return out << "\"HALTON_23_X16\"";
case TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X32: return out << "\"HALTON_23_X32\"";
}
return out << "\"INVALID\"";
}
@@ -723,8 +721,6 @@ int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, TemporalAntiAli
i = parse(tokens, i + 1, jsonChunk, &out->feedback);
} else if (compare(tok, jsonChunk, "lodBias") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->lodBias);
} else if (compare(tok, jsonChunk, "sharpness") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->sharpness);
} else if (compare(tok, jsonChunk, "enabled") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->enabled);
} else if (compare(tok, jsonChunk, "upscaling") == 0) {
@@ -764,7 +760,6 @@ std::ostream& operator<<(std::ostream& out, const TemporalAntiAliasingOptions& i
<< "\"filterWidth\": " << (in.filterWidth) << ",\n"
<< "\"feedback\": " << (in.feedback) << ",\n"
<< "\"lodBias\": " << (in.lodBias) << ",\n"
<< "\"sharpness\": " << (in.sharpness) << ",\n"
<< "\"enabled\": " << to_string(in.enabled) << ",\n"
<< "\"upscaling\": " << to_string(in.upscaling) << ",\n"
<< "\"filterHistory\": " << to_string(in.filterHistory) << ",\n"
+1 -2
View File
@@ -805,11 +805,10 @@ void ViewerGui::updateUserInterface() {
int jitterSequence = (int)mSettings.view.taa.jitterPattern;
int boxClipping = (int)mSettings.view.taa.boxClipping;
int boxType = (int)mSettings.view.taa.boxType;
ImGui::Combo("Jitter Pattern", &jitterSequence, "RGSS x4\0Uniform Helix x4\0Halton x8\0Halton x16\0Halton x32\0\0");
ImGui::Combo("Jitter Pattern", &jitterSequence, "RGSS x4\0Uniform Helix x4\0Halton x8\0Halton x16\0\0");
ImGui::Combo("Box Clipping", &boxClipping, "Accurate\0Clamp\0None\0\0");
ImGui::Combo("Box Type", &boxType, "AABB\0Variance\0Both\0\0");
ImGui::SliderFloat("Variance Gamma", &mSettings.view.taa.varianceGamma, 0.75f, 1.25f);
ImGui::SliderFloat("RCAS", &mSettings.view.taa.sharpness, 0.0f, 1.0f);
mSettings.view.taa.boxClipping = (TemporalAntiAliasingOptions::BoxClipping)boxClipping;
mSettings.view.taa.boxType = (TemporalAntiAliasingOptions::BoxType)boxType;
mSettings.view.taa.jitterPattern = (TemporalAntiAliasingOptions::JitterPattern)jitterSequence;
+1
View File
@@ -19,6 +19,7 @@
#endif
#define saturate(x) clamp(x, 0.0, 1.0)
#define atan2(x, y) atan(y, x)
//------------------------------------------------------------------------------
// Scalar operations
-1
View File
@@ -19,7 +19,6 @@
#include <getopt/getopt.h>
#include <algorithm>
#include <cstdint>
#include <fstream>
#include <iomanip>
#include <iostream>
-1
View File
@@ -141,7 +141,6 @@ Filament.loadGeneratedExtensions = function() {
filterWidth: 1.0,
feedback: 0.12,
lodBias: -1.0,
sharpness: 0.0,
enabled: false,
upscaling: false,
filterHistory: true,
+1 -6
View File
@@ -1657,14 +1657,13 @@ export enum View$TemporalAntiAliasingOptions$JitterPattern {
UNIFORM_HELIX_X4,
HALTON_23_X8,
HALTON_23_X16,
HALTON_23_X32,
}
/**
* Options for Temporal Anti-aliasing (TAA)
* Most TAA parameters are extremely costly to change, as they will trigger the TAA post-process
* shaders to be recompiled. These options should be changed or set during initialization.
* `filterWidth`, `feedback` and `jitterPattern`, however, can be changed at any time.
* `filterWidth`, `feedback` and `jitterPattern`, however, could be changed at any time.
*
* `feedback` of 0.1 effectively accumulates a maximum of 19 samples in steady state.
* see "A Survey of Temporal Antialiasing Techniques" by Lei Yang and all for more information.
@@ -1684,10 +1683,6 @@ export interface View$TemporalAntiAliasingOptions {
* texturing lod bias (typically -1 or -2)
*/
lodBias?: number;
/**
* post-TAA sharpen, especially useful when upscaling is true.
*/
sharpness?: number;
/**
* enables or disables temporal anti-aliasing
*/
-1
View File
@@ -121,7 +121,6 @@ value_object<View::TemporalAntiAliasingOptions>("View$TemporalAntiAliasingOption
.field("filterWidth", &View::TemporalAntiAliasingOptions::filterWidth)
.field("feedback", &View::TemporalAntiAliasingOptions::feedback)
.field("lodBias", &View::TemporalAntiAliasingOptions::lodBias)
.field("sharpness", &View::TemporalAntiAliasingOptions::sharpness)
.field("enabled", &View::TemporalAntiAliasingOptions::enabled)
.field("upscaling", &View::TemporalAntiAliasingOptions::upscaling)
.field("filterHistory", &View::TemporalAntiAliasingOptions::filterHistory)
-1
View File
@@ -50,7 +50,6 @@ enum_<View::TemporalAntiAliasingOptions::JitterPattern>("View$TemporalAntiAliasi
.value("UNIFORM_HELIX_X4", View::TemporalAntiAliasingOptions::JitterPattern::UNIFORM_HELIX_X4)
.value("HALTON_23_X8", View::TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X8)
.value("HALTON_23_X16", View::TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X16)
.value("HALTON_23_X32", View::TemporalAntiAliasingOptions::JitterPattern::HALTON_23_X32)
;
enum_<View::AntiAliasing>("View$AntiAliasing")
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "filament",
"version": "1.50.1",
"version": "1.49.3",
"description": "Real-time physically based rendering engine",
"main": "filament.js",
"module": "filament.js",
+3 -1
View File
@@ -203,7 +203,9 @@ set(HTML_FILES
skinning.html
suzanne.html
test-filament-viewer.html
triangle.html)
triangle.html
benchmark-shader-compilation.html
benchmark-shader-compilation.js)
set(ASSET_FILES
assets/favicon.png)
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Shader Compilation Benchmark</title>
<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1">
<style>
body { margin: 0; overflow: hidden; }
canvas { touch-action: none; width: 100%; height: 100%; }
.frame-time { position: absolute; color: #ffffff; }
</style>
</head>
<body>
<div class="frame-time">
Average Frame Time: <span id="frame-time-counter">Calculating...</span>
</div>
<canvas></canvas>
<script src="filament.js"></script>
<script src="gl-matrix-min.js"></script>
<script src="benchmark-shader-compilation.js"></script>
</body>
</html>
+141
View File
@@ -0,0 +1,141 @@
Filament.init(['nonlit.filamat'], () => {
window.VertexAttribute = Filament.VertexAttribute;
window.AttributeType = Filament.VertexBuffer$AttributeType;
window.Projection = Filament.Camera$Projection;
window.app = new App(
document.getElementsByTagName('canvas')[0],
document.getElementById('frame-time-counter'));
});
const NUMBER_OF_TRIANGLES = 100;
// probably 60 fps; record 1 seconds ish worth of frames.
const NUMBER_OF_FRAMES_TO_RECORD_FPS = 1 * 60;
class App {
constructor(canvas, frameTimeCounter) {
this.canvas = canvas;
this.frameTimeCounter = frameTimeCounter;
this.lastFrameTime = null;
this.frameDeltas = [];
for (let i = 0; i < NUMBER_OF_FRAMES_TO_RECORD_FPS; ++i) {
this.frameDeltas.push(0);
}
this.frameDeltasIndex = 0;
this.frameDeltasSum = 0;
this.frameTimeIsValid = false;
const engine = this.engine = Filament.Engine.create(this.canvas);
this.scene = engine.createScene();
this.triangles = [];
for (let i = 0; i < NUMBER_OF_TRIANGLES; ++i) {
const entity = Filament.EntityManager.get().create();
this.triangles.push({entity: entity});
this.scene.addEntity(entity);
}
const TRIANGLE_POSITIONS = new Float32Array([
1,
0,
Math.cos(Math.PI * 2 / 3),
Math.sin(Math.PI * 2 / 3),
Math.cos(Math.PI * 4 / 3),
Math.sin(Math.PI * 4 / 3),
]);
const TRIANGLE_COLORS =
new Uint32Array([0xffff0000, 0xff00ff00, 0xff0000ff]);
this.vb =
Filament.VertexBuffer.Builder()
.vertexCount(3)
.bufferCount(2)
.attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT2, 0, 8)
.attribute(VertexAttribute.COLOR, 1, AttributeType.UBYTE4, 0, 4)
.normalized(VertexAttribute.COLOR)
.build(engine);
this.vb.setBufferAt(engine, 0, TRIANGLE_POSITIONS);
this.vb.setBufferAt(engine, 1, TRIANGLE_COLORS);
this.ib = Filament.IndexBuffer.Builder()
.indexCount(3)
.bufferType(Filament.IndexBuffer$IndexType.USHORT)
.build(engine);
this.ib.setBuffer(engine, new Uint16Array([0, 1, 2]));
this.swapChain = engine.createSwapChain();
this.renderer = engine.createRenderer();
this.camera = engine.createCamera(Filament.EntityManager.get().create());
this.view = engine.createView();
this.view.setSampleCount(4);
this.view.setCamera(this.camera);
this.view.setScene(this.scene);
this.renderer.setClearOptions(
{clearColor: [0.0, 0.1, 0.2, 1.0], clear: true});
this.resize();
this.render = this.render.bind(this);
this.resize = this.resize.bind(this);
window.addEventListener('resize', this.resize);
window.requestAnimationFrame(this.render);
}
render() {
const frameTime = Date.now();
if (this.lastFrameTime) {
const delta = frameTime - this.lastFrameTime;
this.frameDeltasSum =
this.frameDeltasSum - this.frameDeltas[this.frameDeltasIndex] + delta;
this.frameDeltas[this.frameDeltasIndex] = delta;
this.frameDeltasIndex =
(this.frameDeltasIndex + 1) % NUMBER_OF_FRAMES_TO_RECORD_FPS;
if (this.frameDeltasIndex == 0) {
this.frameTimeIsValid = true;
}
}
this.lastFrameTime = frameTime;
if (this.frameTimeIsValid) {
const averageFrameDelta =
this.frameDeltasSum * 1.0 / NUMBER_OF_FRAMES_TO_RECORD_FPS;
this.frameTimeCounter.innerHTML = averageFrameDelta.toFixed(2) + ' ms';
}
this.triangles.forEach(triangle => {
if (triangle.mat) {
this.engine.destroyMaterial(triangle.mat);
}
triangle.mat = this.engine.createMaterial('nonlit.filamat');
const matinst = triangle.mat.getDefaultInstance();
Filament.RenderableManager.Builder(1)
.boundingBox({center: [-1, -1, -1], halfExtent: [1, 1, 1]})
.material(0, matinst)
.geometry(
0, Filament.RenderableManager$PrimitiveType.TRIANGLES, this.vb,
this.ib)
.build(this.engine, triangle.entity);
});
const radians = Date.now() / 1000;
const transform = mat4.fromRotation(mat4.create(), radians, [0, 0, 1]);
const tcm = this.engine.getTransformManager();
const inst = tcm.getInstance(this.triangles[0].entity);
tcm.setTransform(inst, transform);
inst.delete();
this.renderer.render(this.swapChain, this.view);
window.requestAnimationFrame(this.render);
}
resize() {
const dpr = window.devicePixelRatio;
const width = this.canvas.width = window.innerWidth * dpr;
const height = this.canvas.height = window.innerHeight * dpr;
this.view.setViewport([0, 0, width, height]);
const aspect = width / height;
this.camera.setProjection(Projection.ORTHO, -aspect, aspect, -1, 1, 0, 1);
}
}