Fix build on Wayland

Francesco Pasa 2 weeks ago

src/draw_call.c   M +16 -28

1 #include "alba.h"
2 #include "internal.h"
3 
4-DrawCall* window_create_draw_call(AlbaWindow* window)
5-{
6+DrawCall *window_create_draw_call(AlbaWindow *window) {
7     DrawCall draw_call = {0};
8     draw_call.buffers_dirty = 1;
9     draw_call.bind_group_dirty = 1;
13     return alba_array_last(&window->draw_calls);
14 }
15 
16-void window_set_texture(AlbaWindow* window, const WGPUTexture texture)
17-{
18-    DrawCall* draw_call = alba_array_last(&window->draw_calls);
19-    if (draw_call->texture_set)
20-    {
21+void window_set_texture(AlbaWindow *window, const WGPUTexture texture) {
22+    DrawCall *draw_call = alba_array_last(&window->draw_calls);
23+    if (draw_call->texture_set) {
24         draw_call = window_create_draw_call(window);
25     }
26     draw_call_set_texture(draw_call, texture);
27     draw_call->texture_set = 1;
28 }
29 
30-void window_clear(AlbaWindow* window)
31-{
32+void window_clear(AlbaWindow *window) {
33     alba_array_clear(&window->draw_calls);
34 }
35 
36-void clear_texture_bind_group(const DrawCall* draw_call)
37-{
38+void clear_texture_bind_group(const DrawCall *draw_call) {
39     wgpuBindGroupRelease(draw_call->bind_group);
40 }
41 
42-void draw_call_set_texture(DrawCall* draw_call, const WGPUTexture texture)
43-{
44-    if (draw_call->view != NULL)
45-    {
46+void draw_call_set_texture(DrawCall *draw_call, const WGPUTexture texture) {
47+    if (draw_call->view != NULL) {
48         wgpuTextureViewRelease(draw_call->view);
49     }
50-    if (draw_call->texture != NULL)
51-    {
52+    if (draw_call->texture != NULL) {
53         wgpuTextureDestroy(draw_call->texture);
54         wgpuTextureRelease(draw_call->texture);
55     }
44     draw_call->bind_group_dirty = 1;
45 }
46 
47-void draw_call_update_bind_group(const AlbaWindow* window, DrawCall* draw_call)
48-{
49+void draw_call_update_bind_group(const AlbaWindow *window, DrawCall *draw_call) {
50     WGPUBindGroupEntry bind_group_entries[2] = {0};
51 
52     // Texture
53-    if (draw_call->texture == NULL)
54-    {
55+    if (draw_call->texture == NULL) {
56         draw_call_set_texture(
57             draw_call,
58             // 1x1 white texture
56                 window,
57                 WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopyDst,
58                 (AlbaVector){1, 1},
59-                WGPUTextureFormat_RGBA8UnormSrgb, 1,
60+                window->surface_format,
61+                1,
62                 &(AlbaColor)WHITE
63             )
64         );
68     bind_group_entries[0].textureView = draw_call->view;
69 
70     // Sampler
71-    if (draw_call->sampler == NULL)
72-    {
73+    if (draw_call->sampler == NULL) {
74         WGPUSamplerDescriptor sampler_options = {0};
75         sampler_options.addressModeU = WGPUAddressMode_ClampToEdge;
76         sampler_options.addressModeV = WGPUAddressMode_ClampToEdge;
 91     binding_group_options.entryCount = 2;
 92     binding_group_options.entries = bind_group_entries;
 93 
 94-    if (draw_call->bind_group != NULL)
 95-    {
 96+    if (draw_call->bind_group != NULL) {
 97         wgpuBindGroupRelease(draw_call->bind_group);
 98     }
 99     draw_call->bind_group = wgpuDeviceCreateBindGroup(window->device, &binding_group_options);
100 }
101 
102-void draw_call_release(const DrawCall* draw_call)
103-{
104+void draw_call_release(const DrawCall *draw_call) {
105     wgpuBufferDestroy(draw_call->vertices);
106     wgpuBufferRelease(draw_call->vertices);
107     alba_array_release(&draw_call->new_vertices);

src/helpers.c   M +18 -28

 3 
 4 #include <stdio.h>
 5 
 6-void alba_color_print(const AlbaColor* color)
 7-{
 8+void alba_color_print(const AlbaColor *color) {
 9     printf("AlbaColor{%f, %f, %f, %f}\n", color->r, color->g, color->b, color->a);
10 }
11 
12-int alba_color_is_transparent(const AlbaColor* color)
13-{
14+int alba_color_is_transparent(const AlbaColor *color) {
15     return color->r == 0 && color->g == 0 && color->b == 0 && color->a == 0;
16 }
17 
18-void alba_vector_print(const AlbaVector* vector)
19-{
20+void alba_vector_print(const AlbaVector *vector) {
21     printf("AlbaVector{%f, %f}\n", vector->x, vector->y);
22 }
23 
24-void alba_attribute_print(const AlbaAttribute* attribute)
25-{
26+void alba_attribute_print(const AlbaAttribute *attribute) {
27     printf("AlbaAttribute{\n    ");
28     alba_color_print(&attribute->color);
29     printf("    ");
24 }
25 
26 WGPUBuffer create_buffer(
27-    const AlbaWindow* window,
28-    const uint64_t size, const void* data,
29+    const AlbaWindow *window,
30+    const uint64_t size, const void *data,
31     const WGPUBufferUsageFlags flags
32-)
33-{
34+) {
35     WGPUBufferDescriptor buffer_options = {0};
36     buffer_options.usage = WGPUBufferUsage_CopyDst | flags;
37     buffer_options.size = size;
36     return buffer;
37 }
38 
39-void release_buffer(const WGPUBuffer buffer)
40-{
41-    if (buffer != NULL)
42-    {
43+void release_buffer(const WGPUBuffer buffer) {
44+    if (buffer != NULL) {
45         wgpuBufferDestroy(buffer);
46         wgpuBufferRelease(buffer);
47     }
48 }
49 
50 WGPUBuffer update_buffer(
51-    const AlbaWindow* window, WGPUBuffer buffer, const WGPUBufferUsage usage, AlbaArray data
52-)
53-{
54+    const AlbaWindow *window, WGPUBuffer buffer, const WGPUBufferUsage usage, AlbaArray data
55+) {
56     // Deallocate old buffer if any
57     release_buffer(buffer);
58     // Copy data to new buffer
56 }
57 
58 WGPUTexture create_texture(
59-    const AlbaWindow* window,
60+    const AlbaWindow *window,
61     const WGPUTextureUsage usage,
62     const AlbaVector size,
63-    const WGPUTextureFormat format, const uint8_t samples,
64-    const void* data
65-)
66-{
67+    const WGPUTextureFormat format,
68+    const uint8_t samples,
69+    const void *data
70+) {
71     WGPUTextureDescriptor texture_options = {0};
72     texture_options.usage = usage;
73     texture_options.format = format;
75 
76     const WGPUTexture texture = wgpuDeviceCreateTexture(window->device, &texture_options);
77 
78-    if (data != NULL)
79-    {
80+    if (data != NULL) {
81         const uint64_t bpp = format == WGPUTextureFormat_R8Unorm ? 1 : 4;
82 
83         WGPUImageCopyTexture destination = {0};
 98     return texture;
 99 }
100 
101-void release_texture(const WGPUTexture texture)
102-{
103+void release_texture(const WGPUTexture texture) {
104     wgpuTextureDestroy(texture);
105     wgpuTextureRelease(texture);
106 }

src/internal.h   M +40 -32

12 #define NO_TEXTURE {-1, -1}
13 
14 // Window
15-typedef struct
16-{
17+typedef struct {
18     AlbaString string; // needed?
19     AlbaVector position;
20     // Make part of style?
21     FT_Face face; // needed?
22     AlbaTextStyle style;
23     uint32_t glyph_count;
24-    hb_glyph_info_t* glyphs_infos;
25-    hb_glyph_position_t* glyph_positions;
26+    hb_glyph_info_t *glyphs_infos;
27+    hb_glyph_position_t *glyph_positions;
28 } Text;
29 
30-typedef struct
31-{
32+typedef struct {
33     int buffers_dirty;
34     AlbaArray new_vertices;
35     AlbaArray new_attributes;
43     WGPUBindGroup bind_group;
44 } DrawCall;
45 
46-void draw_call_generate_text(const AlbaWindow* window, DrawCall* draw_call);
47-void draw_call_set_texture(DrawCall* draw_call, WGPUTexture texture);
48-void draw_call_update_bind_group(const AlbaWindow* window, DrawCall* draw_call);
49-void draw_call_release(const DrawCall* draw_call);
50+void draw_call_generate_text(const AlbaWindow *window, DrawCall *draw_call);
51 
52-typedef struct AlbaWindowImpl
53-{
54+void draw_call_set_texture(DrawCall *draw_call, WGPUTexture texture);
55+
56+void draw_call_update_bind_group(const AlbaWindow *window, DrawCall *draw_call);
57+
58+void draw_call_release(const DrawCall *draw_call);
59+
60+typedef struct AlbaWindowImpl {
61     AlbaWindowOptions options;
62-    GLFWwindow* glfw_window;
63+    GLFWwindow *glfw_window;
64     AlbaVector size;
65     AlbaVector scale;
66     WGPUInstance instance;
68     WGPUBindGroup uniforms_bind_group;
69     WGPUBindGroupLayout texture_bind_group_layout;
70     AlbaArray draw_calls;
71+    WGPUTextureFormat surface_format;
72 } AlbaWindow;
73 
74-DrawCall* window_create_draw_call(AlbaWindow* window);
75-void window_set_texture(AlbaWindow* window, WGPUTexture texture);
76-void window_clear(AlbaWindow* window);
77+DrawCall *window_create_draw_call(AlbaWindow *window);
78+
79+void window_set_texture(AlbaWindow *window, WGPUTexture texture);
80+
81+void window_clear(AlbaWindow *window);
82 
83 // Atlas
84-typedef struct
85-{
86+typedef struct {
87     // Key properties
88     uint32_t codepoint;
89     AlbaTextStyle style;
 91     AlbaVector end;
 92 } AlbaGlyph;
 93 
 94-typedef struct
 95-{
 96-    struct hashmap* glyphs;
 97+typedef struct {
 98+    struct hashmap *glyphs;
 99     int dirty;
100     AlbaArray glyph_sizes; // in w, h order
101     AlbaVector size;
102-    uint8_t* image;
103+    uint8_t *image;
104 } Atlas;
105 
106 Atlas create_atlas(uint32_t capacity);
107-void atlas_reserve(Atlas* atlas, uint32_t capacity);
108-void atlas_append(Atlas* atlas, FT_Face face, uint32_t codepoint, AlbaTextStyle style);
109-void atlas_generate_image(Atlas* atlas);
110-void atlas_release(const Atlas* atlas);
111+
112+void atlas_reserve(Atlas *atlas, uint32_t capacity);
113+
114+void atlas_append(Atlas *atlas, FT_Face face, uint32_t codepoint, AlbaTextStyle style);
115+
116+void atlas_generate_image(Atlas *atlas);
117+
118+void atlas_release(const Atlas *atlas);
119 
120 // Helpers
121-WGPUSurface get_window_surface(WGPUInstance instance, AlbaWindow* window);
122+WGPUSurface get_window_surface(WGPUInstance instance, AlbaWindow *window);
123 
124 WGPUBuffer create_buffer(
125-    const AlbaWindow* window,
126-    uint64_t size, const void* data,
127+    const AlbaWindow *window,
128+    uint64_t size, const void *data,
129     WGPUBufferUsageFlags flags
130 );
131+
132 void release_buffer(WGPUBuffer buffer);
133+
134 WGPUBuffer update_buffer(
135-    const AlbaWindow* window, WGPUBuffer buffer, WGPUBufferUsage usage, AlbaArray data
136+    const AlbaWindow *window, WGPUBuffer buffer, WGPUBufferUsage usage, AlbaArray data
137 );
138 
139 WGPUTexture create_texture(
140-    const AlbaWindow* window,
141+    const AlbaWindow *window,
142     WGPUTextureUsage usage,
143     AlbaVector size,
144     WGPUTextureFormat format, uint8_t samples,
145-    const void* data
146+    const void *data
147 );
148+
149 void release_texture(WGPUTexture texture);
150 
151 // Global variables

src/text.c   M +33 -49

1-#include <X11/extensions/render.h>
2-
3 #include "alba.h"
4 #include "internal.h"
5 
13 Atlas atlas;
14 pthread_mutex_t freetype_mutex = PTHREAD_MUTEX_INITIALIZER;
15 
16-void ensure_freetype_initialized()
17-{
18+void ensure_freetype_initialized() {
19     // already initialized
20     if (freetype != NULL) return;
21 
22     pthread_mutex_lock(&freetype_mutex);
23-    if (FT_Init_FreeType(&freetype))
24-    {
25+    if (FT_Init_FreeType(&freetype)) {
26         fprintf(stderr, "error: initializeing FreeType failed");
27         pthread_mutex_unlock(&freetype_mutex);
28         exit(1);
31         0, // face index
32         &roboto
33     );
34-    if (error)
35-    {
36+    if (error) {
37         fprintf(stderr, "error: cound not load built in Roboto font");
38     }
39 
 41 }
 42 
 43 void atlas_add_chars(
 44-    Atlas* atlas,
 45-    const uint32_t glyph_count, const hb_glyph_info_t* glyph_infos,
 46+    Atlas *atlas,
 47+    const uint32_t glyph_count, const hb_glyph_info_t *glyph_infos,
 48     const AlbaTextStyle style
 49-)
 50-{
 51-    for (uint32_t i = 0; i < glyph_count; i++)
 52-    {
 53+) {
 54+    for (uint32_t i = 0; i < glyph_count; i++) {
 55         atlas_append(atlas, roboto, glyph_infos[i].codepoint, style);
 56     }
 57 }
 58 
 59-uint64_t hash_glyph2(const void* item, const uint64_t seed0, const uint64_t seed1)
 60-{
 61-    return hashmap_murmur((FT_Long*)item, sizeof(FT_Long), seed0, seed1);
 62+uint64_t hash_glyph2(const void *item, const uint64_t seed0, const uint64_t seed1) {
 63+    return hashmap_murmur((FT_Long *) item, sizeof(FT_Long), seed0, seed1);
 64 }
 65 
 66 void atlas_generate_text_geometry(
 67-    const Atlas* atlas,
 68-    const Text* text,
 69-    const AlbaWindow* window,
 70-    DrawCall* draw_call
 71-)
 72-{
 73+    const Atlas *atlas,
 74+    const Text *text,
 75+    const AlbaWindow *window,
 76+    DrawCall *draw_call
 77+) {
 78     const AlbaTextStyle style = text->style;
 79-    AlbaArray* vertices = &draw_call->new_vertices;
 80-    AlbaArray* attributes = &draw_call->new_attributes;
 81-    AlbaArray* indices = &draw_call->new_indices;
 82+    AlbaArray *vertices = &draw_call->new_vertices;
 83+    AlbaArray *attributes = &draw_call->new_attributes;
 84+    AlbaArray *indices = &draw_call->new_indices;
 85 
 86     alba_array_reserve(vertices, vertices->length + text->glyph_count * 4);
 87     alba_array_reserve(attributes, attributes->length + text->glyph_count * 4);
 88     alba_array_reserve(indices, indices->length + text->glyph_count * 6);
 89 
 90     AlbaVector current = text->position;
 91-    for (uint32_t i = 0; i < text->glyph_count; i++)
 92-    {
 93+    for (uint32_t i = 0; i < text->glyph_count; i++) {
 94         // TODO: mutex?
 95         const uint32_t codepoint = text->glyphs_infos[i].codepoint;
 96-        const AlbaGlyph* glyph = hashmap_get(
 97+        const AlbaGlyph *glyph = hashmap_get(
 98             atlas->glyphs,
 99             &(AlbaGlyph){
100                 .codepoint = codepoint,
101                 .style = style
102             }
103         );
104-        if (glyph == NULL)
105-        {
106-            fprintf(stderr, "error: unable to find glyph for codepoint '%s'\n", (char*)&codepoint);
107+        if (glyph == NULL) {
108+            fprintf(stderr, "error: unable to find glyph for codepoint '%s'\n", (char *) &codepoint);
109             exit(1);
110         }
111 
112-        const hb_glyph_position_t* pos = &text->glyph_positions[i];
113+        const hb_glyph_position_t *pos = &text->glyph_positions[i];
114         const FT_Glyph_Metrics metrics = glyph->metrics;
115 
116         // All these / 64 are because FreeType reports metrics in 1/64th of pixel
132     }
133 }
134 
135-void draw_call_generate_text(const AlbaWindow* window, DrawCall* draw_call)
136-{
137-    for (uint64_t i = 0; i < draw_call->new_texts.length; i++)
138-    {
139-        const Text* text = draw_call->new_texts.data + i * draw_call->new_texts.element_size;
140+void draw_call_generate_text(const AlbaWindow *window, DrawCall *draw_call) {
141+    for (uint64_t i = 0; i < draw_call->new_texts.length; i++) {
142+        const Text *text = draw_call->new_texts.data + i * draw_call->new_texts.element_size;
143         atlas_generate_text_geometry(&atlas, text, window, draw_call);
144     }
145 }
146 
147 void alba_draw_text(
148-    AlbaWindow* window,
149+    AlbaWindow *window,
150     const AlbaVector pos,
151     const AlbaString string,
152     AlbaTextStyle style
153-)
154-{
155+) {
156     ensure_freetype_initialized();
157 
158     if (style.font_size == 0) style.font_size = 16;
159     if (alba_color_is_transparent(&style.color)) style.color = (AlbaColor)WHITE;
160 
161-    const char* chars = alba_string_to_char(&string);
162-    hb_buffer_t* buffer = hb_buffer_create();
163+    const char *chars = alba_string_to_char(&string);
164+    hb_buffer_t *buffer = hb_buffer_create();
165 
166     // TODO: remove assumption that string is in a single script
167     const hb_script_t script = HB_SCRIPT_LATIN;
170         style.font_size * window->scale.x,
171         style.font_size * window->scale.y
172     );
173-    if (error)
174-    {
175+    if (error) {
176         fprintf(stderr, "error: cound not set Roboto face size");
177     }
178 
178         {HB_TAG('l', 'i', 'g', 'a'), 1, HB_FEATURE_GLOBAL_START, HB_FEATURE_GLOBAL_END},
179     };
180 
181-    hb_font_t* hb_font = hb_ft_font_create_referenced(roboto); // TODO: free
182+    hb_font_t *hb_font = hb_ft_font_create_referenced(roboto); // TODO: free
183     hb_shape(hb_font, buffer, features, 1);
184 
185     Text text = {
193     atlas_add_chars(&atlas, text.glyph_count, text.glyphs_infos, style);
194     pthread_mutex_unlock(&freetype_mutex);
195 
196-    DrawCall* draw_call = alba_array_last(&window->draw_calls);
197-    if (draw_call->texture_set)
198-    {
199+    DrawCall *draw_call = alba_array_last(&window->draw_calls);
200+    if (draw_call->texture_set) {
201         draw_call = window_create_draw_call(window);
202     }
203     alba_array_append(&draw_call->new_texts, &text);

src/window.c   M +70 -106

17 void on_receive_adapter(
18     const WGPURequestAdapterStatus status,
19     const WGPUAdapter adapter,
20-    char const* message,
21-    void* data
22-)
23-{
24-    if (status != WGPURequestAdapterStatus_Success)
25-    {
26+    char const *message,
27+    void *data
28+) {
29+    if (status != WGPURequestAdapterStatus_Success) {
30         fprintf(stderr, "error: requesting adapter failed: %s", message);
31         exit(1);
32     }
33 
34-    *((WGPUAdapter*)data) = adapter;
35+    *((WGPUAdapter *) data) = adapter;
36 }
37 
38-void on_device_lost_error(const WGPUDeviceLostReason reason, char const* message, void* userdata)
39-{
40+void on_device_lost_error(const WGPUDeviceLostReason reason, char const *message, void *userdata) {
41     fprintf(stderr, "error: device lost error (%d): %s", reason, message);
42     exit(1);
43 }
36 void on_receive_device(
37     const WGPURequestDeviceStatus status,
38     const WGPUDevice device,
39-    char const* message,
40-    void* data
41-)
42-{
43-    if (status != WGPURequestDeviceStatus_Success)
44-    {
45+    char const *message,
46+    void *data
47+) {
48+    if (status != WGPURequestDeviceStatus_Success) {
49         fprintf(stderr, "error: requesting device failed: %s", message);
50         exit(1);
51     }
52 
53-    *((WGPUDevice*)data) = device;
54+    *((WGPUDevice *) data) = device;
55 }
56 
57-void on_error(const WGPUErrorType type, char const* message, void* data)
58-{
59-    if (type == WGPUErrorType_NoError)
60-    {
61+void on_error(const WGPUErrorType type, char const *message, void *data) {
62+    if (type == WGPUErrorType_NoError) {
63         return;
64     }
65     fprintf(stderr, "error (%d): %s", type, message);
66 }
67 
68 
69-void create_uniform_bind_group(AlbaWindow* window, const WGPUBindGroupLayout bind_group_layout)
70-{
71+void create_uniform_bind_group(AlbaWindow *window, const WGPUBindGroupLayout bind_group_layout) {
72     const float uniforms_default_value[2] = {1, 1};
73     window->uniforms = create_buffer(
74         window,
76     window->uniforms_bind_group = wgpuDeviceCreateBindGroup(window->device, &binding_group_options);
77 }
78 
79-WGPUPipelineLayout configure_bind_group_layout(AlbaWindow* window)
80-{
81+WGPUPipelineLayout configure_bind_group_layout(AlbaWindow *window) {
82     WGPUBindGroupLayout bind_groups[2];
83 
84     // @group(0) - Uniforms (scale)
130 }
131 
132 
133-void configure_surface(AlbaWindow* window)
134-{
135+void configure_surface(AlbaWindow *window) {
136     int width, height;
137     float x_scale, y_scale;
138     glfwGetWindowSize(window->glfw_window, &width, &height);
146     // Update uniforms
147     wgpuQueueWriteBuffer(window->queue, window->uniforms, 0, &scaled_size, sizeof(AlbaVector));
148 
149-    const WGPUTextureFormat format = wgpuSurfaceGetPreferredFormat(window->surface, window->adapter);
150-
151     WGPUSurfaceConfiguration surface_options = {0};
152     surface_options.device = window->device;
153-    surface_options.format = format;
154+    surface_options.format = window->surface_format;
155     surface_options.usage = WGPUTextureUsage_RenderAttachment;
156     surface_options.presentMode = WGPUPresentMode_Fifo;
157     surface_options.width = width;
156     wgpuSurfaceConfigure(window->surface, &surface_options);
157 }
158 
159-void configure_pipeline(AlbaWindow* window)
160-{
161+void configure_pipeline(AlbaWindow *window) {
162     // Load shaders
163     // --------------------------------------------
164     WGPUShaderModuleWGSLDescriptor shader_options = {0};
164     shader_options.code = _binary_shaders_wgsl_start;
165 
166     WGPUShaderModuleDescriptor shader_loader_options = {0};
167-    shader_loader_options.nextInChain = (WGPUChainedStruct*)&shader_options;
168+    shader_loader_options.nextInChain = (WGPUChainedStruct *) &shader_options;
169 
170     window->shaders = wgpuDeviceCreateShaderModule(window->device, &shader_loader_options);
171 
229         }
230     };
231     WGPUColorTargetState color_state = {0};
232-    color_state.format = WGPUTextureFormat_BGRA8UnormSrgb; // TODO: avoid hardcoding
233+    color_state.format = window->surface_format;
234     color_state.blend = &blend_state;
235     color_state.writeMask = WGPUColorWriteMask_All;
236     WGPUFragmentState fragment_state = {0};
247     wgpuPipelineLayoutRelease(pipleine_options.layout);
248 }
249 
250-AlbaWindow* alba_create_window(const AlbaWindowOptions* options)
251-{
252+AlbaWindow *alba_create_window(const AlbaWindowOptions *options) {
253     pthread_mutex_lock(&glfw_mutex);
254-    if (!glfw_initialized)
255-    {
256-        if (!glfwInit())
257-        {
258-            fprintf(stderr, "error: initializeing GLFW failed");
259+    if (!glfw_initialized) {
260+        if (!glfwInit()) {
261+            fprintf(stderr, "error: initializing GLFW failed");
262             pthread_mutex_unlock(&glfw_mutex);
263             exit(1);
264         }
260     pthread_mutex_unlock(&glfw_mutex);
261 
262     const AlbaWindowOptions default_options = {0};
263-    if (options == NULL)
264-    {
265+    if (options == NULL) {
266         options = &default_options;
267     }
268 
269-    AlbaWindow* window = calloc(1, sizeof(AlbaWindow));
270+    AlbaWindow *window = calloc(1, sizeof(AlbaWindow));
271     memset(window, 0, sizeof(AlbaWindow));
272 
273     window->options = *options;
307     window->queue = wgpuDeviceGetQueue(window->device);
308     window->command_encoder = wgpuDeviceCreateCommandEncoder(window->device, NULL);
309 
310+    // Detect format in advance as it's used both to configure the pipeline and the surface
311+    window->surface_format = wgpuSurfaceGetPreferredFormat(window->surface, window->adapter);
312     configure_pipeline(window);
313     configure_surface(window);
314 
318     return window;
319 }
320 
321-uint32_t alba_window_should_close(const AlbaWindow* window)
322-{
323+uint32_t alba_window_should_close(const AlbaWindow *window) {
324     const int should_close = glfwWindowShouldClose(window->glfw_window);
325-    if (!should_close)
326-    {
327+    if (!should_close) {
328         glfwWaitEventsTimeout(0.01);
329     }
330     return should_close;
331 }
332 
333-void alba_window_release(AlbaWindow* window)
334-{
335-    for (uint64_t i = 0; i < window->draw_calls.length; i++)
336-    {
337+void alba_window_release(AlbaWindow *window) {
338+    for (uint64_t i = 0; i < window->draw_calls.length; i++) {
339         draw_call_release(window->draw_calls.data + i);
340     }
341     alba_array_release(&window->draw_calls);
347     free(window);
348 }
349 
350-uint32_t frame_status_is_valid(const WGPUSurfaceTexture frame)
351-{
352-    switch (frame.status)
353-    {
354-    case WGPUSurfaceGetCurrentTextureStatus_Success:
355-        break;
356-    case WGPUSurfaceGetCurrentTextureStatus_Timeout:
357-    case WGPUSurfaceGetCurrentTextureStatus_Outdated:
358-    case WGPUSurfaceGetCurrentTextureStatus_Lost:
359-        return 0;
360-    case WGPUSurfaceGetCurrentTextureStatus_OutOfMemory:
361-        fprintf(stderr, "error: frame allocation failed due to insufficient memory (%d)\n",
362-                frame.status);
363-    case WGPUSurfaceGetCurrentTextureStatus_DeviceLost:
364-        fprintf(stderr, "error: device lost (%d)\n", frame.status);
365-    case WGPUSurfaceGetCurrentTextureStatus_Force32:
366-        fprintf(stderr, "error: force 32 error (%d)\n", frame.status);
367-        exit(1);
368+uint32_t frame_status_is_valid(const WGPUSurfaceTexture frame) {
369+    switch (frame.status) {
370+        case WGPUSurfaceGetCurrentTextureStatus_Success:
371+            break;
372+        case WGPUSurfaceGetCurrentTextureStatus_Timeout:
373+        case WGPUSurfaceGetCurrentTextureStatus_Outdated:
374+        case WGPUSurfaceGetCurrentTextureStatus_Lost:
375+            return 0;
376+        case WGPUSurfaceGetCurrentTextureStatus_OutOfMemory:
377+            fprintf(stderr, "error: frame allocation failed due to insufficient memory (%d)\n",
378+                    frame.status);
379+        case WGPUSurfaceGetCurrentTextureStatus_DeviceLost:
380+            fprintf(stderr, "error: device lost (%d)\n", frame.status);
381+        case WGPUSurfaceGetCurrentTextureStatus_Force32:
382+            fprintf(stderr, "error: force 32 error (%d)\n", frame.status);
383+            exit(1);
384     }
385 
386     return 1;
387 }
388 
389 
390-void copy_color(const AlbaColor src, WGPUColor* dst)
391-{
392+void copy_color(const AlbaColor src, WGPUColor *dst) {
393     dst->r = src.r;
394     dst->g = src.g;
395     dst->b = src.b;
377 }
378 
379 void ensure_draw_call_updated(
380-    const AlbaWindow* window,
381-    DrawCall* draw_call
382-)
383-{
384-    if (draw_call->text_dirty)
385-    {
386+    const AlbaWindow *window,
387+    DrawCall *draw_call
388+) {
389+    if (draw_call->text_dirty) {
390         pthread_mutex_lock(&freetype_mutex);
391         atlas_generate_image(&atlas);
392         pthread_mutex_unlock(&freetype_mutex);
400         draw_call->text_dirty = 0;
401     }
402 
403-    if (draw_call->buffers_dirty)
404-    {
405+    if (draw_call->buffers_dirty) {
406         draw_call->vertices = update_buffer(
407             window, draw_call->vertices, WGPUBufferUsage_Vertex, draw_call->new_vertices);
408         draw_call->attributes = update_buffer(
411         draw_call->buffers_dirty = 0;
412     }
413 
414-    if (draw_call->bind_group_dirty)
415-    {
416+    if (draw_call->bind_group_dirty) {
417         draw_call_update_bind_group(window, draw_call);
418         draw_call->bind_group_dirty = 0;
419     }
420 }
421 
422 void draw_objects(
423-    const AlbaWindow* window,
424+    const AlbaWindow *window,
425     const WGPUCommandEncoder command_encoder,
426     const WGPURenderPassEncoder render_pass
427-)
428-{
429+) {
430     wgpuRenderPassEncoderSetPipeline(render_pass, window->pipeline);
431     wgpuRenderPassEncoderSetBindGroup(render_pass, 0, window->uniforms_bind_group, 0, NULL);
432 
433-    for (uint64_t i = 0; i < window->draw_calls.length; i++)
434-    {
435-        DrawCall* draw_call = window->draw_calls.data + i;
436+    for (uint64_t i = 0; i < window->draw_calls.length; i++) {
437+        DrawCall *draw_call = window->draw_calls.data + i;
438 
439         ensure_draw_call_updated(window, draw_call);
440         wgpuRenderPassEncoderSetBindGroup(render_pass, 1, draw_call->bind_group, 0, NULL);
434         const uint32_t vertex_size = wgpuBufferGetSize(draw_call->vertices);
435         const uint32_t attributes_size = wgpuBufferGetSize(draw_call->attributes);
436         const uint32_t indices_size = wgpuBufferGetSize(draw_call->indices);
437-        if (vertex_size > 0)
438-        {
439+        if (vertex_size > 0) {
440             wgpuRenderPassEncoderSetVertexBuffer(
441                 render_pass, 0, draw_call->vertices, 0, vertex_size);
442             wgpuRenderPassEncoderSetVertexBuffer(
454     wgpuCommandBufferRelease(command);
455 }
456 
457-void alba_window_render(AlbaWindow* window)
458-{
459+void alba_window_render(AlbaWindow *window) {
460     // Setup textures for rendering
461     // --------------------------------------------
462     WGPUSurfaceTexture frame;
463     wgpuSurfaceGetCurrentTexture(window->surface, &frame);
464-    if (!frame_status_is_valid(frame))
465-    {
466+    if (!frame_status_is_valid(frame)) {
467         // Re-configure surface and skip frame
468-        if (frame.texture != NULL)
469-        {
470+        if (frame.texture != NULL) {
471             wgpuTextureRelease(frame.texture);
472         }
473 
470     }
471 
472     const WGPUTextureView frame_view = wgpuTextureCreateView(frame.texture, NULL);
473-    if (frame_view == NULL)
474-    {
475+    if (frame_view == NULL) {
476         printf("warning: could not get frame view, dropping frame (%d)\n", frame.status);
477         return;
478     }
480         window,
481         WGPUTextureUsage_RenderAttachment,
482         window->size,
483-        WGPUTextureFormat_BGRA8UnormSrgb, 4, // TODO: do not assume format
484+        window->surface_format,
485+        4,
486         NULL
487     );
488     const WGPUTextureView render_target_view = wgpuTextureCreateView(render_target, NULL);
489-    if (render_target_view == NULL)
490-    {
491+    if (render_target_view == NULL) {
492         printf("warning: could not get texture view, dropping frame\n");
493         return;
494     }
526 }
527 
528 
529-void alba_window_get_size(const AlbaWindow* window, float* width, float* height)
530-{
531+void alba_window_get_size(const AlbaWindow *window, float *width, float *height) {
532     int raw_width, raw_height;
533     float x_scale, y_scale;
534     glfwGetWindowSize(window->glfw_window, &raw_width, &raw_height);
536     *height = raw_height / y_scale;
537 }
538 
539-void alba_release()
540-{
541-    if (freetype != NULL)
542-    {
543+void alba_release() {
544+    if (freetype != NULL) {
545         // freetype errors are ignored here
546         FT_Done_FreeType(freetype);
547         // TODO: free faces