vkd3d-shader/hlsl: Handle error instructions in add_shader_compilation().
[vkd3d.git] / demos / gears.c
blob1171c3c786d3076b4c079c165e9ea78b377db86f
1 /*
2 * Copyright 2016 Henri Verbeet for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * This application contains code derived from glxgears, the license for which
21 * follows:
23 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
25 * Permission is hereby granted, free of charge, to any person obtaining a
26 * copy of this software and associated documentation files (the "Software"),
27 * to deal in the Software without restriction, including without limitation
28 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
29 * and/or sell copies of the Software, and to permit persons to whom the
30 * Software is furnished to do so, subject to the following conditions:
32 * The above copyright notice and this permission notice shall be included
33 * in all copies or substantial portions of the Software.
35 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
36 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
38 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
39 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
40 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
43 #define INITGUID
44 #define _GNU_SOURCE
45 #include <sys/time.h>
46 #include <assert.h>
47 #include <stdio.h>
48 #include <math.h>
49 #include "demo.h"
51 DEMO_EMBED(gears_hlsl, "gears.hlsl");
53 struct cxg_fence
55 ID3D12Fence *fence;
56 UINT64 value;
57 HANDLE event;
60 struct cxg_cb_data
62 float mvp_matrix[16];
63 float normal_matrix[12];
66 struct cxg_instance_data
68 struct demo_vec3 diffuse;
69 struct demo_vec4 transform;
72 struct cxg_vertex
74 struct demo_vec3 position;
75 struct demo_vec3 normal;
78 struct cxg_face
80 uint16_t v[3];
83 struct cxg_mesh
85 struct cxg_vertex *vertices;
86 size_t vertex_count;
88 struct cxg_face *faces;
89 size_t flat_face_count;
90 size_t smooth_face_count;
93 struct cxg_draw
95 size_t vertex_idx;
96 size_t flat_index_idx;
97 size_t flat_index_count;
98 size_t smooth_index_idx;
99 size_t smooth_index_count;
102 struct cx_gears
104 struct demo demo;
106 struct demo_window *window;
108 unsigned int width;
109 unsigned int height;
110 float aspect_ratio;
112 bool animate;
113 float alpha;
114 float theta;
115 float phi;
117 D3D12_VIEWPORT vp;
118 D3D12_RECT scissor_rect;
120 ID3D12Device *device;
121 ID3D12CommandQueue *command_queue;
122 struct demo_swapchain *swapchain;
123 ID3D12DescriptorHeap *rtv_heap, *dsv_heap;
124 unsigned int rtv_descriptor_size;
125 ID3D12Resource *render_targets[3];
126 ID3D12CommandAllocator *command_allocator[3];
128 ID3D12RootSignature *root_signature;
129 ID3D12PipelineState *pipeline_state_smooth, *pipeline_state_flat;
130 ID3D12GraphicsCommandList *command_list[3];
131 ID3D12Resource *ds, *cb, *vb[2], *ib;
132 D3D12_VERTEX_BUFFER_VIEW vbv[2];
133 D3D12_INDEX_BUFFER_VIEW ibv;
135 unsigned int rt_idx;
136 struct cxg_fence fence;
138 struct cxg_cb_data *cb_data;
139 struct cxg_instance_data *instance_data;
140 struct cxg_draw draws[3];
143 static void cxg_populate_command_list(struct cx_gears *cxg, unsigned int rt_idx)
145 ID3D12GraphicsCommandList *command_list = cxg->command_list[rt_idx];
146 static const float clear_colour[] = {0.0f, 0.0f, 0.0f, 1.0f};
148 D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle, dsv_handle;
149 D3D12_RESOURCE_BARRIER barrier;
150 HRESULT hr;
151 size_t i;
153 hr = ID3D12CommandAllocator_Reset(cxg->command_allocator[rt_idx]);
154 assert(SUCCEEDED(hr));
156 hr = ID3D12GraphicsCommandList_Reset(command_list, cxg->command_allocator[rt_idx], cxg->pipeline_state_flat);
157 assert(SUCCEEDED(hr));
159 ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, cxg->root_signature);
160 ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(command_list, 0,
161 ID3D12Resource_GetGPUVirtualAddress(cxg->cb));
163 ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &cxg->vp);
164 ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &cxg->scissor_rect);
166 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
167 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
168 barrier.Transition.pResource = cxg->render_targets[rt_idx];
169 barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
170 barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
171 barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
172 ID3D12GraphicsCommandList_ResourceBarrier(command_list, 1, &barrier);
174 rtv_handle = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(cxg->rtv_heap);
175 rtv_handle.ptr += rt_idx * cxg->rtv_descriptor_size;
176 dsv_handle = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(cxg->dsv_heap);
177 ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &rtv_handle, FALSE, &dsv_handle);
179 ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, rtv_handle, clear_colour, 0, NULL);
180 ID3D12GraphicsCommandList_ClearDepthStencilView(command_list,
181 dsv_handle, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, NULL);
182 ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
183 ID3D12GraphicsCommandList_IASetIndexBuffer(command_list, &cxg->ibv);
184 ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, 2, cxg->vbv);
186 for (i = 0; i < ARRAY_SIZE(cxg->draws); ++i)
188 ID3D12GraphicsCommandList_DrawIndexedInstanced(command_list, cxg->draws[i].flat_index_count,
189 1, cxg->draws[i].flat_index_idx, cxg->draws[i].vertex_idx, i);
191 ID3D12GraphicsCommandList_SetPipelineState(command_list, cxg->pipeline_state_smooth);
192 ID3D12GraphicsCommandList_DrawIndexedInstanced(command_list, cxg->draws[i].smooth_index_count,
193 1, cxg->draws[i].smooth_index_idx, cxg->draws[i].vertex_idx, i);
195 ID3D12GraphicsCommandList_SetPipelineState(command_list, cxg->pipeline_state_flat);
198 barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
199 barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
200 ID3D12GraphicsCommandList_ResourceBarrier(command_list, 1, &barrier);
202 hr = ID3D12GraphicsCommandList_Close(command_list);
203 assert(SUCCEEDED(hr));
206 static void cxg_wait_for_previous_frame(struct cx_gears *cxg)
208 struct cxg_fence *fence = &cxg->fence;
209 const UINT64 v = fence->value;
210 HRESULT hr;
212 hr = ID3D12CommandQueue_Signal(cxg->command_queue, fence->fence, v);
213 assert(SUCCEEDED(hr));
215 ++fence->value;
217 if (ID3D12Fence_GetCompletedValue(fence->fence) < v)
219 hr = ID3D12Fence_SetEventOnCompletion(fence->fence, v, fence->event);
220 assert(SUCCEEDED(hr));
221 demo_wait_event(fence->event, INFINITE);
224 cxg->rt_idx = demo_swapchain_get_current_back_buffer_index(cxg->swapchain);
227 static void cxg_update_mvp(struct cx_gears *cxg)
229 float s1 = sinf(cxg->theta);
230 float c1 = cosf(cxg->theta);
231 float s2 = sinf(cxg->phi);
232 float c2 = cosf(cxg->phi);
233 float z_offset = -40.0f;
234 float z_max = 60.0f;
235 float z_min = 5.0f;
236 float sx = z_min;
237 float sy = z_min * cxg->aspect_ratio;
238 float sz = -((z_max + z_min) / (z_max - z_min));
239 float d = (-2.0f * z_max * z_min) / (z_max - z_min);
240 unsigned int i, j;
241 float world[] =
243 c1, s2 * s1, c2 * -s1, 0.0f,
244 0.0f, c2, s2, 0.0f,
245 s1, -s2 * c1, c2 * c1, 0.0f,
246 0.0f, 0.0f, z_offset, 1.0f,
248 float projection[] =
250 sx, 0.0f, 0.0f, 0.0f,
251 0.0f, sy, 0.0f, 0.0f,
252 0.0f, 0.0f, sz, -1.0f,
253 0.0f, 0.0f, d, 0.0f,
256 for (i = 0; i < 4; ++i)
258 for (j = 0; j < 4; ++j)
260 cxg->cb_data->mvp_matrix[i * 4 + j] = projection[j] * world[i * 4]
261 + projection[j + 4] * world[i * 4 + 1]
262 + projection[j + 8] * world[i * 4 + 2]
263 + projection[j + 12] * world[i * 4 + 3];
266 memcpy(cxg->cb_data->normal_matrix, world, sizeof(cxg->cb_data->normal_matrix));
269 static void cxg_render_frame(struct cx_gears *cxg)
271 static double t_prev = -1.0;
272 struct timeval tv;
273 double dt, t;
274 float a;
276 gettimeofday(&tv, NULL);
277 t = tv.tv_sec + tv.tv_usec / 1000000.0;
278 if (t_prev < 0.0)
279 t_prev = t;
280 dt = t - t_prev;
281 t_prev = t;
283 if (cxg->animate)
285 cxg->alpha += (70.0 * M_PI / 180.0) * dt; /* 70°/s */
286 if (cxg->alpha > 20.0 * M_PI)
287 cxg->alpha -= 20.0 * M_PI;
290 a = cxg->alpha;
291 demo_vec4_set(&cxg->instance_data[0].transform, cosf(a), sinf(a), -3.0f, -2.0f);
292 a = (-2.0f * cxg->alpha) - 9.0f * M_PI / 180.0;
293 demo_vec4_set(&cxg->instance_data[1].transform, cosf(a), sinf(a), 3.1f, -2.0f);
294 a = (-2.0f * cxg->alpha) - 25.0f * M_PI / 180.0;
295 demo_vec4_set(&cxg->instance_data[2].transform, cosf(a), sinf(a), -3.1f, 4.2f);
297 ID3D12CommandQueue_ExecuteCommandLists(cxg->command_queue, 1,
298 (ID3D12CommandList **)&cxg->command_list[cxg->rt_idx]);
299 demo_swapchain_present(cxg->swapchain);
300 cxg_wait_for_previous_frame(cxg);
303 static void cxg_destroy_pipeline(struct cx_gears *cxg)
305 unsigned int i;
307 for (i = 0; i < ARRAY_SIZE(cxg->command_allocator); ++i)
309 ID3D12CommandAllocator_Release(cxg->command_allocator[i]);
311 for (i = 0; i < ARRAY_SIZE(cxg->render_targets); ++i)
313 ID3D12Resource_Release(cxg->render_targets[i]);
315 ID3D12DescriptorHeap_Release(cxg->dsv_heap);
316 ID3D12DescriptorHeap_Release(cxg->rtv_heap);
317 demo_swapchain_destroy(cxg->swapchain);
318 ID3D12CommandQueue_Release(cxg->command_queue);
319 ID3D12Device_Release(cxg->device);
322 static void cxg_load_pipeline(struct cx_gears *cxg)
324 struct demo_swapchain_desc swapchain_desc;
325 D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle;
326 D3D12_DESCRIPTOR_HEAP_DESC heap_desc;
327 D3D12_COMMAND_QUEUE_DESC queue_desc;
328 unsigned int i;
329 HRESULT hr;
331 hr = D3D12CreateDevice(NULL, D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, (void **)&cxg->device);
332 assert(SUCCEEDED(hr));
334 memset(&queue_desc, 0, sizeof(queue_desc));
335 queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
336 queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
337 hr = ID3D12Device_CreateCommandQueue(cxg->device, &queue_desc,
338 &IID_ID3D12CommandQueue, (void **)&cxg->command_queue);
339 assert(SUCCEEDED(hr));
341 swapchain_desc.buffer_count = ARRAY_SIZE(cxg->render_targets);
342 swapchain_desc.format = DXGI_FORMAT_B8G8R8A8_UNORM;
343 swapchain_desc.width = cxg->width;
344 swapchain_desc.height = cxg->height;
345 cxg->swapchain = demo_swapchain_create(cxg->command_queue, cxg->window, &swapchain_desc);
346 assert(cxg->swapchain);
347 cxg->rt_idx = demo_swapchain_get_current_back_buffer_index(cxg->swapchain);
349 memset(&heap_desc, 0, sizeof(heap_desc));
350 heap_desc.NumDescriptors = ARRAY_SIZE(cxg->render_targets);
351 heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
352 heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
353 hr = ID3D12Device_CreateDescriptorHeap(cxg->device, &heap_desc,
354 &IID_ID3D12DescriptorHeap, (void **)&cxg->rtv_heap);
355 assert(SUCCEEDED(hr));
357 cxg->rtv_descriptor_size = ID3D12Device_GetDescriptorHandleIncrementSize(cxg->device,
358 D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
359 rtv_handle = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(cxg->rtv_heap);
360 for (i = 0; i < ARRAY_SIZE(cxg->render_targets); ++i)
362 cxg->render_targets[i] = demo_swapchain_get_back_buffer(cxg->swapchain, i);
363 ID3D12Device_CreateRenderTargetView(cxg->device, cxg->render_targets[i], NULL, rtv_handle);
364 rtv_handle.ptr += cxg->rtv_descriptor_size;
367 heap_desc.NumDescriptors = 1;
368 heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
369 heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
370 hr = ID3D12Device_CreateDescriptorHeap(cxg->device, &heap_desc,
371 &IID_ID3D12DescriptorHeap, (void **)&cxg->dsv_heap);
372 assert(SUCCEEDED(hr));
374 for (i = 0; i < ARRAY_SIZE(cxg->command_allocator); ++i)
376 hr = ID3D12Device_CreateCommandAllocator(cxg->device, D3D12_COMMAND_LIST_TYPE_DIRECT,
377 &IID_ID3D12CommandAllocator, (void **)&cxg->command_allocator[i]);
378 assert(SUCCEEDED(hr));
382 static void cxg_fence_destroy(struct cxg_fence *cxg_fence)
384 ID3D12Fence_Release(cxg_fence->fence);
385 demo_destroy_event(cxg_fence->event);
388 static void cxg_destroy_assets(struct cx_gears *cxg)
390 unsigned int i;
392 cxg_fence_destroy(&cxg->fence);
393 ID3D12Resource_Release(cxg->ib);
394 ID3D12Resource_Unmap(cxg->vb[1], 0, NULL);
395 ID3D12Resource_Release(cxg->vb[1]);
396 ID3D12Resource_Release(cxg->vb[0]);
397 ID3D12Resource_Unmap(cxg->cb, 0, NULL);
398 ID3D12Resource_Release(cxg->cb);
399 ID3D12Resource_Release(cxg->ds);
400 for (i = 0; i < ARRAY_SIZE(cxg->command_list); ++i)
401 ID3D12GraphicsCommandList_Release(cxg->command_list[i]);
402 ID3D12PipelineState_Release(cxg->pipeline_state_smooth);
403 ID3D12PipelineState_Release(cxg->pipeline_state_flat);
404 ID3D12RootSignature_Release(cxg->root_signature);
407 static void cxg_fence_create(struct cxg_fence *fence, ID3D12Device *device)
409 HRESULT hr;
411 hr = ID3D12Device_CreateFence(device, 0, D3D12_FENCE_FLAG_NONE,
412 &IID_ID3D12Fence, (void **)&fence->fence);
413 assert(SUCCEEDED(hr));
414 fence->value = 1;
415 fence->event = demo_create_event();
416 assert(fence->event);
419 static void cxg_vertex_set_position(struct cxg_vertex *v, float x, float y, float z)
421 demo_vec3_set(&v->position, x, y, z);
424 static void cxg_vertex_set_normal(struct cxg_vertex *v, float x, float y, float z)
426 demo_vec3_set(&v->normal, x, y, z);
429 static void cxg_mesh_create(ID3D12Device *device, float inner_radius, float outer_radius, float width,
430 unsigned int tooth_count, float tooth_depth, struct cxg_mesh *mesh)
432 struct cxg_vertex *vertices;
433 struct cxg_face *faces;
434 unsigned int i, j;
435 float r0, r1, r2;
436 float angle, da;
438 if (!(vertices = calloc(tooth_count, 12 * sizeof(*vertices))))
439 return;
440 if (!(faces = calloc(tooth_count, 20 * sizeof(*faces))))
442 free(vertices);
443 return;
446 r0 = inner_radius;
447 r1 = outer_radius - tooth_depth / 2.0f;
448 r2 = outer_radius + tooth_depth / 2.0f;
449 da = 2.0f * M_PI / tooth_count / 4.0f;
451 for (i = 0; i < tooth_count; ++i)
453 struct cxg_vertex *tooth = &vertices[i * 12];
454 float u, v;
456 angle = i * 2.0f * M_PI / tooth_count;
458 cxg_vertex_set_position(&tooth[0], r0 * cosf(angle), r0 * sinf(angle), width * 0.5f);
459 cxg_vertex_set_normal(&tooth[0], -cosf(angle), -sinf(angle), 0.0f);
460 cxg_vertex_set_position(&tooth[1], r1 * cosf(angle), r1 * sinf(angle), width * 0.5f);
461 cxg_vertex_set_normal(&tooth[1], 0.0f, 0.0f, 1.0f);
462 cxg_vertex_set_position(&tooth[2], r1 * cosf(angle + 3 * da), r1 * sinf(angle + 3 * da), width * 0.5f);
463 cxg_vertex_set_normal(&tooth[2], 0.0f, 0.0f, 1.0f);
464 cxg_vertex_set_position(&tooth[3], r2 * cosf(angle + da), r2 * sinf(angle + da), width * 0.5f);
465 cxg_vertex_set_normal(&tooth[3], cosf(angle), sinf(angle), 0.0f);
466 cxg_vertex_set_position(&tooth[4], r2 * cosf(angle + 2 * da), r2 * sinf(angle + 2 * da), width * 0.5f);
467 u = r1 * cosf(angle + 3 * da) - r2 * cosf(angle + 2 * da);
468 v = r1 * sinf(angle + 3 * da) - r2 * sinf(angle + 2 * da);
469 cxg_vertex_set_normal(&tooth[4], v, -u, 0.0f);
471 cxg_vertex_set_position(&tooth[5], r0 * cosf(angle), r0 * sinf(angle), -width * 0.5f);
472 cxg_vertex_set_normal(&tooth[5], -cosf(angle), -sinf(angle), 0.0f);
473 cxg_vertex_set_position(&tooth[6], r1 * cosf(angle), r1 * sinf(angle), -width * 0.5f);
474 cxg_vertex_set_normal(&tooth[6], 0.0f, 0.0f, -1.0f);
475 cxg_vertex_set_position(&tooth[7], r1 * cosf(angle + 3 * da), r1 * sinf(angle + 3 * da), -width * 0.5f);
476 cxg_vertex_set_normal(&tooth[7], 0.0f, 0.0f, -1.0f);
477 cxg_vertex_set_position(&tooth[8], r2 * cosf(angle + da), r2 * sinf(angle + da), -width * 0.5f);
478 cxg_vertex_set_normal(&tooth[8], 0.0f, 0.0f, -1.0f);
479 cxg_vertex_set_position(&tooth[9], r2 * cosf(angle + 2 * da), r2 * sinf(angle + 2 * da), -width * 0.5f);
480 cxg_vertex_set_normal(&tooth[9], 0.0f, 0.0f, -1.0f);
482 cxg_vertex_set_position(&tooth[10], r1 * cosf(angle), r1 * sinf(angle), width * 0.5f);
483 u = r2 * cosf(angle + da) - r1 * cosf(angle);
484 v = r2 * sinf(angle + da) - r1 * sinf(angle);
485 cxg_vertex_set_normal(&tooth[10], v, -u, 0.0f);
486 cxg_vertex_set_position(&tooth[11], r1 * cosf(angle + 3 * da), r1 * sinf(angle + 3 * da), width * 0.5f);
487 cxg_vertex_set_normal(&tooth[11], cosf(angle), sinf(angle), 0.0f);
490 for (i = 0; i < tooth_count; ++i)
492 struct cxg_face *f = &faces[i * 18];
493 static const struct cxg_face flat_faces[] =
495 /* Front */
496 {{ 1, 2, 0}},
497 {{ 1, 3, 4}},
498 {{ 1, 4, 2}},
499 {{ 2, 12, 0}},
500 {{ 2, 13, 12}},
501 /* Back */
502 {{ 6, 5, 7}},
503 {{ 6, 9, 8}},
504 {{ 6, 7, 9}},
505 {{ 7, 5, 17}},
506 {{ 7, 17, 18}},
507 /* Outward */
508 {{10, 6, 8}},
509 {{10, 8, 3}},
510 {{ 3, 8, 9}},
511 {{ 3, 9, 4}},
512 {{ 4, 9, 7}},
513 {{ 4, 7, 11}},
514 {{11, 7, 18}},
515 {{11, 18, 22}},
518 for (j = 0; j < ARRAY_SIZE(flat_faces); ++j)
520 f[j].v[0] = (flat_faces[j].v[0] + i * 12) % (tooth_count * 12);
521 f[j].v[1] = (flat_faces[j].v[1] + i * 12) % (tooth_count * 12);
522 f[j].v[2] = (flat_faces[j].v[2] + i * 12) % (tooth_count * 12);
526 for (i = 0; i < tooth_count; ++i)
528 struct cxg_face *f = &faces[i * 2 + tooth_count * 18];
529 static const struct cxg_face smooth_faces[] =
531 /* Inward */
532 {{ 0, 17, 5}},
533 {{ 0, 12, 17}},
536 for (j = 0; j < ARRAY_SIZE(smooth_faces); ++j)
538 f[j].v[0] = (smooth_faces[j].v[0] + i * 12) % (tooth_count * 12);
539 f[j].v[1] = (smooth_faces[j].v[1] + i * 12) % (tooth_count * 12);
540 f[j].v[2] = (smooth_faces[j].v[2] + i * 12) % (tooth_count * 12);
544 mesh->vertices = vertices;
545 mesh->vertex_count = 12 * tooth_count;
546 mesh->faces = faces;
547 mesh->flat_face_count = 18 * tooth_count;
548 mesh->smooth_face_count = 2 * tooth_count;
551 static void cxg_mesh_destroy(struct cxg_mesh *mesh)
553 free(mesh->faces);
554 free(mesh->vertices);
557 static void cxg_load_gears(struct cx_gears *cxg)
559 size_t vertex_count, face_count, vertex_idx, face_idx, i;
560 D3D12_RESOURCE_DESC resource_desc;
561 D3D12_HEAP_PROPERTIES heap_desc;
562 D3D12_RANGE read_range = {0, 0};
563 struct cxg_vertex *vertices;
564 struct cxg_mesh gears[3];
565 struct cxg_face *faces;
566 HRESULT hr;
568 cxg_mesh_create(cxg->device, 1.0f, 4.0f, 1.0f, 20, 0.7f, &gears[0]);
569 demo_vec3_set(&cxg->instance_data[0].diffuse, 0.8f, 0.1f, 0.0f);
570 cxg_mesh_create(cxg->device, 0.5f, 2.0f, 2.0f, 10, 0.7f, &gears[1]);
571 demo_vec3_set(&cxg->instance_data[1].diffuse, 0.0f, 0.8f, 0.2f);
572 cxg_mesh_create(cxg->device, 1.3f, 2.0f, 0.5f, 10, 0.7f, &gears[2]);
573 demo_vec3_set(&cxg->instance_data[2].diffuse, 0.2f, 0.2f, 1.0f);
575 for (i = 0, vertex_count = 0, face_count = 0; i < ARRAY_SIZE(gears); ++i)
577 vertex_count += gears[i].vertex_count;
578 face_count += gears[i].flat_face_count + gears[i].smooth_face_count;
581 heap_desc.Type = D3D12_HEAP_TYPE_UPLOAD;
582 heap_desc.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
583 heap_desc.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
584 heap_desc.CreationNodeMask = 1;
585 heap_desc.VisibleNodeMask = 1;
587 resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
588 resource_desc.Alignment = 0;
589 resource_desc.Width = vertex_count * sizeof(*vertices);
590 resource_desc.Height = 1;
591 resource_desc.DepthOrArraySize = 1;
592 resource_desc.MipLevels = 1;
593 resource_desc.Format = DXGI_FORMAT_UNKNOWN;
594 resource_desc.SampleDesc.Count = 1;
595 resource_desc.SampleDesc.Quality = 0;
596 resource_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
597 resource_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
599 hr = ID3D12Device_CreateCommittedResource(cxg->device, &heap_desc, D3D12_HEAP_FLAG_NONE, &resource_desc,
600 D3D12_RESOURCE_STATE_GENERIC_READ, NULL, &IID_ID3D12Resource, (void **)&cxg->vb[0]);
601 assert(SUCCEEDED(hr));
603 resource_desc.Width = face_count * sizeof(*faces);
604 hr = ID3D12Device_CreateCommittedResource(cxg->device, &heap_desc, D3D12_HEAP_FLAG_NONE, &resource_desc,
605 D3D12_RESOURCE_STATE_GENERIC_READ, NULL, &IID_ID3D12Resource, (void **)&cxg->ib);
606 assert(SUCCEEDED(hr));
608 hr = ID3D12Resource_Map(cxg->vb[0], 0, &read_range, (void **)&vertices);
609 assert(SUCCEEDED(hr));
610 hr = ID3D12Resource_Map(cxg->ib, 0, &read_range, (void **)&faces);
611 assert(SUCCEEDED(hr));
613 for (i = 0, vertex_idx = 0, face_idx = 0; i < ARRAY_SIZE(gears); ++i)
615 size_t tmp;
617 cxg->draws[i].vertex_idx = vertex_idx;
618 memcpy(&vertices[vertex_idx], gears[i].vertices, gears[i].vertex_count * sizeof(*vertices));
619 vertex_idx += gears[i].vertex_count;
621 cxg->draws[i].flat_index_idx = 3 * face_idx;
622 cxg->draws[i].flat_index_count = 3 * gears[i].flat_face_count;
623 cxg->draws[i].smooth_index_idx = cxg->draws[i].flat_index_idx + cxg->draws[i].flat_index_count;
624 cxg->draws[i].smooth_index_count = 3 * gears[i].smooth_face_count;
625 tmp = gears[i].flat_face_count + gears[i].smooth_face_count;
626 memcpy(&faces[face_idx], gears[i].faces, tmp * sizeof(*faces));
627 face_idx += tmp;
630 ID3D12Resource_Unmap(cxg->ib, 0, NULL);
631 ID3D12Resource_Unmap(cxg->vb[0], 0, NULL);
633 cxg_mesh_destroy(&gears[2]);
634 cxg_mesh_destroy(&gears[1]);
635 cxg_mesh_destroy(&gears[0]);
637 cxg->vbv[0].BufferLocation = ID3D12Resource_GetGPUVirtualAddress(cxg->vb[0]);
638 cxg->vbv[0].StrideInBytes = sizeof(*vertices);
639 cxg->vbv[0].SizeInBytes = vertex_count * sizeof(*vertices);
641 cxg->ibv.BufferLocation = ID3D12Resource_GetGPUVirtualAddress(cxg->ib);
642 cxg->ibv.SizeInBytes = face_count * sizeof(*faces);
643 cxg->ibv.Format = DXGI_FORMAT_R16_UINT;
646 static void cxg_load_assets(struct cx_gears *cxg)
648 static const D3D12_INPUT_ELEMENT_DESC il_desc[] =
650 {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
651 {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
652 {"DIFFUSE", 0, DXGI_FORMAT_R32G32B32_FLOAT, 1, 0, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1},
653 {"TRANSFORM", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 12, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1},
656 D3D12_ROOT_SIGNATURE_DESC root_signature_desc;
657 D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc;
658 D3D12_CPU_DESCRIPTOR_HANDLE dsv_handle;
659 D3D12_ROOT_PARAMETER root_parameter;
660 ID3DBlob *vs, *ps_flat, *ps_smooth;
661 D3D12_RESOURCE_DESC resource_desc;
662 D3D12_HEAP_PROPERTIES heap_desc;
663 D3D12_RANGE read_range = {0, 0};
664 D3D12_CLEAR_VALUE clear_value;
665 unsigned int i;
666 HRESULT hr;
668 root_parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
669 root_parameter.Descriptor.ShaderRegister = 0;
670 root_parameter.Descriptor.RegisterSpace = 0;
671 root_parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
673 memset(&root_signature_desc, 0, sizeof(root_signature_desc));
674 root_signature_desc.NumParameters = 1;
675 root_signature_desc.pParameters = &root_parameter;
676 root_signature_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT
677 | D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS
678 | D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS
679 | D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS
680 | D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS;
681 hr = demo_create_root_signature(cxg->device, &root_signature_desc, &cxg->root_signature);
682 assert(SUCCEEDED(hr));
684 hr = D3DCompile(gears_hlsl, gears_hlsl_size, "gears.hlsl",
685 NULL, NULL, "vs_main", "vs_5_0", 0, 0, &vs, NULL);
686 assert(SUCCEEDED(hr));
687 hr = D3DCompile(gears_hlsl, gears_hlsl_size, "gears.hlsl",
688 NULL, NULL, "ps_main_flat", "ps_5_0", 0, 0, &ps_flat, NULL);
689 assert(SUCCEEDED(hr));
690 hr = D3DCompile(gears_hlsl, gears_hlsl_size, "gears.hlsl",
691 NULL, NULL, "ps_main_smooth", "ps_5_0", 0, 0, &ps_smooth, NULL);
692 assert(SUCCEEDED(hr));
694 memset(&pso_desc, 0, sizeof(pso_desc));
695 pso_desc.InputLayout.pInputElementDescs = il_desc;
696 pso_desc.InputLayout.NumElements = ARRAY_SIZE(il_desc);
697 pso_desc.pRootSignature = cxg->root_signature;
698 pso_desc.VS.pShaderBytecode = ID3D10Blob_GetBufferPointer(vs);
699 pso_desc.VS.BytecodeLength = ID3D10Blob_GetBufferSize(vs);
700 pso_desc.PS.pShaderBytecode = ID3D10Blob_GetBufferPointer(ps_flat);
701 pso_desc.PS.BytecodeLength = ID3D10Blob_GetBufferSize(ps_flat);
703 demo_rasterizer_desc_init_default(&pso_desc.RasterizerState);
704 pso_desc.RasterizerState.FrontCounterClockwise = TRUE;
705 demo_blend_desc_init_default(&pso_desc.BlendState);
706 pso_desc.DepthStencilState.DepthEnable = TRUE;
707 pso_desc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
708 pso_desc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
709 pso_desc.DepthStencilState.StencilEnable = FALSE;
710 pso_desc.SampleMask = UINT_MAX;
711 pso_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
712 pso_desc.NumRenderTargets = 1;
713 pso_desc.RTVFormats[0] = DXGI_FORMAT_B8G8R8A8_UNORM;
714 pso_desc.DSVFormat = DXGI_FORMAT_D32_FLOAT;
715 pso_desc.SampleDesc.Count = 1;
716 hr = ID3D12Device_CreateGraphicsPipelineState(cxg->device, &pso_desc,
717 &IID_ID3D12PipelineState, (void **)&cxg->pipeline_state_flat);
718 assert(SUCCEEDED(hr));
720 pso_desc.PS.pShaderBytecode = ID3D10Blob_GetBufferPointer(ps_smooth);
721 pso_desc.PS.BytecodeLength = ID3D10Blob_GetBufferSize(ps_smooth);
722 hr = ID3D12Device_CreateGraphicsPipelineState(cxg->device, &pso_desc,
723 &IID_ID3D12PipelineState, (void **)&cxg->pipeline_state_smooth);
724 assert(SUCCEEDED(hr));
726 ID3D10Blob_Release(vs);
727 ID3D10Blob_Release(ps_flat);
728 ID3D10Blob_Release(ps_smooth);
730 for (i = 0; i < ARRAY_SIZE(cxg->command_list); ++i)
732 hr = ID3D12Device_CreateCommandList(cxg->device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT,
733 cxg->command_allocator[i], cxg->pipeline_state_flat,
734 &IID_ID3D12GraphicsCommandList, (void **)&cxg->command_list[i]);
735 assert(SUCCEEDED(hr));
736 hr = ID3D12GraphicsCommandList_Close(cxg->command_list[i]);
737 assert(SUCCEEDED(hr));
740 heap_desc.Type = D3D12_HEAP_TYPE_DEFAULT;
741 heap_desc.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
742 heap_desc.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
743 heap_desc.CreationNodeMask = 1;
744 heap_desc.VisibleNodeMask = 1;
746 resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
747 resource_desc.Alignment = 0;
748 resource_desc.Width = cxg->width;
749 resource_desc.Height = cxg->height;
750 resource_desc.DepthOrArraySize = 1;
751 resource_desc.MipLevels = 1;
752 resource_desc.Format = DXGI_FORMAT_D32_FLOAT;
753 resource_desc.SampleDesc.Count = 1;
754 resource_desc.SampleDesc.Quality = 0;
755 resource_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
756 resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
758 clear_value.Format = DXGI_FORMAT_D32_FLOAT;
759 clear_value.DepthStencil.Depth = 1.0f;
760 clear_value.DepthStencil.Stencil = 0;
762 hr = ID3D12Device_CreateCommittedResource(cxg->device, &heap_desc, D3D12_HEAP_FLAG_NONE, &resource_desc,
763 D3D12_RESOURCE_STATE_DEPTH_WRITE, &clear_value, &IID_ID3D12Resource, (void **)&cxg->ds);
764 assert(SUCCEEDED(hr));
766 dsv_handle = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(cxg->dsv_heap);
767 ID3D12Device_CreateDepthStencilView(cxg->device, cxg->ds, NULL, dsv_handle);
769 heap_desc.Type = D3D12_HEAP_TYPE_UPLOAD;
771 resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
772 resource_desc.Width = sizeof(*cxg->cb_data);
773 resource_desc.Height = 1;
774 resource_desc.Format = DXGI_FORMAT_UNKNOWN;
775 resource_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
776 resource_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
778 hr = ID3D12Device_CreateCommittedResource(cxg->device, &heap_desc, D3D12_HEAP_FLAG_NONE, &resource_desc,
779 D3D12_RESOURCE_STATE_GENERIC_READ, NULL, &IID_ID3D12Resource, (void **)&cxg->cb);
780 assert(SUCCEEDED(hr));
782 hr = ID3D12Resource_Map(cxg->cb, 0, &read_range, (void **)&cxg->cb_data);
783 assert(SUCCEEDED(hr));
784 cxg_update_mvp(cxg);
786 resource_desc.Width = 3 * sizeof(*cxg->instance_data);
787 hr = ID3D12Device_CreateCommittedResource(cxg->device, &heap_desc, D3D12_HEAP_FLAG_NONE, &resource_desc,
788 D3D12_RESOURCE_STATE_GENERIC_READ, NULL, &IID_ID3D12Resource, (void **)&cxg->vb[1]);
789 assert(SUCCEEDED(hr));
791 hr = ID3D12Resource_Map(cxg->vb[1], 0, &read_range, (void **)&cxg->instance_data);
792 assert(SUCCEEDED(hr));
794 cxg->vbv[1].BufferLocation = ID3D12Resource_GetGPUVirtualAddress(cxg->vb[1]);
795 cxg->vbv[1].StrideInBytes = sizeof(*cxg->instance_data);
796 cxg->vbv[1].SizeInBytes = 3 * sizeof(*cxg->instance_data);
798 cxg_load_gears(cxg);
800 cxg_fence_create(&cxg->fence, cxg->device);
801 cxg_wait_for_previous_frame(cxg);
804 static void cxg_key_press(struct demo_window *window, demo_key key, void *user_data)
806 struct cx_gears *cxg = user_data;
808 switch (key)
810 case 'a':
811 case 'A':
812 cxg->animate = !cxg->animate;
813 break;
814 case DEMO_KEY_ESCAPE:
815 demo_window_destroy(window);
816 break;
817 case DEMO_KEY_LEFT:
818 cxg->theta += M_PI / 36.0f;
819 cxg_update_mvp(cxg);
820 break;
821 case DEMO_KEY_RIGHT:
822 cxg->theta -= M_PI / 36.0f;
823 cxg_update_mvp(cxg);
824 break;
825 case DEMO_KEY_UP:
826 cxg->phi += M_PI / 36.0f;
827 cxg_update_mvp(cxg);
828 break;
829 case DEMO_KEY_DOWN:
830 cxg->phi -= M_PI / 36.0f;
831 cxg_update_mvp(cxg);
832 break;
833 default:
834 break;
838 static void cxg_expose(struct demo_window *window, void *user_data)
840 cxg_render_frame(user_data);
843 static void cxg_idle(struct demo *demo, void *user_data)
845 cxg_render_frame(user_data);
848 static int cxg_main(void)
850 unsigned int width = 300, height = 300;
851 struct cx_gears cxg;
853 memset(&cxg, 0, sizeof(cxg));
854 if (!demo_init(&cxg.demo, &cxg))
855 return EXIT_FAILURE;
856 demo_set_idle_func(&cxg.demo, cxg_idle);
858 cxg.window = demo_window_create(&cxg.demo, "Vkd3d Gears", width, height, &cxg);
859 demo_window_set_key_press_func(cxg.window, cxg_key_press);
860 demo_window_set_expose_func(cxg.window, cxg_expose);
862 cxg.width = width;
863 cxg.height = height;
864 cxg.aspect_ratio = (float)width / (float)height;
866 cxg.animate = true;
867 cxg.theta = M_PI / 6.0f;
868 cxg.phi = M_PI / 9.0f;
870 cxg.vp.Width = width;
871 cxg.vp.Height = height;
872 cxg.vp.MaxDepth = 1.0f;
874 cxg.scissor_rect.right = width;
875 cxg.scissor_rect.bottom = height;
877 cxg_load_pipeline(&cxg);
878 cxg_load_assets(&cxg);
879 cxg_populate_command_list(&cxg, 0);
880 cxg_populate_command_list(&cxg, 1);
881 cxg_populate_command_list(&cxg, 2);
883 demo_process_events(&cxg.demo);
885 cxg_wait_for_previous_frame(&cxg);
886 cxg_destroy_assets(&cxg);
887 cxg_destroy_pipeline(&cxg);
888 demo_cleanup(&cxg.demo);
890 return EXIT_SUCCESS;
893 #ifdef _WIN32
894 /* Do not trigger -Wmissing-prototypes. */
895 int wmain(void);
897 int wmain(void)
898 #else
899 int main(void)
900 #endif
902 return cxg_main();