From 87bdf96449df07e7b459b60d2c9f703ca03b836d Mon Sep 17 00:00:00 2001 From: Sungun Park Date: Thu, 30 Jan 2025 16:02:53 -0800 Subject: [PATCH 01/24] Refactor: Rename shader snippets w/ new naming convention (see README.md) (#8402) This commit renames all shader snippet files to conform to the newly introduced naming convention outlined in README.md. The new naming convention uses a `prefix_name.suffix` format to clearly indicate the purpose and target shader stage of each snippet. This improves the overall organization and readability of the shader code, making it easier to understand how each snippet contributes to the shader generation process. No functional changes were made to the shader code itself or source code. This is purely a refactoring for clarity and maintainability. --- filament/CMakeLists.txt | 8 +- .../backend/include/backend/DriverEnums.h | 2 +- filament/backend/src/metal/MetalDriver.mm | 4 +- filament/backend/src/vulkan/VulkanDriver.cpp | 4 +- filament/src/PostProcessManager.cpp | 2 +- filament/src/ShadowMap.cpp | 6 +- filament/src/details/MorphTargetBuffer.cpp | 2 +- filament/src/details/Renderer.cpp | 2 +- filament/src/details/SkinningBuffer.cpp | 2 +- .../materials/colorGrading/colorGrading.mat | 4 +- .../colorGrading/colorGradingAsSubpass.mat | 4 +- .../filamat/include/filamat/MaterialBuilder.h | 2 +- libs/filamat/src/MaterialBuilder.cpp | 12 +- libs/filamat/src/shaders/CodeGenerator.cpp | 169 +++++++++--------- libs/filamat/src/shaders/CodeGenerator.h | 48 ++--- libs/filamat/src/shaders/ShaderGenerator.cpp | 95 +++++----- libs/filamat/src/shaders/ShaderGenerator.h | 6 +- shaders/CMakeLists.txt | 70 ++++---- shaders/src/README.md | 34 ++++ .../src/{dithering.fs => inline_dithering.fs} | 0 .../src/{vignette.fs => inline_vignette.fs} | 0 .../{post_process.fs => post_process_main.fs} | 0 .../{post_process.vs => post_process_main.vs} | 0 ...lusion.fs => surface_ambient_occlusion.fs} | 0 shaders/src/{brdf.fs => surface_brdf.fs} | 0 .../{depth_main.fs => surface_depth_main.fs} | 4 +- shaders/src/{fog.fs => surface_fog.fs} | 0 .../src/{getters.cs => surface_getters.cs} | 0 .../src/{getters.fs => surface_getters.fs} | 0 .../src/{getters.vs => surface_getters.vs} | 0 ...nstancing.glsl => surface_instancing.glsl} | 0 ...tional.fs => surface_light_directional.fs} | 0 ..._indirect.fs => surface_light_indirect.fs} | 0 ..._punctual.fs => surface_light_punctual.fs} | 2 +- ...ctions.fs => surface_light_reflections.fs} | 0 ...common_lighting.fs => surface_lighting.fs} | 0 shaders/src/{main.cs => surface_main.cs} | 0 shaders/src/{main.fs => surface_main.fs} | 4 +- shaders/src/{main.vs => surface_main.vs} | 2 +- ...common_material.fs => surface_material.fs} | 0 ...l_inputs.fs => surface_material_inputs.fs} | 0 ...l_inputs.vs => surface_material_inputs.vs} | 0 ...{shading_lit.fs => surface_shading_lit.fs} | 0 ...ustom.fs => surface_shading_lit_custom.fs} | 0 ...loth.fs => surface_shading_model_cloth.fs} | 0 ...d.fs => surface_shading_model_standard.fs} | 4 +- ...fs => surface_shading_model_subsurface.fs} | 2 +- ...eters.fs => surface_shading_parameters.fs} | 0 ...ions.fs => surface_shading_reflections.fs} | 0 ...ding_unlit.fs => surface_shading_unlit.fs} | 0 .../{shadowing.fs => surface_shadowing.fs} | 0 ..._shadowing.glsl => surface_shadowing.glsl} | 0 .../{common_types.glsl => surface_types.glsl} | 0 .../{varyings.glsl => surface_varyings.glsl} | 2 +- 54 files changed, 262 insertions(+), 234 deletions(-) create mode 100644 shaders/src/README.md rename shaders/src/{dithering.fs => inline_dithering.fs} (100%) rename shaders/src/{vignette.fs => inline_vignette.fs} (100%) rename shaders/src/{post_process.fs => post_process_main.fs} (100%) rename shaders/src/{post_process.vs => post_process_main.vs} (100%) rename shaders/src/{ambient_occlusion.fs => surface_ambient_occlusion.fs} (100%) rename shaders/src/{brdf.fs => surface_brdf.fs} (100%) rename shaders/src/{depth_main.fs => surface_depth_main.fs} (97%) rename shaders/src/{fog.fs => surface_fog.fs} (100%) rename shaders/src/{getters.cs => surface_getters.cs} (100%) rename shaders/src/{getters.fs => surface_getters.fs} (100%) rename shaders/src/{getters.vs => surface_getters.vs} (100%) rename shaders/src/{common_instancing.glsl => surface_instancing.glsl} (100%) rename shaders/src/{light_directional.fs => surface_light_directional.fs} (100%) rename shaders/src/{light_indirect.fs => surface_light_indirect.fs} (100%) rename shaders/src/{light_punctual.fs => surface_light_punctual.fs} (99%) rename shaders/src/{light_reflections.fs => surface_light_reflections.fs} (100%) rename shaders/src/{common_lighting.fs => surface_lighting.fs} (100%) rename shaders/src/{main.cs => surface_main.cs} (100%) rename shaders/src/{main.fs => surface_main.fs} (96%) rename shaders/src/{main.vs => surface_main.vs} (99%) rename shaders/src/{common_material.fs => surface_material.fs} (100%) rename shaders/src/{material_inputs.fs => surface_material_inputs.fs} (100%) rename shaders/src/{material_inputs.vs => surface_material_inputs.vs} (100%) rename shaders/src/{shading_lit.fs => surface_shading_lit.fs} (100%) rename shaders/src/{shading_lit_custom.fs => surface_shading_lit_custom.fs} (100%) rename shaders/src/{shading_model_cloth.fs => surface_shading_model_cloth.fs} (100%) rename shaders/src/{shading_model_standard.fs => surface_shading_model_standard.fs} (97%) rename shaders/src/{shading_model_subsurface.fs => surface_shading_model_subsurface.fs} (95%) rename shaders/src/{shading_parameters.fs => surface_shading_parameters.fs} (100%) rename shaders/src/{shading_reflections.fs => surface_shading_reflections.fs} (100%) rename shaders/src/{shading_unlit.fs => surface_shading_unlit.fs} (100%) rename shaders/src/{shadowing.fs => surface_shadowing.fs} (100%) rename shaders/src/{common_shadowing.glsl => surface_shadowing.glsl} (100%) rename shaders/src/{common_types.glsl => surface_types.glsl} (100%) rename shaders/src/{varyings.glsl => surface_varyings.glsl} (97%) diff --git a/filament/CMakeLists.txt b/filament/CMakeLists.txt index 9f0364f94e..fae6565e68 100644 --- a/filament/CMakeLists.txt +++ b/filament/CMakeLists.txt @@ -385,16 +385,16 @@ endforeach() add_custom_command( OUTPUT "${MATERIAL_DIR}/colorGrading.filamat" - DEPENDS ../shaders/src/dithering.fs - DEPENDS ../shaders/src/vignette.fs + DEPENDS ../shaders/src/inline_dithering.fs + DEPENDS ../shaders/src/inline_vignette.fs DEPENDS src/materials/colorGrading/colorGrading.fs APPEND ) add_custom_command( OUTPUT "${MATERIAL_DIR}/colorGradingAsSubpass.filamat" - DEPENDS ../shaders/src/dithering.fs - DEPENDS ../shaders/src/vignette.fs + DEPENDS ../shaders/src/inline_dithering.fs + DEPENDS ../shaders/src/inline_vignette.fs DEPENDS src/materials/colorGrading/colorGrading.fs APPEND ) diff --git a/filament/backend/include/backend/DriverEnums.h b/filament/backend/include/backend/DriverEnums.h index 2b68ced9c1..726665e396 100644 --- a/filament/backend/include/backend/DriverEnums.h +++ b/filament/backend/include/backend/DriverEnums.h @@ -1302,7 +1302,7 @@ enum class Workaround : uint16_t { // for some uniform arrays, it's needed to do an initialization to avoid crash on adreno gpu ADRENO_UNIFORM_ARRAY_CRASH, // Workaround a Metal pipeline compilation error with the message: - // "Could not statically determine the target of a texture". See light_indirect.fs + // "Could not statically determine the target of a texture". See surface_light_indirect.fs METAL_STATIC_TEXTURE_TARGET_ERROR, // Adreno drivers sometimes aren't able to blit into a layer of a texture array. DISABLE_BLIT_INTO_TEXTURE_ARRAY, diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index a8eee36dcb..46f285213a 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -1134,8 +1134,8 @@ FeatureLevel MetalDriver::getFeatureLevel() { math::float2 MetalDriver::getClipSpaceParams() { // virtual and physical z-coordinate of clip-space is in [-w, 0] - // Note: this is actually never used (see: main.vs), but it's a backend API so we implement it - // properly. + // Note: this is actually never used (see: surface_main.vs), but it's a backend API so we + // implement it properly. return math::float2{ 1.0f, 0.0f }; } diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index 56c4a7a296..3443b1dfda 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -1091,8 +1091,8 @@ FeatureLevel VulkanDriver::getFeatureLevel() { math::float2 VulkanDriver::getClipSpaceParams() { // virtual and physical z-coordinate of clip-space is in [-w, 0] - // Note: this is actually never used (see: main.vs), but it's a backend API, so we implement it - // properly. + // Note: this is actually never used (see: surface_main.vs), but it's a backend API, so we + // implement it properly. return math::float2{ 1.0f, 0.0f }; } diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index d9ab8b0c16..469c0122ed 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -2661,7 +2661,7 @@ void PostProcessManager::TaaJitterCamera( // update projection matrix inoutCameraInfo->projection[2].xy -= jitterInClipSpace; // VERTEX_DOMAIN_DEVICE doesn't apply the projection, but it still needs this - // clip transform, so we apply it separately (see main.vs) + // clip transform, so we apply it separately (see surface_main.vs) inoutCameraInfo->clipTransform.zw -= jitterInClipSpace; } diff --git a/filament/src/ShadowMap.cpp b/filament/src/ShadowMap.cpp index b71345458d..4985c8ff08 100644 --- a/filament/src/ShadowMap.cpp +++ b/filament/src/ShadowMap.cpp @@ -253,7 +253,7 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine, // The model matrix below is in fact inverted to get the view matrix and passed to the // shader as 'viewFromWorldMatrix', and is used in the VSM case to compute the depth metric. - // (see depth_main.fs). Note that in the case of VSM, 'b' below is identity. + // (see surface_depth_main.fs). Note that in the case of VSM, 'b' below is identity. mCamera->setModelMatrix(FCamera::rigidTransformInverse(highPrecisionMultiplyd(Mv, b))); mCamera->setCustomProjection(mat4(Mn * F * WLMp), znear, zfar); @@ -315,7 +315,7 @@ ShadowMap::ShaderParameters ShadowMap::updatePunctual( // The model matrix below is in fact inverted to get the view matrix and passed to the // shader as 'viewFromWorldMatrix', and is used in the VSM case to compute the depth metric. - // (see depth_main.fs). Note that in the case of VSM, 'b' below is identity. + // (see surface_depth_main.fs). Note that in the case of VSM, 'b' below is identity. mCamera->setModelMatrix(FCamera::rigidTransformInverse(highPrecisionMultiplyd(Mv, b))); mCamera->setCustomProjection(highPrecisionMultiplyd(Mn, Mp), nearPlane, farPlane); @@ -719,7 +719,7 @@ mat4f ShadowMap::computeVsmLightSpaceMatrix(const mat4f& lightSpacePcf, // For VSM, we want to leave the z coordinate in linear light-space, normalized between [0, 1], // i.e. remapping [near, far] to [0, 1]. // When sampling a VSM shadow map, the shader follows suit, and doesn't divide by w for the z - // coordinate. See shadowing.fs. + // coordinate. See surface_shadowing.fs. // compute z' = -(Mv * position).z / (far - near) - (near / (far - near)) const float scale = 1.0f / (zfar - znear); mat4f lightSpaceVsm{ lightSpacePcf }; diff --git a/filament/src/details/MorphTargetBuffer.cpp b/filament/src/details/MorphTargetBuffer.cpp index c496d58b06..b65cd290a3 100644 --- a/filament/src/details/MorphTargetBuffer.cpp +++ b/filament/src/details/MorphTargetBuffer.cpp @@ -66,7 +66,7 @@ MorphTargetBuffer* MorphTargetBuffer::Builder::build(Engine& engine) { // ------------------------------------------------------------------------------------------------ // This value is limited by ES3.0, ES3.0 only guarantees 2048. -// When you change this value, you must change MAX_MORPH_TARGET_BUFFER_WIDTH at getters.vs +// When you change this value, you must change MAX_MORPH_TARGET_BUFFER_WIDTH at surface_getters.vs constexpr size_t MAX_MORPH_TARGET_BUFFER_WIDTH = 2048; static inline size_t getWidth(size_t const vertexCount) noexcept { diff --git a/filament/src/details/Renderer.cpp b/filament/src/details/Renderer.cpp index 186c6249c7..3abcfced58 100644 --- a/filament/src/details/Renderer.cpp +++ b/filament/src/details/Renderer.cpp @@ -781,7 +781,7 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { cameraInfo.projection = highPrecisionMultiply(ts, cameraInfo.projection); // VERTEX_DOMAIN_DEVICE doesn't apply the projection, but it still needs this - // clip transform, so we apply it separately (see main.vs) + // clip transform, so we apply it separately (see surface_main.vs) cameraInfo.clipTransform = { ts[0][0], ts[1][1], ts[3].x, ts[3].y }; // adjust svp to the new, larger, rendering dimensions diff --git a/filament/src/details/SkinningBuffer.cpp b/filament/src/details/SkinningBuffer.cpp index 8386aab0b6..1b608a3aff 100644 --- a/filament/src/details/SkinningBuffer.cpp +++ b/filament/src/details/SkinningBuffer.cpp @@ -174,7 +174,7 @@ void FSkinningBuffer::setBones(FEngine& engine, Handle handle, } // This value is limited by ES3.0, ES3.0 only guarantees 2048. -// When you change this value, you must change MAX_SKINNING_BUFFER_WIDTH at getters.vs +// When you change this value, you must change MAX_SKINNING_BUFFER_WIDTH at surface_getters.vs constexpr size_t MAX_SKINNING_BUFFER_WIDTH = 2048; static inline size_t getSkinningBufferWidth(size_t const pairCount) noexcept { diff --git a/filament/src/materials/colorGrading/colorGrading.mat b/filament/src/materials/colorGrading/colorGrading.mat index 83712beafe..20315b5a62 100644 --- a/filament/src/materials/colorGrading/colorGrading.mat +++ b/filament/src/materials/colorGrading/colorGrading.mat @@ -83,8 +83,8 @@ vertex { fragment { -#include "../../../../shaders/src/dithering.fs" -#include "../../../../shaders/src/vignette.fs" +#include "../../../../shaders/src/inline_dithering.fs" +#include "../../../../shaders/src/inline_vignette.fs" #include "colorGrading.fs" void dummy(){} diff --git a/filament/src/materials/colorGrading/colorGradingAsSubpass.mat b/filament/src/materials/colorGrading/colorGradingAsSubpass.mat index 236ab4d407..0875d2a655 100644 --- a/filament/src/materials/colorGrading/colorGradingAsSubpass.mat +++ b/filament/src/materials/colorGrading/colorGradingAsSubpass.mat @@ -71,8 +71,8 @@ vertex { fragment { -#include "../../../../shaders/src/dithering.fs" -#include "../../../../shaders/src/vignette.fs" +#include "../../../../shaders/src/inline_dithering.fs" +#include "../../../../shaders/src/inline_vignette.fs" #include "colorGrading.fs" void dummy(){} diff --git a/libs/filamat/include/filamat/MaterialBuilder.h b/libs/filamat/include/filamat/MaterialBuilder.h index f21abe129e..d031722027 100644 --- a/libs/filamat/include/filamat/MaterialBuilder.h +++ b/libs/filamat/include/filamat/MaterialBuilder.h @@ -727,7 +727,7 @@ public: static constexpr size_t MAX_DEPTH_OUTPUT = 1; static_assert(MAX_COLOR_OUTPUT == 8, "When updating MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT, manually update post_process_inputs.fs" - " and post_process.fs"); + " and post_process_main.fs"); // Preview the first shader generated by the given CodeGenParams. // This is used to run Static Code Analysis before generating a package. diff --git a/libs/filamat/src/MaterialBuilder.cpp b/libs/filamat/src/MaterialBuilder.cpp index 3a8061e4de..3d6f3af542 100644 --- a/libs/filamat/src/MaterialBuilder.cpp +++ b/libs/filamat/src/MaterialBuilder.cpp @@ -937,15 +937,15 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector= alpha) { discard; @@ -49,7 +49,7 @@ void main() { #endif #if defined(VARIANT_HAS_VSM) - // interpolated depth is stored in vertex_worldPosition.w (see main.vs) + // interpolated depth is stored in vertex_worldPosition.w (see surface_main.vs) // we always compute the "negative" side of ELVSM because the cost is small, and this allows // EVSM/ELVSM choice to be done on the CPU side more easily. highp float depth = vertex_worldPosition.w; diff --git a/shaders/src/fog.fs b/shaders/src/surface_fog.fs similarity index 100% rename from shaders/src/fog.fs rename to shaders/src/surface_fog.fs diff --git a/shaders/src/getters.cs b/shaders/src/surface_getters.cs similarity index 100% rename from shaders/src/getters.cs rename to shaders/src/surface_getters.cs diff --git a/shaders/src/getters.fs b/shaders/src/surface_getters.fs similarity index 100% rename from shaders/src/getters.fs rename to shaders/src/surface_getters.fs diff --git a/shaders/src/getters.vs b/shaders/src/surface_getters.vs similarity index 100% rename from shaders/src/getters.vs rename to shaders/src/surface_getters.vs diff --git a/shaders/src/common_instancing.glsl b/shaders/src/surface_instancing.glsl similarity index 100% rename from shaders/src/common_instancing.glsl rename to shaders/src/surface_instancing.glsl diff --git a/shaders/src/light_directional.fs b/shaders/src/surface_light_directional.fs similarity index 100% rename from shaders/src/light_directional.fs rename to shaders/src/surface_light_directional.fs diff --git a/shaders/src/light_indirect.fs b/shaders/src/surface_light_indirect.fs similarity index 100% rename from shaders/src/light_indirect.fs rename to shaders/src/surface_light_indirect.fs diff --git a/shaders/src/light_punctual.fs b/shaders/src/surface_light_punctual.fs similarity index 99% rename from shaders/src/light_punctual.fs rename to shaders/src/surface_light_punctual.fs index fa55b05728..a4d1f91257 100644 --- a/shaders/src/light_punctual.fs +++ b/shaders/src/surface_light_punctual.fs @@ -115,7 +115,7 @@ float getAngleAttenuation(const highp vec3 lightDir, const highp vec3 l, const h } /** - * Returns a Light structure (see common_lighting.fs) describing a point or spot light. + * Returns a Light structure (see surface_lighting.fs) describing a point or spot light. * The colorIntensity field will store the *pre-exposed* intensity of the light * in the w component. * diff --git a/shaders/src/light_reflections.fs b/shaders/src/surface_light_reflections.fs similarity index 100% rename from shaders/src/light_reflections.fs rename to shaders/src/surface_light_reflections.fs diff --git a/shaders/src/common_lighting.fs b/shaders/src/surface_lighting.fs similarity index 100% rename from shaders/src/common_lighting.fs rename to shaders/src/surface_lighting.fs diff --git a/shaders/src/main.cs b/shaders/src/surface_main.cs similarity index 100% rename from shaders/src/main.cs rename to shaders/src/surface_main.cs diff --git a/shaders/src/main.fs b/shaders/src/surface_main.fs similarity index 96% rename from shaders/src/main.fs rename to shaders/src/surface_main.fs index c0d6bdb61f..c9383a7bb0 100644 --- a/shaders/src/main.fs +++ b/shaders/src/surface_main.fs @@ -43,11 +43,11 @@ void main() { initObjectUniforms(); - // See shading_parameters.fs + // See surface_shading_parameters.fs // Computes global variables we need to evaluate material and lighting computeShadingParams(); - // Initialize the inputs to sensible default values, see material_inputs.fs + // Initialize the inputs to sensible default values, see surface_material_inputs.fs MaterialInputs inputs; initMaterial(inputs); diff --git a/shaders/src/main.vs b/shaders/src/surface_main.vs similarity index 99% rename from shaders/src/main.vs rename to shaders/src/surface_main.vs index bbb9230fc8..c8882de005 100644 --- a/shaders/src/main.vs +++ b/shaders/src/surface_main.vs @@ -33,7 +33,7 @@ void main() { initObjectUniforms(); - // Initialize the inputs to sensible default values, see material_inputs.vs + // Initialize the inputs to sensible default values, see surface_material_inputs.vs #if defined(USE_OPTIMIZED_DEPTH_VERTEX_SHADER) // In USE_OPTIMIZED_DEPTH_VERTEX_SHADER mode, we can even skip this if we're already in diff --git a/shaders/src/common_material.fs b/shaders/src/surface_material.fs similarity index 100% rename from shaders/src/common_material.fs rename to shaders/src/surface_material.fs diff --git a/shaders/src/material_inputs.fs b/shaders/src/surface_material_inputs.fs similarity index 100% rename from shaders/src/material_inputs.fs rename to shaders/src/surface_material_inputs.fs diff --git a/shaders/src/material_inputs.vs b/shaders/src/surface_material_inputs.vs similarity index 100% rename from shaders/src/material_inputs.vs rename to shaders/src/surface_material_inputs.vs diff --git a/shaders/src/shading_lit.fs b/shaders/src/surface_shading_lit.fs similarity index 100% rename from shaders/src/shading_lit.fs rename to shaders/src/surface_shading_lit.fs diff --git a/shaders/src/shading_lit_custom.fs b/shaders/src/surface_shading_lit_custom.fs similarity index 100% rename from shaders/src/shading_lit_custom.fs rename to shaders/src/surface_shading_lit_custom.fs diff --git a/shaders/src/shading_model_cloth.fs b/shaders/src/surface_shading_model_cloth.fs similarity index 100% rename from shaders/src/shading_model_cloth.fs rename to shaders/src/surface_shading_model_cloth.fs diff --git a/shaders/src/shading_model_standard.fs b/shaders/src/surface_shading_model_standard.fs similarity index 97% rename from shaders/src/shading_model_standard.fs rename to shaders/src/surface_shading_model_standard.fs index ca71d1de0f..0931fda63d 100644 --- a/shaders/src/shading_model_standard.fs +++ b/shaders/src/surface_shading_model_standard.fs @@ -91,7 +91,7 @@ vec3 diffuseLobe(const PixelParams pixel, float NoV, float NoL, float LoH) { * Surface BRDF * The surface BRDF uses a diffuse lobe and a specular lobe to render both * dielectrics and conductors. The specular lobe is based on the Cook-Torrance - * micro-facet model (see brdf.fs for more details). In addition, the specular + * micro-facet model (see surface_brdf.fs for more details). In addition, the specular * can be either isotropic or anisotropic. * * Clear coat BRDF @@ -99,7 +99,7 @@ vec3 diffuseLobe(const PixelParams pixel, float NoV, float NoL, float LoH) { * top of the surface. Its IOR is set to 1.5 (polyutherane) to simplify * our computations. This BRDF only contains a specular lobe and while based * on the Cook-Torrance microfacet model, it uses cheaper terms than the surface - * BRDF's specular lobe (see brdf.fs). + * BRDF's specular lobe (see surface_brdf.fs). */ vec3 surfaceShading(const PixelParams pixel, const Light light, float occlusion) { vec3 h = normalize(shading_view + light.l); diff --git a/shaders/src/shading_model_subsurface.fs b/shaders/src/surface_shading_model_subsurface.fs similarity index 95% rename from shaders/src/shading_model_subsurface.fs rename to shaders/src/surface_shading_model_subsurface.fs index c29c62a410..d608edafa3 100644 --- a/shaders/src/shading_model_subsurface.fs +++ b/shaders/src/surface_shading_model_subsurface.fs @@ -1,6 +1,6 @@ /** * Evalutes lit materials with the subsurface shading model. This model is a - * combination of a BRDF (the same used in shading_model_standard.fs, refer to that + * combination of a BRDF (the same used in surface_shading_model_standard.fs, refer to that * file for more information) and of an approximated BTDF to simulate subsurface * scattering. The BTDF itself is not physically based and does not represent a * correct interpretation of transmission events. diff --git a/shaders/src/shading_parameters.fs b/shaders/src/surface_shading_parameters.fs similarity index 100% rename from shaders/src/shading_parameters.fs rename to shaders/src/surface_shading_parameters.fs diff --git a/shaders/src/shading_reflections.fs b/shaders/src/surface_shading_reflections.fs similarity index 100% rename from shaders/src/shading_reflections.fs rename to shaders/src/surface_shading_reflections.fs diff --git a/shaders/src/shading_unlit.fs b/shaders/src/surface_shading_unlit.fs similarity index 100% rename from shaders/src/shading_unlit.fs rename to shaders/src/surface_shading_unlit.fs diff --git a/shaders/src/shadowing.fs b/shaders/src/surface_shadowing.fs similarity index 100% rename from shaders/src/shadowing.fs rename to shaders/src/surface_shadowing.fs diff --git a/shaders/src/common_shadowing.glsl b/shaders/src/surface_shadowing.glsl similarity index 100% rename from shaders/src/common_shadowing.glsl rename to shaders/src/surface_shadowing.glsl diff --git a/shaders/src/common_types.glsl b/shaders/src/surface_types.glsl similarity index 100% rename from shaders/src/common_types.glsl rename to shaders/src/surface_types.glsl diff --git a/shaders/src/varyings.glsl b/shaders/src/surface_varyings.glsl similarity index 97% rename from shaders/src/varyings.glsl rename to shaders/src/surface_varyings.glsl index a0478838de..7c1432ef98 100644 --- a/shaders/src/varyings.glsl +++ b/shaders/src/surface_varyings.glsl @@ -32,7 +32,7 @@ LAYOUT_LOCATION(10) VARYING highp vec4 vertex_uv01; LAYOUT_LOCATION(11) VARYING highp vec4 vertex_lightSpacePosition; #endif -// Note that fragColor is an output and is not declared here; see main.fs and depth_main.fs +// Note that fragColor is an output and is not declared here; see surface_main.fs and surface_depth_main.fs #if defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_INSTANCED) #if defined(GL_ES) && defined(FILAMENT_GLSLANG) From 40851f4b51997aedb1aab6012cdcb5a31a85699e Mon Sep 17 00:00:00 2001 From: Eliza Velasquez Date: Thu, 30 Jan 2025 15:43:59 -0800 Subject: [PATCH 02/24] matdbg: add support for essl1 shader debugging Fixes #8261 --- NEW_RELEASE_NOTES.md | 2 + .../backend/include/private/backend/Driver.h | 10 ++++ filament/backend/src/metal/MetalDriver.h | 1 + filament/backend/src/metal/MetalDriver.mm | 4 ++ filament/backend/src/noop/NoopDriver.cpp | 4 ++ filament/backend/src/noop/NoopDriver.h | 1 + filament/backend/src/opengl/OpenGLDriver.cpp | 4 ++ filament/backend/src/opengl/OpenGLDriver.h | 1 + filament/backend/src/vulkan/VulkanDriver.cpp | 5 ++ filament/backend/src/vulkan/VulkanDriver.h | 1 + filament/src/details/Engine.cpp | 44 ++++++++--------- filament/src/details/Engine.h | 12 +---- libs/matdbg/include/matdbg/DebugServer.h | 3 +- libs/matdbg/include/matdbg/JsonWriter.h | 4 +- libs/matdbg/include/matdbg/ShaderReplacer.h | 5 +- libs/matdbg/src/ApiHandler.cpp | 22 ++++++--- libs/matdbg/src/DebugServer.cpp | 49 +++++-------------- libs/matdbg/src/JsonWriter.cpp | 49 +++++++++++++------ libs/matdbg/src/ShaderReplacer.cpp | 35 +++++++++---- libs/matdbg/web/api.js | 6 ++- libs/matdbg/web/app.js | 15 ++++-- tools/matinfo/src/main.cpp | 3 +- 22 files changed, 171 insertions(+), 109 deletions(-) diff --git a/NEW_RELEASE_NOTES.md b/NEW_RELEASE_NOTES.md index 4a1a9c7fa7..8946d7501f 100644 --- a/NEW_RELEASE_NOTES.md +++ b/NEW_RELEASE_NOTES.md @@ -7,3 +7,5 @@ for next branch cut* header. appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md). ## Release notes for next branch cut + +- matdbg: Add support for debugging ESSL 1.0 shaders diff --git a/filament/backend/include/private/backend/Driver.h b/filament/backend/include/private/backend/Driver.h index 1fe1644681..a00d8e13db 100644 --- a/filament/backend/include/private/backend/Driver.h +++ b/filament/backend/include/private/backend/Driver.h @@ -69,6 +69,16 @@ public: virtual ShaderModel getShaderModel() const noexcept = 0; + // The shader language used for shaders for this driver, used to inform matdbg. + // + // For OpenGL, this distinguishes whether the driver's shaders are powered by ESSL1 or ESSL3. + // This information is used by matdbg to display the correct shader code to the web UI and patch + // the correct chunk when rebuilding shaders live. + // + // Metal shaders can either be MSL or Metal libraries, but at time of writing, matdbg can only + // interface with MSL. + virtual ShaderLanguage getShaderLanguage() const noexcept = 0; + // Returns the dispatcher. This is only called once during initialization of the CommandStream, // so it doesn't matter that it's virtual. virtual Dispatcher getDispatcher() const noexcept = 0; diff --git a/filament/backend/src/metal/MetalDriver.h b/filament/backend/src/metal/MetalDriver.h index ca14adf974..562bafb4aa 100644 --- a/filament/backend/src/metal/MetalDriver.h +++ b/filament/backend/src/metal/MetalDriver.h @@ -67,6 +67,7 @@ private: MetalContext* mContext; ShaderModel getShaderModel() const noexcept final; + ShaderLanguage getShaderLanguage() const noexcept final; // Overrides the default implementation by wrapping the call to fn in an @autoreleasepool block. void execute(std::function const& fn) noexcept final; diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index 46f285213a..e5b5dc6131 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -946,6 +946,10 @@ ShaderModel MetalDriver::getShaderModel() const noexcept { #endif } +ShaderLanguage MetalDriver::getShaderLanguage() const noexcept { + return ShaderLanguage::MSL; +} + Handle MetalDriver::createStreamNative(void* stream) { return {}; } diff --git a/filament/backend/src/noop/NoopDriver.cpp b/filament/backend/src/noop/NoopDriver.cpp index af3ad70fbb..a77200c6fb 100644 --- a/filament/backend/src/noop/NoopDriver.cpp +++ b/filament/backend/src/noop/NoopDriver.cpp @@ -39,6 +39,10 @@ ShaderModel NoopDriver::getShaderModel() const noexcept { #endif } +ShaderLanguage NoopDriver::getShaderLanguage() const noexcept { + return ShaderLanguage::ESSL3; +} + // explicit instantiation of the Dispatcher template class ConcreteDispatcher; diff --git a/filament/backend/src/noop/NoopDriver.h b/filament/backend/src/noop/NoopDriver.h index 5b4037f657..8b522304cc 100644 --- a/filament/backend/src/noop/NoopDriver.h +++ b/filament/backend/src/noop/NoopDriver.h @@ -34,6 +34,7 @@ public: private: ShaderModel getShaderModel() const noexcept final; + ShaderLanguage getShaderLanguage() const noexcept final; uint64_t nextFakeHandle = 1; diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 736fa0d676..8714bacba2 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -349,6 +349,10 @@ ShaderModel OpenGLDriver::getShaderModel() const noexcept { return mContext.getShaderModel(); } +ShaderLanguage OpenGLDriver::getShaderLanguage() const noexcept { + return mContext.isES2() ? ShaderLanguage::ESSL1 : ShaderLanguage::ESSL3; +} + // ------------------------------------------------------------------------------------------------ // Change and track GL state // ------------------------------------------------------------------------------------------------ diff --git a/filament/backend/src/opengl/OpenGLDriver.h b/filament/backend/src/opengl/OpenGLDriver.h index 29ea32c776..22dc76a2e7 100644 --- a/filament/backend/src/opengl/OpenGLDriver.h +++ b/filament/backend/src/opengl/OpenGLDriver.h @@ -204,6 +204,7 @@ private: } ShaderModel getShaderModel() const noexcept final; + ShaderLanguage getShaderLanguage() const noexcept final; /* * Driver interface diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index 3443b1dfda..bc0957bf52 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -26,6 +26,7 @@ #include "VulkanHandles.h" #include "VulkanMemory.h" #include "VulkanTexture.h" +#include "backend/DriverEnums.h" #include "memory/ResourceManager.h" #include "memory/ResourcePointer.h" @@ -295,6 +296,10 @@ ShaderModel VulkanDriver::getShaderModel() const noexcept { #endif } +ShaderLanguage VulkanDriver::getShaderLanguage() const noexcept { + return ShaderLanguage::SPIRV; +} + void VulkanDriver::terminate() { // Flush and wait here to make sure all queued commands are executed and resources that are tied // to those commands are no longer referenced. diff --git a/filament/backend/src/vulkan/VulkanDriver.h b/filament/backend/src/vulkan/VulkanDriver.h index 83215a2ce5..0d826fca48 100644 --- a/filament/backend/src/vulkan/VulkanDriver.h +++ b/filament/backend/src/vulkan/VulkanDriver.h @@ -93,6 +93,7 @@ private: Dispatcher getDispatcher() const noexcept final; ShaderModel getShaderModel() const noexcept final; + ShaderLanguage getShaderLanguage() const noexcept final; template friend class ConcreteDispatcher; diff --git a/filament/src/details/Engine.cpp b/filament/src/details/Engine.cpp index 2116fae4c1..732a3965a6 100644 --- a/filament/src/details/Engine.cpp +++ b/filament/src/details/Engine.cpp @@ -706,28 +706,6 @@ int FEngine::loop() { } } -#if FILAMENT_ENABLE_MATDBG - #ifdef __ANDROID__ - const char* portString = "8081"; - #else - const char* portString = getenv("FILAMENT_MATDBG_PORT"); - #endif - if (portString != nullptr) { - const int port = atoi(portString); - debug.server = new matdbg::DebugServer(mBackend, 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. - if (!debug.server->isReady()) { - delete debug.server; - debug.server = nullptr; - } else { - debug.server->setEditCallback(FMaterial::onEditCallback); - debug.server->setQueryCallback(FMaterial::onQueryCallback); - } - } -#endif - JobSystem::setThreadName("FEngine::loop"); JobSystem::setThreadPriority(JobSystem::Priority::DISPLAY); @@ -749,6 +727,28 @@ int FEngine::loop() { return 0; } +#if FILAMENT_ENABLE_MATDBG + #ifdef __ANDROID__ + const char* portString = "8081"; + #else + const char* portString = getenv("FILAMENT_MATDBG_PORT"); + #endif + if (portString != nullptr) { + const int port = atoi(portString); + debug.server = new matdbg::DebugServer(mBackend, mDriver->getShaderLanguage(), 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. + if (!debug.server->isReady()) { + delete debug.server; + debug.server = nullptr; + } else { + debug.server->setEditCallback(FMaterial::onEditCallback); + debug.server->setQueryCallback(FMaterial::onQueryCallback); + } + } +#endif + while (true) { if (!execute()) { break; diff --git a/filament/src/details/Engine.h b/filament/src/details/Engine.h index 28376a5b6b..7809e85c08 100644 --- a/filament/src/details/Engine.h +++ b/filament/src/details/Engine.h @@ -252,20 +252,12 @@ public: // Return a vector of shader languages, in order of preference. utils::FixedCapacityVector getShaderLanguage() const noexcept { switch (mBackend) { - case Backend::DEFAULT: - case Backend::NOOP: default: - return { backend::ShaderLanguage::ESSL3 }; - case Backend::OPENGL: - return { getDriver().getFeatureLevel() == FeatureLevel::FEATURE_LEVEL_0 - ? backend::ShaderLanguage::ESSL1 - : backend::ShaderLanguage::ESSL3 }; - case Backend::VULKAN: - return { backend::ShaderLanguage::SPIRV }; + return { getDriver().getShaderLanguage() }; case Backend::METAL: const auto& lang = mConfig.preferredShaderLanguage; if (lang == Config::ShaderLanguage::MSL) { - return { backend::ShaderLanguage::MSL, backend::ShaderLanguage::METAL_LIBRARY }; + return { backend::ShaderLanguage::MSL, backend::ShaderLanguage::METAL_LIBRARY}; } return { backend::ShaderLanguage::METAL_LIBRARY, backend::ShaderLanguage::MSL }; } diff --git a/libs/matdbg/include/matdbg/DebugServer.h b/libs/matdbg/include/matdbg/DebugServer.h index 4340001d66..86aaa79bd1 100644 --- a/libs/matdbg/include/matdbg/DebugServer.h +++ b/libs/matdbg/include/matdbg/DebugServer.h @@ -52,7 +52,7 @@ public: static std::string_view const kSuccessHeader; static std::string_view const kErrorHeader; - DebugServer(backend::Backend backend, int port); + DebugServer(backend::Backend backend, backend::ShaderLanguage shaderLanguage, int port); ~DebugServer(); /** @@ -97,6 +97,7 @@ private: const char* newShaderContent, size_t newShaderLength); const backend::Backend mBackend; + const backend::ShaderLanguage mShaderLanguage; CivetServer* mServer; diff --git a/libs/matdbg/include/matdbg/JsonWriter.h b/libs/matdbg/include/matdbg/JsonWriter.h index 8cfbebd1be..4291f6f749 100644 --- a/libs/matdbg/include/matdbg/JsonWriter.h +++ b/libs/matdbg/include/matdbg/JsonWriter.h @@ -46,8 +46,8 @@ public: // The array is of the form [ backend, shaderIndex0, shaderIndex1, ... ] where each // 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::Backend backend, - VariantList activeVariants); + bool writeActiveInfo(const filaflat::ChunkContainer& package, + backend::ShaderLanguage shaderLanguage, VariantList activeVariants); private: utils::CString mJsonString; diff --git a/libs/matdbg/include/matdbg/ShaderReplacer.h b/libs/matdbg/include/matdbg/ShaderReplacer.h index 36b0c536ec..ab6f49e33d 100644 --- a/libs/matdbg/include/matdbg/ShaderReplacer.h +++ b/libs/matdbg/include/matdbg/ShaderReplacer.h @@ -29,11 +29,13 @@ namespace matdbg { // in a manner similar to ShaderExtractor. class ShaderReplacer { public: - ShaderReplacer(backend::Backend backend, const void* data, size_t size); + ShaderReplacer(backend::Backend backend, backend::ShaderLanguage language, + const void* data, size_t size); ~ShaderReplacer(); bool replaceShaderSource(backend::ShaderModel shaderModel, Variant variant, backend::ShaderStage stage, const char* sourceString, size_t stringLength); const uint8_t* getEditedPackage() const; + filamat::ChunkType getMaterialTag() const noexcept; size_t getEditedSize() const; private: bool replaceSpirv(backend::ShaderModel shaderModel, Variant variant, @@ -42,6 +44,7 @@ private: filaflat::ChunkContainer mOriginalPackage; filaflat::ChunkContainer* mEditedPackage = nullptr; filamat::ChunkType mMaterialTag = filamat::ChunkType::Unknown; + filamat::ChunkType mDeleteTag = filamat::ChunkType::Unknown; filamat::ChunkType mDictionaryTag = filamat::ChunkType::Unknown; }; diff --git a/libs/matdbg/src/ApiHandler.cpp b/libs/matdbg/src/ApiHandler.cpp index c9ef42c0ee..d13161eeac 100644 --- a/libs/matdbg/src/ApiHandler.cpp +++ b/libs/matdbg/src/ApiHandler.cpp @@ -86,6 +86,8 @@ bool ApiHandler::handleGetApiShader(struct mg_connection* conn, } std::string_view const glsl("glsl"); + std::string_view const essl3("essl3"); + std::string_view const essl1("essl1"); std::string_view const msl("msl"); std::string_view const spirv("spirv"); size_t const qlength = strlen(request->query_string); @@ -109,12 +111,20 @@ bool ApiHandler::handleGetApiShader(struct mg_connection* conn, } if (glindex[0]) { - if (language != glsl) { - return softError("Only GLSL is supported."); + ChunkType chunkType; + ShaderLanguage shaderLanguage; + if (language == essl3) { + chunkType = ChunkType::MaterialGlsl; + shaderLanguage = ShaderLanguage::ESSL3; + } else if (language == essl1) { + chunkType = ChunkType::MaterialEssl1; + shaderLanguage = ShaderLanguage::ESSL1; + } else { + return softError("Only essl3 and essl1 are supported."); } - FixedCapacityVector info(getShaderCount(package, ChunkType::MaterialGlsl)); - if (!getShaderInfo(package, info.data(), ChunkType::MaterialGlsl)) { + FixedCapacityVector info(getShaderCount(package, chunkType)); + if (!getShaderInfo(package, info.data(), chunkType)) { return error(__LINE__, uri); } @@ -123,7 +133,7 @@ bool ApiHandler::handleGetApiShader(struct mg_connection* conn, return error(__LINE__, uri); } - ShaderExtractor extractor(ShaderLanguage::ESSL3, result->package, result->packageSize); + ShaderExtractor extractor(shaderLanguage, result->package, result->packageSize); if (!extractor.parse()) { return error(__LINE__, uri); } @@ -314,7 +324,7 @@ bool ApiHandler::handleGet(CivetServer* server, struct mg_connection* conn) { return error(__LINE__, uri); } JsonWriter writer; - if (!writer.writeActiveInfo(package, mServer->mBackend, record.activeVariants)) { + if (!writer.writeActiveInfo(package, mServer->mShaderLanguage, record.activeVariants)) { return error(__LINE__, uri); } bool const last = (++index) == mServer->mMaterialRecords.size(); diff --git a/libs/matdbg/src/DebugServer.cpp b/libs/matdbg/src/DebugServer.cpp index e8efb0b227..d75952728b 100644 --- a/libs/matdbg/src/DebugServer.cpp +++ b/libs/matdbg/src/DebugServer.cpp @@ -122,7 +122,8 @@ private: DebugServer* mServer; }; -DebugServer::DebugServer(Backend backend, int port) : mBackend(backend) { +DebugServer::DebugServer(Backend backend, ShaderLanguage shaderLanguage, int port) + : mBackend(backend), mShaderLanguage(shaderLanguage) { #if !SERVE_FROM_SOURCE_TREE ASSET_MAP["/index.html"] = { @@ -254,47 +255,23 @@ bool DebugServer::handleEditCommand(const MaterialKey& key, backend::Backend api return error(__LINE__); } - FixedCapacityVector infos; - size_t shaderCount; - switch (api) { - case backend::Backend::OPENGL: { - shaderCount = getShaderCount(package, ChunkType::MaterialGlsl); - infos.reserve(shaderCount); - infos.resize(shaderCount); - if (!getShaderInfo(package, infos.data(), ChunkType::MaterialGlsl)) { - return error(__LINE__); - } - break; - } - case backend::Backend::VULKAN: { - shaderCount = getShaderCount(package, ChunkType::MaterialSpirv); - infos.reserve(shaderCount); - infos.resize(shaderCount); - if (!getShaderInfo(package, infos.data(), ChunkType::MaterialSpirv)) { - return error(__LINE__); - } - break; - } - case backend::Backend::METAL: { - shaderCount = getShaderCount(package, ChunkType::MaterialMetal); - infos.reserve(shaderCount); - infos.resize(shaderCount); - if (!getShaderInfo(package, infos.data(), ChunkType::MaterialMetal)) { - return error(__LINE__); - } - break; - } - default: - error(__LINE__); - } + ShaderReplacer editor(api, mShaderLanguage, package.getData(), package.getSize()); + size_t shaderCount = getShaderCount(package, editor.getMaterialTag()); if (shaderIndex < 0 || shaderIndex >= shaderCount) { return error(__LINE__); } + FixedCapacityVector infos; + infos.reserve(shaderCount); + infos.resize(shaderCount); + if (!getShaderInfo(package, infos.data(), editor.getMaterialTag())) { + return error(__LINE__); + } + const ShaderInfo info = infos[shaderIndex]; - ShaderReplacer editor(api, package.getData(), package.getSize()); - if (!editor.replaceShaderSource(info.shaderModel, info.variant, info.pipelineStage, source, size)) { + if (!editor.replaceShaderSource(info.shaderModel, info.variant, info.pipelineStage, source, + size)) { return error(__LINE__); } diff --git a/libs/matdbg/src/JsonWriter.cpp b/libs/matdbg/src/JsonWriter.cpp index c9e94c8143..2a22eaeae2 100644 --- a/libs/matdbg/src/JsonWriter.cpp +++ b/libs/matdbg/src/JsonWriter.cpp @@ -136,13 +136,22 @@ static void printShaderInfo(ostream& json, const vector& info, const } } -static bool printGlslInfo(ostream& json, const ChunkContainer& container) { +static bool printGlslInfo(ostream& json, const ChunkContainer& container, ChunkType chunkType) { std::vector info; - info.resize(getShaderCount(container, ChunkType::MaterialGlsl)); - if (!getShaderInfo(container, info.data(), ChunkType::MaterialGlsl)) { + info.resize(getShaderCount(container, chunkType)); + if (!getShaderInfo(container, info.data(), chunkType)) { return false; } - json << "\"opengl\": [\n"; + switch (chunkType) { + case ChunkType::MaterialEssl1: + json << "\"essl1\": [\n"; + break; + case ChunkType::MaterialGlsl: + json << "\"opengl\": [\n"; + break; + default: + assert(false); // unreachable + } printShaderInfo(json, info, container); json << "],\n"; return true; @@ -180,7 +189,10 @@ bool JsonWriter::writeMaterialInfo(const filaflat::ChunkContainer& container) { if (!printParametersInfo(json, container)) { return false; } - if (!printGlslInfo(json, container)) { + if (!printGlslInfo(json, container, ChunkType::MaterialGlsl)) { + return false; + } + if (!printGlslInfo(json, container, ChunkType::MaterialEssl1)) { return false; } if (!printVkInfo(json, container)) { @@ -220,29 +232,34 @@ size_t JsonWriter::getJsonSize() const { } bool JsonWriter::writeActiveInfo(const filaflat::ChunkContainer& package, - Backend backend, VariantList activeVariants) { + ShaderLanguage shaderLanguage, VariantList activeVariants) { vector shaders; ostringstream json; json << "[\""; - switch (backend) { - case Backend::OPENGL: - shaders.resize(getShaderCount(package, ChunkType::MaterialGlsl)); - getShaderInfo(package, shaders.data(), ChunkType::MaterialGlsl); + ChunkType chunkType; + switch (shaderLanguage) { + case ShaderLanguage::ESSL1: + json << "essl1"; + chunkType = ChunkType::MaterialEssl1; + break; + case ShaderLanguage::ESSL3: json << "opengl"; + chunkType = ChunkType::MaterialGlsl; break; - case Backend::VULKAN: - shaders.resize(getShaderCount(package, ChunkType::MaterialSpirv)); - getShaderInfo(package, shaders.data(), ChunkType::MaterialSpirv); + case ShaderLanguage::SPIRV: json << "vulkan"; + chunkType = ChunkType::MaterialSpirv; break; - case Backend::METAL: - shaders.resize(getShaderCount(package, ChunkType::MaterialMetal)); - getShaderInfo(package, shaders.data(), ChunkType::MaterialMetal); + case ShaderLanguage::MSL: json << "metal"; + chunkType = ChunkType::MaterialMetal; break; default: return false; } + shaders.resize(getShaderCount(package, chunkType)); + getShaderInfo(package, shaders.data(), chunkType); + json << "\""; for (size_t variant = 0; variant < activeVariants.size(); variant++) { if (activeVariants[variant]) { diff --git a/libs/matdbg/src/ShaderReplacer.cpp b/libs/matdbg/src/ShaderReplacer.cpp index 8a457e598c..38e4b58229 100644 --- a/libs/matdbg/src/ShaderReplacer.cpp +++ b/libs/matdbg/src/ShaderReplacer.cpp @@ -94,22 +94,33 @@ private: filaflat::BlobDictionary mDataBlobs; }; -ShaderReplacer::ShaderReplacer(Backend backend, const void* data, size_t size) : +ShaderReplacer::ShaderReplacer(Backend backend, ShaderLanguage language, + const void* data, size_t size) : mBackend(backend), mOriginalPackage(data, size) { - switch (backend) { - case Backend::OPENGL: - mMaterialTag = ChunkType::MaterialGlsl; + switch (language) { + // ESSL1 and ESSL3 share the same dictionary, and replacing either will corrupt the other. + // If replacing one, delete both. + case backend::ShaderLanguage::ESSL1: + mMaterialTag = ChunkType::MaterialEssl1; + mDeleteTag = ChunkType::MaterialGlsl; mDictionaryTag = ChunkType::DictionaryText; break; - case Backend::METAL: + case backend::ShaderLanguage::ESSL3: + mMaterialTag = ChunkType::MaterialGlsl; + mDeleteTag = ChunkType::MaterialEssl1; + mDictionaryTag = ChunkType::DictionaryText; + break; + case backend::ShaderLanguage::MSL: mMaterialTag = ChunkType::MaterialMetal; mDictionaryTag = ChunkType::DictionaryText; break; - case Backend::VULKAN: + case backend::ShaderLanguage::SPIRV: mMaterialTag = ChunkType::MaterialSpirv; mDictionaryTag = ChunkType::DictionarySpirv; break; - default: + case backend::ShaderLanguage::METAL_LIBRARY: + mMaterialTag = ChunkType::MaterialMetalLibrary; + mDictionaryTag = ChunkType::DictionaryMetalLibrary; break; } } @@ -133,7 +144,7 @@ bool ShaderReplacer::replaceShaderSource(ShaderModel shaderModel, Variant varian return replaceSpirv(shaderModel, variant, stage, sourceString, stringLength); } - // Clone all chunks except Dictionary* and Material*. + // Clone (almost) all chunks except Dictionary* and Material*. stringstream sstream(std::string((const char*) cc.getData(), cc.getSize())); stringstream tstream; { @@ -145,7 +156,9 @@ bool ShaderReplacer::replaceShaderSource(ShaderModel shaderModel, Variant varian sstream.read((char*) &size, sizeof(size)); content.resize(size); sstream.read((char*) content.data(), size); - if (ChunkType(type) == mDictionaryTag|| ChunkType(type) == mMaterialTag) { + if (ChunkType(type) == mDictionaryTag + || ChunkType(type) == mDeleteTag + || ChunkType(type) == mMaterialTag) { continue; } tstream.write((char*) &type, sizeof(type)); @@ -297,6 +310,10 @@ size_t ShaderReplacer::getEditedSize() const { return mEditedPackage->getSize(); } +filamat::ChunkType ShaderReplacer::getMaterialTag() const noexcept { + return mMaterialTag; +} + ShaderIndex::ShaderIndex(ChunkType dictTag, ChunkType matTag, const filaflat::ChunkContainer& cc) : mDictTag(dictTag), mMatTag(matTag) { diff --git a/libs/matdbg/web/api.js b/libs/matdbg/web/api.js index 3a580fcacf..f16fec3a90 100644 --- a/libs/matdbg/web/api.js +++ b/libs/matdbg/web/api.js @@ -30,6 +30,7 @@ async function fetchShaderCode(matid, backend, language, index) { let query; switch (backend) { case "opengl": + case "essl1": query = `type=${language}&glindex=${index}`; break; case "vulkan": @@ -82,7 +83,10 @@ async function queryActiveShaders() { function rebuildMaterial(materialId, backend, shaderIndex, editedText) { let api = 0; switch (backend) { - case "opengl": api = 1; break; + case "opengl": + case "essl1": + api = 1; + break; case "vulkan": api = 2; break; case "metal": api = 3; break; } diff --git a/libs/matdbg/web/app.js b/libs/matdbg/web/app.js index 325d47487f..58858daa3c 100644 --- a/libs/matdbg/web/app.js +++ b/libs/matdbg/web/app.js @@ -20,11 +20,19 @@ const kUntitledPlaceholder = "untitled"; // Maps to backend to the languages allowed for that backend. const LANGUAGE_CHOICES = { - 'opengl': ['glsl'], + 'opengl': ['essl3', 'essl1'], + 'essl1': ['essl3', 'essl1'], 'vulkan': ['glsl', 'spirv'], 'metal': ['msl'], }; +const DEFAULT_LANGUAGE_FOR_BACKEND = { + 'opengl': 'essl3', + 'essl1': 'essl1', + 'vulkan': 'glsl', + 'metal': 'msl', +}; + const BACKENDS = Object.keys(LANGUAGE_CHOICES); const MATERIAL_INFO_KEY_TO_STRING = { @@ -1051,9 +1059,8 @@ class MatdbgViewer extends LitElement { updated(props) { // Set a language if there hasn't been one set. if (props.has('currentBackend') && this.currentBackend) { - const choices = LANGUAGE_CHOICES[this.currentBackend]; - if (choices.indexOf(this.currentLanguage) < 0) { - this.currentLanguage = choices[0]; + if (LANGUAGE_CHOICES[this.currentBackend].indexOf(this.currentLanguage) < 0) { + this.currentLanguage = DEFAULT_LANGUAGE_FOR_BACKEND[this.currentBackend]; } } if (props.has('currentMaterial')) { diff --git a/tools/matinfo/src/main.cpp b/tools/matinfo/src/main.cpp index ea2d1a0141..cf59f7bb69 100644 --- a/tools/matinfo/src/main.cpp +++ b/tools/matinfo/src/main.cpp @@ -422,7 +422,8 @@ 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, config.serverPort); + DebugServer server(Backend::DEFAULT, filament::backend::ShaderLanguage::ESSL3, + config.serverPort); if (!server.isReady()) { return false; } From 67710723d7f4de6b74f8ed5c7a3a959e126204cc Mon Sep 17 00:00:00 2001 From: Eliza Velasquez Date: Thu, 30 Jan 2025 11:42:02 -0800 Subject: [PATCH 03/24] c-filament-style.el: fix init list indent --- ide/emacs/c-filament-style.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ide/emacs/c-filament-style.el b/ide/emacs/c-filament-style.el index 6b25e52e1b..e9f58c2d8e 100644 --- a/ide/emacs/c-filament-style.el +++ b/ide/emacs/c-filament-style.el @@ -72,7 +72,8 @@ nil if there is none)." (brace-list-intro . c-filament-style-lineup-brace-list-intro) (brace-list-entry . c-filament-style-lineup-brace-list-entry) (brace-list-close . c-filament-style-lineup-brace-list-entry) - (label . [0])))) + (label . [0]) + (member-init-intro . ++)))) (provide 'c-filament-style) From 9a2ca8ddbb69c15e90148e0b4dde6fef0fcec1ed Mon Sep 17 00:00:00 2001 From: Ben Doherty Date: Fri, 31 Jan 2025 13:31:07 -0800 Subject: [PATCH 04/24] Metal: add config to abandon frame if drawable cannot be acquired (#8397) --- filament/backend/CMakeLists.txt | 2 +- .../backend/platforms/PlatformMetal.h} | 36 +++++++++++++--- filament/backend/src/metal/MetalBuffer.h | 10 ++--- filament/backend/src/metal/MetalBuffer.mm | 4 +- filament/backend/src/metal/MetalContext.h | 2 + filament/backend/src/metal/MetalDriver.h | 8 ++-- filament/backend/src/metal/MetalDriver.mm | 38 +++++++++++++--- .../backend/src/metal/MetalDriverFactory.h | 4 +- filament/backend/src/metal/MetalHandles.h | 17 ++++++-- filament/backend/src/metal/MetalHandles.mm | 39 +++++++++++++++-- .../{MetalPlatform.mm => PlatformMetal.mm} | 43 ++++++++++++++----- 11 files changed, 157 insertions(+), 46 deletions(-) rename filament/backend/{src/metal/MetalPlatform.h => include/backend/platforms/PlatformMetal.h} (63%) rename filament/backend/src/metal/{MetalPlatform.mm => PlatformMetal.mm} (59%) diff --git a/filament/backend/CMakeLists.txt b/filament/backend/CMakeLists.txt index 89c29cf53e..208aec0ee0 100644 --- a/filament/backend/CMakeLists.txt +++ b/filament/backend/CMakeLists.txt @@ -139,11 +139,11 @@ if (FILAMENT_SUPPORTS_METAL) src/metal/MetalEnums.mm src/metal/MetalExternalImage.mm src/metal/MetalHandles.mm - src/metal/MetalPlatform.mm src/metal/MetalShaderCompiler.mm src/metal/MetalState.mm src/metal/MetalTimerQuery.mm src/metal/MetalUtils.mm + src/metal/PlatformMetal.mm ) set(METAL_CPP_SRCS diff --git a/filament/backend/src/metal/MetalPlatform.h b/filament/backend/include/backend/platforms/PlatformMetal.h similarity index 63% rename from filament/backend/src/metal/MetalPlatform.h rename to filament/backend/include/backend/platforms/PlatformMetal.h index 82730ff6bb..b308935bb9 100644 --- a/filament/backend/src/metal/MetalPlatform.h +++ b/filament/backend/include/backend/platforms/PlatformMetal.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef TNT_FILAMENT_BACKEND_PRIVATE_METALPLATFORM_H -#define TNT_FILAMENT_BACKEND_PRIVATE_METALPLATFORM_H +#ifndef TNT_FILAMENT_BACKEND_PRIVATE_PLATFORMMETAL_H +#define TNT_FILAMENT_BACKEND_PRIVATE_PLATFORMMETAL_H #include #include @@ -24,9 +24,12 @@ namespace filament::backend { -class MetalPlatform final : public Platform { +struct PlatformMetalImpl; + +class PlatformMetal final : public Platform { public: - ~MetalPlatform() override; + PlatformMetal(); + ~PlatformMetal() noexcept override; Driver* createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept override; int getOSVersion() const noexcept override { return 0; } @@ -54,11 +57,30 @@ public: */ id createAndEnqueueCommandBuffer() noexcept; -private: - id mCommandQueue = nil; + /** + * The action to take if a Drawable cannot be acquired. + * + * Each frame rendered requires a CAMetalDrawable texture, which is presented on-screen at the + * completion of each frame. These are limited and provided round-robin style by the system. + */ + enum class DrawableFailureBehavior : uint8_t { + /** + * Terminates the application and reports an error message (default). + */ + PANIC, + /* + * Aborts execution of the current frame. The Metal backend will attempt to acquire a new + * drawable at the next frame. + */ + ABORT_FRAME + }; + void setDrawableFailureBehavior(DrawableFailureBehavior behavior) noexcept; + DrawableFailureBehavior getDrawableFailureBehavior() const noexcept; +private: + PlatformMetalImpl* pImpl = nullptr; }; } // namespace filament::backend -#endif // TNT_FILAMENT_BACKEND_PRIVATE_METALPLATFORM_H +#endif // TNT_FILAMENT_BACKEND_PRIVATE_PLATFORMMETAL_H diff --git a/filament/backend/src/metal/MetalBuffer.h b/filament/backend/src/metal/MetalBuffer.h index ec724a9f0b..b40e6714cd 100644 --- a/filament/backend/src/metal/MetalBuffer.h +++ b/filament/backend/src/metal/MetalBuffer.h @@ -18,9 +18,9 @@ #define TNT_FILAMENT_DRIVER_METALBUFFER_H #include "MetalContext.h" -#include "MetalPlatform.h" #include +#include #include @@ -54,12 +54,12 @@ public: } } - static void setPlatform(MetalPlatform* p) { platform = p; } + static void setPlatform(PlatformMetal* p) { platform = p; } private: typedef std::chrono::steady_clock clock_t; - static MetalPlatform* platform; + static PlatformMetal* platform; std::chrono::time_point mBeginning; const char* mName; @@ -141,7 +141,7 @@ public: assert_invariant(type != Type::NONE); return aliveBuffers[toIndex(type)]; } - static void setPlatform(MetalPlatform* p) { platform = p; } + static void setPlatform(PlatformMetal* p) { platform = p; } private: void swap(TrackedMetalBuffer& other) noexcept { @@ -152,7 +152,7 @@ private: id mBuffer; Type mType = Type::NONE; - static MetalPlatform* platform; + static PlatformMetal* platform; static std::array aliveBuffers; }; diff --git a/filament/backend/src/metal/MetalBuffer.mm b/filament/backend/src/metal/MetalBuffer.mm index 6347ab70c6..13675f2706 100644 --- a/filament/backend/src/metal/MetalBuffer.mm +++ b/filament/backend/src/metal/MetalBuffer.mm @@ -23,8 +23,8 @@ namespace filament { namespace backend { std::array TrackedMetalBuffer::aliveBuffers = { 0 }; -MetalPlatform* TrackedMetalBuffer::platform = nullptr; -MetalPlatform* ScopedAllocationTimer::platform = nullptr; +PlatformMetal* TrackedMetalBuffer::platform = nullptr; +PlatformMetal* ScopedAllocationTimer::platform = nullptr; MetalBuffer::MetalBuffer(MetalContext& context, BufferObjectBinding bindingType, BufferUsage usage, size_t size, bool forceGpuBuffer) diff --git a/filament/backend/src/metal/MetalContext.h b/filament/backend/src/metal/MetalContext.h index f85e08545b..7535acd5e7 100644 --- a/filament/backend/src/metal/MetalContext.h +++ b/filament/backend/src/metal/MetalContext.h @@ -128,6 +128,7 @@ struct MetalContext { std::atomic latestCompletedCommandBufferId = 0; id pendingCommandBuffer = nil; id currentRenderPassEncoder = nil; + uint32_t currentFrame = 0; std::atomic memorylessLimitsReached = false; @@ -156,6 +157,7 @@ struct MetalContext { RenderPassFlags currentRenderPassFlags; MetalRenderTarget* currentRenderTarget = nullptr; bool validPipelineBound = false; + bool currentRenderPassAbandoned = false; // State trackers. PipelineStateTracker pipelineState; diff --git a/filament/backend/src/metal/MetalDriver.h b/filament/backend/src/metal/MetalDriver.h index 562bafb4aa..7bea1119bf 100644 --- a/filament/backend/src/metal/MetalDriver.h +++ b/filament/backend/src/metal/MetalDriver.h @@ -37,7 +37,7 @@ namespace filament { namespace backend { -class MetalPlatform; +class PlatformMetal; class MetalBuffer; class MetalProgram; @@ -51,19 +51,19 @@ struct BufferState; #endif class MetalDriver final : public DriverBase { - explicit MetalDriver(MetalPlatform* platform, const Platform::DriverConfig& driverConfig) noexcept; + explicit MetalDriver(PlatformMetal* platform, const Platform::DriverConfig& driverConfig) noexcept; ~MetalDriver() noexcept override; Dispatcher getDispatcher() const noexcept final; public: - static Driver* create(MetalPlatform* platform, const Platform::DriverConfig& driverConfig); + static Driver* create(PlatformMetal* platform, const Platform::DriverConfig& driverConfig); private: friend class MetalSwapChain; friend struct MetalDescriptorSet; - MetalPlatform& mPlatform; + PlatformMetal& mPlatform; MetalContext* mContext; ShaderModel getShaderModel() const noexcept final; diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index e5b5dc6131..5e14c55b52 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -30,7 +30,7 @@ #include "MetalState.h" #include "MetalTimerQuery.h" -#include "MetalPlatform.h" +#include #include #include @@ -57,7 +57,7 @@ namespace filament { namespace backend { -Driver* MetalDriverFactory::create(MetalPlatform* const platform, const Platform::DriverConfig& driverConfig) { +Driver* MetalDriverFactory::create(PlatformMetal* const platform, const Platform::DriverConfig& driverConfig) { #if 0 // this is useful for development, but too verbose even for debug builds // For reference on a 64-bits machine in Release mode: @@ -96,7 +96,7 @@ Driver* MetalDriverFactory::create(MetalPlatform* const platform, const Platform } UTILS_NOINLINE -Driver* MetalDriver::create(MetalPlatform* const platform, const Platform::DriverConfig& driverConfig) { +Driver* MetalDriver::create(PlatformMetal* const platform, const Platform::DriverConfig& driverConfig) { assert_invariant(platform); size_t defaultSize = FILAMENT_METAL_HANDLE_ARENA_SIZE_IN_MB * 1024U * 1024U; Platform::DriverConfig validConfig {driverConfig}; @@ -109,7 +109,7 @@ Dispatcher MetalDriver::getDispatcher() const noexcept { } MetalDriver::MetalDriver( - MetalPlatform* platform, const Platform::DriverConfig& driverConfig) noexcept + PlatformMetal* platform, const Platform::DriverConfig& driverConfig) noexcept : mPlatform(*platform), mContext(new MetalContext), mHandleAllocator( @@ -246,6 +246,7 @@ void MetalDriver::tick(int) { void MetalDriver::beginFrame(int64_t monotonic_clock_ns, int64_t refreshIntervalNs, uint32_t frameId) { + mContext->currentFrame = frameId; DEBUG_LOG("beginFrame(monotonic_clock_ns = %lld, refreshIntervalNs = %lld, frameId = %d)\n", monotonic_clock_ns, refreshIntervalNs, frameId); #if defined(FILAMENT_METAL_PROFILING) @@ -631,19 +632,19 @@ void MetalDriver::createFenceR(Handle fh, int dummy) { void MetalDriver::createSwapChainR(Handle sch, void* nativeWindow, uint64_t flags) { if (UTILS_UNLIKELY(flags & SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER)) { CVPixelBufferRef pixelBuffer = (CVPixelBufferRef) nativeWindow; - construct_handle(sch, *mContext, pixelBuffer, flags); + construct_handle(sch, *mContext, mPlatform, pixelBuffer, flags); // This release matches the retain call in setupExternalImage. The MetalSwapchain will have // retained the buffer by now. CVPixelBufferRelease((CVPixelBufferRef)pixelBuffer); } else { auto* metalLayer = (__bridge CAMetalLayer*) nativeWindow; - construct_handle(sch, *mContext, metalLayer, flags); + construct_handle(sch, *mContext, mPlatform, metalLayer, flags); } } void MetalDriver::createSwapChainHeadlessR(Handle sch, uint32_t width, uint32_t height, uint64_t flags) { - construct_handle(sch, *mContext, width, height, flags); + construct_handle(sch, *mContext, mPlatform, width, height, flags); } void MetalDriver::createTimerQueryR(Handle tqh, int) { @@ -1272,6 +1273,13 @@ void MetalDriver::beginRenderPass(Handle rth, MTLRenderPassDescriptor* descriptor = [MTLRenderPassDescriptor renderPassDescriptor]; renderTarget->setUpRenderPassAttachments(descriptor, params); + if (renderTarget->involvesAbandonedSwapChain()) { + mContext->currentRenderPassAbandoned = true; + return; + } else { + mContext->currentRenderPassAbandoned = false; + } + mContext->currentRenderPassEncoder = [getPendingCommandBuffer(mContext) renderCommandEncoderWithDescriptor:descriptor]; if (!mContext->groupMarkers.empty()) { @@ -1333,6 +1341,10 @@ void MetalDriver::endRenderPass(int dummy) { os_signpost_interval_end(mContext->log, OS_SIGNPOST_ID_EXCLUSIVE, "Render pass"); #endif + if (UTILS_UNLIKELY(mContext->currentRenderPassAbandoned)) { + return; + } + [mContext->currentRenderPassEncoder endEncoding]; // Command encoders are one time use. Set it to nil to release the encoder and ensure we don't @@ -1633,6 +1645,11 @@ void MetalDriver::blitDEPRECATED(TargetBufferFlags buffers, auto srcTarget = handle_cast(src); auto dstTarget = handle_cast(dst); + if (UTILS_UNLIKELY(srcTarget->involvesAbandonedSwapChain() || + dstTarget->involvesAbandonedSwapChain())) { + return; + } + FILAMENT_CHECK_PRECONDITION(buffers == TargetBufferFlags::COLOR0) << "blitDEPRECATED only supports COLOR0"; @@ -1917,6 +1934,10 @@ void MetalDriver::bindDescriptorSet( } void MetalDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) { + if (UTILS_UNLIKELY(mContext->currentRenderPassAbandoned)) { + return; + } + FILAMENT_CHECK_PRECONDITION(mContext->currentRenderPassEncoder != nullptr) << "draw() without a valid command encoder."; DEBUG_LOG("draw2(...)\n"); @@ -1960,6 +1981,9 @@ void MetalDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t inst void MetalDriver::draw(PipelineState ps, Handle rph, uint32_t const indexOffset, uint32_t const indexCount, uint32_t const instanceCount) { + if (UTILS_UNLIKELY(mContext->currentRenderPassAbandoned)) { + return; + } MetalRenderPrimitive const* const rp = handle_cast(rph); ps.primitiveType = rp->type; ps.vertexBufferInfo = rp->vertexBuffer->vbih; diff --git a/filament/backend/src/metal/MetalDriverFactory.h b/filament/backend/src/metal/MetalDriverFactory.h index bff7439077..083a592e37 100644 --- a/filament/backend/src/metal/MetalDriverFactory.h +++ b/filament/backend/src/metal/MetalDriverFactory.h @@ -21,12 +21,12 @@ namespace filament { namespace backend { -class MetalPlatform; +class PlatformMetal; class Driver; class MetalDriverFactory { public: - static Driver* create(MetalPlatform* platform, const Platform::DriverConfig& driverConfig); + static Driver* create(PlatformMetal* platform, const Platform::DriverConfig& driverConfig); }; } // namespace backend diff --git a/filament/backend/src/metal/MetalHandles.h b/filament/backend/src/metal/MetalHandles.h index 973e5d19eb..cc17d950d8 100644 --- a/filament/backend/src/metal/MetalHandles.h +++ b/filament/backend/src/metal/MetalHandles.h @@ -30,6 +30,7 @@ #include "MetalState.h" // for MetalState::VertexDescription #include +#include #include #include @@ -51,13 +52,16 @@ class MetalSwapChain : public HwSwapChain { public: // Instantiate a SwapChain from a CAMetalLayer - MetalSwapChain(MetalContext& context, CAMetalLayer* nativeWindow, uint64_t flags); + MetalSwapChain(MetalContext& context, PlatformMetal& platform, CAMetalLayer* nativeWindow, + uint64_t flags); // Instantiate a SwapChain from a CVPixelBuffer - MetalSwapChain(MetalContext& context, CVPixelBufferRef pixelBuffer, uint64_t flags); + MetalSwapChain(MetalContext& context, PlatformMetal& platform, CVPixelBufferRef pixelBuffer, + uint64_t flags); // Instantiate a headless SwapChain. - MetalSwapChain(MetalContext& context, int32_t width, int32_t height, uint64_t flags); + MetalSwapChain(MetalContext& context, PlatformMetal& platform, int32_t width, int32_t height, + uint64_t flags); ~MetalSwapChain(); @@ -86,6 +90,8 @@ public: bool isPixelBuffer() const { return type == SwapChainType::CVPIXELBUFFERREF; } + bool isAbandoned() const; + private: enum class SwapChainType { @@ -103,6 +109,7 @@ private: void ensureDepthStencilTexture(); MetalContext& context; + PlatformMetal& platform; id drawable = nil; id depthStencilTexture = nil; id headlessDrawable = nil; @@ -114,6 +121,8 @@ private: MetalExternalImage externalImage; SwapChainType type; + int64_t abandonedUntilFrame = -1; + // These fields store a callback to notify the client that a frame is ready for presentation. If // !frameScheduled.callback, then the Metal backend automatically calls presentDrawable when the // frame is committed. Otherwise, the Metal backend will not automatically present the frame. @@ -341,6 +350,8 @@ public: void setUpRenderPassAttachments(MTLRenderPassDescriptor* descriptor, const RenderPassParams& params); + bool involvesAbandonedSwapChain() const noexcept; + MTLViewport getViewportFromClientViewport( Viewport rect, float depthRangeNear, float depthRangeFar) { const int32_t height = int32_t(getAttachmentSize().y); diff --git a/filament/backend/src/metal/MetalHandles.mm b/filament/backend/src/metal/MetalHandles.mm index fc12fe0a9a..da10317f51 100644 --- a/filament/backend/src/metal/MetalHandles.mm +++ b/filament/backend/src/metal/MetalHandles.mm @@ -69,8 +69,10 @@ static inline MTLTextureUsage getMetalTextureUsage(TextureUsage usage) { return MTLTextureUsage(u); } -MetalSwapChain::MetalSwapChain(MetalContext& context, CAMetalLayer* nativeWindow, uint64_t flags) +MetalSwapChain::MetalSwapChain( + MetalContext& context, PlatformMetal& platform, CAMetalLayer* nativeWindow, uint64_t flags) : context(context), + platform(platform), depthStencilFormat(decideDepthStencilFormat(flags)), layer(nativeWindow), layerDrawableMutex(std::make_shared()), @@ -94,15 +96,19 @@ MetalSwapChain::MetalSwapChain(MetalContext& context, CAMetalLayer* nativeWindow layer.device = context.device; } -MetalSwapChain::MetalSwapChain(MetalContext& context, int32_t width, int32_t height, uint64_t flags) +MetalSwapChain::MetalSwapChain(MetalContext& context, PlatformMetal& platform, int32_t width, + int32_t height, uint64_t flags) : context(context), + platform(platform), depthStencilFormat(decideDepthStencilFormat(flags)), headlessWidth(width), headlessHeight(height), type(SwapChainType::HEADLESS) {} -MetalSwapChain::MetalSwapChain(MetalContext& context, CVPixelBufferRef pixelBuffer, uint64_t flags) +MetalSwapChain::MetalSwapChain(MetalContext& context, PlatformMetal& platform, + CVPixelBufferRef pixelBuffer, uint64_t flags) : context(context), + platform(platform), depthStencilFormat(decideDepthStencilFormat(flags)), externalImage(MetalExternalImage::createFromImage(context, pixelBuffer)), type(SwapChainType::CVPIXELBUFFERREF) { @@ -140,6 +146,10 @@ NSUInteger MetalSwapChain::getSurfaceHeight() const { return (NSUInteger) layer.drawableSize.height; } +bool MetalSwapChain::isAbandoned() const { + return context.currentFrame < abandonedUntilFrame; +} + id MetalSwapChain::acquireDrawable() { if (drawable) { return drawable.texture; @@ -180,7 +190,18 @@ id MetalSwapChain::acquireDrawable() { drawable = [layer nextDrawable]; } - FILAMENT_CHECK_POSTCONDITION(drawable != nil) << "Could not obtain drawable."; + if (UTILS_UNLIKELY(drawable == nil)) { + switch (platform.getDrawableFailureBehavior()) { + case PlatformMetal::DrawableFailureBehavior::PANIC: + FILAMENT_CHECK_POSTCONDITION(drawable != nil) << "Could not obtain drawable."; + break; + + case PlatformMetal::DrawableFailureBehavior::ABORT_FRAME: + abandonedUntilFrame = context.currentFrame + 1; + return nil; + } + } + return drawable.texture; } @@ -1117,12 +1138,20 @@ void MetalRenderTarget::setUpRenderPassAttachments(MTLRenderPassDescriptor* desc } } +bool MetalRenderTarget::involvesAbandonedSwapChain() const noexcept { + const auto* draw = context->currentDrawSwapChain; + const auto* read = context->currentReadSwapChain; + return (draw && draw->isAbandoned()) || (read && read->isAbandoned()); +} + MetalRenderTarget::Attachment MetalRenderTarget::getDrawColorAttachment(size_t index) { assert_invariant(index < MRT::MAX_SUPPORTED_RENDER_TARGET_COUNT); Attachment result = color[index]; if (index == 0 && defaultRenderTarget) { assert_invariant(context->currentDrawSwapChain); result.texture = context->currentDrawSwapChain->acquireDrawable(); + // acquireDrawable may fail to acquire the drawable, in which case result.texture will be + // nil, and an invalid attachment } return result; } @@ -1133,6 +1162,8 @@ MetalRenderTarget::Attachment MetalRenderTarget::getReadColorAttachment(size_t i if (index == 0 && defaultRenderTarget) { assert_invariant(context->currentReadSwapChain); result.texture = context->currentReadSwapChain->acquireDrawable(); + // acquireDrawable may fail to acquire the drawable, in which case result.texture will be + // nil, and an invalid attachment } return result; } diff --git a/filament/backend/src/metal/MetalPlatform.mm b/filament/backend/src/metal/PlatformMetal.mm similarity index 59% rename from filament/backend/src/metal/MetalPlatform.mm rename to filament/backend/src/metal/PlatformMetal.mm index 4979e602ba..e446698b08 100644 --- a/filament/backend/src/metal/MetalPlatform.mm +++ b/filament/backend/src/metal/PlatformMetal.mm @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "MetalPlatform.h" +#include #include "MetalDriverFactory.h" @@ -22,19 +22,32 @@ #import +#include + namespace filament::backend { +struct PlatformMetalImpl { + id mCommandQueue = nil; + // read form driver thread, read/written to from client thread + std::atomic mDrawableFailureBehavior = + PlatformMetal::DrawableFailureBehavior::PANIC; +}; + Platform* createDefaultMetalPlatform() { - return new MetalPlatform(); + return new PlatformMetal(); } -MetalPlatform::~MetalPlatform() = default; +PlatformMetal::PlatformMetal() : pImpl(new PlatformMetalImpl) {} -Driver* MetalPlatform::createDriver(void* /*sharedContext*/, const Platform::DriverConfig& driverConfig) noexcept { +PlatformMetal::~PlatformMetal() noexcept { + delete pImpl; +} + +Driver* PlatformMetal::createDriver(void* /*sharedContext*/, const Platform::DriverConfig& driverConfig) noexcept { return MetalDriverFactory::create(this, driverConfig); } -id MetalPlatform::createDevice() noexcept { +id PlatformMetal::createDevice() noexcept { id result; #if !defined(FILAMENT_IOS) @@ -62,16 +75,24 @@ id MetalPlatform::createDevice() noexcept { return result; } -id MetalPlatform::createCommandQueue(id device) noexcept { - mCommandQueue = [device newCommandQueue]; - mCommandQueue.label = @"Filament"; - return mCommandQueue; +id PlatformMetal::createCommandQueue(id device) noexcept { + pImpl->mCommandQueue = [device newCommandQueue]; + pImpl->mCommandQueue.label = @"Filament"; + return pImpl->mCommandQueue; } -id MetalPlatform::createAndEnqueueCommandBuffer() noexcept { - id commandBuffer = [mCommandQueue commandBuffer]; +id PlatformMetal::createAndEnqueueCommandBuffer() noexcept { + id commandBuffer = [pImpl->mCommandQueue commandBuffer]; [commandBuffer enqueue]; return commandBuffer; } +void PlatformMetal::setDrawableFailureBehavior(DrawableFailureBehavior behavior) noexcept { + pImpl->mDrawableFailureBehavior = behavior; +} + +PlatformMetal::DrawableFailureBehavior PlatformMetal::getDrawableFailureBehavior() const noexcept { + return pImpl->mDrawableFailureBehavior; +} + } // namespace filament From 793f2b4eb78391e8c9629ffa3dabc37e85070e66 Mon Sep 17 00:00:00 2001 From: Doris Wu Date: Sat, 1 Feb 2025 07:39:47 +0800 Subject: [PATCH 05/24] [Depends on #8332] Integrate `fgviewer` to the engine side (#8344) * Introduce FrameGraphInfo class * Move the assignment into pimpl * Make ctors explicit * Add ctors to fg info structs * Revert the macro change to align with existing * Address the comments * Remove pimpl and move func def to .cc * Fix * Convert the FrameGraph to FrameGraphInfo * Initialize and update debug server on engine side * Fix compile error * Address the comments * Update * Use camelCase * Use camelCase * Update --- filament/src/details/Engine.cpp | 19 +++++++ filament/src/details/Engine.h | 9 ++++ filament/src/details/Renderer.cpp | 7 +++ filament/src/details/View.cpp | 15 ++++++ filament/src/details/View.h | 14 +++++ filament/src/fg/FrameGraph.cpp | 55 ++++++++++++++++++++ filament/src/fg/FrameGraph.h | 14 +++++ libs/fgviewer/include/fgviewer/DebugServer.h | 2 - 8 files changed, 133 insertions(+), 2 deletions(-) diff --git a/filament/src/details/Engine.cpp b/filament/src/details/Engine.cpp index 732a3965a6..3982f9235c 100644 --- a/filament/src/details/Engine.cpp +++ b/filament/src/details/Engine.cpp @@ -749,6 +749,25 @@ int FEngine::loop() { } #endif +#if FILAMENT_ENABLE_FGVIEWER +#ifdef __ANDROID__ + const char* fgviewerPortString = "8085"; +#else + const char* fgviewerPortString = getenv("FILAMENT_FGVIEWER_PORT"); +#endif + if (fgviewerPortString != nullptr) { + const int fgviewerPort = atoi(fgviewerPortString); + debug.fgviewerServer = new fgviewer::DebugServer(fgviewerPort); + + // 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. + if (!debug.fgviewerServer->isReady()) { + delete debug.fgviewerServer; + debug.fgviewerServer = nullptr; + } + } +#endif + while (true) { if (!execute()) { break; diff --git a/filament/src/details/Engine.h b/filament/src/details/Engine.h index 7809e85c08..e2b7058625 100644 --- a/filament/src/details/Engine.h +++ b/filament/src/details/Engine.h @@ -88,6 +88,14 @@ using MaterialKey = uint32_t; } // namespace filament::matdbg #endif +#if FILAMENT_ENABLE_FGVIEWER +#include +#else +namespace filament::fgviewer { + class DebugServer; +} // namespace filament::fgviewer +#endif + namespace filament { class Renderer; @@ -673,6 +681,7 @@ public: bool combine_multiview_images = false; } stereo; matdbg::DebugServer* server = nullptr; + fgviewer::DebugServer* fgviewerServer = nullptr; } debug; struct { diff --git a/filament/src/details/Renderer.cpp b/filament/src/details/Renderer.cpp index 3abcfced58..777aecab24 100644 --- a/filament/src/details/Renderer.cpp +++ b/filament/src/details/Renderer.cpp @@ -1440,6 +1440,13 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { fg.compile(); +#if FILAMENT_ENABLE_FGVIEWER + fgviewer::DebugServer* fgviewerServer = engine.debug.fgviewerServer; + if (UTILS_LIKELY(fgviewerServer)) { + fgviewerServer->update(view.getViewHandle(), fg.getFrameGraphInfo(view.getName())); + } +#endif + //fg.export_graphviz(slog.d, view.getName()); fg.execute(driver); diff --git a/filament/src/details/View.cpp b/filament/src/details/View.cpp index 3022f4be59..4aa9b67532 100644 --- a/filament/src/details/View.cpp +++ b/filament/src/details/View.cpp @@ -109,6 +109,14 @@ FView::FView(FEngine& engine) } #endif +#if FILAMENT_ENABLE_FGVIEWER + fgviewer::DebugServer* fgviewerServer = engine.debug.fgviewerServer; + if (UTILS_LIKELY(fgviewerServer)) { + mFrameGraphViewerViewHandle = + fgviewerServer->createView(utils::CString(getName())); + } +#endif + // allocate UBOs mLightUbh = driver.createBufferObject(CONFIG_MAX_LIGHT_COUNT * sizeof(LightsUib), BufferObjectBinding::UNIFORM, BufferUsage::DYNAMIC); @@ -153,6 +161,13 @@ void FView::terminate(FEngine& engine) { engine.getDebugRegistry().unregisterDataSource("d.view.frame_info"); } #endif + +#if FILAMENT_ENABLE_FGVIEWER + fgviewer::DebugServer* fgviewerServer = engine.debug.fgviewerServer; + if (UTILS_LIKELY(fgviewerServer)) { + fgviewerServer->destroyView(mFrameGraphViewerViewHandle); + } +#endif } void FView::setViewport(filament::Viewport const& viewport) noexcept { diff --git a/filament/src/details/View.h b/filament/src/details/View.h index 34c49e40d5..054aa8e11c 100644 --- a/filament/src/details/View.h +++ b/filament/src/details/View.h @@ -60,6 +60,14 @@ #include #include +#if FILAMENT_ENABLE_FGVIEWER +#include +#else +namespace filament::fgviewer { + using ViewHandle = uint32_t; +} +#endif + #include #include @@ -467,6 +475,10 @@ public: return mUniforms; } + fgviewer::ViewHandle getViewHandle() const noexcept { + return mFrameGraphViewerViewHandle; + } + private: struct FPickingQuery : public PickingQuery { private: @@ -600,6 +612,8 @@ private: { 0, 0, 0, 1 }, }}; + fgviewer::ViewHandle mFrameGraphViewerViewHandle; + #ifndef NDEBUG struct DebugState { std::unique_ptr> debugFrameHistory{}; diff --git a/filament/src/fg/FrameGraph.cpp b/filament/src/fg/FrameGraph.cpp index 6ccd895766..55a0cd044c 100644 --- a/filament/src/fg/FrameGraph.cpp +++ b/filament/src/fg/FrameGraph.cpp @@ -479,6 +479,61 @@ void FrameGraph::export_graphviz(utils::io::ostream& out, char const* name) { mGraph.export_graphviz(out, name); } +fgviewer::FrameGraphInfo FrameGraph::getFrameGraphInfo(const char *viewName) const { +#if FILAMENT_ENABLE_FGVIEWER + fgviewer::FrameGraphInfo info{utils::CString(viewName)}; + std::vector passes; + + auto first = mPassNodes.begin(); + const auto activePassNodesEnd = mActivePassNodesEnd; + while (first != activePassNodesEnd) { + PassNode *const pass = *first; + first++; + + assert_invariant(!pass->isCulled()); + std::vector reads; + auto const &readEdges = mGraph.getIncomingEdges(pass); + for (auto const &edge: readEdges) { + // all incoming edges should be valid by construction + assert_invariant(mGraph.isEdgeValid(edge)); + reads.push_back(edge->from); + } + + std::vector writes; + auto const &writeEdges = mGraph.getOutgoingEdges(pass); + for (auto const &edge: writeEdges) { + // It is possible that the node we're writing to has been culled. + // In this case we'd like to ignore the edge. + if (!mGraph.isEdgeValid(edge)) { + continue; + } + writes.push_back(edge->to); + } + passes.emplace_back(utils::CString(pass->getName()), + std::move(reads), std::move(writes)); + } + + std::unordered_map resources; + for (const auto &resource: mResourceNodes) { + std::vector resourceProps; + // TODO: Fill in resource properties + fgviewer::ResourceId id = resource->getId(); + resources.emplace(id, fgviewer::FrameGraphInfo::Resource( + id, utils::CString(resource->getName()), + std::move(resourceProps)) + ); + } + + info.setResources(std::move(resources)); + info.setPasses(std::move(passes)); + + return info; +#else + return fgviewer::FrameGraphInfo(); +#endif +} + + // ------------------------------------------------------------------------------------------------ /* diff --git a/filament/src/fg/FrameGraph.h b/filament/src/fg/FrameGraph.h index 2311e68967..954e13b79c 100644 --- a/filament/src/fg/FrameGraph.h +++ b/filament/src/fg/FrameGraph.h @@ -36,6 +36,14 @@ #include +#if FILAMENT_ENABLE_FGVIEWER +#include +#else +namespace filament::fgviewer { + class FrameGraphInfo{}; +} // namespace filament::fgviewer +#endif + namespace filament { class ResourceAllocatorInterface; @@ -434,6 +442,12 @@ public: //! export a graphviz view of the graph void export_graphviz(utils::io::ostream& out, const char* name = nullptr); + /** + * Export a fgviewer::FrameGraphInfo for current graph. + * Note that this function should be called after FrameGraph::compile(). + */ + fgviewer::FrameGraphInfo getFrameGraphInfo(const char *viewName) const; + private: friend class FrameGraphResources; friend class PassNode; diff --git a/libs/fgviewer/include/fgviewer/DebugServer.h b/libs/fgviewer/include/fgviewer/DebugServer.h index d56addf909..7a169d4e5d 100644 --- a/libs/fgviewer/include/fgviewer/DebugServer.h +++ b/libs/fgviewer/include/fgviewer/DebugServer.h @@ -31,8 +31,6 @@ namespace filament::fgviewer { using ViewHandle = uint32_t; - - /** * Server-side frame graph debugger. * From 62cd8f1d35fa82beb6e4ed6d6892a53525f8f4c6 Mon Sep 17 00:00:00 2001 From: Rafael Dominguez Date: Thu, 30 Jan 2025 08:24:48 -0800 Subject: [PATCH 06/24] Update multiview shader code generator for Vulkan When targeting Vulkan with multiview, the shader code generator was using the OpenGL extension and built-in variables, which are not supported on Vulkan. Changed it to use GL_EXT_multiview instead of GL_OVR_multiview2 when the target API is Vulkan. --- libs/filamat/src/shaders/CodeGenerator.cpp | 16 +++++++++++++--- shaders/src/common_getters.glsl | 6 ++++++ shaders/src/surface_getters.vs | 6 ++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/libs/filamat/src/shaders/CodeGenerator.cpp b/libs/filamat/src/shaders/CodeGenerator.cpp index 07e370cc47..4b41e7974d 100644 --- a/libs/filamat/src/shaders/CodeGenerator.cpp +++ b/libs/filamat/src/shaders/CodeGenerator.cpp @@ -78,7 +78,11 @@ utils::io::sstream& CodeGenerator::generateCommonProlog(utils::io::sstream& out, out << "#endif\n\n"; break; case StereoscopicType::MULTIVIEW: - out << "#extension GL_OVR_multiview2 : require\n"; + if (mTargetApi == TargetApi::VULKAN) { + out << "#extension GL_EXT_multiview : enable\n"; + } else { + out << "#extension GL_OVR_multiview2 : require\n"; + } break; case StereoscopicType::NONE: break; @@ -101,7 +105,11 @@ utils::io::sstream& CodeGenerator::generateCommonProlog(utils::io::sstream& out, // Nothing to generate break; case StereoscopicType::MULTIVIEW: - out << "#extension GL_OVR_multiview2 : require\n"; + if (mTargetApi == TargetApi::VULKAN) { + out << "#extension GL_EXT_multiview : enable\n"; + } else { + out << "#extension GL_OVR_multiview2 : require\n"; + } break; case StereoscopicType::NONE: break; @@ -124,7 +132,9 @@ utils::io::sstream& CodeGenerator::generateCommonProlog(utils::io::sstream& out, // Nothing to generate break; case StereoscopicType::MULTIVIEW: - out << "layout(num_views = " << material.stereoscopicEyeCount << ") in;\n"; + if (mTargetApi != TargetApi::VULKAN) { + out << "layout(num_views = " << material.stereoscopicEyeCount << ") in;\n"; + } break; case StereoscopicType::NONE: break; diff --git a/shaders/src/common_getters.glsl b/shaders/src/common_getters.glsl index 23a365549a..95ea0799f2 100644 --- a/shaders/src/common_getters.glsl +++ b/shaders/src/common_getters.glsl @@ -28,7 +28,13 @@ highp mat4 getClipFromWorldMatrix() { int eye = instance_index % CONFIG_STEREO_EYE_COUNT; return frameUniforms.clipFromWorldMatrix[eye]; #elif defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_MULTIVIEW) + +#if defined(TARGET_VULKAN_ENVIRONMENT) + return frameUniforms.clipFromWorldMatrix[gl_ViewIndex]; +#else return frameUniforms.clipFromWorldMatrix[gl_ViewID_OVR]; +#endif // TARGET_VULKAN_ENVIRONMENT + #else return frameUniforms.clipFromWorldMatrix[0]; #endif diff --git a/shaders/src/surface_getters.vs b/shaders/src/surface_getters.vs index 09569c6155..a9b8c293ac 100644 --- a/shaders/src/surface_getters.vs +++ b/shaders/src/surface_getters.vs @@ -284,8 +284,14 @@ int getEyeIndex() { #if defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_INSTANCED) return instance_index % CONFIG_STEREO_EYE_COUNT; #elif defined(VARIANT_HAS_STEREO) && defined(FILAMENT_STEREO_MULTIVIEW) + +#if defined(TARGET_VULKAN_ENVIRONMENT) + return int(gl_ViewIndex); +#else // gl_ViewID_OVR is of uint type, which needs an explicit conversion. return int(gl_ViewID_OVR); +#endif // TARGET_VULKAN_ENVIRONMENT + #endif return 0; } From b780cb36d0a392ee9d19e978400e7ca6e5fe72f2 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Wed, 22 Jan 2025 22:09:13 -0800 Subject: [PATCH 07/24] attempt to fix crashers when initializing the JVM - clarify precondition for VirtualMachineEnv, in particular, JNI_OnLoad() must be called from a thread attached to the VM, and should be called once. This is now enforced internally, subsequent calls are ignored. - sVirtualMachine was written and read from potentially different threads without synchronization. It is now mutex protected. - added fatal asserts in all locations that we cannot recover from; previously we would stay in an undefined state. BUGS=[390724273] --- .../private/backend/VirtualMachineEnv.h | 42 +++----- filament/backend/src/VirtualMachineEnv.cpp | 97 ++++++++++++++++--- .../ExternalStreamManagerAndroid.cpp | 73 +++++++------- .../platforms/ExternalStreamManagerAndroid.h | 11 ++- 4 files changed, 140 insertions(+), 83 deletions(-) diff --git a/filament/backend/include/private/backend/VirtualMachineEnv.h b/filament/backend/include/private/backend/VirtualMachineEnv.h index 692abb31df..00dfa439e5 100644 --- a/filament/backend/include/private/backend/VirtualMachineEnv.h +++ b/filament/backend/include/private/backend/VirtualMachineEnv.h @@ -18,7 +18,7 @@ #define TNT_FILAMENT_DRIVER_ANDROID_VIRTUAL_MACHINE_ENV_H #include -#include +#include #include @@ -26,25 +26,17 @@ namespace filament { class VirtualMachineEnv { public: + // must be called before VirtualMachineEnv::get() from a thread that is attached to the JavaVM static jint JNI_OnLoad(JavaVM* vm) noexcept; - static VirtualMachineEnv& get() noexcept { - // declaring this thread local, will ensure it's destroyed with the calling thread - static thread_local VirtualMachineEnv instance; - return instance; - } + // must be called on backend thread + static VirtualMachineEnv& get() noexcept; - static JNIEnv* getThreadEnvironment() noexcept { - JNIEnv* env; - assert_invariant(sVirtualMachine); - if (sVirtualMachine->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { - return nullptr; // this should not happen - } - return env; - } + // can be called from any thread that already has a JniEnv + static JNIEnv* getThreadEnvironment() noexcept; - inline JNIEnv* getEnvironment() noexcept { - assert_invariant(mVirtualMachine); + // must be called from the backend thread + JNIEnv* getEnvironment() noexcept { JNIEnv* env = mJniEnv; if (UTILS_UNLIKELY(!env)) { return getEnvironmentSlow(); @@ -55,20 +47,14 @@ public: static void handleException(JNIEnv* env) noexcept; private: - VirtualMachineEnv() noexcept : mVirtualMachine(sVirtualMachine) { - // We're not initializing the JVM here -- but we could -- because most of the time - // we don't need the jvm. Instead we do the initialization on first use. This means we could get - // a nasty slow down the very first time, but we'll live with it for now. - } - - ~VirtualMachineEnv() { - if (mVirtualMachine) { - mVirtualMachine->DetachCurrentThread(); - } - } - + explicit VirtualMachineEnv(JavaVM* vm) noexcept; + ~VirtualMachineEnv() noexcept; JNIEnv* getEnvironmentSlow() noexcept; + + static utils::Mutex sLock; static JavaVM* sVirtualMachine; + static JavaVM* getVirtualMachine(); + JNIEnv* mJniEnv = nullptr; JavaVM* mVirtualMachine = nullptr; }; diff --git a/filament/backend/src/VirtualMachineEnv.cpp b/filament/backend/src/VirtualMachineEnv.cpp index c7ff7b1790..7909afc130 100644 --- a/filament/backend/src/VirtualMachineEnv.cpp +++ b/filament/backend/src/VirtualMachineEnv.cpp @@ -18,12 +18,28 @@ #include #include +#include +#include #include +#include + namespace filament { -JavaVM* VirtualMachineEnv::sVirtualMachine = nullptr; +using namespace utils; + +// This Mutex shouldn't be subject to the Static Initialization Order Fiasco because its initial state is +// a single int initialized to 0. +/* static*/ Mutex VirtualMachineEnv::sLock; +/* static*/ JavaVM* VirtualMachineEnv::sVirtualMachine = nullptr; + +UTILS_NOINLINE +JavaVM* VirtualMachineEnv::getVirtualMachine() { + std::lock_guard const lock(sLock); + assert_invariant(sVirtualMachine); + return sVirtualMachine; +} /* * This is typically called by filament_jni.so when it is loaded. If filament_jni.so is not used, @@ -35,15 +51,75 @@ JavaVM* VirtualMachineEnv::sVirtualMachine = nullptr; UTILS_PUBLIC UTILS_NOINLINE jint VirtualMachineEnv::JNI_OnLoad(JavaVM* vm) noexcept { - JNIEnv* env = nullptr; - if (UTILS_UNLIKELY(vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK)) { - // this should not happen - return -1; + std::lock_guard const lock(sLock); + if (sVirtualMachine) { + // It doesn't make sense for JNI_OnLoad() to be called more than once + return JNI_VERSION_1_6; } + + // Here we check this VM at least has JNI_VERSION_1_6 + JNIEnv* env = nullptr; + jint const result = vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); + + FILAMENT_CHECK_POSTCONDITION(result == JNI_OK) + << "Couldn't get JniEnv* from the VM, error = " << result; + sVirtualMachine = vm; return JNI_VERSION_1_6; } +UTILS_NOINLINE +VirtualMachineEnv& VirtualMachineEnv::get() noexcept { + JavaVM* const vm = getVirtualMachine(); + // declaring this thread local, will ensure it's destroyed with the calling thread + thread_local VirtualMachineEnv instance{ vm }; + return instance; +} + +UTILS_NOINLINE +JNIEnv* VirtualMachineEnv::getThreadEnvironment() noexcept { + JavaVM* const vm = getVirtualMachine(); + JNIEnv* env = nullptr; + jint const result = vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); + + FILAMENT_CHECK_POSTCONDITION(result == JNI_OK) + << "Couldn't get JniEnv* from the VM, error = " << result; + + return env; +} + +VirtualMachineEnv::VirtualMachineEnv(JavaVM* vm) noexcept : mVirtualMachine(vm) { + // We're not initializing the JVM here -- but we could -- because most of the time + // we don't need the jvm. Instead, we do the initialization on first use. This means we could get + // a nasty slow down the very first time, but we'll live with it for now. +} + +VirtualMachineEnv::~VirtualMachineEnv() noexcept { + if (mVirtualMachine) { + mVirtualMachine->DetachCurrentThread(); + } +} + +UTILS_NOINLINE +JNIEnv* VirtualMachineEnv::getEnvironmentSlow() noexcept { + FILAMENT_CHECK_PRECONDITION(mVirtualMachine) + << "JNI_OnLoad() has not been called"; + +#if defined(__ANDROID__) + jint const result = mVirtualMachine->AttachCurrentThread(&mJniEnv, nullptr); +#else + jint const result = mVirtualMachine->AttachCurrentThread(reinterpret_cast(&mJniEnv), nullptr); +#endif + + FILAMENT_CHECK_POSTCONDITION(result == JNI_OK) + << "JavaVM::AttachCurrentThread failed with error " << result; + + FILAMENT_CHECK_POSTCONDITION(mJniEnv) + << "JavaVM::AttachCurrentThread returned a null mJniEnv"; + + return mJniEnv; +} + UTILS_NOINLINE void VirtualMachineEnv::handleException(JNIEnv* const env) noexcept { if (UTILS_UNLIKELY(env->ExceptionCheck())) { @@ -52,16 +128,5 @@ void VirtualMachineEnv::handleException(JNIEnv* const env) noexcept { } } -UTILS_NOINLINE -JNIEnv* VirtualMachineEnv::getEnvironmentSlow() noexcept { -#if defined(__ANDROID__) - mVirtualMachine->AttachCurrentThread(&mJniEnv, nullptr); -#else - mVirtualMachine->AttachCurrentThread(reinterpret_cast(&mJniEnv), nullptr); -#endif - assert_invariant(mJniEnv); - return mJniEnv; -} - } // namespace filament diff --git a/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.cpp b/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.cpp index 9a37198b3b..88b929d8bb 100644 --- a/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.cpp +++ b/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.cpp @@ -16,13 +16,28 @@ #include "ExternalStreamManagerAndroid.h" -#include +#include + +#include + #include +#include #include +#include -#include +#if __has_include() +# include +# include +#else +struct ASurfaceTexture; +typedef struct ASurfaceTexture ASurfaceTexture; +#endif -#include +#include + +#include + +#include using namespace utils; @@ -32,13 +47,8 @@ using namespace backend; using Stream = Platform::Stream; -template -static void loadSymbol(T*& pfn, const char *symbol) noexcept { - pfn = (T*)dlsym(RTLD_DEFAULT, symbol); -} - ExternalStreamManagerAndroid& ExternalStreamManagerAndroid::create() noexcept { - return *(new ExternalStreamManagerAndroid{}); + return *(new(std::nothrow) ExternalStreamManagerAndroid{}); } void ExternalStreamManagerAndroid::destroy(ExternalStreamManagerAndroid* pExternalStreamManagerAndroid) noexcept { @@ -56,23 +66,13 @@ ExternalStreamManagerAndroid::~ExternalStreamManagerAndroid() noexcept = default UTILS_NOINLINE JNIEnv* ExternalStreamManagerAndroid::getEnvironmentSlow() noexcept { - JNIEnv * env = mVm.getEnvironment(); + JNIEnv* const env = mVm.getEnvironment(); mJniEnv = env; - jclass SurfaceTextureClass = env->FindClass("android/graphics/SurfaceTexture"); - - mSurfaceTextureClass_updateTexImage = env->GetMethodID( - SurfaceTextureClass, "updateTexImage", "()V"); - - mSurfaceTextureClass_attachToGLContext = env->GetMethodID( - SurfaceTextureClass, "attachToGLContext", "(I)V"); - - mSurfaceTextureClass_detachFromGLContext = env->GetMethodID( - SurfaceTextureClass, "detachFromGLContext", "()V"); - - mSurfaceTextureClass_getTimestamp = env->GetMethodID( - SurfaceTextureClass, "getTimestamp", "()J"); - + mSurfaceTextureClass_updateTexImage = env->GetMethodID(SurfaceTextureClass, "updateTexImage", "()V"); + mSurfaceTextureClass_attachToGLContext = env->GetMethodID(SurfaceTextureClass, "attachToGLContext", "(I)V"); + mSurfaceTextureClass_detachFromGLContext = env->GetMethodID(SurfaceTextureClass, "detachFromGLContext", "()V"); + mSurfaceTextureClass_getTimestamp = env->GetMethodID(SurfaceTextureClass, "getTimestamp", "()J"); return env; } @@ -82,7 +82,7 @@ Stream* ExternalStreamManagerAndroid::acquire(jobject surfaceTexture) noexcept { if (!env) { return nullptr; // this should not happen } - EGLStream* stream = new EGLStream(); + EGLStream* stream = new(std::nothrow) EGLStream(); stream->jSurfaceTexture = env->NewGlobalRef(surfaceTexture); if (__builtin_available(android 28, *)) { stream->nSurfaceTexture = ASurfaceTexture_fromSurfaceTexture(env, surfaceTexture); @@ -91,29 +91,30 @@ Stream* ExternalStreamManagerAndroid::acquire(jobject surfaceTexture) noexcept { } void ExternalStreamManagerAndroid::release(Stream* handle) noexcept { - EGLStream* stream = static_cast(handle); + EGLStream const* stream = static_cast(handle); if (__builtin_available(android 28, *)) { ASurfaceTexture_release(stream->nSurfaceTexture); } - JNIEnv* const env = getEnvironment(); + // use VirtualMachineEnv::getEnvironment() directly because we don't need to cache JNI methods here + JNIEnv* const env = mVm.getEnvironment(); assert_invariant(env); // we should have called attach() by now env->DeleteGlobalRef(stream->jSurfaceTexture); delete stream; } void ExternalStreamManagerAndroid::attach(Stream* handle, intptr_t tname) noexcept { - EGLStream* stream = static_cast(handle); + EGLStream const* stream = static_cast(handle); if (__builtin_available(android 28, *)) { // associate our GL texture to the SurfaceTexture ASurfaceTexture* const aSurfaceTexture = stream->nSurfaceTexture; - if (UTILS_UNLIKELY(ASurfaceTexture_attachToGLContext(aSurfaceTexture, (uint32_t)tname))) { + if (UTILS_UNLIKELY(ASurfaceTexture_attachToGLContext(aSurfaceTexture, uint32_t(tname)))) { // Unfortunately, before API 26 SurfaceTexture was always created in attached mode, // so attachToGLContext can fail. We consider this the unlikely case, because // this is how it should work. // So now we have to detach the surfacetexture from its texture ASurfaceTexture_detachFromGLContext(aSurfaceTexture); // and finally, try attaching again - ASurfaceTexture_attachToGLContext(aSurfaceTexture, (uint32_t)tname); + ASurfaceTexture_attachToGLContext(aSurfaceTexture, uint32_t(tname)); } } else { JNIEnv* const env = getEnvironment(); @@ -121,19 +122,19 @@ void ExternalStreamManagerAndroid::attach(Stream* handle, intptr_t tname) noexce // associate our GL texture to the SurfaceTexture jobject jSurfaceTexture = stream->jSurfaceTexture; - env->CallVoidMethod(jSurfaceTexture, mSurfaceTextureClass_attachToGLContext, (jint)tname); + env->CallVoidMethod(jSurfaceTexture, mSurfaceTextureClass_attachToGLContext, jint(tname)); if (UTILS_UNLIKELY(env->ExceptionCheck())) { // Unfortunately, before API 26 SurfaceTexture was always created in attached mode, // so attachToGLContext can fail. We consider this the unlikely case, because // this is how it should work. env->ExceptionClear(); - // so now we have to detach the surfacetexture from its texture + // so now we have to detach the SurfaceTexture from its texture env->CallVoidMethod(jSurfaceTexture, mSurfaceTextureClass_detachFromGLContext); VirtualMachineEnv::handleException(env); // and finally, try attaching again - env->CallVoidMethod(jSurfaceTexture, mSurfaceTextureClass_attachToGLContext, (jint)tname); + env->CallVoidMethod(jSurfaceTexture, mSurfaceTextureClass_attachToGLContext, jint(tname)); VirtualMachineEnv::handleException(env); } } @@ -144,7 +145,7 @@ void ExternalStreamManagerAndroid::detach(Stream* handle) noexcept { if (__builtin_available(android 28, *)) { ASurfaceTexture_detachFromGLContext(stream->nSurfaceTexture); } else { - JNIEnv* const env = mVm.getEnvironment(); + JNIEnv* const env = getEnvironment(); assert_invariant(env); // we should have called attach() by now env->CallVoidMethod(stream->jSurfaceTexture, mSurfaceTextureClass_detachFromGLContext); VirtualMachineEnv::handleException(env); @@ -152,12 +153,12 @@ void ExternalStreamManagerAndroid::detach(Stream* handle) noexcept { } void ExternalStreamManagerAndroid::updateTexImage(Stream* handle, int64_t* timestamp) noexcept { - EGLStream* stream = static_cast(handle); + EGLStream const* stream = static_cast(handle); if (__builtin_available(android 28, *)) { ASurfaceTexture_updateTexImage(stream->nSurfaceTexture); *timestamp = ASurfaceTexture_getTimestamp(stream->nSurfaceTexture); } else { - JNIEnv* const env = mVm.getEnvironment(); + JNIEnv* const env = getEnvironment(); assert_invariant(env); // we should have called attach() by now env->CallVoidMethod(stream->jSurfaceTexture, mSurfaceTextureClass_updateTexImage); VirtualMachineEnv::handleException(env); diff --git a/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.h b/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.h index 9296a0e1c8..d1257269c3 100644 --- a/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.h +++ b/filament/backend/src/opengl/platforms/ExternalStreamManagerAndroid.h @@ -21,14 +21,19 @@ #include +#include + #if __has_include() # include -# include #else struct ASurfaceTexture; typedef struct ASurfaceTexture ASurfaceTexture; #endif +#include + +#include + namespace filament::backend { /* @@ -70,7 +75,8 @@ private: ASurfaceTexture* nSurfaceTexture = nullptr; }; - inline JNIEnv* getEnvironment() noexcept { + // Must only be called from the backend thread + JNIEnv* getEnvironment() noexcept { JNIEnv* env = mJniEnv; if (UTILS_UNLIKELY(!env)) { return getEnvironmentSlow(); @@ -85,7 +91,6 @@ private: jmethodID mSurfaceTextureClass_attachToGLContext{}; jmethodID mSurfaceTextureClass_detachFromGLContext{}; }; - } // namespace filament::backend #endif //TNT_FILAMENT_BACKEND_OPENGL_ANDROID_EXTERNAL_STREAM_MANAGER_ANDROID_H From fb9518e9159882701560bf52ae19e0d357a5edc5 Mon Sep 17 00:00:00 2001 From: Sungun Park Date: Mon, 3 Feb 2025 09:43:44 -0800 Subject: [PATCH 08/24] Fix warnings regarding #pragma clang (#8405) '#pragma clang' is unavailable in MSVC. Wrap them with the proper preprocessor to avoid warnings in MSVC. BUGS=[390207431] --- .../backend/include/private/backend/DriverAPI.inc | 4 ++++ filament/backend/src/opengl/OpenGLDriver.cpp | 4 ++++ filament/backend/src/vulkan/VulkanDriver.cpp | 4 ++++ filament/backend/src/vulkan/VulkanMemory.cpp | 5 +++++ filament/backend/src/vulkan/VulkanMemory.h | 2 ++ .../backend/src/vulkan/VulkanPipelineCache.cpp | 4 ++++ filament/backend/src/vulkan/VulkanPipelineCache.h | 4 ++++ filament/src/Culler.cpp | 8 ++++++++ filament/src/Froxelizer.cpp | 2 ++ filament/src/ToneMapper.cpp | 4 ++++ filament/src/details/ColorGrading.cpp | 14 ++++++++++++++ filament/src/fsr.cpp | 4 ++++ 12 files changed, 59 insertions(+) diff --git a/filament/backend/include/private/backend/DriverAPI.inc b/filament/backend/include/private/backend/DriverAPI.inc index 6b951da975..2c22147aaa 100644 --- a/filament/backend/include/private/backend/DriverAPI.inc +++ b/filament/backend/include/private/backend/DriverAPI.inc @@ -126,8 +126,10 @@ * Driver API below... */ +#if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-parameter" +#endif DECL_DRIVER_API_0(tick) @@ -533,7 +535,9 @@ DECL_DRIVER_API_N(scissor, Viewport, scissor) +#if defined(__clang__) #pragma clang diagnostic pop +#endif #undef EXPAND diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 8714bacba2..9b5b13ed60 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -75,9 +75,11 @@ #include #endif +#if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunknown-pragmas" #pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection" +#endif // We can only support this feature on OpenGL ES 3.1+ // Support is currently disabled as we don't need it @@ -4094,4 +4096,6 @@ template class ConcreteDispatcher; } // namespace filament::backend +#if defined(__clang__) #pragma clang diagnostic pop +#endif diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index bc0957bf52..38db05cbcc 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -44,11 +44,13 @@ using namespace bluevk; using utils::FixedCapacityVector; +#if defined(__clang__) // Vulkan functions often immediately dereference pointers, so it's fine to pass in a pointer // to a stack-allocated variable. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreturn-stack-address" #pragma clang diagnostic ignored "-Wunused-parameter" +#endif namespace filament::backend { @@ -1882,4 +1884,6 @@ template class ConcreteDispatcher; } // namespace filament::backend +#if defined(__clang__) #pragma clang diagnostic pop +#endif diff --git a/filament/backend/src/vulkan/VulkanMemory.cpp b/filament/backend/src/vulkan/VulkanMemory.cpp index 16f94346a7..4e6de735a3 100644 --- a/filament/backend/src/vulkan/VulkanMemory.cpp +++ b/filament/backend/src/vulkan/VulkanMemory.cpp @@ -16,6 +16,7 @@ #include // must be included before vk_mem_alloc +#if defined(__clang__) #pragma clang diagnostic push // Needed because not all clang versions have the warning -Wdeprecated-copy. @@ -32,6 +33,7 @@ #pragma clang diagnostic ignored "-Wextra-semi" #pragma clang diagnostic ignored "-Wc++98-compat-extra-semi" #pragma clang diagnostic ignored "-Wthread-safety-analysis" +#endif static const PFN_vkGetInstanceProcAddr& vkGetInstanceProcAddr = bluevk::vkGetInstanceProcAddr; static const PFN_vkGetDeviceProcAddr& vkGetDeviceProcAddr = bluevk::vkGetDeviceProcAddr; @@ -39,4 +41,7 @@ static const PFN_vkGetDeviceProcAddr& vkGetDeviceProcAddr = bluevk::vkGetDeviceP #define VMA_STATIC_VULKAN_FUNCTIONS 0 #define VMA_IMPLEMENTATION #include "vk_mem_alloc.h" + +#if defined(__clang__) #pragma clang diagnostic pop +#endif diff --git a/filament/backend/src/vulkan/VulkanMemory.h b/filament/backend/src/vulkan/VulkanMemory.h index a5ab295319..d16cd515a8 100644 --- a/filament/backend/src/vulkan/VulkanMemory.h +++ b/filament/backend/src/vulkan/VulkanMemory.h @@ -27,7 +27,9 @@ #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 #endif +#if defined(__clang__) #pragma clang diagnostic ignored "-Wc++98-compat-extra-semi" +#endif #include "vk_mem_alloc.h" diff --git a/filament/backend/src/vulkan/VulkanPipelineCache.cpp b/filament/backend/src/vulkan/VulkanPipelineCache.cpp index 4cf98cef15..8f6e5df8de 100644 --- a/filament/backend/src/vulkan/VulkanPipelineCache.cpp +++ b/filament/backend/src/vulkan/VulkanPipelineCache.cpp @@ -26,10 +26,12 @@ #include "VulkanTexture.h" #include "VulkanUtility.h" +#if defined(__clang__) // Vulkan functions often immediately dereference pointers, so it's fine to pass in a pointer // to a stack-allocated variable. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wreturn-stack-address" +#endif using namespace bluevk; @@ -323,4 +325,6 @@ bool VulkanPipelineCache::PipelineEqual::operator()(const PipelineKey& k1, } // namespace filament::backend +#if defined(__clang__) #pragma clang diagnostic pop +#endif diff --git a/filament/backend/src/vulkan/VulkanPipelineCache.h b/filament/backend/src/vulkan/VulkanPipelineCache.h index c0500fbb8b..a4a6e28c38 100644 --- a/filament/backend/src/vulkan/VulkanPipelineCache.h +++ b/filament/backend/src/vulkan/VulkanPipelineCache.h @@ -68,8 +68,10 @@ public: VkSpecializationInfo* specializationInfos = nullptr; }; +#if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic warning "-Wpadded" +#endif // The RasterState POD contains standard graphics-related state like blending, culling, etc. // The following states are omitted because Filament never changes them: @@ -212,7 +214,9 @@ private: bool operator()(const PipelineKey& k1, const PipelineKey& k2) const; }; +#if defined(__clang__) #pragma clang diagnostic pop +#endif // CACHE ENTRY STRUCTS // ------------------- diff --git a/filament/src/Culler.cpp b/filament/src/Culler.cpp index 85e8bf03ac..0fb5358e03 100644 --- a/filament/src/Culler.cpp +++ b/filament/src/Culler.cpp @@ -40,12 +40,16 @@ void Culler::intersects( float4 const * const UTILS_RESTRICT planes = frustum.mPlanes; count = round(count); +#if defined(__clang__) #pragma clang loop vectorize_width(FILAMENT_CULLER_VECTORIZE_HINT) +#endif for (size_t i = 0; i < count; i++) { int visible = ~0; float4 const sphere(b[i]); +#if defined(__clang__) #pragma clang loop unroll(full) +#endif for (size_t j = 0; j < 6; j++) { // clang doesn't seem to generate vector * scalar instructions, which leads // to increased register pressure and stack spills @@ -69,11 +73,15 @@ void Culler::intersects( float4 const * UTILS_RESTRICT const planes = frustum.mPlanes; count = round(count); +#if defined(__clang__) #pragma clang loop vectorize_width(FILAMENT_CULLER_VECTORIZE_HINT) +#endif for (size_t i = 0; i < count; i++) { int visible = ~0; +#if defined(__clang__) #pragma clang loop unroll(full) +#endif for (size_t j = 0; j < 6; j++) { // clang doesn't seem to generate vector * scalar instructions, which leads // to increased register pressure and stack spills diff --git a/filament/src/Froxelizer.cpp b/filament/src/Froxelizer.cpp index fe8975276e..0feed65717 100644 --- a/filament/src/Froxelizer.cpp +++ b/filament/src/Froxelizer.cpp @@ -395,7 +395,9 @@ bool Froxelizer::update() noexcept { const float linearizer = std::log2(zLightFar / zLightNear) / float(std::max(1u, mFroxelCountZ - 1u)); // for a strange reason when, vectorizing this loop, clang does some math in double // and generates conversions to float. not worth it for so little iterations. +#if defined(__clang__) #pragma clang loop vectorize(disable) unroll(disable) +#endif for (ssize_t i = 1, n = mFroxelCountZ; i <= n; i++) { mDistancesZ[i] = zLightFar * std::exp2(float(i - n) * linearizer); } diff --git a/filament/src/ToneMapper.cpp b/filament/src/ToneMapper.cpp index e6f9fc8c14..5c4203dae3 100644 --- a/filament/src/ToneMapper.cpp +++ b/filament/src/ToneMapper.cpp @@ -399,8 +399,10 @@ float3 DisplayRangeToneMapper::operator()(float3 const c) const noexcept { //------------------------------------------------------------------------------ struct GenericToneMapper::Options { +#if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wshadow" +#endif void setParameters( float contrast, float midGrayIn, @@ -424,7 +426,9 @@ struct GenericToneMapper::Options { inputScale = (a * b * (midGrayOut - 1.0f)) / c; outputScale = midGrayOut * (a - b) / c; } +#if defined(__clang__) #pragma clang diagnostic pop +#endif float contrast; float midGrayIn; diff --git a/filament/src/details/ColorGrading.cpp b/filament/src/details/ColorGrading.cpp index b3c577c2d6..a1077f771b 100644 --- a/filament/src/details/ColorGrading.cpp +++ b/filament/src/details/ColorGrading.cpp @@ -52,10 +52,14 @@ using namespace backend; struct ColorGrading::BuilderDetails { const ToneMapper* toneMapper = nullptr; +#if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif ToneMapping toneMapping = ToneMapping::ACES_LEGACY; +#if defined(__clang__) #pragma clang diagnostic pop +#endif bool hasAdjustments = false; @@ -268,8 +272,10 @@ ColorGrading::Builder& ColorGrading::Builder::outputColorSpace( return *this; } +#if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif ColorGrading* ColorGrading::Builder::build(Engine& engine) { // We want to see if any of the default adjustment values have been modified // We skip the tonemapping operator on purpose since we always want to apply it @@ -309,7 +315,9 @@ ColorGrading* ColorGrading::Builder::build(Engine& engine) { return colorGrading; } +#if defined(__clang__) #pragma clang diagnostic pop +#endif //------------------------------------------------------------------------------ // Exposure @@ -585,8 +593,10 @@ static std::tuple } } +#if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif // The following functions exist to preserve backward compatibility with the // `FILMIC` set via the deprecated `ToneMapping` API. Selecting `ToneMapping::FILMIC` // forces post-processing to be performed in sRGB to guarantee that the inverse tone @@ -612,7 +622,9 @@ static float3 selectColorGradingLuminance(ColorGrading::ToneMapping const toneMa } return LUMINANCE_Rec2020; } +#if defined(__clang__) #pragma clang diagnostic pop +#endif using ColorTransform = float3(*)(float3); @@ -792,7 +804,9 @@ FColorGrading::FColorGrading(FEngine& engine, const Builder& builder) { // we use a vectorize width of 8 because, on ARMv8 it allows the compiler to write eight // 32-bits results in one go. const size_t count = (config.lutDimension * config.lutDimension) & ~0x7u; // tell the compiler that we're a multiple of 8 +#if defined(__clang__) #pragma clang loop vectorize_width(8) +#endif for (size_t i = 0; i < count; ++i) { float4 v{src[i]}; uint32_t pr = uint32_t(std::floor(v.x * 1023.0f + 0.5f)); diff --git a/filament/src/fsr.cpp b/filament/src/fsr.cpp index 943625355c..925db9cd00 100644 --- a/filament/src/fsr.cpp +++ b/filament/src/fsr.cpp @@ -26,9 +26,11 @@ namespace filament { using namespace math; +#if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-function" #pragma clang diagnostic ignored "-Wignored-qualifiers" +#endif #define A_CPU 1 #include "materials/fsr/ffx_a.h" @@ -36,7 +38,9 @@ using namespace math; #define FSR_RCAS_F 1 #include "materials/fsr/ffx_fsr1.h" +#if defined(__clang__) #pragma clang diagnostic pop +#endif void FSR_ScalingSetup(FSRUniforms* outUniforms, FSRScalingConfig config) noexcept { // FsrEasu API claims it needs the left-top offset, however that's not true with OpenGL, From 93fa55bd2909eeba535cf917dee27f541f368a37 Mon Sep 17 00:00:00 2001 From: Powei Feng Date: Mon, 3 Feb 2025 11:10:19 -0800 Subject: [PATCH 09/24] vk: refactor utils into its own namespace (#8280) We move the code that was contained within two "utils" files into separate utils sources in the vulkan/utils directory. --- filament/backend/CMakeLists.txt | 15 +- filament/backend/src/vulkan/VulkanBlitter.cpp | 9 +- filament/backend/src/vulkan/VulkanCommands.h | 6 +- filament/backend/src/vulkan/VulkanContext.cpp | 1 - filament/backend/src/vulkan/VulkanContext.h | 14 +- filament/backend/src/vulkan/VulkanDriver.cpp | 47 ++-- filament/backend/src/vulkan/VulkanDriver.h | 16 +- .../backend/src/vulkan/VulkanFboCache.cpp | 26 +-- filament/backend/src/vulkan/VulkanHandles.cpp | 18 +- filament/backend/src/vulkan/VulkanHandles.h | 25 +-- .../src/vulkan/VulkanPipelineCache.cpp | 4 +- .../backend/src/vulkan/VulkanPipelineCache.h | 1 - .../backend/src/vulkan/VulkanReadPixels.cpp | 13 +- .../backend/src/vulkan/VulkanSamplerCache.cpp | 3 +- .../backend/src/vulkan/VulkanSamplerCache.h | 1 - .../backend/src/vulkan/VulkanStagePool.cpp | 10 +- filament/backend/src/vulkan/VulkanTexture.cpp | 42 ++-- filament/backend/src/vulkan/VulkanTexture.h | 2 +- .../caching/VulkanDescriptorSetManager.cpp | 22 +- .../caching/VulkanDescriptorSetManager.h | 7 +- .../src/vulkan/platform/VulkanPlatform.cpp | 24 +-- .../vulkan/platform/VulkanPlatformAndroid.cpp | 1 - .../platform/VulkanPlatformSwapChainImpl.cpp | 23 +- .../Conversion.cpp} | 68 +----- .../backend/src/vulkan/utils/Conversion.h | 76 +++++++ .../{VulkanUtility.h => utils/Definitions.h} | 204 +----------------- filament/backend/src/vulkan/utils/Helper.h | 84 ++++++++ .../Image.cpp} | 42 +++- .../{VulkanImageUtility.h => utils/Image.h} | 34 ++- .../VulkanSpirvUtils.cpp => utils/Spirv.cpp} | 70 +----- .../VulkanSpirvUtils.h => utils/Spirv.h} | 15 +- .../backend/src/vulkan/utils/StaticVector.h | 134 ++++++++++++ 32 files changed, 541 insertions(+), 516 deletions(-) rename filament/backend/src/vulkan/{VulkanUtility.cpp => utils/Conversion.cpp} (92%) create mode 100644 filament/backend/src/vulkan/utils/Conversion.h rename filament/backend/src/vulkan/{VulkanUtility.h => utils/Definitions.h} (70%) create mode 100644 filament/backend/src/vulkan/utils/Helper.h rename filament/backend/src/vulkan/{VulkanImageUtility.cpp => utils/Image.cpp} (87%) rename filament/backend/src/vulkan/{VulkanImageUtility.h => utils/Image.h} (84%) rename filament/backend/src/vulkan/{spirv/VulkanSpirvUtils.cpp => utils/Spirv.cpp} (72%) rename filament/backend/src/vulkan/{spirv/VulkanSpirvUtils.h => utils/Spirv.h} (77%) create mode 100644 filament/backend/src/vulkan/utils/StaticVector.h diff --git a/filament/backend/CMakeLists.txt b/filament/backend/CMakeLists.txt index 208aec0ee0..9fc673990b 100644 --- a/filament/backend/CMakeLists.txt +++ b/filament/backend/CMakeLists.txt @@ -185,8 +185,15 @@ if (FILAMENT_SUPPORTS_VULKAN) src/vulkan/platform/VulkanPlatform.cpp src/vulkan/platform/VulkanPlatformSwapChainImpl.cpp src/vulkan/platform/VulkanPlatformSwapChainImpl.h - src/vulkan/spirv/VulkanSpirvUtils.cpp - src/vulkan/spirv/VulkanSpirvUtils.h + src/vulkan/utils/Conversion.cpp + src/vulkan/utils/Conversion.h + src/vulkan/utils/Definitions.h + src/vulkan/utils/Helper.h + src/vulkan/utils/Image.h + src/vulkan/utils/Image.cpp + src/vulkan/utils/Spirv.h + src/vulkan/utils/Spirv.cpp + src/vulkan/utils/StaticVector.h src/vulkan/VulkanAsyncHandles.cpp src/vulkan/VulkanAsyncHandles.h src/vulkan/VulkanBlitter.cpp @@ -205,8 +212,6 @@ if (FILAMENT_SUPPORTS_VULKAN) src/vulkan/VulkanFboCache.h src/vulkan/VulkanHandles.cpp src/vulkan/VulkanHandles.h - src/vulkan/VulkanImageUtility.cpp - src/vulkan/VulkanImageUtility.h src/vulkan/VulkanMemory.h src/vulkan/VulkanMemory.cpp src/vulkan/VulkanPipelineCache.cpp @@ -221,8 +226,6 @@ if (FILAMENT_SUPPORTS_VULKAN) src/vulkan/VulkanReadPixels.h src/vulkan/VulkanTexture.cpp src/vulkan/VulkanTexture.h - src/vulkan/VulkanUtility.cpp - src/vulkan/VulkanUtility.h ) if (LINUX OR WIN32) list(APPEND SRCS src/vulkan/platform/VulkanPlatformLinuxWindows.cpp) diff --git a/filament/backend/src/vulkan/VulkanBlitter.cpp b/filament/backend/src/vulkan/VulkanBlitter.cpp index bcb786e63a..c88bc27f46 100644 --- a/filament/backend/src/vulkan/VulkanBlitter.cpp +++ b/filament/backend/src/vulkan/VulkanBlitter.cpp @@ -21,6 +21,7 @@ #include "VulkanHandles.h" #include "VulkanSamplerCache.h" #include "VulkanTexture.h" +#include "vulkan/utils/Image.h" #include #include @@ -61,8 +62,8 @@ inline void blitFast(VulkanCommandBuffer* commands, VkImageAspectFlags aspect, V .dstOffsets = { dstRect[0], dstRect[1] }, }}; vkCmdBlitImage(cmdbuf, - src.getImage(), imgutil::getVkLayout(VulkanLayout::TRANSFER_SRC), - dst.getImage(), imgutil::getVkLayout(VulkanLayout::TRANSFER_DST), + src.getImage(), fvkutils::getVkLayout(VulkanLayout::TRANSFER_SRC), + dst.getImage(), fvkutils::getVkLayout(VulkanLayout::TRANSFER_DST), 1, blitRegions, filter); if (oldSrcLayout == VulkanLayout::UNDEFINED) { @@ -104,8 +105,8 @@ inline void resolveFast(VulkanCommandBuffer* commands, VkImageAspectFlags aspect .extent = { src.getExtent2D().width, src.getExtent2D().height, 1 }, }}; vkCmdResolveImage(cmdbuffer, - src.getImage(), imgutil::getVkLayout(VulkanLayout::TRANSFER_SRC), - dst.getImage(), imgutil::getVkLayout(VulkanLayout::TRANSFER_DST), + src.getImage(), fvkutils::getVkLayout(VulkanLayout::TRANSFER_SRC), + dst.getImage(), fvkutils::getVkLayout(VulkanLayout::TRANSFER_DST), 1, resolveRegions); if (oldSrcLayout == VulkanLayout::UNDEFINED) { diff --git a/filament/backend/src/vulkan/VulkanCommands.h b/filament/backend/src/vulkan/VulkanCommands.h index 2e331dfa4a..0afd4b4b46 100644 --- a/filament/backend/src/vulkan/VulkanCommands.h +++ b/filament/backend/src/vulkan/VulkanCommands.h @@ -23,8 +23,8 @@ #include "VulkanAsyncHandles.h" #include "VulkanConstants.h" -#include "VulkanUtility.h" #include "vulkan/memory/ResourcePointer.h" +#include "vulkan/utils/StaticVector.h" #include #include @@ -79,7 +79,7 @@ struct VulkanCommandBuffer { void reset() noexcept; inline void insertWait(VkSemaphore sem) { - mWaitSemaphores.insert(sem); + mWaitSemaphores.push_back(sem); } void pushMarker(char const* marker) noexcept; @@ -115,7 +115,7 @@ private: bool const isProtected; VkDevice mDevice; VkQueue mQueue; - CappedArray mWaitSemaphores; + fvkutils::StaticVector mWaitSemaphores; VkCommandBuffer mBuffer; VkSemaphore mSubmission; VkFence mFence; diff --git a/filament/backend/src/vulkan/VulkanContext.cpp b/filament/backend/src/vulkan/VulkanContext.cpp index 95d860d618..0345e69cf9 100644 --- a/filament/backend/src/vulkan/VulkanContext.cpp +++ b/filament/backend/src/vulkan/VulkanContext.cpp @@ -20,7 +20,6 @@ #include "VulkanHandles.h" #include "VulkanMemory.h" #include "VulkanTexture.h" -#include "VulkanUtility.h" #include diff --git a/filament/backend/src/vulkan/VulkanContext.h b/filament/backend/src/vulkan/VulkanContext.h index 67c4e52a9b..aebc355050 100644 --- a/filament/backend/src/vulkan/VulkanContext.h +++ b/filament/backend/src/vulkan/VulkanContext.h @@ -18,8 +18,8 @@ #define TNT_FILAMENT_BACKEND_VULKANCONTEXT_H #include "VulkanConstants.h" -#include "VulkanImageUtility.h" -#include "VulkanUtility.h" +#include "vulkan/utils/Image.h" +#include "vulkan/utils/Definitions.h" #include "vulkan/memory/ResourcePointer.h" @@ -28,6 +28,8 @@ #include #include +#include + #include VK_DEFINE_HANDLE(VmaAllocator) @@ -113,11 +115,11 @@ public: return (uint32_t) VK_MAX_MEMORY_TYPES; } - inline VkFormatList const& getAttachmentDepthStencilFormats() const { + inline fvkutils::VkFormatList const& getAttachmentDepthStencilFormats() const { return mDepthStencilFormats; } - inline VkFormatList const& getBlittableDepthStencilFormats() const { + inline fvkutils::VkFormatList const& getBlittableDepthStencilFormats() const { return mBlittableDepthStencilFormats; } @@ -175,8 +177,8 @@ private: bool mLazilyAllocatedMemorySupported = false; bool mProtectedMemorySupported = false; - VkFormatList mDepthStencilFormats; - VkFormatList mBlittableDepthStencilFormats; + fvkutils::VkFormatList mDepthStencilFormats; + fvkutils::VkFormatList mBlittableDepthStencilFormats; // For convenience so that VulkanPlatform can initialize the private fields. friend class VulkanPlatform; diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index 38db05cbcc..9df949d685 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -26,10 +26,12 @@ #include "VulkanHandles.h" #include "VulkanMemory.h" #include "VulkanTexture.h" -#include "backend/DriverEnums.h" -#include "memory/ResourceManager.h" -#include "memory/ResourcePointer.h" +#include "vulkan/memory/ResourceManager.h" +#include "vulkan/memory/ResourcePointer.h" +#include "vulkan/utils/Conversion.h" +#include "vulkan/utils/Definitions.h" +#include #include #include @@ -543,16 +545,16 @@ void VulkanDriver::createTextureViewSwizzleR(Handle th, Handle::cast(&mResourceManager, srch); auto texture = resource_ptr::make(&mResourceManager, th, mPlatform->getDevice(), mPlatform->getPhysicalDevice(), mContext, mAllocator, &mCommands, src, swizzle); texture.inc(); } -void VulkanDriver::createTextureExternalImageR(Handle th, - backend::SamplerType target, backend::TextureFormat format, - uint32_t width, uint32_t height, backend::TextureUsage usage, void* externalImage) { +void VulkanDriver::createTextureExternalImageR(Handle th, backend::SamplerType target, + backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage, + void* externalImage) { FVK_SYSTRACE_SCOPE(); const auto& metadata = mPlatform->getExternalImageMetadata(externalImage); @@ -562,7 +564,7 @@ void VulkanDriver::createTextureExternalImageR(Handle th, assert_invariant(width == metadata.width); assert_invariant(height == metadata.height); - assert_invariant(getVkFormat(format) == metadata.format); + assert_invariant(fvkutils::getVkFormat(format) == metadata.format); const auto& data = mPlatform->createExternalImage(externalImage, metadata); @@ -937,7 +939,7 @@ FenceStatus VulkanDriver::getFenceStatus(Handle fh) { // 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 VulkanDriver::isTextureFormatSupported(TextureFormat format) { - VkFormat vkformat = getVkFormat(format); + VkFormat vkformat = fvkutils::getVkFormat(format); if (vkformat == VK_FORMAT_UNDEFINED) { return false; } @@ -964,7 +966,7 @@ bool VulkanDriver::isTextureFormatMipmappable(TextureFormat format) { } bool VulkanDriver::isRenderTargetFormatSupported(TextureFormat format) { - VkFormat vkformat = getVkFormat(format); + VkFormat vkformat = fvkutils::getVkFormat(format); if (vkformat == VK_FORMAT_UNDEFINED) { return false; } @@ -1022,12 +1024,11 @@ bool VulkanDriver::isDepthStencilResolveSupported() { bool VulkanDriver::isDepthStencilBlitSupported(TextureFormat format) { auto const& formats = mContext.getBlittableDepthStencilFormats(); - return std::find(formats.begin(), formats.end(), getVkFormat(format)) != formats.end(); + return std::find(formats.begin(), formats.end(), fvkutils::getVkFormat(format)) != + formats.end(); } -bool VulkanDriver::isProtectedTexturesSupported() { - return false; -} +bool VulkanDriver::isProtectedTexturesSupported() { return false; } bool VulkanDriver::isDepthClampSupported() { return mContext.isDepthClampSupported(); @@ -1680,25 +1681,25 @@ void VulkanDriver::bindPipeline(PipelineState const& pipelineState) { auto rt = mCurrentRenderPass.renderTarget; VulkanPipelineCache::RasterState const vulkanRasterState{ - .cullMode = getCullMode(rasterState.culling), - .frontFace = getFrontFace(rasterState.inverseFrontFaces), + .cullMode = fvkutils::getCullMode(rasterState.culling), + .frontFace = fvkutils::getFrontFace(rasterState.inverseFrontFaces), .depthBiasEnable = (depthOffset.constant || depthOffset.slope) ? true : false, .blendEnable = rasterState.hasBlending(), .depthWriteEnable = rasterState.depthWrite, .alphaToCoverageEnable = rasterState.alphaToCoverage, - .srcColorBlendFactor = getBlendFactor(rasterState.blendFunctionSrcRGB), - .dstColorBlendFactor = getBlendFactor(rasterState.blendFunctionDstRGB), - .srcAlphaBlendFactor = getBlendFactor(rasterState.blendFunctionSrcAlpha), - .dstAlphaBlendFactor = getBlendFactor(rasterState.blendFunctionDstAlpha), + .srcColorBlendFactor = fvkutils::getBlendFactor(rasterState.blendFunctionSrcRGB), + .dstColorBlendFactor = fvkutils::getBlendFactor(rasterState.blendFunctionDstRGB), + .srcAlphaBlendFactor = fvkutils::getBlendFactor(rasterState.blendFunctionSrcAlpha), + .dstAlphaBlendFactor = fvkutils::getBlendFactor(rasterState.blendFunctionDstAlpha), .colorWriteMask = (VkColorComponentFlags) (rasterState.colorWrite ? 0xf : 0x0), .rasterizationSamples = rt->getSamples(), .depthClamp = rasterState.depthClamp, .colorTargetCount = rt->getColorTargetCount(mCurrentRenderPass), .colorBlendOp = rasterState.blendEquationRGB, - .alphaBlendOp = rasterState.blendEquationAlpha, + .alphaBlendOp = rasterState.blendEquationAlpha, .depthCompareOp = rasterState.depthFunc, .depthBiasConstantFactor = depthOffset.constant, - .depthBiasSlopeFactor = depthOffset.slope + .depthBiasSlopeFactor = depthOffset.slope, }; // unfortunately in Vulkan the topology is per pipeline @@ -1735,7 +1736,7 @@ void VulkanDriver::bindPipeline(PipelineState const& pipelineState) { mBoundPipeline = { .program = program, .pipelineLayout = pipelineLayout, - .descriptorSetMask = DescriptorSetMask(descriptorSetMaskTable[layoutCount]), + .descriptorSetMask = fvkutils::DescriptorSetMask(descriptorSetMaskTable[layoutCount]), }; mPipelineCache.bindLayout(pipelineLayout); diff --git a/filament/backend/src/vulkan/VulkanDriver.h b/filament/backend/src/vulkan/VulkanDriver.h index 0d826fca48..1621dc1106 100644 --- a/filament/backend/src/vulkan/VulkanDriver.h +++ b/filament/backend/src/vulkan/VulkanDriver.h @@ -26,12 +26,13 @@ #include "VulkanReadPixels.h" #include "VulkanSamplerCache.h" #include "VulkanStagePool.h" -#include "VulkanUtility.h" +#include "vulkan/caching/VulkanDescriptorSetManager.h" +#include "vulkan/caching/VulkanPipelineLayoutCache.h" +#include "vulkan/memory/ResourceManager.h" +#include "vulkan/memory/ResourcePointer.h" +#include "vulkan/utils/Definitions.h" + #include "backend/DriverEnums.h" -#include "caching/VulkanDescriptorSetManager.h" -#include "caching/VulkanPipelineLayoutCache.h" -#include "memory/ResourceManager.h" -#include "memory/ResourcePointer.h" #include "DriverBase.h" #include "private/backend/Driver.h" @@ -142,13 +143,14 @@ private: struct { resource_ptr program; VkPipelineLayout pipelineLayout; - DescriptorSetMask descriptorSetMask; + fvkutils::DescriptorSetMask descriptorSetMask; } mBoundPipeline = {}; // We need to store information about a render pass to enable better barriers at the end of a // renderpass. struct { - using AttachmentArray = CappedArray; + using AttachmentArray = + fvkutils::StaticVector; AttachmentArray attachments; } mRenderPassFboInfo = {}; diff --git a/filament/backend/src/vulkan/VulkanFboCache.cpp b/filament/backend/src/vulkan/VulkanFboCache.cpp index 3d76424e36..936b6672c2 100644 --- a/filament/backend/src/vulkan/VulkanFboCache.cpp +++ b/filament/backend/src/vulkan/VulkanFboCache.cpp @@ -14,12 +14,12 @@ * limitations under the License. */ -#include "vulkan/VulkanFboCache.h" - -#include +#include "VulkanFboCache.h" #include "VulkanConstants.h" -#include "VulkanUtility.h" +#include "vulkan/utils/Image.h" + +#include // If any VkRenderPass or VkFramebuffer is unused for more than TIME_BEFORE_EVICTION frames, it // is evicted from the cache. @@ -214,7 +214,7 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey const& config) noexcept if (config.colorFormat[i] == VK_FORMAT_UNDEFINED) { continue; } - const VkImageLayout subpassLayout = imgutil::getVkLayout(VulkanLayout::COLOR_ATTACHMENT); + const VkImageLayout subpassLayout = fvkutils::getVkLayout(VulkanLayout::COLOR_ATTACHMENT); uint32_t index; if (!hasSubpasses) { @@ -259,8 +259,8 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey const& config) noexcept .storeOp = (config.usesLazilyAllocatedMemory & (1 << i)) ? kDisableStore : kEnableStore, .stencilLoadOp = kDontCare, .stencilStoreOp = kDisableStore, - .initialLayout = imgutil::getVkLayout(VulkanLayout::COLOR_ATTACHMENT), - .finalLayout = imgutil::getVkLayout(FINAL_COLOR_ATTACHMENT_LAYOUT), + .initialLayout = fvkutils::getVkLayout(VulkanLayout::COLOR_ATTACHMENT), + .finalLayout = fvkutils::getVkLayout(FINAL_COLOR_ATTACHMENT_LAYOUT), }; } @@ -287,7 +287,7 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey const& config) noexcept pResolveAttachment->attachment = attachmentIndex; pResolveAttachment->layout - = imgutil::getVkLayout(VulkanLayout::COLOR_ATTACHMENT_RESOLVE); + = fvkutils::getVkLayout(VulkanLayout::COLOR_ATTACHMENT_RESOLVE); ++pResolveAttachment; attachments[attachmentIndex++] = { @@ -297,8 +297,8 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey const& config) noexcept .storeOp = kEnableStore, .stencilLoadOp = kDontCare, .stencilStoreOp = kDisableStore, - .initialLayout = imgutil::getVkLayout(VulkanLayout::COLOR_ATTACHMENT), - .finalLayout = imgutil::getVkLayout(FINAL_COLOR_ATTACHMENT_LAYOUT), + .initialLayout = fvkutils::getVkLayout(VulkanLayout::COLOR_ATTACHMENT), + .finalLayout = fvkutils::getVkLayout(FINAL_COLOR_ATTACHMENT_LAYOUT), }; } @@ -307,7 +307,7 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey const& config) noexcept const bool clear = any(config.clear & TargetBufferFlags::DEPTH); const bool discardStart = any(config.discardStart & TargetBufferFlags::DEPTH); const bool discardEnd = any(config.discardEnd & TargetBufferFlags::DEPTH); - depthAttachmentRef.layout = imgutil::getVkLayout(VulkanLayout::DEPTH_ATTACHMENT); + depthAttachmentRef.layout = fvkutils::getVkLayout(VulkanLayout::DEPTH_ATTACHMENT); depthAttachmentRef.attachment = attachmentIndex; attachments[attachmentIndex++] = { .format = config.depthFormat, @@ -316,8 +316,8 @@ VkRenderPass VulkanFboCache::getRenderPass(RenderPassKey const& config) noexcept .storeOp = discardEnd ? kDisableStore : kEnableStore, .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .initialLayout = imgutil::getVkLayout(config.initialDepthLayout), - .finalLayout = imgutil::getVkLayout(FINAL_DEPTH_ATTACHMENT_LAYOUT), + .initialLayout = fvkutils::getVkLayout(config.initialDepthLayout), + .finalLayout = fvkutils::getVkLayout(FINAL_DEPTH_ATTACHMENT_LAYOUT), }; } renderPassInfo.attachmentCount = attachmentIndex; diff --git a/filament/backend/src/vulkan/VulkanHandles.cpp b/filament/backend/src/vulkan/VulkanHandles.cpp index 29c33a82b1..3a7ac6b134 100644 --- a/filament/backend/src/vulkan/VulkanHandles.cpp +++ b/filament/backend/src/vulkan/VulkanHandles.cpp @@ -22,9 +22,11 @@ #include "VulkanDriver.h" #include "VulkanMemory.h" -#include "VulkanUtility.h" #include "vulkan/memory/ResourcePointer.h" -#include "spirv/VulkanSpirvUtils.h" +#include "vulkan/utils/Conversion.h" +#include "vulkan/utils/Definitions.h" +#include "vulkan/utils/Image.h" +#include "vulkan/utils/Spirv.h" #include @@ -56,10 +58,10 @@ template inline void fromStageFlags(backend::ShaderStageFlags stage, descriptor_binding_t binding, Bitmask& mask) { if ((bool) (stage & ShaderStageFlags::VERTEX)) { - mask.set(binding + getVertexStageShift()); + mask.set(binding + fvkutils::getVertexStageShift()); } if ((bool) (stage & ShaderStageFlags::FRAGMENT)) { - mask.set(binding + getFragmentStageShift()); + mask.set(binding + fvkutils::getFragmentStageShift()); } } @@ -206,7 +208,7 @@ VulkanProgram::VulkanProgram(VkDevice device, Program const& builder) noexcept size_t dataSize = blob.size(); if (!specializationConstants.empty()) { - workaroundSpecConstant(blob, specializationConstants, shader); + fvkutils::workaroundSpecConstant(blob, specializationConstants, shader); data = (uint32_t*) shader.data(); dataSize = shader.size() * 4; } @@ -314,8 +316,8 @@ VulkanRenderTarget::VulkanRenderTarget(VkDevice device, VkPhysicalDevice physica // Constrain the sample count according to both kinds of sample count masks obtained from // VkPhysicalDeviceProperties. This is consistent with the VulkanTexture constructor. auto const& limits = context.getPhysicalDeviceLimits(); - samples = reduceSampleCount(samples, limits.framebufferDepthSampleCounts & - limits.framebufferColorSampleCounts); + samples = samples = fvkutils::reduceSampleCount(samples, + limits.framebufferDepthSampleCounts & limits.framebufferColorSampleCounts); auto& rpkey = mInfo->rpkey; rpkey.samples = samples; @@ -498,7 +500,7 @@ VulkanVertexBufferInfo::VulkanVertexBufferInfo( Attribute attrib = attributes[attribIndex]; bool const isInteger = attrib.flags & Attribute::FLAG_INTEGER_TARGET; bool const isNormalized = attrib.flags & Attribute::FLAG_NORMALIZED; - VkFormat vkformat = getVkFormat(attrib.type, isNormalized, isInteger); + VkFormat vkformat = fvkutils::getVkFormat(attrib.type, isNormalized, isInteger); // HACK: Re-use the positions buffer as a dummy buffer for disabled attributes. Filament's // vertex shaders declare all attributes as either vec4 or uvec4 (the latter for bone diff --git a/filament/backend/src/vulkan/VulkanHandles.h b/filament/backend/src/vulkan/VulkanHandles.h index 3250985228..f3656ee6de 100644 --- a/filament/backend/src/vulkan/VulkanHandles.h +++ b/filament/backend/src/vulkan/VulkanHandles.h @@ -25,8 +25,9 @@ #include "VulkanFboCache.h" #include "VulkanSwapChain.h" #include "VulkanTexture.h" -#include "VulkanUtility.h" #include "vulkan/memory/Resource.h" +#include "vulkan/utils/StaticVector.h" +#include "vulkan/utils/Definitions.h" #include @@ -44,11 +45,11 @@ namespace { template inline uint8_t collapsedCount(Bitmask const& mask) { static_assert(sizeof(mask) <= 64); - constexpr uint64_t VERTEX_MASK = (1ULL << getFragmentStageShift()) - 1ULL; - constexpr uint64_t FRAGMENT_MASK = (VERTEX_MASK << getFragmentStageShift()); + constexpr uint64_t VERTEX_MASK = (1ULL << fvkutils::getFragmentStageShift()) - 1ULL; + constexpr uint64_t FRAGMENT_MASK = (VERTEX_MASK << fvkutils::getFragmentStageShift()); uint64_t val = mask.getValue(); - val = ((val & VERTEX_MASK) >> getVertexStageShift()) | - ((val & FRAGMENT_MASK) >> getFragmentStageShift()); + val = ((val & VERTEX_MASK) >> fvkutils::getVertexStageShift()) | + ((val & FRAGMENT_MASK) >> fvkutils::getFragmentStageShift()); return (uint8_t) Bitmask(val).count(); } @@ -67,10 +68,10 @@ struct VulkanDescriptorSetLayout : public HwDescriptorSetLayout, fvkmemory::Reso // The bitmask representation of a set layout. struct Bitmask { // TODO: better utiltize the space below and use bitset instead. - UniformBufferBitmask ubo; // 8 bytes - UniformBufferBitmask dynamicUbo; // 8 bytes - SamplerBitmask sampler; // 8 bytes - InputAttachmentBitmask inputAttachment; // 8 bytes + fvkutils::UniformBufferBitmask ubo; // 8 bytes + fvkutils::UniformBufferBitmask dynamicUbo; // 8 bytes + fvkutils::SamplerBitmask sampler; // 8 bytes + fvkutils::InputAttachmentBitmask inputAttachment; // 8 bytes bool operator==(Bitmask const& right) const { return ubo == right.ubo && dynamicUbo == right.dynamicUbo && sampler == right.sampler && @@ -138,7 +139,7 @@ public: using OnRecycle = std::function; VulkanDescriptorSet(VkDescriptorSet rawSet, - UniformBufferBitmask const& dynamicUboMask, + fvkutils::UniformBufferBitmask const& dynamicUboMask, uint8_t uniqueDynamicUboCount, OnRecycle&& onRecycleFn) : vkSet(rawSet), @@ -164,7 +165,7 @@ public: void acquire(fvkmemory::resource_ptr buffer); VkDescriptorSet const vkSet; - UniformBufferBitmask const dynamicUboMask; + fvkutils::UniformBufferBitmask const dynamicUboMask; uint8_t const uniqueDynamicUboCount; private: @@ -193,7 +194,7 @@ private: }; struct VulkanProgram : public HwProgram, fvkmemory::Resource { - using BindingList = CappedArray; + using BindingList = fvkutils::StaticVector; VulkanProgram(VkDevice device, Program const& builder) noexcept; ~VulkanProgram(); diff --git a/filament/backend/src/vulkan/VulkanPipelineCache.cpp b/filament/backend/src/vulkan/VulkanPipelineCache.cpp index 8f6e5df8de..e7fc0431c7 100644 --- a/filament/backend/src/vulkan/VulkanPipelineCache.cpp +++ b/filament/backend/src/vulkan/VulkanPipelineCache.cpp @@ -24,7 +24,7 @@ #include "VulkanConstants.h" #include "VulkanHandles.h" #include "VulkanTexture.h" -#include "VulkanUtility.h" +#include "vulkan/utils/Conversion.h" #if defined(__clang__) // Vulkan functions often immediately dereference pointers, so it's fine to pass in a pointer @@ -196,7 +196,7 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::createPipeline() n vkDs.depthTestEnable = VK_TRUE; vkDs.depthWriteEnable = raster.depthWriteEnable; - vkDs.depthCompareOp = getCompareOp(raster.depthCompareOp); + vkDs.depthCompareOp = fvkutils::getCompareOp(raster.depthCompareOp); vkDs.depthBoundsTestEnable = VK_FALSE; vkDs.stencilTestEnable = VK_FALSE; vkDs.minDepthBounds = 0.0f; diff --git a/filament/backend/src/vulkan/VulkanPipelineCache.h b/filament/backend/src/vulkan/VulkanPipelineCache.h index a4a6e28c38..a3f372fb25 100644 --- a/filament/backend/src/vulkan/VulkanPipelineCache.h +++ b/filament/backend/src/vulkan/VulkanPipelineCache.h @@ -19,7 +19,6 @@ #include "VulkanCommands.h" #include "VulkanMemory.h" -#include "VulkanUtility.h" #include #include diff --git a/filament/backend/src/vulkan/VulkanReadPixels.cpp b/filament/backend/src/vulkan/VulkanReadPixels.cpp index 48df6c7222..7e7008ab14 100644 --- a/filament/backend/src/vulkan/VulkanReadPixels.cpp +++ b/filament/backend/src/vulkan/VulkanReadPixels.cpp @@ -19,8 +19,9 @@ #include "DataReshaper.h" #include "VulkanCommands.h" #include "VulkanHandles.h" -#include "VulkanImageUtility.h" #include "VulkanTexture.h" +#include "vulkan/utils/Conversion.h" // getComponentType() +#include "vulkan/utils/Image.h" #include @@ -218,7 +219,7 @@ void VulkanReadPixels::run(fvkmemory::resource_ptr srcTarget }; vkBeginCommandBuffer(cmdbuffer, &binfo); - imgutil::transitionLayout(cmdbuffer, { + fvkutils::transitionLayout(cmdbuffer, { .image = stagingImage, .oldLayout = VulkanLayout::UNDEFINED, .newLayout = VulkanLayout::TRANSFER_DST, @@ -265,8 +266,8 @@ void VulkanReadPixels::run(fvkmemory::resource_ptr srcTarget imageCopyRegion.srcOffset.y + imageCopyRegion.extent.height <= srcExtent.height); vkCmdCopyImage(cmdbuffer, srcAttachment.getImage(), - imgutil::getVkLayout(VulkanLayout::TRANSFER_SRC), stagingImage, - imgutil::getVkLayout(VulkanLayout::TRANSFER_DST), 1, &imageCopyRegion); + fvkutils::getVkLayout(VulkanLayout::TRANSFER_SRC), stagingImage, + fvkutils::getVkLayout(VulkanLayout::TRANSFER_DST), 1, &imageCopyRegion); // Restore the source image layout. srcTexture->transitionLayout(cmdbuffer, srcRange, srcTexture->getDefaultLayout()); @@ -318,8 +319,8 @@ void VulkanReadPixels::run(fvkmemory::resource_ptr srcTarget vkMapMemory(device, stagingMemory, 0, VK_WHOLE_SIZE, 0, (void**) &srcPixels); srcPixels += subResourceLayout.offset; - if (!DataReshaper::reshapeImage(&p, getComponentType(srcFormat), - getComponentCount(srcFormat), srcPixels, + if (!DataReshaper::reshapeImage(&p, fvkutils::getComponentType(srcFormat), + fvkutils::getComponentCount(srcFormat), srcPixels, static_cast(subResourceLayout.rowPitch), static_cast(width), static_cast(height), swizzle)) { FVK_LOGE << "Unsupported PixelDataFormat or PixelDataType" << utils::io::endl; diff --git a/filament/backend/src/vulkan/VulkanSamplerCache.cpp b/filament/backend/src/vulkan/VulkanSamplerCache.cpp index 75a2578e75..005c16c525 100644 --- a/filament/backend/src/vulkan/VulkanSamplerCache.cpp +++ b/filament/backend/src/vulkan/VulkanSamplerCache.cpp @@ -15,6 +15,7 @@ */ #include "vulkan/VulkanSamplerCache.h" +#include "vulkan/utils/Conversion.h" #include @@ -114,7 +115,7 @@ VkSampler VulkanSamplerCache::getSampler(SamplerParams params) noexcept { .anisotropyEnable = params.anisotropyLog2 == 0 ? 0u : 1u, .maxAnisotropy = (float)(1u << params.anisotropyLog2), .compareEnable = getCompareEnable(params.compareMode), - .compareOp = getCompareOp(params.compareFunc), + .compareOp = fvkutils::getCompareOp(params.compareFunc), .minLod = 0.0f, .maxLod = getMaxLod(params.filterMin), .borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK, diff --git a/filament/backend/src/vulkan/VulkanSamplerCache.h b/filament/backend/src/vulkan/VulkanSamplerCache.h index cb5fe43ce4..31e902c582 100644 --- a/filament/backend/src/vulkan/VulkanSamplerCache.h +++ b/filament/backend/src/vulkan/VulkanSamplerCache.h @@ -18,7 +18,6 @@ #define TNT_FILAMENT_BACKEND_VULKANSAMPLERCACHE_H #include "VulkanContext.h" -#include "VulkanUtility.h" #include diff --git a/filament/backend/src/vulkan/VulkanStagePool.cpp b/filament/backend/src/vulkan/VulkanStagePool.cpp index cae1e85d25..02e0f0eab1 100644 --- a/filament/backend/src/vulkan/VulkanStagePool.cpp +++ b/filament/backend/src/vulkan/VulkanStagePool.cpp @@ -18,9 +18,9 @@ #include "VulkanCommands.h" #include "VulkanConstants.h" -#include "VulkanImageUtility.h" #include "VulkanMemory.h" -#include "VulkanUtility.h" +#include "vulkan/utils/Conversion.h" +#include "vulkan/utils/Image.h" #include @@ -72,7 +72,7 @@ VulkanStage const* VulkanStagePool::acquireStage(uint32_t numBytes) { VulkanStageImage const* VulkanStagePool::acquireImage(PixelDataFormat format, PixelDataType type, uint32_t width, uint32_t height) { - const VkFormat vkformat = getVkFormat(format, type); + const VkFormat vkformat = fvkutils::getVkFormat(format, type); for (auto image : mFreeImages) { if (image->format == vkformat && image->width == width && image->height == height) { mFreeImages.erase(image); @@ -113,7 +113,7 @@ VulkanStageImage const* VulkanStagePool::acquireImage(PixelDataFormat format, Pi assert_invariant(result == VK_SUCCESS); - VkImageAspectFlags const aspectFlags = getImageAspect(vkformat); + VkImageAspectFlags const aspectFlags = fvkutils::getImageAspect(vkformat); VkCommandBuffer const cmdbuffer = mCommands->get().buffer(); // We use VK_IMAGE_LAYOUT_GENERAL here because the spec says: @@ -122,7 +122,7 @@ VulkanStageImage const* VulkanStagePool::acquireImage(PixelDataFormat format, Pi // VK_IMAGE_LAYOUT_PREINITIALIZED or VK_IMAGE_LAYOUT_GENERAL layout. Calling // vkGetImageSubresourceLayout for a linear image returns a subresource layout mapping that is // valid for either of those image layouts." - imgutil::transitionLayout(cmdbuffer, { + fvkutils::transitionLayout(cmdbuffer, { .image = image->image, .oldLayout = VulkanLayout::UNDEFINED, .newLayout = VulkanLayout::READ_WRITE, // (= VK_IMAGE_LAYOUT_GENERAL) diff --git a/filament/backend/src/vulkan/VulkanTexture.cpp b/filament/backend/src/vulkan/VulkanTexture.cpp index 2f30ee20c9..ff3f4f9a2b 100644 --- a/filament/backend/src/vulkan/VulkanTexture.cpp +++ b/filament/backend/src/vulkan/VulkanTexture.cpp @@ -17,8 +17,8 @@ #include "VulkanCommands.h" #include "VulkanMemory.h" #include "VulkanTexture.h" -#include "VulkanUtility.h" #include "vulkan/memory/ResourcePointer.h" +#include "vulkan/utils/Conversion.h" #include #include @@ -152,7 +152,7 @@ VulkanTextureState::VulkanTextureState(VkDevice device, VmaAllocator allocator, bool isProtected) : mVkFormat(format), mViewType(viewType), - mFullViewRange{filament::backend::getImageAspect(format), 0, levels, 0, layerCount}, + mFullViewRange{fvkutils::getImageAspect(format), 0, levels, 0, layerCount}, mDefaultLayout(defaultLayout), mIsProtected(isProtected), mStagePool(stagePool), @@ -169,7 +169,7 @@ VulkanTexture::VulkanTexture(VkDevice device, VmaAllocator allocator, : HwTexture(SamplerType::SAMPLER_2D, 1, samples, width, height, 1, TextureFormat::UNUSED, tusage), mState(fvkmemory::resource_ptr::construct(resourceManager, device, - allocator, commands, stagePool, format, imgutil::getViewType(SamplerType::SAMPLER_2D), + allocator, commands, stagePool, format, fvkutils::getViewType(SamplerType::SAMPLER_2D), 1, 1, getDefaultLayoutImpl(tusage), any(usage & TextureUsage::PROTECTED))) { mState->mTextureImage = image; mState->mTextureImageMemory = memory; @@ -183,9 +183,10 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice, uint8_t levels, TextureFormat tformat, uint8_t samples, uint32_t w, uint32_t h, uint32_t depth, TextureUsage tusage, VulkanStagePool& stagePool) : HwTexture(target, levels, samples, w, h, depth, tformat, tusage), + mState(fvkmemory::resource_ptr::construct(resourceManager, device, - allocator, commands, stagePool, backend::getVkFormat(tformat), - imgutil::getViewType(target), levels, getLayerCount(target, depth), + allocator, commands, stagePool, fvkutils::getVkFormat(tformat), + fvkutils::getViewType(target), levels, getLayerCount(target, depth), VulkanLayout::UNDEFINED, any(usage & TextureUsage::PROTECTED))) { // Create an appropriately-sized device-only VkImage, but do not fill it yet. VkImageCreateInfo imageInfo{ @@ -281,16 +282,17 @@ VulkanTexture::VulkanTexture(VkDevice device, VkPhysicalDevice physicalDevice, // any kind of attachment (color or depth). const auto& limits = context.getPhysicalDeviceLimits(); if (imageInfo.usage & VK_IMAGE_USAGE_SAMPLED_BIT) { - samples = reduceSampleCount(samples, isVkDepthFormat(mState->mVkFormat) - ? limits.sampledImageDepthSampleCounts - : limits.sampledImageColorSampleCounts); + samples = fvkutils::reduceSampleCount(samples, + fvkutils::isVkDepthFormat(mState->mVkFormat) + ? limits.sampledImageDepthSampleCounts + : limits.sampledImageColorSampleCounts); } if (imageInfo.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) { - samples = reduceSampleCount(samples, limits.framebufferColorSampleCounts); + samples = fvkutils::reduceSampleCount(samples, limits.framebufferColorSampleCounts); } if (imageInfo.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - samples = reduceSampleCount(samples, limits.sampledImageDepthSampleCounts); + samples = fvkutils::reduceSampleCount(samples, limits.sampledImageDepthSampleCounts); } this->samples = samples; imageInfo.samples = (VkSampleCountFlagBits) samples; @@ -401,8 +403,8 @@ void VulkanTexture::updateImage(const PixelBufferDescriptor& data, uint32_t widt } // If format conversion is both required and supported, use vkCmdBlitImage. - const VkFormat hostFormat = backend::getVkFormat(hostData->format, hostData->type); - const VkFormat deviceFormat = getVkFormatLinear(mState->mVkFormat); + const VkFormat hostFormat = fvkutils::getVkFormat(hostData->format, hostData->type); + const VkFormat deviceFormat = fvkutils::getVkFormatLinear(mState->mVkFormat); if (hostFormat != deviceFormat && hostFormat != VK_FORMAT_UNDEFINED) { assert_invariant(xoffset == 0 && yoffset == 0 && zoffset == 0 && "Offsets not yet supported when format conversion is required."); @@ -461,7 +463,7 @@ void VulkanTexture::updateImage(const PixelBufferDescriptor& data, uint32_t widt VulkanLayout const newLayout = VulkanLayout::TRANSFER_DST; VulkanLayout nextLayout = getLayout(transitionRange.baseArrayLayer, miplevel); - VkImageLayout const newVkLayout = imgutil::getVkLayout(newLayout); + VkImageLayout const newVkLayout = fvkutils::getVkLayout(newLayout); if (nextLayout == VulkanLayout::UNDEFINED) { nextLayout = getDefaultLayout(); @@ -508,8 +510,8 @@ void VulkanTexture::updateImageWithBlit(const PixelBufferDescriptor& hostData, u VulkanLayout const oldLayout = getLayout(layer, miplevel); transitionLayout(&commands, range, newLayout); - vkCmdBlitImage(cmdbuf, stage->image, imgutil::getVkLayout(VulkanLayout::TRANSFER_SRC), - mState->mTextureImage, imgutil::getVkLayout(newLayout), 1, blitRegions, VK_FILTER_NEAREST); + vkCmdBlitImage(cmdbuf, stage->image, fvkutils::getVkLayout(VulkanLayout::TRANSFER_SRC), + mState->mTextureImage, fvkutils::getVkLayout(newLayout), 1, blitRegions, VK_FILTER_NEAREST); transitionLayout(&commands, range, oldLayout); } @@ -557,7 +559,7 @@ VkImageView VulkanTexture::getImageView(VkImageSubresourceRange range, VkImageVi VkImageAspectFlags VulkanTexture::getImageAspect() const { // Helper function in VulkanUtility - return filament::backend::getImageAspect(mState->mVkFormat); + return fvkutils::getImageAspect(mState->mVkFormat); } bool VulkanTexture::transitionLayout(VulkanCommandBuffer* commands, @@ -600,7 +602,7 @@ bool VulkanTexture::transitionLayout(VkCommandBuffer cmdbuf, VkImageSubresourceR if (layout == newLayout) { continue; } - hasTransitions = hasTransitions || imgutil::transitionLayout(cmdbuf, { + hasTransitions = hasTransitions || fvkutils::transitionLayout(cmdbuf, { .image = mState->mTextureImage, .oldLayout = layout, .newLayout = newLayout, @@ -615,7 +617,7 @@ bool VulkanTexture::transitionLayout(VkCommandBuffer cmdbuf, VkImageSubresourceR } } } else if (newLayout != oldLayout) { - hasTransitions = imgutil::transitionLayout(cmdbuf, { + hasTransitions = fvkutils::transitionLayout(cmdbuf, { .image = mState->mTextureImage, .oldLayout = oldLayout, .newLayout = newLayout, @@ -650,7 +652,7 @@ void VulkanTexture::samplerToAttachmentBarrier(VulkanCommandBuffer* commands, VkImageSubresourceRange const& range) { VkCommandBuffer const cmdbuf = commands->buffer(); VkImageLayout const layout = - imgutil::getVkLayout(getLayout(range.baseArrayLayer, range.baseMipLevel)); + fvkutils::getVkLayout(getLayout(range.baseArrayLayer, range.baseMipLevel)); VkImageMemoryBarrier barrier = { .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .srcAccessMask = VK_ACCESS_SHADER_READ_BIT, @@ -673,7 +675,7 @@ void VulkanTexture::attachmentToSamplerBarrier(VulkanCommandBuffer* commands, VkImageSubresourceRange const& range) { VkCommandBuffer const cmdbuf = commands->buffer(); VkImageLayout const layout - = imgutil::getVkLayout(getLayout(range.baseArrayLayer, range.baseMipLevel)); + = fvkutils::getVkLayout(getLayout(range.baseArrayLayer, range.baseMipLevel)); VkImageMemoryBarrier barrier = { .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, diff --git a/filament/backend/src/vulkan/VulkanTexture.h b/filament/backend/src/vulkan/VulkanTexture.h index 1889adf121..7f1cfe4e42 100644 --- a/filament/backend/src/vulkan/VulkanTexture.h +++ b/filament/backend/src/vulkan/VulkanTexture.h @@ -20,9 +20,9 @@ #include "DriverBase.h" #include "VulkanBuffer.h" -#include "VulkanImageUtility.h" #include "vulkan/memory/Resource.h" #include "vulkan/memory/ResourcePointer.h" +#include "vulkan/utils/Image.h" #include #include diff --git a/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.cpp b/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.cpp index 19aa989b8c..570dcc5df2 100644 --- a/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.cpp +++ b/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.cpp @@ -16,11 +16,10 @@ #include "VulkanDescriptorSetManager.h" -#include -#include -#include -#include -#include +#include "vulkan/VulkanCommands.h" +#include "vulkan/VulkanHandles.h" +#include "vulkan/VulkanConstants.h" + #include #include @@ -207,17 +206,17 @@ uint32_t createBindings(VkDescriptorSetLayoutBinding* toBind, uint32_t count, Vk mask.forEachSetBit([&](size_t index) { VkShaderStageFlags stages = 0; uint32_t binding = 0; - if (index < getFragmentStageShift()) { + if (index < fvkutils::getFragmentStageShift()) { binding = (uint32_t) index; stages |= VK_SHADER_STAGE_VERTEX_BIT; - auto fragIndex = index + getFragmentStageShift(); + auto fragIndex = index + fvkutils::getFragmentStageShift(); if (mask.test(fragIndex)) { stages |= VK_SHADER_STAGE_FRAGMENT_BIT; alreadySeen.set(fragIndex); } } else if (!alreadySeen.test(index)) { // We are in fragment stage bits - binding = (uint32_t) (index - getFragmentStageShift()); + binding = (uint32_t) (index - fvkutils::getFragmentStageShift()); stages |= VK_SHADER_STAGE_FRAGMENT_BIT; } @@ -346,7 +345,6 @@ private: mVkLayouts; }; - VulkanDescriptorSetManager::VulkanDescriptorSetManager(VkDevice device, fvkmemory::ResourceManager* resourceManager) : mDevice(device), @@ -376,10 +374,10 @@ void VulkanDescriptorSetManager::unbind(uint8_t setIndex) { } void VulkanDescriptorSetManager::commit(VulkanCommandBuffer* commands, - VkPipelineLayout pipelineLayout, DescriptorSetMask const& setMask) { + VkPipelineLayout pipelineLayout, fvkutils::DescriptorSetMask const& setMask) { // setMask indicates the set of descriptor sets the driver wants to bind, curMask is the // actual set of sets that *needs* to be bound. - DescriptorSetMask curMask = setMask; + fvkutils::DescriptorSetMask curMask = setMask; auto& updateSets = mStashedSets; auto& lastBoundSets = mLastBoundInfo.boundSets; @@ -458,7 +456,7 @@ void VulkanDescriptorSetManager::updateSampler(fvkmemory::resource_ptrgetViewForType(range, expectedType); } - info.imageLayout = imgutil::getVkLayout(texture->getDefaultLayout()); + info.imageLayout = fvkutils::getVkLayout(texture->getDefaultLayout()); VkWriteDescriptorSet const descriptorWrite = { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .pNext = nullptr, diff --git a/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.h b/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.h index faeeb14420..87aa076213 100644 --- a/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.h +++ b/filament/backend/src/vulkan/caching/VulkanDescriptorSetManager.h @@ -18,9 +18,8 @@ #define TNT_FILAMENT_BACKEND_CACHING_VULKANDESCRIPTORSETMANAGER_H #include "vulkan/VulkanHandles.h" -#include "vulkan/VulkanTexture.h" -#include "vulkan/VulkanUtility.h" #include "vulkan/memory/ResourcePointer.h" +#include "vulkan/utils/Definitions.h" // For DescriptorSetMask #include #include @@ -68,7 +67,7 @@ public: void unbind(uint8_t setIndex); void commit(VulkanCommandBuffer* commands, VkPipelineLayout pipelineLayout, - DescriptorSetMask const& setMask); + fvkutils::DescriptorSetMask const& setMask); fvkmemory::resource_ptr createSet(Handle handle, fvkmemory::resource_ptr layout); @@ -93,7 +92,7 @@ private: struct { VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; - DescriptorSetMask setMask; + fvkutils::DescriptorSetMask setMask; DescriptorSetArray boundSets = {}; } mLastBoundInfo; }; diff --git a/filament/backend/src/vulkan/platform/VulkanPlatform.cpp b/filament/backend/src/vulkan/platform/VulkanPlatform.cpp index e20ae0270c..c76a1a08dd 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatform.cpp +++ b/filament/backend/src/vulkan/platform/VulkanPlatform.cpp @@ -21,7 +21,7 @@ #include "vulkan/platform/VulkanPlatformSwapChainImpl.h" #include "vulkan/VulkanConstants.h" #include "vulkan/VulkanDriver.h" -#include "vulkan/VulkanUtility.h" +#include "vulkan/utils/Helper.h" #include #include @@ -126,7 +126,7 @@ void printDeviceInfo(VkInstance instance, VkPhysicalDevice device) { const int minor = VK_VERSION_MINOR(deviceProperties.apiVersion); const FixedCapacityVector physicalDevices - = filament::backend::enumerate(vkEnumeratePhysicalDevices, instance); + = fvkutils::enumerate(vkEnumeratePhysicalDevices, instance); FVK_LOGI << "Selected physical device '" << deviceProperties.deviceName << "' from " << physicalDevices.size() << " physical devices. " @@ -172,7 +172,7 @@ ExtensionSet getInstanceExtensions(ExtensionSet const& externallyRequiredExts = }; ExtensionSet exts; FixedCapacityVector const availableExts = - filament::backend::enumerate(vkEnumerateInstanceExtensionProperties, + fvkutils::enumerate(vkEnumerateInstanceExtensionProperties, static_cast(nullptr) /* pLayerName */); for (auto const& extProps: availableExts) { utils::CString name { extProps.extensionName }; @@ -212,7 +212,7 @@ ExtensionSet getDeviceExtensions(VkPhysicalDevice device) { ExtensionSet exts; // Identify supported physical device extensions FixedCapacityVector const extensions - = filament::backend::enumerate(vkEnumerateDeviceExtensionProperties, device, + = fvkutils::enumerate(vkEnumerateDeviceExtensionProperties, device, static_cast(nullptr) /* pLayerName */); for (auto const& extension: extensions) { utils::CString name { extension.extensionName }; @@ -473,7 +473,7 @@ inline int deviceTypeOrder(VkPhysicalDeviceType deviceType) { VkPhysicalDevice selectPhysicalDevice(VkInstance instance, VulkanPlatform::Customization::GPUPreference const& gpuPreference) { FixedCapacityVector const physicalDevices = - filament::backend::enumerate(vkEnumeratePhysicalDevices, instance); + fvkutils::enumerate(vkEnumeratePhysicalDevices, instance); struct DeviceInfo { VkPhysicalDevice device = VK_NULL_HANDLE; VkPhysicalDeviceType deviceType = VK_PHYSICAL_DEVICE_TYPE_OTHER; @@ -508,7 +508,7 @@ VkPhysicalDevice selectPhysicalDevice(VkInstance instance, // Does the device support the VK_KHR_swapchain extension? FixedCapacityVector const extensions - = filament::backend::enumerate(vkEnumerateDeviceExtensionProperties, + = fvkutils::enumerate(vkEnumerateDeviceExtensionProperties, candidateDevice, static_cast(nullptr) /* pLayerName */); bool supportsSwapchain = false; for (auto const& extension: extensions) { @@ -560,7 +560,7 @@ VkPhysicalDevice selectPhysicalDevice(VkInstance instance, return device; } -VkFormatList findAttachmentDepthStencilFormats(VkPhysicalDevice device) { +fvkutils::VkFormatList findAttachmentDepthStencilFormats(VkPhysicalDevice device) { VkFormatFeatureFlags const features = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; // The ordering here indicates the preference of choosing depth+stencil format. @@ -579,17 +579,17 @@ VkFormatList findAttachmentDepthStencilFormats(VkPhysicalDevice device) { selectedFormats.push_back(format); } } - VkFormatList ret(selectedFormats.size()); + fvkutils::VkFormatList ret(selectedFormats.size()); std::copy(selectedFormats.begin(), selectedFormats.end(), ret.begin()); return ret; } -VkFormatList findBlittableDepthStencilFormats(VkPhysicalDevice device) { +fvkutils::VkFormatList findBlittableDepthStencilFormats(VkPhysicalDevice device) { std::vector selectedFormats; VkFormatFeatureFlags const required = VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT; - for (VkFormat format : ALL_VK_FORMATS) { - if (isVkDepthFormat(format)) { + for (VkFormat format : fvkutils::ALL_VK_FORMATS) { + if (fvkutils::isVkDepthFormat(format)) { VkFormatProperties props; vkGetPhysicalDeviceFormatProperties(device, format, &props); if ((props.optimalTilingFeatures & required) == required) { @@ -597,7 +597,7 @@ VkFormatList findBlittableDepthStencilFormats(VkPhysicalDevice device) { } } } - VkFormatList ret(selectedFormats.size()); + fvkutils::VkFormatList ret(selectedFormats.size()); std::copy(selectedFormats.begin(), selectedFormats.end(), ret.begin()); return ret; } diff --git a/filament/backend/src/vulkan/platform/VulkanPlatformAndroid.cpp b/filament/backend/src/vulkan/platform/VulkanPlatformAndroid.cpp index 0ea9df5fa4..268f2a4d02 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatformAndroid.cpp +++ b/filament/backend/src/vulkan/platform/VulkanPlatformAndroid.cpp @@ -199,7 +199,6 @@ VulkanPlatform::ExternalImageMetadata VulkanPlatform::getExternalImageMetadataIm FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "vkGetAndroidHardwareBufferProperties failed with error=" << static_cast(result); - FILAMENT_CHECK_POSTCONDITION(metadata.format == formatInfo.format) << "mismatched image format for external image (AHB)"; metadata.externalFormat = formatInfo.externalFormat; diff --git a/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.cpp b/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.cpp index cb80e48985..921b8c56eb 100644 --- a/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.cpp +++ b/filament/backend/src/vulkan/platform/VulkanPlatformSwapChainImpl.cpp @@ -17,7 +17,9 @@ #include "VulkanPlatformSwapChainImpl.h" #include "vulkan/VulkanConstants.h" -#include "vulkan/VulkanUtility.h" +#include "vulkan/utils/Definitions.h" +#include "vulkan/utils/Helper.h" +#include "vulkan/utils/Image.h" #include @@ -29,9 +31,8 @@ namespace filament::backend { namespace { std::tuple createImageAndMemory(VulkanContext const& context, - VkDevice device, VkExtent2D extent, VkFormat format, - bool isProtected) { - bool const isDepth = isVkDepthFormat(format); + VkDevice device, VkExtent2D extent, VkFormat format, bool isProtected) { + bool const isDepth = fvkutils::isVkDepthFormat(format); // Filament expects blit() to work with any texture, so we almost always set these usage flags // (see copyFrame() and readPixels()). VkImageUsageFlags const blittable = @@ -83,9 +84,9 @@ std::tuple createImageAndMemory(VulkanContext const& co return std::tuple(image, imageMemory); } -VkFormat selectDepthFormat(VkFormatList const& depthFormats, bool hasStencil) { +VkFormat selectDepthFormat(fvkutils::VkFormatList const& depthFormats, bool hasStencil) { auto const formatItr = std::find_if(depthFormats.begin(), depthFormats.end(), - hasStencil ? isVkStencilFormat : isVkDepthFormat); + hasStencil ? fvkutils::isVkStencilFormat : fvkutils::isVkDepthFormat); assert_invariant( formatItr != depthFormats.end() && "Cannot find suitable swapchain depth format"); return *formatItr; @@ -169,7 +170,7 @@ VkResult VulkanPlatformSurfaceSwapChain::create() { // Find a suitable surface format. FixedCapacityVector const surfaceFormats - = enumerate(vkGetPhysicalDeviceSurfaceFormatsKHR, mPhysicalDevice, mSurface); + = fvkutils::enumerate(vkGetPhysicalDeviceSurfaceFormatsKHR, mPhysicalDevice, mSurface); std::array expectedFormats = { VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM, @@ -193,8 +194,8 @@ VkResult VulkanPlatformSurfaceSwapChain::create() { // Verify that our chosen present mode is supported. In practice all devices support the FIFO // mode, but we check for it anyway for completeness. (and to avoid validation warnings) VkPresentModeKHR const desiredPresentMode = VK_PRESENT_MODE_FIFO_KHR; - FixedCapacityVector presentModes - = enumerate(vkGetPhysicalDeviceSurfacePresentModesKHR, mPhysicalDevice, mSurface); + FixedCapacityVector presentModes = fvkutils::enumerate( + vkGetPhysicalDeviceSurfacePresentModesKHR, mPhysicalDevice, mSurface); bool foundSuitablePresentMode = false; for (VkPresentModeKHR mode: presentModes) { if (mode == desiredPresentMode) { @@ -251,7 +252,7 @@ VkResult VulkanPlatformSurfaceSwapChain::create() { FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "vkCreateSwapchainKHR failed." << " error=" << static_cast(result); - mSwapChainBundle.colors = enumerate(vkGetSwapchainImagesKHR, mDevice, mSwapchain); + mSwapChainBundle.colors = fvkutils::enumerate(vkGetSwapchainImagesKHR, mDevice, mSwapchain); mSwapChainBundle.colorFormat = surfaceFormat.format; mSwapChainBundle.depthFormat = selectDepthFormat(mContext.getAttachmentDepthStencilFormats(), mHasStencil); @@ -329,7 +330,7 @@ bool VulkanPlatformSurfaceSwapChain::hasResized() { || perceivedExtent.height == VULKAN_UNDEFINED_EXTENT) { perceivedExtent = mFallbackExtent; } - return !equivalent(mSwapChainBundle.extent, perceivedExtent); + return !fvkutils::equivalent(mSwapChainBundle.extent, perceivedExtent); } bool VulkanPlatformSurfaceSwapChain::isProtected() { diff --git a/filament/backend/src/vulkan/VulkanUtility.cpp b/filament/backend/src/vulkan/utils/Conversion.cpp similarity index 92% rename from filament/backend/src/vulkan/VulkanUtility.cpp rename to filament/backend/src/vulkan/utils/Conversion.cpp index 889e2bdd2f..1d1f9d1c0f 100644 --- a/filament/backend/src/vulkan/VulkanUtility.cpp +++ b/filament/backend/src/vulkan/utils/Conversion.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2024 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. @@ -14,17 +14,13 @@ * limitations under the License. */ -#include "VulkanUtility.h" +#include "vulkan/utils/Conversion.h" -#include -#include #include #include "private/backend/BackendUtils.h" -using namespace bluevk; - -namespace filament::backend { +namespace filament::backend::fvkutils { VkFormat getVkFormat(ElementType type, bool normalized, bool integer) { using ElementType = ElementType; @@ -235,12 +231,6 @@ VkFormat getVkFormat(TextureFormat format) { } } -// Converts PixelBufferDescriptor format + type pair into a VkFormat. -// -// NOTE: This function only returns formats that support VK_FORMAT_FEATURE_BLIT_SRC_BIT as per -// "Required Format Support" in the Vulkan specification. These are the only formats that can be -// used for format conversion. If the requested format does not support this feature, then -// VK_FORMAT_UNDEFINED is returned. VkFormat getVkFormat(PixelDataFormat format, PixelDataType type) { if (type == PixelDataType::USHORT_565) return VK_FORMAT_R5G6B5_UNORM_PACK16; if (type == PixelDataType::UINT_2_10_10_10_REV) return VK_FORMAT_A2B10G10R10_UNORM_PACK32; @@ -284,10 +274,6 @@ VkFormat getVkFormat(PixelDataFormat format, PixelDataType type) { return VK_FORMAT_UNDEFINED; } -// Converts an SRGB Vulkan format identifier into its corresponding canonical UNORM format. If the -// given format is not an SRGB format, it is returned unmodified. This function is useful when -// determining if blit-based conversion is needed, since SRGB is orthogonal to the actual bit layout -// of color components. VkFormat getVkFormatLinear(VkFormat format) { switch (format) { case VK_FORMAT_R8_SRGB: return VK_FORMAT_R8_UNORM; @@ -328,8 +314,6 @@ VkFormat getVkFormatLinear(VkFormat format) { return format; } -// See also FTexture::computeTextureDataSize, which takes a public-facing Texture format rather -// than a driver-level Texture format, and can account for a specified byte alignment. uint32_t getBytesPerPixel(TextureFormat format) { return (uint32_t) getFormatSize(format); } @@ -611,48 +595,4 @@ VkShaderStageFlags getShaderStageFlags(ShaderStageFlags stageFlags) { return flags; } -bool equivalent(const VkRect2D& a, const VkRect2D& b) { - // These are all integers so there's no need for an epsilon. - return a.extent.width == b.extent.width && a.extent.height == b.extent.height && - a.offset.x == b.offset.x && a.offset.y == b.offset.y; -} - -bool equivalent(const VkExtent2D& a, const VkExtent2D& b) { - return a.height == b.height && a.width == b.width; -} - -VkImageAspectFlags getImageAspect(VkFormat format) { - switch (format) { - case VK_FORMAT_D16_UNORM_S8_UINT: - case VK_FORMAT_D24_UNORM_S8_UINT: - case VK_FORMAT_D32_SFLOAT_S8_UINT: - return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - case VK_FORMAT_D16_UNORM: - case VK_FORMAT_X8_D24_UNORM_PACK32: - case VK_FORMAT_D32_SFLOAT: - return VK_IMAGE_ASPECT_DEPTH_BIT; - case VK_FORMAT_S8_UINT: - return VK_IMAGE_ASPECT_STENCIL_BIT; - default: - return VK_IMAGE_ASPECT_COLOR_BIT; - } -} - -bool isVkDepthFormat(VkFormat format) { - return (getImageAspect(format) & VK_IMAGE_ASPECT_DEPTH_BIT) != 0; -} - -bool isVkStencilFormat(VkFormat format) { - return (getImageAspect(format) & VK_IMAGE_ASPECT_STENCIL_BIT) != 0; -} - -static uint32_t mostSignificantBit(uint32_t x) { return 1ul << (31ul - utils::clz(x)); } - -uint8_t reduceSampleCount(uint8_t sampleCount, VkSampleCountFlags mask) { - if (sampleCount & mask) { - return sampleCount; - } - return mostSignificantBit((sampleCount - 1) & mask); -} - -} // namespace filament::backend +} // namespace filament::backend::fvkutils diff --git a/filament/backend/src/vulkan/utils/Conversion.h b/filament/backend/src/vulkan/utils/Conversion.h new file mode 100644 index 0000000000..10f5b5ad0d --- /dev/null +++ b/filament/backend/src/vulkan/utils/Conversion.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2024 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_VULKAN_UTILS_CONVERSION_H +#define TNT_FILAMENT_BACKEND_VULKAN_UTILS_CONVERSION_H + +#include + +#include // for getFormatSize() + +#include + +// Methods for converting Filament types to Vulkan types + +namespace filament::backend::fvkutils { + +VkFormat getVkFormat(ElementType type, bool normalized, bool integer); +VkFormat getVkFormat(TextureFormat format); + +// Converts PixelBufferDescriptor format + type pair into a VkFormat. +// NOTE: This function only returns formats that support VK_FORMAT_FEATURE_BLIT_SRC_BIT as per +// "Required Format Support" in the Vulkan specification. These are the only formats that can be +// used for format conversion. If the requested format does not support this feature, then +// VK_FORMAT_UNDEFINED is returned. +VkFormat getVkFormat(PixelDataFormat format, PixelDataType type); + +// Converts an SRGB Vulkan format identifier into its corresponding canonical UNORM format. If the +// given format is not an SRGB format, it is returned unmodified. This function is useful when +// determining if blit-based conversion is needed, since SRGB is orthogonal to the actual bit layout +// of color components. +VkFormat getVkFormatLinear(VkFormat format); + +// See also FTexture::computeTextureDataSize, which takes a public-facing Texture format rather +// than a driver-level Texture format, and can account for a specified byte alignment. +uint32_t getBytesPerPixel(TextureFormat format); + +VkCompareOp getCompareOp(SamplerCompareFunc func); +VkBlendFactor getBlendFactor(BlendFunction mode); +VkCullModeFlags getCullMode(CullingMode mode); +VkFrontFace getFrontFace(bool inverseFrontFaces); +PixelDataType getComponentType(VkFormat format); +uint32_t getComponentCount(VkFormat format); +VkComponentMapping getSwizzleMap(TextureSwizzle const swizzle[4]); +VkShaderStageFlags getShaderStageFlags(ShaderStageFlags stageFlags); + +inline VkImageViewType getViewType(SamplerType target) { + switch (target) { + case SamplerType::SAMPLER_CUBEMAP: + return VK_IMAGE_VIEW_TYPE_CUBE; + case SamplerType::SAMPLER_2D_ARRAY: + return VK_IMAGE_VIEW_TYPE_2D_ARRAY; + case SamplerType::SAMPLER_CUBEMAP_ARRAY: + return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; + case SamplerType::SAMPLER_3D: + return VK_IMAGE_VIEW_TYPE_3D; + default: + return VK_IMAGE_VIEW_TYPE_2D; + } +} + +}// namespace filament::backend::fvkutils + +#endif// TNT_FILAMENT_BACKEND_VULKAN_UTILS_CONVERSION_H diff --git a/filament/backend/src/vulkan/VulkanUtility.h b/filament/backend/src/vulkan/utils/Definitions.h similarity index 70% rename from filament/backend/src/vulkan/VulkanUtility.h rename to filament/backend/src/vulkan/utils/Definitions.h index 33be80d3fa..157eb4c40f 100644 --- a/filament/backend/src/vulkan/VulkanUtility.h +++ b/filament/backend/src/vulkan/utils/Definitions.h @@ -1,7 +1,7 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2024 The Android Open Source Project * -* Licensed under the Apache License, Version 2.0 (the "License"); + * 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 * @@ -14,82 +14,17 @@ * limitations under the License. */ -#ifndef TNT_FILAMENT_BACKEND_VULKANUTILITY_H -#define TNT_FILAMENT_BACKEND_VULKANUTILITY_H - -#include +#ifndef TNT_FILAMENT_BACKEND_VULKAN_UTILS_DEFINITIONS_H +#define TNT_FILAMENT_BACKEND_VULKAN_UTILS_DEFINITIONS_H #include #include #include -#include +// Definitions for common types used across classes. -namespace filament::backend { - -VkFormat getVkFormat(ElementType type, bool normalized, bool integer); -VkFormat getVkFormat(TextureFormat format); -VkFormat getVkFormat(PixelDataFormat format, PixelDataType type); -VkFormat getVkFormatLinear(VkFormat format); -uint32_t getBytesPerPixel(TextureFormat format); -VkCompareOp getCompareOp(SamplerCompareFunc func); -VkBlendFactor getBlendFactor(BlendFunction mode); -VkCullModeFlags getCullMode(CullingMode mode); -VkFrontFace getFrontFace(bool inverseFrontFaces); -PixelDataType getComponentType(VkFormat format); -uint32_t getComponentCount(VkFormat format); -VkComponentMapping getSwizzleMap(TextureSwizzle const swizzle[4]); -VkShaderStageFlags getShaderStageFlags(ShaderStageFlags stageFlags); - -bool equivalent(const VkRect2D& a, const VkRect2D& b); -bool equivalent(const VkExtent2D& a, const VkExtent2D& b); -bool isVkDepthFormat(VkFormat format); -bool isVkStencilFormat(VkFormat format); - -VkImageAspectFlags getImageAspect(VkFormat format); -uint8_t reduceSampleCount(uint8_t sampleCount, VkSampleCountFlags mask); - -// Helper function for the vkEnumerateX methods. These methods have the format of -// VkResult vkEnumerateX(InputType1 arg1, InputTyp2 arg2, ..., uint32_t* size, -// OutputType* output_arg) -// Instead of macros and explicitly listing the template params, Variadic Template was also -// considered, but because the "variadic" part of the vk methods (i.e. the inputs) are before the -// non-variadic parts, this breaks the template type matching logic. Hence, we use a macro approach -// here. -#define EXPAND_ENUM(...) \ - uint32_t size = 0; \ - VkResult result = func(__VA_ARGS__, nullptr); \ - FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "enumerate size error"; \ - utils::FixedCapacityVector ret(size); \ - result = func(__VA_ARGS__, ret.data()); \ - FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "enumerate error"; \ - return std::move(ret); - -#define EXPAND_ENUM_NO_ARGS() EXPAND_ENUM(&size) -#define EXPAND_ENUM_ARGS(...) EXPAND_ENUM(__VA_ARGS__, &size) - -template -utils::FixedCapacityVector enumerate(VKAPI_ATTR VkResult (*func)(uint32_t*, OutType*)) { - EXPAND_ENUM_NO_ARGS(); -} - -template -utils::FixedCapacityVector enumerate( - VKAPI_ATTR VkResult (*func)(InType, uint32_t*, OutType*), InType inData) { - EXPAND_ENUM_ARGS(inData); -} - -template -utils::FixedCapacityVector enumerate( - VKAPI_ATTR VkResult (*func)(InTypeA, InTypeB, uint32_t*, OutType*), InTypeA inDataA, - InTypeB inDataB) { - EXPAND_ENUM_ARGS(inDataA, inDataB); -} - -#undef EXPAND_ENUM -#undef EXPAND_ENUM_NO_ARGS -#undef EXPAND_ENUM_ARGS +namespace filament::backend::fvkutils { // Useful shorthands using VkFormatList = utils::FixedCapacityVector; @@ -406,128 +341,6 @@ constexpr VkFormat ALL_VK_FORMATS[] = { VK_FORMAT_R16G16_S10_5_NV, }; -// An Array that will be statically fixed in capacity, but the "size" (as in user added elements) is -// variable. Note that this class is movable. -template -class CappedArray { -private: - using FixedSizeArray = std::array; - -public: - using const_iterator = typename FixedSizeArray::const_iterator; - using iterator = typename FixedSizeArray::iterator; - - CappedArray() = default; - - // Delete copy constructor/assignment. - CappedArray(CappedArray const& rhs) = delete; - CappedArray& operator=(CappedArray& rhs) = delete; - - CappedArray(CappedArray&& rhs) noexcept { - this->swap(rhs); - } - - CappedArray& operator=(CappedArray&& rhs) noexcept { - this->swap(rhs); - return *this; - } - - inline ~CappedArray() { - clear(); - } - - inline const_iterator begin() const { - if (mInd == 0) { - return mArray.cend(); - } - return mArray.cbegin(); - } - - inline const_iterator end() const { - if (mInd > 0 && mInd < CAPACITY) { - return mArray.begin() + mInd; - } - return mArray.cend(); - } - - inline iterator begin() { - if (mInd == 0) { - return mArray.end(); - } - return mArray.begin(); - } - - inline iterator end() { - if (mInd > 0 && mInd < CAPACITY) { - return mArray.begin() + mInd; - } - return mArray.end(); - } - - inline T back() { - assert_invariant(mInd > 0); - return *(mArray.begin() + mInd); - } - - inline void pop_back() { - assert_invariant(mInd > 0); - mInd--; - } - - inline const_iterator find(T item) { - return std::find(begin(), end(), item); - } - - inline void insert(T item) { - assert_invariant(mInd < CAPACITY); - mArray[mInd++] = item; - } - - inline void erase(T item) { - PANIC_PRECONDITION("CappedArray::erase should not be called"); - } - - inline void clear() { - if (mInd == 0) { - return; - } - mInd = 0; - } - - inline T& operator[](uint16_t ind) { - return mArray[ind]; - } - - inline T const& operator[](uint16_t ind) const { - return mArray[ind]; - } - - inline uint32_t size() const { - return mInd; - } - - T* data() { - return mArray.data(); - } - - T const* data() const { - return mArray.data(); - } - - bool operator==(CappedArray const& b) const { - return this->mArray == b.mArray; - } - -private: - void swap(CappedArray& rhs) { - std::swap(mArray, rhs.mArray); - std::swap(mInd, rhs.mInd); - } - - FixedSizeArray mArray; - uint32_t mInd = 0; -}; - using UniformBufferBitmask = utils::bitset64; using SamplerBitmask = utils::bitset64; @@ -550,7 +363,6 @@ static constexpr uint8_t getFragmentStageShift() noexcept { // We have at most 4 descriptor sets. This is to indicate which ones are active. using DescriptorSetMask = utils::bitset8; +} // namespace filament::backend::fvkutils -} // namespace filament::backend - -#endif // TNT_FILAMENT_BACKEND_VULKANUTILITY_H +#endif // TNT_FILAMENT_BACKEND_VULKAN_UTILS_DEFINITIONS_H diff --git a/filament/backend/src/vulkan/utils/Helper.h b/filament/backend/src/vulkan/utils/Helper.h new file mode 100644 index 0000000000..0ae3cf5a1c --- /dev/null +++ b/filament/backend/src/vulkan/utils/Helper.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2024 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_VULKAN_UTILS_HELPER_H +#define TNT_FILAMENT_BACKEND_VULKAN_UTILS_HELPER_H + +#include + +#include +#include + +#include + +#include + +namespace filament::backend::fvkutils { + +inline bool equivalent(const VkRect2D& a, const VkRect2D& b) { + // These are all integers so there's no need for an epsilon. + return a.extent.width == b.extent.width && a.extent.height == b.extent.height && + a.offset.x == b.offset.x && a.offset.y == b.offset.y; +} + +inline bool equivalent(const VkExtent2D& a, const VkExtent2D& b) { + return a.height == b.height && a.width == b.width; +} + +// Helper function for the vkEnumerateX methods. These methods have the format of +// VkResult vkEnumerateX(InputType1 arg1, InputTyp2 arg2, ..., uint32_t* size, +// OutputType* output_arg) +// Instead of macros and explicitly listing the template params, Variadic Template was also +// considered, but because the "variadic" part of the vk methods (i.e. the inputs) are before the +// non-variadic parts, this breaks the template type matching logic. Hence, we use a macro approach +// here. +#define EXPAND_ENUM(...) \ + uint32_t size = 0; \ + VkResult result = func(__VA_ARGS__, nullptr); \ + FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "enumerate size error"; \ + utils::FixedCapacityVector ret(size); \ + result = func(__VA_ARGS__, ret.data()); \ + FILAMENT_CHECK_POSTCONDITION(result == VK_SUCCESS) << "enumerate error"; \ + return std::move(ret); + +#define EXPAND_ENUM_NO_ARGS() EXPAND_ENUM(&size) +#define EXPAND_ENUM_ARGS(...) EXPAND_ENUM(__VA_ARGS__, &size) + +template +utils::FixedCapacityVector enumerate(VKAPI_ATTR VkResult (*func)(uint32_t*, OutType*)) { + EXPAND_ENUM_NO_ARGS(); +} + +template +utils::FixedCapacityVector enumerate( + VKAPI_ATTR VkResult (*func)(InType, uint32_t*, OutType*), InType inData) { + EXPAND_ENUM_ARGS(inData); +} + +template +utils::FixedCapacityVector enumerate( + VKAPI_ATTR VkResult (*func)(InTypeA, InTypeB, uint32_t*, OutType*), InTypeA inDataA, + InTypeB inDataB) { + EXPAND_ENUM_ARGS(inDataA, inDataB); +} + +#undef EXPAND_ENUM +#undef EXPAND_ENUM_NO_ARGS +#undef EXPAND_ENUM_ARGS + +} // namespace filament::backend::fvkutils + +#endif // TNT_FILAMENT_BACKEND_VULKAN_UTILS_HELPER_H diff --git a/filament/backend/src/vulkan/VulkanImageUtility.cpp b/filament/backend/src/vulkan/utils/Image.cpp similarity index 87% rename from filament/backend/src/vulkan/VulkanImageUtility.cpp rename to filament/backend/src/vulkan/utils/Image.cpp index 415eb305ca..fb160fc4b0 100644 --- a/filament/backend/src/vulkan/VulkanImageUtility.cpp +++ b/filament/backend/src/vulkan/utils/Image.cpp @@ -14,9 +14,9 @@ * limitations under the License. */ -#include "VulkanImageUtility.h" +#include "vulkan/utils/Image.h" -#include "VulkanTexture.h" +#include "vulkan/VulkanTexture.h" #include #include @@ -26,7 +26,7 @@ using namespace bluevk; -namespace filament::backend::imgutil { +namespace filament::backend::fvkutils { namespace { @@ -159,7 +159,41 @@ bool transitionLayout(VkCommandBuffer cmdbuffer, return true; } -}// namespace filament::backend +VkImageAspectFlags getImageAspect(VkFormat format) { + switch (format) { + case VK_FORMAT_D16_UNORM_S8_UINT: + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + case VK_FORMAT_D16_UNORM: + case VK_FORMAT_X8_D24_UNORM_PACK32: + case VK_FORMAT_D32_SFLOAT: + return VK_IMAGE_ASPECT_DEPTH_BIT; + case VK_FORMAT_S8_UINT: + return VK_IMAGE_ASPECT_STENCIL_BIT; + default: + return VK_IMAGE_ASPECT_COLOR_BIT; + } +} + +bool isVkDepthFormat(VkFormat format) { + return (getImageAspect(format) & VK_IMAGE_ASPECT_DEPTH_BIT) != 0; +} + +bool isVkStencilFormat(VkFormat format) { + return (getImageAspect(format) & VK_IMAGE_ASPECT_STENCIL_BIT) != 0; +} + +static uint32_t mostSignificantBit(uint32_t x) { return 1ul << (31ul - utils::clz(x)); } + +uint8_t reduceSampleCount(uint8_t sampleCount, VkSampleCountFlags mask) { + if (sampleCount & mask) { + return sampleCount; + } + return mostSignificantBit((sampleCount - 1) & mask); +} + +} // namespace filament::backend::fvkutils bool operator<(const VkImageSubresourceRange& a, const VkImageSubresourceRange& b) { if (a.aspectMask < b.aspectMask) return true; diff --git a/filament/backend/src/vulkan/VulkanImageUtility.h b/filament/backend/src/vulkan/utils/Image.h similarity index 84% rename from filament/backend/src/vulkan/VulkanImageUtility.h rename to filament/backend/src/vulkan/utils/Image.h index f8027d9697..fcd57ee331 100644 --- a/filament/backend/src/vulkan/VulkanImageUtility.h +++ b/filament/backend/src/vulkan/utils/Image.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef TNT_FILAMENT_BACKEND_VULKANIMAGEUTILITY_H -#define TNT_FILAMENT_BACKEND_VULKANIMAGEUTILITY_H +#ifndef TNT_FILAMENT_BACKEND_VULKAN_UTILS_IMAGE_H +#define TNT_FILAMENT_BACKEND_VULKAN_UTILS_IMAGE_H #include @@ -59,22 +59,7 @@ struct VulkanLayoutTransition { VkImageSubresourceRange subresources; }; -namespace imgutil { - -inline VkImageViewType getViewType(SamplerType target) { - switch (target) { - case SamplerType::SAMPLER_CUBEMAP: - return VK_IMAGE_VIEW_TYPE_CUBE; - case SamplerType::SAMPLER_2D_ARRAY: - return VK_IMAGE_VIEW_TYPE_2D_ARRAY; - case SamplerType::SAMPLER_CUBEMAP_ARRAY: - return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; - case SamplerType::SAMPLER_3D: - return VK_IMAGE_VIEW_TYPE_3D; - default: - return VK_IMAGE_VIEW_TYPE_2D; - } -} +namespace fvkutils { constexpr inline VkImageLayout getVkLayout(VulkanLayout layout) { switch (layout) { @@ -109,7 +94,15 @@ constexpr inline VkImageLayout getVkLayout(VulkanLayout layout) { // no transition necessary). bool transitionLayout(VkCommandBuffer cmdbuffer, VulkanLayoutTransition transition); -} // namespace imgutil +bool isVkDepthFormat(VkFormat format); + +bool isVkStencilFormat(VkFormat format); + +VkImageAspectFlags getImageAspect(VkFormat format); + +uint8_t reduceSampleCount(uint8_t sampleCount, VkSampleCountFlags mask); + +} // namespace fvkutils } // namespace filament::backend @@ -117,5 +110,4 @@ bool operator<(const VkImageSubresourceRange& a, const VkImageSubresourceRange& utils::io::ostream& operator<<(utils::io::ostream& out, const filament::backend::VulkanLayout& layout); - -#endif // TNT_FILAMENT_BACKEND_VULKANIMAGEUTILITY_H +#endif // TNT_FILAMENT_BACKEND_VULKAN_UTILS_IMAGE_H diff --git a/filament/backend/src/vulkan/spirv/VulkanSpirvUtils.cpp b/filament/backend/src/vulkan/utils/Spirv.cpp similarity index 72% rename from filament/backend/src/vulkan/spirv/VulkanSpirvUtils.cpp rename to filament/backend/src/vulkan/utils/Spirv.cpp index 209745facd..a1c5933dd0 100644 --- a/filament/backend/src/vulkan/spirv/VulkanSpirvUtils.cpp +++ b/filament/backend/src/vulkan/utils/Spirv.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "VulkanSpirvUtils.h" +#include "vulkan/utils/Spirv.h" #include // UTILS_UNUSED_IN_RELEASE, UTILS_FALLTHROUGH #include // assert_invariant @@ -22,12 +22,11 @@ #include -#include -#include -#include #include +#include +#include -namespace filament::backend { +namespace filament::backend::fvkutils { namespace { @@ -99,7 +98,7 @@ void workaroundSpecConstant(Program::ShaderBlob const& blob, uint32_t const* data = (uint32_t*) blob.data(); uint32_t* outputData = output.data(); - std::memcpy(&outputData[0], &data[0], HEADER_SIZE * 4); + memcpy(&outputData[0], &data[0], HEADER_SIZE * 4); size_t outputCursor = HEADER_SIZE; for (uint32_t cursor = HEADER_SIZE, cursorEnd = dataSize; cursor < cursorEnd;) { @@ -147,61 +146,4 @@ void workaroundSpecConstant(Program::ShaderBlob const& blob, output.resize(outputCursor); } -std::tuple getProgramBindings(Program::ShaderBlob const& blob) { - std::unordered_map targetToSet, targetToBinding; - - constexpr size_t HEADER_SIZE = 5; - - size_t const dataSize = blob.size() / 4; - uint32_t const* data = (uint32_t*) blob.data(); - - for (uint32_t cursor = HEADER_SIZE, cursorEnd = dataSize; cursor < cursorEnd;) { - uint32_t const firstWord = data[cursor]; - uint32_t const wordCount = firstWord >> 16; - uint32_t const op = firstWord & 0x0000FFFF; - - switch(op) { - case spv::Op::OpDecorate: { - if (data[cursor + 2] == spv::Decoration::DecorationDescriptorSet) { - uint32_t const targetVar = data[cursor + 1]; - uint32_t const setId = data[cursor + 3]; - targetToSet[targetVar] = setId; - } else if (data[cursor + 2] == spv::Decoration::DecorationBinding) { - uint32_t const targetVar = data[cursor + 1]; - uint32_t const binding = data[cursor + 3]; - targetToBinding[targetVar] = binding; - } - break; - } - default: - break; - } - cursor += wordCount; - } - - constexpr uint32_t UBO = 0; - constexpr uint32_t SAMPLER = 1; - constexpr uint32_t IATTACHMENT = 2; - uint32_t ubo = 0, sampler = 0, inputAttachment = 0; - - for (auto const& [target, setId]: targetToSet) { - uint32_t const binding = targetToBinding[target]; - assert_invariant(binding < 32); - switch(setId) { - case UBO: - ubo |= (1 << binding); - break; - case SAMPLER: - sampler |= (1 << binding); - break; - case IATTACHMENT: - inputAttachment |= (1 << binding); - break; - default: - PANIC_POSTCONDITION("unexpected %d", (int) setId); - } - } - return {ubo, sampler, inputAttachment}; -} - -} // namespace filament::backend +} // namespace filament::backend::fvkutils diff --git a/filament/backend/src/vulkan/spirv/VulkanSpirvUtils.h b/filament/backend/src/vulkan/utils/Spirv.h similarity index 77% rename from filament/backend/src/vulkan/spirv/VulkanSpirvUtils.h rename to filament/backend/src/vulkan/utils/Spirv.h index 2a9f79a611..941c30a32d 100644 --- a/filament/backend/src/vulkan/spirv/VulkanSpirvUtils.h +++ b/filament/backend/src/vulkan/utils/Spirv.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 The Android Open Source Project + * Copyright (C) 2024 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. @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef TNT_FILAMENT_BACKEND_VULKANSPIRVUTILS_H -#define TNT_FILAMENT_BACKEND_VULKANSPIRVUTILS_H +#ifndef TNT_FILAMENT_BACKEND_VULKAN_UTILS_SPIRV_H +#define TNT_FILAMENT_BACKEND_VULKAN_UTILS_SPIRV_H #include @@ -24,7 +24,7 @@ #include #include -namespace filament::backend { +namespace filament::backend::fvkutils { using SpecConstantValue = Program::SpecializationConstant::Type; @@ -44,8 +44,9 @@ void workaroundSpecConstant(Program::ShaderBlob const& blob, std::vector& output); // bindings for UBO, samplers, input attachment -std::tuple getProgramBindings(Program::ShaderBlob const& blob); +// This is no longer needed after the descriptor set refactor, but the code is good for reference. +// std::tuple getProgramBindings(Program::ShaderBlob const& blob); -} // namespace filament::backend +} // namespace filament::backend::fvkutils -#endif // TNT_FILAMENT_BACKEND_VULKANSPIRVUTILS_H +#endif // TNT_FILAMENT_BACKEND_VULKAN_UTILS_SPIRV_H diff --git a/filament/backend/src/vulkan/utils/StaticVector.h b/filament/backend/src/vulkan/utils/StaticVector.h new file mode 100644 index 0000000000..b9abf8f9f2 --- /dev/null +++ b/filament/backend/src/vulkan/utils/StaticVector.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2024 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_VULKAN_UTILS_STATICVECTOR_H +#define TNT_FILAMENT_BACKEND_VULKAN_UTILS_STATICVECTOR_H + +// An Array that will be statically fixed in capacity, but the "size" (as in user added elements) is +// variable. Note that this class is movable. + +#include + +#include + +namespace filament::backend::fvkutils { + +template +class StaticVector { +private: + using FixedSizeArray = std::array; + + static_assert(CAPACITY <= (1LL << (8 * sizeof(uint16_t)))); + +public: + using const_iterator = typename FixedSizeArray::const_iterator; + using iterator = typename FixedSizeArray::iterator; + + StaticVector() = default; + + // Delete copy constructor/assignment. + StaticVector(StaticVector const& rhs) = delete; + StaticVector& operator=(StaticVector& rhs) = delete; + + StaticVector(StaticVector&& rhs) noexcept { + std::swap(mSize, rhs.mSize); + std::swap(mArray, rhs.mArray); + } + + StaticVector& operator=(StaticVector&& rhs) noexcept { + std::swap(mSize, rhs.mSize); + std::swap(mArray, rhs.mArray); + return *this; + } + + inline ~StaticVector() { + clear(); + } + + inline const_iterator begin() const { + return mArray.cbegin(); + } + + inline const_iterator end() const { + assert_invariant(mSize <= CAPACITY); + return mArray.begin() + mSize; + } + + inline iterator begin() { + return mArray.begin(); + } + + inline iterator end() { + assert_invariant(mSize <= CAPACITY); + return mArray.begin() + mSize; + } + + inline T back() { + assert_invariant(mSize > 0); + return *(mArray.begin() + mSize); + } + + inline void pop_back() { + assert_invariant(mSize > 0); + mSize--; + } + + inline const_iterator find(T item) { + return std::find(begin(), end(), item); + } + + inline void push_back(T item) { + assert_invariant(mSize < CAPACITY); + mArray[mSize++] = item; + } + + inline void clear() { + mSize = 0; + } + + inline T& operator[](size_t index) { + assert_invariant(index < mSize); + return mArray[index]; + } + + inline T const& operator[](size_t index) const { + return mArray[index]; + } + + inline uint16_t size() const { + return mSize; + } + + T* data() { + return mArray.data(); + } + + T const* data() const { + return mArray.data(); + } + + bool operator==(StaticVector const& b) const { + return this->mArray == b.mArray && this->mSize == b.mSize; + } + +private: + FixedSizeArray mArray; + uint16_t mSize = 0; +}; + +} // namespace filament::backend::fvkutils + +#endif // TNT_FILAMENT_BACKEND_VULKAN_UTILS_STATICVECTOR_H From 864529254e0a80e6c3d11f2573d1c424604ce6ba Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Mon, 3 Feb 2025 00:07:21 -0800 Subject: [PATCH 10/24] fix color grading as subpass This broke in 48a2c64. Fixes #8401. --- .../src/materials/colorGrading/colorGradingAsSubpass.mat | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/filament/src/materials/colorGrading/colorGradingAsSubpass.mat b/filament/src/materials/colorGrading/colorGradingAsSubpass.mat index 0875d2a655..9c54d8a6bb 100644 --- a/filament/src/materials/colorGrading/colorGradingAsSubpass.mat +++ b/filament/src/materials/colorGrading/colorGradingAsSubpass.mat @@ -16,7 +16,7 @@ material { }, { type : int, - name : fxaa + name : outputLuminance }, { type : float, @@ -110,10 +110,10 @@ void postProcess(inout PostProcessInputs postProcess) { color = dither(color, materialParams.temporalNoise); } - // kill alpha computations when opaque / fxaa luminance + // kill alpha computations when opaque / luminance #if POST_PROCESS_OPAQUE color.a = 1.0; - if (materialParams.fxaa > 0) { + if (materialParams.outputLuminance > 0) { color.a = luminance(color.rgb); } #endif From 4fe852e88a9653951ab07204018b22aa5f7b9cef Mon Sep 17 00:00:00 2001 From: Sungun Park Date: Mon, 3 Feb 2025 13:23:53 -0800 Subject: [PATCH 11/24] Ensure correct resource cleanup sequence to avoid crashes upon app closing (#8408) The commit 1747ae8f5ac1fe9f8af9b550a172cd4da432cdec enfoces a correct order for releasing resource. Fix the order to avoid crashes. Make some samples to use the DEPTH32F format for better compatibility. Some manufacturers don't fully support DEPTH24 on Vulkan. E.g., AMD Radeon PRO W6400 --- .../include/filamentapp/MeshAssimp.h | 7 ++++--- libs/filamentapp/src/MeshAssimp.cpp | 21 +++++++++++-------- samples/hellopbr.cpp | 2 +- samples/hellostereo.cpp | 8 +++---- samples/rendertarget.cpp | 6 +++--- samples/skinningtest.cpp | 18 ++++++++-------- samples/suzanne.cpp | 2 +- 7 files changed, 34 insertions(+), 30 deletions(-) diff --git a/libs/filamentapp/include/filamentapp/MeshAssimp.h b/libs/filamentapp/include/filamentapp/MeshAssimp.h index a9b475826e..43fb3626a7 100644 --- a/libs/filamentapp/include/filamentapp/MeshAssimp.h +++ b/libs/filamentapp/include/filamentapp/MeshAssimp.h @@ -56,6 +56,8 @@ public: explicit MeshAssimp(filament::Engine& engine); ~MeshAssimp(); + // This function takes over the ownership of `materials` to prevent crashes due to the + // incorrect order of resource destruction. void addFromFile(const utils::Path& path, std::map& materials, bool overrideMaterial = false); @@ -127,8 +129,9 @@ private: filament::Material* mDefaultColorMaterial = nullptr; filament::Material* mDefaultTransparentColorMaterial = nullptr; - mutable std::unordered_map mGltfMaterialCache; + std::map mMaterialInstances; + filament::Texture* mDefaultMap = nullptr; filament::Texture* mDefaultNormalMap = nullptr; float mDefaultMetallic = 0.0f; @@ -138,8 +141,6 @@ private: std::vector mRenderables; std::vector mTextures; - - }; #endif // TNT_FILAMENT_SAMPLE_MESH_ASSIMP_H diff --git a/libs/filamentapp/src/MeshAssimp.cpp b/libs/filamentapp/src/MeshAssimp.cpp index 5e3f403e75..2027d2fb10 100644 --- a/libs/filamentapp/src/MeshAssimp.cpp +++ b/libs/filamentapp/src/MeshAssimp.cpp @@ -277,26 +277,25 @@ MeshAssimp::MeshAssimp(Engine& engine) : mEngine(engine) { } MeshAssimp::~MeshAssimp() { + for (Entity renderable : mRenderables) { + mEngine.destroy(renderable); + } mEngine.destroy(mVertexBuffer); mEngine.destroy(mIndexBuffer); + for (auto& item : mMaterialInstances) { + mEngine.destroy(item.second); + } mEngine.destroy(mDefaultColorMaterial); mEngine.destroy(mDefaultTransparentColorMaterial); - mEngine.destroy(mDefaultNormalMap); - mEngine.destroy(mDefaultMap); - for (auto& item : mGltfMaterialCache) { auto material = item.second; mEngine.destroy(material); } - - for (Entity renderable : mRenderables) { - mEngine.destroy(renderable); - } - + mEngine.destroy(mDefaultNormalMap); + mEngine.destroy(mDefaultMap); for (Texture* texture : mTextures) { mEngine.destroy(texture); } - // destroy the Entities itself EntityManager::get().destroy(mRenderables.size(), mRenderables.data()); } @@ -626,6 +625,10 @@ void MeshAssimp::addFromFile(const Path& path, tcm.getInstance(rootEntity) : tcm.getInstance(mRenderables[pindex])); tcm.create(entity, parent, mesh.transform); } + + // Takes over the ownership of the material instances so that resources are gracefully + // destroyed in a correct order. The caller doesn't need to handle the destruction. + mMaterialInstances.swap(materials); } using Assimp::Importer; diff --git a/samples/hellopbr.cpp b/samples/hellopbr.cpp index f5cae37706..c1163c8854 100644 --- a/samples/hellopbr.cpp +++ b/samples/hellopbr.cpp @@ -146,8 +146,8 @@ int main(int argc, char** argv) { auto cleanup = [&app](Engine* engine, View*, Scene*) { engine->destroy(app.light); - engine->destroy(app.materialInstance); engine->destroy(app.mesh.renderable); + engine->destroy(app.materialInstance); engine->destroy(app.material); }; diff --git a/samples/hellostereo.cpp b/samples/hellostereo.cpp index 06936241a8..41c5c4a198 100644 --- a/samples/hellostereo.cpp +++ b/samples/hellostereo.cpp @@ -218,7 +218,7 @@ int main(int argc, char** argv) { .depth(eyeCount) .levels(1) .sampler(Texture::Sampler::SAMPLER_2D_ARRAY) - .format(Texture::InternalFormat::DEPTH24) + .format(Texture::InternalFormat::DEPTH32F) .usage(Texture::Usage::DEPTH_ATTACHMENT) .build(*engine); app.stereoRenderTarget = RenderTarget::Builder() @@ -324,12 +324,12 @@ int main(int argc, char** argv) { auto& em = utils::EntityManager::get(); - for (MaterialInstance* mi : app.quadMatInstances) { - engine->destroy(mi); - } for (utils::Entity e : app.quadEntities) { engine->destroy(e); } + for (MaterialInstance* mi : app.quadMatInstances) { + engine->destroy(mi); + } engine->destroy(app.quadMaterial); engine->destroy(app.quadIb); engine->destroy(app.quadVb); diff --git a/samples/rendertarget.cpp b/samples/rendertarget.cpp index 9ff53ccc37..4e7860d726 100644 --- a/samples/rendertarget.cpp +++ b/samples/rendertarget.cpp @@ -209,7 +209,7 @@ int main(int argc, char** argv) { app.offscreenDepthTexture = Texture::Builder() .width(vp.width).height(vp.height).levels(1) .usage(Texture::Usage::DEPTH_ATTACHMENT) - .format(Texture::InternalFormat::DEPTH24).build(*engine); + .format(Texture::InternalFormat::DEPTH32F).build(*engine); app.offscreenRenderTarget = RenderTarget::Builder() .texture(RenderTarget::AttachmentPoint::COLOR, app.offscreenColorTexture) .texture(RenderTarget::AttachmentPoint::DEPTH, app.offscreenDepthTexture) @@ -321,11 +321,11 @@ int main(int argc, char** argv) { engine->destroy(app.reflectedMonkey); engine->destroy(app.lightEntity); engine->destroy(app.quadEntity); - engine->destroy(app.meshMatInstance); - engine->destroy(app.meshMaterial); engine->destroy(app.monkeyMesh.renderable); engine->destroy(app.monkeyMesh.vertexBuffer); engine->destroy(app.monkeyMesh.indexBuffer); + engine->destroy(app.meshMatInstance); + engine->destroy(app.meshMaterial); engine->destroy(app.offscreenColorTexture); engine->destroy(app.offscreenDepthTexture); engine->destroy(app.offscreenRenderTarget); diff --git a/samples/skinningtest.cpp b/samples/skinningtest.cpp index a2da0b1b5b..d00e9413eb 100644 --- a/samples/skinningtest.cpp +++ b/samples/skinningtest.cpp @@ -639,6 +639,15 @@ int main(int argc, char** argv) { }; auto cleanup = [&app](Engine* engine, View*, Scene*) { + for (auto i = 0; i < 4; i++) { + engine->destroy(app.renderables[i]); + } + for (auto i = 0; i < app.boCount; i++) { + engine->destroy(app.bos[i]); + } + for (auto i = 0; i < app.vbCount; i++) { + engine->destroy(app.vbs[i]); + } engine->destroy(app.skybox); engine->destroy(app.mat); engine->destroy(app.ib); @@ -648,15 +657,6 @@ int main(int argc, char** argv) { engine->destroy(app.mt); engine->destroyCameraComponent(app.camera); EntityManager::get().destroy(app.camera); - for (auto i = 0; i < app.vbCount; i++) { - engine->destroy(app.vbs[i]); - } - for ( auto i = 0; i < app.boCount; i++) { - engine->destroy(app.bos[i]); - } - for ( auto i = 0; i < 4; i++) { - engine->destroy(app.renderables[i]); - } }; FilamentApp::get().animate([&app](Engine* engine, View* view, double now) { diff --git a/samples/suzanne.cpp b/samples/suzanne.cpp index dae42d353e..8eeeef8ef0 100644 --- a/samples/suzanne.cpp +++ b/samples/suzanne.cpp @@ -199,8 +199,8 @@ int main(int argc, char** argv) { }; auto cleanup = [&app](Engine* engine, View*, Scene*) { - engine->destroy(app.materialInstance); engine->destroy(app.mesh.renderable); + engine->destroy(app.materialInstance); engine->destroy(app.material); engine->destroy(app.albedo); engine->destroy(app.normal); From 3c4591df179d50a8c233aeba82648d273b833a81 Mon Sep 17 00:00:00 2001 From: Powei Feng Date: Mon, 3 Feb 2025 22:53:44 -0800 Subject: [PATCH 12/24] java: must use return var in Engine (#8409) --- .../src/main/java/com/google/android/filament/Engine.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/filament-android/src/main/java/com/google/android/filament/Engine.java b/android/filament-android/src/main/java/com/google/android/filament/Engine.java index e73e82944c..392497461b 100644 --- a/android/filament-android/src/main/java/com/google/android/filament/Engine.java +++ b/android/filament-android/src/main/java/com/google/android/filament/Engine.java @@ -1271,7 +1271,7 @@ public class Engine { * {@link android.view.SurfaceHolder.Callback#surfaceDestroyed surfaceDestroyed}.

*/ public void flushAndWait() { - flushAndWait(Fence.WAIT_FOR_EVER); + boolean unused = flushAndWait(Fence.WAIT_FOR_EVER); } /** From fff7bd2b28820c253c573ffcd030683311420be9 Mon Sep 17 00:00:00 2001 From: Ben Doherty Date: Tue, 4 Feb 2025 09:32:49 -0800 Subject: [PATCH 13/24] Combine and install Abseil (#8387) --- CMakeLists.txt | 27 ++++--- build/windows/combine-static-libs.bat | 39 --------- third_party/abseil/tnt/CMakeLists.txt | 109 ++++++++++++++++++++++++++ third_party/abseil/tnt/dummy.c | 0 4 files changed, 126 insertions(+), 49 deletions(-) delete mode 100644 build/windows/combine-static-libs.bat create mode 100644 third_party/abseil/tnt/CMakeLists.txt create mode 100644 third_party/abseil/tnt/dummy.c diff --git a/CMakeLists.txt b/CMakeLists.txt index f9de5b2a5e..d561f4346c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -667,10 +667,6 @@ function(list_licenses OUTPUT MODULES) endfunction() set(COMBINE_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/build/linux/combine-static-libs.sh") -if (WIN32) - set(COMBINE_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/build/windows/combine-static-libs.bat") - set(CMAKE_AR "lib.exe") -endif() # Add a custom command to TARGET that combines the static libraries in DEPS into a single archive. function(combine_static_libs TARGET OUTPUT DEPS) @@ -685,12 +681,22 @@ function(combine_static_libs TARGET OUTPUT DEPS) endif() endforeach() - add_custom_command( - TARGET ${TARGET} POST_BUILD - COMMAND "${COMBINE_SCRIPT}" "${CMAKE_AR}" "${OUTPUT}" ${DEPS_FILES} - COMMENT "Combining ${target} dependencies into single shared library" - VERBATIM - ) + if (WIN32) + add_custom_command( + TARGET ${TARGET} POST_BUILD + COMMAND lib.exe /nologo /out:temp.lib ${DEPS_FILES} + COMMAND "${CMAKE_COMMAND}" -E rename temp.lib ${OUTPUT} + COMMENT "Combining ${target} dependencies into single shared library" + VERBATIM + ) + else() + add_custom_command( + TARGET ${TARGET} POST_BUILD + COMMAND "${COMBINE_SCRIPT}" "${CMAKE_AR}" "${OUTPUT}" ${DEPS_FILES} + COMMENT "Combining ${target} dependencies into single shared library" + VERBATIM + ) + endif() endfunction() # ================================================================================================== @@ -761,6 +767,7 @@ add_subdirectory(${LIBRARIES}/utils) add_subdirectory(${LIBRARIES}/viewer) add_subdirectory(${FILAMENT}/filament) add_subdirectory(${FILAMENT}/shaders) +add_subdirectory(${EXTERNAL}/abseil/tnt) add_subdirectory(${EXTERNAL}/basisu/tnt) add_subdirectory(${EXTERNAL}/civetweb/tnt) add_subdirectory(${EXTERNAL}/imgui/tnt) diff --git a/build/windows/combine-static-libs.bat b/build/windows/combine-static-libs.bat deleted file mode 100644 index 67f13e1d91..0000000000 --- a/build/windows/combine-static-libs.bat +++ /dev/null @@ -1,39 +0,0 @@ -@echo off -set selfName=%0 - -:: Check that we have at least 3 arguments. -set argC=0 -for %%x in (%*) do Set /A argC+=1 -if %argC% LSS 3 goto :print_help - -set AR_TOOL=%1 -shift -set OUTPUT_PATH=%1 -shift - -set ARCHIVES= -:loop -if [%1]==[] goto :finished -set ARCHIVES=%ARCHIVES% %1 -shift -goto :loop - -:finished - -%AR_TOOL% /nologo /out:%OUTPUT_PATH% %ARCHIVES% || goto :error - -exit /B %ERRORLEVEL% - -:print_help -echo %selfName%. Combine multiple static libraries using an archiver tool. -echo; -echo Usage: -echo %selfName% ^ ^ ^... -echo; -echo Notes: -echo ^ must be a list of absolute paths to static library archives. -echo This script creates a temporary working directory inside the current directory. -exit /B 1 - -:error -exit /B %ERRORLEVEL% diff --git a/third_party/abseil/tnt/CMakeLists.txt b/third_party/abseil/tnt/CMakeLists.txt new file mode 100644 index 0000000000..8481d7ad3f --- /dev/null +++ b/third_party/abseil/tnt/CMakeLists.txt @@ -0,0 +1,109 @@ +add_subdirectory(../ "${CMAKE_CURRENT_BINARY_DIR}/abseil") + +# To make Abseil easy for clients to link against, we create a dummy target just for installation +# purposes and combine all of Abseil's libraries into a single, easy to link against static library. +add_library(filament-abseil STATIC dummy.c) + +set(ABSEIL_DEPS + # This is a full list of static library targets that Abseil exports, generated with the + # following commands: + # cd out/cmake-debug + # ninja -t targets | grep libabsl | sed 's/^lib//; s/\.a: phony$//' + absl_bad_any_cast_impl + absl_bad_optional_access + absl_bad_variant_access + absl_base + absl_city + absl_civil_time + absl_cord + absl_cord_internal + absl_cordz_functions + absl_cordz_handle + absl_cordz_info + absl_cordz_sample_token + absl_crc32c + absl_crc_cord_state + absl_crc_cpu_detect + absl_crc_internal + absl_debugging_internal + absl_decode_rust_punycode + absl_demangle_internal + absl_demangle_rust + absl_die_if_null + absl_examine_stack + absl_exponential_biased + absl_failure_signal_handler + absl_flags_commandlineflag + absl_flags_commandlineflag_internal + absl_flags_config + absl_flags_internal + absl_flags_marshalling + absl_flags_parse + absl_flags_private_handle_accessor + absl_flags_program_name + absl_flags_reflection + absl_flags_usage + absl_flags_usage_internal + absl_graphcycles_internal + absl_hash + absl_hashtablez_sampler + absl_int128 + absl_kernel_timeout_internal + absl_leak_check + absl_log_entry + absl_log_flags + absl_log_globals + absl_log_initialize + absl_log_internal_check_op + absl_log_internal_conditions + absl_log_internal_fnmatch + absl_log_internal_format + absl_log_internal_globals + absl_log_internal_log_sink_set + absl_log_internal_message + absl_log_internal_nullguard + absl_log_internal_proto + absl_log_internal_structured_proto + absl_log_severity + absl_log_sink + absl_low_level_hash + absl_malloc_internal + absl_periodic_sampler + absl_poison + absl_random_distributions + absl_random_internal_distribution_test_util + absl_random_internal_platform + absl_random_internal_pool_urbg + absl_random_internal_randen + absl_random_internal_randen_hwaes + absl_random_internal_randen_hwaes_impl + absl_random_internal_randen_slow + absl_random_internal_seed_material + absl_random_seed_gen_exception + absl_random_seed_sequences + absl_raw_hash_set + absl_raw_logging_internal + absl_scoped_set_env + absl_spinlock_wait + absl_stacktrace + absl_status + absl_statusor + absl_str_format_internal + absl_strerror + absl_string_view + absl_strings + absl_strings_internal + absl_symbolize + absl_synchronization + absl_throw_delegate + absl_time + absl_time_zone + absl_tracing_internal + absl_utf8_for_code_point + absl_vlog_config_internal +) +set(ABSEIL_COMBINED_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/libabseil_combined.a") +combine_static_libs(filament-abseil "${ABSEIL_COMBINED_OUTPUT}" "${ABSEIL_DEPS}") + +set(ABSEIL_LIB_NAME ${CMAKE_STATIC_LIBRARY_PREFIX}abseil${CMAKE_STATIC_LIBRARY_SUFFIX}) +install(FILES "${ABSEIL_COMBINED_OUTPUT}" DESTINATION lib/${DIST_DIR} RENAME ${ABSEIL_LIB_NAME}) diff --git a/third_party/abseil/tnt/dummy.c b/third_party/abseil/tnt/dummy.c new file mode 100644 index 0000000000..e69de29bb2 From a04019937ecb1d1ef56ba2f3d0ba52303f41fbf0 Mon Sep 17 00:00:00 2001 From: Powei Feng Date: Tue, 4 Feb 2025 11:30:40 -0800 Subject: [PATCH 14/24] Add feature flag for material/instance destroy assert (#8411) This will allow a more lenient rollout of the assertion, which otherwise will increase crashes for current clients. We also disable features.engine.debug.assert_material_instance_in_use by default (it was enabled for debug builds). --- filament/src/details/Engine.h | 11 ++++++----- filament/src/details/Material.cpp | 11 ++++++++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/filament/src/details/Engine.h b/filament/src/details/Engine.h index e2b7058625..25c3f388af 100644 --- a/filament/src/details/Engine.h +++ b/filament/src/details/Engine.h @@ -690,11 +690,9 @@ public: bool use_shadow_atlas = false; } shadows; struct { -#ifndef NDEBUG - bool assert_material_instance_in_use = true; -#else + // TODO: default the following two flags to true. bool assert_material_instance_in_use = false; -#endif + bool assert_destroy_material_before_material_instance = false; } debug; } engine; struct { @@ -721,7 +719,10 @@ public: &features.engine.shadows.use_shadow_atlas, false }, { "features.engine.debug.assert_material_instance_in_use", "Assert when a MaterialInstance is destroyed while it is in use by RenderableManager.", - &features.engine.debug.assert_material_instance_in_use, false } + &features.engine.debug.assert_material_instance_in_use, false }, + { "features.engine.debug.assert_destroy_material_before_material_instance", + "Assert when a Material is destroyed but its instances are still alive.", + &features.engine.debug.assert_destroy_material_before_material_instance, false }, }}; utils::Slice getFeatureFlags() const noexcept { diff --git a/filament/src/details/Material.cpp b/filament/src/details/Material.cpp index ed5c845981..4347e1aa28 100644 --- a/filament/src/details/Material.cpp +++ b/filament/src/details/Material.cpp @@ -383,9 +383,14 @@ void FMaterial::terminate(FEngine& engine) { auto const& materialInstanceResourceList = engine.getMaterialInstanceResourceList(); auto pos = materialInstanceResourceList.find(this); if (UTILS_LIKELY(pos != materialInstanceResourceList.cend())) { - FILAMENT_CHECK_PRECONDITION(pos->second.empty()) - << "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 { + utils::slog.e << "destroying material \"" << this->getName().c_str_safe() << "\" but " + << pos->second.size() << " instances still alive."; + } } From 06a2def85fd7c6e87553cfd36a745a968689b46e Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Tue, 4 Feb 2025 11:52:37 -0800 Subject: [PATCH 15/24] make sure FXAA resets alpha channel when it's the last postfx (#8412) If FXAA is the last post process effect (i.e. no upscaling), and color grading produced a luma channel, then FXAA needs to reset the alpha channel to 1. --- filament/src/details/Renderer.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/filament/src/details/Renderer.cpp b/filament/src/details/Renderer.cpp index 777aecab24..e9963a17a3 100644 --- a/filament/src/details/Renderer.cpp +++ b/filament/src/details/Renderer.cpp @@ -1351,8 +1351,11 @@ void FRenderer::renderJob(RootArenaScope& rootArenaScope, FView& view) { } if (hasFXAA) { - bool const preserveAlphaChannel = needsAlphaChannel || - (hasColorGrading && colorGradingConfig.outputLuminance); + bool const preserveAlphaChannel = + // we're transparent -- alpha channel has user data + needsAlphaChannel || + // the color-grading pass outputted the luminance channel, and we have an upscaling pass + (hasColorGrading && colorGradingConfig.outputLuminance && scaled); input = ppm.fxaa(fg, input, xvp, colorGradingConfig.ldrFormat, preserveAlphaChannel); // the padded buffer is resolved now xvp.left = xvp.bottom = 0; From ad4f349f00939f54b381c7a632601938c796108b Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Mon, 27 Jan 2025 15:55:26 -0800 Subject: [PATCH 16/24] Improve external texture image API The current API used a void* in Texture::setExternalImage to pass the platform specific image. This was a problem because on some platform like Android, there could be several types (EGLImageKHR and AHardwareBuffer), and with the void* there was no way to distinguish them on the backend / platform side. We now have a new Texture API which takes a Platform::ExternalImageHandle, which is a reference-counted handle to a Platform::ExternalImage. Platform::ExternalImage is an opaque type only known by the platform. This type must be created using a concrete Platform specific API, such as: PlatformEGL::createExternalImage PlatformEGLAndroid::createExternalImage PlatformCocoaGL::createExternalImage PlatformCocoaTouchGL::createExternalImage New types can easily be added in the future. There is no "destroy" call because the Platform::ExternalImageHandle is reference-counted and the client can let go of it as soon as it doesn't need it any longer (typically after calling Texture::setExternalImage). Platform::ExternalImage is a small structure that just anonymously wraps the concrete types. New internal driver APIs have been added to handle this functionality. --- NEW_RELEASE_NOTES.md | 1 + filament/backend/include/backend/Platform.h | 42 +++++++++ .../backend/platforms/OpenGLPlatform.h | 20 ++-- .../backend/platforms/PlatformCocoaGL.h | 10 +- .../backend/platforms/PlatformCocoaTouchGL.h | 10 +- .../include/backend/platforms/PlatformEGL.h | 16 +++- .../backend/platforms/PlatformEGLAndroid.h | 14 +++ .../include/private/backend/DriverAPI.inc | 9 ++ filament/backend/src/Platform.cpp | 85 +++++++++++++++++ filament/backend/src/metal/MetalDriver.mm | 16 ++++ filament/backend/src/noop/NoopDriver.cpp | 7 ++ filament/backend/src/opengl/GLUtils.h | 67 ++++++++----- filament/backend/src/opengl/OpenGLDriver.cpp | 94 ++++++++++++++----- .../backend/src/opengl/OpenGLPlatform.cpp | 12 ++- .../src/opengl/platforms/PlatformCocoaGL.mm | 44 +++++++-- .../opengl/platforms/PlatformCocoaTouchGL.mm | 43 ++++++++- .../src/opengl/platforms/PlatformEGL.cpp | 24 +++-- .../opengl/platforms/PlatformEGLAndroid.cpp | 20 ++++ filament/backend/src/vulkan/VulkanDriver.cpp | 16 ++++ filament/include/filament/Texture.h | 69 +++++++++----- filament/src/Texture.cpp | 4 + filament/src/details/Texture.cpp | 20 ++++ filament/src/details/Texture.h | 1 + 23 files changed, 544 insertions(+), 100 deletions(-) diff --git a/NEW_RELEASE_NOTES.md b/NEW_RELEASE_NOTES.md index 8946d7501f..3482b42bb6 100644 --- a/NEW_RELEASE_NOTES.md +++ b/NEW_RELEASE_NOTES.md @@ -9,3 +9,4 @@ appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md). ## Release notes for next branch cut - matdbg: Add support for debugging ESSL 1.0 shaders +- backend: New platform API to better handle external textures [⚠️ **New Material Version**] diff --git a/filament/backend/include/backend/Platform.h b/filament/backend/include/backend/Platform.h index f9adc51a62..f5a08dad0d 100644 --- a/filament/backend/include/backend/Platform.h +++ b/filament/backend/include/backend/Platform.h @@ -25,6 +25,8 @@ #include #include +#include + namespace filament::backend { class Driver; @@ -41,6 +43,46 @@ public: struct Fence {}; struct Stream {}; + class ExternalImageHandle; + + class ExternalImage { + friend class ExternalImageHandle; + std::atomic_uint32_t mRefCount{0}; + protected: + virtual ~ExternalImage() noexcept; + }; + + class ExternalImageHandle { + ExternalImage* UTILS_NULLABLE mTarget = nullptr; + static void incref(ExternalImage* UTILS_NULLABLE p) noexcept; + static void decref(ExternalImage* UTILS_NULLABLE p) noexcept; + + public: + ExternalImageHandle() noexcept; + ~ExternalImageHandle() noexcept; + explicit ExternalImageHandle(ExternalImage* UTILS_NULLABLE p) noexcept; + ExternalImageHandle(ExternalImageHandle const& rhs) noexcept; + ExternalImageHandle(ExternalImageHandle&& rhs) noexcept; + ExternalImageHandle& operator=(ExternalImageHandle const& rhs) noexcept; + ExternalImageHandle& operator=(ExternalImageHandle&& rhs) noexcept; + + explicit operator bool() const noexcept { return mTarget != nullptr; } + + ExternalImage* UTILS_NULLABLE get() noexcept { return mTarget; } + ExternalImage const* UTILS_NULLABLE get() const noexcept { return mTarget; } + + ExternalImage* UTILS_NULLABLE operator->() noexcept { return mTarget; } + ExternalImage const* UTILS_NULLABLE operator->() const noexcept { return mTarget; } + + ExternalImage& operator*() noexcept { return *mTarget; } + ExternalImage const& operator*() const noexcept { return *mTarget; } + + void clear() noexcept; + void reset(ExternalImage* UTILS_NULLABLE p) noexcept; + }; + + using ExternalImageHandleRef = ExternalImageHandle const&; + /** * The type of technique for stereoscopic rendering. (Note that the materials used will need to * be compatible with the chosen technique.) diff --git a/filament/backend/include/backend/platforms/OpenGLPlatform.h b/filament/backend/include/backend/platforms/OpenGLPlatform.h index e00930c98c..958275cd51 100644 --- a/filament/backend/include/backend/platforms/OpenGLPlatform.h +++ b/filament/backend/include/backend/platforms/OpenGLPlatform.h @@ -51,10 +51,9 @@ protected: ~OpenGLPlatform() noexcept override; public: - struct ExternalTexture { - unsigned int target; // GLenum target - unsigned int id; // GLuint id + unsigned int target; // GLenum target + unsigned int id; // GLuint id }; /** @@ -324,36 +323,45 @@ public: * Destroys an external texture handle and associated data. * @param texture a pointer to the handle to destroy. */ - virtual void destroyExternalImage(ExternalTexture* UTILS_NONNULL texture) noexcept; + virtual void destroyExternalImageTexture(ExternalTexture* UTILS_NONNULL texture) noexcept; // called on the application thread to allow Filament to take ownership of the image /** * Takes ownership of the externalImage. The externalImage parameter depends on the Platform's - * concrete implementation. Ownership is released when destroyExternalImage() is called. + * concrete implementation. Ownership is released when destroyExternalImageTexture() is called. * * WARNING: This is called synchronously from the application thread (NOT the Driver thread) * * @param externalImage A token representing the platform's external image. * @see destroyExternalImage + * @{ */ virtual void retainExternalImage(void* UTILS_NONNULL externalImage) noexcept; + virtual void retainExternalImage(ExternalImageHandleRef externalImage) noexcept; + /** @}*/ + /** * Called to bind the platform-specific externalImage to an ExternalTexture. * ExternalTexture::id is guaranteed to be bound when this method is called and ExternalTexture * is updated with new values for id/target if necessary. * * WARNING: this method is not allowed to change the bound texture, or must restore the previous - * binding upon return. This is to avoid problem with a backend doing state caching. + * binding upon return. This is to avoid a problem with a backend doing state caching. * * @param externalImage The platform-specific external image. * @param texture an in/out pointer to ExternalTexture, id and target can be updated if necessary. * @return true on success, false on error. + * @{ */ virtual bool setExternalImage(void* UTILS_NONNULL externalImage, ExternalTexture* UTILS_NONNULL texture) noexcept; + virtual bool setExternalImage(ExternalImageHandleRef externalImage, + ExternalTexture* UTILS_NONNULL texture) noexcept; + /** @}*/ + /** * The method allows platforms to convert a user-supplied external image object into a new type * (e.g. HardwareBuffer => EGLImage). The default implementation returns source. diff --git a/filament/backend/include/backend/platforms/PlatformCocoaGL.h b/filament/backend/include/backend/platforms/PlatformCocoaGL.h index 97c9c3ce89..869af5c45a 100644 --- a/filament/backend/include/backend/platforms/PlatformCocoaGL.h +++ b/filament/backend/include/backend/platforms/PlatformCocoaGL.h @@ -34,12 +34,14 @@ public: PlatformCocoaGL(); ~PlatformCocoaGL() noexcept override; + ExternalImageHandle createExternalImage(void* cvPixelBuffer) noexcept; + protected: // -------------------------------------------------------------------------------------------- // Platform Interface Driver* createDriver(void* sharedContext, - const Platform::DriverConfig& driverConfig) noexcept override; + const DriverConfig& driverConfig) noexcept override; // Currently returns 0 int getOSVersion() const noexcept override; @@ -59,10 +61,12 @@ protected: void destroySwapChain(SwapChain* swapChain) noexcept override; bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override; void commit(SwapChain* swapChain) noexcept override; - OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override; - void destroyExternalImage(ExternalTexture* texture) noexcept override; + ExternalTexture* createExternalImageTexture() noexcept override; + void destroyExternalImageTexture(ExternalTexture* texture) noexcept override; void retainExternalImage(void* externalImage) noexcept override; bool setExternalImage(void* externalImage, ExternalTexture* texture) noexcept override; + void retainExternalImage(ExternalImageHandleRef externalImage) noexcept override; + bool setExternalImage(ExternalImageHandleRef externalImage, ExternalTexture* texture) noexcept override; private: PlatformCocoaGLImpl* pImpl = nullptr; diff --git a/filament/backend/include/backend/platforms/PlatformCocoaTouchGL.h b/filament/backend/include/backend/platforms/PlatformCocoaTouchGL.h index e7f1d1ffe4..0cea5fe1dc 100644 --- a/filament/backend/include/backend/platforms/PlatformCocoaTouchGL.h +++ b/filament/backend/include/backend/platforms/PlatformCocoaTouchGL.h @@ -32,11 +32,13 @@ public: PlatformCocoaTouchGL(); ~PlatformCocoaTouchGL() noexcept override; + ExternalImageHandle createExternalImage(void* cvPixelBuffer) noexcept; + // -------------------------------------------------------------------------------------------- // Platform Interface Driver* createDriver(void* sharedGLContext, - const Platform::DriverConfig& driverConfig) noexcept override; + const DriverConfig& driverConfig) noexcept override; int getOSVersion() const noexcept final { return 0; } @@ -56,10 +58,12 @@ public: bool makeCurrent(ContextType type, SwapChain* drawSwapChain, SwapChain* readSwapChain) noexcept override; void commit(SwapChain* swapChain) noexcept override; - OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override; - void destroyExternalImage(ExternalTexture* texture) noexcept override; + ExternalTexture* createExternalImageTexture() noexcept override; + void destroyExternalImageTexture(ExternalTexture* texture) noexcept override; void retainExternalImage(void* externalImage) noexcept override; bool setExternalImage(void* externalImage, ExternalTexture* texture) noexcept override; + void retainExternalImage(ExternalImageHandleRef externalImage) noexcept override; + bool setExternalImage(ExternalImageHandleRef externalImage, ExternalTexture* texture) noexcept override; private: PlatformCocoaTouchGLImpl* pImpl = nullptr; diff --git a/filament/backend/include/backend/platforms/PlatformEGL.h b/filament/backend/include/backend/platforms/PlatformEGL.h index ef6876536b..32baeef897 100644 --- a/filament/backend/include/backend/platforms/PlatformEGL.h +++ b/filament/backend/include/backend/platforms/PlatformEGL.h @@ -47,6 +47,11 @@ public: // Return true if we're on an OpenGL platform (as opposed to OpenGL ES). false by default. virtual bool isOpenGL() const noexcept; + /** + * Creates an ExternalImage from a EGLImageKHR + */ + ExternalImageHandle createExternalImage(EGLImageKHR eglImage) noexcept; + protected: // -------------------------------------------------------------------------------------------- // Helper for EGL configs and attributes parameters @@ -118,9 +123,10 @@ protected: void destroyFence(Fence* fence) noexcept override; FenceStatus waitFence(Fence* fence, uint64_t timeout) noexcept override; - OpenGLPlatform::ExternalTexture* createExternalImageTexture() noexcept override; - void destroyExternalImage(ExternalTexture* texture) noexcept override; + ExternalTexture* createExternalImageTexture() noexcept override; + void destroyExternalImageTexture(ExternalTexture* texture) noexcept override; bool setExternalImage(void* externalImage, ExternalTexture* texture) noexcept override; + bool setExternalImage(ExternalImageHandleRef externalImage, ExternalTexture* texture) noexcept override; /** * Logs glGetError() to slog.e @@ -188,6 +194,12 @@ protected: void initializeGlExtensions() noexcept; + struct ExternalImageEGL : public ExternalImage { + EGLImageKHR eglImage = EGL_NO_IMAGE; + protected: + ~ExternalImageEGL() override; + }; + protected: EGLConfig findSwapChainConfig(uint64_t flags, bool window, bool pbuffer) const; diff --git a/filament/backend/include/backend/platforms/PlatformEGLAndroid.h b/filament/backend/include/backend/platforms/PlatformEGLAndroid.h index bc7d0c1f2f..b56d30880b 100644 --- a/filament/backend/include/backend/platforms/PlatformEGLAndroid.h +++ b/filament/backend/include/backend/platforms/PlatformEGLAndroid.h @@ -57,6 +57,11 @@ protected: Driver* createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept override; + /** + * Creates an ExternalImage from a EGLImageKHR + */ + ExternalImageHandle createExternalImage(AHardwareBuffer const *buffer, bool sRGB) noexcept; + // -------------------------------------------------------------------------------------------- // OpenGLPlatform Interface @@ -89,6 +94,15 @@ protected: */ AcquiredImage transformAcquiredImage(AcquiredImage source) noexcept override; + bool setExternalImage(ExternalImageHandleRef externalImage, ExternalTexture* texture) noexcept override; + + struct ExternalImageEGLAndroid : public ExternalImageEGL { + AHardwareBuffer* aHardwareBuffer = nullptr; + bool sRGB = false; + protected: + ~ExternalImageEGLAndroid() override; + }; + protected: bool makeCurrent(ContextType type, SwapChain* drawSwapChain, diff --git a/filament/backend/include/private/backend/DriverAPI.inc b/filament/backend/include/private/backend/DriverAPI.inc index 2c22147aaa..2f2921e671 100644 --- a/filament/backend/include/private/backend/DriverAPI.inc +++ b/filament/backend/include/private/backend/DriverAPI.inc @@ -215,6 +215,14 @@ DECL_DRIVER_API_R_N(backend::TextureHandle, createTextureViewSwizzle, backend::TextureSwizzle, b, backend::TextureSwizzle, a) +DECL_DRIVER_API_R_N(backend::TextureHandle, createTextureExternalImage2, + backend::SamplerType, target, + backend::TextureFormat, format, + uint32_t, width, + uint32_t, height, + backend::TextureUsage, usage, + backend::Platform::ExternalImageHandleRef, image) + DECL_DRIVER_API_R_N(backend::TextureHandle, createTextureExternalImage, backend::SamplerType, target, backend::TextureFormat, format, @@ -355,6 +363,7 @@ DECL_DRIVER_API_SYNCHRONOUS_0(bool, isDepthClampSupported) DECL_DRIVER_API_SYNCHRONOUS_0(uint8_t, getMaxDrawBuffers) DECL_DRIVER_API_SYNCHRONOUS_0(size_t, getMaxUniformBufferSize) DECL_DRIVER_API_SYNCHRONOUS_0(math::float2, getClipSpaceParams) +DECL_DRIVER_API_SYNCHRONOUS_N(void, setupExternalImage2, backend::Platform::ExternalImageHandleRef, image) DECL_DRIVER_API_SYNCHRONOUS_N(void, setupExternalImage, void*, image) DECL_DRIVER_API_SYNCHRONOUS_N(backend::TimerQueryResult, getTimerQueryValue, backend::TimerQueryHandle, query, uint64_t*, elapsedTime) DECL_DRIVER_API_SYNCHRONOUS_N(bool, isWorkaroundNeeded, backend::Workaround, workaround) diff --git a/filament/backend/src/Platform.cpp b/filament/backend/src/Platform.cpp index 77c8512941..b603155923 100644 --- a/filament/backend/src/Platform.cpp +++ b/filament/backend/src/Platform.cpp @@ -16,8 +16,93 @@ #include +#include + +#include +#include + +#include +#include + namespace filament::backend { +void Platform::ExternalImageHandle::incref(ExternalImage* p) noexcept { + if (p) { + // incrementing the ref-count doesn't acquire or release anything + p->mRefCount.fetch_add(1, std::memory_order_relaxed); + } +} + +void Platform::ExternalImageHandle::decref(ExternalImage* p) noexcept { + if (p) { + // When decrementing the ref-count, unless it reaches zero, there is no need to acquire data; we need to + // release all previous writes though so they can be visible to the thread that will actually delete the + // object. + if (p->mRefCount.fetch_sub(1, std::memory_order_release) == 1) { + // if we reach zero, we're about to delete the object, we need to acquire all previous writes from other + // threads (i.e.: the memory from other threads prior to the decref() need to be visible now. + std::atomic_thread_fence(std::memory_order_acquire); + delete p; + } + } +} + +Platform::ExternalImageHandle::ExternalImageHandle() noexcept = default; + +Platform::ExternalImageHandle::~ExternalImageHandle() noexcept { + decref(mTarget); +} + +Platform::ExternalImageHandle::ExternalImageHandle(ExternalImage* p) noexcept + : mTarget(p) { + incref(mTarget); +} + +Platform::ExternalImageHandle::ExternalImageHandle(ExternalImageHandle const& rhs) noexcept + : mTarget(rhs.mTarget) { + incref(mTarget); +} + +Platform::ExternalImageHandle::ExternalImageHandle(ExternalImageHandle&& rhs) noexcept + : mTarget(rhs.mTarget) { + rhs.mTarget = nullptr; +} + +Platform::ExternalImageHandle& Platform::ExternalImageHandle::operator=(ExternalImageHandle const& rhs) noexcept { + if (UTILS_LIKELY(this != &rhs)) { + incref(rhs.mTarget); + decref(mTarget); + mTarget = rhs.mTarget; + } + return *this; +} + +Platform::ExternalImageHandle& Platform::ExternalImageHandle::operator=(ExternalImageHandle&& rhs) noexcept { + if (UTILS_LIKELY(this != &rhs)) { + decref(mTarget); + mTarget = rhs.mTarget; + rhs.mTarget = nullptr; + } + return *this; +} + +void Platform::ExternalImageHandle::clear() noexcept { + decref(mTarget); + mTarget = nullptr; +} + +void Platform::ExternalImageHandle::reset(ExternalImage* p) noexcept { + incref(p); + decref(mTarget); + mTarget = p; +} + +// -------------------------------------------------------------------------------------------------------------------- + +Platform::ExternalImage::~ExternalImage() noexcept = default; + +// -------------------------------------------------------------------------------------------------------------------- + Platform::Platform() noexcept = default; // this generates the vtable in this translation unit diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index 5e14c55b52..4f8010ed93 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -513,6 +513,14 @@ void MetalDriver::createTextureViewSwizzleR(Handle th, Handletextures.insert(construct_handle(th, *mContext, src, r, g, b, a)); } +void MetalDriver::createTextureExternalImage2R(Handle th, + backend::SamplerType target, + backend::TextureFormat format, + uint32_t width, uint32_t height, backend::TextureUsage usage, + Platform::ExternalImageHandleRef image) { + // FIXME: implement createTextureExternalImage2R +} + void MetalDriver::createTextureExternalImageR(Handle th, backend::SamplerType target, backend::TextureFormat format, @@ -747,6 +755,10 @@ Handle MetalDriver::createTextureViewSwizzleS() noexcept { return alloc_handle(); } +Handle MetalDriver::createTextureExternalImage2S() noexcept { + return alloc_handle(); +} + Handle MetalDriver::createTextureExternalImageS() noexcept { return alloc_handle(); } @@ -1218,6 +1230,10 @@ void MetalDriver::update3DImage(Handle th, uint32_t level, th.getId(), level, xoffset, yoffset, zoffset, width, height, depth); } +void MetalDriver::setupExternalImage2(Platform::ExternalImageHandleRef image) { + // FIXME: implement setupExternalImage2 +} + void MetalDriver::setupExternalImage(void* image) { // setupExternalImage is called on the Filament thread when creating a Texture or SwapChain from // a CVPixelBuffer external image. Here we take ownership of the passed in buffer by calling diff --git a/filament/backend/src/noop/NoopDriver.cpp b/filament/backend/src/noop/NoopDriver.cpp index a77200c6fb..f31a6343da 100644 --- a/filament/backend/src/noop/NoopDriver.cpp +++ b/filament/backend/src/noop/NoopDriver.cpp @@ -17,6 +17,10 @@ #include "noop/NoopDriver.h" #include "CommandStreamDispatcher.h" +#include + +#include + namespace filament::backend { Driver* NoopDriver::create() { @@ -262,6 +266,9 @@ void NoopDriver::update3DImage(Handle th, scheduleDestroy(std::move(data)); } +void NoopDriver::setupExternalImage2(Platform::ExternalImageHandleRef image) { +} + void NoopDriver::setupExternalImage(void* image) { } diff --git a/filament/backend/src/opengl/GLUtils.h b/filament/backend/src/opengl/GLUtils.h index dc9df7871a..6559148a1e 100644 --- a/filament/backend/src/opengl/GLUtils.h +++ b/filament/backend/src/opengl/GLUtils.h @@ -18,6 +18,7 @@ #define TNT_FILAMENT_BACKEND_OPENGL_GLUTILS_H #include +#include #include #include @@ -25,6 +26,8 @@ #include #include +#include +#include #include #include "gl_headers.h" @@ -50,7 +53,7 @@ void assertFramebufferStatus(utils::io::ostream& out, GLenum target, const char* # define CHECK_GL_FRAMEBUFFER_STATUS(out, target) { GLUtils::checkFramebufferStatus(out, target, __func__, __LINE__); } #endif -constexpr inline GLuint getComponentCount(ElementType type) noexcept { +constexpr GLuint getComponentCount(ElementType type) noexcept { using ElementType = ElementType; switch (type) { case ElementType::BYTE: @@ -90,7 +93,7 @@ constexpr inline GLuint getComponentCount(ElementType type) noexcept { // Our enums to GLenum conversions // ------------------------------------------------------------------------------------------------ -constexpr inline GLbitfield getAttachmentBitfield(TargetBufferFlags flags) noexcept { +constexpr GLbitfield getAttachmentBitfield(TargetBufferFlags flags) noexcept { GLbitfield mask = 0; if (any(flags & TargetBufferFlags::COLOR_ALL)) { mask |= (GLbitfield)GL_COLOR_BUFFER_BIT; @@ -104,7 +107,7 @@ constexpr inline GLbitfield getAttachmentBitfield(TargetBufferFlags flags) noexc return mask; } -constexpr inline GLenum getBufferUsage(BufferUsage usage) noexcept { +constexpr GLenum getBufferUsage(BufferUsage usage) noexcept { switch (usage) { case BufferUsage::STATIC: return GL_STATIC_DRAW; @@ -113,7 +116,7 @@ constexpr inline GLenum getBufferUsage(BufferUsage usage) noexcept { } } -constexpr inline GLenum getBufferBindingType(BufferObjectBinding bindingType) noexcept { +constexpr GLenum getBufferBindingType(BufferObjectBinding bindingType) noexcept { switch (bindingType) { case BufferObjectBinding::VERTEX: return GL_ARRAY_BUFFER; @@ -134,11 +137,11 @@ constexpr inline GLenum getBufferBindingType(BufferObjectBinding bindingType) no } } -constexpr inline GLboolean getNormalization(bool normalized) noexcept { +constexpr GLboolean getNormalization(bool normalized) noexcept { return GLboolean(normalized ? GL_TRUE : GL_FALSE); } -constexpr inline GLenum getComponentType(ElementType type) noexcept { +constexpr GLenum getComponentType(ElementType type) noexcept { using ElementType = ElementType; switch (type) { case ElementType::BYTE: @@ -183,12 +186,30 @@ constexpr inline GLenum getComponentType(ElementType type) noexcept { } } -constexpr inline GLenum getCubemapTarget(uint16_t layer) noexcept { +constexpr GLenum getTextureTargetNotExternal(SamplerType target) noexcept { + switch (target) { + case SamplerType::SAMPLER_2D: + return GL_TEXTURE_2D; + case SamplerType::SAMPLER_3D: + return GL_TEXTURE_3D; + case SamplerType::SAMPLER_2D_ARRAY: + return GL_TEXTURE_2D_ARRAY; + case SamplerType::SAMPLER_CUBEMAP: + return GL_TEXTURE_CUBE_MAP; + case SamplerType::SAMPLER_CUBEMAP_ARRAY: + return GL_TEXTURE_CUBE_MAP_ARRAY; + case SamplerType::SAMPLER_EXTERNAL: + // we should never be here + return GL_TEXTURE_2D; + } +} + +constexpr GLenum getCubemapTarget(uint16_t layer) noexcept { assert_invariant(layer <= 5); return GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer; } -constexpr inline GLenum getWrapMode(SamplerWrapMode mode) noexcept { +constexpr GLenum getWrapMode(SamplerWrapMode mode) noexcept { using SamplerWrapMode = SamplerWrapMode; switch (mode) { case SamplerWrapMode::REPEAT: @@ -200,7 +221,7 @@ constexpr inline GLenum getWrapMode(SamplerWrapMode mode) noexcept { } } -constexpr inline GLenum getTextureFilter(SamplerMinFilter filter) noexcept { +constexpr GLenum getTextureFilter(SamplerMinFilter filter) noexcept { using SamplerMinFilter = SamplerMinFilter; switch (filter) { case SamplerMinFilter::NEAREST: @@ -215,12 +236,12 @@ constexpr inline GLenum getTextureFilter(SamplerMinFilter filter) noexcept { } } -constexpr inline GLenum getTextureFilter(SamplerMagFilter filter) noexcept { +constexpr GLenum getTextureFilter(SamplerMagFilter filter) noexcept { return GL_NEAREST + GLenum(filter); } -constexpr inline GLenum getBlendEquationMode(BlendEquation mode) noexcept { +constexpr GLenum getBlendEquationMode(BlendEquation mode) noexcept { using BlendEquation = BlendEquation; switch (mode) { case BlendEquation::ADD: return GL_FUNC_ADD; @@ -231,7 +252,7 @@ constexpr inline GLenum getBlendEquationMode(BlendEquation mode) noexcept { } } -constexpr inline GLenum getBlendFunctionMode(BlendFunction mode) noexcept { +constexpr GLenum getBlendFunctionMode(BlendFunction mode) noexcept { using BlendFunction = BlendFunction; switch (mode) { case BlendFunction::ZERO: return GL_ZERO; @@ -248,7 +269,7 @@ constexpr inline GLenum getBlendFunctionMode(BlendFunction mode) noexcept { } } -constexpr inline GLenum getCompareFunc(SamplerCompareFunc func) noexcept { +constexpr GLenum getCompareFunc(SamplerCompareFunc func) noexcept { switch (func) { case SamplerCompareFunc::LE: return GL_LEQUAL; case SamplerCompareFunc::GE: return GL_GEQUAL; @@ -262,25 +283,25 @@ constexpr inline GLenum getCompareFunc(SamplerCompareFunc func) noexcept { } #ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2 -constexpr inline GLenum getTextureCompareMode(SamplerCompareMode mode) noexcept { +constexpr GLenum getTextureCompareMode(SamplerCompareMode mode) noexcept { return mode == SamplerCompareMode::NONE ? GL_NONE : GL_COMPARE_REF_TO_TEXTURE; } -constexpr inline GLenum getTextureCompareFunc(SamplerCompareFunc func) noexcept { +constexpr GLenum getTextureCompareFunc(SamplerCompareFunc func) noexcept { return getCompareFunc(func); } #endif -constexpr inline GLenum getDepthFunc(SamplerCompareFunc func) noexcept { +constexpr GLenum getDepthFunc(SamplerCompareFunc func) noexcept { return getCompareFunc(func); } -constexpr inline GLenum getStencilFunc(SamplerCompareFunc func) noexcept { +constexpr GLenum getStencilFunc(SamplerCompareFunc func) noexcept { return getCompareFunc(func); } -constexpr inline GLenum getStencilOp(StencilOperation op) noexcept { +constexpr GLenum getStencilOp(StencilOperation op) noexcept { switch (op) { case StencilOperation::KEEP: return GL_KEEP; case StencilOperation::ZERO: return GL_ZERO; @@ -293,7 +314,7 @@ constexpr inline GLenum getStencilOp(StencilOperation op) noexcept { } } -constexpr inline GLenum getFormat(PixelDataFormat format) noexcept { +constexpr GLenum getFormat(PixelDataFormat format) noexcept { using PixelDataFormat = PixelDataFormat; switch (format) { case PixelDataFormat::RGB: return GL_RGB; @@ -317,7 +338,7 @@ constexpr inline GLenum getFormat(PixelDataFormat format) noexcept { } } -constexpr inline GLenum getType(PixelDataType type) noexcept { +constexpr GLenum getType(PixelDataType type) noexcept { using PixelDataType = PixelDataType; switch (type) { case PixelDataType::UBYTE: return GL_UNSIGNED_BYTE; @@ -342,7 +363,7 @@ constexpr inline GLenum getType(PixelDataType type) noexcept { } #if !defined(__EMSCRIPTEN__) && !defined(FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2) -constexpr inline GLenum getSwizzleChannel(TextureSwizzle c) noexcept { +constexpr GLenum getSwizzleChannel(TextureSwizzle c) noexcept { using TextureSwizzle = TextureSwizzle; switch (c) { case TextureSwizzle::SUBSTITUTE_ZERO: return GL_ZERO; @@ -355,7 +376,7 @@ constexpr inline GLenum getSwizzleChannel(TextureSwizzle c) noexcept { } #endif -constexpr inline GLenum getCullingMode(CullingMode mode) noexcept { +constexpr GLenum getCullingMode(CullingMode mode) noexcept { switch (mode) { case CullingMode::NONE: // should never happen @@ -370,7 +391,7 @@ constexpr inline GLenum getCullingMode(CullingMode mode) noexcept { } // ES2 supported internal formats for texturing and how they map to a format/type -constexpr inline std::pair textureFormatToFormatAndType( +constexpr std::pair textureFormatToFormatAndType( TextureFormat format) noexcept { switch (format) { case TextureFormat::R8: return { 0x1909 /*GL_LUMINANCE*/, GL_UNSIGNED_BYTE }; diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 9b5b13ed60..86c45f14fc 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -582,6 +582,10 @@ Handle OpenGLDriver::createTextureViewSwizzleS() noexcept { return initHandle(); } +Handle OpenGLDriver::createTextureExternalImage2S() noexcept { + return initHandle(); +} + Handle OpenGLDriver::createTextureExternalImageS() noexcept { return initHandle(); } @@ -903,25 +907,7 @@ void OpenGLDriver::createTextureR(Handle th, SamplerType target, uint t->gl.internalFormat = internalFormat; - switch (target) { - case SamplerType::SAMPLER_EXTERNAL: - // we can't be here -- doesn't matter what we do - case SamplerType::SAMPLER_2D: - t->gl.target = GL_TEXTURE_2D; - break; - case SamplerType::SAMPLER_3D: - t->gl.target = GL_TEXTURE_3D; - break; - case SamplerType::SAMPLER_2D_ARRAY: - t->gl.target = GL_TEXTURE_2D_ARRAY; - break; - case SamplerType::SAMPLER_CUBEMAP: - t->gl.target = GL_TEXTURE_CUBE_MAP; - break; - case SamplerType::SAMPLER_CUBEMAP_ARRAY: - t->gl.target = GL_TEXTURE_CUBE_MAP_ARRAY; - break; - } + t->gl.target = getTextureTargetNotExternal(target); if (t->samples > 1) { // Note: we can't be here in practice because filament's user API doesn't @@ -995,8 +981,7 @@ void OpenGLDriver::createTextureViewR(Handle th, } void OpenGLDriver::createTextureViewSwizzleR(Handle th, Handle srch, - backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b, - backend::TextureSwizzle a) { + TextureSwizzle r, TextureSwizzle g, TextureSwizzle b, TextureSwizzle a) { DEBUG_MARKER() GLTexture const* const src = handle_cast(srch); @@ -1058,6 +1043,57 @@ void OpenGLDriver::createTextureViewSwizzleR(Handle th, Handle th, SamplerType target, + TextureFormat format, uint32_t width, uint32_t height, TextureUsage usage, + Platform::ExternalImageHandleRef image) { + DEBUG_MARKER() + + usage |= TextureUsage::SAMPLEABLE; + usage &= ~TextureUsage::UPLOADABLE; + + auto& gl = mContext; + GLenum internalFormat = getInternalFormat(format); + if (UTILS_UNLIKELY(gl.isES2())) { + // on ES2, format and internal format must match + // FIXME: handle compressed texture format + internalFormat = textureFormatToFormatAndType(format).first; + } + assert_invariant(internalFormat); + + GLTexture* const t = construct(th, target, 1, 1, width, height, 1, format, usage); + assert_invariant(t); + + t->externalTexture = mPlatform.createExternalImageTexture(); + if (t->externalTexture) { + if (target == SamplerType::SAMPLER_EXTERNAL) { + if (UTILS_LIKELY(gl.ext.OES_EGL_image_external_essl3)) { + t->externalTexture->target = GL_TEXTURE_EXTERNAL_OES; + } else { + // revert to texture 2D if external is not supported; what else can we do? + t->externalTexture->target = GL_TEXTURE_2D; + } + } else { + t->externalTexture->target = getTextureTargetNotExternal(target); + } + + t->gl.target = t->externalTexture->target; + t->gl.id = t->externalTexture->id; + // internalFormat actually depends on the external image, but it doesn't matter + // because it's not used anywhere for anything important. + t->gl.internalFormat = internalFormat; + t->gl.baseLevel = 0; + t->gl.maxLevel = 0; + t->gl.external = true; // forces bindTexture() call (they're never cached) + } + + bindTexture(OpenGLContext::DUMMY_TEXTURE_BINDING, t); + if (mPlatform.setExternalImage(image, t->externalTexture)) { + // the target and id can be reset each time + t->gl.target = t->externalTexture->target; + t->gl.id = t->externalTexture->id; + } +} + void OpenGLDriver::createTextureExternalImageR(Handle th, SamplerType target, TextureFormat format, uint32_t width, uint32_t height, TextureUsage usage, void* image) { DEBUG_MARKER() @@ -1079,6 +1115,16 @@ void OpenGLDriver::createTextureExternalImageR(Handle th, SamplerType t->externalTexture = mPlatform.createExternalImageTexture(); if (t->externalTexture) { + if (target == SamplerType::SAMPLER_EXTERNAL) { + if (UTILS_LIKELY(gl.ext.OES_EGL_image_external_essl3)) { + t->externalTexture->target = GL_TEXTURE_EXTERNAL_OES; + } else { + // revert to texture 2D if external is not supported; what else can we do? + t->externalTexture->target = GL_TEXTURE_2D; + } + } else { + t->externalTexture->target = getTextureTargetNotExternal(target); + } t->gl.target = t->externalTexture->target; t->gl.id = t->externalTexture->id; // internalFormat actually depends on the external image, but it doesn't matter @@ -1870,7 +1916,7 @@ void OpenGLDriver::destroyTexture(Handle th) { detachStream(t); } if (UTILS_UNLIKELY(t->target == SamplerType::SAMPLER_EXTERNAL)) { - mPlatform.destroyExternalImage(t->externalTexture); + mPlatform.destroyExternalImageTexture(t->externalTexture); } else { glDeleteTextures(1, &t->gl.id); } @@ -2809,6 +2855,10 @@ void OpenGLDriver::setCompressedTextureData(GLTexture* t, uint32_t level, CHECK_GL_ERROR(utils::slog.e) } +void OpenGLDriver::setupExternalImage2(Platform::ExternalImageHandleRef image) { + mPlatform.retainExternalImage(image); +} + void OpenGLDriver::setupExternalImage(void* image) { mPlatform.retainExternalImage(image); } diff --git a/filament/backend/src/opengl/OpenGLPlatform.cpp b/filament/backend/src/opengl/OpenGLPlatform.cpp index 94c3b99112..3ba229fb32 100644 --- a/filament/backend/src/opengl/OpenGLPlatform.cpp +++ b/filament/backend/src/opengl/OpenGLPlatform.cpp @@ -121,14 +121,24 @@ OpenGLPlatform::ExternalTexture* OpenGLPlatform::createExternalImageTexture() no return nullptr; } -void OpenGLPlatform::destroyExternalImage( +void OpenGLPlatform::destroyExternalImageTexture( UTILS_UNUSED ExternalTexture* texture) noexcept { } +void OpenGLPlatform::retainExternalImage( + UTILS_UNUSED ExternalImageHandleRef externalImage) noexcept { +} + void OpenGLPlatform::retainExternalImage( UTILS_UNUSED void* externalImage) noexcept { } +bool OpenGLPlatform::setExternalImage( + UTILS_UNUSED ExternalImageHandleRef externalImage, + UTILS_UNUSED ExternalTexture* texture) noexcept { + return false; +} + bool OpenGLPlatform::setExternalImage( UTILS_UNUSED void* externalImage, UTILS_UNUSED ExternalTexture* texture) noexcept { diff --git a/filament/backend/src/opengl/platforms/PlatformCocoaGL.mm b/filament/backend/src/opengl/platforms/PlatformCocoaGL.mm index b62783c1dc..246f4c08ac 100644 --- a/filament/backend/src/opengl/platforms/PlatformCocoaGL.mm +++ b/filament/backend/src/opengl/platforms/PlatformCocoaGL.mm @@ -54,8 +54,15 @@ struct PlatformCocoaGLImpl { CVOpenGLTextureCacheRef mTextureCache = nullptr; std::unique_ptr mExternalImageSharedGl; void updateOpenGLContext(NSView *nsView, bool resetView, bool clearView); + struct ExternalImageCocoaGL : public Platform::ExternalImage { + CVPixelBufferRef cvBuffer; + protected: + ~ExternalImageCocoaGL() noexcept final; + }; }; +PlatformCocoaGLImpl::ExternalImageCocoaGL::~ExternalImageCocoaGL() noexcept = default; + CocoaGLSwapChain::CocoaGLSwapChain( NSView* inView ) : view(inView) , previousBounds(NSZeroRect) @@ -309,17 +316,12 @@ OpenGLPlatform::ExternalTexture* PlatformCocoaGL::createExternalImageTexture() n if (!pImpl->mExternalImageSharedGl) { pImpl->mExternalImageSharedGl = std::make_unique(); } - ExternalTexture* outTexture = new CocoaExternalImage(pImpl->mTextureCache, *pImpl->mExternalImageSharedGl); - - // the actual id/target will be set in setExternalImage. - outTexture->id = 0; - outTexture->target = GL_TEXTURE_2D; return outTexture; } -void PlatformCocoaGL::destroyExternalImage(ExternalTexture* texture) noexcept { +void PlatformCocoaGL::destroyExternalImageTexture(ExternalTexture* texture) noexcept { auto* p = static_cast(texture); delete p; } @@ -344,6 +346,36 @@ bool PlatformCocoaGL::setExternalImage(void* externalImage, ExternalTexture* tex return true; } +Platform::ExternalImageHandle PlatformCocoaGL::createExternalImage(void* cvPixelBuffer) noexcept { + auto* p = new(std::nothrow) PlatformCocoaGLImpl::ExternalImageCocoaGL; + p->cvBuffer = (CVPixelBufferRef) cvPixelBuffer; + return ExternalImageHandle{ p }; +} + +void PlatformCocoaGL::retainExternalImage(ExternalImageHandleRef externalImage) noexcept { + auto const* const cocoaGlExternalImage + = static_cast(externalImage.get()); + // Take ownership of the passed in buffer. It will be released the next time + // setExternalImage is called, or when the texture is destroyed. + CVPixelBufferRef pixelBuffer = cocoaGlExternalImage->cvBuffer; + CVPixelBufferRetain(pixelBuffer); +} + +bool PlatformCocoaGL::setExternalImage(ExternalImageHandleRef externalImage, ExternalTexture* texture) noexcept { + auto const* const cocoaGlExternalImage + = static_cast(externalImage.get()); + CVPixelBufferRef cvPixelBuffer = cocoaGlExternalImage->cvBuffer; + CocoaExternalImage* cocoaExternalImage = static_cast(texture); + if (!cocoaExternalImage->set(cvPixelBuffer)) { + return false; + } + texture->target = cocoaExternalImage->getTarget(); + texture->id = cocoaExternalImage->getGlTexture(); + // we used to set the internalFormat, but it's not used anywhere on the gl backend side + // cocoaExternalImage->getInternalFormat(); + return true; +} + void PlatformCocoaGLImpl::updateOpenGLContext(NSView *nsView, bool resetView, bool clearView) { NSOpenGLContext* glContext = mGLContext; diff --git a/filament/backend/src/opengl/platforms/PlatformCocoaTouchGL.mm b/filament/backend/src/opengl/platforms/PlatformCocoaTouchGL.mm index 326f55f06d..e37e61a109 100644 --- a/filament/backend/src/opengl/platforms/PlatformCocoaTouchGL.mm +++ b/filament/backend/src/opengl/platforms/PlatformCocoaTouchGL.mm @@ -47,8 +47,15 @@ struct PlatformCocoaTouchGLImpl { GLuint mDefaultDepthbuffer = 0; CVOpenGLESTextureCacheRef mTextureCache = nullptr; CocoaTouchExternalImage::SharedGl* mExternalImageSharedGl = nullptr; + struct ExternalImageCocoaTouchGL : public Platform::ExternalImage { + CVPixelBufferRef cvBuffer; + protected: + ~ExternalImageCocoaTouchGL() noexcept final; + }; }; +PlatformCocoaTouchGLImpl::ExternalImageCocoaTouchGL::~ExternalImageCocoaTouchGL() noexcept = default; + PlatformCocoaTouchGL::PlatformCocoaTouchGL() : pImpl(new PlatformCocoaTouchGLImpl) { } @@ -198,13 +205,10 @@ void PlatformCocoaTouchGL::commit(Platform::SwapChain* swapChain) noexcept { OpenGLPlatform::ExternalTexture* PlatformCocoaTouchGL::createExternalImageTexture() noexcept { ExternalTexture* outTexture = new CocoaTouchExternalImage(pImpl->mTextureCache, *pImpl->mExternalImageSharedGl); - // the actual id/target will be set in setExternalImage*( - outTexture->id = 0; - outTexture->target = GL_TEXTURE_2D; return outTexture; } -void PlatformCocoaTouchGL::destroyExternalImage(ExternalTexture* texture) noexcept { +void PlatformCocoaTouchGL::destroyExternalImageTexture(ExternalTexture* texture) noexcept { auto* p = static_cast(texture); delete p; } @@ -229,4 +233,35 @@ bool PlatformCocoaTouchGL::setExternalImage(void* externalImage, ExternalTexture return true; } +Platform::ExternalImageHandle PlatformCocoaTouchGL::createExternalImage(void* cvPixelBuffer) noexcept { + auto* p = new(std::nothrow) PlatformCocoaTouchGLImpl::ExternalImageCocoaTouchGL; + p->cvBuffer = (CVPixelBufferRef) cvPixelBuffer; + return ExternalImageHandle{ p }; +} + +void PlatformCocoaTouchGL::retainExternalImage(ExternalImageHandleRef externalImage) noexcept { + auto const* const cocoaTouchGlExternalImage + = static_cast(externalImage.get()); + // Take ownership of the passed in buffer. It will be released the next time + // setExternalImage is called, or when the texture is destroyed. + CVPixelBufferRef pixelBuffer = cocoaTouchGlExternalImage->cvBuffer; + CVPixelBufferRetain(pixelBuffer); +} + +bool PlatformCocoaTouchGL::setExternalImage(ExternalImageHandleRef externalImage, ExternalTexture* texture) noexcept { + auto const* const cocoaTouchGlExternalImage + = static_cast(externalImage.get()); + CVPixelBufferRef cvPixelBuffer = cocoaTouchGlExternalImage->cvBuffer; + CocoaTouchExternalImage* cocoaExternalImage = static_cast(texture); + if (!cocoaExternalImage->set(cvPixelBuffer)) { + return false; + } + texture->target = cocoaExternalImage->getTarget(); + texture->id = cocoaExternalImage->getGlTexture(); + // we used to set the internalFormat, but it's not used anywhere on the gl backend side + // cocoaExternalImage->getInternalFormat(); + return true; +} + + } // namespace filament::backend diff --git a/filament/backend/src/opengl/platforms/PlatformEGL.cpp b/filament/backend/src/opengl/platforms/PlatformEGL.cpp index 9e6b628f02..3190ab3246 100644 --- a/filament/backend/src/opengl/platforms/PlatformEGL.cpp +++ b/filament/backend/src/opengl/platforms/PlatformEGL.cpp @@ -117,7 +117,9 @@ bool PlatformEGL::isOpenGL() const noexcept { return false; } -Driver* PlatformEGL::createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept { +PlatformEGL::ExternalImageEGL::~ExternalImageEGL() = default; + +Driver* PlatformEGL::createDriver(void* sharedContext, const DriverConfig& driverConfig) noexcept { mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); assert_invariant(mEGLDisplay != EGL_NO_DISPLAY); @@ -699,16 +701,10 @@ FenceStatus PlatformEGL::waitFence( OpenGLPlatform::ExternalTexture* PlatformEGL::createExternalImageTexture() noexcept { ExternalTexture* outTexture = new(std::nothrow) ExternalTexture{}; glGenTextures(1, &outTexture->id); - if (UTILS_LIKELY(ext.gl.OES_EGL_image_external_essl3)) { - outTexture->target = GL_TEXTURE_EXTERNAL_OES; - } else { - // if texture external is not supported, revert to texture 2d - outTexture->target = GL_TEXTURE_2D; - } return outTexture; } -void PlatformEGL::destroyExternalImage(ExternalTexture* texture) noexcept { +void PlatformEGL::destroyExternalImageTexture(ExternalTexture* texture) noexcept { glDeleteTextures(1, &texture->id); delete texture; } @@ -728,6 +724,18 @@ bool PlatformEGL::setExternalImage(void* externalImage, return true; } +Platform::ExternalImageHandle PlatformEGL::createExternalImage(EGLImageKHR eglImage) noexcept { + auto* const p = new(std::nothrow) ExternalImageEGL; + p->eglImage = eglImage; + return ExternalImageHandle{p}; +} + +bool PlatformEGL::setExternalImage(ExternalImageHandleRef externalImage, + UTILS_UNUSED_IN_RELEASE ExternalTexture* texture) noexcept { + auto const* const eglExternalImage = static_cast(externalImage.get()); + return setExternalImage(eglExternalImage->eglImage, texture); +} + // ----------------------------------------------------------------------------------------------- void PlatformEGL::initializeGlExtensions() noexcept { diff --git a/filament/backend/src/opengl/platforms/PlatformEGLAndroid.cpp b/filament/backend/src/opengl/platforms/PlatformEGLAndroid.cpp index 07e4b10d36..73828f74ca 100644 --- a/filament/backend/src/opengl/platforms/PlatformEGLAndroid.cpp +++ b/filament/backend/src/opengl/platforms/PlatformEGLAndroid.cpp @@ -231,6 +231,26 @@ Driver* PlatformEGLAndroid::createDriver(void* sharedContext, return driver; } +PlatformEGLAndroid::ExternalImageEGLAndroid::~ExternalImageEGLAndroid() = default; + +Platform::ExternalImageHandle PlatformEGLAndroid::createExternalImage(AHardwareBuffer const* buffer, bool sRGB) noexcept { + auto* const p = new(std::nothrow) ExternalImageEGLAndroid; + p->aHardwareBuffer = const_cast(buffer); + p->sRGB = sRGB; + return ExternalImageHandle{ p }; +} + +bool PlatformEGLAndroid::setExternalImage(ExternalImageHandleRef externalImage, + UTILS_UNUSED_IN_RELEASE ExternalTexture* texture) noexcept { + auto const* const eglExternalImage = static_cast(externalImage.get()); + if (eglExternalImage->aHardwareBuffer) { + // TODO: implement PlatformEGLAndroid::setExternalImage w/ AHardwareBuffer + return true; + } + // not a AHardwareBuffer, fallback to the inherited version + return PlatformEGL::setExternalImage(externalImage, texture); +} + void PlatformEGLAndroid::setPresentationTime(int64_t presentationTimeInNanosecond) noexcept { EGLSurface currentDrawSurface = eglGetCurrentSurface(EGL_DRAW); if (currentDrawSurface != EGL_NO_SURFACE) { diff --git a/filament/backend/src/vulkan/VulkanDriver.cpp b/filament/backend/src/vulkan/VulkanDriver.cpp index 9df949d685..615cf05221 100644 --- a/filament/backend/src/vulkan/VulkanDriver.cpp +++ b/filament/backend/src/vulkan/VulkanDriver.cpp @@ -552,6 +552,15 @@ void VulkanDriver::createTextureViewSwizzleR(Handle th, Handle th, + backend::SamplerType target, backend::TextureFormat format, + uint32_t width, uint32_t height, backend::TextureUsage usage, + Platform::ExternalImageHandleRef externalImage) { + FVK_SYSTRACE_SCOPE(); + + // FIXME: implement createTextureExternalImage2R +} + void VulkanDriver::createTextureExternalImageR(Handle th, backend::SamplerType target, backend::TextureFormat format, uint32_t width, uint32_t height, backend::TextureUsage usage, void* externalImage) { @@ -792,6 +801,10 @@ Handle VulkanDriver::createTextureViewSwizzleS() noexcept { return mResourceManager.allocHandle(); } +Handle VulkanDriver::createTextureExternalImage2S() noexcept { + return mResourceManager.allocHandle(); +} + Handle VulkanDriver::createTextureExternalImageS() noexcept { return mResourceManager.allocHandle(); } @@ -1171,6 +1184,9 @@ void VulkanDriver::update3DImage(Handle th, uint32_t level, uint32_t scheduleDestroy(std::move(data)); } +void VulkanDriver::setupExternalImage2(Platform::ExternalImageHandleRef image) { +} + void VulkanDriver::setupExternalImage(void* image) { } diff --git a/filament/include/filament/Texture.h b/filament/include/filament/Texture.h index 12b28358a9..62ab509435 100644 --- a/filament/include/filament/Texture.h +++ b/filament/include/filament/Texture.h @@ -23,6 +23,7 @@ #include #include +#include #include @@ -70,7 +71,7 @@ class UTILS_PUBLIC Texture : public FilamentAPI { struct BuilderDetails; public: - static constexpr const size_t BASE_LEVEL = 0; + static constexpr size_t BASE_LEVEL = 0; //! Face offsets for all faces of a cubemap struct FaceOffsets; @@ -84,14 +85,16 @@ public: using CompressedType = backend::CompressedPixelDataType; //!< Compressed pixel data format using Usage = backend::TextureUsage; //!< Usage affects texel layout using Swizzle = backend::TextureSwizzle; //!< Texture swizzle + using ExternalImageHandle = backend::Platform::ExternalImageHandle; + using ExternalImageHandleRef = backend::Platform::ExternalImageHandleRef; - /** @return whether a backend supports a particular format. */ + /** @return Whether a backend supports a particular format. */ static bool isTextureFormatSupported(Engine& engine, InternalFormat format) noexcept; - /** @return whether this backend supports protected textures. */ + /** @return Whether this backend supports protected textures. */ static bool isProtectedTexturesSupported(Engine& engine) noexcept; - /** @return whether a backend supports texture swizzling. */ + /** @return Whether a backend supports texture swizzling. */ static bool isTextureSwizzleSupported(Engine& engine) noexcept; static size_t computeTextureDataSize(Format format, Type type, @@ -217,6 +220,18 @@ public: */ Builder& name(const char* UTILS_NONNULL name, size_t len) noexcept; + /** + * Creates an external texture. The content must be set using setExternalImage(). + * The sampler can be SAMPLER_EXTERNAL or SAMPLER_2D depending on the format. Generally + * YUV formats must use SAMPLER_EXTERNAL. This depends on the backend features and is not + * validated. + * + * If the Sampler is set to SAMPLER_EXTERNAL, external() is implied. + * + * @return + */ + Builder& external() noexcept; + /** * Creates the Texture object and returns a pointer to it. * @@ -261,18 +276,6 @@ public: */ Builder& import(intptr_t id) noexcept; - /** - * Creates an external texture. The content must be set using setExternalImage(). - * The sampler can be SAMPLER_EXTERNAL or SAMPLER_2D depending on the format. Generally - * YUV formats must use SAMPLER_EXTERNAL. This depends on the backend features and is not - * validated. - * - * If the Sampler is set to SAMPLER_EXTERNAL, external() is implied. - * - * @return - */ - Builder& external() noexcept; - private: friend class FTexture; }; @@ -359,7 +362,7 @@ public: * uint32_t width, uint32_t height, uint32_t depth, * PixelBufferDescriptor&& buffer) */ - inline void setImage(Engine& engine, size_t level, PixelBufferDescriptor&& buffer) const { + void setImage(Engine& engine, size_t level, PixelBufferDescriptor&& buffer) const { setImage(engine, level, 0, 0, 0, uint32_t(getWidth(level)), uint32_t(getHeight(level)), 1, std::move(buffer)); } @@ -372,7 +375,7 @@ public: * uint32_t width, uint32_t height, uint32_t depth, * PixelBufferDescriptor&& buffer) */ - inline void setImage(Engine& engine, size_t level, + void setImage(Engine& engine, size_t level, uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height, PixelBufferDescriptor&& buffer) const { setImage(engine, level, xoffset, yoffset, 0, width, height, 1, std::move(buffer)); @@ -406,6 +409,26 @@ public: PixelBufferDescriptor&& buffer, const FaceOffsets& faceOffsets) const; + /** + * Specify the external image to associate with this Texture. Typically, the external + * image is OS specific, and can be a video or camera frame. + * There are many restrictions when using an external image as a texture, such as: + * - only the level of detail (lod) 0 can be specified + * - only nearest or linear filtering is supported + * - the size and format of the texture is defined by the external image + * - only the CLAMP_TO_EDGE wrap mode is supported + * + * @param engine Engine this texture is associated to. + * @param image An opaque handle to a platform specific image. It must be created using Platform + * specific APIs. For example PlatformEGL::createExternalImage(EGLImageKHR eglImage) + * + * @see PlatformEGL::createExternalImage + * @see PlatformEGLAndroid::createExternalImage + * @see PlatformCocoaGL::createExternalImage + * @see PlatformCocoaTouchGL::createExternalImage + */ + void setExternalImage(Engine& engine, ExternalImageHandleRef image) noexcept; + /** * Specify the external image to associate with this Texture. Typically, the external * image is OS specific, and can be a video or camera frame. @@ -428,7 +451,9 @@ public: * * @see Builder::sampler() * + * @deprecated Instead, use setExternalImage(Engine& engine, ExternalImageHandleRef image) */ + UTILS_DEPRECATED void setExternalImage(Engine& engine, void* UTILS_NONNULL image) noexcept; /** @@ -463,7 +488,7 @@ public: void setExternalImage(Engine& engine, void* UTILS_NONNULL image, size_t plane) noexcept; /** - * Specify the external stream to associate with this Texture. Typically the external + * Specify the external stream to associate with this Texture. Typically, the external * stream is OS specific, and can be a video or camera stream. * There are many restrictions when using an external stream as a texture, such as: * - only the level of detail (lod) 0 can be specified @@ -474,7 +499,7 @@ public: * @param stream A Stream object * * @attention \p engine must be the instance passed to Builder::build() - * @attention This Texture instance must use Sampler::SAMPLER_EXTERNAL or it has no effect + * @attention This Texture instance must use Sampler::SAMPLER_EXTERNAL, or it has no effect * * @see Builder::sampler(), Stream * @@ -522,9 +547,9 @@ public: * @param buffer Client-side buffer containing the images to set. * @param faceOffsets Offsets in bytes into \p buffer for all six images. The offsets * are specified in the following order: +x, -x, +y, -y, +z, -z - * @param options Optional parameter to controlling user-specified quality and options. + * @param options Optional parameter controlling user-specified quality and options. * - * @exception utils::PreConditionPanic if the source data constraints are not respected. + * @exception utils::PreConditionPanic If the source data constraints are not respected. * */ void generatePrefilterMipmap(Engine& engine, diff --git a/filament/src/Texture.cpp b/filament/src/Texture.cpp index eb67f5b43c..d3f53e8ea9 100644 --- a/filament/src/Texture.cpp +++ b/filament/src/Texture.cpp @@ -58,6 +58,10 @@ void Texture::setImage(Engine& engine, size_t const level, downcast(this)->setImage(downcast(engine), level, std::move(buffer), faceOffsets); } +void Texture::setExternalImage(Engine& engine, ExternalImageHandleRef image) noexcept { + downcast(this)->setExternalImage(downcast(engine), image); +} + void Texture::setExternalImage(Engine& engine, void* image) noexcept { downcast(this)->setExternalImage(downcast(engine), image); } diff --git a/filament/src/details/Texture.cpp b/filament/src/details/Texture.cpp index ee1c3d3432..4d2675dace 100644 --- a/filament/src/details/Texture.cpp +++ b/filament/src/details/Texture.cpp @@ -469,6 +469,26 @@ void FTexture::setImage(FEngine& engine, size_t const level, const_cast(this)->updateLodRange(level); } +void FTexture::setExternalImage(FEngine& engine, ExternalImageHandleRef image) noexcept { + FILAMENT_CHECK_PRECONDITION(mExternal) << "The texture must be external."; + + // The call to setupExternalImage2 is synchronous, and allows the driver to take ownership of the + // external image on this thread, if necessary. + auto& api = engine.getDriverApi(); + api.setupExternalImage2(image); + + auto texture = api.createTextureExternalImage2(mTarget, mFormat, mWidth, mHeight, mUsage, image); + + if (mTextureIsSwizzled) { + auto const& s = mSwizzle; + auto swizzleView = api.createTextureViewSwizzle(texture, s[0], s[1], s[2], s[3]); + api.destroyTexture(texture); + texture = swizzleView; + } + + setHandles(texture); +} + void FTexture::setExternalImage(FEngine& engine, void* image) noexcept { FILAMENT_CHECK_PRECONDITION(mExternal) << "The texture must be external."; diff --git a/filament/src/details/Texture.h b/filament/src/details/Texture.h index f4354f2f57..ad0064b52c 100644 --- a/filament/src/details/Texture.h +++ b/filament/src/details/Texture.h @@ -66,6 +66,7 @@ public: PixelBufferDescriptor&& buffer, const FaceOffsets& faceOffsets, PrefilterOptions const* options); + void setExternalImage(FEngine& engine, ExternalImageHandleRef image) noexcept; void setExternalImage(FEngine& engine, void* image) noexcept; void setExternalImage(FEngine& engine, void* image, size_t plane) noexcept; void setExternalStream(FEngine& engine, FStream* stream) noexcept; From 05cdeccc279045052a5e1d40bb2ec13cec4e2a0e Mon Sep 17 00:00:00 2001 From: Ben Doherty Date: Wed, 5 Feb 2025 11:05:03 -0800 Subject: [PATCH 17/24] Stop precaching stereo depth variants on non-supported platforms (#8413) --- filament/src/details/Material.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/filament/src/details/Material.cpp b/filament/src/details/Material.cpp index 4347e1aa28..d67fc11233 100644 --- a/filament/src/details/Material.cpp +++ b/filament/src/details/Material.cpp @@ -1103,8 +1103,13 @@ void FMaterial::precacheDepthVariants(FEngine const& engine) { // later, when/if needed by createAndCacheProgram(). Doing it now potentially uses more // memory and increases init time, but reduces hiccups during the first frame. if (UTILS_UNLIKELY(mIsDefaultMaterial)) { + const bool stereoSupported = mEngine.getDriverApi().isStereoSupported(); auto const allDepthVariants = VariantUtils::getDepthVariants(); for (auto const variant: allDepthVariants) { + // Don't precache any stereo variants if stereo is not supported. + if (!stereoSupported && Variant::isStereoVariant(variant)) { + continue; + } assert_invariant(Variant::isValidDepthVariant(variant)); if (hasVariant(variant)) { prepareProgram(variant); From ea5d7d4f47113aa35edb78fd462ca13aa5469f3d Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Thu, 23 Jan 2025 17:02:02 -0800 Subject: [PATCH 18/24] Add a way to retrieve the GL_RENDERER and GL_VENDOR strings The API works this way: ``` auto vendor = OpenGLPlatform::getVendorString(engine->getDriver()); ``` Obviously the Backend must be `Backend::OPENGL` and the `Driver` must have been created with an `OpenGLPlatform` subclass. FIXES=[385367277] --- filament/backend/include/backend/Platform.h | 2 +- .../backend/platforms/OpenGLPlatform.h | 13 ++++++ .../backend/platforms/PlatformCocoaGL.h | 1 - .../include/backend/platforms/PlatformEGL.h | 3 +- filament/backend/src/noop/NoopDriver.cpp | 3 ++ filament/backend/src/opengl/OpenGLDriver.cpp | 2 +- filament/backend/src/opengl/OpenGLDriver.h | 44 ++++++++++++------- .../backend/src/opengl/OpenGLPlatform.cpp | 30 ++++++++++++- .../src/opengl/platforms/OpenGLDriverBase.h | 37 ++++++++++++++++ .../src/opengl/platforms/PlatformEGL.cpp | 22 +++++----- filament/include/filament/Engine.h | 12 +++++ filament/src/Engine.cpp | 4 ++ filament/src/details/Engine.h | 13 +++--- 13 files changed, 145 insertions(+), 41 deletions(-) create mode 100644 filament/backend/src/opengl/platforms/OpenGLDriverBase.h diff --git a/filament/backend/include/backend/Platform.h b/filament/backend/include/backend/Platform.h index f5a08dad0d..9fea71deeb 100644 --- a/filament/backend/include/backend/Platform.h +++ b/filament/backend/include/backend/Platform.h @@ -165,7 +165,7 @@ public: * * @return nullptr on failure, or a pointer to the newly created driver. */ - virtual backend::Driver* UTILS_NULLABLE createDriver(void* UTILS_NULLABLE sharedContext, + virtual Driver* UTILS_NULLABLE createDriver(void* UTILS_NULLABLE sharedContext, const DriverConfig& driverConfig) noexcept = 0; /** diff --git a/filament/backend/include/backend/platforms/OpenGLPlatform.h b/filament/backend/include/backend/platforms/OpenGLPlatform.h index 958275cd51..a64278dab2 100644 --- a/filament/backend/include/backend/platforms/OpenGLPlatform.h +++ b/filament/backend/include/backend/platforms/OpenGLPlatform.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -56,6 +57,18 @@ public: unsigned int id; // GLuint id }; + /** + * Return the OpenGL vendor string of the specified Driver instance. + * @return The GL_VENDOR string + */ + static utils::CString getVendorString(Driver const* UTILS_NONNULL driver); + + /** + * Return the OpenGL vendor string of the specified Driver instance + * @return The GL_RENDERER string + */ + static utils::CString getRendererString(Driver const* UTILS_NONNULL driver); + /** * Called by the driver to destroy the OpenGL context. This should clean up any windows * or buffers from initialization. This is for instance where `eglDestroyContext` would be diff --git a/filament/backend/include/backend/platforms/PlatformCocoaGL.h b/filament/backend/include/backend/platforms/PlatformCocoaGL.h index 869af5c45a..24f7a43c85 100644 --- a/filament/backend/include/backend/platforms/PlatformCocoaGL.h +++ b/filament/backend/include/backend/platforms/PlatformCocoaGL.h @@ -17,7 +17,6 @@ #ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_GL_H #define TNT_FILAMENT_BACKEND_OPENGL_OPENGL_PLATFORM_COCOA_GL_H -#include #include #include diff --git a/filament/backend/include/backend/platforms/PlatformEGL.h b/filament/backend/include/backend/platforms/PlatformEGL.h index 32baeef897..13a813e9e7 100644 --- a/filament/backend/include/backend/platforms/PlatformEGL.h +++ b/filament/backend/include/backend/platforms/PlatformEGL.h @@ -80,8 +80,7 @@ protected: * Initializes EGL, creates the OpenGL context and returns a concrete Driver implementation * that supports OpenGL/OpenGL ES. */ - Driver* createDriver(void* sharedContext, - const Platform::DriverConfig& driverConfig) noexcept override; + Driver* createDriver(void* sharedContext, const DriverConfig& driverConfig) noexcept override; /** * This returns zero. This method can be overridden to return something more useful. diff --git a/filament/backend/src/noop/NoopDriver.cpp b/filament/backend/src/noop/NoopDriver.cpp index f31a6343da..fe37a18bfd 100644 --- a/filament/backend/src/noop/NoopDriver.cpp +++ b/filament/backend/src/noop/NoopDriver.cpp @@ -14,6 +14,9 @@ * limitations under the License. */ +#include +#include + #include "noop/NoopDriver.h" #include "CommandStreamDispatcher.h" diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 86c45f14fc..3390b7f81e 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -154,7 +154,7 @@ using namespace GLUtils; // ------------------------------------------------------------------------------------------------ UTILS_NOINLINE -Driver* OpenGLDriver::create(OpenGLPlatform* const platform, +OpenGLDriver* OpenGLDriver::create(OpenGLPlatform* const platform, void* const sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept { assert_invariant(platform); OpenGLPlatform* const ec = platform; diff --git a/filament/backend/src/opengl/OpenGLDriver.h b/filament/backend/src/opengl/OpenGLDriver.h index 22dc76a2e7..8fc7965162 100644 --- a/filament/backend/src/opengl/OpenGLDriver.h +++ b/filament/backend/src/opengl/OpenGLDriver.h @@ -26,11 +26,12 @@ #include "GLTexture.h" #include "ShaderCompilerService.h" -#include +#include "platforms/OpenGLDriverBase.h" #include #include #include +#include #include #include #include @@ -41,6 +42,7 @@ #include #include #include +#include #include #include @@ -74,14 +76,14 @@ class OpenGLProgram; class TimerQueryFactoryInterface; struct PushConstantBundle; -class OpenGLDriver final : public DriverBase { +class OpenGLDriver final : public OpenGLDriverBase { inline explicit OpenGLDriver(OpenGLPlatform* platform, const Platform::DriverConfig& driverConfig) noexcept; - ~OpenGLDriver() noexcept final; - Dispatcher getDispatcher() const noexcept final; + ~OpenGLDriver() noexcept override; + Dispatcher getDispatcher() const noexcept override; public: - static Driver* create(OpenGLPlatform* platform, void* sharedGLContext, + static OpenGLDriver* create(OpenGLPlatform* platform, void* sharedGLContext, const Platform::DriverConfig& driverConfig) noexcept; class DebugMarker { @@ -184,7 +186,7 @@ public: std::condition_variable cond; FenceStatus status{ FenceStatus::TIMEOUT_EXPIRED }; }; - std::shared_ptr state{ std::make_shared() }; + std::shared_ptr state{ std::make_shared() }; }; OpenGLDriver(OpenGLDriver const&) = delete; @@ -203,13 +205,21 @@ private: return mShaderCompilerService; } - ShaderModel getShaderModel() const noexcept final; - ShaderLanguage getShaderLanguage() const noexcept final; + ShaderModel getShaderModel() const noexcept override; + ShaderLanguage getShaderLanguage() const noexcept override; /* - * Driver interface + * OpenGLDriver interface */ + utils::CString getVendorString() const noexcept override { + return utils::CString{ mContext.state.vendor }; + } + + utils::CString getRendererString() const noexcept override { + return utils::CString{ mContext.state.renderer }; + } + template friend class ConcreteDispatcher; @@ -236,21 +246,21 @@ private: } template - typename std::enable_if::value, D>::type* + std::enable_if_t, D>* construct(Handle
const& handle, ARGS&& ... args) { return mHandleAllocator.destroyAndConstruct(handle, std::forward(args) ...); } template::value, D>::type> + typename = std::enable_if_t, D>> void destruct(Handle& handle, D const* p) noexcept { return mHandleAllocator.deallocate(handle, p); } template - typename std::enable_if_t< + std::enable_if_t< std::is_pointer_v && - std::is_base_of_v>, Dp> + std::is_base_of_v>, Dp> handle_cast(Handle& handle) { return mHandleAllocator.handle_cast(handle); } @@ -261,9 +271,9 @@ private: } template - inline typename std::enable_if_t< + std::enable_if_t< std::is_pointer_v && - std::is_base_of_v>, Dp> + std::is_base_of_v>, Dp> handle_cast(Handle const& handle) { return mHandleAllocator.handle_cast(handle); } @@ -303,7 +313,7 @@ private: void renderBufferStorage(GLuint rbo, GLenum internalformat, uint32_t width, uint32_t height, uint8_t samples) const noexcept; - void textureStorage(OpenGLDriver::GLTexture* t, uint32_t width, uint32_t height, + void textureStorage(GLTexture* t, uint32_t width, uint32_t height, uint32_t depth, bool useProtectedMemory) noexcept; /* State tracking GL wrappers... */ @@ -335,7 +345,7 @@ private: void updateDescriptors(utils::bitset8 invalidDescriptorSets) noexcept; struct { - backend::DescriptorSetHandle dsh; + DescriptorSetHandle dsh; std::array offsets; } mBoundDescriptorSets[MAX_DESCRIPTOR_SET_COUNT]; diff --git a/filament/backend/src/opengl/OpenGLPlatform.cpp b/filament/backend/src/opengl/OpenGLPlatform.cpp index 3ba229fb32..88f7accb89 100644 --- a/filament/backend/src/opengl/OpenGLPlatform.cpp +++ b/filament/backend/src/opengl/OpenGLPlatform.cpp @@ -18,26 +18,52 @@ #include "OpenGLDriverFactory.h" +#include "platforms/OpenGLDriverBase.h" + #include #include #include #include - +#include +#include #include + #include #include #include +#include "OpenGLDriver.h" + namespace filament::backend { +OpenGLDriverBase::~OpenGLDriverBase() = default; + Driver* OpenGLPlatform::createDefaultDriver(OpenGLPlatform* platform, - void* sharedContext, const Platform::DriverConfig& driverConfig) { + void* sharedContext, const DriverConfig& driverConfig) { return OpenGLDriverFactory::create(platform, sharedContext, driverConfig); } OpenGLPlatform::~OpenGLPlatform() noexcept = default; +utils::CString OpenGLPlatform::getVendorString(Driver const* driver) { + auto const p = static_cast(driver); +#if UTILS_HAS_RTTI + FILAMENT_CHECK_POSTCONDITION(dynamic_cast(driver)) + << "Driver* has not been allocated with OpenGLPlatform"; +#endif + return p->getVendorString(); +} + +utils::CString OpenGLPlatform::getRendererString(Driver const* driver) { + auto const p = static_cast(driver); +#if UTILS_HAS_RTTI + FILAMENT_CHECK_POSTCONDITION(dynamic_cast(driver)) + << "Driver* has not been allocated with OpenGLPlatform"; +#endif + return p->getRendererString(); +} + void OpenGLPlatform::makeCurrent(SwapChain* drawSwapChain, SwapChain* readSwapChain, utils::Invocable, utils::Invocable) noexcept { makeCurrent(getCurrentContextType(), drawSwapChain, readSwapChain); diff --git a/filament/backend/src/opengl/platforms/OpenGLDriverBase.h b/filament/backend/src/opengl/platforms/OpenGLDriverBase.h new file mode 100644 index 0000000000..6fea8f76ce --- /dev/null +++ b/filament/backend/src/opengl/platforms/OpenGLDriverBase.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGLDRIVERBASE_H +#define TNT_FILAMENT_BACKEND_OPENGL_OPENGLDRIVERBASE_H + +#include "DriverBase.h" + +#include + +namespace filament::backend { + +class OpenGLDriverBase : public DriverBase { +protected: + ~OpenGLDriverBase() override; + +public: + virtual utils::CString getVendorString() const noexcept = 0; + virtual utils::CString getRendererString() const noexcept = 0; +}; + +} // filament::backend + +#endif //TNT_FILAMENT_BACKEND_OPENGL_OPENGLDRIVERBASE_H diff --git a/filament/backend/src/opengl/platforms/PlatformEGL.cpp b/filament/backend/src/opengl/platforms/PlatformEGL.cpp index 3190ab3246..3e141c4639 100644 --- a/filament/backend/src/opengl/platforms/PlatformEGL.cpp +++ b/filament/backend/src/opengl/platforms/PlatformEGL.cpp @@ -297,7 +297,7 @@ Driver* PlatformEGL::createDriver(void* sharedContext, const DriverConfig& drive clearGlError(); // success!! - return OpenGLPlatform::createDefaultDriver(this, sharedContext, driverConfig); + return createDefaultDriver(this, sharedContext, driverConfig); error: // if we're here, we've failed @@ -551,7 +551,7 @@ Platform::SwapChain* PlatformEGL::createSwapChain( return sc; } -void PlatformEGL::destroySwapChain(Platform::SwapChain* swapChain) noexcept { +void PlatformEGL::destroySwapChain(SwapChain* swapChain) noexcept { if (swapChain) { SwapChainEGL const* const sc = static_cast(swapChain); if (sc->sur != EGL_NO_SURFACE) { @@ -564,7 +564,7 @@ void PlatformEGL::destroySwapChain(Platform::SwapChain* swapChain) noexcept { } } -bool PlatformEGL::isSwapChainProtected(Platform::SwapChain* swapChain) noexcept { +bool PlatformEGL::isSwapChainProtected(SwapChain* swapChain) noexcept { if (swapChain) { SwapChainEGL const* const sc = static_cast(swapChain); return bool(sc->flags & SWAP_CHAIN_CONFIG_PROTECTED_CONTENT); @@ -585,10 +585,10 @@ bool PlatformEGL::makeCurrent(ContextType type, return success == EGL_TRUE ? true : false; } -void PlatformEGL::makeCurrent(Platform::SwapChain* drawSwapChain, - Platform::SwapChain* readSwapChain, - utils::Invocable preContextChange, - utils::Invocable postContextChange) noexcept { +void PlatformEGL::makeCurrent(SwapChain* drawSwapChain, + SwapChain* readSwapChain, + Invocable preContextChange, + Invocable postContextChange) noexcept { assert_invariant(drawSwapChain); assert_invariant(readSwapChain); @@ -647,7 +647,7 @@ void PlatformEGL::makeCurrent(Platform::SwapChain* drawSwapChain, } } -void PlatformEGL::commit(Platform::SwapChain* swapChain) noexcept { +void PlatformEGL::commit(SwapChain* swapChain) noexcept { if (swapChain) { SwapChainEGL const* const sc = static_cast(swapChain); if (sc->sur != EGL_NO_SURFACE) { @@ -670,7 +670,7 @@ Platform::Fence* PlatformEGL::createFence() noexcept { return f; } -void PlatformEGL::destroyFence(Platform::Fence* fence) noexcept { +void PlatformEGL::destroyFence(Fence* fence) noexcept { #ifdef EGL_KHR_reusable_sync EGLSyncKHR sync = (EGLSyncKHR) fence; if (sync != EGL_NO_SYNC_KHR) { @@ -680,7 +680,7 @@ void PlatformEGL::destroyFence(Platform::Fence* fence) noexcept { } FenceStatus PlatformEGL::waitFence( - Platform::Fence* fence, uint64_t timeout) noexcept { + Fence* fence, uint64_t timeout) noexcept { #ifdef EGL_KHR_reusable_sync EGLSyncKHR sync = (EGLSyncKHR) fence; if (sync != EGL_NO_SYNC_KHR) { @@ -746,7 +746,7 @@ void PlatformEGL::initializeGlExtensions() noexcept { ext.gl.OES_EGL_image_external_essl3 = glExtensions.has("GL_OES_EGL_image_external_essl3"); } -EGLContext PlatformEGL::getContextForType(OpenGLPlatform::ContextType type) const noexcept { +EGLContext PlatformEGL::getContextForType(ContextType type) const noexcept { switch (type) { case ContextType::NONE: return EGL_NO_CONTEXT; diff --git a/filament/include/filament/Engine.h b/filament/include/filament/Engine.h index 5092e16c38..30d2ca869d 100644 --- a/filament/include/filament/Engine.h +++ b/filament/include/filament/Engine.h @@ -17,6 +17,7 @@ #ifndef TNT_FILAMENT_ENGINE_H #define TNT_FILAMENT_ENGINE_H + #include #include @@ -32,6 +33,7 @@ #include #include + namespace utils { class Entity; class EntityManager; @@ -40,6 +42,10 @@ class JobSystem; namespace filament { +namespace backend { +class Driver; +} // backend + class BufferObject; class Camera; class ColorGrading; @@ -183,6 +189,7 @@ public: using DriverConfig = backend::Platform::DriverConfig; using FeatureLevel = backend::FeatureLevel; using StereoscopicType = backend::StereoscopicType; + using Driver = backend::Driver; /** * Config is used to define the memory footprint used by the engine, such as the @@ -582,6 +589,11 @@ public: static Engine* UTILS_NULLABLE getEngine(void* UTILS_NONNULL token); #endif + /** + * @return the Driver instance used by this Engine. + * @see OpenGLPlatform + */ + backend::Driver const* UTILS_NONNULL getDriver() const noexcept; /** * Destroy the Engine instance and all associated resources. diff --git a/filament/src/Engine.cpp b/filament/src/Engine.cpp index 455067739c..1927e7a34f 100644 --- a/filament/src/Engine.cpp +++ b/filament/src/Engine.cpp @@ -68,6 +68,10 @@ Engine* Engine::getEngine(void* token) { } #endif +Driver const* Engine::getDriver() const noexcept { + return std::addressof(downcast(this)->getDriver()); +} + void Engine::destroy(Engine** pEngine) { if (pEngine) { Engine* engine = *pEngine; diff --git a/filament/src/details/Engine.h b/filament/src/details/Engine.h index 25c3f388af..eec73eba95 100644 --- a/filament/src/details/Engine.h +++ b/filament/src/details/Engine.h @@ -61,6 +61,8 @@ #include #include +#include + #include #include #include @@ -122,12 +124,11 @@ class ResourceAllocator; */ class FEngine : public Engine { public: - - inline void* operator new(std::size_t const size) noexcept { + void* operator new(std::size_t const size) noexcept { return utils::aligned_alloc(size, alignof(FEngine)); } - inline void operator delete(void* p) noexcept { + void operator delete(void* p) noexcept { utils::aligned_free(p); } @@ -490,7 +491,7 @@ public: backend::Handle getOneTextureArray() const { return mDummyOneTextureArray; } backend::Handle getZeroTextureArray() const { return mDummyZeroTextureArray; } - static constexpr const size_t MiB = 1024u * 1024u; + static constexpr size_t MiB = 1024u * 1024u; size_t getMinCommandBufferSize() const noexcept { return mConfig.minCommandBufferSizeMB * MiB; } size_t getCommandBufferSize() const noexcept { return mConfig.commandBufferSizeMB * MiB; } size_t getPerFrameCommandsSize() const noexcept { return mConfig.perFrameCommandsSizeMB * MiB; } @@ -510,6 +511,8 @@ public: void resetBackendState() noexcept; #endif + backend::Driver& getDriver() const noexcept { return *mDriver; } + private: explicit FEngine(Builder const& builder); void init(); @@ -518,8 +521,6 @@ private: int loop(); void flushCommandBuffer(backend::CommandBufferQueue& commandBufferQueue); - backend::Driver& getDriver() const noexcept { return *mDriver; } - template bool isValid(const T* ptr, ResourceList const& list) const; From 8de56a2bbc0a3e9565c8b45804c1dafda427d3be Mon Sep 17 00:00:00 2001 From: Powei Feng Date: Wed, 5 Feb 2025 15:52:05 -0800 Subject: [PATCH 19/24] Add ostream operator for ExternalImageHandle (#8416) Without it, DEBUG_COMMAND_STREAM does not compile. --- filament/backend/include/backend/Platform.h | 4 ++++ filament/backend/src/Platform.cpp | 23 ++++++++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/filament/backend/include/backend/Platform.h b/filament/backend/include/backend/Platform.h index 9fea71deeb..e017cb4edb 100644 --- a/filament/backend/include/backend/Platform.h +++ b/filament/backend/include/backend/Platform.h @@ -79,6 +79,10 @@ public: void clear() noexcept; void reset(ExternalImage* UTILS_NULLABLE p) noexcept; + + private: + friend utils::io::ostream& operator<<(utils::io::ostream& out, + ExternalImageHandle const& handle); }; using ExternalImageHandleRef = ExternalImageHandle const&; diff --git a/filament/backend/src/Platform.cpp b/filament/backend/src/Platform.cpp index b603155923..5618ed6367 100644 --- a/filament/backend/src/Platform.cpp +++ b/filament/backend/src/Platform.cpp @@ -35,12 +35,13 @@ void Platform::ExternalImageHandle::incref(ExternalImage* p) noexcept { void Platform::ExternalImageHandle::decref(ExternalImage* p) noexcept { if (p) { - // When decrementing the ref-count, unless it reaches zero, there is no need to acquire data; we need to - // release all previous writes though so they can be visible to the thread that will actually delete the - // object. + // When decrementing the ref-count, unless it reaches zero, there is no need to acquire + // data; we need to release all previous writes though so they can be visible to the thread + // that will actually delete the object. if (p->mRefCount.fetch_sub(1, std::memory_order_release) == 1) { - // if we reach zero, we're about to delete the object, we need to acquire all previous writes from other - // threads (i.e.: the memory from other threads prior to the decref() need to be visible now. + // if we reach zero, we're about to delete the object, we need to acquire all previous + // writes from other threads (i.e.: the memory from other threads prior to the decref() + // need to be visible now. std::atomic_thread_fence(std::memory_order_acquire); delete p; } @@ -68,7 +69,8 @@ Platform::ExternalImageHandle::ExternalImageHandle(ExternalImageHandle&& rhs) no rhs.mTarget = nullptr; } -Platform::ExternalImageHandle& Platform::ExternalImageHandle::operator=(ExternalImageHandle const& rhs) noexcept { +Platform::ExternalImageHandle& Platform::ExternalImageHandle::operator=( + ExternalImageHandle const& rhs) noexcept { if (UTILS_LIKELY(this != &rhs)) { incref(rhs.mTarget); decref(mTarget); @@ -77,7 +79,8 @@ Platform::ExternalImageHandle& Platform::ExternalImageHandle::operator=(External return *this; } -Platform::ExternalImageHandle& Platform::ExternalImageHandle::operator=(ExternalImageHandle&& rhs) noexcept { +Platform::ExternalImageHandle& Platform::ExternalImageHandle::operator=( + ExternalImageHandle&& rhs) noexcept { if (UTILS_LIKELY(this != &rhs)) { decref(mTarget); mTarget = rhs.mTarget; @@ -97,6 +100,12 @@ void Platform::ExternalImageHandle::reset(ExternalImage* p) noexcept { mTarget = p; } +utils::io::ostream& operator<<(utils::io::ostream& out, + Platform::ExternalImageHandle const& handle) { + out << "ExternalImageHandle{" << handle.mTarget << "}"; + return out; +} + // -------------------------------------------------------------------------------------------------------------------- Platform::ExternalImage::~ExternalImage() noexcept = default; From 538aa39127b5738a6aa26565806ed6dcad8eb9b0 Mon Sep 17 00:00:00 2001 From: Powei Feng Date: Thu, 6 Feb 2025 11:13:55 -0800 Subject: [PATCH 20/24] Release Filament 1.56.8 --- NEW_RELEASE_NOTES.md | 3 --- README.md | 4 ++-- RELEASE_NOTES.md | 5 +++++ android/gradle.properties | 2 +- ios/CocoaPods/Filament.podspec | 4 ++-- web/filament-js/package.json | 2 +- 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/NEW_RELEASE_NOTES.md b/NEW_RELEASE_NOTES.md index 3482b42bb6..4a1a9c7fa7 100644 --- a/NEW_RELEASE_NOTES.md +++ b/NEW_RELEASE_NOTES.md @@ -7,6 +7,3 @@ for next branch cut* header. appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md). ## Release notes for next branch cut - -- matdbg: Add support for debugging ESSL 1.0 shaders -- backend: New platform API to better handle external textures [⚠️ **New Material Version**] diff --git a/README.md b/README.md index 625dd40c3a..914a1f3dba 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation 'com.google.android.filament:filament-android:1.56.7' + implementation 'com.google.android.filament:filament-android:1.56.8' } ``` @@ -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.56.7' +pod 'Filament', '~> 1.56.8' ``` ## Documentation diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 09643b5d20..802f39ef58 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -7,6 +7,11 @@ 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.57.0 + +- matdbg: Add support for debugging ESSL 1.0 shaders +- backend: New platform API to better handle external textures [⚠️ **New Material Version**] + ## v1.56.8 diff --git a/android/gradle.properties b/android/gradle.properties index d1baf95447..6687f3ef9b 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.google.android.filament -VERSION_NAME=1.56.7 +VERSION_NAME=1.56.8 POM_DESCRIPTION=Real-time physically based rendering engine for Android. diff --git a/ios/CocoaPods/Filament.podspec b/ios/CocoaPods/Filament.podspec index e5e319aab0..9d28231177 100644 --- a/ios/CocoaPods/Filament.podspec +++ b/ios/CocoaPods/Filament.podspec @@ -1,12 +1,12 @@ Pod::Spec.new do |spec| spec.name = "Filament" - spec.version = "1.56.7" + spec.version = "1.56.8" 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.56.7/filament-v1.56.7-ios.tgz" } + spec.source = { :http => "https://github.com/google/filament/releases/download/v1.56.8/filament-v1.56.8-ios.tgz" } # Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon. spec.pod_target_xcconfig = { diff --git a/web/filament-js/package.json b/web/filament-js/package.json index 36a97d6c37..bf1aec9263 100644 --- a/web/filament-js/package.json +++ b/web/filament-js/package.json @@ -1,6 +1,6 @@ { "name": "filament", - "version": "1.56.7", + "version": "1.56.8", "description": "Real-time physically based rendering engine", "main": "filament.js", "module": "filament.js", From dd51e1dd96809bbe41698ee0f839f3e1c175d2a8 Mon Sep 17 00:00:00 2001 From: Powei Feng Date: Thu, 6 Feb 2025 11:14:08 -0800 Subject: [PATCH 21/24] Bump version to 1.57.0 --- README.md | 4 ++-- android/gradle.properties | 2 +- ios/CocoaPods/Filament.podspec | 4 ++-- web/filament-js/package.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 914a1f3dba..cba88272aa 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ repositories { } dependencies { - implementation 'com.google.android.filament:filament-android:1.56.8' + implementation 'com.google.android.filament:filament-android:1.57.0' } ``` @@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`: iOS projects can use CocoaPods to install the latest release: ```shell -pod 'Filament', '~> 1.56.8' +pod 'Filament', '~> 1.57.0' ``` ## Documentation diff --git a/android/gradle.properties b/android/gradle.properties index 6687f3ef9b..5974551d51 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.google.android.filament -VERSION_NAME=1.56.8 +VERSION_NAME=1.57.0 POM_DESCRIPTION=Real-time physically based rendering engine for Android. diff --git a/ios/CocoaPods/Filament.podspec b/ios/CocoaPods/Filament.podspec index 9d28231177..37b823a009 100644 --- a/ios/CocoaPods/Filament.podspec +++ b/ios/CocoaPods/Filament.podspec @@ -1,12 +1,12 @@ Pod::Spec.new do |spec| spec.name = "Filament" - spec.version = "1.56.8" + spec.version = "1.57.0" 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.56.8/filament-v1.56.8-ios.tgz" } + spec.source = { :http => "https://github.com/google/filament/releases/download/v1.57.0/filament-v1.57.0-ios.tgz" } # Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon. spec.pod_target_xcconfig = { diff --git a/web/filament-js/package.json b/web/filament-js/package.json index bf1aec9263..cf06353400 100644 --- a/web/filament-js/package.json +++ b/web/filament-js/package.json @@ -1,6 +1,6 @@ { "name": "filament", - "version": "1.56.8", + "version": "1.57.0", "description": "Real-time physically based rendering engine", "main": "filament.js", "module": "filament.js", From 6aa20312e53e33e15c00059dd7624d9b762886f7 Mon Sep 17 00:00:00 2001 From: Benjamin Doherty Date: Mon, 10 Feb 2025 09:48:52 -0800 Subject: [PATCH 22/24] Temporary workaround for PlatformMetal --- filament/backend/include/backend/Platform.h | 7 +++++++ filament/backend/src/metal/PlatformMetal.mm | 3 +++ filament/include/filament/Engine.h | 9 +++++++++ filament/src/details/Engine.cpp | 2 ++ 4 files changed, 21 insertions(+) diff --git a/filament/backend/include/backend/Platform.h b/filament/backend/include/backend/Platform.h index e017cb4edb..dac38211ad 100644 --- a/filament/backend/include/backend/Platform.h +++ b/filament/backend/include/backend/Platform.h @@ -144,6 +144,13 @@ public: * - PlatformEGLAndroid */ bool assertNativeWindowIsValid = false; + + /** + * The action to take if a Drawable cannot be acquired. If true, the + * frame is aborted instead of panic. This is only supported for: + * - PlatformMetal + */ + bool metalDisablePanicOnDrawableFailure = false; }; Platform() noexcept; diff --git a/filament/backend/src/metal/PlatformMetal.mm b/filament/backend/src/metal/PlatformMetal.mm index e446698b08..dbc2302b7f 100644 --- a/filament/backend/src/metal/PlatformMetal.mm +++ b/filament/backend/src/metal/PlatformMetal.mm @@ -44,6 +44,9 @@ PlatformMetal::~PlatformMetal() noexcept { } Driver* PlatformMetal::createDriver(void* /*sharedContext*/, const Platform::DriverConfig& driverConfig) noexcept { + pImpl->mDrawableFailureBehavior = driverConfig.metalDisablePanicOnDrawableFailure + ? DrawableFailureBehavior::ABORT_FRAME + : DrawableFailureBehavior::PANIC; return MetalDriverFactory::create(this, driverConfig); } diff --git a/filament/include/filament/Engine.h b/filament/include/filament/Engine.h index 30d2ca869d..d28f836b0e 100644 --- a/filament/include/filament/Engine.h +++ b/filament/include/filament/Engine.h @@ -317,6 +317,15 @@ public: */ size_t metalUploadBufferSizeBytes = 512 * 1024; + /** + * The action to take if a Drawable cannot be acquired. + * + * Each frame rendered requires a CAMetalDrawable texture, which is + * presented on-screen at the completion of each frame. These are + * limited and provided round-robin style by the system. + */ + bool metalDisablePanicOnDrawableFailure = false; + /** * Set to `true` to forcibly disable parallel shader compilation in the backend. * Currently only honored by the GL and Metal backends. diff --git a/filament/src/details/Engine.cpp b/filament/src/details/Engine.cpp index 3982f9235c..c6b4d67de8 100644 --- a/filament/src/details/Engine.cpp +++ b/filament/src/details/Engine.cpp @@ -123,6 +123,7 @@ Engine* FEngine::create(Builder const& builder) { .forceGLES2Context = instance->getConfig().forceGLES2Context, .stereoscopicType = instance->getConfig().stereoscopicType, .assertNativeWindowIsValid = instance->features.backend.opengl.assert_native_window_is_valid, + .metalDisablePanicOnDrawableFailure = instance->getConfig().metalDisablePanicOnDrawableFailure, }; instance->mDriver = platform->createDriver(sharedContext, driverConfig); @@ -717,6 +718,7 @@ int FEngine::loop() { .forceGLES2Context = mConfig.forceGLES2Context, .stereoscopicType = mConfig.stereoscopicType, .assertNativeWindowIsValid = features.backend.opengl.assert_native_window_is_valid, + .metalDisablePanicOnDrawableFailure = mConfig.metalDisablePanicOnDrawableFailure, }; mDriver = mPlatform->createDriver(mSharedGLContext, driverConfig); From e05784474260458fd02e6a6a4e7365fd77bcab40 Mon Sep 17 00:00:00 2001 From: Benjamin Doherty Date: Mon, 10 Feb 2025 09:49:35 -0800 Subject: [PATCH 23/24] Bump MATERIAL_VERSION to 57 --- libs/filabridge/include/filament/MaterialEnums.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/filabridge/include/filament/MaterialEnums.h b/libs/filabridge/include/filament/MaterialEnums.h index 4092e8a765..f5676640fe 100644 --- a/libs/filabridge/include/filament/MaterialEnums.h +++ b/libs/filabridge/include/filament/MaterialEnums.h @@ -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 = 56; +static constexpr size_t MATERIAL_VERSION = 57; /** * Supported shading models From d8b994bef140a0eb0ddfefba3cf2a3580173f83c Mon Sep 17 00:00:00 2001 From: Sungun Park Date: Mon, 10 Feb 2025 15:21:02 -0800 Subject: [PATCH 24/24] Move OpenGLDriverBase.h under src/opengl/ (#8433) --- filament/backend/src/opengl/OpenGLDriver.h | 3 +-- filament/backend/src/opengl/{platforms => }/OpenGLDriverBase.h | 0 filament/backend/src/opengl/OpenGLPlatform.cpp | 3 +-- 3 files changed, 2 insertions(+), 4 deletions(-) rename filament/backend/src/opengl/{platforms => }/OpenGLDriverBase.h (100%) diff --git a/filament/backend/src/opengl/OpenGLDriver.h b/filament/backend/src/opengl/OpenGLDriver.h index 8fc7965162..30ff4213e7 100644 --- a/filament/backend/src/opengl/OpenGLDriver.h +++ b/filament/backend/src/opengl/OpenGLDriver.h @@ -19,6 +19,7 @@ #include "DriverBase.h" #include "OpenGLContext.h" +#include "OpenGLDriverBase.h" #include "OpenGLTimerQuery.h" #include "GLBufferObject.h" #include "GLDescriptorSet.h" @@ -26,8 +27,6 @@ #include "GLTexture.h" #include "ShaderCompilerService.h" -#include "platforms/OpenGLDriverBase.h" - #include #include #include diff --git a/filament/backend/src/opengl/platforms/OpenGLDriverBase.h b/filament/backend/src/opengl/OpenGLDriverBase.h similarity index 100% rename from filament/backend/src/opengl/platforms/OpenGLDriverBase.h rename to filament/backend/src/opengl/OpenGLDriverBase.h diff --git a/filament/backend/src/opengl/OpenGLPlatform.cpp b/filament/backend/src/opengl/OpenGLPlatform.cpp index 88f7accb89..57d021cf0d 100644 --- a/filament/backend/src/opengl/OpenGLPlatform.cpp +++ b/filament/backend/src/opengl/OpenGLPlatform.cpp @@ -16,10 +16,9 @@ #include +#include "OpenGLDriverBase.h" #include "OpenGLDriverFactory.h" -#include "platforms/OpenGLDriverBase.h" - #include #include #include