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
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.
51 DEMO_EMBED(gears_hlsl
, "gears.hlsl");
63 float normal_matrix
[12];
66 struct cxg_instance_data
68 struct demo_vec3 diffuse
;
69 struct demo_vec4 transform
;
74 struct demo_vec3 position
;
75 struct demo_vec3 normal
;
85 struct cxg_vertex
*vertices
;
88 struct cxg_face
*faces
;
89 size_t flat_face_count
;
90 size_t smooth_face_count
;
96 size_t flat_index_idx
;
97 size_t flat_index_count
;
98 size_t smooth_index_idx
;
99 size_t smooth_index_count
;
106 struct demo_window
*window
;
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
;
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
;
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
;
212 hr
= ID3D12CommandQueue_Signal(cxg
->command_queue
, fence
->fence
, v
);
213 assert(SUCCEEDED(hr
));
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
;
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
);
243 c1
, s2
* s1
, c2
* -s1
, 0.0f
,
245 s1
, -s2
* c1
, c2
* c1
, 0.0f
,
246 0.0f
, 0.0f
, z_offset
, 1.0f
,
250 sx
, 0.0f
, 0.0f
, 0.0f
,
251 0.0f
, sy
, 0.0f
, 0.0f
,
252 0.0f
, 0.0f
, sz
, -1.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;
276 gettimeofday(&tv
, NULL
);
277 t
= tv
.tv_sec
+ tv
.tv_usec
/ 1000000.0;
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
;
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
)
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
;
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
)
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
)
411 hr
= ID3D12Device_CreateFence(device
, 0, D3D12_FENCE_FLAG_NONE
,
412 &IID_ID3D12Fence
, (void **)&fence
->fence
);
413 assert(SUCCEEDED(hr
));
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
;
438 if (!(vertices
= calloc(tooth_count
, 12 * sizeof(*vertices
))))
440 if (!(faces
= calloc(tooth_count
, 20 * sizeof(*faces
))))
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];
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
[] =
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
[] =
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
;
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
)
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
;
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
)
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
));
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
;
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
));
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
);
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
;
812 cxg
->animate
= !cxg
->animate
;
814 case DEMO_KEY_ESCAPE
:
815 demo_window_destroy(window
);
818 cxg
->theta
+= M_PI
/ 36.0f
;
822 cxg
->theta
-= M_PI
/ 36.0f
;
826 cxg
->phi
+= M_PI
/ 36.0f
;
830 cxg
->phi
-= M_PI
/ 36.0f
;
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;
853 memset(&cxg
, 0, sizeof(cxg
));
854 if (!demo_init(&cxg
.demo
, &cxg
))
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
);
864 cxg
.aspect_ratio
= (float)width
/ (float)height
;
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
);
894 /* Do not trigger -Wmissing-prototypes. */