Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e715a4cad3 | ||
|
|
e6751a659e | ||
|
|
2e12008273 | ||
|
|
b9d7a25b91 | ||
|
|
ba63ac63a0 | ||
|
|
1e77947758 | ||
|
|
53df4012fe | ||
|
|
d880fab93f | ||
|
|
fb8030b80a | ||
|
|
e2d009ff2a | ||
|
|
0a67ef4d80 | ||
|
|
79d6f46f1a | ||
|
|
6481fa2acf | ||
|
|
7638b3ddd9 | ||
|
|
fe474a9d7e | ||
|
|
81008abe06 | ||
|
|
ef1d079c53 | ||
|
|
5286dec70b | ||
|
|
d748dc590e | ||
|
|
93a0aec246 | ||
|
|
f3fa734793 | ||
|
|
33d3c3a897 | ||
|
|
bbabf3480b | ||
|
|
e7a8f471a1 |
@@ -7,3 +7,5 @@ for next branch cut* header.
|
||||
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
||||
|
||||
## Release notes for next branch cut
|
||||
|
||||
- materials: sampler now export their type in the material binary [⚠️ **New Material Version**]
|
||||
|
||||
@@ -1801,6 +1801,22 @@ public class View {
|
||||
* @see setAmbientOcclusionOptions()
|
||||
*/
|
||||
public static class AmbientOcclusionOptions {
|
||||
public enum AmbientOcclusionType {
|
||||
/**
|
||||
* use Scalable Ambient Occlusion
|
||||
*/
|
||||
SAO,
|
||||
/**
|
||||
* use Ground Truth-Based Ambient Occlusion
|
||||
*/
|
||||
GTAO,
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of ambient occlusion algorithm.
|
||||
*/
|
||||
@NonNull
|
||||
public AmbientOcclusionOptions.AmbientOcclusionType aoType = AmbientOcclusionOptions.AmbientOcclusionType.SAO;
|
||||
/**
|
||||
* Ambient Occlusion radius in meters, between 0 and ~10.
|
||||
*/
|
||||
@@ -1810,7 +1826,8 @@ public class View {
|
||||
*/
|
||||
public float power = 1.0f;
|
||||
/**
|
||||
* Self-occlusion bias in meters. Use to avoid self-occlusion. Between 0 and a few mm.
|
||||
* Self-occlusion bias in meters. Use to avoid self-occlusion.
|
||||
* Between 0 and a few mm. No effect when aoType set to GTAO
|
||||
*/
|
||||
public float bias = 0.0005f;
|
||||
/**
|
||||
@@ -1826,12 +1843,12 @@ public class View {
|
||||
*/
|
||||
public float bilateralThreshold = 0.05f;
|
||||
/**
|
||||
* affects # of samples used for AO.
|
||||
* affects # of samples used for AO and params for filtering
|
||||
*/
|
||||
@NonNull
|
||||
public QualityLevel quality = QualityLevel.LOW;
|
||||
/**
|
||||
* affects AO smoothness
|
||||
* affects AO smoothness. Recommend setting to HIGH when aoType set to GTAO.
|
||||
*/
|
||||
@NonNull
|
||||
public QualityLevel lowPassFilter = QualityLevel.MEDIUM;
|
||||
@@ -1849,7 +1866,7 @@ public class View {
|
||||
*/
|
||||
public boolean bentNormals = false;
|
||||
/**
|
||||
* min angle in radian to consider
|
||||
* min angle in radian to consider. No effect when aoType set to GTAO.
|
||||
*/
|
||||
public float minHorizonAngleRad = 0.0f;
|
||||
/**
|
||||
@@ -1904,6 +1921,19 @@ public class View {
|
||||
*/
|
||||
public boolean ssctEnabled = false;
|
||||
|
||||
/**
|
||||
* Ground Truth-base Ambient Occlusion (GTAO) options
|
||||
*/
|
||||
public int gtaoSampleSliceCount = 4;
|
||||
/**
|
||||
* Ground Truth-base Ambient Occlusion (GTAO) options
|
||||
*/
|
||||
public int gtaoSampleStepsPerSlice = 3;
|
||||
/**
|
||||
* Ground Truth-base Ambient Occlusion (GTAO) options
|
||||
*/
|
||||
public float gtaoThicknessHeuristic = 0.004f;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -262,6 +262,8 @@ set(MATERIAL_SRCS
|
||||
src/materials/ssao/mipmapDepth.mat
|
||||
src/materials/ssao/sao.mat
|
||||
src/materials/ssao/saoBentNormals.mat
|
||||
src/materials/ssao/gtao.mat
|
||||
src/materials/ssao/gtaoBentNormals.mat
|
||||
src/materials/vsmMipmap.mat
|
||||
)
|
||||
|
||||
@@ -318,8 +320,6 @@ endif()
|
||||
# Definitions
|
||||
# ==================================================================================================
|
||||
|
||||
# "2" corresponds to SYSTRACE_TAG_FILEMENT (See: utils/Systrace.h)
|
||||
add_definitions(-DSYSTRACE_TAG=2)
|
||||
add_definitions(-DFILAMENT_DFG_LUT_SIZE=${DFG_LUT_SIZE})
|
||||
add_definitions(
|
||||
-DFILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB=${FILAMENT_PER_RENDER_PASS_ARENA_SIZE_IN_MB}
|
||||
@@ -463,6 +463,28 @@ add_custom_command(
|
||||
APPEND
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${MATERIAL_DIR}/gtao.filamat"
|
||||
DEPENDS src/materials/ssao/ssaoUtils.fs
|
||||
DEPENDS src/materials/ssao/ssct.fs
|
||||
DEPENDS src/materials/utils/depthUtils.fs
|
||||
DEPENDS src/materials/utils/geometry.fs
|
||||
DEPENDS src/materials/ssao/gtaoImpl.fs
|
||||
DEPENDS src/materials/ssao/ssctImpl.fs
|
||||
APPEND
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${MATERIAL_DIR}/gtaoBentNormals.filamat"
|
||||
DEPENDS src/materials/ssao/ssaoUtils.fs
|
||||
DEPENDS src/materials/ssao/ssct.fs
|
||||
DEPENDS src/materials/utils/depthUtils.fs
|
||||
DEPENDS src/materials/utils/geometry.fs
|
||||
DEPENDS src/materials/ssao/gtaoImpl.fs
|
||||
DEPENDS src/materials/ssao/ssctImpl.fs
|
||||
APPEND
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${MATERIAL_DIR}/bilateralBlur.filamat"
|
||||
DEPENDS src/materials/ssao/ssaoUtils.fs
|
||||
|
||||
@@ -290,12 +290,6 @@ if (ANDROID)
|
||||
list(APPEND SRCS src/BackendUtilsAndroid.cpp)
|
||||
endif()
|
||||
|
||||
# ==================================================================================================
|
||||
# Definitions
|
||||
# ==================================================================================================
|
||||
# "2" corresponds to SYSTRACE_TAG_FILEMENT (See: utils/Systrace.h)
|
||||
add_definitions(-DSYSTRACE_TAG=2 )
|
||||
|
||||
# ==================================================================================================
|
||||
# Includes & target definition
|
||||
# ==================================================================================================
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <array>
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
#include <string_view>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
@@ -162,7 +163,7 @@ enum class TimerQueryResult : int8_t {
|
||||
AVAILABLE = 1, // result is available
|
||||
};
|
||||
|
||||
static constexpr const char* backendToString(Backend backend) {
|
||||
constexpr std::string_view to_string(Backend const backend) noexcept {
|
||||
switch (backend) {
|
||||
case Backend::NOOP:
|
||||
return "Noop";
|
||||
@@ -174,9 +175,10 @@ static constexpr const char* backendToString(Backend backend) {
|
||||
return "Metal";
|
||||
case Backend::WEBGPU:
|
||||
return "WebGPU";
|
||||
default:
|
||||
return "Unknown";
|
||||
case Backend::DEFAULT:
|
||||
return "Default";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,7 +195,7 @@ enum class ShaderLanguage {
|
||||
WGSL = 5,
|
||||
};
|
||||
|
||||
static constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguage) {
|
||||
constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguage) noexcept {
|
||||
switch (shaderLanguage) {
|
||||
case ShaderLanguage::ESSL1:
|
||||
return "ESSL 1.0";
|
||||
@@ -208,6 +210,7 @@ static constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguag
|
||||
case ShaderLanguage::WGSL:
|
||||
return "WGSL";
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
enum class ShaderStage : uint8_t {
|
||||
@@ -225,7 +228,7 @@ enum class ShaderStageFlags : uint8_t {
|
||||
ALL_SHADER_STAGE_FLAGS = VERTEX | FRAGMENT | COMPUTE
|
||||
};
|
||||
|
||||
static inline constexpr bool hasShaderType(ShaderStageFlags flags, ShaderStage type) noexcept {
|
||||
constexpr bool hasShaderType(ShaderStageFlags flags, ShaderStage type) noexcept {
|
||||
switch (type) {
|
||||
case ShaderStage::VERTEX:
|
||||
return bool(uint8_t(flags) & uint8_t(ShaderStageFlags::VERTEX));
|
||||
@@ -236,14 +239,239 @@ static inline constexpr bool hasShaderType(ShaderStageFlags flags, ShaderStage t
|
||||
}
|
||||
}
|
||||
|
||||
enum class DescriptorType : uint8_t {
|
||||
UNIFORM_BUFFER,
|
||||
SHADER_STORAGE_BUFFER,
|
||||
SAMPLER,
|
||||
INPUT_ATTACHMENT,
|
||||
SAMPLER_EXTERNAL
|
||||
enum class TextureType : uint8_t {
|
||||
FLOAT,
|
||||
INT,
|
||||
UINT,
|
||||
DEPTH,
|
||||
STENCIL,
|
||||
DEPTH_STENCIL
|
||||
};
|
||||
|
||||
constexpr std::string_view to_string(TextureType type) noexcept {
|
||||
switch (type) {
|
||||
case TextureType::FLOAT: return "FLOAT";
|
||||
case TextureType::INT: return "INT";
|
||||
case TextureType::UINT: return "UINT";
|
||||
case TextureType::DEPTH: return "DEPTH";
|
||||
case TextureType::STENCIL: return "STENCIL";
|
||||
case TextureType::DEPTH_STENCIL: return "DEPTH_STENCIL";
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
enum class DescriptorType : uint8_t {
|
||||
SAMPLER_2D_FLOAT,
|
||||
SAMPLER_2D_INT,
|
||||
SAMPLER_2D_UINT,
|
||||
SAMPLER_2D_DEPTH,
|
||||
|
||||
SAMPLER_2D_ARRAY_FLOAT,
|
||||
SAMPLER_2D_ARRAY_INT,
|
||||
SAMPLER_2D_ARRAY_UINT,
|
||||
SAMPLER_2D_ARRAY_DEPTH,
|
||||
|
||||
SAMPLER_CUBE_FLOAT,
|
||||
SAMPLER_CUBE_INT,
|
||||
SAMPLER_CUBE_UINT,
|
||||
SAMPLER_CUBE_DEPTH,
|
||||
|
||||
SAMPLER_CUBE_ARRAY_FLOAT,
|
||||
SAMPLER_CUBE_ARRAY_INT,
|
||||
SAMPLER_CUBE_ARRAY_UINT,
|
||||
SAMPLER_CUBE_ARRAY_DEPTH,
|
||||
|
||||
SAMPLER_3D_FLOAT,
|
||||
SAMPLER_3D_INT,
|
||||
SAMPLER_3D_UINT,
|
||||
|
||||
SAMPLER_2D_MS_FLOAT,
|
||||
SAMPLER_2D_MS_INT,
|
||||
SAMPLER_2D_MS_UINT,
|
||||
|
||||
SAMPLER_2D_MS_ARRAY_FLOAT,
|
||||
SAMPLER_2D_MS_ARRAY_INT,
|
||||
SAMPLER_2D_MS_ARRAY_UINT,
|
||||
|
||||
SAMPLER_EXTERNAL,
|
||||
UNIFORM_BUFFER,
|
||||
SHADER_STORAGE_BUFFER,
|
||||
INPUT_ATTACHMENT,
|
||||
};
|
||||
|
||||
constexpr bool isDepthDescriptor(DescriptorType const type) noexcept {
|
||||
switch (type) {
|
||||
case DescriptorType::SAMPLER_2D_DEPTH:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
|
||||
case DescriptorType::SAMPLER_CUBE_DEPTH:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
|
||||
return true;
|
||||
default: ;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr bool isFloatDescriptor(DescriptorType const type) noexcept {
|
||||
switch (type) {
|
||||
case DescriptorType::SAMPLER_2D_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_CUBE_FLOAT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_3D_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_MS_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT:
|
||||
return true;
|
||||
default: ;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr bool isIntDescriptor(DescriptorType const type) noexcept {
|
||||
switch (type) {
|
||||
case DescriptorType::SAMPLER_2D_INT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_CUBE_INT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_3D_INT:
|
||||
case DescriptorType::SAMPLER_2D_MS_INT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT:
|
||||
return true;
|
||||
default: ;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr bool isUnsignedIntDescriptor(DescriptorType const type) noexcept {
|
||||
switch (type) {
|
||||
case DescriptorType::SAMPLER_2D_UINT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
|
||||
case DescriptorType::SAMPLER_CUBE_UINT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
|
||||
case DescriptorType::SAMPLER_3D_UINT:
|
||||
case DescriptorType::SAMPLER_2D_MS_UINT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT:
|
||||
return true;
|
||||
default: ;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr bool is3dTypeDescriptor(DescriptorType const type) noexcept {
|
||||
switch (type) {
|
||||
case DescriptorType::SAMPLER_3D_FLOAT:
|
||||
case DescriptorType::SAMPLER_3D_INT:
|
||||
case DescriptorType::SAMPLER_3D_UINT:
|
||||
return true;
|
||||
default: ;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr bool is2dTypeDescriptor(DescriptorType const type) noexcept {
|
||||
switch (type) {
|
||||
case DescriptorType::SAMPLER_2D_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_INT:
|
||||
case DescriptorType::SAMPLER_2D_UINT:
|
||||
case DescriptorType::SAMPLER_2D_DEPTH:
|
||||
case DescriptorType::SAMPLER_2D_MS_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_MS_INT:
|
||||
case DescriptorType::SAMPLER_2D_MS_UINT:
|
||||
return true;
|
||||
default: ;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr bool is2dArrayTypeDescriptor(DescriptorType const type) noexcept {
|
||||
switch (type) {
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT:
|
||||
return true;
|
||||
default: ;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr bool isCubeTypeDescriptor(DescriptorType const type) noexcept {
|
||||
switch (type) {
|
||||
case DescriptorType::SAMPLER_CUBE_FLOAT:
|
||||
case DescriptorType::SAMPLER_CUBE_INT:
|
||||
case DescriptorType::SAMPLER_CUBE_UINT:
|
||||
case DescriptorType::SAMPLER_CUBE_DEPTH:
|
||||
return true;
|
||||
default: ;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr bool isCubeArrayTypeDescriptor(DescriptorType const type) noexcept {
|
||||
switch (type) {
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
|
||||
return true;
|
||||
default: ;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr bool isMultiSampledTypeDescriptor(DescriptorType const type) noexcept {
|
||||
switch (type) {
|
||||
case DescriptorType::SAMPLER_2D_MS_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_MS_INT:
|
||||
case DescriptorType::SAMPLER_2D_MS_UINT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT:
|
||||
return true;
|
||||
default: ;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr std::string_view to_string(DescriptorType type) noexcept {
|
||||
#define DESCRIPTOR_TYPE_CASE(TYPE) case DescriptorType::TYPE: return #TYPE;
|
||||
switch (type) {
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_FLOAT)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_INT)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_UINT)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_DEPTH)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_ARRAY_FLOAT)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_ARRAY_INT)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_ARRAY_UINT)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_ARRAY_DEPTH)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_FLOAT)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_INT)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_UINT)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_DEPTH)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_ARRAY_FLOAT)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_ARRAY_INT)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_ARRAY_UINT)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_CUBE_ARRAY_DEPTH)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_3D_FLOAT)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_3D_INT)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_3D_UINT)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_MS_FLOAT)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_MS_INT)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_MS_UINT)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_MS_ARRAY_FLOAT)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_MS_ARRAY_INT)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_2D_MS_ARRAY_UINT)
|
||||
DESCRIPTOR_TYPE_CASE(SAMPLER_EXTERNAL)
|
||||
DESCRIPTOR_TYPE_CASE(UNIFORM_BUFFER)
|
||||
DESCRIPTOR_TYPE_CASE(SHADER_STORAGE_BUFFER)
|
||||
DESCRIPTOR_TYPE_CASE(INPUT_ATTACHMENT)
|
||||
}
|
||||
return "UNKNOWN";
|
||||
#undef DESCRIPTOR_TYPE_CASE
|
||||
}
|
||||
|
||||
enum class DescriptorFlags : uint8_t {
|
||||
NONE = 0x00,
|
||||
DYNAMIC_OFFSET = 0x01
|
||||
@@ -254,6 +482,13 @@ using descriptor_set_t = uint8_t;
|
||||
using descriptor_binding_t = uint8_t;
|
||||
|
||||
struct DescriptorSetLayoutBinding {
|
||||
static bool isSampler(DescriptorType type) noexcept {
|
||||
return int(type) <= int(DescriptorType::SAMPLER_EXTERNAL);
|
||||
}
|
||||
static bool isBuffer(DescriptorType type) noexcept {
|
||||
return type == DescriptorType::UNIFORM_BUFFER ||
|
||||
type == DescriptorType::SHADER_STORAGE_BUFFER;
|
||||
}
|
||||
DescriptorType type;
|
||||
ShaderStageFlags stageFlags;
|
||||
descriptor_binding_t binding;
|
||||
@@ -264,7 +499,7 @@ struct DescriptorSetLayoutBinding {
|
||||
// no uninitialized padding bytes.
|
||||
// uint8_t externalSamplerDataIndex = EXTERNAL_SAMPLER_DATA_INDEX_UNUSED;
|
||||
|
||||
friend inline bool operator==(DescriptorSetLayoutBinding const& lhs,
|
||||
friend bool operator==(DescriptorSetLayoutBinding const& lhs,
|
||||
DescriptorSetLayoutBinding const& rhs) noexcept {
|
||||
return lhs.type == rhs.type &&
|
||||
lhs.flags == rhs.flags &&
|
||||
@@ -297,7 +532,7 @@ enum class TargetBufferFlags : uint32_t {
|
||||
ALL = COLOR_ALL | DEPTH | STENCIL //!< Color, depth and stencil buffer selected.
|
||||
};
|
||||
|
||||
inline constexpr TargetBufferFlags getTargetBufferFlagsAt(size_t index) noexcept {
|
||||
constexpr TargetBufferFlags getTargetBufferFlagsAt(size_t index) noexcept {
|
||||
if (index == 0u) return TargetBufferFlags::COLOR0;
|
||||
if (index == 1u) return TargetBufferFlags::COLOR1;
|
||||
if (index == 2u) return TargetBufferFlags::COLOR2;
|
||||
@@ -454,6 +689,24 @@ enum class SamplerType : uint8_t {
|
||||
SAMPLER_CUBEMAP_ARRAY, //!< Cube map array texture (feature level 2)
|
||||
};
|
||||
|
||||
constexpr std::string_view to_string(SamplerType const type) noexcept {
|
||||
switch (type) {
|
||||
case SamplerType::SAMPLER_2D:
|
||||
return "SAMPLER_2D";
|
||||
case SamplerType::SAMPLER_2D_ARRAY:
|
||||
return "SAMPLER_2D_ARRAY";
|
||||
case SamplerType::SAMPLER_CUBEMAP:
|
||||
return "SAMPLER_CUBEMAP";
|
||||
case SamplerType::SAMPLER_EXTERNAL:
|
||||
return "SAMPLER_EXTERNAL";
|
||||
case SamplerType::SAMPLER_3D:
|
||||
return "SAMPLER_3D";
|
||||
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||
return "SAMPLER_CUBEMAP_ARRAY";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
//! Subpass type
|
||||
enum class SubpassType : uint8_t {
|
||||
SUBPASS_INPUT
|
||||
@@ -467,6 +720,20 @@ enum class SamplerFormat : uint8_t {
|
||||
SHADOW = 3 //!< shadow sampler (PCF)
|
||||
};
|
||||
|
||||
constexpr std::string_view to_string(SamplerFormat const format) noexcept {
|
||||
switch (format) {
|
||||
case SamplerFormat::INT:
|
||||
return "INT";
|
||||
case SamplerFormat::UINT:
|
||||
return "UINT";
|
||||
case SamplerFormat::FLOAT:
|
||||
return "FLOAT";
|
||||
case SamplerFormat::SHADOW:
|
||||
return "SHADOW";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
/**
|
||||
* Supported element types
|
||||
*/
|
||||
@@ -506,6 +773,15 @@ enum class BufferObjectBinding : uint8_t {
|
||||
SHADER_STORAGE
|
||||
};
|
||||
|
||||
constexpr std::string_view to_string(BufferObjectBinding type) noexcept {
|
||||
switch (type) {
|
||||
case BufferObjectBinding::VERTEX: return "VERTEX";
|
||||
case BufferObjectBinding::UNIFORM: return "UNIFORM";
|
||||
case BufferObjectBinding::SHADER_STORAGE: return "SHADER_STORAGE";
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
//! Face culling Mode
|
||||
enum class CullingMode : uint8_t {
|
||||
NONE, //!< No culling, front and back faces are visible
|
||||
@@ -767,6 +1043,8 @@ enum class TextureFormat : uint16_t {
|
||||
SRGB_ALPHA_BPTC_UNORM, // BC7 sRGB
|
||||
};
|
||||
|
||||
TextureType getTextureType(TextureFormat format) noexcept;
|
||||
|
||||
//! Bitmask describing the intended Texture Usage
|
||||
enum class TextureUsage : uint16_t {
|
||||
NONE = 0x0000,
|
||||
@@ -794,7 +1072,7 @@ enum class TextureSwizzle : uint8_t {
|
||||
};
|
||||
|
||||
//! returns whether this format a depth format
|
||||
static constexpr bool isDepthFormat(TextureFormat format) noexcept {
|
||||
constexpr bool isDepthFormat(TextureFormat format) noexcept {
|
||||
switch (format) {
|
||||
case TextureFormat::DEPTH32F:
|
||||
case TextureFormat::DEPTH24:
|
||||
@@ -807,7 +1085,7 @@ static constexpr bool isDepthFormat(TextureFormat format) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr bool isStencilFormat(TextureFormat format) noexcept {
|
||||
constexpr bool isStencilFormat(TextureFormat format) noexcept {
|
||||
switch (format) {
|
||||
case TextureFormat::STENCIL8:
|
||||
case TextureFormat::DEPTH24_STENCIL8:
|
||||
@@ -818,7 +1096,7 @@ static constexpr bool isStencilFormat(TextureFormat format) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
inline constexpr bool isColorFormat(TextureFormat format) noexcept {
|
||||
constexpr bool isColorFormat(TextureFormat format) noexcept {
|
||||
switch (format) {
|
||||
// Standard color formats
|
||||
case TextureFormat::R8:
|
||||
@@ -845,7 +1123,7 @@ inline constexpr bool isColorFormat(TextureFormat format) noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
static constexpr bool isUnsignedIntFormat(TextureFormat format) {
|
||||
constexpr bool isUnsignedIntFormat(TextureFormat format) {
|
||||
switch (format) {
|
||||
case TextureFormat::R8UI:
|
||||
case TextureFormat::R16UI:
|
||||
@@ -866,7 +1144,7 @@ static constexpr bool isUnsignedIntFormat(TextureFormat format) {
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr bool isSignedIntFormat(TextureFormat format) {
|
||||
constexpr bool isSignedIntFormat(TextureFormat format) {
|
||||
switch (format) {
|
||||
case TextureFormat::R8I:
|
||||
case TextureFormat::R16I:
|
||||
@@ -888,35 +1166,35 @@ static constexpr bool isSignedIntFormat(TextureFormat format) {
|
||||
}
|
||||
|
||||
//! returns whether this format is a compressed format
|
||||
static constexpr bool isCompressedFormat(TextureFormat format) noexcept {
|
||||
constexpr bool isCompressedFormat(TextureFormat format) noexcept {
|
||||
return format >= TextureFormat::EAC_R11;
|
||||
}
|
||||
|
||||
//! returns whether this format is an ETC2 compressed format
|
||||
static constexpr bool isETC2Compression(TextureFormat format) noexcept {
|
||||
constexpr bool isETC2Compression(TextureFormat format) noexcept {
|
||||
return format >= TextureFormat::EAC_R11 && format <= TextureFormat::ETC2_EAC_SRGBA8;
|
||||
}
|
||||
|
||||
//! returns whether this format is an S3TC compressed format
|
||||
static constexpr bool isS3TCCompression(TextureFormat format) noexcept {
|
||||
constexpr bool isS3TCCompression(TextureFormat format) noexcept {
|
||||
return format >= TextureFormat::DXT1_RGB && format <= TextureFormat::DXT5_SRGBA;
|
||||
}
|
||||
|
||||
static constexpr bool isS3TCSRGBCompression(TextureFormat format) noexcept {
|
||||
constexpr bool isS3TCSRGBCompression(TextureFormat format) noexcept {
|
||||
return format >= TextureFormat::DXT1_SRGB && format <= TextureFormat::DXT5_SRGBA;
|
||||
}
|
||||
|
||||
//! returns whether this format is an RGTC compressed format
|
||||
static constexpr bool isRGTCCompression(TextureFormat format) noexcept {
|
||||
constexpr bool isRGTCCompression(TextureFormat format) noexcept {
|
||||
return format >= TextureFormat::RED_RGTC1 && format <= TextureFormat::SIGNED_RED_GREEN_RGTC2;
|
||||
}
|
||||
|
||||
//! returns whether this format is an BPTC compressed format
|
||||
static constexpr bool isBPTCCompression(TextureFormat format) noexcept {
|
||||
constexpr bool isBPTCCompression(TextureFormat format) noexcept {
|
||||
return format >= TextureFormat::RGB_BPTC_SIGNED_FLOAT && format <= TextureFormat::SRGB_ALPHA_BPTC_UNORM;
|
||||
}
|
||||
|
||||
static constexpr bool isASTCCompression(TextureFormat format) noexcept {
|
||||
constexpr bool isASTCCompression(TextureFormat format) noexcept {
|
||||
return format >= TextureFormat::RGBA_ASTC_4x4 && format <= TextureFormat::SRGB8_ALPHA8_ASTC_12x12;
|
||||
}
|
||||
|
||||
@@ -1037,19 +1315,23 @@ struct SamplerParams { // NOLINT
|
||||
assert_invariant(lhs.padding2 == 0);
|
||||
auto* pLhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&lhs));
|
||||
auto* pRhs = reinterpret_cast<uint32_t const*>(reinterpret_cast<char const*>(&rhs));
|
||||
return *pLhs == *pRhs;
|
||||
return *pLhs < *pRhs;
|
||||
}
|
||||
};
|
||||
|
||||
bool isFiltered() const noexcept {
|
||||
return filterMag != SamplerMagFilter::NEAREST || filterMin != SamplerMinFilter::NEAREST;
|
||||
}
|
||||
|
||||
private:
|
||||
friend inline bool operator == (SamplerParams lhs, SamplerParams rhs) noexcept {
|
||||
return SamplerParams::EqualTo{}(lhs, rhs);
|
||||
friend bool operator == (SamplerParams lhs, SamplerParams rhs) noexcept {
|
||||
return EqualTo{}(lhs, rhs);
|
||||
}
|
||||
friend inline bool operator != (SamplerParams lhs, SamplerParams rhs) noexcept {
|
||||
return !SamplerParams::EqualTo{}(lhs, rhs);
|
||||
friend bool operator != (SamplerParams lhs, SamplerParams rhs) noexcept {
|
||||
return !EqualTo{}(lhs, rhs);
|
||||
}
|
||||
friend inline bool operator < (SamplerParams lhs, SamplerParams rhs) noexcept {
|
||||
return SamplerParams::LessThan{}(lhs, rhs);
|
||||
friend bool operator < (SamplerParams lhs, SamplerParams rhs) noexcept {
|
||||
return LessThan{}(lhs, rhs);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1099,15 +1381,15 @@ struct SamplerYcbcrConversion {// NOLINT
|
||||
};
|
||||
|
||||
private:
|
||||
friend inline bool operator == (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
||||
friend bool operator == (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
||||
noexcept {
|
||||
return SamplerYcbcrConversion::EqualTo{}(lhs, rhs);
|
||||
}
|
||||
friend inline bool operator != (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
||||
friend bool operator != (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
||||
noexcept {
|
||||
return !SamplerYcbcrConversion::EqualTo{}(lhs, rhs);
|
||||
}
|
||||
friend inline bool operator < (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
||||
friend bool operator < (SamplerYcbcrConversion lhs, SamplerYcbcrConversion rhs)
|
||||
noexcept {
|
||||
return SamplerYcbcrConversion::LessThan{}(lhs, rhs);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#include "DataReshaper.h"
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <utils/CString.h>
|
||||
|
||||
#include <string_view>
|
||||
@@ -223,6 +225,143 @@ size_t getFormatSize(TextureFormat format) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
TextureType getTextureType(TextureFormat const format) noexcept {
|
||||
switch (format) {
|
||||
case TextureFormat::UNUSED:
|
||||
// should not happen
|
||||
return TextureType::FLOAT;
|
||||
|
||||
case TextureFormat::R8:
|
||||
case TextureFormat::R16F:
|
||||
case TextureFormat::RG8:
|
||||
case TextureFormat::RGB565:
|
||||
case TextureFormat::RGB5_A1:
|
||||
case TextureFormat::RGBA4:
|
||||
case TextureFormat::R32F:
|
||||
case TextureFormat::RGB8:
|
||||
case TextureFormat::SRGB8:
|
||||
case TextureFormat::RG16F:
|
||||
case TextureFormat::R11F_G11F_B10F:
|
||||
case TextureFormat::RGB9_E5:
|
||||
case TextureFormat::RGBA8:
|
||||
case TextureFormat::SRGB8_A8:
|
||||
case TextureFormat::RGB10_A2:
|
||||
case TextureFormat::RGB16F:
|
||||
case TextureFormat::RG32F:
|
||||
case TextureFormat::RGBA16F:
|
||||
case TextureFormat::RGB32F:
|
||||
case TextureFormat::RGBA32F:
|
||||
return TextureType::FLOAT;
|
||||
|
||||
case TextureFormat::R8_SNORM:
|
||||
case TextureFormat::RG8_SNORM:
|
||||
case TextureFormat::RGB8_SNORM:
|
||||
case TextureFormat::RGBA8_SNORM:
|
||||
// SNORM are treated as float
|
||||
return TextureType::FLOAT;
|
||||
|
||||
case TextureFormat::R8UI:
|
||||
case TextureFormat::R16UI:
|
||||
case TextureFormat::RG8UI:
|
||||
case TextureFormat::RGB8UI:
|
||||
case TextureFormat::R32UI:
|
||||
case TextureFormat::RG16UI:
|
||||
case TextureFormat::RGBA8UI:
|
||||
case TextureFormat::RGB16UI:
|
||||
case TextureFormat::RG32UI:
|
||||
case TextureFormat::RGBA16UI:
|
||||
case TextureFormat::RGB32UI:
|
||||
case TextureFormat::RGBA32UI:
|
||||
return TextureType::UINT;
|
||||
|
||||
case TextureFormat::R8I:
|
||||
case TextureFormat::R16I:
|
||||
case TextureFormat::RG8I:
|
||||
case TextureFormat::RGB8I:
|
||||
case TextureFormat::R32I:
|
||||
case TextureFormat::RG16I:
|
||||
case TextureFormat::RGBA8I:
|
||||
case TextureFormat::RGB16I:
|
||||
case TextureFormat::RG32I:
|
||||
case TextureFormat::RGBA16I:
|
||||
case TextureFormat::RGB32I:
|
||||
case TextureFormat::RGBA32I:
|
||||
return TextureType::INT;
|
||||
|
||||
case TextureFormat::DEPTH16:
|
||||
case TextureFormat::DEPTH24:
|
||||
case TextureFormat::DEPTH32F:
|
||||
return TextureType::DEPTH;
|
||||
|
||||
case TextureFormat::STENCIL8:
|
||||
return TextureType::STENCIL;
|
||||
|
||||
case TextureFormat::DEPTH24_STENCIL8:
|
||||
case TextureFormat::DEPTH32F_STENCIL8:
|
||||
return TextureType::DEPTH_STENCIL;
|
||||
|
||||
// Compressed formats ---------------------------------------------------------------------
|
||||
|
||||
case TextureFormat::EAC_RG11:
|
||||
case TextureFormat::EAC_RG11_SIGNED:
|
||||
case TextureFormat::ETC2_EAC_RGBA8:
|
||||
case TextureFormat::ETC2_EAC_SRGBA8:
|
||||
case TextureFormat::EAC_R11:
|
||||
case TextureFormat::EAC_R11_SIGNED:
|
||||
case TextureFormat::ETC2_RGB8:
|
||||
case TextureFormat::ETC2_SRGB8:
|
||||
case TextureFormat::ETC2_RGB8_A1:
|
||||
case TextureFormat::ETC2_SRGB8_A1:
|
||||
case TextureFormat::DXT1_RGB:
|
||||
case TextureFormat::DXT1_RGBA:
|
||||
case TextureFormat::DXT1_SRGB:
|
||||
case TextureFormat::DXT1_SRGBA:
|
||||
case TextureFormat::DXT3_RGBA:
|
||||
case TextureFormat::DXT3_SRGBA:
|
||||
case TextureFormat::DXT5_RGBA:
|
||||
case TextureFormat::DXT5_SRGBA:
|
||||
case TextureFormat::RED_RGTC1:
|
||||
case TextureFormat::SIGNED_RED_RGTC1:
|
||||
case TextureFormat::RED_GREEN_RGTC2:
|
||||
case TextureFormat::SIGNED_RED_GREEN_RGTC2:
|
||||
case TextureFormat::RGB_BPTC_SIGNED_FLOAT:
|
||||
case TextureFormat::RGB_BPTC_UNSIGNED_FLOAT:
|
||||
case TextureFormat::RGBA_BPTC_UNORM:
|
||||
case TextureFormat::SRGB_ALPHA_BPTC_UNORM:
|
||||
case TextureFormat::RGBA_ASTC_4x4:
|
||||
case TextureFormat::RGBA_ASTC_5x4:
|
||||
case TextureFormat::RGBA_ASTC_5x5:
|
||||
case TextureFormat::RGBA_ASTC_6x5:
|
||||
case TextureFormat::RGBA_ASTC_6x6:
|
||||
case TextureFormat::RGBA_ASTC_8x5:
|
||||
case TextureFormat::RGBA_ASTC_8x6:
|
||||
case TextureFormat::RGBA_ASTC_8x8:
|
||||
case TextureFormat::RGBA_ASTC_10x5:
|
||||
case TextureFormat::RGBA_ASTC_10x6:
|
||||
case TextureFormat::RGBA_ASTC_10x8:
|
||||
case TextureFormat::RGBA_ASTC_10x10:
|
||||
case TextureFormat::RGBA_ASTC_12x10:
|
||||
case TextureFormat::RGBA_ASTC_12x12:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_4x4:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_5x4:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_5x5:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_6x5:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_6x6:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_8x5:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_8x6:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_8x8:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_10x5:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_10x6:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_10x8:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_10x10:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_12x10:
|
||||
case TextureFormat::SRGB8_ALPHA8_ASTC_12x12:
|
||||
return TextureType::FLOAT;
|
||||
}
|
||||
|
||||
return TextureType::FLOAT;
|
||||
}
|
||||
|
||||
size_t getFormatComponentCount(TextureFormat format) noexcept {
|
||||
switch (format) {
|
||||
case TextureFormat::R8:
|
||||
|
||||
@@ -18,12 +18,13 @@
|
||||
#include "private/backend/CircularBuffer.h"
|
||||
#include "private/backend/CommandStream.h"
|
||||
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Mutex.h>
|
||||
#include <utils/ostream.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/Systrace.h>
|
||||
#include <utils/debug.h>
|
||||
|
||||
#include <algorithm>
|
||||
@@ -79,7 +80,7 @@ bool CommandBufferQueue::isExitRequested() const {
|
||||
|
||||
|
||||
void CommandBufferQueue::flush() noexcept {
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
CircularBuffer& circularBuffer = mCircularBuffer;
|
||||
if (circularBuffer.empty()) {
|
||||
@@ -129,7 +130,7 @@ void CommandBufferQueue::flush() noexcept {
|
||||
mHighWatermark = std::max(mHighWatermark, totalUsed);
|
||||
#endif
|
||||
|
||||
SYSTRACE_NAME("waiting: CircularBuffer::flush()");
|
||||
FILAMENT_TRACING_NAME(FILAMENT_TRACING_CATEGORY_FILAMENT, "waiting: CircularBuffer::flush()");
|
||||
|
||||
FILAMENT_CHECK_POSTCONDITION(!mPaused) <<
|
||||
"CommandStream is full, but since the rendering thread is paused, "
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
#include "private/backend/CommandStream.h"
|
||||
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
#if DEBUG_COMMAND_STREAM
|
||||
#include <utils/CallStack.h>
|
||||
#endif
|
||||
@@ -24,7 +26,6 @@
|
||||
#include <utils/Log.h>
|
||||
#include <utils/ostream.h>
|
||||
#include <utils/Profiler.h>
|
||||
#include <utils/Systrace.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
@@ -79,12 +80,13 @@ CommandStream::CommandStream(Driver& driver, CircularBuffer& buffer) noexcept
|
||||
}
|
||||
|
||||
void CommandStream::execute(void* buffer) {
|
||||
// NOTE: we can't use SYSTRACE_CALL() or similar here because, execute() below, also
|
||||
// NOTE: we can't use FILAMENT_TRACING_CALL() or similar here because, execute() below, also
|
||||
// uses systrace BEGIN/END and the END is not guaranteed to be happening in this scope.
|
||||
|
||||
Profiler profiler;
|
||||
|
||||
if (SYSTRACE_TAG) {
|
||||
|
||||
if constexpr (FILAMENT_TRACING_ENABLED) {
|
||||
if (UTILS_UNLIKELY(mUsePerformanceCounter)) {
|
||||
// we want to remove all this when tracing is completely disabled
|
||||
profiler.resetEvents(Profiler::EV_CPU_CYCLES | Profiler::EV_BPU_MISSES);
|
||||
@@ -100,17 +102,17 @@ void CommandStream::execute(void* buffer) {
|
||||
}
|
||||
});
|
||||
|
||||
if (SYSTRACE_TAG) {
|
||||
if constexpr (FILAMENT_TRACING_ENABLED) {
|
||||
if (UTILS_UNLIKELY(mUsePerformanceCounter)) {
|
||||
// we want to remove all this when tracing is completely disabled
|
||||
profiler.stop();
|
||||
UTILS_UNUSED Profiler::Counters const counters = profiler.readCounters();
|
||||
SYSTRACE_CONTEXT();
|
||||
SYSTRACE_VALUE32("GLThread (I)", counters.getInstructions());
|
||||
SYSTRACE_VALUE32("GLThread (C)", counters.getCpuCycles());
|
||||
SYSTRACE_VALUE32("GLThread (CPI x10)", counters.getCPI() * 10);
|
||||
SYSTRACE_VALUE32("GLThread (BPU miss)", counters.getBranchMisses());
|
||||
SYSTRACE_VALUE32("GLThread (I / BPU miss)",
|
||||
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "GLThread (I)", counters.getInstructions());
|
||||
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "GLThread (C)", counters.getCpuCycles());
|
||||
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "GLThread (CPI x10)", counters.getCPI() * 10);
|
||||
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "GLThread (BPU miss)", counters.getBranchMisses());
|
||||
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "GLThread (I / BPU miss)",
|
||||
counters.getInstructions() / counters.getBranchMisses());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,9 @@
|
||||
#include "private/backend/Driver.h"
|
||||
#include "private/backend/CommandStream.h"
|
||||
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Systrace.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
@@ -38,7 +39,7 @@
|
||||
#if DEBUG_LEVEL == DEBUG_LEVEL_NONE
|
||||
# define SYSTRACE()
|
||||
#elif DEBUG_LEVEL == DEBUG_LEVEL_SYSTRACE
|
||||
# define SYSTRACE() SYSTRACE_CALL();
|
||||
# define SYSTRACE() FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
#else
|
||||
# error "invalid debug level"
|
||||
#endif
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include "CompilerThreadPool.h"
|
||||
|
||||
#include <utils/Systrace.h>
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
@@ -41,7 +41,7 @@ void CompilerThreadPool::init(uint32_t threadCount,
|
||||
|
||||
for (size_t i = 0; i < threadCount; i++) {
|
||||
mCompilerThreads.emplace_back([this, setup, cleanup]() {
|
||||
SYSTRACE_CONTEXT();
|
||||
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
(*setup)();
|
||||
|
||||
@@ -54,7 +54,7 @@ void CompilerThreadPool::init(uint32_t threadCount,
|
||||
[](auto&& q) { return q.empty(); }));
|
||||
});
|
||||
|
||||
SYSTRACE_VALUE32("CompilerThreadPool Jobs",
|
||||
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "CompilerThreadPool Jobs",
|
||||
mQueues[0].size() + mQueues[1].size());
|
||||
|
||||
if (UTILS_LIKELY(!mExitRequested)) {
|
||||
|
||||
@@ -23,11 +23,12 @@
|
||||
#include <backend/BufferDescriptor.h>
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/ostream.h>
|
||||
#include <utils/Systrace.h>
|
||||
|
||||
#include <math/half.h>
|
||||
#include <math/vec2.h>
|
||||
@@ -151,30 +152,31 @@ void DriverBase::debugCommandBegin(CommandStream* cmds, bool synchronous, const
|
||||
utils::slog.d << methodName << utils::io::endl;
|
||||
}
|
||||
if constexpr (bool(FILAMENT_DEBUG_COMMANDS & FILAMENT_DEBUG_COMMANDS_SYSTRACE)) {
|
||||
SYSTRACE_CONTEXT();
|
||||
SYSTRACE_NAME_BEGIN(methodName);
|
||||
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
FILAMENT_TRACING_NAME_BEGIN(FILAMENT_TRACING_CATEGORY_FILAMENT, methodName);
|
||||
|
||||
if (!synchronous) {
|
||||
cmds->queueCommand([=]() {
|
||||
SYSTRACE_CONTEXT();
|
||||
SYSTRACE_NAME_BEGIN(methodName);
|
||||
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
FILAMENT_TRACING_NAME_BEGIN(FILAMENT_TRACING_CATEGORY_FILAMENT, methodName);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DriverBase::debugCommandEnd(CommandStream* cmds, bool synchronous, const char* methodName) noexcept {
|
||||
void DriverBase::debugCommandEnd(CommandStream* cmds, bool synchronous,
|
||||
const char* methodName) noexcept {
|
||||
if constexpr (bool(FILAMENT_DEBUG_COMMANDS > FILAMENT_DEBUG_COMMANDS_NONE)) {
|
||||
if constexpr (bool(FILAMENT_DEBUG_COMMANDS & FILAMENT_DEBUG_COMMANDS_SYSTRACE)) {
|
||||
if (!synchronous) {
|
||||
cmds->queueCommand([]() {
|
||||
SYSTRACE_CONTEXT();
|
||||
SYSTRACE_NAME_END();
|
||||
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
FILAMENT_TRACING_NAME_END(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
});
|
||||
}
|
||||
SYSTRACE_CONTEXT();
|
||||
SYSTRACE_NAME_END();
|
||||
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
FILAMENT_TRACING_NAME_END(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
|
||||
#include <private/backend/PlatformFactory.h>
|
||||
|
||||
#include <utils/Systrace.h>
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
#include <utils/debug.h>
|
||||
|
||||
// We need to keep this up top for the linux (X11) name collisions.
|
||||
@@ -85,7 +86,7 @@ namespace filament::backend {
|
||||
// responsible for destroying it. Initialization of the backend API is deferred until
|
||||
// createDriver(). The passed-in backend hint is replaced with the resolved backend.
|
||||
Platform* PlatformFactory::create(Backend* backend) noexcept {
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
assert_invariant(backend);
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#ifndef TNT_FILAMENT_BACKEND_SYSTRACEPROFILE_H
|
||||
#define TNT_FILAMENT_BACKEND_SYSTRACEPROFILE_H
|
||||
|
||||
#include <utils/Systrace.h>
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
#define PROFILE_SCOPE(marker) SYSTRACE_NAME(marker)
|
||||
|
||||
|
||||
@@ -672,22 +672,8 @@ void MetalDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
|
||||
// nothing to do, timer query was constructed in createTimerQueryS
|
||||
}
|
||||
|
||||
const char* toString(DescriptorType type) {
|
||||
switch (type) {
|
||||
case DescriptorType::UNIFORM_BUFFER:
|
||||
return "UNIFORM_BUFFER";
|
||||
case DescriptorType::SHADER_STORAGE_BUFFER:
|
||||
return "SHADER_STORAGE_BUFFER";
|
||||
case DescriptorType::SAMPLER:
|
||||
return "SAMPLER";
|
||||
case DescriptorType::INPUT_ATTACHMENT:
|
||||
return "INPUT_ATTACHMENT";
|
||||
case DescriptorType::SAMPLER_EXTERNAL:
|
||||
return "SAMPLER_EXTERNAL";
|
||||
}
|
||||
}
|
||||
|
||||
const char* toString(ShaderStageFlags flags) {
|
||||
UTILS_UNUSED
|
||||
static const char* toString(ShaderStageFlags flags) {
|
||||
std::vector<const char*> stages;
|
||||
if (any(flags & ShaderStageFlags::VERTEX)) {
|
||||
stages.push_back("VERTEX");
|
||||
|
||||
@@ -1356,7 +1356,31 @@ id<MTLArgumentEncoder> MetalDescriptorSetLayout::getArgumentEncoderSlow(id<MTLDe
|
||||
[arguments addObject:bufferArgument];
|
||||
break;
|
||||
}
|
||||
case DescriptorType::SAMPLER:
|
||||
case DescriptorType::SAMPLER_2D_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_INT:
|
||||
case DescriptorType::SAMPLER_2D_UINT:
|
||||
case DescriptorType::SAMPLER_2D_DEPTH:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
|
||||
case DescriptorType::SAMPLER_CUBE_FLOAT:
|
||||
case DescriptorType::SAMPLER_CUBE_INT:
|
||||
case DescriptorType::SAMPLER_CUBE_UINT:
|
||||
case DescriptorType::SAMPLER_CUBE_DEPTH:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
|
||||
case DescriptorType::SAMPLER_3D_FLOAT:
|
||||
case DescriptorType::SAMPLER_3D_INT:
|
||||
case DescriptorType::SAMPLER_3D_UINT:
|
||||
case DescriptorType::SAMPLER_2D_MS_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_MS_INT:
|
||||
case DescriptorType::SAMPLER_2D_MS_UINT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT:
|
||||
case DescriptorType::SAMPLER_EXTERNAL: {
|
||||
MTLArgumentDescriptor* textureArgument = [MTLArgumentDescriptor argumentDescriptor];
|
||||
textureArgument.index = binding.binding * 2;
|
||||
@@ -1478,7 +1502,31 @@ id<MTLBuffer> MetalDescriptorSet::finalizeAndGetBuffer(MetalDriver* driver, Shad
|
||||
atIndex:binding.binding * 2];
|
||||
break;
|
||||
}
|
||||
case DescriptorType::SAMPLER:
|
||||
case DescriptorType::SAMPLER_2D_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_INT:
|
||||
case DescriptorType::SAMPLER_2D_UINT:
|
||||
case DescriptorType::SAMPLER_2D_DEPTH:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
|
||||
case DescriptorType::SAMPLER_CUBE_FLOAT:
|
||||
case DescriptorType::SAMPLER_CUBE_INT:
|
||||
case DescriptorType::SAMPLER_CUBE_UINT:
|
||||
case DescriptorType::SAMPLER_CUBE_DEPTH:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
|
||||
case DescriptorType::SAMPLER_3D_FLOAT:
|
||||
case DescriptorType::SAMPLER_3D_INT:
|
||||
case DescriptorType::SAMPLER_3D_UINT:
|
||||
case DescriptorType::SAMPLER_2D_MS_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_MS_INT:
|
||||
case DescriptorType::SAMPLER_2D_MS_UINT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT:
|
||||
case DescriptorType::SAMPLER_EXTERNAL: {
|
||||
auto found = textures.find(binding.binding);
|
||||
if (found == textures.end()) {
|
||||
|
||||
@@ -69,9 +69,8 @@ public:
|
||||
assert_invariant(set < MAX_DESCRIPTOR_SET_COUNT);
|
||||
assert_invariant(binding < MAX_DESCRIPTOR_COUNT);
|
||||
assert_invariant(entry.binding < 128); // we reserve 1 bit for the type right now
|
||||
mStorage[set][binding] = { (uint8_t)entry.binding,
|
||||
entry.type == DescriptorType::SAMPLER ||
|
||||
entry.type == DescriptorType::SAMPLER_EXTERNAL };
|
||||
mStorage[set][binding] = { uint8_t(entry.binding),
|
||||
DescriptorSetLayoutBinding::isSampler(entry.type) };
|
||||
mActiveDescriptors[set].set(binding);
|
||||
}
|
||||
|
||||
|
||||
@@ -95,7 +95,32 @@ GLDescriptorSet::GLDescriptorSet(OpenGLContext& gl, DescriptorSetLayoutHandle ds
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DescriptorType::SAMPLER:
|
||||
|
||||
case DescriptorType::SAMPLER_2D_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_INT:
|
||||
case DescriptorType::SAMPLER_2D_UINT:
|
||||
case DescriptorType::SAMPLER_2D_DEPTH:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
|
||||
case DescriptorType::SAMPLER_CUBE_FLOAT:
|
||||
case DescriptorType::SAMPLER_CUBE_INT:
|
||||
case DescriptorType::SAMPLER_CUBE_UINT:
|
||||
case DescriptorType::SAMPLER_CUBE_DEPTH:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
|
||||
case DescriptorType::SAMPLER_3D_FLOAT:
|
||||
case DescriptorType::SAMPLER_3D_INT:
|
||||
case DescriptorType::SAMPLER_3D_UINT:
|
||||
case DescriptorType::SAMPLER_2D_MS_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_MS_INT:
|
||||
case DescriptorType::SAMPLER_2D_MS_UINT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT:
|
||||
case DescriptorType::SAMPLER_EXTERNAL:
|
||||
if (UTILS_UNLIKELY(gl.isES2())) {
|
||||
desc.emplace<SamplerGLES2>();
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <backend/Platform.h>
|
||||
#include <backend/Program.h>
|
||||
|
||||
#include <utils/Systrace.h>
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
@@ -36,7 +36,7 @@ OpenGLBlobCache::OpenGLBlobCache(OpenGLContext& gl) noexcept
|
||||
|
||||
GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
|
||||
Program const& program) const noexcept {
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
if (!mCachingSupported || !platform.hasRetrieveBlobFunc()) {
|
||||
// the key is never updated in that case
|
||||
return 0;
|
||||
@@ -68,7 +68,7 @@ GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
|
||||
programId = glCreateProgram();
|
||||
|
||||
{ // scope for systrace
|
||||
SYSTRACE_NAME("glProgramBinary");
|
||||
FILAMENT_TRACING_NAME(FILAMENT_TRACING_CATEGORY_FILAMENT, "glProgramBinary");
|
||||
glProgramBinary(programId, blob->format, blob->data, programBinarySize);
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
|
||||
|
||||
void OpenGLBlobCache::insert(Platform& platform,
|
||||
BlobCacheKey const& key, GLuint program) noexcept {
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
if (!mCachingSupported || !platform.hasInsertBlobFunc()) {
|
||||
// the key is never updated in that case
|
||||
return;
|
||||
@@ -100,7 +100,7 @@ void OpenGLBlobCache::insert(Platform& platform,
|
||||
GLenum format;
|
||||
GLint programBinarySize = 0;
|
||||
{ // scope for systrace
|
||||
SYSTRACE_NAME("glGetProgramiv");
|
||||
FILAMENT_TRACING_NAME(FILAMENT_TRACING_CATEGORY_FILAMENT, "glGetProgramiv");
|
||||
glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programBinarySize);
|
||||
}
|
||||
if (programBinarySize) {
|
||||
@@ -108,7 +108,7 @@ void OpenGLBlobCache::insert(Platform& platform,
|
||||
std::unique_ptr<Blob, decltype(&::free)> blob{ (Blob*)malloc(size), &::free };
|
||||
if (UTILS_LIKELY(blob)) {
|
||||
{ // scope for systrace
|
||||
SYSTRACE_NAME("glGetProgramBinary");
|
||||
FILAMENT_TRACING_NAME(FILAMENT_TRACING_CATEGORY_FILAMENT, "glGetProgramBinary");
|
||||
glGetProgramBinary(program, programBinarySize,
|
||||
&programBinarySize, &format, blob->data);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@
|
||||
#include "private/backend/Dispatcher.h"
|
||||
#include "private/backend/DriverApi.h"
|
||||
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utils/BitmaskEnum.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
@@ -51,7 +53,6 @@
|
||||
#include <utils/Invocable.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/Systrace.h>
|
||||
#include <utils/Slice.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
@@ -98,13 +99,13 @@
|
||||
|
||||
#define DEBUG_GROUP_MARKER_NONE 0x00 // no debug marker
|
||||
#define DEBUG_GROUP_MARKER_OPENGL 0x01 // markers in the gl command queue (req. driver support)
|
||||
#define DEBUG_GROUP_MARKER_BACKEND 0x02 // markers on the backend side (systrace)
|
||||
#define DEBUG_GROUP_MARKER_BACKEND 0x02 // markers on the backend side (perfetto)
|
||||
#define DEBUG_GROUP_MARKER_ALL 0xFF // all markers
|
||||
|
||||
#define DEBUG_MARKER_NONE 0x00 // no debug marker
|
||||
#define DEBUG_MARKER_OPENGL 0x01 // markers in the gl command queue (req. driver support)
|
||||
#define DEBUG_MARKER_BACKEND 0x02 // markers on the backend side (systrace)
|
||||
#define DEBUG_MARKER_PROFILE 0x04 // profiling on the backend side (systrace)
|
||||
#define DEBUG_MARKER_BACKEND 0x02 // markers on the backend side (perfetto)
|
||||
#define DEBUG_MARKER_PROFILE 0x04 // profiling on the backend side (perfetto)
|
||||
#define DEBUG_MARKER_ALL (0xFF & ~DEBUG_MARKER_PROFILE) // all markers
|
||||
|
||||
// set to the desired debug marker level (for user markers [default: All])
|
||||
@@ -248,8 +249,8 @@ OpenGLDriver::DebugMarker::DebugMarker(OpenGLDriver& driver, const char* string)
|
||||
#endif
|
||||
|
||||
#if DEBUG_MARKER_LEVEL & DEBUG_MARKER_BACKEND
|
||||
SYSTRACE_CONTEXT();
|
||||
SYSTRACE_NAME_BEGIN(string);
|
||||
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
FILAMENT_TRACING_NAME_BEGIN(FILAMENT_TRACING_CATEGORY_FILAMENT, string);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@@ -265,8 +266,8 @@ OpenGLDriver::DebugMarker::~DebugMarker() noexcept {
|
||||
#endif
|
||||
|
||||
#if DEBUG_MARKER_LEVEL & DEBUG_MARKER_BACKEND
|
||||
SYSTRACE_CONTEXT();
|
||||
SYSTRACE_NAME_END();
|
||||
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
FILAMENT_TRACING_NAME_END(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@@ -3348,8 +3349,8 @@ void OpenGLDriver::pushGroupMarker(char const* string) {
|
||||
#endif
|
||||
|
||||
#if DEBUG_GROUP_MARKER_LEVEL & DEBUG_GROUP_MARKER_BACKEND
|
||||
SYSTRACE_CONTEXT();
|
||||
SYSTRACE_NAME_BEGIN(string);
|
||||
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
FILAMENT_TRACING_NAME_BEGIN(FILAMENT_TRACING_CATEGORY_FILAMENT, string);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@@ -3365,8 +3366,8 @@ void OpenGLDriver::popGroupMarker(int) {
|
||||
#endif
|
||||
|
||||
#if DEBUG_GROUP_MARKER_LEVEL & DEBUG_GROUP_MARKER_BACKEND
|
||||
SYSTRACE_CONTEXT();
|
||||
SYSTRACE_NAME_END();
|
||||
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
FILAMENT_TRACING_NAME_END(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@@ -3685,7 +3686,7 @@ void OpenGLDriver::endFrame(UTILS_UNUSED uint32_t frameId) {
|
||||
gl.depthFunc(GL_LESS);
|
||||
gl.disable(GL_SCISSOR_TEST);
|
||||
#endif
|
||||
//SYSTRACE_NAME("glFinish");
|
||||
//FILAMENT_TRACING_NAME(FILAMENT_TRACING_CATEGORY_FILAMENT, "glFinish");
|
||||
//glFinish();
|
||||
mPlatform.endFrame(frameId);
|
||||
insertEventMarker("endFrame");
|
||||
|
||||
@@ -25,12 +25,13 @@
|
||||
#include <backend/Program.h>
|
||||
#include <backend/Handle.h>
|
||||
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
#include <utils/BitmaskEnum.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Systrace.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
@@ -96,8 +97,7 @@ OpenGLProgram::~OpenGLProgram() noexcept {
|
||||
}
|
||||
|
||||
void OpenGLProgram::initialize(OpenGLDriver& gld) {
|
||||
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
assert_invariant(gl.program == 0);
|
||||
assert_invariant(mToken);
|
||||
@@ -122,8 +122,7 @@ void OpenGLProgram::initialize(OpenGLDriver& gld) {
|
||||
*/
|
||||
void OpenGLProgram::initializeProgramState(OpenGLContext& context, GLuint program,
|
||||
LazyInitializationData& lazyInitializationData) noexcept {
|
||||
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
// from the pipeline layout we compute a mapping from {set, binding} to {binding}
|
||||
// for both buffers and textures
|
||||
@@ -175,7 +174,31 @@ void OpenGLProgram::initializeProgramState(OpenGLContext& context, GLuint progra
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DescriptorType::SAMPLER:
|
||||
case DescriptorType::SAMPLER_2D_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_INT:
|
||||
case DescriptorType::SAMPLER_2D_UINT:
|
||||
case DescriptorType::SAMPLER_2D_DEPTH:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
|
||||
case DescriptorType::SAMPLER_CUBE_FLOAT:
|
||||
case DescriptorType::SAMPLER_CUBE_INT:
|
||||
case DescriptorType::SAMPLER_CUBE_UINT:
|
||||
case DescriptorType::SAMPLER_CUBE_DEPTH:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
|
||||
case DescriptorType::SAMPLER_3D_FLOAT:
|
||||
case DescriptorType::SAMPLER_3D_INT:
|
||||
case DescriptorType::SAMPLER_3D_UINT:
|
||||
case DescriptorType::SAMPLER_2D_MS_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_MS_INT:
|
||||
case DescriptorType::SAMPLER_2D_MS_UINT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT:
|
||||
case DescriptorType::SAMPLER_EXTERNAL: {
|
||||
if (!entry.name.empty()) {
|
||||
GLint const loc = glGetUniformLocation(program, entry.name.c_str());
|
||||
|
||||
@@ -23,12 +23,13 @@
|
||||
#include <backend/platforms/OpenGLPlatform.h>
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/JobSystem.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Mutex.h>
|
||||
#include <utils/Systrace.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
@@ -240,8 +241,8 @@ void TimerQueryFenceFactory::beginTimeElapsedQuery(GLTimerQuery* tq) {
|
||||
if (state) {
|
||||
platform.waitFence(fence, FENCE_WAIT_FOR_EVER);
|
||||
state->then = clock::now().time_since_epoch().count();
|
||||
SYSTRACE_CONTEXT();
|
||||
SYSTRACE_ASYNC_BEGIN("OpenGLTimerQueryFence", intptr_t(state.get()));
|
||||
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
FILAMENT_TRACING_ASYNC_BEGIN(FILAMENT_TRACING_CATEGORY_FILAMENT, "OpenGLTimerQueryFence", intptr_t(state.get()));
|
||||
}
|
||||
platform.destroyFence(fence);
|
||||
});
|
||||
@@ -257,8 +258,8 @@ void TimerQueryFenceFactory::endTimeElapsedQuery(OpenGLDriver&, GLTimerQuery* tq
|
||||
platform.waitFence(fence, FENCE_WAIT_FOR_EVER);
|
||||
int64_t const now = clock::now().time_since_epoch().count();
|
||||
state->elapsed.store(now - state->then, std::memory_order_relaxed);
|
||||
SYSTRACE_CONTEXT();
|
||||
SYSTRACE_ASYNC_END("OpenGLTimerQueryFence", intptr_t(state.get()));
|
||||
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
FILAMENT_TRACING_ASYNC_END(FILAMENT_TRACING_CATEGORY_FILAMENT, "OpenGLTimerQueryFence", intptr_t(state.get()));
|
||||
}
|
||||
platform.destroyFence(fence);
|
||||
});
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/Program.h>
|
||||
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/CString.h>
|
||||
#include <utils/debug.h>
|
||||
@@ -36,7 +38,6 @@
|
||||
#include <utils/Log.h>
|
||||
#include <utils/ostream.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/Systrace.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
@@ -367,7 +368,7 @@ void ShaderCompilerService::notifyWhenAllProgramsAreReady(
|
||||
|
||||
GLuint ShaderCompilerService::initialize(program_token_t& token) {
|
||||
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
assert_invariant(token);// This function should be called when the token is still alive.
|
||||
|
||||
@@ -454,8 +455,8 @@ void ShaderCompilerService::runAtNextTick(CompilerPriorityQueue priority,
|
||||
});
|
||||
ops.emplace(pos, priority, token, std::move(job));
|
||||
|
||||
SYSTRACE_CONTEXT();
|
||||
SYSTRACE_VALUE32("ShaderCompilerService Jobs", mRunAtNextTickOps.size());
|
||||
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "ShaderCompilerService Jobs", mRunAtNextTickOps.size());
|
||||
}
|
||||
|
||||
bool ShaderCompilerService::cancelTickOp(program_token_t const& token) noexcept {
|
||||
@@ -468,8 +469,8 @@ bool ShaderCompilerService::cancelTickOp(program_token_t const& token) noexcept
|
||||
ops.erase(pos);
|
||||
return true;
|
||||
}
|
||||
SYSTRACE_CONTEXT();
|
||||
SYSTRACE_VALUE32("ShaderCompilerService Jobs", ops.size());
|
||||
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "ShaderCompilerService Jobs", ops.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -485,15 +486,15 @@ void ShaderCompilerService::executeTickOps() noexcept {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
SYSTRACE_CONTEXT();
|
||||
SYSTRACE_VALUE32("ShaderCompilerService Jobs", ops.size());
|
||||
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "ShaderCompilerService Jobs", ops.size());
|
||||
}
|
||||
|
||||
/* static */ void ShaderCompilerService::compileShaders(OpenGLContext& context,
|
||||
Program::ShaderSource shadersSource,
|
||||
FixedCapacityVector<Program::SpecializationConstant> const& specializationConstants,
|
||||
bool multiview, program_token_t const& token) noexcept {
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
auto const appendSpecConstantString = +[](std::string& s, Program::SpecializationConstant const& sc) {
|
||||
s += "#define SPIRV_CROSS_CONSTANT_ID_" + std::to_string(sc.id) + ' ';
|
||||
@@ -616,7 +617,7 @@ void ShaderCompilerService::executeTickOps() noexcept {
|
||||
}
|
||||
|
||||
/* static */ void ShaderCompilerService::checkCompileStatus(program_token_t const& token) noexcept {
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
UTILS_NOUNROLL
|
||||
for (size_t i = 0; i < Program::SHADER_TYPE_COUNT; i++) {
|
||||
@@ -639,7 +640,7 @@ void ShaderCompilerService::executeTickOps() noexcept {
|
||||
|
||||
/* static */ void ShaderCompilerService::linkProgram(OpenGLContext const& context,
|
||||
program_token_t const& token) noexcept {
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
// Shader compilation should be completed by now. Check the status and log errors on failure.
|
||||
checkCompileStatus(token);
|
||||
@@ -675,7 +676,7 @@ void ShaderCompilerService::executeTickOps() noexcept {
|
||||
|
||||
/* static */ bool ShaderCompilerService::checkLinkStatusAndCleanupShaders(
|
||||
program_token_t const& token) noexcept {
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
assert_invariant(token->gl.program);
|
||||
|
||||
bool linked = true;
|
||||
|
||||
@@ -255,6 +255,7 @@ Platform::ExternalImageHandle PlatformEGLAndroid::createExternalImage(AHardwareB
|
||||
p->height = hardwareBufferDescription.height;
|
||||
p->width = hardwareBufferDescription.width;
|
||||
auto textureFormat = mapToFilamentFormat(hardwareBufferDescription.format, sRGB);
|
||||
p->format = textureFormat;
|
||||
p->usage = mapToFilamentUsage(hardwareBufferDescription.usage, textureFormat);
|
||||
return ExternalImageHandle{ p };
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ VulkanBuffer::VulkanBuffer(VmaAllocator allocator, VulkanStagePool& stagePool,
|
||||
: mAllocator(allocator),
|
||||
mStagePool(stagePool),
|
||||
mUsage(usage),
|
||||
mUpdatedOffset(0),
|
||||
mUpdatedOffset(0),
|
||||
mUpdatedBytes(0) {
|
||||
// for now make sure that only 1 bit is set in usage
|
||||
// (because loadFromCpu() assumes that somewhat)
|
||||
@@ -56,11 +56,12 @@ void VulkanBuffer::loadFromCpu(VkCommandBuffer cmdbuf, const void* cpuData, uint
|
||||
vmaMapMemory(mAllocator, stage->memory, &mapped);
|
||||
memcpy(mapped, cpuData, numBytes);
|
||||
vmaUnmapMemory(mAllocator, stage->memory);
|
||||
vmaFlushAllocation(mAllocator, stage->memory, byteOffset, numBytes);
|
||||
vmaFlushAllocation(mAllocator, stage->memory, 0, numBytes);
|
||||
|
||||
// If there was a previous update, then we need to make sure the following write is properly
|
||||
// synced with the previous read.
|
||||
if (mUpdatedBytes > 0) {
|
||||
if (mUpdatedBytes > 0 &&
|
||||
(byteOffset >= mUpdatedOffset && byteOffset <= (mUpdatedOffset + mUpdatedBytes))) {
|
||||
VkAccessFlags srcAccess = 0;
|
||||
VkPipelineStageFlags srcStage = 0;
|
||||
if (mUsage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) {
|
||||
@@ -74,28 +75,28 @@ void VulkanBuffer::loadFromCpu(VkCommandBuffer cmdbuf, const void* cpuData, uint
|
||||
srcStage = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
||||
}
|
||||
|
||||
VkBufferMemoryBarrier barrier{
|
||||
VkBufferMemoryBarrier barrier = {
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
||||
.srcAccessMask = srcAccess,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.buffer = mGpuBuffer,
|
||||
.offset = mUpdatedOffset,
|
||||
.size = mUpdatedBytes,
|
||||
.offset = byteOffset,
|
||||
.size = numBytes,
|
||||
};
|
||||
vkCmdPipelineBarrier(cmdbuf, srcStage, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 1,
|
||||
&barrier, 0, nullptr);
|
||||
}
|
||||
|
||||
VkBufferCopy region {
|
||||
.srcOffset = 0,
|
||||
.dstOffset = byteOffset,
|
||||
.size = numBytes,
|
||||
VkBufferCopy region = {
|
||||
.srcOffset = 0,
|
||||
.dstOffset = byteOffset,
|
||||
.size = numBytes,
|
||||
};
|
||||
vkCmdCopyBuffer(cmdbuf, stage->buffer, mGpuBuffer, 1, ®ion);
|
||||
|
||||
mUpdatedOffset = byteOffset;
|
||||
mUpdatedOffset = byteOffset;
|
||||
mUpdatedBytes = numBytes;
|
||||
|
||||
// Firstly, ensure that the copy finishes before the next draw call.
|
||||
@@ -112,21 +113,21 @@ void VulkanBuffer::loadFromCpu(VkCommandBuffer cmdbuf, const void* cpuData, uint
|
||||
dstAccessMask |= VK_ACCESS_INDEX_READ_BIT;
|
||||
dstStageMask |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
||||
} else if (mUsage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) {
|
||||
dstAccessMask |= VK_ACCESS_UNIFORM_READ_BIT;
|
||||
dstStageMask |=
|
||||
(VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||
dstAccessMask |= VK_ACCESS_SHADER_READ_BIT;
|
||||
dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
|
||||
} else if (mUsage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) {
|
||||
// TODO: implement me
|
||||
}
|
||||
|
||||
VkBufferMemoryBarrier barrier{
|
||||
VkBufferMemoryBarrier barrier = {
|
||||
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = dstAccessMask,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.buffer = mGpuBuffer,
|
||||
.size = VK_WHOLE_SIZE,
|
||||
.offset = byteOffset,
|
||||
.size = numBytes,
|
||||
};
|
||||
|
||||
vkCmdPipelineBarrier(cmdbuf, VK_PIPELINE_STAGE_TRANSFER_BIT, dstStageMask, 0, 0, nullptr, 1,
|
||||
|
||||
@@ -151,13 +151,13 @@ static_assert(FVK_ENABLED(FVK_DEBUG_VALIDATION));
|
||||
|
||||
#elif FVK_ENABLED(FVK_DEBUG_SYSTRACE)
|
||||
|
||||
#include <utils/Systrace.h>
|
||||
|
||||
#define FVK_SYSTRACE_CONTEXT() SYSTRACE_CONTEXT()
|
||||
#define FVK_SYSTRACE_START(marker) SYSTRACE_NAME_BEGIN(marker)
|
||||
#define FVK_SYSTRACE_END() SYSTRACE_NAME_END()
|
||||
#define FVK_SYSTRACE_SCOPE() SYSTRACE_NAME(__func__)
|
||||
#define FVK_PROFILE_MARKER(marker) FVK_SYSTRACE_SCOPE()
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
#define FVK_SYSTRACE_CONTEXT() FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT)
|
||||
#define FVK_SYSTRACE_START(marker) FILAMENT_TRACING_NAME_BEGIN(FILAMENT_TRACING_CATEGORY_FILAMENT, marker)
|
||||
#define FVK_SYSTRACE_END() FILAMENT_TRACING_NAME_END(FILAMENT_TRACING_CATEGORY_FILAMENT)
|
||||
#define FVK_SYSTRACE_SCOPE() FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT)
|
||||
#define FVK_PROFILE_MARKER(marker) FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT)
|
||||
|
||||
#else
|
||||
#define FVK_SYSTRACE_CONTEXT()
|
||||
|
||||
@@ -358,12 +358,11 @@ void VulkanDescriptorSetCache::updateSamplerImpl(VkDescriptorSet vkset, uint8_t
|
||||
range.levelCount = 1;
|
||||
range.layerCount = 1;
|
||||
}
|
||||
VkDescriptorImageInfo info{
|
||||
VkDescriptorImageInfo info = {
|
||||
.sampler = sampler,
|
||||
.imageView = texture->getView(range),
|
||||
.imageLayout = fvkutils::getVkLayout(texture->getDefaultLayout()),
|
||||
.imageLayout = fvkutils::getVkLayout(texture->getSamplerLayout()),
|
||||
};
|
||||
|
||||
VkWriteDescriptorSet descriptorWrite = {
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.pNext = nullptr,
|
||||
|
||||
@@ -622,7 +622,7 @@ void VulkanDriver::createTextureExternalImage2R(Handle<HwTexture> th, backend::S
|
||||
auto& commands = mCommands.get();
|
||||
// Unlike uploaded textures or swapchains, we need to explicit transition this
|
||||
// texture into the read layout.
|
||||
texture->transitionLayout(&commands, texture->getPrimaryViewRange(), VulkanLayout::READ_ONLY);
|
||||
texture->transitionLayout(&commands, texture->getPrimaryViewRange(), VulkanLayout::FRAG_READ);
|
||||
|
||||
if (imgData.external.valid()) {
|
||||
mExternalImageManager.addExternallySampledTexture(texture, externalImage);
|
||||
|
||||
@@ -93,7 +93,32 @@ BitmaskGroup fromBackendLayout(DescriptorSetLayout const& layout) {
|
||||
case DescriptorType::SAMPLER_EXTERNAL:
|
||||
fromStageFlags(binding.stageFlags, binding.binding, mask.externalSampler);
|
||||
UTILS_FALLTHROUGH;
|
||||
case DescriptorType::SAMPLER: {
|
||||
|
||||
case DescriptorType::SAMPLER_2D_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_INT:
|
||||
case DescriptorType::SAMPLER_2D_UINT:
|
||||
case DescriptorType::SAMPLER_2D_DEPTH:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
|
||||
case DescriptorType::SAMPLER_CUBE_FLOAT:
|
||||
case DescriptorType::SAMPLER_CUBE_INT:
|
||||
case DescriptorType::SAMPLER_CUBE_UINT:
|
||||
case DescriptorType::SAMPLER_CUBE_DEPTH:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
|
||||
case DescriptorType::SAMPLER_3D_FLOAT:
|
||||
case DescriptorType::SAMPLER_3D_INT:
|
||||
case DescriptorType::SAMPLER_3D_UINT:
|
||||
case DescriptorType::SAMPLER_2D_MS_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_MS_INT:
|
||||
case DescriptorType::SAMPLER_2D_MS_UINT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT: {
|
||||
fromStageFlags(binding.stageFlags, binding.binding, mask.sampler);
|
||||
break;
|
||||
}
|
||||
@@ -495,7 +520,8 @@ void VulkanRenderTarget::emitBarriersEndRenderPass(VulkanCommandBuffer& commands
|
||||
}
|
||||
} else {
|
||||
texture->setLayout(range, VulkanFboCache::FINAL_COLOR_ATTACHMENT_LAYOUT);
|
||||
if (!texture->transitionLayout(&commands, range, VulkanLayout::READ_WRITE)) {
|
||||
if (texture->isSampleable() &&
|
||||
!texture->transitionLayout(&commands, range, VulkanLayout::FRAG_READ)) {
|
||||
texture->attachmentToSamplerBarrier(&commands, range);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,6 +234,7 @@ void VulkanReadPixels::run(fvkmemory::resource_ptr<VulkanRenderTarget> srcTarget
|
||||
|
||||
VulkanAttachment const srcAttachment = srcTarget->getColor0();
|
||||
VkImageSubresourceRange const srcRange = srcAttachment.getSubresourceRange();
|
||||
VulkanLayout const srcLayout = srcAttachment.getLayout();
|
||||
srcTexture->transitionLayout(cmdbuffer, srcRange, VulkanLayout::TRANSFER_SRC);
|
||||
|
||||
VkImageCopy const imageCopyRegion = {
|
||||
@@ -270,7 +271,7 @@ void VulkanReadPixels::run(fvkmemory::resource_ptr<VulkanRenderTarget> srcTarget
|
||||
fvkutils::getVkLayout(VulkanLayout::TRANSFER_DST), 1, &imageCopyRegion);
|
||||
|
||||
// Restore the source image layout.
|
||||
srcTexture->transitionLayout(cmdbuffer, srcRange, srcTexture->getDefaultLayout());
|
||||
srcTexture->transitionLayout(cmdbuffer, srcRange, srcLayout);
|
||||
|
||||
vkEndCommandBuffer(cmdbuffer);
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ VulkanStageImage const* VulkanStagePool::acquireImage(PixelDataFormat format, Pi
|
||||
fvkutils::transitionLayout(cmdbuffer, {
|
||||
.image = image->image,
|
||||
.oldLayout = VulkanLayout::UNDEFINED,
|
||||
.newLayout = VulkanLayout::READ_WRITE, // (= VK_IMAGE_LAYOUT_GENERAL)
|
||||
.newLayout = VulkanLayout::STAGING, // (= VK_IMAGE_LAYOUT_GENERAL)
|
||||
.subresources = { aspectFlags, 0, 1, 0, 1 },
|
||||
});
|
||||
return image;
|
||||
|
||||
@@ -125,7 +125,7 @@ inline VulkanLayout getDefaultLayoutImpl(TextureUsage usage) {
|
||||
return VulkanLayout::COLOR_ATTACHMENT;
|
||||
}
|
||||
// Finally, the layout for an immutable texture is optimal read-only.
|
||||
return VulkanLayout::READ_ONLY;
|
||||
return VulkanLayout::FRAG_READ;
|
||||
}
|
||||
|
||||
inline VulkanLayout getDefaultLayoutImpl(VkImageUsageFlags vkusage) {
|
||||
@@ -187,7 +187,7 @@ VkImageUsageFlags getUsage(VulkanContext const& context, uint8_t samples,
|
||||
VkFormatProperties props;
|
||||
vkGetPhysicalDeviceFormatProperties(physicalDevice, vkFormat, &props);
|
||||
if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
|
||||
FVK_LOGW << "Texture usage is SAMPLEABLE but format " << mState->mVkFormat << " is not "
|
||||
FVK_LOGW << "Texture usage is SAMPLEABLE but format " << vkFormat << " is not "
|
||||
"sampleable with optimal tiling." << utils::io::endl;
|
||||
}
|
||||
}
|
||||
@@ -691,6 +691,7 @@ bool VulkanTexture::transitionLayout(VkCommandBuffer cmdbuf, VkImageSubresourceR
|
||||
<< " is skipped because of no change in layout" << utils::io::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
return hasTransitions;
|
||||
}
|
||||
|
||||
@@ -700,16 +701,15 @@ void VulkanTexture::samplerToAttachmentBarrier(VulkanCommandBuffer* commands,
|
||||
VkImageLayout const layout =
|
||||
fvkutils::getVkLayout(getLayout(range.baseArrayLayer, range.baseMipLevel));
|
||||
VkImageMemoryBarrier barrier = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.srcAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||
.dstAccessMask =
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
.oldLayout = layout,
|
||||
.newLayout = layout,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = mState->mTextureImage,
|
||||
.subresourceRange = range,
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.srcAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
.oldLayout = layout,
|
||||
.newLayout = layout,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = mState->mTextureImage,
|
||||
.subresourceRange = range,
|
||||
};
|
||||
vkCmdPipelineBarrier(cmdbuf, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
@@ -723,15 +723,15 @@ void VulkanTexture::attachmentToSamplerBarrier(VulkanCommandBuffer* commands,
|
||||
VkImageLayout const layout
|
||||
= fvkutils::getVkLayout(getLayout(range.baseArrayLayer, range.baseMipLevel));
|
||||
VkImageMemoryBarrier barrier = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||
.oldLayout = layout,
|
||||
.newLayout = layout,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = mState->mTextureImage,
|
||||
.subresourceRange = range,
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
|
||||
.oldLayout = layout,
|
||||
.newLayout = layout,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = mState->mTextureImage,
|
||||
.subresourceRange = range,
|
||||
};
|
||||
vkCmdPipelineBarrier(cmdbuf, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
|
||||
@@ -145,8 +145,14 @@ struct VulkanTexture : public HwTexture, fvkmemory::Resource {
|
||||
|
||||
VkImageSubresourceRange const& getPrimaryViewRange() const { return mPrimaryViewRange; }
|
||||
|
||||
VulkanLayout getPrimaryImageLayout() const {
|
||||
return getLayout(mPrimaryViewRange.baseArrayLayer, mPrimaryViewRange.baseMipLevel);
|
||||
VulkanLayout getSamplerLayout() const {
|
||||
if (!isSampleable()) {
|
||||
return VulkanLayout::UNDEFINED;
|
||||
}
|
||||
if (mState->mUsage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
|
||||
return VulkanLayout::DEPTH_SAMPLER;
|
||||
}
|
||||
return VulkanLayout::FRAG_READ;
|
||||
}
|
||||
|
||||
// Returns the layout for the intended use of this texture (and not the expected layout at the
|
||||
@@ -180,6 +186,10 @@ struct VulkanTexture : public HwTexture, fvkmemory::Resource {
|
||||
return mState->mUsage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
|
||||
}
|
||||
|
||||
bool isSampleable() const {
|
||||
return mState->mUsage & VK_IMAGE_USAGE_SAMPLED_BIT;
|
||||
}
|
||||
|
||||
bool getIsProtected() const {
|
||||
return mState->mIsProtected;
|
||||
}
|
||||
|
||||
@@ -42,20 +42,22 @@ getVkTransition(const VulkanLayoutTransition& transition) {
|
||||
srcStage = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
|
||||
break;
|
||||
case VulkanLayout::COLOR_ATTACHMENT:
|
||||
srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT |
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
||||
srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
srcStage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
srcStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
break;
|
||||
case VulkanLayout::READ_WRITE:
|
||||
case VulkanLayout::STAGING:
|
||||
srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
||||
srcStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
case VulkanLayout::READ_ONLY:
|
||||
case VulkanLayout::FRAG_READ:
|
||||
srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
srcStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
case VulkanLayout::VERT_READ:
|
||||
srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
srcStage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
|
||||
break;
|
||||
case VulkanLayout::TRANSFER_SRC:
|
||||
srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
@@ -69,7 +71,7 @@ getVkTransition(const VulkanLayoutTransition& transition) {
|
||||
srcStage = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
break;
|
||||
case VulkanLayout::DEPTH_SAMPLER:
|
||||
srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
srcStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
case VulkanLayout::COLOR_ATTACHMENT_RESOLVE:
|
||||
@@ -84,19 +86,21 @@ getVkTransition(const VulkanLayoutTransition& transition) {
|
||||
|
||||
switch (transition.newLayout) {
|
||||
case VulkanLayout::COLOR_ATTACHMENT:
|
||||
dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT
|
||||
| VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
|
||||
dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
|
||||
| VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
dstStage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT
|
||||
| VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
dstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
case VulkanLayout::READ_WRITE:
|
||||
case VulkanLayout::STAGING:
|
||||
dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
|
||||
dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
case VulkanLayout::READ_ONLY:
|
||||
case VulkanLayout::FRAG_READ:
|
||||
dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
|
||||
dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
case VulkanLayout::VERT_READ:
|
||||
dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
dstStage = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
|
||||
break;
|
||||
case VulkanLayout::TRANSFER_SRC:
|
||||
dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
|
||||
@@ -112,10 +116,8 @@ getVkTransition(const VulkanLayoutTransition& transition) {
|
||||
dstStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
||||
break;
|
||||
case VulkanLayout::DEPTH_SAMPLER:
|
||||
dstAccessMask =
|
||||
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
||||
dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
dstStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
break;
|
||||
case VulkanLayout::PRESENT:
|
||||
case VulkanLayout::COLOR_ATTACHMENT_RESOLVE:
|
||||
@@ -138,7 +140,6 @@ bool transitionLayout(VkCommandBuffer cmdbuffer,
|
||||
}
|
||||
auto [srcAccessMask, dstAccessMask, srcStage, dstStage, oldLayout, newLayout]
|
||||
= getVkTransition(transition);
|
||||
|
||||
if (oldLayout == newLayout) {
|
||||
return false;
|
||||
}
|
||||
@@ -155,7 +156,7 @@ bool transitionLayout(VkCommandBuffer cmdbuffer,
|
||||
.image = transition.image,
|
||||
.subresourceRange = transition.subresources,
|
||||
};
|
||||
vkCmdPipelineBarrier(cmdbuffer, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
vkCmdPipelineBarrier(cmdbuffer, srcStage, dstStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -264,8 +265,9 @@ utils::io::ostream& operator<<(utils::io::ostream& out,
|
||||
const filament::backend::VulkanLayout& layout) {
|
||||
switch (layout) {
|
||||
CASE(UNDEFINED)
|
||||
CASE(READ_ONLY)
|
||||
CASE(READ_WRITE)
|
||||
CASE(FRAG_READ)
|
||||
CASE(VERT_READ)
|
||||
CASE(STAGING)
|
||||
CASE(TRANSFER_SRC)
|
||||
CASE(TRANSFER_DST)
|
||||
CASE(DEPTH_ATTACHMENT)
|
||||
|
||||
@@ -32,9 +32,11 @@ enum class VulkanLayout : uint8_t {
|
||||
// any transition.
|
||||
UNDEFINED,
|
||||
// Fragment/vertex shader accessible layout for reading and writing.
|
||||
READ_WRITE,
|
||||
// Fragment/vertex shader accessible layout for reading only.
|
||||
READ_ONLY,
|
||||
STAGING,
|
||||
// Fragment shader accessible layout for reading only.
|
||||
FRAG_READ,
|
||||
// Vertex shader accessible layout for reading only.
|
||||
VERT_READ,
|
||||
// For the source of a copy operation.
|
||||
TRANSFER_SRC,
|
||||
// For the destination of a copy operation.
|
||||
@@ -65,9 +67,10 @@ constexpr inline VkImageLayout getVkLayout(VulkanLayout layout) {
|
||||
switch (layout) {
|
||||
case VulkanLayout::UNDEFINED:
|
||||
return VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
case VulkanLayout::READ_WRITE:
|
||||
case VulkanLayout::STAGING:
|
||||
return VK_IMAGE_LAYOUT_GENERAL;
|
||||
case VulkanLayout::READ_ONLY:
|
||||
case VulkanLayout::FRAG_READ:
|
||||
case VulkanLayout::VERT_READ:
|
||||
return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
case VulkanLayout::TRANSFER_SRC:
|
||||
return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
@@ -80,9 +83,8 @@ constexpr inline VkImageLayout getVkLayout(VulkanLayout layout) {
|
||||
case VulkanLayout::PRESENT:
|
||||
return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
// Filament sometimes samples from one miplevel while writing to another level in the
|
||||
// same texture (e.g. bloom does this). Moreover we'd like to avoid lots of expensive
|
||||
// layout transitions. So, keep it simple and use GENERAL for all color-attachable
|
||||
// textures.
|
||||
// same texture (e.g. bloom does this). So, keep it simple and use GENERAL for all
|
||||
// color-attachable textures.
|
||||
case VulkanLayout::COLOR_ATTACHMENT:
|
||||
return VK_IMAGE_LAYOUT_GENERAL;
|
||||
case VulkanLayout::COLOR_ATTACHMENT_RESOLVE:
|
||||
|
||||
@@ -234,6 +234,9 @@ WebGPUDriver::WebGPUDriver(WebGPUPlatform& platform, const Platform::DriverConfi
|
||||
printAdapterDetails(mAdapter);
|
||||
#endif
|
||||
mDevice = mPlatform.requestDevice(mAdapter);
|
||||
wgpu::Limits supportedLimits{};
|
||||
mDevice.GetLimits(&supportedLimits);
|
||||
mMinUniformBufferOffsetAlignment = supportedLimits.minUniformBufferOffsetAlignment;
|
||||
#if FWGPU_ENABLED(FWGPU_PRINT_SYSTEM)
|
||||
printDeviceDetails(mDevice);
|
||||
#endif
|
||||
@@ -468,8 +471,7 @@ void WebGPUDriver::createSwapChainR(Handle<HwSwapChain> sch, void* nativeWindow,
|
||||
mSwapChain = constructHandle<WebGPUSwapChain>(sch, std::move(surface), surfaceSize, mAdapter,
|
||||
mDevice, flags);
|
||||
assert_invariant(mSwapChain);
|
||||
WebGPUDescriptorSet::initializeDummyResourcesIfNotAlready(mDevice,
|
||||
mSwapChain->getColorFormat());
|
||||
|
||||
FWGPU_LOGW << "WebGPU support is still essentially a no-op at this point in development (only "
|
||||
"background components have been instantiated/selected, such as surface/screen, "
|
||||
"graphics device/GPU, etc.), thus nothing is being drawn to the screen."
|
||||
@@ -721,17 +723,20 @@ size_t WebGPUDriver::getMaxArrayTextureLayers() {
|
||||
|
||||
void WebGPUDriver::updateIndexBuffer(Handle<HwIndexBuffer> ibh, BufferDescriptor&& p,
|
||||
uint32_t byteOffset) {
|
||||
updateGPUBuffer(handleCast<WGPUIndexBuffer>(ibh), std::move(p), byteOffset);
|
||||
handleCast<WGPUIndexBuffer>(ibh)->updateGPUBuffer(p, byteOffset, mQueue);
|
||||
scheduleDestroy(std::move(p));
|
||||
}
|
||||
|
||||
void WebGPUDriver::updateBufferObject(Handle<HwBufferObject> ibh, BufferDescriptor&& p,
|
||||
uint32_t byteOffset) {
|
||||
updateGPUBuffer(handleCast<WGPUBufferObject>(ibh), std::move(p), byteOffset);
|
||||
handleCast<WGPUBufferObject>(ibh)->updateGPUBuffer(p, byteOffset, mQueue);
|
||||
scheduleDestroy(std::move(p));
|
||||
}
|
||||
|
||||
void WebGPUDriver::updateBufferObjectUnsynchronized(Handle<HwBufferObject> ibh,
|
||||
BufferDescriptor&& p, uint32_t byteOffset) {
|
||||
updateGPUBuffer(handleCast<WGPUBufferObject>(ibh), std::move(p), byteOffset);
|
||||
handleCast<WGPUBufferObject>(ibh)->updateGPUBuffer(p, byteOffset, mQueue);
|
||||
scheduleDestroy(std::move(p));
|
||||
}
|
||||
|
||||
void WebGPUDriver::resetBufferObject(Handle<HwBufferObject> boh) {
|
||||
@@ -743,8 +748,8 @@ void WebGPUDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t in
|
||||
auto* vertexBuffer = handleCast<WGPUVertexBuffer>(vbh);
|
||||
auto* bufferObject = handleCast<WGPUBufferObject>(boh);
|
||||
assert_invariant(index < vertexBuffer->buffers.size());
|
||||
assert_invariant(bufferObject->buffer.GetUsage() & wgpu::BufferUsage::Vertex);
|
||||
vertexBuffer->buffers[index] = bufferObject->buffer;
|
||||
assert_invariant(bufferObject->getBuffer().GetUsage() & wgpu::BufferUsage::Vertex);
|
||||
vertexBuffer->buffers[index] = bufferObject->getBuffer();
|
||||
}
|
||||
|
||||
void WebGPUDriver::update3DImage(Handle<HwTexture> th,
|
||||
@@ -787,7 +792,7 @@ void WebGPUDriver::beginRenderPass(Handle<HwRenderTarget> rth, RenderPassParams
|
||||
// FWGPU_LOGW << "Non Default render target"
|
||||
// << utils::io::endl;
|
||||
// }
|
||||
wgpu::RenderPassDescriptor renderPassDescriptor2;
|
||||
wgpu::RenderPassDescriptor renderPassDescriptor;
|
||||
wgpu::RenderPassDepthStencilAttachment depthStencilAttachment{
|
||||
.view = mSwapChain->getDepthTextureView(),
|
||||
.depthLoadOp = WGPURenderTarget::getLoadOperation(params, TargetBufferFlags::DEPTH),
|
||||
@@ -799,33 +804,12 @@ void WebGPUDriver::beginRenderPass(Handle<HwRenderTarget> rth, RenderPassParams
|
||||
.stencilClearValue = params.clearStencil,
|
||||
.stencilReadOnly = (params.readOnlyDepthStencil & RenderPassParams::READONLY_STENCIL) > 0
|
||||
};
|
||||
renderTarget->setUpRenderPassAttachments(renderPassDescriptor2, mTextureView, params);
|
||||
renderPassDescriptor2.depthStencilAttachment = &depthStencilAttachment;
|
||||
// TODO: Remove this code once WebGPU pipeline is implemented
|
||||
static float red = 1.0f;
|
||||
if (red - 0.01 > 0) {
|
||||
red -= 0.01;
|
||||
} else {
|
||||
red = 1.0f;
|
||||
}
|
||||
renderTarget->setUpRenderPassAttachments(renderPassDescriptor, mTextureView, params);
|
||||
renderPassDescriptor.depthStencilAttachment = &depthStencilAttachment;
|
||||
|
||||
assert_invariant(mTextureView);
|
||||
wgpu::RenderPassColorAttachment renderPassColorAttachment = {
|
||||
.view = mTextureView,
|
||||
// TODO: remove this code once WebGPU Pipeline is implemented with render targets, pipeline and buffers.
|
||||
.depthSlice = wgpu::kDepthSliceUndefined,
|
||||
.loadOp = wgpu::LoadOp::Clear,
|
||||
.storeOp = wgpu::StoreOp::Store,
|
||||
.clearValue = wgpu::Color{red, 0 , 0 , 1},
|
||||
};
|
||||
|
||||
wgpu::RenderPassDescriptor renderPassDescriptor = {
|
||||
.colorAttachmentCount = 1,
|
||||
.colorAttachments = &renderPassColorAttachment,
|
||||
.depthStencilAttachment = nullptr,
|
||||
.timestampWrites = nullptr,
|
||||
};
|
||||
|
||||
mRenderPassEncoder = mCommandEncoder.BeginRenderPass(&renderPassDescriptor2);
|
||||
mRenderPassEncoder = mCommandEncoder.BeginRenderPass(&renderPassDescriptor);
|
||||
mRenderPassEncoder.SetViewport(params.viewport.left, params.viewport.bottom,
|
||||
params.viewport.width, params.viewport.height, params.depthRange.near, params.depthRange.far);
|
||||
}
|
||||
@@ -976,18 +960,12 @@ void WebGPUDriver::bindRenderPrimitive(Handle<HwRenderPrimitive> rph) {
|
||||
mRenderPassEncoder.SetVertexBuffer(i, renderPrimitive->vertexBuffer->buffers[i]);
|
||||
}
|
||||
|
||||
mRenderPassEncoder.SetIndexBuffer(renderPrimitive->indexBuffer->buffer,
|
||||
mRenderPassEncoder.SetIndexBuffer(renderPrimitive->indexBuffer->getBuffer(),
|
||||
renderPrimitive->indexBuffer->indexFormat);
|
||||
}
|
||||
|
||||
void WebGPUDriver::draw2(uint32_t indexOffset, uint32_t indexCount, uint32_t instanceCount) {
|
||||
// Calling DrawIndexed with "firstInstance = 0" results in a NON spinning triangle
|
||||
// mRenderPassEncoder.DrawIndexed(indexCount, instanceCount, indexOffset, 0, 0);
|
||||
// Calling DrawIndexed with "firstInstance = 1" results in a spinning triangle
|
||||
mRenderPassEncoder.DrawIndexed(indexCount, instanceCount, indexOffset, 0, 1);
|
||||
// Calling Draw with "firstInstance = 0" results in a NON spinning triangle
|
||||
// Calling Draw with "firstInstance = 1" results in a spinning triangle
|
||||
// mRenderPassEncoder.Draw(indexCount, instanceCount, 0, 1);
|
||||
mRenderPassEncoder.DrawIndexed(indexCount, instanceCount, indexOffset, 0, 0);
|
||||
}
|
||||
|
||||
void WebGPUDriver::draw(PipelineState, Handle<HwRenderPrimitive>, uint32_t indexOffset,
|
||||
@@ -1018,8 +996,11 @@ void WebGPUDriver::updateDescriptorSetBuffer(Handle<HwDescriptorSet> dsh,
|
||||
auto buffer = handleCast<WGPUBufferObject>(boh);
|
||||
if (!bindGroup->getIsLocked()) {
|
||||
// TODO making assumptions that size and offset mean the same thing here.
|
||||
FILAMENT_CHECK_PRECONDITION(offset % mMinUniformBufferOffsetAlignment == 0)
|
||||
<< "Binding offset must be multiple of " << mMinUniformBufferOffsetAlignment
|
||||
<< "But requested offset is " << offset;
|
||||
wgpu::BindGroupEntry entry{ .binding = static_cast<uint32_t>(binding * 2),
|
||||
.buffer = buffer->buffer,
|
||||
.buffer = buffer->getBuffer(),
|
||||
.offset = offset,
|
||||
.size = size };
|
||||
bindGroup->addEntry(entry.binding, std::move(entry));
|
||||
@@ -1051,115 +1032,105 @@ void WebGPUDriver::bindDescriptorSet(Handle<HwDescriptorSet> dsh,
|
||||
const auto bindGroup = handleCast<WebGPUDescriptorSet>(dsh);
|
||||
const auto wbg = bindGroup->lockAndReturn(mDevice);
|
||||
assert_invariant(mRenderPassEncoder);
|
||||
// TODO is this how we should be getting the dynamic offsets?
|
||||
// should we add offsets for unused entries or is the input already have them?
|
||||
// this implementation assumes unused entries are not provided, and adds dummy values.
|
||||
// The count also includes unused entities, as not doing so produces errors
|
||||
const size_t dynamicOffsetCount = bindGroup->countEntitiesWithDynamicOffsets();
|
||||
uint32_t const* const dynamicOffsetsWithUnused = bindGroup->setDynamicOffsets(offsets.data());
|
||||
mRenderPassEncoder.SetBindGroup(setIndex, wbg, dynamicOffsetCount, dynamicOffsetsWithUnused);
|
||||
mRenderPassEncoder.SetBindGroup(setIndex, wbg, dynamicOffsetCount, offsets.data());
|
||||
}
|
||||
|
||||
void WebGPUDriver::setDebugTag(HandleBase::HandleId handleId, utils::CString tag) {
|
||||
}
|
||||
wgpu::Sampler WebGPUDriver::makeSampler(SamplerParams const& params) {
|
||||
wgpu::SamplerDescriptor desc;
|
||||
wgpu::SamplerDescriptor desc{};
|
||||
|
||||
desc.label = "TODO";
|
||||
desc.addressModeU = fWrapModeToWAddressMode(params.wrapS);
|
||||
desc.addressModeV = fWrapModeToWAddressMode(params.wrapR);
|
||||
desc.addressModeW = fWrapModeToWAddressMode(params.wrapT);
|
||||
switch (params.filterMag) {
|
||||
case SamplerMagFilter::NEAREST: {
|
||||
desc.magFilter = wgpu::FilterMode::Nearest;
|
||||
break;
|
||||
if (params.compareMode == SamplerCompareMode::COMPARE_TO_TEXTURE) {
|
||||
switch (params.filterMag) {
|
||||
case SamplerMagFilter::NEAREST: {
|
||||
desc.magFilter = wgpu::FilterMode::Nearest;
|
||||
break;
|
||||
}
|
||||
case SamplerMagFilter::LINEAR: {
|
||||
desc.magFilter = wgpu::FilterMode::Linear;
|
||||
break;
|
||||
}
|
||||
}
|
||||
case SamplerMagFilter::LINEAR: {
|
||||
desc.magFilter = wgpu::FilterMode::Linear;
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (params.filterMin) {
|
||||
case SamplerMinFilter::NEAREST: {
|
||||
desc.minFilter = wgpu::FilterMode::Nearest;
|
||||
// Metal Driver uses an explicit not-mipmapped value webgpu lacks. Nearest should
|
||||
// suffice
|
||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
|
||||
break;
|
||||
}
|
||||
case SamplerMinFilter::LINEAR: {
|
||||
desc.minFilter = wgpu::FilterMode::Linear;
|
||||
// Metal Driver uses an explicit not-mipmapped value webgpu lacks. Nearest should
|
||||
// suffice
|
||||
switch (params.filterMin) {
|
||||
case SamplerMinFilter::NEAREST: {
|
||||
desc.minFilter = wgpu::FilterMode::Nearest;
|
||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Undefined;
|
||||
break;
|
||||
}
|
||||
case SamplerMinFilter::LINEAR: {
|
||||
desc.minFilter = wgpu::FilterMode::Linear;
|
||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Undefined;
|
||||
break;
|
||||
}
|
||||
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST: {
|
||||
desc.minFilter = wgpu::FilterMode::Nearest;
|
||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
|
||||
break;
|
||||
}
|
||||
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST: {
|
||||
desc.minFilter = wgpu::FilterMode::Linear;
|
||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
|
||||
|
||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
|
||||
break;
|
||||
}
|
||||
case SamplerMinFilter::NEAREST_MIPMAP_NEAREST: {
|
||||
desc.minFilter = wgpu::FilterMode::Nearest;
|
||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
|
||||
break;
|
||||
}
|
||||
case SamplerMinFilter::LINEAR_MIPMAP_NEAREST: {
|
||||
desc.minFilter = wgpu::FilterMode::Linear;
|
||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Nearest;
|
||||
break;
|
||||
}
|
||||
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR: {
|
||||
desc.minFilter = wgpu::FilterMode::Nearest;
|
||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Linear;
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR: {
|
||||
desc.minFilter = wgpu::FilterMode::Linear;
|
||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Linear;
|
||||
break;
|
||||
}
|
||||
}
|
||||
case SamplerMinFilter::NEAREST_MIPMAP_LINEAR: {
|
||||
desc.minFilter = wgpu::FilterMode::Nearest;
|
||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Linear;
|
||||
|
||||
break;
|
||||
}
|
||||
case SamplerMinFilter::LINEAR_MIPMAP_LINEAR: {
|
||||
desc.minFilter = wgpu::FilterMode::Linear;
|
||||
desc.mipmapFilter = wgpu::MipmapFilterMode::Linear;
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (params.compareFunc) {
|
||||
case SamplerCompareFunc::LE: {
|
||||
desc.compare = wgpu::CompareFunction::LessEqual;
|
||||
break;
|
||||
}
|
||||
case SamplerCompareFunc::GE: {
|
||||
desc.compare = wgpu::CompareFunction::GreaterEqual;
|
||||
break;
|
||||
}
|
||||
case SamplerCompareFunc::L: {
|
||||
desc.compare = wgpu::CompareFunction::Less;
|
||||
break;
|
||||
}
|
||||
case SamplerCompareFunc::G: {
|
||||
desc.compare = wgpu::CompareFunction::Greater;
|
||||
break;
|
||||
}
|
||||
case SamplerCompareFunc::E: {
|
||||
desc.compare = wgpu::CompareFunction::Equal;
|
||||
break;
|
||||
}
|
||||
case SamplerCompareFunc::NE: {
|
||||
desc.compare = wgpu::CompareFunction::NotEqual;
|
||||
break;
|
||||
}
|
||||
case SamplerCompareFunc::A: {
|
||||
desc.compare = wgpu::CompareFunction::Always;
|
||||
break;
|
||||
}
|
||||
case SamplerCompareFunc::N: {
|
||||
desc.compare = wgpu::CompareFunction::Never;
|
||||
break;
|
||||
switch (params.compareFunc) {
|
||||
case SamplerCompareFunc::LE: {
|
||||
desc.compare = wgpu::CompareFunction::LessEqual;
|
||||
break;
|
||||
}
|
||||
case SamplerCompareFunc::GE: {
|
||||
desc.compare = wgpu::CompareFunction::GreaterEqual;
|
||||
break;
|
||||
}
|
||||
case SamplerCompareFunc::L: {
|
||||
desc.compare = wgpu::CompareFunction::Less;
|
||||
break;
|
||||
}
|
||||
case SamplerCompareFunc::G: {
|
||||
desc.compare = wgpu::CompareFunction::Greater;
|
||||
break;
|
||||
}
|
||||
case SamplerCompareFunc::E: {
|
||||
desc.compare = wgpu::CompareFunction::Equal;
|
||||
break;
|
||||
}
|
||||
case SamplerCompareFunc::NE: {
|
||||
desc.compare = wgpu::CompareFunction::NotEqual;
|
||||
break;
|
||||
}
|
||||
case SamplerCompareFunc::A: {
|
||||
desc.compare = wgpu::CompareFunction::Always;
|
||||
break;
|
||||
}
|
||||
case SamplerCompareFunc::N: {
|
||||
desc.compare = wgpu::CompareFunction::Never;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
desc.maxAnisotropy = 1u << params.anisotropyLog2;
|
||||
|
||||
// Unused: WGPU lodMinClamp/lodMaxClamp unnecessary
|
||||
|
||||
// Unused: Filament's compareMode, WGPU lodMinClamp/lodMaxClamp
|
||||
|
||||
//TODO Once we can properly map to descriptorsetlayout use the sampler.
|
||||
return mDevice.CreateSampler(/*&desc*/);
|
||||
return mDevice.CreateSampler(&desc);
|
||||
}
|
||||
wgpu::AddressMode WebGPUDriver::fWrapModeToWAddressMode(const SamplerWrapMode& fWrapMode) {
|
||||
switch (fWrapMode) {
|
||||
@@ -1179,5 +1150,4 @@ wgpu::AddressMode WebGPUDriver::fWrapModeToWAddressMode(const SamplerWrapMode& f
|
||||
return wgpu::AddressMode::Undefined;
|
||||
}
|
||||
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -58,32 +58,13 @@ private:
|
||||
[[nodiscard]] ShaderLanguage getShaderLanguage() const noexcept final;
|
||||
[[nodiscard]] wgpu::Sampler makeSampler(SamplerParams const& params);
|
||||
[[nodiscard]] static wgpu::AddressMode fWrapModeToWAddressMode(const filament::backend::SamplerWrapMode& fUsage);
|
||||
template<typename GPUBufferObject>
|
||||
void updateGPUBuffer(GPUBufferObject* gpuBufferObject, BufferDescriptor&& bufferDescriptor,
|
||||
uint32_t byteOffset) {
|
||||
FILAMENT_CHECK_PRECONDITION(bufferDescriptor.buffer)
|
||||
<< "copyIntoBuffer called with a null buffer";
|
||||
FILAMENT_CHECK_PRECONDITION(
|
||||
bufferDescriptor.size + byteOffset <= gpuBufferObject->buffer.GetSize())
|
||||
<< "Attempting to copy " << bufferDescriptor.size << " bytes into a buffer of size "
|
||||
<< gpuBufferObject->buffer.GetSize() << " at offset " << byteOffset;
|
||||
|
||||
// TODO: All buffer objects are created with CopyDst usage.
|
||||
// This may have some performance implications. That should be investigated later.
|
||||
assert_invariant(gpuBufferObject->buffer.GetUsage() & wgpu::BufferUsage::CopyDst);
|
||||
|
||||
// WriteBuffer is an async call. But cpu buffer data is already written to the staging
|
||||
// buffer on return from the WriteBuffer.
|
||||
mQueue.WriteBuffer(gpuBufferObject->buffer, byteOffset, bufferDescriptor.buffer,
|
||||
bufferDescriptor.size);
|
||||
scheduleDestroy(std::move(bufferDescriptor));
|
||||
}
|
||||
|
||||
// the platform (e.g. OS) specific aspects of the WebGPU backend are strictly only
|
||||
// handled in the WebGPUPlatform
|
||||
WebGPUPlatform& mPlatform;
|
||||
wgpu::Adapter mAdapter = nullptr;
|
||||
wgpu::Device mDevice = nullptr;
|
||||
uint32_t mMinUniformBufferOffsetAlignment;
|
||||
wgpu::Queue mQueue = nullptr;
|
||||
void* mNativeWindow = nullptr;
|
||||
WebGPUSwapChain* mSwapChain = nullptr;
|
||||
|
||||
@@ -41,15 +41,6 @@ constexpr wgpu::BufferUsage getBufferObjectUsage(
|
||||
}
|
||||
}
|
||||
|
||||
wgpu::Buffer createBuffer(wgpu::Device const& device, wgpu::BufferUsage usage, uint32_t size,
|
||||
char const* label) {
|
||||
wgpu::BufferDescriptor descriptor{ .label = label,
|
||||
.usage = usage,
|
||||
.size = size,
|
||||
.mappedAtCreation = false };
|
||||
return device.CreateBuffer(&descriptor);
|
||||
}
|
||||
|
||||
wgpu::VertexFormat getVertexFormat(filament::backend::ElementType type, bool normalized, bool integer) {
|
||||
using ElementType = filament::backend::ElementType;
|
||||
using VertexFormat = wgpu::VertexFormat;
|
||||
@@ -135,7 +126,7 @@ wgpu::StringView getUserTextureLabel(filament::backend::SamplerType target) {
|
||||
case SamplerType::SAMPLER_3D:
|
||||
return "a_3D_user_texture";
|
||||
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||
return "a_cube_mape_array_user_texture";
|
||||
return "a_cube_map_array_user_texture";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +145,7 @@ wgpu::StringView getUserTextureViewLabel(filament::backend::SamplerType target)
|
||||
case SamplerType::SAMPLER_3D:
|
||||
return "a_3D_user_texture_view";
|
||||
case SamplerType::SAMPLER_CUBEMAP_ARRAY:
|
||||
return "a_cube_mape_array_user_texture_view";
|
||||
return "a_cube_map_array_user_texture_view";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,6 +153,49 @@ wgpu::StringView getUserTextureViewLabel(filament::backend::SamplerType target)
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
void WGPUBufferBase::createBuffer(const wgpu::Device& device, wgpu::BufferUsage usage,
|
||||
uint32_t size, const char* label) {
|
||||
// Write size must be divisible by 4. If the whole buffer is written to as is common, so must
|
||||
// the buffer size.
|
||||
size += (4 - (size % 4)) % 4;
|
||||
wgpu::BufferDescriptor descriptor{ .label = label,
|
||||
.usage = usage,
|
||||
.size = size,
|
||||
.mappedAtCreation = false };
|
||||
buffer = device.CreateBuffer(&descriptor);
|
||||
}
|
||||
|
||||
void WGPUBufferBase::updateGPUBuffer(BufferDescriptor& bufferDescriptor, uint32_t byteOffset,
|
||||
wgpu::Queue queue) {
|
||||
FILAMENT_CHECK_PRECONDITION(bufferDescriptor.buffer)
|
||||
<< "copyIntoBuffer called with a null buffer";
|
||||
FILAMENT_CHECK_PRECONDITION(bufferDescriptor.size + byteOffset <= buffer.GetSize())
|
||||
<< "Attempting to copy " << bufferDescriptor.size << " bytes into a buffer of size "
|
||||
<< buffer.GetSize() << " at offset " << byteOffset;
|
||||
FILAMENT_CHECK_PRECONDITION(byteOffset % 4 == 0)
|
||||
<< "Byte offset must be a multiple of 4 but is " << byteOffset;
|
||||
|
||||
// TODO: All buffer objects are created with CopyDst usage.
|
||||
// This may have some performance implications. That should be investigated later.
|
||||
assert_invariant(buffer.GetUsage() & wgpu::BufferUsage::CopyDst);
|
||||
|
||||
size_t remainder = bufferDescriptor.size % 4;
|
||||
|
||||
// WriteBuffer is an async call. But cpu buffer data is already written to the staging
|
||||
// buffer on return from the WriteBuffer.
|
||||
auto legalSize = bufferDescriptor.size - remainder;
|
||||
queue.WriteBuffer(buffer, byteOffset, bufferDescriptor.buffer, legalSize);
|
||||
if (remainder != 0) {
|
||||
const uint8_t* remainderStart =
|
||||
static_cast<const uint8_t*>(bufferDescriptor.buffer) + legalSize;
|
||||
memcpy(mRemainderChunk.data(), remainderStart, remainder);
|
||||
// Pad the remainder with zeros to ensure deterministic behavior, though GPU shouldn't
|
||||
// access this
|
||||
std::memset(mRemainderChunk.data() + remainder, 0, 4 - remainder);
|
||||
|
||||
queue.WriteBuffer(buffer, byteOffset + legalSize, &mRemainderChunk, 4);
|
||||
}
|
||||
}
|
||||
WGPUVertexBufferInfo::WGPUVertexBufferInfo(uint8_t bufferCount, uint8_t attributeCount,
|
||||
AttributeArray const& attributes)
|
||||
: HwVertexBufferInfo(bufferCount, attributeCount),
|
||||
@@ -204,9 +238,10 @@ WGPUVertexBufferInfo::WGPUVertexBufferInfo(uint8_t bufferCount, uint8_t attribut
|
||||
|
||||
WGPUIndexBuffer::WGPUIndexBuffer(wgpu::Device const& device, uint8_t elementSize,
|
||||
uint32_t indexCount)
|
||||
: buffer(createBuffer(device, wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Index,
|
||||
elementSize * indexCount, "index_buffer")),
|
||||
indexFormat(elementSize == 2 ? wgpu::IndexFormat::Uint16 : wgpu::IndexFormat::Uint32) {}
|
||||
: indexFormat(elementSize == 2 ? wgpu::IndexFormat::Uint16 : wgpu::IndexFormat::Uint32) {
|
||||
createBuffer(device, wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Index,
|
||||
elementSize * indexCount, "index_buffer");
|
||||
}
|
||||
|
||||
|
||||
WGPUVertexBuffer::WGPUVertexBuffer(wgpu::Device const& device, uint32_t vertexCount,
|
||||
@@ -217,10 +252,10 @@ WGPUVertexBuffer::WGPUVertexBuffer(wgpu::Device const& device, uint32_t vertexCo
|
||||
|
||||
WGPUBufferObject::WGPUBufferObject(wgpu::Device const& device, BufferObjectBinding bindingType,
|
||||
uint32_t byteCount)
|
||||
: HwBufferObject(byteCount),
|
||||
buffer(createBuffer(device, wgpu::BufferUsage::CopyDst | getBufferObjectUsage(bindingType),
|
||||
byteCount, "buffer_object")),
|
||||
bufferObjectBinding(bindingType) {}
|
||||
: HwBufferObject(byteCount) {
|
||||
createBuffer(device, wgpu::BufferUsage::CopyDst | getBufferObjectUsage(bindingType), byteCount,
|
||||
"buffer_object");
|
||||
}
|
||||
|
||||
wgpu::ShaderStage WebGPUDescriptorSetLayout::filamentStageToWGPUStage(ShaderStageFlags fFlags) {
|
||||
wgpu::ShaderStage retStages = wgpu::ShaderStage::None;
|
||||
@@ -255,8 +290,7 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
|
||||
|
||||
unsigned int samplerCount =
|
||||
std::count_if(layout.bindings.begin(), layout.bindings.end(), [](auto& fEntry) {
|
||||
return fEntry.type == DescriptorType::SAMPLER ||
|
||||
fEntry.type == DescriptorType::SAMPLER_EXTERNAL;
|
||||
return DescriptorSetLayoutBinding::isSampler(fEntry.type);
|
||||
});
|
||||
|
||||
|
||||
@@ -272,26 +306,44 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
|
||||
entryInfo.binding = wEntry.binding;
|
||||
|
||||
switch (fEntry.type) {
|
||||
case DescriptorType::SAMPLER_EXTERNAL:
|
||||
case DescriptorType::SAMPLER: {
|
||||
case DescriptorType::SAMPLER_2D_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_INT:
|
||||
case DescriptorType::SAMPLER_2D_UINT:
|
||||
case DescriptorType::SAMPLER_2D_DEPTH:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_UINT:
|
||||
case DescriptorType::SAMPLER_2D_ARRAY_DEPTH:
|
||||
case DescriptorType::SAMPLER_CUBE_FLOAT:
|
||||
case DescriptorType::SAMPLER_CUBE_INT:
|
||||
case DescriptorType::SAMPLER_CUBE_UINT:
|
||||
case DescriptorType::SAMPLER_CUBE_DEPTH:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_UINT:
|
||||
case DescriptorType::SAMPLER_CUBE_ARRAY_DEPTH:
|
||||
case DescriptorType::SAMPLER_3D_FLOAT:
|
||||
case DescriptorType::SAMPLER_3D_INT:
|
||||
case DescriptorType::SAMPLER_3D_UINT:
|
||||
case DescriptorType::SAMPLER_2D_MS_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_MS_INT:
|
||||
case DescriptorType::SAMPLER_2D_MS_UINT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_FLOAT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_INT:
|
||||
case DescriptorType::SAMPLER_2D_MS_ARRAY_UINT: {
|
||||
auto& samplerEntry = wEntries.emplace_back();
|
||||
auto& samplerEntryInfo = mBindGroupEntries.emplace_back();
|
||||
samplerEntry.binding = fEntry.binding * 2 + 1;
|
||||
samplerEntryInfo.binding = samplerEntry.binding;
|
||||
samplerEntryInfo.type = WebGPUDescriptorSetLayout::BindGroupEntryType::SAMPLER;
|
||||
samplerEntry.visibility = wEntry.visibility;
|
||||
// We are simply hoping that undefined and defaults suffices here.
|
||||
samplerEntry.sampler.type = wgpu::SamplerBindingType::NonFiltering; // Example default
|
||||
wEntry.texture.sampleType = wgpu::TextureSampleType::Float; // Example default
|
||||
// TODO: FIX! THIS IS HACK FOR HELLO-TRIANGLE!
|
||||
if (baseLabel.find("Skybox") != std::string::npos ||
|
||||
(baseLabel == "Filament Default Material_perView" && wEntry.binding == 22)) {
|
||||
wEntry.texture.viewDimension = wgpu::TextureViewDimension::Cube;
|
||||
wEntry.texture.multisampled = isMultiSampledTypeDescriptor(fEntry.type);
|
||||
// TODO: Set once we have the filtering values
|
||||
if (isDepthDescriptor(fEntry.type)) {
|
||||
samplerEntry.sampler.type = wgpu::SamplerBindingType::Comparison;
|
||||
} else {
|
||||
wEntry.texture.viewDimension =
|
||||
wgpu::TextureViewDimension::e2D;// Example default
|
||||
samplerEntry.sampler.type =
|
||||
wgpu::SamplerBindingType::NonFiltering;
|
||||
}
|
||||
entryInfo.type = WebGPUDescriptorSetLayout::BindGroupEntryType::TEXTURE_VIEW;
|
||||
break;
|
||||
}
|
||||
case DescriptorType::UNIFORM_BUFFER: {
|
||||
@@ -302,7 +354,6 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
|
||||
// TODO: Ideally we fill minBindingSize
|
||||
break;
|
||||
}
|
||||
|
||||
case DescriptorType::INPUT_ATTACHMENT: {
|
||||
PANIC_POSTCONDITION("Input Attachment is not supported");
|
||||
break;
|
||||
@@ -311,6 +362,48 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
|
||||
PANIC_POSTCONDITION("Shader storage is not supported");
|
||||
break;
|
||||
}
|
||||
case DescriptorType::SAMPLER_EXTERNAL: {
|
||||
PANIC_POSTCONDITION("External Sampler is not supported");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isDepthDescriptor(fEntry.type))
|
||||
{
|
||||
wEntry.texture.sampleType = wgpu::TextureSampleType::Depth;
|
||||
}
|
||||
else if (isFloatDescriptor(fEntry.type))
|
||||
{
|
||||
// TODO: Set once we have the filtering values
|
||||
wEntry.texture.sampleType = wgpu::TextureSampleType::UnfilterableFloat;
|
||||
}
|
||||
else if (isIntDescriptor(fEntry.type))
|
||||
{
|
||||
wEntry.texture.sampleType = wgpu::TextureSampleType::Sint;
|
||||
}
|
||||
else if (isUnsignedIntDescriptor(fEntry.type))
|
||||
{
|
||||
wEntry.texture.sampleType = wgpu::TextureSampleType::Uint;
|
||||
}
|
||||
|
||||
if (is3dTypeDescriptor(fEntry.type))
|
||||
{
|
||||
wEntry.texture.viewDimension = wgpu::TextureViewDimension::e3D;
|
||||
}
|
||||
else if (is2dTypeDescriptor(fEntry.type))
|
||||
{
|
||||
wEntry.texture.viewDimension = wgpu::TextureViewDimension::e2D;
|
||||
}
|
||||
else if (is2dArrayTypeDescriptor(fEntry.type))
|
||||
{
|
||||
wEntry.texture.viewDimension = wgpu::TextureViewDimension::e2DArray;
|
||||
}
|
||||
else if (isCubeTypeDescriptor(fEntry.type))
|
||||
{
|
||||
wEntry.texture.viewDimension = wgpu::TextureViewDimension::Cube;
|
||||
}
|
||||
else if (isCubeArrayTypeDescriptor(fEntry.type))
|
||||
{
|
||||
wEntry.texture.viewDimension = wgpu::TextureViewDimension::CubeArray;
|
||||
}
|
||||
// fEntry.count is unused currently
|
||||
}
|
||||
@@ -325,114 +418,26 @@ WebGPUDescriptorSetLayout::WebGPUDescriptorSetLayout(DescriptorSetLayout const&
|
||||
|
||||
WebGPUDescriptorSetLayout::~WebGPUDescriptorSetLayout() {}
|
||||
|
||||
wgpu::Buffer WebGPUDescriptorSet::sDummyUniformBuffer = nullptr;
|
||||
wgpu::Texture WebGPUDescriptorSet::sDummyTexture = nullptr;
|
||||
wgpu::TextureView WebGPUDescriptorSet::sDummyTextureView = nullptr;
|
||||
wgpu::Sampler WebGPUDescriptorSet::sDummySampler = nullptr;
|
||||
|
||||
void WebGPUDescriptorSet::initializeDummyResourcesIfNotAlready(wgpu::Device const& device,
|
||||
wgpu::TextureFormat aColorFormat) {
|
||||
if (!sDummyUniformBuffer) {
|
||||
wgpu::BufferDescriptor bufferDescriptor{
|
||||
.label = "dummy_uniform_not_to_be_used",
|
||||
.usage = wgpu::BufferUsage::Uniform,
|
||||
.size = 4
|
||||
};
|
||||
sDummyUniformBuffer = device.CreateBuffer(&bufferDescriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(sDummyUniformBuffer)
|
||||
<< "Failed to create dummy uniform buffer?";
|
||||
}
|
||||
if (!sDummyTexture || !sDummyTextureView) {
|
||||
wgpu::TextureDescriptor textureDescriptor{
|
||||
.label = "dummy_texture_not_to_be_used",
|
||||
.usage = wgpu::TextureUsage::TextureBinding,
|
||||
.dimension = wgpu::TextureDimension::e2D,
|
||||
.size = wgpu::Extent3D{ .width = 4, .height = 4, .depthOrArrayLayers = 1 },
|
||||
.format = aColorFormat,
|
||||
};
|
||||
if (!sDummyTexture) {
|
||||
sDummyTexture = device.CreateTexture(&textureDescriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(sDummyUniformBuffer) << "Failed to create dummy texture?";
|
||||
}
|
||||
if (!sDummyTextureView) {
|
||||
wgpu::TextureViewDescriptor textureViewDescriptor{
|
||||
.label = "dummy_texture_view_not_to_be_used"
|
||||
};
|
||||
sDummyTextureView = sDummyTexture.CreateView(&textureViewDescriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(sDummyUniformBuffer)
|
||||
<< "Failed to create dummy texture view?";
|
||||
}
|
||||
}
|
||||
if (!sDummySampler) {
|
||||
wgpu::SamplerDescriptor samplerDescriptor{
|
||||
.label = "dummy_sampler_not_to_be_used"
|
||||
};
|
||||
sDummySampler = device.CreateSampler(&samplerDescriptor);
|
||||
FILAMENT_CHECK_POSTCONDITION(sDummyUniformBuffer) << "Failed to create dummy sampler?";
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<wgpu::BindGroupEntry> WebGPUDescriptorSet::createDummyEntriesSortedByBinding(
|
||||
std::vector<filament::backend::WebGPUDescriptorSetLayout::BindGroupEntryInfo> const&
|
||||
bindGroupEntries) {
|
||||
assert_invariant(WebGPUDescriptorSet::sDummyUniformBuffer &&
|
||||
"Dummy uniform buffer must have been created before "
|
||||
"creating dummy bind group entries.");
|
||||
assert_invariant(
|
||||
WebGPUDescriptorSet::sDummyTexture &&
|
||||
"Dummy texture must have been created before creating dummy bind group entries.");
|
||||
assert_invariant(
|
||||
WebGPUDescriptorSet::sDummyTextureView &&
|
||||
"Dummy texture view must have been created before creating dummy bind group entries.");
|
||||
assert_invariant(
|
||||
WebGPUDescriptorSet::sDummySampler &&
|
||||
"Dummy sampler must have been created before creating dummy bind group entries.");
|
||||
using filament::backend::WebGPUDescriptorSetLayout;
|
||||
std::vector<wgpu::BindGroupEntry> entries;
|
||||
entries.reserve(bindGroupEntries.size());
|
||||
for (auto const& entryInfo: bindGroupEntries) {
|
||||
auto& entry = entries.emplace_back();
|
||||
entry.binding = entryInfo.binding;
|
||||
switch (entryInfo.type) {
|
||||
case WebGPUDescriptorSetLayout::BindGroupEntryType::UNIFORM_BUFFER:
|
||||
entry.buffer = WebGPUDescriptorSet::sDummyUniformBuffer;
|
||||
break;
|
||||
case WebGPUDescriptorSetLayout::BindGroupEntryType::TEXTURE_VIEW:
|
||||
entry.textureView = WebGPUDescriptorSet::sDummyTextureView;
|
||||
break;
|
||||
case WebGPUDescriptorSetLayout::BindGroupEntryType::SAMPLER:
|
||||
entry.sampler = WebGPUDescriptorSet::sDummySampler;
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::sort(entries.begin(), entries.end(),
|
||||
[](wgpu::BindGroupEntry const& a, wgpu::BindGroupEntry const& b) {
|
||||
return a.binding < b.binding;
|
||||
});
|
||||
return entries;
|
||||
}
|
||||
|
||||
WebGPUDescriptorSet::WebGPUDescriptorSet(wgpu::BindGroupLayout const& layout,
|
||||
std::vector<WebGPUDescriptorSetLayout::BindGroupEntryInfo> const& bindGroupEntries)
|
||||
: mLayout(layout),
|
||||
mEntriesSortedByBinding(createDummyEntriesSortedByBinding(bindGroupEntries)) {
|
||||
mEntriesWithDynamicOffsetsCount(std::count_if(bindGroupEntries.begin(),
|
||||
bindGroupEntries.end(), [](auto const& entry) { return entry.hasDynamicOffset; })) {
|
||||
|
||||
mEntries.resize(bindGroupEntries.size());
|
||||
for (size_t i = 0; i < bindGroupEntries.size(); ++i) {
|
||||
mEntries[i].binding = bindGroupEntries[i].binding;
|
||||
}
|
||||
// Establish the size of entries based on the layout. This should be reliable and efficient.
|
||||
assert_invariant(INVALID_INDEX > mEntryIndexByBinding.size());
|
||||
for (size_t i = 0; i < mEntryIndexByBinding.size(); i++) {
|
||||
mEntryIndexByBinding[i] = INVALID_INDEX;
|
||||
}
|
||||
for (size_t index = 0; index < mEntriesSortedByBinding.size(); index++) {
|
||||
wgpu::BindGroupEntry const& entry = mEntriesSortedByBinding[index];
|
||||
for (size_t index = 0; index < mEntries.size(); index++) {
|
||||
wgpu::BindGroupEntry const& entry = mEntries[index];
|
||||
assert_invariant(entry.binding < mEntryIndexByBinding.size());
|
||||
mEntryIndexByBinding[entry.binding] = static_cast<uint8_t>(index);
|
||||
}
|
||||
for (auto const& entry : bindGroupEntries) {
|
||||
if (entry.hasDynamicOffset) {
|
||||
assert_invariant(entry.binding < mEntriesByBindingWithDynamicOffsets.size());
|
||||
mEntriesByBindingWithDynamicOffsets[entry.binding] = true;
|
||||
}
|
||||
}
|
||||
mDynamicOffsets.reserve(mEntriesSortedByBinding.size());
|
||||
}
|
||||
|
||||
WebGPUDescriptorSet::~WebGPUDescriptorSet() {
|
||||
@@ -447,15 +452,15 @@ wgpu::BindGroup WebGPUDescriptorSet::lockAndReturn(const wgpu::Device& device) {
|
||||
// TODO label? Should we just copy layout label?
|
||||
wgpu::BindGroupDescriptor desc{
|
||||
.layout = mLayout,
|
||||
.entryCount = mEntriesSortedByBinding.size(),
|
||||
.entries = mEntriesSortedByBinding.data()
|
||||
.entryCount = mEntries.size(),
|
||||
.entries = mEntries.data()
|
||||
};
|
||||
mBindGroup = device.CreateBindGroup(&desc);
|
||||
FILAMENT_CHECK_POSTCONDITION(mBindGroup) << "Failed to create bind group?";
|
||||
// once we have created the bind group itself we should no longer need any other state
|
||||
mLayout = nullptr;
|
||||
mEntriesSortedByBinding.clear();
|
||||
mEntriesSortedByBinding.shrink_to_fit();
|
||||
mEntries.clear();
|
||||
mEntries.shrink_to_fit();
|
||||
return mBindGroup;
|
||||
}
|
||||
|
||||
@@ -473,34 +478,14 @@ void WebGPUDescriptorSet::addEntry(unsigned int index, wgpu::BindGroupEntry&& en
|
||||
<< index;
|
||||
uint8_t entryIndex = mEntryIndexByBinding[index];
|
||||
FILAMENT_CHECK_POSTCONDITION(
|
||||
entryIndex != INVALID_INDEX && entryIndex < mEntriesSortedByBinding.size())
|
||||
entryIndex != INVALID_INDEX && entryIndex < mEntries.size())
|
||||
<< "Invalid binding " << index;
|
||||
entry.binding = index;
|
||||
mEntriesSortedByBinding[entryIndex] = std::move(entry);
|
||||
mEntriesByBindingAdded[index] = true;
|
||||
}
|
||||
|
||||
uint32_t const* WebGPUDescriptorSet::setDynamicOffsets(uint32_t const* offsets) {
|
||||
// mDynamicOffsets already reserves enough memory for the number of entries in the set
|
||||
mDynamicOffsets.clear();
|
||||
// this implementation copies the offsets to mDynamicOffsets, but also adds values for
|
||||
// unused entries TODO: is this necessary?
|
||||
size_t inputIndex = 0;
|
||||
size_t outputIndex = 0;
|
||||
for (auto const& entry : mEntriesSortedByBinding) {
|
||||
if (mEntriesByBindingWithDynamicOffsets[entry.binding]) {
|
||||
if (mEntriesByBindingAdded[entry.binding]) {
|
||||
mDynamicOffsets[outputIndex++] = offsets[inputIndex++];
|
||||
} else {
|
||||
mDynamicOffsets[outputIndex++] = 0; // dummy offset, as it was never added
|
||||
}
|
||||
}
|
||||
}
|
||||
return mDynamicOffsets.data();
|
||||
mEntries[entryIndex] = std::move(entry);
|
||||
}
|
||||
|
||||
size_t WebGPUDescriptorSet::countEntitiesWithDynamicOffsets() const {
|
||||
return mEntriesByBindingWithDynamicOffsets.count();
|
||||
return mEntriesWithDynamicOffsetsCount;
|
||||
}
|
||||
|
||||
WGPUTexture::WGPUTexture(SamplerType target, uint8_t levels, TextureFormat format, uint8_t samples,
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#include <webgpu/webgpu_cpp.h>
|
||||
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
@@ -44,7 +43,6 @@ public:
|
||||
std::vector<wgpu::ConstantEntry> constants;
|
||||
};
|
||||
|
||||
struct WGPUBufferObject;
|
||||
|
||||
// VertexBufferInfo contains layout info for Vertex Buffer based on WebGPU structs. In WebGPU each
|
||||
// VertexBufferLayout is associated with a single vertex buffer. So number of mVertexBufferLayout
|
||||
@@ -86,33 +84,37 @@ struct WGPUVertexBuffer : public HwVertexBuffer {
|
||||
utils::FixedCapacityVector<wgpu::Buffer> buffers;
|
||||
};
|
||||
|
||||
struct WGPUIndexBuffer : public HwIndexBuffer {
|
||||
class WGPUBufferBase {
|
||||
public:
|
||||
void createBuffer(wgpu::Device const& device, wgpu::BufferUsage usage, uint32_t size,
|
||||
char const* label);
|
||||
void updateGPUBuffer(BufferDescriptor& bufferDescriptor, uint32_t byteOffset,
|
||||
wgpu::Queue queue);
|
||||
const wgpu::Buffer& getBuffer() const { return buffer; }
|
||||
protected:
|
||||
wgpu::Buffer buffer;
|
||||
private:
|
||||
// 4 bytes to hold any extra chunk we need.
|
||||
std::array<uint8_t,4> mRemainderChunk;
|
||||
};
|
||||
|
||||
class WGPUIndexBuffer : public HwIndexBuffer, public WGPUBufferBase {
|
||||
public:
|
||||
WGPUIndexBuffer(wgpu::Device const &device, uint8_t elementSize,
|
||||
uint32_t indexCount);
|
||||
|
||||
wgpu::Buffer buffer;
|
||||
wgpu::IndexFormat indexFormat;
|
||||
};
|
||||
|
||||
struct WGPUBufferObject : HwBufferObject {
|
||||
class WGPUBufferObject : public HwBufferObject, public WGPUBufferBase {
|
||||
public:
|
||||
WGPUBufferObject(wgpu::Device const &device, BufferObjectBinding bindingType, uint32_t byteCount);
|
||||
|
||||
wgpu::Buffer buffer = nullptr;
|
||||
const BufferObjectBinding bufferObjectBinding;
|
||||
};
|
||||
|
||||
class WebGPUDescriptorSetLayout final : public HwDescriptorSetLayout {
|
||||
public:
|
||||
|
||||
enum class BindGroupEntryType : uint8_t {
|
||||
UNIFORM_BUFFER,
|
||||
TEXTURE_VIEW,
|
||||
SAMPLER
|
||||
};
|
||||
|
||||
struct BindGroupEntryInfo final {
|
||||
uint8_t binding = 0;
|
||||
BindGroupEntryType type = BindGroupEntryType::UNIFORM_BUFFER;
|
||||
bool hasDynamicOffset = false;
|
||||
};
|
||||
|
||||
@@ -125,7 +127,7 @@ public:
|
||||
|
||||
private:
|
||||
// TODO: If this is useful elsewhere, remove it from this class
|
||||
// Convert Filament Shader Stage Flags bitmask to webgpu equivilant
|
||||
// Convert Filament Shader Stage Flags bitmask to webgpu equivalent
|
||||
static wgpu::ShaderStage filamentStageToWGPUStage(ShaderStageFlags fFlags);
|
||||
std::vector<BindGroupEntryInfo> mBindGroupEntries;
|
||||
wgpu::BindGroupLayout mLayout;
|
||||
@@ -133,8 +135,6 @@ private:
|
||||
|
||||
class WebGPUDescriptorSet final : public HwDescriptorSet {
|
||||
public:
|
||||
static void initializeDummyResourcesIfNotAlready(wgpu::Device const&,
|
||||
wgpu::TextureFormat aColorFormat);
|
||||
|
||||
WebGPUDescriptorSet(wgpu::BindGroupLayout const& layout,
|
||||
std::vector<WebGPUDescriptorSetLayout::BindGroupEntryInfo> const& bindGroupEntries);
|
||||
@@ -142,30 +142,15 @@ public:
|
||||
|
||||
wgpu::BindGroup lockAndReturn(wgpu::Device const&);
|
||||
void addEntry(unsigned int index, wgpu::BindGroupEntry&& entry);
|
||||
[[nodiscard]] uint32_t const* setDynamicOffsets(uint32_t const* offsets);
|
||||
[[nodiscard]] bool getIsLocked() const { return mBindGroup != nullptr; }
|
||||
[[nodiscard]] size_t countEntitiesWithDynamicOffsets() const;
|
||||
|
||||
private:
|
||||
static wgpu::Buffer sDummyUniformBuffer;
|
||||
static wgpu::Texture sDummyTexture;
|
||||
static wgpu::TextureView sDummyTextureView;
|
||||
static wgpu::Sampler sDummySampler;
|
||||
|
||||
static std::vector<wgpu::BindGroupEntry> createDummyEntriesSortedByBinding(
|
||||
std::vector<filament::backend::WebGPUDescriptorSetLayout::BindGroupEntryInfo> const&);
|
||||
|
||||
// TODO: Consider storing what we used to make the layout. However we need to essentially
|
||||
// Recreate some of the info (Sampler in slot X with the actual sampler) so letting Dawn confirm
|
||||
// there isn't a mismatch may be easiest.
|
||||
// Also storing the wgpu ObjectBase takes care of ownership challenges in theory
|
||||
wgpu::BindGroupLayout mLayout = nullptr;
|
||||
static constexpr uint8_t INVALID_INDEX = MAX_DESCRIPTOR_COUNT + 1;
|
||||
std::array<uint8_t, MAX_DESCRIPTOR_COUNT> mEntryIndexByBinding{};
|
||||
std::vector<wgpu::BindGroupEntry> mEntriesSortedByBinding;
|
||||
std::bitset<MAX_DESCRIPTOR_COUNT> mEntriesByBindingWithDynamicOffsets{};
|
||||
std::bitset<MAX_DESCRIPTOR_COUNT> mEntriesByBindingAdded{};
|
||||
std::vector<uint32_t> mDynamicOffsets;
|
||||
std::vector<wgpu::BindGroupEntry> mEntries;
|
||||
const size_t mEntriesWithDynamicOffsetsCount;
|
||||
wgpu::BindGroup mBindGroup = nullptr;
|
||||
};
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ static constexpr size_t CONFIG_COMMAND_BUFFERS_SIZE = 3 * CONFIG_MIN_COMMAND
|
||||
|
||||
using namespace filament;
|
||||
using namespace filament::backend;
|
||||
using namespace filament::math;
|
||||
|
||||
#ifndef FILAMENT_IOS
|
||||
#include <imageio/ImageEncoder.h>
|
||||
@@ -106,16 +107,35 @@ Handle<HwSwapChain> BackendTest::createSwapChain() {
|
||||
return getDriverApi().createSwapChain(view.ptr, 0);
|
||||
}
|
||||
|
||||
void BackendTest::fullViewport(RenderPassParams& params) {
|
||||
fullViewport(params.viewport);
|
||||
PipelineState BackendTest::getColorWritePipelineState() {
|
||||
PipelineState result;
|
||||
result.rasterState.colorWrite = true;
|
||||
result.rasterState.depthWrite = false;
|
||||
result.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||
return result;
|
||||
}
|
||||
|
||||
void BackendTest::fullViewport(Viewport& viewport) {
|
||||
const NativeView& view = getNativeView();
|
||||
viewport.left = 0;
|
||||
viewport.bottom = 0;
|
||||
viewport.width = view.width;
|
||||
viewport.height = view.height;
|
||||
filament::backend::Viewport BackendTest::getFullViewport() const {
|
||||
const NativeView& view = getNativeView();
|
||||
return Viewport {
|
||||
.left = 0,
|
||||
.bottom = 0,
|
||||
.width = static_cast<uint32_t>(view.width),
|
||||
.height = static_cast<uint32_t>(view.height)
|
||||
};
|
||||
}
|
||||
|
||||
filament::backend::RenderPassParams BackendTest::getClearColorRenderPass(float4 color) {
|
||||
RenderPassParams params = {};
|
||||
params.flags.clear = TargetBufferFlags::COLOR;
|
||||
params.flags.discardStart = TargetBufferFlags::ALL;
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
params.clearColor = color;
|
||||
return params;
|
||||
}
|
||||
|
||||
filament::backend::RenderPassParams BackendTest::getNoClearRenderPass() {
|
||||
return RenderPassParams{};
|
||||
}
|
||||
|
||||
void BackendTest::renderTriangle(
|
||||
@@ -123,14 +143,9 @@ void BackendTest::renderTriangle(
|
||||
Handle<filament::backend::HwRenderTarget> renderTarget,
|
||||
Handle<filament::backend::HwSwapChain> swapChain,
|
||||
Handle<filament::backend::HwProgram> program) {
|
||||
RenderPassParams params = {};
|
||||
fullViewport(params);
|
||||
params.flags.clear = TargetBufferFlags::COLOR;
|
||||
params.clearColor = {0.f, 0.f, 1.f, 1.f};
|
||||
params.flags.discardStart = TargetBufferFlags::ALL;
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
params.viewport.height = 512;
|
||||
RenderPassParams params = getClearColorRenderPass();
|
||||
params.viewport.width = 512;
|
||||
params.viewport.height = 512;
|
||||
renderTriangle(pipelineLayout, renderTarget, swapChain, program, params);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,9 +52,14 @@ protected:
|
||||
|
||||
filament::backend::Handle<filament::backend::HwSwapChain> createSwapChain();
|
||||
|
||||
// Helper methods to set the viewport to the full extent of the swap chain.
|
||||
static void fullViewport(filament::backend::RenderPassParams& params);
|
||||
static void fullViewport(filament::backend::Viewport& viewport);
|
||||
static filament::backend::PipelineState getColorWritePipelineState();
|
||||
|
||||
// Gets the full back buffer's viewport
|
||||
filament::backend::Viewport getFullViewport() const;
|
||||
// If color is unset this defaults to using opaque cyan
|
||||
static filament::backend::RenderPassParams getClearColorRenderPass(
|
||||
filament::math::float4 color = filament::math::float4(0, 1, 1, 1));
|
||||
static filament::backend::RenderPassParams getNoClearRenderPass();
|
||||
|
||||
void renderTriangle(
|
||||
filament::backend::PipelineLayout const& pipelineLayout,
|
||||
|
||||
@@ -56,26 +56,35 @@ Shader::Shader(DriverApi& api, Cleanup& cleanup, ShaderConfig config) : mCleanup
|
||||
mProgram = cleanup.add(api.createProgram(std::move(prog)));
|
||||
|
||||
if (!kLayouts.empty()) {
|
||||
mDescriptorSetLayout =
|
||||
cleanup.add(api.createDescriptorSetLayout(DescriptorSetLayout{ .bindings = kLayouts }));
|
||||
mDescriptorSetLayout = cleanup.add(
|
||||
api.createDescriptorSetLayout(DescriptorSetLayout{ .bindings = kLayouts }));
|
||||
}
|
||||
}
|
||||
|
||||
filament::backend::DescriptorSetHandle Shader::createDescriptorSet(DriverApi& api) const {
|
||||
DescriptorSetHandle Shader::createDescriptorSet(DriverApi& api) const {
|
||||
return mCleanup.add(api.createDescriptorSet(mDescriptorSetLayout));
|
||||
}
|
||||
|
||||
filament::backend::ProgramHandle Shader::getProgram() const {
|
||||
ProgramHandle Shader::getProgram() const {
|
||||
assert(mProgram);
|
||||
EXPECT_THAT(mProgram, ::testing::IsTrue())
|
||||
<< "Shader program accessed despite being null.";
|
||||
return mProgram;
|
||||
}
|
||||
|
||||
filament::backend::DescriptorSetLayoutHandle Shader::getDescriptorSetLayout() const {
|
||||
DescriptorSetLayoutHandle Shader::getDescriptorSetLayout() const {
|
||||
EXPECT_THAT(mDescriptorSetLayout, ::testing::IsTrue())
|
||||
<< "Shader descriptor set layout accessed despite being null.";
|
||||
return mDescriptorSetLayout;
|
||||
}
|
||||
|
||||
void Shader::addProgramToPipelineState(PipelineState& state) const {
|
||||
state.program = getProgram();
|
||||
// In case another shader was set first, clear the set layout and then set this shader's values.
|
||||
state.pipelineLayout.setLayout = PipelineLayout::SetLayout();
|
||||
if (mDescriptorSetLayout) {
|
||||
state.pipelineLayout.setLayout[0] = { getDescriptorSetLayout() };
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
||||
@@ -90,6 +90,8 @@ public:
|
||||
filament::backend::ProgramHandle getProgram() const;
|
||||
filament::backend::DescriptorSetLayoutHandle getDescriptorSetLayout() const;
|
||||
|
||||
void addProgramToPipelineState(filament::backend::PipelineState& state) const;
|
||||
|
||||
filament::backend::DescriptorSetHandle createDescriptorSet(
|
||||
filament::backend::DriverApi& api) const;
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ ShaderGenerator::Blob ShaderGenerator::transpileShader(ShaderStage stage, std::s
|
||||
} else if (backend == Backend::VULKAN) {
|
||||
shader.insert(pos, "#define TARGET_VULKAN_ENVIRONMENT\n");
|
||||
} else if (backend == Backend::WEBGPU) {
|
||||
shader.insert(pos, "#define TARGET_VULKAN_ENVIRONMENT\n");
|
||||
shader.insert(pos, "#define TARGET_WEBGPU_ENVIRONMENT\n");
|
||||
}
|
||||
|
||||
const char* shaderCString = shader.c_str();
|
||||
@@ -186,4 +186,16 @@ Program ShaderGenerator::getProgram(filament::backend::DriverApi&) noexcept {
|
||||
return program;
|
||||
}
|
||||
|
||||
Program ShaderGenerator::getProgramWithPushConstants(filament::backend::DriverApi&,
|
||||
std::array<PushConstants, filament::backend::Program::SHADER_TYPE_COUNT> constants) {
|
||||
Program program;
|
||||
program.shaderLanguage(mShaderLanguage);
|
||||
program.shader(ShaderStage::VERTEX, mVertexBlob.data(), mVertexBlob.size());
|
||||
program.shader(ShaderStage::FRAGMENT, mFragmentBlob.data(), mFragmentBlob.size());
|
||||
for (auto const stage : {ShaderStage::VERTEX, ShaderStage::FRAGMENT }) {
|
||||
program.pushConstants(stage, constants[uint8_t(stage)]);
|
||||
}
|
||||
return program;
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
||||
@@ -48,6 +48,10 @@ public:
|
||||
|
||||
filament::backend::Program getProgram(filament::backend::DriverApi&) noexcept;
|
||||
|
||||
using PushConstants = utils::FixedCapacityVector<filament::backend::Program::PushConstant>;
|
||||
filament::backend::Program getProgramWithPushConstants(filament::backend::DriverApi&,
|
||||
std::array<PushConstants, filament::backend::Program::SHADER_TYPE_COUNT> constants);
|
||||
|
||||
private:
|
||||
using ShaderStage = filament::backend::ShaderStage;
|
||||
|
||||
|
||||
@@ -184,7 +184,7 @@ std::vector<UniformConfig> GetUniformConfig(ShaderUniformType type) {
|
||||
"backend_test", "test_tex", 0,
|
||||
SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH, false };
|
||||
return {{
|
||||
"test_tex", DescriptorType::SAMPLER, samplerInfo
|
||||
"test_tex", DescriptorType::SAMPLER_2D_FLOAT, samplerInfo
|
||||
}};
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -113,4 +113,15 @@ TrianglePrimitive::PrimitiveHandle TrianglePrimitive::getRenderPrimitive() const
|
||||
return mRenderPrimitive;
|
||||
}
|
||||
|
||||
void TrianglePrimitive::bindWithPipelineState(DriverApi& api, PipelineState state) const {
|
||||
state.primitiveType = PrimitiveType::TRIANGLES;
|
||||
state.vertexBufferInfo = getVertexBufferInfo();
|
||||
api.bindPipeline(state);
|
||||
api.bindRenderPrimitive(getRenderPrimitive());
|
||||
}
|
||||
|
||||
void TrianglePrimitive::draw(DriverApi& api) const {
|
||||
api.draw2(0, 3, 1);
|
||||
}
|
||||
|
||||
} // namespae test
|
||||
|
||||
@@ -55,6 +55,12 @@ public:
|
||||
void updateIndices(const index_type* indices) noexcept;
|
||||
void updateIndices(const index_type* indices, int count, int offset) noexcept;
|
||||
|
||||
VertexInfoHandle getVertexBufferInfo() const { return mVertexBufferInfo; }
|
||||
|
||||
void bindWithPipelineState(filament::backend::DriverApi& api,
|
||||
filament::backend::PipelineState state) const;
|
||||
void draw(filament::backend::DriverApi& api) const;
|
||||
|
||||
private:
|
||||
|
||||
size_t mVertexCount = 3;
|
||||
|
||||
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
@@ -151,3 +151,6 @@ if __name__ == "__main__":
|
||||
results.show_images(file_prefix)
|
||||
else:
|
||||
results.batch_move(args.batch)
|
||||
print("--------------------------------------------------------")
|
||||
print("REMEMBER TO RESYNC CMAKE AND UPDATE HASHES IN TEST FILES")
|
||||
print("--------------------------------------------------------")
|
||||
|
||||
@@ -302,22 +302,13 @@ TEST_F(BlitTest, ColorResolve) {
|
||||
{{ dstColorTexture }}, {}, {}));
|
||||
|
||||
// Prep for rendering.
|
||||
RenderPassParams params = {};
|
||||
params.flags.clear = TargetBufferFlags::COLOR;
|
||||
params.flags.discardStart = TargetBufferFlags::ALL;
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
params.clearColor = float4(1, 1, 0, 1);
|
||||
PipelineState state = getColorWritePipelineState();
|
||||
shader.addProgramToPipelineState(state);
|
||||
|
||||
RenderPassParams params = getClearColorRenderPass();
|
||||
params.viewport.width = kSrcTexWidth;
|
||||
params.viewport.height = kSrcTexHeight;
|
||||
|
||||
PipelineState state = {};
|
||||
state.program = shader.getProgram();
|
||||
state.pipelineLayout.setLayout[0] = { shader.getDescriptorSetLayout() };
|
||||
state.rasterState.colorWrite = true;
|
||||
state.rasterState.depthWrite = false;
|
||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||
state.rasterState.culling = CullingMode::NONE;
|
||||
|
||||
auto ubuffer = mCleanup.add(api.createBufferObject(sizeof(SimpleMaterialParams),
|
||||
BufferObjectBinding::UNIFORM, BufferUsage::STATIC));
|
||||
// Draw red triangle into srcRenderTarget.
|
||||
@@ -328,11 +319,11 @@ TEST_F(BlitTest, ColorResolve) {
|
||||
});
|
||||
shader.bindUniform<SimpleMaterialParams>(api, ubuffer);
|
||||
|
||||
// FIXME: on Metal this triangle is not drawn. Can't understand why.
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
api.beginRenderPass(srcRenderTarget, params);
|
||||
api.draw(state, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
triangle.bindWithPipelineState(api, state);
|
||||
triangle.draw(api);
|
||||
api.endRenderPass();
|
||||
}
|
||||
|
||||
@@ -343,7 +334,7 @@ TEST_F(BlitTest, ColorResolve) {
|
||||
SamplerMagFilter::NEAREST);
|
||||
|
||||
EXPECT_IMAGE(dstRenderTarget, getExpectations(),
|
||||
ScreenshotParams(kDstTexWidth, kDstTexHeight, "ColorResolve", 0xebfac2ef));
|
||||
ScreenshotParams(kDstTexWidth, kDstTexHeight, "ColorResolve", 531759687));
|
||||
}
|
||||
|
||||
TEST_F(BlitTest, Blit2DTextureArray) {
|
||||
|
||||
@@ -76,20 +76,11 @@ TEST_F(BufferUpdatesTest, VertexBufferUpdate) {
|
||||
// buffer. Only the first 3 vertices will be used.
|
||||
TrianglePrimitive triangle(api, largeBuffers);
|
||||
|
||||
RenderPassParams params = {};
|
||||
fullViewport(params);
|
||||
params.flags.clear = TargetBufferFlags::COLOR;
|
||||
params.clearColor = { 0.f, 1.f, 0.f, 1.f };
|
||||
params.flags.discardStart = TargetBufferFlags::ALL;
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
PipelineState state = getColorWritePipelineState();
|
||||
shader.addProgramToPipelineState(state);
|
||||
|
||||
PipelineState state;
|
||||
state.program = shader.getProgram();
|
||||
state.pipelineLayout.setLayout[0] = { shader.getDescriptorSetLayout() };
|
||||
state.rasterState.colorWrite = true;
|
||||
state.rasterState.depthWrite = false;
|
||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||
state.rasterState.culling = CullingMode::NONE;
|
||||
RenderPassParams params = getClearColorRenderPass();
|
||||
params.viewport = getFullViewport();
|
||||
|
||||
// Create a uniform buffer.
|
||||
// We use STATIC here, even though the buffer is updated, to force the Metal backend to use
|
||||
@@ -162,6 +153,9 @@ TEST_F(BufferUpdatesTest, VertexBufferUpdate) {
|
||||
TEST_F(BufferUpdatesTest, BufferObjectUpdateWithOffset) {
|
||||
NONFATAL_FAIL_IF(SkipEnvironment(OperatingSystem::APPLE, Backend::VULKAN),
|
||||
"All values including alpha are written as 0, see b/417254943");
|
||||
constexpr int kTexWidth = 512;
|
||||
constexpr int kTexHeight = 512;
|
||||
|
||||
auto& api = getDriverApi();
|
||||
Cleanup cleanup(api);
|
||||
|
||||
@@ -169,6 +163,8 @@ TEST_F(BufferUpdatesTest, BufferObjectUpdateWithOffset) {
|
||||
auto swapChain = cleanup.add(createSwapChain());
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
|
||||
TrianglePrimitive const triangle(api);
|
||||
|
||||
// Create a program.
|
||||
Shader shader = createShader();
|
||||
|
||||
@@ -182,9 +178,9 @@ TEST_F(BufferUpdatesTest, BufferObjectUpdateWithOffset) {
|
||||
|
||||
// Create a render target.
|
||||
auto colorTexture = cleanup.add(api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
TextureFormat::RGBA8, 1, 512, 512, 1, TextureUsage::COLOR_ATTACHMENT));
|
||||
TextureFormat::RGBA8, 1, kTexWidth, kTexHeight, 1, TextureUsage::COLOR_ATTACHMENT));
|
||||
auto renderTarget = cleanup.add(api.createRenderTarget(
|
||||
TargetBufferFlags::COLOR0, 512, 512, 1, 0, {{ colorTexture }}, {}, {}));
|
||||
TargetBufferFlags::COLOR0, kTexWidth, kTexHeight, 1, 0, {{ colorTexture }}, {}, {}));
|
||||
|
||||
// Upload uniforms for the first triangle.
|
||||
// Upload the uniform, but with an offset to accommodate the padding in the shader's
|
||||
@@ -195,38 +191,50 @@ TEST_F(BufferUpdatesTest, BufferObjectUpdateWithOffset) {
|
||||
.offset = { 0.0f, 0.0f, 0.0f, 0.0f }
|
||||
});
|
||||
|
||||
RenderPassParams params = {};
|
||||
params.flags.clear = TargetBufferFlags::COLOR;
|
||||
params.clearColor = { 0.f, 0.f, 1.f, 1.f };
|
||||
params.flags.discardStart = TargetBufferFlags::ALL;
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
params.viewport.height = 512;
|
||||
params.viewport.width = 512;
|
||||
renderTriangle({ { shader.getDescriptorSetLayout() } }, renderTarget, swapChain,
|
||||
shader.getProgram(), params);
|
||||
{
|
||||
RenderFrame frame(api);
|
||||
|
||||
// Upload uniforms for the second triangle. To test partial buffer updates, we'll only update
|
||||
// color.b, color.a, scaleMinusOne, offset.x, and offset.y.
|
||||
const UniformBindingConfig partialBindingConfig = {
|
||||
.dataSize = sizeof(float) * 8,
|
||||
.bufferSize = sizeof(SimpleMaterialParams) + 64,
|
||||
.byteOffset = 64 + offsetof(SimpleMaterialParams, color.b)
|
||||
};
|
||||
shader.uploadUniform(api, ubuffer, partialBindingConfig,
|
||||
std::array<float, 8>{
|
||||
1.0f, 1.0f, // color.b, color.a
|
||||
0.0f, 0.0f, 0.0f, 0.0f, // scale
|
||||
0.5f, 0.5f // offset.x, offset.y
|
||||
});
|
||||
RenderPassParams clearParams = getClearColorRenderPass();
|
||||
clearParams.viewport.height = kTexWidth;
|
||||
clearParams.viewport.width = kTexHeight;
|
||||
api.beginRenderPass(renderTarget, clearParams);
|
||||
|
||||
params.flags.clear = TargetBufferFlags::NONE;
|
||||
params.flags.discardStart = TargetBufferFlags::NONE;
|
||||
renderTriangle({{ shader.getDescriptorSetLayout() }},
|
||||
renderTarget, swapChain, shader.getProgram(), params);
|
||||
PipelineState state = getColorWritePipelineState();
|
||||
shader.addProgramToPipelineState(state);
|
||||
|
||||
triangle.bindWithPipelineState(api, state);
|
||||
triangle.draw(api);
|
||||
|
||||
api.endRenderPass();
|
||||
|
||||
// Upload uniforms for the second triangle. To test partial buffer updates, we'll only update
|
||||
// color.b, color.a, scaleMinusOne, offset.x, and offset.y.
|
||||
const UniformBindingConfig partialBindingConfig = {
|
||||
.dataSize = sizeof(float) * 8,
|
||||
.bufferSize = sizeof(SimpleMaterialParams) + 64,
|
||||
.byteOffset = 64 + offsetof(SimpleMaterialParams, color.b)
|
||||
};
|
||||
shader.uploadUniform(api, ubuffer, partialBindingConfig,
|
||||
std::array<float, 8>{
|
||||
1.0f, 1.0f, // color.b, color.a
|
||||
0.0f, 0.0f, 0.0f, 0.0f, // scale
|
||||
0.5f, 0.5f // offset.x, offset.y
|
||||
});
|
||||
|
||||
RenderPassParams noClearParams = getNoClearRenderPass();
|
||||
noClearParams.viewport.height = kTexWidth;
|
||||
noClearParams.viewport.width = kTexHeight;
|
||||
api.beginRenderPass(renderTarget, noClearParams);
|
||||
|
||||
triangle.bindWithPipelineState(api, state);
|
||||
triangle.draw(api);
|
||||
|
||||
api.endRenderPass();
|
||||
}
|
||||
|
||||
|
||||
EXPECT_IMAGE(renderTarget, getExpectations(),
|
||||
ScreenshotParams(512, 512, "BufferObjectUpdateWithOffset", 91322442));
|
||||
ScreenshotParams(kTexWidth, kTexHeight, "BufferObjectUpdateWithOffset", 2320747245));
|
||||
|
||||
api.flush();
|
||||
api.commit(swapChain);
|
||||
|
||||
@@ -120,7 +120,7 @@ TEST_F(BackendTest, FeedbackLoops) {
|
||||
Shader shader = Shader(api, cleanup, ShaderConfig {
|
||||
.vertexShader = fullscreenVs,
|
||||
.fragmentShader = fullscreenFs,
|
||||
.uniforms = {{"test_tex", DescriptorType::SAMPLER, samplerInfo}, {"Params"}}
|
||||
.uniforms = {{"test_tex", DescriptorType::SAMPLER_2D_FLOAT, samplerInfo}, {"Params"}}
|
||||
});
|
||||
|
||||
TrianglePrimitive const triangle(getDriverApi());
|
||||
@@ -161,15 +161,10 @@ TEST_F(BackendTest, FeedbackLoops) {
|
||||
for (int frame = 0; frame < kNumFrames; frame++) {
|
||||
|
||||
// Prep for rendering.
|
||||
RenderPassParams params = {};
|
||||
params.flags.clear = TargetBufferFlags::NONE;
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
PipelineState state;
|
||||
state.rasterState.colorWrite = true;
|
||||
state.rasterState.depthWrite = false;
|
||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||
state.program = shader.getProgram();
|
||||
state.pipelineLayout.setLayout[0] = { shader.getDescriptorSetLayout() };
|
||||
PipelineState state = getColorWritePipelineState();
|
||||
shader.addProgramToPipelineState(state);
|
||||
|
||||
RenderPassParams params = getNoClearRenderPass();
|
||||
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
api.beginFrame(0, 0, 0);
|
||||
|
||||
@@ -52,7 +52,7 @@ layout(location = 0, set = 0) uniform {samplerType} test_tex;
|
||||
void main() {
|
||||
vec2 fbsize = vec2(512);
|
||||
vec2 uv = gl_FragCoord.xy / fbsize;
|
||||
#if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT)
|
||||
#if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT) || defined(TARGET_WEBGPU_ENVIRONMENT)
|
||||
uv.y = 1.0 - uv.y;
|
||||
#endif
|
||||
fragColor = vec4(texture(test_tex, uv).rgb, 1.0f);
|
||||
@@ -73,7 +73,7 @@ float getLayer(in sampler2DArray s) { return 2.0f; }
|
||||
void main() {
|
||||
vec2 fbsize = vec2(512);
|
||||
vec2 uv = gl_FragCoord.xy / fbsize;
|
||||
#if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT)
|
||||
#if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT) || defined(TARGET_WEBGPU_ENVIRONMENT)
|
||||
uv.y = 1.0 - uv.y;
|
||||
#endif
|
||||
fragColor = vec4(texture(test_tex, vec3(uv, getLayer(test_tex))).rgb, 1.0f);
|
||||
@@ -91,7 +91,7 @@ layout(location = 0, set = 0) uniform sampler2D test_tex;
|
||||
void main() {
|
||||
vec2 fbsize = vec2(512);
|
||||
vec2 uv = gl_FragCoord.xy / fbsize;
|
||||
#if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT)
|
||||
#if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT) || defined(TARGET_WEBGPU_ENVIRONMENT)
|
||||
uv.y = 1.0 - uv.y;
|
||||
#endif
|
||||
fragColor = vec4(textureLod(test_tex, uv, 1.0f).rgb, 1.0f);
|
||||
@@ -215,7 +215,7 @@ TEST_F(LoadImageTest, UpdateImage2D) {
|
||||
FAIL_IF(Backend::VULKAN, "Multiple test cases crash, see b/417481434");
|
||||
|
||||
// All of these test cases should result in the same rendered image, and thus the same hash.
|
||||
static const uint32_t expectedHash = 3644679986;
|
||||
static const uint32_t expectedHash = 1875922935;
|
||||
|
||||
struct TestCase {
|
||||
const char* name;
|
||||
@@ -308,7 +308,7 @@ TEST_F(LoadImageTest, UpdateImage2D) {
|
||||
Shader shader(api, cleanup, ShaderConfig{
|
||||
.vertexShader = mVertexShader,
|
||||
.fragmentShader= fragment,
|
||||
.uniforms = {{"test_tex", DescriptorType::SAMPLER, samplerInfo}}
|
||||
.uniforms = {{"test_tex", DescriptorType::SAMPLER_2D_FLOAT, samplerInfo}}
|
||||
});
|
||||
|
||||
// Create a Texture.
|
||||
@@ -372,7 +372,7 @@ TEST_F(LoadImageTest, UpdateImageSRGB) {
|
||||
getSamplerTypeName(textureFormat), fragmentTemplate);
|
||||
Shader shader(api, cleanup, ShaderConfig{
|
||||
.vertexShader = mVertexShader, .fragmentShader = fragment, .uniforms = {{
|
||||
"test_tex", DescriptorType::SAMPLER, samplerInfo
|
||||
"test_tex", DescriptorType::SAMPLER_2D_FLOAT, samplerInfo
|
||||
}}});
|
||||
|
||||
// Create a texture.
|
||||
@@ -417,7 +417,7 @@ TEST_F(LoadImageTest, UpdateImageSRGB) {
|
||||
defaultRenderTarget, swapChain, shader.getProgram());
|
||||
|
||||
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
|
||||
ScreenshotParams(512, 512, "UpdateImageSRGB", 359858623));
|
||||
ScreenshotParams(512, 512, "UpdateImageSRGB", 3300305265));
|
||||
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
@@ -447,7 +447,7 @@ TEST_F(LoadImageTest, UpdateImageMipLevel) {
|
||||
Shader shader(api, cleanup, ShaderConfig {
|
||||
.vertexShader = mVertexShader,
|
||||
.fragmentShader = fragment,
|
||||
.uniforms = {{"test_tex", DescriptorType::SAMPLER, samplerInfo}}
|
||||
.uniforms = {{"test_tex", DescriptorType::SAMPLER_2D_FLOAT, samplerInfo}}
|
||||
});
|
||||
|
||||
// Create a texture with 3 mip levels.
|
||||
@@ -476,7 +476,7 @@ TEST_F(LoadImageTest, UpdateImageMipLevel) {
|
||||
defaultRenderTarget, swapChain, shader.getProgram());
|
||||
|
||||
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
|
||||
ScreenshotParams(512, 512, "UpdateImageMipLevel", 3644679986));
|
||||
ScreenshotParams(512, 512, "UpdateImageMipLevel", 1875922935));
|
||||
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
@@ -511,7 +511,7 @@ TEST_F(LoadImageTest, UpdateImage3D) {
|
||||
Shader shader(api, cleanup, ShaderConfig {
|
||||
.vertexShader = mVertexShader,
|
||||
.fragmentShader = fragment,
|
||||
.uniforms = {{"test_tex", DescriptorType::SAMPLER, samplerInfo}}
|
||||
.uniforms = {{"test_tex", DescriptorType::SAMPLER_2D_ARRAY_FLOAT, samplerInfo}}
|
||||
});
|
||||
|
||||
// Create a texture.
|
||||
@@ -550,7 +550,7 @@ TEST_F(LoadImageTest, UpdateImage3D) {
|
||||
defaultRenderTarget, swapChain, shader.getProgram());
|
||||
|
||||
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
|
||||
ScreenshotParams(512, 512, "UpdateImage3D", 3644679986));
|
||||
ScreenshotParams(512, 512, "UpdateImage3D", 1875922935));
|
||||
}
|
||||
|
||||
api.stopCapture();
|
||||
|
||||
@@ -102,19 +102,11 @@ TEST_F(BackendTest, MRT) {
|
||||
{}, // depth
|
||||
{})); // stencil
|
||||
|
||||
RenderPassParams params = {};
|
||||
fullViewport(params);
|
||||
params.flags.clear = TargetBufferFlags::COLOR;
|
||||
params.clearColor = {0.f, 1.f, 0.f, 1.f};
|
||||
params.flags.discardStart = TargetBufferFlags::ALL;
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
PipelineState state = getColorWritePipelineState();
|
||||
shader.addProgramToPipelineState(state);
|
||||
|
||||
PipelineState state;
|
||||
state.program = shader.getProgram();
|
||||
state.rasterState.colorWrite = true;
|
||||
state.rasterState.depthWrite = false;
|
||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||
state.rasterState.culling = CullingMode::NONE;
|
||||
RenderPassParams params = getClearColorRenderPass();
|
||||
params.viewport = getFullViewport();
|
||||
|
||||
api.startCapture(0);
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ TEST_F(BackendTest, TextureViewLod) {
|
||||
.vertexShader = vertexShader,
|
||||
.fragmentShader = fragmentTexturedLod,
|
||||
.uniforms = {{
|
||||
"backend_test_sib_tex", DescriptorType::SAMPLER, samplerInfo
|
||||
"backend_test_sib_tex", DescriptorType::SAMPLER_2D_FLOAT, samplerInfo
|
||||
}}
|
||||
});
|
||||
|
||||
@@ -138,37 +138,25 @@ TEST_F(BackendTest, TextureViewLod) {
|
||||
TargetBufferFlags::COLOR, 32, 32, 1, 0,
|
||||
{texture, 2 /* level */, 0 /* layer */}, {}, {}));
|
||||
{
|
||||
RenderPassParams params = {};
|
||||
fullViewport(params);
|
||||
params.flags.clear = TargetBufferFlags::NONE;
|
||||
params.flags.discardStart = TargetBufferFlags::NONE;
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
PipelineState ps = {};
|
||||
ps.program = whiteShader.getProgram();
|
||||
ps.rasterState.colorWrite = true;
|
||||
ps.rasterState.depthWrite = false;
|
||||
PipelineState state = getColorWritePipelineState();
|
||||
whiteShader.addProgramToPipelineState(state);
|
||||
|
||||
RenderPassParams params = getNoClearRenderPass();
|
||||
params.viewport = getFullViewport();
|
||||
|
||||
api.beginRenderPass(renderTarget, params);
|
||||
api.draw(ps, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
api.draw(state, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
api.endRenderPass();
|
||||
}
|
||||
|
||||
backend::Handle<HwRenderTarget> defaultRenderTarget =
|
||||
cleanup.add(api.createDefaultRenderTarget(0));
|
||||
|
||||
RenderPassParams params = {};
|
||||
fullViewport(params);
|
||||
params.flags.clear = TargetBufferFlags::COLOR;
|
||||
params.clearColor = {0.f, 0.f, 0.5f, 1.f};
|
||||
params.flags.discardStart = TargetBufferFlags::ALL;
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
PipelineState state = getColorWritePipelineState();
|
||||
texturedShader.addProgramToPipelineState(state);
|
||||
|
||||
PipelineState state;
|
||||
state.program = texturedShader.getProgram();
|
||||
state.pipelineLayout.setLayout = { texturedShader.getDescriptorSetLayout() };
|
||||
state.rasterState.colorWrite = true;
|
||||
state.rasterState.depthWrite = false;
|
||||
state.rasterState.depthFunc = SamplerCompareFunc::A;
|
||||
state.rasterState.culling = CullingMode::NONE;
|
||||
RenderPassParams params = getClearColorRenderPass();
|
||||
params.viewport = getFullViewport();
|
||||
|
||||
DescriptorSetHandle descriptorSet13 = texturedShader.createDescriptorSet(api);
|
||||
api.updateDescriptorSetTexture(descriptorSet13, 0, texture13, {
|
||||
|
||||
@@ -79,19 +79,11 @@ TEST_F(BackendTest, MissingRequiredAttributes) {
|
||||
|
||||
TrianglePrimitive triangle(api);
|
||||
|
||||
RenderPassParams params = {};
|
||||
fullViewport(params);
|
||||
params.flags.clear = TargetBufferFlags::COLOR;
|
||||
params.clearColor = { 0.f, 1.f, 0.f, 1.f };
|
||||
params.flags.discardStart = TargetBufferFlags::ALL;
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
PipelineState state = getColorWritePipelineState();
|
||||
shader.addProgramToPipelineState(state);
|
||||
|
||||
PipelineState state;
|
||||
state.program = shader.getProgram();
|
||||
state.rasterState.colorWrite = true;
|
||||
state.rasterState.depthWrite = false;
|
||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||
state.rasterState.culling = CullingMode::NONE;
|
||||
RenderPassParams params = getClearColorRenderPass();
|
||||
params.viewport = getFullViewport();
|
||||
|
||||
api.startCapture(0);
|
||||
|
||||
|
||||
@@ -21,11 +21,16 @@
|
||||
#include "ShaderGenerator.h"
|
||||
#include "Skip.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
#include "backend/DriverEnums.h"
|
||||
#include "backend/Handle.h"
|
||||
|
||||
#include <utils/Hash.h>
|
||||
|
||||
namespace test {
|
||||
|
||||
static ShaderGenerator::PushConstants gVertConstants;
|
||||
static ShaderGenerator::PushConstants gFragConstants;
|
||||
|
||||
using namespace filament;
|
||||
using namespace filament::backend;
|
||||
|
||||
@@ -79,10 +84,29 @@ void main() {
|
||||
fragColor = vec4(pushConstants.red, pushConstants.green, pushConstants.blue, 1.0);
|
||||
})";
|
||||
|
||||
void initPushConstants() {
|
||||
// TODO: move this initialization to a more appropriate place.
|
||||
gVertConstants.clear();
|
||||
gFragConstants.clear();
|
||||
|
||||
gVertConstants.reserve(4);
|
||||
gVertConstants.resize(4);
|
||||
gVertConstants[pushConstantIndex.TRIANGLE_HIDE] = {"hideTriangle", backend::ConstantType::BOOL};
|
||||
gVertConstants[pushConstantIndex.TRIANGLE_SCALE] = {"triangleScale", backend::ConstantType::FLOAT};
|
||||
gVertConstants[pushConstantIndex.TRIANGLE_OFFSET_X] = {"triangleOffsetX", backend::ConstantType::FLOAT};
|
||||
gVertConstants[pushConstantIndex.TRIANGLE_OFFSET_Y] = {"triangleOffsetY", backend::ConstantType::FLOAT};
|
||||
|
||||
gFragConstants.reserve(4);
|
||||
gFragConstants.resize(4);
|
||||
gFragConstants[pushConstantIndex.RED] = {"red", backend::ConstantType::FLOAT};
|
||||
gFragConstants[pushConstantIndex.GREEN] = {"green", backend::ConstantType::FLOAT};
|
||||
gFragConstants[pushConstantIndex.BLUE] = {"blue", backend::ConstantType::FLOAT};
|
||||
}
|
||||
|
||||
TEST_F(BackendTest, PushConstants) {
|
||||
SKIP_IF(Backend::OPENGL, "Push constants not supported on OpenGL");
|
||||
FAIL_IF(Backend::VULKAN,
|
||||
"Crashing due to no program set when setting push constants, see b/417477740");
|
||||
|
||||
initPushConstants();
|
||||
|
||||
auto& api = getDriverApi();
|
||||
|
||||
@@ -98,22 +122,20 @@ TEST_F(BackendTest, PushConstants) {
|
||||
|
||||
// Create a program.
|
||||
ShaderGenerator shaderGen(triangleVs, triangleFs, sBackend, sIsMobilePlatform);
|
||||
Program p = shaderGen.getProgram(api);
|
||||
Program p =
|
||||
shaderGen.getProgramWithPushConstants(api, { gVertConstants, gFragConstants, {} });
|
||||
ProgramHandle program = cleanup.add(api.createProgram(std::move(p)));
|
||||
|
||||
Handle<HwRenderTarget> renderTarget = cleanup.add(api.createDefaultRenderTarget());
|
||||
|
||||
TrianglePrimitive triangle(api);
|
||||
|
||||
RenderPassParams params = {};
|
||||
params.flags.clear = TargetBufferFlags::COLOR0;
|
||||
params.viewport = { 0, 0, 512, 512 };
|
||||
params.clearColor = math::float4(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
params.flags.discardStart = TargetBufferFlags::ALL;
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
RenderPassParams params = getClearColorRenderPass();
|
||||
params.viewport = getFullViewport();
|
||||
|
||||
PipelineState ps = {};
|
||||
ps.program = program;
|
||||
ps.vertexBufferInfo = triangle.getVertexBufferInfo();
|
||||
ps.rasterState.colorWrite = true;
|
||||
ps.rasterState.depthWrite = false;
|
||||
|
||||
@@ -121,6 +143,8 @@ TEST_F(BackendTest, PushConstants) {
|
||||
api.beginFrame(0, 0, 0);
|
||||
|
||||
api.beginRenderPass(renderTarget, params);
|
||||
api.bindPipeline(ps);
|
||||
api.bindRenderPrimitive(triangle.getRenderPrimitive());
|
||||
|
||||
// Set the push constants to scale the triangle in half
|
||||
api.setPushConstant(ShaderStage::VERTEX, pushConstantIndex.TRIANGLE_HIDE, false);
|
||||
@@ -130,7 +154,7 @@ TEST_F(BackendTest, PushConstants) {
|
||||
api.setPushConstant(ShaderStage::FRAGMENT, pushConstantIndex.RED, 0.25f);
|
||||
api.setPushConstant(ShaderStage::FRAGMENT, pushConstantIndex.GREEN, 0.5f);
|
||||
api.setPushConstant(ShaderStage::FRAGMENT, pushConstantIndex.BLUE, 1.0f);
|
||||
api.draw(ps, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
api.draw2(0, 3, 1);
|
||||
|
||||
// Draw another triangle, transposed to the upper-right.
|
||||
api.setPushConstant(ShaderStage::VERTEX, pushConstantIndex.TRIANGLE_OFFSET_X, 0.5f);
|
||||
@@ -140,7 +164,7 @@ TEST_F(BackendTest, PushConstants) {
|
||||
api.setPushConstant(ShaderStage::FRAGMENT, pushConstantIndex.GREEN, 0.5f);
|
||||
api.setPushConstant(ShaderStage::FRAGMENT, pushConstantIndex.BLUE, 0.25f);
|
||||
|
||||
api.draw(ps, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
api.draw2(0, 3, 1);
|
||||
|
||||
// Draw a final triangle, transposed to the lower-left.
|
||||
api.setPushConstant(ShaderStage::VERTEX, pushConstantIndex.TRIANGLE_OFFSET_X, -0.5f);
|
||||
@@ -150,12 +174,13 @@ TEST_F(BackendTest, PushConstants) {
|
||||
api.setPushConstant(ShaderStage::FRAGMENT, pushConstantIndex.GREEN, 0.25f);
|
||||
api.setPushConstant(ShaderStage::FRAGMENT, pushConstantIndex.BLUE, 1.00f);
|
||||
|
||||
api.draw(ps, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
api.draw2(0, 3, 1);
|
||||
|
||||
api.endRenderPass();
|
||||
|
||||
EXPECT_IMAGE(renderTarget, getExpectations(),
|
||||
ScreenshotParams(512, 512, "pushConstants", 1957275826));
|
||||
ScreenshotParams(params.viewport.width, params.viewport.height, "pushConstants",
|
||||
3575588741));
|
||||
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
|
||||
@@ -279,14 +279,9 @@ TEST_F(ReadPixelsTest, ReadPixels) {
|
||||
|
||||
TrianglePrimitive const triangle(api);
|
||||
|
||||
RenderPassParams params = {};
|
||||
fullViewport(params);
|
||||
params.flags.clear = TargetBufferFlags::COLOR;
|
||||
params.clearColor = { 0.f, 0.f, 1.f, 1.f };
|
||||
params.flags.discardStart = TargetBufferFlags::ALL;
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
params.viewport.height = t.getRenderTargetSize();
|
||||
RenderPassParams params = getClearColorRenderPass(math::float4(0, 0, 1, 1));
|
||||
params.viewport.width = t.getRenderTargetSize();
|
||||
params.viewport.height = t.getRenderTargetSize();
|
||||
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
api.beginFrame(0, 0, 0);
|
||||
@@ -294,15 +289,12 @@ TEST_F(ReadPixelsTest, ReadPixels) {
|
||||
// Render a white triangle over blue.
|
||||
api.beginRenderPass(renderTarget, params);
|
||||
|
||||
PipelineState state;
|
||||
state.program = floatShader.getProgram();
|
||||
PipelineState state = getColorWritePipelineState();
|
||||
if (isUnsignedIntFormat(t.textureFormat)) {
|
||||
state.program = uintShader.getProgram();
|
||||
uintShader.addProgramToPipelineState(state);
|
||||
} else {
|
||||
floatShader.addProgramToPipelineState(state);
|
||||
}
|
||||
state.rasterState.colorWrite = true;
|
||||
state.rasterState.depthWrite = false;
|
||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||
state.rasterState.culling = CullingMode::NONE;
|
||||
api.draw(state, triangle.getRenderPrimitive(), 0, 3, 1);
|
||||
|
||||
api.endRenderPass();
|
||||
@@ -400,24 +392,15 @@ TEST_F(ReadPixelsTest, ReadPixelsPerformance) {
|
||||
|
||||
TrianglePrimitive triangle(api);
|
||||
|
||||
RenderPassParams params = {};
|
||||
fullViewport(params);
|
||||
params.flags.clear = TargetBufferFlags::COLOR;
|
||||
params.clearColor = { 0.f, 0.f, 1.f, 1.f };
|
||||
params.flags.discardStart = TargetBufferFlags::ALL;
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
params.viewport.height = renderTargetSize;
|
||||
PipelineState state = getColorWritePipelineState();
|
||||
shader.addProgramToPipelineState(state);
|
||||
|
||||
RenderPassParams params = getClearColorRenderPass(math::float4(0, 0, 1, 1));
|
||||
params.viewport.width = renderTargetSize;
|
||||
params.viewport.height = renderTargetSize;
|
||||
|
||||
void* buffer = calloc(1, renderTargetSize * renderTargetSize * 4);
|
||||
|
||||
PipelineState state;
|
||||
state.program = shader.getProgram();
|
||||
state.rasterState.colorWrite = true;
|
||||
state.rasterState.depthWrite = false;
|
||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||
state.rasterState.culling = CullingMode::NONE;
|
||||
|
||||
for (int iteration = 0; iteration < iterationCount; ++iteration) {
|
||||
readPixelsFinished = false;
|
||||
|
||||
|
||||
@@ -73,20 +73,11 @@ TEST_F(BackendTest, RenderExternalImageWithoutSet) {
|
||||
1, // depth
|
||||
usage)); // usage
|
||||
|
||||
RenderPassParams params = {};
|
||||
fullViewport(params);
|
||||
params.flags.clear = TargetBufferFlags::COLOR;
|
||||
params.clearColor = { 0.f, 1.f, 0.f, 1.f };
|
||||
params.flags.discardStart = TargetBufferFlags::ALL;
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
PipelineState state = getColorWritePipelineState();
|
||||
shader.addProgramToPipelineState(state);
|
||||
|
||||
PipelineState state;
|
||||
state.program = shader.getProgram();
|
||||
state.pipelineLayout.setLayout[0] = { shader.getDescriptorSetLayout() };
|
||||
state.rasterState.colorWrite = true;
|
||||
state.rasterState.depthWrite = false;
|
||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||
state.rasterState.culling = CullingMode::NONE;
|
||||
RenderPassParams params = getClearColorRenderPass();
|
||||
params.viewport = getFullViewport();
|
||||
|
||||
DescriptorSetHandle descriptorSet = shader.createDescriptorSet(api);
|
||||
|
||||
@@ -179,20 +170,11 @@ TEST_F(BackendTest, RenderExternalImage) {
|
||||
// We're now free to release the buffer.
|
||||
CVBufferRelease(pixBuffer);
|
||||
|
||||
RenderPassParams params = {};
|
||||
fullViewport(params);
|
||||
params.flags.clear = TargetBufferFlags::COLOR;
|
||||
params.clearColor = { 0.f, 1.f, 0.f, 1.f };
|
||||
params.flags.discardStart = TargetBufferFlags::ALL;
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
PipelineState state = getColorWritePipelineState();
|
||||
shader.addProgramToPipelineState(state);
|
||||
|
||||
PipelineState state;
|
||||
state.program = shader.getProgram();
|
||||
state.pipelineLayout.setLayout[0] = { shader.getDescriptorSetLayout() };
|
||||
state.rasterState.colorWrite = true;
|
||||
state.rasterState.depthWrite = false;
|
||||
state.rasterState.depthFunc = RasterState::DepthFunc::A;
|
||||
state.rasterState.culling = CullingMode::NONE;
|
||||
RenderPassParams params = getClearColorRenderPass();
|
||||
params.viewport = getFullViewport();
|
||||
|
||||
api.startCapture(0);
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
@@ -210,7 +192,7 @@ TEST_F(BackendTest, RenderExternalImage) {
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
EXPECT_IMAGE(defaultRenderTarget, getExpectations(),
|
||||
ScreenshotParams(512, 512, "RenderExternalImage", 267229901));
|
||||
ScreenshotParams(512, 512, "RenderExternalImage", 1206264951));
|
||||
|
||||
api.stopCapture(0);
|
||||
api.finish();
|
||||
|
||||
@@ -80,8 +80,8 @@ TEST_F(BackendTest, ScissorViewportRegion) {
|
||||
});
|
||||
|
||||
// Create source color and depth textures.
|
||||
Handle<HwTexture> srcTexture = cleanup.add(api.createTexture(SamplerType::SAMPLER_2D, kNumLevels,
|
||||
kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
Handle<HwTexture> srcTexture = cleanup.add(api.createTexture(SamplerType::SAMPLER_2D,
|
||||
kNumLevels, kSrcTexFormat, 1, kSrcTexWidth, kSrcTexHeight, 1,
|
||||
TextureUsage::SAMPLEABLE | TextureUsage::COLOR_ATTACHMENT));
|
||||
Handle<HwTexture> depthTexture = cleanup.add(api.createTexture(SamplerType::SAMPLER_2D, 1,
|
||||
TextureFormat::DEPTH16, 1, 512, 512, 1,
|
||||
@@ -104,27 +104,21 @@ TEST_F(BackendTest, ScissorViewportRegion) {
|
||||
// We purposely set the render target width and height to smaller than the texture, to check
|
||||
// that this case is handled correctly.
|
||||
Handle<HwRenderTarget> srcRenderTarget = cleanup.add(api.createRenderTarget(
|
||||
TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH, kSrcRtHeight, kSrcRtHeight, 1, 0,
|
||||
{srcTexture, kSrcLevel, 0}, {depthTexture, 0, 0}, {}));
|
||||
TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH, kSrcRtHeight, kSrcRtHeight, 1,
|
||||
0, { srcTexture, kSrcLevel, 0 }, { depthTexture, 0, 0 }, {}));
|
||||
|
||||
Handle<HwRenderTarget> fullRenderTarget = cleanup.add(api.createRenderTarget(TargetBufferFlags::COLOR,
|
||||
kSrcTexHeight >> kSrcLevel, kSrcTexWidth >> kSrcLevel, 1, 0,
|
||||
{srcTexture, kSrcLevel, 0}, {}, {}));
|
||||
Handle<HwRenderTarget> fullRenderTarget = cleanup.add(
|
||||
api.createRenderTarget(TargetBufferFlags::COLOR, kSrcTexHeight >> kSrcLevel,
|
||||
kSrcTexWidth >> kSrcLevel, 1, 0, {srcTexture, kSrcLevel, 0}, {}, {}));
|
||||
|
||||
TrianglePrimitive triangle(api);
|
||||
|
||||
// Render a white triangle over blue.
|
||||
RenderPassParams params = {};
|
||||
params.flags.clear = TargetBufferFlags::COLOR0;
|
||||
RenderPassParams params = getClearColorRenderPass();
|
||||
params.viewport = srcRect;
|
||||
params.clearColor = math::float4(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
params.flags.discardStart = TargetBufferFlags::ALL;
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
|
||||
PipelineState ps = {};
|
||||
ps.program = shader.getProgram();
|
||||
ps.rasterState.colorWrite = true;
|
||||
ps.rasterState.depthWrite = false;
|
||||
PipelineState ps = getColorWritePipelineState();
|
||||
shader.addProgramToPipelineState(ps);
|
||||
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
api.beginFrame(0, 0, 0);
|
||||
@@ -135,7 +129,7 @@ TEST_F(BackendTest, ScissorViewportRegion) {
|
||||
api.endRenderPass();
|
||||
|
||||
EXPECT_IMAGE(fullRenderTarget, getExpectations(),
|
||||
ScreenshotParams(kSrcTexWidth >> 1, kSrcTexHeight >> 1, "scissor", 0xAB3D1C53));
|
||||
ScreenshotParams(kSrcTexWidth >> 1, kSrcTexHeight >> 1, "scissor", 15842520));
|
||||
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
@@ -196,17 +190,11 @@ TEST_F(BackendTest, ScissorViewportEdgeCases) {
|
||||
TrianglePrimitive triangle(api);
|
||||
|
||||
// Render a white triangle over blue.
|
||||
RenderPassParams params = {};
|
||||
params.flags.clear = TargetBufferFlags::COLOR0;
|
||||
RenderPassParams params = getClearColorRenderPass();
|
||||
params.viewport = bottomLeftViewport;
|
||||
params.clearColor = math::float4(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
params.flags.discardStart = TargetBufferFlags::ALL;
|
||||
params.flags.discardEnd = TargetBufferFlags::NONE;
|
||||
|
||||
PipelineState ps = {};
|
||||
ps.program = shader.getProgram();
|
||||
ps.rasterState.colorWrite = true;
|
||||
ps.rasterState.depthWrite = false;
|
||||
PipelineState ps = getColorWritePipelineState();
|
||||
shader.addProgramToPipelineState(ps);
|
||||
|
||||
api.makeCurrent(swapChain, swapChain);
|
||||
api.beginFrame(0, 0, 0);
|
||||
@@ -225,7 +213,7 @@ TEST_F(BackendTest, ScissorViewportEdgeCases) {
|
||||
api.endRenderPass();
|
||||
|
||||
EXPECT_IMAGE(renderTarget, getExpectations(),
|
||||
ScreenshotParams(512, 512, "ScissorViewportEdgeCases", 0x6BF00F31));
|
||||
ScreenshotParams(512, 512, "ScissorViewportEdgeCases", 2199186852));
|
||||
|
||||
api.commit(swapChain);
|
||||
api.endFrame(0);
|
||||
|
||||
@@ -130,7 +130,7 @@ public:
|
||||
*
|
||||
* @param engine Reference to the filament::Engine associated with this BufferObject.
|
||||
* @param buffer A BufferDescriptor representing the data used to initialize the BufferObject.
|
||||
* @param byteOffset Offset in bytes into the BufferObject
|
||||
* @param byteOffset Offset in bytes into the BufferObject. Must be multiple of 4.
|
||||
*/
|
||||
void setBuffer(Engine& engine, BufferDescriptor&& buffer, uint32_t byteOffset = 0);
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ public:
|
||||
* @param buffer A BufferDescriptor representing the data used to initialize the IndexBuffer.
|
||||
* BufferDescriptor points to raw, untyped data that will be interpreted as
|
||||
* either 16-bit or 32-bits indices based on the Type of this IndexBuffer.
|
||||
* @param byteOffset Offset in *bytes* into the IndexBuffer
|
||||
* @param byteOffset Offset in *bytes* into the IndexBuffer. Must be multiple of 4.
|
||||
*/
|
||||
void setBuffer(Engine& engine, BufferDescriptor&& buffer, uint32_t byteOffset = 0);
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include <filament/FilamentAPI.h>
|
||||
#include <filament/Color.h>
|
||||
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/MaterialEnums.h>
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
@@ -529,6 +529,13 @@ public:
|
||||
void setStencilWriteMask(uint8_t writeMask,
|
||||
StencilFace face = StencilFace::FRONT_AND_BACK) noexcept;
|
||||
|
||||
/**
|
||||
* PostProcess and compute domain material instance must be commited manually. This call has
|
||||
* no effect on surface domain materials.
|
||||
* @param engine Filament engine
|
||||
*/
|
||||
void commit(Engine& engine) const;
|
||||
|
||||
protected:
|
||||
// prevent heap allocation
|
||||
~MaterialInstance() = default;
|
||||
|
||||
@@ -373,18 +373,30 @@ struct RenderQuality {
|
||||
* @see setAmbientOcclusionOptions()
|
||||
*/
|
||||
struct AmbientOcclusionOptions {
|
||||
enum class AmbientOcclusionType : uint8_t {
|
||||
SAO, //!< use Scalable Ambient Occlusion
|
||||
GTAO, //!< use Ground Truth-Based Ambient Occlusion
|
||||
};
|
||||
|
||||
AmbientOcclusionType aoType = AmbientOcclusionType::SAO;//!< Type of ambient occlusion algorithm.
|
||||
float radius = 0.3f; //!< Ambient Occlusion radius in meters, between 0 and ~10.
|
||||
float power = 1.0f; //!< Controls ambient occlusion's contrast. Must be positive.
|
||||
float bias = 0.0005f; //!< Self-occlusion bias in meters. Use to avoid self-occlusion. Between 0 and a few mm.
|
||||
|
||||
/**
|
||||
* Self-occlusion bias in meters. Use to avoid self-occlusion.
|
||||
* Between 0 and a few mm. No effect when aoType set to GTAO
|
||||
*/
|
||||
float bias = 0.0005f;
|
||||
|
||||
float resolution = 0.5f;//!< How each dimension of the AO buffer is scaled. Must be either 0.5 or 1.0.
|
||||
float intensity = 1.0f; //!< Strength of the Ambient Occlusion effect.
|
||||
float bilateralThreshold = 0.05f; //!< depth distance that constitute an edge for filtering
|
||||
QualityLevel quality = QualityLevel::LOW; //!< affects # of samples used for AO.
|
||||
QualityLevel lowPassFilter = QualityLevel::MEDIUM; //!< affects AO smoothness
|
||||
QualityLevel quality = QualityLevel::LOW; //!< affects # of samples used for AO and params for filtering
|
||||
QualityLevel lowPassFilter = QualityLevel::MEDIUM; //!< affects AO smoothness. Recommend setting to HIGH when aoType set to GTAO.
|
||||
QualityLevel upsampling = QualityLevel::LOW; //!< affects AO buffer upsampling quality
|
||||
bool enabled = false; //!< enables or disables screen-space ambient occlusion
|
||||
bool bentNormals = false; //!< enables bent normals computation from AO, and specular AO
|
||||
float minHorizonAngleRad = 0.0f; //!< min angle in radian to consider
|
||||
float minHorizonAngleRad = 0.0f; //!< min angle in radian to consider. No effect when aoType set to GTAO.
|
||||
/**
|
||||
* Screen Space Cone Tracing (SSCT) options
|
||||
* Ambient shadows from dominant light
|
||||
@@ -402,6 +414,16 @@ struct AmbientOcclusionOptions {
|
||||
bool enabled = false; //!< enables or disables SSCT
|
||||
};
|
||||
Ssct ssct; // %codegen_skip_javascript% %codegen_java_flatten%
|
||||
|
||||
/**
|
||||
* Ground Truth-base Ambient Occlusion (GTAO) options
|
||||
*/
|
||||
struct Gtao {
|
||||
uint8_t sampleSliceCount = 4; //!< # of slices. Higher value makes less noise.
|
||||
uint8_t sampleStepsPerSlice = 3; //!< # of steps the radius is divided into for integration. Higher value makes less bias.
|
||||
float thicknessHeuristic = 0.004f; //!< thickness heuristic, should be closed to 0
|
||||
};
|
||||
Gtao gtao; // %codegen_skip_javascript% %codegen_java_flatten%
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -221,7 +221,7 @@ public:
|
||||
* index \p bufferIndex. BufferDescriptor points to raw, untyped data that will
|
||||
* be copied as-is into the buffer.
|
||||
* @param byteOffset Offset in *bytes* into the buffer at index \p bufferIndex of this vertex
|
||||
* buffer set.
|
||||
* buffer set. Must be multiple of 4.
|
||||
*/
|
||||
void setBufferAt(Engine& engine, uint8_t bufferIndex, BufferDescriptor&& buffer,
|
||||
uint32_t byteOffset = 0);
|
||||
|
||||
@@ -20,12 +20,13 @@
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/ostream.h>
|
||||
#include <utils/Systrace.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
@@ -90,8 +91,8 @@ void FrameInfoManager::beginFrame(DriverApi& driver, Config const& config, uint3
|
||||
mLast = (mLast + 1) % POOL_COUNT;
|
||||
break;
|
||||
case TimerQueryResult::AVAILABLE: {
|
||||
SYSTRACE_CONTEXT();
|
||||
SYSTRACE_VALUE32("FrameInfo::elapsed", uint32_t(elapsed));
|
||||
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "FrameInfo::elapsed", uint32_t(elapsed));
|
||||
// conversion to our duration happens here
|
||||
pFront = mQueries[mLast].pInfo;
|
||||
pFront->frameTime = std::chrono::duration<uint64_t, std::nano>(elapsed);
|
||||
|
||||
@@ -30,11 +30,12 @@
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
#include <utils/BinaryTreeArray.h>
|
||||
#include <utils/JobSystem.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Slice.h>
|
||||
#include <utils/Systrace.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
|
||||
@@ -296,7 +297,7 @@ void Froxelizer::updateBoundingSpheres(
|
||||
float4 const* UTILS_RESTRICT planesY,
|
||||
float const* UTILS_RESTRICT planesZ) noexcept {
|
||||
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
// TODO: this could potentially be parallel_for'ized
|
||||
|
||||
@@ -579,7 +580,7 @@ void Froxelizer::froxelizeLights(FEngine& engine,
|
||||
void Froxelizer::froxelizeLoop(FEngine& engine,
|
||||
const mat4f& UTILS_RESTRICT viewMatrix,
|
||||
const FScene::LightSoa& UTILS_RESTRICT lightData) noexcept {
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
Slice<FroxelThreadData> froxelThreadData = mFroxelShardedData;
|
||||
memset(froxelThreadData.data(), 0, froxelThreadData.sizeInBytes());
|
||||
@@ -593,7 +594,7 @@ void Froxelizer::froxelizeLoop(FEngine& engine,
|
||||
spheres, directions, instances, &viewMatrix, &lcm ]
|
||||
(size_t const count, size_t const offset, size_t const stride) {
|
||||
|
||||
SYSTRACE_NAME("FroxelizeLoop Job");
|
||||
FILAMENT_TRACING_NAME(FILAMENT_TRACING_CATEGORY_FILAMENT, "FroxelizeLoop Job");
|
||||
|
||||
const mat4f& projection = mProjection;
|
||||
const mat3f& vn = viewMatrix.upperLeft();
|
||||
@@ -646,8 +647,7 @@ void Froxelizer::froxelizeLoop(FEngine& engine,
|
||||
}
|
||||
|
||||
void Froxelizer::froxelizeAssignRecordsCompress() noexcept {
|
||||
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
Slice<FroxelThreadData> const froxelThreadData = mFroxelShardedData;
|
||||
|
||||
|
||||
@@ -398,4 +398,8 @@ bool MaterialInstance::isDepthCullingEnabled() const noexcept {
|
||||
return downcast(this)->isDepthCullingEnabled();
|
||||
}
|
||||
|
||||
void MaterialInstance::commit(Engine& engine) const {
|
||||
downcast(this)->commit(downcast(engine));
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -100,7 +100,9 @@ using namespace backend;
|
||||
static constexpr uint8_t kMaxBloomLevels = 12u;
|
||||
static_assert(kMaxBloomLevels >= 3, "We require at least 3 bloom levels");
|
||||
|
||||
constexpr static float halton(unsigned int i, unsigned int const b) noexcept {
|
||||
namespace {
|
||||
|
||||
constexpr float halton(unsigned int i, unsigned int const b) noexcept {
|
||||
// skipping a bunch of entries makes the average of the sequence closer to 0.5
|
||||
i += 409;
|
||||
float f = 1.0f;
|
||||
@@ -113,6 +115,19 @@ constexpr static float halton(unsigned int i, unsigned int const b) noexcept {
|
||||
return r;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void setConstantParameter(FMaterial* const material, std::string_view const name,
|
||||
ValueType value, bool& dirty) noexcept {
|
||||
auto id = material->getSpecializationConstantId(name);
|
||||
if (id.has_value()) {
|
||||
if (material->setConstant(id.value(), value)) {
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
PostProcessManager::PostProcessMaterial::PostProcessMaterial(StaticMaterialInfo const& info) noexcept
|
||||
@@ -232,7 +247,7 @@ PostProcessManager::~PostProcessManager() noexcept = default;
|
||||
void PostProcessManager::setFrameUniforms(DriverApi& driver,
|
||||
TypedUniformBuffer<PerViewUib>& uniforms) noexcept {
|
||||
mPostProcessDescriptorSet.setFrameUniforms(driver, uniforms);
|
||||
mSsrPassDescriptorSet.setFrameUniforms(uniforms);
|
||||
mSsrPassDescriptorSet.setFrameUniforms(mEngine, uniforms);
|
||||
}
|
||||
|
||||
void PostProcessManager::bindPostProcessDescriptorSet(DriverApi& driver) const noexcept {
|
||||
@@ -289,6 +304,8 @@ static const PostProcessManager::StaticMaterialInfo sMaterialList[] = {
|
||||
{ "mipmapDepth", MATERIAL(MIPMAPDEPTH) },
|
||||
{ "sao", MATERIAL(SAO) },
|
||||
{ "saoBentNormals", MATERIAL(SAOBENTNORMALS) },
|
||||
{ "gtao", MATERIAL(GTAO) },
|
||||
{ "gtaoBentNormals", MATERIAL(GTAOBENTNORMALS) },
|
||||
{ "separableGaussianBlur1", MATERIAL(SEPARABLEGAUSSIANBLUR),
|
||||
{ {"arraySampler", false}, {"componentCount", 1} } },
|
||||
{ "separableGaussianBlur1L", MATERIAL(SEPARABLEGAUSSIANBLUR),
|
||||
@@ -504,6 +521,7 @@ PostProcessManager::StructurePassOutput PostProcessManager::structure(FrameGraph
|
||||
FrameGraphTexture::Usage::DEPTH_ATTACHMENT);
|
||||
|
||||
if (config.picking) {
|
||||
// FIXME: the DescriptorSetLayout must specify SAMPLER_FLOAT
|
||||
data.picking = builder.createTexture("Picking Buffer", {
|
||||
.width = width, .height = height,
|
||||
.format = isES2 ? TextureFormat::RGBA8 : TextureFormat::RG32F });
|
||||
@@ -653,7 +671,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::ssr(FrameGraph& fg,
|
||||
options, passBuilder = passBuilder]
|
||||
(FrameGraphResources const& resources, auto const& data, DriverApi& driver) mutable {
|
||||
// set structure sampler
|
||||
mSsrPassDescriptorSet.prepareStructure(data.structure ?
|
||||
mSsrPassDescriptorSet.prepareStructure(mEngine, data.structure ?
|
||||
resources.getTexture(data.structure) : getOneTexture());
|
||||
|
||||
// set screen-space reflections and screen-space refractions
|
||||
@@ -664,7 +682,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::ssr(FrameGraph& fg,
|
||||
// the history sampler is a regular texture2D
|
||||
TextureHandle const history = data.history ?
|
||||
resources.getTexture(data.history) : getZeroTexture();
|
||||
mSsrPassDescriptorSet.prepareHistorySSR(history, reprojection, uvFromViewMatrix, options);
|
||||
mSsrPassDescriptorSet.prepareHistorySSR(mEngine, history, reprojection, uvFromViewMatrix, options);
|
||||
|
||||
mSsrPassDescriptorSet.commit(mEngine);
|
||||
|
||||
@@ -845,12 +863,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::screenSpaceAmbientOcclusion(
|
||||
0.5f * cameraInfo.projection[0].x * desc.width,
|
||||
0.5f * cameraInfo.projection[1].y * desc.height);
|
||||
|
||||
// Where the falloff function peaks
|
||||
const float peak = 0.1f * options.radius;
|
||||
const float intensity = (f::TAU * peak) * options.intensity;
|
||||
// always square AO result, as it looks much better
|
||||
const float power = options.power * 2.0f;
|
||||
|
||||
const auto invProjection = inverse(cameraInfo.projection);
|
||||
const float inc = (1.0f / (sampleCount - 0.5f)) * spiralTurns * f::TAU;
|
||||
|
||||
@@ -861,40 +873,75 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::screenSpaceAmbientOcclusion(
|
||||
0.0, 0.0, 0.0, 1.0
|
||||
}};
|
||||
|
||||
auto& material = computeBentNormals ?
|
||||
getPostProcessMaterial("saoBentNormals") :
|
||||
getPostProcessMaterial("sao");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
std::string_view materialName;
|
||||
if (options.aoType ==
|
||||
AmbientOcclusionOptions::AmbientOcclusionType::GTAO) {
|
||||
materialName = computeBentNormals ? "gtaoBentNormals" : "gtao";
|
||||
} else {
|
||||
materialName = computeBentNormals ? "saoBentNormals" : "sao";
|
||||
}
|
||||
|
||||
auto& material = getPostProcessMaterial(materialName);
|
||||
|
||||
FMaterial const * const ma = material.getMaterial(mEngine);
|
||||
FMaterialInstance* const mi = PostProcessMaterial::getMaterialInstance(ma);
|
||||
mi->setParameter("depth", depth, {
|
||||
.filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
|
||||
|
||||
// Set AO type specific material parameters
|
||||
switch (options.aoType) {
|
||||
case AmbientOcclusionOptions::AmbientOcclusionType::SAO: {
|
||||
// Where the falloff function peaks
|
||||
const float peak = 0.1f * options.radius;
|
||||
const float intensity = (f::TAU * peak) * options.intensity;
|
||||
|
||||
// always square AO result, as it looks much better
|
||||
const float power = options.power * 2.0f;
|
||||
|
||||
mi->setParameter("minHorizonAngleSineSquared",
|
||||
std::pow(std::sin(options.minHorizonAngleRad), 2.0f));
|
||||
mi->setParameter("intensity", intensity / sampleCount);
|
||||
mi->setParameter("power", power);
|
||||
mi->setParameter("peak2", peak * peak);
|
||||
mi->setParameter("bias", options.bias);
|
||||
mi->setParameter("sampleCount",
|
||||
float2{ sampleCount, 1.0f / (sampleCount - 0.5f) });
|
||||
mi->setParameter("spiralTurns", spiralTurns);
|
||||
mi->setParameter("angleIncCosSin", float2{ std::cos(inc), std::sin(inc) });
|
||||
break;
|
||||
}
|
||||
case AmbientOcclusionOptions::AmbientOcclusionType::GTAO: {
|
||||
const auto sliceCount = static_cast<float>(options.gtao.sampleSliceCount);
|
||||
mi->setParameter("stepsPerSlice",
|
||||
static_cast<float>(options.gtao.sampleStepsPerSlice));
|
||||
mi->setParameter("sliceCount",
|
||||
float2{ sliceCount, 1.0f / sliceCount });
|
||||
mi->setParameter("power", options.power);
|
||||
mi->setParameter("radius", options.radius);
|
||||
mi->setParameter("intensity", options.intensity);
|
||||
mi->setParameter("thicknessHeuristic", options.gtao.thicknessHeuristic);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Set common material parameters
|
||||
mi->setParameter("invRadiusSquared", 1.0f / (options.radius * options.radius));
|
||||
mi->setParameter("depth", depth,
|
||||
{ .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
|
||||
mi->setParameter("screenFromViewMatrix",
|
||||
mat4f(screenFromClipMatrix * cameraInfo.projection));
|
||||
mi->setParameter("resolution",
|
||||
float4{ desc.width, desc.height, 1.0f / desc.width, 1.0f / desc.height });
|
||||
mi->setParameter("invRadiusSquared",
|
||||
1.0f / (options.radius * options.radius));
|
||||
mi->setParameter("minHorizonAngleSineSquared",
|
||||
std::pow(std::sin(options.minHorizonAngleRad), 2.0f));
|
||||
mi->setParameter("projectionScale",
|
||||
projectionScale);
|
||||
mi->setParameter("projectionScaleRadius",
|
||||
projectionScale * options.radius);
|
||||
mi->setParameter("positionParams", float2{
|
||||
invProjection[0][0], invProjection[1][1] } * 2.0f);
|
||||
mi->setParameter("peak2", peak * peak);
|
||||
mi->setParameter("bias", options.bias);
|
||||
mi->setParameter("power", power);
|
||||
mi->setParameter("intensity", intensity / sampleCount);
|
||||
mi->setParameter("projectionScale", projectionScale);
|
||||
mi->setParameter("projectionScaleRadius", projectionScale * options.radius);
|
||||
mi->setParameter("positionParams",
|
||||
float2{ invProjection[0][0], invProjection[1][1] } * 2.0f);
|
||||
mi->setParameter("maxLevel", uint32_t(levelCount - 1));
|
||||
mi->setParameter("sampleCount", float2{ sampleCount, 1.0f / (sampleCount - 0.5f) });
|
||||
mi->setParameter("spiralTurns", spiralTurns);
|
||||
mi->setParameter("angleIncCosSin", float2{ std::cos(inc), std::sin(inc) });
|
||||
mi->setParameter("invFarPlane", 1.0f / -cameraInfo.zf);
|
||||
|
||||
mi->setParameter("ssctShadowDistance", options.ssct.shadowDistance);
|
||||
mi->setParameter("ssctConeAngleTangeant", std::tan(options.ssct.lightConeRad * 0.5f));
|
||||
mi->setParameter("ssctContactDistanceMaxInv", 1.0f / options.ssct.contactDistanceMax);
|
||||
mi->setParameter("ssctConeAngleTangeant",
|
||||
std::tan(options.ssct.lightConeRad * 0.5f));
|
||||
mi->setParameter("ssctContactDistanceMaxInv",
|
||||
1.0f / options.ssct.contactDistanceMax);
|
||||
// light direction in view space
|
||||
const mat4f view{ cameraInfo.getUserViewMatrix() };
|
||||
const float3 l = normalize(
|
||||
@@ -2631,25 +2678,15 @@ void PostProcessManager::configureTemporalAntiAliasingMaterial(
|
||||
FMaterial* const ma = getPostProcessMaterial("taa").getMaterial(mEngine);
|
||||
bool dirty = false;
|
||||
|
||||
auto setConstantParameter =
|
||||
[&dirty](FMaterial* const material, std::string_view const name, auto value) noexcept {
|
||||
auto id = material->getSpecializationConstantId(name);
|
||||
if (id.has_value()) {
|
||||
if (material->setConstant(id.value(), value)) {
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
setConstantParameter(ma, "upscaling", taaOptions.upscaling);
|
||||
setConstantParameter(ma, "historyReprojection", taaOptions.historyReprojection);
|
||||
setConstantParameter(ma, "filterHistory", taaOptions.filterHistory);
|
||||
setConstantParameter(ma, "filterInput", taaOptions.filterInput);
|
||||
setConstantParameter(ma, "useYCoCg", taaOptions.useYCoCg);
|
||||
setConstantParameter(ma, "preventFlickering", taaOptions.preventFlickering);
|
||||
setConstantParameter(ma, "boxType", int32_t(taaOptions.boxType));
|
||||
setConstantParameter(ma, "boxClipping", int32_t(taaOptions.boxClipping));
|
||||
setConstantParameter(ma, "varianceGamma", taaOptions.varianceGamma);
|
||||
setConstantParameter(ma, "upscaling", taaOptions.upscaling, dirty);
|
||||
setConstantParameter(ma, "historyReprojection", taaOptions.historyReprojection, dirty);
|
||||
setConstantParameter(ma, "filterHistory", taaOptions.filterHistory, dirty);
|
||||
setConstantParameter(ma, "filterInput", taaOptions.filterInput, dirty);
|
||||
setConstantParameter(ma, "useYCoCg", taaOptions.useYCoCg, dirty);
|
||||
setConstantParameter(ma, "preventFlickering", taaOptions.preventFlickering, dirty);
|
||||
setConstantParameter(ma, "boxType", int32_t(taaOptions.boxType), dirty);
|
||||
setConstantParameter(ma, "boxClipping", int32_t(taaOptions.boxClipping), dirty);
|
||||
setConstantParameter(ma, "varianceGamma", taaOptions.varianceGamma, dirty);
|
||||
if (dirty) {
|
||||
ma->invalidate();
|
||||
// TODO: call Material::compile(), we can't do that now because it works only
|
||||
@@ -2664,18 +2701,8 @@ FMaterialInstance* PostProcessManager::configureColorGradingMaterial(
|
||||
FMaterial* const ma = material.getMaterial(mEngine);
|
||||
bool dirty = false;
|
||||
|
||||
auto setConstantParameter =
|
||||
[&dirty](FMaterial* const material, std::string_view const name, auto value) noexcept {
|
||||
auto id = material->getSpecializationConstantId(name);
|
||||
if (id.has_value()) {
|
||||
if (material->setConstant(id.value(), value)) {
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
setConstantParameter(ma, "isOneDimensional", colorGrading->isOneDimensional());
|
||||
setConstantParameter(ma, "isLDR", colorGrading->isLDR());
|
||||
setConstantParameter(ma, "isOneDimensional", colorGrading->isOneDimensional(), dirty);
|
||||
setConstantParameter(ma, "isLDR", colorGrading->isLDR(), dirty);
|
||||
|
||||
if (dirty) {
|
||||
ma->invalidate();
|
||||
|
||||
@@ -40,12 +40,13 @@
|
||||
#include "private/backend/CircularBuffer.h"
|
||||
#include "private/backend/CommandStream.h"
|
||||
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/JobSystem.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/Slice.h>
|
||||
#include <utils/Systrace.h>
|
||||
#include <utils/Range.h>
|
||||
|
||||
#include <algorithm>
|
||||
@@ -192,11 +193,11 @@ void RenderPass::appendCommands(FEngine const& engine,
|
||||
Variant const variant,
|
||||
float3 const cameraPosition,
|
||||
float3 const cameraForwardVector) const noexcept {
|
||||
SYSTRACE_CALL();
|
||||
SYSTRACE_CONTEXT();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
// trace the number of visible renderables
|
||||
SYSTRACE_VALUE32("visibleRenderables", visibleRenderables.size());
|
||||
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "visibleRenderables", visibleRenderables.size());
|
||||
if (UTILS_UNLIKELY(visibleRenderables.empty())) {
|
||||
// no renderables, we still need the sentinel and the command buffer size should be
|
||||
// exactly 1.
|
||||
@@ -272,7 +273,7 @@ void RenderPass::appendCustomCommand(Command* commands,
|
||||
|
||||
RenderPass::Command* RenderPass::sortCommands(
|
||||
Command* const begin, Command* const end) noexcept {
|
||||
SYSTRACE_NAME("sort commands");
|
||||
FILAMENT_TRACING_NAME(FILAMENT_TRACING_CATEGORY_FILAMENT, "sort commands");
|
||||
|
||||
std::sort(begin, end);
|
||||
|
||||
@@ -289,7 +290,7 @@ RenderPass::Command* RenderPass::instanceify(DriverApi& driver,
|
||||
DescriptorSetLayoutHandle perRenderableDescriptorSetLayoutHandle,
|
||||
Command* curr, Command* const last,
|
||||
int32_t const eyeCount) const noexcept {
|
||||
SYSTRACE_NAME("instanceify");
|
||||
FILAMENT_TRACING_NAME(FILAMENT_TRACING_CATEGORY_FILAMENT, "instanceify");
|
||||
|
||||
// instanceify works by scanning the **sorted** command stream, looking for repeat draw
|
||||
// commands. When one is found, it is replaced by an instanced command.
|
||||
@@ -492,7 +493,7 @@ void RenderPass::generateCommands(CommandTypeFlags commandTypeFlags, Command* co
|
||||
float3 const cameraPosition, float3 const cameraForward,
|
||||
uint8_t instancedStereoEyeCount) noexcept {
|
||||
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
// generateCommands() writes both the draw and depth commands simultaneously such that
|
||||
// we go throw the list of renderables just once.
|
||||
@@ -922,14 +923,14 @@ UTILS_NOINLINE // no need to be inlined
|
||||
void RenderPass::Executor::execute(FEngine const& engine, DriverApi& driver,
|
||||
Command const* first, Command const* last) const noexcept {
|
||||
|
||||
SYSTRACE_CALL();
|
||||
SYSTRACE_CONTEXT();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
FILAMENT_TRACING_CONTEXT(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
size_t const capacity = engine.getMinCommandBufferSize();
|
||||
CircularBuffer const& circularBuffer = driver.getCircularBuffer();
|
||||
|
||||
if (first != last) {
|
||||
SYSTRACE_VALUE32("commandCount", last - first);
|
||||
FILAMENT_TRACING_VALUE(FILAMENT_TRACING_CATEGORY_FILAMENT, "commandCount", last - first);
|
||||
|
||||
// The scissor rectangle is associated to a render pass, so the tracking can be local.
|
||||
backend::Viewport currentScissor{ 0, 0, INT32_MAX, INT32_MAX };
|
||||
@@ -942,6 +943,13 @@ void RenderPass::Executor::execute(FEngine const& engine, DriverApi& driver,
|
||||
driver.scissor(mScissor);
|
||||
}
|
||||
|
||||
// If we have a mColorPassDescriptorSet, we need to use its idea of "VSM" to select
|
||||
// the descriptor set layout. Materials always offer both.
|
||||
// If we don't have a mColorPassDescriptorSet, it doesn't matter because the layout
|
||||
// are chosen via the variant only.
|
||||
bool const useVsmDescriptorSetLayout =
|
||||
mColorPassDescriptorSet ? mColorPassDescriptorSet->isVSM() : false;
|
||||
|
||||
bool const polygonOffsetOverride = mPolygonOffsetOverride;
|
||||
PipelineState pipeline{
|
||||
// initialize with polygon offset override
|
||||
@@ -1051,8 +1059,13 @@ void RenderPass::Executor::execute(FEngine const& engine, DriverApi& driver,
|
||||
|
||||
// Each material has its own version of the per-view descriptor-set layout,
|
||||
// because it depends on the material features (e.g. lit/unlit)
|
||||
// TODO: QUESTION: are
|
||||
// Variant::isValidDepthVariant(info.materialVariant) and
|
||||
// Variant::isSSRVariant(info.materialVariant)
|
||||
// constant? If so we could precompute ma->getPerViewDescriptorSetLayout()
|
||||
pipeline.pipelineLayout.setLayout[+DescriptorSetBindingPoints::PER_VIEW] =
|
||||
ma->getPerViewDescriptorSetLayout(info.materialVariant).getHandle();
|
||||
ma->getPerViewDescriptorSetLayout(info.materialVariant,
|
||||
useVsmDescriptorSetLayout).getHandle();
|
||||
|
||||
// Each material has a per-material descriptor-set layout which encodes the
|
||||
// material's parameters (ubo and samplers)
|
||||
|
||||
@@ -205,11 +205,13 @@ RendererUtils::ColorPassOutput RendererUtils::colorPass(
|
||||
view.prepareSSAO(data.ssao ?
|
||||
resources.getTexture(data.ssao) : engine.getOneTextureArray());
|
||||
|
||||
view.prepareShadowMapping(view.getVsmShadowOptions().highPrecision);
|
||||
view.prepareShadowMapping(engine, view.getVsmShadowOptions().highPrecision);
|
||||
|
||||
// set shadow sampler
|
||||
view.prepareShadow(data.shadows ?
|
||||
resources.getTexture(data.shadows) : engine.getOneTextureArray());
|
||||
resources.getTexture(data.shadows) :
|
||||
(view.getShadowType() != ShadowType::PCF ?
|
||||
engine.getOneTextureArray() : engine.getOneTextureArrayDepth()));
|
||||
|
||||
// set structure sampler
|
||||
view.prepareStructure(data.structure ?
|
||||
|
||||
@@ -29,11 +29,12 @@
|
||||
#include <backend/DriverApiForward.h>
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/debug.h>
|
||||
#include <utils/Entity.h>
|
||||
#include <utils/Slice.h>
|
||||
#include <utils/Systrace.h>
|
||||
|
||||
#include <math/vec3.h>
|
||||
#include <math/vec4.h>
|
||||
@@ -1200,7 +1201,7 @@ float ShadowMap::texelSizeWorldSpace(const mat4f& Wp, const mat4f& MbMtF,
|
||||
template<typename Casters, typename Receivers>
|
||||
void ShadowMap::visitScene(const FScene& scene, uint32_t const visibleLayers,
|
||||
Casters casters, Receivers receivers) noexcept {
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
using State = FRenderableManager::Visibility;
|
||||
FScene::RenderableSoa const& soa = scene.getRenderableData();
|
||||
|
||||
@@ -20,9 +20,19 @@
|
||||
|
||||
#include "FilamentAPI-impl.h"
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <filament/BufferObject.h>
|
||||
|
||||
#include <utils/CString.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/StaticString.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace filament {
|
||||
|
||||
struct BufferObject::BuilderDetails {
|
||||
@@ -78,6 +88,10 @@ void FBufferObject::terminate(FEngine& engine) {
|
||||
}
|
||||
|
||||
void FBufferObject::setBuffer(FEngine& engine, BufferDescriptor&& buffer, uint32_t const byteOffset) {
|
||||
|
||||
FILAMENT_CHECK_PRECONDITION((byteOffset & 0x3) == 0)
|
||||
<< "byteOffset must be a multiple of 4";
|
||||
|
||||
engine.getDriverApi().updateBufferObject(mHandle, std::move(buffer), byteOffset);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,9 +29,10 @@
|
||||
#include <math/vec3.h>
|
||||
#include <math/vec4.h>
|
||||
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
#include <utils/JobSystem.h>
|
||||
#include <utils/Mutex.h>
|
||||
#include <utils/Systrace.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
@@ -656,7 +657,7 @@ struct Config {
|
||||
// we force TSAN off to silence the warning.
|
||||
UTILS_NO_SANITIZE_THREAD
|
||||
FColorGrading::FColorGrading(FEngine& engine, const Builder& builder) {
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
DriverApi& driver = engine.getDriverApi();
|
||||
|
||||
|
||||
@@ -50,6 +50,8 @@
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
|
||||
#include <private/utils/Tracing.h>
|
||||
|
||||
#include <utils/Allocator.h>
|
||||
#include <utils/CallStack.h>
|
||||
#include <utils/compiler.h>
|
||||
@@ -59,7 +61,6 @@
|
||||
#include <utils/ostream.h>
|
||||
#include <utils/Panic.h>
|
||||
#include <utils/PrivateImplementation-impl.h>
|
||||
#include <utils/Systrace.h>
|
||||
#include <utils/ThreadUtils.h>
|
||||
|
||||
#include <math/vec3.h>
|
||||
@@ -105,8 +106,8 @@ struct Engine::BuilderDetails {
|
||||
};
|
||||
|
||||
Engine* FEngine::create(Builder const& builder) {
|
||||
SYSTRACE_ENABLE();
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_ENABLE(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
FEngine* instance = new FEngine(builder);
|
||||
|
||||
@@ -169,8 +170,8 @@ Engine* FEngine::create(Builder const& builder) {
|
||||
#if UTILS_HAS_THREADING
|
||||
|
||||
void FEngine::create(Builder const& builder, Invocable<void(void*)>&& callback) {
|
||||
SYSTRACE_ENABLE();
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_ENABLE(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
FEngine* instance = new FEngine(builder);
|
||||
|
||||
@@ -300,7 +301,7 @@ uint32_t FEngine::getJobSystemThreadPoolSize(Config const& config) noexcept {
|
||||
*/
|
||||
|
||||
void FEngine::init() {
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
// this must be first.
|
||||
assert_invariant( intptr_t(&mDriverApiStorage) % alignof(DriverApi) == 0 );
|
||||
@@ -361,8 +362,6 @@ void FEngine::init() {
|
||||
}
|
||||
|
||||
// initialize the dummy textures so that their contents are not undefined
|
||||
static constexpr uint32_t zeroes[6] = {};
|
||||
static constexpr uint32_t ones = 0xffffffff;
|
||||
|
||||
mDefaultIblTexture = downcast(Texture::Builder()
|
||||
.width(1).height(1).levels(1)
|
||||
@@ -371,7 +370,8 @@ void FEngine::init() {
|
||||
.build(*this));
|
||||
|
||||
driverApi.update3DImage(mDefaultIblTexture->getHwHandle(), 0, 0, 0, 0, 1, 1, 6,
|
||||
{ zeroes, sizeof(zeroes), Texture::Format::RGBA, Texture::Type::UBYTE });
|
||||
{ std::array<uint8_t, 6>{}.data(), 6,
|
||||
Texture::Format::RGBA, Texture::Type::UBYTE });
|
||||
|
||||
// 3 bands = 9 float3
|
||||
constexpr float sh[9 * 3] = { 0.0f };
|
||||
@@ -393,10 +393,12 @@ void FEngine::init() {
|
||||
TextureFormat::RGBA8, 1, 1, 1, 1, TextureUsage::DEFAULT);
|
||||
|
||||
driverApi.update3DImage(mDummyOneTexture, 0, 0, 0, 0, 1, 1, 1,
|
||||
{ &ones, 4, Texture::Format::RGBA, Texture::Type::UBYTE });
|
||||
{ std::array<uint8_t, 4>{0xff, 0xff, 0xff, 0xff}.data(), 4,
|
||||
Texture::Format::RGBA, Texture::Type::UBYTE });
|
||||
|
||||
driverApi.update3DImage(mDummyZeroTexture, 0, 0, 0, 0, 1, 1, 1,
|
||||
{ zeroes, 4, Texture::Format::RGBA, Texture::Type::UBYTE });
|
||||
{ std::array<uint8_t, 4>{}.data(), 4,
|
||||
Texture::Format::RGBA, Texture::Type::UBYTE });
|
||||
|
||||
|
||||
mPerViewDescriptorSetLayoutSsrVariant = {
|
||||
@@ -423,25 +425,28 @@ void FEngine::init() {
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
mDefaultColorGrading = downcast(ColorGrading::Builder().build(*this));
|
||||
|
||||
FMaterial::DefaultMaterialBuilder defaultMaterialBuilder;
|
||||
switch (mConfig.stereoscopicType) {
|
||||
case StereoscopicType::NONE:
|
||||
case StereoscopicType::INSTANCED:
|
||||
defaultMaterialBuilder.package(
|
||||
MATERIALS_DEFAULTMATERIAL_DATA, MATERIALS_DEFAULTMATERIAL_SIZE);
|
||||
MATERIALS_DEFAULTMATERIAL_DATA, MATERIALS_DEFAULTMATERIAL_SIZE);
|
||||
break;
|
||||
case StereoscopicType::MULTIVIEW:
|
||||
#ifdef FILAMENT_ENABLE_MULTIVIEW
|
||||
defaultMaterialBuilder.package(
|
||||
MATERIALS_DEFAULTMATERIAL_MULTIVIEW_DATA, MATERIALS_DEFAULTMATERIAL_MULTIVIEW_SIZE);
|
||||
MATERIALS_DEFAULTMATERIAL_MULTIVIEW_DATA,
|
||||
MATERIALS_DEFAULTMATERIAL_MULTIVIEW_SIZE);
|
||||
#else
|
||||
assert_invariant(false);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
mDefaultMaterial = downcast(defaultMaterialBuilder.build(*this));
|
||||
}
|
||||
|
||||
if (UTILS_UNLIKELY(getSupportedFeatureLevel() >= FeatureLevel::FEATURE_LEVEL_1)) {
|
||||
mDefaultColorGrading = downcast(ColorGrading::Builder().build(*this));
|
||||
|
||||
constexpr float3 dummyPositions[1] = {};
|
||||
constexpr short4 dummyTangents[1] = {};
|
||||
@@ -451,14 +456,26 @@ void FEngine::init() {
|
||||
mDummyOneTextureArray = driverApi.createTexture(SamplerType::SAMPLER_2D_ARRAY, 1,
|
||||
TextureFormat::RGBA8, 1, 1, 1, 1, TextureUsage::DEFAULT);
|
||||
|
||||
mDummyOneTextureArrayDepth = driverApi.createTexture(SamplerType::SAMPLER_2D_ARRAY, 1,
|
||||
TextureFormat::DEPTH32F, 1, 1, 1, 1, TextureUsage::DEFAULT);
|
||||
|
||||
mDummyZeroTextureArray = driverApi.createTexture(SamplerType::SAMPLER_2D_ARRAY, 1,
|
||||
TextureFormat::RGBA8, 1, 1, 1, 1, TextureUsage::DEFAULT);
|
||||
|
||||
driverApi.update3DImage(mDummyOneTextureArray, 0, 0, 0, 0, 1, 1, 1,
|
||||
{ &ones, 4, Texture::Format::RGBA, Texture::Type::UBYTE });
|
||||
{ std::array<uint8_t, 4>{0xff, 0xff, 0xff, 0xff}.data(), 4,
|
||||
Texture::Format::RGBA, Texture::Type::UBYTE });
|
||||
|
||||
driverApi.update3DImage(mDummyOneTextureArrayDepth, 0, 0, 0, 0, 1, 1, 1,
|
||||
{ std::array<float, 1>{1.0f}.data(), 4,
|
||||
Texture::Format::DEPTH_COMPONENT, Texture::Type::FLOAT });
|
||||
|
||||
driverApi.update3DImage(mDummyZeroTextureArray, 0, 0, 0, 0, 1, 1, 1,
|
||||
{ zeroes, 4, Texture::Format::RGBA, Texture::Type::UBYTE });
|
||||
{ std::array<uint8_t, 4>{}.data(), 4,
|
||||
Texture::Format::RGBA, Texture::Type::UBYTE });
|
||||
|
||||
mDummyUniformBuffer = driverApi.createBufferObject(CONFIG_MINSPEC_UBO_SIZE,
|
||||
BufferObjectBinding::UNIFORM, BufferUsage::STATIC);
|
||||
|
||||
mLightManager.init(*this);
|
||||
mDFG.init(*this);
|
||||
@@ -502,7 +519,7 @@ void FEngine::init() {
|
||||
}
|
||||
|
||||
FEngine::~FEngine() noexcept {
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
assert_invariant(!mResourceAllocatorDisposer);
|
||||
delete mDriver;
|
||||
if (mOwnPlatform) {
|
||||
@@ -511,7 +528,7 @@ FEngine::~FEngine() noexcept {
|
||||
}
|
||||
|
||||
void FEngine::shutdown() {
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
|
||||
// by construction this should never be nullptr
|
||||
assert_invariant(mResourceAllocatorDisposer);
|
||||
@@ -608,6 +625,8 @@ void FEngine::shutdown() {
|
||||
driver.destroyTexture(std::move(mDummyZeroTexture));
|
||||
driver.destroyTexture(std::move(mDummyZeroTextureArray));
|
||||
|
||||
driver.destroyBufferObject(std::move(mDummyUniformBuffer));
|
||||
|
||||
driver.destroyRenderTarget(std::move(mDefaultRenderTarget));
|
||||
|
||||
/*
|
||||
@@ -645,7 +664,7 @@ void FEngine::shutdown() {
|
||||
}
|
||||
|
||||
void FEngine::prepare() {
|
||||
SYSTRACE_CALL();
|
||||
FILAMENT_TRACING_CALL(FILAMENT_TRACING_CATEGORY_FILAMENT);
|
||||
// prepare() is called once per Renderer frame. Ideally we would upload the content of
|
||||
// UBOs that are visible only. It's not such a big issue because the actual upload() is
|
||||
// skipped if the UBO hasn't changed. Still we could have a lot of these.
|
||||
@@ -653,8 +672,12 @@ void FEngine::prepare() {
|
||||
|
||||
for (auto& materialInstanceList: mMaterialInstances) {
|
||||
materialInstanceList.second.forEach([&driver](FMaterialInstance* item) {
|
||||
item->commitStreamUniformAssociations(driver);
|
||||
item->commit(driver);
|
||||
// post-process materials instances must be commited explicitly because their
|
||||
// parameters are typically not set at this point in time.
|
||||
if (item->getMaterial()->getMaterialDomain() == MaterialDomain::SURFACE) {
|
||||
item->commitStreamUniformAssociations(driver);
|
||||
item->commit(driver);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -712,8 +735,7 @@ int FEngine::loop() {
|
||||
if (mPlatform == nullptr) {
|
||||
mPlatform = PlatformFactory::create(&mBackend);
|
||||
mOwnPlatform = true;
|
||||
const char* const backend = backendToString(mBackend);
|
||||
slog.i << "FEngine resolved backend: " << backend << io::endl;
|
||||
slog.i << "FEngine resolved backend: " << to_string(mBackend) << io::endl;
|
||||
if (mPlatform == nullptr) {
|
||||
slog.e << "Selected backend not supported in this build." << io::endl;
|
||||
mDriverBarrier.latch();
|
||||
|
||||