1#include "PipelineStatesWebGPU.h"
3#include "GraphicsDeviceWebGPU.h"
5#include "Foundation/Logging/Logger.h"
10 WGPUBlendOperation wgpu(Cogs::BlendState::BlendOperation opp)
12 if(opp == Cogs::BlendState::BlendOperation::Add)
13 return WGPUBlendOperation_Add;
14 if(opp == Cogs::BlendState::BlendOperation::Subtract)
15 return WGPUBlendOperation_Subtract;
16 if(opp == Cogs::BlendState::BlendOperation::ReverseSubtract)
17 return WGPUBlendOperation_ReverseSubtract;
18 if(opp == Cogs::BlendState::BlendOperation::Min)
19 return WGPUBlendOperation_Min;
20 if(opp == Cogs::BlendState::BlendOperation::Max)
21 return WGPUBlendOperation_Max;
23 return WGPUBlendOperation_Add;
28 if(blend == Cogs::BlendState::Blend::Zero)
29 return WGPUBlendFactor_Zero;
30 if(blend == Cogs::BlendState::Blend::One)
31 return WGPUBlendFactor_One;
32 if(blend == Cogs::BlendState::Blend::SourceColor)
33 return WGPUBlendFactor_Src;
34 if(blend == Cogs::BlendState::Blend::InverseSourceColor)
35 return WGPUBlendFactor_OneMinusSrc;
36 if(blend == Cogs::BlendState::Blend::SourceAlpha)
37 return WGPUBlendFactor_SrcAlpha;
38 if(blend == Cogs::BlendState::Blend::InverseSourceAlpha)
39 return WGPUBlendFactor_OneMinusSrcAlpha;
40 if(blend == Cogs::BlendState::Blend::DestinationAlpha)
41 return WGPUBlendFactor_DstAlpha;
42 if(blend == Cogs::BlendState::Blend::InverseDestinationAlpha)
43 return WGPUBlendFactor_OneMinusDstAlpha;
44 if(blend == Cogs::BlendState::Blend::DestinationColor)
45 return WGPUBlendFactor_Dst;
46 if(blend == Cogs::BlendState::Blend::InverseDestinationColor)
47 return WGPUBlendFactor_OneMinusDst;
48 if(blend == Cogs::BlendState::Blend::SourceAlphaSaturate)
49 return WGPUBlendFactor_SrcAlphaSaturated;
50 if(blend == Cogs::BlendState::Blend::BlendFactor)
51 return WGPUBlendFactor_Constant;
52 if(blend == Cogs::BlendState::Blend::InverseBlendFactor)
53 return WGPUBlendFactor_OneMinusConstant;
55 return WGPUBlendFactor_Zero;
61 void PipelineStatesWebGPU::initialize(GraphicsDeviceWebGPU *device)
63 graphics_device = device;
66 size_t PipelineStatesWebGPU::renderPipelineHash(EffectHandle effectHandle,
67 InputLayoutHandle inputLayoutHandle,
69 RasterizerStateHandle rasterizeStateHandle,
70 DepthStencilStateHandle depthStencilStateHandle,
71 BlendStateHandle blendStateHandle,
72 RenderTargetHandle renderTargetHandle,
73 DepthStencilHandle depthStencilHandle,
74 WGPUIndexFormat stripIndexFormat)
76 EffectsWebGPU &effects = graphics_device->effects;
77 BuffersWebGPU &buffers = graphics_device->buffers;
78 RenderTargetsWebGPU &render_targets = graphics_device->renderTargets;
82 EffectWebGPU& effect = effects.effects[effectHandle];
83 pso_hash = effect.hash(pso_hash);
86 InputLayoutWebGPU& layout = buffers.inputLayouts[inputLayoutHandle];
87 pso_hash = layout.hash(pso_hash);
89 pso_hash =
Cogs::hash(primitiveType, pso_hash);
90 pso_hash =
Cogs::hash(rasterizeStateHandle.handle, pso_hash);
91 pso_hash =
Cogs::hash(depthStencilStateHandle.handle, pso_hash);
92 pso_hash =
Cogs::hash(blendStateHandle.handle, pso_hash);
94 RenderTargetWebGPU& render_target = render_targets.render_targets[renderTargetHandle];
95 pso_hash = render_target.hash(pso_hash);
98 DepthStencilTargetWebGPU& depth_target = render_targets.depth_stencil_targets[depthStencilHandle];
99 pso_hash = depth_target.hash(pso_hash);
101 pso_hash =
Cogs::hash(
static_cast<int>(stripIndexFormat), pso_hash);
104 RenderPipelineHandle PipelineStatesWebGPU::loadRenderPipeline(EffectHandle effectHandle,
105 InputLayoutHandle inputLayoutHandle,
107 RasterizerStateHandle rasterizeStateHandle,
108 DepthStencilStateHandle depthStencilStateHandle,
109 BlendStateHandle blendStateHandle,
110 RenderTargetHandle renderTargetHandle,
111 DepthStencilHandle depthStencilHandle,
112 WGPUIndexFormat stripIndexFormat)
114 WGPUDevice device = graphics_device->device;
115 BuffersWebGPU &buffers = graphics_device->buffers;
116 ResourceCountersWebGPU &counters = graphics_device->counters;
117 RenderTargetsWebGPU &renderTargets = graphics_device->renderTargets;
119 size_t pso_hash = renderPipelineHash(effectHandle,
122 rasterizeStateHandle,
123 depthStencilStateHandle,
128 auto iter = renderPipelineHashMap.find(pso_hash);
129 if(iter != renderPipelineHashMap.end()){
133 EffectWebGPU &effect = graphics_device->effects.effects[effectHandle];
134 const RasterizerState &rs =
135 rasterizeStateHandle ?
136 *
reinterpret_cast<RasterizerState*
>(rasterizeStateHandle.handle):
142 const DepthStencilState &ds =
143 depthStencilStateHandle ?
144 *
reinterpret_cast<DepthStencilState*
>(depthStencilStateHandle.handle) :
146 const BlendState &bsc =
148 reinterpret_cast<BlendState*
>(blendStateHandle.handle)[0] :
150 const BlendState &bsa =
152 reinterpret_cast<BlendState*
>(blendStateHandle.handle)[1] :
155 LOG_INFO(logger,
"PipelineStateLoad %s", effect.name.c_str());
157 WGPURenderPipelineDescriptor desc = WGPU_RENDER_PIPELINE_DESCRIPTOR_INIT;
158 desc.label = {effect.name.c_str(), WGPU_STRLEN};
159 desc.layout =
nullptr;
160 WGPUPipelineLayout pipeline_layout;
161 WGPUBindGroupLayout bind_group_layout;
163 WGPUBindGroupLayoutEntry layoutEntryList[EffectWebGPU::maxConstantBuffers];
164 size_t numConstantBufferBindings = 0;
165 const WebGPUConstantBufferBinding* bindings;
166 bindings = graphics_device->effects.getConstantBufferBindings(effectHandle, numConstantBufferBindings);
167 for (
size_t i = 0; i < numConstantBufferBindings; i++) {
168 assert(bindings[i].group == 0);
169 layoutEntryList[i] = bindings[i].bg_ent;
171 WGPUBindGroupLayoutDescriptor bind_group_layout_desc = WGPU_BIND_GROUP_LAYOUT_DESCRIPTOR_INIT;
172 bind_group_layout_desc.label = {effect.name.c_str(), WGPU_STRLEN};
173 bind_group_layout_desc.entryCount = numConstantBufferBindings;
174 bind_group_layout_desc.entries = layoutEntryList;
175 bind_group_layout = wgpuDeviceCreateBindGroupLayout(device, &bind_group_layout_desc);
176 counters.bind_group_layout++;
178 WGPUPipelineLayoutDescriptor pipeline_layout_desc = WGPU_PIPELINE_LAYOUT_DESCRIPTOR_INIT;
179 pipeline_layout_desc.bindGroupLayoutCount = 1;
180 pipeline_layout_desc.bindGroupLayouts = &bind_group_layout;
181 pipeline_layout = wgpuDeviceCreatePipelineLayout(device, &pipeline_layout_desc);
182 counters.pipeline_layout++;
183 desc.label = {effect.name.c_str(), WGPU_STRLEN};
184 desc.layout = pipeline_layout;
187 WGPUPrimitiveState &primitive_state = desc.primitive;
191 primitive_state.topology = WGPUPrimitiveTopology_PointList;
192 primitive_state.stripIndexFormat = WGPUIndexFormat_Undefined;
195 primitive_state.topology = WGPUPrimitiveTopology_LineList;
196 primitive_state.stripIndexFormat = WGPUIndexFormat_Undefined;
199 primitive_state.topology = WGPUPrimitiveTopology_LineStrip;
200 primitive_state.stripIndexFormat = stripIndexFormat != WGPUIndexFormat_Undefined ? stripIndexFormat : WGPUIndexFormat_Uint32;
203 primitive_state.topology = WGPUPrimitiveTopology_TriangleList;
204 primitive_state.stripIndexFormat = WGPUIndexFormat_Undefined;
207 primitive_state.topology = WGPUPrimitiveTopology_TriangleStrip;
208 primitive_state.stripIndexFormat = stripIndexFormat != WGPUIndexFormat_Undefined ? stripIndexFormat : WGPUIndexFormat_Uint32;
214 if(rs.frontCounterClockwise)
215 primitive_state.frontFace = WGPUFrontFace_CCW;
217 primitive_state.frontFace = WGPUFrontFace_CW;
219 primitive_state.cullMode = WGPUCullMode_Front;
221 primitive_state.cullMode = WGPUCullMode_Back;
223 primitive_state.cullMode = WGPUCullMode_None;
226 WGPUVertexState &vertex_state = desc.vertex;
228 vertex_state.module = effect.vs_module;
229 vertex_state.entryPoint = {effect.vs_entry.c_str(), WGPU_STRLEN};
230 vertex_state.constantCount = 0;
231 vertex_state.constants =
nullptr;
233 InputLayoutWebGPU& layout = buffers.inputLayouts[inputLayoutHandle];
234 vertex_state.bufferCount = (uint32_t)layout.vertex_buffer_layout.size();
235 vertex_state.buffers = layout.vertex_buffer_layout.data();
241 uint32_t samples = 0;
242 WGPUDepthStencilState depthStencil = WGPU_DEPTH_STENCIL_STATE_INIT;
245 SwapChainWebGPU &defaultSwapChain = graphics_device->defaultSwapChain;
246 depthStencil.format = defaultSwapChain.depth_format;
247 samples = defaultSwapChain.samples;
250 DepthStencilTargetWebGPU &dst = renderTargets.depth_stencil_targets[depthStencilHandle];
251 depthStencil.format = dst.format;
252 samples = dst.samples;
256 depthStencil.depthWriteEnabled =
static_cast<WGPUOptionalBool
>(ds.writeEnabled);
259 depthStencil.depthCompare = WGPUCompareFunction_Never;
261 depthStencil.depthCompare = WGPUCompareFunction_Less;
263 depthStencil.depthCompare = WGPUCompareFunction_LessEqual;
265 depthStencil.depthCompare = WGPUCompareFunction_Equal;
267 depthStencil.depthCompare = WGPUCompareFunction_GreaterEqual;
269 depthStencil.depthCompare = WGPUCompareFunction_Greater;
271 depthStencil.depthCompare = WGPUCompareFunction_NotEqual;
273 depthStencil.depthCompare = WGPUCompareFunction_Always;
278 depthStencil.depthWriteEnabled = WGPUOptionalBool(
false);
279 depthStencil.depthCompare = WGPUCompareFunction_Always;
282 depthStencil.stencilFront.compare = WGPUCompareFunction_Always;
283 depthStencil.stencilFront.failOp = WGPUStencilOperation_Keep;
284 depthStencil.stencilFront.depthFailOp = WGPUStencilOperation_Keep;
285 depthStencil.stencilFront.passOp = WGPUStencilOperation_Keep;
287 depthStencil.stencilBack.compare = WGPUCompareFunction_Always;
288 depthStencil.stencilBack.failOp = WGPUStencilOperation_Keep;
289 depthStencil.stencilBack.depthFailOp = WGPUStencilOperation_Keep;
290 depthStencil.stencilBack.passOp = WGPUStencilOperation_Keep;
292 depthStencil.stencilReadMask = 0;
293 depthStencil.stencilWriteMask = 0;
295 depthStencil.depthBias = (int32_t)rs.depthBias;
296 depthStencil.depthBiasSlopeScale = rs.slopeScaledDepthBias;
297 depthStencil.depthBiasClamp = rs.depthBiasClamp;
302 if(depthStencil.depthBias != 0){
303 depthStencil.depthBias = 0;
304 LOG_INFO_ONCE(logger,
"Setting depthBias to 0 for points and lines (%s).", effect.name.c_str());
306 if(depthStencil.depthBiasSlopeScale != 0.0f){
307 depthStencil.depthBiasSlopeScale = 0.0f;
308 LOG_INFO_ONCE(logger,
"Setting depthBiasSlopeScale to 0.0 for points and lines (%s).", effect.name.c_str());
310 if(depthStencil.depthBiasClamp != 0.0f){
311 depthStencil.depthBiasClamp = 0.0f;
312 LOG_INFO_ONCE(logger,
"Setting depthBiasClamp to 0.0 for points and lines (%s).", effect.name.c_str());
316 desc.depthStencil = &depthStencil;
319 WGPUColorTargetState color_target[8] = {};
320 for(uint32_t i=0; i<
sizeof(color_target)/
sizeof(color_target[0]); i++){
321 color_target[i] = WGPU_COLOR_TARGET_STATE_INIT;
323 uint32_t color_target_count = 0;
325 RenderTargetWebGPU &rt = renderTargets.render_targets[renderTargetHandle];
326 samples = glm::max(rt.samples, samples);
327 color_target_count = rt.count;
328 for(uint32_t i=0; i<rt.count; i++){
329 color_target[i].format = rt.format[i];
330 color_target[i].writeMask = WGPUColorWriteMask_All;
333 else if(use_swap_chain){
334 SwapChainWebGPU &defaultSwapChain = graphics_device->defaultSwapChain;
335 color_target_count = 1;
336 color_target[0].format = defaultSwapChain.color_format;
337 color_target[0].writeMask = WGPUColorWriteMask_All;
340 WGPUBlendState blend_state = WGPU_BLEND_STATE_INIT;
341 if(bsc.enabled || bsa.enabled){
343 blend_state.color.operation = wgpu(bsc.operation);
344 blend_state.color.srcFactor = wgpu(bsc.sourceBlend);
345 blend_state.color.dstFactor = wgpu(bsc.destinationBlend);
346 blend_state.alpha.operation = wgpu(bsa.operation);
347 blend_state.alpha.srcFactor = wgpu(bsa.sourceBlend);
348 blend_state.alpha.dstFactor = wgpu(bsa.destinationBlend);
349 for(uint32_t i=0; i<color_target_count; i++){
350 color_target[i].blend = &blend_state;
354 WGPUFragmentState fragment = WGPU_FRAGMENT_STATE_INIT;
355 if(effect.fs_module){
356 fragment.module = effect.fs_module;
357 fragment.entryPoint = {effect.fs_entry.c_str(), WGPU_STRLEN};
358 fragment.constantCount = 0;
359 fragment.constants =
nullptr;
360 if(color_target_count > 0){
361 fragment.targetCount = color_target_count;
362 fragment.targets = color_target;
364 desc.fragment = &fragment;
367 WGPUMultisampleState &multisample = desc.multisample;
370 multisample.count = samples > 1 ? 4 : 1;
371 multisample.mask = ~0x00000000u;
372 multisample.alphaToCoverageEnabled =
false;
375 WGPURenderPipeline pipeline = wgpuDeviceCreateRenderPipeline(device, &desc);
376 counters.render_pipeline++;
379 RenderPipelineWebGPU pipelineState = {};
380 pipelineState.hash = pso_hash;
381 pipelineState.effect = effectHandle;
382 pipelineState.inputLayoutHandle = inputLayoutHandle;
383 pipelineState.primitiveType = primitiveType;
384 pipelineState.rasterizeStateHandle = rasterizeStateHandle;
385 pipelineState.depthStencilStateHandle = depthStencilStateHandle;
386 pipelineState.blendStateHandle = blendStateHandle;
387 pipelineState.renderTargetHandle = renderTargetHandle;
388 pipelineState.depthStencilHandle = depthStencilHandle;
390 pipelineState.pipeline = pipeline;
391 pipelineState.pipeline_layout = pipeline_layout;
392 pipelineState.bind_group_layout = bind_group_layout;
394 auto handle = this->renderPipeline.addResource(std::move(pipelineState));
395 renderPipelineHashMap.insert({pso_hash, handle});
399 ComputePipelineHandle PipelineStatesWebGPU::loadComputePipeline(EffectHandle effectHandle)
401 WGPUDevice device = graphics_device->device;
404 pso_hash =
Cogs::hash(effectHandle.handle, pso_hash);
405 auto iter = computePipelineHashMap.find(pso_hash);
406 if(iter != computePipelineHashMap.end()){
410 ResourceCountersWebGPU &counters = graphics_device->counters;
411 EffectWebGPU &effect = graphics_device->effects.effects[effectHandle];
413 LOG_INFO(logger,
"PipelineStateLoad %s", effect.name.c_str());
415 WGPUComputePipelineDescriptor desc = WGPU_COMPUTE_PIPELINE_DESCRIPTOR_INIT;
416 desc.label = {effect.name.c_str(), WGPU_STRLEN};
417 desc.layout =
nullptr;
418 WGPUComputeState &compute = desc.compute;
419 compute.module = effect.cs_module;
420 compute.entryPoint = {effect.cs_entry.c_str(), WGPU_STRLEN};
421 compute.constantCount = 0;
422 compute.constants =
nullptr;
423 WGPUComputePipeline pipeline = wgpuDeviceCreateComputePipeline(device, &desc);
424 counters.compute_pipeline++;
427 uint32_t groupIndex = 0;
428 WGPUBindGroupLayout layout = wgpuComputePipelineGetBindGroupLayout(pipeline, groupIndex);
431 ComputePipelineWebGPU pipelineState = {};
432 pipelineState.hash = pso_hash;
433 pipelineState.effect = effectHandle;
435 pipelineState.pipeline = pipeline;
436 pipelineState.layout = layout;
438 auto handle = this->computePipeline.addResource(std::move(pipelineState));
439 computePipelineHashMap.insert({pso_hash, handle});
443 void PipelineStatesWebGPU::releaseRenderPipeline(RenderPipelineHandle handle)
445 RenderPipelineWebGPU &pipeline = renderPipeline[handle];
447 wgpuRenderPipelineRelease(pipeline.pipeline);
448 wgpuPipelineLayoutRelease(pipeline.pipeline_layout);
449 wgpuBindGroupLayoutRelease(pipeline.bind_group_layout);
451 size_t hash = pipeline.hash;
452 renderPipelineHashMap.erase(
hash);
453 renderPipeline.removeResource(handle);
456 void PipelineStatesWebGPU::releaseComputePipeline(ComputePipelineHandle handle)
458 ComputePipelineWebGPU &pipeline = computePipeline[handle];
460 wgpuComputePipelineRelease(pipeline.pipeline);
462 size_t hash = pipeline.hash;
463 computePipelineHashMap.erase(
hash);
464 computePipeline.removeResource(handle);
467 void PipelineStatesWebGPU::releaseResources()
469 std::vector<RenderPipelineHandle> renderPipelineHandles;
470 renderPipelineHandles.reserve(renderPipelineHashMap.size());
471 for(
auto &tmp : renderPipelineHashMap){
472 renderPipelineHandles.push_back(tmp.second);
474 for(
auto &tmp : renderPipelineHandles){
475 releaseRenderPipeline(tmp);
478 std::vector<ComputePipelineHandle> computePipelineHandles;
479 computePipelineHandles.reserve(computePipelineHashMap.size());
480 for(
auto &tmp : computePipelineHashMap){
481 computePipelineHandles.push_back(tmp.second);
483 for(
auto &tmp : computePipelineHandles){
484 releaseComputePipeline(tmp);
Log implementation class.
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Contains all Cogs related functionality.
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
PrimitiveType
Primitive types for interpreting vertex data sent to the graphics pipeline.
@ PointList
List of points.
@ TriangleStrip
Triangle strip.
@ TriangleListAdjacency
List of triangles with adjacency.
@ TriangleList
List of triangles.
static BlendState DefaultState()
Creates a blend state object initialized with the default settings.
Blend
Options for blend functions.
@ Never
Never evaluates to true. When using this, all objects will fail depth testing.
@ GreaterOrEqual
Greater or equal depth.
@ NotEqual
Depth not equal evaluates to true.
@ Always
Always evaluates to true.
@ LessOrEqual
Less or equal depth.
static DepthStencilState DefaultState()
Constructs a depth stencil state object initialized with the default values.
static RasterizerState DefaultState()
Constructs a rasterizer state initialized with the default values.
@ Back
Cull back facing primitives.
@ Front
Cull front facing primitives.