1#include "ContextWebGPU.h"
3#include "GraphicsDeviceWebGPU.h"
4#include "PipelineStatesWebGPU.h"
5#include "Foundation/Logging/Logger.h"
10 void context_error_callback(WGPUPopErrorScopeStatus status, WGPUErrorType type, WGPUStringView message,
void* userdata1,
void* userdata2)
16 if(status == WGPUPopErrorScopeStatus_CallbackCancelled){
17 LOG_ERROR(logger,
"WebGPU context err status: Cancelled");
19 if(status == WGPUPopErrorScopeStatus_Error){
20 LOG_ERROR(logger,
"WebGPU context err status: Error");
22 if(message.data && message.length){
23 LOG_ERROR(logger,
"WebGPU context err (%d) %.*s", type, WGPUStringViewFormat(message));
27 WGPULoadOp ConvWebGPULoadOp(Cogs::LoadOp load_op)
30 case Cogs::LoadOp::Undefined:
return WGPULoadOp_Undefined;
31 case Cogs::LoadOp::Clear:
return WGPULoadOp_Clear;
32 case Cogs::LoadOp::Load:
return WGPULoadOp_Load;
34 return WGPULoadOp_Undefined;
36 WGPUStoreOp ConvWebGPUStoreOp(Cogs::StoreOp store_op)
39 case Cogs::StoreOp::Undefined:
return WGPUStoreOp_Undefined;
40 case Cogs::StoreOp::Store:
return WGPUStoreOp_Store;
41 case Cogs::StoreOp::Discard:
return WGPUStoreOp_Discard;
43 return WGPUStoreOp_Undefined;
46 void decodeConstantBufferBindingHandle(int64_t handle,
size_t &group, uint32_t &binding) {
49 binding = (i & 0xFFFF) - 1;
56 void ContextWebGPU::initialize(GraphicsDeviceWebGPU *graphicsDeviceIn)
58 graphicsDevice = graphicsDeviceIn;
68 assert(!inRenderPass);
69 for(
size_t i=0; i<
sizeof(clearColor)/
sizeof(clearColor[0]); i++){
70 clearColor[i].r = value[0];
71 clearColor[i].g = value[1];
72 clearColor[i].b = value[2];
73 clearColor[i].a = value[3];
75 do_clear_render_target =
true;
76 update_render_target =
true;
81 assert(!inRenderPass);
82 for(
int i=0; i<numvalues; i++){
83 clearColor[i].r = values[i][0];
84 clearColor[i].g = values[i][1];
85 clearColor[i].b = values[i][2];
86 clearColor[i].a = values[i][3];
88 for(
size_t i=numvalues; i<
sizeof(clearColor)/
sizeof(clearColor[0]); i++){
89 clearColor[i] = WGPU_COLOR_INIT;
91 do_clear_render_target =
true;
92 update_render_target =
true;
97 assert(!inRenderPass);
98 clearDepthVal = depth;
99 do_clear_depth =
true;
100 update_render_target =
true;
153 WGPUStringView label = {name.
data(), name.
length()};
154 if(renderPassEncoder != 0){
155 wgpuRenderPassEncoderInsertDebugMarker(renderPassEncoder, label);
157 else if(computePassEncoder != 0){
158 wgpuComputePassEncoderInsertDebugMarker(computePassEncoder, label);
164 wgpuCommandEncoderInsertDebugMarker(graphicsDevice->commandEncoder, label);
170 assert(renderPassEncoder == 0);
171 assert(computePassEncoder == 0);
172 assert(!inRenderPass);
174 update_render_target =
false;
176 renderTargetHandle = info.renderTargetHandle;
177 depthStencilHandle = info.depthStencilHandle;
179 WGPURenderPassColorAttachment color_attachment[8] = {};
180 WGPURenderPassDepthStencilAttachment ds_attachment = WGPU_RENDER_PASS_DEPTH_STENCIL_ATTACHMENT_INIT;
181 uint32_t color_attachment_count = 0;
182 uint32_t ds_attachment_count = 0;
184 const char *name =
nullptr;
185 if (HandleIsValid(info.renderTargetHandle) || HandleIsValid(info.depthStencilHandle)) {
186 name =
"Custom Render Pass";
187 if(HandleIsValid(info.renderTargetHandle)){
188 RenderTargetWebGPU &target = graphicsDevice->renderTargets.render_targets[info.renderTargetHandle];
189 for(
size_t i=0; i<target.count; i++){
190 WGPURenderPassColorAttachment &att = color_attachment[i];
191 att.view = target.view[i];
192 att.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED;
193 if(info.resolveHandle[i]){
194 att.resolveTarget = graphicsDevice->textures.textureViews[info.resolveHandle[i]].texture_view;
197 att.resolveTarget =
nullptr;
199 att.loadOp = ConvWebGPULoadOp(info.loadOp[i]);
200 att.storeOp = ConvWebGPUStoreOp(info.storeOp[i]);
201 att.clearValue.r = info.clearValue[i][0];
202 att.clearValue.g = info.clearValue[i][1];
203 att.clearValue.b = info.clearValue[i][2];
204 att.clearValue.a = info.clearValue[i][3];
206 color_attachment_count = target.count;
208 if(HandleIsValid(info.depthStencilHandle)){
210 WGPURenderPassDepthStencilAttachment &att = ds_attachment;
211 att.view = target.view;
212 att.depthLoadOp = ConvWebGPULoadOp(info.depthLoadOp);
213 att.depthStoreOp = ConvWebGPUStoreOp(info.depthStoreOp);
214 att.depthClearValue = info.depthClearValue;
215 att.depthReadOnly = info.depthReadOnly;
216 att.stencilLoadOp = WGPULoadOp_Undefined;
217 att.stencilStoreOp = WGPUStoreOp_Undefined;
218 att.stencilClearValue = 0;
219 att.stencilReadOnly =
false;
220 ds_attachment_count = 1;
224 name =
"Default Render Pass";
226 if(defaultSwapChain.samples > 1){
227 color_attachment[0].view = defaultSwapChain.colorBufferView;
228 color_attachment[0].resolveTarget = defaultSwapChain.resolveView;
231 color_attachment[0].view = defaultSwapChain.resolveView;
233 color_attachment[0].depthSlice = WGPU_DEPTH_SLICE_UNDEFINED;
234 color_attachment[0].loadOp = ConvWebGPULoadOp(info.loadOp[0]);
235 color_attachment[0].storeOp = ConvWebGPUStoreOp(info.storeOp[0]);
236 color_attachment[0].clearValue.r = info.clearValue[0][0];
237 color_attachment[0].clearValue.g = info.clearValue[0][1];
238 color_attachment[0].clearValue.b = info.clearValue[0][2];
239 color_attachment[0].clearValue.a = info.clearValue[0][3];
240 color_attachment_count = 1;
242 ds_attachment.view = defaultSwapChain.depthBufferView;
243 ds_attachment.depthLoadOp = ConvWebGPULoadOp(info.depthLoadOp);
244 ds_attachment.depthStoreOp = ConvWebGPUStoreOp(info.depthStoreOp);
245 ds_attachment.depthClearValue = info.depthClearValue;
246 ds_attachment.depthReadOnly = info.depthReadOnly;
247 ds_attachment.stencilLoadOp = WGPULoadOp_Undefined;
248 ds_attachment.stencilStoreOp = WGPUStoreOp_Undefined;
249 ds_attachment.stencilClearValue = 0;
250 ds_attachment.stencilReadOnly =
false;
251 ds_attachment_count = 1;
254 if(graphicsDevice->use_error_scope){
255 wgpuDevicePushErrorScope(graphicsDevice->device, graphicsDevice->filter);
258 WGPURenderPassDescriptor render_pass_desc = WGPU_RENDER_PASS_DESCRIPTOR_INIT;
259 render_pass_desc.label = {name, WGPU_STRLEN};
260 if(color_attachment_count){
261 render_pass_desc.colorAttachmentCount = color_attachment_count;
262 render_pass_desc.colorAttachments = color_attachment;
264 if(ds_attachment_count){
265 render_pass_desc.depthStencilAttachment = &ds_attachment;
267 render_pass_desc.occlusionQuerySet =
nullptr;
269 render_pass_desc.timestampWrites =
nullptr;
270 renderPassEncoder = wgpuCommandEncoderBeginRenderPass(graphicsDevice->commandEncoder, &render_pass_desc);
274 assert(renderPassEncoder);
275 assert(inRenderPass);
276 inRenderPass =
false;
277 wgpuRenderPassEncoderEnd(renderPassEncoder);
278 wgpuRenderPassEncoderRelease(renderPassEncoder);
279 renderPassEncoder = 0;
280 update_render_target =
true;
282 if(graphicsDevice->use_error_scope){
283 WGPUPopErrorScopeCallbackInfo info = WGPU_POP_ERROR_SCOPE_CALLBACK_INFO_INIT;
284 info.mode = WGPUCallbackMode_AllowSpontaneous;
285 info.callback = context_error_callback;
286 info.userdata1 =
this;
287 info.userdata2 = graphicsDevice;
288 WGPUFuture future = wgpuDevicePopErrorScope(graphicsDevice->device, info);
295 if(HandleIsValid(rt_handle))
296 renderTargetHandle = rt_handle;
298 renderTargetHandle = {};
299 if(HandleIsValid(ds_handle))
300 depthStencilHandle = ds_handle;
302 depthStencilHandle = {};
303 rasterizeStateHandle = {};
304 blendStateHandle = {};
305 assert(do_clear_render_target ==
false);
306 assert(do_clear_depth ==
false);
307 do_clear_render_target =
false;
308 do_clear_depth =
false;
309 update_render_target =
true;
315 float minDepth = 0.0f;
316 float maxDepth = 1.0f;
317 wgpuRenderPassEncoderSetViewport(renderPassEncoder, x, y, width, height, minDepth, maxDepth);
325 int xx = glm::clamp(x, 0, w);
326 int yy = glm::clamp(y, 0, h);
327 int ww = glm::clamp(width, 0, w-xx);
328 int hh = glm::clamp(height, 0, h-yy);
329 wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, xx, yy, ww, hh);
334 if(HandleIsValid(handle))
335 depthStencilStateHandle = handle;
337 depthStencilStateHandle = {};
343 if(HandleIsValid(handle))
344 blendStateHandle = handle;
346 blendStateHandle = {};
349 color.r = constants[0];
350 color.g = constants[1];
351 color.b = constants[2];
352 color.a = constants[3];
360 wgpuRenderPassEncoderSetBlendConstant(renderPassEncoder, &color);
365 if(HandleIsValid(handle))
366 rasterizeStateHandle = handle;
368 rasterizeStateHandle = {};
371 void ContextWebGPU::setDefaults() {
372 rasterizeStateHandle = {};
373 depthStencilStateHandle = {};
374 blendStateHandle = {};
379 if(HandleIsValid(handle))
383 inputLayoutHandle = {};
385 update_descriptors =
true;
390 setTexture(getEffects()->getTextureBinding(getCurrentEffect(), name, unit), textureHandle);
397 if (!HandleIsValid(handle)) {
398 descriptors.erase((uint32_t)binding.
handle);
401 if (!HandleIsValid(binding)) {
404 TextureWebGPU texture = graphicsDevice->textures.textures[handle];
405 WGPUBindGroupEntry bg_ent = WGPU_BIND_GROUP_ENTRY_INIT;
406 size_t group = ~(size_t)0;
407 decodeConstantBufferBindingHandle(binding.
handle, group, bg_ent.binding);
409 bg_ent.buffer =
nullptr;
412 bg_ent.sampler =
nullptr;
413 bg_ent.textureView = texture.texture_view;
414 descriptors[bg_ent.binding] = bg_ent;
415 update_descriptors =
true;
420 setTexture(getEffects()->getTextureBinding(getCurrentEffect(), name, 1), textureViewHandle);
427 if (!HandleIsValid(handle)) {
428 descriptors.erase((uint32_t)binding.handle);
431 TextureViewWebGPU texture_view = graphicsDevice->textures.textureViews[handle];
432 WGPUBindGroupEntry bg_ent = WGPU_BIND_GROUP_ENTRY_INIT;
433 size_t group = ~(size_t)0;
434 decodeConstantBufferBindingHandle(binding.handle, group, bg_ent.binding);
436 bg_ent.buffer =
nullptr;
439 bg_ent.sampler =
nullptr;
440 bg_ent.textureView = texture_view.texture_view;
441 descriptors[bg_ent.binding] = bg_ent;
442 update_descriptors =
true;
447 setSamplerState(getEffects()->getSamplerStateBinding(getCurrentEffect(), name, unit), handle);
454 if (!HandleIsValid(handle)) {
455 descriptors.erase((uint32_t)binding.
handle);
458 if (!HandleIsValid(binding)) {
462 WGPUBindGroupEntry bg_ent = WGPU_BIND_GROUP_ENTRY_INIT;
463 size_t group = ~(size_t)0;
464 decodeConstantBufferBindingHandle(binding.
handle, group, bg_ent.binding);
466 bg_ent.buffer =
nullptr;
469 bg_ent.sampler = sampler.sampler;
470 bg_ent.textureView =
nullptr;
471 descriptors[bg_ent.binding] = bg_ent;
478 update_descriptors =
true;
483 if(HandleIsValid(handle))
484 inputLayoutHandle = handle;
486 inputLayoutHandle = {};
492 for(
size_t i=0; i<count; i++){
494 uint32_t slot = (uint32_t)i;
496 uint32_t offset = offsets ? offsets[i] : 0;
497 wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, slot, buffer.buffer, offset, buffer.size-offset);
512 WGPUIndexFormat format = (stride == 2) ? WGPUIndexFormat_Uint16 : WGPUIndexFormat_Uint32;
513 currentIndexFormat = format;
514 uint64_t offset = offset_in;
516 wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, buffer.buffer, format, offset, buffer.size);
526 setConstantBuffer(getEffects()->getConstantBufferBinding(getCurrentEffect(), name), bufferHandle, offset, size);
533 if (!HandleIsValid(handle)) {
534 descriptors.erase((uint32_t)binding.
handle);
537 if (!HandleIsValid(binding)) {
541 BufferWebGPU &buffer = graphicsDevice->buffers.buffers[handle];
542 WGPUBindGroupEntry bg_ent = WGPU_BIND_GROUP_ENTRY_INIT;
543 size_t group = ~(size_t)0;
544 decodeConstantBufferBindingHandle(binding.
handle, group, bg_ent.binding);
546 bg_ent.buffer = buffer.buffer;
547 bg_ent.offset = offset;
548 bg_ent.size = (size == ~0u) ? WGPU_WHOLE_SIZE : size;
549 bg_ent.sampler =
nullptr;
550 bg_ent.textureView =
nullptr;
551 descriptors[bg_ent.binding] = bg_ent;
552 update_descriptors =
true;
584 drawInstanced(primitiveType, startVertex, numVertexes, 0, 1);
590 if (updateRenderPipeline(primitiveType)) {
591 wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, (uint32_t)numIndexes, 1, (uint32_t)startIndex, (int32_t)startVertex, 0);
592 if (frameStatisticsEnabled) { frameStatisticsAccountDrawCall(numIndexes,
true); }
595 LOG_ERROR_ONCE(logger,
"skip drawIndexed(), updateRenderPipeline failed.");
602 if (updateRenderPipeline(primitiveType)) {
603 wgpuRenderPassEncoderDraw(renderPassEncoder, (uint32_t)numVertexes, (uint32_t)numInstances, (uint32_t)startVertex, (uint32_t)startInstance);
604 if (frameStatisticsEnabled) { frameStatisticsAccountDrawCall(numVertexes*numInstances,
false); }
607 LOG_ERROR_ONCE(logger,
"skip draw()/drawInstanced(), updateRenderPipeline failed.");
614 if (updateRenderPipeline(primitiveType)) {
615 wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, (uint32_t)numIndexes, (uint32_t)numInstances, (uint32_t)startIndex, 0, (uint32_t)startInstance);
616 if (frameStatisticsEnabled) { frameStatisticsAccountDrawCall(numIndexes*numInstances,
true); }
619 LOG_ERROR_ONCE(logger,
"skip drawInstancedIndexed(), updateRenderPipeline failed.");
623 void ContextWebGPU::beginRenderPassInt()
625 assert(renderPassEncoder == 0);
626 assert(computePassEncoder == 0);
627 WGPURenderPassColorAttachment color_attachment[8] = {};
628 WGPURenderPassDepthStencilAttachment ds_attachment = WGPU_RENDER_PASS_DEPTH_STENCIL_ATTACHMENT_INIT;
629 uint32_t color_attachment_count = 0;
630 uint32_t ds_attachment_count = 0;
632 WGPULoadOp loadOp = do_clear_render_target ? WGPULoadOp_Clear : WGPULoadOp_Load;
633 do_clear_render_target =
false;
634 WGPULoadOp depthLoadOp = do_clear_depth ? WGPULoadOp_Clear : WGPULoadOp_Load;
635 do_clear_depth =
false;
636 const char *name =
nullptr;
637 if (HandleIsValid(renderTargetHandle) || HandleIsValid(depthStencilHandle)) {
638 name =
"Custom Render Pass";
639 if(HandleIsValid(renderTargetHandle)){
640 RenderTargetWebGPU &target = graphicsDevice->renderTargets.render_targets[renderTargetHandle];
641 for(
size_t i=0; i<target.count; i++){
642 WGPURenderPassColorAttachment &att = color_attachment[i];
643 att.view = target.view[i];
644 att.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED;
645 att.resolveTarget =
nullptr;
647 att.storeOp = WGPUStoreOp_Store;
648 att.clearValue = clearColor[i];
650 color_attachment_count = target.count;
653 DepthStencilTargetWebGPU &target = graphicsDevice->renderTargets.depth_stencil_targets[depthStencilHandle];
654 WGPURenderPassDepthStencilAttachment &att = ds_attachment;
655 att.view = target.view;
656 att.depthLoadOp = depthLoadOp;
657 att.depthStoreOp = WGPUStoreOp_Store;
658 att.depthClearValue = clearDepthVal;
659 att.depthReadOnly =
false;
660 att.stencilLoadOp = WGPULoadOp_Undefined;
661 att.stencilStoreOp = WGPUStoreOp_Undefined;
662 att.stencilClearValue = 0;
663 att.stencilReadOnly =
false;
664 ds_attachment_count = 1;
668 name =
"Default Render Pass";
669 SwapChainWebGPU &defaultSwapChain = graphicsDevice->defaultSwapChain;
670 if(defaultSwapChain.samples > 1){
671 color_attachment[0].view = defaultSwapChain.colorBufferView;
672 color_attachment[0].resolveTarget = defaultSwapChain.resolveView;
675 color_attachment[0].view = defaultSwapChain.resolveView;
677 color_attachment[0].depthSlice = WGPU_DEPTH_SLICE_UNDEFINED;
678 color_attachment[0].loadOp = loadOp;
679 color_attachment[0].storeOp = WGPUStoreOp_Store;
680 color_attachment[0].clearValue = clearColor[0];
681 color_attachment_count = 1;
683 ds_attachment.view = defaultSwapChain.depthBufferView;
684 ds_attachment.depthLoadOp = depthLoadOp;
685 ds_attachment.depthStoreOp = WGPUStoreOp_Store;
686 ds_attachment.depthClearValue = clearDepthVal;
687 ds_attachment.depthReadOnly =
false;
688 ds_attachment.stencilLoadOp = WGPULoadOp_Undefined;
689 ds_attachment.stencilStoreOp = WGPUStoreOp_Undefined;
690 ds_attachment.stencilClearValue = 0;
691 ds_attachment.stencilReadOnly =
false;
692 ds_attachment_count = 1;
695 if(graphicsDevice->use_error_scope){
696 wgpuDevicePushErrorScope(graphicsDevice->device, graphicsDevice->filter);
699 WGPURenderPassDescriptor render_pass_desc = WGPU_RENDER_PASS_DESCRIPTOR_INIT;
700 render_pass_desc.label = {name, WGPU_STRLEN};
701 if(color_attachment_count){
702 render_pass_desc.colorAttachmentCount = color_attachment_count;
703 render_pass_desc.colorAttachments = color_attachment;
705 if(ds_attachment_count){
706 render_pass_desc.depthStencilAttachment = &ds_attachment;
708 render_pass_desc.occlusionQuerySet =
nullptr;
710 render_pass_desc.timestampWrites =
nullptr;
711 renderPassEncoder = wgpuCommandEncoderBeginRenderPass(graphicsDevice->commandEncoder, &render_pass_desc);
714 void ContextWebGPU::endRenderPassInt()
716 assert(!inRenderPass);
717 if(!renderPassEncoder)
return;
718 wgpuRenderPassEncoderEnd(renderPassEncoder);
719 wgpuRenderPassEncoderRelease(renderPassEncoder);
720 renderPassEncoder = 0;
721 update_render_target =
true;
722 current_bind_group = {};
723 update_descriptors =
true;
725 if(graphicsDevice->use_error_scope){
726 WGPUPopErrorScopeCallbackInfo info = WGPU_POP_ERROR_SCOPE_CALLBACK_INFO_INIT;
727 info.mode = WGPUCallbackMode_AllowSpontaneous;
728 info.callback = context_error_callback;
729 info.userdata1 =
this;
730 info.userdata2 = graphicsDevice;
731 WGPUFuture future = wgpuDevicePopErrorScope(graphicsDevice->device, info);
736 void ContextWebGPU::updateRenderPass()
738 if(update_render_target){
741 beginRenderPassInt();
742 update_render_target =
false;
746 bool ContextWebGPU::updateRenderPipeline(
PrimitiveType primitiveType)
748 assert(renderPassEncoder);
749 ResourceCountersWebGPU &counters = graphicsDevice->counters;
750 PipelineStatesWebGPU &pipeline_states = graphicsDevice->pipeline_states;
753 RenderPipelineWebGPU pipelineState = pipeline_states.renderPipeline[currentRenderPipeline];
754 size_t hash = pipeline_states.renderPipelineHash(effect,
757 rasterizeStateHandle,
758 depthStencilStateHandle,
763 if(
hash != pipelineState.hash) reload =
true;
769 RenderPipelineHandle pipelineStateHandle = pipeline_states.loadRenderPipeline
774 rasterizeStateHandle,
775 depthStencilStateHandle,
781 RenderPipelineWebGPU pipelineState = pipeline_states.renderPipeline[pipelineStateHandle];
782 currentRenderPipeline = pipelineStateHandle;
785 RenderPipelineWebGPU &pipelineState = pipeline_states.renderPipeline[currentRenderPipeline];
786 wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelineState.pipeline);
788 if(update_descriptors){
789 update_descriptors =
false;
790 RenderPipelineWebGPU &pipelineState = pipeline_states.renderPipeline[currentRenderPipeline];
792 std::vector<WGPUBindGroupEntry> entries;
793 entries.resize(descriptors.size());
795 for(
auto &tmp : descriptors){
796 entries[i++] = tmp.second;
798 descriptor_count += (uint32_t)descriptors.size();
802 auto bindings = getEffects()->getConstantBufferBindings(effect, num_bindings);
804 for (
size_t ii = 0; ii < num_bindings; ii++) {
806 for (
size_t j = 0; j < entries.size(); j++) {
807 if (bindings[ii].bg_ent.binding == entries[j].binding) {
812 LOG_ERROR_ONCE(logger,
"binding %d in layout but not set (%s)", bindings[ii].bg_ent.binding, bindings[ii].name.c_str());
816 for (
size_t j = 0; j < entries.size(); j++) {
818 for (
size_t ii = 0; ii < num_bindings; ii++) {
819 if (bindings[ii].bg_ent.binding == entries[j].binding) {
824 LOG_ERROR_ONCE(logger,
"binding %d is set but not in layout", entries[j].binding);
829 WGPUBindGroupDescriptor bg_desc = WGPU_BIND_GROUP_DESCRIPTOR_INIT;
831 bg_desc.layout = pipelineState.bind_group_layout;
832 bg_desc.entryCount = (uint32_t)entries.size();
833 bg_desc.entries = entries.data();
834 current_bind_group = wgpuDeviceCreateBindGroup(graphicsDevice->device, &bg_desc);
835 bind_groups.push_back(current_bind_group);
836 counters.bind_group++;
838 if(current_bind_group){
839 uint32_t groupIndex = 0;
840 wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, groupIndex, current_bind_group, 0,
nullptr);
848 updateComputePipeline();
849 wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, threadGroupsX, threadGroupsY, threadGroupsZ);
852 void ContextWebGPU::beginComputePass()
854 assert(renderPassEncoder == 0);
855 assert(computePassEncoder == 0);
856 WGPUComputePassDescriptor compute_pass_desc = WGPU_COMPUTE_PASS_DESCRIPTOR_INIT;
857 compute_pass_desc.label = {
"Compute Pass", WGPU_STRLEN};
859 compute_pass_desc.timestampWrites =
nullptr;
860 computePassEncoder = wgpuCommandEncoderBeginComputePass(graphicsDevice->commandEncoder, &compute_pass_desc);
863 void ContextWebGPU::endComputePass()
865 if(!computePassEncoder)
return;
866 wgpuComputePassEncoderEnd(computePassEncoder);
867 wgpuComputePassEncoderRelease(computePassEncoder);
868 computePassEncoder = 0;
871 void ContextWebGPU::updateComputePass()
873 if(!computePassEncoder){
876 update_render_target =
true;
880 void ContextWebGPU::updateComputePipeline()
882 assert(computePassEncoder);
883 ResourceCountersWebGPU &counters = graphicsDevice->counters;
884 PipelineStatesWebGPU &pipeline_states = graphicsDevice->pipeline_states;
887 ComputePipelineWebGPU pipelineState = pipeline_states.computePipeline[currentComputePipeline];
888 if(pipelineState.effect != effect) reload =
true;
894 ComputePipelineHandle pipelineStateHandle = pipeline_states.loadComputePipeline(effect);
895 ComputePipelineWebGPU pipelineState = pipeline_states.computePipeline[pipelineStateHandle];
896 currentComputePipeline = pipelineStateHandle;
899 ComputePipelineWebGPU &pipelineState = pipeline_states.computePipeline[currentComputePipeline];
900 wgpuComputePassEncoderSetPipeline(computePassEncoder, pipelineState.pipeline);
902 if(update_descriptors){
903 update_descriptors =
false;
904 ComputePipelineWebGPU &pipelineState = pipeline_states.computePipeline[currentComputePipeline];
906 std::vector<WGPUBindGroupEntry> entries;
907 entries.resize(descriptors.size());
909 for(
auto &tmp : descriptors){
910 entries[i++] = tmp.second;
912 descriptor_count += (uint32_t)descriptors.size();
914 WGPUBindGroupDescriptor bg_desc = WGPU_BIND_GROUP_DESCRIPTOR_INIT;
916 bg_desc.layout = pipelineState.layout;
917 bg_desc.entryCount = (uint32_t)entries.size();
918 bg_desc.entries = entries.data();
919 current_bind_group = wgpuDeviceCreateBindGroup(graphicsDevice->device, &bg_desc);
920 bind_groups.push_back(current_bind_group);
921 counters.bind_group++;
923 if(current_bind_group){
924 uint32_t groupIndex = 0;
925 wgpuComputePassEncoderSetBindGroup(computePassEncoder, groupIndex, current_bind_group, 0,
nullptr);
931 const WGPUCommandEncoder &commandEncoder = graphicsDevice->commandEncoder;
933 BufferWebGPU buffer = graphicsDevice->buffers.buffers[bufferHandle];
937 WGPUTexelCopyTextureInfo src = WGPU_TEXEL_COPY_TEXTURE_INFO_INIT;
938 if (HandleIsValid(renderTargetHandle) || HandleIsValid(depthStencilHandle)) {
939 if(!HandleIsValid(depthStencilHandle))
return;
941 TextureWebGPU &src_tex = textures.textures[target.textureHandle];
942 src.texture = src_tex.texture;
946 src.texture = defaultSwapChain.depthBufferTexture;
949 src.origin = {(uint32_t)x, (uint32_t)y, 0};
950 src.aspect = WGPUTextureAspect_DepthOnly;
951 WGPUTexelCopyBufferInfo dst = WGPU_TEXEL_COPY_BUFFER_INFO_INIT;
952 dst.layout.offset = 0;
953 dst.layout.bytesPerRow = (uint32_t)buffer.size;
954 dst.layout.rowsPerImage = 1;
955 dst.buffer = buffer.buffer;
956 WGPUExtent3D size = WGPU_EXTENT_3D_INIT;
958 size.height = height;
959 size.depthOrArrayLayers = 1;
960 wgpuCommandEncoderCopyTextureToBuffer(commandEncoder, &src, &dst, &size);
965 const WGPUCommandEncoder &commandEncoder = graphicsDevice->commandEncoder;
967 BufferWebGPU buffer = graphicsDevice->buffers.buffers[bufferHandle];
971 WGPUTexelCopyTextureInfo src = WGPU_TEXEL_COPY_TEXTURE_INFO_INIT;
972 if (HandleIsValid(renderTargetHandle) || HandleIsValid(depthStencilHandle)) {
973 if(!HandleIsValid(renderTargetHandle))
return;
974 RenderTargetWebGPU target = graphicsDevice->renderTargets.render_targets[renderTargetHandle];
975 TextureWebGPU &src_tex = textures.textures[target.textureHandle[0]];
976 src.texture = src_tex.texture;
982 src.texture = defaultSwapChain.colorBufferTexture;
984 src.texture = defaultSwapChain.resolveTexture;
988 src.origin = {(uint32_t)x, (uint32_t)y, 0};
989 src.aspect = WGPUTextureAspect_All;
990 WGPUTexelCopyBufferInfo dst = WGPU_TEXEL_COPY_BUFFER_INFO_INIT;
991 dst.layout.offset = 0;
992 dst.layout.bytesPerRow = (uint32_t)buffer.size;
993 dst.layout.rowsPerImage = 1;
994 dst.buffer = buffer.buffer;
995 WGPUExtent3D size = WGPU_EXTENT_3D_INIT;
997 size.height = height;
998 size.depthOrArrayLayers = 1;
999 wgpuCommandEncoderCopyTextureToBuffer(commandEncoder, &src, &dst, &size);
1004 assert(stride ==
nullptr || stride[0] == 0);
1005 BufferWebGPU &buffer = graphicsDevice->buffers.buffers[handle];
1006 if(buffer.is_read_buffer){
1008 uint32_t offset = 0;
1009 WGPUBufferMapCallback callback =
nullptr;
1010 void * userdata =
nullptr;
1011 WGPUBufferMapCallbackInfo callbackInfo = WGPU_BUFFER_MAP_CALLBACK_INFO_INIT;
1012 callbackInfo.callback = callback;
1013 callbackInfo.mode = WGPUCallbackMode_AllowProcessEvents;
1014 callbackInfo.nextInChain =
nullptr;
1015 callbackInfo.userdata1 = userdata;
1016 wgpuBufferMapAsync(buffer.buffer, WGPUMapMode_Read, offset, buffer.size, callbackInfo);
1017#ifndef __EMSCRIPTEN__
1018 WGPUBufferMapState state = wgpuBufferGetMapState(buffer.buffer);
1019 while(state != WGPUBufferMapState_Mapped){
1021 assert(state == WGPUBufferMapState_Pending);
1022 wgpuInstanceProcessEvents(graphicsDevice->instance);
1023 wgpuDeviceTick(graphicsDevice->device);
1024 state = wgpuBufferGetMapState(buffer.buffer);
1030 return (
void*)wgpuBufferGetConstMappedRange(buffer.buffer, 0, buffer.size);
1034 buffer.NextInstance(graphicsDevice, graphicsDevice->buffers);
1035 buffer.map =
new char[buffer.size];
1048 BufferWebGPU &buffer = graphicsDevice->buffers.buffers[handle];
1049 if(buffer.is_read_buffer){
1052 wgpuBufferUnmap(buffer.buffer);
1055 if(buffer.size > 0){
1056 wgpuQueueWriteBuffer(graphicsDevice->queue, buffer.buffer, 0, buffer.map, buffer.size);
1057 if(uploadStatisticsEnabled) uploadStatisticsBufferUpload(buffer.size);
1059 delete [] (
char*)buffer.map;
1060 buffer.map =
nullptr;
1071 BufferWebGPU &buffer = graphicsDevice->buffers.buffers[handle];
1072 assert(!buffer.is_read_buffer);
1073 if(size == 0)
return;
1074 if(size > buffer.size){
1075 LOG_ERROR(logger,
"updateBuffer: write size (%zu) exceeds buffer size (%zu)", size, buffer.size);
1078 buffer.NextInstance(graphicsDevice, graphicsDevice->buffers);
1079 wgpuQueueWriteBuffer(graphicsDevice->queue, buffer.buffer, 0, data, size);
1080 if(uploadStatisticsEnabled) uploadStatisticsBufferUpload(size);
1085 assert(HandleIsValid(textureHandle) &&
"Texture handle is invalid.");
1087 TextureWebGPU & texture = graphicsDevice->textures.textures[textureHandle];
1089 const uint32_t width = Cogs::getMipSize(texture.width,
static_cast<uint32_t
>(level));
1090 const uint32_t height = Cogs::getMipSize(texture.height,
static_cast<uint32_t
>(level));
1092 WGPUTexelCopyTextureInfo destinationTexture;
1093 destinationTexture.texture = texture.texture;
1094 destinationTexture.mipLevel =
static_cast<uint32_t
>(level);
1095 destinationTexture.aspect = WGPUTextureAspect_All;
1096 destinationTexture.origin = { 0, 0, 0 };
1098 const Cogs::FormatInfo *textureFormat = Cogs::getFormatInfo(texture.format);
1100 WGPUTexelCopyBufferLayout sourceLayout;
1101 sourceLayout.offset = 0;
1103 sourceLayout.rowsPerImage = (height + textureFormat->
blockExtent.height - 1) / textureFormat->
blockExtent.height;
1105 size_t size = sourceLayout.bytesPerRow * sourceLayout.rowsPerImage;
1107 WGPUExtent3D extent;
1108 extent.width = width;
1109 extent.height = height;
1110 extent.depthOrArrayLayers = 1;
1112 wgpuQueueWriteTexture(graphicsDevice->queue, &destinationTexture, data,
static_cast<size_t>(size), &sourceLayout, &extent);
1114 if(uploadStatisticsEnabled) uploadStatisticsTextureUpload(texture.estimatedByteSize);
1119 BufferWebGPU &buffer = graphicsDevice->buffers.buffers[handle];
1120 if(size == 0)
return;
1121 assert(!buffer.is_read_buffer);
1122 if(offset + size > buffer.size){
1123 LOG_ERROR(logger,
"updateSubBuffer: write range (offset: %zu, size: %zu) exceeds buffer size (%zu)", offset, size, buffer.size);
1126 assert(buffer.alias_idx == 0);
1128 wgpuQueueWriteBuffer(graphicsDevice->queue, buffer.buffer, offset, data, size);
1129 if(uploadStatisticsEnabled) uploadStatisticsBufferUpload(size);
1142 void ContextWebGPU::copyResource(TextureHandle , TextureHandle )
1147 void ContextWebGPU::copyTexture(TextureHandle dstHandle,
unsigned dstSub,
unsigned dstX,
unsigned dstY,
unsigned dstZ, TextureHandle srcHandle,
unsigned srcSub)
1149 graphicsDevice->maybeCreateUploadCommandEncoder();
1150 const WGPUCommandEncoder &commandEncoder = graphicsDevice->commandEncoder;
1151 TexturesWebGPU &textures = graphicsDevice->textures;
1153 TextureWebGPU &src = textures.textures[srcHandle];
1154 TextureWebGPU &dst = textures.textures[dstHandle];
1156 uint32_t srcLevel = 0;
1157 uint32_t srcLayer = srcSub;
1159 WGPUTexelCopyTextureInfo copy_src = WGPU_TEXEL_COPY_TEXTURE_INFO_INIT;
1160 copy_src.texture = src.texture;
1161 copy_src.mipLevel = srcLevel;
1162 copy_src.origin = {0, 0, srcLayer};
1163 copy_src.aspect = WGPUTextureAspect_All;
1165 uint32_t dstLevel = 0;
1166 uint32_t dstLayer = dstSub;
1168 WGPUTexelCopyTextureInfo copy_dst = WGPU_TEXEL_COPY_TEXTURE_INFO_INIT;
1169 copy_dst.texture = dst.texture;
1170 copy_dst.mipLevel = dstLevel;
1171 copy_dst.origin = {dstX, dstY, dstZ+dstLayer};
1172 copy_dst.aspect = WGPUTextureAspect_All;
1174 WGPUExtent3D size = WGPU_EXTENT_3D_INIT;
1175 size.width = src.width;
1176 size.height = src.height;
1177 size.depthOrArrayLayers = 1;
1178 wgpuCommandEncoderCopyTextureToTexture(commandEncoder, ©_src, ©_dst, &size);
1181 void ContextWebGPU::clearResource(BufferHandle , uint32_t* )
1186 void ContextWebGPU::clearResource(BufferHandle ,
float* )
1191 void ContextWebGPU::beginFrame() {
1192 prevStats = currStats;
1193 currStats = FrameStatistics{};
1195 prevUploadStats = currUploadStats;
1196 currUploadStats = UploadStatistics{};
1199 void ContextWebGPU::frameStatisticsAccountDrawCall(
size_t count,
bool indexed)
1202 unsigned bucket = 0;
1204 if ((t & 0xFFFF0000) != 0) { bucket += 16; t = t >> 16u; }
1205 if ((t & 0x0000FF00) != 0) { bucket += 8; t = t >> 8u; }
1206 if ((t & 0x000000F0) != 0) { bucket += 4; t = t >> 4u; }
1207 if ((t & 0x0000000C) != 0) { bucket += 2; t = t >> 2u; }
1208 if ((t & 0x00000002) != 0) { bucket += 1; }
1211 assert(uint64_t(count) < (uint64_t(1) << (bucket + 1)));
1213 assert((uint64_t(1) << bucket) <= uint64_t(count));
1216 assert(bucket == 0);
1220 currStats.drawCallHistogram[bucket]++;
1221 currStats.vertices += count;
1222 if (indexed) currStats.indices += count;
1225 void ContextWebGPU::uploadStatisticsBufferUpload(
size_t size)
1227 currUploadStats.bufferUploads++;
1228 currUploadStats.bufferUploadSize += size;
1231 void ContextWebGPU::uploadStatisticsTextureUpload(
size_t size)
1233 currUploadStats.textureUploads++;
1234 currUploadStats.textureUploadSize += size;
1237 EffectHandle ContextWebGPU::getCurrentEffect()
1242 EffectsWebGPU *ContextWebGPU::getEffects()
1244 return &graphicsDevice->effects;
1247 void ContextWebGPU::ClearBindGroups()
1249 ResourceCountersWebGPU &counters = graphicsDevice->counters;
1250 for(
auto &bg : last_bind_groups){
1251 wgpuBindGroupRelease(bg);
1252 counters.bind_group--;
1254 last_bind_groups.clear();
1255 current_bind_group = {};
1256 update_descriptors =
true;
1258 counters.descriptor_count = descriptor_count;
1259 descriptor_count = 0;
1261 void ContextWebGPU::SwapBindGroups()
1263 last_bind_groups = std::move(bind_groups);
virtual void setSamplerState(const StringView &, unsigned int, SamplerStateHandle) override
Sets the sampler slot given by unit with the given name to contain the given sampler state.
virtual void pushCommandGroupAnnotation(const StringView &name) override
Begin to tag a sequence of commands as a group in graphics debugger.
virtual void getBufferCounter(BufferHandle, BufferHandle) override
Get the associated counter of a buffer.
virtual void setAnnotationMarker(const StringView &name) override
Add a tag in the sequence of commands in graphics debugger.
virtual void setEffect(EffectHandle) override
Set the current effect.
virtual void draw(PrimitiveType, const size_t, const size_t) override
Draws non-indexed, non-instanced primitives.
virtual void readColorBuffer(BufferHandle, int, int, int, int, Framebuffer) override
Reads data from the current render target into the given bufferHandle.
virtual void resolveResource(TextureHandle, TextureHandle) override
Resolves the given source resource target into the given destination texture.
virtual void clearDepth(const float=1.0f) override
Clear the currently set depth/stencil target to the given depth.
virtual void setBlendState(const BlendStateHandle, const float *) override
Set the current blend state.
virtual void updateSubBuffer(BufferHandle, const size_t, const size_t, const void *) override
Update a region of data in a buffer.
virtual void setVertexBuffers(const VertexBufferHandle *, const size_t, const uint32_t *, const uint32_t *) override
Sets the current vertex buffers.
virtual void readDepthBuffer(BufferHandle, int, int, int, int, Framebuffer) override
Reads data from the current depth target into the given bufferHandle.
virtual void drawInstanced(PrimitiveType, const size_t, const size_t, const size_t, const size_t) override
Draws non-indexed, instanced primitives.
virtual void setBuffer(const StringView &, BufferHandle) override
Sets the given buffer to the buffer binding slot with the given name.
virtual void popCommandGroupAnnotation() override
End to tag a sequence of commands as a group in graphics debugger.
virtual void dispatchCompute(const unsigned int, const unsigned int, const unsigned int) override
Dispatch computing work on the graphics device using the desired thread group count.
virtual void setConstantBuffer(const StringView &, const BufferHandle, const uint32_t=0, const uint32_t=~0u) override
Sets a constant buffer to be bound to the given name and slot.
virtual void * map(BufferHandle, MapMode::EMapMode, uint32_t *=nullptr) override
Maps the given buffer so it can be accessed.
virtual void setBufferCounter(BufferHandle, uint32_t) override
Set the associated counter of a buffer.
virtual void unmap(BufferHandle) override
Unmaps the given buffer, applying any synchronization necessary to reflect changes in the mapped memo...
virtual void drawIndexed(PrimitiveType, const size_t, const size_t, const size_t=0) override
Draws indexed, non-instanced primitives.
virtual void setDepthStencilState(const DepthStencilStateHandle) override
Set the current depth stencil state.
virtual void setScissor(const int, const int, const int, const int) override
Sets the current scissor rectangle.
virtual void setRasterizerState(const RasterizerStateHandle) override
Set the current rasterizer state.
virtual void endRenderPass() override
End a render pass.
virtual void drawInstancedIndexed(PrimitiveType, const size_t, const size_t, const size_t, const size_t) override
Draws indexed, instanced primitives.
virtual void updateSubTexture(TextureHandle, const size_t, const void *) override
Update the data of a level in the given texture.
virtual void beginRenderPass(const RenderPassInfo &info) override
Begin a render pass.
virtual void setVertexArrayObject(VertexArrayObjectHandle) override
Sets vertexBuffers and index buffers using a prevalidated vertex array object.
virtual void signal(FenceHandle) override
Insert a fence in the command stream that will signal when all commands before the fence are complete...
virtual void setIndexBuffer(IndexBufferHandle, uint32_t=4, uint32_t=0) override
Sets the current index buffer.
virtual void clearRenderTarget(const float *) override
Clear the currently set render target to the given value (4 component floating point RGBA).
virtual void setTexture(const StringView &, unsigned int, TextureHandle) override
Sets the texture slot given by unit with the given name to contain the given texture.
virtual void setInputLayout(const InputLayoutHandle) override
Sets the current input layout.
virtual void setRenderTarget(const RenderTargetHandle handle, const DepthStencilHandle depthStencilHandle) override
Sets the current render target and an associated depth stencil target.
virtual void setViewport(const float, const float, const float, const float) override
Sets the current viewport to the given location and dimensions.
virtual void updateBuffer(BufferHandle, const void *, const size_t) override
Replace contents of buffer with new data.
void releaseBufferBinding(BufferBindingHandle) override
Release a handle to a buffer binding.
BufferBindingHandle getBufferBinding(EffectHandle effectHandle, const StringView &name) override
Get a handle to a buffer binding.
virtual bool getSize(int &w, int &h) const override
Retrieve the size previously set by setSize.
Log implementation class.
Provides a weakly referenced view over the contents of a string.
constexpr const char * data() const noexcept
Get the sequence of characters referenced by the string view.
constexpr size_t length() const noexcept
Get the length of the string.
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.
Framebuffer
Framebuffers to select from when doing framebuffer operations.
PrimitiveType
Primitive types for interpreting vertex data sent to the graphics pipeline.
Handle template class used to provide opaque, non-converting handles.
static const Handle_t NoHandle
Represents a handle to nothing.
handle_type handle
Internal resource handle.
EMapMode
Mapping mode enumeration.
@ WriteDiscard
Write access. When unmapping the graphics system will discard the old contents of the resource.