cube.c revision 7461fcf758fa133fe84da0c1b8f4abd776f3f385
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_GPU_MEMORY mem;
216        XGL_DEPTH_STENCIL_VIEW view;
217    } depth;
218
219    struct {
220        XGL_SAMPLER sampler;
221
222        char *filename;
223        XGL_IMAGE image;
224        XGL_GPU_MEMORY mem;
225        XGL_IMAGE_VIEW view;
226    } textures[DEMO_TEXTURE_COUNT];
227
228    struct {
229        XGL_GPU_MEMORY mem;
230        XGL_MEMORY_VIEW_ATTACH_INFO view;
231
232        XGL_PIPELINE_VERTEX_INPUT_CREATE_INFO vi;
233        XGL_VERTEX_INPUT_BINDING_DESCRIPTION vi_bindings[1];
234        XGL_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION vi_attrs[2];
235    } vertices;
236
237    struct {
238        XGL_GPU_MEMORY mem;
239        XGL_MEMORY_VIEW_ATTACH_INFO view;
240    } uniform_data;
241
242    XGL_DESCRIPTOR_SET dset;
243
244    XGL_PIPELINE pipeline;
245
246    XGL_VIEWPORT_STATE_OBJECT viewport;
247    XGL_RASTER_STATE_OBJECT raster;
248    XGL_MSAA_STATE_OBJECT msaa;
249    XGL_COLOR_BLEND_STATE_OBJECT color_blend;
250    XGL_DEPTH_STENCIL_STATE_OBJECT depth_stencil;
251
252    mat4x4 projection_matrix;
253    mat4x4 view_matrix;
254    mat4x4 model_matrix;
255
256    XGL_FLOAT spin_angle;
257    XGL_FLOAT spin_increment;
258    bool pause;
259
260    XGL_CMD_BUFFER cmd;
261
262    xcb_window_t window;
263    xcb_intern_atom_reply_t *atom_wm_delete_window;
264
265    bool quit;
266    XGL_UINT current_buffer;
267};
268
269static void demo_draw_build_cmd(struct demo *demo)
270{
271    const XGL_COLOR_ATTACHMENT_BIND_INFO color_attachment = {
272        .view = demo->buffers[demo->current_buffer].view,
273        .colorAttachmentState = XGL_IMAGE_STATE_TARGET_RENDER_ACCESS_OPTIMAL,
274    };
275    const XGL_DEPTH_STENCIL_BIND_INFO depth_stencil = {
276        .view = demo->depth.view,
277        .depthState = XGL_IMAGE_STATE_TARGET_RENDER_ACCESS_OPTIMAL,
278        .stencilState = XGL_IMAGE_STATE_TARGET_RENDER_ACCESS_OPTIMAL,
279    };
280    const XGL_FLOAT clear_color[4] = { 0.2f, 0.2f, 0.2f, 0.2f };
281    const XGL_FLOAT clear_depth = 1.0f;
282    XGL_IMAGE_SUBRESOURCE_RANGE clear_range;
283    XGL_RESULT err;
284
285    err = xglBeginCommandBuffer(demo->cmd,
286            XGL_CMD_BUFFER_OPTIMIZE_GPU_SMALL_BATCH_BIT |
287            XGL_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT);
288    assert(!err);
289
290    xglCmdBindPipeline(demo->cmd, XGL_PIPELINE_BIND_POINT_GRAPHICS,
291                                  demo->pipeline);
292    xglCmdBindDescriptorSet(demo->cmd, XGL_PIPELINE_BIND_POINT_GRAPHICS,
293            0, demo->dset, 0);
294
295    xglCmdBindStateObject(demo->cmd, XGL_STATE_BIND_VIEWPORT, demo->viewport);
296    xglCmdBindStateObject(demo->cmd, XGL_STATE_BIND_RASTER, demo->raster);
297    xglCmdBindStateObject(demo->cmd, XGL_STATE_BIND_MSAA, demo->msaa);
298    xglCmdBindStateObject(demo->cmd, XGL_STATE_BIND_COLOR_BLEND,
299                                     demo->color_blend);
300    xglCmdBindStateObject(demo->cmd, XGL_STATE_BIND_DEPTH_STENCIL,
301                                     demo->depth_stencil);
302
303    xglCmdBindAttachments(demo->cmd, 1, &color_attachment, &depth_stencil);
304
305    clear_range.aspect = XGL_IMAGE_ASPECT_COLOR;
306    clear_range.baseMipLevel = 0;
307    clear_range.mipLevels = 1;
308    clear_range.baseArraySlice = 0;
309    clear_range.arraySize = 1;
310    xglCmdClearColorImage(demo->cmd,
311            demo->buffers[demo->current_buffer].image,
312            clear_color, 1, &clear_range);
313
314    clear_range.aspect = XGL_IMAGE_ASPECT_DEPTH;
315    xglCmdClearDepthStencil(demo->cmd, demo->depth.image,
316            clear_depth, 0, 1, &clear_range);
317
318    xglCmdDraw(demo->cmd, 0, 12 * 3, 0, 1);
319
320    err = xglEndCommandBuffer(demo->cmd);
321    assert(!err);
322}
323
324
325void demo_update_data_buffer(struct demo *demo)
326{
327    mat4x4 MVP, Model, VP;
328    int matrixSize = sizeof(MVP);
329    XGL_UINT8 *pData;
330    XGL_RESULT err;
331
332    mat4x4_mul(VP, demo->projection_matrix, demo->view_matrix);
333
334    // Rotate 22.5 degrees around the Y axis
335    mat4x4_dup(Model, demo->model_matrix);
336    mat4x4_rotate(demo->model_matrix, Model, 0.0f, 1.0f, 0.0f, degreesToRadians(demo->spin_angle));
337    mat4x4_mul(MVP, VP, demo->model_matrix);
338
339    err = xglMapMemory(demo->uniform_data.mem, 0, (XGL_VOID **) &pData);
340    assert(!err);
341
342    memcpy(pData, (const void*) &MVP[0][0], matrixSize);
343
344    err = xglUnmapMemory(demo->uniform_data.mem);
345    assert(!err);
346}
347
348static void demo_draw(struct demo *demo)
349{
350    const XGL_WSI_X11_PRESENT_INFO present = {
351        .destWindow = demo->window,
352        .srcImage = demo->buffers[demo->current_buffer].image,
353        .async = true,
354        .flip = false,
355    };
356    XGL_FENCE fence = demo->buffers[demo->current_buffer].fence;
357    XGL_RESULT err;
358
359    demo_draw_build_cmd(demo);
360
361    err = xglWaitForFences(demo->device, 1, &fence, XGL_TRUE, ~((XGL_UINT64) 0));
362    assert(err == XGL_SUCCESS || err == XGL_ERROR_UNAVAILABLE);
363
364    err = xglQueueSubmit(demo->queue, 1, &demo->cmd,
365            0, NULL, XGL_NULL_HANDLE);
366    assert(!err);
367
368    err = xglWsiX11QueuePresent(demo->queue, &present, fence);
369    assert(!err);
370
371    demo->current_buffer = (demo->current_buffer + 1) % DEMO_BUFFER_COUNT;
372}
373
374static void demo_prepare_buffers(struct demo *demo)
375{
376    const XGL_WSI_X11_PRESENTABLE_IMAGE_CREATE_INFO presentable_image = {
377        .format = demo->format,
378        .usage = XGL_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
379        .extent = {
380            .width = demo->width,
381            .height = demo->height,
382        },
383        .flags = 0,
384    };
385    const XGL_FENCE_CREATE_INFO fence = {
386        .sType = XGL_STRUCTURE_TYPE_FENCE_CREATE_INFO,
387        .pNext = NULL,
388        .flags = 0,
389    };
390    XGL_RESULT err;
391    XGL_UINT i;
392
393    for (i = 0; i < DEMO_BUFFER_COUNT; i++) {
394        XGL_COLOR_ATTACHMENT_VIEW_CREATE_INFO color_attachment_view = {
395            .sType = XGL_STRUCTURE_TYPE_COLOR_ATTACHMENT_VIEW_CREATE_INFO,
396            .pNext = NULL,
397            .format = demo->format,
398            .mipLevel = 0,
399            .baseArraySlice = 0,
400            .arraySize = 1,
401        };
402
403        err = xglWsiX11CreatePresentableImage(demo->device, &presentable_image,
404                &demo->buffers[i].image, &demo->buffers[i].mem);
405        assert(!err);
406
407        color_attachment_view.image = demo->buffers[i].image;
408
409        err = xglCreateColorAttachmentView(demo->device,
410                &color_attachment_view, &demo->buffers[i].view);
411        assert(!err);
412
413        err = xglCreateFence(demo->device,
414                &fence, &demo->buffers[i].fence);
415        assert(!err);
416    }
417}
418
419static void demo_prepare_depth(struct demo *demo)
420{
421    const XGL_FORMAT depth_format = { XGL_CH_FMT_R16, XGL_NUM_FMT_DS };
422    const XGL_IMAGE_CREATE_INFO image = {
423        .sType = XGL_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
424        .pNext = NULL,
425        .imageType = XGL_IMAGE_2D,
426        .format = depth_format,
427        .extent = { demo->width, demo->height, 1 },
428        .mipLevels = 1,
429        .arraySize = 1,
430        .samples = 1,
431        .tiling = XGL_OPTIMAL_TILING,
432        .usage = XGL_IMAGE_USAGE_DEPTH_STENCIL_BIT,
433        .flags = 0,
434    };
435    XGL_MEMORY_ALLOC_INFO mem_alloc = {
436        .sType = XGL_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
437        .pNext = NULL,
438        .allocationSize = 0,
439        .alignment = 0,
440        .flags = 0,
441        .heapCount = 0,
442        .memPriority = XGL_MEMORY_PRIORITY_NORMAL,
443    };
444    XGL_DEPTH_STENCIL_VIEW_CREATE_INFO view = {
445        .sType = XGL_STRUCTURE_TYPE_DEPTH_STENCIL_VIEW_CREATE_INFO,
446        .pNext = NULL,
447        .image = XGL_NULL_HANDLE,
448        .mipLevel = 0,
449        .baseArraySlice = 0,
450        .arraySize = 1,
451        .flags = 0,
452    };
453    XGL_MEMORY_REQUIREMENTS mem_reqs;
454    XGL_SIZE mem_reqs_size = sizeof(XGL_MEMORY_REQUIREMENTS);
455    XGL_RESULT err;
456
457    demo->depth.format = depth_format;
458
459    /* create image */
460    err = xglCreateImage(demo->device, &image,
461            &demo->depth.image);
462    assert(!err);
463
464    err = xglGetObjectInfo(demo->depth.image,
465            XGL_INFO_TYPE_MEMORY_REQUIREMENTS,
466            &mem_reqs_size, &mem_reqs);
467    assert(!err && mem_reqs_size == sizeof(mem_reqs));
468
469    mem_alloc.allocationSize = mem_reqs.size;
470    mem_alloc.alignment = mem_reqs.alignment;
471    mem_alloc.heapCount = mem_reqs.heapCount;
472    memcpy(mem_alloc.heaps, mem_reqs.heaps,
473            sizeof(mem_reqs.heaps[0]) * mem_reqs.heapCount);
474
475    /* allocate memory */
476    err = xglAllocMemory(demo->device, &mem_alloc,
477            &demo->depth.mem);
478    assert(!err);
479
480    /* bind memory */
481    err = xglBindObjectMemory(demo->depth.image,
482            demo->depth.mem, 0);
483    assert(!err);
484
485    /* create image view */
486    view.image = demo->depth.image;
487    err = xglCreateDepthStencilView(demo->device, &view,
488            &demo->depth.view);
489    assert(!err);
490}
491
492/** loadTexture
493 * 	loads a png file into an memory object, using cstdio , libpng.
494 *
495 *    	\param demo : Needed to access XGL calls
496 * 	\param filename : the png file to be loaded
497 * 	\param width : width of png, to be updated as a side effect of this function
498 * 	\param height : height of png, to be updated as a side effect of this function
499 *
500 * 	\return bool : an opengl texture id.  true if successful?,
501 * 					should be validated by the client of this function.
502 *
503 * Source: http://en.wikibooks.org/wiki/OpenGL_Programming/Intermediate/Textures
504 * Modified to copy image to memory
505 *
506 */
507bool loadTexture(char *filename, XGL_UINT8 *rgba_data,
508                 XGL_SUBRESOURCE_LAYOUT *layout,
509                 XGL_INT *width, XGL_INT *height)
510{
511  //header for testing if it is a png
512  png_byte header[8];
513  int i, is_png, bit_depth, color_type,rowbytes;
514  png_uint_32 twidth, theight;
515  png_structp  png_ptr;
516  png_infop info_ptr, end_info;
517  png_byte *image_data;
518  png_bytep *row_pointers;
519
520  //open file as binary
521  FILE *fp = fopen(filename, "rb");
522  if (!fp) {
523    return false;
524  }
525
526  //read the header
527  fread(header, 1, 8, fp);
528
529  //test if png
530  is_png = !png_sig_cmp(header, 0, 8);
531  if (!is_png) {
532    fclose(fp);
533    return false;
534  }
535
536  //create png struct
537  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
538      NULL, NULL);
539  if (!png_ptr) {
540    fclose(fp);
541    return (false);
542  }
543
544  //create png info struct
545  info_ptr = png_create_info_struct(png_ptr);
546  if (!info_ptr) {
547    png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
548    fclose(fp);
549    return (false);
550  }
551
552  //create png info struct
553  end_info = png_create_info_struct(png_ptr);
554  if (!end_info) {
555    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
556    fclose(fp);
557    return (false);
558  }
559
560  //png error stuff, not sure libpng man suggests this.
561  if (setjmp(png_jmpbuf(png_ptr))) {
562    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
563    fclose(fp);
564    return (false);
565  }
566
567  //init png reading
568  png_init_io(png_ptr, fp);
569
570  //let libpng know you already read the first 8 bytes
571  png_set_sig_bytes(png_ptr, 8);
572
573  // read all the info up to the image data
574  png_read_info(png_ptr, info_ptr);
575
576  // get info about png
577  png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type,
578      NULL, NULL, NULL);
579
580  //update width and height based on png info
581  *width = twidth;
582  *height = theight;
583
584  // Require that incoming texture be 8bits per color component
585  // and 4 components (RGBA).
586  if (png_get_bit_depth(png_ptr, info_ptr) != 8 ||
587      png_get_channels(png_ptr, info_ptr) != 4) {
588      return false;
589  }
590
591  if (rgba_data == NULL) {
592      // If data pointer is null, we just want the width & height
593      // clean up memory and close stuff
594      png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
595      fclose(fp);
596
597      return true;
598  }
599
600  // Update the png info struct.
601  png_read_update_info(png_ptr, info_ptr);
602
603  // Row size in bytes.
604  rowbytes = png_get_rowbytes(png_ptr, info_ptr);
605
606  // Allocate the image_data as a big block, to be given to opengl
607  image_data = (png_byte *)malloc(rowbytes * theight * sizeof(png_byte));
608  if (!image_data) {
609    //clean up memory and close stuff
610    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
611    fclose(fp);
612    return false;
613  }
614
615  // row_pointers is for pointing to image_data for reading the png with libpng
616  row_pointers = (png_bytep *)malloc(theight * sizeof(png_bytep));
617  if (!row_pointers) {
618    //clean up memory and close stuff
619    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
620    // delete[] image_data;
621    fclose(fp);
622    return false;
623  }
624  // set the individual row_pointers to point at the correct offsets of image_data
625  for (i = 0; i < theight; ++i)
626    row_pointers[theight - 1 - i] = rgba_data + i * rowbytes;
627
628  // read the png into image_data through row_pointers
629  png_read_image(png_ptr, row_pointers);
630
631  // clean up memory and close stuff
632  png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
633  free(row_pointers);
634  free(image_data);
635  fclose(fp);
636
637  return true;
638}
639
640static void demo_prepare_textures(struct demo *demo)
641{
642    const XGL_FORMAT tex_format = { XGL_CH_FMT_R8G8B8A8, XGL_NUM_FMT_UNORM };
643    XGL_INT tex_width;
644    XGL_INT tex_height;
645    XGL_RESULT err;
646    XGL_UINT i;
647
648    for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
649        const XGL_SAMPLER_CREATE_INFO sampler = {
650            .sType = XGL_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
651            .pNext = NULL,
652            .magFilter = XGL_TEX_FILTER_NEAREST,
653            .minFilter = XGL_TEX_FILTER_NEAREST,
654            .mipMode = XGL_TEX_MIPMAP_BASE,
655            .addressU = XGL_TEX_ADDRESS_CLAMP,
656            .addressV = XGL_TEX_ADDRESS_CLAMP,
657            .addressW = XGL_TEX_ADDRESS_CLAMP,
658            .mipLodBias = 0.0f,
659            .maxAnisotropy = 0,
660            .compareFunc = XGL_COMPARE_NEVER,
661            .minLod = 0.0f,
662            .maxLod = 0.0f,
663            .borderColorType = XGL_BORDER_COLOR_OPAQUE_WHITE,
664        };
665
666        assert(loadTexture(tex_files[i], NULL, NULL, &tex_width, &tex_height));
667
668        const XGL_IMAGE_CREATE_INFO image = {
669            .sType = XGL_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
670            .pNext = NULL,
671            .imageType = XGL_IMAGE_2D,
672            .format = tex_format,
673            .extent = { tex_width, tex_height, 1 },
674            .mipLevels = 1,
675            .arraySize = 1,
676            .samples = 1,
677            .tiling = XGL_LINEAR_TILING,
678            .usage = XGL_IMAGE_USAGE_SHADER_ACCESS_READ_BIT,
679            .flags = 0,
680        };
681        XGL_MEMORY_ALLOC_INFO mem_alloc = {
682            .sType = XGL_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
683            .pNext = NULL,
684            .allocationSize = 0,
685            .alignment = 0,
686            .flags = 0,
687            .heapCount = 0,
688            .memPriority = XGL_MEMORY_PRIORITY_NORMAL,
689        };
690        XGL_IMAGE_VIEW_CREATE_INFO view = {
691            .sType = XGL_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
692            .pNext = NULL,
693            .image = XGL_NULL_HANDLE,
694            .viewType = XGL_IMAGE_VIEW_2D,
695            .format = image.format,
696            .channels = { XGL_CHANNEL_SWIZZLE_R,
697                          XGL_CHANNEL_SWIZZLE_G,
698                          XGL_CHANNEL_SWIZZLE_B,
699                          XGL_CHANNEL_SWIZZLE_A, },
700            .subresourceRange = { XGL_IMAGE_ASPECT_COLOR, 0, 1, 0, 1 },
701            .minLod = 0.0f,
702        };
703        XGL_MEMORY_REQUIREMENTS mem_reqs;
704        XGL_SIZE mem_reqs_size = sizeof(XGL_MEMORY_REQUIREMENTS);
705
706        /* create sampler */
707        err = xglCreateSampler(demo->device, &sampler,
708                &demo->textures[i].sampler);
709        assert(!err);
710
711        /* create image */
712        err = xglCreateImage(demo->device, &image,
713                &demo->textures[i].image);
714        assert(!err);
715
716        err = xglGetObjectInfo(demo->textures[i].image,
717                XGL_INFO_TYPE_MEMORY_REQUIREMENTS,
718                &mem_reqs_size, &mem_reqs);
719        assert(!err && mem_reqs_size == sizeof(mem_reqs));
720
721        mem_alloc.allocationSize = mem_reqs.size;
722        mem_alloc.alignment = mem_reqs.alignment;
723        mem_alloc.heapCount = mem_reqs.heapCount;
724        memcpy(mem_alloc.heaps, mem_reqs.heaps,
725                sizeof(mem_reqs.heaps[0]) * mem_reqs.heapCount);
726
727        /* allocate memory */
728        err = xglAllocMemory(demo->device, &mem_alloc,
729                &demo->textures[i].mem);
730        assert(!err);
731
732        /* bind memory */
733        err = xglBindObjectMemory(demo->textures[i].image,
734                demo->textures[i].mem, 0);
735        assert(!err);
736
737        /* create image view */
738        view.image = demo->textures[i].image;
739        err = xglCreateImageView(demo->device, &view,
740                &demo->textures[i].view);
741        assert(!err);
742    }
743
744    for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
745        const XGL_IMAGE_SUBRESOURCE subres = {
746            .aspect = XGL_IMAGE_ASPECT_COLOR,
747            .mipLevel = 0,
748            .arraySlice = 0,
749        };
750        XGL_SUBRESOURCE_LAYOUT layout;
751        XGL_SIZE layout_size;
752        XGL_VOID *data;
753
754        err = xglGetImageSubresourceInfo(demo->textures[i].image, &subres,
755                XGL_INFO_TYPE_SUBRESOURCE_LAYOUT, &layout_size, &layout);
756        assert(!err && layout_size == sizeof(layout));
757
758        err = xglMapMemory(demo->textures[i].mem, 0, &data);
759        assert(!err);
760
761        loadTexture(tex_files[i], data, &layout, &tex_width, &tex_height);
762
763        err = xglUnmapMemory(demo->textures[i].mem);
764        assert(!err);
765    }
766}
767
768void demo_prepare_cube_data_buffer(struct demo *demo)
769{
770    XGL_MEMORY_ALLOC_INFO alloc_info;
771    XGL_UINT8 *pData;
772    int i;
773    mat4x4 MVP, VP;
774    XGL_RESULT err;
775    struct xgltexcube_vs_uniform data;
776
777    mat4x4_mul(VP, demo->projection_matrix, demo->view_matrix);
778    mat4x4_mul(MVP, VP, demo->model_matrix);
779    memcpy(data.mvp, MVP, sizeof(MVP));
780//    dumpMatrix("MVP", MVP);
781
782    for (i=0; i<12*3; i++) {
783        data.position[i][0] = g_vertex_buffer_data[i*3];
784        data.position[i][1] = g_vertex_buffer_data[i*3+1];
785        data.position[i][2] = g_vertex_buffer_data[i*3+2];
786        data.position[i][3] = 1.0f;
787        data.attr[i][0] = g_uv_buffer_data[2*i];
788        data.attr[i][1] = g_uv_buffer_data[2*i + 1];
789        data.attr[i][2] = 0;
790        data.attr[i][3] = 0;
791    }
792
793    memset(&alloc_info, 0, sizeof(alloc_info));
794    alloc_info.sType = XGL_STRUCTURE_TYPE_MEMORY_ALLOC_INFO;
795    alloc_info.allocationSize = sizeof(data);
796    alloc_info.alignment = 0;
797    alloc_info.heapCount = 1;
798    alloc_info.heaps[0] = 0; // TODO: Use known existing heap
799
800    alloc_info.flags = XGL_MEMORY_HEAP_CPU_VISIBLE_BIT;
801    alloc_info.memPriority = XGL_MEMORY_PRIORITY_NORMAL;
802
803    err = xglAllocMemory(demo->device, &alloc_info, &demo->uniform_data.mem);
804    assert(!err);
805
806    err = xglMapMemory(demo->uniform_data.mem, 0, (XGL_VOID **) &pData);
807    assert(!err);
808
809    memcpy(pData, &data, alloc_info.allocationSize);
810
811    err = xglUnmapMemory(demo->uniform_data.mem);
812    assert(!err);
813
814    // set up the memory view for the constant buffer
815    demo->uniform_data.view.sType = XGL_STRUCTURE_TYPE_MEMORY_VIEW_ATTACH_INFO;
816    demo->uniform_data.view.stride = 16;
817    demo->uniform_data.view.range  = alloc_info.allocationSize;
818    demo->uniform_data.view.offset = 0;
819    demo->uniform_data.view.mem    = demo->uniform_data.mem;
820    demo->uniform_data.view.format.channelFormat = XGL_CH_FMT_R32G32B32A32;
821    demo->uniform_data.view.format.numericFormat = XGL_NUM_FMT_FLOAT;
822}
823
824static void demo_prepare_descriptor_set(struct demo *demo)
825{
826    const XGL_DESCRIPTOR_SET_CREATE_INFO descriptor_set = {
827        .sType = XGL_STRUCTURE_TYPE_DESCRIPTOR_SET_CREATE_INFO,
828        .pNext = NULL,
829        .slots = DEMO_TEXTURE_COUNT * 2 + 2,
830    };
831    XGL_RESULT err;
832
833    err = xglCreateDescriptorSet(demo->device, &descriptor_set, &demo->dset);
834    assert(!err);
835
836    xglBeginDescriptorSetUpdate(demo->dset);
837    xglClearDescriptorSetSlots(demo->dset, 0, DEMO_TEXTURE_COUNT * 2 + 2);
838
839//    xglAttachMemoryViewDescriptors(demo->dset, 0, 1, &demo->vertices.view);
840
841    xglAttachMemoryViewDescriptors(demo->dset, 0, 1, &demo->uniform_data.view);
842
843    XGL_IMAGE_VIEW_ATTACH_INFO image_view;
844
845    image_view.sType = XGL_STRUCTURE_TYPE_IMAGE_VIEW_ATTACH_INFO;
846    image_view.pNext = NULL;
847    image_view.view = demo->textures[0].view;
848    image_view.state = XGL_IMAGE_STATE_GRAPHICS_SHADER_READ_ONLY;
849
850    xglAttachSamplerDescriptors(demo->dset, 1, 1, &demo->textures[0].sampler);
851    xglAttachImageViewDescriptors(demo->dset, 2, 1, &image_view);
852
853    xglEndDescriptorSetUpdate(demo->dset);
854}
855
856static XGL_SHADER demo_prepare_shader(struct demo *demo,
857                                      XGL_PIPELINE_SHADER_STAGE stage,
858                                      const void *code,
859                                      XGL_SIZE size)
860{
861    XGL_SHADER_CREATE_INFO createInfo;
862    XGL_SHADER shader;
863    XGL_RESULT err;
864
865
866    createInfo.sType = XGL_STRUCTURE_TYPE_SHADER_CREATE_INFO;
867    createInfo.pNext = NULL;
868
869#ifdef EXTERNAL_BIL
870    createInfo.codeSize = size;
871    createInfo.pCode = code;
872    createInfo.flags = 0;
873
874    err = xglCreateShader(demo->device, &createInfo, &shader);
875    if (err) {
876        free((void *) createInfo.pCode);
877    }
878#else
879    // Create fake BIL structure to feed GLSL
880    // to the driver "under the covers"
881    createInfo.codeSize = 3 * sizeof(uint32_t) + size + 1;
882    createInfo.pCode = malloc(createInfo.codeSize);
883    createInfo.flags = 0;
884
885    /* try version 0 first: XGL_PIPELINE_SHADER_STAGE followed by GLSL */
886    ((uint32_t *) createInfo.pCode)[0] = ICD_BIL_MAGIC;
887    ((uint32_t *) createInfo.pCode)[1] = 0;
888    ((uint32_t *) createInfo.pCode)[2] = stage;
889    memcpy(((uint32_t *) createInfo.pCode + 3), code, size + 1);
890
891    err = xglCreateShader(demo->device, &createInfo, &shader);
892    if (err) {
893        free((void *) createInfo.pCode);
894        return NULL;
895    }
896#endif
897
898    return shader;
899}
900
901char *demo_read_bil(const char *filename, XGL_SIZE *psize)
902{
903    long int size;
904    void *shader_code;
905
906    FILE *fp = fopen(filename, "rb");
907    if (!fp) return NULL;
908
909    fseek(fp, 0L, SEEK_END);
910    size = ftell(fp);
911
912    fseek(fp, 0L, SEEK_SET);
913
914    shader_code = malloc(size);
915    fread(shader_code, size, 1, fp);
916
917    *psize = size;
918
919    return shader_code;
920}
921
922static XGL_SHADER demo_prepare_vs(struct demo *demo)
923{
924#ifdef EXTERNAL_BIL
925    void *vertShaderCode;
926    XGL_SIZE size;
927
928    vertShaderCode = demo_read_bil("cube-vert.bil", &size);
929
930    return demo_prepare_shader(demo, XGL_SHADER_STAGE_VERTEX,
931                               vertShaderCode, size);
932#else
933    static const char *vertShaderText =
934            "#version 140\n"
935            "#extension GL_ARB_separate_shader_objects : enable\n"
936            "#extension GL_ARB_shading_language_420pack : enable\n"
937            "\n"
938            "layout(binding = 0) uniform buf {\n"
939            "        mat4 MVP;\n"
940            "        vec4 position[12*3];\n"
941            "        vec4 attr[12*3];\n"
942            "} ubuf;\n"
943            "\n"
944            "layout (location = 0) out vec4 texcoord;\n"
945            "\n"
946            "void main() \n"
947            "{\n"
948            "   texcoord = ubuf.attr[gl_VertexID];\n"
949            "   gl_Position = ubuf.MVP * ubuf.position[gl_VertexID];\n"
950            "}\n";
951
952    return demo_prepare_shader(demo, XGL_SHADER_STAGE_VERTEX,
953                               (const void *) vertShaderText,
954                               strlen(vertShaderText));
955#endif
956}
957
958static XGL_SHADER demo_prepare_fs(struct demo *demo)
959{
960#ifdef EXTERNAL_BIL
961    void *fragShaderCode;
962    XGL_SIZE size;
963
964    fragShaderCode = demo_read_bil("cube-frag.bil", &size);
965
966    return demo_prepare_shader(demo, XGL_SHADER_STAGE_FRAGMENT,
967                               fragShaderCode, size);
968#else
969    static const char *fragShaderText =
970            "#version 140\n"
971            "#extension GL_ARB_separate_shader_objects : enable\n"
972            "#extension GL_ARB_shading_language_420pack : enable\n"
973            "layout (binding = 0) uniform sampler2D tex;\n"
974            "\n"
975            "layout (location = 0) in vec4 texcoord;\n"
976            "void main() {\n"
977            "   gl_FragColor = texture(tex, texcoord.xy);\n"
978            "}\n";
979
980    return demo_prepare_shader(demo, XGL_SHADER_STAGE_FRAGMENT,
981                               (const void *) fragShaderText,
982                               strlen(fragShaderText));
983#endif
984}
985
986static void demo_prepare_pipeline(struct demo *demo)
987{
988    XGL_GRAPHICS_PIPELINE_CREATE_INFO pipeline;
989    XGL_PIPELINE_IA_STATE_CREATE_INFO ia;
990    XGL_PIPELINE_RS_STATE_CREATE_INFO rs;
991    XGL_PIPELINE_CB_STATE cb;
992    XGL_PIPELINE_DB_STATE_CREATE_INFO db;
993    XGL_PIPELINE_SHADER_STAGE_CREATE_INFO vs;
994    XGL_PIPELINE_SHADER_STAGE_CREATE_INFO fs;
995    XGL_DESCRIPTOR_SLOT_INFO vs_slots[3];
996    XGL_DESCRIPTOR_SLOT_INFO fs_slots[3];
997    XGL_RESULT err;
998
999    memset(&pipeline, 0, sizeof(pipeline));
1000    pipeline.sType = XGL_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
1001
1002    memset(&ia, 0, sizeof(ia));
1003    ia.sType = XGL_STRUCTURE_TYPE_PIPELINE_IA_STATE_CREATE_INFO;
1004    ia.topology = XGL_TOPOLOGY_TRIANGLE_LIST;
1005
1006    memset(&rs, 0, sizeof(rs));
1007    rs.sType = XGL_STRUCTURE_TYPE_PIPELINE_RS_STATE_CREATE_INFO;
1008
1009    memset(&cb, 0, sizeof(cb));
1010    cb.sType = XGL_STRUCTURE_TYPE_PIPELINE_CB_STATE_CREATE_INFO;
1011    cb.attachment[0].format = demo->format;
1012    cb.attachment[0].channelWriteMask = 0xf;
1013
1014    memset(&db, 0, sizeof(db));
1015    db.sType = XGL_STRUCTURE_TYPE_PIPELINE_DB_STATE_CREATE_INFO;
1016    db.format = demo->depth.format;
1017
1018    memset(&vs_slots, 0, sizeof(vs_slots));
1019    vs_slots[0].slotObjectType = XGL_SLOT_SHADER_RESOURCE;
1020    vs_slots[0].shaderEntityIndex = 0;
1021
1022    memset(&fs_slots, 0, sizeof(fs_slots));
1023    fs_slots[1].slotObjectType = XGL_SLOT_SHADER_SAMPLER;
1024    fs_slots[1].shaderEntityIndex = 0;
1025    fs_slots[2].slotObjectType = XGL_SLOT_SHADER_TEXTURE_RESOURCE;
1026    fs_slots[2].shaderEntityIndex = 0;
1027
1028    memset(&vs, 0, sizeof(vs));
1029    vs.sType = XGL_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1030    vs.shader.stage = XGL_SHADER_STAGE_VERTEX;
1031    vs.shader.shader = demo_prepare_vs(demo);
1032    assert(vs.shader.shader != NULL);
1033    vs.shader.descriptorSetMapping[0].descriptorCount = 3;
1034    vs.shader.descriptorSetMapping[0].pDescriptorInfo = vs_slots;
1035
1036    memset(&fs, 0, sizeof(fs));
1037    fs.sType = XGL_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1038    fs.shader.stage = XGL_SHADER_STAGE_FRAGMENT;
1039    fs.shader.shader = demo_prepare_fs(demo);
1040    assert(fs.shader.shader != NULL);
1041    fs.shader.descriptorSetMapping[0].descriptorCount = 3;
1042    fs.shader.descriptorSetMapping[0].pDescriptorInfo = fs_slots;
1043
1044    pipeline.pNext = (const XGL_VOID *) &ia;
1045    ia.pNext = (const XGL_VOID *) &rs;
1046    rs.pNext = (const XGL_VOID *) &cb;
1047    cb.pNext = (const XGL_VOID *) &db;
1048    db.pNext = (const XGL_VOID *) &vs;
1049    vs.pNext = (const XGL_VOID *) &fs;
1050
1051    err = xglCreateGraphicsPipeline(demo->device, &pipeline, &demo->pipeline);
1052    assert(!err);
1053
1054    xglDestroyObject(vs.shader.shader);
1055    xglDestroyObject(fs.shader.shader);
1056}
1057
1058static void demo_prepare_dynamic_states(struct demo *demo)
1059{
1060    XGL_VIEWPORT_STATE_CREATE_INFO viewport;
1061    XGL_RASTER_STATE_CREATE_INFO raster;
1062    XGL_MSAA_STATE_CREATE_INFO msaa;
1063    XGL_COLOR_BLEND_STATE_CREATE_INFO color_blend;
1064    XGL_DEPTH_STENCIL_STATE_CREATE_INFO depth_stencil;
1065    XGL_RESULT err;
1066
1067    memset(&viewport, 0, sizeof(viewport));
1068    viewport.viewportCount = 1;
1069    viewport.scissorEnable = XGL_FALSE;
1070    viewport.viewports[0].width = (XGL_FLOAT) demo->width;
1071    viewport.viewports[0].height = (XGL_FLOAT) demo->height;
1072    viewport.viewports[0].minDepth = (XGL_FLOAT) 0.0f;
1073    viewport.viewports[0].maxDepth = (XGL_FLOAT) 1.0f;
1074
1075    memset(&raster, 0, sizeof(raster));
1076    raster.sType = XGL_STRUCTURE_TYPE_RASTER_STATE_CREATE_INFO;
1077    raster.fillMode = XGL_FILL_SOLID;
1078    raster.cullMode = XGL_CULL_NONE;
1079    raster.frontFace = XGL_FRONT_FACE_CCW;
1080
1081    memset(&msaa, 0, sizeof(msaa));
1082    msaa.sType = XGL_STRUCTURE_TYPE_MSAA_STATE_CREATE_INFO;
1083    msaa.samples = 1;
1084    msaa.sampleMask = 0x1;
1085
1086    memset(&color_blend, 0, sizeof(color_blend));
1087    color_blend.sType = XGL_STRUCTURE_TYPE_COLOR_BLEND_STATE_CREATE_INFO;
1088
1089    memset(&depth_stencil, 0, sizeof(depth_stencil));
1090    depth_stencil.sType = XGL_STRUCTURE_TYPE_DEPTH_STENCIL_STATE_CREATE_INFO;
1091    depth_stencil.depthTestEnable = XGL_TRUE;
1092    depth_stencil.depthWriteEnable = XGL_TRUE;
1093    depth_stencil.depthFunc = XGL_COMPARE_LESS_EQUAL;
1094    depth_stencil.depthBoundsEnable = XGL_FALSE;
1095
1096    err = xglCreateViewportState(demo->device, &viewport, &demo->viewport);
1097    assert(!err);
1098
1099    err = xglCreateRasterState(demo->device, &raster, &demo->raster);
1100    assert(!err);
1101
1102    err = xglCreateMsaaState(demo->device, &msaa, &demo->msaa);
1103    assert(!err);
1104
1105    err = xglCreateColorBlendState(demo->device,
1106            &color_blend, &demo->color_blend);
1107    assert(!err);
1108
1109    err = xglCreateDepthStencilState(demo->device,
1110            &depth_stencil, &demo->depth_stencil);
1111    assert(!err);
1112}
1113
1114static void demo_prepare(struct demo *demo)
1115{
1116    const XGL_CMD_BUFFER_CREATE_INFO cmd = {
1117        .sType = XGL_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,
1118        .pNext = NULL,
1119        .queueType = XGL_QUEUE_TYPE_GRAPHICS,
1120        .flags = 0,
1121    };
1122    XGL_RESULT err;
1123
1124    demo_prepare_buffers(demo);
1125    demo_prepare_depth(demo);
1126    demo_prepare_textures(demo);
1127    demo_prepare_cube_data_buffer(demo);
1128    demo_prepare_descriptor_set(demo);
1129
1130    demo_prepare_pipeline(demo);
1131    demo_prepare_dynamic_states(demo);
1132
1133    err = xglCreateCommandBuffer(demo->device, &cmd, &demo->cmd);
1134    assert(!err);
1135}
1136
1137static void demo_handle_event(struct demo *demo,
1138                              const xcb_generic_event_t *event)
1139{
1140    u_int8_t event_code = event->response_type & 0x7f;
1141    switch (event_code) {
1142    case XCB_EXPOSE:
1143        // TODO: Resize window
1144        break;
1145    case XCB_CLIENT_MESSAGE:
1146        if((*(xcb_client_message_event_t*)event).data.data32[0] ==
1147           (*demo->atom_wm_delete_window).atom) {
1148            demo->quit = true;
1149        }
1150        break;
1151    case XCB_KEY_RELEASE:
1152        {
1153            const xcb_key_release_event_t *key =
1154                (const xcb_key_release_event_t *) event;
1155
1156            switch (key->detail) {
1157            case 0x9:           // Escape
1158                demo->quit = true;
1159                break;
1160            case 0x71:          // left arrow key
1161                demo->spin_angle += demo->spin_increment;
1162                break;
1163            case 0x72:          // right arrow key
1164                demo->spin_angle -= demo->spin_increment;
1165                break;
1166            case 0x41:
1167                demo->pause = !demo->pause;
1168                 break;
1169            }
1170        }
1171        break;
1172    default:
1173        break;
1174    }
1175}
1176
1177static void demo_run(struct demo *demo)
1178{
1179    xcb_flush(demo->connection);
1180
1181    while (!demo->quit) {
1182        xcb_generic_event_t *event;
1183
1184        if (demo->pause) {
1185            event = xcb_wait_for_event(demo->connection);
1186        } else {
1187            event = xcb_poll_for_event(demo->connection);
1188        }
1189        if (event) {
1190            demo_handle_event(demo, event);
1191            free(event);
1192        }
1193
1194        // Wait for work to finish before updating MVP.
1195        xglDeviceWaitIdle(demo->device);
1196        demo_update_data_buffer(demo);
1197
1198        demo_draw(demo);
1199
1200        // Wait for work to finish before updating MVP.
1201        xglDeviceWaitIdle(demo->device);
1202    }
1203}
1204
1205static void demo_create_window(struct demo *demo)
1206{
1207    uint32_t value_mask, value_list[32];
1208
1209    demo->window = xcb_generate_id(demo->connection);
1210
1211    value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
1212    value_list[0] = demo->screen->black_pixel;
1213    value_list[1] = XCB_EVENT_MASK_KEY_RELEASE |
1214                    XCB_EVENT_MASK_EXPOSURE;
1215
1216    xcb_create_window(demo->connection,
1217            XCB_COPY_FROM_PARENT,
1218            demo->window, demo->screen->root,
1219            0, 0, demo->width, demo->height, 0,
1220            XCB_WINDOW_CLASS_INPUT_OUTPUT,
1221            demo->screen->root_visual,
1222            value_mask, value_list);
1223
1224    /* Magic code that will send notification when window is destroyed */
1225    xcb_intern_atom_cookie_t cookie = xcb_intern_atom(demo->connection, 1, 12,
1226                                                      "WM_PROTOCOLS");
1227    xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(demo->connection, cookie, 0);
1228
1229    xcb_intern_atom_cookie_t cookie2 = xcb_intern_atom(demo->connection, 0, 16, "WM_DELETE_WINDOW");
1230    demo->atom_wm_delete_window = xcb_intern_atom_reply(demo->connection, cookie2, 0);
1231
1232    xcb_change_property(demo->connection, XCB_PROP_MODE_REPLACE,
1233                        demo->window, (*reply).atom, 4, 32, 1,
1234                        &(*demo->atom_wm_delete_window).atom);
1235    free(reply);
1236
1237    xcb_map_window(demo->connection, demo->window);
1238}
1239
1240static void demo_init_xgl(struct demo *demo)
1241{
1242    const XGL_APPLICATION_INFO app = {
1243        .sType = XGL_STRUCTURE_TYPE_APPLICATION_INFO,
1244        .pNext = NULL,
1245        .pAppName = "cube",
1246        .appVersion = 0,
1247        .pEngineName = "cube",
1248        .engineVersion = 0,
1249        .apiVersion = XGL_MAKE_VERSION(0, 22, 0),
1250    };
1251    const XGL_WSI_X11_CONNECTION_INFO connection = {
1252        .pConnection = demo->connection,
1253        .root = demo->screen->root,
1254        .provider = 0,
1255    };
1256    const XGL_DEVICE_QUEUE_CREATE_INFO queue = {
1257        .queueNodeIndex = 0,
1258        .queueCount = 1,
1259    };
1260    const XGL_CHAR *ext_names[] = {
1261        "XGL_WSI_X11",
1262    };
1263    const XGL_DEVICE_CREATE_INFO device = {
1264        .sType = XGL_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
1265        .pNext = NULL,
1266        .queueRecordCount = 1,
1267        .pRequestedQueues = &queue,
1268        .extensionCount = 1,
1269        .ppEnabledExtensionNames = ext_names,
1270        .maxValidationLevel = XGL_VALIDATION_LEVEL_END_RANGE,
1271        .flags = XGL_DEVICE_CREATE_VALIDATION_BIT,
1272    };
1273    XGL_RESULT err;
1274    XGL_UINT gpu_count;
1275    XGL_UINT i;
1276
1277    err = xglInitAndEnumerateGpus(&app, NULL, 1, &gpu_count, &demo->gpu);
1278    assert(!err && gpu_count == 1);
1279
1280    for (i = 0; i < device.extensionCount; i++) {
1281        err = xglGetExtensionSupport(demo->gpu, ext_names[i]);
1282        assert(!err);
1283    }
1284
1285    err = xglWsiX11AssociateConnection(demo->gpu, &connection);
1286    assert(!err);
1287
1288    err = xglCreateDevice(demo->gpu, &device, &demo->device);
1289    assert(!err);
1290
1291    err = xglGetDeviceQueue(demo->device, XGL_QUEUE_TYPE_GRAPHICS,
1292            0, &demo->queue);
1293    assert(!err);
1294}
1295
1296static void demo_init_connection(struct demo *demo)
1297{
1298    const xcb_setup_t *setup;
1299    xcb_screen_iterator_t iter;
1300    int scr;
1301
1302    demo->connection = xcb_connect(NULL, &scr);
1303
1304    setup = xcb_get_setup(demo->connection);
1305    iter = xcb_setup_roots_iterator(setup);
1306    while (scr-- > 0)
1307        xcb_screen_next(&iter);
1308
1309    demo->screen = iter.data;
1310}
1311
1312static void demo_init(struct demo *demo)
1313{
1314    vec3 eye = {0.0f, 3.0f, 5.0f};
1315    vec3 origin = {0, 0, 0};
1316    vec3 up = {0.0f, -1.0f, 0.0};
1317
1318    memset(demo, 0, sizeof(*demo));
1319
1320    demo_init_connection(demo);
1321    demo_init_xgl(demo);
1322
1323    demo->width = 500;
1324    demo->height = 500;
1325    demo->format.channelFormat = XGL_CH_FMT_B8G8R8A8;
1326    demo->format.numericFormat = XGL_NUM_FMT_UNORM;
1327
1328    demo->spin_angle = 0.01f;
1329    demo->spin_increment = 0.01f;
1330    demo->pause = false;
1331
1332    mat4x4_perspective(demo->projection_matrix, degreesToRadians(45.0f), 1.0f, 0.1f, 100.0f);
1333    mat4x4_look_at(demo->view_matrix, eye, origin, up);
1334    mat4x4_identity(demo->model_matrix);
1335}
1336
1337static void demo_cleanup(struct demo *demo)
1338{
1339    XGL_UINT i;
1340
1341    xglDestroyObject(demo->cmd);
1342
1343    xglDestroyObject(demo->viewport);
1344    xglDestroyObject(demo->raster);
1345    xglDestroyObject(demo->msaa);
1346    xglDestroyObject(demo->color_blend);
1347    xglDestroyObject(demo->depth_stencil);
1348
1349    xglDestroyObject(demo->pipeline);
1350
1351    xglDestroyObject(demo->dset);
1352
1353//    xglFreeMemory(demo->vertices.mem);
1354
1355    for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
1356        xglDestroyObject(demo->textures[i].view);
1357        xglDestroyObject(demo->textures[i].image);
1358        xglFreeMemory(demo->textures[i].mem);
1359        xglDestroyObject(demo->textures[i].sampler);
1360    }
1361
1362    xglDestroyObject(demo->depth.view);
1363    xglDestroyObject(demo->depth.image);
1364    xglFreeMemory(demo->depth.mem);
1365
1366    for (i = 0; i < DEMO_BUFFER_COUNT; i++) {
1367        xglDestroyObject(demo->buffers[i].fence);
1368        xglDestroyObject(demo->buffers[i].view);
1369        xglDestroyObject(demo->buffers[i].image);
1370    }
1371
1372    xglDestroyDevice(demo->device);
1373
1374    xcb_destroy_window(demo->connection, demo->window);
1375    xcb_disconnect(demo->connection);
1376}
1377
1378int main(void)
1379{
1380    struct demo demo;
1381
1382    demo_init(&demo);
1383
1384    demo_prepare(&demo);
1385    demo_create_window(&demo);
1386    demo_run(&demo);
1387
1388    demo_cleanup(&demo);
1389
1390    return 0;
1391}
1392