Files
filament/docs/dup/fgviewer.html
Filament Bot f5c9d973dc [automated] Updating /docs due to commit 778cbe0
Full commit hash is 778cbe09d1

DOCS_ALLOW_DIRECT_EDITS
2025-10-31 22:25:27 +00:00

346 lines
17 KiB
HTML

<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>fgviewer - 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="fgviewer"><a class="header" href="#fgviewer">fgviewer</a></h1>
<ol>
<li><a href="#capabilities">Capabilities</a></li>
<li><a href="#setup-for-desktop">Setup for Desktop</a></li>
<li><a href="#setup-for-android">Setup for Android</a></li>
<li><a href="#debugger-usage">Debugger Usage</a></li>
<li><a href="#architecture-overview">Architecture Overview</a></li>
<li><a href="#c-server">C++ Server</a></li>
<li><a href="#javascript-client">JavaScript Client</a></li>
<li><a href="#http-requests">HTTP Requests</a></li>
<li><a href="#wish-list">Wish List</a></li>
</ol>
<h2 id="capabilities"><a class="header" href="#capabilities">Capabilities</a></h2>
<p>fgviewer is a library and web application for real-time visualization of the frame graph in Filament.
It displays active passes and resource usage, providing insights into the rendering pipeline.</p>
<h2 id="setup-for-desktop"><a class="header" href="#setup-for-desktop">Setup for Desktop</a></h2>
<p>When using the easy build script, include the <code>-t</code> argument. For example:</p>
<pre><code>./build.sh -ft debug gltf_viewer
</code></pre>
<p>The <code>t</code> enables a CMake option called <code>FILAMENT_ENABLE_FGVIEWER</code> and the <code>f</code> ensures that CMake gets
re-run so that the option is honored.</p>
<p>Next, set an environment variable as follows. In Windows, use <code>set</code> instead of <code>export</code>.</p>
<pre><code>export FILAMENT_FGVIEWER_PORT=8050
</code></pre>
<p>Next, launch any app that links against a debug build of a Filament and point your web browser to
http://localhost:8050. Skip ahead to <strong>Debugger Usage</strong>.</p>
<h2 id="setup-for-android"><a class="header" href="#setup-for-android">Setup for Android</a></h2>
<p>Rebuild Filament for Android after enabling a CMake option called <code>FILAMENT_ENABLE_FGVIEWER</code>. Note that
CMake is invoked from several places for Android (both gradle and our easy build script), so one
pragmatic and reliable way of doing this is to simply hack <code>CMakeLists.txt</code> and
<code>filament-android/CMakeLists.txt</code> by unconditionally setting <code>FILAMENT_ENABLE_FGVIEWER</code> to <code>ON</code>.</p>
<p>After rebuilding Filament with the option enabled, ensure that internet permissions are enabled in
your app by adding the following into your manifest as a child of the <code>&lt;manifest&gt;</code> element.</p>
<pre><code>&lt;uses-permission android:name="android.permission.INTERNET" /&gt;
</code></pre>
<p>Now launch your app as usual. The Filament Engine sets up a server that is hardcoded to listen to
port <code>8085</code>. Next, you will need to forward your device's TCP port <code>8085</code> to your host port of choice.
For example, to forward the fgviewer server on your device to port <code>8085</code> on your host machine, do the
following:</p>
<pre><code>adb forward tcp:8085 tcp:8085
</code></pre>
<p>This lets you go to http://localhost:8085 in Chrome on your host machine.</p>
<h2 id="debugger-usage"><a class="header" href="#debugger-usage">Debugger Usage</a></h2>
<p>After opening the fgviewer page in your browser, you can see the active views are on the left panel.
Then you can select any of them to see the active passes and resources for that view.</p>
<p align="center">
<img width="600px" src=https://github.com/user-attachments/assets/2d31767f-fc25-4f17-8c14-528fe5c6b698>
</p>
<h2 id="architecture-overview"><a class="header" href="#architecture-overview">Architecture Overview</a></h2>
<p align="center">
<img width="450" src=https://github.com/user-attachments/assets/537ebb89-6ad0-4b93-bbeb-207d4fe9ec5a>
</p>
<p>The fgviewer library has two parts: a C++ server and a JavaScript client. The C++ server is
responsible for instancing a <a href="https://github.com/civetweb/civetweb">civetweb</a> context that handles HTTP requests. The
JavaScript client is a small web app that contains a view into an in-browser database of framegraphs.</p>
<p>When a new connection is established, the client asks the server for a list of framegraphs
in order to populate its in-browser database. If the connection is lost (e.g. if the app crashes),
then the database stays intact and the web app is still functional.</p>
<h2 id="c-server"><a class="header" href="#c-server">C++ Server</a></h2>
<p>The civetweb server is wrapped by our <code>DebugServer</code> class, which provides a public interface consisting of
a few methods invoked by the Filament engine.</p>
<p>Since each view corresponds to a frame graph, the engine should notify <code>DebugServer</code> of any changes to the views
on the engine side.</p>
<ul>
<li><strong>createView</strong> Notifies the debugger that a new view has been created.</li>
<li><strong>updateView</strong> Notifies the debugger of updates to an existing view.</li>
<li><strong>destroyView</strong> Notifies the debugger that a view is being removed.</li>
</ul>
<h2 id="javascript-client"><a class="header" href="#javascript-client">JavaScript Client</a></h2>
<p>The web app is built using LitElement, a lightweight library for creating Web Components. Our goal is to keep the code simple and modern, avoiding frameworks like React or Angular.</p>
<p>The app presents a view over a pseudo-database, which is essentially a global variable holding a dictionary that maps frame graph ids to objects following the JSON structure described below.</p>
<h2 id="http-requests"><a class="header" href="#http-requests">HTTP requests</a></h2>
<p>The server responds to the following GET requests by returning a JSON blob. The <code>{id}</code> in these
requests is a concept specific to fgviewer (not Filament) which is an 8-digit hex string for identifying frame graphs.</p>
<hr />
<p><code>/api/framegraphs</code></p>
<p>Returns an array containing all framegraphs in an app. Example:</p>
<pre><code class="language-json">[{
"fgid": "00000000",
"viewName": "Main View",
"passes": [{
"name": "shadow pass",
"reads": [],
"writes": ["0"]
}],
"resources": [{
"id": "0",
"name": "shadowmap",
"properties": [{"resolution": "256x256"}, {"is_subresource": "false"}]
}]
},
{
"fgid": "00000001",
"viewName": "UI view",
...
}]
</code></pre>
<hr />
<p><code>/api/framegraph?fg={id}</code></p>
<p>Returns a specific framegraph info. Example:</p>
<pre><code class="language-json">{
"fgid": "00000000",
"viewName": "Main View",
"passes": [{
"name": "shadow pass",
"reads": [],
"writes": ["0"]
}],
"resources": [{
"id": "0",
"name": "shadowmap",
"properties": [{"resolution": "256x256"}, {"is_subresource": "false"}]
}]
}
</code></pre>
<hr />
<p><code>/api/status</code></p>
<p>Returns one of the below:</p>
<ul>
<li><code>0</code>: first time connected</li>
<li><code>1</code>: no-op</li>
<li><code>{fgid}</code>: the corresponding frame graph has an update
<ul>
<li>Then the web view can request for the actual info using the previous api</li>
</ul>
</li>
</ul>
<p>If the request gets timeout, the web page show disconnected to the user.</p>
<hr />
<h2 id="wish-list"><a class="header" href="#wish-list">Wish List</a></h2>
<ul>
<li>Display the texture contents on the webview</li>
</ul>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../dup/bluevk.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/filamat.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="../dup/bluevk.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/filamat.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>