diff --git a/filament/src/Culler.cpp b/filament/src/Culler.cpp index 4a3570b2e8..8430655bb6 100644 --- a/filament/src/Culler.cpp +++ b/filament/src/Culler.cpp @@ -22,8 +22,17 @@ using namespace filament::math; +// We use a vectorize width of 8 because, on ARMv8 it allows the compiler to write eight +// 8-bits results in one go. Without this it has to do 4 separate byte writes, which +// ends-up being slower. + +#define FILAMENT_CULLER_VECTORIZE_HINT 8 + namespace filament { +static_assert(Culler::MODULO % FILAMENT_CULLER_VECTORIZE_HINT == 0, + "MODULO m=must be a multiple of FILAMENT_CULLER_VECTORIZE_HINT"); + void Culler::intersects( result_type* UTILS_RESTRICT results, Frustum const& UTILS_RESTRICT frustum, @@ -32,11 +41,8 @@ void Culler::intersects( float4 const * const UTILS_RESTRICT planes = frustum.mPlanes; - // we use a vectorize width of 8 because, on ARMv8 it allow the compiler to write 8 - // 8-bits results in one go. Without this it has to do 4 separate byte writes, which - // ends-up being slower. - count = round(count); // capacity guaranteed to be multiple of 8 - #pragma clang loop vectorize_width(8) + count = round(count); + #pragma clang loop vectorize_width(FILAMENT_CULLER_VECTORIZE_HINT) for (size_t i = 0; i < count; i++) { int visible = ~0; float4 const sphere(b[i]); @@ -64,11 +70,8 @@ void Culler::intersects( float4 const * UTILS_RESTRICT const planes = frustum.mPlanes; - // we use a vectorize width of 8 because, on ARMv8 it allows the compiler to write eight - // 8-bits results in one go. Without this it has to do 4 separate byte writes, which - // ends-up being slower. - count = round(count); // capacity guaranteed to be multiple of 8 - #pragma clang loop vectorize_width(8) + count = round(count); + #pragma clang loop vectorize_width(FILAMENT_CULLER_VECTORIZE_HINT) for (size_t i = 0; i < count; i++) { int visible = ~0; diff --git a/filament/src/Culler.h b/filament/src/Culler.h index 95f501a8ee..a2555367b5 100644 --- a/filament/src/Culler.h +++ b/filament/src/Culler.h @@ -37,14 +37,11 @@ namespace filament { class Culler { public: // Culler can only process buffers with a size multiple of MODULO - static constexpr size_t MODULO = 8; + static constexpr size_t MODULO = 8u; static inline size_t round(size_t count) noexcept { return (count + (MODULO - 1)) & ~(MODULO - 1); } - // A good loop value to use to amortize the loop overhead - static constexpr size_t MIN_LOOP_COUNT_HINT = 8; - using result_type = uint8_t; /* diff --git a/filament/src/RenderPass.cpp b/filament/src/RenderPass.cpp index 17df69eccd..37048489d8 100644 --- a/filament/src/RenderPass.cpp +++ b/filament/src/RenderPass.cpp @@ -275,7 +275,6 @@ void RenderPass::generateCommandsImpl(uint32_t extraFlags, const bool depthFilterAlphaMaskedObjects = bool(extraFlags & CommandTypeFlags::DEPTH_FILTER_ALPHA_MASKED_OBJECTS); auto const* const UTILS_RESTRICT soaWorldAABBCenter = soa.data(); - auto const* const UTILS_RESTRICT soaReversedWinding = soa.data(); auto const* const UTILS_RESTRICT soaVisibility = soa.data(); auto const* const UTILS_RESTRICT soaPrimitives = soa.data(); auto const* const UTILS_RESTRICT soaVisibilityMask = soa.data(); @@ -347,7 +346,7 @@ void RenderPass::generateCommandsImpl(uint32_t extraFlags, const uint32_t distanceBits = reinterpret_cast(distance); // calculate the per-primitive face winding order inversion - const bool inverseFrontFaces = viewInverseFrontFaces ^ soaReversedWinding[i]; + const bool inverseFrontFaces = viewInverseFrontFaces ^ soaVisibility[i].reversedWindingOrder; cmdColor.key = makeField(soaVisibility[i].priority, PRIORITY_MASK, PRIORITY_SHIFT); cmdColor.primitive.index = (uint16_t)i; diff --git a/filament/src/Scene.cpp b/filament/src/Scene.cpp index 609dc19121..c7dbb390e3 100644 --- a/filament/src/Scene.cpp +++ b/filament/src/Scene.cpp @@ -121,6 +121,7 @@ void FScene::prepare(const mat4& worldOriginTransform, bool shadowReceiversAreCa const Box worldAABB = rigidTransform(rcm.getAABB(ri), worldTransform); auto visibility = rcm.getVisibility(ri); + visibility.reversedWindingOrder = reversedWindingOrder; if (shadowReceiversAreCasters && visibility.receiveShadows) { visibility.castShadows = true; } @@ -135,7 +136,6 @@ void FScene::prepare(const mat4& worldOriginTransform, bool shadowReceiversAreCa sceneData.push_back_unsafe( ri, // RENDERABLE_INSTANCE worldTransform, // WORLD_TRANSFORM - reversedWindingOrder, // REVERSED_WINDING_ORDER visibility, // VISIBILITY_STATE rcm.getSkinningBufferInfo(ri), // SKINNING_BUFFER worldAABB.center, // WORLD_AABB_CENTER @@ -207,6 +207,7 @@ void FScene::updateUBOs(utils::Range visibleRenderables, backend::Hand auto& sceneData = mRenderableData; for (uint32_t i : visibleRenderables) { mat4f const& model = sceneData.elementAt(i); + FRenderableManager::Visibility visibility = sceneData.elementAt(i); const size_t offset = i * sizeof(PerRenderableUib); UniformBuffer::setUniform(buffer, @@ -229,7 +230,7 @@ void FScene::updateUBOs(utils::Range visibleRenderables, backend::Hand // The shading normal must be flipped for mirror transformations. // Basically we're shading the other side of the polygon and therefore need to negate the // normal, similar to what we already do to support double-sided lighting. - if (sceneData.elementAt(i)) { + if (visibility.reversedWindingOrder) { m = -m; } @@ -239,7 +240,6 @@ void FScene::updateUBOs(utils::Range visibleRenderables, backend::Hand // Note that we cast bool to uint32_t. Booleans are byte-sized in C++, but we need to // initialize all 32 bits in the UBO field. - FRenderableManager::Visibility visibility = sceneData.elementAt(i); hasContactShadows = hasContactShadows || visibility.screenSpaceContactShadows; UniformBuffer::setUniform(buffer, diff --git a/filament/src/View.cpp b/filament/src/View.cpp index d483c48acd..32f5fdd47d 100644 --- a/filament/src/View.cpp +++ b/filament/src/View.cpp @@ -196,7 +196,7 @@ bool FView::isSkyboxVisible() const noexcept { return skybox != nullptr && (skybox->getLayerMask() & mVisibleLayers); } -void FView::prepareShadowing(FEngine& engine, backend::DriverApi& driver, +void FView::prepareShadowing(FEngine& engine, DriverApi& driver, FScene::RenderableSoa& renderableData, FScene::LightSoa& lightData) noexcept { SYSTRACE_CALL(); @@ -320,7 +320,7 @@ void FView::prepareLighting(FEngine& engine, FEngine::DriverApi& driver, ArenaSc mHasDirectionalLight = directionalLight.isValid(); } -void FView::prepare(FEngine& engine, backend::DriverApi& driver, ArenaScope& arena, +void FView::prepare(FEngine& engine, DriverApi& driver, ArenaScope& arena, filament::Viewport const& viewport, float4 const& userTime) noexcept { JobSystem& js = engine.getJobSystem(); @@ -436,7 +436,7 @@ void FView::prepare(FEngine& engine, backend::DriverApi& driver, ArenaScope& are uint8_t const* layers = renderableData.data(); auto const* visibility = renderableData.data(); computeVisibilityMasks(getVisibleLayers(), layers, visibility, cullingMask.begin(), - renderableData.size(), hasVsm()); + renderableData.size()); auto const beginRenderables = renderableData.begin(); auto beginCasters = partition(beginRenderables, renderableData.end(), VISIBLE_RENDERABLE); @@ -466,7 +466,7 @@ void FView::prepare(FEngine& engine, backend::DriverApi& driver, ArenaScope& are mRenderableUBOSize = uint32_t(count * sizeof(PerRenderableUib)); driver.destroyBufferObject(mRenderableUbh); mRenderableUbh = driver.createBufferObject(mRenderableUBOSize, - BufferObjectBinding::UNIFORM, backend::BufferUsage::STREAM); + BufferObjectBinding::UNIFORM, BufferUsage::STREAM); } else { // TODO: should we shrink the underlying UBO at some point? } @@ -498,7 +498,7 @@ void FView::computeVisibilityMasks( uint8_t visibleLayers, uint8_t const* UTILS_RESTRICT layers, FRenderableManager::Visibility const* UTILS_RESTRICT visibility, - uint8_t* UTILS_RESTRICT visibleMask, size_t count, bool hasVsm) { + Culler::result_type* UTILS_RESTRICT visibleMask, size_t count) { // __restrict__ seems to only be taken into account as function parameters. This is very // important here, otherwise, this loop doesn't get vectorized. // This is vectorized 16x. @@ -565,16 +565,16 @@ void FView::prepareSSAO(Handle ssao) const noexcept { mPerViewUniforms.prepareSSAO(ssao, mAmbientOcclusionOptions); } -void FView::prepareSSR(backend::Handle ssr, float refractionLodOffset) const noexcept { +void FView::prepareSSR(Handle ssr, float refractionLodOffset) const noexcept { mPerViewUniforms.prepareSSR(ssr, refractionLodOffset); } -void FView::prepareStructure(backend::Handle structure) const noexcept { +void FView::prepareStructure(Handle structure) const noexcept { // sampler must be NEAREST mPerViewUniforms.prepareStructure(structure); } -void FView::prepareShadow(backend::Handle texture) const noexcept { +void FView::prepareShadow(Handle texture) const noexcept { if (hasVsm()) { mPerViewUniforms.prepareShadowVSM(texture, mVsmShadowOptions); } else { @@ -597,14 +597,14 @@ void FView::froxelize(FEngine& engine) const noexcept { mFroxelizer.froxelizeLights(engine, mViewingCameraInfo, mScene->getLightData()); } -void FView::commitUniforms(backend::DriverApi& driver) const noexcept { +void FView::commitUniforms(DriverApi& driver) const noexcept { mPerViewUniforms.commit(driver); if (mShadowUb.isDirty()) { driver.updateBufferObject(mShadowUbh, mShadowUb.toBufferDescriptor(driver), 0); } } -void FView::commitFroxels(backend::DriverApi& driverApi) const noexcept { +void FView::commitFroxels(DriverApi& driverApi) const noexcept { if (mHasDynamicLighting) { mFroxelizer.commit(driverApi); } diff --git a/filament/src/components/RenderableManager.h b/filament/src/components/RenderableManager.h index 6274bb1db0..bf805af9cb 100644 --- a/filament/src/components/RenderableManager.h +++ b/filament/src/components/RenderableManager.h @@ -57,6 +57,7 @@ public: bool skinning : 1; bool morphing : 1; bool screenSpaceContactShadows : 1; + bool reversedWindingOrder : 1; }; static_assert(sizeof(Visibility) == sizeof(uint16_t), "Visibility should be 16 bits"); diff --git a/filament/src/details/Scene.h b/filament/src/details/Scene.h index 4c2c8dede4..501b470557 100644 --- a/filament/src/details/Scene.h +++ b/filament/src/details/Scene.h @@ -103,7 +103,6 @@ public: enum { RENDERABLE_INSTANCE, // 4 | instance of the Renderable component WORLD_TRANSFORM, // 16 | instance of the Transform component - REVERSED_WINDING_ORDER, // 1 | det(WORLD_TRANSFORM)<0 VISIBILITY_STATE, // 1 | visibility data of the component SKINNING_BUFFER, // 8 | bones uniform buffer handle, count, offset WORLD_AABB_CENTER, // 12 | world-space bounding box center of the renderable @@ -126,7 +125,6 @@ public: using RenderableSoa = utils::StructureOfArrays< utils::EntityInstance, // RENDERABLE_INSTANCE math::mat4f, // WORLD_TRANSFORM - bool, // REVERSED_WINDING_ORDER FRenderableManager::Visibility, // VISIBILITY_STATE FRenderableManager::SkinningBindingInfo, // SKINNING_BUFFER math::float3, // WORLD_AABB_CENTER diff --git a/filament/src/details/View.h b/filament/src/details/View.h index 656ffb992c..a4471bb9b5 100644 --- a/filament/src/details/View.h +++ b/filament/src/details/View.h @@ -88,19 +88,19 @@ static constexpr size_t VISIBLE_RENDERABLE_BIT = 0u; static constexpr size_t VISIBLE_DIR_SHADOW_RENDERABLE_BIT = 1u; static constexpr size_t VISIBLE_SPOT_SHADOW_RENDERABLE_N_BIT(size_t n) { return n + 2; } -static constexpr uint8_t VISIBLE_RENDERABLE = 1u << VISIBLE_RENDERABLE_BIT; -static constexpr uint8_t VISIBLE_DIR_SHADOW_RENDERABLE = 1u << VISIBLE_DIR_SHADOW_RENDERABLE_BIT; -static constexpr uint8_t VISIBLE_SPOT_SHADOW_RENDERABLE_N(size_t n) { +static constexpr Culler::result_type VISIBLE_RENDERABLE = 1u << VISIBLE_RENDERABLE_BIT; +static constexpr Culler::result_type VISIBLE_DIR_SHADOW_RENDERABLE = 1u << VISIBLE_DIR_SHADOW_RENDERABLE_BIT; +static constexpr Culler::result_type VISIBLE_SPOT_SHADOW_RENDERABLE_N(size_t n) { return 1u << VISIBLE_SPOT_SHADOW_RENDERABLE_N_BIT(n); } // ORing of all the VISIBLE_SPOT_SHADOW_RENDERABLE bits -static constexpr uint8_t VISIBLE_SPOT_SHADOW_RENDERABLE = - (0xFFu >> (sizeof(uint8_t) * 8u - CONFIG_MAX_SHADOW_CASTING_SPOTS)) << 2u; +static constexpr Culler::result_type VISIBLE_SPOT_SHADOW_RENDERABLE = + (0xFFu >> (sizeof(Culler::result_type) * 8u - CONFIG_MAX_SHADOW_CASTING_SPOTS)) << 2u; // Because we're using a uint8_t for the visibility mask, we're limited to 6 spot light shadows. // (2 of the bits are used for visible renderables + directional light shadow casters). -static_assert(CONFIG_MAX_SHADOW_CASTING_SPOTS <= 6, +static_assert(CONFIG_MAX_SHADOW_CASTING_SPOTS <= sizeof(Culler::result_type) * 8 - 2, "CONFIG_MAX_SHADOW_CASTING_SPOTS cannot be higher than 6."); // ------------------------------------------------------------------------------------------------ @@ -441,8 +441,9 @@ private: static void computeVisibilityMasks( uint8_t visibleLayers, uint8_t const* layers, - FRenderableManager::Visibility const* visibility, uint8_t* visibleMask, - size_t count, bool hasVsm); + FRenderableManager::Visibility const* visibility, + Culler::result_type* visibleMask, + size_t count); void bindPerViewUniformsAndSamplers(FEngine::DriverApi& driver) const noexcept { mPerViewUniforms.bind(driver); diff --git a/libs/utils/include/utils/Allocator.h b/libs/utils/include/utils/Allocator.h index 75d94cd4b8..5d881c135c 100644 --- a/libs/utils/include/utils/Allocator.h +++ b/libs/utils/include/utils/Allocator.h @@ -19,6 +19,7 @@ #include +#include #include #include #include @@ -793,7 +794,9 @@ public: explicit STLAllocator(STLAllocator const& rhs) : mArena(rhs.mArena) { } TYPE* allocate(std::size_t n) { - return static_cast(mArena.alloc(n * sizeof(TYPE), alignof(TYPE))); + auto p = static_cast(mArena.alloc(n * sizeof(TYPE), alignof(TYPE))); + assert_invariant(p); + return p; } void deallocate(TYPE* p, std::size_t n) {