Add a way to specify an additional uniform name along with a sampler param for the associated transform matrix (#8490)
BUGS=[399959254]
This commit is contained in:
@@ -7,3 +7,4 @@ for next branch cut* header.
|
||||
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
||||
|
||||
## Release notes for next branch cut
|
||||
- materials: add an optional `transformName` field to sampler material parameters. [⚠️ **New Material Version**]
|
||||
|
||||
@@ -991,10 +991,13 @@ Type
|
||||
|
||||
Value
|
||||
: Each entry is an object with the properties `name` and `type`, both of `string` type. The
|
||||
name must be a valid GLSL identifier. Entries also have an optional `precision`, which can be
|
||||
name must be a valid GLSL identifier. Entries have an optional `precision`, which can be
|
||||
one of `default` (best precision for the platform, typically `high` on desktop, `medium` on
|
||||
mobile), `low`, `medium`, `high`. The type must be one of the types described in
|
||||
table [materialParamsTypes].
|
||||
table [materialParamsTypes]. For Android external textures, entries also have an optional
|
||||
transformName parameter to specify the name of the material parameter that will be
|
||||
used to expose the transform matrix associated with the external sampler. In iOS and Vulkan,
|
||||
this will always be identity.
|
||||
|
||||
Type | Description
|
||||
:----------------------|:---------------------------------
|
||||
|
||||
@@ -421,6 +421,7 @@ bool ChunkUniformInterfaceBlock::unflatten(Unflattener& unflattener,
|
||||
uint64_t fieldSize = 0;
|
||||
uint8_t fieldType = 0;
|
||||
uint8_t fieldPrecision = 0;
|
||||
uint8_t fieldAssociatedSampler = 0;
|
||||
|
||||
if (!unflattener.read(&fieldName)) {
|
||||
return false;
|
||||
@@ -438,8 +439,13 @@ bool ChunkUniformInterfaceBlock::unflatten(Unflattener& unflattener,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!unflattener.read(&fieldAssociatedSampler)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// a size of 1 means not an array
|
||||
builder.add({{{ fieldName.data(), fieldName.size() },
|
||||
fieldAssociatedSampler,
|
||||
uint32_t(fieldSize == 1 ? 0 : fieldSize),
|
||||
BufferInterfaceBlock::Type(fieldType),
|
||||
BufferInterfaceBlock::Precision(fieldPrecision) }});
|
||||
|
||||
@@ -40,11 +40,28 @@ public:
|
||||
std::string_view name;
|
||||
uint32_t size;
|
||||
backend::UniformType type;
|
||||
backend::Precision precision{};
|
||||
backend::FeatureLevel minFeatureLevel = backend::FeatureLevel::FEATURE_LEVEL_1;
|
||||
std::string_view structName{};
|
||||
uint32_t stride{};
|
||||
std::string_view sizeName{};
|
||||
backend::Precision precision;
|
||||
uint8_t associatedSampler = 0;
|
||||
backend::FeatureLevel minFeatureLevel;
|
||||
std::string_view structName;
|
||||
uint32_t stride;
|
||||
std::string_view sizeName;
|
||||
|
||||
InterfaceBlockEntry() = default;
|
||||
InterfaceBlockEntry(std::string_view name, uint32_t size, backend::UniformType type,
|
||||
backend::Precision precision = {},
|
||||
backend::FeatureLevel minFeatureLevel = backend::FeatureLevel::FEATURE_LEVEL_1, std::string_view structName = {},
|
||||
uint32_t stride = {}, std::string_view sizeName = {}) noexcept
|
||||
: name(name), size(size), type(type), precision(precision),
|
||||
associatedSampler(0), minFeatureLevel(minFeatureLevel),
|
||||
structName(structName), stride(stride), sizeName(sizeName) {}
|
||||
InterfaceBlockEntry(std::string_view name, uint8_t associatedSampler, uint32_t size, backend::UniformType type,
|
||||
backend::Precision precision = {},
|
||||
backend::FeatureLevel minFeatureLevel = backend::FeatureLevel::FEATURE_LEVEL_1, std::string_view structName = {},
|
||||
uint32_t stride = {}, std::string_view sizeName = {}) noexcept
|
||||
: name(name), size(size), type(type), precision(precision),
|
||||
associatedSampler(associatedSampler), minFeatureLevel(minFeatureLevel),
|
||||
structName(structName), stride(stride), sizeName(sizeName) {}
|
||||
};
|
||||
|
||||
BufferInterfaceBlock();
|
||||
@@ -68,6 +85,7 @@ public:
|
||||
bool isArray; // true if the field is an array
|
||||
uint32_t size; // size of the array in elements, or 0 if not an array
|
||||
Precision precision; // precision of this field
|
||||
uint8_t associatedSampler; // sampler associated with this field
|
||||
backend::FeatureLevel minFeatureLevel; // below this feature level, this field is not needed
|
||||
utils::CString structName; // name of this field structure if type is STRUCT
|
||||
utils::CString sizeName; // name of the size parameter in the shader
|
||||
@@ -152,6 +170,10 @@ public:
|
||||
// negative value if name doesn't exist or Panic if exceptions are enabled
|
||||
ssize_t getFieldOffset(std::string_view name, size_t index) const;
|
||||
|
||||
// returns offset in bytes of the transform matrix for the given external texture binding
|
||||
// returns -1 if the field doesn't exist
|
||||
ssize_t getTransformFieldOffset(uint8_t binding) const;
|
||||
|
||||
FieldInfo const* getFieldInfo(std::string_view name) const;
|
||||
|
||||
bool hasField(std::string_view name) const noexcept {
|
||||
@@ -179,6 +201,7 @@ private:
|
||||
utils::CString mName;
|
||||
utils::FixedCapacityVector<FieldInfo> mFieldInfoList;
|
||||
std::unordered_map<std::string_view , uint32_t> mInfoMap;
|
||||
std::unordered_map<uint8_t, uint32_t> mTransformOffsetMap;
|
||||
uint32_t mSize = 0; // size in bytes rounded to multiple of 4
|
||||
Alignment mAlignment = Alignment::std140;
|
||||
Target mTarget = Target::UNIFORM;
|
||||
|
||||
@@ -58,7 +58,7 @@ BufferInterfaceBlock::Builder& BufferInterfaceBlock::Builder::add(
|
||||
for (auto const& item : list) {
|
||||
mEntries.push_back({
|
||||
{ item.name.data(), item.name.size() },
|
||||
0, uint8_t(item.stride), item.type, item.size > 0, item.size, item.precision, item.minFeatureLevel,
|
||||
0, uint8_t(item.stride), item.type, item.size > 0, item.size, item.precision, item.associatedSampler, item.minFeatureLevel,
|
||||
{ item.structName.data(), item.structName.size() },
|
||||
{ item.sizeName.data(), item.sizeName.size() }
|
||||
});
|
||||
@@ -71,7 +71,7 @@ BufferInterfaceBlock::Builder& BufferInterfaceBlock::Builder::addVariableSizedAr
|
||||
mHasVariableSizeArray = true;
|
||||
mEntries.push_back({
|
||||
{ item.name.data(), item.name.size() },
|
||||
0, uint8_t(item.stride), item.type, true, 0, item.precision, item.minFeatureLevel,
|
||||
0, uint8_t(item.stride), item.type, true, 0, item.precision, item.associatedSampler, item.minFeatureLevel,
|
||||
{ item.structName.data(), item.structName.size() },
|
||||
{ item.sizeName.data(), item.sizeName.size() }
|
||||
});
|
||||
@@ -122,6 +122,8 @@ BufferInterfaceBlock::BufferInterfaceBlock(Builder const& builder) noexcept
|
||||
|
||||
auto& uniformsInfoList = mFieldInfoList;
|
||||
|
||||
auto& transformOffsetMap = mTransformOffsetMap;
|
||||
|
||||
uint32_t i = 0;
|
||||
uint16_t offset = 0;
|
||||
for (auto const& e : builder.mEntries) {
|
||||
@@ -143,11 +145,16 @@ BufferInterfaceBlock::BufferInterfaceBlock(Builder const& builder) noexcept
|
||||
|
||||
FieldInfo& info = uniformsInfoList[i];
|
||||
info = { e.name, offset, uint8_t(stride), e.type, e.isArray, e.size,
|
||||
e.precision, e.minFeatureLevel, e.structName, e.sizeName };
|
||||
e.precision, e.associatedSampler, e.minFeatureLevel, e.structName, e.sizeName };
|
||||
|
||||
// record this uniform info
|
||||
infoMap[{ info.name.data(), info.name.size() }] = i;
|
||||
|
||||
// record the transform offset if this is an external sampler
|
||||
if (e.associatedSampler != 0) {
|
||||
transformOffsetMap[e.associatedSampler] = offset;
|
||||
}
|
||||
|
||||
// advance offset to next slot
|
||||
offset += stride * std::max(1u, e.size);
|
||||
++i;
|
||||
@@ -163,6 +170,14 @@ ssize_t BufferInterfaceBlock::getFieldOffset(std::string_view name, size_t index
|
||||
return (ssize_t)info->getBufferOffset(index);
|
||||
}
|
||||
|
||||
ssize_t BufferInterfaceBlock::getTransformFieldOffset(uint8_t binding) const {
|
||||
auto pos = mTransformOffsetMap.find(binding);
|
||||
if (pos == mTransformOffsetMap.end()) {
|
||||
return -1;
|
||||
}
|
||||
return (ssize_t)pos->second;
|
||||
}
|
||||
|
||||
BufferInterfaceBlock::FieldInfo const* BufferInterfaceBlock::getFieldInfo(
|
||||
std::string_view name) const {
|
||||
auto pos = mInfoMap.find(name);
|
||||
|
||||
@@ -318,7 +318,8 @@ public:
|
||||
MaterialBuilder& parameter(const char* name, SamplerType samplerType,
|
||||
SamplerFormat format = SamplerFormat::FLOAT,
|
||||
ParameterPrecision precision = ParameterPrecision::DEFAULT,
|
||||
bool multisample = false) noexcept;
|
||||
bool multisample = false,
|
||||
const char* transformName = "") noexcept;
|
||||
|
||||
MaterialBuilder& buffer(filament::BufferInterfaceBlock bib) noexcept;
|
||||
|
||||
@@ -650,8 +651,8 @@ public:
|
||||
Parameter() noexcept: parameterType(INVALID) {}
|
||||
|
||||
// Sampler
|
||||
Parameter(const char* paramName, SamplerType t, SamplerFormat f, ParameterPrecision p, bool ms)
|
||||
: name(paramName), size(1), precision(p), samplerType(t), format(f), parameterType(SAMPLER), multisample(ms) { }
|
||||
Parameter(const char* paramName, SamplerType t, SamplerFormat f, ParameterPrecision p, bool ms, const char* tn)
|
||||
: name(paramName), size(1), precision(p), samplerType(t), format(f), parameterType(SAMPLER), multisample(ms), transformName(tn) { }
|
||||
|
||||
// Uniform
|
||||
Parameter(const char* paramName, UniformType t, size_t typeSize, ParameterPrecision p)
|
||||
@@ -669,6 +670,7 @@ public:
|
||||
SubpassType subpassType;
|
||||
SamplerFormat format;
|
||||
bool multisample;
|
||||
utils::CString transformName;
|
||||
enum {
|
||||
INVALID,
|
||||
UNIFORM,
|
||||
|
||||
@@ -279,7 +279,7 @@ MaterialBuilder& MaterialBuilder::parameter(const char* name, UniformType type,
|
||||
|
||||
|
||||
MaterialBuilder& MaterialBuilder::parameter(const char* name, SamplerType samplerType,
|
||||
SamplerFormat format, ParameterPrecision precision, bool multisample) noexcept {
|
||||
SamplerFormat format, ParameterPrecision precision, bool multisample, const char* transformName) noexcept {
|
||||
FILAMENT_CHECK_PRECONDITION(!multisample ||
|
||||
(format != SamplerFormat::SHADOW &&
|
||||
(samplerType == SamplerType::SAMPLER_2D ||
|
||||
@@ -288,7 +288,7 @@ MaterialBuilder& MaterialBuilder::parameter(const char* name, SamplerType sample
|
||||
" as long as type is not SHADOW";
|
||||
|
||||
FILAMENT_CHECK_POSTCONDITION(mParameterCount < MAX_PARAMETERS_COUNT) << "Too many parameters";
|
||||
mParameters[mParameterCount++] = { name, samplerType, format, precision, multisample };
|
||||
mParameters[mParameterCount++] = { name, samplerType, format, precision, multisample, transformName };
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -609,12 +609,18 @@ void MaterialBuilder::prepareToBuild(MaterialInfo& info) noexcept {
|
||||
SamplerInterfaceBlock::Builder sbb;
|
||||
BufferInterfaceBlock::Builder ibb;
|
||||
// sampler bindings start at 1, 0 is the ubo
|
||||
for (size_t i = 0, binding = 1, c = mParameterCount; i < c; i++) {
|
||||
uint16_t binding = 1;
|
||||
for (size_t i = 0, c = mParameterCount; i < c; i++) {
|
||||
auto const& param = mParameters[i];
|
||||
assert_invariant(!param.isSubpass());
|
||||
if (param.isSampler()) {
|
||||
sbb.add({ param.name.data(), param.name.size() },
|
||||
binding++, param.samplerType, param.format, param.precision, param.multisample);
|
||||
binding, param.samplerType, param.format, param.precision, param.multisample);
|
||||
if (!param.transformName.empty()) {
|
||||
ibb.add({{{ param.transformName.data(), param.transformName.size() }, uint8_t(binding),
|
||||
0, UniformType::MAT3, Precision::DEFAULT, FeatureLevel::FEATURE_LEVEL_0 }});
|
||||
}
|
||||
binding++;
|
||||
} else if (param.isUniform()) {
|
||||
ibb.add({{{ param.name.data(), param.name.size() },
|
||||
uint32_t(param.size == 1u ? 0u : param.size), param.uniformType,
|
||||
|
||||
@@ -52,6 +52,7 @@ void MaterialUniformInterfaceBlockChunk::flatten(Flattener& f) {
|
||||
f.writeUint64(uInfo.size);
|
||||
f.writeUint8(static_cast<uint8_t>(uInfo.type));
|
||||
f.writeUint8(static_cast<uint8_t>(uInfo.precision));
|
||||
f.writeUint8(static_cast<uint8_t>(uInfo.associatedSampler));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -153,6 +153,12 @@ static bool processParameter(MaterialBuilder& builder, const JsonishObject& json
|
||||
std::cerr << "parameters: name value must be STRING." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
const JsonishValue* transformNameValue = jsonObject.getValue("transformName");
|
||||
if (transformNameValue && transformNameValue->getType() != JsonishValue::STRING) {
|
||||
std::cerr << "parameters: transformName value must be STRING." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
const JsonishValue* precisionValue = jsonObject.getValue("precision");
|
||||
if (precisionValue) {
|
||||
@@ -221,7 +227,19 @@ static bool processParameter(MaterialBuilder& builder, const JsonishObject& json
|
||||
|
||||
auto multisample = multiSampleValue ? multiSampleValue->toJsonBool()->getBool() : false;
|
||||
|
||||
builder.parameter(nameString.c_str(), type, format, precision, multisample);
|
||||
if (transformNameValue) {
|
||||
if (type != MaterialBuilder::SamplerType::SAMPLER_EXTERNAL) {
|
||||
std::cerr << "parameters: the parameter with name '" << nameString << "'"
|
||||
<< " is a sampler of type " << typeString << " and has a transformName."
|
||||
<< " Transform names are only supported for external samplers."
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
auto transformName = transformNameValue->toJsonString()->getString();
|
||||
builder.parameter(nameString.c_str(), type, format, precision, multisample, transformName.c_str());
|
||||
} else {
|
||||
builder.parameter(nameString.c_str(), type, format, precision, multisample);
|
||||
}
|
||||
|
||||
} else {
|
||||
std::cerr << "parameters: the type '" << typeString
|
||||
|
||||
Reference in New Issue
Block a user