载入中...
搜索中...
未找到
ShaderResourceScriptBindings.cpp
浏览该文件的文档.
1#include <algorithm>
2#include <memory>
3#include <stdexcept>
8#include "graphics/Bloom.h"
9#include "graphics/Graphics.h"
10#include "graphics/Mesh.h"
13
14namespace eve::graphics::detail {
15namespace {
16const Value& field(const Value& object, const std::string& name, Value::Type type) {
17 auto* found = object.find(name);
18 if (!found || found->type() != type) throw std::runtime_error("Missing or invalid image field: " + name);
19 return *found;
20}
21uint32_t number(const Value& object, const std::string& name) {
22 auto value = field(object, name, Value::Type::Int64).asInt();
23 if (value < 0 || uint64_t(value) > UINT32_MAX) throw std::runtime_error("Image integer out of range: " + name);
24 return uint32_t(value);
25}
26std::shared_ptr<const filesystem::FileData> readBytes(const std::string& path, size_t limit) {
27 auto* filesystem = filesystem::Filesystem::create();
28 if (!filesystem) throw std::runtime_error("Filesystem module initialization failed");
30 if (!result) throw std::runtime_error(result.status().describe());
31 return std::move(result).takeValue();
32}
33Result<void> replace(Graphics& graphics, Shader& shader, const std::string& vertex, const std::string& fragment,
34 const Value& descriptions, const std::string& constants, const std::string& instances = {}) {
35 try {
36 if (!descriptions.isArray() || descriptions.arraySize() > 16)
37 throw std::runtime_error("Expected at most 16 image resource descriptions");
38 std::vector<uint32_t> vert;
39 if (!vertex.empty()) {
40 auto stage = readShaderStageFile(vertex);
41 if (!stage) return Result<void>::failure(stage.status());
42 vert = std::move(stage).takeValue();
43 }
44 auto frag = readShaderStageFile(fragment);
45 if (!frag) return Result<void>::failure(frag.status());
46 std::vector<ShaderImageInput> images;
47 std::vector<std::shared_ptr<const filesystem::FileData>> files;
48 constexpr std::string_view keys[] = {"binding", "format", "dimension", "width", "height",
49 "layers", "mips", "path", "filter", "wrapU",
50 "wrapV", "anisotropy", "depth", "wrapW"};
51 constexpr std::pair<std::string_view, ShaderImageFormat> formats[] = {
52 {"r8-unorm", ShaderImageFormat::R8},
53 {"rg8-unorm", ShaderImageFormat::RG8},
54 {"r16-unorm", ShaderImageFormat::R16},
55 {"rgba8-unorm", ShaderImageFormat::RGBA8},
56 {"bgra8-unorm", ShaderImageFormat::BGRA8},
57 {"rgba8-srgb", ShaderImageFormat::RGBA8Srgb},
58 {"bgra8-srgb", ShaderImageFormat::BGRA8Srgb},
59 {"bc3-unorm", ShaderImageFormat::BC3},
60 {"bc1-unorm", ShaderImageFormat::BC1},
61 {"bc1-srgb", ShaderImageFormat::BC1Srgb},
62 {"bc3-srgb", ShaderImageFormat::BC3Srgb},
63 {"bc7-unorm", ShaderImageFormat::BC7},
64 {"bc7-srgb", ShaderImageFormat::BC7Srgb},
65 {"rgba16-unorm", ShaderImageFormat::RGBA16Unorm},
66 {"rgba16-float", ShaderImageFormat::RGBA16Float},
67 {"rgba32-float", ShaderImageFormat::RGBA32Float}};
68 size_t totalBytes = 0;
69 for (size_t i = 0; i < descriptions.arraySize(); ++i) {
70 const auto& row = descriptions.at(i);
71 if (!row.isObject()) throw std::runtime_error("Image description must be an object");
72 for (const auto& key : row.keys())
73 if (std::find(std::begin(keys), std::end(keys), key) == std::end(keys))
74 throw std::runtime_error("Unknown image resource field: " + key);
75 ShaderImageInput image;
76 image.binding = number(row, "binding");
77 image.width = number(row, "width");
78 image.height = number(row, "height");
79 image.layers = number(row, "layers");
80 image.mipLevels = number(row, "mips");
81 const auto format = field(row, "format", Value::Type::String).asString();
82 auto found = std::find_if(std::begin(formats), std::end(formats),
83 [&](const auto& item) { return item.first == format; });
84 if (found == std::end(formats)) throw std::runtime_error("Unknown image format: " + format);
85 image.format = found->second;
86 const auto dimension = field(row, "dimension", Value::Type::String).asString();
87 if (dimension == "2d")
89 else if (dimension == "array2d")
91 else if (dimension == "cube")
93 else if (dimension == "3d")
95 else
96 throw std::runtime_error("Unknown image view dimension: " + dimension);
97 if (row.find("depth") || image.dimension == ShaderImageDimension::Image3D)
98 image.depth = number(row, "depth");
99 auto filter = number(row, "filter");
100 auto wrapU = number(row, "wrapU"), wrapV = number(row, "wrapV");
101 if (filter > 2 || wrapU > 1 || wrapV > 1) throw std::runtime_error("Unknown resource sampler mode");
102 image.sampler.min = image.sampler.mag = filter == 0 ? FilterMode::Nearest : FilterMode::Linear;
103 image.sampler.mipmap = image.mipLevels <= 1 ? MipmapMode::Disabled
106 image.sampler.repeatU = wrapU == 0;
107 image.sampler.repeatV = wrapV == 0;
108 if (row.find("wrapW") || image.dimension == ShaderImageDimension::Image3D) {
109 const auto wrapW = number(row, "wrapW");
110 if (wrapW > 1) throw std::runtime_error("Unknown resource W sampler mode");
111 image.sampler.repeatW = wrapW == 0;
112 }
113 image.sampler.maxAnisotropy = float(number(row, "anisotropy"));
114 const auto path = field(row, "path", Value::Type::String).asString();
115 files.push_back(readBytes(path, 1024ull * 1024 * 1024));
116 const auto& bytes = *files.back();
117 totalBytes += bytes.getSize();
118 if (totalBytes > 2ull * 1024 * 1024 * 1024) throw std::runtime_error("Resource set exceeds 2 GiB");
119 image.bytes = {static_cast<const std::byte*>(bytes.getData()), size_t(bytes.getSize())};
120 image.contentOwner = files.back();
121 images.push_back(image);
122 }
123 std::shared_ptr<const filesystem::FileData> uniform;
124 std::shared_ptr<const filesystem::FileData> matrices;
125 ShaderResourceInputs inputs{images, {}};
126 if (!constants.empty()) {
127 uniform = readBytes(constants, 65536);
128 inputs.constants = {static_cast<const std::byte*>(uniform->getData()), size_t(uniform->getSize())};
129 }
130 if (!instances.empty()) {
131 matrices = readBytes(instances, 64ull * 1024 * 1024);
132 inputs.instanceMatrices = {static_cast<const std::byte*>(matrices->getData()), size_t(matrices->getSize())};
133 }
134 return graphics.replaceMeshShaderResources(shader, vert, frag.value(), inputs);
135 } catch (const std::exception& error) {
137 }
138}
139} // namespace
140void exposeShaderResourceBindings(ssq::Table& table, ssq::Class& cls) {
141 const auto vm = table.getHandle();
142 cls.addFunc("setBloomFilter", [vm](Graphics* graphics, const std::string& mode, float scatter, int iterations,
143 float clamp) {
144 if (!graphics || (mode != "karisTent" && mode != "gaussianScatter" && mode != "gaussianPyramid"))
148 "Expected bloom filter karisTent, gaussianScatter or gaussianPyramid", "graphics.bloom")));
150 : mode == "gaussianPyramid" ? BloomFilter::GaussianPyramid
152 scatter, iterations, clamp};
156 });
157 cls.addFunc("getBloomFilter", [](Graphics* graphics) {
158 return std::string(
159 graphics->pipelineBloom()->filterSettings().filter == BloomFilter::GaussianScatter ? "gaussianScatter"
160 : graphics->pipelineBloom()->filterSettings().filter == BloomFilter::GaussianPyramid ? "gaussianPyramid"
161 : "karisTent");
162 });
163 cls.addFunc("setSceneToneMapping", [vm](Graphics* graphics, const std::string& mode) {
164 if (!graphics || (mode != "none" && mode != "aces" && mode != "filmic"))
167 "Expected scene tone mapping none, aces or filmic",
168 "graphics.presentation")));
171 : mode == "filmic" ? Graphics::SceneToneMapping::Filmic
173 });
174 cls.addFunc("setScenePhotographicVignette", [vm](Graphics* graphics, float intensity) {
175 return script::projectResult(vm, graphics->setScenePhotographicVignette(intensity));
176 });
177 cls.addFunc("getScenePhotographicVignette",
178 [](Graphics* graphics) { return graphics->getScenePhotographicVignette(); });
179 cls.addFunc("getSceneToneMapping", [](Graphics* graphics) {
180 return std::string(graphics->getSceneToneMapping() == Graphics::SceneToneMapping::None ? "none"
182 : "aces");
183 });
184 cls.addFunc("setDisplayOutputMode", [vm](Graphics* graphics, const std::string& mode) {
185 if (!graphics)
187 DiagnosticCode::InvalidArgument, "Graphics must be present",
188 "graphics.presentation")));
190 if (mode == "sdr")
192 else if (mode == "auto")
194 else if (mode == "hdr10")
196 else if (mode == "scrgb")
198 else
201 "Expected display output mode sdr|auto|hdr10|scrgb",
202 "graphics.presentation")));
204 });
205 cls.addFunc("getDisplayOutputMode", [](Graphics* graphics) {
206 switch (graphics->getDisplayOutputMode()) {
208 return std::string("auto");
210 return std::string("hdr10");
212 return std::string("scrgb");
214 default:
215 return std::string("sdr");
216 }
217 });
218 cls.addFunc("setDisplayHdrCalibration",
219 [vm](Graphics* graphics, float paperWhiteNits, float peakNits) {
220 if (!graphics)
223 "Graphics must be present",
224 "graphics.presentation")));
226 vm, graphics->setDisplayHdrCalibration(paperWhiteNits, peakNits));
227 });
228 cls.addFunc("getDisplayPaperWhiteNits", &Graphics::getDisplayPaperWhiteNits);
229 cls.addFunc("getDisplayPeakNits", &Graphics::getDisplayPeakNits);
230 cls.addFunc("getActiveDisplayColorSpace", [](Graphics* graphics) {
231 switch (graphics->getActiveDisplayColorSpace()) {
233 return std::string("hdr10");
235 return std::string("scrgb");
237 default:
238 return std::string("sdr");
239 }
240 });
241 cls.addFunc("isDisplayHdrActive", &Graphics::isDisplayHdrActive);
242 cls.addFunc("queryDisplayOutputSupport", [vm](Graphics* graphics) {
243 if (!graphics)
246 DiagnosticCode::InvalidArgument, "Graphics must be present", "graphics.presentation")),
249 [](const Graphics::DisplayOutputSupport& support) {
250 return Value::Object{{"sdr", support.sdr},
251 {"hdr10", support.hdr10},
252 {"scRgb", support.scRgb}};
253 });
254 });
255 cls.addFunc("drawMeshShaderInstances", [vm](Graphics* graphics, Mesh* mesh, Shader* shader, ssq::Array model,
256 int64_t first, int64_t count) {
257 try {
258 if (!graphics || !mesh || !shader || model.size() != 16 || first < 0 || count < 0 ||
259 uint64_t(first) > UINT32_MAX || uint64_t(count) > UINT32_MAX)
260 throw std::runtime_error("Expected mesh, shader, 16 matrix floats and nonnegative uint32 range");
261 glm::mat4 transform;
262 for (int i = 0; i < 16; ++i) transform[i / 4][i % 4] = model.get<float>(i);
263 return script::projectResult(vm, graphics->drawMeshShaderInstances(*mesh, *shader, transform, Color(1.f),
264 uint32_t(first), uint32_t(count)));
265 } catch (const std::exception& error) {
267 DiagnosticCode::InvalidArgument, error.what(), "graphics.instances")));
268 }
269 });
270 cls.addFunc("replaceMeshShaderResourcesFromFiles", [vm](Graphics* graphics, Shader* shader,
271 const std::string& vertex, const std::string& fragment,
272 ssq::Object images, const std::string& constants) {
273 if (!graphics || !shader)
276 Diagnostic::error(DiagnosticCode::InvalidArgument, "Graphics and Shader must be present")));
277 auto value = script::valueFromSquirrel(images);
279 return script::projectResult(vm, replace(*graphics, *shader, vertex, fragment, value.value(), constants));
280 });
281 cls.addFunc("replaceInstancedMeshShaderResourcesFromFiles",
282 [vm](Graphics* graphics, Shader* shader, const std::string& vertex, const std::string& fragment,
283 ssq::Object images, const std::string& constants, const std::string& instances) {
284 if (!graphics || !shader || instances.empty())
287 "Graphics, Shader and instance file must be present")));
288 auto value = script::valueFromSquirrel(images);
291 vm, replace(*graphics, *shader, vertex, fragment, value.value(), constants, instances));
292 });
293}
294} // namespace eve::graphics::detail
double value
std::vector< BuildingInstanceSnapshot > instances
HSQUIRRELVM vm
Definition ECS.cpp:20
HSQOBJECT cls
Definition ECS.cpp:21
vk::ShaderModule vert
vk::ShaderModule frag
std::uint32_t key
vk::UniqueImage image
int inputs
Definition GridGraph.cpp:23
std::int32_t first
std::uint64_t bytes
std::string name
bool valid
std::string error
Definition Package.cpp:60
std::string path
Definition PlayHost.cpp:110
float begin
Mesh * mesh
Shader * shader
glm::mat4 model
double number
bool found
std::string filter
std::uint32_t count
The single Squirrel projection for common Result, Status and Value.
TerrainThermalSettings settings
int limit
Definition TreeMesh.cpp:164
int iterations
Definition TreeMesh.cpp:311
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 failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
std::map< std::string, Value > Object
Definition Value.h:34
Type
Runtime kind of the owned value.
Definition Value.h:38
Result< void > configureFilter(const BloomFilterSettings &settings)
Select a reconstruction filter for subsequent builds.
BloomFilterSettings filterSettings() const
Return a value snapshot. Render thread only; retains no references.
Definition Bloom.h:56
virtual Result< DisplayOutputSupport > queryDisplayOutputSupport() const
Query which present formats the current surface can offer.
virtual DisplayColorSpace getActiveDisplayColorSpace() const
Color space of the live swapchain after the last rebuild.
virtual float getDisplayPaperWhiteNits() const
Paper-white luminance in nits for HDR present encoding.
virtual float getDisplayPeakNits() const
Peak luminance in nits for HDR present encoding.
virtual float getScenePhotographicVignette() const
Return photographic vignette intensity; render thread only.
Definition Graphics.h:1387
virtual Result< void > setDisplayHdrCalibration(float paperWhiteNits, float peakNits)
Set paper-white and peak luminance used by HDR present encoding.
virtual bool isDisplayHdrActive() const
True when the live swapchain is scRGB or HDR10.
DisplayOutputMode
Requested swapchain present preference.
Definition Graphics.h:1327
Bloom * pipelineBloom()
Pipeline-owned linear-HDR bloom pyramid, created on first use. @lifetime Returned effect remains vali...
virtual Result< void > setScenePhotographicVignette(float intensity)
Set cosine-fourth photographic vignette intensity in [0,1].
virtual DisplayOutputMode getDisplayOutputMode() const
Return the requested present preference.
virtual Result< void > drawMeshShaderInstances(Mesh &mesh, Shader &shader, const glm::mat4 &model, const Color &tint, std::uint32_t first, std::uint32_t count)
Draw a checked range from a resource shader's immutable instance matrix buffer. @ownership Mesh and S...
Definition Graphics.h:1116
virtual SceneToneMapping getSceneToneMapping() const
Return the current final display mapping; graphics/render thread only.
Definition Graphics.h:1347
virtual Result< void > setSceneToneMapping(SceneToneMapping mode)
Set final scene display mapping on the graphics/render thread.
virtual Result< void > setDisplayOutputMode(DisplayOutputMode mode)
Request a present color space on the graphics/render thread.
GPU mesh handle (+ optional CPU morph targets).
Definition Mesh.h:25
Custom GPU program.
Definition Shader.h:39
std::variant< std::monostate, std::int64_t, double, std::string, bool > Value
Definition Database.h:26
Result< std::shared_ptr< const FileData > > readPreparedFile(const std::string &path, size_t limit)
Join a queued read or synchronously read an immutable file snapshot.
void exposeShaderResourceBindings(ssq::Table &table, ssq::Class &cls)
Expose shader resource bindings.
Result< std::vector< std::uint32_t > > readShaderStageFile(const std::string &path)
Reads shader stage file.
eve::Color Color
RGBA color used by every graphics draw call. Lives inside eve::graphics so including a graphics heade...
Definition Color.h:13
EVENGINE_API_BACKENDS Result< void > validateBloomFilterSettings(const BloomFilterSettings &settings)
Validate enum, finite scatter [0,1], iterations [1,16], and finite clamp (0,65504].
const EditorValue * field(const EditorValue &value, const char *name)
ssq::Table projectResult(HSQUIRRELVM vm, Result< void > &&result)
Consume and project a void native Result using the common schema.
Result< Value > valueFromSquirrel(HSQUIRRELVM vm, SQInteger index, const SquirrelValueOptions &options)
Convert one Squirrel value into the canonical owning Value tree.
WidgetDesc row(std::vector< WidgetDesc > children, std::string id)
Horizontal elastic layout row.
Definition Widget.cpp:679
Value-owned Gaussian bloom settings, independent of camera intensity and threshold.
Definition Bloom.h:21
Surface present formats the current device/window can offer.
Definition Graphics.h:1331