载入中...
搜索中...
未找到
ShaderAsset.cpp
浏览该文件的文档.
1#include "asset/ShaderAsset.h"
2
3#include <cmath>
4#include <limits>
5#include <set>
6
7namespace eve::asset {
8namespace {
9Result<std::vector<std::uint32_t>> stage(const Value& value, std::uint32_t model, const ShaderAssetLimits& limits) {
10 const auto* input = value.getIf<Value::Array>();
11 if (!input || input->size() < 5 || input->size() > limits.maximumStageWords)
12 return Result<std::vector<std::uint32_t>>::failure(
13 Diagnostic::error(DiagnosticCode::InvalidArgument, "Shader stage size is invalid", {}, {}, "asset.shader"));
14 std::vector<std::uint32_t> words;
15 words.reserve(input->size());
16 for (const auto& word : *input) {
17 if (!word.isInt64() || word.asInt() < 0 || word.asInt() > std::numeric_limits<std::uint32_t>::max())
18 return Result<std::vector<std::uint32_t>>::failure(
19 Diagnostic::error(DiagnosticCode::InvalidArgument, "Shader stage requires unsigned 32-bit words", {},
20 {}, "asset.shader"));
21 words.push_back(static_cast<std::uint32_t>(word.asInt()));
22 }
23 if (words[0] != 0x07230203 || words[1] < 0x00010000 || words[1] > 0x00010600 || (words[1] & 0xff) != 0 ||
24 words[3] == 0 || words[4] != 0)
25 return Result<std::vector<std::uint32_t>>::failure(
26 Diagnostic::error(DiagnosticCode::InvalidArgument, "Unsupported SPIR-V header", {}, {}, "asset.shader"));
27 bool main = false;
28 for (std::size_t cursor = 5; cursor < words.size();) {
29 const auto count = words[cursor] >> 16;
30 const auto opcode = words[cursor] & 0xffff;
31 if (count == 0 || count > words.size() - cursor)
32 return Result<std::vector<std::uint32_t>>::failure(Diagnostic::error(
33 DiagnosticCode::InvalidArgument, "Truncated SPIR-V instruction", {}, {}, "asset.shader"));
34 if (opcode == 15) {
35 if (count < 4)
36 return Result<std::vector<std::uint32_t>>::failure(Diagnostic::error(
37 DiagnosticCode::InvalidArgument, "Invalid SPIR-V entry point", {}, {}, "asset.shader"));
38 if (count >= 5 && words[cursor + 3] == 0x6e69616d && words[cursor + 4] == 0) {
39 if (main || words[cursor + 1] != model || words[cursor + 2] == 0 || words[cursor + 2] >= words[3])
40 return Result<std::vector<std::uint32_t>>::failure(Diagnostic::error(
41 DiagnosticCode::InvalidArgument, "Incompatible main entry point", {}, {}, "asset.shader"));
42 main = true;
43 }
44 }
45 cursor += count;
46 }
47 if (!main)
48 return Result<std::vector<std::uint32_t>>::failure(Diagnostic::error(
49 DiagnosticCode::InvalidArgument, "SPIR-V main entry point is missing", {}, {}, "asset.shader"));
50 return Result<std::vector<std::uint32_t>>::success(std::move(words));
51}
52} // namespace
53
55 const auto* fields = definition.getIf<Value::Object>();
56 if (!fields || fields->size() != 7)
58 "Shader definition requires exactly seven known fields",
59 {}, {}, "asset.shader"));
60 for (const auto name : {"schema", "schemaVersion", "interface", "format", "vertex", "fragment", "parameters"})
61 if (!fields->contains(name))
63 DiagnosticCode::InvalidArgument, "Shader field is missing or unknown", {}, {}, "asset.shader"));
64 if (!fields->at("schema").isString() || fields->at("schema").asString() != "eve.shader" ||
65 !fields->at("schemaVersion").isInt64() || fields->at("schemaVersion").asInt() != 1)
67 DiagnosticCode::UnknownVersion, "Unsupported shader schema/version", {}, {}, "asset.shader"));
68 if (!fields->at("format").isString() || fields->at("format").asString() != "spirv-1.6" ||
69 !fields->at("interface").isString())
71 DiagnosticCode::InvalidArgument, "Unsupported shader format/interface", {}, {}, "asset.shader"));
72 ShaderAsset result;
73 const auto& interface = fields->at("interface").asString();
74 if (interface == "sprite2d")
76 else if (interface != "mesh3d")
78 Diagnostic::error(DiagnosticCode::InvalidArgument, "Unsupported shader interface", {}, {}, "asset.shader"));
79 const auto* parameters = fields->at("parameters").getIf<Value::Array>();
80 if (!parameters || parameters->size() > 32)
82 DiagnosticCode::InvalidArgument, "Invalid shader parameter count", {}, {}, "asset.shader"));
83 std::set<std::string> names;
84 std::size_t slots = 0;
85 for (const auto& parameter : *parameters) {
86 const auto* object = parameter.getIf<Value::Object>();
87 if (!object || object->size() != 2 || !object->contains("name") || !object->contains("default") ||
88 !object->at("name").isString())
90 Diagnostic::error(DiagnosticCode::InvalidArgument, "Invalid parameter fields", {}, {}, "asset.shader"));
91 const auto& name = object->at("name").asString();
92 const auto* defaults = object->at("default").getIf<Value::Array>();
93 if (name.empty() || name.size() > 128 || name.find('\0') != std::string::npos || !names.insert(name).second ||
94 !defaults || defaults->empty() || defaults->size() > 4 || (slots += defaults->size()) > 32)
96 "Invalid parameter name or push-constant capacity",
97 {}, {}, "asset.shader"));
99 for (const auto& value : *defaults) {
100 if (!value.isDouble() && !value.isInt64())
102 Diagnostic::error(DiagnosticCode::InvalidArgument, "Non-numeric default", {}, {}, "asset.shader"));
103 const double number = value.isDouble() ? value.asDouble() : static_cast<double>(value.asInt());
104 if (!std::isfinite(number) || std::abs(number) > std::numeric_limits<float>::max())
106 DiagnosticCode::InvalidArgument, "Non-finite float default", {}, {}, "asset.shader"));
107 output.defaults.push_back(static_cast<float>(number));
108 }
109 result.parameters.push_back(std::move(output));
110 }
111 auto vertex = stage(fields->at("vertex"), 0, limits);
112 if (!vertex) return Result<ShaderAsset>::failure(vertex.status());
113 auto fragment = stage(fields->at("fragment"), 4, limits);
114 if (!fragment) return Result<ShaderAsset>::failure(fragment.status());
115 result.vertex = std::move(vertex).takeValue();
116 result.fragment = std::move(fragment).takeValue();
117 return Result<ShaderAsset>::success(std::move(result));
118}
119} // namespace eve::asset
double value
std::string output
EvpackChunkInput input
Definition Evpack.cpp:170
std::string name
std::vector< std::string > fields
Definition PlayHost.cpp:111
glm::mat4 model
double number
LocalPageCacheEntry slots[ShadowConfig::kLocalSlots]
std::uint32_t count
std::size_t cursor
Json object
const AssetImportLimits & limits
std::size_t at
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
The canonical owning dynamic value used by data-facing protocols.
Definition Value.h:31
std::map< std::string, Value > Object
Definition Value.h:34
std::vector< Value > Array
Definition Value.h:33
std::string word
int main(int argc, char **argv)
Definition main.cpp:46
Result< ShaderAsset > decodeShaderAsset(const Value &definition, const ShaderAssetLimits &limits)
Decode strict eve.shader/1 metadata with SPIR-V 1.0 through 1.6 stages.
Admission bounds checked before copying stage words.
Definition ShaderAsset.h:34
One sequential float/vector push-constant parameter, owned by the definition.
Definition ShaderAsset.h:20
Owning CPU program snapshot; decoding does not prove GPU/descriptor compatibility.
Definition ShaderAsset.h:26
std::vector< std::uint32_t > vertex
Definition ShaderAsset.h:28
ShaderAssetInterface interface
Definition ShaderAsset.h:27
std::vector< ShaderAssetParameter > parameters
Definition ShaderAsset.h:30
std::vector< std::uint32_t > fragment
Definition ShaderAsset.h:29