Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea9fdbeb5c |
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,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.
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include <backend/PixelBufferDescriptor.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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?
|
||||
}, [¤t](FrameGraphResources const& resources, auto const& data, auto&) {
|
||||
resources.detach(data.color, ¤t.color, ¤t.desc);
|
||||
data.color = builder.sample(input); // FIXME: an access must be declared for detach(), why?
|
||||
}, [¤t](FrameGraphResources const& resources, auto const& data,
|
||||
backend::DriverApi&) {
|
||||
resources.detach(data.color,
|
||||
¤t.color, ¤t.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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include <utils/Mutex.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <optional>
|
||||
|
||||
namespace filament {
|
||||
|
||||
|
||||
@@ -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, ¤t.ssr.color, ¤t.ssr.desc);
|
||||
resources.detach(data.history,
|
||||
¤t.ssr.color, ¤t.ssr.desc);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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");
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace utils {
|
||||
|
||||
bool Path::mkdir() const {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#endif
|
||||
|
||||
#define saturate(x) clamp(x, 0.0, 1.0)
|
||||
#define atan2(x, y) atan(y, x)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Scalar operations
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <getopt/getopt.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
@@ -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,
|
||||
|
||||
Vendored
+1
-6
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,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",
|
||||
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user