From 8c91b1baf5ebc162888a99f583485f79fd4ead05 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Tue, 3 Sep 2024 17:17:21 -0700 Subject: [PATCH 01/10] fix debug markers when implemented with systrace when debug markers are implemented with systrace, begin/end can is not guaranteed to happen in the same C++ scope, so we can't really use other scoped systraces. --- filament/backend/src/CommandStream.cpp | 10 ++++++++-- filament/src/fg/FrameGraph.cpp | 5 +---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/filament/backend/src/CommandStream.cpp b/filament/backend/src/CommandStream.cpp index 69730d688c8..d12ac923bb5 100644 --- a/filament/backend/src/CommandStream.cpp +++ b/filament/backend/src/CommandStream.cpp @@ -20,11 +20,16 @@ #include #endif +#include #include +#include #include #include +#include #include +#include +#include #ifdef __ANDROID__ #include @@ -74,8 +79,8 @@ CommandStream::CommandStream(Driver& driver, CircularBuffer& buffer) noexcept } void CommandStream::execute(void* buffer) { - SYSTRACE_CALL(); - SYSTRACE_CONTEXT(); + // NOTE: we can't use SYSTRACE_CALL() or similar here because, execute() below, also + // uses systrace BEGIN/END and the END is not guaranteed to be happening in this scope. Profiler profiler; @@ -100,6 +105,7 @@ void CommandStream::execute(void* buffer) { // we want to remove all this when tracing is completely disabled profiler.stop(); UTILS_UNUSED Profiler::Counters const counters = profiler.readCounters(); + SYSTRACE_CONTEXT(); SYSTRACE_VALUE32("GLThread (I)", counters.getInstructions()); SYSTRACE_VALUE32("GLThread (C)", counters.getCpuCycles()); SYSTRACE_VALUE32("GLThread (CPI x10)", counters.getCPI() * 10); diff --git a/filament/src/fg/FrameGraph.cpp b/filament/src/fg/FrameGraph.cpp index fec8580326a..d7c2a6f07eb 100644 --- a/filament/src/fg/FrameGraph.cpp +++ b/filament/src/fg/FrameGraph.cpp @@ -195,12 +195,11 @@ FrameGraph& FrameGraph::compile() noexcept { void FrameGraph::execute(backend::DriverApi& driver) noexcept { - SYSTRACE_CALL(); - bool const useProtectedMemory = mMode == Mode::PROTECTED; auto const& passNodes = mPassNodes; auto& resourceAllocator = mResourceAllocator; + SYSTRACE_NAME("FrameGraph"); driver.pushGroupMarker("FrameGraph"); auto first = passNodes.begin(); @@ -211,7 +210,6 @@ void FrameGraph::execute(backend::DriverApi& driver) noexcept { assert_invariant(!node->isCulled()); SYSTRACE_NAME(node->getName()); - driver.pushGroupMarker(node->getName()); // devirtualize resourcesList @@ -229,7 +227,6 @@ void FrameGraph::execute(backend::DriverApi& driver) noexcept { assert_invariant(resource->last == node); resource->destroy(resourceAllocator); } - driver.popGroupMarker(); } driver.popGroupMarker(); From c2b363272553e8061bda59955c97390454d41663 Mon Sep 17 00:00:00 2001 From: Zaven Muradyan Date: Thu, 5 Sep 2024 15:21:26 -0700 Subject: [PATCH 02/10] Expose getShadowType on View. (#8106) While this method exists on FView, it is missing from View and thus not accessible for filament users. This adds a pass-through method on View. --- filament/include/filament/View.h | 7 +++++++ filament/src/View.cpp | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/filament/include/filament/View.h b/filament/include/filament/View.h index d4c9848de8f..139dcac7f40 100644 --- a/filament/include/filament/View.h +++ b/filament/include/filament/View.h @@ -570,6 +570,13 @@ class UTILS_PUBLIC View : public FilamentAPI { */ void setShadowType(ShadowType shadow) noexcept; + /** + * Returns the shadow mapping technique used by this View. + * + * @return value set by setShadowType(). + */ + ShadowType getShadowType() const noexcept; + /** * Sets VSM shadowing options that apply across the entire View. * diff --git a/filament/src/View.cpp b/filament/src/View.cpp index 65635f3f647..0d5d3aa61ca 100644 --- a/filament/src/View.cpp +++ b/filament/src/View.cpp @@ -193,6 +193,10 @@ void View::setShadowType(View::ShadowType shadow) noexcept { downcast(this)->setShadowType(shadow); } +View::ShadowType View::getShadowType() const noexcept { + return downcast(this)->getShadowType(); +} + void View::setVsmShadowOptions(VsmShadowOptions const& options) noexcept { downcast(this)->setVsmShadowOptions(options); } From 78aa1c4b10ca29370029d4934e8695cfd7c496f9 Mon Sep 17 00:00:00 2001 From: Powei Feng Date: Fri, 6 Sep 2024 15:10:01 -0700 Subject: [PATCH 03/10] vk: use std::unordered_map in PipelineLayoutCache (#7990) This is to address a weird map.find() miss that only happens on ARM in release mode. BUG=365159519 Co-authored-by: Sungun Park --- .../src/vulkan/caching/VulkanPipelineLayoutCache.cpp | 8 ++++---- .../src/vulkan/caching/VulkanPipelineLayoutCache.h | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/filament/backend/src/vulkan/caching/VulkanPipelineLayoutCache.cpp b/filament/backend/src/vulkan/caching/VulkanPipelineLayoutCache.cpp index 67cc54e5914..79ae8ed72ab 100644 --- a/filament/backend/src/vulkan/caching/VulkanPipelineLayoutCache.cpp +++ b/filament/backend/src/vulkan/caching/VulkanPipelineLayoutCache.cpp @@ -32,8 +32,8 @@ VkPipelineLayout VulkanPipelineLayoutCache::getLayout( } // build the push constant layout key - uint32_t pushConstantRangeCount = program->getPushConstantRangeCount(); - auto const& pushConstantRanges = program->getPushConstantRanges(); + uint32_t const pushConstantRangeCount = program->getPushConstantRangeCount(); + auto const& pushConstantRanges = program->getPushConstantRanges(); if (pushConstantRangeCount > 0) { assert_invariant(pushConstantRangeCount <= Program::SHADER_TYPE_COUNT); for (uint8_t i = 0; i < pushConstantRangeCount; ++i) { @@ -52,8 +52,8 @@ VkPipelineLayout VulkanPipelineLayoutCache::getLayout( } } - if (PipelineLayoutMap::iterator iter = mPipelineLayouts.find(key); iter != mPipelineLayouts.end()) { - PipelineLayoutCacheEntry& entry = iter.value(); + if (auto iter = mPipelineLayouts.find(key); iter != mPipelineLayouts.end()) { + PipelineLayoutCacheEntry& entry = iter->second; entry.lastUsed = mTimestamp++; return entry.handle; } diff --git a/filament/backend/src/vulkan/caching/VulkanPipelineLayoutCache.h b/filament/backend/src/vulkan/caching/VulkanPipelineLayoutCache.h index 42bd2926acd..25c401b21e7 100644 --- a/filament/backend/src/vulkan/caching/VulkanPipelineLayoutCache.h +++ b/filament/backend/src/vulkan/caching/VulkanPipelineLayoutCache.h @@ -22,7 +22,7 @@ #include -#include +#include namespace filament::backend { @@ -36,8 +36,8 @@ class VulkanPipelineLayoutCache { void terminate() noexcept; struct PushConstantKey { - uint8_t stage;// We have one set of push constant per shader stage (fragment, vertex, etc). - uint8_t size; + uint8_t stage = 0;// We have one set of push constant per shader stage (fragment, vertex, etc). + uint8_t size = 0; // Note that there is also an offset parameter for push constants, but // we always assume our update range will have the offset 0. }; @@ -73,7 +73,7 @@ class VulkanPipelineLayoutCache { } }; - using PipelineLayoutMap = tsl::robin_map; VkDevice mDevice; @@ -82,6 +82,6 @@ class VulkanPipelineLayoutCache { PipelineLayoutMap mPipelineLayouts; }; -} +} // filament::backend #endif // TNT_FILAMENT_BACKEND_VULKANPIPELINECACHE_H From 8999b21187a35634479eb67fe2410fefcf5e2f6a Mon Sep 17 00:00:00 2001 From: Powei Feng Date: Thu, 5 Sep 2024 14:14:00 -0700 Subject: [PATCH 04/10] Revert "reenable the SimplificationPass in spirv-opt" This reverts commit 30387af61cbd29a9e9f3bdbc6959938222b64c81. Causes breakage on Pixel 8pro for 1P apps. --- libs/filamat/src/GLSLPostProcessor.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/libs/filamat/src/GLSLPostProcessor.cpp b/libs/filamat/src/GLSLPostProcessor.cpp index bd879b1ee0c..3a4a4824e0e 100644 --- a/libs/filamat/src/GLSLPostProcessor.cpp +++ b/libs/filamat/src/GLSLPostProcessor.cpp @@ -671,15 +671,13 @@ void GLSLPostProcessor::fixupClipDistance( // - triggers a crash on some Adreno drivers (b/291140208, b/289401984, b/289393290) // However Metal requires this pass in order to correctly generate half-precision MSL // -// Note: CreateSimplificationPass() used to creates a lot of problems: +// CreateSimplificationPass() creates a lot of problems: // - Adreno GPU show artifacts after running simplification passes (Vulkan) // - spirv-cross fails generating working glsl // (https://github.com/KhronosGroup/SPIRV-Cross/issues/2162) -// -// However this problem was addressed in spirv-cross here: -// https://github.com/KhronosGroup/SPIRV-Cross/pull/2163 -// -// The simplification passes below are necessary when targeting Metal, otherwise the +// - generally it makes the code more complicated, e.g.: replacing for loops with +// while-if-break, unclear if it helps for anything. +// However, the simplification passes below are necessary when targeting Metal, otherwise the // result is mismatched half / float assignments in MSL. @@ -712,11 +710,11 @@ void GLSLPostProcessor::registerPerformancePasses(Optimizer& optimizer, Config c RegisterPass(CreateAggressiveDCEPass()); RegisterPass(CreateRedundancyEliminationPass()); RegisterPass(CreateCombineAccessChainsPass()); - RegisterPass(CreateSimplificationPass()); + RegisterPass(CreateSimplificationPass(), MaterialBuilder::TargetApi::METAL); RegisterPass(CreateVectorDCEPass()); RegisterPass(CreateDeadInsertElimPass()); RegisterPass(CreateDeadBranchElimPass()); - RegisterPass(CreateSimplificationPass()); + RegisterPass(CreateSimplificationPass(), MaterialBuilder::TargetApi::METAL); RegisterPass(CreateIfConversionPass()); RegisterPass(CreateCopyPropagateArraysPass()); RegisterPass(CreateReduceLoadSizePass()); @@ -725,7 +723,7 @@ void GLSLPostProcessor::registerPerformancePasses(Optimizer& optimizer, Config c RegisterPass(CreateRedundancyEliminationPass()); RegisterPass(CreateDeadBranchElimPass()); RegisterPass(CreateBlockMergePass()); - RegisterPass(CreateSimplificationPass()); + RegisterPass(CreateSimplificationPass(), MaterialBuilder::TargetApi::METAL); } void GLSLPostProcessor::registerSizePasses(Optimizer& optimizer, Config const& config) { From 37c615e2492263f097a1843cbda84a8cee3e8e38 Mon Sep 17 00:00:00 2001 From: Sungun Park Date: Mon, 9 Sep 2024 13:27:58 -0700 Subject: [PATCH 05/10] Support multi-layered render target (#8108) Clients can create a multi-layered render target that consists of array textures, and use it as a custom render target. A new sample app "hellostereo" demonstrates how to use this feature. --- NEW_RELEASE_NOTES.md | 2 + filament/src/details/RenderTarget.cpp | 12 +- samples/CMakeLists.txt | 3 + samples/hellostereo.cpp | 366 ++++++++++++++++++++++++++ samples/materials/arrayTexture.mat | 39 +++ 5 files changed, 419 insertions(+), 3 deletions(-) create mode 100644 samples/hellostereo.cpp create mode 100644 samples/materials/arrayTexture.mat diff --git a/NEW_RELEASE_NOTES.md b/NEW_RELEASE_NOTES.md index 4a1a9c7fa7e..a65a064c7a3 100644 --- a/NEW_RELEASE_NOTES.md +++ b/NEW_RELEASE_NOTES.md @@ -7,3 +7,5 @@ for next branch cut* header. appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md). ## Release notes for next branch cut + +- Add support for multi-layered render target with array textures. \ No newline at end of file diff --git a/filament/src/details/RenderTarget.cpp b/filament/src/details/RenderTarget.cpp index dad0af4d633..421df0dcc34 100644 --- a/filament/src/details/RenderTarget.cpp +++ b/filament/src/details/RenderTarget.cpp @@ -34,7 +34,7 @@ struct RenderTarget::BuilderDetails { uint32_t mWidth{}; uint32_t mHeight{}; uint8_t mSamples = 1; // currently not settable in the public facing API - uint8_t mLayerCount = 0;// currently not settable in the public facing API + uint8_t mLayerCount = 1; }; using BuilderType = RenderTarget; @@ -91,22 +91,28 @@ RenderTarget* RenderTarget::Builder::build(Engine& engine) { uint32_t maxWidth = 0; uint32_t minHeight = std::numeric_limits::max(); uint32_t maxHeight = 0; + uint32_t minDepth = std::numeric_limits::max(); + uint32_t maxDepth = 0; for (auto const& attachment : mImpl->mAttachments) { if (attachment.texture) { const uint32_t w = attachment.texture->getWidth(attachment.mipLevel); const uint32_t h = attachment.texture->getHeight(attachment.mipLevel); + const uint32_t d = attachment.texture->getDepth(attachment.mipLevel); minWidth = std::min(minWidth, w); minHeight = std::min(minHeight, h); + minDepth = std::min(minDepth, d); maxWidth = std::max(maxWidth, w); maxHeight = std::max(maxHeight, h); + maxDepth = std::max(maxDepth, d); } } - FILAMENT_CHECK_PRECONDITION(minWidth == maxWidth && minHeight == maxHeight) - << "All attachments dimensions must match"; + FILAMENT_CHECK_PRECONDITION(minWidth == maxWidth && minHeight == maxHeight + && minDepth == maxDepth) << "All attachments dimensions must match"; mImpl->mWidth = minWidth; mImpl->mHeight = minHeight; + mImpl->mLayerCount = minDepth; return downcast(engine).createRenderTarget(*this); } diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 7cd8ce6b9e6..0ff03049a7e 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -22,6 +22,7 @@ set(MATERIAL_SRCS materials/bakedTexture.mat materials/pointSprites.mat materials/aoPreview.mat + materials/arrayTexture.mat materials/groundShadow.mat materials/heightfield.mat materials/image.mat @@ -252,6 +253,7 @@ if (NOT ANDROID) add_demo(helloskinning) add_demo(helloskinningbuffer) add_demo(helloskinningbuffer_morebones) + add_demo(hellostereo) add_demo(image_viewer) add_demo(lightbulb) add_demo(material_sandbox) @@ -274,6 +276,7 @@ if (NOT ANDROID) target_link_libraries(gltf_viewer PRIVATE gltf-demo-resources uberarchive gltfio viewer) target_link_libraries(gltf_instances PRIVATE gltf-demo-resources uberarchive gltfio viewer) target_link_libraries(hellopbr PRIVATE filameshio suzanne-resources) + target_link_libraries(hellostereo PRIVATE filameshio suzanne-resources) target_link_libraries(image_viewer PRIVATE viewer imageio) target_link_libraries(multiple_windows PRIVATE filameshio suzanne-resources) target_link_libraries(rendertarget PRIVATE filameshio suzanne-resources) diff --git a/samples/hellostereo.cpp b/samples/hellostereo.cpp new file mode 100644 index 00000000000..fff1616ace0 --- /dev/null +++ b/samples/hellostereo.cpp @@ -0,0 +1,366 @@ +/* + * Copyright (C) 2024 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include +#include + +#include + +#include +#include + +#include "generated/resources/resources.h" +#include "generated/resources/monkey.h" + +using namespace filament; +using namespace filamesh; +using namespace filament::math; + +struct Vertex { + float3 position; + float2 uv; +}; + +struct App { + Config config; + + Material* monkeyMaterial; + MaterialInstance* monkeyMatInstance; + MeshReader::Mesh monkeyMesh; + mat4f monkeyTransform; + utils::Entity lightEntity; + + View* stereoView = nullptr; + Scene* stereoScene = nullptr; + Camera* stereoCamera = nullptr; + Texture* stereoColorTexture = nullptr; + Texture* stereoDepthTexture = nullptr; + RenderTarget* stereoRenderTarget = nullptr; + + VertexBuffer* quadVb = nullptr; + IndexBuffer* quadIb = nullptr; + Material* quadMaterial = nullptr; + std::vector quadEntities; + std::vector quadMatInstances; +}; + +static void printUsage(char* name) { + std::string exec_name(utils::Path(name).getName()); + std::string usage( + "SHOWCASE renders multiple quads displaying the contents of stereoscopic rendering\n" + "Usage:\n" + " SHOWCASE [options]\n" + "Options:\n" + " --help, -h\n" + " Prints this message\n\n" + " --api, -a\n" + " Specify the backend API: opengl (default), vulkan, or metal\n" + " --eyes=, -y \n" + " Sets the number of stereoscopic eyes (default: 2) when stereoscopic rendering is\n" + " enabled.\n\n" + ); + const std::string from("SHOWCASE"); + for (size_t pos = usage.find(from); pos != std::string::npos; pos = usage.find(from, pos)) { + usage.replace(pos, from.length(), exec_name); + } + std::cout << usage; +} + +static int handleCommandLineArguments(int argc, char* argv[], App* app) { + static constexpr const char* OPTSTR = "ha:y:"; + static const struct option OPTIONS[] = { + { "help", no_argument, nullptr, 'h' }, + { "api", required_argument, nullptr, 'a' }, + { "eyes", required_argument, nullptr, 'y' }, + { nullptr, 0, nullptr, 0 } + }; + int opt; + int option_index = 0; + while ((opt = getopt_long(argc, argv, OPTSTR, OPTIONS, &option_index)) >= 0) { + std::string arg(optarg ? optarg : ""); + switch (opt) { + default: + case 'h': + printUsage(argv[0]); + exit(0); + case 'a': + if (arg == "opengl") { + app->config.backend = Engine::Backend::OPENGL; + } else if (arg == "vulkan") { + app->config.backend = Engine::Backend::VULKAN; + } else if (arg == "metal") { + app->config.backend = Engine::Backend::METAL; + } else { + std::cerr << "Unrecognized backend. Must be 'opengl'|'vulkan'|'metal'.\n"; + exit(1); + } + break; + case 'y': { + int eyeCount = 0; + try { + eyeCount = std::stoi(arg); + } catch (std::invalid_argument &e) { } + if (eyeCount >= 2 && eyeCount <= CONFIG_MAX_STEREOSCOPIC_EYES) { + app->config.stereoscopicEyeCount = eyeCount; + } else { + std::cerr << "Eye count must be between 2 and CONFIG_MAX_STEREOSCOPIC_EYES (" + << (int)CONFIG_MAX_STEREOSCOPIC_EYES << ") (inclusive).\n"; + exit(1); + } + break; + } + } + } + return optind; +} + +int main(int argc, char** argv) { + +#if !defined(FILAMENT_SAMPLES_STEREO_TYPE_MULTIVIEW) + std::cerr << "This sample only works with multiview enabled.\n"; + exit(1); +#endif + + App app{}; + app.config.title = "stereoscopic rendering"; + handleCommandLineArguments(argc, argv, &app); + + auto setup = [&app](Engine* engine, View* view, Scene* scene) { + auto& tcm = engine->getTransformManager(); + auto& rcm = engine->getRenderableManager(); + auto& em = utils::EntityManager::get(); + auto vp = view->getViewport(); + + constexpr float3 monkeyPosition{ 0, 0, -4}; + constexpr float3 upVector{ 0, 1, 0}; + const int eyeCount = app.config.stereoscopicEyeCount; + + // Create a mesh material and an instance. + app.monkeyMaterial = Material::Builder() + .package(RESOURCES_AIDEFAULTMAT_DATA, RESOURCES_AIDEFAULTMAT_SIZE) + .build(*engine); + auto mi = app.monkeyMatInstance = app.monkeyMaterial->createInstance(); + mi->setParameter("baseColor", RgbType::LINEAR, {0.8, 1.0, 1.0}); + mi->setParameter("metallic", 0.0f); + mi->setParameter("roughness", 0.4f); + mi->setParameter("reflectance", 0.5f); + + // Add a monkey and a light source into the main scene. + app.monkeyMesh = MeshReader::loadMeshFromBuffer( + engine, MONKEY_SUZANNE_DATA, nullptr, nullptr, mi); + auto ti = tcm.getInstance(app.monkeyMesh.renderable); + app.monkeyTransform = mat4f{mat3f(1), monkeyPosition } * tcm.getWorldTransform(ti); + rcm.setCastShadows(rcm.getInstance(app.monkeyMesh.renderable), false); + scene->addEntity(app.monkeyMesh.renderable); + + app.lightEntity = em.create(); + LightManager::Builder(LightManager::Type::SUN) + .color(Color::toLinear(sRGBColor(0.98f, 0.92f, 0.89f))) + .intensity(110000) + .direction({ 0.7, -1, -0.8 }) + .sunAngularRadius(1.9f) + .castShadows(false) + .build(*engine, app.lightEntity); + scene->addEntity(app.lightEntity); + + // Create a stereo render target that will be rendered as an offscreen view. + app.stereoScene = engine->createScene(); + app.stereoScene->addEntity(app.monkeyMesh.renderable); + app.stereoScene->addEntity(app.lightEntity); + app.stereoView = engine->createView(); + app.stereoView->setScene(app.stereoScene); + app.stereoView->setPostProcessingEnabled(false); + app.stereoColorTexture = Texture::Builder() + .width(vp.width) + .height(vp.height) + .depth(eyeCount) + .levels(1) + .sampler(Texture::Sampler::SAMPLER_2D_ARRAY) + .format(Texture::InternalFormat::RGBA8) + .usage(Texture::Usage::COLOR_ATTACHMENT | Texture::Usage::SAMPLEABLE) + .build(*engine); + app.stereoDepthTexture = Texture::Builder() + .width(vp.width) + .height(vp.height) + .depth(eyeCount) + .levels(1) + .sampler(Texture::Sampler::SAMPLER_2D_ARRAY) + .format(Texture::InternalFormat::DEPTH24) + .usage(Texture::Usage::DEPTH_ATTACHMENT) + .build(*engine); + app.stereoRenderTarget = RenderTarget::Builder() + .texture(RenderTarget::AttachmentPoint::COLOR, app.stereoColorTexture) + .texture(RenderTarget::AttachmentPoint::DEPTH, app.stereoDepthTexture) + .build(*engine); + app.stereoView->setRenderTarget(app.stereoRenderTarget); + app.stereoView->setViewport({0, 0, vp.width, vp.height}); + app.stereoCamera = engine->createCamera(em.create()); + app.stereoView->setCamera(app.stereoCamera); + app.stereoView->setStereoscopicOptions({.enabled = true}); + FilamentApp::get().addOffscreenView(app.stereoView); + + // Camera settings for the stereo render target + constexpr double projNear = 0.1; + constexpr double projFar = 100; + + mat4 projections[CONFIG_MAX_STEREOSCOPIC_EYES]; + mat4 eyeModels[CONFIG_MAX_STEREOSCOPIC_EYES]; + static_assert(CONFIG_MAX_STEREOSCOPIC_EYES == 4, "Update matrices"); + projections[0] = Camera::projection(24, 1.0, projNear, projFar); + projections[1] = Camera::projection(70, 1.0, projNear, projFar); + projections[2] = Camera::projection(50, 1.0, projNear, projFar); + projections[3] = Camera::projection(35, 1.0, projNear, projFar); + app.stereoCamera->setCustomEyeProjection(projections, 4, projections[0], projNear, projFar); + + eyeModels[0] = mat4::lookAt(float3{ -4, 0, 0 }, monkeyPosition, upVector); + eyeModels[1] = mat4::lookAt(float3{ 4, 0, 0 }, monkeyPosition, upVector); + eyeModels[2] = mat4::lookAt(float3{ 0, 3, 0 }, monkeyPosition, upVector); + eyeModels[3] = mat4::lookAt(float3{ 0, -3, 0 }, monkeyPosition, upVector); + for (int i = 0; i < eyeCount; ++i) { + app.stereoCamera->setEyeModelMatrix(i, eyeModels[i]); + } + + // Create a vertex buffer and an index buffer for a quad. This will be used to display the contents + // of each layer of the stereo texture. + float3 quadCenter = {0, 0, 0}; + float3 quadNormal = normalize(float3 {0, 0, 1}); + float3 u = normalize(cross(quadNormal, upVector)); + float3 v = cross(quadNormal, u); + static Vertex quadVertices[4] = { + {{quadCenter - u - v}, {1, 0}}, + {{quadCenter + u - v}, {0, 0}}, + {{quadCenter - u + v}, {1, 1}}, + {{quadCenter + u + v}, {0, 1}} + }; + + static_assert(sizeof(Vertex) == 20, "Strange vertex size."); + app.quadVb = VertexBuffer::Builder() + .vertexCount(4) + .bufferCount(1) + .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3, 0, sizeof(Vertex)) + .attribute(VertexAttribute::UV0, 0, VertexBuffer::AttributeType::FLOAT2, 12, sizeof(Vertex)) + .build(*engine); + app.quadVb->setBufferAt(*engine, 0, + VertexBuffer::BufferDescriptor(quadVertices, sizeof(Vertex) * 4, nullptr)); + + static constexpr uint16_t quadIndices[6] = { 0, 1, 2, 3, 2, 1 }; + app.quadIb = IndexBuffer::Builder() + .indexCount(6) + .bufferType(IndexBuffer::IndexType::USHORT) + .build(*engine); + app.quadIb->setBuffer(*engine, IndexBuffer::BufferDescriptor(quadIndices, 12, nullptr)); + + // Create quad material instances and renderables. + app.quadMaterial = Material::Builder() + .package(RESOURCES_ARRAYTEXTURE_DATA, RESOURCES_ARRAYTEXTURE_SIZE) + .build(*engine); + + for (int i = 0; i < eyeCount; ++i) { + MaterialInstance* quadMatInst = app.quadMaterial->createInstance(); + TextureSampler sampler(TextureSampler::MinFilter::LINEAR, TextureSampler::MagFilter::LINEAR); + quadMatInst->setParameter("image", app.stereoColorTexture, sampler); + quadMatInst->setParameter("layerIndex", i); + quadMatInst->setParameter("borderEffect", true); + app.quadMatInstances.push_back(quadMatInst); + + utils::Entity quadEntity = em.create(); + app.quadEntities.push_back(quadEntity); + RenderableManager::Builder(1) + .boundingBox({{ -1, -1, -1 }, { 1, 1, 1 }}) + .material(0, quadMatInst) + .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, app.quadVb, app.quadIb, 0, 6) + .culling(false) + .receiveShadows(false) + .castShadows(false) + .build(*engine, quadEntity); + scene->addEntity(quadEntity); + + // Place quads at equal intervals. + TransformManager::Instance quadTi = tcm.getInstance(quadEntity); + mat4f quadWorld = tcm.getWorldTransform(quadTi); + constexpr float leftMostPos = -4; + constexpr float rightMostPos = 4; + float xpos = leftMostPos + ( (rightMostPos - leftMostPos) / (eyeCount - 1) ) * i; + tcm.setTransform(quadTi, mat4f::translation(float3(xpos, 2, -8)) * quadWorld); + } + }; + + auto cleanup = [&app](Engine* engine, View*, Scene*) { + + auto& em = utils::EntityManager::get(); + + for (MaterialInstance* mi : app.quadMatInstances) { + engine->destroy(mi); + } + for (utils::Entity e : app.quadEntities) { + engine->destroy(e); + } + engine->destroy(app.quadMaterial); + engine->destroy(app.quadIb); + engine->destroy(app.quadVb); + engine->destroy(app.stereoRenderTarget); + engine->destroy(app.stereoDepthTexture); + engine->destroy(app.stereoColorTexture); + auto camera = app.stereoCamera->getEntity(); + engine->destroyCameraComponent(camera); + em.destroy(camera); + engine->destroy(app.stereoScene); + engine->destroy(app.stereoView); + engine->destroy(app.lightEntity); + engine->destroy(app.monkeyMesh.renderable); + engine->destroy(app.monkeyMesh.indexBuffer); + engine->destroy(app.monkeyMesh.vertexBuffer); + engine->destroy(app.monkeyMatInstance); + engine->destroy(app.monkeyMaterial); + }; + + auto preRender = [&app](Engine*, View*, Scene*, Renderer* renderer) { + renderer->setClearOptions({.clearColor = {0.1,0.2,0.4,1.0}, .clear = true}); + }; + + FilamentApp::get().animate([&app](Engine* engine, View* view, double now) { + auto& tcm = engine->getTransformManager(); + + // Animate the monkey by spinning and sliding back and forth along Z. + auto ti = tcm.getInstance(app.monkeyMesh.renderable); + mat4f xform = app.monkeyTransform * mat4f::rotation(now, float3{0, 1, 0 }); + tcm.setTransform(ti, xform); + }); + + FilamentApp::get().run(app.config, setup, cleanup, FilamentApp::ImGuiCallback(), preRender); + + return 0; +} diff --git a/samples/materials/arrayTexture.mat b/samples/materials/arrayTexture.mat new file mode 100644 index 00000000000..f14a86bc864 --- /dev/null +++ b/samples/materials/arrayTexture.mat @@ -0,0 +1,39 @@ +material { + name : ArrayTexture, + parameters : [ + { + type : sampler2dArray, + name : image + }, + { + type : int, + name : layerIndex + }, + { + type : bool, + name : borderEffect + } + ], + requires : [ + uv0 + ], + shadingModel : unlit, + culling : none +} + +fragment { + void material(inout MaterialInputs material) { + prepareMaterial(material); + float3 v = texture(materialParams_image, vec3(getUV0(), materialParams.layerIndex)).rgb; + material.baseColor.rgb = v; + + // Add black border effect. + if (materialParams.borderEffect) { + vec2 st = getUV0(); + float minDist0 = min(st.x, st.y); + float minDist1 = min(1.0 - st.x, 1.0 - st.y); + float minDist = min(minDist0, minDist1); + material.baseColor.rgb *= smoothstep(0.0, 0.1, minDist); + } + } +} From 684d441ba74298eb350b4693387a70d0029ab145 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Mon, 9 Sep 2024 22:19:25 -0700 Subject: [PATCH 06/10] fix FrameSkipper (#8110) FrameSkipper was recently broken because of a typo resulting in the frame latency being always 3 instead of the default of 2. This change also makes the maximum latency 2 instead of 3, because on ANDROID, 3 can cause CPU throttling at seemingly random places on the GL thread. --- filament/src/FrameSkipper.cpp | 3 +-- filament/src/FrameSkipper.h | 13 ++++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/filament/src/FrameSkipper.cpp b/filament/src/FrameSkipper.cpp index ef14f5a0f82..673e82ef4f8 100644 --- a/filament/src/FrameSkipper.cpp +++ b/filament/src/FrameSkipper.cpp @@ -31,8 +31,7 @@ using namespace utils; using namespace backend; FrameSkipper::FrameSkipper(size_t latency) noexcept - : mLast(std::max(latency, MAX_FRAME_LATENCY) - 1) { - assert_invariant(latency <= MAX_FRAME_LATENCY); + : mLast(std::clamp(latency, size_t(1), MAX_FRAME_LATENCY) - 1) { } FrameSkipper::~FrameSkipper() noexcept = default; diff --git a/filament/src/FrameSkipper.h b/filament/src/FrameSkipper.h index 61bc4049735..814299341a2 100644 --- a/filament/src/FrameSkipper.h +++ b/filament/src/FrameSkipper.h @@ -32,7 +32,18 @@ namespace filament { * outrun the GPU. */ class FrameSkipper { - static constexpr size_t MAX_FRAME_LATENCY = 3; + /* + * The maximum frame latency acceptable on ANDROID is 2 because higher latencies will be + * throttled anyway in BufferQueueProducer::dequeueBuffer(), because ANDROID is generally + * triple-buffered no more; that case is actually pretty bad because the GL thread can block + * anywhere (usually inside the first draw command that touches the swapchain). + * + * A frame latency of 1 has the benefit of reducing render latency, + * but the drawback of preventing CPU / GPU overlap. + * + * Generally a frame latency of 2 is the best compromise. + */ + static constexpr size_t MAX_FRAME_LATENCY = 2; public: /* * The latency parameter defines how many unfinished frames we want to accept before we start From e9e7abe287f3795cf615d567f7b78b2b5f5853a6 Mon Sep 17 00:00:00 2001 From: Sungun Park Date: Tue, 10 Sep 2024 09:24:28 -0700 Subject: [PATCH 07/10] Add missing include (#8112) ptrdiff_t was transiently included by type_traits. However, this is not true for some cpp toolchains. Add the header inclusion explicitly. --- libs/utils/include/utils/memalign.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/utils/include/utils/memalign.h b/libs/utils/include/utils/memalign.h index 4c048bffdaf..ce2568ee1f2 100644 --- a/libs/utils/include/utils/memalign.h +++ b/libs/utils/include/utils/memalign.h @@ -17,6 +17,7 @@ #ifndef TNT_UTILS_MEMALIGN_H #define TNT_UTILS_MEMALIGN_H +#include #include #include From 597406579882d1efbb23417f7b970ef1528a1291 Mon Sep 17 00:00:00 2001 From: Sungun Park Date: Tue, 10 Sep 2024 11:21:28 -0700 Subject: [PATCH 08/10] Prefer using C header (#8113) Use stddef.h instead of cstddef for ptrdiff_t --- libs/utils/include/utils/memalign.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libs/utils/include/utils/memalign.h b/libs/utils/include/utils/memalign.h index ce2568ee1f2..c8c08fe1dea 100644 --- a/libs/utils/include/utils/memalign.h +++ b/libs/utils/include/utils/memalign.h @@ -17,7 +17,6 @@ #ifndef TNT_UTILS_MEMALIGN_H #define TNT_UTILS_MEMALIGN_H -#include #include #include @@ -74,8 +73,8 @@ class STLAlignedAllocator { using const_pointer = const TYPE*; using reference = TYPE&; using const_reference = const TYPE&; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; + using size_type = ::size_t; + using difference_type = ::ptrdiff_t; using propagate_on_container_move_assignment = std::true_type; using is_always_equal = std::true_type; From 72ba2eee6d9223ae83b1f9472933ce5570fbcd4f Mon Sep 17 00:00:00 2001 From: Powei Feng Date: Tue, 10 Sep 2024 12:26:43 -0700 Subject: [PATCH 09/10] Release Filament 1.54.3 --- NEW_RELEASE_NOTES.md | 2 -- README.md | 4 ++-- RELEASE_NOTES.md | 4 ++++ android/gradle.properties | 2 +- ios/CocoaPods/Filament.podspec | 4 ++-- web/filament-js/package.json | 2 +- 6 files changed, 10 insertions(+), 8 deletions(-) diff --git a/NEW_RELEASE_NOTES.md b/NEW_RELEASE_NOTES.md index a65a064c7a3..4a1a9c7fa7e 100644 --- a/NEW_RELEASE_NOTES.md +++ b/NEW_RELEASE_NOTES.md @@ -7,5 +7,3 @@ for next branch cut* header. appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md). ## Release notes for next branch cut - -- Add support for multi-layered render target with array textures. \ No newline at end of file diff --git a/README.md b/README.md index bdf20804b93..43a3ef8de2b 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation 'com.google.android.filament:filament-android:1.54.2' + implementation 'com.google.android.filament:filament-android:1.54.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.54.2' +pod 'Filament', '~> 1.54.3' ``` ## Documentation diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 48144bb1d81..c3bede1e3f5 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -7,6 +7,10 @@ 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.54.4 + +- Add support for multi-layered render target with array textures. + ## v1.54.3 diff --git a/android/gradle.properties b/android/gradle.properties index 510e34eb0a4..6b5d7c8454c 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.google.android.filament -VERSION_NAME=1.54.2 +VERSION_NAME=1.54.3 POM_DESCRIPTION=Real-time physically based rendering engine for Android. diff --git a/ios/CocoaPods/Filament.podspec b/ios/CocoaPods/Filament.podspec index 73fe0a78f81..c324c7cc115 100644 --- a/ios/CocoaPods/Filament.podspec +++ b/ios/CocoaPods/Filament.podspec @@ -1,12 +1,12 @@ Pod::Spec.new do |spec| spec.name = "Filament" - spec.version = "1.54.2" + spec.version = "1.54.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.54.2/filament-v1.54.2-ios.tgz" } + spec.source = { :http => "https://github.com/google/filament/releases/download/v1.54.3/filament-v1.54.3-ios.tgz" } # Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon. spec.pod_target_xcconfig = { diff --git a/web/filament-js/package.json b/web/filament-js/package.json index 7b502cf79ab..410de0fec0a 100644 --- a/web/filament-js/package.json +++ b/web/filament-js/package.json @@ -1,6 +1,6 @@ { "name": "filament", - "version": "1.54.2", + "version": "1.54.3", "description": "Real-time physically based rendering engine", "main": "filament.js", "module": "filament.js", From 429fd7acc672cb0f2096d2ae6e80d64d0483e211 Mon Sep 17 00:00:00 2001 From: Powei Feng Date: Tue, 10 Sep 2024 12:26:56 -0700 Subject: [PATCH 10/10] Bump version to 1.54.4 --- README.md | 4 ++-- android/gradle.properties | 2 +- ios/CocoaPods/Filament.podspec | 4 ++-- web/filament-js/package.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 43a3ef8de2b..4322afea615 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation 'com.google.android.filament:filament-android:1.54.3' + implementation 'com.google.android.filament:filament-android:1.54.4' } ``` @@ -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.54.3' +pod 'Filament', '~> 1.54.4' ``` ## Documentation diff --git a/android/gradle.properties b/android/gradle.properties index 6b5d7c8454c..e0c7ac6c119 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.google.android.filament -VERSION_NAME=1.54.3 +VERSION_NAME=1.54.4 POM_DESCRIPTION=Real-time physically based rendering engine for Android. diff --git a/ios/CocoaPods/Filament.podspec b/ios/CocoaPods/Filament.podspec index c324c7cc115..07e8121b8e1 100644 --- a/ios/CocoaPods/Filament.podspec +++ b/ios/CocoaPods/Filament.podspec @@ -1,12 +1,12 @@ Pod::Spec.new do |spec| spec.name = "Filament" - spec.version = "1.54.3" + spec.version = "1.54.4" 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.54.3/filament-v1.54.3-ios.tgz" } + spec.source = { :http => "https://github.com/google/filament/releases/download/v1.54.4/filament-v1.54.4-ios.tgz" } # Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon. spec.pod_target_xcconfig = { diff --git a/web/filament-js/package.json b/web/filament-js/package.json index 410de0fec0a..eccad539620 100644 --- a/web/filament-js/package.json +++ b/web/filament-js/package.json @@ -1,6 +1,6 @@ { "name": "filament", - "version": "1.54.3", + "version": "1.54.4", "description": "Real-time physically based rendering engine", "main": "filament.js", "module": "filament.js",