update headers to Filament v1.25.0
This commit is contained in:
@@ -33,7 +33,6 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace filament {
|
|
||||||
/**
|
/**
|
||||||
* Types and enums used by filament's driver.
|
* Types and enums used by filament's driver.
|
||||||
*
|
*
|
||||||
@@ -41,24 +40,24 @@ namespace filament {
|
|||||||
* internal redeclaration of these types.
|
* internal redeclaration of these types.
|
||||||
* For e.g. Use Texture::Sampler instead of filament::SamplerType.
|
* For e.g. Use Texture::Sampler instead of filament::SamplerType.
|
||||||
*/
|
*/
|
||||||
namespace backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
static constexpr uint64_t SWAP_CHAIN_CONFIG_TRANSPARENT = 0x1;
|
static constexpr uint64_t SWAP_CHAIN_CONFIG_TRANSPARENT = 0x1;
|
||||||
static constexpr uint64_t SWAP_CHAIN_CONFIG_READABLE = 0x2;
|
static constexpr uint64_t SWAP_CHAIN_CONFIG_READABLE = 0x2;
|
||||||
static constexpr uint64_t SWAP_CHAIN_CONFIG_ENABLE_XCB = 0x4;
|
static constexpr uint64_t SWAP_CHAIN_CONFIG_ENABLE_XCB = 0x4;
|
||||||
static constexpr uint64_t SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER = 0x8;
|
static constexpr uint64_t SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER = 0x8;
|
||||||
|
|
||||||
static constexpr size_t MAX_VERTEX_ATTRIBUTE_COUNT = 16; // This is guaranteed by OpenGL ES.
|
static constexpr size_t MAX_VERTEX_ATTRIBUTE_COUNT = 16; // This is guaranteed by OpenGL ES.
|
||||||
static constexpr size_t MAX_VERTEX_SAMPLER_COUNT = 16; // This is guaranteed by OpenGL ES.
|
static constexpr size_t MAX_VERTEX_SAMPLER_COUNT = 16; // This is guaranteed by OpenGL ES.
|
||||||
static constexpr size_t MAX_FRAGMENT_SAMPLER_COUNT = 16; // This is guaranteed by OpenGL ES.
|
static constexpr size_t MAX_FRAGMENT_SAMPLER_COUNT = 16; // This is guaranteed by OpenGL ES.
|
||||||
static constexpr size_t MAX_SAMPLER_COUNT = 32; // This is guaranteed by OpenGL ES.
|
static constexpr size_t MAX_SAMPLER_COUNT = 32; // This is guaranteed by OpenGL ES.
|
||||||
static constexpr size_t MAX_VERTEX_BUFFER_COUNT = 16; // Max number of bound buffer objects.
|
static constexpr size_t MAX_VERTEX_BUFFER_COUNT = 16; // Max number of bound buffer objects.
|
||||||
|
|
||||||
static_assert(MAX_VERTEX_BUFFER_COUNT <= MAX_VERTEX_ATTRIBUTE_COUNT,
|
static_assert(MAX_VERTEX_BUFFER_COUNT <= MAX_VERTEX_ATTRIBUTE_COUNT,
|
||||||
"The number of buffer objects that can be attached to a VertexBuffer must be "
|
"The number of buffer objects that can be attached to a VertexBuffer must be "
|
||||||
"less than or equal to the maximum number of vertex attributes.");
|
"less than or equal to the maximum number of vertex attributes.");
|
||||||
|
|
||||||
static constexpr size_t CONFIG_BINDING_COUNT = 8;
|
static constexpr size_t CONFIG_BINDING_COUNT = 12; // This is guaranteed by OpenGL ES.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects which driver a particular Engine should use.
|
* Selects which driver a particular Engine should use.
|
||||||
@@ -129,7 +128,6 @@ inline constexpr TargetBufferFlags getTargetBufferFlagsAt(size_t index) noexcept
|
|||||||
enum class BufferUsage : uint8_t {
|
enum class BufferUsage : uint8_t {
|
||||||
STATIC, //!< content modified once, used many times
|
STATIC, //!< content modified once, used many times
|
||||||
DYNAMIC, //!< content modified frequently, used many times
|
DYNAMIC, //!< content modified frequently, used many times
|
||||||
STREAM, //!< content invalidated and modified frequently, used many times
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -142,9 +140,9 @@ struct Viewport {
|
|||||||
uint32_t width; //!< width in pixels
|
uint32_t width; //!< width in pixels
|
||||||
uint32_t height; //!< height in pixels
|
uint32_t height; //!< height in pixels
|
||||||
//! get the right coordinate in window space of the viewport
|
//! get the right coordinate in window space of the viewport
|
||||||
int32_t right() const noexcept { return left + width; }
|
int32_t right() const noexcept { return left + int32_t(width); }
|
||||||
//! get the top coordinate in window space of the viewport
|
//! get the top coordinate in window space of the viewport
|
||||||
int32_t top() const noexcept { return bottom + height; }
|
int32_t top() const noexcept { return bottom + int32_t(height); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -160,7 +158,7 @@ struct DepthRange {
|
|||||||
* @see Fence, Fence::wait()
|
* @see Fence, Fence::wait()
|
||||||
*/
|
*/
|
||||||
enum class FenceStatus : int8_t {
|
enum class FenceStatus : int8_t {
|
||||||
ERROR = -1, //!< An error occured. The Fence condition is not satisfied.
|
ERROR = -1, //!< An error occurred. The Fence condition is not satisfied.
|
||||||
CONDITION_SATISFIED = 0, //!< The Fence condition is satisfied.
|
CONDITION_SATISFIED = 0, //!< The Fence condition is satisfied.
|
||||||
TIMEOUT_EXPIRED = 1, //!< wait()'s timeout expired. The Fence condition is not satisfied.
|
TIMEOUT_EXPIRED = 1, //!< wait()'s timeout expired. The Fence condition is not satisfied.
|
||||||
};
|
};
|
||||||
@@ -169,7 +167,7 @@ enum class FenceStatus : int8_t {
|
|||||||
* Status codes for sync objects
|
* Status codes for sync objects
|
||||||
*/
|
*/
|
||||||
enum class SyncStatus : int8_t {
|
enum class SyncStatus : int8_t {
|
||||||
ERROR = -1, //!< An error occured. The Sync is not signaled.
|
ERROR = -1, //!< An error occurred. The Sync is not signaled.
|
||||||
SIGNALED = 0, //!< The Sync is signaled.
|
SIGNALED = 0, //!< The Sync is signaled.
|
||||||
NOT_SIGNALED = 1, //!< The Sync is not signaled yet
|
NOT_SIGNALED = 1, //!< The Sync is not signaled yet
|
||||||
};
|
};
|
||||||
@@ -720,7 +718,7 @@ enum class SamplerCompareMode : uint8_t {
|
|||||||
COMPARE_TO_TEXTURE = 1
|
COMPARE_TO_TEXTURE = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
//! comparison function for the depth sampler
|
//! comparison function for the depth / stencil sampler
|
||||||
enum class SamplerCompareFunc : uint8_t {
|
enum class SamplerCompareFunc : uint8_t {
|
||||||
// don't change the enums values
|
// don't change the enums values
|
||||||
LE = 0, //!< Less or equal
|
LE = 0, //!< Less or equal
|
||||||
@@ -729,11 +727,11 @@ enum class SamplerCompareFunc : uint8_t {
|
|||||||
G, //!< Strictly greater than
|
G, //!< Strictly greater than
|
||||||
E, //!< Equal
|
E, //!< Equal
|
||||||
NE, //!< Not equal
|
NE, //!< Not equal
|
||||||
A, //!< Always. Depth testing is deactivated.
|
A, //!< Always. Depth / stencil testing is deactivated.
|
||||||
N //!< Never. The depth test always fails.
|
N //!< Never. The depth / stencil test always fails.
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Sampler paramters
|
//! Sampler parameters
|
||||||
struct SamplerParams { // NOLINT
|
struct SamplerParams { // NOLINT
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
@@ -786,10 +784,21 @@ enum class BlendFunction : uint8_t {
|
|||||||
SRC_ALPHA_SATURATE //!< f(src, dst) = (1,1,1) * min(src.a, 1 - dst.a), 1
|
SRC_ALPHA_SATURATE //!< f(src, dst) = (1,1,1) * min(src.a, 1 - dst.a), 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! stencil operation
|
||||||
|
enum class StencilOperation : uint8_t {
|
||||||
|
KEEP, //!< Keeps the current value.
|
||||||
|
ZERO, //!< Sets the value to 0.
|
||||||
|
REPLACE, //!< Sets the value to the stencil reference value.
|
||||||
|
INCR, //!< Increments the current value. Clamps to the maximum representable unsigned value.
|
||||||
|
INCR_WRAP, //!< Increments the current value. Wraps value to zero when incrementing the maximum representable unsigned value.
|
||||||
|
DECR, //!< Decrements the current value. Clamps to 0.
|
||||||
|
DECR_WRAP, //!< Decrements the current value. Wraps value to the maximum representable unsigned value when decrementing a value of zero.
|
||||||
|
INVERT, //!< Bitwise inverts the current value.
|
||||||
|
};
|
||||||
|
|
||||||
//! Stream for external textures
|
//! Stream for external textures
|
||||||
enum class StreamType {
|
enum class StreamType {
|
||||||
NATIVE, //!< Not synchronized but copy-free. Good for video.
|
NATIVE, //!< Not synchronized but copy-free. Good for video.
|
||||||
TEXTURE_ID, //!< Synchronized, but GL-only and incurs copies. Good for AR on devices before API 26.
|
|
||||||
ACQUIRED, //!< Synchronized, copy-free, and take a release callback. Good for AR but requires API 26+.
|
ACQUIRED, //!< Synchronized, copy-free, and take a release callback. Good for AR but requires API 26+.
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -819,9 +828,11 @@ struct RasterState {
|
|||||||
using DepthFunc = backend::SamplerCompareFunc;
|
using DepthFunc = backend::SamplerCompareFunc;
|
||||||
using BlendEquation = backend::BlendEquation;
|
using BlendEquation = backend::BlendEquation;
|
||||||
using BlendFunction = backend::BlendFunction;
|
using BlendFunction = backend::BlendFunction;
|
||||||
|
using StencilFunction = backend::SamplerCompareFunc;
|
||||||
|
using StencilOperation = backend::StencilOperation;
|
||||||
|
|
||||||
RasterState() noexcept { // NOLINT
|
RasterState() noexcept { // NOLINT
|
||||||
static_assert(sizeof(RasterState) == sizeof(uint32_t),
|
static_assert(sizeof(RasterState) == sizeof(uint64_t),
|
||||||
"RasterState size not what was intended");
|
"RasterState size not what was intended");
|
||||||
culling = CullingMode::BACK;
|
culling = CullingMode::BACK;
|
||||||
blendEquationRGB = BlendEquation::ADD;
|
blendEquationRGB = BlendEquation::ADD;
|
||||||
@@ -830,6 +841,10 @@ struct RasterState {
|
|||||||
blendFunctionSrcAlpha = BlendFunction::ONE;
|
blendFunctionSrcAlpha = BlendFunction::ONE;
|
||||||
blendFunctionDstRGB = BlendFunction::ZERO;
|
blendFunctionDstRGB = BlendFunction::ZERO;
|
||||||
blendFunctionDstAlpha = BlendFunction::ZERO;
|
blendFunctionDstAlpha = BlendFunction::ZERO;
|
||||||
|
stencilFunc = StencilFunction::A;
|
||||||
|
stencilOpStencilFail = StencilOperation::KEEP;
|
||||||
|
stencilOpDepthFail = StencilOperation::KEEP;
|
||||||
|
stencilOpDepthStencilPass = StencilOperation::KEEP;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator == (RasterState rhs) const noexcept { return u == rhs.u; }
|
bool operator == (RasterState rhs) const noexcept { return u == rhs.u; }
|
||||||
@@ -858,40 +873,56 @@ struct RasterState {
|
|||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
//! culling mode
|
//! culling mode
|
||||||
CullingMode culling : 2; // 2
|
CullingMode culling : 2; // 2
|
||||||
|
|
||||||
//! blend equation for the red, green and blue components
|
//! blend equation for the red, green and blue components
|
||||||
BlendEquation blendEquationRGB : 3; // 5
|
BlendEquation blendEquationRGB : 3; // 5
|
||||||
//! blend equation for the alpha component
|
//! blend equation for the alpha component
|
||||||
BlendEquation blendEquationAlpha : 3; // 8
|
BlendEquation blendEquationAlpha : 3; // 8
|
||||||
|
|
||||||
//! blending function for the source color
|
//! blending function for the source color
|
||||||
BlendFunction blendFunctionSrcRGB : 4; // 12
|
BlendFunction blendFunctionSrcRGB : 4; // 12
|
||||||
//! blending function for the source alpha
|
//! blending function for the source alpha
|
||||||
BlendFunction blendFunctionSrcAlpha : 4; // 16
|
BlendFunction blendFunctionSrcAlpha : 4; // 16
|
||||||
//! blending function for the destination color
|
//! blending function for the destination color
|
||||||
BlendFunction blendFunctionDstRGB : 4; // 20
|
BlendFunction blendFunctionDstRGB : 4; // 20
|
||||||
//! blending function for the destination alpha
|
//! blending function for the destination alpha
|
||||||
BlendFunction blendFunctionDstAlpha : 4; // 24
|
BlendFunction blendFunctionDstAlpha : 4; // 24
|
||||||
|
|
||||||
//! Whether depth-buffer writes are enabled
|
//! Whether depth-buffer writes are enabled
|
||||||
bool depthWrite : 1; // 25
|
bool depthWrite : 1; // 25
|
||||||
//! Depth test function
|
//! Depth test function
|
||||||
DepthFunc depthFunc : 3; // 28
|
DepthFunc depthFunc : 3; // 28
|
||||||
|
|
||||||
//! Whether color-buffer writes are enabled
|
//! Whether color-buffer writes are enabled
|
||||||
bool colorWrite : 1; // 29
|
bool colorWrite : 1; // 29
|
||||||
|
|
||||||
//! use alpha-channel as coverage mask for anti-aliasing
|
//! use alpha-channel as coverage mask for anti-aliasing
|
||||||
bool alphaToCoverage : 1; // 30
|
bool alphaToCoverage : 1; // 30
|
||||||
|
|
||||||
//! whether front face winding direction must be inverted
|
//! whether front face winding direction must be inverted
|
||||||
bool inverseFrontFaces : 1; // 31
|
bool inverseFrontFaces : 1; // 31
|
||||||
|
|
||||||
|
//! Whether stencil-buffer writes are enabled
|
||||||
|
bool stencilWrite : 1; // 32
|
||||||
|
//! Stencil reference value
|
||||||
|
uint8_t stencilRef : 8; // 40
|
||||||
|
//! Stencil test function
|
||||||
|
StencilFunction stencilFunc : 3; // 43
|
||||||
|
//! Stencil operation when stencil test fails
|
||||||
|
StencilOperation stencilOpStencilFail : 3; // 46
|
||||||
//! padding, must be 0
|
//! padding, must be 0
|
||||||
uint8_t padding : 1; // 32
|
uint8_t padding0 : 2; // 48
|
||||||
|
//! Stencil operation when stencil test passes but depth test fails
|
||||||
|
StencilOperation stencilOpDepthFail : 3; // 51
|
||||||
|
//! Stencil operation when both stencil and depth test pass
|
||||||
|
StencilOperation stencilOpDepthStencilPass : 3; // 54
|
||||||
|
//! padding, must be 0
|
||||||
|
uint8_t padding1 : 2; // 56
|
||||||
|
//! padding, must be 0
|
||||||
|
uint8_t padding2 : 8; // 64
|
||||||
};
|
};
|
||||||
uint32_t u = 0;
|
uint64_t u = 0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -914,7 +945,7 @@ struct ShaderStageFlags {
|
|||||||
(fragment && type == ShaderType::FRAGMENT);
|
(fragment && type == ShaderType::FRAGMENT);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
static constexpr ShaderStageFlags ALL_SHADER_STAGE_FLAGS = { .vertex = true, .fragment = true };
|
static constexpr ShaderStageFlags ALL_SHADER_STAGE_FLAGS = { true, true };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects which buffers to clear at the beginning of the render pass, as well as which buffers
|
* Selects which buffers to clear at the beginning of the render pass, as well as which buffers
|
||||||
@@ -998,8 +1029,7 @@ enum class Workaround : uint16_t {
|
|||||||
ALLOW_READ_ONLY_ANCILLARY_FEEDBACK_LOOP
|
ALLOW_READ_ONLY_ANCILLARY_FEEDBACK_LOOP
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace backend
|
} // namespace filament::backend
|
||||||
} // namespace filament
|
|
||||||
|
|
||||||
template<> struct utils::EnableBitMaskOperators<filament::backend::TargetBufferFlags>
|
template<> struct utils::EnableBitMaskOperators<filament::backend::TargetBufferFlags>
|
||||||
: public std::true_type {};
|
: public std::true_type {};
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace filament::backend {
|
namespace filament::backend {
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ public:
|
|||||||
* underlying platform is returned and \p backendHint is updated
|
* underlying platform is returned and \p backendHint is updated
|
||||||
* accordingly. Can't be nullptr.
|
* accordingly. Can't be nullptr.
|
||||||
*
|
*
|
||||||
* @return A pointer to the Plaform object.
|
* @return A pointer to the Platform object.
|
||||||
*
|
*
|
||||||
* @see destroy
|
* @see destroy
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -388,6 +388,9 @@ public:
|
|||||||
//! Enable / disable depth based culling (enabled by default, material instances can override).
|
//! Enable / disable depth based culling (enabled by default, material instances can override).
|
||||||
MaterialBuilder& depthCulling(bool enable) noexcept;
|
MaterialBuilder& depthCulling(bool enable) noexcept;
|
||||||
|
|
||||||
|
//! Enable / disable instanced primitives (disabled by default).
|
||||||
|
MaterialBuilder& instanced(bool enable) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Double-sided materials don't cull faces, equivalent to culling(CullingMode::NONE).
|
* Double-sided materials don't cull faces, equivalent to culling(CullingMode::NONE).
|
||||||
* doubleSided() overrides culling() if called.
|
* doubleSided() overrides culling() if called.
|
||||||
@@ -731,6 +734,7 @@ private:
|
|||||||
bool mDoubleSidedCapability = false;
|
bool mDoubleSidedCapability = false;
|
||||||
bool mColorWrite = true;
|
bool mColorWrite = true;
|
||||||
bool mDepthTest = true;
|
bool mDepthTest = true;
|
||||||
|
bool mInstanced = true;
|
||||||
bool mDepthWrite = true;
|
bool mDepthWrite = true;
|
||||||
bool mDepthWriteSet = false;
|
bool mDepthWriteSet = false;
|
||||||
|
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ public:
|
|||||||
* range can be adjusted with this method.
|
* range can be adjusted with this method.
|
||||||
*
|
*
|
||||||
* @param intensity Scale factor applied to the environment and irradiance such that
|
* @param intensity Scale factor applied to the environment and irradiance such that
|
||||||
* the result is in lux, or <i>lumen/m^2(default = 30000)
|
* the result is in lux, or <i>lumen/m^2</i> (default = 30000)
|
||||||
*/
|
*/
|
||||||
void setIntensity(float intensity) noexcept;
|
void setIntensity(float intensity) noexcept;
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ enum UTILS_PUBLIC ChunkType : uint64_t {
|
|||||||
MaterialColorWrite = charTo64bitNum("MAT_CWRIT"),
|
MaterialColorWrite = charTo64bitNum("MAT_CWRIT"),
|
||||||
MaterialDepthWrite = charTo64bitNum("MAT_DWRIT"),
|
MaterialDepthWrite = charTo64bitNum("MAT_DWRIT"),
|
||||||
MaterialDepthTest = charTo64bitNum("MAT_DTEST"),
|
MaterialDepthTest = charTo64bitNum("MAT_DTEST"),
|
||||||
|
MaterialInstanced = charTo64bitNum("MAT_INSTA"),
|
||||||
MaterialCullingMode = charTo64bitNum("MAT_CUMO"),
|
MaterialCullingMode = charTo64bitNum("MAT_CUMO"),
|
||||||
|
|
||||||
MaterialHasCustomDepthShader =charTo64bitNum("MAT_CSDP"),
|
MaterialHasCustomDepthShader =charTo64bitNum("MAT_CSDP"),
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
namespace filament {
|
namespace filament {
|
||||||
|
|
||||||
// update this when a new version of filament wouldn't work with older materials
|
// update this when a new version of filament wouldn't work with older materials
|
||||||
static constexpr size_t MATERIAL_VERSION = 21;
|
static constexpr size_t MATERIAL_VERSION = 25;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Supported shading models
|
* Supported shading models
|
||||||
|
|||||||
@@ -78,43 +78,49 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the position of morph target at the index.
|
* Updates positions for the given morph target.
|
||||||
|
*
|
||||||
|
* This is equivalent to the float4 method, but uses 1.0 for the 4th component.
|
||||||
*
|
*
|
||||||
* Both positions and tangents must be provided.
|
* Both positions and tangents must be provided.
|
||||||
*
|
*
|
||||||
* @param engine Reference to the filament::Engine associated with this MorphTargetBuffer.
|
* @param engine Reference to the filament::Engine associated with this MorphTargetBuffer.
|
||||||
* @param targetIndex the index of morph target to be updated.
|
* @param targetIndex the index of morph target to be updated.
|
||||||
* @param weights pointer to at least count positions
|
* @param positions pointer to at least "count" positions
|
||||||
* @param count number of position elements in positions
|
* @param count number of float3 vectors in positions
|
||||||
|
* @param offset offset into the target buffer, expressed as a number of float4 vectors
|
||||||
* @see setTangentsAt
|
* @see setTangentsAt
|
||||||
*/
|
*/
|
||||||
void setPositionsAt(Engine& engine, size_t targetIndex,
|
void setPositionsAt(Engine& engine, size_t targetIndex,
|
||||||
math::float3 const* positions, size_t count, size_t offset = 0);
|
math::float3 const* positions, size_t count, size_t offset = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the position of morph target at the index.
|
* Updates positions for the given morph target.
|
||||||
*
|
*
|
||||||
* Both positions and tangents must be provided.
|
* Both positions and tangents must be provided.
|
||||||
*
|
*
|
||||||
* @param engine Reference to the filament::Engine associated with this MorphTargetBuffer.
|
* @param engine Reference to the filament::Engine associated with this MorphTargetBuffer.
|
||||||
* @param targetIndex the index of morph target to be updated.
|
* @param targetIndex the index of morph target to be updated.
|
||||||
* @param weights pointer to at least count positions
|
* @param positions pointer to at least "count" positions
|
||||||
* @param count number of position elements in positions
|
* @param count number of float4 vectors in positions
|
||||||
* @see setPositionsAt
|
* @param offset offset into the target buffer, expressed as a number of float4 vectors
|
||||||
|
* @see setTangentsAt
|
||||||
*/
|
*/
|
||||||
void setPositionsAt(Engine& engine, size_t targetIndex,
|
void setPositionsAt(Engine& engine, size_t targetIndex,
|
||||||
math::float4 const* positions, size_t count, size_t offset = 0);
|
math::float4 const* positions, size_t count, size_t offset = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the position of morph target at the index.
|
* Updates tangents for the given morph target.
|
||||||
*
|
*
|
||||||
* Both positions and tangents must be provided.
|
* These quaternions must be represented as signed shorts, where real numbers in the [-1,+1]
|
||||||
|
* range multiplied by 32767.
|
||||||
*
|
*
|
||||||
* @param engine Reference to the filament::Engine associated with this MorphTargetBuffer.
|
* @param engine Reference to the filament::Engine associated with this MorphTargetBuffer.
|
||||||
* @param targetIndex the index of morph target to be updated.
|
* @param targetIndex the index of morph target to be updated.
|
||||||
* @param tangents pointer to at least count tangents
|
* @param tangents pointer to at least "count" tangents
|
||||||
* @param count number of tangent elements in tangents
|
* @param count number of short4 quaternions in tangents
|
||||||
* @see setTangentsAt
|
* @param offset offset into the target buffer, expressed as a number of short4 vectors
|
||||||
|
* @see setPositionsAt
|
||||||
*/
|
*/
|
||||||
void setTangentsAt(Engine& engine, size_t targetIndex,
|
void setTangentsAt(Engine& engine, size_t targetIndex,
|
||||||
math::short4 const* tangents, size_t count, size_t offset = 0);
|
math::short4 const* tangents, size_t count, size_t offset = 0);
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ namespace filament {
|
|||||||
|
|
||||||
class Texture;
|
class Texture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic quality level.
|
||||||
|
*/
|
||||||
enum class QualityLevel : uint8_t {
|
enum class QualityLevel : uint8_t {
|
||||||
LOW,
|
LOW,
|
||||||
MEDIUM,
|
MEDIUM,
|
||||||
@@ -69,8 +72,8 @@ enum class BlendMode : uint8_t {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct DynamicResolutionOptions {
|
struct DynamicResolutionOptions {
|
||||||
math::float2 minScale = math::float2(0.5f); //!< minimum scale factors in x and y
|
math::float2 minScale = {0.5f, 0.5f}; //!< minimum scale factors in x and y %codegen_java_float%
|
||||||
math::float2 maxScale = math::float2(1.0f); //!< maximum scale factors in x and y
|
math::float2 maxScale = {1.0f, 1.0f}; //!< maximum scale factors in x and y %codegen_java_float%
|
||||||
float sharpness = 0.9f; //!< sharpness when QualityLevel::MEDIUM or higher is used [0 (disabled), 1 (sharpest)]
|
float sharpness = 0.9f; //!< sharpness when QualityLevel::MEDIUM or higher is used [0 (disabled), 1 (sharpest)]
|
||||||
bool enabled = false; //!< enable or disable dynamic resolution
|
bool enabled = false; //!< enable or disable dynamic resolution
|
||||||
bool homogeneousScaling = false; //!< set to true to force homogeneous scaling
|
bool homogeneousScaling = false; //!< set to true to force homogeneous scaling
|
||||||
@@ -125,8 +128,8 @@ struct BloomOptions {
|
|||||||
ADD, //!< Bloom is modulated by the strength parameter and added to the scene
|
ADD, //!< Bloom is modulated by the strength parameter and added to the scene
|
||||||
INTERPOLATE //!< Bloom is interpolated with the scene using the strength parameter
|
INTERPOLATE //!< Bloom is interpolated with the scene using the strength parameter
|
||||||
};
|
};
|
||||||
Texture* dirt = nullptr; //!< user provided dirt texture
|
Texture* dirt = nullptr; //!< user provided dirt texture %codegen_skip_json% %codegen_skip_javascript%
|
||||||
float dirtStrength = 0.2f; //!< strength of the dirt texture
|
float dirtStrength = 0.2f; //!< strength of the dirt texture %codegen_skip_json% %codegen_skip_javascript%
|
||||||
float strength = 0.10f; //!< bloom's strength between 0.0 and 1.0
|
float strength = 0.10f; //!< bloom's strength between 0.0 and 1.0
|
||||||
uint32_t resolution = 360; //!< resolution of vertical axis (2^levels to 2048)
|
uint32_t resolution = 360; //!< resolution of vertical axis (2^levels to 2048)
|
||||||
float anamorphism = 1.0f; //!< bloom x/y aspect-ratio (1/32 to 32)
|
float anamorphism = 1.0f; //!< bloom x/y aspect-ratio (1/32 to 32)
|
||||||
@@ -151,16 +154,16 @@ struct BloomOptions {
|
|||||||
* Options to control fog in the scene
|
* Options to control fog in the scene
|
||||||
*/
|
*/
|
||||||
struct FogOptions {
|
struct FogOptions {
|
||||||
float distance = 0.0f; //!< distance in world units from the camera where the fog starts ( >= 0.0 )
|
float distance = 0.0f; //!< distance in world units from the camera where the fog starts ( >= 0.0 )
|
||||||
float maximumOpacity = 1.0f; //!< fog's maximum opacity between 0 and 1
|
float maximumOpacity = 1.0f; //!< fog's maximum opacity between 0 and 1
|
||||||
float height = 0.0f; //!< fog's floor in world units
|
float height = 0.0f; //!< fog's floor in world units
|
||||||
float heightFalloff = 1.0f; //!< how fast fog dissipates with altitude
|
float heightFalloff = 1.0f; //!< how fast fog dissipates with altitude
|
||||||
LinearColor color{0.5f}; //!< fog's color (linear), see fogColorFromIbl
|
LinearColor color = {0.5f, 0.5f, 0.5f};//!< fog's color (linear), see fogColorFromIbl
|
||||||
float density = 0.1f; //!< fog's density at altitude given by 'height'
|
float density = 0.1f; //!< fog's density at altitude given by 'height'
|
||||||
float inScatteringStart = 0.0f; //!< distance in world units from the camera where in-scattering starts
|
float inScatteringStart = 0.0f; //!< distance in world units from the camera where in-scattering starts
|
||||||
float inScatteringSize = -1.0f; //!< size of in-scattering (>0 to activate). Good values are >> 1 (e.g. ~10 - 100).
|
float inScatteringSize = -1.0f; //!< size of in-scattering (>0 to activate). Good values are >> 1 (e.g. ~10 - 100).
|
||||||
bool fogColorFromIbl = false; //!< Fog color will be modulated by the IBL color in the view direction.
|
bool fogColorFromIbl = false; //!< Fog color will be modulated by the IBL color in the view direction.
|
||||||
bool enabled = false; //!< enable or disable fog
|
bool enabled = false; //!< enable or disable fog
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -174,8 +177,9 @@ struct FogOptions {
|
|||||||
*/
|
*/
|
||||||
struct DepthOfFieldOptions {
|
struct DepthOfFieldOptions {
|
||||||
enum class Filter : uint8_t {
|
enum class Filter : uint8_t {
|
||||||
NONE = 0,
|
NONE,
|
||||||
MEDIAN = 2
|
UNUSED,
|
||||||
|
MEDIAN
|
||||||
};
|
};
|
||||||
float cocScale = 1.0f; //!< circle of confusion scale factor (amount of blur)
|
float cocScale = 1.0f; //!< circle of confusion scale factor (amount of blur)
|
||||||
float maxApertureDiameter = 0.01f; //!< maximum aperture diameter in meters (zero to disable rotation)
|
float maxApertureDiameter = 0.01f; //!< maximum aperture diameter in meters (zero to disable rotation)
|
||||||
@@ -227,7 +231,7 @@ struct VignetteOptions {
|
|||||||
float midPoint = 0.5f; //!< high values restrict the vignette closer to the corners, between 0 and 1
|
float midPoint = 0.5f; //!< high values restrict the vignette closer to the corners, between 0 and 1
|
||||||
float roundness = 0.5f; //!< controls the shape of the vignette, from a rounded rectangle (0.0), to an oval (0.5), to a circle (1.0)
|
float roundness = 0.5f; //!< controls the shape of the vignette, from a rounded rectangle (0.0), to an oval (0.5), to a circle (1.0)
|
||||||
float feather = 0.5f; //!< softening amount of the vignette effect, between 0 and 1
|
float feather = 0.5f; //!< softening amount of the vignette effect, between 0 and 1
|
||||||
LinearColorA color{0.0f, 0.0f, 0.0f, 1.0f}; //!< color of the vignette effect, alpha is currently ignored
|
LinearColorA color = {0.0f, 0.0f, 0.0f, 1.0f}; //!< color of the vignette effect, alpha is currently ignored
|
||||||
bool enabled = false; //!< enables or disables the vignette effect
|
bool enabled = false; //!< enables or disables the vignette effect
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -271,17 +275,18 @@ struct AmbientOcclusionOptions {
|
|||||||
* Ambient shadows from dominant light
|
* Ambient shadows from dominant light
|
||||||
*/
|
*/
|
||||||
struct Ssct {
|
struct Ssct {
|
||||||
float lightConeRad = 1.0f; //!< full cone angle in radian, between 0 and pi/2
|
float lightConeRad = 1.0f; //!< full cone angle in radian, between 0 and pi/2
|
||||||
float shadowDistance = 0.3f; //!< how far shadows can be cast
|
float shadowDistance = 0.3f; //!< how far shadows can be cast
|
||||||
float contactDistanceMax = 1.0f; //!< max distance for contact
|
float contactDistanceMax = 1.0f; //!< max distance for contact
|
||||||
float intensity = 0.8f; //!< intensity
|
float intensity = 0.8f; //!< intensity
|
||||||
math::float3 lightDirection{ 0, -1, 0 }; //!< light direction
|
math::float3 lightDirection = { 0, -1, 0 }; //!< light direction
|
||||||
float depthBias = 0.01f; //!< depth bias in world units (mitigate self shadowing)
|
float depthBias = 0.01f; //!< depth bias in world units (mitigate self shadowing)
|
||||||
float depthSlopeBias = 0.01f; //!< depth slope bias (mitigate self shadowing)
|
float depthSlopeBias = 0.01f; //!< depth slope bias (mitigate self shadowing)
|
||||||
uint8_t sampleCount = 4; //!< tracing sample count, between 1 and 255
|
uint8_t sampleCount = 4; //!< tracing sample count, between 1 and 255
|
||||||
uint8_t rayCount = 1; //!< # of rays to trace, between 1 and 255
|
uint8_t rayCount = 1; //!< # of rays to trace, between 1 and 255
|
||||||
bool enabled = false; //!< enables or disables SSCT
|
bool enabled = false; //!< enables or disables SSCT
|
||||||
} ssct;
|
};
|
||||||
|
Ssct ssct; // %codegen_skip_javascript% %codegen_java_flatten%
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -328,21 +333,31 @@ struct ScreenSpaceReflectionsOptions {
|
|||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options for the screen-space guard band.
|
||||||
|
* A guard band can be enabled to avoid some artifacts towards the edge of the screen when
|
||||||
|
* using screen-space effects such as SSAO. Enabling the guard band reduces performance slightly.
|
||||||
|
* Currently the guard band can only be enabled or disabled.
|
||||||
|
*/
|
||||||
|
struct GuardBandOptions {
|
||||||
|
bool enabled = false;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of available post-processing anti-aliasing techniques.
|
* List of available post-processing anti-aliasing techniques.
|
||||||
* @see setAntiAliasing, getAntiAliasing, setSampleCount
|
* @see setAntiAliasing, getAntiAliasing, setSampleCount
|
||||||
*/
|
*/
|
||||||
enum class AntiAliasing : uint8_t {
|
enum class AntiAliasing : uint8_t {
|
||||||
NONE = 0, //!< no anti aliasing performed as part of post-processing
|
NONE, //!< no anti aliasing performed as part of post-processing
|
||||||
FXAA = 1 //!< FXAA is a low-quality but very efficient type of anti-aliasing. (default).
|
FXAA //!< FXAA is a low-quality but very efficient type of anti-aliasing. (default).
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of available post-processing dithering techniques.
|
* List of available post-processing dithering techniques.
|
||||||
*/
|
*/
|
||||||
enum class Dithering : uint8_t {
|
enum class Dithering : uint8_t {
|
||||||
NONE = 0, //!< No dithering
|
NONE, //!< No dithering
|
||||||
TEMPORAL = 1 //!< Temporal dithering (default)
|
TEMPORAL //!< Temporal dithering (default)
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -205,10 +205,12 @@ public:
|
|||||||
* avoid using a separate View for the HUD. Note that priority is completely orthogonal to
|
* avoid using a separate View for the HUD. Note that priority is completely orthogonal to
|
||||||
* Builder::layerMask, which merely controls visibility.
|
* Builder::layerMask, which merely controls visibility.
|
||||||
*
|
*
|
||||||
* \see Builder::blendOrder()
|
* @param priority clamped to the range [0..7], defaults to 4; 7 is lowest priority
|
||||||
|
* (rendered last).
|
||||||
*
|
*
|
||||||
* The priority is clamped to the range [0..7], defaults to 4; 7 is lowest priority
|
* @return Builder reference for chaining calls.
|
||||||
* (rendered last).
|
*
|
||||||
|
* @see Builder::blendOrder(), RenderableManager::setBlendOrderAt()
|
||||||
*/
|
*/
|
||||||
Builder& priority(uint8_t priority) noexcept;
|
Builder& priority(uint8_t priority) noexcept;
|
||||||
|
|
||||||
@@ -337,23 +339,44 @@ public:
|
|||||||
*/
|
*/
|
||||||
Builder& morphing(uint8_t level, size_t primitiveIndex,
|
Builder& morphing(uint8_t level, size_t primitiveIndex,
|
||||||
MorphTargetBuffer* morphTargetBuffer, size_t offset, size_t count) noexcept;
|
MorphTargetBuffer* morphTargetBuffer, size_t offset, size_t count) noexcept;
|
||||||
|
|
||||||
inline Builder& morphing(uint8_t level, size_t primitiveIndex,
|
inline Builder& morphing(uint8_t level, size_t primitiveIndex,
|
||||||
MorphTargetBuffer* morphTargetBuffer) noexcept;
|
MorphTargetBuffer* morphTargetBuffer) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets an ordering index for blended primitives that all live at the same Z value.
|
* Sets the drawing order for blended primitives. The drawing order is either global or
|
||||||
|
* local (default) to this Renderable. In either case, the Renderable priority takes
|
||||||
|
* precedence.
|
||||||
*
|
*
|
||||||
* @param primitiveIndex the primitive of interest
|
* @param primitiveIndex the primitive of interest
|
||||||
* @param order draw order number (0 by default). Only the lowest 15 bits are used.
|
* @param order draw order number (0 by default). Only the lowest 15 bits are used.
|
||||||
|
*
|
||||||
|
* @return Builder reference for chaining calls.
|
||||||
|
*
|
||||||
|
* @see globalBlendOrderEnabled
|
||||||
*/
|
*/
|
||||||
Builder& blendOrder(size_t primitiveIndex, uint16_t order) noexcept;
|
Builder& blendOrder(size_t primitiveIndex, uint16_t order) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the blend order is global or local to this Renderable (by default).
|
||||||
|
*
|
||||||
|
* @param primitiveIndex the primitive of interest
|
||||||
|
* @param enabled true for global, false for local blend ordering.
|
||||||
|
*
|
||||||
|
* @return Builder reference for chaining calls.
|
||||||
|
*
|
||||||
|
* @see blendOrder
|
||||||
|
*/
|
||||||
|
Builder& globalBlendOrderEnabled(size_t primitiveIndex, bool enabled) noexcept;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies the number of draw instance of this renderable. The default is 1 instance and
|
* Specifies the number of draw instance of this renderable. The default is 1 instance and
|
||||||
* the maximum number of instances allowed is 65535. 0 is invalid.
|
* the maximum number of instances allowed is 65535. 0 is invalid.
|
||||||
* All instances are culled using the same bounding box, so care must be taken to make
|
* All instances are culled using the same bounding box, so care must be taken to make
|
||||||
* sure all instances render inside the specified bounding box.
|
* sure all instances render inside the specified bounding box.
|
||||||
* The material can use getInstanceIndex() in the vertex shader to get the instance index and
|
* The material must set its `instanced` parameter to `true` in order to use
|
||||||
|
* getInstanceIndex() in the vertex or fragment shader to get the instance index and
|
||||||
* possibly adjust the position or transform.
|
* possibly adjust the position or transform.
|
||||||
*
|
*
|
||||||
* @param instanceCount the number of instances silently clamped between 1 and 65535.
|
* @param instanceCount the number of instances silently clamped between 1 and 65535.
|
||||||
@@ -394,6 +417,7 @@ public:
|
|||||||
MaterialInstance const* materialInstance = nullptr;
|
MaterialInstance const* materialInstance = nullptr;
|
||||||
PrimitiveType type = PrimitiveType::TRIANGLES;
|
PrimitiveType type = PrimitiveType::TRIANGLES;
|
||||||
uint16_t blendOrder = 0;
|
uint16_t blendOrder = 0;
|
||||||
|
bool globalBlendOrderEnabled = false;
|
||||||
struct {
|
struct {
|
||||||
MorphTargetBuffer* buffer = nullptr;
|
MorphTargetBuffer* buffer = nullptr;
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
@@ -497,7 +521,15 @@ public:
|
|||||||
void setBones(Instance instance, math::mat4f const* transforms, size_t boneCount = 1, size_t offset = 0); //!< \overload
|
void setBones(Instance instance, math::mat4f const* transforms, size_t boneCount = 1, size_t offset = 0); //!< \overload
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Associates a SkinningBuffer to a renderable instance
|
* Associates a region of a SkinningBuffer to a renderable instance
|
||||||
|
*
|
||||||
|
* Note: due to hardware limitations offset + 256 must be smaller or equal to
|
||||||
|
* skinningBuffer->getBoneCount()
|
||||||
|
*
|
||||||
|
* @param instance Instance of the component obtained from getInstance().
|
||||||
|
* @param skinningBuffer skinning buffer to associate to the instance
|
||||||
|
* @param count Size of the region in bones, must be smaller or equal to 256.
|
||||||
|
* @param offset Start offset of the region in bones
|
||||||
*/
|
*/
|
||||||
void setSkinningBuffer(Instance instance, SkinningBuffer* skinningBuffer,
|
void setSkinningBuffer(Instance instance, SkinningBuffer* skinningBuffer,
|
||||||
size_t count, size_t offset);
|
size_t count, size_t offset);
|
||||||
@@ -511,7 +543,7 @@ public:
|
|||||||
* @param instance Instance of the component obtained from getInstance().
|
* @param instance Instance of the component obtained from getInstance().
|
||||||
* @param weights Pointer to morph target weights to be update.
|
* @param weights Pointer to morph target weights to be update.
|
||||||
* @param count Number of morph target weights.
|
* @param count Number of morph target weights.
|
||||||
* @param offset Index of the first first morph target weight to set at instance.
|
* @param offset Index of the first morph target weight to set at instance.
|
||||||
*/
|
*/
|
||||||
void setMorphWeights(Instance instance,
|
void setMorphWeights(Instance instance,
|
||||||
float const* weights, size_t count, size_t offset = 0);
|
float const* weights, size_t count, size_t offset = 0);
|
||||||
@@ -578,24 +610,28 @@ public:
|
|||||||
size_t offset, size_t count) noexcept;
|
size_t offset, size_t count) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the active range of indices or topology for the given primitive.
|
* Changes the drawing order for blended primitives. The drawing order is either global or
|
||||||
*
|
* local (default) to this Renderable. In either case, the Renderable priority takes precedence.
|
||||||
* \see Builder::geometry()
|
|
||||||
*/
|
|
||||||
void setGeometryAt(Instance instance, size_t primitiveIndex,
|
|
||||||
PrimitiveType type, size_t offset, size_t count) noexcept;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the ordering index for blended primitives that all live at the same Z value.
|
|
||||||
*
|
|
||||||
* \see Builder::blendOrder()
|
|
||||||
*
|
*
|
||||||
* @param instance the renderable of interest
|
* @param instance the renderable of interest
|
||||||
* @param primitiveIndex the primitive of interest
|
* @param primitiveIndex the primitive of interest
|
||||||
* @param order draw order number (0 by default). Only the lowest 15 bits are used.
|
* @param order draw order number (0 by default). Only the lowest 15 bits are used.
|
||||||
|
*
|
||||||
|
* @see Builder::blendOrder(), setGlobalBlendOrderEnabledAt()
|
||||||
*/
|
*/
|
||||||
void setBlendOrderAt(Instance instance, size_t primitiveIndex, uint16_t order) noexcept;
|
void setBlendOrderAt(Instance instance, size_t primitiveIndex, uint16_t order) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes whether the blend order is global or local to this Renderable (by default).
|
||||||
|
*
|
||||||
|
* @param instance the renderable of interest
|
||||||
|
* @param primitiveIndex the primitive of interest
|
||||||
|
* @param enabled true for global, false for local blend ordering.
|
||||||
|
*
|
||||||
|
* @see Builder::globalBlendOrderEnabled(), setBlendOrderAt()
|
||||||
|
*/
|
||||||
|
void setGlobalBlendOrderEnabledAt(Instance instance, size_t primitiveIndex, bool enabled) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the set of enabled attribute slots in the given primitive's VertexBuffer.
|
* Retrieves the set of enabled attribute slots in the given primitive's VertexBuffer.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -80,11 +80,8 @@ public:
|
|||||||
// refresh-rate of the display in Hz. set to 0 for offscreen or turn off frame-pacing.
|
// refresh-rate of the display in Hz. set to 0 for offscreen or turn off frame-pacing.
|
||||||
float refreshRate = 60.0f;
|
float refreshRate = 60.0f;
|
||||||
|
|
||||||
// how far in advance a buffer must be queued for presentation at a given time in ns
|
[[deprecated]] uint64_t presentationDeadlineNanos = 0;
|
||||||
uint64_t presentationDeadlineNanos = 0;
|
[[deprecated]] uint64_t vsyncOffsetNanos = 0;
|
||||||
|
|
||||||
// offset by which vsyncSteadyClockTimeNano provided in beginFrame() is offset in ns
|
|
||||||
uint64_t vsyncOffsetNanos = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -243,6 +240,20 @@ public:
|
|||||||
bool beginFrame(SwapChain* swapChain,
|
bool beginFrame(SwapChain* swapChain,
|
||||||
uint64_t vsyncSteadyClockTimeNano = 0u);
|
uint64_t vsyncSteadyClockTimeNano = 0u);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the time at which the frame must be presented to the display.
|
||||||
|
*
|
||||||
|
* This must be called between beginFrame() and endFrame().
|
||||||
|
*
|
||||||
|
* @param monotonic_clock_ns the time in nanoseconds corresponding to the system monotonic up-time clock.
|
||||||
|
* the presentation time is typically set in the middle of the period
|
||||||
|
* of interest. The presentation time cannot be too far in the
|
||||||
|
* future because it is limited by how many buffers are available in
|
||||||
|
* the display sub-system. Typically it is set to 1 or 2 vsync periods
|
||||||
|
* away.
|
||||||
|
*/
|
||||||
|
void setPresentationTime(int64_t monotonic_clock_ns);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render a View into this renderer's window.
|
* Render a View into this renderer's window.
|
||||||
*
|
*
|
||||||
@@ -444,6 +455,10 @@ public:
|
|||||||
*
|
*
|
||||||
* It is also possible to use a Fence to wait for the read-back.
|
* It is also possible to use a Fence to wait for the read-back.
|
||||||
*
|
*
|
||||||
|
* OpenGL only: if issuing a readPixels on a RenderTarget backed by a Texture that had data
|
||||||
|
* uploaded to it via setImage, the data returned from readPixels will be y-flipped with respect
|
||||||
|
* to the setImage call.
|
||||||
|
*
|
||||||
* @remark
|
* @remark
|
||||||
* readPixels() is intended for debugging and testing. It will impact performance significantly.
|
* readPixels() is intended for debugging and testing. It will impact performance significantly.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ namespace filament {
|
|||||||
/**
|
/**
|
||||||
* SkinningBuffer is used to hold skinning data (bones). It is a simple wraper around
|
* SkinningBuffer is used to hold skinning data (bones). It is a simple wraper around
|
||||||
* a structured UBO.
|
* a structured UBO.
|
||||||
|
* @see RenderableManager::setSkinningBuffer
|
||||||
*/
|
*/
|
||||||
class UTILS_PUBLIC SkinningBuffer : public FilamentAPI {
|
class UTILS_PUBLIC SkinningBuffer : public FilamentAPI {
|
||||||
struct BuilderDetails;
|
struct BuilderDetails;
|
||||||
@@ -93,6 +94,7 @@ public:
|
|||||||
* @param transforms pointer to at least count Bone
|
* @param transforms pointer to at least count Bone
|
||||||
* @param count number of Bone elements in transforms
|
* @param count number of Bone elements in transforms
|
||||||
* @param offset offset in elements (not bytes) in the SkinningBuffer (not in transforms)
|
* @param offset offset in elements (not bytes) in the SkinningBuffer (not in transforms)
|
||||||
|
* @see RenderableManager::setSkinningBuffer
|
||||||
*/
|
*/
|
||||||
void setBones(Engine& engine, RenderableManager::Bone const* transforms,
|
void setBones(Engine& engine, RenderableManager::Bone const* transforms,
|
||||||
size_t count, size_t offset = 0);
|
size_t count, size_t offset = 0);
|
||||||
@@ -103,6 +105,7 @@ public:
|
|||||||
* @param transforms pointer to at least count mat4f
|
* @param transforms pointer to at least count mat4f
|
||||||
* @param count number of mat4f elements in transforms
|
* @param count number of mat4f elements in transforms
|
||||||
* @param offset offset in elements (not bytes) in the SkinningBuffer (not in transforms)
|
* @param offset offset in elements (not bytes) in the SkinningBuffer (not in transforms)
|
||||||
|
* @see RenderableManager::setSkinningBuffer
|
||||||
*/
|
*/
|
||||||
void setBones(Engine& engine, math::mat4f const* transforms,
|
void setBones(Engine& engine, math::mat4f const* transforms,
|
||||||
size_t count, size_t offset = 0);
|
size_t count, size_t offset = 0);
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ public:
|
|||||||
*
|
*
|
||||||
* Ignored if an environment is set.
|
* Ignored if an environment is set.
|
||||||
*
|
*
|
||||||
* @param color
|
* @param color the constant color
|
||||||
*
|
*
|
||||||
* @return This Builder, for chaining calls.
|
* @return This Builder, for chaining calls.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -35,10 +35,9 @@ class Engine;
|
|||||||
/**
|
/**
|
||||||
* Stream is used to attach a video stream to a Filament `Texture`.
|
* Stream is used to attach a video stream to a Filament `Texture`.
|
||||||
*
|
*
|
||||||
* Note that the `Stream` class is fairly Android centric. It supports three different
|
* Note that the `Stream` class is fairly Android centric. It supports two different
|
||||||
* configurations:
|
* configurations:
|
||||||
*
|
*
|
||||||
* - TEXTURE_ID...takes an OpenGL texture ID and incurs a copy
|
|
||||||
* - ACQUIRED.....connects to an Android AHardwareBuffer
|
* - ACQUIRED.....connects to an Android AHardwareBuffer
|
||||||
* - NATIVE.......connects to an Android SurfaceTexture
|
* - NATIVE.......connects to an Android SurfaceTexture
|
||||||
*
|
*
|
||||||
@@ -67,10 +66,6 @@ class Engine;
|
|||||||
* - Filament invokes low-level graphics commands on the \em{driver thread}.
|
* - Filament invokes low-level graphics commands on the \em{driver thread}.
|
||||||
* - The thread that calls `beginFrame` is called the \em{main thread}.
|
* - The thread that calls `beginFrame` is called the \em{main thread}.
|
||||||
*
|
*
|
||||||
* The TEXTURE_ID configuration achieves synchronization automatically. In this mode, Filament
|
|
||||||
* performs a copy on the main thread during `beginFrame` by blitting the external image into
|
|
||||||
* an internal round-robin queue of images. This copy has a run-time cost.
|
|
||||||
*
|
|
||||||
* For ACQUIRED streams, there is no need to perform the copy because Filament explictly acquires
|
* For ACQUIRED streams, there is no need to perform the copy because Filament explictly acquires
|
||||||
* the stream, then releases it later via a callback function. This configuration is especially
|
* the stream, then releases it later via a callback function. This configuration is especially
|
||||||
* useful when the Vulkan backend is enabled.
|
* useful when the Vulkan backend is enabled.
|
||||||
@@ -97,7 +92,7 @@ public:
|
|||||||
* By default, Stream objects are ACQUIRED and must have external images pushed to them via
|
* By default, Stream objects are ACQUIRED and must have external images pushed to them via
|
||||||
* <pre>Stream::setAcquiredImage</pre>.
|
* <pre>Stream::setAcquiredImage</pre>.
|
||||||
*
|
*
|
||||||
* To create a NATIVE or TEXTURE_ID stream, call one of the <pre>stream</pre> methods
|
* To create a NATIVE stream, call one of the <pre>stream</pre> methods
|
||||||
* on the builder.
|
* on the builder.
|
||||||
*/
|
*/
|
||||||
class Builder : public BuilderBase<BuilderDetails> {
|
class Builder : public BuilderBase<BuilderDetails> {
|
||||||
@@ -122,23 +117,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
Builder& stream(void* stream) noexcept;
|
Builder& stream(void* stream) noexcept;
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a TEXTURE_ID stream. This will sample data from the supplied
|
|
||||||
* external texture and copy it into an internal private texture.
|
|
||||||
*
|
|
||||||
* @param externalTextureId An opaque texture id (typically a GLuint created with glGenTextures)
|
|
||||||
* In a context shared with filament. In that case this texture's
|
|
||||||
* target must be GL_TEXTURE_EXTERNAL_OES and the wrap mode must
|
|
||||||
* be CLAMP_TO_EDGE.
|
|
||||||
*
|
|
||||||
* @return This Builder, for chaining calls.
|
|
||||||
*
|
|
||||||
* @see Texture::setExternalStream()
|
|
||||||
* @deprecated this method existed only for ARCore which doesn't need this anymore, use Texture::import() instead.
|
|
||||||
*/
|
|
||||||
UTILS_DEPRECATED
|
|
||||||
Builder& stream(intptr_t externalTextureId) noexcept;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param width initial width of the incoming stream. Whether this value is used is
|
* @param width initial width of the incoming stream. Whether this value is used is
|
||||||
@@ -173,7 +151,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether this stream is a NATIVE stream, TEXTURE_ID stream, or ACQUIRED stream.
|
* Indicates whether this stream is a NATIVE stream or ACQUIRED stream.
|
||||||
*/
|
*/
|
||||||
StreamType getStreamType() const noexcept;
|
StreamType getStreamType() const noexcept;
|
||||||
|
|
||||||
@@ -190,7 +168,7 @@ public:
|
|||||||
* also where the callback is invoked. This method can only be used for streams that were
|
* also where the callback is invoked. This method can only be used for streams that were
|
||||||
* constructed without calling the `stream` method on the builder.
|
* constructed without calling the `stream` method on the builder.
|
||||||
*
|
*
|
||||||
* @see Stream for more information about NATIVE, TEXTURE_ID, and ACQUIRED configurations.
|
* @see Stream for more information about NATIVE and ACQUIRED configurations.
|
||||||
*
|
*
|
||||||
* @param image Pointer to AHardwareBuffer, casted to void* since this is a public header.
|
* @param image Pointer to AHardwareBuffer, casted to void* since this is a public header.
|
||||||
* @param callback This is triggered by Filament when it wishes to release the image.
|
* @param callback This is triggered by Filament when it wishes to release the image.
|
||||||
@@ -222,63 +200,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
void setDimensions(uint32_t width, uint32_t height) noexcept;
|
void setDimensions(uint32_t width, uint32_t height) noexcept;
|
||||||
|
|
||||||
/**
|
|
||||||
* Read-back the content of the last frame of a Stream since the last call to
|
|
||||||
* Renderer.beginFrame().
|
|
||||||
*
|
|
||||||
* The Stream must be of type externalTextureId. This function is a no-op otherwise.
|
|
||||||
*
|
|
||||||
* @param xoffset Left offset of the sub-region to read back.
|
|
||||||
* @param yoffset Bottom offset of the sub-region to read back.
|
|
||||||
* @param width Width of the sub-region to read back.
|
|
||||||
* @param height Height of the sub-region to read back.
|
|
||||||
* @param buffer Client-side buffer where the read-back will be written.
|
|
||||||
*
|
|
||||||
* The following format are always supported:
|
|
||||||
* - PixelBufferDescriptor::PixelDataFormat::RGBA
|
|
||||||
* - PixelBufferDescriptor::PixelDataFormat::RGBA_INTEGER
|
|
||||||
*
|
|
||||||
* The following types are always supported:
|
|
||||||
* - PixelBufferDescriptor::PixelDataType::UBYTE
|
|
||||||
* - PixelBufferDescriptor::PixelDataType::UINT
|
|
||||||
* - PixelBufferDescriptor::PixelDataType::INT
|
|
||||||
* - PixelBufferDescriptor::PixelDataType::FLOAT
|
|
||||||
*
|
|
||||||
* Other combination of format/type may be supported. If a combination is
|
|
||||||
* not supported, this operation may fail silently. Use a DEBUG build
|
|
||||||
* to get some logs about the failure.
|
|
||||||
*
|
|
||||||
* Stream buffer User buffer (PixelBufferDescriptor&)
|
|
||||||
* +--------------------+
|
|
||||||
* | | .stride .alignment
|
|
||||||
* | | ----------------------->-->
|
|
||||||
* | | O----------------------+--+ low addresses
|
|
||||||
* | | | | | |
|
|
||||||
* | w | | | .top | |
|
|
||||||
* | <---------> | | V | |
|
|
||||||
* | +---------+ | | +---------+ | |
|
|
||||||
* | | ^ | | ======> | | | | |
|
|
||||||
* | x | h| | | |.left| | | |
|
|
||||||
* +------>| v | | +---->| | | |
|
|
||||||
* | +.........+ | | +.........+ | |
|
|
||||||
* | ^ | | | |
|
|
||||||
* | y | | +----------------------+--+ high addresses
|
|
||||||
* O------------+-------+
|
|
||||||
*
|
|
||||||
* Typically readPixels() will be called after Renderer.beginFrame().
|
|
||||||
*
|
|
||||||
* After issuing this method, the callback associated with `buffer` will be invoked on the
|
|
||||||
* main thread, indicating that the read-back has completed. Typically, this will happen
|
|
||||||
* after multiple calls to beginFrame(), render(), endFrame().
|
|
||||||
*
|
|
||||||
* It is also possible to use a Fence to wait for the read-back.
|
|
||||||
*
|
|
||||||
* @remark
|
|
||||||
* readPixels() is intended for debugging and testing. It will impact performance significantly.
|
|
||||||
*/
|
|
||||||
void readPixels(uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height,
|
|
||||||
backend::PixelBufferDescriptor&& buffer) noexcept;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the presentation time of the currently displayed frame in nanosecond.
|
* Returns the presentation time of the currently displayed frame in nanosecond.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -134,12 +134,12 @@ struct UTILS_PUBLIC GenericToneMapper final : public ToneMapper {
|
|||||||
* constructor parameters approximate an ACES tone mapping curve
|
* constructor parameters approximate an ACES tone mapping curve
|
||||||
* and the maximum input value is set to 10.0.
|
* and the maximum input value is set to 10.0.
|
||||||
*
|
*
|
||||||
* @param contrast: controls the contrast of the curve, must be > 0.0, values
|
* @param contrast controls the contrast of the curve, must be > 0.0, values
|
||||||
* in the range 0.5..2.0 are recommended.
|
* in the range 0.5..2.0 are recommended.
|
||||||
* @param midGrayIn: sets the input middle gray, between 0.0 and 1.0.
|
* @param midGrayIn sets the input middle gray, between 0.0 and 1.0.
|
||||||
* @param midGrayOut: sets the output middle gray, between 0.0 and 1.0.
|
* @param midGrayOut sets the output middle gray, between 0.0 and 1.0.
|
||||||
* @param hdrMax: defines the maximum input value that will be mapped to
|
* @param hdrMax defines the maximum input value that will be mapped to
|
||||||
* output white. Must be >= 1.0.
|
* output white. Must be >= 1.0.
|
||||||
*/
|
*/
|
||||||
explicit GenericToneMapper(
|
explicit GenericToneMapper(
|
||||||
float contrast = 1.55f,
|
float contrast = 1.55f,
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ public:
|
|||||||
using VsmShadowOptions = VsmShadowOptions;
|
using VsmShadowOptions = VsmShadowOptions;
|
||||||
using SoftShadowOptions = SoftShadowOptions;
|
using SoftShadowOptions = SoftShadowOptions;
|
||||||
using ScreenSpaceReflectionsOptions = ScreenSpaceReflectionsOptions;
|
using ScreenSpaceReflectionsOptions = ScreenSpaceReflectionsOptions;
|
||||||
|
using GuardBandOptions = GuardBandOptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the View's name. Only useful for debugging.
|
* Sets the View's name. Only useful for debugging.
|
||||||
@@ -345,6 +346,20 @@ public:
|
|||||||
*/
|
*/
|
||||||
ScreenSpaceReflectionsOptions const& getScreenSpaceReflectionsOptions() const noexcept;
|
ScreenSpaceReflectionsOptions const& getScreenSpaceReflectionsOptions() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables or disable screen-space guard band. Disabled by default.
|
||||||
|
*
|
||||||
|
* @param options guard band options
|
||||||
|
*/
|
||||||
|
void setGuardBandOptions(GuardBandOptions options) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns screen-space guard band options.
|
||||||
|
*
|
||||||
|
* @return guard band options
|
||||||
|
*/
|
||||||
|
GuardBandOptions const& getGuardBandOptions() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables or disable multi-sample anti-aliasing (MSAA). Disabled by default.
|
* Enables or disable multi-sample anti-aliasing (MSAA). Disabled by default.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -43,11 +43,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
Viewport() noexcept : backend::Viewport{} {}
|
Viewport() noexcept : backend::Viewport{} {}
|
||||||
|
|
||||||
Viewport(const Viewport& viewport) noexcept = default;
|
|
||||||
Viewport(Viewport&& viewport) noexcept = default;
|
|
||||||
Viewport& operator=(const Viewport& viewport) noexcept = default;
|
|
||||||
Viewport& operator=(Viewport&& viewport) noexcept = default;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a Viewport from its left-bottom coordinates, width and height in pixels
|
* Creates a Viewport from its left-bottom coordinates, width and height in pixels
|
||||||
*
|
*
|
||||||
@@ -67,16 +62,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool empty() const noexcept { return !width || !height; }
|
bool empty() const noexcept { return !width || !height; }
|
||||||
|
|
||||||
/**
|
|
||||||
* Computes a new scaled Viewport
|
|
||||||
* @param s scaling factor on the x and y axes.
|
|
||||||
* @return A new scaled Viewport. The coordinates and dimensions of the new Viewport are
|
|
||||||
* rounded to the nearest integer value.
|
|
||||||
*/
|
|
||||||
Viewport scale(math::float2 s) const noexcept;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares two Viewports for equality
|
* Compares two Viewports for equality
|
||||||
* @param lhs reference to the left hand side Viewport
|
* @param lhs reference to the left hand side Viewport
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public:
|
|||||||
|
|
||||||
void unregisterAll();
|
void unregisterAll();
|
||||||
|
|
||||||
std::size_t numRegistered() const noexcept;
|
size_t numRegistered() const noexcept;
|
||||||
|
|
||||||
void getRegisteredMaterials(filament::MaterialInstance** materialList,
|
void getRegisteredMaterials(filament::MaterialInstance** materialList,
|
||||||
utils::CString* materialNameList) const;
|
utils::CString* materialNameList) const;
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ enum class ComponentType {
|
|||||||
SHORT, //!< If normalization is enabled, this maps from [-32767,32767] to [-1,+1]
|
SHORT, //!< If normalization is enabled, this maps from [-32767,32767] to [-1,+1]
|
||||||
USHORT, //!< If normalization is enabled, this maps from [0,65535] to [0, +1]
|
USHORT, //!< If normalization is enabled, this maps from [0,65535] to [0, +1]
|
||||||
HALF, //!< 1 sign bit, 5 exponent bits, and 5 mantissa bits.
|
HALF, //!< 1 sign bit, 5 exponent bits, and 5 mantissa bits.
|
||||||
|
FLOAT, //!< Standard 32-bit float
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
#include <gltfio/FilamentAsset.h>
|
#include <gltfio/FilamentAsset.h>
|
||||||
#include <gltfio/FilamentInstance.h>
|
#include <gltfio/FilamentInstance.h>
|
||||||
|
|
||||||
namespace gltfio {
|
namespace filament::gltfio {
|
||||||
|
|
||||||
struct FFilamentAsset;
|
struct FFilamentAsset;
|
||||||
struct FFilamentInstance;
|
struct FFilamentInstance;
|
||||||
@@ -56,6 +56,32 @@ public:
|
|||||||
*/
|
*/
|
||||||
void updateBoneMatrices();
|
void updateBoneMatrices();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies a blended transform to the union of nodes affected by two animations.
|
||||||
|
* Used for cross-fading from a previous skinning-based animation or rigid body animation.
|
||||||
|
*
|
||||||
|
* First, this stashes the current transform hierarchy into a transient memory buffer.
|
||||||
|
*
|
||||||
|
* Next, this applies previousAnimIndex / previousAnimTime to the actual asset by internally
|
||||||
|
* calling applyAnimation().
|
||||||
|
*
|
||||||
|
* Finally, the stashed local transforms are lerped (via the scale / translation / rotation
|
||||||
|
* components) with their live counterparts, and the results are pushed to the asset.
|
||||||
|
*
|
||||||
|
* To achieve a cross fade effect with skinned models, clients will typically call animator
|
||||||
|
* methods in this order: (1) applyAnimation (2) applyCrossFade (3) updateBoneMatrices. The
|
||||||
|
* animation that clients pass to applyAnimation is the "current" animation corresponding to
|
||||||
|
* alpha=1, while the "previous" animation passed to applyCrossFade corresponds to alpha=0.
|
||||||
|
*/
|
||||||
|
void applyCrossFade(size_t previousAnimIndex, float previousAnimTime, float alpha);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pass the identity matrix into all bone nodes, useful for returning to the T pose.
|
||||||
|
*
|
||||||
|
* NOTE: this operation is independent of \c animation.
|
||||||
|
*/
|
||||||
|
void resetBoneMatrices();
|
||||||
|
|
||||||
/** Returns the number of \c animation definitions in the glTF asset. */
|
/** Returns the number of \c animation definitions in the glTF asset. */
|
||||||
size_t getAnimationCount() const;
|
size_t getAnimationCount() const;
|
||||||
|
|
||||||
@@ -88,6 +114,6 @@ private:
|
|||||||
AnimatorImpl* mImpl;
|
AnimatorImpl* mImpl;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gltfio
|
} // namespace filament::gltfio
|
||||||
|
|
||||||
#endif // GLTFIO_ANIMATOR_H
|
#endif // GLTFIO_ANIMATOR_H
|
||||||
|
|||||||
@@ -34,7 +34,9 @@ namespace utils {
|
|||||||
/**
|
/**
|
||||||
* Loader and pipeline for glTF 2.0 assets.
|
* Loader and pipeline for glTF 2.0 assets.
|
||||||
*/
|
*/
|
||||||
namespace gltfio {
|
namespace filament::gltfio {
|
||||||
|
|
||||||
|
class NodeManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \struct AssetConfiguration AssetLoader.h gltfio/AssetLoader.h
|
* \struct AssetConfiguration AssetLoader.h gltfio/AssetLoader.h
|
||||||
@@ -47,7 +49,7 @@ struct AssetConfiguration {
|
|||||||
|
|
||||||
//! Controls whether the loader uses filamat to generate materials on the fly, or loads a small
|
//! Controls whether the loader uses filamat to generate materials on the fly, or loads a small
|
||||||
//! set of precompiled ubershader materials. Deleting the MaterialProvider is the client's
|
//! set of precompiled ubershader materials. Deleting the MaterialProvider is the client's
|
||||||
//! responsibility. See createMaterialGenerator() and createUbershaderLoader().
|
//! responsibility. See createJitShaderProvider() and createUbershaderProvider().
|
||||||
MaterialProvider* materials;
|
MaterialProvider* materials;
|
||||||
|
|
||||||
//! Optional manager for associating string names with entities in the transform hierarchy.
|
//! Optional manager for associating string names with entities in the transform hierarchy.
|
||||||
@@ -70,7 +72,8 @@ struct AssetConfiguration {
|
|||||||
* object, which is a bundle of Filament entities, material instances, textures, vertex buffers,
|
* object, which is a bundle of Filament entities, material instances, textures, vertex buffers,
|
||||||
* and index buffers.
|
* and index buffers.
|
||||||
*
|
*
|
||||||
* Clients must use AssetLoader to create and destroy FilamentAsset objects.
|
* Clients must use AssetLoader to create and destroy FilamentAsset objects. This is similar to
|
||||||
|
* how filament::Engine is used to create and destroy core objects like VertexBuffer.
|
||||||
*
|
*
|
||||||
* AssetLoader does not fetch external buffer data or create textures on its own. Clients can use
|
* AssetLoader does not fetch external buffer data or create textures on its own. Clients can use
|
||||||
* ResourceLoader for this, which obtains the URI list from the asset. This is demonstrated in the
|
* ResourceLoader for this, which obtains the URI list from the asset. This is demonstrated in the
|
||||||
@@ -83,7 +86,8 @@ struct AssetConfiguration {
|
|||||||
*
|
*
|
||||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
* auto engine = Engine::create();
|
* auto engine = Engine::create();
|
||||||
* auto materials = createMaterialGenerator(engine);
|
* auto materials = createJitShaderProvider(engine);
|
||||||
|
* auto decoder = createStbProvider(engine);
|
||||||
* auto loader = AssetLoader::create({engine, materials});
|
* auto loader = AssetLoader::create({engine, materials});
|
||||||
*
|
*
|
||||||
* // Parse the glTF content and create Filament entities.
|
* // Parse the glTF content and create Filament entities.
|
||||||
@@ -92,7 +96,10 @@ struct AssetConfiguration {
|
|||||||
* content.clear();
|
* content.clear();
|
||||||
*
|
*
|
||||||
* // Load buffers and textures from disk.
|
* // Load buffers and textures from disk.
|
||||||
* ResourceLoader({engine, ".", true}).loadResources(asset);
|
* ResourceLoader resourceLoader({engine, ".", true});
|
||||||
|
* resourceLoader.addTextureProvider("image/png", decoder)
|
||||||
|
* resourceLoader.addTextureProvider("image/jpeg", decoder)
|
||||||
|
* resourceLoader.loadResources(asset);
|
||||||
*
|
*
|
||||||
* // Free the glTF hierarchy as it is no longer needed.
|
* // Free the glTF hierarchy as it is no longer needed.
|
||||||
* asset->releaseSourceData();
|
* asset->releaseSourceData();
|
||||||
@@ -114,6 +121,7 @@ struct AssetConfiguration {
|
|||||||
* loader->destroyAsset(asset);
|
* loader->destroyAsset(asset);
|
||||||
* materials->destroyMaterials();
|
* materials->destroyMaterials();
|
||||||
* delete materials;
|
* delete materials;
|
||||||
|
* delete decoder;
|
||||||
* AssetLoader::destroy(&loader);
|
* AssetLoader::destroy(&loader);
|
||||||
* Engine::destroy(&engine);
|
* Engine::destroy(&engine);
|
||||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
@@ -221,7 +229,9 @@ public:
|
|||||||
|
|
||||||
utils::NameComponentManager* getNames() const noexcept;
|
utils::NameComponentManager* getNames() const noexcept;
|
||||||
|
|
||||||
MaterialProvider* getMaterialProvider() const noexcept;
|
NodeManager& getNodeManager() noexcept;
|
||||||
|
|
||||||
|
MaterialProvider& getMaterialProvider() noexcept;
|
||||||
|
|
||||||
/*! \cond PRIVATE */
|
/*! \cond PRIVATE */
|
||||||
protected:
|
protected:
|
||||||
@@ -236,6 +246,6 @@ public:
|
|||||||
/*! \endcond */
|
/*! \endcond */
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gltfio
|
} // namespace filament::gltfio
|
||||||
|
|
||||||
#endif // GLTFIO_ASSETLOADER_H
|
#endif // GLTFIO_ASSETLOADER_H
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
#include <filament/Box.h>
|
#include <filament/Box.h>
|
||||||
#include <filament/TextureSampler.h>
|
#include <filament/TextureSampler.h>
|
||||||
|
|
||||||
|
#include <gltfio/NodeManager.h>
|
||||||
|
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
#include <utils/Entity.h>
|
#include <utils/Entity.h>
|
||||||
|
|
||||||
@@ -27,9 +29,10 @@ namespace filament {
|
|||||||
class Camera;
|
class Camera;
|
||||||
class Engine;
|
class Engine;
|
||||||
class MaterialInstance;
|
class MaterialInstance;
|
||||||
|
class Scene;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace gltfio {
|
namespace filament::gltfio {
|
||||||
|
|
||||||
class Animator;
|
class Animator;
|
||||||
class FilamentInstance;
|
class FilamentInstance;
|
||||||
@@ -42,7 +45,7 @@ class FilamentInstance;
|
|||||||
*
|
*
|
||||||
* This class owns a hierarchy of entities that have been loaded from a glTF asset. Every entity has
|
* This class owns a hierarchy of entities that have been loaded from a glTF asset. Every entity has
|
||||||
* a filament::TransformManager component, and some entities also have \c Name, \c Renderable,
|
* a filament::TransformManager component, and some entities also have \c Name, \c Renderable,
|
||||||
* \c Light, or \c Camera components.
|
* \c Light, \c Camera, or \c Node components.
|
||||||
*
|
*
|
||||||
* In addition to the aforementioned entities, an asset has strong ownership over a list of
|
* In addition to the aforementioned entities, an asset has strong ownership over a list of
|
||||||
* filament::VertexBuffer, filament::IndexBuffer, filament::MaterialInstance, filament::Texture,
|
* filament::VertexBuffer, filament::IndexBuffer, filament::MaterialInstance, filament::Texture,
|
||||||
@@ -55,12 +58,14 @@ class FilamentInstance;
|
|||||||
*/
|
*/
|
||||||
class UTILS_PUBLIC FilamentAsset {
|
class UTILS_PUBLIC FilamentAsset {
|
||||||
public:
|
public:
|
||||||
|
using Entity = utils::Entity;
|
||||||
|
using SceneMask = NodeManager::SceneMask;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the list of entities, one for each glTF node. All of these have a Transform component.
|
* Gets the list of entities, one for each glTF node. All of these have a Transform component.
|
||||||
* Some of the returned entities may also have a Renderable component and/or a Light component.
|
* Some of the returned entities may also have a Renderable component and/or a Light component.
|
||||||
*/
|
*/
|
||||||
const utils::Entity* getEntities() const noexcept;
|
const Entity* getEntities() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the number of entities returned by getEntities().
|
* Gets the number of entities returned by getEntities().
|
||||||
@@ -70,13 +75,23 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Gets the list of entities in the scene representing lights. All of these have a Light component.
|
* Gets the list of entities in the scene representing lights. All of these have a Light component.
|
||||||
*/
|
*/
|
||||||
const utils::Entity* getLightEntities() const noexcept;
|
const Entity* getLightEntities() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the number of entities returned by getLightEntities().
|
* Gets the number of entities returned by getLightEntities().
|
||||||
*/
|
*/
|
||||||
size_t getLightEntityCount() const noexcept;
|
size_t getLightEntityCount() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of entities in the asset that have renderable components.
|
||||||
|
*/
|
||||||
|
const utils::Entity* getRenderableEntities() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of entities returned by getRenderableEntities().
|
||||||
|
*/
|
||||||
|
size_t getRenderableEntityCount() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the list of entities in the scene representing cameras. All of these have a \c Camera
|
* Gets the list of entities in the scene representing cameras. All of these have a \c Camera
|
||||||
* component.
|
* component.
|
||||||
@@ -95,7 +110,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @see filament::Camera::setScaling
|
* @see filament::Camera::setScaling
|
||||||
*/
|
*/
|
||||||
const utils::Entity* getCameraEntities() const noexcept;
|
const Entity* getCameraEntities() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the number of entities returned by getCameraEntities().
|
* Gets the number of entities returned by getCameraEntities().
|
||||||
@@ -109,7 +124,7 @@ public:
|
|||||||
* assets, this is a "super root" where each of its children is a root in a particular instance.
|
* assets, this is a "super root" where each of its children is a root in a particular instance.
|
||||||
* This allows users to transform all instances en masse if they wish to do so.
|
* This allows users to transform all instances en masse if they wish to do so.
|
||||||
*/
|
*/
|
||||||
utils::Entity getRoot() const noexcept;
|
Entity getRoot() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pops a ready renderable off the queue, or returns 0 if no renderables have become ready.
|
* Pops a ready renderable off the queue, or returns 0 if no renderables have become ready.
|
||||||
@@ -122,12 +137,12 @@ public:
|
|||||||
* textures gradually become ready through asynchronous loading. For example, on every frame
|
* textures gradually become ready through asynchronous loading. For example, on every frame
|
||||||
* progressive applications can do something like this:
|
* progressive applications can do something like this:
|
||||||
*
|
*
|
||||||
* while (utils::Entity e = popRenderable()) { scene.addEntity(e); }
|
* while (Entity e = popRenderable()) { scene.addEntity(e); }
|
||||||
*
|
*
|
||||||
* \see ResourceLoader#asyncBeginLoad
|
* \see ResourceLoader#asyncBeginLoad
|
||||||
* \see popRenderables()
|
* \see popRenderables()
|
||||||
*/
|
*/
|
||||||
utils::Entity popRenderable() noexcept;
|
Entity popRenderable() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pops up to "count" ready renderables off the queue, or returns the available number.
|
* Pops up to "count" ready renderables off the queue, or returns the available number.
|
||||||
@@ -138,7 +153,7 @@ public:
|
|||||||
*
|
*
|
||||||
* \see ResourceLoader#asyncBeginLoad
|
* \see ResourceLoader#asyncBeginLoad
|
||||||
*/
|
*/
|
||||||
size_t popRenderables(utils::Entity* entities, size_t count) noexcept;
|
size_t popRenderables(Entity* entities, size_t count) noexcept;
|
||||||
|
|
||||||
/** Gets all material instances. These are already bound to renderables. */
|
/** Gets all material instances. These are already bound to renderables. */
|
||||||
const filament::MaterialInstance* const* getMaterialInstances() const noexcept;
|
const filament::MaterialInstance* const* getMaterialInstances() const noexcept;
|
||||||
@@ -159,10 +174,10 @@ public:
|
|||||||
filament::Aabb getBoundingBox() const noexcept;
|
filament::Aabb getBoundingBox() const noexcept;
|
||||||
|
|
||||||
/** Gets the NameComponentManager label for the given entity, if it exists. */
|
/** Gets the NameComponentManager label for the given entity, if it exists. */
|
||||||
const char* getName(utils::Entity) const noexcept;
|
const char* getName(Entity) const noexcept;
|
||||||
|
|
||||||
/** Returns the first entity with the given name, or 0 if none exist. */
|
/** Returns the first entity with the given name, or 0 if none exist. */
|
||||||
utils::Entity getFirstEntityByName(const char* name) noexcept;
|
Entity getFirstEntityByName(const char* name) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a list of entities with the given name.
|
* Gets a list of entities with the given name.
|
||||||
@@ -174,7 +189,7 @@ public:
|
|||||||
* @return If entities is non-null, the number of entities written to the entity pointer.
|
* @return If entities is non-null, the number of entities written to the entity pointer.
|
||||||
* Otherwise this returns the number of entities with the given name.
|
* Otherwise this returns the number of entities with the given name.
|
||||||
*/
|
*/
|
||||||
size_t getEntitiesByName(const char* name, utils::Entity* entities,
|
size_t getEntitiesByName(const char* name, Entity* entities,
|
||||||
size_t maxCount) const noexcept;
|
size_t maxCount) const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -187,11 +202,11 @@ public:
|
|||||||
* @return If entities is non-null, the number of entities written to the entity pointer.
|
* @return If entities is non-null, the number of entities written to the entity pointer.
|
||||||
* Otherwise this returns the number of entities with the given prefix.
|
* Otherwise this returns the number of entities with the given prefix.
|
||||||
*/
|
*/
|
||||||
size_t getEntitiesByPrefix(const char* prefix, utils::Entity* entities,
|
size_t getEntitiesByPrefix(const char* prefix, Entity* entities,
|
||||||
size_t maxCount) const noexcept;
|
size_t maxCount) const noexcept;
|
||||||
|
|
||||||
/** Gets the glTF extras string for a specific node, or for the asset, if it exists. */
|
/** Gets the glTF extras string for a specific node, or for the asset, if it exists. */
|
||||||
const char* getExtras(utils::Entity entity = {}) const noexcept;
|
const char* getExtras(Entity entity = {}) const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the animation engine.
|
* Returns the animation engine.
|
||||||
@@ -221,17 +236,32 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Gets joints at skin index.
|
* Gets joints at skin index.
|
||||||
*/
|
*/
|
||||||
const utils::Entity* getJointsAt(size_t skinIndex) const noexcept;
|
const Entity* getJointsAt(size_t skinIndex) const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attaches the given skin to the given node, which must have an associated mesh with
|
||||||
|
* BONE_INDICES and BONE_WEIGHTS attributes.
|
||||||
|
*
|
||||||
|
* This is a no-op if the given skin index or target is invalid.
|
||||||
|
*/
|
||||||
|
void attachSkin(size_t skinIndex, Entity target) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detaches the given skin from the given node.
|
||||||
|
*
|
||||||
|
* This is a no-op if the given skin index or target is invalid.
|
||||||
|
*/
|
||||||
|
void detachSkin(size_t skinIndex, Entity target) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the morph target name at the given index in the given entity.
|
* Gets the morph target name at the given index in the given entity.
|
||||||
*/
|
*/
|
||||||
const char* getMorphTargetNameAt(utils::Entity entity, size_t targetIndex) const noexcept;
|
const char* getMorphTargetNameAt(Entity entity, size_t targetIndex) const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of morph targets in the given entity.
|
* Returns the number of morph targets in the given entity.
|
||||||
*/
|
*/
|
||||||
size_t getMorphTargetCountAt(utils::Entity entity) const noexcept;
|
size_t getMorphTargetCountAt(Entity entity) const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of material variants in the asset.
|
* Returns the number of material variants in the asset.
|
||||||
@@ -261,7 +291,7 @@ public:
|
|||||||
* Lazily creates a single LINES renderable that draws the transformed bounding-box hierarchy
|
* Lazily creates a single LINES renderable that draws the transformed bounding-box hierarchy
|
||||||
* for diagnostic purposes. The wireframe is owned by the asset so clients should not delete it.
|
* for diagnostic purposes. The wireframe is owned by the asset so clients should not delete it.
|
||||||
*/
|
*/
|
||||||
utils::Entity getWireframe() noexcept;
|
Entity getWireframe() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the Filament engine associated with the AssetLoader that created this asset.
|
* Returns the Filament engine associated with the AssetLoader that created this asset.
|
||||||
@@ -282,6 +312,28 @@ public:
|
|||||||
*/
|
*/
|
||||||
const void* getSourceAsset() noexcept;
|
const void* getSourceAsset() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of scenes in the asset.
|
||||||
|
*/
|
||||||
|
size_t getSceneCount() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the given scene.
|
||||||
|
*
|
||||||
|
* Returns null if the given scene does not have a name or is out of bounds.
|
||||||
|
*/
|
||||||
|
const char* getSceneName(size_t sceneIndex) const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds entities to a Filament scene only if they belong to at least one of the given glTF
|
||||||
|
* scenes.
|
||||||
|
*
|
||||||
|
* This is just a helper that provides an alternative to directly calling scene->addEntities()
|
||||||
|
* and provides filtering functionality.
|
||||||
|
*/
|
||||||
|
void addEntitiesToScene(filament::Scene& targetScene, const Entity* entities, size_t count,
|
||||||
|
SceneMask sceneFilter);
|
||||||
|
|
||||||
/*! \cond PRIVATE */
|
/*! \cond PRIVATE */
|
||||||
|
|
||||||
FilamentInstance** getAssetInstances() noexcept;
|
FilamentInstance** getAssetInstances() noexcept;
|
||||||
@@ -299,6 +351,6 @@ public:
|
|||||||
/*! \endcond */
|
/*! \endcond */
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gltfio
|
} // namespace filament::gltfio
|
||||||
|
|
||||||
#endif // GLTFIO_FILAMENTASSET_H
|
#endif // GLTFIO_FILAMENTASSET_H
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
#include <utils/Entity.h>
|
#include <utils/Entity.h>
|
||||||
|
|
||||||
namespace gltfio {
|
namespace filament::gltfio {
|
||||||
|
|
||||||
class Animator;
|
class Animator;
|
||||||
class FilamentAsset;
|
class FilamentAsset;
|
||||||
@@ -76,6 +76,6 @@ public:
|
|||||||
Animator* getAnimator() noexcept;
|
Animator* getAnimator() noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gltfio
|
} // namespace filament::gltfio
|
||||||
|
|
||||||
#endif // GLTFIO_FILAMENTINSTANCE_H
|
#endif // GLTFIO_FILAMENTINSTANCE_H
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace gltfio {
|
namespace filament::gltfio {
|
||||||
|
|
||||||
enum class AlphaMode : uint8_t {
|
enum class AlphaMode : uint8_t {
|
||||||
OPAQUE,
|
OPAQUE,
|
||||||
@@ -118,12 +118,12 @@ inline uint8_t getNumUvSets(const UvMap& uvmap) {
|
|||||||
* \class MaterialProvider MaterialProvider.h gltfio/MaterialProvider.h
|
* \class MaterialProvider MaterialProvider.h gltfio/MaterialProvider.h
|
||||||
* \brief Interface to a provider of glTF materials (has two implementations).
|
* \brief Interface to a provider of glTF materials (has two implementations).
|
||||||
*
|
*
|
||||||
* - The \c MaterialGenerator implementation generates materials at run time (which can be slow) and
|
* - The \c JitShaderProvider implementation generates materials at run time (which can be slow) and
|
||||||
* requires the filamat library, but produces streamlined shaders. See createMaterialGenerator().
|
* requires the filamat library, but produces streamlined shaders. See createJitShaderProvider().
|
||||||
*
|
*
|
||||||
* - The \c UbershaderLoader implementation uses a small number of pre-built materials with complex
|
* - The \c UbershaderProvider implementation uses a small number of pre-built materials with complex
|
||||||
* fragment shaders, but does not require any run time work or usage of filamat. See
|
* fragment shaders, but does not require any run time work or usage of filamat. See
|
||||||
* createUbershaderLoader().
|
* createUbershaderProvider().
|
||||||
*
|
*
|
||||||
* Both implementations of MaterialProvider maintain a small cache of materials which must be
|
* Both implementations of MaterialProvider maintain a small cache of materials which must be
|
||||||
* explicitly freed using destroyMaterials(). These materials are not freed automatically when the
|
* explicitly freed using destroyMaterials(). These materials are not freed automatically when the
|
||||||
@@ -186,23 +186,22 @@ void processShaderString(std::string* shader, const UvMap& uvmap,
|
|||||||
*
|
*
|
||||||
* Requires \c libfilamat to be linked in. Not available in \c libgltfio_core.
|
* Requires \c libfilamat to be linked in. Not available in \c libgltfio_core.
|
||||||
*
|
*
|
||||||
* @see createUbershaderLoader
|
* @see createUbershaderProvider
|
||||||
*/
|
*/
|
||||||
UTILS_PUBLIC
|
UTILS_PUBLIC
|
||||||
MaterialProvider* createMaterialGenerator(filament::Engine* engine, bool optimizeShaders = false);
|
MaterialProvider* createJitShaderProvider(filament::Engine* engine, bool optimizeShaders = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a material provider that loads a small set of pre-built materials.
|
* Creates a material provider that loads a small set of pre-built materials.
|
||||||
*
|
*
|
||||||
* @return New material provider that can quickly load a material from a cache.
|
* @return New material provider that can quickly load a material from a cache.
|
||||||
*
|
*
|
||||||
* Requires \c libgltfio_resources to be linked in.
|
* @see createJitShaderProvider
|
||||||
*
|
|
||||||
* @see createMaterialGenerator
|
|
||||||
*/
|
*/
|
||||||
UTILS_PUBLIC
|
UTILS_PUBLIC
|
||||||
MaterialProvider* createUbershaderLoader(filament::Engine* engine);
|
MaterialProvider* createUbershaderProvider(filament::Engine* engine, const void* archive,
|
||||||
|
size_t archiveByteCount);
|
||||||
|
|
||||||
} // namespace gltfio
|
} // namespace filament::gltfio
|
||||||
|
|
||||||
#endif // GLTFIO_MATERIALPROVIDER_H
|
#endif // GLTFIO_MATERIALPROVIDER_H
|
||||||
|
|||||||
110
ios/include/gltfio/NodeManager.h
Normal file
110
ios/include/gltfio/NodeManager.h
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GLTFIO_NODEMANAGER_H
|
||||||
|
#define GLTFIO_NODEMANAGER_H
|
||||||
|
|
||||||
|
#include <filament/FilamentAPI.h>
|
||||||
|
|
||||||
|
#include <utils/bitset.h>
|
||||||
|
#include <utils/compiler.h>
|
||||||
|
#include <utils/CString.h>
|
||||||
|
#include <utils/EntityInstance.h>
|
||||||
|
#include <utils/FixedCapacityVector.h>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
class Entity;
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
namespace filament::gltfio {
|
||||||
|
|
||||||
|
class FNodeManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NodeManager is used to add annotate entities with glTF-specific information.
|
||||||
|
*
|
||||||
|
* Node components are created by gltfio and exposed to users to allow inspection.
|
||||||
|
*
|
||||||
|
* Nodes do not store the glTF hierarchy or names; see TransformManager and NameComponentManager.
|
||||||
|
*/
|
||||||
|
class UTILS_PUBLIC NodeManager {
|
||||||
|
public:
|
||||||
|
using Instance = utils::EntityInstance<NodeManager>;
|
||||||
|
using Entity = utils::Entity;
|
||||||
|
using CString = utils::CString;
|
||||||
|
using SceneMask = utils::bitset32;
|
||||||
|
|
||||||
|
static constexpr size_t MAX_SCENE_COUNT = 32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether a particular Entity is associated with a component of this NodeManager
|
||||||
|
* @param e An Entity.
|
||||||
|
* @return true if this Entity has a component associated with this manager.
|
||||||
|
*/
|
||||||
|
bool hasComponent(Entity e) const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an Instance representing the node component associated with the given Entity.
|
||||||
|
* @param e An Entity.
|
||||||
|
* @return An Instance object, which represents the node component associated with the Entity e.
|
||||||
|
* @note Use Instance::isValid() to make sure the component exists.
|
||||||
|
* @see hasComponent()
|
||||||
|
*/
|
||||||
|
Instance getInstance(Entity e) const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a node component and associates it with the given entity.
|
||||||
|
* @param entity An Entity to associate a node component with.
|
||||||
|
*
|
||||||
|
* If this component already exists on the given entity, it is first destroyed as if
|
||||||
|
* destroy(Entity e) was called.
|
||||||
|
*
|
||||||
|
* @see destroy()
|
||||||
|
*/
|
||||||
|
void create(Entity entity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys this component from the given entity.
|
||||||
|
* @param e An entity.
|
||||||
|
*
|
||||||
|
* @see create()
|
||||||
|
*/
|
||||||
|
void destroy(Entity e) noexcept;
|
||||||
|
|
||||||
|
void setMorphTargetNames(Instance ci, utils::FixedCapacityVector<CString> names) noexcept;
|
||||||
|
const utils::FixedCapacityVector<CString>& getMorphTargetNames(Instance ci) const noexcept;
|
||||||
|
|
||||||
|
void setExtras(Instance ci, CString extras) noexcept;
|
||||||
|
const CString& getExtras(Instance ci) const noexcept;
|
||||||
|
|
||||||
|
void setSceneMembership(Instance ci, SceneMask scenes) noexcept;
|
||||||
|
SceneMask getSceneMembership(Instance ci) const noexcept;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
NodeManager() noexcept = default;
|
||||||
|
~NodeManager() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
NodeManager(NodeManager const&) = delete;
|
||||||
|
NodeManager(NodeManager&&) = delete;
|
||||||
|
NodeManager& operator=(NodeManager const&) = delete;
|
||||||
|
NodeManager& operator=(NodeManager&&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace filament::gltfio
|
||||||
|
|
||||||
|
|
||||||
|
#endif // GLTFIO_NODEMANAGER_H
|
||||||
@@ -27,10 +27,11 @@ namespace filament {
|
|||||||
class Engine;
|
class Engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace gltfio {
|
namespace filament::gltfio {
|
||||||
|
|
||||||
struct FFilamentAsset;
|
struct FFilamentAsset;
|
||||||
class AssetPool;
|
class AssetPool;
|
||||||
|
class TextureProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \struct ResourceConfiguration ResourceLoader.h gltfio/ResourceLoader.h
|
* \struct ResourceConfiguration ResourceLoader.h gltfio/ResourceLoader.h
|
||||||
@@ -53,8 +54,8 @@ struct ResourceConfiguration {
|
|||||||
//! do not need this, but it is useful for robustness.
|
//! do not need this, but it is useful for robustness.
|
||||||
bool recomputeBoundingBoxes;
|
bool recomputeBoundingBoxes;
|
||||||
|
|
||||||
//! If true, ignore skinned primitives bind transform when compute bounding box. Implicitly true
|
//! If true, ignores skinning when computing bounding boxes. Implicitly true for instanced
|
||||||
//! for instanced asset. Only applicable when recomputeBoundingBoxes is set to true
|
//! assets. Only applicable when recomputeBoundingBoxes is set to true.
|
||||||
bool ignoreBindTransform;
|
bool ignoreBindTransform;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -94,6 +95,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
void addResourceData(const char* uri, BufferDescriptor&& buffer);
|
void addResourceData(const char* uri, BufferDescriptor&& buffer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a plugin that can consume PNG / JPEG content and produce filament::Texture objects.
|
||||||
|
*
|
||||||
|
* Destruction of the given provider is the client's responsibility.
|
||||||
|
*/
|
||||||
|
void addTextureProvider(const char* mimeType, TextureProvider* provider);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the given resource has already been added to the URI cache.
|
* Checks if the given resource has already been added to the URI cache.
|
||||||
*/
|
*/
|
||||||
@@ -153,7 +161,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool loadResources(FFilamentAsset* asset, bool async);
|
bool loadResources(FFilamentAsset* asset, bool async);
|
||||||
void applySparseData(FFilamentAsset* asset) const;
|
|
||||||
void normalizeSkinningWeights(FFilamentAsset* asset) const;
|
void normalizeSkinningWeights(FFilamentAsset* asset) const;
|
||||||
void updateBoundingBoxes(FFilamentAsset* asset) const;
|
void updateBoundingBoxes(FFilamentAsset* asset) const;
|
||||||
AssetPool* mPool;
|
AssetPool* mPool;
|
||||||
@@ -161,7 +168,7 @@ private:
|
|||||||
Impl* pImpl;
|
Impl* pImpl;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gltfio
|
} // namespace filament::gltfio
|
||||||
|
|
||||||
#endif // GLTFIO_RESOURCELOADER_H
|
#endif // GLTFIO_RESOURCELOADER_H
|
||||||
|
|
||||||
|
|||||||
180
ios/include/gltfio/TextureProvider.h
Normal file
180
ios/include/gltfio/TextureProvider.h
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GLTFIO_TEXTUREPROVIDER_H
|
||||||
|
#define GLTFIO_TEXTUREPROVIDER_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <utils/compiler.h>
|
||||||
|
|
||||||
|
namespace filament {
|
||||||
|
class Engine;
|
||||||
|
class Texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace filament::gltfio {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TextureProvider is an interface that allows clients to implement their own texture decoding
|
||||||
|
* facility for JPEG, PNG, or KTX2 content. It constructs Filament Texture objects synchronously,
|
||||||
|
* but populates their miplevels asynchronously.
|
||||||
|
*
|
||||||
|
* gltfio calls all public methods from the foreground thread, i.e. the thread that the Filament
|
||||||
|
* engine was created with. However the implementation may create 0 or more background threads to
|
||||||
|
* perform decoding work.
|
||||||
|
*
|
||||||
|
* The following pseudocode illustrates how this interface could be used, but in practice the only
|
||||||
|
* client is the gltfio ResourceLoader.
|
||||||
|
*
|
||||||
|
* filament::Engine* engine = ...;
|
||||||
|
* TextureProvider* provider = createStbProvider(engine);
|
||||||
|
*
|
||||||
|
* for (auto filename : textureFiles) {
|
||||||
|
* std::vector<uint8_t> buf = readEntireFile(filename);
|
||||||
|
* Texture* texture = provider->pushTexture(buf.data(), buf.size(), "image/png", 0);
|
||||||
|
* if (texture == nullptr) { puts(provider->getPushMessage()); exit(1); }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // At this point, the returned textures can be bound to material instances, but none of their
|
||||||
|
* // miplevel images have been populated yet.
|
||||||
|
*
|
||||||
|
* while (provider->getPoppedCount() < provider->getPushedCount()) {
|
||||||
|
* sleep(200);
|
||||||
|
*
|
||||||
|
* // The following call gives the provider an opportunity to reap the results of any
|
||||||
|
* // background decoder work that has been completed (e.g. by calling Texture::setImage).
|
||||||
|
* provider->updateQueue();
|
||||||
|
*
|
||||||
|
* // Check for textures that now have all their miplevels initialized.
|
||||||
|
* while (Texture* texture = provider->popTexture()) {
|
||||||
|
* printf("%p has all its miplevels ready.\n", texture);
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* delete provider;
|
||||||
|
*/
|
||||||
|
class UTILS_PUBLIC TextureProvider {
|
||||||
|
public:
|
||||||
|
using Texture = filament::Texture;
|
||||||
|
using FlagBits = uint64_t;
|
||||||
|
|
||||||
|
enum class Flags {
|
||||||
|
sRGB = 1 << 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Filament texture and pushes it to the asynchronous decoding queue.
|
||||||
|
*
|
||||||
|
* If construction fails, nothing is pushed to the queue and null is returned. The failure
|
||||||
|
* reason can be obtained with getPushMessage(). The given buffer pointer is not held, so the
|
||||||
|
* caller can free it immediately. It is also the caller's responsibility to free the returned
|
||||||
|
* Texture object, but it is only safe to do so after it has been popped from the queue.
|
||||||
|
*/
|
||||||
|
virtual Texture* pushTexture(const uint8_t* data, size_t byteCount,
|
||||||
|
const char* mimeType, FlagBits flags) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if any texture is ready to be removed from the asynchronous decoding queue, and if so
|
||||||
|
* pops it off.
|
||||||
|
*
|
||||||
|
* Unless an error or cancellation occurred during the decoding process, the returned texture
|
||||||
|
* should have all its miplevels populated. If the texture is not complete, the reason can be
|
||||||
|
* obtained with getPopMessage().
|
||||||
|
*
|
||||||
|
* Due to concurrency, textures are not necessarily popped off in the same order they were
|
||||||
|
* pushed. Returns null if there are no textures that are ready to be popped.
|
||||||
|
*/
|
||||||
|
virtual Texture* popTexture() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Polls textures in the queue and uploads mipmap images if any have emerged from the decoder.
|
||||||
|
*
|
||||||
|
* This gives the provider an opportunity to call Texture::setImage() on the foreground thread.
|
||||||
|
* If needed, it can also call Texture::generateMipmaps() here.
|
||||||
|
*
|
||||||
|
* Items in the decoding queue can become "poppable" only during this call.
|
||||||
|
*/
|
||||||
|
virtual void updateQueue() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a failure message for the most recent call to pushTexture(), or null for success.
|
||||||
|
*
|
||||||
|
* Note that this method does not pertain to the decoding process. If decoding fails, clients to
|
||||||
|
* can pop the incomplete texture off the queue and obtain a failure message using the
|
||||||
|
* getPopFailure() method.
|
||||||
|
*
|
||||||
|
* The returned string is owned by the provider and becomes invalid after the next call to
|
||||||
|
* pushTexture().
|
||||||
|
*/
|
||||||
|
virtual const char* getPushMessage() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a failure message for the most recent call to popTexture(), or null for success.
|
||||||
|
*
|
||||||
|
* If the most recent call to popTexture() returned null, then no error occurred and this
|
||||||
|
* returns null. If the most recent call to popTexture() returned a "complete" texture (i.e.
|
||||||
|
* all miplevels present), then this returns null. This returns non-null only if an error or
|
||||||
|
* cancellation occurred while decoding the popped texture.
|
||||||
|
*
|
||||||
|
* The returned string is owned by the provider and becomes invalid after the next call to
|
||||||
|
* popTexture().
|
||||||
|
*/
|
||||||
|
virtual const char* getPopMessage() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for all outstanding decoding jobs to complete.
|
||||||
|
*
|
||||||
|
* Clients should call updateQueue() afterwards if they wish to update the push / pop queue.
|
||||||
|
*/
|
||||||
|
virtual void waitForCompletion() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels all not-yet-started decoding jobs and waits for all other jobs to complete.
|
||||||
|
*
|
||||||
|
* Jobs that have already started cannot be canceled. Textures whose decoding process has
|
||||||
|
* been cancelled will be made poppable on the subsequent call to updateQueue().
|
||||||
|
*/
|
||||||
|
virtual void cancelDecoding() = 0;
|
||||||
|
|
||||||
|
/** Total number of successful push calls since the provider was created. */
|
||||||
|
virtual size_t getPushedCount() const = 0;
|
||||||
|
|
||||||
|
/** Total number of successful pop calls since the provider was created. */
|
||||||
|
virtual size_t getPoppedCount() const = 0;
|
||||||
|
|
||||||
|
/** Total number of textures that have become ready-to-pop since the provider was created. */
|
||||||
|
virtual size_t getDecodedCount() const = 0;
|
||||||
|
|
||||||
|
virtual ~TextureProvider() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a simple decoder based on stb_image that can handle "image/png" and "image/jpeg".
|
||||||
|
* This works only if your build configuration includes STB.
|
||||||
|
*/
|
||||||
|
TextureProvider* createStbProvider(filament::Engine* engine);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a decoder that can handle certain types of "image/ktx2" content as specified in
|
||||||
|
* the KHR_texture_basisu specification.
|
||||||
|
*/
|
||||||
|
TextureProvider* createKtx2Provider(filament::Engine* engine);
|
||||||
|
|
||||||
|
} // namespace filament::gltfio
|
||||||
|
|
||||||
|
#endif // GLTFIO_TEXTUREPROVIDER_H
|
||||||
13
ios/include/gltfio/materials/uberarchive.h
Normal file
13
ios/include/gltfio/materials/uberarchive.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef UBERARCHIVE_H_
|
||||||
|
#define UBERARCHIVE_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
extern const uint8_t UBERARCHIVE_PACKAGE[];
|
||||||
|
extern int UBERARCHIVE_DEFAULT_OFFSET;
|
||||||
|
extern int UBERARCHIVE_DEFAULT_SIZE;
|
||||||
|
}
|
||||||
|
#define UBERARCHIVE_DEFAULT_DATA (UBERARCHIVE_PACKAGE + UBERARCHIVE_DEFAULT_OFFSET)
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
#include <math/mat4.h>
|
#include <math/mat4.h>
|
||||||
#include <math/TVecHelpers.h>
|
#include <math/TVecHelpers.h>
|
||||||
|
|
||||||
namespace gltfio {
|
namespace filament::gltfio {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
UTILS_PUBLIC T cubicSpline(const T& vert0, const T& tang0, const T& vert1, const T& tang1, float t) {
|
UTILS_PUBLIC T cubicSpline(const T& vert0, const T& tang0, const T& vert1, const T& tang1, float t) {
|
||||||
@@ -121,6 +121,6 @@ inline filament::math::mat3f matrixFromUvTransform(const float offset[2], float
|
|||||||
return filament::math::mat3f(sx * c, sx * s, tx, -sy * s, sy * c, ty, 0.0f, 0.0f, 1.0f);
|
return filament::math::mat3f(sx * c, sx * s, tx, -sy * s, sy * c, ty, 0.0f, 0.0f, 1.0f);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gltfio
|
} // namespace filament::gltfio
|
||||||
|
|
||||||
#endif // GLTFIO_MATH_H
|
#endif // GLTFIO_MATH_H
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
#ifndef GLTFRESOURCES_H_
|
|
||||||
#define GLTFRESOURCES_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
extern const uint8_t GLTFRESOURCES_PACKAGE[];
|
|
||||||
extern int GLTFRESOURCES_LIT_FADE_OFFSET;
|
|
||||||
extern int GLTFRESOURCES_LIT_FADE_SIZE;
|
|
||||||
extern int GLTFRESOURCES_LIT_OPAQUE_OFFSET;
|
|
||||||
extern int GLTFRESOURCES_LIT_OPAQUE_SIZE;
|
|
||||||
extern int GLTFRESOURCES_LIT_MASKED_OFFSET;
|
|
||||||
extern int GLTFRESOURCES_LIT_MASKED_SIZE;
|
|
||||||
extern int GLTFRESOURCES_SPECULARGLOSSINESS_FADE_OFFSET;
|
|
||||||
extern int GLTFRESOURCES_SPECULARGLOSSINESS_FADE_SIZE;
|
|
||||||
extern int GLTFRESOURCES_SPECULARGLOSSINESS_OPAQUE_OFFSET;
|
|
||||||
extern int GLTFRESOURCES_SPECULARGLOSSINESS_OPAQUE_SIZE;
|
|
||||||
extern int GLTFRESOURCES_SPECULARGLOSSINESS_MASKED_OFFSET;
|
|
||||||
extern int GLTFRESOURCES_SPECULARGLOSSINESS_MASKED_SIZE;
|
|
||||||
extern int GLTFRESOURCES_UNLIT_FADE_OFFSET;
|
|
||||||
extern int GLTFRESOURCES_UNLIT_FADE_SIZE;
|
|
||||||
extern int GLTFRESOURCES_UNLIT_OPAQUE_OFFSET;
|
|
||||||
extern int GLTFRESOURCES_UNLIT_OPAQUE_SIZE;
|
|
||||||
extern int GLTFRESOURCES_UNLIT_MASKED_OFFSET;
|
|
||||||
extern int GLTFRESOURCES_UNLIT_MASKED_SIZE;
|
|
||||||
extern int GLTFRESOURCES_LIT_VOLUME_OFFSET;
|
|
||||||
extern int GLTFRESOURCES_LIT_VOLUME_SIZE;
|
|
||||||
extern int GLTFRESOURCES_LIT_TRANSMISSION_OFFSET;
|
|
||||||
extern int GLTFRESOURCES_LIT_TRANSMISSION_SIZE;
|
|
||||||
extern int GLTFRESOURCES_LIT_SHEEN_OFFSET;
|
|
||||||
extern int GLTFRESOURCES_LIT_SHEEN_SIZE;
|
|
||||||
}
|
|
||||||
#define GLTFRESOURCES_LIT_FADE_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_LIT_FADE_OFFSET)
|
|
||||||
#define GLTFRESOURCES_LIT_OPAQUE_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_LIT_OPAQUE_OFFSET)
|
|
||||||
#define GLTFRESOURCES_LIT_MASKED_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_LIT_MASKED_OFFSET)
|
|
||||||
#define GLTFRESOURCES_SPECULARGLOSSINESS_FADE_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_SPECULARGLOSSINESS_FADE_OFFSET)
|
|
||||||
#define GLTFRESOURCES_SPECULARGLOSSINESS_OPAQUE_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_SPECULARGLOSSINESS_OPAQUE_OFFSET)
|
|
||||||
#define GLTFRESOURCES_SPECULARGLOSSINESS_MASKED_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_SPECULARGLOSSINESS_MASKED_OFFSET)
|
|
||||||
#define GLTFRESOURCES_UNLIT_FADE_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_UNLIT_FADE_OFFSET)
|
|
||||||
#define GLTFRESOURCES_UNLIT_OPAQUE_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_UNLIT_OPAQUE_OFFSET)
|
|
||||||
#define GLTFRESOURCES_UNLIT_MASKED_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_UNLIT_MASKED_OFFSET)
|
|
||||||
#define GLTFRESOURCES_LIT_VOLUME_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_LIT_VOLUME_OFFSET)
|
|
||||||
#define GLTFRESOURCES_LIT_TRANSMISSION_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_LIT_TRANSMISSION_OFFSET)
|
|
||||||
#define GLTFRESOURCES_LIT_SHEEN_DATA (GLTFRESOURCES_PACKAGE + GLTFRESOURCES_LIT_SHEEN_OFFSET)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#ifndef GLTFRESOURCES_LITE_H_
|
|
||||||
#define GLTFRESOURCES_LITE_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
extern const uint8_t GLTFRESOURCES_LITE_PACKAGE[];
|
|
||||||
extern int GLTFRESOURCES_LITE_LIT_OPAQUE_OFFSET;
|
|
||||||
extern int GLTFRESOURCES_LITE_LIT_OPAQUE_SIZE;
|
|
||||||
extern int GLTFRESOURCES_LITE_LIT_FADE_OFFSET;
|
|
||||||
extern int GLTFRESOURCES_LITE_LIT_FADE_SIZE;
|
|
||||||
}
|
|
||||||
#define GLTFRESOURCES_LITE_LIT_OPAQUE_DATA (GLTFRESOURCES_LITE_PACKAGE + GLTFRESOURCES_LITE_LIT_OPAQUE_OFFSET)
|
|
||||||
#define GLTFRESOURCES_LITE_LIT_FADE_DATA (GLTFRESOURCES_LITE_PACKAGE + GLTFRESOURCES_LITE_LIT_FADE_OFFSET)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -158,8 +158,8 @@ inline filament::math::float3 linearToSRGB(const filament::math::float3& color)
|
|||||||
return sRGBColor;
|
return sRGBColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a n-channel sRGB image from a linear floating-point image.
|
// Creates a N-channel sRGB image from a linear floating-point image.
|
||||||
// The source image can have more than N channels, but only the first N are converted to sRGB.
|
// The source image can have more than N channels, but only the first 3 are converted to sRGB.
|
||||||
template<typename T, int N = 3>
|
template<typename T, int N = 3>
|
||||||
std::unique_ptr<uint8_t[]> fromLinearTosRGB(const LinearImage& image) {
|
std::unique_ptr<uint8_t[]> fromLinearTosRGB(const LinearImage& image) {
|
||||||
const size_t w = image.getWidth();
|
const size_t w = image.getWidth();
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef IMAGE_KTXBUNDLE_H
|
#ifndef IMAGE_KTX1BUNDLE_H
|
||||||
#define IMAGE_KTXBUNDLE_H
|
#define IMAGE_KTX1BUNDLE_H
|
||||||
|
|
||||||
#include <math/vec3.h>
|
#include <math/vec3.h>
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ struct KtxBlobList;
|
|||||||
struct KtxMetadata;
|
struct KtxMetadata;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* KtxBundle is a structured set of opaque data blobs that can be passed straight to the GPU, such
|
* Ktx1Bundle is a structured set of opaque data blobs that can be passed straight to the GPU, such
|
||||||
* that a single bundle corresponds to a single texture object. It is well suited for storing
|
* that a single bundle corresponds to a single texture object. It is well suited for storing
|
||||||
* block-compressed texture data.
|
* block-compressed texture data.
|
||||||
*
|
*
|
||||||
@@ -63,22 +63,22 @@ struct KtxMetadata;
|
|||||||
*
|
*
|
||||||
* https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
|
* https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
|
||||||
*/
|
*/
|
||||||
class UTILS_PUBLIC KtxBundle {
|
class UTILS_PUBLIC Ktx1Bundle {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
~KtxBundle();
|
~Ktx1Bundle();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a hierarchy of empty texture blobs, to be filled later via setBlob().
|
* Creates a hierarchy of empty texture blobs, to be filled later via setBlob().
|
||||||
*/
|
*/
|
||||||
KtxBundle(uint32_t numMipLevels, uint32_t arrayLength, bool isCubemap);
|
Ktx1Bundle(uint32_t numMipLevels, uint32_t arrayLength, bool isCubemap);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new bundle by deserializing the given data.
|
* Creates a new bundle by deserializing the given data.
|
||||||
*
|
*
|
||||||
* Typically, this constructor is used to consume the contents of a KTX file.
|
* Typically, this constructor is used to consume the contents of a KTX file.
|
||||||
*/
|
*/
|
||||||
KtxBundle(uint8_t const* bytes, uint32_t nbytes);
|
Ktx1Bundle(uint8_t const* bytes, uint32_t nbytes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serializes the bundle into the given target memory. Returns false if there's not enough
|
* Serializes the bundle into the given target memory. Returns false if there's not enough
|
||||||
@@ -276,4 +276,4 @@ private:
|
|||||||
|
|
||||||
} // namespace image
|
} // namespace image
|
||||||
|
|
||||||
#endif /* IMAGE_KTXBUNDLE_H */
|
#endif /* IMAGE_Ktx1Bundle_H */
|
||||||
@@ -1,367 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2018 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef IMAGE_KTXUTILITY_H
|
|
||||||
#define IMAGE_KTXUTILITY_H
|
|
||||||
|
|
||||||
#include <filament/Engine.h>
|
|
||||||
#include <filament/Texture.h>
|
|
||||||
|
|
||||||
#include <image/KtxBundle.h>
|
|
||||||
|
|
||||||
namespace image {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows clients to create Filament textures from KtxBundle objects.
|
|
||||||
*
|
|
||||||
* Note that libimage does not have a dependency on libfilament, so for simplicity this is a
|
|
||||||
* header-only library with inlined functions.
|
|
||||||
*/
|
|
||||||
namespace ktx {
|
|
||||||
|
|
||||||
using Texture = filament::Texture;
|
|
||||||
using Engine = filament::Engine;
|
|
||||||
|
|
||||||
using TextureFormat = Texture::InternalFormat;
|
|
||||||
using CompressedPixelDataType = Texture::CompressedType;
|
|
||||||
using PixelDataType = Texture::Type;
|
|
||||||
using PixelDataFormat = Texture::Format;
|
|
||||||
using PixelBufferDescriptor = Texture::PixelBufferDescriptor;
|
|
||||||
|
|
||||||
using Callback = void(*)(void* userdata);
|
|
||||||
|
|
||||||
CompressedPixelDataType toCompressedPixelDataType(const KtxInfo& info);
|
|
||||||
PixelDataType toPixelDataType(const KtxInfo& info);
|
|
||||||
PixelDataFormat toPixelDataFormat(const KtxInfo& info);
|
|
||||||
bool isCompressed(const KtxInfo& info);
|
|
||||||
TextureFormat toTextureFormat(const KtxInfo& info);
|
|
||||||
TextureFormat toSrgbTextureFormat(TextureFormat tex);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a Texture object from a KTX file and populates all of its faces and miplevels.
|
|
||||||
*
|
|
||||||
* @param engine Used to create the Filament Texture
|
|
||||||
* @param ktx In-memory representation of a KTX file
|
|
||||||
* @param srgb Forces the KTX-specified format into an SRGB format if possible
|
|
||||||
* @param callback Gets called after all texture data has been uploaded to the GPU
|
|
||||||
* @param userdata Passed into the callback
|
|
||||||
*/
|
|
||||||
inline Texture* createTexture(Engine* engine, const KtxBundle& ktx, bool srgb,
|
|
||||||
Callback callback, void* userdata) {
|
|
||||||
using Sampler = Texture::Sampler;
|
|
||||||
const auto& ktxinfo = ktx.getInfo();
|
|
||||||
const uint32_t nmips = ktx.getNumMipLevels();
|
|
||||||
const auto cdatatype = toCompressedPixelDataType(ktxinfo);
|
|
||||||
const auto datatype = toPixelDataType(ktxinfo);
|
|
||||||
const auto dataformat = toPixelDataFormat(ktxinfo);
|
|
||||||
|
|
||||||
auto texformat = toTextureFormat(ktxinfo);
|
|
||||||
if (srgb) {
|
|
||||||
texformat = toSrgbTextureFormat(texformat);
|
|
||||||
}
|
|
||||||
|
|
||||||
Texture* texture = Texture::Builder()
|
|
||||||
.width(ktxinfo.pixelWidth)
|
|
||||||
.height(ktxinfo.pixelHeight)
|
|
||||||
.levels(static_cast<uint8_t>(nmips))
|
|
||||||
.sampler(ktx.isCubemap() ? Sampler::SAMPLER_CUBEMAP : Sampler::SAMPLER_2D)
|
|
||||||
.format(texformat)
|
|
||||||
.build(*engine);
|
|
||||||
|
|
||||||
struct Userdata {
|
|
||||||
uint32_t remainingBuffers;
|
|
||||||
Callback callback;
|
|
||||||
void* userdata;
|
|
||||||
};
|
|
||||||
|
|
||||||
Userdata* cbuser = new Userdata({nmips, callback, userdata});
|
|
||||||
|
|
||||||
PixelBufferDescriptor::Callback cb = [](void*, size_t, void* cbuserptr) {
|
|
||||||
Userdata* cbuser = (Userdata*) cbuserptr;
|
|
||||||
if (--cbuser->remainingBuffers == 0) {
|
|
||||||
if (cbuser->callback) {
|
|
||||||
cbuser->callback(cbuser->userdata);
|
|
||||||
}
|
|
||||||
delete cbuser;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8_t* data;
|
|
||||||
uint32_t size;
|
|
||||||
|
|
||||||
if (isCompressed(ktxinfo)) {
|
|
||||||
if (ktx.isCubemap()) {
|
|
||||||
for (uint32_t level = 0; level < nmips; ++level) {
|
|
||||||
ktx.getBlob({level, 0, 0}, &data, &size);
|
|
||||||
PixelBufferDescriptor pbd(data, size * 6, cdatatype, size, cb, cbuser);
|
|
||||||
texture->setImage(*engine, level, std::move(pbd), Texture::FaceOffsets(size));
|
|
||||||
}
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
for (uint32_t level = 0; level < nmips; ++level) {
|
|
||||||
ktx.getBlob({level, 0, 0}, &data, &size);
|
|
||||||
PixelBufferDescriptor pbd(data, size, cdatatype, size, cb, cbuser);
|
|
||||||
texture->setImage(*engine, level, std::move(pbd));
|
|
||||||
}
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ktx.isCubemap()) {
|
|
||||||
for (uint32_t level = 0; level < nmips; ++level) {
|
|
||||||
ktx.getBlob({level, 0, 0}, &data, &size);
|
|
||||||
PixelBufferDescriptor pbd(data, size * 6, dataformat, datatype, cb, cbuser);
|
|
||||||
texture->setImage(*engine, level, std::move(pbd), Texture::FaceOffsets(size));
|
|
||||||
}
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t level = 0; level < nmips; ++level) {
|
|
||||||
ktx.getBlob({level, 0, 0}, &data, &size);
|
|
||||||
PixelBufferDescriptor pbd(data, size, dataformat, datatype, cb, cbuser);
|
|
||||||
texture->setImage(*engine, level, std::move(pbd));
|
|
||||||
}
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a Texture object from a KTX bundle, populates all of its faces and miplevels,
|
|
||||||
* and automatically destroys the bundle after all the texture data has been uploaded.
|
|
||||||
*
|
|
||||||
* @param engine Used to create the Filament Texture
|
|
||||||
* @param ktx In-memory representation of a KTX file
|
|
||||||
* @param srgb Forces the KTX-specified format into an SRGB format if possible
|
|
||||||
*/
|
|
||||||
inline Texture* createTexture(Engine* engine, KtxBundle* ktx, bool srgb) {
|
|
||||||
auto freeKtx = [] (void* userdata) {
|
|
||||||
KtxBundle* ktx = (KtxBundle*) userdata;
|
|
||||||
delete ktx;
|
|
||||||
};
|
|
||||||
return createTexture(engine, *ktx, srgb, freeKtx, ktx);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T toCompressedFilamentEnum(uint32_t format) {
|
|
||||||
switch (format) {
|
|
||||||
case KtxBundle::RGB_S3TC_DXT1: return T::DXT1_RGB;
|
|
||||||
case KtxBundle::RGBA_S3TC_DXT1: return T::DXT1_RGBA;
|
|
||||||
case KtxBundle::RGBA_S3TC_DXT3: return T::DXT3_RGBA;
|
|
||||||
case KtxBundle::RGBA_S3TC_DXT5: return T::DXT5_RGBA;
|
|
||||||
case KtxBundle::RGBA_ASTC_4x4: return T::RGBA_ASTC_4x4;
|
|
||||||
case KtxBundle::RGBA_ASTC_5x4: return T::RGBA_ASTC_5x4;
|
|
||||||
case KtxBundle::RGBA_ASTC_5x5: return T::RGBA_ASTC_5x5;
|
|
||||||
case KtxBundle::RGBA_ASTC_6x5: return T::RGBA_ASTC_6x5;
|
|
||||||
case KtxBundle::RGBA_ASTC_6x6: return T::RGBA_ASTC_6x6;
|
|
||||||
case KtxBundle::RGBA_ASTC_8x5: return T::RGBA_ASTC_8x5;
|
|
||||||
case KtxBundle::RGBA_ASTC_8x6: return T::RGBA_ASTC_8x6;
|
|
||||||
case KtxBundle::RGBA_ASTC_8x8: return T::RGBA_ASTC_8x8;
|
|
||||||
case KtxBundle::RGBA_ASTC_10x5: return T::RGBA_ASTC_10x5;
|
|
||||||
case KtxBundle::RGBA_ASTC_10x6: return T::RGBA_ASTC_10x6;
|
|
||||||
case KtxBundle::RGBA_ASTC_10x8: return T::RGBA_ASTC_10x8;
|
|
||||||
case KtxBundle::RGBA_ASTC_10x10: return T::RGBA_ASTC_10x10;
|
|
||||||
case KtxBundle::RGBA_ASTC_12x10: return T::RGBA_ASTC_12x10;
|
|
||||||
case KtxBundle::RGBA_ASTC_12x12: return T::RGBA_ASTC_12x12;
|
|
||||||
case KtxBundle::SRGB8_ALPHA8_ASTC_4x4: return T::SRGB8_ALPHA8_ASTC_4x4;
|
|
||||||
case KtxBundle::SRGB8_ALPHA8_ASTC_5x4: return T::SRGB8_ALPHA8_ASTC_5x4;
|
|
||||||
case KtxBundle::SRGB8_ALPHA8_ASTC_5x5: return T::SRGB8_ALPHA8_ASTC_5x5;
|
|
||||||
case KtxBundle::SRGB8_ALPHA8_ASTC_6x5: return T::SRGB8_ALPHA8_ASTC_6x5;
|
|
||||||
case KtxBundle::SRGB8_ALPHA8_ASTC_6x6: return T::SRGB8_ALPHA8_ASTC_6x6;
|
|
||||||
case KtxBundle::SRGB8_ALPHA8_ASTC_8x5: return T::SRGB8_ALPHA8_ASTC_8x5;
|
|
||||||
case KtxBundle::SRGB8_ALPHA8_ASTC_8x6: return T::SRGB8_ALPHA8_ASTC_8x6;
|
|
||||||
case KtxBundle::SRGB8_ALPHA8_ASTC_8x8: return T::SRGB8_ALPHA8_ASTC_8x8;
|
|
||||||
case KtxBundle::SRGB8_ALPHA8_ASTC_10x5: return T::SRGB8_ALPHA8_ASTC_10x5;
|
|
||||||
case KtxBundle::SRGB8_ALPHA8_ASTC_10x6: return T::SRGB8_ALPHA8_ASTC_10x6;
|
|
||||||
case KtxBundle::SRGB8_ALPHA8_ASTC_10x8: return T::SRGB8_ALPHA8_ASTC_10x8;
|
|
||||||
case KtxBundle::SRGB8_ALPHA8_ASTC_10x10: return T::SRGB8_ALPHA8_ASTC_10x10;
|
|
||||||
case KtxBundle::SRGB8_ALPHA8_ASTC_12x10: return T::SRGB8_ALPHA8_ASTC_12x10;
|
|
||||||
case KtxBundle::SRGB8_ALPHA8_ASTC_12x12: return T::SRGB8_ALPHA8_ASTC_12x12;
|
|
||||||
case KtxBundle::R11_EAC: return T::EAC_R11;
|
|
||||||
case KtxBundle::SIGNED_R11_EAC: return T::EAC_R11_SIGNED;
|
|
||||||
case KtxBundle::RG11_EAC: return T::EAC_RG11;
|
|
||||||
case KtxBundle::SIGNED_RG11_EAC: return T::EAC_RG11_SIGNED;
|
|
||||||
case KtxBundle::RGB8_ETC2: return T::ETC2_RGB8;
|
|
||||||
case KtxBundle::SRGB8_ETC2: return T::ETC2_SRGB8;
|
|
||||||
case KtxBundle::RGB8_ALPHA1_ETC2: return T::ETC2_RGB8_A1;
|
|
||||||
case KtxBundle::SRGB8_ALPHA1_ETC: return T::ETC2_SRGB8_A1;
|
|
||||||
case KtxBundle::RGBA8_ETC2_EAC: return T::ETC2_EAC_RGBA8;
|
|
||||||
case KtxBundle::SRGB8_ALPHA8_ETC2_EAC: return T::ETC2_EAC_SRGBA8;
|
|
||||||
}
|
|
||||||
return (T) 0xffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline CompressedPixelDataType toCompressedPixelDataType(const KtxInfo& info) {
|
|
||||||
return toCompressedFilamentEnum<CompressedPixelDataType>(info.glInternalFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PixelDataType toPixelDataType(const KtxInfo& info) {
|
|
||||||
switch (info.glType) {
|
|
||||||
case KtxBundle::UNSIGNED_BYTE: return PixelDataType::UBYTE;
|
|
||||||
case KtxBundle::UNSIGNED_SHORT: return PixelDataType::USHORT;
|
|
||||||
case KtxBundle::HALF_FLOAT: return PixelDataType::HALF;
|
|
||||||
case KtxBundle::FLOAT: return PixelDataType::FLOAT;
|
|
||||||
case KtxBundle::R11F_G11F_B10F: return PixelDataType::UINT_10F_11F_11F_REV;
|
|
||||||
}
|
|
||||||
return (PixelDataType) 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PixelDataFormat toPixelDataFormat(const KtxInfo& info) {
|
|
||||||
switch (info.glFormat) {
|
|
||||||
case KtxBundle::LUMINANCE:
|
|
||||||
case KtxBundle::RED: return PixelDataFormat::R;
|
|
||||||
case KtxBundle::RG: return PixelDataFormat::RG;
|
|
||||||
case KtxBundle::RGB: return PixelDataFormat::RGB;
|
|
||||||
case KtxBundle::RGBA: return PixelDataFormat::RGBA;
|
|
||||||
// glFormat should NOT be a sized format according to the spec
|
|
||||||
// however cmgen was generating incorrect files until after Filament 1.8.0
|
|
||||||
// so we keep this line here to preserve compatibility with older assets
|
|
||||||
case KtxBundle::R11F_G11F_B10F: return PixelDataFormat::RGB;
|
|
||||||
}
|
|
||||||
return (PixelDataFormat) 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool isCompressed(const KtxInfo& info) {
|
|
||||||
return info.glFormat == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline TextureFormat toSrgbTextureFormat(TextureFormat format) {
|
|
||||||
switch(format) {
|
|
||||||
// Non-compressed
|
|
||||||
case Texture::InternalFormat::RGB8:
|
|
||||||
return Texture::InternalFormat::SRGB8;
|
|
||||||
case Texture::InternalFormat::RGBA8:
|
|
||||||
return Texture::InternalFormat::SRGB8_A8;
|
|
||||||
|
|
||||||
// ASTC
|
|
||||||
case Texture::InternalFormat::RGBA_ASTC_4x4:
|
|
||||||
return Texture::InternalFormat::SRGB8_ALPHA8_ASTC_4x4;
|
|
||||||
case Texture::InternalFormat::RGBA_ASTC_5x4:
|
|
||||||
return Texture::InternalFormat::SRGB8_ALPHA8_ASTC_5x4;
|
|
||||||
case Texture::InternalFormat::RGBA_ASTC_5x5:
|
|
||||||
return Texture::InternalFormat::SRGB8_ALPHA8_ASTC_5x5;
|
|
||||||
case Texture::InternalFormat::RGBA_ASTC_6x5:
|
|
||||||
return Texture::InternalFormat::SRGB8_ALPHA8_ASTC_6x5;
|
|
||||||
case Texture::InternalFormat::RGBA_ASTC_6x6:
|
|
||||||
return Texture::InternalFormat::SRGB8_ALPHA8_ASTC_6x6;
|
|
||||||
case Texture::InternalFormat::RGBA_ASTC_8x5:
|
|
||||||
return Texture::InternalFormat::SRGB8_ALPHA8_ASTC_8x5;
|
|
||||||
case Texture::InternalFormat::RGBA_ASTC_8x6:
|
|
||||||
return Texture::InternalFormat::SRGB8_ALPHA8_ASTC_8x6;
|
|
||||||
case Texture::InternalFormat::RGBA_ASTC_8x8:
|
|
||||||
return Texture::InternalFormat::SRGB8_ALPHA8_ASTC_8x8;
|
|
||||||
case Texture::InternalFormat::RGBA_ASTC_10x5:
|
|
||||||
return Texture::InternalFormat::SRGB8_ALPHA8_ASTC_10x5;
|
|
||||||
case Texture::InternalFormat::RGBA_ASTC_10x6:
|
|
||||||
return Texture::InternalFormat::SRGB8_ALPHA8_ASTC_10x6;
|
|
||||||
case Texture::InternalFormat::RGBA_ASTC_10x8:
|
|
||||||
return Texture::InternalFormat::SRGB8_ALPHA8_ASTC_10x8;
|
|
||||||
case Texture::InternalFormat::RGBA_ASTC_10x10:
|
|
||||||
return Texture::InternalFormat::SRGB8_ALPHA8_ASTC_10x10;
|
|
||||||
case Texture::InternalFormat::RGBA_ASTC_12x10:
|
|
||||||
return Texture::InternalFormat::SRGB8_ALPHA8_ASTC_12x10;
|
|
||||||
case Texture::InternalFormat::RGBA_ASTC_12x12:
|
|
||||||
return Texture::InternalFormat::SRGB8_ALPHA8_ASTC_12x12;
|
|
||||||
|
|
||||||
// ETC2
|
|
||||||
case Texture::InternalFormat::ETC2_RGB8:
|
|
||||||
return Texture::InternalFormat::ETC2_SRGB8;
|
|
||||||
case Texture::InternalFormat::ETC2_RGB8_A1:
|
|
||||||
return Texture::InternalFormat::ETC2_SRGB8_A1;
|
|
||||||
case Texture::InternalFormat::ETC2_EAC_RGBA8:
|
|
||||||
return Texture::InternalFormat::ETC2_EAC_SRGBA8;
|
|
||||||
|
|
||||||
// DXT
|
|
||||||
case Texture::InternalFormat::DXT1_RGB:
|
|
||||||
return Texture::InternalFormat::DXT1_SRGB;
|
|
||||||
case Texture::InternalFormat::DXT1_RGBA:
|
|
||||||
return Texture::InternalFormat::DXT1_SRGBA;
|
|
||||||
case Texture::InternalFormat::DXT3_RGBA:
|
|
||||||
return Texture::InternalFormat::DXT3_SRGBA;
|
|
||||||
case Texture::InternalFormat::DXT5_RGBA:
|
|
||||||
return Texture::InternalFormat::DXT5_SRGBA;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return format;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline TextureFormat toTextureFormat(const KtxInfo& info) {
|
|
||||||
switch (info.glInternalFormat) {
|
|
||||||
case KtxBundle::RED: return TextureFormat::R8;
|
|
||||||
case KtxBundle::RG: return TextureFormat::RG8;
|
|
||||||
case KtxBundle::RGB: return TextureFormat::RGB8;
|
|
||||||
case KtxBundle::RGBA: return TextureFormat::RGBA8;
|
|
||||||
case KtxBundle::LUMINANCE: return TextureFormat::R8;
|
|
||||||
case KtxBundle::LUMINANCE_ALPHA: return TextureFormat::RG8;
|
|
||||||
case KtxBundle::R8: return TextureFormat::R8;
|
|
||||||
case KtxBundle::R8_SNORM: return TextureFormat::R8_SNORM;
|
|
||||||
case KtxBundle::R8UI: return TextureFormat::R8UI;
|
|
||||||
case KtxBundle::R8I: return TextureFormat::R8I;
|
|
||||||
case KtxBundle::STENCIL_INDEX8: return TextureFormat::STENCIL8;
|
|
||||||
case KtxBundle::R16F: return TextureFormat::R16F;
|
|
||||||
case KtxBundle::R16UI: return TextureFormat::R16UI;
|
|
||||||
case KtxBundle::R16I: return TextureFormat::R16I;
|
|
||||||
case KtxBundle::RG8: return TextureFormat::RG8;
|
|
||||||
case KtxBundle::RG8_SNORM: return TextureFormat::RG8_SNORM;
|
|
||||||
case KtxBundle::RG8UI: return TextureFormat::RG8UI;
|
|
||||||
case KtxBundle::RG8I: return TextureFormat::RG8I;
|
|
||||||
case KtxBundle::RGB565: return TextureFormat::RGB565;
|
|
||||||
case KtxBundle::RGB9_E5: return TextureFormat::RGB9_E5;
|
|
||||||
case KtxBundle::RGB5_A1: return TextureFormat::RGB5_A1;
|
|
||||||
case KtxBundle::RGBA4: return TextureFormat::RGBA4;
|
|
||||||
case KtxBundle::DEPTH_COMPONENT16: return TextureFormat::DEPTH16;
|
|
||||||
case KtxBundle::RGB8: return TextureFormat::RGB8;
|
|
||||||
case KtxBundle::SRGB8: return TextureFormat::SRGB8;
|
|
||||||
case KtxBundle::RGB8_SNORM: return TextureFormat::RGB8_SNORM;
|
|
||||||
case KtxBundle::RGB8UI: return TextureFormat::RGB8UI;
|
|
||||||
case KtxBundle::RGB8I: return TextureFormat::RGB8I;
|
|
||||||
case KtxBundle::R32F: return TextureFormat::R32F;
|
|
||||||
case KtxBundle::R32UI: return TextureFormat::R32UI;
|
|
||||||
case KtxBundle::R32I: return TextureFormat::R32I;
|
|
||||||
case KtxBundle::RG16F: return TextureFormat::RG16F;
|
|
||||||
case KtxBundle::RG16UI: return TextureFormat::RG16UI;
|
|
||||||
case KtxBundle::RG16I: return TextureFormat::RG16I;
|
|
||||||
case KtxBundle::R11F_G11F_B10F: return TextureFormat::R11F_G11F_B10F;
|
|
||||||
case KtxBundle::RGBA8: return TextureFormat::RGBA8;
|
|
||||||
case KtxBundle::SRGB8_ALPHA8: return TextureFormat::SRGB8_A8;
|
|
||||||
case KtxBundle::RGBA8_SNORM: return TextureFormat::RGBA8_SNORM;
|
|
||||||
case KtxBundle::RGB10_A2: return TextureFormat::RGB10_A2;
|
|
||||||
case KtxBundle::RGBA8UI: return TextureFormat::RGBA8UI;
|
|
||||||
case KtxBundle::RGBA8I: return TextureFormat::RGBA8I;
|
|
||||||
case KtxBundle::DEPTH24_STENCIL8: return TextureFormat::DEPTH24_STENCIL8;
|
|
||||||
case KtxBundle::DEPTH32F_STENCIL8: return TextureFormat::DEPTH32F_STENCIL8;
|
|
||||||
case KtxBundle::RGB16F: return TextureFormat::RGB16F;
|
|
||||||
case KtxBundle::RGB16UI: return TextureFormat::RGB16UI;
|
|
||||||
case KtxBundle::RGB16I: return TextureFormat::RGB16I;
|
|
||||||
case KtxBundle::RG32F: return TextureFormat::RG32F;
|
|
||||||
case KtxBundle::RG32UI: return TextureFormat::RG32UI;
|
|
||||||
case KtxBundle::RG32I: return TextureFormat::RG32I;
|
|
||||||
case KtxBundle::RGBA16F: return TextureFormat::RGBA16F;
|
|
||||||
case KtxBundle::RGBA16UI: return TextureFormat::RGBA16UI;
|
|
||||||
case KtxBundle::RGBA16I: return TextureFormat::RGBA16I;
|
|
||||||
case KtxBundle::RGB32F: return TextureFormat::RGB32F;
|
|
||||||
case KtxBundle::RGB32UI: return TextureFormat::RGB32UI;
|
|
||||||
case KtxBundle::RGB32I: return TextureFormat::RGB32I;
|
|
||||||
case KtxBundle::RGBA32F: return TextureFormat::RGBA32F;
|
|
||||||
case KtxBundle::RGBA32UI: return TextureFormat::RGBA32UI;
|
|
||||||
case KtxBundle::RGBA32I: return TextureFormat::RGBA32I;
|
|
||||||
}
|
|
||||||
return toCompressedFilamentEnum<TextureFormat>(info.glInternalFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ktx
|
|
||||||
|
|
||||||
} // namespace image
|
|
||||||
|
|
||||||
#endif
|
|
||||||
142
ios/include/ktxreader/Ktx1Reader.h
Normal file
142
ios/include/ktxreader/Ktx1Reader.h
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef KTXREADER_KTX1READER_H
|
||||||
|
#define KTXREADER_KTX1READER_H
|
||||||
|
|
||||||
|
#include <image/Ktx1Bundle.h>
|
||||||
|
|
||||||
|
#include <filament/Texture.h>
|
||||||
|
|
||||||
|
namespace filament {
|
||||||
|
class Engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ktxreader {
|
||||||
|
|
||||||
|
using KtxInfo = image::KtxInfo;
|
||||||
|
using Ktx1Bundle = image::Ktx1Bundle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows clients to create Filament textures from Ktx1Bundle objects.
|
||||||
|
*/
|
||||||
|
namespace Ktx1Reader {
|
||||||
|
|
||||||
|
using Texture = filament::Texture;
|
||||||
|
using Engine = filament::Engine;
|
||||||
|
|
||||||
|
using TextureFormat = Texture::InternalFormat;
|
||||||
|
using CompressedPixelDataType = Texture::CompressedType;
|
||||||
|
using PixelDataType = Texture::Type;
|
||||||
|
using PixelDataFormat = Texture::Format;
|
||||||
|
using PixelBufferDescriptor = Texture::PixelBufferDescriptor;
|
||||||
|
|
||||||
|
using Callback = void(*)(void* userdata);
|
||||||
|
|
||||||
|
CompressedPixelDataType toCompressedPixelDataType(const KtxInfo& info);
|
||||||
|
PixelDataType toPixelDataType(const KtxInfo& info);
|
||||||
|
PixelDataFormat toPixelDataFormat(const KtxInfo& info);
|
||||||
|
bool isCompressed(const KtxInfo& info);
|
||||||
|
TextureFormat toTextureFormat(const KtxInfo& info);
|
||||||
|
TextureFormat toSrgbTextureFormat(TextureFormat tex);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T toCompressedFilamentEnum(uint32_t format) {
|
||||||
|
switch (format) {
|
||||||
|
case Ktx1Bundle::RGB_S3TC_DXT1: return T::DXT1_RGB;
|
||||||
|
case Ktx1Bundle::RGBA_S3TC_DXT1: return T::DXT1_RGBA;
|
||||||
|
case Ktx1Bundle::RGBA_S3TC_DXT3: return T::DXT3_RGBA;
|
||||||
|
case Ktx1Bundle::RGBA_S3TC_DXT5: return T::DXT5_RGBA;
|
||||||
|
case Ktx1Bundle::RGBA_ASTC_4x4: return T::RGBA_ASTC_4x4;
|
||||||
|
case Ktx1Bundle::RGBA_ASTC_5x4: return T::RGBA_ASTC_5x4;
|
||||||
|
case Ktx1Bundle::RGBA_ASTC_5x5: return T::RGBA_ASTC_5x5;
|
||||||
|
case Ktx1Bundle::RGBA_ASTC_6x5: return T::RGBA_ASTC_6x5;
|
||||||
|
case Ktx1Bundle::RGBA_ASTC_6x6: return T::RGBA_ASTC_6x6;
|
||||||
|
case Ktx1Bundle::RGBA_ASTC_8x5: return T::RGBA_ASTC_8x5;
|
||||||
|
case Ktx1Bundle::RGBA_ASTC_8x6: return T::RGBA_ASTC_8x6;
|
||||||
|
case Ktx1Bundle::RGBA_ASTC_8x8: return T::RGBA_ASTC_8x8;
|
||||||
|
case Ktx1Bundle::RGBA_ASTC_10x5: return T::RGBA_ASTC_10x5;
|
||||||
|
case Ktx1Bundle::RGBA_ASTC_10x6: return T::RGBA_ASTC_10x6;
|
||||||
|
case Ktx1Bundle::RGBA_ASTC_10x8: return T::RGBA_ASTC_10x8;
|
||||||
|
case Ktx1Bundle::RGBA_ASTC_10x10: return T::RGBA_ASTC_10x10;
|
||||||
|
case Ktx1Bundle::RGBA_ASTC_12x10: return T::RGBA_ASTC_12x10;
|
||||||
|
case Ktx1Bundle::RGBA_ASTC_12x12: return T::RGBA_ASTC_12x12;
|
||||||
|
case Ktx1Bundle::SRGB8_ALPHA8_ASTC_4x4: return T::SRGB8_ALPHA8_ASTC_4x4;
|
||||||
|
case Ktx1Bundle::SRGB8_ALPHA8_ASTC_5x4: return T::SRGB8_ALPHA8_ASTC_5x4;
|
||||||
|
case Ktx1Bundle::SRGB8_ALPHA8_ASTC_5x5: return T::SRGB8_ALPHA8_ASTC_5x5;
|
||||||
|
case Ktx1Bundle::SRGB8_ALPHA8_ASTC_6x5: return T::SRGB8_ALPHA8_ASTC_6x5;
|
||||||
|
case Ktx1Bundle::SRGB8_ALPHA8_ASTC_6x6: return T::SRGB8_ALPHA8_ASTC_6x6;
|
||||||
|
case Ktx1Bundle::SRGB8_ALPHA8_ASTC_8x5: return T::SRGB8_ALPHA8_ASTC_8x5;
|
||||||
|
case Ktx1Bundle::SRGB8_ALPHA8_ASTC_8x6: return T::SRGB8_ALPHA8_ASTC_8x6;
|
||||||
|
case Ktx1Bundle::SRGB8_ALPHA8_ASTC_8x8: return T::SRGB8_ALPHA8_ASTC_8x8;
|
||||||
|
case Ktx1Bundle::SRGB8_ALPHA8_ASTC_10x5: return T::SRGB8_ALPHA8_ASTC_10x5;
|
||||||
|
case Ktx1Bundle::SRGB8_ALPHA8_ASTC_10x6: return T::SRGB8_ALPHA8_ASTC_10x6;
|
||||||
|
case Ktx1Bundle::SRGB8_ALPHA8_ASTC_10x8: return T::SRGB8_ALPHA8_ASTC_10x8;
|
||||||
|
case Ktx1Bundle::SRGB8_ALPHA8_ASTC_10x10: return T::SRGB8_ALPHA8_ASTC_10x10;
|
||||||
|
case Ktx1Bundle::SRGB8_ALPHA8_ASTC_12x10: return T::SRGB8_ALPHA8_ASTC_12x10;
|
||||||
|
case Ktx1Bundle::SRGB8_ALPHA8_ASTC_12x12: return T::SRGB8_ALPHA8_ASTC_12x12;
|
||||||
|
case Ktx1Bundle::R11_EAC: return T::EAC_R11;
|
||||||
|
case Ktx1Bundle::SIGNED_R11_EAC: return T::EAC_R11_SIGNED;
|
||||||
|
case Ktx1Bundle::RG11_EAC: return T::EAC_RG11;
|
||||||
|
case Ktx1Bundle::SIGNED_RG11_EAC: return T::EAC_RG11_SIGNED;
|
||||||
|
case Ktx1Bundle::RGB8_ETC2: return T::ETC2_RGB8;
|
||||||
|
case Ktx1Bundle::SRGB8_ETC2: return T::ETC2_SRGB8;
|
||||||
|
case Ktx1Bundle::RGB8_ALPHA1_ETC2: return T::ETC2_RGB8_A1;
|
||||||
|
case Ktx1Bundle::SRGB8_ALPHA1_ETC: return T::ETC2_SRGB8_A1;
|
||||||
|
case Ktx1Bundle::RGBA8_ETC2_EAC: return T::ETC2_EAC_RGBA8;
|
||||||
|
case Ktx1Bundle::SRGB8_ALPHA8_ETC2_EAC: return T::ETC2_EAC_SRGBA8;
|
||||||
|
}
|
||||||
|
return (T) 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Texture object from a KTX file and populates all of its faces and miplevels.
|
||||||
|
*
|
||||||
|
* @param engine Used to create the Filament Texture
|
||||||
|
* @param ktx In-memory representation of a KTX file
|
||||||
|
* @param srgb Requests an sRGB format from the KTX file
|
||||||
|
* @param callback Gets called after all texture data has been uploaded to the GPU
|
||||||
|
* @param userdata Passed into the callback
|
||||||
|
*/
|
||||||
|
Texture* createTexture(Engine* engine, const Ktx1Bundle& ktx, bool srgb,
|
||||||
|
Callback callback, void* userdata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Texture object from a KTX bundle, populates all of its faces and miplevels,
|
||||||
|
* and automatically destroys the bundle after all the texture data has been uploaded.
|
||||||
|
*
|
||||||
|
* @param engine Used to create the Filament Texture
|
||||||
|
* @param ktx In-memory representation of a KTX file
|
||||||
|
* @param srgb Requests an sRGB format from the KTX file
|
||||||
|
*/
|
||||||
|
Texture* createTexture(Engine* engine, Ktx1Bundle* ktx, bool srgb);
|
||||||
|
|
||||||
|
CompressedPixelDataType toCompressedPixelDataType(const KtxInfo& info);
|
||||||
|
|
||||||
|
PixelDataType toPixelDataType(const KtxInfo& info);
|
||||||
|
|
||||||
|
PixelDataFormat toPixelDataFormat(const KtxInfo& info);
|
||||||
|
|
||||||
|
bool isCompressed(const KtxInfo& info);
|
||||||
|
|
||||||
|
bool isSrgbTextureFormat(TextureFormat format);
|
||||||
|
|
||||||
|
TextureFormat toTextureFormat(const KtxInfo& info);
|
||||||
|
|
||||||
|
} // namespace Ktx1Reader
|
||||||
|
} // namespace ktxreader
|
||||||
|
|
||||||
|
#endif
|
||||||
203
ios/include/ktxreader/Ktx2Reader.h
Normal file
203
ios/include/ktxreader/Ktx2Reader.h
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef KTXREADER_KTX2READER_H
|
||||||
|
#define KTXREADER_KTX2READER_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include <filament/Texture.h>
|
||||||
|
|
||||||
|
#include <utils/FixedCapacityVector.h>
|
||||||
|
|
||||||
|
namespace filament {
|
||||||
|
class Engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace basist {
|
||||||
|
class ktx2_transcoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ktxreader {
|
||||||
|
|
||||||
|
class Ktx2Reader {
|
||||||
|
public:
|
||||||
|
using Engine = filament::Engine;
|
||||||
|
using Texture = filament::Texture;
|
||||||
|
enum class TransferFunction { LINEAR, sRGB };
|
||||||
|
|
||||||
|
enum class Result {
|
||||||
|
SUCCESS,
|
||||||
|
COMPRESSED_TRANSCODE_FAILURE,
|
||||||
|
UNCOMPRESSED_TRANSCODE_FAILURE,
|
||||||
|
FORMAT_UNSUPPORTED,
|
||||||
|
FORMAT_ALREADY_REQUESTED,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ktx2Reader(Engine& engine, bool quiet = false);
|
||||||
|
~Ktx2Reader();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests that the reader constructs Filament textures with given internal format.
|
||||||
|
*
|
||||||
|
* This MUST be called at least once before calling load().
|
||||||
|
*
|
||||||
|
* As a reminder, a basis-encoded KTX2 can be quickly transcoded to any number of formats,
|
||||||
|
* so you need to tell it what formats your hw supports. That's why this method exists.
|
||||||
|
*
|
||||||
|
* Call requestFormat as many times as needed; formats that are submitted early are
|
||||||
|
* considered higher priority.
|
||||||
|
*
|
||||||
|
* If BasisU knows a priori that the given format is not available (e.g. if the build has
|
||||||
|
* disabled it), the format is not added and FORMAT_UNSUPPORTED is returned.
|
||||||
|
*
|
||||||
|
* Returns FORMAT_ALREADY_REQUESTED if the given format has already been requested.
|
||||||
|
*
|
||||||
|
* Hint: BasisU supports the following uncompressed formats: RGBA8, RGB565, RGBA4.
|
||||||
|
*/
|
||||||
|
Result requestFormat(Texture::InternalFormat format) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the given format from the list, or does nothing if it hasn't been requested.
|
||||||
|
*/
|
||||||
|
void unrequestFormat(Texture::InternalFormat format) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to create and load a Filament texture from the given KTX2 blob.
|
||||||
|
*
|
||||||
|
* If none of the requested formats can be extracted from the data, this returns null.
|
||||||
|
*
|
||||||
|
* This method iterates through the requested format list, checking each one against the
|
||||||
|
* platform's capabilities and its availability from the transcoder. When a suitable format
|
||||||
|
* is determined, it then performs lossless decompression (zstd) before transcoding the data
|
||||||
|
* into the final format.
|
||||||
|
*
|
||||||
|
* The transfer function specified here is used in two ways:
|
||||||
|
* 1) It is checked against the transfer function that was specified as metadata
|
||||||
|
* in the KTX2 blob. If they do not match, this method fails.
|
||||||
|
* 2) It is used as a filter when determining the final internal format.
|
||||||
|
*/
|
||||||
|
Texture* load(const void* data, size_t size, TransferFunction transfer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asynchronous Interface
|
||||||
|
* ======================
|
||||||
|
*
|
||||||
|
* Alternative API suitable for asynchronous transcoding of mipmap levels.
|
||||||
|
* If unsure that you need to use this, then don't, just call load() instead.
|
||||||
|
* Usage pseudocode:
|
||||||
|
*
|
||||||
|
* auto async = reader->asyncCreate(data, size, TransferFunction::LINEAR);
|
||||||
|
* mTexture = async->getTexture();
|
||||||
|
* auto backgroundThread = spawnThread({ async->doTranscoding(); })
|
||||||
|
* backgroundThread.wait();
|
||||||
|
* async->uploadImages();
|
||||||
|
* reader->asyncDestroy(async);
|
||||||
|
*
|
||||||
|
* In the documentation comments, "foreground thread" refers to the thread that the
|
||||||
|
* Filament Engine was created on.
|
||||||
|
*/
|
||||||
|
class Async {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Retrieves the Texture object.
|
||||||
|
*
|
||||||
|
* The texture is available immediately, but does not have its miplevels ready until
|
||||||
|
* after doTranscoding() and the subsequent uploadImages() have been completed. The
|
||||||
|
* caller has ownership over this texture and is responsible for freeing it after all
|
||||||
|
* miplevels have been uploaded.
|
||||||
|
*/
|
||||||
|
Texture* getTexture() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads all mipmaps from the KTX2 file and transcodes them to the resolved format.
|
||||||
|
*
|
||||||
|
* This does not return until all mipmaps have been transcoded. This is typically
|
||||||
|
* called from a background thread.
|
||||||
|
*/
|
||||||
|
Result doTranscoding();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uploads pending mipmaps to the texture.
|
||||||
|
*
|
||||||
|
* This can safely be called while doTranscoding() is still working in another thread.
|
||||||
|
* Since this calls Texture::setImage(), it should be called from the foreground thread;
|
||||||
|
* see "Thread safety" in the documentation for filament::Engine.
|
||||||
|
*/
|
||||||
|
void uploadImages();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Async() noexcept = default;
|
||||||
|
~Async() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Async(Async const&) = delete;
|
||||||
|
Async(Async&&) = delete;
|
||||||
|
Async& operator=(Async const&) = delete;
|
||||||
|
Async& operator=(Async&&) = delete;
|
||||||
|
|
||||||
|
friend class Ktx2Reader;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a texture without starting the transcode process.
|
||||||
|
*
|
||||||
|
* This method is an alternative to load() that allows users to populate mipmap levels
|
||||||
|
* asynchronously. The texture object however is still created synchronously.
|
||||||
|
*
|
||||||
|
* - For a usage example, see the documentation for the Async object.
|
||||||
|
* - Creates a copy of the given buffer, allowing clients to free it immediately.
|
||||||
|
* - Returns null if none of the requested formats can be extracted from the data.
|
||||||
|
*
|
||||||
|
* This method iterates through the requested format list, checking each one against the
|
||||||
|
* platform's capabilities and its availability from the transcoder. When a suitable format
|
||||||
|
* is determined, it then performs lossless decompression (zstd) before transcoding the data
|
||||||
|
* into the final format.
|
||||||
|
*
|
||||||
|
* The transfer function specified here is used in two ways:
|
||||||
|
* 1) It is checked against the transfer function that was specified as metadata
|
||||||
|
* in the KTX2 blob. If they do not match, this method fails.
|
||||||
|
* 2) It is used as a filter when determining the final internal format.
|
||||||
|
*/
|
||||||
|
Async* asyncCreate(const void* data, size_t size, TransferFunction transfer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees the given async object and sets it to null.
|
||||||
|
*
|
||||||
|
* This frees the original source data (i.e. the raw content of the KTX2 file) but does not
|
||||||
|
* free the associated Texture object. This can be done after transcoding has finished.
|
||||||
|
*/
|
||||||
|
void asyncDestroy(Async** async);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ktx2Reader(const Ktx2Reader&) = delete;
|
||||||
|
Ktx2Reader& operator=(const Ktx2Reader&) = delete;
|
||||||
|
Ktx2Reader(Ktx2Reader&& that) noexcept = delete;
|
||||||
|
Ktx2Reader& operator=(Ktx2Reader&& that) noexcept = delete;
|
||||||
|
|
||||||
|
Texture* createTexture(basist::ktx2_transcoder* transcoder, const void* data,
|
||||||
|
size_t size, TransferFunction transfer);
|
||||||
|
|
||||||
|
Engine& mEngine;
|
||||||
|
basist::ktx2_transcoder* const mTranscoder;
|
||||||
|
utils::FixedCapacityVector<Texture::InternalFormat> mRequestedFormats;
|
||||||
|
bool mQuiet;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ktxreader
|
||||||
|
|
||||||
|
#endif
|
||||||
7529
ios/include/stb/stb_image.h
Normal file
7529
ios/include/stb/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
32
ios/include/uberz/ArchiveEnums.h
Normal file
32
ios/include/uberz/ArchiveEnums.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UBERZ_ARCHIVE_ENUMS_H
|
||||||
|
#define UBERZ_ARCHIVE_ENUMS_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace filament::uberz {
|
||||||
|
|
||||||
|
enum class ArchiveFeature : uint64_t {
|
||||||
|
UNSUPPORTED,
|
||||||
|
OPTIONAL,
|
||||||
|
REQUIRED,
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace filament::uberz
|
||||||
|
|
||||||
|
#endif // UBERZ_ARCHIVE_ENUMS_H
|
||||||
79
ios/include/uberz/ReadableArchive.h
Normal file
79
ios/include/uberz/ReadableArchive.h
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UBERZ_READABLE_ARCHIVE_H
|
||||||
|
#define UBERZ_READABLE_ARCHIVE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <uberz/ArchiveEnums.h>
|
||||||
|
|
||||||
|
#include <filament/MaterialEnums.h>
|
||||||
|
|
||||||
|
namespace filament::uberz {
|
||||||
|
|
||||||
|
// ArchiveSpec is a parse-free binary format. The client simply casts a word-aligned content blob
|
||||||
|
// into a ReadableArchive struct pointer, then calls the following function to convert all the
|
||||||
|
// offset fields into pointers.
|
||||||
|
void convertOffsetsToPointers(struct ReadableArchive* archive);
|
||||||
|
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic warning "-Wpadded"
|
||||||
|
|
||||||
|
// Precompiled set of materials bundled with a list of features flags that each material supports.
|
||||||
|
// This is the readable counterpart to WriteableArchive.
|
||||||
|
// Used by gltfio; users do not need to access this class directly.
|
||||||
|
struct ReadableArchive {
|
||||||
|
uint32_t magic;
|
||||||
|
uint32_t version;
|
||||||
|
uint64_t specsCount;
|
||||||
|
union {
|
||||||
|
struct ArchiveSpec* specs;
|
||||||
|
uint64_t specsOffset;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr Shading INVALID_SHADING_MODEL = (Shading) 0xff;
|
||||||
|
static constexpr BlendingMode INVALID_BLENDING = (BlendingMode) 0xff;
|
||||||
|
|
||||||
|
struct ArchiveSpec {
|
||||||
|
Shading shadingModel;
|
||||||
|
BlendingMode blendingMode;
|
||||||
|
uint16_t flagsCount;
|
||||||
|
uint32_t packageByteCount;
|
||||||
|
union {
|
||||||
|
struct ArchiveFlag* flags;
|
||||||
|
uint64_t flagsOffset;
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
uint8_t* package;
|
||||||
|
uint64_t packageOffset;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ArchiveFlag {
|
||||||
|
union {
|
||||||
|
const char* name;
|
||||||
|
uint64_t nameOffset;
|
||||||
|
};
|
||||||
|
ArchiveFeature value;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
|
} // namespace filament::uberz
|
||||||
|
|
||||||
|
#endif // UBERZ_READABLE_ARCHIVE_H
|
||||||
64
ios/include/uberz/WritableArchive.h
Normal file
64
ios/include/uberz/WritableArchive.h
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UBERZ_WRITABLE_ARCHIVE_H
|
||||||
|
#define UBERZ_WRITABLE_ARCHIVE_H
|
||||||
|
|
||||||
|
#include <filament/MaterialEnums.h>
|
||||||
|
|
||||||
|
#include <uberz/ArchiveEnums.h>
|
||||||
|
#include <utils/FixedCapacityVector.h>
|
||||||
|
#include <utils/CString.h>
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#include <tsl/robin_map.h>
|
||||||
|
|
||||||
|
namespace filament::uberz {
|
||||||
|
|
||||||
|
// Precompiled set of materials bundled with a list of features flags that each material supports.
|
||||||
|
// This is the writeable counterpart to ReadableArchive.
|
||||||
|
// Users do not need to access this class directly, they should go through gltfio.
|
||||||
|
class WritableArchive {
|
||||||
|
public:
|
||||||
|
WritableArchive(size_t materialCount) : mMaterials(materialCount) {}
|
||||||
|
void addMaterial(const char* name, const uint8_t* package, size_t packageSize);
|
||||||
|
void addSpecLine(std::string_view line);
|
||||||
|
utils::FixedCapacityVector<uint8_t> serialize() const;
|
||||||
|
|
||||||
|
// Low-level alternatives to addSpecLine that do not involve parsing:
|
||||||
|
void setShadingModel(Shading sm);
|
||||||
|
void setBlendingModel(BlendingMode bm);
|
||||||
|
void setFeatureFlag(const char* key, ArchiveFeature value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t mLineNumber = 1;
|
||||||
|
ssize_t mMaterialIndex = -1;
|
||||||
|
|
||||||
|
struct Material {
|
||||||
|
utils::CString name;
|
||||||
|
utils::FixedCapacityVector<uint8_t> package;
|
||||||
|
Shading shadingModel;
|
||||||
|
BlendingMode blendingMode;
|
||||||
|
tsl::robin_map<utils::CString, ArchiveFeature, utils::CString::Hasher> flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
utils::FixedCapacityVector<Material> mMaterials;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace filament::uberz
|
||||||
|
|
||||||
|
#endif // UBERZ_WRITABLE_ARCHIVE_H
|
||||||
@@ -162,7 +162,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void free(void* p, size_t) noexcept {
|
void free(void* p, size_t) noexcept {
|
||||||
free(p);
|
this->free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
~HeapAllocator() noexcept = default;
|
~HeapAllocator() noexcept = default;
|
||||||
@@ -457,6 +457,12 @@ private:
|
|||||||
void* mEnd = nullptr;
|
void* mEnd = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class NullArea {
|
||||||
|
public:
|
||||||
|
void* data() const noexcept { return nullptr; }
|
||||||
|
size_t size() const noexcept { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace AreaPolicy
|
} // namespace AreaPolicy
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@@ -498,6 +504,7 @@ struct HighWatermark {
|
|||||||
void onFree(void* p, size_t size) noexcept;
|
void onFree(void* p, size_t size) noexcept;
|
||||||
void onReset() noexcept;
|
void onReset() noexcept;
|
||||||
void onRewind(void const* addr) noexcept;
|
void onRewind(void const* addr) noexcept;
|
||||||
|
uint32_t getHighWatermark() const noexcept { return mHighWaterMark; }
|
||||||
protected:
|
protected:
|
||||||
const char* mName = nullptr;
|
const char* mName = nullptr;
|
||||||
void* mBase = nullptr;
|
void* mBase = nullptr;
|
||||||
|
|||||||
114
ios/include/utils/BinaryTreeArray.h
Normal file
114
ios/include/utils/BinaryTreeArray.h
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_BINARYTREEARRAY_H
|
||||||
|
#define TNT_UTILS_BINARYTREEARRAY_H
|
||||||
|
|
||||||
|
#include <utils/compiler.h>
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
class BinaryTreeArray {
|
||||||
|
|
||||||
|
// Simple fixed capacity stack
|
||||||
|
template<typename TYPE, size_t CAPACITY,
|
||||||
|
typename = typename std::enable_if<std::is_pod<TYPE>::value>::type>
|
||||||
|
class stack {
|
||||||
|
TYPE mElements[CAPACITY];
|
||||||
|
size_t mSize = 0;
|
||||||
|
public:
|
||||||
|
bool empty() const noexcept { return mSize == 0; }
|
||||||
|
void push(TYPE const& v) noexcept {
|
||||||
|
assert(mSize < CAPACITY);
|
||||||
|
mElements[mSize++] = v;
|
||||||
|
}
|
||||||
|
void pop() noexcept {
|
||||||
|
assert(mSize > 0);
|
||||||
|
--mSize;
|
||||||
|
}
|
||||||
|
const TYPE& back() const noexcept {
|
||||||
|
return mElements[mSize - 1];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
static size_t count(size_t height) noexcept { return (1u << height) - 1; }
|
||||||
|
static size_t left(size_t i, size_t height) noexcept { return i + 1; }
|
||||||
|
static size_t right(size_t i, size_t height) noexcept { return i + (1u << (height - 1)); }
|
||||||
|
|
||||||
|
// this builds the depth-first binary tree array top down (post-order)
|
||||||
|
template<typename Leaf, typename Node>
|
||||||
|
static void traverse(size_t height, Leaf leaf, Node node) noexcept {
|
||||||
|
|
||||||
|
struct TNode {
|
||||||
|
uint32_t index;
|
||||||
|
uint32_t col;
|
||||||
|
uint32_t height;
|
||||||
|
uint32_t next;
|
||||||
|
|
||||||
|
bool isLeaf() const noexcept { return height == 1; }
|
||||||
|
size_t left() const noexcept { return BinaryTreeArray::left(index, height); }
|
||||||
|
size_t right() const noexcept { return BinaryTreeArray::right(index, height); }
|
||||||
|
};
|
||||||
|
|
||||||
|
stack<TNode, 16> stack;
|
||||||
|
stack.push(TNode{ 0, 0, (uint32_t)height, (uint32_t)count(height) });
|
||||||
|
|
||||||
|
uint32_t prevLeft = 0;
|
||||||
|
uint32_t prevRight = 0;
|
||||||
|
uint32_t prevIndex = 0;
|
||||||
|
while (!stack.empty()) {
|
||||||
|
TNode const* const UTILS_RESTRICT curr = &stack.back();
|
||||||
|
const bool isLeaf = curr->isLeaf();
|
||||||
|
const uint32_t index = curr->index;
|
||||||
|
const uint32_t l = (uint32_t)curr->left();
|
||||||
|
const uint32_t r = (uint32_t)curr->right();
|
||||||
|
|
||||||
|
if (prevLeft == index || prevRight == index) {
|
||||||
|
if (!isLeaf) {
|
||||||
|
// the 'next' node of our left node's right descendants is our right child
|
||||||
|
stack.push({ l, 2 * curr->col, curr->height - 1, r });
|
||||||
|
}
|
||||||
|
} else if (l == prevIndex) {
|
||||||
|
if (!isLeaf) {
|
||||||
|
// the 'next' node of our right child is our own 'next' sibling
|
||||||
|
stack.push({ r, 2 * curr->col + 1, curr->height - 1, curr->next });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!isLeaf) {
|
||||||
|
node(index, l, r, curr->next);
|
||||||
|
} else {
|
||||||
|
leaf(index, curr->col, curr->next);
|
||||||
|
}
|
||||||
|
stack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
prevLeft = l;
|
||||||
|
prevRight = r;
|
||||||
|
prevIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif //TNT_UTILS_BINARYTREEARRAY_H
|
||||||
@@ -79,7 +79,7 @@ public:
|
|||||||
using const_pointer = const value_type*;
|
using const_pointer = const value_type*;
|
||||||
using const_iterator = const value_type*;
|
using const_iterator = const value_type*;
|
||||||
|
|
||||||
constexpr StaticString() noexcept = default;
|
constexpr StaticString() noexcept {} // NOLINT(modernize-use-equals-default), Ubuntu compiler bug
|
||||||
|
|
||||||
// initialization from a string literal
|
// initialization from a string literal
|
||||||
template<size_t N>
|
template<size_t N>
|
||||||
@@ -149,6 +149,14 @@ public:
|
|||||||
|
|
||||||
size_type getHash() const noexcept { return mHash; }
|
size_type getHash() const noexcept { return mHash; }
|
||||||
|
|
||||||
|
struct Hasher {
|
||||||
|
typedef StaticString argument_type;
|
||||||
|
typedef size_t result_type;
|
||||||
|
result_type operator()(const argument_type& s) const noexcept {
|
||||||
|
return s.getHash();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const_pointer mString = nullptr;
|
const_pointer mString = nullptr;
|
||||||
size_type mLength = 0;
|
size_type mLength = 0;
|
||||||
@@ -200,7 +208,7 @@ public:
|
|||||||
using iterator = value_type*;
|
using iterator = value_type*;
|
||||||
using const_iterator = const value_type*;
|
using const_iterator = const value_type*;
|
||||||
|
|
||||||
CString() noexcept = default;
|
CString() noexcept {} // NOLINT(modernize-use-equals-default), Ubuntu compiler bug
|
||||||
|
|
||||||
// Allocates memory and appends a null. This constructor can be used to hold arbitrary data
|
// Allocates memory and appends a null. This constructor can be used to hold arbitrary data
|
||||||
// inside the string (i.e. it can contain nulls or non-ASCII encodings).
|
// inside the string (i.e. it can contain nulls or non-ASCII encodings).
|
||||||
@@ -220,7 +228,7 @@ public:
|
|||||||
: CString(other, N - 1) {
|
: CString(other, N - 1) {
|
||||||
}
|
}
|
||||||
|
|
||||||
CString(StaticString const& s) : CString(s.c_str(), s.size()) {}
|
CString(StaticString const& s) : CString(s.c_str(), s.size()) {} // NOLINT(google-explicit-constructor)
|
||||||
|
|
||||||
CString(const CString& rhs);
|
CString(const CString& rhs);
|
||||||
|
|
||||||
@@ -309,11 +317,19 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// placement new declared as "throw" to avoid the compiler's null-check
|
// placement new declared as "throw" to avoid the compiler's null-check
|
||||||
inline void* operator new(size_t size, void* ptr) {
|
inline void* operator new(size_t, void* ptr) {
|
||||||
assert(ptr);
|
assert(ptr);
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Hasher : private hashCStrings {
|
||||||
|
typedef CString argument_type;
|
||||||
|
typedef size_t result_type;
|
||||||
|
result_type operator()(const argument_type& s) const noexcept {
|
||||||
|
return hashCStrings::operator()(s.c_str());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Data {
|
struct Data {
|
||||||
size_type length;
|
size_type length;
|
||||||
@@ -365,34 +381,4 @@ CString to_string(T value) noexcept;
|
|||||||
|
|
||||||
} // namespace utils
|
} // namespace utils
|
||||||
|
|
||||||
// FIXME: how could we not include this one?
|
|
||||||
// needed for std::hash, since implementation is inline, this would not cause
|
|
||||||
// binaries incompatibilities if another STL version was used.
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
|
|
||||||
//! \privatesection
|
|
||||||
template<>
|
|
||||||
struct hash<utils::CString> {
|
|
||||||
typedef utils::CString argument_type;
|
|
||||||
typedef size_t result_type;
|
|
||||||
utils::hashCStrings hasher;
|
|
||||||
size_t operator()(const utils::CString& s) const noexcept {
|
|
||||||
return hasher(s.c_str());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//! \privatesection
|
|
||||||
template<>
|
|
||||||
struct hash<utils::StaticString> {
|
|
||||||
typedef utils::StaticString argument_type;
|
|
||||||
typedef size_t result_type;
|
|
||||||
size_t operator()(const utils::StaticString& s) const noexcept {
|
|
||||||
return s.getHash();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace std
|
|
||||||
|
|
||||||
#endif // TNT_UTILS_CSTRING_H
|
#endif // TNT_UTILS_CSTRING_H
|
||||||
|
|||||||
26
ios/include/utils/Condition.h
Normal file
26
ios/include/utils/Condition.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_CONDITION_H
|
||||||
|
#define TNT_UTILS_CONDITION_H
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
#include <utils/linux/Condition.h>
|
||||||
|
#else
|
||||||
|
#include <utils/generic/Condition.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_CONDITION_H
|
||||||
91
ios/include/utils/CountDownLatch.h
Normal file
91
ios/include/utils/CountDownLatch.h
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_COUNTDOWNLATCH_H
|
||||||
|
#define TNT_UTILS_COUNTDOWNLATCH_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
// note: we use our version of mutex/condition to keep this public header STL free
|
||||||
|
#include <utils/Condition.h>
|
||||||
|
#include <utils/Mutex.h>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A count down latch is used to block one or several threads until the latch is signaled
|
||||||
|
* a certain number of times.
|
||||||
|
*
|
||||||
|
* Threads entering the latch are blocked until the latch is signaled enough times.
|
||||||
|
*
|
||||||
|
* @see CyclicBarrier
|
||||||
|
*/
|
||||||
|
class CountDownLatch {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Creates a count down latch with a specified count. The minimum useful value is 1.
|
||||||
|
* @param count the latch counter initial value
|
||||||
|
*/
|
||||||
|
explicit CountDownLatch(size_t count) noexcept;
|
||||||
|
~CountDownLatch() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blocks until latch() is called \p count times.
|
||||||
|
* @see CountDownLatch(size_t count)
|
||||||
|
*/
|
||||||
|
void await() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases threads blocked in await() when called \p count times. Calling latch() more than
|
||||||
|
* \p count times has no effect.
|
||||||
|
* @see reset()
|
||||||
|
*/
|
||||||
|
void latch() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the count-down latch to the given value.
|
||||||
|
*
|
||||||
|
* @param new_count New latch count. A value of zero will immediately unblock all waiting
|
||||||
|
* threads.
|
||||||
|
*
|
||||||
|
* @warning Use with caution. It's only safe to reset the latch count when you're sure
|
||||||
|
* that no threads are waiting in await(). This can be guaranteed in various ways, for
|
||||||
|
* instance, if you have a single thread calling await(), you could call reset() from that
|
||||||
|
* thread, or you could use a CyclicBarrier to make sure all threads using the CountDownLatch
|
||||||
|
* are at a known place (i.e.: not in await()) when reset() is called.
|
||||||
|
*/
|
||||||
|
void reset(size_t new_count) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the number of times latch() has been called since construction or reset.
|
||||||
|
* @see reset(), CountDownLatch(size_t count)
|
||||||
|
*/
|
||||||
|
size_t getCount() const noexcept;
|
||||||
|
|
||||||
|
CountDownLatch() = delete;
|
||||||
|
CountDownLatch(const CountDownLatch&) = delete;
|
||||||
|
CountDownLatch& operator=(const CountDownLatch&) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t m_initial_count;
|
||||||
|
uint32_t m_remaining_count;
|
||||||
|
mutable Mutex m_lock;
|
||||||
|
mutable Condition m_cv;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_COUNTDOWNLATCH_H
|
||||||
84
ios/include/utils/CyclicBarrier.h
Normal file
84
ios/include/utils/CyclicBarrier.h
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_CYCLIC_BARRIER_H
|
||||||
|
#define TNT_UTILS_CYCLIC_BARRIER_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
// note: we use our version of mutex/condition to keep this public header STL free
|
||||||
|
#include <utils/Condition.h>
|
||||||
|
#include <utils/Mutex.h>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A cyclic barrier is used to synchronize several threads to a particular execution point.
|
||||||
|
*
|
||||||
|
* Threads entering the barrier are halted until all threads reach the barrier.
|
||||||
|
*
|
||||||
|
* @see CountDownLatch
|
||||||
|
*/
|
||||||
|
class CyclicBarrier {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Creates a cyclic barrier with a specified number of threads to synchronize. The minimum
|
||||||
|
* useful value is 2. A value of 0 is invalid and is silently changed to 1.
|
||||||
|
* @param num_threads Number of threads to synchronize.
|
||||||
|
*/
|
||||||
|
explicit CyclicBarrier(size_t num_threads) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The number of thread that are synchronized.
|
||||||
|
*/
|
||||||
|
size_t getThreadCount() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Number of threads currently waiting on the barrier.
|
||||||
|
*/
|
||||||
|
size_t getWaitingThreadCount() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blocks until getThreadCount()-1 other threads reach await().
|
||||||
|
*/
|
||||||
|
void await() noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the cyclic barrier to its original state and releases all waiting threads.
|
||||||
|
*/
|
||||||
|
void reset() noexcept;
|
||||||
|
|
||||||
|
CyclicBarrier() = delete;
|
||||||
|
CyclicBarrier(const CyclicBarrier&) = delete;
|
||||||
|
CyclicBarrier& operator=(const CyclicBarrier&) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class State {
|
||||||
|
TRAP, RELEASE
|
||||||
|
};
|
||||||
|
|
||||||
|
const size_t m_num_threads;
|
||||||
|
mutable Mutex m_lock;
|
||||||
|
mutable Condition m_cv;
|
||||||
|
|
||||||
|
State m_state = State::TRAP;
|
||||||
|
size_t m_trapped_threads = 0;
|
||||||
|
size_t m_released_threads = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_CYCLIC_BARRIER_H
|
||||||
@@ -19,9 +19,6 @@
|
|||||||
|
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
|
|
||||||
// FIXME: could we get rid of <functional>
|
|
||||||
#include <functional> // for std::hash
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
@@ -30,7 +27,7 @@ namespace utils {
|
|||||||
class UTILS_PUBLIC Entity {
|
class UTILS_PUBLIC Entity {
|
||||||
public:
|
public:
|
||||||
// this can be used to create an array of to-be-filled entities (see create())
|
// this can be used to create an array of to-be-filled entities (see create())
|
||||||
Entity() noexcept = default;
|
Entity() noexcept { } // NOLINT(modernize-use-equals-default), Ubuntu compiler bug
|
||||||
|
|
||||||
// Entities can be copied
|
// Entities can be copied
|
||||||
Entity(const Entity& e) noexcept = default;
|
Entity(const Entity& e) noexcept = default;
|
||||||
@@ -68,10 +65,17 @@ public:
|
|||||||
return Entity{ Type(identity) };
|
return Entity{ Type(identity) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Hasher {
|
||||||
|
typedef Entity argument_type;
|
||||||
|
typedef size_t result_type;
|
||||||
|
result_type operator()(argument_type const& e) const {
|
||||||
|
return e.getId();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class EntityManager;
|
friend class EntityManager;
|
||||||
friend class EntityManagerImpl;
|
friend class EntityManagerImpl;
|
||||||
friend struct std::hash<Entity>;
|
|
||||||
using Type = uint32_t;
|
using Type = uint32_t;
|
||||||
|
|
||||||
explicit Entity(Type identity) noexcept : mIdentity(identity) { }
|
explicit Entity(Type identity) noexcept : mIdentity(identity) { }
|
||||||
@@ -81,18 +85,4 @@ private:
|
|||||||
|
|
||||||
} // namespace utils
|
} // namespace utils
|
||||||
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct hash<utils::Entity> {
|
|
||||||
typedef utils::Entity argument_type;
|
|
||||||
typedef size_t result_type;
|
|
||||||
result_type operator()(argument_type const& e) const {
|
|
||||||
return e.getId();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace std
|
|
||||||
|
|
||||||
#endif // TNT_UTILS_ENTITY_H
|
#endif // TNT_UTILS_ENTITY_H
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ namespace utils {
|
|||||||
|
|
||||||
class UTILS_PUBLIC EntityManager {
|
class UTILS_PUBLIC EntityManager {
|
||||||
public:
|
public:
|
||||||
// Get the global EntityManager. Is is recommended to cache this value.
|
// Get the global EntityManager. It is recommended to cache this value.
|
||||||
// Thread Safe.
|
// Thread Safe.
|
||||||
static EntityManager& get() noexcept;
|
static EntityManager& get() noexcept;
|
||||||
|
|
||||||
|
|||||||
103
ios/include/utils/Hash.h
Normal file
103
ios/include/utils/Hash.h
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_HASH_H
|
||||||
|
#define TNT_UTILS_HASH_H
|
||||||
|
|
||||||
|
#include <functional> // for std::hash
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
namespace utils::hash {
|
||||||
|
|
||||||
|
// Hash function that takes an arbitrary swath of word-aligned data.
|
||||||
|
inline uint32_t murmur3(const uint32_t* key, size_t wordCount, uint32_t seed) noexcept {
|
||||||
|
uint32_t h = seed;
|
||||||
|
size_t i = wordCount;
|
||||||
|
do {
|
||||||
|
uint32_t k = *key++;
|
||||||
|
k *= 0xcc9e2d51u;
|
||||||
|
k = (k << 15u) | (k >> 17u);
|
||||||
|
k *= 0x1b873593u;
|
||||||
|
h ^= k;
|
||||||
|
h = (h << 13u) | (h >> 19u);
|
||||||
|
h = (h * 5u) + 0xe6546b64u;
|
||||||
|
} while (--i);
|
||||||
|
h ^= wordCount;
|
||||||
|
h ^= h >> 16u;
|
||||||
|
h *= 0x85ebca6bu;
|
||||||
|
h ^= h >> 13u;
|
||||||
|
h *= 0xc2b2ae35u;
|
||||||
|
h ^= h >> 16u;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The hash yields the same result for a given byte sequence regardless of alignment.
|
||||||
|
inline uint32_t murmurSlow(const uint8_t* key, size_t byteCount, uint32_t seed) noexcept {
|
||||||
|
const size_t wordCount = (byteCount + 3) / 4;
|
||||||
|
const uint8_t* const last = key + byteCount;
|
||||||
|
|
||||||
|
// The remainder is identical to murmur3() except an inner loop safely "reads" an entire word.
|
||||||
|
uint32_t h = seed;
|
||||||
|
size_t i = wordCount;
|
||||||
|
do {
|
||||||
|
uint32_t k = 0;
|
||||||
|
for (int i = 0; i < 4 && key < last; ++i, ++key) {
|
||||||
|
k >>= 8;
|
||||||
|
k |= uint32_t(*key) << 24;
|
||||||
|
}
|
||||||
|
k *= 0xcc9e2d51u;
|
||||||
|
k = (k << 15u) | (k >> 17u);
|
||||||
|
k *= 0x1b873593u;
|
||||||
|
h ^= k;
|
||||||
|
h = (h << 13u) | (h >> 19u);
|
||||||
|
h = (h * 5u) + 0xe6546b64u;
|
||||||
|
} while (--i);
|
||||||
|
h ^= wordCount;
|
||||||
|
h ^= h >> 16u;
|
||||||
|
h *= 0x85ebca6bu;
|
||||||
|
h ^= h >> 13u;
|
||||||
|
h *= 0xc2b2ae35u;
|
||||||
|
h ^= h >> 16u;
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct MurmurHashFn {
|
||||||
|
uint32_t operator()(const T& key) const noexcept {
|
||||||
|
static_assert(0 == (sizeof(key) & 3u), "Hashing requires a size that is a multiple of 4.");
|
||||||
|
return murmur3((const uint32_t*) &key, sizeof(key) / 4, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// combines two hashes together
|
||||||
|
template<class T>
|
||||||
|
inline void combine(size_t& seed, const T& v) noexcept {
|
||||||
|
std::hash<T> hasher;
|
||||||
|
seed ^= hasher(v) + 0x9e3779b9u + (seed << 6u) + (seed >> 2u);
|
||||||
|
}
|
||||||
|
|
||||||
|
// combines two hashes together, faster but less good
|
||||||
|
template<class T>
|
||||||
|
inline void combine_fast(size_t& seed, const T& v) noexcept {
|
||||||
|
std::hash<T> hasher;
|
||||||
|
seed ^= hasher(v) << 1u;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace utils::hash
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_HASH_H
|
||||||
@@ -62,7 +62,7 @@ public:
|
|||||||
|
|
||||||
// Creates an Invocable from the functor passed in.
|
// Creates an Invocable from the functor passed in.
|
||||||
template<typename Fn, EnableIfFnMatchesInvocable<Fn, R, Args...> = 0>
|
template<typename Fn, EnableIfFnMatchesInvocable<Fn, R, Args...> = 0>
|
||||||
Invocable(Fn&& fn) noexcept;
|
Invocable(Fn&& fn) noexcept; // NOLINT(google-explicit-constructor)
|
||||||
|
|
||||||
Invocable(const Invocable&) = delete;
|
Invocable(const Invocable&) = delete;
|
||||||
Invocable(Invocable&& rhs) noexcept;
|
Invocable(Invocable&& rhs) noexcept;
|
||||||
@@ -121,12 +121,9 @@ Invocable<R(Args...)>::Invocable(Invocable&& rhs) noexcept
|
|||||||
template<typename R, typename... Args>
|
template<typename R, typename... Args>
|
||||||
Invocable<R(Args...)>& Invocable<R(Args...)>::operator=(Invocable&& rhs) noexcept {
|
Invocable<R(Args...)>& Invocable<R(Args...)>::operator=(Invocable&& rhs) noexcept {
|
||||||
if (this != &rhs) {
|
if (this != &rhs) {
|
||||||
mInvocable = rhs.mInvocable;
|
std::swap(mInvocable, rhs.mInvocable);
|
||||||
mDeleter = rhs.mDeleter;
|
std::swap(mDeleter, rhs.mDeleter);
|
||||||
mInvoker = rhs.mInvoker;
|
std::swap(mInvoker, rhs.mInvoker);
|
||||||
rhs.mInvocable = nullptr;
|
|
||||||
rhs.mDeleter = nullptr;
|
|
||||||
rhs.mInvoker = nullptr;
|
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|||||||
530
ios/include/utils/JobSystem.h
Normal file
530
ios/include/utils/JobSystem.h
Normal file
@@ -0,0 +1,530 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_JOBSYSTEM_H
|
||||||
|
#define TNT_UTILS_JOBSYSTEM_H
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <functional>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <tsl/robin_map.h>
|
||||||
|
|
||||||
|
#include <utils/Allocator.h>
|
||||||
|
#include <utils/architecture.h>
|
||||||
|
#include <utils/compiler.h>
|
||||||
|
#include <utils/Condition.h>
|
||||||
|
#include <utils/Log.h>
|
||||||
|
#include <utils/memalign.h>
|
||||||
|
#include <utils/Mutex.h>
|
||||||
|
#include <utils/Slice.h>
|
||||||
|
#include <utils/WorkStealingDequeue.h>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
class JobSystem {
|
||||||
|
static constexpr size_t MAX_JOB_COUNT = 16384;
|
||||||
|
static_assert(MAX_JOB_COUNT <= 0x7FFE, "MAX_JOB_COUNT must be <= 0x7FFE");
|
||||||
|
using WorkQueue = WorkStealingDequeue<uint16_t, MAX_JOB_COUNT>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
class Job;
|
||||||
|
|
||||||
|
using JobFunc = void(*)(void*, JobSystem&, Job*);
|
||||||
|
|
||||||
|
class alignas(CACHELINE_SIZE) Job {
|
||||||
|
public:
|
||||||
|
Job() noexcept {} /* = default; */ /* clang bug */ // NOLINT(modernize-use-equals-default,cppcoreguidelines-pro-type-member-init)
|
||||||
|
Job(const Job&) = delete;
|
||||||
|
Job(Job&&) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class JobSystem;
|
||||||
|
|
||||||
|
// Size is chosen so that we can store at least std::function<>
|
||||||
|
// the alignas() qualifier ensures we're multiple of a cache-line.
|
||||||
|
static constexpr size_t JOB_STORAGE_SIZE_BYTES =
|
||||||
|
sizeof(std::function<void()>) > 48 ? sizeof(std::function<void()>) : 48;
|
||||||
|
static constexpr size_t JOB_STORAGE_SIZE_WORDS =
|
||||||
|
(JOB_STORAGE_SIZE_BYTES + sizeof(void*) - 1) / sizeof(void*);
|
||||||
|
|
||||||
|
// keep it first, so it's correctly aligned with all architectures
|
||||||
|
// this is where we store the job's data, typically a std::function<>
|
||||||
|
// v7 | v8
|
||||||
|
void* storage[JOB_STORAGE_SIZE_WORDS]; // 48 | 48
|
||||||
|
JobFunc function; // 4 | 8
|
||||||
|
uint16_t parent; // 2 | 2
|
||||||
|
std::atomic<uint16_t> runningJobCount = { 1 }; // 2 | 2
|
||||||
|
mutable std::atomic<uint16_t> refCount = { 1 }; // 2 | 2
|
||||||
|
// 6 | 2 (padding)
|
||||||
|
// 64 | 64
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit JobSystem(size_t threadCount = 0, size_t adoptableThreadsCount = 1) noexcept;
|
||||||
|
|
||||||
|
~JobSystem();
|
||||||
|
|
||||||
|
// Make the current thread part of the thread pool.
|
||||||
|
void adopt();
|
||||||
|
|
||||||
|
// Remove this adopted thread from the parent. This is intended to be used for
|
||||||
|
// shutting down a JobSystem. In particular, this doesn't allow the parent to
|
||||||
|
// adopt more thread.
|
||||||
|
void emancipate();
|
||||||
|
|
||||||
|
|
||||||
|
// If a parent is not specified when creating a job, that job will automatically take the
|
||||||
|
// root job as a parent.
|
||||||
|
// The root job is reset when waited on.
|
||||||
|
Job* setRootJob(Job* job) noexcept { return mRootJob = job; }
|
||||||
|
|
||||||
|
// use setRootJob() instead
|
||||||
|
UTILS_DEPRECATED
|
||||||
|
Job* setMasterJob(Job* job) noexcept { return setRootJob(job); }
|
||||||
|
|
||||||
|
|
||||||
|
Job* create(Job* parent, JobFunc func) noexcept;
|
||||||
|
|
||||||
|
// NOTE: All methods below must be called from the same thread and that thread must be
|
||||||
|
// owned by JobSystem's thread pool.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Job creation examples:
|
||||||
|
* ----------------------
|
||||||
|
*
|
||||||
|
* struct Functor {
|
||||||
|
* uintptr_t storage[6];
|
||||||
|
* void operator()(JobSystem&, Jobsystem::Job*);
|
||||||
|
* } functor;
|
||||||
|
*
|
||||||
|
* struct Foo {
|
||||||
|
* uintptr_t storage[6];
|
||||||
|
* void method(JobSystem&, Jobsystem::Job*);
|
||||||
|
* } foo;
|
||||||
|
*
|
||||||
|
* Functor and Foo size muse be <= uintptr_t[6]
|
||||||
|
*
|
||||||
|
* createJob()
|
||||||
|
* createJob(parent)
|
||||||
|
* createJob<Foo, &Foo::method>(parent, &foo)
|
||||||
|
* createJob<Foo, &Foo::method>(parent, foo)
|
||||||
|
* createJob<Foo, &Foo::method>(parent, std::ref(foo))
|
||||||
|
* createJob(parent, functor)
|
||||||
|
* createJob(parent, std::ref(functor))
|
||||||
|
* createJob(parent, [ up-to 6 uintptr_t ](JobSystem*, Jobsystem::Job*){ })
|
||||||
|
*
|
||||||
|
* Utility functions:
|
||||||
|
* ------------------
|
||||||
|
* These are less efficient, but handle any size objects using the heap if needed.
|
||||||
|
* (internally uses std::function<>), and don't require the callee to take
|
||||||
|
* a (JobSystem&, Jobsystem::Job*) as parameter.
|
||||||
|
*
|
||||||
|
* struct BigFoo {
|
||||||
|
* uintptr_t large[16];
|
||||||
|
* void operator()();
|
||||||
|
* void method(int answerToEverything);
|
||||||
|
* static void exec(BigFoo&) { }
|
||||||
|
* } bigFoo;
|
||||||
|
*
|
||||||
|
* jobs::createJob(js, parent, [ any-capture ](int answerToEverything){}, 42);
|
||||||
|
* jobs::createJob(js, parent, &BigFoo::method, &bigFoo, 42);
|
||||||
|
* jobs::createJob(js, parent, &BigFoo::exec, std::ref(bigFoo));
|
||||||
|
* jobs::createJob(js, parent, bigFoo);
|
||||||
|
* jobs::createJob(js, parent, std::ref(bigFoo));
|
||||||
|
* etc...
|
||||||
|
*
|
||||||
|
* struct SmallFunctor {
|
||||||
|
* uintptr_t storage[3];
|
||||||
|
* void operator()(T* data, size_t count);
|
||||||
|
* } smallFunctor;
|
||||||
|
*
|
||||||
|
* jobs::parallel_for(js, data, count, [ up-to 3 uintptr_t ](T* data, size_t count) { });
|
||||||
|
* jobs::parallel_for(js, data, count, smallFunctor);
|
||||||
|
* jobs::parallel_for(js, data, count, std::ref(smallFunctor));
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// creates an empty (no-op) job with an optional parent
|
||||||
|
Job* createJob(Job* parent = nullptr) noexcept {
|
||||||
|
return create(parent, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates a job from a KNOWN method pointer w/ object passed by pointer
|
||||||
|
// the caller must ensure the object will outlive the Job
|
||||||
|
template<typename T, void(T::*method)(JobSystem&, Job*)>
|
||||||
|
Job* createJob(Job* parent, T* data) noexcept {
|
||||||
|
Job* job = create(parent, [](void* user, JobSystem& js, Job* job) {
|
||||||
|
(*static_cast<T**>(user)->*method)(js, job);
|
||||||
|
});
|
||||||
|
if (job) {
|
||||||
|
job->storage[0] = data;
|
||||||
|
}
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates a job from a KNOWN method pointer w/ object passed by value
|
||||||
|
template<typename T, void(T::*method)(JobSystem&, Job*)>
|
||||||
|
Job* createJob(Job* parent, T data) noexcept {
|
||||||
|
static_assert(sizeof(data) <= sizeof(Job::storage), "user data too large");
|
||||||
|
Job* job = create(parent, [](void* user, JobSystem& js, Job* job) {
|
||||||
|
T* that = static_cast<T*>(user);
|
||||||
|
(that->*method)(js, job);
|
||||||
|
that->~T();
|
||||||
|
});
|
||||||
|
if (job) {
|
||||||
|
new(job->storage) T(std::move(data));
|
||||||
|
}
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates a job from a functor passed by value
|
||||||
|
template<typename T>
|
||||||
|
Job* createJob(Job* parent, T functor) noexcept {
|
||||||
|
static_assert(sizeof(functor) <= sizeof(Job::storage), "functor too large");
|
||||||
|
Job* job = create(parent, [](void* user, JobSystem& js, Job* job){
|
||||||
|
T& that = *static_cast<T*>(user);
|
||||||
|
that(js, job);
|
||||||
|
that.~T();
|
||||||
|
});
|
||||||
|
if (job) {
|
||||||
|
new(job->storage) T(std::move(functor));
|
||||||
|
}
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Jobs are normally finished automatically, this can be used to cancel a job before it is run.
|
||||||
|
*
|
||||||
|
* Never use this once a flavor of run() has been called.
|
||||||
|
*/
|
||||||
|
void cancel(Job*& job) noexcept;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adds a reference to a Job.
|
||||||
|
*
|
||||||
|
* This allows the caller to waitAndRelease() on this job from multiple threads.
|
||||||
|
* Use runAndWait() if waiting from multiple threads is not needed.
|
||||||
|
*
|
||||||
|
* This job MUST BE waited on with waitAndRelease(), or released with release().
|
||||||
|
*/
|
||||||
|
Job* retain(Job* job) noexcept;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Releases a reference from a Job obtained with runAndRetain() or a call to retain().
|
||||||
|
*
|
||||||
|
* The job can't be used after this call.
|
||||||
|
*/
|
||||||
|
void release(Job*& job) noexcept;
|
||||||
|
void release(Job*&& job) noexcept {
|
||||||
|
Job* p = job;
|
||||||
|
release(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add job to this thread's execution queue. It's reference will drop automatically.
|
||||||
|
* Current thread must be owned by JobSystem's thread pool. See adopt().
|
||||||
|
*
|
||||||
|
* The job can't be used after this call.
|
||||||
|
*/
|
||||||
|
void run(Job*& job) noexcept;
|
||||||
|
void run(Job*&& job) noexcept { // allows run(createJob(...));
|
||||||
|
Job* p = job;
|
||||||
|
run(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void signal() noexcept;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add job to this thread's execution queue and and keep a reference to it.
|
||||||
|
* Current thread must be owned by JobSystem's thread pool. See adopt().
|
||||||
|
*
|
||||||
|
* This job MUST BE waited on with wait(), or released with release().
|
||||||
|
*/
|
||||||
|
Job* runAndRetain(Job* job) noexcept;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait on a job and destroys it.
|
||||||
|
* Current thread must be owned by JobSystem's thread pool. See adopt().
|
||||||
|
*
|
||||||
|
* The job must first be obtained from runAndRetain() or retain().
|
||||||
|
* The job can't be used after this call.
|
||||||
|
*/
|
||||||
|
void waitAndRelease(Job*& job) noexcept;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Runs and wait for a job. This is equivalent to calling
|
||||||
|
* runAndRetain(job);
|
||||||
|
* wait(job);
|
||||||
|
*
|
||||||
|
* The job can't be used after this call.
|
||||||
|
*/
|
||||||
|
void runAndWait(Job*& job) noexcept;
|
||||||
|
void runAndWait(Job*&& job) noexcept { // allows runAndWait(createJob(...));
|
||||||
|
Job* p = job;
|
||||||
|
runAndWait(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// for debugging
|
||||||
|
friend utils::io::ostream& operator << (utils::io::ostream& out, JobSystem const& js);
|
||||||
|
|
||||||
|
|
||||||
|
// utility functions...
|
||||||
|
|
||||||
|
// set the name of the current thread (on OSes that support it)
|
||||||
|
static void setThreadName(const char* threadName) noexcept;
|
||||||
|
|
||||||
|
enum class Priority {
|
||||||
|
NORMAL,
|
||||||
|
DISPLAY,
|
||||||
|
URGENT_DISPLAY
|
||||||
|
};
|
||||||
|
|
||||||
|
static void setThreadPriority(Priority priority) noexcept;
|
||||||
|
static void setThreadAffinityById(size_t id) noexcept;
|
||||||
|
|
||||||
|
size_t getParallelSplitCount() const noexcept {
|
||||||
|
return mParallelSplitCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// this is just to avoid using std::default_random_engine, since we're in a public header.
|
||||||
|
class default_random_engine {
|
||||||
|
static constexpr uint32_t m = 0x7fffffffu;
|
||||||
|
uint32_t mState; // must be 0 < seed < 0x7fffffff
|
||||||
|
public:
|
||||||
|
inline constexpr explicit default_random_engine(uint32_t seed = 1u) noexcept
|
||||||
|
: mState(((seed % m) == 0u) ? 1u : seed % m) {
|
||||||
|
}
|
||||||
|
inline uint32_t operator()() noexcept {
|
||||||
|
return mState = uint32_t((uint64_t(mState) * 48271u) % m);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct alignas(CACHELINE_SIZE) ThreadState { // this causes 40-bytes padding
|
||||||
|
// make sure storage is cache-line aligned
|
||||||
|
WorkQueue workQueue;
|
||||||
|
|
||||||
|
// these are not accessed by the worker threads
|
||||||
|
alignas(CACHELINE_SIZE) // this causes 56-bytes padding
|
||||||
|
JobSystem* js;
|
||||||
|
std::thread thread;
|
||||||
|
default_random_engine rndGen;
|
||||||
|
uint32_t id;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(ThreadState) % CACHELINE_SIZE == 0,
|
||||||
|
"ThreadState doesn't align to a cache line");
|
||||||
|
|
||||||
|
ThreadState& getState() noexcept;
|
||||||
|
|
||||||
|
void incRef(Job const* job) noexcept;
|
||||||
|
void decRef(Job const* job) noexcept;
|
||||||
|
|
||||||
|
Job* allocateJob() noexcept;
|
||||||
|
JobSystem::ThreadState* getStateToStealFrom(JobSystem::ThreadState& state) noexcept;
|
||||||
|
bool hasJobCompleted(Job const* job) noexcept;
|
||||||
|
|
||||||
|
void requestExit() noexcept;
|
||||||
|
bool exitRequested() const noexcept;
|
||||||
|
bool hasActiveJobs() const noexcept;
|
||||||
|
|
||||||
|
void loop(ThreadState* state) noexcept;
|
||||||
|
bool execute(JobSystem::ThreadState& state) noexcept;
|
||||||
|
Job* steal(JobSystem::ThreadState& state) noexcept;
|
||||||
|
void finish(Job* job) noexcept;
|
||||||
|
|
||||||
|
void put(WorkQueue& workQueue, Job* job) noexcept;
|
||||||
|
Job* pop(WorkQueue& workQueue) noexcept;
|
||||||
|
Job* steal(WorkQueue& workQueue) noexcept;
|
||||||
|
|
||||||
|
void wait(std::unique_lock<Mutex>& lock, Job* job = nullptr) noexcept;
|
||||||
|
void wakeAll() noexcept;
|
||||||
|
void wakeOne() noexcept;
|
||||||
|
|
||||||
|
// these have thread contention, keep them together
|
||||||
|
utils::Mutex mWaiterLock;
|
||||||
|
utils::Condition mWaiterCondition;
|
||||||
|
|
||||||
|
std::atomic<uint32_t> mActiveJobs = { 0 };
|
||||||
|
utils::Arena<utils::ThreadSafeObjectPoolAllocator<Job>, LockingPolicy::NoLock> mJobPool;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using aligned_vector = std::vector<T, utils::STLAlignedAllocator<T>>;
|
||||||
|
|
||||||
|
// these are essentially const, make sure they're on a different cache-lines than the
|
||||||
|
// read-write atomics.
|
||||||
|
// We can't use "alignas(CACHELINE_SIZE)" because the standard allocator can't make this
|
||||||
|
// guarantee.
|
||||||
|
char padding[CACHELINE_SIZE];
|
||||||
|
|
||||||
|
alignas(16) // at least we align to half (or quarter) cache-line
|
||||||
|
aligned_vector<ThreadState> mThreadStates; // actual data is stored offline
|
||||||
|
std::atomic<bool> mExitRequested = { false }; // this one is almost never written
|
||||||
|
std::atomic<uint16_t> mAdoptedThreads = { 0 }; // this one is almost never written
|
||||||
|
Job* const mJobStorageBase; // Base for conversion to indices
|
||||||
|
uint16_t mThreadCount = 0; // total # of threads in the pool
|
||||||
|
uint8_t mParallelSplitCount = 0; // # of split allowable in parallel_for
|
||||||
|
Job* mRootJob = nullptr;
|
||||||
|
|
||||||
|
utils::SpinLock mThreadMapLock; // this should have very little contention
|
||||||
|
tsl::robin_map<std::thread::id, ThreadState *> mThreadMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------
|
||||||
|
// Utility functions built on top of JobSystem
|
||||||
|
|
||||||
|
namespace jobs {
|
||||||
|
|
||||||
|
// These are convenience C++11 style job creation methods that support lambdas
|
||||||
|
//
|
||||||
|
// IMPORTANT: these are less efficient to call and may perform heap allocation
|
||||||
|
// depending on the capture and parameters
|
||||||
|
//
|
||||||
|
template<typename CALLABLE, typename ... ARGS>
|
||||||
|
JobSystem::Job* createJob(JobSystem& js, JobSystem::Job* parent,
|
||||||
|
CALLABLE&& func, ARGS&&... args) noexcept {
|
||||||
|
struct Data {
|
||||||
|
std::function<void()> f;
|
||||||
|
// Renaming the method below could cause an Arrested Development.
|
||||||
|
void gob(JobSystem&, JobSystem::Job*) noexcept { f(); }
|
||||||
|
} user{ std::bind(std::forward<CALLABLE>(func),
|
||||||
|
std::forward<ARGS>(args)...) };
|
||||||
|
return js.createJob<Data, &Data::gob>(parent, std::move(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename CALLABLE, typename T, typename ... ARGS,
|
||||||
|
typename = typename std::enable_if<
|
||||||
|
std::is_member_function_pointer<typename std::remove_reference<CALLABLE>::type>::value
|
||||||
|
>::type
|
||||||
|
>
|
||||||
|
JobSystem::Job* createJob(JobSystem& js, JobSystem::Job* parent,
|
||||||
|
CALLABLE&& func, T&& o, ARGS&&... args) noexcept {
|
||||||
|
struct Data {
|
||||||
|
std::function<void()> f;
|
||||||
|
// Renaming the method below could cause an Arrested Development.
|
||||||
|
void gob(JobSystem&, JobSystem::Job*) noexcept { f(); }
|
||||||
|
} user{ std::bind(std::forward<CALLABLE>(func), std::forward<T>(o),
|
||||||
|
std::forward<ARGS>(args)...) };
|
||||||
|
return js.createJob<Data, &Data::gob>(parent, std::move(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
template<typename S, typename F>
|
||||||
|
struct ParallelForJobData {
|
||||||
|
using SplitterType = S;
|
||||||
|
using Functor = F;
|
||||||
|
using JobData = ParallelForJobData;
|
||||||
|
using size_type = uint32_t;
|
||||||
|
|
||||||
|
ParallelForJobData(size_type start, size_type count, uint8_t splits,
|
||||||
|
Functor functor,
|
||||||
|
const SplitterType& splitter) noexcept
|
||||||
|
: start(start), count(count),
|
||||||
|
functor(std::move(functor)),
|
||||||
|
splits(splits),
|
||||||
|
splitter(splitter) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void parallelWithJobs(JobSystem& js, JobSystem::Job* parent) noexcept {
|
||||||
|
assert(parent);
|
||||||
|
|
||||||
|
// this branch is often miss-predicted (it both sides happen 50% of the calls)
|
||||||
|
right_side:
|
||||||
|
if (splitter.split(splits, count)) {
|
||||||
|
const size_type lc = count / 2;
|
||||||
|
JobData ld(start, lc, splits + uint8_t(1), functor, splitter);
|
||||||
|
JobSystem::Job* l = js.createJob<JobData, &JobData::parallelWithJobs>(parent, std::move(ld));
|
||||||
|
if (UTILS_UNLIKELY(l == nullptr)) {
|
||||||
|
// couldn't create a job, just pretend we're done splitting
|
||||||
|
goto execute;
|
||||||
|
}
|
||||||
|
|
||||||
|
// start the left side before attempting the right side, so we parallelize in case
|
||||||
|
// of job creation failure -- rare, but still.
|
||||||
|
js.run(l);
|
||||||
|
|
||||||
|
// don't spawn a job for the right side, just reuse us -- spawning jobs is more
|
||||||
|
// costly than we'd like.
|
||||||
|
start += lc;
|
||||||
|
count -= lc;
|
||||||
|
++splits;
|
||||||
|
goto right_side;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
execute:
|
||||||
|
// we're done splitting, do the real work here!
|
||||||
|
functor(start, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_type start; // 4
|
||||||
|
size_type count; // 4
|
||||||
|
Functor functor; // ?
|
||||||
|
uint8_t splits; // 1
|
||||||
|
SplitterType splitter; // 1
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
|
||||||
|
|
||||||
|
// parallel jobs with start/count indices
|
||||||
|
template<typename S, typename F>
|
||||||
|
JobSystem::Job* parallel_for(JobSystem& js, JobSystem::Job* parent,
|
||||||
|
uint32_t start, uint32_t count, F functor, const S& splitter) noexcept {
|
||||||
|
using JobData = details::ParallelForJobData<S, F>;
|
||||||
|
JobData jobData(start, count, 0, std::move(functor), splitter);
|
||||||
|
return js.createJob<JobData, &JobData::parallelWithJobs>(parent, std::move(jobData));
|
||||||
|
}
|
||||||
|
|
||||||
|
// parallel jobs with pointer/count
|
||||||
|
template<typename T, typename S, typename F>
|
||||||
|
JobSystem::Job* parallel_for(JobSystem& js, JobSystem::Job* parent,
|
||||||
|
T* data, uint32_t count, F functor, const S& splitter) noexcept {
|
||||||
|
auto user = [data, f = std::move(functor)](uint32_t s, uint32_t c) {
|
||||||
|
f(data + s, c);
|
||||||
|
};
|
||||||
|
using JobData = details::ParallelForJobData<S, decltype(user)>;
|
||||||
|
JobData jobData(0, count, 0, std::move(user), splitter);
|
||||||
|
return js.createJob<JobData, &JobData::parallelWithJobs>(parent, std::move(jobData));
|
||||||
|
}
|
||||||
|
|
||||||
|
// parallel jobs on a Slice<>
|
||||||
|
template<typename T, typename S, typename F>
|
||||||
|
JobSystem::Job* parallel_for(JobSystem& js, JobSystem::Job* parent,
|
||||||
|
utils::Slice<T> slice, F functor, const S& splitter) noexcept {
|
||||||
|
return parallel_for(js, parent, slice.data(), slice.size(), functor, splitter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <size_t COUNT, size_t MAX_SPLITS = 12>
|
||||||
|
class CountSplitter {
|
||||||
|
public:
|
||||||
|
bool split(size_t splits, size_t count) const noexcept {
|
||||||
|
return (splits < MAX_SPLITS && count >= COUNT * 2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace jobs
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_JOBSYSTEM_H
|
||||||
@@ -17,40 +17,19 @@
|
|||||||
#ifndef TNT_UTILS_NAMECOMPONENTMANAGER_H
|
#ifndef TNT_UTILS_NAMECOMPONENTMANAGER_H
|
||||||
#define TNT_UTILS_NAMECOMPONENTMANAGER_H
|
#define TNT_UTILS_NAMECOMPONENTMANAGER_H
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
|
#include <utils/CString.h>
|
||||||
#include <utils/Entity.h>
|
#include <utils/Entity.h>
|
||||||
#include <utils/EntityInstance.h>
|
#include <utils/EntityInstance.h>
|
||||||
#include <utils/SingleInstanceComponentManager.h>
|
#include <utils/SingleInstanceComponentManager.h>
|
||||||
|
|
||||||
#include <functional>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace utils {
|
namespace utils {
|
||||||
|
|
||||||
class EntityManager;
|
class EntityManager;
|
||||||
|
|
||||||
namespace details {
|
|
||||||
class SafeString {
|
|
||||||
public:
|
|
||||||
SafeString() noexcept = default;
|
|
||||||
explicit SafeString(const char* str) noexcept : mCStr(strdup(str)) { }
|
|
||||||
SafeString(SafeString&& rhs) noexcept : mCStr(rhs.mCStr) { rhs.mCStr = nullptr; }
|
|
||||||
SafeString& operator=(SafeString&& rhs) noexcept {
|
|
||||||
std::swap(mCStr, rhs.mCStr);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
~SafeString() { free((void*)mCStr); }
|
|
||||||
const char* c_str() const noexcept { return mCStr; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
char const* mCStr = nullptr;
|
|
||||||
};
|
|
||||||
} // namespace details
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \class NameComponentManager NameComponentManager.h utils/NameComponentManager.h
|
* \class NameComponentManager NameComponentManager.h utils/NameComponentManager.h
|
||||||
* \brief Allows clients to associate string labels with entities.
|
* \brief Allows clients to associate string labels with entities.
|
||||||
@@ -69,7 +48,7 @@ private:
|
|||||||
* printf("%s\n", names->getName(names->getInstance(myEntity));
|
* printf("%s\n", names->getName(names->getInstance(myEntity));
|
||||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
*/
|
*/
|
||||||
class UTILS_PUBLIC NameComponentManager : public SingleInstanceComponentManager<details::SafeString> {
|
class UTILS_PUBLIC NameComponentManager : public SingleInstanceComponentManager<utils::CString> {
|
||||||
public:
|
public:
|
||||||
using Instance = EntityInstance<NameComponentManager>;
|
using Instance = EntityInstance<NameComponentManager>;
|
||||||
|
|
||||||
@@ -93,7 +72,7 @@ public:
|
|||||||
* @return Non-zero handle if the entity has a name component, 0 otherwise.
|
* @return Non-zero handle if the entity has a name component, 0 otherwise.
|
||||||
*/
|
*/
|
||||||
Instance getInstance(Entity e) const noexcept {
|
Instance getInstance(Entity e) const noexcept {
|
||||||
return Instance(SingleInstanceComponentManager::getInstance(e));
|
return { SingleInstanceComponentManager::getInstance(e) };
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \cond PRIVATE */
|
/*! \cond PRIVATE */
|
||||||
|
|||||||
212
ios/include/utils/Profiler.h
Normal file
212
ios/include/utils/Profiler.h
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_PROFILER_H
|
||||||
|
#define TNT_UTILS_PROFILER_H
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <chrono> // note: This is safe (only used inline)
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
# include <unistd.h>
|
||||||
|
# include <sys/ioctl.h>
|
||||||
|
# include <linux/perf_event.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <utils/compiler.h>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
class Profiler {
|
||||||
|
public:
|
||||||
|
enum {
|
||||||
|
INSTRUCTIONS = 0, // must be zero
|
||||||
|
CPU_CYCLES = 1,
|
||||||
|
DCACHE_REFS = 2,
|
||||||
|
DCACHE_MISSES = 3,
|
||||||
|
BRANCHES = 4,
|
||||||
|
BRANCH_MISSES = 5,
|
||||||
|
ICACHE_REFS = 6,
|
||||||
|
ICACHE_MISSES = 7,
|
||||||
|
|
||||||
|
// Must be last one
|
||||||
|
EVENT_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
EV_CPU_CYCLES = 1u << CPU_CYCLES,
|
||||||
|
EV_L1D_REFS = 1u << DCACHE_REFS,
|
||||||
|
EV_L1D_MISSES = 1u << DCACHE_MISSES,
|
||||||
|
EV_BPU_REFS = 1u << BRANCHES,
|
||||||
|
EV_BPU_MISSES = 1u << BRANCH_MISSES,
|
||||||
|
EV_L1I_REFS = 1u << ICACHE_REFS,
|
||||||
|
EV_L1I_MISSES = 1u << ICACHE_MISSES,
|
||||||
|
// helpers
|
||||||
|
EV_L1D_RATES = EV_L1D_REFS | EV_L1D_MISSES,
|
||||||
|
EV_L1I_RATES = EV_L1I_REFS | EV_L1I_MISSES,
|
||||||
|
EV_BPU_RATES = EV_BPU_REFS | EV_BPU_MISSES,
|
||||||
|
};
|
||||||
|
|
||||||
|
Profiler() noexcept; // must call resetEvents()
|
||||||
|
explicit Profiler(uint32_t eventMask) noexcept;
|
||||||
|
~Profiler() noexcept;
|
||||||
|
|
||||||
|
Profiler(const Profiler& rhs) = delete;
|
||||||
|
Profiler(Profiler&& rhs) = delete;
|
||||||
|
Profiler& operator=(const Profiler& rhs) = delete;
|
||||||
|
Profiler& operator=(Profiler&& rhs) = delete;
|
||||||
|
|
||||||
|
// selects which events are enabled.
|
||||||
|
uint32_t resetEvents(uint32_t eventMask) noexcept;
|
||||||
|
|
||||||
|
uint32_t getEnabledEvents() const noexcept { return mEnabledEvents; }
|
||||||
|
|
||||||
|
// could return false if performance counters are not supported/enabled
|
||||||
|
bool isValid() const { return mCountersFd[0] >= 0; }
|
||||||
|
|
||||||
|
class Counters {
|
||||||
|
friend class Profiler;
|
||||||
|
uint64_t nr;
|
||||||
|
uint64_t time_enabled;
|
||||||
|
uint64_t time_running;
|
||||||
|
struct {
|
||||||
|
uint64_t value;
|
||||||
|
uint64_t id;
|
||||||
|
} counters[Profiler::EVENT_COUNT];
|
||||||
|
|
||||||
|
friend Counters operator-(Counters lhs, const Counters& rhs) noexcept {
|
||||||
|
lhs.nr -= rhs.nr;
|
||||||
|
lhs.time_enabled -= rhs.time_enabled;
|
||||||
|
lhs.time_running -= rhs.time_running;
|
||||||
|
for (size_t i = 0; i < EVENT_COUNT; ++i) {
|
||||||
|
lhs.counters[i].value -= rhs.counters[i].value;
|
||||||
|
}
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
uint64_t getInstructions() const { return counters[INSTRUCTIONS].value; }
|
||||||
|
uint64_t getCpuCycles() const { return counters[CPU_CYCLES].value; }
|
||||||
|
uint64_t getL1DReferences() const { return counters[DCACHE_REFS].value; }
|
||||||
|
uint64_t getL1DMisses() const { return counters[DCACHE_MISSES].value; }
|
||||||
|
uint64_t getL1IReferences() const { return counters[ICACHE_REFS].value; }
|
||||||
|
uint64_t getL1IMisses() const { return counters[ICACHE_MISSES].value; }
|
||||||
|
uint64_t getBranchInstructions() const { return counters[BRANCHES].value; }
|
||||||
|
uint64_t getBranchMisses() const { return counters[BRANCH_MISSES].value; }
|
||||||
|
|
||||||
|
std::chrono::duration<uint64_t, std::nano> getWallTime() const {
|
||||||
|
return std::chrono::duration<uint64_t, std::nano>(time_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::chrono::duration<uint64_t, std::nano> getRunningTime() const {
|
||||||
|
return std::chrono::duration<uint64_t, std::nano>(time_running);
|
||||||
|
}
|
||||||
|
|
||||||
|
double getIPC() const noexcept {
|
||||||
|
uint64_t cpuCycles = getCpuCycles();
|
||||||
|
uint64_t instructions = getInstructions();
|
||||||
|
return double(instructions) / double(cpuCycles);
|
||||||
|
}
|
||||||
|
|
||||||
|
double getCPI() const noexcept {
|
||||||
|
uint64_t cpuCycles = getCpuCycles();
|
||||||
|
uint64_t instructions = getInstructions();
|
||||||
|
return double(cpuCycles) / double(instructions);
|
||||||
|
}
|
||||||
|
|
||||||
|
double getL1DMissRate() const noexcept {
|
||||||
|
uint64_t cacheReferences = getL1DReferences();
|
||||||
|
uint64_t cacheMisses = getL1DMisses();
|
||||||
|
return double(cacheMisses) / double(cacheReferences);
|
||||||
|
}
|
||||||
|
|
||||||
|
double getL1DHitRate() const noexcept {
|
||||||
|
return 1.0 - getL1DMissRate();
|
||||||
|
}
|
||||||
|
|
||||||
|
double getL1IMissRate() const noexcept {
|
||||||
|
uint64_t cacheReferences = getL1IReferences();
|
||||||
|
uint64_t cacheMisses = getL1IMisses();
|
||||||
|
return double(cacheMisses) / double(cacheReferences);
|
||||||
|
}
|
||||||
|
|
||||||
|
double getL1IHitRate() const noexcept {
|
||||||
|
return 1.0 - getL1IMissRate();
|
||||||
|
}
|
||||||
|
|
||||||
|
double getBranchMissRate() const noexcept {
|
||||||
|
uint64_t branchReferences = getBranchInstructions();
|
||||||
|
uint64_t branchMisses = getBranchMisses();
|
||||||
|
return double(branchMisses) / double(branchReferences);
|
||||||
|
}
|
||||||
|
|
||||||
|
double getBranchHitRate() const noexcept {
|
||||||
|
return 1.0 - getBranchMissRate();
|
||||||
|
}
|
||||||
|
|
||||||
|
double getMPKI(uint64_t misses) const noexcept {
|
||||||
|
return (misses * 1000.0) / getInstructions();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
|
||||||
|
void reset() noexcept {
|
||||||
|
int fd = mCountersFd[0];
|
||||||
|
ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void start() noexcept {
|
||||||
|
int fd = mCountersFd[0];
|
||||||
|
ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop() noexcept {
|
||||||
|
int fd = mCountersFd[0];
|
||||||
|
ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
Counters readCounters() noexcept;
|
||||||
|
|
||||||
|
#else // !__linux__
|
||||||
|
|
||||||
|
void reset() noexcept { }
|
||||||
|
void start() noexcept { }
|
||||||
|
void stop() noexcept { }
|
||||||
|
Counters readCounters() noexcept { return {}; }
|
||||||
|
|
||||||
|
#endif // __linux__
|
||||||
|
|
||||||
|
bool hasBranchRates() const noexcept {
|
||||||
|
return (mCountersFd[BRANCHES] >= 0) && (mCountersFd[BRANCH_MISSES] >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasICacheRates() const noexcept {
|
||||||
|
return (mCountersFd[ICACHE_REFS] >= 0) && (mCountersFd[ICACHE_MISSES] >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
UTILS_UNUSED uint8_t mIds[EVENT_COUNT] = {};
|
||||||
|
int mCountersFd[EVENT_COUNT];
|
||||||
|
uint32_t mEnabledEvents = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_PROFILER_H
|
||||||
88
ios/include/utils/Range.h
Normal file
88
ios/include/utils/Range.h
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_RANGE_H
|
||||||
|
#define TNT_UTILS_RANGE_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct Range {
|
||||||
|
using value_type = T;
|
||||||
|
T first = 0;
|
||||||
|
T last = 0; // this actually refers to one past the last
|
||||||
|
|
||||||
|
size_t size() const noexcept { return last - first; }
|
||||||
|
bool empty() const noexcept { return !size(); }
|
||||||
|
bool contains(const T& t) const noexcept { return first <= t && t < last; }
|
||||||
|
|
||||||
|
bool overlaps(const Range<T>& that) const noexcept {
|
||||||
|
return that.first < this->last && that.last > this->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
class const_iterator {
|
||||||
|
friend struct Range;
|
||||||
|
T value = {};
|
||||||
|
|
||||||
|
public:
|
||||||
|
const_iterator() noexcept = default;
|
||||||
|
explicit const_iterator(T value) noexcept : value(value) {}
|
||||||
|
|
||||||
|
using value_type = T;
|
||||||
|
using pointer = value_type*;
|
||||||
|
using difference_type = ptrdiff_t;
|
||||||
|
using iterator_category = std::random_access_iterator_tag;
|
||||||
|
|
||||||
|
|
||||||
|
const value_type operator*() const { return value; }
|
||||||
|
const value_type operator[](size_t n) const { return value + n; }
|
||||||
|
|
||||||
|
const_iterator& operator++() { ++value; return *this; }
|
||||||
|
const_iterator& operator--() { --value; return *this; }
|
||||||
|
|
||||||
|
const const_iterator operator++(int) { const_iterator t(value); value++; return t; }
|
||||||
|
const const_iterator operator--(int) { const_iterator t(value); value--; return t; }
|
||||||
|
|
||||||
|
const_iterator operator+(size_t rhs) const { return { value + rhs }; }
|
||||||
|
const_iterator operator+(size_t rhs) { return { value + rhs }; }
|
||||||
|
const_iterator operator-(size_t rhs) const { return { value - rhs }; }
|
||||||
|
|
||||||
|
difference_type operator-(const_iterator const& rhs) const { return value - rhs.value; }
|
||||||
|
|
||||||
|
bool operator==(const_iterator const& rhs) const { return (value == rhs.value); }
|
||||||
|
bool operator!=(const_iterator const& rhs) const { return (value != rhs.value); }
|
||||||
|
bool operator>=(const_iterator const& rhs) const { return (value >= rhs.value); }
|
||||||
|
bool operator> (const_iterator const& rhs) const { return (value > rhs.value); }
|
||||||
|
bool operator<=(const_iterator const& rhs) const { return (value <= rhs.value); }
|
||||||
|
bool operator< (const_iterator const& rhs) const { return (value < rhs.value); }
|
||||||
|
};
|
||||||
|
|
||||||
|
const_iterator begin() noexcept { return const_iterator{ first }; }
|
||||||
|
const_iterator end() noexcept { return const_iterator{ last }; }
|
||||||
|
const_iterator begin() const noexcept { return const_iterator{ first }; }
|
||||||
|
const_iterator end() const noexcept { return const_iterator{ last }; }
|
||||||
|
|
||||||
|
const_iterator front() const noexcept { return const_iterator{ first }; }
|
||||||
|
const_iterator back() const noexcept { return const_iterator{ last - 1 }; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_RANGE_H
|
||||||
308
ios/include/utils/RangeMap.h
Normal file
308
ios/include/utils/RangeMap.h
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_RANGEMAP_H
|
||||||
|
#define TNT_UTILS_RANGEMAP_H
|
||||||
|
|
||||||
|
#include <utils/Panic.h>
|
||||||
|
#include <utils/Range.h>
|
||||||
|
#include <utils/debug.h>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sparse container for a series of ordered non-overlapping intervals.
|
||||||
|
*
|
||||||
|
* RangeMap has a low memory footprint if it contains fairly homogeneous data. Internally, the
|
||||||
|
* intervals are automatically split and merged as elements are added or removed.
|
||||||
|
*
|
||||||
|
* Each interval maps to an instance of ValueType, which should support cheap equality checks
|
||||||
|
* and copy assignment. (simple concrete types are ideal)
|
||||||
|
*
|
||||||
|
* KeyType should support operator< because intervals are internally sorted using std::map.
|
||||||
|
*/
|
||||||
|
template<typename KeyType, typename ValueType>
|
||||||
|
class RangeMap {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Replaces all slots between first (inclusive) and last (exclusive).
|
||||||
|
*/
|
||||||
|
void add(KeyType first, KeyType last, const ValueType& value) noexcept {
|
||||||
|
// First check if an existing range contains "first".
|
||||||
|
Iterator iter = findRange(first);
|
||||||
|
if (iter != end()) {
|
||||||
|
const Range<KeyType> existing = getRange(iter);
|
||||||
|
// Check if the existing range be extended.
|
||||||
|
if (getValue(iter) == value) {
|
||||||
|
if (existing.last < last) {
|
||||||
|
wipe(existing.last, last);
|
||||||
|
iter = shrink(iter, existing.first, last);
|
||||||
|
mergeRight(iter);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Split the existing range into two ranges.
|
||||||
|
if (last < existing.last && first > existing.first) {
|
||||||
|
iter = shrink(iter, existing.first, first);
|
||||||
|
insert(first, last, value);
|
||||||
|
insert(last, existing.last, getValue(iter));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
clear(first, last);
|
||||||
|
insert(first, last, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if an existing range contains the end of the new range.
|
||||||
|
KeyType back = last;
|
||||||
|
iter = findRange(--back);
|
||||||
|
if (iter == end()) {
|
||||||
|
wipe(first, last);
|
||||||
|
insert(first, last, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const Range<KeyType> existing = getRange(iter);
|
||||||
|
|
||||||
|
// Check if the existing range be extended.
|
||||||
|
if (getValue(iter) == value) {
|
||||||
|
if (existing.first > first) {
|
||||||
|
wipe(first, existing.first);
|
||||||
|
iter = shrink(iter, first, existing.last);
|
||||||
|
mergeLeft(iter);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clip the beginning of the existing range and potentially remove it.
|
||||||
|
if (last < existing.last) {
|
||||||
|
shrink(iter, last, existing.last);
|
||||||
|
}
|
||||||
|
wipe(first, last);
|
||||||
|
insert(first, last, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shorthand for the "add" method that inserts a single element.
|
||||||
|
*/
|
||||||
|
void set(KeyType key, const ValueType& value) noexcept {
|
||||||
|
KeyType begin = key;
|
||||||
|
add(begin, ++key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a range exists that encompasses the given key.
|
||||||
|
*/
|
||||||
|
bool has(KeyType key) const noexcept {
|
||||||
|
return findRange(key) != mMap.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the element at the given location, panics if no element exists.
|
||||||
|
*/
|
||||||
|
const ValueType& get(KeyType key) const {
|
||||||
|
ConstIterator iter = findRange(key);
|
||||||
|
ASSERT_PRECONDITION(iter != end(), "RangeMap: No element exists at the given key.");
|
||||||
|
return getValue(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all elements between begin (inclusive) and end (exclusive).
|
||||||
|
*/
|
||||||
|
void clear(KeyType first, KeyType last) noexcept {
|
||||||
|
// Check if an existing range contains "first".
|
||||||
|
Iterator iter = findRange(first);
|
||||||
|
if (iter != end()) {
|
||||||
|
const Range<KeyType> existing = getRange(iter);
|
||||||
|
// Split the existing range into two ranges.
|
||||||
|
if (last < existing.last && first > existing.first) {
|
||||||
|
iter = shrink(iter, existing.first, first);
|
||||||
|
insert(last, existing.last, getValue(iter));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Clip one of the ends of the existing range or remove it.
|
||||||
|
if (first > existing.first) {
|
||||||
|
shrink(iter, existing.first, first);
|
||||||
|
} else if (last < existing.last) {
|
||||||
|
shrink(iter, last, existing.last);
|
||||||
|
} else {
|
||||||
|
wipe(first, last);
|
||||||
|
}
|
||||||
|
// There might be another range that intersects the cleared range, so try again.
|
||||||
|
clear(first, last);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if an existing range contains the end of the new range.
|
||||||
|
KeyType back = last;
|
||||||
|
iter = findRange(--back);
|
||||||
|
if (iter == end()) {
|
||||||
|
wipe(first, last);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const Range<KeyType> existing = getRange(iter);
|
||||||
|
|
||||||
|
// Clip the beginning of the existing range and potentially remove it.
|
||||||
|
if (last < existing.last) {
|
||||||
|
shrink(iter, last, existing.last);
|
||||||
|
}
|
||||||
|
wipe(first, last);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shorthand for the "clear" method that clears a single element.
|
||||||
|
*/
|
||||||
|
void reset(KeyType key) noexcept {
|
||||||
|
KeyType begin = key;
|
||||||
|
clear(begin, ++key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of internal interval objects (rarely used).
|
||||||
|
*/
|
||||||
|
size_t rangeCount() const noexcept { return mMap.size(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
using Map = std::map<KeyType, std::pair<Range<KeyType>, ValueType>>;
|
||||||
|
using Iterator = typename Map::iterator;
|
||||||
|
using ConstIterator = typename Map::const_iterator;
|
||||||
|
|
||||||
|
ConstIterator begin() const noexcept { return mMap.begin(); }
|
||||||
|
ConstIterator end() const noexcept { return mMap.end(); }
|
||||||
|
|
||||||
|
Iterator begin() noexcept { return mMap.begin(); }
|
||||||
|
Iterator end() noexcept { return mMap.end(); }
|
||||||
|
|
||||||
|
Range<KeyType>& getRange(Iterator iter) const { return iter->second.first; }
|
||||||
|
ValueType& getValue(Iterator iter) const { return iter->second.second; }
|
||||||
|
|
||||||
|
const Range<KeyType>& getRange(ConstIterator iter) const { return iter->second.first; }
|
||||||
|
const ValueType& getValue(ConstIterator iter) const { return iter->second.second; }
|
||||||
|
|
||||||
|
// Private helper that assumes there is no existing range that overlaps the given range.
|
||||||
|
void insert(KeyType first, KeyType last, const ValueType& value) noexcept {
|
||||||
|
assert_invariant(!has(first));
|
||||||
|
assert_invariant(!has(last - 1));
|
||||||
|
|
||||||
|
// Check if there is an adjacent range to the left than can be extended.
|
||||||
|
KeyType previous = first;
|
||||||
|
if (Iterator iter = findRange(--previous); iter != end() && getValue(iter) == value) {
|
||||||
|
getRange(iter).last = last;
|
||||||
|
mergeRight(iter);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if there is an adjacent range to the right than can be extended.
|
||||||
|
if (Iterator iter = findRange(last); iter != end() && getValue(iter) == value) {
|
||||||
|
getRange(iter).first = first;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mMap[first] = {Range<KeyType> { first, last }, value};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private helper that erases all intervals that are wholly contained within the given range.
|
||||||
|
// Note that this is quite different from the public "clear" method.
|
||||||
|
void wipe(KeyType first, KeyType last) noexcept {
|
||||||
|
// Find the first range whose beginning is greater than or equal to "first".
|
||||||
|
Iterator iter = mMap.lower_bound(first);
|
||||||
|
while (iter != end() && getRange(iter).first < last) {
|
||||||
|
KeyType existing_last = getRange(iter).last;
|
||||||
|
if (existing_last > last) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
iter = mMap.erase(iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks if there is range to the right that touches the given range.
|
||||||
|
// If so, erases it, extends the given range rightwards, and returns true.
|
||||||
|
bool mergeRight(Iterator iter) {
|
||||||
|
Iterator next = iter;
|
||||||
|
if (++next == end() || getValue(next) != getValue(iter)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getRange(next).first != getRange(iter).last) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
getRange(iter).last = getRange(next).last;
|
||||||
|
mMap.erase(next);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks if there is range to the left that touches the given range.
|
||||||
|
// If so, erases it, extends the given range leftwards, and returns true.
|
||||||
|
bool mergeLeft(Iterator iter) {
|
||||||
|
Iterator prev = iter;
|
||||||
|
if (--prev == end() || getValue(prev) != getValue(iter)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getRange(prev).last != getRange(iter).first) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
getRange(iter).first = getRange(prev).first;
|
||||||
|
mMap.erase(prev);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private helper that clips one end of an existing range.
|
||||||
|
Iterator shrink(Iterator iter, KeyType first, KeyType last) {
|
||||||
|
assert_invariant(first < last);
|
||||||
|
assert_invariant(getRange(iter).first == first || getRange(iter).last == last);
|
||||||
|
std::pair<utils::Range<KeyType>, ValueType> value = {{first, last}, iter->second.second};
|
||||||
|
mMap.erase(iter);
|
||||||
|
return mMap.insert({first, value}).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the given key is encompassed by an existing range, returns an iterator for that range.
|
||||||
|
// If no encompassing range exists, returns end().
|
||||||
|
ConstIterator findRange(KeyType key) const noexcept {
|
||||||
|
return findRangeT<ConstIterator>(*this, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the given key is encompassed by an existing range, returns an iterator for that range.
|
||||||
|
// If no encompassing range exists, returns end().
|
||||||
|
Iterator findRange(KeyType key) noexcept {
|
||||||
|
return findRangeT<Iterator>(*this, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This template method allows us to avoid code duplication for const and non-const variants of
|
||||||
|
// findRange. C++17 has "std::as_const()" but that would not be helpful here, as we would still
|
||||||
|
// need to convert a const iterator to a non-const iterator.
|
||||||
|
template<typename IteratorType, typename SelfType>
|
||||||
|
static IteratorType findRangeT(SelfType& instance, KeyType key) noexcept {
|
||||||
|
// Find the first range whose beginning is greater than or equal to the given key.
|
||||||
|
IteratorType iter = instance.mMap.lower_bound(key);
|
||||||
|
if (iter != instance.end() && instance.getRange(iter).contains(key)) {
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
// If that was the first range, or if the map is empty, return false.
|
||||||
|
if (iter == instance.begin()) {
|
||||||
|
return instance.end();
|
||||||
|
}
|
||||||
|
// Check the range immediately previous to the one that was found.
|
||||||
|
return instance.getRange(--iter).contains(key) ? iter : instance.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This maps from the start value of each range to the range itself.
|
||||||
|
Map mMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_RANGEMAP_H
|
||||||
@@ -256,7 +256,7 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// maps an entity to an instance index
|
// maps an entity to an instance index
|
||||||
tsl::robin_map<Entity, Instance> mInstanceMap;
|
tsl::robin_map<Entity, Instance, Entity::Hasher> mInstanceMap;
|
||||||
default_random_engine mRng;
|
default_random_engine mRng;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
103
ios/include/utils/Stopwatch.h
Normal file
103
ios/include/utils/Stopwatch.h
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_STOPWATCH_H
|
||||||
|
#define TNT_UTILS_STOPWATCH_H
|
||||||
|
|
||||||
|
#include <utils/Log.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A very basic Stopwatch class
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<typename Clock = std::chrono::steady_clock>
|
||||||
|
class Stopwatch {
|
||||||
|
public:
|
||||||
|
using duration = typename Clock::duration;
|
||||||
|
using time_point = typename Clock::time_point;
|
||||||
|
|
||||||
|
private:
|
||||||
|
time_point mStart;
|
||||||
|
duration mMinLap = std::numeric_limits<duration>::max();
|
||||||
|
duration mMaxLap{};
|
||||||
|
std::chrono::duration<double, std::nano> mAvgLap{};
|
||||||
|
size_t mCount = 0;
|
||||||
|
const char* mName = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Create a Stopwatch with a name and clock
|
||||||
|
explicit Stopwatch(const char* name) noexcept: mName(name) {}
|
||||||
|
|
||||||
|
// Logs min/avg/max lap time
|
||||||
|
~Stopwatch() noexcept;
|
||||||
|
|
||||||
|
// start the stopwatch
|
||||||
|
inline void start() noexcept {
|
||||||
|
mStart = Clock::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop the stopwatch
|
||||||
|
inline void stop() noexcept {
|
||||||
|
auto d = Clock::now() - mStart;
|
||||||
|
mMinLap = std::min(mMinLap, d);
|
||||||
|
mMaxLap = std::max(mMaxLap, d);
|
||||||
|
mAvgLap = (mAvgLap * mCount + d) / (mCount + 1);
|
||||||
|
mCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the minimum lap time recorded
|
||||||
|
duration getMinLapTime() const noexcept { return mMinLap; }
|
||||||
|
|
||||||
|
// get the maximum lap time recorded
|
||||||
|
duration getMaxLapTime() const noexcept { return mMaxLap; }
|
||||||
|
|
||||||
|
// get the average lap time
|
||||||
|
duration getAverageLapTime() const noexcept { return mAvgLap; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Clock>
|
||||||
|
Stopwatch<Clock>::~Stopwatch() noexcept {
|
||||||
|
slog.d << "Stopwatch \"" << mName << "\" : ["
|
||||||
|
<< mMinLap.count() << ", "
|
||||||
|
<< std::chrono::duration_cast<duration>(mAvgLap).count() << ", "
|
||||||
|
<< mMaxLap.count() << "] ns" << io::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AutoStopwatch can be used to start and stop a Stopwatch automatically
|
||||||
|
* when entering and exiting a scope.
|
||||||
|
*/
|
||||||
|
template<typename Stopwatch>
|
||||||
|
class AutoStopwatch {
|
||||||
|
Stopwatch& stopwatch;
|
||||||
|
public:
|
||||||
|
inline explicit AutoStopwatch(Stopwatch& stopwatch) noexcept: stopwatch(stopwatch) {
|
||||||
|
stopwatch.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~AutoStopwatch() noexcept { stopwatch.stop(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_STOPWATCH_H
|
||||||
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include <array> // note: this is safe, see how std::array is used below (inline / private)
|
#include <array> // note: this is safe, see how std::array is used below (inline / private)
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <functional>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@@ -509,7 +508,7 @@ private:
|
|||||||
mSize = needed;
|
mSize = needed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this calculate the offset adjusted for all data alignment of a given array
|
// this calculates the offset adjusted for all data alignment of a given array
|
||||||
static inline size_t getOffset(size_t index, size_t capacity) noexcept {
|
static inline size_t getOffset(size_t index, size_t capacity) noexcept {
|
||||||
auto offsets = getOffsets(capacity);
|
auto offsets = getOffsets(capacity);
|
||||||
return offsets[index];
|
return offsets[index];
|
||||||
|
|||||||
278
ios/include/utils/Systrace.h
Normal file
278
ios/include/utils/Systrace.h
Normal file
@@ -0,0 +1,278 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_SYSTRACE_H
|
||||||
|
#define TNT_UTILS_SYSTRACE_H
|
||||||
|
|
||||||
|
|
||||||
|
#define SYSTRACE_TAG_NEVER (0)
|
||||||
|
#define SYSTRACE_TAG_ALWAYS (1<<0)
|
||||||
|
#define SYSTRACE_TAG_FILAMENT (1<<1) // don't change, used in makefiles
|
||||||
|
#define SYSTRACE_TAG_JOBSYSTEM (1<<2)
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <utils/compiler.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The SYSTRACE_ macros use SYSTRACE_TAG as a the TAG, which should be defined
|
||||||
|
* before this file is included. If not, the SYSTRACE_TAG_ALWAYS tag will be used.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SYSTRACE_TAG
|
||||||
|
#define SYSTRACE_TAG (SYSTRACE_TAG_ALWAYS)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// enable tracing
|
||||||
|
#define SYSTRACE_ENABLE() ::utils::details::Systrace::enable(SYSTRACE_TAG)
|
||||||
|
|
||||||
|
// disable tracing
|
||||||
|
#define SYSTRACE_DISABLE() ::utils::details::Systrace::disable(SYSTRACE_TAG)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Systrace context in the current scope. needed for calling all other systrace
|
||||||
|
* commands below.
|
||||||
|
*/
|
||||||
|
#define SYSTRACE_CONTEXT() ::utils::details::Systrace ___tracer(SYSTRACE_TAG)
|
||||||
|
|
||||||
|
|
||||||
|
// SYSTRACE_NAME traces the beginning and end of the current scope. To trace
|
||||||
|
// the correct start and end times this macro should be declared first in the
|
||||||
|
// scope body.
|
||||||
|
// It also automatically creates a Systrace context
|
||||||
|
#define SYSTRACE_NAME(name) ::utils::details::ScopedTrace ___tracer(SYSTRACE_TAG, name)
|
||||||
|
|
||||||
|
// SYSTRACE_CALL is an SYSTRACE_NAME that uses the current function name.
|
||||||
|
#define SYSTRACE_CALL() SYSTRACE_NAME(__FUNCTION__)
|
||||||
|
|
||||||
|
#define SYSTRACE_NAME_BEGIN(name) \
|
||||||
|
___tracer.traceBegin(SYSTRACE_TAG, name)
|
||||||
|
|
||||||
|
#define SYSTRACE_NAME_END() \
|
||||||
|
___tracer.traceEnd(SYSTRACE_TAG)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trace the beginning of an asynchronous event. Unlike ATRACE_BEGIN/ATRACE_END
|
||||||
|
* contexts, asynchronous events do not need to be nested. The name describes
|
||||||
|
* the event, and the cookie provides a unique identifier for distinguishing
|
||||||
|
* simultaneous events. The name and cookie used to begin an event must be
|
||||||
|
* used to end it.
|
||||||
|
*/
|
||||||
|
#define SYSTRACE_ASYNC_BEGIN(name, cookie) \
|
||||||
|
___tracer.asyncBegin(SYSTRACE_TAG, name, cookie)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trace the end of an asynchronous event.
|
||||||
|
* This should have a corresponding SYSTRACE_ASYNC_BEGIN.
|
||||||
|
*/
|
||||||
|
#define SYSTRACE_ASYNC_END(name, cookie) \
|
||||||
|
___tracer.asyncEnd(SYSTRACE_TAG, name, cookie)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traces an integer counter value. name is used to identify the counter.
|
||||||
|
* This can be used to track how a value changes over time.
|
||||||
|
*/
|
||||||
|
#define SYSTRACE_VALUE32(name, val) \
|
||||||
|
___tracer.value(SYSTRACE_TAG, name, int32_t(val))
|
||||||
|
|
||||||
|
#define SYSTRACE_VALUE64(name, val) \
|
||||||
|
___tracer.value(SYSTRACE_TAG, name, int64_t(val))
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// No user serviceable code below...
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
class Systrace {
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum tags {
|
||||||
|
NEVER = SYSTRACE_TAG_NEVER,
|
||||||
|
ALWAYS = SYSTRACE_TAG_ALWAYS,
|
||||||
|
FILAMENT = SYSTRACE_TAG_FILAMENT,
|
||||||
|
JOBSYSTEM = SYSTRACE_TAG_JOBSYSTEM
|
||||||
|
// we could define more TAGS here, as we need them.
|
||||||
|
};
|
||||||
|
|
||||||
|
Systrace(uint32_t tag) noexcept {
|
||||||
|
if (tag) init(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void enable(uint32_t tags) noexcept;
|
||||||
|
static void disable(uint32_t tags) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
inline void traceBegin(uint32_t tag, const char* name) noexcept {
|
||||||
|
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
|
||||||
|
beginSection(this, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void traceEnd(uint32_t tag) noexcept {
|
||||||
|
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
|
||||||
|
endSection(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void asyncBegin(uint32_t tag, const char* name, int32_t cookie) noexcept {
|
||||||
|
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
|
||||||
|
beginAsyncSection(this, name, cookie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void asyncEnd(uint32_t tag, const char* name, int32_t cookie) noexcept {
|
||||||
|
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
|
||||||
|
endAsyncSection(this, name, cookie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void value(uint32_t tag, const char* name, int32_t value) noexcept {
|
||||||
|
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
|
||||||
|
setCounter(this, name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void value(uint32_t tag, const char* name, int64_t value) noexcept {
|
||||||
|
if (tag && UTILS_UNLIKELY(mIsTracingEnabled)) {
|
||||||
|
setCounter(this, name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class ScopedTrace;
|
||||||
|
|
||||||
|
// whether tracing is supported at all by the platform
|
||||||
|
|
||||||
|
using ATrace_isEnabled_t = bool (*)(void);
|
||||||
|
using ATrace_beginSection_t = void (*)(const char* sectionName);
|
||||||
|
using ATrace_endSection_t = void (*)(void);
|
||||||
|
using ATrace_beginAsyncSection_t = void (*)(const char* sectionName, int32_t cookie);
|
||||||
|
using ATrace_endAsyncSection_t = void (*)(const char* sectionName, int32_t cookie);
|
||||||
|
using ATrace_setCounter_t = void (*)(const char* counterName, int64_t counterValue);
|
||||||
|
|
||||||
|
struct GlobalState {
|
||||||
|
bool isTracingAvailable;
|
||||||
|
std::atomic<uint32_t> isTracingEnabled;
|
||||||
|
int markerFd;
|
||||||
|
|
||||||
|
ATrace_isEnabled_t ATrace_isEnabled;
|
||||||
|
ATrace_beginSection_t ATrace_beginSection;
|
||||||
|
ATrace_endSection_t ATrace_endSection;
|
||||||
|
ATrace_beginAsyncSection_t ATrace_beginAsyncSection;
|
||||||
|
ATrace_endAsyncSection_t ATrace_endAsyncSection;
|
||||||
|
ATrace_setCounter_t ATrace_setCounter;
|
||||||
|
|
||||||
|
void (*beginSection)(Systrace* that, const char* name);
|
||||||
|
void (*endSection)(Systrace* that);
|
||||||
|
void (*beginAsyncSection)(Systrace* that, const char* name, int32_t cookie);
|
||||||
|
void (*endAsyncSection)(Systrace* that, const char* name, int32_t cookie);
|
||||||
|
void (*setCounter)(Systrace* that, const char* name, int64_t value);
|
||||||
|
};
|
||||||
|
|
||||||
|
static GlobalState sGlobalState;
|
||||||
|
|
||||||
|
|
||||||
|
// per-instance versions for better performance
|
||||||
|
ATrace_isEnabled_t ATrace_isEnabled;
|
||||||
|
ATrace_beginSection_t ATrace_beginSection;
|
||||||
|
ATrace_endSection_t ATrace_endSection;
|
||||||
|
ATrace_beginAsyncSection_t ATrace_beginAsyncSection;
|
||||||
|
ATrace_endAsyncSection_t ATrace_endAsyncSection;
|
||||||
|
ATrace_setCounter_t ATrace_setCounter;
|
||||||
|
|
||||||
|
void (*beginSection)(Systrace* that, const char* name);
|
||||||
|
void (*endSection)(Systrace* that);
|
||||||
|
void (*beginAsyncSection)(Systrace* that, const char* name, int32_t cookie);
|
||||||
|
void (*endAsyncSection)(Systrace* that, const char* name, int32_t cookie);
|
||||||
|
void (*setCounter)(Systrace* that, const char* name, int64_t value);
|
||||||
|
|
||||||
|
void init(uint32_t tag) noexcept;
|
||||||
|
|
||||||
|
// cached values for faster access, no need to be initialized
|
||||||
|
bool mIsTracingEnabled;
|
||||||
|
int mMarkerFd = -1;
|
||||||
|
pid_t mPid;
|
||||||
|
|
||||||
|
static void setup() noexcept;
|
||||||
|
static void init_once() noexcept;
|
||||||
|
static bool isTracingEnabled(uint32_t tag) noexcept;
|
||||||
|
|
||||||
|
static void begin_body(int fd, int pid, const char* name) noexcept;
|
||||||
|
static void end_body(int fd, int pid) noexcept;
|
||||||
|
static void async_begin_body(int fd, int pid, const char* name, int32_t cookie) noexcept;
|
||||||
|
static void async_end_body(int fd, int pid, const char* name, int32_t cookie) noexcept;
|
||||||
|
static void int64_body(int fd, int pid, const char* name, int64_t value) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class ScopedTrace {
|
||||||
|
public:
|
||||||
|
// we don't inline this because it's relatively heavy due to a global check
|
||||||
|
ScopedTrace(uint32_t tag, const char* name) noexcept : mTrace(tag), mTag(tag) {
|
||||||
|
mTrace.traceBegin(tag, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~ScopedTrace() noexcept {
|
||||||
|
mTrace.traceEnd(mTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void value(uint32_t tag, const char* name, int32_t v) noexcept {
|
||||||
|
mTrace.value(tag, name, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void value(uint32_t tag, const char* name, int64_t v) noexcept {
|
||||||
|
mTrace.value(tag, name, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Systrace mTrace;
|
||||||
|
const uint32_t mTag;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
#else // !ANDROID
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define SYSTRACE_ENABLE()
|
||||||
|
#define SYSTRACE_DISABLE()
|
||||||
|
#define SYSTRACE_CONTEXT()
|
||||||
|
#define SYSTRACE_NAME(name)
|
||||||
|
#define SYSTRACE_NAME_BEGIN(name)
|
||||||
|
#define SYSTRACE_NAME_END()
|
||||||
|
#define SYSTRACE_CALL()
|
||||||
|
#define SYSTRACE_ASYNC_BEGIN(name, cookie)
|
||||||
|
#define SYSTRACE_ASYNC_END(name, cookie)
|
||||||
|
#define SYSTRACE_VALUE32(name, val)
|
||||||
|
#define SYSTRACE_VALUE64(name, val)
|
||||||
|
|
||||||
|
#endif // ANDROID
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_SYSTRACE_H
|
||||||
26
ios/include/utils/ThermalManager.h
Normal file
26
ios/include/utils/ThermalManager.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_THERMALMANAGER_H
|
||||||
|
#define TNT_UTILS_THERMALMANAGER_H
|
||||||
|
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
#include <utils/android/ThermalManager.h>
|
||||||
|
#else
|
||||||
|
#include <utils/generic/ThermalManager.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_THERMALMANAGER_H
|
||||||
32
ios/include/utils/ThreadUtils.h
Normal file
32
ios/include/utils/ThreadUtils.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_THREADUTILS_H
|
||||||
|
#define TNT_UTILS_THREADUTILS_H
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
class ThreadUtils {
|
||||||
|
public:
|
||||||
|
static std::thread::id getThreadId() noexcept;
|
||||||
|
static bool isThisThread(std::thread::id id) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_THREADUTILS_H
|
||||||
202
ios/include/utils/WorkStealingDequeue.h
Normal file
202
ios/include/utils/WorkStealingDequeue.h
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_WORKSTEALINGDEQUEUE_H
|
||||||
|
#define TNT_UTILS_WORKSTEALINGDEQUEUE_H
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A templated, lockless, fixed-size work-stealing dequeue
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* top bottom
|
||||||
|
* v v
|
||||||
|
* |----|----|----|----|----|----|
|
||||||
|
* steal() push(), pop()
|
||||||
|
* any thread main thread
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
template <typename TYPE, size_t COUNT>
|
||||||
|
class WorkStealingDequeue {
|
||||||
|
static_assert(!(COUNT & (COUNT - 1)), "COUNT must be a power of two");
|
||||||
|
static constexpr size_t MASK = COUNT - 1;
|
||||||
|
|
||||||
|
// mTop and mBottom must be signed integers. We use 64-bits atomics so we don't have
|
||||||
|
// to worry about wrapping around.
|
||||||
|
using index_t = int64_t;
|
||||||
|
|
||||||
|
std::atomic<index_t> mTop = { 0 }; // written/read in pop()/steal()
|
||||||
|
std::atomic<index_t> mBottom = { 0 }; // written only in pop(), read in push(), steal()
|
||||||
|
|
||||||
|
TYPE mItems[COUNT];
|
||||||
|
|
||||||
|
// NOTE: it's not safe to return a reference because getItemAt() can be called
|
||||||
|
// concurrently and the caller could std::move() the item unsafely.
|
||||||
|
TYPE getItemAt(index_t index) noexcept { return mItems[index & MASK]; }
|
||||||
|
|
||||||
|
void setItemAt(index_t index, TYPE item) noexcept { mItems[index & MASK] = item; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = TYPE;
|
||||||
|
|
||||||
|
inline void push(TYPE item) noexcept;
|
||||||
|
inline TYPE pop() noexcept;
|
||||||
|
inline TYPE steal() noexcept;
|
||||||
|
|
||||||
|
size_t getSize() const noexcept { return COUNT; }
|
||||||
|
|
||||||
|
// for debugging only...
|
||||||
|
size_t getCount() const noexcept {
|
||||||
|
index_t bottom = mBottom.load(std::memory_order_relaxed);
|
||||||
|
index_t top = mTop.load(std::memory_order_relaxed);
|
||||||
|
return bottom - top;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adds an item at the BOTTOM of the queue.
|
||||||
|
*
|
||||||
|
* Must be called from the main thread.
|
||||||
|
*/
|
||||||
|
template <typename TYPE, size_t COUNT>
|
||||||
|
void WorkStealingDequeue<TYPE, COUNT>::push(TYPE item) noexcept {
|
||||||
|
// std::memory_order_relaxed is sufficient because this load doesn't acquire anything from
|
||||||
|
// another thread. mBottom is only written in pop() which cannot be concurrent with push()
|
||||||
|
index_t bottom = mBottom.load(std::memory_order_relaxed);
|
||||||
|
setItemAt(bottom, item);
|
||||||
|
|
||||||
|
// std::memory_order_release is used because we release the item we just pushed to other
|
||||||
|
// threads which are calling steal().
|
||||||
|
mBottom.store(bottom + 1, std::memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Removes an item from the BOTTOM of the queue.
|
||||||
|
*
|
||||||
|
* Must be called from the main thread.
|
||||||
|
*/
|
||||||
|
template <typename TYPE, size_t COUNT>
|
||||||
|
TYPE WorkStealingDequeue<TYPE, COUNT>::pop() noexcept {
|
||||||
|
// std::memory_order_seq_cst is needed to guarantee ordering in steal()
|
||||||
|
// Note however that this is not a typical acquire/release operation:
|
||||||
|
// - not acquire because mBottom is only written in push() which is not concurrent
|
||||||
|
// - not release because we're not publishing anything to steal() here
|
||||||
|
//
|
||||||
|
// QUESTION: does this prevent mTop load below to be reordered before the "store" part of
|
||||||
|
// fetch_sub()? Hopefully it does. If not we'd need a full memory barrier.
|
||||||
|
//
|
||||||
|
index_t bottom = mBottom.fetch_sub(1, std::memory_order_seq_cst) - 1;
|
||||||
|
|
||||||
|
// bottom could be -1 if we tried to pop() from an empty queue. This will be corrected below.
|
||||||
|
assert( bottom >= -1 );
|
||||||
|
|
||||||
|
// std::memory_order_seq_cst is needed to guarantee ordering in steal()
|
||||||
|
// Note however that this is not a typical acquire operation
|
||||||
|
// (i.e. other thread's writes of mTop don't publish data)
|
||||||
|
index_t top = mTop.load(std::memory_order_seq_cst);
|
||||||
|
|
||||||
|
if (top < bottom) {
|
||||||
|
// Queue isn't empty and it's not the last item, just return it, this is the common case.
|
||||||
|
return getItemAt(bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPE item{};
|
||||||
|
if (top == bottom) {
|
||||||
|
// we just took the last item
|
||||||
|
item = getItemAt(bottom);
|
||||||
|
|
||||||
|
// Because we know we took the last item, we could be racing with steal() -- the last
|
||||||
|
// item being both at the top and bottom of the queue.
|
||||||
|
// We resolve this potential race by also stealing that item from ourselves.
|
||||||
|
if (mTop.compare_exchange_strong(top, top + 1,
|
||||||
|
std::memory_order_seq_cst,
|
||||||
|
std::memory_order_relaxed)) {
|
||||||
|
// success: we stole our last item from ourself, meaning that a concurrent steal()
|
||||||
|
// would have failed.
|
||||||
|
// mTop now equals top + 1, we adjust top to make the queue empty.
|
||||||
|
top++;
|
||||||
|
} else {
|
||||||
|
// failure: mTop was not equal to top, which means the item was stolen under our feet.
|
||||||
|
// top now equals to mTop. Simply discard the item we just popped.
|
||||||
|
// The queue is now empty.
|
||||||
|
item = TYPE();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We could be here if the item was stolen just before we read mTop, we'll adjust
|
||||||
|
// mBottom below.
|
||||||
|
assert(top - bottom == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::memory_order_relaxed used because we're not publishing any data.
|
||||||
|
// no concurrent writes to mBottom possible, it's always safe to write mBottom.
|
||||||
|
mBottom.store(top, std::memory_order_relaxed);
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Steals an item from the TOP of another thread's queue.
|
||||||
|
*
|
||||||
|
* This can be called concurrently with steal(), push() or pop()
|
||||||
|
*
|
||||||
|
* steal() never fails, either there is an item and it atomically takes it, or there isn't and
|
||||||
|
* it returns an empty item.
|
||||||
|
*/
|
||||||
|
template <typename TYPE, size_t COUNT>
|
||||||
|
TYPE WorkStealingDequeue<TYPE, COUNT>::steal() noexcept {
|
||||||
|
while (true) {
|
||||||
|
/*
|
||||||
|
* Note: A Key component of this algorithm is that mTop is read before mBottom here
|
||||||
|
* (and observed as such in other threads)
|
||||||
|
*/
|
||||||
|
|
||||||
|
// std::memory_order_seq_cst is needed to guarantee ordering in pop()
|
||||||
|
// Note however that this is not a typical acquire operation
|
||||||
|
// (i.e. other thread's writes of mTop don't publish data)
|
||||||
|
index_t top = mTop.load(std::memory_order_seq_cst);
|
||||||
|
|
||||||
|
// std::memory_order_acquire is needed because we're acquiring items published in push().
|
||||||
|
// std::memory_order_seq_cst is needed to guarantee ordering in pop()
|
||||||
|
index_t bottom = mBottom.load(std::memory_order_seq_cst);
|
||||||
|
|
||||||
|
if (top >= bottom) {
|
||||||
|
// queue is empty
|
||||||
|
return TYPE();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The queue isn't empty
|
||||||
|
TYPE item(getItemAt(top));
|
||||||
|
if (mTop.compare_exchange_strong(top, top + 1,
|
||||||
|
std::memory_order_seq_cst,
|
||||||
|
std::memory_order_relaxed)) {
|
||||||
|
// success: we stole an item, just return it.
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
// failure: the item we just tried to steal was pop()'ed under our feet,
|
||||||
|
// simply discard it; nothing to do -- it's okay to try again.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_WORKSTEALINGDEQUEUE_H
|
||||||
122
ios/include/utils/Zip2Iterator.h
Normal file
122
ios/include/utils/Zip2Iterator.h
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_ZIP2ITERATOR_H
|
||||||
|
#define TNT_UTILS_ZIP2ITERATOR_H
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include <utils/compiler.h>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A random access iterator that wraps two other random access iterators.
|
||||||
|
* This mostly exists so that one can sort an array using values from another.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<typename It1, typename It2>
|
||||||
|
class Zip2Iterator {
|
||||||
|
std::pair<It1, It2> mIt;
|
||||||
|
using Ref1 = typename std::iterator_traits<It1>::reference;
|
||||||
|
using Ref2 = typename std::iterator_traits<It2>::reference;
|
||||||
|
using Val1 = typename std::iterator_traits<It1>::value_type;
|
||||||
|
using Val2 = typename std::iterator_traits<It2>::value_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct Ref : public std::pair<Ref1, Ref2> {
|
||||||
|
using std::pair<Ref1, Ref2>::pair;
|
||||||
|
using std::pair<Ref1, Ref2>::operator=;
|
||||||
|
private:
|
||||||
|
friend void swap(Ref lhs, Ref rhs) {
|
||||||
|
using std::swap;
|
||||||
|
swap(lhs.first, rhs.first);
|
||||||
|
swap(lhs.second, rhs.second);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using value_type = std::pair<Val1, Val2>;
|
||||||
|
using reference = Ref;
|
||||||
|
using pointer = value_type*;
|
||||||
|
using difference_type = ptrdiff_t;
|
||||||
|
using iterator_category = std::random_access_iterator_tag;
|
||||||
|
|
||||||
|
Zip2Iterator() = default;
|
||||||
|
Zip2Iterator(It1 first, It2 second) : mIt({first, second}) {}
|
||||||
|
Zip2Iterator(Zip2Iterator const& rhs) noexcept = default;
|
||||||
|
Zip2Iterator& operator=(Zip2Iterator const& rhs) = default;
|
||||||
|
|
||||||
|
reference operator*() const { return { *mIt.first, *mIt.second }; }
|
||||||
|
|
||||||
|
reference operator[](size_t n) const { return *(*this + n); }
|
||||||
|
|
||||||
|
Zip2Iterator& operator++() {
|
||||||
|
++mIt.first;
|
||||||
|
++mIt.second;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Zip2Iterator& operator--() {
|
||||||
|
--mIt.first;
|
||||||
|
--mIt.second;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Postfix operator needed by Microsoft C++
|
||||||
|
const Zip2Iterator operator++(int) {
|
||||||
|
Zip2Iterator t(*this);
|
||||||
|
mIt.first++;
|
||||||
|
mIt.second++;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Zip2Iterator operator--(int) {
|
||||||
|
Zip2Iterator t(*this);
|
||||||
|
mIt.first--;
|
||||||
|
mIt.second--;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
Zip2Iterator& operator+=(size_t v) {
|
||||||
|
mIt.first += v;
|
||||||
|
mIt.second += v;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Zip2Iterator& operator-=(size_t v) {
|
||||||
|
mIt.first -= v;
|
||||||
|
mIt.second -= v;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Zip2Iterator operator+(size_t rhs) const { return { mIt.first + rhs, mIt.second + rhs }; }
|
||||||
|
Zip2Iterator operator+(size_t rhs) { return { mIt.first + rhs, mIt.second + rhs }; }
|
||||||
|
Zip2Iterator operator-(size_t rhs) const { return { mIt.first - rhs, mIt.second - rhs }; }
|
||||||
|
|
||||||
|
difference_type operator-(Zip2Iterator const& rhs) const { return mIt.first - rhs.mIt.first; }
|
||||||
|
|
||||||
|
bool operator==(Zip2Iterator const& rhs) const { return (mIt.first == rhs.mIt.first); }
|
||||||
|
bool operator!=(Zip2Iterator const& rhs) const { return (mIt.first != rhs.mIt.first); }
|
||||||
|
bool operator>=(Zip2Iterator const& rhs) const { return (mIt.first >= rhs.mIt.first); }
|
||||||
|
bool operator> (Zip2Iterator const& rhs) const { return (mIt.first > rhs.mIt.first); }
|
||||||
|
bool operator<=(Zip2Iterator const& rhs) const { return (mIt.first <= rhs.mIt.first); }
|
||||||
|
bool operator< (Zip2Iterator const& rhs) const { return (mIt.first < rhs.mIt.first); }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_ZIP2ITERATOR_H
|
||||||
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
|
|
||||||
#include <functional> // for std::less
|
|
||||||
#include <type_traits> // for std::enable_if
|
#include <type_traits> // for std::enable_if
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
@@ -168,74 +167,6 @@ T log2i(T x) noexcept {
|
|||||||
return (sizeof(x) * 8 - 1u) - clz(x);
|
return (sizeof(x) * 8 - 1u) - clz(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* branch-less version of std::lower_bound and std::upper_bound.
|
|
||||||
* These versions are intended to be fully inlined, which only happens when the size
|
|
||||||
* of the array is known at compile time. This code also performs better if the
|
|
||||||
* array is a power-of-two in size.
|
|
||||||
*
|
|
||||||
* These code works even if the conditions above are not met, and becomes a less-branches
|
|
||||||
* algorithm instead of a branch-less one!
|
|
||||||
*/
|
|
||||||
|
|
||||||
template<typename RandomAccessIterator, typename T, typename COMPARE = typename std::less<T>>
|
|
||||||
inline UTILS_PUBLIC
|
|
||||||
RandomAccessIterator lower_bound(
|
|
||||||
RandomAccessIterator first, RandomAccessIterator last, const T& value,
|
|
||||||
COMPARE comp = std::less<T>(),
|
|
||||||
bool assume_power_of_two = false) {
|
|
||||||
size_t len = last - first;
|
|
||||||
|
|
||||||
if (!assume_power_of_two) {
|
|
||||||
// handle non power-of-two sized arrays. If it's POT, the next line is a no-op
|
|
||||||
// and gets optimized out if the size is known at compile time.
|
|
||||||
len = 1u << (31 - clz(uint32_t(len))); // next power of two length / 2
|
|
||||||
size_t difference = (last - first) - len;
|
|
||||||
// If len was already a POT, then difference will be 0.
|
|
||||||
// We need to explicitly check this case to avoid dereferencing past the end of the array
|
|
||||||
first += !difference || comp(first[len], value) ? difference : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (len) {
|
|
||||||
// The number of repetitions here doesn't affect the result. We manually unroll the loop
|
|
||||||
// twice, to guarantee we have at least two iterations without branches (for the case
|
|
||||||
// where the size is not known at compile time
|
|
||||||
first += comp(first[len >>= 1u], value) ? len : 0;
|
|
||||||
first += comp(first[len >>= 1u], value) ? len : 0;
|
|
||||||
}
|
|
||||||
first += comp(*first, value);
|
|
||||||
return first;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename RandomAccessIterator, typename T, typename COMPARE = typename std::less<T>>
|
|
||||||
inline UTILS_PUBLIC
|
|
||||||
RandomAccessIterator upper_bound(
|
|
||||||
RandomAccessIterator first, RandomAccessIterator last,
|
|
||||||
const T& value, COMPARE comp = std::less<T>(),
|
|
||||||
bool assume_power_of_two = false) {
|
|
||||||
size_t len = last - first;
|
|
||||||
|
|
||||||
if (!assume_power_of_two) {
|
|
||||||
// handle non power-of-two sized arrays. If it's POT, the next line is a no-op
|
|
||||||
// and gets optimized out if the size is known at compile time.
|
|
||||||
len = 1u << (31 - clz(uint32_t(len))); // next power of two length / 2
|
|
||||||
size_t difference = (last - first) - len;
|
|
||||||
// If len was already a POT, then difference will be 0.
|
|
||||||
// We need to explicitly check this case to avoid dereferencing past the end of the array
|
|
||||||
first += !difference || comp(value, first[len]) ? 0 : difference;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (len) {
|
|
||||||
// The number of repetitions here doesn't affect the result. We manually unroll the loop
|
|
||||||
// twice, to guarantee we have at least two iterations without branches (for the case
|
|
||||||
// where the size is not known at compile time
|
|
||||||
first += !comp(value, first[len >>= 1u]) ? len : 0;
|
|
||||||
first += !comp(value, first[len >>= 1u]) ? len : 0;
|
|
||||||
}
|
|
||||||
first += !comp(value, *first);
|
|
||||||
return first;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename RandomAccessIterator, typename COMPARE>
|
template<typename RandomAccessIterator, typename COMPARE>
|
||||||
inline UTILS_PUBLIC
|
inline UTILS_PUBLIC
|
||||||
RandomAccessIterator partition_point(
|
RandomAccessIterator partition_point(
|
||||||
|
|||||||
60
ios/include/utils/android/ThermalManager.h
Normal file
60
ios/include/utils/android/ThermalManager.h
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_ANDROID_THERMALMANAGER_H
|
||||||
|
#define TNT_UTILS_ANDROID_THERMALMANAGER_H
|
||||||
|
|
||||||
|
#include <utils/compiler.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct AThermalManager;
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
class ThermalManager {
|
||||||
|
public:
|
||||||
|
enum class ThermalStatus : int8_t {
|
||||||
|
ERROR = -1,
|
||||||
|
NONE,
|
||||||
|
LIGHT,
|
||||||
|
MODERATE,
|
||||||
|
SEVERE,
|
||||||
|
CRITICAL,
|
||||||
|
EMERGENCY,
|
||||||
|
SHUTDOWN
|
||||||
|
};
|
||||||
|
|
||||||
|
ThermalManager();
|
||||||
|
~ThermalManager();
|
||||||
|
|
||||||
|
// Movable
|
||||||
|
ThermalManager(ThermalManager&& rhs) noexcept;
|
||||||
|
ThermalManager& operator=(ThermalManager&& rhs) noexcept;
|
||||||
|
|
||||||
|
// not copiable
|
||||||
|
ThermalManager(ThermalManager const& rhs) = delete;
|
||||||
|
ThermalManager& operator=(ThermalManager const& rhs) = delete;
|
||||||
|
|
||||||
|
ThermalStatus getCurrentThermalStatus() const noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
AThermalManager* mThermalManager = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_ANDROID_THERMALMANAGER_H
|
||||||
34
ios/include/utils/api_level.h
Normal file
34
ios/include/utils/api_level.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_APILEVEL_H
|
||||||
|
#define TNT_UTILS_APILEVEL_H
|
||||||
|
|
||||||
|
#include <utils/compiler.h>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns this platform's API level. On Android this function will return
|
||||||
|
* the API level as defined by the SDK API level version. If a platform does
|
||||||
|
* not have an API level, this function returns 0.
|
||||||
|
*/
|
||||||
|
UTILS_PUBLIC
|
||||||
|
int api_level();
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_APILEVEL_H
|
||||||
28
ios/include/utils/architecture.h
Normal file
28
ios/include/utils/architecture.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_ARCHITECTURE_H
|
||||||
|
#define TNT_UTILS_ARCHITECTURE_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
constexpr size_t CACHELINE_SIZE = 64;
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_ARCHITECTURE_H
|
||||||
28
ios/include/utils/ashmem.h
Normal file
28
ios/include/utils/ashmem.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_ASHMEM_H
|
||||||
|
#define TNT_UTILS_ASHMEM_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
int ashmem_create_region(const char *name, size_t size);
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_ASHMEM_H
|
||||||
39
ios/include/utils/generic/Condition.h
Normal file
39
ios/include/utils/generic/Condition.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_GENERIC_CONDITION_H
|
||||||
|
#define TNT_UTILS_GENERIC_CONDITION_H
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
class Condition : public std::condition_variable {
|
||||||
|
public:
|
||||||
|
using std::condition_variable::condition_variable;
|
||||||
|
|
||||||
|
inline void notify_n(size_t n) noexcept {
|
||||||
|
if (n == 1) {
|
||||||
|
notify_one();
|
||||||
|
} else if (n > 1) {
|
||||||
|
notify_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_GENERIC_CONDITION_H
|
||||||
56
ios/include/utils/generic/ThermalManager.h
Normal file
56
ios/include/utils/generic/ThermalManager.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_GENERIC_THERMALMANAGER_H
|
||||||
|
#define TNT_UTILS_GENERIC_THERMALMANAGER_H
|
||||||
|
|
||||||
|
#include <utils/compiler.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
class ThermalManager {
|
||||||
|
public:
|
||||||
|
enum class ThermalStatus : int8_t {
|
||||||
|
ERROR = -1,
|
||||||
|
NONE,
|
||||||
|
LIGHT,
|
||||||
|
MODERATE,
|
||||||
|
SEVERE,
|
||||||
|
CRITICAL,
|
||||||
|
EMERGENCY,
|
||||||
|
SHUTDOWN
|
||||||
|
};
|
||||||
|
|
||||||
|
ThermalManager() = default;
|
||||||
|
|
||||||
|
// Movable
|
||||||
|
ThermalManager(ThermalManager&& rhs) noexcept = default;
|
||||||
|
ThermalManager& operator=(ThermalManager&& rhs) noexcept = default;
|
||||||
|
|
||||||
|
// not copiable
|
||||||
|
ThermalManager(ThermalManager const& rhs) = delete;
|
||||||
|
ThermalManager& operator=(ThermalManager const& rhs) = delete;
|
||||||
|
|
||||||
|
ThermalStatus getCurrentThermalStatus() const noexcept {
|
||||||
|
return ThermalStatus::NONE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_GENERIC_THERMALMANAGER_H
|
||||||
123
ios/include/utils/linux/Condition.h
Normal file
123
ios/include/utils/linux/Condition.h
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_LINUX_CONDITION_H
|
||||||
|
#define TNT_UTILS_LINUX_CONDITION_H
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <chrono>
|
||||||
|
#include <condition_variable> // for cv_status
|
||||||
|
#include <limits>
|
||||||
|
#include <mutex> // for unique_lock
|
||||||
|
|
||||||
|
#include <utils/linux/Mutex.h>
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A very simple condition variable class that can be used as an (almost) drop-in replacement
|
||||||
|
* for std::condition_variable (doesn't have the timed wait() though).
|
||||||
|
* It is very low overhead as most of it is inlined.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Condition {
|
||||||
|
public:
|
||||||
|
Condition() noexcept = default;
|
||||||
|
Condition(const Condition&) = delete;
|
||||||
|
Condition& operator=(const Condition&) = delete;
|
||||||
|
|
||||||
|
void notify_all() noexcept {
|
||||||
|
pulse(std::numeric_limits<int>::max());
|
||||||
|
}
|
||||||
|
|
||||||
|
void notify_one() noexcept {
|
||||||
|
pulse(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void notify_n(size_t n) noexcept {
|
||||||
|
if (n > 0) pulse(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wait(std::unique_lock<Mutex>& lock) noexcept {
|
||||||
|
wait_until(lock.mutex(), false, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class P>
|
||||||
|
void wait(std::unique_lock<Mutex>& lock, P predicate) {
|
||||||
|
while (!predicate()) {
|
||||||
|
wait(lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename D>
|
||||||
|
std::cv_status wait_until(std::unique_lock<Mutex>& lock,
|
||||||
|
const std::chrono::time_point<std::chrono::steady_clock, D>& timeout_time) noexcept {
|
||||||
|
// convert to nanoseconds
|
||||||
|
uint64_t ns = std::chrono::duration<uint64_t, std::nano>(timeout_time.time_since_epoch()).count();
|
||||||
|
using sec_t = decltype(timespec::tv_sec);
|
||||||
|
using nsec_t = decltype(timespec::tv_nsec);
|
||||||
|
timespec ts{ sec_t(ns / 1000000000), nsec_t(ns % 1000000000) };
|
||||||
|
return wait_until(lock.mutex(), false, &ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename D>
|
||||||
|
std::cv_status wait_until(std::unique_lock<Mutex>& lock,
|
||||||
|
const std::chrono::time_point<std::chrono::system_clock, D>& timeout_time) noexcept {
|
||||||
|
// convert to nanoseconds
|
||||||
|
uint64_t ns = std::chrono::duration<uint64_t, std::nano>(timeout_time.time_since_epoch()).count();
|
||||||
|
using sec_t = decltype(timespec::tv_sec);
|
||||||
|
using nsec_t = decltype(timespec::tv_nsec);
|
||||||
|
timespec ts{ sec_t(ns / 1000000000), nsec_t(ns % 1000000000) };
|
||||||
|
return wait_until(lock.mutex(), true, &ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename C, typename D, typename P>
|
||||||
|
bool wait_until(std::unique_lock<Mutex>& lock,
|
||||||
|
const std::chrono::time_point<C, D>& timeout_time, P predicate) noexcept {
|
||||||
|
while (!predicate()) {
|
||||||
|
if (wait_until(lock, timeout_time) == std::cv_status::timeout) {
|
||||||
|
return predicate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename R, typename Period>
|
||||||
|
std::cv_status wait_for(std::unique_lock<Mutex>& lock,
|
||||||
|
const std::chrono::duration<R, Period>& rel_time) noexcept {
|
||||||
|
return wait_until(lock, std::chrono::steady_clock::now() + rel_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename R, typename Period, typename P>
|
||||||
|
bool wait_for(std::unique_lock<Mutex>& lock,
|
||||||
|
const std::chrono::duration<R, Period>& rel_time, P pred) noexcept {
|
||||||
|
return wait_until(lock, std::chrono::steady_clock::now() + rel_time, std::move(pred));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::atomic<uint32_t> mState = { 0 };
|
||||||
|
|
||||||
|
void pulse(int threadCount) noexcept;
|
||||||
|
|
||||||
|
std::cv_status wait_until(Mutex* lock,
|
||||||
|
bool realtimeClock, timespec* ts) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_LINUX_CONDITION_H
|
||||||
64
ios/include/utils/linux/Mutex.h
Normal file
64
ios/include/utils/linux/Mutex.h
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_LINUX_MUTEX_H
|
||||||
|
#define TNT_UTILS_LINUX_MUTEX_H
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
#include <utils/compiler.h>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A very simple mutex class that can be used as an (almost) drop-in replacement
|
||||||
|
* for std::mutex.
|
||||||
|
* It is very low overhead as most of it is inlined.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Mutex {
|
||||||
|
public:
|
||||||
|
constexpr Mutex() noexcept = default;
|
||||||
|
Mutex(const Mutex&) = delete;
|
||||||
|
Mutex& operator=(const Mutex&) = delete;
|
||||||
|
|
||||||
|
void lock() noexcept {
|
||||||
|
uint32_t old_state = UNLOCKED;
|
||||||
|
if (UTILS_UNLIKELY(!mState.compare_exchange_strong(old_state,
|
||||||
|
LOCKED, std::memory_order_acquire, std::memory_order_relaxed))) {
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void unlock() noexcept {
|
||||||
|
if (UTILS_UNLIKELY(mState.exchange(UNLOCKED, std::memory_order_release) == LOCKED_CONTENDED)) {
|
||||||
|
wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum {
|
||||||
|
UNLOCKED = 0, LOCKED = 1, LOCKED_CONTENDED = 2
|
||||||
|
};
|
||||||
|
std::atomic<uint32_t> mState = { UNLOCKED };
|
||||||
|
|
||||||
|
void wait() noexcept;
|
||||||
|
void wake() noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_LINUX_MUTEX_H
|
||||||
@@ -30,15 +30,13 @@
|
|||||||
namespace utils {
|
namespace utils {
|
||||||
|
|
||||||
inline void* aligned_alloc(size_t size, size_t align) noexcept {
|
inline void* aligned_alloc(size_t size, size_t align) noexcept {
|
||||||
|
// 'align' must be a power of two and a multiple of sizeof(void*)
|
||||||
|
align = (align < sizeof(void*)) ? sizeof(void*) : align;
|
||||||
assert(align && !(align & align - 1));
|
assert(align && !(align & align - 1));
|
||||||
|
assert((align % sizeof(void*)) == 0);
|
||||||
|
|
||||||
void* p = nullptr;
|
void* p = nullptr;
|
||||||
|
|
||||||
// must be a power of two and >= sizeof(void*)
|
|
||||||
while (align < sizeof(void*)) {
|
|
||||||
align <<= 1u;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(WIN32)
|
#if defined(WIN32)
|
||||||
p = ::_aligned_malloc(size, align);
|
p = ::_aligned_malloc(size, align);
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -17,13 +17,14 @@
|
|||||||
#ifndef TNT_UTILS_OSTREAM_H
|
#ifndef TNT_UTILS_OSTREAM_H
|
||||||
#define TNT_UTILS_OSTREAM_H
|
#define TNT_UTILS_OSTREAM_H
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include <utils/bitset.h>
|
#include <utils/bitset.h>
|
||||||
#include <utils/compiler.h>
|
#include <utils/compiler.h>
|
||||||
#include <utils/PrivateImplementation.h>
|
#include <utils/PrivateImplementation.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace utils::io {
|
namespace utils::io {
|
||||||
|
|
||||||
struct ostream_;
|
struct ostream_;
|
||||||
@@ -60,6 +61,9 @@ public:
|
|||||||
ostream& operator<<(const char* string) noexcept;
|
ostream& operator<<(const char* string) noexcept;
|
||||||
ostream& operator<<(const unsigned char* string) noexcept;
|
ostream& operator<<(const unsigned char* string) noexcept;
|
||||||
|
|
||||||
|
ostream& operator<<(std::string const& s) noexcept;
|
||||||
|
ostream& operator<<(std::string_view const& s) noexcept;
|
||||||
|
|
||||||
ostream& operator<<(ostream& (* f)(ostream&)) noexcept { return f(*this); }
|
ostream& operator<<(ostream& (* f)(ostream&)) noexcept { return f(*this); }
|
||||||
|
|
||||||
ostream& dec() noexcept;
|
ostream& dec() noexcept;
|
||||||
@@ -110,9 +114,6 @@ private:
|
|||||||
const char* getFormat(type t) const noexcept;
|
const char* getFormat(type t) const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
// handles std::string
|
|
||||||
inline ostream& operator << (ostream& o, std::string const& s) noexcept { return o << s.c_str(); }
|
|
||||||
|
|
||||||
// handles utils::bitset
|
// handles utils::bitset
|
||||||
inline ostream& operator << (ostream& o, utils::bitset32 const& s) noexcept {
|
inline ostream& operator << (ostream& o, utils::bitset32 const& s) noexcept {
|
||||||
return o << (void*)uintptr_t(s.getValue());
|
return o << (void*)uintptr_t(s.getValue());
|
||||||
@@ -131,7 +132,7 @@ inline ostream& operator<<(ostream& stream, const VECTOR<T>& v) {
|
|||||||
|
|
||||||
inline ostream& hex(ostream& s) noexcept { return s.hex(); }
|
inline ostream& hex(ostream& s) noexcept { return s.hex(); }
|
||||||
inline ostream& dec(ostream& s) noexcept { return s.dec(); }
|
inline ostream& dec(ostream& s) noexcept { return s.dec(); }
|
||||||
inline ostream& endl(ostream& s) noexcept { s << "\n"; return s.flush(); }
|
inline ostream& endl(ostream& s) noexcept { s << '\n'; return s.flush(); }
|
||||||
inline ostream& flush(ostream& s) noexcept { return s.flush(); }
|
inline ostream& flush(ostream& s) noexcept { return s.flush(); }
|
||||||
|
|
||||||
} // namespace utils::io
|
} // namespace utils::io
|
||||||
|
|||||||
32
ios/include/utils/sstream.h
Normal file
32
ios/include/utils/sstream.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_SSTREAM_H
|
||||||
|
#define TNT_UTILS_SSTREAM_H
|
||||||
|
|
||||||
|
#include <utils/ostream.h>
|
||||||
|
|
||||||
|
namespace utils::io {
|
||||||
|
|
||||||
|
class sstream : public ostream {
|
||||||
|
public:
|
||||||
|
ostream& flush() noexcept override;
|
||||||
|
const char* c_str() const noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace utils::io
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_SSTREAM_H
|
||||||
28
ios/include/utils/string.h
Normal file
28
ios/include/utils/string.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_STRING_H
|
||||||
|
#define TNT_UTILS_STRING_H
|
||||||
|
|
||||||
|
#include <utils/ostream.h>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
float strtof_c(const char* start, char** end);
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_STRING_H
|
||||||
40
ios/include/utils/trap.h
Normal file
40
ios/include/utils/trap.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_TRAP_H
|
||||||
|
#define TNT_UTILS_TRAP_H
|
||||||
|
|
||||||
|
#include <csignal>
|
||||||
|
|
||||||
|
#if defined(WIN32)
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <utils/unwindows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
// This can be used as a programmatic breakpoint.
|
||||||
|
inline void debug_trap() noexcept {
|
||||||
|
#if defined(WIN32)
|
||||||
|
DebugBreak();
|
||||||
|
#else
|
||||||
|
std::raise(SIGINT);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace utils
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_TRAP_H
|
||||||
61
ios/include/utils/vector.h
Normal file
61
ios/include/utils/vector.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_VECTOR_H
|
||||||
|
#define TNT_UTILS_VECTOR_H
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace utils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts the specified item in the vector at its sorted position.
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
static inline void insert_sorted(std::vector<T>& v, T item) {
|
||||||
|
auto pos = std::lower_bound(v.begin(), v.end(), item);
|
||||||
|
v.insert(pos, std::move(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts the specified item in the vector at its sorted position.
|
||||||
|
* The item type must implement the < operator. If the specified
|
||||||
|
* item is already present in the vector, this method returns without
|
||||||
|
* inserting the item again.
|
||||||
|
*
|
||||||
|
* @return True if the item was inserted at is sorted position, false
|
||||||
|
* if the item already exists in the vector.
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
static inline bool insert_sorted_unique(std::vector<T>& v, T item) {
|
||||||
|
if (UTILS_LIKELY(v.size() == 0 || v.back() < item)) {
|
||||||
|
v.push_back(item);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pos = std::lower_bound(v.begin(), v.end(), item);
|
||||||
|
if (UTILS_LIKELY(pos == v.end() || item < *pos)) {
|
||||||
|
v.insert(pos, std::move(item));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end utils namespace
|
||||||
|
|
||||||
|
#endif // TNT_UTILS_VECTOR_H
|
||||||
33
ios/include/utils/win32/stdtypes.h
Normal file
33
ios/include/utils/win32/stdtypes.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TNT_UTILS_WIN32_STDTYPES_H
|
||||||
|
#define TNT_UTILS_WIN32_STDTYPES_H
|
||||||
|
|
||||||
|
#if defined(WIN32)
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
// Copied from linux libc sys/stat.h:
|
||||||
|
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
||||||
|
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||||||
|
#define PATH_MAX (MAX_PATH)
|
||||||
|
|
||||||
|
// For getcwd
|
||||||
|
#include <direct.h>
|
||||||
|
#define getcwd _getcwd
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif // TNT_UTILS_WIN32_STDTYPES_H
|
||||||
@@ -40,7 +40,7 @@ namespace viewer {
|
|||||||
*
|
*
|
||||||
* When executing a test, clients should call tick() after each frame is rendered, which gives
|
* When executing a test, clients should call tick() after each frame is rendered, which gives
|
||||||
* automation an opportunity to push settings to Filament, increment the current test index (if
|
* automation an opportunity to push settings to Filament, increment the current test index (if
|
||||||
* enough time has elapsed), and request an asychronous screenshot.
|
* enough time has elapsed), and request an asynchronous screenshot.
|
||||||
*
|
*
|
||||||
* The time to sleep between tests is configurable and can be set to zero. Automation also waits a
|
* The time to sleep between tests is configurable and can be set to zero. Automation also waits a
|
||||||
* specified minimum number of frames between tests.
|
* specified minimum number of frames between tests.
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ using MultiSampleAntiAliasingOptions = filament::View::MultiSampleAntiAliasingOp
|
|||||||
using TemporalAntiAliasingOptions = filament::View::TemporalAntiAliasingOptions;
|
using TemporalAntiAliasingOptions = filament::View::TemporalAntiAliasingOptions;
|
||||||
using VignetteOptions = filament::View::VignetteOptions;
|
using VignetteOptions = filament::View::VignetteOptions;
|
||||||
using VsmShadowOptions = filament::View::VsmShadowOptions;
|
using VsmShadowOptions = filament::View::VsmShadowOptions;
|
||||||
|
using GuardBandOptions = filament::View::GuardBandOptions;
|
||||||
using LightManager = filament::LightManager;
|
using LightManager = filament::LightManager;
|
||||||
|
|
||||||
// These functions push all editable property values to their respective Filament objects.
|
// These functions push all editable property values to their respective Filament objects.
|
||||||
@@ -171,6 +172,7 @@ struct ViewSettings {
|
|||||||
TemporalAntiAliasingOptions taa;
|
TemporalAntiAliasingOptions taa;
|
||||||
VignetteOptions vignette;
|
VignetteOptions vignette;
|
||||||
VsmShadowOptions vsmShadowOptions;
|
VsmShadowOptions vsmShadowOptions;
|
||||||
|
GuardBandOptions guardBand;
|
||||||
|
|
||||||
// Custom View Options
|
// Custom View Options
|
||||||
ColorGradingSettings colorGrading;
|
ColorGradingSettings colorGrading;
|
||||||
@@ -194,7 +196,7 @@ struct LightSettings {
|
|||||||
LightManager::ShadowOptions shadowOptions;
|
LightManager::ShadowOptions shadowOptions;
|
||||||
SoftShadowOptions softShadowOptions;
|
SoftShadowOptions softShadowOptions;
|
||||||
float sunlightIntensity = 100000.0f;
|
float sunlightIntensity = 100000.0f;
|
||||||
math::float3 sunlightDirection = {0.6, -1.0, -0.8};;
|
math::float3 sunlightDirection = {0.6, -1.0, -0.8};
|
||||||
math::float3 sunlightColor = filament::Color::toLinear<filament::ACCURATE>({ 0.98, 0.92, 0.89});
|
math::float3 sunlightColor = filament::Color::toLinear<filament::ACCURATE>({ 0.98, 0.92, 0.89});
|
||||||
float iblIntensity = 30000.0f;
|
float iblIntensity = 30000.0f;
|
||||||
float iblRotation = 0.0f;
|
float iblRotation = 0.0f;
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef VIEWER_SIMPLEVIEWER_H
|
#ifndef VIEWER_VIEWERGUI_H
|
||||||
#define VIEWER_SIMPLEVIEWER_H
|
#define VIEWER_VIEWERGUI_H
|
||||||
|
|
||||||
#include <filament/Box.h>
|
#include <filament/Box.h>
|
||||||
#include <filament/DebugRegistry.h>
|
#include <filament/DebugRegistry.h>
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
#include <gltfio/Animator.h>
|
#include <gltfio/Animator.h>
|
||||||
#include <gltfio/FilamentAsset.h>
|
#include <gltfio/FilamentAsset.h>
|
||||||
|
#include <gltfio/NodeManager.h>
|
||||||
|
|
||||||
#include <viewer/Settings.h>
|
#include <viewer/Settings.h>
|
||||||
|
|
||||||
@@ -35,6 +36,7 @@
|
|||||||
#include <math/mat4.h>
|
#include <math/mat4.h>
|
||||||
#include <math/vec3.h>
|
#include <math/vec3.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace filagui {
|
namespace filagui {
|
||||||
@@ -45,15 +47,15 @@ namespace filament {
|
|||||||
namespace viewer {
|
namespace viewer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \class SimpleViewer SimpleViewer.h viewer/SimpleViewer.h
|
* \class ViewerGui ViewerGui.h viewer/ViewerGui.h
|
||||||
* \brief Manages the state for a simple glTF viewer with imgui controls and a tree view.
|
* \brief Builds ImGui widgets for a simple glTF viewer and manages the associated state.
|
||||||
*
|
*
|
||||||
* This is a utility that can be used across multiple platforms, including web.
|
* This is a utility that can be used across multiple platforms, including web.
|
||||||
*
|
*
|
||||||
* \note If you don't need ImGui controls, there is no need to use this class, just use AssetLoader
|
* \note If you don't need ImGui controls, there is no need to use this class, just use AssetLoader
|
||||||
* instead.
|
* instead.
|
||||||
*/
|
*/
|
||||||
class UTILS_PUBLIC SimpleViewer {
|
class UTILS_PUBLIC ViewerGui {
|
||||||
public:
|
public:
|
||||||
using Animator = gltfio::Animator;
|
using Animator = gltfio::Animator;
|
||||||
using FilamentAsset = gltfio::FilamentAsset;
|
using FilamentAsset = gltfio::FilamentAsset;
|
||||||
@@ -62,29 +64,39 @@ public:
|
|||||||
static constexpr int DEFAULT_SIDEBAR_WIDTH = 350;
|
static constexpr int DEFAULT_SIDEBAR_WIDTH = 350;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a SimpleViewer that has a fixed association with the given Filament objects.
|
* Constructs a ViewerGui that has a fixed association with the given Filament objects.
|
||||||
*
|
*
|
||||||
* Upon construction, the simple viewer may create some additional Filament objects (such as
|
* Upon construction, the simple viewer may create some additional Filament objects (such as
|
||||||
* light sources) that it owns.
|
* light sources) that it owns.
|
||||||
*/
|
*/
|
||||||
SimpleViewer(filament::Engine* engine, filament::Scene* scene, filament::View* view,
|
ViewerGui(filament::Engine* engine, filament::Scene* scene, filament::View* view,
|
||||||
int sidebarWidth = DEFAULT_SIDEBAR_WIDTH);
|
int sidebarWidth = DEFAULT_SIDEBAR_WIDTH);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroys the SimpleViewer and any Filament entities that it owns.
|
* Destroys the ViewerGui and any Filament entities that it owns.
|
||||||
*/
|
*/
|
||||||
~SimpleViewer();
|
~ViewerGui();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the asset's ready-to-render entities into the scene.
|
* Sets the viewer's current asset.
|
||||||
*
|
*
|
||||||
* The viewer does not claim ownership over the asset or its entities. Clients should use
|
* The viewer does not claim ownership over the asset or its entities. Clients should use
|
||||||
* AssetLoader and ResourceLoader to load an asset before passing it in.
|
* AssetLoader and ResourceLoader to load an asset before passing it in.
|
||||||
*
|
*
|
||||||
|
* This method does not add renderables to the scene; see populateScene().
|
||||||
|
*
|
||||||
* @param asset The asset to view.
|
* @param asset The asset to view.
|
||||||
* @param instanceToAnimate Optional instance from which to get the animator.
|
* @param instanceToAnimate Optional instance from which to get the animator.
|
||||||
*/
|
*/
|
||||||
void populateScene(FilamentAsset* asset, FilamentInstance* instanceToAnimate = nullptr);
|
void setAsset(FilamentAsset* asset, FilamentInstance* instanceToAnimate = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the asset's ready-to-render entities into the scene.
|
||||||
|
*
|
||||||
|
* This is used for asychronous loading. It can be called once per frame to gradually add
|
||||||
|
* entities into the scene as their textures are loaded.
|
||||||
|
*/
|
||||||
|
void populateScene();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the current asset from the viewer.
|
* Removes the current asset from the viewer.
|
||||||
@@ -126,7 +138,7 @@ public:
|
|||||||
void renderUserInterface(float timeStepInSeconds, filament::View* guiView, float pixelRatio);
|
void renderUserInterface(float timeStepInSeconds, filament::View* guiView, float pixelRatio);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event-passing methods, useful only when SimpleViewer manages its own instance of ImGuiHelper.
|
* Event-passing methods, useful only when ViewerGui manages its own instance of ImGuiHelper.
|
||||||
* The key codes used in these methods are just normal ASCII/ANSI codes.
|
* The key codes used in these methods are just normal ASCII/ANSI codes.
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
@@ -218,8 +230,14 @@ public:
|
|||||||
int getCurrentCamera() const { return mCurrentCamera; }
|
int getCurrentCamera() const { return mCurrentCamera; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using SceneMask = gltfio::NodeManager::SceneMask;
|
||||||
|
|
||||||
void updateIndirectLight();
|
void updateIndirectLight();
|
||||||
|
|
||||||
|
bool isRemoteMode() const { return mAsset == nullptr; }
|
||||||
|
|
||||||
|
void sceneSelectionUI();
|
||||||
|
|
||||||
// Immutable properties set from the constructor.
|
// Immutable properties set from the constructor.
|
||||||
filament::Engine* const mEngine;
|
filament::Engine* const mEngine;
|
||||||
filament::Scene* const mScene;
|
filament::Scene* const mScene;
|
||||||
@@ -238,7 +256,6 @@ private:
|
|||||||
// Properties that can be changed from the UI.
|
// Properties that can be changed from the UI.
|
||||||
int mCurrentAnimation = 1; // It is a 1-based index and 0 means not playing animation
|
int mCurrentAnimation = 1; // It is a 1-based index and 0 means not playing animation
|
||||||
int mCurrentVariant = 0;
|
int mCurrentVariant = 0;
|
||||||
bool mResetAnimation = true;
|
|
||||||
bool mEnableWireframe = false;
|
bool mEnableWireframe = false;
|
||||||
int mVsmMsaaSamplesLog2 = 1;
|
int mVsmMsaaSamplesLog2 = 1;
|
||||||
Settings mSettings;
|
Settings mSettings;
|
||||||
@@ -246,10 +263,19 @@ private:
|
|||||||
uint32_t mFlags;
|
uint32_t mFlags;
|
||||||
utils::Entity mCurrentMorphingEntity;
|
utils::Entity mCurrentMorphingEntity;
|
||||||
std::vector<float> mMorphWeights;
|
std::vector<float> mMorphWeights;
|
||||||
|
SceneMask mVisibleScenes;
|
||||||
|
bool mShowingRestPose = false;
|
||||||
|
|
||||||
// 0 is the default "free camera". Additional cameras come from the gltf file (1-based index).
|
// 0 is the default "free camera". Additional cameras come from the gltf file (1-based index).
|
||||||
int mCurrentCamera = 0;
|
int mCurrentCamera = 0;
|
||||||
|
|
||||||
|
// Cross fade animation parameters.
|
||||||
|
float mCrossFadeDuration = 0.5f; // number of seconds to transition between animations
|
||||||
|
int mPreviousAnimation = 0; // one-based index of the previous animation
|
||||||
|
double mCurrentStartTime = 0.0f; // start time of most recent cross-fade (seconds)
|
||||||
|
double mPreviousStartTime = 0.0f; // start time of previous cross-fade (seconds)
|
||||||
|
bool mResetAnimation = true; // set when building ImGui widgets, honored in applyAnimation
|
||||||
|
|
||||||
// Color grading UI state.
|
// Color grading UI state.
|
||||||
float mToneMapPlot[1024];
|
float mToneMapPlot[1024];
|
||||||
float mRangePlot[1024 * 3];
|
float mRangePlot[1024 * 3];
|
||||||
@@ -262,4 +288,4 @@ filament::math::mat4f fitIntoUnitCube(const filament::Aabb& bounds, float zoffse
|
|||||||
} // namespace viewer
|
} // namespace viewer
|
||||||
} // namespace filament
|
} // namespace filament
|
||||||
|
|
||||||
#endif // VIEWER_SIMPLEVIEWER_H
|
#endif // VIEWER_VIEWERGUI_H
|
||||||
Reference in New Issue
Block a user