Files
filament/filament/src/MaterialParser.cpp
Philip Rideout d73453863d Fix swallowed errors in MaterialParser.
If `ChunkContainer::parse` failed, then `MaterialParser::parse` was
returning SUCCESS.
2022-07-07 22:34:32 -07:00

453 lines
15 KiB
C++

/*
* Copyright (C) 2017 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.
*/
#include "MaterialParser.h"
#include <filaflat/ChunkContainer.h>
#include <filaflat/MaterialChunk.h>
#include <filaflat/DictionaryReader.h>
#include <filaflat/Unflattener.h>
#include <filament/MaterialChunkType.h>
#include <private/filament/SamplerInterfaceBlock.h>
#include <private/filament/UniformInterfaceBlock.h>
#include <private/filament/SubpassInfo.h>
#include <private/filament/Variant.h>
#include <utils/CString.h>
#include <stdlib.h>
using namespace utils;
using namespace filament::backend;
using namespace filaflat;
using namespace filamat;
namespace filament {
// ------------------------------------------------------------------------------------------------
MaterialParser::MaterialParserDetails::MaterialParserDetails(Backend backend, const void* data, size_t size)
: mManagedBuffer(data, size),
mChunkContainer(mManagedBuffer.data(), mManagedBuffer.size()),
mMaterialChunk(mChunkContainer) {
switch (backend) {
case Backend::OPENGL:
mMaterialTag = ChunkType::MaterialGlsl;
mDictionaryTag = ChunkType::DictionaryText;
break;
case Backend::METAL:
mMaterialTag = ChunkType::MaterialMetal;
mDictionaryTag = ChunkType::DictionaryText;
break;
case Backend::VULKAN:
mMaterialTag = ChunkType::MaterialSpirv;
mDictionaryTag = ChunkType::DictionarySpirv;
break;
default:
// this is for testing purpose -- for e.g.: with the NoopDriver
mMaterialTag = ChunkType::MaterialGlsl;
mDictionaryTag = ChunkType::DictionaryText;
break;
}
}
template<typename T>
UTILS_NOINLINE
bool MaterialParser::MaterialParserDetails::getFromSimpleChunk(
filamat::ChunkType type, T* value) const noexcept {
ChunkContainer const& chunkContainer = mChunkContainer;
ChunkContainer::ChunkDesc const* pChunkDesc;
if (chunkContainer.hasChunk(type, &pChunkDesc)) {
Unflattener unflattener(pChunkDesc->start, pChunkDesc->start + pChunkDesc->size);
return unflattener.read(value);
}
return false;
}
// ------------------------------------------------------------------------------------------------
MaterialParser::MaterialParser(Backend backend, const void* data, size_t size)
: mImpl(backend, data, size) {
}
ChunkContainer& MaterialParser::getChunkContainer() noexcept {
return mImpl.mChunkContainer;
}
ChunkContainer const& MaterialParser::getChunkContainer() const noexcept {
return mImpl.mChunkContainer;
}
MaterialParser::ParseResult MaterialParser::parse() noexcept {
ChunkContainer& cc = getChunkContainer();
if (UTILS_UNLIKELY(!cc.parse())) {
return ParseResult::ERROR_OTHER;
}
const ChunkType matTag = mImpl.mMaterialTag;
const ChunkType dictTag = mImpl.mDictionaryTag;
if (UTILS_UNLIKELY(!cc.hasChunk(matTag) || !cc.hasChunk(dictTag))) {
return ParseResult::ERROR_MISSING_BACKEND;
}
if (UTILS_UNLIKELY(!DictionaryReader::unflatten(cc, dictTag, mImpl.mBlobDictionary))) {
return ParseResult::ERROR_OTHER;
}
if (UTILS_UNLIKELY(!mImpl.mMaterialChunk.initialize(matTag))) {
return ParseResult::ERROR_OTHER;
}
return ParseResult::SUCCESS;
}
// Accessors
bool MaterialParser::getMaterialVersion(uint32_t* value) const noexcept {
return mImpl.getFromSimpleChunk(ChunkType::MaterialVersion, value);
}
bool MaterialParser::getName(utils::CString* cstring) const noexcept {
ChunkType type = ChunkType::MaterialName;
const uint8_t* start = mImpl.mChunkContainer.getChunkStart(type);
const uint8_t* end = mImpl.mChunkContainer.getChunkEnd(type);
Unflattener unflattener(start, end);
return unflattener.read(cstring);
}
bool MaterialParser::getUIB(UniformInterfaceBlock* uib) const noexcept {
auto type = MaterialUib;
const uint8_t* start = mImpl.mChunkContainer.getChunkStart(type);
const uint8_t* end = mImpl.mChunkContainer.getChunkEnd(type);
Unflattener unflattener(start, end);
return ChunkUniformInterfaceBlock::unflatten(unflattener, uib);
}
bool MaterialParser::getSIB(SamplerInterfaceBlock* sib) const noexcept {
auto type = MaterialSib;
const uint8_t* start = mImpl.mChunkContainer.getChunkStart(type);
const uint8_t* end = mImpl.mChunkContainer.getChunkEnd(type);
Unflattener unflattener(start, end);
return ChunkSamplerInterfaceBlock::unflatten(unflattener, sib);
}
bool MaterialParser::getSubpasses(SubpassInfo* subpass) const noexcept {
auto type = MaterialSubpass;
const uint8_t* start = mImpl.mChunkContainer.getChunkStart(type);
const uint8_t* end = mImpl.mChunkContainer.getChunkEnd(type);
Unflattener unflattener(start, end);
return ChunkSubpassInterfaceBlock::unflatten(unflattener, subpass);
}
bool MaterialParser::getShaderModels(uint32_t* value) const noexcept {
return mImpl.getFromSimpleChunk(ChunkType::MaterialShaderModels, value);
}
bool MaterialParser::getMaterialProperties(uint64_t* value) const noexcept {
return mImpl.getFromSimpleChunk(ChunkType::MaterialProperties, value);
}
bool MaterialParser::getDepthWriteSet(bool* value) const noexcept {
return mImpl.getFromSimpleChunk(ChunkType::MaterialDepthWriteSet, value);
}
bool MaterialParser::getDepthWrite(bool* value) const noexcept {
return mImpl.getFromSimpleChunk(ChunkType::MaterialDepthWrite, value);
}
bool MaterialParser::getDoubleSidedSet(bool* value) const noexcept {
return mImpl.getFromSimpleChunk(ChunkType::MaterialDoubleSidedSet, value);
}
bool MaterialParser::getDoubleSided(bool* value) const noexcept {
return mImpl.getFromSimpleChunk(ChunkType::MaterialDoubleSided, value);
}
bool MaterialParser::getColorWrite(bool* value) const noexcept {
return mImpl.getFromSimpleChunk(ChunkType::MaterialColorWrite, value);
}
bool MaterialParser::getDepthTest(bool* value) const noexcept {
return mImpl.getFromSimpleChunk(ChunkType::MaterialDepthTest, value);
}
bool MaterialParser::getInstanced(bool* value) const noexcept {
return mImpl.getFromSimpleChunk(ChunkType::MaterialInstanced, value);
}
bool MaterialParser::getCullingMode(CullingMode* value) const noexcept {
static_assert(sizeof(CullingMode) == sizeof(uint8_t),
"CullingMode expected size is wrong");
return mImpl.getFromSimpleChunk(ChunkType::MaterialCullingMode, reinterpret_cast<uint8_t*>(value));
}
bool MaterialParser::getTransparencyMode(TransparencyMode* value) const noexcept {
static_assert(sizeof(TransparencyMode) == sizeof(uint8_t),
"TransparencyMode expected size is wrong");
return mImpl.getFromSimpleChunk(ChunkType::MaterialTransparencyMode,
reinterpret_cast<uint8_t*>(value));
}
bool MaterialParser::getInterpolation(Interpolation* value) const noexcept {
static_assert(sizeof(Interpolation) == sizeof(uint8_t),
"Interpolation expected size is wrong");
return mImpl.getFromSimpleChunk(ChunkType::MaterialInterpolation, reinterpret_cast<uint8_t*>(value));
}
bool MaterialParser::getVertexDomain(VertexDomain* value) const noexcept {
static_assert(sizeof(VertexDomain) == sizeof(uint8_t),
"VertexDomain expected size is wrong");
return mImpl.getFromSimpleChunk(ChunkType::MaterialVertexDomain, reinterpret_cast<uint8_t*>(value));
}
bool MaterialParser::getMaterialDomain(MaterialDomain* value) const noexcept {
static_assert(sizeof(MaterialDomain) == sizeof(uint8_t),
"MaterialDomain expected size is wrong");
return mImpl.getFromSimpleChunk(ChunkType::MaterialDomain, reinterpret_cast<uint8_t*>(value));
}
bool MaterialParser::getBlendingMode(BlendingMode* value) const noexcept {
static_assert(sizeof(BlendingMode) == sizeof(uint8_t),
"BlendingMode expected size is wrong");
return mImpl.getFromSimpleChunk(ChunkType::MaterialBlendingMode, reinterpret_cast<uint8_t*>(value));
}
bool MaterialParser::getMaskThreshold(float* value) const noexcept {
return mImpl.getFromSimpleChunk(ChunkType::MaterialMaskThreshold, value);
}
bool MaterialParser::hasShadowMultiplier(bool* value) const noexcept {
return mImpl.getFromSimpleChunk(ChunkType::MaterialShadowMultiplier, value);
}
bool MaterialParser::getShading(Shading* value) const noexcept {
static_assert(sizeof(Shading) == sizeof(uint8_t),
"Shading expected size is wrong");
return mImpl.getFromSimpleChunk(ChunkType::MaterialShading, reinterpret_cast<uint8_t*>(value));
}
bool MaterialParser::hasCustomDepthShader(bool* value) const noexcept {
return mImpl.getFromSimpleChunk(ChunkType::MaterialHasCustomDepthShader, value);
}
bool MaterialParser::hasSpecularAntiAliasing(bool* value) const noexcept {
return mImpl.getFromSimpleChunk(ChunkType::MaterialSpecularAntiAliasing, value);
}
bool MaterialParser::getSpecularAntiAliasingVariance(float* value) const noexcept {
return mImpl.getFromSimpleChunk(ChunkType::MaterialSpecularAntiAliasingVariance, value);
}
bool MaterialParser::getSpecularAntiAliasingThreshold(float* value) const noexcept {
return mImpl.getFromSimpleChunk(ChunkType::MaterialSpecularAntiAliasingThreshold, value);
}
bool MaterialParser::getRequiredAttributes(AttributeBitset* value) const noexcept {
uint32_t rawAttributes = 0;
if (!mImpl.getFromSimpleChunk(ChunkType::MaterialRequiredAttributes, &rawAttributes)) {
return false;
}
*value = AttributeBitset();
value->setValue(rawAttributes);
return true;
}
bool MaterialParser::getRefractionMode(RefractionMode* value) const noexcept {
static_assert(sizeof(RefractionMode) == sizeof(uint8_t),
"Refraction expected size is wrong");
return mImpl.getFromSimpleChunk(ChunkType::MaterialRefraction, (uint8_t*)value);
}
bool MaterialParser::getRefractionType(RefractionType* value) const noexcept {
static_assert(sizeof(RefractionType) == sizeof(uint8_t),
"RefractionType expected size is wrong");
return mImpl.getFromSimpleChunk(ChunkType::MaterialRefractionType, (uint8_t*)value);
}
bool MaterialParser::getReflectionMode(ReflectionMode* value) const noexcept {
static_assert(sizeof(ReflectionMode) == sizeof(uint8_t),
"ReflectionMode expected size is wrong");
return mImpl.getFromSimpleChunk(ChunkType::MaterialReflectionMode, (uint8_t*)value);
}
bool MaterialParser::getShader(ShaderContent& shader,
ShaderModel shaderModel, Variant variant, ShaderType stage) noexcept {
return mImpl.mMaterialChunk.getShader(shader,
mImpl.mBlobDictionary, (uint8_t)shaderModel, variant, stage);
}
// ------------------------------------------------------------------------------------------------
bool ChunkUniformInterfaceBlock::unflatten(Unflattener& unflattener,
filament::UniformInterfaceBlock* uib) {
UniformInterfaceBlock::Builder builder = UniformInterfaceBlock::Builder();
CString name;
if (!unflattener.read(&name)) {
return false;
}
builder.name(std::move(name));
// Read number of fields.
uint64_t numFields = 0;
if (!unflattener.read(&numFields)) {
return false;
}
for (uint64_t i = 0; i < numFields; i++) {
CString fieldName;
uint64_t fieldSize = 0;
uint8_t fieldType = 0;
uint8_t fieldPrecision = 0;
if (!unflattener.read(&fieldName)) {
return false;
}
if (!unflattener.read(&fieldSize)) {
return false;
}
if (!unflattener.read(&fieldType)) {
return false;
}
if (!unflattener.read(&fieldPrecision)) {
return false;
}
// a size of 1 means not an array
builder.add(fieldName, fieldSize == 1 ? 0 : fieldSize,
UniformInterfaceBlock::Type(fieldType),
UniformInterfaceBlock::Precision(fieldPrecision));
}
*uib = builder.build();
return true;
}
bool ChunkSamplerInterfaceBlock::unflatten(Unflattener& unflattener,
filament::SamplerInterfaceBlock* sib) {
SamplerInterfaceBlock::Builder builder = SamplerInterfaceBlock::Builder();
CString name;
if (!unflattener.read(&name)) {
return false;
}
builder.name(name);
// Read number of fields.
uint64_t numFields = 0;
if (!unflattener.read(&numFields)) {
return false;
}
for (uint64_t i = 0; i < numFields; i++) {
CString fieldName;
uint8_t fieldType = 0;
uint8_t fieldFormat = 0;
uint8_t fieldPrecision = 0;
bool fieldMultisample = false;
if (!unflattener.read(&fieldName)) {
return false;
}
if (!unflattener.read(&fieldType)) {
return false;
}
if (!unflattener.read(&fieldFormat)) {
return false;
}
if (!unflattener.read(&fieldPrecision)) {
return false;
}
if (!unflattener.read(&fieldMultisample)) {
return false;
}
builder.add(fieldName, SamplerInterfaceBlock::Type(fieldType),
SamplerInterfaceBlock::Format(fieldFormat),
SamplerInterfaceBlock::Precision(fieldPrecision),
fieldMultisample);
}
*sib = builder.build();
return true;
}
bool ChunkSubpassInterfaceBlock::unflatten(Unflattener& unflattener,
filament::SubpassInfo* subpass) {
CString block;
if (!unflattener.read(&block)) {
return false;
}
subpass->block = block;
// Read number of subpasses.
uint64_t numSubpasses = 0;
if (!unflattener.read(&numSubpasses)) {
return false;
}
for (uint64_t i = 0; i < numSubpasses; i++) {
CString subpassName;
uint8_t subpassType = 0;
uint8_t subpassFormat = 0;
uint8_t subpassPrecision = 0;
if (!unflattener.read(&subpass->name)) {
return false;
}
if (!unflattener.read(&subpassType)) {
return false;
}
if (!unflattener.read(&subpassFormat)) {
return false;
}
if (!unflattener.read(&subpassPrecision)) {
return false;
}
if (!unflattener.read(&subpass->attachmentIndex)) {
return false;
}
if (!unflattener.read(&subpass->binding)) {
return false;
}
subpass->type = SubpassType (subpassType);
subpass->format = Format (subpassFormat);
subpass->precision = Precision (subpassPrecision);
subpass->isValid = true;
}
return true;
}
} // namespace filament