Compare commits

..
140 changed files with 3848 additions and 2544 deletions
+6 -1
View File
@@ -22,6 +22,7 @@ project(TNT)
option(FILAMENT_USE_EXTERNAL_GLES3 "Experimental: Compile Filament against OpenGL ES 3" OFF)
option(FILAMENT_ENABLE_LTO "Enable link-time optimizations if supported by the compiler" OFF)
option(FILAMENT_SKIP_SAMPLES "Don't build samples" OFF)
option(FILAMENT_SUPPORTS_XCB "Include XCB support in Linux builds" ON)
@@ -286,6 +287,9 @@ set(FILAMENT ${CMAKE_CURRENT_SOURCE_DIR})
# Where our tools are
set(TOOLS ${CMAKE_CURRENT_SOURCE_DIR}/tools)
# Where our tools are
set(TESTS ${CMAKE_CURRENT_SOURCE_DIR}/test)
# ==================================================================================================
# Compiler check
# ==================================================================================================
@@ -870,7 +874,6 @@ if (IS_HOST_PLATFORM)
add_subdirectory(${LIBRARIES}/filamentapp)
endif()
add_subdirectory(${LIBRARIES}/imageio)
add_subdirectory(${LIBRARIES}/filament-matp)
add_subdirectory(${FILAMENT}/samples)
@@ -896,6 +899,8 @@ if (IS_HOST_PLATFORM)
add_subdirectory(${TOOLS}/roughness-prefilter)
add_subdirectory(${TOOLS}/specular-color)
add_subdirectory(${TOOLS}/uberz)
add_subdirectory(${TESTS}/gltf-comparison)
endif()
# Generate exported executables for cross-compiled builds (Android, WebGL, and iOS)
+3
View File
@@ -7,3 +7,6 @@ We are chaning the way Vulkan buffers are handled. We need to switch over to a m
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut
- Rename `sampler` parameter `unfilterable` to `filterable` [⚠️ **New Material Version**]
- Added `Renderer::shouldRenderFrame()`
+2 -3
View File
@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.63.1'
implementation 'com.google.android.filament:filament-android:1.62.1'
}
```
@@ -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.63.1'
pod 'Filament', '~> 1.62.1'
```
## Documentation
@@ -331,7 +331,6 @@ and tools.
- `filamesh`: Mesh converter
- `glslminifier`: Minifies GLSL source code
- `matc`: Material compiler
- `filament-matp`: Material parser
- `matinfo` Displays information about materials compiled with `matc`
- `mipgen` Generates a series of miplevels from a source image
- `normal-blending`: Tool to blend normal maps
-8
View File
@@ -7,14 +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.63.1
## v1.63.0
- Rename `sampler` parameter `unfilterable` to `filterable` [⚠️ **New Material Version**]
- Added `Renderer::shouldRenderFrame()`
## v1.62.2
- Metal: fix, respect alpha to coverage rasterization
+1 -1
View File
@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.63.1
VERSION_NAME=1.62.1
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
+1 -1
View File
@@ -5,7 +5,7 @@ libs/math/test_math
libs/image/test_image compare libs/image/tests/reference/
libs/utils/test_utils
libs/filamat/test_filamat
libs/filament-matp/test_matp
tools/matc/test_matc
tools/cmgen/test_cmgen compare
tools/glslminifier/test_glslminifier
libs/filameshio/test_filameshio
+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.62.2'
implementation 'com.google.android.filament:filament-android:1.62.1'
}
</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.62.2'
<pre><code class="language-shell">pod 'Filament', '~&gt; 1.62.1'
</code></pre>
<h2 id="documentation"><a class="header" href="#documentation">Documentation</a></h2>
<ul>
+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.62.2'
implementation 'com.google.android.filament:filament-android:1.62.1'
}
</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.62.2'
<pre><code class="language-shell">pod 'Filament', '~&gt; 1.62.1'
</code></pre>
<h2 id="documentation"><a class="header" href="#documentation">Documentation</a></h2>
<ul>
+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
@@ -87,8 +87,6 @@ public:
void gc();
void resetCachedState() noexcept { mLastBoundInfo = {}; }
private:
void updateSamplerImpl(VkDescriptorSet set, uint8_t binding,
fvkmemory::resource_ptr<VulkanTexture> texture, VkSampler sampler) noexcept;
@@ -2061,7 +2061,6 @@ void VulkanDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag
void VulkanDriver::endCommandRecording() {
mCommands.flush();
mPipelineCache.resetBoundPipeline();
mDescriptorSetCache.resetCachedState();
}
// explicit instantiation of the Dispatcher
+107 -237
View File
@@ -18,7 +18,6 @@
#include "WebGPUConstants.h"
#include "WebGPUStrings.h"
#include "WebGPUTextureHelpers.h"
#include "webgpu/utils/StringPlaceholderTemplateProcessor.h"
#include <backend/DriverEnums.h>
@@ -38,32 +37,6 @@ namespace filament::backend {
namespace {
/**
* @return true if copyToTextureToTexture validation would succeed and we could use that for the
* "blit"
* ( see https://www.w3.org/TR/webgpu/#dom-gpucommandencoder-copytexturetotexture )
* NOTE: this does not validate usage of the source and/or destination.
* If canDoDirectCopy(...) == true and the textures don't have the appropriate usages
* we should panic (we should not be doing a renderpass blit when we could have been
* doing a direct copy)
*/
[[nodiscard]] constexpr bool canDoDirectCopy(const uint32_t sourceSampleCount,
const wgpu::TextureFormat sourceFormat, const wgpu::Origin2D sourceOrigin,
const wgpu::Extent2D sourceExtent, const uint32_t destinationSampleCount,
const wgpu::TextureFormat destinationFormat, const wgpu::Origin2D destinationOrigin,
const wgpu::Extent2D destinationExtent) {
const wgpu::Extent2D sourceBlockSize{ getBlockSize(sourceFormat) };
const wgpu::Extent2D destinationBlockSize{ getBlockSize(destinationFormat) };
return sourceSampleCount == destinationSampleCount &&
areCopyCompatible(sourceFormat, destinationFormat) &&
(sourceExtent.width == destinationExtent.width) &&
(sourceExtent.height == destinationExtent.height) &&
((sourceOrigin.x & sourceBlockSize.width) == 0) &&
((sourceOrigin.y & sourceBlockSize.height) == 0) &&
((destinationOrigin.x & destinationBlockSize.width) == 0) &&
((destinationOrigin.y & destinationBlockSize.height) == 0);
}
struct BlitFragmentShaderArgs final {
uint32_t depthPlane{ 0 };
uint32_t padding{ 0 }; // Add 4 bytes of padding to align the vec2 members
@@ -88,18 +61,11 @@ constexpr std::string_view FRAGMENT_SHADER_ENTRY_POINT{ "fragmentShaderMain" };
// otherwise be present in the template:
constexpr std::string_view PLACEHOLDER_PREFIX{ "{{" };
constexpr std::string_view PLACEHOLDER_SUFFIX{ "}}" };
// texture_2d<f32> or texture_multisampled_2d<f32> or texture_3d<f32> or
// texture_depth_2d or texture_depth_multisampled_2d
// texture_2d<f32> or texture_multisampled_2d<f32> or texture_3d<f32>
constexpr std::string_view TEXTURE_TYPE_PLACEHOLDER{ "TEXTURE_TYPE" };
// texture_2d<f32> or texture_depth_2d
[[maybe_unused]] constexpr std::string_view TEXTURE_2D_TYPE_PLACEHOLDER { "TEXTURE_2D_TYPE" };
// "" for no sampler, otherwise "@group(0) @binding(2) var sourceSampler: sampler;"
constexpr std::string_view SAMPLER_DECLARATION_PLACEHOLDER{ "SAMPLER_DECLARATION" };
constexpr std::string_view FRAGMENT_SHADER_SNIPPET_PLACEHOLDER{ "FRAGMENT_SHADER_SNIPPET" };
// @location(0) vec4<f32> or @builtin(frag_depth) f32
constexpr std::string_view FRAGMENT_RETURN_ATTRIBUTE_AND_TYPE_PLACEHOLDER{
"FRAGMENT_RETURN_ATTRIBUTE_AND_TYPE"
};
constexpr std::string_view SHADER_SOURCE_TEMPLATE{ R"(
struct BlitFragmentShaderArgs {
depthPlane: u32,
@@ -129,7 +95,7 @@ constexpr std::string_view SHADER_SOURCE_TEMPLATE{ R"(
fn getNormalized2dSourceTextureCoordinates(
position: vec2<f32>,
sourceTexture: {{TEXTURE_2D_TYPE}}) -> vec2<f32> {
sourceTexture: texture_2d<f32>) -> vec2<f32> {
let sourceDimensions: vec2<u32> = textureDimensions(sourceTexture);
return normalize2dSourceTextureCoordinates(
getUnnormalizedSourceTextureCoordinates(position),
@@ -173,9 +139,9 @@ constexpr std::string_view SHADER_SOURCE_TEMPLATE{ R"(
{{FRAGMENT_SHADER_SNIPPET}}
)" };
constexpr std::string_view FRAGMENT_SHADER_SNIPPET_MSAA_INPUT_TEMPLATE{ R"(
constexpr std::string_view FRAGMENT_SHADER_SNIPPET_MSAA_INPUT{ R"(
@fragment
fn fragmentShaderMain(@builtin(position) position: vec4<f32>) -> {{FRAGMENT_RETURN_ATTRIBUTE_AND_TYPE}} {
fn fragmentShaderMain(@builtin(position) position: vec4<f32>) -> @location(0) vec4<f32> {
var color: vec4<f32> = vec4<f32>(0.0, 0.0, 0.0, 0.0);
let numberOfSamples: u32 = textureNumSamples(sourceTexture);
let coordinatesF: vec2<f32> = getUnnormalizedSourceTextureCoordinates(position.xy);
@@ -188,17 +154,17 @@ constexpr std::string_view FRAGMENT_SHADER_SNIPPET_MSAA_INPUT_TEMPLATE{ R"(
}
)" };
constexpr std::string_view FRAGMENT_SHADER_SNIPPET_3D_INPUT_TEMPLATE{ R"(
constexpr std::string_view FRAGMENT_SHADER_SNIPPET_3D_INPUT{ R"(
@fragment
fn fragmentShaderMain(@builtin(position) position: vec4<f32>) -> {{FRAGMENT_RETURN_ATTRIBUTE_AND_TYPE}} {
fn fragmentShaderMain(@builtin(position) position: vec4<f32>) -> @location(0) vec4<f32> {
let coordinates: vec3<f32> = getNormalized3dSourceTextureCoordinates(position.xy, sourceTexture);
return textureSample(sourceTexture, sourceSampler, coordinates);
}
)" };
constexpr std::string_view FRAGMENT_SHADER_SNIPPET_2D_INPUT_TEMPLATE{ R"(
constexpr std::string_view FRAGMENT_SHADER_SNIPPET_2D_INPUT{ R"(
@fragment
fn fragmentShaderMain(@builtin(position) position: vec4<f32>) -> {{FRAGMENT_RETURN_ATTRIBUTE_AND_TYPE}} {
fn fragmentShaderMain(@builtin(position) position: vec4<f32>) -> @location(0) vec4<f32> {
let coordinates: vec2<f32> = getNormalized2dSourceTextureCoordinates(position.xy, sourceTexture);
return textureSample(sourceTexture, sourceSampler, coordinates);
}
@@ -233,24 +199,39 @@ void WebGPUBlitter::blit(wgpu::Queue const& queue, wgpu::CommandEncoder const& c
// time no major known graphics API supports this, including WebGPU. Furthermore, the Metal
// blitter does not support this either.
const bool willDirectCopy{ canDoDirectCopy(args.source.texture.GetSampleCount(),
args.source.texture.GetFormat(), args.source.origin, args.source.extent,
args.destination.texture.GetSampleCount(), args.destination.texture.GetFormat(),
args.destination.origin, args.destination.extent) };
#if FWGPU_ENABLED(FWGPU_DEBUG_BLIT)
FWGPU_LOGD << "ABOUT to blit using " << (willDirectCopy ? "copy-texture-to-texture" : "renderpass");
// TODO REMOVE (keeping for troubleshooting/debug purposes for now)
#if FWGPU_ENABLED(FWGPU_DEBUG_VALIDATION)
FWGPU_LOGD << "ABOUT to blit:";
FWGPU_LOGD << " Source:";
FWGPU_LOGD << " " << webGPUTextureToString(args.source.texture);
FWGPU_LOGD << " aspect: " << webGPUPrintableToString(args.source.aspect);
FWGPU_LOGD << " texture:" << webGPUPrintableToString(args.source.texture.GetFormat());
FWGPU_LOGD << " depthOrArrayLayers: " << args.source.texture.GetDepthOrArrayLayers();
FWGPU_LOGD << " " << webGPUPrintableToString(args.source.texture.GetDimension());
FWGPU_LOGD << " format: " << webGPUTextureFormatToString(args.source.texture.GetFormat());
FWGPU_LOGD << " height: " << args.source.texture.GetHeight();
FWGPU_LOGD << " mipLevelCount: " << args.source.texture.GetMipLevelCount();
FWGPU_LOGD << " sampleCount: " << args.source.texture.GetSampleCount();
FWGPU_LOGD << " " << webGPUPrintableToString(args.source.texture.GetUsage());
FWGPU_LOGD << " width: " << args.source.texture.GetWidth();
FWGPU_LOGD << " origin: x: " << args.source.origin.x << " y: " << args.source.origin.y;
FWGPU_LOGD << " extent: width: " << args.source.extent.width << " height: " << args.source.extent.height;
FWGPU_LOGD << " extent: width: " << args.source.extent.width
<< " height: " << args.source.extent.height;
FWGPU_LOGD << " mipLevel: " << args.source.mipLevel;
FWGPU_LOGD << " layerOrDepth: " << args.source.layerOrDepth;
FWGPU_LOGD << " Destination:";
FWGPU_LOGD << " " << webGPUTextureToString(args.destination.texture);
FWGPU_LOGD << " aspect: " << webGPUPrintableToString(args.destination.aspect);
FWGPU_LOGD << " origin: x: " << args.destination.origin.x << " y: " << args.destination.origin.y;
FWGPU_LOGD << " extent: width: " << args.destination.extent.width << " height: " << args.destination.extent.height;
FWGPU_LOGD << " texture:" << webGPUPrintableToString(args.destination.texture.GetFormat());
FWGPU_LOGD << " depthOrArrayLayers: " << args.destination.texture.GetDepthOrArrayLayers();
FWGPU_LOGD << " " << webGPUPrintableToString(args.destination.texture.GetDimension());
FWGPU_LOGD << " format: "
<< webGPUTextureFormatToString(args.destination.texture.GetFormat());
FWGPU_LOGD << " height: " << args.destination.texture.GetHeight();
FWGPU_LOGD << " mipLevelCount: " << args.destination.texture.GetMipLevelCount();
FWGPU_LOGD << " sampleCount: " << args.destination.texture.GetSampleCount();
FWGPU_LOGD << " " << webGPUPrintableToString(args.destination.texture.GetUsage());
FWGPU_LOGD << " width: " << args.destination.texture.GetWidth();
FWGPU_LOGD << " origin: x: " << args.destination.origin.x
<< " y: " << args.destination.origin.y;
FWGPU_LOGD << " extent: width: " << args.destination.extent.width
<< " height: " << args.destination.extent.height;
FWGPU_LOGD << " mipLevel: " << args.destination.mipLevel;
FWGPU_LOGD << " layerOrDepth: " << args.destination.layerOrDepth;
FWGPU_LOGD << " filter: " << (args.filter == SamplerMagFilter::NEAREST ? "NEAREST" : "LINEAR");
@@ -259,18 +240,6 @@ void WebGPUBlitter::blit(wgpu::Queue const& queue, wgpu::CommandEncoder const& c
args.source.texture.GetSampleCount() == 1)
<< "Multispampled 3D textures are not supported (the source 3D texture was configured "
"for multisampling) (this should not be possible?)";
if (willDirectCopy) {
FILAMENT_CHECK_PRECONDITION(args.source.texture.GetUsage() & wgpu::TextureUsage::CopySrc)
<< "source texture usage doesn't have wgpu::TextureUsage::CopySrc";
FILAMENT_CHECK_PRECONDITION(
args.destination.texture.GetUsage() & wgpu::TextureUsage::CopyDst)
<< "destination texture usage doesn't have wgpu::TextureUsage::CopyDst";
copy(commandEncoder, args);
return;
}
// need to do a render pass blit...
FILAMENT_CHECK_PRECONDITION(args.destination.texture.GetSampleCount() == 1)
<< "Blitting does not currently support writing to multisampled output textures.";
@@ -297,7 +266,7 @@ void WebGPUBlitter::blit(wgpu::Queue const& queue, wgpu::CommandEncoder const& c
? 1
: args.source.layerOrDepth,
.arrayLayerCount = 1,
.aspect = args.source.aspect,
.aspect = wgpu::TextureAspect::All,
.usage = wgpu::TextureUsage::TextureBinding,
};
const wgpu::TextureView sourceView{ args.source.texture.CreateView(&sourceViewDescriptor) };
@@ -317,7 +286,7 @@ void WebGPUBlitter::blit(wgpu::Queue const& queue, wgpu::CommandEncoder const& c
? 1
: args.destination.layerOrDepth,
.arrayLayerCount = 1,
.aspect = args.destination.aspect,
.aspect = wgpu::TextureAspect::All,
.usage = wgpu::TextureUsage::RenderAttachment,
};
const wgpu::TextureView destinationView{ args.destination.texture.CreateView(
@@ -384,91 +353,50 @@ void WebGPUBlitter::blit(wgpu::Queue const& queue, wgpu::CommandEncoder const& c
.sampler = sampler, // note: might be nullptr if we don't need it
}
};
const bool multisampledSource{ args.source.texture.GetSampleCount() > 1 };
const bool depthSource{ hasDepth(args.source.texture.GetFormat()) };
const bool depthDestination{ hasDepth(args.destination.texture.GetFormat()) };
const wgpu::BindGroupDescriptor textureBindGroupDescriptor{
.label = "blit_texture_bind_group",
.layout = getOrCreateTextureBindGroupLayout(args.filter, sourceDimension,
multisampledSource, depthSource),
args.source.texture.GetSampleCount() > 1),
.entryCount = textureBindGroupEntriesCount,
.entries = textureBindGroupEntries,
};
const wgpu::BindGroup textureBindGroup{ mDevice.CreateBindGroup(&textureBindGroupDescriptor) };
FILAMENT_CHECK_POSTCONDITION(textureBindGroup)
<< "Failed to create texture bind group for render pass blit?";
// create color or depth attachment (output)...
wgpu::RenderPassDescriptor renderPassDescriptor{
// create color attachment (output)...
const wgpu::RenderPassColorAttachment colorAttachment{
.view = destinationView,
.depthSlice = args.destination.texture.GetDimension() == wgpu::TextureDimension::e3D
? args.destination.layerOrDepth
: wgpu::kDepthSliceUndefined,
// we don't need this resolveTarget because we are doing a resolve in software (the shader),
// but we probably should (leveraging a msaa sidecar texture) to take advantage of
// hardware acceleration. Thus, this might be an opportunity for optimization
.resolveTarget = nullptr,
.loadOp = wgpu::LoadOp::Clear,
.storeOp = wgpu::StoreOp::Store,
.clearValue = { .r = 0.0, .g = 0.0, .b = 0.0, .a = 1.0 },
};
const wgpu::RenderPassDescriptor renderPassDescriptor{
.label = "blit_render_pass",
.colorAttachmentCount = 0, // updated if non-depth destination
.colorAttachments = nullptr, // updated if non-depth destination
.depthStencilAttachment = nullptr, // updated if depth destination
.colorAttachmentCount = 1,
.colorAttachments = &colorAttachment,
.depthStencilAttachment = nullptr, // not applicable
.occlusionQuerySet = nullptr, // not applicable
.timestampWrites = nullptr, // not applicable
};
if (depthDestination) {
const wgpu::RenderPassDepthStencilAttachment depthStencilAttachment{
.view = destinationView,
.depthLoadOp = wgpu::LoadOp::Clear,
.depthStoreOp = wgpu::StoreOp::Store,
.depthClearValue = 0.0f, // explicitly defining for consistency
.depthReadOnly = false,
.stencilLoadOp = wgpu::LoadOp::Undefined, // stencil not supported
.stencilStoreOp = wgpu::StoreOp::Undefined, // stencil not supported
};
renderPassDescriptor.depthStencilAttachment = &depthStencilAttachment;
} else {
// color destination...
const wgpu::RenderPassColorAttachment colorAttachment{
.view = destinationView,
.depthSlice = args.destination.texture.GetDimension() == wgpu::TextureDimension::e3D
? args.destination.layerOrDepth
: wgpu::kDepthSliceUndefined,
// we don't need this resolveTarget because we are doing a resolve in software (the
// shader), but we probably should (leveraging a msaa sidecar texture) to take advantage
// of hardware acceleration. Thus, this might be an opportunity for optimization
.resolveTarget = nullptr,
.loadOp = wgpu::LoadOp::Clear,
.storeOp = wgpu::StoreOp::Store,
.clearValue = { .r = 0.0, .g = 0.0, .b = 0.0, .a = 1.0 },
};
renderPassDescriptor.colorAttachmentCount = 1;
renderPassDescriptor.colorAttachments = &colorAttachment;
}
const wgpu::RenderPassEncoder renderPassEncoder{ commandEncoder.BeginRenderPass(
&renderPassDescriptor) };
FILAMENT_CHECK_POSTCONDITION(renderPassEncoder)
<< "Failed to create render pass encoder for blit?";
renderPassEncoder.SetPipeline(getOrCreateRenderPipeline(args.filter, sourceDimension,
args.source.texture.GetSampleCount(), depthSource,
args.destination.texture.GetFormat()));
args.source.texture.GetSampleCount(), args.destination.texture.GetFormat()));
renderPassEncoder.SetBindGroup(TEXTURE_BIND_GROUP_INDEX, textureBindGroup);
renderPassEncoder.Draw(3); // draw the full-screen triangle
// with hard-coded vertices in the shader
renderPassEncoder.End();
}
void WebGPUBlitter::copy(wgpu::CommandEncoder const& commandEncoder, BlitArgs const& args) {
const wgpu::TexelCopyTextureInfo sourceCopyInfo{
.texture = args.source.texture,
.mipLevel = args.source.mipLevel,
.origin = { args.source.origin.x, args.source.origin.y, args.source.layerOrDepth },
.aspect = args.source.aspect,
};
const wgpu::TexelCopyTextureInfo destinationCopyInfo{
.texture = args.destination.texture,
.mipLevel = args.destination.mipLevel,
.origin = {
args.destination.origin.x,
args.destination.origin.y,
args.destination.layerOrDepth,
},
.aspect = args.destination.aspect,
};
const wgpu::Extent3D copySize{ args.source.extent.width, args.source.extent.height, 1 };
commandEncoder.CopyTextureToTexture(&sourceCopyInfo, &destinationCopyInfo, &copySize);
}
void WebGPUBlitter::createSampler(const SamplerMagFilter filter) {
wgpu::StringView label;
wgpu::FilterMode magFilter;
@@ -518,40 +446,32 @@ void WebGPUBlitter::createSampler(const SamplerMagFilter filter) {
wgpu::RenderPipeline const& WebGPUBlitter::getOrCreateRenderPipeline(
const SamplerMagFilter filterType, const wgpu::TextureViewDimension sourceDimension,
const uint32_t sourceSampleCount, const bool depthSource,
const wgpu::TextureFormat destinationTextureFormat) {
const size_t key{ hashRenderPipelineKey(filterType, sourceDimension, sourceSampleCount,
depthSource, destinationTextureFormat) };
const uint32_t sourceSampleCount, const wgpu::TextureFormat destinationTextureFormat) {
const size_t key{ hashRenderPipelineKey(filterType, sourceDimension, sourceSampleCount) };
if (mRenderPipelines.find(key) == mRenderPipelines.end()) {
mRenderPipelines[key] = createRenderPipeline(filterType, sourceDimension, sourceSampleCount,
depthSource, destinationTextureFormat);
destinationTextureFormat);
}
return mRenderPipelines[key];
}
wgpu::RenderPipeline WebGPUBlitter::createRenderPipeline(const SamplerMagFilter filterType,
const wgpu::TextureViewDimension sourceDimension, const uint32_t sourceSampleCount,
const bool depthSource, const wgpu::TextureFormat destinationTextureFormat) {
const bool depthDestination{ hasDepth(destinationTextureFormat) };
const wgpu::TextureFormat destinationTextureFormat) {
const wgpu::ColorTargetState colorTargetState{ .format = destinationTextureFormat };
const wgpu::DepthStencilState depthStencilState{
.format = destinationTextureFormat,
.depthWriteEnabled = true,
.depthCompare = wgpu::CompareFunction::Always,
};
wgpu::ShaderModule const& shaderModule{ getOrCreateShaderModule(sourceDimension,
sourceSampleCount > 1, depthSource, hasDepth(destinationTextureFormat)) };
sourceSampleCount > 1) };
const wgpu::FragmentState fragmentState{
.module = shaderModule,
.entryPoint = FRAGMENT_SHADER_ENTRY_POINT,
.constantCount = 0, // should not matter, just being consistently defined
.constants = nullptr, // should not matter, just being consistently defined
.targetCount = depthDestination ? 0u : 1u,
.targets = depthDestination ? nullptr : &colorTargetState,
.targetCount = 1,
.targets = &colorTargetState,
};
const wgpu::RenderPipelineDescriptor pipelineDescriptor{
.label = "render_pass_blit_pipeline",
.layout = getOrCreatePipelineLayout(filterType, sourceDimension, sourceSampleCount > 1, depthSource),
.layout = getOrCreatePipelineLayout(filterType, sourceDimension, sourceSampleCount > 1),
.vertex = {
.module = shaderModule,
.entryPoint = VERTEX_SHADER_ENTRY_POINT,
@@ -571,7 +491,8 @@ wgpu::RenderPipeline WebGPUBlitter::createRenderPipeline(const SamplerMagFilter
.cullMode = wgpu::CullMode::None,
.unclippedDepth = false, // should not matter, just being consistently defined
},
.depthStencil = depthDestination ? &depthStencilState : nullptr,
.depthStencil = nullptr, // not applicable, but explicitly set here for
// consistent definition
.multisample = {
.count = sourceSampleCount,
.mask = 0xFFFFFFFF,
@@ -585,36 +506,31 @@ wgpu::RenderPipeline WebGPUBlitter::createRenderPipeline(const SamplerMagFilter
}
size_t WebGPUBlitter::hashRenderPipelineKey(const SamplerMagFilter filterType,
const wgpu::TextureViewDimension sourceDimension, const uint32_t sourceSampleCount,
const bool depthSource, const wgpu::TextureFormat destinationTextureFormat) {
const wgpu::TextureViewDimension sourceDimension, const uint32_t sourceSampleCount) {
size_t seed{ std::hash<uint8_t>{}(static_cast<uint8_t>(filterType)) };
utils::hash::combine(seed, static_cast<uint32_t>(sourceDimension));
utils::hash::combine(seed, sourceSampleCount);
utils::hash::combine(seed, depthSource);
utils::hash::combine(seed, static_cast<uint32_t>(destinationTextureFormat));
return seed;
}
wgpu::PipelineLayout const& WebGPUBlitter::getOrCreatePipelineLayout(
const SamplerMagFilter filterType, const wgpu::TextureViewDimension sourceDimension,
const bool multisampledSource, const bool depthSource) {
const size_t key{ hashPipelineLayoutKey(filterType, sourceDimension, multisampledSource,
depthSource) };
const bool multisampledSource) {
const size_t key{ hashPipelineLayoutKey(filterType, sourceDimension, multisampledSource) };
if (mPipelineLayouts.find(key) == mPipelineLayouts.end()) {
mPipelineLayouts[key] =
createPipelineLayout(filterType, sourceDimension, multisampledSource, depthSource);
createPipelineLayout(filterType, sourceDimension, multisampledSource);
}
return mPipelineLayouts[key];
}
wgpu::PipelineLayout WebGPUBlitter::createPipelineLayout(const SamplerMagFilter filterType,
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource,
const bool depthSource) {
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource) {
const wgpu::PipelineLayoutDescriptor pipelineLayoutDescriptor{
.label = "render_pass_blit_pipeline_layout",
.bindGroupLayoutCount = 1,
.bindGroupLayouts = &getOrCreateTextureBindGroupLayout(filterType, sourceDimension,
multisampledSource, depthSource),
.bindGroupLayouts =
&getOrCreateTextureBindGroupLayout(filterType, sourceDimension, multisampledSource),
};
const wgpu::PipelineLayout pipelineLayout{ mDevice.CreatePipelineLayout(
&pipelineLayoutDescriptor) };
@@ -624,42 +540,36 @@ wgpu::PipelineLayout WebGPUBlitter::createPipelineLayout(const SamplerMagFilter
}
size_t WebGPUBlitter::hashPipelineLayoutKey(const SamplerMagFilter filterType,
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource,
const bool depthSource) {
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource) {
size_t seed{ std::hash<uint8_t>{}(static_cast<uint8_t>(filterType)) };
utils::hash::combine(seed, static_cast<uint32_t>(sourceDimension));
utils::hash::combine(seed, multisampledSource);
utils::hash::combine(seed, depthSource);
return seed;
}
wgpu::BindGroupLayout const& WebGPUBlitter::getOrCreateTextureBindGroupLayout(
const SamplerMagFilter filterType, const wgpu::TextureViewDimension sourceDimension,
const bool multisampledSource, const bool depthSource) {
const size_t key{ hashTextureBindGroupLayoutKey(filterType, sourceDimension, multisampledSource,
depthSource) };
const bool multisampledSource) {
const size_t key{ hashTextureBindGroupLayoutKey(filterType, sourceDimension,
multisampledSource) };
if (mTextureBindGroupLayouts.find(key) == mTextureBindGroupLayouts.end()) {
mTextureBindGroupLayouts[key] = createTextureBindGroupLayout(filterType, sourceDimension,
multisampledSource, depthSource);
mTextureBindGroupLayouts[key] =
createTextureBindGroupLayout(filterType, sourceDimension, multisampledSource);
}
return mTextureBindGroupLayouts[key];
}
wgpu::BindGroupLayout WebGPUBlitter::createTextureBindGroupLayout(const SamplerMagFilter filterType,
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource,
const bool depthSource) {
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource) {
const wgpu::BindGroupLayoutEntry bindGroupLayoutEntries[MAX_TEXTURE_BIND_GROUP_ENTRY_SIZE] {
{
.binding = TEXTURE_BINDING_INDEX,
.visibility = wgpu::ShaderStage::Fragment,
.texture = {
.sampleType = depthSource
? wgpu::TextureSampleType::Depth
: wgpu::TextureSampleType::Float, // only F32 scalar sample
// type supported for now
// (aside from depth)
// see assumptions listed
// in blit function
.sampleType = wgpu::TextureSampleType::Float, // only F32 scalar sample
// type supported for now
// see assumptions listed
// in blit function
.viewDimension = sourceDimension,
.multisampled = multisampledSource,
},
@@ -698,85 +608,47 @@ wgpu::BindGroupLayout WebGPUBlitter::createTextureBindGroupLayout(const SamplerM
}
size_t WebGPUBlitter::hashTextureBindGroupLayoutKey(const SamplerMagFilter filterType,
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource,
const bool depthSource) {
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource) {
size_t seed{ std::hash<uint8_t>{}(static_cast<uint8_t>(filterType)) };
utils::hash::combine(seed, static_cast<uint32_t>(sourceDimension));
utils::hash::combine(seed, multisampledSource);
utils::hash::combine(seed, depthSource);
return seed;
}
wgpu::ShaderModule const& WebGPUBlitter::getOrCreateShaderModule(
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource,
const bool depthSource, const bool depthDestination) {
const size_t key{ hashShaderModuleKey(sourceDimension, multisampledSource, depthSource,
depthDestination) };
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource) {
const size_t key{ hashShaderModuleKey(sourceDimension, multisampledSource) };
if (mShaderModules.find(key) == mShaderModules.end()) {
mShaderModules[key] = createShaderModule(sourceDimension, multisampledSource, depthSource,
depthDestination);
mShaderModules[key] = createShaderModule(sourceDimension, multisampledSource);
}
return mShaderModules[key];
}
wgpu::ShaderModule WebGPUBlitter::createShaderModule(
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource,
const bool depthSource, const bool depthDestination) {
std::string_view textureType;
if (depthSource) {
if (multisampledSource) {
textureType = "texture_depth_multisampled_2d";
} else {
textureType = "texture_depth_2d";
}
} else {
// non-depth
if (multisampledSource) {
textureType = "texture_multisampled_2d";
} else {
if (sourceDimension == wgpu::TextureViewDimension::e3D) {
textureType = "texture_3d<f32>";
} else {
textureType = "texture_2d<f32>";
}
}
}
const std::string_view texture2dType{ depthSource ? "texture_depth_2d" : "texture_2d<f32>" };
// we don't declare a sampler in the shader or pipeline for the multisampled case
const wgpu::TextureViewDimension sourceDimension, const bool multisampledSource) {
const std::string_view textureType{
multisampledSource
? "texture_multisampled_2d<f32>"
: (sourceDimension == wgpu::TextureViewDimension::e3D ? "texture_3d<f32>"
: "texture_2d<f32>")
};
const std::string_view samplerDeclaration{
multisampledSource ? "" : "@group(0) @binding(2) var sourceSampler: sampler;"
};
const std::string_view fragmentReturnAttributeAndType{
depthDestination ? "@builtin(frag_depth) f32" : "@location(0) vec4<f32>"
const std::string_view fragmentShaderSnippet{
multisampledSource ? FRAGMENT_SHADER_SNIPPET_MSAA_INPUT
: (sourceDimension == wgpu::TextureViewDimension::e3D
? FRAGMENT_SHADER_SNIPPET_3D_INPUT
: FRAGMENT_SHADER_SNIPPET_2D_INPUT)
};
const std::unordered_map<std::string_view, std::string_view>
valueByPlaceholderNameForFragmentSnippet{
{ FRAGMENT_RETURN_ATTRIBUTE_AND_TYPE_PLACEHOLDER, fragmentReturnAttributeAndType },
};
std::string fragmentShaderSnippet;
if (multisampledSource) {
fragmentShaderSnippet = webgpuutils::processPlaceholderTemplate(
FRAGMENT_SHADER_SNIPPET_MSAA_INPUT_TEMPLATE, PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX,
valueByPlaceholderNameForFragmentSnippet);
} else {
if (sourceDimension == wgpu::TextureViewDimension::e3D) {
fragmentShaderSnippet = webgpuutils::processPlaceholderTemplate(
FRAGMENT_SHADER_SNIPPET_3D_INPUT_TEMPLATE, PLACEHOLDER_PREFIX,
PLACEHOLDER_SUFFIX, valueByPlaceholderNameForFragmentSnippet);
} else {
fragmentShaderSnippet = webgpuutils::processPlaceholderTemplate(
FRAGMENT_SHADER_SNIPPET_2D_INPUT_TEMPLATE, PLACEHOLDER_PREFIX,
PLACEHOLDER_SUFFIX, valueByPlaceholderNameForFragmentSnippet);
}
}
const std::unordered_map<std::string_view, std::string_view> valueByPlaceholderNameForModule{
std::unordered_map<std::string_view, std::string_view> valueByPlaceholderName{
{ TEXTURE_TYPE_PLACEHOLDER, textureType },
{ TEXTURE_2D_TYPE_PLACEHOLDER, texture2dType },
{ SAMPLER_DECLARATION_PLACEHOLDER, samplerDeclaration },
{ FRAGMENT_SHADER_SNIPPET_PLACEHOLDER, fragmentShaderSnippet },
{ FRAGMENT_SHADER_SNIPPET_PLACEHOLDER, fragmentShaderSnippet }
};
const std::string shaderSource{ webgpuutils::processPlaceholderTemplate(SHADER_SOURCE_TEMPLATE,
PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, valueByPlaceholderNameForModule) };
PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, valueByPlaceholderName) };
wgpu::ShaderModuleWGSLDescriptor wgslDescriptor{};
wgslDescriptor.code = shaderSource.data();
const wgpu::ShaderModuleDescriptor shaderModuleDescriptor{
@@ -790,11 +662,9 @@ wgpu::ShaderModule WebGPUBlitter::createShaderModule(
}
size_t WebGPUBlitter::hashShaderModuleKey(const wgpu::TextureViewDimension sourceDimension,
const bool multisampledSource, const bool depthSource, const bool depthDestination) {
const bool multisampledSource) {
size_t seed{ std::hash<uint32_t>{}(static_cast<uint32_t>(sourceDimension)) };
utils::hash::combine(seed, multisampledSource);
utils::hash::combine(seed, depthSource);
utils::hash::combine(seed, depthDestination);
return seed;
}
+12 -20
View File
@@ -31,7 +31,6 @@ public:
struct BlitArgs final {
struct Attachment final {
wgpu::Texture const& texture;
wgpu::TextureAspect aspect{ wgpu::TextureAspect::Undefined };
wgpu::Origin2D origin{};
wgpu::Extent2D extent{};
uint32_t mipLevel{ 0 };
@@ -48,52 +47,45 @@ public:
void blit(wgpu::Queue const&, wgpu::CommandEncoder const&, BlitArgs const&);
private:
/**
* ONLY should be called if canDoDirectCopy(...) is true (see it in WebGPUBlitter.cpp)
*/
void copy(wgpu::CommandEncoder const&, BlitArgs const&);
void createSampler(SamplerMagFilter);
[[nodiscard]] wgpu::RenderPipeline const& getOrCreateRenderPipeline(SamplerMagFilter,
wgpu::TextureViewDimension sourceDimension, uint32_t sourceSampleCount,
bool depthSource, wgpu::TextureFormat destinationTextureFormat);
wgpu::TextureFormat destinationTextureFormat);
[[nodiscard]] wgpu::RenderPipeline createRenderPipeline(SamplerMagFilter,
wgpu::TextureViewDimension sourceDimension, uint32_t sourceSampleCount,
bool depthSource, wgpu::TextureFormat destinationTextureFormat);
wgpu::TextureFormat destinationTextureFormat);
[[nodiscard]] static size_t hashRenderPipelineKey(SamplerMagFilter,
wgpu::TextureViewDimension sourceDimension, uint32_t sourceSampleCount,
bool depthSource, wgpu::TextureFormat destinationTextureFormat);
wgpu::TextureViewDimension sourceDimension, uint32_t sourceSampleCount);
[[nodiscard]] wgpu::PipelineLayout const& getOrCreatePipelineLayout(SamplerMagFilter,
wgpu::TextureViewDimension, bool multisampledSource, bool depthSource);
wgpu::TextureViewDimension, bool multisampledSource);
[[nodiscard]] wgpu::PipelineLayout createPipelineLayout(SamplerMagFilter,
wgpu::TextureViewDimension sourceDimension, bool multisampledSource, bool depthSource);
wgpu::TextureViewDimension sourceDimension, bool multisampledSource);
[[nodiscard]] static size_t hashPipelineLayoutKey(SamplerMagFilter,
wgpu::TextureViewDimension sourceDimension, bool multisampledSource, bool depthSource);
wgpu::TextureViewDimension sourceDimension, bool multisampledSource);
[[nodiscard]] wgpu::BindGroupLayout const& getOrCreateTextureBindGroupLayout(SamplerMagFilter,
wgpu::TextureViewDimension sourceDimension, bool multisampledSource, bool depthSource);
wgpu::TextureViewDimension sourceDimension, bool multisampledSource);
[[nodiscard]] wgpu::BindGroupLayout createTextureBindGroupLayout(SamplerMagFilter,
wgpu::TextureViewDimension sourceDimension, bool multisampledSource, bool depthSource);
wgpu::TextureViewDimension sourceDimension, bool multisampledSource);
[[nodiscard]] static size_t hashTextureBindGroupLayoutKey(SamplerMagFilter,
wgpu::TextureViewDimension sourceDimension, bool multisampledSource, bool depthSource);
wgpu::TextureViewDimension sourceDimension, bool multisampledSource);
[[nodiscard]] wgpu::ShaderModule const& getOrCreateShaderModule(
wgpu::TextureViewDimension sourceDimension, bool multisampledSource, bool depthSource,
bool depthDestination);
wgpu::TextureViewDimension sourceDimension, bool multisampledSource);
[[nodiscard]] wgpu::ShaderModule createShaderModule(wgpu::TextureViewDimension sourceDimension,
bool multisampledSource, bool depthSource, bool depthDestination);
bool multisampledSource);
[[nodiscard]] static size_t hashShaderModuleKey(wgpu::TextureViewDimension sourceDimension,
bool multisampledSource, bool depthSource, bool depthDestination);
bool multisampledSource);
wgpu::Device mDevice;
wgpu::Sampler mNearestSampler{ nullptr };
@@ -36,18 +36,6 @@ constexpr size_t FILAMENT_WEBGPU_BUFFER_SIZE_MODULUS = 4;
// appear in order of calls).
#define FWGPU_DEBUG_FORCE_LOG_TO_I 0x00000004
// Set this to enable logging related to the WebGPU backend's update3DImage function, which would
// otherwise spam the logs.
#define FWGPU_DEBUG_UPDATE_IMAGE 0x00000008
// Set this to enable logging related to the WebGPU backend's WebGPUBlitter functionality,
// which would otherwise spam the logs.
#define FWGPU_DEBUG_BLIT 0x00000010
// Set this to enable logging relating to bind groups (bind group layouts, bind groups themselves,
// textures, samplers, and buffers,...), which would otherwise spam the logs.
#define FWGPU_DEBUG_BIND_GROUPS 0x00000020
// Useful default combinations
#define FWGPU_DEBUG_EVERYTHING 0xFFFFFFFF
@@ -16,11 +16,7 @@
#include "WebGPUDescriptorSet.h"
#include "WebGPUConstants.h"
#include "WebGPUDescriptorSetLayout.h"
#if FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
#include "WebGPUStrings.h"
#endif
#include <backend/DriverEnums.h>
@@ -96,29 +92,6 @@ wgpu::BindGroup WebGPUDescriptorSet::lockAndReturn(wgpu::Device const& device) {
mBindGroup = device.CreateBindGroup(&descriptor);
FILAMENT_CHECK_POSTCONDITION(mBindGroup) << "Failed to create bind group?";
// once we have created the bind group itself we should no longer need any other state
#if FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
FWGPU_LOGD << "WebGPUDescriptorSet (lockAndReturn):";
FWGPU_LOGD << " wgpu::BindGroupLayout handle: " << mLayout.Get();
FWGPU_LOGD << " wgpu::BindGroup handle: " << mBindGroup.Get();
FWGPU_LOGD << " Entries with DynamicOffsets: " << mEntriesWithDynamicOffsetsCount;
FWGPU_LOGD << " Entries (" << mEntries.size() << "):";
for (wgpu::BindGroupEntry const& entry: mEntries) {
if (entry.buffer) {
FWGPU_LOGD << " binding:" << entry.binding << " buffer "
<< webGPUPrintableToString(entry.buffer.GetUsage())
<< " buffer size:" << entry.buffer.GetSize() << " offset:" << entry.offset
<< " size:" << (entry.size == wgpu::kWholeSize
? "Whole Size"
: ("Partial/specified Size (" + std::to_string(entry.size) + ")"));
}
if (entry.sampler) {
FWGPU_LOGD << " binding:" << entry.binding << " sampler";
}
if (entry.textureView) {
FWGPU_LOGD << " binding:" << entry.binding << " texture (view)";
}
}
#endif
mLayout = nullptr;
mEntries.clear();
mEntries.shrink_to_fit();
@@ -19,8 +19,6 @@
#include "WebGPUDescriptorSetLayout.h"
#include "WebGPUConstants.h"
#include "DriverBase.h"
#include <backend/DriverEnums.h>
@@ -51,10 +49,6 @@ public:
// May be nullptr. Use lockAndReturn to create the bind group when appropriate
[[nodiscard]] wgpu::BindGroup const& getBindGroup() const { return mBindGroup; }
#if FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
[[nodiscard]] wgpu::BindGroupLayout const& getLayout() const { return mLayout; }
#endif
private:
wgpu::BindGroupLayout mLayout = nullptr;
std::array<uint8_t, MAX_DESCRIPTOR_COUNT> mEntryIndexByBinding{};
@@ -16,11 +16,6 @@
#include "WebGPUDescriptorSetLayout.h"
#include "WebGPUConstants.h"
#if FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
#include "WebGPUStrings.h"
#endif
#include <backend/DriverEnums.h>
#include <utils/BitmaskEnum.h>
@@ -189,19 +184,6 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
mLayout = device.CreateBindGroupLayout(&layoutDescriptor);
FILAMENT_CHECK_POSTCONDITION(mLayout)
<< "Failed to create bind group layout with label " << label;
#if FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
FWGPU_LOGD << "WebGPUDescriptorSetLayout:";
FWGPU_LOGD << " label: " << label;
FWGPU_LOGD << " wgpu::BindGroupLayout handle: " << mLayout.Get();
FWGPU_LOGD << " Filament bindings (" << layout.bindings.size() << "):";
for (DescriptorSetLayoutBinding const& layoutBinding: layout.bindings) {
FWGPU_LOGD << " binding:" << +layoutBinding.binding
<< " type:" << filamentDescriptorTypeToString(layoutBinding.type)
<< " stageFlags:" << filamentStageFlagsToString(layoutBinding.stageFlags)
<< " flags:" << filamentDescriptorFlagsToString(layoutBinding.flags)
<< " count:" << layoutBinding.count;
}
#endif
}
} // namespace filament::backend
+52 -120
View File
@@ -16,7 +16,6 @@
#include "webgpu/WebGPUDriver.h"
#include "WebGPUBufferObject.h"
#include "WebGPUConstants.h"
#include "WebGPUDescriptorSet.h"
#include "WebGPUDescriptorSetLayout.h"
#include "WebGPUFence.h"
@@ -137,10 +136,6 @@ void WebGPUDriver::setPresentationTime(int64_t monotonic_clock_ns) {
void WebGPUDriver::endFrame(const uint32_t /* frameId */) {
mPipelineLayoutCache.onFrameEnd();
mPipelineCache.onFrameEnd();
for (size_t i = 0; i < MAX_DESCRIPTOR_SET_COUNT; i++) {
mCurrentDescriptorSets[i] = {};
}
}
void WebGPUDriver::flush(int) {
@@ -577,7 +572,7 @@ FenceStatus WebGPUDriver::getFenceStatus(Handle<HwFence> fenceHandle) {
// We create all textures using VK_IMAGE_TILING_OPTIMAL, so our definition of "supported" is that
// the GPU supports the given texture format with non-zero optimal tiling features.
bool WebGPUDriver::isTextureFormatSupported(const TextureFormat format) {
return toWGPUTextureFormat(format) != wgpu::TextureFormat::Undefined;
return WebGPUTexture::fToWGPUTextureFormat(format) != wgpu::TextureFormat::Undefined;
}
bool WebGPUDriver::isTextureSwizzleSupported() {
@@ -585,18 +580,18 @@ bool WebGPUDriver::isTextureSwizzleSupported() {
}
bool WebGPUDriver::isTextureFormatMipmappable(const TextureFormat format) {
const wgpu::TextureFormat webGpuFormat{ toWGPUTextureFormat(format) };
// passing 2D and sampleCount 1 to only check the format
const WebGPURenderPassMipmapGenerator::FormatCompatibility renderPassCompatibility{
WebGPURenderPassMipmapGenerator::getCompatibilityFor(webGpuFormat,
wgpu::TextureDimension::e2D, 1)
WebGPURenderPassMipmapGenerator::getCompatibilityFor(
WebGPUTexture::fToWGPUTextureFormat(format), wgpu::TextureDimension::e2D, 1)
};
if (renderPassCompatibility.compatible) {
return true;
}
return WebGPUTexture::supportsMultipleMipLevelsViaStorageBinding(webGpuFormat);
return WebGPUTexture::supportsMultipleMipLevelsViaStorageBinding(
WebGPUTexture::fToWGPUTextureFormat(format));
}
bool WebGPUDriver::isRenderTargetFormatSupported(const TextureFormat format) {
@@ -773,15 +768,16 @@ void WebGPUDriver::update3DImage(Handle<HwTexture> textureHandle, const uint32_t
scheduleDestroy(std::move(pixelBufferDescriptor));
return;
}
const wgpu::TextureFormat inputPixelFormat{ toWebGPUFormat(inputData->format,
inputData->type) };
const wgpu::TextureFormat outputLinearFormat{ toLinearFormat(
const wgpu::TextureFormat outputLinearFormat{ toWebGPULinearFormat(
texture->getTexture().GetFormat()) };
const bool conversionNecessary{
inputPixelFormat != outputLinearFormat && inputData->type != PixelDataType::COMPRESSED
}; // compressed formats should never need conversion
const bool doBlit{ conversionNecessary };
#if FWGPU_ENABLED(FWGPU_DEBUG_UPDATE_IMAGE)
#if FWGPU_ENABLED(FWGPU_DEBUG_VALIDATION)
if (texture->width > 1000 && texture->height > 500) {
FWGPU_LOGD << "Update3DImage(..., level=" << level << ", xoffset=" << xoffset
<< ", yoffset=" << yoffset << ", zoffset=" << zoffset << ", width=" << width
@@ -881,15 +877,6 @@ void WebGPUDriver::update3DImage(Handle<HwTexture> textureHandle, const uint32_t
mBlitter.blit(mQueue, mCommandEncoder, blitArgs);
}
if (!reusedCommandEncoder) {
// TODO consider removing encoder finish + submit once we have test coverage and can
// safely verify doing so will not result in strange errors. We don't think this
// submit is necessary, as the encoder should get finished and the command
// submitted in commit(), finish(), and/or flush() in this frame
// or the next anyway. And, the blit bits will be encoded before other things.
// Thus, not submitting here _seems_ ok. Nonetheless, doing the submit here likely
// represents unnecessary inefficiency and higher bandwidth
// between the CPU and GPU, but we are worried about functional correctness at this
// stage.
const wgpu::CommandBufferDescriptor commandBufferDescriptor{
.label = "blit_command_buffer",
};
@@ -983,17 +970,6 @@ void WebGPUDriver::generateMipmaps(Handle<HwTexture> textureHandle) {
mSpdComputePassMipmapGenerator.Generate(encoder, wgpuTexture, spdConfig);
// Finish the encoder and submit all the passes at once.
// TODO consider reusing the existing command encoder or creating it in this function
// if it doesn't already exist and removing encoder finish + submit here once
// we have test coverage and can safely verify doing so will not result in
// strange errors. We don't think this submit is necessary, as the encoder
// should get finished and the command submitted in
// commit(), finish(), and/or flush() in this frame or the next anyway.
// And, the mipmap generation bits will be encoded before other things.
// Thus, not submitting here _seems_ ok. Nonetheless, doing the submit here likely
// represents unnecessary inefficiency and higher bandwidth
// between the CPU and GPU, but we are worried about functional correctness at this
// stage.
wgpu::CommandBufferDescriptor cmdBufferDesc = {};
cmdBufferDesc.label = "Mipmap Command Buffer";
wgpu::CommandBuffer commandBuffer = encoder.Finish(&cmdBufferDesc);
@@ -1314,7 +1290,8 @@ void WebGPUDriver::readPixels(Handle<HwRenderTarget> sourceRenderTargetHandle, c
const size_t dstBytesPerPixel = PixelBufferDescriptor::computePixelSize(
pixelBufferDescriptor.format, pixelBufferDescriptor.type);
const size_t srcBytesPerPixel = getWGPUTextureFormatPixelSize(srcTexture.GetFormat());
const size_t srcBytesPerPixel =
WebGPUTexture::getWGPUTextureFormatPixelSize(srcTexture.GetFormat());
FILAMENT_CHECK_PRECONDITION(dstBytesPerPixel == srcBytesPerPixel && dstBytesPerPixel > 0)
<< "Source texture pixel size (" << srcBytesPerPixel
@@ -1355,15 +1332,6 @@ void WebGPUDriver::readPixels(Handle<HwRenderTarget> sourceRenderTargetHandle, c
wgpu::Extent3D copySize{ .width = actualWidth,
.height = actualHeight,
.depthOrArrayLayers = 1 };
// TODO consider removing encoder finish + submit once we have test coverage and can
// safely verify doing so will not result in strange errors. We don't think this
// submit is necessary, as the encoder should get finished and the command
// submitted in commit(), finish(), and/or flush() in this frame
// or the next anyway. And, the read/copy bits will be encoded before other things.
// Thus, not submitting here _seems_ ok. Nonetheless, doing the submit here likely
// represents unnecessary inefficiency and higher bandwidth
// between the CPU and GPU, but we are worried about functional correctness at this
// stage.
encoder.CopyTextureToBuffer(&source, &destination, &copySize);
wgpu::CommandBuffer commandBuffer = encoder.Finish();
mQueue.Submit(1, &commandBuffer);
@@ -1416,9 +1384,7 @@ void WebGPUDriver::readBufferSubData(Handle<HwBufferObject> bufferObjectHandle,
void WebGPUDriver::blitDEPRECATED(TargetBufferFlags buffers,
Handle<HwRenderTarget> destinationRenderTargetHandle, const Viewport destinationViewport,
Handle<HwRenderTarget> sourceRenderTargetHandle, const Viewport sourceViewport,
const SamplerMagFilter filter) {
PANIC_PRECONDITION("WebGPUDriver::blitDEPRECATED not supported");
}
const SamplerMagFilter filter) {}
void WebGPUDriver::resolve(Handle<HwTexture> destinationTextureHandle, const uint8_t sourceLevel,
const uint8_t sourceLayer, Handle<HwTexture> sourceTextureHandle,
@@ -1456,56 +1422,45 @@ void WebGPUDriver::blit(Handle<HwTexture> destinationTextureHandle, const uint8_
const uint8_t sourceLayer, const math::uint2 destinationOrigin,
Handle<HwTexture> sourceTextureHandle, const uint8_t destinationLevel,
const uint8_t destinationLayer, const math::uint2 sourceOrigin, const math::uint2 size) {
bool reusedCommandEncoder{ true };
if (!mCommandEncoder) {
reusedCommandEncoder = false;
const wgpu::CommandEncoderDescriptor commandEncoderDescriptor{
.label = "blit_command",
};
mCommandEncoder = mDevice.CreateCommandEncoder(&commandEncoderDescriptor);
FILAMENT_CHECK_POSTCONDITION(mCommandEncoder)
<< "Failed to create command encoder for blit?";
}
const auto sourceTexture{ handleCast<WebGPUTexture>(sourceTextureHandle) };
const auto destinationTexture{ handleCast<WebGPUTexture>(destinationTextureHandle) };
const WebGPUBlitter::BlitArgs blitArgs{
.source = {
.texture = sourceTexture->getTexture(),
.aspect = sourceTexture->getAspect(),
.origin = {.x = sourceOrigin.x, .y=sourceOrigin.y},
.extent = {.width=size.x, .height =size.y},
.mipLevel = sourceLevel,
.layerOrDepth = sourceLayer,
},
.destination = {
.texture = destinationTexture->getTexture(),
.aspect = destinationTexture->getAspect(),
.origin = {.x = destinationOrigin.x, .y=destinationOrigin.y},
.extent = {.width=size.x, .height =size.y},
.mipLevel = destinationLevel,
.layerOrDepth = destinationLayer,
},
.filter = SamplerMagFilter::NEAREST,
};
mBlitter.blit(mQueue, mCommandEncoder, blitArgs);
if (!reusedCommandEncoder) {
// TODO consider removing encoder finish + submit once we have test coverage and can
// safely verify doing so will not result in strange errors. We don't think this
// submit is necessary, as the encoder should get finished and the command submitted in
// commit(), finish(), and/or flush() in this frame or the next anyway.
// And, the blit bits will be encoded before other things.
// Thus, not submitting here _seems_ ok. Nonetheless, doing the submit here likely
// represents unnecessary inefficiency and higher bandwidth
// between the CPU and GPU, but we are worried about functional correctness at this
// stage.
const wgpu::CommandBufferDescriptor commandBufferDescriptor{
.label = "blit_command_buffer",
};
const wgpu::CommandBuffer blitCommand{ mCommandEncoder.Finish(&commandBufferDescriptor) };
FILAMENT_CHECK_POSTCONDITION(blitCommand) << "Failed to create command buffer for blit?";
mQueue.Submit(1, &blitCommand);
mCommandEncoder = nullptr;
}
// TODO uncomment when texture format is taken into account with sampler settings in the
// blitter
// bool reusedCommandEncoder{ true };
// if (!mCommandEncoder) {
// reusedCommandEncoder = false;
// const wgpu::CommandEncoderDescriptor commandEncoderDescriptor{
// .label = "blit_command",
// };
// mCommandEncoder = mDevice.CreateCommandEncoder(&commandEncoderDescriptor);
// FILAMENT_CHECK_POSTCONDITION(mCommandEncoder)
// << "Failed to create command encoder for blit?";
// }
// const WebGPUBlitter::BlitArgs blitArgs{
// .source = {
// .texture = handleCast<WebGPUTexture>(sourceTextureHandle)->getTexture(),
// .origin = {.x = sourceOrigin.x, .y=sourceOrigin.y},
// .extent = {.width=size.x, .height =size.y},
// .mipLevel = sourceLevel,
// .layerOrDepth = sourceLayer,
// },
// .destination = {
// .texture = handleCast<WebGPUTexture>(destinationTextureHandle)->getTexture(),
// .origin = {.x = destinationOrigin.x, .y=destinationOrigin.y},
// .extent = {.width=size.x, .height =size.y},
// .mipLevel = destinationLevel,
// .layerOrDepth = destinationLayer,
// },
// .filter = SamplerMagFilter::NEAREST,
// };
// mBlitter.blit(mQueue, mCommandEncoder, blitArgs);
// if (!reusedCommandEncoder) {
// const wgpu::CommandBufferDescriptor commandBufferDescriptor{
// .label = "blit_command_buffer",
// };
// const wgpu::CommandBuffer blitCommand{ mCommandEncoder.Finish(&commandBufferDescriptor) };
// FILAMENT_CHECK_POSTCONDITION(blitCommand) << "Failed to create command buffer for blit?";
// mQueue.Submit(1, &blitCommand);
// mCommandEncoder = nullptr;
// }
}
void WebGPUDriver::bindPipeline(PipelineState const& pipelineState) {
@@ -1525,8 +1480,8 @@ void WebGPUDriver::bindPipeline(PipelineState const& pipelineState) {
assert_invariant(bindGroupLayouts.size() >= pipelineState.pipelineLayout.setLayout.size());
size_t bindGroupLayoutCount{ 0 };
for (size_t i{ 0 }; i < bindGroupLayouts.size(); i++) {
const auto handle{ pipelineState.pipelineLayout.setLayout[i] };
if (!handle) {
const auto handle{ pipelineState.pipelineLayout.setLayout[bindGroupLayoutCount] };
if (handle.getId() == HandleBase::nullid) {
continue;
}
bindGroupLayouts[bindGroupLayoutCount++] =
@@ -1700,35 +1655,12 @@ void WebGPUDriver::updateDescriptorSetTexture(Handle<HwDescriptorSet> descriptor
.binding = static_cast<uint32_t>(binding * 2 + 1),
.sampler = sampler };
bindGroup->addEntry(sEntry.binding, std::move(sEntry));
#if FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
FWGPU_LOGD << "updateDescriptorSetTexture:";
FWGPU_LOGD << " wgpu::BindGroupLayout handle: " << bindGroup->getLayout().Get();
FWGPU_LOGD << " texture: binding:" << tEntry.binding
<< " wgpu handle:" << texture->getTexture().Get()
<< " " << webGPUTextureToString(texture->getTexture())
<< " " << webGPUPrintableToString(texture->getAspect());
FWGPU_LOGD << " sampler: binding:" << sEntry.binding
<< " filterMag:" << filamentSamplerMagFilterToString(params.filterMag)
<< " filterMin:" << filamentSamplerMinFilterToString(params.filterMin)
<< " wrapS:" << filamentSamplerWrapModeToString(params.wrapS)
<< " wrapT:" << filamentSamplerWrapModeToString(params.wrapT)
<< " wrapR:" << filamentSamplerWrapModeToString(params.wrapR)
<< " anisotropyLog2:" << +params.anisotropyLog2
<< " compareMode:" << filamentSamplerCompareModeToString(params.compareMode)
<< " compareFunc:" << filamentSamplerCompareFuncToString(params.compareFunc);
#endif
}
}
void WebGPUDriver::bindDescriptorSet(Handle<HwDescriptorSet> descriptorSetHandle,
const backend::descriptor_set_t setIndex, backend::DescriptorSetOffsetArray&& offsets) {
assert_invariant(setIndex < MAX_DESCRIPTOR_SET_COUNT);
// An empty handle signifies we need to release this bind point
if (!descriptorSetHandle) {
mCurrentDescriptorSets[setIndex] = {};
return;
}
const auto bindGroup = handleCast<WebGPUDescriptorSet>(descriptorSetHandle);
const auto wbg = bindGroup->lockAndReturn(mDevice);
@@ -16,7 +16,7 @@
#include "WebGPUMsaaTextureResolver.h"
#include "WebGPUTextureHelpers.h"
#include "WebGPUTexture.h"
#include <utils/Panic.h>
@@ -17,7 +17,7 @@
#include "WebGPUPipelineCache.h"
#include "WebGPUConstants.h"
#include "WebGPUTextureHelpers.h"
#include "WebGPUTexture.h"
#include "WebGPUVertexBufferInfo.h"
#include <backend/DriverEnums.h>
+1 -235
View File
@@ -36,10 +36,7 @@
namespace filament::backend {
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM) \
|| FWGPU_ENABLED(FWGPU_DEBUG_UPDATE_IMAGE) \
|| FWGPU_ENABLED(FWGPU_DEBUG_BLIT)\
|| FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
template<typename WebGPUPrintable>
[[nodiscard]] inline std::string webGPUPrintableToString(const WebGPUPrintable printable) {
std::stringstream out;
@@ -242,37 +239,6 @@ template<typename WebGPUPrintable>
}
}
[[nodiscard]] constexpr std::string_view webGPUTextureDimensionToString(
const wgpu::TextureDimension dimension) {
switch (dimension) {
case wgpu::TextureDimension::Undefined: return "Undefined";
case wgpu::TextureDimension::e1D: return "e1D";
case wgpu::TextureDimension::e2D: return "e2D";
case wgpu::TextureDimension::e3D: return "e3D";
}
}
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM) \
|| FWGPU_ENABLED(FWGPU_DEBUG_UPDATE_IMAGE) \
|| FWGPU_ENABLED(FWGPU_DEBUG_BLIT) \
|| FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
[[nodiscard]] std::string webGPUTextureToString(wgpu::Texture const& texture) {
if (texture == nullptr) {
return "nullptr (no wgpu::Texture)";
}
std::stringstream out;
out << "wgpu::Texture("
<< " format:" << webGPUTextureFormatToString(texture.GetFormat())
<< " dimension:" << webGPUTextureDimensionToString(texture.GetDimension())
<< " " << webGPUPrintableToString(texture.GetUsage())
<< " mipLevelCount:" << texture.GetMipLevelCount()
<< " sampleCount:" << texture.GetSampleCount() << " width:" << texture.GetWidth()
<< " height:" << texture.GetHeight()
<< " depthOrArrayLayers:" << texture.GetDepthOrArrayLayers() << ")";
return out.str();
}
#endif
[[nodiscard]] constexpr std::string_view filamentShaderStageToString(const ShaderStage stage) {
switch (stage) {
case ShaderStage::VERTEX: return "vertex";
@@ -281,206 +247,6 @@ template<typename WebGPUPrintable>
}
}
#if FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
[[nodiscard]] constexpr std::string_view filamentDescriptorTypeToString(const DescriptorType type) {
switch (type) {
case DescriptorType::SAMPLER_2D_FLOAT: return "SAMPLER_2D_FLOAT";
case DescriptorType::SAMPLER_2D_INT: return "SAMPLER_2D_INT";
case DescriptorType::SAMPLER_2D_UINT: return "SAMPLER_2D_UINT";
case DescriptorType::SAMPLER_2D_DEPTH: return "SAMPLER_2D_DEPTH";
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT: return "SAMPLER_2D_ARRAY_FLOAT";
case DescriptorType::SAMPLER_2D_ARRAY_INT: return "SAMPLER_2D_ARRAY_INT";
case DescriptorType::SAMPLER_2D_ARRAY_UINT: return "SAMPLER_2D_ARRAY_UINT";
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH: return "SAMPLER_2D_ARRAY_DEPTH";
case DescriptorType::SAMPLER_CUBE_FLOAT: return "SAMPLER_CUBE_FLOAT";
case DescriptorType::SAMPLER_CUBE_INT: return "SAMPLER_CUBE_INT";
case DescriptorType::SAMPLER_CUBE_UINT: return "SAMPLER_CUBE_UINT";
case DescriptorType::SAMPLER_CUBE_DEPTH: return "SAMPLER_CUBE_DEPTH";
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT: return "SAMPLER_CUBE_ARRAY_FLOAT";
case DescriptorType::SAMPLER_CUBE_ARRAY_INT: return "SAMPLER_CUBE_ARRAY_INT";
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT: return "SAMPLER_CUBE_ARRAY_UINT";
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH: return "SAMPLER_CUBE_ARRAY_DEPTH";
case DescriptorType::SAMPLER_3D_FLOAT: return "SAMPLER_3D_FLOAT";
case DescriptorType::SAMPLER_3D_INT: return "SAMPLER_3D_INT";
case DescriptorType::SAMPLER_3D_UINT: return "SAMPLER_3D_UINT";
case DescriptorType::SAMPLER_2D_MS_FLOAT: return "SAMPLER_2D_MS_FLOAT";
case DescriptorType::SAMPLER_2D_MS_INT: return "SAMPLER_2D_MS_INT";
case DescriptorType::SAMPLER_2D_MS_UINT: return "SAMPLER_2D_MS_UINT";
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT: return "SAMPLER_2D_MS_ARRAY_FLOAT";
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT: return "SAMPLER_2D_MS_ARRAY_INT";
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT: return "SAMPLER_2D_MS_ARRAY_UINT";
case DescriptorType::SAMPLER_EXTERNAL: return "SAMPLER_EXTERNAL";
case DescriptorType::UNIFORM_BUFFER: return "UNIFORM_BUFFER";
case DescriptorType::SHADER_STORAGE_BUFFER: return "SHADER_STORAGE_BUFFER";
case DescriptorType::INPUT_ATTACHMENT: return "INPUT_ATTACHMENT";
}
}
[[nodiscard]] constexpr std::string_view filamentStageFlagsToString(const ShaderStageFlags flags) {
if (flags == ShaderStageFlags::FRAGMENT) {
return "FRAGMENT";
}
if (flags == (ShaderStageFlags::VERTEX | ShaderStageFlags::FRAGMENT)) {
return "VERTEX | FRAGMENT";
}
if (flags == ShaderStageFlags::VERTEX) {
return "VERTEX";
}
if (flags == ShaderStageFlags::COMPUTE) {
return "COMPUTE";
}
if (flags == ShaderStageFlags::ALL_SHADER_STAGE_FLAGS) {
return "VERTEX | FRAGMENT | COMPUTE";
}
if (flags == (ShaderStageFlags::FRAGMENT | ShaderStageFlags::COMPUTE)) {
return "FRAGMENT | COMPUTE";
}
if (flags == (ShaderStageFlags::VERTEX | ShaderStageFlags::COMPUTE)) {
return "VERTEX | COMPUTE";
}
if (flags == ShaderStageFlags::NONE) {
return "NONE";
}
return "UNKNOWN/UNHANDLED"; // should not be possible
}
[[nodiscard]] constexpr std::string_view filamentDescriptorFlagsToString(const DescriptorFlags flags) {
if (flags == DescriptorFlags::NONE) {
return "NONE";
}
if (flags == DescriptorFlags::DYNAMIC_OFFSET) {
return "DYNAMIC_OFFSET";
}
if (flags == DescriptorFlags::UNFILTERABLE) {
return "UNFILTERABLE";
}
if (flags == (DescriptorFlags::DYNAMIC_OFFSET | DescriptorFlags::UNFILTERABLE)) {
return "DYNAMIC_OFFSET | UNFILTERABLE";
}
return "UNKNOWN/UNHANDLED"; // should not be possible
}
[[nodiscard]] constexpr std::string_view filamentSamplerMagFilterToString(
const SamplerMagFilter filter) {
switch (filter) {
case SamplerMagFilter::NEAREST: return "NEAREST";
case SamplerMagFilter::LINEAR: return "LINEAR";
}
}
[[nodiscard]] constexpr std::string_view filamentSamplerMinFilterToString(
const SamplerMinFilter filter) {
switch (filter) {
case SamplerMinFilter::NEAREST: return "NEAREST";
case SamplerMinFilter::LINEAR: return "LINEAR";
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST: return "NEAREST_MIPMAP_NEAREST";
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST: return "LINEAR_MIPMAP_NEAREST";
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR: return "NEAREST_MIPMAP_LINEAR";
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR: return "LINEAR_MIPMAP_LINEAR";
}
}
[[nodiscard]] constexpr std::string_view filamentSamplerWrapModeToString(
const SamplerWrapMode mode) {
switch (mode) {
case SamplerWrapMode::CLAMP_TO_EDGE: return "CLAMP_TO_EDGE";
case SamplerWrapMode::REPEAT: return "REPEAT";
case SamplerWrapMode::MIRRORED_REPEAT: return "MIRRORED_REPEAT";
}
}
[[nodiscard]] constexpr std::string_view filamentSamplerCompareModeToString(
const SamplerCompareMode mode) {
switch (mode) {
case SamplerCompareMode::NONE: return "NONE";
case SamplerCompareMode::COMPARE_TO_TEXTURE: return "COMPARE_TO_TEXTURE";
}
}
[[nodiscard]] constexpr std::string_view filamentSamplerCompareFuncToString(
const SamplerCompareFunc func) {
switch (func) {
case SamplerCompareFunc::LE: return "LE";
case SamplerCompareFunc::GE: return "GE";
case SamplerCompareFunc::L: return "L";
case SamplerCompareFunc::G: return "G";
case SamplerCompareFunc::E: return "E";
case SamplerCompareFunc::NE: return "NE";
case SamplerCompareFunc::A: return "A";
case SamplerCompareFunc::N: return "N";
}
}
[[nodiscard]] std::string filamentTextureUsageFlagsToString(const TextureUsage flags) {
if (flags == TextureUsage::NONE) {
return "NONE";
}
bool first{ true };
std::stringstream out;
if (any(flags & TextureUsage::COLOR_ATTACHMENT)) {
first = false;
out << "COLOR_ATTACHMENT";
}
if (any(flags & TextureUsage::DEPTH_ATTACHMENT)) {
if (!first) {
out << " | ";
}
first = false;
out << "DEPTH_ATTACHMENT";
}
if (any(flags & TextureUsage::STENCIL_ATTACHMENT)) {
if (!first) {
out << " | ";
}
first = false;
out << "STENCIL_ATTACHMENT";
}
if (any(flags & TextureUsage::UPLOADABLE)) {
if (!first) {
out << " | ";
}
first = false;
out << "UPLOADABLE";
}
if (any(flags & TextureUsage::SAMPLEABLE)) {
if (!first) {
out << " | ";
}
first = false;
out << "SAMPLEABLE";
}
if (any(flags & TextureUsage::SUBPASS_INPUT)) {
if (!first) {
out << " | ";
}
first = false;
out << "SUBPASS_INPUT";
}
if (any(flags & TextureUsage::BLIT_SRC)) {
if (!first) {
out << " | ";
}
first = false;
out << "BLIT_SRC";
}
if (any(flags & TextureUsage::BLIT_DST)) {
if (!first) {
out << " | ";
}
first = false;
out << "BLIT_DST";
}
if (any(flags & TextureUsage::PROTECTED)) {
if (!first) {
out << " | ";
}
first = false;
out << "PROTECTED";
}
return out.str();
}
#endif // FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
}// namespace filament::backend
#endif// TNT_FILAMENT_BACKEND_WEBGPUSTRINGS_H
+296 -8
View File
@@ -19,7 +19,6 @@
#include "WebGPUConstants.h"
#include "WebGPURenderPassMipmapGenerator.h"
#include "WebGPUStrings.h"
#include "WebGPUTextureHelpers.h"
#include "DriverBase.h"
#include "private/backend/BackendUtils.h"
@@ -65,6 +64,37 @@ namespace {
}
}
/**
* @param format texture format to potentially be used for storage binding
* @return true if the format is compatible with wgpu::TextureUsage::StorageBinding
*/
[[nodiscard]] constexpr bool isFormatStorageCompatible(const wgpu::TextureFormat format) {
switch (format) {
// List of formats that support storage binding
case wgpu::TextureFormat::R32Float:
case wgpu::TextureFormat::R32Sint:
case wgpu::TextureFormat::R32Uint:
case wgpu::TextureFormat::RG32Float:
case wgpu::TextureFormat::RG32Sint:
case wgpu::TextureFormat::RG32Uint:
case wgpu::TextureFormat::RGBA16Float:
case wgpu::TextureFormat::RGBA16Sint:
case wgpu::TextureFormat::RGBA16Uint:
case wgpu::TextureFormat::RGBA32Float:
case wgpu::TextureFormat::RGBA32Sint:
case wgpu::TextureFormat::RGBA32Uint:
case wgpu::TextureFormat::RGBA8Unorm:
case wgpu::TextureFormat::RGBA8Snorm:
case wgpu::TextureFormat::RGBA8Uint:
case wgpu::TextureFormat::RGBA8Sint:
return true;
default:
// All other formats, including packed floats (RG11B10Ufloat),
// depth/stencil, and sRGB formats do not support storage.
return false;
}
}
/**
* @param viewFormat potential view format to a texture
* @return an underlying texture format that is storage binding compatible for which this view
@@ -219,6 +249,30 @@ namespace {
return wgpu::TextureAspect::All;
}
[[nodiscard]] constexpr wgpu::TextureViewDimension toWebGPUTextureViewDimension(
const SamplerType samplerType) {
switch (samplerType) {
case SamplerType::SAMPLER_2D: return wgpu::TextureViewDimension::e2D;
case SamplerType::SAMPLER_2D_ARRAY: return wgpu::TextureViewDimension::e2DArray;
case SamplerType::SAMPLER_CUBEMAP: return wgpu::TextureViewDimension::Cube;
case SamplerType::SAMPLER_EXTERNAL: return wgpu::TextureViewDimension::e2D;
case SamplerType::SAMPLER_3D: return wgpu::TextureViewDimension::e3D;
case SamplerType::SAMPLER_CUBEMAP_ARRAY: return wgpu::TextureViewDimension::CubeArray;
}
}
[[nodiscard]] constexpr wgpu::TextureDimension toWebGPUTextureDimension(
const SamplerType samplerType) {
switch (samplerType) {
case SamplerType::SAMPLER_2D: return wgpu::TextureDimension::e2D;
case SamplerType::SAMPLER_2D_ARRAY: return wgpu::TextureDimension::e2D;
case SamplerType::SAMPLER_CUBEMAP: return wgpu::TextureDimension::e2D;
case SamplerType::SAMPLER_EXTERNAL: return wgpu::TextureDimension::e2D;
case SamplerType::SAMPLER_3D: return wgpu::TextureDimension::e3D;
case SamplerType::SAMPLER_CUBEMAP_ARRAY: return wgpu::TextureDimension::e2D;
}
}
[[nodiscard]] WebGPUTexture::MipmapGenerationStrategy determineMipmapGenerationStrategy(
const wgpu::TextureFormat format, const SamplerType samplerType, const uint8_t sampleCount,
const uint8_t mipmapLevels) {
@@ -270,12 +324,82 @@ namespace {
} // namespace
size_t WebGPUTexture::getWGPUTextureFormatPixelSize(const wgpu::TextureFormat format) {
switch (format) {
// 1 byte
case wgpu::TextureFormat::R8Unorm:
case wgpu::TextureFormat::R8Snorm:
case wgpu::TextureFormat::R8Uint:
case wgpu::TextureFormat::R8Sint:
case wgpu::TextureFormat::Stencil8:
return 1;
// 2 bytes
case wgpu::TextureFormat::R16Uint:
case wgpu::TextureFormat::R16Sint:
case wgpu::TextureFormat::R16Float:
case wgpu::TextureFormat::RG8Unorm:
case wgpu::TextureFormat::RG8Snorm:
case wgpu::TextureFormat::RG8Uint:
case wgpu::TextureFormat::RG8Sint:
case wgpu::TextureFormat::Depth16Unorm:
return 2;
// 4 bytes
// -- 32-bit single-channel formats
case wgpu::TextureFormat::R32Float:
case wgpu::TextureFormat::R32Uint:
case wgpu::TextureFormat::R32Sint:
// -- 16-bit two-channel formats
case wgpu::TextureFormat::RG16Uint:
case wgpu::TextureFormat::RG16Sint:
case wgpu::TextureFormat::RG16Float:
// -- 8-bit four-channel formats
case wgpu::TextureFormat::RGBA8Unorm:
case wgpu::TextureFormat::RGBA8UnormSrgb:
case wgpu::TextureFormat::RGBA8Snorm:
case wgpu::TextureFormat::RGBA8Uint:
case wgpu::TextureFormat::RGBA8Sint:
case wgpu::TextureFormat::BGRA8Unorm:
case wgpu::TextureFormat::BGRA8UnormSrgb:
// -- Packed 32-bit formats
case wgpu::TextureFormat::RGB10A2Unorm:
case wgpu::TextureFormat::RGB10A2Uint:
case wgpu::TextureFormat::RG11B10Ufloat:
case wgpu::TextureFormat::RGB9E5Ufloat:
// -- Depth/Stencil formats
case wgpu::TextureFormat::Depth32Float:
case wgpu::TextureFormat::Depth24Plus:
case wgpu::TextureFormat::Depth24PlusStencil8:
return 4;
// 8 bytes
case wgpu::TextureFormat::RG32Float:
case wgpu::TextureFormat::RG32Uint:
case wgpu::TextureFormat::RG32Sint:
case wgpu::TextureFormat::RGBA16Uint:
case wgpu::TextureFormat::RGBA16Sint:
case wgpu::TextureFormat::RGBA16Float:
return 8;
// 16 bytes
case wgpu::TextureFormat::RGBA32Float:
case wgpu::TextureFormat::RGBA32Uint:
case wgpu::TextureFormat::RGBA32Sint:
return 16;
// Non-copyable or compressed formats
case wgpu::TextureFormat::Depth32FloatStencil8: // Not copyable from texture to buffer
default:
return 0;
}
}
WebGPUTexture::WebGPUTexture(const SamplerType samplerType, 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,
wgpu::Device const& device) noexcept
: HwTexture{ samplerType, levels, samples, width, height, depth, format, usage },
mViewFormat{ toWGPUTextureFormat(format) },
mViewFormat{ fToWGPUTextureFormat(format) },
mMipmapGenerationStrategy{ determineMipmapGenerationStrategy(mViewFormat, samplerType,
samples, levels) },
mWebGPUFormat{ mMipmapGenerationStrategy == MipmapGenerationStrategy::SPD_COMPUTE_PASS
@@ -329,12 +453,6 @@ WebGPUTexture::WebGPUTexture(const SamplerType samplerType, const uint8_t levels
<< viewFormatStream.str() << " and texture format " << textureFormatStream.str();
}
#endif
#if FWGPU_ENABLED(FWGPU_DEBUG_BIND_GROUPS)
FWGPU_LOGD << "WebGPUTexture: wgpu handle " << mTexture.Get()
<< " samplerType:" << to_string(samplerType)
<< " usage flags:" << filamentTextureUsageFlagsToString(usage)
<< " " << webGPUTextureToString(mTexture);
#endif
}
WebGPUTexture::WebGPUTexture(WebGPUTexture const* src, const uint8_t baseLevel,
@@ -447,6 +565,176 @@ wgpu::TextureView WebGPUTexture::makeMsaaSidecarTextureViewIfTextureSidecarExist
return textureView;
}
wgpu::TextureFormat WebGPUTexture::fToWGPUTextureFormat(TextureFormat const& fFormat) {
switch (fFormat) {
case TextureFormat::R8: return wgpu::TextureFormat::R8Unorm;
case TextureFormat::R8_SNORM: return wgpu::TextureFormat::R8Snorm;
case TextureFormat::R8UI: return wgpu::TextureFormat::R8Uint;
case TextureFormat::R8I: return wgpu::TextureFormat::R8Sint;
case TextureFormat::STENCIL8: return wgpu::TextureFormat::Stencil8;
case TextureFormat::R16F: return wgpu::TextureFormat::R16Float;
case TextureFormat::R16UI: return wgpu::TextureFormat::R16Uint;
case TextureFormat::R16I: return wgpu::TextureFormat::R16Sint;
case TextureFormat::RG8: return wgpu::TextureFormat::RG8Unorm;
case TextureFormat::RG8_SNORM: return wgpu::TextureFormat::RG8Snorm;
case TextureFormat::RG8UI: return wgpu::TextureFormat::RG8Uint;
case TextureFormat::RG8I: return wgpu::TextureFormat::RG8Sint;
case TextureFormat::R32F: return wgpu::TextureFormat::R32Float;
case TextureFormat::R32UI: return wgpu::TextureFormat::R32Uint;
case TextureFormat::R32I: return wgpu::TextureFormat::R32Sint;
case TextureFormat::RG16F: return wgpu::TextureFormat::RG16Float;
case TextureFormat::RG16UI: return wgpu::TextureFormat::RG16Uint;
case TextureFormat::RG16I: return wgpu::TextureFormat::RG16Sint;
case TextureFormat::RGBA8: return wgpu::TextureFormat::RGBA8Unorm;
case TextureFormat::SRGB8_A8: return wgpu::TextureFormat::RGBA8UnormSrgb;
case TextureFormat::RGBA8_SNORM: return wgpu::TextureFormat::RGBA8Snorm;
case TextureFormat::RGBA8UI: return wgpu::TextureFormat::RGBA8Uint;
case TextureFormat::RGBA8I: return wgpu::TextureFormat::RGBA8Sint;
case TextureFormat::DEPTH16: return wgpu::TextureFormat::Depth16Unorm;
case TextureFormat::DEPTH24: return wgpu::TextureFormat::Depth24Plus;
case TextureFormat::DEPTH32F: return wgpu::TextureFormat::Depth32Float;
case TextureFormat::DEPTH24_STENCIL8: return wgpu::TextureFormat::Depth24PlusStencil8;
case TextureFormat::DEPTH32F_STENCIL8: return wgpu::TextureFormat::Depth32FloatStencil8;
case TextureFormat::RG32F: return wgpu::TextureFormat::RG32Float;
case TextureFormat::RG32UI: return wgpu::TextureFormat::RG32Uint;
case TextureFormat::RG32I: return wgpu::TextureFormat::RG32Sint;
case TextureFormat::RGBA16F: return wgpu::TextureFormat::RGBA16Float;
case TextureFormat::RGBA16UI: return wgpu::TextureFormat::RGBA16Uint;
case TextureFormat::RGBA16I: return wgpu::TextureFormat::RGBA16Sint;
case TextureFormat::RGBA32F: return wgpu::TextureFormat::RGBA32Float;
case TextureFormat::RGBA32UI: return wgpu::TextureFormat::RGBA32Uint;
case TextureFormat::RGBA32I: return wgpu::TextureFormat::RGBA32Sint;
case TextureFormat::EAC_R11: return wgpu::TextureFormat::EACR11Unorm;
case TextureFormat::EAC_R11_SIGNED: return wgpu::TextureFormat::EACR11Snorm;
case TextureFormat::EAC_RG11: return wgpu::TextureFormat::EACRG11Unorm;
case TextureFormat::EAC_RG11_SIGNED: return wgpu::TextureFormat::EACRG11Snorm;
case TextureFormat::ETC2_RGB8: return wgpu::TextureFormat::ETC2RGB8Unorm;
case TextureFormat::ETC2_SRGB8: return wgpu::TextureFormat::ETC2RGB8UnormSrgb;
case TextureFormat::ETC2_RGB8_A1: return wgpu::TextureFormat::ETC2RGB8A1Unorm;
case TextureFormat::ETC2_SRGB8_A1: return wgpu::TextureFormat::ETC2RGB8A1UnormSrgb;
case TextureFormat::ETC2_EAC_RGBA8: return wgpu::TextureFormat::ETC2RGBA8Unorm;
case TextureFormat::ETC2_EAC_SRGBA8: return wgpu::TextureFormat::ETC2RGBA8UnormSrgb;
case TextureFormat::RGBA_ASTC_4x4: return wgpu::TextureFormat::ASTC4x4Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_4x4: return wgpu::TextureFormat::ASTC4x4UnormSrgb;
case TextureFormat::RGBA_ASTC_5x4: return wgpu::TextureFormat::ASTC5x4Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_5x4: return wgpu::TextureFormat::ASTC5x4UnormSrgb;
case TextureFormat::RGBA_ASTC_5x5: return wgpu::TextureFormat::ASTC5x5Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_5x5: return wgpu::TextureFormat::ASTC5x5UnormSrgb;
case TextureFormat::RGBA_ASTC_6x5: return wgpu::TextureFormat::ASTC6x5Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_6x5: return wgpu::TextureFormat::ASTC6x5UnormSrgb;
case TextureFormat::RGBA_ASTC_6x6: return wgpu::TextureFormat::ASTC6x6Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_6x6: return wgpu::TextureFormat::ASTC6x6UnormSrgb;
case TextureFormat::RGBA_ASTC_8x5: return wgpu::TextureFormat::ASTC8x5Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_8x5: return wgpu::TextureFormat::ASTC8x5UnormSrgb;
case TextureFormat::RGBA_ASTC_8x6: return wgpu::TextureFormat::ASTC8x6Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_8x6: return wgpu::TextureFormat::ASTC8x6UnormSrgb;
case TextureFormat::RGBA_ASTC_8x8: return wgpu::TextureFormat::ASTC8x8Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_8x8: return wgpu::TextureFormat::ASTC8x8UnormSrgb;
case TextureFormat::RGBA_ASTC_10x5: return wgpu::TextureFormat::ASTC10x5Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_10x5: return wgpu::TextureFormat::ASTC10x5UnormSrgb;
case TextureFormat::RGBA_ASTC_10x6: return wgpu::TextureFormat::ASTC10x6Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_10x6: return wgpu::TextureFormat::ASTC10x6UnormSrgb;
case TextureFormat::RGBA_ASTC_10x8: return wgpu::TextureFormat::ASTC10x8Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_10x8: return wgpu::TextureFormat::ASTC10x8UnormSrgb;
case TextureFormat::RGBA_ASTC_10x10: return wgpu::TextureFormat::ASTC10x10Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_10x10: return wgpu::TextureFormat::ASTC10x10UnormSrgb;
case TextureFormat::RGBA_ASTC_12x10: return wgpu::TextureFormat::ASTC12x10Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_12x10: return wgpu::TextureFormat::ASTC12x10UnormSrgb;
case TextureFormat::RGBA_ASTC_12x12: return wgpu::TextureFormat::ASTC12x12Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_12x12: return wgpu::TextureFormat::ASTC12x12UnormSrgb;
case TextureFormat::RED_RGTC1: return wgpu::TextureFormat::BC4RUnorm;
case TextureFormat::SIGNED_RED_RGTC1: return wgpu::TextureFormat::BC4RSnorm;
case TextureFormat::RED_GREEN_RGTC2: return wgpu::TextureFormat::BC5RGUnorm;
case TextureFormat::SIGNED_RED_GREEN_RGTC2: return wgpu::TextureFormat::BC5RGSnorm;
case TextureFormat::RGB_BPTC_UNSIGNED_FLOAT: return wgpu::TextureFormat::BC6HRGBUfloat;
case TextureFormat::RGB_BPTC_SIGNED_FLOAT: return wgpu::TextureFormat::BC6HRGBFloat;
case TextureFormat::RGBA_BPTC_UNORM: return wgpu::TextureFormat::BC7RGBAUnorm;
case TextureFormat::SRGB_ALPHA_BPTC_UNORM: return wgpu::TextureFormat::BC7RGBAUnormSrgb;
case TextureFormat::RGB565:
// No direct mapping in wgpu. Could potentially map to RGBA8Unorm
// and discard the alpha and lower precision.
FWGPU_LOGW << "Requested Filament texture format RGB565 but getting "
"wgpu::TextureFormat::Undefined (no direct mapping in wgpu)";
return wgpu::TextureFormat::Undefined;
case TextureFormat::RGB9_E5: return wgpu::TextureFormat::RGB9E5Ufloat;
case TextureFormat::RGB5_A1:
// No direct mapping in wgpu. Could potentially map to RGBA8Unorm
// and handle the packing/unpacking in shaders.
FWGPU_LOGW << "Requested Filament texture format RGB5_A1 but getting "
"wgpu::TextureFormat::Undefined (no direct mapping in wgpu)";
return wgpu::TextureFormat::Undefined;
case TextureFormat::RGBA4:
// No direct mapping in wgpu. Could potentially map to RGBA8Unorm
// and handle the packing/unpacking in shaders.
FWGPU_LOGW << "Requested Filament texture format RGBA4 but getting "
"wgpu::TextureFormat::Undefined (no direct mapping in wgpu)";
return wgpu::TextureFormat::Undefined;
case TextureFormat::RGB8:
FWGPU_LOGW << "Requested Filament texture format RGB8 but getting "
"wgpu::TextureFormat::RGBA8Unorm (no direct sRGB equivalent in wgpu "
"without alpha)";
return wgpu::TextureFormat::RGBA8Unorm;
case TextureFormat::SRGB8:
FWGPU_LOGW << "Requested Filament texture format SRGB8 but getting "
"wgpu::TextureFormat::RGBA8UnormSrgb (no direct sRGB equivalent in wgpu "
"without alpha)";
return wgpu::TextureFormat::RGBA8UnormSrgb;
case TextureFormat::RGB8_SNORM:
FWGPU_LOGW
<< "Requested Filament texture format RGB8_SNORM but getting "
"wgpu::TextureFormat::RGBA8Snorm (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA8Snorm;
case TextureFormat::RGB8UI:
FWGPU_LOGW << "Requested Filament texture format RGB8UI but getting "
"wgpu::TextureFormat::RGBA8Uint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA8Uint;
case TextureFormat::RGB8I:
FWGPU_LOGW << "Requested Filament texture format RGB8I but getting "
"wgpu::TextureFormat::RGBA8Sint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA8Sint;
case TextureFormat::R11F_G11F_B10F: return wgpu::TextureFormat::RG11B10Ufloat;
case TextureFormat::UNUSED: return wgpu::TextureFormat::Undefined;
case TextureFormat::RGB10_A2: return wgpu::TextureFormat::RGB10A2Unorm;
case TextureFormat::RGB16F:
FWGPU_LOGW
<< "Requested Filament texture format RGB16F but getting "
"wgpu::TextureFormat::RGBA16Float (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA16Float;
case TextureFormat::RGB16UI:
FWGPU_LOGW
<< "Requested Filament texture format RGB16UI but getting "
"wgpu::TextureFormat::RGBA16Uint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA16Uint;
case TextureFormat::RGB16I:
FWGPU_LOGW
<< "Requested Filament texture format RGB16I but getting "
"wgpu::TextureFormat::RGBA16Sint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA16Sint;
case TextureFormat::RGB32F:
FWGPU_LOGW
<< "Requested Filament texture format RGB32F but getting "
"wgpu::TextureFormat::RGBA32Float (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA32Float;
case TextureFormat::RGB32UI:
FWGPU_LOGW
<< "Requested Filament texture format RGB32UI but getting "
"wgpu::TextureFormat::RGBA32Uint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA32Uint;
case TextureFormat::RGB32I:
FWGPU_LOGW
<< "Requested Filament texture format RGB32I but getting "
"wgpu::TextureFormat::RGBA32Sint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA32Sint;
case TextureFormat::DXT1_RGB: return wgpu::TextureFormat::BC1RGBAUnorm;
case TextureFormat::DXT1_RGBA: return wgpu::TextureFormat::BC1RGBAUnorm;
case TextureFormat::DXT3_RGBA: return wgpu::TextureFormat::BC2RGBAUnorm;
case TextureFormat::DXT5_RGBA: return wgpu::TextureFormat::BC3RGBAUnorm;
case TextureFormat::DXT1_SRGB: return wgpu::TextureFormat::BC1RGBAUnormSrgb;
case TextureFormat::DXT1_SRGBA: return wgpu::TextureFormat::BC1RGBAUnormSrgb;
case TextureFormat::DXT3_SRGBA: return wgpu::TextureFormat::BC2RGBAUnormSrgb;
case TextureFormat::DXT5_SRGBA: return wgpu::TextureFormat::BC3RGBAUnormSrgb;
}
}
wgpu::TextureView WebGPUTexture::makeTextureView(const uint8_t& baseLevel,
const uint8_t& levelCount, const uint32_t& baseArrayLayer, const uint32_t& arrayLayerCount,
const wgpu::TextureViewDimension dimension) const noexcept {
+20 -2
View File
@@ -26,6 +26,20 @@
namespace filament::backend {
[[nodiscard]] constexpr bool hasStencil(const wgpu::TextureFormat textureFormat) {
return textureFormat == wgpu::TextureFormat::Depth24PlusStencil8 ||
textureFormat == wgpu::TextureFormat::Depth32FloatStencil8 ||
textureFormat == wgpu::TextureFormat::Stencil8;
}
[[nodiscard]] constexpr bool hasDepth(const wgpu::TextureFormat textureFormat) {
return textureFormat == wgpu::TextureFormat::Depth16Unorm ||
textureFormat == wgpu::TextureFormat::Depth32Float ||
textureFormat == wgpu::TextureFormat::Depth24Plus ||
textureFormat == wgpu::TextureFormat::Depth24PlusStencil8 ||
textureFormat == wgpu::TextureFormat::Depth32FloatStencil8;
}
class WebGPUTexture : public HwTexture {
public:
enum class MipmapGenerationStrategy : uint8_t {
@@ -90,8 +104,10 @@ public:
/**
* @return nullptr if a MSAA sidecar texture is not appliable, otherwise a view to one
*/
[[nodiscard]] wgpu::TextureView makeMsaaSidecarTextureView(wgpu::Texture const&,
uint8_t mipLevel, uint32_t arrayLayer) const;
[[nodiscard]] wgpu::TextureView makeMsaaSidecarTextureView(wgpu::Texture const&, uint8_t mipLevel, uint32_t arrayLayer) const;
[[nodiscard]] static wgpu::TextureFormat fToWGPUTextureFormat(
filament::backend::TextureFormat const& fFormat);
/**
* @param format a required texture format (can be a view to a different underlying texture
@@ -102,6 +118,8 @@ public:
[[nodiscard]] static bool supportsMultipleMipLevelsViaStorageBinding(
wgpu::TextureFormat format);
[[nodiscard]] static size_t getWGPUTextureFormatPixelSize(const wgpu::TextureFormat format);
private:
// the texture view's format, which may differ from the underlying texture's format itself,
// an example of when this is needed is when certain underlying shaders don't support
@@ -17,8 +17,6 @@
#ifndef TNT_FILAMENT_BACKEND_WEBGPUTEXTUREHELPERS_H
#define TNT_FILAMENT_BACKEND_WEBGPUTEXTUREHELPERS_H
#include "webgpu/WebGPUConstants.h"
#include <backend/DriverEnums.h>
#include <webgpu/webgpu_cpp.h>
@@ -27,20 +25,6 @@
namespace filament::backend {
[[nodiscard]] constexpr bool hasStencil(const wgpu::TextureFormat textureFormat) {
return textureFormat == wgpu::TextureFormat::Depth24PlusStencil8 ||
textureFormat == wgpu::TextureFormat::Depth32FloatStencil8 ||
textureFormat == wgpu::TextureFormat::Stencil8;
}
[[nodiscard]] constexpr bool hasDepth(const wgpu::TextureFormat textureFormat) {
return textureFormat == wgpu::TextureFormat::Depth16Unorm ||
textureFormat == wgpu::TextureFormat::Depth32Float ||
textureFormat == wgpu::TextureFormat::Depth24Plus ||
textureFormat == wgpu::TextureFormat::Depth24PlusStencil8 ||
textureFormat == wgpu::TextureFormat::Depth32FloatStencil8;
}
[[nodiscard]] constexpr std::string_view toString(const PixelDataFormat format) {
switch (format) {
case PixelDataFormat::R: return "R";
@@ -113,206 +97,7 @@ namespace filament::backend {
return wgpu::TextureFormat::Undefined;
}
[[nodiscard]] constexpr wgpu::TextureFormat toWGPUTextureFormat(const TextureFormat fFormat) {
switch (fFormat) {
case TextureFormat::R8: return wgpu::TextureFormat::R8Unorm;
case TextureFormat::R8_SNORM: return wgpu::TextureFormat::R8Snorm;
case TextureFormat::R8UI: return wgpu::TextureFormat::R8Uint;
case TextureFormat::R8I: return wgpu::TextureFormat::R8Sint;
case TextureFormat::STENCIL8: return wgpu::TextureFormat::Stencil8;
case TextureFormat::R16F: return wgpu::TextureFormat::R16Float;
case TextureFormat::R16UI: return wgpu::TextureFormat::R16Uint;
case TextureFormat::R16I: return wgpu::TextureFormat::R16Sint;
case TextureFormat::RG8: return wgpu::TextureFormat::RG8Unorm;
case TextureFormat::RG8_SNORM: return wgpu::TextureFormat::RG8Snorm;
case TextureFormat::RG8UI: return wgpu::TextureFormat::RG8Uint;
case TextureFormat::RG8I: return wgpu::TextureFormat::RG8Sint;
case TextureFormat::R32F: return wgpu::TextureFormat::R32Float;
case TextureFormat::R32UI: return wgpu::TextureFormat::R32Uint;
case TextureFormat::R32I: return wgpu::TextureFormat::R32Sint;
case TextureFormat::RG16F: return wgpu::TextureFormat::RG16Float;
case TextureFormat::RG16UI: return wgpu::TextureFormat::RG16Uint;
case TextureFormat::RG16I: return wgpu::TextureFormat::RG16Sint;
case TextureFormat::RGBA8: return wgpu::TextureFormat::RGBA8Unorm;
case TextureFormat::SRGB8_A8: return wgpu::TextureFormat::RGBA8UnormSrgb;
case TextureFormat::RGBA8_SNORM: return wgpu::TextureFormat::RGBA8Snorm;
case TextureFormat::RGBA8UI: return wgpu::TextureFormat::RGBA8Uint;
case TextureFormat::RGBA8I: return wgpu::TextureFormat::RGBA8Sint;
case TextureFormat::DEPTH16: return wgpu::TextureFormat::Depth16Unorm;
case TextureFormat::DEPTH24: return wgpu::TextureFormat::Depth24Plus;
case TextureFormat::DEPTH32F: return wgpu::TextureFormat::Depth32Float;
case TextureFormat::DEPTH24_STENCIL8: return wgpu::TextureFormat::Depth24PlusStencil8;
case TextureFormat::DEPTH32F_STENCIL8: return wgpu::TextureFormat::Depth32FloatStencil8;
case TextureFormat::RG32F: return wgpu::TextureFormat::RG32Float;
case TextureFormat::RG32UI: return wgpu::TextureFormat::RG32Uint;
case TextureFormat::RG32I: return wgpu::TextureFormat::RG32Sint;
case TextureFormat::RGBA16F: return wgpu::TextureFormat::RGBA16Float;
case TextureFormat::RGBA16UI: return wgpu::TextureFormat::RGBA16Uint;
case TextureFormat::RGBA16I: return wgpu::TextureFormat::RGBA16Sint;
case TextureFormat::RGBA32F: return wgpu::TextureFormat::RGBA32Float;
case TextureFormat::RGBA32UI: return wgpu::TextureFormat::RGBA32Uint;
case TextureFormat::RGBA32I: return wgpu::TextureFormat::RGBA32Sint;
case TextureFormat::EAC_R11: return wgpu::TextureFormat::EACR11Unorm;
case TextureFormat::EAC_R11_SIGNED: return wgpu::TextureFormat::EACR11Snorm;
case TextureFormat::EAC_RG11: return wgpu::TextureFormat::EACRG11Unorm;
case TextureFormat::EAC_RG11_SIGNED: return wgpu::TextureFormat::EACRG11Snorm;
case TextureFormat::ETC2_RGB8: return wgpu::TextureFormat::ETC2RGB8Unorm;
case TextureFormat::ETC2_SRGB8: return wgpu::TextureFormat::ETC2RGB8UnormSrgb;
case TextureFormat::ETC2_RGB8_A1: return wgpu::TextureFormat::ETC2RGB8A1Unorm;
case TextureFormat::ETC2_SRGB8_A1: return wgpu::TextureFormat::ETC2RGB8A1UnormSrgb;
case TextureFormat::ETC2_EAC_RGBA8: return wgpu::TextureFormat::ETC2RGBA8Unorm;
case TextureFormat::ETC2_EAC_SRGBA8: return wgpu::TextureFormat::ETC2RGBA8UnormSrgb;
case TextureFormat::RGBA_ASTC_4x4: return wgpu::TextureFormat::ASTC4x4Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_4x4: return wgpu::TextureFormat::ASTC4x4UnormSrgb;
case TextureFormat::RGBA_ASTC_5x4: return wgpu::TextureFormat::ASTC5x4Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_5x4: return wgpu::TextureFormat::ASTC5x4UnormSrgb;
case TextureFormat::RGBA_ASTC_5x5: return wgpu::TextureFormat::ASTC5x5Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_5x5: return wgpu::TextureFormat::ASTC5x5UnormSrgb;
case TextureFormat::RGBA_ASTC_6x5: return wgpu::TextureFormat::ASTC6x5Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_6x5: return wgpu::TextureFormat::ASTC6x5UnormSrgb;
case TextureFormat::RGBA_ASTC_6x6: return wgpu::TextureFormat::ASTC6x6Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_6x6: return wgpu::TextureFormat::ASTC6x6UnormSrgb;
case TextureFormat::RGBA_ASTC_8x5: return wgpu::TextureFormat::ASTC8x5Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_8x5: return wgpu::TextureFormat::ASTC8x5UnormSrgb;
case TextureFormat::RGBA_ASTC_8x6: return wgpu::TextureFormat::ASTC8x6Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_8x6: return wgpu::TextureFormat::ASTC8x6UnormSrgb;
case TextureFormat::RGBA_ASTC_8x8: return wgpu::TextureFormat::ASTC8x8Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_8x8: return wgpu::TextureFormat::ASTC8x8UnormSrgb;
case TextureFormat::RGBA_ASTC_10x5: return wgpu::TextureFormat::ASTC10x5Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_10x5: return wgpu::TextureFormat::ASTC10x5UnormSrgb;
case TextureFormat::RGBA_ASTC_10x6: return wgpu::TextureFormat::ASTC10x6Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_10x6: return wgpu::TextureFormat::ASTC10x6UnormSrgb;
case TextureFormat::RGBA_ASTC_10x8: return wgpu::TextureFormat::ASTC10x8Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_10x8: return wgpu::TextureFormat::ASTC10x8UnormSrgb;
case TextureFormat::RGBA_ASTC_10x10: return wgpu::TextureFormat::ASTC10x10Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_10x10: return wgpu::TextureFormat::ASTC10x10UnormSrgb;
case TextureFormat::RGBA_ASTC_12x10: return wgpu::TextureFormat::ASTC12x10Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_12x10: return wgpu::TextureFormat::ASTC12x10UnormSrgb;
case TextureFormat::RGBA_ASTC_12x12: return wgpu::TextureFormat::ASTC12x12Unorm;
case TextureFormat::SRGB8_ALPHA8_ASTC_12x12: return wgpu::TextureFormat::ASTC12x12UnormSrgb;
case TextureFormat::RED_RGTC1: return wgpu::TextureFormat::BC4RUnorm;
case TextureFormat::SIGNED_RED_RGTC1: return wgpu::TextureFormat::BC4RSnorm;
case TextureFormat::RED_GREEN_RGTC2: return wgpu::TextureFormat::BC5RGUnorm;
case TextureFormat::SIGNED_RED_GREEN_RGTC2: return wgpu::TextureFormat::BC5RGSnorm;
case TextureFormat::RGB_BPTC_UNSIGNED_FLOAT: return wgpu::TextureFormat::BC6HRGBUfloat;
case TextureFormat::RGB_BPTC_SIGNED_FLOAT: return wgpu::TextureFormat::BC6HRGBFloat;
case TextureFormat::RGBA_BPTC_UNORM: return wgpu::TextureFormat::BC7RGBAUnorm;
case TextureFormat::SRGB_ALPHA_BPTC_UNORM: return wgpu::TextureFormat::BC7RGBAUnormSrgb;
case TextureFormat::RGB565:
// No direct mapping in wgpu. Could potentially map to RGBA8Unorm
// and discard the alpha and lower precision.
FWGPU_LOGW << "Requested Filament texture format RGB565 but getting "
"wgpu::TextureFormat::Undefined (no direct mapping in wgpu)";
return wgpu::TextureFormat::Undefined;
case TextureFormat::RGB9_E5: return wgpu::TextureFormat::RGB9E5Ufloat;
case TextureFormat::RGB5_A1:
// No direct mapping in wgpu. Could potentially map to RGBA8Unorm
// and handle the packing/unpacking in shaders.
FWGPU_LOGW << "Requested Filament texture format RGB5_A1 but getting "
"wgpu::TextureFormat::Undefined (no direct mapping in wgpu)";
return wgpu::TextureFormat::Undefined;
case TextureFormat::RGBA4:
// No direct mapping in wgpu. Could potentially map to RGBA8Unorm
// and handle the packing/unpacking in shaders.
FWGPU_LOGW << "Requested Filament texture format RGBA4 but getting "
"wgpu::TextureFormat::Undefined (no direct mapping in wgpu)";
return wgpu::TextureFormat::Undefined;
case TextureFormat::RGB8:
FWGPU_LOGW << "Requested Filament texture format RGB8 but getting "
"wgpu::TextureFormat::RGBA8Unorm (no direct sRGB equivalent in wgpu "
"without alpha)";
return wgpu::TextureFormat::RGBA8Unorm;
case TextureFormat::SRGB8:
FWGPU_LOGW << "Requested Filament texture format SRGB8 but getting "
"wgpu::TextureFormat::RGBA8UnormSrgb (no direct sRGB equivalent in wgpu "
"without alpha)";
return wgpu::TextureFormat::RGBA8UnormSrgb;
case TextureFormat::RGB8_SNORM:
FWGPU_LOGW
<< "Requested Filament texture format RGB8_SNORM but getting "
"wgpu::TextureFormat::RGBA8Snorm (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA8Snorm;
case TextureFormat::RGB8UI:
FWGPU_LOGW << "Requested Filament texture format RGB8UI but getting "
"wgpu::TextureFormat::RGBA8Uint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA8Uint;
case TextureFormat::RGB8I:
FWGPU_LOGW << "Requested Filament texture format RGB8I but getting "
"wgpu::TextureFormat::RGBA8Sint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA8Sint;
case TextureFormat::R11F_G11F_B10F: return wgpu::TextureFormat::RG11B10Ufloat;
case TextureFormat::UNUSED: return wgpu::TextureFormat::Undefined;
case TextureFormat::RGB10_A2: return wgpu::TextureFormat::RGB10A2Unorm;
case TextureFormat::RGB16F:
FWGPU_LOGW
<< "Requested Filament texture format RGB16F but getting "
"wgpu::TextureFormat::RGBA16Float (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA16Float;
case TextureFormat::RGB16UI:
FWGPU_LOGW
<< "Requested Filament texture format RGB16UI but getting "
"wgpu::TextureFormat::RGBA16Uint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA16Uint;
case TextureFormat::RGB16I:
FWGPU_LOGW
<< "Requested Filament texture format RGB16I but getting "
"wgpu::TextureFormat::RGBA16Sint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA16Sint;
case TextureFormat::RGB32F:
FWGPU_LOGW
<< "Requested Filament texture format RGB32F but getting "
"wgpu::TextureFormat::RGBA32Float (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA32Float;
case TextureFormat::RGB32UI:
FWGPU_LOGW
<< "Requested Filament texture format RGB32UI but getting "
"wgpu::TextureFormat::RGBA32Uint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA32Uint;
case TextureFormat::RGB32I:
FWGPU_LOGW
<< "Requested Filament texture format RGB32I but getting "
"wgpu::TextureFormat::RGBA32Sint (no direct mapping in wgpu without alpha)";
return wgpu::TextureFormat::RGBA32Sint;
case TextureFormat::DXT1_RGB: return wgpu::TextureFormat::BC1RGBAUnorm;
case TextureFormat::DXT1_RGBA: return wgpu::TextureFormat::BC1RGBAUnorm;
case TextureFormat::DXT3_RGBA: return wgpu::TextureFormat::BC2RGBAUnorm;
case TextureFormat::DXT5_RGBA: return wgpu::TextureFormat::BC3RGBAUnorm;
case TextureFormat::DXT1_SRGB: return wgpu::TextureFormat::BC1RGBAUnormSrgb;
case TextureFormat::DXT1_SRGBA: return wgpu::TextureFormat::BC1RGBAUnormSrgb;
case TextureFormat::DXT3_SRGBA: return wgpu::TextureFormat::BC2RGBAUnormSrgb;
case TextureFormat::DXT5_SRGBA: return wgpu::TextureFormat::BC3RGBAUnormSrgb;
}
}
[[nodiscard]] constexpr wgpu::TextureViewDimension toWebGPUTextureViewDimension(
const SamplerType samplerType) {
switch (samplerType) {
case SamplerType::SAMPLER_2D: return wgpu::TextureViewDimension::e2D;
case SamplerType::SAMPLER_2D_ARRAY: return wgpu::TextureViewDimension::e2DArray;
case SamplerType::SAMPLER_CUBEMAP: return wgpu::TextureViewDimension::Cube;
case SamplerType::SAMPLER_EXTERNAL: return wgpu::TextureViewDimension::e2D;
case SamplerType::SAMPLER_3D: return wgpu::TextureViewDimension::e3D;
case SamplerType::SAMPLER_CUBEMAP_ARRAY: return wgpu::TextureViewDimension::CubeArray;
}
}
[[nodiscard]] constexpr wgpu::TextureDimension toWebGPUTextureDimension(
const SamplerType samplerType) {
switch (samplerType) {
case SamplerType::SAMPLER_2D: return wgpu::TextureDimension::e2D;
case SamplerType::SAMPLER_2D_ARRAY: return wgpu::TextureDimension::e2D;
case SamplerType::SAMPLER_CUBEMAP: return wgpu::TextureDimension::e2D;
case SamplerType::SAMPLER_EXTERNAL: return wgpu::TextureDimension::e2D;
case SamplerType::SAMPLER_3D: return wgpu::TextureDimension::e3D;
case SamplerType::SAMPLER_CUBEMAP_ARRAY: return wgpu::TextureDimension::e2D;
}
}
/**
* @return the linear version of the format (removing the Srgb part) or the original format if it
* is already linear
*/
[[nodiscard]] constexpr wgpu::TextureFormat toLinearFormat(const wgpu::TextureFormat format) {
[[nodiscard]] constexpr wgpu::TextureFormat toWebGPULinearFormat(const wgpu::TextureFormat format) {
switch (format) {
case wgpu::TextureFormat::RGBA8UnormSrgb: return wgpu::TextureFormat::RGBA8Unorm;
case wgpu::TextureFormat::BGRA8UnormSrgb: return wgpu::TextureFormat::BGRA8Unorm;
@@ -341,199 +126,6 @@ namespace filament::backend {
}
}
/**
* @return true if https://www.w3.org/TR/webgpu/#copy-compatible which states:
* Two GPUTextureFormats format1 and format2 are copy-compatible if:
* - format1 equals format2, or
* - format1 and format2 differ only in whether they are srgb formats (have the -srgb suffix).
*/
[[nodiscard]] constexpr bool areCopyCompatible(const wgpu::TextureFormat sourceFormat,
const wgpu::TextureFormat destinationFormat) {
return sourceFormat == destinationFormat ||
(toLinearFormat(sourceFormat) == toLinearFormat(destinationFormat));
}
[[nodiscard]] constexpr wgpu::Extent2D getBlockSize(const wgpu::TextureFormat format) {
// see https://www.w3.org/TR/webgpu/#texture-formats
// and https://www.w3.org/TR/webgpu/#texture-format-caps
switch (format) {
// BC compressed formats
case wgpu::TextureFormat::BC1RGBAUnorm:
case wgpu::TextureFormat::BC1RGBAUnormSrgb:
case wgpu::TextureFormat::BC2RGBAUnorm:
case wgpu::TextureFormat::BC2RGBAUnormSrgb:
case wgpu::TextureFormat::BC3RGBAUnorm:
case wgpu::TextureFormat::BC3RGBAUnormSrgb:
case wgpu::TextureFormat::BC4RUnorm:
case wgpu::TextureFormat::BC4RSnorm:
case wgpu::TextureFormat::BC5RGUnorm:
case wgpu::TextureFormat::BC5RGSnorm:
case wgpu::TextureFormat::BC6HRGBUfloat:
case wgpu::TextureFormat::BC6HRGBFloat:
case wgpu::TextureFormat::BC7RGBAUnorm:
case wgpu::TextureFormat::BC7RGBAUnormSrgb:
// ETC2 compressed formats
case wgpu::TextureFormat::ETC2RGB8Unorm:
case wgpu::TextureFormat::ETC2RGB8UnormSrgb:
case wgpu::TextureFormat::ETC2RGB8A1Unorm:
case wgpu::TextureFormat::ETC2RGB8A1UnormSrgb:
case wgpu::TextureFormat::ETC2RGBA8Unorm:
case wgpu::TextureFormat::ETC2RGBA8UnormSrgb:
case wgpu::TextureFormat::EACR11Unorm:
case wgpu::TextureFormat::EACR11Snorm:
case wgpu::TextureFormat::EACRG11Unorm:
case wgpu::TextureFormat::EACRG11Snorm:
// ASTC compressed formats
case wgpu::TextureFormat::ASTC4x4Unorm:
case wgpu::TextureFormat::ASTC4x4UnormSrgb:
return { .width = 4, .height = 4 };
case wgpu::TextureFormat::ASTC5x4Unorm:
case wgpu::TextureFormat::ASTC5x4UnormSrgb:
return { .width = 5, .height = 4 };
case wgpu::TextureFormat::ASTC5x5Unorm:
case wgpu::TextureFormat::ASTC5x5UnormSrgb:
return { .width = 5, .height = 5 };
case wgpu::TextureFormat::ASTC6x5Unorm:
case wgpu::TextureFormat::ASTC6x5UnormSrgb:
return { .width = 6, .height = 5 };
case wgpu::TextureFormat::ASTC6x6Unorm:
case wgpu::TextureFormat::ASTC6x6UnormSrgb:
return { .width = 6, .height = 6 };
case wgpu::TextureFormat::ASTC8x5Unorm:
case wgpu::TextureFormat::ASTC8x5UnormSrgb:
return { .width = 8, .height = 5 };
case wgpu::TextureFormat::ASTC8x6Unorm:
case wgpu::TextureFormat::ASTC8x6UnormSrgb:
return { .width = 8, .height = 6 };
case wgpu::TextureFormat::ASTC8x8Unorm:
case wgpu::TextureFormat::ASTC8x8UnormSrgb:
return { .width = 8, .height = 8 };
case wgpu::TextureFormat::ASTC10x5Unorm:
case wgpu::TextureFormat::ASTC10x5UnormSrgb:
return { .width = 10, .height = 5 };
case wgpu::TextureFormat::ASTC10x6Unorm:
case wgpu::TextureFormat::ASTC10x6UnormSrgb:
return { .width = 10, .height = 6 };
case wgpu::TextureFormat::ASTC10x8Unorm:
case wgpu::TextureFormat::ASTC10x8UnormSrgb:
return { .width = 10, .height = 8 };
case wgpu::TextureFormat::ASTC10x10Unorm:
case wgpu::TextureFormat::ASTC10x10UnormSrgb:
return { .width = 10, .height = 10 };
case wgpu::TextureFormat::ASTC12x10Unorm:
case wgpu::TextureFormat::ASTC12x10UnormSrgb:
return { .width = 12, .height = 10 };
case wgpu::TextureFormat::ASTC12x12Unorm:
case wgpu::TextureFormat::ASTC12x12UnormSrgb:
return { .width = 12, .height = 12 };
default:
// All other formats are uncompressed and have a 1x1 block size.
return { .width = 1, .height = 1 };
}
}
[[nodiscard]] constexpr size_t getWGPUTextureFormatPixelSize(const wgpu::TextureFormat format) {
switch (format) {
// 1 byte
case wgpu::TextureFormat::R8Unorm:
case wgpu::TextureFormat::R8Snorm:
case wgpu::TextureFormat::R8Uint:
case wgpu::TextureFormat::R8Sint:
case wgpu::TextureFormat::Stencil8:
return 1;
// 2 bytes
case wgpu::TextureFormat::R16Uint:
case wgpu::TextureFormat::R16Sint:
case wgpu::TextureFormat::R16Float:
case wgpu::TextureFormat::RG8Unorm:
case wgpu::TextureFormat::RG8Snorm:
case wgpu::TextureFormat::RG8Uint:
case wgpu::TextureFormat::RG8Sint:
case wgpu::TextureFormat::Depth16Unorm:
return 2;
// 4 bytes
// -- 32-bit single-channel formats
case wgpu::TextureFormat::R32Float:
case wgpu::TextureFormat::R32Uint:
case wgpu::TextureFormat::R32Sint:
// -- 16-bit two-channel formats
case wgpu::TextureFormat::RG16Uint:
case wgpu::TextureFormat::RG16Sint:
case wgpu::TextureFormat::RG16Float:
// -- 8-bit four-channel formats
case wgpu::TextureFormat::RGBA8Unorm:
case wgpu::TextureFormat::RGBA8UnormSrgb:
case wgpu::TextureFormat::RGBA8Snorm:
case wgpu::TextureFormat::RGBA8Uint:
case wgpu::TextureFormat::RGBA8Sint:
case wgpu::TextureFormat::BGRA8Unorm:
case wgpu::TextureFormat::BGRA8UnormSrgb:
// -- Packed 32-bit formats
case wgpu::TextureFormat::RGB10A2Unorm:
case wgpu::TextureFormat::RGB10A2Uint:
case wgpu::TextureFormat::RG11B10Ufloat:
case wgpu::TextureFormat::RGB9E5Ufloat:
// -- Depth/Stencil formats
case wgpu::TextureFormat::Depth32Float:
case wgpu::TextureFormat::Depth24Plus:
case wgpu::TextureFormat::Depth24PlusStencil8:
return 4;
// 8 bytes
case wgpu::TextureFormat::RG32Float:
case wgpu::TextureFormat::RG32Uint:
case wgpu::TextureFormat::RG32Sint:
case wgpu::TextureFormat::RGBA16Uint:
case wgpu::TextureFormat::RGBA16Sint:
case wgpu::TextureFormat::RGBA16Float:
return 8;
// 16 bytes
case wgpu::TextureFormat::RGBA32Float:
case wgpu::TextureFormat::RGBA32Uint:
case wgpu::TextureFormat::RGBA32Sint:
return 16;
// Non-copyable or compressed formats
case wgpu::TextureFormat::Depth32FloatStencil8: // Not copyable from texture to buffer
default:
return 0;
}
}
/**
* @param format texture format to potentially be used for storage binding
* @return true if the format is compatible with wgpu::TextureUsage::StorageBinding
*/
[[nodiscard]] constexpr bool isFormatStorageCompatible(const wgpu::TextureFormat format) {
switch (format) {
// List of formats that support storage binding
case wgpu::TextureFormat::R32Float:
case wgpu::TextureFormat::R32Sint:
case wgpu::TextureFormat::R32Uint:
case wgpu::TextureFormat::RG32Float:
case wgpu::TextureFormat::RG32Sint:
case wgpu::TextureFormat::RG32Uint:
case wgpu::TextureFormat::RGBA16Float:
case wgpu::TextureFormat::RGBA16Sint:
case wgpu::TextureFormat::RGBA16Uint:
case wgpu::TextureFormat::RGBA32Float:
case wgpu::TextureFormat::RGBA32Sint:
case wgpu::TextureFormat::RGBA32Uint:
case wgpu::TextureFormat::RGBA8Unorm:
case wgpu::TextureFormat::RGBA8Snorm:
case wgpu::TextureFormat::RGBA8Uint:
case wgpu::TextureFormat::RGBA8Sint:
return true;
default:
// All other formats, including packed floats (RG11B10Ufloat),
// depth/stencil, and sRGB formats do not support storage.
return false;
}
}
} // namespace filament::backend
#endif // TNT_FILAMENT_BACKEND_WEBGPUTEXTUREHELPERS_H
@@ -54,10 +54,9 @@ std::string processPlaceholderTemplate(std::string_view const& stringTemplate,
positionAfterPlaceholder - positionOfPlaceholder) };
if (const auto iter{ valueByPlaceholderName.find(placeholderName) };
iter == valueByPlaceholderName.end()) {
// wrapping placeholderName in a std::string to null terminate the C string....
PANIC_POSTCONDITION("Found placeholder '%s' in template, but this is not present in "
"valueByPlaceholderName",
std::string{ placeholderName }.data());
placeholderName.data());
} else {
const std::string_view value{ iter->second };
out << value;
-2
View File
@@ -46,8 +46,6 @@ Backend parseArgumentsForBackend(int argc, char* argv[]) {
backend = Backend::VULKAN;
} else if (arg == "metal") {
backend = Backend::METAL;
} else if (arg == "webgpu") {
backend = Backend::WEBGPU;
} else {
std::cerr << "Unrecognized target API. Must be 'opengl'|'vulkan'|'metal'."
<< std::endl
+2 -2
View File
@@ -21,9 +21,9 @@
#include "utils/Hash.h"
#include <fstream>
#include "BackendTest.h"
//#include "BackendTest.h"
#include "backend/PixelBufferDescriptor.h"
#include "private/backend/DriverApi.h"
//#include "private/backend/DriverApi.h"
#ifndef FILAMENT_IOS
-3
View File
@@ -49,9 +49,6 @@ test::NativeView getNativeView() {
if (self.backend == test::Backend::VULKAN) {
nativeView.ptr = (void*) view;
}
if (self.backend == test::Backend::WEBGPU) {
nativeView.ptr = (void*) view.layer;
}
CGSize drawableSize = ((CAMetalLayer*) view.layer).drawableSize;
nativeView.width = static_cast<size_t>(drawableSize.width);
nativeView.height = static_cast<size_t>(drawableSize.height);
-2
View File
@@ -27,7 +27,6 @@ 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();
Cleanup cleanup(api);
@@ -88,7 +87,6 @@ TEST_F(BackendTest, FrameScheduledCallback) {
TEST_F(BackendTest, FrameCompletedCallback) {
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();
Cleanup cleanup(api);
@@ -104,7 +104,6 @@ TEST_F(BackendTest, FeedbackLoops) {
SKIP_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::OPENGL),
"OpenGL image is upside down due to readPixels failing for texture with uploaded image "
"data");
FAIL_IF(Backend::WEBGPU, "BUG");
auto& api = getDriverApi();
Cleanup cleanup(api);
+18 -125
View File
@@ -36,7 +36,6 @@
#include "details/Engine.h"
#include "ds/DescriptorSet.h"
#include "ds/SsrPassDescriptorSet.h"
#include "ds/TypedUniformBuffer.h"
@@ -252,11 +251,6 @@ void PostProcessManager::bindPostProcessDescriptorSet(DriverApi& driver) const n
mPostProcessDescriptorSet.bind(driver);
}
void PostProcessManager::bindPerRenderableDescriptorSet(DriverApi& driver) noexcept {
driver.bindDescriptorSet(mDummyPerRenderableDsh, +DescriptorSetBindingPoints::PER_RENDERABLE,
{ { 0, 0 }, driver });
}
UTILS_NOINLINE
void PostProcessManager::registerPostProcessMaterial(std::string_view const name,
StaticMaterialInfo const& info) {
@@ -320,32 +314,6 @@ void PostProcessManager::init() noexcept {
mFullScreenQuadVbih = engine.getFullScreenVertexBuffer()->getVertexBufferInfoHandle();
mPerRenderableDslh = engine.getPerRenderableDescriptorSetLayout().getHandle();
mDummyPerRenderableDsh = driver.createDescriptorSet(mPerRenderableDslh);
driver.updateDescriptorSetBuffer(mDummyPerRenderableDsh,
+PerRenderableBindingPoints::OBJECT_UNIFORMS, engine.getDummyUniformBuffer(), 0,
sizeof(PerRenderableUib));
driver.updateDescriptorSetBuffer(mDummyPerRenderableDsh,
+PerRenderableBindingPoints::BONES_UNIFORMS, engine.getDummyUniformBuffer(), 0,
sizeof(PerRenderableBoneUib));
driver.updateDescriptorSetBuffer(mDummyPerRenderableDsh,
+PerRenderableBindingPoints::MORPHING_UNIFORMS, engine.getDummyUniformBuffer(), 0,
sizeof(PerRenderableMorphingUib));
driver.updateDescriptorSetTexture(mDummyPerRenderableDsh,
+PerRenderableBindingPoints::MORPH_TARGET_POSITIONS,
engine.getDummyMorphTargetBuffer()->getPositionsHandle(), {});
driver.updateDescriptorSetTexture(mDummyPerRenderableDsh,
+PerRenderableBindingPoints::MORPH_TARGET_TANGENTS,
engine.getDummyMorphTargetBuffer()->getTangentsHandle(), {});
driver.updateDescriptorSetTexture(mDummyPerRenderableDsh,
+PerRenderableBindingPoints::BONES_INDICES_AND_WEIGHTS, engine.getZeroTextureArray(),
{});
mSsrPassDescriptorSet.init(engine);
mPostProcessDescriptorSet.init(engine);
mStructureDescriptorSet.init(engine);
@@ -416,8 +384,6 @@ void PostProcessManager::terminate(DriverApi& driver) noexcept {
FEngine& engine = mEngine;
driver.destroyTexture(mStarburstTexture);
driver.destroyDescriptorSet(mDummyPerRenderableDsh);
// Must destroy the instances before the materials
mMaterialInstanceManager.terminate(engine);
@@ -454,12 +420,6 @@ void PostProcessManager::resetForRender() {
mFixedMaterialInstanceIndex = {};
}
void PostProcessManager::unbindAllDescriptorSets(DriverApi& driver) noexcept {
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_VIEW);
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_RENDERABLE);
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
}
UTILS_NOINLINE
PipelineState PostProcessManager::getPipelineState(
FMaterial const* const ma, PostProcessVariant variant) const noexcept {
@@ -523,7 +483,6 @@ void PostProcessManager::commitAndRenderFullScreenQuad(DriverApi& driver,
driver.beginRenderPass(out.target, out.params);
driver.draw(pipeline, mFullScreenQuadRph, 0, 3, 1);
driver.endRenderPass();
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
}
// ------------------------------------------------------------------------------------------------
@@ -586,7 +545,6 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph
// bind the per-view descriptorSet that is used for the structure pass
getStructureDescriptorSet().bind(driver);
bindPerRenderableDescriptorSet(driver);
passBuilder.renderFlags(structureRenderFlags);
passBuilder.variant(structureVariant);
@@ -597,7 +555,6 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph
driver.beginRenderPass(out.target, out.params);
pass.getExecutor().execute(mEngine, driver);
driver.endRenderPass();
unbindAllDescriptorSets(driver);
});
auto const depth = structurePass->depth;
@@ -624,8 +581,7 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph
}
},
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
getStructureDescriptorSet().bind(driver);
bindPerRenderableDescriptorSet(driver);
getStructureDescriptorSet().bind(driver);
auto in = resources.getTexture(data.depth);
auto& material = getPostProcessMaterial("mipmapDepth");
@@ -645,10 +601,8 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph
mi->commit(driver);
mi->use(driver);
renderFullScreenQuad(out, pipeline, driver);
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
driver.destroyTexture(th);
}
unbindAllDescriptorSets(driver);
});
return { depth, structurePass->picking };
@@ -696,7 +650,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::transparentPicking(FrameGrap
// bind the per-view descriptorSet that is used for the structure pass
getStructureDescriptorSet().bind(driver);
bindPerRenderableDescriptorSet(driver);
auto [target, params] = resources.getRenderPassInfo();
passBuilder.renderFlags(structureRenderFlags);
@@ -707,7 +660,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::transparentPicking(FrameGrap
driver.beginRenderPass(target, params);
pass.getExecutor().execute(mEngine, driver);
driver.endRenderPass();
unbindAllDescriptorSets(driver);
});
return pickingRenderPass->picking;
@@ -718,7 +670,9 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::transparentPicking(FrameGrap
FrameGraphId<FrameGraphTexture> PostProcessManager::ssr(FrameGraph& fg,
RenderPassBuilder const& passBuilder,
FrameHistory const& frameHistory,
CameraInfo const& cameraInfo,
FrameGraphId<FrameGraphTexture> const structure,
ScreenSpaceReflectionsOptions const& options,
FrameGraphTexture::Descriptor const& desc) noexcept {
struct SSRPassData {
@@ -739,6 +693,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::ssr(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> const history = fg.import("SSR history", previous.desc,
FrameGraphTexture::Usage::SAMPLEABLE, previous.color);
mat4 const& historyProjection = previous.projection;
auto const& uvFromClipMatrix = mEngine.getUvFromClipMatrix();
auto const& ssrPass = fg.addPass<SSRPassData>("SSR Pass",
[&](FrameGraph::Builder& builder, auto& data) {
@@ -772,23 +728,28 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::ssr(FrameGraph& fg,
data.history = builder.sample(history);
}
},
[this, passBuilder = passBuilder](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) mutable {
[this, projection = cameraInfo.projection,
userViewMatrix = cameraInfo.getUserViewMatrix(), uvFromClipMatrix, historyProjection,
options, passBuilder = passBuilder]
(FrameGraphResources const& resources, auto const& data, DriverApi& driver) mutable {
// set structure sampler
mSsrPassDescriptorSet.prepareStructure(mEngine, data.structure ?
resources.getTexture(data.structure) : getOneTexture());
// set screen-space reflections and screen-space refractions
mat4f const uvFromViewMatrix = uvFromClipMatrix * projection;
mat4f const reprojection = uvFromClipMatrix *
mat4f{ historyProjection * inverse(userViewMatrix) };
// the history sampler is a regular texture2D
TextureHandle const history = data.history ?
resources.getTexture(data.history) : getZeroTexture();
mSsrPassDescriptorSet.prepareHistorySSR(mEngine, history);
mSsrPassDescriptorSet.prepareHistorySSR(mEngine, history, reprojection, uvFromViewMatrix, options);
mSsrPassDescriptorSet.commit(mEngine);
mSsrPassDescriptorSet.bind(driver);
bindPerRenderableDescriptorSet(driver);
auto const out = resources.getRenderPassInfo();
// Remove the HAS_SHADOWING RenderFlags, since it's irrelevant when rendering reflections
@@ -805,7 +766,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::ssr(FrameGraph& fg,
driver.beginRenderPass(out.target, out.params);
pass.getExecutor().execute(mEngine, driver);
driver.endRenderPass();
unbindAllDescriptorSets(driver);
});
return ssrPass->reflections;
@@ -956,7 +916,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::screenSpaceAmbientOcclusion(
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
// bind the per-view descriptorSet that is used for the structure pass
getStructureDescriptorSet().bind(driver);
bindPerRenderableDescriptorSet(driver);
auto depth = resources.getTexture(data.depth);
auto ssao = resources.getRenderPassInfo();
@@ -1072,7 +1031,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::screenSpaceAmbientOcclusion(
pipeline.rasterState.depthFunc = RasterState::DepthFunc::L;
assert_invariant(ssao.params.readOnlyDepthStencil & RenderPassParams::READONLY_DEPTH);
renderFullScreenQuad(ssao, pipeline, driver);
unbindAllDescriptorSets(driver);
});
FrameGraphId<FrameGraphTexture> ssao = SSAOPass->ssao;
@@ -1151,7 +1109,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::bilateralBlurPass(FrameGraph
auto const& data, DriverApi& driver) {
// TODO: the structure descriptor set might not be the best fit.
getStructureDescriptorSet().bind(driver);
bindPerRenderableDescriptorSet(driver);
auto ssao = resources.getTexture(data.input);
auto blurred = resources.getRenderPassInfo();
@@ -1192,7 +1149,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::bilateralBlurPass(FrameGraph
auto pipeline = getPipelineState(ma);
pipeline.rasterState.depthFunc = RasterState::DepthFunc::L;
renderFullScreenQuad(blurred, pipeline, driver);
unbindAllDescriptorSets(driver);
});
return blurPass->blurred;
@@ -1318,7 +1274,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::gaussianBlurPass(FrameGraph&
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
// don't use auto for those, b/c the ide can't resolve them
using FGTD = FrameGraphTexture::Descriptor;
@@ -1410,7 +1365,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::gaussianBlurPass(FrameGraph&
commitAndRenderFullScreenQuad(driver, hwOutRT, mi);
}
unbindAllDescriptorSets(driver);
});
return blurPass->out;
@@ -1795,8 +1749,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
},
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
auto const& out = resources.getRenderPassInfo();
auto color = resources.getTexture(data.color);
auto depth = resources.getTexture(data.depth);
@@ -1815,7 +1767,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
1.0f / float(colorDesc.width),
1.0f / float(colorDesc.height) });
commitAndRenderFullScreenQuad(driver, out, mi);
unbindAllDescriptorSets(driver);
});
/*
@@ -1856,7 +1807,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
auto desc = resources.getDescriptor(data.inOutColor);
auto inOutColor = resources.getTexture(data.inOutColor);
@@ -1883,12 +1833,10 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
mi->use(driver);
renderFullScreenQuad(out, pipeline, driver);
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
driver.destroyTexture(inColor);
driver.destroyTexture(inCoc);
}
unbindAllDescriptorSets(driver);
});
/*
@@ -1934,7 +1882,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
auto const& inputDesc = resources.getDescriptor(data.inCocMinMax);
auto const& out = resources.getRenderPassInfo();
auto inCocMinMax = resources.getTexture(data.inCocMinMax);
@@ -1945,7 +1892,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
mi->setParameter("cocMinMax", inCocMinMax, { .filterMin = SamplerMinFilter::NEAREST });
mi->setParameter("texelSize", float2{ 1.0f / inputDesc.width, 1.0f / inputDesc.height });
commitAndRenderFullScreenQuad(driver, out, mi);
unbindAllDescriptorSets(driver);
});
inTilesCocMinMax = ppDoFTiling->outTilesCocMinMax;
}
@@ -1972,15 +1918,12 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
auto const& out = resources.getRenderPassInfo();
auto inTilesCocMinMax = resources.getTexture(data.inTilesCocMinMax);
auto const& material = getPostProcessMaterial("dofDilate");
FMaterialInstance* const mi = getMaterialInstance(mEngine, material);
mi->setParameter("tiles", inTilesCocMinMax, { .filterMin = SamplerMinFilter::NEAREST });
commitAndRenderFullScreenQuad(driver, out, mi);
unbindAllDescriptorSets(driver);
});
return ppDoFDilate->outTilesCocMinMax;
};
@@ -2028,8 +1971,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
},
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
auto const& out = resources.getRenderPassInfo();
auto color = resources.getTexture(data.color);
@@ -2062,7 +2003,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
});
mi->setParameter("bokehAngle", bokehAngle);
commitAndRenderFullScreenQuad(driver, out, mi);
unbindAllDescriptorSets(driver);
});
/*
@@ -2094,8 +2034,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
},
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
auto const& out = resources.getRenderPassInfo();
auto inColor = resources.getTexture(data.inColor);
@@ -2108,7 +2046,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
mi->setParameter("alpha", inAlpha, { .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
mi->setParameter("tiles", tilesCocMinMax, { .filterMin = SamplerMinFilter::NEAREST });
commitAndRenderFullScreenQuad(driver, out, mi);
unbindAllDescriptorSets(driver);
});
@@ -2144,8 +2081,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
auto const& out = resources.getRenderPassInfo();
auto color = resources.getTexture(data.color);
@@ -2160,7 +2095,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
mi->setParameter("alpha", alpha, { .filterMag = SamplerMagFilter::NEAREST });
mi->setParameter("tiles", tilesCocMinMax, { .filterMin = SamplerMinFilter::NEAREST });
commitAndRenderFullScreenQuad(driver, out, mi);
unbindAllDescriptorSets(driver);
});
return ppDoFCombine->output;
@@ -2183,8 +2117,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::downscalePass(FrameGraph& fg
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
auto const& out = resources.getRenderPassInfo();
auto const& material = getPostProcessMaterial("bloomDownsample2x");
FMaterialInstance* const mi = getMaterialInstance(mEngine, material);
@@ -2197,7 +2129,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::downscalePass(FrameGraph& fg
mi->setParameter("fireflies", fireflies ? 1.0f : 0.0f);
mi->setParameter("invHighlight", std::isinf(highlight) ? 0.0f : 1.0f / highlight);
commitAndRenderFullScreenQuad(driver, out, mi);
unbindAllDescriptorSets(driver);
});
return downsamplePass->output;
}
@@ -2318,7 +2250,6 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg,
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
// TODO: if downsampling is not exactly a multiple of two, use the 13 samples
// filter. This is generally the accepted solution, however, the 13 samples
@@ -2354,7 +2285,6 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg,
commitAndRenderFullScreenQuad(driver, hwDstRT, mi);
driver.destroyTexture(hwOutView);
}
unbindAllDescriptorSets(driver);
});
// output of bloom downsample pass becomes input of next (flare) pass
@@ -2374,7 +2304,6 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg,
},
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
auto hwOut = resources.getTexture(data.out);
auto const& outDesc = resources.getDescriptor(data.out);
@@ -2403,10 +2332,8 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg,
mi->commit(driver);
mi->use(driver);
renderFullScreenQuad(hwDstRT, pipeline, driver);
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
driver.destroyTexture(hwOutView);
}
unbindAllDescriptorSets(driver);
});
return { bloomUpsamplePass->out, flare };
@@ -2436,7 +2363,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::flarePass(FrameGraph& fg,
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
auto in = resources.getTexture(data.in);
auto const out = resources.getRenderPassInfo(0);
const float aspectRatio = float(width) / float(height);
@@ -2461,7 +2387,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::flarePass(FrameGraph& fg,
mi->setParameter("haloThickness", bloomOptions.haloThickness);
commitAndRenderFullScreenQuad(driver, out, mi);
unbindAllDescriptorSets(driver);
});
constexpr float kernelWidth = 9;
@@ -2515,7 +2440,6 @@ void PostProcessManager::colorGradingSubpass(DriverApi& driver,
ColorGradingConfig const& colorGradingConfig) noexcept {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
PostProcessVariant const variant = colorGradingConfig.translucent ?
PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE;
@@ -2547,7 +2471,6 @@ void PostProcessManager::customResolvePrepareSubpass(DriverApi& driver, CustomRe
void PostProcessManager::customResolveSubpass(DriverApi& driver) noexcept {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
FEngine const& engine = mEngine;
Handle<HwRenderPrimitive> const& fullScreenRenderPrimitive = engine.getFullScreenRenderPrimitive();
@@ -2582,7 +2505,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::customResolveUncompressPass(
auto out = resources.getRenderPassInfo();
out.params.subpassMask = 1;
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
driver.beginRenderPass(out.target, out.params);
customResolveSubpass(driver);
driver.endRenderPass();
@@ -2657,7 +2579,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::colorGrading(FrameGraph& fg,
},
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
auto colorTexture = resources.getTexture(data.input);
auto bloomTexture =
@@ -2724,8 +2645,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::colorGrading(FrameGraph& fg,
commitAndRenderFullScreenQuad(driver, out, mi,
colorGradingConfig.translucent
? PostProcessVariant::TRANSLUCENT : PostProcessVariant::OPAQUE);
unbindAllDescriptorSets(driver);
}
);
@@ -2753,7 +2672,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::fxaa(FrameGraph& fg,
},
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
auto const& inDesc = resources.getDescriptor(data.input);
auto const& texture = resources.getTexture(data.input);
auto const& out = resources.getRenderPassInfo();
@@ -2779,7 +2697,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::fxaa(FrameGraph& fg,
mi->setParameter("texelSize", 1.0f / float2{ inDesc.width, inDesc.height });
commitAndRenderFullScreenQuad(driver, out, mi, variant);
unbindAllDescriptorSets(driver);
});
return ppFXAA->output;
@@ -2972,7 +2889,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
},
[=, &current](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
constexpr mat4f normalizedToClip{mat4f::row_major_init{
2, 0, 0, -1,
@@ -3065,7 +2981,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
colorGradingSubpass(driver, colorGradingConfig);
}
driver.endRenderPass();
unbindAllDescriptorSets(driver);
});
input = colorGradingConfig.asSubpass ? taaPass->tonemappedOutput : taaPass->output;
@@ -3115,7 +3030,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::rcas(
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
auto const input = resources.getTexture(data.input);
auto const out = resources.getRenderPassInfo();
@@ -3136,7 +3050,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::rcas(
outputDesc.width, outputDesc.height,
1.0f / outputDesc.width, 1.0f / outputDesc.height });
commitAndRenderFullScreenQuad(driver, out, mi, variant);
unbindAllDescriptorSets(driver);
});
return ppFsrRcas->output;
@@ -3187,7 +3100,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleBilinear(FrameGraph&
[this, vp, filter](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
auto color = resources.getTexture(data.input);
auto const& inputDesc = resources.getDescriptor(data.input);
@@ -3217,7 +3129,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleBilinear(FrameGraph&
auto pipeline = getPipelineState(material.getMaterial(mEngine));
renderFullScreenQuad(out, pipeline, driver);
unbindAllDescriptorSets(driver);
});
auto output = ppQuadBlit->output;
@@ -3253,7 +3164,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleSGSR1(FrameGraph& fg,
[this, vp, sourceHasLuminance](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
auto color = resources.getTexture(data.input);
auto const& inputDesc = resources.getDescriptor(data.input);
@@ -3293,9 +3203,9 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleSGSR1(FrameGraph& fg,
mi->commit(driver);
mi->use(driver);
auto const out = resources.getRenderPassInfo();
auto out = resources.getRenderPassInfo();
commitAndRenderFullScreenQuad(driver, out, mi, variant);
unbindAllDescriptorSets(driver);
});
auto output = ppQuadBlit->output;
@@ -3341,7 +3251,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleFSR1(FrameGraph& fg,
[this, twoPassesEASU, dsrOptions, vp](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
// helper to set the EASU uniforms
auto setEasuUniforms = [vp, backend = mEngine.getBackend()](FMaterialInstance* mi,
@@ -3433,7 +3342,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscaleFSR1(FrameGraph& fg,
auto pipeline = getPipelineState(easuMaterial->getMaterial(mEngine));
renderFullScreenQuad(out, pipeline, driver);
}
unbindAllDescriptorSets(driver);
});
auto output = ppQuadBlit->output;
@@ -3472,7 +3380,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::blit(FrameGraph& fg, bool co
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
auto color = resources.getTexture(data.input);
auto const& inputDesc = resources.getDescriptor(data.input);
auto out = resources.getRenderPassInfo();
@@ -3509,7 +3416,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::blit(FrameGraph& fg, bool co
pipeline.rasterState.blendFunctionDstAlpha = BlendFunction::ONE_MINUS_SRC_ALPHA;
}
renderFullScreenQuad(out, pipeline, driver);
unbindAllDescriptorSets(driver);
});
return ppQuadBlit->output;
@@ -3574,7 +3480,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::blitDepth(FrameGraph& fg,
},
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
getStructureDescriptorSet().bind(driver);
bindPerRenderableDescriptorSet(driver);
auto depth = resources.getTexture(data.input);
auto const& inputDesc = resources.getDescriptor(data.input);
auto const out = resources.getRenderPassInfo();
@@ -3594,7 +3499,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::blitDepth(FrameGraph& fg,
float(vp.bottom) / inputDesc.height, float(vp.width) / inputDesc.width,
float(vp.height) / inputDesc.height});
commitAndRenderFullScreenQuad(driver, out, mi);
unbindAllDescriptorSets(driver);
});
return ppQuadBlit->output;
@@ -3693,14 +3597,12 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::resolveDepth(FrameGraph& fg,
},
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
auto const& input = resources.getTexture(data.input);
auto const& material = getPostProcessMaterial("resolveDepth");
FMaterialInstance* const mi =
getMaterialInstance(mEngine, material);
mi->setParameter("depth", input, {}); // NEAREST
commitAndRenderFullScreenQuad(driver, resources.getRenderPassInfo(), mi);
unbindAllDescriptorSets(driver);
});
return ppResolve->output;
@@ -3732,7 +3634,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::vsmMipmapPass(FrameGraph& fg
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
auto in = driver.createTextureView(resources.getTexture(data.in), level, 1);
auto out = resources.getRenderPassInfo();
@@ -3761,7 +3662,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::vsmMipmapPass(FrameGraph& fg
mi->use(driver);
renderFullScreenQuadWithScissor(out, pipeline, scissor, driver);
unbindAllDescriptorSets(driver);
driver.destroyTexture(in); // `in` is just a view on `data.in`
});
@@ -3789,7 +3689,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugShadowCascades(FrameGra
},
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
auto color = resources.getTexture(data.color);
auto depth = resources.getTexture(data.depth);
auto const out = resources.getRenderPassInfo();
@@ -3799,7 +3698,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugShadowCascades(FrameGra
mi->setParameter("color", color, {}); // nearest
mi->setParameter("depth", depth, {}); // nearest
commitAndRenderFullScreenQuad(driver, out, mi);
unbindAllDescriptorSets(driver);
});
return debugShadowCascadePass->output;
@@ -3836,7 +3734,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugCombineArrayTexture(Fra
},
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
auto color = resources.getTexture(data.input);
auto const& inputDesc = resources.getDescriptor(data.input);
auto out = resources.getRenderPassInfo();
@@ -3878,13 +3775,11 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugCombineArrayTexture(Fra
mi->setParameter("layerIndex", i);
mi->commit(driver);
renderFullScreenQuad(out, pipeline, driver);
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
// From the second draw, don't clear the targetbuffer.
out.params.flags.clear = TargetBufferFlags::NONE;
out.params.flags.discardStart = TargetBufferFlags::NONE;
out.params.viewport.left += out.params.viewport.width;
}
unbindAllDescriptorSets(driver);
});
return ppQuadBlit->output;
@@ -3919,7 +3814,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugDisplayShadowTexture(
},
[=](FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
bindPostProcessDescriptorSet(driver);
bindPerRenderableDescriptorSet(driver);
auto const out = resources.getRenderPassInfo();
auto in = resources.getTexture(data.depth);
auto const& material = getPostProcessMaterial("shadowmap");
@@ -3932,7 +3826,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::debugDisplayShadowTexture(
mi->setParameter("channel", (uint32_t)channel);
mi->setParameter("power", power);
commitAndRenderFullScreenQuad(driver, out, mi);
unbindAllDescriptorSets(driver);
});
input = shadomapDebugPass->color;
}
+2 -8
View File
@@ -114,7 +114,9 @@ public:
FrameGraphId<FrameGraphTexture> ssr(FrameGraph& fg,
RenderPassBuilder const& passBuilder,
FrameHistory const& frameHistory,
CameraInfo const& cameraInfo,
FrameGraphId<FrameGraphTexture> structure,
ScreenSpaceReflectionsOptions const& options,
FrameGraphTexture::Descriptor const& desc) noexcept;
// SSAO
@@ -393,9 +395,6 @@ public:
void resetForRender();
private:
static void unbindAllDescriptorSets(backend::DriverApi& driver) noexcept;
void bindPerRenderableDescriptorSet(backend::DriverApi& driver) noexcept;
// Helper to get a MaterialInstance from a FMaterial
// This currently just call FMaterial::getDefaultInstance().
@@ -414,11 +413,6 @@ private:
backend::VertexBufferInfoHandle mFullScreenQuadVbih;
backend::DescriptorSetLayoutHandle mPerRenderableDslh;
// We need to have a dummy descriptor set because each post processing pass is expected to have
// a descriptor set bound at the renderable bind point. But the set itself contains dummy
// values.
backend::DescriptorSetHandle mDummyPerRenderableDsh;
FEngine& mEngine;
mutable SsrPassDescriptorSet mSsrPassDescriptorSet;
+2 -3
View File
@@ -1067,8 +1067,7 @@ void RenderPass::Executor::execute(FEngine const& engine, DriverApi& driver,
// Each material has a per-material descriptor-set layout which encodes the
// material's parameters (ubo and samplers)
pipeline.pipelineLayout.setLayout[+DescriptorSetBindingPoints::PER_MATERIAL] =
ma->getDescriptorSetLayout(info.materialVariant).getHandle();
ma->getDescriptorSetLayout().getHandle();
if (UTILS_UNLIKELY(ma->getMaterialDomain() == MaterialDomain::POST_PROCESS)) {
// It is possible to get a post-process material here (even though it's
@@ -1092,7 +1091,7 @@ void RenderPass::Executor::execute(FEngine const& engine, DriverApi& driver,
}
// Each MaterialInstance has its own descriptor set. This binds it.
mi->use(driver, info.materialVariant);
mi->use(driver);
}
assert_invariant(ma);
+27 -22
View File
@@ -21,15 +21,11 @@
#include "details/Engine.h"
#include "details/View.h"
#include "ds/DescriptorSet.h"
#include "fg/FrameGraph.h"
#include "fg/FrameGraphId.h"
#include "fg/FrameGraphResources.h"
#include "fg/FrameGraphTexture.h"
#include <private/filament/EngineEnums.h>
#include <filament/Options.h>
#include <filament/RenderableManager.h>
#include <filament/Viewport.h>
@@ -117,7 +113,7 @@ RendererUtils::ColorPassOutput RendererUtils::colorPass(
clearDepthFlags = TargetBufferFlags::DEPTH;
clearStencilFlags = config.enabledStencilBuffer ?
TargetBufferFlags::STENCIL : TargetBufferFlags::NONE;
const char* const textureName = config.enabledStencilBuffer ?
const char* const name = config.enabledStencilBuffer ?
"Depth/Stencil Buffer" : "Depth Buffer";
bool const isES2 =
@@ -132,7 +128,7 @@ RendererUtils::ColorPassOutput RendererUtils::colorPass(
TextureFormat const format = config.enabledStencilBuffer ?
stencilFormat : depthOnlyFormat;
data.depth = builder.createTexture(textureName, {
data.depth = builder.createTexture(name, {
.width = colorBufferDesc.width,
.height = colorBufferDesc.height,
// If the color attachment requested MS, we assume this means the MS
@@ -208,23 +204,37 @@ RendererUtils::ColorPassOutput RendererUtils::colorPass(
view.prepareSSAO(data.ssao ?
resources.getTexture(data.ssao) : engine.getOneTextureArray());
// set screen-space reflections and screen-space refractions
view.prepareSSR(data.ssr ?
resources.getTexture(data.ssr) : engine.getOneTextureArray());
view.prepareShadowMapping(engine, view.getVsmShadowOptions().highPrecision);
// set shadow sampler
view.prepareShadow(data.shadows ?
resources.getTexture(data.shadows) :
(view.getShadowType() != ShadowType::PCF ?
engine.getOneTextureArray() : engine.getOneTextureArrayDepth()));
// set structure sampler
view.prepareStructure(data.structure ?
resources.getTexture(data.structure) : engine.getOneTexture());
// set shadow sampler
view.prepareShadowMapping(engine,
data.shadows
? resources.getTexture(data.shadows)
: (view.getShadowType() != ShadowType::PCF
? engine.getOneTextureArray()
: engine.getOneTextureArrayDepth()));
// set screen-space reflections and screen-space refractions
TextureHandle const ssr = data.ssr ?
resources.getTexture(data.ssr) : engine.getOneTextureArray();
view.commitDescriptorSet(driver);
view.prepareSSR(ssr, config.screenSpaceReflectionHistoryNotReady,
config.ssrLodOffset, view.getScreenSpaceReflectionsOptions());
// Note: here we can't use data.color's descriptor for the viewport because
// the actual viewport might be offset when the target is the swapchain.
// However, the width/height should be the same.
assert_invariant(
out.params.viewport.width == resources.getDescriptor(data.color).width);
assert_invariant(
out.params.viewport.height == resources.getDescriptor(data.color).height);
view.prepareViewport(static_cast<filament::Viewport&>(out.params.viewport),
config.logicalViewport);
view.commitUniformsAndSamplers(driver);
// TODO: this should be a parameter of FrameGraphRenderPass::Descriptor
out.params.clearStencil = config.clearStencil;
@@ -244,11 +254,6 @@ RendererUtils::ColorPassOutput RendererUtils::colorPass(
driver.beginRenderPass(out.target, out.params);
passExecutor.execute(engine, driver);
driver.endRenderPass();
// unbind all descriptor sets to avoid false dependencies with the next pass
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_VIEW);
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_RENDERABLE);
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
}
);
+4
View File
@@ -65,12 +65,16 @@ public:
math::float4 clearColor = {};
// Clear stencil
uint8_t clearStencil = 0u;
// Lod offset for the SSR passes
float ssrLodOffset;
// Contact shadow enabled?
bool hasContactShadows;
// Screen space reflections enabled
bool hasScreenSpaceReflectionsOrRefractions;
// Use a depth format with a stencil component.
bool enabledStencilBuffer;
// whether the screenspace reflections history buffer is initialized
bool screenSpaceReflectionHistoryNotReady;
};
struct ColorPassInput {
+4 -13
View File
@@ -23,7 +23,7 @@
#include <filament/LightManager.h>
#include <filament/Options.h>
#include <iterator>
#include <private/filament/EngineEnums.h>
#include "components/RenderableManager.h"
@@ -33,8 +33,6 @@
#include "details/Texture.h"
#include "details/View.h"
#include "ds/DescriptorSet.h"
#include "fg/FrameGraph.h"
#include "fg/FrameGraphId.h"
#include "fg/FrameGraphRenderPass.h"
@@ -59,7 +57,6 @@
#include <array>
#include <cmath>
#include <functional>
#include <iterator>
#include <limits>
#include <new>
#include <memory>
@@ -436,7 +433,6 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
// Finally update our UBO in one batch
if (mShadowUb.isDirty()) {
mShadowUb.clean();
driver.updateBufferObject(mShadowUbh,
mShadowUb.toBufferDescriptor(driver), 0);
}
@@ -564,19 +560,14 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
// if we know there are no visible shadows, we can skip rendering, but
// we need the render-pass to clear/initialize the shadow-map
// Note: this is always true for directional/cascade shadows.
if (ShadowMap const* const shadowMap = curr->shadowMap; shadowMap->hasVisibleShadows()) {
shadowMap->bind(driver);
curr->executor.overrideScissor(shadowMap->getScissor());
if (curr->shadowMap->hasVisibleShadows()) {
curr->shadowMap->bind(driver);
curr->executor.overrideScissor(curr->shadowMap->getScissor());
curr->executor.execute(engine, driver);
}
}
driver.endRenderPass();
// unbind all descriptor sets to avoid false dependencies with the next pass
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_VIEW);
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_RENDERABLE);
DescriptorSet::unbind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
});
first = last;
+14 -10
View File
@@ -465,9 +465,6 @@ void FEngine::init() {
}
mDefaultMaterial = downcast(defaultMaterialBuilder.build(*this));
}
// We must commit the default material instance here. It may not be used in a scene, but its
// descriptor set may still be used for shared variants.
mDefaultMaterial->getDefaultInstance()->commit(driverApi);
if (UTILS_UNLIKELY(getSupportedFeatureLevel() >= FeatureLevel::FEATURE_LEVEL_1)) {
mDefaultColorGrading = downcast(ColorGrading::Builder().build(*this));
@@ -1238,13 +1235,20 @@ bool FEngine::destroy(const FMaterialInstance* p) {
size_t const primitiveCount = rcm.getPrimitiveCount(ri, 0);
for (size_t j = 0; j < primitiveCount; j++) {
auto const* const mi = rcm.getMaterialInstanceAt(ri, 0, j);
auto const& featureFlags = features.engine.debug;
FILAMENT_FLAG_GUARDED_CHECK_PRECONDITION(
mi != p,
featureFlags.assert_material_instance_in_use)
<< "destroying MaterialInstance \"" << mi->getName()
<< "\" which is still in use by Renderable (entity=" << entity.getId()
<< ", instance=" << ri.asValue() << ", index=" << j << ")";
if (features.engine.debug.assert_material_instance_in_use) {
FILAMENT_CHECK_PRECONDITION(mi != p)
<< "destroying MaterialInstance \""
<< mi->getName() << "\" which is still in use by Renderable (entity="
<< entity.getId() << ", instance="
<< ri.asValue() << ", index=" << j << ")";
} else {
if (UTILS_UNLIKELY(mi == p)) {
LOG(ERROR) << "destroying MaterialInstance \"" << mi->getName()
<< "\" which is still in use by Renderable (entity="
<< entity.getId() << ", instance=" << ri.asValue()
<< ", index=" << j << ")";
}
}
}
}
}
-5
View File
@@ -731,8 +731,6 @@ public:
bool assert_vertex_buffer_count_exceeds_8 = CORRECTNESS_ASSERTION_DEFAULT;
bool assert_vertex_buffer_attribute_stride_mult_of_4 =
CORRECTNESS_ASSERTION_DEFAULT;
bool assert_material_instance_texture_descriptor_set_compatible =
CORRECTNESS_ASSERTION_DEFAULT;
} debug;
} engine;
struct {
@@ -785,9 +783,6 @@ public:
{ "backend.vulkan.enable_staging_buffer_bypass",
"vulkan: enable a staging bypass logic for unified memory architecture",
&features.backend.vulkan.enable_staging_buffer_bypass, false },
{ "engine.debug.assert_material_instance_texture_descriptor_set_compatible",
"Assert that the textures in a material instance are compatible with descriptor set.",
&features.engine.debug.assert_material_instance_texture_descriptor_set_compatible, false },
}};
utils::Slice<const FeatureFlag> getFeatureFlags() const noexcept {
+10 -5
View File
@@ -391,11 +391,16 @@ void FMaterial::terminate(FEngine& engine) {
auto const& materialInstanceResourceList = engine.getMaterialInstanceResourceList();
auto pos = materialInstanceResourceList.find(this);
if (UTILS_LIKELY(pos != materialInstanceResourceList.cend())) {
auto const& featureFlags = engine.features.engine.debug;
FILAMENT_FLAG_GUARDED_CHECK_PRECONDITION(pos->second.empty(),
featureFlags.assert_destroy_material_before_material_instance)
<< "destroying material \"" << this->getName().c_str_safe() << "\" but "
<< pos->second.size() << " instances still alive.";
if (engine.features.engine.debug.assert_destroy_material_before_material_instance) {
FILAMENT_CHECK_PRECONDITION(pos->second.empty())
<< "destroying material \"" << this->getName().c_str_safe() << "\" but "
<< pos->second.size() << " instances still alive.";
} else {
if (UTILS_UNLIKELY(!pos->second.empty())) {
LOG(ERROR) << "destroying material \"" << this->getName().c_str_safe() << "\" but "
<< pos->second.size() << " instances still alive.";
}
}
}
#if FILAMENT_ENABLE_MATDBG
+2 -29
View File
@@ -96,18 +96,8 @@ public:
DescriptorSetLayout const& getPerViewDescriptorSetLayout(
Variant const variant, bool const useVsmDescriptorSetLayout) const noexcept;
// Returns the layout that should be used when this material is bound to the pipeline for the
// given variant. Shared variants use the Engine's default material's variants, so we should
// also use the default material's layout.
DescriptorSetLayout const& getDescriptorSetLayout(Variant variant = {}) const noexcept {
if (!isSharedVariant(variant)) {
return mDescriptorSetLayout;
}
FMaterial const* const pDefaultMaterial = mEngine.getDefaultMaterial();
if (UTILS_UNLIKELY(!pDefaultMaterial)) {
return mDescriptorSetLayout;
}
return pDefaultMaterial->getDescriptorSetLayout();
DescriptorSetLayout const& getDescriptorSetLayout() const noexcept {
return mDescriptorSetLayout;
}
void compile(CompilerPriorityQueue priority,
@@ -160,23 +150,6 @@ public:
return mCachedPrograms[variant.key];
}
// MaterialInstance::use() binds descriptor sets before drawing. For shared variants,
// however, the material instance will call useShared() to bind the default material's sets
// instead.
// Returns true if this is a shared variant.
bool useShared(backend::DriverApi& driver, Variant variant) const noexcept {
if (!isSharedVariant(variant)) {
return false;
}
FMaterial const* const pDefaultMaterial = mEngine.getDefaultMaterial();
if (UTILS_UNLIKELY(!pDefaultMaterial)) {
return false;
}
FMaterialInstance const* const pDefaultInstance = pDefaultMaterial->getDefaultInstance();
pDefaultInstance->use(driver, variant);
return true;
}
[[nodiscard]]
backend::Handle<backend::HwProgram> getProgramWithMATDBG(Variant variant) const noexcept;
+4 -13
View File
@@ -222,7 +222,6 @@ void FMaterialInstance::commit(FEngine& engine) const {
void FMaterialInstance::commit(DriverApi& driver) const {
// update uniforms if needed
if (mUniforms.isDirty() || mHasStreamUniformAssociations) {
mUniforms.clean();
driver.updateBufferObject(mUbHandle, mUniforms.toBufferDescriptor(driver), 0);
}
if (!mTextureParameters.empty()) {
@@ -286,11 +285,9 @@ void FMaterialInstance::setParameterImpl(std::string_view const name,
DescriptorType const descriptorType = descriptorSetLayout.getDescriptorType(binding);
TextureType const textureType = texture->getTextureType();
SamplerType const samplerType = texture->getTarget();
auto const& featureFlags = mMaterial->getEngine().features.engine.debug;
FILAMENT_FLAG_GUARDED_CHECK_PRECONDITION(
DescriptorSet::isTextureCompatibleWithDescriptor(
textureType, samplerType, descriptorType),
featureFlags.assert_material_instance_texture_descriptor_set_compatible)
FILAMENT_CHECK_PRECONDITION(
DescriptorSet::isTextureCompatibleWithDescriptor(textureType, samplerType, descriptorType))
<< "Texture format " << int(texture->getFormat())
<< " of type " << to_string(textureType)
<< " with sampler type " << to_string(samplerType)
@@ -383,7 +380,7 @@ const char* FMaterialInstance::getName() const noexcept {
// ------------------------------------------------------------------------------------------------
void FMaterialInstance::use(FEngine::DriverApi& driver, Variant variant) const {
void FMaterialInstance::use(FEngine::DriverApi& driver) const {
if (UTILS_UNLIKELY(mMissingSamplerDescriptors.any())) {
std::call_once(mMissingSamplersFlag, [this] {
@@ -404,12 +401,6 @@ void FMaterialInstance::use(FEngine::DriverApi& driver, Variant variant) const {
mMissingSamplerDescriptors.clear();
}
// Checks if this variant is shared. If so, FMaterial takes responsibility for binding the
// descriptor sets.
if (mMaterial->useShared(driver, variant)) {
return;
}
mDescriptorSet.bind(driver, DescriptorSetBindingPoints::PER_MATERIAL);
}
+1 -3
View File
@@ -29,8 +29,6 @@
#include <filament/MaterialInstance.h>
#include <private/filament/Variant.h>
#include <backend/DriverEnums.h>
#include <backend/Handle.h>
@@ -73,7 +71,7 @@ public:
void commit(FEngine::DriverApi& driver) const;
void use(FEngine::DriverApi& driver, Variant variant = {}) const;
void use(FEngine::DriverApi& driver) const;
FMaterial const* getMaterial() const noexcept { return mMaterial; }
+39 -58
View File
@@ -574,20 +574,12 @@ void FRenderer::renderStandaloneView(FView const* view) {
1'000'000'000.0 / mDisplayInfo.refreshRate),
mFrameId);
// because we don't have a "present" call, we use flush so the driver can submit
// the command buffer; we do this before driver.endFrame() to mimic what would
// happen with Renderer::beginFrame/endFrame.
renderInternal(view, true);
renderInternal(view);
driver.endFrame(mFrameId);
// engine.flush() has already been called by renderInternal(), but we need an extra one
// 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.
// This is a workaround for internal bug b/361822355.
// TODO: properly address the bug and remove this workaround.
if (engine.getBackend() == Backend::VULKAN) {
engine.flushAndWait();
}
@@ -608,11 +600,11 @@ void FRenderer::render(FView const* view) {
assert_invariant(mSwapChain);
if (UTILS_LIKELY(view && view->getScene() && view->hasCamera())) {
renderInternal(view, false);
renderInternal(view);
}
}
void FRenderer::renderInternal(FView const* view, bool flush) {
void FRenderer::renderInternal(FView const* view) {
FEngine& engine = mEngine;
FILAMENT_CHECK_PRECONDITION(!view->hasPostProcessPass() ||
@@ -629,10 +621,6 @@ void FRenderer::renderInternal(FView const* view, bool flush) {
// execute the render pass
renderJob(rootArenaScope, const_cast<FView&>(*view));
if (flush) {
engine.getDriverApi().flush();
}
// make sure to flush the command buffer
engine.flush();
@@ -830,57 +818,29 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
xvp.bottom = int32_t(guardBand);
}
/*
* Frame graph
*/
FrameGraph fg(*mResourceAllocator,
isProtectedContent ? FrameGraph::Mode::PROTECTED : FrameGraph::Mode::UNPROTECTED);
auto& blackboard = fg.getBlackboard();
PostProcessManager::ScreenSpaceRefConfig const ssrConfig = PostProcessManager::prepareMipmapSSR(
fg, svp.width, svp.height,
ssReflectionsOptions.enabled ? TextureFormat::RGBA16F : TextureFormat::R11F_G11F_B10F,
view.getCameraUser().getFieldOfView(Camera::Fov::VERTICAL), scale);
/*
* Update the PER_VIEW UBO used for the color, ssr and postfx passes. This UBO is never
* updated again during the frame.
*/
auto [bias, derivativeScale] = prepareUpscaler(scale, taaOptions, dsrOptions);
view.prepare(engine, driver, rootArenaScope, svp, cameraInfo, getShaderUserTime(), needsAlphaChannel);
view.prepareLodBias(bias, derivativeScale);
view.prepareSSAO(aoOptions);
view.prepareSSR(engine, cameraInfo, ssrConfig.lodOffset, ssReflectionsOptions);
view.prepareShadowMapping();
// There might be a bug here with svp's origin; normally the origin could offset when the
// target is the swapchain (width/height are the same though). This would mean that we'd have
// to wait for the color pass to execute to set the viewport. For now, I wasn't able to
// get into such a case though.
view.prepareViewport(svp, xvp);
view.commitUniforms(driver);
/*
* Update the PER_VIEW UBO use for the structure pass. It never updated again after this point.
*/
view.prepare(engine, driver, rootArenaScope, svp, cameraInfo, getShaderUserTime(), needsAlphaChannel);
view.prepareLodBias(bias, derivativeScale);
// Set the PER_VIEW UBO for the passes that use the user materials, but are not the color pass
// (e.g. structure, ssao). The PER_VIEW UBO may be different because these passes don't run
// at the same resolution. We set only the values that are relevant to both user-materials
// and the concerned passes. The PER_VIEW UBO contains data that is needed by the user
// materials public APIs.
{ // the scope helps to guarantee that we're not modifying the descriptor-set later
StructureDescriptorSet& ds = ppm.getStructureDescriptorSet();
ds.prepareCamera(engine, cameraInfo);
ds.prepareTime(engine, getShaderUserTime());
ds.prepareViewport(svp, {
StructureDescriptorSet& descriptorSet = ppm.getStructureDescriptorSet();
descriptorSet.prepareCamera(engine, cameraInfo);
descriptorSet.prepareTime(engine, getShaderUserTime());
descriptorSet.prepareViewport(svp, {
int32_t(float(xvp.left) * aoOptions.resolution),
int32_t(float(xvp.bottom) * aoOptions.resolution),
uint32_t(float(xvp.width) * aoOptions.resolution),
uint32_t(float(xvp.height) * aoOptions.resolution) });
ds.prepareLodBias(bias, derivativeScale);
ds.prepareMaterialGlobals(view.getMaterialGlobals());
}
descriptorSet.prepareLodBias(bias, derivativeScale);
descriptorSet.prepareMaterialGlobals(view.getMaterialGlobals());
descriptorSet.commit(driver);
/*
* Allocate command buffer
@@ -914,6 +874,14 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
variant.setVsm(view.hasShadowing() && view.getShadowType() != ShadowType::PCF);
variant.setStereo(view.hasStereo());
/*
* Frame graph
*/
FrameGraph fg(*mResourceAllocator,
isProtectedContent ? FrameGraph::Mode::PROTECTED : FrameGraph::Mode::UNPROTECTED);
auto& blackboard = fg.getBlackboard();
/*
* Shadow pass
*/
@@ -989,7 +957,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
// the clearFlags and clearColor specified below will only apply when rendering into the
// temporary color buffer. In particular, they won't apply when rendering into the main
// swapchain (imported render target above)
RendererUtils::ColorPassConfig const config{
RendererUtils::ColorPassConfig config{
.physicalViewport = svp,
.logicalViewport = xvp,
.scale = scale,
@@ -998,6 +966,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
.clearFlags = getClearFlags(),
.clearColor = clearColor,
.clearStencil = clearStencil,
.ssrLodOffset = 0.0f,
.hasContactShadows = scene.hasContactShadows(),
// at this point we don't know if we have refraction, but that's handled later
.hasScreenSpaceReflectionsOrRefractions = ssReflectionsOptions.enabled,
@@ -1083,12 +1052,23 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
blackboard["ssao"] = ssao;
}
// --------------------------------------------------------------------------------------------
// prepare screen-space reflection/refraction passes
PostProcessManager::ScreenSpaceRefConfig const ssrConfig = PostProcessManager::prepareMipmapSSR(
fg, svp.width, svp.height,
ssReflectionsOptions.enabled ? TextureFormat::RGBA16F : TextureFormat::R11F_G11F_B10F,
view.getCameraUser().getFieldOfView(Camera::Fov::VERTICAL), config.scale);
config.ssrLodOffset = ssrConfig.lodOffset;
// --------------------------------------------------------------------------------------------
// screen-space reflections pass
if (ssReflectionsOptions.enabled) {
auto reflections = ppm.ssr(fg, passBuilder,
view.getFrameHistory(), structure,
view.getFrameHistory(), cameraInfo,
structure,
ssReflectionsOptions,
{ .width = svp.width, .height = svp.height });
if (UTILS_LIKELY(reflections)) {
@@ -1096,6 +1076,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
PostProcessManager::generateMipmapSSR(ppm, fg,
reflections, ssrConfig.reflection, false, ssrConfig);
}
config.screenSpaceReflectionHistoryNotReady = !reflections;
}
// --------------------------------------------------------------------------------------------
+1 -1
View File
@@ -189,7 +189,7 @@ private:
return mCommandsHighWatermark;
}
void renderInternal(FView const* view, bool flush);
void renderInternal(FView const* view);
void renderJob(RootArenaScope& rootArenaScope, FView& view);
static std::pair<float, math::float2> prepareUpscaler(math::float2 scale,
+1 -2
View File
@@ -446,8 +446,7 @@ void FScene::updateUBOs(
// We capture state shared between Scene and the update buffer callback, because the Scene could
// be destroyed before the callback executes.
std::weak_ptr<SharedState>* const weakShared =
new (std::nothrow) std::weak_ptr<SharedState>(mSharedState);
std::weak_ptr<SharedState>* const weakShared = new(std::nothrow) std::weak_ptr(mSharedState);
// update the UBO
driver.resetBufferObject(renderableUbh);
+15 -9
View File
@@ -158,11 +158,12 @@ VertexBuffer* VertexBuffer::Builder::build(Engine& engine) {
static_assert(DOCUMENTED_MAX_VERTEX_BUFFER_COUNT <= MAX_VERTEX_BUFFER_COUNT);
auto const& featureFlags = static_cast<FEngine*>(&engine)->features.engine.debug;
FILAMENT_FLAG_GUARDED_CHECK_PRECONDITION(
mImpl->mBufferCount <= DOCUMENTED_MAX_VERTEX_BUFFER_COUNT,
featureFlags.assert_vertex_buffer_count_exceeds_8)
<< "bufferCount cannot be more than " << DOCUMENTED_MAX_VERTEX_BUFFER_COUNT;
if (downcast(engine).features.engine.debug.assert_vertex_buffer_count_exceeds_8) {
FILAMENT_CHECK_PRECONDITION(mImpl->mBufferCount <= DOCUMENTED_MAX_VERTEX_BUFFER_COUNT)
<< "bufferCount cannot be more than " << DOCUMENTED_MAX_VERTEX_BUFFER_COUNT;
} else if (mImpl->mBufferCount > DOCUMENTED_MAX_VERTEX_BUFFER_COUNT) {
LOG(WARNING) << "bufferCount cannot be more than " << DOCUMENTED_MAX_VERTEX_BUFFER_COUNT;
}
// Next we check if any unused buffer slots have been allocated. This helps prevent errors
// because uploading to an unused slot can trigger undefined behavior in the backend.
@@ -176,10 +177,15 @@ VertexBuffer* VertexBuffer::Builder::build(Engine& engine) {
<< "attribute " << j << " offset=" << attributes[j].offset
<< " is not multiple of 4";
FILAMENT_FLAG_GUARDED_CHECK_PRECONDITION((attributes[j].stride & 0x3u) == 0,
featureFlags.assert_vertex_buffer_attribute_stride_mult_of_4)
<< "attribute " << j << " stride=" << +attributes[j].stride
<< " is not multiple of 4";
FEngine* fengine = static_cast<FEngine*>(&engine);
if (fengine->features.engine.debug.assert_vertex_buffer_attribute_stride_mult_of_4) {
FILAMENT_CHECK_PRECONDITION((attributes[j].stride & 0x3u) == 0)
<< "attribute " << j << " stride=" << attributes[j].stride
<< " is not multiple of 4";
} else if ((attributes[j].stride & 0x3u) != 0) {
LOG(WARNING) << "attribute " << j << " stride=" << attributes[j].stride
<< " is not multiple of 4";
}
if (engine.getActiveFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0) {
FILAMENT_CHECK_PRECONDITION(!(attributes[j].flags & Attribute::FLAG_INTEGER_TARGET))
+34 -113
View File
@@ -948,140 +948,61 @@ void FView::prepareSSAO(Handle<HwTexture> ssao) const noexcept {
getColorPassDescriptorSet().prepareSSAO(ssao, mAmbientOcclusionOptions);
}
void FView::prepareSSAO(AmbientOcclusionOptions const& options) const noexcept {
// High quality sampling is enabled only if AO itself is enabled and upsampling quality is at
// least set to high and of course only if upsampling is needed.
const bool highQualitySampling = options.upsampling >= QualityLevel::HIGH
&& options.resolution < 1.0f;
const float edgeDistance = 1.0f / options.bilateralThreshold;
auto& s = mUniforms.edit();
s.aoSamplingQualityAndEdgeDistance =
options.enabled ? (highQualitySampling ? edgeDistance : 0.0f) : -1.0f;
s.aoBentNormals = options.enabled && options.bentNormals ? 1.0f : 0.0f;
}
void FView::prepareSSR(Handle<HwTexture> ssr) const noexcept {
getColorPassDescriptorSet().prepareScreenSpaceRefraction(ssr);
}
void FView::prepareSSR(FEngine& engine, CameraInfo const& cameraInfo,
void FView::prepareSSR(Handle<HwTexture> ssr,
bool const disableSSR,
float const refractionLodOffset,
ScreenSpaceReflectionsOptions const& options) const noexcept {
auto const& ssr = getFrameHistory().getPrevious().ssr;
bool const disableSSR = !ssr.color.handle;
mat4 const& historyProjection = ssr.projection;
mat4f const& uvFromClipMatrix = engine.getUvFromClipMatrix();
mat4f const projection = cameraInfo.projection;
mat4 const userViewMatrix = cameraInfo.getUserViewMatrix();
// set screen-space reflections and screen-space refractions
mat4f const uvFromViewMatrix = uvFromClipMatrix * projection;
mat4f const reprojection = uvFromClipMatrix *
mat4f{ historyProjection * inverse(userViewMatrix) };
auto& s = mUniforms.edit();
s.ssrReprojection = reprojection;
s.ssrUvFromViewMatrix = uvFromViewMatrix;
s.ssrThickness = options.thickness;
s.ssrBias = options.bias;
s.ssrStride = options.stride;
s.refractionLodOffset = refractionLodOffset;
s.ssrDistance = (options.enabled && !disableSSR) ? options.maxDistance : 0.0f;
ScreenSpaceReflectionsOptions const& ssrOptions) const noexcept {
getColorPassDescriptorSet().prepareSSR(ssr, disableSSR, refractionLodOffset, ssrOptions);
}
void FView::prepareStructure(Handle<HwTexture> structure) const noexcept {
// sampler must be NEAREST
getColorPassDescriptorSet().prepareStructure(structure);
}
void FView::prepareShadowMapping(FEngine const& engine, Handle<HwTexture> texture) const noexcept {
void FView::prepareShadow(Handle<HwTexture> texture) const noexcept {
// when needsShadowMap() is not set, this method only just sets a dummy texture
// in the needed samplers (in that case `texture` is actually a dummy texture).
ShadowMapManager::ShadowMappingUniforms uniforms;
if (needsShadowMap()) {
uniforms = mShadowMapManager->getShadowMappingUniforms();
}
switch (mShadowType) {
case ShadowType::PCF:
getColorPassDescriptorSet().prepareShadowPCF(texture, uniforms);
break;
case ShadowType::VSM:
getColorPassDescriptorSet().prepareShadowVSM(texture, uniforms, mVsmShadowOptions);
break;
case ShadowType::DPCF:
getColorPassDescriptorSet().prepareShadowDPCF(texture, uniforms, mSoftShadowOptions);
break;
case ShadowType::PCSS:
getColorPassDescriptorSet().prepareShadowPCSS(texture, uniforms, mSoftShadowOptions);
break;
case ShadowType::PCFd:
getColorPassDescriptorSet().prepareShadowPCFDebug(texture, uniforms);
break;
}
}
void FView::prepareShadowMapping(FEngine const& engine, bool const highPrecision) const noexcept {
BufferObjectHandle ubo{ engine.getDummyUniformBuffer() };
if (mHasShadowing) {
assert_invariant(mShadowMapManager);
ubo = mShadowMapManager->getShadowUniformsHandle();
}
getColorPassDescriptorSet().prepareShadowMapping(ubo);
switch (mShadowType) {
case ShadowType::PCF:
getColorPassDescriptorSet().prepareShadowPCF(texture);
break;
case ShadowType::VSM:
getColorPassDescriptorSet().prepareShadowVSM(texture, mVsmShadowOptions);
break;
case ShadowType::DPCF:
getColorPassDescriptorSet().prepareShadowDPCF(texture);
break;
case ShadowType::PCSS:
getColorPassDescriptorSet().prepareShadowPCSS(texture);
break;
case ShadowType::PCFd:
getColorPassDescriptorSet().prepareShadowPCFDebug(texture);
break;
}
getColorPassDescriptorSet().prepareShadowMapping(ubo, highPrecision);
}
void FView::prepareShadowMapping() const noexcept {
ShadowMapManager::ShadowMappingUniforms uniforms{};
if (needsShadowMap()) {
uniforms = mShadowMapManager->getShadowMappingUniforms();
}
constexpr float low = 5.54f; // ~ std::log(std::numeric_limits<math::half>::max()) * 0.5f;
constexpr float high = 42.0f; // ~ std::log(std::numeric_limits<float>::max()) * 0.5f;
constexpr uint32_t SHADOW_SAMPLING_RUNTIME_PCF = 0u;
constexpr uint32_t SHADOW_SAMPLING_RUNTIME_EVSM = 1u;
constexpr uint32_t SHADOW_SAMPLING_RUNTIME_DPCF = 2u;
constexpr uint32_t SHADOW_SAMPLING_RUNTIME_PCSS = 3u;
auto& s = mUniforms.edit();
s.cascadeSplits = uniforms.cascadeSplits;
s.ssContactShadowDistance = uniforms.ssContactShadowDistance;
s.directionalShadows = int32_t(uniforms.directionalShadows);
s.cascades = int32_t(uniforms.cascades);
switch (mShadowType) {
case ShadowType::PCF:
s.shadowSamplingType = SHADOW_SAMPLING_RUNTIME_PCF;
break;
case ShadowType::VSM:
s.shadowSamplingType = SHADOW_SAMPLING_RUNTIME_EVSM;
s.vsmExponent = mVsmShadowOptions.highPrecision ? high : low;
s.vsmDepthScale = mVsmShadowOptions.minVarianceScale * 0.01f * s.vsmExponent;
s.vsmLightBleedReduction = mVsmShadowOptions.lightBleedReduction;
break;
case ShadowType::DPCF:
s.shadowSamplingType = SHADOW_SAMPLING_RUNTIME_DPCF;
s.shadowPenumbraRatioScale = mSoftShadowOptions.penumbraRatioScale;
break;
case ShadowType::PCSS:
s.shadowSamplingType = SHADOW_SAMPLING_RUNTIME_PCSS;
s.shadowPenumbraRatioScale = mSoftShadowOptions.penumbraRatioScale;
break;
case ShadowType::PCFd:
s.shadowSamplingType = SHADOW_SAMPLING_RUNTIME_PCF;
break;
}
}
void FView::commitUniforms(DriverApi& driver) const noexcept {
if (mUniforms.isDirty()) {
mUniforms.clean();
driver.updateBufferObject(mUniforms.getUboHandle(),
mUniforms.toBufferDescriptor(driver), 0);
}
}
void FView::commitDescriptorSet(DriverApi& driver) const noexcept {
void FView::commitUniformsAndSamplers(DriverApi& driver) const noexcept {
getColorPassDescriptorSet().commit(driver);
}
void FView::unbindSamplers(FEngine& engine) noexcept {
getColorPassDescriptorSet().unbindSamplers(engine);
}
void FView::commitFroxels(DriverApi& driverApi) const noexcept {
if (mHasDynamicLighting) {
mFroxelizer.commit(driverApi);
+7 -10
View File
@@ -173,19 +173,16 @@ public:
void prepareLighting(FEngine& engine, CameraInfo const& cameraInfo) noexcept;
void prepareSSAO(backend::Handle<backend::HwTexture> ssao) const noexcept;
void prepareSSAO(AmbientOcclusionOptions const& options) const noexcept;
void prepareSSR(backend::Handle<backend::HwTexture> ssr) const noexcept;
void prepareSSR(FEngine& engine, CameraInfo const& cameraInfo,
float refractionLodOffset, ScreenSpaceReflectionsOptions const& options) const noexcept;
void prepareSSR(backend::Handle<backend::HwTexture> ssr, bool disableSSR,
float refractionLodOffset,
ScreenSpaceReflectionsOptions const& ssrOptions) const noexcept;
void prepareStructure(backend::Handle<backend::HwTexture> structure) const noexcept;
void prepareShadowMapping(FEngine const& engine, backend::Handle<backend::HwTexture> structure) const noexcept;
void prepareShadowMapping() const noexcept;
void prepareShadow(backend::Handle<backend::HwTexture> structure) const noexcept;
void prepareShadowMapping(FEngine const& engine, bool highPrecision) const noexcept;
void commitFroxels(backend::DriverApi& driverApi) const noexcept;
void commitUniforms(backend::DriverApi& driver) const noexcept;
void commitDescriptorSet(backend::DriverApi& driver) const noexcept;
void commitUniformsAndSamplers(backend::DriverApi& driver) const noexcept;
void unbindSamplers(FEngine& engine) noexcept;
utils::JobSystem::Job* getFroxelizerSync() const noexcept { return mFroxelizerSync; }
void setFroxelizerSync(utils::JobSystem::Job* sync) noexcept { mFroxelizerSync = sync; }
+85 -6
View File
@@ -257,6 +257,7 @@ void ColorPassDescriptorSet::prepareFog(FEngine& engine, const CameraInfo& camer
void ColorPassDescriptorSet::prepareSSAO(Handle<HwTexture> ssao,
AmbientOcclusionOptions const& options) noexcept {
// High quality sampling is enabled only if AO itself is enabled and upsampling quality is at
// least set to high and of course only if upsampling is needed.
const bool highQualitySampling = options.upsampling >= QualityLevel::HIGH
@@ -267,6 +268,12 @@ void ColorPassDescriptorSet::prepareSSAO(Handle<HwTexture> ssao,
.filterMag = options.enabled && !highQualitySampling ?
SamplerMagFilter::LINEAR : SamplerMagFilter::NEAREST
});
const float edgeDistance = 1.0f / options.bilateralThreshold;
auto& s = mUniforms.edit();
s.aoSamplingQualityAndEdgeDistance =
options.enabled ? (highQualitySampling ? edgeDistance : 0.0f) : -1.0f;
s.aoBentNormals = options.enabled && options.bentNormals ? 1.0f : 0.0f;
}
void ColorPassDescriptorSet::prepareBlending(bool const needsAlphaChannel) noexcept {
@@ -278,11 +285,19 @@ void ColorPassDescriptorSet::prepareMaterialGlobals(
PerViewDescriptorSetUtils::prepareMaterialGlobals(mUniforms.edit(), materialGlobals);
}
void ColorPassDescriptorSet::prepareScreenSpaceRefraction(Handle<HwTexture> ssr) noexcept {
void ColorPassDescriptorSet::prepareSSR(Handle<HwTexture> ssr,
bool const disableSSR,
float const refractionLodOffset,
ScreenSpaceReflectionsOptions const& ssrOptions) noexcept {
setSampler(+PerViewBindingPoints::SSR, ssr, {
.filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_LINEAR
});
auto& s = mUniforms.edit();
s.refractionLodOffset = refractionLodOffset;
s.ssrDistance = (ssrOptions.enabled && !disableSSR) ? ssrOptions.maxDistance : 0.0f;
}
void ColorPassDescriptorSet::prepareStructure(Handle<HwTexture> structure) noexcept {
@@ -364,12 +379,27 @@ void ColorPassDescriptorSet::prepareDynamicLights(Froxelizer& froxelizer) noexce
s.lightFarAttenuationParams = 0.5f * float2{ 10.0f, 10.0f / (f * f) };
}
void ColorPassDescriptorSet::prepareShadowMapping(BufferObjectHandle shadowUniforms) noexcept {
void ColorPassDescriptorSet::prepareShadowMapping(BufferObjectHandle shadowUniforms, bool const highPrecision) noexcept {
auto& s = mUniforms.edit();
constexpr float low = 5.54f; // ~ std::log(std::numeric_limits<math::half>::max()) * 0.5f;
constexpr float high = 42.0f; // ~ std::log(std::numeric_limits<float>::max()) * 0.5f;
s.vsmExponent = highPrecision ? high : low;
setBuffer(+PerViewBindingPoints::SHADOWS, shadowUniforms, 0, sizeof(ShadowUib));
}
void ColorPassDescriptorSet::prepareShadowSampling(PerViewUib& uniforms,
ShadowMappingUniforms const& shadowMappingUniforms) noexcept {
uniforms.cascadeSplits = shadowMappingUniforms.cascadeSplits;
uniforms.ssContactShadowDistance = shadowMappingUniforms.ssContactShadowDistance;
uniforms.directionalShadows = int32_t(shadowMappingUniforms.directionalShadows);
uniforms.cascades = int32_t(shadowMappingUniforms.cascades);
}
void ColorPassDescriptorSet::prepareShadowVSM(Handle<HwTexture> texture,
ShadowMappingUniforms const& shadowMappingUniforms,
VsmShadowOptions const& options) noexcept {
constexpr float low = 5.54f; // ~ std::log(std::numeric_limits<math::half>::max()) * 0.5f;
constexpr float high = 42.0f; // ~ std::log(std::numeric_limits<float>::max()) * 0.5f;
SamplerMinFilter filterMin = SamplerMinFilter::LINEAR;
if (options.anisotropy > 0 || options.mipmapping) {
filterMin = SamplerMinFilter::LINEAR_MIPMAP_LINEAR;
@@ -380,9 +410,16 @@ void ColorPassDescriptorSet::prepareShadowVSM(Handle<HwTexture> texture,
.filterMin = filterMin,
.anisotropyLog2 = options.anisotropy,
});
auto& s = mUniforms.edit();
s.shadowSamplingType = SHADOW_SAMPLING_RUNTIME_EVSM;
s.vsmExponent = options.highPrecision ? high : low;
s.vsmDepthScale = options.minVarianceScale * 0.01f * s.vsmExponent;
s.vsmLightBleedReduction = options.lightBleedReduction;
prepareShadowSampling(s, shadowMappingUniforms);
}
void ColorPassDescriptorSet::prepareShadowPCF(Handle<HwTexture> texture) noexcept {
void ColorPassDescriptorSet::prepareShadowPCF(Handle<HwTexture> texture,
ShadowMappingUniforms const& shadowMappingUniforms) noexcept {
setSampler(+PerViewBindingPoints::SHADOW_MAP,
texture, {
.filterMag = SamplerMagFilter::LINEAR,
@@ -390,29 +427,71 @@ void ColorPassDescriptorSet::prepareShadowPCF(Handle<HwTexture> texture) noexcep
.compareMode = SamplerCompareMode::COMPARE_TO_TEXTURE,
.compareFunc = SamplerCompareFunc::GE
});
auto& s = mUniforms.edit();
s.shadowSamplingType = SHADOW_SAMPLING_RUNTIME_PCF;
prepareShadowSampling(s, shadowMappingUniforms);
}
void ColorPassDescriptorSet::prepareShadowDPCF(Handle<HwTexture> texture) noexcept {
void ColorPassDescriptorSet::prepareShadowDPCF(Handle<HwTexture> texture,
ShadowMappingUniforms const& shadowMappingUniforms,
SoftShadowOptions const& options) noexcept {
setSampler(+PerViewBindingPoints::SHADOW_MAP, texture, {});
auto& s = mUniforms.edit();
s.shadowSamplingType = SHADOW_SAMPLING_RUNTIME_DPCF;
s.shadowPenumbraRatioScale = options.penumbraRatioScale;
prepareShadowSampling(s, shadowMappingUniforms);
}
void ColorPassDescriptorSet::prepareShadowPCSS(Handle<HwTexture> texture) noexcept {
void ColorPassDescriptorSet::prepareShadowPCSS(Handle<HwTexture> texture,
ShadowMappingUniforms const& shadowMappingUniforms,
SoftShadowOptions const& options) noexcept {
setSampler(+PerViewBindingPoints::SHADOW_MAP, texture, {});
auto& s = mUniforms.edit();
s.shadowSamplingType = SHADOW_SAMPLING_RUNTIME_PCSS;
s.shadowPenumbraRatioScale = options.penumbraRatioScale;
prepareShadowSampling(s, shadowMappingUniforms);
}
void ColorPassDescriptorSet::prepareShadowPCFDebug(Handle<HwTexture> texture) noexcept {
void ColorPassDescriptorSet::prepareShadowPCFDebug(Handle<HwTexture> texture,
ShadowMappingUniforms const& shadowMappingUniforms) noexcept {
setSampler(+PerViewBindingPoints::SHADOW_MAP, texture, {
.filterMag = SamplerMagFilter::NEAREST,
.filterMin = SamplerMinFilter::NEAREST
});
auto& s = mUniforms.edit();
s.shadowSamplingType = SHADOW_SAMPLING_RUNTIME_PCF;
prepareShadowSampling(s, shadowMappingUniforms);
}
void ColorPassDescriptorSet::commit(DriverApi& driver) noexcept {
if (mUniforms.isDirty()) {
driver.updateBufferObject(mUniforms.getUboHandle(),
mUniforms.toBufferDescriptor(driver), 0);
}
for (size_t i = 0; i < DESCRIPTOR_LAYOUT_COUNT; i++) {
mDescriptorSet[i].commit(mDescriptorSetLayout[i], driver);
}
}
void ColorPassDescriptorSet::unbindSamplers(FEngine& engine) noexcept {
// this needs to reset the sampler that are only set in RendererUtils::colorPass(), because
// this descriptor-set is also used for ssr/picking/structure and these could be stale
// it would be better to use a separate descriptor-set for those two cases so that we don't
// have to do this
setBuffer(+PerViewBindingPoints::SHADOWS,
engine.getDummyUniformBuffer(), 0, sizeof(ShadowUib));
setSampler(+PerViewBindingPoints::STRUCTURE,
engine.getZeroTexture(), {});
setSampler(+PerViewBindingPoints::SHADOW_MAP,
engine.getOneTextureArrayDepth(), {});
setSampler(+PerViewBindingPoints::SSAO,
engine.getZeroTextureArray(), {});
setSampler(+PerViewBindingPoints::SSR,
engine.getZeroTextureArray(), {});
}
void ColorPassDescriptorSet::setSampler(descriptor_binding_t const binding,
TextureHandle th, SamplerParams const params) noexcept {
for (size_t i = 0; i < DESCRIPTOR_LAYOUT_COUNT; i++) {
+26 -7
View File
@@ -23,7 +23,6 @@
#include "TypedUniformBuffer.h"
#include <private/filament/EngineEnums.h>
#include <private/filament/UibStructs.h>
#include <backend/DriverEnums.h>
@@ -67,6 +66,11 @@ class ColorPassDescriptorSet {
using LightManagerInstance = utils::EntityInstance<LightManager>;
using TextureHandle = backend::Handle<backend::HwTexture>;
static constexpr uint32_t SHADOW_SAMPLING_RUNTIME_PCF = 0u;
static constexpr uint32_t SHADOW_SAMPLING_RUNTIME_EVSM = 1u;
static constexpr uint32_t SHADOW_SAMPLING_RUNTIME_DPCF = 2u;
static constexpr uint32_t SHADOW_SAMPLING_RUNTIME_PCSS = 3u;
public:
static uint8_t getIndex(bool lit, bool ssr, bool fog) noexcept;
@@ -108,9 +112,12 @@ public:
void prepareMaterialGlobals(std::array<math::float4, 4> const& materialGlobals) noexcept;
// screen-space reflection and/or refraction (SSR)
void prepareScreenSpaceRefraction(TextureHandle ssr) noexcept;
void prepareSSR(TextureHandle ssr,
bool disableSSR,
float refractionLodOffset,
ScreenSpaceReflectionsOptions const& ssrOptions) noexcept;
void prepareShadowMapping(backend::BufferObjectHandle shadowUniforms) noexcept;
void prepareShadowMapping(backend::BufferObjectHandle shadowUniforms, bool highPrecision) noexcept;
void prepareDirectionalLight(FEngine& engine, float exposure,
math::float3 const& sceneSpaceDirection, LightManagerInstance instance) noexcept;
@@ -121,19 +128,28 @@ public:
void prepareDynamicLights(Froxelizer& froxelizer) noexcept;
void prepareShadowVSM(TextureHandle texture,
ShadowMappingUniforms const& shadowMappingUniforms,
VsmShadowOptions const& options) noexcept;
void prepareShadowPCF(TextureHandle texture) noexcept;
void prepareShadowPCF(TextureHandle texture,
ShadowMappingUniforms const& shadowMappingUniforms) noexcept;
void prepareShadowDPCF(TextureHandle texture) noexcept;
void prepareShadowDPCF(TextureHandle texture,
ShadowMappingUniforms const& shadowMappingUniforms,
SoftShadowOptions const& options) noexcept;
void prepareShadowPCSS(TextureHandle texture) noexcept;
void prepareShadowPCSS(TextureHandle texture,
ShadowMappingUniforms const& shadowMappingUniforms,
SoftShadowOptions const& options) noexcept;
void prepareShadowPCFDebug(TextureHandle texture) noexcept;
void prepareShadowPCFDebug(TextureHandle texture,
ShadowMappingUniforms const& shadowMappingUniforms) noexcept;
// update local data into GPU UBO
void commit(backend::DriverApi& driver) noexcept;
void unbindSamplers(FEngine& engine) noexcept;
// bind this UBO
void bind(backend::DriverApi& driver, uint8_t const index) const noexcept {
mDescriptorSet[index].bind(driver, DescriptorSetBindingPoints::PER_VIEW);
@@ -150,6 +166,9 @@ private:
void setBuffer(backend::descriptor_binding_t binding,
backend::BufferObjectHandle boh, uint32_t offset, uint32_t size) noexcept;
static void prepareShadowSampling(PerViewUib& uniforms,
ShadowMappingUniforms const& shadowMappingUniforms) noexcept;
TypedUniformBuffer<PerViewUib>& mUniforms;
std::array<DescriptorSetLayout, DESCRIPTOR_LAYOUT_COUNT> mDescriptorSetLayout;
std::array<DescriptorSet, DESCRIPTOR_LAYOUT_COUNT> mDescriptorSet;
-5
View File
@@ -139,11 +139,6 @@ void DescriptorSet::bind(FEngine::DriverApi& driver, DescriptorSetBindingPoints
driver.bindDescriptorSet(mDescriptorSetHandle, +set, std::move(dynamicOffsets));
}
void DescriptorSet::unbind(backend::DriverApi& driver,
DescriptorSetBindingPoints set) noexcept {
driver.bindDescriptorSet({}, +set, {});
}
void DescriptorSet::setBuffer(DescriptorSetLayout const& layout,
backend::descriptor_binding_t const binding,
backend::Handle<backend::HwBufferObject> boh, uint32_t const offset, uint32_t const size) {
-3
View File
@@ -62,9 +62,6 @@ public:
void bind(backend::DriverApi& driver, DescriptorSetBindingPoints set,
backend::DescriptorSetOffsetArray dynamicOffsets) const noexcept;
// unbind the descriptor set
static void unbind(backend::DriverApi& driver, DescriptorSetBindingPoints set) noexcept;
// sets a ubo/ssbo descriptor
void setBuffer(DescriptorSetLayout const& layout,
backend::descriptor_binding_t binding,
+21 -1
View File
@@ -66,14 +66,29 @@ void SsrPassDescriptorSet::setFrameUniforms(FEngine const& engine,
// and GL would be okay without this, but Vulkan's validation layer would complain.
mDescriptorSet.setBuffer(engine.getPerViewDescriptorSetLayoutSsrVariant(),
+PerViewBindingPoints::SHADOWS, mShadowUbh, 0, sizeof(ShadowUib));
mUniforms = std::addressof(uniforms);
}
void SsrPassDescriptorSet::prepareHistorySSR(FEngine const& engine, Handle<HwTexture> ssr) noexcept {
void SsrPassDescriptorSet::prepareHistorySSR(FEngine const& engine, Handle<HwTexture> ssr,
mat4f const& historyProjection,
mat4f const& uvFromViewMatrix,
ScreenSpaceReflectionsOptions const& ssrOptions) noexcept {
mDescriptorSet.setSampler(engine.getPerViewDescriptorSetLayoutSsrVariant(),
+PerViewBindingPoints::SSR_HISTORY, ssr, {
.filterMag = SamplerMagFilter::LINEAR,
.filterMin = SamplerMinFilter::LINEAR
});
assert_invariant(mUniforms);
auto& s = mUniforms->edit();
s.ssrReprojection = historyProjection;
s.ssrUvFromViewMatrix = uvFromViewMatrix;
s.ssrThickness = ssrOptions.thickness;
s.ssrBias = ssrOptions.bias;
s.ssrDistance = ssrOptions.enabled ? ssrOptions.maxDistance : 0.0f;
s.ssrStride = ssrOptions.stride;
}
void SsrPassDescriptorSet::prepareStructure(FEngine const& engine,
@@ -84,7 +99,12 @@ void SsrPassDescriptorSet::prepareStructure(FEngine const& engine,
}
void SsrPassDescriptorSet::commit(FEngine& engine) noexcept {
assert_invariant(mUniforms);
DriverApi& driver = engine.getDriverApi();
if (mUniforms->isDirty()) {
driver.updateBufferObject(mUniforms->getUboHandle(),
mUniforms->toBufferDescriptor(driver), 0);
}
mDescriptorSet.commit(engine.getPerViewDescriptorSetLayoutSsrVariant(), driver);
}
+10 -1
View File
@@ -19,6 +19,8 @@
#include "DescriptorSet.h"
#include "DescriptorSetLayout.h"
#include "TypedUniformBuffer.h"
#include <private/filament/UibStructs.h>
@@ -26,6 +28,8 @@
#include <backend/DriverApiForward.h>
#include <backend/Handle.h>
#include <math/mat4.h>
namespace filament {
class FEngine;
@@ -47,7 +51,11 @@ public:
void prepareStructure(FEngine const& engine, TextureHandle structure) noexcept;
void prepareHistorySSR(FEngine const& engine, TextureHandle ssr) noexcept;
void prepareHistorySSR(FEngine const& engine, TextureHandle ssr,
math::mat4f const& historyProjection,
math::mat4f const& uvFromViewMatrix,
ScreenSpaceReflectionsOptions const& ssrOptions) noexcept;
// update local data into GPU UBO
void commit(FEngine& engine) noexcept;
@@ -56,6 +64,7 @@ public:
void bind(backend::DriverApi& driver) noexcept;
private:
TypedUniformBuffer<PerViewUib>* mUniforms = nullptr;
DescriptorSet mDescriptorSet;
backend::BufferObjectHandle mShadowUbh;
};
+7 -7
View File
@@ -63,14 +63,14 @@ void StructureDescriptorSet::terminate(DriverApi& driver) {
mUniforms.terminate(driver);
}
void StructureDescriptorSet::bind(DriverApi& driver) const noexcept {
void StructureDescriptorSet::commit(DriverApi& driver) noexcept {
assert_invariant(mDescriptorSetLayout);
if (mUniforms.isDirty()) {
mUniforms.clean();
driver.updateBufferObject(mUniforms.getUboHandle(),
mUniforms.toBufferDescriptor(driver), 0);
mDescriptorSet.commit(*mDescriptorSetLayout, driver);
}
driver.updateBufferObject(mUniforms.getUboHandle(),
mUniforms.toBufferDescriptor(driver), 0);
mDescriptorSet.commit(*mDescriptorSetLayout, driver);
}
void StructureDescriptorSet::bind(DriverApi& driver) const noexcept {
mDescriptorSet.bind(driver, DescriptorSetBindingPoints::PER_VIEW);
}
+3 -2
View File
@@ -45,7 +45,8 @@ public:
void terminate(backend::DriverApi& driver);
// this commits the UBO if needed and binds the descriptor set
void commit(backend::DriverApi& driver) noexcept;
void bind(backend::DriverApi& driver) const noexcept;
@@ -64,7 +65,7 @@ public:
private:
DescriptorSetLayout const* mDescriptorSetLayout = nullptr;
mutable DescriptorSet mDescriptorSet;
DescriptorSet mDescriptorSet;
TypedUniformBuffer<PerViewUib> mUniforms;
};
+1 -2
View File
@@ -4,8 +4,7 @@ material {
{
type : sampler2dArray,
name : shadowmap,
precision : high,
filterable : false
precision : high
},
{
type : float,
@@ -4,8 +4,7 @@ material {
{
type : sampler2dArray,
name : ssao,
precision: medium,
filterable: false
precision: medium
},
{
type : float2,
@@ -4,8 +4,7 @@ material {
{
type : sampler2dArray,
name : ssao,
precision: medium,
filterable: false
precision: medium
},
{
type : float2,
@@ -5,7 +5,7 @@ material {
type : sampler2d,
name : depth,
precision: high,
filterable: false
unfilterable: true
},
{
type : mat4,
+2 -2
View File
@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.63.1"
spec.version = "1.62.1"
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
spec.homepage = "https://google.github.io/filament"
spec.authors = "Google LLC."
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
spec.platform = :ios, "11.0"
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.63.1/filament-v1.63.1-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.62.1/filament-v1.62.1-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {
@@ -28,7 +28,7 @@
namespace filament {
// update this when a new version of filament wouldn't work with older materials
static constexpr size_t MATERIAL_VERSION = 63;
static constexpr size_t MATERIAL_VERSION = 62;
/**
* Supported shading models
+2 -3
View File
@@ -539,14 +539,13 @@ io::sstream& CodeGenerator::generateOutput(io::sstream& out, ShaderStage stage,
const char* swizzleString = "";
// Metal and WebGPU don't support some 3-component texture formats, so the backend uses 4-component
// Metal doesn't support some 3-component texture formats, so the backend uses 4-component
// formats behind the scenes. It's an error to output fewer components than the attachment
// needs, so we always output a float4 instead of a float3. It's never an error to output extra
// components.
//
// Meanwhile, ESSL 1.0 must always write to gl_FragColor, a vec4.
if (mTargetApi == TargetApi::METAL || mTargetApi == TargetApi::WEBGPU ||
mFeatureLevel == FeatureLevel::FEATURE_LEVEL_0) {
if (mTargetApi == TargetApi::METAL || mFeatureLevel == FeatureLevel::FEATURE_LEVEL_0) {
if (outputType == MaterialBuilder::OutputType::FLOAT3) {
outputType = MaterialBuilder::OutputType::FLOAT4;
swizzleString = ".rgb";
-68
View File
@@ -1,68 +0,0 @@
cmake_minimum_required(VERSION 3.19)
project(matp)
set(TARGET matp)
set(PUBLIC_HDR_DIR include)
# ==================================================================================================
# Sources and headers
# ==================================================================================================
set(PUBLIC_HDRS
include/filament-matp/Config.h
include/filament-matp/MaterialParser.h
)
set(SRCS
src/DirIncluder.h
src/JsonishLexeme.h
src/JsonishLexer.h
src/JsonishParser.h
src/Lexeme.h
src/Lexer.h
src/MaterialLexeme.h
src/MaterialLexer.h
src/ParametersProcessor.h
src/DirIncluder.cpp
src/JsonishLexer.cpp
src/JsonishParser.cpp
src/MaterialLexer.cpp
src/MaterialParser.cpp
src/ParametersProcessor.cpp
)
# ==================================================================================================
# Include and target definitions
# ==================================================================================================
include_directories(${PUBLIC_HDR_DIR})
add_library(${TARGET} STATIC ${PUBLIC_HDRS} ${SRCS})
target_include_directories(${TARGET} PUBLIC ${PUBLIC_HDR_DIR})
target_include_directories(${TARGET} PRIVATE ${filamat_SOURCE_DIR}/src)
set_target_properties(${TARGET} PROPERTIES FOLDER Libs)
target_link_libraries(${TARGET} getopt filamat filabridge utils)
# ==================================================================================================
# Installation
# ==================================================================================================
install(TARGETS ${TARGET} ARCHIVE DESTINATION lib/${DIST_DIR})
install(DIRECTORY ${PUBLIC_HDR_DIR}/ DESTINATION include)
# ==================================================================================================
# Tests
# ==================================================================================================
project(test_matp)
set(TARGET test_matp)
set(SRCS
tests/test_matp.cpp
tests/test_includer.cpp
tests/TestMaterialParser.h
tests/test_compute_material.cpp
)
add_executable(${TARGET} ${SRCS})
target_link_libraries(${TARGET} matp gtest)
set_target_properties(test_matp PROPERTIES FOLDER Tests)
@@ -1,96 +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_MATERIALPARSER_H
#define TNT_MATERIALPARSER_H
#include <string>
#include <unordered_map>
#include "Config.h"
namespace filamat {
class MaterialBuilder;
}
class TestMaterialParser;
namespace matp {
class JsonishValue;
class MaterialLexeme;
class MaterialParser {
public:
MaterialParser();
// Parses a string material so that it can be used in MaterialBuilder.
// Call MaterialBuilder::init before passing in the builder; call MaterialBuilder::build to
// create filamat::Package after.
bool parse(
filamat::MaterialBuilder& builder,
const Config& config,
Config::Input* input, ssize_t& size, std::unique_ptr<const char[]>& buffer);
// Replaces macro keywords with user specified ones. Must be called before parse.
bool processTemplateSubstitutions(
const Config& config, ssize_t& size, std::unique_ptr<const char[]>& buffer);
private:
friend class ::TestMaterialParser;
bool parseMaterial(const char* buffer, size_t size,
filamat::MaterialBuilder& builder) const noexcept;
bool processMaterial(const MaterialLexeme&,
filamat::MaterialBuilder& builder) const noexcept;
bool processVertexShader(const MaterialLexeme&,
filamat::MaterialBuilder& builder) const noexcept;
bool processFragmentShader(const MaterialLexeme&,
filamat::MaterialBuilder& builder) const noexcept;
bool processComputeShader(const MaterialLexeme&,
filamat::MaterialBuilder& builder) const noexcept;
bool ignoreLexeme(const MaterialLexeme&, filamat::MaterialBuilder& builder) const noexcept;
bool parseMaterialAsJSON(const char* buffer, size_t size,
filamat::MaterialBuilder& builder) const noexcept;
bool processMaterialJSON(const JsonishValue*,
filamat::MaterialBuilder& builder) const noexcept;
bool processVertexShaderJSON(const JsonishValue*,
filamat::MaterialBuilder& builder) const noexcept;
bool processFragmentShaderJSON(const JsonishValue*,
filamat::MaterialBuilder& builder) const noexcept;
bool processComputeShaderJSON(const JsonishValue*,
filamat::MaterialBuilder& builder) const noexcept;
bool ignoreLexemeJSON(const JsonishValue*, filamat::MaterialBuilder& builder) const noexcept;
bool isValidJsonStart(const char* buffer, size_t size) const noexcept;
bool processMaterialParameters(filamat::MaterialBuilder& builder, const Config& config) const;
// Member function pointer type, this is used to implement a Command design
// pattern.
using MaterialConfigProcessor = bool (MaterialParser::*)
(const MaterialLexeme&, filamat::MaterialBuilder& builder) const;
// Map used to store Command pattern function pointers.
std::unordered_map<std::string, MaterialConfigProcessor> mConfigProcessor;
// The same, but for pure JSON syntax
using MaterialConfigProcessorJSON = bool (MaterialParser::*)
(const JsonishValue*, filamat::MaterialBuilder& builder) const;
std::unordered_map<std::string, MaterialConfigProcessorJSON> mConfigProcessorJSON;
};
} // namespace matp
#endif // TNT_MATERIALPARSER_H
-521
View File
@@ -1,521 +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 <filament-matp/MaterialParser.h>
#include <memory>
#include <iostream>
#include <utility>
#include <filamat/MaterialBuilder.h>
#include <filamat/Enums.h>
#include <utils/Log.h>
#include <utils/JobSystem.h>
#include "DirIncluder.h"
#include "JsonishLexer.h"
#include "JsonishParser.h"
#include "MaterialLexeme.h"
#include "MaterialLexer.h"
#include "ParametersProcessor.h"
#include <filament-matp/Config.h>
using namespace utils;
using namespace filamat;
using namespace std::placeholders;
namespace matp {
static constexpr const char* CONFIG_KEY_MATERIAL= "material";
static constexpr const char* CONFIG_KEY_VERTEX_SHADER = "vertex";
static constexpr const char* CONFIG_KEY_FRAGMENT_SHADER = "fragment";
static constexpr const char* CONFIG_KEY_COMPUTE_SHADER = "compute";
static constexpr const char* CONFIG_KEY_TOOL = "tool";
MaterialParser::MaterialParser() {
mConfigProcessor[CONFIG_KEY_MATERIAL] = &MaterialParser::processMaterial;
mConfigProcessor[CONFIG_KEY_VERTEX_SHADER] = &MaterialParser::processVertexShader;
mConfigProcessor[CONFIG_KEY_FRAGMENT_SHADER] = &MaterialParser::processFragmentShader;
mConfigProcessor[CONFIG_KEY_COMPUTE_SHADER] = &MaterialParser::processComputeShader;
mConfigProcessor[CONFIG_KEY_TOOL] = &MaterialParser::ignoreLexeme;
mConfigProcessorJSON[CONFIG_KEY_MATERIAL] = &MaterialParser::processMaterialJSON;
mConfigProcessorJSON[CONFIG_KEY_VERTEX_SHADER] = &MaterialParser::processVertexShaderJSON;
mConfigProcessorJSON[CONFIG_KEY_FRAGMENT_SHADER] = &MaterialParser::processFragmentShaderJSON;
mConfigProcessorJSON[CONFIG_KEY_COMPUTE_SHADER] = &MaterialParser::processComputeShaderJSON;
mConfigProcessorJSON[CONFIG_KEY_TOOL] = &MaterialParser::ignoreLexemeJSON;
}
bool MaterialParser::processMaterial(const MaterialLexeme& jsonLexeme,
MaterialBuilder& builder) const noexcept {
JsonishLexer jlexer;
jlexer.lex(jsonLexeme.getStart(), jsonLexeme.getSize(), jsonLexeme.getLine());
JsonishParser parser(jlexer.getLexemes());
std::unique_ptr<JsonishObject> const json = parser.parse();
if (json == nullptr) {
std::cerr << "JsonishParser error (see above)." << std::endl;
return false;
}
ParametersProcessor parametersProcessor;
bool const ok = parametersProcessor.process(builder, *json);
if (!ok) {
std::cerr << "Error while processing material." << std::endl;
return false;
}
return true;
}
bool MaterialParser::processVertexShader(const MaterialLexeme& lexeme,
MaterialBuilder& builder) const noexcept {
MaterialLexeme const trimmedLexeme = lexeme.trimBlockMarkers();
std::string const shaderStr = trimmedLexeme.getStringValue();
// getLine() returns a line number, with 1 being the first line, but .material wants a 0-based
// line number offset, where 0 is the first line.
builder.materialVertex(shaderStr.c_str(), trimmedLexeme.getLine() - 1);
return true;
}
bool MaterialParser::processFragmentShader(const MaterialLexeme& lexeme,
MaterialBuilder& builder) const noexcept {
MaterialLexeme const trimmedLexeme = lexeme.trimBlockMarkers();
std::string const shaderStr = trimmedLexeme.getStringValue();
// getLine() returns a line number, with 1 being the first line, but .material wants a 0-based
// line number offset, where 0 is the first line.
builder.material(shaderStr.c_str(), trimmedLexeme.getLine() - 1);
return true;
}
bool MaterialParser::processComputeShader(const MaterialLexeme& lexeme,
MaterialBuilder& builder) const noexcept {
return MaterialParser::processFragmentShader(lexeme, builder);
}
bool MaterialParser::ignoreLexeme(const MaterialLexeme&, MaterialBuilder&) const noexcept {
return true;
}
static bool reflectParameters(const MaterialBuilder& builder) {
uint8_t const count = builder.getParameterCount();
const MaterialBuilder::ParameterList& parameters = builder.getParameters();
std::cout << "{" << std::endl;
std::cout << " \"parameters\": [" << std::endl;
for (uint8_t i = 0; i < count; i++) {
const MaterialBuilder::Parameter& parameter = parameters[i];
std::cout << " {" << std::endl;
std::cout << R"( "name": ")" << parameter.name.c_str() << "\"," << std::endl;
if (parameter.isSampler()) {
std::cout << R"( "type": ")" <<
Enums::toString(parameter.samplerType) << "\"," << std::endl;
std::cout << R"( "format": ")" <<
Enums::toString(parameter.format) << "\"," << std::endl;
std::cout << R"( "precision": ")" <<
Enums::toString(parameter.precision) << "\"," << std::endl;
std::cout << R"( "multisample": ")" <<
(parameter.multisample ? "true" : "false")<< "\"" << std::endl;
} else if (parameter.isUniform()) {
std::cout << R"( "type": ")" <<
Enums::toString(parameter.uniformType) << "\"," << std::endl;
std::cout << R"( "size": ")" << parameter.size << "\"" << std::endl;
} else if (parameter.isSubpass()) {
std::cout << R"( "type": ")" <<
Enums::toString(parameter.subpassType) << "\"," << std::endl;
std::cout << R"( "format": ")" <<
Enums::toString(parameter.format) << "\"," << std::endl;
std::cout << R"( "precision": ")" <<
Enums::toString(parameter.precision) << "\"" << std::endl;
}
std::cout << " }";
if (i < count - 1) std::cout << ",";
std::cout << std::endl;
}
std::cout << " ]" << std::endl;
std::cout << "}" << std::endl;
return true;
}
bool MaterialParser::processMaterialJSON(const JsonishValue* value,
filamat::MaterialBuilder& builder) const noexcept {
if (!value) {
std::cerr << "'material' block does not have a value, one is required." << std::endl;
return false;
}
if (value->getType() != JsonishValue::OBJECT) {
std::cerr << "'material' block has an invalid type: "
<< JsonishValue::typeToString(value->getType())
<< ", should be OBJECT."
<< std::endl;
return false;
}
ParametersProcessor parametersProcessor;
bool const ok = parametersProcessor.process(builder, *value->toJsonObject());
if (!ok) {
std::cerr << "Error while processing material." << std::endl;
return false;
}
return true;
}
bool MaterialParser::processVertexShaderJSON(const JsonishValue* value,
filamat::MaterialBuilder& builder) const noexcept {
if (!value) {
std::cerr << "'vertex' block does not have a value, one is required." << std::endl;
return false;
}
if (value->getType() != JsonishValue::STRING) {
std::cerr << "'vertex' block has an invalid type: "
<< JsonishValue::typeToString(value->getType())
<< ", should be STRING."
<< std::endl;
return false;
}
builder.materialVertex(value->toJsonString()->getString().c_str());
return true;
}
bool MaterialParser::processFragmentShaderJSON(const JsonishValue* value,
filamat::MaterialBuilder& builder) const noexcept {
if (!value) {
std::cerr << "'fragment' block does not have a value, one is required." << std::endl;
return false;
}
if (value->getType() != JsonishValue::STRING) {
std::cerr << "'fragment' block has an invalid type: "
<< JsonishValue::typeToString(value->getType())
<< ", should be STRING."
<< std::endl;
return false;
}
builder.material(value->toJsonString()->getString().c_str());
return true;
}
bool MaterialParser::processComputeShaderJSON(const JsonishValue* value,
filamat::MaterialBuilder& builder) const noexcept {
if (!value) {
std::cerr << "'compute' block does not have a value, one is required." << std::endl;
return false;
}
if (value->getType() != JsonishValue::STRING) {
std::cerr << "'compute' block has an invalid type: "
<< JsonishValue::typeToString(value->getType())
<< ", should be STRING."
<< std::endl;
return false;
}
builder.material(value->toJsonString()->getString().c_str());
return true;
}
bool MaterialParser::ignoreLexemeJSON(const JsonishValue*,
filamat::MaterialBuilder&) const noexcept {
return true;
}
bool MaterialParser::isValidJsonStart(const char* buffer, size_t size) const noexcept {
// Skip all whitespace characters.
const char* end = buffer + size;
while (buffer != end && isspace(buffer[0])) {
buffer++;
}
// A buffer made only of whitespace is not a valid JSON start.
if (buffer == end) {
return false;
}
const char c = buffer[0];
// Take care of block, array, and string
if (c == '{' || c == '[' || c == '"') {
return true;
}
// boolean true
if (c == 't' && (end - buffer) > 3 && strncmp(buffer, "true", 4) != 0) {
return true;
}
// boolean false
if (c == 'f' && (end - buffer) > 4 && strncmp(buffer, "false", 5) != 0) {
return true;
}
// null literal
return c == 'n' && (end - buffer) > 3 && strncmp(buffer, "null", 5) != 0;
}
bool MaterialParser::parseMaterialAsJSON(const char* buffer, size_t size,
filamat::MaterialBuilder& builder) const noexcept {
JsonishLexer jlexer;
jlexer.lex(buffer, size, 1);
JsonishParser parser(jlexer.getLexemes());
std::unique_ptr<JsonishObject> json = parser.parse();
if (json == nullptr) {
std::cerr << "Could not parse JSON material file" << std::endl;
return false;
}
for (auto& entry : json->getEntries()) {
const std::string& key = entry.first;
if (mConfigProcessorJSON.find(key) == mConfigProcessorJSON.end()) {
std::cerr << "Unknown identifier '" << key << "'" << std::endl;
return false;
}
// Retrieve function member pointer
MaterialConfigProcessorJSON const p = mConfigProcessorJSON.at(key);
// Call it.
bool const ok = (*this.*p)(entry.second, builder);
if (!ok) {
std::cerr << "Error while processing block with key:'" << key << "'" << std::endl;
return false;
}
}
return true;
}
bool MaterialParser::parseMaterial(const char* buffer, size_t size,
filamat::MaterialBuilder& builder) const noexcept {
MaterialLexer materialLexer;
materialLexer.lex(buffer, size);
auto lexemes = materialLexer.getLexemes();
// Make sure the lexer did not stumble upon unknown character. This could mean we received
// a binary file.
for (auto lexeme : lexemes) {
if (lexeme.getType() == MaterialType::UNKNOWN) {
std::cerr << "Unexpected character at line:" << lexeme.getLine()
<< " position:" << lexeme.getLinePosition() << std::endl;
return false;
}
}
// Make a first quick pass just to make sure the format was respected (the material format is
// a series of IDENTIFIER, BLOCK pairs).
if (lexemes.size() < 2) {
std::cerr << "Input MUST be an alternation of [identifier, block] pairs." << std::endl;
return false;
}
for (size_t i = 0; i < lexemes.size(); i += 2) {
auto lexeme = lexemes.at(i);
if (lexeme.getType() != MaterialType::IDENTIFIER) {
std::cerr << "An identifier was expected at line:" << lexeme.getLine()
<< " position:" << lexeme.getLinePosition() << std::endl;
return false;
}
if (i == lexemes.size() - 1) {
std::cerr << "Identifier at line:" << lexeme.getLine()
<< " position:" << lexeme.getLinePosition()
<< " must be followed by a block." << std::endl;
return false;
}
auto nextLexeme = lexemes.at(i + 1);
if (nextLexeme.getType() != MaterialType::BLOCK) {
std::cerr << "A block was expected at line:" << lexeme.getLine()
<< " position:" << lexeme.getLinePosition() << std::endl;
return false;
}
}
std::string identifier;
for (auto lexeme : lexemes) {
if (lexeme.getType() == MaterialType::IDENTIFIER) {
identifier = lexeme.getStringValue();
if (mConfigProcessor.find(identifier) == mConfigProcessor.end()) {
std::cerr << "Unknown identifier '"
<< lexeme.getStringValue()
<< "' at line:" << lexeme.getLine()
<< " position:" << lexeme.getLinePosition() << std::endl;
return false;
}
} else if (lexeme.getType() == MaterialType::BLOCK) {
MaterialConfigProcessor const processor = mConfigProcessor.at(identifier);
if (!(*this.*processor)(lexeme, builder)) {
std::cerr << "Error while processing block with key:'" << identifier << "'"
<< std::endl;
return false;
}
}
}
return true;
}
bool MaterialParser::processMaterialParameters(filamat::MaterialBuilder& builder,
const Config& config) const {
ParametersProcessor parametersProcessor;
bool ok = true;
for (const auto& param : config.getMaterialParameters()) {
ok &= parametersProcessor.process(builder, param.first, param.second);
}
return ok;
}
bool MaterialParser::processTemplateSubstitutions(
const Config& config, ssize_t& size, std::unique_ptr<const char[]>& buffer) {
const auto& templateMap = config.getTemplateMap();
ssize_t modifiedSize = size;
bool modified = false;
if (!templateMap.empty()) {
for (ssize_t cursor = 0, n = size - 1; cursor < n; ++cursor) {
if (UTILS_LIKELY(buffer[cursor] != '$' || buffer[cursor + 1] != '{')) {
continue;
}
cursor += 2;
ssize_t endCursor = cursor;
while (true) {
if (endCursor == size) {
std::cerr << "Unexpected end of file" << std::endl;
return false;
}
if (buffer[endCursor] == '}') {
break;
}
++endCursor;
}
// At this point, cursor points to the F in ${FOO} and endCursor points to the }.
std::string_view const macro(&buffer[cursor], endCursor - cursor);
if (auto iter = templateMap.find(macro); iter != templateMap.end()) {
modifiedSize -= macro.size() + 3;
modifiedSize += iter->second.size();
} else {
std::cerr << "Undefined template macro:" << macro << std::endl;
return false;
}
modified = true;
}
}
// Second pass of template substitution allocates a new buffer and performs the actual
// substitutions. Since the first pass did not return early, we can safely assume no errors.
if (modified) {
auto modifiedBuffer = std::make_unique<char[]>(modifiedSize);
for (ssize_t cursor = 0, dstCursor = 0; cursor < size; ++cursor) {
const ssize_t next = cursor + 1;
if (UTILS_LIKELY(buffer[cursor] != '$' || next >= size || buffer[next] != '{')) {
modifiedBuffer[dstCursor++] = buffer[cursor];
continue;
}
cursor += 2;
ssize_t endCursor = cursor;
while (buffer[endCursor] != '}') ++endCursor;
// At this point, cursor points to the F in ${FOO} and endCursor points to the }.
std::string_view const macro(&buffer[cursor], endCursor - cursor);
const std::string& val = templateMap.find(macro)->second;
for (size_t i = 0, n = val.size(); i < n; ++i, ++dstCursor) {
modifiedBuffer[dstCursor] = val[i];
}
cursor = endCursor;
}
buffer = std::move(modifiedBuffer);
size = modifiedSize;
}
return true;
}
bool MaterialParser::parse(filamat::MaterialBuilder& builder,
const Config& config,
Config::Input* input, ssize_t& size, std::unique_ptr<const char[]>& buffer) {
utils::Path const materialFilePath = utils::Path(input->getName()).getAbsolutePath();
assert(materialFilePath.isFile());
if (builder.getFeatureLevel() > config.getFeatureLevel()) {
std::cerr << "Material feature level (" << +builder.getFeatureLevel()
<< ") is higher than maximum allowed (" << +config.getFeatureLevel() << ")" << std::endl;
return false;
}
// Before attempting an expensive lex, let's find out if we were sent pure JSON.
bool parsed;
if (isValidJsonStart(buffer.get(), size_t(size))) {
parsed = parseMaterialAsJSON(buffer.get(), size_t(size), builder);
} else {
parsed = parseMaterial(buffer.get(), size_t(size), builder);
}
if (!parsed) {
return false;
}
switch (config.getReflectionTarget()) {
case Config::Metadata::NONE:
break;
case Config::Metadata::PARAMETERS:
return reflectParameters(builder);
}
// Set the root include directory to the directory containing the material file.
DirIncluder includer;
includer.setIncludeDirectory(materialFilePath.getParent());
builder
.noSamplerValidation(config.noSamplerValidation())
.includeEssl1(config.includeEssl1())
.includeCallback(includer)
.fileName(materialFilePath.getName().c_str())
.platform(config.getPlatform())
.targetApi(config.getTargetApi())
.optimization(config.getOptimizationLevel())
.printShaders(config.printShaders())
.saveRawVariants(config.saveRawVariants())
.generateDebugInfo(config.isDebug())
.variantFilter(config.getVariantFilter() | builder.getVariantFilter());
for (const auto& define : config.getDefines()) {
builder.shaderDefine(define.first.c_str(), define.second.c_str());
}
if (!processMaterialParameters(builder, config)) {
std::cerr << "Error while processing material parameters." << std::endl;
return false;
}
return true;
}
} // namespace matp
@@ -1,42 +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_TESTMATERIALPARSER_H
#define TNT_TESTMATERIALPARSER_H
#include "filamat/MaterialBuilder.h"
#include <filament-matp/MaterialParser.h>
class TestMaterialParser {
public:
explicit TestMaterialParser(const matp::MaterialParser& materialParser) :
mMaterialParser(materialParser) {}
bool parseMaterial(const char* buffer, size_t size, filamat::MaterialBuilder& builder)
noexcept{
return mMaterialParser.parseMaterial(buffer, size, builder);
}
bool parseMaterialAsJSON(const char* buffer, size_t size, filamat::MaterialBuilder& builder)
noexcept{
return mMaterialParser.parseMaterialAsJSON(buffer, size, builder);
}
private:
const matp::MaterialParser mMaterialParser;
};
#endif // TNT_TESTMATERIALPARSER_H
-35
View File
@@ -544,27 +544,6 @@ public:
}
};
template<typename PanicType>
class FlagGuardedStream : public PanicStream {
public:
FlagGuardedStream(bool enable, char const* function, char const* file, int line,
char const* condition)
: PanicStream(function, file, line, condition),
mEnablePanic(enable) {}
~FlagGuardedStream() noexcept(false) {
if (mEnablePanic) {
PanicType::panic(mFunction, mFile, mLine, mLiteral, mStream.c_str());
} else {
logWarning();
}
}
private:
void logWarning() noexcept;
bool mEnablePanic;
};
} // namespace details
// -----------------------------------------------------------------------------------------------
@@ -603,20 +582,6 @@ private:
FILAMENT_CHECK_CONDITION_IMPL(condition) FILAMENT_PANIC_IMPL(#condition, ArithmeticPanic)
#endif
#define FILAMENT_FLAG_GUARDED_PANIC_IMPL(flag, condition, TYPE) \
::utils::details::FlagGuardedStream<::utils::TYPE>(flag, PANIC_FUNCTION, PANIC_FILE(__FILE__), \
__LINE__, #condition)
#ifndef FILAMENT_FLAG_GUARDED_CHECK_PRECONDITION
#define FILAMENT_FLAG_GUARDED_CHECK_PRECONDITION(condition, flag) \
FILAMENT_CHECK_CONDITION_IMPL(condition) FILAMENT_FLAG_GUARDED_PANIC_IMPL(flag, condition, PreconditionPanic)
#endif
#ifndef FILAMENT_FLAG_GUARDED_CHECK_POSTCONDITION
#define FILAMENT_FLAG_GUARDED_CHECK_POSTCONDITION(condition, flag) \
FILAMENT_CHECK_CONDITION_IMPL(condition) FILAMENT_FLAG_GUARDED_PANIC_IMPL(flag, condition, PostconditionPanic)
#endif
#define PANIC_PRECONDITION_IMPL(cond, format, ...) \
::utils::PreconditionPanic::panic(PANIC_FUNCTION, \
PANIC_FILE(__FILE__), __LINE__, #cond, format, ##__VA_ARGS__)
-1
View File
@@ -26,7 +26,6 @@
#include <algorithm> // for std::fill
#include <iterator>
#include <limits>
#include <type_traits>
#if defined(__ARM_NEON)
-12
View File
@@ -21,7 +21,6 @@
#include <utils/CallStack.h>
#include <utils/compiler.h>
#include <utils/Log.h>
#include <utils/Logger.h>
#include <utils/ostream.h>
#include <stdarg.h>
@@ -353,17 +352,6 @@ PanicStream& PanicStream::operator<<(std::string_view const& value) noexcept {
return *this;
}
template<typename PanicType>
void FlagGuardedStream<PanicType>::logWarning() noexcept {
LOG(WARNING) << "Failed [" << mLiteral << "]" << "\n file=" << mFile
<< "\n function=" << mFunction << "\n line=" << mLine << "\n info=\""
<< mStream.c_str() << "\"";
}
template void FlagGuardedStream<PreconditionPanic>::logWarning() noexcept;
template void FlagGuardedStream<PostconditionPanic>::logWarning() noexcept;
} // namespace details
// -----------------------------------------------------------------------------------------------
+150
View File
@@ -0,0 +1,150 @@
cmake_minimum_required(VERSION 3.19)
project(filament C ASM)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../..)
set(GENERATION_ROOT ${CMAKE_CURRENT_BINARY_DIR})
set(RESOURCE_DIR "${GENERATION_ROOT}/generated/resources")
set(MATERIAL_DIR "${GENERATION_ROOT}/generated/material")
set(TEXTURE_DIR "${GENERATION_ROOT}/generated/texture")
set(RESOURCE_BINS)
# Materials
set(MATERIAL_SRCS
${ROOT_DIR}/samples/materials/aiDefaultMat.mat
${ROOT_DIR}/samples/materials/bakedColor.mat
${ROOT_DIR}/samples/materials/bakedTexture.mat
${ROOT_DIR}/samples/materials/aoPreview.mat
${ROOT_DIR}/samples/materials/arrayTexture.mat
${ROOT_DIR}/samples/materials/groundShadow.mat
${ROOT_DIR}/samples/materials/heightfield.mat
${ROOT_DIR}/samples/materials/image.mat
${ROOT_DIR}/samples/materials/mirror.mat
${ROOT_DIR}/samples/materials/overdraw.mat
${ROOT_DIR}/samples/materials/sandboxCloth.mat
${ROOT_DIR}/samples/materials/sandboxLit.mat
${ROOT_DIR}/samples/materials/sandboxLitFade.mat
${ROOT_DIR}/samples/materials/sandboxLitTransparent.mat
${ROOT_DIR}/samples/materials/sandboxLitThinRefraction.mat
${ROOT_DIR}/samples/materials/sandboxLitThinRefractionSsr.mat
${ROOT_DIR}/samples/materials/sandboxLitSolidRefraction.mat
${ROOT_DIR}/samples/materials/sandboxLitSolidRefractionSsr.mat
${ROOT_DIR}/samples/materials/sandboxSpecGloss.mat
${ROOT_DIR}/samples/materials/sandboxSubsurface.mat
${ROOT_DIR}/samples/materials/sandboxUnlit.mat
${ROOT_DIR}/samples/materials/texturedLit.mat
)
# Tint does not support setting gl_PointSize, disable the relevant sample if using WebGPU
# https://github.com/gpuweb/gpuweb/issues/1190
if (NOT FILAMENT_SUPPORTS_WEBGPU)
set(MATERIAL_SRCS ${MATERIAL_SRCS} materials/pointSprites.mat)
endif ()
if (CMAKE_CROSSCOMPILING)
include(${IMPORT_EXECUTABLES})
endif()
file(MAKE_DIRECTORY ${MATERIAL_DIR})
set (MATC_FLAGS ${MATC_BASE_FLAGS})
if (FILAMENT_SAMPLES_STEREO_TYPE STREQUAL "instanced")
set (MATC_FLAGS ${MATC_FLAGS} -PstereoscopicType=instanced)
add_definitions(-DFILAMENT_SAMPLES_STEREO_TYPE_INSTANCED)
elseif (FILAMENT_SAMPLES_STEREO_TYPE STREQUAL "multiview")
set (MATC_FLAGS ${MATC_FLAGS} -PstereoscopicType=multiview)
add_definitions(-DFILAMENT_SAMPLES_STEREO_TYPE_MULTIVIEW)
endif ()
foreach (mat_src ${MATERIAL_SRCS})
get_filename_component(localname "${mat_src}" NAME_WE)
get_filename_component(fullname "${mat_src}" ABSOLUTE)
set(output_path "${MATERIAL_DIR}/${localname}.filamat")
add_custom_command(
OUTPUT ${output_path}
COMMAND matc ${MATC_FLAGS} -o ${output_path} ${fullname}
MAIN_DEPENDENCY ${mat_src}
DEPENDS matc
COMMENT "Compiling material ${mat_src} to ${output_path}"
)
list(APPEND RESOURCE_BINS ${output_path})
endforeach()
# Resources
file(MAKE_DIRECTORY ${RESOURCE_DIR})
get_resgen_vars(${RESOURCE_DIR} resources)
add_custom_command(
OUTPUT ${RESGEN_OUTPUTS}
COMMAND resgen ${RESGEN_FLAGS} ${RESOURCE_BINS}
DEPENDS resgen ${RESOURCE_BINS}
COMMENT "Aggregating resources"
)
if (DEFINED RESGEN_SOURCE_FLAGS)
set_source_files_properties(${RESGEN_SOURCE} PROPERTIES COMPILE_FLAGS ${RESGEN_SOURCE_FLAGS})
endif()
add_library(gltf-resources ${DUMMY_SRC})
set_target_properties(gltf-resources PROPERTIES FOLDER Samples/Resources)
set(GLTF_DEMO_RESOURCES
${ROOT_DIR}/third_party/models/DamagedHelmet/DamagedHelmet.glb
${MATERIAL_DIR}/groundShadow.filamat
${MATERIAL_DIR}/overdraw.filamat
)
get_resgen_vars(${RESOURCE_DIR} gltf_demo)
add_custom_command(
OUTPUT ${RESGEN_OUTPUTS}
COMMAND resgen ${RESGEN_FLAGS} ${GLTF_DEMO_RESOURCES}
DEPENDS resgen ${GLTF_DEMO_RESOURCES}
)
if (DEFINED RESGEN_SOURCE_FLAGS)
set_source_files_properties(${RESGEN_SOURCE} PROPERTIES COMPILE_FLAGS ${RESGEN_SOURCE_FLAGS})
endif()
target_sources(gltf-resources PRIVATE ${RESGEN_SOURCE})
# CMake fails to invoke ar on Windows unless there is at least one C/C++ file in the library.
set(DUMMY_SRC "${RESOURCE_DIR}/dummy.c")
add_custom_command(OUTPUT ${DUMMY_SRC} COMMAND echo "//" > ${DUMMY_SRC})
# Test binary
set(GLTF_COMPARISON_SOURCES
src/test_CompareGLTF.cpp
src/GLTFViewer.cpp
src/ImageExpectations.cpp
src/RunOnMain.cpp
src/CrossThreadTask.cpp
src/main.cpp
)
file(COPY glTF_cases DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/images/actual_images)
file(COPY expected_images DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/images)
enable_testing()
add_executable(gltf_comparison ${GLTF_COMPARISON_SOURCES})
target_include_directories(gltf_comparison PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(gltf_comparison
gtest
filamentapp
absl::str_format
uberarchive
gltf-resources
gltfio
viewer
)
include(GoogleTest)
gtest_discover_tests(gltf_comparison)
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

@@ -0,0 +1,15 @@
# LICENSE file for the model: Box
All files in this directory tree are licensed as indicated below.
* All files directly associated with the model including all text, image and binary files:
* [CC BY 4.0 International]("https://creativecommons.org/licenses/by/4.0/legalcode") [SPDX license identifier: "CC-BY-4.0"]
* This file and all other metadocumentation files including "metadata.json":
* [Creative Commons Attribtution 4.0 International]("https://creativecommons.org/licenses/by/4.0/legalcode") [SPDX license identifier: "CC-BY-4.0"]
Full license text of these licenses are available at the links above
#### Generated by modelmetadata
@@ -0,0 +1,7 @@
## Screenshot
![screenshot](screenshot/screenshot.png)
## Description
Simple cube model.
@@ -0,0 +1,31 @@
# Box
## Tags
[core](../../Models-core.md), [testing](../../Models-testing.md)
## Summary
One mesh and one material. Start with this.
## Operations
* [Display](https://github.khronos.org/glTF-Sample-Viewer-Release/?model=https://raw.GithubUserContent.com/KhronosGroup/glTF-Sample-Assets/main/./Models/Box/glTF-Binary/Box.glb) in SampleViewer
* [Download GLB](https://raw.GithubUserContent.com/KhronosGroup/glTF-Sample-Assets/main/./Models/Box/glTF-Binary/Box.glb)
* [Model Directory](./)
## Screenshot
![screenshot](screenshot/screenshot.png)
## Description
Simple cube model.
## Legal
&copy; 2017, Cesium. [CC BY 4.0 International](https://creativecommons.org/licenses/by/4.0/legalcode)
- Cesium for Everything
#### Assembled by modelmetadata
@@ -0,0 +1,152 @@
{
"asset": {
"generator": "COLLADA2GLTF",
"version": "2.0"
},
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
],
"nodes": [
{
"children": [
1
],
"matrix": [
1,
0,
0,
0,
0,
0,
-1,
0,
0,
1,
0,
0,
0,
0,
0,
1
]
},
{
"mesh": 0
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"NORMAL": 1,
"POSITION": 2
},
"indices": 0,
"mode": 4,
"material": 0,
"extensions": {
"KHR_draco_mesh_compression": {
"bufferView": 0,
"attributes": {
"NORMAL": 0,
"POSITION": 1
}
}
}
}
],
"name": "Mesh"
}
],
"accessors": [
{
"componentType": 5123,
"count": 36,
"max": [
23
],
"min": [
0
],
"type": "SCALAR"
},
{
"componentType": 5126,
"count": 24,
"max": [
1.007843137254902,
1.007843137254902,
1.007843137254902
],
"min": [
-1.007843137254902,
-1.007843137254902,
-1.007843137254902
],
"type": "VEC3"
},
{
"componentType": 5126,
"count": 24,
"max": [
0.5004885197850513,
0.5004885197850513,
0.5004885197850513
],
"min": [
-0.5004885197850513,
-0.5004885197850513,
-0.5004885197850513
],
"type": "VEC3"
}
],
"materials": [
{
"pbrMetallicRoughness": {
"baseColorFactor": [
0.800000011920929,
0,
0,
1
],
"metallicFactor": 0,
"roughnessFactor": 1
},
"name": "Red",
"emissiveFactor": [
0,
0,
0
],
"alphaMode": "OPAQUE",
"doubleSided": false
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 118
}
],
"buffers": [
{
"name": "Box",
"byteLength": 120,
"uri": "Box.bin"
}
],
"extensionsRequired": [
"KHR_draco_mesh_compression"
],
"extensionsUsed": [
"KHR_draco_mesh_compression"
]
}
@@ -0,0 +1,142 @@
{
"asset": {
"generator": "COLLADA2GLTF",
"version": "2.0"
},
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
],
"nodes": [
{
"children": [
1
],
"matrix": [
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
-1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0
]
},
{
"mesh": 0
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"NORMAL": 1,
"POSITION": 2
},
"indices": 0,
"mode": 4,
"material": 0
}
],
"name": "Mesh"
}
],
"accessors": [
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5123,
"count": 36,
"max": [
23
],
"min": [
0
],
"type": "SCALAR"
},
{
"bufferView": 1,
"byteOffset": 0,
"componentType": 5126,
"count": 24,
"max": [
1.0,
1.0,
1.0
],
"min": [
-1.0,
-1.0,
-1.0
],
"type": "VEC3"
},
{
"bufferView": 1,
"byteOffset": 288,
"componentType": 5126,
"count": 24,
"max": [
0.5,
0.5,
0.5
],
"min": [
-0.5,
-0.5,
-0.5
],
"type": "VEC3"
}
],
"materials": [
{
"pbrMetallicRoughness": {
"baseColorFactor": [
0.800000011920929,
0.0,
0.0,
1.0
],
"metallicFactor": 0.0
},
"name": "Red"
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 576,
"byteLength": 72,
"target": 34963
},
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 576,
"byteStride": 12,
"target": 34962
}
],
"buffers": [
{
"byteLength": 648,
"uri": "data:application/octet-stream;base64,AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAvwAAAL8AAAC/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAC/AAABAAIAAwACAAEABAAFAAYABwAGAAUACAAJAAoACwAKAAkADAANAA4ADwAOAA0AEAARABIAEwASABEAFAAVABYAFwAWABUA"
}
]
}
@@ -0,0 +1,142 @@
{
"asset": {
"generator": "COLLADA2GLTF",
"version": "2.0"
},
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
],
"nodes": [
{
"children": [
1
],
"matrix": [
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
-1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0
]
},
{
"mesh": 0
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"NORMAL": 1,
"POSITION": 2
},
"indices": 0,
"mode": 4,
"material": 0
}
],
"name": "Mesh"
}
],
"accessors": [
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5123,
"count": 36,
"max": [
23
],
"min": [
0
],
"type": "SCALAR"
},
{
"bufferView": 1,
"byteOffset": 0,
"componentType": 5126,
"count": 24,
"max": [
1.0,
1.0,
1.0
],
"min": [
-1.0,
-1.0,
-1.0
],
"type": "VEC3"
},
{
"bufferView": 1,
"byteOffset": 288,
"componentType": 5126,
"count": 24,
"max": [
0.5,
0.5,
0.5
],
"min": [
-0.5,
-0.5,
-0.5
],
"type": "VEC3"
}
],
"materials": [
{
"pbrMetallicRoughness": {
"baseColorFactor": [
0.800000011920929,
0.0,
0.0,
1.0
],
"metallicFactor": 0.0
},
"name": "Red"
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 576,
"byteLength": 72,
"target": 34963
},
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 576,
"byteStride": 12,
"target": 34962
}
],
"buffers": [
{
"byteLength": 648,
"uri": "Box0.bin"
}
]
}
@@ -0,0 +1,25 @@
{
"version": 2,
"legal": [
{
"license": "CC-BY 4.0",
"licenseUrl": "https://creativecommons.org/licenses/by/4.0/legalcode",
"artist": "Cesium",
"year": "2017",
"owner": "Cesium",
"what": "Everything",
"text": "CC BY 4.0 International",
"spdx": "CC-BY-4.0",
"icon": "https://licensebuttons.net/l/by/3.0/88x31.png"
}
],
"tags": [
"core",
"testing"
],
"screenshot": "screenshot/screenshot.png",
"name": "Box",
"path": "./Models/Box",
"summary": "One mesh and one material. Start with this.",
"createReadme": true
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

@@ -0,0 +1,17 @@
# LICENSE file for the model: Box Textured
All files in this directory tree are licensed as indicated below.
* All files directly associated with the model including all text, image and binary files:
* [CC-BY 4.0 International with Trademark Limitations]("") [SPDX license identifier: "LicenseRef-CC-BY-TM"]
* [Cesium Trademark or Logo]("") [SPDX license identifier: "LicenseRef-LegalMark-Cesium"]
* This file and all other metadocumentation files including "metadata.json":
* [Creative Commons Attribtution 4.0 International]("https://creativecommons.org/licenses/by/4.0/legalcode") [SPDX license identifier: "CC-BY-4.0"]
Full license text of these licenses are available at the links above
#### Generated by modelmetadata
@@ -0,0 +1,7 @@
## Screenshot
![screenshot](screenshot/screenshot.png)
## Description
Box with a power-of-2 texture, using the Cesium logo.
@@ -0,0 +1,35 @@
# Box Textured
## Tags
[core](../../Models-core.md), [issues](../../Models-issues.md), [testing](../../Models-testing.md)
## Summary
Box with a power-of-2 texture. [Issues: non-Khronos mark]
## Operations
* [Display](https://github.khronos.org/glTF-Sample-Viewer-Release/?model=https://raw.GithubUserContent.com/KhronosGroup/glTF-Sample-Assets/main/./Models/BoxTextured/glTF-Binary/BoxTextured.glb) in SampleViewer
* [Download GLB](https://raw.GithubUserContent.com/KhronosGroup/glTF-Sample-Assets/main/./Models/BoxTextured/glTF-Binary/BoxTextured.glb)
* [Model Directory](./)
## Screenshot
![screenshot](screenshot/screenshot.png)
## Description
Box with a power-of-2 texture, using the Cesium logo.
## Legal
&copy; 2017, Cesium. [CC-BY 4.0 International with Trademark Limitations]()
- Cesium for Everything
&copy; 2015, Cesium. [Cesium Trademark or Logo]()
- Non-copyrightable logo for Cesium logo
#### Assembled by modelmetadata
File diff suppressed because one or more lines are too long
@@ -0,0 +1,181 @@
{
"asset": {
"generator": "COLLADA2GLTF",
"version": "2.0"
},
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
],
"nodes": [
{
"children": [
1
],
"matrix": [
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
-1.0,
0.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0
]
},
{
"mesh": 0
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"NORMAL": 1,
"POSITION": 2,
"TEXCOORD_0": 3
},
"indices": 0,
"mode": 4,
"material": 0
}
],
"name": "Mesh"
}
],
"accessors": [
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5123,
"count": 36,
"max": [
23
],
"min": [
0
],
"type": "SCALAR"
},
{
"bufferView": 1,
"byteOffset": 0,
"componentType": 5126,
"count": 24,
"max": [
1.0,
1.0,
1.0
],
"min": [
-1.0,
-1.0,
-1.0
],
"type": "VEC3"
},
{
"bufferView": 1,
"byteOffset": 288,
"componentType": 5126,
"count": 24,
"max": [
0.5,
0.5,
0.5
],
"min": [
-0.5,
-0.5,
-0.5
],
"type": "VEC3"
},
{
"bufferView": 2,
"byteOffset": 0,
"componentType": 5126,
"count": 24,
"max": [
6.0,
1.0
],
"min": [
0.0,
0.0
],
"type": "VEC2"
}
],
"materials": [
{
"pbrMetallicRoughness": {
"baseColorTexture": {
"index": 0
},
"metallicFactor": 0.0
},
"name": "Texture"
}
],
"textures": [
{
"sampler": 0,
"source": 0
}
],
"images": [
{
"uri": "CesiumLogoFlat.png"
}
],
"samplers": [
{
"magFilter": 9729,
"minFilter": 9986,
"wrapS": 10497,
"wrapT": 10497
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 768,
"byteLength": 72,
"target": 34963
},
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 576,
"byteStride": 12,
"target": 34962
},
{
"buffer": 0,
"byteOffset": 576,
"byteLength": 192,
"byteStride": 8,
"target": 34962
}
],
"buffers": [
{
"byteLength": 840,
"uri": "BoxTextured0.bin"
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

@@ -0,0 +1,37 @@
{
"version": 2,
"legal": [
{
"license": "LicenseRef-CC-BY-TM",
"licenseUrl": "",
"artist": "Cesium",
"year": "2017",
"owner": "Cesium",
"what": "Everything",
"text": "CC-BY 4.0 International with Trademark Limitations",
"spdx": "LicenseRef-CC-BY-TM",
"icon": "https://licensebuttons.net/l/by/3.0/88x31.png"
},
{
"license": "LicenseRef-LegalMark-Cesium",
"licenseUrl": "",
"artist": "Non-copyrightable logo",
"year": "2015",
"owner": "Cesium",
"what": "Cesium logo",
"text": "Cesium Trademark or Logo",
"spdx": "LicenseRef-LegalMark-Cesium",
"icon": ""
}
],
"tags": [
"core",
"issues",
"testing"
],
"screenshot": "screenshot/screenshot.png",
"name": "Box Textured",
"path": "./Models/BoxTextured",
"summary": "Box with a power-of-2 texture. [Issues: non-Khronos mark]",
"createReadme": true
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

@@ -0,0 +1,3 @@
Files here are copied directly from https://github.com/KhronosGroup/glTF-Sample-Assets
Each glTF model includes its own license and attribution in LICENSE.md and metadata.json.
@@ -0,0 +1,71 @@
/*
* 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_CROSSTHREADTASK_H
#define TNT_CROSSTHREADTASK_H
#include <optional>
#include <functional>
#include <mutex>
#include <atomic>
template <typename T, typename... Args>
class CrossThreadTask {
public:
bool queueTask(std::function<T> task);
void runTask(Args...);
bool isClosed() const;
void setClosed();
private:
std::mutex mMutex;
std::optional<std::function<T>> mTask;
std::atomic<bool> mClosed = false;
};
template <typename T, typename... Args>
bool CrossThreadTask<T, Args...>::queueTask(std::function<T> task) {
std::unique_lock<std::mutex> lock(mMutex);
if (mTask.has_value()) {
return false;
}
mTask = task;
return true;
}
template <typename T, typename... Args>
void CrossThreadTask<T, Args...>::runTask(Args... args) {
std::optional<std::function<T>> taskToRun;
{
std::unique_lock<std::mutex> lock(mMutex);
std::swap(mTask, taskToRun);
}
if (taskToRun.has_value()) {
(*taskToRun)(args...);
}
}
template <typename T, typename... Args>
bool CrossThreadTask<T, Args...>::isClosed() const {
return mClosed;
}
template <typename T, typename... Args>
void CrossThreadTask<T, Args...>::setClosed() {
mClosed = true;
}
#endif // TNT_CROSSTHREADTASK_H
+88
View File
@@ -0,0 +1,88 @@
/*
* 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_GLTFVIEWER_H
#define TNT_GLTFVIEWER_H
#include <string>
#include <filamentapp/Config.h>
#include <filamentapp/FilamentApp.h>
#include <filamentapp/IBL.h>
#include <filament/Camera.h>
#include <filament/Engine.h>
#include <filament/IndexBuffer.h>
#include <filament/Material.h>
#include <filament/MaterialInstance.h>
#include <filament/RenderableManager.h>
#include <filament/Scene.h>
#include <filament/Skybox.h>
#include <filament/TransformManager.h>
#include <filament/VertexBuffer.h>
#include <filament/View.h>
#include <gltfio/AssetLoader.h>
#include <gltfio/FilamentAsset.h>
#include <gltfio/ResourceLoader.h>
#include <gltfio/TextureProvider.h>
#include <viewer/ViewerGui.h>
#include <utils/EntityManager.h>
class GLTFViewer {
public:
void setFilename(std::string fileName);
void runApp(std::function<void(filament::Engine*, filament::View*, filament::Scene*,
filament::Renderer*)>
postRender);
private:
void setup(filament::Engine* engine, filament::View* view, filament::Scene* scene);
void cleanup(filament::Engine* engine, filament::View* view, filament::Scene* scene);
void animate(filament::Engine* engine, filament::View* view, double now);
void loadAsset(utils::Path filename);
void loadResources(utils::Path filename);
enum MaterialSource {
JITSHADER,
UBERSHADER,
};
struct App {
filament::Engine* engine;
filament::viewer::ViewerGui* viewer;
Config config;
filament::gltfio::AssetLoader* loader;
filament::gltfio::FilamentAsset* asset = nullptr;
utils::NameComponentManager* names;
filament::gltfio::MaterialProvider* materials;
MaterialSource materialSource = UBERSHADER;
filament::gltfio::ResourceLoader* resourceLoader = nullptr;
filament::gltfio::TextureProvider* stbDecoder = nullptr;
filament::gltfio::TextureProvider* ktxDecoder = nullptr;
filament::gltfio::FilamentInstance* instance;
bool enableMSAA = false;
};
App mApp;
std::string mFilename;
};
#endif // TNT_GLTFVIEWER_H

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