blob: bf46e805a93eb998b0ba8b73da3c484921ce563a [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "impeller/runtime_stage/runtime_stage.h"
#include <array>
#include <memory>
#include "fml/mapping.h"
#include "impeller/base/validation.h"
#include "impeller/core/runtime_types.h"
#include "impeller/core/shader_types.h"
#include "impeller/runtime_stage/runtime_stage_flatbuffers.h"
#include "runtime_stage_types_flatbuffers.h"
namespace impeller {
static RuntimeUniformType ToType(fb::UniformDataType type) {
switch (type) {
case fb::UniformDataType::kFloat:
return RuntimeUniformType::kFloat;
case fb::UniformDataType::kSampledImage:
return RuntimeUniformType::kSampledImage;
case fb::UniformDataType::kStruct:
return RuntimeUniformType::kStruct;
}
FML_UNREACHABLE();
}
static RuntimeShaderStage ToShaderStage(fb::Stage stage) {
switch (stage) {
case fb::Stage::kVertex:
return RuntimeShaderStage::kVertex;
case fb::Stage::kFragment:
return RuntimeShaderStage::kFragment;
case fb::Stage::kCompute:
return RuntimeShaderStage::kCompute;
}
FML_UNREACHABLE();
}
/// The generated name from GLSLang/shaderc for the UBO containing non-opaque
/// uniforms specified in the user-written runtime effect shader.
///
/// Vulkan does not allow non-opaque uniforms outside of a UBO.
const char* RuntimeStage::kVulkanUBOName =
"_RESERVED_IDENTIFIER_FIXUP_gl_DefaultUniformBlock";
std::unique_ptr<RuntimeStage> RuntimeStage::RuntimeStageIfPresent(
const fb::RuntimeStage* runtime_stage,
const std::shared_ptr<fml::Mapping>& payload) {
if (!runtime_stage) {
return nullptr;
}
return std::unique_ptr<RuntimeStage>(
new RuntimeStage(runtime_stage, payload));
}
RuntimeStage::Map RuntimeStage::DecodeRuntimeStages(
const std::shared_ptr<fml::Mapping>& payload) {
if (payload == nullptr || !payload->GetMapping()) {
return {};
}
if (!fb::RuntimeStagesBufferHasIdentifier(payload->GetMapping())) {
return {};
}
auto raw_stages = fb::GetRuntimeStages(payload->GetMapping());
return {
{RuntimeStageBackend::kSkSL,
RuntimeStageIfPresent(raw_stages->sksl(), payload)},
{RuntimeStageBackend::kMetal,
RuntimeStageIfPresent(raw_stages->metal(), payload)},
{RuntimeStageBackend::kOpenGLES,
RuntimeStageIfPresent(raw_stages->opengles(), payload)},
{RuntimeStageBackend::kVulkan,
RuntimeStageIfPresent(raw_stages->vulkan(), payload)},
};
}
RuntimeStage::RuntimeStage(const fb::RuntimeStage* runtime_stage,
const std::shared_ptr<fml::Mapping>& payload)
: payload_(payload) {
FML_DCHECK(runtime_stage);
stage_ = ToShaderStage(runtime_stage->stage());
entrypoint_ = runtime_stage->entrypoint()->str();
auto* uniforms = runtime_stage->uniforms();
// Note: image bindings are screwy and will always have the same offset.
// track the binding of the UBO to determine where the image bindings go.
// This is only guaranteed to give us the correct bindings if there is a
// single sampler2D.
std::optional<size_t> ubo_id;
if (uniforms) {
for (auto i = uniforms->begin(), end = uniforms->end(); i != end; i++) {
RuntimeUniformDescription desc;
desc.name = i->name()->str();
desc.location = i->location();
desc.binding = i->binding();
desc.type = ToType(i->type());
if (desc.type == kStruct) {
ubo_id = desc.location;
desc.binding = desc.location;
}
desc.dimensions = RuntimeUniformDimensions{
static_cast<size_t>(i->rows()), static_cast<size_t>(i->columns())};
desc.bit_width = i->bit_width();
desc.array_elements = i->array_elements();
if (i->struct_layout()) {
for (const auto& byte_type : *i->struct_layout()) {
desc.struct_layout.push_back(static_cast<uint8_t>(byte_type));
}
}
desc.struct_float_count = i->struct_float_count();
uniforms_.push_back(std::move(desc));
}
}
code_mapping_ = std::make_shared<fml::NonOwnedMapping>(
runtime_stage->shader()->data(), //
runtime_stage->shader()->size(), //
[payload = payload_](auto, auto) {} //
);
size_t binding = 64;
if (ubo_id.has_value() && ubo_id.value() == binding) {
binding++;
}
for (auto& uniform : uniforms_) {
if (uniform.type == kSampledImage) {
uniform.binding = binding;
binding++;
if (ubo_id.has_value() && ubo_id.value() == binding) {
binding++;
}
}
}
for (const auto& uniform : GetUniforms()) {
if (uniform.type == kStruct) {
descriptor_set_layouts_.push_back(DescriptorSetLayout{
static_cast<uint32_t>(uniform.location),
DescriptorType::kUniformBuffer,
ShaderStage::kFragment,
});
} else if (uniform.type == kSampledImage) {
descriptor_set_layouts_.push_back(DescriptorSetLayout{
static_cast<uint32_t>(uniform.binding),
DescriptorType::kSampledImage,
ShaderStage::kFragment,
});
}
}
is_valid_ = true;
}
RuntimeStage::~RuntimeStage() = default;
RuntimeStage::RuntimeStage(RuntimeStage&&) = default;
RuntimeStage& RuntimeStage::operator=(RuntimeStage&&) = default;
bool RuntimeStage::IsValid() const {
return is_valid_;
}
const std::shared_ptr<fml::Mapping>& RuntimeStage::GetCodeMapping() const {
return code_mapping_;
}
const std::vector<RuntimeUniformDescription>& RuntimeStage::GetUniforms()
const {
return uniforms_;
}
const RuntimeUniformDescription* RuntimeStage::GetUniform(
const std::string& name) const {
for (const auto& uniform : uniforms_) {
if (uniform.name == name) {
return &uniform;
}
}
return nullptr;
}
const std::string& RuntimeStage::GetEntrypoint() const {
return entrypoint_;
}
RuntimeShaderStage RuntimeStage::GetShaderStage() const {
return stage_;
}
bool RuntimeStage::IsDirty() const {
return is_dirty_;
}
void RuntimeStage::SetClean() {
is_dirty_ = false;
}
const std::vector<DescriptorSetLayout>& RuntimeStage::GetDescriptorSetLayouts()
const {
return descriptor_set_layouts_;
}
} // namespace impeller