From 59f9d7fb6d7d10f7608eb009209a97ccdff3517d Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Sun, 27 Jun 2021 15:17:36 -0700 Subject: [PATCH] Generate struct for per vertex data. --- .../flutter/impeller/compiler/reflector.cc | 176 ++++++++++++++---- .../src/flutter/impeller/compiler/reflector.h | 29 ++- .../impeller/entity/entity_renderer.mm | 1 - .../src/flutter/impeller/primitives/box.frag | 4 +- .../src/flutter/impeller/primitives/box.vert | 7 +- 5 files changed, 170 insertions(+), 47 deletions(-) diff --git a/engine/src/flutter/impeller/compiler/reflector.cc b/engine/src/flutter/impeller/compiler/reflector.cc index b04f94d8f5f..7d88825a834 100644 --- a/engine/src/flutter/impeller/compiler/reflector.cc +++ b/engine/src/flutter/impeller/compiler/reflector.cc @@ -149,14 +149,14 @@ std::shared_ptr Reflector::GetReflectionCC() const { std::optional Reflector::GenerateTemplateArguments() const { nlohmann::json root; - { - const auto& entrypoints = compiler_->get_entry_points_and_stages(); - if (entrypoints.size() != 1) { - FML_LOG(ERROR) << "Incorrect number of entrypoints in the shader. Found " - << entrypoints.size() << " but expected 1."; - return std::nullopt; - } + const auto& entrypoints = compiler_->get_entry_points_and_stages(); + if (entrypoints.size() != 1) { + FML_LOG(ERROR) << "Incorrect number of entrypoints in the shader. Found " + << entrypoints.size() << " but expected 1."; + return std::nullopt; + } + { root["entrypoint"] = entrypoints.front().name; root["shader_name"] = options_.shader_name; root["shader_stage"] = @@ -187,20 +187,31 @@ std::optional Reflector::GenerateTemplateArguments() const { return std::nullopt; } - auto& struct_definitions = root["struct_definitions"] = - nlohmann::json::array_t{}; - std::set known_structs; - ir_->for_each_typed_id([&](uint32_t, const SPIRType& type) { - if (known_structs.find(type.self) != known_structs.end()) { - // Iterating over types this way leads to duplicates which may cause - // duplicate struct definitions. - return; + { + auto& struct_definitions = root["struct_definitions"] = + nlohmann::json::array_t{}; + std::set known_structs; + ir_->for_each_typed_id([&](uint32_t, const SPIRType& type) { + if (known_structs.find(type.self) != known_structs.end()) { + // Iterating over types this way leads to duplicates which may cause + // duplicate struct definitions. + return; + } + known_structs.insert(type.self); + if (auto struc = ReflectStructDefinition(type.self); struc.has_value()) { + struct_definitions.emplace_back(EmitStructDefinition(struc.value())); + } + }); + + if (entrypoints.front().execution_model == + spv::ExecutionModel::ExecutionModelVertex) { + if (auto struc = + ReflectPerVertexStructDefinition(shader_resources.stage_inputs); + struc.has_value()) { + struct_definitions.emplace_back(EmitStructDefinition(struc.value())); + } } - known_structs.insert(type.self); - if (auto struc = ReflectStructDefinition(type.self); struc.has_value()) { - struct_definitions.emplace_back(std::move(struc.value())); - } - }); + } return root; } @@ -448,7 +459,7 @@ std::vector Reflector::ReadStructMembers( return result; } -std::optional Reflector::ReflectStructDefinition( +std::optional Reflector::ReflectStructDefinition( const TypeID& type_id) const { const auto& type = compiler_->get_type(type_id); if (type.basetype != SPIRType::BaseType::Struct) { @@ -460,28 +471,125 @@ std::optional Reflector::ReflectStructDefinition( return std::nullopt; } - nlohmann::json::object_t struc; - struc["name"] = struct_name; - size_t total_size = 0u; for (const auto& member_type_id : type.member_types) { const auto& member_type = compiler_->get_type(member_type_id); total_size += (member_type.width * member_type.vecsize * member_type.columns) / 8u; } - struc["byte_length"] = total_size; - size_t members_size = 0u; - struc["members"] = nlohmann::json::array_t{}; - const auto struct_members = ReadStructMembers(type_id); - for (const auto& struct_member : struct_members) { - auto& member = struc["members"].emplace_back(nlohmann::json::object_t{}); - member["name"] = struct_member.name; - member["type"] = struct_member.type; - member["offset"] = struct_member.offset; - member["byte_length"] = struct_member.byte_length; + StructDefinition struc; + struc.name = struct_name; + struc.byte_length = total_size; + struc.members = ReadStructMembers(type_id); + return struc; +} + +nlohmann::json::object_t Reflector::EmitStructDefinition( + std::optional struc) const { + nlohmann::json::object_t result; + result["name"] = struc->name; + result["byte_length"] = struc->byte_length; + auto& members = result["members"] = nlohmann::json::array_t{}; + for (const auto& struc_member : struc->members) { + auto& member = members.emplace_back(nlohmann::json::object_t{}); + member["name"] = struc_member.name; + member["type"] = struc_member.type; + member["offset"] = struc_member.offset; + member["byte_length"] = struc_member.byte_length; + } + return result; +} + +struct VertexType { + std::string type_name; + std::string variable_name; + size_t byte_length = 0u; +}; + +static VertexType VertexTypeFromInputResource(const CompilerMSL& compiler, + const Resource* resource) { + VertexType result; + result.variable_name = resource->name; + auto type = compiler.get_type(resource->type_id); + const auto total_size = type.columns * type.vecsize * type.width / 8u; + result.byte_length = total_size; + + if (type.basetype == SPIRType::BaseType::Float && type.columns == 1u && + type.vecsize == 2u && type.width == sizeof(float) * 8u) { + result.type_name = "Point"; + } else if (type.basetype == SPIRType::BaseType::Float && type.columns == 1u && + type.vecsize == 4u && type.width == sizeof(float) * 8u) { + result.type_name = "Vector4"; + } else if (type.basetype == SPIRType::BaseType::Float && type.columns == 1u && + type.vecsize == 3u && type.width == sizeof(float) * 8u) { + result.type_name = "Vector3"; + } else { + // Catch all unknown padding. + result.type_name = TypeNameWithPaddingOfSize(total_size); } + return result; +} + +std::optional +Reflector::ReflectPerVertexStructDefinition( + const SmallVector& stage_inputs) const { + // Avoid emitting a zero sized structure. The code gen templates assume a + // non-zero size. + if (stage_inputs.empty()) { + return std::nullopt; + } + + // Validate locations are contiguous and there are no duplicates. + std::set locations; + for (const auto& input : stage_inputs) { + auto location = compiler_->get_decoration( + input.id, spv::Decoration::DecorationLocation); + if (locations.count(location) != 0) { + // Duplicate location. Bail. + return std::nullopt; + } + locations.insert(location); + } + + for (size_t i = 0; i < locations.size(); i++) { + if (locations.count(i) != 1) { + // Locations are not contiguous. Bail. + return std::nullopt; + } + } + + auto input_for_location = [&](uint32_t queried_location) -> const Resource* { + for (const auto& input : stage_inputs) { + auto location = compiler_->get_decoration( + input.id, spv::Decoration::DecorationLocation); + if (location == queried_location) { + return &input; + } + } + // This really cannot happen with all the validation above. + return nullptr; + }; + + StructDefinition struc; + struc.name = "PerVertexData"; + struc.byte_length = 0u; + for (size_t i = 0; i < locations.size(); i++) { + auto resource = input_for_location(i); + if (resource == nullptr) { + return std::nullopt; + } + const auto vertex_type = VertexTypeFromInputResource(*compiler_, resource); + + StructMember member; + member.name = vertex_type.variable_name; + member.type = vertex_type.type_name; + member.byte_length = vertex_type.byte_length; + member.offset = struc.byte_length; + struc.byte_length += vertex_type.byte_length; + struc.members.emplace_back(std::move(member)); + } return struc; } diff --git a/engine/src/flutter/impeller/compiler/reflector.h b/engine/src/flutter/impeller/compiler/reflector.h index 0b46b852836..615423675ee 100644 --- a/engine/src/flutter/impeller/compiler/reflector.h +++ b/engine/src/flutter/impeller/compiler/reflector.h @@ -38,8 +38,22 @@ class Reflector { std::shared_ptr GetReflectionCC() const; private: + struct StructMember { + std::string type; + std::string name; + size_t offset = 0u; + size_t byte_length = 0u; + }; + + struct StructDefinition { + std::string name; + size_t byte_length = 0u; + std::vector members; + }; + const Options options_; const std::shared_ptr ir_; + // TODO: There is no reason this needs to the MSL subtype. const std::shared_ptr compiler_; std::unique_ptr template_arguments_; std::shared_ptr reflection_header_; @@ -64,9 +78,16 @@ class Reflector { std::optional ReflectType( const spirv_cross::TypeID& type_id) const; - std::optional ReflectStructDefinition( + nlohmann::json::object_t EmitStructDefinition( + std::optional struc) const; + + std::optional ReflectStructDefinition( const spirv_cross::TypeID& type_id) const; + std::optional ReflectPerVertexStructDefinition( + const spirv_cross::SmallVector& stage_inputs) + const; + std::optional GetMemberNameAtIndexIfExists( const spirv_cross::SPIRType& parent_type, size_t index) const; @@ -75,12 +96,6 @@ class Reflector { size_t index, std::string suffix = "") const; - struct StructMember { - std::string type; - std::string name; - size_t offset; - size_t byte_length; - }; std::vector ReadStructMembers( const spirv_cross::TypeID& type_id) const; diff --git a/engine/src/flutter/impeller/entity/entity_renderer.mm b/engine/src/flutter/impeller/entity/entity_renderer.mm index 663dd1670af..9595a0188da 100644 --- a/engine/src/flutter/impeller/entity/entity_renderer.mm +++ b/engine/src/flutter/impeller/entity/entity_renderer.mm @@ -42,7 +42,6 @@ bool EntityRenderer::OnRender(const Surface& surface, RenderPass& pass) { pass.SetLabel("EntityRenderer Render Pass"); shader::BoxVertexInfo::UniformBuffer uniforms; - uniforms.color = Color::Blue(); uniforms.mvp = Matrix::MakeOrthographic(surface.GetSize()); diff --git a/engine/src/flutter/impeller/primitives/box.frag b/engine/src/flutter/impeller/primitives/box.frag index b00ed258eb8..e3a23d1c266 100644 --- a/engine/src/flutter/impeller/primitives/box.frag +++ b/engine/src/flutter/impeller/primitives/box.frag @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -in vec3 color; +in vec4 color; out vec4 fragColor; void main() { - fragColor = vec4(color, 1.0); + fragColor = color; } diff --git a/engine/src/flutter/impeller/primitives/box.vert b/engine/src/flutter/impeller/primitives/box.vert index c5bd284b526..8058ada1752 100644 --- a/engine/src/flutter/impeller/primitives/box.vert +++ b/engine/src/flutter/impeller/primitives/box.vert @@ -4,13 +4,14 @@ uniform UniformBuffer { mat4 mvp; - vec3 color; } uniforms; in vec3 vertexPosition; -out vec3 color; +in vec4 vertexColor; + +out vec4 color; void main() { gl_Position = uniforms.mvp * vec4(vertexPosition, 1.0); - color = uniforms.color; + color = vertexColor; }