Compare commits

...
Author SHA1 Message Date
Sungun Park 6fc16bdcda Release Filament 1.51.8 2024-05-13 20:53:36 +00:00
Mathias Agopian 4f021583f1 backend tests were broken by a change in TargetBufferInfo
- a field was added, which broke the layout of the structure. We fix it
by adding constructors which will handle the old and new way of
initializing this structure.

- one of the test needed a hash update

- OpenGLContext wrongly asserted when trying to unbind texture 0
2024-05-10 14:39:22 -07:00
Powei Feng ef15a29c0c vk: fix missing lib for backend test 2024-05-10 13:00:00 -07:00
Benjamin Doherty a0472d3c9f Rename Metal log message 2024-05-10 11:25:34 -07:00
Ben Doherty 54a800a25d Metal: implement more accurate buffer tracking (#7839) 2024-05-10 11:14:41 -07:00
Powei Feng 7f8fbe586c gl: push constant small clean-up (#7841) 2024-05-10 10:23:32 -07:00
Powei Feng 6f2c45c76d Add push constants (#7817)
- Push constants is a small set of bytes that can be recorded
   directly on the command buffer.
 - Implemented it for the vulkan/gl backend.
2024-05-09 16:14:03 -07:00
Ryan ad60008b6a ryanmyers: Improve logging for Metallib function lookup failures (#7836)
If a .metallib was compiled with a target iOS version that's newer than
the current device, loading the .metallib may succeed, but finding main0
(or any other function in it) will fail. Currently, this causes a crash
due to an assert. Logging the error and returning
MetalFunctionBundle::error() makes the crash slightly easier to
diagnose.

(Note that in practice, this will probably be a useless "Compiler
encountered an internal error" message -- the GPU backend is crashing,
and the Metal stub library sees XPC_ERROR_CONNECTION_INTERRUPTED. It
retries up to 3 times (crashing each time) and then gives up.)
2024-05-09 10:49:41 -07:00
Mathias Agopian d87f9b621b add a simple tranformmanager unit test
this was to test issue #7827
2024-05-09 09:00:41 -07:00
Ben Doherty 1b38cda0d5 Add preferredShaderLanguage Java bindings (#7835) 2024-05-08 14:42:40 -07:00
Ben Doherty a1dea7b1fa Metal: log slow buffer allocation times (#7834) 2024-05-08 14:39:53 -07:00
Mathias Agopian 744708b5ca remove the single <sstream> usage we have
the STL's stream headers can bring in a lot of code, we don't use them.
2024-05-07 16:23:31 -07:00
Benjamin Doherty e901837317 Log excess buffer allocations for Metal 2024-05-07 15:39:48 -07:00
Powei Feng 17f71c9b81 Release Filament 1.51.7 2024-05-07 14:35:42 -07:00
Mathias AgopianandPowei Feng b056c126fe Add an Engine debug setting to force GLES 2.0 (#7829)
* Add an Engine debug setting to force GLES 2.0

This setting is only meaningful on GLES backends, it's otherwise
ignored. When set to true, the backend will try to force a ES2 context
if supported. If not supported by the platform,
the backend will pretend it's a ES2 context.

This setting is currently only taken into account by the EGL platform.

* Update filament/backend/include/backend/Platform.h

Co-authored-by: Powei Feng <powei@google.com>

---------

Co-authored-by: Powei Feng <powei@google.com>
2024-05-07 09:53:31 -07:00
Sungun Park 6ac36d1aab Fix a shader error (#7828)
gl_ViewID_OVR is of uint type. Explicitly convert it to int to fix the
error.
2024-05-06 21:03:04 +00:00
Ben Doherty a1752b363c Add preferredShaderLanguage option to Engine::Config (#7816) 2024-05-06 12:12:38 -07:00
Levente Koncz e855f4aafb Fix mixed up FBO targets in status check code inside OpenGLDriver::blit() 2024-05-06 09:17:15 -07:00
Ben Doherty 1c693e24cf Metal: track types of buffers (#7796) 2024-05-03 14:32:01 -07:00
Ben Doherty af92a1f21b Add getEyeIndex vertex API (#7822) 2024-05-03 14:22:24 -07:00
Powei Feng 10ff1ee3e4 Update filament to 1.51.6 for public pages (#7821)
Updated both /viewer and /remote
2024-05-03 20:49:53 +00:00
Vladyslav PopovychandVladyslav 5449f46350 Remove bitcode from iOS builds (#7802)
Co-authored-by: Vladyslav <vlad@arthouse.ar>
2024-05-03 12:25:00 -07:00
Mathias Agopian 2967888d26 repair instanced stereo in debug builds (#7819)
- it was broken by a wrong assertion
- also auto instancing + stereo instancing was
  always broken, but this makes it work
2024-05-03 09:36:09 -07:00
Powei Feng afe81d6889 vk: Use offset when uploading buffer data (#7818) 2024-05-02 11:17:32 -07:00
Mathias AgopianandBen Doherty 95134883d6 add the -a option to skinning and morphing samples (#7815)
* add the `-a` option to skinning and morphing samples

* Update samples/skinningtest.cpp

Co-authored-by: Ben Doherty <bendoherty@google.com>

* Update samples/helloskinningbuffer_morebones.cpp

Co-authored-by: Ben Doherty <bendoherty@google.com>

* Update samples/hellomorphing.cpp

Co-authored-by: Ben Doherty <bendoherty@google.com>

* Update samples/helloskinningbuffer.cpp

Co-authored-by: Ben Doherty <bendoherty@google.com>

---------

Co-authored-by: Ben Doherty <bendoherty@google.com>
2024-05-01 15:24:01 -07:00
Mathias Agopian 600c122761 fix ES2 support
- make sure we can build with ES2 headers only
- make sure to not use ES3 features when in ES2 mode
  (post processing was accidentally creating an R8 texture, 
  which is not supported)
2024-05-01 13:29:58 -07:00
Mathias Agopian 1cf5335964 Skybox doesn't need a commit() method
The material parameter changes are committed automatically in
Engine::prepare(), no need to do it explicitly for SkyBox.
2024-05-01 10:11:39 -07:00
Eliza Velasquez 4ac4ffd8d6 filagui: Split uiBlit material into two
Unfortunately, the external uniform was not optimized out as expected. The only
option is to split it into its own independent material.
2024-04-30 14:14:23 -07:00
Eliza Velasquez 6c40721695 Fix broken ImGui on web
I was unfortunately naive about the way that Filament handled external textures
on non-GLES platforms. This fix restricts the changes to Android (which is the
only place this change is required in the first place). Long story short, the
change broke WebGL. Desktop seems to be unaffected.
2024-04-30 14:14:23 -07:00
87 changed files with 1578 additions and 267 deletions
+2 -10
View File
@@ -173,15 +173,6 @@ if (NOT ANDROID AND NOT WEBGL AND NOT IOS AND NOT FILAMENT_LINUX_IS_MOBILE)
set(IS_HOST_PLATFORM TRUE)
endif()
if (IOS)
# Remove the headerpad_max_install_names linker flag on iOS. It causes warnings when linking
# executables with bitcode.
string(REPLACE "-Wl,-headerpad_max_install_names" "" CMAKE_C_LINK_FLAGS ${CMAKE_C_LINK_FLAGS})
string(REPLACE "-Wl,-headerpad_max_install_names" "" CMAKE_CXX_LINK_FLAGS ${CMAKE_CXX_LINK_FLAGS})
string(REPLACE "-Wl,-headerpad_max_install_names" "" CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS})
string(REPLACE "-Wl,-headerpad_max_install_names" "" CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS})
endif()
if (WIN32)
# Link statically against c/c++ lib to avoid missing redistriburable such as
# "VCRUNTIME140.dll not found. Try reinstalling the app.", but give users
@@ -393,8 +384,9 @@ endif()
if (NOT MSVC AND NOT IOS)
# Omitting stack frame pointers prevents the generation of readable stack traces in crash reports on iOS
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fomit-frame-pointer")
endif()
# These aren't compatible with -fembed-bitcode (and seem to have no effect on Apple platforms anyway)
if (NOT MSVC)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ffunction-sections -fdata-sections")
endif()
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.51.6'
implementation 'com.google.android.filament:filament-android:1.51.8'
}
```
@@ -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.51.6'
pod 'Filament', '~> 1.51.8'
```
### Snapshots
+10
View File
@@ -7,6 +7,16 @@ 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.51.9
## v1.51.8
- filagui: Fix regression which broke WebGL
- Add a new Engine::Config setting to control preferred shader language
- Add `getEyeIndex` vertex API
- ios: Remove bitcode from iOS builds
## v1.51.7
- Add new matedit tool
@@ -517,7 +517,9 @@ extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBu
jlong textureUseAfterFreePoolSize, jboolean disableParallelShaderCompile,
jint stereoscopicType, jlong stereoscopicEyeCount,
jlong resourceAllocatorCacheSizeMB, jlong resourceAllocatorCacheMaxAge,
jboolean disableHandleUseAfterFreeCheck) {
jboolean disableHandleUseAfterFreeCheck,
jint preferredShaderLanguage,
jboolean forceGLES2Context) {
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
Engine::Config config = {
.commandBufferSizeMB = (uint32_t) commandBufferSizeMB,
@@ -533,6 +535,8 @@ extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBu
.resourceAllocatorCacheSizeMB = (uint32_t) resourceAllocatorCacheSizeMB,
.resourceAllocatorCacheMaxAge = (uint8_t) resourceAllocatorCacheMaxAge,
.disableHandleUseAfterFreeCheck = (bool) disableHandleUseAfterFreeCheck,
.preferredShaderLanguage = (Engine::Config::ShaderLanguage) preferredShaderLanguage,
.forceGLES2Context = (bool) forceGLES2Context,
};
builder->config(&config);
}
@@ -225,7 +225,9 @@ public class Engine {
config.textureUseAfterFreePoolSize, config.disableParallelShaderCompile,
config.stereoscopicType.ordinal(), config.stereoscopicEyeCount,
config.resourceAllocatorCacheSizeMB, config.resourceAllocatorCacheMaxAge,
config.disableHandleUseAfterFreeCheck);
config.disableHandleUseAfterFreeCheck,
config.preferredShaderLanguage.ordinal(),
config.forceGLES2Context);
return this;
}
@@ -428,6 +430,35 @@ public class Engine {
* Disable backend handles use-after-free checks.
*/
public boolean disableHandleUseAfterFreeCheck = false;
/*
* Sets a preferred shader language for Filament to use.
*
* The Metal backend supports two shader languages: MSL (Metal Shading Language) and
* METAL_LIBRARY (precompiled .metallib). This option controls which shader language is
* used when materials contain both.
*
* By default, when preferredShaderLanguage is unset, Filament will prefer METAL_LIBRARY
* shaders if present within a material, falling back to MSL. Setting
* preferredShaderLanguage to ShaderLanguage::MSL will instead instruct Filament to check
* for the presence of MSL in a material first, falling back to METAL_LIBRARY if MSL is not
* present.
*
* When using a non-Metal backend, setting this has no effect.
*/
public enum ShaderLanguage {
DEFAULT,
MSL,
METAL_LIBRARY,
};
public ShaderLanguage preferredShaderLanguage = ShaderLanguage.DEFAULT;
/*
* When the OpenGL ES backend is used, setting this value to true will force a GLES2.0
* context if supported by the Platform, or if not, will have the backend pretend
* it's a GLES2 context. Ignored on other backends.
*/
public boolean forceGLES2Context = false;
}
private Engine(long nativeEngine, Config config) {
@@ -1353,7 +1384,9 @@ public class Engine {
long textureUseAfterFreePoolSize, boolean disableParallelShaderCompile,
int stereoscopicType, long stereoscopicEyeCount,
long resourceAllocatorCacheSizeMB, long resourceAllocatorCacheMaxAge,
boolean disableHandleUseAfterFreeCheck);
boolean disableHandleUseAfterFreeCheck,
int preferredShaderLanguage,
boolean forceGLES2Context);
private static native void nSetBuilderFeatureLevel(long nativeBuilder, int ordinal);
private static native void nSetBuilderSharedContext(long nativeBuilder, long sharedContext);
private static native void nSetBuilderPaused(long nativeBuilder, boolean paused);
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.51.6
VERSION_NAME=1.51.8
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
+2 -2
View File
@@ -476,7 +476,7 @@ Energy conservation is one of the key components of a good BRDF for physically b
<p>
For the specular term, \(f_m\) is a mirror BRDF that can be modeled with the Fresnel law, noted \(F\) in the Cook-Torrance approximation of the microfacet model integration:
For the specular term, \(f_r\) is a mirror BRDF that can be modeled with the Fresnel law, noted \(F\) in the Cook-Torrance approximation of the microfacet model integration:
</p><p>
@@ -857,7 +857,7 @@ The full GLSL implementation of the standard model is shown in <a href="#listing
<span class="line"> <span class="hljs-comment">// perceptually linear roughness to roughness (see parameterization)</span></span>
<span class="line"> <span class="hljs-type">float</span> roughness = perceptualRoughness * perceptualRoughness;</span>
<span class="line"></span>
<span class="line"> <span class="hljs-type">float</span> D = D_GGX(NoH, a);</span>
<span class="line"> <span class="hljs-type">float</span> D = D_GGX(NoH, roughness);</span>
<span class="line"> <span class="hljs-type">vec3</span> F = F_Schlick(LoH, f0);</span>
<span class="line"> <span class="hljs-type">float</span> V = V_SmithGGXCorrelated(NoV, NoL, roughness);</span>
<span class="line"></span>
+141 -53
View File
File diff suppressed because one or more lines are too long
+1
View File
@@ -2425,6 +2425,7 @@ The following APIs are only available from the vertex block:
**getWorldFromModelMatrix()** | float4x4 | Matrix that converts from model (object) space to world space
**getWorldFromModelNormalMatrix()** | float3x3 | Matrix that converts normals from model (object) space to world space
**getVertexIndex()** | int | Index of the current vertex
**getEyeIndex()** | int | Index of the eye being rendered, starting at 0
### Fragment only
File diff suppressed because one or more lines are too long
Binary file not shown.
+1 -1
View File
@@ -43,7 +43,7 @@ filament-viewer::part(canvas) {
</p>
</main>
<script src="https://unpkg.com/filament@1.44.0/filament.js"></script>
<script src="https://unpkg.com/filament@1.51.6/filament.js"></script>
<script src="https://unpkg.com/gltumble"></script>
<script src="filament-viewer.js" type="module"></script>
</body>
+4
View File
@@ -478,6 +478,10 @@ if (APPLE)
# linker from removing "unused" symbols.
target_link_libraries(backend_test_mac PRIVATE -force_load backend_test)
set_target_properties(backend_test_mac PROPERTIES FOLDER Tests)
# This is needed after XCode 15.3
set_target_properties(backend_test_mac PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
set_target_properties(backend_test_mac PROPERTIES INSTALL_RPATH /usr/local/lib)
endif()
endif()
@@ -31,6 +31,7 @@
#include <array> // FIXME: STL headers are not allowed in public headers
#include <type_traits> // FIXME: STL headers are not allowed in public headers
#include <variant> // FIXME: STL headers are not allowed in public headers
#include <stddef.h>
#include <stdint.h>
@@ -91,12 +92,15 @@ static constexpr uint64_t SWAP_CHAIN_HAS_STENCIL_BUFFER = SWAP_CHAIN_CON
*/
static constexpr uint64_t SWAP_CHAIN_CONFIG_PROTECTED_CONTENT = 0x40;
static constexpr size_t MAX_VERTEX_ATTRIBUTE_COUNT = 16; // This is guaranteed by OpenGL ES.
static constexpr size_t MAX_SAMPLER_COUNT = 62; // Maximum needed at feature level 3.
static constexpr size_t MAX_VERTEX_BUFFER_COUNT = 16; // Max number of bound buffer objects.
static constexpr size_t MAX_SSBO_COUNT = 4; // This is guaranteed by OpenGL ES.
static constexpr size_t MAX_PUSH_CONSTANT_COUNT = 32; // Vulkan 1.1 spec allows for 128-byte
// of push constant (we assume 4-byte
// types).
// Per feature level caps
// Use (int)FeatureLevel to index this array
static constexpr struct {
@@ -332,7 +336,7 @@ enum class UniformType : uint8_t {
/**
* Supported constant parameter types
*/
enum class ConstantType : uint8_t {
enum class ConstantType : uint8_t {
INT,
FLOAT,
BOOL
@@ -1219,6 +1223,8 @@ struct StencilState {
uint8_t padding = 0;
};
using PushConstantVariant = std::variant<int32_t, float, bool>;
static_assert(sizeof(StencilState::StencilOperations) == 5u,
"StencilOperations size not what was intended");
@@ -65,6 +65,12 @@ public:
* Disable backend handles use-after-free checks.
*/
bool disableHandleUseAfterFreeCheck = false;
/**
* Force GLES2 context if supported, or pretend the context is ES2. Only meaningful on
* GLES 3.x backends.
*/
bool forceGLES2Context = false;
};
Platform() noexcept;
@@ -117,6 +117,14 @@ public:
Program& specializationConstants(
utils::FixedCapacityVector<SpecializationConstant> specConstants) noexcept;
struct PushConstant {
utils::CString name;
ConstantType type;
};
Program& pushConstants(ShaderStage stage,
utils::FixedCapacityVector<PushConstant> constants) noexcept;
Program& cacheId(uint64_t cacheId) noexcept;
Program& multiview(bool multiview) noexcept;
@@ -148,6 +156,15 @@ public:
return mSpecializationConstants;
}
utils::FixedCapacityVector<PushConstant> const& getPushConstants(
ShaderStage stage) const noexcept {
return mPushConstants[static_cast<uint8_t>(stage)];
}
utils::FixedCapacityVector<PushConstant>& getPushConstants(ShaderStage stage) noexcept {
return mPushConstants[static_cast<uint8_t>(stage)];
}
uint64_t getCacheId() const noexcept { return mCacheId; }
bool isMultiview() const noexcept { return mMultiview; }
@@ -165,6 +182,7 @@ private:
uint64_t mCacheId{};
utils::Invocable<utils::io::ostream&(utils::io::ostream& out)> mLogger;
utils::FixedCapacityVector<SpecializationConstant> mSpecializationConstants;
std::array<utils::FixedCapacityVector<PushConstant>, SHADER_TYPE_COUNT> mPushConstants;
utils::FixedCapacityVector<std::pair<utils::CString, uint8_t>> mAttributes;
std::array<UniformInfo, Program::UNIFORM_BINDING_COUNT> mBindingUniformInfo;
CompilerPriorityQueue mPriorityQueue = CompilerPriorityQueue::HIGH;
@@ -29,17 +29,36 @@ namespace filament::backend {
//! \privatesection
struct TargetBufferInfo {
// note: the parameters of this constructor are not in the order of this structure's fields
TargetBufferInfo(Handle<HwTexture> handle, uint8_t level, uint16_t layer, uint8_t baseViewIndex) noexcept
: handle(handle), baseViewIndex(baseViewIndex), level(level), layer(layer) {
}
TargetBufferInfo(Handle<HwTexture> handle, uint8_t level, uint16_t layer) noexcept
: handle(handle), level(level), layer(layer) {
}
TargetBufferInfo(Handle<HwTexture> handle, uint8_t level) noexcept
: handle(handle), level(level) {
}
TargetBufferInfo(Handle<HwTexture> handle) noexcept // NOLINT(*-explicit-constructor)
: handle(handle) {
}
TargetBufferInfo() noexcept = default;
// texture to be used as render target
Handle<HwTexture> handle;
// starting layer index for multiview. This value is only used when the `layerCount` for the
// Starting layer index for multiview. This value is only used when the `layerCount` for the
// render target is greater than 1.
uint8_t baseViewIndex = 0;
// level to be used
uint8_t level = 0;
// for cubemaps and 3D textures. See TextureCubemapFace for the face->layer mapping
// For cubemaps and 3D textures. See TextureCubemapFace for the face->layer mapping
uint16_t layer = 0;
};
@@ -64,7 +83,7 @@ public:
MRT() noexcept = default;
MRT(TargetBufferInfo const& color) noexcept // NOLINT(hicpp-explicit-conversions)
MRT(TargetBufferInfo const& color) noexcept // NOLINT(hicpp-explicit-conversions, *-explicit-constructor)
: mInfos{ color } {
}
@@ -84,7 +103,7 @@ public:
// this is here for backward compatibility
MRT(Handle<HwTexture> handle, uint8_t level, uint16_t layer) noexcept
: mInfos{{ handle, 0, level, layer }} {
: mInfos{{ handle, level, layer, 0 }} {
}
};
@@ -434,6 +434,11 @@ DECL_DRIVER_API_N(bindSamplers,
uint32_t, index,
backend::SamplerGroupHandle, sbh)
DECL_DRIVER_API_N(setPushConstant,
backend::ShaderStage, stage,
uint8_t, index,
backend::PushConstantVariant, value)
DECL_DRIVER_API_N(insertEventMarker,
const char*, string,
uint32_t, len = 0)
+6
View File
@@ -91,6 +91,12 @@ Program& Program::specializationConstants(
return *this;
}
Program& Program::pushConstants(ShaderStage stage,
utils::FixedCapacityVector<PushConstant> constants) noexcept {
mPushConstants[static_cast<uint8_t>(stage)] = std::move(constants);
return *this;
}
Program& Program::cacheId(uint64_t cacheId) noexcept {
mCacheId = cacheId;
return *this;
+121 -37
View File
@@ -18,6 +18,7 @@
#define TNT_FILAMENT_DRIVER_METALBUFFER_H
#include "MetalContext.h"
#include "MetalPlatform.h"
#include <backend/DriverEnums.h>
@@ -28,47 +29,122 @@
#include <utility>
#include <memory>
#include <atomic>
#include <chrono>
namespace filament::backend {
class TrackedMetalBuffer {
class ScopedAllocationTimer {
public:
TrackedMetalBuffer() noexcept : mBuffer(nil) {}
TrackedMetalBuffer(id<MTLBuffer> buffer) noexcept : mBuffer(buffer) {
if (buffer) {
aliveBuffers++;
}
}
~TrackedMetalBuffer() {
if (mBuffer) {
aliveBuffers--;
ScopedAllocationTimer(const char* name) : mBeginning(clock_t::now()), mName(name) {}
~ScopedAllocationTimer() {
using namespace std::literals::chrono_literals;
static constexpr std::chrono::seconds LONG_TIME_THRESHOLD = 10s;
auto end = clock_t::now();
std::chrono::duration<double, std::micro> allocationTimeMicroseconds = end - mBeginning;
if (UTILS_UNLIKELY(allocationTimeMicroseconds > LONG_TIME_THRESHOLD)) {
if (platform && platform->hasDebugUpdateStatFunc()) {
char buffer[64];
snprintf(buffer, sizeof(buffer), "filament.metal.long_buffer_allocation_time.%s",
mName);
platform->debugUpdateStat(
buffer, static_cast<uint64_t>(allocationTimeMicroseconds.count()));
}
}
}
TrackedMetalBuffer(TrackedMetalBuffer&&) = delete;
TrackedMetalBuffer(TrackedMetalBuffer const&) = delete;
TrackedMetalBuffer& operator=(TrackedMetalBuffer const&) = delete;
TrackedMetalBuffer& operator=(TrackedMetalBuffer&& rhs) noexcept {
swap(rhs);
return *this;
}
id<MTLBuffer> get() const noexcept { return mBuffer; }
operator bool() const noexcept { return bool(mBuffer); }
static uint64_t getAliveBuffers() { return aliveBuffers; }
static void setPlatform(MetalPlatform* p) { platform = p; }
private:
void swap(TrackedMetalBuffer& other) noexcept {
id<MTLBuffer> temp = mBuffer;
mBuffer = other.mBuffer;
other.mBuffer = temp;
typedef std::chrono::steady_clock clock_t;
static MetalPlatform* platform;
std::chrono::time_point<clock_t> mBeginning;
const char* mName;
};
#ifndef FILAMENT_METAL_BUFFER_TRACKING
#define FILAMENT_METAL_BUFFER_TRACKING 0
#endif
class MetalBufferTracking {
public:
static constexpr size_t EXCESS_BUFFER_COUNT = 30000;
enum class Type {
NONE = 0,
GENERIC = 1,
RING = 2,
STAGING = 3,
};
static constexpr size_t TypeCount = 3;
static constexpr auto toIndex(Type t) {
assert_invariant(t != Type::NONE);
switch (t) {
case Type::NONE:
case Type::GENERIC:
return 0;
case Type::RING:
return 1;
case Type::STAGING:
return 2;
}
}
id<MTLBuffer> mBuffer;
#if FILAMENT_METAL_BUFFER_TRACKING
static void initialize() {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
for (size_t i = 0; i < TypeCount; i++) {
aliveBuffers[i] = [NSHashTable weakObjectsHashTable];
}
});
}
static std::atomic<uint64_t> aliveBuffers;
static void setPlatform(MetalPlatform* p) { platform = p; }
static void track(id<MTLBuffer> buffer, Type type) {
assert_invariant(type != Type::NONE);
if (UTILS_UNLIKELY(getAliveBuffers() >= EXCESS_BUFFER_COUNT)) {
if (platform && platform->hasDebugUpdateStatFunc()) {
platform->debugUpdateStat("filament.metal.excess_buffers_allocated",
MetalBufferTracking::getAliveBuffers());
}
}
[aliveBuffers[toIndex(type)] addObject:buffer];
}
static uint64_t getAliveBuffers() {
uint64_t sum = 0;
for (size_t i = 1; i < TypeCount; i++) {
sum += getAliveBuffers(static_cast<Type>(i));
}
return sum;
}
static uint64_t getAliveBuffers(Type type) {
assert_invariant(type != Type::NONE);
NSHashTable* hashTable = aliveBuffers[toIndex(type)];
// Caution! We can't simply use hashTable.count here, which is inaccurate.
// See http://cocoamine.net/blog/2013/12/13/nsmaptable-and-zeroing-weak-references/
return hashTable.objectEnumerator.allObjects.count;
}
#else
static void initialize() {}
static void setPlatform(MetalPlatform* p) {}
static id<MTLBuffer> track(id<MTLBuffer> buffer, Type type) { return buffer; }
static uint64_t getAliveBuffers() { return 0; }
static uint64_t getAliveBuffers(Type type) { return 0; }
#endif
private:
#if FILAMENT_METAL_BUFFER_TRACKING
static std::array<NSHashTable<id<MTLBuffer>>*, TypeCount> aliveBuffers;
static MetalPlatform* platform;
#endif
};
class MetalBuffer {
@@ -122,7 +198,7 @@ public:
private:
TrackedMetalBuffer mBuffer;
id<MTLBuffer> mBuffer;
size_t mBufferSize = 0;
void* mCpuBuffer = nullptr;
MetalContext& mContext;
@@ -171,7 +247,11 @@ public:
mBufferOptions(options),
mSlotSizeBytes(computeSlotSize(layout)),
mSlotCount(slotCount) {
mBuffer = [device newBufferWithLength:mSlotSizeBytes * mSlotCount options:mBufferOptions];
{
ScopedAllocationTimer timer("ring");
mBuffer = [device newBufferWithLength:mSlotSizeBytes * mSlotCount options:mBufferOptions];
}
MetalBufferTracking::track(mBuffer, MetalBufferTracking::Type::RING);
assert_invariant(mBuffer);
}
@@ -189,9 +269,13 @@ public:
// If we already have an aux buffer, it will get freed here, unless it has been retained
// by a MTLCommandBuffer. In that case, it will be freed when the command buffer
// finishes executing.
mAuxBuffer = [mDevice newBufferWithLength:mSlotSizeBytes options:mBufferOptions];
{
ScopedAllocationTimer timer("ring");
mAuxBuffer = [mDevice newBufferWithLength:mSlotSizeBytes options:mBufferOptions];
}
MetalBufferTracking::track(mAuxBuffer, MetalBufferTracking::Type::RING);
assert_invariant(mAuxBuffer);
return {mAuxBuffer.get(), 0};
return { mAuxBuffer, 0 };
}
mCurrentSlot = (mCurrentSlot + 1) % mSlotCount;
mOccupiedSlots->fetch_add(1, std::memory_order_relaxed);
@@ -220,9 +304,9 @@ public:
*/
std::pair<id<MTLBuffer>, NSUInteger> getCurrentAllocation() const {
if (UTILS_UNLIKELY(mAuxBuffer)) {
return { mAuxBuffer.get(), 0 };
return { mAuxBuffer, 0 };
}
return { mBuffer.get(), mCurrentSlot * mSlotSizeBytes };
return { mBuffer, mCurrentSlot * mSlotSizeBytes };
}
bool canAccomodateLayout(MTLSizeAndAlign layout) const {
@@ -231,8 +315,8 @@ public:
private:
id<MTLDevice> mDevice;
TrackedMetalBuffer mBuffer;
TrackedMetalBuffer mAuxBuffer;
id<MTLBuffer> mBuffer;
id<MTLBuffer> mAuxBuffer;
MTLResourceOptions mBufferOptions;
+16 -6
View File
@@ -22,7 +22,13 @@
namespace filament {
namespace backend {
std::atomic<uint64_t> TrackedMetalBuffer::aliveBuffers = 0;
MetalPlatform* ScopedAllocationTimer::platform = nullptr;
#if FILAMENT_METAL_BUFFER_TRACKING
std::array<NSHashTable<id<MTLBuffer>>*, MetalBufferTracking::TypeCount>
MetalBufferTracking::aliveBuffers;
MetalPlatform* MetalBufferTracking::platform = nullptr;
#endif
MetalBuffer::MetalBuffer(MetalContext& context, BufferObjectBinding bindingType, BufferUsage usage,
size_t size, bool forceGpuBuffer) : mBufferSize(size), mContext(context) {
@@ -37,7 +43,11 @@ MetalBuffer::MetalBuffer(MetalContext& context, BufferObjectBinding bindingType,
}
// Otherwise, we allocate a private GPU buffer.
mBuffer = [context.device newBufferWithLength:size options:MTLResourceStorageModePrivate];
{
ScopedAllocationTimer timer("generic");
mBuffer = [context.device newBufferWithLength:size options:MTLResourceStorageModePrivate];
}
MetalBufferTracking::track(mBuffer, MetalBufferTracking::Type::GENERIC);
ASSERT_POSTCONDITION(mBuffer, "Could not allocate Metal buffer of size %zu.", size);
}
@@ -64,7 +74,7 @@ void MetalBuffer::copyIntoBuffer(void* src, size_t size, size_t byteOffset) {
// Acquire a staging buffer to hold the contents of this update.
MetalBufferPool* bufferPool = mContext.bufferPool;
const MetalBufferPoolEntry* const staging = bufferPool->acquireBuffer(size);
memcpy(staging->buffer.get().contents, src, size);
memcpy(staging->buffer.contents, src, size);
// The blit below requires that byteOffset be a multiple of 4.
ASSERT_PRECONDITION(!(byteOffset & 0x3u), "byteOffset must be a multiple of 4");
@@ -73,9 +83,9 @@ void MetalBuffer::copyIntoBuffer(void* src, size_t size, size_t byteOffset) {
id<MTLCommandBuffer> cmdBuffer = getPendingCommandBuffer(&mContext);
id<MTLBlitCommandEncoder> blitEncoder = [cmdBuffer blitCommandEncoder];
blitEncoder.label = @"Buffer upload blit";
[blitEncoder copyFromBuffer:staging->buffer.get()
[blitEncoder copyFromBuffer:staging->buffer
sourceOffset:0
toBuffer:mBuffer.get()
toBuffer:mBuffer
destinationOffset:byteOffset
size:size];
[blitEncoder endEncoding];
@@ -96,7 +106,7 @@ id<MTLBuffer> MetalBuffer::getGpuBufferForDraw(id<MTLCommandBuffer> cmdBuffer) n
return nil;
}
assert_invariant(mBuffer);
return mBuffer.get();
return mBuffer;
}
void MetalBuffer::bindBuffers(id<MTLCommandBuffer> cmdBuffer, id<MTLCommandEncoder> encoder,
+1 -1
View File
@@ -32,7 +32,7 @@ struct MetalContext;
// Immutable POD representing a shared CPU-GPU buffer.
struct MetalBufferPoolEntry {
TrackedMetalBuffer buffer;
id<MTLBuffer> buffer;
size_t capacity;
mutable uint64_t lastAccessed;
mutable uint32_t referenceCount;
@@ -42,8 +42,13 @@ MetalBufferPoolEntry const* MetalBufferPool::acquireBuffer(size_t numBytes) {
}
// We were not able to find a sufficiently large stage, so create a new one.
id<MTLBuffer> buffer = [mContext.device newBufferWithLength:numBytes
options:MTLResourceStorageModeShared];
id<MTLBuffer> buffer = nil;
{
ScopedAllocationTimer timer("staging");
buffer = [mContext.device newBufferWithLength:numBytes
options:MTLResourceStorageModeShared];
}
MetalBufferTracking::track(buffer, MetalBufferTracking::Type::STAGING);
ASSERT_POSTCONDITION(buffer, "Could not allocate Metal staging buffer of size %zu.", numBytes);
MetalBufferPoolEntry* stage = new MetalBufferPoolEntry {
.buffer = buffer,
+19 -1
View File
@@ -105,6 +105,10 @@ MetalDriver::MetalDriver(MetalPlatform* platform, const Platform::DriverConfig&
driverConfig.disableHandleUseAfterFreeCheck) {
mContext->driver = this;
ScopedAllocationTimer::setPlatform(platform);
MetalBufferTracking::initialize();
MetalBufferTracking::setPlatform(platform);
mContext->device = mPlatform.createDevice();
assert_invariant(mContext->device);
@@ -198,6 +202,8 @@ MetalDriver::MetalDriver(MetalPlatform* platform, const Platform::DriverConfig&
}
MetalDriver::~MetalDriver() noexcept {
MetalBufferTracking::setPlatform(nullptr);
ScopedAllocationTimer::setPlatform(nullptr);
mContext->device = nil;
mContext->emptyTexture = nil;
CFRelease(mContext->textureCache);
@@ -218,7 +224,16 @@ void MetalDriver::beginFrame(int64_t monotonic_clock_ns,
os_signpost_interval_begin(mContext->log, mContext->signpostId, "Frame encoding", "%{public}d", frameId);
#endif
if (mPlatform.hasDebugUpdateStatFunc()) {
mPlatform.debugUpdateStat("filament.metal.alive_buffers", TrackedMetalBuffer::getAliveBuffers());
#if FILAMENT_METAL_BUFFER_TRACKING
const uint64_t generic = MetalBufferTracking::getAliveBuffers(MetalBufferTracking::Type::GENERIC);
const uint64_t ring = MetalBufferTracking::getAliveBuffers(MetalBufferTracking::Type::RING);
const uint64_t staging = MetalBufferTracking::getAliveBuffers(MetalBufferTracking::Type::STAGING);
const uint64_t total = generic + ring + staging;
mPlatform.debugUpdateStat("filament.metal.alive_buffers", total);
mPlatform.debugUpdateStat("filament.metal.alive_buffers.generic", generic);
mPlatform.debugUpdateStat("filament.metal.alive_buffers.ring", ring);
mPlatform.debugUpdateStat("filament.metal.alive_buffers.staging", staging);
#endif
}
}
@@ -1241,6 +1256,9 @@ void MetalDriver::bindSamplers(uint32_t index, Handle<HwSamplerGroup> sbh) {
mContext->samplerBindings[index] = sb;
}
void MetalDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
backend::PushConstantVariant value) {}
void MetalDriver::insertEventMarker(const char* string, uint32_t len) {
}
+2 -2
View File
@@ -789,13 +789,13 @@ void MetalTexture::loadWithCopyBuffer(uint32_t level, uint32_t slice, MTLRegion
PixelBufferDescriptor const& data, const PixelBufferShape& shape) {
const size_t stagingBufferSize = shape.totalBytes;
auto entry = context.bufferPool->acquireBuffer(stagingBufferSize);
memcpy(entry->buffer.get().contents,
memcpy(entry->buffer.contents,
static_cast<uint8_t*>(data.buffer) + shape.sourceOffset,
stagingBufferSize);
id<MTLCommandBuffer> blitCommandBuffer = getPendingCommandBuffer(&context);
id<MTLBlitCommandEncoder> blitCommandEncoder = [blitCommandBuffer blitCommandEncoder];
blitCommandEncoder.label = @"Texture upload buffer blit";
[blitCommandEncoder copyFromBuffer:entry->buffer.get()
[blitCommandEncoder copyFromBuffer:entry->buffer
sourceOffset:0
sourceBytesPerRow:shape.bytesPerRow
sourceBytesPerImage:shape.bytesPerSlice
@@ -169,6 +169,23 @@ bool MetalShaderCompiler::isParallelShaderCompileSupported() const noexcept {
id<MTLFunction> function = [library newFunctionWithName:@"main0"
constantValues:constants
error:&error];
if (function == nil) {
// If the library loads but functions within it fail to load, it usually means the
// GPU backend crashed. (This can happen if it's a Metallib shader that was compiled
// with a minimum iOS version that's newer than this device.)
NSString* errorMessage = @"unknown error";
if (error) {
auto description =
[error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding];
utils::slog.w << description << utils::io::endl;
errorMessage = error.localizedDescription;
}
PANIC_LOG("Failed to load main0 in Metal program.");
NSString* programName =
[NSString stringWithFormat:@"%s::main0", program.getName().c_str_safe()];
return MetalFunctionBundle::error(errorMessage, programName);
}
if (!program.getName().empty()) {
function.label = @(program.getName().c_str());
}
+4
View File
@@ -312,6 +312,10 @@ void NoopDriver::unbindBuffer(BufferObjectBinding bindingType, uint32_t index) {
void NoopDriver::bindSamplers(uint32_t index, Handle<HwSamplerGroup> sbh) {
}
void NoopDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
backend::PushConstantVariant value) {
}
void NoopDriver::insertEventMarker(char const* string, uint32_t len) {
}
+19 -7
View File
@@ -63,7 +63,8 @@ bool OpenGLContext::queryOpenGLVersion(GLint* major, GLint* minor) noexcept {
#endif
}
OpenGLContext::OpenGLContext(OpenGLPlatform& platform) noexcept
OpenGLContext::OpenGLContext(OpenGLPlatform& platform,
Platform::DriverConfig const& driverConfig) noexcept
: mPlatform(platform),
mSamplerMap(32) {
@@ -85,6 +86,13 @@ OpenGLContext::OpenGLContext(OpenGLPlatform& platform) noexcept
queryOpenGLVersion(&state.major, &state.minor);
#if defined(BACKEND_OPENGL_VERSION_GLES)
if (UTILS_UNLIKELY(driverConfig.forceGLES2Context)) {
state.major = 2;
state.minor = 0;
}
#endif
OpenGLContext::initExtensions(&ext, state.major, state.minor);
OpenGLContext::initProcs(&procs, ext, state.major, state.minor);
@@ -886,12 +894,16 @@ void OpenGLContext::unbindTexture(
// unbind this texture from all the units it might be bound to
// no need unbind the texture from FBOs because we're not tracking that state (and there is
// no need to).
UTILS_NOUNROLL
for (GLuint unit = 0; unit < MAX_TEXTURE_UNIT_COUNT; unit++) {
if (state.textures.units[unit].id == texture_id) {
// if this texture is bound, it should be at the same target
assert_invariant(state.textures.units[unit].target == target);
unbindTextureUnit(unit);
// Never attempt to unbind texture 0. This could happen with external textures w/ streaming if
// never populated.
if (texture_id) {
UTILS_NOUNROLL
for (GLuint unit = 0; unit < MAX_TEXTURE_UNIT_COUNT; unit++) {
if (state.textures.units[unit].id == texture_id) {
// if this texture is bound, it should be at the same target
assert_invariant(state.textures.units[unit].target == target);
unbindTextureUnit(unit);
}
}
}
}
+2 -1
View File
@@ -91,7 +91,8 @@ public:
static bool queryOpenGLVersion(GLint* major, GLint* minor) noexcept;
explicit OpenGLContext(OpenGLPlatform& platform) noexcept;
explicit OpenGLContext(OpenGLPlatform& platform,
Platform::DriverConfig const& driverConfig) noexcept;
~OpenGLContext() noexcept final;
+48 -4
View File
@@ -173,6 +173,10 @@ Driver* OpenGLDriver::create(OpenGLPlatform* const platform,
PANIC_LOG("OpenGL ES 2.0 minimum needed (current %d.%d)", major, minor);
goto cleanup;
}
if (UTILS_UNLIKELY(driverConfig.forceGLES2Context)) {
major = 2;
minor = 0;
}
#else
// we require GL 4.1 headers and minimum version
if (UTILS_UNLIKELY(!((major == 4 && minor >= 1) || major > 4))) {
@@ -203,12 +207,13 @@ OpenGLDriver::DebugMarker::~DebugMarker() noexcept {
OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform, const Platform::DriverConfig& driverConfig) noexcept
: mPlatform(*platform),
mContext(mPlatform),
mContext(mPlatform, driverConfig),
mShaderCompilerService(*this),
mHandleAllocator("Handles",
driverConfig.handleArenaSize,
driverConfig.disableHandleUseAfterFreeCheck),
mDriverConfig(driverConfig) {
mDriverConfig(driverConfig),
mCurrentPushConstants(new(std::nothrow) PushConstantBundle{}) {
std::fill(mSamplerBindings.begin(), mSamplerBindings.end(), nullptr);
@@ -265,6 +270,9 @@ void OpenGLDriver::terminate() {
assert_invariant(mGpuCommandCompleteOps.empty());
#endif
delete mCurrentPushConstants;
mCurrentPushConstants = nullptr;
mContext.terminate();
mPlatform.terminate();
@@ -285,6 +293,39 @@ void OpenGLDriver::bindSampler(GLuint unit, GLuint sampler) noexcept {
mContext.bindSampler(unit, sampler);
}
void OpenGLDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
backend::PushConstantVariant value) {
assert_invariant(stage == ShaderStage::VERTEX || stage == ShaderStage::FRAGMENT);
utils::Slice<std::pair<GLint, ConstantType>> constants;
if (stage == ShaderStage::VERTEX) {
constants = mCurrentPushConstants->vertexConstants;
} else if (stage == ShaderStage::FRAGMENT) {
constants = mCurrentPushConstants->fragmentConstants;
}
assert_invariant(index < constants.size());
auto const& [location, type] = constants[index];
// This push constant wasn't found in the shader. It's ok to return without error-ing here.
if (location < 0) {
return;
}
if (std::holds_alternative<bool>(value)) {
assert_invariant(type == ConstantType::BOOL);
bool const bval = std::get<bool>(value);
glUniform1i(location, bval ? 1 : 0);
} else if (std::holds_alternative<float>(value)) {
assert_invariant(type == ConstantType::FLOAT);
float const fval = std::get<float>(value);
glUniform1f(location, fval);
} else {
assert_invariant(type == ConstantType::INT);
int const ival = std::get<int>(value);
glUniform1i(location, ival);
}
}
void OpenGLDriver::bindTexture(GLuint unit, GLTexture const* t) noexcept {
assert_invariant(t != nullptr);
mContext.bindTexture(unit, t->gl.target, t->gl.id);
@@ -3382,7 +3423,9 @@ void OpenGLDriver::executeGpuCommandsCompleteOps() noexcept {
void OpenGLDriver::tick(int) {
DEBUG_MARKER()
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
executeGpuCommandsCompleteOps();
#endif
executeEveryNowAndThenOps();
getShaderCompilerService().tick();
}
@@ -3654,7 +3697,7 @@ void OpenGLDriver::blit(
case SamplerType::SAMPLER_EXTERNAL:
break;
}
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_READ_FRAMEBUFFER)
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_DRAW_FRAMEBUFFER)
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, fbo[1]);
switch (s->target) {
@@ -3680,7 +3723,7 @@ void OpenGLDriver::blit(
case SamplerType::SAMPLER_EXTERNAL:
break;
}
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_DRAW_FRAMEBUFFER)
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_READ_FRAMEBUFFER)
gl.disable(GL_SCISSOR_TEST);
glBlitFramebuffer(
@@ -3802,6 +3845,7 @@ void OpenGLDriver::bindPipeline(PipelineState state) {
gl.polygonOffset(state.polygonOffset.slope, state.polygonOffset.constant);
OpenGLProgram* const p = handle_cast<OpenGLProgram*>(state.program);
mValidProgram = useProgram(p);
(*mCurrentPushConstants) = p->getPushConstants();
}
void OpenGLDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
+3 -1
View File
@@ -66,9 +66,9 @@ namespace filament::backend {
class OpenGLPlatform;
class PixelBufferDescriptor;
struct TargetBufferInfo;
class OpenGLProgram;
class TimerQueryFactoryInterface;
struct PushConstantBundle;
class OpenGLDriver final : public DriverBase {
inline explicit OpenGLDriver(OpenGLPlatform* platform,
@@ -375,6 +375,8 @@ private:
// for ES2 sRGB support
GLSwapChain* mCurrentDrawSwapChain = nullptr;
bool mRec709OutputColorspace = false;
PushConstantBundle* mCurrentPushConstants = nullptr;
};
// ------------------------------------------------------------------------------------------------
+19 -1
View File
@@ -46,6 +46,8 @@ struct OpenGLProgram::LazyInitializationData {
Program::UniformBlockInfo uniformBlockInfo;
Program::SamplerGroupInfo samplerGroupInfo;
std::array<Program::UniformInfo, Program::UNIFORM_BINDING_COUNT> bindingUniformInfo;
utils::FixedCapacityVector<Program::PushConstant> vertexPushConstants;
utils::FixedCapacityVector<Program::PushConstant> fragmentPushConstants;
};
@@ -53,7 +55,6 @@ OpenGLProgram::OpenGLProgram() noexcept = default;
OpenGLProgram::OpenGLProgram(OpenGLDriver& gld, Program&& program) noexcept
: HwProgram(std::move(program.getName())) {
auto* const lazyInitializationData = new(std::nothrow) LazyInitializationData();
lazyInitializationData->samplerGroupInfo = std::move(program.getSamplerGroupInfo());
if (UTILS_UNLIKELY(gld.getContext().isES2())) {
@@ -61,6 +62,8 @@ OpenGLProgram::OpenGLProgram(OpenGLDriver& gld, Program&& program) noexcept
} else {
lazyInitializationData->uniformBlockInfo = std::move(program.getUniformBlockBindings());
}
lazyInitializationData->vertexPushConstants = std::move(program.getPushConstants(ShaderStage::VERTEX));
lazyInitializationData->fragmentPushConstants = std::move(program.getPushConstants(ShaderStage::FRAGMENT));
ShaderCompilerService& compiler = gld.getShaderCompilerService();
mToken = compiler.createProgram(name, std::move(program));
@@ -203,6 +206,21 @@ void OpenGLProgram::initializeProgramState(OpenGLContext& context, GLuint progra
}
}
mUsedBindingsCount = usedBindingCount;
auto& vertexConstants = lazyInitializationData.vertexPushConstants;
auto& fragmentConstants = lazyInitializationData.fragmentPushConstants;
size_t const totalConstantCount = vertexConstants.size() + fragmentConstants.size();
if (totalConstantCount > 0) {
mPushConstants.reserve(totalConstantCount);
mPushConstantFragmentStageOffset = vertexConstants.size();
auto const transformAndAdd = [&](Program::PushConstant const& constant) {
GLint const loc = glGetUniformLocation(program, constant.name.c_str());
mPushConstants.push_back({loc, constant.type});
};
std::for_each(vertexConstants.cbegin(), vertexConstants.cend(), transformAndAdd);
std::for_each(fragmentConstants.cbegin(), fragmentConstants.cend(), transformAndAdd);
}
}
void OpenGLProgram::updateSamplers(OpenGLDriver* const gld) const noexcept {
+25 -4
View File
@@ -27,6 +27,7 @@
#include <utils/compiler.h>
#include <utils/FixedCapacityVector.h>
#include <utils/Slice.h>
#include <array>
#include <limits>
@@ -38,6 +39,11 @@ namespace filament::backend {
class OpenGLDriver;
struct PushConstantBundle {
utils::Slice<std::pair<GLint, ConstantType>> vertexConstants;
utils::Slice<std::pair<GLint, ConstantType>> fragmentConstants;
};
class OpenGLProgram : public HwProgram {
public:
@@ -78,6 +84,14 @@ public:
GLuint program = 0;
} gl; // 4 bytes
PushConstantBundle getPushConstants() {
auto fragBegin = mPushConstants.begin() + mPushConstantFragmentStageOffset;
return {
.vertexConstants = utils::Slice(mPushConstants.begin(), fragBegin),
.fragmentConstants = utils::Slice(fragBegin, mPushConstants.end()),
};
}
private:
// keep these away from of other class attributes
struct LazyInitializationData;
@@ -95,11 +109,14 @@ private:
ShaderCompilerService::program_token_t mToken{}; // 16 bytes
uint8_t mUsedBindingsCount = 0u; // 1 byte
UTILS_UNUSED uint8_t padding[3] = {}; // 3 bytes
UTILS_UNUSED uint8_t padding[2] = {}; // 2 byte
// Push constant array offset for fragment stage constants.
uint8_t mPushConstantFragmentStageOffset = 0u; // 1 byte
// only needed for ES2
GLint mRec709Location = -1; // 4 bytes
GLint mRec709Location = -1; // 4 bytes
using LocationInfo = utils::FixedCapacityVector<GLint>;
struct UniformsRecord {
Program::UniformInfo uniforms;
@@ -107,11 +124,15 @@ private:
mutable GLuint id = 0;
mutable uint16_t age = std::numeric_limits<uint16_t>::max();
};
UniformsRecord const* mUniformsRecords = nullptr;
UniformsRecord const* mUniformsRecords = nullptr; // 8 bytes
// Note that this can be replaced with a raw pointer and an uint8_t (for size) to reduce the
// size of the container to 9 bytes if there is a need in the future.
utils::FixedCapacityVector<std::pair<GLint, ConstantType>> mPushConstants;// 16 bytes
};
// if OpenGLProgram is larger tha 64 bytes, it'll fall in a larger Handle bucket.
static_assert(sizeof(OpenGLProgram) <= 64); // currently 48 bytes
static_assert(sizeof(OpenGLProgram) <= 64); // currently 64 bytes
} // namespace filament::backend
@@ -174,7 +174,7 @@ Driver* PlatformEGL::createDriver(void* sharedContext, const Platform::DriverCon
};
#ifdef __ANDROID__
bool requestES2Context = false;
bool requestES2Context = driverConfig.forceGLES2Context;
char property[PROP_VALUE_MAX];
int const length = __system_property_get("debug.filament.es2", property);
if (length > 0) {
+1
View File
@@ -410,6 +410,7 @@ io::ostream& operator<<(io::ostream& out, const RasterState& rs) {
io::ostream& operator<<(io::ostream& out, const TargetBufferInfo& tbi) {
return out << "TargetBufferInfo{"
<< "handle=" << tbi.handle
<< ", baseViewIndex=" << tbi.baseViewIndex
<< ", level=" << tbi.level
<< ", layer=" << tbi.layer << "}";
}
+5 -2
View File
@@ -50,7 +50,6 @@ VulkanBuffer::~VulkanBuffer() {
void VulkanBuffer::loadFromCpu(VkCommandBuffer cmdbuf, const void* cpuData, uint32_t byteOffset,
uint32_t numBytes) {
assert_invariant(byteOffset == 0);
VulkanStage const* stage = mStagePool.acquireStage(numBytes);
void* mapped;
vmaMapMemory(mAllocator, stage->memory, &mapped);
@@ -87,7 +86,11 @@ void VulkanBuffer::loadFromCpu(VkCommandBuffer cmdbuf, const void* cpuData, uint
&barrier, 0, nullptr);
}
VkBufferCopy region{ .size = numBytes };
VkBufferCopy region {
.srcOffset = 0,
.dstOffset = byteOffset,
.size = numBytes,
};
vkCmdCopyBuffer(cmdbuf, stage->buffer, mGpuBuffer, 1, &region);
mUpdatedBytes = numBytes;
+17 -3
View File
@@ -259,8 +259,8 @@ VulkanDriver::VulkanDriver(VulkanPlatform* platform, VulkanContext const& contex
mDescriptorSetManager.setPlaceHolders(mSamplerCache.getSampler({}), mEmptyTexture,
mEmptyBufferObject);
mGetPipelineFunction = [this](VulkanDescriptorSetLayoutList const& layouts) {
return mPipelineLayoutCache.getLayout(layouts);
mGetPipelineFunction = [this](VulkanDescriptorSetLayoutList const& layouts, VulkanProgram* program) {
return mPipelineLayoutCache.getLayout(layouts, program);
};
}
@@ -1572,6 +1572,14 @@ void VulkanDriver::bindSamplers(uint32_t index, Handle<HwSamplerGroup> sbh) {
mSamplerBindings[index] = hwsb;
}
void VulkanDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
backend::PushConstantVariant value) {
assert_invariant(mBoundPipeline.program && "Expect a program when writing to push constants");
VulkanCommands* commands = &mCommands;
mBoundPipeline.program->writePushConstant(commands, mBoundPipeline.pipelineLayout, stage, index,
value);
}
void VulkanDriver::insertEventMarker(char const* string, uint32_t len) {
#if FVK_ENABLED(FVK_DEBUG_GROUP_MARKERS)
mCommands.insertEventMarker(string, len);
@@ -1857,7 +1865,13 @@ void VulkanDriver::bindPipeline(PipelineState pipelineState) {
mDescriptorSetManager.updateSampler({}, binding, texture, vksampler);
}
mPipelineCache.bindLayout(mDescriptorSetManager.bind(commands, program, mGetPipelineFunction));
auto const pipelineLayout = mDescriptorSetManager.bind(commands, program, mGetPipelineFunction);
mBoundPipeline = {
.program = program,
.pipelineLayout = pipelineLayout,
};
mPipelineCache.bindLayout(pipelineLayout);
mPipelineCache.bindPipeline(commands);
FVK_SYSTRACE_END();
}
@@ -160,6 +160,13 @@ private:
VulkanDescriptorSetManager::GetPipelineLayoutFunction mGetPipelineFunction;
// This is necessary for us to write to push constants after binding a pipeline.
struct BoundPipeline {
VulkanProgram* program;
VkPipelineLayout pipelineLayout;
};
BoundPipeline mBoundPipeline = {};
RenderPassFboBundle mRenderPassFboInfo;
bool const mIsSRGBSwapChainSupported;
+60 -5
View File
@@ -112,27 +112,82 @@ inline VkDescriptorSetLayout createDescriptorSetLayout(VkDevice device,
return layout;
}
inline VkShaderStageFlags getVkStage(backend::ShaderStage stage) {
switch(stage) {
case backend::ShaderStage::VERTEX:
return VK_SHADER_STAGE_VERTEX_BIT;
case backend::ShaderStage::FRAGMENT:
return VK_SHADER_STAGE_FRAGMENT_BIT;
case backend::ShaderStage::COMPUTE:
PANIC_POSTCONDITION("Unsupported stage");
}
}
} // anonymous namespace
VulkanDescriptorSetLayout::VulkanDescriptorSetLayout(VkDevice device, VkDescriptorSetLayoutCreateInfo const& info,
Bitmask const& bitmask)
VulkanDescriptorSetLayout::VulkanDescriptorSetLayout(VkDevice device,
VkDescriptorSetLayoutCreateInfo const& info, Bitmask const& bitmask)
: VulkanResource(VulkanResourceType::DESCRIPTOR_SET_LAYOUT),
mDevice(device),
vklayout(createDescriptorSetLayout(device, info)),
bitmask(bitmask),
bindings(getBindings(bitmask)),
count(Count::fromLayoutBitmask(bitmask)) {
}
count(Count::fromLayoutBitmask(bitmask)) {}
VulkanDescriptorSetLayout::~VulkanDescriptorSetLayout() {
vkDestroyDescriptorSetLayout(mDevice, vklayout, VKALLOC);
}
PushConstantDescription::PushConstantDescription(backend::Program const& program) noexcept {
mRangeCount = 0;
for (auto stage : { ShaderStage::VERTEX, ShaderStage::FRAGMENT, ShaderStage::COMPUTE }) {
auto const& constants = program.getPushConstants(stage);
if (constants.empty()) {
continue;
}
// We store the type of the constant for type-checking when writing.
auto& types = mTypes[(uint8_t) stage];
types.reserve(constants.size());
std::for_each(constants.cbegin(), constants.cend(), [&types] (Program::PushConstant t) {
types.push_back(t.type);
});
mRanges[mRangeCount++] = {
.stageFlags = getVkStage(stage),
.offset = 0,
.size = (uint32_t) constants.size() * ENTRY_SIZE,
};
}
}
void PushConstantDescription::write(VulkanCommands* commands, VkPipelineLayout layout,
backend::ShaderStage stage, uint8_t index, backend::PushConstantVariant const& value) {
VulkanCommandBuffer* cmdbuf = &(commands->get());
uint32_t binaryValue = 0;
UTILS_UNUSED_IN_RELEASE auto const& types = mTypes[(uint8_t) stage];
if (std::holds_alternative<bool>(value)) {
assert_invariant(types[index] == ConstantType::BOOL);
bool const bval = std::get<bool>(value);
binaryValue = static_cast<uint32_t const>(bval ? VK_TRUE : VK_FALSE);
} else if (std::holds_alternative<float>(value)) {
assert_invariant(types[index] == ConstantType::FLOAT);
float const fval = std::get<float>(value);
binaryValue = *reinterpret_cast<uint32_t const*>(&fval);
} else {
assert_invariant(types[index] == ConstantType::INT);
int const ival = std::get<int>(value);
binaryValue = *reinterpret_cast<uint32_t const*>(&ival);
}
vkCmdPushConstants(cmdbuf->buffer(), layout, getVkStage(stage), index * ENTRY_SIZE, ENTRY_SIZE,
&binaryValue);
}
VulkanProgram::VulkanProgram(VkDevice device, Program const& builder) noexcept
: HwProgram(builder.getName()),
VulkanResource(VulkanResourceType::PROGRAM),
mInfo(new PipelineInfo()),
mInfo(new(std::nothrow) PipelineInfo(builder)),
mDevice(device) {
constexpr uint8_t UBO_MODULE_OFFSET = (sizeof(UniformBufferBitmask) * 8) / MAX_SHADER_MODULES;
+43 -5
View File
@@ -26,10 +26,10 @@
#include "VulkanTexture.h"
#include "VulkanUtility.h"
#include "private/backend/SamplerGroup.h"
#include "utils/FixedCapacityVector.h"
#include "vulkan/vulkan_core.h"
#include <private/backend/SamplerGroup.h>
#include <backend/Program.h>
#include <utils/FixedCapacityVector.h>
#include <utils/Mutex.h>
#include <utils/StructureOfArrays.h>
@@ -180,6 +180,28 @@ private:
using VulkanDescriptorSetList = std::array<Handle<VulkanDescriptorSet>,
VulkanDescriptorSetLayout::UNIQUE_DESCRIPTOR_SET_COUNT>;
using PushConstantNameArray = utils::FixedCapacityVector<char const*>;
using PushConstantNameByStage = std::array<PushConstantNameArray, Program::SHADER_TYPE_COUNT>;
struct PushConstantDescription {
explicit PushConstantDescription(backend::Program const& program) noexcept;
VkPushConstantRange const* getVkRanges() const noexcept { return mRanges; }
uint32_t getVkRangeCount() const noexcept { return mRangeCount; }
void write(VulkanCommands* commands, VkPipelineLayout layout, backend::ShaderStage stage,
uint8_t index, backend::PushConstantVariant const& value);
private:
static constexpr uint32_t ENTRY_SIZE = sizeof(uint32_t);
utils::FixedCapacityVector<backend::ConstantType> mTypes[Program::SHADER_TYPE_COUNT];
VkPushConstantRange mRanges[Program::SHADER_TYPE_COUNT];
uint32_t mRangeCount;
};
struct VulkanProgram : public HwProgram, VulkanResource {
using BindingList = CappedArray<uint16_t, MAX_SAMPLER_COUNT>;
@@ -212,6 +234,19 @@ struct VulkanProgram : public HwProgram, VulkanResource {
VulkanDescriptorSetLayout::UNIQUE_DESCRIPTOR_SET_COUNT>;
inline LayoutDescriptionList const& getLayoutDescriptionList() const { return mInfo->layouts; }
inline uint32_t getPushConstantRangeCount() const {
return mInfo->pushConstantDescription.getVkRangeCount();
}
inline VkPushConstantRange const* getPushConstantRanges() const {
return mInfo->pushConstantDescription.getVkRanges();
}
inline void writePushConstant(VulkanCommands* commands, VkPipelineLayout layout,
backend::ShaderStage stage, uint8_t index, backend::PushConstantVariant const& value) {
mInfo->pushConstantDescription.write(commands, layout, stage, index, value);
}
#if FVK_ENABLED_DEBUG_SAMPLER_NAME
inline utils::FixedCapacityVector<std::string> const& getBindingToName() const {
return mInfo->bindingToName;
@@ -224,8 +259,9 @@ struct VulkanProgram : public HwProgram, VulkanResource {
private:
struct PipelineInfo {
PipelineInfo()
: bindingToSamplerIndex(MAX_SAMPLER_COUNT, 0xffff)
explicit PipelineInfo(backend::Program const& program) noexcept
: bindingToSamplerIndex(MAX_SAMPLER_COUNT, 0xffff),
pushConstantDescription(program)
#if FVK_ENABLED_DEBUG_SAMPLER_NAME
, bindingToName(MAX_SAMPLER_COUNT, "")
#endif
@@ -241,6 +277,8 @@ private:
// descset::DescriptorSetLayout layout;
LayoutDescriptionList layouts;
PushConstantDescription pushConstantDescription;
#if FVK_ENABLED_DEBUG_SAMPLER_NAME
// We store the sampler name mapped from binding index (only for debug purposes).
utils::FixedCapacityVector<std::string> bindingToName;
@@ -879,7 +879,7 @@ public:
vkUpdateDescriptorSets(mDevice, nwrites, descriptorWrites, 0, nullptr);
}
VkPipelineLayout const pipelineLayout = getPipelineLayoutFn(outLayouts);
VkPipelineLayout const pipelineLayout = getPipelineLayoutFn(outLayouts, program);
VkCommandBuffer const cmdbuffer = commands->buffer();
BoundState state{};
@@ -45,8 +45,8 @@ class VulkanDescriptorSetManager {
public:
static constexpr uint8_t UNIQUE_DESCRIPTOR_SET_COUNT =
VulkanDescriptorSetLayout::UNIQUE_DESCRIPTOR_SET_COUNT;
using GetPipelineLayoutFunction =
std::function<VkPipelineLayout(VulkanDescriptorSetLayoutList const&)>;
using GetPipelineLayoutFunction = std::function<VkPipelineLayout(
VulkanDescriptorSetLayoutList const&, VulkanProgram* program)>;
VulkanDescriptorSetManager(VkDevice device, VulkanResourceAllocator* resourceAllocator);
@@ -108,3 +108,4 @@ private:
}// namespace filament::backend
#endif// TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETMANAGER_H
@@ -21,13 +21,34 @@
namespace filament::backend {
VkPipelineLayout VulkanPipelineLayoutCache::getLayout(
VulkanDescriptorSetLayoutList const& descriptorSetLayouts) {
PipelineLayoutKey key = {VK_NULL_HANDLE};
VulkanDescriptorSetLayoutList const& descriptorSetLayouts, VulkanProgram* program) {
PipelineLayoutKey key = {};
uint8_t descSetLayoutCount = 0;
for (auto layoutHandle: descriptorSetLayouts) {
if (layoutHandle) {
auto layout = mAllocator->handle_cast<VulkanDescriptorSetLayout*>(layoutHandle);
key[descSetLayoutCount++] = layout->vklayout;
key.descSetLayouts[descSetLayoutCount++] = layout->vklayout;
}
}
// build the push constant layout key
uint32_t pushConstantRangeCount = program->getPushConstantRangeCount();
auto const& pushCostantRanges = program->getPushConstantRanges();
if (pushConstantRangeCount > 0) {
assert_invariant(pushConstantRangeCount <= Program::SHADER_TYPE_COUNT);
for (uint8_t i = 0; i < pushConstantRangeCount; ++i) {
auto const& range = pushCostantRanges[i];
auto& pushConstant = key.pushConstant[i];
if (range.stageFlags & VK_SHADER_STAGE_VERTEX_BIT) {
pushConstant.stage = static_cast<uint8_t>(ShaderStage::VERTEX);
}
if (range.stageFlags & VK_SHADER_STAGE_FRAGMENT_BIT) {
pushConstant.stage = static_cast<uint8_t>(ShaderStage::FRAGMENT);
}
if (range.stageFlags & VK_SHADER_STAGE_COMPUTE_BIT) {
pushConstant.stage = static_cast<uint8_t>(ShaderStage::COMPUTE);
}
pushConstant.size = range.size;
}
}
@@ -42,9 +63,11 @@ VkPipelineLayout VulkanPipelineLayoutCache::getLayout(
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.pNext = nullptr,
.setLayoutCount = (uint32_t) descSetLayoutCount,
.pSetLayouts = key.data(),
.pushConstantRangeCount = 0,
.pSetLayouts = key.descSetLayouts.data(),
.pushConstantRangeCount = pushConstantRangeCount,
.pPushConstantRanges = pushCostantRanges,
};
VkPipelineLayout layout;
vkCreatePipelineLayout(mDevice, &info, VKALLOC, &layout);
@@ -35,13 +35,29 @@ public:
void terminate() noexcept;
using PipelineLayoutKey = std::array<VkDescriptorSetLayout,
VulkanDescriptorSetLayout::UNIQUE_DESCRIPTOR_SET_COUNT>;
struct PushConstantKey {
uint8_t stage;// We have one set of push constant per shader stage (fragment, vertex, etc).
uint8_t size;
// Note that there is also an offset parameter for push constants, but
// we always assume our update range will have the offset 0.
};
struct PipelineLayoutKey {
using DescriptorSetLayoutArray = std::array<VkDescriptorSetLayout,
VulkanDescriptorSetLayout::UNIQUE_DESCRIPTOR_SET_COUNT>;
DescriptorSetLayoutArray descSetLayouts = {}; // 8 * 3
PushConstantKey pushConstant[Program::SHADER_TYPE_COUNT] = {}; // 2 * 3
uint16_t padding = 0;
};
static_assert(sizeof(PipelineLayoutKey) == 32);
VulkanPipelineLayoutCache(VulkanPipelineLayoutCache const&) = delete;
VulkanPipelineLayoutCache& operator=(VulkanPipelineLayoutCache const&) = delete;
VkPipelineLayout getLayout(VulkanDescriptorSetLayoutList const& descriptorSetLayouts);
// A pipeline layout depends on the descriptor set layout and the push constant ranges, which
// are described in the program.
VkPipelineLayout getLayout(VulkanDescriptorSetLayoutList const& descriptorSetLayouts,
VulkanProgram* program);
private:
using Timestamp = uint64_t;
+1 -1
View File
@@ -265,7 +265,7 @@ TEST_F(BackendTest, FeedbackLoops) {
for (auto rt : renderTargets) api.destroyRenderTarget(rt);
}
const uint32_t expected = 0xe93a4a07;
const uint32_t expected = 0x70695aa1;
printf("Computed hash is 0x%8.8x, Expected 0x%8.8x\n", sPixelHashResult, expected);
EXPECT_TRUE(sPixelHashResult == expected);
}
+29
View File
@@ -340,6 +340,35 @@ public:
* Disable backend handles use-after-free checks.
*/
bool disableHandleUseAfterFreeCheck = false;
/*
* Sets a preferred shader language for Filament to use.
*
* The Metal backend supports two shader languages: MSL (Metal Shading Language) and
* METAL_LIBRARY (precompiled .metallib). This option controls which shader language is
* used when materials contain both.
*
* By default, when preferredShaderLanguage is unset, Filament will prefer METAL_LIBRARY
* shaders if present within a material, falling back to MSL. Setting
* preferredShaderLanguage to ShaderLanguage::MSL will instead instruct Filament to check
* for the presence of MSL in a material first, falling back to METAL_LIBRARY if MSL is not
* present.
*
* When using a non-Metal backend, setting this has no effect.
*/
enum class ShaderLanguage {
DEFAULT = 0,
MSL = 1,
METAL_LIBRARY = 2,
};
ShaderLanguage preferredShaderLanguage = ShaderLanguage::DEFAULT;
/*
* When the OpenGL ES backend is used, setting this value to true will force a GLES2.0
* context if supported by the Platform, or if not, will have the backend pretend
* it's a GLES2 context. Ignored on other backends.
*/
bool forceGLES2Context = false;
};
+51
View File
@@ -30,6 +30,7 @@
#include <private/filament/SubpassInfo.h>
#include <private/filament/Variant.h>
#include <private/filament/ConstantInfo.h>
#include <private/filament/PushConstantInfo.h>
#include <utils/CString.h>
@@ -225,6 +226,14 @@ bool MaterialParser::getConstants(utils::FixedCapacityVector<MaterialConstant>*
return ChunkMaterialConstants::unflatten(unflattener, value);
}
bool MaterialParser::getPushConstants(utils::CString* structVarName,
utils::FixedCapacityVector<MaterialPushConstant>* value) const noexcept {
auto [start, end] = mImpl.mChunkContainer.getChunkRange(filamat::MaterialPushConstants);
if (start == end) return false;
Unflattener unflattener(start, end);
return ChunkMaterialPushConstants::unflatten(unflattener, structVarName, value);
}
bool MaterialParser::getDepthWriteSet(bool* value) const noexcept {
return mImpl.getFromSimpleChunk(ChunkType::MaterialDepthWriteSet, value);
}
@@ -709,4 +718,46 @@ bool ChunkMaterialConstants::unflatten(filaflat::Unflattener& unflattener,
return true;
}
bool ChunkMaterialPushConstants::unflatten(filaflat::Unflattener& unflattener,
utils::CString* structVarName,
utils::FixedCapacityVector<MaterialPushConstant>* materialPushConstants) {
assert_invariant(materialPushConstants);
if (!unflattener.read(structVarName)) {
return false;
}
// Read number of constants.
uint64_t numConstants = 0;
if (!unflattener.read(&numConstants)) {
return false;
}
materialPushConstants->reserve(numConstants);
materialPushConstants->resize(numConstants);
for (uint64_t i = 0; i < numConstants; i++) {
CString constantName;
uint8_t constantType = 0;
uint8_t shaderStage = 0;
if (!unflattener.read(&constantName)) {
return false;
}
if (!unflattener.read(&constantType)) {
return false;
}
if (!unflattener.read(&shaderStage)) {
return false;
}
(*materialPushConstants)[i].name = constantName;
(*materialPushConstants)[i].type = static_cast<backend::ConstantType>(constantType);
(*materialPushConstants)[i].stage = static_cast<backend::ShaderStage>(shaderStage);
}
return true;
}
} // namespace filament
+8
View File
@@ -47,6 +47,7 @@ class BufferInterfaceBlock;
class SamplerInterfaceBlock;
struct SubpassInfo;
struct MaterialConstant;
struct MaterialPushConstant;
class MaterialParser {
public:
@@ -79,6 +80,8 @@ public:
bool getSamplerBlockBindings(SamplerGroupBindingInfoList* pSamplerGroupInfoList,
SamplerBindingToNameMap* pSamplerBindingToNameMap) const noexcept;
bool getConstants(utils::FixedCapacityVector<MaterialConstant>* value) const noexcept;
bool getPushConstants(utils::CString* structVarName,
utils::FixedCapacityVector<MaterialPushConstant>* value) const noexcept;
using BindingUniformInfoContainer = utils::FixedCapacityVector<
std::pair<filament::UniformBindingPoints, backend::Program::UniformInfo>>;
@@ -214,6 +217,11 @@ struct ChunkMaterialConstants {
utils::FixedCapacityVector<MaterialConstant>* materialConstants);
};
struct ChunkMaterialPushConstants {
static bool unflatten(filaflat::Unflattener& unflattener, utils::CString* structVarName,
utils::FixedCapacityVector<MaterialPushConstant>* materialPushConstants);
};
} // namespace filament
#endif // TNT_FILAMENT_MATERIALPARSER_H
+14 -11
View File
@@ -341,19 +341,22 @@ void PostProcessManager::init() noexcept {
}
}
mStarburstTexture = driver.createTexture(SamplerType::SAMPLER_2D, 1,
TextureFormat::R8, 1, 256, 1, 1, TextureUsage::DEFAULT);
if (engine.hasFeatureLevel(FeatureLevel::FEATURE_LEVEL_1)) {
mStarburstTexture = driver.createTexture(SamplerType::SAMPLER_2D, 1,
TextureFormat::R8, 1, 256, 1, 1, TextureUsage::DEFAULT);
PixelBufferDescriptor dataStarburst(driver.allocate(256), 256, PixelDataFormat::R, PixelDataType::UBYTE);
std::generate_n((uint8_t*)dataStarburst.buffer, 256,
[&dist = mUniformDistribution, &gen = mEngine.getRandomEngine()]() {
float const r = 0.5f + 0.5f * dist(gen);
return uint8_t(r * 255.0f);
});
PixelBufferDescriptor dataStarburst(driver.allocate(256), 256,
PixelDataFormat::R, PixelDataType::UBYTE);
std::generate_n((uint8_t*)dataStarburst.buffer, 256,
[&dist = mUniformDistribution, &gen = mEngine.getRandomEngine()]() {
float const r = 0.5f + 0.5f * dist(gen);
return uint8_t(r * 255.0f);
});
driver.update3DImage(mStarburstTexture,
0, 0, 0, 0, 256, 1, 1,
std::move(dataStarburst));
driver.update3DImage(mStarburstTexture,
0, 0, 0, 0, 256, 1, 1,
std::move(dataStarburst));
}
}
void PostProcessManager::terminate(DriverApi& driver) noexcept {
+7 -4
View File
@@ -152,7 +152,11 @@ RenderPass::RenderPass(FEngine& engine, RenderPassBuilder const& builder) noexce
sortCommands(builder.mArena);
if (engine.isAutomaticInstancingEnabled()) {
instanceify(engine, builder.mArena);
uint32_t stereoscopicEyeCount = 1;
if (builder.mFlags & IS_INSTANCED_STEREOSCOPIC) {
stereoscopicEyeCount *= engine.getConfig().stereoscopicEyeCount;
}
instanceify(engine, builder.mArena, stereoscopicEyeCount);
}
}
@@ -279,7 +283,7 @@ void RenderPass::execute(RenderPass const& pass,
driver.endRenderPass();
}
void RenderPass::instanceify(FEngine& engine, Arena& arena) noexcept {
void RenderPass::instanceify(FEngine& engine, Arena& arena, int32_t eyeCount) noexcept {
SYSTRACE_NAME("instanceify");
// instanceify works by scanning the **sorted** command stream, looking for repeat draw
@@ -362,7 +366,7 @@ void RenderPass::instanceify(FEngine& engine, Arena& arena) noexcept {
}
// make the first command instanced
curr[0].info.instanceCount = instanceCount;
curr[0].info.instanceCount = instanceCount * eyeCount;
curr[0].info.index = instancedPrimitiveOffset;
curr[0].info.boh = mInstancedUboHandle;
@@ -653,7 +657,6 @@ RenderPass::Command* RenderPass::generateCommandsImpl(RenderPass::CommandTypeFla
cmd.info.boh = soaInstanceInfo[i].handle;
} else {
// with no- or user- instancing, we can only know after instanceify()
assert_invariant(cmd.info.instanceCount <= 1);
cmd.info.boh = renderablesUbo;
}
+1 -1
View File
@@ -413,7 +413,7 @@ private:
void sortCommands(Arena& arena) noexcept;
// instanceify commands then trims sentinels
void instanceify(FEngine& engine, Arena& arena) noexcept;
void instanceify(FEngine& engine, Arena& arena, int32_t eyeCount) noexcept;
// We choose the command count per job to minimize JobSystem overhead.
// On a Pixel 4, 2048 commands is about half a millisecond of processing.
+4 -2
View File
@@ -102,7 +102,8 @@ Engine* FEngine::create(Engine::Builder const& builder) {
.handleArenaSize = instance->getRequestedDriverHandleArenaSize(),
.textureUseAfterFreePoolSize = instance->getConfig().textureUseAfterFreePoolSize,
.disableParallelShaderCompile = instance->getConfig().disableParallelShaderCompile,
.disableHandleUseAfterFreeCheck = instance->getConfig().disableHandleUseAfterFreeCheck
.disableHandleUseAfterFreeCheck = instance->getConfig().disableHandleUseAfterFreeCheck,
.forceGLES2Context = instance->getConfig().forceGLES2Context
};
instance->mDriver = platform->createDriver(sharedContext, driverConfig);
@@ -673,7 +674,8 @@ int FEngine::loop() {
.handleArenaSize = getRequestedDriverHandleArenaSize(),
.textureUseAfterFreePoolSize = mConfig.textureUseAfterFreePoolSize,
.disableParallelShaderCompile = mConfig.disableParallelShaderCompile,
.disableHandleUseAfterFreeCheck = mConfig.disableHandleUseAfterFreeCheck
.disableHandleUseAfterFreeCheck = mConfig.disableHandleUseAfterFreeCheck,
.forceGLES2Context = mConfig.forceGLES2Context
};
mDriver = mPlatform->createDriver(mSharedGLContext, driverConfig);
+4
View File
@@ -246,6 +246,10 @@ public:
case Backend::VULKAN:
return { backend::ShaderLanguage::SPIRV };
case Backend::METAL:
const auto& lang = mConfig.preferredShaderLanguage;
if (lang == Config::ShaderLanguage::MSL) {
return { backend::ShaderLanguage::MSL, backend::ShaderLanguage::METAL_LIBRARY };
}
return { backend::ShaderLanguage::METAL_LIBRARY, backend::ShaderLanguage::MSL };
}
}
+46 -6
View File
@@ -25,6 +25,7 @@
#include <private/filament/EngineEnums.h>
#include <private/filament/SamplerInterfaceBlock.h>
#include <private/filament/BufferInterfaceBlock.h>
#include <private/filament/PushConstantInfo.h>
#include <private/filament/Variant.h>
#include <filament/Material.h>
@@ -57,10 +58,9 @@
#include <array>
#include <iterator>
#include <memory>
#include <mutex>
#include <new>
#include <optional>
#include <sstream>
#include <string>
#include <string_view>
#include <unordered_map>
#include <utility>
@@ -83,18 +83,18 @@ static std::unique_ptr<MaterialParser> createParser(Backend backend,
MaterialParser::ParseResult const materialResult = materialParser->parse();
if (UTILS_UNLIKELY(materialResult == MaterialParser::ParseResult::ERROR_MISSING_BACKEND)) {
std::stringstream languageNames;
std::string languageNames;
for (auto it = languages.begin(); it != languages.end(); ++it) {
languageNames << shaderLanguageToString(*it);
languageNames.append(shaderLanguageToString(*it));
if (std::next(it) != languages.end()) {
languageNames << ", ";
languageNames.append(", ");
}
}
ASSERT_PRECONDITION(materialResult != MaterialParser::ParseResult::ERROR_MISSING_BACKEND,
"the material was not built for any of the %s backend's supported shader "
"languages (%s)\n",
backendToString(backend), languageNames.str().c_str());
backendToString(backend), languageNames.c_str());
}
if (backend == Backend::NOOP) {
@@ -298,6 +298,7 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder,
processBlendingMode(parser);
processSpecializationConstants(engine, builder, parser);
processPushConstants(engine, parser);
processDepthVariants(engine, parser);
// we can only initialize the default instance once we're initialized ourselves
@@ -576,6 +577,9 @@ Program FMaterial::getProgramWithVariants(
program.specializationConstants(mSpecializationConstants);
program.pushConstants(ShaderStage::VERTEX, mPushConstants[(uint8_t) ShaderStage::VERTEX]);
program.pushConstants(ShaderStage::FRAGMENT, mPushConstants[(uint8_t) ShaderStage::FRAGMENT]);
program.cacheId(utils::hash::combine(size_t(mCacheId), variant.key));
return program;
@@ -928,6 +932,42 @@ void FMaterial::processSpecializationConstants(FEngine& engine, Material::Builde
}
}
void FMaterial::processPushConstants(FEngine& engine, MaterialParser const* parser) {
utils::FixedCapacityVector<backend::Program::PushConstant>& vertexConstants =
mPushConstants[(uint8_t) ShaderStage::VERTEX];
utils::FixedCapacityVector<backend::Program::PushConstant>& fragmentConstants =
mPushConstants[(uint8_t) ShaderStage::FRAGMENT];
CString structVarName;
utils::FixedCapacityVector<MaterialPushConstant> pushConstants;
parser->getPushConstants(&structVarName, &pushConstants);
vertexConstants.reserve(pushConstants.size());
fragmentConstants.reserve(pushConstants.size());
constexpr size_t MAX_NAME_LEN = 60;
char buf[MAX_NAME_LEN];
uint8_t vertexCount = 0, fragmentCount = 0;
std::for_each(pushConstants.cbegin(), pushConstants.cend(),
[&](MaterialPushConstant const& constant) {
snprintf(buf, sizeof(buf), "%s.%s", structVarName.c_str(), constant.name.c_str());
switch (constant.stage) {
case ShaderStage::VERTEX:
vertexConstants.push_back({utils::CString(buf), constant.type});
vertexCount++;
break;
case ShaderStage::FRAGMENT:
fragmentConstants.push_back({utils::CString(buf), constant.type});
fragmentCount++;
break;
case ShaderStage::COMPUTE:
break;
}
});
}
void FMaterial::processDepthVariants(FEngine& engine, MaterialParser const* const parser) {
parser->hasCustomDepthShader(&mHasCustomDepthShader);
+7
View File
@@ -253,6 +253,8 @@ private:
void processSpecializationConstants(FEngine& engine, Material::Builder const& builder,
MaterialParser const* parser);
void processPushConstants(FEngine& engine, MaterialParser const* parser);
void processDepthVariants(FEngine& engine, MaterialParser const* parser);
void createAndCacheProgram(backend::Program&& p, Variant variant) const noexcept;
@@ -318,6 +320,11 @@ private:
// current specialization constants for the HwProgram
utils::FixedCapacityVector<backend::Program::SpecializationConstant> mSpecializationConstants;
// current push constants for the HwProgram
std::array<utils::FixedCapacityVector<backend::Program::PushConstant>,
backend::Program::SHADER_TYPE_COUNT>
mPushConstants;
#if FILAMENT_ENABLE_MATDBG
matdbg::MaterialKey mDebuggerId;
mutable utils::Mutex mActiveProgramsLock;
+8 -4
View File
@@ -719,10 +719,6 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
RenderPass::RenderFlags renderFlags = 0;
if (view.hasShadowing()) renderFlags |= RenderPass::HAS_SHADOWING;
if (view.isFrontFaceWindingInverted()) renderFlags |= RenderPass::HAS_INVERSE_FRONT_FACES;
if (view.hasStereo() &&
engine.getConfig().stereoscopicType == backend::StereoscopicType::INSTANCED) {
renderFlags |= RenderPass::IS_INSTANCED_STEREOSCOPIC;
}
RenderPassBuilder passBuilder(commandArena);
passBuilder.renderFlags(renderFlags);
@@ -998,6 +994,14 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
passBuilder.commandTypeFlags(RenderPass::CommandTypeFlags::COLOR);
// RenderPass::IS_INSTANCED_STEREOSCOPIC only applies to the color pass
if (view.hasStereo() &&
engine.getConfig().stereoscopicType == backend::StereoscopicType::INSTANCED) {
renderFlags |= RenderPass::IS_INSTANCED_STEREOSCOPIC;
passBuilder.renderFlags(renderFlags);
}
RenderPass const pass{ passBuilder.build(engine) };
FrameGraphTexture::Descriptor colorBufferDesc = {
-5
View File
@@ -439,11 +439,6 @@ void FScene::updateUBOs(
delete weakShared;
}, weakShared
}, 0);
// update skybox
if (mSkybox) {
mSkybox->commit(driver);
}
}
void FScene::terminate(FEngine&) {
+12 -9
View File
@@ -17,21 +17,28 @@
#include "details/Skybox.h"
#include "details/Engine.h"
#include "details/Texture.h"
#include "details/VertexBuffer.h"
#include "details/IndexBuffer.h"
#include "details/IndirectLight.h"
#include "details/Material.h"
#include "details/MaterialInstance.h"
#include "details/Texture.h"
#include "details/VertexBuffer.h"
#include "FilamentAPI-impl.h"
#include <filament/Material.h>
#include <filament/MaterialInstance.h>
#include <filament/RenderableManager.h>
#include <filament/TextureSampler.h>
#include <filament/Skybox.h>
#include <backend/DriverEnums.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/Panic.h>
#include <filament/Skybox.h>
#include <math/vec4.h>
#include <stdint.h>
#include "generated/resources/materials.h"
@@ -164,8 +171,4 @@ void FSkybox::setColor(math::float4 color) noexcept {
mSkyboxMaterialInstance->setParameter("color", color);
}
void FSkybox::commit(backend::DriverApi& driver) noexcept {
mSkyboxMaterialInstance->commit(driver);
}
} // namespace filament
-3
View File
@@ -53,9 +53,6 @@ public:
void setColor(math::float4 color) noexcept;
// commits UBOs
void commit(backend::DriverApi& driver) noexcept;
private:
// we don't own these
FTexture const* mSkyboxTexture = nullptr;
+17
View File
@@ -179,6 +179,23 @@ TEST(FilamentTest, SkinningMath) {
}
}
TEST(FilamentTest, TransformManagerSimple) {
filament::FTransformManager tcm;
EntityManager& em = EntityManager::get();
Entity root = em.create();
tcm.create(root);
auto ti = tcm.getInstance(root);
auto t = mat4f::translation(float3{ 1, 2, 3 });
auto prev = tcm.getWorldTransform(ti);
tcm.setTransform(ti, t);
auto updated = tcm.getWorldTransform(ti);
EXPECT_NE(prev, t);
EXPECT_EQ(updated, t);
}
TEST(FilamentTest, TransformManager) {
filament::FTransformManager tcm;
tcm.setAccurateTranslationsEnabled(true);
+2 -2
View File
@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.51.6"
spec.version = "1.51.8"
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.51.6/filament-v1.51.6-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.51.8/filament-v1.51.8-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {
@@ -53,6 +53,7 @@ enum UTILS_PUBLIC ChunkType : uint64_t {
MaterialAttributeInfo = charTo64bitNum("MAT_ATTR"),
MaterialProperties = charTo64bitNum("MAT_PROP"),
MaterialConstants = charTo64bitNum("MAT_CONS"),
MaterialPushConstants = charTo64bitNum("MAT_PCON"),
MaterialName = charTo64bitNum("MAT_NAME"),
MaterialVersion = charTo64bitNum("MAT_VERS"),
@@ -20,6 +20,7 @@
#include <backend/DriverEnums.h>
#include <utils/BitmaskEnum.h>
#include <utils/FixedCapacityVector.h>
#include <stddef.h>
#include <stdint.h>
@@ -71,6 +72,10 @@ enum class ReservedSpecializationConstants : uint8_t {
CONFIG_STEREO_EYE_COUNT = 8, // don't change (hardcoded in ShaderCompilerService.cpp)
};
enum class PushConstantIds {
MORPHING_BUFFER_OFFSET = 0,
};
// This value is limited by UBO size, ES3.0 only guarantees 16 KiB.
// It's also limited by the Froxelizer's record buffer data type (uint8_t).
constexpr size_t CONFIG_MAX_LIGHT_COUNT = 256;
@@ -0,0 +1,43 @@
/*
* Copyright (C) 2023 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_FILAMENT_PUSHCONSTANTINFO_H
#define TNT_FILAMENT_PUSHCONSTANTINFO_H
#include <backend/DriverEnums.h>
#include <utils/CString.h>
namespace filament {
struct MaterialPushConstant {
using ShaderStage = backend::ShaderStage;
using ConstantType = backend::ConstantType;
utils::CString name;
ConstantType type;
ShaderStage stage;
MaterialPushConstant() = default;
MaterialPushConstant(const char* name, ConstantType type, ShaderStage stage)
: name(name),
type(type),
stage(stage) {}
};
}
#endif // TNT_FILAMENT_PUSHCONSTANTINFO_H
+5
View File
@@ -33,6 +33,11 @@ endif()
set(MATERIAL_SRCS
src/materials/uiBlit.mat)
if (ANDROID)
list(APPEND MATERIAL_SRCS
src/materials/uiBlitExternal.mat)
endif()
file(MAKE_DIRECTORY ${MATERIAL_DIR})
foreach (mat_src ${MATERIAL_SRCS})
+4 -2
View File
@@ -84,12 +84,14 @@ public:
filament::View* mView; // The view is owned by the client.
filament::Scene* mScene;
filament::Material* mMaterial2d = nullptr;
std::vector<filament::MaterialInstance*> mMaterial2dInstances;
#ifdef __ANDROID__
filament::Material* mMaterialExternal = nullptr;
std::vector<filament::MaterialInstance*> mMaterialExternalInstances;
#endif
filament::Camera* mCamera = nullptr;
std::vector<filament::VertexBuffer*> mVertexBuffers;
std::vector<filament::IndexBuffer*> mIndexBuffers;
std::vector<filament::MaterialInstance*> mMaterial2dInstances;
std::vector<filament::MaterialInstance*> mMaterialExternalInstances;
utils::Entity mRenderable;
utils::Entity mCameraEntity;
filament::Texture* mTexture = nullptr;
+13 -11
View File
@@ -62,12 +62,12 @@ ImGuiHelper::ImGuiHelper(Engine* engine, filament::View* view, const Path& fontP
// Create a simple alpha-blended 2D blitting material.
mMaterial2d = Material::Builder()
.package(FILAGUI_RESOURCES_UIBLIT_DATA, FILAGUI_RESOURCES_UIBLIT_SIZE)
.constant("external", false)
.build(*engine);
#ifdef __ANDROID__
mMaterialExternal = Material::Builder()
.package(FILAGUI_RESOURCES_UIBLIT_DATA, FILAGUI_RESOURCES_UIBLIT_SIZE)
.constant("external", true)
.package(FILAGUI_RESOURCES_UIBLITEXTERNAL_DATA, FILAGUI_RESOURCES_UIBLITEXTERNAL_SIZE)
.build(*engine);
#endif
// If the given font path is invalid, ImGui will silently fall back to proggy, which is a
// tiny "pixel art" texture that is compiled into the library.
@@ -79,7 +79,7 @@ ImGuiHelper::ImGuiHelper(Engine* engine, filament::View* view, const Path& fontP
// For proggy, switch to NEAREST for pixel-perfect text.
if (!fontPath.isFile() && !imGuiContext) {
mSampler = TextureSampler(MinFilter::NEAREST, MagFilter::NEAREST);
mMaterial2d->setDefaultParameter("albedo2d", mTexture, mSampler);
mMaterial2d->setDefaultParameter("albedo", mTexture, mSampler);
}
utils::EntityManager& em = utils::EntityManager::get();
@@ -122,7 +122,7 @@ void ImGuiHelper::createAtlasTexture(Engine* engine) {
mTexture->setImage(*engine, 0, std::move(pb));
mSampler = TextureSampler(MinFilter::LINEAR, MagFilter::LINEAR);
mMaterial2d->setDefaultParameter("albedo2d", mTexture, mSampler);
mMaterial2d->setDefaultParameter("albedo", mTexture, mSampler);
}
ImGuiHelper::~ImGuiHelper() {
@@ -134,10 +134,12 @@ ImGuiHelper::~ImGuiHelper() {
mEngine->destroy(mi);
}
mEngine->destroy(mMaterial2d);
#ifdef __ANDROID__
for (auto& mi : mMaterialExternalInstances) {
mEngine->destroy(mi);
}
mEngine->destroy(mMaterialExternal);
#endif
mEngine->destroy(mTexture);
for (auto& vb : mVertexBuffers) {
mEngine->destroy(vb);
@@ -227,19 +229,19 @@ void ImGuiHelper::processImGuiCommands(ImDrawData* commands, const ImGuiIO& io)
pcmd.UserCallback(cmds, &pcmd);
} else {
auto texture = (Texture const*)pcmd.TextureId;
const char* uniformName;
MaterialInstance* materialInstance;
#ifdef __ANDROID__
if (texture && texture->getTarget() == Texture::Sampler::SAMPLER_EXTERNAL) {
if (materialExternalIndex == mMaterialExternalInstances.size()) {
mMaterialExternalInstances.push_back(mMaterialExternal->createInstance());
}
uniformName = "albedoExternal";
materialInstance = mMaterialExternalInstances[materialExternalIndex++];
} else {
} else
#endif
{
if (material2dIndex == mMaterial2dInstances.size()) {
mMaterial2dInstances.push_back(mMaterial2d->createInstance());
}
uniformName = "albedo2d";
materialInstance = mMaterial2dInstances[material2dIndex++];
}
materialInstance->setScissor(
@@ -249,9 +251,9 @@ void ImGuiHelper::processImGuiCommands(ImDrawData* commands, const ImGuiIO& io)
(uint16_t) (pcmd.ClipRect.w - pcmd.ClipRect.y));
if (texture) {
TextureSampler sampler(MinFilter::LINEAR, MagFilter::LINEAR);
materialInstance->setParameter(uniformName, texture, sampler);
materialInstance->setParameter("albedo", texture, sampler);
} else {
materialInstance->setParameter(uniformName, mTexture, mSampler);
materialInstance->setParameter("albedo", mTexture, mSampler);
}
rbuilder
.geometry(primIndex, RenderableManager::PrimitiveType::TRIANGLES,
+2 -14
View File
@@ -1,19 +1,9 @@
material {
name : uiBlit,
constants : [
{
name : external,
type : bool
}
],
parameters : [
{
type : samplerExternal,
name : albedoExternal
},
{
type : sampler2d,
name : albedo2d
name : albedo
}
],
requires : [
@@ -32,9 +22,7 @@ fragment {
prepareMaterial(material);
vec2 uv = getUV0();
uv.y = 1.0 - uv.y;
vec4 albedo = materialConstants_external
? texture2D(materialParams_albedoExternal, uv)
: texture2D(materialParams_albedo2d, uv);
vec4 albedo = texture2D(materialParams_albedo, uv);
material.baseColor = getColor() * albedo;
material.baseColor.rgb *= material.baseColor.a;
}
@@ -0,0 +1,29 @@
material {
name : uiBlitExternal,
parameters : [
{
type : samplerExternal,
name : albedo
}
],
requires : [
uv0,
color
],
shadingModel : unlit,
culling : none,
depthCulling: false,
blending : transparent,
featureLevel : 0
}
fragment {
void material(inout MaterialInputs material) {
prepareMaterial(material);
vec2 uv = getUV0();
uv.y = 1.0 - uv.y;
vec4 albedo = texture2D(materialParams_albedo, uv);
material.baseColor = getColor() * albedo;
material.baseColor.rgb *= material.baseColor.a;
}
}
+2 -1
View File
@@ -23,7 +23,8 @@ set(COMMON_PRIVATE_HDRS
src/eiff/MaterialInterfaceBlockChunk.h
src/eiff/ShaderEntry.h
src/eiff/SimpleFieldChunk.h
src/Includes.h)
src/Includes.h
src/PushConstantDefinitions.h)
set(COMMON_SRCS
src/eiff/Chunk.cpp
@@ -245,6 +245,7 @@ public:
using CullingMode = filament::backend::CullingMode;
using FeatureLevel = filament::backend::FeatureLevel;
using StereoscopicType = filament::backend::StereoscopicType;
using ShaderStage = filament::backend::ShaderStage;
enum class VariableQualifier : uint8_t {
OUT
@@ -692,6 +693,12 @@ public:
} defaultValue;
};
struct PushConstant {
utils::CString name;
ConstantType type;
ShaderStage stage;
};
static constexpr size_t MATERIAL_PROPERTIES_COUNT = filament::MATERIAL_PROPERTIES_COUNT;
using Property = filament::Property;
@@ -720,6 +727,7 @@ public:
using SubpassList = Parameter[MAX_SUBPASS_COUNT];
using BufferList = std::vector<std::unique_ptr<filament::BufferInterfaceBlock>>;
using ConstantList = std::vector<Constant>;
using PushConstantList = std::vector<PushConstant>;
// returns the number of parameters declared in this material
uint8_t getParameterCount() const noexcept { return mParameterCount; }
@@ -763,6 +771,10 @@ private:
void prepareToBuild(MaterialInfo& info) noexcept;
// Initialize internal push constants that will both be written to the shaders and material
// chunks (like user-defined spec constants).
void initPushConstants() noexcept;
// Return true if the shader is syntactically and semantically valid.
// This method finds all the properties defined in the fragment and
// vertex shaders of the material.
@@ -829,6 +841,7 @@ private:
PropertyList mProperties;
ParameterList mParameters;
ConstantList mConstants;
PushConstantList mPushConstants;
SubpassList mSubpasses;
VariableList mVariables;
OutputList mOutputs;
+26 -2
View File
@@ -20,6 +20,7 @@
#include "Includes.h"
#include "MaterialVariants.h"
#include "PushConstantDefinitions.h"
#include "shaders/SibGenerator.h"
#include "shaders/UibGenerator.h"
@@ -173,6 +174,8 @@ void MaterialBuilderBase::prepare(bool vulkanSemantics,
MaterialBuilder::MaterialBuilder() : mMaterialName("Unnamed") {
std::fill_n(mProperties, MATERIAL_PROPERTIES_COUNT, false);
mShaderModels.reset();
initPushConstants();
}
MaterialBuilder::~MaterialBuilder() = default;
@@ -660,6 +663,19 @@ void MaterialBuilder::prepareToBuild(MaterialInfo& info) noexcept {
info.userMaterialHasCustomDepth = false;
}
void MaterialBuilder::initPushConstants() noexcept {
mPushConstants.reserve(PUSH_CONSTANTS.size());
mPushConstants.resize(PUSH_CONSTANTS.size());
std::transform(PUSH_CONSTANTS.cbegin(), PUSH_CONSTANTS.cend(), mPushConstants.begin(),
[](filament::MaterialPushConstant const& inConstant) -> PushConstant {
return {
.name = inConstant.name,
.type = inConstant.type,
.stage = inConstant.stage,
};
});
}
bool MaterialBuilder::findProperties(backend::ShaderStage type,
MaterialBuilder::PropertyList& allProperties,
CodeGenParams const& semanticCodeGenParams) noexcept {
@@ -828,7 +844,7 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
BlobDictionary spirvDictionary;
// End: must be protected by lock
ShaderGenerator sg(mProperties, mVariables, mOutputs, mDefines, mConstants,
ShaderGenerator sg(mProperties, mVariables, mOutputs, mDefines, mConstants, mPushConstants,
mMaterialFragmentCode.getResolved(), mMaterialFragmentCode.getLineOffset(),
mMaterialVertexCode.getResolved(), mMaterialVertexCode.getLineOffset(),
mMaterialDomain);
@@ -1358,7 +1374,7 @@ bool MaterialBuilder::needsStandardDepthProgram() const noexcept {
std::string MaterialBuilder::peek(backend::ShaderStage stage,
const CodeGenParams& params, const PropertyList& properties) noexcept {
ShaderGenerator sg(properties, mVariables, mOutputs, mDefines, mConstants,
ShaderGenerator sg(properties, mVariables, mOutputs, mDefines, mConstants, mPushConstants,
mMaterialFragmentCode.getResolved(), mMaterialFragmentCode.getLineOffset(),
mMaterialVertexCode.getResolved(), mMaterialVertexCode.getLineOffset(),
mMaterialDomain);
@@ -1512,6 +1528,14 @@ void MaterialBuilder::writeCommonChunks(ChunkContainer& container, MaterialInfo&
[](Constant const& c) { return MaterialConstant(c.name.c_str(), c.type); });
container.push<MaterialConstantParametersChunk>(std::move(constantsEntry));
utils::FixedCapacityVector<MaterialPushConstant> pushConstantsEntry(mPushConstants.size());
std::transform(mPushConstants.begin(), mPushConstants.end(), pushConstantsEntry.begin(),
[](PushConstant const& c) {
return MaterialPushConstant(c.name.c_str(), c.type, c.stage);
});
container.push<MaterialPushConstantParametersChunk>(
utils::CString(PUSH_CONSTANT_STRUCT_VAR_NAME), std::move(pushConstantsEntry));
// TODO: should we write the SSBO info? this would only be needed if we wanted to provide
// an interface to set [get?] values in the buffer. But we can do that easily
// with a c-struct (what about kotlin/java?). tbd.
@@ -0,0 +1,44 @@
/*
* 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.
*/
#ifndef TNT_FILAMAT_PUSH_CONSTANT_DEFINTITIONS_H
#define TNT_FILAMAT_PUSH_CONSTANT_DEFINTITIONS_H
#include <private/filament/EngineEnums.h>
#include <private/filament/PushConstantInfo.h>
#include <utils/FixedCapacityVector.h>
#include <tuple>
namespace filamat {
constexpr char PUSH_CONSTANT_STRUCT_VAR_NAME[] = "pushConstants";
utils::FixedCapacityVector<filament::MaterialPushConstant> const PUSH_CONSTANTS = {
{
"morphingBufferOffset",
filament::backend::ConstantType::INT,
filament::backend::ShaderStage::VERTEX,
},
};
// Make sure that the indices defined in filabridge match the actual array indices defined here.
static_assert(static_cast<uint8_t>(filament::PushConstantIds::MORPHING_BUFFER_OFFSET) == 0u);
}// namespace filamat
#endif
@@ -22,6 +22,7 @@
#include <private/filament/BufferInterfaceBlock.h>
#include <private/filament/SubpassInfo.h>
#include <private/filament/ConstantInfo.h>
#include <private/filament/PushConstantInfo.h>
#include <utility>
@@ -104,6 +105,24 @@ void MaterialConstantParametersChunk::flatten(Flattener& f) {
// ------------------------------------------------------------------------------------------------
MaterialPushConstantParametersChunk::MaterialPushConstantParametersChunk(
CString const& structVarName, utils::FixedCapacityVector<MaterialPushConstant> constants)
: Chunk(ChunkType::MaterialPushConstants),
mStructVarName(structVarName),
mConstants(std::move(constants)) {}
void MaterialPushConstantParametersChunk::flatten(Flattener& f) {
f.writeString(mStructVarName.c_str());
f.writeUint64(mConstants.size());
for (const auto& constant: mConstants) {
f.writeString(constant.name.c_str());
f.writeUint8(static_cast<uint8_t>(constant.type));
f.writeUint8(static_cast<uint8_t>(constant.stage));
}
}
// ------------------------------------------------------------------------------------------------
MaterialUniformBlockBindingsChunk::MaterialUniformBlockBindingsChunk(
utils::FixedCapacityVector<std::pair<std::string_view, filament::UniformBindingPoints>> list)
: Chunk(ChunkType::MaterialUniformBindings),
@@ -31,6 +31,7 @@ class SamplerInterfaceBlock;
class BufferInterfaceBlock;
struct SubpassInfo;
struct MaterialConstant;
struct MaterialPushConstant;
} // namespace filament
namespace filamat {
@@ -88,6 +89,21 @@ private:
// ------------------------------------------------------------------------------------------------
class MaterialPushConstantParametersChunk final : public Chunk {
public:
explicit MaterialPushConstantParametersChunk(utils::CString const& structVarName,
utils::FixedCapacityVector<filament::MaterialPushConstant> constants);
~MaterialPushConstantParametersChunk() final = default;
private:
void flatten(Flattener&) final;
utils::CString mStructVarName;
utils::FixedCapacityVector<filament::MaterialPushConstant> mConstants;
};
// ------------------------------------------------------------------------------------------------
class MaterialUniformBlockBindingsChunk final : public Chunk {
using Container = utils::FixedCapacityVector<
std::pair<std::string_view, filament::UniformBindingPoints>>;
+41 -2
View File
@@ -17,6 +17,7 @@
#include "CodeGenerator.h"
#include "MaterialInfo.h"
#include "../PushConstantDefinitions.h"
#include "generated/shaders.h"
@@ -454,8 +455,8 @@ io::sstream& CodeGenerator::generateVariable(io::sstream& out, ShaderStage stage
}
io::sstream& CodeGenerator::generateShaderInputs(io::sstream& out, ShaderStage type,
const AttributeBitset& attributes, Interpolation interpolation) const {
const AttributeBitset& attributes, Interpolation interpolation,
MaterialBuilder::PushConstantList const& pushConstants) const {
auto const& attributeDatabase = MaterialBuilder::getAttributeDatabase();
const char* shading = getInterpolationQualifier(interpolation);
@@ -479,6 +480,9 @@ io::sstream& CodeGenerator::generateShaderInputs(io::sstream& out, ShaderStage t
}
out << getTypeName(attribute.type) << " " << attribute.getAttributeName() << ";\n";
});
out << "\n";
generatePushConstants(out, pushConstants, attributes.size());
}
out << "\n";
@@ -906,6 +910,41 @@ utils::io::sstream& CodeGenerator::generateSpecializationConstant(utils::io::sst
return out;
}
utils::io::sstream& CodeGenerator::generatePushConstants(utils::io::sstream& out,
MaterialBuilder::PushConstantList const& pushConstants, size_t const layoutLocation) const {
static constexpr char const* STRUCT_NAME = "Constants";
bool const outputSpirv =
mTargetLanguage == TargetLanguage::SPIRV && mTargetApi != TargetApi::OPENGL;
auto const getType = [](ConstantType const& type) {
switch (type) {
case ConstantType::BOOL:
return "bool";
case ConstantType::INT:
return "int";
case ConstantType::FLOAT:
return "float";
}
};
if (outputSpirv) {
out << "layout(push_constant) uniform " << STRUCT_NAME << " {\n ";
} else {
out << "struct " << STRUCT_NAME << " {\n";
}
for (auto const& constant: pushConstants) {
out << getType(constant.type) << " " << constant.name.c_str() << ";\n";
}
if (outputSpirv) {
out << "} " << PUSH_CONSTANT_STRUCT_VAR_NAME << ";\n";
} else {
out << "};\n";
out << "LAYOUT_LOCATION(" << static_cast<int>(layoutLocation) << ") uniform " << STRUCT_NAME
<< " " << PUSH_CONSTANT_STRUCT_VAR_NAME << ";\n";
}
return out;
}
io::sstream& CodeGenerator::generateMaterialProperty(io::sstream& out,
MaterialBuilder::Property property, bool isSet) {
+6 -1
View File
@@ -107,7 +107,8 @@ public:
// generate declarations for non-custom "in" variables
utils::io::sstream& generateShaderInputs(utils::io::sstream& out, ShaderStage type,
const filament::AttributeBitset& attributes, filament::Interpolation interpolation) const;
const filament::AttributeBitset& attributes, filament::Interpolation interpolation,
MaterialBuilder::PushConstantList const& pushConstants) const;
static utils::io::sstream& generatePostProcessInputs(utils::io::sstream& out, ShaderStage type);
// generate declarations for custom output variables
@@ -156,6 +157,10 @@ public:
utils::io::sstream& generateSpecializationConstant(utils::io::sstream& out,
const char* name, uint32_t id, std::variant<int, float, bool> value) const;
utils::io::sstream& generatePushConstants(utils::io::sstream& out,
MaterialBuilder::PushConstantList const& pushConstants,
size_t const layoutLocation) const;
static utils::io::sstream& generatePostProcessGetters(utils::io::sstream& out, ShaderStage type);
static utils::io::sstream& generateGetters(utils::io::sstream& out, ShaderStage stage);
static utils::io::sstream& generateParameters(utils::io::sstream& out, ShaderStage type);
+19 -4
View File
@@ -304,6 +304,7 @@ ShaderGenerator::ShaderGenerator(
MaterialBuilder::OutputList const& outputs,
MaterialBuilder::PreprocessorDefineList const& defines,
MaterialBuilder::ConstantList const& constants,
MaterialBuilder::PushConstantList const& pushConstants,
CString const& materialCode, size_t lineOffset,
CString const& materialVertexCode, size_t vertexLineOffset,
MaterialBuilder::MaterialDomain materialDomain) noexcept {
@@ -325,6 +326,7 @@ ShaderGenerator::ShaderGenerator(
mMaterialDomain = materialDomain;
mDefines = defines;
mConstants = constants;
mPushConstants = pushConstants;
if (mMaterialFragmentCode.empty()) {
if (mMaterialDomain == MaterialBuilder::MaterialDomain::SURFACE) {
@@ -418,7 +420,15 @@ std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel,
attributes.set(VertexAttribute::MORPH_TANGENTS_3);
}
}
cg.generateShaderInputs(vs, ShaderStage::VERTEX, attributes, interpolation);
MaterialBuilder::PushConstantList vertexPushConstants;
std::copy_if(mPushConstants.begin(), mPushConstants.end(),
std::back_insert_iterator<MaterialBuilder::PushConstantList>(vertexPushConstants),
[](MaterialBuilder::PushConstant const& constant) {
return constant.stage == ShaderStage::VERTEX;
});
cg.generateShaderInputs(vs, ShaderStage::VERTEX, attributes, interpolation,
vertexPushConstants);
CodeGenerator::generateCommonTypes(vs, ShaderStage::VERTEX);
@@ -519,9 +529,14 @@ std::string ShaderGenerator::createFragmentProgram(ShaderModel shaderModel,
generateSurfaceMaterialVariantProperties(fs, mProperties, mDefines);
cg.generateShaderInputs(fs, ShaderStage::FRAGMENT,
material.requiredAttributes, interpolation);
MaterialBuilder::PushConstantList fragmentPushConstants;
std::copy_if(mPushConstants.begin(), mPushConstants.end(),
std::back_insert_iterator<MaterialBuilder::PushConstantList>(fragmentPushConstants),
[](MaterialBuilder::PushConstant const& constant) {
return constant.stage == ShaderStage::FRAGMENT;
});
cg.generateShaderInputs(fs, ShaderStage::FRAGMENT, material.requiredAttributes, interpolation,
fragmentPushConstants);
CodeGenerator::generateCommonTypes(fs, ShaderStage::FRAGMENT);
@@ -43,6 +43,7 @@ public:
MaterialBuilder::OutputList const& outputs,
MaterialBuilder::PreprocessorDefineList const& defines,
MaterialBuilder::ConstantList const& constants,
MaterialBuilder::PushConstantList const& pushConstants,
utils::CString const& materialCode,
size_t lineOffset,
utils::CString const& materialVertexCode,
@@ -125,6 +126,7 @@ private:
MaterialBuilder::MaterialDomain mMaterialDomain;
MaterialBuilder::PreprocessorDefineList mDefines;
MaterialBuilder::ConstantList mConstants;
MaterialBuilder::PushConstantList mPushConstants;
utils::CString mMaterialFragmentCode; // fragment or compute code
utils::CString mMaterialVertexCode;
size_t mMaterialLineOffset;
+60
View File
@@ -27,17 +27,22 @@
#include <filament/View.h>
#include <utils/EntityManager.h>
#include <utils/Path.h>
#include <getopt/getopt.h>
#include <filamentapp/Config.h>
#include <filamentapp/FilamentApp.h>
#include <cmath>
#include <iostream>
#include "generated/resources/resources.h"
using namespace filament;
using utils::Entity;
using utils::EntityManager;
using utils::Path;
using namespace filament::math;
struct App {
@@ -83,10 +88,65 @@ static const short4 targets_tan[9] = {
static constexpr uint16_t TRIANGLE_INDICES[3] = { 0, 1, 2 };
static void printUsage(char* name) {
std::string exec_name(Path(name).getName());
std::string usage(
"SAMPLE is a command-line tool for testing Filament skinning buffers.\n"
"Usage:\n"
" SAMPLE [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\n"
);
const std::string from("SAMPLE");
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 handleCommandLineArgments(int argc, char* argv[], Config* config) {
static constexpr const char* OPTSTR = "ha:";
static const struct option OPTIONS[] = {
{ "help", no_argument, nullptr, 'h' },
{ "api", required_argument, nullptr, 'a' },
{ nullptr, 0, nullptr, 0 } // termination of the option list
};
int opt;
int option_index = 0;
while ((opt = getopt_long(argc, argv, OPTSTR, OPTIONS, &option_index)) >= 0) {
std::string arg(optarg != nullptr ? optarg : "");
switch (opt) {
default:
case 'h':
printUsage(argv[0]);
exit(0);
case 'a':
if (arg == "opengl") {
config->backend = Engine::Backend::OPENGL;
} else if (arg == "vulkan") {
config->backend = Engine::Backend::VULKAN;
} else if (arg == "metal") {
config->backend = Engine::Backend::METAL;
} else {
std::cerr << "Unrecognized backend. Must be 'opengl'|'vulkan'|'metal'."
<< std::endl;
}
break;
}
}
return optind;
}
int main(int argc, char** argv) {
Config config;
config.title = "helloMorphing";
handleCommandLineArgments(argc, argv, &config);
App app;
auto setup = [&app](Engine* engine, View* view, Scene* scene) {
app.skybox = Skybox::Builder().color({0.1, 0.125, 0.25, 1.0}).build(*engine);
+61
View File
@@ -27,17 +27,22 @@
#include <filament/View.h>
#include <utils/EntityManager.h>
#include <utils/Path.h>
#include <filamentapp/Config.h>
#include <filamentapp/FilamentApp.h>
#include <cmath>
#include <iostream>
#include <getopt/getopt.h>
#include "generated/resources/resources.h"
using namespace filament;
using utils::Entity;
using utils::EntityManager;
using utils::Path;
using namespace filament::math;
struct App {
@@ -58,6 +63,60 @@ struct VertexWithBones {
filament::math::float4 weighs;
};
static void printUsage(char* name) {
std::string exec_name(Path(name).getName());
std::string usage(
"SAMPLE is a command-line tool for testing Filament skinning.\n"
"Usage:\n"
" SAMPLE [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\n"
);
const std::string from("SAMPLE");
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 handleCommandLineArgments(int argc, char* argv[], Config* config) {
static constexpr const char* OPTSTR = "ha:";
static const struct option OPTIONS[] = {
{ "help", no_argument, nullptr, 'h' },
{ "api", required_argument, nullptr, 'a' },
{ nullptr, 0, nullptr, 0 } // termination of the option list
};
int opt;
int option_index = 0;
while ((opt = getopt_long(argc, argv, OPTSTR, OPTIONS, &option_index)) >= 0) {
std::string arg(optarg != nullptr ? optarg : "");
switch (opt) {
default:
case 'h':
printUsage(argv[0]);
exit(0);
case 'a':
if (arg == "opengl") {
config->backend = Engine::Backend::OPENGL;
} else if (arg == "vulkan") {
config->backend = Engine::Backend::VULKAN;
} else if (arg == "metal") {
config->backend = Engine::Backend::METAL;
} else {
std::cerr << "Unrecognized backend. Must be 'opengl'|'vulkan'|'metal'."
<< std::endl;
}
break;
}
}
return optind;
}
static const VertexWithBones TRIANGLE_VERTICES_WITHBONES[6] = {
{{1, 0}, 0xffff0000u, {0,1,0,0}, {1.0f,0.f,0.f,0.f}},
{{cos(M_PI * 2 / 3), sin(M_PI * 2 / 3)}, 0xff00ff00u, {0,1,0,0}, {0.f,1.f,0.f,0.f}},
@@ -78,6 +137,8 @@ int main(int argc, char** argv) {
Config config;
config.title = "hello skinning";
handleCommandLineArgments(argc, argv, &config);
App app;
auto setup = [&app](Engine* engine, View* view, Scene* scene) {
app.skybox = Skybox::Builder().color({0.1, 0.125, 0.25, 1.0}).build(*engine);
+60
View File
@@ -27,17 +27,22 @@
#include <filament/View.h>
#include <utils/EntityManager.h>
#include <utils/Path.h>
#include <getopt/getopt.h>
#include <filamentapp/Config.h>
#include <filamentapp/FilamentApp.h>
#include <cmath>
#include <iostream>
#include "generated/resources/resources.h"
using namespace filament;
using utils::Entity;
using utils::EntityManager;
using utils::Path;
using namespace filament::math;
struct App {
@@ -85,10 +90,65 @@ mat4f transforms[] = {math::mat4f(1.f),
mat4f::translation(float3(0, -1, 0)),
mat4f::translation(float3(1, -1, 0))};
static void printUsage(char* name) {
std::string exec_name(Path(name).getName());
std::string usage(
"SAMPLE is a command-line tool for testing Filament skinning buffers.\n"
"Usage:\n"
" SAMPLE [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\n"
);
const std::string from("SAMPLE");
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 handleCommandLineArgments(int argc, char* argv[], Config* config) {
static constexpr const char* OPTSTR = "ha:";
static const struct option OPTIONS[] = {
{ "help", no_argument, nullptr, 'h' },
{ "api", required_argument, nullptr, 'a' },
{ nullptr, 0, nullptr, 0 } // termination of the option list
};
int opt;
int option_index = 0;
while ((opt = getopt_long(argc, argv, OPTSTR, OPTIONS, &option_index)) >= 0) {
std::string arg(optarg != nullptr ? optarg : "");
switch (opt) {
default:
case 'h':
printUsage(argv[0]);
exit(0);
case 'a':
if (arg == "opengl") {
config->backend = Engine::Backend::OPENGL;
} else if (arg == "vulkan") {
config->backend = Engine::Backend::VULKAN;
} else if (arg == "metal") {
config->backend = Engine::Backend::METAL;
} else {
std::cerr << "Unrecognized backend. Must be 'opengl'|'vulkan'|'metal'."
<< std::endl;
}
break;
}
}
return optind;
}
int main(int argc, char** argv) {
Config config;
config.title = "skinning buffer common for two renderables";
handleCommandLineArgments(argc, argv, &config);
App app;
auto setup = [&app](Engine* engine, View* view, Scene* scene) {
app.skybox = Skybox::Builder().color({0.1, 0.125, 0.25, 1.0}).build(*engine);
+61
View File
@@ -27,17 +27,22 @@
#include <filament/View.h>
#include <utils/EntityManager.h>
#include <utils/Path.h>
#include <getopt/getopt.h>
#include <filamentapp/Config.h>
#include <filamentapp/FilamentApp.h>
#include <cmath>
#include <iostream>
#include "generated/resources/resources.h"
using namespace filament;
using utils::Entity;
using utils::EntityManager;
using utils::Path;
using namespace filament::math;
struct App {
@@ -77,9 +82,65 @@ mat4f transforms[] = {math::mat4f(1.f),
utils::FixedCapacityVector<utils::FixedCapacityVector<float2>> boneDataPerPrimitive(3);
static void printUsage(char* name) {
std::string exec_name(Path(name).getName());
std::string usage(
"SAMPLE is a command-line tool for testing Filament skinning buffers.\n"
"Usage:\n"
" SAMPLE [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\n"
);
const std::string from("SAMPLE");
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 handleCommandLineArgments(int argc, char* argv[], Config* config) {
static constexpr const char* OPTSTR = "ha:";
static const struct option OPTIONS[] = {
{ "help", no_argument, nullptr, 'h' },
{ "api", required_argument, nullptr, 'a' },
{ nullptr, 0, nullptr, 0 } // termination of the option list
};
int opt;
int option_index = 0;
while ((opt = getopt_long(argc, argv, OPTSTR, OPTIONS, &option_index)) >= 0) {
std::string arg(optarg != nullptr ? optarg : "");
switch (opt) {
default:
case 'h':
printUsage(argv[0]);
exit(0);
case 'a':
if (arg == "opengl") {
config->backend = Engine::Backend::OPENGL;
} else if (arg == "vulkan") {
config->backend = Engine::Backend::VULKAN;
} else if (arg == "metal") {
config->backend = Engine::Backend::METAL;
} else {
std::cerr << "Unrecognized backend. Must be 'opengl'|'vulkan'|'metal'."
<< std::endl;
}
break;
}
}
return optind;
}
int main(int argc, char** argv) {
Config config;
config.title = "skinning buffer common for two renderables";
handleCommandLineArgments(argc, argv, &config);
size_t boneCount = 9;
utils::FixedCapacityVector<float2> boneDataPerVertex(9);
float weight = 1.f / boneCount;
+61
View File
@@ -28,17 +28,22 @@
#include <filament/View.h>
#include <utils/EntityManager.h>
#include <utils/Path.h>
#include <getopt/getopt.h>
#include <filamentapp/Config.h>
#include <filamentapp/FilamentApp.h>
#include <cmath>
#include <iostream>
#include "generated/resources/resources.h"
using namespace filament;
using utils::Entity;
using utils::EntityManager;
using utils::Path;
using utils::FixedCapacityVector;
using namespace filament::math;
@@ -128,6 +133,60 @@ mat4f transforms[] = {math::mat4f(1),
mat4f::translation(float3(0, -1, 0)),
mat4f::translation(float3(1, -1, 0))};
static void printUsage(char* name) {
std::string exec_name(Path(name).getName());
std::string usage(
"SAMPLE is a command-line tool for testing Filament skinning buffers.\n"
"Usage:\n"
" SAMPLE [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\n"
);
const std::string from("SAMPLE");
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 handleCommandLineArgments(int argc, char* argv[], Config* config) {
static constexpr const char* OPTSTR = "ha:";
static const struct option OPTIONS[] = {
{ "help", no_argument, nullptr, 'h' },
{ "api", required_argument, nullptr, 'a' },
{ nullptr, 0, nullptr, 0 } // termination of the option list
};
int opt;
int option_index = 0;
while ((opt = getopt_long(argc, argv, OPTSTR, OPTIONS, &option_index)) >= 0) {
std::string arg(optarg != nullptr ? optarg : "");
switch (opt) {
default:
case 'h':
printUsage(argv[0]);
exit(0);
case 'a':
if (arg == "opengl") {
config->backend = Engine::Backend::OPENGL;
} else if (arg == "vulkan") {
config->backend = Engine::Backend::VULKAN;
} else if (arg == "metal") {
config->backend = Engine::Backend::METAL;
} else {
std::cerr << "Unrecognized backend. Must be 'opengl'|'vulkan'|'metal'."
<< std::endl;
}
break;
}
}
return optind;
}
int main(int argc, char** argv) {
App app;
@@ -138,6 +197,8 @@ int main(int argc, char** argv) {
Config config;
config.title = "skinning test with more than 4 bones per vertex";
handleCommandLineArgments(argc, argv, &config);
size_t boneCount = app.bonesPerVertex;
float weight = 1.f / boneCount;
FixedCapacityVector<float2> boneDataPerVertex(boneCount);
+14
View File
@@ -266,3 +266,17 @@ vec4 computeWorldPosition() {
#error Unknown Vertex Domain
#endif
}
/**
* Index of the eye being rendered, starting at 0.
* @public-api
*/
int getEyeIndex() {
#if defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_INSTANCED)
return instance_index % CONFIG_STEREO_EYE_COUNT;
#elif defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_MULTIVIEW)
// gl_ViewID_OVR is of uint type, which needs an explicit conversion.
return int(gl_ViewID_OVR);
#endif
return 0;
}
-8
View File
@@ -108,11 +108,3 @@ SET(IOS_COMMON_FLAGS "-m${PLATFORM_FLAG_NAME}-version-min=${IOS_MIN_TARGET}")
SET(CMAKE_C_FLAGS_INIT "${IOS_COMMON_FLAGS}")
SET(CMAKE_CXX_FLAGS_INIT "${IOS_COMMON_FLAGS}")
SET(CMAKE_ASM_FLAGS_INIT "${IOS_COMMON_FLAGS}")
SET(CMAKE_C_FLAGS_DEBUG_INIT "-fembed-bitcode-marker")
SET(CMAKE_CXX_FLAGS_DEBUG_INIT "-fembed-bitcode-marker")
SET(CMAKE_ASM_FLAGS_DEBUG_INIT "-fembed-bitcode-marker")
SET(CMAKE_C_FLAGS_RELEASE_INIT "-fembed-bitcode")
SET(CMAKE_CXX_FLAGS_RELEASE_INIT "-fembed-bitcode")
SET(CMAKE_ASM_FLAGS_RELEASE_INIT "-fembed-bitcode")
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "filament",
"version": "1.51.6",
"version": "1.51.8",
"description": "Real-time physically based rendering engine",
"main": "filament.js",
"module": "filament.js",