Compare commits

...
Author SHA1 Message Date
Benjamin Doherty 791f51dcb4 Update glslang to e3bca2a 2022-05-04 12:29:21 -07:00
Benjamin Doherty 4621f3ec5d Filament specific changes 2022-05-04 12:06:26 -07:00
Benjamin Doherty ab9c09d0d9 Update spirv-tools to 46492aa 2022-05-04 12:00:04 -07:00
Benjamin Doherty dbf51c1c7d Update SPIRV-Cross to 0c8a79b 2022-05-04 11:07:15 -07:00
Mathias Agopian ebd5f150c1 fix a potential threading/memory corruption
We can't call prepareProgram() from any thread, since it is calling
into the backend. When we had more than a certain number of commands,
we would use the jobsystem to generate them and so prepareProgram()
could end up being called from a jobsystem thread.

This is fixed by looping through all the commands once they're generated
and calling prepareProgram() then.
2022-05-03 15:16:11 -07:00
Philip Rideout 156dcb54e8 gltf_viewer: fix accidental removal of camera selector. 2022-05-03 14:33:43 -07:00
Mathias Agopian 88ef76989c Cleanup Renderer.cpp
The main changes are:

- ColorPass() and RefractionPass() are now static and moved into a 
  new RendererUtils file. These methods don't need FRenderer and are 
  more like a big "script".

- Cleaned-up includes

- Reformatted/reordered methods
2022-05-03 14:27:48 -07:00
Philip Rideout fc284af684 Rename SimpleViewer to ViewerGui.
The SimpleViewer C++ class was not viewer component like `ModelViewer`
and `<filament-viewer>`. It was actually just the UI builder used
in the `gltf_viewer` desktop app and the remote Android interface.
2022-05-03 08:10:53 -07:00
Philip Rideout 3a8685cd15 Upgrade emsdk to 3.1.9 2022-05-03 08:10:26 -07:00
Philip Rideout f035655f5b Add support for KHR_texture_basisu.
This adds a new implementation of the TextureProvider interface called
Ktx2Provider.

Tested using the KTX2 variant of the StainedGlassLamp model in the
Khronos samples repo.

Tested on WebGL 2.0 (Chrome v100), Android (Pixel 6 Pro), and Desktop
(Metal, OpenGL, and Vulkan via MoltenVK).
2022-05-02 13:15:56 -07:00
Ben Doherty f498e08d1e Update hello-pbr to work in all orientations (#5488) 2022-05-02 14:41:32 -04:00
Philip Rideout db3186a65f Remove etc2comp and astcenc from the repo. 2022-05-02 11:29:19 -07:00
Philip Rideout 248815a3e0 Fix regression with <filament-viewer>. 2022-05-02 11:09:26 -07:00
Benjamin Doherty ebb62b5d55 Release Filament 1.21.3 2022-05-02 13:17:33 -04:00
Philip Rideout b9a5ad205a Fix unit test failures.
Basis does not support DXT3 so in the past this unit test passed only
due to the enum translation bug that was recently fixed.
2022-05-02 09:48:36 -07:00
Philip Rideout 100986d8d9 Fix WebGL debug build (assert with 3-channel images) 2022-04-29 16:30:14 -07:00
Philip Rideout b7c9a36d57 Ktx2Reader: Fix error in enum translation table.
This caused DXT5 content to be interpreted as DXT3 by the GPU,
which seemed to manifest as visual artifacts in the alpha channel.
2022-04-29 16:29:53 -07:00
Philip Rideout d76551ab28 Add async interface to Ktx2Reader. 2022-04-29 14:20:57 -07:00
Mathias Agopian 92bc0752d1 repair VSM gaussian blur
When there was more than one shadowmap we would hit an assert. This 
bug was introduced recently and was due to incorrect use of the 
framegraph.
2022-04-29 12:46:37 -07:00
Mathias Agopian 657c251463 Ensure we always have 4 "safe" mip levels
A "safe" mip-level is one that has exactly half the dimensions of
the current level. In other words, we guarantee that we can halve the
dimensions 4 times without loss (i.e. odd dimension).

This is achieved by effectively padding the viewport (i.e. making the
viewport's dimensions multiple of 16). The post-processing passes
eventually take care of cropping the extra padding so the final
image is unchanged.

This is a more generic solution to dynamic resolution padding, helps
with memory allocations and helps all the algorithms that depend on
mipmaping (e.g. DoF, SSAO, Bloom).


One important improvement brought by this change is that all "final"
post-processing effects are now able to handle a sub-region of the
source, including: color-gradding, fxaa and upscaling.
2022-04-29 12:05:08 -07:00
Philip Rideout b6b8fee483 WebGL: fix isTextureFormatSupported for ETC2 formats.
It was assumed that ETC2 is supported on all ES3 devices, but WebGL on
desktop machines does not support ETC2.

Note that WebGL has its own special extension strings for compressed
textures.
2022-04-29 12:04:59 -07:00
Mathias Agopian be5b60f895 cleaner handling of shadow related uniforms
Some uniforms are needed during shadow map generation, other
during shadow sampling (color pass). We didn't have a clear separation
between them and ended up setting the UBOs that were needed only for
sampling multiple times during generation.
2022-04-29 12:04:47 -07:00
Mathias Agopian 681d31758f move the ShadowUib out of View into ShadowMapManager 2022-04-29 12:04:47 -07:00
Ben Doherty 80dc2f5c9d Move toCompressedFilamentEnum to Ktx1Reader header (#5493) 2022-04-29 14:49:54 -04:00
Mathias Agopian ce7dd7a1fb reorganize again our main UBO
- try to sort data by usage.
- clarify what post-process materials have access to (not enforced yet)
2022-04-28 10:13:20 -07:00
Mathias Agopian 85617c96a2 shrink post-process materials a bit
post-process materials don't need common_shadowing nor common_shading.

also don't rely on MIN_ROUGHNESS in .mat files, because it's not public.
2022-04-28 10:13:20 -07:00
Mathias Agopian 58760adb6a fix typo introduced in previous PR. fixes froxels. 2022-04-27 17:28:16 -07:00
Mathias Agopian 4ef0b72773 rearrange the per-view UBO (breaks materials)
- rename common_math and common_shadowing from .fs to .glsl
  because they were both included in both vertex and fragment
  shaders

- add getFragCoord() which always returns coordinates in the
  glsl convention. This is useful when used with RNGs to get
  consistant results accross backends.
2022-04-27 15:27:47 -07:00
Mathias Agopian 45631c3b81 update binding points from 8 to 12. 2022-04-27 15:27:03 -07:00
Mathias Agopian 6f6dde2579 Optimize custom rendertargets use in Renderer
we just store the "sampleable" attachments as a bitmask in 
RenderTarget instead of computing it each time.
2022-04-27 15:26:45 -07:00
Mathias Agopian e0acbe42cf update material version 2022-04-27 10:14:38 -07:00
Mathias Agopian 4f137ccf89 don't rely on frameUniform.resolution for froxelization
this is because this uniform is not well defined -- it's unclear if
it is set to the viewport or the buffer size.

also, it's not needed, and removes a couple multiplies from the shader.
2022-04-27 09:38:33 -07:00
Mathias Agopian 04010e7dd9 when matdbg is used don't terminate the program on errors 2022-04-27 08:20:00 -07:00
Mathias Agopian f4f9f331c0 CameraInfo cleanups
- add getUserViewMatrix() on CameraInfo, the "user" view matrix is the 
view matrix before we apply the world origin transform, it is needed in
 a few places, so we make it a  method so that in the future we could 
precompute it if we wanted to.

- remove worldOffset which is just the last column of worldOrigin
2022-04-26 11:32:41 -07:00
Mathias Agopian dada291f6b rename mScaling to mScalingCS 2022-04-26 11:32:41 -07:00
Mathias Agopian 18f2f8b6d4 remove unused parameters and state 2022-04-26 11:32:41 -07:00
Mathias Agopian d4117ac968 use interleavedGradientNoise() instead of custom implementaion
interleavedGradientNoise() is available in common_math, so use that
instead of our custom gradient noise RNG.
2022-04-26 11:32:41 -07:00
Mathias Agopian eccbc8c242 simplify FXAA setup
We now do all the setup math on the CPU side, but we also remove some
unnecessary computations based on assumptions that are no longer true.
2022-04-26 11:32:41 -07:00
Mathias Agopian 3cdf24f515 remove getUV() from post-process materials
it made it actually more confusing to have two version of the uv
(normalized and not). Also the unnormalized version was computed from
frameUniforms which is not great in the case of post-processing
(it just happened to work).
2022-04-26 11:30:35 -07:00
Mathias Agopian d91faf9df8 avoid unnecessary parameter copies 2022-04-26 11:28:36 -07:00
Brian Stringham d950efa6ea Changed ALL_SHADER_STATE_FLAGS initializer to support c++17, which is required for C++/CLI support. (#5465) 2022-04-26 08:59:44 -07:00
Benjamin Doherty 861d69ea7c Release Filament 1.21.2 2022-04-25 16:57:00 -04:00
LaiJF b2cc904fab Fix typo 2022-04-25 09:06:12 -07:00
Mathias Agopian 3f87b520bb ShadowMap::render() doesn't need CameraInfo anymore 2022-04-22 12:35:00 -07:00
LaiJF 135a362176 Fix typo (#5455) 2022-04-22 10:46:04 -04:00
Philip Rideout 391ebc3702 gltfio: fix progress indicator when error occurs.
The progress bar in `gltf_viewer` should not appear to hang if any
of an asset's textures fail to load.
2022-04-21 17:41:32 -07:00
Philip Rideout b4d1443720 Repair iOS build. I think. 2022-04-21 15:36:37 -07:00
Philip Rideout c06737aca2 TextureProvider fixup in ResourceLoader JNI. 2022-04-21 13:44:44 -07:00
Philip Rideout f847232296 gltfio: introduce TextureProvider API.
This allows clients to provide their own asynchronous texture decoders
for various mime-typed images. This is a plug-in component for gltfio,
in some ways similar to MaterialProvider.

There are two motivations for this: to decouple gltfio from STB and
to make it easier to integrate support for BasisU textures.

This also has the side effect of simplifying ResourceLoader, since the
texture decoding jobs have been moved out.

As part of this work, I made the "stb" CMake target into a traditional
static library. Previously we had several files called `Image.cpp`
whose sole purpose was to enable STB_IMAGE_IMPLEMENTATION.
2022-04-21 13:25:40 -07:00
LaiJF 89f06b8923 Fix typo (#5454) 2022-04-21 09:52:04 -06:00
Philip Rideout 90a2b1f3c9 Remove WebGL workaround for bloom.
Bloom now works fine (tested with Chrome 100 on a x86 MacBook) without
this workaround for overly aggressive feedback loop detection.
2022-04-20 12:07:49 -07:00
Ben Doherty 059f51338d Audit backends and test cases for correct Y orientation. (#5440) 2022-04-20 11:01:31 -06:00
LaiJF d3cea5121e Fix typo 2022-04-20 09:58:46 -07:00
LaiJF c37301d2dc Fix typo. 2022-04-19 20:27:52 -07:00
Mathias Agopian aa16778fbd don't leak Engine if the driver fail to initialize
If there is an error during the driver initialization, Engine::create() 
returns nullptr, but the FEngine was allocated and would then never
be destroyed.

mTerminated was useless because by construction it would always have
the expected value.
2022-04-19 11:49:07 -07:00
Mathias Agopian ee499ad2ca don't use a unique_ptr to hold the DFG
we can simply make it a member of FEngine.
2022-04-19 11:49:07 -07:00
Mathias Agopian 958dd5bb27 a lot of our workaround don't apply when using ANGLE 2022-04-18 20:19:09 -07:00
Mathias Agopian f988b75999 fix the 2 passes version of FSR
This version is used only on qualcomm devices. It's now forbidden to
create a program inside a renderpass. Unfortunately there was still
one codepath doing so.
2022-04-18 20:18:45 -07:00
Philip Rideout e3ccb4bb3c gltfio Animator: add resetBoneMatrices().
See #5436.
2022-04-18 15:07:35 -07:00
Philip Rideout 3f0dc6f7e6 Minor Ktx2Reader refactoring. 2022-04-18 15:02:08 -07:00
Mathias Agopian c212dd5bc7 remove the CameraInfo state from FView
this state only exists during Renderer::render(), having it outside
of view is more flexible as it give us an opportunity to adjust
camera parameter globally before drawing.

Also greatly reduced the size of RenderPass (which is a Value object).
2022-04-18 12:04:18 -07:00
LaiJF 1eceab0040 Fix typo. 2022-04-18 10:46:31 -07:00
Philip Rideout ab9d1e5956 Fix unit test. 2022-04-15 12:22:12 -07:00
Philip Rideout c906290416 Add to release notes. 2022-04-15 10:54:27 -07:00
Philip Rideout d52a24b6e9 Incorporate feedback from code review. 2022-04-15 10:48:48 -07:00
Philip Rideout 9aeec3a759 Add Ktx2Reader and BasisEncoder and use them in samples.
mipgen can now emit basis-encoded KTX2 files. Both the desktop and
web "suzanne" samples use this as a test for compressed textures.

This PR does not add KTX2 support to glTF, but it's on the way.

`BasisEncoder` has a builder style API that calls the basis encoder to
create KTX2 files. This hides some low-level BasisU features that we are
not using, like file I/O and mipmap generation.

`Ktx2Reader` is an easy-to-use API for creating Filament textures from
KTX2 files. Its API primarily consists of these two methods:

    bool requestFormat(Texture::InternalFormat format);
    Filament::Texture* load(const uint8_t* data, size_t size);

The first method is used to build an ordered list of formats that are
supported by your hardware. The second method consumes the contents of a
basis-encoded KTX2 file and attempts to produce a Filament texture with
a preferred format.

IMPORTANT: Our tools still let you use KTX1 for non-compressed images
because it is useful for HDR, but you can no longer use KTX1 for
block-compressed data.

Partial fix for #4771.
2022-04-15 10:48:48 -07:00
Mathias Agopian 550fcfe2e3 fix typos 2022-04-15 09:18:06 -07:00
Mathias Agopian b2cdf9f2b4 don't issue a flush systematically after framegraph's execute
This is only a good place for a flush *if* we're going to draw another
view (so the GPU can start working). Otherwise, it can be costly
on some drivers and unnecessary since swapbuffers will do the same.
2022-04-15 09:12:39 -07:00
Mathias Agopian 19a3fe3dce allow radius parameter for upsample bloom stage
The original article we used for our bloom (siggraph'14) called for
a radius parameter for the upsample stage. We're always using 1.0 right
now, but it is useful to keep this possibility for experimentations.
2022-04-14 14:04:32 -07:00
Mathias Agopian 754abbf78e bloom pass cleanups 2022-04-14 14:04:32 -07:00
Mathias Agopian 9b855e9a03 fix bloom downsample
a bug was introduced in 8/2020 where the downsampling filter was wrong,
due to a mistake using textureLodOffset, which obviously uses offsets
in source texel -- we were assuming destination.
2022-04-14 14:04:32 -07:00
Mathias Agopian 2534fdf92d propagate the matdbg flag to graddle 2022-04-14 14:04:15 -07:00
Mathias Agopian dab02e915e Remove deprecated Stream APIs 2022-04-14 12:51:03 -07:00
Mathias Agopian 68da1a25eb disable ANGLE optimization that hurts filament 2022-04-14 08:52:56 -07:00
Romain Guy c67b363576 Fix compilation warnings 2022-04-13 15:15:16 -07:00
Philip Rideout 5c0e7d8211 sample-gltf-viewer: fix regression with zip files.
Path resolution was broken with #5285, which only worked when the glTF
happened to be at root level. This new fix has been tested against:

- My Sponza zip file that hass all files in a "sponza" folder.
- My Bistro zip file, which has resources in a child folder relative to
  the gltf file
- A self-created flat zip using IridescentDishWithOlives, with
  everything at root level.

Side note: Bistro still fails on a Pixel 6 Pro Mali but for an unrelated
reason: (null deref in backend::TimerQueryNative::queryResultAvailable)
2022-04-13 12:18:47 -07:00
Benjamin Doherty 3d57c60840 Release Filament 1.21.1 2022-04-13 10:14:44 -06:00
Mathias Agopian 8ab2725a79 string improvements
- don't use __PRETTY_FUNCTION__ and try to parse it, __func__ is
standardized and in most case returns what we want (the function name).

- add native support for string_view in our ostream.

- uninline string support from ostream
2022-04-13 08:53:33 -07:00
Mathias Agopian ff27f8109c Use DEBUG_MARKER() only on (and on all) driver APIs 2022-04-13 08:53:14 -07:00
Philip Rideout 8e09d8bd71 Fix sRGB correctness in Ktx1Reader.
When creating a KTX file (e.g. with mipgen), you can of course choose
whether or not you want to use an sRGB format.

At load time, your app has an expectation about whether a particular
texture has an sRGB format. e.g. the glTF convention is that albedo
textures should be sRGB, while roughness textures are linear.

Before this commit, our KTX loader would look at the app's expectation,
then silently re-interpret the bits in the glTF texture in order to
match this expectation. This seems very wrong.

Instead, if the expectated format does not match the format in the KTX
file, we now print a warning.

Fixes #2422, which will also be obsoleted by our upcoming KTX2 support.
2022-04-12 11:52:36 -07:00
LaiJF d6df4cd03a Fix typo. 2022-04-12 10:57:46 -07:00
Philip Rideout df03fdf3d7 mipgen: fixups / clarification regarding sRGB.
The `g_linearized` variable was being used for two purposes: to denote
the linearity of the source format AND the linearity of the destination
format. This was confusing and is now split is `sourceIsLinear` and
`destIsLinear`.

This change has no effect on the the look of the suzanne demo.
2022-04-11 14:28:34 -07:00
Mathias Agopian 6c59945395 fix typo preventing desktop GL builds to work 2022-04-11 09:51:38 -07:00
Philip Rideout d16cc50561 Shrink BasisU transcoder.
We do not support these formats and they add bloat to the basis tables.
In a release x86 build, this reduces the transcoder size from 774 KiB to
475 KiB.
2022-04-08 15:03:30 -07:00
LaiJF e667484a94 Fix typo. (#5413) 2022-04-08 14:23:46 -07:00
LaiJF 71e5e6c6c0 Fix typo. (#5407) 2022-04-08 14:22:29 -07:00
LaiJF c1df902593 Fix typo. (#5414) 2022-04-08 14:14:47 -07:00
Mathias Agopian 3c3320a2ba we need to be able to query the version before creating OpenGLDriver. 2022-04-07 20:30:11 -07:00
Mathias Agopian 35753bc6c2 CommandStream shouldn't be copyable.
This actually avoids a copy of Dispatcher (which is pretty large)
when constructing Engine.
2022-04-07 14:07:20 -07:00
Mathias Agopian 5f7967d09c Improve HandleAllocator
Allocation and destruction of handles generates a fair amount of code
because they are synchronized and the spinlock is inlined.

So we fix this by generating the 3 (de)allocation methods we really
need, we only need 3 because we're using 3 pools. These are now 
out-of-line, which reduces size and reduces pressure on the i-cache.
Performance is not affected much because in the end it's just a
static branch (and in most case the return is elided).
2022-04-07 14:07:20 -07:00
Mathias Agopian 404b6e8af3 Improve CommandStream Dispatcher
The main change here is that instead of allocating a Dispatcher on the
heap and storing a pointer to it in the CommandStream, we now have
a Dispatcher directly inside the CommandStream.

This avoids a heap allocation and a dereference when executing a command.
2022-04-07 14:07:20 -07:00
Mathias Agopian 898c20e584 OpenGLContext cleanups
the main change here is to make OpenGLContext friendly with ES2
2022-04-07 14:07:20 -07:00
Mathias Agopian f278b76b04 gl backend version management cleanup 2022-04-07 14:07:20 -07:00
Ben Doherty 6353f17635 Releases: specify Python dependencies in requirements.txt file (#5402) 2022-04-07 11:23:03 -07:00
daemyung jang 9cae34babf Add Java binding to get skins in FilamentAsset 2022-04-07 08:53:27 -07:00
Philip Rideout c37cc61b30 Update WebGL demos again. 2022-04-06 11:03:18 -07:00
Philip Rideout 9aced8e9b8 WebGL: fix intermittent 'detached ArrayBuffer' errors.
Partial fix for #5404.
2022-04-06 10:58:30 -07:00
Philip Rideout dde060bf4d Repair iOS build. 2022-04-06 10:56:37 -07:00
Philip Rideout b60518caa5 Add libs/ktxreader, rename some things to prep for KTX2.
Changes:

- Remove the strange header-only variant of libs/image
- Rename KtxBundle => Ktx1Bundle
- Move image/KtxUtility => ktxreader/Ktx1Reader
- Add unit test for Ktx1Reader and test stub for KTX2.

Notes:

- Ktx1Bundle does not depend on Filament and is used by cmgen
  and mipgen to generate KTX files.

- Ktx1Reader has a dependency on Filament and should therefore live in
  a separate library, which it now does.
2022-04-06 10:56:37 -07:00
Philip Rideout 69000ef1f2 Fix online demo.
The `demo_*` web samples were using unpkg to refer to the Filament build
rather than using the local copy, which was inconsistent with the other
web samples.

We now use the local copy of Filament for everything except the
drag-and-drop viewer, which always uses the latest version of Filament.
2022-04-06 09:14:25 -07:00
Philip Rideout 39d6106ef2 Add BasisU to third_party. 2022-04-06 09:02:18 -07:00
Ben Doherty 96a1cbe69f Attempt to fix GitHub release asset upload (#5398) 2022-04-05 13:01:20 -07:00
1664 changed files with 200444 additions and 86588 deletions
+4 -8
View File
@@ -50,8 +50,7 @@ jobs:
cd build/$WORKFLOW_OS && printf "y" | ./build.sh release
- name: Upload release assets
run: |
pip3 install setuptools
pip3 install PyGithub
xargs -L 1 sudo pip3 install < build/common/requirements.txt
if [ -f out/filament-release-darwin.tgz ]; then mv out/filament-release-darwin.tgz out/filament-${TAG}-mac.tgz; fi;
if [ -f out/filament-release-linux.tgz ]; then mv out/filament-release-linux.tgz out/filament-${TAG}-linux.tgz; fi;
python3 build/common/upload-assets.py ${TAG} out/*.tgz
@@ -80,8 +79,7 @@ jobs:
cd build/web && printf "y" | ./build.sh release
- name: Upload release assets
run: |
pip3 install setuptools
pip3 install PyGithub
xargs -L 1 sudo pip3 install < build/common/requirements.txt
mv out/filament-release-web.tgz out/filament-${TAG}-web.tgz
python3 build/common/upload-assets.py ${TAG} out/*.tgz
env:
@@ -123,8 +121,7 @@ jobs:
APK_KEYSTORE_PASS: ${{ secrets.APK_KEYSTORE_PASS }}
- name: Upload release assets
run: |
pip3 install setuptools
pip3 install PyGithub
xargs -L 1 sudo pip3 install < build/common/requirements.txt
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
@@ -157,8 +154,7 @@ jobs:
cd build/ios && printf "y" | ./build.sh release
- name: Upload release assets
run: |
pip3 install setuptools
pip3 install PyGithub
xargs -L 1 sudo pip3 install < build/common/requirements.txt
mv out/filament-release-ios.tgz out/filament-${TAG}-ios.tgz
python3 build/common/upload-assets.py ${TAG} out/*.tgz
env:
+1 -1
View File
@@ -349,7 +349,7 @@ same version that our continuous builds use.
```
cd <your chosen parent folder for the emscripten SDK>
curl -L https://github.com/emscripten-core/emsdk/archive/refs/tags/3.1.5.zip > emsdk.zip
curl -L https://github.com/emscripten-core/emsdk/archive/refs/tags/3.1.9.zip > emsdk.zip
unzip emsdk.zip ; mv emsdk-* emsdk ; cd emsdk
python ./emsdk.py install latest
python ./emsdk.py activate latest
+2 -2
View File
@@ -647,12 +647,14 @@ add_subdirectory(${LIBRARIES}/gltfio)
add_subdirectory(${LIBRARIES}/ibl)
add_subdirectory(${LIBRARIES}/iblprefilter)
add_subdirectory(${LIBRARIES}/image)
add_subdirectory(${LIBRARIES}/ktxreader)
add_subdirectory(${LIBRARIES}/math)
add_subdirectory(${LIBRARIES}/mathio)
add_subdirectory(${LIBRARIES}/utils)
add_subdirectory(${LIBRARIES}/viewer)
add_subdirectory(${FILAMENT}/filament)
add_subdirectory(${FILAMENT}/shaders)
add_subdirectory(${EXTERNAL}/basisu/tnt)
add_subdirectory(${EXTERNAL}/civetweb/tnt)
add_subdirectory(${EXTERNAL}/hat-trie/tnt)
add_subdirectory(${EXTERNAL}/imgui/tnt)
@@ -705,8 +707,6 @@ if (IS_HOST_PLATFORM)
add_subdirectory(${FILAMENT}/samples)
add_subdirectory(${EXTERNAL}/astcenc/tnt)
add_subdirectory(${EXTERNAL}/etc2comp)
add_subdirectory(${EXTERNAL}/libassimp/tnt)
add_subdirectory(${EXTERNAL}/libpng/tnt)
add_subdirectory(${EXTERNAL}/libsdl2/tnt)
+3 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.21.0'
implementation 'com.google.android.filament:filament-android:1.21.3'
}
```
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
iOS projects can use CocoaPods to install the latest release:
```
pod 'Filament', '~> 1.21.0'
pod 'Filament', '~> 1.21.3'
```
### Snapshots
@@ -177,6 +177,7 @@ steps:
- [x] KHR_materials_variants
- [x] KHR_materials_volume
- [x] KHR_mesh_quantization
- [x] KHR_texture_basisu
- [x] KHR_texture_transform
+32 -3
View File
@@ -3,11 +3,40 @@
This file contains one line summaries of commits that are worthy of mentioning in release notes.
A new header is inserted each time a *tag* is created.
## v1.21.2 (currently main branch)
## v1.22.1 (currently main branch)
## v1.22.0
- engine: Changed UBOs layout [⚠️ **Material breakage**].
- engine: Improve effects relying on mipmapping
## v1.21.3
- Java: Renamed the `KTXLoader` Kotlin class to `KTX1Loader`. [⚠️ **API Change**].
- libs: Added `Ktx2Reader` and `BasisEncoder` to support Basis-encoded KTX2 files.
- engine: Remove deprecated `Stream` APIs, see `Texture::import()` for an alternative [⚠️ **API Change**].
- tools: Removed KTX1 compression support from mipgen. [⚠️ **API Change**].
- tools: Added support for KTX2 to mipgen.
- gltfio: Added `resetBoneMatrices()` method.
- gltfio: Introduced `TextureProvider` interface. [⚠️ **API Change**].
- gltfio: Fix progress indicator when error occurs.
- samples: Desktop and Web Suzanne samples now use KTX2 instead of KTX1.
- samples: Fix regression with sample-gltf-viewer and zip files.
## v1.21.2
- Java: Add Java binding to get skins in `FilamentAsset`.
- libs: Add libs/ktxreader [⚠️ **API Change**].
- mipgen: fixups / clarification regarding sRGB.
- WebGL: fix intermittent 'detached ArrayBuffer' errors.
## v1.21.1
- engine: allow both screen-space refraction and screen-space reflections on the same object [⚠️ **Material breakage**].
- engine: Allow both screen-space refraction and screen-space reflections on the same object [⚠️ **Material breakage**].
- engine: Optimizations for screen-space reflections.
- engine: Remove `Viewport::scale()` [⚠️ **API Change**].
- engine: Fix 12x overallocation of memory in `MorphTargetBuffer`.
- Metal: Fix validation error when reading from default `SwapChain`.
## v1.21.0
@@ -442,7 +471,7 @@ devices.
- engine: Fix RenderTarget NPE when depth is not present.
- engine: Improvements to Camera APIs. Move focus distance from DofOptions to Camera.
- engine: VSM shadows now support `shadowMultiplier`.
- java: Expose severla MaterialInstance APIs (setColorWrite, setDepthWrite, setDepthCulling) that
- java: Expose several MaterialInstance APIs (setColorWrite, setDepthWrite, setDepthCulling) that
should have been public.
- java: fix bug with Texture::setImage buffer size calculation.
+11 -1
View File
@@ -11,6 +11,9 @@
// com.google.android.filament.exclude-vulkan
// When set, support for Vulkan will be excluded.
//
// com.google.android.filament.matdbg
// When set, enables matdbg, disables shader optimizations
//
// com.google.android.filament.skip-samples
// Exclude samples from the project. Useful to speed up compilation.
//
@@ -59,6 +62,11 @@ buildscript {
.forUseAtConfigurationTime()
.isPresent()
def matdbg = providers
.gradleProperty("com.google.android.filament.matdbg")
.forUseAtConfigurationTime()
.isPresent()
def abis = ["arm64-v8a", "armeabi-v7a", "x86_64", "x86"]
def newAbis = providers
.gradleProperty("com.google.android.filament.abis")
@@ -102,7 +110,9 @@ buildscript {
"-DANDROID_PLATFORM=21",
"-DANDROID_STL=c++_static",
"-DFILAMENT_DIST_DIR=${filamentPath}".toString(),
"-DFILAMENT_SUPPORTS_VULKAN=${excludeVulkan ? 'OFF' : 'ON'}".toString()
"-DFILAMENT_SUPPORTS_VULKAN=${excludeVulkan ? 'OFF' : 'ON'}".toString(),
"-DFILAMENT_ENABLE_MATDBG=${matdbg ? 'ON' : 'OFF'}".toString(),
"-DFILAMENT_DISABLE_MATOPT=${matdbg ? 'ON' : 'OFF'}".toString()
]
ext.cppFlags = [
@@ -133,7 +133,7 @@ public class MaterialBuilder {
FADE, // material is transparent and color is alpha-pre-multiplied,
// affects specular lighting
MULTIPLY, // material darkens what's behind it
SCREN // material brightens what's behind it
SCREEN // material brightens what's behind it
}
public enum VertexDomain {
@@ -98,16 +98,6 @@ Java_com_google_android_filament_Stream_nBuilderStreamSource(JNIEnv* env,
builder->setStreamSource(env, streamSource);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_Stream_nBuilderStream(JNIEnv*, jclass,
jlong nativeStreamBuilder, jlong externalTextureId) {
StreamBuilder* builder = (StreamBuilder*) nativeStreamBuilder;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
builder->builder()->stream(externalTextureId);
#pragma clang diagnostic pop
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_Stream_nBuilderWidth(JNIEnv*, jclass,
jlong nativeStreamBuilder, jint width) {
@@ -143,41 +133,6 @@ Java_com_google_android_filament_Stream_nSetDimensions(JNIEnv*, jclass, jlong na
stream->setDimensions((uint32_t) width, (uint32_t) height);
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_Stream_nReadPixels(JNIEnv *env, jclass,
jlong nativeStream, jlong nativeEngine,
jint xoffset, jint yoffset, jint width, jint height,
jobject storage, jint remaining,
jint left, jint top, jint type, jint alignment, jint stride, jint format,
jobject handler, jobject runnable) {
Stream *stream = (Stream *) nativeStream;
Engine *engine = (Engine *) nativeEngine;
stride = stride ? stride : width;
size_t sizeInBytes = PixelBufferDescriptor::computeDataSize(
(PixelDataFormat) format, (PixelDataType) type,
(size_t) stride, (size_t) (height + top), (size_t) alignment);
AutoBuffer nioBuffer(env, storage, 0);
if (sizeInBytes > (remaining << nioBuffer.getShift())) {
// BufferOverflowException
return -1;
}
void *buffer = nioBuffer.getData();
auto *callback = JniBufferCallback::make(engine, env, handler, runnable, std::move(nioBuffer));
PixelBufferDescriptor desc(buffer, sizeInBytes, (backend::PixelDataFormat) format,
(backend::PixelDataType) type, (uint8_t) alignment, (uint32_t) left, (uint32_t) top,
(uint32_t) stride,
callback->getHandler(), &JniBufferCallback::postToJavaAndDestroy, callback);
stream->readPixels(uint32_t(xoffset), uint32_t(yoffset), uint32_t(width), uint32_t(height),
std::move(desc));
return 0;
}
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_Stream_nGetTimestamp(JNIEnv*, jclass, jlong nativeStream) {
Stream *stream = (Stream *) nativeStream;
@@ -531,6 +531,10 @@ public class Renderer {
* Typically, this will happen after multiple calls to {@link #beginFrame},
* {@link #render}, {@link #endFrame}.</p>
* <br>
* <p>OpenGL only: if issuing a <code>readPixels</code> on a {@link RenderTarget} backed by a
* {@link Texture} that had data uploaded to it via {@link Texture#setImage}, the data returned
* from <code>readPixels</code> will be y-flipped with respect to the {@link Texture#setImage}
* call.</p>
* <p><code>readPixels</code> is intended for debugging and testing.
* It will impact performance significantly.</p>
*
@@ -103,9 +103,6 @@ public class Stream {
/** Not synchronized but copy-free. Good for video. */
NATIVE,
/** Synchronized, but GL-only and incurs copies. Good for AR on devices before API 26. */
TEXTURE_ID,
/** Synchronized, copy-free, and take a release callback. Good for AR but requires API 26+. */
ACQUIRED,
};
@@ -121,7 +118,7 @@ public class Stream {
* By default, Stream objects are {@link StreamType#ACQUIRED ACQUIRED} and must have external images pushed to them via
* {@link #setAcquiredImage}.
*
* To create a {@link StreamType#NATIVE NATIVE} or {@link StreamType#TEXTURE_ID TEXTURE_ID} stream, call one of the <pre>stream</pre> methods
* To create a {@link StreamType#NATIVE NATIVE} stream, call one of the <pre>stream</pre> methods
* on the builder.
*/
public static class Builder {
@@ -156,27 +153,6 @@ public class Stream {
throw new IllegalArgumentException("Invalid stream source: " + streamSource);
}
/**
* Creates a {@link StreamType#TEXTURE_ID TEXTURE_ID} stream. A copy stream will sample data from the supplied
* external texture and copy it into an internal private texture.
*
* <p>Currently only OpenGL external texture ids are supported.</p>
*
* @param externalTextureId An opaque texture id (typically a GLuint created with
* <code>glGenTextures()</code>) in a context shared with
* filament -- in that case this texture's target must be
* <code>GL_TEXTURE_EXTERNAL_OES.</code>
* @return This Builder, for chaining calls.
* @see Texture#setExternalStream
* @deprecated this method existed only for ARCore which doesn't need this anymore, use {@link Texture.Builder#importTexture(long)} instead.
*/
@Deprecated
@NonNull
public Builder stream(long externalTextureId) {
nBuilderStream(mNativeBuilder, externalTextureId);
return this;
}
/**
* @param width initial width of the incoming stream. Whether this value is used is
* stream dependent. On Android, it must be set when using
@@ -276,92 +252,6 @@ public class Stream {
nSetDimensions(getNativeObject(), width, height);
}
/**
* Reads back the content of the last frame of a <code>Stream</code> since the last call to
* {@link Renderer#beginFrame}.
*
* <p>The Stream must be a copy stream, which can be checked with {@link #getStreamType()}.
* This function is a no-op otherwise.</p>
*
* <pre>
*
* Stream buffer User buffer (PixelBufferDescriptor)
* +--------------------+
* | | .stride .alignment
* | | ----------------------->-->
* | | O----------------------+--+ low addresses
* | | | | | |
* | w | | | .top | |
* | <---------> | | V | |
* | +---------+ | | +---------+ | |
* | | ^ | | ======> | | | | |
* | x | h| | | |.left| | | |
* +------>| v | | +---->| | | |
* | +.........+ | | +.........+ | |
* | ^ | | | |
* | y | | +----------------------+--+ high addresses
* O------------+-------+
*
* </pre>
*
* <p>Typically readPixels() will be called after {@link Renderer#beginFrame}.</p>
*
* <p>After calling this method, the callback associated with <code>buffer</code>
* will be invoked on the main thread, indicating that the read-back has completed.
* Typically, this will happen after multiple calls to {@link Renderer#beginFrame},
* {@link Renderer#render}, {@link Renderer#endFrame}.</p>
*
* <p><code>readPixels</code> is intended for debugging and testing.
* It will impact performance significantly.</p>
*
* @param xoffset left offset of the sub-region to read back
* @param yoffset bottom offset of the sub-region to read back
* @param width width of the sub-region to read back
* @param height height of the sub-region to read back
* @param buffer client-side buffer where the read-back will be written
*
* <p>
* The following format are always supported:
* <li>{@link Texture.Format#RGBA}</li>
* <li>{@link Texture.Format#RGBA_INTEGER}</li>
* </p>
*
* <p>
* The following types are always supported:
* <li>{@link Texture.Type#UBYTE}</li>
* <li>{@link Texture.Type#UINT}</li>
* <li>{@link Texture.Type#INT}</li>
* <li>{@link Texture.Type#FLOAT}</li>
* </p>
*
* <p>Other combination of format/type may be supported. If a combination is
* not supported, this operation may fail silently. Use a DEBUG build
* to get some logs about the failure.</p>
*
* @exception BufferOverflowException if the specified parameters would result in reading
* outside of <code>buffer</code>.
*/
public void readPixels(
@IntRange(from = 0) int xoffset, @IntRange(from = 0) int yoffset,
@IntRange(from = 0) int width, @IntRange(from = 0) int height,
@NonNull Texture.PixelBufferDescriptor buffer) {
if (buffer.storage.isReadOnly()) {
throw new ReadOnlyBufferException();
}
int result = nReadPixels(getNativeObject(), mNativeEngine,
xoffset, yoffset, width, height,
buffer.storage, buffer.storage.remaining(),
buffer.left, buffer.top, buffer.type.ordinal(), buffer.alignment,
buffer.stride, buffer.format.ordinal(),
buffer.handler, buffer.callback);
if (result < 0) {
throw new BufferOverflowException();
}
}
/**
* Returns the presentation time of the currently displayed frame in nanosecond.
*
@@ -387,7 +277,6 @@ public class Stream {
private static native long nCreateBuilder();
private static native void nDestroyBuilder(long nativeStreamBuilder);
private static native void nBuilderStreamSource(long nativeStreamBuilder, Object streamSource);
private static native void nBuilderStream(long nativeStreamBuilder, long externalTextureId);
private static native void nBuilderWidth(long nativeStreamBuilder, int width);
private static native void nBuilderHeight(long nativeStreamBuilder, int height);
private static native long nBuilderBuild(long nativeStreamBuilder, long nativeEngine);
@@ -14,6 +14,10 @@ add_library(image STATIC IMPORTED)
set_target_properties(image PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libimage.a)
add_library(ktxreader STATIC IMPORTED)
set_target_properties(ktxreader PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libktxreader.a)
add_library(viewer STATIC IMPORTED)
set_target_properties(viewer PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libviewer.a)
@@ -64,5 +68,6 @@ target_link_libraries(filament-utils-jni
camutils
iblprefilter
image
ktxreader
viewer
)
@@ -20,13 +20,14 @@
#include <filament/IndirectLight.h>
#include <filament/Skybox.h>
#include <image/KtxUtility.h>
#include <ktxreader/Ktx1Reader.h>
#include "common/NioUtils.h"
using namespace filament;
using namespace filament::math;
using namespace image;
using namespace ktxreader;
jlong nCreateHDRTexture(JNIEnv* env, jclass,
jlong nativeEngine, jobject javaBuffer, jint remaining, jint internalFormat);
@@ -35,9 +36,9 @@ static jlong nCreateKTXTexture(JNIEnv* env, jclass,
jlong nativeEngine, jobject javaBuffer, jint remaining, jboolean srgb) {
Engine* engine = (Engine*) nativeEngine;
AutoBuffer buffer(env, javaBuffer, remaining);
KtxBundle* bundle = new KtxBundle((const uint8_t*) buffer.getData(), buffer.getSize());
return (jlong) ktx::createTexture(engine, *bundle, srgb, [](void* userdata) {
KtxBundle* bundle = (KtxBundle*) userdata;
Ktx1Bundle* bundle = new Ktx1Bundle((const uint8_t*) buffer.getData(), buffer.getSize());
return (jlong) Ktx1Reader::createTexture(engine, *bundle, srgb, [](void* userdata) {
Ktx1Bundle* bundle = (Ktx1Bundle*) userdata;
delete bundle;
}, bundle);
}
@@ -46,9 +47,9 @@ static jlong nCreateIndirectLight(JNIEnv* env, jclass,
jlong nativeEngine, jobject javaBuffer, jint remaining, jboolean srgb) {
Engine* engine = (Engine*) nativeEngine;
AutoBuffer buffer(env, javaBuffer, remaining);
KtxBundle* bundle = new KtxBundle((const uint8_t*) buffer.getData(), buffer.getSize());
Texture* cubemap = ktx::createTexture(engine, *bundle, srgb, [](void* userdata) {
KtxBundle* bundle = (KtxBundle*) userdata;
Ktx1Bundle* bundle = new Ktx1Bundle((const uint8_t*) buffer.getData(), buffer.getSize());
Texture* cubemap = Ktx1Reader::createTexture(engine, *bundle, srgb, [](void* userdata) {
Ktx1Bundle* bundle = (Ktx1Bundle*) userdata;
delete bundle;
}, bundle);
@@ -68,9 +69,9 @@ static jlong nCreateSkybox(JNIEnv* env, jclass,
jlong nativeEngine, jobject javaBuffer, jint remaining, jboolean srgb) {
Engine* engine = (Engine*) nativeEngine;
AutoBuffer buffer(env, javaBuffer, remaining);
KtxBundle* bundle = new KtxBundle((const uint8_t*) buffer.getData(), buffer.getSize());
Texture* cubemap = ktx::createTexture(engine, *bundle, srgb, [](void* userdata) {
KtxBundle* bundle = (KtxBundle*) userdata;
Ktx1Bundle* bundle = new Ktx1Bundle((const uint8_t*) buffer.getData(), buffer.getSize());
Texture* cubemap = Ktx1Reader::createTexture(engine, *bundle, srgb, [](void* userdata) {
Ktx1Bundle* bundle = (Ktx1Bundle*) userdata;
delete bundle;
}, bundle);
return (jlong) Skybox::Builder().environment(cubemap).showSun(true).build(*engine);
@@ -79,7 +80,7 @@ static jlong nCreateSkybox(JNIEnv* env, jclass,
static jboolean nGetSphericalHarmonics(JNIEnv* env, jclass, jobject javaBuffer, jint remaining,
jfloatArray outSphericalHarmonics_) {
AutoBuffer buffer(env, javaBuffer, remaining);
KtxBundle bundle((const uint8_t*) buffer.getData(), buffer.getSize());
Ktx1Bundle bundle((const uint8_t*) buffer.getData(), buffer.getSize());
jfloat* outSphericalHarmonics = env->GetFloatArrayElements(outSphericalHarmonics_, nullptr);
const auto success = bundle.getSphericalHarmonics(
@@ -98,8 +99,8 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
int rc;
// KTXLoader
jclass ktxloaderClass = env->FindClass("com/google/android/filament/utils/KTXLoader");
// KTX1Loader
jclass ktxloaderClass = env->FindClass("com/google/android/filament/utils/KTX1Loader");
if (ktxloaderClass == nullptr) return JNI_ERR;
static const JNINativeMethod ktxMethods[] = {
{(char*)"nCreateKTXTexture", (char*)"(JLjava/nio/Buffer;IZ)J", reinterpret_cast<void*>(nCreateKTXTexture)},
@@ -40,7 +40,7 @@ import com.google.android.filament.Renderer;
*
* When executing a test, clients should call tick() after each frame is rendered, which provides an
* opportunity to push settings to Filament, increment the current test index (if enough time has
* elapsed), and request an asychronous screenshot.
* elapsed), and request an asynchronous screenshot.
*
* The time to sleep between tests is configurable and can be set to zero. Automation also waits a
* specified minimum number of frames between tests.
@@ -24,12 +24,12 @@ import com.google.android.filament.Texture
import java.nio.Buffer
/**
* Utilities for consuming KTX files and producing Filament textures, IBLs, and sky boxes.
* Utilities for consuming KTX1 files and producing Filament textures, IBLs, and sky boxes.
*
* KTX is a simple container format that makes it easy to bundle miplevels and cubemap faces
* into a single file.
*/
object KTXLoader {
object KTX1Loader {
class Options {
var srgb = false
}
+18 -3
View File
@@ -11,6 +11,18 @@ add_library(dracodec STATIC IMPORTED)
set_target_properties(dracodec PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libdracodec.a)
add_library(ktxreader STATIC IMPORTED)
set_target_properties(ktxreader PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libktxreader.a)
add_library(stb STATIC IMPORTED)
set_target_properties(stb PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libstb.a)
add_library(basis_transcoder STATIC IMPORTED)
set_target_properties(basis_transcoder PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libbasis_transcoder.a)
add_library(utils STATIC IMPORTED)
set_target_properties(utils PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libutils.a)
@@ -32,6 +44,7 @@ set(GLTFIO_SRCS
${GLTFIO_DIR}/include/gltfio/ResourceLoader.h
${GLTFIO_DIR}/include/gltfio/FilamentAsset.h
${GLTFIO_DIR}/include/gltfio/FilamentInstance.h
${GLTFIO_DIR}/include/gltfio/TextureProvider.h
${GLTFIO_DIR}/include/gltfio/math.h
${GLTFIO_DIR}/src/Animator.cpp
@@ -45,15 +58,16 @@ set(GLTFIO_SRCS
${GLTFIO_DIR}/src/FFilamentInstance.h
${GLTFIO_DIR}/src/FilamentInstance.cpp
${GLTFIO_DIR}/src/GltfEnums.h
${GLTFIO_DIR}/src/Ktx2Provider.cpp
${GLTFIO_DIR}/src/MaterialProvider.cpp
${GLTFIO_DIR}/src/ResourceLoader.cpp
${GLTFIO_DIR}/src/StbProvider.cpp
${GLTFIO_DIR}/src/TangentsJob.h
${GLTFIO_DIR}/src/TangentsJob.cpp
${GLTFIO_DIR}/src/UbershaderLoader.cpp
${GLTFIO_DIR}/src/Wireframe.cpp
${GLTFIO_DIR}/src/Wireframe.h
${GLTFIO_DIR}/src/upcast.h
${GLTFIO_DIR}/src/Image.cpp
src/main/cpp/Animator.cpp
src/main/cpp/AssetLoader.cpp
@@ -81,6 +95,7 @@ set(GLTFIO_INCLUDE_DIRS
../../third_party/hat-trie
../../third_party/stb
../../libs/utils/include
../../libs/ktxreader/include
)
add_library(gltfio-jni SHARED ${GLTFIO_SRCS})
@@ -90,9 +105,9 @@ set_target_properties(gltfio-jni PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_
if(GLTFIO_LITE)
target_compile_definitions(gltfio-jni PUBLIC GLTFIO_LITE=1)
target_link_libraries(gltfio-jni filament-jni utils log gltfio_resources_lite)
target_link_libraries(gltfio-jni filament-jni utils log stb ktxreader basis_transcoder gltfio_resources_lite)
else()
target_link_libraries(gltfio-jni filament-jni utils log gltfio_resources)
target_link_libraries(gltfio-jni filament-jni utils log stb ktxreader basis_transcoder gltfio_resources)
# Enable Draco in the non-lite variant of gltfio.
target_link_libraries(gltfio-jni dracodec)
@@ -36,6 +36,12 @@ Java_com_google_android_filament_gltfio_Animator_nUpdateBoneMatrices(JNIEnv*, jc
animator->updateBoneMatrices();
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_gltfio_Animator_nResetBoneMatrices(JNIEnv*, jclass, jlong nativeAnimator) {
Animator* animator = (Animator*) nativeAnimator;
animator->resetBoneMatrices();
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_gltfio_Animator_nGetAnimationCount(JNIEnv*, jclass, jlong nativeAnimator) {
Animator* animator = (Animator*) nativeAnimator;
@@ -201,6 +201,44 @@ Java_com_google_android_filament_gltfio_FilamentAsset_nGetExtras(JNIEnv* env, jc
return val ? env->NewStringUTF(val) : nullptr;
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_gltfio_FilamentAsset_nGetSkinCount(JNIEnv* , jclass,
jlong nativeAsset) {
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
return (jint) asset->getSkinCount();
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_gltfio_FilamentAsset_nGetSkinNames(JNIEnv* env, jclass,
jlong nativeAsset, jobjectArray result) {
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
jsize available = env->GetArrayLength(result);
for (int i = 0; i < available; ++i) {
const char* name = asset->getSkinNameAt(i);
if (name) {
env->SetObjectArrayElement(result, (jsize) i, env->NewStringUTF(name));
}
}
}
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_gltfio_FilamentAsset_nGetJointCountAt(JNIEnv* , jclass,
jlong nativeAsset, jint skinIndex) {
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
return (jint) asset->getJointCountAt(skinIndex);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_gltfio_FilamentAsset_nGetJointsAt(JNIEnv* env, jclass,
jlong nativeAsset, jint skinIndex, jintArray result) {
FilamentAsset* asset = (FilamentAsset*) nativeAsset;
jsize available = env->GetArrayLength(result);
Entity* entities = (Entity*) env->GetIntArrayElements(result, nullptr);
std::copy_n(asset->getJointsAt(skinIndex),
std::min(available, (jsize) asset->getJointCountAt(skinIndex)), entities);
env->ReleaseIntArrayElements(result, (jint*) entities, 0);
}
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_gltfio_FilamentAsset_nGetAnimator(JNIEnv* , jclass,
jlong nativeAsset) {
@@ -19,6 +19,7 @@
#include <filament/Engine.h>
#include <gltfio/ResourceLoader.h>
#include <gltfio/TextureProvider.h>
#include <utils/Log.h>
@@ -114,3 +115,34 @@ Java_com_google_android_filament_gltfio_ResourceLoader_nAsyncCancelLoad(JNIEnv*,
ResourceLoader* loader = (ResourceLoader*) nativeLoader;
loader->asyncCancelLoad();
}
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_gltfio_ResourceLoader_nCreateStbProvider(JNIEnv*, jclass,
jlong nativeEngine) {
Engine* engine = (Engine*) nativeEngine;
return (jlong) createStbProvider(engine);
}
extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_gltfio_ResourceLoader_nCreateKtx2Provider(JNIEnv*, jclass,
jlong nativeEngine) {
Engine* engine = (Engine*) nativeEngine;
return (jlong) createKtx2Provider(engine);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_gltfio_ResourceLoader_nDestroyTextureProvider(JNIEnv*, jclass,
jlong nativeProvider) {
TextureProvider* provider = (TextureProvider*) nativeProvider;
delete provider;
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_gltfio_ResourceLoader_nAddTextureProvider(JNIEnv* env, jclass,
jlong nativeLoader, jstring url, jlong nativeProvider) {
ResourceLoader* loader = (ResourceLoader*) nativeLoader;
TextureProvider* provider = (TextureProvider*) nativeProvider;
const char* cstring = env->GetStringUTFChars(url, nullptr);
loader->addTextureProvider(cstring, provider);
env->ReleaseStringUTFChars(url, cstring);
}
@@ -66,6 +66,15 @@ public class Animator {
nUpdateBoneMatrices(getNativeObject());
}
/**
* Pass the identity matrix into all bone nodes, useful for returning to the T pose.
*
* <p>NOTE: this operation is independent of <code>animation</code>.</p>
*/
public void resetBoneMatrices() {
nResetBoneMatrices(getNativeObject());
}
/**
* Returns the number of <code>animation</code> definitions in the glTF asset.
*/
@@ -109,6 +118,7 @@ public class Animator {
private static native void nApplyAnimation(long nativeAnimator, int index, float time);
private static native void nUpdateBoneMatrices(long nativeAnimator);
private static native void nResetBoneMatrices(long nativeAnimator);
private static native int nGetAnimationCount(long nativeAnimator);
private static native float nGetAnimationDuration(long nativeAnimator, int index);
private static native String nGetAnimationName(long nativeAnimator, int index);
@@ -216,6 +216,38 @@ public class FilamentAsset {
return mAnimator;
}
/**
* Gets the skin count of this asset.
*/
public int getSkinCount() {
return nGetSkinCount(getNativeObject());
}
/**
* Gets the skin name at skin index in this asset.
*/
public @NonNull String[] getSkinNames() {
String[] result = new String[getSkinCount()];
nGetSkinNames(getNativeObject(), result);
return result;
}
/**
* Gets the joint count at skin index in this asset.
*/
public int getJointCountAt(int skinIndex) {
return nGetJointCountAt(getNativeObject(), skinIndex);
}
/**
* Gets joints at skin index in this asset.
*/
public @NonNull @Entity int[] getJointsAt(int skinIndex) {
int[] result = new int[getJointCountAt(skinIndex)];
nGetJointsAt(getNativeObject(), skinIndex, result);
return result;
}
/**
* Gets the names of all morph targets in the given entity.
*/
@@ -306,6 +338,10 @@ public class FilamentAsset {
private static native String nGetExtras(long nativeAsset, int entity);
private static native long nGetAnimator(long nativeAsset);
private static native void nApplyMaterialVariant(long nativeAsset, int variantIndex);
private static native int nGetSkinCount(long nativeAsset);
private static native void nGetSkinNames(long nativeAsset, String[] result);
private static native int nGetJointCountAt(long nativeAsset, int skinIndex);
private static native void nGetJointsAt(long nativeAsset, int skinIndex, int[] result);
private static native int nGetResourceUriCount(long nativeAsset);
private static native void nGetResourceUris(long nativeAsset, String[] result);
private static native void nReleaseSourceData(long nativeAsset);
@@ -35,6 +35,8 @@ import java.nio.Buffer;
*/
public class ResourceLoader {
private final long mNativeObject;
private final long mNativeStbProvider;
private final long mNativeKtx2Provider;
/**
* Constructs a resource loader tied to the given Filament engine.
@@ -46,6 +48,11 @@ public class ResourceLoader {
public ResourceLoader(@NonNull Engine engine) {
long nativeEngine = engine.getNativeObject();
mNativeObject = nCreateResourceLoader(nativeEngine, false, false, false);
mNativeStbProvider = nCreateStbProvider(nativeEngine);
mNativeKtx2Provider = nCreateKtx2Provider(nativeEngine);
nAddTextureProvider(mNativeObject, "image/jpeg", mNativeStbProvider);
nAddTextureProvider(mNativeObject, "image/png", mNativeStbProvider);
nAddTextureProvider(mNativeObject, "image/ktx2", mNativeKtx2Provider);
}
/**
@@ -63,6 +70,11 @@ public class ResourceLoader {
long nativeEngine = engine.getNativeObject();
mNativeObject = nCreateResourceLoader(nativeEngine, normalizeSkinningWeights,
recomputeBoundingBoxes, ignoreBindTransform);
mNativeStbProvider = nCreateStbProvider(nativeEngine);
mNativeKtx2Provider = nCreateKtx2Provider(nativeEngine);
nAddTextureProvider(mNativeObject, "image/jpeg", mNativeStbProvider);
nAddTextureProvider(mNativeObject, "image/png", mNativeStbProvider);
nAddTextureProvider(mNativeObject, "image/ktx2", mNativeKtx2Provider);
}
/**
@@ -70,6 +82,8 @@ public class ResourceLoader {
*/
public void destroy() {
nDestroyResourceLoader(mNativeObject);
nDestroyTextureProvider(mNativeStbProvider);
nDestroyTextureProvider(mNativeKtx2Provider);
}
/**
@@ -178,4 +192,9 @@ public class ResourceLoader {
private static native float nAsyncGetLoadProgress(long nativeLoader);
private static native void nAsyncUpdateLoad(long nativeLoader);
private static native void nAsyncCancelLoad(long nativeLoader);
private static native long nCreateStbProvider(long nativeEngine);
private static native long nCreateKtx2Provider(long nativeEngine);
private static native void nAddTextureProvider(long nativeLoader, String url, long nativeProvider);
private static native void nDestroyTextureProvider(long nativeProvider);
}
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.21.0
VERSION_NAME=1.21.3
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
@@ -150,12 +150,12 @@ class MainActivity : Activity() {
val scene = modelViewer.scene
val ibl = "default_env"
readCompressedAsset("envs/$ibl/${ibl}_ibl.ktx").let {
scene.indirectLight = KTXLoader.createIndirectLight(engine, it)
scene.indirectLight = KTX1Loader.createIndirectLight(engine, it)
scene.indirectLight!!.intensity = 30_000.0f
viewerContent.indirectLight = modelViewer.scene.indirectLight
}
readCompressedAsset("envs/$ibl/${ibl}_skybox.ktx").let {
scene.skybox = KTXLoader.createSkybox(engine, it)
scene.skybox = KTX1Loader.createSkybox(engine, it)
}
}
@@ -297,9 +297,10 @@ class MainActivity : Activity() {
val gltfBuffer = pathToBufferMapping[gltfPath]!!
// The gltf is often not at the root level (e.g. if a folder is zipped) so
// we need to extract its path in order to resolve the embedded uri strings.
var prefix = URI(gltfPath!!).resolve("..")
// In a zip file, the gltf file might be in the same folder as resources, or in a different
// folder. It is crucial to test against both of these cases. In any case, the resource
// paths are all specified relative to the location of the gltf file.
var prefix = URI(gltfPath!!).resolve(".")
withContext(Dispatchers.Main) {
if (gltfPath!!.endsWith(".glb")) {
@@ -308,7 +309,7 @@ class MainActivity : Activity() {
modelViewer.loadModelGltf(gltfBuffer) { uri ->
val path = prefix.resolve(uri).toString()
if (!pathToBufferMapping.contains(path)) {
Log.e(TAG, "Could not find '$uri' in zip using prefix '$prefix'")
Log.e(TAG, "Could not find '$uri' in zip using prefix '$prefix' and base path '${gltfPath!!}'")
setStatusText("Zip is missing $path")
}
pathToBufferMapping[path]
@@ -79,8 +79,6 @@ class MainActivity : Activity(), ActivityCompat.OnRequestPermissionsResultCallba
// Performs the rendering and schedules new frames
private val frameScheduler = FrameCallback()
private var externalTextureID: Int = 0
@RequiresApi(30)
class Api30Impl {
companion object {
@@ -103,8 +101,6 @@ class MainActivity : Activity(), ActivityCompat.OnRequestPermissionsResultCallba
setupView()
setupScene()
externalTextureID = createExternalTexture()
@Suppress("deprecation")
val display = if (Build.VERSION.SDK_INT >= 30) {
Api30Impl.getDisplay(this)
@@ -112,7 +108,7 @@ class MainActivity : Activity(), ActivityCompat.OnRequestPermissionsResultCallba
windowManager.defaultDisplay!!
}
streamHelper = StreamHelper(engine, materialInstance, display, externalTextureID)
streamHelper = StreamHelper(engine, materialInstance, display)
this.title = streamHelper.getTestName()
}
@@ -445,31 +441,4 @@ class MainActivity : Activity(), ActivityCompat.OnRequestPermissionsResultCallba
check(EGL14.eglMakeCurrent(display, surface, surface, context)) { "Error making GL context." }
return context
}
private fun createExternalTexture(): Int {
val textures = IntArray(1)
GLES30.glGenTextures(1, textures, 0)
val result = textures[0]
val textureTarget = GLES11Ext.GL_TEXTURE_EXTERNAL_OES
GLES30.glBindTexture(textureTarget, result)
GLES30.glTexParameteri(textureTarget, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE)
GLES30.glTexParameteri(textureTarget, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE)
GLES30.glTexParameteri(textureTarget, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST)
GLES30.glTexParameteri(textureTarget, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_NEAREST)
if (!GLES30.glIsTexture(result)) {
throw RuntimeException("OpenGL error: $result is an invalid texture.")
}
val error = GLES30.glGetError()
if (error != GLES30.GL_NO_ERROR) {
val errorString = GLU.gluErrorString(error)
throw RuntimeException("OpenGL error: $errorString!")
}
return result
}
}
@@ -37,7 +37,6 @@ class StreamHelper(
private val filamentEngine: Engine,
private val filamentMaterial: MaterialInstance,
private val display: Display,
private val externalTextureId: Int
) {
/**
* The StreamSource configures the source data for the texture.
@@ -51,7 +50,6 @@ class StreamHelper(
*/
enum class StreamSource {
CANVAS_STREAM_NATIVE, // copy-free but does not guarantee synchronization
CANVAS_STREAM_TEXID, // synchronized but incurs a copy
CANVAS_STREAM_ACQUIRED, // synchronized and copy-free
}
@@ -127,10 +125,6 @@ class StreamHelper(
surface.unlockCanvasAndPost(canvas)
if (streamSource == StreamSource.CANVAS_STREAM_TEXID) {
surfaceTexture!!.updateTexImage()
}
if (streamSource == StreamSource.CANVAS_STREAM_ACQUIRED) {
val image = imageReader!!.acquireLatestImage()
filamentStream!!.setAcquiredImage(
@@ -146,7 +140,7 @@ class StreamHelper(
fun nextTest() {
stopTest()
streamSource = StreamSource.values()[(streamSource.ordinal + 1) % 3]
streamSource = StreamSource.values()[(streamSource.ordinal + 1) % StreamSource.values().size]
startTest()
}
@@ -213,23 +207,6 @@ class StreamHelper(
filamentTexture.setExternalStream(filamentEngine, filamentStream!!)
}
if (streamSource == StreamSource.CANVAS_STREAM_TEXID) {
// Create the Android surface that will hold the canvas image.
surfaceTexture = SurfaceTexture(externalTextureId)
surfaceTexture!!.setDefaultBufferSize(resolution.width, resolution.height)
canvasSurface = Surface(surfaceTexture)
// Create the Filament Stream object that gets bound to the Texture.
filamentStream = Stream.Builder()
.stream(externalTextureId.toLong())
.width(resolution.width)
.height(resolution.height)
.build(filamentEngine)
filamentTexture.setExternalStream(filamentEngine, filamentStream!!)
}
if (streamSource == StreamSource.CANVAS_STREAM_ACQUIRED) {
filamentStream = Stream.Builder()
.width(resolution.width)
Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

+10 -6
View File
@@ -98,9 +98,9 @@ function print_matdbg_help {
echo ""
echo "FOR ANDROID BUILDS:"
echo ""
echo "1) The most reliable way to enable matdbg is to bypass Gradle and"
echo " directly modify the appropriate two lines in the following file:"
echo " ./android/filament-android/CMakeLists.txt"
echo "1) For Android Studio builds, make sure to set:"
echo " -Pcom.google.android.filament.matdbg"
echo " option in Preferences > Build > Compiler > Command line options."
echo ""
echo "2) The port number is hardcoded to 8081 so you will need to do:"
echo " adb forward tcp:8081 tcp:8081"
@@ -156,6 +156,7 @@ VULKAN_ANDROID_GRADLE_OPTION=""
SWIFTSHADER_OPTION="-DFILAMENT_USE_SWIFTSHADER=OFF"
MATDBG_OPTION="-DFILAMENT_ENABLE_MATDBG=OFF"
MATDBG_GRADLE_OPTION=""
IOS_BUILD_SIMULATOR=false
BUILD_UNIVERSAL_LIBRARIES=false
@@ -303,7 +304,7 @@ function build_webgl_with_target {
}
function build_webgl {
# For the host tools, supress install and always use Release.
# For the host tools, suppress install and always use Release.
local old_install_command=${INSTALL_COMMAND}; INSTALL_COMMAND=
local old_issue_debug_build=${ISSUE_DEBUG_BUILD}; ISSUE_DEBUG_BUILD=false
local old_issue_release_build=${ISSUE_RELEASE_BUILD}; ISSUE_RELEASE_BUILD=true
@@ -402,7 +403,7 @@ function ensure_android_build {
function build_android {
ensure_android_build
# Supress intermediate desktop tools install
# Suppress intermediate desktop tools install
local old_install_command=${INSTALL_COMMAND}
INSTALL_COMMAND=
@@ -456,6 +457,7 @@ function build_android {
-Pcom.google.android.filament.dist-dir=../out/android-debug/filament \
-Pcom.google.android.filament.abis=${ABI_GRADLE_OPTION} \
${VULKAN_ANDROID_GRADLE_OPTION} \
${MATDBG_GRADLE_OPTION} \
:filament-android:assembleDebug \
:gltfio-android:assembleDebug \
:filament-utils-android:assembleDebug
@@ -504,6 +506,7 @@ function build_android {
-Pcom.google.android.filament.dist-dir=../out/android-release/filament \
-Pcom.google.android.filament.abis=${ABI_GRADLE_OPTION} \
${VULKAN_ANDROID_GRADLE_OPTION} \
${MATDBG_GRADLE_OPTION} \
:filament-android:assembleRelease \
:gltfio-android:assembleRelease \
:filament-utils-android:assembleRelease
@@ -598,7 +601,7 @@ function archive_ios {
}
function build_ios {
# Supress intermediate desktop tools install
# Suppress intermediate desktop tools install
local old_install_command=${INSTALL_COMMAND}
INSTALL_COMMAND=
@@ -754,6 +757,7 @@ while getopts ":hacCfijmp:q:uvslwtdk:" opt; do
d)
PRINT_MATDBG_HELP=true
MATDBG_OPTION="-DFILAMENT_ENABLE_MATDBG=ON, -DFILAMENT_DISABLE_MATOPT=ON, -DFILAMENT_BUILD_FILAMAT=ON"
MATDBG_GRADLE_OPTION="-Pcom.google.android.filament.matdbg"
;;
f)
ISSUE_CMAKE_ALWAYS=true
+14
View File
@@ -0,0 +1,14 @@
setuptools==40.6.2
wheel==0.37.1
certifi==2021.10.8
cffi==1.15.0
charset-normalizer==2.0.12
Deprecated==1.2.13
idna==3.3
pycparser==2.21
PyGithub==1.55
PyJWT==2.3.0
PyNaCl==1.5.0
requests==2.27.1
urllib3==1.26.9
wrapt==1.14.0
+1
View File
@@ -11,3 +11,4 @@ tools/cmgen/test_cmgen compare
tools/glslminifier/test_glslminifier
libs/filameshio/test_filameshio
libs/camutils/test_camutils
libs/ktxreader/test_ktxreader
+19
View File
@@ -12,6 +12,25 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# requirements.txt created via:
#
# pip3 install virtualenv
# python3 -m venv env
# pip3 install PyGithub
# pip3 install wheel
# --all includes wheel and setuputils, which is needed for GitHub Actions
# pip3 freeze --all > requirements.txt
# Manually move 'setuptools' and 'wheel' lines to the beginning of the file.
# Manually remove the 'pip' line.
#
# Requirements are installed in GitHub Actions via:
# xargs -L 1 sudo pip3 install < build/common/requirements.txt
# xargs must be used because the ordering of the dependencies matters (namely, setuptools).
# sudo must be used to uninstall non-matching versions of packages.
# pip is removed to avoid conflicts with the pre-installed pip version on Actions.
# This technique does not work with Windows, unfortunately.
from github import Github
import os, sys
+1 -1
View File
@@ -17,7 +17,7 @@ export PATH="$PWD:$PATH"
# npm install -g typescript
# Install emscripten.
curl -L https://github.com/emscripten-core/emsdk/archive/refs/tags/3.1.5.zip > emsdk.zip
curl -L https://github.com/emscripten-core/emsdk/archive/refs/tags/3.1.9.zip > emsdk.zip
unzip emsdk.zip ; mv emsdk-* emsdk ; cd emsdk
./emsdk install latest
./emsdk activate latest
+1 -1
View File
@@ -2169,7 +2169,7 @@ type aliases:
Name | Type | Description
:-----------------------------------|:--------:|:------------------------------------
**getResolution()** | float4 | Resolution of the view in pixels: `width`, `height`, `1 / width`, `1 / height`
**getResolution()** | float4 | Dimensions of the view's effective viewport in pixels: `width`, `height`, `1 / width`, `1 / height`. This might be different from `View::getViewport()` for instance because of added rendering guard-bands. This can be used in conjunction with `getNormalizedViewportCoord()` to generate pixel coordinates.
**getWorldCameraPosition()** | float3 | Position of the camera/eye in world space
**getWorldOffset()** | float3 | The shift required to obtain API-level world space
**getTime()** | float | Current time as a remainder of 1 second. Yields a value between 0 and 1
+1 -1
View File
@@ -12,7 +12,7 @@
</head>
<body>
<canvas></canvas>
<script src="//unpkg.com/filament@1.15.0/filament.js"></script>
<script src="filament.js"></script>
<script src="//unpkg.com/gl-matrix@2.8.1"></script>
<script src="//unpkg.com/gltumble"></script>
<script src="tutorial_redball.js"></script>
+1 -1
View File
@@ -12,7 +12,7 @@
</head>
<body>
<canvas></canvas>
<script src="//unpkg.com/filament@1.15.0/filament.js"></script>
<script src="filament.js"></script>
<script src="//unpkg.com/gl-matrix@2.8.1"></script>
<script src="//unpkg.com/gltumble"></script>
<script src="tutorial_suzanne.js"></script>
+1 -1
View File
@@ -12,7 +12,7 @@
</head>
<body>
<canvas></canvas>
<script src="//unpkg.com/filament@1.15.0/filament.js"></script>
<script src="filament.js"></script>
<script src="//unpkg.com/gl-matrix@2.8.1"></script>
<script src="//unpkg.com/gltumble"></script>
<script src="tutorial_triangle.js"></script>
+10 -6
View File
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+20 -13
View File
@@ -64,7 +64,7 @@
<td align="left">Array of 16-bit or 32-bit unsigned integers consumed by the GPU.</td>
</tr>
<tr>
<td align="left"><a href="#KtxBundle">KtxBundle</a></td>
<td align="left"><a href="#Ktx1Bundle">Ktx1Bundle</a></td>
<td align="left">In-memory representation of a KTX file.</td>
</tr>
<tr>
@@ -583,6 +583,11 @@
<li><em>overrides</em> Dictionary with one or more of the following properties: enabled, sampleCount, customResolve.</li>
</ul>
</li>
<li><strong>engine.setScreenSpaceReflectionsOptions(overrides)</strong>
<ul>
<li><em>overrides</em> Dictionary with one or more of the following properties: thickness, bias, maxDistance, stride, enabled.</li>
</ul>
</li>
<li><strong>engine.setShadowOptions(instance, overrides)</strong>
<ul>
<li><em>instance</em> Instance of a light component obtained from <code>getInstance</code>.</li>
@@ -662,63 +667,63 @@ as quaternions.</li>
</ul>
</div>
<div class='classdoc'>
<h2>class <a id='KtxBundle' href='#KtxBundle'>KtxBundle</a></h2>
<h2>class <a id='Ktx1Bundle' href='#Ktx1Bundle'>Ktx1Bundle</a></h2>
<p>In-memory representation of a KTX file.</p>
<ul>
<li><strong>ktxBundle.getArrayLength()</strong>
<li><strong>ktx1Bundle.getArrayLength()</strong>
<ul>
<li>Obtains length of the texture array.</li>
<li><em>returns</em> The number of elements in the texture array</li>
</ul>
</li>
<li><strong>ktxBundle.getCompressedPixelDataType()</strong>
<li><strong>ktx1Bundle.getCompressedPixelDataType()</strong>
<ul>
<li><em>returns</em> <a href="#CompressedPixelDataType">CompressedPixelDataType</a></li>
</ul>
</li>
<li><strong>ktxBundle.getInternalFormat(srgb)</strong>
<li><strong>ktx1Bundle.getInternalFormat(srgb)</strong>
<ul>
<li><em>srgb</em> boolean that forces the resulting format to SRGB if possible.</li>
<li><em>returns</em> <a href="#Texture%24InternalFormat">Texture$InternalFormat</a></li>
</ul>
</li>
<li><strong>ktxBundle.getMetadata(key)</strong>
<li><strong>ktx1Bundle.getMetadata(key)</strong>
<ul>
<li>Obtains arbitrary metadata from the KTX file.</li>
<li><em>key</em> string</li>
<li><em>returns</em> string</li>
</ul>
</li>
<li><strong>ktxBundle.getPixelDataFormat()</strong>
<li><strong>ktx1Bundle.getPixelDataFormat()</strong>
<ul>
<li><em>returns</em> <a href="#PixelDataFormat">PixelDataFormat</a></li>
</ul>
</li>
<li><strong>ktxBundle.getPixelDataType()</strong>
<li><strong>ktx1Bundle.getPixelDataType()</strong>
<ul>
<li><em>returns</em> <a href="#PixelDataType">PixelDataType</a></li>
</ul>
</li>
<li><strong>ktxBundle.info()</strong>
<li><strong>ktx1Bundle.info()</strong>
<ul>
<li>Obtains properties of the KTX header.</li>
<li><em>returns</em> The <a href="#KtxInfo">KtxInfo</a> property accessor object.</li>
</ul>
</li>
<li><strong>ktxBundle.info()</strong>
<li><strong>ktx1Bundle.info()</strong>
<ul>
<li>Obtains properties of the KTX header.</li>
<li><em>returns</em> The <a href="#KtxInfo">KtxInfo</a> property accessor object.</li>
</ul>
</li>
<li><strong>ktxBundle.isCompressed()</strong>
<li><strong>ktx1Bundle.isCompressed()</strong>
<ul>
<li><em>returns</em> boolean</li>
</ul>
</li>
</ul>
<p>Most clients should use one of the <code>create*FromKtx</code> utility methods in the JavaScript <a href="#Engine">Engine</a>
wrapper rather than interacting with <code>KtxBundle</code> directly.</p>
wrapper rather than interacting with <code>Ktx1Bundle</code> directly.</p>
</div>
<div class='classdoc'>
<h2>class <a id='KtxInfo' href='#KtxInfo'>KtxInfo</a></h2>
@@ -743,7 +748,7 @@ wrapper rather than interacting with <code>KtxBundle</code> directly.</p>
</ul>
</li>
</ul>
<p>For example, <code>ktxbundle.info().pixelWidth</code>. See the
<p>For example, <code>Ktx1Bundle.info().pixelWidth</code>. See the
<a href="https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/">KTX spec</a> for the list of
properties.</p>
</div>
@@ -1267,7 +1272,9 @@ This defines the following functions:</p>
<ul>
<li>POINTS</li>
<li>LINES</li>
<li>LINE_STRIP</li>
<li>TRIANGLES</li>
<li>TRIANGLE_STRIP</li>
<li>NONE</li>
</ul>
</div>
Binary file not shown.
Binary file not shown.
+18 -16
View File
@@ -12,7 +12,9 @@ textures.</p>
<a href="tutorial_triangle.html">previous tutorial</a>. Change the last script tag from <code>triangle.js</code> to <code>redball.js</code>.</p>
<p>Next you'll need to get a couple command-line tools: <code>matc</code> and <code>cmgen</code>. You can find these in the
appropriate <a href="//github.com/google/filament/releases">Filament release</a>. You should choose the
archive that corresponds to your development machine rather than the one for web.</p>
archive that corresponds to your development machine rather than the one for web, and the version
that matches the <code>unpkg.com/filament@x.x.x</code> url in the script tag of <code>redball.html</code> (you may check
out the last available release of <a href="https://www.npmjs.com/package/filament">filament on npm</a>).</p>
<h2>Define plastic material</h2>
<p>The <code>matc</code> tool consumes a text file containing a high-level description of a PBR material, and
produces a binary material package that contains shader code and associated metadata. For more
@@ -60,12 +62,12 @@ IBL KTX contains these coefficients in its metadata.</p>
<h2>Create JavaScript</h2>
<p>Next, create <code>redball.js</code> with the following content.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span> environ <span style="color: #666666">=</span> <span style="color: #BA2121">&#39;pillars_2k&#39;</span>;
<span style="color: #008000; font-weight: bold">const</span> ibl_url <span style="color: #666666">=</span> <span style="color: #BA2121">`</span><span style="color: #BB6688; font-weight: bold">${</span>environ<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #BB6688; font-weight: bold">${</span>environ<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">_ibl.ktx`</span>;
<span style="color: #008000; font-weight: bold">const</span> sky_url <span style="color: #666666">=</span> <span style="color: #BA2121">`</span><span style="color: #BB6688; font-weight: bold">${</span>environ<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #BB6688; font-weight: bold">${</span>environ<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">_skybox.ktx`</span>;
<span style="color: #008000; font-weight: bold">const</span> ibl_url <span style="color: #666666">=</span> <span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_ibl.ktx`</span>;
<span style="color: #008000; font-weight: bold">const</span> sky_url <span style="color: #666666">=</span> <span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_skybox.ktx`</span>;
<span style="color: #008000; font-weight: bold">const</span> filamat_url <span style="color: #666666">=</span> <span style="color: #BA2121">&#39;plastic.filamat&#39;</span>
Filament.init([ filamat_url, ibl_url, sky_url ], () =&gt; {
<span style="color: #408080; font-style: italic">// Create some global aliases to enums for convenience.</span>
<span style="color: #3D7B7B; font-style: italic">// Create some global aliases to enums for convenience.</span>
<span style="color: #008000">window</span>.VertexAttribute <span style="color: #666666">=</span> Filament.VertexAttribute;
<span style="color: #008000">window</span>.AttributeType <span style="color: #666666">=</span> Filament.VertexBuffer$AttributeType;
<span style="color: #008000">window</span>.PrimitiveType <span style="color: #666666">=</span> Filament.RenderableManager$PrimitiveType;
@@ -73,7 +75,7 @@ Filament.init([ filamat_url, ibl_url, sky_url ], () =&gt; {
<span style="color: #008000">window</span>.Fov <span style="color: #666666">=</span> Filament.Camera$Fov;
<span style="color: #008000">window</span>.LightType <span style="color: #666666">=</span> Filament.LightManager$Type;
<span style="color: #408080; font-style: italic">// Obtain the canvas DOM object and pass it to the App.</span>
<span style="color: #3D7B7B; font-style: italic">// Obtain the canvas DOM object and pass it to the App.</span>
<span style="color: #008000; font-weight: bold">const</span> canvas <span style="color: #666666">=</span> <span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">&#39;canvas&#39;</span>)[<span style="color: #666666">0</span>];
<span style="color: #008000">window</span>.app <span style="color: #666666">=</span> <span style="color: #AA22FF; font-weight: bold">new</span> App(canvas);
} );
@@ -84,11 +86,11 @@ Filament.init([ filamat_url, ibl_url, sky_url ], () =&gt; {
<span style="color: #008000; font-weight: bold">const</span> engine <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine <span style="color: #666666">=</span> Filament.Engine.create(canvas);
<span style="color: #008000; font-weight: bold">const</span> scene <span style="color: #666666">=</span> engine.createScene();
<span style="color: #408080; font-style: italic">// TODO: create material</span>
<span style="color: #408080; font-style: italic">// TODO: create sphere</span>
<span style="color: #408080; font-style: italic">// TODO: create lights</span>
<span style="color: #408080; font-style: italic">// TODO: create IBL</span>
<span style="color: #408080; font-style: italic">// TODO: create skybox</span>
<span style="color: #3D7B7B; font-style: italic">// TODO: create material</span>
<span style="color: #3D7B7B; font-style: italic">// TODO: create sphere</span>
<span style="color: #3D7B7B; font-style: italic">// TODO: create lights</span>
<span style="color: #3D7B7B; font-style: italic">// TODO: create IBL</span>
<span style="color: #3D7B7B; font-style: italic">// TODO: create skybox</span>
<span style="color: #008000; font-weight: bold">this</span>.swapChain <span style="color: #666666">=</span> engine.createSwapChain();
<span style="color: #008000; font-weight: bold">this</span>.renderer <span style="color: #666666">=</span> engine.createRenderer();
@@ -209,9 +211,9 @@ following (don't type this out, there's an easier way).</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span> format <span style="color: #666666">=</span> Filament.PixelDataFormat.RGB;
<span style="color: #008000; font-weight: bold">const</span> datatype <span style="color: #666666">=</span> Filament.PixelDataType.UINT_10F_11F_11F_REV;
<span style="color: #408080; font-style: italic">// Create a Texture object for the mipmapped cubemap.</span>
<span style="color: #3D7B7B; font-style: italic">// Create a Texture object for the mipmapped cubemap.</span>
<span style="color: #008000; font-weight: bold">const</span> ibl_package <span style="color: #666666">=</span> Filament.Buffer(Filament.assets[ibl_url]);
<span style="color: #008000; font-weight: bold">const</span> iblktx <span style="color: #666666">=</span> <span style="color: #AA22FF; font-weight: bold">new</span> Filament.KtxBundle(ibl_package);
<span style="color: #008000; font-weight: bold">const</span> iblktx <span style="color: #666666">=</span> <span style="color: #AA22FF; font-weight: bold">new</span> Filament.Ktx1Bundle(ibl_package);
<span style="color: #008000; font-weight: bold">const</span> ibltex <span style="color: #666666">=</span> Filament.Texture.Builder()
.width(iblktx.info().pixelWidth)
@@ -227,11 +229,11 @@ following (don't type this out, there's an easier way).</p>
ibltex.setImageCube(engine, level, pixelbuffer);
}
<span style="color: #408080; font-style: italic">// Parse the spherical harmonics metadata.</span>
<span style="color: #3D7B7B; font-style: italic">// Parse the spherical harmonics metadata.</span>
<span style="color: #008000; font-weight: bold">const</span> shstring <span style="color: #666666">=</span> iblktx.getMetadata(<span style="color: #BA2121">&#39;sh&#39;</span>);
<span style="color: #008000; font-weight: bold">const</span> shfloats <span style="color: #666666">=</span> shstring.split(<span style="color: #BB6688">/\s/</span>, <span style="color: #666666">9</span> <span style="color: #666666">*</span> <span style="color: #666666">3</span>).map(<span style="color: #008000">parseFloat</span>);
<span style="color: #008000; font-weight: bold">const</span> shfloats <span style="color: #666666">=</span> shstring.split(<span style="color: #A45A77">/\s/</span>, <span style="color: #666666">9</span> <span style="color: #666666">*</span> <span style="color: #666666">3</span>).map(<span style="color: #008000">parseFloat</span>);
<span style="color: #408080; font-style: italic">// Build the IBL object and insert it into the scene.</span>
<span style="color: #3D7B7B; font-style: italic">// Build the IBL object and insert it into the scene.</span>
<span style="color: #008000; font-weight: bold">const</span> indirectLight <span style="color: #666666">=</span> Filament.IndirectLight.Builder()
.reflections(ibltex)
.irradianceSh(<span style="color: #666666">3</span>, shfloats)
@@ -253,7 +255,7 @@ scene.setIndirectLight(indirectLight);
Without a skybox, the reflections on the ball are not representative of its surroundings.
Here's one way to create a texture for the skybox:</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">const</span> sky_package <span style="color: #666666">=</span> Filament.Buffer(Filament.assets[sky_url]);
<span style="color: #008000; font-weight: bold">const</span> skyktx <span style="color: #666666">=</span> <span style="color: #AA22FF; font-weight: bold">new</span> Filament.KtxBundle(sky_package);
<span style="color: #008000; font-weight: bold">const</span> skyktx <span style="color: #666666">=</span> <span style="color: #AA22FF; font-weight: bold">new</span> Filament.Ktx1Bundle(sky_package);
<span style="color: #008000; font-weight: bold">const</span> skytex <span style="color: #666666">=</span> Filament.Texture.Builder()
.width(skyktx.info().pixelWidth)
.height(skyktx.info().pixelHeight)
+21 -21
View File
@@ -22,25 +22,25 @@ converting <a href="https://github.com/google/filament/blob/main/assets/models/m
<p>Next, let's create mipmapped KTX files using filament's <code>mipgen</code> tool. We'll create compressed and
non-compressed variants for each texture, since not all platforms support the same compression
formats. First copy over the PNG files from the <a href="https://github.com/google/filament/blob/main/assets/models/monkey">monkey folder</a>, then do:</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #408080; font-style: italic"># Create mipmaps for base color and two compressed variants.</span>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic"># Create mipmaps for base color and two compressed variants.</span>
mipgen albedo.png albedo.ktx
mipgen --compression<span style="color: #666666">=</span>astc_fast_ldr_4x4 albedo.png albedo_astc.ktx
mipgen --compression<span style="color: #666666">=</span>s3tc_rgb_dxt1 albedo.png albedo_s3tc_srgb.ktx
<span style="color: #408080; font-style: italic"># Create mipmaps for the normal map and a compressed variant.</span>
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the normal map and a compressed variant.</span>
mipgen --strip-alpha --kernel<span style="color: #666666">=</span>NORMALS --linear normal.png normal.ktx
mipgen --strip-alpha --kernel<span style="color: #666666">=</span>NORMALS --linear --compression<span style="color: #666666">=</span>etc_rgb8_normalxyz_40 <span style="color: #BB6622; font-weight: bold">\</span>
mipgen --strip-alpha --kernel<span style="color: #666666">=</span>NORMALS --linear --compression<span style="color: #666666">=</span>etc_rgb8_normalxyz_40 <span style="color: #AA5D1F; font-weight: bold">\</span>
normal.png normal_etc.ktx
<span style="color: #408080; font-style: italic"># Create mipmaps for the single-component roughness map and a compressed variant.</span>
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component roughness map and a compressed variant.</span>
mipgen --grayscale roughness.png roughness.ktx
mipgen --grayscale --compression<span style="color: #666666">=</span>etc_r11_numeric_40 roughness.png roughness_etc.ktx
<span style="color: #408080; font-style: italic"># Create mipmaps for the single-component metallic map and a compressed variant.</span>
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component metallic map and a compressed variant.</span>
mipgen --grayscale metallic.png metallic.ktx
mipgen --grayscale --compression<span style="color: #666666">=</span>etc_r11_numeric_40 metallic.png metallic_etc.ktx
<span style="color: #408080; font-style: italic"># Create mipmaps for the single-component occlusion map and a compressed variant.</span>
<span style="color: #3D7B7B; font-style: italic"># Create mipmaps for the single-component occlusion map and a compressed variant.</span>
mipgen --grayscale ao.png ao.ktx
mipgen --grayscale --compression<span style="color: #666666">=</span>etc_r11_numeric_40 ao.png ao_etc.ktx
</pre></div>
@@ -101,7 +101,7 @@ materials, consult the official document describing the <a href="https://google.
<p>Create a text file called <code>suzanne.html</code> and copy over the HTML that we used in the <a href="tutorial_redball.html">previous
tutorial</a>. Change the last script tag from <code>redball.js</code> to <code>suzanne.js</code>. Next, create <code>suzanne.js</code>
with the following content.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #408080; font-style: italic">// TODO: declare asset URLs</span>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic">// TODO: declare asset URLs</span>
Filament.init([ filamat_url, filamesh_url, sky_small_url, ibl_url ], () =&gt; {
<span style="color: #008000">window</span>.app <span style="color: #666666">=</span> <span style="color: #AA22FF; font-weight: bold">new</span> App(<span style="color: #008000">document</span>.getElementsByTagName(<span style="color: #BA2121">&#39;canvas&#39;</span>)[<span style="color: #666666">0</span>]);
@@ -119,9 +119,9 @@ Filament.init([ filamat_url, filamesh_url, sky_small_url, ibl_url ], () =&gt; {
<span style="color: #008000; font-weight: bold">const</span> filamesh <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine.loadFilamesh(filamesh_url, <span style="color: #008000; font-weight: bold">this</span>.matinstance);
<span style="color: #008000; font-weight: bold">this</span>.suzanne <span style="color: #666666">=</span> filamesh.renderable;
<span style="color: #408080; font-style: italic">// TODO: create sky box and IBL</span>
<span style="color: #408080; font-style: italic">// TODO: initialize gltumble</span>
<span style="color: #408080; font-style: italic">// TODO: fetch larger assets</span>
<span style="color: #3D7B7B; font-style: italic">// TODO: create sky box and IBL</span>
<span style="color: #3D7B7B; font-style: italic">// TODO: initialize gltumble</span>
<span style="color: #3D7B7B; font-style: italic">// TODO: fetch larger assets</span>
<span style="color: #008000; font-weight: bold">this</span>.swapChain <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine.createSwapChain();
<span style="color: #008000; font-weight: bold">this</span>.renderer <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine.createRenderer();
@@ -141,7 +141,7 @@ Filament.init([ filamat_url, filamesh_url, sky_small_url, ibl_url ], () =&gt; {
}
render() {
<span style="color: #408080; font-style: italic">// TODO: apply gltumble matrix</span>
<span style="color: #3D7B7B; font-style: italic">// TODO: apply gltumble matrix</span>
<span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain, <span style="color: #008000; font-weight: bold">this</span>.view);
<span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
}
@@ -176,14 +176,14 @@ last resort. Go ahead and replace the <strong>declare asset URLs</strong> commen
<span style="color: #008000; font-weight: bold">const</span> texture_suffix <span style="color: #666666">=</span> Filament.getSupportedFormatSuffix(<span style="color: #BA2121">&#39;etc&#39;</span>);
<span style="color: #008000; font-weight: bold">const</span> environ <span style="color: #666666">=</span> <span style="color: #BA2121">&#39;venetian_crossroads_2k&#39;</span>
<span style="color: #008000; font-weight: bold">const</span> ibl_url <span style="color: #666666">=</span> <span style="color: #BA2121">`</span><span style="color: #BB6688; font-weight: bold">${</span>environ<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #BB6688; font-weight: bold">${</span>environ<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">_ibl.ktx`</span>;
<span style="color: #008000; font-weight: bold">const</span> sky_small_url <span style="color: #666666">=</span> <span style="color: #BA2121">`</span><span style="color: #BB6688; font-weight: bold">${</span>environ<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #BB6688; font-weight: bold">${</span>environ<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">_skybox_tiny.ktx`</span>;
<span style="color: #008000; font-weight: bold">const</span> sky_large_url <span style="color: #666666">=</span> <span style="color: #BA2121">`</span><span style="color: #BB6688; font-weight: bold">${</span>environ<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #BB6688; font-weight: bold">${</span>environ<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">_skybox.ktx`</span>;
<span style="color: #008000; font-weight: bold">const</span> albedo_url <span style="color: #666666">=</span> <span style="color: #BA2121">`albedo</span><span style="color: #BB6688; font-weight: bold">${</span>albedo_suffix<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;
<span style="color: #008000; font-weight: bold">const</span> ao_url <span style="color: #666666">=</span> <span style="color: #BA2121">`ao</span><span style="color: #BB6688; font-weight: bold">${</span>texture_suffix<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;
<span style="color: #008000; font-weight: bold">const</span> metallic_url <span style="color: #666666">=</span> <span style="color: #BA2121">`metallic</span><span style="color: #BB6688; font-weight: bold">${</span>texture_suffix<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;
<span style="color: #008000; font-weight: bold">const</span> normal_url <span style="color: #666666">=</span> <span style="color: #BA2121">`normal</span><span style="color: #BB6688; font-weight: bold">${</span>texture_suffix<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;
<span style="color: #008000; font-weight: bold">const</span> roughness_url <span style="color: #666666">=</span> <span style="color: #BA2121">`roughness</span><span style="color: #BB6688; font-weight: bold">${</span>texture_suffix<span style="color: #BB6688; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;
<span style="color: #008000; font-weight: bold">const</span> ibl_url <span style="color: #666666">=</span> <span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_ibl.ktx`</span>;
<span style="color: #008000; font-weight: bold">const</span> sky_small_url <span style="color: #666666">=</span> <span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_skybox_tiny.ktx`</span>;
<span style="color: #008000; font-weight: bold">const</span> sky_large_url <span style="color: #666666">=</span> <span style="color: #BA2121">`</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">/</span><span style="color: #A45A77; font-weight: bold">${</span>environ<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">_skybox.ktx`</span>;
<span style="color: #008000; font-weight: bold">const</span> albedo_url <span style="color: #666666">=</span> <span style="color: #BA2121">`albedo</span><span style="color: #A45A77; font-weight: bold">${</span>albedo_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;
<span style="color: #008000; font-weight: bold">const</span> ao_url <span style="color: #666666">=</span> <span style="color: #BA2121">`ao</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;
<span style="color: #008000; font-weight: bold">const</span> metallic_url <span style="color: #666666">=</span> <span style="color: #BA2121">`metallic</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;
<span style="color: #008000; font-weight: bold">const</span> normal_url <span style="color: #666666">=</span> <span style="color: #BA2121">`normal</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;
<span style="color: #008000; font-weight: bold">const</span> roughness_url <span style="color: #666666">=</span> <span style="color: #BA2121">`roughness</span><span style="color: #A45A77; font-weight: bold">${</span>texture_suffix<span style="color: #A45A77; font-weight: bold">}</span><span style="color: #BA2121">.ktx`</span>;
<span style="color: #008000; font-weight: bold">const</span> filamat_url <span style="color: #666666">=</span> <span style="color: #BA2121">&#39;textured.filamat&#39;</span>;
<span style="color: #008000; font-weight: bold">const</span> filamesh_url <span style="color: #666666">=</span> <span style="color: #BA2121">&#39;suzanne.filamesh&#39;</span>;
</pre></div>
@@ -224,7 +224,7 @@ was created in the app constructor.</p>
<span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">&#39;normal&#39;</span>, normal, sampler);
<span style="color: #008000; font-weight: bold">this</span>.matinstance.setTextureParameter(<span style="color: #BA2121">&#39;ao&#39;</span>, ao, sampler);
<span style="color: #408080; font-style: italic">// Replace low-res skybox with high-res skybox.</span>
<span style="color: #3D7B7B; font-style: italic">// Replace low-res skybox with high-res skybox.</span>
<span style="color: #008000; font-weight: bold">this</span>.engine.destroySkybox(<span style="color: #008000; font-weight: bold">this</span>.skybox);
<span style="color: #008000; font-weight: bold">this</span>.skybox <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine.createSkyFromKtx(sky_large_url);
<span style="color: #008000; font-weight: bold">this</span>.scene.setSkybox(<span style="color: #008000; font-weight: bold">this</span>.skybox);
@@ -236,7 +236,7 @@ was created in the app constructor.</p>
<h2>Introduce trackball rotation</h2>
<p>Add the following script tag to your HTML file. This imports a small third-party library that
listens for drag events and computes a rotation matrix.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>&lt;<span style="color: #008000; font-weight: bold">script</span> <span style="color: #7D9029">src</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;//unpkg.com/gltumble&quot;</span>&gt;&lt;/<span style="color: #008000; font-weight: bold">script</span>&gt;
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>&lt;<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;//unpkg.com/gltumble&quot;</span>&gt;&lt;/<span style="color: #008000; font-weight: bold">script</span>&gt;
</pre></div>
<p>Next, replace the <strong>initialize gltumble</strong> and <strong>apply gltumble matrix</strong> comments with the following
+22 -22
View File
@@ -16,22 +16,22 @@ subsequent code blocks.</p>
<h2>Start your project</h2>
<p>First, create a text file called <code>triangle.html</code> and fill it with the following HTML. This creates
a mobile-friendly page with a full-screen canvas.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #BC7A00">&lt;!DOCTYPE html&gt;</span>
&lt;<span style="color: #008000; font-weight: bold">html</span> <span style="color: #7D9029">lang</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;en&quot;</span>&gt;
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #9C6500">&lt;!DOCTYPE html&gt;</span>
&lt;<span style="color: #008000; font-weight: bold">html</span> <span style="color: #687822">lang</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;en&quot;</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">head</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">title</span>&gt;Filament Tutorial&lt;/<span style="color: #008000; font-weight: bold">title</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">meta</span> <span style="color: #7D9029">charset</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;utf-8&quot;</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">meta</span> <span style="color: #7D9029">name</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;viewport&quot;</span> <span style="color: #7D9029">content</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;width=device-width,user-scalable=no,initial-scale=1&quot;</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">style</span>&gt;
<span style="color: #008000; font-weight: bold">body</span> { <span style="color: #008000; font-weight: bold">margin</span>: <span style="color: #666666">0</span>; <span style="color: #008000; font-weight: bold">overflow</span>: <span style="color: #008000; font-weight: bold">hidden</span>; }
<span style="color: #008000; font-weight: bold">canvas</span> { touch-action: <span style="color: #008000; font-weight: bold">none</span>; <span style="color: #008000; font-weight: bold">width</span>: <span style="color: #666666">100</span><span style="color: #B00040">%</span>; <span style="color: #008000; font-weight: bold">height</span>: <span style="color: #666666">100</span><span style="color: #B00040">%</span>; }
&lt;/<span style="color: #008000; font-weight: bold">style</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">meta</span> <span style="color: #687822">charset</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;utf-8&quot;</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">meta</span> <span style="color: #687822">name</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;viewport&quot;</span> <span style="color: #687822">content</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;width=device-width,user-scalable=no,initial-scale=1&quot;</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">style</span>&gt;<span style="color: #bbbbbb"></span>
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">body</span><span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">margin</span>:<span style="color: #bbbbbb"> </span><span style="color: #666666">0</span>;<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">overflow</span>:<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">hidden</span>;<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">canvas</span><span style="color: #bbbbbb"> </span>{<span style="color: #bbbbbb"> </span>touch-action:<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">none</span>;<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">width</span>:<span style="color: #bbbbbb"> </span><span style="color: #666666">100</span><span style="color: #B00040">%</span>;<span style="color: #bbbbbb"> </span><span style="color: #008000; font-weight: bold">height</span>:<span style="color: #bbbbbb"> </span><span style="color: #666666">100</span><span style="color: #B00040">%</span>;<span style="color: #bbbbbb"> </span>}<span style="color: #bbbbbb"></span>
<span style="color: #bbbbbb"> </span>&lt;/<span style="color: #008000; font-weight: bold">style</span>&gt;
&lt;/<span style="color: #008000; font-weight: bold">head</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">body</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">canvas</span>&gt;&lt;/<span style="color: #008000; font-weight: bold">canvas</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">script</span> <span style="color: #7D9029">src</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;//unpkg.com/filament@1.15.0/filament.js&quot;</span>&gt;&lt;/<span style="color: #008000; font-weight: bold">script</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">script</span> <span style="color: #7D9029">src</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;//unpkg.com/gl-matrix@2.8.1&quot;</span>&gt;&lt;/<span style="color: #008000; font-weight: bold">script</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">script</span> <span style="color: #7D9029">src</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;triangle.js&quot;</span>&gt;&lt;/<span style="color: #008000; font-weight: bold">script</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;filament.js&quot;</span>&gt;&lt;/<span style="color: #008000; font-weight: bold">script</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;//unpkg.com/gl-matrix@2.8.1&quot;</span>&gt;&lt;/<span style="color: #008000; font-weight: bold">script</span>&gt;
&lt;<span style="color: #008000; font-weight: bold">script</span> <span style="color: #687822">src</span><span style="color: #666666">=</span><span style="color: #BA2121">&quot;triangle.js&quot;</span>&gt;&lt;/<span style="color: #008000; font-weight: bold">script</span>&gt;
&lt;/<span style="color: #008000; font-weight: bold">body</span>&gt;
&lt;/<span style="color: #008000; font-weight: bold">html</span>&gt;
</pre></div>
@@ -50,18 +50,18 @@ a mobile-friendly page with a full-screen canvas.</p>
<p>Go ahead and create <code>triangle.js</code> with the following content.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #008000; font-weight: bold">class</span> App {
<span style="color: #008000; font-weight: bold">constructor</span>() {
<span style="color: #408080; font-style: italic">// TODO: create entities</span>
<span style="color: #3D7B7B; font-style: italic">// TODO: create entities</span>
<span style="color: #008000; font-weight: bold">this</span>.render <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.render.bind(<span style="color: #008000; font-weight: bold">this</span>);
<span style="color: #008000; font-weight: bold">this</span>.resize <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.resize.bind(<span style="color: #008000; font-weight: bold">this</span>);
<span style="color: #008000">window</span>.addEventListener(<span style="color: #BA2121">&#39;resize&#39;</span>, <span style="color: #008000; font-weight: bold">this</span>.resize);
<span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
}
render() {
<span style="color: #408080; font-style: italic">// TODO: render scene</span>
<span style="color: #3D7B7B; font-style: italic">// TODO: render scene</span>
<span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
}
resize() {
<span style="color: #408080; font-style: italic">// TODO: adjust viewport and canvas</span>
<span style="color: #3D7B7B; font-style: italic">// TODO: adjust viewport and canvas</span>
}
}
@@ -81,9 +81,9 @@ that define a PBR material. We'll learn more about material packages in the next
<h2>Spawn a local server</h2>
<p>Because of CORS restrictions, your web app cannot fetch the material package directly from the
file system. One way around this is to create a temporary server using Python or node:</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>python3 -m http.server <span style="color: #408080; font-style: italic"># Python 3</span>
python -m SimpleHTTPServer <span style="color: #408080; font-style: italic"># Python 2.7</span>
npx http-server -p <span style="color: #666666">8000</span> <span style="color: #408080; font-style: italic"># nodejs</span>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>python3 -m http.server <span style="color: #3D7B7B; font-style: italic"># Python 3</span>
python -m SimpleHTTPServer <span style="color: #3D7B7B; font-style: italic"># Python 2.7</span>
npx http-server -p <span style="color: #666666">8000</span> <span style="color: #3D7B7B; font-style: italic"># nodejs</span>
</pre></div>
<p>To see if this works, navigate to <a href="http://localhost:8000">http://localhost:8000</a> and check if you
@@ -185,10 +185,10 @@ view.</p>
<span style="color: #008000; font-weight: bold">this</span>.view.setCamera(<span style="color: #008000; font-weight: bold">this</span>.camera);
<span style="color: #008000; font-weight: bold">this</span>.view.setScene(<span style="color: #008000; font-weight: bold">this</span>.scene);
<span style="color: #408080; font-style: italic">// Set up a blue-green background:</span>
<span style="color: #3D7B7B; font-style: italic">// Set up a blue-green background:</span>
<span style="color: #008000; font-weight: bold">this</span>.renderer.setClearOptions({clearColor<span style="color: #666666">:</span> [<span style="color: #666666">0.0</span>, <span style="color: #666666">0.1</span>, <span style="color: #666666">0.2</span>, <span style="color: #666666">1.0</span>], clear<span style="color: #666666">:</span> <span style="color: #008000; font-weight: bold">true</span>});
<span style="color: #408080; font-style: italic">// Adjust the initial viewport:</span>
<span style="color: #3D7B7B; font-style: italic">// Adjust the initial viewport:</span>
<span style="color: #008000; font-weight: bold">this</span>.resize();
</pre></div>
@@ -198,14 +198,14 @@ However the canvas is still blank!</p>
<p>Recall that our App class has a skeletal render method, which the browser calls every time it needs
to repaint. Often this is 60 times a second.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span>render() {
<span style="color: #408080; font-style: italic">// TODO: render scene</span>
<span style="color: #3D7B7B; font-style: italic">// TODO: render scene</span>
<span style="color: #008000">window</span>.requestAnimationFrame(<span style="color: #008000; font-weight: bold">this</span>.render);
}
</pre></div>
<p>Let's flesh this out by rotating the triangle and invoking the Filament renderer. Add the following
code to the top of the render method.</p>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #408080; font-style: italic">// Rotate the triangle.</span>
<div class="highlight" style="background: #f8f8f8"><pre style="line-height: 125%;"><span></span><span style="color: #3D7B7B; font-style: italic">// Rotate the triangle.</span>
<span style="color: #008000; font-weight: bold">const</span> radians <span style="color: #666666">=</span> <span style="color: #008000">Date</span>.now() <span style="color: #666666">/</span> <span style="color: #666666">1000</span>;
<span style="color: #008000; font-weight: bold">const</span> transform <span style="color: #666666">=</span> mat4.fromRotation(mat4.create(), radians, [<span style="color: #666666">0</span>, <span style="color: #666666">0</span>, <span style="color: #666666">1</span>]);
<span style="color: #008000; font-weight: bold">const</span> tcm <span style="color: #666666">=</span> <span style="color: #008000; font-weight: bold">this</span>.engine.getTransformManager();
@@ -213,7 +213,7 @@ code to the top of the render method.</p>
tcm.setTransform(inst, transform);
inst.<span style="color: #AA22FF; font-weight: bold">delete</span>();
<span style="color: #408080; font-style: italic">// Render the frame.</span>
<span style="color: #3D7B7B; font-style: italic">// Render the frame.</span>
<span style="color: #008000; font-weight: bold">this</span>.renderer.render(<span style="color: #008000; font-weight: bold">this</span>.swapChain, <span style="color: #008000; font-weight: bold">this</span>.view);
</pre></div>
+2
View File
@@ -77,6 +77,7 @@ set(SRCS
src/RenderTarget.cpp
src/RenderableManager.cpp
src/Renderer.cpp
src/RendererUtils.cpp
src/ResourceAllocator.cpp
src/ResourceList.cpp
src/Scene.cpp
@@ -143,6 +144,7 @@ set(PRIVATE_HDRS
src/PerViewUniforms.h
src/PIDController.h
src/PostProcessManager.h
src/RendererUtils.h
src/RenderPass.h
src/RenderPrimitive.h
src/ResourceAllocator.h
+1 -3
View File
@@ -42,6 +42,7 @@ set(PRIVATE_HDRS
include/private/backend/CircularBuffer.h
include/private/backend/CommandBufferQueue.h
include/private/backend/CommandStream.h
include/private/backend/Dispatcher.h
include/private/backend/Driver.h
include/private/backend/DriverApi.h
include/private/backend/DriverAPI.inc
@@ -64,8 +65,6 @@ if (FILAMENT_SUPPORTS_OPENGL AND NOT FILAMENT_USE_EXTERNAL_GLES3 AND NOT FILAMEN
src/opengl/gl_headers.h
src/opengl/GLUtils.cpp
src/opengl/GLUtils.h
src/opengl/OpenGLBlitter.cpp
src/opengl/OpenGLBlitter.h
src/opengl/OpenGLContext.cpp
src/opengl/OpenGLContext.h
src/opengl/OpenGLDriver.cpp
@@ -88,7 +87,6 @@ if (FILAMENT_SUPPORTS_OPENGL AND NOT FILAMENT_USE_EXTERNAL_GLES3 AND NOT FILAMEN
endif ()
if (ANDROID)
list(APPEND SRCS src/opengl/platforms/ExternalStreamManagerAndroid.cpp)
list(APPEND SRCS src/android/ExternalTextureManagerAndroid.cpp)
list(APPEND SRCS src/opengl/platforms/PlatformEGLAndroid.cpp)
elseif (IOS)
list(APPEND SRCS src/opengl/platforms/PlatformCocoaTouchGL.mm)
+14 -17
View File
@@ -33,7 +33,6 @@
#include <stddef.h>
#include <stdint.h>
namespace filament {
/**
* Types and enums used by filament's driver.
*
@@ -41,24 +40,24 @@ namespace filament {
* internal redeclaration of these types.
* For e.g. Use Texture::Sampler instead of filament::SamplerType.
*/
namespace backend {
namespace filament::backend {
static constexpr uint64_t SWAP_CHAIN_CONFIG_TRANSPARENT = 0x1;
static constexpr uint64_t SWAP_CHAIN_CONFIG_READABLE = 0x2;
static constexpr uint64_t SWAP_CHAIN_CONFIG_ENABLE_XCB = 0x4;
static constexpr uint64_t SWAP_CHAIN_CONFIG_TRANSPARENT = 0x1;
static constexpr uint64_t SWAP_CHAIN_CONFIG_READABLE = 0x2;
static constexpr uint64_t SWAP_CHAIN_CONFIG_ENABLE_XCB = 0x4;
static constexpr uint64_t SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER = 0x8;
static constexpr size_t MAX_VERTEX_ATTRIBUTE_COUNT = 16; // This is guaranteed by OpenGL ES.
static constexpr size_t MAX_VERTEX_SAMPLER_COUNT = 16; // This is guaranteed by OpenGL ES.
static constexpr size_t MAX_FRAGMENT_SAMPLER_COUNT = 16; // This is guaranteed by OpenGL ES.
static constexpr size_t MAX_SAMPLER_COUNT = 32; // This is guaranteed by OpenGL ES.
static constexpr size_t MAX_VERTEX_BUFFER_COUNT = 16; // Max number of bound buffer objects.
static constexpr size_t MAX_VERTEX_ATTRIBUTE_COUNT = 16; // This is guaranteed by OpenGL ES.
static constexpr size_t MAX_VERTEX_SAMPLER_COUNT = 16; // This is guaranteed by OpenGL ES.
static constexpr size_t MAX_FRAGMENT_SAMPLER_COUNT = 16; // This is guaranteed by OpenGL ES.
static constexpr size_t MAX_SAMPLER_COUNT = 32; // This is guaranteed by OpenGL ES.
static constexpr size_t MAX_VERTEX_BUFFER_COUNT = 16; // Max number of bound buffer objects.
static_assert(MAX_VERTEX_BUFFER_COUNT <= MAX_VERTEX_ATTRIBUTE_COUNT,
"The number of buffer objects that can be attached to a VertexBuffer must be "
"less than or equal to the maximum number of vertex attributes.");
static constexpr size_t CONFIG_BINDING_COUNT = 8;
static constexpr size_t CONFIG_BINDING_COUNT = 12; // This is guaranteed by OpenGL ES.
/**
* Selects which driver a particular Engine should use.
@@ -160,7 +159,7 @@ struct DepthRange {
* @see Fence, Fence::wait()
*/
enum class FenceStatus : int8_t {
ERROR = -1, //!< An error occured. The Fence condition is not satisfied.
ERROR = -1, //!< An error occurred. The Fence condition is not satisfied.
CONDITION_SATISFIED = 0, //!< The Fence condition is satisfied.
TIMEOUT_EXPIRED = 1, //!< wait()'s timeout expired. The Fence condition is not satisfied.
};
@@ -169,7 +168,7 @@ enum class FenceStatus : int8_t {
* Status codes for sync objects
*/
enum class SyncStatus : int8_t {
ERROR = -1, //!< An error occured. The Sync is not signaled.
ERROR = -1, //!< An error occurred. The Sync is not signaled.
SIGNALED = 0, //!< The Sync is signaled.
NOT_SIGNALED = 1, //!< The Sync is not signaled yet
};
@@ -789,7 +788,6 @@ enum class BlendFunction : uint8_t {
//! Stream for external textures
enum class StreamType {
NATIVE, //!< Not synchronized but copy-free. Good for video.
TEXTURE_ID, //!< Synchronized, but GL-only and incurs copies. Good for AR on devices before API 26.
ACQUIRED, //!< Synchronized, copy-free, and take a release callback. Good for AR but requires API 26+.
};
@@ -914,7 +912,7 @@ struct ShaderStageFlags {
(fragment && type == ShaderType::FRAGMENT);
}
};
static constexpr ShaderStageFlags ALL_SHADER_STAGE_FLAGS = { .vertex = true, .fragment = true };
static constexpr ShaderStageFlags ALL_SHADER_STAGE_FLAGS = { true, true };
/**
* Selects which buffers to clear at the beginning of the render pass, as well as which buffers
@@ -998,8 +996,7 @@ enum class Workaround : uint16_t {
ALLOW_READ_ONLY_ANCILLARY_FEEDBACK_LOOP
};
} // namespace backend
} // namespace filament
} // namespace filament::backend
template<> struct utils::EnableBitMaskOperators<filament::backend::TargetBufferFlags>
: public std::true_type {};
+1 -1
View File
@@ -80,7 +80,7 @@ public:
* underlying platform is returned and \p backendHint is updated
* accordingly. Can't be nullptr.
*
* @return A pointer to the Plaform object.
* @return A pointer to the Platform object.
*
* @see destroy
*/
@@ -1,5 +1,3 @@
#include <utility>
/*
* Copyright (C) 2018 The Android Open Source Project
*
@@ -20,23 +18,19 @@
#define TNT_FILAMENT_BACKEND_PRIVATE_COMMANDSTREAM_H
#include "private/backend/CircularBuffer.h"
#include "private/backend/Dispatcher.h"
#include "private/backend/Program.h"
#include "private/backend/SamplerGroup.h"
#include "private/backend/Driver.h"
#include <backend/BufferDescriptor.h>
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
#include <backend/PipelineState.h>
#include <backend/PixelBufferDescriptor.h>
#include <backend/PresentCallable.h>
#include <backend/TargetBufferInfo.h>
#include "private/backend/Program.h"
#include "private/backend/SamplerGroup.h"
// FIXME: we'd like to not need this header here.
#include "private/backend/Driver.h"
#include <backend/DriverEnums.h>
#include <utils/compiler.h>
#include <utils/ThreadUtils.h>
@@ -45,40 +39,14 @@
#include <thread>
#include <utility>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
// Set to true to print every commands out on log.d. This requires RTTI and DEBUG
// Set to true to print every command out on log.d. This requires RTTI and DEBUG
#define DEBUG_COMMAND_STREAM false
namespace filament {
namespace backend {
class Driver;
class CommandBase;
/*
* Dispatcher is a data structure containing only function pointers.
* Each function pointer targets code that unpacks the arguments to the driver's method and
* calls it.
*
* Dispatcher's function pointers are populated during initialization and no CommandStream calls
* can be made before that.
*
* When a command is inserted into the stream, the corresponding function pointer is copied
* directly into CommandBase from Dispatcher.
*/
class Dispatcher {
public:
using Execute = void (*)(Driver& driver, CommandBase* self, intptr_t* next);
#define DECL_DRIVER_API_SYNCHRONOUS(RetType, methodName, paramsDecl, params)
#define DECL_DRIVER_API(methodName, paramsDecl, params) Execute methodName##_;
#define DECL_DRIVER_API_RETURN(RetType, methodName, paramsDecl, params) Execute methodName##_;
#include "DriverAPI.inc"
};
// ------------------------------------------------------------------------------------------------
namespace filament::backend {
class CommandBase {
static constexpr size_t FILAMENT_OBJECT_ALIGNMENT = alignof(std::max_align_t);
@@ -96,8 +64,10 @@ public:
// executes this command and returns the next one
inline CommandBase* execute(Driver& driver) {
// it is important to return the next command offset by output parameter instead
// of return value -- it allows the compiler to perform the tail call optimization.
// returning the next command by output parameter allows the compiler to perform the
// tail-call optimization in the function called by mExecute, however that comes at
// a cost here (writing and reading the stack at each iteration), in the end it's
// probably better to pay the cost at just one location.
intptr_t next;
mExecute(driver, this, &next);
return reinterpret_cast<CommandBase*>(reinterpret_cast<intptr_t>(this) + next);
@@ -132,7 +102,7 @@ constexpr decltype(auto) apply(M&& m, D&& d, T&& t) {
/*
* CommandType<> is just a wrapper class to specialize on a pointer-to-member of Driver
* (i.e. a method pointer to a method of Driver of a particular type -- but not the
* method itself). We only do that so we can identify the parameters of that method.
* method itself). We only do that, so we can identify the parameters of that method.
* We won't call through that pointer though.
*/
template<typename... ARGS>
@@ -208,7 +178,7 @@ class NoopCommand : public CommandBase {
}
public:
inline constexpr explicit NoopCommand(void* next) noexcept
: CommandBase(execute), mNext(size_t((char *)next - (char *)this)) { }
: CommandBase(execute), mNext(intptr_t((char *)next - (char *)this)) { }
};
// ------------------------------------------------------------------------------------------------
@@ -216,41 +186,34 @@ public:
#if !defined(NDEBUG) || (FILAMENT_DEBUG_COMMANDS >= FILAMENT_DEBUG_COMMANDS_ENABLE)
// For now, simply pass the method name down as a string and throw away the parameters.
// This is good enough for certain debugging needs and we can improve this later.
#define DEBUG_COMMAND_BEGIN(methodName, sync, ...) mDriver->debugCommandBegin(this, sync, #methodName)
#define DEBUG_COMMAND_END(methodName, sync) mDriver->debugCommandEnd(this, sync, #methodName)
#define DEBUG_COMMAND_BEGIN(methodName, sync, ...) mDriver.debugCommandBegin(this, sync, #methodName)
#define DEBUG_COMMAND_END(methodName, sync) mDriver.debugCommandEnd(this, sync, #methodName)
#else
#define DEBUG_COMMAND_BEGIN(methodName, sync, ...)
#define DEBUG_COMMAND_END(methodName, sync)
#endif
class CommandStream {
// Dispatcher could be a value (instead of pointer), which saves a load when writing commands
// at the expense of a larger CommandStream object (about ~400 bytes)
Dispatcher* mDispatcher = nullptr;
Driver* mDriver = nullptr;
CircularBuffer* UTILS_RESTRICT mCurrentBuffer = nullptr;
#ifndef NDEBUG
// just for debugging...
std::thread::id mThreadId{};
#endif
bool mUsePerformanceCounter = false;
template<typename T>
struct AutoExecute {
T closure;
inline AutoExecute(T&& closure) : closure(std::forward<T>(closure)) {}
inline explicit AutoExecute(T&& closure) : closure(std::forward<T>(closure)) {}
inline ~AutoExecute() { closure(); }
};
public:
CommandStream(Driver& driver, CircularBuffer& buffer) noexcept;
CommandStream(CommandStream const& rhs) noexcept = delete;
CommandStream& operator=(CommandStream const& rhs) noexcept = delete;
public:
#define DECL_DRIVER_API(methodName, paramsDecl, params) \
inline void methodName(paramsDecl) { \
DEBUG_COMMAND_BEGIN(methodName, false, params); \
using Cmd = COMMAND_TYPE(methodName); \
void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); \
new(p) Cmd(mDispatcher->methodName##_, APPLY(std::move, params)); \
new(p) Cmd(mDispatcher.methodName##_, APPLY(std::move, params)); \
DEBUG_COMMAND_END(methodName, false); \
}
@@ -260,16 +223,16 @@ public:
AutoExecute callOnExit([=](){ \
DEBUG_COMMAND_END(methodName, true); \
}); \
return apply(&Driver::methodName, *mDriver, std::forward_as_tuple(params)); \
return apply(&Driver::methodName, mDriver, std::forward_as_tuple(params)); \
}
#define DECL_DRIVER_API_RETURN(RetType, methodName, paramsDecl, params) \
inline RetType methodName(paramsDecl) { \
DEBUG_COMMAND_BEGIN(methodName, false, params); \
RetType result = mDriver->methodName##S(); \
RetType result = mDriver.methodName##S(); \
using Cmd = COMMAND_TYPE(methodName##R); \
void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); \
new(p) Cmd(mDispatcher->methodName##_, RetType(result), APPLY(std::move, params)); \
new(p) Cmd(mDispatcher.methodName##_, RetType(result), APPLY(std::move, params)); \
DEBUG_COMMAND_END(methodName, false); \
return result; \
}
@@ -277,10 +240,7 @@ public:
#include "DriverAPI.inc"
public:
CommandStream() noexcept = default;
CommandStream(Driver& driver, CircularBuffer& buffer) noexcept;
// This is for debugging only. Currently CircularBuffer can only be written from a
// This is for debugging only. Currently, CircularBuffer can only be written from a
// single thread. In debug builds we assert this condition.
// Call this first in the render loop.
inline void debugThreading() noexcept {
@@ -315,8 +275,21 @@ public:
private:
inline void* allocateCommand(size_t size) {
assert_invariant(utils::ThreadUtils::isThisThread(mThreadId));
return mCurrentBuffer->allocate(size);
return mCurrentBuffer.allocate(size);
}
// We use a copy of Dispatcher (instead of a pointer) because this removes one dereference
// when executing driver commands.
Driver& UTILS_RESTRICT mDriver;
CircularBuffer& UTILS_RESTRICT mCurrentBuffer;
Dispatcher mDispatcher;
#ifndef NDEBUG
// just for debugging...
std::thread::id mThreadId{};
#endif
bool mUsePerformanceCounter = false;
};
void* CommandStream::allocate(size_t size, size_t alignment) noexcept {
@@ -341,7 +314,6 @@ PodType* CommandStream::allocatePod(size_t count, size_t alignment) noexcept {
return static_cast<PodType*>(allocate(count * sizeof(PodType), alignment));
}
} // namespace backend
} // namespace filament
} // namespace filament::backend
#endif // TNT_FILAMENT_BACKEND_PRIVATE_COMMANDSTREAM_H
@@ -0,0 +1,50 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_FILAMENT_BACKEND_PRIVATE_DISPATCHER_H
#define TNT_FILAMENT_BACKEND_PRIVATE_DISPATCHER_H
#include <stdint.h>
namespace filament::backend {
class Driver;
class CommandBase;
/*
* Dispatcher is a data structure containing only function pointers.
* Each function pointer targets code that unpacks the arguments to the driver's method and
* calls it.
*
* Dispatcher's function pointers are populated during initialization and no CommandStream calls
* can be made before that.
*
* When a command is inserted into the stream, the corresponding function pointer is copied
* directly into CommandBase from Dispatcher.
*/
class Dispatcher {
public:
using Execute = void (*)(Driver& driver, CommandBase* self, intptr_t* next);
#define DECL_DRIVER_API_SYNCHRONOUS(RetType, methodName, paramsDecl, params)
#define DECL_DRIVER_API(methodName, paramsDecl, params) Execute methodName##_;
#define DECL_DRIVER_API_RETURN(RetType, methodName, paramsDecl, params) Execute methodName##_;
#include "DriverAPI.inc"
};
} // namespace filament::backend
#endif //TNT_FILAMENT_BACKEND_PRIVATE_DISPATCHER_H
@@ -17,23 +17,14 @@
#ifndef TNT_FILAMENT_BACKEND_PRIVATE_DRIVER_H
#define TNT_FILAMENT_BACKEND_PRIVATE_DRIVER_H
#include <backend/BufferDescriptor.h>
#include <backend/CallbackHandler.h>
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
#include <backend/PipelineState.h>
#include <backend/PixelBufferDescriptor.h>
#include <backend/PresentCallable.h>
#include <backend/TargetBufferInfo.h>
#include "private/backend/DriverApiForward.h"
#include "private/backend/Program.h"
#include "private/backend/SamplerGroup.h"
#include <utils/compiler.h>
#include <utils/Log.h>
#include <functional>
#include <stdint.h>
@@ -49,8 +40,13 @@
#define FILAMENT_DEBUG_COMMANDS FILAMENT_DEBUG_COMMANDS_NONE
namespace filament {
namespace backend {
namespace filament::backend {
class BufferDescriptor;
class CallbackHandler;
class PixelBufferDescriptor;
class Program;
class SamplerGroup;
template<typename T>
class ConcreteDispatcher;
@@ -59,27 +55,32 @@ class CommandStream;
class Driver {
public:
static size_t getElementTypeSize(ElementType type) noexcept;
virtual ~Driver() noexcept;
static size_t getElementTypeSize(ElementType type) noexcept;
// called from the main thread (NOT the render-thread) at various intervals, this
// is where the driver can execute user callbacks.
virtual void purge() noexcept = 0;
virtual ShaderModel getShaderModel() const noexcept = 0;
virtual Dispatcher& getDispatcher() noexcept = 0;
// Returns the dispatcher. This is only called once during initialization of the CommandStream,
// so it doesn't matter that it's virtual.
virtual Dispatcher getDispatcher() const noexcept = 0;
// called from CommandStream::execute on the render-thread
// the fn function will execute a batch of driver commands
// this gives the driver a chance to wrap their execution in a meaningful manner
// the default implementation simply calls fn
virtual void execute(std::function<void(void)> fn) noexcept;
virtual void execute(std::function<void(void)> const& fn) noexcept;
// This is called on debug build, or when enabled manually on the backend thread side.
virtual void debugCommandBegin(CommandStream* cmds, bool synchronous, const char* methodName) noexcept = 0;
virtual void debugCommandEnd(CommandStream* cmds, bool synchronous, const char* methodName) noexcept = 0;
virtual void debugCommandBegin(CommandStream* cmds,
bool synchronous, const char* methodName) noexcept = 0;
virtual void debugCommandEnd(CommandStream* cmds,
bool synchronous, const char* methodName) noexcept = 0;
/*
* Asynchronous calls here only to provide a type to CommandStream. They must be non-virtual
@@ -101,7 +102,6 @@ public:
#include "private/backend/DriverAPI.inc"
};
} // namespace backend
} // namespace filament
} // namespace filament::backend
#endif // TNT_FILAMENT_BACKEND_PRIVATE_DRIVER_H
@@ -246,11 +246,6 @@ DECL_DRIVER_API_R_N(backend::SwapChainHandle, createSwapChainHeadless,
uint32_t, height,
uint64_t, flags)
DECL_DRIVER_API_R_N(backend::StreamHandle, createStreamFromTextureId,
intptr_t, externalTextureId,
uint32_t, width,
uint32_t, height)
DECL_DRIVER_API_R_0(backend::TimerQueryHandle, createTimerQuery)
@@ -461,14 +456,6 @@ DECL_DRIVER_API_N(readPixels,
uint32_t, height,
backend::PixelBufferDescriptor&&, data)
DECL_DRIVER_API_N(readStreamPixels,
backend::StreamHandle, sh,
uint32_t, x,
uint32_t, y,
uint32_t, width,
uint32_t, height,
backend::PixelBufferDescriptor&&, data)
/*
* Rendering operations
* --------------------
@@ -17,15 +17,12 @@
#ifndef TNT_FILAMENT_BACKEND_PRIVATE_DRIVERAPIFORWARD_H
#define TNT_FILAMENT_BACKEND_PRIVATE_DRIVERAPIFORWARD_H
namespace filament {
namespace backend {
namespace filament::backend {
class CommandStream;
using DriverApi = CommandStream;
} // namespace backend
} // namespace filament
} // namespace filament::backend
#endif // TNT_FILAMENT_BACKEND_PRIVATE_DRIVERAPIFORWARD_H
@@ -61,7 +61,7 @@ public:
*/
template<typename D, typename ... ARGS>
Handle<D> allocateAndConstruct(ARGS&& ... args) noexcept {
Handle<D> h{ allocateHandle(sizeof(D)) };
Handle<D> h{ allocateHandle<sizeof(D)>() };
D* addr = handle_cast<D*>(h);
new(addr) D(std::forward<ARGS>(args)...);
#if HANDLE_TYPE_SAFETY
@@ -84,7 +84,7 @@ public:
*/
template<typename D>
Handle<D> allocate() noexcept {
Handle<D> h{ allocateHandle(sizeof(D)) };
Handle<D> h{ allocateHandle<sizeof(D)>() };
#if HANDLE_TYPE_SAFETY
D* addr = handle_cast<D*>(h);
mLock.lock();
@@ -167,7 +167,7 @@ public:
}
#endif
p->~D();
deallocateHandle(handle.getId(), sizeof(D));
deallocateHandle<sizeof(D)>(handle.getId());
}
}
@@ -249,23 +249,49 @@ private:
utils::LockingPolicy::SpinLock>;
#endif
// this is inlined because we're always called with a constexpr size
HandleBase::HandleId allocateHandle(size_t size) noexcept {
void* p = mHandleArena.alloc(size);
if (UTILS_LIKELY(p)) {
return pointerToHandle(p);
// allocateHandle()/deallocateHandle() selects the pool to use at compile-time based on the
// allocation size this is always inlined, because all these do is to call
// allocateHandleInPool()/deallocateHandleFromPool() with the right pool size.
template<size_t SIZE>
HandleBase::HandleId allocateHandle() noexcept {
if constexpr (SIZE <= P0) { return allocateHandleInPool<P0>(); }
if constexpr (SIZE <= P1) { return allocateHandleInPool<P1>(); }
return allocateHandleInPool<P2>();
}
template<size_t SIZE>
void deallocateHandle(HandleBase::HandleId id) noexcept {
if constexpr (SIZE <= P0) {
deallocateHandleFromPool<P0>(id);
} else if constexpr (SIZE <= P1) {
deallocateHandleFromPool<P1>(id);
} else {
return allocateHandleSlow(size);
deallocateHandleFromPool<P2>(id);
}
}
// this is inlined because we're always called with a constexpr size
void deallocateHandle(HandleBase::HandleId id, size_t size) noexcept {
// allocateHandleInPool()/deallocateHandleFromPool() is NOT inlined, which will cause three
// versions to be generated, one for each pool. Because the arena is synchronized,
// the code generated is not trivial (even if it's not insane either).
template<size_t SIZE>
UTILS_NOINLINE
HandleBase::HandleId allocateHandleInPool() noexcept {
void* p = mHandleArena.alloc(SIZE);
if (UTILS_LIKELY(p)) {
return pointerToHandle(p);
} else {
return allocateHandleSlow(SIZE);
}
}
template<size_t SIZE>
UTILS_NOINLINE
void deallocateHandleFromPool(HandleBase::HandleId id) noexcept {
if (UTILS_LIKELY(isPoolHandle(id))) {
void* p = handleToPointer(id);
mHandleArena.free(p, size);
mHandleArena.free(p, SIZE);
} else {
deallocateHandleSlow(id, size);
deallocateHandleSlow(id, SIZE);
}
}
@@ -82,15 +82,6 @@ public:
virtual void detach(Stream* stream) noexcept = 0;
virtual void updateTexImage(Stream* stream, int64_t* timestamp) noexcept = 0;
// external texture storage
virtual ExternalTexture* createExternalTextureStorage() noexcept = 0;
// this is called synchronously in the application thread (NOT the Driver thread)
virtual void reallocateExternalStorage(ExternalTexture* ets,
uint32_t w, uint32_t h, TextureFormat format) noexcept = 0;
virtual void destroyExternalTextureStorage(ExternalTexture* ets) noexcept = 0;
// The method allows platforms to convert a user-supplied external image object into a new type
// (e.g. HardwareBuffer => EGLImage). It makes sense for the default implementation to do nothing.
virtual AcquiredImage transformAcquiredImage(AcquiredImage source) noexcept { return source; }
+4 -4
View File
@@ -33,8 +33,7 @@
using namespace utils;
namespace filament {
namespace backend {
namespace filament::backend {
CircularBuffer::CircularBuffer(size_t size) {
mData = alloc(size);
@@ -56,6 +55,7 @@ CircularBuffer::~CircularBuffer() noexcept {
// If the system does not support mmap, emulate soft circular buffer with two buffers next
// to each others and a special case in circularize()
UTILS_NOINLINE
void* CircularBuffer::alloc(size_t size) noexcept {
#if HAS_MMAP
void* data = nullptr;
@@ -127,6 +127,7 @@ void* CircularBuffer::alloc(size_t size) noexcept {
#endif
}
UTILS_NOINLINE
void CircularBuffer::dealloc() noexcept {
#if HAS_MMAP
if (mData) {
@@ -162,5 +163,4 @@ void CircularBuffer::circularize() noexcept {
mTail = mHead;
}
} // namespace backend
} // namespace filament
} // namespace filament::backend
+7 -9
View File
@@ -29,8 +29,7 @@
using namespace utils;
namespace filament {
namespace backend {
namespace filament::backend {
// ------------------------------------------------------------------------------------------------
// A few utility functions for debugging...
@@ -57,9 +56,9 @@ static UTILS_NOINLINE UTILS_UNUSED std::string extractMethodName(std::string& co
// ------------------------------------------------------------------------------------------------
CommandStream::CommandStream(Driver& driver, CircularBuffer& buffer) noexcept
: mDispatcher(&driver.getDispatcher()),
mDriver(&driver),
mCurrentBuffer(&buffer)
: mDriver(driver),
mCurrentBuffer(buffer),
mDispatcher(driver.getDispatcher())
#ifndef NDEBUG
, mThreadId(ThreadUtils::getThreadId())
#endif
@@ -84,8 +83,8 @@ void CommandStream::execute(void* buffer) {
}
}
mDriver->execute([this, buffer]() {
Driver& UTILS_RESTRICT driver = *mDriver;
mDriver.execute([this, buffer]() {
Driver& UTILS_RESTRICT driver = mDriver;
CommandBase* UTILS_RESTRICT base = static_cast<CommandBase*>(buffer);
while (UTILS_LIKELY(base)) {
base = base->execute(driver);
@@ -152,5 +151,4 @@ void CustomCommand::execute(Driver&, CommandBase* base, intptr_t* next) noexcept
static_cast<CustomCommand*>(base)->~CustomCommand();
}
} // namespace backend
} // namespace filament
} // namespace filament::backend
+16 -10
View File
@@ -23,9 +23,9 @@
#include <utils/compiler.h>
#include <utils/Systrace.h>
#include <cstddef>
#include <utility>
#include <stddef.h>
#include <stdint.h>
#define DEBUG_LEVEL_NONE 0
@@ -46,10 +46,10 @@
namespace filament::backend {
template<typename ConcreteDriver>
class ConcreteDispatcher final : public Dispatcher {
class ConcreteDispatcher {
public:
// initialize the dispatch table
ConcreteDispatcher() noexcept;
static Dispatcher make() noexcept;
private:
#define DECL_DRIVER_API_SYNCHRONOUS(RetType, methodName, paramsDecl, params)
@@ -72,13 +72,19 @@ private:
template<typename ConcreteDriver>
UTILS_NOINLINE
ConcreteDispatcher<ConcreteDriver>::ConcreteDispatcher() noexcept : Dispatcher() {
#define DECL_DRIVER_API_SYNCHRONOUS(RetType, methodName, paramsDecl, params)
#define DECL_DRIVER_API(methodName, paramsDecl, params) methodName##_ = &ConcreteDispatcher::methodName;
#define DECL_DRIVER_API_RETURN(RetType, methodName, paramsDecl, params) methodName##_ = &ConcreteDispatcher::methodName;
#include "private/backend/DriverAPI.inc"
}
Dispatcher ConcreteDispatcher<ConcreteDriver>::make() noexcept {
Dispatcher dispatcher;
#define DECL_DRIVER_API_SYNCHRONOUS(RetType, methodName, paramsDecl, params)
#define DECL_DRIVER_API(methodName, paramsDecl, params) \
dispatcher.methodName##_ = &ConcreteDispatcher::methodName;
#define DECL_DRIVER_API_RETURN(RetType, methodName, paramsDecl, params) \
dispatcher.methodName##_ = &ConcreteDispatcher::methodName;
#include "private/backend/DriverAPI.inc"
return dispatcher;
}
} // namespace filament::backend
+14 -19
View File
@@ -15,6 +15,8 @@
*/
#include "private/backend/Driver.h"
#include "private/backend/AcquiredImage.h"
#include "private/backend/CommandStream.h"
#include "DriverBase.h"
@@ -25,20 +27,15 @@
#include <math/vec4.h>
#include <backend/BufferDescriptor.h>
#include <backend/PixelBufferDescriptor.h>
#include <utils/Systrace.h>
using namespace utils;
using namespace filament::math;
namespace filament {
namespace filament::backend {
using namespace math;
namespace backend {
DriverBase::DriverBase(Dispatcher* dispatcher) noexcept
: mDispatcher(dispatcher) {
DriverBase::DriverBase() noexcept {
if constexpr (UTILS_HAS_THREADING) {
// This thread services user callbacks
mServiceThread = std::thread([this]() {
@@ -75,7 +72,6 @@ DriverBase::~DriverBase() noexcept {
lock.unlock();
mServiceThread.join();
}
delete mDispatcher;
}
// ------------------------------------------------------------------------------------------------
@@ -169,14 +165,6 @@ void DriverBase::debugCommandEnd(CommandStream* cmds, bool synchronous, const ch
}
}
// ------------------------------------------------------------------------------------------------
Driver::~Driver() noexcept = default;
void Driver::execute(std::function<void(void)> fn) noexcept {
fn();
}
size_t Driver::getElementTypeSize(ElementType type) noexcept {
switch (type) {
case ElementType::BYTE: return sizeof(int8_t);
@@ -208,5 +196,12 @@ size_t Driver::getElementTypeSize(ElementType type) noexcept {
}
}
} // namespace backend
} // namespace filament
// ------------------------------------------------------------------------------------------------
Driver::~Driver() noexcept = default;
void Driver::execute(std::function<void(void)> const& fn) noexcept {
fn();
}
} // namespace filament::backend
+5 -10
View File
@@ -22,14 +22,14 @@
#include <backend/Platform.h>
#include <backend/BufferDescriptor.h>
#include <backend/DriverEnums.h>
#include <backend/CallbackHandler.h>
#include "private/backend/AcquiredImage.h"
#include "private/backend/Dispatcher.h"
#include "private/backend/Driver.h"
#include "private/backend/SamplerGroup.h"
#include <array>
#include <condition_variable>
#include <memory>
#include <mutex>
@@ -41,7 +41,7 @@
namespace filament::backend {
class Dispatcher;
struct AcquiredImage;
/*
* Hardware handles
@@ -72,7 +72,7 @@ struct HwBufferObject : public HwBase {
uint32_t byteCount{};
HwBufferObject() noexcept = default;
HwBufferObject(uint32_t byteCount) noexcept : byteCount(byteCount) {}
explicit HwBufferObject(uint32_t byteCount) noexcept : byteCount(byteCount) {}
};
struct HwIndexBuffer : public HwBase {
@@ -167,21 +167,16 @@ struct HwTimerQuery : public HwBase {
class DriverBase : public Driver {
public:
DriverBase() = delete;
explicit DriverBase(Dispatcher* dispatcher) noexcept;
DriverBase() noexcept;
~DriverBase() noexcept override;
void purge() noexcept final;
Dispatcher& getDispatcher() noexcept final { return *mDispatcher; }
// --------------------------------------------------------------------------------------------
// Privates
// --------------------------------------------------------------------------------------------
protected:
Dispatcher* mDispatcher;
class CallbackDataDetails;
// Helpers...
@@ -1,222 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ExternalTextureManagerAndroid.h"
#include <utils/api_level.h>
#include <utils/compiler.h>
#include <utils/Log.h>
#include <dlfcn.h>
using namespace utils;
namespace filament::backend {
template <typename T>
static void loadSymbol(T*& pfn, const char *symbol) noexcept {
pfn = (T*)dlsym(RTLD_DEFAULT, symbol);
}
// ------------------------------------------------------------------------------------------------
namespace ndk {
/*
* This mimics the GraphicBuffer class for pre-API 26
*/
template<typename NATIVE_TYPE, typename REF>
struct ANativeObjectBase : public NATIVE_TYPE, public REF {
};
struct android_native_base_t {
unsigned int magic;
unsigned int version;
void* reserved[4];
void (* incRef)(struct android_native_base_t* base);
void (* decRef)(struct android_native_base_t* base);
};
struct ANativeWindowBuffer {
struct android_native_base_t common;
unsigned int width;
unsigned int height;
unsigned int stride;
unsigned int format;
unsigned int usage_deprecated;
uintptr_t layerCount;
void* reserved[1];
const void* handle;
uint64_t usage;
void* reserved_proc[8 - (sizeof(uint64_t) / sizeof(void*))];
};
struct RefBase {
virtual ~RefBase() = default;
void* ref;
};
struct GraphicBuffer : public ANativeObjectBase<ANativeWindowBuffer, RefBase> {
};
struct GraphicBufferWrapper {
GraphicBuffer* graphicBuffer;
};
} // namespace ndk
// ------------------------------------------------------------------------------------------------
using namespace ndk;
struct EGLExternalTexture : public ExternalTextureManagerAndroid::ExternalTexture {
GraphicBufferWrapper* graphicBufferWrapper = nullptr;
};
ExternalTextureManagerAndroid& ExternalTextureManagerAndroid::create() noexcept {
return *(new ExternalTextureManagerAndroid{});
}
void ExternalTextureManagerAndroid::destroy(ExternalTextureManagerAndroid* pExternalTextureManager) noexcept {
delete pExternalTextureManager;
}
// called on gl thread
ExternalTextureManagerAndroid::ExternalTextureManagerAndroid() noexcept
: mVm(VirtualMachineEnv::get()) {
}
// not quite sure on which thread this is going to be called
ExternalTextureManagerAndroid::~ExternalTextureManagerAndroid() noexcept {
if (__builtin_available(android 26, *)) {
} else {
if (mGraphicBufferClass) {
JNIEnv* env = VirtualMachineEnv::getThreadEnvironment();
if (env) {
env->DeleteGlobalRef(mGraphicBufferClass);
}
}
}
}
// called on gl thread
Platform::ExternalTexture* ExternalTextureManagerAndroid::createExternalTexture() noexcept {
if (__builtin_available(android 26, *)) {
} else {
// initialize java stuff on-demand
if (!mGraphicBufferClass) {
JNIEnv* env = mVm.getEnvironment();
mGraphicBufferClass = env->FindClass("android/view/GraphicBuffer");
mGraphicBuffer_nCreateGraphicBuffer = env->GetStaticMethodID(
mGraphicBufferClass, "nCreateGraphicBuffer", "(IIII)J");
mGraphicBuffer_nDestroyGraphicBuffer = env->GetStaticMethodID(
mGraphicBufferClass, "nDestroyGraphicBuffer", "(J)V");
mGraphicBufferClass = static_cast<jclass>(env->NewGlobalRef(mGraphicBufferClass));
}
}
EGLExternalTexture* ets = new EGLExternalTexture;
return ets;
}
// called on app thread
void ExternalTextureManagerAndroid::reallocate(
Platform::ExternalTexture* ets, uint32_t w, uint32_t h,
TextureFormat format, uint64_t usage) noexcept {
destroyStorage(ets);
alloc(ets, w, h, format, usage);
}
// called on gl thread
void ExternalTextureManagerAndroid::destroy(Platform::ExternalTexture* ets) noexcept {
destroyStorage(ets);
delete static_cast<EGLExternalTexture*>(ets);
}
// called on app thread
void ExternalTextureManagerAndroid::alloc(
Platform::ExternalTexture* t,
uint32_t w, uint32_t h, TextureFormat format, uint64_t usage) noexcept {
EGLExternalTexture* ets = static_cast<EGLExternalTexture*>(t);
AHardwareBuffer_Desc desc = { w, h, 1, 0, usage, 0, 0, 0 };
switch (format) {
case TextureFormat::RGB8:
// don't use R8G8B8 here because some drivers produce garbled images
desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
break;
case TextureFormat::RGBA8:
desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
break;
case TextureFormat::RGB565:
desc.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
break;
case TextureFormat::RGB10_A2:
desc.format = AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
break;
default:
slog.e << "Unsupported format " << (int)format << ", use RGBA8 or RGB8 only."
<< io::endl;
return;
}
if (__builtin_available(android 26, *)) {
// allocate new storage...
AHardwareBuffer* buffer = nullptr;
if (AHardwareBuffer_allocate(&desc, &buffer) < 0) {
slog.e << "AHardwareBuffer_allocate() failed" << io::endl;
return;
}
ets->hardwareBuffer = buffer;
} else {
// note: This is called on the application thread (not the GL thread)
JNIEnv* env = VirtualMachineEnv::getThreadEnvironment();
if (!env) {
return; // this should not happen
}
jlong graphicBufferWrapperJni = env->CallStaticLongMethod(mGraphicBufferClass,
mGraphicBuffer_nCreateGraphicBuffer, w, h, desc.format, usage);
VirtualMachineEnv::handleException(env);
if (graphicBufferWrapperJni) {
GraphicBuffer* const gb = ((GraphicBufferWrapper*)graphicBufferWrapperJni)->graphicBuffer;
ets->graphicBufferWrapper = (GraphicBufferWrapper*)graphicBufferWrapperJni;
ets->clientBuffer = static_cast<ANativeWindowBuffer*>(gb);
}
}
}
// called on gl thread
void ExternalTextureManagerAndroid::destroyStorage(Platform::ExternalTexture* t) noexcept {
EGLExternalTexture* ets = static_cast<EGLExternalTexture*>(t);
if (__builtin_available(android 26, *)) {
// destroy the current storage if any
if (ets->hardwareBuffer) {
AHardwareBuffer_release(ets->hardwareBuffer);
ets->hardwareBuffer = nullptr;
}
} else {
if (ets->graphicBufferWrapper) {
JNIEnv* env = VirtualMachineEnv::get().getEnvironment();
env->CallStaticVoidMethod(mGraphicBufferClass,
mGraphicBuffer_nDestroyGraphicBuffer, (jlong)ets->graphicBufferWrapper);
VirtualMachineEnv::handleException(env);
ets->graphicBufferWrapper = nullptr;
}
}
}
} // namespace filament::backend
@@ -1,84 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_FILAMENT_DRIVER_ANDROID_EXTERNAL_TEXTURE_MANAGER_ANDROID_H
#define TNT_FILAMENT_DRIVER_ANDROID_EXTERNAL_TEXTURE_MANAGER_ANDROID_H
#include "private/backend/VirtualMachineEnv.h"
#include <backend/DriverEnums.h>
#include <backend/Platform.h>
#include <android/api-level.h>
#include <android/hardware_buffer.h>
namespace filament::backend {
/*
* ExternalTextureManagerAndroid::ExternalTexture is basically a wrapper for AHardwareBuffer.
*
* This class doesn't rely on GL or EGL, and could be used for other Android platform if needed
* (e.g. Vulkan).
*
* ExternalTextureManagerAndroid handle allocation/destruction using either Java or the NDK,
* whichever is available.
*/
class ExternalTextureManagerAndroid {
public:
struct ExternalTexture : public Platform::ExternalTexture {
void* clientBuffer = nullptr;
AHardwareBuffer* hardwareBuffer = nullptr;
};
// must be called on backend thread
static ExternalTextureManagerAndroid& create() noexcept;
// must be called on backend thread
static void destroy(ExternalTextureManagerAndroid* pExternalTextureManager) noexcept;
// must be called on backend thread (only because we don't synchronize
Platform::ExternalTexture* createExternalTexture() noexcept;
// called on app thread
void reallocate(
Platform::ExternalTexture* ets, uint32_t w, uint32_t h,
TextureFormat format, uint64_t usage) noexcept;
// must be called on backend thread
void destroy(Platform::ExternalTexture* ets) noexcept;
private:
ExternalTextureManagerAndroid() noexcept;
~ExternalTextureManagerAndroid() noexcept;
// called on app thread
void alloc(Platform::ExternalTexture* ets,
uint32_t w, uint32_t h, TextureFormat format, uint64_t usage) noexcept;
// called on gl thread
void destroyStorage(Platform::ExternalTexture* ets) noexcept;
VirtualMachineEnv& mVm;
jclass mGraphicBufferClass = nullptr;
jmethodID mGraphicBuffer_nCreateGraphicBuffer = nullptr;
jmethodID mGraphicBuffer_nDestroyGraphicBuffer = nullptr;
};
} // namespace filament::backend
#endif // TNT_FILAMENT_DRIVER_ANDROID_EXTERNAL_TEXTURE_MANAGER_ANDROID_H
+2 -1
View File
@@ -44,6 +44,7 @@ struct UniformBufferState;
class MetalDriver final : public DriverBase {
explicit MetalDriver(MetalPlatform* platform) noexcept;
~MetalDriver() noexcept override;
Dispatcher getDispatcher() const noexcept final;
public:
static Driver* create(MetalPlatform* platform);
@@ -59,7 +60,7 @@ private:
ShaderModel getShaderModel() const noexcept final;
// Overrides the default implementation by wrapping the call to fn in an @autoreleasepool block.
void execute(std::function<void(void)> fn) noexcept final;
void execute(std::function<void(void)> const& fn) noexcept final;
/*
* Driver interface
+8 -18
View File
@@ -50,11 +50,14 @@ Driver* MetalDriver::create(MetalPlatform* const platform) {
return new MetalDriver(platform);
}
Dispatcher MetalDriver::getDispatcher() const noexcept {
return ConcreteDispatcher<MetalDriver>::make();
}
MetalDriver::MetalDriver(MetalPlatform* platform) noexcept
: DriverBase(new ConcreteDispatcher<MetalDriver>()),
mPlatform(*platform),
mContext(new MetalContext),
mHandleAllocator("Handles", FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U) {
: mPlatform(*platform),
mContext(new MetalContext),
mHandleAllocator("Handles", FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U) {
mContext->driver = this;
mContext->device = mPlatform.createDevice();
@@ -158,7 +161,7 @@ void MetalDriver::setFrameCompletedCallback(Handle<HwSwapChain> sch,
swapChain->setFrameCompletedCallback(callback, user);
}
void MetalDriver::execute(std::function<void(void)> fn) noexcept {
void MetalDriver::execute(std::function<void(void)> const& fn) noexcept {
@autoreleasepool {
fn();
}
@@ -356,10 +359,6 @@ void MetalDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch,
construct_handle<MetalSwapChain>(sch, *mContext, width, height, flags);
}
void MetalDriver::createStreamFromTextureIdR(Handle<HwStream>, intptr_t externalTextureId,
uint32_t width, uint32_t height) {
}
void MetalDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
// nothing to do, timer query was constructed in createTimerQueryS
}
@@ -428,10 +427,6 @@ Handle<HwSwapChain> MetalDriver::createSwapChainHeadlessS() noexcept {
return alloc_handle<MetalSwapChain>();
}
Handle<HwStream> MetalDriver::createStreamFromTextureIdS() noexcept {
return {};
}
Handle<HwTimerQuery> MetalDriver::createTimerQueryS() noexcept {
// The handle must be constructed here, as a synchronous call to getTimerQueryValue might happen
// before createTimerQueryR is executed.
@@ -1050,11 +1045,6 @@ void MetalDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y,
}];
}
void MetalDriver::readStreamPixels(Handle<HwStream> sh, uint32_t x, uint32_t y, uint32_t width,
uint32_t height, PixelBufferDescriptor&& data) {
}
void MetalDriver::blit(TargetBufferFlags buffers,
Handle<HwRenderTarget> dst, Viewport dstRect,
Handle<HwRenderTarget> src, Viewport srcRect,
+1 -1
View File
@@ -367,7 +367,7 @@ MetalProgram::MetalProgram(id<MTLDevice> device, const Program& program) noexcep
*shaderFunctions[i] = [library newFunctionWithName:@"main0"];
}
// All stages of the program have compiled successfuly, this is a valid program.
// All stages of the program have compiled successfully, this is a valid program.
isValid = true;
// This calculates Metal resource binding indices. Filament's sampler bindings range from 0-31
+1 -1
View File
@@ -170,7 +170,7 @@ private:
};
// StateTracker keeps track of state changes made to a Metal command encoder.
// Different kinds of state, like pipeline state, uniform buffer state, etc, are passed to the
// Different kinds of state, like pipeline state, uniform buffer state, etc., are passed to the
// current Metal command encoder and persist throughout the lifetime of the encoder (a frame).
// StateTracker is used to prevent calling redundant state change methods.
template<typename StateType>
+5 -7
View File
@@ -23,11 +23,14 @@ Driver* NoopDriver::create() {
return new NoopDriver();
}
NoopDriver::NoopDriver() noexcept : DriverBase(new ConcreteDispatcher<NoopDriver>()) {
}
NoopDriver::NoopDriver() noexcept = default;
NoopDriver::~NoopDriver() noexcept = default;
Dispatcher NoopDriver::getDispatcher() const noexcept {
return ConcreteDispatcher<NoopDriver>::make();
}
ShaderModel NoopDriver::getShaderModel() const noexcept {
#if defined(__ANDROID__) || defined(IOS) || defined(__EMSCRIPTEN__)
return ShaderModel::GL_ES_30;
@@ -305,11 +308,6 @@ void NoopDriver::readPixels(Handle<HwRenderTarget> src,
scheduleDestroy(std::move(p));
}
void NoopDriver::readStreamPixels(Handle<HwStream> sh, uint32_t x, uint32_t y, uint32_t width,
uint32_t height, PixelBufferDescriptor&& p) {
scheduleDestroy(std::move(p));
}
void NoopDriver::blit(TargetBufferFlags buffers,
Handle<HwRenderTarget> dst, Viewport dstRect,
Handle<HwRenderTarget> src, Viewport srcRect,
+1
View File
@@ -27,6 +27,7 @@ namespace filament::backend {
class NoopDriver final : public DriverBase {
NoopDriver() noexcept;
~NoopDriver() noexcept override;
Dispatcher getDispatcher() const noexcept final;
public:
static Driver* create();
+16
View File
@@ -121,5 +121,21 @@ void assertFramebufferStatus(io::ostream& out, GLenum target, const char* functi
}
}
bool unordered_string_set::has(std::string_view str) const noexcept {
return find(str) != end();
}
unordered_string_set split(const char* extensions) noexcept {
unordered_string_set set;
std::string_view string(extensions);
do {
auto p = string.find(' ');
p = (p == std::string_view::npos ? string.length() : p);
set.emplace(string.data(), p);
string.remove_prefix(p == string.length() ? p : p + 1);
} while(!string.empty());
return set;
}
} // namespace GLUtils
} // namespace filament::backend
+8 -24
View File
@@ -22,7 +22,7 @@
#include <backend/DriverEnums.h>
#include <string>
#include <string_view>
#include <unordered_set>
#include <string.h>
@@ -42,13 +42,12 @@ void assertFramebufferStatus(utils::io::ostream& out, GLenum target, const char*
#ifdef NDEBUG
# define CHECK_GL_ERROR(out)
# define CHECK_GL_ERROR_NON_FATAL(out)
# define CHECK_GL_FRAMEBUFFER_STATUS(out, target)
#else
# ifdef _MSC_VER
# define __PRETTY_FUNCTION__ __FUNCSIG__
# endif
# define CHECK_GL_ERROR(out) { GLUtils::assertGLError(out, __PRETTY_FUNCTION__, __LINE__); }
# define CHECK_GL_FRAMEBUFFER_STATUS(out, target) { GLUtils::checkFramebufferStatus(out, target, __PRETTY_FUNCTION__, __LINE__); }
# define CHECK_GL_ERROR(out) { GLUtils::assertGLError(out, __func__, __LINE__); }
# define CHECK_GL_ERROR_NON_FATAL(out) { GLUtils::checkGLError(out, __func__, __LINE__); }
# define CHECK_GL_FRAMEBUFFER_STATUS(out, target) { GLUtils::checkFramebufferStatus(out, target, __func__, __LINE__); }
#endif
constexpr inline GLuint getComponentCount(ElementType type) noexcept {
@@ -507,27 +506,12 @@ constexpr /* inline */ GLenum getInternalFormat(TextureFormat format) noexcept {
}
}
class unordered_string_set : public std::unordered_set<std::string> {
class unordered_string_set : public std::unordered_set<std::string_view> {
public:
bool has(const char* str) {
return find(std::string(str)) != end();
}
bool has(std::string_view str) const noexcept;
};
inline unordered_string_set split(const char* spacedList) {
unordered_string_set set;
const char* current = spacedList;
const char* head = current;
do {
head = strchr(current, ' ');
std::string s(current, head ? head - current : strlen(current));
if (s.length()) {
set.insert(std::move(s));
}
current = head + 1;
} while (head);
return set;
}
unordered_string_set split(const char* extensions) noexcept;
} // namespace GLUtils
} // namespace filament::backend
@@ -1,215 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "OpenGLBlitter.h"
#include "GLUtils.h"
#include "OpenGLContext.h"
#include <utils/compiler.h>
#include <utils/Log.h>
#include <math/vec2.h>
using namespace filament::math;
using namespace utils;
namespace filament::backend {
static const char s_vertexES[] = R"SHADER(#version 300 es
in vec4 pos;
void main() {
gl_Position = pos;
}
)SHADER";
static const char s_vertexGL[] = R"SHADER(#version 410 core
in vec4 pos;
void main() {
gl_Position = pos;
}
)SHADER";
static const char s_fragmentES[] = R"SHADER(#version 300 es
#extension GL_OES_EGL_image_external_essl3 : enable
precision mediump float;
uniform samplerExternalOES sampler;
out vec4 fragColor;
void main() {
fragColor = texelFetch(sampler, ivec2(gl_FragCoord.xy), 0);
}
)SHADER";
static const char s_fragmentGL[] = R"SHADER(#version 410 core
precision mediump float;
uniform sampler2D sampler;
out vec4 fragColor;
void main() {
fragColor = texelFetch(sampler, ivec2(gl_FragCoord.xy), 0);
}
)SHADER";
void OpenGLBlitter::init() noexcept {
glGenSamplers(1, &mSampler);
glSamplerParameteri(mSampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glSamplerParameteri(mSampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glSamplerParameteri(mSampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glSamplerParameteri(mSampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glSamplerParameteri(mSampler, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
GLint status;
char const* vsource[2] = { s_vertexES, s_vertexGL };
char const* fsource[2] = { s_fragmentES, s_fragmentGL };
const size_t index = GLES30_HEADERS ? 0 : 1;
mVertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(mVertexShader, 1, vsource + index, nullptr);
glCompileShader(mVertexShader);
glGetShaderiv(mVertexShader, GL_COMPILE_STATUS, &status);
assert_invariant(status == GL_TRUE);
mFragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(mFragmentShader, 1, fsource + index, nullptr);
glCompileShader(mFragmentShader);
glGetShaderiv(mFragmentShader, GL_COMPILE_STATUS, &status);
assert_invariant(status == GL_TRUE);
mProgram = glCreateProgram();
glAttachShader(mProgram, mVertexShader);
glAttachShader(mProgram, mFragmentShader);
glLinkProgram(mProgram);
glGetProgramiv(mProgram, GL_LINK_STATUS, &status);
assert_invariant(status == GL_TRUE);
glUseProgram(mProgram);
GLint loc = glGetUniformLocation(mProgram, "sampler");
GLuint tmu = 0;
glUniform1i(loc, tmu);
glGenFramebuffers(1, &mFBO);
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLBlitter::terminate() noexcept {
glDeleteSamplers(1, &mSampler);
glDetachShader(mProgram, mVertexShader);
glDetachShader(mProgram, mFragmentShader);
glDeleteShader(mVertexShader);
glDeleteShader(mFragmentShader);
glDeleteProgram(mProgram);
glDeleteFramebuffers(1, &mFBO);
}
void OpenGLBlitter::blit(GLuint srcTextureExternal, GLuint dstTexture2d, GLuint w, GLuint h) noexcept {
const float2 vtx[3] = {{ -1.0f, 3.0f },
{ -1.0f, -1.0f },
{ 3.0f, -1.0f }};
// we're using tmu 0 as the source texture
GLuint tmu = 0;
// source texture
glBindSampler(tmu, mSampler);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, srcTextureExternal);
CHECK_GL_ERROR(utils::slog.e)
// destination texture
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dstTexture2d, 0);
CHECK_GL_ERROR(utils::slog.e)
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_FRAMEBUFFER)
// geometry
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vtx);
// blit...
glViewport(0, 0, w, h);
glUseProgram(mProgram);
glDrawArrays(GL_TRIANGLES, 0, 3);
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLBlitter::State::save() noexcept {
mHasState = true;
// TODO: technically we should also save glVertexAttribPointer
GLuint tmu = 0;
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &framebuffer);
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &array);
glGetIntegerv(GL_CURRENT_PROGRAM, &program);
glGetIntegerv(GL_VIEWPORT, viewport);
glGetIntegerv(GL_COLOR_WRITEMASK, writeMask);
scissorTest = glIsEnabled(GL_SCISSOR_TEST);
stencilTest = glIsEnabled(GL_STENCIL_TEST);
cullFace = glIsEnabled(GL_CULL_FACE);
glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &vertexAttrib);
// save the current active texture first
glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture);
// we're using tmu 0 as the source texture
glActiveTexture(GL_TEXTURE0 + tmu);
// save what depends on glActiveTexture
glGetIntegerv(GL_SAMPLER_BINDING, &sampler);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &texture);
/*
* Set the state
*/
// we're using tmu 0 as the source texture
glDisable(GL_SCISSOR_TEST);
glDisable(GL_STENCIL_TEST);
glDisable(GL_CULL_FACE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
CHECK_GL_ERROR(utils::slog.e)
}
void OpenGLBlitter::State::restore() noexcept {
GLuint tmu = 0;
glColorMask(
(GLboolean)writeMask[0],
(GLboolean)writeMask[1],
(GLboolean)writeMask[2],
(GLboolean)writeMask[3]);
if (cullFace) {
glEnable(GL_CULL_FACE);
}
if (stencilTest) {
glEnable(GL_STENCIL_TEST);
}
if (scissorTest) {
glEnable(GL_SCISSOR_TEST);
}
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
glUseProgram(static_cast<GLuint>(program));
glBindBuffer(GL_ARRAY_BUFFER, static_cast<GLuint>(array));
glBindFramebuffer(GL_FRAMEBUFFER, static_cast<GLuint>(framebuffer));
if (!vertexAttrib) {
glDisableVertexAttribArray(0);
}
glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(texture));
glBindSampler(tmu, static_cast<GLuint>(sampler));
glActiveTexture(static_cast<GLenum>(activeTexture));
CHECK_GL_ERROR(utils::slog.e)
}
} // namespace filament::backend
@@ -1,67 +0,0 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGLBLITTER_H
#define TNT_FILAMENT_BACKEND_OPENGL_OPENGLBLITTER_H
#include <utils/compiler.h>
#include "gl_headers.h"
namespace filament::backend {
class OpenGLContext;
class OpenGLBlitter {
public:
explicit OpenGLBlitter(OpenGLContext& context) noexcept : mContext(context) {}
void init() noexcept;
void terminate() noexcept;
void blit(GLuint srcTextureExternal, GLuint dstTexture2d, GLuint w, GLuint h) noexcept;
class State {
bool mHasState = false;
GLint activeTexture, sampler, texture, framebuffer, array, vertexAttrib, program;
GLboolean stencilTest, scissorTest, cullFace;
GLint viewport[4], writeMask[4];
void save() noexcept;
void restore() noexcept;
public:
void setup() noexcept {
if (UTILS_UNLIKELY(!mHasState)) {
save();
}
}
~State() noexcept {
if (UTILS_UNLIKELY(mHasState)) {
restore();
}
}
};
private:
UTILS_UNUSED OpenGLContext& mContext;
GLuint mSampler{};
GLuint mVertexShader{};
GLuint mFragmentShader{};
GLuint mProgram{};
GLuint mFBO{};
};
} // namespace filament::backend
#endif // TNT_FILAMENT_BACKEND_OPENGL_OPENGLBLITTER_H
+217 -195
View File
@@ -19,122 +19,153 @@
// change to true to display all GL extensions in the console on start-up
#define DEBUG_PRINT_EXTENSIONS false
using namespace utils;
namespace filament::backend {
using namespace backend;
bool OpenGLContext::queryOpenGLVersion(GLint* major, GLint* minor) noexcept {
if constexpr (BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GLES) {
char const* version = (char const*)glGetString(GL_VERSION);
// This works on all versions of GLES
int n = version ? sscanf(version, "OpenGL ES %d.%d", major, minor) : 0;
return n == 2;
} else if constexpr (BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GL) {
// OpenGL version
glGetIntegerv(GL_MAJOR_VERSION, major);
glGetIntegerv(GL_MINOR_VERSION, minor);
return (glGetError() == GL_NO_ERROR);
}
}
OpenGLContext::OpenGLContext() noexcept {
state.vao.p = &mDefaultVAO;
state.enables.caps.set(getIndexForCap(GL_DITHER));
UTILS_UNUSED char const* const vendor = (char const*) glGetString(GL_VENDOR);
UTILS_UNUSED char const* const renderer = (char const*) glGetString(GL_RENDERER);
UTILS_UNUSED char const* const version = (char const*) glGetString(GL_VERSION);
UTILS_UNUSED char const* const shader = (char const*) glGetString(GL_SHADING_LANGUAGE_VERSION);
// There query work with all GL/GLES versions!
state.vendor = (char const*)glGetString(GL_VENDOR);
state.renderer = (char const*)glGetString(GL_RENDERER);
state.version = (char const*)glGetString(GL_VERSION);
state.shader = (char const*)glGetString(GL_SHADING_LANGUAGE_VERSION);
slog.v << "[" << vendor << "], [" << renderer << "], [" << version << "], [" << shader << "]" << io::endl;
slog.v << "[" << state.vendor << "], [" << state.renderer << "], "
"[" << state.version << "], [" << state.shader << "]" << io::endl;
// OpenGL (ES) version
GLint major = 0;
GLint minor = 0;
glGetIntegerv(GL_MAJOR_VERSION, &major);
glGetIntegerv(GL_MINOR_VERSION, &minor);
/*
* Figure out GL / GLES version and available features
*/
// Figure out if we have the extension we need
GLint n = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &n);
ExtentionSet exts;
for (GLint i = 0; i < n; i++) {
const char * const extension = (const char*)glGetStringi(GL_EXTENSIONS, (GLuint)i);
exts.insert(StaticString::make(extension, strlen(extension)));
if (DEBUG_PRINT_EXTENSIONS) {
slog.d << extension << io::endl;
queryOpenGLVersion(&state.major, &state.minor);
if constexpr (BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GLES) {
// This works on all versions of GLES
if (state.major == 3 && state.minor >= 0) {
mShaderModel = ShaderModel::GL_ES_30;
}
}
ShaderModel shaderModel = ShaderModel::UNKNOWN;
if (GLES30_HEADERS) {
if (major == 3 && minor >= 0) {
shaderModel = ShaderModel::GL_ES_30;
}
if (major == 3 && minor >= 1) {
if (state.major == 3 && state.minor >= 1) {
features.multisample_texture = true;
}
initExtensionsGLES(major, minor, exts);
} else if (GL41_HEADERS) {
if (major == 4 && minor >= 1) {
shaderModel = ShaderModel::GL_CORE_41;
initExtensionsGLES();
} else if constexpr (BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GL) {
// OpenGL version
if (state.major == 4 && state.minor >= 1) {
mShaderModel = ShaderModel::GL_CORE_41;
}
initExtensionsGL(major, minor, exts);
features.multisample_texture = true;
// feedback loops are allowed on GL desktop as long as writes are disabled
bugs.allow_read_only_ancillary_feedback_loop = true;
initExtensionsGL();
}
assert_invariant(shaderModel != ShaderModel::UNKNOWN);
mShaderModel = shaderModel;
// Figure out which driver bugs we need to workaround
if (strstr(renderer, "Adreno")) {
bugs.invalidate_end_only_if_invalidate_start = true;
assert_invariant(mShaderModel != ShaderModel::UNKNOWN);
// On Adreno (As of 3/20) timer query seem to return the CPU time, not the GPU time.
bugs.dont_use_timer_query = true;
/*
* Figure out which driver bugs we need to workaround
*/
// Blits to texture arrays are failing
// This bug continues to reproduce, though at times we've seen it appear to "go away". The
// standalone sample app that was written to show this problem still reproduces.
// The working hypthesis is that some other state affects this behavior.
bugs.disable_sidecar_blit_into_texture_array = true;
const bool isAngle = strstr(state.renderer, "ANGLE");
if (!isAngle) {
if (strstr(state.renderer, "Adreno")) {
// Qualcomm GPU
bugs.invalidate_end_only_if_invalidate_start = true;
// early exit condition is flattened in EASU code
bugs.split_easu = true;
int maj, min, driverMajor, driverMinor;
int c = sscanf(version, "OpenGL ES %d.%d V@%d.%d", // NOLINT(cert-err34-c)
&maj, &min, &driverMajor, &driverMinor);
if (c == 4) {
// workarounds based on version here.
// notes:
// bugs.invalidate_end_only_if_invalidate_start
// - appeared at least in "OpenGL ES 3.2 V@0490.0 (GIT@85da404, I46ff5fc46f, 1606794520) (Date:11/30/20)"
// - wasn't present in "OpenGL ES 3.2 V@0490.0 (GIT@0905e9f, Ia11ce2d146, 1599072951) (Date:09/02/20)"
// - has been confirmed fixed in V@570.1 by Qualcomm
if (driverMajor < 490 || driverMajor > 570 || (driverMajor == 570 && driverMinor >= 1)) {
bugs.invalidate_end_only_if_invalidate_start = false;
}
}
// qualcomm seems to have no problem with this (which is good for us)
bugs.allow_read_only_ancillary_feedback_loop = true;
} else if (strstr(renderer, "Mali")) {
bugs.vao_doesnt_store_element_array_buffer_binding = true;
if (strstr(renderer, "Mali-T")) {
bugs.disable_glFlush = true;
bugs.disable_shared_context_draws = true;
bugs.texture_external_needs_rebind = true;
// We have not verified that timer queries work on Mali-T, so we disable to be safe.
// On Adreno (As of 3/20) timer query seem to return the CPU time, not the GPU time.
bugs.dont_use_timer_query = true;
}
if (strstr(renderer, "Mali-G")) {
// note: We have verified that timer queries work well at least on some Mali-G.
}
// Mali seems to have no problem with this (which is good for us)
bugs.allow_read_only_ancillary_feedback_loop = true;
} else if (strstr(renderer, "Intel")) {
bugs.vao_doesnt_store_element_array_buffer_binding = true;
} else if (strstr(renderer, "PowerVR")) {
} else if (strstr(renderer, "Apple")) {
} else if (strstr(renderer, "Tegra") || strstr(renderer, "GeForce") || strstr(renderer, "NV")) {
} else if (strstr(renderer, "Vivante")) {
} else if (strstr(renderer, "AMD") || strstr(renderer, "ATI")) {
} else if (strstr(renderer, "Mozilla")) {
bugs.disable_invalidate_framebuffer = true;
// Blits to texture arrays are failing
// This bug continues to reproduce, though at times we've seen it appear to "go away".
// The standalone sample app that was written to show this problem still reproduces.
// The working hypthesis is that some other state affects this behavior.
bugs.disable_sidecar_blit_into_texture_array = true;
// early exit condition is flattened in EASU code
bugs.split_easu = true;
int maj, min, driverMajor, driverMinor;
int c = sscanf(state.version, "OpenGL ES %d.%d V@%d.%d", // NOLINT(cert-err34-c)
&maj, &min, &driverMajor, &driverMinor);
if (c == 4) {
// workarounds based on version here.
// notes:
// bugs.invalidate_end_only_if_invalidate_start
// - appeared at least in
// "OpenGL ES 3.2 V@0490.0 (GIT@85da404, I46ff5fc46f, 1606794520) (Date:11/30/20)"
// - wasn't present in
// "OpenGL ES 3.2 V@0490.0 (GIT@0905e9f, Ia11ce2d146, 1599072951) (Date:09/02/20)"
// - has been confirmed fixed in V@570.1 by Qualcomm
if (driverMajor < 490 || driverMajor > 570 ||
(driverMajor == 570 && driverMinor >= 1)) {
bugs.invalidate_end_only_if_invalidate_start = false;
}
}
// qualcomm seems to have no problem with this (which is good for us)
bugs.allow_read_only_ancillary_feedback_loop = true;
} else if (strstr(state.renderer, "Mali")) {
// ARM GPU
bugs.vao_doesnt_store_element_array_buffer_binding = true;
if (strstr(state.renderer, "Mali-T")) {
bugs.disable_glFlush = true;
bugs.disable_shared_context_draws = true;
bugs.texture_external_needs_rebind = true;
// We have not verified that timer queries work on Mali-T, so we disable to be safe.
bugs.dont_use_timer_query = true;
}
if (strstr(state.renderer, "Mali-G")) {
// note: We have verified that timer queries work well at least on some Mali-G.
}
// Mali seems to have no problem with this (which is good for us)
bugs.allow_read_only_ancillary_feedback_loop = true;
} else if (strstr(state.renderer, "Intel")) {
// Intel GPU
bugs.vao_doesnt_store_element_array_buffer_binding = true;
} else if (strstr(state.renderer, "PowerVR")) {
// PowerVR GPU
} else if (strstr(state.renderer, "Apple")) {
// Apple GPU
} else if (strstr(state.renderer, "Tegra") ||
strstr(state.renderer, "GeForce") ||
strstr(state.renderer, "NV")) {
// NVIDIA GPU
} else if (strstr(state.renderer, "Vivante")) {
// Vivante GPU
} else if (strstr(state.renderer, "AMD") ||
strstr(state.renderer, "ATI")) {
// AMD/ATI GPU
} else if (strstr(state.renderer, "Mozilla")) {
bugs.disable_invalidate_framebuffer = true;
}
} else {
// When running under ANGLE, it's a different set of workaround that we need.
if (strstr(state.renderer, "Adreno")) {
// Qualcomm GPU
// early exit condition is flattened in EASU code
// (that should be regardless of ANGLE, but we should double check)
bugs.split_easu = true;
}
// TODO: see if we could use `bugs.allow_read_only_ancillary_feedback_loop = true`
}
slog.v << "Active workarounds: " << '\n';
UTILS_NOUNROLL
for (auto [enabled, name, _] : mBugDatabase) {
if (enabled) {
slog.v << name << '\n';
@@ -186,7 +217,7 @@ OpenGLContext::OpenGLContext() noexcept {
// Point sprite size and seamless cubemap filtering are disabled by default in desktop GL.
// In OpenGL ES, these flags do not exist because they are always on.
#if GL41_HEADERS
#if BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GL
enable(GL_PROGRAM_POINT_SIZE);
#endif
@@ -219,50 +250,27 @@ OpenGLContext::OpenGLContext() noexcept {
if (ext.KHR_debug) {
auto cb = [](GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
const GLchar* message, const void *userParam) {
io::ostream* stream = nullptr;
io::ostream* stream = &slog.i;
switch (severity) {
case GL_DEBUG_SEVERITY_HIGH:
stream = &slog.e;
break;
case GL_DEBUG_SEVERITY_MEDIUM:
stream = &slog.w;
break;
case GL_DEBUG_SEVERITY_LOW:
stream = &slog.d;
break;
case GL_DEBUG_SEVERITY_HIGH: stream = &slog.e; break;
case GL_DEBUG_SEVERITY_MEDIUM: stream = &slog.w; break;
case GL_DEBUG_SEVERITY_LOW: stream = &slog.d; break;
case GL_DEBUG_SEVERITY_NOTIFICATION:
default:
stream = &slog.i;
break;
default: break;
}
io::ostream& out = *stream;
out << "KHR_debug ";
const char* level = ": ";
switch (type) {
case GL_DEBUG_TYPE_ERROR:
out << "ERROR";
break;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
out << "DEPRECATED_BEHAVIOR";
break;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
out << "UNDEFINED_BEHAVIOR";
break;
case GL_DEBUG_TYPE_PORTABILITY:
out << "PORTABILITY";
break;
case GL_DEBUG_TYPE_PERFORMANCE:
out << "PERFORMANCE";
break;
case GL_DEBUG_TYPE_OTHER:
out << "OTHER";
break;
case GL_DEBUG_TYPE_MARKER:
out << "MARKER";
break;
default:
break;
case GL_DEBUG_TYPE_ERROR: level = "ERROR: "; break;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: level = "DEPRECATED_BEHAVIOR: "; break;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: level = "UNDEFINED_BEHAVIOR: "; break;
case GL_DEBUG_TYPE_PORTABILITY: level = "PORTABILITY: "; break;
case GL_DEBUG_TYPE_PERFORMANCE: level = "PERFORMANCE: "; break;
case GL_DEBUG_TYPE_OTHER: level = "OTHER: "; break;
case GL_DEBUG_TYPE_MARKER: level = "MARKER: "; break;
default: break;
}
out << ": " << message << io::endl;
out << "KHR_debug " << level << message << io::endl;
};
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
@@ -277,60 +285,83 @@ OpenGLContext::OpenGLContext() noexcept {
#endif
}
UTILS_NOINLINE
bool OpenGLContext::hasExtension(ExtentionSet const& map, utils::StaticString ext) noexcept {
return map.find(ext) != map.end();
}
void OpenGLContext::initExtensionsGLES() noexcept {
const char * const extensions = (const char*)glGetString(GL_EXTENSIONS);
GLUtils::unordered_string_set exts = GLUtils::split(extensions);
if constexpr (DEBUG_PRINT_EXTENSIONS) {
for (auto extension: exts) {
slog.d << "\"" << std::string_view(extension) << "\"\n";
}
flush(slog.d);
}
void OpenGLContext::initExtensionsGLES(GLint major, GLint minor, ExtentionSet const& exts) {
// figure out and initialize the extensions we need
ext.APPLE_color_buffer_packed_float = hasExtension(exts, "GL_APPLE_color_buffer_packed_float");
ext.EXT_clip_control = hasExtension(exts, "GL_EXT_clip_control");
ext.EXT_color_buffer_float = hasExtension(exts, "GL_EXT_color_buffer_float");
ext.EXT_color_buffer_half_float = hasExtension(exts, "GL_EXT_color_buffer_half_float");
ext.EXT_debug_marker = hasExtension(exts, "GL_EXT_debug_marker");
ext.EXT_disjoint_timer_query = hasExtension(exts, "GL_EXT_disjoint_timer_query");
ext.EXT_multisampled_render_to_texture = hasExtension(exts, "GL_EXT_multisampled_render_to_texture");
ext.EXT_multisampled_render_to_texture2 = hasExtension(exts, "GL_EXT_multisampled_render_to_texture2");
ext.EXT_shader_framebuffer_fetch = hasExtension(exts, "GL_EXT_shader_framebuffer_fetch");
using namespace std::literals;
ext.APPLE_color_buffer_packed_float = exts.has("GL_APPLE_color_buffer_packed_float"sv);
ext.EXT_clip_control = exts.has("GL_EXT_clip_control"sv);
ext.EXT_color_buffer_float = exts.has("GL_EXT_color_buffer_float"sv);
ext.EXT_color_buffer_half_float = exts.has("GL_EXT_color_buffer_half_float"sv);
ext.EXT_debug_marker = exts.has("GL_EXT_debug_marker"sv);
ext.EXT_disjoint_timer_query = exts.has("GL_EXT_disjoint_timer_query"sv);
ext.EXT_multisampled_render_to_texture = exts.has("GL_EXT_multisampled_render_to_texture"sv);
ext.EXT_multisampled_render_to_texture2 = exts.has("GL_EXT_multisampled_render_to_texture2"sv);
ext.EXT_shader_framebuffer_fetch = exts.has("GL_EXT_shader_framebuffer_fetch"sv);
#if !defined(__EMSCRIPTEN__)
ext.EXT_texture_compression_etc2 = true;
ext.EXT_texture_filter_anisotropic = hasExtension(exts, "GL_EXT_texture_filter_anisotropic");
ext.GOOGLE_cpp_style_line_directive = hasExtension(exts, "GL_GOOGLE_cpp_style_line_directive");
ext.KHR_debug = hasExtension(exts, "GL_KHR_debug");
ext.OES_EGL_image_external_essl3 = hasExtension(exts, "GL_OES_EGL_image_external_essl3");
ext.QCOM_tiled_rendering = hasExtension(exts, "GL_QCOM_tiled_rendering");
ext.EXT_texture_compression_s3tc = hasExtension(exts, "GL_EXT_texture_compression_s3tc");
ext.EXT_texture_compression_s3tc_srgb = hasExtension(exts, "GL_EXT_texture_compression_s3tc_srgb");
ext.WEBGL_compressed_texture_s3tc = hasExtension(exts, "WEBGL_compressed_texture_s3tc");
ext.WEBGL_compressed_texture_s3tc_srgb = hasExtension(exts, "WEBGL_compressed_texture_s3tc_srgb");
ext.WEBGL_compressed_texture_etc = hasExtension(exts, "WEBGL_compressed_texture_etc");
#endif
ext.EXT_texture_filter_anisotropic = exts.has("GL_EXT_texture_filter_anisotropic"sv);
ext.GOOGLE_cpp_style_line_directive = exts.has("GL_GOOGLE_cpp_style_line_directive"sv);
ext.KHR_debug = exts.has("GL_KHR_debug"sv);
ext.OES_EGL_image_external_essl3 = exts.has("GL_OES_EGL_image_external_essl3"sv);
ext.QCOM_tiled_rendering = exts.has("GL_QCOM_tiled_rendering"sv);
ext.EXT_texture_compression_s3tc = exts.has("GL_EXT_texture_compression_s3tc"sv);
ext.EXT_texture_compression_s3tc_srgb = exts.has("GL_EXT_texture_compression_s3tc_srgb"sv);
ext.WEBGL_compressed_texture_s3tc = exts.has("WEBGL_compressed_texture_s3tc"sv);
ext.WEBGL_compressed_texture_s3tc_srgb = exts.has("WEBGL_compressed_texture_s3tc_srgb"sv);
ext.WEBGL_compressed_texture_etc = exts.has("WEBGL_compressed_texture_etc"sv);
// ES 3.2 implies EXT_color_buffer_float
if (major >= 3 && minor >= 2) {
if (state.major >= 3 && state.minor >= 2) {
ext.EXT_color_buffer_float = true;
}
}
void OpenGLContext::initExtensionsGL(GLint major, GLint minor, ExtentionSet const& exts) {
void OpenGLContext::initExtensionsGL() noexcept {
GLUtils::unordered_string_set exts;
GLint n = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &n);
for (GLint i = 0; i < n; i++) {
exts.emplace((const char*)glGetStringi(GL_EXTENSIONS, (GLuint)i));
}
if constexpr (DEBUG_PRINT_EXTENSIONS) {
for (auto extension: exts) {
slog.d << "\"" << std::string_view(extension) << "\"\n";
}
flush(slog.d);
}
using namespace std::literals;
auto major = state.major;
auto minor = state.minor;
ext.APPLE_color_buffer_packed_float = true; // Assumes core profile.
ext.ARB_shading_language_packing = hasExtension(exts, "GL_ARB_shading_language_packing") || (major == 4 && minor >= 2);
ext.EXT_clip_control = hasExtension(exts, "GL_ARB_clip_control") || (major == 4 && minor >= 5);
ext.ARB_shading_language_packing = exts.has("GL_ARB_shading_language_packing"sv) || (major == 4 && minor >= 2);
ext.EXT_clip_control = exts.has("GL_ARB_clip_control"sv) || (major == 4 && minor >= 5);
ext.EXT_color_buffer_float = true; // Assumes core profile.
ext.EXT_color_buffer_half_float = true; // Assumes core profile.
ext.EXT_debug_marker = hasExtension(exts, "GL_EXT_debug_marker");
ext.EXT_shader_framebuffer_fetch = hasExtension(exts, "GL_EXT_shader_framebuffer_fetch");
ext.EXT_texture_compression_etc2 = hasExtension(exts, "GL_ARB_ES3_compatibility");
ext.EXT_texture_filter_anisotropic = hasExtension(exts, "GL_EXT_texture_filter_anisotropic");
ext.EXT_texture_sRGB = hasExtension(exts, "GL_EXT_texture_sRGB");
ext.GOOGLE_cpp_style_line_directive = hasExtension(exts, "GL_GOOGLE_cpp_style_line_directive");
ext.EXT_debug_marker = exts.has("GL_EXT_debug_marker"sv);
ext.EXT_shader_framebuffer_fetch = exts.has("GL_EXT_shader_framebuffer_fetch"sv);
ext.EXT_texture_compression_etc2 = exts.has("GL_ARB_ES3_compatibility"sv);
ext.EXT_texture_filter_anisotropic = exts.has("GL_EXT_texture_filter_anisotropic"sv);
ext.EXT_texture_sRGB = exts.has("GL_EXT_texture_sRGB"sv);
ext.GOOGLE_cpp_style_line_directive = exts.has("GL_GOOGLE_cpp_style_line_directive"sv);
ext.KHR_debug = major >= 4 && minor >= 3;
ext.OES_EGL_image_external_essl3 = hasExtension(exts, "GL_OES_EGL_image_external_essl3");
ext.EXT_texture_compression_s3tc = hasExtension(exts, "GL_EXT_texture_compression_s3tc");
ext.EXT_texture_compression_s3tc_srgb = hasExtension(exts, "GL_EXT_texture_compression_s3tc_srgb");
ext.OES_EGL_image_external_essl3 = exts.has("GL_OES_EGL_image_external_essl3"sv);
ext.EXT_texture_compression_s3tc = exts.has("GL_EXT_texture_compression_s3tc"sv);
ext.EXT_texture_compression_s3tc_srgb = exts.has("GL_EXT_texture_compression_s3tc_srgb"sv);
}
void OpenGLContext::bindBuffer(GLenum target, GLuint buffer) noexcept {
size_t targetIndex = getIndexForBufferTarget(target);
if (target == GL_ELEMENT_ARRAY_BUFFER) {
constexpr size_t targetIndex = getIndexForBufferTarget(GL_ELEMENT_ARRAY_BUFFER);
// GL_ELEMENT_ARRAY_BUFFER is a special case, where the currently bound VAO remembers
// the index buffer, unless there are no VAO bound (see: bindVertexArray)
assert_invariant(state.vao.p);
@@ -343,6 +374,7 @@ void OpenGLContext::bindBuffer(GLenum target, GLuint buffer) noexcept {
glBindBuffer(target, buffer);
}
} else {
size_t targetIndex = getIndexForBufferTarget(target);
update_state(state.buffers.genericBinding[targetIndex], buffer, [&]() {
glBindBuffer(target, buffer);
});
@@ -350,33 +382,22 @@ void OpenGLContext::bindBuffer(GLenum target, GLuint buffer) noexcept {
}
void OpenGLContext::pixelStore(GLenum pname, GLint param) noexcept {
GLint* pcur = nullptr;
switch (pname) {
case GL_PACK_ROW_LENGTH:
pcur = &state.pack.row_length;
break;
case GL_PACK_SKIP_ROWS:
pcur = &state.pack.skip_row;
break;
case GL_PACK_SKIP_PIXELS:
pcur = &state.pack.skip_pixels;
break;
case GL_PACK_ALIGNMENT:
pcur = &state.pack.alignment;
break;
GLint* pcur;
case GL_UNPACK_ROW_LENGTH:
pcur = &state.unpack.row_length;
break;
case GL_UNPACK_ALIGNMENT:
pcur = &state.unpack.alignment;
break;
case GL_UNPACK_SKIP_PIXELS:
pcur = &state.unpack.skip_pixels;
break;
case GL_UNPACK_SKIP_ROWS:
pcur = &state.unpack.skip_row;
break;
// Note: GL_UNPACK_SKIP_PIXELS, GL_UNPACK_SKIP_ROWS and
// GL_PACK_SKIP_PIXELS, GL_PACK_SKIP_ROWS
// are actually provided as conveniences to the programmer; they provide no functionality
// that cannot be duplicated at the call site (e.g. glTexImage2D or glReadPixels)
switch (pname) {
case GL_PACK_ALIGNMENT: pcur = &state.pack.alignment; break;
case GL_PACK_ROW_LENGTH: pcur = &state.pack.row_length; break;
case GL_PACK_SKIP_PIXELS: pcur = &state.pack.skip_pixels; break; // convenience
case GL_PACK_SKIP_ROWS: pcur = &state.pack.skip_row; break; // convenience
case GL_UNPACK_ALIGNMENT: pcur = &state.unpack.alignment; break;
case GL_UNPACK_ROW_LENGTH: pcur = &state.unpack.row_length; break;
case GL_UNPACK_SKIP_PIXELS: pcur = &state.unpack.skip_pixels; break; // convenience
case GL_UNPACK_SKIP_ROWS: pcur = &state.unpack.skip_row; break; // convenience
default:
goto default_case;
}
@@ -393,6 +414,7 @@ void OpenGLContext::unbindTexture(GLenum target, GLuint texture_id) noexcept {
// no need unbind the texture from FBOs because we're not tracking that state (and there is
// no need to).
const size_t index = getIndexForTextureTarget(target);
UTILS_NOUNROLL
for (GLuint unit = 0; unit < MAX_TEXTURE_UNIT_COUNT; unit++) {
if (state.textures.units[unit].targets[index].texture_id == texture_id) {
bindTexture(unit, target, (GLuint)0, index);
@@ -402,7 +424,7 @@ void OpenGLContext::unbindTexture(GLenum target, GLuint texture_id) noexcept {
void OpenGLContext::unbindSampler(GLuint sampler) noexcept {
// unbind this sampler from all the units it might be bound to
#pragma nounroll // clang generates >800B of code!!!
UTILS_NOUNROLL // clang generates >800B of code!!!
for (GLuint unit = 0; unit < MAX_TEXTURE_UNIT_COUNT; unit++) {
if (state.textures.units[unit].sampler == sampler) {
bindSampler(unit, 0);
@@ -415,7 +437,7 @@ void OpenGLContext::deleteBuffers(GLsizei n, const GLuint* buffers, GLenum targe
// bindings of bound buffers are reset to 0
const size_t targetIndex = getIndexForBufferTarget(target);
auto& genericBuffer = state.buffers.genericBinding[targetIndex];
#pragma nounroll
UTILS_NOUNROLL
for (GLsizei i = 0; i < n; ++i) {
if (genericBuffer == buffers[i]) {
genericBuffer = 0;
@@ -423,9 +445,9 @@ void OpenGLContext::deleteBuffers(GLsizei n, const GLuint* buffers, GLenum targe
}
if (target == GL_UNIFORM_BUFFER || target == GL_TRANSFORM_FEEDBACK_BUFFER) {
auto& indexedBuffer = state.buffers.targets[targetIndex];
#pragma nounroll // clang generates >1 KiB of code!!
UTILS_NOUNROLL // clang generates >1 KiB of code!!
for (GLsizei i = 0; i < n; ++i) {
#pragma nounroll
UTILS_NOUNROLL
for (auto& buffer : indexedBuffer.buffers) {
if (buffer.name == buffers[i]) {
buffer.name = 0;
+44 -34
View File
@@ -39,32 +39,31 @@ public:
typedef math::details::TVec4<GLint> vec4gli;
typedef math::details::TVec2<GLclampf> vec2glf;
// TODO: the footprint of this structure can be reduced. We need only 1 bit for index type, 16
// bits for vertexAttribArray. We can also use fewer bits for vertexBufferVersion, although
// this will require a corollary update in OpenGLDriver::setVertexBufferObject().
struct RenderPrimitive {
GLuint vao = 0;
GLenum indicesType = GL_UNSIGNED_INT;
GLuint elementArray = 0;
utils::bitset32 vertexAttribArray;
static_assert(MAX_VERTEX_ATTRIBUTE_COUNT <= 16);
GLuint vao = 0; // 4
GLuint elementArray = 0; // 4
utils::bitset<uint16_t> vertexAttribArray; // 2
// If this version number does not match vertexBufferWithObjects->bufferObjectsVersion,
// then the VAO needs to be updated.
uint8_t vertexBufferVersion = 0; // 1
uint8_t indicesSize = 0; // 1
// The optional 32-bit handle to a GLVertexBuffer is necessary only if the referenced
// VertexBuffer supports buffer objects. If this is zero, then the VBO handles array is
// immutable.
Handle<HwVertexBuffer> vertexBufferWithObjects = {};
Handle<HwVertexBuffer> vertexBufferWithObjects = {}; // 4
// If this version number does not match vertexBufferWithObjects->bufferObjectsVersion,
// then the VAO needs to be updated.
uint8_t vertexBufferVersion = 0;
GLenum getIndicesType() const noexcept {
return indicesSize == 4 ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
}
} gl;
OpenGLContext() noexcept;
static bool queryOpenGLVersion(GLint* major, GLint* minor) noexcept;
// this is chosen to minimize code size
using ExtentionSet = std::set<utils::StaticString>;
static bool hasExtension(ExtentionSet const& exts, utils::StaticString ext) noexcept;
void initExtensionsGLES(GLint major, GLint minor, ExtentionSet const& extensionsMap);
void initExtensionsGL(GLint major, GLint minor, ExtentionSet const& extensionsMap);
OpenGLContext() noexcept;
constexpr static inline size_t getIndexForTextureTarget(GLuint target) noexcept;
constexpr inline size_t getIndexForCap(GLenum cap) noexcept;
@@ -105,7 +104,7 @@ public:
inline void polygonOffset(GLfloat factor, GLfloat units) noexcept;
inline void beginQuery(GLenum target, GLuint query) noexcept;
inline void endQuery(GLenum target) noexcept;
inline GLuint getQuery(GLenum target) noexcept;
inline GLuint getQuery(GLenum target) const noexcept;
inline void setScissor(GLint left, GLint bottom, GLsizei width, GLsizei height) noexcept;
inline void viewport(GLint left, GLint bottom, GLsizei width, GLsizei height) noexcept;
@@ -205,6 +204,19 @@ public:
bool allow_read_only_ancillary_feedback_loop = false;
} bugs;
// state getters -- as needed.
vec4gli const& getViewport() const { return state.window.viewport; }
// function to handle state changes we don't control
void updateTexImage(GLenum target, GLuint id) noexcept {
const size_t index = getIndexForTextureTarget(target);
state.textures.units[state.textures.active].targets[index].texture_id = id;
}
void resetProgram() noexcept { state.program.use = 0; }
private:
ShaderModel mShaderModel = ShaderModel::UNKNOWN;
const std::array<std::tuple<bool const&, char const*, char const*>, sizeof(bugs)> mBugDatabase{{
{ bugs.disable_glFlush,
"disable_glFlush",
@@ -244,22 +256,16 @@ public:
""},
}};
// state getters -- as needed.
GLuint getDrawFbo() const noexcept { return state.draw_fbo; }
vec4gli const& getViewport() const { return state.window.viewport; }
// function to handle state changes we don't control
void updateTexImage(GLenum target, GLuint id) noexcept {
const size_t index = getIndexForTextureTarget(target);
state.textures.units[state.textures.active].targets[index].texture_id = id;
}
void resetProgram() noexcept { state.program.use = 0; }
private:
ShaderModel mShaderModel;
// Try to keep the State structure sorted by data-access patterns
struct State {
GLint major = 0;
GLint minor = 0;
char const* vendor = nullptr;
char const* renderer = nullptr;
char const* version = nullptr;
char const* shader = nullptr;
GLuint draw_fbo = 0;
GLuint read_fbo = 0;
@@ -345,6 +351,10 @@ private:
RenderPrimitive mDefaultVAO;
// this is chosen to minimize code size
void initExtensionsGLES() noexcept;
void initExtensionsGL() noexcept;
template <typename T, typename F>
static inline void update_state(T& state, T const& expected, F functor, bool force = false) noexcept {
if (UTILS_UNLIKELY(force || state != expected)) {
@@ -390,7 +400,7 @@ constexpr size_t OpenGLContext::getIndexForCap(GLenum cap) noexcept { //NOLINT
#ifdef GL_ARB_seamless_cube_map
case GL_TEXTURE_CUBE_MAP_SEAMLESS: index = 11; break;
#endif
#if GL41_HEADERS
#if BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GL
case GL_PROGRAM_POINT_SIZE: index = 12; break;
#endif
default: index = 13; break; // should never happen
@@ -661,7 +671,7 @@ void OpenGLContext::endQuery(GLenum target) noexcept {
glEndQuery(target);
}
GLuint OpenGLContext::getQuery(GLenum target) noexcept {
GLuint OpenGLContext::getQuery(GLenum target) const noexcept {
switch (target) {
case GL_TIME_ELAPSED:
return state.queries.timer;
+41 -271
View File
@@ -20,7 +20,6 @@
#include "private/backend/OpenGLPlatform.h"
#include "CommandStreamDispatcher.h"
#include "OpenGLBlitter.h"
#include "OpenGLDriverFactory.h"
#include "OpenGLProgram.h"
#include "OpenGLTimerQuery.h"
@@ -53,7 +52,7 @@
#if DEBUG_MARKER_LEVEL == DEBUG_MARKER_OPENGL
# define DEBUG_MARKER() \
DebugMarker _debug_marker(*this, __PRETTY_FUNCTION__);
DebugMarker _debug_marker(*this, __func__);
#else
# define DEBUG_MARKER()
#endif
@@ -115,23 +114,21 @@ Driver* OpenGLDriver::create(
// here we check we're on a supported version of GL before initializing the driver
GLint major = 0, minor = 0;
glGetIntegerv(GL_MAJOR_VERSION, &major);
glGetIntegerv(GL_MINOR_VERSION, &minor);
bool success = OpenGLContext::queryOpenGLVersion(&major, &minor);
if (UTILS_UNLIKELY(glGetError() != GL_NO_ERROR)) {
if (UTILS_UNLIKELY(!success)) {
PANIC_LOG("Can't get OpenGL version");
cleanup:
ec->terminate();
return {};
}
if (GLES30_HEADERS) {
// we require GLES 3.1 headers, but we support GLES 3.0
if constexpr (BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GLES) {
if (UTILS_UNLIKELY(!(major >= 3 && minor >= 0))) {
PANIC_LOG("OpenGL ES 3.0 minimum needed (current %d.%d)", major, minor);
goto cleanup;
}
} else if (GL41_HEADERS) {
} else if constexpr (BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GL) {
// we require GL 4.1 headers and minimum version
if (UTILS_UNLIKELY(!((major == 4 && minor >= 1) || major > 4))) {
PANIC_LOG("OpenGL 4.1 minimum needed (current %d.%d)", major, minor);
@@ -147,10 +144,7 @@ Driver* OpenGLDriver::create(
OpenGLDriver::DebugMarker::DebugMarker(OpenGLDriver& driver, const char* string) noexcept
: driver(driver) {
// FIXME: this is not safe nor portable
const char* const begin = string + sizeof("virtual void filament::backend::OpenGLDriver::") - 1;
const char* const end = strchr(begin, '(');
driver.pushGroupMarker(begin, end - begin);
driver.pushGroupMarker(string, strlen(string));
}
OpenGLDriver::DebugMarker::~DebugMarker() noexcept {
@@ -160,8 +154,7 @@ OpenGLDriver::DebugMarker::~DebugMarker() noexcept {
// ------------------------------------------------------------------------------------------------
OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform) noexcept
: DriverBase(new ConcreteDispatcher<OpenGLDriver>()),
mHandleAllocator("Handles", FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U), // TODO: set the amount in configuration
: mHandleAllocator("Handles", FILAMENT_OPENGL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U), // TODO: set the amount in configuration
mSamplerMap(32),
mPlatform(*platform) {
@@ -174,14 +167,8 @@ OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform) noexcept
slog.i << "OS version: " << mPlatform.getOSVersion() << io::endl;
#endif
// Initialize the blitter only if we have OES_EGL_image_external_essl3
if (mContext.ext.OES_EGL_image_external_essl3) {
mOpenGLBlitter = new OpenGLBlitter(mContext);
mOpenGLBlitter->init();
mContext.resetProgram();
}
if (mContext.ext.EXT_disjoint_timer_query || GL41_HEADERS) {
if (mContext.ext.EXT_disjoint_timer_query ||
BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GL) {
// timer queries are available
if (mContext.bugs.dont_use_timer_query && mPlatform.canCreateFence()) {
// however, they don't work well, revert to using fences if we can.
@@ -202,7 +189,10 @@ OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform) noexcept
}
OpenGLDriver::~OpenGLDriver() noexcept {
delete mOpenGLBlitter;
}
Dispatcher OpenGLDriver::getDispatcher() const noexcept {
return ConcreteDispatcher<OpenGLDriver>::make();
}
// ------------------------------------------------------------------------------------------------
@@ -224,9 +214,6 @@ void OpenGLDriver::terminate() {
glDeleteSamplers(1, &item.second);
}
mSamplerMap.clear();
if (mOpenGLBlitter) {
mOpenGLBlitter->terminate();
}
delete mTimerQueryImpl;
@@ -382,10 +369,6 @@ Handle<HwSwapChain> OpenGLDriver::createSwapChainHeadlessS() noexcept {
return initHandle<HwSwapChain>();
}
Handle<HwStream> OpenGLDriver::createStreamFromTextureIdS() noexcept {
return initHandle<GLStream>();
}
Handle<HwTimerQuery> OpenGLDriver::createTimerQueryS() noexcept {
return initHandle<GLTimerQuery>();
}
@@ -478,14 +461,14 @@ void OpenGLDriver::textureStorage(OpenGLDriver::GLTexture* t,
break;
}
case GL_TEXTURE_2D_MULTISAMPLE:
if (TEXTURE_2D_MULTISAMPLE_SUPPORTED) {
if constexpr (TEXTURE_2D_MULTISAMPLE_SUPPORTED) {
// NOTE: if there is a mix of texture and renderbuffers, "fixed_sample_locations" must be true
// NOTE: what's the benefit of setting "fixed_sample_locations" to false?
#if GLES31_HEADERS
// only supported from GL 4.3 and GLES 3.1
#if BACKEND_OPENGL_LEVEL >= BACKEND_OPENGL_LEVEL_GLES31
// only supported from GL 4.3 and GLES 3.1 headers
glTexStorage2DMultisample(t->gl.target, t->samples, t->gl.internalFormat,
GLsizei(width), GLsizei(height), GL_TRUE);
#elif GL41_HEADERS
#elif defined(GL_VERSION_4_1)
// only supported in GL (GL4.1 doesn't support glTexStorage2DMultisample)
glTexImage2DMultisample(t->gl.target, t->samples, t->gl.internalFormat,
GLsizei(width), GLsizei(height), GL_TRUE);
@@ -1138,24 +1121,6 @@ void OpenGLDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch,
sc->swapChain = mPlatform.createSwapChain(width, height, flags);
}
void OpenGLDriver::createStreamFromTextureIdR(Handle<HwStream> sh,
intptr_t externalTextureId, uint32_t width, uint32_t height) {
DEBUG_MARKER()
GLStream* s = handle_cast<GLStream*>(sh);
// It would be better if we could query the externalTextureId size, unfortunately
// this is not supported in GL for GL_TEXTURE_EXTERNAL_OES targets
s->width = width;
s->height = height;
s->gl.externalTextureId = static_cast<GLuint>(externalTextureId);
s->streamType = StreamType::TEXTURE_ID;
glGenTextures(GLStream::ROUND_ROBIN_TEXTURE_COUNT, s->user_thread.read);
glGenTextures(GLStream::ROUND_ROBIN_TEXTURE_COUNT, s->user_thread.write);
for (auto& info : s->user_thread.infos) {
info.ets = mPlatform.createExternalTextureStorage();
}
}
void OpenGLDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
DEBUG_MARKER()
@@ -1302,15 +1267,6 @@ void OpenGLDriver::destroyStream(Handle<HwStream> sh) {
}
if (s->streamType == StreamType::NATIVE) {
mPlatform.destroyStream(s->stream);
} else if (s->streamType == StreamType::TEXTURE_ID) {
glDeleteTextures(GLStream::ROUND_ROBIN_TEXTURE_COUNT, s->user_thread.read);
glDeleteTextures(GLStream::ROUND_ROBIN_TEXTURE_COUNT, s->user_thread.write);
if (s->gl.fbo) {
glDeleteFramebuffers(1, &s->gl.fbo);
}
for (auto const& info : s->user_thread.infos) {
mPlatform.destroyExternalTextureStorage(info.ets);
}
}
destruct(sh, s);
}
@@ -1369,7 +1325,6 @@ void OpenGLDriver::setAcquiredImage(Handle<HwStream> sh, void* hwbuffer,
void OpenGLDriver::updateStreams(DriverApi* driver) {
if (UTILS_UNLIKELY(!mExternalStreams.empty())) {
OpenGLBlitter::State state;
for (GLTexture* t : mExternalStreams) {
assert_invariant(t);
@@ -1380,11 +1335,6 @@ void OpenGLDriver::updateStreams(DriverApi* driver) {
continue;
}
if (s->streamType == StreamType::TEXTURE_ID) {
state.setup();
updateStreamTexId(t, driver);
}
if (s->streamType == StreamType::ACQUIRED) {
updateStreamAcquired(t, driver);
}
@@ -1512,7 +1462,7 @@ bool OpenGLDriver::isRenderTargetFormatSupported(TextureFormat format) {
// Three-component SRGB is a color-renderable texture format in core OpenGL on desktop.
case TextureFormat::SRGB8:
return GL41_HEADERS;
return BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GL;
// Half-float formats, requires extension.
case TextureFormat::R16F:
@@ -1851,7 +1801,6 @@ void OpenGLDriver::setTextureData(GLTexture* t,
uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
uint32_t width, uint32_t height, uint32_t depth,
PixelBufferDescriptor&& p, FaceOffsets const* faceOffsets) {
DEBUG_MARKER()
auto& gl = mContext;
assert_invariant(xoffset + width <= std::max(1u, t->width >> level));
@@ -1941,7 +1890,6 @@ void OpenGLDriver::setCompressedTextureData(GLTexture* t, uint32_t level,
uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
uint32_t width, uint32_t height, uint32_t depth,
PixelBufferDescriptor&& p, FaceOffsets const* faceOffsets) {
DEBUG_MARKER()
auto& gl = mContext;
assert_invariant(xoffset + width <= std::max(1u, t->width >> level));
@@ -2031,11 +1979,13 @@ void OpenGLDriver::cancelExternalImage(void* image) {
}
void OpenGLDriver::setExternalImage(Handle<HwTexture> th, void* image) {
DEBUG_MARKER()
mPlatform.setExternalImage(image, handle_cast<GLTexture*>(th));
setExternalTexture(handle_cast<GLTexture*>(th), image);
}
void OpenGLDriver::setExternalImagePlane(Handle<HwTexture> th, void* image, uint32_t plane) {
DEBUG_MARKER()
}
void OpenGLDriver::setExternalTexture(GLTexture* t, void* image) {
@@ -2043,8 +1993,6 @@ void OpenGLDriver::setExternalTexture(GLTexture* t, void* image) {
// TODO: move this logic to PlatformEGL.
if (gl.ext.OES_EGL_image_external_essl3) {
DEBUG_MARKER()
assert_invariant(t->target == SamplerType::SAMPLER_EXTERNAL);
assert_invariant(t->gl.target == GL_TEXTURE_EXTERNAL_OES);
@@ -2083,20 +2031,12 @@ void OpenGLDriver::setExternalStream(Handle<HwTexture> th, Handle<HwStream> sh)
UTILS_NOINLINE
void OpenGLDriver::attachStream(GLTexture* t, GLStream* hwStream) noexcept {
auto& gl = mContext;
mExternalStreams.push_back(t);
switch (hwStream->streamType) {
case StreamType::NATIVE:
mPlatform.attach(hwStream->stream, t->gl.id);
break;
case StreamType::TEXTURE_ID:
assert_invariant(t->target == SamplerType::SAMPLER_EXTERNAL);
// The texture doesn't need a texture name anymore, get rid of it
gl.unbindTexture(t->gl.target, t->gl.id);
glDeleteTextures(1, &t->gl.id);
t->gl.id = hwStream->user_thread.read[hwStream->user_thread.cur];
break;
case StreamType::ACQUIRED:
break;
}
@@ -2118,8 +2058,6 @@ void OpenGLDriver::detachStream(GLTexture* t) noexcept {
mPlatform.detach(t->hwStream->stream);
// ^ this deletes the texture id
break;
case StreamType::TEXTURE_ID:
break;
case StreamType::ACQUIRED:
gl.unbindTexture(t->gl.target, t->gl.id);
glDeleteTextures(1, &t->gl.id);
@@ -2144,7 +2082,6 @@ void OpenGLDriver::replaceStream(GLTexture* texture, GLStream* newStream) noexce
mPlatform.detach(texture->hwStream->stream);
// ^ this deletes the texture id
break;
case StreamType::TEXTURE_ID:
case StreamType::ACQUIRED:
break;
}
@@ -2154,10 +2091,6 @@ void OpenGLDriver::replaceStream(GLTexture* texture, GLStream* newStream) noexce
glGenTextures(1, &texture->gl.id);
mPlatform.attach(newStream->stream, texture->gl.id);
break;
case StreamType::TEXTURE_ID:
assert_invariant(texture->target == SamplerType::SAMPLER_EXTERNAL);
texture->gl.id = newStream->user_thread.read[newStream->user_thread.cur];
break;
case StreamType::ACQUIRED:
// Just re-use the old texture id.
break;
@@ -2167,6 +2100,7 @@ void OpenGLDriver::replaceStream(GLTexture* texture, GLStream* newStream) noexce
}
void OpenGLDriver::beginTimerQuery(Handle<HwTimerQuery> tqh) {
DEBUG_MARKER()
GLTimerQuery* tq = handle_cast<GLTimerQuery*>(tqh);
// reset the state of the result availability
tq->elapsed.store(0, std::memory_order_relaxed);
@@ -2174,6 +2108,7 @@ void OpenGLDriver::beginTimerQuery(Handle<HwTimerQuery> tqh) {
}
void OpenGLDriver::endTimerQuery(Handle<HwTimerQuery> tqh) {
DEBUG_MARKER()
GLTimerQuery* tq = handle_cast<GLTimerQuery*>(tqh);
mTimerQueryImpl->endTimeElapsedQuery(tq);
@@ -2238,7 +2173,8 @@ void OpenGLDriver::beginRenderPass(Handle<HwRenderTarget> rth,
// glInvalidateFramebuffer appeared on GLES 3.0 and GL4.3, for simplicity we just
// ignore it on GL (rather than having to do a runtime check).
if (GLES30_HEADERS) {
if (BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GLES &&
BACKEND_OPENGL_LEVEL >= BACKEND_OPENGL_LEVEL_GLES30) {
if (!gl.bugs.disable_invalidate_framebuffer) {
AttachmentArray attachments; // NOLINT
GLsizei attachmentCount = getAttachments(attachments, rt, discardFlags);
@@ -2312,7 +2248,8 @@ void OpenGLDriver::endRenderPass(int) {
// glInvalidateFramebuffer appeared on GLES 3.0 and GL4.3, for simplicity we just
// ignore it on GL (rather than having to do a runtime check).
if (GLES30_HEADERS) {
if (BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GLES &&
BACKEND_OPENGL_LEVEL >= BACKEND_OPENGL_LEVEL_GLES30) {
auto effectiveDiscardFlags = discardFlags;
if (gl.bugs.invalidate_end_only_if_invalidate_start) {
effectiveDiscardFlags &= mRenderPassParams.flags.discardStart;
@@ -2436,7 +2373,7 @@ void OpenGLDriver::setRenderPrimitiveBuffer(Handle<HwRenderPrimitive> rph,
gl.bindVertexArray(&rp->gl);
CHECK_GL_ERROR(utils::slog.e)
rp->gl.indicesType = ib->elementSize == 4 ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT;
rp->gl.indicesSize = (ib->elementSize == 4u) ? 4u : 2u;
rp->gl.vertexBufferWithObjects = vbh;
// update the VBO bindings in the VAO
@@ -2456,7 +2393,7 @@ void OpenGLDriver::setRenderPrimitiveRange(Handle<HwRenderPrimitive> rph,
GLRenderPrimitive* const rp = handle_cast<GLRenderPrimitive*>(rph);
rp->type = pt;
rp->offset = offset * ((rp->gl.indicesType == GL_UNSIGNED_INT) ? 4 : 2);
rp->offset = offset * rp->gl.indicesSize;
rp->count = count;
rp->minIndex = minIndex;
rp->maxIndex = maxIndex > minIndex ? maxIndex : rp->maxVertexCount - 1; // sanitize max index
@@ -2464,7 +2401,6 @@ void OpenGLDriver::setRenderPrimitiveRange(Handle<HwRenderPrimitive> rph,
// Sets up a scissor rectangle that automatically gets clipped against the viewport.
void OpenGLDriver::setViewportScissor(Viewport const& viewportScissor) noexcept {
DEBUG_MARKER()
auto& gl = mContext;
// In OpenGL, all four scissor parameters are actually signed, so clamp to MAX_INT32.
@@ -2524,179 +2460,6 @@ void OpenGLDriver::updateStreamAcquired(GLTexture* gltexture, DriverApi* driver)
});
}
#define DEBUG_NO_EXTERNAL_STREAM_COPY false
void OpenGLDriver::updateStreamTexId(GLTexture* t, DriverApi* driver) noexcept {
SYSTRACE_CALL();
auto& gl = mContext;
GLStream* s = static_cast<GLStream*>(t->hwStream);
assert_invariant(s);
assert_invariant(s->streamType == StreamType::TEXTURE_ID);
// round-robin to the next texture name
if (UTILS_UNLIKELY(DEBUG_NO_EXTERNAL_STREAM_COPY ||
gl.bugs.disable_shared_context_draws || !mOpenGLBlitter)) {
driver->queueCommand([this, t, s]() {
// the stream may have been destroyed since we enqueued the command
// also make sure that this texture is still associated with the same stream
auto& streams = mExternalStreams;
if (UTILS_LIKELY(std::find(streams.begin(), streams.end(), t) != streams.end()) &&
(t->hwStream == s)) {
t->gl.id = s->gl.externalTextureId;
}
});
} else {
s->user_thread.cur = uint8_t(
(s->user_thread.cur + 1) % GLStream::ROUND_ROBIN_TEXTURE_COUNT);
GLuint writeTexture = s->user_thread.write[s->user_thread.cur];
GLuint readTexture = s->user_thread.read[s->user_thread.cur];
// Make sure we're using the proper size
GLStream::Info& info = s->user_thread.infos[s->user_thread.cur];
if (UTILS_UNLIKELY(info.width != s->width || info.height != s->height)) {
// nothing guarantees that this buffer is free (i.e. has been consumed by the
// GL thread), so we could potentially cause a glitch by reallocating the
// texture here. This should be very rare though.
// This could be fixed by always using a new temporary texture here, and
// replacing it in the queueCommand() below. imho, not worth it.
info.width = s->width;
info.height = s->height;
Platform::ExternalTexture* ets = s->user_thread.infos[s->user_thread.cur].ets;
mPlatform.reallocateExternalStorage(ets, info.width, info.height, TextureFormat::RGB8);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, writeTexture);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, readTexture);
#ifdef GL_OES_EGL_image
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)ets->image);
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)ets->image);
#endif
}
// copy the texture...
#ifndef NDEBUG
if (t->gl.fence) {
// we're about to overwrite a buffer that hasn't been consumed
slog.d << "OpenGLDriver::updateStream(): about to overwrite buffer " <<
int(s->user_thread.cur) << " of Texture at " << t << " of Stream at " << s
<< io::endl;
}
#endif
mOpenGLBlitter->blit(s->gl.externalTextureId, writeTexture, s->width, s->height);
// We need a fence to guarantee that this copy has happened when we need the texture
// in OpenGLProgram::updateSamplers(), i.e. when we bind textures just before use.
GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
// Per https://www.khronos.org/opengl/wiki/Sync_Object, flush to make sure that the
// sync object is in the driver's command queue.
glFlush();
// Update the stream timestamp. It's not clear to me that this is correct; which
// timestamp do we really want? Here we use "now" because we have nothing else we
// can use.
s->user_thread.timestamp = std::chrono::steady_clock::now().time_since_epoch().count();
driver->queueCommand([this, t, s, fence, readTexture, writeTexture]() {
// the stream may have been destroyed since we enqueued the command
// also make sure that this texture is still associated with the same stream
auto& streams = mExternalStreams;
if (UTILS_LIKELY(std::find(streams.begin(), streams.end(), t) != streams.end()) &&
(t->hwStream == s)) {
if (UTILS_UNLIKELY(t->gl.fence)) {
// if the texture still has a fence set, destroy it now, so it's not leaked.
glDeleteSync(t->gl.fence);
}
t->gl.id = readTexture;
t->gl.fence = fence;
s->gl.externalTexture2DId = writeTexture;
} else {
glDeleteSync(fence);
}
});
}
}
void OpenGLDriver::readStreamPixels(Handle<HwStream> sh,
uint32_t x, uint32_t y, uint32_t width, uint32_t height,
PixelBufferDescriptor&& p) {
DEBUG_MARKER()
auto& gl = mContext;
GLStream* s = handle_cast<GLStream*>(sh);
if (UTILS_UNLIKELY(s->streamType == StreamType::ACQUIRED)) {
PANIC_LOG("readStreamPixels with ACQUIRED streams is not yet implemented.");
return;
}
if (UTILS_LIKELY(s->streamType == StreamType::TEXTURE_ID)) {
GLuint tid = s->gl.externalTexture2DId;
if (tid == 0) {
return;
}
GLenum glFormat = getFormat(p.format);
GLenum glType = getType(p.type);
gl.pixelStore(GL_PACK_ROW_LENGTH, p.stride);
gl.pixelStore(GL_PACK_ALIGNMENT, p.alignment);
gl.pixelStore(GL_PACK_SKIP_PIXELS, p.left);
gl.pixelStore(GL_PACK_SKIP_ROWS, p.top);
if (s->gl.fbo == 0) {
glGenFramebuffers(1, &s->gl.fbo);
}
gl.bindFramebuffer(GL_FRAMEBUFFER, s->gl.fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tid, 0);
CHECK_GL_ERROR(utils::slog.e)
/*
* It looks like glReadPixels() behaves differently, or even wrongly,
* when the FBO is backed by an EXTERNAL texture...
*
*
* External texture FBO User buffer
*
* O---+----------------+
* | | | .stride .alignment
* | | | ----------------------->-->
* | | y | O----------------------+--+ low adresses
* | | | | | | |
* | | w | | | .bottom | |
* | V <---------> | | V | |
* | +---------+ | | +---------+ | |
* | | ^ | | ======> | | | | |
* | x | h| | | |.left| | | |
* +------>| v | | +---->| | | |
* | +.........+ | | +.........+ | |
* | | | | |
* | | +----------------------+--+ high adresses
* +--------------------+
*
* Origin is at the The image is NOT y-reversed
* top-left corner and bottom is counted from
* the top! "bottom" is in fact treated
* as "top".
*/
// The filament API provides yoffset as the "bottom" offset, therefore it needs to
// be corrected to match glReadPixels()'s behavior.
y = (s->height - height) - y;
// TODO: we could use a PBO to make this asynchronous
glReadPixels(GLint(x), GLint(y), GLint(width), GLint(height), glFormat, glType, p.buffer);
CHECK_GL_ERROR(utils::slog.e)
gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
scheduleDestroy(std::move(p));
}
}
// ------------------------------------------------------------------------------------------------
// Setting rendering state
// ------------------------------------------------------------------------------------------------
@@ -2952,11 +2715,13 @@ void OpenGLDriver::executeRenderPassOps() noexcept {
// ------------------------------------------------------------------------------------------------
void OpenGLDriver::tick(int) {
DEBUG_MARKER()
executeGpuCommandsCompleteOps();
executeEveryNowAndThenOps();
}
void OpenGLDriver::beginFrame(int64_t monotonic_clock_ns, uint32_t frameId) {
DEBUG_MARKER()
auto& gl = mContext;
insertEventMarker("beginFrame");
if (UTILS_UNLIKELY(!mExternalStreams.empty())) {
@@ -2976,20 +2741,21 @@ void OpenGLDriver::beginFrame(int64_t monotonic_clock_ns, uint32_t frameId) {
void OpenGLDriver::setFrameScheduledCallback(Handle<HwSwapChain> sch,
FrameScheduledCallback callback, void* user) {
DEBUG_MARKER()
}
void OpenGLDriver::setFrameCompletedCallback(Handle<HwSwapChain> sch,
FrameCompletedCallback callback, void* user) {
DEBUG_MARKER()
}
void OpenGLDriver::setPresentationTime(int64_t monotonic_clock_ns) {
DEBUG_MARKER()
mPlatform.setPresentationTime(monotonic_clock_ns);
}
void OpenGLDriver::endFrame(uint32_t frameId) {
//SYSTRACE_NAME("glFinish");
DEBUG_MARKER()
#if defined(__EMSCRIPTEN__)
// WebGL builds are single-threaded so users might manipulate various GL state after we're
// done with the frame. We do NOT officially support using Filament in this way, but we can
@@ -3003,6 +2769,7 @@ void OpenGLDriver::endFrame(uint32_t frameId) {
gl.depthFunc(GL_LESS);
gl.disable(GL_SCISSOR_TEST);
#endif
//SYSTRACE_NAME("glFinish");
//glFinish();
insertEventMarker("endFrame");
}
@@ -3034,7 +2801,6 @@ void OpenGLDriver::finish(int) {
UTILS_NOINLINE
void OpenGLDriver::clearWithRasterPipe(TargetBufferFlags clearFlags,
math::float4 const& linearColor, GLfloat depth, GLint stencil) noexcept {
DEBUG_MARKER()
RasterState rs(mRasterState);
if (any(clearFlags & TargetBufferFlags::COLOR_ALL)) {
@@ -3213,14 +2979,18 @@ void OpenGLDriver::draw(PipelineState state, Handle<HwRenderPrimitive> rph, uint
if (UTILS_LIKELY(instanceCount <= 1)) {
glDrawRangeElements(GLenum(rp->type), rp->minIndex, rp->maxIndex, rp->count,
rp->gl.indicesType, reinterpret_cast<const void*>(rp->offset));
rp->gl.getIndicesType(), reinterpret_cast<const void*>(rp->offset));
} else {
glDrawElementsInstanced(GLenum(rp->type), rp->count,
rp->gl.indicesType, reinterpret_cast<const void*>(rp->offset),
rp->gl.getIndicesType(), reinterpret_cast<const void*>(rp->offset),
instanceCount);
}
#ifdef FILAMENT_ENABLE_MATDBG
CHECK_GL_ERROR_NON_FATAL(utils::slog.e)
#else
CHECK_GL_ERROR(utils::slog.e)
#endif
}
// explicit instantiation of the Dispatcher
+5 -23
View File
@@ -17,12 +17,14 @@
#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGLDRIVER_H
#define TNT_FILAMENT_BACKEND_OPENGL_OPENGLDRIVER_H
#include "private/backend/Driver.h"
#include "DriverBase.h"
#include "GLUtils.h"
#include "OpenGLContext.h"
#include "private/backend/AcquiredImage.h"
#include "private/backend/Driver.h"
#include "private/backend/HandleAllocator.h"
#include "private/backend/Program.h"
#include "backend/TargetBufferInfo.h"
@@ -52,6 +54,7 @@ class OpenGLTimerQueryInterface;
class OpenGLDriver final : public DriverBase {
inline explicit OpenGLDriver(OpenGLPlatform* platform) noexcept;
~OpenGLDriver() noexcept final;
Dispatcher getDispatcher() const noexcept final;
public:
static Driver* create(OpenGLPlatform* platform, void* sharedGLContext) noexcept;
@@ -142,7 +145,6 @@ public:
};
struct GLStream : public HwStream {
static constexpr size_t ROUND_ROBIN_TEXTURE_COUNT = 3; // 3 maximum
using HwStream::HwStream;
struct Info {
// storage for the read/write textures below
@@ -150,29 +152,11 @@ public:
GLuint width = 0;
GLuint height = 0;
};
struct {
// id of the texture where the external frames are streamed (i.e. the texture
// used by SurfaceTexture on Android)
GLuint externalTextureId = 0;
/*
* This is for making a cpu copy of the camera frame
*/
GLuint externalTexture2DId = 0;
GLuint fbo = 0;
} gl; // 20 bytes
/*
* The fields below are accessed from the main application thread
* (not the GL thread)
*/
struct {
// texture id used to texture from, always used in the GL thread
GLuint read[ROUND_ROBIN_TEXTURE_COUNT]; // 12 bytes
// texture id to write into, always used from the user thread
GLuint write[ROUND_ROBIN_TEXTURE_COUNT]; // 12 bytes
Info infos[ROUND_ROBIN_TEXTURE_COUNT]; // 48 bytes
int64_t timestamp = 0;
uint8_t cur = 0;
AcquiredImage acquired;
@@ -361,7 +345,7 @@ private:
void setViewportScissor(Viewport const& viewportScissor) noexcept;
// sampler buffer binding points (nullptr if not used)
std::array<HwSamplerGroup*, Program::BINDING_COUNT> mSamplerBindings = {}; // 8 pointers
std::array<HwSamplerGroup*, Program::BINDING_COUNT> mSamplerBindings = {}; // 12 pointers
mutable tsl::robin_map<uint32_t, GLuint> mSamplerMap;
mutable std::vector<GLTexture*> mExternalStreams;
@@ -372,8 +356,6 @@ private:
OpenGLPlatform& mPlatform;
OpenGLBlitter* mOpenGLBlitter = nullptr;
void updateStreamTexId(GLTexture* t, DriverApi* driver) noexcept;
void updateStreamAcquired(GLTexture* t, DriverApi* driver) noexcept;
void updateBuffer(GLBufferObject* buffer, BufferDescriptor const& p,
uint32_t byteOffset, uint32_t alignment = 16) noexcept;
@@ -264,7 +264,7 @@ void OpenGLProgram::initialize(OpenGLContext& context) {
mValid = OpenGLProgram::checkProgramStatus(name.c_str_safe(),
gl.program, gl.shaders, initializationData->shaderSourceCode);
if (mValid) {
if (UTILS_LIKELY(mValid)) {
initializeProgramState(context, gl.program,
initializationData->uniformBlockInfo,
initializationData->samplerGroupInfo);
+2 -2
View File
@@ -60,7 +60,7 @@ public:
// turns out the former might be relatively cheap to check, the later requires
// a bit less. Compared to what updateSamplers() actually does, which is
// pretty little, I'm not sure we'll get ahead.
// pretty little, I'm not sure if we'll get ahead.
updateSamplers(gld);
}
@@ -113,7 +113,7 @@ private:
union {
// when mInitialized == true:
// information about each USED sampler buffer per binding (no gaps)
std::array<uint8_t, Program::BINDING_COUNT> mUsedBindingPoints; // 8 bytes
std::array<uint8_t, Program::BINDING_COUNT> mUsedBindingPoints; // 12 bytes
// when mInitialized == false:
// lazy initialization data pointer
LazyInitializationData* mLazyInitializationData;
+2 -2
View File
@@ -14,11 +14,11 @@
* limitations under the License.
*/
#include "gl_headers.h"
#if defined(__ANDROID__) || defined(FILAMENT_USE_EXTERNAL_GLES3) || defined(__EMSCRIPTEN__)
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#include <GLES2/gl2ext.h>
#include <mutex>
namespace glext {
+29 -22
View File
@@ -115,6 +115,35 @@
#endif
#if (!defined(GL_ES_VERSION_2_0) && !defined(GL_VERSION_4_1))
#error "Minimum header version must be OpenGL ES 2.0 or OpenGL 4.1"
#endif
#define BACKEND_OPENGL_VERSION_GLES 0
#define BACKEND_OPENGL_VERSION_GL 1
#if defined(GL_ES_VERSION_2_0)
# define BACKEND_OPENGL_VERSION BACKEND_OPENGL_VERSION_GLES
#elif defined(GL_VERSION_4_1)
# define BACKEND_OPENGL_VERSION BACKEND_OPENGL_VERSION_GL
#endif
#define BACKEND_OPENGL_LEVEL_GLES20 0
#define BACKEND_OPENGL_LEVEL_GLES30 1
#define BACKEND_OPENGL_LEVEL_GLES31 2
#if defined(GL_VERSION_4_1)
# define BACKEND_OPENGL_LEVEL BACKEND_OPENGL_LEVEL_GLES30
#endif
#if defined(GL_ES_VERSION_3_1)
# define BACKEND_OPENGL_LEVEL BACKEND_OPENGL_LEVEL_GLES31
#elif defined(GL_ES_VERSION_3_0)
# define BACKEND_OPENGL_LEVEL BACKEND_OPENGL_LEVEL_GLES30
#elif defined(GL_ES_VERSION_2_0)
# define BACKEND_OPENGL_LEVEL BACKEND_OPENGL_LEVEL_GLES20
#endif
// This is just to simplify the implementation (i.e. so we don't have to have #ifdefs everywhere)
#ifndef GL_OES_EGL_image_external
#define GL_TEXTURE_EXTERNAL_OES 0x8D65
@@ -122,26 +151,4 @@
#include "NullGLES.h"
#if (!defined(GL_ES_VERSION_3_0) && !defined(GL_VERSION_4_1))
#error "Minimum header version must be OpenGL ES 3.0 or OpenGL 4.1"
#endif
#if defined(GL_ES_VERSION_3_0)
#define GLES30_HEADERS true
#else
#define GLES30_HEADERS false
#endif
#if defined(GL_ES_VERSION_3_1)
#define GLES31_HEADERS true
#else
#define GLES31_HEADERS false
#endif
#if defined(GL_VERSION_4_1)
#define GL41_HEADERS true
#else
#define GL41_HEADERS false
#endif
#endif // TNT_FILAMENT_BACKEND_OPENGL_GL_HEADERS_H
@@ -55,11 +55,6 @@ public:
void detach(Stream* stream) noexcept final {}
void updateTexImage(Stream* stream, int64_t* timestamp) noexcept final {}
ExternalTexture* createExternalTextureStorage() noexcept final { return nullptr; }
void reallocateExternalStorage(ExternalTexture* ets,
uint32_t w, uint32_t h, TextureFormat format) noexcept final { }
void destroyExternalTextureStorage(ExternalTexture* ets) noexcept final { }
int getOSVersion() const noexcept final { return 0; }
bool pumpEvents() noexcept override;
@@ -56,11 +56,6 @@ public:
void detach(Stream* stream) noexcept final {}
void updateTexImage(Stream* stream, int64_t* timestamp) noexcept final {}
ExternalTexture* createExternalTextureStorage() noexcept final { return nullptr; }
void reallocateExternalStorage(ExternalTexture* ets,
uint32_t w, uint32_t h, TextureFormat format) noexcept final { }
void destroyExternalTextureStorage(ExternalTexture* ets) noexcept final { }
int getOSVersion() const noexcept final { return 0; }
bool setExternalImage(void* externalImage, void* texture) noexcept final;
@@ -51,11 +51,6 @@ public:
void detach(Stream* stream) noexcept final override {}
void updateTexImage(Stream* stream, int64_t* timestamp) noexcept final override {}
ExternalTexture* createExternalTextureStorage() noexcept final override { return nullptr; }
void reallocateExternalStorage(ExternalTexture* ets,
uint32_t w, uint32_t h, TextureFormat format) noexcept final override { }
void destroyExternalTextureStorage(ExternalTexture* ets) noexcept final override { }
int getOSVersion() const noexcept final override { return 0; }
};
@@ -62,11 +62,6 @@ public:
void detach(Stream* stream) noexcept override {}
void updateTexImage(Stream* stream, int64_t* timestamp) noexcept override {}
ExternalTexture* createExternalTextureStorage() noexcept override { return nullptr; }
void reallocateExternalStorage(ExternalTexture* ets,
uint32_t w, uint32_t h, TextureFormat format) noexcept override {}
void destroyExternalTextureStorage(ExternalTexture* ets) noexcept override {}
protected:
static void logEglError(const char* name) noexcept;
@@ -19,7 +19,6 @@
#include "opengl/OpenGLDriver.h"
#include "opengl/OpenGLContext.h"
#include "android/ExternalTextureManagerAndroid.h"
#include "ExternalStreamManagerAndroid.h"
#include "private/backend/VirtualMachineEnv.h"
@@ -73,8 +72,7 @@ using EGLStream = Platform::Stream;
PlatformEGLAndroid::PlatformEGLAndroid() noexcept
: PlatformEGL(),
mExternalStreamManager(ExternalStreamManagerAndroid::create()),
mExternalTextureManager(ExternalTextureManagerAndroid::create()) {
mExternalStreamManager(ExternalStreamManagerAndroid::create()) {
char scratch[PROP_VALUE_MAX + 1];
int length = __system_property_get("ro.build.version.release", scratch);
@@ -85,6 +83,18 @@ PlatformEGLAndroid::PlatformEGLAndroid() noexcept
length = __system_property_get("ro.build.version.sdk", scratch);
mOSVersion = length >= 0 ? atoi(scratch) : 1;
}
// This disables an ANGLE optimization on ARM, which turns out to be more costly for us
// see b/229017581
// We need to do this before we create the GL context.
// An alternative solution is use a system property:
// __system_property_set(
// "debug.angle.feature_overrides_disabled",
// "preferSubmitAtFBOBoundary");
// but that would outlive this process, so the environment variable is better.
// We also make sure to not update the variable if it already exists.
// There is no harm setting this if we're not on ANGLE or ARM.
setenv("ANGLE_FEATURE_OVERRIDES_DISABLED", "preferSubmitAtFBOBoundary", false);
}
PlatformEGLAndroid::~PlatformEGLAndroid() noexcept = default;
@@ -92,7 +102,6 @@ PlatformEGLAndroid::~PlatformEGLAndroid() noexcept = default;
void PlatformEGLAndroid::terminate() noexcept {
ExternalStreamManagerAndroid::destroy(&mExternalStreamManager);
ExternalTextureManagerAndroid::destroy(&mExternalTextureManager);
PlatformEGL::terminate();
}
@@ -100,7 +109,8 @@ Driver* PlatformEGLAndroid::createDriver(void* sharedContext) noexcept {
Driver* driver = PlatformEGL::createDriver(sharedContext);
auto extensions = GLUtils::split(eglQueryString(mEGLDisplay, EGL_EXTENSIONS));
eglGetNativeClientBufferANDROID = (PFNEGLGETNATIVECLIENTBUFFERANDROIDPROC) eglGetProcAddress("eglGetNativeClientBufferANDROID");
eglGetNativeClientBufferANDROID = (PFNEGLGETNATIVECLIENTBUFFERANDROIDPROC) eglGetProcAddress(
"eglGetNativeClientBufferANDROID");
if (extensions.has("EGL_ANDROID_presentation_time")) {
eglPresentationTimeANDROID = (PFNEGLPRESENTATIONTIMEANDROIDPROC)eglGetProcAddress(
@@ -154,58 +164,6 @@ void PlatformEGLAndroid::updateTexImage(Stream* stream, int64_t* timestamp) noex
mExternalStreamManager.updateTexImage(stream, timestamp);
}
Platform::ExternalTexture* PlatformEGLAndroid::createExternalTextureStorage() noexcept {
return mExternalTextureManager.createExternalTexture();
}
void PlatformEGLAndroid::reallocateExternalStorage(
Platform::ExternalTexture* externalTexture,
uint32_t w, uint32_t h, TextureFormat format) noexcept {
if (externalTexture) {
if ((EGLImageKHR)externalTexture->image != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(mEGLDisplay, (EGLImageKHR)externalTexture->image);
externalTexture->image = (uintptr_t)EGL_NO_IMAGE_KHR;
}
mExternalTextureManager.reallocate(externalTexture, w, h, format,
AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE);
auto ets = (ExternalTextureManagerAndroid::ExternalTexture*)externalTexture;
EGLClientBuffer clientBuffer;
if (ets->hardwareBuffer) {
clientBuffer = eglGetNativeClientBufferANDROID(ets->hardwareBuffer);
if (UTILS_UNLIKELY(!clientBuffer)) {
logEglError("eglGetNativeClientBufferANDROID");
return;
}
} else if (ets->clientBuffer) {
clientBuffer = (EGLClientBuffer)ets->clientBuffer;
} else {
// woops, reallocate failed.
return;
}
const EGLint attr[] = { EGL_NONE };
EGLImageKHR image = eglCreateImageKHR(mEGLDisplay,
EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attr);
if (UTILS_UNLIKELY(!image)) {
logEglError("eglCreateImageKHR");
}
ets->image = (uintptr_t)image;
}
}
void PlatformEGLAndroid::destroyExternalTextureStorage(
Platform::ExternalTexture* externalTexture) noexcept {
if (externalTexture) {
mExternalTextureManager.destroy(externalTexture);
if ((EGLImageKHR)externalTexture->image != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(mEGLDisplay, (EGLImageKHR)externalTexture->image);
externalTexture->image = (uintptr_t)EGL_NO_IMAGE_KHR;
}
}
}
int PlatformEGLAndroid::getOSVersion() const noexcept {
return mOSVersion;
}
@@ -22,7 +22,6 @@
namespace filament::backend {
class ExternalStreamManagerAndroid;
class ExternalTextureManagerAndroid;
class PlatformEGLAndroid final : public PlatformEGL {
public:
@@ -44,17 +43,11 @@ public:
void detach(Stream* stream) noexcept final;
void updateTexImage(Stream* stream, int64_t* timestamp) noexcept final;
ExternalTexture* createExternalTextureStorage() noexcept final;
void reallocateExternalStorage(ExternalTexture* ets,
uint32_t w, uint32_t h, TextureFormat format) noexcept final;
void destroyExternalTextureStorage(ExternalTexture* ets) noexcept final;
AcquiredImage transformAcquiredImage(AcquiredImage source) noexcept final;
private:
int mOSVersion;
ExternalStreamManagerAndroid& mExternalStreamManager;
ExternalTextureManagerAndroid& mExternalTextureManager;
};
} // namespace filament::backend
@@ -55,11 +55,6 @@ public:
void detach(Stream* stream) noexcept final override {}
void updateTexImage(Stream* stream, int64_t* timestamp) noexcept final override {}
ExternalTexture* createExternalTextureStorage() noexcept final override { return nullptr; }
void reallocateExternalStorage(ExternalTexture* ets,
uint32_t w, uint32_t h, TextureFormat format) noexcept final override { }
void destroyExternalTextureStorage(ExternalTexture* ets) noexcept final override { }
int getOSVersion() const noexcept final override { return 0; }
private:
@@ -51,11 +51,6 @@ public:
void detach(Stream* stream) noexcept final override {}
void updateTexImage(Stream* stream, int64_t* timestamp) noexcept final override {}
ExternalTexture* createExternalTextureStorage() noexcept final override { return nullptr; }
void reallocateExternalStorage(ExternalTexture* ets,
uint32_t w, uint32_t h, TextureFormat format) noexcept final override { }
void destroyExternalTextureStorage(ExternalTexture* ets) noexcept final override { }
int getOSVersion() const noexcept final override { return 0; }
private:
@@ -52,11 +52,6 @@ public:
void detach(Stream* stream) noexcept final override {}
void updateTexImage(Stream* stream, int64_t* timestamp) noexcept final override {}
ExternalTexture* createExternalTextureStorage() noexcept final override { return nullptr; }
void reallocateExternalStorage(ExternalTexture* ets,
uint32_t w, uint32_t h, TextureFormat format) noexcept final override { }
void destroyExternalTextureStorage(ExternalTexture* ets) noexcept final override { }
int getOSVersion() const noexcept final override { return 0; }
};
@@ -20,11 +20,13 @@
#include "VulkanTexture.h"
#include "VulkanUtility.h"
#include <algorithm> // for std::max
#include <backend/PixelBufferDescriptor.h>
#include <utils/Panic.h>
#include <utils/FixedCapacityVector.h>
#include <algorithm> // for std::max
using namespace bluevk;
using utils::FixedCapacityVector;
+5 -21
View File
@@ -92,9 +92,12 @@ Driver* VulkanDriverFactory::create(VulkanPlatform* const platform,
return VulkanDriver::create(platform, ppRequiredExtensions, requiredExtensionCount);
}
Dispatcher VulkanDriver::getDispatcher() const noexcept {
return ConcreteDispatcher<VulkanDriver>::make();
}
VulkanDriver::VulkanDriver(VulkanPlatform* platform,
const char* const* ppRequiredExtensions, uint32_t requiredExtensionCount) noexcept :
DriverBase(new ConcreteDispatcher<VulkanDriver>()),
mHandleAllocator("Handles", FILAMENT_VULKAN_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U),
mContextManager(*platform),
mStagePool(mContext),
@@ -605,10 +608,6 @@ void VulkanDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch,
construct<VulkanSwapChain>(sch, mContext, mStagePool, width, height);
}
void VulkanDriver::createStreamFromTextureIdR(Handle<HwStream> sh, intptr_t externalTextureId,
uint32_t width, uint32_t height) {
}
void VulkanDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
// nothing to do, timer query was constructed in createTimerQueryS
}
@@ -675,10 +674,6 @@ Handle<HwSwapChain> VulkanDriver::createSwapChainHeadlessS() noexcept {
return allocHandle<VulkanSwapChain>();
}
Handle<HwStream> VulkanDriver::createStreamFromTextureIdS() noexcept {
return {};
}
Handle<HwTimerQuery> VulkanDriver::createTimerQueryS() noexcept {
// The handle must be constructed here, as a synchronous call to getTimerQueryValue might happen
// before createTimerQueryR is executed.
@@ -1605,14 +1600,8 @@ void VulkanDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y
vkMapMemory(device, stagingMemory, 0, VK_WHOLE_SIZE, 0, (void**) &srcPixels);
srcPixels += subResourceLayout.offset;
// NOTE: the reasons for this are unclear, but issuing ReadPixels on a VkImage that has been
// extracted from a swap chain does not need a Y flip, but explicitly created VkImages do. (The
// former can be tested with "Export Screenshots" in gltf_viewer, the latter can be tested with
// test_ReadPixels.cpp). We've seen this behavior with both SwiftShader and MoltenVK.
const bool flipY = !srcTarget->isSwapChain();
if (!DataReshaper::reshapeImage(&pbd, getComponentType(srcFormat), srcPixels,
subResourceLayout.rowPitch, width, height, swizzle, flipY)) {
subResourceLayout.rowPitch, width, height, swizzle, false)) {
utils::slog.e << "Unsupported PixelDataFormat or PixelDataType" << utils::io::endl;
}
@@ -1626,11 +1615,6 @@ void VulkanDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y
scheduleDestroy(std::move(pbd));
}
void VulkanDriver::readStreamPixels(Handle<HwStream> sh, uint32_t x, uint32_t y, uint32_t width,
uint32_t height, PixelBufferDescriptor&& p) {
scheduleDestroy(std::move(p));
}
void VulkanDriver::blit(TargetBufferFlags buffers, Handle<HwRenderTarget> dst, Viewport dstRect,
Handle<HwRenderTarget> src, Viewport srcRect, SamplerMagFilter filter) {
assert_invariant(mContext.currentRenderPass.renderPass == VK_NULL_HANDLE);
@@ -53,6 +53,8 @@ private:
~VulkanDriver() noexcept override;
Dispatcher getDispatcher() const noexcept final;
ShaderModel getShaderModel() const noexcept final;
template<typename T>
@@ -289,18 +289,17 @@ private:
// Represents all the Vulkan state that comprises a bound descriptor set.
struct DescriptorKey {
VkBuffer uniformBuffers[UBUFFER_BINDING_COUNT]; // 0
DescriptorImageInfo samplers[SAMPLER_BINDING_COUNT]; // 64
DescriptorImageInfo inputAttachments[TARGET_BINDING_COUNT]; // 832
uint32_t uniformBufferOffsets[UBUFFER_BINDING_COUNT]; // 1024
uint32_t uniformBufferSizes[UBUFFER_BINDING_COUNT]; // 1056
VkBuffer uniformBuffers[UBUFFER_BINDING_COUNT]; // 96 0
DescriptorImageInfo samplers[SAMPLER_BINDING_COUNT]; // 768 96
DescriptorImageInfo inputAttachments[TARGET_BINDING_COUNT]; // 192 864
uint32_t uniformBufferOffsets[UBUFFER_BINDING_COUNT]; // 48 1056
uint32_t uniformBufferSizes[UBUFFER_BINDING_COUNT]; // 48 1104
};
static_assert(offsetof(DescriptorKey, samplers) == 64);
static_assert(offsetof(DescriptorKey, inputAttachments) == 832);
static_assert(offsetof(DescriptorKey, uniformBufferOffsets) == 1024);
static_assert(offsetof(DescriptorKey, uniformBufferSizes) == 1056);
static_assert(sizeof(DescriptorKey) == 1088, "DescriptorKey must not have implicit padding.");
static_assert(offsetof(DescriptorKey, samplers) == 96);
static_assert(offsetof(DescriptorKey, inputAttachments) == 864);
static_assert(offsetof(DescriptorKey, uniformBufferOffsets) == 1056);
static_assert(offsetof(DescriptorKey, uniformBufferSizes) == 1104);
static_assert(sizeof(DescriptorKey) == 1152, "DescriptorKey must not have implicit padding.");
using DescHashFn = utils::hash::MurmurHashFn<DescriptorKey>;
+3 -3
View File
@@ -59,7 +59,7 @@ void BackendTest::initializeDriver() {
DefaultPlatform* platform = DefaultPlatform::create(&backend);
assert_invariant(static_cast<uint8_t>(backend) == static_cast<uint8_t>(sBackend));
driver = platform->createDriver(nullptr);
commandStream = CommandStream(*driver, commandBufferQueue.getCircularBuffer());
commandStream = std::make_unique<CommandStream>(*driver, commandBufferQueue.getCircularBuffer());
}
void BackendTest::executeCommands() {
@@ -67,7 +67,7 @@ void BackendTest::executeCommands() {
auto buffers = commandBufferQueue.waitForCommands();
for (auto& item : buffers) {
if (UTILS_LIKELY(item.begin)) {
commandStream.execute(item.begin);
getDriverApi().execute(item.begin);
commandBufferQueue.releaseBuffer(item);
}
}
@@ -84,7 +84,7 @@ void BackendTest::flushAndWait(uint64_t timeout) {
Handle<HwSwapChain> BackendTest::createSwapChain() {
const NativeView& view = getNativeView();
return commandStream.createSwapChain(view.ptr, 0);
return getDriverApi().createSwapChain(view.ptr, 0);
}
void BackendTest::fullViewport(RenderPassParams& params) {
+2 -2
View File
@@ -58,14 +58,14 @@ protected:
void readPixelsAndAssertHash(const char* testName, size_t width, size_t height,
filament::backend::Handle<filament::backend::HwRenderTarget> rt, uint32_t expectedHash);
filament::backend::DriverApi& getDriverApi() { return commandStream; }
filament::backend::DriverApi& getDriverApi() { return *commandStream; }
filament::backend::Driver& getDriver() { return *driver; }
private:
filament::backend::Driver* driver = nullptr;
filament::backend::CommandBufferQueue commandBufferQueue;
filament::backend::DriverApi commandStream;
std::unique_ptr<filament::backend::DriverApi> commandStream;
filament::backend::Handle<filament::backend::HwBufferObject> uniform;
};
@@ -26,6 +26,14 @@ namespace test {
/**
* A wrapper class that manages the necessary resources for a simple triangle renderable used for
* test cases.
*
* The default vertices orient the triangle as such:
* o
* . .
* . .
* . .
* . .
* o . . . . o
*/
class TrianglePrimitive {
public:

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