cube.c revision 71fcc2dae2f302fd2e52836b4098b233762d56f8
1#define _GNU_SOURCE
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <stdbool.h>
6#include <assert.h>
7
8#include <xcb/xcb.h>
9#include <xgl.h>
10#include <xglDbg.h>
11#include <xglWsiX11Ext.h>
12
13#include "icd-bil.h"
14
15#include "linmath.h"
16#include <unistd.h>
17#include <png.h>
18
19#define DEMO_BUFFER_COUNT 2
20#define DEMO_TEXTURE_COUNT 1
21
22/*
23 * When not defined, code will use built-in GLSL compiler
24 * which may not be supported on all drivers
25 */
26#define EXTERNAL_BIL
27
28static char *tex_files[] = {
29    "lunarg-logo-256x256-solid.png"
30};
31
32struct xglcube_vs_uniform {
33    // Must start with MVP
34    XGL_FLOAT   mvp[4][4];
35    XGL_FLOAT   position[12*3][4];
36    XGL_FLOAT   color[12*3][4];
37};
38
39struct xgltexcube_vs_uniform {
40    // Must start with MVP
41    XGL_FLOAT   mvp[4][4];
42    XGL_FLOAT   position[12*3][4];
43    XGL_FLOAT   attr[12*3][4];
44};
45
46//--------------------------------------------------------------------------------------
47// Mesh and VertexFormat Data
48//--------------------------------------------------------------------------------------
49struct Vertex
50{
51    XGL_FLOAT posX, posY, posZ, posW;    // Position data
52    XGL_FLOAT r, g, b, a;                // Color
53};
54
55struct VertexPosTex
56{
57    XGL_FLOAT posX, posY, posZ, posW;    // Position data
58    XGL_FLOAT u, v, s, t;                // Texcoord
59};
60
61#define XYZ1(_x_, _y_, _z_)         (_x_), (_y_), (_z_), 1.f
62#define UV(_u_, _v_)                (_u_), (_v_), 0.f, 1.f
63
64static const XGL_FLOAT g_vertex_buffer_data[] = {
65    -1.0f,-1.0f,-1.0f,  // Vertex 0
66    -1.0f,-1.0f, 1.0f,
67    -1.0f, 1.0f, 1.0f,
68
69    -1.0f, 1.0f, 1.0f,  // Vertex 1
70    -1.0f, 1.0f,-1.0f,
71    -1.0f,-1.0f,-1.0f,
72
73    -1.0f,-1.0f,-1.0f,  // Vertex 2
74     1.0f, 1.0f,-1.0f,
75     1.0f,-1.0f,-1.0f,
76
77    -1.0f,-1.0f,-1.0f,  // Vertex 3
78     1.0f, 1.0f,-1.0f,
79    -1.0f, 1.0f,-1.0f,
80
81    -1.0f,-1.0f,-1.0f,  // Vertex 4
82     1.0f,-1.0f, 1.0f,
83     1.0f,-1.0f,-1.0f,
84
85    -1.0f,-1.0f,-1.0f,  // Vertex 5
86    -1.0f,-1.0f, 1.0f,
87     1.0f,-1.0f, 1.0f,
88
89    -1.0f, 1.0f,-1.0f,  // Vertex 6
90    -1.0f, 1.0f, 1.0f,
91     1.0f, 1.0f, 1.0f,
92
93    -1.0f, 1.0f,-1.0f,  // Vertex 7
94     1.0f, 1.0f,-1.0f,
95     1.0f, 1.0f, 1.0f,
96
97     1.0f, 1.0f,-1.0f,  // Vertex 8
98     1.0f, 1.0f, 1.0f,
99     1.0f,-1.0f, 1.0f,
100
101     1.0f,-1.0f, 1.0f,  // Vertex 9
102     1.0f,-1.0f,-1.0f,
103     1.0f, 1.0f,-1.0f,
104
105    -1.0f, 1.0f, 1.0f,  // Vertex 10
106     1.0f, 1.0f, 1.0f,
107    -1.0f,-1.0f, 1.0f,
108
109    -1.0f,-1.0f, 1.0f,  // Vertex 11
110     1.0f,-1.0f, 1.0f,
111     1.0f, 1.0f, 1.0f,
112};
113
114static const XGL_FLOAT g_uv_buffer_data[] = {
115    1.0f, 0.0f,  // Vertex 0
116    0.0f, 0.0f,
117    0.0f, 1.0f,
118
119    0.0f, 1.0f,  // Vertex 1
120    1.0f, 1.0f,
121    1.0f, 0.0f,
122
123//    0.0f, 1.0f,  // Vertex 2
124//    1.0f, 0.0f,
125//    0.0f, 0.0f,
126
127//    0.0f, 1.0f,  // Vertex 3
128//    1.0f, 0.0f,
129//    1.0f, 1.0f,
130
131    0.0f, 0.0f,  // Vertex 2
132    1.0f, 1.0f,
133    1.0f, 0.0f,
134
135    0.0f, 0.0f,  // Vertex 3
136    1.0f, 1.0f,
137    0.0f, 1.0f,
138
139    0.0f, 1.0f,  // Vertex 4
140    1.0f, 0.0f,
141    0.0f, 0.0f,
142
143    0.0f, 1.0f,  // Vertex 5
144    1.0f, 1.0f,
145    1.0f, 0.0f,
146
147    0.0f, 1.0f,  // Vertex 6
148    1.0f, 1.0f,
149    1.0f, 0.0f,
150
151    0.0f, 1.0f,  // Vertex 7
152    0.0f, 0.0f,
153    1.0f, 0.0f,
154
155    0.0f, 1.0f,  // Vertex 8
156    1.0f, 1.0f,
157    1.0f, 0.0f,
158
159    1.0f, 0.0f,  // Vertex 9
160    0.0f, 0.0f,
161    0.0f, 1.0f,
162
163    1.0f, 1.0f,  // Vertex 10
164    0.0f, 1.0f,
165    1.0f, 0.0f,
166
167    1.0f, 0.0f,  // Vertex 11
168    0.0f, 0.0f,
169    0.0f, 1.0f,
170};
171
172void dumpMatrix(const char *note, mat4x4 MVP)
173{
174    int i;
175
176    printf("%s: \n", note);
177    for (i=0; i<4; i++) {
178        printf("%f, %f, %f, %f\n", MVP[i][0], MVP[i][1], MVP[i][2], MVP[i][3]);
179    }
180    printf("\n");
181    fflush(stdout);
182}
183
184void dumpVec4(const char *note, vec4 vector)
185{
186    printf("%s: \n", note);
187        printf("%f, %f, %f, %f\n", vector[0], vector[1], vector[2], vector[3]);
188    printf("\n");
189    fflush(stdout);
190}
191
192struct demo {
193    xcb_connection_t *connection;
194    xcb_screen_t *screen;
195
196    XGL_PHYSICAL_GPU gpu;
197    XGL_DEVICE device;
198    XGL_QUEUE queue;
199
200    int width, height;
201    XGL_FORMAT format;
202
203    struct {
204        XGL_IMAGE image;
205        XGL_GPU_MEMORY mem;
206
207        XGL_COLOR_ATTACHMENT_VIEW view;
208        XGL_FENCE fence;
209    } buffers[DEMO_BUFFER_COUNT];
210
211    struct {
212        XGL_FORMAT format;
213
214        XGL_IMAGE image;
215        XGL_UINT num_mem;
216        XGL_GPU_MEMORY *mem;
217        XGL_DEPTH_STENCIL_VIEW view;
218    } depth;
219
220    struct {
221        XGL_SAMPLER sampler;
222
223        char *filename;
224        XGL_IMAGE image;
225        XGL_UINT num_mem;
226        XGL_GPU_MEMORY *mem;
227        XGL_IMAGE_VIEW view;
228    } textures[DEMO_TEXTURE_COUNT];
229
230    struct {
231        XGL_BUFFER buf;
232        XGL_UINT num_mem;
233        XGL_GPU_MEMORY *mem;
234        XGL_BUFFER_VIEW view;
235        XGL_BUFFER_VIEW_ATTACH_INFO attach;
236    } uniform_data;
237
238    XGL_DESCRIPTOR_SET_LAYOUT desc_layout_vs;
239    XGL_DESCRIPTOR_SET_LAYOUT desc_layout_fs;
240    XGL_DESCRIPTOR_SET_LAYOUT *desc_layout_last;
241    XGL_PIPELINE pipeline;
242
243    XGL_DYNAMIC_VP_STATE_OBJECT viewport;
244    XGL_DYNAMIC_RS_STATE_OBJECT raster;
245    XGL_DYNAMIC_CB_STATE_OBJECT color_blend;
246    XGL_DYNAMIC_DS_STATE_OBJECT depth_stencil;
247
248    mat4x4 projection_matrix;
249    mat4x4 view_matrix;
250    mat4x4 model_matrix;
251
252    XGL_FLOAT spin_angle;
253    XGL_FLOAT spin_increment;
254    bool pause;
255
256    XGL_CMD_BUFFER cmd;
257
258    XGL_DESCRIPTOR_REGION desc_region;
259    XGL_DESCRIPTOR_SET desc_set;
260
261    xcb_window_t window;
262    xcb_intern_atom_reply_t *atom_wm_delete_window;
263
264    bool quit;
265    XGL_UINT current_buffer;
266};
267
268static void demo_draw_build_cmd(struct demo *demo)
269{
270    const XGL_COLOR_ATTACHMENT_BIND_INFO color_attachment = {
271        .view = demo->buffers[demo->current_buffer].view,
272        .layout = XGL_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
273    };
274    const XGL_DEPTH_STENCIL_BIND_INFO depth_stencil = {
275        .view = demo->depth.view,
276        .layout = XGL_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
277    };
278    const XGL_FLOAT clear_color[4] = { 0.2f, 0.2f, 0.2f, 0.2f };
279    const XGL_FLOAT clear_depth = 1.0f;
280    XGL_IMAGE_SUBRESOURCE_RANGE clear_range;
281    XGL_CMD_BUFFER_GRAPHICS_BEGIN_INFO graphics_cmd_buf_info = {
282        .sType = XGL_STRUCTURE_TYPE_CMD_BUFFER_GRAPHICS_BEGIN_INFO,
283        .pNext = NULL,
284        .operation = XGL_RENDER_PASS_OPERATION_BEGIN_AND_END,
285    };
286    XGL_CMD_BUFFER_BEGIN_INFO cmd_buf_info = {
287        .sType = XGL_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,
288        .pNext = &graphics_cmd_buf_info,
289        .flags = XGL_CMD_BUFFER_OPTIMIZE_GPU_SMALL_BATCH_BIT |
290            XGL_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT,
291    };
292    XGL_RESULT err;
293    XGL_ATTACHMENT_LOAD_OP load_op = XGL_ATTACHMENT_LOAD_OP_DONT_CARE;
294    XGL_ATTACHMENT_STORE_OP store_op = XGL_ATTACHMENT_STORE_OP_DONT_CARE;
295    const XGL_FRAMEBUFFER_CREATE_INFO fb_info = {
296         .sType = XGL_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
297         .pNext = NULL,
298         .colorAttachmentCount = 1,
299         .pColorAttachments = (XGL_COLOR_ATTACHMENT_BIND_INFO*) &color_attachment,
300         .pDepthStencilAttachment = (XGL_DEPTH_STENCIL_BIND_INFO*) &depth_stencil,
301         .sampleCount = 1,
302         .width  = demo->width,
303         .height = demo->height,
304         .layers = 1,
305    };
306    XGL_RENDER_PASS_CREATE_INFO rp_info;
307
308    memset(&rp_info, 0 , sizeof(rp_info));
309    err = xglCreateFramebuffer(demo->device, &fb_info, &(rp_info.framebuffer));
310    assert(!err);
311    rp_info.sType = XGL_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
312    rp_info.renderArea.extent.width = demo->width;
313    rp_info.renderArea.extent.height = demo->height;
314    rp_info.pColorLoadOps = &load_op;
315    rp_info.pColorStoreOps = &store_op;
316    rp_info.depthLoadOp = XGL_ATTACHMENT_LOAD_OP_DONT_CARE;
317    rp_info.depthStoreOp = XGL_ATTACHMENT_STORE_OP_DONT_CARE;
318    rp_info.stencilLoadOp = XGL_ATTACHMENT_LOAD_OP_DONT_CARE;
319    rp_info.stencilStoreOp = XGL_ATTACHMENT_STORE_OP_DONT_CARE;
320    err = xglCreateRenderPass(demo->device, &rp_info, &(graphics_cmd_buf_info.renderPass));
321    assert(!err);
322
323    err = xglBeginCommandBuffer(demo->cmd, &cmd_buf_info);
324    assert(!err);
325
326    xglCmdBindPipeline(demo->cmd, XGL_PIPELINE_BIND_POINT_GRAPHICS,
327                                  demo->pipeline);
328    xglCmdBindDescriptorSet(demo->cmd, XGL_PIPELINE_BIND_POINT_GRAPHICS,
329            demo->desc_set, NULL);
330
331    xglCmdBindDynamicStateObject(demo->cmd, XGL_STATE_BIND_VIEWPORT, demo->viewport);
332    xglCmdBindDynamicStateObject(demo->cmd, XGL_STATE_BIND_RASTER, demo->raster);
333    xglCmdBindDynamicStateObject(demo->cmd, XGL_STATE_BIND_COLOR_BLEND,
334                                     demo->color_blend);
335    xglCmdBindDynamicStateObject(demo->cmd, XGL_STATE_BIND_DEPTH_STENCIL,
336                                     demo->depth_stencil);
337
338    clear_range.aspect = XGL_IMAGE_ASPECT_COLOR;
339    clear_range.baseMipLevel = 0;
340    clear_range.mipLevels = 1;
341    clear_range.baseArraySlice = 0;
342    clear_range.arraySize = 1;
343    xglCmdClearColorImage(demo->cmd,
344            demo->buffers[demo->current_buffer].image,
345            clear_color, 1, &clear_range);
346
347    clear_range.aspect = XGL_IMAGE_ASPECT_DEPTH;
348    xglCmdClearDepthStencil(demo->cmd, demo->depth.image,
349            clear_depth, 0, 1, &clear_range);
350
351    xglCmdDraw(demo->cmd, 0, 12 * 3, 0, 1);
352
353    err = xglEndCommandBuffer(demo->cmd);
354    assert(!err);
355}
356
357
358void demo_update_data_buffer(struct demo *demo)
359{
360    mat4x4 MVP, Model, VP;
361    int matrixSize = sizeof(MVP);
362    XGL_UINT8 *pData;
363    XGL_RESULT err;
364
365    mat4x4_mul(VP, demo->projection_matrix, demo->view_matrix);
366
367    // Rotate 22.5 degrees around the Y axis
368    mat4x4_dup(Model, demo->model_matrix);
369    mat4x4_rotate(demo->model_matrix, Model, 0.0f, 1.0f, 0.0f, degreesToRadians(demo->spin_angle));
370    mat4x4_mul(MVP, VP, demo->model_matrix);
371
372    assert(demo->uniform_data.num_mem == 1);
373    err = xglMapMemory(demo->uniform_data.mem[0], 0, (XGL_VOID **) &pData);
374    assert(!err);
375
376    memcpy(pData, (const void*) &MVP[0][0], matrixSize);
377
378    err = xglUnmapMemory(demo->uniform_data.mem[0]);
379    assert(!err);
380}
381
382static void demo_draw(struct demo *demo)
383{
384    const XGL_WSI_X11_PRESENT_INFO present = {
385        .destWindow = demo->window,
386        .srcImage = demo->buffers[demo->current_buffer].image,
387        .async = true,
388        .flip = false,
389    };
390    XGL_FENCE fence = demo->buffers[demo->current_buffer].fence;
391    XGL_RESULT err;
392
393    demo_draw_build_cmd(demo);
394
395    err = xglWaitForFences(demo->device, 1, &fence, XGL_TRUE, ~((XGL_UINT64) 0));
396    assert(err == XGL_SUCCESS || err == XGL_ERROR_UNAVAILABLE);
397
398    err = xglQueueSubmit(demo->queue, 1, &demo->cmd,
399            0, NULL, XGL_NULL_HANDLE);
400    assert(!err);
401
402    err = xglWsiX11QueuePresent(demo->queue, &present, fence);
403    assert(!err);
404
405    demo->current_buffer = (demo->current_buffer + 1) % DEMO_BUFFER_COUNT;
406}
407
408static void demo_prepare_buffers(struct demo *demo)
409{
410    const XGL_WSI_X11_PRESENTABLE_IMAGE_CREATE_INFO presentable_image = {
411        .format = demo->format,
412        .usage = XGL_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
413        .extent = {
414            .width = demo->width,
415            .height = demo->height,
416        },
417        .flags = 0,
418    };
419    const XGL_FENCE_CREATE_INFO fence = {
420        .sType = XGL_STRUCTURE_TYPE_FENCE_CREATE_INFO,
421        .pNext = NULL,
422        .flags = 0,
423    };
424    XGL_RESULT err;
425    XGL_UINT i;
426
427    for (i = 0; i < DEMO_BUFFER_COUNT; i++) {
428        XGL_COLOR_ATTACHMENT_VIEW_CREATE_INFO color_attachment_view = {
429            .sType = XGL_STRUCTURE_TYPE_COLOR_ATTACHMENT_VIEW_CREATE_INFO,
430            .pNext = NULL,
431            .format = demo->format,
432            .mipLevel = 0,
433            .baseArraySlice = 0,
434            .arraySize = 1,
435        };
436
437        err = xglWsiX11CreatePresentableImage(demo->device, &presentable_image,
438                &demo->buffers[i].image, &demo->buffers[i].mem);
439        assert(!err);
440
441        color_attachment_view.image = demo->buffers[i].image;
442
443        err = xglCreateColorAttachmentView(demo->device,
444                &color_attachment_view, &demo->buffers[i].view);
445        assert(!err);
446
447        err = xglCreateFence(demo->device,
448                &fence, &demo->buffers[i].fence);
449        assert(!err);
450    }
451}
452
453static void demo_prepare_depth(struct demo *demo)
454{
455    const XGL_FORMAT depth_format = XGL_FMT_D16_UNORM;
456    const XGL_IMAGE_CREATE_INFO image = {
457        .sType = XGL_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
458        .pNext = NULL,
459        .imageType = XGL_IMAGE_2D,
460        .format = depth_format,
461        .extent = { demo->width, demo->height, 1 },
462        .mipLevels = 1,
463        .arraySize = 1,
464        .samples = 1,
465        .tiling = XGL_OPTIMAL_TILING,
466        .usage = XGL_IMAGE_USAGE_DEPTH_STENCIL_BIT,
467        .flags = 0,
468    };
469    XGL_MEMORY_ALLOC_IMAGE_INFO img_alloc = {
470        .sType = XGL_STRUCTURE_TYPE_MEMORY_ALLOC_IMAGE_INFO,
471        .pNext = NULL,
472    };
473    XGL_MEMORY_ALLOC_INFO mem_alloc = {
474        .sType = XGL_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
475        .pNext = &img_alloc,
476        .allocationSize = 0,
477        .memProps = XGL_MEMORY_PROPERTY_GPU_ONLY,
478        .memType = XGL_MEMORY_TYPE_IMAGE,
479        .memPriority = XGL_MEMORY_PRIORITY_NORMAL,
480    };
481    XGL_DEPTH_STENCIL_VIEW_CREATE_INFO view = {
482        .sType = XGL_STRUCTURE_TYPE_DEPTH_STENCIL_VIEW_CREATE_INFO,
483        .pNext = NULL,
484        .image = XGL_NULL_HANDLE,
485        .mipLevel = 0,
486        .baseArraySlice = 0,
487        .arraySize = 1,
488        .flags = 0,
489    };
490    XGL_MEMORY_REQUIREMENTS *mem_reqs;
491    XGL_SIZE mem_reqs_size = sizeof(XGL_MEMORY_REQUIREMENTS);
492    XGL_IMAGE_MEMORY_REQUIREMENTS img_reqs;
493    XGL_SIZE img_reqs_size = sizeof(XGL_IMAGE_MEMORY_REQUIREMENTS);
494    XGL_RESULT err;
495    XGL_UINT num_allocations = 0;
496    XGL_SIZE num_alloc_size = sizeof(num_allocations);
497
498    demo->depth.format = depth_format;
499
500    /* create image */
501    err = xglCreateImage(demo->device, &image,
502            &demo->depth.image);
503    assert(!err);
504
505
506    err = xglGetObjectInfo(demo->depth.image, XGL_INFO_TYPE_MEMORY_ALLOCATION_COUNT, &num_alloc_size, &num_allocations);
507    assert(!err && num_alloc_size == sizeof(num_allocations));
508    mem_reqs = malloc(num_allocations * sizeof(XGL_MEMORY_REQUIREMENTS));
509    demo->depth.mem = malloc(num_allocations * sizeof(XGL_GPU_MEMORY));
510    demo->depth.num_mem = num_allocations;
511    err = xglGetObjectInfo(demo->depth.image,
512                    XGL_INFO_TYPE_MEMORY_REQUIREMENTS,
513                    &mem_reqs_size, mem_reqs);
514    assert(!err && mem_reqs_size == num_allocations * sizeof(XGL_MEMORY_REQUIREMENTS));
515    err = xglGetObjectInfo(demo->depth.image,
516                    XGL_INFO_TYPE_IMAGE_MEMORY_REQUIREMENTS,
517                    &img_reqs_size, &img_reqs);
518    assert(!err && img_reqs_size == sizeof(XGL_IMAGE_MEMORY_REQUIREMENTS));
519    img_alloc.usage = img_reqs.usage;
520    img_alloc.formatClass = img_reqs.formatClass;
521    img_alloc.samples = img_reqs.samples;
522    for (XGL_UINT i = 0; i < num_allocations; i ++) {
523        mem_alloc.allocationSize = mem_reqs[i].size;
524
525        /* allocate memory */
526        err = xglAllocMemory(demo->device, &mem_alloc,
527                    &(demo->depth.mem[i]));
528        assert(!err);
529
530        /* bind memory */
531        err = xglBindObjectMemory(demo->depth.image, i,
532                demo->depth.mem[i], 0);
533        assert(!err);
534    }
535
536    /* create image view */
537    view.image = demo->depth.image;
538    err = xglCreateDepthStencilView(demo->device, &view,
539            &demo->depth.view);
540    assert(!err);
541}
542
543/** loadTexture
544 * 	loads a png file into an memory object, using cstdio , libpng.
545 *
546 *    	\param demo : Needed to access XGL calls
547 * 	\param filename : the png file to be loaded
548 * 	\param width : width of png, to be updated as a side effect of this function
549 * 	\param height : height of png, to be updated as a side effect of this function
550 *
551 * 	\return bool : an opengl texture id.  true if successful?,
552 * 					should be validated by the client of this function.
553 *
554 * Source: http://en.wikibooks.org/wiki/OpenGL_Programming/Intermediate/Textures
555 * Modified to copy image to memory
556 *
557 */
558bool loadTexture(char *filename, XGL_UINT8 *rgba_data,
559                 XGL_SUBRESOURCE_LAYOUT *layout,
560                 XGL_INT *width, XGL_INT *height)
561{
562  //header for testing if it is a png
563  png_byte header[8];
564  int i, is_png, bit_depth, color_type,rowbytes;
565  png_uint_32 twidth, theight;
566  png_structp  png_ptr;
567  png_infop info_ptr, end_info;
568  png_byte *image_data;
569  png_bytep *row_pointers;
570
571  //open file as binary
572  FILE *fp = fopen(filename, "rb");
573  if (!fp) {
574    return false;
575  }
576
577  //read the header
578  fread(header, 1, 8, fp);
579
580  //test if png
581  is_png = !png_sig_cmp(header, 0, 8);
582  if (!is_png) {
583    fclose(fp);
584    return false;
585  }
586
587  //create png struct
588  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
589      NULL, NULL);
590  if (!png_ptr) {
591    fclose(fp);
592    return (false);
593  }
594
595  //create png info struct
596  info_ptr = png_create_info_struct(png_ptr);
597  if (!info_ptr) {
598    png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
599    fclose(fp);
600    return (false);
601  }
602
603  //create png info struct
604  end_info = png_create_info_struct(png_ptr);
605  if (!end_info) {
606    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
607    fclose(fp);
608    return (false);
609  }
610
611  //png error stuff, not sure libpng man suggests this.
612  if (setjmp(png_jmpbuf(png_ptr))) {
613    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
614    fclose(fp);
615    return (false);
616  }
617
618  //init png reading
619  png_init_io(png_ptr, fp);
620
621  //let libpng know you already read the first 8 bytes
622  png_set_sig_bytes(png_ptr, 8);
623
624  // read all the info up to the image data
625  png_read_info(png_ptr, info_ptr);
626
627  // get info about png
628  png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type,
629      NULL, NULL, NULL);
630
631  //update width and height based on png info
632  *width = twidth;
633  *height = theight;
634
635  // Require that incoming texture be 8bits per color component
636  // and 4 components (RGBA).
637  if (png_get_bit_depth(png_ptr, info_ptr) != 8 ||
638      png_get_channels(png_ptr, info_ptr) != 4) {
639      return false;
640  }
641
642  if (rgba_data == NULL) {
643      // If data pointer is null, we just want the width & height
644      // clean up memory and close stuff
645      png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
646      fclose(fp);
647
648      return true;
649  }
650
651  // Update the png info struct.
652  png_read_update_info(png_ptr, info_ptr);
653
654  // Row size in bytes.
655  rowbytes = png_get_rowbytes(png_ptr, info_ptr);
656
657  // Allocate the image_data as a big block, to be given to opengl
658  image_data = (png_byte *)malloc(rowbytes * theight * sizeof(png_byte));
659  if (!image_data) {
660    //clean up memory and close stuff
661    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
662    fclose(fp);
663    return false;
664  }
665
666  // row_pointers is for pointing to image_data for reading the png with libpng
667  row_pointers = (png_bytep *)malloc(theight * sizeof(png_bytep));
668  if (!row_pointers) {
669    //clean up memory and close stuff
670    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
671    // delete[] image_data;
672    fclose(fp);
673    return false;
674  }
675  // set the individual row_pointers to point at the correct offsets of image_data
676  for (i = 0; i < theight; ++i)
677    row_pointers[theight - 1 - i] = rgba_data + i * rowbytes;
678
679  // read the png into image_data through row_pointers
680  png_read_image(png_ptr, row_pointers);
681
682  // clean up memory and close stuff
683  png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
684  free(row_pointers);
685  free(image_data);
686  fclose(fp);
687
688  return true;
689}
690
691static void demo_prepare_textures(struct demo *demo)
692{
693    const XGL_FORMAT tex_format = XGL_FMT_R8G8B8A8_UNORM;
694    XGL_INT tex_width;
695    XGL_INT tex_height;
696    XGL_RESULT err;
697    XGL_UINT i;
698
699    for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
700        const XGL_SAMPLER_CREATE_INFO sampler = {
701            .sType = XGL_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
702            .pNext = NULL,
703            .magFilter = XGL_TEX_FILTER_NEAREST,
704            .minFilter = XGL_TEX_FILTER_NEAREST,
705            .mipMode = XGL_TEX_MIPMAP_BASE,
706            .addressU = XGL_TEX_ADDRESS_CLAMP,
707            .addressV = XGL_TEX_ADDRESS_CLAMP,
708            .addressW = XGL_TEX_ADDRESS_CLAMP,
709            .mipLodBias = 0.0f,
710            .maxAnisotropy = 0,
711            .compareFunc = XGL_COMPARE_NEVER,
712            .minLod = 0.0f,
713            .maxLod = 0.0f,
714            .borderColorType = XGL_BORDER_COLOR_OPAQUE_WHITE,
715        };
716
717        assert(loadTexture(tex_files[i], NULL, NULL, &tex_width, &tex_height));
718
719        const XGL_IMAGE_CREATE_INFO image = {
720            .sType = XGL_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
721            .pNext = NULL,
722            .imageType = XGL_IMAGE_2D,
723            .format = tex_format,
724            .extent = { tex_width, tex_height, 1 },
725            .mipLevels = 1,
726            .arraySize = 1,
727            .samples = 1,
728            .tiling = XGL_LINEAR_TILING,
729            .usage = XGL_IMAGE_USAGE_SHADER_ACCESS_READ_BIT,
730            .flags = 0,
731        };
732        XGL_MEMORY_ALLOC_IMAGE_INFO img_alloc = {
733            .sType = XGL_STRUCTURE_TYPE_MEMORY_ALLOC_IMAGE_INFO,
734            .pNext = NULL,
735        };
736        XGL_MEMORY_ALLOC_INFO mem_alloc = {
737            .sType = XGL_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
738            .pNext = &img_alloc,
739            .allocationSize = 0,
740            .memProps = XGL_MEMORY_PROPERTY_GPU_ONLY,
741            .memType = XGL_MEMORY_TYPE_IMAGE,
742            .memPriority = XGL_MEMORY_PRIORITY_NORMAL,
743        };
744        XGL_IMAGE_VIEW_CREATE_INFO view = {
745            .sType = XGL_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
746            .pNext = NULL,
747            .image = XGL_NULL_HANDLE,
748            .viewType = XGL_IMAGE_VIEW_2D,
749            .format = image.format,
750            .channels = { XGL_CHANNEL_SWIZZLE_R,
751                          XGL_CHANNEL_SWIZZLE_G,
752                          XGL_CHANNEL_SWIZZLE_B,
753                          XGL_CHANNEL_SWIZZLE_A, },
754            .subresourceRange = { XGL_IMAGE_ASPECT_COLOR, 0, 1, 0, 1 },
755            .minLod = 0.0f,
756        };
757
758        XGL_MEMORY_REQUIREMENTS *mem_reqs;
759        XGL_SIZE mem_reqs_size = sizeof(XGL_MEMORY_REQUIREMENTS);
760        XGL_IMAGE_MEMORY_REQUIREMENTS img_reqs;
761        XGL_SIZE img_reqs_size = sizeof(XGL_IMAGE_MEMORY_REQUIREMENTS);
762        XGL_UINT num_allocations = 0;
763        XGL_SIZE num_alloc_size = sizeof(num_allocations);
764
765        /* create sampler */
766        err = xglCreateSampler(demo->device, &sampler,
767                &demo->textures[i].sampler);
768        assert(!err);
769
770        /* create image */
771        err = xglCreateImage(demo->device, &image,
772                &demo->textures[i].image);
773        assert(!err);
774
775        err = xglGetObjectInfo(demo->textures[i].image,
776                    XGL_INFO_TYPE_MEMORY_ALLOCATION_COUNT,
777                    &num_alloc_size, &num_allocations);
778        assert(!err && num_alloc_size == sizeof(num_allocations));
779        mem_reqs = malloc(num_allocations * sizeof(XGL_MEMORY_REQUIREMENTS));
780        demo->textures[i].mem = malloc(num_allocations * sizeof(XGL_GPU_MEMORY));
781        demo->textures[i].num_mem = num_allocations;
782        err = xglGetObjectInfo(demo->textures[i].image,
783                    XGL_INFO_TYPE_MEMORY_REQUIREMENTS,
784                    &mem_reqs_size, mem_reqs);
785        assert(!err && mem_reqs_size == num_allocations * sizeof(XGL_MEMORY_REQUIREMENTS));
786        err = xglGetObjectInfo(demo->textures[i].image,
787                        XGL_INFO_TYPE_IMAGE_MEMORY_REQUIREMENTS,
788                        &img_reqs_size, &img_reqs);
789        assert(!err && img_reqs_size == sizeof(XGL_IMAGE_MEMORY_REQUIREMENTS));
790        img_alloc.usage = img_reqs.usage;
791        img_alloc.formatClass = img_reqs.formatClass;
792        img_alloc.samples = img_reqs.samples;
793        for (XGL_UINT j = 0; j < num_allocations; j ++) {
794            mem_alloc.allocationSize = mem_reqs[j].size;
795
796            /* allocate memory */
797            err = xglAllocMemory(demo->device, &mem_alloc,
798                        &(demo->textures[i].mem[j]));
799            assert(!err);
800
801            /* bind memory */
802            err = xglBindObjectMemory(demo->textures[i].image, j,
803                    demo->textures[i].mem[j], 0);
804            assert(!err);
805        }
806
807        /* create image view */
808        view.image = demo->textures[i].image;
809        err = xglCreateImageView(demo->device, &view,
810                &demo->textures[i].view);
811        assert(!err);
812    }
813
814    for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
815        const XGL_IMAGE_SUBRESOURCE subres = {
816            .aspect = XGL_IMAGE_ASPECT_COLOR,
817            .mipLevel = 0,
818            .arraySlice = 0,
819        };
820        XGL_SUBRESOURCE_LAYOUT layout;
821        XGL_SIZE layout_size = sizeof(layout);
822        XGL_VOID *data;
823
824        err = xglGetImageSubresourceInfo(demo->textures[i].image, &subres,
825                XGL_INFO_TYPE_SUBRESOURCE_LAYOUT, &layout_size, &layout);
826        assert(!err && layout_size == sizeof(layout));
827        assert(demo->textures[i].num_mem == 1);
828
829        err = xglMapMemory(demo->textures[i].mem[0], 0, &data);
830        assert(!err);
831
832        loadTexture(tex_files[i], data, &layout, &tex_width, &tex_height);
833
834        err = xglUnmapMemory(demo->textures[i].mem[0]);
835        assert(!err);
836    }
837}
838
839void demo_prepare_cube_data_buffer(struct demo *demo)
840{
841    XGL_BUFFER_CREATE_INFO buf_info;
842    XGL_BUFFER_VIEW_CREATE_INFO view_info;
843    XGL_MEMORY_ALLOC_BUFFER_INFO buf_alloc = {
844        .sType = XGL_STRUCTURE_TYPE_MEMORY_ALLOC_BUFFER_INFO,
845        .pNext = NULL,
846    };
847    XGL_MEMORY_ALLOC_INFO alloc_info = {
848        .sType = XGL_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
849        .pNext = &buf_alloc,
850        .allocationSize = 0,
851        .memProps = XGL_MEMORY_PROPERTY_CPU_VISIBLE_BIT,
852        .memType = XGL_MEMORY_TYPE_BUFFER,
853        .memPriority = XGL_MEMORY_PRIORITY_NORMAL,
854    };
855    XGL_MEMORY_REQUIREMENTS *mem_reqs;
856    XGL_SIZE mem_reqs_size = sizeof(XGL_MEMORY_REQUIREMENTS);
857    XGL_BUFFER_MEMORY_REQUIREMENTS buf_reqs;
858    XGL_SIZE buf_reqs_size = sizeof(XGL_BUFFER_MEMORY_REQUIREMENTS);
859    XGL_UINT num_allocations = 0;
860    XGL_SIZE num_alloc_size = sizeof(num_allocations);
861    XGL_UINT8 *pData;
862    int i;
863    mat4x4 MVP, VP;
864    XGL_RESULT err;
865    struct xgltexcube_vs_uniform data;
866
867    mat4x4_mul(VP, demo->projection_matrix, demo->view_matrix);
868    mat4x4_mul(MVP, VP, demo->model_matrix);
869    memcpy(data.mvp, MVP, sizeof(MVP));
870//    dumpMatrix("MVP", MVP);
871
872    for (i=0; i<12*3; i++) {
873        data.position[i][0] = g_vertex_buffer_data[i*3];
874        data.position[i][1] = g_vertex_buffer_data[i*3+1];
875        data.position[i][2] = g_vertex_buffer_data[i*3+2];
876        data.position[i][3] = 1.0f;
877        data.attr[i][0] = g_uv_buffer_data[2*i];
878        data.attr[i][1] = g_uv_buffer_data[2*i + 1];
879        data.attr[i][2] = 0;
880        data.attr[i][3] = 0;
881    }
882
883    memset(&buf_info, 0, sizeof(buf_info));
884    buf_info.sType = XGL_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
885    buf_info.size = sizeof(data);
886    buf_info.usage = XGL_BUFFER_USAGE_UNIFORM_READ_BIT;
887    err = xglCreateBuffer(demo->device, &buf_info, &demo->uniform_data.buf);
888    assert(!err);
889
890    err = xglGetObjectInfo(demo->uniform_data.buf,
891                           XGL_INFO_TYPE_MEMORY_ALLOCATION_COUNT,
892                           &num_alloc_size, &num_allocations);
893    assert(!err && num_alloc_size == sizeof(num_allocations));
894    mem_reqs = malloc(num_allocations * sizeof(XGL_MEMORY_REQUIREMENTS));
895    demo->uniform_data.mem = malloc(num_allocations * sizeof(XGL_GPU_MEMORY));
896    demo->uniform_data.num_mem = num_allocations;
897    err = xglGetObjectInfo(demo->uniform_data.buf,
898            XGL_INFO_TYPE_MEMORY_REQUIREMENTS,
899            &mem_reqs_size, mem_reqs);
900    assert(!err && mem_reqs_size == num_allocations * sizeof(*mem_reqs));
901    err = xglGetObjectInfo(demo->uniform_data.buf,
902                    XGL_INFO_TYPE_BUFFER_MEMORY_REQUIREMENTS,
903                    &buf_reqs_size, &buf_reqs);
904    assert(!err && buf_reqs_size == sizeof(XGL_BUFFER_MEMORY_REQUIREMENTS));
905    buf_alloc.usage = buf_reqs.usage;
906    for (XGL_UINT i = 0; i < num_allocations; i ++) {
907        alloc_info.allocationSize = mem_reqs[i].size;
908
909        err = xglAllocMemory(demo->device, &alloc_info, &(demo->uniform_data.mem[i]));
910        assert(!err);
911
912        err = xglMapMemory(demo->uniform_data.mem[i], 0, (XGL_VOID **) &pData);
913        assert(!err);
914
915        memcpy(pData, &data, alloc_info.allocationSize);
916
917        err = xglUnmapMemory(demo->uniform_data.mem[i]);
918        assert(!err);
919
920        err = xglBindObjectMemory(demo->uniform_data.buf, i,
921                    demo->uniform_data.mem[i], 0);
922        assert(!err);
923    }
924
925    memset(&view_info, 0, sizeof(view_info));
926    view_info.sType = XGL_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
927    view_info.buffer = demo->uniform_data.buf;
928    view_info.viewType = XGL_BUFFER_VIEW_RAW;
929    view_info.offset = 0;
930    view_info.range = sizeof(data);
931
932    err = xglCreateBufferView(demo->device, &view_info, &demo->uniform_data.view);
933    assert(!err);
934
935    demo->uniform_data.attach.sType = XGL_STRUCTURE_TYPE_BUFFER_VIEW_ATTACH_INFO;
936    demo->uniform_data.attach.view = demo->uniform_data.view;
937}
938
939static void demo_prepare_descriptor_layout(struct demo *demo)
940{
941    const XGL_DESCRIPTOR_SET_LAYOUT_CREATE_INFO descriptor_layout_vs = {
942        .sType = XGL_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
943        .pNext = NULL,
944        .descriptorType = XGL_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
945        .count = 1,
946        .stageFlags = XGL_SHADER_STAGE_FLAGS_VERTEX_BIT,
947        .immutableSampler = XGL_NULL_HANDLE,
948    };
949    const XGL_DESCRIPTOR_SET_LAYOUT_CREATE_INFO descriptor_layout_fs = {
950        .sType = XGL_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
951        .pNext = NULL,
952        .descriptorType = XGL_DESCRIPTOR_TYPE_SAMPLER_TEXTURE,
953        .count = DEMO_TEXTURE_COUNT,
954        .stageFlags = XGL_SHADER_STAGE_FLAGS_FRAGMENT_BIT,
955        .immutableSampler = XGL_NULL_HANDLE,
956    };
957    const uint32_t bind_point = 0;
958    XGL_RESULT err;
959
960    err = xglCreateDescriptorSetLayout(demo->device,
961            XGL_SHADER_STAGE_FLAGS_VERTEX_BIT, &bind_point,
962            XGL_NULL_HANDLE, &descriptor_layout_vs,
963            &demo->desc_layout_vs);
964    assert(!err);
965
966    err = xglCreateDescriptorSetLayout(demo->device,
967            XGL_SHADER_STAGE_FLAGS_FRAGMENT_BIT, &bind_point,
968            demo->desc_layout_vs, &descriptor_layout_fs,
969            &demo->desc_layout_fs);
970    assert(!err);
971
972    demo->desc_layout_last = &demo->desc_layout_fs;
973}
974
975static XGL_SHADER demo_prepare_shader(struct demo *demo,
976                                      XGL_PIPELINE_SHADER_STAGE stage,
977                                      const void *code,
978                                      XGL_SIZE size)
979{
980    XGL_SHADER_CREATE_INFO createInfo;
981    XGL_SHADER shader;
982    XGL_RESULT err;
983
984
985    createInfo.sType = XGL_STRUCTURE_TYPE_SHADER_CREATE_INFO;
986    createInfo.pNext = NULL;
987
988#ifdef EXTERNAL_BIL
989    createInfo.codeSize = size;
990    createInfo.pCode = code;
991    createInfo.flags = 0;
992
993    err = xglCreateShader(demo->device, &createInfo, &shader);
994    if (err) {
995        free((void *) createInfo.pCode);
996    }
997#else
998    // Create fake BIL structure to feed GLSL
999    // to the driver "under the covers"
1000    createInfo.codeSize = 3 * sizeof(uint32_t) + size + 1;
1001    createInfo.pCode = malloc(createInfo.codeSize);
1002    createInfo.flags = 0;
1003
1004    /* try version 0 first: XGL_PIPELINE_SHADER_STAGE followed by GLSL */
1005    ((uint32_t *) createInfo.pCode)[0] = ICD_BIL_MAGIC;
1006    ((uint32_t *) createInfo.pCode)[1] = 0;
1007    ((uint32_t *) createInfo.pCode)[2] = stage;
1008    memcpy(((uint32_t *) createInfo.pCode + 3), code, size + 1);
1009
1010    err = xglCreateShader(demo->device, &createInfo, &shader);
1011    if (err) {
1012        free((void *) createInfo.pCode);
1013        return NULL;
1014    }
1015#endif
1016
1017    return shader;
1018}
1019
1020char *demo_read_bil(const char *filename, XGL_SIZE *psize)
1021{
1022    long int size;
1023    void *shader_code;
1024
1025    FILE *fp = fopen(filename, "rb");
1026    if (!fp) return NULL;
1027
1028    fseek(fp, 0L, SEEK_END);
1029    size = ftell(fp);
1030
1031    fseek(fp, 0L, SEEK_SET);
1032
1033    shader_code = malloc(size);
1034    fread(shader_code, size, 1, fp);
1035
1036    *psize = size;
1037
1038    return shader_code;
1039}
1040
1041static XGL_SHADER demo_prepare_vs(struct demo *demo)
1042{
1043#ifdef EXTERNAL_BIL
1044    void *vertShaderCode;
1045    XGL_SIZE size;
1046
1047    vertShaderCode = demo_read_bil("cube-vert.bil", &size);
1048
1049    return demo_prepare_shader(demo, XGL_SHADER_STAGE_VERTEX,
1050                               vertShaderCode, size);
1051#else
1052    static const char *vertShaderText =
1053            "#version 140\n"
1054            "#extension GL_ARB_separate_shader_objects : enable\n"
1055            "#extension GL_ARB_shading_language_420pack : enable\n"
1056            "\n"
1057            "layout(binding = 0) uniform buf {\n"
1058            "        mat4 MVP;\n"
1059            "        vec4 position[12*3];\n"
1060            "        vec4 attr[12*3];\n"
1061            "} ubuf;\n"
1062            "\n"
1063            "layout (location = 0) out vec4 texcoord;\n"
1064            "\n"
1065            "void main() \n"
1066            "{\n"
1067            "   texcoord = ubuf.attr[gl_VertexID];\n"
1068            "   gl_Position = ubuf.MVP * ubuf.position[gl_VertexID];\n"
1069            "}\n";
1070
1071    return demo_prepare_shader(demo, XGL_SHADER_STAGE_VERTEX,
1072                               (const void *) vertShaderText,
1073                               strlen(vertShaderText));
1074#endif
1075}
1076
1077static XGL_SHADER demo_prepare_fs(struct demo *demo)
1078{
1079#ifdef EXTERNAL_BIL
1080    void *fragShaderCode;
1081    XGL_SIZE size;
1082
1083    fragShaderCode = demo_read_bil("cube-frag.bil", &size);
1084
1085    return demo_prepare_shader(demo, XGL_SHADER_STAGE_FRAGMENT,
1086                               fragShaderCode, size);
1087#else
1088    static const char *fragShaderText =
1089            "#version 140\n"
1090            "#extension GL_ARB_separate_shader_objects : enable\n"
1091            "#extension GL_ARB_shading_language_420pack : enable\n"
1092            "layout (binding = 0) uniform sampler2D tex;\n"
1093            "\n"
1094            "layout (location = 0) in vec4 texcoord;\n"
1095            "void main() {\n"
1096            "   gl_FragColor = texture(tex, texcoord.xy);\n"
1097            "}\n";
1098
1099    return demo_prepare_shader(demo, XGL_SHADER_STAGE_FRAGMENT,
1100                               (const void *) fragShaderText,
1101                               strlen(fragShaderText));
1102#endif
1103}
1104
1105static void demo_prepare_pipeline(struct demo *demo)
1106{
1107    XGL_GRAPHICS_PIPELINE_CREATE_INFO pipeline;
1108    XGL_PIPELINE_IA_STATE_CREATE_INFO ia;
1109    XGL_PIPELINE_RS_STATE_CREATE_INFO rs;
1110    XGL_PIPELINE_CB_STATE_CREATE_INFO cb;
1111    XGL_PIPELINE_DS_STATE_CREATE_INFO ds;
1112    XGL_PIPELINE_SHADER_STAGE_CREATE_INFO vs;
1113    XGL_PIPELINE_SHADER_STAGE_CREATE_INFO fs;
1114    XGL_PIPELINE_VP_STATE_CREATE_INFO vp;
1115    XGL_PIPELINE_MS_STATE_CREATE_INFO ms;
1116    XGL_RESULT err;
1117
1118    memset(&pipeline, 0, sizeof(pipeline));
1119    pipeline.sType = XGL_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
1120    pipeline.lastSetLayout = *demo->desc_layout_last;
1121
1122    memset(&ia, 0, sizeof(ia));
1123    ia.sType = XGL_STRUCTURE_TYPE_PIPELINE_IA_STATE_CREATE_INFO;
1124    ia.topology = XGL_TOPOLOGY_TRIANGLE_LIST;
1125
1126    memset(&rs, 0, sizeof(rs));
1127    rs.sType = XGL_STRUCTURE_TYPE_PIPELINE_RS_STATE_CREATE_INFO;
1128    rs.fillMode = XGL_FILL_SOLID;
1129    rs.cullMode = XGL_CULL_NONE;
1130    rs.frontFace = XGL_FRONT_FACE_CCW;
1131
1132    memset(&cb, 0, sizeof(cb));
1133    cb.sType = XGL_STRUCTURE_TYPE_PIPELINE_CB_STATE_CREATE_INFO;
1134    XGL_PIPELINE_CB_ATTACHMENT_STATE att_state[1];
1135    memset(att_state, 0, sizeof(att_state));
1136    att_state[0].format = demo->format;
1137    att_state[0].channelWriteMask = 0xf;
1138    att_state[0].blendEnable = XGL_FALSE;
1139    cb.attachmentCount = 1;
1140    cb.pAttachments = att_state;
1141
1142    memset(&vp, 0, sizeof(vp));
1143    vp.sType = XGL_STRUCTURE_TYPE_PIPELINE_VP_STATE_CREATE_INFO;
1144    vp.scissorEnable = XGL_FALSE;
1145
1146    memset(&ds, 0, sizeof(ds));
1147    ds.sType = XGL_STRUCTURE_TYPE_PIPELINE_DS_STATE_CREATE_INFO;
1148    ds.format = demo->depth.format;
1149    ds.depthTestEnable = XGL_TRUE;
1150    ds.depthWriteEnable = XGL_TRUE;
1151    ds.depthFunc = XGL_COMPARE_LESS_EQUAL;
1152    ds.depthBoundsEnable = XGL_FALSE;
1153    ds.back.stencilFailOp = XGL_STENCIL_OP_KEEP;
1154    ds.back.stencilPassOp = XGL_STENCIL_OP_KEEP;
1155    ds.back.stencilFunc = XGL_COMPARE_ALWAYS;
1156    ds.stencilTestEnable = XGL_FALSE;
1157    ds.front = ds.back;
1158
1159    memset(&vs, 0, sizeof(vs));
1160    vs.sType = XGL_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1161    vs.shader.stage = XGL_SHADER_STAGE_VERTEX;
1162    vs.shader.shader = demo_prepare_vs(demo);
1163    assert(vs.shader.shader != NULL);
1164
1165    memset(&fs, 0, sizeof(fs));
1166    fs.sType = XGL_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1167    fs.shader.stage = XGL_SHADER_STAGE_FRAGMENT;
1168    fs.shader.shader = demo_prepare_fs(demo);
1169    assert(fs.shader.shader != NULL);
1170
1171    memset(&ms, 0, sizeof(ms));
1172    ms.sType = XGL_STRUCTURE_TYPE_PIPELINE_MS_STATE_CREATE_INFO;
1173    ms.sampleMask = 1;
1174    ms.multisampleEnable = XGL_FALSE;
1175    ms.samples = 1;
1176
1177    pipeline.pNext = (const XGL_VOID *) &ia;
1178    ia.pNext = (const XGL_VOID *) &rs;
1179    rs.pNext = (const XGL_VOID *) &cb;
1180    cb.pNext = (const XGL_VOID *) &ms;
1181    ms.pNext = (const XGL_VOID *) &vp;
1182    vp.pNext = (const XGL_VOID *) &ds;
1183    ds.pNext = (const XGL_VOID *) &vs;
1184    vs.pNext = (const XGL_VOID *) &fs;
1185
1186    err = xglCreateGraphicsPipeline(demo->device, &pipeline, &demo->pipeline);
1187    assert(!err);
1188
1189    xglDestroyObject(vs.shader.shader);
1190    xglDestroyObject(fs.shader.shader);
1191}
1192
1193static void demo_prepare_dynamic_states(struct demo *demo)
1194{
1195    XGL_DYNAMIC_VP_STATE_CREATE_INFO viewport_create;
1196    XGL_DYNAMIC_RS_STATE_CREATE_INFO raster;
1197    XGL_DYNAMIC_CB_STATE_CREATE_INFO color_blend;
1198    XGL_DYNAMIC_DS_STATE_CREATE_INFO depth_stencil;
1199    XGL_RESULT err;
1200
1201    memset(&viewport_create, 0, sizeof(viewport_create));
1202    viewport_create.sType = XGL_STRUCTURE_TYPE_DYNAMIC_VP_STATE_CREATE_INFO;
1203    viewport_create.viewportCount = 1;
1204    XGL_VIEWPORT viewport;
1205    viewport.height = (XGL_FLOAT) demo->height;
1206    viewport.width = (XGL_FLOAT) demo->width;
1207    viewport.minDepth = (XGL_FLOAT) 0.0f;
1208    viewport.maxDepth = (XGL_FLOAT) 1.0f;
1209    viewport_create.pViewports = &viewport;
1210
1211    memset(&raster, 0, sizeof(raster));
1212    raster.sType = XGL_STRUCTURE_TYPE_DYNAMIC_RS_STATE_CREATE_INFO;
1213
1214    memset(&color_blend, 0, sizeof(color_blend));
1215    color_blend.sType = XGL_STRUCTURE_TYPE_DYNAMIC_CB_STATE_CREATE_INFO;
1216
1217    memset(&depth_stencil, 0, sizeof(depth_stencil));
1218    depth_stencil.sType = XGL_STRUCTURE_TYPE_DYNAMIC_DS_STATE_CREATE_INFO;
1219    depth_stencil.stencilBackRef = 0;
1220    depth_stencil.stencilFrontRef = 0;
1221    depth_stencil.stencilReadMask = 0xff;
1222    depth_stencil.stencilWriteMask = 0xff;
1223
1224    err = xglCreateDynamicViewportState(demo->device, &viewport_create, &demo->viewport);
1225    assert(!err);
1226
1227    err = xglCreateDynamicRasterState(demo->device, &raster, &demo->raster);
1228    assert(!err);
1229
1230    err = xglCreateDynamicColorBlendState(demo->device,
1231            &color_blend, &demo->color_blend);
1232    assert(!err);
1233
1234    err = xglCreateDynamicDepthStencilState(demo->device,
1235            &depth_stencil, &demo->depth_stencil);
1236    assert(!err);
1237}
1238
1239static void demo_prepare_descriptor_region(struct demo *demo)
1240{
1241    const XGL_DESCRIPTOR_TYPE_COUNT type_counts[2] = {
1242        [0] = {
1243            .type = XGL_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
1244            .count = 1,
1245        },
1246        [1] = {
1247            .type = XGL_DESCRIPTOR_TYPE_SAMPLER_TEXTURE,
1248            .count = DEMO_TEXTURE_COUNT,
1249        },
1250    };
1251    const XGL_DESCRIPTOR_REGION_CREATE_INFO descriptor_region = {
1252        .sType = XGL_STRUCTURE_TYPE_DESCRIPTOR_REGION_CREATE_INFO,
1253        .pNext = NULL,
1254        .count = 2,
1255        .pTypeCount = type_counts,
1256    };
1257    XGL_RESULT err;
1258
1259    err = xglCreateDescriptorRegion(demo->device,
1260            XGL_DESCRIPTOR_REGION_USAGE_ONE_SHOT, 1,
1261            &descriptor_region, &demo->desc_region);
1262    assert(!err);
1263}
1264
1265static void demo_prepare_descriptor_set(struct demo *demo)
1266{
1267    const XGL_BUFFER_VIEW_ATTACH_INFO *view_info_vs =
1268        &demo->uniform_data.attach;
1269    XGL_IMAGE_VIEW_ATTACH_INFO view_info[DEMO_TEXTURE_COUNT];
1270    XGL_SAMPLER_IMAGE_VIEW_INFO combined_info[DEMO_TEXTURE_COUNT];
1271    XGL_UPDATE_SAMPLER_TEXTURES update_fs;
1272    XGL_UPDATE_BUFFERS update_vs;
1273    XGL_RESULT err;
1274    uint32_t count;
1275    XGL_UINT i;
1276
1277    for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
1278        view_info[i].sType = XGL_STRUCTURE_TYPE_IMAGE_VIEW_ATTACH_INFO;
1279        view_info[i].pNext = NULL;
1280        view_info[i].view = demo->textures[i].view,
1281        view_info[i].layout = XGL_IMAGE_LAYOUT_GENERAL;
1282
1283        combined_info[i].pSampler = demo->textures[i].sampler;
1284        combined_info[i].pImageView = &view_info[i];
1285    }
1286
1287    memset(&update_vs, 0, sizeof(update_vs));
1288    update_vs.sType = XGL_STRUCTURE_TYPE_UPDATE_BUFFERS;
1289    update_vs.pNext = &update_fs;
1290    update_vs.descriptorType = XGL_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1291    update_vs.count = 1;
1292    update_vs.pBufferViews = &view_info_vs;
1293
1294    memset(&update_fs, 0, sizeof(update_fs));
1295    update_fs.sType = XGL_STRUCTURE_TYPE_UPDATE_SAMPLER_TEXTURES;
1296    update_fs.index = 1;
1297    update_fs.count = DEMO_TEXTURE_COUNT;
1298    update_fs.pSamplerImageViews = combined_info;
1299
1300    err = xglAllocDescriptorSets(demo->desc_region,
1301            XGL_DESCRIPTOR_SET_USAGE_STATIC,
1302            1, demo->desc_layout_last,
1303            &demo->desc_set, &count);
1304    assert(!err && count == 1);
1305
1306    xglBeginDescriptorRegionUpdate(demo->device,
1307            XGL_DESCRIPTOR_UPDATE_MODE_FASTEST);
1308
1309    xglClearDescriptorSets(demo->desc_region, 1, &demo->desc_set);
1310    xglUpdateDescriptors(demo->desc_set, &update_vs);
1311
1312    xglEndDescriptorRegionUpdate(demo->device, demo->cmd);
1313}
1314
1315static void demo_prepare(struct demo *demo)
1316{
1317    const XGL_CMD_BUFFER_CREATE_INFO cmd = {
1318        .sType = XGL_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,
1319        .pNext = NULL,
1320        .queueType = XGL_QUEUE_TYPE_GRAPHICS,
1321        .flags = 0,
1322    };
1323    XGL_RESULT err;
1324
1325    demo_prepare_buffers(demo);
1326    demo_prepare_depth(demo);
1327    demo_prepare_textures(demo);
1328    demo_prepare_cube_data_buffer(demo);
1329
1330    demo_prepare_descriptor_layout(demo);
1331    demo_prepare_pipeline(demo);
1332    demo_prepare_dynamic_states(demo);
1333
1334    err = xglCreateCommandBuffer(demo->device, &cmd, &demo->cmd);
1335    assert(!err);
1336
1337    demo_prepare_descriptor_region(demo);
1338    demo_prepare_descriptor_set(demo);
1339}
1340
1341static void demo_handle_event(struct demo *demo,
1342                              const xcb_generic_event_t *event)
1343{
1344    u_int8_t event_code = event->response_type & 0x7f;
1345    switch (event_code) {
1346    case XCB_EXPOSE:
1347        // TODO: Resize window
1348        break;
1349    case XCB_CLIENT_MESSAGE:
1350        if((*(xcb_client_message_event_t*)event).data.data32[0] ==
1351           (*demo->atom_wm_delete_window).atom) {
1352            demo->quit = true;
1353        }
1354        break;
1355    case XCB_KEY_RELEASE:
1356        {
1357            const xcb_key_release_event_t *key =
1358                (const xcb_key_release_event_t *) event;
1359
1360            switch (key->detail) {
1361            case 0x9:           // Escape
1362                demo->quit = true;
1363                break;
1364            case 0x71:          // left arrow key
1365                demo->spin_angle += demo->spin_increment;
1366                break;
1367            case 0x72:          // right arrow key
1368                demo->spin_angle -= demo->spin_increment;
1369                break;
1370            case 0x41:
1371                demo->pause = !demo->pause;
1372                 break;
1373            }
1374        }
1375        break;
1376    default:
1377        break;
1378    }
1379}
1380
1381static void demo_run(struct demo *demo)
1382{
1383    xcb_flush(demo->connection);
1384
1385    while (!demo->quit) {
1386        xcb_generic_event_t *event;
1387
1388        if (demo->pause) {
1389            event = xcb_wait_for_event(demo->connection);
1390        } else {
1391            event = xcb_poll_for_event(demo->connection);
1392        }
1393        if (event) {
1394            demo_handle_event(demo, event);
1395            free(event);
1396        }
1397
1398        // Wait for work to finish before updating MVP.
1399        xglDeviceWaitIdle(demo->device);
1400        demo_update_data_buffer(demo);
1401
1402        demo_draw(demo);
1403
1404        // Wait for work to finish before updating MVP.
1405        xglDeviceWaitIdle(demo->device);
1406    }
1407}
1408
1409static void demo_create_window(struct demo *demo)
1410{
1411    uint32_t value_mask, value_list[32];
1412
1413    demo->window = xcb_generate_id(demo->connection);
1414
1415    value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
1416    value_list[0] = demo->screen->black_pixel;
1417    value_list[1] = XCB_EVENT_MASK_KEY_RELEASE |
1418                    XCB_EVENT_MASK_EXPOSURE;
1419
1420    xcb_create_window(demo->connection,
1421            XCB_COPY_FROM_PARENT,
1422            demo->window, demo->screen->root,
1423            0, 0, demo->width, demo->height, 0,
1424            XCB_WINDOW_CLASS_INPUT_OUTPUT,
1425            demo->screen->root_visual,
1426            value_mask, value_list);
1427
1428    /* Magic code that will send notification when window is destroyed */
1429    xcb_intern_atom_cookie_t cookie = xcb_intern_atom(demo->connection, 1, 12,
1430                                                      "WM_PROTOCOLS");
1431    xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(demo->connection, cookie, 0);
1432
1433    xcb_intern_atom_cookie_t cookie2 = xcb_intern_atom(demo->connection, 0, 16, "WM_DELETE_WINDOW");
1434    demo->atom_wm_delete_window = xcb_intern_atom_reply(demo->connection, cookie2, 0);
1435
1436    xcb_change_property(demo->connection, XCB_PROP_MODE_REPLACE,
1437                        demo->window, (*reply).atom, 4, 32, 1,
1438                        &(*demo->atom_wm_delete_window).atom);
1439    free(reply);
1440
1441    xcb_map_window(demo->connection, demo->window);
1442}
1443
1444static void demo_init_xgl(struct demo *demo)
1445{
1446    const XGL_APPLICATION_INFO app = {
1447        .sType = XGL_STRUCTURE_TYPE_APPLICATION_INFO,
1448        .pNext = NULL,
1449        .pAppName = "cube",
1450        .appVersion = 0,
1451        .pEngineName = "cube",
1452        .engineVersion = 0,
1453        .apiVersion = XGL_MAKE_VERSION(0, 22, 0),
1454    };
1455    const XGL_WSI_X11_CONNECTION_INFO connection = {
1456        .pConnection = demo->connection,
1457        .root = demo->screen->root,
1458        .provider = 0,
1459    };
1460    const XGL_DEVICE_QUEUE_CREATE_INFO queue = {
1461        .queueNodeIndex = 0,
1462        .queueCount = 1,
1463    };
1464    const XGL_CHAR *ext_names[] = {
1465        "XGL_WSI_X11",
1466    };
1467    const XGL_DEVICE_CREATE_INFO device = {
1468        .sType = XGL_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
1469        .pNext = NULL,
1470        .queueRecordCount = 1,
1471        .pRequestedQueues = &queue,
1472        .extensionCount = 1,
1473        .ppEnabledExtensionNames = ext_names,
1474        .maxValidationLevel = XGL_VALIDATION_LEVEL_END_RANGE,
1475        .flags = XGL_DEVICE_CREATE_VALIDATION_BIT,
1476    };
1477    XGL_RESULT err;
1478    XGL_UINT gpu_count;
1479    XGL_UINT i;
1480
1481    err = xglInitAndEnumerateGpus(&app, NULL, 1, &gpu_count, &demo->gpu);
1482    assert(!err && gpu_count == 1);
1483
1484    for (i = 0; i < device.extensionCount; i++) {
1485        err = xglGetExtensionSupport(demo->gpu, ext_names[i]);
1486        assert(!err);
1487    }
1488
1489    err = xglWsiX11AssociateConnection(demo->gpu, &connection);
1490    assert(!err);
1491
1492    err = xglCreateDevice(demo->gpu, &device, &demo->device);
1493    assert(!err);
1494
1495    err = xglGetDeviceQueue(demo->device, XGL_QUEUE_TYPE_GRAPHICS,
1496            0, &demo->queue);
1497    assert(!err);
1498}
1499
1500static void demo_init_connection(struct demo *demo)
1501{
1502    const xcb_setup_t *setup;
1503    xcb_screen_iterator_t iter;
1504    int scr;
1505
1506    demo->connection = xcb_connect(NULL, &scr);
1507
1508    setup = xcb_get_setup(demo->connection);
1509    iter = xcb_setup_roots_iterator(setup);
1510    while (scr-- > 0)
1511        xcb_screen_next(&iter);
1512
1513    demo->screen = iter.data;
1514}
1515
1516static void demo_init(struct demo *demo)
1517{
1518    vec3 eye = {0.0f, 3.0f, 5.0f};
1519    vec3 origin = {0, 0, 0};
1520    vec3 up = {0.0f, -1.0f, 0.0};
1521
1522    memset(demo, 0, sizeof(*demo));
1523
1524    demo_init_connection(demo);
1525    demo_init_xgl(demo);
1526
1527    demo->width = 500;
1528    demo->height = 500;
1529    demo->format = XGL_FMT_B8G8R8A8_UNORM;
1530
1531    demo->spin_angle = 0.01f;
1532    demo->spin_increment = 0.01f;
1533    demo->pause = false;
1534
1535    mat4x4_perspective(demo->projection_matrix, degreesToRadians(45.0f), 1.0f, 0.1f, 100.0f);
1536    mat4x4_look_at(demo->view_matrix, eye, origin, up);
1537    mat4x4_identity(demo->model_matrix);
1538}
1539
1540static void demo_cleanup(struct demo *demo)
1541{
1542    XGL_UINT i, j;
1543
1544    xglDestroyObject(demo->desc_set);
1545    xglDestroyObject(demo->desc_region);
1546
1547    xglDestroyObject(demo->cmd);
1548
1549    xglDestroyObject(demo->viewport);
1550    xglDestroyObject(demo->raster);
1551    xglDestroyObject(demo->color_blend);
1552    xglDestroyObject(demo->depth_stencil);
1553
1554    xglDestroyObject(demo->pipeline);
1555    xglDestroyObject(demo->desc_layout_fs);
1556    xglDestroyObject(demo->desc_layout_vs);
1557
1558//    xglFreeMemory(demo->vertices.mem);
1559
1560    for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
1561        xglDestroyObject(demo->textures[i].view);
1562        xglDestroyObject(demo->textures[i].image);
1563        for (j = 0; j < demo->textures[i].num_mem; j++)
1564            xglFreeMemory(demo->textures[i].mem[j]);
1565        xglDestroyObject(demo->textures[i].sampler);
1566    }
1567
1568    xglDestroyObject(demo->depth.view);
1569    xglDestroyObject(demo->depth.image);
1570    for (j = 0; j < demo->depth.num_mem; j++)
1571        xglFreeMemory(demo->depth.mem[j]);
1572    xglDestroyObject(demo->uniform_data.buf);
1573    for (j = 0; j < demo->uniform_data.num_mem; j++)
1574        xglFreeMemory(demo->uniform_data.mem[j]);
1575
1576    for (i = 0; i < DEMO_BUFFER_COUNT; i++) {
1577        xglDestroyObject(demo->buffers[i].fence);
1578        xglDestroyObject(demo->buffers[i].view);
1579        xglDestroyObject(demo->buffers[i].image);
1580    }
1581
1582    xglDestroyDevice(demo->device);
1583
1584    xcb_destroy_window(demo->connection, demo->window);
1585    xcb_disconnect(demo->connection);
1586}
1587
1588int main(void)
1589{
1590    struct demo demo;
1591
1592    demo_init(&demo);
1593
1594    demo_prepare(&demo);
1595    demo_create_window(&demo);
1596    demo_run(&demo);
1597
1598    demo_cleanup(&demo);
1599
1600    return 0;
1601}
1602