Merge branch 'rc/1.58.1' into release
This commit is contained in:
@@ -9,6 +9,11 @@ name: Release
|
||||
env:
|
||||
RELEASE_TAG: ${{ github.event.inputs.release_tag }}
|
||||
|
||||
# The default GITHUB_TOKEN does not have write permissions, which is needed to upload release
|
||||
# assets.
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
|
||||
@@ -7,4 +7,3 @@ for next branch cut* header.
|
||||
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
||||
|
||||
## Release notes for next branch cut
|
||||
- materials: add an optional `transformName` field to sampler material parameters. [⚠️ **New Material Version**]
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.58.0'
|
||||
implementation 'com.google.android.filament:filament-android:1.58.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.58.0'
|
||||
pod 'Filament', '~> 1.58.1'
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -7,6 +7,10 @@ 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.58.1
|
||||
|
||||
- materials: add an optional `transformName` field to sampler material parameters. [⚠️ **New Material Version**]
|
||||
|
||||
## v1.57.3
|
||||
|
||||
- android: breaking changes to API KTX1Loader::createIndirectLight and KTX1Loader::createSkybox
|
||||
|
||||
@@ -71,10 +71,9 @@ buildscript {
|
||||
.gradleProperty("com.google.android.filament.include-webgpu")
|
||||
.isPresent()
|
||||
|
||||
// TODO: Uncomment below when fgviewer is ready
|
||||
// def fgviewer = providers
|
||||
// .gradleProperty("com.google.android.filament.fgviewer")
|
||||
// .isPresent()
|
||||
def fgviewer = providers
|
||||
.gradleProperty("com.google.android.filament.fgviewer")
|
||||
.isPresent()
|
||||
|
||||
def matdbg = providers
|
||||
.gradleProperty("com.google.android.filament.matdbg")
|
||||
@@ -131,8 +130,7 @@ buildscript {
|
||||
"-DFILAMENT_DIST_DIR=${filamentPath}".toString(),
|
||||
"-DFILAMENT_SUPPORTS_VULKAN=${excludeVulkan ? 'OFF' : 'ON'}".toString(),
|
||||
"-DFILAMENT_SUPPORTS_WEBGPU=${includeWebGPU ? 'ON' : 'OFF'}".toString(),
|
||||
// TODO: Uncomment below when fgviewer is ready
|
||||
// "-DFILAMENT_ENABLE_FGVIEWER=${fgviewer ? 'ON' : 'OFF'}".toString(),
|
||||
"-DFILAMENT_ENABLE_FGVIEWER=${fgviewer ? 'ON' : 'OFF'}".toString(),
|
||||
"-DFILAMENT_ENABLE_MATDBG=${matdbg ? 'ON' : 'OFF'}".toString(),
|
||||
"-DFILAMENT_DISABLE_MATOPT=${matnopt ? 'ON' : 'OFF'}".toString()
|
||||
]
|
||||
|
||||
@@ -2,8 +2,7 @@ cmake_minimum_required(VERSION 3.19)
|
||||
project(filament-android)
|
||||
|
||||
option(FILAMENT_SUPPORTS_VULKAN "Enables Vulkan on Android" OFF)
|
||||
# TODO: Uncomment below when fgviewer is ready
|
||||
# option(FILAMENT_ENABLE_FGVIEWER "Enables Frame Graph Viewer" OFF)
|
||||
option(FILAMENT_ENABLE_FGVIEWER "Enables Frame Graph Viewer" OFF)
|
||||
option(FILAMENT_ENABLE_MATDBG "Enables Material debugger" OFF)
|
||||
option(FILAMENT_DISABLE_MATOPT "Disables material optimizations" OFF)
|
||||
option(FILAMENT_SUPPORTS_WEBGPU "Enables WebGPU on Android" OFF)
|
||||
@@ -60,12 +59,11 @@ add_library(smol-v STATIC IMPORTED)
|
||||
set_target_properties(smol-v PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libsmol-v.a)
|
||||
|
||||
# TODO: Uncomment below when fgviewer is ready
|
||||
# if (FILAMENT_ENABLE_FGVIEWER)
|
||||
# add_library(fgviewer STATIC IMPORTED)
|
||||
# set_target_properties(fgviewer PROPERTIES IMPORTED_LOCATION
|
||||
# ${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfgviewer.a)
|
||||
# endif()
|
||||
if (FILAMENT_ENABLE_FGVIEWER)
|
||||
add_library(fgviewer STATIC IMPORTED)
|
||||
set_target_properties(fgviewer PROPERTIES IMPORTED_LOCATION
|
||||
${FILAMENT_DIR}/lib/${ANDROID_ABI}/libfgviewer.a)
|
||||
endif()
|
||||
|
||||
if (FILAMENT_ENABLE_MATDBG)
|
||||
add_library(matdbg STATIC IMPORTED)
|
||||
@@ -133,8 +131,7 @@ target_link_libraries(filament-jni
|
||||
# libgeometry is PUBLIC because gltfio uses it.
|
||||
PUBLIC geometry
|
||||
|
||||
# TODO: Uncomment below when fgviewer is ready
|
||||
# $<$<STREQUAL:${FILAMENT_ENABLE_FGVIEWER},ON>:fgviewer>
|
||||
$<$<STREQUAL:${FILAMENT_ENABLE_FGVIEWER},ON>:fgviewer>
|
||||
$<$<STREQUAL:${FILAMENT_ENABLE_MATDBG},ON>:matdbg>
|
||||
$<$<STREQUAL:${FILAMENT_ENABLE_MATDBG},ON>:filamat>
|
||||
$<$<STREQUAL:${FILAMENT_SUPPORTS_VULKAN},ON>:bluevk>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.58.0
|
||||
VERSION_NAME=1.58.1
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
@@ -30,4 +30,5 @@ com.google.android.filament.abis=all
|
||||
#com.google.android.filament.include-webgpu
|
||||
|
||||
#com.google.android.filament.matdbg
|
||||
#com.google.android.filament.fgviewer
|
||||
#com.google.android.filament.matnopt
|
||||
|
||||
@@ -246,6 +246,10 @@ if (FILAMENT_SUPPORTS_WEBGPU)
|
||||
)
|
||||
endif()
|
||||
|
||||
if (ANDROID)
|
||||
list(APPEND SRCS src/BackendUtilsAndroid.cpp)
|
||||
endif()
|
||||
|
||||
# ==================================================================================================
|
||||
# Definitions
|
||||
# ==================================================================================================
|
||||
|
||||
@@ -807,6 +807,33 @@ static constexpr bool isStencilFormat(TextureFormat format) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
inline constexpr bool isColorFormat(TextureFormat format) noexcept {
|
||||
switch (format) {
|
||||
// Standard color formats
|
||||
case TextureFormat::R8:
|
||||
case TextureFormat::RG8:
|
||||
case TextureFormat::RGBA8:
|
||||
case TextureFormat::R16F:
|
||||
case TextureFormat::RG16F:
|
||||
case TextureFormat::RGBA16F:
|
||||
case TextureFormat::R32F:
|
||||
case TextureFormat::RG32F:
|
||||
case TextureFormat::RGBA32F:
|
||||
case TextureFormat::RGB10_A2:
|
||||
case TextureFormat::R11F_G11F_B10F:
|
||||
case TextureFormat::SRGB8:
|
||||
case TextureFormat::SRGB8_A8:
|
||||
case TextureFormat::RGB8:
|
||||
case TextureFormat::RGB565:
|
||||
case TextureFormat::RGB5_A1:
|
||||
case TextureFormat::RGBA4:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static constexpr bool isUnsignedIntFormat(TextureFormat format) {
|
||||
switch (format) {
|
||||
case TextureFormat::R8UI:
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_FILAMENT_BACKEND_PRIVATE_BACKENDUTILSANDROID_H
|
||||
#define TNT_FILAMENT_BACKEND_PRIVATE_BACKENDUTILSANDROID_H
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
/**
|
||||
* Maps AHardwareBuffer format to TextureFormat.
|
||||
*/
|
||||
TextureFormat mapToFilamentFormat(unsigned int format, bool isSrgbTransfer) noexcept;
|
||||
|
||||
/**
|
||||
* Maps AHardwareBuffer usage to TextureUsage.
|
||||
*/
|
||||
TextureUsage mapToFilamentUsage(unsigned int usage, TextureFormat format) noexcept;
|
||||
|
||||
} // namespace filament
|
||||
|
||||
#endif // TNT_FILAMENT_BACKEND_PRIVATE_BACKENDUTILSANDROID_H
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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 "private/backend/BackendUtilsAndroid.h"
|
||||
|
||||
#include <android/hardware_buffer.h>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
TextureFormat mapToFilamentFormat(unsigned int format, bool isSrgbTransfer) noexcept {
|
||||
if (isSrgbTransfer) {
|
||||
switch (format) {
|
||||
case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
|
||||
return TextureFormat::SRGB8;
|
||||
default:
|
||||
return TextureFormat::SRGB8_A8;
|
||||
}
|
||||
}
|
||||
switch (format) {
|
||||
case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
|
||||
case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
|
||||
return TextureFormat::RGBA8;
|
||||
case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
|
||||
case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
|
||||
return TextureFormat::RGB8;
|
||||
case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
|
||||
return TextureFormat::RGB565;
|
||||
case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
|
||||
return TextureFormat::RGBA16F;
|
||||
case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
|
||||
return TextureFormat::RGB10_A2;
|
||||
case AHARDWAREBUFFER_FORMAT_D16_UNORM:
|
||||
return TextureFormat::DEPTH16;
|
||||
case AHARDWAREBUFFER_FORMAT_D24_UNORM:
|
||||
return TextureFormat::DEPTH24;
|
||||
case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
|
||||
return TextureFormat::DEPTH24_STENCIL8;
|
||||
case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
|
||||
return TextureFormat::DEPTH32F;
|
||||
case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT:
|
||||
return TextureFormat::DEPTH32F_STENCIL8;
|
||||
case AHARDWAREBUFFER_FORMAT_S8_UINT:
|
||||
return TextureFormat::STENCIL8;
|
||||
case AHARDWAREBUFFER_FORMAT_R8_UNORM:
|
||||
return TextureFormat::R8;
|
||||
default:
|
||||
return TextureFormat::UNUSED;
|
||||
}
|
||||
}
|
||||
|
||||
TextureUsage mapToFilamentUsage(unsigned int usage, TextureFormat format) noexcept {
|
||||
TextureUsage usageFlags = TextureUsage::NONE;
|
||||
|
||||
if (usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) {
|
||||
usageFlags |= TextureUsage::SAMPLEABLE;
|
||||
}
|
||||
|
||||
if (usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER) {
|
||||
if (isDepthFormat(format)) {
|
||||
usageFlags |= TextureUsage::DEPTH_ATTACHMENT;
|
||||
}
|
||||
if (isStencilFormat(format)) {
|
||||
usageFlags |= TextureUsage::STENCIL_ATTACHMENT;
|
||||
}
|
||||
if (isColorFormat(format)) {
|
||||
usageFlags |= TextureUsage::COLOR_ATTACHMENT;
|
||||
}
|
||||
}
|
||||
|
||||
if (usage & AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER) {
|
||||
usageFlags |= TextureUsage::UPLOADABLE;
|
||||
}
|
||||
|
||||
if (usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) {
|
||||
usageFlags |= TextureUsage::PROTECTED;
|
||||
}
|
||||
|
||||
if (usageFlags == TextureUsage::NONE) {
|
||||
usageFlags = TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE;
|
||||
}
|
||||
|
||||
return usageFlags;
|
||||
}
|
||||
|
||||
} // namespace backend::filament
|
||||
@@ -751,7 +751,8 @@ int FEngine::loop() {
|
||||
#endif
|
||||
if (portString != nullptr) {
|
||||
const int port = atoi(portString);
|
||||
debug.server = new matdbg::DebugServer(mBackend, mDriver->getShaderLanguage(), port);
|
||||
debug.server = new matdbg::DebugServer(mBackend, mDriver->getShaderLanguage(),
|
||||
matdbg::DbgShaderModel((uint8_t) mDriver->getShaderModel()), port);
|
||||
|
||||
// Sometimes the server can fail to spin up (e.g. if the above port is already in use).
|
||||
// When this occurs, carry onward, developers can look at civetweb.txt for details.
|
||||
|
||||
@@ -154,7 +154,14 @@ public:
|
||||
#if FILAMENT_ENABLE_MATDBG
|
||||
assert_invariant((size_t)variant.key < VARIANT_COUNT);
|
||||
std::unique_lock<utils::Mutex> lock(mActiveProgramsLock);
|
||||
mActivePrograms.set(variant.key);
|
||||
if (getMaterialDomain() == MaterialDomain::SURFACE) {
|
||||
auto vert = Variant::filterVariantVertex(variant);
|
||||
auto frag = Variant::filterVariantFragment(variant);
|
||||
mActivePrograms.set(vert.key);
|
||||
mActivePrograms.set(frag.key);
|
||||
} else {
|
||||
mActivePrograms.set(variant.key);
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
if (isSharedVariant(variant)) {
|
||||
|
||||
@@ -638,6 +638,9 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) {
|
||||
if (isRenderingMultiview) {
|
||||
hasPostProcess = false;
|
||||
msaaOptions.enabled = false;
|
||||
|
||||
// Picking is not supported for multiview rendering. Clear any pending picking queries.
|
||||
view.clearPickingQueries();
|
||||
}
|
||||
const uint8_t msaaSampleCount = msaaOptions.enabled ? msaaOptions.sampleCount : 1u;
|
||||
|
||||
|
||||
@@ -164,6 +164,26 @@ Texture* Texture::Builder::build(Engine& engine) {
|
||||
(isProtectedTexturesSupported && useProtectedMemory) || !useProtectedMemory)
|
||||
<< "Texture is PROTECTED but protected textures are not supported";
|
||||
|
||||
const auto validateSamplerType = [&engine = downcast(engine)](SamplerType const sampler) -> bool {
|
||||
switch (sampler) {
|
||||
case SamplerType::SAMPLER_2D:
|
||||
case SamplerType::SAMPLER_CUBEMAP:
|
||||
case SamplerType::SAMPLER_EXTERNAL:
|
||||
return true;
|
||||
case SamplerType::SAMPLER_3D:
|
||||
case SamplerType::SAMPLER_2D_ARRAY:
|
||||
return engine.hasFeatureLevel(FeatureLevel::FEATURE_LEVEL_1);
|
||||
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||
return engine.hasFeatureLevel(FeatureLevel::FEATURE_LEVEL_2);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// Validate sampler before any further interaction with it.
|
||||
FILAMENT_CHECK_PRECONDITION(validateSamplerType(mImpl->mTarget))
|
||||
<< "SamplerType " << uint8_t(mImpl->mTarget) << " not support at feature level "
|
||||
<< uint8_t(engine.getActiveFeatureLevel());
|
||||
|
||||
// SAMPLER_EXTERNAL implies imported.
|
||||
if (mImpl->mTarget == SamplerType::SAMPLER_EXTERNAL) {
|
||||
mImpl->mExternal = true;
|
||||
@@ -216,24 +236,6 @@ Texture* Texture::Builder::build(Engine& engine) {
|
||||
FILAMENT_CHECK_PRECONDITION(!swizzled) << "WebGL does not support texture swizzling.";
|
||||
#endif
|
||||
|
||||
auto validateSamplerType = [&engine = downcast(engine)](SamplerType const sampler) -> bool {
|
||||
switch (sampler) {
|
||||
case SamplerType::SAMPLER_2D:
|
||||
case SamplerType::SAMPLER_CUBEMAP:
|
||||
case SamplerType::SAMPLER_EXTERNAL:
|
||||
return true;
|
||||
case SamplerType::SAMPLER_3D:
|
||||
case SamplerType::SAMPLER_2D_ARRAY:
|
||||
return engine.hasFeatureLevel(FeatureLevel::FEATURE_LEVEL_1);
|
||||
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||
return engine.hasFeatureLevel(FeatureLevel::FEATURE_LEVEL_2);
|
||||
}
|
||||
};
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION(validateSamplerType(mImpl->mTarget))
|
||||
<< "SamplerType " << uint8_t(mImpl->mTarget) << " not support at feature level "
|
||||
<< uint8_t(engine.getActiveFeatureLevel());
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION((swizzled && sampleable) || !swizzled)
|
||||
<< "Swizzled texture must be SAMPLEABLE";
|
||||
|
||||
|
||||
@@ -137,12 +137,7 @@ FView::~FView() noexcept = default;
|
||||
void FView::terminate(FEngine& engine) {
|
||||
// Here we would cleanly free resources we've allocated, or we own (currently none).
|
||||
|
||||
while (mActivePickingQueriesList) {
|
||||
FPickingQuery* const pQuery = mActivePickingQueriesList;
|
||||
mActivePickingQueriesList = pQuery->next;
|
||||
pQuery->callback(pQuery->result, pQuery);
|
||||
FPickingQuery::put(pQuery);
|
||||
}
|
||||
clearPickingQueries();
|
||||
|
||||
DriverApi& driver = engine.getDriverApi();
|
||||
driver.destroyBufferObject(mLightUbh);
|
||||
@@ -1178,6 +1173,15 @@ void FView::executePickingQueries(DriverApi& driver,
|
||||
}
|
||||
}
|
||||
|
||||
void FView::clearPickingQueries() noexcept {
|
||||
while (mActivePickingQueriesList) {
|
||||
FPickingQuery* const pQuery = mActivePickingQueriesList;
|
||||
mActivePickingQueriesList = pQuery->next;
|
||||
pQuery->callback(pQuery->result, pQuery);
|
||||
FPickingQuery::put(pQuery);
|
||||
}
|
||||
}
|
||||
|
||||
void FView::setTemporalAntiAliasingOptions(TemporalAntiAliasingOptions options) noexcept {
|
||||
options.feedback = clamp(options.feedback, 0.0f, 1.0f);
|
||||
options.filterWidth = std::max(0.2f, options.filterWidth); // below 0.2 causes issues
|
||||
|
||||
@@ -463,6 +463,8 @@ public:
|
||||
void executePickingQueries(backend::DriverApi& driver,
|
||||
backend::RenderTargetHandle handle, math::float2 scale) noexcept;
|
||||
|
||||
void clearPickingQueries() noexcept;
|
||||
|
||||
void setMaterialGlobal(uint32_t index, math::float4 const& value);
|
||||
|
||||
math::float4 getMaterialGlobal(uint32_t index) const;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.58.0"
|
||||
spec.version = "1.58.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.58.0/filament-v1.58.0-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.58.1/filament-v1.58.1-ios.tgz" }
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
|
||||
@@ -26,16 +26,47 @@ set(SRCS
|
||||
src/JsonWriter.cpp
|
||||
)
|
||||
|
||||
# ==================================================================================================
|
||||
# Resources
|
||||
# ==================================================================================================
|
||||
|
||||
set(RESOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(RESOURCE_BINS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/web/api.js
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/web/app.js
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/web/index.html
|
||||
)
|
||||
|
||||
get_resgen_vars(${RESOURCE_DIR} fgviewer_resources)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${RESGEN_OUTPUTS}
|
||||
COMMAND resgen -t ${RESGEN_FLAGS} ${RESOURCE_BINS}
|
||||
DEPENDS resgen ${RESOURCE_BINS}
|
||||
)
|
||||
|
||||
if (DEFINED RESGEN_SOURCE_FLAGS)
|
||||
set_source_files_properties(${RESGEN_SOURCE} PROPERTIES COMPILE_FLAGS ${RESGEN_SOURCE_FLAGS})
|
||||
endif()
|
||||
|
||||
set(DUMMY_SRC "${RESOURCE_DIR}/dummy.c")
|
||||
add_custom_command(OUTPUT ${DUMMY_SRC} COMMAND echo "//" > ${DUMMY_SRC})
|
||||
|
||||
add_library(fgviewer_resources ${DUMMY_SRC} ${RESGEN_SOURCE})
|
||||
set_target_properties(fgviewer_resources PROPERTIES FOLDER Libs)
|
||||
|
||||
# ==================================================================================================
|
||||
# Include and target definitions
|
||||
# ==================================================================================================
|
||||
|
||||
include_directories(${PUBLIC_HDR_DIR})
|
||||
include_directories(${PUBLIC_HDR_DIR} ${RESOURCE_DIR})
|
||||
|
||||
add_library(${TARGET} STATIC ${PUBLIC_HDRS} ${SRCS})
|
||||
|
||||
target_link_libraries(${TARGET} PUBLIC
|
||||
civetweb
|
||||
fgviewer_resources
|
||||
utils
|
||||
)
|
||||
|
||||
@@ -57,11 +88,12 @@ endif()
|
||||
# Installation
|
||||
# ==================================================================================================
|
||||
|
||||
# matdbg has dependencies on non-installed libraries. Here we bundle them all together into a single
|
||||
# fgviewer has dependencies on non-installed libraries. Here we bundle them all together into a single
|
||||
# library that gets copied into the installation folder so users are only required to link against
|
||||
# matdbg.
|
||||
# fgviewer.
|
||||
set(FGVIEWER_DEPS
|
||||
fgviewer
|
||||
fgviewer_resources
|
||||
civetweb
|
||||
)
|
||||
|
||||
|
||||
@@ -30,9 +30,26 @@
|
||||
|
||||
namespace filament::fgviewer {
|
||||
|
||||
// If set to 0, this serves HTML from a resgen resource. Use 1 only during local development, which
|
||||
// serves files directly from the source code tree.
|
||||
#define SERVE_FROM_SOURCE_TREE 0
|
||||
|
||||
#if SERVE_FROM_SOURCE_TREE
|
||||
namespace {
|
||||
std::string const BASE_URL = "libs/fgviewer/web";
|
||||
} // anonymous
|
||||
#else
|
||||
#include "fgviewer_resources.h"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace {
|
||||
struct Asset {
|
||||
std::string_view mime;
|
||||
std::string_view data;
|
||||
};
|
||||
std::unordered_map<std::string_view, Asset> ASSET_MAP;
|
||||
} // anonymous
|
||||
#endif // SERVE_FROM_SOURCE_TREE
|
||||
|
||||
using namespace utils;
|
||||
|
||||
@@ -56,10 +73,21 @@ public:
|
||||
uri = "/index.html";
|
||||
}
|
||||
|
||||
#if SERVE_FROM_SOURCE_TREE
|
||||
if (uri == "/index.html" || uri == "/app.js" || uri == "/api.js") {
|
||||
mg_send_file(conn, (BASE_URL + uri).c_str());
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
auto const& asset_itr = ASSET_MAP.find(uri);
|
||||
if (asset_itr != ASSET_MAP.end()) {
|
||||
auto const& mime = asset_itr->second.mime;
|
||||
auto const& data = asset_itr->second.data;
|
||||
mg_printf(conn, kSuccessHeader.data(), mime.data());
|
||||
mg_write(conn, data.data(), data.size());
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
slog.e << "[fgviewer] DebugServer: bad request at line " << __LINE__ << ": " << uri << io::endl;
|
||||
return false;
|
||||
}
|
||||
@@ -68,6 +96,21 @@ private:
|
||||
};
|
||||
|
||||
DebugServer::DebugServer(int port) {
|
||||
#if !SERVE_FROM_SOURCE_TREE
|
||||
ASSET_MAP["/index.html"] = {
|
||||
.mime = "text/html",
|
||||
.data = {(char const*) FGVIEWER_RESOURCES_INDEX_DATA},
|
||||
};
|
||||
ASSET_MAP["/app.js"] = {
|
||||
.mime = "text/javascript",
|
||||
.data = {(char const*) FGVIEWER_RESOURCES_APP_DATA},
|
||||
};
|
||||
ASSET_MAP["/api.js"] = {
|
||||
.mime = "text/javascript",
|
||||
.data = {(char const*) FGVIEWER_RESOURCES_API_DATA},
|
||||
};
|
||||
#endif
|
||||
|
||||
// By default the server spawns 50 threads so we override this to 10. According to the civetweb
|
||||
// documentation, "it is recommended to use num_threads of at least 5, since browsers often
|
||||
/// establish multiple connections to load a single web page, including all linked documents
|
||||
|
||||
+45
-29
@@ -16,7 +16,7 @@
|
||||
|
||||
import {LitElement, html, css, unsafeCSS, nothing} from "https://unpkg.com/lit@2.8.0?module";
|
||||
|
||||
const kUntitledPlaceholder = "untitled";
|
||||
const kUntitledPlaceholder = "Untitled View";
|
||||
|
||||
// CSS constants
|
||||
const FOREGROUND_COLOR = '#fafafa';
|
||||
@@ -293,11 +293,6 @@ class FrameGraphTable extends LitElement {
|
||||
margin-right: 5px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.scrollable-table td,
|
||||
.scrollable-table th {
|
||||
padding: 12px;
|
||||
@@ -351,6 +346,7 @@ class FrameGraphTable extends LitElement {
|
||||
super();
|
||||
this.frameGraphData = null;
|
||||
this.selectedResourceId = -1;
|
||||
this.collapsedResources = new Set();
|
||||
}
|
||||
|
||||
updated(props) {
|
||||
@@ -369,11 +365,13 @@ class FrameGraphTable extends LitElement {
|
||||
}
|
||||
|
||||
_toggleCollapse(resourceIndex) {
|
||||
const subresourceRows = this.shadowRoot.querySelectorAll(`[id^="subresource-${resourceIndex}-"]`);
|
||||
const icon = this.shadowRoot.querySelector(`#resource-${resourceIndex} .toggle-icon`);
|
||||
const isHidden = subresourceRows[0]?.classList.contains('hidden');
|
||||
subresourceRows.forEach(row => row.classList.toggle('hidden'));
|
||||
icon.textContent = isHidden ? '▼' : '▶';
|
||||
if (this.collapsedResources.has(resourceIndex)) {
|
||||
this.collapsedResources.delete(resourceIndex);
|
||||
}
|
||||
else {
|
||||
this.collapsedResources.add(resourceIndex);
|
||||
}
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
_handleResourceClick(ev) {
|
||||
@@ -384,13 +382,16 @@ class FrameGraphTable extends LitElement {
|
||||
}));
|
||||
}
|
||||
|
||||
_renderResourceUsage(allPasses, resourceId, defaultColor) {
|
||||
_renderResourceUsage(allPasses, resourceIds, defaultColor) {
|
||||
return allPasses.map((passData, index) => {
|
||||
const isRead = passData?.reads.includes(resourceId);
|
||||
const isWrite = passData?.writes.includes(resourceId);
|
||||
const isRead = resourceIds.some(resourceId => passData?.reads.includes(resourceId));
|
||||
const isWrite = resourceIds.some(resourceId => passData?.writes.includes(resourceId));
|
||||
let type = null;
|
||||
|
||||
const hasUsed = (passData) => {
|
||||
return passData?.reads.includes(resourceId) || passData?.writes.includes(resourceId);
|
||||
return resourceIds.some(resourceId =>
|
||||
passData?.reads.includes(resourceId) || passData?.writes.includes(resourceId)
|
||||
);
|
||||
};
|
||||
const hasBeenUsedBefore = allPasses.slice(0, index).some(hasUsed);
|
||||
const willBeUsedLater = allPasses.slice(index + 1).some(hasUsed);
|
||||
@@ -399,6 +400,7 @@ class FrameGraphTable extends LitElement {
|
||||
else if (isRead) type = RESOURCE_USAGE_TYPE_READ;
|
||||
else if (isWrite) type = RESOURCE_USAGE_TYPE_WRITE;
|
||||
else if (hasBeenUsedBefore && willBeUsedLater) type = RESOURCE_USAGE_TYPE_NO_ACCESS;
|
||||
|
||||
return html`
|
||||
<td style="background-color: ${unsafeCSS(this._getCellColor(type, defaultColor))};">
|
||||
${type ?? nothing}
|
||||
@@ -423,24 +425,38 @@ class FrameGraphTable extends LitElement {
|
||||
}
|
||||
|
||||
_renderResourceRow(resource, resourceIndex, resources, allPasses) {
|
||||
const hasSubresources = resources.some(subresource => this._isSubresourceOfParent(subresource, resource));
|
||||
const subresourceIds = resources
|
||||
.filter(subresource => this._isSubresourceOfParent(subresource, resource))
|
||||
.map(subresource => subresource.id);
|
||||
|
||||
const hasSubresources = subresourceIds.length > 0;
|
||||
const isCollapsed = this.collapsedResources.has(resourceIndex);
|
||||
// Show the aggregated resource usage when the subresources are collapsed.
|
||||
const resourceIds = isCollapsed ? [resource.id, ...subresourceIds]:[resource.id];
|
||||
|
||||
const onClickResource = () => this._handleResourceClick(resource.id);
|
||||
const selectedStyle = resource.id === this.selectedResourceId ? "selected" : "";
|
||||
|
||||
return html`
|
||||
<tr id="resource-${resourceIndex}">
|
||||
<th class="sticky-col resource ${selectedStyle}" @click="${onClickResource}">
|
||||
${hasSubresources ? html`
|
||||
<span class="toggle-icon"
|
||||
@click="${() => this._toggleCollapse(resourceIndex)}">▶</span>` : nothing}
|
||||
${resource.name}
|
||||
</th>
|
||||
${this._renderResourceUsage(allPasses, resource.id, DEFAULT_COLOR)}
|
||||
</tr>
|
||||
${this._renderSubresourceRows(resources, resource, resourceIndex, allPasses)}
|
||||
`;
|
||||
<tr id="resource-${resourceIndex}">
|
||||
<th class="sticky-col resource ${selectedStyle}" @click="${onClickResource}">
|
||||
${hasSubresources
|
||||
? html`
|
||||
<span class="toggle-icon"
|
||||
@click="${(e) => { e.stopPropagation(); this._toggleCollapse(resourceIndex); }}">
|
||||
${isCollapsed ? '▶' : '▼'}
|
||||
</span>`
|
||||
: nothing}
|
||||
${resource.name}
|
||||
${hasSubresources && isCollapsed ? html`(${subresourceIds.length})` : nothing}
|
||||
</th>
|
||||
${this._renderResourceUsage(allPasses, resourceIds, DEFAULT_COLOR)}
|
||||
</tr>
|
||||
${!isCollapsed ? this._renderSubresourceRows(resources, resource, resourceIndex, allPasses) : nothing}
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
_renderSubresourceRows(resources, parentResource, resourceIndex, allPasses) {
|
||||
return resources
|
||||
.filter(subresource => this._isSubresourceOfParent(subresource, parentResource))
|
||||
@@ -452,13 +468,13 @@ class FrameGraphTable extends LitElement {
|
||||
const selectedStyle = subresource.id === this.selectedResourceId ? "selected" : "";
|
||||
|
||||
return html`
|
||||
<tr id="subresource-${resourceIndex}-${subIndex}" class="collapsible hidden">
|
||||
<tr id="subresource-${resourceIndex}-${subIndex}" class="collapsible">
|
||||
<td class="sticky-col resource ${selectedStyle}"
|
||||
@click="${onClickResource}"
|
||||
style="background-color: ${SUBRESOURCE_COLOR}">
|
||||
${subresource.name}
|
||||
</td>
|
||||
${this._renderResourceUsage(allPasses, subresource.id, SUBRESOURCE_COLOR)}
|
||||
${this._renderResourceUsage(allPasses, [subresource.id], SUBRESOURCE_COLOR)}
|
||||
</tr>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -85,6 +85,10 @@ target_include_directories(${TARGET} PUBLIC ${PUBLIC_HDR_DIR})
|
||||
set_target_properties(${TARGET} PROPERTIES FOLDER Libs)
|
||||
target_link_libraries(${TARGET} backend_headers shaders filabridge utils smol-v)
|
||||
|
||||
if (FILAMENT_SUPPORTS_WEBGPU)
|
||||
target_link_libraries(${TARGET} libtint)
|
||||
endif ()
|
||||
|
||||
# We are being naughty and accessing private headers here
|
||||
# For spirv-tools, we're just following glslang's example
|
||||
target_include_directories(${TARGET} PRIVATE ${spirv-tools_SOURCE_DIR}/include)
|
||||
|
||||
@@ -44,6 +44,10 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#ifdef FILAMENT_SUPPORTS_WEBGPU
|
||||
#include <tint/tint.h>
|
||||
#endif
|
||||
|
||||
using namespace glslang;
|
||||
using namespace spirv_cross;
|
||||
using namespace spvtools;
|
||||
@@ -514,8 +518,43 @@ void GLSLPostProcessor::spirvToMsl(const SpirvBlob* spirv, std::string* outMsl,
|
||||
}
|
||||
}
|
||||
|
||||
bool GLSLPostProcessor::spirvToWgsl(const SpirvBlob *spirv, std::string *outWsl) {
|
||||
#if FILAMENT_SUPPORTS_WEBGPU
|
||||
//Currently no options we want to use
|
||||
const tint::spirv::reader::Options readerOpts{};
|
||||
tint::wgsl::writer::Options writerOpts{};
|
||||
|
||||
tint::Program tintRead = tint::spirv::reader::Read(*spirv, readerOpts);
|
||||
|
||||
if (tintRead.Diagnostics().ContainsErrors()) {
|
||||
slog.w << "This tint reader error is currently ignored during WebGPU bringup:" << tintRead.Diagnostics().Str() << io::endl;
|
||||
|
||||
//TODO: We should actually return false here, but for initial debugging
|
||||
// let it slide until combined image sampler is resolved
|
||||
// return false;
|
||||
}
|
||||
|
||||
tint::Result<tint::wgsl::writer::Output> wgslOut = tint::wgsl::writer::Generate(tintRead,writerOpts);
|
||||
/// An instance of SuccessType that can be used to check a tint Result.
|
||||
tint::SuccessType tintSuccess;
|
||||
|
||||
if (wgslOut != tintSuccess) {
|
||||
slog.w << "This tint writer error is currently ignored during WebGPU bringup:" << wgslOut.Failure().reason.Str() << io::endl;
|
||||
//TODO: We should actually return false here, but for initial debugging
|
||||
// let it slide until combined image sampler is resolved
|
||||
// return false;
|
||||
}
|
||||
*outWsl = wgslOut->wgsl;
|
||||
return true;
|
||||
#else
|
||||
slog.i << "Trying to emit WGSL without including WebGPU dependencies, please set CMake arg FILAMENT_SUPPORTS_WEBGPU and FILAMENT_SUPPORTS_WEBGPU" << io::endl;
|
||||
return false;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
bool GLSLPostProcessor::process(const std::string& inputShader, Config const& config,
|
||||
std::string* outputGlsl, SpirvBlob* outputSpirv, std::string* outputMsl) {
|
||||
std::string* outputGlsl, SpirvBlob* outputSpirv, std::string* outputMsl, std::string* outputWgsl) {
|
||||
using TargetLanguage = MaterialBuilder::TargetLanguage;
|
||||
|
||||
if (config.targetLanguage == TargetLanguage::GLSL) {
|
||||
@@ -530,6 +569,7 @@ bool GLSLPostProcessor::process(const std::string& inputShader, Config const& co
|
||||
.glslOutput = outputGlsl,
|
||||
.spirvOutput = outputSpirv,
|
||||
.mslOutput = outputMsl,
|
||||
.wgslOutput = outputWgsl,
|
||||
};
|
||||
|
||||
switch (config.shaderType) {
|
||||
@@ -610,13 +650,20 @@ bool GLSLPostProcessor::process(const std::string& inputShader, Config const& co
|
||||
config.shaderType, config.shaderModel, config.hasFramebufferFetch, descriptors,
|
||||
mGenerateDebugInfo ? &internalConfig.minifier : nullptr);
|
||||
}
|
||||
if (internalConfig.wgslOutput) {
|
||||
if (!spirvToWgsl(internalConfig.spirvOutput, internalConfig.wgslOutput)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
slog.e << "GLSL post-processor invoked with optimization level NONE"
|
||||
<< io::endl;
|
||||
}
|
||||
break;
|
||||
case MaterialBuilder::Optimization::PREPROCESSOR:
|
||||
preprocessOptimization(tShader, config, internalConfig);
|
||||
if (!preprocessOptimization(tShader, config, internalConfig)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case MaterialBuilder::Optimization::SIZE:
|
||||
case MaterialBuilder::Optimization::PERFORMANCE:
|
||||
@@ -646,7 +693,7 @@ bool GLSLPostProcessor::process(const std::string& inputShader, Config const& co
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader,
|
||||
bool GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader,
|
||||
GLSLPostProcessor::Config const& config, InternalConfig& internalConfig) const {
|
||||
using TargetApi = MaterialBuilder::TargetApi;
|
||||
assert_invariant(bool(internalConfig.spirvOutput) == (config.targetApi != TargetApi::OPENGL));
|
||||
@@ -662,6 +709,7 @@ void GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader,
|
||||
|
||||
if (!ok) {
|
||||
slog.e << tShader.getInfoLog() << io::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (internalConfig.spirvOutput) {
|
||||
@@ -683,6 +731,7 @@ void GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader,
|
||||
bool const linkOk = program.link(msg);
|
||||
if (!ok || !linkOk) {
|
||||
slog.e << spirvShader.getInfoLog() << io::endl;
|
||||
return false;
|
||||
} else {
|
||||
SpvOptions options;
|
||||
options.generateDebugInfo = mGenerateDebugInfo;
|
||||
@@ -702,10 +751,17 @@ void GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader,
|
||||
config.shaderModel, config.hasFramebufferFetch, descriptors,
|
||||
mGenerateDebugInfo ? &internalConfig.minifier : nullptr);
|
||||
}
|
||||
if (internalConfig.wgslOutput) {
|
||||
if (!spirvToWgsl(internalConfig.spirvOutput, internalConfig.wgslOutput)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (internalConfig.glslOutput) {
|
||||
*internalConfig.glslOutput = glsl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GLSLPostProcessor::fullOptimization(const TShader& tShader,
|
||||
@@ -746,6 +802,11 @@ bool GLSLPostProcessor::fullOptimization(const TShader& tShader,
|
||||
config.hasFramebufferFetch, descriptors,
|
||||
mGenerateDebugInfo ? &internalConfig.minifier : nullptr);
|
||||
}
|
||||
if (internalConfig.wgslOutput) {
|
||||
if (!spirvToWgsl(&spirv, internalConfig.wgslOutput)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Transpile back to GLSL
|
||||
if (internalConfig.glslOutput) {
|
||||
|
||||
@@ -81,7 +81,8 @@ public:
|
||||
bool process(const std::string& inputShader, Config const& config,
|
||||
std::string* outputGlsl,
|
||||
SpirvBlob* outputSpirv,
|
||||
std::string* outputMsl);
|
||||
std::string* outputMsl,
|
||||
std::string* outputWgsl);
|
||||
|
||||
// public so backend_test can also use it
|
||||
static void spirvToMsl(const SpirvBlob* spirv, std::string* outMsl,
|
||||
@@ -89,11 +90,14 @@ public:
|
||||
bool useFramebufferFetch, const DescriptorSets& descriptorSets,
|
||||
const ShaderMinifier* minifier);
|
||||
|
||||
static bool spirvToWgsl(const SpirvBlob* spirv, std::string* outWsl);
|
||||
|
||||
private:
|
||||
struct InternalConfig {
|
||||
std::string* glslOutput = nullptr;
|
||||
SpirvBlob* spirvOutput = nullptr;
|
||||
std::string* mslOutput = nullptr;
|
||||
std::string* wgslOutput = nullptr;
|
||||
EShLanguage shLang = EShLangFragment;
|
||||
// use 100 for ES environment, 110 for desktop
|
||||
int langVersion = 0;
|
||||
@@ -103,7 +107,7 @@ private:
|
||||
bool fullOptimization(const glslang::TShader& tShader,
|
||||
GLSLPostProcessor::Config const& config, InternalConfig& internalConfig) const;
|
||||
|
||||
void preprocessOptimization(glslang::TShader& tShader,
|
||||
bool preprocessOptimization(glslang::TShader& tShader,
|
||||
GLSLPostProcessor::Config const& config, InternalConfig& internalConfig) const;
|
||||
|
||||
/**
|
||||
|
||||
@@ -909,6 +909,7 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
|
||||
const bool targetApiNeedsSpirv =
|
||||
(targetApi == TargetApi::VULKAN || targetApi == TargetApi::METAL);
|
||||
const bool targetApiNeedsMsl = targetApi == TargetApi::METAL;
|
||||
const bool targetApiNeedsWgsl = targetApi == TargetApi::WEBGPU;
|
||||
const bool targetApiNeedsGlsl = targetApi == TargetApi::OPENGL;
|
||||
|
||||
// Set when a job fails
|
||||
@@ -923,9 +924,11 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
|
||||
// TODO: avoid allocations when not required
|
||||
std::vector<uint32_t> spirv;
|
||||
std::string msl;
|
||||
std::string wgsl;
|
||||
|
||||
std::vector<uint32_t>* pSpirv = targetApiNeedsSpirv ? &spirv : nullptr;
|
||||
std::string* pMsl = targetApiNeedsMsl ? &msl : nullptr;
|
||||
std::string* pWgsl = targetApiNeedsWgsl ? &wgsl : nullptr;
|
||||
|
||||
TextEntry glslEntry{};
|
||||
BinaryEntry spirvEntry{};
|
||||
@@ -1006,7 +1009,7 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
|
||||
config.glsl.subpassInputToColorLocation.emplace_back(0, 0);
|
||||
}
|
||||
|
||||
bool const ok = postProcessor.process(shader, config, pGlsl, pSpirv, pMsl);
|
||||
bool const ok = postProcessor.process(shader, config, pGlsl, pSpirv, pMsl, pWgsl);
|
||||
if (!ok) {
|
||||
showErrorMessage(mMaterialName.c_str_safe(), v.variant, targetApi, v.stage,
|
||||
featureLevel, shader);
|
||||
|
||||
@@ -297,12 +297,22 @@ utils::io::sstream& CodeGenerator::generateCommonProlog(utils::io::sstream& out,
|
||||
generateSpecializationConstant(out, "BACKEND_FEATURE_LEVEL",
|
||||
+ReservedSpecializationConstants::BACKEND_FEATURE_LEVEL, 1);
|
||||
|
||||
generateSpecializationConstant(out, "CONFIG_MAX_INSTANCES",
|
||||
+ReservedSpecializationConstants::CONFIG_MAX_INSTANCES, (int)CONFIG_MAX_INSTANCES);
|
||||
if (mTargetApi == TargetApi::WEBGPU) {
|
||||
// Note: This is a revived hack for a hack.
|
||||
//
|
||||
// WGSL doesn't support specialization constants as an array length
|
||||
// CONFIG_MAX_INSTANCES is only needed for WebGL, so we can replace it with a constant.
|
||||
// More information at https://github.com/gpuweb/gpuweb/issues/572#issuecomment-649760005
|
||||
out << "const int CONFIG_MAX_INSTANCES = " << (int)CONFIG_MAX_INSTANCES << ";\n";
|
||||
out << "const int CONFIG_FROXEL_BUFFER_HEIGHT = 2048;\n";
|
||||
} else {
|
||||
generateSpecializationConstant(out, "CONFIG_MAX_INSTANCES",
|
||||
+ReservedSpecializationConstants::CONFIG_MAX_INSTANCES, (int)CONFIG_MAX_INSTANCES);
|
||||
|
||||
// the default of 1024 (16KiB) is needed for 32% of Android devices
|
||||
generateSpecializationConstant(out, "CONFIG_FROXEL_BUFFER_HEIGHT",
|
||||
+ReservedSpecializationConstants::CONFIG_FROXEL_BUFFER_HEIGHT, 1024);
|
||||
// the default of 1024 (16KiB) is needed for 32% of Android devices
|
||||
generateSpecializationConstant(out, "CONFIG_FROXEL_BUFFER_HEIGHT",
|
||||
+ReservedSpecializationConstants::CONFIG_FROXEL_BUFFER_HEIGHT, 1024);
|
||||
}
|
||||
|
||||
// directional shadowmap visualization
|
||||
generateSpecializationConstant(out, "CONFIG_DEBUG_DIRECTIONAL_SHADOWMAP",
|
||||
|
||||
@@ -41,6 +41,13 @@ struct MaterialRecord {
|
||||
VariantList activeVariants;
|
||||
};
|
||||
|
||||
// Matches DriverEnums' ShaderModel
|
||||
enum class DbgShaderModel {
|
||||
MOBILE = 1, //!< Mobile level functionality
|
||||
DESKTOP = 2, //!< Desktop level functionality
|
||||
MATINFO = 10, //!< To indicate debug server is running from matinfo
|
||||
};
|
||||
|
||||
/**
|
||||
* Server-side material debugger.
|
||||
*
|
||||
@@ -52,7 +59,8 @@ public:
|
||||
static std::string_view const kSuccessHeader;
|
||||
static std::string_view const kErrorHeader;
|
||||
|
||||
DebugServer(backend::Backend backend, backend::ShaderLanguage shaderLanguage, int port);
|
||||
DebugServer(backend::Backend backend, backend::ShaderLanguage shaderLanguage,
|
||||
DbgShaderModel perferredShaderModel, int port);
|
||||
~DebugServer();
|
||||
|
||||
/**
|
||||
@@ -85,10 +93,13 @@ public:
|
||||
bool isReady() const { return mServer; }
|
||||
|
||||
private:
|
||||
// called from ApiHandler
|
||||
MaterialRecord const* getRecord(const MaterialKey& key) const;
|
||||
|
||||
// called from ApiHandler
|
||||
void updateActiveVariants();
|
||||
|
||||
// called from ApiHandler
|
||||
/**
|
||||
* Replaces the entire content of a particular shader variant. The given shader index uses the
|
||||
* same ordering that the variants have within the package.
|
||||
@@ -96,8 +107,9 @@ private:
|
||||
bool handleEditCommand(const MaterialKey& mat, backend::Backend api, int shaderIndex,
|
||||
const char* newShaderContent, size_t newShaderLength);
|
||||
|
||||
const backend::Backend mBackend;
|
||||
const backend::ShaderLanguage mShaderLanguage;
|
||||
backend::Backend const mBackend;
|
||||
backend::ShaderLanguage const mShaderLanguage;
|
||||
DbgShaderModel const mPreferredShaderModel;
|
||||
|
||||
CivetServer* mServer;
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#ifndef MATDBG_JSONWRITER_H
|
||||
#define MATDBG_JSONWRITER_H
|
||||
|
||||
#include <matdbg/DebugServer.h>
|
||||
|
||||
#include <filaflat/ChunkContainer.h>
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
@@ -47,7 +49,8 @@ public:
|
||||
// shader index is an active variant. Each bit in the activeVariants bitmask
|
||||
// represents one of the possible variant combinations.
|
||||
bool writeActiveInfo(const filaflat::ChunkContainer& package,
|
||||
backend::ShaderLanguage shaderLanguage, VariantList activeVariants);
|
||||
backend::ShaderLanguage shaderLanguage, DbgShaderModel shaderModel,
|
||||
VariantList activeVariants);
|
||||
|
||||
private:
|
||||
utils::CString mJsonString;
|
||||
|
||||
@@ -332,11 +332,12 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) {
|
||||
return error(__LINE__, uri);
|
||||
}
|
||||
JsonWriter writer;
|
||||
if (!writer.writeActiveInfo(package, mServer->mShaderLanguage, record.activeVariants)) {
|
||||
if (!writer.writeActiveInfo(package, mServer->mShaderLanguage,
|
||||
mServer->mPreferredShaderModel, record.activeVariants)) {
|
||||
return error(__LINE__, uri);
|
||||
}
|
||||
bool const last = (++index) == mServer->mMaterialRecords.size();
|
||||
mg_printf(conn, "\"%8.8x\": %s %s", pair.first, writer.getJsonString(),
|
||||
mg_printf(conn, "\"%8.8x\": %s%s", pair.first, writer.getJsonString(),
|
||||
last ? "" : ",");
|
||||
}
|
||||
mg_printf(conn, "}");
|
||||
@@ -356,6 +357,18 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto writeMaterialRecord = [&](JsonWriter* writer, MaterialRecord const* record) {
|
||||
ChunkContainer package(record->package, record->packageSize);
|
||||
if (!package.parse()) {
|
||||
return error(__LINE__, uri);
|
||||
}
|
||||
|
||||
if (!writer->writeMaterialInfo(package)) {
|
||||
return error(__LINE__, uri);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if (uri == "/api/materials") {
|
||||
std::unique_lock const lock(mServer->mMaterialRecordsMutex);
|
||||
mg_printf(conn, kSuccessHeader.data(), "application/json");
|
||||
@@ -363,17 +376,11 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) {
|
||||
int index = 0;
|
||||
for (auto const& record: mServer->mMaterialRecords) {
|
||||
bool const last = (++index) == mServer->mMaterialRecords.size();
|
||||
|
||||
ChunkContainer package(record.second.package, record.second.packageSize);
|
||||
if (!package.parse()) {
|
||||
return error(__LINE__, uri);
|
||||
}
|
||||
|
||||
auto const& mat = record.second;
|
||||
JsonWriter writer;
|
||||
if (!writer.writeMaterialInfo(package)) {
|
||||
return error(__LINE__, uri);
|
||||
if (!writeMaterialRecord(&writer, &mat)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mg_printf(conn, "{ \"matid\": \"%8.8x\", %s } %s", record.first, writer.getJsonString(),
|
||||
last ? "" : ",");
|
||||
}
|
||||
@@ -386,15 +393,9 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) {
|
||||
if (!result) {
|
||||
return error(__LINE__, uri);
|
||||
}
|
||||
|
||||
ChunkContainer package(result->package, result->packageSize);
|
||||
if (!package.parse()) {
|
||||
return error(__LINE__, uri);
|
||||
}
|
||||
|
||||
JsonWriter writer;
|
||||
if (!writer.writeMaterialInfo(package)) {
|
||||
return error(__LINE__, uri);
|
||||
if (!writeMaterialRecord(&writer, result)) {
|
||||
return false;
|
||||
}
|
||||
mg_printf(conn, kSuccessHeader.data(), "application/json");
|
||||
mg_printf(conn, "{ %s }", writer.getJsonString());
|
||||
|
||||
@@ -122,8 +122,11 @@ private:
|
||||
DebugServer* mServer;
|
||||
};
|
||||
|
||||
DebugServer::DebugServer(Backend backend, ShaderLanguage shaderLanguage, int port)
|
||||
: mBackend(backend), mShaderLanguage(shaderLanguage) {
|
||||
DebugServer::DebugServer(Backend backend, ShaderLanguage shaderLanguage,
|
||||
DbgShaderModel perferredShaderModel, int port)
|
||||
: mBackend(backend),
|
||||
mShaderLanguage(shaderLanguage),
|
||||
mPreferredShaderModel(perferredShaderModel) {
|
||||
|
||||
#if !SERVE_FROM_SOURCE_TREE
|
||||
ASSET_MAP["/index.html"] = {
|
||||
|
||||
@@ -232,7 +232,7 @@ size_t JsonWriter::getJsonSize() const {
|
||||
}
|
||||
|
||||
bool JsonWriter::writeActiveInfo(const filaflat::ChunkContainer& package,
|
||||
ShaderLanguage shaderLanguage, VariantList activeVariants) {
|
||||
ShaderLanguage shaderLanguage, DbgShaderModel shaderModel, VariantList activeVariants) {
|
||||
vector<ShaderInfo> shaders;
|
||||
ostringstream json;
|
||||
json << "[\"";
|
||||
@@ -260,7 +260,20 @@ bool JsonWriter::writeActiveInfo(const filaflat::ChunkContainer& package,
|
||||
shaders.resize(getShaderCount(package, chunkType));
|
||||
getShaderInfo(package, shaders.data(), chunkType);
|
||||
|
||||
json << "\", \"";
|
||||
switch (shaderModel) {
|
||||
case DbgShaderModel::DESKTOP:
|
||||
json << toString(ShaderModel::DESKTOP);
|
||||
break;
|
||||
case DbgShaderModel::MOBILE:
|
||||
json << toString(ShaderModel::MOBILE);
|
||||
break;
|
||||
case DbgShaderModel::MATINFO:
|
||||
json << "matinfo";
|
||||
break;
|
||||
}
|
||||
json << "\"";
|
||||
|
||||
for (size_t variant = 0; variant < activeVariants.size(); variant++) {
|
||||
if (activeVariants[variant]) {
|
||||
json << ", " << variant;
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
#include <matdbg/ShaderInfo.h>
|
||||
|
||||
#include "CommonWriter.h"
|
||||
|
||||
#include <filaflat/ChunkContainer.h>
|
||||
#include <filaflat/DictionaryReader.h>
|
||||
#include <filaflat/MaterialChunk.h>
|
||||
@@ -48,12 +50,16 @@ size_t getShaderCount(const ChunkContainer& container, ChunkType type) {
|
||||
return shaderCount;
|
||||
}
|
||||
|
||||
|
||||
bool getShaderInfo(const ChunkContainer& container, ShaderInfo* info, ChunkType chunkType) {
|
||||
if (!container.hasChunk(chunkType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MaterialDomain domain;
|
||||
if (!read(container, ChunkType::MaterialDomain, reinterpret_cast<uint8_t*>(&domain))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto [start, end] = container.getChunkRange(chunkType);
|
||||
Unflattener unflattener(start, end);
|
||||
|
||||
@@ -84,6 +90,12 @@ bool getShaderInfo(const ChunkContainer& container, ShaderInfo* info, ChunkType
|
||||
return false;
|
||||
}
|
||||
|
||||
auto stage = ShaderStage(pipelineStageValue);
|
||||
if (domain == MaterialDomain::SURFACE) {
|
||||
variant = stage == ShaderStage::VERTEX ?
|
||||
Variant::filterVariantVertex(variant) :
|
||||
Variant::filterVariantFragment(variant);
|
||||
}
|
||||
*info++ = {
|
||||
.shaderModel = ShaderModel(shaderModelValue),
|
||||
.variant = variant,
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#define MATDBG_SOURCE_FORMATTER_H
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
namespace filament::matdbg {
|
||||
|
||||
|
||||
@@ -68,14 +68,13 @@ async function fetchMatIds() {
|
||||
}
|
||||
|
||||
async function queryActiveShaders() {
|
||||
const activeMaterials = await _fetchJson("api/active");
|
||||
const activeVariants = await _fetchJson("api/active");
|
||||
const actives = {};
|
||||
for (matid in activeMaterials) {
|
||||
const backend = activeMaterials[matid][0];
|
||||
const variants = activeMaterials[matid].slice(1);
|
||||
actives[matid] = {
|
||||
backend, variants
|
||||
};
|
||||
for (matid in activeVariants) {
|
||||
const backend = activeVariants[matid][0];
|
||||
const shaderModel = activeVariants[matid][1];
|
||||
const variants = activeVariants[matid].slice(2);
|
||||
actives[matid] = { backend, shaderModel, variants };
|
||||
}
|
||||
return actives;
|
||||
}
|
||||
|
||||
+69
-50
@@ -59,8 +59,8 @@ const FOREGROUND_COLOR = '#fafafa';
|
||||
const INACTIVE_COLOR = '#9a9a9a';
|
||||
const DARKER_INACTIVE_COLOR = '#6f6f6f';
|
||||
const LIGHTER_INACTIVE_COLOR = '#d9d9d9';
|
||||
const UNSELECTED_COLOR = '#dfdfdf';
|
||||
const BACKGROUND_COLOR = '#5362e5';
|
||||
const UNSELECTED_COLOR = '#d0d0d0';
|
||||
const BACKGROUND_COLOR = '#6885c5';
|
||||
const HOVER_BACKGROUND_COLOR = '#b3c2ff';
|
||||
const CODE_VIEWER_BOTTOM_ROW_HEIGHT = 60;
|
||||
const REGULAR_FONT_SIZE = 12;
|
||||
@@ -343,7 +343,7 @@ class MenuSection extends LitElement {
|
||||
color: ${unsafeCSS(UNSELECTED_COLOR)};
|
||||
}
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-size: 20px;
|
||||
color: ${unsafeCSS(UNSELECTED_COLOR)};
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -365,6 +365,9 @@ class MenuSection extends LitElement {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.expanded-title {
|
||||
color: ${unsafeCSS(FOREGROUND_COLOR)};
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -380,9 +383,10 @@ class MenuSection extends LitElement {
|
||||
render() {
|
||||
const expandedIcon = this.showing ? '-' : '+';
|
||||
const slot = (() => html`<slot></slot>`)();
|
||||
const epandedTitleClass = this.showing ? 'expanded-title' : '';
|
||||
return html`
|
||||
<div class="container">
|
||||
<div class="section-title expander" @click="${this._showClick}">
|
||||
<div class="section-title expander ${epandedTitleClass}" @click="${this._showClick}">
|
||||
<span>${this.title}</span> <span>${expandedIcon}</span>
|
||||
</div>
|
||||
<hr />
|
||||
@@ -460,6 +464,7 @@ class AdvancedOptions extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
currentBackend: {type: String, attribute: 'current-backend'},
|
||||
currentShaderModel: {type: String, attribute: 'current-shader-model'},
|
||||
hideInactiveVariants: {type: Boolean, attribute: 'hide-inactive-variants'},
|
||||
availableBackends: {type: Array, state: true},
|
||||
};
|
||||
@@ -478,6 +483,7 @@ class AdvancedOptions extends LitElement {
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.borderless {
|
||||
border: 1px solid rgba(0,0,0,0);
|
||||
@@ -570,7 +576,7 @@ class AdvancedOptions extends LitElement {
|
||||
return html`
|
||||
<div class="option">
|
||||
<div class="option-heading">Current Backend</div>
|
||||
<form action="" id="backend-option-form">
|
||||
<form style="display:flex;flex-wrap:wrap" action="" id="backend-option-form">
|
||||
${div}
|
||||
</form>
|
||||
</div>
|
||||
@@ -578,6 +584,9 @@ class AdvancedOptions extends LitElement {
|
||||
}
|
||||
|
||||
_hideInactiveVariantsOption() {
|
||||
if (this.currentShaderModel == 'matinfo') {
|
||||
return null;
|
||||
}
|
||||
const onChange = (ev) => {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(
|
||||
@@ -585,7 +594,7 @@ class AdvancedOptions extends LitElement {
|
||||
{detail: null, bubbles: true, composed: true}));
|
||||
}
|
||||
return html`
|
||||
<div class="option borderless">
|
||||
<div class="option">
|
||||
<!--<div class="option-heading">Current Backend</div>-->
|
||||
<form action="" id="hide-inactive-variants-form">
|
||||
<input type="checkbox" name="InactiveVariants"
|
||||
@@ -630,8 +639,8 @@ class MaterialSidePanel extends LitElement {
|
||||
color: white;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
margin: 0 0 10px 0;
|
||||
font-size: 20px;
|
||||
margin: 0 0 20px 0;
|
||||
font-size: 25px;
|
||||
}
|
||||
.materials {
|
||||
display: flex;
|
||||
@@ -675,6 +684,7 @@ class MaterialSidePanel extends LitElement {
|
||||
currentBackend: {type: String, attribute: 'current-backend'},
|
||||
currentLanguage: {type: String, attribute: 'current-language'},
|
||||
hideInactiveVariants: {type: Boolean, attribute: 'hide-inactive-variants'},
|
||||
currentShaderModel: {type: String, attribute: 'current-shader-model'},
|
||||
|
||||
database: {type: Object, state: true},
|
||||
materials: {type: Array, state: true},
|
||||
@@ -702,29 +712,19 @@ class MaterialSidePanel extends LitElement {
|
||||
|
||||
updated(props) {
|
||||
if (props.has('database')) {
|
||||
const items = [];
|
||||
|
||||
// Names need not be unique, so we display a numeric suffix for non-unique names.
|
||||
// To achieve stable ordering of anonymous materials, we first sort by matid.
|
||||
const labels = new Set();
|
||||
const matids = Object.keys(this.database).sort();
|
||||
const duplicatedLabels = {};
|
||||
for (const matid of matids) {
|
||||
const name = this.database[matid].name || kUntitledPlaceholder;
|
||||
if (labels.has(name)) {
|
||||
duplicatedLabels[name] = 0;
|
||||
} else {
|
||||
labels.add(name);
|
||||
}
|
||||
}
|
||||
const names = matids.map(matid => (this.database[matid].name || kUntitledPlaceholder));
|
||||
const labelCount = {};
|
||||
names.forEach(name => labelCount[name] = (labelCount[name] || 0) + 1);
|
||||
const duplicates = names.filter(name => labelCount[name] > 1);
|
||||
|
||||
this.materials = matids.map((matid) => {
|
||||
const material = this.database[matid];
|
||||
let name = material.name || kUntitledPlaceholder;
|
||||
if (name in duplicatedLabels) {
|
||||
const index = duplicatedLabels[name];
|
||||
duplicatedLabels[name] = index + 1;
|
||||
name = `${name} (${index})`;
|
||||
if (duplicates.includes(name)) {
|
||||
name = `${name} (${labelCount[name]--})`;
|
||||
}
|
||||
return {
|
||||
matid: matid,
|
||||
@@ -784,7 +784,7 @@ class MaterialSidePanel extends LitElement {
|
||||
let divClass =
|
||||
'material_variant_language language' +
|
||||
(isLanguageSelected ? ' selected' : '') +
|
||||
(!isActive ? ' inactive' : '');
|
||||
(!isActive && this.currentShaderModel != 'matinfo' ? ' inactive' : '');
|
||||
const onClickLanguage = this._handleLanguageClick.bind(this, lang);
|
||||
lang = (isLanguageSelected ? '● ' : '') + lang;
|
||||
return html`
|
||||
@@ -796,10 +796,11 @@ class MaterialSidePanel extends LitElement {
|
||||
return html`<div class="languages">${languagesDiv}</div>`;
|
||||
}
|
||||
|
||||
_buildShaderDiv(showAllShaders) {
|
||||
_buildShaderDiv() {
|
||||
if (!this.variants) {
|
||||
return null;
|
||||
}
|
||||
const isMatinfo = this.currentShaderModel == 'matinfo';
|
||||
let variants =
|
||||
this.variants
|
||||
.sort((a, b) => {
|
||||
@@ -808,7 +809,10 @@ class MaterialSidePanel extends LitElement {
|
||||
if (b.active && !a.active) return 1;
|
||||
return 0;
|
||||
})
|
||||
.filter((variant) => (!this.hideInactiveVariants || variant.shader.active))
|
||||
.filter(variant => (!this.hideInactiveVariants || variant.shader.active))
|
||||
.filter(variant => (
|
||||
isMatinfo || variant.shader.shaderModel == this.currentShaderModel
|
||||
))
|
||||
.map((variant) => {
|
||||
let divClass = 'material_variant_language';
|
||||
const shaderIndex = +variant.shader.index;
|
||||
@@ -817,7 +821,7 @@ class MaterialSidePanel extends LitElement {
|
||||
if (isVariantSelected) {
|
||||
divClass += ' selected';
|
||||
}
|
||||
if (!isActive) {
|
||||
if (!isActive && !isMatinfo) {
|
||||
divClass += ' inactive';
|
||||
}
|
||||
const onClickVariant = this._handleVariantClick.bind(this, shaderIndex);
|
||||
@@ -826,11 +830,18 @@ class MaterialSidePanel extends LitElement {
|
||||
if (vstring.length > 0) {
|
||||
vstring = `[${vstring}]`;
|
||||
}
|
||||
const shaderModelSymbol = {
|
||||
'desktop': '🄳 ',
|
||||
'mobile': '🄼 ',
|
||||
};
|
||||
|
||||
let languagesDiv = isVariantSelected ? this._buildLanguagesDiv(isActive) : null;
|
||||
const stage = (isVariantSelected ? '● ' : '') + variant.shader.pipelineStage;
|
||||
const stage =
|
||||
(isMatinfo ? shaderModelSymbol[variant.shader.shaderModel] : '') +
|
||||
(variant.shader.pipelineStage.indexOf('vertex') >=0 ? '𝕍ert' : '𝔽rag');
|
||||
return html`
|
||||
<div class="${divClass}" @click="${onClickVariant}">
|
||||
<div>${stage} ${vstring} </div>
|
||||
<div>${stage}  ${vstring} </div>
|
||||
</div>
|
||||
${languagesDiv ?? nothing}
|
||||
`
|
||||
@@ -839,6 +850,7 @@ class MaterialSidePanel extends LitElement {
|
||||
}
|
||||
|
||||
render() {
|
||||
const isMatinfo = this.currentShaderModel == 'matinfo';
|
||||
const sections = (title, domain) => {
|
||||
const mats = this.materials
|
||||
.filter((m) => m.domain == domain)
|
||||
@@ -854,14 +866,12 @@ class MaterialSidePanel extends LitElement {
|
||||
const isMaterialSelected = mat.matid === this.currentMaterial;
|
||||
if (isMaterialSelected) {
|
||||
divClass += ' selected';
|
||||
// If we are looking at an inactive material, show all shaders regardless.
|
||||
const showAllShaders = !material.active;
|
||||
shaderDiv = this._buildShaderDiv(showAllShaders);
|
||||
shaderDiv = this._buildShaderDiv();
|
||||
}
|
||||
if (!material.active) {
|
||||
if (!material.active && !isMatinfo) {
|
||||
divClass += " inactive";
|
||||
}
|
||||
const matName = (isMaterialSelected ? '● ' : '') + mat.name;
|
||||
const matName = mat.name;
|
||||
return html`
|
||||
<div class="${divClass}" @click="${onClick}" data-id="${mat.matid}">
|
||||
${matName}
|
||||
@@ -878,6 +888,7 @@ class MaterialSidePanel extends LitElement {
|
||||
(() => html`
|
||||
<advanced-options id="advanced-options"
|
||||
current-backend=${this.currentBackend}
|
||||
current-shader-model=${this.currentShaderModel}
|
||||
?hide-inactive-variants=${this.hideInactiveVariants}
|
||||
></advanced-options>
|
||||
`)();
|
||||
@@ -885,7 +896,7 @@ class MaterialSidePanel extends LitElement {
|
||||
return html`
|
||||
<style>${this.dynamicStyle()}</style>
|
||||
<div class="container">
|
||||
<div class="title">matdbg</div>
|
||||
<div class="title">${isMatinfo ? 'matinfo' : 'matdbg'}</div>
|
||||
${sections("Surface", "surface") ?? nothing}
|
||||
${sections("Post-processing", "postpro") ?? nothing}
|
||||
<material-info id="material-info"></material-info>
|
||||
@@ -938,8 +949,7 @@ class MatdbgViewer extends LitElement {
|
||||
}
|
||||
);
|
||||
|
||||
let materials = await fetchMaterials();
|
||||
this.database = materials;
|
||||
this.database = await fetchMaterials();
|
||||
|
||||
// This is the user preferences stored in localStorage
|
||||
let hideInactiveVariantsVal = localStorage.getItem('option-hide-inactive-variants');
|
||||
@@ -979,6 +989,7 @@ class MatdbgViewer extends LitElement {
|
||||
this.currentMaterial = null;
|
||||
this.currentLanguage = null;
|
||||
this.currentBackend = null;
|
||||
this.currentShaderModel = null;
|
||||
this.hideInactiveVariants = false;
|
||||
this.init();
|
||||
|
||||
@@ -1049,6 +1060,7 @@ class MatdbgViewer extends LitElement {
|
||||
// Each material has a list of variants compiled for it, this index tracks a position in the list.
|
||||
currentShaderIndex: {type: Number, state: true},
|
||||
currentBackend: {type: String, state: true},
|
||||
currentShaderModel: {type: String, state: true},
|
||||
codeViewerExpectedWidth: {type: Number, state: true},
|
||||
codeViewerExpectedHeight: {type: Number, state: true},
|
||||
|
||||
@@ -1070,8 +1082,8 @@ class MatdbgViewer extends LitElement {
|
||||
const activeVariants = this.activeShaders[this.currentMaterial].variants;
|
||||
const materialShaders = material[this.currentBackend];
|
||||
for (let shader in materialShaders) {
|
||||
let ind = activeVariants.indexOf(+shader);
|
||||
if (ind >= 0) {
|
||||
const shaderVariant = materialShaders[shader].variant;
|
||||
if (activeVariants.indexOf(shaderVariant) >= 0) {
|
||||
this.currentShaderIndex = +shader;
|
||||
break;
|
||||
}
|
||||
@@ -1095,7 +1107,6 @@ class MatdbgViewer extends LitElement {
|
||||
shader.modified = false;
|
||||
this.database = this.database;
|
||||
}
|
||||
|
||||
// Size of the editor will be adjusted due to the code being loaded, we try to
|
||||
// fit the editor again by calling the resize signal.
|
||||
setTimeout(this._onResize.bind(this), 700);
|
||||
@@ -1119,22 +1130,29 @@ class MatdbgViewer extends LitElement {
|
||||
}
|
||||
}
|
||||
if (_validDict(this.activeShaders)) {
|
||||
let backends = {};
|
||||
let setBackend = null;
|
||||
let setShaderModel = null;
|
||||
for (let matid in this.activeShaders) {
|
||||
const backend = this.activeShaders[matid].backend;
|
||||
if (backend in backends) {
|
||||
backends[backend] = backends[backend] + 1;
|
||||
} else {
|
||||
backends[backend] = 1;
|
||||
if (!setBackend && backend) {
|
||||
setBackend = backend;
|
||||
}
|
||||
const shaderModel = this.activeShaders[matid].shaderModel;
|
||||
if (!setShaderModel && shaderModel) {
|
||||
setShaderModel = shaderModel;
|
||||
}
|
||||
}
|
||||
let backendList = Object.keys(backends);
|
||||
if (backendList.length > 0) {
|
||||
this.currentBackend = backendList[0];
|
||||
if (this.currentBackend != setBackend) {
|
||||
this.currentBackend = setBackend;
|
||||
}
|
||||
} else if (!this.currentBackend) {
|
||||
if (this.currentShaderModel != setShaderModel) {
|
||||
this.currentShaderModel = setShaderModel;
|
||||
}
|
||||
|
||||
} else if (!this.currentBackend || !this.currentShaderModel) {
|
||||
// Make a guess on the backend if one wasn't from activeShaders.
|
||||
this.currentBackend = guessBackend();
|
||||
this.currentShaderModel = 'matinfo';
|
||||
}
|
||||
|
||||
this._sidepanel.database = this.database;
|
||||
@@ -1166,6 +1184,7 @@ class MatdbgViewer extends LitElement {
|
||||
current-shader-index="${this.currentShaderIndex}"
|
||||
current-material="${this.currentMaterial}"
|
||||
current-backend="${this.currentBackend}"
|
||||
current-shader-model="${this.currentShaderModel}"
|
||||
?hide-inactive-variants="${this.hideInactiveVariants}" >
|
||||
</material-sidepanel>
|
||||
<code-viewer id="code-viewer"
|
||||
|
||||
Vendored
+3
-1
@@ -12,5 +12,7 @@ set(DAWN_ABSEIL_DIR ${EXTERNAL}/abseil)
|
||||
set(DAWN_SPIRV_TOOLS_DIR ${EXTERNAL}/spirv-tools/)
|
||||
set(DAWN_SPIRV_HEADERS_DIR ${EXTERNAL}/spirv-headers)
|
||||
set(DAWN_GLSLANG_DIR ${EXTERNAL}/glslang/)
|
||||
|
||||
if(IS_HOST_PLATFORM)
|
||||
set(TINT_BUILD_SPV_READER ON)
|
||||
endif ()
|
||||
add_subdirectory(../ ${PROJECT_BINARY_DIR}/third_party/dawn)
|
||||
@@ -423,7 +423,7 @@ static bool parseChunks(Config config, void* data, size_t size) {
|
||||
if (config.serverPort) {
|
||||
// Spin up a web server on a secondary thread.
|
||||
DebugServer server(Backend::DEFAULT, filament::backend::ShaderLanguage::ESSL3,
|
||||
config.serverPort);
|
||||
filament::matdbg::DbgShaderModel::MATINFO, config.serverPort);
|
||||
if (!server.isReady()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "filament",
|
||||
"version": "1.58.0",
|
||||
"version": "1.58.1",
|
||||
"description": "Real-time physically based rendering engine",
|
||||
"main": "filament.js",
|
||||
"module": "filament.js",
|
||||
|
||||
Reference in New Issue
Block a user