Generate struct for per vertex data.

This commit is contained in:
Chinmay Garde 2021-06-27 15:17:36 -07:00 committed by Dan Field
parent b5ebf6805a
commit 59f9d7fb6d
5 changed files with 170 additions and 47 deletions

View File

@ -149,14 +149,14 @@ std::shared_ptr<fml::Mapping> Reflector::GetReflectionCC() const {
std::optional<nlohmann::json> 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<nlohmann::json> Reflector::GenerateTemplateArguments() const {
return std::nullopt;
}
auto& struct_definitions = root["struct_definitions"] =
nlohmann::json::array_t{};
std::set<spirv_cross::ID> known_structs;
ir_->for_each_typed_id<SPIRType>([&](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<spirv_cross::ID> known_structs;
ir_->for_each_typed_id<SPIRType>([&](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::StructMember> Reflector::ReadStructMembers(
return result;
}
std::optional<nlohmann::json::object_t> Reflector::ReflectStructDefinition(
std::optional<Reflector::StructDefinition> 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<nlohmann::json::object_t> 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<Reflector::StructDefinition> 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::StructDefinition>
Reflector::ReflectPerVertexStructDefinition(
const SmallVector<spirv_cross::Resource>& 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<uint32_t> 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;
}

View File

@ -38,8 +38,22 @@ class Reflector {
std::shared_ptr<fml::Mapping> 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<StructMember> members;
};
const Options options_;
const std::shared_ptr<const spirv_cross::ParsedIR> ir_;
// TODO: There is no reason this needs to the MSL subtype.
const std::shared_ptr<const spirv_cross::CompilerMSL> compiler_;
std::unique_ptr<const nlohmann::json> template_arguments_;
std::shared_ptr<fml::Mapping> reflection_header_;
@ -64,9 +78,16 @@ class Reflector {
std::optional<nlohmann::json::object_t> ReflectType(
const spirv_cross::TypeID& type_id) const;
std::optional<nlohmann::json::object_t> ReflectStructDefinition(
nlohmann::json::object_t EmitStructDefinition(
std::optional<Reflector::StructDefinition> struc) const;
std::optional<StructDefinition> ReflectStructDefinition(
const spirv_cross::TypeID& type_id) const;
std::optional<StructDefinition> ReflectPerVertexStructDefinition(
const spirv_cross::SmallVector<spirv_cross::Resource>& stage_inputs)
const;
std::optional<std::string> 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<StructMember> ReadStructMembers(
const spirv_cross::TypeID& type_id) const;

View File

@ -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());

View File

@ -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;
}

View File

@ -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;
}