Compare commits

..
382 Commits
Author SHA1 Message Date
Eliza Velasquez b29345b974 wip: nix 2023-12-12 14:11:11 -08:00
Eliza Velasquez b1794a82ca Generate dummy skinning variants for FL0 mats
Even if skinning is not fully implemented on FL0, we have clients which depend
on materials with skinning variants that otherwise could easily be converted to
FL0 materials. There are two proper ways to deal with this:

1. Support skinning/morphing in Feature Level 0.

2. Allow ESSL 1.0 code and ESSL 3.0 code to support different sets of variants.

However, the simplest solution is to just include skinning/morphing variants,
but disable codegen for ESSL 1.0 code, making them identical to the base
variants. This shouldn't increase the file size much due to the dictionary
deflation. Of course, skinning will not work correctly on FL0, but this has
always been the case. Future work here would be to properly implement one of the
two solutions described above.
2023-12-07 15:37:23 -08:00
Powei Feng 56bd2871ec vk: spec const workaround through runtime spirv modification (#7399)
To avoid driver edge cases with spec const, we manually change the
spec const into a regular constant in the spirv.

FIXES=310603393
2023-12-07 14:49:12 -08:00
Mathias Agopian 5a9c47bcb5 Improve blitting APIs
- deprecate blit(), renamed to blitDEPRECATED. It's only used in one
  place in copyFrame() now. We can't void it because we don't have
  access to the texture from the RenderTarget.

- add a new blit() api that works with textures instead of render
  targets.

- add a new resolve() api that works with textures instead of render
  targets. doesn't support scaling.

- always use a shader when scaling in the framegraph
  (there was only one place where we used blit)

- use the new blit() for:
	- for mipmap generation on vk (fixme)
	- copying the depth buffer to avoid ssao feedback loop

- use the new resolve() for:
    - manually resolving MSAA color/depth

- Simplify the resolve APIs on the filament side

- implement generateMipmaps for the vulkan backend

simplify MetalBlitter

- remove metal blit workarounds
- don't issue a blit from a renderpass, this only affect Renderer::copyFrame
- We only handle a single texture now (instead of color+depth), so we
  can simplify the code a lot.
  Didn't touch the "slowpath" much, but it now assumes it blits color or
  depth, not both.
2023-12-06 11:22:53 -08:00
Ben Doherty 51c2fa2728 Fix typo in getStereoscopicOptions Java (#7410) 2023-12-06 11:03:51 -08:00
Mathias Agopian 334c71de52 material depth variant caching should only happen for surface materials (#7407) 2023-12-05 14:28:32 -08:00
Mathias AgopianandBen Doherty 001098098b on ANGLE we now use a thread pool for parallel shader compilation (#7405)
* on ANGLE we now use a thread pool for parallel shader compilation

in general we now prefer using a thread pool instead of the KHR
extension, because we have less control over how the queue is
managed by the driver.

ANGLE supports many threads very well, so we use cpu_threads/2 for the
pool size, at background priority.

* Update filament/backend/src/opengl/ShaderCompilerService.h

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

* Update filament/backend/src/opengl/ShaderCompilerService.h

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

---------

Co-authored-by: Ben Doherty <bendoherty@google.com>
2023-12-05 14:28:11 -08:00
Sungun Park 35a00b1d84 Release Filament 1.48.0 2023-12-05 11:33:03 -08:00
Powei Feng b517a45213 Fix sed in bump-version.sh for Linux (#7406) 2023-12-05 11:28:42 -08:00
Powei Feng f8057b9a5b Add spirv-headers as a separate third_party repo (#7401)
* Add spirv-headers as a separate third_party repo

Previously, we pulled in spirv-headers as part of spirv-tools. We
still keep this behavior but move the content of the repo to
third_party.

We introduce a script for updating spirv-tools, and update the patch
file. The same script will also pull in a dependent spirv-headers.
2023-12-05 10:02:15 -08:00
Mathias Agopian d9ee526a72 fix jni Scene.getEntities
we were using the version of ReleaseIntArrayElements that doesn't
always keep changes to the array.
2023-12-05 09:28:50 -08:00
Powei Feng 164d7507bb Update MATERIAL_VERSION to 48 2023-12-01 11:00:53 -08:00
Eliza Velasquez b007e9137e Fix ESSL 1.0 external samplers
matc was re-introducing the incorrect extension for external samplers in ESSL
1.0 code after spirv optimizations.
2023-11-30 14:07:23 -08:00
Mathias AgopianandPowei Feng 06bae26e1b better handle invalid programs in release builds (#7389)
* better handle invalid programs in release builds

Until now invalid program would basically be undefined behavior,
which in practice was a crash via a null pointer dereference.
With this change, invalid programs cause drawing ops to become no-ops.

Additionally fixed an unsynchronized access of a the variable containing
the program id. I don't think it would have caused issues though.

FIXES=[311775564]

Co-authored-by: Powei Feng <powei@google.com>
2023-11-29 09:39:35 -08:00
Rene Sepulveda 1be3e13427 Add namespace qualifiers to satisfy gcc (-fpermissive) 2023-11-29 09:38:19 -08:00
Mathias Agopian e7c67d1adb Fix a possible NPE in UiHelper
We were not unregistering the TextureView or SurfaceHolder callbacks on
detach, so they could fire and access an null'ed RenderSurface

FIXES=[308443790]
2023-11-28 10:24:16 -08:00
Powei Feng 9b67d80961 Add intermediate.h include to builtinResource.h (#7388) 2023-11-28 10:23:31 -08:00
Powei Feng b066678a37 matdbg: fix backend selection 2023-11-27 16:54:49 -08:00
Powei Feng b10d5c58aa backend: Add linux as platform for tests (#7375)
- Also fixed a leak in `test_FeedbackLoops`
2023-11-27 15:48:31 -08:00
Powei Feng 000bff5ce1 Release Filament 1.47.0 2023-11-27 14:19:52 -08:00
Powei Feng 47d45a64fa Update MATERIAL_VERSION to 47 2023-11-27 11:40:00 -08:00
Eliza Velasquez 2bd48f58ff Enable optimizations for ESSL 1.0 code
The CL introducing the ESSL 1.0 chunk in materials inadvertently disabled
optimizations for said code. This commit reintroduces those optimizations and
fixes associated bugs which manifested. In particular, spirv-cross was
generating uints for bools; this has been fixed with a hack. Additionally,
spirv-cross is now compiled with exceptions enabled so that matc can gracefully
fail and show the code which failed to compile rather than abruptly aborting.
2023-11-16 14:59:01 -08:00
Mathias Agopian f2f4f556b5 fix a lot of issues with the backend tests
With these fixes failing tests are:

OpenGL:
BackendTest.FeedbackLoops

Metal:
BackendTest.ColorResolve
BackendTest.BufferObjectUpdateWithOffset
BasicStencilBufferTest.StencilBufferMSAA

Vulkan:
Many failures still
2023-11-16 14:56:07 -08:00
Mathias Agopian 5aa15f061b fix scissor/viewport state tracking 2023-11-16 13:13:27 -08:00
Eliza Velasquez 63db4f0bf0 Fix typo in depth_main.fs 2023-11-16 12:57:54 -08:00
Eliza Velasquez 7797f5af38 Incorporate feedback 2023-11-16 12:47:46 -08:00
Eliza Velasquez f9def09d17 Update NEW_RELEASE_NOTES.md 2023-11-16 12:47:46 -08:00
Eliza Velasquez 494934f34e Add option to matc to disable ESSL 1.0 codegen 2023-11-16 12:47:46 -08:00
Eliza Velasquez caae42fdf6 Enable preprocessor optimization of ESSL 1.0
Since #7358 is blocked by an upstream spirv-cross issue, we can at least do a
bit of preprocessor optimization for ESSL 1.0 code in the meantime and introduce
the FILAMENT_EFFECTIVE_VERSION preprocessor definitions.
2023-11-16 12:47:46 -08:00
Benjamin Doherty 8f6c4841cb Fix LoadImage backend tests 2023-11-15 14:42:25 -08:00
Ben Doherty 5d0c06e3f2 Remove debug code in MetalShaderCompiler (#7368) 2023-11-15 13:50:59 -08:00
Ben Doherty 7d31a7f7ea Move stereoscopic debug options to Settings framework (#7347) 2023-11-15 10:51:58 -08:00
Powei Feng 4f4a439f8b Release Filament 1.46.0 2023-11-14 21:34:31 -08:00
Eliza Velasquez 2306b56ea7 Add FILAMENT_ENABLE_FEATURE_LEVEL_0 option
This allows clients to selectively exclude feature level 0 support.
2023-11-14 16:50:44 -08:00
Antonio MaioranoandPowei Feng eebb40d30d Add missing include for latest glslang (#7365)
This change in glslang removes the include of "intermediate.h" from
GlslangToSpv.h:
https://github.com/KhronosGroup/glslang/commit/62de186c3383feef067feb6ea578f79977910722

As a result, the definition of "class TIntermediate" is removed, and
will fail compilation of MaterialCompiler.cpp when glslang is updated to
a version including the aforementioned change. We fix this by adding an
explicit include to this header in MaterialCompiler.cpp.

Co-authored-by: Powei Feng <powei@google.com>
2023-11-14 15:23:39 -08:00
Eliza Velasquez 766e4f2ec9 Fix some ES2 issues
Fix specification of mipmaps when generating textures.

Fix oversight where emulated UBOs would not replace uniforms when swapped out
for another.
2023-11-14 13:39:01 -08:00
Powei Feng b0a584c915 Small compilation fixes (#7363)
- gltfio: Enable -Wall -Werror for gltfio_core
 - gltfio: Fix various errors that were missed warnings
 - matdbg: switch from std::atomic_uint64_t to
   std::atomic<uint64_t> for older clang
2023-11-14 13:26:48 -08:00
Powei Feng d5bab43ceb Revert "engine: move setFrontFaceWindingInverted from View to MaterialInstance (#7331)" (#7360)
This reverts commit 038f07cb34.
2023-11-13 22:26:03 -08:00
Mathias Agopian 485ae1b324 add Material.compile and Engine.flush java bindings (#7348)
* Add Material.compile() Java binding.

* Add Engine.flush() java binding

* Add Scene.forEach java binding

update the Android gltf-viewer sample to precompile all variants of all
materials in the scene, similarly to the desktop sample.
2023-11-13 10:43:52 -08:00
Powei Feng 75e8961109 Update Material_VERSION to 45 2023-11-13 10:37:16 -08:00
Mathias Agopian 0e9b2eda0a Fix (again) the shadow transform
- we were not using the correct field in ShadowMapManager
- we were not computing the transform correctly, it should applied
  after the local transform, not before.

FIXES=[299310624]
2023-11-10 15:33:06 -08:00
Mathias Agopian a900bc69fb don't precompile variants in gltfio
we recently added calls to Material::compile in gltfio to precompile
materials are they are discovered. that wasn't a good call, because 
this should be the responsibility of the app, not of gltfio, at least
not without an option.

This is now done in gltf_viewer. We need something similar for 
Android.

Bugs #7318, #7336
2023-11-10 15:30:44 -08:00
Ben Doherty edbfefda0a Fix Java FeatureLevel Enum (#7344) 2023-11-10 14:41:17 -08:00
Mathias Agopian 1a0b5ddc14 fix [Pixel]BufferDescriptor functor callbacks
and attempt to make functor<->callback code less confusing.
2023-11-10 13:15:29 -08:00
Mathias Agopian e8bed52b3f repair visible shadow status
FIXES=[309519433]
2023-11-10 08:58:48 -08:00
Ben Doherty 06e8b1d689 Support up to 4 side-by-side stereoscopic eyes (#7328) 2023-11-09 15:34:50 -08:00
Benjamin Doherty 9c351b28ab Release Filament 1.45.1 2023-11-09 10:09:36 -08:00
Ben Doherty cbc3bb3326 Fix mix-precision quaternion conversions (#7339) 2023-11-08 12:38:57 -08:00
Powei Feng 0eb851ff8c Update debug.cpp (#7337) 2023-11-08 10:55:28 -08:00
Powei Feng 038f07cb34 engine: move setFrontFaceWindingInverted from View to MaterialInstance (#7331)
Moving setFrontFaceWindingInverted to MaterialInstance will enable
finer control over face inversion and aligns better with Vulkan's
pipeline definition (see VkGraphicsPipelineCreateInfo).
2023-11-06 14:06:00 -08:00
Sungun Park 62adb234d1 Cleanup RenderPassNode::declareRenderTarget (#7332)
There's no functional change. Remove an unused local variable
`outgoingEdges` to save CPU resource. Tidy up an usage of local variable
to slightly improve readability.
2023-11-06 13:22:30 -08:00
Powei Feng 53d8d2a41f vk: fix headless semaphore wait logic (#7335)
We removed the no-op queue submit for headless in PR #7264. This
means that a semaphore will not be waited on and caused a
validation error.  Here, we simply don't acquire that semaphore
for present.

Also reorganzied the pSempaphores array code for better
readability.

Fixes #7334
2023-11-03 17:14:31 -07:00
Mathias Agopian 974a69a273 update remote ui and web samples 2023-11-02 07:15:46 -07:00
Mathias Agopian 7d694ee85e repair gltf_viewer drag&drop
Drag and dropping a gltf folder was broken:
- the handle didn't find the gltf file on drag&drop
- the ResourceLoader cached the asset path
- don't exit(1) when drag&dropping an invalid file
2023-11-02 06:00:45 -07:00
Powei Feng 46e6664c3d matdbg: fix matinfo use case (#7325)
- Make sure matinfo works by selecting a default backend in the
   absence of activeShaders.
 - Add options to select backend in matinfo mode.
 - Workaround cursor misplacement for monaco
 - Refactor menu sections into a common element.
2023-11-01 21:42:42 -07:00
Eliza Velasquez 4fd7c418e5 Remove invalid FeatureLevel0Sampler3D test 2023-11-01 21:17:22 +00:00
Eliza Velasquez a3fdca7997 Fix basic post processing on ES2
First, this commit introduces some very simple bugfixes regarding ES2
compatibility related to postprocessing.

Second, this commit adds support for creating textures specified as R8, SRGB8,
and SRGB8_A8 in ES2. R8 is trivial: just use GL_LUMINANCE instead. The sRGB
formats, however, are maybe a bit more controversial. As implemented, they
instead just use the equivalent non-sRGB formats. This is of course technically
incorrect. There are a few approaches to how to add sRGB compatibility for ES2
that I can think of.

1. Do a bunch of complex shader nonsense in matc. Maybe even traversing the AST
and ensuring any texture lookup of a texture flagged as sRGB uses some
compatibility function. This would require static analysis to track if samplers
are reassigned to another variable, for example. This of course also breaks down
if you don't know at compile time if the shader will receive an RGB or an sRGB
sampler, or if the shader should be able to support both RGB or sRGB samplers.
Really only worth mentioning here for the sake of completion.

2. You could also generate simple compatibility functions to look up each
sampler, which would only apply to FL0 materials.

First, we would have to extend the material format to be able to explicitly
"color" a sampler as sRGB or not, like:

```
parameters : [
    {
        type : sampler2d,
        name : albedo,
        precision : medium,
        colorSpace : srgb,
    },
    {
        type : sampler2d,
        name : normal,
        precision : medium,
        colorSpace : linear,
    }
],
```

Then, the following GLSL code would be generated.

```glsl
\#if __VERSION__ == 100
vec4 texture_albedo(vec2 position) {
  return sRGBtoLinear(texture2D(materialParams_albedo, position));
}
vec4 texture_normal(vec2 position) {
  return texture2D(materialParams_albedo, position);
}
\#else
vec4 texture_albedo(vec2 position) {
  return texture(materialParams_albedo, position);
}
vec4 texture_normal(vec2 normal) {
  return texture(materialParams_normal, position);
}
\#endif
```

Finally, at runtime, if a sampler is "colored" one way or the other, we would
verify that only the appropriate kinds of samplers are bound.

I'm actually very partial to this solution. Since sRGB compatibility is only a
concern on ES2, we can generate this code only for FL0 shaders, which already
require GLSL shader authors to care about ESSL 1.0 compatibility by calling the
appropriate `textureXX` functions. Additionally, it provides a layer of
high-level validation that texture lookups are correct, even if a real ES2
context is not available on the device being tested.

3. Leave it entirely up to the client. (What this commit does.) This leaves
client code ripe for making mistakes, but luckily, we can go back and do
solution 2 whenever. If specifying a color space for a sampler remains optional,
then if this feature is retrofitted in the future, client code will continue to
compile.
2023-11-01 18:23:27 +00:00
Eliza Velasquez 7f1704481e Force post-processing materials to be unlit
This both fixes compilation of FL0 ES2 materials and unsaddles post-processing
materials with a lot of requirements added on by being considered lit.
2023-11-01 18:23:27 +00:00
Eliza Velasquez e6b962b038 Further improve feature level 0 support
Enable a limited subset of materials in PostProcessManager for FL0.

Create new function Material::getFeatureLevel() in C++ and Java.

Create missing Material::getReflectionMode() method in Java.
2023-11-01 18:23:27 +00:00
Eliza Velasquez 668fb07ac2 matc: support basic post-process materials in FL0
This change hard-codes writing the post process output at index 0 (i.e. color)
to gl_FragColor when generating ESSL 1.0 shaders. Any other outputs (besides
depth) are discarded with a warning, but as far as I can tell, no such cases yet
exist in Filament.
2023-11-01 18:23:27 +00:00
Eliza Velasquez f64eef02a3 Miscellaneous feature level 0 fixes
Fix edge case where an empty struct could be generated in an ESSL 1.0 shader.

Include _maskThreshold and _doubleSided in ESSL 1.0 shaders.

Add GL_OES_standard_derivatives extension to ESSL 1.0 shaders. According to
gpuinfo.org, this has 96% device coverage and supports both Mali-400 and Adreno
(TM) 304.

Remove 3D sampler support from ESSL 1.0 shaders. This extension is only
supported by 62% of devices.

Change filagui material to a FL0 material.
2023-11-01 18:23:27 +00:00
Eliza Velasquez 239e98ccec Add basic Emacs support 2023-11-01 17:28:26 +00:00
Mathias Agopian 919cfae6b2 improve ShadowMapManager slightly
don't use FixedCapacityVector to store pointers to active shadowmaps,
that's just not needed. They're all stored un a static array already
and directional and spot shadows are partitioned. 

This saves a couple heap allocations as well a an pointer dereference.
2023-11-01 09:59:32 -07:00
Mathias Agopian 0b9389430b avoid to dereference nullable objects (#7322)
Add missing @NonNull annotations

FIXES=[308443790]
2023-10-31 16:12:03 -07:00
Eliza Velasquez 1d157677d1 Add proper language server support
compile_commands.json was being generated, but hidden away inside of the cmake
build directories. This change makes build.sh link it to the main project dir
and adds some associated .gitignore entries. Now compile_commands.json is
properly read when starting clangd from Emacs, for example, and probably many
other editors.
2023-10-31 22:54:38 +00:00
Powei Feng ef3f0cb326 vk: assert updateImage is called with non-empty size (#7315)
BUG=303073160
2023-10-31 10:36:07 -07:00
Mathias Agopian fcf53f2c3e fix SSR artifact when enabling SSR
When we enable SSR the first time, the SSR buffer is not initialized,
this can result in the color pass fragment shader aborting, which in 
turn prevents the SSR history buffer from being initialized (since 
it's made from the result of the color pass), repeating the cycle.

In some other case, the system somehow recovers but we still see a
flicker when enabling SSR.

The solution here is to disable SSR in the shader until the history
buffer is ready (i.e. a frame later).
2023-10-31 10:32:14 -07:00
Mathias Agopian d6fda03b06 fix logging typo 2023-10-30 15:08:56 -07:00
Mathias Agopian a76addd2bf disable multiple context support on WGL
The reason is that some implementations of WGL require all contexts to
be created on the same thread, which we're not necessarily doing here.

fixes #7078
2023-10-27 15:53:48 -07:00
Mathias Agopian b1f7731dbe fix max lod level computation in IBLPrefilter
FIXES=[308012116]
2023-10-27 15:28:24 -07:00
Mathias Agopian e3e12dbf73 Make sure to unbind imported textures when destroying one
fixes #7280
2023-10-27 15:28:07 -07:00
Benjamin Doherty 31a75029f0 Update RELEASE_GUIDE with npm and CocoaPods instructions 2023-10-27 16:22:47 -04:00
Mathias Agopian e5c24cc718 Fix dangling pointer where destroying a samplergroup 2023-10-27 13:10:21 -07:00
Mathias Agopian 2b86c8df6f cleanup and better bone weight checks
- only check/log in debug builds
- use epsilon = 2e-7 * double(tempPairCount)
- compute boneWeightsSum in double
- don't modify the weights if they're within the threshold

FIXES=[306565054]
2023-10-27 11:33:03 -07:00
Mathias Agopian 4d8e6eefa1 don't use a spinlock for the HandleArena
We've seen hangs/ANR that are not well understood on that spinlock, so
for now we're going back to mutexes, which, on android, are very 
efficient under low contention (no syscall).

FIXES=[308029108]
2023-10-27 11:32:38 -07:00
Ben Doherty 8aeec2ba35 Fix iOS transparent rendering sample (#7300) 2023-10-27 13:44:28 -04:00
Eliza Velasquez 4eb4fd5aba Explicitly prevent upgrading from feature level 0 2023-10-26 22:20:57 +00:00
Eliza Velasquez 56355231bd Allow explicitly initializing at feature level 0
This change does three main things. First, it adds an option to the Engine
Builder to pick the feature level at which to instantiate Filament. The only
real practical purpose of allowing this is to be able to instantiate at feature
level 0. Secondly, it allows feature level 0 to properly work on non-ES2
devices. Thirdly, it changes both Android and desktop hellotriangle samples to
explicitly opt-in to feature level 0.

Unfortunately, feature levels are used in two different, somewhat contradictory
ways presently in Filament, which can make reasoning about this change a bit
confusing. From a client perspective, feature levels refer to buckets of
capabilities which are guaranteed to be supported. Internally, there is a
separate "feature level" stored internally at the Driver subclass level which
generally corresponds to the maximum supported feature level, but is also
referenced when activating workarounds for limited devices. For example, Uniform
Buffer Objects are not supported in ES2, however, Filament supports emulating
them such that the client does not need to care at all; a supported feature is a
supported feature. But internally, Filament uses this "Driver" feature level to
determine whether or not a given workaround is needed. There were several cases
where the "active feature level" was being examined in order to activate these
workarounds rather than the "driver feature level", which was incorrect.

Why should non-ES2-only devices want to activate feature level 0? Allowing this
behavior 1. makes feature level 0 more consistent with the behavior of other
feature levels and 2. allows clients a layer of validation that their software
will work on all devices supported by Filament if they explicitly opt into it.

Consistency: Filament guarantees that any given device which supports a given
feature level will also support running on every feature level below, except for
feature level 0. This change removes that exception.

Validation: It's not perfect, and there will likely be bugs and unexpected
differences in behavior between ES2 and non-ES2 devices that crop up in the
future between two devices running on the same feature level. However, it's at
least a basic high level layer of validation that enables more rapid testing
workflows directly via desktop versions of Filament rather than having to fiddle
with something like ANGLE to get perfect GLES 2.0 compliance. Additionally, it
expands options for automated testing (with the same caveats).

This change has been tested on both the desktop and Android versions of
hellotriangle.
2023-10-26 22:20:57 +00:00
Powei Feng 9ccb8fce31 matdbg: UI refresh (#7301) 2023-10-26 14:14:01 -07:00
Mathias Agopian e674420e9c improvements to EntityManagers and Filament APIs (#7302)
* prevent public classes from being created on the stack

- we used to to this by deleting operator delete, but this prevented
  the internal "F" classes from being virtual; which can be useful
  when using EntityManger::Listener.
  now we just make the destructor protected in each class.

- EntityManger::Listener now has a virtual destructor so that
  objects could be correctly destroyed from Listener*

* improve EntityManger and Component managers

- all component managers now have the same "base" API
    - getComponentCount()
	- empty()
    - getEntity()
    - getEntities()

- Scene now has getEntityCount()

- EntityManager now has getEntityCount()

- all component manager implement gc() the same way, by calling destroy()

- SingleInstanceComponentManager::gc() that calls removeComponent() has
  been removed because it's dangerous. removeComponent() is often
  not enough, some additional cleanup might be needed.
2023-10-26 13:10:43 -07:00
Mathias Agopian 8a9cbcfb99 fix a Transform component leak in CameraManager
CameraManager creates a Transform component for each Camera component
is not already present. However, it didn't destroy the transform
component when it's itself destroyed. the leaked transform component
would eventually be garbage collected, but caused significant
slow down and memory pressure. This is because camera components are
created every frame for the shadow maps.

FIXES=[303914944]
2023-10-26 13:05:35 -07:00
Mathias Agopian f0d5cd3fa1 improve BlobCache API and compatibility
- the insert and retrieve handlers can now be set/unset independently.
  this could be useful for debugging.

- program caching is disabled if the GL implementation doesn't support it.

- removed unused code

FIXES=[307549547]
2023-10-25 22:15:25 -07:00
Powei Feng 73b0751ccf Release Filament 1.45.0 2023-10-25 15:15:35 -07:00
Powei Feng cc95a4a7a3 vk: remove unused platform GGP (#7298) 2023-10-25 11:00:35 -07:00
Ben Doherty d76cf643c5 Improve Metal vertex buffer bindings (#7293) 2023-10-25 12:14:02 -04:00
Powei Feng 6e249c4c1b matdbg: material info and fix resizing (#7295) 2023-10-24 21:56:42 -07:00
Mathias Agopian af0c6a7fe9 OpenGLBlobCache: be more robust when shader fails to compile
- don't call BlobCache if link status false
- don't assume glGetProgramiv never fails
- don't assume malloc never fails

FIXES=[307549547]
2023-10-24 16:42:01 -07:00
Powei Feng 7b7dfad552 filamat: Fix MaterialInfo::userMaterialHasCustomDepth init (#7292)
Leaving it uninitialized leads to msan failure.
2023-10-24 15:43:24 -07:00
Powei Feng deb3eb0b11 matdbg: fix deadlock and add experimental UI (#7275)
- Ensure that waiting on lock times out so that we don't lock
   up a thread when the client is gone.
 - Add an experimental folder to matdbg/web/ for the new
   UI work.
2023-10-24 13:48:29 -07:00
Sungun Park d3016adaff FFilamentAsset has root nodes' scene-mask set
The transient property `mRootNotes` in FAssetLoader is built when a new
root asset is created and referenced whenever a new instance is created.
So it incurs an undefined behavior when a previously created asset tries
creating a new instance after a newly created asset has already created
via the same asset loader.

Move this transient property to each asset so that they can reference it
when a new instance is created.

This partially fixes #7269
2023-10-23 15:30:49 -07:00
Sungun Park 6c29542fad Cleanup function signatures
There's no functional change in this commit.

Make some parameter names more legible by renaming them and put output
parameters to the right of their function.
2023-10-23 15:30:49 -07:00
Sungun Park 0d2a96d630 Remove transient property mAsset from FAssetLoader
The temporary variable has been used to store the current instance of
FFilamentAsset being loaded for easy access from internal methods.  This
causes a crash as to a complex scenario as follows.

val asset1 = assetLoader.createAsset(assetBuffer1)
val instance1 = assetLoader.createInstance(asset1)
val asset2 = assetLoader.createAsset(assetBuffer2)
val instance2 = assetLoader.createInstance(asset1)

As the first step of fixing this issue, remove the transient property
`mAsset` from FAssetLoader. This commit alone doesn't resolve the issue,
and more commits are following.

Consolidate the low level version of createInstance, which takes a
pointer to cgltf_data type, into the high level version as the latter
one uses a parameter for FFilamentAsset instead of referencing mAsset.

Update all other relevant methods to take a FFilamentAsset pointer
instead of cgltf_data.

This partially fixes #7269
2023-10-23 15:30:49 -07:00
Ben Doherty d3fe46765f Implement Metal parallel shader compilation (#7205) 2023-10-23 17:08:09 -04:00
Mathias Agopian 892f94e3c4 attempt to repair PlatformEGLHeadLess
It had been broken for a while. Here we attempt to repair it by moving
a lot of its functionality into PlatformEGL.
2023-10-23 11:13:02 -07:00
Mathias Agopian f75f7039f4 Add support for stenciled swapchains in EGL
Support for GLX, WGL and WebGL is still missing.

partially fixes #7232
2023-10-23 11:13:02 -07:00
Mathias Agopian 8303d6b28e EGL: fix typos in config creation
thankfully it didn't seem to cause harm.
2023-10-23 11:13:02 -07:00
Mathias Agopian 0f9a2dd6af Froxel visualization debug option
The setting can be changed at runtime using a debug property.
2023-10-23 10:02:52 -07:00
Mathias Agopian 626621fb1c minor filament benchmarks cleanup 2023-10-23 10:02:26 -07:00
Powei Feng 2b78fd8359 Update MATERIAL_VERSION to 45 2023-10-22 22:18:43 -07:00
Ben Doherty 9d181a172a Create use-after-free detector for Metal textures (#7250) 2023-10-20 17:15:42 -04:00
Benjamin Doherty d4b9d1e023 Update NEW_RELEASE_NOTES.md to reflect cherry-pick 2023-10-20 17:09:50 -04:00
Powei Feng b62991d967 vk: support stencil format in swapchain (#7277)
Fixes #7233
FIXES=302197523
2023-10-19 13:43:23 -07:00
Mathias Agopian 562ea65d5c Increase FrameGraph Arena to 256KiB
It was possible to run out of space with the Bistro scene and 
everything enabled.
2023-10-19 12:21:31 -07:00
Mathias AgopianandPowei Feng 6498cf5b64 dynamic shadowmap visualization (#7274)
* debugging PCF mode

This mode always uses a hard PCF and takes a 
slightly slower code path.

* dynamic shadowmap visualization

The directional shadowmap visualizer is implemented behind a 
specialization constant. Add the DebugRegistry infrastructure to be
able to update the spec-constant at runtime and have a subset of 
all materials invalidated.

This allows to toggle the visualization at runtime using a debug
property.

This is also a proof of concept that we can update spec-constants
at runtime; we could probably leverage this work for engine-wide
shader configurations.

* Update main.fs

* Update filament/src/details/Material.cpp

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

---------

Co-authored-by: Powei Feng <powei@google.com>
2023-10-19 12:18:00 -07:00
Adrian Perez 3c77d2c3f5 StructureOfArrays can push_back move-only types 2023-10-19 12:13:28 -07:00
Powei Feng 960c6170fe vk: optimize headless swapchain (#7264)
- Remove queue submit call when using headless swapchain. It was meant
    to emulate a real swapchain, but queue submits are expensive.
 - Add option to remove flush and wait when window resizes. If a
    headless platform uses this signal to refresh the swapchain, we
    don't necessarily need it to also flush and wait before the refresh.
 - Refactor VulkanPlatform customizations
2023-10-19 11:43:24 -07:00
mackong 37c2fe31d5 samples: support apply all animations in gltf_viewer 2023-10-19 08:45:25 -07:00
Mathias Agopian 21b51caf3d add Renderer::getClearOptions (#7272)
FIXES=[243846268]
2023-10-18 15:16:01 -07:00
Benjamin Doherty 76dbc08176 Fix missing SkinningBuffer include 2023-10-18 13:44:31 -07:00
Mathias Agopian 1b0db0fca2 fix a couple shadow stability bugs
- shadows are now stable (in stable mode) when an IBL rotation is
  used.

- fix the shadow transform option which didn't work when an IBL rotation
  was used

- also use the x-axis as a reference for the "up" direction when
  computing the light space matrix so that we don't fall into the
  degenerate case when the light points straight down, which is a
  common case

FIXES=[299310624]
2023-10-17 12:26:43 -07:00
mackongandMathias Agopian 163f02035f fix ubershader index for transmission&volume material (#7244)
Co-authored-by: Mathias Agopian <mathias@google.com>
2023-10-16 12:15:47 -07:00
Mathias Agopian 14263efbea fix mixed-precision quaternion math
We follow the same rules as C++, e.g. float * double -> double
2023-10-16 10:52:36 -07:00
Sungun Park 7c6103a458 Update BUILDING.md for the latest instruction (#7267)
- filament can be built with Visual Studio 2022 as well.
- Fix the link to the Windows SDK.
2023-10-14 00:13:54 -07:00
Powei Feng 92846305f5 matdbg: change from websocket to GET (#7263)
- Use a hanging-GET approach to reduce dependency on websockets.
 - Also add mutex to protect access to MaterialRecords, which is
   written to/read from from multiple threads.
2023-10-13 14:43:34 -07:00
Powei Feng d5ebca0c49 vk: clean up depth formats (#7262)
To prepare for allowing stencil formats in attachments.
2023-10-13 11:21:29 -07:00
Ben Doherty 38ceee8d75 Support stencil buffer when post-processing is disabled (#7227) 2023-10-13 10:04:39 -07:00
Ben Doherty fc6744ba75 Add AgX tonemapper (#7236) 2023-10-13 09:44:29 -07:00
Powei Feng 078a17469a matdbg: refactor EDIT command (#7255)
The websocket code for parsing the EDIT command is pretty verbose.
Proposing that we move to a HTTP POST request instead.

Also moved the API handler code out of DebugServer.h for clarity.
2023-10-12 10:40:57 -07:00
Eliza Velasquez 0887e388db matinfo: further refactor out redundant code 2023-10-11 16:17:48 -07:00
Eliza Velasquez e4a57cedf9 matinfo: add support for viewing ESSL1 code 2023-10-11 16:17:48 -07:00
Ben Doherty d92bdce852 Remove problematic GlslangToSpv option: emitNonSemanticShaderDebugInfo (#7260) 2023-10-11 15:13:41 -07:00
Ben Doherty 76bf906856 Update glslang to 277d09e679f0f4d9469c463c00cb11c6a040e65f (#7261) 2023-10-11 15:01:35 -07:00
Mustafa Uzun b5e23162df fix: CameraInfo.clipTransform typo 2023-10-11 11:02:32 -07:00
Powei Feng eeb53606c8 doc: fix viewer page again (#7254)
- reverse the link and original relationship between
   docs/viewer/filament-viewer.js and
   web/filament-js/filament-viewer.js
 - symlink in github pages does not seem to link to outside of the
   /doc directory (it does not get pulled in during deploy).
2023-10-10 13:32:22 -07:00
Mathias Agopian dd23f271e3 cleanup Camera code and docs
- setProjection and setLensProjection are now less special, they can
  now be entirely implemented by the user thanks to two new helper
  functions. Everything can now be done with setCustomProjection.

- fix some out-dated comments

- remove dead code

- reorder methods in Camera.h
2023-10-10 13:14:37 -07:00
Powei Feng e78a06797c doc: pin viewer lit to a specific version (#7253)
- Pin lit to version 2.8.0 (to fix a breakage caused by new
   release).
 - Update viewer filament version to latest
 - Use symbolic link instead of having two copies of the same
   file. (Could we consider removing `filament-viewer.js` in
   `web/filament-js/` ?)
 - Update `web/filament-js/README.md`
2023-10-10 13:06:24 -07:00
Ben Doherty 6279613b79 Metal: support float16 operations in --optimize-size mode (#7249) 2023-10-09 14:15:07 -07:00
Powei Feng 78d433cafa Update NEW_RELEASE_NOTES.md 2023-10-05 22:43:39 -07:00
Mathias Agopian 6590f62052 handle more generic projections for shadowFar
When we update the Far plane in the projection matrix, we assumed the
shape of the matrix. This fell appart when the projection matrix was
(for instance) a blend between an ortho and perspective projection.

We now do this more generally, that is, with less assumptions on the
projection matrix shape.
2023-10-05 16:31:39 -07:00
Jacob Su f1f7aeb14f fix java Engine.Builder method access modifiers. 2023-10-05 14:21:58 -07:00
Mathias Agopian 5190b03f89 the visibility type can be 8 bits instead of 16.
It was changed to 16 a while back to handle more shadows, but since
then we changed the culling algorithm and 8 bits is enough again.
2023-10-05 14:20:48 -07:00
Powei Feng 2cd492ed38 Fix build failures due to filamat lite removal try 4 (#7228) 2023-10-04 10:25:15 -07:00
Mathias Agopian 07975868fe update cgltf to latest v1.13
FIXES=[239321615]
2023-10-04 10:19:39 -07:00
Powei Feng 5ab526cbb0 Fix build failures due to filamat lite removal try 3 (#7226) 2023-10-03 15:23:03 -07:00
Powei Feng df935b75e5 engine: add job system thread count configuration (#7223)
- Plumb Engine::Config in Java
 - Add Engine::Builder for Java
 - Add jobSystemThreadCount to Engine::Config

BUG=303129581
2023-10-03 15:22:46 -07:00
Powei Feng b4d6f975c1 Fix build failures due to filamat lite removal #2 (#7224) 2023-10-03 12:39:50 -07:00
Powei Feng 2cf86454bb vk: refactor VulkanProgram (#7221) 2023-10-03 10:49:45 -07:00
Benjamin Doherty 5572097fb3 Fix build failures due to filamat lite removal 2023-10-03 09:07:37 -07:00
Benjamin Doherty 480cfb2820 Release Filament 1.44.0 2023-10-02 15:27:29 -07:00
Mathias Agopian 39d555d115 get rid of filmat-lite, which was poorly maintained 2023-10-02 14:18:25 -07:00
Powei Feng df50f4c25d vk: layout transition clean up (#7217)
- Return the correct SubresourceRange for depth attachments
 - Fix transition for when one layout within mulitple mip-levels
   is different
 - Use implicit layout transition for renderpasses
 - Fix access mask for sampler in vertex shaders
 - Use unordered_map for VkSubresourceRange in VulkanTexture
2023-10-02 10:54:44 -07:00
Eliza Velasquez 976f304ee7 Revert "Remove now-redundant feature level 0 materials"
This reverts most of commit 9a6b8bf24e. The hello
triangle sample remains unreverted.

The original commit inadvertently broke screen space reflections, and perhaps
other features when the default material was used. The source of the issue is
that MaterialBuilder.cpp (correctly) filters out variants that aren't supported
in feature level 0 materials, including screen space reflections.

Unfortunately, while the "feature level 0 compatibility" feature itself was
intended to make creating duplicate materials like this redundant in client
code, unfortunately, it seems the best solution for resolving this issue is to
simply keep these redundant materials in the core.

To elaborate: clients should expect that feature level 0 materials that they
create work on /all/ feature levels /exactly/ or /close to exactly/ identically.
This includes restricting more advanced features that theoretically could be
available on a higher feature level, like SSR. It's already true that if a user
would like to optionally opt-in to a more advanced material which takes
advantage of more advanced features, they would have to maintain two separate
versions of that material: one for feature level 3 and one for feature level 1.
It should be no different in this case.

However, the materials built into the engine core are an exception to this
expectation. Given that feature level 0 was tacked on after the fact with fewer
features, there must /by necessity/ have been a new material introduced for both
the default material and the default skybox specifically for feature level 0
with fewer features than extant client apps expected to be included by default.
I imagine if filament were to be rebuilt from the ground up, this exception
wouldn't exist. However, the end result is this somewhat messy redundancy.
2023-09-29 23:48:47 +00:00
Mathias Agopian 21ea99a1d9 fade shadows out at shadowFar distance
Instead of a hard cutoff, we fade shadows out at
the shadowFar distance if active, fading occurs
over about 10% of the shadowFar distance.

- this works only for the directional shadow
  (other lights don't use shadowFar).
2023-09-28 16:21:27 -07:00
Mathias Agopian f0b0505207 fix materials that write to the depth or use discard
these materials would not generate proper structure or shadow buffer,
because they used a special variant that in most case removed the
user code.

now when the user code writes the depth or calls discard, the user
shader is kept.
2023-09-28 16:19:17 -07:00
Mathias Agopian 11997d007a cleanup ASTHelpers, GLSLTools
- fix IDE warnings
- rename ASTUtils to ASTHelpers to match filename
- break dependency of ASTHelper on GLSLTools
- break dependency of GLSLTools on MaterialInfo
2023-09-28 16:19:17 -07:00
Powei Feng c0327c95d4 vk: remove uneeded log in readpixels 2023-09-28 15:24:11 -07:00
Romain Guy e1dfea0f12 Fix masked materials (#7215) 2023-09-27 21:36:28 -07:00
Powei Feng b2cef9bfee Update MATERIAL_VERSION to 44 2023-09-27 16:32:17 -07:00
Powei Feng f6b979c8e4 vk: refactor VulkanResources.h (#7206)
- Make the size of FixedSizedVulkanResources declarable
- Rename `acquire`
2023-09-27 15:01:33 -07:00
Powei Feng 2e9dd03222 Release Filament 1.43.1 2023-09-27 11:10:42 -07:00
Eliza Velasquez 9a6b8bf24e Remove now-redundant feature level 0 materials 2023-09-26 22:46:51 +00:00
Eliza Velasquez 3aee9402d5 Add ESSL1 block to feature level 0 mats
Previously, when a material was expilicitly built for feature level 0, it was
necessary to write ESSL 1.0 code which was incompatible with the OpenGL feature
level 1 implementation in Filament. Rather than adjust the Filament
implementation so that feature level 1 uses the same workarounds as feature
level 0 to emulate GLES 3.0+ features, it's more runtime-efficient to have matc
embed ESSL 1.0 and 3.0 shaders as separate chunks and load the corresponding
one based on the active feature level.

Feature level 0 material shaders must still be written in what is effectively
ESSL 1.0. To assist with this, a small set of compatibility definitions are
introduced when building the ESSL 3.0 variant. These are virtually all
textureXXX() functions, and end up either optimized out or inlined by glslang.

One final effect of this change is that external and 3D samplers are now
properly supported in feature level 0 materials.
2023-09-26 22:46:51 +00:00
Eliza Velasquez fcf5866fc3 Add .editorconfig file
This informs a broad variety of text editors of some of the formatting
conventions of the filament project. It may be possible to replicate some of the
more specific formatting conventions like brace placement in a future commit.
2023-09-26 22:46:51 +00:00
Powei Feng 864a854c13 vk: remove unnecessary flush and gc (#7207) 2023-09-26 14:05:36 -07:00
Jacob Su 5a18cdf0f6 Fix: remove duplicated links inside ios samples. (#7190) 2023-09-25 14:19:00 -07:00
Jacob Su 6ebd22f474 Fix test_gltfio cmake duplicate libs and failed UT. (#7199)
* fix test-gltfio cmake duplicated libs links.

* fix test_gltfio failed UT.
2023-09-25 12:52:46 -07:00
Ben Doherty 9f5c1bb0dc Move CallbackManager out of OpenGL driver (#7194) 2023-09-25 11:07:43 -07:00
Powei Feng 9cbf741ac2 Update MATERIAL_VERSION to 43 2023-09-25 10:08:56 -07:00
Mathias Agopian 04c8845284 skinning: fix a possible crash/assert
all textures declared in a shader must be bound, in the case of the
new skinning API, if less than 4 bone weights are used the texture is 
not needed, but it must still be bound.
2023-09-24 14:20:33 -07:00
Mathias Agopian d82b7a529c skinning: minor cleanup 2023-09-24 14:20:33 -07:00
Mathias Agopian 72c60b35d7 fix TAA when camera is far from the origin
The intermediate transforms needed to be kept in double precision.
2023-09-22 10:10:18 -07:00
fvbj 5d30435620 Extend skinning for >4 bones per vertex (#6772)
* Add skinning and morphing samples to check functionality
* Implement skinning for more than four bones pair vertex

The API allows defining an unlimited number of bone indices and weights of primitives. Data is defined in building process of the renderable manager. Backward compatibility with the original solution.
Skinning of vertices is calculated on GPU, data is transferred to the vertex shader in the texture.
2023-09-21 13:04:12 -07:00
Mathias Agopian d02231dce9 fix build most recent emscripten build 2023-09-21 13:02:35 -07:00
Powei Feng ea70fe540f vulkan: cache vertex buffer info (#7181)
To reduce CPU on draw(), we move the VertexBuffer related metadata
out of draw into a cache. We store the cache info outside of the
actual VulkanVertexBuffer class since VulkanVertexBuffer subclass
HwVertexBuffer, which is a Handle meant to be minimal.

This  means that we need to cache on the heap, but it should be ok
since the caching is only for scene set-up and not per-frame.
2023-09-20 12:19:43 -07:00
Romain Guy cb9bfaeb83 Fix build warnings (#7189)
The latest macOS toolchain triggers warnings for duplicate libraries at
link time. This is caused by our dependency chains.

Also remove an inlining warning in Kotlin and unnecessary warnings in
build.sh when doing a clean or generating web docs.
2023-09-20 10:16:55 -07:00
Mathias Agopian 3dcdb202d1 new API to return a Material's supported variants
FIXES=[297456590]
2023-09-19 15:48:39 -07:00
Mathias Agopian da73f89a23 improve/simplify "Focus on shadow casters" algorithm
Functionally this shouldn't be too different, but we have some
improvements:
- better detection of "no shadows" cases
- more computations done in light-space, which should result in
  better light frustum.
- spit the code into several static functions
2023-09-19 14:15:52 -07:00
Mathias Agopian 9474798c75 remove anamorphic bloom feature
This features didn't work well, had a lot of artifacts and generally
wasn't very useful. This kind of effect should be accomplished
differently.

This is an API break because BloomOptions::anamorphism has been removed.
2023-09-18 16:09:21 -07:00
Ben Doherty 13df6652ae Add npm deploy GitHub workflow (#7184) 2023-09-18 15:11:58 -07:00
Ben Doherty 4f925f07e8 Add CocoaPods Deploy GitHub workflow (#7176) 2023-09-18 14:39:20 -07:00
Benjamin Doherty 8f64756721 Release Filament 1.43.0 2023-09-18 14:21:43 -07:00
Mathias Agopian 9f62dc2f2f Improve bloom
- add a quality option
- remove the ping-pong code, we'll disable for GPU that don't work
  instead.
- improve quality by doing a better first downscale
  (using a 5x5 gaussian).
- improve performance by using a 9 tap filter instead of 13 for
  in most cases
- fix usages of setMinMaxLevels as it resets the base level to "min"
2023-09-18 11:51:51 -07:00
Mathias Agopian 9c0fb67b87 repair "focus on shadow casters" features
This broken recently because of a typo in refactoring.
2023-09-15 14:32:56 -07:00
Ben Doherty 0b97de425f Fix, Metal setMinMaxLevel called between render passes (#7175) 2023-09-15 11:48:52 -07:00
Powei Feng 373c5710b1 Fix the output of Windows release workflow (#7171)
This probably broke due to a change from old windows command prompt to powershell. The way to refer to env variables in powershell is `$Env:var`
2023-09-14 21:23:02 -07:00
Powei Feng 91b55bdea1 vulkan: fix fence deadlock (#7173)
Should only reset fences in VulkanCommands::gc
2023-09-14 17:09:33 -07:00
Powei Feng 976b8c6ae4 vulkan: refactor debug defines (#7170)
Add more fine grain debug defines and add some systrace markers.
2023-09-14 15:30:42 -07:00
Powei Feng c80fbfdf17 Release Filament 1.42.2 2023-09-13 22:59:33 -07:00
Powei Feng d4d03e4a35 vulkan: reset fences instead create/destroy (#7169)
We allocate all the fences beforehand to reduce calls to
vkCreateFence.

Also remove blocking code in `getFenceStatus` since there is
not a usecase that would require that.
2023-09-13 21:17:31 -07:00
Ben Doherty 2114995489 Implement setMinMaxLevels for Metal (#7158) 2023-09-13 12:33:10 -07:00
Powei Feng ec30ddd2fb vulkan: implicitly free command buffers (#7167)
We were calling vkFreeCommandBuffers directly, but resetting
the buffers implicitly (when vkBeginCommandBuffer is called)
seems to be a lot more performant.

Also, cleaned up destructor for VkBuffer to no longer require
a separate terminate() method.
2023-09-13 11:21:04 -07:00
Mathias Agopian c35a60808c repair ShadowOptions::shadowFar
the shadow far plane (shadowFar) was only partially taken into account
2023-09-13 10:29:05 -07:00
Eliza Velasquez 58017a0e6a Tweak documentation
This is admittedly a very nitpicky change.

For most of the changes, I went through the various Markdown files and added
language names to the source blocks for better syntax highlighting on GitHub. It
also makes it easier to copy and paste commands without copying the leading `$`.
I avoided changing anything in `third_party`.

Additionally, I added some instructions for compiling the Android samples on the
command line and fixed some typos.
2023-09-12 20:28:46 +00:00
mackongandMathias Agopian d9c2893976 Fix possible change of scale sign when decomposing matrix (#7138)
Co-authored-by: Mathias Agopian <mathias@google.com>
2023-09-12 12:28:02 -07:00
Mathias Agopian 1ff0a2dd6d Improvements to shadowing
- use the geometric normal to apply the shadow bias. This affects
  cascades > 0 and spot/point lights.

- use the scene's origin as a reference point for stabilizing the
  shadowmap, this is more robust.

- clamp directional shadowmap correctly to the 1-texel border, which
  needs to be reachable, as it is a valid value.

- don't snap the shadowmap to texel boundaries if stable mode is not
  active (before we only didn't do it based on lispsm). Stable mode can
  make the shadow unstable when both the camera and the scene move 
  together, so it's better to have a more predictable API where
  "stable" mode means that the snapping occurs and doesn't otherwise.

- add "far origin" distance slider to the debug ui

FIXES=[299310624]
2023-09-12 10:14:21 -07:00
Mathias Agopian da96b45827 apply shadow settings to all lights in the scene
this "fixes" point light shadows in gltf_viewer, which were never
enabled
2023-09-12 10:08:07 -07:00
Powei Feng 9ac4fa63ed vulkan: fix swapchain leak (#7161) 2023-09-11 23:21:52 -07:00
Jacob Su 8d621561f3 fix ios samples missing functional header (#7153) (#7154)
1. ios sample: ios/samples/hello-gltf;
2. ios sample: ios/samples/hello-pbr;
2023-09-11 16:25:06 -07:00
Ben Doherty 2c63a5ad7a Fix use of -Wno-deprecated-register flag and MSVC (#7156) 2023-09-11 13:40:02 -07:00
Ben Doherty d328b64dce Only call .put if the tick op was canceled (#7152) 2023-09-11 12:58:29 -07:00
Ben Doherty 3ab7780c38 Fix incorrect SamplerParams operators (#7150) 2023-09-08 13:06:52 -07:00
Mathias Agopian 6fd5d45295 fix shadow stability when eye is far from world origin
in stable mode the scale was ever so slightly varying with the 
camera position, because it was calculated from the camera frustum in
world-space, this variation was amplified when the camera is far from 
the origin, which eventually caused the modulo needed for snapping the
shadowmap projection to widely vary, leading to the instability.

We now calculate the camera frustum sphere in view space, which is
guaranteed to be constant. If "shadow caster mode" is chosen, we 
quantize the scale a little bit so it stays constant.

The snapping code itself has been cleaned.
2023-09-08 11:19:19 -07:00
Benjamin Doherty 4f11a02889 Release Filament 1.42.1 2023-09-07 17:54:47 -07:00
Ben Doherty a57225cf2e Fix race condition in ShaderCompilerService (#7147) 2023-09-07 17:46:45 -07:00
Romain Guy dc818abadc Quiet popd/pushd 2023-09-07 14:48:11 -07:00
Jacob Su c808d8f260 More robust validation in build.sh 2023-09-07 09:42:48 -07:00
Mathias Agopian e0a37de1ba cleanup 2023-09-07 00:09:02 -07:00
Mathias Agopian 4e2a791e81 Directional shadows can now be transformed
This setting only exists for artistic reasons.

b/297095805
2023-09-07 00:09:02 -07:00
Romain Guy 60627f836f Update cmgen README 2023-09-06 09:07:40 -07:00
Romain Guy 22c9d350c1 Fix docs 2023-09-06 08:45:45 -07:00
Ben Doherty d11a782c3e Set CMAKE_OSX_DEPLOYMENT_TARGET in CMakeLists.txt as opposed to build.sh (#7143) 2023-09-05 17:46:19 -07:00
Powei Feng b4a45f126a vulkan: fix ordering when using debugMarkerExt (#7141) 2023-09-05 16:23:09 -07:00
Mathias Agopian 35a8e73675 remove Program operator=
It is currently not needed, AFAIK, and it was not implemented properly.
2023-09-05 12:19:37 -07:00
Jacob Su 8d7743ce67 Bug: fix underscores literal operators c++ compatible error. (#7136) 2023-09-05 10:03:51 -07:00
mackong 682585be4a Fix TextureFlags for sheenRoughnessMap (#7139) 2023-09-05 10:00:12 -07:00
Romain Guy 9046d04de4 Fix a crash in gltfio when not using ubershaders (#7135) 2023-09-02 12:45:58 -07:00
mackongandRomain Guy 0f21c6c90b Use flatmat for mat parameters (#7131)
Co-authored-by: Romain Guy <romainguy@curious-creature.com>
2023-09-01 12:39:07 -07:00
Powei Feng cc6a6454d7 vulkan: properly set bool spec onst (#7125)
We wrote a bool directly into 4 bytes (as the first byte). This has two issues:
 - the other 3 bytes are not initialized
 - should be writing VK_TRUE/FALSE instead
2023-09-01 10:59:30 -07:00
Romain Guy 609dc97c4a Remove warnings 2023-08-31 11:58:06 -07:00
Benjamin Doherty 87351097ad Adjust NEW_RELEASE_NOTES to reflect cherry-picks 2023-08-30 16:30:10 -07:00
Ben Doherty 694766682f Update FrameCompletedCallback using directive (#7128) 2023-08-30 16:26:15 -07:00
Ben Doherty c946ebd1e6 Make destroyFence asynchronous (#7127) 2023-08-30 16:22:37 -07:00
Romain Guy 25a8291101 Don't force masked blending for transmission/volume materials (#7126)
* Don't force masked blending for transmission/volume materials

glTF lets you choose your own alpha mode when using the transmission
and volume material extensions. We were forcing the masked mode which
was incorrect, except to pass the standard tests.

* Update release notes
2023-08-30 13:34:49 -07:00
Mathias Agopian 60c689688d attempt to fix remote ui (#7120)
fixes #7116
2023-08-30 08:46:53 -07:00
Romain Guy 763bc1f34a Fix possible NPE when updating fog options (#7123) 2023-08-30 08:44:39 -07:00
Romain Guy ef07638eef Properly apply emissive to masked materials (#7122)
* Properly apply emissive to masked materials

The emissive property should not be multiplied by the color alpha
in masked materials. The alpha is treated as a coverage value in
that case, not an opacity value.

* Update release notes
2023-08-30 08:43:36 -07:00
Ben Doherty 0aa0efe159 Transition setFrameCompletedCallback to take a CallbackHandler (#7103) 2023-08-28 10:27:38 -07:00
Powei Feng ef7bcd1e19 vulkan: refactor resource garbage collection (#7110) 2023-08-28 10:20:37 -07:00
Powei Feng 702ceda82a vulkan: fix debug marker pop (#7112) 2023-08-25 21:27:30 -07:00
Mathias Agopian 66b78074de Revert "workaround another PowerVR compiler bug "
This reverts commit 58f96be2c4.

This caused material files to increase in size significantly. It turns
out that glslang has to generate a copy for each parameter that is
passed to a function as a non-const parameter.


This revert will break IMG devices again, but that should be the case
only on debug builds. Release builds lose the const qualifier by 
virtue of going through spirv. We'll try to address this some other 
way later.
2023-08-25 15:31:00 -07:00
Mathias Agopian 8d440cea17 Update/Improve ViewerGUI
- separate out the settings for bloom, ssao and ssr
- update webgl binaries

- change default bloom resolution to 384 from 360 to have up to 7 
mipmap levels vertically
2023-08-25 09:53:52 -07:00
Mathias Agopian 3ab8e4d725 fix lenseflare effect
we were accessing an uninitialized LOD.
2023-08-25 09:53:33 -07:00
Mathias Agopian 97f20afdd7 remove the anonymous union in SamplerParams
- don't rely on it being 32-bits
- update the jni code to store SamplerParams in a long (64 bits)
  instead of a int. This gives us some future-proofing of the java side.
2023-08-24 21:36:42 -07:00
Mathias Agopian 42989e76d7 fix possible NPE crasher in timerquery
fixes #7106
2023-08-24 21:36:21 -07:00
Powei Feng ad45cc9092 Release Filament 1.42.0 2023-08-22 13:36:35 -07:00
Ben Doherty 04669f6ab9 Add Engine query for stereoscopic support (#7086) 2023-08-22 12:41:56 -07:00
Powei Feng c3c0dde82f vulkan: fix crashing Pixel 4xl adreno (#7087)
Adreno doesn't seem to like defining the size of arrays using a
`const int`.
2023-08-22 12:36:45 -07:00
Powei Feng ecd5b681d0 Update MaterialEnums.h (#7098) 2023-08-21 10:49:44 -07:00
Romain Guy 66081e6cc1 Add fields used by JNI to proguard rules (#7096) 2023-08-21 10:39:34 -07:00
Jacob Su aa6e94a128 Fix Mat cofactor UT error on Mac M2 chip machine. 2023-08-18 10:28:51 -07:00
Mathias AgopianandPowei Feng 098be2e115 rework how we initialize the gl context (#7085)
* rework how we initialize the gl context

- early initialization is now implemented with static methods so that
  it's very clear which state they need.

- the version number is no longer used outside of initialization,
  instead we use the feature level.

- ES3.0 Adreno devices are downgraded to feature level 0

* Update filament/backend/src/opengl/OpenGLContext.cpp

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

---------

Co-authored-by: Powei Feng <powei@google.com>
2023-08-18 10:25:10 -07:00
Mathias Agopian 17caf6cae9 improvements to CompilerThreadPool and OpenGLPlatform
CompilerThreadPool:
- it now supports a thread cleanup function
- some initialization is moved to the setup function

OpenGLPlatform:
- now cleans-up the thread pool threads upon exit
2023-08-17 20:11:57 -07:00
Mathias Agopian 26952631a3 only attempt to compile shaders in parallel if supported
It can be extremely counter productive to attempt to do this if not
supported.
2023-08-17 20:10:57 -07:00
Mathias Agopian fc7b6447b7 make sure to not assert when matdbg is enabled 2023-08-17 20:09:55 -07:00
Powei Feng 6c0db37919 vulkan: fix readPixels selectMemory (#7084)
readPixels requests staging memory to be host-visible/coherent/cached.
But "cached" is not supported on Mali (Pixel 6pro).  We make it a
preferrable but optional bit.
2023-08-17 15:19:43 -07:00
Mathias Agopian 69f78dbcbe better fix for calls to eglMakeCurrent
turns out that KHR_surfaceless_context is implied for ES3.0 when 
KHR_create_context is present. However, Adreno 306 fails even if
it advertises it. So, we now reset the value of KHR_surfaceless_context
based on actually calling eglMakeCurrent(EGL_NO_SURFACE).
2023-08-16 22:46:36 -07:00
Mathias Agopian c0389ac54c rework ShaderCompilerService to improve performance
- remove support for non-shared contextes parallel compilation.
  this wasn't used. we can always revive it later if we need to.

- rework how callbacks work so that we don't have to use a work list
  executed at each tick() in the shared context case (common case).
  this improves performance significantly on low-end devices, by
  not having to go through the list to check if all programs are
  compiled, multiple times per frame.

The new CallbackManager handles scheduling the callbacks after all
previous programs are compiled.
2023-08-16 22:46:13 -07:00
Mathias Agopian c0db909c13 don't use eglMakeCurrent with EGL_NO_SURFACE unless we're allowed
EGL_KHR_surfaceless_context is needed to be able to use eglMakeCurrent
without an EGLSurface.
2023-08-16 21:35:29 -07:00
Ben Doherty 46e4e966b9 Fix assert with matdbg enabled (#7079) 2023-08-16 14:23:24 -07:00
Powei Feng 288b59a348 Fix missing createFence (#7076)
Continuing from #7072
2023-08-16 12:18:15 -07:00
Mathias Agopian 1c7293db8d fix fuzzyEqual
- the return value was inverted
- fuzzyEqual could generate alignment faults
- move it out of mat4 and mat2 because it was
  only used in one place.
2023-08-16 10:40:13 -07:00
Benjamin Doherty 6006b47c44 Release Filament 1.41.0 2023-08-15 17:11:38 -07:00
Ben Doherty 6bb29f6e01 Implement preliminary support for instanced stereo (#6967) 2023-08-15 17:08:11 -07:00
Mathias Agopian f1b160db04 remove backend wait(timeout) API
The only use of this API was with a timeout 0 to check the fence
status. Timeouts other than zero could be very dangerous and since we're
not using that feature for now, we just get rid of it.


wait() is replaced with getFenceStatus(). It is currently only used by
the FrameSkipper.

This is not a public API.
2023-08-15 12:17:02 -07:00
Mathias Agopian 3bb52f083b Remove (unused) support for hardware fences
This code hasn't been used for a while and we should not resurrect it.
2023-08-15 12:17:02 -07:00
Mathias Agopian 88337ab358 use whenGpuCommandComplete to emulate platform fences
This is more appropriate (and simple) than runEveryNowAndThen because 
the later doesn't manage a fence, and therefore is more of a superset.
This will allow us to use a shared context implementation in the future.
2023-08-15 12:17:02 -07:00
Mathias Agopian 0935fe3fe3 cleanup the timer query implementations
We don't use runEveryNowAndThen for implementations that don't need it
(e.g. the EGL fence version, or the fallback version).
2023-08-15 12:17:02 -07:00
Mathias Agopian 96ed19549e reduce the number of shader compiler thread to two from four
more threads also use (much) more memory which can be a problem for
lower end devices
2023-08-14 10:20:01 -07:00
Mathias Agopian 945e9a2cb5 don't pin the GL thread on PowerVR 2023-08-14 10:20:01 -07:00
Ben Doherty 4d703e3807 Refactor CompilerThreadPool out of OpenGLDriver (#7067) 2023-08-11 17:03:36 -07:00
Mathias Agopian f537f62adf Use 4 background threads for shader compiler on PowerVR
Since powervr supports parallel shader compilation well, we use 
4 background threads for shader compilation.
2023-08-11 15:22:19 -07:00
Mathias Agopian 7840404132 Enable read-only feedback loop for PowerVR
This is technically forbidden by the GLES 3.x specification but many
GPU support it, which saves us a depth buffer copy. 
Note that this is supported in GL desktop.
2023-08-11 15:22:19 -07:00
Mathias Agopian afad361cac Workaround a PowerVR performance issue with destroying FBOs
Destroying the FBO target of a blit operation causes a stall similar
to calling glFnish().
We workaround this by delaying all FBO destructions to after the
GPU is finished with the current frame.
2023-08-11 15:22:19 -07:00
Mathias Agopian 58b23c290c Work around a PowerVR bug where gl_InstanceID is not initialized 2023-08-11 15:22:19 -07:00
Mathias Agopian 12a73137d7 workaround another PowerVR compiler bug
In some situation, functions with const parameter cause the shader
compilation to fail without an error message.

We remove all the `const` qualifiers on functions, assuming this
shouldn't impact code generation a lot.
2023-08-11 15:22:19 -07:00
Powei Feng 7a136eec5d vulkan: clean-up includes and refactor handle allocator (#7056) 2023-08-10 16:19:24 -07:00
Mathias Agopian e9bd9ab3a6 Fix matdbg for 32 bits architectures 2023-08-09 19:19:05 -07:00
Mathias Agopian 083bff62e3 better handle "urgent" shader compilation
instead of moving the "urgent" compilation to the head of the queue,
we simply remove it from the queue and process it immediately. This
has the benefit that on drivers that truly support parallel compilation,
the latency will be reduced as we don't need to wait for the current
compile to finish.
2023-08-09 15:01:55 -07:00
Mathias Agopian f713316541 Enable parallel shader compilation on more devices 2023-08-09 15:01:32 -07:00
Powei Feng bcfdf2f70d Release Filament 1.40.5 2023-08-09 10:26:17 -07:00
Mathias Agopian 018d6f877f Workaround for some PowerVR devices
The PowerVR compiler systematically crashes on some devices when
`gl_Position` is written twice in the vertex shader.


fixes #5118, b/190221124
2023-08-08 08:59:59 -07:00
Mathias Agopian 1e4172b820 RenderTarget needs not to have a color attachment
This was a somewhat arbitrary requirement, some RenderTarget could be
depth only for instance.
2023-08-08 08:59:32 -07:00
Mathias AgopianandBen Doherty 6b6827b70d add a GLES compiler unit test (#7050)
* add a GLES compiler unit test

* Update filament/test/compiler_test.cpp

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

---------

Co-authored-by: Ben Doherty <bendoherty@google.com>
2023-08-08 08:59:06 -07:00
Romain Guy 96cccc83c6 Update BUILDING.md 2023-08-06 08:44:55 -07:00
Mathias Agopian 2468a3a854 fix a typo causing EXT_color_buffer_float enabled on al ES3 devices
b/287126679
2023-08-04 16:51:04 -07:00
Powei Feng f68825f2ed vulkan: fix fence initialization (#7038)
Previously, we have a VulkanSync with a default constructor that
allows us to have sync objects that returns error when
actual fences are not yet present.  We need to replicate that
with VulkanFence since sync objects have been removed from the
API.

Fixes #7034
2023-08-04 11:13:57 -07:00
Mathias Agopian 2a12f71f96 fix a crash when shutting the engine down
We were breaking the promise of pending shader compilation jobs by 
destroying the corresponding std::promise embedded in the job queue. 
In practice there was no danger of a deadlock by construction, but
std::promise throws an exception in that case. On builds without
exception enabled, this we be turned into an abort().

We fix this by using our own mechanism for signaling instead of
std::promise. This ends up be more lightweight anyways.


Fix: #6933
2023-08-04 10:00:37 -07:00
Romain Guy 74b64a5451 Update README.md (#7037) 2023-08-03 15:03:03 -07:00
조다니엘(Daniel Cho) 7d01e0349b Fix rendering issue when using DoF 2023-08-03 13:49:57 -07:00
Mathias Agopian 80014bf2b1 fix a possible overflow when picking
We don't need to convert the object id to float,
instead we can just "reinterpret_cast" it.

With the current possible values of Entities, there was a risk of 
overflow once the age gets to 128 (very rare).
2023-08-03 13:49:14 -07:00
Mathias Agopian adf3421f4a Workaround Adreno bug causing picking to fail
Adreno drivers don't support precision qualifiers in structs.

fixes #6997
2023-08-03 13:49:14 -07:00
Mathias Agopian 51c65ccfdc add picking to gltf_viewer for debugging 2023-08-02 12:40:16 -07:00
Powei Feng 5d37d08cf8 vulkan: fix TSAN in readpixels (#7023) 2023-08-01 16:29:27 -07:00
Benjamin Doherty eb18d75b2e Release Filament 1.40.4 2023-08-01 15:37:51 -07:00
mackongandMathias Agopian 549c582287 engine: support setDepthFunc for MaterialInstance (#7004)
Co-authored-by: Mathias Agopian <mathias@google.com>
2023-07-31 15:49:48 -07:00
Mathias Agopian 6c05029a9f workaround a crash with some adreno drivers
The crashes are triggered by spirv-opt's MergeReturnPass, so we 
just disable it. This pass also caused issues with AMD drivers on macOS.


fixes b/291140208
2023-07-31 15:48:44 -07:00
Mathias Agopian b2278986dd Update bug_report.md 2023-07-31 11:47:32 -07:00
Mathias Agopian 98a2b8f159 Improve FrameSkipper performance on GLES/Android
We get rid of the backend's HwSync object because on all platforms
but GL it was implemented just like a HwFence. We now use HwFence 
instead.

On GL platforms though, HwFence doesn't exist natively it is instead
provided by the Platform. In that case, we emulate it as with GLSync
objects -- the emulation incurs some latency that can cause frames
to be skipped.

On Android and platforms that provide the Fence functionality, there is
no such issue.

This change improves significantly frame pacing on Android.
2023-07-31 11:29:40 -07:00
Mathias Agopian 0ba891fb14 Fix off-by-one in FrameSkipper
The frame latency specified was off-by-one, i.e. a value of 1 meant a
latency of 2. The default was 2, which meant 3. Also it wasn't possible
to specify the max latency of 4, which would OOB.
2023-07-31 11:29:40 -07:00
Mathias Agopian 042cd670aa Improve fence-based timer query emulation
It now uses the fence for the start time and end time, leading to much
more accurate timings. We also use a single atomic variable instead of
two.
2023-07-31 11:29:40 -07:00
mackong 95c7e4d02b sample: fix typo 2023-07-27 10:03:11 -07:00
Mathias Agopian d302525674 Add a way to query the validity of filament objects
Engine::isValid() can be used to check the validity of most filament
objects.
2023-07-27 10:02:31 -07:00
Mathias Agopian 3dbb7298f8 fix a cleanup of material parallel compilation
When the engine is shut down, it's possible for some parallel
compilation jobs (and callbacks) to be queued. We need to make sure
to clear the queues and call the callbacks before destroying the
parallel compilation service.


Fixes b/290388359
2023-07-27 10:02:31 -07:00
Mathias Agopian 0ed71ab53b fix an issue causing callbacks to be called too late
We were waiting for programs from both queues to be compiled before 
calling the callback associated with one queue. In practice this caused
the callback associated with high priority programs to be called only 
after low priority programs were ready.

Also cleanup-up "token" so that it doesn't store the priority.

Update the documentation and sample to better reflect what the 
implementation does.
2023-07-27 10:02:31 -07:00
Mathias Agopian b1491ae5b1 Disable timer queries on all Mali GPUs
fixes b/233754398
2023-07-27 09:57:41 -07:00
Mathias Agopian 03b8dc8027 The "back" key will now terminate the gltf_viewer activity
This is useful for testing our shutdown code.
2023-07-27 09:57:14 -07:00
Mirsfang e3568cd89f fix macos openggl compile process_ARB_shading_language_packing type conversion error (#6994) 2023-07-27 09:34:41 -07:00
Powei Feng b35e24daa7 gltfio: exclude unsupported platforms from test (#7000) 2023-07-26 19:11:50 -07:00
Powei Feng f506b27a31 gltfio: simple test for asset loading (#6990) 2023-07-26 16:50:06 -07:00
Benjamin Doherty 9452d5be1d Release Filament 1.40.3 2023-07-26 12:51:50 -07:00
Romain Guy ea3f449a08 Update dependencies (#6992) 2023-07-26 11:05:09 -07:00
Ben Doherty dc9510fe25 Support EXT_clip_cull_distance for future use (#6965)
This PR sets up the ability for shaders to use `gl_ClipDistance`, which will be needed in the future. Desktop GL supports this natively. OpenGL ES requires the EXT_clip_cull_distance extension.

Unfortunately glslang does not support this extension, so we have to employ a workaround for mobile when going through glslang. We instead write to `filament_gl_ClipDistance`, and then modify the SPIR-V to decorate this as `gl_ClipDistance`. See the comment in SpirvFixup.h.

Note this PR does not actually use `gl_ClipDistance` yet, so there should be no change to shaders.
2023-07-26 10:01:28 -07:00
Powei Feng 731dd761d9 vulkan: Implement async readPixels (#6695)
- Carry out readPixels without blocking and wait for the read to
   complete own a separate thread.
 - Add mContext.commands->wait() in finish()
 - Wait for readPixels to complete in finish()
 - Remove unused commandBuffer in Context
2023-07-25 14:07:56 -07:00
Powei Feng 6726ccb2fb vulkan: fix subpass validation (#6980)
- Before, we supposed that the maximum number of input attachment
   should match the maximum number of color attachments. But in
   reality, we've only used one input attachment for the second
   subpass.
 - The problem with the above supposition is that the descriptor
   set layout for the input attachment descriptor set must have the
   exact number of input attachment specified in the shader. If the
   *layout* has more input attachment slots than specified in the
   shader, then we'd run into a validation error.
 - In this patch, we fix the number of max input attachment in
   the descriptor set layout to 1, since we ever only make use of
   one.

Fixes #6513
2023-07-25 11:24:14 -07:00
Powei Feng 5fce0f9ecf filamentapp: fix vulkan dependency (#6987)
Fixes #6983
2023-07-24 16:50:51 -07:00
Mathias Agopian ad03fc4118 fix typo that prevented the shader blob cache to work (#6979)
fixes b/290670707
2023-07-24 09:59:19 -07:00
Y-way 3f77ff8815 Build error on msvc 2022 2023-07-21 10:00:51 -07:00
Mathias Agopian 26b5fa1e38 fix a crash when using Material::compile with a callback
The work queue is sorted by priority but when we insert a notification
job we didn't have a priority to use for insertion, in addition the
priority was taken from the token, but for the notification job we don't
have a token.

The fix consists in passing the priority around so we have it when needed.
2023-07-21 10:00:21 -07:00
mackong 24286e6016 gltfio: fix crash when compute morph target without material 2023-07-21 09:08:22 -07:00
Ben Doherty 626577fe3d Fix ineffective FOG variant filter (#6968) 2023-07-20 11:54:18 -07:00
Romain Guy 176915b59c Add missing setParameter variants to MaterialInstance (#6973)
Adds support for mat3/mat4 parameter types
2023-07-20 11:19:35 -07:00
mackong 0b60933c2a web: remove const qualifier for getMaterialInstances (#6952) 2023-07-20 10:43:33 -07:00
Pawan Vimukthi 0e31d6936a Update android/Windows.md (#6964)
Updated the flag `filament-skip-samples` in the code snippet to align with the documentation.
2023-07-19 13:23:08 -07:00
Benjamin Doherty 78d9c43ef1 Release Filament 1.40.2 2023-07-17 15:49:14 -06:00
Powei Feng ce253a9563 vulkan: swapchain resize condition update (#6951) 2023-07-13 10:54:51 -07:00
Benjamin Doherty 18c3c36727 Release Filament 1.40.1 2023-07-12 13:43:11 -07:00
Ben Doherty 4e6f6a4579 Disable shader precompilation on WebGL (#6925) 2023-07-12 07:32:58 -07:00
Powei Feng 84487f4d8d vulkan: add lock to VulkanTimerQuery fence (#6949)
Call to Driver::getTimerQueryValue is synchronous so we need to
make sure the fence shared_ptr is protected by a lock.
2023-07-11 09:14:06 -07:00
Powei Feng 45f5a07989 Update MATERIAL_VERSION to 40 (#6948) 2023-07-10 15:22:15 -07:00
Romain Guy 0061883dbf Fix dynamic resolution with quality > low and translucency (#6940)
The scene graph was using the wrong boolean to decide whether to fallback
to low quality upscaling when the render target is translucent. It was
instead only looking at the view's blending mode. We need to check both,
as color grading does in the same function.
2023-07-10 12:48:54 -07:00
조다니엘(Daniel Cho) 47e3be11f0 Fix typo in BUILDING.md (#6942) 2023-07-07 08:13:37 -07:00
junsang.lee 420f4000c2 fix: 64-Bits Windows, Path::exists() fails for files over 2GB. (#6938) 2023-07-07 00:14:54 -07:00
Romain Guy 4582ce8769 Fix texture upload callbacks in Java/Kotlin (#6939)
* Fix texture upload callbacks in Java/Kotlin

* Update release notes
2023-07-06 15:53:24 -07:00
조다니엘(Daniel Cho) 3beb39f30b Fix typo in build.sh (#6935) 2023-07-06 09:07:14 -07:00
Romain Guy b72d6c058a Move file to the correct location 2023-06-26 12:48:22 -07:00
Benjamin Doherty 0c8f367b29 Release Filament 1.40.0 2023-06-26 13:16:53 +08:00
JEONG TAEHUNandjeongth9446 50045edb4f [ModelViewer.kt, Remove Lint warning] (#6917)
- Use of getter method instead of property access syntax (for getInstance)
 - 'rangeTo' or the '..' call should be replaced with 'until' (in for)

Co-authored-by: jeongth9446 <taehuniy@gmail.com>
2023-06-26 12:05:43 +08:00
Benjamin Doherty f538d1aa43 Add missing atomic header 2023-06-26 11:47:44 +08:00
SahilMadan 4bd8d2a3b7 Make initializeGlExtensions protected (#6914) 2023-06-22 14:17:12 +08:00
Ben Doherty 9fa952d968 For web assembly, implement logging as emscripten_err and emscripten_out (#6913) 2023-06-22 11:18:23 +08:00
Ben Doherty 1edad92d73 Update RELEASE_GUIDE.md 2023-06-21 07:45:37 +08:00
Powei Feng 52282baeff Update MaterialEnums.h to v39 2023-06-20 11:48:07 -07:00
Benjamin Doherty 85ab9d211d Release Filament 1.39.0 2023-06-20 23:44:33 +08:00
Ben Doherty 6e99a4dcfc Turn off iOS exceptions in debug builds (#6912) 2023-06-20 14:59:10 +08:00
Mathias Agopian 35c91827af fix error reporting with ShaderCompilerService
when using the thread pool we were destroying the shaders immediately,
we need to defer this until we query the program link status, so that 
in case of failure we can query each shader compile status.

we make the shader handles part of the promise/future so they can be 
transferred to the main thread, just like the program id is.
2023-06-16 11:04:59 -07:00
Powei Feng 5c11b237f3 vulkan: address debugUtils bug (#6904)
vkCmdEndDebugUtilsLabelEXT expects that a label was "pushed" onto
the command queue (as described in the spec). It is possible to push
labels across command buffers, but the pushed label must still be in
the queue (unexecuted) when End is called. This implies that we need
to make sure the labels are in a good state (all popped) when
vkQueueSubmit is called.

- We add a stack to carry the labels across vkQueueSubmit.
- Also add CPU time durations between push and pop to provide rough
  CPU execution times (in debug).
- Add systrace markers for Android systrace
2023-06-15 11:27:48 -07:00
Powei Feng 432b5d0427 vulkan: fix taa validations (#6903)
- Validation failing due to incorrect layout wrt Blitter
   render pass.
 - Clear colors are also not needed for blitter renderpass.
 - SAMPLEABLE + DEPTH_ATTACHMENT needs to have the correct layout.
2023-06-15 09:20:08 -07:00
Powei Feng b8b1fadfa1 vulkan: fix timer query (#6905)
- Timer query stashed a pointer to VulkanCommandBuffer, but this
   points to an object that can be reused.
- We use the shared_ptr'd fence object instead to track whether
  the query request has been completed.
2023-06-14 22:17:10 -07:00
Mathias Agopian 74f5d8a066 the ShaderCompilerService handles async shader compilation (#6848)
It supports KHR_parallel_shader_compile as well as a
thread pool of GL contexts.

- we have a new 2-priorities queue for shader compilation
- use this feature in gltfio in the ubershader case
2023-06-14 10:51:02 -07:00
Powei Feng 09aeeccfa7 vulkan: fix present layout warning on mac (#6896)
Fixing validation warning of the form:
(UNASSIGNED-BestPractices-ImageBarrierAccessLayout) Validation Warning: [ UNASSIGNED-BestPractices-ImageBarrierAccessLayout ] Object 0: handle = 0x7f824f057218, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0x849fcec7 | vkCmdPipelineBarrier: accessMask is VK_ACCESS_2_TRANSFER_READ_BIT, but for layout VK_IMAGE_LAYOUT_PRESENT_SRC_KHR expected accessMask are VkAccessFlags2(0).
2023-06-13 16:22:53 -07:00
Mathias Agopian 094abdc194 helpers to fix jank when resizing a TextureView (#6889)
There was two related issues:
- we need to "latch" the new TextureView size when its resized. That
  can only be done by recreating the EGLSurface (i.e. recreating the
  SwapChain). UiHelper now calls onNativeWindowChanged in the case of
  the TextureView resize, so clients can recreate their SwapChain.
- we also needed to make sure that all current filament frames have
  finished to render (i.e. the last eglSwapBuffers has been called) so
  that they don't pick-up a new size (this happens after
  eglSwapBuffers) that doesn't match the viewport.

Fixes b/282220665
2023-06-12 23:09:47 -07:00
Mathias Agopian f4b97028b0 align uniform buffer to 16 bytes
this is needed on armv7 because we use alignas to get strcture-alignment,
but that also implies (to the compiler) that the structure itself
is aligned properly.
2023-06-12 23:08:51 -07:00
Ben Doherty e14cbf2163 Add query instead of relying on CONFIG_MAX_INSTANCES (#6891) 2023-06-12 21:43:38 -07:00
Powei Feng 032cbab7b0 vulkan: fix missing sampler texture (#6885) 2023-06-12 09:30:10 -07:00
Mathias Agopian e306856c4f update spirv-cross (#6881) 2023-06-09 14:08:03 -05:00
Ben Doherty c1f164190b Re-enable Metal half conversion, only register SimplificationPasses for Metal (#6883) 2023-06-08 14:00:05 -05:00
Powei Feng 8030a078ff vulkan: sRGB swapchain (#6879) 2023-06-08 10:06:52 -07:00
Mathias Agopian 11adcbed25 fix VSM's high precision option on mobile (#6873)
the math needs to be maintained in highp, including during the blur
pass.

we add the ability to specify a "precision" qualifier to the "output"
of a post-process material.

we also remove the mediump clamping we used to do on mobile, it shouldn't
be done automatically behind the scenes, it's up to the shaders to do
it if it makes sense.
2023-06-07 21:57:17 -07:00
Ben Doherty c2b10859c9 Temporarily disable Metal relaxed to half pass due to spirv-cross bug (#6880) 2023-06-07 19:30:31 -05:00
Powei Feng e0e2c76d2f vulkan: minor fixes (#6874)
- flush() and wait() before destroying a swapchain
 - Make sure the debug marker extension is enabled under correct
   circumstances.
 - Change shared_ptrs to unique_ptrs and raw pointers.
 - Rename most teardown methods to terminate()
2023-06-07 11:05:47 -07:00
Benjamin Doherty b0238c1560 Release Filament 1.38.0 2023-06-07 11:31:01 -05:00
Mathias Agopian 5ffb52a17d Workaround invalid glsl generation
spirv-opt's CreateSimplificationPass() cuases spirv-cross to fail
generating working glsl.
2023-06-06 19:53:57 -07:00
Mathias Agopian 6b34e72418 disable glsl/msl minification when generate debug info is active 2023-06-06 19:53:09 -07:00
Powei Feng d43c632e55 vulkan: add option to choose gpu in platform (#6864) 2023-06-06 17:18:57 -07:00
Romain Guy d55dfdebde Fix erroneous comment 2023-06-06 15:30:06 -07:00
Powei Feng 4b12876ebc vulkan: fix context sharing (#6869)
- Make sure terminate() doesn't free shared context
- Assume no extensions have been enabled.
2023-06-06 14:04:28 -07:00
Daniel Kutenin 3e12449b8f Fix strict weak ordering in VulkanPlatform.cpp (#6867)
Merged-by: Powei Feng <powei@google.com>
2023-06-06 13:07:28 -07:00
Mathias Agopian fdc3f302d9 fix a crash on adreno when vsm is enabled
fixes b/285928132
2023-06-06 09:55:35 -07:00
Mathias Agopian 07642fec83 workaround a bug in spirv-tools causing vsm to fail
it's unclear if the problem was in spirv-cross or spirv-opt, but
eitherway, the generated code at the end was invalid.
2023-06-06 09:54:45 -07:00
Mathias Agopian 4ce93232c3 MaterialParser micro optimizations
- improves performance
- reduces code size
2023-06-05 12:45:30 -07:00
Powei Feng ccea370cd9 vulkan: wait on command buffers before resource gc (#6855) 2023-06-02 10:50:06 -07:00
Powei Feng 8f6885689b release: adjust version-bump script for linux (#6859) 2023-06-02 09:58:47 -07:00
Romain Guy 64b15fafe2 Save ImGui settings in a user-specific directory (#6865)
* Save ImGui settings in a user-specific directory

Fixes #6862

* Fix Windows build

* Fix Web build

* Add missing file
2023-06-02 08:42:27 -07:00
Powei Feng d891acb8c0 Fix missing include (#6858) 2023-06-01 15:15:34 -07:00
Powei Feng de0bc718be vulkan: fix freebsd platform breakage (#6863) 2023-06-01 13:42:39 -07:00
Romain Guy 283a06e200 Update AGP and Kotlin coroutines dependency (#6857) 2023-06-01 08:22:51 -07:00
Powei Feng 3cfb2f8339 vulkan: fix accidentally enabled API dump (#6856) 2023-05-31 16:05:27 -07:00
Powei Feng 21164885e8 Update MATERIAL_VERSION to 38 (#6852) 2023-05-31 11:26:03 -07:00
Mathias Agopian 0d745c4fea JobQueue is not used anymore, remove it. 2023-05-30 17:44:06 -07:00
Powei Feng 0e2f8b5dda Release Filament 1.37.0 2023-05-30 16:21:45 -07:00
Powei Feng 321777e8c1 Fix froxelizer entry count (#6845) 2023-05-26 15:46:34 -07:00
Powei Feng aa9f0a4ca3 vulkan: platform API for context sharing (#6844) 2023-05-26 11:01:03 -07:00
Mathias Agopian bee8862897 add basic support for KHR_parallel_shader_compile
We're just detecting the extension here, not making use of it.
2023-05-25 21:24:01 -07:00
Mathias Agopian fed69025d2 update remote-ui and web samples 2023-05-25 11:26:21 -07:00
Powei Feng f953488a31 vulkan: platform swapchain API (#6830)
- Introduce new custom swapchain API for VulkanPlatform.h
 - Implement the API for the base VulkanPlatform by refactoring
   the existing swapchain code.
 - VulkanSwapChain is now a wrapper for VulkanPlatform's
   swap chain API.
 - Actual implementation is in
   vulkan/platform/VulkanPlatformSwapChainImpl.{h,cpp}
2023-05-25 07:57:55 -07:00
Mathias Agopian 25708e8082 don't hardcode the system page size to 4096
It's already 16K on macOS and other systems.
2023-05-24 21:35:38 -07:00
Mathias Agopian a8afa91b7d add support for custom fog color in gltf_viewer
this is implemented by here by using the skybox texture and blurring it
with the irradiance filter + mipmapping. This only creates a subtle
anisotropic phase-function effect.
2023-05-24 16:37:10 -07:00
Mathias Agopian 2806221eda fix a couple of subtle bugs related to custom commands
- we must sort commmands *after* we have added all commands!
- custom commands could change the UBO/Sampler bindings so we need
  to make sure to invalidate them after executing the command.
2023-05-24 16:02:14 -07:00
Mathias Agopian a9763376b7 IBLPrefilter can now generate the irradiance texture 2023-05-23 15:52:22 -07:00
Mathias Agopian 153dc08aa7 Support for custom fog-color texture
Fix 282968398
2023-05-23 15:52:01 -07:00
Ben Doherty 332b924325 Better fix for WebGL debug assertion (#6832) 2023-05-23 14:34:18 -07:00
Ben Doherty b2ee4e93d4 Fix assertion in WebGL debug (#6831) 2023-05-23 14:10:22 -07:00
Mathias Agopian fda62e0065 fix sampling direction of fog color from IBL
When sampling the fog color from the IBL we need to take into account
the IBL transform. This broke recently when the for calculation was
moved in user world coordinates.
2023-05-23 09:01:34 -07:00
Mathias Agopian faafb1464c fix build, a unit test was broken 2023-05-23 00:01:53 -07:00
Mathias Agopian edfd06eaef froxelizer doesn't use textures anymore (#6824)
* froxelizer doesn't use textures anymore

All data is stored in UBOs.
Additionally, the buffer size is no longer hardcoded at compile time.

This CL cuts in half the numbers of froxels to accommodate devices
limited to 16KiB,

* Use a specialization constant to adjust the size of froxel UBO

This really only affects OpenGL in practice because metal supports 256MB
minimum and only 3% of android devices support less than 32K, which is
what we need.
2023-05-22 13:56:13 -07:00
Powei Feng 1a83083651 vulkan: fix unitialization (#6822)
And reformat VulkanContext.h
2023-05-22 11:47:03 -07:00
Mathias Agopian 5cb3b16f36 correctly account for user samplers in matc and document it
The number of usable sampler in materials is now documented and properly
accounted for in matc.
2023-05-22 09:59:12 -07:00
Romain Guy 3aa6913538 Add .bin option to --sh-output to generate SH in binary (#6823)
- Passing filename.bin to --sh-output generates a file containing the SH
  as binary floats in native endianness (LE on x86 and arm64)
- Fix --sh-output so it works properly with -x
- Cleanup variable names to avoid shadowing
2023-05-19 14:27:55 -07:00
Mathias Agopian 2c6f723317 extract depth/view reconstruction from ssao
these utilities can be used by other materials
2023-05-18 16:28:31 -07:00
Powei Feng ddfeaef2ca vulkan: VulkanContext/Platform refactor (#6810)
We need to keep the context handles as part of the platform
class so that we can implement the new swapchain API based
on them.

 - Move creation of "context" handles from Context to Platform
 - VulkanContext contains immutable data
 - Change constructor of classes that depended on VulkanContext
 - Move timer query logic from VulkanDriver to VulkanTimerQuery
   and VulkanTimestamps
2023-05-18 13:27:55 -07:00
Mathias Agopian a71baef5d3 improve internal documentation of per-view sampler interface blocks 2023-05-18 11:45:12 -07:00
Powei Feng e63ec23922 vulkan: fix depth+stencil image aspect (#6813)
- Need to be specific about image aspect
Also:
 - Add missing layout for debug print in VulkanImageUtility
2023-05-18 10:59:34 -07:00
5519 changed files with 337463 additions and 167273 deletions
BIN
View File
Binary file not shown.
+7
View File
@@ -0,0 +1,7 @@
;;; Directory Local Variables -*- no-byte-compile: t -*-
;;; For more information see (info "(emacs) Directory Variables")
((c++-mode . ((c-file-style . "filament")
(apheleia-inhibit . t)))
(c-mode . ((c-file-style . "filament")
(apheleia-inhibit . t))))
+11
View File
@@ -0,0 +1,11 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
[*.{c,cpp,h,inc,kt,java,js,md}]
indent_style = space
indent_size = 4
max_line_length = 100
+4 -2
View File
@@ -4,6 +4,8 @@ about: Create a report to help us improve
---
⚠️ **Issues not using this template will be systematically closed.**
**Describe the bug**
A clear and concise description of what the bug is.
@@ -18,8 +20,8 @@ A clear and concise description of what you expected to happen.
If applicable, add screenshots to help explain your problem.
**Logs**
If applicable, copy logs from your console here. Please *do not*
use screenshots of logs, copy them as text.
If applicable, copy **full** logs from your console here. Please *do not*
use screenshots of logs, copy them as text, use gist or attach an *uncompressed* file.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
-4
View File
@@ -29,10 +29,6 @@ jobs:
with:
name: filamat-android-full
path: out/filamat-android-release.aar
- uses: actions/upload-artifact@v1.0.0
with:
name: filamat-android-lite
path: out/filamat-android-lite-release.aar
- uses: actions/upload-artifact@v1.0.0
with:
name: gltfio-android-release
+30
View File
@@ -0,0 +1,30 @@
name: CocoaPods Deploy
# This must be run after the iOS release job has finished, and the iOS release
# asset has been uploaded to Github.
on:
workflow_dispatch:
inputs:
release_tag:
description: 'Release tag to deploy (e.g., v1.42.2)'
required: true
default: 'v1.42.2'
jobs:
cocoapods-deploy:
name: cocoapods-deploy
runs-on: macos-latest
steps:
- name: Check out iOS/CocoaPods directory
uses: Bhacaz/checkout-files@49fc3050859046bf4f4873678d46099985640e89
with:
files: ios/CocoaPods
token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ github.event.inputs.release_tag }}
- name: Move podspec to root
run: mv ios/CocoaPods/*.podspec .
- name: Install CocoaPods
run: gem install cocoapods
- uses: michaelhenry/deploy-to-cocoapods-github-action@745686ab065f90596e0d5cfcf97bb2416d94262e
env:
COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
+33
View File
@@ -0,0 +1,33 @@
name: Npm Deploy
on:
workflow_dispatch:
inputs:
release_tag:
description: 'Release tag to deploy (e.g., v1.42.2)'
required: true
default: 'v1.42.2'
jobs:
npm-deploy:
name: npm-deploy
runs-on: macos-latest
steps:
- uses: actions/checkout@v3.3.0
with:
ref: ${{ github.event.inputs.release_tag }}
# Setup .npmrc file to publish to npm
- uses: actions/setup-node@v3
with:
node-version: '18.x'
registry-url: 'https://registry.npmjs.org'
- name: Run build script
run: |
cd build/web && printf "y" | ./build.sh release
- name: Deploy to npm
run: |
cd out/cmake-webgl-release/web/filament-js
npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+1 -3
View File
@@ -124,7 +124,6 @@ jobs:
cd ../..
mv out/filament-android-release.aar out/filament-${TAG}-android.aar
mv out/filamat-android-release.aar out/filamat-${TAG}-android.aar
mv out/filamat-android-lite-release.aar out/filamat-${TAG}-lite-android.aar
mv out/gltfio-android-release.aar out/gltfio-${TAG}-android.aar
mv out/filament-utils-android-release.aar out/filament-utils-${TAG}-android.aar
- name: Sign sample-gltf-viewer
@@ -206,8 +205,7 @@ jobs:
TAG: ${{ steps.git_ref.outputs.tag }}
run: |
build\windows\build-github.bat release
cd ..\..
move out\filament-windows.tgz out\filament-%TAG%-windows.tgz
move out\filament-windows.tgz out\filament-$Env:TAG-windows.tgz
shell: cmd
- uses: actions/github-script@v6
env:
+4
View File
@@ -16,3 +16,7 @@ settings.json
test*.png
test*.json
results
/compile_commands.json
/.cache
# Nix
/result*
+79 -77
View File
@@ -5,7 +5,7 @@
To build Filament, you must first install the following tools:
- CMake 3.19 (or more recent)
- clang 7.0 (or more recent)
- clang 14.0 (or more recent)
- [ninja 1.10](https://github.com/ninja-build/ninja/wiki/Pre-built-Ninja-packages) (or more recent)
Additional dependencies may be required for your operating system. Please refer to the appropriate
@@ -40,25 +40,27 @@ inside the Filament source tree.
To trigger an incremental debug build:
```
$ ./build.sh debug
```shell
./build.sh debug
```
To trigger an incremental release build:
```
$ ./build.sh release
```shell
./build.sh release
```
To trigger both incremental debug and release builds:
```
$ ./build.sh debug release
```shell
./build.sh debug release
```
If build fails for some reasons, it may leave the `out/` directory in a broken state. You can
force a clean build by adding the `-c` flag in that case.
To install the libraries and executables in `out/debug/` and `out/release/`, add the `-i` flag.
You can force a clean build by adding the `-c` flag. The script offers more features described
by executing `build.sh -h`.
The script offers more features described by executing `build.sh -h`.
### Filament-specific CMake Options
@@ -76,9 +78,9 @@ The following CMake options are boolean options specific to Filament:
To turn an option on or off:
```
$ cd <cmake-build-directory>
$ cmake . -DOPTION=ON # Relace OPTION with the option name, set to ON / OFF
```shell
cd <cmake-build-directory>
cmake . -DOPTION=ON # Replace OPTION with the option name, set to ON / OFF
```
Options can also be set with the CMake GUI.
@@ -87,10 +89,10 @@ Options can also be set with the CMake GUI.
Make sure you've installed the following dependencies:
- `clang-7` or higher
- `clang-14` or higher
- `libglu1-mesa-dev`
- `libc++-7-dev` (`libcxx-devel` and `libcxx-static` on Fedora) or higher
- `libc++abi-7-dev` (`libcxxabi-static` on Fedora) or higher
- `libc++-14-dev` (`libcxx-devel` and `libcxx-static` on Fedora) or higher
- `libc++abi-14-dev` (`libcxxabi-static` on Fedora) or higher
- `ninja-build`
- `libxi-dev`
- `libxcomposite-dev` (`libXcomposite-devel` on Fedora)
@@ -102,38 +104,38 @@ script.
If you'd like to run `cmake` directly rather than using the build script, it can be invoked as
follows, with some caveats that are explained further down.
```
$ mkdir out/cmake-release
$ cd out/cmake-release
$ cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../release/filament ../..
```shell
mkdir out/cmake-release
cd out/cmake-release
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../release/filament ../..
```
Your Linux distribution might default to `gcc` instead of `clang`, if that's the case invoke
`cmake` with the following command:
```
$ mkdir out/cmake-release
$ cd out/cmake-release
# Or use a specific version of clang, for instance /usr/bin/clang-7
$ CC=/usr/bin/clang CXX=/usr/bin/clang++ CXXFLAGS=-stdlib=libc++ \
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../release/filament ../..
```shell
mkdir out/cmake-release
cd out/cmake-release
# Or use a specific version of clang, for instance /usr/bin/clang-14
CC=/usr/bin/clang CXX=/usr/bin/clang++ CXXFLAGS=-stdlib=libc++ \
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../release/filament ../..
```
You can also export the `CC` and `CXX` environment variables to always point to `clang`. Another
solution is to use `update-alternatives` to both change the default compiler, and point to a
specific version of clang:
```
$ update-alternatives --install /usr/bin/clang clang /usr/bin/clang-7 100
$ update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-7 100
$ update-alternatives --install /usr/bin/cc cc /usr/bin/clang 100
$ update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++ 100
```shell
update-alternatives --install /usr/bin/clang clang /usr/bin/clang-14 100
update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-14 100
update-alternatives --install /usr/bin/cc cc /usr/bin/clang 100
update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++ 100
```
Finally, invoke `ninja`:
```
$ ninja
```shell
ninja
```
This will build Filament, its tests and samples, and various host tools.
@@ -143,8 +145,8 @@ This will build Filament, its tests and samples, and various host tools.
To compile Filament you must have the most recent version of Xcode installed and you need to
make sure the command line tools are setup by running:
```
$ xcode-select --install
```shell
xcode-select --install
```
If you wish to run the Vulkan backend instead of the default Metal backend, you must install
@@ -152,11 +154,11 @@ the LunarG SDK, enable "System Global Components", and reboot your machine.
Then run `cmake` and `ninja` to trigger a build:
```
$ mkdir out/cmake-release
$ cd out/cmake-release
$ cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../release/filament ../..
$ ninja
```shell
mkdir out/cmake-release
cd out/cmake-release
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../release/filament ../..
ninja
```
### iOS
@@ -164,24 +166,24 @@ $ ninja
The easiest way to build Filament for iOS is to use `build.sh` and the
`-p ios` flag. For instance to build the debug target:
```
$ ./build.sh -p ios debug
```shell
./build.sh -p ios debug
```
See [ios/samples/README.md](./ios/samples/README.md) for more information.
### Windows
#### Building on Windows with Visual Studio 2019
#### Building on Windows with Visual Studio 2019 or later
Install the following components:
- [Visual Studio 2019](https://www.visualstudio.com/downloads)
- [Windows 10 SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk)
- [Visual Studio 2019 or later](https://www.visualstudio.com/downloads)
- [Windows SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/)
- [Python 3.7](https://www.python.org/ftp/python/3.7.0/python-3.7.0.exe)
- [CMake 3.14 or later](https://github.com/Kitware/CMake/releases/download/v3.14.7/cmake-3.14.7-win64-x64.msi)
The latest Windows SDK can also by installed by opening Visual Studio and selecting _Get Tools and
The latest Windows SDK can also be installed by opening Visual Studio and selecting _Get Tools and
Features..._ under the _Tools_ menu.
By default, Windows treats the file system as case insensitive. Please do not enable case
@@ -191,10 +193,10 @@ using `fsutil.exe file queryCaseSensitiveInfo`.
Next, open `x64 Native Tools Command Prompt for VS 2019`, create a working directory, and run
CMake in it:
```
> mkdir out
> cd out
> cmake ..
```bat
mkdir out
cd out
cmake ..
```
Open the generated solution file `TNT.sln` in Visual Studio.
@@ -204,15 +206,15 @@ target in the _Solution Explorer_ and choose _Build_ to build a specific target.
For example, build the `material_sandbox` sample and run it from the `out` directory with:
```
> samples\Debug\material_sandbox.exe ..\assets\models\monkey\monkey.obj
```bat
samples\Debug\material_sandbox.exe ..\assets\models\monkey\monkey.obj
```
You can also use CMake to invoke the build without opening Visual Studio. For example, from the
`out` folder run the following command.
```
> cmake --build . --target gltf_viewer --config Release
```bat
cmake --build . --target gltf_viewer --config Release
```
### Android
@@ -237,8 +239,8 @@ To build Android on Windows machines, see [android/Windows.md](android/Windows.m
The easiest way to build Filament for Android is to use `build.sh` and the
`-p android` flag. For instance to build the release target:
```
$ ./build.sh -p android release
```shell
./build.sh -p android release
```
Run `build.sh -h` for more information.
@@ -248,23 +250,23 @@ Run `build.sh -h` for more information.
Invoke CMake in a build directory of your choice, inside of filament's directory. The commands
below show how to build Filament for ARM 64-bit (`aarch64`).
```
$ mkdir out/android-build-release-aarch64
$ cd out/android-build-release-aarch64
$ cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=../../build/toolchain-aarch64-linux-android.cmake \
-DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../android-release/filament ../..
```shell
mkdir out/android-build-release-aarch64
cd out/android-build-release-aarch64
cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=../../build/toolchain-aarch64-linux-android.cmake \
-DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../android-release/filament ../..
```
And then invoke `ninja`:
```
$ ninja install
```shell
ninja install
```
or
```
$ ninja install/strip
```shell
ninja install/strip
```
This will generate Filament's Android binaries in `out/android-release`. This location is important
@@ -296,8 +298,8 @@ AAR.
Alternatively you can build the AAR from the command line by executing the following in the
`android/` directory:
```
$ ./gradlew -Pcom.google.android.filament.dist-dir=../../out/android-release/filament assembleRelease
```shell
./gradlew -Pcom.google.android.filament.dist-dir=../../out/android-release/filament assembleRelease
```
The `-Pcom.google.android.filament.dist-dir` can be used to specify a different installation
@@ -311,7 +313,7 @@ sure to add the newly created module as a dependency to your application.
If you do not wish to include all supported ABIs, make sure to create the appropriate flavors in
your Gradle build file. For example:
```
```gradle
flavorDimensions 'cpuArch'
productFlavors {
arm8 {
@@ -353,7 +355,7 @@ started, follow the instructions for building Filament on your platform ([macOS]
Next, you need to install the Emscripten SDK. The following instructions show how to install the
same version that our continuous builds use.
```
```shell
cd <your chosen parent folder for the emscripten SDK>
curl -L https://github.com/emscripten-core/emsdk/archive/refs/tags/3.1.15.zip > emsdk.zip
unzip emsdk.zip ; mv emsdk-* emsdk ; cd emsdk
@@ -364,7 +366,7 @@ source ./emsdk_env.sh
After this you can invoke the [easy build](#easy-build) script as follows:
```
```shell
export EMSDK=<your chosen home for the emscripten SDK>
./build.sh -p webgl release
```
@@ -374,7 +376,7 @@ creates a `samples` folder that can be used as the root of a simple static web s
cannot open the HTML directly from the filesystem due to CORS. We recommend using the emrun tool
to create a quick localhost server:
```
```shell
emrun out/cmake-webgl-release/web/samples --no_browser --port 8000
```
@@ -395,7 +397,7 @@ Some of the samples accept FBX/OBJ meshes while others rely on the `filamesh` fi
generate a `filamesh ` file from an FBX/OBJ asset, run the `filamesh` tool
(`./tools/filamesh/filamesh` in your build directory):
```
```shell
filamesh ./assets/models/monkey/monkey.obj monkey.filamesh
```
@@ -405,7 +407,7 @@ files for the IBL (which are PNGs containing `R11F_G11F_B10F` data) or a path to
containing two `.ktx` files (one for the IBL itself, one for the skybox). To generate an IBL
simply use this command:
```
```shell
cmgen -f ktx -x ./ibls/ my_ibl.exr
```
@@ -427,9 +429,9 @@ value is the desired roughness between 0 and 1.
To generate the documentation you must first install `doxygen` and `graphviz`, then run the
following commands:
```
$ cd filament/filament
$ doxygen docs/doxygen/filament.doxygen
```shell
cd filament/filament
doxygen docs/doxygen/filament.doxygen
```
Finally simply open `docs/html/index.html` in your web browser.
@@ -439,7 +441,7 @@ Finally simply open `docs/html/index.html` in your web browser.
To try out Filament's Vulkan support with SwiftShader, first build SwiftShader and set the
`SWIFTSHADER_LD_LIBRARY_PATH` variable to the folder that contains `libvk_swiftshader.dylib`:
```
```shell
git clone https://github.com/google/swiftshader.git
cd swiftshader/build
cmake .. && make -j
@@ -454,7 +456,7 @@ Continuous testing turnaround can be quite slow if you need to build SwiftShader
provide an Ubuntu-based Docker image that has it already built. The Docker image also includes
everything necessary for building Filament. You can fetch and run the image as follows:
```
```shell
docker pull ghcr.io/filament-assets/swiftshader
docker run -it ghcr.io/filament-assets/swiftshader
```
+36 -11
View File
@@ -3,6 +3,14 @@
# ==================================================================================================
cmake_minimum_required(VERSION 3.19)
# ==================================================================================================
# Toolchain configuration
# ==================================================================================================
if (APPLE AND NOT IOS)
# This must be set before project() is called
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15 CACHE STRING "")
endif()
# ==================================================================================================
# Project declaration
# ==================================================================================================
@@ -33,6 +41,8 @@ option(FILAMENT_LINUX_IS_MOBILE "Treat Linux as Mobile" OFF)
option(FILAMENT_ENABLE_ASAN_UBSAN "Enable Address and Undefined Behavior Sanitizers" OFF)
option(FILAMENT_ENABLE_FEATURE_LEVEL_0 "Enable Feature Level 0" ON)
set(FILAMENT_NDK_VERSION "" CACHE STRING
"Android NDK version or version prefix to be used when building for Android."
)
@@ -57,6 +67,9 @@ set(FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB "8" CACHE STRING
"Size of the Metal handle arena, default 8."
)
# Enable exceptions by default in spirv-cross.
set(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS OFF)
# ==================================================================================================
# CMake policies
# ==================================================================================================
@@ -308,8 +321,15 @@ if (WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_USE_MATH_DEFINES=1")
endif()
set(CMAKE_VERBOSE_MAKEFILE ON)
if (LINUX)
option(USE_STATIC_LIBCXX "Link against the static runtime libraries." ON)
if (DEFINED ENV{NIX_CC})
set(USE_STATIC_LIBCXX OFF)
endif()
if (${USE_STATIC_LIBCXX})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
link_libraries("-static-libgcc -static-libstdc++")
@@ -329,6 +349,7 @@ endif()
if (CYGWIN)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti")
set(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS ON)
endif()
if (MSVC)
@@ -365,6 +386,7 @@ endif()
# saved by -fno-exception and 10 KiB saved by -fno-rtti).
if (ANDROID OR IOS OR WEBGL)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fno-exceptions -fno-rtti")
set(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS ON)
if (ANDROID OR WEBGL)
# Omitting unwind info prevents the generation of readable stack traces in crash reports on iOS
@@ -372,6 +394,13 @@ if (ANDROID OR IOS OR WEBGL)
endif()
endif()
# Turn off exceptions on iOS debug as well. This fixes an availability error we see when using
# std::visit, which is not supported on iOS 11.0 when exceptions are enabled.
if (IOS)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-exceptions")
set(SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS ON)
endif()
# With WebGL, we disable RTTI even for debug builds because we pass emscripten::val back and forth
# between C++ and JavaScript in order to efficiently access typed arrays, which are unbound.
# NOTE: This is not documented in emscripten so we should consider a different approach.
@@ -479,13 +508,6 @@ else()
option(FILAMENT_ENABLE_MATDBG "Enable the material debugger" OFF)
endif()
# By default, link in fgdbg for Desktop + Debug
if (CMAKE_BUILD_TYPE STREQUAL "Debug" AND IS_HOST_PLATFORM)
option(FILAMENT_ENABLE_FGDBG "Enable the framegraph debugger" ON)
else()
option(FILAMENT_ENABLE_FGDBG "Enable the framegraph debugger" OFF)
endif()
# Only optimize materials in Release mode (so error message lines match the source code)
if (CMAKE_BUILD_TYPE MATCHES Release)
option(FILAMENT_DISABLE_MATOPT "Disable material optimizations" OFF)
@@ -516,6 +538,11 @@ if (FILAMENT_SUPPORTS_METAL)
set(MATC_API_FLAGS ${MATC_API_FLAGS} -a metal)
endif()
# Disable ESSL 1.0 code generation.
if (NOT FILAMENT_ENABLE_FEATURE_LEVEL_0)
set(MATC_API_FLAGS ${MATC_API_FLAGS} -1)
endif()
# Enable debug info (preserves names in SPIR-V)
if (FILAMENT_ENABLE_MATDBG)
set(MATC_OPT_FLAGS ${MATC_OPT_FLAGS} -d)
@@ -718,15 +745,13 @@ if (FILAMENT_BUILD_FILAMAT OR IS_HOST_PLATFORM)
if (FILAMENT_ENABLE_MATDBG OR IS_HOST_PLATFORM)
add_subdirectory(${LIBRARIES}/matdbg)
endif()
if (FILAMENT_ENABLE_FGDBG OR IS_HOST_PLATFORM)
add_subdirectory(${LIBRARIES}/fgdbg)
endif()
endif()
if (FILAMENT_SUPPORTS_VULKAN)
add_subdirectory(${LIBRARIES}/bluevk)
add_subdirectory(${EXTERNAL}/vkmemalloc/tnt)
set(SPIRV_HEADERS_SKIP_EXAMPLES ON)
add_subdirectory(${EXTERNAL}/spirv-headers)
endif()
set(FILAMENT_SAMPLES_BINARY_DIR ${PROJECT_BINARY_DIR}/samples)
+1 -1
View File
@@ -27,7 +27,7 @@ again.
## Code Style
See [CodeStyle.md](/CODE_STYLE.md)
See [CODE_STYLE.md](/CODE_STYLE.md)
## Code reviews
+1 -2
View File
@@ -8,5 +8,4 @@ appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut
- engine: a new feature to set a transform on the global-scale fog [⚠️ **Recompile materials**]
- engine: large-scale fog can now be opted-out on a per-renderable basis
- matc: Generate skinning variants for FL0 materials [⚠️ **Recompile materials**]
+4 -4
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.36.0'
implementation 'com.google.android.filament:filament-android:1.48.0'
}
```
@@ -40,6 +40,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
| Artifact | Description |
| ------------- | ------------- |
| [![filament-android](https://maven-badges.herokuapp.com/maven-central/com.google.android.filament/filament-android/badge.svg?subject=filament-android)](https://maven-badges.herokuapp.com/maven-central/com.google.android.filament/filament-android) | The Filament rendering engine itself. |
| [![filament-android-debug](https://maven-badges.herokuapp.com/maven-central/com.google.android.filament/filament-android-debug/badge.svg?subject=filament-android-debug)](https://maven-badges.herokuapp.com/maven-central/com.google.android.filament/filament-android-debug) | Debug version of `filament-android`. |
| [![gltfio-android](https://maven-badges.herokuapp.com/maven-central/com.google.android.filament/gltfio-android/badge.svg?subject=gltfio-android)](https://maven-badges.herokuapp.com/maven-central/com.google.android.filament/gltfio-android) | A glTF 2.0 loader for Filament, depends on `filament-android`. |
| [![filament-utils-android](https://maven-badges.herokuapp.com/maven-central/com.google.android.filament/filament-utils-android/badge.svg?subject=filament-utils-android)](https://maven-badges.herokuapp.com/maven-central/com.google.android.filament/filament-utils-android) | KTX loading, Kotlin math, and camera utilities, depends on `gltfio-android`. |
| [![filamat-android](https://maven-badges.herokuapp.com/maven-central/com.google.android.filament/filamat-android/badge.svg?subject=filamat-android)](https://maven-badges.herokuapp.com/maven-central/com.google.android.filament/filamat-android) | A runtime material builder/compiler. This library is large but contains a full shader compiler/validator/optimizer and supports both OpenGL and Vulkan. |
@@ -49,8 +50,8 @@ Here are all the libraries available in the group `com.google.android.filament`:
iOS projects can use CocoaPods to install the latest release:
```
pod 'Filament', '~> 1.36.0'
```shell
pod 'Filament', '~> 1.48.0'
```
### Snapshots
@@ -312,7 +313,6 @@ and tools.
- `bluegl`: OpenGL bindings for macOS, Linux and Windows
- `bluevk`: Vulkan bindings for macOS, Linux, Windows and Android
- `camutils`: Camera manipulation utilities
- `fgdbg`: Frame Graph inspector and debugger (debug builds only)
- `filabridge`: Library shared by the Filament engine and host tools
- `filaflat`: Serialization/deserialization library used for materials
- `filagui`: Helper library for [Dear ImGui](https://github.com/ocornut/imgui)
+19 -3
View File
@@ -9,11 +9,15 @@ Before starting, ensure that each of these branches is up-to-date with origin:
- rc/$RELEASE
- main
## 0. Make sure the rc/$RELEASE branch has the correct version.
## 0. Check versions.
It should have the version corresponding to its name, $RELEASE.
Make sure the rc/$RELEASE branch has the correct Filament version. It should have the version
corresponding to its name, $RELEASE.
## 1. Bump versions on main to $RELEASE.
Make sure `MATERIAL_VERSION` has been bumped to a new version if this is a MAJOR or MINOR release
(first two version numbers).
## 1. Bump Filament versions on main to $RELEASE.
Checkout main and run the following command to bump Filament's version to $RELEASE:
@@ -124,3 +128,15 @@ Navigate to [Filament's release
workflow](https://github.com/google/filament/actions/workflows/release.yml). Hit the _Run workflow_
dropdown. Modify _Platform to build_ and _Release tag to build_, then hit _Run workflow_. This will
initiate a new release run.
## 11. Kick off the npm and CocoaPods release jobs
Navigate to [Filament's npm deploy
workflow](https://github.com/google/filament/actions/workflows/npm-deploy.yml).
Hit the _Run workflow_ dropdown. Modify _Release tag to deploy_ to the tag corresponding to this
release (for example, v1.42.2).
Navigate to [Filament's CocoaPods deploy
workflow](https://github.com/google/filament/actions/workflows/cocopods-deploy.yml).
Hit the _Run workflow_ dropdown. Modify _Release tag to deploy_ to the tag corresponding to this
release (for example, v1.42.2).
+137
View File
@@ -7,6 +7,143 @@ 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.49.0
- matc: Fix ESSL 1.0 codegen when using external samplers [⚠️ **Recompile materials**]
## v1.48.0
- matc: New option `-1` to disable generation of ESSL 1.0 code in Feature Level 0 materials
- matc: Support optimizations for ESSL 1.0 code [⚠️ **Recompile materials**]
## v1.47.0
- engine: Support up to 4 side-by-side stereoscopic eyes, configurable at Engine creation time. See
`Engine::Config::stereoscopicEyeCount`. [⚠️ **Recompile Materials**]
## v1.46.0
- engine: Allow instantiating Engine at a given feature level via `Engine::Builder::featureLevel`
- matc: Enable `GL_OES_standard_derivatives` extension in ESSL 1.0 shaders
- matc: Fix code generation of double sided and masked materials in ESSL 1.0 shaders
- filagui: Add support for feature level 0
- matc: Add support for post-process materials in feature level 0
- engine: Add `Material::getFeatureLevel()`
- engine: Add missing `Material::getReflectionMode()` method in Java
- engine: Support basic usage of post-processing materials on feature level 0
- engine: Fix critical GLES 2.0 bugs
- engine: Add `FILAMENT_ENABLE_FEATURE_LEVEL_0` build-time option optionally allow building Filament
without FL0 support.
## v1.45.1
- engine: Added parameter for configuring JobSystem thread count
- engine: In Java, introduce Engine.Builder
- gltfio: fix ubershader index for transmission&volume material
- engine: New tone mapper: `AgXTonemapper`.
- matinfo: Add support for viewing ESSL 1.0 shaders
- engine: Add `Renderer::getClearOptions()` [b/243846268]
- engine: Fix stable shadows (again) when an IBL rotation is used
## v1.45.0
- materials: fix alpha masked materials when MSAA is turned on [⚠️ **Recompile materials**]
- materials: better support materials with custom depth [**Recompile Materials**]
- engine: fade shadows at shadowFar distance instead of hard cutoff [⚠️ **New Material Version**]
## v1.44.0
- engine: add support for skinning with more than four bones per vertex.
- engine: remove `BloomOptions::anamorphism` which wasn't working well in most cases [**API CHANGE**]
- engine: new API to return a Material's supported variants, C++ only (b/297456590)
- build: fix emscripten-1.3.46 build
- engine: materials built for feature level 0 can now also be loaded in higher feature levels [⚠️
**New Material Version**]
## v1.43.1
## v1.43.0
- gltfio: Fix possible change of scale sign when decomposing transform matrix for animation
- engine: Fixes "stable" shadows (see b/299310624)
## v1.42.2
- Fix possible NPE when updating fog options from Java/Kotlin
- The `emissive` property was not applied properly to `MASKED` materials, and could cause
dark fringes to appear (recompile materials)
- Allow glTF materials with transmission/volume extensions to choose their alpha mode
instead of forcing `MASKED`
- Fix a crash in gltfio when not using ubershaders
- Use flatmat for mat parameter in jsbinding
- Fix TextureFlags for sheenRoughnessMap when textures of sheenRoughnessMap and sheenColorMap is same
- Directional shadows can now be transformed (b/297095805)
## v1.42.1
- Fix potential `EXC_BAD_ACCESS` with Metal backend: b/297059776
- `setFrameCompletedCallback` now takes a `backend::CallbackHandler`.
## v1.42.0
- engine: add preliminary support for instanced stereoscopic rendering [⚠️ **Recompile materials**]
## v1.41.0
- backend: fix #6997 : picking can fail on Adreno [⚠️ **New Material Version**]
- backend: A partial workaround for PowerVR devices (#5118, b/190221124) [⚠️ **Recompile Materials**]
## v1.40.5
- backend: Disable timer queries on all Mali GPUs (fixes b/233754398)
- engine: Add a way to query the validity of most filament objects (see `Engine::isValid`)
- opengl: fix b/290388359 : possible crash when shutting down the engine
- engine: Improve precision of frame time measurement when using emulated TimerQueries
- backend: Improve frame pacing on Android and Vulkan.
- backend: workaround b/291140208 (gltf_viewer crashes on Nexus 6P)
- engine: support `setDepthFunc` for `MaterialInstance`
- web: Added setDepthFunc()/getDepthFunc() to MaterialInstance
- android: Added setDepthFunc()/getDepthFunc() to MaterialInstance
## v1.40.4
- gltfio: fix crash when compute morph target without material
- matc: fix buggy `variant-filter` flag
- web: Added missing setMat3Parameter()/setMat4Parameter() to MaterialInstance
- opengl: fix b/290670707 : crash when using the blob cache
- engine: fix a crash with `Material::compile()` when a callback is specified
## v1.40.3
## v1.40.2
- rendering: dynamic resolution would not work with a translucent render target and quality > low
- Java/Kotlin: user callbacks were not invoked on successful texture upload
## v1.40.1
## v1.40.0
- matc: fix VSM high precision option on mobile [⚠️ **Recompile materials**]
- vulkan: support sRGB swap chain
- Add new `getMaxAutomaticInstances()` API on `Engine` to get max supported automatic instances.
- UiHelper: fix jank when a `TextureView` is resized (fixes b\282220665)
- backend: parallel shader compilation support. This breaks and improves the recent `Material::compile` API.
## v1.39.0
- matc: workaround a bug in spirv-tools causing vsm to fail [⚠️ **Recompile materials**]
## v1.38.0
- engine: a new feature to set a transform on the global-scale fog [⚠️ **Recompile materials**]
- engine: large-scale fog can now be opted-out on a per-renderable basis
- engine: improve froxelizer resource efficiency [⚠️ **Recompile materials**]
- matc: better accounting and validation of used samplers in user materials
- engine: add support for sampling fog color from a custom texture [⚠️ **Recompile materials**]
- vulkan: introduce new custom swapchain API
- vulkan: new context sharing API
## v1.37.0
- backend: added `Platform` blob cache APIs, typically used to cache programs [⚠️ **Recompile materials**]
+1 -1
View File
@@ -135,7 +135,7 @@ gradlew -Pcom.google.android.filament.dist-dir=..\out\android-release\filament a
If you're only interested in building SDK, you may skip samples build by passing a `com.google.android.filament.skip-samples` flag:
```
gradlew -Pcom.google.android.filament.dist-dir=..\out\android-release\filament assembleRelease -Pfilament_skip_samples
gradlew -Pcom.google.android.filament.dist-dir=..\out\android-release\filament assembleRelease -Pcom.google.android.filament.skip-samples
```
+7 -7
View File
@@ -83,12 +83,12 @@ buildscript {
'minSdk': 19,
'targetSdk': 33,
'compileSdk': 33,
'kotlin': '1.8.20',
'kotlin_coroutines': '1.6.4',
'buildTools': '33.0.2',
'kotlin': '1.9.0',
'kotlin_coroutines': '1.7.2',
'buildTools': '34.0.0',
'ndk': '25.1.8937393',
'androidx_core': '1.10.0',
'androidx_annotations': '1.3.0'
'androidx_core': '1.10.1',
'androidx_annotations': '1.6.0'
]
ext.deps = [
@@ -104,7 +104,7 @@ buildscript {
]
dependencies {
classpath 'com.android.tools.build:gradle:8.0.0'
classpath 'com.android.tools.build:gradle:8.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
}
@@ -152,7 +152,7 @@ buildscript {
}
plugins {
id "io.github.gradle-nexus.publish-plugin" version "1.1.0"
id "io.github.gradle-nexus.publish-plugin" version "1.3.0"
}
// See https://github.com/gradle-nexus/publish-plugin
-3
View File
@@ -6,9 +6,6 @@ option(FILAMENT_ENABLE_MATDBG "Enables Material debugger" OFF)
set(FILAMENT_DIR ${FILAMENT_DIST_DIR})
set(FILAMAT_FLAVOR "filamat")
if(FILAMAT_LITE)
set(FILAMAT_FLAVOR "filamat_lite")
endif()
if (FILAMENT_SUPPORTS_VULKAN)
message("Library filamat ignores Vulkan settings")
+3 -29
View File
@@ -1,29 +1,8 @@
android {
namespace 'com.google.android.filament.filamat'
flavorDimensions "functionality"
productFlavors {
full {
dimension "functionality"
}
lite {
dimension "functionality"
externalNativeBuild {
cmake {
arguments.add("-DFILAMAT_LITE=ON")
}
}
}
}
publishing {
singleVariant("fullRelease") {
withSourcesJar()
withJavadocJar()
}
singleVariant("liteRelease") {
singleVariant("release") {
withSourcesJar()
withJavadocJar()
}
@@ -39,14 +18,9 @@ apply from: rootProject.file('gradle/gradle-mvn-push.gradle')
afterEvaluate { project ->
publishing {
publications {
fullRelease(MavenPublication) {
release(MavenPublication) {
artifactId = POM_ARTIFACT_ID_FULL
from components.fullRelease
}
liteRelease(MavenPublication) {
artifactId = POM_ARTIFACT_ID_LITE
from components.liteRelease
from components.release
}
}
}
@@ -25,15 +25,8 @@
using namespace filament;
using namespace utils;
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_Engine_nCreateEngine(JNIEnv*, jclass, jlong backend,
jlong sharedContext) {
return (jlong) Engine::create((Engine::Backend) backend, nullptr, (void*) sharedContext);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_Engine_nDestroyEngine(JNIEnv*, jclass,
jlong nativeEngine) {
Java_com_google_android_filament_Engine_nDestroyEngine(JNIEnv*, jclass, jlong nativeEngine) {
Engine* engine = (Engine*) nativeEngine;
Engine::destroy(&engine);
}
@@ -278,6 +271,112 @@ Java_com_google_android_filament_Engine_nDestroyEntity(JNIEnv*, jclass,
engine->destroy(entity);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Engine_nIsValidRenderer(JNIEnv*, jclass,
jlong nativeEngine, jlong nativeRenderer) {
Engine* engine = (Engine *)nativeEngine;
return (jboolean)engine->isValid((Renderer*)nativeRenderer);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Engine_nIsValidView(JNIEnv*, jclass,
jlong nativeEngine, jlong nativeView) {
Engine* engine = (Engine *)nativeEngine;
return (jboolean)engine->isValid((View*)nativeView);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Engine_nIsValidScene(JNIEnv*, jclass,
jlong nativeEngine, jlong nativeScene) {
Engine* engine = (Engine *)nativeEngine;
return (jboolean)engine->isValid((Scene*)nativeScene);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Engine_nIsValidFence(JNIEnv*, jclass,
jlong nativeEngine, jlong nativeFence) {
Engine* engine = (Engine *)nativeEngine;
return (jboolean)engine->isValid((Fence*)nativeFence);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Engine_nIsValidStream(JNIEnv*, jclass,
jlong nativeEngine, jlong nativeStream) {
Engine* engine = (Engine *)nativeEngine;
return (jboolean)engine->isValid((Stream*)nativeStream);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Engine_nIsValidIndexBuffer(JNIEnv*, jclass,
jlong nativeEngine, jlong nativeIndexBuffer) {
Engine* engine = (Engine *)nativeEngine;
return (jboolean)engine->isValid((IndexBuffer*)nativeIndexBuffer);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Engine_nIsValidVertexBuffer(JNIEnv*, jclass,
jlong nativeEngine, jlong nativeVertexBuffer) {
Engine* engine = (Engine *)nativeEngine;
return (jboolean)engine->isValid((VertexBuffer*)nativeVertexBuffer);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Engine_nIsValidSkinningBuffer(JNIEnv*, jclass,
jlong nativeEngine, jlong nativeSkinningBuffer) {
Engine* engine = (Engine *)nativeEngine;
return (jboolean)engine->isValid((SkinningBuffer*)nativeSkinningBuffer);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Engine_nIsValidIndirectLight(JNIEnv*, jclass,
jlong nativeEngine, jlong nativeIndirectLight) {
Engine* engine = (Engine *)nativeEngine;
return (jboolean)engine->isValid((IndirectLight*)nativeIndirectLight);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Engine_nIsValidMaterial(JNIEnv*, jclass,
jlong nativeEngine, jlong nativeMaterial) {
Engine* engine = (Engine *)nativeEngine;
return (jboolean)engine->isValid((Material*)nativeMaterial);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Engine_nIsValidSkybox(JNIEnv*, jclass,
jlong nativeEngine, jlong nativeSkybox) {
Engine* engine = (Engine *)nativeEngine;
return (jboolean)engine->isValid((Skybox*)nativeSkybox);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Engine_nIsValidColorGrading(JNIEnv*, jclass,
jlong nativeEngine, jlong nativeColorGrading) {
Engine* engine = (Engine *)nativeEngine;
return (jboolean)engine->isValid((ColorGrading*)nativeColorGrading);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Engine_nIsValidTexture(JNIEnv*, jclass,
jlong nativeEngine, jlong nativeTexture) {
Engine* engine = (Engine *)nativeEngine;
return (jboolean)engine->isValid((Texture*)nativeTexture);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Engine_nIsValidRenderTarget(JNIEnv*, jclass,
jlong nativeEngine, jlong nativeTarget) {
Engine* engine = (Engine *)nativeEngine;
return (jboolean)engine->isValid((RenderTarget*)nativeTarget);
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Engine_nIsValidSwapChain(JNIEnv*, jclass,
jlong nativeEngine, jlong nativeSwapChain) {
Engine* engine = (Engine *)nativeEngine;
return (jboolean)engine->isValid((SwapChain*)nativeSwapChain);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_Engine_nFlushAndWait(JNIEnv*, jclass,
jlong nativeEngine) {
@@ -285,6 +384,13 @@ Java_com_google_android_filament_Engine_nFlushAndWait(JNIEnv*, jclass,
engine->flushAndWait();
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_Engine_nFlush(JNIEnv*, jclass,
jlong nativeEngine) {
Engine* engine = (Engine*) nativeEngine;
engine->flush();
}
// Managers...
extern "C" JNIEXPORT jlong JNICALL
@@ -329,6 +435,13 @@ Java_com_google_android_filament_Engine_nIsAutomaticInstancingEnabled(JNIEnv*, j
return (jboolean)engine->isAutomaticInstancingEnabled();
}
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_Engine_nGetMaxStereoscopicEyes(JNIEnv*, jclass, jlong nativeEngine) {
Engine* engine = (Engine*) nativeEngine;
return (jlong) engine->getMaxStereoscopicEyes();
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_Engine_nGetSupportedFeatureLevel(JNIEnv *, jclass,
jlong nativeEngine) {
@@ -348,4 +461,57 @@ Java_com_google_android_filament_Engine_nGetActiveFeatureLevel(JNIEnv *, jclass,
jlong nativeEngine) {
Engine* engine = (Engine*) nativeEngine;
return (jint)engine->getActiveFeatureLevel();
}
}
extern "C" JNIEXPORT jlong JNICALL Java_com_google_android_filament_Engine_nCreateBuilder(JNIEnv*,
jclass) {
Engine::Builder* builder = new Engine::Builder{};
return (jlong) builder;
}
extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nDestroyBuilder(JNIEnv*,
jclass, jlong nativeBuilder) {
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
delete builder;
}
extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBuilderBackend(
JNIEnv*, jclass, jlong nativeBuilder, jlong backend) {
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
builder->backend((Engine::Backend) backend);
}
extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBuilderConfig(JNIEnv*,
jclass, jlong nativeBuilder, jlong commandBufferSizeMB, jlong perRenderPassArenaSizeMB,
jlong driverHandleArenaSizeMB, jlong minCommandBufferSizeMB, jlong perFrameCommandsSizeMB,
jlong jobSystemThreadCount, jlong stereoscopicEyeCount) {
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
Engine::Config config = {
.commandBufferSizeMB = (uint32_t) commandBufferSizeMB,
.perRenderPassArenaSizeMB = (uint32_t) perRenderPassArenaSizeMB,
.driverHandleArenaSizeMB = (uint32_t) driverHandleArenaSizeMB,
.minCommandBufferSizeMB = (uint32_t) minCommandBufferSizeMB,
.perFrameCommandsSizeMB = (uint32_t) perFrameCommandsSizeMB,
.jobSystemThreadCount = (uint32_t) jobSystemThreadCount,
.stereoscopicEyeCount = (uint8_t) stereoscopicEyeCount,
};
builder->config(&config);
}
extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBuilderFeatureLevel(
JNIEnv*, jclass, jlong nativeBuilder, jint ordinal) {
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
builder->featureLevel((Engine::FeatureLevel)ordinal);
}
extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_Engine_nSetBuilderSharedContext(
JNIEnv*, jclass, jlong nativeBuilder, jlong sharedContext) {
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
builder->sharedContext((void*) sharedContext);
}
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_Engine_nBuilderBuild(JNIEnv*, jclass, jlong nativeBuilder) {
Engine::Builder* builder = (Engine::Builder*) nativeBuilder;
return (jlong) builder->build();
}
@@ -38,7 +38,7 @@ Java_com_google_android_filament_EntityManager_nCreateArray(JNIEnv* env, jclass,
// (which it is), but still.
em->create((size_t) n, reinterpret_cast<Entity *>(entities));
env->ReleaseIntArrayElements(entities_, entities, 0);
env->ReleaseIntArrayElements(entities_, entities, JNI_ABORT);
}
extern "C" JNIEXPORT jint JNICALL
@@ -79,7 +79,8 @@ Java_com_google_android_filament_LightManager_nBuilderShadowOptions(JNIEnv* env,
jfloat shadowFarHint, jboolean stable, jboolean lispsm,
jfloat polygonOffsetConstant, jfloat polygonOffsetSlope,
jboolean screenSpaceContactShadows, jint stepCount,
jfloat maxShadowDistance, jboolean elvsm, jfloat blurWidth, jfloat shadowBulbRadius) {
jfloat maxShadowDistance, jboolean elvsm, jfloat blurWidth, jfloat shadowBulbRadius,
jfloatArray transform) {
LightManager::Builder *builder = (LightManager::Builder *) nativeBuilder;
LightManager::ShadowOptions shadowOptions {
.mapSize = (uint32_t)mapSize,
@@ -102,12 +103,18 @@ Java_com_google_android_filament_LightManager_nBuilderShadowOptions(JNIEnv* env,
},
.shadowBulbRadius = shadowBulbRadius
};
jfloat *nativeSplits = env->GetFloatArrayElements(splitPositions, NULL);
const jsize splitCount = std::min((jsize) 3, env->GetArrayLength(splitPositions));
for (jsize i = 0; i < splitCount; i++) {
shadowOptions.cascadeSplitPositions[i] = nativeSplits[i];
}
std::copy_n(nativeSplits, splitCount, shadowOptions.cascadeSplitPositions);
env->ReleaseFloatArrayElements(splitPositions, nativeSplits, 0);
jfloat* nativeTransform = env->GetFloatArrayElements(transform, NULL);
std::copy_n(nativeTransform,
std::min(4, env->GetArrayLength(transform)),
shadowOptions.transform.xyzw.v);
env->ReleaseFloatArrayElements(transform, nativeTransform, 0);
builder->shadowOptions(shadowOptions);
}
@@ -19,6 +19,7 @@
#include <filament/Material.h>
#include "common/NioUtils.h"
#include "common/CallbackUtils.h"
using namespace filament;
@@ -105,6 +106,22 @@ Java_com_google_android_filament_Material_nGetRefractionType(JNIEnv*, jclass,
return (jint) material->getRefractionType();
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_google_android_filament_Material_nGetReflectionMode(JNIEnv*, jclass,
jlong nativeMaterial) {
Material* material = (Material*) nativeMaterial;
return (jint) material->getReflectionMode();
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_google_android_filament_Material_nGetFeatureLevel(JNIEnv*, jclass,
jlong nativeMaterial) {
Material* material = (Material*) nativeMaterial;
return (jint) material->getFeatureLevel();
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_google_android_filament_Material_nGetVertexDomain(JNIEnv*, jclass,
@@ -255,3 +272,17 @@ Java_com_google_android_filament_Material_nHasParameter(JNIEnv* env, jclass,
env->ReleaseStringUTFChars(name_, name);
return (jboolean) hasParameter;
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_Material_nCompile(JNIEnv *env, jclass clazz,
jlong nativeMaterial, jint priority, jint variants, jobject handler, jobject runnable) {
Material* material = (Material*) nativeMaterial;
JniCallback* jniCallback = JniCallback::make(env, handler, runnable);
material->compile(
(Material::CompilerPriorityQueue) priority,
(UserVariantFilterBit) variants,
jniCallback->getHandler(), [jniCallback](Material*){
JniCallback::postToJavaAndDestroy(jniCallback);
});
}
@@ -205,7 +205,7 @@ Java_com_google_android_filament_MaterialInstance_nSetIntParameterArray(JNIEnv *
break;
}
env->ReleaseIntArrayElements(v_, v, 0);
env->ReleaseIntArrayElements(v_, v, JNI_ABORT);
env->ReleaseStringUTFChars(name_, name);
}
@@ -246,17 +246,21 @@ Java_com_google_android_filament_MaterialInstance_nSetFloatParameterArray(JNIEnv
env->ReleaseStringUTFChars(name_, name);
}
// defined in TextureSampler.cpp
namespace filament::JniUtils {
TextureSampler from_long(jlong params) noexcept;
} // TextureSamplerJniUtils
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_MaterialInstance_nSetParameterTexture(
JNIEnv *env, jclass, jlong nativeMaterialInstance, jstring name_,
jlong nativeTexture, jint sampler_) {
jlong nativeTexture, jlong sampler_) {
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
Texture* texture = (Texture*) nativeTexture;
TextureSampler& sampler = reinterpret_cast<TextureSampler&>(sampler_);
const char *name = env->GetStringUTFChars(name_, 0);
instance->setParameter(name, texture, sampler);
instance->setParameter(name, texture, JniUtils::from_long(sampler_));
env->ReleaseStringUTFChars(name_, name);
}
@@ -357,6 +361,14 @@ Java_com_google_android_filament_MaterialInstance_nSetDepthCulling(JNIEnv*,
instance->setDepthCulling(enable);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_MaterialInstance_nSetDepthFunc(JNIEnv*,
jclass, jlong nativeMaterialInstance, jlong function) {
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
instance->setDepthFunc(static_cast<MaterialInstance::DepthFunc>(function));
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_MaterialInstance_nSetStencilCompareFunction(JNIEnv*, jclass,
@@ -524,3 +536,11 @@ Java_com_google_android_filament_MaterialInstance_nIsDepthCullingEnabled(JNIEnv*
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
return instance->isDepthCullingEnabled();
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_google_android_filament_MaterialInstance_nGetDepthFunc(JNIEnv* env, jclass clazz,
jlong nativeMaterialInstance) {
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
return (jint)instance->getDepthFunc();
}
@@ -71,6 +71,13 @@ Java_com_google_android_filament_Scene_nRemoveEntities(JNIEnv *env, jclass type,
env->ReleaseIntArrayElements(entities, (jint*) nativeEntities, JNI_ABORT);
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_Scene_nGetEntityCount(JNIEnv *env, jclass type,
jlong nativeScene) {
Scene* scene = (Scene*) nativeScene;
return (jint) scene->getEntityCount();
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_Scene_nGetRenderableCount(JNIEnv *env, jclass type,
jlong nativeScene) {
@@ -91,3 +98,22 @@ Java_com_google_android_filament_Scene_nHasEntity(JNIEnv *env, jclass type, jlon
Entity entity = Entity::import(entityId);
return (jboolean) scene->hasEntity(entity);
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_Scene_nGetEntities(JNIEnv *env, jclass ,
jlong nativeScene, jintArray outArray, jint length) {
Scene const* const scene = (Scene*) nativeScene;
if (length < scene->getEntityCount()) {
// should not happen because we already checked on the java side
return JNI_FALSE;
}
jint *out = (jint *) env->GetIntArrayElements(outArray, nullptr);
scene->forEach([out, length, i = 0](Entity entity)mutable {
if (i < length) { // this is just paranoia here
out[i++] = (jint) entity.getId();
}
});
env->ReleaseIntArrayElements(outArray, (jint*) out, 0);
return JNI_TRUE;
}
@@ -27,11 +27,10 @@ extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_SwapChain_nSetFrameCompletedCallback(JNIEnv* env, jclass,
jlong nativeSwapChain, jobject handler, jobject runnable) {
SwapChain* swapChain = (SwapChain*) nativeSwapChain;
auto *callback = JniCallback::make(env, handler, runnable);
swapChain->setFrameCompletedCallback([](void* user) {
JniCallback* callback = (JniCallback*)user;
auto* callback = JniCallback::make(env, handler, runnable);
swapChain->setFrameCompletedCallback(nullptr, [callback](SwapChain* swapChain) {
JniCallback::postToJavaAndDestroy(callback);
}, callback);
});
}
extern "C" JNIEXPORT jboolean JNICALL
@@ -511,9 +511,7 @@ public:
private:
void* mData = nullptr;
jobject mBitmap = nullptr;
jobject mHandler = nullptr;
jobject mCallback = nullptr;
jobject mBitmap{};
AndroidBitmapInfo mInfo{};
};
@@ -18,142 +18,139 @@
#include <filament/TextureSampler.h>
#include <utils/algorithm.h>
using namespace filament;
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_TextureSampler_nCreateSampler(JNIEnv *env, jclass type, jint min,
namespace filament::JniUtils {
jlong to_long(TextureSampler const& sampler) noexcept {
return jlong(utils::bit_cast<uint32_t>(sampler.getSamplerParams()));
}
TextureSampler from_long(jlong params) noexcept {
return TextureSampler{
utils::bit_cast<backend::SamplerParams>(
static_cast<uint32_t>(params))};
}
} // namespace filament::JniUtils
using namespace JniUtils;
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_TextureSampler_nCreateSampler(JNIEnv *, jclass, jint min,
jint max, jint s, jint t, jint r) {
return TextureSampler(static_cast<TextureSampler::MinFilter>(min),
static_cast<TextureSampler::MagFilter>(max), static_cast<TextureSampler::WrapMode>(s),
static_cast<TextureSampler::WrapMode>(t),
static_cast<TextureSampler::WrapMode>(r)).getSamplerParams().u;
TextureSampler sampler(static_cast<TextureSampler::MinFilter>(min),
static_cast<TextureSampler::MagFilter>(max),
static_cast<TextureSampler::WrapMode>(s),
static_cast<TextureSampler::WrapMode>(t),
static_cast<TextureSampler::WrapMode>(r));
return to_long(sampler);
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_TextureSampler_nCreateCompareSampler(JNIEnv *env, jclass type,
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_TextureSampler_nCreateCompareSampler(JNIEnv *, jclass,
jint mode, jint function) {
return TextureSampler(static_cast<TextureSampler::CompareMode>(mode),
static_cast<TextureSampler::CompareFunc>(function)).getSamplerParams().u;
TextureSampler sampler(static_cast<TextureSampler::CompareMode>(mode),
static_cast<TextureSampler::CompareFunc>(function));
return to_long(sampler);
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_TextureSampler_nGetMinFilter(JNIEnv *env, jclass type,
jint sampler_) {
TextureSampler &sampler = reinterpret_cast<TextureSampler &>(sampler_);
return static_cast<jint>(sampler.getMinFilter());
Java_com_google_android_filament_TextureSampler_nGetMinFilter(JNIEnv *, jclass, jlong sampler) {
return static_cast<jint>(from_long(sampler).getMinFilter());
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_TextureSampler_nSetMinFilter(JNIEnv *env, jclass type,
jint sampler_, jint filter) {
TextureSampler &sampler = reinterpret_cast<TextureSampler &>(sampler_);
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_TextureSampler_nSetMinFilter(JNIEnv *, jclass, jlong sampler_, jint filter) {
TextureSampler sampler{from_long(sampler_)};
sampler.setMinFilter(static_cast<TextureSampler::MinFilter>(filter));
return sampler.getSamplerParams().u;
return to_long(sampler);
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_TextureSampler_nGetMagFilter(JNIEnv *env, jclass type,
jint sampler_) {
TextureSampler &sampler = reinterpret_cast<TextureSampler &>(sampler_);
return static_cast<jint>(sampler.getMagFilter());
Java_com_google_android_filament_TextureSampler_nGetMagFilter(JNIEnv *, jclass, jlong sampler) {
return static_cast<jint>(from_long(sampler).getMagFilter());
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_TextureSampler_nSetMagFilter(JNIEnv *env, jclass type,
jint sampler_, jint filter) {
TextureSampler &sampler = reinterpret_cast<TextureSampler &>(sampler_);
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_TextureSampler_nSetMagFilter(JNIEnv *, jclass, jlong sampler_, jint filter) {
TextureSampler sampler{from_long(sampler_)};
sampler.setMagFilter(static_cast<TextureSampler::MagFilter>(filter));
return sampler.getSamplerParams().u;
return to_long(sampler);
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_TextureSampler_nGetWrapModeS(JNIEnv *env, jclass type,
jint sampler_) {
TextureSampler &sampler = reinterpret_cast<TextureSampler &>(sampler_);
return static_cast<jint>(sampler.getWrapModeS());
Java_com_google_android_filament_TextureSampler_nGetWrapModeS(JNIEnv *, jclass, jlong sampler) {
return static_cast<jint>(from_long(sampler).getWrapModeS());
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_TextureSampler_nSetWrapModeS(JNIEnv *env, jclass type,
jint sampler_, jint mode) {
TextureSampler &sampler = reinterpret_cast<TextureSampler &>(sampler_);
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_TextureSampler_nSetWrapModeS(JNIEnv *, jclass, jlong sampler_, jint mode) {
TextureSampler sampler{from_long(sampler_)};
sampler.setWrapModeS(static_cast<TextureSampler::WrapMode>(mode));
return sampler.getSamplerParams().u;
return to_long(sampler);
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_TextureSampler_nGetWrapModeT(JNIEnv *env, jclass type,
jint sampler_) {
TextureSampler &sampler = reinterpret_cast<TextureSampler &>(sampler_);
return static_cast<jint>(sampler.getWrapModeT());
Java_com_google_android_filament_TextureSampler_nGetWrapModeT(JNIEnv *, jclass, jlong sampler) {
return static_cast<jint>(from_long(sampler).getWrapModeT());
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_TextureSampler_nSetWrapModeT(JNIEnv *env, jclass type,
jint sampler_, jint mode) {
TextureSampler &sampler = reinterpret_cast<TextureSampler &>(sampler_);
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_TextureSampler_nSetWrapModeT(JNIEnv *, jclass, jlong sampler_, jint mode) {
TextureSampler sampler{from_long(sampler_)};
sampler.setWrapModeT(static_cast<TextureSampler::WrapMode>(mode));
return sampler.getSamplerParams().u;
return to_long(sampler);
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_TextureSampler_nGetWrapModeR(JNIEnv *env, jclass type,
jint sampler_) {
TextureSampler &sampler = reinterpret_cast<TextureSampler &>(sampler_);
return static_cast<jint>(sampler.getWrapModeR());
Java_com_google_android_filament_TextureSampler_nGetWrapModeR(JNIEnv *, jclass, jlong sampler) {
return static_cast<jint>(from_long(sampler).getWrapModeR());
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_TextureSampler_nSetWrapModeR(JNIEnv *env, jclass type,
jint sampler_, jint mode) {
TextureSampler &sampler = reinterpret_cast<TextureSampler &>(sampler_);
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_TextureSampler_nSetWrapModeR(JNIEnv *, jclass, jlong sampler_, jint mode) {
TextureSampler sampler{from_long(sampler_)};
sampler.setWrapModeR(static_cast<TextureSampler::WrapMode>(mode));
return sampler.getSamplerParams().u;
return to_long(sampler);
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_TextureSampler_nGetCompareMode(JNIEnv *env, jclass type,
jint sampler_) {
TextureSampler &sampler = reinterpret_cast<TextureSampler &>(sampler_);
return static_cast<jint>(sampler.getCompareMode());
Java_com_google_android_filament_TextureSampler_nGetCompareMode(JNIEnv *, jclass, jlong sampler) {
return static_cast<jint>(from_long(sampler).getCompareMode());
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_TextureSampler_nSetCompareMode(JNIEnv *env, jclass type,
jint sampler_, jint mode) {
TextureSampler &sampler = reinterpret_cast<TextureSampler &>(sampler_);
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_TextureSampler_nSetCompareMode(JNIEnv *, jclass, jlong sampler_, jint mode) {
TextureSampler sampler{from_long(sampler_)};
sampler.setCompareMode(static_cast<TextureSampler::CompareMode>(mode),
sampler.getCompareFunc());
return sampler.getSamplerParams().u;
return to_long(sampler);
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_TextureSampler_nGetCompareFunction(JNIEnv *env, jclass type,
jint sampler_) {
TextureSampler &sampler = reinterpret_cast<TextureSampler &>(sampler_);
return static_cast<jint>(sampler.getCompareFunc());
Java_com_google_android_filament_TextureSampler_nGetCompareFunction(JNIEnv *, jclass, jlong sampler) {
return static_cast<jint>(from_long(sampler).getCompareFunc());
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_TextureSampler_nSetCompareFunction(JNIEnv *env, jclass type,
jint sampler_, jint function) {
TextureSampler &sampler = reinterpret_cast<TextureSampler &>(sampler_);
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_TextureSampler_nSetCompareFunction(JNIEnv *, jclass, jlong sampler_, jint function) {
TextureSampler sampler{from_long(sampler_)};
sampler.setCompareMode(sampler.getCompareMode(),
static_cast<TextureSampler::CompareFunc>(function));
return sampler.getSamplerParams().u;
return to_long(sampler);
}
extern "C" JNIEXPORT jfloat JNICALL
Java_com_google_android_filament_TextureSampler_nGetAnisotropy(JNIEnv *env, jclass type,
jint sampler_) {
TextureSampler &sampler = reinterpret_cast<TextureSampler &>(sampler_);
return sampler.getAnisotropy();
Java_com_google_android_filament_TextureSampler_nGetAnisotropy(JNIEnv *, jclass, jlong sampler) {
return from_long(sampler).getAnisotropy();
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_TextureSampler_nSetAnisotropy(JNIEnv *env, jclass type,
jint sampler_, jfloat anisotropy) {
TextureSampler &sampler = reinterpret_cast<TextureSampler &>(sampler_);
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_TextureSampler_nSetAnisotropy(JNIEnv *, jclass, jlong sampler_, jfloat anisotropy) {
TextureSampler sampler{from_long(sampler_)};
sampler.setAnisotropy(anisotropy);
return sampler.getSamplerParams().u;
return to_long(sampler);
}
@@ -47,6 +47,11 @@ Java_com_google_android_filament_ToneMapper_nCreateFilmicToneMapper(JNIEnv*, jcl
return (jlong) new FilmicToneMapper();
}
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_ToneMapper_nCreateAgxToneMapper(JNIEnv*, jclass, jint look) {
return (jlong) new AgxToneMapper(AgxToneMapper::AgxLook(look));
}
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_ToneMapper_nCreateGenericToneMapper(JNIEnv*, jclass,
jfloat contrast, jfloat midGrayIn, jfloat midGrayOut, jfloat hdrMax) {
+15 -3
View File
@@ -282,7 +282,7 @@ Java_com_google_android_filament_View_nSetSSCTOptions(JNIEnv *, jclass, jlong na
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_View_nSetBloomOptions(JNIEnv*, jclass,
jlong nativeView, jlong nativeTexture,
jfloat dirtStrength, jfloat strength, jint resolution, jfloat anamorphism, jint levels,
jfloat dirtStrength, jfloat strength, jint resolution, jint levels,
jint blendMode, jboolean threshold, jboolean enabled, jfloat highlight,
jboolean lensFlare, jboolean starburst, jfloat chromaticAberration, jint ghostCount,
jfloat ghostSpacing, jfloat ghostThreshold, jfloat haloThickness, jfloat haloRadius,
@@ -294,7 +294,6 @@ Java_com_google_android_filament_View_nSetBloomOptions(JNIEnv*, jclass,
.dirtStrength = dirtStrength,
.strength = strength,
.resolution = (uint32_t)resolution,
.anamorphism = anamorphism,
.levels = (uint8_t)levels,
.blendMode = (View::BloomOptions::BlendMode)blendMode,
.threshold = (bool)threshold,
@@ -317,8 +316,9 @@ extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_View_nSetFogOptions(JNIEnv *, jclass , jlong nativeView,
jfloat distance, jfloat maximumOpacity, jfloat height, jfloat heightFalloff, jfloat cutOffDistance,
jfloat r, jfloat g, jfloat b, jfloat density, jfloat inScatteringStart,
jfloat inScatteringSize, jboolean fogColorFromIbl, jboolean enabled) {
jfloat inScatteringSize, jboolean fogColorFromIbl, jlong skyColorNativeObject, jboolean enabled) {
View* view = (View*) nativeView;
Texture* skyColor = (Texture*) skyColorNativeObject;
View::FogOptions options = {
.distance = distance,
.cutOffDistance = cutOffDistance,
@@ -330,6 +330,7 @@ Java_com_google_android_filament_View_nSetFogOptions(JNIEnv *, jclass , jlong na
.inScatteringStart = inScatteringStart,
.inScatteringSize = inScatteringSize,
.fogColorFromIbl = (bool)fogColorFromIbl,
.skyColor = skyColor,
.enabled = (bool)enabled
};
view->setFogOptions(options);
@@ -479,6 +480,17 @@ Java_com_google_android_filament_View_nIsStencilBufferEnabled(JNIEnv *, jclass,
return view->isStencilBufferEnabled();
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_View_nSetStereoscopicOptions(JNIEnv *, jclass, jlong nativeView,
jboolean enabled) {
View* view = (View*) nativeView;
View::StereoscopicOptions options {
.enabled = (bool) enabled
};
view->setStereoscopicOptions(options);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_google_android_filament_View_nSetGuardBandOptions(JNIEnv *, jclass,
@@ -111,6 +111,8 @@ public class Engine {
private long mNativeObject;
private Config mConfig;
@NonNull private final TransformManager mTransformManager;
@NonNull private final LightManager mLightManager;
@NonNull private final RenderableManager mRenderableManager;
@@ -150,16 +152,219 @@ public class Engine {
FEATURE_LEVEL_0,
/** OpenGL ES 3.0 features (default) */
FEATURE_LEVEL_1,
/** OpenGL ES 3.1 features + 16 textures units + cubemap arrays */
FEATURE_LEVEL_2,
/** OpenGL ES 3.1 features + 31 textures units + cubemap arrays */
FEATURE_LEVEL_2
FEATURE_LEVEL_3,
};
private Engine(long nativeEngine) {
/**
* Constructs <code>Engine</code> objects using a builder pattern.
*/
public static class Builder {
@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
private final BuilderFinalizer mFinalizer;
private final long mNativeBuilder;
private Config mConfig;
public Builder() {
mNativeBuilder = nCreateBuilder();
mFinalizer = new BuilderFinalizer(mNativeBuilder);
}
/**
* Sets the {@link Backend} for the Engine.
*
* @param backend Driver backend to use
* @return A reference to this Builder for chaining calls.
*/
public Builder backend(Backend backend) {
nSetBuilderBackend(mNativeBuilder, backend.ordinal());
return this;
}
/**
* Sets a sharedContext for the Engine.
*
* @param sharedContext A platform-dependant OpenGL context used as a shared context
* when creating filament's internal context. On Android this parameter
* <b>must be</b> an instance of {@link android.opengl.EGLContext}.
* @return A reference to this Builder for chaining calls.
*/
public Builder sharedContext(Object sharedContext) {
if (Platform.get().validateSharedContext(sharedContext)) {
nSetBuilderSharedContext(mNativeBuilder,
Platform.get().getSharedContextNativeHandle(sharedContext));
return this;
}
throw new IllegalArgumentException("Invalid shared context " + sharedContext);
}
/**
* Configure the Engine with custom parameters.
*
* @param config A {@link Config} object
* @return A reference to this Builder for chaining calls.
*/
public Builder config(Config config) {
mConfig = config;
nSetBuilderConfig(mNativeBuilder, config.commandBufferSizeMB,
config.perRenderPassArenaSizeMB, config.driverHandleArenaSizeMB,
config.minCommandBufferSizeMB, config.perFrameCommandsSizeMB,
config.jobSystemThreadCount, config.stereoscopicEyeCount);
return this;
}
/**
* Sets the initial featureLevel for the Engine.
*
* @param featureLevel The feature level at which initialize Filament.
* @return A reference to this Builder for chaining calls.
*/
public Builder featureLevel(FeatureLevel featureLevel) {
nSetBuilderFeatureLevel(mNativeBuilder, featureLevel.ordinal());
return this;
}
/**
* Creates an instance of Engine
*
* @return A newly created <code>Engine</code>, or <code>null</code> if the GPU driver couldn't
* be initialized, for instance if it doesn't support the right version of OpenGL or
* OpenGL ES.
*
* @exception IllegalStateException can be thrown if there isn't enough memory to
* allocate the command buffer.
*/
public Engine build() {
long nativeEngine = nBuilderBuild(mNativeBuilder);
if (nativeEngine == 0) throw new IllegalStateException("Couldn't create Engine");
return new Engine(nativeEngine, mConfig);
}
private static class BuilderFinalizer {
private final long mNativeObject;
BuilderFinalizer(long nativeObject) {
mNativeObject = nativeObject;
}
@Override
public void finalize() {
try {
super.finalize();
} catch (Throwable t) { // Ignore
} finally {
nDestroyBuilder(mNativeObject);
}
}
}
}
/**
* Parameters for customizing the initialization of {@link Engine}.
*/
public static class Config {
// #defines in Engine.h
private static final long FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB = 3;
private static final long FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB = 2;
private static final long FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB = 1;
private static final long FILAMENT_COMMAND_BUFFER_SIZE_IN_MB =
FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB * 3;
/**
* Size in MiB of the low-level command buffer arena.
*
* Each new command buffer is allocated from here. If this buffer is too small the program
* might terminate or rendering errors might occur.
*
* This is typically set to minCommandBufferSizeMB * 3, so that up to 3 frames can be
* batched-up at once.
*
* This value affects the application's memory usage.
*/
public long commandBufferSizeMB = FILAMENT_COMMAND_BUFFER_SIZE_IN_MB;
/**
* Size in MiB of the per-frame data arena.
*
* This is the main arena used for allocations when preparing a frame.
* e.g.: Froxel data and high-level commands are allocated from this arena.
*
* If this size is too small, the program will abort on debug builds and have undefined
* behavior otherwise.
*
* This value affects the application's memory usage.
*/
public long perRenderPassArenaSizeMB = FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB;
/**
* Size in MiB of the backend's handle arena.
*
* Backends will fallback to slower heap-based allocations when running out of space and
* log this condition.
*
* If 0, then the default value for the given platform is used
*
* This value affects the application's memory usage.
*/
public long driverHandleArenaSizeMB = 0;
/**
* Minimum size in MiB of a low-level command buffer.
*
* This is how much space is guaranteed to be available for low-level commands when a new
* buffer is allocated. If this is too small, the engine might have to stall to wait for
* more space to become available, this situation is logged.
*
* This value does not affect the application's memory usage.
*/
public long minCommandBufferSizeMB = FILAMENT_MIN_COMMAND_BUFFERS_SIZE_IN_MB;
/**
* Size in MiB of the per-frame high level command buffer.
*
* This buffer is related to the number of draw calls achievable within a frame, if it is
* too small, the program will abort on debug builds and have undefined behavior otherwise.
*
* It is allocated from the 'per-render-pass arena' above. Make sure that at least 1 MiB is
* left in the per-render-pass arena when deciding the size of this buffer.
*
* This value does not affect the application's memory usage.
*/
public long perFrameCommandsSizeMB = FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB;
/**
* Number of threads to use in Engine's JobSystem.
*
* Engine uses a utils::JobSystem to carry out paralleization of Engine workloads. This
* value sets the number of threads allocated for JobSystem. Configuring this value can be
* helpful in CPU-constrained environments where too many threads can cause contention of
* CPU and reduce performance.
*
* The default value is 0, which implies that the Engine will use a heuristic to determine
* the number of threads to use.
*/
public long jobSystemThreadCount = 0;
/**
* The number of eyes to render when stereoscopic rendering is enabled. Supported values are
* between 1 and Engine#getMaxStereoscopicEyes() (inclusive).
*
* @see View#setStereoscopicOptions
* @see Engine#getMaxStereoscopicEyes
*/
public long stereoscopicEyeCount = 2;
}
private Engine(long nativeEngine, Config config) {
mNativeObject = nativeEngine;
mTransformManager = new TransformManager(nGetTransformManager(nativeEngine));
mLightManager = new LightManager(nGetLightManager(nativeEngine));
mRenderableManager = new RenderableManager(nGetRenderableManager(nativeEngine));
mEntityManager = new EntityManager(nGetEntityManager(nativeEngine));
mConfig = config;
}
/**
@@ -177,9 +382,7 @@ public class Engine {
*/
@NonNull
public static Engine create() {
long nativeEngine = nCreateEngine(0, 0);
if (nativeEngine == 0) throw new IllegalStateException("Couldn't create Engine");
return new Engine(nativeEngine);
return new Builder().build();
}
/**
@@ -199,9 +402,9 @@ public class Engine {
*/
@NonNull
public static Engine create(@NonNull Backend backend) {
long nativeEngine = nCreateEngine(backend.ordinal(), 0);
if (nativeEngine == 0) throw new IllegalStateException("Couldn't create Engine");
return new Engine(nativeEngine);
return new Builder()
.backend(backend)
.build();
}
/**
@@ -223,13 +426,9 @@ public class Engine {
*/
@NonNull
public static Engine create(@NonNull Object sharedContext) {
if (Platform.get().validateSharedContext(sharedContext)) {
long nativeEngine = nCreateEngine(0,
Platform.get().getSharedContextNativeHandle(sharedContext));
if (nativeEngine == 0) throw new IllegalStateException("Couldn't create Engine");
return new Engine(nativeEngine);
}
throw new IllegalArgumentException("Invalid shared context " + sharedContext);
return new Builder()
.sharedContext(sharedContext)
.build();
}
/**
@@ -296,17 +495,23 @@ public class Engine {
}
/**
* Activate all features of a given feature level. By default FeatureLevel::FEATURE_LEVEL_1 is
* active. The selected feature level must not be higher than the value returned by
* getActiveFeatureLevel() and it's not possible lower the active feature level.
* Activate all features of a given feature level. If an explicit feature level is not specified
* at Engine initialization time via {@link Builder#featureLevel}, the default feature level is
* {@link FeatureLevel#FEATURE_LEVEL_0} on devices not compatible with GLES 3.0; otherwise, the
* default is {@link FeatureLevel::FEATURE_LEVEL_1}. The selected feature level must not be
* higher than the value returned by {@link #getActiveFeatureLevel} and it's not possible lower
* the active feature level. Additionally, it is not possible to modify the feature level at all
* if the Engine was initialized at {@link FeatureLevel#FEATURE_LEVEL_0}.
*
* @param featureLevel the feature level to activate. If featureLevel is lower than
* getActiveFeatureLevel(), the current (higher) feature level is kept.
* If featureLevel is higher than getSupportedFeatureLevel(), an exception
* is thrown, or the program is terminated if exceptions are disabled.
* @param featureLevel the feature level to activate. If featureLevel is lower than {@link
* #getActiveFeatureLevel}, the current (higher) feature level is kept. If
* featureLevel is higher than {@link #getSupportedFeatureLevel}, or if the
* engine was initialized at feature level 0, an exception is thrown, or the
* program is terminated if exceptions are disabled.
*
* @return the active feature level.
*
* @see Builder#featureLevel
* @see #getSupportedFeatureLevel
* @see #getActiveFeatureLevel
*/
@@ -352,6 +557,37 @@ public class Engine {
return nIsAutomaticInstancingEnabled(getNativeObject());
}
/**
* Retrieves the configuration settings of this {@link Engine}.
*
* This method returns the configuration object that was supplied to the Engine's {@link
* Builder#config} method during the creation of this Engine. If the {@link Builder::config}
* method was not explicitly called (or called with null), this method returns the default
* configuration settings.
*
* @return a {@link Config} object with this Engine's configuration
* @see Builder#config
*/
@NonNull
public Config getConfig() {
if (mConfig == null) {
mConfig = new Config();
}
return mConfig;
}
/**
* Returns the maximum number of stereoscopic eyes supported by Filament. The actual number of
* eyes rendered is set at Engine creation time with the {@link
* Engine#Config#stereoscopicEyeCount} setting.
*
* @return the max number of stereoscopic eyes supported
* @see Engine#Config#stereoscopicEyeCount
*/
public long getMaxStereoscopicEyes() {
return nGetMaxStereoscopicEyes(getNativeObject());
}
// SwapChain
@@ -449,6 +685,141 @@ public class Engine {
swapChain.clearNativeObject();
}
/**
* Returns whether the object is valid.
* @param object Object to check for validity
* @return returns true if the specified object is valid.
*/
public boolean isValidRenderer(@NonNull Renderer object) {
return nIsValidRenderer(getNativeObject(), object.getNativeObject());
}
/**
* Returns whether the object is valid.
* @param object Object to check for validity
* @return returns true if the specified object is valid.
*/
public boolean isValidView(@NonNull View object) {
return nIsValidView(getNativeObject(), object.getNativeObject());
}
/**
* Returns whether the object is valid.
* @param object Object to check for validity
* @return returns true if the specified object is valid.
*/
public boolean isValidScene(@NonNull Scene object) {
return nIsValidScene(getNativeObject(), object.getNativeObject());
}
/**
* Returns whether the object is valid.
* @param object Object to check for validity
* @return returns true if the specified object is valid.
*/
public boolean isValidFence(@NonNull Fence object) {
return nIsValidFence(getNativeObject(), object.getNativeObject());
}
/**
* Returns whether the object is valid.
* @param object Object to check for validity
* @return returns true if the specified object is valid.
*/
public boolean isValidStream(@NonNull Stream object) {
return nIsValidStream(getNativeObject(), object.getNativeObject());
}
/**
* Returns whether the object is valid.
* @param object Object to check for validity
* @return returns true if the specified object is valid.
*/
public boolean isValidIndexBuffer(@NonNull IndexBuffer object) {
return nIsValidIndexBuffer(getNativeObject(), object.getNativeObject());
}
/**
* Returns whether the object is valid.
* @param object Object to check for validity
* @return returns true if the specified object is valid.
*/
public boolean isValidVertexBuffer(@NonNull VertexBuffer object) {
return nIsValidVertexBuffer(getNativeObject(), object.getNativeObject());
}
/**
* Returns whether the object is valid.
* @param object Object to check for validity
* @return returns true if the specified object is valid.
*/
public boolean isValidSkinningBuffer(@NonNull SkinningBuffer object) {
return nIsValidSkinningBuffer(getNativeObject(), object.getNativeObject());
}
/**
* Returns whether the object is valid.
* @param object Object to check for validity
* @return returns true if the specified object is valid.
*/
public boolean isValidIndirectLight(@NonNull IndirectLight object) {
return nIsValidIndirectLight(getNativeObject(), object.getNativeObject());
}
/**
* Returns whether the object is valid.
* @param object Object to check for validity
* @return returns true if the specified object is valid.
*/
public boolean isValidMaterial(@NonNull Material object) {
return nIsValidMaterial(getNativeObject(), object.getNativeObject());
}
/**
* Returns whether the object is valid.
* @param object Object to check for validity
* @return returns true if the specified object is valid.
*/
public boolean isValidSkybox(@NonNull Skybox object) {
return nIsValidSkybox(getNativeObject(), object.getNativeObject());
}
/**
* Returns whether the object is valid.
* @param object Object to check for validity
* @return returns true if the specified object is valid.
*/
public boolean isValidColorGrading(@NonNull ColorGrading object) {
return nIsValidColorGrading(getNativeObject(), object.getNativeObject());
}
/**
* Returns whether the object is valid.
* @param object Object to check for validity
* @return returns true if the specified object is valid.
*/
public boolean isValidTexture(@NonNull Texture object) {
return nIsValidTexture(getNativeObject(), object.getNativeObject());
}
/**
* Returns whether the object is valid.
* @param object Object to check for validity
* @return returns true if the specified object is valid.
*/
public boolean isValidRenderTarget(@NonNull RenderTarget object) {
return nIsValidRenderTarget(getNativeObject(), object.getNativeObject());
}
/**
* Returns whether the object is valid.
* @param object Object to check for validity
* @return returns true if the specified object is valid.
*/
public boolean isValidSwapChain(@NonNull SwapChain object) {
return nIsValidSwapChain(getNativeObject(), object.getNativeObject());
}
// View
/**
@@ -753,6 +1124,18 @@ public class Engine {
nFlushAndWait(getNativeObject());
}
/**
* Kicks the hardware thread (e.g. the OpenGL, Vulkan or Metal thread) but does not wait
* for commands to be either executed or the hardware finished.
*
* <p>This is typically used after creating a lot of objects to start draining the command
* queue which has a limited size.</p>
*/
public void flush() {
nFlush(getNativeObject());
}
@UsedByReflection("TextureHelper.java")
public long getNativeObject() {
if (mNativeObject == 0) {
@@ -779,23 +1162,22 @@ public class Engine {
}
}
private static native long nCreateEngine(long backend, long sharedContext);
private static native void nDestroyEngine(long nativeEngine);
private static native long nGetBackend(long nativeEngine);
private static native long nCreateSwapChain(long nativeEngine, Object nativeWindow, long flags);
private static native long nCreateSwapChainHeadless(long nativeEngine, int width, int height, long flags);
private static native long nCreateSwapChainFromRawPointer(long nativeEngine, long pointer, long flags);
private static native boolean nDestroySwapChain(long nativeEngine, long nativeSwapChain);
private static native long nCreateView(long nativeEngine);
private static native boolean nDestroyView(long nativeEngine, long nativeView);
private static native long nCreateRenderer(long nativeEngine);
private static native boolean nDestroyRenderer(long nativeEngine, long nativeRenderer);
private static native long nCreateCamera(long nativeEngine, int entity);
private static native long nGetCameraComponent(long nativeEngine, int entity);
private static native void nDestroyCameraComponent(long nativeEngine, int entity);
private static native long nCreateScene(long nativeEngine);
private static native boolean nDestroyScene(long nativeEngine, long nativeScene);
private static native long nCreateFence(long nativeEngine);
private static native boolean nDestroyRenderer(long nativeEngine, long nativeRenderer);
private static native boolean nDestroyView(long nativeEngine, long nativeView);
private static native boolean nDestroyScene(long nativeEngine, long nativeScene);
private static native boolean nDestroyFence(long nativeEngine, long nativeFence);
private static native boolean nDestroyStream(long nativeEngine, long nativeStream);
private static native boolean nDestroyIndexBuffer(long nativeEngine, long nativeIndexBuffer);
@@ -808,8 +1190,25 @@ public class Engine {
private static native boolean nDestroyColorGrading(long nativeEngine, long nativeColorGrading);
private static native boolean nDestroyTexture(long nativeEngine, long nativeTexture);
private static native boolean nDestroyRenderTarget(long nativeEngine, long nativeTarget);
private static native boolean nDestroySwapChain(long nativeEngine, long nativeSwapChain);
private static native boolean nIsValidRenderer(long nativeEngine, long nativeRenderer);
private static native boolean nIsValidView(long nativeEngine, long nativeView);
private static native boolean nIsValidScene(long nativeEngine, long nativeScene);
private static native boolean nIsValidFence(long nativeEngine, long nativeFence);
private static native boolean nIsValidStream(long nativeEngine, long nativeStream);
private static native boolean nIsValidIndexBuffer(long nativeEngine, long nativeIndexBuffer);
private static native boolean nIsValidVertexBuffer(long nativeEngine, long nativeVertexBuffer);
private static native boolean nIsValidSkinningBuffer(long nativeEngine, long nativeSkinningBuffer);
private static native boolean nIsValidIndirectLight(long nativeEngine, long nativeIndirectLight);
private static native boolean nIsValidMaterial(long nativeEngine, long nativeMaterial);
private static native boolean nIsValidSkybox(long nativeEngine, long nativeSkybox);
private static native boolean nIsValidColorGrading(long nativeEngine, long nativeColorGrading);
private static native boolean nIsValidTexture(long nativeEngine, long nativeTexture);
private static native boolean nIsValidRenderTarget(long nativeEngine, long nativeTarget);
private static native boolean nIsValidSwapChain(long nativeEngine, long nativeSwapChain);
private static native void nDestroyEntity(long nativeEngine, int entity);
private static native void nFlushAndWait(long nativeEngine);
private static native void nFlush(long nativeEngine);
private static native long nGetTransformManager(long nativeEngine);
private static native long nGetLightManager(long nativeEngine);
private static native long nGetRenderableManager(long nativeEngine);
@@ -817,7 +1216,19 @@ public class Engine {
private static native long nGetEntityManager(long nativeEngine);
private static native void nSetAutomaticInstancingEnabled(long nativeEngine, boolean enable);
private static native boolean nIsAutomaticInstancingEnabled(long nativeEngine);
private static native long nGetMaxStereoscopicEyes(long nativeEngine);
private static native int nGetSupportedFeatureLevel(long nativeEngine);
private static native int nSetActiveFeatureLevel(long nativeEngine, int ordinal);
private static native int nGetActiveFeatureLevel(long nativeEngine);
private static native long nCreateBuilder();
private static native void nDestroyBuilder(long nativeBuilder);
private static native void nSetBuilderBackend(long nativeBuilder, long backend);
private static native void nSetBuilderConfig(long nativeBuilder, long commandBufferSizeMB,
long perRenderPassArenaSizeMB, long driverHandleArenaSizeMB,
long minCommandBufferSizeMB, long perFrameCommandsSizeMB, long jobSystemThreadCount,
long stereoscopicEyeCount);
private static native void nSetBuilderFeatureLevel(long nativeBuilder, int ordinal);
private static native void nSetBuilderSharedContext(long nativeBuilder, long sharedContext);
private static native long nBuilderBuild(long nativeBuilder);
}
@@ -258,6 +258,7 @@ public class LightManager {
* shadows that are too far and wouldn't contribute to the scene much, improving
* performance and quality. This value is always positive.
* Use 0.0f to use the camera far distance.
* This only affect directional lights.
*/
public float shadowFar = 0.0f;
@@ -368,6 +369,17 @@ public class LightManager {
* enabled. (2cm by default).
*/
public float shadowBulbRadius = 0.02f;
/**
* Transforms the shadow direction. Must be a unit quaternion.
* The default is identity.
* Ignored if the light type isn't directional. For artistic use. Use with caution.
* The quaternion is stored as the imaginary part in the first 3 elements and the real
* part in the last element of the transform array.
*/
@NonNull
@Size(min = 4, max = 4)
public float[] transform = { 0.0f, 0.0f, 0.0f, 1.0f };
}
public static class ShadowCascades {
@@ -506,7 +518,7 @@ public class LightManager {
options.polygonOffsetConstant, options.polygonOffsetSlope,
options.screenSpaceContactShadows,
options.stepCount, options.maxShadowDistance,
options.elvsm, options.blurWidth, options.shadowBulbRadius);
options.elvsm, options.blurWidth, options.shadowBulbRadius, options.transform);
return this;
}
@@ -1169,7 +1181,7 @@ public class LightManager {
boolean stable, boolean lispsm,
float polygonOffsetConstant, float polygonOffsetSlope,
boolean screenSpaceContactShadows, int stepCount, float maxShadowDistance,
boolean elvsm, float blurWidth, float shadowBulbRadius);
boolean elvsm, float blurWidth, float shadowBulbRadius, float[] transform);
private static native void nBuilderCastLight(long nativeBuilder, boolean enabled);
private static native void nBuilderPosition(long nativeBuilder, float x, float y, float z);
private static native void nBuilderDirection(long nativeBuilder, float x, float y, float z);
@@ -18,9 +18,11 @@ package com.google.android.filament;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.Size;
import com.google.android.filament.proguard.UsedByNative;
import com.google.android.filament.Engine.FeatureLevel;
import java.nio.Buffer;
import java.util.ArrayList;
@@ -46,6 +48,8 @@ public class Material {
static final BlendingMode[] sBlendingModeValues = BlendingMode.values();
static final RefractionMode[] sRefractionModeValues = RefractionMode.values();
static final RefractionType[] sRefractionTypeValues = RefractionType.values();
static final ReflectionMode[] sReflectionModeValues = ReflectionMode.values();
static final FeatureLevel[] sFeatureLevelValues = FeatureLevel.values();
static final VertexDomain[] sVertexDomainValues = VertexDomain.values();
static final CullingMode[] sCullingModeValues = CullingMode.values();
static final VertexBuffer.VertexAttribute[] sVertexAttributeValues =
@@ -181,6 +185,18 @@ public class Material {
THIN
}
/**
* Supported reflection modes
*
* @see
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/lighting:reflections">
* Lighting: reflections</a>
*/
public enum ReflectionMode {
DEFAULT,
SCREEN_SPACE
}
/**
* Supported types of vertex domains
*
@@ -223,6 +239,31 @@ public class Material {
FRONT_AND_BACK
}
public enum CompilerPriorityQueue {
HIGH,
LOW
}
public static class UserVariantFilterBit {
/** Directional lighting */
public static int DIRECTIONAL_LIGHTING = 0x01;
/** Dynamic lighting */
public static int DYNAMIC_LIGHTING = 0x02;
/** Shadow receiver */
public static int SHADOW_RECEIVER = 0x04;
/** Skinning */
public static int SKINNING = 0x08;
/** Fog */
public static int FOG = 0x10;
/** Variance shadow maps */
public static int VSM = 0x20;
/** Screen-space reflections */
public static int SSR = 0x40;
/** Instanced stereo rendering */
public static int STE = 0x80;
public static int ALL = 0xFF;
}
@UsedByNative("Material.cpp")
public static class Parameter {
private static final Type[] sTypeValues = Type.values();
@@ -337,6 +378,55 @@ public class Material {
}
}
/**
* Asynchronously ensures that a subset of this Material's variants are compiled. After issuing
* several compile() calls in a row, it is recommended to call {@link Engine#flush}
* such that the backend can start the compilation work as soon as possible.
* The provided callback is guaranteed to be called on the main thread after all specified
* variants of the material are compiled. This can take hundreds of milliseconds.
*<p>
* If all the material's variants are already compiled, the callback will be scheduled as
* soon as possible, but this might take a few dozen millisecond, corresponding to how
* many previous frames are enqueued in the backend. This also varies by backend. Therefore,
* it is recommended to only call this method once per material shortly after creation.
*</p>
*<p>
* If the same variant is scheduled for compilation multiple times, the first scheduling
* takes precedence; later scheduling are ignored.
*</p>
*<p>
* caveat: A consequence is that if a variant is scheduled on the low priority queue and later
* scheduled again on the high priority queue, the later scheduling is ignored.
* Therefore, the second callback could be called before the variant is compiled.
* However, the first callback, if specified, will trigger as expected.
*</p>
*<p>
* The callback is guaranteed to be called. If the engine is destroyed while some material
* variants are still compiling or in the queue, these will be discarded and the corresponding
* callback will be called. In that case however the Material pointer passed to the callback
* is guaranteed to be invalid (either because it's been destroyed by the user already, or,
* because it's been cleaned-up by the Engine).
*</p>
*<p>
* {@link UserVariantFilterBit#ALL} should be used with caution. Only variants that an application
* needs should be included in the variants argument. For example, the STE variant is only used
* for stereoscopic rendering. If an application is not planning to render in stereo, this bit
* should be turned off to avoid unnecessary material compilations.
*</p>
* @param priority Which priority queue to use, LOW or HIGH.
* @param variants Variants to include to the compile command.
* @param handler An {@link java.util.concurrent.Executor Executor}. On Android this can also be a {@link android.os.Handler Handler}.
* @param callback callback called on the main thread when the compilation is done on
* by backend.
*/
public void compile(@NonNull CompilerPriorityQueue priority,
int variants,
@Nullable Object handler,
@Nullable Runnable callback) {
nCompile(getNativeObject(), priority.ordinal(), variants, handler, callback);
}
/**
* Creates a new instance of this material. Material instances should be freed using
* {@link Engine#destroyMaterialInstance(MaterialInstance)}.
@@ -437,6 +527,28 @@ public class Material {
return EnumCache.sRefractionTypeValues[nGetRefractionType(getNativeObject())];
}
/**
* Returns the reflection mode of this material.
*
* @see
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/lighting:reflections">
* Lighting: reflections</a>
*/
public ReflectionMode getReflectionMode() {
return EnumCache.sReflectionModeValues[nGetReflectionMode(getNativeObject())];
}
/**
* Returns the minimum required feature level for this material.
*
* @see
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/general:featurelevel">
* General: featureLevel</a>
*/
public FeatureLevel getFeatureLevel() {
return EnumCache.sFeatureLevelValues[nGetFeatureLevel(getNativeObject())];
}
/**
* Returns the vertex domain of this material.
*
@@ -916,6 +1028,7 @@ public class Material {
private static native long nCreateInstanceWithName(long nativeMaterial, @NonNull String name);
private static native long nGetDefaultInstance(long nativeMaterial);
private static native void nCompile(long nativeMaterial, int priority, int variants, Object handler, Runnable runnable);
private static native String nGetName(long nativeMaterial);
private static native int nGetShading(long nativeMaterial);
private static native int nGetInterpolation(long nativeMaterial);
@@ -932,6 +1045,8 @@ public class Material {
private static native float nGetSpecularAntiAliasingThreshold(long nativeMaterial);
private static native int nGetRefractionMode(long nativeMaterial);
private static native int nGetRefractionType(long nativeMaterial);
private static native int nGetReflectionMode(long nativeMaterial);
private static native int nGetFeatureLevel(long nativeMaterial);
private static native int nGetParameterCount(long nativeMaterial);
@@ -625,6 +625,15 @@ public class MaterialInstance {
nSetDepthCulling(getNativeObject(), enable);
}
/**
* Sets the depth comparison function (default is {@link TextureSampler.CompareFunction#GE}).
*
* @param func the depth comparison function
*/
public void setDepthFunc(TextureSampler.CompareFunction func) {
nSetDepthFunc(getNativeObject(), func.ordinal());
}
/**
* Returns whether depth culling is enabled.
*/
@@ -632,6 +641,13 @@ public class MaterialInstance {
return nIsDepthCullingEnabled(getNativeObject());
}
/**
* Returns the depth comparison function.
*/
public TextureSampler.CompareFunction getDepthFunc() {
return TextureSampler.EnumCache.sCompareFunctionValues[nGetDepthFunc(getNativeObject())];
}
/**
* Sets the stencil comparison function (default is {@link TextureSampler.CompareFunction#ALWAYS}).
*
@@ -884,7 +900,7 @@ public class MaterialInstance {
@IntRange(from = 0) int offset, @IntRange(from = 1) int count);
private static native void nSetParameterTexture(long nativeMaterialInstance,
@NonNull String name, long nativeTexture, int sampler);
@NonNull String name, long nativeTexture, long sampler);
private static native void nSetScissor(long nativeMaterialInstance,
@IntRange(from = 0) int left, @IntRange(from = 0) int bottom,
@@ -908,6 +924,7 @@ public class MaterialInstance {
private static native void nSetDepthWrite(long nativeMaterialInstance, boolean enable);
private static native void nSetStencilWrite(long nativeMaterialInstance, boolean enable);
private static native void nSetDepthCulling(long nativeMaterialInstance, boolean enable);
private static native void nSetDepthFunc(long nativeMaterialInstance, long function);
private static native void nSetStencilCompareFunction(long nativeMaterialInstance,
long function, long face);
@@ -939,4 +956,5 @@ public class MaterialInstance {
private static native boolean nIsDepthWriteEnabled(long nativeMaterialInstance);
private static native boolean nIsStencilWriteEnabled(long nativeMaterialInstance);
private static native boolean nIsDepthCullingEnabled(long nativeMaterialInstance);
private static native int nGetDepthFunc(long nativeMaterialInstance);
}
@@ -81,8 +81,6 @@ public class RenderTarget {
/**
* Sets a texture to a given attachment point.
*
* <p>All RenderTargets must have a non-null <code>COLOR</code> attachment.</p>
*
* @param attachment The attachment point of the texture.
* @param texture The associated texture object.
* @return A reference to this Builder for chaining calls.
@@ -16,6 +16,7 @@
package com.google.android.filament;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/**
@@ -146,18 +147,29 @@ public class Scene {
}
/**
* Returns the number of {@link RenderableManager} components in the <code>Scene</code>.
* Returns the total number of Entities in the <code>Scene</code>, whether alive or not.
*
* @return number of {@link RenderableManager} components in the <code>Scene</code>..
* @return the total number of Entities in the <code>Scene</code>.
*/
public int getEntityCount() {
return nGetEntityCount(getNativeObject());
}
/**
* Returns the number of active (alive) {@link RenderableManager} components in the
* <code>Scene</code>.
*
* @return number of {@link RenderableManager} components in the <code>Scene</code>.
*/
public int getRenderableCount() {
return nGetRenderableCount(getNativeObject());
}
/**
* Returns the number of {@link LightManager} components in the <code>Scene</code>.
* Returns the number of active (alive) {@link LightManager} components in the
* <code>Scene</code>.
*
* @return number of {@link LightManager} components in the <code>Scene</code>..
* @return number of {@link LightManager} components in the <code>Scene</code>.
*/
public int getLightCount() {
return nGetLightCount(getNativeObject());
@@ -179,6 +191,52 @@ public class Scene {
return mNativeObject;
}
/**
* Returns the list of all entities in the Scene. If outArray is provided and large enough,
* it is used to store the list and returned, otherwise a new array is allocated and returned.
* @param outArray an array to store the list of entities in the scene.
* @return outArray if it was used or a newly allocated array.
* @see #getEntityCount
*/
public int[] getEntities(@Nullable int[] outArray) {
int c = getEntityCount();
if (outArray == null || outArray.length < c) {
outArray = new int[c];
}
boolean success = nGetEntities(getNativeObject(), outArray, outArray.length);
if (!success) {
throw new IllegalStateException("Error retriving Scene's entities");
}
return outArray;
}
/**
* Returns the list of all entities in the Scene in a newly allocated array.
* @return an array containing the list of all entities in the scene.
* @see #getEntityCount
*/
public int[] getEntities() {
return getEntities(null);
}
public interface EntityProcessor {
void process(@Entity int entity);
}
/**
* Invokes user functor on each entity in the scene.
*
* It is not allowed to add or remove an entity from the scene within the functor.
*
* @param entityProcessor User provided functor called for each entity in the scene
*/
public void forEach(@NonNull EntityProcessor entityProcessor) {
int[] entities = getEntities(null);
for (int entity : entities) {
entityProcessor.process(entity);
}
}
void clearNativeObject() {
mNativeObject = 0;
}
@@ -189,7 +247,9 @@ public class Scene {
private static native void nAddEntities(long nativeScene, int[] entities);
private static native void nRemove(long nativeScene, int entity);
private static native void nRemoveEntities(long nativeScene, int[] entities);
private static native int nGetEntityCount(long nativeScene);
private static native int nGetRenderableCount(long nativeScene);
private static native int nGetLightCount(long nativeScene);
private static native boolean nHasEntity(long nativeScene, int entity);
private static native boolean nGetEntities(long nativeScene, int[] outArray, int length);
}
@@ -103,6 +103,31 @@ public class SwapChain {
*/
public static final long CONFIG_SRGB_COLORSPACE = 0x10;
/**
* Indicates that this SwapChain should allocate a stencil buffer in addition to a depth buffer.
*
* This flag is necessary when using View::setStencilBufferEnabled and rendering directly into
* the SwapChain (when post-processing is disabled).
*
* The specific format of the stencil buffer depends on platform support. The following pixel
* formats are tried, in order of preference:
*
* Depth only (without CONFIG_HAS_STENCIL_BUFFER):
* - DEPTH32F
* - DEPTH24
*
* Depth + stencil (with CONFIG_HAS_STENCIL_BUFFER):
* - DEPTH32F_STENCIL8
* - DEPTH24F_STENCIL8
*
* Note that enabling the stencil buffer may hinder depth precision and should only be used if
* necessary.
*
* @see View#setStencilBufferEnabled
* @see View#setPostProcessingEnabled
*/
public static final long CONFIG_HAS_STENCIL_BUFFER = 0x20;
SwapChain(long nativeSwapChain, Object surface) {
mNativeObject = nativeSwapChain;
mSurface = surface;
@@ -137,10 +162,6 @@ public class SwapChain {
* </p>
*
* <p>
* The FrameCompletedCallback is guaranteed to be called on the main Filament thread.
* </p>
*
* <p>
* Warning: Only Filament's Metal backend supports frame callbacks. Other backends ignore the
* callback (which will never be called) and proceed normally.
* </p>
@@ -849,6 +849,10 @@ public class Texture {
public static final int SAMPLEABLE = 0x10;
/** Texture can be used as a subpass input */
public static final int SUBPASS_INPUT = 0x20;
/** Texture can be used the source of a blit() */
public static final int BLIT_SRC = 0x40;
/** Texture can be used the destination of a blit() */
public static final int BLIT_DST = 0x80;
/** by default textures are <code>UPLOADABLE</code> and <code>SAMPLEABLE</code>*/
public static final int DEFAULT = UPLOADABLE | SAMPLEABLE;
}
@@ -126,7 +126,7 @@ public class TextureSampler {
NEVER
}
int mSampler = 0; // bit field used by native
long mSampler = 0; // bit field used by native
/**
* Initializes the <code>TextureSampler</code> with default values.
@@ -342,26 +342,26 @@ public class TextureSampler {
}
}
private static native int nCreateSampler(int min, int max, int s, int t, int r);
private static native int nCreateCompareSampler(int mode, int function);
private static native long nCreateSampler(int min, int max, int s, int t, int r);
private static native long nCreateCompareSampler(int mode, int function);
private static native int nGetMinFilter(int sampler);
private static native int nSetMinFilter(int sampler, int filter);
private static native int nGetMagFilter(int sampler);
private static native int nSetMagFilter(int sampler, int filter);
private static native int nGetMinFilter(long sampler);
private static native long nSetMinFilter(long sampler, int filter);
private static native int nGetMagFilter(long sampler);
private static native long nSetMagFilter(long sampler, int filter);
private static native int nGetWrapModeS(int sampler);
private static native int nSetWrapModeS(int sampler, int mode);
private static native int nGetWrapModeT(int sampler);
private static native int nSetWrapModeT(int sampler, int mode);
private static native int nGetWrapModeR(int sampler);
private static native int nSetWrapModeR(int sampler, int mode);
private static native int nGetWrapModeS(long sampler);
private static native long nSetWrapModeS(long sampler, int mode);
private static native int nGetWrapModeT(long sampler);
private static native long nSetWrapModeT(long sampler, int mode);
private static native int nGetWrapModeR(long sampler);
private static native long nSetWrapModeR(long sampler, int mode);
private static native int nGetCompareMode(int sampler);
private static native int nSetCompareMode(int sampler, int mode);
private static native int nGetCompareFunction(int sampler);
private static native int nSetCompareFunction(int sampler, int function);
private static native int nGetCompareMode(long sampler);
private static native long nSetCompareMode(long sampler, int mode);
private static native int nGetCompareFunction(long sampler);
private static native long nSetCompareFunction(long sampler, int function);
private static native float nGetAnisotropy(int sampler);
private static native int nSetAnisotropy(int sampler, float anisotropy);
private static native float nGetAnisotropy(long sampler);
private static native long nSetAnisotropy(long sampler, float anisotropy);
}
@@ -100,6 +100,45 @@ public class ToneMapper {
}
}
/**
* AgX tone mapping operator.
*/
public static class Agx extends ToneMapper {
public enum AgxLook {
/**
* Base contrast with no look applied
*/
NONE,
/**
* A punchy and more chroma laden look for sRGB displays
*/
PUNCHY,
/**
* A golden tinted, slightly washed look for BT.1886 displays
*/
GOLDEN
}
/**
* Builds a new AgX tone mapper with no look applied.
*/
public Agx() {
this(AgxLook.NONE);
}
/**
* Builds a new AgX tone mapper.
*
* @param look: an optional creative adjustment to contrast and saturation
*/
public Agx(AgxLook look) {
super(nCreateAgxToneMapper(look.ordinal()));
}
}
/**
* Generic tone mapping operator that gives control over the tone mapping
* curve. This operator can be used to control the aesthetics of the final
@@ -194,6 +233,7 @@ public class ToneMapper {
private static native long nCreateACESToneMapper();
private static native long nCreateACESLegacyToneMapper();
private static native long nCreateFilmicToneMapper();
private static native long nCreateAgxToneMapper(int look);
private static native long nCreateGenericToneMapper(
float contrast, float midGrayIn, float midGrayOut, float hdrMax);
@@ -27,6 +27,8 @@ import static com.google.android.filament.Asserts.assertFloat3In;
import static com.google.android.filament.Asserts.assertFloat4In;
import static com.google.android.filament.Colors.LinearColor;
import com.google.android.filament.proguard.UsedByNative;
/**
* Encompasses all the state needed for rendering a {@link Scene}.
*
@@ -73,6 +75,7 @@ public class View {
private AmbientOcclusionOptions mAmbientOcclusionOptions;
private BloomOptions mBloomOptions;
private FogOptions mFogOptions;
private StereoscopicOptions mStereoscopicOptions;
private RenderTarget mRenderTarget;
private BlendMode mBlendMode;
private DepthOfFieldOptions mDepthOfFieldOptions;
@@ -902,7 +905,7 @@ public class View {
mBloomOptions = options;
nSetBloomOptions(getNativeObject(), options.dirt != null ? options.dirt.getNativeObject() : 0,
options.dirtStrength, options.strength, options.resolution,
options.anamorphism, options.levels, options.blendMode.ordinal(),
options.levels, options.blendMode.ordinal(),
options.threshold, options.enabled, options.highlight,
options.lensFlare, options.starburst, options.chromaticAberration,
options.ghostCount, options.ghostSpacing, options.ghostThreshold,
@@ -966,6 +969,7 @@ public class View {
options.color[0], options.color[1], options.color[2],
options.density, options.inScatteringStart, options.inScatteringSize,
options.fogColorFromIbl,
options.skyColor == null ? 0 : options.skyColor.getNativeObject(),
options.enabled);
}
@@ -1029,7 +1033,8 @@ public class View {
* </p>
*
* <p>
* Post-processing must be enabled in order to use the stencil buffer.
* If post-processing is disabled, then the SwapChain must have the CONFIG_HAS_STENCIL_BUFFER
* flag set in order to use the stencil buffer.
* </p>
*
* <p>
@@ -1051,6 +1056,51 @@ public class View {
return nIsStencilBufferEnabled(getNativeObject());
}
/**
* Sets the stereoscopic rendering options for this view.
*
* <p>
* Currently, only one type of stereoscopic rendering is supported: side-by-side.
* Side-by-side stereo rendering splits the viewport into two halves: a left and right half.
* Eye 0 will render to the left half, while Eye 1 will render into the right half.
* </p>
*
* <p>
* Currently, the following features are not supported with stereoscopic rendering:
* - post-processing
* - shadowing
* - punctual lights
* </p>
*
* <p>
* Stereo rendering depends on device and platform support. To check if stereo rendering is
* supported, use {@link Engine#isStereoSupported()}. If stereo rendering is not supported, then
* the stereoscopic options have no effect.
* </p>
*
* @param options The stereoscopic options to use on this view
* @see #getStereoscopicOptions
*/
public void setStereoscopicOptions(@NonNull StereoscopicOptions options) {
mStereoscopicOptions = options;
nSetStereoscopicOptions(getNativeObject(), options.enabled);
}
/**
* Gets the stereoscopic options.
*
* @return options Stereoscopic options currently set.
* @see #setStereoscopicOptions
*/
@NonNull
public StereoscopicOptions getStereoscopicOptions() {
if (mStereoscopicOptions == null) {
mStereoscopicOptions = new StereoscopicOptions();
}
return mStereoscopicOptions;
}
/**
* A class containing the result of a picking query
*/
@@ -1095,10 +1145,29 @@ public class View {
nPick(getNativeObject(), x, y, handler, internalCallback);
}
@UsedByNative("View.cpp")
private static class InternalOnPickCallback implements Runnable {
private final OnPickCallback mUserCallback;
private final PickingQueryResult mPickingQueryResult = new PickingQueryResult();
@UsedByNative("View.cpp")
@Entity
int mRenderable;
@UsedByNative("View.cpp")
float mDepth;
@UsedByNative("View.cpp")
float mFragCoordsX;
@UsedByNative("View.cpp")
float mFragCoordsY;
@UsedByNative("View.cpp")
float mFragCoordsZ;
public InternalOnPickCallback(OnPickCallback mUserCallback) {
this.mUserCallback = mUserCallback;
}
@Override
public void run() {
mPickingQueryResult.renderable = mRenderable;
@@ -1108,13 +1177,6 @@ public class View {
mPickingQueryResult.fragCoords[2] = mFragCoordsZ;
mUserCallback.onPick(mPickingQueryResult);
}
private final OnPickCallback mUserCallback;
private final PickingQueryResult mPickingQueryResult = new PickingQueryResult();
@Entity int mRenderable;
float mDepth;
float mFragCoordsX;
float mFragCoordsY;
float mFragCoordsZ;
}
/**
@@ -1201,9 +1263,10 @@ public class View {
private static native int nGetAmbientOcclusion(long nativeView);
private static native void nSetAmbientOcclusionOptions(long nativeView, float radius, float bias, float power, float resolution, float intensity, float bilateralThreshold, int quality, int lowPassFilter, int upsampling, boolean enabled, boolean bentNormals, float minHorizonAngleRad);
private static native void nSetSSCTOptions(long nativeView, float ssctLightConeRad, float ssctStartTraceDistance, float ssctContactDistanceMax, float ssctIntensity, float v, float v1, float v2, float ssctDepthBias, float ssctDepthSlopeBias, int ssctSampleCount, int ssctRayCount, boolean ssctEnabled);
private static native void nSetBloomOptions(long nativeView, long dirtNativeObject, float dirtStrength, float strength, int resolution, float anamorphism, int levels, int blendMode, boolean threshold, boolean enabled, float highlight,
private static native void nSetBloomOptions(long nativeView, long dirtNativeObject, float dirtStrength, float strength, int resolution, int levels, int blendMode, boolean threshold, boolean enabled, float highlight,
boolean lensFlare, boolean starburst, float chromaticAberration, int ghostCount, float ghostSpacing, float ghostThreshold, float haloThickness, float haloRadius, float haloThreshold);
private static native void nSetFogOptions(long nativeView, float distance, float maximumOpacity, float height, float heightFalloff, float cutOffDistance, float v, float v1, float v2, float density, float inScatteringStart, float inScatteringSize, boolean fogColorFromIbl, boolean enabled);
private static native void nSetFogOptions(long nativeView, float distance, float maximumOpacity, float height, float heightFalloff, float cutOffDistance, float v, float v1, float v2, float density, float inScatteringStart, float inScatteringSize, boolean fogColorFromIbl, long skyColorNativeObject, boolean enabled);
private static native void nSetStereoscopicOptions(long nativeView, boolean enabled);
private static native void nSetBlendMode(long nativeView, int blendMode);
private static native void nSetDepthOfFieldOptions(long nativeView, float cocScale, float maxApertureDiameter, boolean enabled, int filter,
boolean nativeResolution, int foregroundRingCount, int backgroundRingCount, int fastGatherRingCount, int maxForegroundCOC, int maxBackgroundCOC);
@@ -1338,8 +1401,6 @@ public class View {
* blendMode: Whether the bloom effect is purely additive (false) or mixed with the original
* image (true).
*
* anamorphism: Bloom's aspect ratio (x/y), for artistic purposes.
*
* threshold: When enabled, a threshold at 1.0 is applied on the source image, this is
* useful for artistic reasons and is usually needed when a dirt texture is used.
*
@@ -1377,13 +1438,9 @@ public class View {
/**
* resolution of vertical axis (2^levels to 2048)
*/
public int resolution = 360;
public int resolution = 384;
/**
* bloom x/y aspect-ratio (1/32 to 32)
*/
public float anamorphism = 1.0f;
/**
* number of blur levels (3 to 11)
* number of blur levels (1 to 11)
*/
public int levels = 6;
/**
@@ -1403,6 +1460,17 @@ public class View {
* limit highlights to this value before bloom [10, +inf]
*/
public float highlight = 1000.0f;
/**
* Bloom quality level.
* LOW (default): use a more optimized down-sampling filter, however there can be artifacts
* with dynamic resolution, this can be alleviated by using the homogenous mode.
* MEDIUM: Good balance between quality and performance.
* HIGH: In this mode the bloom resolution is automatically increased to avoid artifacts.
* This mode can be significantly slower on mobile, especially at high resolution.
* This mode greatly improves the anamorphic bloom.
*/
@NonNull
public QualityLevel quality = QualityLevel.LOW;
/**
* enable screen-space lens flare
*/
@@ -1518,9 +1586,31 @@ public class View {
/**
* The fog color will be sampled from the IBL in the view direction and tinted by `color`.
* Depending on the scene this can produce very convincing results.
* This simulate a more anisotropic phase-function.
*
* This simulates a more anisotropic phase-function.
*
* `fogColorFromIbl` is ignored when skyTexture is specified.
*
* @see skyColor
*/
public boolean fogColorFromIbl = false;
/**
* skyTexture must be a mipmapped cubemap. When provided, the fog color will be sampled from
* this texture, higher resolution mip levels will be used for objects at the far clip plane,
* and lower resolution mip levels for objects closer to the camera. The skyTexture should
* typically be heavily blurred; a typical way to produce this texture is to blur the base
* level with a strong gaussian filter or even an irradiance filter and then generate mip
* levels as usual. How blurred the base level is somewhat of an artistic decision.
*
* This simulates a more anisotropic phase-function.
*
* `fogColorFromIbl` is ignored when skyTexture is specified.
*
* @see Texture
* @see fogColorFromIbl
*/
@Nullable
public Texture skyColor = null;
/**
* Enable or disable large-scale fog
*/
@@ -1887,6 +1977,7 @@ public class View {
* PCF with soft shadows and contact hardening
*/
PCSS,
PCFd,
}
/**
@@ -1949,4 +2040,11 @@ public class View {
*/
public float penumbraRatioScale = 1.0f;
}
/**
* Options for stereoscopic (multi-eye) rendering.
*/
public static class StereoscopicOptions {
public boolean enabled = false;
}
}
@@ -22,17 +22,35 @@ import com.google.android.filament.Fence;
public class FilamentHelper {
/**
* Wait for all pending frames to be processed before returning. This is to
* avoid a race between the surface being resized before pending frames are
* rendered into it. This is typically called from {@link UiHelper.RendererCallback#onResized},
* {@link android.view.SurfaceHolder.Callback#surfaceChanged} or
* {@link android.view.TextureView.SurfaceTextureListener#onSurfaceTextureSizeChanged}.
* Wait for all pending frames to be processed before returning. This is to avoid a race
* between the surface being resized before pending frames are rendered into it.
* <p>
* For {@link android.view.TextureView} this must be called before the texture's size is
* reconfigured, which unfortunately is done by the Android framework before
* {@link UiHelper} listeners are invoked. Therefore <code>synchronizePendingFrames</code>
* cannot be called from
* {@link android.view.TextureView.SurfaceTextureListener#onSurfaceTextureSizeChanged}; instead
* a subclass of {@link android.view.TextureView} must be used in order to call it from
* {@link android.view.TextureView#onSizeChanged}:
* </p>
* <pre>
* public class MyTextureView extends TextureView {
* private Engine engine;
* protected void onSizeChanged(int w, int h, int oldw, int oldh) {
* FilamentHelper.synchronizePendingFrames(engine);
* super.onSizeChanged(w, h, oldw, oldh);
* }
* }
* </pre>
*
* Otherwise, this is typically called from {@link UiHelper.RendererCallback#onResized},
* {@link android.view.SurfaceHolder.Callback#surfaceChanged}.
*
* @param engine Filament engine to synchronize
*
* @see UiHelper.RendererCallback#onResized
* @see android.view.SurfaceHolder.Callback#surfaceChanged
* @see android.view.TextureView.SurfaceTextureListener#onSurfaceTextureSizeChanged
* @see android.view.TextureView#onSizeChanged
*/
static public void synchronizePendingFrames(Engine engine) {
Fence fence = engine.createFence();
@@ -182,28 +182,85 @@ public class UiHelper {
void detach();
}
private static class SurfaceViewHandler implements RenderSurface {
private final SurfaceView mSurfaceView;
private class SurfaceViewHandler implements RenderSurface, SurfaceHolder.Callback {
@NonNull private final SurfaceView mSurfaceView;
SurfaceViewHandler(SurfaceView surface) {
mSurfaceView = surface;
SurfaceViewHandler(@NonNull SurfaceView surfaceView) {
mSurfaceView = surfaceView;
@NonNull SurfaceHolder holder = surfaceView.getHolder();
holder.addCallback(this);
if (mDesiredWidth > 0 && mDesiredHeight > 0) {
holder.setFixedSize(mDesiredWidth, mDesiredHeight);
}
// in case the SurfaceView's surface already existed
final Surface surface = holder.getSurface();
if (surface != null && surface.isValid()) {
surfaceCreated(holder);
// there is no way to retrieve the actual PixelFormat, since it is not used
// in the callback, we can use whatever we want.
surfaceChanged(holder, PixelFormat.RGBA_8888,
holder.getSurfaceFrame().width(), holder.getSurfaceFrame().height());
}
}
@Override
public void resize(int width, int height) {
mSurfaceView.getHolder().setFixedSize(width, height);
@NonNull SurfaceHolder holder = mSurfaceView.getHolder();
holder.setFixedSize(width, height);
}
@Override
public void detach() {
@NonNull SurfaceHolder holder = mSurfaceView.getHolder();
holder.removeCallback(this);
}
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
if (LOGGING) Log.d(LOG_TAG, "surfaceCreated()");
createSwapChain(holder.getSurface());
}
@Override
public void surfaceChanged(
@NonNull SurfaceHolder holder, int format, int width, int height) {
// Note: this is always called at least once after surfaceCreated()
if (LOGGING) Log.d(LOG_TAG, "surfaceChanged(" + width + ", " + height + ")");
if (mRenderCallback != null) {
mRenderCallback.onResized(width, height);
}
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
if (LOGGING) Log.d(LOG_TAG, "surfaceDestroyed()");
destroySwapChain();
}
}
private static class SurfaceHolderHandler implements RenderSurface {
private class SurfaceHolderHandler implements RenderSurface, SurfaceHolder.Callback {
private final SurfaceHolder mSurfaceHolder;
SurfaceHolderHandler(SurfaceHolder surface) {
mSurfaceHolder = surface;
SurfaceHolderHandler(@NonNull SurfaceHolder holder) {
mSurfaceHolder = holder;
holder.addCallback(this);
if (mDesiredWidth > 0 && mDesiredHeight > 0) {
holder.setFixedSize(mDesiredWidth, mDesiredHeight);
}
// in case the SurfaceHolder's surface already existed
final Surface surface = holder.getSurface();
if (surface != null && surface.isValid()) {
surfaceCreated(holder);
// there is no way to retrieve the actual PixelFormat, since it is not used
// in the callback, we can use whatever we want.
surfaceChanged(holder, PixelFormat.RGBA_8888,
holder.getSurfaceFrame().width(), holder.getSurfaceFrame().height());
}
}
@Override
@@ -213,30 +270,127 @@ public class UiHelper {
@Override
public void detach() {
mSurfaceHolder.removeCallback(this);
}
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
if (LOGGING) Log.d(LOG_TAG, "surfaceCreated()");
createSwapChain(holder.getSurface());
}
@Override
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
// Note: this is always called at least once after surfaceCreated()
if (LOGGING) Log.d(LOG_TAG, "surfaceChanged(" + width + ", " + height + ")");
if (mRenderCallback != null) {
mRenderCallback.onResized(width, height);
}
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) {
if (LOGGING) Log.d(LOG_TAG, "surfaceDestroyed()");
destroySwapChain();
}
}
private class TextureViewHandler implements RenderSurface {
private class TextureViewHandler implements RenderSurface, TextureView.SurfaceTextureListener {
private final TextureView mTextureView;
private Surface mSurface;
TextureViewHandler(TextureView surface) { mTextureView = surface; }
TextureViewHandler(@NonNull TextureView view) {
mTextureView = view;
mTextureView.setSurfaceTextureListener(this);
// in case the View's SurfaceTexture already existed
if (view.isAvailable()) {
SurfaceTexture surfaceTexture = view.getSurfaceTexture();
if (surfaceTexture != null) {
this.onSurfaceTextureAvailable(surfaceTexture,
mDesiredWidth, mDesiredHeight);
}
}
}
@Override
public void resize(int width, int height) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
mTextureView.getSurfaceTexture().setDefaultBufferSize(width, height);
final SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
if (surfaceTexture != null) {
surfaceTexture.setDefaultBufferSize(width, height);
}
}
if (mRenderCallback != null) {
// the call above won't cause TextureView.onSurfaceTextureSizeChanged()
mRenderCallback.onResized(width, height);
}
// the call above won't cause TextureView.onSurfaceTextureSizeChanged()
mRenderCallback.onResized(width, height);
}
@Override
public void detach() {
mTextureView.setSurfaceTextureListener(null);
setSurface(null);
}
void setSurface(Surface surface) {
@Override
public void onSurfaceTextureAvailable(
@NonNull SurfaceTexture surfaceTexture, int width, int height) {
if (LOGGING) Log.d(LOG_TAG, "onSurfaceTextureAvailable()");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
if (mDesiredWidth > 0 && mDesiredHeight > 0) {
surfaceTexture.setDefaultBufferSize(mDesiredWidth, mDesiredHeight);
}
}
final Surface surface = new Surface(surfaceTexture);
setSurface(surface);
createSwapChain(surface);
if (mRenderCallback != null) {
// Call this the first time because onSurfaceTextureSizeChanged()
// isn't called at initialization time
mRenderCallback.onResized(width, height);
}
}
@Override
public void onSurfaceTextureSizeChanged(
@NonNull SurfaceTexture surfaceTexture, int width, int height) {
if (LOGGING) Log.d(LOG_TAG, "onSurfaceTextureSizeChanged()");
if (mRenderCallback != null) {
if (mDesiredWidth > 0 && mDesiredHeight > 0) {
surfaceTexture.setDefaultBufferSize(mDesiredWidth, mDesiredHeight);
mRenderCallback.onResized(mDesiredWidth, mDesiredHeight);
} else {
mRenderCallback.onResized(width, height);
}
// We must recreate the SwapChain to guarantee that it sees the new size.
// More precisely, for an EGL client, the EGLSurface must be recreated. For
// a Vulkan client, the SwapChain must be recreated. Calling
// onNativeWindowChanged() will accomplish that.
// This requirement comes from SurfaceTexture.setDefaultBufferSize()
// documentation.
final Surface surface = getSurface();
if (surface != null) {
mRenderCallback.onNativeWindowChanged(surface);
}
}
}
@Override
public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surfaceTexture) {
if (LOGGING) Log.d(LOG_TAG, "onSurfaceTextureDestroyed()");
destroySwapChain();
return true;
}
@Override
public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) { }
private void setSurface(@Nullable Surface surface) {
if (surface == null) {
if (mSurface != null) {
mSurface.release();
@@ -244,6 +398,10 @@ public class UiHelper {
}
mSurface = surface;
}
private Surface getSurface() {
return mSurface;
}
}
/**
@@ -294,7 +452,6 @@ public class UiHelper {
/**
* Checks whether we are ready to render into the attached surface.
*
* Using OpenGL ES when this returns true, will result in drawing commands being lost,
* HOWEVER, GLES state will be preserved. This is useful to initialize the engine.
*
@@ -339,7 +496,6 @@ public class UiHelper {
/**
* Controls whether the render target (SurfaceView or TextureView) is opaque or not.
* The render target is considered opaque by default.
*
* Must be called before calling {@link #attachTo(SurfaceView)}, {@link #attachTo(TextureView)},
* or {@link #attachTo(SurfaceHolder)}.
*
@@ -362,10 +518,8 @@ public class UiHelper {
* positioned above other surfaces but below the activity's surface. This property
* only has an effect when used in combination with {@link #setOpaque(boolean) setOpaque(false)}
* and does not affect TextureView targets.
*
* Must be called before calling {@link #attachTo(SurfaceView)}
* or {@link #attachTo(TextureView)}.
*
* Has no effect when using {@link #attachTo(SurfaceHolder)}.
*
* @param overlay Indicates whether the render target should be rendered below the activity's
@@ -386,7 +540,6 @@ public class UiHelper {
/**
* Associate UiHelper with a SurfaceView.
*
* As soon as SurfaceView is ready (i.e. has a Surface), we'll create the
* EGL resources needed, and call user callbacks if needed.
*/
@@ -401,163 +554,32 @@ public class UiHelper {
view.setZOrderOnTop(translucent);
}
int format = isOpaque() ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT;
view.getHolder().setFormat(format);
view.getHolder().setFormat(isOpaque() ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT);
mRenderSurface = new SurfaceViewHandler(view);
final SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (LOGGING) Log.d(LOG_TAG, "surfaceCreated()");
createSwapChain(holder.getSurface());
}
@Override
public void surfaceChanged(
SurfaceHolder holder, int format, int width, int height) {
// Note: this is always called at least once after surfaceCreated()
if (LOGGING) Log.d(LOG_TAG, "surfaceChanged(" + width + ", " + height + ")");
mRenderCallback.onResized(width, height);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (LOGGING) Log.d(LOG_TAG, "surfaceDestroyed()");
destroySwapChain();
}
};
SurfaceHolder holder = view.getHolder();
holder.addCallback(callback);
if (mDesiredWidth > 0 && mDesiredHeight > 0) {
holder.setFixedSize(mDesiredWidth, mDesiredHeight);
}
// in case the SurfaceView's surface already existed
final Surface surface = holder.getSurface();
if (surface != null && surface.isValid()) {
callback.surfaceCreated(holder);
callback.surfaceChanged(holder, format,
holder.getSurfaceFrame().width(), holder.getSurfaceFrame().height());
}
}
}
/**
* Associate UiHelper with a TextureView.
*
* As soon as TextureView is ready (i.e. has a buffer), we'll create the
* EGL resources needed, and call user callbacks if needed.
*/
public void attachTo(@NonNull TextureView view) {
if (attach(view)) {
view.setOpaque(isOpaque());
mRenderSurface = new TextureViewHandler(view);
TextureView.SurfaceTextureListener listener = new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(
SurfaceTexture surfaceTexture, int width, int height) {
if (LOGGING) Log.d(LOG_TAG, "onSurfaceTextureAvailable()");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
if (mDesiredWidth > 0 && mDesiredHeight > 0) {
surfaceTexture.setDefaultBufferSize(mDesiredWidth, mDesiredHeight);
}
}
Surface surface = new Surface(surfaceTexture);
TextureViewHandler textureViewHandler = (TextureViewHandler) mRenderSurface;
textureViewHandler.setSurface(surface);
createSwapChain(surface);
// Call this the first time because onSurfaceTextureSizeChanged()
// isn't called at initialization time
mRenderCallback.onResized(width, height);
}
@Override
public void onSurfaceTextureSizeChanged(
SurfaceTexture surfaceTexture, int width, int height) {
if (LOGGING) Log.d(LOG_TAG, "onSurfaceTextureSizeChanged()");
if (mDesiredWidth > 0 && mDesiredHeight > 0) {
surfaceTexture.setDefaultBufferSize(mDesiredWidth, mDesiredHeight);
mRenderCallback.onResized(mDesiredWidth, mDesiredHeight);
} else {
mRenderCallback.onResized(width, height);
}
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
if (LOGGING) Log.d(LOG_TAG, "onSurfaceTextureDestroyed()");
destroySwapChain();
return true;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) { }
};
view.setSurfaceTextureListener(listener);
// in case the View's SurfaceTexture already existed
if (view.isAvailable()) {
SurfaceTexture surfaceTexture = view.getSurfaceTexture();
listener.onSurfaceTextureAvailable(surfaceTexture, mDesiredWidth, mDesiredHeight);
}
}
}
/**
* Associate UiHelper with a SurfaceHolder.
*
* As soon as a Surface is created, we'll create the
* EGL resources needed, and call user callbacks if needed.
*/
public void attachTo(@NonNull SurfaceHolder holder) {
if (attach(holder)) {
int format = isOpaque() ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT;
holder.setFormat(format);
holder.setFormat(isOpaque() ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT);
mRenderSurface = new SurfaceHolderHandler(holder);
final SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
if (LOGGING) Log.d(LOG_TAG, "surfaceCreated()");
createSwapChain(holder.getSurface());
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// Note: this is always called at least once after surfaceCreated()
if (LOGGING) Log.d(LOG_TAG, "surfaceChanged(" + width + ", " + height + ")");
mRenderCallback.onResized(width, height);
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
if (LOGGING) Log.d(LOG_TAG, "surfaceDestroyed()");
destroySwapChain();
}
};
holder.addCallback(callback);
if (mDesiredWidth > 0 && mDesiredHeight > 0) {
holder.setFixedSize(mDesiredWidth, mDesiredHeight);
}
// in case the SurfaceHolder's surface already existed
final Surface surface = holder.getSurface();
if (surface != null && surface.isValid()) {
callback.surfaceCreated(holder);
callback.surfaceChanged(holder, format,
holder.getSurfaceFrame().width(), holder.getSurfaceFrame().height());
}
}
}
@@ -575,7 +597,9 @@ public class UiHelper {
}
private void createSwapChain(@NonNull Surface surface) {
mRenderCallback.onNativeWindowChanged(surface);
if (mRenderCallback != null) {
mRenderCallback.onNativeWindowChanged(surface);
}
mHasSwapChain = true;
}
@@ -583,7 +607,9 @@ public class UiHelper {
if (mRenderSurface != null) {
mRenderSurface.detach();
}
mRenderCallback.onDetachedFromSurface();
if (mRenderCallback != null) {
mRenderCallback.onDetachedFromSurface();
}
mHasSwapChain = false;
}
}
@@ -12,9 +12,6 @@ android {
}
}
defaultConfig {
missingDimensionStrategy 'functionality', 'full'
}
packagingOptions {
// No need to package up the following shared libs, which arise as a side effect of our
// externalNativeBuild dependencies. When clients pick and choose from project-level gradle
@@ -17,6 +17,8 @@
// Operators +, *, / based on http://half.sourceforge.net/ by Christian Rau
// and licensed under MIT
@file:Suppress("NOTHING_TO_INLINE")
package com.google.android.filament.utils
import com.google.android.filament.utils.Half.Companion.POSITIVE_INFINITY
@@ -191,7 +191,7 @@ class ModelViewer(
asset = assetLoader.createAsset(buffer)
asset?.let { asset ->
resourceLoader.asyncBeginLoad(asset)
animator = asset.getInstance().animator
animator = asset.instance.animator
asset.releaseSourceData()
}
}
@@ -214,7 +214,7 @@ class ModelViewer(
resourceLoader.addResourceData(uri, resourceBuffer)
}
resourceLoader.asyncBeginLoad(asset)
animator = asset.getInstance().animator
animator = asset.instance.animator
asset.releaseSourceData()
}
}
@@ -311,7 +311,7 @@ class ModelViewer(
var count = 0
val popRenderables = { count = asset.popRenderables(readyRenderables); count != 0 }
while (popRenderables()) {
for (i in 0..count - 1) {
for (i in 0 until count) {
val ri = rcm.getInstance(readyRenderables[i])
rcm.setScreenSpaceContactShadows(ri, true)
}
@@ -371,7 +371,7 @@ class ModelViewer(
resourceLoader.addResourceData(uri, buffer)
}
resourceLoader.asyncBeginLoad(asset)
animator = asset.getInstance().animator
animator = asset.instance.animator
asset.releaseSourceData()
}
}
+3
View File
@@ -52,6 +52,7 @@ set(GLTFIO_SRCS
${GLTFIO_DIR}/include/gltfio/FilamentInstance.h
${GLTFIO_DIR}/include/gltfio/MaterialProvider.h
${GLTFIO_DIR}/include/gltfio/NodeManager.h
${GLTFIO_DIR}/include/gltfio/TrsTransformManager.h
${GLTFIO_DIR}/include/gltfio/ResourceLoader.h
${GLTFIO_DIR}/include/gltfio/TextureProvider.h
${GLTFIO_DIR}/include/gltfio/math.h
@@ -69,10 +70,12 @@ set(GLTFIO_SRCS
${GLTFIO_DIR}/src/FilamentAsset.cpp
${GLTFIO_DIR}/src/FilamentInstance.cpp
${GLTFIO_DIR}/src/FNodeManager.h
${GLTFIO_DIR}/src/FTrsTransformManager.h
${GLTFIO_DIR}/src/GltfEnums.h
${GLTFIO_DIR}/src/Ktx2Provider.cpp
${GLTFIO_DIR}/src/MaterialProvider.cpp
${GLTFIO_DIR}/src/NodeManager.cpp
${GLTFIO_DIR}/src/TrsTransformManager.cpp
${GLTFIO_DIR}/src/ResourceLoader.cpp
${GLTFIO_DIR}/src/StbProvider.cpp
${GLTFIO_DIR}/src/TangentsJob.cpp
+3 -9
View File
@@ -1,12 +1,6 @@
android {
namespace 'com.google.android.filament.gltfio'
flavorDimensions "functionality"
productFlavors {
full {
dimension "functionality"
}
}
packagingOptions {
// No need to package up the following shared libs, which arise as a side effect of our
// externalNativeBuild dependencies. When clients pick and choose from project-level gradle
@@ -18,7 +12,7 @@ android {
}
publishing {
singleVariant("fullRelease") {
singleVariant("release") {
withSourcesJar()
withJavadocJar()
}
@@ -36,9 +30,9 @@ apply from: rootProject.file('gradle/gradle-mvn-push.gradle')
afterEvaluate { project ->
publishing {
publications {
fullRelease(MavenPublication) {
release(MavenPublication) {
artifactId = POM_ARTIFACT_ID_FULL
from components.fullRelease
from components.release
}
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.36.0
VERSION_NAME=1.48.0
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
+18 -8
View File
@@ -87,9 +87,9 @@ compile Filament's native library and Filament's AAR for this project. The easie
is to install all the required dependencies and to run the following commands at the root of the
source tree:
```
$ ./build.sh -p desktop -i release
$ ./build.sh -p android release
```shell
./build.sh -p desktop -i release
./build.sh -p android release
```
This will build all the native components and the AAR required by this sample application.
@@ -100,8 +100,8 @@ distribution/install directory for desktop (produced by make/ninja install). Thi
contain `bin/matc` and `bin/cmgen`.
Example:
```
$ ./gradlew -Pfilament_tools_dir=../../dist-release assembleDebug
```shell
./gradlew -Pfilament_tools_dir=../../dist-release assembleDebug
```
## Important: SDK location
@@ -110,14 +110,24 @@ Either ensure your `ANDROID_HOME` environment variable is set or make sure the r
contains a `local.properties` file with the `sdk.dir` property pointing to your installation of
the Android SDK.
## Android Studio
## Compiling
### Android Studio
You must use the latest stable release of Android Studio. To open the project, point Studio to the
`android` folder. After opening the project and syncing to gradle, select the sample of your choice
using the drop-down widget in the toolbar.
## Compiling
To compile and run each sample make sure you have selected the appropriate build variant
(arm7, arm8, x86 or x86_64). If you are not sure you can simply select the "universal"
variant which includes all the other ones.
### Command Line
From the `android` directory in the project root:
```shell
./gradlew :samples:sample-hello-triangle:installDebug
```
Replace `sample-hello-triangle` with your preferred project.
@@ -32,7 +32,6 @@ android {
applicationId "com.google.android.filament.gltf"
minSdkVersion 19
targetSdkVersion versions.targetSdk
missingDimensionStrategy 'functionality', 'full'
}
// NOTE: This is a workaround required because the AGP task collectReleaseDependencies
@@ -26,8 +26,10 @@ import android.widget.TextView
import android.widget.Toast
import com.google.android.filament.Fence
import com.google.android.filament.IndirectLight
import com.google.android.filament.Material
import com.google.android.filament.Skybox
import com.google.android.filament.View
import com.google.android.filament.View.OnPickCallback
import com.google.android.filament.utils.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -56,7 +58,9 @@ class MainActivity : Activity() {
private lateinit var modelViewer: ModelViewer
private lateinit var titlebarHint: TextView
private val doubleTapListener = DoubleTapListener()
private val singleTapListener = SingleTapListener()
private lateinit var doubleTapDetector: GestureDetector
private lateinit var singleTapDetector: GestureDetector
private var remoteServer: RemoteServer? = null
private var statusToast: Toast? = null
private var statusText: String? = null
@@ -77,6 +81,7 @@ class MainActivity : Activity() {
choreographer = Choreographer.getInstance()
doubleTapDetector = GestureDetector(applicationContext, doubleTapListener)
singleTapDetector = GestureDetector(applicationContext, singleTapListener)
modelViewer = ModelViewer(surfaceView)
viewerContent.view = modelViewer.view
@@ -88,6 +93,7 @@ class MainActivity : Activity() {
surfaceView.setOnTouchListener { _, event ->
modelViewer.onTouchEvent(event)
doubleTapDetector.onTouchEvent(event)
singleTapDetector.onTouchEvent(event)
true
}
@@ -229,6 +235,7 @@ class MainActivity : Activity() {
modelViewer.scene.skybox = sky
modelViewer.scene.indirectLight = ibl
viewerContent.indirectLight = ibl
}
}
}
@@ -337,6 +344,11 @@ class MainActivity : Activity() {
remoteServer?.close()
}
override fun onBackPressed() {
super.onBackPressed()
finish()
}
fun loadModelData(message: RemoteServer.ReceivedMessage) {
Log.i(TAG, "Downloaded model ${message.label} (${message.buffer.capacity()} bytes)")
clearStatusText()
@@ -381,6 +393,36 @@ class MainActivity : Activity() {
Log.i(TAG, "The Filament backend took $total ms to load the model geometry.")
modelViewer.engine.destroyFence(it)
loadStartFence = null
val materials = mutableSetOf<Material>()
val rcm = modelViewer.engine.renderableManager
modelViewer.scene.forEach {
val entity = it
if (rcm.hasComponent(entity)) {
val ri = rcm.getInstance(entity)
val c = rcm.getPrimitiveCount(ri)
for (i in 0 until c) {
val mi = rcm.getMaterialInstanceAt(ri, i)
val ma = mi.material
materials.add(ma)
}
}
}
materials.forEach {
it.compile(
Material.CompilerPriorityQueue.HIGH,
Material.UserVariantFilterBit.DIRECTIONAL_LIGHTING or
Material.UserVariantFilterBit.DYNAMIC_LIGHTING or
Material.UserVariantFilterBit.SHADOW_RECEIVER,
null, null)
it.compile(
Material.CompilerPriorityQueue.LOW,
Material.UserVariantFilterBit.FOG or
Material.UserVariantFilterBit.SKINNING or
Material.UserVariantFilterBit.SSR or
Material.UserVariantFilterBit.VSM,
null, null)
}
}
}
@@ -425,4 +467,19 @@ class MainActivity : Activity() {
return super.onDoubleTap(e)
}
}
// Just for testing purposes
inner class SingleTapListener : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapUp(event: MotionEvent): Boolean {
modelViewer.view.pick(
event.x.toInt(),
surfaceView.height - event.y.toInt(),
surfaceView.handler, {
val name = modelViewer.asset!!.getName(it.renderable)
Log.v("Filament", "Picked ${it.renderable}: " + name)
},
)
return super.onSingleTapUp(event)
}
}
}
@@ -20,6 +20,8 @@ import android.animation.ValueAnimator
import android.app.Activity
import android.opengl.Matrix
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.Choreographer
import android.view.Surface
import android.view.SurfaceView
@@ -110,7 +112,7 @@ class MainActivity : Activity() {
}
private fun setupFilament() {
engine = Engine.create()
engine = Engine.Builder().featureLevel(Engine.FeatureLevel.FEATURE_LEVEL_0).build()
renderer = engine.createRenderer()
scene = engine.createScene()
view = engine.createView()
@@ -120,13 +122,8 @@ class MainActivity : Activity() {
private fun setupView() {
scene.skybox = Skybox.Builder().color(0.035f, 0.035f, 0.035f, 1.0f).build(engine)
if (engine.activeFeatureLevel == Engine.FeatureLevel.FEATURE_LEVEL_0) {
// post-processing is not supported at feature level 0
view.isPostProcessingEnabled = false
} else {
// NOTE: Try to disable post-processing (tone-mapping, etc.) to see the difference
// view.isPostProcessingEnabled = false
}
// post-processing is not supported at feature level 0
view.isPostProcessingEnabled = false
// Tell the view which camera we want to use
view.camera = camera
@@ -160,12 +157,16 @@ class MainActivity : Activity() {
}
private fun loadMaterial() {
var name = "materials/baked_color.filamat"
if (engine.activeFeatureLevel == Engine.FeatureLevel.FEATURE_LEVEL_0) {
name = "materials/baked_color_es2.filamat"
}
readUncompressedAsset(name).let {
readUncompressedAsset("materials/baked_color.filamat").let {
material = Material.Builder().payload(it, it.remaining()).build(engine)
material.compile(
Material.CompilerPriorityQueue.HIGH,
Material.UserVariantFilterBit.ALL,
Handler(Looper.getMainLooper())) {
android.util.Log.i("hellotriangle",
"Material " + material.name + " compiled.")
}
engine.flush()
}
}
@@ -17,7 +17,8 @@ material {
],
// This material disables all lighting
shadingModel : unlit
shadingModel : unlit,
featureLevel : 0
}
fragment {
@@ -1,33 +0,0 @@
// Simple unlit material that uses the colors associated with each vertex.
//
// This source material must be compiled to a binary material using the matc tool.
// The command used to compile this material is:
// matc -p mobile -a opengl -o app/src/main/assets/baked_color.filamat app/src/materials/baked_color.mat
//
// See build.gradle for an example of how to compile materials automatically
// Please refer to the documentation for more information about matc and the materials system.
material {
name : baked_color,
// Lists the required vertex attributes
// Here we only need a color (RGBA)
requires : [
color
],
// This material disables all lighting
shadingModel : unlit,
featureLevel : 0
}
fragment {
void material(inout MaterialInputs material) {
// You must always call the prepareMaterial() function
prepareMaterial(material);
// We set the material's color to the color interpolated from
// the model's vertices
material.baseColor = getColor();
}
}
@@ -118,9 +118,10 @@ class MainActivity : Activity() {
}
private fun setupView() {
val ssaoOptions = view.ambientOcclusionOptions
ssaoOptions.enabled = true
view.ambientOcclusionOptions = ssaoOptions
// ambient occlusion is the cheapest effect that adds a lot of quality
view.ambientOcclusionOptions = view.ambientOcclusionOptions.apply {
enabled = true
}
// NOTE: Try to disable post-processing (tone-mapping, etc.) to see the difference
// view.isPostProcessingEnabled = false
@@ -32,13 +32,6 @@ android {
targetSdkVersion versions.targetSdk
}
// The filamat library has two variants: full and lite. Here we default to the "full" variant.
// Replace "full" with "lite" to use the filamat-lite variant, which has a smaller binary size
// but comes with certain restrictions. See "Filamat Lite" in libs/filamat/README.md.
defaultConfig {
missingDimensionStrategy 'functionality', 'full'
}
// NOTE: This is a workaround required because the AGP task collectReleaseDependencies
// is not configuration-cache friendly yet; this is only useful for Play publication
dependenciesInfo {
@@ -33,7 +33,6 @@ android {
applicationId "com.google.android.filament.textured"
minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk
missingDimensionStrategy 'functionality', 'full'
}
// NOTE: This is a workaround required because the AGP task collectReleaseDependencies
@@ -231,7 +231,7 @@ class MainActivity : Activity() {
animator.repeatCount = ValueAnimator.INFINITE
animator.addUpdateListener { a ->
val v = (a.animatedValue as Float)
camera.lookAt(cos(v) * 4.5, 1.5, sin(v) * 4.5, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
camera.lookAt(cos(v) * 5.5, 1.5, sin(v) * 5.5, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
}
animator.start()
}
@@ -253,7 +253,7 @@ class MainActivity : Activity() {
// Stop the animation and any pending frame
choreographer.removeFrameCallback(frameScheduler)
animator.cancel();
animator.cancel()
// Always detach the surface before destroying the engine
uiHelper.detach()
@@ -140,9 +140,9 @@ class MainActivity : Activity() {
camera = engine.createCamera(engine.entityManager.create())
// clear the swapchain with transparent pixels
val options = renderer.clearOptions
options.clear = true
renderer.clearOptions = options
renderer.clearOptions = renderer.clearOptions.apply {
clear = true
}
}
private fun setupView() {
+13
View File
@@ -0,0 +1,13 @@
[book]
authors = ["Eliza Velasquez"]
language = "en"
multilingual = false
src = "mdbook"
title = "Filament"
[build]
build-dir = "docs"
create-missing = false
[output.html]
mathjax-support = true
+69 -45
View File
@@ -90,8 +90,8 @@ function print_help {
echo " Desktop matc target, release build:"
echo " \$ ./$self_name release matc"
echo ""
echo " Build gltf_viewer then immediately run it with no arguments:"
echo " \$ ./$self_name release run_gltf_viewer"
echo " Build gltf_viewer:"
echo " \$ ./$self_name release gltf_viewer"
echo ""
}
@@ -172,8 +172,6 @@ MATOPT_GRADLE_OPTION=""
ASAN_UBSAN_OPTION=""
FGDBG_OPTION="-DFILAMENT_ENABLE_FGDBG=OFF"
IOS_BUILD_SIMULATOR=false
BUILD_UNIVERSAL_LIBRARIES=false
@@ -193,6 +191,7 @@ function build_clean {
rm -Rf android/filamat-android/build android/filamat-android/.externalNativeBuild android/filamat-android/.cxx
rm -Rf android/gltfio-android/build android/gltfio-android/.externalNativeBuild android/gltfio-android/.cxx
rm -Rf android/filament-utils-android/build android/filament-utils-android/.externalNativeBuild android/filament-utils-android/.cxx
rm -f compile_commands.json
}
function build_clean_aggressive {
@@ -212,13 +211,10 @@ function build_desktop_target {
echo "Building ${lc_target} in out/cmake-${lc_target}..."
mkdir -p "out/cmake-${lc_target}"
cd "out/cmake-${lc_target}"
pushd "out/cmake-${lc_target}" > /dev/null
# On macOS, set the deployment target to 10.15.
local lc_name=$(echo "${UNAME}" | tr '[:upper:]' '[:lower:]')
if [[ "${lc_name}" == "darwin" ]]; then
local deployment_target="-DCMAKE_OSX_DEPLOYMENT_TARGET=10.15"
if [[ "${BUILD_UNIVERSAL_LIBRARIES}" == "true" ]]; then
local architectures="-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64"
fi
@@ -235,10 +231,10 @@ function build_desktop_target {
${MATDBG_OPTION} \
${MATOPT_OPTION} \
${ASAN_UBSAN_OPTION} \
${FGDBG_OPTION} \
${deployment_target} \
${architectures} \
../..
ln -sf "out/cmake-${lc_target}/compile_commands.json" \
../../compile_commands.json
fi
${BUILD_COMMAND} ${build_targets}
@@ -250,12 +246,13 @@ function build_desktop_target {
if [[ -d "../${lc_target}/filament" ]]; then
if [[ "${ISSUE_ARCHIVES}" == "true" ]]; then
echo "Generating out/filament-${lc_target}-${LC_UNAME}.tgz..."
cd "../${lc_target}"
pushd "../${lc_target}" > /dev/null
tar -czvf "../filament-${lc_target}-${LC_UNAME}.tgz" filament
popd > /dev/null
fi
fi
cd ../..
popd > /dev/null
}
function build_desktop {
@@ -273,7 +270,7 @@ function build_webgl_with_target {
echo "Building WebGL ${lc_target}..."
mkdir -p "out/cmake-webgl-${lc_target}"
cd "out/cmake-webgl-${lc_target}"
pushd "out/cmake-webgl-${lc_target}" > /dev/null
if [[ ! "${BUILD_TARGETS}" ]]; then
BUILD_TARGETS=${BUILD_CUSTOM_TARGETS}
@@ -293,6 +290,8 @@ function build_webgl_with_target {
-DCMAKE_INSTALL_PREFIX="../webgl-${lc_target}/filament" \
-DWEBGL=1 \
../..
ln -sf "out/cmake-webgl-${lc_target}/compile_commands.json" \
../../compile_commands.json
${BUILD_COMMAND} ${BUILD_TARGETS}
)
fi
@@ -310,17 +309,17 @@ function build_webgl_with_target {
if [[ "${ISSUE_ARCHIVES}" == "true" ]]; then
echo "Generating out/filament-${lc_target}-web.tgz..."
cd web/filament-js
pushd web/filament-js > /dev/null
tar -cvf "../../../filament-${lc_target}-web.tar" filament.js
tar -rvf "../../../filament-${lc_target}-web.tar" filament.wasm
tar -rvf "../../../filament-${lc_target}-web.tar" filament.d.ts
cd -
popd > /dev/null
gzip -c "../filament-${lc_target}-web.tar" > "../filament-${lc_target}-web.tgz"
rm "../filament-${lc_target}-web.tar"
fi
fi
cd ../..
popd > /dev/null
}
function build_webgl {
@@ -351,7 +350,7 @@ function build_android_target {
echo "Building Android ${lc_target} (${arch})..."
mkdir -p "out/cmake-android-${lc_target}-${arch}"
cd "out/cmake-android-${lc_target}-${arch}"
pushd "out/cmake-android-${lc_target}-${arch}" > /dev/null
if [[ ! -d "CMakeFiles" ]] || [[ "${ISSUE_CMAKE_ALWAYS}" == "true" ]]; then
cmake \
@@ -363,15 +362,16 @@ function build_android_target {
-DCMAKE_TOOLCHAIN_FILE="../../build/toolchain-${arch}-linux-android.cmake" \
${MATDBG_OPTION} \
${MATOPT_OPTION} \
${FGDBG_OPTION} \
${VULKAN_ANDROID_OPTION} \
../..
ln -sf "out/cmake-android-${lc_target}-${arch}/compile_commands.json" \
../../compile_commands.json
fi
# We must always install Android libraries to build the AAR
${BUILD_COMMAND} install
cd ../..
popd > /dev/null
}
function build_android_arch {
@@ -392,9 +392,9 @@ function archive_android {
if [[ -d "out/android-${lc_target}/filament" ]]; then
if [[ "${ISSUE_ARCHIVES}" == "true" ]]; then
echo "Generating out/filament-android-${lc_target}-${LC_UNAME}.tgz..."
cd "out/android-${lc_target}"
pushd "out/android-${lc_target}" > /dev/null
tar -czvf "../filament-android-${lc_target}-${LC_UNAME}.tgz" filament
cd ../..
popd > /dev/null
fi
fi
}
@@ -472,7 +472,7 @@ function build_android {
archive_android "Release"
fi
cd android
pushd android > /dev/null
if [[ "${ISSUE_DEBUG_BUILD}" == "true" ]]; then
./gradlew \
@@ -502,13 +502,13 @@ function build_android {
if [[ "${INSTALL_COMMAND}" ]]; then
echo "Installing out/filamat-android-debug.aar..."
cp filamat-android/build/outputs/aar/filamat-android-full-debug.aar ../out/filamat-android-debug.aar
cp filamat-android/build/outputs/aar/filamat-android-debug.aar ../out/filamat-android-debug.aar
echo "Installing out/filament-android-debug.aar..."
cp filament-android/build/outputs/aar/filament-android-debug.aar ../out/
echo "Installing out/gltfio-android-debug.aar..."
cp gltfio-android/build/outputs/aar/gltfio-android-full-debug.aar ../out/gltfio-android-debug.aar
cp gltfio-android/build/outputs/aar/gltfio-android-debug.aar ../out/gltfio-android-debug.aar
echo "Installing out/filament-utils-android-debug.aar..."
cp filament-utils-android/build/outputs/aar/filament-utils-android-debug.aar ../out/filament-utils-android-debug.aar
@@ -551,14 +551,13 @@ function build_android {
if [[ "${INSTALL_COMMAND}" ]]; then
echo "Installing out/filamat-android-release.aar..."
cp filamat-android/build/outputs/aar/filamat-android-lite-release.aar ../out/
cp filamat-android/build/outputs/aar/filamat-android-full-release.aar ../out/filamat-android-release.aar
cp filamat-android/build/outputs/aar/filamat-android-release.aar ../out/filamat-android-release.aar
echo "Installing out/filament-android-release.aar..."
cp filament-android/build/outputs/aar/filament-android-release.aar ../out/
echo "Installing out/gltfio-android-release.aar..."
cp gltfio-android/build/outputs/aar/gltfio-android-full-release.aar ../out/gltfio-android-release.aar
cp gltfio-android/build/outputs/aar/gltfio-android-release.aar ../out/gltfio-android-release.aar
echo "Installing out/filament-utils-android-release.aar..."
cp filament-utils-android/build/outputs/aar/filament-utils-android-release.aar ../out/filament-utils-android-release.aar
@@ -573,7 +572,7 @@ function build_android {
fi
fi
cd ..
popd > /dev/null
}
function build_ios_target {
@@ -584,7 +583,7 @@ function build_ios_target {
echo "Building iOS ${lc_target} (${arch}) for ${platform}..."
mkdir -p "out/cmake-ios-${lc_target}-${arch}"
cd "out/cmake-ios-${lc_target}-${arch}"
pushd "out/cmake-ios-${lc_target}-${arch}" > /dev/null
if [[ ! -d "CMakeFiles" ]] || [[ "${ISSUE_CMAKE_ALWAYS}" == "true" ]]; then
cmake \
@@ -598,8 +597,9 @@ function build_ios_target {
-DCMAKE_TOOLCHAIN_FILE=../../third_party/clang/iOS.cmake \
${MATDBG_OPTION} \
${MATOPT_OPTION} \
${FGDBG_OPTION} \
../..
ln -sf "out/cmake-ios-${lc_target}-${arch}/compile_commands.json" \
../../compile_commands.json
fi
${BUILD_COMMAND}
@@ -609,7 +609,7 @@ function build_ios_target {
${BUILD_COMMAND} ${INSTALL_COMMAND}
fi
cd ../..
popd > /dev/null
}
function archive_ios {
@@ -618,9 +618,9 @@ function archive_ios {
if [[ -d "out/ios-${lc_target}/filament" ]]; then
if [[ "${ISSUE_ARCHIVES}" == "true" ]]; then
echo "Generating out/filament-${lc_target}-ios.tgz..."
cd "out/ios-${lc_target}"
pushd "out/ios-${lc_target}" > /dev/null
tar -czvf "../filament-${lc_target}-ios.tgz" filament
cd ../..
popd > /dev/null
fi
fi
}
@@ -679,14 +679,14 @@ function build_web_docs {
mkdir -p out/web-docs
cp -f docs/web-docs-package.json out/web-docs/package.json
cd out/web-docs
pushd out/web-docs > /dev/null
npm install > /dev/null
# Generate documents
npx markdeep-rasterizer ../../docs/Filament.md.html ../../docs/Materials.md.html ../../docs/
cd ../..
popd > /dev/null
}
function validate_build_command {
@@ -759,6 +759,19 @@ function run_tests {
fi
}
function check_debug_release_build {
if [[ "${ISSUE_DEBUG_BUILD}" == "true" || \
"${ISSUE_RELEASE_BUILD}" == "true" || \
"${ISSUE_CLEAN}" == "true" || \
"${ISSUE_WEB_DOCS}" == "true" ]]; then
"$@";
else
echo "You must declare a debug or release target for $@ builds."
echo ""
exit 1
fi
}
# Beginning of the script
pushd "$(dirname "$0")" > /dev/null
@@ -767,7 +780,7 @@ while getopts ":hacCfgijmp:q:uvslwtedk:b" opt; do
case ${opt} in
h)
print_help
exit 1
exit 0
;;
a)
ISSUE_ARCHIVES=true
@@ -783,7 +796,6 @@ while getopts ":hacCfgijmp:q:uvslwtedk:b" opt; do
PRINT_MATDBG_HELP=true
MATDBG_OPTION="-DFILAMENT_ENABLE_MATDBG=ON, -DFILAMENT_BUILD_FILAMAT=ON"
MATDBG_GRADLE_OPTION="-Pcom.google.android.filament.matdbg"
FGDBG_OPTION="-DFILAMENT_ENABLE_FGDBG=ON"
;;
f)
ISSUE_CMAKE_ALWAYS=true
@@ -804,7 +816,7 @@ while getopts ":hacCfgijmp:q:uvslwtedk:b" opt; do
platforms=$(echo "${OPTARG}" | tr ',' '\n')
for platform in ${platforms}
do
case ${platform} in
case $(echo "${platform}" | tr '[:upper:]' '[:lower:]') in
desktop)
ISSUE_DESKTOP_BUILD=true
;;
@@ -823,6 +835,12 @@ while getopts ":hacCfgijmp:q:uvslwtedk:b" opt; do
ISSUE_DESKTOP_BUILD=true
ISSUE_WEBGL_BUILD=false
;;
*)
echo "Unknown platform ${platform}"
echo "Platform must be one of [desktop|android|ios|webgl|all]"
echo ""
exit 1
;;
esac
done
;;
@@ -835,7 +853,7 @@ while getopts ":hacCfgijmp:q:uvslwtedk:b" opt; do
abis=$(echo "${OPTARG}" | tr ',' '\n')
for abi in ${abis}
do
case ${abi} in
case $(echo "${abi}" | tr '[:upper:]' '[:lower:]') in
armeabi-v7a)
ABI_ARMEABI_V7A=true
;;
@@ -854,6 +872,12 @@ while getopts ":hacCfgijmp:q:uvslwtedk:b" opt; do
ABI_X86=true
ABI_X86_64=true
;;
*)
echo "Unknown abi ${abi}"
echo "ABI must be one of [armeabi-v7a|arm64-v8a|x86|x86_64|all]"
echo ""
exit 1
;;
esac
done
;;
@@ -917,9 +941,9 @@ fi
shift $((OPTIND - 1))
for arg; do
if [[ "${arg}" == "release" ]]; then
if [[ $(echo "${arg}" | tr '[:upper:]' '[:lower:]') == "release" ]]; then
ISSUE_RELEASE_BUILD=true
elif [[ "${arg}" == "debug" ]]; then
elif [[ $(echo "${arg}" | tr '[:upper:]' '[:lower:]') == "debug" ]]; then
ISSUE_DEBUG_BUILD=true
else
BUILD_CUSTOM_TARGETS="${BUILD_CUSTOM_TARGETS} ${arg}"
@@ -937,19 +961,19 @@ if [[ "${ISSUE_CLEAN_AGGRESSIVE}" == "true" ]]; then
fi
if [[ "${ISSUE_DESKTOP_BUILD}" == "true" ]]; then
build_desktop
check_debug_release_build build_desktop
fi
if [[ "${ISSUE_ANDROID_BUILD}" == "true" ]]; then
build_android
check_debug_release_build build_android
fi
if [[ "${ISSUE_IOS_BUILD}" == "true" ]]; then
build_ios
check_debug_release_build build_ios
fi
if [[ "${ISSUE_WEBGL_BUILD}" == "true" ]]; then
build_webgl
check_debug_release_build build_webgl
fi
if [[ "${ISSUE_WEB_DOCS}" == "true" ]]; then
+10 -1
View File
@@ -2,6 +2,11 @@
set -e
case "$(uname -s)" in
Darwin*) IS_DARWIN=1;;
*) ;;
esac
function print_help {
local SELF_NAME
SELF_NAME=$(basename "$0")
@@ -45,7 +50,11 @@ function replace {
FIND_STR="${1//\{\{VERSION\}\}/${VERSION_REGEX}}"
REPLACE_STR="${1//\{\{VERSION\}\}/${NEW_VERSION}}"
local FILE_NAME="$2"
sed -i '' -E "s/${FIND_STR}/${REPLACE_STR}/" "${FILE_NAME}"
if [ IS_DARWIN == 1 ]; then
sed -i '' -E "s/${FIND_STR}/${REPLACE_STR}/" "${FILE_NAME}"
else
sed -i -E "s/${FIND_STR}/${REPLACE_STR}/" "${FILE_NAME}"
fi
}
# The following are the canonical locations where the Filament version number is referenced.
-1
View File
@@ -5,7 +5,6 @@ libs/math/test_math
libs/image/test_image compare libs/image/tests/reference/
libs/utils/test_utils
libs/filamat/test_filamat
libs/filamat/test_filamat_lite
tools/matc/test_matc
tools/cmgen/test_cmgen compare
tools/glslminifier/test_glslminifier
+1
View File
@@ -0,0 +1 @@
This file makes sure that Github Pages doesn't process mdBook's output.
+226 -65
View File
@@ -1,73 +1,234 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-us" lang="en-us">
<head>
<link href="//gmpg.org/xfn/11" rel="profile">
<link href="https://google.github.io/filament/favicon.png" rel="icon" type="image/x-icon" />
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="generator" content="Hugo 0.72.0" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>404 Page not found &middot; Filament</title>
<link type="text/css" rel="stylesheet" href="https://google.github.io/filament/css/print.css" media="print">
<link type="text/css" rel="stylesheet" href="https://google.github.io/filament/css/poole.css">
<link type="text/css" rel="stylesheet" href="https://google.github.io/filament/css/syntax.css">
<link type="text/css" rel="stylesheet" href="https://google.github.io/filament/css/hyde.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700|Tangerine:700|Inconsolata" rel="stylesheet">
<!DOCTYPE HTML>
<html lang="en" class="light" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Page not found - Filament</title>
<base href="/">
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="/apple-touch-icon-144-precomposed.png">
<link rel="shortcut icon" href="/favicon.png">
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link href="" rel="alternate" type="application/rss+xml" title="Filament" />
<link rel="icon" href="favicon.svg">
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
</head>
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="fonts/fonts.css">
<body class="theme-base-0d ">
<aside class="sidebar">
<div class="container sidebar-sticky">
<div class="sidebar-about">
<a href="https://google.github.io/filament/">
<div style="width:100%; height:150px">
<img src="https://google.github.io/filament/images/filament_logo_small.png" class="lightbulb" />
</div>
</a>
<p class="lead">
</p>
</div>
<nav>
<ul class="sidebar-nav">
<li>
<a href="https://github.com/google/filament"> GitHub Project </a>
</li><li>
<a href="/filament/documentation/"> Core Documentation </a>
</li><li>
<a href="/filament/ios/"> iOS Tutorials </a>
</li><li>
<a href="/filament/webgl/"> Web Docs / Demos </a>
</li>
</ul>
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="highlight.css">
<link rel="stylesheet" href="tomorrow-night.css">
<link rel="stylesheet" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- MathJax -->
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
</head>
<body class="sidebar-visible no-js">
<div id="body-container">
<!-- Provide site root to javascript -->
<script>
var path_to_root = "";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('light')
html.classList.add(theme);
var body = document.querySelector('body');
body.classList.remove('no-js')
body.classList.add('js');
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var body = document.querySelector('body');
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
body.classList.remove('sidebar-visible');
body.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded "><a href="core.html"><strong aria-hidden="true">1.</strong> Core Documentation</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="core-design.html"><strong aria-hidden="true">1.1.</strong> Filament Design</a></li><li class="chapter-item expanded "><a href="core-materials.html"><strong aria-hidden="true">1.2.</strong> Materials Overview</a></li></ol></li><li class="chapter-item expanded "><a href="api.html"><strong aria-hidden="true">2.</strong> API Reference</a></li><li class="chapter-item expanded "><a href="ios.html"><strong aria-hidden="true">3.</strong> iOS</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="cocoapods.html"><strong aria-hidden="true">3.1.</strong> CocoaPods Hello Triangle</a></li></ol></li><li class="chapter-item expanded "><a href="web.html"><strong aria-hidden="true">4.</strong> Web</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="web-tutorials.html"><strong aria-hidden="true">4.1.</strong> Tutorials</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="web-tutorial-triangle.html"><strong aria-hidden="true">4.1.1.</strong> Triangle Tutorial</a></li><li class="chapter-item expanded "><a href="web-tutorial-redball.html"><strong aria-hidden="true">4.1.2.</strong> Redball Tutorial</a></li><li class="chapter-item expanded "><a href="web-tutorial-suzanne.html"><strong aria-hidden="true">4.1.3.</strong> Suzanne Tutorial</a></li></ol></li></ol></li><li class="chapter-item expanded "><a href="dev.html"><strong aria-hidden="true">5.</strong> Developing Filament</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="dev-debugging.html"><strong aria-hidden="true">5.1.</strong> Filament Debugging</a></li><li class="chapter-item expanded "><a href="dev-spirv-debugging.html"><strong aria-hidden="true">5.2.</strong> Investigating SPIRV Issues</a></li><li class="chapter-item expanded "><a href="dev-versioning.html"><strong aria-hidden="true">5.3.</strong> Versioning</a></li><li class="chapter-item expanded "><a href="dev-vulkan.html"><strong aria-hidden="true">5.4.</strong> Vulkan Backend</a></li></ol></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
</div>
</aside>
<main class="content container">
<h1>404: Page not found</h1>
<p class="lead">Sorry, we've misplaced that URL or it's pointing to something that doesn't exist. <a href="https://google.github.io/filament/">Head back home</a> to try finding it again.</p>
</main>
</body>
<!-- Track and set sidebar scroll position -->
<script>
var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox');
sidebarScrollbox.addEventListener('click', function(e) {
if (e.target.tagName === 'A') {
sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop);
}
}, { passive: true });
var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
sessionStorage.removeItem('sidebar-scroll');
if (sidebarScrollTop) {
// preserve sidebar scroll position when navigating via links within sidebar
sidebarScrollbox.scrollTop = sidebarScrollTop;
} else {
// scroll sidebar to current active section when navigating via "next/previous chapter" buttons
var activeSection = document.querySelector('#sidebar .active');
if (activeSection) {
activeSection.scrollIntoView({ block: 'center' });
}
}
</script>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Filament</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="document-not-found-404"><a class="header" href="#document-not-found-404">Document not found (404)</a></h1>
<p>This URL is invalid, sorry. Please use the navigation bar or search to continue.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
</nav>
</div>
<!-- Livereload script (if served using the cli tool) -->
<script>
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
const socket = new WebSocket(wsAddress);
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload();
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<script>
window.playground_copyable = true;
</script>
<script src="elasticlunr.min.js"></script>
<script src="mark.min.js"></script>
<script src="searcher.js"></script>
<script src="clipboard.min.js"></script>
<script src="highlight.js"></script>
<script src="book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
+25 -1
View File
@@ -1139,7 +1139,8 @@ Type
: array of `string`
Value
: Each entry must be any of `dynamicLighting`, `directionalLighting`, `shadowReceiver`,`skinning` or `ssr`.
: Each entry must be any of `dynamicLighting`, `directionalLighting`, `shadowReceiver`,
`skinning`, `ssr`, or `stereo`.
Description
: Used to specify a list of shader variants that the application guarantees will never be
@@ -1158,6 +1159,7 @@ Description of the variants:
- `fog`, used when global fog is applied to the scene
- `vsm`, used when VSM shadows are enabled and the object is a shadow receiver
- `ssr`, used when screen-space reflections are enabled in the View
- `stereo`, used when stereoscopic rendering is enabled in the View
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
material {
@@ -2593,4 +2595,26 @@ pre-multiplied ahead of time. On Android, any texture uploaded from a
[Bitmap](https://developer.android.com/reference/android/graphics/Bitmap.html) will be
pre-multiplied by default.
# Sampler usage in Materials
The number of usable sampler parameters (e.g.: type is `sampler2d`) in materials is limited and
depends on the material properties, shading model, feature level and variant filter.
## Feature level 1 and 2
`unlit` materials can use up to 12 samplers by default.
`lit` materials can use up to 9 samplers by default, however if `refractionMode` or `reflectionMode`
is set to `screenspace` that number is reduced to 8.
Finally if `variantFilter` contains the `fog` filter, an extra sampler is made available, such that
`unlit` materials can use up to 13 and `lit` materials up to 10 samplers by default.
## Feature level 3
16 samplers are available.
!!! TIP: external samplers
Be aware that `external` samplers account for 2 regular samplers.
<!-- Markdeep: --><style class="fallback">body{visibility:hidden;white-space:pre;font-family:monospace}</style><script src="../third_party/markdeep/markdeep.min.js"></script><script src="https://casual-effects.com/markdeep/latest/markdeep.min.js"></script><script>window.alreadyProcessedMarkdeep||(document.body.style.visibility="visible")</script>
+279
View File
@@ -0,0 +1,279 @@
<meta charset="utf-8">
<link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet">
<style>
img { max-width: 100px !important }
.md, body, .md h1, .md div.title, .md a {
font-family: "Montserrat", sans-serif;
color: #555;
}
.md div.title { color: #a55 }
.md a { color: #55a }
</style>
**Vulkan Backend**
*Last updated: 26 October 2022*
![](./images/filament_logo.png)
-----
This document is a high-level "state of the union" for Filament's Vulkan backend. Some of the
details may be out of date by the time you read it, but we hope to keep it reasonably well
maintained, which is why it lives as a markdown document in our source tree.
# Architecture
At a high level, the Vulkan backend is composed of the **driver**, a set of **helpers**, and
a set of **handle types**.
The driver is responsible for implementing all `DriverAPI` entry points, as well as managing a
single `VkDevice` and `VkInstance`.
************************************************************************************************
* *
* .---------------------------------------. *
* | Client Application | *
* '------------------+--------------------' *
* | *
* v *
* .----------------------------------------. .--------------------------------------. *
* | Filament Rendering Engine | | filament::SwapChain | *
* '------------------+---------------------' '------------------+-------------------' *
* | | *
* v v *
* .----------------------------------------. .---------------------------------------. *
* | | | | *
* | VulkanDriver : DriverBase | | VulkanSwapChain : HwSwapChain | *
* | | | | *
* |------------------------------------------| |-----------------------------------------| *
* | | | | *
* | Helpers VulkanContext | | VulkanTexture VulkanTexture | *
* | .--------------. .---------------. | | .----------------+----------------. | *
* | | PipelineCache| | VkDevice | | | | VkImage | VkImage | | *
* | +--------------+ | VkInstance | | | | VkImageView | VkImageView | | *
* | | Disposer | | VulkanCommands | | | | | | | *
* | +--------------+ '---------------' | | '----------------+----------------' | *
* | | FboCache | | | | *
* | +--------------+ | | | *
* | | SamplerCache | | | | *
* | +--------------+ | | | *
* | | StagePool | | '---------------------------------------' *
* | '--------------' | *
* | | *
* | | *
* | | *
* '----------------------------------------' *
* *
************************************************************************************************
# Overview
## VulkanDriver and VulkanContext
The `VulkanDriver` class is the bridge between the backend and the Filament engine, and is kept as
minimal as possible. Most of the actual logic is contained in methods in `VulkanContext` and in the
handle types rather than directly in `VulkanDriver`.
In a self-imposed design constraint, we have decided that every method in `VulkanDriver` must be an
override; it should have no private methods other than the handle allocators. This reins in
complexity because it must implement every method in `DriverAPI` while dealing with Vulkan itself,
which has an extremely low-level API.
## Command buffers
The `VulkanCommands` class creates command buffers on the fly and maintains a chain of semaphores
to ensure that submitted command buffers are executed serially.
## Handle types
This sole purpose of `VulkanHandles.h` is to declare structs that descend from the hardware handles
that are defined in `DriverBase.h`.
Most of the handle types do not contain much logic, but they often do more than mere wrapping of
Vk objects. Notably, `VulkanRenderTarget` does not have a straightforward mapping to any one Vk
object. See its class comment for details. Also, `VulkanTexture` and `VulkanSwapChain` have their
own cpps file because of complexity around layouts and subresources.
VulkanProgram
: Descends from `HwProgram`, owns a pair of `VkShaderModule`.
VulkanRenderTarget
: Descends from `HwRenderTarget`, contains references to `VulkanTexture` objects.
VulkanSwapChain
: Descends from `HwSwapChain`, has a reference to `VkSurfaceKHR` and `VkSwapchainKHR`.
VulkanVertexBuffer
: Descends from `HwVertexBuffer`, owns a set of `VkBuffer`.
VulkanIndexBuffer
: Descends from `HwIndexBuffer`, owns a `VkBuffer`.
VulkanSamplerGroup
: Descends from `HwSamplerGroup`, does not own Vk objects.
VulkanTexture
: Descends from `HwTexture`, owns a `VkImage` and a set of `VkImageLayout`.
VulkanRenderPrimitive
: Descends from `HwRenderPrimitive`, does not own Vk objects.
One special case is `VulkanBuffer`, which is not a handle class. It encapulates functionality shared
between `VulkanIndexBuffer` and `VulkanVertexBuffer`.
## Helpers
`VulkanDriver` owns one instance of each helper. They are not part of a class hierarchy but
they do follow a common set of conventions. For example, most of them implement a `gc()` method
that is called once per frame to free unused objects.
VulkanPipelineCache
: Cache of VkDescriptorSet, VkPipeline, and VkPipelineLayout.
VulkanDisposer
: Holds reference counts to Vulkan objects in order to defer their destruction.
VulkanFboCache
: Cache of VkRenderPass and VkFramebuffer. Contains weak references to VkImage handles, but does not
own any pixel data. The cache key for render passes is quite complex because it needs to include
image layout information in a compact way. For details see the comments in the `RenderPassKey`
declaration.
VulkanStagePool
: Pool of VkBuffer objects that can be memory mapped (shared between host and device).
VulkanSamplerCache
: This is our simplest cache object because Vulkan samplers are fairly lightweight and re-usable.
## Folder layout and namespacing
With the exception of BlueVK, all Vulkan-specific code lives in `backend/src/vulkan`, which has
no subfolders. All backend-specific types and functions live directly in the `filament::backend`
namespace, and we simply prefix our names with "Vulkan" when necessary to avoid ambiguation with
OpenGL.
# Image Layout Strategy
Adhering to a coherent strategy for image layout transitions is crucial. Without this, validation
errors (and actual black screens with some GPU vendors) occur far too easily and can feel like
whack-a-mole.
Vulkan provides several mechanisms for transitioning layout (render passes, barriers) so the
strategy outlined below specifies which mechanism should be used in various scenarios.
The current image layouts are tracked at the subresource level in `VulkanTexture` using a
specialized STL-ish container that we designed for this purpose:
[RangeMap](https://github.com/google/filament/blob/main/libs/utils/include/utils/RangeMap.h).
In the past we tried to avoid tracking since it theoritically duplicates state that exists in the
GPU vendor's driver. However in practice this was impossible to manage, because complex logic was
required to deduce the current layout. Also, tracking lets us use `assert_invariant` in many places
to ensure that the behavior described in this document is implemented properly. It is much easier
to catch errors with asserts than with validation.
As of this writing, the current rules are:
(1) **Read-Only Color Textures**
These should be created in an UNDEFINED state and stay that way until data gets uploaded into them,
at which point the appropriate subresources are transitioned to TRANSFER_DST_OPTIMAL for the upload,
then to SHADER_READ_ONLY_OPTIMAL, both times using a barrier. Note that a subresource might be
updated several times; each time it undergoes these two transitions.
If a shader samples from a texture whose mipmaps are only partially loaded, we might see validation
warnings about how some subresources are in an UNDEFINED layout. However if we are properly using
the `setMinMaxLevels` driver API, then the Vulkan backend will not bind those particular
subresources, so validation should not complain.
(2) **Writeable Color Textures**
During construction of the HwTexture, these are transitioned to GENERAL using a barrier.
GENERAL layout is not recommended by AMD best practices but in our case we wish to avoid thrashing
the layout between COLOR_ATTACHMENT_OPTIMAL and SHADER_READ_ONLY_OPTIMAL for post-processing
effects. Moreover we do not have a priori knowledge about blitting and read pixels usage.
(3) **Depth Textures**
During construction of the HwTexture, these are transitioned to GENERAL using a barrier.
Note that some post-processing passes (e.g. SSAO) sample from the depth buffer while also enabling
depth testing. Using GENERAL makes this legal.
(4) **Swap Chain Textures**
During construction, these are transitioned to GENERAL using a barrier. They are then transitioned
to PRESENT at the end of the frame using a barrier, and transitioned back to GENERAL using the first
render pass of the frame.
Note that we transition to PRESENT using a barrier, but with some GPU vendors it might be preferable
to transition them using the last render pass. However we have no way of knowing ahead of time which
pass is last.
Note that Filament allows swap chains to be used as blit targets and blit sources (e.g. for
ReadPixels). Using GENERAL makes this easier to manage.
(5) **Headless Swap Chain Textures**
These follow the same rules as writeable color texture and depth textures.
# VulkanPipelineCache
Uniforms, samplers, and shaders are not directly bindable in Vulkan; instead they are bound through
indirection layers called *pipelines* and *descriptor sets*. The `VulkanPipelineCache` class allows
the driver to call methods that are conceptually simple like `bindUniformBuffer`, even though no
such function exists in the low-level Vulkan API.
Although it is actually just another cache manager, `VulkanPipelineCache` has a fairly rich set of
public methods. See its header file for details.
The pipeline cache also manages the *layout objects*, which constrain the number of uniform buffers
and samplers that can be bound simultaneously (see `VkDescriptorSetLayout` and `VkPipelineLayout`).
# Memory Allocation
Some architectures (e.g. Adreno) only allow a small number of `VkDeviceMemory` objects to exist at
once, so we consolidate these using a simple third-party library
([vk_mem_alloc](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator)). This library is
used each time the backend needs to create a `VkBuffer` or `VkImage`. See `VulkanStagePool` for a
usage example.
# BlueVK
BlueVK loads in functions for all Vulkan entry points and supported extensions. On Android, this
is not absolutely necessary since core functionality is available through static linking. However,
we found that in practice it is simpler to use BlueVK across all platforms because of its ability
to load extensions.
The BlueVK C++ source is generated from a Python script that consumes `vk.xml`. This XML file is an
API specification maintained by Khronos on GitHub.
None of the source files in the Vulkan backend include `vulkan.h` directly, instead they include
the BlueVK header, which in turn includes the Vulkan headers.
!!! Note
Each time we update BlueVK by feeding it the latest `vk.xml`, we should also update the
Vulkan headers that are checked in to `libs/bluevk/include/vulkan`. If BlueVK and the Vulkan
headers are not updated concurrently, this will cause build errors.
# Top Issues
Here we list some of the most significant issues and to-be-done items for the Vulkan backend.
- Improve the UBO strategy
- Currently we use staging buffers and perform lots of copies (host-to-host, then host-to-device)
- Consider an approach similar to MetalDriver, which effectively implements double-buffering
using a pool of shared mem buffers
- Consider using subpasses for the depth prepass
- We lazily create pipeline objects
1. This is notoriously slow in Vulkan
2. We do lots of state hashing for this
3. Vulkan has special pipeline cache objects that we aren't using yet, but...
4. It might be better to enhance our driver API to allow a priori construction
- We need more automated testing
- We don't *quite* have feature parity with the OpenGL backend
- No support for streaming camera texture yet
- This is possible, even in Android O, just haven't gotten around to it yet
<script src="https://casual-effects.com/markdeep/latest/markdeep.min.js"></script>
<script>window.alreadyProcessedMarkdeep||(document.body.style.visibility="visible")</script>
+250
View File
@@ -0,0 +1,250 @@
<!DOCTYPE HTML>
<html lang="en" class="light" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>API Reference - Filament</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="favicon.svg">
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="highlight.css">
<link rel="stylesheet" href="tomorrow-night.css">
<link rel="stylesheet" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- MathJax -->
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
</head>
<body class="sidebar-visible no-js">
<div id="body-container">
<!-- Provide site root to javascript -->
<script>
var path_to_root = "";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('light')
html.classList.add(theme);
var body = document.querySelector('body');
body.classList.remove('no-js')
body.classList.add('js');
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var body = document.querySelector('body');
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
body.classList.remove('sidebar-visible');
body.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded "><a href="core.html"><strong aria-hidden="true">1.</strong> Core Documentation</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="core-design.html"><strong aria-hidden="true">1.1.</strong> Filament Design</a></li><li class="chapter-item expanded "><a href="core-materials.html"><strong aria-hidden="true">1.2.</strong> Materials Overview</a></li></ol></li><li class="chapter-item expanded "><a href="api.html" class="active"><strong aria-hidden="true">2.</strong> API Reference</a></li><li class="chapter-item expanded "><a href="ios.html"><strong aria-hidden="true">3.</strong> iOS</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="cocoapods.html"><strong aria-hidden="true">3.1.</strong> CocoaPods Hello Triangle</a></li></ol></li><li class="chapter-item expanded "><a href="web.html"><strong aria-hidden="true">4.</strong> Web</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="web-tutorials.html"><strong aria-hidden="true">4.1.</strong> Tutorials</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="web-tutorial-triangle.html"><strong aria-hidden="true">4.1.1.</strong> Triangle Tutorial</a></li><li class="chapter-item expanded "><a href="web-tutorial-redball.html"><strong aria-hidden="true">4.1.2.</strong> Redball Tutorial</a></li><li class="chapter-item expanded "><a href="web-tutorial-suzanne.html"><strong aria-hidden="true">4.1.3.</strong> Suzanne Tutorial</a></li></ol></li></ol></li><li class="chapter-item expanded "><a href="dev.html"><strong aria-hidden="true">5.</strong> Developing Filament</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="dev-debugging.html"><strong aria-hidden="true">5.1.</strong> Filament Debugging</a></li><li class="chapter-item expanded "><a href="dev-spirv-debugging.html"><strong aria-hidden="true">5.2.</strong> Investigating SPIRV Issues</a></li><li class="chapter-item expanded "><a href="dev-versioning.html"><strong aria-hidden="true">5.3.</strong> Versioning</a></li><li class="chapter-item expanded "><a href="dev-vulkan.html"><strong aria-hidden="true">5.4.</strong> Vulkan Backend</a></li></ol></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<!-- Track and set sidebar scroll position -->
<script>
var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox');
sidebarScrollbox.addEventListener('click', function(e) {
if (e.target.tagName === 'A') {
sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop);
}
}, { passive: true });
var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
sessionStorage.removeItem('sidebar-scroll');
if (sidebarScrollTop) {
// preserve sidebar scroll position when navigating via links within sidebar
sidebarScrollbox.scrollTop = sidebarScrollTop;
} else {
// scroll sidebar to current active section when navigating via "next/previous chapter" buttons
var activeSection = document.querySelector('#sidebar .active');
if (activeSection) {
activeSection.scrollIntoView({ block: 'center' });
}
}
</script>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Filament</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="api-reference"><a class="header" href="#api-reference">API Reference</a></h1>
<p>Refer to the following for a complete reference to the Filament API.</p>
<ul>
<li><a href="TODO">C++</a></li>
<li><a href="TODO">Java</a></li>
<li><a href="TODO">JavaScript</a></li>
</ul>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="core-materials.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="ios.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="core-materials.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="ios.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<!-- Livereload script (if served using the cli tool) -->
<script>
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
const socket = new WebSocket(wsAddress);
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload();
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<script>
window.playground_copyable = true;
</script>
<script src="elasticlunr.min.js"></script>
<script src="mark.min.js"></script>
<script src="searcher.js"></script>
<script src="clipboard.min.js"></script>
<script src="highlight.js"></script>
<script src="book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 570 B

+78
View File
@@ -0,0 +1,78 @@
/*
Based off of the Ayu theme
Original by Dempfi (https://github.com/dempfi/ayu)
*/
.hljs {
display: block;
overflow-x: auto;
background: #191f26;
color: #e6e1cf;
}
.hljs-comment,
.hljs-quote {
color: #5c6773;
font-style: italic;
}
.hljs-variable,
.hljs-template-variable,
.hljs-attribute,
.hljs-attr,
.hljs-regexp,
.hljs-link,
.hljs-selector-id,
.hljs-selector-class {
color: #ff7733;
}
.hljs-number,
.hljs-meta,
.hljs-builtin-name,
.hljs-literal,
.hljs-type,
.hljs-params {
color: #ffee99;
}
.hljs-string,
.hljs-bullet {
color: #b8cc52;
}
.hljs-title,
.hljs-built_in,
.hljs-section {
color: #ffb454;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-symbol {
color: #ff7733;
}
.hljs-name {
color: #36a3d9;
}
.hljs-tag {
color: #00568d;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
.hljs-addition {
color: #91b362;
}
.hljs-deletion {
color: #d96c75;
}
+697
View File
@@ -0,0 +1,697 @@
"use strict";
// Fix back button cache problem
window.onunload = function () { };
// Global variable, shared between modules
function playground_text(playground, hidden = true) {
let code_block = playground.querySelector("code");
if (window.ace && code_block.classList.contains("editable")) {
let editor = window.ace.edit(code_block);
return editor.getValue();
} else if (hidden) {
return code_block.textContent;
} else {
return code_block.innerText;
}
}
(function codeSnippets() {
function fetch_with_timeout(url, options, timeout = 6000) {
return Promise.race([
fetch(url, options),
new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout))
]);
}
var playgrounds = Array.from(document.querySelectorAll(".playground"));
if (playgrounds.length > 0) {
fetch_with_timeout("https://play.rust-lang.org/meta/crates", {
headers: {
'Content-Type': "application/json",
},
method: 'POST',
mode: 'cors',
})
.then(response => response.json())
.then(response => {
// get list of crates available in the rust playground
let playground_crates = response.crates.map(item => item["id"]);
playgrounds.forEach(block => handle_crate_list_update(block, playground_crates));
});
}
function handle_crate_list_update(playground_block, playground_crates) {
// update the play buttons after receiving the response
update_play_button(playground_block, playground_crates);
// and install on change listener to dynamically update ACE editors
if (window.ace) {
let code_block = playground_block.querySelector("code");
if (code_block.classList.contains("editable")) {
let editor = window.ace.edit(code_block);
editor.addEventListener("change", function (e) {
update_play_button(playground_block, playground_crates);
});
// add Ctrl-Enter command to execute rust code
editor.commands.addCommand({
name: "run",
bindKey: {
win: "Ctrl-Enter",
mac: "Ctrl-Enter"
},
exec: _editor => run_rust_code(playground_block)
});
}
}
}
// updates the visibility of play button based on `no_run` class and
// used crates vs ones available on https://play.rust-lang.org
function update_play_button(pre_block, playground_crates) {
var play_button = pre_block.querySelector(".play-button");
// skip if code is `no_run`
if (pre_block.querySelector('code').classList.contains("no_run")) {
play_button.classList.add("hidden");
return;
}
// get list of `extern crate`'s from snippet
var txt = playground_text(pre_block);
var re = /extern\s+crate\s+([a-zA-Z_0-9]+)\s*;/g;
var snippet_crates = [];
var item;
while (item = re.exec(txt)) {
snippet_crates.push(item[1]);
}
// check if all used crates are available on play.rust-lang.org
var all_available = snippet_crates.every(function (elem) {
return playground_crates.indexOf(elem) > -1;
});
if (all_available) {
play_button.classList.remove("hidden");
} else {
play_button.classList.add("hidden");
}
}
function run_rust_code(code_block) {
var result_block = code_block.querySelector(".result");
if (!result_block) {
result_block = document.createElement('code');
result_block.className = 'result hljs language-bash';
code_block.append(result_block);
}
let text = playground_text(code_block);
let classes = code_block.querySelector('code').classList;
let edition = "2015";
if(classes.contains("edition2018")) {
edition = "2018";
} else if(classes.contains("edition2021")) {
edition = "2021";
}
var params = {
version: "stable",
optimize: "0",
code: text,
edition: edition
};
if (text.indexOf("#![feature") !== -1) {
params.version = "nightly";
}
result_block.innerText = "Running...";
fetch_with_timeout("https://play.rust-lang.org/evaluate.json", {
headers: {
'Content-Type': "application/json",
},
method: 'POST',
mode: 'cors',
body: JSON.stringify(params)
})
.then(response => response.json())
.then(response => {
if (response.result.trim() === '') {
result_block.innerText = "No output";
result_block.classList.add("result-no-output");
} else {
result_block.innerText = response.result;
result_block.classList.remove("result-no-output");
}
})
.catch(error => result_block.innerText = "Playground Communication: " + error.message);
}
// Syntax highlighting Configuration
hljs.configure({
tabReplace: ' ', // 4 spaces
languages: [], // Languages used for auto-detection
});
let code_nodes = Array
.from(document.querySelectorAll('code'))
// Don't highlight `inline code` blocks in headers.
.filter(function (node) {return !node.parentElement.classList.contains("header"); });
if (window.ace) {
// language-rust class needs to be removed for editable
// blocks or highlightjs will capture events
code_nodes
.filter(function (node) {return node.classList.contains("editable"); })
.forEach(function (block) { block.classList.remove('language-rust'); });
code_nodes
.filter(function (node) {return !node.classList.contains("editable"); })
.forEach(function (block) { hljs.highlightBlock(block); });
} else {
code_nodes.forEach(function (block) { hljs.highlightBlock(block); });
}
// Adding the hljs class gives code blocks the color css
// even if highlighting doesn't apply
code_nodes.forEach(function (block) { block.classList.add('hljs'); });
Array.from(document.querySelectorAll("code.hljs")).forEach(function (block) {
var lines = Array.from(block.querySelectorAll('.boring'));
// If no lines were hidden, return
if (!lines.length) { return; }
block.classList.add("hide-boring");
var buttons = document.createElement('div');
buttons.className = 'buttons';
buttons.innerHTML = "<button class=\"fa fa-eye\" title=\"Show hidden lines\" aria-label=\"Show hidden lines\"></button>";
// add expand button
var pre_block = block.parentNode;
pre_block.insertBefore(buttons, pre_block.firstChild);
pre_block.querySelector('.buttons').addEventListener('click', function (e) {
if (e.target.classList.contains('fa-eye')) {
e.target.classList.remove('fa-eye');
e.target.classList.add('fa-eye-slash');
e.target.title = 'Hide lines';
e.target.setAttribute('aria-label', e.target.title);
block.classList.remove('hide-boring');
} else if (e.target.classList.contains('fa-eye-slash')) {
e.target.classList.remove('fa-eye-slash');
e.target.classList.add('fa-eye');
e.target.title = 'Show hidden lines';
e.target.setAttribute('aria-label', e.target.title);
block.classList.add('hide-boring');
}
});
});
if (window.playground_copyable) {
Array.from(document.querySelectorAll('pre code')).forEach(function (block) {
var pre_block = block.parentNode;
if (!pre_block.classList.contains('playground')) {
var buttons = pre_block.querySelector(".buttons");
if (!buttons) {
buttons = document.createElement('div');
buttons.className = 'buttons';
pre_block.insertBefore(buttons, pre_block.firstChild);
}
var clipButton = document.createElement('button');
clipButton.className = 'fa fa-copy clip-button';
clipButton.title = 'Copy to clipboard';
clipButton.setAttribute('aria-label', clipButton.title);
clipButton.innerHTML = '<i class=\"tooltiptext\"></i>';
buttons.insertBefore(clipButton, buttons.firstChild);
}
});
}
// Process playground code blocks
Array.from(document.querySelectorAll(".playground")).forEach(function (pre_block) {
// Add play button
var buttons = pre_block.querySelector(".buttons");
if (!buttons) {
buttons = document.createElement('div');
buttons.className = 'buttons';
pre_block.insertBefore(buttons, pre_block.firstChild);
}
var runCodeButton = document.createElement('button');
runCodeButton.className = 'fa fa-play play-button';
runCodeButton.hidden = true;
runCodeButton.title = 'Run this code';
runCodeButton.setAttribute('aria-label', runCodeButton.title);
buttons.insertBefore(runCodeButton, buttons.firstChild);
runCodeButton.addEventListener('click', function (e) {
run_rust_code(pre_block);
});
if (window.playground_copyable) {
var copyCodeClipboardButton = document.createElement('button');
copyCodeClipboardButton.className = 'fa fa-copy clip-button';
copyCodeClipboardButton.innerHTML = '<i class="tooltiptext"></i>';
copyCodeClipboardButton.title = 'Copy to clipboard';
copyCodeClipboardButton.setAttribute('aria-label', copyCodeClipboardButton.title);
buttons.insertBefore(copyCodeClipboardButton, buttons.firstChild);
}
let code_block = pre_block.querySelector("code");
if (window.ace && code_block.classList.contains("editable")) {
var undoChangesButton = document.createElement('button');
undoChangesButton.className = 'fa fa-history reset-button';
undoChangesButton.title = 'Undo changes';
undoChangesButton.setAttribute('aria-label', undoChangesButton.title);
buttons.insertBefore(undoChangesButton, buttons.firstChild);
undoChangesButton.addEventListener('click', function () {
let editor = window.ace.edit(code_block);
editor.setValue(editor.originalCode);
editor.clearSelection();
});
}
});
})();
(function themes() {
var html = document.querySelector('html');
var themeToggleButton = document.getElementById('theme-toggle');
var themePopup = document.getElementById('theme-list');
var themeColorMetaTag = document.querySelector('meta[name="theme-color"]');
var stylesheets = {
ayuHighlight: document.querySelector("[href$='ayu-highlight.css']"),
tomorrowNight: document.querySelector("[href$='tomorrow-night.css']"),
highlight: document.querySelector("[href$='highlight.css']"),
};
function showThemes() {
themePopup.style.display = 'block';
themeToggleButton.setAttribute('aria-expanded', true);
themePopup.querySelector("button#" + get_theme()).focus();
}
function updateThemeSelected() {
themePopup.querySelectorAll('.theme-selected').forEach(function (el) {
el.classList.remove('theme-selected');
});
themePopup.querySelector("button#" + get_theme()).classList.add('theme-selected');
}
function hideThemes() {
themePopup.style.display = 'none';
themeToggleButton.setAttribute('aria-expanded', false);
themeToggleButton.focus();
}
function get_theme() {
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch (e) { }
if (theme === null || theme === undefined) {
return default_theme;
} else {
return theme;
}
}
function set_theme(theme, store = true) {
let ace_theme;
if (theme == 'coal' || theme == 'navy') {
stylesheets.ayuHighlight.disabled = true;
stylesheets.tomorrowNight.disabled = false;
stylesheets.highlight.disabled = true;
ace_theme = "ace/theme/tomorrow_night";
} else if (theme == 'ayu') {
stylesheets.ayuHighlight.disabled = false;
stylesheets.tomorrowNight.disabled = true;
stylesheets.highlight.disabled = true;
ace_theme = "ace/theme/tomorrow_night";
} else {
stylesheets.ayuHighlight.disabled = true;
stylesheets.tomorrowNight.disabled = true;
stylesheets.highlight.disabled = false;
ace_theme = "ace/theme/dawn";
}
setTimeout(function () {
themeColorMetaTag.content = getComputedStyle(document.documentElement).backgroundColor;
}, 1);
if (window.ace && window.editors) {
window.editors.forEach(function (editor) {
editor.setTheme(ace_theme);
});
}
var previousTheme = get_theme();
if (store) {
try { localStorage.setItem('mdbook-theme', theme); } catch (e) { }
}
html.classList.remove(previousTheme);
html.classList.add(theme);
updateThemeSelected();
}
// Set theme
var theme = get_theme();
set_theme(theme, false);
themeToggleButton.addEventListener('click', function () {
if (themePopup.style.display === 'block') {
hideThemes();
} else {
showThemes();
}
});
themePopup.addEventListener('click', function (e) {
var theme;
if (e.target.className === "theme") {
theme = e.target.id;
} else if (e.target.parentElement.className === "theme") {
theme = e.target.parentElement.id;
} else {
return;
}
set_theme(theme);
});
themePopup.addEventListener('focusout', function(e) {
// e.relatedTarget is null in Safari and Firefox on macOS (see workaround below)
if (!!e.relatedTarget && !themeToggleButton.contains(e.relatedTarget) && !themePopup.contains(e.relatedTarget)) {
hideThemes();
}
});
// Should not be needed, but it works around an issue on macOS & iOS: https://github.com/rust-lang/mdBook/issues/628
document.addEventListener('click', function(e) {
if (themePopup.style.display === 'block' && !themeToggleButton.contains(e.target) && !themePopup.contains(e.target)) {
hideThemes();
}
});
document.addEventListener('keydown', function (e) {
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; }
if (!themePopup.contains(e.target)) { return; }
switch (e.key) {
case 'Escape':
e.preventDefault();
hideThemes();
break;
case 'ArrowUp':
e.preventDefault();
var li = document.activeElement.parentElement;
if (li && li.previousElementSibling) {
li.previousElementSibling.querySelector('button').focus();
}
break;
case 'ArrowDown':
e.preventDefault();
var li = document.activeElement.parentElement;
if (li && li.nextElementSibling) {
li.nextElementSibling.querySelector('button').focus();
}
break;
case 'Home':
e.preventDefault();
themePopup.querySelector('li:first-child button').focus();
break;
case 'End':
e.preventDefault();
themePopup.querySelector('li:last-child button').focus();
break;
}
});
})();
(function sidebar() {
var body = document.querySelector("body");
var sidebar = document.getElementById("sidebar");
var sidebarLinks = document.querySelectorAll('#sidebar a');
var sidebarToggleButton = document.getElementById("sidebar-toggle");
var sidebarResizeHandle = document.getElementById("sidebar-resize-handle");
var firstContact = null;
function showSidebar() {
body.classList.remove('sidebar-hidden')
body.classList.add('sidebar-visible');
Array.from(sidebarLinks).forEach(function (link) {
link.setAttribute('tabIndex', 0);
});
sidebarToggleButton.setAttribute('aria-expanded', true);
sidebar.setAttribute('aria-hidden', false);
try { localStorage.setItem('mdbook-sidebar', 'visible'); } catch (e) { }
}
var sidebarAnchorToggles = document.querySelectorAll('#sidebar a.toggle');
function toggleSection(ev) {
ev.currentTarget.parentElement.classList.toggle('expanded');
}
Array.from(sidebarAnchorToggles).forEach(function (el) {
el.addEventListener('click', toggleSection);
});
function hideSidebar() {
body.classList.remove('sidebar-visible')
body.classList.add('sidebar-hidden');
Array.from(sidebarLinks).forEach(function (link) {
link.setAttribute('tabIndex', -1);
});
sidebarToggleButton.setAttribute('aria-expanded', false);
sidebar.setAttribute('aria-hidden', true);
try { localStorage.setItem('mdbook-sidebar', 'hidden'); } catch (e) { }
}
// Toggle sidebar
sidebarToggleButton.addEventListener('click', function sidebarToggle() {
if (body.classList.contains("sidebar-hidden")) {
var current_width = parseInt(
document.documentElement.style.getPropertyValue('--sidebar-width'), 10);
if (current_width < 150) {
document.documentElement.style.setProperty('--sidebar-width', '150px');
}
showSidebar();
} else if (body.classList.contains("sidebar-visible")) {
hideSidebar();
} else {
if (getComputedStyle(sidebar)['transform'] === 'none') {
hideSidebar();
} else {
showSidebar();
}
}
});
sidebarResizeHandle.addEventListener('mousedown', initResize, false);
function initResize(e) {
window.addEventListener('mousemove', resize, false);
window.addEventListener('mouseup', stopResize, false);
body.classList.add('sidebar-resizing');
}
function resize(e) {
var pos = (e.clientX - sidebar.offsetLeft);
if (pos < 20) {
hideSidebar();
} else {
if (body.classList.contains("sidebar-hidden")) {
showSidebar();
}
pos = Math.min(pos, window.innerWidth - 100);
document.documentElement.style.setProperty('--sidebar-width', pos + 'px');
}
}
//on mouseup remove windows functions mousemove & mouseup
function stopResize(e) {
body.classList.remove('sidebar-resizing');
window.removeEventListener('mousemove', resize, false);
window.removeEventListener('mouseup', stopResize, false);
}
document.addEventListener('touchstart', function (e) {
firstContact = {
x: e.touches[0].clientX,
time: Date.now()
};
}, { passive: true });
document.addEventListener('touchmove', function (e) {
if (!firstContact)
return;
var curX = e.touches[0].clientX;
var xDiff = curX - firstContact.x,
tDiff = Date.now() - firstContact.time;
if (tDiff < 250 && Math.abs(xDiff) >= 150) {
if (xDiff >= 0 && firstContact.x < Math.min(document.body.clientWidth * 0.25, 300))
showSidebar();
else if (xDiff < 0 && curX < 300)
hideSidebar();
firstContact = null;
}
}, { passive: true });
})();
(function chapterNavigation() {
document.addEventListener('keydown', function (e) {
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; }
if (window.search && window.search.hasFocus()) { return; }
var html = document.querySelector('html');
function next() {
var nextButton = document.querySelector('.nav-chapters.next');
if (nextButton) {
window.location.href = nextButton.href;
}
}
function prev() {
var previousButton = document.querySelector('.nav-chapters.previous');
if (previousButton) {
window.location.href = previousButton.href;
}
}
switch (e.key) {
case 'ArrowRight':
e.preventDefault();
if (html.dir == 'rtl') {
prev();
} else {
next();
}
break;
case 'ArrowLeft':
e.preventDefault();
if (html.dir == 'rtl') {
next();
} else {
prev();
}
break;
}
});
})();
(function clipboard() {
var clipButtons = document.querySelectorAll('.clip-button');
function hideTooltip(elem) {
elem.firstChild.innerText = "";
elem.className = 'fa fa-copy clip-button';
}
function showTooltip(elem, msg) {
elem.firstChild.innerText = msg;
elem.className = 'fa fa-copy tooltipped';
}
var clipboardSnippets = new ClipboardJS('.clip-button', {
text: function (trigger) {
hideTooltip(trigger);
let playground = trigger.closest("pre");
return playground_text(playground, false);
}
});
Array.from(clipButtons).forEach(function (clipButton) {
clipButton.addEventListener('mouseout', function (e) {
hideTooltip(e.currentTarget);
});
});
clipboardSnippets.on('success', function (e) {
e.clearSelection();
showTooltip(e.trigger, "Copied!");
});
clipboardSnippets.on('error', function (e) {
showTooltip(e.trigger, "Clipboard error!");
});
})();
(function scrollToTop () {
var menuTitle = document.querySelector('.menu-title');
menuTitle.addEventListener('click', function () {
document.scrollingElement.scrollTo({ top: 0, behavior: 'smooth' });
});
})();
(function controllMenu() {
var menu = document.getElementById('menu-bar');
(function controllPosition() {
var scrollTop = document.scrollingElement.scrollTop;
var prevScrollTop = scrollTop;
var minMenuY = -menu.clientHeight - 50;
// When the script loads, the page can be at any scroll (e.g. if you reforesh it).
menu.style.top = scrollTop + 'px';
// Same as parseInt(menu.style.top.slice(0, -2), but faster
var topCache = menu.style.top.slice(0, -2);
menu.classList.remove('sticky');
var stickyCache = false; // Same as menu.classList.contains('sticky'), but faster
document.addEventListener('scroll', function () {
scrollTop = Math.max(document.scrollingElement.scrollTop, 0);
// `null` means that it doesn't need to be updated
var nextSticky = null;
var nextTop = null;
var scrollDown = scrollTop > prevScrollTop;
var menuPosAbsoluteY = topCache - scrollTop;
if (scrollDown) {
nextSticky = false;
if (menuPosAbsoluteY > 0) {
nextTop = prevScrollTop;
}
} else {
if (menuPosAbsoluteY > 0) {
nextSticky = true;
} else if (menuPosAbsoluteY < minMenuY) {
nextTop = prevScrollTop + minMenuY;
}
}
if (nextSticky === true && stickyCache === false) {
menu.classList.add('sticky');
stickyCache = true;
} else if (nextSticky === false && stickyCache === true) {
menu.classList.remove('sticky');
stickyCache = false;
}
if (nextTop !== null) {
menu.style.top = nextTop + 'px';
topCache = nextTop;
}
prevScrollTop = scrollTop;
}, { passive: true });
})();
(function controllBorder() {
function updateBorder() {
if (menu.offsetTop === 0) {
menu.classList.remove('bordered');
} else {
menu.classList.add('bordered');
}
}
updateBorder();
document.addEventListener('scroll', updateBorder, { passive: true });
})();
})();
-74
View File
@@ -1,74 +0,0 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-us" lang="en-us">
<head>
<link href="//gmpg.org/xfn/11" rel="profile">
<link href="https://google.github.io/filament/favicon.png" rel="icon" type="image/x-icon" />
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="generator" content="Hugo 0.72.0" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Categories &middot; Filament</title>
<link type="text/css" rel="stylesheet" href="https://google.github.io/filament/css/print.css" media="print">
<link type="text/css" rel="stylesheet" href="https://google.github.io/filament/css/poole.css">
<link type="text/css" rel="stylesheet" href="https://google.github.io/filament/css/syntax.css">
<link type="text/css" rel="stylesheet" href="https://google.github.io/filament/css/hyde.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700|Tangerine:700|Inconsolata" rel="stylesheet">
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="/apple-touch-icon-144-precomposed.png">
<link rel="shortcut icon" href="/favicon.png">
<link href="https://google.github.io/filament/categories/index.xml" rel="alternate" type="application/rss+xml" title="Filament" />
</head>
<body class="theme-base-0d ">
<aside class="sidebar">
<div class="container sidebar-sticky">
<div class="sidebar-about">
<a href="https://google.github.io/filament/">
<div style="width:100%; height:150px">
<img src="https://google.github.io/filament/images/filament_logo_small.png" class="lightbulb" />
</div>
</a>
<p class="lead">
</p>
</div>
<nav>
<ul class="sidebar-nav">
<li>
<a href="https://github.com/google/filament"> GitHub Project </a>
</li><li>
<a href="/filament/documentation/"> Core Documentation </a>
</li><li>
<a href="/filament/ios/"> iOS Tutorials </a>
</li><li>
<a href="/filament/webgl/"> Web Docs / Demos </a>
</li>
</ul>
</nav>
</div>
</aside>
<main class="content container">
<ul class="posts">
</ul>
</main>
</body>
</html>
-14
View File
@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Categories on Filament</title>
<link>https://google.github.io/filament/categories/</link>
<description>Recent content in Categories on Filament</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<atom:link href="https://google.github.io/filament/categories/index.xml" rel="self" type="application/rss+xml" />
</channel>
</rss>
+7
View File
File diff suppressed because one or more lines are too long
+685
View File
@@ -0,0 +1,685 @@
<!DOCTYPE HTML>
<html lang="en" class="light" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>CocoaPods Hello Triangle - Filament</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="favicon.svg">
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="highlight.css">
<link rel="stylesheet" href="tomorrow-night.css">
<link rel="stylesheet" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- MathJax -->
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
</head>
<body class="sidebar-visible no-js">
<div id="body-container">
<!-- Provide site root to javascript -->
<script>
var path_to_root = "";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('light')
html.classList.add(theme);
var body = document.querySelector('body');
body.classList.remove('no-js')
body.classList.add('js');
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var body = document.querySelector('body');
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
body.classList.remove('sidebar-visible');
body.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded "><a href="core.html"><strong aria-hidden="true">1.</strong> Core Documentation</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="core-design.html"><strong aria-hidden="true">1.1.</strong> Filament Design</a></li><li class="chapter-item expanded "><a href="core-materials.html"><strong aria-hidden="true">1.2.</strong> Materials Overview</a></li></ol></li><li class="chapter-item expanded "><a href="api.html"><strong aria-hidden="true">2.</strong> API Reference</a></li><li class="chapter-item expanded "><a href="ios.html"><strong aria-hidden="true">3.</strong> iOS</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="cocoapods.html" class="active"><strong aria-hidden="true">3.1.</strong> CocoaPods Hello Triangle</a></li></ol></li><li class="chapter-item expanded "><a href="web.html"><strong aria-hidden="true">4.</strong> Web</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="web-tutorials.html"><strong aria-hidden="true">4.1.</strong> Tutorials</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="web-tutorial-triangle.html"><strong aria-hidden="true">4.1.1.</strong> Triangle Tutorial</a></li><li class="chapter-item expanded "><a href="web-tutorial-redball.html"><strong aria-hidden="true">4.1.2.</strong> Redball Tutorial</a></li><li class="chapter-item expanded "><a href="web-tutorial-suzanne.html"><strong aria-hidden="true">4.1.3.</strong> Suzanne Tutorial</a></li></ol></li></ol></li><li class="chapter-item expanded "><a href="dev.html"><strong aria-hidden="true">5.</strong> Developing Filament</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="dev-debugging.html"><strong aria-hidden="true">5.1.</strong> Filament Debugging</a></li><li class="chapter-item expanded "><a href="dev-spirv-debugging.html"><strong aria-hidden="true">5.2.</strong> Investigating SPIRV Issues</a></li><li class="chapter-item expanded "><a href="dev-versioning.html"><strong aria-hidden="true">5.3.</strong> Versioning</a></li><li class="chapter-item expanded "><a href="dev-vulkan.html"><strong aria-hidden="true">5.4.</strong> Vulkan Backend</a></li></ol></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<!-- Track and set sidebar scroll position -->
<script>
var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox');
sidebarScrollbox.addEventListener('click', function(e) {
if (e.target.tagName === 'A') {
sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop);
}
}, { passive: true });
var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
sessionStorage.removeItem('sidebar-scroll');
if (sidebarScrollTop) {
// preserve sidebar scroll position when navigating via links within sidebar
sidebarScrollbox.scrollTop = sidebarScrollTop;
} else {
// scroll sidebar to current active section when navigating via "next/previous chapter" buttons
var activeSection = document.querySelector('#sidebar .active');
if (activeSection) {
activeSection.scrollIntoView({ block: 'center' });
}
}
</script>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Filament</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="cocoapods-hello-triangle"><a class="header" href="#cocoapods-hello-triangle">CocoaPods Hello Triangle</a></h1>
<p>As of release 1.8.0, you can install Filament in your iOS application using
CocoaPods.</p>
<p>This guide will walk you through creating a basic &quot;hello triangle&quot; iOS
application using Filament and the Metal backend.</p>
<p><img src="./cocoapods/rotating-triangle.gif" alt="a rotating triangle" /></p>
<p>The full source for this example is
<a href="https://github.com/google/filament/tree/main/ios/samples/HelloCocoaPods">here</a>.
If you're just looking to get something up and running quickly, download the
project, <code>pod install</code>, build, and run.</p>
<p>We'll be walking through 7 steps to get the rotating triangle up and running.
All of the code we'll be writing will be in a single ViewController.mm file, and
you can follow along
<a href="https://github.com/google/filament/blob/main/ios/samples/HelloCocoaPods/HelloCocoaPods/ViewController.mm">here</a>.</p>
<ol>
<li><a href="#creating-a-boilerplate-app-with-filament">Creating a Boilerplate App</a></li>
<li><a href="#instantiating-the-filament-engine">Instantiating Filament</a></li>
<li><a href="#creating-a-swapchain">Creating a SwapChain</a></li>
<li><a href="#clearing-the-screen">Clearing the Screen</a></li>
<li><a href="#drawing-a-triangle">Drawing a Triangle</a></li>
<li><a href="#compiling-a-custom-material">Compiling a Custom Material</a></li>
<li><a href="#animating-the-triangle">Animating the Triangle</a></li>
</ol>
<h2 id="creating-a-boilerplate-app-with-filament"><a class="header" href="#creating-a-boilerplate-app-with-filament">Creating a Boilerplate App with Filament</a></h2>
<p>We'll start fresh by creating a new Single View App in Xcode.</p>
<p><img src="./cocoapods/single-view-app.png" alt="create a single view app in Xcodde" /></p>
<p>Give your app a name, and use the default options.</p>
<p><img src="./cocoapods/default-options.png" alt="use the default options in Xcode" /></p>
<p>If you haven't used CocoaPods before, I recommend watching
<a href="https://www.youtube.com/watch?v=iEAjvNRdZa0">this Route 85 video</a> to help you
get set up.</p>
<p>Create a Podfile in the Xcode project directory with the following:</p>
<pre><code class="language-text">platform :ios, '11.0'
target 'HelloCocoaPods' do
pod 'Filament'
end
</code></pre>
<p>Then run:</p>
<pre><code class="language-shell">pod install
</code></pre>
<p>Close the project and then re-open the newly created HelloCocoaPods.xcworkspace
file.</p>
<h2 id="instantiating-the-filament-engine"><a class="header" href="#instantiating-the-filament-engine">Instantiating the Filament Engine</a></h2>
<p>Before we do anything with Filament, we first need to include the appropriate
headers. Filament exposes a C++ API, so any files that include Filament headers
need to be compiled in a variant of C++. We'll be using Objective-C++.</p>
<p>You should be able to simply change the extension of the default ViewController
from .m to .mm, though I've found Xcode to be buggy with this on occasion. To
make sure Xcode recognizes it as an Objective-C++ file, check that the type of
file is &quot;Objective-C++ Source&quot;.</p>
<p><img src="./cocoapods/obj-cpp.png" alt="change the type of ViewController.m to Objective-C++" /></p>
<p>Then, add the following to the top of ViewController.</p>
<pre><code class="language-obj-c">#include &lt;filament/Engine.h&gt;
using namespace filament;
</code></pre>
<p>We'll need to keep track of a few Filament objects, so let's add a section for
private instance variables and add a pointer for our <code>Engine</code> instance.</p>
<pre><code class="language-obj-c">@implementation Viewcontroller {
Engine* _engine;
}
</code></pre>
<p>The Filament <code>Engine</code> is our main entrypoint into Filament. We start by
instantiating it inside <code>viewDidLoad</code>.</p>
<pre><code class="language-obj-c">- (void)viewDidLoad {
[super viewDidLoad];
_engine = Engine::create(Engine::Backend::METAL);
}
</code></pre>
<p>We specify <code>Engine::Backend::METAL</code> to select the Metal backend. Filament also
supports OpenGL on iOS, but we strongly recommend sticking to Metal.</p>
<p>Every Filament object we create must also be destroyed. Add the <code>dealloc</code> method
and the following:</p>
<pre><code class="language-obj-c">- (void)dealloc {
_engine-&gt;destroy(&amp;_engine);
}
</code></pre>
<p>If you compile and run the app now you should see output similar to the
following:</p>
<pre><code>FEngine (64 bits) created at 0x10ab94000 (threading is enabled)
FEngine resolved backend: Metal
</code></pre>
<h2 id="creating-a-swapchain"><a class="header" href="#creating-a-swapchain">Creating a SwapChain</a></h2>
<p>Before we can render anything, we'll first need to create a <code>SwapChain</code>. The
<code>SwapChain</code> represents a platform-specific surface that can be rendered into. On
iOS with Metal, it's a
<a href="https://developer.apple.com/documentation/quartzcore/cametallayer"><code>CAMetalLayer</code></a>.</p>
<p>We could set up our own <code>CAMetalLayer</code> if we wanted to, but Apple provides a
<code>MTKView</code> that is already backed by a <code>CAMetalLayer</code>. It also has a delegate
protocol with some methods that will make things easier for us.</p>
<p>Inside Main.storyboard, change the type of ViewController's view to a <code>MTKView</code>.</p>
<p><img src="./cocoapods/view.png" alt="ViewController view" /></p>
<p><img src="./cocoapods/mtkview.gif" alt="change type of MTKView" /></p>
<p>Include the SwapChain.h and MTKView.h headers and make the <code>ViewController</code>
conform to the <code>MTKViewDelegate</code> protocol.</p>
<pre><code class="language-obj-c">#include &lt;filament/SwapChain.h&gt;
#import &lt;MetalKit/MTKView.h&gt;
@interface ViewController () &lt;MTKViewDelegate&gt;
@end
</code></pre>
<p>Add a new private var:</p>
<pre><code class="language-obj-c">SwapChain* _swapChain;
</code></pre>
<p>Inside <code>viewDidLoad</code>, we'll set our <code>ViewController</code> as the <code>MTKView</code> delegate
and instantiate our <code>SwapChain</code>. To instantiate the <code>SwapChain</code>, we pass in
<code>view.layer</code> which, because we set our <code>View</code> to a <code>MTKView</code>, will be a
<code>CAMetalLayer</code>. Filament's API is platform-agnostic, which is why we need to
cast the layer to a <code>void*</code>.</p>
<pre><code class="language-obj-c">MTKView* mtkView = (MTKView*) self.view;
mtkView.delegate = self;
_swapChain = _engine-&gt;createSwapChain((__bridge void*) mtkView.layer);
</code></pre>
<p>The <code>SwapChain</code> needs to be destroyed in our <code>dealloc</code> function. We'll destroy
the objects in the reverse order we created them; the <code>Engine</code> object should
always be the the last object we destroy.</p>
<pre><code class="language-obj-c">_engine-&gt;destroy(_swapChain);
_engine-&gt;destroy(&amp;_engine);
</code></pre>
<p>Finally, add stubs for some <code>MTKViewDelegate</code> methods, which we'll fill in
later.</p>
<pre><code class="language-obj-c">- (void)mtkView:(nonnull MTKView*)view drawableSizeWillChange:(CGSize)size {
// todo
}
- (void)drawInMTKView:(nonnull MTKView*)view {
// todo
}
</code></pre>
<h2 id="clearing-the-screen"><a class="header" href="#clearing-the-screen">Clearing The Screen</a></h2>
<p>We now have a Filament <code>Engine</code> and <code>SwapChain</code> set up. We'll need a few more
objects before we can render anything.</p>
<p>A Filament <code>Renderer</code> gives us an API to render frames into the <code>SwapChain</code>. It
takes a <code>View</code>, which defines a <code>Viewport</code>, <code>Scene</code> and <code>Camera</code> for rendering.
The <code>Camera</code> represents a vantage point into a <code>Scene</code>, which contains
references to all the entities we want to render.</p>
<p>Creating these are objects is straightforward. First, include the appropriate
headers</p>
<pre><code class="language-c++">#include &lt;filament/Renderer.h&gt;
#include &lt;filament/View.h&gt;
#include &lt;filament/Camera.h&gt;
#include &lt;filament/Scene.h&gt;
#include &lt;filament/Viewport.h&gt;
#include &lt;utils/Entity.h&gt;
#include &lt;utils/EntityManager.h&gt;
using namespace utils;
</code></pre>
<p>add the following private vars</p>
<pre><code class="language-obj-c">Renderer* _renderer;
View* _view;
Scene* _scene;
Camera* _camera;
Entity _cameraEntity;
</code></pre>
<p>and then instantiate them</p>
<pre><code class="language-obj-c">_renderer = _engine-&gt;createRenderer();
_view = _engine-&gt;createView();
_scene = _engine-&gt;createScene();
</code></pre>
<p>The camera is a bit special. Filament uses an entity-component system, so we'll
first need to create an <code>Entity</code> which we then attach a <code>Camera</code> component to.</p>
<pre><code class="language-obj-c">_cameraEntity = EntityManager::get().create();
_camera = _engine-&gt;createCamera(_cameraEntity);
</code></pre>
<p>Let's also inform our <code>Renderer</code> to clear to a light blue clear color, so we can
know everything is working.</p>
<pre><code class="language-obj-c">_renderer-&gt;setClearOptions({
.clearColor = {0.25f, 0.5f, 1.0f, 1.0f},
.clear = true
});
</code></pre>
<p>The <code>Camera</code> and <code>Scene</code> need to be wired up to the <code>View</code>.</p>
<pre><code class="language-obj-c">_view-&gt;setScene(_scene);
_view-&gt;setCamera(_camera);
</code></pre>
<p>Our newly created objects get cleaned up inside <code>dealloc</code>.</p>
<pre><code class="language-obj-c">_engine-&gt;destroyCameraComponent(_cameraEntity);
EntityManager::get().destroy(_cameraEntity);
_engine-&gt;destroy(_scene);
_engine-&gt;destroy(_view);
_engine-&gt;destroy(_renderer);
</code></pre>
<p>We need to set the <code>Viewport</code> on our <code>View</code>, which we want to do whenever the
size of our <code>SwapChain</code> changes. We'll also update the projection matrix on our
camera.</p>
<p>Let's create a new method, <code>resize:</code>, which will update the <code>Viewport</code> on our
<code>View</code> to a given size. We'll call it in the <code>mtkView:drawableSizeWillChange:</code>
delegate method, and at the end of <code>viewDidLoad</code>:</p>
<pre><code class="language-obj-c">- (void)resize:(CGSize)size {
_view-&gt;setViewport({0, 0, (uint32_t) size.width, (uint32_t) size.height});
const double aspect = size.width / size.height;
const double left = -2.0 * aspect;
const double right = 2.0 * aspect;
const double bottom = -2.0;
const double top = 2.0;
const double near = 0.0;
const double far = 1.0;
_camera-&gt;setProjection(Camera::Projection::ORTHO, left, right, bottom, top, near, far);
}
- (void)viewDidLoad {
...
// Give our View a starting size based on the drawable size.
[self resize:mtkView.drawableSize];
}
- (void)mtkView(nonnull MTKView*)view drawableSizeWillChange:(CGSize)size {
[self resize:size];
}
</code></pre>
<p>Lastly, in order to render, we'll call a few Filament API methods inside the
<code>drawInMTKView:</code> method:</p>
<pre><code class="language-obj-c">- (void)drawInMTKView:(nonnull MTKView*)view {
if (_renderer-&gt;beginFrame(_swapChain)) {
_renderer-&gt;render(_view);
_renderer-&gt;endFrame();
}
}
</code></pre>
<p>The <code>beginFrame</code> method instructs Filament to start rendering to our specific
<code>SwapChain</code> instance. It returns <code>true</code> if the engine is ready for another
frame. It returns <code>false</code> to signal us to skip this frame, which could happen if
we're sending frames down too quickly for the GPU to process.</p>
<p>At this point, you should be able to build and run the app, and you'll see a
blue screen.</p>
<p><img src="./cocoapods/blue-screen.png" alt="blue screen after clearing" /></p>
<h2 id="drawing-a-triangle"><a class="header" href="#drawing-a-triangle">Drawing a Triangle</a></h2>
<p>In order to draw a triangle, we need to create vertex and index buffers to
define its geometry. We'll then create a <code>Renderable</code> component.</p>
<p>We'll start by including some additional headers and adding a few new private
vars:</p>
<pre><code class="language-obj-c">#include &lt;filament/VertexBuffer.h&gt;
#include &lt;filament/IndexBuffer.h&gt;
#include &lt;filament/RenderableManager.h&gt;
...
VertexBuffer* _vertexBuffer;
IndexBuffer* _indexBuffer;
Entity _triangle;
</code></pre>
<p>First, we'll define the data for a single vertex.</p>
<pre><code class="language-obj-c">struct Vertex {
math::float2 position;
math::float3 color;
};
</code></pre>
<p>Creating a <code>VertexBuffer</code> and <code>IndexBuffer</code> is a matter of giving Filament a
pointer to the data, along with information on its layout and size. Filament
uses <code>BufferDescriptors</code> to accomplish this.</p>
<p>Inside <code>viewDidLoad</code>, we'll statically define some verticies and indices and
create a <code>BufferDescriptor</code> for each.</p>
<pre><code class="language-obj-c">static const Vertex TRIANGLE_VERTICES[3] = {
{ { 0.867, -0.500}, {1.0, 0.0, 0.0} },
{ { 0.000, 1.000}, {0.0, 1.0, 0.0} },
{ {-0.867, -0.500}, {0.0, 0.0, 1.0} },
};
static const uint16_t TRIANGLE_INDICES[3] = { 0, 1, 2 };
VertexBuffer::BufferDescriptor vertices(TRIANGLE_VERTICES, sizeof(Vertex) * 3, nullptr);
IndexBuffer::BufferDescriptor indices(TRIANGLE_INDICES, sizeof(uint16_t) * 3, nullptr);
</code></pre>
<p>The last argument is an optional callback function, which will be called after
Filament is done uploading the data to the GPU. Inside the callback, you'd
typically release the memory of any buffers via a <code>free</code> or <code>delete</code> call. We
pass <code>nullptr</code> because we don't need a callback as our vertex and index buffer
memory is static.</p>
<p>Now we can instantiate our <code>VertexBuffer</code> and <code>IndexBuffer</code>.</p>
<pre><code class="language-obj-c">using Type = VertexBuffer::AttributeType;
const uint8_t stride = sizeof(Vertex);
_vertexBuffer = VertexBuffer::Builder()
.vertexCount(3)
.bufferCount(1)
.attribute(VertexAttribute::POSITION, 0, Type::FLOAT2, offsetof(Vertex, position), stride)
.attribute(VertexAttribute::COLOR, 0, Type::FLOAT3, offsetof(Vertex, color), stride)
.build(*_engine);
_indexBuffer = IndexBuffer::Builder()
.indexCount(3)
.bufferType(IndexBuffer::IndexType::USHORT)
.build(*_engine);
_vertexBuffer-&gt;setBufferAt(*_engine, 0, std::move(vertices));
_indexBuffer-&gt;setBuffer(*_engine, std::move(indices));
</code></pre>
<p>We first create an <code>Entity</code> like we did for our camera. This time, we're
attaching a <code>Renderable</code> component to the entity. The <code>Renderable</code> component
takes geometry defined by our vertex and index buffers, and makes the entity
visible in our scene.</p>
<pre><code class="language-obj-c">_triangle = utils::EntityManager::get().create();
using Primitive = RenderableManager::PrimitiveType;
RenderableManager::Builder(1)
.geometry(0, Primitive::TRIANGLES, _vertexBuffer, _indexBuffer, 0, 3)
.culling(false)
.receiveShadows(false)
.castShadows(false)
.build(*_engine, _triangle);
// Add the triangle to the scene.
_scene-&gt;addEntity(_triangle);
</code></pre>
<p>Destroy the entity and buffers in <code>dealloc</code>.</p>
<pre><code class="language-obj-c">_engine-&gt;destroy(_triangle);
EntityManager::get().destroy(_triangle);
_engine-&gt;destroy(_indexBuffer);
_engine-&gt;destroy(_vertexBuffer);
</code></pre>
<p>If you build and run the app now, you should see a plain white triangle. When we
created the renderable, we didn't specify any specific <code>Material</code> to use, so
Filament used a default, white material. Let's create a custom material to color
the triangle.</p>
<p><img src="./cocoapods/white-triangle.png" alt="a white triangle" /></p>
<h2 id="compiling-a-custom-material"><a class="header" href="#compiling-a-custom-material">Compiling a Custom Material</a></h2>
<p>For simplicity, we're going to compile a custom material at runtime. For
production, we recommend using our matc tool to compile materials offline. You
can download it as part of one of our
<a href="https://github.com/google/filament/releases">releases</a>.</p>
<p>First, add a few more headers. We'll be using Filament's filamat library to
compile a custom material.</p>
<pre><code class="language-c++">#include &lt;filament/Material.h&gt;
#include &lt;filament/MaterialInstance.h&gt;
#include &lt;filamat/MaterialBuilder.h&gt;
</code></pre>
<p>We'll store our material in a new private var. We'll also need one to store a
material <em>instance</em>. You can think of a material as a &quot;template&quot;, where a
material instance is an instantiation of the template (similar to OOP classes
and instances). For more information on Filament materials, read the
<a href="https://google.github.io/filament/Materials.html">Filament Materials Guide</a>.</p>
<pre><code class="language-obj-c">Material* _material;
MaterialInstance* _materialInstance;
</code></pre>
<p>We'll use the filamat library to compile a material into a package, which we can
then load into Filament. The material will be simple; it will load the
interpolated color attribute and set it as the <code>baseColor</code>.</p>
<p>Make sure to insert this code into <code>viewDidLoad</code> <em>before</em> we create our
<code>Renderable</code>.</p>
<pre><code class="language-obj-c">// init must be called before we can build any materials.
filamat::MaterialBuilder::init();
// Compile a custom material to use on the triangle.
filamat::Package pkg = filamat::MaterialBuilder()
// The material name, only used for debugging purposes.
.name(&quot;Triangle material&quot;)
// Use the unlit shading mode, because we don't have any lights in our scene.
.shading(filamat::MaterialBuilder::Shading::UNLIT)
// Expose the COLOR attribute visible to our shader code.
.require(VertexAttribute::COLOR)
// Custom GLSL fragment shader
.material(&quot;void material (inout MaterialInputs material) {&quot;
&quot; prepareMaterial(material);&quot;
&quot; material.baseColor = getColor();&quot;
&quot;}&quot;)
// Compile for Metal on mobile platforms.
.targetApi(filamat::MaterialBuilder::TargetApi::METAL)
.platform(filamat::MaterialBuilder::Platform::MOBILE)
.build();
assert(pkg.isValid());
// shutdown should be called after all materials are built.
filamat::MaterialBuilder::shutdown();
</code></pre>
<p>Now that we have a <code>filamat::Package</code> representing the material, we can use it
to instantiate a Filament <code>Material</code>. Note that again, we recommend using the
matc command-line tool to compile material packages during your app's
compilation phase if possible, instead of at run-time.</p>
<pre><code class="language-obj-c">// Create a Filament material from the Package.
_material = Material::Builder()
.package(pkg.getData(), pkg.getSize())
.build(*_engine);
_materialInstance = _material-&gt;getDefaultInstance();
</code></pre>
<p>Now we can use the <code>MaterialInstance</code> when creating our <code>Renderable</code>.</p>
<pre><code class="language-obj-c">// Create a renderable using our geometry and material.
using Primitive = RenderableManager::PrimitiveType;
RenderableManager::Builder(1)
.geometry(0, Primitive::TRIANGLES, _vertexBuffer, _indexBuffer, 0, 3)
// Use the MaterialInstance we just created.
.material(0, _materialInstance)
.culling(false)
.receiveShadows(false)
.castShadows(false)
.build(*_engine, _triangle);
</code></pre>
<p>Lastly, we make sure to destroy everything inside <code>dealloc</code>.</p>
<pre><code class="language-obj-c">_engine-&gt;destroy(_materialInstance);
_engine-&gt;destroy(_material);
</code></pre>
<p>Build and run. You should see the same triangle, but with colors.</p>
<p><img src="./cocoapods/colored-triangle.png" alt="the triangle with our custom material" /></p>
<h2 id="animating-the-triangle"><a class="header" href="#animating-the-triangle">Animating the Triangle</a></h2>
<p>We'll do this by animating a transform on our triangle entity. First, include a
new header.</p>
<pre><code class="language-obj-c">#include &lt;filament/TransformManager.h&gt;
</code></pre>
<p>When we create our triangle entity, we'll also attach a transform component.
We've already seen two other components: <code>Renderable</code> and <code>Camera</code>. The
<code>Transform</code> component allows us to set world-space transformations on entities.</p>
<p>Inside <code>viewDidLoad</code>, after we create the triangle entity's <code>Renderable</code>
component, we'll also attach a <code>Transform</code> component.</p>
<pre><code class="language-obj-c">// Add a Transform component to the triangle, so we can animate it.
_engine-&gt;getTransformManager().create(_triangle);
</code></pre>
<p>Create a new function, <code>update</code>, and add call it inside the <code>drawInMTKView:</code>
method.</p>
<pre><code class="language-obj-c">- (void)update {
auto&amp; tm = _engine-&gt;getTransformManager();
auto i = tm.getInstance(_triangle);
const auto time = CACurrentMediaTime();
tm.setTransform(i, math::mat4f::rotation(time, math::float3 {0.0, 0.0, 1.0}));
}
- (void)drawInMTKView:(nonnull MTKView*)view {
[self update];
if (_renderer-&gt;beginFrame(_swapChain)) {
_renderer-&gt;render(_view);
_renderer-&gt;endFrame();
}
}
</code></pre>
<p>Now we should see the triangle rotate around its z axis.</p>
<p><img src="./cocoapods/rotating-triangle.gif" alt="a rotating triangle" /></p>
<h2 id="next-steps"><a class="header" href="#next-steps">Next Steps</a></h2>
<p>In this guide we've covered how to install Filament with CocoaPods and get
rendering using the Metal backend. We also compiled a custom material. Again,
here's the
<a href="https://github.com/google/filament/tree/main/ios/samples/HelloCocoaPods">complete sample code</a>
for the app. If you're interesting in learning more, check out Filament's
additional
<a href="https://github.com/google/filament/tree/main/ios/samples">iOS samples</a>. If you
have any problems, feel free to open an
<a href="https://github.com/google/filament/issues">issue</a>.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="ios.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="web.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="ios.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="web.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<!-- Livereload script (if served using the cli tool) -->
<script>
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
const socket = new WebSocket(wsAddress);
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload();
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<script>
window.playground_copyable = true;
</script>
<script src="elasticlunr.min.js"></script>
<script src="mark.min.js"></script>
<script src="searcher.js"></script>
<script src="clipboard.min.js"></script>
<script src="highlight.js"></script>
<script src="book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Before

Width:  |  Height:  |  Size: 2.4 MiB

After

Width:  |  Height:  |  Size: 2.4 MiB

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 104 KiB

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

+246
View File
@@ -0,0 +1,246 @@
<!DOCTYPE HTML>
<html lang="en" class="light" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Filament Design - Filament</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="favicon.svg">
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="highlight.css">
<link rel="stylesheet" href="tomorrow-night.css">
<link rel="stylesheet" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- MathJax -->
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
</head>
<body class="sidebar-visible no-js">
<div id="body-container">
<!-- Provide site root to javascript -->
<script>
var path_to_root = "";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('light')
html.classList.add(theme);
var body = document.querySelector('body');
body.classList.remove('no-js')
body.classList.add('js');
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var body = document.querySelector('body');
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
body.classList.remove('sidebar-visible');
body.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded "><a href="core.html"><strong aria-hidden="true">1.</strong> Core Documentation</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="core-design.html" class="active"><strong aria-hidden="true">1.1.</strong> Filament Design</a></li><li class="chapter-item expanded "><a href="core-materials.html"><strong aria-hidden="true">1.2.</strong> Materials Overview</a></li></ol></li><li class="chapter-item expanded "><a href="api.html"><strong aria-hidden="true">2.</strong> API Reference</a></li><li class="chapter-item expanded "><a href="ios.html"><strong aria-hidden="true">3.</strong> iOS</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="cocoapods.html"><strong aria-hidden="true">3.1.</strong> CocoaPods Hello Triangle</a></li></ol></li><li class="chapter-item expanded "><a href="web.html"><strong aria-hidden="true">4.</strong> Web</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="web-tutorials.html"><strong aria-hidden="true">4.1.</strong> Tutorials</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="web-tutorial-triangle.html"><strong aria-hidden="true">4.1.1.</strong> Triangle Tutorial</a></li><li class="chapter-item expanded "><a href="web-tutorial-redball.html"><strong aria-hidden="true">4.1.2.</strong> Redball Tutorial</a></li><li class="chapter-item expanded "><a href="web-tutorial-suzanne.html"><strong aria-hidden="true">4.1.3.</strong> Suzanne Tutorial</a></li></ol></li></ol></li><li class="chapter-item expanded "><a href="dev.html"><strong aria-hidden="true">5.</strong> Developing Filament</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="dev-debugging.html"><strong aria-hidden="true">5.1.</strong> Filament Debugging</a></li><li class="chapter-item expanded "><a href="dev-spirv-debugging.html"><strong aria-hidden="true">5.2.</strong> Investigating SPIRV Issues</a></li><li class="chapter-item expanded "><a href="dev-versioning.html"><strong aria-hidden="true">5.3.</strong> Versioning</a></li><li class="chapter-item expanded "><a href="dev-vulkan.html"><strong aria-hidden="true">5.4.</strong> Vulkan Backend</a></li></ol></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<!-- Track and set sidebar scroll position -->
<script>
var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox');
sidebarScrollbox.addEventListener('click', function(e) {
if (e.target.tagName === 'A') {
sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop);
}
}, { passive: true });
var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
sessionStorage.removeItem('sidebar-scroll');
if (sidebarScrollTop) {
// preserve sidebar scroll position when navigating via links within sidebar
sidebarScrollbox.scrollTop = sidebarScrollTop;
} else {
// scroll sidebar to current active section when navigating via "next/previous chapter" buttons
var activeSection = document.querySelector('#sidebar .active');
if (activeSection) {
activeSection.scrollIntoView({ block: 'center' });
}
}
</script>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Filament</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="filament-design"><a class="header" href="#filament-design">Filament Design</a></h1>
<p>The <a href="./Filament.html">Filament Design</a> doc gives a high level overview of the
PBR rendering techniques used in Filament.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="core.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="core-materials.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="core.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="core-materials.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<!-- Livereload script (if served using the cli tool) -->
<script>
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
const socket = new WebSocket(wsAddress);
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload();
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<script>
window.playground_copyable = true;
</script>
<script src="elasticlunr.min.js"></script>
<script src="mark.min.js"></script>
<script src="searcher.js"></script>
<script src="clipboard.min.js"></script>
<script src="highlight.js"></script>
<script src="book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>
File diff suppressed because it is too large Load Diff
+266
View File
@@ -0,0 +1,266 @@
<!DOCTYPE HTML>
<html lang="en" class="light" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Core Documentation - Filament</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="favicon.svg">
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="highlight.css">
<link rel="stylesheet" href="tomorrow-night.css">
<link rel="stylesheet" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- MathJax -->
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
</head>
<body class="sidebar-visible no-js">
<div id="body-container">
<!-- Provide site root to javascript -->
<script>
var path_to_root = "";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
var html = document.querySelector('html');
html.classList.remove('light')
html.classList.add(theme);
var body = document.querySelector('body');
body.classList.remove('no-js')
body.classList.add('js');
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var body = document.querySelector('body');
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
body.classList.remove('sidebar-visible');
body.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div class="sidebar-scrollbox">
<ol class="chapter"><li class="chapter-item expanded "><a href="core.html" class="active"><strong aria-hidden="true">1.</strong> Core Documentation</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="core-design.html"><strong aria-hidden="true">1.1.</strong> Filament Design</a></li><li class="chapter-item expanded "><a href="core-materials.html"><strong aria-hidden="true">1.2.</strong> Materials Overview</a></li></ol></li><li class="chapter-item expanded "><a href="api.html"><strong aria-hidden="true">2.</strong> API Reference</a></li><li class="chapter-item expanded "><a href="ios.html"><strong aria-hidden="true">3.</strong> iOS</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="cocoapods.html"><strong aria-hidden="true">3.1.</strong> CocoaPods Hello Triangle</a></li></ol></li><li class="chapter-item expanded "><a href="web.html"><strong aria-hidden="true">4.</strong> Web</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="web-tutorials.html"><strong aria-hidden="true">4.1.</strong> Tutorials</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="web-tutorial-triangle.html"><strong aria-hidden="true">4.1.1.</strong> Triangle Tutorial</a></li><li class="chapter-item expanded "><a href="web-tutorial-redball.html"><strong aria-hidden="true">4.1.2.</strong> Redball Tutorial</a></li><li class="chapter-item expanded "><a href="web-tutorial-suzanne.html"><strong aria-hidden="true">4.1.3.</strong> Suzanne Tutorial</a></li></ol></li></ol></li><li class="chapter-item expanded "><a href="dev.html"><strong aria-hidden="true">5.</strong> Developing Filament</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="dev-debugging.html"><strong aria-hidden="true">5.1.</strong> Filament Debugging</a></li><li class="chapter-item expanded "><a href="dev-spirv-debugging.html"><strong aria-hidden="true">5.2.</strong> Investigating SPIRV Issues</a></li><li class="chapter-item expanded "><a href="dev-versioning.html"><strong aria-hidden="true">5.3.</strong> Versioning</a></li><li class="chapter-item expanded "><a href="dev-vulkan.html"><strong aria-hidden="true">5.4.</strong> Vulkan Backend</a></li></ol></li></ol>
</div>
<div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
</nav>
<!-- Track and set sidebar scroll position -->
<script>
var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox');
sidebarScrollbox.addEventListener('click', function(e) {
if (e.target.tagName === 'A') {
sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop);
}
}, { passive: true });
var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
sessionStorage.removeItem('sidebar-scroll');
if (sidebarScrollTop) {
// preserve sidebar scroll position when navigating via links within sidebar
sidebarScrollbox.scrollTop = sidebarScrollTop;
} else {
// scroll sidebar to current active section when navigating via "next/previous chapter" buttons
var activeSection = document.querySelector('#sidebar .active');
if (activeSection) {
activeSection.scrollIntoView({ block: 'center' });
}
}
</script>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Filament</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="core-documentation"><a class="header" href="#core-documentation">Core Documentation</a></h1>
<h2 id="about"><a class="header" href="#about">About</a></h2>
<p>Filament is a real-time physically based rendering engine for Android, iOS,
Linux, macOS, Windows, and WebGL. It is designed to be as small as possible and
as efficient as possible on Android.</p>
<p>This book contains demos, tutorials, and links to important reference materials
for developing software with Filament.</p>
<p>In addition to the contents in this book, the following external resources are
also available.</p>
<ul>
<li>
<p><a href="https://github.com/google/filament">GitHub Project</a></p>
<p>Contains build instructions, instructions for contributors, etc.</p>
</li>
<li>
<p><a href="./Material%20Properties.pdf">Materials Ref Sheet</a></p>
<p>A visual guide that demonstrates the effects of tweaking various PBR
parameters.</p>
</li>
</ul>
<p>To report errors in this book, please refer to the Filament project's
<a href="https://github.com/google/filament/issues">issue tracker</a>.</p>
<h2 id="authors"><a class="header" href="#authors">Authors</a></h2>
<ul>
<li><a href="https://github.com/romainguy">Romain Guy</a>,
<a href="https://twitter.com/romainguy">@romainguy</a></li>
<li><a href="https://github.com/pixelflinger">Mathias Agopian</a>,
<a href="https://twitter.com/darthmoosious">@darthmoosious</a></li>
</ul>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="next prefetch" href="core-design.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="next prefetch" href="core-design.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<!-- Livereload script (if served using the cli tool) -->
<script>
const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsAddress = wsProtocol + "//" + location.host + "/" + "__livereload";
const socket = new WebSocket(wsAddress);
socket.onmessage = function (event) {
if (event.data === "reload") {
socket.close();
location.reload();
}
};
window.onbeforeunload = function() {
socket.close();
}
</script>
<script>
window.playground_copyable = true;
</script>
<script src="elasticlunr.min.js"></script>
<script src="mark.min.js"></script>
<script src="searcher.js"></script>
<script src="clipboard.min.js"></script>
<script src="highlight.js"></script>
<script src="book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>
+587
View File
@@ -0,0 +1,587 @@
/* CSS for UI elements (a.k.a. chrome) */
@import 'variables.css';
html {
scrollbar-color: var(--scrollbar) var(--bg);
}
#searchresults a,
.content a:link,
a:visited,
a > .hljs {
color: var(--links);
}
/*
body-container is necessary because mobile browsers don't seem to like
overflow-x on the body tag when there is a <meta name="viewport"> tag.
*/
#body-container {
/*
This is used when the sidebar pushes the body content off the side of
the screen on small screens. Without it, dragging on mobile Safari
will want to reposition the viewport in a weird way.
*/
overflow-x: clip;
}
/* Menu Bar */
#menu-bar,
#menu-bar-hover-placeholder {
z-index: 101;
margin: auto calc(0px - var(--page-padding));
}
#menu-bar {
position: relative;
display: flex;
flex-wrap: wrap;
background-color: var(--bg);
border-block-end-color: var(--bg);
border-block-end-width: 1px;
border-block-end-style: solid;
}
#menu-bar.sticky,
.js #menu-bar-hover-placeholder:hover + #menu-bar,
.js #menu-bar:hover,
.js.sidebar-visible #menu-bar {
position: -webkit-sticky;
position: sticky;
top: 0 !important;
}
#menu-bar-hover-placeholder {
position: sticky;
position: -webkit-sticky;
top: 0;
height: var(--menu-bar-height);
}
#menu-bar.bordered {
border-block-end-color: var(--table-border-color);
}
#menu-bar i, #menu-bar .icon-button {
position: relative;
padding: 0 8px;
z-index: 10;
line-height: var(--menu-bar-height);
cursor: pointer;
transition: color 0.5s;
}
@media only screen and (max-width: 420px) {
#menu-bar i, #menu-bar .icon-button {
padding: 0 5px;
}
}
.icon-button {
border: none;
background: none;
padding: 0;
color: inherit;
}
.icon-button i {
margin: 0;
}
.right-buttons {
margin: 0 15px;
}
.right-buttons a {
text-decoration: none;
}
.left-buttons {
display: flex;
margin: 0 5px;
}
.no-js .left-buttons button {
display: none;
}
.menu-title {
display: inline-block;
font-weight: 200;
font-size: 2.4rem;
line-height: var(--menu-bar-height);
text-align: center;
margin: 0;
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.js .menu-title {
cursor: pointer;
}
.menu-bar,
.menu-bar:visited,
.nav-chapters,
.nav-chapters:visited,
.mobile-nav-chapters,
.mobile-nav-chapters:visited,
.menu-bar .icon-button,
.menu-bar a i {
color: var(--icons);
}
.menu-bar i:hover,
.menu-bar .icon-button:hover,
.nav-chapters:hover,
.mobile-nav-chapters i:hover {
color: var(--icons-hover);
}
/* Nav Icons */
.nav-chapters {
font-size: 2.5em;
text-align: center;
text-decoration: none;
position: fixed;
top: 0;
bottom: 0;
margin: 0;
max-width: 150px;
min-width: 90px;
display: flex;
justify-content: center;
align-content: center;
flex-direction: column;
transition: color 0.5s, background-color 0.5s;
}
.nav-chapters:hover {
text-decoration: none;
background-color: var(--theme-hover);
transition: background-color 0.15s, color 0.15s;
}
.nav-wrapper {
margin-block-start: 50px;
display: none;
}
.mobile-nav-chapters {
font-size: 2.5em;
text-align: center;
text-decoration: none;
width: 90px;
border-radius: 5px;
background-color: var(--sidebar-bg);
}
/* Only Firefox supports flow-relative values */
.previous { float: left; }
[dir=rtl] .previous { float: right; }
/* Only Firefox supports flow-relative values */
.next {
float: right;
right: var(--page-padding);
}
[dir=rtl] .next {
float: left;
right: unset;
left: var(--page-padding);
}
/* Use the correct buttons for RTL layouts*/
[dir=rtl] .previous i.fa-angle-left:before {content:"\f105";}
[dir=rtl] .next i.fa-angle-right:before { content:"\f104"; }
@media only screen and (max-width: 1080px) {
.nav-wide-wrapper { display: none; }
.nav-wrapper { display: block; }
}
/* sidebar-visible */
@media only screen and (max-width: 1380px) {
#sidebar-toggle-anchor:checked ~ .page-wrapper .nav-wide-wrapper { display: none; }
#sidebar-toggle-anchor:checked ~ .page-wrapper .nav-wrapper { display: block; }
}
/* Inline code */
:not(pre) > .hljs {
display: inline;
padding: 0.1em 0.3em;
border-radius: 3px;
}
:not(pre):not(a) > .hljs {
color: var(--inline-code-color);
overflow-x: initial;
}
a:hover > .hljs {
text-decoration: underline;
}
pre {
position: relative;
}
pre > .buttons {
position: absolute;
z-index: 100;
right: 0px;
top: 2px;
margin: 0px;
padding: 2px 0px;
color: var(--sidebar-fg);
cursor: pointer;
visibility: hidden;
opacity: 0;
transition: visibility 0.1s linear, opacity 0.1s linear;
}
pre:hover > .buttons {
visibility: visible;
opacity: 1
}
pre > .buttons :hover {
color: var(--sidebar-active);
border-color: var(--icons-hover);
background-color: var(--theme-hover);
}
pre > .buttons i {
margin-inline-start: 8px;
}
pre > .buttons button {
cursor: inherit;
margin: 0px 5px;
padding: 3px 5px;
font-size: 14px;
border-style: solid;
border-width: 1px;
border-radius: 4px;
border-color: var(--icons);
background-color: var(--theme-popup-bg);
transition: 100ms;
transition-property: color,border-color,background-color;
color: var(--icons);
}
@media (pointer: coarse) {
pre > .buttons button {
/* On mobile, make it easier to tap buttons. */
padding: 0.3rem 1rem;
}
}
pre > code {
padding: 1rem;
}
/* FIXME: ACE editors overlap their buttons because ACE does absolute
positioning within the code block which breaks padding. The only solution I
can think of is to move the padding to the outer pre tag (or insert a div
wrapper), but that would require fixing a whole bunch of CSS rules.
*/
.hljs.ace_editor {
padding: 0rem 0rem;
}
pre > .result {
margin-block-start: 10px;
}
/* Search */
#searchresults a {
text-decoration: none;
}
mark {
border-radius: 2px;
padding-block-start: 0;
padding-block-end: 1px;
padding-inline-start: 3px;
padding-inline-end: 3px;
margin-block-start: 0;
margin-block-end: -1px;
margin-inline-start: -3px;
margin-inline-end: -3px;
background-color: var(--search-mark-bg);
transition: background-color 300ms linear;
cursor: pointer;
}
mark.fade-out {
background-color: rgba(0,0,0,0) !important;
cursor: auto;
}
.searchbar-outer {
margin-inline-start: auto;
margin-inline-end: auto;
max-width: var(--content-max-width);
}
#searchbar {
width: 100%;
margin-block-start: 5px;
margin-block-end: 0;
margin-inline-start: auto;
margin-inline-end: auto;
padding: 10px 16px;
transition: box-shadow 300ms ease-in-out;
border: 1px solid var(--searchbar-border-color);
border-radius: 3px;
background-color: var(--searchbar-bg);
color: var(--searchbar-fg);
}
#searchbar:focus,
#searchbar.active {
box-shadow: 0 0 3px var(--searchbar-shadow-color);
}
.searchresults-header {
font-weight: bold;
font-size: 1em;
padding-block-start: 18px;
padding-block-end: 0;
padding-inline-start: 5px;
padding-inline-end: 0;
color: var(--searchresults-header-fg);
}
.searchresults-outer {
margin-inline-start: auto;
margin-inline-end: auto;
max-width: var(--content-max-width);
border-block-end: 1px dashed var(--searchresults-border-color);
}
ul#searchresults {
list-style: none;
padding-inline-start: 20px;
}
ul#searchresults li {
margin: 10px 0px;
padding: 2px;
border-radius: 2px;
}
ul#searchresults li.focus {
background-color: var(--searchresults-li-bg);
}
ul#searchresults span.teaser {
display: block;
clear: both;
margin-block-start: 5px;
margin-block-end: 0;
margin-inline-start: 20px;
margin-inline-end: 0;
font-size: 0.8em;
}
ul#searchresults span.teaser em {
font-weight: bold;
font-style: normal;
}
/* Sidebar */
.sidebar {
position: fixed;
left: 0;
top: 0;
bottom: 0;
width: var(--sidebar-width);
font-size: 0.875em;
box-sizing: border-box;
-webkit-overflow-scrolling: touch;
overscroll-behavior-y: contain;
background-color: var(--sidebar-bg);
color: var(--sidebar-fg);
}
[dir=rtl] .sidebar { left: unset; right: 0; }
.sidebar-resizing {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
.no-js .sidebar,
.js:not(.sidebar-resizing) .sidebar {
transition: transform 0.3s; /* Animation: slide away */
}
.sidebar code {
line-height: 2em;
}
.sidebar .sidebar-scrollbox {
overflow-y: auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
padding: 10px 10px;
}
.sidebar .sidebar-resize-handle {
position: absolute;
cursor: col-resize;
width: 0;
right: 0;
top: 0;
bottom: 0;
}
[dir=rtl] .sidebar .sidebar-resize-handle { right: unset; left: 0; }
.js .sidebar .sidebar-resize-handle {
cursor: col-resize;
width: 5px;
}
/* sidebar-hidden */
#sidebar-toggle-anchor:not(:checked) ~ .sidebar {
transform: translateX(calc(0px - var(--sidebar-width)));
z-index: -1;
}
[dir=rtl] #sidebar-toggle-anchor:not(:checked) ~ .sidebar {
transform: translateX(var(--sidebar-width));
}
.sidebar::-webkit-scrollbar {
background: var(--sidebar-bg);
}
.sidebar::-webkit-scrollbar-thumb {
background: var(--scrollbar);
}
/* sidebar-visible */
#sidebar-toggle-anchor:checked ~ .page-wrapper {
transform: translateX(var(--sidebar-width));
}
[dir=rtl] #sidebar-toggle-anchor:checked ~ .page-wrapper {
transform: translateX(calc(0px - var(--sidebar-width)));
}
@media only screen and (min-width: 620px) {
#sidebar-toggle-anchor:checked ~ .page-wrapper {
transform: none;
margin-inline-start: var(--sidebar-width);
}
[dir=rtl] #sidebar-toggle-anchor:checked ~ .page-wrapper {
transform: none;
}
}
.chapter {
list-style: none outside none;
padding-inline-start: 0;
line-height: 2.2em;
}
.chapter ol {
width: 100%;
}
.chapter li {
display: flex;
color: var(--sidebar-non-existant);
}
.chapter li a {
display: block;
padding: 0;
text-decoration: none;
color: var(--sidebar-fg);
}
.chapter li a:hover {
color: var(--sidebar-active);
}
.chapter li a.active {
color: var(--sidebar-active);
}
.chapter li > a.toggle {
cursor: pointer;
display: block;
margin-inline-start: auto;
padding: 0 10px;
user-select: none;
opacity: 0.68;
}
.chapter li > a.toggle div {
transition: transform 0.5s;
}
/* collapse the section */
.chapter li:not(.expanded) + li > ol {
display: none;
}
.chapter li.chapter-item {
line-height: 1.5em;
margin-block-start: 0.6em;
}
.chapter li.expanded > a.toggle div {
transform: rotate(90deg);
}
.spacer {
width: 100%;
height: 3px;
margin: 5px 0px;
}
.chapter .spacer {
background-color: var(--sidebar-spacer);
}
@media (-moz-touch-enabled: 1), (pointer: coarse) {
.chapter li a { padding: 5px 0; }
.spacer { margin: 10px 0; }
}
.section {
list-style: none outside none;
padding-inline-start: 20px;
line-height: 1.9em;
}
/* Theme Menu Popup */
.theme-popup {
position: absolute;
left: 10px;
top: var(--menu-bar-height);
z-index: 1000;
border-radius: 4px;
font-size: 0.7em;
color: var(--fg);
background: var(--theme-popup-bg);
border: 1px solid var(--theme-popup-border);
margin: 0;
padding: 0;
list-style: none;
display: none;
/* Don't let the children's background extend past the rounded corners. */
overflow: hidden;
}
[dir=rtl] .theme-popup { left: unset; right: 10px; }
.theme-popup .default {
color: var(--icons);
}
.theme-popup .theme {
width: 100%;
border: 0;
margin: 0;
padding: 2px 20px;
line-height: 25px;
white-space: nowrap;
text-align: start;
cursor: pointer;
color: inherit;
background: inherit;
font-size: inherit;
}
.theme-popup .theme:hover {
background-color: var(--theme-hover);
}
.theme-selected::before {
display: inline-block;
content: "✓";
margin-inline-start: -14px;
width: 14px;
}
+234
View File
@@ -0,0 +1,234 @@
/* Base styles and content styles */
@import 'variables.css';
:root {
/* Browser default font-size is 16px, this way 1 rem = 10px */
font-size: 62.5%;
color-scheme: var(--color-scheme);
}
html {
font-family: "Open Sans", sans-serif;
color: var(--fg);
background-color: var(--bg);
text-size-adjust: none;
-webkit-text-size-adjust: none;
}
body {
margin: 0;
font-size: 1.6rem;
overflow-x: hidden;
}
code {
font-family: var(--mono-font) !important;
font-size: var(--code-font-size);
direction: ltr !important;
}
/* make long words/inline code not x overflow */
main {
overflow-wrap: break-word;
}
/* make wide tables scroll if they overflow */
.table-wrapper {
overflow-x: auto;
}
/* Don't change font size in headers. */
h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
font-size: unset;
}
.left { float: left; }
.right { float: right; }
.boring { opacity: 0.6; }
.hide-boring .boring { display: none; }
.hidden { display: none !important; }
h2, h3 { margin-block-start: 2.5em; }
h4, h5 { margin-block-start: 2em; }
.header + .header h3,
.header + .header h4,
.header + .header h5 {
margin-block-start: 1em;
}
h1:target::before,
h2:target::before,
h3:target::before,
h4:target::before,
h5:target::before,
h6:target::before {
display: inline-block;
content: "»";
margin-inline-start: -30px;
width: 30px;
}
/* This is broken on Safari as of version 14, but is fixed
in Safari Technology Preview 117 which I think will be Safari 14.2.
https://bugs.webkit.org/show_bug.cgi?id=218076
*/
:target {
/* Safari does not support logical properties */
scroll-margin-top: calc(var(--menu-bar-height) + 0.5em);
}
.page {
outline: 0;
padding: 0 var(--page-padding);
margin-block-start: calc(0px - var(--menu-bar-height)); /* Compensate for the #menu-bar-hover-placeholder */
}
.page-wrapper {
box-sizing: border-box;
background-color: var(--bg);
}
.no-js .page-wrapper,
.js:not(.sidebar-resizing) .page-wrapper {
transition: margin-left 0.3s ease, transform 0.3s ease; /* Animation: slide away */
}
[dir=rtl] .js:not(.sidebar-resizing) .page-wrapper {
transition: margin-right 0.3s ease, transform 0.3s ease; /* Animation: slide away */
}
.content {
overflow-y: auto;
padding: 0 5px 50px 5px;
}
.content main {
margin-inline-start: auto;
margin-inline-end: auto;
max-width: var(--content-max-width);
}
.content p { line-height: 1.45em; }
.content ol { line-height: 1.45em; }
.content ul { line-height: 1.45em; }
.content a { text-decoration: none; }
.content a:hover { text-decoration: underline; }
.content img, .content video { max-width: 100%; }
.content .header:link,
.content .header:visited {
color: var(--fg);
}
.content .header:link,
.content .header:visited:hover {
text-decoration: none;
}
table {
margin: 0 auto;
border-collapse: collapse;
}
table td {
padding: 3px 20px;
border: 1px var(--table-border-color) solid;
}
table thead {
background: var(--table-header-bg);
}
table thead td {
font-weight: 700;
border: none;
}
table thead th {
padding: 3px 20px;
}
table thead tr {
border: 1px var(--table-header-bg) solid;
}
/* Alternate background colors for rows */
table tbody tr:nth-child(2n) {
background: var(--table-alternate-bg);
}
blockquote {
margin: 20px 0;
padding: 0 20px;
color: var(--fg);
background-color: var(--quote-bg);
border-block-start: .1em solid var(--quote-border);
border-block-end: .1em solid var(--quote-border);
}
.warning {
margin: 20px;
padding: 0 20px;
border-inline-start: 2px solid var(--warning-border);
}
.warning:before {
position: absolute;
width: 3rem;
height: 3rem;
margin-inline-start: calc(-1.5rem - 21px);
content: "ⓘ";
text-align: center;
background-color: var(--bg);
color: var(--warning-border);
font-weight: bold;
font-size: 2rem;
}
blockquote .warning:before {
background-color: var(--quote-bg);
}
kbd {
background-color: var(--table-border-color);
border-radius: 4px;
border: solid 1px var(--theme-popup-border);
box-shadow: inset 0 -1px 0 var(--theme-hover);
display: inline-block;
font-size: var(--code-font-size);
font-family: var(--mono-font);
line-height: 10px;
padding: 4px 5px;
vertical-align: middle;
}
:not(.footnote-definition) + .footnote-definition,
.footnote-definition + :not(.footnote-definition) {
margin-block-start: 2em;
}
.footnote-definition {
font-size: 0.9em;
margin: 0.5em 0;
}
.footnote-definition p {
display: inline;
}
.tooltiptext {
position: absolute;
visibility: hidden;
color: #fff;
background-color: #333;
transform: translateX(-50%); /* Center by moving tooltip 50% of its width left */
left: -8px; /* Half of the width of the icon */
top: -35px;
font-size: 0.8em;
text-align: center;
border-radius: 6px;
padding: 5px 8px;
margin: 5px;
z-index: 1000;
}
.tooltipped .tooltiptext {
visibility: visible;
}
.chapter li.part-title {
color: var(--sidebar-fg);
margin: 5px 0px;
font-weight: bold;
}
.result-no-output {
font-style: italic;
}
-283
View File
@@ -1,283 +0,0 @@
/*
* __ __
* /\ \ /\ \
* \ \ \___ __ __ \_\ \ __
* \ \ _ `\/\ \/\ \ /'_` \ /'__`\
* \ \ \ \ \ \ \_\ \/\ \_\ \/\ __/
* \ \_\ \_\/`____ \ \___,_\ \____\
* \/_/\/_/`/___/> \/__,_ /\/____/
* /\___/
* \/__/
*
* Designed, built, and released under MIT license by @mdo. Learn more at
* https://github.com/poole/hyde.
*/
/*
* Contents
*
* Global resets
* Sidebar
* Container
* Reverse layout
* Themes
*/
/*
* Global resets
*
* Update the foundational and global aspects of the page.
*/
html {
font-family: "Open Sans", Helvetica, Arial, sans-serif;
}
@media (min-width: 48em) {
html {
font-size: 16px;
}
}
@media (min-width: 58em) {
html {
font-size: 20px;
}
}
/*
* Sidebar
*
* Flexible banner for housing site name, intro, and "footer" content. Starts
* out above content in mobile and later moves to the side with wider viewports.
*/
.sidebar {
text-align: center;
padding: 2rem 1rem;
color: rgba(255,255,255,.5);
background-color: #202020;
}
@media (min-width: 48em) {
.sidebar {
position: fixed;
top: 0;
left: 0;
bottom: 0;
width: 18rem;
text-align: left;
}
}
/* Sidebar links */
.sidebar a {
color: #fff;
}
/* About section */
.sidebar-about h1 {
color: #fff;
margin-top: 0;
font-family: "Abril Fatface", serif;
font-size: 3.25rem;
}
/* Sidebar nav */
.sidebar-nav {
padding-left: 0;
list-style: none;
}
.sidebar-nav-item {
display: block;
}
a.sidebar-nav-item:hover,
a.sidebar-nav-item:focus {
text-decoration: underline;
}
.sidebar-nav-item.active {
font-weight: bold;
}
/* Sticky sidebar
*
* Add the `sidebar-sticky` class to the sidebar's container to affix it the
* contents to the bottom of the sidebar in tablets and up.
*/
@media (min-width: 48em) {
.sidebar-sticky {
position: absolute;
right: 1rem;
bottom: 1rem;
left: 1rem;
}
}
/* Container
*
* Align the contents of the site above the proper threshold with some margin-fu
* with a 25%-wide `.sidebar`.
*/
.content {
padding-top: 4rem;
padding-bottom: 4rem;
}
@media (min-width: 48em) {
.content {
max-width: 50rem;
margin-left: 20rem;
margin-right: 2rem;
}
}
@media (min-width: 64em) {
.content {
margin-left: 22rem;
margin-right: 4rem;
}
}
/*
* Reverse layout
*
* Flip the orientation of the page by placing the `.sidebar` on the right.
*/
@media (min-width: 48em) {
.layout-reverse .sidebar {
left: auto;
right: 0;
}
.layout-reverse .content {
margin-left: 2rem;
margin-right: 20rem;
}
}
@media (min-width: 64em) {
.layout-reverse .content {
margin-left: 4rem;
margin-right: 22rem;
}
}
/*
* Themes
*
* As of v1.1, Hyde includes optional themes to color the sidebar and links
* within blog posts. To use, add the class of your choosing to the `body`.
*/
/* Base16 (http://chriskempson.github.io/base16/#default) */
/* Red */
.theme-base-08 .sidebar {
background-color: #ac4142;
}
.theme-base-08 .content a,
.theme-base-08 .related-posts li a:hover {
color: #ac4142;
}
/* Orange */
.theme-base-09 .sidebar {
background-color: #d28445;
}
.theme-base-09 .content a,
.theme-base-09 .related-posts li a:hover {
color: #d28445;
}
/* Yellow */
.theme-base-0a .sidebar {
background-color: #f4bf75;
}
.theme-base-0a .content a,
.theme-base-0a .related-posts li a:hover {
color: #f4bf75;
}
/* Green */
.theme-base-0b .sidebar {
background-color: #90a959;
}
.theme-base-0b .content a,
.theme-base-0b .related-posts li a:hover {
color: #90a959;
}
/* Cyan */
.theme-base-0c .sidebar {
background-color: #75b5aa;
}
.theme-base-0c .content a,
.theme-base-0c .related-posts li a:hover {
color: #75b5aa;
}
/* Light Gray */
.theme-base-0d .sidebar {
background-color: #d0d0d0;
}
.theme-base-0d .content a,
.theme-base-0d .related-posts li a:hover {
color: #7080d0;
}
.theme-base-0d .lead {
color: black;
}
.theme-base-0d .sidebar a {
color: #34a;
}
.content.container {
padding-top: 32px;
}
.lightbulb {
max-height: 100%;
display: inline;
}
@media (min-width: 48em) {
.lightbulb {
margin-left: -10px;
}
}
iframe {
border: 0;
width: 100%;
margin-bottom: 15px;
}
/* Magenta */
.theme-base-0e .sidebar {
background-color: #aa759f;
}
.theme-base-0e .content a,
.theme-base-0e .related-posts li a:hover {
color: #aa759f;
}
/* Brown */
.theme-base-0f .sidebar {
background-color: #8f5536;
}
.theme-base-0f .content a,
.theme-base-0f .related-posts li a:hover {
color: #8f5536;
}
.post li {
list-style-type: none;
}
-403
View File
@@ -1,403 +0,0 @@
/*
* ___
* /\_ \
* _____ ___ ___\//\ \ __
* /\ '__`\ / __`\ / __`\\ \ \ /'__`\
* \ \ \_\ \/\ \_\ \/\ \_\ \\_\ \_/\ __/
* \ \ ,__/\ \____/\ \____//\____\ \____\
* \ \ \/ \/___/ \/___/ \/____/\/____/
* \ \_\
* \/_/
*
* Designed, built, and released under MIT license by @mdo. Learn more at
* https://github.com/poole/poole.
*/
/*
* Contents
*
* Body resets
* Custom type
* Messages
* Container
* Masthead
* Posts and pages
* Pagination
* Reverse layout
* Themes
*/
/*
* Body resets
*
* Update the foundational and global aspects of the page.
*/
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
html,
body {
margin: 0;
padding: 0;
}
html {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 16px;
line-height: 1.5;
}
@media (min-width: 38em) {
html {
font-size: 20px;
}
}
body {
color: #515151;
background-color: #fff;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
/* No `:visited` state is required by default (browsers will use `a`) */
a {
color: #268bd2;
text-decoration: none;
}
/* `:focus` is linked to `:hover` for basic accessibility */
a:hover,
a:focus {
text-decoration: underline;
}
/* Headings */
h1, h2, h3, h4, h5, h6 {
margin-bottom: .5rem;
font-weight: bold;
line-height: 1.25;
color: #313131;
text-rendering: optimizeLegibility;
}
h1 {
font-size: 2rem;
}
h2 {
margin-top: 1rem;
font-size: 1.5rem;
}
h3 {
margin-top: 1.5rem;
font-size: 1.25rem;
}
h4, h5, h6 {
margin-top: 1rem;
font-size: 1rem;
}
/* Body text */
p {
margin-top: 0;
margin-bottom: 1rem;
}
strong {
color: #303030;
}
/* Lists */
ul, ol, dl {
margin-top: 0;
margin-bottom: 1rem;
}
dt {
font-weight: bold;
}
dd {
margin-bottom: .5rem;
}
/* Misc */
hr {
position: relative;
margin: 1.5rem 0;
border: 0;
border-top: 1px solid #eee;
border-bottom: 1px solid #fff;
}
abbr {
font-size: 85%;
font-weight: bold;
color: #555;
text-transform: uppercase;
}
abbr[title] {
cursor: help;
border-bottom: 1px dotted #e5e5e5;
}
/* Code */
code,
pre {
font-family: Menlo, Monaco, "Courier New", monospace;
}
code {
padding: .25em .5em;
font-size: 85%;
color: #bf616a;
background-color: #f9f9f9;
border-radius: 3px;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
padding: 1rem;
font-size: .8rem;
line-height: 1.4;
white-space: pre;
white-space: pre-wrap;
word-break: break-all;
word-wrap: break-word;
background-color: #f9f9f9;
}
pre code {
padding: 0;
font-size: 100%;
color: inherit;
background-color: transparent;
}
.highlight {
margin-bottom: 1rem;
border-radius: 4px;
}
.highlight pre {
margin-bottom: 0;
}
/* Quotes */
blockquote {
padding: .5rem 1rem;
margin: .8rem 0;
color: #7a7a7a;
border-left: .25rem solid #e5e5e5;
}
blockquote p:last-child {
margin-bottom: 0;
}
@media (min-width: 30em) {
blockquote {
padding-right: 5rem;
padding-left: 1.25rem;
}
}
img {
display: block;
margin: 0 0 1rem;
border-radius: 5px;
max-width: 100%;
}
/* Tables */
table {
margin-bottom: 1rem;
width: 100%;
border: 1px solid #e5e5e5;
border-collapse: collapse;
}
td,
th {
padding: .25rem .5rem;
border: 1px solid #e5e5e5;
}
tbody tr:nth-child(odd) td,
tbody tr:nth-child(odd) th {
background-color: #f9f9f9;
}
/*
* Custom type
*
* Extend paragraphs with `.lead` for larger introductory text.
*/
.lead {
font-size: 1.25rem;
font-weight: 300;
}
/*
* Messages
*
* Show alert messages to users. You may add it to single elements like a `<p>`,
* or to a parent if there are multiple elements to show.
*/
.message {
margin-bottom: 1rem;
padding: 1rem;
color: #717171;
background-color: #f9f9f9;
}
/*
* Container
*
* Center the page content.
*/
.container {
max-width: 38rem;
padding-left: 1rem;
padding-right: 1rem;
margin-left: auto;
margin-right: auto;
}
/*
* Masthead
*
* Super small header above the content for site name and short description.
*/
.masthead {
padding-top: 1rem;
padding-bottom: 1rem;
margin-bottom: 3rem;
}
.masthead-title {
margin-top: 0;
margin-bottom: 0;
color: #505050;
}
.masthead-title a {
color: #505050;
}
.masthead-title small {
font-size: 75%;
font-weight: 400;
color: #c0c0c0;
letter-spacing: 0;
}
/*
* Posts and pages
*
* Each post is wrapped in `.post` and is used on default and post layouts. Each
* page is wrapped in `.page` and is only used on the page layout.
*/
.page,
.post {
margin-bottom: 4em;
}
/* Blog post or page title */
.page-title,
.post-title,
.post-title a {
color: #303030;
}
.page-title,
.post-title {
margin-top: 0;
}
/* Meta data line below post title */
.post-date {
display: block;
margin-top: -.5rem;
margin-bottom: 1rem;
color: #9a9a9a;
}
/* Related posts */
.related {
padding-top: 2rem;
padding-bottom: 2rem;
border-top: 1px solid #eee;
}
.related-posts {
padding-left: 0;
list-style: none;
}
.related-posts h3 {
margin-top: 0;
}
.related-posts li small {
font-size: 75%;
color: #999;
}
.related-posts li a:hover {
color: #268bd2;
text-decoration: none;
}
.related-posts li a:hover small {
color: inherit;
}
/*
* Pagination
*
* Super lightweight (HTML-wise) blog pagination. `span`s are provide for when
* there are no more previous or next posts to show.
*/
.pagination {
overflow: hidden; /* clearfix */
margin-left: -1rem;
margin-right: -1rem;
font-family: "Open Sans", Helvetica, Arial, sans-serif;
color: #ccc;
text-align: center;
}
/* Pagination items can be `span`s or `a`s */
.pagination-item {
display: block;
padding: 1rem;
border: 1px solid #eee;
}
.pagination-item:first-child {
margin-bottom: -1px;
}
/* Only provide a hover state for linked pagination items */
a.pagination-item:hover {
background-color: #f5f5f5;
}
@media (min-width: 30em) {
.pagination {
margin: 3rem 0;
}
.pagination-item {
float: left;
width: 50%;
}
.pagination-item:first-child {
margin-bottom: 0;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.pagination-item:last-child {
margin-left: -1px;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
}
}

Some files were not shown because too many files have changed in this diff Show More