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 drawInstanced(primitiveType, startVertex, numVertexes, 0, 1);
585 }
586
587 void ContextWebGPU::drawIndexed(PrimitiveType primitiveType, const size_t startIndex, const size_t numIndexes, const size_t startVertex)
588 {
589 updateRenderPass();
590 if (updateRenderPipeline(primitiveType)) {
591 wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, (uint32_t)numIndexes, 1, (uint32_t)startIndex, (int32_t)startVertex, 0);
592 if (frameStatisticsEnabled) { frameStatisticsAccountDrawCall(numIndexes, true); }
593 }
594 else{
595 LOG_ERROR_ONCE(logger, "skip drawIndexed(), updateRenderPipeline failed.");
596 }
597 }
598
599 void ContextWebGPU::drawInstanced(PrimitiveType primitiveType, const size_t startVertex, const size_t numVertexes, const size_t startInstance, const size_t numInstances)
600 {
601 updateRenderPass();
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); }
605 }
606 else{
607 LOG_ERROR_ONCE(logger, "skip draw()/drawInstanced(), updateRenderPipeline failed.");
608 }
609 }
610
611 void ContextWebGPU::drawInstancedIndexed(PrimitiveType primitiveType, const size_t startInstance, const size_t numInstances, const size_t startIndex, const size_t numIndexes)
612 {
613 updateRenderPass();
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); }
617 }
618 else{
619 LOG_ERROR_ONCE(logger, "skip drawInstancedIndexed(), updateRenderPipeline failed.");
620 }
621 }
622
623 void ContextWebGPU::beginRenderPassInt()
624 {
625 assert(renderPassEncoder == 0);
626 assert(computePassEncoder == 0);
627 WGPURenderPassColorAttachment color_attachment[8] = {}; // WGPU_RENDER_PASS_COLOR_ATTACHMENT_INIT
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;
631
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;
646 att.loadOp = loadOp;
647 att.storeOp = WGPUStoreOp_Store;
648 att.clearValue = clearColor[i];
649 }
650 color_attachment_count = target.count;
651 }
652 if(HandleIsValid(depthStencilHandle)){
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;
665 }
666 }
667 else{
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;
673 }
674 else{
675 color_attachment[0].view = defaultSwapChain.resolveView;
676 }
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;
682
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;
693 }
694
695 if(graphicsDevice->use_error_scope){
696 wgpuDevicePushErrorScope(graphicsDevice->device, graphicsDevice->filter);
697 }
698
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;
704 }
705 if(ds_attachment_count){
706 render_pass_desc.depthStencilAttachment = &ds_attachment;
707 }
708 render_pass_desc.occlusionQuerySet = nullptr;
709 // render_pass_desc.timestampWriteCount = 0;
710 render_pass_desc.timestampWrites = nullptr;
711 renderPassEncoder = wgpuCommandEncoderBeginRenderPass(graphicsDevice->commandEncoder, &render_pass_desc);
712 }
713
714 void ContextWebGPU::endRenderPassInt()
715 {
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;
724
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);
732 // WGPUWaitStatus wgpuInstanceWaitAny(WGPUInstance instance, size_t futureCount, WGPUFutureWaitInfo * futures, uint64_t timeoutNS);
733 }
734 }
735
736 void ContextWebGPU::updateRenderPass()
737 {
738 if(update_render_target){
739 endComputePass();
740 endRenderPassInt();
741 beginRenderPassInt();
742 update_render_target = false;
743 }
744 }
745
746 bool ContextWebGPU::updateRenderPipeline(PrimitiveType primitiveType)
747 {
748 assert(renderPassEncoder);
749 ResourceCountersWebGPU &counters = graphicsDevice->counters;
750 PipelineStatesWebGPU &pipeline_states = graphicsDevice->pipeline_states;
751 bool reload = false;
752 if(HandleIsValid(currentRenderPipeline)){
753 RenderPipelineWebGPU pipelineState = pipeline_states.renderPipeline[currentRenderPipeline];
754 size_t hash = pipeline_states.renderPipelineHash(effect,
755 inputLayoutHandle,
756 primitiveType,
757 rasterizeStateHandle,
758 depthStencilStateHandle,
759 blendStateHandle,
760 renderTargetHandle,
761 depthStencilHandle,
762 currentIndexFormat);
763 if(hash != pipelineState.hash) reload = true;
764 }
765 else{
766 reload = true;
767 }
768 if(reload){
769 RenderPipelineHandle pipelineStateHandle = pipeline_states.loadRenderPipeline
770 (
771 effect,
772 inputLayoutHandle,
773 primitiveType,
774 rasterizeStateHandle,
775 depthStencilStateHandle,
776 blendStateHandle,
777 renderTargetHandle,
778 depthStencilHandle,
779 currentIndexFormat
780 );
781 RenderPipelineWebGPU pipelineState = pipeline_states.renderPipeline[pipelineStateHandle];
782 currentRenderPipeline = pipelineStateHandle;
783 }
784 if(HandleIsValid(currentRenderPipeline)){
785 RenderPipelineWebGPU &pipelineState = pipeline_states.renderPipeline[currentRenderPipeline];
786 wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelineState.pipeline);
787 }
788 if(update_descriptors){
789 update_descriptors = false;
790 RenderPipelineWebGPU &pipelineState = pipeline_states.renderPipeline[currentRenderPipeline];
791
792 std::vector<WGPUBindGroupEntry> entries;
793 entries.resize(descriptors.size());
794 uint32_t i=0;
795 for(auto &tmp : descriptors){
796 entries[i++] = tmp.second;
797 }
798 descriptor_count += (uint32_t)descriptors.size();
801 size_t num_bindings;
802 auto bindings = getEffects()->getConstantBufferBindings(effect, num_bindings);
803
804 for (size_t ii = 0; ii < num_bindings; ii++) {
805 bool found = false;
806 for (size_t j = 0; j < entries.size(); j++) {
807 if (bindings[ii].bg_ent.binding == entries[j].binding) {
808 found = true;
809 }
810 }
811 if (!found) {
812 LOG_ERROR_ONCE(logger, "binding %d in layout but not set (%s)", bindings[ii].bg_ent.binding, bindings[ii].name.c_str());
813 return false;
814 }
815 }
816 for (size_t j = 0; j < entries.size(); j++) {
817 bool found = false;
818 for (size_t ii = 0; ii < num_bindings; ii++) {
819 if (bindings[ii].bg_ent.binding == entries[j].binding) {
820 found = true;
821 }
822 }
823 if (!found) {
824 LOG_ERROR_ONCE(logger, "binding %d is set but not in layout", entries[j].binding);
825 return false;
826 }
827 }
829 WGPUBindGroupDescriptor bg_desc = WGPU_BIND_GROUP_DESCRIPTOR_INIT;
830 // char const * label;
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++;
837 }
838 if(current_bind_group){
839 uint32_t groupIndex = 0;
840 wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, groupIndex, current_bind_group, 0, nullptr);
841 }
842 return true;
843 }
844
845 void ContextWebGPU::dispatchCompute(const unsigned int threadGroupsX, const unsigned int threadGroupsY, const unsigned int threadGroupsZ)
846 {
847 updateComputePass();
848 updateComputePipeline();
849 wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, threadGroupsX, threadGroupsY, threadGroupsZ);
850 }
851
852 void ContextWebGPU::beginComputePass()
853 {
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};
858 // compute_pass_desc.timestampWriteCount = 0;
859 compute_pass_desc.timestampWrites = nullptr;
860 computePassEncoder = wgpuCommandEncoderBeginComputePass(graphicsDevice->commandEncoder, &compute_pass_desc);
861 }
862
863 void ContextWebGPU::endComputePass()
864 {
865 if(!computePassEncoder) return;
866 wgpuComputePassEncoderEnd(computePassEncoder);
867 wgpuComputePassEncoderRelease(computePassEncoder);
868 computePassEncoder = 0;
869 }
870
871 void ContextWebGPU::updateComputePass()
872 {
873 if(!computePassEncoder){
874 endRenderPassInt();
875 beginComputePass();
876 update_render_target = true;
877 }
878 }
879
880 void ContextWebGPU::updateComputePipeline()
881 {
882 assert(computePassEncoder);
883 ResourceCountersWebGPU &counters = graphicsDevice->counters;
884 PipelineStatesWebGPU &pipeline_states = graphicsDevice->pipeline_states;
885 bool reload = false;
886 if(HandleIsValid(currentComputePipeline)){
887 ComputePipelineWebGPU pipelineState = pipeline_states.computePipeline[currentComputePipeline];
888 if(pipelineState.effect != effect) reload = true;
889 }
890 else{
891 reload = true;
892 }
893 if(reload){
894 ComputePipelineHandle pipelineStateHandle = pipeline_states.loadComputePipeline(effect);
895 ComputePipelineWebGPU pipelineState = pipeline_states.computePipeline[pipelineStateHandle];
896 currentComputePipeline = pipelineStateHandle;
897 }
898 if(HandleIsValid(currentComputePipeline)){
899 ComputePipelineWebGPU &pipelineState = pipeline_states.computePipeline[currentComputePipeline];
900 wgpuComputePassEncoderSetPipeline(computePassEncoder, pipelineState.pipeline);
901 }
902 if(update_descriptors){
903 update_descriptors = false;
904 ComputePipelineWebGPU &pipelineState = pipeline_states.computePipeline[currentComputePipeline];
905
906 std::vector<WGPUBindGroupEntry> entries;
907 entries.resize(descriptors.size());
908 uint32_t i=0;
909 for(auto &tmp : descriptors){
910 entries[i++] = tmp.second;
911 }
912 descriptor_count += (uint32_t)descriptors.size();
913
914 WGPUBindGroupDescriptor bg_desc = WGPU_BIND_GROUP_DESCRIPTOR_INIT;
915 // char const * label;
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++;
922 }
923 if(current_bind_group){
924 uint32_t groupIndex = 0;
925 wgpuComputePassEncoderSetBindGroup(computePassEncoder, groupIndex, current_bind_group, 0, nullptr);
926 }
927 }
928
929 void ContextWebGPU::readDepthBuffer(BufferHandle bufferHandle, int x, int y, int width, int height, Framebuffer)
930 {
931 const WGPUCommandEncoder &commandEncoder = graphicsDevice->commandEncoder;
932 TexturesWebGPU &textures = graphicsDevice->textures;
933 BufferWebGPU buffer = graphicsDevice->buffers.buffers[bufferHandle];
934
935 endRenderPassInt();
936
937 WGPUTexelCopyTextureInfo src = WGPU_TEXEL_COPY_TEXTURE_INFO_INIT;
938 if (HandleIsValid(renderTargetHandle) || HandleIsValid(depthStencilHandle)) {
939 if(!HandleIsValid(depthStencilHandle)) return;
940 DepthStencilTargetWebGPU &target = graphicsDevice->renderTargets.depth_stencil_targets[depthStencilHandle];
941 TextureWebGPU &src_tex = textures.textures[target.textureHandle];
942 src.texture = src_tex.texture;
943 }
944 else{
945 SwapChainWebGPU &defaultSwapChain = graphicsDevice->defaultSwapChain;
946 src.texture = defaultSwapChain.depthBufferTexture;
947 }
948 src.mipLevel = 0;
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;
957 size.width = width;
958 size.height = height;
959 size.depthOrArrayLayers = 1;
960 wgpuCommandEncoderCopyTextureToBuffer(commandEncoder, &src, &dst, &size);
961 }
962
963 void ContextWebGPU::readColorBuffer(BufferHandle bufferHandle, int x, int y, int width, int height, Framebuffer)
964 {
965 const WGPUCommandEncoder &commandEncoder = graphicsDevice->commandEncoder;
966 TexturesWebGPU &textures = graphicsDevice->textures;
967 BufferWebGPU buffer = graphicsDevice->buffers.buffers[bufferHandle];
968
969 endRenderPassInt();
970
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;
977 }
978 else{
979 SwapChainWebGPU &defaultSwapChain = graphicsDevice->defaultSwapChain;
980#ifdef __EMSCRIPTEN__
981 // assert(false); // TODO ...
982 src.texture = defaultSwapChain.colorBufferTexture;
983#else
984 src.texture = defaultSwapChain.resolveTexture;
985#endif
986 }
987 src.mipLevel = 0;
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;
996 size.width = width;
997 size.height = height;
998 size.depthOrArrayLayers = 1;
999 wgpuCommandEncoderCopyTextureToBuffer(commandEncoder, &src, &dst, &size);
1000 }
1001
1002 void *ContextWebGPU::map(BufferHandle handle, MapMode::EMapMode mapMode, uint32_t* stride)
1003 {
1004 assert(stride == nullptr || stride[0] == 0);
1005 BufferWebGPU &buffer = graphicsDevice->buffers.buffers[handle];
1006 if(buffer.is_read_buffer){
1007 assert(mapMode == MapMode::Read);
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){
1020 // TODO this is bad... (Redesign for callback?)
1021 assert(state == WGPUBufferMapState_Pending);
1022 wgpuInstanceProcessEvents(graphicsDevice->instance);
1023 wgpuDeviceTick(graphicsDevice->device);
1024 state = wgpuBufferGetMapState(buffer.buffer);
1025 }
1026#else
1027 assert(false);
1028#endif
1029
1030 return (void*)wgpuBufferGetConstMappedRange(buffer.buffer, 0, buffer.size);
1031 }
1032 else{
1033 assert(mapMode == MapMode::WriteDiscard);
1034 buffer.NextInstance(graphicsDevice, graphicsDevice->buffers);
1035 buffer.map = new char[buffer.size];
1036 return buffer.map;
1037 }
1038 }
1039
1040 void *ContextWebGPU::map(TextureHandle /*textureHandle*/, MapMode::EMapMode /*accessMode*/, uint32_t* /*rowPitch*/, uint32_t* /*depthPitch*/)
1041 {
1042 assert(false); // TODO
1043 return nullptr;
1044 }
1045
1047 {
1048 BufferWebGPU &buffer = graphicsDevice->buffers.buffers[handle];
1049 if(buffer.is_read_buffer){
1050 // WGPUBufferMapState state = wgpuBufferGetMapState(buffer.buffer);
1051 // if(state == WGPUBufferMapState_Mapped)
1052 wgpuBufferUnmap(buffer.buffer);
1053 }
1054 else{
1055 if(buffer.size > 0){
1056 wgpuQueueWriteBuffer(graphicsDevice->queue, buffer.buffer, 0, buffer.map, buffer.size);
1057 if(uploadStatisticsEnabled) uploadStatisticsBufferUpload(buffer.size);
1058 }
1059 delete [] (char*)buffer.map;
1060 buffer.map = nullptr;
1061 }
1062 }
1063
1064 void ContextWebGPU::unmap(TextureHandle /*textureHandle*/)
1065 {
1066 assert(false); // TODO
1067 }
1068
1069 void ContextWebGPU::updateBuffer(BufferHandle handle, const void* data, const size_t size)
1070 {
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);
1076 return;
1077 }
1078 buffer.NextInstance(graphicsDevice, graphicsDevice->buffers);
1079 wgpuQueueWriteBuffer(graphicsDevice->queue, buffer.buffer, 0, data, size);
1080 if(uploadStatisticsEnabled) uploadStatisticsBufferUpload(size);
1081 }
1082
1083 void ContextWebGPU::updateSubTexture(TextureHandle textureHandle, const size_t level, const void* data)
1084 {
1085 assert(HandleIsValid(textureHandle) && "Texture handle is invalid.");
1086
1087 TextureWebGPU & texture = graphicsDevice->textures.textures[textureHandle];
1088
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));
1091
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 };
1097
1098 const Cogs::FormatInfo *textureFormat = Cogs::getFormatInfo(texture.format);
1099
1100 WGPUTexelCopyBufferLayout sourceLayout;
1101 sourceLayout.offset = 0;
1102 sourceLayout.bytesPerRow = textureFormat->blockSize * ((width + textureFormat->blockExtent.width - 1) / textureFormat->blockExtent.width);
1103 sourceLayout.rowsPerImage = (height + textureFormat->blockExtent.height - 1) / textureFormat->blockExtent.height;
1104
1105 size_t size = sourceLayout.bytesPerRow * sourceLayout.rowsPerImage;
1106
1107 WGPUExtent3D extent;
1108 extent.width = width;
1109 extent.height = height;
1110 extent.depthOrArrayLayers = 1;
1111
1112 wgpuQueueWriteTexture(graphicsDevice->queue, &destinationTexture, data, static_cast<size_t>(size), &sourceLayout, &extent);
1113
1114 if(uploadStatisticsEnabled) uploadStatisticsTextureUpload(texture.estimatedByteSize); // TODO size?
1115 }
1116
1117 void ContextWebGPU::updateSubBuffer(BufferHandle handle, const size_t offset, const size_t size, const void* data)
1118 {
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);
1124 return;
1125 }
1126 assert(buffer.alias_idx == 0); // TODO Copy over alias buffer data...
1127 buffer.alias_idx++;
1128 wgpuQueueWriteBuffer(graphicsDevice->queue, buffer.buffer, offset, data, size);
1129 if(uploadStatisticsEnabled) uploadStatisticsBufferUpload(size);
1130 }
1131
1133 {
1134 assert(false); // TODO
1135 }
1136
1137 void ContextWebGPU::copyResource(BufferHandle /*destinationHandle*/, BufferHandle /*sourceHandle*/)
1138 {
1139 assert(false); // TODO
1140 }
1141
1142 void ContextWebGPU::copyResource(TextureHandle /*destinationHandle*/, TextureHandle /*sourceHandle*/)
1143 {
1144 assert(false); // TODO
1145 }
1146
1147 void ContextWebGPU::copyTexture(TextureHandle dstHandle, unsigned dstSub, unsigned dstX, unsigned dstY, unsigned dstZ, TextureHandle srcHandle, unsigned srcSub)
1148 {
1149 graphicsDevice->maybeCreateUploadCommandEncoder();
1150 const WGPUCommandEncoder &commandEncoder = graphicsDevice->commandEncoder;
1151 TexturesWebGPU &textures = graphicsDevice->textures;
1152
1153 TextureWebGPU &src = textures.textures[srcHandle];
1154 TextureWebGPU &dst = textures.textures[dstHandle];
1155
1156 uint32_t srcLevel = 0; // TODO srcSub%LevelCount
1157 uint32_t srcLayer = srcSub; // TODO srcSub/LevelCount
1158
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;
1164
1165 uint32_t dstLevel = 0; // TODO dstSub%LevelCount
1166 uint32_t dstLayer = dstSub; // TODO dstSub/LevelCount
1167
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;
1173
1174 WGPUExtent3D size = WGPU_EXTENT_3D_INIT;
1175 size.width = src.width;
1176 size.height = src.height;
1177 size.depthOrArrayLayers = 1;
1178 wgpuCommandEncoderCopyTextureToTexture(commandEncoder, &copy_src, &copy_dst, &size);
1179 }
1180
1181 void ContextWebGPU::clearResource(BufferHandle /*destinationHandle*/, uint32_t* /*values*/)
1182 {
1183 assert(false); // TODO
1184 }
1185
1186 void ContextWebGPU::clearResource(BufferHandle /*destinationHandle*/, float* /*values*/)
1187 {
1188 assert(false); // TODO
1189 }
1190
1191 void ContextWebGPU::beginFrame() {
1192 prevStats = currStats;
1193 currStats = FrameStatistics{};
1194
1195 prevUploadStats = currUploadStats;
1196 currUploadStats = UploadStatistics{};
1197 }
1198
1199 void ContextWebGPU::frameStatisticsAccountDrawCall(size_t count, bool indexed)
1200 {
1201 // bucket is position of most significant bit, zero is zero.
1202 unsigned bucket = 0;
1203 size_t t = count;
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; }
1209
1210#ifdef _DEBUG
1211 assert(uint64_t(count) < (uint64_t(1) << (bucket + 1)));
1212 if (count) {
1213 assert((uint64_t(1) << bucket) <= uint64_t(count));
1214 }
1215 else {
1216 assert(bucket == 0);
1217 }
1218#endif
1219
1220 currStats.drawCallHistogram[bucket]++;
1221 currStats.vertices += count;
1222 if (indexed) currStats.indices += count;
1223 }
1224
1225 void ContextWebGPU::uploadStatisticsBufferUpload(size_t size)
1226 {
1227 currUploadStats.bufferUploads++;
1228 currUploadStats.bufferUploadSize += size;
1229 }
1230
1231 void ContextWebGPU::uploadStatisticsTextureUpload(size_t size)
1232 {
1233 currUploadStats.textureUploads++;
1234 currUploadStats.textureUploadSize += size;
1235 }
1236
1237 EffectHandle ContextWebGPU::getCurrentEffect()
1238 {
1239 return effect;
1240 }
1241
1242 EffectsWebGPU *ContextWebGPU::getEffects()
1243 {
1244 return &graphicsDevice->effects;
1245 }
1246
1247 void ContextWebGPU::ClearBindGroups()
1248 {
1249 ResourceCountersWebGPU &counters = graphicsDevice->counters;
1250 for(auto &bg : last_bind_groups){
1251 wgpuBindGroupRelease(bg);
1252 counters.bind_group--;
1253 }
1254 last_bind_groups.clear();
1255 current_bind_group = {};
1256 update_descriptors = true;
1257
1258 counters.descriptor_count = descriptor_count;
1259 descriptor_count = 0;
1260 }
1261 void ContextWebGPU::SwapBindGroups()
1262 {
1263 last_bind_groups = std::move(bind_groups);
1264 }
1265}
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