/* * Copyright (c) 2024 Huawei Device Co., Ltd. * 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 "pipeline_layout_loader.h" #include #include #include #include #include "json_format_serialization.h" #include "json_util.h" #include "util/log.h" using namespace BASE_NS; using namespace CORE_NS; RENDER_BEGIN_NAMESPACE() // clang-format off CORE_JSON_SERIALIZE_ENUM(ShaderStageFlagBits, { { (ShaderStageFlagBits)0, nullptr }, { ShaderStageFlagBits::CORE_SHADER_STAGE_VERTEX_BIT, "vertex_bit" }, { ShaderStageFlagBits::CORE_SHADER_STAGE_FRAGMENT_BIT, "fragment_bit" }, { ShaderStageFlagBits::CORE_SHADER_STAGE_COMPUTE_BIT, "compute_bit" }, }) CORE_JSON_SERIALIZE_ENUM(DescriptorType, { { DescriptorType::CORE_DESCRIPTOR_TYPE_MAX_ENUM, nullptr }, // default { DescriptorType::CORE_DESCRIPTOR_TYPE_SAMPLER, "sampler" }, { DescriptorType::CORE_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, "combined_image_sampler" }, { DescriptorType::CORE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, "sampled_image" }, { DescriptorType::CORE_DESCRIPTOR_TYPE_STORAGE_IMAGE, "storage_image" }, { DescriptorType::CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER, "uniform_texel_buffer" }, { DescriptorType::CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER, "storage_texel_buffer" }, { DescriptorType::CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER, "uniform_buffer" }, { DescriptorType::CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER, "storage_buffer" }, { DescriptorType::CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, "uniform_buffer_dynamic" }, { DescriptorType::CORE_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, "storage_buffer_dynamic" }, { DescriptorType::CORE_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, "input_attachment" }, { DescriptorType::CORE_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE, "acceleration_structure" }, }) // clang-format on void FromJson(const json::value& jsonData, JsonContext& context) { SafeGetJsonValue(jsonData, "binding", context.error, context.data.binding); SafeGetJsonEnum(jsonData, "descriptorType", context.error, context.data.descriptorType); SafeGetJsonValue(jsonData, "descriptorCount", context.error, context.data.descriptorCount); SafeGetJsonBitfield( jsonData, "shaderStageFlags", context.error, context.data.shaderStageFlags); } void FromJson(const json::value& jsonData, JsonContext& context) { SafeGetJsonValue(jsonData, "set", context.error, context.data.set); PipelineLayoutLoader::LoadResult loadResult; ParseArray(jsonData, "bindings", context.data.bindings, loadResult); context.error = loadResult.error; // NOTE: does not fetch descriptor set arrays } PipelineLayoutLoader::LoadResult Load(const json::value& jsonData, const string_view uri, PipelineLayout& pl) { PipelineLayoutLoader::LoadResult result; pl = {}; // reset if (const auto pcIter = jsonData.find("pushConstant"); pcIter) { SafeGetJsonValue(*pcIter, "size", result.error, pl.pushConstant.byteSize); SafeGetJsonValue(*pcIter, "byteSize", result.error, pl.pushConstant.byteSize); SafeGetJsonBitfield( *pcIter, "shaderStageFlags", result.error, pl.pushConstant.shaderStageFlags); #if (RENDER_VALIDATION_ENABLED == 1) if (pl.pushConstant.byteSize > PipelineLayoutConstants::MAX_PUSH_CONSTANT_BYTE_SIZE) { PLUGIN_LOG_W("RENDER_VALIDATION: Invalid push constant size clamped (name:%s). push constant size %u <= %u", uri.data(), pl.pushConstant.byteSize, PipelineLayoutConstants::MAX_PUSH_CONSTANT_BYTE_SIZE); } #endif pl.pushConstant.byteSize = Math::min(PipelineLayoutConstants::MAX_PUSH_CONSTANT_BYTE_SIZE, pl.pushConstant.byteSize); } vector descriptorSetLayouts; ParseArray( jsonData, "descriptorSetLayouts", descriptorSetLayouts, result); if (!descriptorSetLayouts.empty()) { const uint32_t inputDescriptorSetCount = static_cast(descriptorSetLayouts.size()); #if (RENDER_VALIDATION_ENABLED == 1) if (inputDescriptorSetCount > PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) { PLUGIN_LOG_W("RENDER_VALIDATION: Invalid pipeline layout sizes clamped (name:%s). Set count %u <= %u", uri.data(), inputDescriptorSetCount, PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT); } for (const auto& descRef : descriptorSetLayouts) { if (descRef.bindings.size() > PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT) { PLUGIN_LOG_W( "RENDER_VALIDATION: Binding count exceeds the maximum (name:%s). Binding count count %u <= %u", uri.data(), static_cast(descRef.bindings.size()), PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT); } for (const auto& bindingRef : descRef.bindings) { if (bindingRef.descriptorType == DescriptorType::CORE_DESCRIPTOR_TYPE_MAX_ENUM) { PLUGIN_LOG_W("RENDER_VALIDATION: Unknown descriptor type (name:%s) (set:%u, binding:%u).", uri.data(), descRef.set, bindingRef.binding); } } } #endif // pipeline layout descriptor sets might have gaps and only some sets defined for (uint32_t idx = 0; idx < inputDescriptorSetCount; ++idx) { const uint32_t setIndex = descriptorSetLayouts[idx].set; if (setIndex < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT) { pl.descriptorSetLayouts[setIndex] = move(descriptorSetLayouts[idx]); pl.descriptorSetCount++; } } // reassure pl.descriptorSetCount = Math::min(pl.descriptorSetCount, PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT); } else { result.error += "invalid descriptor set layout count"; } result.success = result.error.empty(); if (!result.success) { PLUGIN_LOG_E("error loading pipeline layout from json: %s", result.error.c_str()); } return result; } string_view PipelineLayoutLoader::GetUri() const { return uri_; } const PipelineLayout& PipelineLayoutLoader::GetPipelineLayout() const { return pipelineLayout_; } PipelineLayoutLoader::LoadResult PipelineLayoutLoader::Load(const string_view jsonString) { if (json::value jsonData = json::parse(jsonString.data()); jsonData) { return RENDER_NS::Load(jsonData, uri_, pipelineLayout_); } return LoadResult("Invalid json file."); } PipelineLayoutLoader::LoadResult PipelineLayoutLoader::Load(IFileManager& fileManager, const string_view uri) { uri_ = uri; IFile::Ptr file = fileManager.OpenFile(uri); if (!file) { PLUGIN_LOG_E("Error loading '%s'", string(uri).c_str()); return LoadResult("Failed to open file."); } const uint64_t byteLength = file->GetLength(); string raw; raw.resize(static_cast(byteLength)); if (file->Read(raw.data(), byteLength) != byteLength) { PLUGIN_LOG_E("Error loading '%s'", string(uri).c_str()); return LoadResult("Failed to read file."); } return Load(string_view(raw)); } RENDER_END_NAMESPACE()