Compare commits

..
Author SHA1 Message Date
Benjamin Doherty 15424c85b5 Metal: use atomic for buffer tracking 2025-09-19 13:41:37 -07:00
125 changed files with 1126 additions and 3781 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
name: build-android
# We intentially use a larger runner here to enable larger disk space
# (standard linux runner will fail on disk space and faster build time).
runs-on: 'ubuntu-24.04-16core'
runs-on: 'ubuntu-24.04-32core'
steps:
- uses: actions/checkout@v4.1.6
+2 -2
View File
@@ -26,7 +26,7 @@ jobs:
build-desktop-linux:
name: build-linux
runs-on: 'ubuntu-24.04-16core'
runs-on: ubuntu-22.04-16core
steps:
- uses: actions/checkout@v4.1.6
with:
@@ -171,7 +171,7 @@ jobs:
validate-wgsl-webgpu:
name: validate-wgsl-webgpu
runs-on: 'ubuntu-24.04-16core'
runs-on: 'ubuntu-24.04-8core'
steps:
- uses: actions/checkout@v4.1.6
with:
+1 -1
View File
@@ -31,7 +31,7 @@ on:
jobs:
build-linux:
name: build-linux
runs-on: 'ubuntu-24.04-16core'
runs-on: ubuntu-22.04-32core
if: github.event_name == 'release' || github.event.inputs.platform == 'desktop'
steps:
-6
View File
@@ -18,9 +18,3 @@ test*.json
results
/compile_commands.json
/.cache
# For /test/renderdiff dependencies
/mesa
/gltf
/filament-assets
/venv
+2 -2
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.65.2'
implementation 'com.google.android.filament:filament-android:1.65.0'
}
```
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
iOS projects can use CocoaPods to install the latest release:
```shell
pod 'Filament', '~> 1.65.2'
pod 'Filament', '~> 1.65.0'
```
## Documentation
-6
View File
@@ -7,12 +7,6 @@ A new header is inserted each time a *tag* is created.
Instead, if you are authoring a PR for the main branch, add your release note to
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
## v1.65.3
## v1.65.2
## v1.65.1
- `setFrameScheduledCallback` now works on all backends (frame presentation scheduling is still only
@@ -28,8 +28,9 @@ Java_com_google_android_filament_SwapChain_nSetFrameCompletedCallback(JNIEnv* en
jlong nativeSwapChain, jobject handler, jobject runnable) {
SwapChain* swapChain = (SwapChain*) nativeSwapChain;
auto* callback = JniCallback::make(env, handler, runnable);
swapChain->setFrameCompletedCallback(callback->getHandler(),
[callback](SwapChain* swapChain) { JniCallback::postToJavaAndDestroy(callback); });
swapChain->setFrameCompletedCallback(nullptr, [callback](SwapChain* swapChain) {
JniCallback::postToJavaAndDestroy(callback);
});
}
extern "C" JNIEXPORT jboolean JNICALL
@@ -52,22 +53,3 @@ Java_com_google_android_filament_SwapChain_nIsProtectedContentSupported(
Engine* engine = (Engine*) nativeEngine;
return (jboolean)SwapChain::isProtectedContentSupported(*engine);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_SwapChain_nSetFrameScheduledCallback(JNIEnv* env, jclass,
jlong nativeSwapChain, jobject handler, jobject runnable) {
SwapChain* swapChain = (SwapChain*) nativeSwapChain;
auto* callback = JniCallback::make(env, handler, runnable);
swapChain->setFrameScheduledCallback(callback->getHandler(),
[callback](backend::PresentCallable) {
// Ignore PresentCallable, which is only meaningful with the Metal backend.
JniCallback::postToJavaAndDestroy(callback);
});
}
extern "C" JNIEXPORT jboolean JNICALL
Java_com_google_android_filament_SwapChain_nIsFrameScheduledCallbackSet(
JNIEnv *, jclass, jlong nativeSwapChain) {
SwapChain* swapChain = (SwapChain*) nativeSwapChain;
return (jboolean)swapChain->isFrameScheduledCallbackSet();
}
@@ -139,78 +139,6 @@ public class SwapChain {
nSetFrameCompletedCallback(getNativeObject(), handler, callback);
}
/**
* FrameScheduledCallback is a callback function that notifies an application about the status
* of a frame after Filament has finished its processing.
*
* <p>
* The exact timing and semantics of this callback differ depending on the graphics backend in
* use.
* </p>
*
* <h3>Metal Backend</h3>
* <p>
* With the Metal backend, this callback signifies that Filament has completed all CPU-side
* processing for a frame and the frame is ready to be scheduled for presentation.
* </p>
*
* <p>
* Typically, Filament is responsible for scheduling the frame's presentation to the SwapChain.
* If a FrameScheduledCallback is set, however, the application bears the responsibility of
* scheduling the frame for presentation by calling the PresentCallable passed to the callback
* function. In this mode, Filament will not automatically schedule the frame for presentation.
* </p>
*
* <p>
* When using the Metal backend, if your application delays the call to the PresentCallable
* (e.g., by invoking it on a separate thread), you must ensure all PresentCallables have been
* called before shutting down the Filament Engine. You can guarantee this by calling
* Engine.flushAndWait() before Engine.shutdown(). This is necessary to ensure the Engine has
* a chance to clean up all memory related to frame presentation.
* </p>
*
* <h3>Other Backends (OpenGL, Vulkan, WebGPU)</h3>
* <p>
* On other backends, this callback serves as a notification that Filament has completed all
* CPU-side processing for a frame. Filament proceeds with its normal presentation logic
* automatically, and the PresentCallable passed to the callback is a no-op that can be safely
* ignored.
* </p>
*
* <h3>General Behavior</h3>
* <p>
* A FrameScheduledCallback can be set on an individual SwapChain through
* setFrameScheduledCallback. Each SwapChain can have only one callback set per frame. If
* setFrameScheduledCallback is called multiple times on the same SwapChain before
* Renderer.endFrame(), the most recent call effectively overwrites any previously set callback.
* </p>
*
* <p>
* The callback set by setFrameScheduledCallback is "latched" when Renderer.endFrame() is
* executed. At this point, the callback is fixed for the frame that was just encoded.
* Subsequent calls to setFrameScheduledCallback after endFrame() will apply to the next frame.
* </p>
*
* <p>
* Use setFrameScheduledCallback() (with default arguments) to unset the callback.
* </p>
*
* @param handler A {@link java.util.concurrent.Executor Executor}.
* @param callback The Runnable callback to invoke when frame processing is complete.
*/
public void setFrameScheduledCallback(@NonNull Object handler, @NonNull Runnable callback) {
nSetFrameScheduledCallback(getNativeObject(), handler, callback);
}
/**
* Returns whether this SwapChain currently has a FrameScheduledCallback set.
*
* @return true, if the last call to setFrameScheduledCallback set a callback
*/
public boolean isFrameScheduledCallbackSet() {
return nIsFrameScheduledCallbackSet(getNativeObject());
}
public long getNativeObject() {
if (mNativeObject == 0) {
throw new IllegalStateException("Calling method on destroyed SwapChain");
@@ -223,8 +151,6 @@ public class SwapChain {
}
private static native void nSetFrameCompletedCallback(long nativeSwapChain, Object handler, Runnable callback);
private static native void nSetFrameScheduledCallback(long nativeSwapChain, Object handler, Runnable callback);
private static native boolean nIsFrameScheduledCallbackSet(long nativeSwapChain);
private static native boolean nIsSRGBSwapChainSupported(long nativeEngine);
private static native boolean nIsMSAASwapChainSupported(long nativeEngine, int samples);
private static native boolean nIsProtectedContentSupported(long nativeEngine);
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.65.2
VERSION_NAME=1.65.0
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
@@ -24,7 +24,7 @@ android {
compileSdkVersion versions.compileSdk
defaultConfig {
applicationId "com.google.android.filament.hellocam"
applicationId "com.google.android.filament.hellocamera"
minSdkVersion 23
targetSdkVersion versions.targetSdk
}
+2 -2
View File
@@ -181,7 +181,7 @@ important for <code>matc</code> (material compiler).</p>
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.65.1'
implementation 'com.google.android.filament:filament-android:1.65.0'
}
</code></pre>
<p>Here are all the libraries available in the group <code>com.google.android.filament</code>:</p>
@@ -196,7 +196,7 @@ dependencies {
</div>
<h3 id="ios"><a class="header" href="#ios">iOS</a></h3>
<p>iOS projects can use CocoaPods to install the latest release:</p>
<pre><code class="language-shell">pod 'Filament', '~&gt; 1.65.1'
<pre><code class="language-shell">pod 'Filament', '~&gt; 1.65.0'
</code></pre>
<h2 id="documentation"><a class="header" href="#documentation">Documentation</a></h2>
<ul>
-334
View File
@@ -1,334 +0,0 @@
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>renderdiff - Filament</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- MathJax -->
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div style="display:flex;align-items:center;justify-content:center">
<img class="flogo" src="../images/filament_logo_small.png"></img>
</div>
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
<!--
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
-->
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Filament</h1>
<div class="right-buttons">
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="rendering-difference-test"><a class="header" href="#rendering-difference-test">Rendering Difference Test</a></h1>
<p>We created a few scripts to run <code>gltf_viewer</code> and produce headless renderings.</p>
<p>This is mainly useful for continuous integration where GPUs are generally not available on cloud
machines. To perform software rasterization, these scripts are centered around <a href="https://docs.mesa3d.org">Mesa</a>'s software
rasterizers, but nothing bars us from using another rasterizer like <a href="https://github.com/google/swiftshader">SwiftShader</a>. Additionally,
we should be able to use GPUs where available (though this is more of a future work).</p>
<p>The script <code>render.py</code> contains the core logic for taking input parameters (such as the test
description file) and then running gltf_viewer to produce the renderings.</p>
<p>In the <code>test</code> directory is a list of test descriptions that are specified in json. Please see
<code>sample.json</code> to parse the structure.</p>
<h2 id="setting-up-python"><a class="header" href="#setting-up-python">Setting up python</a></h2>
<p>The <code>renderdiff</code> project uses <code>python</code> extensively. To install the dependencies for producing
renderings, do the following step</p>
<ul>
<li>Set up a virtual environment (from the root directory)
<pre><code> python3 -m venv venv
. ./venv/bin/activate
</code></pre>
</li>
<li>Install the rendering dependencies
<pre><code> pip install -r test/renderdiff/src/rendering_requirements.txt
</code></pre>
</li>
<li>Install the viewer depdencies
<pre><code> pip install -r test/renderdiff/src/viewer_requirements.txt
</code></pre>
</li>
<li>For the commands in the following section, do not exit the virtual environment. Once you've
completed all your work, you can exit with
<pre><code> deactivate
</code></pre>
</li>
</ul>
<h2 id="running-the-test-locally"><a class="header" href="#running-the-test-locally">Running the test locally</a></h2>
<ul>
<li>
<p>To run the same presbumit as <a href="presubmit-renderdiff"><code>test-renderdiff</code></a>, you can do</p>
<pre><code>bash test/renderdiff/local_test.sh
</code></pre>
</li>
<li>
<p>This script will generate the renderings based on the current state of your repo.
Additionally, it will also compare the generated images with corresponding images in the
golden repo.</p>
</li>
<li>
<p>To just render without running the test, you could use the following script</p>
<pre><code>bash test/renderdiff/generate.sh
</code></pre>
</li>
</ul>
<h2 id="update-the-golden-images"><a class="header" href="#update-the-golden-images">Update the golden images</a></h2>
<p>The golden images are stored in a github repository: https://github.com/google/filament-assets.
Filament team members should have access to write to the repository. A typical flow for updating
the goldens is to upload your changed images into <strong>branch</strong> of <code>filament-assets</code>. This branch is
paired with a PR or commit on the <code>filament</code> repo.</p>
<p>As an example, imagine I am working on a PR, and I've uploaded my change, which is in a branch
called <code>my-pr-branch</code>, to <code>filament</code>. This PR requires updating the golden. We would do it
in the following fashion</p>
<h3 id="using-a-script-to-update-the-golden-repo"><a class="header" href="#using-a-script-to-update-the-golden-repo">Using a script to update the golden repo</a></h3>
<ul>
<li>
<p>Run interactive mode in the <code>update_golden.py</code> script.</p>
<pre><code>python3 test/renderdiff/src/update_golden.py
</code></pre>
</li>
<li>
<p>This will guide you through a series of steps to push the changes to a remote branch
on <code>filament-assets</code>.</p>
</li>
</ul>
<h3 id="manually-updating-the-golden-repo"><a class="header" href="#manually-updating-the-golden-repo">Manually updating the golden repo</a></h3>
<ul>
<li>
<p>Check out the golden repo</p>
<pre><code>git clone git@github.com:google/filament-assets.git
</code></pre>
</li>
<li>
<p>Create a branch on the golden repo</p>
<pre><code>cd filament-assets
git switch -c my-pr-branch-golden
</code></pre>
</li>
<li>
<p>Copy the new images to their appropriate place in <code>filament-assets</code></p>
</li>
<li>
<p>Push the <code>filament-assets</code> working branch to remote</p>
<pre><code>git push origin my-pr-branch-golden
</code></pre>
</li>
<li>
<p>In the commit message of your working branch on <code>filament</code>, add the following line</p>
<pre><code>RDIFF_BBRANCH=my-pr-branch-golden
</code></pre>
</li>
</ul>
<p>Doing the above has multiple effects:</p>
<ul>
<li>The presubmit test <a href="https://github.com/google/filament/blob/e85dfe75c86106a05019e13ccdbef67e030af675/.github/workflows/presubmit.yml#L118"><code>test-renderdiff</code></a> will test against the provided
branch of the golden repo (i.e. <code>my-pr-branch-golden</code>).</li>
<li>If the PR is merged, then there is another workflow that will merge <code>my-pr-branch-golden</code> to
the <code>main</code> branch of the golden repo.</li>
</ul>
<h2 id="viewing-test-results"><a class="header" href="#viewing-test-results">Viewing test results</a></h2>
<p>We provide a viewer for looking at the result of a test run. The viewer is a webapp that can be used by
pointing your browser to a localhost port. If you input the viewer with a PR or a directory, it will
parse the test result and show the results and the rendered and/or golden images.</p>
<p><img src="../images/renderdiff_example.png" alt="Viewer" /></p>
<p>To run the viewer of a test output directory that has been generated locally, you would run the
following</p>
<pre><code>python3 test/renderdiff/src/viewer.py --diff=[test output]
</code></pre>
<p>where <code>[test output]</code> is a directory containing the <code>compare_results.json</code> of the test run.
For example, it could be <code>out/renderdiff/diffs/presubmit</code> for the standard path to the
<code>presubmit</code> test output.</p>
<p>To see the results of a Pull Request initiated test run, you would do the following</p>
<pre><code>python3 test/renderdiff/src/viewer.py --pr_number=[PR #] --github_token=[github token]
</code></pre>
<p>where <code>[PR #]</code> is the numeric ID of your pull request, and the <code>[github token]</code> is an acess token
that you (as a github user) needs to generate (<a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens">reference</a>).</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../notes/tests.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/libs.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../notes/tests.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/libs.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 KiB

+2 -2
View File
@@ -335,7 +335,7 @@ nodes</li>
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/tests.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../notes/libs.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
@@ -349,7 +349,7 @@ nodes</li>
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../notes/tests.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<a rel="next prefetch" href="../notes/libs.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
+2 -2
View File
@@ -165,7 +165,7 @@
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../dup/renderdiff.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../notes/framegraph.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
@@ -179,7 +179,7 @@
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../dup/renderdiff.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<a rel="prev" href="../notes/framegraph.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
-215
View File
@@ -1,215 +0,0 @@
<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Tests - Filament</title>
<!-- Custom HTML head -->
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="../highlight.css">
<link rel="stylesheet" href="../tomorrow-night.css">
<link rel="stylesheet" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- MathJax -->
<script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<!-- Provide site root to javascript -->
<script>
var path_to_root = "../";
var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "light" : "light";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
var sidebar = null;
var sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<div style="display:flex;align-items:center;justify-content:center">
<img class="flogo" src="../images/filament_logo_small.png"></img>
</div>
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<!-- Filament: disable themes because the markdeep part does not look good for dark themes -->
<!--
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
-->
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Filament</h1>
<div class="right-buttons">
<a href="https://github.com/google/filament" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="tests"><a class="header" href="#tests">Tests</a></h1>
<p>Filament has a collection of tests that can be run locally. Many of them are used
for in our Continuation Integration flow <a href="https://https://github.com/google/filament/tree/main/.github/workflows">on github</a>.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../notes/framegraph.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/renderdiff.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../notes/framegraph.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../dup/renderdiff.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>
File diff suppressed because one or more lines are too long
Binary file not shown.
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
-6
View File
@@ -78,11 +78,5 @@
},
"docs_src/README.md": {
"dest": "dup/docs.md"
},
"test/renderdiff/README.md": {
"dest": "dup/renderdiff.md",
"link_transforms": {
"docs/images/": "../images/"
}
}
}
-2
View File
@@ -27,8 +27,6 @@
- [Code coverage analysis](./notes/coverage.md)
- [Performance analysis](./notes/performance_analysis.md)
- [Framegraph](./notes/framegraph.md)
- [Tests](./notes/tests.md)
- [renderdiff](./dup/renderdiff.md)
- [Libraries](./notes/libs.md)
- [bluegl](./dup/bluegl.md)
- [bluevk](./dup/bluevk.md)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 KiB

-4
View File
@@ -1,4 +0,0 @@
# Tests
Filament has a collection of tests that can be run locally. Many of them are used
for in our Continuation Integration flow [on github](https://https://github.com/google/filament/tree/main/.github/workflows).
File diff suppressed because one or more lines are too long
Binary file not shown.
-4
View File
@@ -84,8 +84,6 @@ set(SRCS
src/InstanceBuffer.cpp
src/LightManager.cpp
src/Material.cpp
src/MaterialCache.cpp
src/MaterialDefinition.cpp
src/MaterialInstance.cpp
src/MaterialInstanceManager.cpp
src/MaterialParser.cpp
@@ -177,8 +175,6 @@ set(PRIVATE_HDRS
src/HwRenderPrimitiveFactory.h
src/HwVertexBufferInfoFactory.h
src/Intersections.h
src/MaterialCache.h
src/MaterialDefinition.h
src/MaterialParser.h
src/MaterialInstanceManager.h
src/PIDController.h
-3
View File
@@ -78,8 +78,6 @@ if (FILAMENT_SUPPORTS_OPENGL AND NOT FILAMENT_USE_EXTERNAL_GLES3)
src/opengl/GLTexture.h
src/opengl/GLUtils.cpp
src/opengl/GLUtils.h
src/opengl/GLMemoryMappedBuffer.cpp
src/opengl/GLMemoryMappedBuffer.h
src/opengl/OpenGLBlobCache.cpp
src/opengl/OpenGLBlobCache.h
src/opengl/OpenGLContext.cpp
@@ -568,7 +566,6 @@ if (APPLE OR LINUX)
test/test_ReadPixels.cpp
test/test_BufferUpdates.cpp
test/test_Callbacks.cpp
test/test_MemoryMappedBuffer.cpp
test/test_MRT.cpp
test/test_PushConstants.cpp
test/test_LoadImage.cpp
+4 -27
View File
@@ -556,21 +556,12 @@ constexpr TargetBufferFlags getTargetBufferFlagsAt(size_t index) noexcept {
}
/**
* How the buffer will be used.
* Frequency at which a buffer is expected to be modified and used. This is used as an hint
* for the driver to make better decisions about managing memory internally.
*/
enum class BufferUsage : uint8_t {
STATIC = 0, //!< (legacy) content modified once, used many times
DYNAMIC = 1, //!< (legacy) content modified frequently, used many times
DYNAMIC_BIT = 0x1, //!< buffer can be modified frequently, used many times
SHARED_WRITE_BIT = 0x04, //!< buffer can be memory mapped for write operations
};
/**
* How the buffer will be mapped.
*/
enum class MapBufferAccessFlags : uint8_t {
WRITE_BIT = 0x2, //!< buffer is mapped from writing
INVALIDATE_RANGE_BIT = 0x4, //!< the mapped range content is lost
STATIC, //!< content modified once, used many times
DYNAMIC, //!< content modified frequently, used many times
};
/**
@@ -636,15 +627,6 @@ enum class ShaderModel : uint8_t {
};
static constexpr size_t SHADER_MODEL_COUNT = 2;
constexpr std::string_view to_string(ShaderModel model) noexcept {
switch (model) {
case ShaderModel::MOBILE:
return "mobile";
case ShaderModel::DESKTOP:
return "desktop";
}
}
/**
* Primitive types
*/
@@ -1710,11 +1692,6 @@ template<> struct utils::EnableBitMaskOperators<filament::backend::TextureUsage>
: public std::true_type {};
template<> struct utils::EnableBitMaskOperators<filament::backend::StencilFace>
: public std::true_type {};
template<> struct utils::EnableBitMaskOperators<filament::backend::BufferUsage>
: public std::true_type {};
template<> struct utils::EnableBitMaskOperators<filament::backend::MapBufferAccessFlags>
: public std::true_type {};
template<> struct utils::EnableIntegerOperators<filament::backend::TextureCubemapFace>
: public std::true_type {};
template<> struct utils::EnableIntegerOperators<filament::backend::FeatureLevel>
@@ -45,7 +45,6 @@ struct HwVertexBufferInfo;
struct HwVertexBuffer;
struct HwDescriptorSetLayout;
struct HwDescriptorSet;
struct HwMemoryMappedBuffer;
/*
* A handle to a backend resource. HandleBase is for internal use only.
@@ -160,7 +159,6 @@ using VertexBufferHandle = Handle<HwVertexBuffer>;
using VertexBufferInfoHandle = Handle<HwVertexBufferInfo>;
using DescriptorSetLayoutHandle = Handle<HwDescriptorSetLayout>;
using DescriptorSetHandle = Handle<HwDescriptorSet>;
using MemoryMappedBufferHandle = Handle<HwMemoryMappedBuffer>;
} // namespace filament::backend
@@ -168,7 +168,6 @@ protected:
EGLConfig mEGLConfig = EGL_NO_CONFIG_KHR;
Config mContextAttribs;
std::vector<EGLContext> mAdditionalContexts;
bool mMSAA4XSupport = false;
// supported extensions detected at runtime
struct {
@@ -219,8 +218,6 @@ private:
return makeCurrent(mCurrentContext, drawSurface, readSurface);
}
} egl{ mEGLDisplay };
bool checkIfMSAASwapChainSupported(uint32_t samples) const noexcept;
};
} // namespace filament::backend
@@ -108,16 +108,12 @@
DECL_DRIVER_API_RETURN(R, N, PAIR_ARGS_N(ARG, ##__VA_ARGS__), PAIR_ARGS_N(PARAM, ##__VA_ARGS__))
#define DECL_DRIVER_API_TAGGED_R_N(R, N, ...) \
DECL_DRIVER_API_RETURN(R, N, PAIR_ARGS_N(ARG, ##__VA_ARGS__, utils::CString&&, tag = {}), \
PAIR_ARGS_N(PARAM, ##__VA_ARGS__, utils::CString&&, tag))
DECL_DRIVER_API_RETURN(R, N, PAIR_ARGS_N(ARG, ##__VA_ARGS__, utils::CString, tag = {}), \
PAIR_ARGS_N(PARAM, ##__VA_ARGS__, utils::CString, tag))
#define DECL_DRIVER_API_SYNCHRONOUS_N(R, N, ...) \
DECL_DRIVER_API_SYNCHRONOUS(R, N, PAIR_ARGS_N(ARG, ##__VA_ARGS__), PAIR_ARGS_N(PARAM, ##__VA_ARGS__))
#define DECL_DRIVER_API_SYNCHRONOUS_TAGGED_N(R, N, ...) \
DECL_DRIVER_API_SYNCHRONOUS(R, N, PAIR_ARGS_N(ARG, ##__VA_ARGS__, utils::CString, tag = {}), \
PAIR_ARGS_N(PARAM, ##__VA_ARGS__, utils::CString, tag))
// on some compilers the ##__VA_ARGS__ hack is not supported, so we can't handle 0-parameter APIs
// with DECL_DRIVER_API_SYNCHRONOUS_N
#define DECL_DRIVER_API_SYNCHRONOUS_0(R, N) \
@@ -295,11 +291,27 @@ DECL_DRIVER_API_TAGGED_R_N(backend::DescriptorSetLayoutHandle, createDescriptorS
DECL_DRIVER_API_TAGGED_R_N(backend::DescriptorSetHandle, createDescriptorSet,
backend::DescriptorSetLayoutHandle, dslh)
DECL_DRIVER_API_TAGGED_R_N(backend::MemoryMappedBufferHandle, mapBuffer,
DECL_DRIVER_API_N(updateDescriptorSetBuffer,
backend::DescriptorSetHandle, dsh,
backend::descriptor_binding_t, binding,
backend::BufferObjectHandle, boh,
size_t, offset,
size_t, size,
backend::MapBufferAccessFlags, access)
uint32_t, offset,
uint32_t, size
)
DECL_DRIVER_API_N(updateDescriptorSetTexture,
backend::DescriptorSetHandle, dsh,
backend::descriptor_binding_t, binding,
backend::TextureHandle, th,
SamplerParams, params
)
DECL_DRIVER_API_N(bindDescriptorSet,
backend::DescriptorSetHandle, dsh,
backend::descriptor_set_t, set,
backend::DescriptorSetOffsetArray&&, offsets
)
/*
* Destroying driver objects
@@ -309,7 +321,7 @@ DECL_DRIVER_API_TAGGED_R_N(backend::MemoryMappedBufferHandle, mapBuffer,
DECL_DRIVER_API_N(destroyVertexBuffer, backend::VertexBufferHandle, vbh)
DECL_DRIVER_API_N(destroyVertexBufferInfo, backend::VertexBufferInfoHandle, vbih)
DECL_DRIVER_API_N(destroyIndexBuffer, backend::IndexBufferHandle, ibh)
DECL_DRIVER_API_N(destroyBufferObject, backend::BufferObjectHandle, boh)
DECL_DRIVER_API_N(destroyBufferObject, backend::BufferObjectHandle, ibh)
DECL_DRIVER_API_N(destroyRenderPrimitive, backend::RenderPrimitiveHandle, rph)
DECL_DRIVER_API_N(destroyProgram, backend::ProgramHandle, ph)
DECL_DRIVER_API_N(destroyTexture, backend::TextureHandle, th)
@@ -321,7 +333,6 @@ DECL_DRIVER_API_N(destroyFence, backend::FenceHandle, fh)
DECL_DRIVER_API_N(destroySync, backend::SyncHandle, sh)
DECL_DRIVER_API_N(destroyDescriptorSetLayout, backend::DescriptorSetLayoutHandle, dslh)
DECL_DRIVER_API_N(destroyDescriptorSet, backend::DescriptorSetHandle, dsh)
DECL_DRIVER_API_N(unmapBuffer, backend::MemoryMappedBufferHandle, mmbh)
/*
* Synchronous APIs
@@ -329,8 +340,8 @@ DECL_DRIVER_API_N(unmapBuffer, backend::MemoryMappedBufferHandl
*/
DECL_DRIVER_API_SYNCHRONOUS_0(void, terminate)
DECL_DRIVER_API_SYNCHRONOUS_TAGGED_N(backend::StreamHandle, createStreamNative, void*, stream)
DECL_DRIVER_API_SYNCHRONOUS_TAGGED_N(backend::StreamHandle, createStreamAcquired)
DECL_DRIVER_API_SYNCHRONOUS_N(backend::StreamHandle, createStreamNative, void*, stream, utils::CString, tag)
DECL_DRIVER_API_SYNCHRONOUS_N(backend::StreamHandle, createStreamAcquired, utils::CString, tag)
DECL_DRIVER_API_SYNCHRONOUS_N(void, setAcquiredImage, backend::StreamHandle, stream, void*, image, const math::mat3f&, transform, backend::CallbackHandler*, handler, backend::StreamCallback, cb, void*, userData)
DECL_DRIVER_API_SYNCHRONOUS_N(void, setStreamDimensions, backend::StreamHandle, stream, uint32_t, width, uint32_t, height)
DECL_DRIVER_API_SYNCHRONOUS_N(int64_t, getStreamTimestamp, backend::StreamHandle, stream)
@@ -362,7 +373,7 @@ DECL_DRIVER_API_SYNCHRONOUS_0(size_t, getMaxArrayTextureLayers)
DECL_DRIVER_API_SYNCHRONOUS_0(math::float2, getClipSpaceParams)
DECL_DRIVER_API_SYNCHRONOUS_N(void, setupExternalImage2, backend::Platform::ExternalImageHandleRef, image)
DECL_DRIVER_API_SYNCHRONOUS_N(void, setupExternalImage, void*, image)
DECL_DRIVER_API_SYNCHRONOUS_N(backend::TimerQueryResult, getTimerQueryValue, backend::TimerQueryHandle, tqh, uint64_t*, elapsedTime)
DECL_DRIVER_API_SYNCHRONOUS_N(backend::TimerQueryResult, getTimerQueryValue, backend::TimerQueryHandle, query, uint64_t*, elapsedTime)
DECL_DRIVER_API_SYNCHRONOUS_N(bool, isWorkaroundNeeded, backend::Workaround, workaround)
DECL_DRIVER_API_SYNCHRONOUS_0(backend::FeatureLevel, getFeatureLevel)
@@ -387,16 +398,16 @@ DECL_DRIVER_API_N(updateBufferObject,
uint32_t, byteOffset)
DECL_DRIVER_API_N(registerBufferObjectStreams,
backend::BufferObjectHandle, boh,
backend::BufferObjectHandle, ibh,
backend::BufferObjectStreamDescriptor&&, streams)
DECL_DRIVER_API_N(updateBufferObjectUnsynchronized,
backend::BufferObjectHandle, boh,
backend::BufferObjectHandle, ibh,
backend::BufferDescriptor&&, data,
uint32_t, byteOffset)
DECL_DRIVER_API_N(resetBufferObject,
backend::BufferObjectHandle, boh)
backend::BufferObjectHandle, ibh)
DECL_DRIVER_API_N(update3DImage,
backend::TextureHandle, th,
@@ -425,10 +436,10 @@ DECL_DRIVER_API_0(endRenderPass)
DECL_DRIVER_API_0(nextSubpass)
DECL_DRIVER_API_N(beginTimerQuery,
backend::TimerQueryHandle, tqh)
backend::TimerQueryHandle, query)
DECL_DRIVER_API_N(endTimerQuery,
backend::TimerQueryHandle, tqh)
backend::TimerQueryHandle, query)
DECL_DRIVER_API_N(compilePrograms,
backend::CompilerPriorityQueue, priority,
@@ -436,26 +447,6 @@ DECL_DRIVER_API_N(compilePrograms,
backend::CallbackHandler::Callback, callback,
void*, user)
DECL_DRIVER_API_N(updateDescriptorSetBuffer,
backend::DescriptorSetHandle, dsh,
backend::descriptor_binding_t, binding,
backend::BufferObjectHandle, boh,
uint32_t, offset,
uint32_t, size
)
DECL_DRIVER_API_N(updateDescriptorSetTexture,
backend::DescriptorSetHandle, dsh,
backend::descriptor_binding_t, binding,
backend::TextureHandle, th,
SamplerParams, params
)
DECL_DRIVER_API_N(copyToMemoryMappedBuffer,
backend::MemoryMappedBufferHandle, mmbh,
size_t, offset,
backend::BufferDescriptor&&, data)
/*
* Swap chain
*/
@@ -544,12 +535,6 @@ DECL_DRIVER_API_N(bindPipeline,
DECL_DRIVER_API_N(bindRenderPrimitive,
backend::RenderPrimitiveHandle, rph)
DECL_DRIVER_API_N(bindDescriptorSet,
backend::DescriptorSetHandle, dsh,
backend::descriptor_set_t, set,
backend::DescriptorSetOffsetArray&&, offsets
)
DECL_DRIVER_API_N(draw2,
uint32_t, indexOffset,
uint32_t, indexCount,
+4 -10
View File
@@ -18,16 +18,10 @@
#include "DataReshaper.h"
#include <backend/PixelBufferDescriptor.h>
#include <backend/DriverEnums.h>
#include <utils/BitmaskEnum.h>
#include <utils/compiler.h>
#include <utils/CString.h>
#include <cstddef>
#include <cstdint>
#include <utility>
#include <string_view>
namespace filament::backend {
@@ -642,7 +636,7 @@ bool reshape(const PixelBufferDescriptor& data, PixelBufferDescriptor& reshaped)
switch (data.type) {
case PixelDataType::BYTE:
case PixelDataType::UBYTE: {
uint8_t* bytes = static_cast<uint8_t*>(malloc(reshapedSize));
uint8_t* bytes = (uint8_t*) malloc(reshapedSize);
DataReshaper::reshape<uint8_t, 3, 4>(bytes, data.buffer, data.size);
PixelBufferDescriptor pbd(bytes, reshapedSize, reshapedFormat, data.type,
data.alignment, data.left, data.top, data.stride, freeFunc);
@@ -652,7 +646,7 @@ bool reshape(const PixelBufferDescriptor& data, PixelBufferDescriptor& reshaped)
case PixelDataType::SHORT:
case PixelDataType::USHORT:
case PixelDataType::HALF: {
uint8_t* bytes = static_cast<uint8_t*>(malloc(reshapedSize));
uint8_t* bytes = (uint8_t*) malloc(reshapedSize);
DataReshaper::reshape<uint16_t, 3, 4>(bytes, data.buffer, data.size);
PixelBufferDescriptor pbd(bytes, reshapedSize, reshapedFormat, data.type,
data.alignment, data.left, data.top, data.stride, freeFunc);
@@ -661,7 +655,7 @@ bool reshape(const PixelBufferDescriptor& data, PixelBufferDescriptor& reshaped)
}
case PixelDataType::INT:
case PixelDataType::UINT: {
uint8_t* bytes = static_cast<uint8_t*>(malloc(reshapedSize));
uint8_t* bytes = (uint8_t*) malloc(reshapedSize);
DataReshaper::reshape<uint32_t, 3, 4>(bytes, data.buffer, data.size);
PixelBufferDescriptor pbd(bytes, reshapedSize, reshapedFormat, data.type,
data.alignment, data.left, data.top, data.stride, freeFunc);
@@ -669,7 +663,7 @@ bool reshape(const PixelBufferDescriptor& data, PixelBufferDescriptor& reshaped)
return true;
}
case PixelDataType::FLOAT: {
uint8_t* bytes = static_cast<uint8_t*>(malloc(reshapedSize));
uint8_t* bytes = (uint8_t*) malloc(reshapedSize);
DataReshaper::reshape<float, 3, 4>(bytes, data.buffer, data.size);
PixelBufferDescriptor pbd(bytes, reshapedSize, reshapedFormat, data.type,
data.alignment, data.left, data.top, data.stride, freeFunc);
+8 -25
View File
@@ -63,7 +63,6 @@ public:
static void copyImage(uint8_t* UTILS_RESTRICT dest,
const uint8_t* UTILS_RESTRICT src,
size_t srcBytesPerRow, size_t /*srcChannelCount*/,
size_t /*dstRowOffset */, size_t /*dstColumnOffset */,
size_t dstBytesPerRow, size_t /*dstChannelCount*/,
size_t /*width*/, size_t height, bool /*swizzle*/) {
if (srcBytesPerRow == dstBytesPerRow) {
@@ -80,20 +79,17 @@ public:
template<typename dstComponentType, typename srcComponentType>
static void reshapeImage(uint8_t* UTILS_RESTRICT dest, const uint8_t* UTILS_RESTRICT src,
size_t srcBytesPerRow,
size_t srcChannelCount,
size_t dstRowOffset, size_t dstColumnOffset,
size_t dstBytesPerRow, size_t dstChannelCount,
size_t srcChannelCount, size_t dstBytesPerRow, size_t dstChannelCount,
size_t width, size_t height, bool swizzle) {
const dstComponentType dstMaxValue = getMaxValue<dstComponentType>();
const srcComponentType srcMaxValue = getMaxValue<srcComponentType>();
const size_t minChannelCount = math::min(srcChannelCount, dstChannelCount);
assert_invariant(minChannelCount <= 4);
UTILS_ASSUME(minChannelCount <= 4);
dest += (dstRowOffset * dstBytesPerRow);
const int inds[4] = { swizzle ? 2 : 0, 1, swizzle ? 0 : 2, 3 };
for (size_t row = 0; row < height; ++row) {
const srcComponentType* in = (const srcComponentType*) src;
dstComponentType* out = (dstComponentType*)dest + (dstColumnOffset * dstChannelCount);
const srcComponentType* in = (const srcComponentType*)src;
dstComponentType* out = (dstComponentType*)dest;
for (size_t column = 0; column < width; ++column) {
for (size_t channel = 0; channel < minChannelCount; ++channel) {
if constexpr (std::is_same_v<dstComponentType, srcComponentType>) {
@@ -132,23 +128,17 @@ public:
default: return false;
}
void (*reshaper)(uint8_t* dest, const uint8_t* src, size_t srcBytesPerRow,
size_t srcChannelCount,
size_t srcRowOffset, size_t srcColumnOffset,
size_t dstBytesPerRow, size_t dstChannelCount,
size_t srcChannelCount, size_t dstBytesPerRow, size_t dstChannelCount,
size_t width, size_t height, bool swizzle) = nullptr;
constexpr auto UBYTE = PixelDataType::UBYTE;
constexpr auto FLOAT = PixelDataType::FLOAT;
constexpr auto UINT = PixelDataType::UINT;
constexpr auto INT = PixelDataType::INT;
constexpr auto HALF = PixelDataType::HALF;
constexpr auto UBYTE = PixelDataType::UBYTE, FLOAT = PixelDataType::FLOAT,
UINT = PixelDataType::UINT, INT = PixelDataType::INT;
switch (dst->type) {
case UBYTE:
switch (srcType) {
case UBYTE:
reshaper = reshapeImage<uint8_t, uint8_t>;
if (dst->format == PixelDataFormat::RGBA &&
dstChannelCount == srcChannelCount && !swizzle && dst->top == 0 &&
dst->left == 0) {
dstChannelCount == srcChannelCount && !swizzle) {
reshaper = copyImage;
}
break;
@@ -185,20 +175,13 @@ public:
default: return false;
}
break;
case HALF:
switch (srcType) {
case HALF: reshaper = copyImage; break;
default: return false;
}
break;
default:
return false;
}
uint8_t* dstBytes = (uint8_t*) dst->buffer;
const int dstBytesPerRow = PixelBufferDescriptor::computeDataSize(dst->format, dst->type,
dst->stride ? dst->stride : width, 1, dst->alignment);
reshaper(dstBytes, srcBytes, srcBytesPerRow, srcChannelCount,
dst->top, dst->left, dstBytesPerRow,
reshaper(dstBytes, srcBytes, srcBytesPerRow, srcChannelCount, dstBytesPerRow,
dstChannelCount, width, height, swizzle);
return true;
}
+1 -4
View File
@@ -78,9 +78,6 @@ struct HwBufferObject : public HwBase {
explicit HwBufferObject(uint32_t byteCount) noexcept : byteCount(byteCount) {}
};
struct HwMemoryMappedBuffer : public HwBase {
};
struct HwIndexBuffer : public HwBase {
uint32_t count : 27;
uint32_t elementSize : 5;
@@ -214,7 +211,7 @@ public:
protected:
class CallbackDataDetails;
void scheduleDestroy(BufferDescriptor&& buffer) noexcept {
inline void scheduleDestroy(BufferDescriptor&& buffer) noexcept {
if (buffer.hasCallback()) {
scheduleDestroySlow(std::move(buffer));
}
+1 -11
View File
@@ -18,7 +18,6 @@
#define TNT_FILAMENT_DRIVER_METALBUFFER_H
#include "MetalContext.h"
#include "MetalFlags.h"
#include <backend/DriverEnums.h>
#include <backend/platforms/PlatformMetal.h>
@@ -154,7 +153,7 @@ private:
Type mType = Type::NONE;
static PlatformMetal* platform;
static std::array<uint64_t, TypeCount> aliveBuffers;
static std::array<std::atomic<uint64_t>, TypeCount> aliveBuffers;
};
class MetalBuffer {
@@ -192,15 +191,6 @@ public:
void* getCpuBuffer() const noexcept { return mCpuBuffer; }
void setLabel(const utils::CString& label) {
#if FILAMENT_METAL_DEBUG_LABELS
if (label.empty()) {
return;
}
mBuffer.get().label = @(label.c_str_safe());
#endif
}
enum Stage : uint8_t {
VERTEX = 1u << 0u,
FRAGMENT = 1u << 1u,
+1 -1
View File
@@ -24,7 +24,7 @@
namespace filament {
namespace backend {
std::array<uint64_t, TrackedMetalBuffer::TypeCount> TrackedMetalBuffer::aliveBuffers = { 0 };
std::array<std::atomic<uint64_t>, TrackedMetalBuffer::TypeCount> TrackedMetalBuffer::aliveBuffers = { 0 };
PlatformMetal* TrackedMetalBuffer::platform = nullptr;
PlatformMetal* ScopedAllocationTimer::platform = nullptr;
+1 -6
View File
@@ -102,7 +102,7 @@ id<MTLCommandBuffer> getPendingCommandBuffer(MetalContext* context) {
context->pendingCommandBuffer = [context->commandQueue commandBuffer];
// It's safe for this block to capture the context variable. MetalDriver::terminate will ensure
// all frames and their completion handlers finish before context is deallocated.
const uint64_t thisCommandBufferId = context->pendingCommandBufferId;
uint64_t thisCommandBufferId = context->pendingCommandBufferId;
[context->pendingCommandBuffer addCompletedHandler:^(id <MTLCommandBuffer> buffer) {
context->resourceTracker.clearResources((__bridge void*) buffer);
@@ -118,11 +118,6 @@ id<MTLCommandBuffer> getPendingCommandBuffer(MetalContext* context) {
context->memorylessLimitsReached = true;
}
}
if (UTILS_UNLIKELY(errorCode != MTLCommandBufferErrorNone)) {
LOG(ERROR) << "Filament Metal command buffer errored with code: " << errorCode << " ("
<< stringifyMTLCommandBufferError(errorCode) << ").";
}
}];
FILAMENT_CHECK_POSTCONDITION(context->pendingCommandBuffer)
<< "Could not obtain command buffer.";
+34 -82
View File
@@ -418,14 +418,14 @@ void MetalDriver::finish(int) {
}
void MetalDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vbih, uint8_t bufferCount,
uint8_t attributeCount, AttributeArray attributes, utils::CString&& tag) {
uint8_t attributeCount, AttributeArray attributes, utils::CString tag) {
construct_handle<MetalVertexBufferInfo>(vbih, *mContext,
bufferCount, attributeCount, attributes);
mHandleAllocator.associateTagToHandle(vbih.getId(), std::move(tag));
}
void MetalDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh,
uint32_t vertexCount, Handle<HwVertexBufferInfo> vbih, utils::CString&& tag) {
uint32_t vertexCount, Handle<HwVertexBufferInfo> vbih, utils::CString tag) {
MetalVertexBufferInfo const* const vbi = handle_cast<const MetalVertexBufferInfo>(vbih);
construct_handle<MetalVertexBuffer>(vbh, *mContext, vertexCount, vbi->bufferCount, vbih);
mHandleAllocator.associateTagToHandle(vbh.getId(), std::move(tag));
@@ -433,7 +433,7 @@ void MetalDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh,
}
void MetalDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType,
uint32_t indexCount, BufferUsage usage, utils::CString&& tag) {
uint32_t indexCount, BufferUsage usage, utils::CString tag) {
auto elementSize = (uint8_t)getElementTypeSize(elementType);
auto* indexBuffer =
construct_handle<MetalIndexBuffer>(ibh, *mContext, usage, elementSize, indexCount);
@@ -441,18 +441,16 @@ void MetalDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elem
FILAMENT_CHECK_POSTCONDITION(buffer.wasAllocationSuccessful())
<< "Could not allocate Metal index buffer of size " << buffer.getSize()
<< ", tag=" << tag.c_str_safe();
buffer.setLabel(tag);
mHandleAllocator.associateTagToHandle(ibh.getId(), std::move(tag));
}
void MetalDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
BufferObjectBinding bindingType, BufferUsage usage, utils::CString&& tag) {
BufferObjectBinding bindingType, BufferUsage usage, utils::CString tag) {
auto* bufferObject =
construct_handle<MetalBufferObject>(boh, *mContext, bindingType, usage, byteCount);
FILAMENT_CHECK_POSTCONDITION(bufferObject->getBuffer()->wasAllocationSuccessful())
<< "Could not allocate Metal buffer of size " << byteCount
<< ", tag=" << tag.c_str_safe();
bufferObject->getBuffer()->setLabel(tag);
mHandleAllocator.associateTagToHandle(boh.getId(), std::move(tag));
}
@@ -488,16 +486,13 @@ inline const char* stringify(SamplerType samplerType) {
void MetalDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height,
uint32_t depth, TextureUsage usage, utils::CString&& tag) {
uint32_t depth, TextureUsage usage, utils::CString tag) {
// Clamp sample count to what the device supports.
auto& sc = mContext->sampleCountLookup;
samples = sc[std::min(MAX_SAMPLE_COUNT, samples)];
MetalTexture* texture = construct_handle<MetalTexture>(th, *mContext, target, levels, format,
samples, width, height, depth, usage);
mContext->textures.insert(texture);
texture->setLabel(tag);
mContext->textures.insert(construct_handle<MetalTexture>(
th, *mContext, target, levels, format, samples, width, height, depth, usage));
DEBUG_LOG(
"createTextureR(th = %d, target = %s, levels = %d, format = ?, samples = %d, width = "
@@ -508,22 +503,18 @@ void MetalDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8
}
void MetalDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> srch,
uint8_t baseLevel, uint8_t levelCount, utils::CString&& tag) {
uint8_t baseLevel, uint8_t levelCount, utils::CString tag) {
MetalTexture const* src = handle_cast<MetalTexture>(srch);
MetalTexture* texture =
construct_handle<MetalTexture>(th, *mContext, src, baseLevel, levelCount);
mContext->textures.insert(texture);
texture->setLabel(tag);
mContext->textures.insert(
construct_handle<MetalTexture>(th, *mContext, src, baseLevel, levelCount));
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void MetalDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b,
backend::TextureSwizzle a, utils::CString&& tag) {
backend::TextureSwizzle a, utils::CString tag) {
MetalTexture const* src = handle_cast<MetalTexture>(srch);
MetalTexture* texture = construct_handle<MetalTexture>(th, *mContext, src, r, g, b, a);
mContext->textures.insert(texture);
texture->setLabel(tag);
mContext->textures.insert(construct_handle<MetalTexture>(th, *mContext, src, r, g, b, a));
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
@@ -531,17 +522,15 @@ void MetalDriver::createTextureExternalImage2R(Handle<HwTexture> th,
backend::SamplerType target,
backend::TextureFormat format,
uint32_t width, uint32_t height, backend::TextureUsage usage,
Platform::ExternalImageHandleRef image, utils::CString&& tag) {
Platform::ExternalImageHandleRef image, utils::CString tag) {
// FIXME: implement createTextureExternalImage2R
}
void MetalDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::SamplerType target,
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
void* image, utils::CString&& tag) {
MetalTexture* texture = construct_handle<MetalTexture>(th, *mContext, format, width, height,
usage, (CVPixelBufferRef) image);
mContext->textures.insert(texture);
texture->setLabel(tag);
void* image, utils::CString tag) {
mContext->textures.insert(construct_handle<MetalTexture>(
th, *mContext, format, width, height, usage, (CVPixelBufferRef)image));
// This release matches the retain call in setupExternalImage. The MetalTexture will have
// retained the buffer by now.
CVPixelBufferRelease((CVPixelBufferRef)image);
@@ -550,11 +539,9 @@ void MetalDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::Sam
void MetalDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
void* image, uint32_t plane, utils::CString&& tag) {
MetalTexture* texture = construct_handle<MetalTexture>(th, *mContext, format, width, height,
usage, (CVPixelBufferRef) image, plane);
mContext->textures.insert(texture);
texture->setLabel(tag);
void* image, uint32_t plane, utils::CString tag) {
mContext->textures.insert(construct_handle<MetalTexture>(
th, *mContext, format, width, height, usage, (CVPixelBufferRef)image, plane));
// This release matches the retain call in setupExternalImage. The MetalTexture will have
// retained the buffer by now.
CVPixelBufferRelease((CVPixelBufferRef)image);
@@ -564,7 +551,7 @@ void MetalDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
void MetalDriver::importTextureR(Handle<HwTexture> th, intptr_t i,
SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t width, uint32_t height,
uint32_t depth, TextureUsage usage, utils::CString&& tag) {
uint32_t depth, TextureUsage usage, utils::CString tag) {
id<MTLTexture> metalTexture = (id<MTLTexture>) CFBridgingRelease((void*) i);
FILAMENT_CHECK_PRECONDITION(metalTexture.width == width)
<< "Imported id<MTLTexture> width (" << metalTexture.width
@@ -579,22 +566,20 @@ void MetalDriver::importTextureR(Handle<HwTexture> th, intptr_t i,
FILAMENT_CHECK_PRECONDITION(metalTexture.textureType == filamentMetalType)
<< "Imported id<MTLTexture> type (" << metalTexture.textureType
<< ") != Filament texture type (" << filamentMetalType << ")";
MetalTexture* texture = construct_handle<MetalTexture>(th, *mContext, target, levels, format,
samples, width, height, depth, usage, metalTexture);
mContext->textures.insert(texture);
texture->setLabel(tag);
mContext->textures.insert(construct_handle<MetalTexture>(th, *mContext,
target, levels, format, samples, width, height, depth, usage, metalTexture));
mHandleAllocator.associateTagToHandle(th.getId(), std::move(tag));
}
void MetalDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh,
PrimitiveType pt, utils::CString&& tag) {
PrimitiveType pt, utils::CString tag) {
construct_handle<MetalRenderPrimitive>(rph);
MetalDriver::setRenderPrimitiveBuffer(rph, pt, vbh, ibh);
mHandleAllocator.associateTagToHandle(rph.getId(), std::move(tag));
}
void MetalDriver::createProgramR(Handle<HwProgram> rph, Program&& program, utils::CString&& tag) {
void MetalDriver::createProgramR(Handle<HwProgram> rph, Program&& program, utils::CString tag) {
#if FILAMENT_METAL_DEBUG_LOG
auto handleId = rph.getId();
DEBUG_LOG("createProgramR(rph = %d, program = ", handleId);
@@ -604,7 +589,7 @@ void MetalDriver::createProgramR(Handle<HwProgram> rph, Program&& program, utils
mHandleAllocator.associateTagToHandle(rph.getId(), std::move(tag));
}
void MetalDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, utils::CString&& tag) {
void MetalDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, utils::CString tag) {
construct_handle<MetalRenderTarget>(rth, mContext);
mHandleAllocator.associateTagToHandle(rth.getId(), std::move(tag));
}
@@ -612,7 +597,7 @@ void MetalDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, utils::
void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
TargetBufferFlags targetBufferFlags, uint32_t width, uint32_t height,
uint8_t samples, uint8_t layerCount, MRT color,
TargetBufferInfo depth, TargetBufferInfo stencil, utils::CString&& tag) {
TargetBufferInfo depth, TargetBufferInfo stencil, utils::CString tag) {
FILAMENT_CHECK_PRECONDITION(!isInRenderPass(mContext))
<< "createRenderTarget must be called outside of a render pass.";
// Clamp sample count to what the device supports.
@@ -659,14 +644,14 @@ void MetalDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
mHandleAllocator.associateTagToHandle(rth.getId(), std::move(tag));
}
void MetalDriver::createFenceR(Handle<HwFence> fh, utils::CString&& tag) {
void MetalDriver::createFenceR(Handle<HwFence> fh, utils::CString tag) {
auto* fence = handle_cast<MetalFence>(fh);
fence->encode();
mHandleAllocator.associateTagToHandle(fh.getId(), std::move(tag));
}
void MetalDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags,
utils::CString&& tag) {
utils::CString tag) {
// TODO: support MSAA swapchain
if (UTILS_UNLIKELY(flags & SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER)) {
@@ -683,18 +668,18 @@ void MetalDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
}
void MetalDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch,
uint32_t width, uint32_t height, uint64_t flags, utils::CString&& tag) {
uint32_t width, uint32_t height, uint64_t flags, utils::CString tag) {
construct_handle<MetalSwapChain>(sch, *mContext, mPlatform, width, height, flags);
mHandleAllocator.associateTagToHandle(sch.getId(), std::move(tag));
}
void MetalDriver::createSyncR(Handle<HwSync> sh, utils::CString&& tag) {
void MetalDriver::createSyncR(Handle<HwSync> sh, utils::CString tag) {
// TODO: Ensure sync is active, and then invoke and clear all pending
// callbacks.
mHandleAllocator.associateTagToHandle(sh.getId(), std::move(tag));
}
void MetalDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, utils::CString&& tag) {
void MetalDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, utils::CString tag) {
// nothing to do, timer query was constructed in createTimerQueryS
mHandleAllocator.associateTagToHandle(tqh.getId(), std::move(tag));
}
@@ -733,7 +718,7 @@ const char* toString(DescriptorFlags flags) {
}
void MetalDriver::createDescriptorSetLayoutR(
Handle<HwDescriptorSetLayout> dslh, DescriptorSetLayout&& info, utils::CString&& tag) {
Handle<HwDescriptorSetLayout> dslh, DescriptorSetLayout&& info, utils::CString tag) {
#if FILAMENT_METAL_DEBUG_LOG == 1
const char* labelStr = "";
std::visit([&labelStr](auto&& arg) {
@@ -758,11 +743,10 @@ void MetalDriver::createDescriptorSetLayoutR(
}
void MetalDriver::createDescriptorSetR(
Handle<HwDescriptorSet> dsh, Handle<HwDescriptorSetLayout> dslh, utils::CString&& tag) {
Handle<HwDescriptorSet> dsh, Handle<HwDescriptorSetLayout> dslh, utils::CString tag) {
DEBUG_LOG("createDescriptorSetR(dsh = %d, dslh = %d)\n", dsh.getId(), dslh.getId());
MetalDescriptorSetLayout* layout = handle_cast<MetalDescriptorSetLayout>(dslh);
MetalDescriptorSet* ds = construct_handle<MetalDescriptorSet>(dsh, layout);
ds->setLabel(tag);
construct_handle<MetalDescriptorSet>(dsh, layout);
mHandleAllocator.associateTagToHandle(dsh.getId(), std::move(tag));
}
@@ -2217,38 +2201,6 @@ void MetalDriver::executeDeferredOps() noexcept {
}
}
MemoryMappedBufferHandle MetalDriver::mapBufferS() noexcept {
return alloc_handle<MetalMemoryMappedBuffer>();
}
void MetalDriver::mapBufferR(MemoryMappedBufferHandle mmbh,
BufferObjectHandle boh, size_t offset,
size_t size, MapBufferAccessFlags access, utils::CString&& tag) {
construct_handle<MetalMemoryMappedBuffer>(mmbh, boh, offset, size, access);
mHandleAllocator.associateTagToHandle(mmbh.getId(), std::move(tag));
}
void MetalDriver::unmapBuffer(MemoryMappedBufferHandle mmbh) {
if (UTILS_UNLIKELY(!mmbh)) {
return;
}
destruct_handle<MetalMemoryMappedBuffer>(mmbh);
}
void MetalDriver::copyToMemoryMappedBuffer(MemoryMappedBufferHandle mmbh, size_t offset,
BufferDescriptor&& data) {
auto mmb = handle_cast<MetalMemoryMappedBuffer>(mmbh);
assert_invariant(any(mmb->access & MapBufferAccessFlags::WRITE_BIT));
assert_invariant(offset + data.size <= mmb->size);
// TODO: this isa zero-effort implementation of copyToMemoryMappedBuffer(), where we just
// call updateBufferObject(). This could be a fallback implementation for when
// shared memory is not available.
// On UMA systems, this should just be a memcpy into the memory-mapped buffer.
updateBufferObject(mmb->boh, std::move(data), mmb->offset + offset);
}
// explicit instantiation of the Dispatcher
template class ConcreteDispatcher<MetalDriver>;
-32
View File
@@ -451,38 +451,6 @@ inline MTLTextureSwizzleChannels getSwizzleChannels(TextureSwizzle r, TextureSwi
getSwizzle(a));
}
inline const char* stringifyMTLCommandBufferError(MTLCommandBufferError error) {
#if !defined(FILAMENT_IOS)
if (error == MTLCommandBufferErrorDeviceRemoved) {
return "MTLCommandBufferErrorDeviceRemoved";
}
#endif
switch (error) {
case MTLCommandBufferErrorNone:
return "MTLCommandBufferErrorNone";
case MTLCommandBufferErrorInternal:
return "MTLCommandBufferErrorInternal";
case MTLCommandBufferErrorTimeout:
return "MTLCommandBufferErrorTimeout";
case MTLCommandBufferErrorPageFault:
return "MTLCommandBufferErrorPageFault";
case MTLCommandBufferErrorAccessRevoked:
return "MTLCommandBufferErrorAccessRevoked";
case MTLCommandBufferErrorNotPermitted:
return "MTLCommandBufferErrorNotPermitted";
case MTLCommandBufferErrorOutOfMemory:
return "MTLCommandBufferErrorOutOfMemory";
case MTLCommandBufferErrorInvalidResource:
return "MTLCommandBufferErrorInvalidResource";
case MTLCommandBufferErrorMemoryless:
return "MTLCommandBufferErrorMemoryless";
case MTLCommandBufferErrorStackOverflow:
return "MTLCommandBufferErrorStackOverflow";
default:
return "Unknown";
}
}
} // namespace backend
} // namespace filament
-28
View File
@@ -1,28 +0,0 @@
/*
* Copyright (C) 2025 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_METALFLAGS_H
#define TNT_FILAMENT_DRIVER_METALFLAGS_H
#ifndef FILAMENT_METAL_DEBUG_LABELS
#ifndef NDEBUG
#define FILAMENT_METAL_DEBUG_LABELS 1
#else
#define FILAMENT_METAL_DEBUG_LABELS 0
#endif
#endif
#endif
-36
View File
@@ -27,7 +27,6 @@
#include "MetalContext.h"
#include "MetalEnums.h"
#include "MetalExternalImage.h"
#include "MetalFlags.h"
#include "MetalState.h" // for MetalState::VertexDescription
#include <backend/DriverEnums.h>
@@ -267,16 +266,6 @@ public:
static MTLPixelFormat decidePixelFormat(MetalContext* context, TextureFormat format);
void setLabel(const utils::CString& label) {
#if FILAMENT_METAL_DEBUG_LABELS
if (label.empty()) {
return;
}
texture.label = @(label.c_str_safe());
swizzledTextureView.label = @(label.c_str_safe());
#endif
}
MetalContext& context;
// A "sidecar" texture used to implement automatic MSAA resolve.
@@ -494,15 +483,6 @@ struct MetalDescriptorSet : public HwDescriptorSet {
void finalize(MetalDriver* driver);
void setLabel(const utils::CString& l) {
#if FILAMENT_METAL_DEBUG_LABELS
if (l.empty()) {
return;
}
label = l;
#endif
}
id<MTLBuffer> finalizeAndGetBuffer(MetalDriver* driver, ShaderStage stage);
MetalDescriptorSetLayout* layout;
@@ -525,22 +505,6 @@ struct MetalDescriptorSet : public HwDescriptorSet {
std::vector<std::shared_ptr<MetalExternalImage>> externalImages;
std::array<TrackedMetalBuffer, Program::SHADER_TYPE_COUNT> cachedBuffer = { nil };
#if FILAMENT_METAL_DEBUG_LABELS
utils::CString label;
#endif
};
struct MetalMemoryMappedBuffer : public HwMemoryMappedBuffer {
MetalMemoryMappedBuffer(BufferObjectHandle boh, size_t const offset,
size_t const size, MapBufferAccessFlags const access)
: boh(boh), access(access), size(size), offset(offset) {
}
BufferObjectHandle boh{};
MapBufferAccessFlags access{};
uint32_t size = 0;
uint32_t offset = 0;
};
} // namespace backend
@@ -295,12 +295,6 @@ void MetalSwapChain::ensureDepthStencilTexture() {
void MetalSwapChain::setFrameScheduledCallback(
CallbackHandler* handler, FrameScheduledCallback&& callback, uint64_t flags) {
if (!callback) {
frameScheduled.handler = nullptr;
frameScheduled.callback.reset();
frameScheduled.flags = 0;
return;
}
frameScheduled.handler = handler;
frameScheduled.callback = std::make_shared<FrameScheduledCallback>(std::move(callback));
frameScheduled.flags = flags;
@@ -1492,11 +1486,6 @@ id<MTLBuffer> MetalDescriptorSet::finalizeAndGetBuffer(MetalDriver* driver, Shad
buffer = { [context.device newBufferWithLength:encoder.encodedLength
options:MTLResourceStorageModeShared],
TrackedMetalBuffer::Type::DESCRIPTOR_SET };
#if FILAMENT_METAL_DEBUG_LABELS
if (!label.empty()) {
buffer.get().label = @(label.c_str_safe());
}
#endif
}
[encoder setArgumentBuffer:buffer.get() offset:0];
+13 -20
View File
@@ -328,8 +328,8 @@ void NoopDriver::makeCurrent(Handle<HwSwapChain> drawSch, Handle<HwSwapChain> re
void NoopDriver::commit(Handle<HwSwapChain> sch) {
}
void NoopDriver::setPushConstant(ShaderStage stage, uint8_t index,
PushConstantVariant value) {
void NoopDriver::setPushConstant(backend::ShaderStage stage, uint8_t index,
backend::PushConstantVariant value) {
}
void NoopDriver::insertEventMarker(char const* string) {
@@ -353,8 +353,8 @@ void NoopDriver::readPixels(Handle<HwRenderTarget> src,
scheduleDestroy(std::move(p));
}
void NoopDriver::readBufferSubData(BufferObjectHandle boh,
uint32_t offset, uint32_t size, BufferDescriptor&& p) {
void NoopDriver::readBufferSubData(backend::BufferObjectHandle boh,
uint32_t offset, uint32_t size, backend::BufferDescriptor&& p) {
scheduleDestroy(std::move(p));
}
@@ -405,31 +405,24 @@ void NoopDriver::resetState(int) {
}
void NoopDriver::updateDescriptorSetBuffer(
DescriptorSetHandle dsh,
descriptor_binding_t binding,
BufferObjectHandle boh,
backend::DescriptorSetHandle dsh,
backend::descriptor_binding_t binding,
backend::BufferObjectHandle boh,
uint32_t offset,
uint32_t size) {
}
void NoopDriver::updateDescriptorSetTexture(
DescriptorSetHandle dsh,
descriptor_binding_t binding,
TextureHandle th,
backend::DescriptorSetHandle dsh,
backend::descriptor_binding_t binding,
backend::TextureHandle th,
SamplerParams params) {
}
void NoopDriver::bindDescriptorSet(
DescriptorSetHandle dsh,
descriptor_set_t set,
DescriptorSetOffsetArray&& offsets) {
}
void NoopDriver::unmapBuffer(MemoryMappedBufferHandle mmbh) {
}
void NoopDriver::copyToMemoryMappedBuffer(MemoryMappedBufferHandle mmbh, size_t offset,
BufferDescriptor&& data) {
backend::DescriptorSetHandle dsh,
backend::descriptor_set_t set,
backend::DescriptorSetOffsetArray&& offsets) {
}
} // namespace filament
+3 -5
View File
@@ -40,12 +40,10 @@ struct GLBufferObject : public HwBufferObject {
GLenum binding;
void* buffer;
};
} gl{};
BufferUsage usage : 4;
BufferObjectBinding bindingType : 4;
uint8_t mappingCount = 0;
} gl;
BufferUsage usage;
BufferObjectBinding bindingType;
uint16_t age = 0;
};
} // namespace filament::backend
@@ -1,154 +0,0 @@
/*
* Copyright (C) 2025 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 "GLMemoryMappedBuffer.h"
#include "GLBufferObject.h"
#include "GLUtils.h"
#include "OpenGLContext.h"
#include "OpenGLDriver.h"
#include "gl_headers.h"
#include <private/backend/HandleAllocator.h>
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/BitmaskEnum.h>
#include <limits>
#include <utility>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
namespace filament::backend {
GLMemoryMappedBuffer::GLMemoryMappedBuffer() = default;
GLMemoryMappedBuffer::~GLMemoryMappedBuffer() = default;
GLMemoryMappedBuffer::GLMemoryMappedBuffer(OpenGLContext& glc, HandleAllocatorGL& handleAllocator,
BufferObjectHandle boh,
size_t const offset, size_t const size, MapBufferAccessFlags const access)
: boh(boh), access(access) {
GLBufferObject* const bo = handleAllocator.handle_cast<GLBufferObject*>(boh);
assert_invariant(bo);
assert_invariant(bo->mappingCount < std::numeric_limits<uint8_t>::max());
assert_invariant(offset + size <= bo->byteCount);
if (any(access & MapBufferAccessFlags::WRITE_BIT)) {
assert_invariant(any(bo->usage & BufferUsage::SHARED_WRITE_BIT));
}
if (UTILS_UNLIKELY(glc.isES2())) {
gl.vaddr = static_cast<char*>(bo->gl.buffer) + offset;
gl.size = size;
gl.offset = offset;
gl.binding = 0; // in ES2 mode, bo->gl.binding is not available
gl.id = bo->gl.id;
bo->age++; // technically we could do this only in copy()
bo->mappingCount++;
return;
}
#if !defined(FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2)
void* addr = nullptr;
# if !defined(__EMSCRIPTEN__)
// unsynchronized is implied (but is incompatible with reading)
GLbitfield gl_access = GL_MAP_UNSYNCHRONIZED_BIT;
if (any(access & MapBufferAccessFlags::WRITE_BIT)) {
gl_access |= GL_MAP_WRITE_BIT;
}
if (any(access & MapBufferAccessFlags::INVALIDATE_RANGE_BIT)) {
// note: GL_MAP_INVALIDATE_RANGE_BIT is incompatible with GL_MAP_READ_BIT
gl_access |= GL_MAP_INVALIDATE_RANGE_BIT;
}
glc.bindBuffer(bo->gl.binding, bo->gl.id);
addr = glMapBufferRange(bo->gl.binding, GLsizeiptr(offset), GLsizeiptr(size), gl_access);
CHECK_GL_ERROR();
# endif
// if we failed here, addr would be nullptr
gl.vaddr = addr;
gl.size = size;
gl.offset = offset;
gl.binding = bo->gl.binding;
gl.id = bo->gl.id;
bo->mappingCount++;
#endif
}
void GLMemoryMappedBuffer::unmap(OpenGLContext& glc, HandleAllocatorGL& handleAllocator) const {
GLBufferObject* const bo = handleAllocator.handle_cast<GLBufferObject*>(boh);
assert_invariant(bo);
assert_invariant(bo->mappingCount > 0);
bo->mappingCount--;
if (UTILS_UNLIKELY(glc.isES2())) {
// nothing to do
return;
}
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
glc.bindBuffer(gl.binding, gl.id);
# if !defined(__EMSCRIPTEN__)
// don't unmap if we don't have a mapping or it didn't work
if (UTILS_LIKELY(gl.vaddr)) {
if (UTILS_UNLIKELY(glUnmapBuffer(gl.binding) == GL_FALSE)) {
// TODO: According to the spec, UnmapBuffer can return FALSE in rare conditions (e.g.
// during a screen mode change). Note that this is not a GL error, but the whole
// mapping is lost. This is very problematic for us here.
}
CHECK_GL_ERROR();
}
# endif
#endif
}
void GLMemoryMappedBuffer::copy(OpenGLContext& glc, OpenGLDriver& gld,
size_t const offset, BufferDescriptor&& data) const {
assert_invariant(any(access & MapBufferAccessFlags::WRITE_BIT));
assert_invariant(offset + data.size <= gl.size);
if (UTILS_LIKELY(gl.vaddr)) {
memcpy(static_cast<char *>(gl.vaddr) + offset, data.buffer, data.size);
} else {
assert_invariant(!glc.isES2());
// we couldn't map (WebGL or error), revert to glBufferSubData. In the future we can
// improve this by keeping around the BufferDescriptor and coalescing the calls
// to glBufferSubData.
glc.bindBuffer(gl.binding, gl.id);
glBufferSubData(gl.binding, GLintptr(gl.offset + offset), GLsizeiptr(data.size), data.buffer);
CHECK_GL_ERROR();
}
gld.scheduleDestroy(std::move(data));
}
} // namespace filament::backend
@@ -1,66 +0,0 @@
/*
* Copyright (C) 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef TNT_FILAMENT_BACKEND_OPENGL_GLMEMORYMAPPEDBUFFER_H
#define TNT_FILAMENT_BACKEND_OPENGL_GLMEMORYMAPPEDBUFFER_H
#include "DriverBase.h"
#include <private/backend/HandleAllocator.h>
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
#include "gl_headers.h"
#include <stddef.h>
#include <stdint.h>
namespace filament::backend {
class OpenGLContext;
class OpenGLDriver;
class BufferDescriptor;
struct GLBufferObject;
struct GLMemoryMappedBuffer : public HwMemoryMappedBuffer {
BufferObjectHandle boh;
MapBufferAccessFlags access;
struct {
void* vaddr = nullptr;
uint32_t size = 0;
uint32_t offset = 0;
GLenum binding = 0;
GLuint id = 0;
} gl;
GLMemoryMappedBuffer();
GLMemoryMappedBuffer(OpenGLContext& glc, HandleAllocatorGL& handleAllocator,
BufferObjectHandle boh, size_t offset, size_t size, MapBufferAccessFlags access);
~GLMemoryMappedBuffer();
void unmap(OpenGLContext& gl, HandleAllocatorGL& handleAllocator) const;
void copy(OpenGLContext& glc, OpenGLDriver& gld,
size_t offset, BufferDescriptor&& data) const;
};
} // namespace filament::backend
#endif //TNT_FILAMENT_BACKEND_OPENGL_GLMEMORYMAPPEDBUFFER_H
+7 -26
View File
@@ -21,14 +21,12 @@
#include <backend/platforms/OpenGLPlatform.h>
#include <backend/DriverEnums.h>
#include <backend/Platform.h>
#include <utils/Logger.h>
#include <utils/compiler.h>
#include <utils/debug.h>
#include <utils/ostream.h>
#include <algorithm>
#include <functional>
#include <string_view>
#include <utility>
@@ -103,8 +101,6 @@ OpenGLContext::OpenGLContext(OpenGLPlatform& platform,
initBugs(&bugs, ext, state.major, state.minor,
state.vendor, state.renderer, state.version, state.shader);
initWorkarounds(bugs, &ext);
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &gets.max_renderbuffer_size);
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &gets.max_texture_image_units);
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &gets.max_combined_texture_image_units);
@@ -563,22 +559,13 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts,
}
if (strstr(vendor, "Mesa")) {
if (strstr(renderer, "llvmpipe")) {
// Seen on
// [Mesa],
// [llvmpipe (LLVM 17.0.6, 256 bits)],
// [4.5 (Core Profile) Mesa 24.0.6-1],
// [4.50]
// not known which version are affected
bugs->rebind_buffer_after_deletion = true;
// Seen on
// [Mesa]
// [llvmpipe (LLVM 17.0.6, 256 bits)]
// [4.5 (Core Profile) Mesa 24.2.1 (git-c222f7299c)]
// [4.50]
bugs->disable_framebuffer_fetch_extension = true;
}
// Seen on
// [Mesa],
// [llvmpipe (LLVM 17.0.6, 256 bits)],
// [4.5 (Core Profile) Mesa 24.0.6-1],
// [4.50]
// not known which version are affected
bugs->rebind_buffer_after_deletion = true;
}
} else {
// When running under ANGLE, it's a different set of workaround that we need.
@@ -624,12 +611,6 @@ void OpenGLContext::initBugs(Bugs* bugs, Extensions const& exts,
#endif
}
void OpenGLContext::initWorkarounds(Bugs const& bugs, Extensions* ext) {
if (bugs.disable_framebuffer_fetch_extension) {
ext->EXT_shader_framebuffer_fetch = false;
}
}
FeatureLevel OpenGLContext::resolveFeatureLevel(GLint major, GLint minor,
Extensions const& exts,
Gets const& gets,
@@ -334,12 +334,6 @@ public:
// those particular browsers.
bool disable_depth_precache_for_default_material;
// On llvmpipe (mesa), enabling framebuffer fetch causes a crash in draw2
// 'OpenGL error 0x502 (GL_INVALID_OPERATION) in "draw2" at line 4389'
// This coincides with the use of framebuffer fetch (ColorGradingAsSubpass). We disable
// framebuffer fetch in the case of llvmpipe.
bool disable_framebuffer_fetch_extension;
} bugs = {};
// state getters -- as needed.
@@ -583,9 +577,6 @@ private:
{ bugs.disable_depth_precache_for_default_material,
"disable_depth_precache_for_default_material",
""},
{ bugs.disable_framebuffer_fetch_extension,
"disable_framebuffer_fetch_extension",
""},
}};
// this is chosen to minimize code size
@@ -616,8 +607,6 @@ private:
static void initProcs(Procs* procs,
Extensions const& exts, GLint major, GLint minor) noexcept;
static void initWorkarounds(Bugs const& bugs, Extensions* ext);
static FeatureLevel resolveFeatureLevel(GLint major, GLint minor,
Extensions const& exts,
Gets const& gets,
File diff suppressed because it is too large Load Diff
+1 -6
View File
@@ -24,7 +24,6 @@
#include "GLBufferObject.h"
#include "GLDescriptorSet.h"
#include "GLDescriptorSetLayout.h"
#include "GLMemoryMappedBuffer.h"
#include "GLTexture.h"
#include "ShaderCompilerService.h"
@@ -103,7 +102,7 @@ public:
bool rec709 = false;
struct {
CallbackHandler* handler = nullptr;
std::shared_ptr<FrameScheduledCallback> callback = nullptr;
FrameScheduledCallback callback;
} frameScheduled;
};
@@ -152,8 +151,6 @@ public:
using GLDescriptorSet = filament::backend::GLDescriptorSet;
using GLMemoryMappedBuffer = filament::backend::GLMemoryMappedBuffer;
struct GLStream : public HwStream {
using HwStream::HwStream;
struct Info {
@@ -217,8 +214,6 @@ public:
OpenGLDriver(OpenGLDriver const&) = delete;
OpenGLDriver& operator=(OpenGLDriver const&) = delete;
using DriverBase::scheduleDestroy;
private:
OpenGLPlatform& mPlatform;
OpenGLContext mContext;
@@ -322,7 +322,6 @@ Driver* PlatformEGL::createDriver(void* sharedContext, const DriverConfig& drive
mCurrentContextType = ContextType::UNPROTECTED;
mContextAttribs = std::move(contextAttribs);
mMSAA4XSupport = checkIfMSAASwapChainSupported(4);
initializeGlExtensions();
@@ -492,11 +491,34 @@ bool PlatformEGL::isMSAASwapChainSupported(uint32_t samples) const noexcept {
return true;
}
if (samples == 4) {
return mMSAA4XSupport;
Config configAttribs = {
{ EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT },
{ EGL_RED_SIZE, 8 },
{ EGL_GREEN_SIZE, 8 },
{ EGL_BLUE_SIZE, 8 },
{ EGL_DEPTH_SIZE, 24 },
{ EGL_SAMPLE_BUFFERS, 1 },
{ EGL_SAMPLES, samples },
};
if (!ext.egl.KHR_no_config_context) {
if (isOpenGL()) {
configAttribs[EGL_RENDERABLE_TYPE] = EGL_OPENGL_BIT;
} else {
configAttribs[EGL_RENDERABLE_TYPE] = EGL_OPENGL_ES2_BIT;
if (ext.egl.KHR_create_context) {
configAttribs[EGL_RENDERABLE_TYPE] |= EGL_OPENGL_ES3_BIT_KHR;
}
}
}
return false;
EGLConfig config = EGL_NO_CONFIG_KHR;
EGLint configsCount;
if (!eglChooseConfig(mEGLDisplay, configAttribs.data(), &config, 1, &configsCount)) {
return false;
}
return configsCount > 0;
}
Platform::SwapChain* PlatformEGL::createSwapChain(
@@ -816,38 +838,6 @@ EGLContext PlatformEGL::getContextForType(ContextType type) const noexcept {
}
}
bool PlatformEGL::checkIfMSAASwapChainSupported(uint32_t samples) const noexcept {
// Retrieve the config to see if the given number of samples is supported. The result is cached.
Config configAttribs = {
{ EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT },
{ EGL_RED_SIZE, 8 },
{ EGL_GREEN_SIZE, 8 },
{ EGL_BLUE_SIZE, 8 },
{ EGL_DEPTH_SIZE, 24 },
{ EGL_SAMPLE_BUFFERS, 1 },
{ EGL_SAMPLES, (EGLint)samples },
};
if (!ext.egl.KHR_no_config_context) {
if (isOpenGL()) {
configAttribs[EGL_RENDERABLE_TYPE] = EGL_OPENGL_BIT;
} else {
configAttribs[EGL_RENDERABLE_TYPE] = EGL_OPENGL_ES2_BIT;
if (ext.egl.KHR_create_context) {
configAttribs[EGL_RENDERABLE_TYPE] |= EGL_OPENGL_ES3_BIT_KHR;
}
}
}
EGLConfig config = EGL_NO_CONFIG_KHR;
EGLint configsCount;
if (!eglChooseConfig(mEGLDisplay, configAttribs.data(), &config, 1, &configsCount)) {
return false;
}
return configsCount > 0;
}
// ---------------------------------------------------------------------------------------------
PlatformEGL::Config::Config() = default;
+5 -1
View File
@@ -95,7 +95,11 @@ io::ostream& operator<<(io::ostream& out, ElementType type) {
}
io::ostream& operator<<(io::ostream& out, BufferUsage usage) {
return out << io::hex << uint32_t(usage) << io::dec;
switch (usage) {
CASE(BufferUsage, STATIC)
CASE(BufferUsage, DYNAMIC)
}
return out;
}
io::ostream& operator<<(io::ostream& out, CullingMode mode) {
@@ -107,11 +107,8 @@ VulkanCommandBuffer::VulkanCommandBuffer(VulkanContext const& context, VkDevice
.sType = VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO,
.handleTypes = context.getFenceExportFlags()
};
fenceCreateInfo.pNext = &exportFenceCreateInfo;
// Necessary to guard this. Otherwise, swiftshader would throw an error.
if (context.getFenceExportFlags()) {
fenceCreateInfo.pNext = &exportFenceCreateInfo;
}
vkCreateFence(device, &fenceCreateInfo, VKALLOC, &mFence);
}
+22 -60
View File
@@ -476,21 +476,6 @@ void VulkanDriver::updateDescriptorSetTexture(
}
}
void VulkanDriver::copyToMemoryMappedBuffer(MemoryMappedBufferHandle mmbh, size_t offset,
BufferDescriptor&& data) {
FVK_SYSTRACE_SCOPE();
auto mmb = resource_ptr<VulkanMemoryMappedBuffer>::cast(&mResourceManager, mmbh);
assert_invariant(any(mmb->access & MapBufferAccessFlags::WRITE_BIT));
assert_invariant(offset + data.size <= mmb->size);
// TODO: this isa zero-effort implementation of copyToMemoryMappedBuffer(), where we just
// call updateBufferObject(). This could be a fallback implementation for when
// shared memory is not available.
// On UMA systems, this should just be a memcpy into the memory-mapped buffer.
updateBufferObject(mmb->boh, std::move(data), mmb->offset + offset);
}
void VulkanDriver::flush(int) {
FVK_SYSTRACE_SCOPE();
endCommandRecording();
@@ -517,7 +502,7 @@ void VulkanDriver::finish(int dummy) {
void VulkanDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> rph,
Handle<HwVertexBuffer> vbh, Handle<HwIndexBuffer> ibh,
PrimitiveType pt, utils::CString&& tag) {
PrimitiveType pt, utils::CString tag) {
FVK_SYSTRACE_SCOPE();
auto vb = resource_ptr<VulkanVertexBuffer>::cast(&mResourceManager, vbh);
auto ib = resource_ptr<VulkanIndexBuffer>::cast(&mResourceManager, ibh);
@@ -536,7 +521,7 @@ void VulkanDriver::destroyRenderPrimitive(Handle<HwRenderPrimitive> rph) {
}
void VulkanDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vbih, uint8_t bufferCount,
uint8_t attributeCount, AttributeArray attributes, utils::CString&& tag) {
uint8_t attributeCount, AttributeArray attributes, utils::CString tag) {
FVK_SYSTRACE_SCOPE();
auto vbi = resource_ptr<VulkanVertexBufferInfo>::make(&mResourceManager, vbih, bufferCount,
attributeCount, attributes);
@@ -554,7 +539,7 @@ void VulkanDriver::destroyVertexBufferInfo(Handle<HwVertexBufferInfo> vbih) {
}
void VulkanDriver::createVertexBufferR(Handle<HwVertexBuffer> vbh, uint32_t vertexCount,
Handle<HwVertexBufferInfo> vbih, utils::CString&& tag) {
Handle<HwVertexBufferInfo> vbih, utils::CString tag) {
FVK_SYSTRACE_SCOPE();
auto vbi = resource_ptr<VulkanVertexBufferInfo>::cast(&mResourceManager, vbih);
auto vb = resource_ptr<VulkanVertexBuffer>::make(&mResourceManager, vbh, mContext, mStagePool,
@@ -573,7 +558,7 @@ void VulkanDriver::destroyVertexBuffer(Handle<HwVertexBuffer> vbh) {
}
void VulkanDriver::createIndexBufferR(Handle<HwIndexBuffer> ibh, ElementType elementType,
uint32_t indexCount, BufferUsage usage, utils::CString&& tag) {
uint32_t indexCount, BufferUsage usage, utils::CString tag) {
FVK_SYSTRACE_SCOPE();
auto elementSize = (uint8_t) getElementTypeSize(elementType);
auto ib = resource_ptr<VulkanIndexBuffer>::make(&mResourceManager, ibh, mContext, mAllocator,
@@ -592,7 +577,7 @@ void VulkanDriver::destroyIndexBuffer(Handle<HwIndexBuffer> ibh) {
}
void VulkanDriver::createBufferObjectR(Handle<HwBufferObject> boh, uint32_t byteCount,
BufferObjectBinding bindingType, BufferUsage usage, utils::CString&& tag) {
BufferObjectBinding bindingType, BufferUsage usage, utils::CString tag) {
FVK_SYSTRACE_SCOPE();
auto bo = resource_ptr<VulkanBufferObject>::make(&mResourceManager, boh, mContext, mAllocator,
mStagePool, mBufferCache, byteCount, bindingType);
@@ -611,7 +596,7 @@ void VulkanDriver::destroyBufferObject(Handle<HwBufferObject> boh) {
void VulkanDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
TextureUsage usage, utils::CString&& tag) {
TextureUsage usage, utils::CString tag) {
FVK_SYSTRACE_SCOPE();
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mPlatform->getDevice(),
mPlatform->getPhysicalDevice(), mContext, mAllocator, &mResourceManager, &mCommands,
@@ -628,7 +613,7 @@ void VulkanDriver::createTextureR(Handle<HwTexture> th, SamplerType target, uint
}
void VulkanDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> srch,
uint8_t baseLevel, uint8_t levelCount, utils::CString&& tag) {
uint8_t baseLevel, uint8_t levelCount, utils::CString tag) {
auto src = resource_ptr<VulkanTexture>::cast(&mResourceManager, srch);
auto texture = resource_ptr<VulkanTexture>::make(&mResourceManager, th, mPlatform->getDevice(),
mPlatform->getPhysicalDevice(), mContext, mAllocator, &mCommands, src, baseLevel,
@@ -639,7 +624,7 @@ void VulkanDriver::createTextureViewR(Handle<HwTexture> th, Handle<HwTexture> sr
void VulkanDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwTexture> srch,
backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b,
backend::TextureSwizzle a, utils::CString&& tag) {
backend::TextureSwizzle a, utils::CString tag) {
TextureSwizzle const swizzleArray[] = { r, g, b, a };
VkComponentMapping const swizzle = fvkutils::getSwizzleMap(swizzleArray);
auto src = resource_ptr<VulkanTexture>::cast(&mResourceManager, srch);
@@ -651,7 +636,7 @@ void VulkanDriver::createTextureViewSwizzleR(Handle<HwTexture> th, Handle<HwText
void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::SamplerType target,
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
Platform::ExternalImageHandleRef externalImage, utils::CString&& tag) {
Platform::ExternalImageHandleRef externalImage, utils::CString tag) {
FVK_SYSTRACE_SCOPE();
auto metadata = mPlatform->extractExternalImageMetadata(externalImage);
@@ -702,7 +687,7 @@ void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::S
void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::SamplerType target,
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
void* externalImage, utils::CString&& tag) {
void* externalImage, utils::CString tag) {
FVK_SYSTRACE_SCOPE();
assert_invariant(false && "Not supported in Vulkan backend");
// not supported in this backend
@@ -710,14 +695,14 @@ void VulkanDriver::createTextureExternalImageR(Handle<HwTexture> th, backend::Sa
void VulkanDriver::createTextureExternalImagePlaneR(Handle<HwTexture> th,
backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage,
void* image, uint32_t plane, utils::CString&& tag) {
void* image, uint32_t plane, utils::CString tag) {
assert_invariant(false && "Not supported in Vulkan backend");
}
void VulkanDriver::importTextureR(Handle<HwTexture> th, intptr_t id,
SamplerType target, uint8_t levels,
TextureFormat format, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth,
TextureUsage usage, utils::CString&& tag) {
TextureUsage usage, utils::CString tag) {
// not supported in this backend
assert_invariant(false && "Not supported in Vulkan backend");
mResourceManager.associateHandle(th.getId(), std::move(tag));
@@ -733,7 +718,7 @@ void VulkanDriver::destroyTexture(Handle<HwTexture> th) {
mExternalImageManager.removeExternallySampledTexture(texture);
}
void VulkanDriver::createProgramR(Handle<HwProgram> ph, Program&& program, utils::CString&& tag) {
void VulkanDriver::createProgramR(Handle<HwProgram> ph, Program&& program, utils::CString tag) {
FVK_SYSTRACE_SCOPE();
auto vprogram = resource_ptr<VulkanProgram>::make(&mResourceManager, ph, mPlatform->getDevice(),
program);
@@ -749,7 +734,7 @@ void VulkanDriver::destroyProgram(Handle<HwProgram> ph) {
vprogram.dec();
}
void VulkanDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, utils::CString&& tag) {
void VulkanDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, utils::CString tag) {
assert_invariant(mDefaultRenderTarget); // Default render target should already exist.
auto renderTarget = resource_ptr<VulkanRenderTarget>::make(&mResourceManager, rth,
@@ -762,7 +747,7 @@ void VulkanDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> rth, utils:
void VulkanDriver::createRenderTargetR(Handle<HwRenderTarget> rth,
TargetBufferFlags targets, uint32_t width, uint32_t height, uint8_t samples,
uint8_t layerCount, MRT color, TargetBufferInfo depth, TargetBufferInfo stencil,
utils::CString&& tag) {
utils::CString tag) {
FVK_SYSTRACE_SCOPE();
@@ -839,7 +824,7 @@ void VulkanDriver::destroyRenderTarget(Handle<HwRenderTarget> rth) {
}
}
void VulkanDriver::createFenceR(Handle<HwFence> fh, utils::CString&& tag) {
void VulkanDriver::createFenceR(Handle<HwFence> fh, utils::CString tag) {
VulkanCommandBuffer* cmdbuf;
if (mCurrentRenderPass.commandBuffer) {
cmdbuf = mCurrentRenderPass.commandBuffer;
@@ -854,7 +839,7 @@ void VulkanDriver::createFenceR(Handle<HwFence> fh, utils::CString&& tag) {
mResourceManager.associateHandle(fh.getId(), std::move(tag));
}
void VulkanDriver::createSyncR(Handle<HwSync> sh, utils::CString&& tag) {
void VulkanDriver::createSyncR(Handle<HwSync> sh, utils::CString tag) {
auto sync = resource_ptr<VulkanSync>::cast(&mResourceManager, sh);
VkFence fence = VK_NULL_HANDLE;
std::shared_ptr<VulkanCmdFence> fenceStatus;
@@ -885,7 +870,7 @@ void VulkanDriver::createSyncR(Handle<HwSync> sh, utils::CString&& tag) {
}
void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow, uint64_t flags,
utils::CString&& tag) {
utils::CString tag) {
FVK_SYSTRACE_SCOPE();
// Running gc() to guard against an edge case where the old swapchains need to have been
// destroyed before the new swapchain can be created. Otherwise, we would fail
@@ -914,7 +899,7 @@ void VulkanDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
}
void VulkanDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t width,
uint32_t height, uint64_t flags, utils::CString&& tag) {
uint32_t height, uint64_t flags, utils::CString tag) {
if ((flags & backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE) != 0 && !isSRGBSwapChainSupported()) {
FVK_LOGW << "sRGB swapchain requested, but Platform does not support it";
flags = flags | ~(backend::SWAP_CHAIN_CONFIG_SRGB_COLORSPACE);
@@ -927,13 +912,13 @@ void VulkanDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t wi
mResourceManager.associateHandle(sch.getId(), std::move(tag));
}
void VulkanDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, utils::CString&& tag) {
void VulkanDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, utils::CString tag) {
// nothing to do, timer query was constructed in createTimerQueryS
mResourceManager.associateHandle(tqh.getId(), std::move(tag));
}
void VulkanDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh,
backend::DescriptorSetLayout&& info, utils::CString&& tag) {
backend::DescriptorSetLayout&& info, utils::CString tag) {
FVK_SYSTRACE_SCOPE();
auto layout = mDescriptorSetLayoutCache.createLayout(dslh, std::move(info));
layout.inc();
@@ -941,7 +926,7 @@ void VulkanDriver::createDescriptorSetLayoutR(Handle<HwDescriptorSetLayout> dslh
}
void VulkanDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
Handle<HwDescriptorSetLayout> dslh, utils::CString&& tag) {
Handle<HwDescriptorSetLayout> dslh, utils::CString tag) {
FVK_SYSTRACE_SCOPE();
fvkmemory::resource_ptr<VulkanDescriptorSetLayout> layout =
fvkmemory::resource_ptr<VulkanDescriptorSetLayout>::cast(&mResourceManager, dslh);
@@ -955,16 +940,6 @@ void VulkanDriver::createDescriptorSetR(Handle<HwDescriptorSet> dsh,
mResourceManager.associateHandle(dsh.getId(), std::move(tag));
}
void VulkanDriver::mapBufferR(MemoryMappedBufferHandle mmbh,
BufferObjectHandle boh, size_t offset,
size_t size, MapBufferAccessFlags access, utils::CString&& tag) {
FVK_SYSTRACE_SCOPE();
auto mmb = resource_ptr<VulkanMemoryMappedBuffer>::make(&mResourceManager, mmbh,
boh, offset, size, access);
mmb.inc();
mResourceManager.associateHandle(mmbh.getId(), std::move(tag));
}
Handle<HwVertexBufferInfo> VulkanDriver::createVertexBufferInfoS() noexcept {
return mResourceManager.allocHandle<VulkanVertexBufferInfo>();
}
@@ -1063,19 +1038,6 @@ Handle<HwDescriptorSet> VulkanDriver::createDescriptorSetS() noexcept {
return mResourceManager.allocHandle<VulkanDescriptorSet>();
}
MemoryMappedBufferHandle VulkanDriver::mapBufferS() noexcept {
return mResourceManager.allocHandle<VulkanMemoryMappedBuffer>();
}
void VulkanDriver::unmapBuffer(MemoryMappedBufferHandle mmbh) {
if (!mmbh) {
return;
}
auto mmb = resource_ptr<VulkanMemoryMappedBuffer>::cast(&mResourceManager, mmbh);
mmb.dec();
}
void VulkanDriver::destroySwapChain(Handle<HwSwapChain> sch) {
if (!sch) {
return;
@@ -225,17 +225,6 @@ private:
fvkutils::UniformBufferBitmask mUboMask;
};
struct VulkanMemoryMappedBuffer : public HwMemoryMappedBuffer, Resource {
VulkanMemoryMappedBuffer(BufferObjectHandle boh, size_t const offset,
size_t const size, MapBufferAccessFlags const access)
: boh(boh), access(access), size(size), offset(offset) {
}
BufferObjectHandle boh{};
MapBufferAccessFlags access{};
uint32_t size = 0;
uint32_t offset = 0;
};
using PushConstantNameArray = utils::FixedCapacityVector<char const*>;
using PushConstantNameByStage = std::array<PushConstantNameArray, Program::SHADER_TYPE_COUNT>;
@@ -123,9 +123,9 @@ void VulkanSwapChain::present(DriverBase& driver) {
if (frameScheduled.callback) {
driver.scheduleCallback(frameScheduled.handler,
[callback = frameScheduled.callback]() {
[callback = std::move(frameScheduled.callback)]() {
PresentCallable noop = PresentCallable(PresentCallable::noopPresent, nullptr);
callback->operator()(noop);
callback(noop);
});
}
}
@@ -29,7 +29,6 @@
#include <bluevk/BlueVK.h>
#include <utils/FixedCapacityVector.h>
#include <memory>
using namespace bluevk;
@@ -83,13 +82,8 @@ struct VulkanSwapChain : public HwSwapChain, fvkmemory::Resource {
inline void setFrameScheduledCallback(CallbackHandler* handler,
FrameScheduledCallback&& callback) noexcept {
if (!callback) {
frameScheduled.handler = nullptr;
frameScheduled.callback.reset();
return;
}
frameScheduled.handler = handler;
frameScheduled.callback = std::make_shared<FrameScheduledCallback>(std::move(callback));
frameScheduled.callback = std::move(callback);
}
private:
@@ -110,7 +104,7 @@ private:
// These fields store a callback to notify the client that Filament is commiting a frame.
struct {
CallbackHandler* handler = nullptr;
std::shared_ptr<FrameScheduledCallback> callback = nullptr;
FrameScheduledCallback callback;
} frameScheduled;
// We create VulkanTextures based on VkImages. VulkanTexture has facilities for doing layout
@@ -39,7 +39,6 @@ template ResourceType getTypeEnum<VulkanDescriptorSet>() noexcept;
template ResourceType getTypeEnum<VulkanFence>() noexcept;
template ResourceType getTypeEnum<VulkanBuffer>() noexcept;
template ResourceType getTypeEnum<VulkanSync>() noexcept;
template ResourceType getTypeEnum<VulkanMemoryMappedBuffer>() noexcept;
template<typename D>
ResourceType getTypeEnum() noexcept {
@@ -97,9 +96,6 @@ ResourceType getTypeEnum() noexcept {
if constexpr (std::is_same_v<D, VulkanSync>) {
return ResourceType::SYNC;
}
if constexpr (std::is_same_v<D, VulkanMemoryMappedBuffer>) {
return ResourceType::MEMORY_MAPPED_BUFFER;
}
return ResourceType::UNDEFINED_TYPE;
}
@@ -141,8 +137,6 @@ std::string_view getTypeStr(ResourceType type) {
return "VulkanBuffer";
case ResourceType::SYNC:
return "Sync";
case ResourceType::MEMORY_MAPPED_BUFFER:
return "VulkanMemoryMappedBuffer";
case ResourceType::UNDEFINED_TYPE:
return "";
}
@@ -53,8 +53,7 @@ enum class ResourceType : uint8_t {
STAGE_SEGMENT = 15,
STAGE_IMAGE = 16,
SYNC = 17,
MEMORY_MAPPED_BUFFER = 18,
UNDEFINED_TYPE = 19, // Must be the last enum because we use it for iterating over the enums.
UNDEFINED_TYPE = 18, // Must be the last enum because we use it for iterating over the enums.
};
template<typename D>
@@ -117,9 +117,6 @@ void ResourceManager::destroyWithType(ResourceType type, HandleId id) {
case ResourceType::SYNC:
destruct<VulkanSync>(Handle<VulkanSync>(id));
break;
case ResourceType::MEMORY_MAPPED_BUFFER:
destruct<VulkanMemoryMappedBuffer>(Handle<VulkanMemoryMappedBuffer>(id));
break;
case ResourceType::UNDEFINED_TYPE:
break;
}
+23 -44
View File
@@ -450,7 +450,7 @@ Handle<HwTexture> WebGPUDriver::createTextureExternalImagePlaneS() noexcept {
// ------------------------------------------------------------------------------------------------
void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
const uint64_t flags, utils::CString&& tag) {
const uint64_t flags, utils::CString tag) {
FWGPU_SYSTRACE_SCOPE();
// TODO: support MSAA swapchain
@@ -480,7 +480,7 @@ void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
}
void WebGPUDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t width,
uint32_t height, uint64_t flags, utils::CString&& tag) {
uint32_t height, uint64_t flags, utils::CString tag) {
wgpu::Extent2D extent = { .width = width, .height = height };
mSwapChain = constructHandle<WebGPUSwapChain>(sch, extent, mAdapter,
mDevice, flags);
@@ -493,7 +493,7 @@ void WebGPUDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch, uint32_t wi
void WebGPUDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vertexBufferInfoHandle,
const uint8_t bufferCount, const uint8_t attributeCount, const AttributeArray attributes,
utils::CString&& tag) {
utils::CString tag) {
FWGPU_SYSTRACE_SCOPE();
constructHandle<WebGPUVertexBufferInfo>(vertexBufferInfoHandle, bufferCount, attributeCount,
attributes, mDeviceLimits);
@@ -502,7 +502,7 @@ void WebGPUDriver::createVertexBufferInfoR(Handle<HwVertexBufferInfo> vertexBuff
void WebGPUDriver::createVertexBufferR(Handle<HwVertexBuffer> vertexBufferHandle,
const uint32_t vertexCount, Handle<HwVertexBufferInfo> vertexBufferInfoHandle,
utils::CString&& tag) {
utils::CString tag) {
FWGPU_SYSTRACE_SCOPE();
const auto vertexBufferInfo = handleCast<WebGPUVertexBufferInfo>(vertexBufferInfoHandle);
constructHandle<WebGPUVertexBuffer>(vertexBufferHandle, vertexCount,
@@ -512,7 +512,7 @@ void WebGPUDriver::createVertexBufferR(Handle<HwVertexBuffer> vertexBufferHandle
void WebGPUDriver::createIndexBufferR(Handle<HwIndexBuffer> indexBufferHandle,
const ElementType elementType, const uint32_t indexCount, const BufferUsage usage,
utils::CString&& tag) {
utils::CString tag) {
FWGPU_SYSTRACE_SCOPE();
const auto elementSize = static_cast<uint8_t>(getElementTypeSize(elementType));
constructHandle<WebGPUIndexBuffer>(indexBufferHandle, mDevice, elementSize, indexCount);
@@ -521,7 +521,7 @@ void WebGPUDriver::createIndexBufferR(Handle<HwIndexBuffer> indexBufferHandle,
void WebGPUDriver::createBufferObjectR(Handle<HwBufferObject> bufferObjectHandle,
const uint32_t byteCount, const BufferObjectBinding bindingType, const BufferUsage usage,
utils::CString&& tag) {
utils::CString tag) {
FWGPU_SYSTRACE_SCOPE();
constructHandle<WebGPUBufferObject>(bufferObjectHandle, mDevice, bindingType, byteCount);
setDebugTag(bufferObjectHandle.getId(), std::move(tag));
@@ -530,7 +530,7 @@ void WebGPUDriver::createBufferObjectR(Handle<HwBufferObject> bufferObjectHandle
void WebGPUDriver::createTextureR(Handle<HwTexture> textureHandle, const SamplerType target,
const uint8_t levels, const TextureFormat format, const uint8_t samples,
const uint32_t width, const uint32_t height, const uint32_t depth,
const TextureUsage usage, utils::CString&& tag) {
const TextureUsage usage, utils::CString tag) {
FWGPU_SYSTRACE_SCOPE();
constructHandle<WebGPUTexture>(textureHandle, target, levels, format, samples, width, height,
depth, usage, mDevice);
@@ -539,7 +539,7 @@ void WebGPUDriver::createTextureR(Handle<HwTexture> textureHandle, const Sampler
void WebGPUDriver::createTextureViewR(Handle<HwTexture> textureHandle,
Handle<HwTexture> sourceTextureHandle, const uint8_t baseLevel, const uint8_t levelCount,
utils::CString&& tag) {
utils::CString tag) {
auto source = handleCast<WebGPUTexture>(sourceTextureHandle);
constructHandle<WebGPUTexture>(textureHandle, source, baseLevel, levelCount);
@@ -550,7 +550,7 @@ void WebGPUDriver::createTextureViewR(Handle<HwTexture> textureHandle,
void WebGPUDriver::createTextureViewSwizzleR(Handle<HwTexture> textureHandle,
Handle<HwTexture> sourceTextureHandle, const backend::TextureSwizzle r,
const backend::TextureSwizzle g, const backend::TextureSwizzle b,
const backend::TextureSwizzle a, utils::CString&& tag) {
const backend::TextureSwizzle a, utils::CString tag) {
if (!isTextureSwizzleSupported()) {
FWGPU_LOGW << "WebGPUDriver::createTextureViewSwizzleR called while texture swizzling is "
@@ -577,7 +577,7 @@ void WebGPUDriver::createTextureViewSwizzleR(Handle<HwTexture> textureHandle,
void WebGPUDriver::createTextureExternalImage2R(Handle<HwTexture> textureHandle,
const backend::SamplerType target, const backend::TextureFormat format,
const uint32_t width, const uint32_t height, const backend::TextureUsage usage,
Platform::ExternalImageHandleRef externalImage, utils::CString&& tag) {
Platform::ExternalImageHandleRef externalImage, utils::CString tag) {
FWGPU_SYSTRACE_SCOPE();
PANIC_POSTCONDITION("External WebGPU Texture is not supported");
}
@@ -585,27 +585,27 @@ void WebGPUDriver::createTextureExternalImage2R(Handle<HwTexture> textureHandle,
void WebGPUDriver::createTextureExternalImageR(Handle<HwTexture> textureHandle,
const backend::SamplerType target, const backend::TextureFormat format,
const uint32_t width, const uint32_t height, const backend::TextureUsage usage,
void* externalImage, utils::CString&& tag) {
void* externalImage, utils::CString tag) {
FWGPU_SYSTRACE_SCOPE();
PANIC_POSTCONDITION("External WebGPU Texture is not supported");
}
void WebGPUDriver::createTextureExternalImagePlaneR(Handle<HwTexture> textureHandle,
const backend::TextureFormat format, const uint32_t width, const uint32_t height,
const backend::TextureUsage usage, void* image, const uint32_t plane, utils::CString&& tag) {
const backend::TextureUsage usage, void* image, const uint32_t plane, utils::CString tag) {
PANIC_POSTCONDITION("External WebGPU Texture is not supported");
}
void WebGPUDriver::importTextureR(Handle<HwTexture> textureHandle, const intptr_t id,
const SamplerType target, const uint8_t levels, const TextureFormat format,
const uint8_t samples, const uint32_t width, const uint32_t height, const uint32_t depth,
const TextureUsage usage, utils::CString&& tag) {
const TextureUsage usage, utils::CString tag) {
PANIC_POSTCONDITION("Import WebGPU Texture is not supported");
}
void WebGPUDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> renderPrimitiveHandle,
Handle<HwVertexBuffer> vertexBufferHandle, Handle<HwIndexBuffer> indexBufferHandle,
const PrimitiveType primitiveType, utils::CString&& tag) {
const PrimitiveType primitiveType, utils::CString tag) {
FWGPU_SYSTRACE_SCOPE();
assert_invariant(mDevice);
const auto renderPrimitive = constructHandle<WebGPURenderPrimitive>(renderPrimitiveHandle);
@@ -618,14 +618,14 @@ void WebGPUDriver::createRenderPrimitiveR(Handle<HwRenderPrimitive> renderPrimit
}
void WebGPUDriver::createProgramR(Handle<HwProgram> programHandle, Program&& program,
utils::CString&& tag) {
utils::CString tag) {
FWGPU_SYSTRACE_SCOPE();
constructHandle<WebGPUProgram>(programHandle, mDevice, program);
setDebugTag(programHandle.getId(), std::move(tag));
}
void WebGPUDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> renderTargetHandle,
utils::CString&& tag) {
utils::CString tag) {
assert_invariant(!mDefaultRenderTarget);
mDefaultRenderTarget = constructHandle<WebGPURenderTarget>(renderTargetHandle);
assert_invariant(mDefaultRenderTarget);
@@ -638,7 +638,7 @@ void WebGPUDriver::createDefaultRenderTargetR(Handle<HwRenderTarget> renderTarge
void WebGPUDriver::createRenderTargetR(Handle<HwRenderTarget> renderTargetHandle,
const TargetBufferFlags targetFlags, const uint32_t width, const uint32_t height,
const uint8_t samples, const uint8_t layerCount, const MRT color,
const TargetBufferInfo depth, const TargetBufferInfo stencil, utils::CString&& tag) {
const TargetBufferInfo depth, const TargetBufferInfo stencil, utils::CString tag) {
FWGPU_SYSTRACE_SCOPE();
constructHandle<WebGPURenderTarget>(
renderTargetHandle, width, height, samples, layerCount, color, depth, stencil,
@@ -650,7 +650,7 @@ void WebGPUDriver::createRenderTargetR(Handle<HwRenderTarget> renderTargetHandle
setDebugTag(renderTargetHandle.getId(), std::move(tag));
}
void WebGPUDriver::createFenceR(Handle<HwFence> fenceHandle, utils::CString&& tag) {
void WebGPUDriver::createFenceR(Handle<HwFence> fenceHandle, utils::CString tag) {
// The handle is constructed synchronously in createFenceS.
const auto fence = handleCast<WebGPUFence>(fenceHandle);
assert_invariant(mQueue);
@@ -658,24 +658,24 @@ void WebGPUDriver::createFenceR(Handle<HwFence> fenceHandle, utils::CString&& ta
setDebugTag(fenceHandle.getId(), std::move(tag));
}
void WebGPUDriver::createSyncR(Handle<HwSync> syncHandle, utils::CString&& tag) {
void WebGPUDriver::createSyncR(Handle<HwSync> syncHandle, utils::CString tag) {
// TODO: Ensure sync is active, and then invoke and clear all pending
// callbacks.
setDebugTag(syncHandle.getId(), std::move(tag));
}
void WebGPUDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, utils::CString&& tag) {}
void WebGPUDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, utils::CString tag) {}
void WebGPUDriver::createDescriptorSetLayoutR(
Handle<HwDescriptorSetLayout> descriptorSetLayoutHandle,
backend::DescriptorSetLayout&& info, utils::CString&& tag) {
backend::DescriptorSetLayout&& info, utils::CString tag) {
FWGPU_SYSTRACE_SCOPE();
constructHandle<WebGPUDescriptorSetLayout>(descriptorSetLayoutHandle, std::move(info), mDevice);
setDebugTag(descriptorSetLayoutHandle.getId(), std::move(tag));
}
void WebGPUDriver::createDescriptorSetR(Handle<HwDescriptorSet> descriptorSetHandle,
Handle<HwDescriptorSetLayout> descriptorSetLayoutHandle, utils::CString&& tag) {
Handle<HwDescriptorSetLayout> descriptorSetLayoutHandle, utils::CString tag) {
FWGPU_SYSTRACE_SCOPE();
auto layout = handleCast<WebGPUDescriptorSetLayout>(descriptorSetLayoutHandle);
constructHandle<WebGPUDescriptorSet>(descriptorSetHandle, layout->getLayout(),
@@ -2091,7 +2091,7 @@ void WebGPUDriver::bindDescriptorSet(Handle<HwDescriptorSet> descriptorSetHandle
.offsets = std::move(offsets) };
}
void WebGPUDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString&& tag) {
void WebGPUDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
//todo
}
@@ -2207,25 +2207,4 @@ wgpu::AddressMode WebGPUDriver::fWrapModeToWAddressMode(const SamplerWrapMode& f
return wgpu::AddressMode::Undefined;
}
MemoryMappedBufferHandle WebGPUDriver::mapBufferS() noexcept {
// TODO: MetalDriver::mapBufferS
return {};
}
void WebGPUDriver::mapBufferR(MemoryMappedBufferHandle mmbh,
BufferObjectHandle boh, size_t offset,
size_t size, MapBufferAccessFlags access, utils::CString&& tag) {
// TODO: MetalDriver::mapBufferR
}
void WebGPUDriver::unmapBuffer(MemoryMappedBufferHandle mmbh) {
// TODO: MetalDriver::unmapBuffer
}
void WebGPUDriver::copyToMemoryMappedBuffer(MemoryMappedBufferHandle mmbh, size_t offset,
BufferDescriptor&& data) {
// TODO: MetalDriver::copyToMemoryMappedBuffer
}
} // namespace filament::backend
+1 -1
View File
@@ -68,7 +68,7 @@ private:
[[nodiscard]] ShaderLanguage getShaderLanguage() const noexcept final;
[[nodiscard]] wgpu::Sampler makeSampler(SamplerParams const& params);
[[nodiscard]] static wgpu::AddressMode fWrapModeToWAddressMode(const filament::backend::SamplerWrapMode& fUsage);
void setDebugTag(HandleBase::HandleId handleId, utils::CString&& tag);
void setDebugTag(HandleBase::HandleId handleId, utils::CString tag);
// The platform (e.g. OS) specific aspects of the WebGPU backend are strictly only
// handled in the WebGPUPlatform.
-37
View File
@@ -39,12 +39,7 @@ Cleanup::~Cleanup() {
for (const auto descriptorSetLayout : mDescriptorSetLayouts) {
mDriverApi.destroyDescriptorSetLayout(descriptorSetLayout);
}
for (const auto memoryMappedBuffer : mMemoryMappedBuffers) {
// destroy those before buffer objects
mDriverApi.unmapBuffer(memoryMappedBuffer);
}
for (const auto bufferObject : mBufferObjects) {
// destroy those after memory mapped buffers
mDriverApi.destroyBufferObject(bufferObject);
}
for (const auto program : mPrograms) {
@@ -56,18 +51,6 @@ Cleanup::~Cleanup() {
for (const auto renderTarget : mRenderTargets) {
mDriverApi.destroyRenderTarget(renderTarget);
}
for (const auto renderPrimitive : mRenderPrimitives) {
mDriverApi.destroyRenderPrimitive(renderPrimitive);
}
for (const auto vertexBufferInfo : mVertexBufferInfos) {
mDriverApi.destroyVertexBufferInfo(vertexBufferInfo);
}
for (const auto indexBuffer : mIndexBuffers) {
mDriverApi.destroyIndexBuffer(indexBuffer);
}
for (const auto vertexBuffer : mVertexBuffers) {
mDriverApi.destroyVertexBuffer(vertexBuffer);
}
for (const auto& callback : mCallbacks) {
callback();
@@ -103,26 +86,6 @@ template <>
void Cleanup::addInternal(filament::backend::RenderTargetHandle handle) {
mRenderTargets.push_back(handle);
}
template <>
void Cleanup::addInternal(filament::backend::MemoryMappedBufferHandle handle) {
mMemoryMappedBuffers.push_back(handle);
}
template <>
void Cleanup::addInternal(filament::backend::RenderPrimitiveHandle handle) {
mRenderPrimitives.push_back(handle);
}
template <>
void Cleanup::addInternal(filament::backend::VertexBufferInfoHandle handle) {
mVertexBufferInfos.push_back(handle);
}
template <>
void Cleanup::addInternal(filament::backend::VertexBufferHandle handle) {
mVertexBuffers.push_back(handle);
}
template <>
void Cleanup::addInternal(filament::backend::IndexBufferHandle handle) {
mIndexBuffers.push_back(handle);
}
void Cleanup::addPostCall(std::function<void()> callback){
mCallbacks.emplace_back(std::move(callback));
-5
View File
@@ -68,11 +68,6 @@ private:
std::vector<filament::backend::ProgramHandle> mPrograms;
std::vector<filament::backend::TextureHandle> mTextures;
std::vector<filament::backend::RenderTargetHandle> mRenderTargets;
std::vector<filament::backend::RenderPrimitiveHandle> mRenderPrimitives;
std::vector<filament::backend::VertexBufferInfoHandle> mVertexBufferInfos;
std::vector<filament::backend::VertexBufferHandle> mVertexBuffers;
std::vector<filament::backend::IndexBufferHandle> mIndexBuffers;
std::vector<filament::backend::MemoryMappedBufferHandle> mMemoryMappedBuffers;
std::vector<std::function<void()>> mCallbacks;
};
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

-4
View File
@@ -269,10 +269,6 @@ TEST_F(BlitTest, ColorResolve) {
SKIP_IF(Backend::WEBGPU, "test cases fail in WebGPU, see b/424157731");
auto& api = getDriverApi();
if (api.getFeatureLevel() < FeatureLevel::FEATURE_LEVEL_2) {
GTEST_SKIP() << "Skipping test because multi-sampled textures are not supported at Feature level < 2";
}
constexpr int kSrcTexWidth = 256;
constexpr int kSrcTexHeight = 256;
constexpr int kDstTexWidth = 256;
+3 -12
View File
@@ -25,6 +25,8 @@ using namespace filament::backend;
namespace test {
TEST_F(BackendTest, FrameScheduledCallback) {
SKIP_IF(Backend::OPENGL, "Frame callbacks are unsupported in OpenGL");
SKIP_IF(Backend::VULKAN, "Frame callbacks are unsupported in Vulkan, see b/417254479");
SKIP_IF(Backend::WEBGPU, "Frame callbacks are unsupported in WebGPU");
auto& api = getDriverApi();
@@ -66,18 +68,7 @@ TEST_F(BackendTest, FrameScheduledCallback) {
callbackCountB++;
}, 0);
// Render another frame.
api.makeCurrent(swapChain, swapChain);
api.beginFrame(0, 0, 0);
api.beginRenderPass(renderTarget, {});
api.endRenderPass(0);
api.commit(swapChain);
api.endFrame(0);
// Now, unset the callback
api.setFrameScheduledCallback(swapChain, nullptr, {}, 0);
// Render a final frame. This time no callback should be called.
// Render one final frame.
api.makeCurrent(swapChain, swapChain);
api.beginFrame(0, 0, 0);
api.beginRenderPass(renderTarget, {});
+14 -3
View File
@@ -392,6 +392,10 @@ TEST_F(LoadImageTest, UpdateImage2D) {
}
TEST_F(LoadImageTest, UpdateImageSRGB) {
FAIL_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
"Crashing when reading pixels without a redundant call to makeCurrent right before the"
"render pass. b/422798473");
auto& api = getDriverApi();
Cleanup cleanup(api);
api.startCapture();
@@ -476,6 +480,10 @@ TEST_F(LoadImageTest, UpdateImageSRGB) {
}
TEST_F(LoadImageTest, UpdateImageMipLevel) {
FAIL_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
"Crashing when reading pixels without a redundant call to makeCurrent right before the"
"render pass. b/422798473");
auto& api = getDriverApi();
Cleanup cleanup(api);
api.startCapture();
@@ -511,6 +519,8 @@ TEST_F(LoadImageTest, UpdateImageMipLevel) {
PixelBufferDescriptor descriptor = checkerboardPixelBuffer(pixelFormat, pixelType, kTexSize);
api.update3DImage(texture, /* level*/ 1, 0, 0, 0, kTexSize, kTexSize, 1, std::move(descriptor));
api.beginFrame(0, 0, 0);
// Update samplers.
DescriptorSetHandle descriptorSet = shader.createDescriptorSet(api);
api.updateDescriptorSetTexture(descriptorSet, 0, texture, {
@@ -534,12 +544,13 @@ TEST_F(LoadImageTest, UpdateImageMipLevel) {
api.bindRenderPrimitive(mTriangle.getRenderPrimitive());
api.draw2(0, 3, 1);
api.endRenderPass();
EXPECT_IMAGE(defaultRenderTarget,
ScreenshotParams(kTexSize, kTexSize, "UpdateImageMipLevel", 1875922935));
}
EXPECT_IMAGE(defaultRenderTarget,
ScreenshotParams(kTexSize, kTexSize, "UpdateImageMipLevel", 1875922935));
api.commit(swapChain);
api.endFrame(0);
api.stopCapture();
}
@@ -1,388 +0,0 @@
/*
* Copyright (C) 2025 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 "BackendTest.h"
#include "ImageExpectations.h"
#include "Lifetimes.h"
#include "Shader.h"
#include "SharedShaders.h"
#include "SharedShadersConstants.h"
#include "Skip.h"
#include <backend/BufferDescriptor.h>
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
#include <backend/PipelineState.h>
#include <math/vec2.h>
#include <math/vec4.h>
#include <gtest/gtest.h>
#include <array>
#include <cstdint>
#include <cstddef>
#include <new>
#include <tuple>
#include <utility>
#include <stdlib.h>
#include <string.h>
namespace test {
using namespace filament;
using namespace filament::backend;
class MemoryMappedTest : public BackendTest {
protected:
RenderTargetHandle makeRenderTarget(Cleanup& cleanup) {
auto& api = getDriverApi();
auto colorTexture = cleanup.add(
api.createTexture(SamplerType::SAMPLER_2D, 1, TextureFormat::RGBA8, 1,
screenWidth(), screenHeight(), 1,
TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE));
auto renderTarget = cleanup.add(api.createRenderTarget(TargetBufferFlags::COLOR0,
screenWidth(), screenHeight(), 1, 1, { { colorTexture } }, {}, {}));
return renderTarget;
}
std::tuple<VertexBufferInfoHandle, VertexBufferHandle, IndexBufferHandle>
setupGeometryBuffer(Cleanup& cleanup,
uint32_t const count, uint8_t const stride, uint32_t const baseVertex,
BufferObjectHandle buffer) {
auto& api = getDriverApi();
AttributeArray attributes = {};
attributes[0] = { .offset = 0, .stride = stride, .buffer = 0, .type = ElementType::FLOAT2 };
auto vbih = cleanup.add(api.createVertexBufferInfo(1, 1, attributes));
// The vertex buffer must be large enough to hold the "garbage" vertices created by the offset.
auto vbh = cleanup.add(api.createVertexBuffer(count + baseVertex, vbih));
api.setVertexBufferObject(vbh, 0, buffer);
auto* const indices = new(std::nothrow)uint16_t[count];
for (size_t i = 0; i < count; i++) {
indices[i] = i + baseVertex;
}
auto ibh = cleanup.add(
api.createIndexBuffer(ElementType::USHORT, count, BufferUsage::STATIC));
api.updateIndexBuffer(ibh, {
indices, count * sizeof(uint16_t),
[](void* b, size_t, void*) {
delete [] static_cast<uint16_t*>(b);
}, indices }, 0);
return { vbih, vbh, ibh };
}
Shader getSimpleShader(Cleanup& cleanup, math::float4 const& color) {
auto& api = getDriverApi();
Shader const shader = SharedShaders::makeShader(getDriverApi(), cleanup, ShaderRequest{
.mVertexType = VertexShaderType::Simple,
.mFragmentType = FragmentShaderType::SolidColored,
.mUniformType = ShaderUniformType::Simple
});
auto const ubuffer = cleanup.add(api.createBufferObject(sizeof(SimpleMaterialParams),
BufferObjectBinding::UNIFORM, BufferUsage::DYNAMIC_BIT));
shader.bindUniform<SimpleMaterialParams>(api, ubuffer);
shader.uploadUniform(api, ubuffer, SimpleMaterialParams{ .color = color });
return shader;
}
void copyData(const void* data, size_t const size, size_t const offset,
MemoryMappedBufferHandle const& mmb, int& callbacksExecuted) {
auto& api = getDriverApi();
void* p = malloc(size);
memcpy(p, data, size);
api.copyToMemoryMappedBuffer(mmb, offset, {
p, size, [](void* buffer, size_t, void* user) {
free(buffer);
(*static_cast<int*>(user))++;
}, &callbacksExecuted
});
}
void render(uint32_t count,
int64_t const frame,
SwapChainHandle swapChain,
RenderTargetHandle renderTarget,
RenderPrimitiveHandle renderPrimitive, PipelineState const& state) {
auto& api = getDriverApi();
RenderPassParams params = getClearColorRenderPass({0,0,0,1});
params.viewport = getFullViewport();
api.beginFrame(frame, 0, 0);
api.beginRenderPass(renderTarget, params);
api.bindPipeline(state);
api.bindRenderPrimitive(renderPrimitive);
api.draw2(0, count, 1);
api.endRenderPass();
api.commit(swapChain);
api.endFrame(0);
flushAndWait();
}
void runOffsetRenderTest(size_t const mapOffset,
size_t const copyOffset,
const math::float4& color,
const char* screenshotName) {
SKIP_IF(Backend::WEBGPU, "HwMemoryMappedBuffer APIs not yet implemented");
auto& api = getDriverApi();
Cleanup cleanup(api);
auto const swapChain = cleanup.add(createSwapChain());
api.makeCurrent(swapChain, swapChain);
auto const renderTarget = makeRenderTarget(cleanup);
constexpr std::array<math::float2, 3> vertices = {{
{-0.25f, -0.25f},
{ 0.25f, -0.25f},
{-0.25f, 0.25f},
}};
constexpr size_t vertexDataSize = vertices.size() * sizeof(math::float2);
constexpr size_t stride = sizeof(math::float2);
// The total offset is the sum of the map and copy offsets.
const size_t totalOffset = mapOffset + copyOffset;
// Calculate how many vertices we need to skip to account for the total offset.
const uint32_t baseVertex = totalOffset / stride;
// Create a buffer large enough to hold the offset and the vertex data.
auto const bufferObject = cleanup.add(api.createBufferObject(vertexDataSize + totalOffset,
BufferObjectBinding::VERTEX, BufferUsage::SHARED_WRITE_BIT));
int callbackExecuted = 0;
// Map the buffer with a specific offset.
MemoryMappedBufferHandle const memoryMappedBuffer =
api.mapBuffer(bufferObject, mapOffset, vertexDataSize + copyOffset,
MapBufferAccessFlags::WRITE_BIT, utils::CString{ screenshotName });
copyData(vertices.data(), vertexDataSize, copyOffset, memoryMappedBuffer, callbackExecuted);
api.unmapBuffer(memoryMappedBuffer);
flushAndWait();
EXPECT_EQ(callbackExecuted, 1);
Shader const shader = getSimpleShader(cleanup, color);
auto [vbih, vbh, ibh] = setupGeometryBuffer(cleanup, 3, stride, baseVertex, bufferObject);
auto const renderPrimitive = cleanup.add(api.createRenderPrimitive(vbh, ibh, PrimitiveType::TRIANGLES));
PipelineState state = getColorWritePipelineState();
shader.addProgramToPipelineState(state);
state.rasterState.culling = CullingMode::NONE;
state.primitiveType = PrimitiveType::TRIANGLES;
state.vertexBufferInfo = vbih;
render(3, 0, swapChain, renderTarget, renderPrimitive, state);
EXPECT_IMAGE(renderTarget, ScreenshotParams(screenWidth(), screenHeight(), screenshotName, 0));
}
};
TEST_F(MemoryMappedTest, MapCopyUnmap) {
SKIP_IF(Backend::WEBGPU, "HwMemoryMappedBuffer APIs not yet implemented");
auto& api = getDriverApi();
Cleanup cleanup(api);
// Create a buffer object.
BufferObjectHandle const bufferObject = cleanup.add(api.createBufferObject(1024,
BufferObjectBinding::VERTEX, BufferUsage::DYNAMIC_BIT | BufferUsage::SHARED_WRITE_BIT));
// Map the buffer.
MemoryMappedBufferHandle const memoryMappedBuffer = api.mapBuffer(bufferObject, 0, 1024,
MapBufferAccessFlags::WRITE_BIT, "MemoryMappedBuffer");
if (memoryMappedBuffer) {
// Create some data to copy.
constexpr size_t dataSize = 256;
auto* const data = new uint8_t[dataSize];
for (size_t i = 0; i < dataSize; ++i) {
data[i] = uint8_t(i);
}
// Copy the data into the mapped buffer.
BufferDescriptor bufferDescriptor(data, dataSize, [](void* buffer, size_t, void*) {
delete[] static_cast<uint8_t*>(buffer);
});
api.copyToMemoryMappedBuffer(memoryMappedBuffer, 0, std::move(bufferDescriptor));
// Unmap the buffer.
api.unmapBuffer(memoryMappedBuffer);
}
}
TEST_F(MemoryMappedTest, WriteAndRender) {
runOffsetRenderTest(0, 0, {1, 0, 0, 1}, "WriteAndRender");
}
TEST_F(MemoryMappedTest, MapWithOffset) {
runOffsetRenderTest(16, 0, {0, 1, 0, 1}, "MapWithOffset");
}
TEST_F(MemoryMappedTest, CopyWithOffset) {
runOffsetRenderTest(0, 16, {0, 0, 1, 1}, "CopyWithOffset");
}
TEST_F(MemoryMappedTest, MapAndCopyWithOffsets) {
runOffsetRenderTest(16, 32, {1, 0, 1, 1}, "MapAndCopyWithOffsets");
}
TEST_F(MemoryMappedTest, MultipleCopies) {
SKIP_IF(Backend::WEBGPU, "HwMemoryMappedBuffer APIs not yet implemented");
auto& api = getDriverApi();
Cleanup cleanup(api);
auto const swapChain = cleanup.add(createSwapChain());
api.makeCurrent(swapChain, swapChain);
auto const renderTarget = makeRenderTarget(cleanup);
constexpr std::array<math::float2, 3> triangle1 = {{{-0.5f, 0.5f}, {-0.8f, 0.2f}, {-0.2f, 0.2f}}};
constexpr std::array<math::float2, 3> triangle2 = {{{0.5f, 0.5f}, {0.2f, 0.2f}, {0.8f, 0.2f}}};
constexpr std::array<math::float2, 3> triangle3 = {{{-0.5f, -0.5f}, {-0.8f, -0.8f}, {-0.2f, -0.8f}}};
constexpr size_t singleTriangleSize = triangle1.size() * sizeof(math::float2);
constexpr size_t totalDataSize = singleTriangleSize * 3;
auto const bufferObject = cleanup.add(api.createBufferObject(totalDataSize,
BufferObjectBinding::VERTEX, BufferUsage::SHARED_WRITE_BIT));
int callbacksExecuted = 0;
MemoryMappedBufferHandle const memoryMappedBuffer = api.mapBuffer(bufferObject, 0, totalDataSize,
MapBufferAccessFlags::WRITE_BIT, "MultipleCopies");
copyData(triangle1.data(), singleTriangleSize, 0,
memoryMappedBuffer, callbacksExecuted);
copyData(triangle2.data(), singleTriangleSize, singleTriangleSize,
memoryMappedBuffer, callbacksExecuted);
copyData(triangle3.data(), singleTriangleSize, singleTriangleSize * 2,
memoryMappedBuffer, callbacksExecuted);
api.unmapBuffer(memoryMappedBuffer);
flushAndWait();
EXPECT_EQ(callbacksExecuted, 3);
Shader const shader = getSimpleShader(cleanup, { 1, 1, 0, 1 });
auto [vbih, vbh, ibh] = setupGeometryBuffer(cleanup, 9, sizeof(math::float2), 0, bufferObject);
auto const renderPrimitive = cleanup.add(api.createRenderPrimitive(vbh, ibh, PrimitiveType::TRIANGLES));
PipelineState state = getColorWritePipelineState();
shader.addProgramToPipelineState(state);
state.rasterState.culling = CullingMode::NONE;
state.primitiveType = PrimitiveType::TRIANGLES;
state.vertexBufferInfo = vbih;
render(9, 0, swapChain, renderTarget, renderPrimitive, state);
EXPECT_IMAGE(renderTarget, ScreenshotParams(screenWidth(), screenHeight(), "MultipleCopies", 0));
}
TEST_F(MemoryMappedTest, UpdatePartial) {
SKIP_IF(Backend::WEBGPU, "HwMemoryMappedBuffer APIs not yet implemented");
auto& api = getDriverApi();
Cleanup cleanup(api);
auto swapChain = cleanup.add(createSwapChain());
api.makeCurrent(swapChain, swapChain);
auto renderTarget = makeRenderTarget(cleanup);
constexpr std::array<math::float2, 3> triangle1 = {{{-0.5f, 0.5f}, {-0.8f, 0.2f}, {-0.2f, 0.2f}}};
constexpr std::array<math::float2, 3> triangle2 = {{{0.5f, 0.5f}, {0.2f, 0.2f}, {0.8f, 0.2f}}};
constexpr std::array<math::float2, 3> triangle3 = {{{-0.5f, -0.5f}, {-0.8f, -0.8f}, {-0.2f, -0.8f}}};
constexpr size_t singleTriangleSize = triangle1.size() * sizeof(math::float2);
constexpr size_t totalDataSize = singleTriangleSize * 3;
auto bufferObject = cleanup.add(api.createBufferObject(totalDataSize,
BufferObjectBinding::VERTEX, BufferUsage::SHARED_WRITE_BIT));
int callbacksExecuted = 0;
// Initial data upload
{
MemoryMappedBufferHandle const memoryMappedBuffer = api.mapBuffer(bufferObject, 0, totalDataSize,
MapBufferAccessFlags::WRITE_BIT, "UpdatePartial_initial");
copyData(triangle1.data(), singleTriangleSize, 0,
memoryMappedBuffer, callbacksExecuted);
copyData(triangle2.data(), singleTriangleSize, singleTriangleSize,
memoryMappedBuffer, callbacksExecuted);
copyData(triangle3.data(), singleTriangleSize, singleTriangleSize * 2,
memoryMappedBuffer, callbacksExecuted);
api.unmapBuffer(memoryMappedBuffer);
flushAndWait();
EXPECT_EQ(callbacksExecuted, 3);
}
Shader const shader = getSimpleShader(cleanup, { 1, 1, 0, 1 });
auto [vbih, vbh, ibh] = setupGeometryBuffer(cleanup, 9, sizeof(math::float2), 0, bufferObject);
auto renderPrimitive = cleanup.add(api.createRenderPrimitive(vbh, ibh, PrimitiveType::TRIANGLES));
PipelineState state = getColorWritePipelineState();
shader.addProgramToPipelineState(state);
state.rasterState.culling = CullingMode::NONE;
state.primitiveType = PrimitiveType::TRIANGLES;
state.vertexBufferInfo = vbih;
render(9, 0, swapChain, renderTarget, renderPrimitive, state);
EXPECT_IMAGE(renderTarget, ScreenshotParams(screenWidth(), screenHeight(), "UpdatePartial_before", 0));
// Now, update the middle triangle
constexpr std::array<math::float2, 3> triangle2_updated = {{{0.5f, -0.5f}, {0.2f, -0.8f}, {0.8f, -0.8f}}};
callbacksExecuted = 0;
{
MemoryMappedBufferHandle const memoryMappedBuffer =
api.mapBuffer(bufferObject, singleTriangleSize, singleTriangleSize,
MapBufferAccessFlags::WRITE_BIT, "UpdatePartial_update");
copyData(triangle2_updated.data(), singleTriangleSize, 0, memoryMappedBuffer, callbacksExecuted);
api.unmapBuffer(memoryMappedBuffer);
flushAndWait();
EXPECT_EQ(callbacksExecuted, 1);
}
// need this because render() above calls commit()
api.makeCurrent(swapChain, swapChain);
// Second render, after update
render(9, 1, swapChain, renderTarget, renderPrimitive, state);
EXPECT_IMAGE(renderTarget, ScreenshotParams(screenWidth(), screenHeight(), "UpdatePartial_after", 0));
}
} // namespace test
+20 -39
View File
@@ -23,7 +23,6 @@
#include "Skip.h"
#include "TrianglePrimitive.h"
#include <utils/debug.h>
#include <utils/Hash.h>
#include <fstream>
@@ -82,6 +81,8 @@ public:
TEST_F(ReadPixelsTest, ReadPixels) {
SKIP_IF(Backend::WEBGPU, "test cases fail in WebGPU, see b/424157731");
NONFATAL_FAIL_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
"Two cases fail, see b/417255941 and b/417255943");
// These test scenarios use a known hash of the result pixel buffer to decide pass / fail,
// asserting an exact pixel-for-pixel match. So far, rendering on macOS and iPhone have had
// deterministic results. Take this test with a grain of salt, however, as other platform / GPU
@@ -123,15 +124,11 @@ TEST_F(ReadPixelsTest, ReadPixels) {
size_t bufferDimension = getRenderTargetSize();
size_t getBufferSizeBytes() const {
return bufferDimension * bufferDimension * getBytesPerPixels();
}
size_t getBytesPerPixels() const {
int bpp;
size_t components;
int bpp;
getPixelInfo(format, type, components, bpp);
return bpp;
};
return bufferDimension * bufferDimension * bpp;
}
// The offset and stride set on the pixel buffer.
size_t left = 0, top = 0, alignment = 1;
@@ -148,21 +145,7 @@ TEST_F(ReadPixelsTest, ReadPixels) {
const size_t width = readRect.width, height = readRect.height;
LinearImage image(width, height, 4);
if (format == PixelDataFormat::RGBA && type == PixelDataType::UBYTE) {
if (top == 0 && left == 0 && renderTargetBaseSize == readRect.width) {
image = toLinearWithAlpha<uint8_t>(width, height, width * 4, (uint8_t*)pixelData);
} else {
float* pixelRef = image.getPixelRef();
size_t const bpp = getBytesPerPixels();
size_t const bpr = bpp * bufferDimension;
for (size_t l = left; l < left + width; ++l) {
for (size_t t = top; t < top + height; ++t) {
for (size_t c = 0; c < 4; ++c) {
pixelRef[c + (l - left) * 4 + ((t - top) * 4 * width)] =
((uint8_t*)pixelData)[c + l * bpp + t * bpr] / 255.0f;
}
}
}
}
image = toLinearWithAlpha<uint8_t>(width, height, width * 4, (uint8_t*)pixelData);
}
if (format == PixelDataFormat::RGBA && type == PixelDataType::FLOAT) {
memcpy(image.getPixelRef(), pixelData, width * height * sizeof(math::float4));
@@ -186,17 +169,14 @@ TEST_F(ReadPixelsTest, ReadPixels) {
// The normative read pixels test case. Render a white triangle over a blue background and read
// the full viewport into a pixel buffer.
TestCase const t0(renderTargetBaseSize);
TestCase::Rect const subregionRect = {
.x = 90,
.y = 403,
.width = 64,
.height = 64,
};
// Check that a subregion of the render target can be read into a pixel buffer.
TestCase t2(renderTargetBaseSize);
t2.testName = "readPixels_subregion";
t2.readRect = subregionRect;
t2.readRect.x = 90;
t2.readRect.y = 403;
t2.readRect.width = 64;
t2.readRect.height = 64;
t2.bufferDimension = 64;
t2.hash = 0xcba7675a;
@@ -219,17 +199,16 @@ TEST_F(ReadPixelsTest, ReadPixels) {
// Check that readPixels can read a region of the render target into a subregion of a large
// buffer.
const size_t actualBufferSize = renderTargetBaseSize * 2;
constexpr size_t readOffset = 64;;
assert_invariant(renderTargetBaseSize + readOffset < actualBufferSize);
TestCase t5(renderTargetBaseSize);
t5.testName = "readPixels_subbuffer";
t5.readRect = subregionRect;
t5.bufferDimension = actualBufferSize;
t5.left = readOffset;
t5.top = readOffset;
t5.hash = 0x64585D10;
t5.readRect.x = 90;
t5.readRect.y = 403;
t5.readRect.width = 64;
t5.readRect.height = 64;
t5.bufferDimension = 512;
t5.left = 64;
t5.top = 64;
t5.hash = 0xbaefdb54;
// Check that readPixels works with integer formats.
TestCase t6(renderTargetBaseSize);
@@ -374,6 +353,8 @@ TEST_F(ReadPixelsTest, ReadPixels) {
api.commit(swapChain);
api.endFrame(0);
}
// This ensures all driver commands have finished before exiting the test.
flushAndWait();
}
-65
View File
@@ -1,65 +0,0 @@
/*
* Copyright (C) 2025 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 "MaterialCache.h"
#include "MaterialParser.h"
#include <backend/DriverEnums.h>
#include <details/Engine.h>
#include <details/Material.h>
#include <utils/Logger.h>
namespace filament {
size_t MaterialCache::Key::Hash::operator()(
filament::MaterialCache::Key const& key) const noexcept {
uint32_t crc;
if (key.parser->getMaterialCrc32(&crc)) {
return size_t(crc);
}
return size_t(key.parser->computeCrc32());
}
bool MaterialCache::Key::operator==(Key const& rhs) const noexcept {
return parser == rhs.parser;
}
MaterialCache::~MaterialCache() {
if (!mDefinitions.empty()) {
LOG(WARNING) << "MaterialCache was destroyed but wasn't empty";
}
}
MaterialDefinition* UTILS_NULLABLE MaterialCache::acquire(FEngine& engine,
const void* UTILS_NONNULL data, size_t size) noexcept {
std::unique_ptr<MaterialParser> parser = MaterialDefinition::createParser(engine.getBackend(),
engine.getShaderLanguage(), data, size);
assert_invariant(parser);
return mDefinitions.acquire(Key{parser.get()}, [&engine, parser = std::move(parser)]() mutable {
return MaterialDefinition::create(engine, std::move(parser));
});
}
void MaterialCache::release(FEngine& engine, MaterialParser const& parser) noexcept {
mDefinitions.release(Key{&parser}, [&engine](MaterialDefinition& definition) {
definition.terminate(engine);
});
}
} // namespace filament
-65
View File
@@ -1,65 +0,0 @@
/*
* Copyright (C) 2025 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_MATERIALCACHE_H
#define TNT_FILAMENT_MATERIALCACHE_H
#include "MaterialDefinition.h"
#include <private/filament/Variant.h>
#include <backend/CallbackHandler.h>
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
#include <backend/Program.h>
#include <utils/Invocable.h>
#include <utils/RefCountedMap.h>
namespace filament {
class Material;
class MaterialCache {
// A newtype around a material parser used as a key for the material cache. The material file's
// CRC32 is used as the hash function.
struct Key {
struct Hash {
size_t operator()(Key const& x) const noexcept;
};
bool operator==(Key const& rhs) const noexcept;
MaterialParser const* UTILS_NONNULL parser;
};
public:
~MaterialCache();
/** Acquire or create a new entry in the cache for the given material data. */
MaterialDefinition* UTILS_NULLABLE acquire(FEngine& engine, const void* UTILS_NONNULL data,
size_t size) noexcept;
/** Release an entry in the cache, potentially freeing its GPU resources. */
void release(FEngine& engine, MaterialParser const& parser) noexcept;
private:
// We use unique_ptr here because we need these pointers to be stable.
// TODO: investigate using a custom allocator here?
utils::RefCountedMap<Key, std::unique_ptr<MaterialDefinition>, Key::Hash> mDefinitions;
};
} // namespace filament
#endif // TNT_FILAMENT_MATERIALCACHE_H
-391
View File
@@ -1,391 +0,0 @@
#include "MaterialDefinition.h"
#include "Froxelizer.h"
#include "MaterialParser.h"
#include <backend/DriverEnums.h>
#include <ds/ColorPassDescriptorSet.h>
#include <details/Engine.h>
#include <utils/Logger.h>
#include <utils/Panic.h>
namespace filament {
using namespace backend;
using namespace utils;
std::unique_ptr<MaterialParser> MaterialDefinition::createParser(Backend const backend,
FixedCapacityVector<ShaderLanguage> languages, const void* data, size_t size) {
// unique_ptr so we don't leak MaterialParser on failures below
auto materialParser = std::make_unique<MaterialParser>(languages, data, size);
MaterialParser::ParseResult const materialResult = materialParser->parse();
if (UTILS_UNLIKELY(materialResult == MaterialParser::ParseResult::ERROR_MISSING_BACKEND)) {
CString languageNames;
for (auto it = languages.begin(); it != languages.end(); ++it) {
languageNames.append(CString{shaderLanguageToString(*it)});
if (std::next(it) != languages.end()) {
languageNames.append(", ");
}
}
FILAMENT_CHECK_POSTCONDITION(
materialResult != MaterialParser::ParseResult::ERROR_MISSING_BACKEND)
<< "the material was not built for any of the " << to_string(backend)
<< " backend's supported shader languages (" << languageNames.c_str() << ")\n";
}
if (backend == Backend::NOOP) {
return materialParser;
}
FILAMENT_CHECK_POSTCONDITION(materialResult == MaterialParser::ParseResult::SUCCESS)
<< "could not parse the material package";
uint32_t version = 0;
materialParser->getMaterialVersion(&version);
FILAMENT_CHECK_POSTCONDITION(version == MATERIAL_VERSION)
<< "Material version mismatch. Expected " << MATERIAL_VERSION << " but received "
<< version << ".";
assert_invariant(backend != Backend::DEFAULT && "Default backend has not been resolved.");
return materialParser;
}
std::unique_ptr<MaterialDefinition> MaterialDefinition::create(FEngine& engine,
std::unique_ptr<MaterialParser> parser) {
// Try checking CRC32 value for the package and skip if it's unavailable.
if (downcast(engine).features.material.check_crc32_after_loading) {
uint32_t parsedCrc32 = 0;
parser->getMaterialCrc32(&parsedCrc32);
uint32_t expectedCrc32 = parser->computeCrc32();
if (parsedCrc32 != expectedCrc32) {
CString name;
parser->getName(&name);
LOG(ERROR) << "The material '" << name.c_str_safe()
<< "' is corrupted: crc32_expected=" << expectedCrc32
<< ", crc32_parsed=" << parsedCrc32;
return nullptr;
}
}
uint32_t v = 0;
parser->getShaderModels(&v);
bitset32 shaderModels;
shaderModels.setValue(v);
ShaderModel const shaderModel = downcast(engine).getShaderModel();
if (!shaderModels.test(static_cast<uint32_t>(shaderModel))) {
CString name;
parser->getName(&name);
char shaderModelsString[16];
snprintf(shaderModelsString, sizeof(shaderModelsString), "%#x", shaderModels.getValue());
LOG(ERROR) << "The material '" << name.c_str_safe() << "' was not built for "
<< to_string(shaderModel) << ".";
LOG(ERROR) << "Compiled material contains shader models " << shaderModelsString << ".";
return nullptr;
}
// Print a warning if the material's stereo type doesn't align with the engine's
// setting.
MaterialDomain materialDomain;
UserVariantFilterMask variantFilterMask;
parser->getMaterialDomain(&materialDomain);
parser->getMaterialVariantFilterMask(&variantFilterMask);
bool const hasStereoVariants =
!(variantFilterMask & UserVariantFilterMask(UserVariantFilterBit::STE));
if (materialDomain == MaterialDomain::SURFACE && hasStereoVariants) {
StereoscopicType const engineStereoscopicType = engine.getConfig().stereoscopicType;
// Default materials are always compiled with either 'instanced' or 'multiview'.
// So, we only verify compatibility if the engine is set up for stereo.
if (engineStereoscopicType != StereoscopicType::NONE) {
StereoscopicType materialStereoscopicType = StereoscopicType::NONE;
parser->getStereoscopicType(&materialStereoscopicType);
if (materialStereoscopicType != engineStereoscopicType) {
CString name;
parser->getName(&name);
LOG(WARNING) << "The stereoscopic type in the compiled material '"
<< name.c_str_safe() << "' is " << (int) materialStereoscopicType
<< ", which is not compatible with the engine's setting "
<< (int) engineStereoscopicType << ".";
}
}
}
return std::make_unique<MaterialDefinition>(engine, std::move(parser));
}
void MaterialDefinition::terminate(FEngine& engine) {
DriverApi& driver = engine.getDriverApi();
perViewDescriptorSetLayout.terminate(engine.getDescriptorSetLayoutFactory(), driver);
perViewDescriptorSetLayoutVsm.terminate(engine.getDescriptorSetLayoutFactory(), driver);
descriptorSetLayout.terminate(engine.getDescriptorSetLayoutFactory(), driver);
}
MaterialDefinition::MaterialDefinition(FEngine& engine,
std::unique_ptr<MaterialParser> materialParser)
: mMaterialParser(std::move(materialParser)) {
processMain();
processBlendingMode();
processSpecializationConstants();
processDescriptorSets(engine);
}
void MaterialDefinition::processMain() {
UTILS_UNUSED_IN_RELEASE bool const nameOk = mMaterialParser->getName(&name);
assert_invariant(nameOk);
featureLevel = [this]() -> FeatureLevel {
// code written this way so the IDE will complain when/if we add a FeatureLevel
uint8_t level = 1;
mMaterialParser->getFeatureLevel(&level);
assert_invariant(level <= 3);
FeatureLevel featureLevel = FeatureLevel::FEATURE_LEVEL_1;
switch (FeatureLevel(level)) {
case FeatureLevel::FEATURE_LEVEL_0:
case FeatureLevel::FEATURE_LEVEL_1:
case FeatureLevel::FEATURE_LEVEL_2:
case FeatureLevel::FEATURE_LEVEL_3:
featureLevel = FeatureLevel(level);
break;
}
return featureLevel;
}();
UTILS_UNUSED_IN_RELEASE bool success;
success = mMaterialParser->getCacheId(&cacheId);
assert_invariant(success);
success = mMaterialParser->getSIB(&samplerInterfaceBlock);
assert_invariant(success);
success = mMaterialParser->getUIB(&uniformInterfaceBlock);
assert_invariant(success);
if (UTILS_UNLIKELY(mMaterialParser->getShaderLanguage() == ShaderLanguage::ESSL1)) {
success = mMaterialParser->getAttributeInfo(&attributeInfo);
assert_invariant(success);
success = mMaterialParser->getBindingUniformInfo(&bindingUniformInfo);
assert_invariant(success);
}
// Older materials will not have a subpass chunk; this should not be an error.
if (!mMaterialParser->getSubpasses(&subpassInfo)) {
subpassInfo.isValid = false;
}
mMaterialParser->getShading(&shading);
mMaterialParser->getMaterialProperties(&materialProperties);
mMaterialParser->getInterpolation(&interpolation);
mMaterialParser->getVertexDomain(&vertexDomain);
mMaterialParser->getMaterialDomain(&materialDomain);
mMaterialParser->getMaterialVariantFilterMask(&variantFilterMask);
mMaterialParser->getRequiredAttributes(&requiredAttributes);
mMaterialParser->getRefractionMode(&refractionMode);
mMaterialParser->getRefractionType(&refractionType);
mMaterialParser->getReflectionMode(&reflectionMode);
mMaterialParser->getTransparencyMode(&transparencyMode);
mMaterialParser->getDoubleSided(&doubleSided);
mMaterialParser->getCullingMode(&cullingMode);
if (shading == Shading::UNLIT) {
mMaterialParser->hasShadowMultiplier(&hasShadowMultiplier);
}
isVariantLit = shading != Shading::UNLIT || hasShadowMultiplier;
// color write
bool colorWrite = false;
mMaterialParser->getColorWrite(&colorWrite);
rasterState.colorWrite = colorWrite;
// depth test
bool depthTest = false;
mMaterialParser->getDepthTest(&depthTest);
rasterState.depthFunc = depthTest ? RasterState::DepthFunc::GE : RasterState::DepthFunc::A;
// if doubleSided() was called we override culling()
bool doubleSideSet = false;
mMaterialParser->getDoubleSidedSet(&doubleSideSet);
if (doubleSideSet) {
doubleSidedCapability = true;
rasterState.culling = doubleSided ? CullingMode::NONE : cullingMode;
} else {
rasterState.culling = cullingMode;
}
// specular anti-aliasing
mMaterialParser->hasSpecularAntiAliasing(&specularAntiAliasing);
if (specularAntiAliasing) {
mMaterialParser->getSpecularAntiAliasingVariance(&specularAntiAliasingVariance);
mMaterialParser->getSpecularAntiAliasingThreshold(&specularAntiAliasingThreshold);
}
mMaterialParser->hasCustomDepthShader(&hasCustomDepthShader);
bool const isLit = isVariantLit || hasShadowMultiplier;
bool const isSSR = reflectionMode == ReflectionMode::SCREEN_SPACE ||
refractionMode == RefractionMode::SCREEN_SPACE;
bool const hasFog = !(variantFilterMask & UserVariantFilterMask(UserVariantFilterBit::FOG));
perViewLayoutIndex = ColorPassDescriptorSet::getIndex(isLit, isSSR, hasFog);
}
void MaterialDefinition::processBlendingMode() {
mMaterialParser->getBlendingMode(&blendingMode);
if (blendingMode == BlendingMode::MASKED) {
mMaterialParser->getMaskThreshold(&maskThreshold);
}
if (blendingMode == BlendingMode::CUSTOM) {
mMaterialParser->getCustomBlendFunction(&customBlendFunctions);
}
// blending mode
switch (blendingMode) {
// Do not change the MASKED behavior without checking for regressions with
// AlphaBlendModeTest and TextureLinearInterpolationTest, with and without
// View::BlendMode::TRANSLUCENT.
case BlendingMode::MASKED:
case BlendingMode::OPAQUE:
rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
rasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
rasterState.blendFunctionDstRGB = BlendFunction::ZERO;
rasterState.blendFunctionDstAlpha = BlendFunction::ZERO;
rasterState.depthWrite = true;
break;
case BlendingMode::TRANSPARENT:
case BlendingMode::FADE:
rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
rasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
rasterState.blendFunctionDstRGB = BlendFunction::ONE_MINUS_SRC_ALPHA;
rasterState.blendFunctionDstAlpha = BlendFunction::ONE_MINUS_SRC_ALPHA;
rasterState.depthWrite = false;
break;
case BlendingMode::ADD:
rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
rasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
rasterState.blendFunctionDstRGB = BlendFunction::ONE;
rasterState.blendFunctionDstAlpha = BlendFunction::ONE;
rasterState.depthWrite = false;
break;
case BlendingMode::MULTIPLY:
rasterState.blendFunctionSrcRGB = BlendFunction::ZERO;
rasterState.blendFunctionSrcAlpha = BlendFunction::ZERO;
rasterState.blendFunctionDstRGB = BlendFunction::SRC_COLOR;
rasterState.blendFunctionDstAlpha = BlendFunction::SRC_COLOR;
rasterState.depthWrite = false;
break;
case BlendingMode::SCREEN:
rasterState.blendFunctionSrcRGB = BlendFunction::ONE;
rasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
rasterState.blendFunctionDstRGB = BlendFunction::ONE_MINUS_SRC_COLOR;
rasterState.blendFunctionDstAlpha = BlendFunction::ONE_MINUS_SRC_COLOR;
rasterState.depthWrite = false;
break;
case BlendingMode::CUSTOM:
rasterState.blendFunctionSrcRGB = customBlendFunctions[0];
rasterState.blendFunctionSrcAlpha = customBlendFunctions[1];
rasterState.blendFunctionDstRGB = customBlendFunctions[2];
rasterState.blendFunctionDstAlpha = customBlendFunctions[3];
rasterState.depthWrite = false;
}
// depth write
bool depthWriteSet = false;
mMaterialParser->getDepthWriteSet(&depthWriteSet);
if (depthWriteSet) {
bool depthWrite = false;
mMaterialParser->getDepthWrite(&depthWrite);
rasterState.depthWrite = depthWrite;
}
// alpha to coverage
bool alphaToCoverageSet = false;
mMaterialParser->getAlphaToCoverageSet(&alphaToCoverageSet);
if (alphaToCoverageSet) {
bool alphaToCoverage = false;
mMaterialParser->getAlphaToCoverage(&alphaToCoverage);
rasterState.alphaToCoverage = alphaToCoverage;
} else {
rasterState.alphaToCoverage = blendingMode == BlendingMode::MASKED;
}
}
void MaterialDefinition::processSpecializationConstants() {
// Older materials won't have a constants chunk, but that's okay.
mMaterialParser->getConstants(&materialConstants);
for (size_t i = 0, c = materialConstants.size(); i < c; i++) {
auto& item = materialConstants[i];
// the key can be a string_view because mMaterialConstant owns the CString
std::string_view const key{ item.name.data(), item.name.size() };
specializationConstantsNameToIndex[key] = i;
}
}
void MaterialDefinition::processDescriptorSets(FEngine& engine) {
UTILS_UNUSED_IN_RELEASE bool success;
success = mMaterialParser->getDescriptorBindings(&programDescriptorBindings);
assert_invariant(success);
backend::DescriptorSetLayout descriptorSetLayout;
success = mMaterialParser->getDescriptorSetLayout(&descriptorSetLayout);
assert_invariant(success);
// get the PER_VIEW descriptor binding info
bool const isLit = isVariantLit || hasShadowMultiplier;
bool const isSSR = reflectionMode == ReflectionMode::SCREEN_SPACE ||
refractionMode == RefractionMode::SCREEN_SPACE;
bool const hasFog = !(variantFilterMask & UserVariantFilterMask(UserVariantFilterBit::FOG));
auto perViewDescriptorSetLayout = descriptor_sets::getPerViewDescriptorSetLayout(
materialDomain, isLit, isSSR, hasFog, false);
auto perViewDescriptorSetLayoutVsm = descriptor_sets::getPerViewDescriptorSetLayout(
materialDomain, isLit, isSSR, hasFog, true);
// set the labels
descriptorSetLayout.label = CString{ name }.append("_perMat");
perViewDescriptorSetLayout.label = CString{ name }.append("_perView");
perViewDescriptorSetLayoutVsm.label = CString{ name }.append("_perViewVsm");
// get the PER_RENDERABLE and PER_VIEW descriptor binding info
for (auto&& [bindingPoint, descriptorSetLayout] : {
std::pair{ DescriptorSetBindingPoints::PER_RENDERABLE,
descriptor_sets::getPerRenderableLayout() },
std::pair{ DescriptorSetBindingPoints::PER_VIEW,
perViewDescriptorSetLayout }}) {
Program::DescriptorBindingsInfo& descriptors = programDescriptorBindings[+bindingPoint];
descriptors.reserve(descriptorSetLayout.bindings.size());
for (auto const& entry: descriptorSetLayout.bindings) {
auto const& name = descriptor_sets::getDescriptorName(bindingPoint, entry.binding);
descriptors.push_back({ name, entry.type, entry.binding });
}
}
this->descriptorSetLayout = {
engine.getDescriptorSetLayoutFactory(),
engine.getDriverApi(), std::move(descriptorSetLayout) };
this->perViewDescriptorSetLayout = {
engine.getDescriptorSetLayoutFactory(),
engine.getDriverApi(), std::move(perViewDescriptorSetLayout) };
this->perViewDescriptorSetLayoutVsm = {
engine.getDescriptorSetLayoutFactory(),
engine.getDriverApi(), std::move(perViewDescriptorSetLayoutVsm) };
}
} // namespace filament
-131
View File
@@ -1,131 +0,0 @@
/*
* Copyright (C) 2025 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_MATERIALDEFINITION_H
#define TNT_FILAMENT_MATERIALDEFINITION_H
#include <private/filament/Variant.h>
#include <private/filament/BufferInterfaceBlock.h>
#include <private/filament/SamplerInterfaceBlock.h>
#include <private/filament/SubpassInfo.h>
#include <private/filament/ConstantInfo.h>
#include <ds/DescriptorSetLayout.h>
#include <backend/Program.h>
namespace filament {
class FEngine;
class MaterialParser;
/** A MaterialDefinition is a parsed, unmarshalled material file, containing no state.
*
* Given that this is a pure read-only class, nearly all members are public without getters.
*/
struct MaterialDefinition {
using BlendingMode = filament::BlendingMode;
using Shading = filament::Shading;
using Interpolation = filament::Interpolation;
using VertexDomain = filament::VertexDomain;
using TransparencyMode = filament::TransparencyMode;
using CullingMode = backend::CullingMode;
using AttributeInfoContainer = utils::FixedCapacityVector<std::pair<utils::CString, uint8_t>>;
using BindingUniformInfoContainer = utils::FixedCapacityVector<
std::tuple<uint8_t, utils::CString, backend::Program::UniformInfo>>;
// public only due to std::make_unique().
MaterialDefinition(FEngine& engine, std::unique_ptr<MaterialParser> parser);
// Free GPU resources owned by this MaterialDefinition.
void terminate(FEngine& engine);
MaterialParser const& getMaterialParser() const noexcept { return *mMaterialParser; }
// try to order by frequency of use
DescriptorSetLayout perViewDescriptorSetLayout;
DescriptorSetLayout perViewDescriptorSetLayoutVsm;
DescriptorSetLayout descriptorSetLayout;
backend::Program::DescriptorSetInfo programDescriptorBindings;
backend::RasterState rasterState;
TransparencyMode transparencyMode = TransparencyMode::DEFAULT;
bool isVariantLit = false;
backend::FeatureLevel featureLevel = backend::FeatureLevel::FEATURE_LEVEL_1;
Shading shading = Shading::UNLIT;
BlendingMode blendingMode = BlendingMode::OPAQUE;
std::array<backend::BlendFunction, 4> customBlendFunctions = {};
Interpolation interpolation = Interpolation::SMOOTH;
VertexDomain vertexDomain = VertexDomain::OBJECT;
MaterialDomain materialDomain = MaterialDomain::SURFACE;
CullingMode cullingMode = CullingMode::NONE;
AttributeBitset requiredAttributes;
UserVariantFilterMask variantFilterMask = 0;
RefractionMode refractionMode = RefractionMode::NONE;
RefractionType refractionType = RefractionType::SOLID;
ReflectionMode reflectionMode = ReflectionMode::DEFAULT;
uint64_t materialProperties = 0;
uint8_t perViewLayoutIndex = 0;
float maskThreshold = 0.4f;
float specularAntiAliasingVariance = 0.0f;
float specularAntiAliasingThreshold = 0.0f;
bool doubleSided = false;
bool doubleSidedCapability = false;
bool hasShadowMultiplier = false;
bool hasCustomDepthShader = false;
bool specularAntiAliasing = false;
SamplerInterfaceBlock samplerInterfaceBlock;
BufferInterfaceBlock uniformInterfaceBlock;
SubpassInfo subpassInfo;
BindingUniformInfoContainer bindingUniformInfo;
AttributeInfoContainer attributeInfo;
// Constants defined by this Material
utils::FixedCapacityVector<MaterialConstant> materialConstants;
// A map from the Constant name to the materialConstants index
std::unordered_map<std::string_view, uint32_t> specializationConstantsNameToIndex;
utils::CString name;
uint64_t cacheId = 0;
private:
friend class MaterialCache;
friend class FMaterial;
static std::unique_ptr<MaterialParser> createParser(backend::Backend const backend,
utils::FixedCapacityVector<backend::ShaderLanguage> languages,
const void* UTILS_NONNULL data, size_t size);
static std::unique_ptr<MaterialDefinition> create(FEngine& engine,
std::unique_ptr<MaterialParser> parser);
void processMain();
void processBlendingMode();
void processSpecializationConstants();
void processDescriptorSets(FEngine& engine);
std::unique_ptr<MaterialParser> mMaterialParser;
};
} // namespace filament
#endif // TNT_FILAMENT_MATERIALDEFINITION_H
+1 -23
View File
@@ -38,7 +38,6 @@
#include <utils/compiler.h>
#include <utils/CString.h>
#include <utils/FixedCapacityVector.h>
#include <utils/Hash.h>
#include <array>
#include <optional>
@@ -107,14 +106,6 @@ MaterialParser::MaterialParserDetails::ManagedBuffer::~ManagedBuffer() noexcept
// ------------------------------------------------------------------------------------------------
bool MaterialParser::operator==(MaterialParser const& rhs) const noexcept {
if (mImpl.mManagedBuffer.size() != rhs.mImpl.mManagedBuffer.size()) {
return false;
}
return !std::memcmp(mImpl.mManagedBuffer.data(), rhs.mImpl.mManagedBuffer.data(),
mImpl.mManagedBuffer.size());
}
template<typename T>
bool MaterialParser::get(typename T::Container* container) const noexcept {
auto [start, end] = mImpl.mChunkContainer.getChunkRange(T::tag);
@@ -171,19 +162,6 @@ MaterialParser::ParseResult MaterialParser::parse() noexcept {
return ParseResult::SUCCESS;
}
uint32_t MaterialParser::computeCrc32() const noexcept {
const size_t size = mImpl.mManagedBuffer.size();
const void* const UTILS_NONNULL payload = mImpl.mManagedBuffer.data();
constexpr size_t crc32ChunkSize = sizeof(uint64_t) + sizeof(uint32_t) + sizeof(uint32_t);
const size_t originalSize = size - crc32ChunkSize;
assert_invariant(size > crc32ChunkSize);
std::vector<uint32_t> crc32Table;
utils::hash::crc32GenerateTable(crc32Table);
return utils::hash::crc32Update(0, payload, originalSize, crc32Table);
}
ShaderLanguage MaterialParser::getShaderLanguage() const noexcept {
return mImpl.mChosenLanguage;
}
@@ -418,7 +396,7 @@ bool MaterialParser::getReflectionMode(ReflectionMode* value) const noexcept {
}
bool MaterialParser::getShader(ShaderContent& shader,
ShaderModel const shaderModel, Variant const variant, ShaderStage const stage) const noexcept {
ShaderModel const shaderModel, Variant const variant, ShaderStage const stage) noexcept {
return mImpl.mMaterialChunk.getShader(shader,
mImpl.mBlobDictionary, shaderModel, variant, stage);
}
+1 -5
View File
@@ -65,11 +65,7 @@ public:
ERROR_OTHER
};
bool operator==(MaterialParser const& rhs) const noexcept;
ParseResult parse() noexcept;
uint32_t computeCrc32() const noexcept;
backend::ShaderLanguage getShaderLanguage() const noexcept;
// Accessors
@@ -133,7 +129,7 @@ public:
bool getMaterialCrc32(uint32_t* value) const noexcept;
bool getShader(filaflat::ShaderContent& shader, backend::ShaderModel shaderModel,
Variant variant, backend::ShaderStage stage) const noexcept;
Variant variant, backend::ShaderStage stage) noexcept;
bool hasShader(backend::ShaderModel const model,
Variant const variant, backend::ShaderStage const stage) const noexcept {
+1 -1
View File
@@ -569,7 +569,7 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph
// FIXME: the DescriptorSetLayout must specify SAMPLER_FLOAT
data.picking = builder.createTexture("Picking Buffer", {
.width = width, .height = height,
.format = isES2 ? TextureFormat::RGBA8 : TextureFormat::RG32UI });
.format = isES2 ? TextureFormat::RGBA8 : TextureFormat::RG32F });
data.picking = builder.write(data.picking,
FrameGraphTexture::Usage::COLOR_ATTACHMENT);
+1 -1
View File
@@ -76,7 +76,7 @@ FBufferObject::FBufferObject(FEngine& engine, const Builder& builder)
: mByteCount(builder->mByteCount), mBindingType(builder->mBindingType) {
FEngine::DriverApi& driver = engine.getDriverApi();
mHandle = driver.createBufferObject(builder->mByteCount, builder->mBindingType,
backend::BufferUsage::STATIC, utils::CString{ builder.getName() });
backend::BufferUsage::STATIC, builder.getName());
}
void FBufferObject::terminate(FEngine& engine) {
+2 -2
View File
@@ -908,8 +908,8 @@ FIndirectLight* FEngine::createIndirectLight(const IndirectLight::Builder& build
}
FMaterial* FEngine::createMaterial(const Material::Builder& builder,
MaterialDefinition const& definition) noexcept {
return create(mMaterials, builder, definition);
std::unique_ptr<MaterialParser> materialParser) noexcept {
return create(mMaterials, builder, std::move(materialParser));
}
FSkybox* FEngine::createSkybox(const Skybox::Builder& builder) noexcept {
+1 -8
View File
@@ -25,7 +25,6 @@
#include "ResourceList.h"
#include "HwDescriptorSetLayoutFactory.h"
#include "HwVertexBufferInfoFactory.h"
#include "MaterialCache.h"
#include "components/CameraManager.h"
#include "components/LightManager.h"
@@ -292,10 +291,6 @@ public:
return mResourceAllocatorDisposer;
}
MaterialCache& getMaterialCache() const noexcept {
return mMaterialCache;
}
void* streamAlloc(size_t size, size_t alignment) noexcept;
Epoch getEngineEpoch() const { return mEngineEpoch; }
@@ -317,8 +312,7 @@ public:
FMorphTargetBuffer* createMorphTargetBuffer(const MorphTargetBuffer::Builder& builder) noexcept;
FInstanceBuffer* createInstanceBuffer(const InstanceBuffer::Builder& builder) noexcept;
FIndirectLight* createIndirectLight(const IndirectLight::Builder& builder) noexcept;
FMaterial* createMaterial(const Material::Builder& builder,
MaterialDefinition const& definition) noexcept;
FMaterial* createMaterial(const Material::Builder& builder, std::unique_ptr<MaterialParser> materialParser) noexcept;
FTexture* createTexture(const Texture::Builder& builder) noexcept;
FSkybox* createSkybox(const Skybox::Builder& builder) noexcept;
FColorGrading* createColorGrading(const ColorGrading::Builder& builder) noexcept;
@@ -596,7 +590,6 @@ private:
FLightManager mLightManager;
FCameraManager mCameraManager;
std::shared_ptr<ResourceAllocatorDisposer> mResourceAllocatorDisposer;
mutable MaterialCache mMaterialCache;
HwVertexBufferInfoFactory mHwVertexBufferInfoFactory;
HwDescriptorSetLayoutFactory mHwDescriptorSetLayoutFactory;
DescriptorSetLayout mPerViewDescriptorSetLayoutDepthVariant;
+440 -92
View File
@@ -58,8 +58,12 @@
#include <algorithm>
#include <array>
#include <iterator>
#include <memory>
#include <mutex>
#include <new>
#include <optional>
#include <string>
#include <string_view>
#include <unordered_map>
#include <utility>
@@ -74,6 +78,46 @@ using namespace backend;
using namespace filaflat;
using namespace utils;
static std::unique_ptr<MaterialParser> createParser(Backend const backend,
FixedCapacityVector<ShaderLanguage> languages, const void* data, size_t size) {
// unique_ptr so we don't leak MaterialParser on failures below
auto materialParser = std::make_unique<MaterialParser>(languages, data, size);
MaterialParser::ParseResult const materialResult = materialParser->parse();
if (UTILS_UNLIKELY(materialResult == MaterialParser::ParseResult::ERROR_MISSING_BACKEND)) {
CString languageNames;
for (auto it = languages.begin(); it != languages.end(); ++it) {
languageNames.append(CString{shaderLanguageToString(*it)});
if (std::next(it) != languages.end()) {
languageNames.append(", ");
}
}
FILAMENT_CHECK_POSTCONDITION(
materialResult != MaterialParser::ParseResult::ERROR_MISSING_BACKEND)
<< "the material was not built for any of the " << to_string(backend)
<< " backend's supported shader languages (" << languageNames.c_str() << ")\n";
}
if (backend == Backend::NOOP) {
return materialParser;
}
FILAMENT_CHECK_POSTCONDITION(materialResult == MaterialParser::ParseResult::SUCCESS)
<< "could not parse the material package";
uint32_t version = 0;
materialParser->getMaterialVersion(&version);
FILAMENT_CHECK_POSTCONDITION(version == MATERIAL_VERSION)
<< "Material version mismatch. Expected " << MATERIAL_VERSION << " but received "
<< version << ".";
assert_invariant(backend != Backend::DEFAULT && "Default backend has not been resolved.");
return materialParser;
}
struct Material::BuilderDetails {
const void* mPayload = nullptr;
size_t mSize = 0;
@@ -136,21 +180,192 @@ const char* toString(ShaderModel model) {
}
Material* Material::Builder::build(Engine& engine) const {
MaterialDefinition* r = downcast(engine).getMaterialCache().acquire(downcast(engine),
mImpl->mPayload, mImpl->mSize);
if (r) {
return downcast(engine).createMaterial(*this, *r);
std::unique_ptr<MaterialParser> materialParser = createParser(
downcast(engine).getBackend(), downcast(engine).getShaderLanguage(),
mImpl->mPayload, mImpl->mSize);
if (!materialParser) {
return nullptr;
}
return nullptr;
// Try checking CRC32 value for the package and skip if it's unavailable.
if (downcast(engine).features.material.check_crc32_after_loading) {
uint32_t parsedCrc32 = 0;
materialParser->getMaterialCrc32(&parsedCrc32);
constexpr size_t crc32ChunkSize = sizeof(uint64_t) + sizeof(uint32_t) + sizeof(uint32_t);
const size_t originalSize = mImpl->mSize - crc32ChunkSize;
assert_invariant(mImpl->mSize > crc32ChunkSize);
std::vector<uint32_t> crc32Table;
hash::crc32GenerateTable(crc32Table);
uint32_t expectedCrc32 = hash::crc32Update(0, mImpl->mPayload, originalSize, crc32Table);
if (parsedCrc32 != expectedCrc32) {
CString name;
materialParser->getName(&name);
LOG(ERROR) << "The material '" << name.c_str_safe()
<< "' is corrupted: crc32_expected=" << expectedCrc32
<< ", crc32_parsed=" << parsedCrc32;
return nullptr;
}
}
uint32_t v = 0;
materialParser->getShaderModels(&v);
bitset32 shaderModels;
shaderModels.setValue(v);
ShaderModel const shaderModel = downcast(engine).getShaderModel();
if (!shaderModels.test(static_cast<uint32_t>(shaderModel))) {
CString name;
materialParser->getName(&name);
char shaderModelsString[16];
snprintf(shaderModelsString, sizeof(shaderModelsString), "%#x", shaderModels.getValue());
LOG(ERROR) << "The material '" << name.c_str_safe() << "' was not built for "
<< toString(shaderModel) << ".";
LOG(ERROR) << "Compiled material contains shader models " << shaderModelsString << ".";
return nullptr;
}
// Print a warning if the material's stereo type doesn't align with the engine's setting.
MaterialDomain materialDomain;
UserVariantFilterMask variantFilterMask;
materialParser->getMaterialDomain(&materialDomain);
materialParser->getMaterialVariantFilterMask(&variantFilterMask);
bool const hasStereoVariants = !(variantFilterMask & UserVariantFilterMask(UserVariantFilterBit::STE));
if (materialDomain == MaterialDomain::SURFACE && hasStereoVariants) {
StereoscopicType const engineStereoscopicType = engine.getConfig().stereoscopicType;
// Default materials are always compiled with either 'instanced' or 'multiview'.
// So, we only verify compatibility if the engine is set up for stereo.
if (engineStereoscopicType != StereoscopicType::NONE) {
StereoscopicType materialStereoscopicType = StereoscopicType::NONE;
materialParser->getStereoscopicType(&materialStereoscopicType);
if (materialStereoscopicType != engineStereoscopicType) {
CString name;
materialParser->getName(&name);
LOG(WARNING) << "The stereoscopic type in the compiled material '"
<< name.c_str_safe() << "' is " << (int) materialStereoscopicType
<< ", which is not compatible with the engine's setting "
<< (int) engineStereoscopicType << ".";
}
}
}
return downcast(engine).createMaterial(*this, std::move(materialParser));
}
FMaterial::FMaterial(FEngine& engine, const Builder& builder, MaterialDefinition const& definition)
: mDefinition(definition),
mIsDefaultMaterial(builder->mDefaultMaterial),
FMaterial::FMaterial(FEngine& engine, const Builder& builder,
std::unique_ptr<MaterialParser> materialParser)
: mIsDefaultMaterial(builder->mDefaultMaterial),
mEngine(engine),
mMaterialId(engine.getMaterialId()) {
processSpecializationConstants(engine, builder);
processPushConstants(engine);
mMaterialId(engine.getMaterialId()),
mMaterialParser(std::move(materialParser)) {
MaterialParser* const parser = mMaterialParser.get();
UTILS_UNUSED_IN_RELEASE bool const nameOk = parser->getName(&mName);
assert_invariant(nameOk);
mFeatureLevel = [parser]() -> FeatureLevel {
// code written this way so the IDE will complain when/if we add a FeatureLevel
uint8_t level = 1;
parser->getFeatureLevel(&level);
assert_invariant(level <= 3);
FeatureLevel featureLevel = FeatureLevel::FEATURE_LEVEL_1;
switch (FeatureLevel(level)) {
case FeatureLevel::FEATURE_LEVEL_0:
case FeatureLevel::FEATURE_LEVEL_1:
case FeatureLevel::FEATURE_LEVEL_2:
case FeatureLevel::FEATURE_LEVEL_3:
featureLevel = FeatureLevel(level);
break;
}
return featureLevel;
}();
UTILS_UNUSED_IN_RELEASE bool success;
success = parser->getCacheId(&mCacheId);
assert_invariant(success);
success = parser->getSIB(&mSamplerInterfaceBlock);
assert_invariant(success);
success = parser->getUIB(&mUniformInterfaceBlock);
assert_invariant(success);
if (UTILS_UNLIKELY(parser->getShaderLanguage() == ShaderLanguage::ESSL1)) {
success = parser->getAttributeInfo(&mAttributeInfo);
assert_invariant(success);
success = parser->getBindingUniformInfo(&mBindingUniformInfo);
assert_invariant(success);
}
// Older materials will not have a subpass chunk; this should not be an error.
if (!parser->getSubpasses(&mSubpassInfo)) {
mSubpassInfo.isValid = false;
}
parser->getShading(&mShading);
parser->getMaterialProperties(&mMaterialProperties);
parser->getInterpolation(&mInterpolation);
parser->getVertexDomain(&mVertexDomain);
parser->getMaterialDomain(&mMaterialDomain);
parser->getMaterialVariantFilterMask(&mVariantFilterMask);
parser->getRequiredAttributes(&mRequiredAttributes);
parser->getRefractionMode(&mRefractionMode);
parser->getRefractionType(&mRefractionType);
parser->getReflectionMode(&mReflectionMode);
parser->getTransparencyMode(&mTransparencyMode);
parser->getDoubleSided(&mDoubleSided);
parser->getCullingMode(&mCullingMode);
if (mShading == Shading::UNLIT) {
parser->hasShadowMultiplier(&mHasShadowMultiplier);
}
mIsVariantLit = mShading != Shading::UNLIT || mHasShadowMultiplier;
// color write
bool colorWrite = false;
parser->getColorWrite(&colorWrite);
mRasterState.colorWrite = colorWrite;
// depth test
bool depthTest = false;
parser->getDepthTest(&depthTest);
mRasterState.depthFunc = depthTest ? RasterState::DepthFunc::GE : RasterState::DepthFunc::A;
// if doubleSided() was called we override culling()
bool doubleSideSet = false;
parser->getDoubleSidedSet(&doubleSideSet);
if (doubleSideSet) {
mDoubleSidedCapability = true;
mRasterState.culling = mDoubleSided ? CullingMode::NONE : mCullingMode;
} else {
mRasterState.culling = mCullingMode;
}
// specular anti-aliasing
parser->hasSpecularAntiAliasing(&mSpecularAntiAliasing);
if (mSpecularAntiAliasing) {
parser->getSpecularAntiAliasingVariance(&mSpecularAntiAliasingVariance);
parser->getSpecularAntiAliasingThreshold(&mSpecularAntiAliasingThreshold);
}
parser->hasCustomDepthShader(&mHasCustomDepthShader);
bool const isLit = mIsVariantLit || mHasShadowMultiplier;
bool const isSSR = mReflectionMode == ReflectionMode::SCREEN_SPACE ||
mRefractionMode == RefractionMode::SCREEN_SPACE;
bool const hasFog = !(mVariantFilterMask & UserVariantFilterMask(UserVariantFilterBit::FOG));
mPerViewLayoutIndex = ColorPassDescriptorSet::getIndex(isLit, isSSR, hasFog);
processBlendingMode(parser);
processSpecializationConstants(engine, builder, parser);
processPushConstants(engine, parser);
processDescriptorSets(engine, parser);
precacheDepthVariants(engine);
#if FILAMENT_ENABLE_MATDBG
@@ -158,7 +373,7 @@ FMaterial::FMaterial(FEngine& engine, const Builder& builder, MaterialDefinition
matdbg::DebugServer* server = downcast(engine).debug.server;
if (UTILS_UNLIKELY(server)) {
auto const details = builder.mImpl;
mDebuggerId = server->addMaterial(mDefinition.name, details->mPayload, details->mSize, this);
mDebuggerId = server->addMaterial(mName, details->mPayload, details->mSize, this);
}
#endif
}
@@ -168,9 +383,9 @@ FMaterial::~FMaterial() noexcept = default;
void FMaterial::invalidate(Variant::type_t variantMask, Variant::type_t variantValue) noexcept {
// Note: This API is not public at the moment, so it's okay to have some debugging logs
// and extra checks.
if (mDefinition.materialDomain == MaterialDomain::SURFACE &&
!mIsDefaultMaterial &&
!mDefinition.hasCustomDepthShader) {
if (mMaterialDomain == MaterialDomain::SURFACE &&
!mIsDefaultMaterial &&
!mHasCustomDepthShader) {
// it would be unsafe to invalidate any of the cached depth variant
if (UTILS_UNLIKELY(!((variantMask & Variant::DEP) && !(variantValue & Variant::DEP)))) {
char variantMaskString[16];
@@ -187,6 +402,7 @@ void FMaterial::invalidate(Variant::type_t variantMask, Variant::type_t variantV
}
void FMaterial::terminate(FEngine& engine) {
if (mDefaultMaterialInstance) {
mDefaultMaterialInstance->setDefaultInstance(false);
engine.destroy(mDefaultMaterialInstance);
@@ -213,24 +429,28 @@ void FMaterial::terminate(FEngine& engine) {
#endif
destroyPrograms(engine);
engine.getMaterialCache().release(engine, mDefinition.getMaterialParser());
DriverApi& driver = engine.getDriverApi();
mPerViewDescriptorSetLayout.terminate(engine.getDescriptorSetLayoutFactory(), driver);
mPerViewDescriptorSetLayoutVsm.terminate(engine.getDescriptorSetLayoutFactory(), driver);
mDescriptorSetLayout.terminate(engine.getDescriptorSetLayoutFactory(), driver);
}
filament::DescriptorSetLayout const& FMaterial::getPerViewDescriptorSetLayout(
Variant const variant, bool const useVsmDescriptorSetLayout) const noexcept {
if (Variant::isValidDepthVariant(variant)) {
assert_invariant(mDefinition.materialDomain == MaterialDomain::SURFACE);
assert_invariant(mMaterialDomain == MaterialDomain::SURFACE);
return mEngine.getPerViewDescriptorSetLayoutDepthVariant();
}
if (Variant::isSSRVariant(variant)) {
assert_invariant(mDefinition.materialDomain == MaterialDomain::SURFACE);
assert_invariant(mMaterialDomain == MaterialDomain::SURFACE);
return mEngine.getPerViewDescriptorSetLayoutSsrVariant();
}
if (useVsmDescriptorSetLayout) {
assert_invariant(mDefinition.materialDomain == MaterialDomain::SURFACE);
return mDefinition.perViewDescriptorSetLayoutVsm;
assert_invariant(mMaterialDomain == MaterialDomain::SURFACE);
return mPerViewDescriptorSetLayoutVsm;
}
return mDefinition.perViewDescriptorSetLayout;
return mPerViewDescriptorSetLayout;
}
void FMaterial::compile(CompilerPriorityQueue const priority,
@@ -287,35 +507,25 @@ FMaterialInstance* FMaterial::createInstance(const char* name) const noexcept {
FMaterialInstance* FMaterial::getDefaultInstance() noexcept {
if (UTILS_UNLIKELY(!mDefaultMaterialInstance)) {
mDefaultMaterialInstance = mEngine.createMaterialInstance(this,
mDefinition.name.c_str());
mDefaultMaterialInstance = mEngine.createMaterialInstance(this, mName.c_str());
mDefaultMaterialInstance->setDefaultInstance(true);
}
return mDefaultMaterialInstance;
}
bool FMaterial::hasParameter(const char* name) const noexcept {
return mDefinition.uniformInterfaceBlock.hasField(name) ||
mDefinition.samplerInterfaceBlock.hasSampler(name) ||
mDefinition.subpassInfo.name == CString(name);
return mUniformInterfaceBlock.hasField(name) ||
mSamplerInterfaceBlock.hasSampler(name) ||
mSubpassInfo.name == CString(name);
}
bool FMaterial::isSampler(const char* name) const noexcept {
return mDefinition.samplerInterfaceBlock.hasSampler(name);
return mSamplerInterfaceBlock.hasSampler(name);
}
BufferInterfaceBlock::FieldInfo const* FMaterial::reflect(
std::string_view const name) const noexcept {
return mDefinition.uniformInterfaceBlock.getFieldInfo(name);
}
MaterialParser const& FMaterial::getMaterialParser() const noexcept {
#if FILAMENT_ENABLE_MATDBG
if (mEditedMaterialParser) {
return *mEditedMaterialParser;
}
#endif
return mDefinition.getMaterialParser();
return mUniformInterfaceBlock.getFieldInfo(name);
}
bool FMaterial::hasVariant(Variant const variant) const noexcept {
@@ -333,10 +543,10 @@ bool FMaterial::hasVariant(Variant const variant) const noexcept {
return false;
}
const ShaderModel sm = mEngine.getShaderModel();
if (!mDefinition.getMaterialParser().hasShader(sm, vertexVariant, ShaderStage::VERTEX)) {
if (!mMaterialParser->hasShader(sm, vertexVariant, ShaderStage::VERTEX)) {
return false;
}
if (!mDefinition.getMaterialParser().hasShader(sm, fragmentVariant, ShaderStage::FRAGMENT)) {
if (!mMaterialParser->hasShader(sm, fragmentVariant, ShaderStage::FRAGMENT)) {
return false;
}
return true;
@@ -344,7 +554,7 @@ bool FMaterial::hasVariant(Variant const variant) const noexcept {
void FMaterial::prepareProgramSlow(Variant const variant,
backend::CompilerPriorityQueue const priorityQueue) const noexcept {
assert_invariant(mEngine.hasFeatureLevel(mDefinition.featureLevel));
assert_invariant(mEngine.hasFeatureLevel(mFeatureLevel));
switch (getMaterialDomain()) {
case MaterialDomain::SURFACE:
getSurfaceProgramSlow(variant, priorityQueue);
@@ -395,15 +605,13 @@ Program FMaterial::getProgramWithVariants(
* Vertex shader
*/
MaterialParser const& parser = getMaterialParser();
ShaderContent& vsBuilder = engine.getVertexShaderContent();
UTILS_UNUSED_IN_RELEASE bool const vsOK = parser.getShader(vsBuilder, sm,
UTILS_UNUSED_IN_RELEASE bool const vsOK = mMaterialParser->getShader(vsBuilder, sm,
vertexVariant, ShaderStage::VERTEX);
FILAMENT_CHECK_POSTCONDITION(isNoop || (vsOK && !vsBuilder.empty()))
<< "The material '" << mDefinition.name.c_str()
<< "The material '" << mName.c_str()
<< "' has not been compiled to include the required GLSL or SPIR-V chunks for the "
"vertex shader (variant="
<< +variant.key << ", filtered=" << +vertexVariant.key << ").";
@@ -414,11 +622,11 @@ Program FMaterial::getProgramWithVariants(
ShaderContent& fsBuilder = engine.getFragmentShaderContent();
UTILS_UNUSED_IN_RELEASE bool const fsOK = parser.getShader(fsBuilder, sm,
UTILS_UNUSED_IN_RELEASE bool const fsOK = mMaterialParser->getShader(fsBuilder, sm,
fragmentVariant, ShaderStage::FRAGMENT);
FILAMENT_CHECK_POSTCONDITION(isNoop || (fsOK && !fsBuilder.empty()))
<< "The material '" << mDefinition.name.c_str()
<< "The material '" << mName.c_str()
<< "' has not been compiled to include the required GLSL or SPIR-V chunks for the "
"fragment shader (variant="
<< +variant.key << ", filtered=" << +fragmentVariant.key << ").";
@@ -426,8 +634,8 @@ Program FMaterial::getProgramWithVariants(
Program program;
program.shader(ShaderStage::VERTEX, vsBuilder.data(), vsBuilder.size())
.shader(ShaderStage::FRAGMENT, fsBuilder.data(), fsBuilder.size())
.shaderLanguage(parser.getShaderLanguage())
.diagnostics(mDefinition.name,
.shaderLanguage(mMaterialParser->getShaderLanguage())
.diagnostics(mName,
[variant, vertexVariant, fragmentVariant](utils::CString const& name,
io::ostream& out) -> io::ostream& {
return out << name.c_str_safe() << ", variant=(" << io::hex << +variant.key
@@ -436,26 +644,26 @@ Program FMaterial::getProgramWithVariants(
<< io::hex << +fragmentVariant.key << io::dec << ")";
});
if (UTILS_UNLIKELY(parser.getShaderLanguage() == ShaderLanguage::ESSL1)) {
assert_invariant(!mDefinition.bindingUniformInfo.empty());
for (auto const& [index, name, uniforms] : mDefinition.bindingUniformInfo) {
if (UTILS_UNLIKELY(mMaterialParser->getShaderLanguage() == ShaderLanguage::ESSL1)) {
assert_invariant(!mBindingUniformInfo.empty());
for (auto const& [index, name, uniforms] : mBindingUniformInfo) {
program.uniforms(uint32_t(index), name, uniforms);
}
program.attributes(mDefinition.attributeInfo);
program.attributes(mAttributeInfo);
}
program.descriptorBindings(+DescriptorSetBindingPoints::PER_VIEW,
mDefinition.programDescriptorBindings[+DescriptorSetBindingPoints::PER_VIEW]);
mProgramDescriptorBindings[+DescriptorSetBindingPoints::PER_VIEW]);
program.descriptorBindings(+DescriptorSetBindingPoints::PER_RENDERABLE,
mDefinition.programDescriptorBindings[+DescriptorSetBindingPoints::PER_RENDERABLE]);
mProgramDescriptorBindings[+DescriptorSetBindingPoints::PER_RENDERABLE]);
program.descriptorBindings(+DescriptorSetBindingPoints::PER_MATERIAL,
mDefinition.programDescriptorBindings[+DescriptorSetBindingPoints::PER_MATERIAL]);
mProgramDescriptorBindings[+DescriptorSetBindingPoints::PER_MATERIAL]);
program.specializationConstants(mSpecializationConstants);
program.pushConstants(ShaderStage::VERTEX, mPushConstants[uint8_t(ShaderStage::VERTEX)]);
program.pushConstants(ShaderStage::FRAGMENT, mPushConstants[uint8_t(ShaderStage::FRAGMENT)]);
program.cacheId(hash::combine(size_t(mDefinition.cacheId), variant.key));
program.cacheId(hash::combine(size_t(mCacheId), variant.key));
return program;
}
@@ -478,7 +686,7 @@ void FMaterial::createAndCacheProgram(Program&& p, Variant const variant) const
}
}
auto const program = driverApi.createProgram(std::move(p), CString{ mDefinition.name });
auto const program = driverApi.createProgram(std::move(p), mName);
assert_invariant(program);
mCachedPrograms[variant.key] = program;
@@ -496,7 +704,7 @@ void FMaterial::createAndCacheProgram(Program&& p, Variant const variant) const
size_t FMaterial::getParameters(ParameterInfo* parameters, size_t count) const noexcept {
count = std::min(count, getParameterCount());
const auto& uniforms = mDefinition.uniformInterfaceBlock.getFieldInfoList();
const auto& uniforms = mUniformInterfaceBlock.getFieldInfoList();
size_t i = 0;
size_t const uniformCount = std::min(count, size_t(uniforms.size()));
for ( ; i < uniformCount; i++) {
@@ -510,7 +718,7 @@ size_t FMaterial::getParameters(ParameterInfo* parameters, size_t count) const n
info.precision = uniformInfo.precision;
}
const auto& samplers = mDefinition.samplerInterfaceBlock.getSamplerInfoList();
const auto& samplers = mSamplerInterfaceBlock.getSamplerInfoList();
size_t const samplerCount = samplers.size();
for (size_t j = 0; i < count && j < samplerCount; i++, j++) {
ParameterInfo& info = parameters[i];
@@ -523,14 +731,14 @@ size_t FMaterial::getParameters(ParameterInfo* parameters, size_t count) const n
info.precision = samplerInfo.precision;
}
if (mDefinition.subpassInfo.isValid && i < count) {
if (mSubpassInfo.isValid && i < count) {
ParameterInfo& info = parameters[i];
info.name = mDefinition.subpassInfo.name.c_str();
info.name = mSubpassInfo.name.c_str();
info.isSampler = false;
info.isSubpass = true;
info.subpassType = mDefinition.subpassInfo.type;
info.subpassType = mSubpassInfo.type;
info.count = 1;
info.precision = mDefinition.subpassInfo.precision;
info.precision = mSubpassInfo.precision;
}
return count;
@@ -543,7 +751,7 @@ size_t FMaterial::getParameters(ParameterInfo* parameters, size_t count) const n
// Material Debugger is attached. The only editable features of a material package are the shader
// source strings, so here we trigger a rebuild of the HwProgram objects.
void FMaterial::applyPendingEdits() noexcept {
const char* name = mDefinition.name.c_str();
const char* name = mName.c_str();
DLOG(INFO) << "Applying edits to " << (name ? name : "(untitled)");
destroyPrograms(mEngine); // FIXME: this will not destroy the shared variants
latchPendingEdits();
@@ -561,7 +769,7 @@ bool FMaterial::hasPendingEdits() const noexcept {
void FMaterial::latchPendingEdits() noexcept {
std::lock_guard const lock(mPendingEditsLock);
mEditedMaterialParser = std::move(mPendingEdits);
mMaterialParser = std::move(mPendingEdits);
}
/**
@@ -578,7 +786,7 @@ void FMaterial::onEditCallback(void* userdata, const CString&, const void* packa
// This is called on a web server thread, so we defer clearing the program cache
// and swapping out the MaterialParser until the next getProgram call.
std::unique_ptr<MaterialParser> pending = MaterialDefinition::createParser(
std::unique_ptr<MaterialParser> pending = createParser(
engine.getBackend(), engine.getShaderLanguage(), packageData, packageSize);
material->setPendingEdits(std::move(pending));
}
@@ -624,9 +832,9 @@ void FMaterial::destroyPrograms(FEngine& engine,
DriverApi& driverApi = engine.getDriverApi();
auto& cachedPrograms = mCachedPrograms;
switch (mDefinition.materialDomain) {
switch (mMaterialDomain) {
case MaterialDomain::SURFACE: {
if (mIsDefaultMaterial || mDefinition.hasCustomDepthShader) {
if (mIsDefaultMaterial || mHasCustomDepthShader) {
// default material, or we have custom depth shaders, we destroy all variants
for (size_t k = 0, n = VARIANT_COUNT; k < n; ++k) {
if ((k & variantMask) == variantValue) {
@@ -692,8 +900,8 @@ void FMaterial::destroyPrograms(FEngine& engine,
}
std::optional<uint32_t> FMaterial::getSpecializationConstantId(std::string_view const name) const noexcept {
auto const pos = mDefinition.specializationConstantsNameToIndex.find(name);
if (pos != mDefinition.specializationConstantsNameToIndex.end()) {
auto const pos = mSpecializationConstantsNameToIndex.find(name);
if (pos != mSpecializationConstantsNameToIndex.end()) {
return pos->second + CONFIG_MAX_RESERVED_SPEC_CONSTANTS;
}
return std::nullopt;
@@ -701,11 +909,11 @@ std::optional<uint32_t> FMaterial::getSpecializationConstantId(std::string_view
template<typename T, typename>
bool FMaterial::setConstant(uint32_t id, T value) noexcept {
size_t const maxId = mDefinition.materialConstants.size() + CONFIG_MAX_RESERVED_SPEC_CONSTANTS;
size_t const maxId = mMaterialConstants.size() + CONFIG_MAX_RESERVED_SPEC_CONSTANTS;
if (UTILS_LIKELY(id < maxId)) {
if (id >= CONFIG_MAX_RESERVED_SPEC_CONSTANTS) {
// Constant from the material itself (as opposed to the reserved ones)
auto const& constant = mDefinition.materialConstants[id - CONFIG_MAX_RESERVED_SPEC_CONSTANTS];
auto const& constant = mMaterialConstants[id - CONFIG_MAX_RESERVED_SPEC_CONSTANTS];
using ConstantType = ConstantType;
switch (constant.type) {
case ConstantType::INT:
@@ -738,8 +946,98 @@ bool FMaterial::setConstant(uint32_t id, T value) noexcept {
return false;
}
void FMaterial::processSpecializationConstants(FEngine& engine, Builder const& builder) {
// TODO: migrate some or all of this into MaterialDefinition.
void FMaterial::processBlendingMode(MaterialParser const* const parser) {
parser->getBlendingMode(&mBlendingMode);
if (mBlendingMode == BlendingMode::MASKED) {
parser->getMaskThreshold(&mMaskThreshold);
}
if (mBlendingMode == BlendingMode::CUSTOM) {
parser->getCustomBlendFunction(&mCustomBlendFunctions);
}
// blending mode
switch (mBlendingMode) {
// Do not change the MASKED behavior without checking for regressions with
// AlphaBlendModeTest and TextureLinearInterpolationTest, with and without
// View::BlendMode::TRANSLUCENT.
case BlendingMode::MASKED:
case BlendingMode::OPAQUE:
mRasterState.blendFunctionSrcRGB = BlendFunction::ONE;
mRasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
mRasterState.blendFunctionDstRGB = BlendFunction::ZERO;
mRasterState.blendFunctionDstAlpha = BlendFunction::ZERO;
mRasterState.depthWrite = true;
break;
case BlendingMode::TRANSPARENT:
case BlendingMode::FADE:
mRasterState.blendFunctionSrcRGB = BlendFunction::ONE;
mRasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
mRasterState.blendFunctionDstRGB = BlendFunction::ONE_MINUS_SRC_ALPHA;
mRasterState.blendFunctionDstAlpha = BlendFunction::ONE_MINUS_SRC_ALPHA;
mRasterState.depthWrite = false;
break;
case BlendingMode::ADD:
mRasterState.blendFunctionSrcRGB = BlendFunction::ONE;
mRasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
mRasterState.blendFunctionDstRGB = BlendFunction::ONE;
mRasterState.blendFunctionDstAlpha = BlendFunction::ONE;
mRasterState.depthWrite = false;
break;
case BlendingMode::MULTIPLY:
mRasterState.blendFunctionSrcRGB = BlendFunction::ZERO;
mRasterState.blendFunctionSrcAlpha = BlendFunction::ZERO;
mRasterState.blendFunctionDstRGB = BlendFunction::SRC_COLOR;
mRasterState.blendFunctionDstAlpha = BlendFunction::SRC_COLOR;
mRasterState.depthWrite = false;
break;
case BlendingMode::SCREEN:
mRasterState.blendFunctionSrcRGB = BlendFunction::ONE;
mRasterState.blendFunctionSrcAlpha = BlendFunction::ONE;
mRasterState.blendFunctionDstRGB = BlendFunction::ONE_MINUS_SRC_COLOR;
mRasterState.blendFunctionDstAlpha = BlendFunction::ONE_MINUS_SRC_COLOR;
mRasterState.depthWrite = false;
break;
case BlendingMode::CUSTOM:
mRasterState.blendFunctionSrcRGB = mCustomBlendFunctions[0];
mRasterState.blendFunctionSrcAlpha = mCustomBlendFunctions[1];
mRasterState.blendFunctionDstRGB = mCustomBlendFunctions[2];
mRasterState.blendFunctionDstAlpha = mCustomBlendFunctions[3];
mRasterState.depthWrite = false;
}
// depth write
bool depthWriteSet = false;
parser->getDepthWriteSet(&depthWriteSet);
if (depthWriteSet) {
bool depthWrite = false;
parser->getDepthWrite(&depthWrite);
mRasterState.depthWrite = depthWrite;
}
// alpha to coverage
bool alphaToCoverageSet = false;
parser->getAlphaToCoverageSet(&alphaToCoverageSet);
if (alphaToCoverageSet) {
bool alphaToCoverage = false;
parser->getAlphaToCoverage(&alphaToCoverage);
mRasterState.alphaToCoverage = alphaToCoverage;
} else {
mRasterState.alphaToCoverage = mBlendingMode == BlendingMode::MASKED;
}
}
void FMaterial::processSpecializationConstants(FEngine& engine, Builder const& builder,
MaterialParser const* const parser) {
// Older materials won't have a constants chunk, but that's okay.
parser->getConstants(&mMaterialConstants);
for (size_t i = 0, c = mMaterialConstants.size(); i < c; i++) {
auto& item = mMaterialConstants[i];
// the key can be a string_view because mMaterialConstant owns the CString
std::string_view const key{ item.name.data(), item.name.size() };
mSpecializationConstantsNameToIndex[key] = i;
}
// Verify that all the constant specializations exist in the material and that their types match.
// The first specialization constants are defined internally by Filament.
@@ -762,8 +1060,7 @@ void FMaterial::processSpecializationConstants(FEngine& engine, Builder const& b
bool const powerVrShaderWorkarounds =
engine.getDriverApi().isWorkaroundNeeded(Workaround::POWER_VR_SHADER_WORKAROUNDS);
mSpecializationConstants.reserve(
mDefinition.materialConstants.size() + CONFIG_MAX_RESERVED_SPEC_CONSTANTS);
mSpecializationConstants.reserve(mMaterialConstants.size() + CONFIG_MAX_RESERVED_SPEC_CONSTANTS);
mSpecializationConstants.push_back({
+ReservedSpecializationConstants::BACKEND_FEATURE_LEVEL,
int(engine.getSupportedFeatureLevel()) });
@@ -797,8 +1094,7 @@ void FMaterial::processSpecializationConstants(FEngine& engine, Builder const& b
mSpecializationConstants.push_back({
+ReservedSpecializationConstants::CONFIG_SHADOW_SAMPLING_METHOD,
int32_t(builder->mShadowSamplingQuality) });
if (UTILS_UNLIKELY(
mDefinition.getMaterialParser().getShaderLanguage() == ShaderLanguage::ESSL1)) {
if (UTILS_UNLIKELY(parser->getShaderLanguage() == ShaderLanguage::ESSL1)) {
// The actual value of this spec-constant is set in the OpenGLDriver backend.
mSpecializationConstants.push_back({
+ReservedSpecializationConstants::CONFIG_SRGB_SWAPCHAIN_EMULATION,
@@ -807,29 +1103,29 @@ void FMaterial::processSpecializationConstants(FEngine& engine, Builder const& b
for (auto const& [name, value] : builder->mConstantSpecializations) {
std::string_view const key{ name.data(), name.size() };
auto pos = mDefinition.specializationConstantsNameToIndex.find(key);
FILAMENT_CHECK_PRECONDITION(pos != mDefinition.specializationConstantsNameToIndex.end())
<< "The material " << mDefinition.name.c_str_safe()
auto pos = mSpecializationConstantsNameToIndex.find(key);
FILAMENT_CHECK_PRECONDITION(pos != mSpecializationConstantsNameToIndex.end())
<< "The material " << mName.c_str_safe()
<< " does not have a constant parameter named " << name.c_str() << ".";
constexpr char const* const types[3] = {"an int", "a float", "a bool"};
auto const& constant = mDefinition.materialConstants[pos->second];
auto const& constant = mMaterialConstants[pos->second];
switch (constant.type) {
case ConstantType::INT:
FILAMENT_CHECK_PRECONDITION(std::holds_alternative<int32_t>(value))
<< "The constant parameter " << name.c_str() << " on material "
<< mDefinition.name.c_str_safe() << " is of type int, but " << types[value.index()]
<< mName.c_str_safe() << " is of type int, but " << types[value.index()]
<< " was provided.";
break;
case ConstantType::FLOAT:
FILAMENT_CHECK_PRECONDITION(std::holds_alternative<float>(value))
<< "The constant parameter " << name.c_str() << " on material "
<< mDefinition.name.c_str_safe() << " is of type float, but " << types[value.index()]
<< mName.c_str_safe() << " is of type float, but " << types[value.index()]
<< " was provided.";
break;
case ConstantType::BOOL:
FILAMENT_CHECK_PRECONDITION(std::holds_alternative<bool>(value))
<< "The constant parameter " << name.c_str() << " on material "
<< mDefinition.name.c_str_safe() << " is of type bool, but " << types[value.index()]
<< mName.c_str_safe() << " is of type bool, but " << types[value.index()]
<< " was provided.";
break;
}
@@ -838,9 +1134,7 @@ void FMaterial::processSpecializationConstants(FEngine& engine, Builder const& b
}
}
void FMaterial::processPushConstants(FEngine&) {
// TODO: move some or all of this into MaterialDefinition.
void FMaterial::processPushConstants(FEngine&, MaterialParser const* parser) {
FixedCapacityVector<Program::PushConstant>& vertexConstants =
mPushConstants[uint8_t(ShaderStage::VERTEX)];
FixedCapacityVector<Program::PushConstant>& fragmentConstants =
@@ -848,7 +1142,7 @@ void FMaterial::processPushConstants(FEngine&) {
CString structVarName;
FixedCapacityVector<MaterialPushConstant> pushConstants;
mDefinition.getMaterialParser().getPushConstants(&structVarName, &pushConstants);
parser->getPushConstants(&structVarName, &pushConstants);
vertexConstants.reserve(pushConstants.size());
fragmentConstants.reserve(pushConstants.size());
@@ -902,9 +1196,9 @@ void FMaterial::precacheDepthVariants(FEngine& engine) {
}
// if possible pre-cache all depth variants from the default material
if (mDefinition.materialDomain == MaterialDomain::SURFACE &&
if (mMaterialDomain == MaterialDomain::SURFACE &&
!mIsDefaultMaterial &&
!mDefinition.hasCustomDepthShader) {
!mHasCustomDepthShader) {
FMaterial const* const pDefaultMaterial = engine.getDefaultMaterial();
assert_invariant(pDefaultMaterial);
auto const allDepthVariants = VariantUtils::getDepthVariants();
@@ -915,9 +1209,63 @@ void FMaterial::precacheDepthVariants(FEngine& engine) {
}
}
void FMaterial::processDescriptorSets(FEngine& engine, MaterialParser const* const parser) {
UTILS_UNUSED_IN_RELEASE bool success;
success = parser->getDescriptorBindings(&mProgramDescriptorBindings);
assert_invariant(success);
backend::DescriptorSetLayout descriptorSetLayout;
success = parser->getDescriptorSetLayout(&descriptorSetLayout);
assert_invariant(success);
// get the PER_VIEW descriptor binding info
bool const isLit = mIsVariantLit || mHasShadowMultiplier;
bool const isSSR = mReflectionMode == ReflectionMode::SCREEN_SPACE ||
mRefractionMode == RefractionMode::SCREEN_SPACE;
bool const hasFog = !(mVariantFilterMask & UserVariantFilterMask(UserVariantFilterBit::FOG));
auto perViewDescriptorSetLayout = descriptor_sets::getPerViewDescriptorSetLayout(
mMaterialDomain, isLit, isSSR, hasFog, false);
auto perViewDescriptorSetLayoutVsm = descriptor_sets::getPerViewDescriptorSetLayout(
mMaterialDomain, isLit, isSSR, hasFog, true);
// set the labels
descriptorSetLayout.label = CString{ mName }.append("_perMat");
perViewDescriptorSetLayout.label = CString{ mName }.append("_perView");
perViewDescriptorSetLayoutVsm.label = CString{ mName }.append("_perViewVsm");
// get the PER_RENDERABLE and PER_VIEW descriptor binding info
for (auto&& [bindingPoint, descriptorSetLayout] : {
std::pair{ DescriptorSetBindingPoints::PER_RENDERABLE,
descriptor_sets::getPerRenderableLayout() },
std::pair{ DescriptorSetBindingPoints::PER_VIEW,
perViewDescriptorSetLayout }}) {
Program::DescriptorBindingsInfo& descriptors = mProgramDescriptorBindings[+bindingPoint];
descriptors.reserve(descriptorSetLayout.bindings.size());
for (auto const& entry: descriptorSetLayout.bindings) {
auto const& name = descriptor_sets::getDescriptorName(bindingPoint, entry.binding);
descriptors.push_back({ name, entry.type, entry.binding });
}
}
mDescriptorSetLayout = {
engine.getDescriptorSetLayoutFactory(),
engine.getDriverApi(), std::move(descriptorSetLayout) };
mPerViewDescriptorSetLayout = {
engine.getDescriptorSetLayoutFactory(),
engine.getDriverApi(), std::move(perViewDescriptorSetLayout) };
mPerViewDescriptorSetLayoutVsm = {
engine.getDescriptorSetLayoutFactory(),
engine.getDriverApi(), std::move(perViewDescriptorSetLayoutVsm) };
}
descriptor_binding_t FMaterial::getSamplerBinding(
std::string_view const& name) const {
return mDefinition.samplerInterfaceBlock.getSamplerInfo(name)->binding;
return mSamplerInterfaceBlock.getSamplerInfo(name)->binding;
}
template bool FMaterial::setConstant<int32_t>(uint32_t id, int32_t value) noexcept;
+111 -47
View File
@@ -46,8 +46,15 @@
#include <utils/Mutex.h>
#include <array>
#include <memory>
#include <mutex>
#include <new>
#include <optional>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <stddef.h>
#include <stdint.h>
@@ -65,7 +72,7 @@ class FEngine;
class FMaterial : public Material {
public:
FMaterial(FEngine& engine, const Builder& builder,
MaterialDefinition const& definition);
std::unique_ptr<MaterialParser> materialParser);
~FMaterial() noexcept;
class DefaultMaterialBuilder : public Builder {
@@ -78,12 +85,12 @@ public:
// return the uniform interface block for this material
const BufferInterfaceBlock& getUniformInterfaceBlock() const noexcept {
return mDefinition.uniformInterfaceBlock;
return mUniformInterfaceBlock;
}
DescriptorSetLayout const& getPerViewDescriptorSetLayout() const noexcept {
assert_invariant(mDefinition.materialDomain == MaterialDomain::POST_PROCESS);
return mDefinition.perViewDescriptorSetLayout;
assert_invariant(mMaterialDomain == MaterialDomain::POST_PROCESS);
return mPerViewDescriptorSetLayout;
}
DescriptorSetLayout const& getPerViewDescriptorSetLayout(
@@ -94,11 +101,11 @@ public:
// also use the default material's layout.
DescriptorSetLayout const& getDescriptorSetLayout(Variant variant = {}) const noexcept {
if (!isSharedVariant(variant)) {
return mDefinition.descriptorSetLayout;
return mDescriptorSetLayout;
}
FMaterial const* const pDefaultMaterial = mEngine.getDefaultMaterial();
if (UTILS_UNLIKELY(!pDefaultMaterial)) {
return mDefinition.descriptorSetLayout;
return mDescriptorSetLayout;
}
return pDefaultMaterial->getDescriptorSetLayout();
}
@@ -173,58 +180,58 @@ public:
[[nodiscard]]
backend::Handle<backend::HwProgram> getProgramWithMATDBG(Variant variant) const noexcept;
bool isVariantLit() const noexcept { return mDefinition.isVariantLit; }
bool isVariantLit() const noexcept { return mIsVariantLit; }
const utils::CString& getName() const noexcept { return mDefinition.name; }
backend::FeatureLevel getFeatureLevel() const noexcept { return mDefinition.featureLevel; }
backend::RasterState getRasterState() const noexcept { return mDefinition.rasterState; }
const utils::CString& getName() const noexcept { return mName; }
backend::FeatureLevel getFeatureLevel() const noexcept { return mFeatureLevel; }
backend::RasterState getRasterState() const noexcept { return mRasterState; }
uint32_t getId() const noexcept { return mMaterialId; }
UserVariantFilterMask getSupportedVariants() const noexcept {
return UserVariantFilterMask(UserVariantFilterBit::ALL) & ~mDefinition.variantFilterMask;
return UserVariantFilterMask(UserVariantFilterBit::ALL) & ~mVariantFilterMask;
}
Shading getShading() const noexcept { return mDefinition.shading; }
Interpolation getInterpolation() const noexcept { return mDefinition.interpolation; }
BlendingMode getBlendingMode() const noexcept { return mDefinition.blendingMode; }
VertexDomain getVertexDomain() const noexcept { return mDefinition.vertexDomain; }
MaterialDomain getMaterialDomain() const noexcept { return mDefinition.materialDomain; }
CullingMode getCullingMode() const noexcept { return mDefinition.cullingMode; }
TransparencyMode getTransparencyMode() const noexcept { return mDefinition.transparencyMode; }
bool isColorWriteEnabled() const noexcept { return mDefinition.rasterState.colorWrite; }
bool isDepthWriteEnabled() const noexcept { return mDefinition.rasterState.depthWrite; }
Shading getShading() const noexcept { return mShading; }
Interpolation getInterpolation() const noexcept { return mInterpolation; }
BlendingMode getBlendingMode() const noexcept { return mBlendingMode; }
VertexDomain getVertexDomain() const noexcept { return mVertexDomain; }
MaterialDomain getMaterialDomain() const noexcept { return mMaterialDomain; }
CullingMode getCullingMode() const noexcept { return mCullingMode; }
TransparencyMode getTransparencyMode() const noexcept { return mTransparencyMode; }
bool isColorWriteEnabled() const noexcept { return mRasterState.colorWrite; }
bool isDepthWriteEnabled() const noexcept { return mRasterState.depthWrite; }
bool isDepthCullingEnabled() const noexcept {
return mDefinition.rasterState.depthFunc != backend::RasterState::DepthFunc::A;
return mRasterState.depthFunc != backend::RasterState::DepthFunc::A;
}
bool isDoubleSided() const noexcept { return mDefinition.doubleSided; }
bool hasDoubleSidedCapability() const noexcept { return mDefinition.doubleSidedCapability; }
bool isAlphaToCoverageEnabled() const noexcept { return mDefinition.rasterState.alphaToCoverage; }
float getMaskThreshold() const noexcept { return mDefinition.maskThreshold; }
bool hasShadowMultiplier() const noexcept { return mDefinition.hasShadowMultiplier; }
AttributeBitset getRequiredAttributes() const noexcept { return mDefinition.requiredAttributes; }
RefractionMode getRefractionMode() const noexcept { return mDefinition.refractionMode; }
RefractionType getRefractionType() const noexcept { return mDefinition.refractionType; }
ReflectionMode getReflectionMode() const noexcept { return mDefinition.reflectionMode; }
bool isDoubleSided() const noexcept { return mDoubleSided; }
bool hasDoubleSidedCapability() const noexcept { return mDoubleSidedCapability; }
bool isAlphaToCoverageEnabled() const noexcept { return mRasterState.alphaToCoverage; }
float getMaskThreshold() const noexcept { return mMaskThreshold; }
bool hasShadowMultiplier() const noexcept { return mHasShadowMultiplier; }
AttributeBitset getRequiredAttributes() const noexcept { return mRequiredAttributes; }
RefractionMode getRefractionMode() const noexcept { return mRefractionMode; }
RefractionType getRefractionType() const noexcept { return mRefractionType; }
ReflectionMode getReflectionMode() const noexcept { return mReflectionMode; }
bool hasSpecularAntiAliasing() const noexcept { return mDefinition.specularAntiAliasing; }
float getSpecularAntiAliasingVariance() const noexcept { return mDefinition.specularAntiAliasingVariance; }
float getSpecularAntiAliasingThreshold() const noexcept { return mDefinition.specularAntiAliasingThreshold; }
bool hasSpecularAntiAliasing() const noexcept { return mSpecularAntiAliasing; }
float getSpecularAntiAliasingVariance() const noexcept { return mSpecularAntiAliasingVariance; }
float getSpecularAntiAliasingThreshold() const noexcept { return mSpecularAntiAliasingThreshold; }
backend::descriptor_binding_t getSamplerBinding(
std::string_view const& name) const;
bool hasMaterialProperty(Property property) const noexcept {
return bool(mDefinition.materialProperties & uint64_t(property));
return bool(mMaterialProperties & uint64_t(property));
}
SamplerInterfaceBlock const& getSamplerInterfaceBlock() const noexcept {
return mDefinition.samplerInterfaceBlock;
return mSamplerInterfaceBlock;
}
size_t getParameterCount() const noexcept {
return mDefinition.uniformInterfaceBlock.getFieldInfoList().size() +
mDefinition.samplerInterfaceBlock.getSamplerInfoList().size() +
(mDefinition.subpassInfo.isValid ? 1 : 0);
return mUniformInterfaceBlock.getFieldInfoList().size() +
mSamplerInterfaceBlock.getSamplerInfoList().size() +
(mSubpassInfo.isValid ? 1 : 0);
}
size_t getParameters(ParameterInfo* parameters, size_t count) const noexcept;
@@ -243,7 +250,7 @@ public:
bool setConstant(uint32_t id, T value) noexcept;
uint8_t getPerViewLayoutIndex() const noexcept {
return mDefinition.perViewLayoutIndex;
return mPerViewLayoutIndex;
}
#if FILAMENT_ENABLE_MATDBG
@@ -279,8 +286,6 @@ public:
#endif
private:
MaterialParser const& getMaterialParser() const noexcept;
bool hasVariant(Variant variant) const noexcept;
void prepareProgramSlow(Variant variant,
CompilerPriorityQueue priorityQueue) const noexcept;
@@ -291,25 +296,82 @@ private:
backend::Program getProgramWithVariants(Variant variant,
Variant vertexVariant, Variant fragmentVariant) const;
void processSpecializationConstants(FEngine& engine, Builder const& builder);
void processPushConstants(FEngine& engine);
void processBlendingMode(MaterialParser const* parser);
void processSpecializationConstants(FEngine& engine, Builder const& builder,
MaterialParser const* parser);
void processPushConstants(FEngine& engine, MaterialParser const* parser);
void precacheDepthVariants(FEngine& engine);
void processDescriptorSets(FEngine& engine, MaterialParser const* parser);
void createAndCacheProgram(backend::Program&& p, Variant variant) const noexcept;
inline bool isSharedVariant(Variant const variant) const {
return (mDefinition.materialDomain == MaterialDomain::SURFACE) && !mIsDefaultMaterial &&
!mDefinition.hasCustomDepthShader && Variant::isValidDepthVariant(variant);
return (mMaterialDomain == MaterialDomain::SURFACE) && !mIsDefaultMaterial &&
!mHasCustomDepthShader && Variant::isValidDepthVariant(variant);
}
// try to order by frequency of use
mutable std::array<backend::Handle<backend::HwProgram>, VARIANT_COUNT> mCachedPrograms;
MaterialDefinition const& mDefinition;
DescriptorSetLayout mPerViewDescriptorSetLayout;
DescriptorSetLayout mPerViewDescriptorSetLayoutVsm;
DescriptorSetLayout mDescriptorSetLayout;
backend::Program::DescriptorSetInfo mProgramDescriptorBindings;
backend::RasterState mRasterState;
TransparencyMode mTransparencyMode = TransparencyMode::DEFAULT;
bool mIsVariantLit = false;
backend::FeatureLevel mFeatureLevel = backend::FeatureLevel::FEATURE_LEVEL_1;
Shading mShading = Shading::UNLIT;
BlendingMode mBlendingMode = BlendingMode::OPAQUE;
std::array<backend::BlendFunction, 4> mCustomBlendFunctions = {};
Interpolation mInterpolation = Interpolation::SMOOTH;
VertexDomain mVertexDomain = VertexDomain::OBJECT;
MaterialDomain mMaterialDomain = MaterialDomain::SURFACE;
CullingMode mCullingMode = CullingMode::NONE;
AttributeBitset mRequiredAttributes;
UserVariantFilterMask mVariantFilterMask = 0;
RefractionMode mRefractionMode = RefractionMode::NONE;
RefractionType mRefractionType = RefractionType::SOLID;
ReflectionMode mReflectionMode = ReflectionMode::DEFAULT;
uint64_t mMaterialProperties = 0;
uint8_t mPerViewLayoutIndex = 0;
float mMaskThreshold = 0.4f;
float mSpecularAntiAliasingVariance = 0.0f;
float mSpecularAntiAliasingThreshold = 0.0f;
bool mDoubleSided = false;
bool mDoubleSidedCapability = false;
bool mHasShadowMultiplier = false;
bool mHasCustomDepthShader = false;
bool mIsDefaultMaterial = false;
bool mSpecularAntiAliasing = false;
// reserve some space to construct the default material instance
mutable FMaterialInstance* mDefaultMaterialInstance = nullptr;
SamplerInterfaceBlock mSamplerInterfaceBlock;
BufferInterfaceBlock mUniformInterfaceBlock;
SubpassInfo mSubpassInfo;
using BindingUniformInfoContainer = utils::FixedCapacityVector<std::tuple<
uint8_t, utils::CString, backend::Program::UniformInfo>>;
BindingUniformInfoContainer mBindingUniformInfo;
using AttributeInfoContainer = utils::FixedCapacityVector<std::pair<utils::CString, uint8_t>>;
AttributeInfoContainer mAttributeInfo;
// Constants defined by this Material
utils::FixedCapacityVector<MaterialConstant> mMaterialConstants;
// A map from the Constant name to the mMaterialConstant index
std::unordered_map<std::string_view, uint32_t> mSpecializationConstantsNameToIndex;
// current specialization constants for the HwProgram
utils::FixedCapacityVector<backend::Program::SpecializationConstant> mSpecializationConstants;
@@ -324,15 +386,17 @@ private:
mutable VariantList mActivePrograms;
mutable utils::Mutex mPendingEditsLock;
std::unique_ptr<MaterialParser> mPendingEdits;
std::unique_ptr<MaterialParser> mEditedMaterialParser;
void setPendingEdits(std::unique_ptr<MaterialParser> pendingEdits) noexcept;
bool hasPendingEdits() const noexcept;
void latchPendingEdits() noexcept;
#endif
utils::CString mName;
FEngine& mEngine;
const uint32_t mMaterialId;
uint64_t mCacheId = 0;
mutable uint32_t mMaterialInstanceId = 0;
std::unique_ptr<MaterialParser> mMaterialParser;
};
+2 -2
View File
@@ -81,7 +81,7 @@ FMaterialInstance::FMaterialInstance(FEngine& engine, FMaterial const* material,
size_t const uboSize = std::max(size_t(16), material->getUniformInterfaceBlock().getSize());
mUniforms = UniformBuffer(uboSize);
mUbHandle = driver.createBufferObject(mUniforms.getSize(), BufferObjectBinding::UNIFORM,
BufferUsage::STATIC, utils::CString{ material->getName() });
BufferUsage::STATIC, material->getName());
// set the UBO, always descriptor 0
mDescriptorSet.setBuffer(material->getDescriptorSetLayout(),
@@ -148,7 +148,7 @@ FMaterialInstance::FMaterialInstance(FEngine& engine,
mUniforms.setUniforms(other->getUniformBuffer());
mUbHandle = driver.createBufferObject(mUniforms.getSize(), BufferObjectBinding::UNIFORM,
BufferUsage::DYNAMIC, CString{ material->getName() });
BufferUsage::DYNAMIC, material->getName());
// set the UBO, always descriptor 0
mDescriptorSet.setBuffer(mMaterial->getDescriptorSetLayout(),
+2 -2
View File
@@ -128,7 +128,7 @@ FMorphTargetBuffer::FMorphTargetBuffer(FEngine& engine, const Builder& builder)
getHeight(mVertexCount),
mCount,
TextureUsage::DEFAULT,
utils::CString{ builder.getName() });
builder.getName());
mTbHandle = driver.createTexture(SamplerType::SAMPLER_2D_ARRAY, 1,
TextureFormat::RGBA16I, 1,
@@ -136,7 +136,7 @@ FMorphTargetBuffer::FMorphTargetBuffer(FEngine& engine, const Builder& builder)
getHeight(mVertexCount),
mCount,
TextureUsage::DEFAULT,
utils::CString{ builder.getName() });
builder.getName());
}
void FMorphTargetBuffer::terminate(FEngine& engine) {
+1 -1
View File
@@ -221,7 +221,7 @@ FRenderTarget::FRenderTarget(FEngine& engine, const Builder& builder)
FEngine::DriverApi& driver = engine.getDriverApi();
mHandle = driver.createRenderTarget(mAttachmentMask,
builder.mImpl->mWidth, builder.mImpl->mHeight, builder.mImpl->mSamples,
builder.mImpl->mLayerCount, mrt, dinfo, {}, utils::CString{ builder.getName() });
builder.mImpl->mLayerCount, mrt, dinfo, {}, builder.getName());
}
void FRenderTarget::terminate(FEngine& engine) {
+6
View File
@@ -585,6 +585,12 @@ void FRenderer::renderStandaloneView(FView const* view) {
// for endFrame() above. This operation in actually not too heavy, it just kicks the
// driver thread, which is mostlikely already running.
engine.flush();
// FIXME: This is a workaround for internal bug b/361822355.
// properly address the bug and remove this workaround.
if (engine.getBackend() == Backend::VULKAN) {
engine.flushAndWait();
}
}
}
+1 -1
View File
@@ -91,7 +91,7 @@ FSkinningBuffer::FSkinningBuffer(FEngine& engine, const Builder& builder)
getPhysicalBoneCount(mBoneCount) * sizeof(PerRenderableBoneUib::BoneData),
BufferObjectBinding::UNIFORM,
BufferUsage::DYNAMIC,
utils::CString{ builder.getName() });
builder.getName());
if (builder->mInitialize) {
// initialize the bones to identity (before rounding up)
+1 -1
View File
@@ -313,7 +313,7 @@ FTexture::FTexture(FEngine& engine, const Builder& builder)
return;
}
CString tag{ builder.getName() };
auto tag = builder.getName();
if (tag.empty()) {
tag = CString{"FTexture"};
}
+3 -6
View File
@@ -280,8 +280,7 @@ FVertexBuffer::FVertexBuffer(FEngine& engine, const Builder& builder)
mVertexBufferInfoHandle = engine.getVertexBufferInfoFactory().create(driver,
mBufferCount, mDeclaredAttributes.count(), mAttributes);
mHandle = driver.createVertexBuffer(mVertexCount, mVertexBufferInfoHandle,
utils::CString{ builder.getName() });
mHandle = driver.createVertexBuffer(mVertexCount, mVertexBufferInfoHandle, builder.getName());
// calculate buffer sizes
size_t bufferSizes[MAX_VERTEX_BUFFER_COUNT] = {};
@@ -308,8 +307,7 @@ FVertexBuffer::FVertexBuffer(FEngine& engine, const Builder& builder)
assert_invariant(bufferSizes[i] > 0);
if (!mBufferObjects[i]) {
BufferObjectHandle const bo = driver.createBufferObject(bufferSizes[i],
BufferObjectBinding::VERTEX, BufferUsage::STATIC,
utils::CString{ builder.getName() });
BufferObjectBinding::VERTEX, BufferUsage::STATIC, builder.getName());
driver.setVertexBufferObject(mHandle, i, bo);
mBufferObjects[i] = bo;
}
@@ -325,8 +323,7 @@ FVertexBuffer::FVertexBuffer(FEngine& engine, const Builder& builder)
assert_invariant(bufferSizes[i] > 0);
if (!mBufferObjects[i]) {
BufferObjectHandle const bo = driver.createBufferObject(bufferSizes[i],
BufferObjectBinding::VERTEX, BufferUsage::STATIC,
utils::CString{ builder.getName() });
BufferObjectBinding::VERTEX, BufferUsage::STATIC, builder.getName());
driver.setVertexBufferObject(mHandle, i, bo);
mBufferObjects[i] = bo;
}
+2 -2
View File
@@ -1399,8 +1399,8 @@ void FView::executePickingQueries(DriverApi& driver,
});
} else {
driver.readPixels(handle, x, y, 1, 1, {
&pQuery->result.renderable, 4u * 4u, // 4*uint
PixelDataFormat::RGBA_INTEGER, PixelDataType::UINT,
&pQuery->result.renderable, 4u * 4u, // 4*float
PixelDataFormat::RG, PixelDataType::FLOAT,
pQuery->handler, [](void*, size_t, void* user) {
FPickingQuery* const pQuery = static_cast<FPickingQuery*>(user);
// pQuery->result.renderable already contains the right value!
-1
View File
@@ -67,7 +67,6 @@ DescriptorSet& DescriptorSet::operator=(DescriptorSet&& rhs) noexcept {
mValid = rhs.mValid;
mSetAfterCommitWarning = rhs.mSetAfterCommitWarning;
mSetUndefinedParameterWarning = rhs.mSetUndefinedParameterWarning;
mName = rhs.mName;
}
return *this;
}

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