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;
585 if (updateRenderPipeline(primitiveType)) {
586 drawInstanced(primitiveType, startVertex, numVertexes, 0, 1);
587 if (frameStatisticsEnabled) { frameStatisticsAccountDrawCall(numVertexes,
false); }
590 LOG_ERROR_ONCE(logger,
"skip draw(), updateRenderPipeline failed.");
597 if (updateRenderPipeline(primitiveType)) {
598 wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, (uint32_t)numIndexes, 1, (uint32_t)startIndex, (int32_t)startVertex, 0);
599 if (frameStatisticsEnabled) { frameStatisticsAccountDrawCall(numIndexes,
true); }
602 LOG_ERROR_ONCE(logger,
"skip drawIndexed(), updateRenderPipeline failed.");
609 if (updateRenderPipeline(primitiveType)) {
610 wgpuRenderPassEncoderDraw(renderPassEncoder, (uint32_t)numVertexes, (uint32_t)numInstances, (uint32_t)startVertex, (uint32_t)startInstance);
611 if (frameStatisticsEnabled) { frameStatisticsAccountDrawCall(numVertexes*numInstances,
false); }
614 LOG_ERROR_ONCE(logger,
"skip drawInstanced(), updateRenderPipeline failed.");
621 if (updateRenderPipeline(primitiveType)) {
622 wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, (uint32_t)numIndexes, (uint32_t)numInstances, (uint32_t)startIndex, 0, (uint32_t)startInstance);
623 if (frameStatisticsEnabled) { frameStatisticsAccountDrawCall(numIndexes*numInstances,
true); }
626 LOG_ERROR_ONCE(logger,
"skip drawInstancedIndexed(), updateRenderPipeline failed.");
630 void ContextWebGPU::beginRenderPassInt()
632 assert(renderPassEncoder == 0);
633 assert(computePassEncoder == 0);
634 WGPURenderPassColorAttachment color_attachment[8] = {};
635 WGPURenderPassDepthStencilAttachment ds_attachment = WGPU_RENDER_PASS_DEPTH_STENCIL_ATTACHMENT_INIT;
636 uint32_t color_attachment_count = 0;
637 uint32_t ds_attachment_count = 0;
639 WGPULoadOp loadOp = do_clear_render_target ? WGPULoadOp_Clear : WGPULoadOp_Load;
640 do_clear_render_target =
false;
641 WGPULoadOp depthLoadOp = do_clear_depth ? WGPULoadOp_Clear : WGPULoadOp_Load;
642 do_clear_depth =
false;
643 const char *name =
nullptr;
644 if (HandleIsValid(renderTargetHandle) || HandleIsValid(depthStencilHandle)) {
645 name =
"Custom Render Pass";
646 if(HandleIsValid(renderTargetHandle)){
647 RenderTargetWebGPU &target = graphicsDevice->renderTargets.render_targets[renderTargetHandle];
648 for(
size_t i=0; i<target.count; i++){
649 WGPURenderPassColorAttachment &att = color_attachment[i];
650 att.view = target.view[i];
651 att.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED;
652 att.resolveTarget =
nullptr;
654 att.storeOp = WGPUStoreOp_Store;
655 att.clearValue = clearColor[i];
657 color_attachment_count = target.count;
660 DepthStencilTargetWebGPU &target = graphicsDevice->renderTargets.depth_stencil_targets[depthStencilHandle];
661 WGPURenderPassDepthStencilAttachment &att = ds_attachment;
662 att.view = target.view;
663 att.depthLoadOp = depthLoadOp;
664 att.depthStoreOp = WGPUStoreOp_Store;
665 att.depthClearValue = clearDepthVal;
666 att.depthReadOnly =
false;
667 att.stencilLoadOp = WGPULoadOp_Undefined;
668 att.stencilStoreOp = WGPUStoreOp_Undefined;
669 att.stencilClearValue = 0;
670 att.stencilReadOnly =
false;
671 ds_attachment_count = 1;
675 name =
"Default Render Pass";
676 SwapChainWebGPU &defaultSwapChain = graphicsDevice->defaultSwapChain;
677 if(defaultSwapChain.samples > 1){
678 color_attachment[0].view = defaultSwapChain.colorBufferView;
679 color_attachment[0].resolveTarget = defaultSwapChain.resolveView;
682 color_attachment[0].view = defaultSwapChain.resolveView;
684 color_attachment[0].depthSlice = WGPU_DEPTH_SLICE_UNDEFINED;
685 color_attachment[0].loadOp = loadOp;
686 color_attachment[0].storeOp = WGPUStoreOp_Store;
687 color_attachment[0].clearValue = clearColor[0];
688 color_attachment_count = 1;
690 ds_attachment.view = defaultSwapChain.depthBufferView;
691 ds_attachment.depthLoadOp = depthLoadOp;
692 ds_attachment.depthStoreOp = WGPUStoreOp_Store;
693 ds_attachment.depthClearValue = clearDepthVal;
694 ds_attachment.depthReadOnly =
false;
695 ds_attachment.stencilLoadOp = WGPULoadOp_Undefined;
696 ds_attachment.stencilStoreOp = WGPUStoreOp_Undefined;
697 ds_attachment.stencilClearValue = 0;
698 ds_attachment.stencilReadOnly =
false;
699 ds_attachment_count = 1;
702 if(graphicsDevice->use_error_scope){
703 wgpuDevicePushErrorScope(graphicsDevice->device, graphicsDevice->filter);
706 WGPURenderPassDescriptor render_pass_desc = WGPU_RENDER_PASS_DESCRIPTOR_INIT;
707 render_pass_desc.label = {name, WGPU_STRLEN};
708 if(color_attachment_count){
709 render_pass_desc.colorAttachmentCount = color_attachment_count;
710 render_pass_desc.colorAttachments = color_attachment;
712 if(ds_attachment_count){
713 render_pass_desc.depthStencilAttachment = &ds_attachment;
715 render_pass_desc.occlusionQuerySet =
nullptr;
717 render_pass_desc.timestampWrites =
nullptr;
718 renderPassEncoder = wgpuCommandEncoderBeginRenderPass(graphicsDevice->commandEncoder, &render_pass_desc);
721 void ContextWebGPU::endRenderPassInt()
723 assert(!inRenderPass);
724 if(!renderPassEncoder)
return;
725 wgpuRenderPassEncoderEnd(renderPassEncoder);
726 wgpuRenderPassEncoderRelease(renderPassEncoder);
727 renderPassEncoder = 0;
728 update_render_target =
true;
730 if(graphicsDevice->use_error_scope){
731 WGPUPopErrorScopeCallbackInfo info = WGPU_POP_ERROR_SCOPE_CALLBACK_INFO_INIT;
732 info.mode = WGPUCallbackMode_AllowSpontaneous;
733 info.callback = context_error_callback;
734 info.userdata1 =
this;
735 info.userdata2 = graphicsDevice;
736 WGPUFuture future = wgpuDevicePopErrorScope(graphicsDevice->device, info);
741 void ContextWebGPU::updateRenderPass()
743 if(update_render_target){
746 beginRenderPassInt();
747 update_render_target =
false;
751 bool ContextWebGPU::updateRenderPipeline(
PrimitiveType primitiveType)
753 assert(renderPassEncoder);
754 ResourceCountersWebGPU &counters = graphicsDevice->counters;
755 PipelineStatesWebGPU &pipeline_states = graphicsDevice->pipeline_states;
758 RenderPipelineWebGPU pipelineState = pipeline_states.renderPipeline[currentRenderPipeline];
759 size_t hash = pipeline_states.renderPipelineHash(effect,
762 rasterizeStateHandle,
763 depthStencilStateHandle,
768 if(
hash != pipelineState.hash) reload =
true;
774 RenderPipelineHandle pipelineStateHandle = pipeline_states.loadRenderPipeline
779 rasterizeStateHandle,
780 depthStencilStateHandle,
786 RenderPipelineWebGPU pipelineState = pipeline_states.renderPipeline[pipelineStateHandle];
787 currentRenderPipeline = pipelineStateHandle;
790 RenderPipelineWebGPU &pipelineState = pipeline_states.renderPipeline[currentRenderPipeline];
791 wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelineState.pipeline);
793 if(update_descriptors){
794 RenderPipelineWebGPU &pipelineState = pipeline_states.renderPipeline[currentRenderPipeline];
796 std::vector<WGPUBindGroupEntry> entries;
797 entries.resize(descriptors.size());
799 for(
auto &tmp : descriptors){
800 entries[i++] = tmp.second;
805 auto bindings = getEffects()->getConstantBufferBindings(effect, num_bindings);
807 for (
size_t ii = 0; ii < num_bindings; ii++) {
809 for (
size_t j = 0; j < entries.size(); j++) {
810 if (bindings[ii].bg_ent.binding == entries[j].binding) {
815 LOG_ERROR_ONCE(logger,
"binding %d in layout but not set (%s)", bindings[ii].bg_ent.binding, bindings[ii].name.c_str());
819 for (
size_t j = 0; j < entries.size(); j++) {
821 for (
size_t ii = 0; ii < num_bindings; ii++) {
822 if (bindings[ii].bg_ent.binding == entries[j].binding) {
827 LOG_ERROR_ONCE(logger,
"binding %d is set but not in layout", entries[j].binding);
832 WGPUBindGroupDescriptor bg_desc = WGPU_BIND_GROUP_DESCRIPTOR_INIT;
834 bg_desc.layout = pipelineState.bind_group_layout;
835 bg_desc.entryCount = (uint32_t)entries.size();
836 bg_desc.entries = entries.data();
837 current_bind_group = wgpuDeviceCreateBindGroup(graphicsDevice->device, &bg_desc);
838 bind_groups.push_back(current_bind_group);
839 counters.bind_group++;
841 if(current_bind_group){
842 uint32_t groupIndex = 0;
843 wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, groupIndex, current_bind_group, 0,
nullptr);
851 updateComputePipeline();
852 wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, threadGroupsX, threadGroupsY, threadGroupsZ);
855 void ContextWebGPU::beginComputePass()
857 assert(renderPassEncoder == 0);
858 assert(computePassEncoder == 0);
859 WGPUComputePassDescriptor compute_pass_desc = WGPU_COMPUTE_PASS_DESCRIPTOR_INIT;
860 compute_pass_desc.label = {
"Compute Pass", WGPU_STRLEN};
862 compute_pass_desc.timestampWrites =
nullptr;
863 computePassEncoder = wgpuCommandEncoderBeginComputePass(graphicsDevice->commandEncoder, &compute_pass_desc);
866 void ContextWebGPU::endComputePass()
868 if(!computePassEncoder)
return;
869 wgpuComputePassEncoderEnd(computePassEncoder);
870 computePassEncoder = 0;
873 void ContextWebGPU::updateComputePass()
875 if(!computePassEncoder){
879 update_render_target =
true;
883 void ContextWebGPU::updateComputePipeline()
885 assert(computePassEncoder);
886 ResourceCountersWebGPU &counters = graphicsDevice->counters;
887 PipelineStatesWebGPU &pipeline_states = graphicsDevice->pipeline_states;
890 ComputePipelineWebGPU pipelineState = pipeline_states.computePipeline[currentComputePipeline];
891 if(pipelineState.effect != effect) reload =
true;
897 ComputePipelineHandle pipelineStateHandle = pipeline_states.loadComputePipeline(effect);
898 ComputePipelineWebGPU pipelineState = pipeline_states.computePipeline[pipelineStateHandle];
899 currentComputePipeline = pipelineStateHandle;
902 ComputePipelineWebGPU &pipelineState = pipeline_states.computePipeline[currentComputePipeline];
903 wgpuComputePassEncoderSetPipeline(computePassEncoder, pipelineState.pipeline);
905 if(update_descriptors){
906 ComputePipelineWebGPU &pipelineState = pipeline_states.computePipeline[currentComputePipeline];
908 std::vector<WGPUBindGroupEntry> entries;
909 entries.resize(descriptors.size());
911 for(
auto &tmp : descriptors){
912 entries[i++] = tmp.second;
915 WGPUBindGroupDescriptor bg_desc = WGPU_BIND_GROUP_DESCRIPTOR_INIT;
917 bg_desc.layout = pipelineState.layout;
918 bg_desc.entryCount = (uint32_t)entries.size();
919 bg_desc.entries = entries.data();
920 current_bind_group = wgpuDeviceCreateBindGroup(graphicsDevice->device, &bg_desc);
921 bind_groups.push_back(current_bind_group);
922 counters.bind_group++;
924 if(current_bind_group){
925 uint32_t groupIndex = 0;
926 wgpuComputePassEncoderSetBindGroup(computePassEncoder, groupIndex, current_bind_group, 0,
nullptr);
932 const WGPUCommandEncoder &commandEncoder = graphicsDevice->commandEncoder;
934 BufferWebGPU buffer = graphicsDevice->buffers.buffers[bufferHandle];
938 WGPUTexelCopyTextureInfo src = WGPU_TEXEL_COPY_TEXTURE_INFO_INIT;
939 if (HandleIsValid(renderTargetHandle) || HandleIsValid(depthStencilHandle)) {
940 if(!HandleIsValid(depthStencilHandle))
return;
942 TextureWebGPU &src_tex = textures.textures[target.textureHandle];
943 src.texture = src_tex.texture;
947 src.texture = defaultSwapChain.depthBufferTexture;
950 src.origin = {(uint32_t)x, (uint32_t)y, 0};
951 src.aspect = WGPUTextureAspect_DepthOnly;
952 WGPUTexelCopyBufferInfo dst = WGPU_TEXEL_COPY_BUFFER_INFO_INIT;
953 dst.layout.offset = 0;
954 dst.layout.bytesPerRow = (uint32_t)buffer.size;
955 dst.layout.rowsPerImage = 1;
956 dst.buffer = buffer.buffer;
957 WGPUExtent3D size = WGPU_EXTENT_3D_INIT;
959 size.height = height;
960 size.depthOrArrayLayers = 1;
961 wgpuCommandEncoderCopyTextureToBuffer(commandEncoder, &src, &dst, &size);
966 const WGPUCommandEncoder &commandEncoder = graphicsDevice->commandEncoder;
968 BufferWebGPU buffer = graphicsDevice->buffers.buffers[bufferHandle];
972 WGPUTexelCopyTextureInfo src = WGPU_TEXEL_COPY_TEXTURE_INFO_INIT;
973 if (HandleIsValid(renderTargetHandle) || HandleIsValid(depthStencilHandle)) {
974 if(!HandleIsValid(renderTargetHandle))
return;
975 RenderTargetWebGPU target = graphicsDevice->renderTargets.render_targets[renderTargetHandle];
976 TextureWebGPU &src_tex = textures.textures[target.textureHandle[0]];
977 src.texture = src_tex.texture;
983 src.texture = defaultSwapChain.colorBufferTexture;
985 src.texture = defaultSwapChain.resolveTexture;
989 src.origin = {(uint32_t)x, (uint32_t)y, 0};
990 src.aspect = WGPUTextureAspect_All;
991 WGPUTexelCopyBufferInfo dst = WGPU_TEXEL_COPY_BUFFER_INFO_INIT;
992 dst.layout.offset = 0;
993 dst.layout.bytesPerRow = (uint32_t)buffer.size;
994 dst.layout.rowsPerImage = 1;
995 dst.buffer = buffer.buffer;
996 WGPUExtent3D size = WGPU_EXTENT_3D_INIT;
998 size.height = height;
999 size.depthOrArrayLayers = 1;
1000 wgpuCommandEncoderCopyTextureToBuffer(commandEncoder, &src, &dst, &size);
1005 assert(stride ==
nullptr || stride[0] == 0);
1006 BufferWebGPU &buffer = graphicsDevice->buffers.buffers[handle];
1007 if(buffer.is_read_buffer){
1009 uint32_t offset = 0;
1010 WGPUBufferMapCallback callback =
nullptr;
1011 void * userdata =
nullptr;
1012 WGPUBufferMapCallbackInfo callbackInfo = WGPU_BUFFER_MAP_CALLBACK_INFO_INIT;
1013 callbackInfo.callback = callback;
1014 callbackInfo.mode = WGPUCallbackMode_AllowProcessEvents;
1015 callbackInfo.nextInChain =
nullptr;
1016 callbackInfo.userdata1 = userdata;
1017 wgpuBufferMapAsync(buffer.buffer, WGPUMapMode_Read, offset, buffer.size, callbackInfo);
1018#ifndef __EMSCRIPTEN__
1019 WGPUBufferMapState state = wgpuBufferGetMapState(buffer.buffer);
1020 while(state != WGPUBufferMapState_Mapped){
1022 assert(state == WGPUBufferMapState_Pending);
1023 wgpuInstanceProcessEvents(graphicsDevice->instance);
1024 wgpuDeviceTick(graphicsDevice->device);
1025 state = wgpuBufferGetMapState(buffer.buffer);
1032 return (
void*)wgpuBufferGetConstMappedRange(buffer.buffer, 0, buffer.size);
1036 buffer.NextInstance(graphicsDevice, graphicsDevice->buffers);
1037 buffer.map =
new char[buffer.size];
1050 BufferWebGPU &buffer = graphicsDevice->buffers.buffers[handle];
1051 if(buffer.is_read_buffer){
1054 wgpuBufferUnmap(buffer.buffer);
1059 if(buffer.size > 0){
1060 wgpuQueueWriteBuffer(graphicsDevice->queue, buffer.buffer, 0, buffer.map, buffer.size);
1061 if(uploadStatisticsEnabled) uploadStatisticsBufferUpload(buffer.size);
1063 delete [] (
char*)buffer.map;
1064 buffer.map =
nullptr;
1075 BufferWebGPU &buffer = graphicsDevice->buffers.buffers[handle];
1076 if(size == 0)
return;
1077 if(size > buffer.size){
1078 LOG_ERROR(logger,
"updateBuffer: write size (%zu) exceeds buffer size (%zu)", size, buffer.size);
1081 buffer.NextInstance(graphicsDevice, graphicsDevice->buffers);
1082 wgpuQueueWriteBuffer(graphicsDevice->queue, buffer.buffer, 0, data, size);
1083 if(uploadStatisticsEnabled) uploadStatisticsBufferUpload(size);
1088 assert(HandleIsValid(textureHandle) &&
"Texture handle is invalid.");
1090 TextureWebGPU & texture = graphicsDevice->textures.textures[textureHandle];
1092 const uint32_t width = Cogs::getMipSize(texture.width,
static_cast<uint32_t
>(level));
1093 const uint32_t height = Cogs::getMipSize(texture.height,
static_cast<uint32_t
>(level));
1095 WGPUTexelCopyTextureInfo destinationTexture;
1096 destinationTexture.texture = texture.texture;
1097 destinationTexture.mipLevel =
static_cast<uint32_t
>(level);
1098 destinationTexture.aspect = WGPUTextureAspect_All;
1099 destinationTexture.origin = { 0, 0, 0 };
1101 const Cogs::FormatInfo *textureFormat = Cogs::getFormatInfo(texture.format);
1103 WGPUTexelCopyBufferLayout sourceLayout;
1104 sourceLayout.offset = 0;
1106 sourceLayout.rowsPerImage = (height + textureFormat->
blockExtent.height - 1) / textureFormat->
blockExtent.height;
1108 size_t size = sourceLayout.bytesPerRow * sourceLayout.rowsPerImage;
1110 WGPUExtent3D extent;
1111 extent.width = width;
1112 extent.height = height;
1113 extent.depthOrArrayLayers = 1;
1115 wgpuQueueWriteTexture(graphicsDevice->queue, &destinationTexture, data,
static_cast<size_t>(size), &sourceLayout, &extent);
1117 if(uploadStatisticsEnabled) uploadStatisticsTextureUpload(texture.estimatedByteSize);
1122 BufferWebGPU &buffer = graphicsDevice->buffers.buffers[handle];
1123 if(size == 0)
return;
1124 if(offset + size > buffer.size){
1125 LOG_ERROR(logger,
"updateSubBuffer: write range (offset: %zu, size: %zu) exceeds buffer size (%zu)", offset, size, buffer.size);
1128 assert(buffer.alias_idx == 0);
1130 wgpuQueueWriteBuffer(graphicsDevice->queue, buffer.buffer, offset, data, size);
1131 if(uploadStatisticsEnabled) uploadStatisticsBufferUpload(size);
1144 void ContextWebGPU::copyResource(TextureHandle , TextureHandle )
1149 void ContextWebGPU::copyTexture(TextureHandle dstHandle,
unsigned dstSub,
unsigned dstX,
unsigned dstY,
unsigned dstZ, TextureHandle srcHandle,
unsigned srcSub)
1151 graphicsDevice->maybeCreateUploadCommandEncoder();
1152 const WGPUCommandEncoder &commandEncoder = graphicsDevice->commandEncoder;
1153 TexturesWebGPU &textures = graphicsDevice->textures;
1155 TextureWebGPU &src = textures.textures[srcHandle];
1156 TextureWebGPU &dst = textures.textures[dstHandle];
1158 uint32_t srcLevel = 0;
1159 uint32_t srcLayer = srcSub;
1161 WGPUTexelCopyTextureInfo copy_src = WGPU_TEXEL_COPY_TEXTURE_INFO_INIT;
1162 copy_src.texture = src.texture;
1163 copy_src.mipLevel = srcLevel;
1164 copy_src.origin = {0, 0, srcLayer};
1165 copy_src.aspect = WGPUTextureAspect_All;
1167 uint32_t dstLevel = 0;
1168 uint32_t dstLayer = dstSub;
1170 WGPUTexelCopyTextureInfo copy_dst = WGPU_TEXEL_COPY_TEXTURE_INFO_INIT;
1171 copy_dst.texture = dst.texture;
1172 copy_dst.mipLevel = dstLevel;
1173 copy_dst.origin = {dstX, dstY, dstZ+dstLayer};
1174 copy_dst.aspect = WGPUTextureAspect_All;
1176 WGPUExtent3D size = WGPU_EXTENT_3D_INIT;
1177 size.width = src.width;
1178 size.height = src.height;
1179 size.depthOrArrayLayers = 1;
1180 wgpuCommandEncoderCopyTextureToTexture(commandEncoder, ©_src, ©_dst, &size);
1183 void ContextWebGPU::clearResource(BufferHandle , uint32_t* )
1188 void ContextWebGPU::clearResource(BufferHandle ,
float* )
1193 void ContextWebGPU::beginFrame() {
1194 prevStats = currStats;
1195 currStats = FrameStatistics{};
1197 prevUploadStats = currUploadStats;
1198 currUploadStats = UploadStatistics{};
1201 void ContextWebGPU::frameStatisticsAccountDrawCall(
size_t count,
bool indexed)
1204 unsigned bucket = 0;
1206 if ((t & 0xFFFF0000) != 0) { bucket += 16; t = t >> 16u; }
1207 if ((t & 0x0000FF00) != 0) { bucket += 8; t = t >> 8u; }
1208 if ((t & 0x000000F0) != 0) { bucket += 4; t = t >> 4u; }
1209 if ((t & 0x0000000C) != 0) { bucket += 2; t = t >> 2u; }
1210 if ((t & 0x00000002) != 0) { bucket += 1; }
1213 assert(uint64_t(count) < (uint64_t(1) << (bucket + 1)));
1215 assert((uint64_t(1) << bucket) <= uint64_t(count));
1218 assert(bucket == 0);
1222 currStats.drawCallHistogram[bucket]++;
1223 currStats.vertices += count;
1224 if (indexed) currStats.indices += count;
1227 void ContextWebGPU::uploadStatisticsBufferUpload(
size_t size)
1229 currUploadStats.bufferUploads++;
1230 currUploadStats.bufferUploadSize += size;
1233 void ContextWebGPU::uploadStatisticsTextureUpload(
size_t size)
1235 currUploadStats.textureUploads++;
1236 currUploadStats.textureUploadSize += size;
1239 EffectHandle ContextWebGPU::getCurrentEffect()
1244 EffectsWebGPU *ContextWebGPU::getEffects()
1246 return &graphicsDevice->effects;
1249 void ContextWebGPU::ClearBindGroups()
1251 ResourceCountersWebGPU &counters = graphicsDevice->counters;
1252 for(
auto &bg : last_bind_groups){
1253 wgpuBindGroupRelease(bg);
1254 counters.bind_group--;
1256 last_bind_groups.clear();
1258 void ContextWebGPU::SwapBindGroups()
1260 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.