/* * 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. */ #include #include #include #include #include #include "CommonWriter.h" #include #include #include using namespace filament; using namespace backend; using namespace filaflat; using namespace filamat; using namespace std; using namespace utils; namespace filament { namespace matdbg { static std::string arraySizeToString(uint64_t size) { if (size > 1) { std::string s = "["; s += size; s += "]"; return s; } return ""; } template static void printChunk(ostream& json, const ChunkContainer& container, ChunkType type, const char* title) { T value; if (read(container, type, reinterpret_cast(&value))) { json << "\"" << title << "\": \"" << toString(value) << "\",\n"; } } static void printFloatChunk(ostream& json, const ChunkContainer& container, ChunkType type, const char* title) { float value; if (read(container, type, &value)) { json << "\"" << title << "\": " << setprecision(2) << value << ",\n"; } } static void printUint32Chunk(ostream& json, const ChunkContainer& container, ChunkType type, const char* title) { uint32_t value; if (read(container, type, &value)) { json << "\"" << title << "\": " << value << ",\n"; } } static void printStringChunk(ostream& json, const ChunkContainer& container, ChunkType type, const char* title) { CString value; if (read(container, type, &value)) { json << "\"" << title << "\": \"" << value.c_str_safe() << "\",\n"; } } static bool printMaterial(ostream& json, const ChunkContainer& container) { printStringChunk(json, container, MaterialName, "name"); printUint32Chunk(json, container, MaterialVersion, "version"); json << "\"shading\": {\n"; printChunk(json, container, MaterialShading, "model"); printChunk(json, container, ChunkType::MaterialDomain, "material_domain"); printChunk(json, container, MaterialVertexDomain, "vertex_domain"); printChunk(json, container, MaterialInterpolation, "interpolation"); printChunk(json, container, MaterialShadowMultiplier, "shadow_multiply"); printChunk(json, container, MaterialSpecularAntiAliasing, "specular_antialiasing"); printFloatChunk(json, container, MaterialSpecularAntiAliasingVariance, "variance"); printFloatChunk(json, container, MaterialSpecularAntiAliasingThreshold, "threshold"); printChunk(json, container, MaterialClearCoatIorChange, "clear_coat_IOR_change"); json << "\"_\": 0 },\n"; json << "\"raster\": {\n"; printChunk(json, container, MaterialBlendingMode, "blending"); printFloatChunk(json, container, MaterialMaskThreshold, "mask_threshold"); printChunk(json, container, MaterialColorWrite, "color_write"); printChunk(json, container, MaterialDepthWrite, "depth_write"); printChunk(json, container, MaterialDepthTest, "depth_test"); printChunk(json, container, MaterialDoubleSided, "double_sided"); printChunk(json, container, MaterialCullingMode, "culling"); printChunk(json, container, MaterialTransparencyMode, "transparency"); json << "\"_\": 0 },\n"; return true; } static bool printParametersInfo(ostream& json, const ChunkContainer& container) { // TODO return true; } static void printShaderInfo(ostream& json, const std::vector& info) { for (uint64_t i = 0; i < info.size(); ++i) { const auto& item = info[i]; string variantString = ""; // NOTE: The 3-character nomenclature used here is consistent with the ASCII art seen in the // Variant header file and allows the information to fit in a reasonable amount of space on // the page. The HTML file has a legend. if (item.variant) { if (item.variant & filament::Variant::DIRECTIONAL_LIGHTING) variantString += "DIR|"; if (item.variant & filament::Variant::DYNAMIC_LIGHTING) variantString += "DYN|"; if (item.variant & filament::Variant::SHADOW_RECEIVER) variantString += "SRE|"; if (item.variant & filament::Variant::SKINNING_OR_MORPHING) variantString += "SKN|"; if (item.variant & filament::Variant::DEPTH) variantString += "DEP|"; variantString = variantString.substr(0, variantString.length() - 1); } string ps = (item.pipelineStage == backend::ShaderType::VERTEX) ? "vertex " : "fragment"; json << " {" << "\"index\": \"" << std::setw(2) << i << "\", " << "\"shaderModel\": \"" << toString(item.shaderModel) << "\", " << "\"pipelineStage\": \"" << ps << "\", " << "\"variantString\": \"" << variantString << "\", " << "\"variant\": \"" << std::hex << int(item.variant) << std::dec << "\" }" << ((i == info.size() - 1) ? "\n" : ",\n"); } } static bool printGlslInfo(ostream& json, const ChunkContainer& container) { std::vector info; info.resize(getShaderCount(container, ChunkType::MaterialGlsl)); if (!getGlShaderInfo(container, info.data())) { return false; } json << "\"opengl\": [\n"; printShaderInfo(json, info); json << "],\n"; return true; } static bool printVkInfo(ostream& json, const ChunkContainer& container) { std::vector info; info.resize(getShaderCount(container, ChunkType::MaterialSpirv)); if (!getVkShaderInfo(container, info.data())) { return false; } json << "\"vulkan\": [\n"; printShaderInfo(json, info); json << "],\n"; return true; } static bool printMetalInfo(ostream& json, const ChunkContainer& container) { std::vector info; info.resize(getShaderCount(container, ChunkType::MaterialMetal)); if (!getMetalShaderInfo(container, info.data())) { return false; } json << "\"metal\": [\n"; printShaderInfo(json, info); json << "],\n"; return true; } bool JsonWriter::writeMaterialInfo(const filaflat::ChunkContainer& container) { ostringstream json; if (!printMaterial(json, container)) { return false; } if (!printParametersInfo(json, container)) { return false; } if (!printGlslInfo(json, container)) { return false; } if (!printVkInfo(json, container)) { return false; } if (!printMetalInfo(json, container)) { return false; } json << "\"required_attributes\": [\n"; uint32_t requiredAttributes; if (read(container, MaterialRequiredAttributes, &requiredAttributes)) { string comma; AttributeBitset bitset; bitset.setValue(requiredAttributes); if (bitset.count() > 0) { for (size_t i = 0; i < bitset.size(); i++) { if (bitset.test(i)) { json << comma << "\"" << toString(static_cast(i)) << "\""; comma = ","; } } } } json << "]\n"; mJsonString = CString(json.str().c_str()); return true; } const char* JsonWriter::getJsonString() const { return mJsonString.c_str(); } size_t JsonWriter::getJsonSize() const { return mJsonString.size(); } bool JsonWriter::writeActiveInfo(const filaflat::ChunkContainer& package, Backend backend, uint64_t activeVariants) { vector shaders; ostringstream json; json << "[\""; switch (backend) { case Backend::OPENGL: shaders.resize(getShaderCount(package, ChunkType::MaterialGlsl)); getGlShaderInfo(package, shaders.data()); json << "opengl"; break; case Backend::VULKAN: shaders.resize(getShaderCount(package, ChunkType::MaterialSpirv)); getVkShaderInfo(package, shaders.data()); json << "vulkan"; break; case Backend::METAL: shaders.resize(getShaderCount(package, ChunkType::MaterialMetal)); getMetalShaderInfo(package, shaders.data()); json << "metal"; break; default: return false; } json << "\""; for (uint8_t variant = 0; variant < VARIANT_COUNT; variant++) { if (activeVariants & (1 << variant)) { int shaderIndex = 0; for (const auto& info : shaders) { if (info.variant == variant) { json << ", " << shaderIndex; } shaderIndex++; } } } json << "]"; mJsonString = CString(json.str().c_str()); return true; } } // namespace matdbg } // namespace filament