9#include "graphics/shaders/pbr_surface.frag_wgsl.inc"
10#include "graphics/shaders/pbr_surface.vert_wgsl.inc"
14std::string_view sourceView(
const std::uint32_t* words, std::size_t
count) {
15 std::string_view
source(
reinterpret_cast<const char*
>(words),
count *
sizeof(std::uint32_t));
20void eraseDeclaration(std::string&
source, std::string_view variable) {
21 const std::string marker =
" var " + std::string(variable) +
" :";
23 if (
position == std::string::npos)
return;
31void eraseKeepalive(std::string&
source, std::string_view variable) {
32 const std::string marker =
"_ = " + std::string(variable) +
";";
43void replaceAll(std::string&
source, std::string_view
from, std::string_view
to) {
51std::string samplerName(std::uint32_t resource) {
53 if (resource < canonicalCount)
return "map" + std::to_string(resource) +
"_sampler";
54 return "detailMap" + std::to_string(resource - canonicalCount) +
"_sampler";
57void coalesceSampler(std::string&
source, std::string_view resource, std::uint32_t resourceIndex,
58 std::uint32_t representative) {
60 const std::string
sampler = std::string(resource) +
"_sampler";
66void replaceResourceCalls(std::string&
source, std::string_view
function, std::string_view resource,
67 std::string_view replacement) {
68 const std::string prefix = std::string(
function) +
"(" + std::string(resource);
69 std::size_t
begin = 0;
71 const auto delimiter =
begin + prefix.size();
72 if (delimiter >=
source.size() || (
source[delimiter] !=
',' &&
source[delimiter] !=
')')) {
76 std::size_t
depth = 0;
86 begin += replacement.size();
90void removeSampledResource(std::string&
source, std::string_view base,
91 std::string_view replacement =
"vec4<f32>(1.0f)") {
92 const std::string
image = std::string(base) +
"_image";
93 const std::string
sampler = std::string(base) +
"_sampler";
94 replaceResourceCalls(
source,
"textureSampleLevel", image, replacement);
95 replaceResourceCalls(
source,
"textureSampleCompare", image,
"1.0f");
96 replaceResourceCalls(
source,
"textureSample", image, replacement);
97 eraseDeclaration(
source, image);
99 eraseKeepalive(
source, image);
105 return {sourceView(pbr_surface_vert_wgsl, pbr_surface_vert_wgsl_count),
106 sourceView(pbr_surface_frag_wgsl, pbr_surface_frag_wgsl_count)};
112 static constexpr std::array<std::string_view, 11> maps{
113 "map0",
"map1",
"map2",
"map3",
"map4",
"map5",
"map6",
"map7",
"map8",
"map9",
"map10"};
114 static constexpr std::array<std::string_view, 3> detailMaps{
"detailMap0",
"detailMap1",
"detailMap2"};
117 removeSampledResource(result.fragment, maps[
index]);
120 removeSampledResource(result.fragment, detailMaps[
index]);
123 coalesceSampler(result.fragment, maps[
index],
index,
127 coalesceSampler(result.fragment, detailMaps[
index],
133 removeSampledResource(result.fragment,
"vegetationFadeNoise",
134 "vec4<f32>(0.0f, 0.0f, 0.0f, 1.0f)");
136 replaceResourceCalls(result.fragment,
"textureNumLevels",
"environmentMap_image",
"1u");
137 removeSampledResource(result.fragment,
"environmentMap");
140 replaceResourceCalls(result.fragment,
"textureDimensions",
"shadowMap_image",
"vec2<u32>(1u)");
141 replaceResourceCalls(result.fragment,
"textureNumLayers",
"shadowMap_image",
"1u");
142 removeSampledResource(result.fragment,
"shadowMap",
"1.0f");
155 if (!device || !instance)
158 device.PushErrorScope(wgpu::ErrorFilter::Validation);
159 auto makeModule = [&](std::string_view
source) {
160 wgpu::ShaderSourceWGSL wgsl{};
161 wgsl.code =
source.data();
164 return device.CreateShaderModule(&
descriptor);
166 auto vertex = makeModule(sources.
vertex);
167 auto fragment = makeModule(sources.
fragment);
170 wgpu::ErrorType
error = wgpu::ErrorType::Unknown;
172 device.PopErrorScope(
173 wgpu::CallbackMode::AllowProcessEvents,
174 [&](wgpu::PopErrorScopeStatus
status, wgpu::ErrorType
type, wgpu::StringView
text) {
175 error =
status == wgpu::PopErrorScopeStatus::Success ?
type : wgpu::ErrorType::Unknown;
179 while (!done) wgpuInstanceProcessEvents(instance.Get());
180 if (!vertex || !fragment ||
error != wgpu::ErrorType::NoError)
183 message.empty() ?
"WebGPU rejected generated PBR WGSL" :
message));
189 if (!modules)
return modules;
191 device.PushErrorScope(wgpu::ErrorFilter::Validation);
192 auto makeModule = [&](std::string_view
source) {
193 wgpu::ShaderSourceWGSL wgsl{};
194 wgsl.code =
source.data();
195 wgpu::ShaderModuleDescriptor moduleDescriptor{};
196 moduleDescriptor.nextInChain = &wgsl;
197 return device.CreateShaderModule(&moduleDescriptor);
199 auto vertex = makeModule(sources.
vertex);
200 auto fragment = makeModule(sources.
fragment);
202 std::array<wgpu::VertexAttribute, 16> attributes{};
203 auto attribute = [&](std::size_t
index, wgpu::VertexFormat format, std::uint64_t
offset,
204 std::uint32_t location) {
205 attributes[
index].format = format;
207 attributes[
index].shaderLocation = location;
209 attribute(0, wgpu::VertexFormat::Float32x3, 0, 0);
210 attribute(1, wgpu::VertexFormat::Float32x3, 12, 1);
211 attribute(2, wgpu::VertexFormat::Float32x2, 24, 2);
212 attribute(3, wgpu::VertexFormat::Uint16x4, 32, 3);
213 attribute(4, wgpu::VertexFormat::Float32x4, 40, 4);
215 attribute(
index + 5, wgpu::VertexFormat::Float32x2, std::uint64_t(
index) * 8u,
index + 5);
216 std::array<wgpu::VertexBufferLayout, 2> buffers{};
217 buffers[0].arrayStride = 56;
218 buffers[0].attributeCount = 5;
219 buffers[0].attributes = attributes.data();
220 buffers[1].arrayStride = 88;
221 buffers[1].attributeCount = 11;
222 buffers[1].attributes = attributes.data() + 5;
224 wgpu::ColorTargetState
target{};
225 target.format = wgpu::TextureFormat::RGBA8Unorm;
226 wgpu::FragmentState fragmentState{};
227 fragmentState.module = fragment;
228 fragmentState.entryPoint =
"main";
229 fragmentState.targetCount = 1;
230 fragmentState.targets = &
target;
234 descriptor.vertex.bufferCount = buffers.size();
237 descriptor.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
239 auto pipeline = device.CreateRenderPipeline(&
descriptor);
242 wgpu::ErrorType
error = wgpu::ErrorType::Unknown;
244 device.PopErrorScope(
245 wgpu::CallbackMode::AllowProcessEvents,
246 [&](wgpu::PopErrorScopeStatus
status, wgpu::ErrorType
type, wgpu::StringView
text) {
247 error =
status == wgpu::PopErrorScopeStatus::Success ?
type : wgpu::ErrorType::Unknown;
251 while (!done) wgpuInstanceProcessEvents(instance.Get());
252 if (!pipeline ||
error != wgpu::ErrorType::NoError)
vk::UniqueSampler sampler
wgpu::PopErrorScopeStatus status
HexCoordinates to
Cell the unit walks towards on this segment.
std::array< float, 3 > position
MigrationFunction function
const UnitySourceAsset & source
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.
Move-only operation result carrying either a value or Status.
static Result success(T value)
Construct a successful result owning value.
static Result failure(Status status)
Construct a failed result from a structured status.
Result< void > debugValidatePbrVariantBaseSources()
Compile the generated full PBR WGSL stages under a validation scope.
Result< void > debugValidatePbrVariantSources(const PbrVariantSources &sources)
Compile caller-provided PBR WGSL stages under a validation scope.
Result< void > debugValidatePbrVariantPipeline(const PbrVariantSources &sources)
Compile and link a specialized PBR pair through a real Dawn render pipeline.
PbrVariantSources pbrVariantBaseSources()
Return immutable full PBR WGSL generated from the canonical GLSL implementation.
PbrSpecializedSources specializePbrVariantSources(const PbrVariantPlan &plan)
Specialize the generated WGSL for the resource reachability encoded by a checked plan.
Owning WGSL stages after unreachable texture operations and declarations are removed.
Stable resource-layout key and checked stage counts for a PBR snapshot.
static constexpr std::uint32_t NoSampler
std::uint32_t detailTextureMask
std::uint32_t vertexFlags
std::array< std::uint32_t, 11 > canonicalSamplerRepresentatives
std::array< std::uint32_t, 3 > detailSamplerRepresentatives
std::uint32_t fragmentFlags
std::uint32_t canonicalTextureMask
Reproducibly generated full PBR WGSL sources before resource specialization.
std::string_view fragment