617 lines
22 KiB
C++
617 lines
22 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 "filamat/MaterialBuilder.h"
|
|
|
|
#include <vector>
|
|
|
|
#include <utils/Panic.h>
|
|
#include <utils/Log.h>
|
|
|
|
#include <private/filament/UniformInterfaceBlock.h>
|
|
#include <private/filament/SamplerInterfaceBlock.h>
|
|
|
|
#include <private/filament/Variant.h>
|
|
|
|
#include "GLSLPostProcessor.h"
|
|
|
|
#include "shaders/MaterialInfo.h"
|
|
#include "shaders/ShaderGenerator.h"
|
|
|
|
#include "eiff/BlobDictionary.h"
|
|
#include "eiff/LineDictionary.h"
|
|
#include "eiff/MaterialInterfaceBlockChunk.h"
|
|
#include "eiff/MaterialTextChunk.h"
|
|
#include "eiff/MaterialSpirvChunk.h"
|
|
#include "eiff/ChunkContainer.h"
|
|
#include "eiff/SimpleFieldChunk.h"
|
|
#include "eiff/DictionaryTextChunk.h"
|
|
#include "eiff/DictionarySpirvChunk.h"
|
|
|
|
#include "sca/GLSLTools.h"
|
|
|
|
using namespace utils;
|
|
|
|
namespace filamat {
|
|
|
|
void MaterialBuilderBase::prepare() {
|
|
mCodeGenPermutations.clear();
|
|
mShaderModels.reset();
|
|
|
|
if (mPlatform == Platform::MOBILE) {
|
|
mShaderModels.set(static_cast<size_t>(ShaderModel::GL_ES_30));
|
|
} else if (mPlatform == Platform::DESKTOP) {
|
|
mShaderModels.set(static_cast<size_t>(ShaderModel::GL_CORE_41));
|
|
} else if (mPlatform == Platform::ALL) {
|
|
mShaderModels.set(static_cast<size_t>(ShaderModel::GL_ES_30));
|
|
mShaderModels.set(static_cast<size_t>(ShaderModel::GL_CORE_41));
|
|
}
|
|
|
|
// OpenGL is a special case. If we're doing any optimization, then we need to go to Spir-V.
|
|
TargetApi glCodeGenTargetApi = mOptimization > MaterialBuilder::Optimization::PREPROCESSOR ?
|
|
TargetApi::VULKAN : TargetApi::OPENGL;
|
|
|
|
// Build a list of codegen permutations, which is useful across all types of material builders.
|
|
// The shader model loop starts at 1 to skip ShaderModel::UNKNOWN.
|
|
for (uint8_t i = 1; i < filament::driver::SHADER_MODEL_COUNT; i++) {
|
|
if (!mShaderModels.test(i)) {
|
|
continue; // skip this shader model since it was not requested.
|
|
}
|
|
switch (mTargetApi) {
|
|
case TargetApi::ALL:
|
|
mCodeGenPermutations.push_back({i, TargetApi::OPENGL, glCodeGenTargetApi});
|
|
mCodeGenPermutations.push_back({i, TargetApi::VULKAN, TargetApi::VULKAN});
|
|
break;
|
|
case TargetApi::OPENGL:
|
|
mCodeGenPermutations.push_back({i, TargetApi::OPENGL, glCodeGenTargetApi});
|
|
break;
|
|
case TargetApi::VULKAN:
|
|
mCodeGenPermutations.push_back({i, TargetApi::VULKAN, TargetApi::VULKAN});
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
MaterialBuilder::MaterialBuilder() : mMaterialName("Unnamed") {
|
|
std::fill_n(mProperties, filament::MATERIAL_PROPERTIES_COUNT, false);
|
|
mShaderModels.reset();
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::name(const char* name) noexcept {
|
|
mMaterialName = CString(name);
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::material(const char* code, size_t line) noexcept {
|
|
mMaterialCode = CString(code);
|
|
mMaterialLineOffset = line;
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::materialVertex(const char* code, size_t line) noexcept {
|
|
mMaterialVertexCode = CString(code);
|
|
mMaterialVertexLineOffset = line;
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::shading(Shading shading) noexcept {
|
|
mShading = shading;
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::interpolation(Interpolation interpolation) noexcept {
|
|
mInterpolation = interpolation;
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::variable(Variable v, const char* name) noexcept {
|
|
switch (v) {
|
|
case Variable::CUSTOM0:
|
|
case Variable::CUSTOM1:
|
|
case Variable::CUSTOM2:
|
|
case Variable::CUSTOM3:
|
|
assert(size_t(v) < filament::MATERIAL_VARIABLES_COUNT);
|
|
mVariables[size_t(v)] = CString(name);
|
|
break;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::parameter(UniformType type, const char* name) noexcept {
|
|
ASSERT_POSTCONDITION(mParameterCount < MAX_PARAMETERS_COUNT, "Too many parameters");
|
|
mParameters[mParameterCount++] = { name, type, 1 };
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::parameter(UniformType type, size_t size, const char* name) noexcept {
|
|
ASSERT_POSTCONDITION(mParameterCount < MAX_PARAMETERS_COUNT, "Too many parameters");
|
|
mParameters[mParameterCount++] = { name, type, size };
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::parameter(
|
|
SamplerType samplerType, SamplerFormat format, SamplerPrecision precision, const char* name) noexcept {
|
|
ASSERT_POSTCONDITION(mParameterCount < MAX_PARAMETERS_COUNT, "Too many parameters");
|
|
mParameters[mParameterCount++] = { name, samplerType, format, precision };
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::parameter(
|
|
SamplerType samplerType, SamplerFormat format, const char* name) noexcept {
|
|
return parameter(samplerType, format, SamplerPrecision::DEFAULT, name);
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::parameter(
|
|
SamplerType samplerType, SamplerPrecision precision, const char* name) noexcept {
|
|
return parameter(samplerType, SamplerFormat::FLOAT, precision, name);
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::parameter(
|
|
SamplerType samplerType, const char* name) noexcept {
|
|
return parameter(samplerType, SamplerFormat::FLOAT, SamplerPrecision::DEFAULT, name);
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::require(filament::VertexAttribute attribute) noexcept {
|
|
mRequiredAttributes.set(attribute);
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::blending(BlendingMode blending) noexcept {
|
|
mBlendingMode = blending;
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::vertexDomain(VertexDomain domain) noexcept {
|
|
mVertexDomain = domain;
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::culling(CullingMode culling) noexcept {
|
|
mCullingMode = culling;
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::colorWrite(bool enable) noexcept {
|
|
mColorWrite = enable;
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::depthWrite(bool enable) noexcept {
|
|
mDepthWrite = enable;
|
|
mDepthWriteSet = true;
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::depthCulling(bool enable) noexcept {
|
|
mDepthTest = enable;
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::doubleSided(bool doubleSided) noexcept {
|
|
mDoubleSided = doubleSided;
|
|
mDoubleSidedSet = true;
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::maskThreshold(float threshold) noexcept {
|
|
mMaskThreshold = threshold;
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::shadowMultiplier(bool shadowMultiplier) noexcept {
|
|
mShadowMultiplier = shadowMultiplier;
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::transparencyMode(TransparencyMode mode) noexcept {
|
|
mTransparencyMode = mode;
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::platform(Platform platform) noexcept {
|
|
mPlatform = platform;
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::targetApi(TargetApi targetApi) noexcept {
|
|
mTargetApi = targetApi;
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::optimization(Optimization optimization) noexcept {
|
|
mOptimization = optimization;
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::printShaders(bool printShaders) noexcept {
|
|
mPrintShaders = printShaders;
|
|
return *this;
|
|
}
|
|
|
|
MaterialBuilder& MaterialBuilder::variantFilter(uint8_t variantFilter) noexcept {
|
|
mVariantFilter = variantFilter;
|
|
return *this;
|
|
}
|
|
|
|
bool MaterialBuilder::hasExternalSampler() const noexcept {
|
|
for (size_t i = 0, c = mParameterCount; i < c; i++) {
|
|
auto const& param = mParameters[i];
|
|
if (param.isSampler && param.samplerType == SamplerType::SAMPLER_EXTERNAL) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void MaterialBuilder::prepareToBuild(MaterialInfo& info) noexcept {
|
|
MaterialBuilderBase::prepare();
|
|
|
|
// Build the per-material sampler block and uniform block.
|
|
filament::SamplerInterfaceBlock::Builder sbb;
|
|
filament::UniformInterfaceBlock::Builder ibb;
|
|
for (size_t i = 0, c = mParameterCount; i < c; i++) {
|
|
auto const& param = mParameters[i];
|
|
if (param.isSampler) {
|
|
sbb.add(param.name, param.samplerType, param.samplerFormat, param.samplerPrecision);
|
|
} else {
|
|
ibb.add(param.name, param.size, param.uniformType);
|
|
}
|
|
}
|
|
|
|
if (mBlendingMode == BlendingMode::MASKED) {
|
|
ibb.add("maskThreshold", 1, UniformType::FLOAT);
|
|
}
|
|
|
|
mRequiredAttributes.set(filament::VertexAttribute::POSITION);
|
|
if (mShading != filament::Shading::UNLIT || mShadowMultiplier) {
|
|
mRequiredAttributes.set(filament::VertexAttribute::TANGENTS);
|
|
}
|
|
|
|
info.sib = sbb.name("MaterialParams").build();
|
|
info.uib = ibb.name("MaterialParams").build();
|
|
|
|
info.isLit = isLit();
|
|
info.isDoubleSided = mDoubleSided;
|
|
info.hasExternalSamplers = hasExternalSampler();
|
|
info.requiredAttributes = mRequiredAttributes;
|
|
info.blendingMode = mBlendingMode;
|
|
info.shading = mShading;
|
|
info.hasShadowMultiplier = mShadowMultiplier;
|
|
}
|
|
|
|
bool MaterialBuilder::runStaticCodeAnalysis() noexcept {
|
|
using namespace filament::driver;
|
|
|
|
GLSLTools glslTools;
|
|
|
|
// Populate mProperties with the properties set in the shader.
|
|
if (!glslTools.findProperties(*this, mProperties, mTargetApi)) {
|
|
return false;
|
|
}
|
|
|
|
// At this point the shader is syntactically correct. Perform semantic analysis now.
|
|
ShaderModel model;
|
|
|
|
std::string shaderCode = peek(ShaderType::VERTEX, model, mProperties);
|
|
bool result = glslTools.analyzeVertexShader(shaderCode, model, mTargetApi);
|
|
if (!result) return result;
|
|
|
|
shaderCode = peek(ShaderType::FRAGMENT, model, mProperties);
|
|
result = glslTools.analyzeFragmentShader(shaderCode, model, mTargetApi);
|
|
return result;
|
|
}
|
|
|
|
static void showErrorMessage(const char* materialName, uint8_t variant,
|
|
MaterialBuilder::TargetApi targetApi, filament::driver::ShaderType shaderType,
|
|
const std::string& shaderCode) {
|
|
using ShaderType = filament::driver::ShaderType;
|
|
using TargetApi = MaterialBuilder::TargetApi;
|
|
utils::slog.e
|
|
<< "Error in \"" << materialName << "\""
|
|
<< ", Variant 0x" << io::hex << (int) variant
|
|
<< (targetApi == TargetApi::VULKAN ? ", Vulkan.\n" : ", OpenGL.\n")
|
|
<< "=========================\n"
|
|
<< "Generated "
|
|
<< (shaderType == ShaderType::VERTEX ? "Vertex Shader\n" : "Fragment Shader\n")
|
|
<< "=========================\n"
|
|
<< shaderCode;
|
|
}
|
|
|
|
Package MaterialBuilder::build() noexcept {
|
|
GLSLTools::init();
|
|
|
|
if (!runStaticCodeAnalysis()) {
|
|
// Return an empty package to signal a failure to build the material.
|
|
Package package(0);
|
|
package.setValid(false);
|
|
return package;
|
|
}
|
|
|
|
bool errorOccured = false;
|
|
|
|
MaterialInfo info;
|
|
prepareToBuild(info);
|
|
|
|
// Create a postprocessor to optimize / compile to Spir-V if necessary.
|
|
GLSLPostProcessor postProcessor(mOptimization, mPrintShaders);
|
|
|
|
// Create chunk tree.
|
|
ChunkContainer container;
|
|
|
|
SimpleFieldChunk<uint32_t> matVersion(ChunkType::MaterialVersion, 1);
|
|
container.addChild(&matVersion);
|
|
|
|
SimpleFieldChunk<const char*> matName(ChunkType::MaterialName, mMaterialName.c_str_safe());
|
|
container.addChild(&matName);
|
|
|
|
SimpleFieldChunk<uint8_t> matShading(ChunkType::MaterialShading, static_cast<uint8_t>(mShading));
|
|
container.addChild(&matShading);
|
|
|
|
SimpleFieldChunk<uint8_t> matBlendingMode(ChunkType::MaterialBlendingMode,
|
|
static_cast<uint8_t>(mBlendingMode));
|
|
container.addChild(&matBlendingMode);
|
|
|
|
SimpleFieldChunk<float> matMaskThreshold(ChunkType::MaterialMaskThreshold, mMaskThreshold);
|
|
if (mBlendingMode == BlendingMode::MASKED) {
|
|
container.addChild(&matMaskThreshold);
|
|
}
|
|
|
|
SimpleFieldChunk<bool> matShadowMultiplier(ChunkType::MaterialShadowMultiplier, mShadowMultiplier);
|
|
if (mShading == Shading::UNLIT) {
|
|
container.addChild(&matShadowMultiplier);
|
|
}
|
|
|
|
SimpleFieldChunk<uint8_t> matTransparency(ChunkType::MaterialTransparencyMode,
|
|
static_cast<uint8_t>(mTransparencyMode));
|
|
container.addChild(&matTransparency);
|
|
|
|
SimpleFieldChunk<uint32_t> matRequiredAttributes(ChunkType::MaterialRequiredAttributes,
|
|
mRequiredAttributes.getValue());
|
|
container.addChild(&matRequiredAttributes);
|
|
|
|
// UIB
|
|
MaterialUniformInterfaceBlockChunk matUib = MaterialUniformInterfaceBlockChunk(info.uib);
|
|
container.addChild(&matUib);
|
|
|
|
// SIB
|
|
MaterialSamplerInterfaceBlockChunk matSib = MaterialSamplerInterfaceBlockChunk(info.sib);
|
|
container.addChild(&matSib);
|
|
|
|
SimpleFieldChunk<bool> matDepthWriteSet(ChunkType::MaterialDepthWriteSet, mDepthWriteSet);
|
|
container.addChild(&matDepthWriteSet);
|
|
|
|
SimpleFieldChunk<bool> matDoubleSidedSet(ChunkType::MaterialDoubleSidedSet, mDoubleSidedSet);
|
|
container.addChild(&matDoubleSidedSet);
|
|
|
|
SimpleFieldChunk<bool> matDoubleSided(ChunkType::MaterialDoubleSided, mDoubleSided);
|
|
container.addChild(&matDoubleSided);
|
|
|
|
SimpleFieldChunk<bool> matColorWrite(ChunkType::MaterialColorWrite, mColorWrite);
|
|
container.addChild(&matColorWrite);
|
|
|
|
SimpleFieldChunk<bool> matDepthWrite(ChunkType::MaterialDepthWrite, mDepthWrite);
|
|
container.addChild(&matDepthWrite);
|
|
|
|
SimpleFieldChunk<bool> matDepthTest(ChunkType::MaterialDepthTest, mDepthTest);
|
|
container.addChild(&matDepthTest);
|
|
|
|
SimpleFieldChunk<uint8_t> matCullingMode(ChunkType::MaterialCullingMode,
|
|
static_cast<uint8_t>(mCullingMode));
|
|
container.addChild(&matCullingMode);
|
|
|
|
SimpleFieldChunk<uint8_t> matVertexDomain(ChunkType::MaterialVertexDomain,
|
|
static_cast<uint8_t>(mVertexDomain));
|
|
container.addChild(&matVertexDomain);
|
|
|
|
SimpleFieldChunk<uint8_t> matInterpolation(ChunkType::MaterialInterpolation,
|
|
static_cast<uint8_t>(mInterpolation));
|
|
container.addChild(&matInterpolation);
|
|
|
|
SimpleFieldChunk<uint32_t> matShaderModels(ChunkType::MaterialShaderModels,
|
|
mShaderModels.getValue());
|
|
container.addChild(&matShaderModels);
|
|
|
|
// Generate all shaders.
|
|
std::vector<TextEntry> glslEntries;
|
|
std::vector<SpirvEntry> spirvEntries;
|
|
LineDictionary glslDictionary;
|
|
BlobDictionary spirvDictionary;
|
|
std::vector<uint32_t> spirv;
|
|
|
|
ShaderGenerator sg(mProperties, mVariables,
|
|
mMaterialCode, mMaterialLineOffset, mMaterialVertexCode, mMaterialVertexLineOffset);
|
|
|
|
bool emptyVertexCode = mMaterialVertexCode.empty();
|
|
bool customDepth = sg.hasCustomDepthShader() ||
|
|
mBlendingMode == BlendingMode::MASKED || !emptyVertexCode;
|
|
SimpleFieldChunk<bool> hasCustomDepth(ChunkType::MaterialHasCustomDepthShader, customDepth);
|
|
container.addChild(&hasCustomDepth);
|
|
|
|
for (const auto& params : mCodeGenPermutations) {
|
|
const ShaderModel shaderModel = ShaderModel(params.shaderModel);
|
|
const TargetApi targetApi = params.targetApi;
|
|
const TargetApi codeGenTargetApi = params.codeGenTargetApi;
|
|
std::vector<uint32_t>* pSpirv = (targetApi == TargetApi::VULKAN) ? &spirv : nullptr;
|
|
|
|
// Re-populate the set of sampler bindings for this API.
|
|
filament::SamplerBindingMap map;
|
|
auto backend = static_cast<filament::driver::Backend>(params.targetApi);
|
|
uint8_t offset = filament::getSamplerBindingsStart(backend);
|
|
map.populate(offset, &info.sib, mMaterialName.c_str());
|
|
info.samplerBindings = std::move(map);
|
|
|
|
TextEntry glslEntry;
|
|
SpirvEntry spirvEntry;
|
|
|
|
glslEntry.shaderModel = static_cast<uint8_t>(params.shaderModel);
|
|
spirvEntry.shaderModel = static_cast<uint8_t>(params.shaderModel);
|
|
|
|
// apply custom variants filters
|
|
uint8_t variantMask = ~mVariantFilter;
|
|
|
|
for (uint8_t k = 0; k < filament::VARIANT_COUNT; k++) {
|
|
|
|
if (filament::Variant::isReserved(k)) {
|
|
continue;
|
|
}
|
|
|
|
glslEntry.variant = k;
|
|
spirvEntry.variant = k;
|
|
|
|
// Remove variants for unlit materials
|
|
uint8_t v = filament::Variant::filterVariant(
|
|
k & variantMask, isLit() || mShadowMultiplier);
|
|
|
|
if (filament::Variant::filterVariantVertex(v) == k) {
|
|
// Vertex Shader
|
|
std::string vs = sg.createVertexProgram(
|
|
shaderModel, targetApi, codeGenTargetApi, info, k,
|
|
mInterpolation, mVertexDomain);
|
|
|
|
bool ok = postProcessor.process(vs, filament::driver::ShaderType::VERTEX,
|
|
shaderModel, &vs, pSpirv);
|
|
if (!ok) {
|
|
showErrorMessage(mMaterialName.c_str_safe(), k, targetApi,
|
|
filament::driver::ShaderType::VERTEX, vs);
|
|
errorOccured = true;
|
|
break;
|
|
}
|
|
|
|
if (targetApi == TargetApi::OPENGL) {
|
|
if (codeGenTargetApi == TargetApi::VULKAN) {
|
|
sg.fixupExternalSamplers(shaderModel, vs, info);
|
|
}
|
|
|
|
glslEntry.stage = filament::driver::ShaderType::VERTEX;
|
|
glslEntry.shaderSize = vs.size();
|
|
glslEntry.shader = (char*) malloc(glslEntry.shaderSize + 1);
|
|
strcpy(glslEntry.shader, vs.c_str());
|
|
glslDictionary.addText(glslEntry.shader);
|
|
glslEntries.push_back(glslEntry);
|
|
}
|
|
|
|
if (targetApi == TargetApi::VULKAN) {
|
|
assert(spirv.size() > 0);
|
|
spirvEntry.stage = filament::driver::ShaderType::VERTEX;
|
|
spirvEntry.dictionaryIndex = spirvDictionary.addBlob(spirv);
|
|
spirv.clear();
|
|
spirvEntries.push_back(spirvEntry);
|
|
}
|
|
}
|
|
|
|
if (filament::Variant::filterVariantFragment(v) == k) {
|
|
// Fragment Shader
|
|
std::string fs = sg.createFragmentProgram(
|
|
shaderModel, targetApi, codeGenTargetApi, info, k, mInterpolation);
|
|
|
|
bool ok = postProcessor.process(fs, filament::driver::ShaderType::FRAGMENT,
|
|
shaderModel, &fs, pSpirv);
|
|
if (!ok) {
|
|
showErrorMessage(mMaterialName.c_str_safe(), k, targetApi,
|
|
filament::driver::ShaderType::FRAGMENT, fs);
|
|
errorOccured = true;
|
|
break;
|
|
}
|
|
|
|
if (targetApi == TargetApi::OPENGL) {
|
|
if (codeGenTargetApi == TargetApi::VULKAN) {
|
|
sg.fixupExternalSamplers(shaderModel, fs, info);
|
|
}
|
|
|
|
glslEntry.stage = filament::driver::ShaderType::FRAGMENT;
|
|
glslEntry.shaderSize = fs.size();
|
|
glslEntry.shader = (char*) malloc(glslEntry.shaderSize + 1);
|
|
strcpy(glslEntry.shader, fs.c_str());
|
|
glslDictionary.addText(glslEntry.shader);
|
|
glslEntries.push_back(glslEntry);
|
|
}
|
|
|
|
if (targetApi == TargetApi::VULKAN) {
|
|
assert(spirv.size() > 0);
|
|
spirvEntry.stage = filament::driver::ShaderType::FRAGMENT;
|
|
spirvEntry.dictionaryIndex = spirvDictionary.addBlob(spirv);
|
|
spirv.clear();
|
|
spirvEntries.push_back(spirvEntry);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Emit GLSL chunks (TextDictionaryReader and MaterialTextChunk).
|
|
filamat::DictionaryTextChunk dicGlslChunk(glslDictionary, ChunkType::DictionaryGlsl);
|
|
MaterialTextChunk glslChunk(glslEntries, glslDictionary, ChunkType::MaterialGlsl);
|
|
if (!glslEntries.empty()) {
|
|
container.addChild(&dicGlslChunk);
|
|
container.addChild(&glslChunk);
|
|
}
|
|
|
|
// Emit SPIRV chunks (SpirvDictionaryReader and MaterialSpirvChunk).
|
|
filamat::DictionarySpirvChunk dicSpirvChunk(spirvDictionary);
|
|
MaterialSpirvChunk spirvChunk(spirvEntries);
|
|
if (!spirvEntries.empty()) {
|
|
container.addChild(&dicSpirvChunk);
|
|
container.addChild(&spirvChunk);
|
|
}
|
|
|
|
// Flatten all chunks in the container into a Package.
|
|
size_t packageSize = container.getSize();
|
|
Package package(packageSize);
|
|
Flattener f(package);
|
|
container.flatten(f);
|
|
package.setValid(!errorOccured);
|
|
|
|
// Free all shaders that were created earlier.
|
|
for (TextEntry entry : glslEntries) {
|
|
free(entry.shader);
|
|
}
|
|
return package;
|
|
}
|
|
|
|
const std::string MaterialBuilder::peek(filament::driver::ShaderType type,
|
|
filament::driver::ShaderModel& model, const PropertyList& properties) noexcept {
|
|
|
|
ShaderGenerator sg(properties, mVariables,
|
|
mMaterialCode, mMaterialLineOffset, mMaterialVertexCode, mMaterialVertexLineOffset);
|
|
|
|
MaterialInfo info;
|
|
prepareToBuild(info);
|
|
|
|
for (const auto& params : mCodeGenPermutations) {
|
|
model = ShaderModel(params.shaderModel);
|
|
const TargetApi targetApi = params.targetApi;
|
|
const TargetApi codeGenTargetApi = params.codeGenTargetApi;
|
|
|
|
// Re-populate the set of sampler bindings for this API.
|
|
filament::SamplerBindingMap map;
|
|
auto backend = static_cast<filament::driver::Backend>(params.targetApi);
|
|
uint8_t offset = filament::getSamplerBindingsStart(backend);
|
|
map.populate(offset, &info.sib, mMaterialName.c_str());
|
|
info.samplerBindings = std::move(map);
|
|
|
|
if (type == filament::driver::ShaderType::VERTEX) {
|
|
return sg.createVertexProgram(model, targetApi, codeGenTargetApi,
|
|
info, 0, mInterpolation, mVertexDomain);
|
|
} else {
|
|
return sg.createFragmentProgram(model, targetApi, codeGenTargetApi,
|
|
info, 0, mInterpolation);
|
|
}
|
|
}
|
|
|
|
return std::string("");
|
|
}
|
|
|
|
} // namespace filamat
|