Cogs.Core
ContextWebGPU.cpp
1#include "ContextWebGPU.h"
2
3#include "GraphicsDeviceWebGPU.h"
4#include "PipelineStatesWebGPU.h"
5#include "Foundation/Logging/Logger.h"
6
7namespace {
8 Cogs::Logging::Log logger = Cogs::Logging::getLogger("ContextWebGPU");
9
10 void context_error_callback(WGPUPopErrorScopeStatus status, WGPUErrorType type, WGPUStringView message, void* userdata1, void* userdata2)
11 {
12 Cogs::ContextWebGPU *context = (Cogs::ContextWebGPU*)userdata1;
13 (void)context;
15 (void)ptr;
16 if(status == WGPUPopErrorScopeStatus_CallbackCancelled){
17 LOG_ERROR(logger, "WebGPU context err status: Cancelled");
18 }
19 if(status == WGPUPopErrorScopeStatus_Error){
20 LOG_ERROR(logger, "WebGPU context err status: Error");
21 }
22 if(message.data && message.length){
23 LOG_ERROR(logger, "WebGPU context err (%d) %.*s", type, WGPUStringViewFormat(message));
24 }
25 }
26
27 WGPULoadOp ConvWebGPULoadOp(Cogs::LoadOp load_op)
28 {
29 switch(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;
33 }
34 return WGPULoadOp_Undefined;
35 }
36 WGPUStoreOp ConvWebGPUStoreOp(Cogs::StoreOp store_op)
37 {
38 switch(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;
42 }
43 return WGPUStoreOp_Undefined;
44 }
45
46 void decodeConstantBufferBindingHandle(int64_t handle, size_t &group, uint32_t &binding) {
47 int64_t i = handle;
48 group = i >> 16;
49 binding = (i & 0xFFFF) - 1;
50 }
51
52}
53
54namespace Cogs{
55
56 void ContextWebGPU::initialize(GraphicsDeviceWebGPU *graphicsDeviceIn)
57 {
58 graphicsDevice = graphicsDeviceIn;
59 }
60
61 void ContextWebGPU::signal(FenceHandle /*fenceHandle*/)
62 {
63 // assert(false); // TODO
64 }
65
66 void ContextWebGPU::clearRenderTarget(const float* value)
67 {
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];
74 }
75 do_clear_render_target = true;
76 update_render_target = true;
77 }
78
79 void ContextWebGPU::clearRenderTarget(const float** values, const int numvalues)
80 {
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];
87 }
88 for(size_t i=numvalues; i<sizeof(clearColor)/sizeof(clearColor[0]); i++){
89 clearColor[i] = WGPU_COLOR_INIT;
90 }
91 do_clear_render_target = true;
92 update_render_target = true;
93 }
94
95 void ContextWebGPU::clearDepth(const float depth)
96 {
97 assert(!inRenderPass);
98 clearDepthVal = depth;
99 do_clear_depth = true;
100 update_render_target = true;
101 }
102
104 {
105 (void)name;
106
107 // TODO: This seems to become messed up when changing render passes, etc
108
109 // WGPUStringView label = {name.data(), name.length()};
110 // if(renderPassEncoder != 0){
111 // wgpuRenderPassEncoderPushDebugGroup(renderPassEncoder, label);
112 // annotation_type.push_back(ANNOTATION_TYPE_RENDER_PASS);
113 // }
114 // else if(computePassEncoder != 0){
115 // wgpuComputePassEncoderPushDebugGroup(computePassEncoder, label);
116 // annotation_type.push_back(ANNOTATION_TYPE_COMPUTE_PASS);
117 // }
118 // // else if(renderBundleEncoder != 0){
119 // // annotation_type.push_back(ANNOTATION_TYPE_RENDER_BUNDLE);
120 // // wgpuRenderBundleEncoderPushDebugGroup(renderBundleEncoder, label);
121 // // }
122 // else{
123 // wgpuCommandEncoderPushDebugGroup(graphicsDevice->commandEncoder, label);
124 // annotation_type.push_back(ANNOTATION_TYPE_COMMAND_ENCODER);
125 // }
126 }
127
129 {
130 // assert(annotation_type.size());
131 // WGPUAnnotationType type = annotation_type.back();
132 // annotation_type.pop_back();
133 // if(type == ANNOTATION_TYPE_RENDER_PASS){
134 // assert(renderPassEncoder != 0);
135 // wgpuRenderPassEncoderPopDebugGroup(renderPassEncoder);
136 // }
137 // else if(type == ANNOTATION_TYPE_COMPUTE_PASS){
138 // assert(computePassEncoder != 0);
139 // wgpuComputePassEncoderPopDebugGroup(computePassEncoder);
140 // }
141 // // else if(type == ANNOTATION_TYPE_RENDER_BUNDLE){
142 // // assert(renderBundleEncoder != 0);
143 // // wgpuRenderBundleEncoderPopDebugGroup(renderBundleEncoder);
144 // // }
145 // else{
146 // assert(type == ANNOTATION_TYPE_COMMAND_ENCODER);
147 // wgpuCommandEncoderPopDebugGroup(graphicsDevice->commandEncoder);
148 // }
149 }
150
152 {
153 WGPUStringView label = {name.data(), name.length()};
154 if(renderPassEncoder != 0){
155 wgpuRenderPassEncoderInsertDebugMarker(renderPassEncoder, label);
156 }
157 else if(computePassEncoder != 0){
158 wgpuComputePassEncoderInsertDebugMarker(computePassEncoder, label);
159 }
160 // else if(renderBundleEncoder != 0){
161 // wgpuRenderBundleEncoderInsertDebugMarker(renderBundleEncoder, label);
162 // }
163 else{
164 wgpuCommandEncoderInsertDebugMarker(graphicsDevice->commandEncoder, label);
165 }
166 }
167
169 {
170 assert(renderPassEncoder == 0);
171 assert(computePassEncoder == 0);
172 assert(!inRenderPass);
173 inRenderPass = true;
174 update_render_target = false;
175
176 renderTargetHandle = info.renderTargetHandle;
177 depthStencilHandle = info.depthStencilHandle;
178
179 WGPURenderPassColorAttachment color_attachment[8] = {}; // WGPU_RENDER_PASS_COLOR_ATTACHMENT_INIT
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;
183
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;
195 }
196 else{
197 att.resolveTarget = nullptr;
198 }
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];
205 }
206 color_attachment_count = target.count;
207 }
208 if(HandleIsValid(info.depthStencilHandle)){
209 DepthStencilTargetWebGPU &target = graphicsDevice->renderTargets.depth_stencil_targets[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;
221 }
222 }
223 else{
224 name = "Default Render Pass";
225 SwapChainWebGPU &defaultSwapChain = graphicsDevice->defaultSwapChain;
226 if(defaultSwapChain.samples > 1){
227 color_attachment[0].view = defaultSwapChain.colorBufferView;
228 color_attachment[0].resolveTarget = defaultSwapChain.resolveView;
229 }
230 else{
231 color_attachment[0].view = defaultSwapChain.resolveView;
232 }
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;
241
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;
252 }
253
254 if(graphicsDevice->use_error_scope){
255 wgpuDevicePushErrorScope(graphicsDevice->device, graphicsDevice->filter);
256 }
257
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;
263 }
264 if(ds_attachment_count){
265 render_pass_desc.depthStencilAttachment = &ds_attachment;
266 }
267 render_pass_desc.occlusionQuerySet = nullptr;
268 // render_pass_desc.timestampWriteCount = 0;
269 render_pass_desc.timestampWrites = nullptr;
270 renderPassEncoder = wgpuCommandEncoderBeginRenderPass(graphicsDevice->commandEncoder, &render_pass_desc);
271 }
273 {
274 assert(renderPassEncoder);
275 assert(inRenderPass);
276 inRenderPass = false;
277 wgpuRenderPassEncoderEnd(renderPassEncoder);
278 wgpuRenderPassEncoderRelease(renderPassEncoder);
279 renderPassEncoder = 0;
280 update_render_target = true;
281
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);
289 // WGPUWaitStatus wgpuInstanceWaitAny(WGPUInstance instance, size_t futureCount, WGPUFutureWaitInfo * futures, uint64_t timeoutNS);
290 }
291 }
292
294 {
295 if(HandleIsValid(rt_handle))
296 renderTargetHandle = rt_handle;
297 else
298 renderTargetHandle = {};
299 if(HandleIsValid(ds_handle))
300 depthStencilHandle = ds_handle;
301 else
302 depthStencilHandle = {};
303 rasterizeStateHandle = {};
304 blendStateHandle = {};
305 assert(do_clear_render_target == false); // Maybe do update render pass to force clear?
306 assert(do_clear_depth == false); // Maybe do update render pass to force clear?
307 do_clear_render_target = false;
308 do_clear_depth = false;
309 update_render_target = true;
310 }
311
312 void ContextWebGPU::setViewport(const float x, const float y, const float width, const float height)
313 {
314 updateRenderPass();
315 float minDepth = 0.0f; // TODO
316 float maxDepth = 1.0f; // TODO
317 wgpuRenderPassEncoderSetViewport(renderPassEncoder, x, y, width, height, minDepth, maxDepth);
318 }
319
320 void ContextWebGPU::setScissor(const int x, const int y, const int width, const int height)
321 {
322 updateRenderPass();
323 int w, h;
324 graphicsDevice->getSize(w, h); // TODO
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);
330 }
331
333 {
334 if(HandleIsValid(handle))
335 depthStencilStateHandle = handle;
336 else
337 depthStencilStateHandle = {};
338 }
339
340 void ContextWebGPU::setBlendState(const BlendStateHandle handle, const float *constants)
341 {
342 updateRenderPass();
343 if(HandleIsValid(handle))
344 blendStateHandle = handle;
345 else
346 blendStateHandle = {};
347 WGPUColor color; // Emulate dx11 with 1.0f constants if not set
348 if(constants){
349 color.r = constants[0];
350 color.g = constants[1];
351 color.b = constants[2];
352 color.a = constants[3];
353 }
354 else{
355 color.r = 1.0f;
356 color.g = 1.0f;
357 color.b = 1.0f;
358 color.a = 1.0f;
359 }
360 wgpuRenderPassEncoderSetBlendConstant(renderPassEncoder, &color);
361 }
362
364 {
365 if(HandleIsValid(handle))
366 rasterizeStateHandle = handle;
367 else
368 rasterizeStateHandle = {};
369 }
370
371 void ContextWebGPU::setDefaults() {
372 rasterizeStateHandle = {};
373 depthStencilStateHandle = {};
374 blendStateHandle = {};
375 }
376
378 {
379 if(HandleIsValid(handle))
380 effect = handle;
381 else
382 effect = {};
383 inputLayoutHandle = {};
384 descriptors.clear();
385 update_descriptors = true;
386 }
387
388 void ContextWebGPU::setTexture(const StringView& name, unsigned int unit, TextureHandle textureHandle)
389 {
390 setTexture(getEffects()->getTextureBinding(getCurrentEffect(), name, unit), textureHandle);
391 }
392
394 {
395 // WebGPU does not support setting invalid textures, so we remove the binding from the descriptor.
396 // If it is needed we will detect the issue when creatng the bindgroup if the texture is required
397 if (!HandleIsValid(handle)) {
398 descriptors.erase((uint32_t)binding.handle);
399 return;
400 }
401 if (!HandleIsValid(binding)) {
402 return;
403 }
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);
408 assert(group == 0);
409 bg_ent.buffer = nullptr;
410 bg_ent.offset = 0;
411 bg_ent.size = 0;
412 bg_ent.sampler = nullptr;
413 bg_ent.textureView = texture.texture_view;
414 descriptors[bg_ent.binding] = bg_ent;
415 update_descriptors = true;
416 }
417
418 void ContextWebGPU::setTexture(const StringView& name, TextureViewHandle textureViewHandle)
419 {
420 setTexture(getEffects()->getTextureBinding(getCurrentEffect(), name, 1), textureViewHandle);
421 }
422
423 void ContextWebGPU::setTexture(const TextureBindingHandle binding, TextureViewHandle handle)
424 {
425 // WebGPU does not support setting invalid textures, so we remove the binding from the descriptor.
426 // If it is needed we will detect the issue when creatng the bindgroup if the texture is required
427 if (!HandleIsValid(handle)) {
428 descriptors.erase((uint32_t)binding.handle);
429 return;
430 }
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);
435 assert(group == 0);
436 bg_ent.buffer = nullptr;
437 bg_ent.offset = 0;
438 bg_ent.size = 0;
439 bg_ent.sampler = nullptr;
440 bg_ent.textureView = texture_view.texture_view;
441 descriptors[bg_ent.binding] = bg_ent;
442 update_descriptors = true;
443 }
444
445 void ContextWebGPU::setSamplerState(const StringView& name, unsigned int unit, SamplerStateHandle handle)
446 {
447 setSamplerState(getEffects()->getSamplerStateBinding(getCurrentEffect(), name, unit), handle);
448 }
449
451 {
452 // WebGPU does not support setting invalid samplers, so we remove the binding from the descriptor.
453 // If it is needed we will detect the issue when creatng the bindgroup if the sampler is required
454 if (!HandleIsValid(handle)) {
455 descriptors.erase((uint32_t)binding.handle);
456 return;
457 }
458 if (!HandleIsValid(binding)) {
459 return;
460 }
461 SamplerStateWebGPU sampler = graphicsDevice->textures.samplerStates[handle];
462 WGPUBindGroupEntry bg_ent = WGPU_BIND_GROUP_ENTRY_INIT;
463 size_t group = ~(size_t)0;
464 decodeConstantBufferBindingHandle(binding.handle, group, bg_ent.binding);
465 assert(group == 0);
466 bg_ent.buffer = nullptr;
467 bg_ent.offset = 0;
468 bg_ent.size = 0;
469 bg_ent.sampler = sampler.sampler;
470 bg_ent.textureView = nullptr;
471 descriptors[bg_ent.binding] = bg_ent;
472 //WGPUBindGroupLayoutEntry bg_le{
473 // .binding = (uint32_t)binding.handle,
474 // .sampler = {
475 // .type = WGPUSamplerBindingType_Filtering,
476 // }
477 //};
478 update_descriptors = true;
479 }
480
482 {
483 if(HandleIsValid(handle))
484 inputLayoutHandle = handle;
485 else
486 inputLayoutHandle = {};
487 }
488
489 void ContextWebGPU::setVertexBuffers(const VertexBufferHandle* vertexBufferHandles, const size_t count, const uint32_t* /*strides*/, const uint32_t* offsets)
490 {
491 updateRenderPass();
492 for(size_t i=0; i<count; i++){
493 BufferWebGPU buffer = graphicsDevice->buffers.buffers[(BufferHandle)vertexBufferHandles[i].handle];
494 uint32_t slot = (uint32_t)i;
495 // uint32_t stride = strides ? strides[i] : 0;
496 uint32_t offset = offsets ? offsets[i] : 0;
497 wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, slot, buffer.buffer, offset, buffer.size-offset);
498 }
499 }
500
501 void ContextWebGPU::setVertexBuffers(const VertexBufferHandle * handles, const size_t count)
502 {
503 setVertexBuffers(handles, count, nullptr, nullptr);
504 }
505
506 void ContextWebGPU::setIndexBuffer(IndexBufferHandle bufferHandle, uint32_t stride, uint32_t offset_in)
507 {
508 if (bufferHandle == IndexBufferHandle::NoHandle) {
509 return;
510 }
511 updateRenderPass();
512 WGPUIndexFormat format = (stride == 2) ? WGPUIndexFormat_Uint16 : WGPUIndexFormat_Uint32;
513 currentIndexFormat = format;
514 uint64_t offset = offset_in;
515 BufferWebGPU buffer = graphicsDevice->buffers.buffers[(BufferHandle)bufferHandle.handle];
516 wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, buffer.buffer, format, offset, buffer.size);
517 }
518
520 {
521 assert(false); // TODO
522 }
523
524 void ContextWebGPU::setConstantBuffer(const StringView& name, const BufferHandle bufferHandle, const uint32_t offset, const uint32_t size)
525 {
526 setConstantBuffer(getEffects()->getConstantBufferBinding(getCurrentEffect(), name), bufferHandle, offset, size);
527 }
528
529 void ContextWebGPU::setConstantBuffer(const ConstantBufferBindingHandle binding, const BufferHandle handle, const uint32_t offset, const uint32_t size)
530 {
531 // WebGPU does not support setting invalid buffers, so we remove the binding from the descriptor.
532 // If it is needed we will detect the issue when creatng the bindgroup if the buffer is required
533 if (!HandleIsValid(handle)) {
534 descriptors.erase((uint32_t)binding.handle);
535 return;
536 }
537 if (!HandleIsValid(binding)) {
538 return;
539 }
540
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);
545 assert(group == 0);
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;
553 }
554
555 void ContextWebGPU::setBuffer(const StringView& name, BufferHandle bufferHandle)
556 {
557 auto binding = getEffects()->getBufferBinding(getCurrentEffect(), name);
558 setBuffer(binding, bufferHandle);
559 getEffects()->releaseBufferBinding(binding);
560 }
561
562 void ContextWebGPU::setBuffer(const BufferBindingHandle /*bufferBindingHandle*/, BufferHandle /*bufferHandle*/)
563 {
564 assert(false); // TODO
565 }
566
567 void ContextWebGPU::setBufferCounter(BufferHandle /*bufferHandle*/, uint32_t /*value*/)
568 {
569 assert(false); // TODO
570 }
571
572 void ContextWebGPU::setBufferCounter(BufferHandle /*bufferHandle*/, BufferHandle /*sourceBufferHandle*/)
573 {
574 assert(false); // TODO
575 }
576
577 void ContextWebGPU::getBufferCounter(BufferHandle /*bufferHandle*/, BufferHandle /*destinationBufferHandle*/)
578 {
579 assert(false); // TODO
580 }
581
582 void ContextWebGPU::draw(PrimitiveType primitiveType, const size_t startVertex, const size_t numVertexes)
583 {
584 updateRenderPass();
585 if (updateRenderPipeline(primitiveType)) {
586 drawInstanced(primitiveType, startVertex, numVertexes, 0, 1);
587 if (frameStatisticsEnabled) { frameStatisticsAccountDrawCall(numVertexes, false); }
588 }
589 else{
590 LOG_ERROR_ONCE(logger, "skip draw(), updateRenderPipeline failed.");
591 }
592 }
593
594 void ContextWebGPU::drawIndexed(PrimitiveType primitiveType, const size_t startIndex, const size_t numIndexes, const size_t startVertex)
595 {
596 updateRenderPass();
597 if (updateRenderPipeline(primitiveType)) {
598 wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, (uint32_t)numIndexes, 1, (uint32_t)startIndex, (int32_t)startVertex, 0);
599 if (frameStatisticsEnabled) { frameStatisticsAccountDrawCall(numIndexes, true); }
600 }
601 else{
602 LOG_ERROR_ONCE(logger, "skip drawIndexed(), updateRenderPipeline failed.");
603 }
604 }
605
606 void ContextWebGPU::drawInstanced(PrimitiveType primitiveType, const size_t startVertex, const size_t numVertexes, const size_t startInstance, const size_t numInstances)
607 {
608 updateRenderPass();
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); }
612 }
613 else{
614 LOG_ERROR_ONCE(logger, "skip drawInstanced(), updateRenderPipeline failed.");
615 }
616 }
617
618 void ContextWebGPU::drawInstancedIndexed(PrimitiveType primitiveType, const size_t startInstance, const size_t numInstances, const size_t startIndex, const size_t numIndexes)
619 {
620 updateRenderPass();
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); }
624 }
625 else{
626 LOG_ERROR_ONCE(logger, "skip drawInstancedIndexed(), updateRenderPipeline failed.");
627 }
628 }
629
630 void ContextWebGPU::beginRenderPassInt()
631 {
632 assert(renderPassEncoder == 0);
633 assert(computePassEncoder == 0);
634 WGPURenderPassColorAttachment color_attachment[8] = {}; // WGPU_RENDER_PASS_COLOR_ATTACHMENT_INIT
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;
638
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;
653 att.loadOp = loadOp;
654 att.storeOp = WGPUStoreOp_Store;
655 att.clearValue = clearColor[i];
656 }
657 color_attachment_count = target.count;
658 }
659 if(HandleIsValid(depthStencilHandle)){
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;
672 }
673 }
674 else{
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;
680 }
681 else{
682 color_attachment[0].view = defaultSwapChain.resolveView;
683 }
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;
689
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;
700 }
701
702 if(graphicsDevice->use_error_scope){
703 wgpuDevicePushErrorScope(graphicsDevice->device, graphicsDevice->filter);
704 }
705
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;
711 }
712 if(ds_attachment_count){
713 render_pass_desc.depthStencilAttachment = &ds_attachment;
714 }
715 render_pass_desc.occlusionQuerySet = nullptr;
716 // render_pass_desc.timestampWriteCount = 0;
717 render_pass_desc.timestampWrites = nullptr;
718 renderPassEncoder = wgpuCommandEncoderBeginRenderPass(graphicsDevice->commandEncoder, &render_pass_desc);
719 }
720
721 void ContextWebGPU::endRenderPassInt()
722 {
723 assert(!inRenderPass);
724 if(!renderPassEncoder) return;
725 wgpuRenderPassEncoderEnd(renderPassEncoder);
726 wgpuRenderPassEncoderRelease(renderPassEncoder);
727 renderPassEncoder = 0;
728 update_render_target = true;
729
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);
737 // WGPUWaitStatus wgpuInstanceWaitAny(WGPUInstance instance, size_t futureCount, WGPUFutureWaitInfo * futures, uint64_t timeoutNS);
738 }
739 }
740
741 void ContextWebGPU::updateRenderPass()
742 {
743 if(update_render_target){
744 endComputePass();
745 endRenderPassInt();
746 beginRenderPassInt();
747 update_render_target = false;
748 }
749 }
750
751 bool ContextWebGPU::updateRenderPipeline(PrimitiveType primitiveType)
752 {
753 assert(renderPassEncoder);
754 ResourceCountersWebGPU &counters = graphicsDevice->counters;
755 PipelineStatesWebGPU &pipeline_states = graphicsDevice->pipeline_states;
756 bool reload = false;
757 if(HandleIsValid(currentRenderPipeline)){
758 RenderPipelineWebGPU pipelineState = pipeline_states.renderPipeline[currentRenderPipeline];
759 size_t hash = pipeline_states.renderPipelineHash(effect,
760 inputLayoutHandle,
761 primitiveType,
762 rasterizeStateHandle,
763 depthStencilStateHandle,
764 blendStateHandle,
765 renderTargetHandle,
766 depthStencilHandle,
767 currentIndexFormat);
768 if(hash != pipelineState.hash) reload = true;
769 }
770 else{
771 reload = true;
772 }
773 if(reload){
774 RenderPipelineHandle pipelineStateHandle = pipeline_states.loadRenderPipeline
775 (
776 effect,
777 inputLayoutHandle,
778 primitiveType,
779 rasterizeStateHandle,
780 depthStencilStateHandle,
781 blendStateHandle,
782 renderTargetHandle,
783 depthStencilHandle,
784 currentIndexFormat
785 );
786 RenderPipelineWebGPU pipelineState = pipeline_states.renderPipeline[pipelineStateHandle];
787 currentRenderPipeline = pipelineStateHandle;
788 }
789 if(HandleIsValid(currentRenderPipeline)){
790 RenderPipelineWebGPU &pipelineState = pipeline_states.renderPipeline[currentRenderPipeline];
791 wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelineState.pipeline);
792 }
793 if(update_descriptors){
794 RenderPipelineWebGPU &pipelineState = pipeline_states.renderPipeline[currentRenderPipeline];
795
796 std::vector<WGPUBindGroupEntry> entries;
797 entries.resize(descriptors.size());
798 uint32_t i=0;
799 for(auto &tmp : descriptors){
800 entries[i++] = tmp.second;
801 }
804 size_t num_bindings;
805 auto bindings = getEffects()->getConstantBufferBindings(effect, num_bindings);
806
807 for (size_t ii = 0; ii < num_bindings; ii++) {
808 bool found = false;
809 for (size_t j = 0; j < entries.size(); j++) {
810 if (bindings[ii].bg_ent.binding == entries[j].binding) {
811 found = true;
812 }
813 }
814 if (!found) {
815 LOG_ERROR_ONCE(logger, "binding %d in layout but not set (%s)", bindings[ii].bg_ent.binding, bindings[ii].name.c_str());
816 return false;
817 }
818 }
819 for (size_t j = 0; j < entries.size(); j++) {
820 bool found = false;
821 for (size_t ii = 0; ii < num_bindings; ii++) {
822 if (bindings[ii].bg_ent.binding == entries[j].binding) {
823 found = true;
824 }
825 }
826 if (!found) {
827 LOG_ERROR_ONCE(logger, "binding %d is set but not in layout", entries[j].binding);
828 return false;
829 }
830 }
832 WGPUBindGroupDescriptor bg_desc = WGPU_BIND_GROUP_DESCRIPTOR_INIT;
833 // char const * label;
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++;
840 }
841 if(current_bind_group){
842 uint32_t groupIndex = 0;
843 wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, groupIndex, current_bind_group, 0, nullptr);
844 }
845 return true;
846 }
847
848 void ContextWebGPU::dispatchCompute(const unsigned int threadGroupsX, const unsigned int threadGroupsY, const unsigned int threadGroupsZ)
849 {
850 updateComputePass();
851 updateComputePipeline();
852 wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, threadGroupsX, threadGroupsY, threadGroupsZ);
853 }
854
855 void ContextWebGPU::beginComputePass()
856 {
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};
861 // compute_pass_desc.timestampWriteCount = 0;
862 compute_pass_desc.timestampWrites = nullptr;
863 computePassEncoder = wgpuCommandEncoderBeginComputePass(graphicsDevice->commandEncoder, &compute_pass_desc);
864 }
865
866 void ContextWebGPU::endComputePass()
867 {
868 if(!computePassEncoder) return;
869 wgpuComputePassEncoderEnd(computePassEncoder);
870 computePassEncoder = 0;
871 }
872
873 void ContextWebGPU::updateComputePass()
874 {
875 if(!computePassEncoder){
876 // endComputePass();
877 endRenderPassInt();
878 beginComputePass();
879 update_render_target = true;
880 }
881 }
882
883 void ContextWebGPU::updateComputePipeline()
884 {
885 assert(computePassEncoder);
886 ResourceCountersWebGPU &counters = graphicsDevice->counters;
887 PipelineStatesWebGPU &pipeline_states = graphicsDevice->pipeline_states;
888 bool reload = false;
889 if(HandleIsValid(currentComputePipeline)){
890 ComputePipelineWebGPU pipelineState = pipeline_states.computePipeline[currentComputePipeline];
891 if(pipelineState.effect != effect) reload = true;
892 }
893 else{
894 reload = true;
895 }
896 if(reload){
897 ComputePipelineHandle pipelineStateHandle = pipeline_states.loadComputePipeline(effect);
898 ComputePipelineWebGPU pipelineState = pipeline_states.computePipeline[pipelineStateHandle];
899 currentComputePipeline = pipelineStateHandle;
900 }
901 if(HandleIsValid(currentComputePipeline)){
902 ComputePipelineWebGPU &pipelineState = pipeline_states.computePipeline[currentComputePipeline];
903 wgpuComputePassEncoderSetPipeline(computePassEncoder, pipelineState.pipeline);
904 }
905 if(update_descriptors){
906 ComputePipelineWebGPU &pipelineState = pipeline_states.computePipeline[currentComputePipeline];
907
908 std::vector<WGPUBindGroupEntry> entries;
909 entries.resize(descriptors.size());
910 uint32_t i=0;
911 for(auto &tmp : descriptors){
912 entries[i++] = tmp.second;
913 }
914
915 WGPUBindGroupDescriptor bg_desc = WGPU_BIND_GROUP_DESCRIPTOR_INIT;
916 // char const * label;
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++;
923 }
924 if(current_bind_group){
925 uint32_t groupIndex = 0;
926 wgpuComputePassEncoderSetBindGroup(computePassEncoder, groupIndex, current_bind_group, 0, nullptr);
927 }
928 }
929
930 void ContextWebGPU::readDepthBuffer(BufferHandle bufferHandle, int x, int y, int width, int height, Framebuffer)
931 {
932 const WGPUCommandEncoder &commandEncoder = graphicsDevice->commandEncoder;
933 TexturesWebGPU &textures = graphicsDevice->textures;
934 BufferWebGPU buffer = graphicsDevice->buffers.buffers[bufferHandle];
935
936 endRenderPassInt();
937
938 WGPUTexelCopyTextureInfo src = WGPU_TEXEL_COPY_TEXTURE_INFO_INIT;
939 if (HandleIsValid(renderTargetHandle) || HandleIsValid(depthStencilHandle)) {
940 if(!HandleIsValid(depthStencilHandle)) return;
941 DepthStencilTargetWebGPU &target = graphicsDevice->renderTargets.depth_stencil_targets[depthStencilHandle];
942 TextureWebGPU &src_tex = textures.textures[target.textureHandle];
943 src.texture = src_tex.texture;
944 }
945 else{
946 SwapChainWebGPU &defaultSwapChain = graphicsDevice->defaultSwapChain;
947 src.texture = defaultSwapChain.depthBufferTexture;
948 }
949 src.mipLevel = 0;
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;
958 size.width = width;
959 size.height = height;
960 size.depthOrArrayLayers = 1;
961 wgpuCommandEncoderCopyTextureToBuffer(commandEncoder, &src, &dst, &size);
962 }
963
964 void ContextWebGPU::readColorBuffer(BufferHandle bufferHandle, int x, int y, int width, int height, Framebuffer)
965 {
966 const WGPUCommandEncoder &commandEncoder = graphicsDevice->commandEncoder;
967 TexturesWebGPU &textures = graphicsDevice->textures;
968 BufferWebGPU buffer = graphicsDevice->buffers.buffers[bufferHandle];
969
970 endRenderPassInt();
971
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;
978 }
979 else{
980 SwapChainWebGPU &defaultSwapChain = graphicsDevice->defaultSwapChain;
981#ifdef __EMSCRIPTEN__
982 // assert(false); // TODO ...
983 src.texture = defaultSwapChain.colorBufferTexture;
984#else
985 src.texture = defaultSwapChain.resolveTexture;
986#endif
987 }
988 src.mipLevel = 0;
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;
997 size.width = width;
998 size.height = height;
999 size.depthOrArrayLayers = 1;
1000 wgpuCommandEncoderCopyTextureToBuffer(commandEncoder, &src, &dst, &size);
1001 }
1002
1003 void *ContextWebGPU::map(BufferHandle handle, MapMode::EMapMode mapMode, uint32_t* stride)
1004 {
1005 assert(stride == nullptr || stride[0] == 0);
1006 BufferWebGPU &buffer = graphicsDevice->buffers.buffers[handle];
1007 if(buffer.is_read_buffer){
1008 assert(mapMode == MapMode::Read);
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){
1021 // TODO this is bad... (Redesign for callback?)
1022 assert(state == WGPUBufferMapState_Pending);
1023 wgpuInstanceProcessEvents(graphicsDevice->instance);
1024 wgpuDeviceTick(graphicsDevice->device);
1025 state = wgpuBufferGetMapState(buffer.buffer);
1026 }
1027#else
1028 assert(false);
1029#endif
1030
1031 // return wgpuBufferGetMappedRange(buffer.buffer, 0, buffer.size);
1032 return (void*)wgpuBufferGetConstMappedRange(buffer.buffer, 0, buffer.size);
1033 }
1034 else{
1035 assert(mapMode == MapMode::WriteDiscard);
1036 buffer.NextInstance(graphicsDevice, graphicsDevice->buffers);
1037 buffer.map = new char[buffer.size];
1038 return buffer.map;
1039 }
1040 }
1041
1042 void *ContextWebGPU::map(TextureHandle /*textureHandle*/, MapMode::EMapMode /*accessMode*/, uint32_t* /*rowPitch*/, uint32_t* /*depthPitch*/)
1043 {
1044 assert(false); // TODO
1045 return nullptr;
1046 }
1047
1049 {
1050 BufferWebGPU &buffer = graphicsDevice->buffers.buffers[handle];
1051 if(buffer.is_read_buffer){
1052 // WGPUBufferMapState state = wgpuBufferGetMapState(buffer.buffer);
1053 // if(state == WGPUBufferMapState_Mapped)
1054 wgpuBufferUnmap(buffer.buffer);
1055 }
1056 else{
1057 // const WGPUCommandEncoder &commandEncoder = graphicsDevice->commandEncoder;
1058 // wgpuCommandEncoderWriteBuffer(commandEncoder, buffer.buffer, 0, (uint8_t*)buffer.map, buffer.size);
1059 if(buffer.size > 0){
1060 wgpuQueueWriteBuffer(graphicsDevice->queue, buffer.buffer, 0, buffer.map, buffer.size);
1061 if(uploadStatisticsEnabled) uploadStatisticsBufferUpload(buffer.size);
1062 }
1063 delete [] (char*)buffer.map;
1064 buffer.map = nullptr;
1065 }
1066 }
1067
1068 void ContextWebGPU::unmap(TextureHandle /*textureHandle*/)
1069 {
1070 assert(false); // TODO
1071 }
1072
1073 void ContextWebGPU::updateBuffer(BufferHandle handle, const void* data, const size_t size)
1074 {
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);
1079 return;
1080 }
1081 buffer.NextInstance(graphicsDevice, graphicsDevice->buffers);
1082 wgpuQueueWriteBuffer(graphicsDevice->queue, buffer.buffer, 0, data, size);
1083 if(uploadStatisticsEnabled) uploadStatisticsBufferUpload(size);
1084 }
1085
1086 void ContextWebGPU::updateSubTexture(TextureHandle textureHandle, const size_t level, const void* data)
1087 {
1088 assert(HandleIsValid(textureHandle) && "Texture handle is invalid.");
1089
1090 TextureWebGPU & texture = graphicsDevice->textures.textures[textureHandle];
1091
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));
1094
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 };
1100
1101 const Cogs::FormatInfo *textureFormat = Cogs::getFormatInfo(texture.format);
1102
1103 WGPUTexelCopyBufferLayout sourceLayout;
1104 sourceLayout.offset = 0;
1105 sourceLayout.bytesPerRow = textureFormat->blockSize * ((width + textureFormat->blockExtent.width - 1) / textureFormat->blockExtent.width);
1106 sourceLayout.rowsPerImage = (height + textureFormat->blockExtent.height - 1) / textureFormat->blockExtent.height;
1107
1108 size_t size = sourceLayout.bytesPerRow * sourceLayout.rowsPerImage;
1109
1110 WGPUExtent3D extent;
1111 extent.width = width;
1112 extent.height = height;
1113 extent.depthOrArrayLayers = 1;
1114
1115 wgpuQueueWriteTexture(graphicsDevice->queue, &destinationTexture, data, static_cast<size_t>(size), &sourceLayout, &extent);
1116
1117 if(uploadStatisticsEnabled) uploadStatisticsTextureUpload(texture.estimatedByteSize); // TODO size?
1118 }
1119
1120 void ContextWebGPU::updateSubBuffer(BufferHandle handle, const size_t offset, const size_t size, const void* data)
1121 {
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);
1126 return;
1127 }
1128 assert(buffer.alias_idx == 0); // TODO Copy over alias buffer data...
1129 buffer.alias_idx++;
1130 wgpuQueueWriteBuffer(graphicsDevice->queue, buffer.buffer, offset, data, size);
1131 if(uploadStatisticsEnabled) uploadStatisticsBufferUpload(size);
1132 }
1133
1135 {
1136 assert(false); // TODO
1137 }
1138
1139 void ContextWebGPU::copyResource(BufferHandle /*destinationHandle*/, BufferHandle /*sourceHandle*/)
1140 {
1141 assert(false); // TODO
1142 }
1143
1144 void ContextWebGPU::copyResource(TextureHandle /*destinationHandle*/, TextureHandle /*sourceHandle*/)
1145 {
1146 assert(false); // TODO
1147 }
1148
1149 void ContextWebGPU::copyTexture(TextureHandle dstHandle, unsigned dstSub, unsigned dstX, unsigned dstY, unsigned dstZ, TextureHandle srcHandle, unsigned srcSub)
1150 {
1151 graphicsDevice->maybeCreateUploadCommandEncoder();
1152 const WGPUCommandEncoder &commandEncoder = graphicsDevice->commandEncoder;
1153 TexturesWebGPU &textures = graphicsDevice->textures;
1154
1155 TextureWebGPU &src = textures.textures[srcHandle];
1156 TextureWebGPU &dst = textures.textures[dstHandle];
1157
1158 uint32_t srcLevel = 0; // TODO srcSub%LevelCount
1159 uint32_t srcLayer = srcSub; // TODO srcSub/LevelCount
1160
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;
1166
1167 uint32_t dstLevel = 0; // TODO dstSub%LevelCount
1168 uint32_t dstLayer = dstSub; // TODO dstSub/LevelCount
1169
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;
1175
1176 WGPUExtent3D size = WGPU_EXTENT_3D_INIT;
1177 size.width = src.width;
1178 size.height = src.height;
1179 size.depthOrArrayLayers = 1;
1180 wgpuCommandEncoderCopyTextureToTexture(commandEncoder, &copy_src, &copy_dst, &size);
1181 }
1182
1183 void ContextWebGPU::clearResource(BufferHandle /*destinationHandle*/, uint32_t* /*values*/)
1184 {
1185 assert(false); // TODO
1186 }
1187
1188 void ContextWebGPU::clearResource(BufferHandle /*destinationHandle*/, float* /*values*/)
1189 {
1190 assert(false); // TODO
1191 }
1192
1193 void ContextWebGPU::beginFrame() {
1194 prevStats = currStats;
1195 currStats = FrameStatistics{};
1196
1197 prevUploadStats = currUploadStats;
1198 currUploadStats = UploadStatistics{};
1199 }
1200
1201 void ContextWebGPU::frameStatisticsAccountDrawCall(size_t count, bool indexed)
1202 {
1203 // bucket is position of most significant bit, zero is zero.
1204 unsigned bucket = 0;
1205 size_t t = count;
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; }
1211
1212#ifdef _DEBUG
1213 assert(uint64_t(count) < (uint64_t(1) << (bucket + 1)));
1214 if (count) {
1215 assert((uint64_t(1) << bucket) <= uint64_t(count));
1216 }
1217 else {
1218 assert(bucket == 0);
1219 }
1220#endif
1221
1222 currStats.drawCallHistogram[bucket]++;
1223 currStats.vertices += count;
1224 if (indexed) currStats.indices += count;
1225 }
1226
1227 void ContextWebGPU::uploadStatisticsBufferUpload(size_t size)
1228 {
1229 currUploadStats.bufferUploads++;
1230 currUploadStats.bufferUploadSize += size;
1231 }
1232
1233 void ContextWebGPU::uploadStatisticsTextureUpload(size_t size)
1234 {
1235 currUploadStats.textureUploads++;
1236 currUploadStats.textureUploadSize += size;
1237 }
1238
1239 EffectHandle ContextWebGPU::getCurrentEffect()
1240 {
1241 return effect;
1242 }
1243
1244 EffectsWebGPU *ContextWebGPU::getEffects()
1245 {
1246 return &graphicsDevice->effects;
1247 }
1248
1249 void ContextWebGPU::ClearBindGroups()
1250 {
1251 ResourceCountersWebGPU &counters = graphicsDevice->counters;
1252 for(auto &bg : last_bind_groups){
1253 wgpuBindGroupRelease(bg);
1254 counters.bind_group--;
1255 }
1256 last_bind_groups.clear();
1257 }
1258 void ContextWebGPU::SwapBindGroups()
1259 {
1260 last_bind_groups = std::move(bind_groups);
1261 }
1262}
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.
Definition: EffectsWebGPU.h:88
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.
Definition: LogManager.h:140
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:50
constexpr const char * data() const noexcept
Get the sequence of characters referenced by the string view.
Definition: StringView.h:197
constexpr size_t length() const noexcept
Get the length of the string.
Definition: StringView.h:211
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
Definition: LogManager.h:181
Contains all Cogs related functionality.
Definition: FieldSetter.h:23
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
Definition: HashFunctions.h:62
Framebuffer
Framebuffers to select from when doing framebuffer operations.
Definition: Common.h:147
PrimitiveType
Primitive types for interpreting vertex data sent to the graphics pipeline.
Definition: Common.h:112
uint8_t blockSize
Bytesize of one block of data.
Definition: DataFormat.h:257
TextureExtent blockExtent
Number of data items in a block.
Definition: DataFormat.h:258
Handle template class used to provide opaque, non-converting handles.
Definition: Common.h:23
static const Handle_t NoHandle
Represents a handle to nothing.
Definition: Common.h:78
handle_type handle
Internal resource handle.
Definition: Common.h:75
EMapMode
Mapping mode enumeration.
Definition: Flags.h:93
@ WriteDiscard
Write access. When unmapping the graphics system will discard the old contents of the resource.
Definition: Flags.h:103