update headers to Filament v1.25.0
This commit is contained in:
@@ -33,7 +33,6 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace filament {
|
||||
/**
|
||||
* Types and enums used by filament's driver.
|
||||
*
|
||||
@@ -41,24 +40,24 @@ namespace filament {
|
||||
* internal redeclaration of these types.
|
||||
* 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_READABLE = 0x2;
|
||||
static constexpr uint64_t SWAP_CHAIN_CONFIG_ENABLE_XCB = 0x4;
|
||||
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_ENABLE_XCB = 0x4;
|
||||
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_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_VERTEX_BUFFER_COUNT = 16; // Max number of bound buffer objects.
|
||||
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_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_VERTEX_BUFFER_COUNT = 16; // Max number of bound buffer objects.
|
||||
|
||||
static_assert(MAX_VERTEX_BUFFER_COUNT <= MAX_VERTEX_ATTRIBUTE_COUNT,
|
||||
"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.");
|
||||
|
||||
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.
|
||||
@@ -129,7 +128,6 @@ inline constexpr TargetBufferFlags getTargetBufferFlagsAt(size_t index) noexcept
|
||||
enum class BufferUsage : uint8_t {
|
||||
STATIC, //!< content modified once, 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 height; //!< height in pixels
|
||||
//! 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
|
||||
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()
|
||||
*/
|
||||
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.
|
||||
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
|
||||
*/
|
||||
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.
|
||||
NOT_SIGNALED = 1, //!< The Sync is not signaled yet
|
||||
};
|
||||
@@ -720,7 +718,7 @@ enum class SamplerCompareMode : uint8_t {
|
||||
COMPARE_TO_TEXTURE = 1
|
||||
};
|
||||
|
||||
//! comparison function for the depth sampler
|
||||
//! comparison function for the depth / stencil sampler
|
||||
enum class SamplerCompareFunc : uint8_t {
|
||||
// don't change the enums values
|
||||
LE = 0, //!< Less or equal
|
||||
@@ -729,11 +727,11 @@ enum class SamplerCompareFunc : uint8_t {
|
||||
G, //!< Strictly greater than
|
||||
E, //!< Equal
|
||||
NE, //!< Not equal
|
||||
A, //!< Always. Depth testing is deactivated.
|
||||
N //!< Never. The depth test always fails.
|
||||
A, //!< Always. Depth / stencil testing is deactivated.
|
||||
N //!< Never. The depth / stencil test always fails.
|
||||
};
|
||||
|
||||
//! Sampler paramters
|
||||
//! Sampler parameters
|
||||
struct SamplerParams { // NOLINT
|
||||
union {
|
||||
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
|
||||
};
|
||||
|
||||
//! 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
|
||||
enum class StreamType {
|
||||
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+.
|
||||
};
|
||||
|
||||
@@ -819,9 +828,11 @@ struct RasterState {
|
||||
using DepthFunc = backend::SamplerCompareFunc;
|
||||
using BlendEquation = backend::BlendEquation;
|
||||
using BlendFunction = backend::BlendFunction;
|
||||
using StencilFunction = backend::SamplerCompareFunc;
|
||||
using StencilOperation = backend::StencilOperation;
|
||||
|
||||
RasterState() noexcept { // NOLINT
|
||||
static_assert(sizeof(RasterState) == sizeof(uint32_t),
|
||||
static_assert(sizeof(RasterState) == sizeof(uint64_t),
|
||||
"RasterState size not what was intended");
|
||||
culling = CullingMode::BACK;
|
||||
blendEquationRGB = BlendEquation::ADD;
|
||||
@@ -830,6 +841,10 @@ struct RasterState {
|
||||
blendFunctionSrcAlpha = BlendFunction::ONE;
|
||||
blendFunctionDstRGB = 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; }
|
||||
@@ -858,40 +873,56 @@ struct RasterState {
|
||||
union {
|
||||
struct {
|
||||
//! culling mode
|
||||
CullingMode culling : 2; // 2
|
||||
CullingMode culling : 2; // 2
|
||||
|
||||
//! blend equation for the red, green and blue components
|
||||
BlendEquation blendEquationRGB : 3; // 5
|
||||
BlendEquation blendEquationRGB : 3; // 5
|
||||
//! blend equation for the alpha component
|
||||
BlendEquation blendEquationAlpha : 3; // 8
|
||||
BlendEquation blendEquationAlpha : 3; // 8
|
||||
|
||||
//! blending function for the source color
|
||||
BlendFunction blendFunctionSrcRGB : 4; // 12
|
||||
BlendFunction blendFunctionSrcRGB : 4; // 12
|
||||
//! blending function for the source alpha
|
||||
BlendFunction blendFunctionSrcAlpha : 4; // 16
|
||||
BlendFunction blendFunctionSrcAlpha : 4; // 16
|
||||
//! blending function for the destination color
|
||||
BlendFunction blendFunctionDstRGB : 4; // 20
|
||||
BlendFunction blendFunctionDstRGB : 4; // 20
|
||||
//! blending function for the destination alpha
|
||||
BlendFunction blendFunctionDstAlpha : 4; // 24
|
||||
BlendFunction blendFunctionDstAlpha : 4; // 24
|
||||
|
||||
//! Whether depth-buffer writes are enabled
|
||||
bool depthWrite : 1; // 25
|
||||
bool depthWrite : 1; // 25
|
||||
//! Depth test function
|
||||
DepthFunc depthFunc : 3; // 28
|
||||
DepthFunc depthFunc : 3; // 28
|
||||
|
||||
//! Whether color-buffer writes are enabled
|
||||
bool colorWrite : 1; // 29
|
||||
bool colorWrite : 1; // 29
|
||||
|
||||
//! 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
|
||||
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
|
||||
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);
|
||||
}
|
||||
};
|
||||
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
|
||||
@@ -998,8 +1029,7 @@ enum class Workaround : uint16_t {
|
||||
ALLOW_READ_ONLY_ANCILLARY_FEEDBACK_LOOP
|
||||
};
|
||||
|
||||
} // namespace backend
|
||||
} // namespace filament
|
||||
} // namespace filament::backend
|
||||
|
||||
template<> struct utils::EnableBitMaskOperators<filament::backend::TargetBufferFlags>
|
||||
: public std::true_type {};
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
* underlying platform is returned and \p backendHint is updated
|
||||
* accordingly. Can't be nullptr.
|
||||
*
|
||||
* @return A pointer to the Plaform object.
|
||||
* @return A pointer to the Platform object.
|
||||
*
|
||||
* @see destroy
|
||||
*/
|
||||
|
||||
@@ -388,6 +388,9 @@ public:
|
||||
//! Enable / disable depth based culling (enabled by default, material instances can override).
|
||||
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).
|
||||
* doubleSided() overrides culling() if called.
|
||||
@@ -731,6 +734,7 @@ private:
|
||||
bool mDoubleSidedCapability = false;
|
||||
bool mColorWrite = true;
|
||||
bool mDepthTest = true;
|
||||
bool mInstanced = true;
|
||||
bool mDepthWrite = true;
|
||||
bool mDepthWriteSet = false;
|
||||
|
||||
|
||||
@@ -260,7 +260,7 @@ public:
|
||||
* range can be adjusted with this method.
|
||||
*
|
||||
* @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;
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ enum UTILS_PUBLIC ChunkType : uint64_t {
|
||||
MaterialColorWrite = charTo64bitNum("MAT_CWRIT"),
|
||||
MaterialDepthWrite = charTo64bitNum("MAT_DWRIT"),
|
||||
MaterialDepthTest = charTo64bitNum("MAT_DTEST"),
|
||||
MaterialInstanced = charTo64bitNum("MAT_INSTA"),
|
||||
MaterialCullingMode = charTo64bitNum("MAT_CUMO"),
|
||||
|
||||
MaterialHasCustomDepthShader =charTo64bitNum("MAT_CSDP"),
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
namespace filament {
|
||||
|
||||
// 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
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
* @param engine Reference to the filament::Engine associated with this MorphTargetBuffer.
|
||||
* @param targetIndex the index of morph target to be updated.
|
||||
* @param weights pointer to at least count positions
|
||||
* @param count number of position elements in positions
|
||||
* @param positions pointer to at least "count" 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
|
||||
*/
|
||||
void setPositionsAt(Engine& engine, size_t targetIndex,
|
||||
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.
|
||||
*
|
||||
* @param engine Reference to the filament::Engine associated with this MorphTargetBuffer.
|
||||
* @param targetIndex the index of morph target to be updated.
|
||||
* @param weights pointer to at least count positions
|
||||
* @param count number of position elements in positions
|
||||
* @see setPositionsAt
|
||||
* @param positions pointer to at least "count" positions
|
||||
* @param count number of float4 vectors in positions
|
||||
* @param offset offset into the target buffer, expressed as a number of float4 vectors
|
||||
* @see setTangentsAt
|
||||
*/
|
||||
void setPositionsAt(Engine& engine, size_t targetIndex,
|
||||
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 targetIndex the index of morph target to be updated.
|
||||
* @param tangents pointer to at least count tangents
|
||||
* @param count number of tangent elements in tangents
|
||||
* @see setTangentsAt
|
||||
* @param tangents pointer to at least "count" tangents
|
||||
* @param count number of short4 quaternions in tangents
|
||||
* @param offset offset into the target buffer, expressed as a number of short4 vectors
|
||||
* @see setPositionsAt
|
||||
*/
|
||||
void setTangentsAt(Engine& engine, size_t targetIndex,
|
||||
math::short4 const* tangents, size_t count, size_t offset = 0);
|
||||
|
||||
@@ -25,6 +25,9 @@ namespace filament {
|
||||
|
||||
class Texture;
|
||||
|
||||
/**
|
||||
* Generic quality level.
|
||||
*/
|
||||
enum class QualityLevel : uint8_t {
|
||||
LOW,
|
||||
MEDIUM,
|
||||
@@ -69,8 +72,8 @@ enum class BlendMode : uint8_t {
|
||||
*
|
||||
*/
|
||||
struct DynamicResolutionOptions {
|
||||
math::float2 minScale = math::float2(0.5f); //!< minimum scale factors in x and y
|
||||
math::float2 maxScale = math::float2(1.0f); //!< maximum 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 = {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)]
|
||||
bool enabled = false; //!< enable or disable dynamic resolution
|
||||
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
|
||||
INTERPOLATE //!< Bloom is interpolated with the scene using the strength parameter
|
||||
};
|
||||
Texture* dirt = nullptr; //!< user provided dirt texture
|
||||
float dirtStrength = 0.2f; //!< strength of the dirt texture
|
||||
Texture* dirt = nullptr; //!< user provided dirt texture %codegen_skip_json% %codegen_skip_javascript%
|
||||
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
|
||||
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)
|
||||
@@ -151,16 +154,16 @@ struct BloomOptions {
|
||||
* Options to control fog in the scene
|
||||
*/
|
||||
struct FogOptions {
|
||||
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 height = 0.0f; //!< fog's floor in world units
|
||||
float heightFalloff = 1.0f; //!< how fast fog dissipates with altitude
|
||||
LinearColor color{0.5f}; //!< fog's color (linear), see fogColorFromIbl
|
||||
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 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 enabled = false; //!< enable or disable fog
|
||||
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 height = 0.0f; //!< fog's floor in world units
|
||||
float heightFalloff = 1.0f; //!< how fast fog dissipates with altitude
|
||||
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 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).
|
||||
bool fogColorFromIbl = false; //!< Fog color will be modulated by the IBL color in the view direction.
|
||||
bool enabled = false; //!< enable or disable fog
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -174,8 +177,9 @@ struct FogOptions {
|
||||
*/
|
||||
struct DepthOfFieldOptions {
|
||||
enum class Filter : uint8_t {
|
||||
NONE = 0,
|
||||
MEDIAN = 2
|
||||
NONE,
|
||||
UNUSED,
|
||||
MEDIAN
|
||||
};
|
||||
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)
|
||||
@@ -227,7 +231,7 @@ struct VignetteOptions {
|
||||
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 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
|
||||
};
|
||||
|
||||
@@ -271,17 +275,18 @@ struct AmbientOcclusionOptions {
|
||||
* Ambient shadows from dominant light
|
||||
*/
|
||||
struct Ssct {
|
||||
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 contactDistanceMax = 1.0f; //!< max distance for contact
|
||||
float intensity = 0.8f; //!< intensity
|
||||
math::float3 lightDirection{ 0, -1, 0 }; //!< light direction
|
||||
float depthBias = 0.01f; //!< depth bias in world units (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 rayCount = 1; //!< # of rays to trace, between 1 and 255
|
||||
bool enabled = false; //!< enables or disables SSCT
|
||||
} ssct;
|
||||
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 contactDistanceMax = 1.0f; //!< max distance for contact
|
||||
float intensity = 0.8f; //!< intensity
|
||||
math::float3 lightDirection = { 0, -1, 0 }; //!< light direction
|
||||
float depthBias = 0.01f; //!< depth bias in world units (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 rayCount = 1; //!< # of rays to trace, between 1 and 255
|
||||
bool enabled = false; //!< enables or disables SSCT
|
||||
};
|
||||
Ssct ssct; // %codegen_skip_javascript% %codegen_java_flatten%
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -328,21 +333,31 @@ struct ScreenSpaceReflectionsOptions {
|
||||
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.
|
||||
* @see setAntiAliasing, getAntiAliasing, setSampleCount
|
||||
*/
|
||||
enum class AntiAliasing : uint8_t {
|
||||
NONE = 0, //!< no anti aliasing performed as part of post-processing
|
||||
FXAA = 1 //!< FXAA is a low-quality but very efficient type of anti-aliasing. (default).
|
||||
NONE, //!< no anti aliasing performed as part of post-processing
|
||||
FXAA //!< FXAA is a low-quality but very efficient type of anti-aliasing. (default).
|
||||
};
|
||||
|
||||
/**
|
||||
* List of available post-processing dithering techniques.
|
||||
*/
|
||||
enum class Dithering : uint8_t {
|
||||
NONE = 0, //!< No dithering
|
||||
TEMPORAL = 1 //!< Temporal dithering (default)
|
||||
NONE, //!< No dithering
|
||||
TEMPORAL //!< Temporal dithering (default)
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -205,10 +205,12 @@ public:
|
||||
* avoid using a separate View for the HUD. Note that priority is completely orthogonal to
|
||||
* 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
|
||||
* (rendered last).
|
||||
* @return Builder reference for chaining calls.
|
||||
*
|
||||
* @see Builder::blendOrder(), RenderableManager::setBlendOrderAt()
|
||||
*/
|
||||
Builder& priority(uint8_t priority) noexcept;
|
||||
|
||||
@@ -337,23 +339,44 @@ public:
|
||||
*/
|
||||
Builder& morphing(uint8_t level, size_t primitiveIndex,
|
||||
MorphTargetBuffer* morphTargetBuffer, size_t offset, size_t count) noexcept;
|
||||
|
||||
inline Builder& morphing(uint8_t level, size_t primitiveIndex,
|
||||
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 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;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* @param instanceCount the number of instances silently clamped between 1 and 65535.
|
||||
@@ -394,6 +417,7 @@ public:
|
||||
MaterialInstance const* materialInstance = nullptr;
|
||||
PrimitiveType type = PrimitiveType::TRIANGLES;
|
||||
uint16_t blendOrder = 0;
|
||||
bool globalBlendOrderEnabled = false;
|
||||
struct {
|
||||
MorphTargetBuffer* buffer = nullptr;
|
||||
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
|
||||
|
||||
/**
|
||||
* 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,
|
||||
size_t count, size_t offset);
|
||||
@@ -511,7 +543,7 @@ public:
|
||||
* @param instance Instance of the component obtained from getInstance().
|
||||
* @param weights Pointer to morph target weights to be update.
|
||||
* @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,
|
||||
float const* weights, size_t count, size_t offset = 0);
|
||||
@@ -578,24 +610,28 @@ public:
|
||||
size_t offset, size_t count) noexcept;
|
||||
|
||||
/**
|
||||
* Changes the active range of indices or topology for the given primitive.
|
||||
*
|
||||
* \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()
|
||||
* 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.
|
||||
*
|
||||
* @param instance the renderable of interest
|
||||
* @param primitiveIndex the primitive of interest
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@@ -80,11 +80,8 @@ public:
|
||||
// refresh-rate of the display in Hz. set to 0 for offscreen or turn off frame-pacing.
|
||||
float refreshRate = 60.0f;
|
||||
|
||||
// how far in advance a buffer must be queued for presentation at a given time in ns
|
||||
uint64_t presentationDeadlineNanos = 0;
|
||||
|
||||
// offset by which vsyncSteadyClockTimeNano provided in beginFrame() is offset in ns
|
||||
uint64_t vsyncOffsetNanos = 0;
|
||||
[[deprecated]] uint64_t presentationDeadlineNanos = 0;
|
||||
[[deprecated]] uint64_t vsyncOffsetNanos = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -243,6 +240,20 @@ public:
|
||||
bool beginFrame(SwapChain* swapChain,
|
||||
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.
|
||||
*
|
||||
@@ -444,6 +455,10 @@ public:
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
* a structured UBO.
|
||||
* @see RenderableManager::setSkinningBuffer
|
||||
*/
|
||||
class UTILS_PUBLIC SkinningBuffer : public FilamentAPI {
|
||||
struct BuilderDetails;
|
||||
@@ -93,6 +94,7 @@ public:
|
||||
* @param transforms pointer to at least count Bone
|
||||
* @param count number of Bone elements 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,
|
||||
size_t count, size_t offset = 0);
|
||||
@@ -103,6 +105,7 @@ public:
|
||||
* @param transforms pointer to at least count mat4f
|
||||
* @param count number of mat4f elements 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,
|
||||
size_t count, size_t offset = 0);
|
||||
|
||||
@@ -124,7 +124,7 @@ public:
|
||||
*
|
||||
* Ignored if an environment is set.
|
||||
*
|
||||
* @param color
|
||||
* @param color the constant color
|
||||
*
|
||||
* @return This Builder, for chaining calls.
|
||||
*/
|
||||
|
||||
@@ -35,10 +35,9 @@ class Engine;
|
||||
/**
|
||||
* 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:
|
||||
*
|
||||
* - TEXTURE_ID...takes an OpenGL texture ID and incurs a copy
|
||||
* - ACQUIRED.....connects to an Android AHardwareBuffer
|
||||
* - NATIVE.......connects to an Android SurfaceTexture
|
||||
*
|
||||
@@ -67,10 +66,6 @@ class Engine;
|
||||
* - Filament invokes low-level graphics commands on the \em{driver 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
|
||||
* the stream, then releases it later via a callback function. This configuration is especially
|
||||
* 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
|
||||
* <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.
|
||||
*/
|
||||
class Builder : public BuilderBase<BuilderDetails> {
|
||||
@@ -122,23 +117,6 @@ public:
|
||||
*/
|
||||
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
|
||||
@@ -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;
|
||||
|
||||
@@ -190,7 +168,7 @@ public:
|
||||
* 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.
|
||||
*
|
||||
* @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 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;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
||||
@@ -134,12 +134,12 @@ struct UTILS_PUBLIC GenericToneMapper final : public ToneMapper {
|
||||
* constructor parameters approximate an ACES tone mapping curve
|
||||
* and the maximum input value is set to 10.0.
|
||||
*
|
||||
* @param contrast: controls the contrast of the curve, must be > 0.0, values
|
||||
* in the range 0.5..2.0 are recommended.
|
||||
* @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 hdrMax: defines the maximum input value that will be mapped to
|
||||
* output white. Must be >= 1.0.
|
||||
* @param contrast controls the contrast of the curve, must be > 0.0, values
|
||||
* in the range 0.5..2.0 are recommended.
|
||||
* @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 hdrMax defines the maximum input value that will be mapped to
|
||||
* output white. Must be >= 1.0.
|
||||
*/
|
||||
explicit GenericToneMapper(
|
||||
float contrast = 1.55f,
|
||||
|
||||
@@ -84,6 +84,7 @@ public:
|
||||
using VsmShadowOptions = VsmShadowOptions;
|
||||
using SoftShadowOptions = SoftShadowOptions;
|
||||
using ScreenSpaceReflectionsOptions = ScreenSpaceReflectionsOptions;
|
||||
using GuardBandOptions = GuardBandOptions;
|
||||
|
||||
/**
|
||||
* Sets the View's name. Only useful for debugging.
|
||||
@@ -345,6 +346,20 @@ public:
|
||||
*/
|
||||
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.
|
||||
*
|
||||
|
||||
@@ -43,11 +43,6 @@ public:
|
||||
*/
|
||||
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
|
||||
*
|
||||
@@ -67,16 +62,7 @@ public:
|
||||
*/
|
||||
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:
|
||||
|
||||
/**
|
||||
* Compares two Viewports for equality
|
||||
* @param lhs reference to the left hand side Viewport
|
||||
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
|
||||
void unregisterAll();
|
||||
|
||||
std::size_t numRegistered() const noexcept;
|
||||
size_t numRegistered() const noexcept;
|
||||
|
||||
void getRegisteredMaterials(filament::MaterialInstance** materialList,
|
||||
utils::CString* materialNameList) const;
|
||||
|
||||
@@ -31,6 +31,7 @@ enum class ComponentType {
|
||||
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]
|
||||
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/FilamentInstance.h>
|
||||
|
||||
namespace gltfio {
|
||||
namespace filament::gltfio {
|
||||
|
||||
struct FFilamentAsset;
|
||||
struct FFilamentInstance;
|
||||
@@ -56,6 +56,32 @@ public:
|
||||
*/
|
||||
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. */
|
||||
size_t getAnimationCount() const;
|
||||
|
||||
@@ -88,6 +114,6 @@ private:
|
||||
AnimatorImpl* mImpl;
|
||||
};
|
||||
|
||||
} // namespace gltfio
|
||||
} // namespace filament::gltfio
|
||||
|
||||
#endif // GLTFIO_ANIMATOR_H
|
||||
|
||||
@@ -34,7 +34,9 @@ namespace utils {
|
||||
/**
|
||||
* Loader and pipeline for glTF 2.0 assets.
|
||||
*/
|
||||
namespace gltfio {
|
||||
namespace filament::gltfio {
|
||||
|
||||
class NodeManager;
|
||||
|
||||
/**
|
||||
* \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
|
||||
//! set of precompiled ubershader materials. Deleting the MaterialProvider is the client's
|
||||
//! responsibility. See createMaterialGenerator() and createUbershaderLoader().
|
||||
//! responsibility. See createJitShaderProvider() and createUbershaderProvider().
|
||||
MaterialProvider* materials;
|
||||
|
||||
//! 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,
|
||||
* 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
|
||||
* 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 materials = createMaterialGenerator(engine);
|
||||
* auto materials = createJitShaderProvider(engine);
|
||||
* auto decoder = createStbProvider(engine);
|
||||
* auto loader = AssetLoader::create({engine, materials});
|
||||
*
|
||||
* // Parse the glTF content and create Filament entities.
|
||||
@@ -92,7 +96,10 @@ struct AssetConfiguration {
|
||||
* content.clear();
|
||||
*
|
||||
* // 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.
|
||||
* asset->releaseSourceData();
|
||||
@@ -114,6 +121,7 @@ struct AssetConfiguration {
|
||||
* loader->destroyAsset(asset);
|
||||
* materials->destroyMaterials();
|
||||
* delete materials;
|
||||
* delete decoder;
|
||||
* AssetLoader::destroy(&loader);
|
||||
* Engine::destroy(&engine);
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -221,7 +229,9 @@ public:
|
||||
|
||||
utils::NameComponentManager* getNames() const noexcept;
|
||||
|
||||
MaterialProvider* getMaterialProvider() const noexcept;
|
||||
NodeManager& getNodeManager() noexcept;
|
||||
|
||||
MaterialProvider& getMaterialProvider() noexcept;
|
||||
|
||||
/*! \cond PRIVATE */
|
||||
protected:
|
||||
@@ -236,6 +246,6 @@ public:
|
||||
/*! \endcond */
|
||||
};
|
||||
|
||||
} // namespace gltfio
|
||||
} // namespace filament::gltfio
|
||||
|
||||
#endif // GLTFIO_ASSETLOADER_H
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include <filament/Box.h>
|
||||
#include <filament/TextureSampler.h>
|
||||
|
||||
#include <gltfio/NodeManager.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Entity.h>
|
||||
|
||||
@@ -27,9 +29,10 @@ namespace filament {
|
||||
class Camera;
|
||||
class Engine;
|
||||
class MaterialInstance;
|
||||
class Scene;
|
||||
}
|
||||
|
||||
namespace gltfio {
|
||||
namespace filament::gltfio {
|
||||
|
||||
class Animator;
|
||||
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
|
||||
* 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
|
||||
* filament::VertexBuffer, filament::IndexBuffer, filament::MaterialInstance, filament::Texture,
|
||||
@@ -55,12 +58,14 @@ class FilamentInstance;
|
||||
*/
|
||||
class UTILS_PUBLIC FilamentAsset {
|
||||
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.
|
||||
* 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().
|
||||
@@ -70,13 +75,23 @@ public:
|
||||
/**
|
||||
* 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().
|
||||
*/
|
||||
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
|
||||
* component.
|
||||
@@ -95,7 +110,7 @@ public:
|
||||
*
|
||||
* @see filament::Camera::setScaling
|
||||
*/
|
||||
const utils::Entity* getCameraEntities() const noexcept;
|
||||
const Entity* getCameraEntities() const noexcept;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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.
|
||||
@@ -122,12 +137,12 @@ public:
|
||||
* textures gradually become ready through asynchronous loading. For example, on every frame
|
||||
* 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 popRenderables()
|
||||
*/
|
||||
utils::Entity popRenderable() noexcept;
|
||||
Entity popRenderable() noexcept;
|
||||
|
||||
/**
|
||||
* Pops up to "count" ready renderables off the queue, or returns the available number.
|
||||
@@ -138,7 +153,7 @@ public:
|
||||
*
|
||||
* \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. */
|
||||
const filament::MaterialInstance* const* getMaterialInstances() const noexcept;
|
||||
@@ -159,10 +174,10 @@ public:
|
||||
filament::Aabb getBoundingBox() const noexcept;
|
||||
|
||||
/** 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. */
|
||||
utils::Entity getFirstEntityByName(const char* name) noexcept;
|
||||
Entity getFirstEntityByName(const char* name) noexcept;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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;
|
||||
|
||||
/**
|
||||
@@ -187,11 +202,11 @@ public:
|
||||
* @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.
|
||||
*/
|
||||
size_t getEntitiesByPrefix(const char* prefix, utils::Entity* entities,
|
||||
size_t getEntitiesByPrefix(const char* prefix, Entity* entities,
|
||||
size_t maxCount) const noexcept;
|
||||
|
||||
/** 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.
|
||||
@@ -221,17 +236,32 @@ public:
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
size_t getMorphTargetCountAt(utils::Entity entity) const noexcept;
|
||||
size_t getMorphTargetCountAt(Entity entity) const noexcept;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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.
|
||||
@@ -282,6 +312,28 @@ public:
|
||||
*/
|
||||
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 */
|
||||
|
||||
FilamentInstance** getAssetInstances() noexcept;
|
||||
@@ -299,6 +351,6 @@ public:
|
||||
/*! \endcond */
|
||||
};
|
||||
|
||||
} // namespace gltfio
|
||||
} // namespace filament::gltfio
|
||||
|
||||
#endif // GLTFIO_FILAMENTASSET_H
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Entity.h>
|
||||
|
||||
namespace gltfio {
|
||||
namespace filament::gltfio {
|
||||
|
||||
class Animator;
|
||||
class FilamentAsset;
|
||||
@@ -76,6 +76,6 @@ public:
|
||||
Animator* getAnimator() noexcept;
|
||||
};
|
||||
|
||||
} // namespace gltfio
|
||||
} // namespace filament::gltfio
|
||||
|
||||
#endif // GLTFIO_FILAMENTINSTANCE_H
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
namespace gltfio {
|
||||
namespace filament::gltfio {
|
||||
|
||||
enum class AlphaMode : uint8_t {
|
||||
OPAQUE,
|
||||
@@ -118,12 +118,12 @@ inline uint8_t getNumUvSets(const UvMap& uvmap) {
|
||||
* \class MaterialProvider MaterialProvider.h gltfio/MaterialProvider.h
|
||||
* \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
|
||||
* requires the filamat library, but produces streamlined shaders. See createMaterialGenerator().
|
||||
* - The \c JitShaderProvider implementation generates materials at run time (which can be slow) and
|
||||
* 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
|
||||
* createUbershaderLoader().
|
||||
* createUbershaderProvider().
|
||||
*
|
||||
* 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
|
||||
@@ -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.
|
||||
*
|
||||
* @see createUbershaderLoader
|
||||
* @see createUbershaderProvider
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @return New material provider that can quickly load a material from a cache.
|
||||
*
|
||||
* Requires \c libgltfio_resources to be linked in.
|
||||
*
|
||||
* @see createMaterialGenerator
|
||||
* @see createJitShaderProvider
|
||||
*/
|
||||
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
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
namespace gltfio {
|
||||
namespace filament::gltfio {
|
||||
|
||||
struct FFilamentAsset;
|
||||
class AssetPool;
|
||||
class TextureProvider;
|
||||
|
||||
/**
|
||||
* \struct ResourceConfiguration ResourceLoader.h gltfio/ResourceLoader.h
|
||||
@@ -53,8 +54,8 @@ struct ResourceConfiguration {
|
||||
//! do not need this, but it is useful for robustness.
|
||||
bool recomputeBoundingBoxes;
|
||||
|
||||
//! If true, ignore skinned primitives bind transform when compute bounding box. Implicitly true
|
||||
//! for instanced asset. Only applicable when recomputeBoundingBoxes is set to true
|
||||
//! If true, ignores skinning when computing bounding boxes. Implicitly true for instanced
|
||||
//! assets. Only applicable when recomputeBoundingBoxes is set to true.
|
||||
bool ignoreBindTransform;
|
||||
};
|
||||
|
||||
@@ -94,6 +95,13 @@ public:
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
@@ -153,7 +161,6 @@ public:
|
||||
|
||||
private:
|
||||
bool loadResources(FFilamentAsset* asset, bool async);
|
||||
void applySparseData(FFilamentAsset* asset) const;
|
||||
void normalizeSkinningWeights(FFilamentAsset* asset) const;
|
||||
void updateBoundingBoxes(FFilamentAsset* asset) const;
|
||||
AssetPool* mPool;
|
||||
@@ -161,7 +168,7 @@ private:
|
||||
Impl* pImpl;
|
||||
};
|
||||
|
||||
} // namespace gltfio
|
||||
} // namespace filament::gltfio
|
||||
|
||||
#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/TVecHelpers.h>
|
||||
|
||||
namespace gltfio {
|
||||
namespace filament::gltfio {
|
||||
|
||||
template <typename 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);
|
||||
};
|
||||
|
||||
} // namespace gltfio
|
||||
} // namespace filament::gltfio
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
// 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.
|
||||
// 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 3 are converted to sRGB.
|
||||
template<typename T, int N = 3>
|
||||
std::unique_ptr<uint8_t[]> fromLinearTosRGB(const LinearImage& image) {
|
||||
const size_t w = image.getWidth();
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef IMAGE_KTXBUNDLE_H
|
||||
#define IMAGE_KTXBUNDLE_H
|
||||
#ifndef IMAGE_KTX1BUNDLE_H
|
||||
#define IMAGE_KTX1BUNDLE_H
|
||||
|
||||
#include <math/vec3.h>
|
||||
|
||||
@@ -48,7 +48,7 @@ struct KtxBlobList;
|
||||
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
|
||||
* block-compressed texture data.
|
||||
*
|
||||
@@ -63,22 +63,22 @@ struct KtxMetadata;
|
||||
*
|
||||
* https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
|
||||
*/
|
||||
class UTILS_PUBLIC KtxBundle {
|
||||
class UTILS_PUBLIC Ktx1Bundle {
|
||||
public:
|
||||
|
||||
~KtxBundle();
|
||||
~Ktx1Bundle();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
@@ -276,4 +276,4 @@ private:
|
||||
|
||||
} // 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 {
|
||||
free(p);
|
||||
this->free(p);
|
||||
}
|
||||
|
||||
~HeapAllocator() noexcept = default;
|
||||
@@ -457,6 +457,12 @@ private:
|
||||
void* mEnd = nullptr;
|
||||
};
|
||||
|
||||
class NullArea {
|
||||
public:
|
||||
void* data() const noexcept { return nullptr; }
|
||||
size_t size() const noexcept { return 0; }
|
||||
};
|
||||
|
||||
} // namespace AreaPolicy
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
@@ -498,6 +504,7 @@ struct HighWatermark {
|
||||
void onFree(void* p, size_t size) noexcept;
|
||||
void onReset() noexcept;
|
||||
void onRewind(void const* addr) noexcept;
|
||||
uint32_t getHighWatermark() const noexcept { return mHighWaterMark; }
|
||||
protected:
|
||||
const char* mName = 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_iterator = const value_type*;
|
||||
|
||||
constexpr StaticString() noexcept = default;
|
||||
constexpr StaticString() noexcept {} // NOLINT(modernize-use-equals-default), Ubuntu compiler bug
|
||||
|
||||
// initialization from a string literal
|
||||
template<size_t N>
|
||||
@@ -149,6 +149,14 @@ public:
|
||||
|
||||
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:
|
||||
const_pointer mString = nullptr;
|
||||
size_type mLength = 0;
|
||||
@@ -200,7 +208,7 @@ public:
|
||||
using iterator = 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
|
||||
// inside the string (i.e. it can contain nulls or non-ASCII encodings).
|
||||
@@ -220,7 +228,7 @@ public:
|
||||
: 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);
|
||||
|
||||
@@ -309,11 +317,19 @@ public:
|
||||
}
|
||||
|
||||
// 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);
|
||||
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:
|
||||
struct Data {
|
||||
size_type length;
|
||||
@@ -365,34 +381,4 @@ CString to_string(T value) noexcept;
|
||||
|
||||
} // 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
|
||||
|
||||
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>
|
||||
|
||||
// FIXME: could we get rid of <functional>
|
||||
#include <functional> // for std::hash
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -30,7 +27,7 @@ namespace utils {
|
||||
class UTILS_PUBLIC Entity {
|
||||
public:
|
||||
// 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
|
||||
Entity(const Entity& e) noexcept = default;
|
||||
@@ -68,10 +65,17 @@ public:
|
||||
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:
|
||||
friend class EntityManager;
|
||||
friend class EntityManagerImpl;
|
||||
friend struct std::hash<Entity>;
|
||||
using Type = uint32_t;
|
||||
|
||||
explicit Entity(Type identity) noexcept : mIdentity(identity) { }
|
||||
@@ -81,18 +85,4 @@ private:
|
||||
|
||||
} // 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
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace utils {
|
||||
|
||||
class UTILS_PUBLIC EntityManager {
|
||||
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.
|
||||
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.
|
||||
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(Invocable&& rhs) noexcept;
|
||||
@@ -121,12 +121,9 @@ Invocable<R(Args...)>::Invocable(Invocable&& rhs) noexcept
|
||||
template<typename R, typename... Args>
|
||||
Invocable<R(Args...)>& Invocable<R(Args...)>::operator=(Invocable&& rhs) noexcept {
|
||||
if (this != &rhs) {
|
||||
mInvocable = rhs.mInvocable;
|
||||
mDeleter = rhs.mDeleter;
|
||||
mInvoker = rhs.mInvoker;
|
||||
rhs.mInvocable = nullptr;
|
||||
rhs.mDeleter = nullptr;
|
||||
rhs.mInvoker = nullptr;
|
||||
std::swap(mInvocable, rhs.mInvocable);
|
||||
std::swap(mDeleter, rhs.mDeleter);
|
||||
std::swap(mInvoker, rhs.mInvoker);
|
||||
}
|
||||
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
|
||||
#define TNT_UTILS_NAMECOMPONENTMANAGER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/CString.h>
|
||||
#include <utils/Entity.h>
|
||||
#include <utils/EntityInstance.h>
|
||||
#include <utils/SingleInstanceComponentManager.h>
|
||||
|
||||
#include <functional>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
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
|
||||
* \brief Allows clients to associate string labels with entities.
|
||||
@@ -69,7 +48,7 @@ private:
|
||||
* 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:
|
||||
using Instance = EntityInstance<NameComponentManager>;
|
||||
|
||||
@@ -93,7 +72,7 @@ public:
|
||||
* @return Non-zero handle if the entity has a name component, 0 otherwise.
|
||||
*/
|
||||
Instance getInstance(Entity e) const noexcept {
|
||||
return Instance(SingleInstanceComponentManager::getInstance(e));
|
||||
return { SingleInstanceComponentManager::getInstance(e) };
|
||||
}
|
||||
|
||||
/*! \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:
|
||||
// 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;
|
||||
};
|
||||
|
||||
|
||||
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 <cstddef>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
#include <stddef.h>
|
||||
@@ -509,7 +508,7 @@ private:
|
||||
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 {
|
||||
auto offsets = getOffsets(capacity);
|
||||
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 <functional> // for std::less
|
||||
#include <type_traits> // for std::enable_if
|
||||
|
||||
#include <limits.h>
|
||||
@@ -168,74 +167,6 @@ T log2i(T x) noexcept {
|
||||
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>
|
||||
inline UTILS_PUBLIC
|
||||
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 {
|
||||
|
||||
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 % sizeof(void*)) == 0);
|
||||
|
||||
void* p = nullptr;
|
||||
|
||||
// must be a power of two and >= sizeof(void*)
|
||||
while (align < sizeof(void*)) {
|
||||
align <<= 1u;
|
||||
}
|
||||
|
||||
#if defined(WIN32)
|
||||
p = ::_aligned_malloc(size, align);
|
||||
#else
|
||||
|
||||
@@ -17,13 +17,14 @@
|
||||
#ifndef TNT_UTILS_OSTREAM_H
|
||||
#define TNT_UTILS_OSTREAM_H
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <utils/bitset.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/PrivateImplementation.h>
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
namespace utils::io {
|
||||
|
||||
struct ostream_;
|
||||
@@ -60,6 +61,9 @@ public:
|
||||
ostream& operator<<(const 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& dec() noexcept;
|
||||
@@ -110,9 +114,6 @@ private:
|
||||
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
|
||||
inline ostream& operator << (ostream& o, utils::bitset32 const& s) noexcept {
|
||||
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& 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(); }
|
||||
|
||||
} // 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
|
||||
* 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
|
||||
* specified minimum number of frames between tests.
|
||||
|
||||
@@ -72,6 +72,7 @@ using MultiSampleAntiAliasingOptions = filament::View::MultiSampleAntiAliasingOp
|
||||
using TemporalAntiAliasingOptions = filament::View::TemporalAntiAliasingOptions;
|
||||
using VignetteOptions = filament::View::VignetteOptions;
|
||||
using VsmShadowOptions = filament::View::VsmShadowOptions;
|
||||
using GuardBandOptions = filament::View::GuardBandOptions;
|
||||
using LightManager = filament::LightManager;
|
||||
|
||||
// These functions push all editable property values to their respective Filament objects.
|
||||
@@ -171,6 +172,7 @@ struct ViewSettings {
|
||||
TemporalAntiAliasingOptions taa;
|
||||
VignetteOptions vignette;
|
||||
VsmShadowOptions vsmShadowOptions;
|
||||
GuardBandOptions guardBand;
|
||||
|
||||
// Custom View Options
|
||||
ColorGradingSettings colorGrading;
|
||||
@@ -194,7 +196,7 @@ struct LightSettings {
|
||||
LightManager::ShadowOptions shadowOptions;
|
||||
SoftShadowOptions softShadowOptions;
|
||||
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});
|
||||
float iblIntensity = 30000.0f;
|
||||
float iblRotation = 0.0f;
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef VIEWER_SIMPLEVIEWER_H
|
||||
#define VIEWER_SIMPLEVIEWER_H
|
||||
#ifndef VIEWER_VIEWERGUI_H
|
||||
#define VIEWER_VIEWERGUI_H
|
||||
|
||||
#include <filament/Box.h>
|
||||
#include <filament/DebugRegistry.h>
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include <gltfio/Animator.h>
|
||||
#include <gltfio/FilamentAsset.h>
|
||||
#include <gltfio/NodeManager.h>
|
||||
|
||||
#include <viewer/Settings.h>
|
||||
|
||||
@@ -35,6 +36,7 @@
|
||||
#include <math/mat4.h>
|
||||
#include <math/vec3.h>
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace filagui {
|
||||
@@ -45,15 +47,15 @@ namespace filament {
|
||||
namespace viewer {
|
||||
|
||||
/**
|
||||
* \class SimpleViewer SimpleViewer.h viewer/SimpleViewer.h
|
||||
* \brief Manages the state for a simple glTF viewer with imgui controls and a tree view.
|
||||
* \class ViewerGui ViewerGui.h viewer/ViewerGui.h
|
||||
* \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.
|
||||
*
|
||||
* \note If you don't need ImGui controls, there is no need to use this class, just use AssetLoader
|
||||
* instead.
|
||||
*/
|
||||
class UTILS_PUBLIC SimpleViewer {
|
||||
class UTILS_PUBLIC ViewerGui {
|
||||
public:
|
||||
using Animator = gltfio::Animator;
|
||||
using FilamentAsset = gltfio::FilamentAsset;
|
||||
@@ -62,29 +64,39 @@ public:
|
||||
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
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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 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.
|
||||
@@ -126,7 +138,7 @@ public:
|
||||
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.
|
||||
* @{
|
||||
*/
|
||||
@@ -218,8 +230,14 @@ public:
|
||||
int getCurrentCamera() const { return mCurrentCamera; }
|
||||
|
||||
private:
|
||||
using SceneMask = gltfio::NodeManager::SceneMask;
|
||||
|
||||
void updateIndirectLight();
|
||||
|
||||
bool isRemoteMode() const { return mAsset == nullptr; }
|
||||
|
||||
void sceneSelectionUI();
|
||||
|
||||
// Immutable properties set from the constructor.
|
||||
filament::Engine* const mEngine;
|
||||
filament::Scene* const mScene;
|
||||
@@ -238,7 +256,6 @@ private:
|
||||
// Properties that can be changed from the UI.
|
||||
int mCurrentAnimation = 1; // It is a 1-based index and 0 means not playing animation
|
||||
int mCurrentVariant = 0;
|
||||
bool mResetAnimation = true;
|
||||
bool mEnableWireframe = false;
|
||||
int mVsmMsaaSamplesLog2 = 1;
|
||||
Settings mSettings;
|
||||
@@ -246,10 +263,19 @@ private:
|
||||
uint32_t mFlags;
|
||||
utils::Entity mCurrentMorphingEntity;
|
||||
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).
|
||||
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.
|
||||
float mToneMapPlot[1024];
|
||||
float mRangePlot[1024 * 3];
|
||||
@@ -262,4 +288,4 @@ filament::math::mat4f fitIntoUnitCube(const filament::Aabb& bounds, float zoffse
|
||||
} // namespace viewer
|
||||
} // namespace filament
|
||||
|
||||
#endif // VIEWER_SIMPLEVIEWER_H
|
||||
#endif // VIEWER_VIEWERGUI_H
|
||||
Reference in New Issue
Block a user