tri.c revision d38dcc92057e23405c3accf874c91e988237f7ed
1/*
2 * Draw a textured triangle with depth testing.  This is written against Intel
3 * ICD.  It does not do state transition nor object memory binding like it
4 * should.  It also does no error checking.
5 */
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <stdbool.h>
11#include <assert.h>
12
13#include <xcb/xcb.h>
14#include <vulkan.h>
15#include <vkDbg.h>
16#include <vkWsiX11Ext.h>
17
18#include "icd-spv.h"
19
20#define DEMO_BUFFER_COUNT 2
21#define DEMO_TEXTURE_COUNT 1
22#define VERTEX_BUFFER_BIND_ID 0
23
24struct texture_object {
25    VK_SAMPLER sampler;
26
27    VK_IMAGE image;
28    VK_IMAGE_LAYOUT imageLayout;
29
30    uint32_t  num_mem;
31    VK_GPU_MEMORY *mem;
32    VK_IMAGE_VIEW view;
33    int32_t tex_width, tex_height;
34};
35
36struct demo {
37    xcb_connection_t *connection;
38    xcb_screen_t *screen;
39
40    VK_INSTANCE inst;
41    VK_PHYSICAL_GPU gpu;
42    VK_DEVICE device;
43    VK_QUEUE queue;
44    VK_PHYSICAL_GPU_PROPERTIES *gpu_props;
45    VK_PHYSICAL_GPU_QUEUE_PROPERTIES *queue_props;
46    uint32_t graphics_queue_node_index;
47
48    int width, height;
49    VK_FORMAT format;
50
51    struct {
52        VK_IMAGE image;
53        VK_GPU_MEMORY mem;
54
55        VK_COLOR_ATTACHMENT_VIEW view;
56        VK_FENCE fence;
57    } buffers[DEMO_BUFFER_COUNT];
58
59    struct {
60        VK_FORMAT format;
61
62        VK_IMAGE image;
63        uint32_t  num_mem;
64        VK_GPU_MEMORY *mem;
65        VK_DEPTH_STENCIL_VIEW view;
66    } depth;
67
68    struct texture_object textures[DEMO_TEXTURE_COUNT];
69
70    struct {
71        VK_BUFFER buf;
72        uint32_t  num_mem;
73        VK_GPU_MEMORY *mem;
74
75        VK_PIPELINE_VERTEX_INPUT_CREATE_INFO vi;
76        VK_VERTEX_INPUT_BINDING_DESCRIPTION vi_bindings[1];
77        VK_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION vi_attrs[2];
78    } vertices;
79
80    VK_CMD_BUFFER cmd;  // Buffer for initialization commands
81    VK_DESCRIPTOR_SET_LAYOUT_CHAIN desc_layout_chain;
82    VK_DESCRIPTOR_SET_LAYOUT desc_layout;
83    VK_PIPELINE pipeline;
84
85    VK_DYNAMIC_VP_STATE_OBJECT viewport;
86    VK_DYNAMIC_RS_STATE_OBJECT raster;
87    VK_DYNAMIC_CB_STATE_OBJECT color_blend;
88    VK_DYNAMIC_DS_STATE_OBJECT depth_stencil;
89
90    VK_DESCRIPTOR_POOL desc_pool;
91    VK_DESCRIPTOR_SET desc_set;
92
93    xcb_window_t window;
94    xcb_intern_atom_reply_t *atom_wm_delete_window;
95
96    bool quit;
97    bool use_staging_buffer;
98    uint32_t current_buffer;
99};
100
101static void demo_flush_init_cmd(struct demo *demo)
102{
103    VK_RESULT err;
104
105    if (demo->cmd == VK_NULL_HANDLE)
106        return;
107
108    err = vkEndCommandBuffer(demo->cmd);
109    assert(!err);
110
111    const VK_CMD_BUFFER cmd_bufs[] = { demo->cmd };
112
113    err = vkQueueSubmit(demo->queue, 1, cmd_bufs, VK_NULL_HANDLE);
114    assert(!err);
115
116    err = vkQueueWaitIdle(demo->queue);
117    assert(!err);
118
119    vkDestroyObject(demo->cmd);
120    demo->cmd = VK_NULL_HANDLE;
121}
122
123static void demo_add_mem_refs(
124        struct demo *demo,
125        int num_refs, VK_GPU_MEMORY *mem)
126{
127    for (int i = 0; i < num_refs; i++) {
128        vkQueueAddMemReference(demo->queue, mem[i]);
129    }
130}
131
132static void demo_remove_mem_refs(
133        struct demo *demo,
134        int num_refs, VK_GPU_MEMORY *mem)
135{
136    for (int i = 0; i < num_refs; i++) {
137        vkQueueRemoveMemReference(demo->queue, mem[i]);
138    }
139}
140
141static void demo_set_image_layout(
142        struct demo *demo,
143        VK_IMAGE image,
144        VK_IMAGE_LAYOUT old_image_layout,
145        VK_IMAGE_LAYOUT new_image_layout)
146{
147    VK_RESULT err;
148
149    if (demo->cmd == VK_NULL_HANDLE) {
150        const VK_CMD_BUFFER_CREATE_INFO cmd = {
151            .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,
152            .pNext = NULL,
153            .queueNodeIndex = demo->graphics_queue_node_index,
154            .flags = 0,
155        };
156
157        err = vkCreateCommandBuffer(demo->device, &cmd, &demo->cmd);
158        assert(!err);
159
160        VK_CMD_BUFFER_BEGIN_INFO cmd_buf_info = {
161            .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,
162            .pNext = NULL,
163            .flags = VK_CMD_BUFFER_OPTIMIZE_GPU_SMALL_BATCH_BIT |
164                VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT,
165        };
166        err = vkBeginCommandBuffer(demo->cmd, &cmd_buf_info);
167    }
168
169    VK_IMAGE_MEMORY_BARRIER image_memory_barrier = {
170        .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
171        .pNext = NULL,
172        .outputMask = 0,
173        .inputMask = 0,
174        .oldLayout = old_image_layout,
175        .newLayout = new_image_layout,
176        .image = image,
177        .subresourceRange = { VK_IMAGE_ASPECT_COLOR, 0, 1, 0, 0 }
178    };
179
180    if (new_image_layout == VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL) {
181        /* Make sure anything that was copying from this image has completed */
182        image_memory_barrier.inputMask = VK_MEMORY_INPUT_COPY_BIT;
183    }
184
185    if (new_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
186        /* Make sure any Copy or CPU writes to image are flushed */
187        image_memory_barrier.outputMask = VK_MEMORY_OUTPUT_COPY_BIT | VK_MEMORY_OUTPUT_CPU_WRITE_BIT;
188    }
189
190    VK_IMAGE_MEMORY_BARRIER *pmemory_barrier = &image_memory_barrier;
191
192    VK_PIPE_EVENT set_events[] = { VK_PIPE_EVENT_TOP_OF_PIPE };
193
194    VK_PIPELINE_BARRIER pipeline_barrier;
195    pipeline_barrier.sType = VK_STRUCTURE_TYPE_PIPELINE_BARRIER;
196    pipeline_barrier.pNext = NULL;
197    pipeline_barrier.eventCount = 1;
198    pipeline_barrier.pEvents = set_events;
199    pipeline_barrier.waitEvent = VK_WAIT_EVENT_TOP_OF_PIPE;
200    pipeline_barrier.memBarrierCount = 1;
201    pipeline_barrier.ppMemBarriers = (const void **)&pmemory_barrier;
202
203    vkCmdPipelineBarrier(demo->cmd, &pipeline_barrier);
204}
205
206static void demo_draw_build_cmd(struct demo *demo)
207{
208    const VK_COLOR_ATTACHMENT_BIND_INFO color_attachment = {
209        .view = demo->buffers[demo->current_buffer].view,
210        .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
211    };
212    const VK_DEPTH_STENCIL_BIND_INFO depth_stencil = {
213        .view = demo->depth.view,
214        .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
215    };
216    const VK_CLEAR_COLOR clear_color = {
217        .color.floatColor = { 0.2f, 0.2f, 0.2f, 0.2f },
218        .useRawValue = false,
219    };
220    const float clear_depth = 0.9f;
221    VK_IMAGE_SUBRESOURCE_RANGE clear_range;
222    VK_CMD_BUFFER_BEGIN_INFO cmd_buf_info = {
223        .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,
224        .pNext = NULL,
225        .flags = VK_CMD_BUFFER_OPTIMIZE_GPU_SMALL_BATCH_BIT |
226            VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT,
227    };
228    VK_RESULT err;
229    VK_ATTACHMENT_LOAD_OP load_op = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
230    VK_ATTACHMENT_STORE_OP store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE;
231    const VK_FRAMEBUFFER_CREATE_INFO fb_info = {
232         .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
233         .pNext = NULL,
234         .colorAttachmentCount = 1,
235         .pColorAttachments = (VK_COLOR_ATTACHMENT_BIND_INFO*) &color_attachment,
236         .pDepthStencilAttachment = (VK_DEPTH_STENCIL_BIND_INFO*) &depth_stencil,
237         .sampleCount = 1,
238         .width  = demo->width,
239         .height = demo->height,
240         .layers = 1,
241    };
242    VK_RENDER_PASS_CREATE_INFO rp_info;
243    VK_RENDER_PASS_BEGIN rp_begin;
244
245    memset(&rp_info, 0 , sizeof(rp_info));
246    err = vkCreateFramebuffer(demo->device, &fb_info, &rp_begin.framebuffer);
247    assert(!err);
248    rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
249    rp_info.renderArea.extent.width = demo->width;
250    rp_info.renderArea.extent.height = demo->height;
251    rp_info.colorAttachmentCount = fb_info.colorAttachmentCount;
252    rp_info.pColorFormats = &demo->format;
253    rp_info.pColorLayouts = &color_attachment.layout;
254    rp_info.pColorLoadOps = &load_op;
255    rp_info.pColorStoreOps = &store_op;
256    rp_info.pColorLoadClearValues = &clear_color;
257    rp_info.depthStencilFormat = VK_FMT_D16_UNORM;
258    rp_info.depthStencilLayout = depth_stencil.layout;
259    rp_info.depthLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
260    rp_info.depthLoadClearValue = clear_depth;
261    rp_info.depthStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
262    rp_info.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
263    rp_info.stencilLoadClearValue = 0;
264    rp_info.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
265    err = vkCreateRenderPass(demo->device, &rp_info, &(rp_begin.renderPass));
266    assert(!err);
267
268    err = vkBeginCommandBuffer(demo->cmd, &cmd_buf_info);
269    assert(!err);
270
271    vkCmdBindPipeline(demo->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
272                                  demo->pipeline);
273    vkCmdBindDescriptorSets(demo->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
274            demo->desc_layout_chain, 0, 1, & demo->desc_set, NULL);
275
276    vkCmdBindDynamicStateObject(demo->cmd, VK_STATE_BIND_VIEWPORT, demo->viewport);
277    vkCmdBindDynamicStateObject(demo->cmd, VK_STATE_BIND_RASTER, demo->raster);
278    vkCmdBindDynamicStateObject(demo->cmd, VK_STATE_BIND_COLOR_BLEND,
279                                     demo->color_blend);
280    vkCmdBindDynamicStateObject(demo->cmd, VK_STATE_BIND_DEPTH_STENCIL,
281                                     demo->depth_stencil);
282
283
284    vkCmdBindVertexBuffer(demo->cmd, demo->vertices.buf, 0, VERTEX_BUFFER_BIND_ID);
285
286    vkCmdBeginRenderPass(demo->cmd, &rp_begin);
287    clear_range.aspect = VK_IMAGE_ASPECT_COLOR;
288    clear_range.baseMipLevel = 0;
289    clear_range.mipLevels = 1;
290    clear_range.baseArraySlice = 0;
291    clear_range.arraySize = 1;
292    vkCmdClearColorImage(demo->cmd,
293            demo->buffers[demo->current_buffer].image,
294            VK_IMAGE_LAYOUT_CLEAR_OPTIMAL,
295            clear_color, 1, &clear_range);
296
297    clear_range.aspect = VK_IMAGE_ASPECT_DEPTH;
298    vkCmdClearDepthStencil(demo->cmd,
299            demo->depth.image, VK_IMAGE_LAYOUT_CLEAR_OPTIMAL,
300            clear_depth, 0, 1, &clear_range);
301
302    vkCmdDraw(demo->cmd, 0, 3, 0, 1);
303    vkCmdEndRenderPass(demo->cmd, rp_begin.renderPass);
304
305    err = vkEndCommandBuffer(demo->cmd);
306    assert(!err);
307
308    vkDestroyObject(rp_begin.renderPass);
309    vkDestroyObject(rp_begin.framebuffer);
310}
311
312static void demo_draw(struct demo *demo)
313{
314    const VK_WSI_X11_PRESENT_INFO present = {
315        .destWindow = demo->window,
316        .srcImage = demo->buffers[demo->current_buffer].image,
317    };
318    VK_FENCE fence = demo->buffers[demo->current_buffer].fence;
319    VK_RESULT err;
320
321    demo_draw_build_cmd(demo);
322
323    err = vkWaitForFences(demo->device, 1, &fence, VK_TRUE, ~((uint64_t) 0));
324    assert(err == VK_SUCCESS || err == VK_ERROR_UNAVAILABLE);
325
326    err = vkQueueSubmit(demo->queue, 1, &demo->cmd, VK_NULL_HANDLE);
327    assert(!err);
328
329    err = vkWsiX11QueuePresent(demo->queue, &present, fence);
330    assert(!err);
331
332    demo->current_buffer = (demo->current_buffer + 1) % DEMO_BUFFER_COUNT;
333}
334
335static void demo_prepare_buffers(struct demo *demo)
336{
337    const VK_WSI_X11_PRESENTABLE_IMAGE_CREATE_INFO presentable_image = {
338        .format = demo->format,
339        .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
340        .extent = {
341            .width = demo->width,
342            .height = demo->height,
343        },
344        .flags = 0,
345    };
346    const VK_FENCE_CREATE_INFO fence = {
347        .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
348        .pNext = NULL,
349        .flags = 0,
350    };
351    VK_RESULT err;
352    uint32_t i;
353
354    for (i = 0; i < DEMO_BUFFER_COUNT; i++) {
355        VK_COLOR_ATTACHMENT_VIEW_CREATE_INFO color_attachment_view = {
356            .sType = VK_STRUCTURE_TYPE_COLOR_ATTACHMENT_VIEW_CREATE_INFO,
357            .pNext = NULL,
358            .format = demo->format,
359            .mipLevel = 0,
360            .baseArraySlice = 0,
361            .arraySize = 1,
362        };
363
364        err = vkWsiX11CreatePresentableImage(demo->device, &presentable_image,
365                &demo->buffers[i].image, &demo->buffers[i].mem);
366        assert(!err);
367        demo_add_mem_refs(demo, 1, &demo->buffers[i].mem);
368        demo_set_image_layout(demo, demo->buffers[i].image,
369                               VK_IMAGE_LAYOUT_UNDEFINED,
370                               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
371
372        color_attachment_view.image = demo->buffers[i].image;
373
374        err = vkCreateColorAttachmentView(demo->device,
375                &color_attachment_view, &demo->buffers[i].view);
376        assert(!err);
377
378        err = vkCreateFence(demo->device,
379                &fence, &demo->buffers[i].fence);
380        assert(!err);
381    }
382
383    demo->current_buffer = 0;
384}
385
386static void demo_prepare_depth(struct demo *demo)
387{
388    const VK_FORMAT depth_format = VK_FMT_D16_UNORM;
389    const VK_IMAGE_CREATE_INFO image = {
390        .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
391        .pNext = NULL,
392        .imageType = VK_IMAGE_2D,
393        .format = depth_format,
394        .extent = { demo->width, demo->height, 1 },
395        .mipLevels = 1,
396        .arraySize = 1,
397        .samples = 1,
398        .tiling = VK_OPTIMAL_TILING,
399        .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_BIT,
400        .flags = 0,
401    };
402    VK_MEMORY_ALLOC_IMAGE_INFO img_alloc = {
403        .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_IMAGE_INFO,
404        .pNext = NULL,
405    };
406    VK_MEMORY_ALLOC_INFO mem_alloc = {
407        .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
408        .pNext = &img_alloc,
409        .allocationSize = 0,
410        .memProps = VK_MEMORY_PROPERTY_GPU_ONLY,
411        .memType = VK_MEMORY_TYPE_IMAGE,
412        .memPriority = VK_MEMORY_PRIORITY_NORMAL,
413    };
414    VK_DEPTH_STENCIL_VIEW_CREATE_INFO view = {
415        .sType = VK_STRUCTURE_TYPE_DEPTH_STENCIL_VIEW_CREATE_INFO,
416        .pNext = NULL,
417        .image = VK_NULL_HANDLE,
418        .mipLevel = 0,
419        .baseArraySlice = 0,
420        .arraySize = 1,
421        .flags = 0,
422    };
423
424    VK_MEMORY_REQUIREMENTS *mem_reqs;
425    size_t mem_reqs_size = sizeof(VK_MEMORY_REQUIREMENTS);
426    VK_IMAGE_MEMORY_REQUIREMENTS img_reqs;
427    size_t img_reqs_size = sizeof(VK_IMAGE_MEMORY_REQUIREMENTS);
428    VK_RESULT err;
429    uint32_t num_allocations = 0;
430    size_t num_alloc_size = sizeof(num_allocations);
431
432    demo->depth.format = depth_format;
433
434    /* create image */
435    err = vkCreateImage(demo->device, &image,
436            &demo->depth.image);
437    assert(!err);
438
439    err = vkGetObjectInfo(demo->depth.image, VK_INFO_TYPE_MEMORY_ALLOCATION_COUNT, &num_alloc_size, &num_allocations);
440    assert(!err && num_alloc_size == sizeof(num_allocations));
441    mem_reqs = malloc(num_allocations * sizeof(VK_MEMORY_REQUIREMENTS));
442    demo->depth.mem = malloc(num_allocations * sizeof(VK_GPU_MEMORY));
443    demo->depth.num_mem = num_allocations;
444    err = vkGetObjectInfo(demo->depth.image,
445                    VK_INFO_TYPE_MEMORY_REQUIREMENTS,
446                    &mem_reqs_size, mem_reqs);
447    assert(!err && mem_reqs_size == num_allocations * sizeof(VK_MEMORY_REQUIREMENTS));
448    err = vkGetObjectInfo(demo->depth.image,
449                    VK_INFO_TYPE_IMAGE_MEMORY_REQUIREMENTS,
450                    &img_reqs_size, &img_reqs);
451    assert(!err && img_reqs_size == sizeof(VK_IMAGE_MEMORY_REQUIREMENTS));
452    img_alloc.usage = img_reqs.usage;
453    img_alloc.formatClass = img_reqs.formatClass;
454    img_alloc.samples = img_reqs.samples;
455    for (uint32_t i = 0; i < num_allocations; i ++) {
456        mem_alloc.allocationSize = mem_reqs[i].size;
457
458        /* allocate memory */
459        err = vkAllocMemory(demo->device, &mem_alloc,
460                    &(demo->depth.mem[i]));
461        assert(!err);
462
463        /* bind memory */
464        err = vkBindObjectMemory(demo->depth.image, i,
465                demo->depth.mem[i], 0);
466        assert(!err);
467    }
468
469    demo_set_image_layout(demo, demo->depth.image,
470                           VK_IMAGE_LAYOUT_UNDEFINED,
471                           VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
472
473    demo_add_mem_refs(demo, demo->depth.num_mem, demo->depth.mem);
474
475    /* create image view */
476    view.image = demo->depth.image;
477    err = vkCreateDepthStencilView(demo->device, &view,
478            &demo->depth.view);
479    assert(!err);
480}
481
482static void demo_prepare_texture_image(struct demo *demo,
483                                       const uint32_t *tex_colors,
484                                       struct texture_object *tex_obj,
485                                       VK_IMAGE_TILING tiling,
486                                       VK_FLAGS mem_props)
487{
488    const VK_FORMAT tex_format = VK_FMT_B8G8R8A8_UNORM;
489    const int32_t tex_width = 2;
490    const int32_t tex_height = 2;
491    VK_RESULT err;
492
493    tex_obj->tex_width = tex_width;
494    tex_obj->tex_height = tex_height;
495
496    const VK_IMAGE_CREATE_INFO image_create_info = {
497        .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
498        .pNext = NULL,
499        .imageType = VK_IMAGE_2D,
500        .format = tex_format,
501        .extent = { tex_width, tex_height, 1 },
502        .mipLevels = 1,
503        .arraySize = 1,
504        .samples = 1,
505        .tiling = tiling,
506        .usage = VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT,
507        .flags = 0,
508    };
509    VK_MEMORY_ALLOC_IMAGE_INFO img_alloc = {
510        .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_IMAGE_INFO,
511        .pNext = NULL,
512    };
513    VK_MEMORY_ALLOC_INFO mem_alloc = {
514        .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
515        .pNext = &img_alloc,
516        .allocationSize = 0,
517        .memProps = mem_props,
518        .memType = VK_MEMORY_TYPE_IMAGE,
519        .memPriority = VK_MEMORY_PRIORITY_NORMAL,
520    };
521
522    VK_MEMORY_REQUIREMENTS *mem_reqs;
523    size_t mem_reqs_size = sizeof(VK_MEMORY_REQUIREMENTS);
524    VK_IMAGE_MEMORY_REQUIREMENTS img_reqs;
525    size_t img_reqs_size = sizeof(VK_IMAGE_MEMORY_REQUIREMENTS);
526    uint32_t num_allocations = 0;
527    size_t num_alloc_size = sizeof(num_allocations);
528
529    err = vkCreateImage(demo->device, &image_create_info,
530            &tex_obj->image);
531    assert(!err);
532
533    err = vkGetObjectInfo(tex_obj->image,
534                VK_INFO_TYPE_MEMORY_ALLOCATION_COUNT,
535                &num_alloc_size, &num_allocations);
536    assert(!err && num_alloc_size == sizeof(num_allocations));
537    mem_reqs = malloc(num_allocations * sizeof(VK_MEMORY_REQUIREMENTS));
538    tex_obj->mem = malloc(num_allocations * sizeof(VK_GPU_MEMORY));
539    err = vkGetObjectInfo(tex_obj->image,
540                VK_INFO_TYPE_MEMORY_REQUIREMENTS,
541                &mem_reqs_size, mem_reqs);
542    assert(!err && mem_reqs_size == num_allocations * sizeof(VK_MEMORY_REQUIREMENTS));
543    err = vkGetObjectInfo(tex_obj->image,
544                    VK_INFO_TYPE_IMAGE_MEMORY_REQUIREMENTS,
545                    &img_reqs_size, &img_reqs);
546    assert(!err && img_reqs_size == sizeof(VK_IMAGE_MEMORY_REQUIREMENTS));
547    img_alloc.usage = img_reqs.usage;
548    img_alloc.formatClass = img_reqs.formatClass;
549    img_alloc.samples = img_reqs.samples;
550    mem_alloc.memProps = VK_MEMORY_PROPERTY_CPU_VISIBLE_BIT;
551    for (uint32_t j = 0; j < num_allocations; j ++) {
552        mem_alloc.allocationSize = mem_reqs[j].size;
553        mem_alloc.memType = mem_reqs[j].memType;
554
555        /* allocate memory */
556        err = vkAllocMemory(demo->device, &mem_alloc,
557                    &(tex_obj->mem[j]));
558        assert(!err);
559
560        /* bind memory */
561        err = vkBindObjectMemory(tex_obj->image, j, tex_obj->mem[j], 0);
562        assert(!err);
563    }
564    free(mem_reqs);
565    mem_reqs = NULL;
566
567    tex_obj->num_mem = num_allocations;
568
569    if (mem_props & VK_MEMORY_PROPERTY_CPU_VISIBLE_BIT) {
570        const VK_IMAGE_SUBRESOURCE subres = {
571            .aspect = VK_IMAGE_ASPECT_COLOR,
572            .mipLevel = 0,
573            .arraySlice = 0,
574        };
575        VK_SUBRESOURCE_LAYOUT layout;
576        size_t layout_size = sizeof(VK_SUBRESOURCE_LAYOUT);
577        void *data;
578        int32_t x, y;
579
580        err = vkGetImageSubresourceInfo(tex_obj->image, &subres,
581                                         VK_INFO_TYPE_SUBRESOURCE_LAYOUT,
582                                         &layout_size, &layout);
583        assert(!err && layout_size == sizeof(layout));
584        /* Linear texture must be within a single memory object */
585        assert(num_allocations == 1);
586
587        err = vkMapMemory(tex_obj->mem[0], 0, &data);
588        assert(!err);
589
590        for (y = 0; y < tex_height; y++) {
591            uint32_t *row = (uint32_t *) ((char *) data + layout.rowPitch * y);
592            for (x = 0; x < tex_width; x++)
593                row[x] = tex_colors[(x & 1) ^ (y & 1)];
594        }
595
596        err = vkUnmapMemory(tex_obj->mem[0]);
597        assert(!err);
598    }
599
600    tex_obj->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
601    demo_set_image_layout(demo, tex_obj->image,
602                           VK_IMAGE_LAYOUT_UNDEFINED,
603                           tex_obj->imageLayout);
604    /* setting the image layout does not reference the actual memory so no need to add a mem ref */
605}
606
607static void demo_destroy_texture_image(struct texture_object *tex_obj)
608{
609    /* clean up staging resources */
610    for (uint32_t j = 0; j < tex_obj->num_mem; j ++) {
611        vkBindObjectMemory(tex_obj->image, j, VK_NULL_HANDLE, 0);
612        vkFreeMemory(tex_obj->mem[j]);
613    }
614
615    free(tex_obj->mem);
616    vkDestroyObject(tex_obj->image);
617}
618
619static void demo_prepare_textures(struct demo *demo)
620{
621    const VK_FORMAT tex_format = VK_FMT_B8G8R8A8_UNORM;
622    VK_FORMAT_PROPERTIES props;
623    size_t size = sizeof(props);
624    const uint32_t tex_colors[DEMO_TEXTURE_COUNT][2] = {
625        { 0xffff0000, 0xff00ff00 },
626    };
627    VK_RESULT err;
628    uint32_t i;
629
630    err = vkGetFormatInfo(demo->device, tex_format,
631                           VK_INFO_TYPE_FORMAT_PROPERTIES,
632                           &size, &props);
633    assert(!err);
634
635    for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
636        if ((props.linearTilingFeatures & VK_FORMAT_IMAGE_SHADER_READ_BIT) && !demo->use_staging_buffer) {
637            /* Device can texture using linear textures */
638            demo_prepare_texture_image(demo, tex_colors[i], &demo->textures[i],
639                                       VK_LINEAR_TILING, VK_MEMORY_PROPERTY_CPU_VISIBLE_BIT);
640        } else if (props.optimalTilingFeatures & VK_FORMAT_IMAGE_SHADER_READ_BIT){
641            /* Must use staging buffer to copy linear texture to optimized */
642            struct texture_object staging_texture;
643
644            memset(&staging_texture, 0, sizeof(staging_texture));
645            demo_prepare_texture_image(demo, tex_colors[i], &staging_texture,
646                                       VK_LINEAR_TILING, VK_MEMORY_PROPERTY_CPU_VISIBLE_BIT);
647
648            demo_prepare_texture_image(demo, tex_colors[i], &demo->textures[i],
649                                       VK_OPTIMAL_TILING, VK_MEMORY_PROPERTY_GPU_ONLY);
650
651            demo_set_image_layout(demo, staging_texture.image,
652                                   staging_texture.imageLayout,
653                                   VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL);
654
655            demo_set_image_layout(demo, demo->textures[i].image,
656                                   demo->textures[i].imageLayout,
657                                   VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL);
658
659            VK_IMAGE_COPY copy_region = {
660                .srcSubresource = { VK_IMAGE_ASPECT_COLOR, 0, 0 },
661                .srcOffset = { 0, 0, 0 },
662                .destSubresource = { VK_IMAGE_ASPECT_COLOR, 0, 0 },
663                .destOffset = { 0, 0, 0 },
664                .extent = { staging_texture.tex_width, staging_texture.tex_height, 1 },
665            };
666            vkCmdCopyImage(demo->cmd,
667                            staging_texture.image, VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL,
668                            demo->textures[i].image, VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL,
669                            1, &copy_region);
670
671            demo_add_mem_refs(demo, staging_texture.num_mem, staging_texture.mem);
672            demo_add_mem_refs(demo, demo->textures[i].num_mem, demo->textures[i].mem);
673
674            demo_set_image_layout(demo, demo->textures[i].image,
675                                   VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL,
676                                   demo->textures[i].imageLayout);
677
678            demo_flush_init_cmd(demo);
679
680            demo_destroy_texture_image(&staging_texture);
681            demo_remove_mem_refs(demo, staging_texture.num_mem, staging_texture.mem);
682        } else {
683            /* Can't support VK_FMT_B8G8R8A8_UNORM !? */
684            assert(!"No support for B8G8R8A8_UNORM as texture image format");
685        }
686
687        const VK_SAMPLER_CREATE_INFO sampler = {
688            .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
689            .pNext = NULL,
690            .magFilter = VK_TEX_FILTER_NEAREST,
691            .minFilter = VK_TEX_FILTER_NEAREST,
692            .mipMode = VK_TEX_MIPMAP_BASE,
693            .addressU = VK_TEX_ADDRESS_WRAP,
694            .addressV = VK_TEX_ADDRESS_WRAP,
695            .addressW = VK_TEX_ADDRESS_WRAP,
696            .mipLodBias = 0.0f,
697            .maxAnisotropy = 1,
698            .compareFunc = VK_COMPARE_NEVER,
699            .minLod = 0.0f,
700            .maxLod = 0.0f,
701            .borderColorType = VK_BORDER_COLOR_OPAQUE_WHITE,
702        };
703        VK_IMAGE_VIEW_CREATE_INFO view = {
704            .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
705            .pNext = NULL,
706            .image = VK_NULL_HANDLE,
707            .viewType = VK_IMAGE_VIEW_2D,
708            .format = tex_format,
709            .channels = { VK_CHANNEL_SWIZZLE_R,
710                          VK_CHANNEL_SWIZZLE_G,
711                          VK_CHANNEL_SWIZZLE_B,
712                          VK_CHANNEL_SWIZZLE_A, },
713            .subresourceRange = { VK_IMAGE_ASPECT_COLOR, 0, 1, 0, 1 },
714            .minLod = 0.0f,
715        };
716
717        /* create sampler */
718        err = vkCreateSampler(demo->device, &sampler,
719                &demo->textures[i].sampler);
720        assert(!err);
721
722        /* create image view */
723        view.image = demo->textures[i].image;
724        err = vkCreateImageView(demo->device, &view,
725                                 &demo->textures[i].view);
726        assert(!err);
727    }
728}
729
730static void demo_prepare_vertices(struct demo *demo)
731{
732    const float vb[3][5] = {
733        /*      position             texcoord */
734        { -1.0f, -1.0f, -0.6f,      0.0f, 0.0f },
735        {  1.0f, -1.0f, -0.5f,      1.0f, 0.0f },
736        {  0.0f,  1.0f,  1.0f,      0.5f, 1.0f },
737    };
738    const VK_BUFFER_CREATE_INFO buf_info = {
739        .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
740        .pNext = NULL,
741        .size = sizeof(vb),
742        .usage = VK_BUFFER_USAGE_VERTEX_FETCH_BIT,
743        .flags = 0,
744    };
745    VK_MEMORY_ALLOC_BUFFER_INFO buf_alloc = {
746        .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_BUFFER_INFO,
747        .pNext = NULL,
748    };
749    VK_MEMORY_ALLOC_INFO mem_alloc = {
750        .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
751        .pNext = &buf_alloc,
752        .allocationSize = 0,
753        .memProps = VK_MEMORY_PROPERTY_CPU_VISIBLE_BIT,
754        .memType = VK_MEMORY_TYPE_BUFFER,
755        .memPriority = VK_MEMORY_PRIORITY_NORMAL,
756    };
757    VK_MEMORY_REQUIREMENTS *mem_reqs;
758    size_t mem_reqs_size = sizeof(VK_MEMORY_REQUIREMENTS);
759    VK_BUFFER_MEMORY_REQUIREMENTS buf_reqs;
760    size_t buf_reqs_size = sizeof(VK_BUFFER_MEMORY_REQUIREMENTS);
761    uint32_t num_allocations = 0;
762    size_t num_alloc_size = sizeof(num_allocations);
763    VK_RESULT err;
764    void *data;
765
766    memset(&demo->vertices, 0, sizeof(demo->vertices));
767
768    err = vkCreateBuffer(demo->device, &buf_info, &demo->vertices.buf);
769    assert(!err);
770
771    err = vkGetObjectInfo(demo->vertices.buf,
772                           VK_INFO_TYPE_MEMORY_ALLOCATION_COUNT,
773                           &num_alloc_size, &num_allocations);
774    assert(!err && num_alloc_size == sizeof(num_allocations));
775    mem_reqs = malloc(num_allocations * sizeof(VK_MEMORY_REQUIREMENTS));
776    demo->vertices.mem = malloc(num_allocations * sizeof(VK_GPU_MEMORY));
777    demo->vertices.num_mem = num_allocations;
778    err = vkGetObjectInfo(demo->vertices.buf,
779            VK_INFO_TYPE_MEMORY_REQUIREMENTS,
780            &mem_reqs_size, mem_reqs);
781    assert(!err && mem_reqs_size == sizeof(*mem_reqs));
782    err = vkGetObjectInfo(demo->vertices.buf,
783                    VK_INFO_TYPE_BUFFER_MEMORY_REQUIREMENTS,
784                    &buf_reqs_size, &buf_reqs);
785    assert(!err && buf_reqs_size == sizeof(VK_BUFFER_MEMORY_REQUIREMENTS));
786    buf_alloc.usage = buf_reqs.usage;
787    for (uint32_t i = 0; i < num_allocations; i ++) {
788        mem_alloc.allocationSize = mem_reqs[i].size;
789
790        err = vkAllocMemory(demo->device, &mem_alloc, &demo->vertices.mem[i]);
791        assert(!err);
792
793        err = vkMapMemory(demo->vertices.mem[i], 0, &data);
794        assert(!err);
795
796        memcpy(data, vb, sizeof(vb));
797
798        err = vkUnmapMemory(demo->vertices.mem[i]);
799        assert(!err);
800
801        err = vkBindObjectMemory(demo->vertices.buf, i, demo->vertices.mem[i], 0);
802        assert(!err);
803    }
804
805    demo_add_mem_refs(demo, demo->vertices.num_mem, demo->vertices.mem);
806
807    demo->vertices.vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_CREATE_INFO;
808    demo->vertices.vi.pNext = NULL;
809    demo->vertices.vi.bindingCount = 1;
810    demo->vertices.vi.pVertexBindingDescriptions = demo->vertices.vi_bindings;
811    demo->vertices.vi.attributeCount = 2;
812    demo->vertices.vi.pVertexAttributeDescriptions = demo->vertices.vi_attrs;
813
814    demo->vertices.vi_bindings[0].binding = VERTEX_BUFFER_BIND_ID;
815    demo->vertices.vi_bindings[0].strideInBytes = sizeof(vb[0]);
816    demo->vertices.vi_bindings[0].stepRate = VK_VERTEX_INPUT_STEP_RATE_VERTEX;
817
818    demo->vertices.vi_attrs[0].binding = VERTEX_BUFFER_BIND_ID;
819    demo->vertices.vi_attrs[0].location = 0;
820    demo->vertices.vi_attrs[0].format = VK_FMT_R32G32B32_SFLOAT;
821    demo->vertices.vi_attrs[0].offsetInBytes = 0;
822
823    demo->vertices.vi_attrs[1].binding = VERTEX_BUFFER_BIND_ID;
824    demo->vertices.vi_attrs[1].location = 1;
825    demo->vertices.vi_attrs[1].format = VK_FMT_R32G32_SFLOAT;
826    demo->vertices.vi_attrs[1].offsetInBytes = sizeof(float) * 3;
827}
828
829static void demo_prepare_descriptor_layout(struct demo *demo)
830{
831    const VK_DESCRIPTOR_SET_LAYOUT_BINDING layout_binding = {
832        .descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER_TEXTURE,
833        .count = DEMO_TEXTURE_COUNT,
834        .stageFlags = VK_SHADER_STAGE_FLAGS_FRAGMENT_BIT,
835        .pImmutableSamplers = NULL,
836    };
837    const VK_DESCRIPTOR_SET_LAYOUT_CREATE_INFO descriptor_layout = {
838        .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
839        .pNext = NULL,
840        .count = 1,
841        .pBinding = &layout_binding,
842    };
843    VK_RESULT err;
844
845    err = vkCreateDescriptorSetLayout(demo->device,
846            &descriptor_layout, &demo->desc_layout);
847    assert(!err);
848
849    err = vkCreateDescriptorSetLayoutChain(demo->device,
850            1, &demo->desc_layout, &demo->desc_layout_chain);
851    assert(!err);
852}
853
854static VK_SHADER demo_prepare_shader(struct demo *demo,
855                                      VK_PIPELINE_SHADER_STAGE stage,
856                                      const void *code,
857                                      size_t size)
858{
859    VK_SHADER_CREATE_INFO createInfo;
860    VK_SHADER shader;
861    VK_RESULT err;
862
863    createInfo.sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO;
864    createInfo.pNext = NULL;
865
866    // Create fake SPV structure to feed GLSL
867    // to the driver "under the covers"
868    createInfo.codeSize = 3 * sizeof(uint32_t) + size + 1;
869    createInfo.pCode = malloc(createInfo.codeSize);
870    createInfo.flags = 0;
871
872    /* try version 0 first: VK_PIPELINE_SHADER_STAGE followed by GLSL */
873    ((uint32_t *) createInfo.pCode)[0] = ICD_SPV_MAGIC;
874    ((uint32_t *) createInfo.pCode)[1] = 0;
875    ((uint32_t *) createInfo.pCode)[2] = stage;
876    memcpy(((uint32_t *) createInfo.pCode + 3), code, size + 1);
877
878    err = vkCreateShader(demo->device, &createInfo, &shader);
879    if (err) {
880        free((void *) createInfo.pCode);
881        return NULL;
882    }
883
884    return shader;
885}
886
887static VK_SHADER demo_prepare_vs(struct demo *demo)
888{
889    static const char *vertShaderText =
890            "#version 140\n"
891            "#extension GL_ARB_separate_shader_objects : enable\n"
892            "#extension GL_ARB_shading_language_420pack : enable\n"
893            "layout (location = 0) in vec4 pos;\n"
894            "layout (location = 1) in vec2 attr;\n"
895            "out vec2 texcoord;\n"
896            "void main() {\n"
897            "   texcoord = attr;\n"
898            "   gl_Position = pos;\n"
899            "}\n";
900
901    return demo_prepare_shader(demo, VK_SHADER_STAGE_VERTEX,
902                               (const void *) vertShaderText,
903                               strlen(vertShaderText));
904}
905
906static VK_SHADER demo_prepare_fs(struct demo *demo)
907{
908    static const char *fragShaderText =
909            "#version 140\n"
910            "#extension GL_ARB_separate_shader_objects : enable\n"
911            "#extension GL_ARB_shading_language_420pack : enable\n"
912            "layout (binding = 0) uniform sampler2D tex;\n"
913            "layout (location = 0) in vec2 texcoord;\n"
914            "void main() {\n"
915            "   gl_FragColor = texture(tex, texcoord);\n"
916            "}\n";
917
918    return demo_prepare_shader(demo, VK_SHADER_STAGE_FRAGMENT,
919                               (const void *) fragShaderText,
920                               strlen(fragShaderText));
921}
922
923static void demo_prepare_pipeline(struct demo *demo)
924{
925    VK_GRAPHICS_PIPELINE_CREATE_INFO pipeline;
926    VK_PIPELINE_VERTEX_INPUT_CREATE_INFO vi;
927    VK_PIPELINE_IA_STATE_CREATE_INFO ia;
928    VK_PIPELINE_RS_STATE_CREATE_INFO rs;
929    VK_PIPELINE_CB_STATE_CREATE_INFO cb;
930    VK_PIPELINE_DS_STATE_CREATE_INFO ds;
931    VK_PIPELINE_SHADER_STAGE_CREATE_INFO vs;
932    VK_PIPELINE_SHADER_STAGE_CREATE_INFO fs;
933    VK_PIPELINE_VP_STATE_CREATE_INFO vp;
934    VK_PIPELINE_MS_STATE_CREATE_INFO ms;
935    VK_RESULT err;
936
937    memset(&pipeline, 0, sizeof(pipeline));
938    pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
939    pipeline.pSetLayoutChain = demo->desc_layout_chain;
940
941    vi = demo->vertices.vi;
942
943    memset(&ia, 0, sizeof(ia));
944    ia.sType = VK_STRUCTURE_TYPE_PIPELINE_IA_STATE_CREATE_INFO;
945    ia.topology = VK_TOPOLOGY_TRIANGLE_LIST;
946
947    memset(&rs, 0, sizeof(rs));
948    rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RS_STATE_CREATE_INFO;
949    rs.fillMode = VK_FILL_SOLID;
950    rs.cullMode = VK_CULL_NONE;
951    rs.frontFace = VK_FRONT_FACE_CCW;
952
953    memset(&cb, 0, sizeof(cb));
954    cb.sType = VK_STRUCTURE_TYPE_PIPELINE_CB_STATE_CREATE_INFO;
955    VK_PIPELINE_CB_ATTACHMENT_STATE att_state[1];
956    memset(att_state, 0, sizeof(att_state));
957    att_state[0].format = demo->format;
958    att_state[0].channelWriteMask = 0xf;
959    att_state[0].blendEnable = VK_FALSE;
960    cb.attachmentCount = 1;
961    cb.pAttachments = att_state;
962
963
964    memset(&vp, 0, sizeof(vp));
965    vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VP_STATE_CREATE_INFO;
966    vp.numViewports = 1;
967    vp.clipOrigin = VK_COORDINATE_ORIGIN_UPPER_LEFT;
968
969    memset(&ds, 0, sizeof(ds));
970    ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DS_STATE_CREATE_INFO;
971    ds.format = demo->depth.format;
972    ds.depthTestEnable = VK_TRUE;
973    ds.depthWriteEnable = VK_TRUE;
974    ds.depthFunc = VK_COMPARE_LESS_EQUAL;
975    ds.depthBoundsEnable = VK_FALSE;
976    ds.back.stencilFailOp = VK_STENCIL_OP_KEEP;
977    ds.back.stencilPassOp = VK_STENCIL_OP_KEEP;
978    ds.back.stencilFunc = VK_COMPARE_ALWAYS;
979    ds.stencilTestEnable = VK_FALSE;
980    ds.front = ds.back;
981
982    memset(&vs, 0, sizeof(vs));
983    vs.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
984    vs.shader.stage = VK_SHADER_STAGE_VERTEX;
985    vs.shader.shader = demo_prepare_vs(demo);
986    vs.shader.linkConstBufferCount = 0;
987
988    memset(&fs, 0, sizeof(fs));
989    fs.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
990    fs.shader.stage = VK_SHADER_STAGE_FRAGMENT;
991    fs.shader.shader = demo_prepare_fs(demo);
992
993    memset(&ms, 0, sizeof(ms));
994    ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MS_STATE_CREATE_INFO;
995    ms.sampleMask = 1;
996    ms.multisampleEnable = VK_FALSE;
997    ms.samples = 1;
998
999    pipeline.pNext = (const void *) &vi;
1000    vi.pNext = (void *) &ia;
1001    ia.pNext = (const void *) &rs;
1002    rs.pNext = (const void *) &cb;
1003    cb.pNext = (const void *) &ms;
1004    ms.pNext = (const void *) &vp;
1005    vp.pNext = (const void *) &ds;
1006    ds.pNext = (const void *) &vs;
1007    vs.pNext = (const void *) &fs;
1008
1009    err = vkCreateGraphicsPipeline(demo->device, &pipeline, &demo->pipeline);
1010    assert(!err);
1011
1012    vkDestroyObject(vs.shader.shader);
1013    vkDestroyObject(fs.shader.shader);
1014}
1015
1016static void demo_prepare_dynamic_states(struct demo *demo)
1017{
1018    VK_DYNAMIC_VP_STATE_CREATE_INFO viewport_create;
1019    VK_DYNAMIC_RS_STATE_CREATE_INFO raster;
1020    VK_DYNAMIC_CB_STATE_CREATE_INFO color_blend;
1021    VK_DYNAMIC_DS_STATE_CREATE_INFO depth_stencil;
1022    VK_RESULT err;
1023
1024    memset(&viewport_create, 0, sizeof(viewport_create));
1025    viewport_create.sType = VK_STRUCTURE_TYPE_DYNAMIC_VP_STATE_CREATE_INFO;
1026    viewport_create.viewportAndScissorCount = 1;
1027    VK_VIEWPORT viewport;
1028    memset(&viewport, 0, sizeof(viewport));
1029    viewport.height = (float) demo->height;
1030    viewport.width = (float) demo->width;
1031    viewport.minDepth = (float) 0.0f;
1032    viewport.maxDepth = (float) 1.0f;
1033    viewport_create.pViewports = &viewport;
1034    VK_RECT scissor;
1035    memset(&scissor, 0, sizeof(scissor));
1036    scissor.extent.width = demo->width;
1037    scissor.extent.height = demo->height;
1038    scissor.offset.x = 0;
1039    scissor.offset.y = 0;
1040    viewport_create.pScissors = &scissor;
1041
1042    memset(&raster, 0, sizeof(raster));
1043    raster.sType = VK_STRUCTURE_TYPE_DYNAMIC_RS_STATE_CREATE_INFO;
1044    raster.pointSize = 1.0;
1045    raster.lineWidth = 1.0;
1046
1047    memset(&color_blend, 0, sizeof(color_blend));
1048    color_blend.sType = VK_STRUCTURE_TYPE_DYNAMIC_CB_STATE_CREATE_INFO;
1049    color_blend.blendConst[0] = 1.0f;
1050    color_blend.blendConst[1] = 1.0f;
1051    color_blend.blendConst[2] = 1.0f;
1052    color_blend.blendConst[3] = 1.0f;
1053
1054    memset(&depth_stencil, 0, sizeof(depth_stencil));
1055    depth_stencil.sType = VK_STRUCTURE_TYPE_DYNAMIC_DS_STATE_CREATE_INFO;
1056    depth_stencil.minDepth = 0.0f;
1057    depth_stencil.maxDepth = 1.0f;
1058    depth_stencil.stencilBackRef = 0;
1059    depth_stencil.stencilFrontRef = 0;
1060    depth_stencil.stencilReadMask = 0xff;
1061    depth_stencil.stencilWriteMask = 0xff;
1062
1063    err = vkCreateDynamicViewportState(demo->device, &viewport_create, &demo->viewport);
1064    assert(!err);
1065
1066    err = vkCreateDynamicRasterState(demo->device, &raster, &demo->raster);
1067    assert(!err);
1068
1069    err = vkCreateDynamicColorBlendState(demo->device,
1070            &color_blend, &demo->color_blend);
1071    assert(!err);
1072
1073    err = vkCreateDynamicDepthStencilState(demo->device,
1074            &depth_stencil, &demo->depth_stencil);
1075    assert(!err);
1076}
1077
1078static void demo_prepare_descriptor_pool(struct demo *demo)
1079{
1080    const VK_DESCRIPTOR_TYPE_COUNT type_count = {
1081        .type = VK_DESCRIPTOR_TYPE_SAMPLER_TEXTURE,
1082        .count = DEMO_TEXTURE_COUNT,
1083    };
1084    const VK_DESCRIPTOR_POOL_CREATE_INFO descriptor_pool = {
1085        .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
1086        .pNext = NULL,
1087        .count = 1,
1088        .pTypeCount = &type_count,
1089    };
1090    VK_RESULT err;
1091
1092    err = vkCreateDescriptorPool(demo->device,
1093            VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, 1,
1094            &descriptor_pool, &demo->desc_pool);
1095    assert(!err);
1096}
1097
1098static void demo_prepare_descriptor_set(struct demo *demo)
1099{
1100    VK_IMAGE_VIEW_ATTACH_INFO view_info[DEMO_TEXTURE_COUNT];
1101    VK_SAMPLER_IMAGE_VIEW_INFO combined_info[DEMO_TEXTURE_COUNT];
1102    VK_UPDATE_SAMPLER_TEXTURES update;
1103    const void *update_array[1] = { &update };
1104    VK_RESULT err;
1105    uint32_t count;
1106    uint32_t i;
1107
1108    for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
1109        view_info[i].sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_ATTACH_INFO;
1110        view_info[i].pNext = NULL;
1111        view_info[i].view = demo->textures[i].view,
1112        view_info[i].layout = VK_IMAGE_LAYOUT_GENERAL;
1113
1114        combined_info[i].sampler = demo->textures[i].sampler;
1115        combined_info[i].pImageView = &view_info[i];
1116    }
1117
1118    memset(&update, 0, sizeof(update));
1119    update.sType = VK_STRUCTURE_TYPE_UPDATE_SAMPLER_TEXTURES;
1120    update.count = DEMO_TEXTURE_COUNT;
1121    update.pSamplerImageViews = combined_info;
1122
1123    err = vkAllocDescriptorSets(demo->desc_pool,
1124            VK_DESCRIPTOR_SET_USAGE_STATIC,
1125            1, &demo->desc_layout,
1126            &demo->desc_set, &count);
1127    assert(!err && count == 1);
1128
1129    vkBeginDescriptorPoolUpdate(demo->device,
1130            VK_DESCRIPTOR_UPDATE_MODE_FASTEST);
1131
1132    vkClearDescriptorSets(demo->desc_pool, 1, &demo->desc_set);
1133    vkUpdateDescriptors(demo->desc_set, 1, update_array);
1134
1135    vkEndDescriptorPoolUpdate(demo->device, demo->cmd);
1136}
1137
1138static void demo_prepare(struct demo *demo)
1139{
1140    const VK_CMD_BUFFER_CREATE_INFO cmd = {
1141        .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,
1142        .pNext = NULL,
1143        .queueNodeIndex = demo->graphics_queue_node_index,
1144        .flags = 0,
1145    };
1146    VK_RESULT err;
1147
1148    demo_prepare_buffers(demo);
1149    demo_prepare_depth(demo);
1150    demo_prepare_textures(demo);
1151    demo_prepare_vertices(demo);
1152    demo_prepare_descriptor_layout(demo);
1153    demo_prepare_pipeline(demo);
1154    demo_prepare_dynamic_states(demo);
1155
1156    err = vkCreateCommandBuffer(demo->device, &cmd, &demo->cmd);
1157    assert(!err);
1158
1159    demo_prepare_descriptor_pool(demo);
1160    demo_prepare_descriptor_set(demo);
1161}
1162
1163static void demo_handle_event(struct demo *demo,
1164                              const xcb_generic_event_t *event)
1165{
1166    switch (event->response_type & 0x7f) {
1167    case XCB_EXPOSE:
1168        demo_draw(demo);
1169        break;
1170    case XCB_CLIENT_MESSAGE:
1171        if((*(xcb_client_message_event_t*)event).data.data32[0] ==
1172           (*demo->atom_wm_delete_window).atom) {
1173            demo->quit = true;
1174        }
1175        break;
1176    case XCB_KEY_RELEASE:
1177        {
1178            const xcb_key_release_event_t *key =
1179                (const xcb_key_release_event_t *) event;
1180
1181            if (key->detail == 0x9)
1182                demo->quit = true;
1183        }
1184        break;
1185    case XCB_DESTROY_NOTIFY:
1186        demo->quit = true;
1187        break;
1188    default:
1189        break;
1190    }
1191}
1192
1193static void demo_run(struct demo *demo)
1194{
1195    xcb_flush(demo->connection);
1196
1197    while (!demo->quit) {
1198        xcb_generic_event_t *event;
1199
1200        event = xcb_wait_for_event(demo->connection);
1201        if (event) {
1202            demo_handle_event(demo, event);
1203            free(event);
1204        }
1205    }
1206}
1207
1208static void demo_create_window(struct demo *demo)
1209{
1210    uint32_t value_mask, value_list[32];
1211
1212    demo->window = xcb_generate_id(demo->connection);
1213
1214    value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
1215    value_list[0] = demo->screen->black_pixel;
1216    value_list[1] = XCB_EVENT_MASK_KEY_RELEASE |
1217                    XCB_EVENT_MASK_EXPOSURE |
1218                    XCB_EVENT_MASK_STRUCTURE_NOTIFY;
1219
1220    xcb_create_window(demo->connection,
1221            XCB_COPY_FROM_PARENT,
1222            demo->window, demo->screen->root,
1223            0, 0, demo->width, demo->height, 0,
1224            XCB_WINDOW_CLASS_INPUT_OUTPUT,
1225            demo->screen->root_visual,
1226            value_mask, value_list);
1227
1228    /* Magic code that will send notification when window is destroyed */
1229    xcb_intern_atom_cookie_t cookie = xcb_intern_atom(demo->connection, 1, 12,
1230                                                      "WM_PROTOCOLS");
1231    xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(demo->connection, cookie, 0);
1232
1233    xcb_intern_atom_cookie_t cookie2 = xcb_intern_atom(demo->connection, 0, 16, "WM_DELETE_WINDOW");
1234    demo->atom_wm_delete_window = xcb_intern_atom_reply(demo->connection, cookie2, 0);
1235
1236    xcb_change_property(demo->connection, XCB_PROP_MODE_REPLACE,
1237                        demo->window, (*reply).atom, 4, 32, 1,
1238                        &(*demo->atom_wm_delete_window).atom);
1239    free(reply);
1240
1241    xcb_map_window(demo->connection, demo->window);
1242}
1243
1244static void demo_init_vk(struct demo *demo)
1245{
1246    const VK_APPLICATION_INFO app = {
1247        .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
1248        .pNext = NULL,
1249        .pAppName = "tri",
1250        .appVersion = 0,
1251        .pEngineName = "tri",
1252        .engineVersion = 0,
1253        .apiVersion = VK_API_VERSION,
1254    };
1255    const VK_INSTANCE_CREATE_INFO inst_info = {
1256        .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
1257        .pNext = NULL,
1258        .pAppInfo = &app,
1259        .pAllocCb = NULL,
1260        .extensionCount = 0,
1261        .ppEnabledExtensionNames = NULL,
1262    };
1263    const VK_WSI_X11_CONNECTION_INFO connection = {
1264        .pConnection = demo->connection,
1265        .root = demo->screen->root,
1266        .provider = 0,
1267    };
1268    const VK_DEVICE_QUEUE_CREATE_INFO queue = {
1269        .queueNodeIndex = 0,
1270        .queueCount = 1,
1271    };
1272    const char *ext_names[] = {
1273        "VK_WSI_X11",
1274    };
1275    const VK_DEVICE_CREATE_INFO device = {
1276        .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
1277        .pNext = NULL,
1278        .queueRecordCount = 1,
1279        .pRequestedQueues = &queue,
1280        .extensionCount = 1,
1281        .ppEnabledExtensionNames = ext_names,
1282        .maxValidationLevel = VK_VALIDATION_LEVEL_END_RANGE,
1283        .flags = VK_DEVICE_CREATE_VALIDATION_BIT,
1284    };
1285    VK_RESULT err;
1286    uint32_t gpu_count;
1287    uint32_t i;
1288    size_t data_size;
1289    uint32_t queue_count;
1290
1291    err = vkCreateInstance(&inst_info, &demo->inst);
1292    if (err == VK_ERROR_INCOMPATIBLE_DRIVER) {
1293        printf("Cannot find a compatible Vulkan installable client driver "
1294               "(ICD).\nExiting ...\n");
1295        fflush(stdout);
1296        exit(1);
1297    } else {
1298        assert(!err);
1299    }
1300
1301    err = vkEnumerateGpus(demo->inst, 1, &gpu_count, &demo->gpu);
1302    assert(!err && gpu_count == 1);
1303
1304    for (i = 0; i < device.extensionCount; i++) {
1305        err = vkGetExtensionSupport(demo->gpu, ext_names[i]);
1306        assert(!err);
1307    }
1308
1309    err = vkWsiX11AssociateConnection(demo->gpu, &connection);
1310    assert(!err);
1311
1312    err = vkCreateDevice(demo->gpu, &device, &demo->device);
1313    assert(!err);
1314
1315    err = vkGetGpuInfo(demo->gpu, VK_INFO_TYPE_PHYSICAL_GPU_PROPERTIES,
1316                        &data_size, NULL);
1317    assert(!err);
1318
1319    demo->gpu_props = (VK_PHYSICAL_GPU_PROPERTIES *) malloc(data_size);
1320    err = vkGetGpuInfo(demo->gpu, VK_INFO_TYPE_PHYSICAL_GPU_PROPERTIES,
1321                        &data_size, demo->gpu_props);
1322    assert(!err);
1323
1324    err = vkGetGpuInfo(demo->gpu, VK_INFO_TYPE_PHYSICAL_GPU_QUEUE_PROPERTIES,
1325                        &data_size, NULL);
1326    assert(!err);
1327
1328    demo->queue_props = (VK_PHYSICAL_GPU_QUEUE_PROPERTIES *) malloc(data_size);
1329    err = vkGetGpuInfo(demo->gpu, VK_INFO_TYPE_PHYSICAL_GPU_QUEUE_PROPERTIES,
1330                        &data_size, demo->queue_props);
1331    assert(!err);
1332	queue_count = (uint32_t) (data_size / sizeof(VK_PHYSICAL_GPU_QUEUE_PROPERTIES));
1333    assert(queue_count >= 1);
1334
1335    for (i = 0; i < queue_count; i++) {
1336        if (demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
1337            break;
1338    }
1339    assert(i < queue_count);
1340    demo->graphics_queue_node_index = i;
1341
1342    err = vkGetDeviceQueue(demo->device, demo->graphics_queue_node_index,
1343            0, &demo->queue);
1344    assert(!err);
1345}
1346
1347static void demo_init_connection(struct demo *demo)
1348{
1349    const xcb_setup_t *setup;
1350    xcb_screen_iterator_t iter;
1351    int scr;
1352
1353    demo->connection = xcb_connect(NULL, &scr);
1354    if (demo->connection == NULL) {
1355        printf("Cannot find a compatible Vulkan installable client driver "
1356               "(ICD).\nExiting ...\n");
1357        fflush(stdout);
1358        exit(1);
1359    }
1360
1361    setup = xcb_get_setup(demo->connection);
1362    iter = xcb_setup_roots_iterator(setup);
1363    while (scr-- > 0)
1364        xcb_screen_next(&iter);
1365
1366    demo->screen = iter.data;
1367}
1368
1369static void demo_init(struct demo *demo, const int argc, const char *argv[])
1370{
1371    memset(demo, 0, sizeof(*demo));
1372
1373    for (int i = 0; i < argc; i++) {
1374        if (strncmp(argv[i], "--use_staging", strlen("--use_staging")) == 0)
1375            demo->use_staging_buffer = true;
1376    }
1377
1378    demo_init_connection(demo);
1379    demo_init_vk(demo);
1380
1381    demo->width = 300;
1382    demo->height = 300;
1383    demo->format = VK_FMT_B8G8R8A8_UNORM;
1384}
1385
1386static void demo_cleanup(struct demo *demo)
1387{
1388    uint32_t i, j;
1389
1390    vkDestroyObject(demo->desc_set);
1391    vkDestroyObject(demo->desc_pool);
1392
1393    vkDestroyObject(demo->cmd);
1394
1395    vkDestroyObject(demo->viewport);
1396    vkDestroyObject(demo->raster);
1397    vkDestroyObject(demo->color_blend);
1398    vkDestroyObject(demo->depth_stencil);
1399
1400    vkDestroyObject(demo->pipeline);
1401    vkDestroyObject(demo->desc_layout_chain);
1402    vkDestroyObject(demo->desc_layout);
1403
1404    vkBindObjectMemory(demo->vertices.buf, 0, VK_NULL_HANDLE, 0);
1405    vkDestroyObject(demo->vertices.buf);
1406    demo_remove_mem_refs(demo, demo->vertices.num_mem, demo->vertices.mem);
1407    for (j = 0; j < demo->vertices.num_mem; j++)
1408        vkFreeMemory(demo->vertices.mem[j]);
1409
1410    for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
1411        vkDestroyObject(demo->textures[i].view);
1412        vkBindObjectMemory(demo->textures[i].image, 0, VK_NULL_HANDLE, 0);
1413        vkDestroyObject(demo->textures[i].image);
1414        demo_remove_mem_refs(demo, demo->textures[i].num_mem, demo->textures[i].mem);
1415        for (j = 0; j < demo->textures[i].num_mem; j++)
1416            vkFreeMemory(demo->textures[i].mem[j]);
1417        free(demo->textures[i].mem);
1418        vkDestroyObject(demo->textures[i].sampler);
1419    }
1420
1421    vkDestroyObject(demo->depth.view);
1422    vkBindObjectMemory(demo->depth.image, 0, VK_NULL_HANDLE, 0);
1423    demo_remove_mem_refs(demo, demo->depth.num_mem, demo->depth.mem);
1424    vkDestroyObject(demo->depth.image);
1425    for (j = 0; j < demo->depth.num_mem; j++)
1426        vkFreeMemory(demo->depth.mem[j]);
1427
1428    for (i = 0; i < DEMO_BUFFER_COUNT; i++) {
1429        vkDestroyObject(demo->buffers[i].fence);
1430        vkDestroyObject(demo->buffers[i].view);
1431        vkDestroyObject(demo->buffers[i].image);
1432        demo_remove_mem_refs(demo, 1, &demo->buffers[i].mem);
1433    }
1434
1435    vkDestroyDevice(demo->device);
1436    vkDestroyInstance(demo->inst);
1437
1438    xcb_destroy_window(demo->connection, demo->window);
1439    xcb_disconnect(demo->connection);
1440}
1441
1442int main(const int argc, const char *argv[])
1443{
1444    struct demo demo;
1445
1446    demo_init(&demo, argc, argv);
1447
1448    demo_prepare(&demo);
1449    demo_create_window(&demo);
1450    demo_run(&demo);
1451
1452    demo_cleanup(&demo);
1453
1454    return 0;
1455}
1456