demos/triangle: Add a demo program.

This commit is contained in:
Henri Verbeet
2016-10-13 13:50:36 +02:00
parent 6cbe8626c2
commit fa5b972371
13 changed files with 1525 additions and 11 deletions

2
demos/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
triangle
*.spv

110
demos/demo.h Normal file
View File

@@ -0,0 +1,110 @@
/*
* Copyright 2016 Henri Verbeet for CodeWeavers
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/* Hack for MinGW-w64 headers.
*
* We want to use WIDL C inline wrappers because some methods
* in D3D12 interfaces return aggregate objects. Unfortunately,
* WIDL C inline wrappers are broken when used with MinGW-w64
* headers because FORCEINLINE expands to extern inline
* which leads to the "multiple storage classes in declaration
* specifiers" compiler error.
*/
#ifdef __MINGW32__
#include <_mingw.h>
# ifdef __MINGW64_VERSION_MAJOR
# undef __forceinline
# define __forceinline __inline__ __attribute__((__always_inline__,__gnu_inline__))
# endif
#endif
#include <vkd3d_windows.h>
#define WIDL_C_INLINE_WRAPPERS
#define COBJMACROS
#include <d3d12.h>
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
struct demo_vec3
{
float x, y, z;
};
struct demo_vec4
{
float x, y, z, w;
};
struct demo_swapchain_desc
{
unsigned int width;
unsigned int height;
unsigned int buffer_count;
DXGI_FORMAT format;
};
static inline void demo_rasterizer_desc_init_default(D3D12_RASTERIZER_DESC *desc)
{
desc->FillMode = D3D12_FILL_MODE_SOLID;
desc->CullMode = D3D12_CULL_MODE_BACK;
desc->FrontCounterClockwise = FALSE;
desc->DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
desc->DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
desc->SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
desc->DepthClipEnable = TRUE;
desc->MultisampleEnable = FALSE;
desc->AntialiasedLineEnable = FALSE;
desc->ForcedSampleCount = 0;
desc->ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
}
static inline void demo_blend_desc_init_default(D3D12_BLEND_DESC *desc)
{
static const D3D12_RENDER_TARGET_BLEND_DESC rt_blend_desc =
{
.BlendEnable = FALSE,
.LogicOpEnable = FALSE,
.SrcBlend = D3D12_BLEND_ONE,
.DestBlend = D3D12_BLEND_ZERO,
.BlendOp = D3D12_BLEND_OP_ADD,
.SrcBlendAlpha = D3D12_BLEND_ONE,
.DestBlendAlpha = D3D12_BLEND_ZERO,
.BlendOpAlpha = D3D12_BLEND_OP_ADD,
.LogicOp = D3D12_LOGIC_OP_NOOP,
.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL,
};
unsigned int i;
desc->AlphaToCoverageEnable = FALSE;
desc->IndependentBlendEnable = FALSE;
for (i = 0; i < ARRAY_SIZE(desc->RenderTarget); ++i)
{
desc->RenderTarget[i] = rt_blend_desc;
}
}
#ifdef _WIN32
#include "demo_win32.h"
#else
#include <vkd3d_utils.h>
#include "demo_xcb.h"
#endif

302
demos/demo_win32.h Normal file
View File

@@ -0,0 +1,302 @@
/*
* Copyright 2016 Józef Kucia for CodeWeavers
* Copyright 2016 Henri Verbeet for CodeWeavers
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <dxgi1_4.h>
#include <stdbool.h>
#define DEMO_WINDOW_CLASS_NAME L"demo_wc"
struct demo
{
HMODULE d3dcompiler;
HRESULT (WINAPI *compile_from_file)(const WCHAR *filename, const void *defines, void *include,
const char *entry_point, const char *profile, UINT flags1, UINT flags2,
ID3DBlob **code, ID3DBlob **errors);
size_t window_count;
bool quit;
};
struct demo_window
{
HINSTANCE instance;
HWND hwnd;
struct demo *demo;
void *user_data;
void (*draw_func)(void *user_data);
};
struct demo_swapchain
{
IDXGISwapChain3 *swapchain;
};
static inline struct demo_window *demo_window_create(struct demo *demo, const char *title,
unsigned int width, unsigned int height, void (*draw_func)(void *user_data), void *user_data)
{
RECT rect = {0, 0, width, height};
struct demo_window *window;
int title_size;
WCHAR *title_w;
DWORD style;
if (!(window = malloc(sizeof(*window))))
return NULL;
title_size = MultiByteToWideChar(CP_UTF8, 0, title, -1, NULL, 0);
if (!(title_w = calloc(title_size, sizeof(*title_w))))
{
free(window);
return NULL;
}
MultiByteToWideChar(CP_UTF8, 0, title, -1, title_w, title_size);
window->instance = GetModuleHandle(NULL);
window->draw_func = draw_func;
window->user_data = user_data;
style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE;
AdjustWindowRect(&rect, style, FALSE);
window->hwnd = CreateWindowExW(0, DEMO_WINDOW_CLASS_NAME, title_w, style, CW_USEDEFAULT, CW_USEDEFAULT,
rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, window->instance, NULL);
free(title_w);
if (!window->hwnd)
{
free(window);
return NULL;
}
SetWindowLongPtrW(window->hwnd, GWLP_USERDATA, (LONG_PTR)window);
window->demo = demo;
++demo->window_count;
return window;
}
static inline void demo_window_destroy(struct demo_window *window)
{
if (window->hwnd)
DestroyWindow(window->hwnd);
if (!--window->demo->window_count)
window->demo->quit = true;
free(window);
}
static inline LRESULT CALLBACK demo_window_proc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
struct demo_window *window = (void *)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
switch (message)
{
case WM_PAINT:
if (window && window->draw_func)
window->draw_func(window->user_data);
return 0;
case WM_DESTROY:
window->hwnd = NULL;
demo_window_destroy(window);
return 0;
}
return DefWindowProcW(hwnd, message, wparam, lparam);
}
static inline void demo_process_events(struct demo *demo)
{
MSG msg = {0};
while (GetMessage(&msg, NULL, 0, 0) != -1)
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessageW(&msg);
if (demo->quit)
PostQuitMessage(0);
}
}
static inline bool demo_init(struct demo *demo)
{
WNDCLASSEXW wc;
if (!(demo->d3dcompiler = LoadLibraryW(L"d3dcompiler_47")))
return false;
if (!(demo->compile_from_file = (void *)GetProcAddress(demo->d3dcompiler, "D3DCompileFromFile")))
goto fail;
wc.cbSize = sizeof(wc);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = demo_window_proc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetModuleHandle(NULL);
wc.hIcon = LoadIconW(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = DEMO_WINDOW_CLASS_NAME;
wc.hIconSm = LoadIconW(NULL, IDI_WINLOGO);
if (!RegisterClassExW(&wc))
goto fail;
demo->quit = false;
return true;
fail:
FreeLibrary(demo->d3dcompiler);
return false;
}
static inline void demo_cleanup(struct demo *demo)
{
UnregisterClassW(DEMO_WINDOW_CLASS_NAME, GetModuleHandle(NULL));
FreeLibrary(demo->d3dcompiler);
}
static inline struct demo_swapchain *demo_swapchain_create(ID3D12CommandQueue *command_queue,
struct demo_window *window, const struct demo_swapchain_desc *desc)
{
DXGI_SWAP_CHAIN_DESC1 swapchain_desc;
struct demo_swapchain *swapchain;
IDXGISwapChain1 *swapchain1;
IDXGIFactory2 *factory;
HRESULT hr;
if (!(swapchain = malloc(sizeof(*swapchain))))
return NULL;
if (FAILED(CreateDXGIFactory1(&IID_IDXGIFactory2, (void **)&factory)))
goto fail;
memset(&swapchain_desc, 0, sizeof(swapchain_desc));
swapchain_desc.BufferCount = desc->buffer_count;
swapchain_desc.Width = desc->width;
swapchain_desc.Height = desc->height;
swapchain_desc.Format = desc->format;
swapchain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapchain_desc.SampleDesc.Count = 1;
hr = IDXGIFactory2_CreateSwapChainForHwnd(factory, (IUnknown *)command_queue,
window->hwnd, &swapchain_desc, NULL, NULL, &swapchain1);
IDXGIFactory2_Release(factory);
if (FAILED(hr))
goto fail;
hr = IDXGISwapChain1_QueryInterface(swapchain1, &IID_IDXGISwapChain3, (void **)&swapchain->swapchain);
IDXGISwapChain1_Release(swapchain1);
if (FAILED(hr))
goto fail;
return swapchain;
fail:
free(swapchain);
return NULL;
}
static inline unsigned int demo_swapchain_get_current_back_buffer_index(struct demo_swapchain *swapchain)
{
return IDXGISwapChain3_GetCurrentBackBufferIndex(swapchain->swapchain);
}
static inline ID3D12Resource *demo_swapchain_get_back_buffer(struct demo_swapchain *swapchain, unsigned int index)
{
ID3D12Resource *buffer;
if (FAILED(IDXGISwapChain3_GetBuffer(swapchain->swapchain, index,
&IID_ID3D12Resource, (void **)&buffer)))
return NULL;
return buffer;
}
static inline void demo_swapchain_present(struct demo_swapchain *swapchain)
{
IDXGISwapChain3_Present(swapchain->swapchain, 1, 0);
}
static inline void demo_swapchain_destroy(struct demo_swapchain *swapchain)
{
IDXGISwapChain3_Release(swapchain->swapchain);
free(swapchain);
}
static inline HANDLE demo_create_event(void)
{
return CreateEventA(NULL, FALSE, FALSE, NULL);
}
static inline unsigned int demo_wait_event(HANDLE event, unsigned int ms)
{
return WaitForSingleObject(event, ms);
}
static inline void demo_destroy_event(HANDLE event)
{
CloseHandle(event);
}
static inline HRESULT demo_create_root_signature(ID3D12Device *device,
const D3D12_ROOT_SIGNATURE_DESC *desc, ID3D12RootSignature **signature)
{
ID3DBlob *blob;
HRESULT hr;
if (FAILED(hr = D3D12SerializeRootSignature(desc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, NULL)))
return hr;
hr = ID3D12Device_CreateRootSignature(device, 0, ID3D10Blob_GetBufferPointer(blob),
ID3D10Blob_GetBufferSize(blob), &IID_ID3D12RootSignature, (void **)signature);
ID3D10Blob_Release(blob);
return hr;
}
static inline bool demo_load_shader(struct demo *demo, const wchar_t *hlsl_name, const char *entry_point,
const char *profile, const char *spv_name, D3D12_SHADER_BYTECODE *shader)
{
ID3D10Blob *blob, *errors;
HRESULT hr;
hr = demo->compile_from_file(hlsl_name, NULL, NULL, entry_point, profile, 0, 0, &blob, &errors);
if (errors)
{
fprintf(stderr, "%.*s\n", (int)ID3D10Blob_GetBufferSize(errors), (char *)ID3D10Blob_GetBufferPointer(errors));
ID3D10Blob_Release(errors);
}
if (FAILED(hr))
return false;
shader->BytecodeLength = ID3D10Blob_GetBufferSize(blob);
if (!(shader->pShaderBytecode = malloc(shader->BytecodeLength)))
{
ID3D10Blob_Release(blob);
return false;
}
memcpy((void *)shader->pShaderBytecode, ID3D10Blob_GetBufferPointer(blob), shader->BytecodeLength);
ID3D10Blob_Release(blob);
return true;
}

543
demos/demo_xcb.h Normal file

File diff suppressed because it is too large Load Diff

410
demos/triangle.c Normal file
View File

@@ -0,0 +1,410 @@
/*
* Copyright 2016 Henri Verbeet for CodeWeavers
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
/*
* This application contains code derived from Microsoft's "HelloTriangle"
* demo, the license for which follows:
*
* Copyright (c) 2015 Microsoft
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#define INITGUID
#include <limits.h>
#include <assert.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include "demo.h"
struct cxt_fence
{
ID3D12Fence *fence;
UINT64 value;
HANDLE event;
};
struct cx_triangle
{
struct demo demo;
struct demo_window *window;
unsigned int width;
unsigned int height;
float aspect_ratio;
D3D12_VIEWPORT vp;
D3D12_RECT scissor_rect;
ID3D12Device *device;
ID3D12CommandQueue *command_queue;
struct demo_swapchain *swapchain;
ID3D12DescriptorHeap *rtv_heap;
unsigned int rtv_descriptor_size;
ID3D12Resource *render_targets[2];
ID3D12CommandAllocator *command_allocator;
ID3D12RootSignature *root_signature;
ID3D12PipelineState *pipeline_state;
ID3D12GraphicsCommandList *command_list;
ID3D12Resource *vb;
D3D12_VERTEX_BUFFER_VIEW vbv;
unsigned int frame_idx;
struct cxt_fence fence;
};
static void cxt_populate_command_list(struct cx_triangle *cxt)
{
static const float clear_colour[] = {0.0f, 0.2f, 0.4f, 1.0f};
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle;
D3D12_RESOURCE_BARRIER barrier;
HRESULT hr;
hr = ID3D12CommandAllocator_Reset(cxt->command_allocator);
assert(SUCCEEDED(hr));
hr = ID3D12GraphicsCommandList_Reset(cxt->command_list, cxt->command_allocator, cxt->pipeline_state);
assert(SUCCEEDED(hr));
ID3D12GraphicsCommandList_SetGraphicsRootSignature(cxt->command_list, cxt->root_signature);
ID3D12GraphicsCommandList_RSSetViewports(cxt->command_list, 1, &cxt->vp);
ID3D12GraphicsCommandList_RSSetScissorRects(cxt->command_list, 1, &cxt->scissor_rect);
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource = cxt->render_targets[cxt->frame_idx];
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
ID3D12GraphicsCommandList_ResourceBarrier(cxt->command_list, 1, &barrier);
rtv_handle = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(cxt->rtv_heap);
rtv_handle.ptr += cxt->frame_idx * cxt->rtv_descriptor_size;
ID3D12GraphicsCommandList_OMSetRenderTargets(cxt->command_list, 1, &rtv_handle, FALSE, NULL);
ID3D12GraphicsCommandList_ClearRenderTargetView(cxt->command_list, rtv_handle, clear_colour, 0, NULL);
ID3D12GraphicsCommandList_IASetPrimitiveTopology(cxt->command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D12GraphicsCommandList_IASetVertexBuffers(cxt->command_list, 0, 1, &cxt->vbv);
ID3D12GraphicsCommandList_DrawInstanced(cxt->command_list, 3, 1, 0, 0);
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
ID3D12GraphicsCommandList_ResourceBarrier(cxt->command_list, 1, &barrier);
hr = ID3D12GraphicsCommandList_Close(cxt->command_list);
assert(SUCCEEDED(hr));
}
static void cxt_wait_for_previous_frame(struct cx_triangle *cxt)
{
struct cxt_fence *fence = &cxt->fence;
const UINT64 v = fence->value;
HRESULT hr;
hr = ID3D12CommandQueue_Signal(cxt->command_queue, fence->fence, v);
assert(SUCCEEDED(hr));
++fence->value;
if (ID3D12Fence_GetCompletedValue(fence->fence) < v)
{
ID3D12Fence_SetEventOnCompletion(fence->fence, v, fence->event);
demo_wait_event(fence->event, INFINITE);
}
cxt->frame_idx = demo_swapchain_get_current_back_buffer_index(cxt->swapchain);
}
static void cxt_render_frame(void *user_data)
{
struct cx_triangle *cxt = user_data;
cxt_populate_command_list(cxt);
ID3D12CommandQueue_ExecuteCommandLists(cxt->command_queue, 1, (ID3D12CommandList **)&cxt->command_list);
demo_swapchain_present(cxt->swapchain);
cxt_wait_for_previous_frame(cxt);
}
static void cxt_destroy_pipeline(struct cx_triangle *cxt)
{
unsigned int i;
ID3D12CommandAllocator_Release(cxt->command_allocator);
for (i = 0; i < ARRAY_SIZE(cxt->render_targets); ++i)
{
ID3D12Resource_Release(cxt->render_targets[i]);
}
ID3D12DescriptorHeap_Release(cxt->rtv_heap);
demo_swapchain_destroy(cxt->swapchain);
ID3D12CommandQueue_Release(cxt->command_queue);
ID3D12Device_Release(cxt->device);
}
static void cxt_load_pipeline(struct cx_triangle *cxt)
{
struct demo_swapchain_desc swapchain_desc;
D3D12_DESCRIPTOR_HEAP_DESC rtv_heap_desc;
D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle;
D3D12_COMMAND_QUEUE_DESC queue_desc;
unsigned int i;
HRESULT hr;
hr = D3D12CreateDevice(NULL, D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, (void **)&cxt->device);
assert(SUCCEEDED(hr));
memset(&queue_desc, 0, sizeof(queue_desc));
queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
hr = ID3D12Device_CreateCommandQueue(cxt->device, &queue_desc,
&IID_ID3D12CommandQueue, (void **)&cxt->command_queue);
assert(SUCCEEDED(hr));
swapchain_desc.buffer_count = ARRAY_SIZE(cxt->render_targets);
swapchain_desc.format = DXGI_FORMAT_B8G8R8A8_UNORM;
swapchain_desc.width = cxt->width;
swapchain_desc.height = cxt->height;
cxt->swapchain = demo_swapchain_create(cxt->command_queue, cxt->window, &swapchain_desc);
assert(cxt->swapchain);
cxt->frame_idx = demo_swapchain_get_current_back_buffer_index(cxt->swapchain);
memset(&rtv_heap_desc, 0, sizeof(rtv_heap_desc));
rtv_heap_desc.NumDescriptors = ARRAY_SIZE(cxt->render_targets);
rtv_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
rtv_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
hr = ID3D12Device_CreateDescriptorHeap(cxt->device, &rtv_heap_desc,
&IID_ID3D12DescriptorHeap, (void **)&cxt->rtv_heap);
assert(SUCCEEDED(hr));
cxt->rtv_descriptor_size = ID3D12Device_GetDescriptorHandleIncrementSize(cxt->device,
D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
rtv_handle = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(cxt->rtv_heap);
for (i = 0; i < ARRAY_SIZE(cxt->render_targets); ++i)
{
cxt->render_targets[i] = demo_swapchain_get_back_buffer(cxt->swapchain, i);
ID3D12Device_CreateRenderTargetView(cxt->device, cxt->render_targets[i], NULL, rtv_handle);
rtv_handle.ptr += cxt->rtv_descriptor_size;
}
hr = ID3D12Device_CreateCommandAllocator(cxt->device, D3D12_COMMAND_LIST_TYPE_DIRECT,
&IID_ID3D12CommandAllocator, (void **)&cxt->command_allocator);
assert(SUCCEEDED(hr));
}
static void cxt_fence_destroy(struct cxt_fence *cxt_fence)
{
ID3D12Fence_Release(cxt_fence->fence);
demo_destroy_event(cxt_fence->event);
}
static void cxt_destroy_assets(struct cx_triangle *cxt)
{
cxt_fence_destroy(&cxt->fence);
ID3D12Resource_Release(cxt->vb);
ID3D12GraphicsCommandList_Release(cxt->command_list);
ID3D12PipelineState_Release(cxt->pipeline_state);
ID3D12RootSignature_Release(cxt->root_signature);
}
static void cxt_load_shaders(struct cx_triangle *cxt, D3D12_SHADER_BYTECODE *vs, D3D12_SHADER_BYTECODE *ps)
{
bool ret;
ret = demo_load_shader(&cxt->demo, L"triangle.hlsl", "vs_main", "vs_5_0", "triangle.vert.spv", vs);
assert(ret);
ret = demo_load_shader(&cxt->demo, L"triangle.hlsl", "ps_main", "ps_5_0", "triangle.frag.spv", ps);
assert(ret);
}
static void cxt_fence_create(struct cxt_fence *fence, ID3D12Device *device)
{
HRESULT hr;
hr = ID3D12Device_CreateFence(device, 0, D3D12_FENCE_FLAG_NONE,
&IID_ID3D12Fence, (void **)&fence->fence);
assert(SUCCEEDED(hr));
fence->value = 1;
fence->event = demo_create_event();
assert(fence->event);
}
static void cxt_load_assets(struct cx_triangle *cxt)
{
static const D3D12_INPUT_ELEMENT_DESC il_desc[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
};
const struct
{
struct demo_vec3 position;
struct demo_vec4 colour;
}
vertices[] =
{
{{ 0.0f, 0.25f * cxt->aspect_ratio, 0.0f}, {1.0f, 0.0f, 0.0f, 1.0f}},
{{ 0.25f, -0.25f * cxt->aspect_ratio, 0.0f}, {0.0f, 1.0f, 0.0f, 1.0f}},
{{-0.25f, -0.25f * cxt->aspect_ratio, 0.0f}, {0.0f, 0.0f, 1.0f, 1.0f}},
};
D3D12_ROOT_SIGNATURE_DESC root_signature_desc;
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc;
D3D12_RESOURCE_DESC resource_desc;
D3D12_HEAP_PROPERTIES heap_desc;
D3D12_RANGE read_range = {0, 0};
HRESULT hr;
void *data;
memset(&root_signature_desc, 0, sizeof(root_signature_desc));
root_signature_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
hr = demo_create_root_signature(cxt->device, &root_signature_desc, &cxt->root_signature);
assert(SUCCEEDED(hr));
memset(&pso_desc, 0, sizeof(pso_desc));
pso_desc.InputLayout.pInputElementDescs = il_desc;
pso_desc.InputLayout.NumElements = ARRAY_SIZE(il_desc);
pso_desc.pRootSignature = cxt->root_signature;
cxt_load_shaders(cxt, &pso_desc.VS, &pso_desc.PS);
demo_rasterizer_desc_init_default(&pso_desc.RasterizerState);
demo_blend_desc_init_default(&pso_desc.BlendState);
pso_desc.DepthStencilState.DepthEnable = FALSE;
pso_desc.DepthStencilState.StencilEnable = FALSE;
pso_desc.SampleMask = UINT_MAX;
pso_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
pso_desc.NumRenderTargets = 1;
pso_desc.RTVFormats[0] = DXGI_FORMAT_B8G8R8A8_UNORM;
pso_desc.SampleDesc.Count = 1;
hr = ID3D12Device_CreateGraphicsPipelineState(cxt->device, &pso_desc,
&IID_ID3D12PipelineState, (void **)&cxt->pipeline_state);
assert(SUCCEEDED(hr));
free((void *)pso_desc.PS.pShaderBytecode);
free((void *)pso_desc.VS.pShaderBytecode);
hr = ID3D12Device_CreateCommandList(cxt->device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT, cxt->command_allocator,
cxt->pipeline_state, &IID_ID3D12GraphicsCommandList, (void **)&cxt->command_list);
assert(SUCCEEDED(hr));
hr = ID3D12GraphicsCommandList_Close(cxt->command_list);
assert(SUCCEEDED(hr));
heap_desc.Type = D3D12_HEAP_TYPE_UPLOAD;
heap_desc.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heap_desc.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
heap_desc.CreationNodeMask = 1;
heap_desc.VisibleNodeMask = 1;
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
resource_desc.Alignment = 0;
resource_desc.Width = sizeof(vertices);
resource_desc.Height = 1;
resource_desc.DepthOrArraySize = 1;
resource_desc.MipLevels = 1;
resource_desc.Format = DXGI_FORMAT_UNKNOWN;
resource_desc.SampleDesc.Count = 1;
resource_desc.SampleDesc.Quality = 0;
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
resource_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
hr = ID3D12Device_CreateCommittedResource(cxt->device, &heap_desc, D3D12_HEAP_FLAG_NONE, &resource_desc,
D3D12_RESOURCE_STATE_GENERIC_READ, NULL, &IID_ID3D12Resource, (void **)&cxt->vb);
assert(SUCCEEDED(hr));
hr = ID3D12Resource_Map(cxt->vb, 0, &read_range, &data);
assert(SUCCEEDED(hr));
memcpy(data, vertices, sizeof(vertices));
ID3D12Resource_Unmap(cxt->vb, 0, NULL);
cxt->vbv.BufferLocation = ID3D12Resource_GetGPUVirtualAddress(cxt->vb);
cxt->vbv.StrideInBytes = sizeof(*vertices);
cxt->vbv.SizeInBytes = sizeof(vertices);
cxt_fence_create(&cxt->fence, cxt->device);
cxt_wait_for_previous_frame(cxt);
}
static int cxt_main(void)
{
unsigned int width = 640, height = 480;
struct cx_triangle cxt;
memset(&cxt, 0, sizeof(cxt));
if (!demo_init(&cxt.demo))
return EXIT_FAILURE;
cxt.window = demo_window_create(&cxt.demo, "Vkd3d Triangle",
width, height, cxt_render_frame, &cxt);
cxt.width = width;
cxt.height = height;
cxt.aspect_ratio = (float)width / (float)height;
cxt.vp.Width = (float)width;
cxt.vp.Height = (float)height;
cxt.vp.MaxDepth = 1.0f;
cxt.scissor_rect.right = width;
cxt.scissor_rect.bottom = height;
cxt_load_pipeline(&cxt);
cxt_load_assets(&cxt);
demo_process_events(&cxt.demo);
cxt_wait_for_previous_frame(&cxt);
cxt_destroy_assets(&cxt);
cxt_destroy_pipeline(&cxt);
demo_cleanup(&cxt.demo);
return EXIT_SUCCESS;
}
#ifdef _WIN32
int wmain(void)
#else
int main(void)
#endif
{
return cxt_main();
}

10
demos/triangle.frag Normal file
View File

@@ -0,0 +1,10 @@
#version 150
#extension GL_ARB_separate_shader_objects : enable
layout(location = 0) in vec4 colour_in;
layout(location = 0) out vec4 colour_out;
void main(void)
{
colour_out = colour_in;
}

20
demos/triangle.hlsl Normal file
View File

@@ -0,0 +1,20 @@
struct ps_in
{
float4 position : SV_POSITION;
float4 colour : COLOR;
};
struct ps_in vs_main(float4 position : POSITION, float4 colour : COLOR)
{
struct ps_in o;
o.position = position;
o.colour = colour;
return o;
}
float4 ps_main(struct ps_in i) : SV_TARGET
{
return i.colour;
}

14
demos/triangle.vert Normal file
View File

@@ -0,0 +1,14 @@
#version 150
#extension GL_ARB_separate_shader_objects : enable
layout(location = 0) in vec4 position_in;
layout(location = 1) in vec4 colour_in;
layout(location = 0) out vec4 colour_out;
void main(void)
{
gl_Position.xzw = position_in.xzw;
gl_Position.y = -position_in.y;
colour_out = colour_in;
}