Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fdd710c3b0 | ||
|
|
208e936dab | ||
|
|
bbea03224d |
@@ -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)
|
||||
|
||||
@@ -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()`
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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', '~> 1.62.2'
|
||||
<pre><code class="language-shell">pod 'Filament', '~> 1.62.1'
|
||||
</code></pre>
|
||||
<h2 id="documentation"><a class="header" href="#documentation">Documentation</a></h2>
|
||||
<ul>
|
||||
|
||||
@@ -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', '~> 1.62.2'
|
||||
<pre><code class="language-shell">pod 'Filament', '~> 1.62.1'
|
||||
</code></pre>
|
||||
<h2 id="documentation"><a class="header" href="#documentation">Documentation</a></h2>
|
||||
<ul>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, ©Size);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, ©Size);
|
||||
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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
[=, ¤t](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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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__)
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
#include <algorithm> // for std::fill
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#if defined(__ARM_NEON)
|
||||
|
||||
@@ -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
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -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)
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
|
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
|
||||
|
||||

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

|
||||
|
||||
## Description
|
||||
|
||||
Simple cube model.
|
||||
|
||||
## Legal
|
||||
|
||||
© 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
|
||||
}
|
||||
|
After Width: | Height: | Size: 5.0 KiB |
|
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
|
||||
|
||||

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

|
||||
|
||||
## Description
|
||||
|
||||
Box with a power-of-2 texture, using the Cesium logo.
|
||||
|
||||
## Legal
|
||||
|
||||
© 2017, Cesium. [CC-BY 4.0 International with Trademark Limitations]()
|
||||
|
||||
- Cesium for Everything
|
||||
|
||||
© 2015, Cesium. [Cesium Trademark or Logo]()
|
||||
|
||||
- Non-copyrightable logo for Cesium logo
|
||||
|
||||
#### Assembled by modelmetadata
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
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
|
||||
}
|
||||
|
After Width: | Height: | Size: 14 KiB |
|
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
|
||||
@@ -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
|
||||