Partial: remove pipelines - render pass & draw call fixes
Francesco Pasa 10 months ago
Francesco Pasa 10 months ago
src/helpers.c M +86
20 alba_vector_print(&attribute->uv);
21 printf("}\n");
22 }
23+
24+WGPUBuffer create_buffer(
25+ const AlbaWindow* window,
26+ const uint64_t size, const void* data,
27+ const WGPUBufferUsageFlags flags
28+)
29+{
30+ WGPUBufferDescriptor buffer_options = {0};
31+ buffer_options.usage = WGPUBufferUsage_CopyDst | flags;
32+ buffer_options.size = size;
33+ const WGPUBuffer buffer = wgpuDeviceCreateBuffer(window->device, &buffer_options);
34+ wgpuQueueWriteBuffer(window->queue, buffer, 0, data, size);
35+ return buffer;
36+}
37+
38+void release_buffer(const WGPUBuffer buffer)
39+{
40+ if (buffer != NULL)
41+ {
42+ wgpuBufferDestroy(buffer);
43+ wgpuBufferRelease(buffer);
44+ }
45+}
46+
47+WGPUBuffer update_buffer(
48+ const AlbaWindow* window, WGPUBuffer buffer, const WGPUBufferUsage usage, AlbaArray data
49+)
50+{
51+ // Deallocate old buffer if any
52+ release_buffer(buffer);
53+ // Copy data to new buffer
54+ buffer = create_buffer(window, data.length * data.element_size, data.data, usage);
55+ // Clear local copy for next frame
56+ alba_array_clear(&data);
57+ return buffer;
58+}
59+
60+WGPUTexture create_texture(
61+ const AlbaWindow* window,
62+ const WGPUTextureUsage usage,
63+ const AlbaVector size,
64+ const WGPUTextureFormat format, const uint8_t samples,
65+ const void* data
66+)
67+{
68+ WGPUTextureDescriptor texture_options = {0};
69+ texture_options.usage = usage;
70+ texture_options.format = format;
71+ texture_options.dimension = WGPUTextureDimension_2D;
72+ texture_options.size.width = size.x;
73+ texture_options.size.height = size.y;
74+ texture_options.size.depthOrArrayLayers = 1;
75+ texture_options.sampleCount = samples;
76+ texture_options.mipLevelCount = 1;
77+
78+ const WGPUTexture texture = wgpuDeviceCreateTexture(window->device, &texture_options);
79+
80+ if (data != NULL)
81+ {
82+ const uint64_t bpp = format == WGPUTextureFormat_R8Unorm ? 1 : 4;
83+
84+ WGPUImageCopyTexture destination = {0};
85+ destination.texture = texture;
86+ destination.aspect = WGPUTextureAspect_All;
87+
88+ WGPUTextureDataLayout source = {0};
89+ source.bytesPerRow = size.x * bpp;
90+ source.rowsPerImage = size.y;
91+
92+ wgpuQueueWriteTexture(
93+ window->queue,
94+ &destination, data,
95+ size.x * size.y * bpp,
96+ &source,
97+ &texture_options.size
98+ );
99+ }
100+
101+ return texture;
102+}
103+
104+void release_texture(const WGPUTexture texture)
105+{
106+ wgpuTextureDestroy(texture);
107+ wgpuTextureRelease(texture);
108+}
src/internal.h M +14 -10
9
10 #define NO_TEXTURE {-1, -1}
11
12+// Window
13 typedef struct
14 {
15 // if set, the next frame will update the buffers
39 WGPUAdapter adapter;
40 WGPUDevice device;
41 WGPUQueue queue;
42+ WGPUCommandEncoder command_encoder;
43 WGPUShaderModule shaders;
44 WGPURenderPipeline pipeline;
45 WGPUBuffer uniforms;
75
76 // Helpers
77 WGPUSurface get_window_surface(WGPUInstance instance, AlbaWindow* window);
78+
79+WGPUBuffer create_buffer(
80+ const AlbaWindow* window,
81+ uint64_t size, const void* data,
82+ WGPUBufferUsageFlags flags
83+);
84+void release_buffer(WGPUBuffer buffer);
85+WGPUBuffer update_buffer(
86+ const AlbaWindow* window, WGPUBuffer buffer, WGPUBufferUsage usage, AlbaArray data
87+);
88+
89 WGPUTexture create_texture(
90 const AlbaWindow* window,
91 WGPUTextureUsage usage,
93 WGPUTextureFormat format, uint8_t samples,
94 const void* data
95 );
96-
97-// Drawng
98-void draw_triangles_indexed_render_pass(
99- DrawCall* data,
100- uint32_t num_vertices,
101- const AlbaVector* vertices,
102- const AlbaAttribute* attributes,
103- uint32_t num_indices,
104- uint32_t* indices
105-);
106+void release_texture(WGPUTexture texture);
107
108 // Global variables
109 static int glfw_initialized = 0;
src/window.c M +71 -145
11
12 extern char _binary_shaders_wgsl_start[];
13
14-WGPUBuffer create_buffer(
15- const AlbaWindow* window,
16- const uint64_t size, const void* data,
17- const WGPUBufferUsageFlags flags
18-)
19-{
20- WGPUBufferDescriptor buffer_options = {0};
21- buffer_options.usage = WGPUBufferUsage_CopyDst | flags;
22- buffer_options.size = size;
23- const WGPUBuffer buffer = wgpuDeviceCreateBuffer(window->device, &buffer_options);
24- wgpuQueueWriteBuffer(window->queue, buffer, 0, data, size);
25- return buffer;
26-}
27-
28-void clear_buffer(const WGPUBuffer buffer)
29-{
30- if (buffer != NULL)
31- {
32- wgpuBufferDestroy(buffer);
33- wgpuBufferRelease(buffer);
34- }
35-}
36-
37-WGPUBuffer update_buffer(
38- const AlbaWindow* window, WGPUBuffer buffer, const WGPUBufferUsage usage, AlbaArray data
39-)
40-{
41- // Deallocate old buffer if any
42- clear_buffer(buffer);
43- // Copy data to new buffer
44- buffer = create_buffer(window, data.length * data.element_size, data.data, usage);
45- // Clear local copy for next frame
46- alba_array_clear(&data);
47- return buffer;
48-}
49-
50 void on_receive_adapter(
51 const WGPURequestAdapterStatus status,
52 const WGPUAdapter adapter,
58 fprintf(stderr, "error (%d): %s", type, message);
59 }
60
61-WGPUTexture create_texture(
62- const AlbaWindow* window,
63- const WGPUTextureUsage usage,
64- const AlbaVector size,
65- const WGPUTextureFormat format, const uint8_t samples,
66- const void* data
67-)
68-{
69- WGPUTextureDescriptor texture_options = {0};
70- texture_options.usage = usage;
71- texture_options.format = format;
72- texture_options.dimension = WGPUTextureDimension_2D;
73- texture_options.size.width = size.x;
74- texture_options.size.height = size.y;
75- texture_options.size.depthOrArrayLayers = 1;
76- texture_options.sampleCount = samples;
77- texture_options.mipLevelCount = 1;
78-
79- const WGPUTexture texture = wgpuDeviceCreateTexture(window->device, &texture_options);
80-
81- if (data != NULL)
82- {
83- const uint64_t bpp = format == WGPUTextureFormat_R8Unorm ? 1 : 4;
84-
85- WGPUImageCopyTexture destination = {0};
86- destination.texture = texture;
87- destination.aspect = WGPUTextureAspect_All;
88-
89- WGPUTextureDataLayout source = {0};
90- source.bytesPerRow = size.x * bpp;
91- source.rowsPerImage = size.y;
92-
93- wgpuQueueWriteTexture(
94- window->queue,
95- &destination, data,
96- size.x * size.y * bpp,
97- &source,
98- &texture_options.size
99- );
100- }
101-
102- return texture;
103-}
104
105 // TODO: reorganize code
106 WGPUPipelineLayout configure_resources(const AlbaWindow* window, DrawCall* data)
342 on_receive_device,
343 &window->device
344 );
345-
346- // Errors
347 wgpuDeviceSetUncapturedErrorCallback(window->device, on_error, NULL);
348- // Queue
349- window->queue = wgpuDeviceGetQueue(window->device);
350
351+ window->queue = wgpuDeviceGetQueue(window->device);
352+ window->command_encoder = wgpuDeviceCreateCommandEncoder(window->device, NULL);
353
354 configure_pipeline(window);
355 configure_surface(window);
356
357- // This is necessary to initialize buffers
358- window->layers[0].drawing.dirty = 1;
359- window->layers[0].text.dirty = 1;
360-
361 return window;
362 }
363
372 alba_array_release(&window->draw_calls);
373
374 wgpuBindGroupRelease(window->uniforms_bind_group);
375- clear_buffer(window->uniforms);
376+ release_buffer(window->uniforms);
377 wgpuRenderPipelineRelease(window->pipeline);
378 wgpuShaderModuleRelease(window->shaders);
379+ wgpuCommandEncoderRelease(window->command_encoder);
380 wgpuQueueRelease(window->queue);
381 wgpuDeviceRelease(window->device);
382 wgpuAdapterRelease(window->adapter);
418 dst->a = src.a;
419 }
420
421-void render_pass(
422- AlbaWindow* window,
423- const WGPUTextureView frame,
424- const WGPUTextureView render_target,
425- const int clear,
426- DrawCall* data
427+
428+void draw_objects(
429+ const AlbaWindow* window,
430+ const WGPURenderPassEncoder render_pass
431 )
432 {
433- if (data->dirty)
434+ wgpuRenderPassEncoderSetPipeline(render_pass, window->pipeline);
435+ for (uint64_t i = 0; i < window->draw_calls.length; i++)
436 {
437- // TODO: optimize (and only recreate the necessary pipeline)
438- configure_pipeline(window);
439- data->vertices = update_buffer(window, data->vertices, WGPUBufferUsage_Vertex, data->new_vertices);
440- data->attributes = update_buffer(window, data->attributes, WGPUBufferUsage_Vertex, data->new_attributes);
441- data->indices = update_buffer(window, data->indices, WGPUBufferUsage_Index, data->new_indices);
442- data->dirty = 0;
443- }
444+ DrawCall* draw_call = &window->draw_calls.data[i];
445
446- const WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(window->device, NULL);
447+ wgpuRenderPassEncoderSetBindGroup(render_pass, 0, draw_call->bind_group, 0, NULL);
448
449- // Configures rendering
450- WGPURenderPassColorAttachment render_pass_attachment_options = {0};
451- render_pass_attachment_options.view = render_target;
452- render_pass_attachment_options.loadOp = clear ? WGPULoadOp_Clear : WGPULoadOp_Load;
453- render_pass_attachment_options.storeOp = WGPUStoreOp_Store;
454- render_pass_attachment_options.resolveTarget = frame;
455- copy_color(window->options.clear_color, &render_pass_attachment_options.clearValue);
456-
457- WGPURenderPassDescriptor render_pass_options = {0};
458- render_pass_options.colorAttachmentCount = 1;
459- render_pass_options.colorAttachments = &render_pass_attachment_options;
460-
461- const WGPURenderPassEncoder render_pass = wgpuCommandEncoderBeginRenderPass(
462- encoder, &render_pass_options);
463+ if (draw_call->dirty)
464+ {
465+ // // TODO: optimize (and only recreate the necessary pipeline)
466+ // configure_pipeline(window);
467+ draw_call->vertices = update_buffer(
468+ window, draw_call->vertices, WGPUBufferUsage_Vertex, draw_call->new_vertices);
469+ draw_call->attributes = update_buffer(
470+ window, draw_call->attributes, WGPUBufferUsage_Vertex, draw_call->new_attributes);
471+ draw_call->indices = update_buffer(
472+ window, draw_call->indices, WGPUBufferUsage_Index, draw_call->new_indices);
473+ draw_call->dirty = 0;
474+ }
475
476- wgpuRenderPassEncoderSetPipeline(render_pass, data->pipeline);
477- wgpuRenderPassEncoderSetBindGroup(render_pass, 0, data->bind_group, 0, NULL);
478+ const uint32_t vertex_size = wgpuBufferGetSize(draw_call->vertices);
479+ const uint32_t attributes_size = wgpuBufferGetSize(draw_call->attributes);
480+ const uint32_t indices_size = wgpuBufferGetSize(draw_call->indices);
481+ if (vertex_size > 0)
482+ {
483+ wgpuRenderPassEncoderSetVertexBuffer(
484+ render_pass, 0, draw_call->vertices, 0, vertex_size);
485+ wgpuRenderPassEncoderSetVertexBuffer(
486+ render_pass, 1, draw_call->attributes, 0, attributes_size);
487+ wgpuRenderPassEncoderSetIndexBuffer(
488+ render_pass, draw_call->indices, WGPUIndexFormat_Uint32, 0, indices_size);
489+ wgpuRenderPassEncoderDrawIndexed(
490+ render_pass, indices_size / sizeof(uint32_t), 1, 0, 0, 0);
491+ }
492
493- const uint32_t vertex_size = wgpuBufferGetSize(data->vertices);
494- const uint32_t attributes_size = wgpuBufferGetSize(data->attributes);
495- const uint32_t indices_size = wgpuBufferGetSize(data->indices);
496- if (vertex_size > 0)
497- {
498- wgpuRenderPassEncoderSetVertexBuffer(render_pass, 0, data->vertices, 0, vertex_size);
499- wgpuRenderPassEncoderSetVertexBuffer(render_pass, 1, data->attributes, 0, attributes_size);
500- wgpuRenderPassEncoderSetIndexBuffer(render_pass, data->indices, WGPUIndexFormat_Uint32, 0,
501- indices_size);
502- wgpuRenderPassEncoderDrawIndexed(render_pass, indices_size / sizeof(uint32_t), 1, 0, 0, 0);
503+ // Encode render command and send to GPU
504+ const WGPUCommandBuffer command = wgpuCommandEncoderFinish(window->command_encoder, NULL);
505+ wgpuQueueSubmit(window->queue, 1, &command);
506+ wgpuCommandBufferRelease(command);
507 }
508-
509- wgpuRenderPassEncoderEnd(render_pass);
510-
511- // Encode render command and send to GPU
512- const WGPUCommandBuffer command = wgpuCommandEncoderFinish(encoder, NULL);
513- wgpuQueueSubmit(window->queue, 1, &command);
514-
515- wgpuCommandBufferRelease(command);
516- wgpuRenderPassEncoderRelease(render_pass);
517- wgpuCommandEncoderRelease(encoder);
518 }
519
520 void alba_window_render(AlbaWindow* window)
521 {
522+ // Setup textures for rendering
523+ // --------------------------------------------
524 WGPUSurfaceTexture frame;
525 wgpuSurfaceGetCurrentTexture(window->surface, &frame);
526 if (!frame_status_is_valid(window, frame))
506 return;
507 }
508
509+ // Draw commands
510+ // --------------------------------------------
511+ const WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(window->device, NULL);
512+
513+ // Configures rendering
514+ WGPURenderPassColorAttachment render_pass_attachment_options = {0};
515+ render_pass_attachment_options.view = render_target_view;
516+ render_pass_attachment_options.loadOp = WGPULoadOp_Clear;
517+ render_pass_attachment_options.storeOp = WGPUStoreOp_Store;
518+ render_pass_attachment_options.resolveTarget = frame;
519+ copy_color(window->options.clear_color, &render_pass_attachment_options.clearValue);
520+
521+ WGPURenderPassDescriptor render_pass_options = {0};
522+ render_pass_options.colorAttachmentCount = 1;
523+ render_pass_options.colorAttachments = &render_pass_attachment_options;
524+
525+ const WGPURenderPassEncoder render_pass = wgpuCommandEncoderBeginRenderPass(
526+ encoder, &render_pass_options);
527+
528 // Draw calls
529- render_pass(window, frame_view, render_target_view, 1, &window->layers[0].drawing);
530+ draw_objects(window, render_pass);
531
532- // Update screen
533+ // Update screen & cleanup
534+ // --------------------------------------------
535 wgpuSurfacePresent(window->surface);
536
537+ wgpuRenderPassEncoderEnd(render_pass);
538+ wgpuRenderPassEncoderRelease(render_pass);
539+
540 wgpuTextureViewRelease(render_target_view);
541+ release_texture(render_target);
542 wgpuTextureViewRelease(frame_view);
543- wgpuTextureDestroy(render_target);
544- wgpuTextureRelease(render_target);
545- wgpuTextureDestroy(frame.texture);
546- wgpuTextureRelease(frame.texture);
547+ release_texture(frame.texture);
548 }
549
550