Compare commits

..

94 Commits

Author SHA1 Message Date
Benjamin Doherty
5c8977c906 Merge branch 'rc/1.21.3' into release 2022-05-02 13:18:06 -04:00
Benjamin Doherty
6b3cc2e2f3 Update RELEASE_NOTES for 1.21.3 2022-05-02 13:12:51 -04:00
Ben Doherty
76b2edd6ea Move toCompressedFilamentEnum to Ktx1Reader header (#5493) 2022-04-29 14:50:24 -04:00
Benjamin Doherty
8ebb37d011 Bump version to 1.21.3 2022-04-25 16:58:19 -04:00
Benjamin Doherty
3366db83ef Merge branch 'rc/1.21.2' into release 2022-04-25 16:57:25 -04:00
Benjamin Doherty
861d69ea7c Release Filament 1.21.2 2022-04-25 16:57:00 -04:00
Benjamin Doherty
5415254aac Update RELEASE_NOTES for 1.21.2 2022-04-25 16:50:53 -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
caacc61602 Bump version to 1.21.2 2022-04-13 10:21:09 -06:00
Benjamin Doherty
e902df19b2 Merge branch 'rc/1.21.1' into release 2022-04-13 10:15:50 -06: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
Benjamin Doherty
40b372dda7 Update RELEASE_NOTES for 1.21.1 2022-04-12 14:36:26 -06: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
Ben Doherty
fd330a98aa Releases: specify Python dependencies in requirements.txt file (#5402) 2022-04-08 14:35:51 -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
Benjamin Doherty
5710304114 Bump version to 1.21.1 2022-04-04 13:03:39 -07:00
Benjamin Doherty
09fe495384 Release Filament 1.21.0 2022-04-04 13:00:48 -07:00
Pavel Korolev
8457d6092d Use index offset provided by ImGui when rendering UI 2022-04-04 10:49:43 -07:00
Mathias Agopian
72c16e07ed remove Viewport::scale()
because a float->integer conversion is needed, it's better to let the
caller decide what they want.
2022-04-02 20:37:00 -07:00
Mathias Agopian
12b96cba04 minor cleanup: rename internal class attributes 2022-04-02 20:37:00 -07:00
Mathias Agopian
e4d943e942 update release nodes and bump material version 2022-04-02 20:36:40 -07:00
Ben Doherty
7fa66325f3 Fix Metal validation error when reading from default SwapChain (#5392) 2022-04-01 16:37:46 -07:00
Mathias Agopian
e188a7875e enable both screen-space refraction and reflection
Both "SSR" can now be used on the same material. This is made possible
by using a 2D array to store both buffers.
2022-04-01 16:22:10 -07:00
Mathias Agopian
ac9822b8c8 Fix a framegraph dependency bug when writing to subresources
The dependency graph was set incorrectly when writing to a subresource
of a subresource.
2022-04-01 16:22:10 -07:00
Mathias Agopian
edb5fddd03 one more step towards reflection+refraction support
With this change we are now generating refraction and reflections
buffer into their own layer of a 2D array -- so they can coexist.

This change doesn't actually enable both at the same time yet.

There are downsides to this approach:
- a 2d array of 2 layers is created even if only one of reflection or
  refraction is active. This could be fixed at the cost of more
  complexity.
- if reflections are active then refraction must use a RGBA16F texture
  instead of RGB_11_11_10, because they share the texture
2022-04-01 14:37:40 -07:00
Mathias Agopian
35f4a97e32 new framegraph API do add a pass without an execute stage 2022-04-01 14:37:40 -07:00
Mathias Agopian
487b10fdda repair and optimize matdbg
we add a checkProgramEdits() method that must be called periodically
on all materials. This is currently done at the beginning of a frame.
2022-03-31 16:52:26 -07:00
Mathias Agopian
271cda88aa Move vulkan backend implementation into the filament::backend namespace 2022-03-31 11:53:54 -07:00
Mathias Agopian
25b73ddcfa Move opengl backend implementation into the filament::backend namespace 2022-03-31 11:53:54 -07:00
Mathias Agopian
35b8146a87 move metal backend out of the metal namespace
this is to be consistent with other backends, which are all in
filament::backend.

had to rename metal::PipelineState to MetalPipelineState.
2022-03-31 11:53:54 -07:00
Mathias Agopian
091e5a33ac move Noop backend into filament::backend namespace 2022-03-31 11:53:54 -07:00
Ben Doherty
ffe4b7390d Correctly prepare color grading as subpass programs (#5384) 2022-03-30 16:25:27 -07:00
Mathias Agopian
604d3e34a4 avoid an extra copy during the screen-space reflection pass
unlike for refraction, the reflection buffer is distinct from "the"
color buffer, this allows an optimization (compared to ssr) when we
generate the mipmap chain -- we can allocate the mipmaped texture
and render the SSR pass directly into its level 0. This achieved
use the framegraph's forward resource feature.
2022-03-30 15:32:52 -07:00
Mathias Agopian
e116dd4aec Improve framegraph forward resource API
This add a couple methods to allow the creation and forwarding in a
single call.
2022-03-30 15:32:52 -07:00
Mathias Agopian
d53614fb0a fix a framegraph crash when forwarding a subresource
the crash would happen when forwarding a subresource of a subresource,
because in this case the parent's handle would be reset to the null
handle.
2022-03-30 15:32:30 -07:00
Mathias Agopian
c91e5df117 Add comment about how we calculate the viewport when upscaling 2022-03-30 08:58:50 -07:00
Philip Rideout
96574816b3 Fix 12x overallocation of memory in MorphTargetBuffer.
I noticed this while helping someone at Google understand our new API.
2022-03-30 08:24:40 -07:00
Mathias Agopian
b43a609ebc rename framegraph fg2/ folder to fg/ 2022-03-29 14:38:36 -07:00
421 changed files with 139290 additions and 4866 deletions

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:

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)

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

View File

@@ -3,9 +3,33 @@
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.1 (currently main branch)
## v1.21.3 (currently main branch)
- engine: allow both screen-space refraction and screen-space reflections on the same object [⚠️ **Material breakage**].
- 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: 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
@@ -440,7 +464,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.

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 = [

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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>
*

View File

@@ -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);

View File

@@ -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
)

View File

@@ -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)},

View File

@@ -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.

View File

@@ -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
}

View File

@@ -11,6 +11,10 @@ add_library(dracodec STATIC IMPORTED)
set_target_properties(dracodec PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libdracodec.a)
add_library(stb STATIC IMPORTED)
set_target_properties(stb PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libstb.a)
add_library(utils STATIC IMPORTED)
set_target_properties(utils PROPERTIES IMPORTED_LOCATION
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libutils.a)
@@ -32,6 +36,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
@@ -47,13 +52,13 @@ set(GLTFIO_SRCS
${GLTFIO_DIR}/src/GltfEnums.h
${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
@@ -90,9 +95,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 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 gltfio_resources)
# Enable Draco in the non-lite variant of gltfio.
target_link_libraries(gltfio-jni dracodec)

View File

@@ -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;

View File

@@ -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) {

View File

@@ -19,6 +19,7 @@
#include <filament/Engine.h>
#include <gltfio/ResourceLoader.h>
#include <gltfio/TextureProvider.h>
#include <utils/Log.h>
@@ -114,3 +115,27 @@ 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_nCreateTextureProvider(JNIEnv*, jclass,
jlong nativeEngine) {
Engine* engine = (Engine*) nativeEngine;
return (jlong) createStbProvider(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);
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -35,6 +35,7 @@ import java.nio.Buffer;
*/
public class ResourceLoader {
private final long mNativeObject;
private final long mNativeProvider;
/**
* Constructs a resource loader tied to the given Filament engine.
@@ -46,6 +47,9 @@ public class ResourceLoader {
public ResourceLoader(@NonNull Engine engine) {
long nativeEngine = engine.getNativeObject();
mNativeObject = nCreateResourceLoader(nativeEngine, false, false, false);
mNativeProvider = nCreateTextureProvider(nativeEngine);
nAddTextureProvider(mNativeObject, "image/jpeg", mNativeProvider);
nAddTextureProvider(mNativeObject, "image/png", mNativeProvider);
}
/**
@@ -63,6 +67,9 @@ public class ResourceLoader {
long nativeEngine = engine.getNativeObject();
mNativeObject = nCreateResourceLoader(nativeEngine, normalizeSkinningWeights,
recomputeBoundingBoxes, ignoreBindTransform);
mNativeProvider = nCreateTextureProvider(nativeEngine);
nAddTextureProvider(mNativeObject, "image/jpeg", mNativeProvider);
nAddTextureProvider(mNativeObject, "image/png", mNativeProvider);
}
/**
@@ -70,6 +77,7 @@ public class ResourceLoader {
*/
public void destroy() {
nDestroyResourceLoader(mNativeObject);
nDestroyTextureProvider(mNativeProvider);
}
/**
@@ -178,4 +186,8 @@ 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 nCreateTextureProvider(long nativeEngine);
private static native void nAddTextureProvider(long nativeLoader, String url, long nativeProvider);
private static native void nDestroyTextureProvider(long nativeProvider);
}

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.

View File

@@ -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]

View File

@@ -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
}
}

View File

@@ -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

BIN
art/diagrams/NDC.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

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

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

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

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

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>

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>

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>

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.

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.

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)

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

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>

View File

@@ -92,7 +92,6 @@ set(SRCS
src/UniformBuffer.cpp
src/VertexBuffer.cpp
src/View.cpp
src/Viewport.cpp
src/components/CameraManager.cpp
src/components/LightManager.cpp
src/components/RenderableManager.cpp
@@ -118,14 +117,14 @@ set(SRCS
src/details/Texture.cpp
src/details/VertexBuffer.cpp
src/details/View.cpp
src/fg2/Blackboard.cpp
src/fg2/DependencyGraph.cpp
src/fg2/FrameGraph.cpp
src/fg2/FrameGraphPass.cpp
src/fg2/FrameGraphResources.cpp
src/fg2/FrameGraphTexture.cpp
src/fg2/PassNode.cpp
src/fg2/ResourceNode.cpp
src/fg/Blackboard.cpp
src/fg/DependencyGraph.cpp
src/fg/FrameGraph.cpp
src/fg/FrameGraphPass.cpp
src/fg/FrameGraphResources.cpp
src/fg/FrameGraphTexture.cpp
src/fg/PassNode.cpp
src/fg/ResourceNode.cpp
src/fsr.cpp
)
@@ -177,19 +176,19 @@ set(PRIVATE_HDRS
src/details/Texture.h
src/details/VertexBuffer.h
src/details/View.h
src/fg2/Blackboard.h
src/fg2/FrameGraph.h
src/fg2/FrameGraphId.h
src/fg2/FrameGraphPass.h
src/fg2/FrameGraphRenderPass.h
src/fg2/FrameGraphResources.h
src/fg2/FrameGraphTexture.h
src/fg2/Resource.cpp
src/fg2/details/DependencyGraph.h
src/fg2/details/PassNode.h
src/fg2/details/Resource.h
src/fg2/details/ResourceNode.h
src/fg2/details/Utilities.h
src/fg/Blackboard.h
src/fg/FrameGraph.h
src/fg/FrameGraphId.h
src/fg/FrameGraphPass.h
src/fg/FrameGraphRenderPass.h
src/fg/FrameGraphResources.h
src/fg/FrameGraphTexture.h
src/fg/Resource.cpp
src/fg/details/DependencyGraph.h
src/fg/details/PassNode.h
src/fg/details/Resource.h
src/fg/details/ResourceNode.h
src/fg/details/Utilities.h
src/fsr.h
src/materials/fsr/ffx_a.h
src/materials/fsr/ffx_fsr1.h

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
@@ -74,8 +73,8 @@ if (FILAMENT_SUPPORTS_OPENGL AND NOT FILAMENT_USE_EXTERNAL_GLES3 AND NOT FILAMEN
src/opengl/OpenGLProgram.cpp
src/opengl/OpenGLProgram.h
src/opengl/OpenGLPlatform.cpp
src/opengl/TimerQuery.cpp
src/opengl/TimerQuery.h
src/opengl/OpenGLTimerQuery.cpp
src/opengl/OpenGLTimerQuery.h
include/private/backend/OpenGLPlatform.h
)
if (EGL)
@@ -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)

View File

@@ -33,7 +33,6 @@
#include <stddef.h>
#include <stdint.h>
namespace filament {
/**
* Types and enums used by filament's driver.
*
@@ -41,7 +40,7 @@ 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;
@@ -142,9 +141,9 @@ struct Viewport {
uint32_t width; //!< width in pixels
uint32_t height; //!< height in pixels
//! get the right coordinate in window space of the viewport
int32_t right() const noexcept { return left + width; }
int32_t right() const noexcept { return left + int32_t(width); }
//! get the top coordinate in window space of the viewport
int32_t top() const noexcept { return bottom + height; }
int32_t top() const noexcept { return bottom + int32_t(height); }
};
/**
@@ -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+.
};
@@ -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 {};

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
*/

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
* --------------------

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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; }

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

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

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

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

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...

View File

@@ -28,7 +28,7 @@ namespace filament::backend {
#ifndef NDEBUG
static char const * const kOurNamespace = "filament::";
static char const * const kOurNamespace = "filament::backend";
// removes all occurrences of "what" from "str"
UTILS_NOINLINE

View File

@@ -1,223 +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 {
using namespace 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
backend::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(
backend::Platform::ExternalTexture* ets, uint32_t w, uint32_t h,
backend::TextureFormat format, uint64_t usage) noexcept {
destroyStorage(ets);
alloc(ets, w, h, format, usage);
}
// called on gl thread
void ExternalTextureManagerAndroid::destroy(backend::Platform::ExternalTexture* ets) noexcept {
destroyStorage(ets);
delete static_cast<EGLExternalTexture*>(ets);
}
// called on app thread
void ExternalTextureManagerAndroid::alloc(
backend::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(backend::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

View File

@@ -1,86 +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 {
/*
* 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 backend::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
backend::Platform::ExternalTexture* createExternalTexture() noexcept;
// called on app thread
void reallocate(
backend::Platform::ExternalTexture* ets, uint32_t w, uint32_t h,
backend::TextureFormat format, uint64_t usage) noexcept;
// must be called on backend thread
void destroy(backend::Platform::ExternalTexture* ets) noexcept;
private:
ExternalTextureManagerAndroid() noexcept;
~ExternalTextureManagerAndroid() noexcept;
// called on app thread
void alloc(backend::Platform::ExternalTexture* ets,
uint32_t w, uint32_t h, backend::TextureFormat format, uint64_t usage) noexcept;
// called on gl thread
void destroyStorage(backend::Platform::ExternalTexture* ets) noexcept;
VirtualMachineEnv& mVm;
jclass mGraphicBufferClass = nullptr;
jmethodID mGraphicBuffer_nCreateGraphicBuffer = nullptr;
jmethodID mGraphicBuffer_nDestroyGraphicBuffer = nullptr;
};
} // namespace filament
#endif // TNT_FILAMENT_DRIVER_ANDROID_EXTERNAL_TEXTURE_MANAGER_ANDROID_H

View File

@@ -26,7 +26,6 @@
namespace filament {
namespace backend {
namespace metal {
struct MetalContext;
@@ -133,7 +132,6 @@ private:
};
} // namespace metal
} // namespace backend
} // namespace filament

View File

@@ -23,7 +23,6 @@
namespace filament {
namespace backend {
namespace metal {
static const char* functionLibrary = R"(
#include <metal_stdlib>
@@ -300,7 +299,7 @@ void MetalBlitter::blitDepthPlane(id<MTLCommandBuffer> cmdBuffer, bool blitColor
}
id<MTLFunction> fragmentFunction = getBlitFragmentFunction(key);
PipelineState pipelineState {
MetalPipelineState pipelineState {
.vertexFunction = getBlitVertexFunction(),
.fragmentFunction = fragmentFunction,
.vertexDescription = {},
@@ -530,6 +529,5 @@ id<MTLFunction> MetalBlitter::getBlitFragmentFunction(BlitFunctionKey key) {
return function;
}
} // namespace metal
} // namespace backend
} // namespace filament

View File

@@ -26,7 +26,6 @@
namespace filament {
namespace backend {
namespace metal {
class MetalBuffer {
public:
@@ -94,7 +93,6 @@ private:
void copyIntoStreamBuffer(void* src, size_t size);
};
} // namespace metal
} // namespace backend
} // namespace filament

View File

@@ -22,7 +22,6 @@
namespace filament {
namespace backend {
namespace metal {
MetalBuffer::MetalBuffer(MetalContext& context, BufferUsage usage, size_t size, bool forceGpuBuffer)
: mBufferSize(size), mContext(context) {
@@ -206,6 +205,5 @@ void MetalBuffer::bindBuffers(id<MTLCommandBuffer> cmdBuffer, id<MTLRenderComman
}
}
} // namespace metal
} // namespace backend
} // namespace filament

View File

@@ -25,7 +25,6 @@
namespace filament {
namespace backend {
namespace metal {
struct MetalContext;
@@ -78,7 +77,6 @@ private:
static constexpr uint32_t TIME_BEFORE_EVICTION = 10;
};
} // namespace metal
} // namespace backend
} // namespace filament

View File

@@ -26,7 +26,6 @@
namespace filament {
namespace backend {
namespace metal {
MetalBufferPoolEntry const* MetalBufferPool::acquireBuffer(size_t numBytes) {
std::lock_guard<std::mutex> lock(mMutex);
@@ -110,6 +109,5 @@ void MetalBufferPool::reset() noexcept {
mFreeStages.clear();
}
} // namespace metal
} // namespace backend
} // namespace filament

View File

@@ -36,14 +36,13 @@
namespace filament {
namespace backend {
namespace metal {
class MetalDriver;
class MetalBlitter;
class MetalBufferPool;
class MetalRenderTarget;
class MetalSwapChain;
class TimerQueryInterface;
class MetalTimerQueryInterface;
struct MetalUniformBuffer;
struct MetalIndexBuffer;
struct MetalSamplerGroup;
@@ -113,7 +112,7 @@ struct MetalContext {
MTLSharedEventListener* eventListener = nil;
uint64_t signalId = 1;
TimerQueryInterface* timerQueryImpl;
MetalTimerQueryInterface* timerQueryImpl;
std::stack<const char*> groupMarkers;
@@ -134,7 +133,6 @@ id<MTLTexture> getOrCreateEmptyTexture(MetalContext* context);
bool isInRenderPass(MetalContext* context);
} // namespace metal
} // namespace backend
} // namespace filament

View File

@@ -25,7 +25,6 @@
namespace filament {
namespace backend {
namespace metal {
void initializeSupportedGpuFamilies(MetalContext* context) {
auto& highestSupportedFamily = context->highestSupportedGpuFamily;
@@ -145,6 +144,5 @@ bool isInRenderPass(MetalContext* context) {
return context->currentRenderPassEncoder != nil;
}
} // namespace metal
} // namespace backend
} // namespace filament

View File

@@ -31,8 +31,6 @@ namespace backend {
class MetalPlatform;
namespace metal {
class MetalBuffer;
struct MetalUniformBuffer;
struct MetalContext;
@@ -44,31 +42,32 @@ struct UniformBufferState;
#endif
class MetalDriver final : public DriverBase {
explicit MetalDriver(backend::MetalPlatform* platform) noexcept;
explicit MetalDriver(MetalPlatform* platform) noexcept;
~MetalDriver() noexcept override;
Dispatcher getDispatcher() const noexcept final;
public:
static Driver* create(backend::MetalPlatform* platform);
static Driver* create(MetalPlatform* platform);
private:
friend class MetalSwapChain;
backend::MetalPlatform& mPlatform;
MetalPlatform& mPlatform;
MetalContext* mContext;
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
*/
template<typename T>
friend class backend::ConcreteDispatcher;
friend class ConcreteDispatcher;
#define DECL_DRIVER_API(methodName, paramsDecl, params) \
UTILS_ALWAYS_INLINE inline void methodName(paramsDecl);
@@ -86,7 +85,7 @@ private:
* Memory management
*/
backend::HandleAllocatorMTL mHandleAllocator;
HandleAllocatorMTL mHandleAllocator;
template<typename D>
Handle<D> alloc_handle() {
@@ -126,7 +125,6 @@ private:
};
} // namespace metal
} // namespace backend
} // namespace filament

View File

@@ -41,22 +41,23 @@ namespace filament {
namespace backend {
Driver* MetalDriverFactory::create(MetalPlatform* const platform) {
return metal::MetalDriver::create(platform);
return MetalDriver::create(platform);
}
namespace metal {
UTILS_NOINLINE
Driver* MetalDriver::create(MetalPlatform* const platform) {
assert_invariant(platform);
return new MetalDriver(platform);
}
MetalDriver::MetalDriver(backend::MetalPlatform* platform) noexcept
: DriverBase(new ConcreteDispatcher<MetalDriver>()),
mPlatform(*platform),
mContext(new MetalContext),
mHandleAllocator("Handles", FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U) {
Dispatcher MetalDriver::getDispatcher() const noexcept {
return ConcreteDispatcher<MetalDriver>::make();
}
MetalDriver::MetalDriver(MetalPlatform* platform) noexcept
: mPlatform(*platform),
mContext(new MetalContext),
mHandleAllocator("Handles", FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U) {
mContext->driver = this;
mContext->device = mPlatform.createDevice();
@@ -108,7 +109,7 @@ MetalDriver::MetalDriver(backend::MetalPlatform* platform) noexcept
mContext->blitter = new MetalBlitter(*mContext);
if (@available(iOS 12, *)) {
mContext->timerQueryImpl = new TimerQueryFence(*mContext);
mContext->timerQueryImpl = new MetalTimerQueryFence(*mContext);
} else {
mContext->timerQueryImpl = new TimerQueryNoop();
}
@@ -149,18 +150,18 @@ void MetalDriver::beginFrame(int64_t monotonic_clock_ns, uint32_t frameId) {
}
void MetalDriver::setFrameScheduledCallback(Handle<HwSwapChain> sch,
backend::FrameScheduledCallback callback, void* user) {
FrameScheduledCallback callback, void* user) {
auto* swapChain = handle_cast<MetalSwapChain>(sch);
swapChain->setFrameScheduledCallback(callback, user);
}
void MetalDriver::setFrameCompletedCallback(Handle<HwSwapChain> sch,
backend::FrameCompletedCallback callback, void* user) {
FrameCompletedCallback callback, void* user) {
auto* swapChain = handle_cast<MetalSwapChain>(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();
}
@@ -291,7 +292,7 @@ void MetalDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, int dum
void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
TargetBufferFlags targetBufferFlags, uint32_t width, uint32_t height,
uint8_t samples, backend::MRT color,
uint8_t samples, MRT color,
TargetBufferInfo depth, TargetBufferInfo stencil) {
// Clamp sample count to what the device supports.
auto& sc = mContext->sampleCountLookup;
@@ -344,7 +345,7 @@ void MetalDriver::createSyncR(Handle<HwSync> sh, int) {
}
void MetalDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags) {
if (UTILS_UNLIKELY(flags & backend::SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER)) {
if (UTILS_UNLIKELY(flags & SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER)) {
CVPixelBufferRef pixelBuffer = (CVPixelBufferRef) nativeWindow;
construct_handle<MetalSwapChain>(sch, *mContext, pixelBuffer, flags);
} else {
@@ -358,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
}
@@ -430,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.
@@ -569,7 +562,7 @@ Handle<HwStream> MetalDriver::createStreamAcquired() {
}
void MetalDriver::setAcquiredImage(Handle<HwStream> sh, void* image,
backend::CallbackHandler* handler, backend::StreamCallback cb, void* userData) {
CallbackHandler* handler, StreamCallback cb, void* userData) {
}
void MetalDriver::setStreamDimensions(Handle<HwStream> stream, uint32_t width,
@@ -581,7 +574,7 @@ int64_t MetalDriver::getStreamTimestamp(Handle<HwStream> stream) {
return 0;
}
void MetalDriver::updateStreams(backend::DriverApi* driver) {
void MetalDriver::updateStreams(DriverApi* driver) {
}
@@ -1052,14 +1045,9 @@ 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, backend::Viewport dstRect,
Handle<HwRenderTarget> src, backend::Viewport srcRect,
Handle<HwRenderTarget> dst, Viewport dstRect,
Handle<HwRenderTarget> src, Viewport srcRect,
SamplerMagFilter filter) {
// If we're the in middle of a render pass, finish it.
// This condition should only occur during copyFrame. It's okay to end the render pass because
@@ -1166,7 +1154,7 @@ void MetalDriver::blit(TargetBufferFlags buffers,
mContext->blitter->blit(getPendingCommandBuffer(mContext), args);
}
void MetalDriver::draw(backend::PipelineState ps, Handle<HwRenderPrimitive> rph, uint32_t instanceCount) {
void MetalDriver::draw(PipelineState ps, Handle<HwRenderPrimitive> rph, uint32_t instanceCount) {
ASSERT_PRECONDITION(mContext->currentRenderPassEncoder != nullptr,
"Attempted to draw without a valid command encoder.");
auto primitive = handle_cast<MetalRenderPrimitive>(rph);
@@ -1196,7 +1184,7 @@ void MetalDriver::draw(backend::PipelineState ps, Handle<HwRenderPrimitive> rph,
if (depthAttachment) {
depthPixelFormat = depthAttachment.getPixelFormat();
}
metal::PipelineState pipelineState {
MetalPipelineState pipelineState {
.vertexFunction = program->vertexFunction,
.fragmentFunction = program->fragmentFunction,
.vertexDescription = primitive->vertexDescription,
@@ -1304,15 +1292,15 @@ void MetalDriver::draw(backend::PipelineState ps, Handle<HwRenderPrimitive> rph,
return mContext->samplerStateCache.getOrCreateState(s);
};
id<MTLTexture> texturesToBindVertex[backend::MAX_VERTEX_SAMPLER_COUNT] = {};
id<MTLSamplerState> samplersToBindVertex[backend::MAX_VERTEX_SAMPLER_COUNT] = {};
id<MTLTexture> texturesToBindVertex[MAX_VERTEX_SAMPLER_COUNT] = {};
id<MTLSamplerState> samplersToBindVertex[MAX_VERTEX_SAMPLER_COUNT] = {};
enumerateSamplerGroups(program, ShaderType::VERTEX,
[this, &getTextureToBind, &getSamplerToBind, &texturesToBindVertex, &samplersToBindVertex](
const SamplerGroup::Sampler* sampler, uint8_t binding) {
// We currently only support a max of MAX_VERTEX_SAMPLER_COUNT samplers. Ignore any additional
// samplers that may be bound.
if (binding >= backend::MAX_VERTEX_SAMPLER_COUNT) {
if (binding >= MAX_VERTEX_SAMPLER_COUNT) {
return;
}
@@ -1336,21 +1324,21 @@ void MetalDriver::draw(backend::PipelineState ps, Handle<HwRenderPrimitive> rph,
}
}
NSRange vertexSamplerRange = NSMakeRange(0, backend::MAX_VERTEX_SAMPLER_COUNT);
NSRange vertexSamplerRange = NSMakeRange(0, MAX_VERTEX_SAMPLER_COUNT);
[mContext->currentRenderPassEncoder setVertexTextures:texturesToBindVertex
withRange:vertexSamplerRange];
[mContext->currentRenderPassEncoder setVertexSamplerStates:samplersToBindVertex
withRange:vertexSamplerRange];
id<MTLTexture> texturesToBindFragment[backend::MAX_FRAGMENT_SAMPLER_COUNT] = {};
id<MTLSamplerState> samplersToBindFragment[backend::MAX_FRAGMENT_SAMPLER_COUNT] = {};
id<MTLTexture> texturesToBindFragment[MAX_FRAGMENT_SAMPLER_COUNT] = {};
id<MTLSamplerState> samplersToBindFragment[MAX_FRAGMENT_SAMPLER_COUNT] = {};
enumerateSamplerGroups(program, ShaderType::FRAGMENT,
[this, &getTextureToBind, &getSamplerToBind, &texturesToBindFragment, &samplersToBindFragment](
const SamplerGroup::Sampler* sampler, uint8_t binding) {
// We currently only support a max of MAX_FRAGMENT_SAMPLER_COUNT samplers. Ignore any additional
// samplers that may be bound.
if (binding >= backend::MAX_FRAGMENT_SAMPLER_COUNT) {
if (binding >= MAX_FRAGMENT_SAMPLER_COUNT) {
return;
}
@@ -1374,7 +1362,7 @@ void MetalDriver::draw(backend::PipelineState ps, Handle<HwRenderPrimitive> rph,
}
}
NSRange fragmentSamplerRange = NSMakeRange(0, backend::MAX_FRAGMENT_SAMPLER_COUNT);
NSRange fragmentSamplerRange = NSMakeRange(0, MAX_FRAGMENT_SAMPLER_COUNT);
[mContext->currentRenderPassEncoder setFragmentTextures:texturesToBindFragment
withRange:fragmentSamplerRange];
[mContext->currentRenderPassEncoder setFragmentSamplerStates:samplersToBindFragment
@@ -1479,10 +1467,8 @@ void MetalDriver::enumerateBoundUniformBuffers(
}
}
} // namespace metal
// explicit instantiation of the Dispatcher
template class ConcreteDispatcher<metal::MetalDriver>;
template class ConcreteDispatcher<MetalDriver>;
} // namespace backend
} // namespace filament

View File

@@ -24,7 +24,7 @@ class Driver;
class MetalDriverFactory {
public:
static Driver* create(backend::MetalPlatform* platform);
static Driver* create(MetalPlatform* platform);
};
} // namespace backend

View File

@@ -27,7 +27,6 @@
namespace filament {
namespace backend {
namespace metal {
struct MetalContext;
@@ -405,7 +404,6 @@ inline MTLTextureSwizzleChannels getSwizzleChannels(TextureSwizzle r, TextureSwi
getSwizzle(a));
}
} // namespace metal
} // namespace backend
} // namespace filament

View File

@@ -20,7 +20,6 @@
namespace filament {
namespace backend {
namespace metal {
MTLPixelFormat getMetalFormat(MetalContext* context, TextureFormat format) noexcept {
switch (format) {
@@ -207,6 +206,5 @@ MTLPixelFormat getMetalFormat(MetalContext* context, TextureFormat format) noexc
return MTLPixelFormatInvalid;
}
} // namespace metal
} // namespace backend
} // namespace filament

View File

@@ -24,7 +24,6 @@
namespace filament {
namespace backend {
namespace metal {
struct MetalContext;
@@ -129,7 +128,6 @@ private:
} mSwizzle;
};
} // namespace metal
} // namespace backend
} // namespace filament

View File

@@ -32,7 +32,6 @@
namespace filament {
namespace backend {
namespace metal {
static const auto cvBufferDeleter = [](const void* buffer) {
CVBufferRelease((CVMetalTextureRef) buffer);
@@ -300,6 +299,5 @@ id<MTLCommandBuffer> MetalExternalImage::encodeColorConversionPass(id<MTLTexture
return commandBuffer;
}
} // namespace metal
} // namespace backend
} // namespace filament

View File

@@ -40,7 +40,6 @@
namespace filament {
namespace backend {
namespace metal {
class MetalSwapChain : public HwSwapChain {
public:
@@ -357,7 +356,6 @@ struct MetalTimerQuery : public HwTimerQuery {
std::shared_ptr<Status> status;
};
} // namespace metal
} // namespace backend
} // namespace filament

View File

@@ -32,7 +32,6 @@
namespace filament {
namespace backend {
namespace metal {
static inline MTLTextureUsage getMetalTextureUsage(TextureUsage usage) {
NSUInteger u = 0;
@@ -68,9 +67,8 @@ MetalSwapChain::MetalSwapChain(MetalContext& context, CAMetalLayer* nativeWindow
}
// Needed so we can use the SwapChain as a blit source.
if (flags & SwapChain::CONFIG_READABLE) {
nativeWindow.framebufferOnly = NO;
}
// Also needed for rendering directly into the SwapChain during refraction.
nativeWindow.framebufferOnly = NO;
layer.device = context.device;
}
@@ -81,7 +79,7 @@ MetalSwapChain::MetalSwapChain(MetalContext& context, int32_t width, int32_t hei
MetalSwapChain::MetalSwapChain(MetalContext& context, CVPixelBufferRef pixelBuffer, uint64_t flags)
: context(context), externalImage(context), type(SwapChainType::CVPIXELBUFFERREF) {
assert_invariant(flags & backend::SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER);
assert_invariant(flags & SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER);
MetalExternalImage::assertWritableImage(pixelBuffer);
externalImage.set(pixelBuffer);
assert_invariant(externalImage.isValid());
@@ -224,7 +222,7 @@ void MetalSwapChain::scheduleFrameScheduledCallback() {
}
assert_invariant(drawable);
backend::FrameScheduledCallback callback = frameScheduledCallback;
FrameScheduledCallback callback = frameScheduledCallback;
// This block strongly captures drawable to keep it alive until the handler executes.
// We cannot simply reference this->drawable inside the block because the block would then only
// capture the _this_ pointer (MetalSwapChain*) instead of the drawable.
@@ -245,12 +243,12 @@ void MetalSwapChain::scheduleFrameCompletedCallback() {
return;
}
backend::FrameCompletedCallback callback = frameCompletedCallback;
FrameCompletedCallback callback = frameCompletedCallback;
void* userData = frameCompletedUserData;
[getPendingCommandBuffer(&context) addCompletedHandler:^(id<MTLCommandBuffer> cb) {
struct CallbackData {
void* userData;
backend::FrameCompletedCallback callback;
FrameCompletedCallback callback;
};
CallbackData* data = new CallbackData();
data->userData = userData;
@@ -369,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
@@ -1024,6 +1022,5 @@ FenceStatus MetalFence::wait(uint64_t timeoutNs) {
return FenceStatus::ERROR;
}
} // namespace metal
} // namespace backend
} // namespace filament

View File

@@ -20,7 +20,6 @@
namespace filament {
namespace backend {
namespace metal {
bool MetalResourceTracker::trackResource(CommandBuffer buffer, Resource resource,
ResourceDeleter deleter) {
@@ -53,6 +52,5 @@ void MetalResourceTracker::clearResources(CommandBuffer buffer) {
mResources.erase(found);
}
} // namespace metal
} // namespace backend
} // namespace filament

View File

@@ -25,7 +25,6 @@
namespace filament {
namespace backend {
namespace metal {
/**
* MetalResourceTracker is a simple utility that maps individual command buffers to a set of
@@ -76,7 +75,6 @@ private:
std::mutex mMutex;
};
} // namespace metal
} // namespace backend
} // namespace filament

View File

@@ -31,24 +31,21 @@
namespace filament {
namespace backend {
inline bool operator==(const backend::SamplerParams& lhs, const backend::SamplerParams& rhs) {
inline bool operator==(const SamplerParams& lhs, const SamplerParams& rhs) {
return lhs.u == rhs.u;
}
namespace metal {
static constexpr uint32_t MAX_VERTEX_ATTRIBUTE_COUNT = backend::MAX_VERTEX_ATTRIBUTE_COUNT;
static constexpr uint32_t SAMPLER_GROUP_COUNT = Program::BINDING_COUNT;
static constexpr uint32_t SAMPLER_BINDING_COUNT = backend::MAX_SAMPLER_COUNT;
static constexpr uint32_t SAMPLER_BINDING_COUNT = MAX_SAMPLER_COUNT;
static constexpr uint32_t VERTEX_BUFFER_START = Program::BINDING_COUNT;
// The "zero" buffer is a small buffer for missing attributes that resides in the vertex slot
// immediately following any user-provided vertex buffers.
static constexpr uint32_t ZERO_VERTEX_BUFFER = backend::MAX_VERTEX_BUFFER_COUNT;
static constexpr uint32_t ZERO_VERTEX_BUFFER = MAX_VERTEX_BUFFER_COUNT;
// The total number of vertex buffer "slots" that the Metal backend can bind.
// + 1 to account for the zero buffer.
static constexpr uint32_t VERTEX_BUFFER_COUNT = backend::MAX_VERTEX_BUFFER_COUNT + 1;
static constexpr uint32_t VERTEX_BUFFER_COUNT = MAX_VERTEX_BUFFER_COUNT + 1;
// Forward declarations necessary here, definitions at end of file.
inline bool operator==(const MTLViewport& lhs, const MTLViewport& rhs);
@@ -173,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>
@@ -212,7 +209,7 @@ private:
// Pipeline state
struct PipelineState {
struct MetalPipelineState {
id<MTLFunction> vertexFunction = nil; // 8 bytes
id<MTLFunction> fragmentFunction = nil; // 8 bytes
VertexDescription vertexDescription; // 528 bytes
@@ -223,7 +220,7 @@ struct PipelineState {
bool colorWrite = true; // 1 byte
char padding[7] = { 0 }; // 7 bytes
bool operator==(const PipelineState& rhs) const noexcept {
bool operator==(const MetalPipelineState& rhs) const noexcept {
return (
this->vertexFunction == rhs.vertexFunction &&
this->fragmentFunction == rhs.fragmentFunction &&
@@ -237,23 +234,23 @@ struct PipelineState {
);
}
bool operator!=(const PipelineState& rhs) const noexcept {
bool operator!=(const MetalPipelineState& rhs) const noexcept {
return !operator==(rhs);
}
};
// This assert checks that the struct is the size we expect without any "hidden" padding bytes
// inserted by the compiler.
static_assert(sizeof(PipelineState) == 688, "PipelineState unexpected size.");
static_assert(sizeof(MetalPipelineState) == 688, "MetalPipelineState unexpected size.");
struct PipelineStateCreator {
id<MTLRenderPipelineState> operator()(id<MTLDevice> device, const PipelineState& state)
id<MTLRenderPipelineState> operator()(id<MTLDevice> device, const MetalPipelineState& state)
noexcept;
};
using PipelineStateTracker = StateTracker<PipelineState>;
using PipelineStateTracker = StateTracker<MetalPipelineState>;
using PipelineStateCache = StateCache<PipelineState, id<MTLRenderPipelineState>,
using PipelineStateCache = StateCache<MetalPipelineState, id<MTLRenderPipelineState>,
PipelineStateCreator>;
// Depth-stencil State
@@ -315,7 +312,7 @@ using UniformBufferStateTracker = StateTracker<UniformBufferState>;
// Sampler states
struct SamplerState {
backend::SamplerParams samplerParams;
SamplerParams samplerParams;
uint32_t minLod = 0;
uint32_t maxLod = UINT_MAX;
@@ -343,7 +340,6 @@ using SamplerStateCache = StateCache<SamplerState, id<MTLSamplerState>, SamplerS
using CullModeStateTracker = StateTracker<MTLCullMode>;
using WindingStateTracker = StateTracker<MTLWinding>;
} // namespace metal
} // namespace backend
} // namespace filament

View File

@@ -20,10 +20,9 @@
namespace filament {
namespace backend {
namespace metal {
id<MTLRenderPipelineState> PipelineStateCreator::operator()(id<MTLDevice> device,
const PipelineState& state) noexcept {
const MetalPipelineState& state) noexcept {
MTLRenderPipelineDescriptor* descriptor = [MTLRenderPipelineDescriptor new];
// Shader Functions
@@ -105,7 +104,7 @@ id<MTLDepthStencilState> DepthStateCreator::operator()(id<MTLDevice> device,
id<MTLSamplerState> SamplerStateCreator::operator()(id<MTLDevice> device,
const SamplerState& state) noexcept {
backend::SamplerParams params = state.samplerParams;
SamplerParams params = state.samplerParams;
MTLSamplerDescriptor* samplerDescriptor = [MTLSamplerDescriptor new];
samplerDescriptor.minFilter = getFilter(params.filterMin);
samplerDescriptor.magFilter = getFilter(params.filterMag);
@@ -133,6 +132,5 @@ id<MTLSamplerState> SamplerStateCreator::operator()(id<MTLDevice> device,
return [device newSamplerStateWithDescriptor:samplerDescriptor];
}
} // namespace metal
} // namespace backend
} // namespace filament

View File

@@ -23,14 +23,13 @@
namespace filament {
namespace backend {
namespace metal {
struct MetalTimerQuery;
struct MetalContext;
class TimerQueryInterface {
class MetalTimerQueryInterface {
public:
virtual ~TimerQueryInterface();
virtual ~MetalTimerQueryInterface();
virtual void beginTimeElapsedQuery(MetalTimerQuery* query) = 0;
virtual void endTimeElapsedQuery(MetalTimerQuery* query) = 0;
virtual bool getQueryResult(MetalTimerQuery* query, uint64_t* outElapsedTime) = 0;
@@ -41,9 +40,9 @@ protected:
// Uses MTLSharedEvents to implement timer queries.
// Only available on >= iOS 12.0.
class API_AVAILABLE(ios(12.0)) TimerQueryFence : public TimerQueryInterface {
class API_AVAILABLE(ios(12.0)) MetalTimerQueryFence : public MetalTimerQueryInterface {
public:
explicit TimerQueryFence(MetalContext& context) : mContext(context) {}
explicit MetalTimerQueryFence(MetalContext& context) : mContext(context) {}
void beginTimeElapsedQuery(MetalTimerQuery* query) override;
void endTimeElapsedQuery(MetalTimerQuery* query) override;
@@ -53,14 +52,13 @@ private:
MetalContext& mContext;
};
class TimerQueryNoop : public TimerQueryInterface {
class TimerQueryNoop : public MetalTimerQueryInterface {
public:
void beginTimeElapsedQuery(MetalTimerQuery* query) override {}
void endTimeElapsedQuery(MetalTimerQuery* query) override {}
bool getQueryResult(MetalTimerQuery* query, uint64_t* outElapsedTime) override;
};
} // namespace metal
} // namespace backend
} // namespace filament

View File

@@ -20,11 +20,10 @@
namespace filament {
namespace backend {
namespace metal {
TimerQueryInterface::~TimerQueryInterface() = default;
MetalTimerQueryInterface::~MetalTimerQueryInterface() = default;
void TimerQueryFence::beginTimeElapsedQuery(MetalTimerQuery* query) {
void MetalTimerQueryFence::beginTimeElapsedQuery(MetalTimerQuery* query) {
auto* fence = new MetalFence(mContext);
fence->encode();
query->status->elapsed = 0;
@@ -41,7 +40,7 @@ void TimerQueryFence::beginTimeElapsedQuery(MetalTimerQuery* query) {
});
}
void TimerQueryFence::endTimeElapsedQuery(MetalTimerQuery* query) {
void MetalTimerQueryFence::endTimeElapsedQuery(MetalTimerQuery* query) {
auto* fence = new MetalFence(mContext);
fence->encode();
@@ -57,7 +56,7 @@ void TimerQueryFence::endTimeElapsedQuery(MetalTimerQuery* query) {
});
}
bool TimerQueryFence::getQueryResult(MetalTimerQuery* query, uint64_t* outElapsedTime) {
bool MetalTimerQueryFence::getQueryResult(MetalTimerQuery* query, uint64_t* outElapsedTime) {
if (!query->status->available.load()) {
return false;
}
@@ -71,6 +70,5 @@ bool TimerQueryNoop::getQueryResult(MetalTimerQuery* query, uint64_t* outElapsed
return false;
}
} // namespace metal
} // namespace backend
} // namespace filament

View File

@@ -19,7 +19,7 @@
#include <Metal/Metal.h>
namespace filament::backend::metal {
namespace filament::backend {
/**
* Creates a texture view of the passed-in texture with the given swizzle. If swizzle is the default
@@ -42,6 +42,6 @@ id<MTLTexture> createTextureViewWithSwizzle(id<MTLTexture> texture,
*/
id<MTLTexture> createTextureViewWithSingleSlice(id<MTLTexture> texture, NSUInteger slice);
} // namespace filament::backend::metal
} // namespace filament::backend
#endif //TNT_FILAMENT_DRIVER_METALUTILS_H

View File

@@ -16,7 +16,7 @@
#include "MetalUtils.h"
namespace filament::backend::metal {
namespace filament::backend {
id<MTLTexture> createTextureViewWithSwizzle(id<MTLTexture> texture,
MTLTextureSwizzleChannels swizzle) {
@@ -48,4 +48,4 @@ id<MTLTexture> createTextureViewWithSingleSlice(id<MTLTexture> texture, NSUInteg
slices:NSMakeRange(slice, 1)];
}
}
} // namespace filament::backend

View File

@@ -17,20 +17,21 @@
#include "noop/NoopDriver.h"
#include "CommandStreamDispatcher.h"
namespace filament {
using namespace backend;
namespace filament::backend {
Driver* NoopDriver::create() {
return new NoopDriver();
}
NoopDriver::NoopDriver() noexcept : DriverBase(new ConcreteDispatcher<NoopDriver>()) {
}
NoopDriver::NoopDriver() noexcept = default;
NoopDriver::~NoopDriver() noexcept = default;
backend::ShaderModel NoopDriver::getShaderModel() const noexcept {
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;
#else
@@ -39,7 +40,7 @@ backend::ShaderModel NoopDriver::getShaderModel() const noexcept {
}
// explicit instantiation of the Dispatcher
template class backend::ConcreteDispatcher<NoopDriver>;
template class ConcreteDispatcher<NoopDriver>;
void NoopDriver::terminate() {
@@ -52,12 +53,12 @@ void NoopDriver::beginFrame(int64_t monotonic_clock_ns, uint32_t frameId) {
}
void NoopDriver::setFrameScheduledCallback(Handle<HwSwapChain> sch,
backend::FrameScheduledCallback callback, void* user) {
FrameScheduledCallback callback, void* user) {
}
void NoopDriver::setFrameCompletedCallback(Handle<HwSwapChain> sch,
backend::FrameCompletedCallback callback, void* user) {
FrameCompletedCallback callback, void* user) {
}
@@ -118,7 +119,7 @@ Handle<HwStream> NoopDriver::createStreamAcquired() {
}
void NoopDriver::setAcquiredImage(Handle<HwStream> sh, void* image,
backend::CallbackHandler* handler, backend::StreamCallback cb, void* userData) {
CallbackHandler* handler, StreamCallback cb, void* userData) {
}
void NoopDriver::setStreamDimensions(Handle<HwStream> sh, uint32_t width, uint32_t height) {
@@ -148,7 +149,7 @@ bool NoopDriver::isTextureSwizzleSupported() {
return true;
}
bool NoopDriver::isTextureFormatMipmappable(backend::TextureFormat format) {
bool NoopDriver::isTextureFormatMipmappable(TextureFormat format) {
return true;
}
@@ -181,7 +182,7 @@ math::float2 NoopDriver::getClipSpaceParams() {
}
uint8_t NoopDriver::getMaxDrawBuffers() {
return backend::MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT;
return MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT;
}
void NoopDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
@@ -307,14 +308,9 @@ 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, backend::Viewport dstRect,
Handle<HwRenderTarget> src, backend::Viewport srcRect,
Handle<HwRenderTarget> dst, Viewport dstRect,
Handle<HwRenderTarget> src, Viewport srcRect,
SamplerMagFilter filter) {
}

View File

@@ -14,32 +14,33 @@
* limitations under the License.
*/
#ifndef TNT_FILAMENT_DRIVER_NOOPDRIVER_H
#define TNT_FILAMENT_DRIVER_NOOPDRIVER_H
#ifndef TNT_FILAMENT_BACKEND_NOOPDRIVER_H
#define TNT_FILAMENT_BACKEND_NOOPDRIVER_H
#include "private/backend/Driver.h"
#include "DriverBase.h"
#include <utils/compiler.h>
namespace filament {
namespace filament::backend {
class NoopDriver final : public backend::DriverBase {
class NoopDriver final : public DriverBase {
NoopDriver() noexcept;
~NoopDriver() noexcept override;
Dispatcher getDispatcher() const noexcept final;
public:
static backend::Driver* create();
static Driver* create();
private:
backend::ShaderModel getShaderModel() const noexcept final;
ShaderModel getShaderModel() const noexcept final;
/*
* Driver interface
*/
template<typename T>
friend class backend::ConcreteDispatcher;
friend class ConcreteDispatcher;
#define DECL_DRIVER_API(methodName, paramsDecl, params) \
UTILS_ALWAYS_INLINE inline void methodName(paramsDecl);
@@ -57,4 +58,4 @@ private:
} // namespace filament
#endif // TNT_FILAMENT_DRIVER_NOOPDRIVER_H
#endif // TNT_FILAMENT_BACKEND_NOOPDRIVER_H

View File

@@ -18,9 +18,9 @@
#include "noop/NoopDriver.h"
namespace filament {
namespace filament::backend {
backend::Driver* PlatformNoop::createDriver(void* const sharedGLContext) noexcept {
Driver* PlatformNoop::createDriver(void* const sharedGLContext) noexcept {
return NoopDriver::create();
}

View File

@@ -14,15 +14,15 @@
* limitations under the License.
*/
#ifndef TNT_FILAMENT_DRIVER_NOOP_PLATFORM_NOOP_H
#define TNT_FILAMENT_DRIVER_NOOP_PLATFORM_NOOP_H
#ifndef TNT_FILAMENT_BACKEND_NOOP_PLATFORM_NOOP_H
#define TNT_FILAMENT_BACKEND_NOOP_PLATFORM_NOOP_H
#include <backend/DriverEnums.h>
#include <backend/Platform.h>
namespace filament {
namespace filament::backend {
class PlatformNoop final : public backend::DefaultPlatform {
class PlatformNoop final : public DefaultPlatform {
public:
int getOSVersion() const noexcept final { return 0; }
@@ -31,9 +31,9 @@ public:
protected:
backend::Driver* createDriver(void* sharedContext) noexcept override;
Driver* createDriver(void* sharedContext) noexcept override;
};
} // namespace filament
#endif // TNT_FILAMENT_DRIVER_NOOP_PLATFORM_NOOP_H
#endif // TNT_FILAMENT_BACKEND_NOOP_PLATFORM_NOOP_H

View File

@@ -20,7 +20,7 @@
#include "private/backend/Driver.h"
namespace filament {
namespace filament::backend {
using namespace backend;
using namespace utils;
@@ -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
} // namespace filament::backend

View File

@@ -14,22 +14,22 @@
* limitations under the License.
*/
#ifndef TNT_FILAMENT_DRIVER_GLUTILS_H
#define TNT_FILAMENT_DRIVER_GLUTILS_H
#ifndef TNT_FILAMENT_BACKEND_OPENGL_GLUTILS_H
#define TNT_FILAMENT_BACKEND_OPENGL_GLUTILS_H
#include <utils/compiler.h>
#include <utils/Log.h>
#include <backend/DriverEnums.h>
#include <string>
#include <string_view>
#include <unordered_set>
#include <string.h>
#include "gl_headers.h"
namespace filament {
namespace filament::backend {
namespace GLUtils {
const char* getGLError(GLenum error) noexcept;
@@ -44,15 +44,12 @@ void assertFramebufferStatus(utils::io::ostream& out, GLenum target, const char*
# define CHECK_GL_ERROR(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_FRAMEBUFFER_STATUS(out, target) { GLUtils::checkFramebufferStatus(out, target, __func__, __LINE__); }
#endif
constexpr inline GLuint getComponentCount(backend::ElementType type) noexcept {
using ElementType = backend::ElementType;
constexpr inline GLuint getComponentCount(ElementType type) noexcept {
using ElementType = ElementType;
switch (type) {
case ElementType::BYTE:
case ElementType::UBYTE:
@@ -91,35 +88,35 @@ constexpr inline GLuint getComponentCount(backend::ElementType type) noexcept {
// Our enums to GLenum conversions
// ------------------------------------------------------------------------------------------------
constexpr inline GLbitfield getAttachmentBitfield(backend::TargetBufferFlags flags) noexcept {
constexpr inline GLbitfield getAttachmentBitfield(TargetBufferFlags flags) noexcept {
GLbitfield mask = 0;
if (any(flags & backend::TargetBufferFlags::COLOR_ALL)) {
if (any(flags & TargetBufferFlags::COLOR_ALL)) {
mask |= (GLbitfield)GL_COLOR_BUFFER_BIT;
}
if (any(flags & backend::TargetBufferFlags::DEPTH)) {
if (any(flags & TargetBufferFlags::DEPTH)) {
mask |= (GLbitfield)GL_DEPTH_BUFFER_BIT;
}
if (any(flags & backend::TargetBufferFlags::STENCIL)) {
if (any(flags & TargetBufferFlags::STENCIL)) {
mask |= (GLbitfield)GL_STENCIL_BUFFER_BIT;
}
return mask;
}
constexpr inline GLenum getBufferUsage(backend::BufferUsage usage) noexcept {
constexpr inline GLenum getBufferUsage(BufferUsage usage) noexcept {
switch (usage) {
case backend::BufferUsage::STATIC:
case BufferUsage::STATIC:
return GL_STATIC_DRAW;
case backend::BufferUsage::DYNAMIC:
case backend::BufferUsage::STREAM:
case BufferUsage::DYNAMIC:
case BufferUsage::STREAM:
return GL_DYNAMIC_DRAW;
}
}
constexpr inline GLenum getBufferBindingType(backend::BufferObjectBinding bindingType) noexcept {
constexpr inline GLenum getBufferBindingType(BufferObjectBinding bindingType) noexcept {
switch (bindingType) {
case backend::BufferObjectBinding::VERTEX:
case BufferObjectBinding::VERTEX:
return GL_ARRAY_BUFFER;
case backend::BufferObjectBinding::UNIFORM:
case BufferObjectBinding::UNIFORM:
return GL_UNIFORM_BUFFER;
}
}
@@ -128,8 +125,8 @@ constexpr inline GLboolean getNormalization(bool normalized) noexcept {
return GLboolean(normalized ? GL_TRUE : GL_FALSE);
}
constexpr inline GLenum getComponentType(backend::ElementType type) noexcept {
using ElementType = backend::ElementType;
constexpr inline GLenum getComponentType(ElementType type) noexcept {
using ElementType = ElementType;
switch (type) {
case ElementType::BYTE:
case ElementType::BYTE2:
@@ -173,8 +170,8 @@ constexpr inline GLenum getCubemapTarget(uint16_t layer) noexcept {
return GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer;
}
constexpr inline GLenum getWrapMode(backend::SamplerWrapMode mode) noexcept {
using SamplerWrapMode = backend::SamplerWrapMode;
constexpr inline GLenum getWrapMode(SamplerWrapMode mode) noexcept {
using SamplerWrapMode = SamplerWrapMode;
switch (mode) {
case SamplerWrapMode::REPEAT:
return GL_REPEAT;
@@ -185,8 +182,8 @@ constexpr inline GLenum getWrapMode(backend::SamplerWrapMode mode) noexcept {
}
}
constexpr inline GLenum getTextureFilter(backend::SamplerMinFilter filter) noexcept {
using SamplerMinFilter = backend::SamplerMinFilter;
constexpr inline GLenum getTextureFilter(SamplerMinFilter filter) noexcept {
using SamplerMinFilter = SamplerMinFilter;
switch (filter) {
case SamplerMinFilter::NEAREST:
case SamplerMinFilter::LINEAR:
@@ -200,13 +197,13 @@ constexpr inline GLenum getTextureFilter(backend::SamplerMinFilter filter) noexc
}
}
constexpr inline GLenum getTextureFilter(backend::SamplerMagFilter filter) noexcept {
constexpr inline GLenum getTextureFilter(SamplerMagFilter filter) noexcept {
return GL_NEAREST + GLenum(filter);
}
constexpr inline GLenum getBlendEquationMode(backend::BlendEquation mode) noexcept {
using BlendEquation = backend::BlendEquation;
constexpr inline GLenum getBlendEquationMode(BlendEquation mode) noexcept {
using BlendEquation = BlendEquation;
switch (mode) {
case BlendEquation::ADD: return GL_FUNC_ADD;
case BlendEquation::SUBTRACT: return GL_FUNC_SUBTRACT;
@@ -216,8 +213,8 @@ constexpr inline GLenum getBlendEquationMode(backend::BlendEquation mode) noexce
}
}
constexpr inline GLenum getBlendFunctionMode(backend::BlendFunction mode) noexcept {
using BlendFunction = backend::BlendFunction;
constexpr inline GLenum getBlendFunctionMode(BlendFunction mode) noexcept {
using BlendFunction = BlendFunction;
switch (mode) {
case BlendFunction::ZERO: return GL_ZERO;
case BlendFunction::ONE: return GL_ONE;
@@ -233,13 +230,13 @@ constexpr inline GLenum getBlendFunctionMode(backend::BlendFunction mode) noexce
}
}
constexpr inline GLenum getTextureCompareMode(backend::SamplerCompareMode mode) noexcept {
return mode == backend::SamplerCompareMode::NONE ?
constexpr inline GLenum getTextureCompareMode(SamplerCompareMode mode) noexcept {
return mode == SamplerCompareMode::NONE ?
GL_NONE : GL_COMPARE_REF_TO_TEXTURE;
}
constexpr inline GLenum getTextureCompareFunc(backend::SamplerCompareFunc func) noexcept {
using SamplerCompareFunc = backend::SamplerCompareFunc;
constexpr inline GLenum getTextureCompareFunc(SamplerCompareFunc func) noexcept {
using SamplerCompareFunc = SamplerCompareFunc;
switch (func) {
case SamplerCompareFunc::LE: return GL_LEQUAL;
case SamplerCompareFunc::GE: return GL_GEQUAL;
@@ -252,12 +249,12 @@ constexpr inline GLenum getTextureCompareFunc(backend::SamplerCompareFunc func)
}
}
constexpr inline GLenum getDepthFunc(backend::SamplerCompareFunc func) noexcept {
constexpr inline GLenum getDepthFunc(SamplerCompareFunc func) noexcept {
return getTextureCompareFunc(func);
}
constexpr inline GLenum getFormat(backend::PixelDataFormat format) noexcept {
using PixelDataFormat = backend::PixelDataFormat;
constexpr inline GLenum getFormat(PixelDataFormat format) noexcept {
using PixelDataFormat = PixelDataFormat;
switch (format) {
case PixelDataFormat::R: return GL_RED;
case PixelDataFormat::R_INTEGER: return GL_RED_INTEGER;
@@ -274,8 +271,8 @@ constexpr inline GLenum getFormat(backend::PixelDataFormat format) noexcept {
}
}
constexpr inline GLenum getType(backend::PixelDataType type) noexcept {
using PixelDataType = backend::PixelDataType;
constexpr inline GLenum getType(PixelDataType type) noexcept {
using PixelDataType = PixelDataType;
switch (type) {
case PixelDataType::UBYTE: return GL_UNSIGNED_BYTE;
case PixelDataType::BYTE: return GL_BYTE;
@@ -292,8 +289,8 @@ constexpr inline GLenum getType(backend::PixelDataType type) noexcept {
}
}
constexpr inline GLenum getSwizzleChannel(backend::TextureSwizzle c) noexcept {
using TextureSwizzle = backend::TextureSwizzle;
constexpr inline GLenum getSwizzleChannel(TextureSwizzle c) noexcept {
using TextureSwizzle = TextureSwizzle;
switch (c) {
case TextureSwizzle::SUBSTITUTE_ZERO:
return GL_ZERO;
@@ -313,8 +310,8 @@ constexpr inline GLenum getSwizzleChannel(backend::TextureSwizzle c) noexcept {
// clang looses it on this one, and generates a huge jump table when
// inlined. So we don't mark it as inline (only constexpr) which solves the problem,
// strangely, when not inlined, clang simply generates an array lookup.
constexpr /* inline */ GLenum getInternalFormat(backend::TextureFormat format) noexcept {
using TextureFormat = backend::TextureFormat;
constexpr /* inline */ GLenum getInternalFormat(TextureFormat format) noexcept {
using TextureFormat = TextureFormat;
switch (format) {
// 8-bits per element
case TextureFormat::R8: return GL_R8;
@@ -507,29 +504,14 @@ constexpr /* inline */ GLenum getInternalFormat(backend::TextureFormat format) n
}
}
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
} // namespace filament::backend
#endif // TNT_FILAMENT_DRIVER_GLUTILS_H
#endif // TNT_FILAMENT_BACKEND_OPENGL_GLUTILS_H

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#ifndef TNT_FILAMENT_DRIVER_NULLGLES_H
#define TNT_FILAMENT_DRIVER_NULLGLES_H
#ifndef TNT_FILAMENT_BACKEND_OPENGL_NULLGLES_H
#define TNT_FILAMENT_BACKEND_OPENGL_NULLGLES_H
/*
* This is used for debugging (stubbing out GLES calls)
@@ -27,7 +27,7 @@
*
*/
namespace filament {
namespace filament::backend {
namespace nullgles {
inline void glScissor(GLint, GLint, GLsizei, GLsizei) { }
@@ -81,6 +81,6 @@ inline GLenum glGetError() { return GL_NO_ERROR; }
// turn GLES calls defined above into no-ops
//using namespace nullgles;
} // namespace filament
} // namespace filament::backend
#endif // TNT_FILAMENT_DRIVER_NULLGLES_H
#endif // TNT_FILAMENT_BACKEND_OPENGL_NULLGLES_H

View File

@@ -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 {
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

View File

@@ -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_DRIVER_OPENGLBLITTER_H
#define TNT_FILAMENT_DRIVER_OPENGLBLITTER_H
#include <utils/compiler.h>
#include "gl_headers.h"
namespace filament {
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
#endif // TNT_FILAMENT_DRIVER_OPENGLBLITTER_H

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 {
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,81 @@ 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);
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");
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 +372,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 +380,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 +412,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 +422,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 +435,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 +443,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;

View File

@@ -30,47 +30,46 @@
#include <set>
#include <utility>
namespace filament {
namespace filament::backend {
class OpenGLContext {
public:
static constexpr const size_t MAX_TEXTURE_UNIT_COUNT = backend::MAX_SAMPLER_COUNT;
static constexpr const size_t MAX_TEXTURE_UNIT_COUNT = MAX_SAMPLER_COUNT;
static constexpr const size_t MAX_BUFFER_BINDINGS = 32;
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.
backend::Handle<backend::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;
constexpr static inline size_t getIndexForBufferTarget(GLenum target) noexcept;
backend::ShaderModel getShaderModel() const noexcept { return mShaderModel; }
ShaderModel getShaderModel() const noexcept { return mShaderModel; }
inline void useProgram(GLuint program) 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:
backend::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;

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