* minimal backend support for compute - added api to dispatch a compute shader - added api to create and bind a ssbo - added api to read back a buffer Only implemented in the gl backend * Add a backend compute test suite * basic support for compute shaders in matc this is still very much work-in-progress. We're not supporting images nor ssbo for now. * rename UniformInterfaceBlock to BufferInterfaceBlock * augment BufferInterfaceBlock to support ssbo features - add support for std430 - add support for ssbo - add support for variable-size array - add support for memory qualifiers * reformat MaterialBuilder * material format: move subpasses outside of parameters subpasses now are their own json property instead of being a "parameter". * refactor parameter() methods to match Buffer/SamplerInterfaceBlock We're just shuffling the arguments. * add support for buffers in .mat files * filamat now generates buffer blocks (ssbo) * take feature level into consideration when optimizing shaders * don't store the 'uniform binding' chunk for level 2 materials this includes some refactoring/cleanups of MaterialParser * matinfo: fixes for compute - separate subpasses from parameters - don't attempt to print material properties
180 lines
5.0 KiB
C++
180 lines
5.0 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 <filaflat/MaterialChunk.h>
|
|
#include <filaflat/ChunkContainer.h>
|
|
|
|
#include <utils/Log.h>
|
|
|
|
namespace filaflat {
|
|
|
|
static inline uint32_t makeKey(uint8_t shaderModel, filament::Variant variant, uint8_t stage) noexcept {
|
|
static_assert(sizeof(variant.key) * 8 <= 8);
|
|
return (shaderModel << 16) | (stage << 8) | variant.key;
|
|
}
|
|
|
|
void MaterialChunk::decodeKey(uint32_t key, uint8_t* model, filament::Variant::type_t* variant,
|
|
uint8_t* stage) {
|
|
*variant = key & 0xff;
|
|
*stage = (key >> 8) & 0xff;
|
|
*model = (key >> 16) & 0xff;
|
|
}
|
|
|
|
MaterialChunk::MaterialChunk(ChunkContainer const& container)
|
|
: mContainer(container) {
|
|
}
|
|
|
|
MaterialChunk::~MaterialChunk() noexcept = default;
|
|
|
|
bool MaterialChunk::initialize(filamat::ChunkType materialTag) {
|
|
|
|
if (mBase != nullptr) {
|
|
// initialize() should be called only once.
|
|
return true;
|
|
}
|
|
|
|
auto [start, end] = mContainer.getChunkRange(materialTag);
|
|
Unflattener unflattener(start, end);
|
|
|
|
mUnflattener = unflattener;
|
|
mMaterialTag = materialTag;
|
|
mBase = unflattener.getCursor();
|
|
|
|
// Read how many shaders we have in the chunk.
|
|
uint64_t numShaders;
|
|
if (!unflattener.read(&numShaders) || numShaders == 0) {
|
|
return false;
|
|
}
|
|
|
|
// Read all index entries.
|
|
for (uint64_t i = 0 ; i < numShaders; i++) {
|
|
uint8_t shaderModelValue;
|
|
filament::Variant variant;
|
|
uint8_t pipelineStageValue;
|
|
uint32_t offsetValue;
|
|
|
|
if (!unflattener.read(&shaderModelValue)) {
|
|
return false;
|
|
}
|
|
|
|
if (!unflattener.read(&variant)) {
|
|
return false;
|
|
}
|
|
|
|
if (!unflattener.read(&pipelineStageValue)) {
|
|
return false;
|
|
}
|
|
|
|
if (!unflattener.read(&offsetValue)) {
|
|
return false;
|
|
}
|
|
|
|
uint32_t key = makeKey(shaderModelValue, variant, pipelineStageValue);
|
|
mOffsets[key] = offsetValue;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool MaterialChunk::getTextShader(Unflattener unflattener, BlobDictionary const& dictionary,
|
|
ShaderContent& shaderContent, uint8_t shaderModel, filament::Variant variant, uint8_t ps) {
|
|
if (mBase == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
// Jump and read
|
|
uint32_t key = makeKey(shaderModel, variant, ps);
|
|
auto pos = mOffsets.find(key);
|
|
if (pos == mOffsets.end()) {
|
|
return false;
|
|
}
|
|
|
|
size_t offset = pos->second;
|
|
if (offset == 0) {
|
|
// This shader was not found.
|
|
return false;
|
|
}
|
|
unflattener.setCursor(mBase + offset);
|
|
|
|
// Read how big the shader is.
|
|
uint32_t shaderSize = 0;
|
|
if (!unflattener.read(&shaderSize)){
|
|
return false;
|
|
}
|
|
|
|
// Read how many lines there are.
|
|
uint32_t lineCount = 0;
|
|
if (!unflattener.read(&lineCount)){
|
|
return false;
|
|
}
|
|
|
|
shaderContent.reserve(shaderSize);
|
|
shaderContent.resize(shaderSize);
|
|
size_t cursor = 0;
|
|
|
|
// Read all lines.
|
|
for(int32_t i = 0 ; i < lineCount; i++) {
|
|
uint16_t lineIndex;
|
|
if (!unflattener.read(&lineIndex)) {
|
|
return false;
|
|
}
|
|
const auto& content = dictionary[lineIndex];
|
|
|
|
// Replace null with newline.
|
|
memcpy(&shaderContent[cursor], content.data(), content.size() - 1);
|
|
cursor += content.size() - 1;
|
|
shaderContent[cursor++] = '\n';
|
|
}
|
|
|
|
// Write the terminating null character.
|
|
shaderContent[cursor++] = 0;
|
|
assert_invariant(cursor == shaderSize);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool MaterialChunk::getSpirvShader(BlobDictionary const& dictionary,
|
|
ShaderContent& shaderContent, uint8_t shaderModel, filament::Variant variant, uint8_t stage) {
|
|
|
|
if (mBase == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
uint32_t key = makeKey(shaderModel, variant, stage);
|
|
auto pos = mOffsets.find(key);
|
|
if (pos == mOffsets.end()) {
|
|
return false;
|
|
}
|
|
|
|
shaderContent = dictionary[pos->second];
|
|
return true;
|
|
}
|
|
|
|
bool MaterialChunk::getShader(ShaderContent& shaderContent,
|
|
BlobDictionary const& dictionary, uint8_t shaderModel, filament::Variant variant, uint8_t stage) {
|
|
switch (mMaterialTag) {
|
|
case filamat::ChunkType::MaterialGlsl:
|
|
case filamat::ChunkType::MaterialMetal:
|
|
return getTextShader(mUnflattener, dictionary, shaderContent, shaderModel, variant, stage);
|
|
case filamat::ChunkType::MaterialSpirv:
|
|
return getSpirvShader(dictionary, shaderContent, shaderModel, variant, stage);
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
} // namespace filaflat
|
|
|