浏览代码

Merge pull request #412 from Ohjurot/d3d12_backend

backend: add D3D12
dumblob 3 年之前
父节点
当前提交
10ecc825cc

+ 9 - 0
demo/d3d12/build.bat

@@ -0,0 +1,9 @@
+@echo off
+
+rem This will use VS2015 for compiler... if you have vs 2015 and it is installed at this / the default path
+call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86
+
+fxc.exe /nologo /T vs_5_1 /E vs /O3 /Zpc /Ges /Fh nuklear_d3d12_vertex_shader.h /Vn nk_d3d12_vertex_shader /Qstrip_reflect /Qstrip_debug /Qstrip_priv nuklear_d3d12.hlsl
+fxc.exe /nologo /T ps_5_1 /E ps /O3 /Zpc /Ges /Fh nuklear_d3d12_pixel_shader.h /Vn nk_d3d12_pixel_shader /Qstrip_reflect /Qstrip_debug /Qstrip_priv /enable_unbounded_descriptor_tables nuklear_d3d12.hlsl
+
+cl /D_CRT_SECURE_NO_DEPRECATE /nologo /W3 /O2 /fp:fast /Gm- /Fedemo.exe main.c user32.lib dxguid.lib dxgi.lib d3d12.lib /link /incremental:no

+ 439 - 0
demo/d3d12/main.c

@@ -0,0 +1,439 @@
+/* nuklear - 1.32.0 - public domain */
+#define COBJMACROS
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <combaseapi.h>
+#include <dxgi1_6.h>
+#include <d3d12.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <time.h>
+
+#define WINDOW_WIDTH 800
+#define WINDOW_HEIGHT 600
+#define USER_TEXTURES 6
+
+#define MAX_VERTEX_BUFFER 512 * 1024
+#define MAX_INDEX_BUFFER 128 * 1024
+
+#define NK_INCLUDE_FIXED_TYPES
+#define NK_INCLUDE_STANDARD_IO
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_DEFAULT_ALLOCATOR
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+#define NK_IMPLEMENTATION
+#define NK_D3D12_IMPLEMENTATION
+#include "../../nuklear.h"
+#include "nuklear_d3d12.h"
+
+/* ===============================================================
+ *
+ *                          EXAMPLE
+ *
+ * ===============================================================*/
+/* This are some code examples to provide a small overview of what can be
+ * done with this library. To try out an example uncomment the defines */
+/*#define INCLUDE_ALL */
+/*#define INCLUDE_STYLE */
+/*#define INCLUDE_CALCULATOR */
+/*#define INCLUDE_CANVAS */
+/*#define INCLUDE_OVERVIEW */
+/*#define INCLUDE_NODE_EDITOR */
+
+#ifdef INCLUDE_ALL
+  #define INCLUDE_STYLE
+  #define INCLUDE_CALCULATOR
+  #define INCLUDE_CANVAS
+  #define INCLUDE_OVERVIEW
+  #define INCLUDE_NODE_EDITOR
+#endif
+
+#ifdef INCLUDE_STYLE
+  #include "../style.c"
+#endif
+#ifdef INCLUDE_CALCULATOR
+  #include "../calculator.c"
+#endif
+#ifdef INCLUDE_CANVAS
+  #include "../canvas.c"
+#endif
+#ifdef INCLUDE_OVERVIEW
+  #include "../overview.c"
+#endif
+#ifdef INCLUDE_NODE_EDITOR
+  #include "../node_editor.c"
+#endif
+
+/* ===============================================================
+ *
+ *                          DEMO
+ *
+ * ===============================================================*/
+/* DXGI & Window related device objects */
+static IDXGIFactory2 *dxgi_factory;
+static IDXGISwapChain1 *swap_chain;
+static ID3D12DescriptorHeap *rtv_descriptor_heap;
+static D3D12_CPU_DESCRIPTOR_HANDLE rtv_handles[2];
+static ID3D12Resource *rtv_buffers[2];
+static UINT rtv_desc_increment;
+static UINT rtv_index;
+/* DirectX common device objects */
+static ID3D12Device *device;
+static ID3D12CommandQueue *command_queue;
+static ID3D12Fence *queue_fence;
+static UINT64 fence_value;
+static ID3D12CommandAllocator *command_allocator;
+static ID3D12GraphicsCommandList *command_list;
+
+static void signal_and_wait()
+{
+    HRESULT hr;
+
+    /* Signal fence when execution finishes */
+    hr = ID3D12CommandQueue_Signal(command_queue, queue_fence, ++fence_value);
+    assert(SUCCEEDED(hr));
+
+    /* Wait for queue to finish */
+    while(ID3D12Fence_GetCompletedValue(queue_fence) != fence_value)
+    {
+      SwitchToThread(); /* Allow windows to do other work */
+    }
+}
+
+static void execute_commands()
+{
+    /* Prepare command list for execution */
+    ID3D12GraphicsCommandList_Close(command_list);
+
+    /* Execute on command queue */
+    ID3D12CommandList* cmd_lists[] = { (ID3D12CommandList*)command_list};
+    ID3D12CommandQueue_ExecuteCommandLists(command_queue, 1, cmd_lists);
+
+    /* Wait for execution */
+    signal_and_wait();
+
+    /* Reset command allocator and list */
+    ID3D12CommandAllocator_Reset(command_allocator);
+    ID3D12GraphicsCommandList_Reset(command_list, command_allocator, NULL);
+}
+
+static void get_swap_chain_buffers()
+{
+    HRESULT hr;
+    D3D12_CPU_DESCRIPTOR_HANDLE descriptor_handle;
+
+    /* Get resource objects from swap chain */
+    hr = IDXGISwapChain1_GetBuffer(swap_chain, 0, &IID_ID3D12Resource, &rtv_buffers[0]);
+    assert(SUCCEEDED(hr));
+    hr = IDXGISwapChain1_GetBuffer(swap_chain, 1, &IID_ID3D12Resource, &rtv_buffers[1]);
+    assert(SUCCEEDED(hr));
+
+    /* Recreate render target views */
+    ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(rtv_descriptor_heap, &descriptor_handle);
+    ID3D12Device_CreateRenderTargetView(device, rtv_buffers[0], NULL, descriptor_handle);
+    rtv_handles[0] = descriptor_handle;
+    descriptor_handle.ptr += rtv_desc_increment;
+    ID3D12Device_CreateRenderTargetView(device, rtv_buffers[1], NULL, descriptor_handle);
+    rtv_handles[1] = descriptor_handle;
+}
+
+static void
+set_swap_chain_size(int width, int height)
+{
+    HRESULT hr;
+
+    /* Wait for pending work */
+    signal_and_wait();
+    signal_and_wait(); /* Two times because we have two buffers in flight */
+
+    /* Release all open refereces to the buffers */
+    ID3D12Resource_Release(rtv_buffers[0]);
+    ID3D12Resource_Release(rtv_buffers[1]);
+
+    /* DXGI can now perform resizing */
+    hr = IDXGISwapChain1_ResizeBuffers(swap_chain, 2, width, height, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);
+    assert(SUCCEEDED(hr));
+
+    /* Get references for the new resized buffers */
+    get_swap_chain_buffers();
+
+    /* Reset RTV index */
+    rtv_index = 0;
+}
+
+static LRESULT CALLBACK
+WindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    switch (msg)
+    {
+    case WM_DESTROY:
+        PostQuitMessage(0);
+        return 0;
+
+    case WM_SIZE:
+        if (swap_chain)
+        {
+            int width = LOWORD(lparam);
+            int height = HIWORD(lparam);
+            set_swap_chain_size(width, height);
+            nk_d3d12_resize(width, height);
+        }
+        break;
+    }
+
+    if (nk_d3d12_handle_event(wnd, msg, wparam, lparam))
+        return 0;
+
+    return DefWindowProcW(wnd, msg, wparam, lparam);
+}
+
+int main(void)
+{  
+    struct nk_context *ctx;
+    struct nk_colorf bg;
+
+    WNDCLASSW wc;
+    RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
+    DWORD style = WS_OVERLAPPEDWINDOW;
+    DWORD exstyle = WS_EX_APPWINDOW;
+    HWND wnd;
+    int running = 1;
+    HRESULT hr;
+
+    D3D12_COMMAND_QUEUE_DESC command_queue_desc;
+    DXGI_SWAP_CHAIN_DESC1 swap_chain_desc;
+    D3D12_DESCRIPTOR_HEAP_DESC rtv_desc_heap_desc;
+
+    /* Win32 */
+    memset(&wc, 0, sizeof(wc));
+    wc.style = CS_DBLCLKS;
+    wc.lpfnWndProc = WindowProc;
+    wc.hInstance = GetModuleHandleW(0);
+    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+    wc.lpszClassName = L"NuklearWindowClass";
+    RegisterClassW(&wc);
+
+    AdjustWindowRectEx(&rect, style, FALSE, exstyle);
+
+    wnd = CreateWindowExW(exstyle, wc.lpszClassName, L"Nuklear Demo",
+        style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
+        rect.right - rect.left, rect.bottom - rect.top,
+        NULL, NULL, wc.hInstance, NULL);
+
+    /* D3D12 setup */
+    /* Create default Device */
+    hr = D3D12CreateDevice(NULL, D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, &device);
+    assert(SUCCEEDED(hr));
+    /* Create a command queue */
+    command_queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
+    command_queue_desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
+    command_queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
+    command_queue_desc.NodeMask = 0;
+    hr = ID3D12Device_CreateCommandQueue(device, &command_queue_desc, &IID_ID3D12CommandQueue, &command_queue);
+    assert(SUCCEEDED(hr));
+    /* Create a fence for command queue executions */
+    fence_value = 0;
+    hr = ID3D12Device_CreateFence(device, fence_value, D3D12_FENCE_FLAG_NONE, &IID_ID3D12Fence, &queue_fence);
+    assert(SUCCEEDED(hr));
+    /* Create a command allocator */
+    hr = ID3D12Device_CreateCommandAllocator(device, D3D12_COMMAND_LIST_TYPE_DIRECT, &IID_ID3D12CommandAllocator, &command_allocator);
+    assert(SUCCEEDED(hr));
+    /* Create a command list that will use our allocator */
+    hr = ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT, command_allocator, NULL,  &IID_ID3D12GraphicsCommandList1, &command_list);
+    assert(SUCCEEDED(hr));
+
+    /* DXGI Setup (Swap chain & resources) */
+    /* Create a descriptor heap for the back buffers */
+    rtv_desc_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
+    rtv_desc_heap_desc.NumDescriptors = 2;
+    rtv_desc_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
+    rtv_desc_heap_desc.NodeMask = 0;
+    hr = ID3D12Device_CreateDescriptorHeap(device, &rtv_desc_heap_desc, &IID_ID3D12DescriptorHeap, &rtv_descriptor_heap);
+    assert(SUCCEEDED(hr));
+    /* Get descriptor increment */
+    rtv_desc_increment = ID3D12Device_GetDescriptorHandleIncrementSize(device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
+    /* Get the DXGI factory */
+    hr = CreateDXGIFactory1(&IID_IDXGIFactory2, &dxgi_factory);
+    assert(SUCCEEDED(hr));
+    /* Create the swap chain */
+    swap_chain_desc.Width = WINDOW_WIDTH;
+    swap_chain_desc.Height = WINDOW_HEIGHT;
+    swap_chain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+    swap_chain_desc.Stereo = 0;
+    swap_chain_desc.SampleDesc.Count = 1;
+    swap_chain_desc.SampleDesc.Quality = 0;
+    swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+    swap_chain_desc.BufferCount = 2;
+    swap_chain_desc.Scaling = DXGI_SCALING_STRETCH;
+    swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL ;
+    swap_chain_desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
+    swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
+    hr = IDXGIFactory2_CreateSwapChainForHwnd(dxgi_factory, (IUnknown*)command_queue, wnd, &swap_chain_desc, NULL, NULL, &swap_chain);
+    assert(SUCCEEDED(hr));
+    get_swap_chain_buffers();
+
+    /* GUI */
+    ctx = nk_d3d12_init(device, WINDOW_WIDTH, WINDOW_HEIGHT, MAX_VERTEX_BUFFER, MAX_INDEX_BUFFER, USER_TEXTURES);
+    
+    /* Load Fonts: if none of these are loaded a default font will be used  */
+    /* Load Cursor: if you uncomment cursor loading please hide the cursor */
+    {
+    struct nk_font_atlas *atlas;
+    nk_d3d12_font_stash_begin(&atlas);
+    /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../extra_font/DroidSans.ttf", 14, 0);*/
+    /*struct nk_font *robot = nk_font_atlas_add_from_file(atlas, "../../extra_font/Roboto-Regular.ttf", 14, 0);*/
+    /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
+    /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../extra_font/ProggyClean.ttf", 12, 0);*/
+    /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../extra_font/ProggyTiny.ttf", 10, 0);*/
+    /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../extra_font/Cousine-Regular.ttf", 13, 0);*/
+    nk_d3d12_font_stash_end(command_list);
+    /*nk_style_load_all_cursors(ctx, atlas->cursors);*/
+    /*nk_style_set_font(ctx, &droid->handle)*/;
+    }
+
+    /* Execute the command list to make sure all texture (font) data has been uploaded */
+    execute_commands();
+    /* Now we can cleanup all resources consumed by font stashing that are no longer used */
+    nk_d3d12_font_stash_cleanup();
+
+    /* style.c */
+    #ifdef INCLUDE_STYLE
+    /*set_style(ctx, THEME_WHITE);*/
+    /*set_style(ctx, THEME_RED);*/
+    /*set_style(ctx, THEME_BLUE);*/
+    /*set_style(ctx, THEME_DARK);*/
+    #endif
+
+    bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;
+    while (running)
+    {
+        /* Input */
+        MSG msg;
+        nk_input_begin(ctx);
+        while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
+        {
+            if (msg.message == WM_QUIT)
+                running = 0;
+            TranslateMessage(&msg);
+            DispatchMessageW(&msg);
+        }
+        nk_input_end(ctx);
+
+        /* GUI */
+        if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250),
+            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
+            NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
+        {
+            enum {EASY, HARD};
+            static int op = EASY;
+            static int property = 20;
+
+            nk_layout_row_static(ctx, 30, 80, 1);
+            if (nk_button_label(ctx, "button"))
+                fprintf(stdout, "button pressed\n");
+            nk_layout_row_dynamic(ctx, 30, 2);
+            if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
+            if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
+            nk_layout_row_dynamic(ctx, 22, 1);
+            nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
+
+            nk_layout_row_dynamic(ctx, 20, 1);
+            nk_label(ctx, "background:", NK_TEXT_LEFT);
+            nk_layout_row_dynamic(ctx, 25, 1);
+            if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {
+                nk_layout_row_dynamic(ctx, 120, 1);
+                bg = nk_color_picker(ctx, bg, NK_RGBA);
+                nk_layout_row_dynamic(ctx, 25, 1);
+                bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f);
+                bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f);
+                bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f);
+                bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f);
+                nk_combo_end(ctx);
+            }
+        }
+        nk_end(ctx);
+
+        /* -------------- EXAMPLES ---------------- */
+        #ifdef INCLUDE_CALCULATOR
+          calculator(ctx);
+        #endif
+        #ifdef INCLUDE_CANVAS
+          canvas(ctx);
+        #endif
+        #ifdef INCLUDE_OVERVIEW
+          overview(ctx);
+        #endif
+        #ifdef INCLUDE_NODE_EDITOR
+          node_editor(ctx);
+        #endif
+        /* ----------------------------------------- */
+
+        /* Set rtv resource state */
+        D3D12_RESOURCE_BARRIER resource_barrier;
+        resource_barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+        resource_barrier.Transition.pResource = rtv_buffers[rtv_index];
+        resource_barrier.Transition.Subresource = 0;
+        resource_barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
+        resource_barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
+        resource_barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
+        ID3D12GraphicsCommandList_ResourceBarrier(command_list, 1, &resource_barrier);
+
+        /* Clear and set the rtv */
+        ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, rtv_handles[rtv_index], &bg.r, 0, NULL);
+        ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &rtv_handles[rtv_index], FALSE, NULL);
+
+        /* Draw */
+        nk_d3d12_render(command_list, NK_ANTI_ALIASING_ON);
+
+        /* Bring the rtv resource back to present state */
+        resource_barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+        resource_barrier.Transition.pResource = rtv_buffers[rtv_index];
+        resource_barrier.Transition.Subresource = 0;
+        resource_barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
+        resource_barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
+        resource_barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
+        ID3D12GraphicsCommandList_ResourceBarrier(command_list, 1, &resource_barrier);
+
+        /* Execute command list and wait */
+        execute_commands();
+
+        /* Present frame */
+        hr = IDXGISwapChain2_Present(swap_chain, 1, 0);
+        rtv_index = (rtv_index + 1) % 2;
+        if (hr == DXGI_ERROR_DEVICE_RESET || hr == DXGI_ERROR_DEVICE_REMOVED) {
+            /* to recover from this, you'll need to recreate device and all the resources */
+            MessageBoxW(NULL, L"D3D12 device is lost or removed!", L"Error", 0);
+            break;
+        } else if (hr == DXGI_STATUS_OCCLUDED) {
+            /* window is not visible, so vsync won't work. Let's sleep a bit to reduce CPU usage */
+            Sleep(10);
+        }
+        assert(SUCCEEDED(hr));
+    }
+
+    /* Nuklear shutdown */
+    nk_d3d12_shutdown();
+
+    /* D3D12 and DXGI shutdown */
+    signal_and_wait();
+    signal_and_wait(); /* Two times because we have two buffers in flight */
+    ID3D12Resource_Release(rtv_buffers[0]);
+    ID3D12Resource_Release(rtv_buffers[1]);
+    ID3D12DescriptorHeap_Release(rtv_descriptor_heap);
+    IDXGISwapChain1_Release(swap_chain);
+    IDXGIFactory2_Release(dxgi_factory);
+    ID3D12GraphicsCommandList_Release(command_list);
+    ID3D12CommandAllocator_Release(command_allocator);
+    ID3D12CommandQueue_Release(command_queue);
+    ID3D12Fence_Release(queue_fence);
+    ID3D12Device_Release(device);
+
+    /* win32 shutdown */
+    UnregisterClassW(wc.lpszClassName, wc.hInstance);
+
+    return 0;
+}

+ 928 - 0
demo/d3d12/nuklear_d3d12.h

@@ -0,0 +1,928 @@
+/*
+ * Nuklear - 1.32.0 - public domain
+ * no warrenty implied; use at your own risk.
+ * authored from 2015-2016 by Micha Mettke
+ * 
+ * D3D12 backend created by Ludwig Fuechsl (2022)
+ */
+/*
+ * ==============================================================
+ *
+ *                              API
+ *
+ * ===============================================================
+ */
+#ifndef NK_D3D12_H_
+#define NK_D3D12_H_
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+/*
+ * USAGE:
+ *    - This function will initialize a new nuklear rendering context. The context will be bound to a GLOBAL DirectX 12 rendering state.
+ */
+NK_API struct nk_context *nk_d3d12_init(ID3D12Device *device, int width, int height, unsigned int max_vertex_buffer, unsigned int max_index_buffer, unsigned int max_user_textures);
+/*
+ * USAGE:
+ *    - A call to this function prepares the global nuklear d3d12 backend for receiving font information’s. Use the obtained atlas pointer to load all required fonts and do all required font setup.
+ */
+NK_API void nk_d3d12_font_stash_begin(struct nk_font_atlas **atlas);
+/*
+ * USAGE:
+ *    - Call this function after a call to nk_d3d12_font_stash_begin(...) when all fonts have been loaded and configured. 
+ *    - This function will place commands on the supplied ID3D12GraphicsCommandList.
+ *    - This function will allocate temporary data that is required until the command list has finish executing. The temporary data can be free by calling nk_d3d12_font_stash_cleanup(...)
+ */
+NK_API void nk_d3d12_font_stash_end(ID3D12GraphicsCommandList *command_list);
+/*
+ * USAGE:
+ *    - This function will free temporary data that was allocated by nk_d3d12_font_stash_begin(...)
+ *    - Only call this function after the command list used in the nk_d3d12_font_stash_begin(...) function call has finished executing.
+ *    - It is NOT required to call this function but highly recommended.
+ */
+NK_API void nk_d3d12_font_stash_cleanup();
+/*
+ * USAGE:
+ *    - This function will setup the supplied texture (ID3D12Resource) for rendering custom images using the supplied D3D12_SHADER_RESOURCE_VIEW_DESC.
+ *    - This function may override any previous calls to nk_d3d12_set_user_texture(...) while using the same index.
+ *    - The returned handle can be used as texture handle to render custom images.
+ *    - The caller must keep track of the state of the texture when it comes to rendering with nk_d3d12_render(...).
+ */
+NK_API nk_bool nk_d3d12_set_user_texture(unsigned int index, ID3D12Resource* texture, const D3D12_SHADER_RESOURCE_VIEW_DESC* description, nk_handle* handle_out);
+/*
+ * USAGE:
+ *    - This function should be called within the user window proc to allow nuklear to listen to window events
+ */
+NK_API int nk_d3d12_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
+/*
+ * USAGE:
+ *    - A call to this function renders any previous placed nuklear draw calls and will flush all nuklear buffers for the next frame
+ *    - This function will place commands on the supplied ID3D12GraphicsCommandList.
+ *    - When using custom images for rendering make sure they are in the correct resource state (D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) when calling this function.
+ *    - This function will upload data to the gpu (64 + max_vertex_buffer + max_index_buffer BYTES).
+ */
+NK_API void nk_d3d12_render(ID3D12GraphicsCommandList *command_list, enum nk_anti_aliasing AA);
+/*
+ * USAGE:
+ *    - This function will notify nuklear that the framebuffer dimensions have changed.
+ */
+NK_API void nk_d3d12_resize(int width, int height);
+/*
+ * USAGE:
+ *    - This function will free the global d3d12 rendering state.
+ */
+NK_API void nk_d3d12_shutdown(void);
+
+#endif
+/*
+ * ==============================================================
+ *
+ *                          IMPLEMENTATION
+ *
+ * ===============================================================
+ */
+#ifdef NK_D3D12_IMPLEMENTATION
+
+#define WIN32_LEAN_AND_MEAN
+#define COBJMACROS
+#include <d3d12.h>
+
+#include <stddef.h>
+#include <string.h>
+#include <float.h>
+#include <assert.h>
+
+#include "nuklear_d3d12_vertex_shader.h"
+#include "nuklear_d3d12_pixel_shader.h"
+
+struct nk_d3d12_vertex 
+{
+    float position[2];
+    float uv[2];
+    nk_byte col[4];
+};
+
+static struct
+{
+    struct nk_context ctx;
+    struct nk_font_atlas atlas;
+    struct nk_buffer cmds;
+
+    struct nk_draw_null_texture null;
+    unsigned int max_vertex_buffer;
+    unsigned int max_index_buffer;
+    unsigned int max_user_textures;
+
+    D3D12_HEAP_PROPERTIES heap_prop_default;
+    D3D12_HEAP_PROPERTIES heap_prop_upload;
+
+    UINT cbv_srv_uav_desc_increment;
+
+    D3D12_VIEWPORT viewport;
+    ID3D12Device *device;
+    ID3D12RootSignature *root_signature;
+    ID3D12PipelineState *pipeline_state;
+    ID3D12DescriptorHeap *desc_heap;
+    ID3D12Resource *font_texture;
+    ID3D12Resource *font_upload_buffer;
+    ID3D12Resource *upload_buffer;
+    ID3D12Resource *const_buffer;
+    ID3D12Resource *index_buffer;
+    ID3D12Resource *vertex_buffer;
+
+    D3D12_CPU_DESCRIPTOR_HANDLE cpu_descriptor_handle;
+    D3D12_GPU_DESCRIPTOR_HANDLE gpu_descriptor_handle;
+    D3D12_GPU_VIRTUAL_ADDRESS gpu_vertex_buffer_address;
+    D3D12_GPU_VIRTUAL_ADDRESS gpu_index_buffer_address;
+} d3d12;
+
+NK_API void
+nk_d3d12_render(ID3D12GraphicsCommandList *command_list, enum nk_anti_aliasing AA)
+{
+    HRESULT hr;
+#ifdef NK_UINT_DRAW_INDEX
+    DXGI_FORMAT index_buffer_format = DXGI_FORMAT_R32_UINT;
+#else
+    DXGI_FORMAT index_buffer_format = DXGI_FORMAT_R16_UINT;
+#endif
+    const UINT stride = sizeof(struct nk_d3d12_vertex);
+    const struct nk_draw_command *cmd;
+    UINT offset = 0;
+    D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view;
+    D3D12_INDEX_BUFFER_VIEW index_buffer_view;
+    unsigned char* ptr_data;
+    D3D12_RANGE map_range;
+    D3D12_RESOURCE_BARRIER resource_barriers[3];
+
+    /* Activate D3D12 pipeline state and config root signature */
+    ID3D12GraphicsCommandList_SetPipelineState(command_list, d3d12.pipeline_state);
+    ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, d3d12.root_signature);
+    ID3D12GraphicsCommandList_SetDescriptorHeaps(command_list, 1, &d3d12.desc_heap);
+    ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(command_list, 0, d3d12.gpu_descriptor_handle);
+
+    /* Configure rendering pipeline */
+    ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
+    vertex_buffer_view.BufferLocation = d3d12.gpu_vertex_buffer_address;
+    vertex_buffer_view.SizeInBytes = d3d12.max_vertex_buffer;
+    vertex_buffer_view.StrideInBytes = stride;
+    ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, 1, &vertex_buffer_view);
+    index_buffer_view.BufferLocation = d3d12.gpu_index_buffer_address;
+    index_buffer_view.Format = index_buffer_format;
+    index_buffer_view.SizeInBytes = d3d12.max_index_buffer;
+    ID3D12GraphicsCommandList_IASetIndexBuffer(command_list, &index_buffer_view);
+    ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &d3d12.viewport);
+
+    /* Map upload buffer to cpu accessible pointer */
+    map_range.Begin = sizeof(float) * 4 * 4;
+    map_range.End = map_range.Begin + d3d12.max_vertex_buffer + d3d12.max_index_buffer;
+    hr = ID3D12Resource_Map(d3d12.upload_buffer, 0, &map_range, &ptr_data);
+    NK_ASSERT(SUCCEEDED(hr));
+
+    /* Nuklear convert and copy to upload buffer */
+    {
+    struct nk_convert_config config;
+    NK_STORAGE const struct nk_draw_vertex_layout_element vertex_layout[] = {
+        {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_d3d12_vertex, position)},
+        {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_d3d12_vertex, uv)},
+        {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_d3d12_vertex, col)},
+        {NK_VERTEX_LAYOUT_END}
+    };
+    memset(&config, 0, sizeof(config));
+    config.vertex_layout = vertex_layout;
+    config.vertex_size = sizeof(struct nk_d3d12_vertex);
+    config.vertex_alignment = NK_ALIGNOF(struct nk_d3d12_vertex);
+    config.global_alpha = 1.0f;
+    config.shape_AA = AA;
+    config.line_AA = AA;
+    config.circle_segment_count = 22;
+    config.curve_segment_count = 22;
+    config.arc_segment_count = 22;
+    config.null = d3d12.null;
+
+    struct nk_buffer vbuf, ibuf;
+    nk_buffer_init_fixed(&vbuf, &ptr_data[sizeof(float) * 4 * 4], (size_t)d3d12.max_vertex_buffer);
+    nk_buffer_init_fixed(&ibuf, &ptr_data[sizeof(float) * 4 * 4 + d3d12.max_vertex_buffer], (size_t)d3d12.max_index_buffer);
+    nk_convert(&d3d12.ctx, &d3d12.cmds, &vbuf, &ibuf, &config);
+    }
+
+    /* Close mapping range */
+    ID3D12Resource_Unmap(d3d12.upload_buffer, 0, &map_range);
+
+    /* Issue GPU resource change for copying */
+    resource_barriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+    resource_barriers[0].Transition.pResource = d3d12.const_buffer;
+    resource_barriers[0].Transition.Subresource = 0;
+    resource_barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
+    resource_barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
+    resource_barriers[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
+    resource_barriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+    resource_barriers[1].Transition.pResource = d3d12.vertex_buffer;
+    resource_barriers[1].Transition.Subresource = 0;
+    resource_barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
+    resource_barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
+    resource_barriers[1].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
+    resource_barriers[2].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+    resource_barriers[2].Transition.pResource = d3d12.index_buffer;
+    resource_barriers[2].Transition.Subresource = 0;
+    resource_barriers[2].Transition.StateBefore = D3D12_RESOURCE_STATE_INDEX_BUFFER;
+    resource_barriers[2].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
+    resource_barriers[2].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
+    ID3D12GraphicsCommandList_ResourceBarrier(command_list, 3, resource_barriers);
+
+    /* Copy from upload buffer to gpu buffers */
+    ID3D12GraphicsCommandList_CopyBufferRegion(command_list, d3d12.const_buffer, 0, d3d12.upload_buffer, 0, sizeof(float) * 4 * 4);
+    ID3D12GraphicsCommandList_CopyBufferRegion(command_list, d3d12.vertex_buffer, 0, d3d12.upload_buffer, sizeof(float) * 4 * 4, d3d12.max_vertex_buffer);
+    ID3D12GraphicsCommandList_CopyBufferRegion(command_list, d3d12.index_buffer, 0, d3d12.upload_buffer, sizeof(float) * 4 * 4 + d3d12.max_vertex_buffer, d3d12.max_index_buffer);
+
+    /* Issue GPU resource change for rendering */
+    resource_barriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+    resource_barriers[0].Transition.pResource = d3d12.const_buffer;
+    resource_barriers[0].Transition.Subresource = 0;
+    resource_barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
+    resource_barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
+    resource_barriers[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
+    resource_barriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+    resource_barriers[1].Transition.pResource = d3d12.vertex_buffer;
+    resource_barriers[1].Transition.Subresource = 0;
+    resource_barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
+    resource_barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
+    resource_barriers[1].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
+    resource_barriers[2].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+    resource_barriers[2].Transition.pResource = d3d12.index_buffer;
+    resource_barriers[2].Transition.Subresource = 0;
+    resource_barriers[2].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
+    resource_barriers[2].Transition.StateAfter = D3D12_RESOURCE_STATE_INDEX_BUFFER;
+    resource_barriers[2].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
+    ID3D12GraphicsCommandList_ResourceBarrier(command_list, 3, resource_barriers);
+
+    /* Issue draw commands */
+    nk_draw_foreach(cmd, &d3d12.ctx, &d3d12.cmds)
+    {
+        D3D12_RECT scissor;
+        UINT32 texture_id;
+
+        /* Only place a drawcall in case the command contains drawable data */
+        if(cmd->elem_count)
+        {
+            /* Setup scissor rect */
+            scissor.left = (LONG)cmd->clip_rect.x;
+            scissor.right = (LONG)(cmd->clip_rect.x + cmd->clip_rect.w);
+            scissor.top = (LONG)cmd->clip_rect.y;
+            scissor.bottom = (LONG)(cmd->clip_rect.y + cmd->clip_rect.h);
+            ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &scissor);
+
+            /* Setup texture (index to descriptor heap table) to use for draw call */
+            texture_id = (UINT32)cmd->texture.id;
+            ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 1, 1, &texture_id, 0);
+
+            /* Dispatch draw call */
+            ID3D12GraphicsCommandList_DrawIndexedInstanced(command_list, (UINT)cmd->elem_count, 1, offset, 0, 0);
+            offset += cmd->elem_count;
+        }
+    }
+
+    /* Default nuklear context and command buffer clear */
+    nk_clear(&d3d12.ctx);
+    nk_buffer_clear(&d3d12.cmds);
+}
+
+static void
+nk_d3d12_get_projection_matrix(int width, int height, float *result)
+{
+    const float L = 0.0f;
+    const float R = (float)width;
+    const float T = 0.0f;
+    const float B = (float)height;
+    float matrix[4][4] =
+    {
+        { 0.0f, 0.0f, 0.0f, 0.0f },
+        { 0.0f, 0.0f, 0.0f, 0.0f },
+        { 0.0f, 0.0f, 0.5f, 0.0f },
+        { 0.0f, 0.0f, 0.5f, 1.0f },
+    };
+    matrix[0][0] = 2.0f / (R - L);
+    matrix[1][1] = 2.0f / (T - B);
+    matrix[3][0] = (R + L) / (L - R);
+    matrix[3][1] = (T + B) / (B - T);
+    memcpy(result, matrix, sizeof(matrix));
+}
+
+NK_API void
+nk_d3d12_resize(int width, int height)
+{
+    D3D12_RANGE map_range;
+    void* ptr_data;
+
+    /* Describe area to be mapped (the upload buffer region where the constant buffer / projection matrix) lives */
+    map_range.Begin = 0;
+    map_range.End = sizeof(float) * 4 * 4;
+
+    /* Map area to cpu accassible pointer (from upload buffer) */
+    if (SUCCEEDED(ID3D12Resource_Map(d3d12.upload_buffer, 0, &map_range, &ptr_data)))
+    {
+        /* Compute projection matrix into upload buffer */
+        nk_d3d12_get_projection_matrix(width, height, (float*)ptr_data);
+        ID3D12Resource_Unmap(d3d12.upload_buffer, 0, &map_range);
+
+        /* Update internal viewport state to relect resize changes */
+        d3d12.viewport.Width = (float)width;
+        d3d12.viewport.Height = (float)height;
+    }
+
+    /*
+        NOTE:
+        When mapping and copying succeeds, the data will still be in CPU sided memory
+        copying to the GPU is done in the nk_d3d12_render function
+    */
+}
+
+NK_API int
+nk_d3d12_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    switch (msg)
+    {
+    case WM_KEYDOWN:
+    case WM_KEYUP:
+    case WM_SYSKEYDOWN:
+    case WM_SYSKEYUP:
+    {
+        int down = !((lparam >> 31) & 1);
+        int ctrl = GetKeyState(VK_CONTROL) & (1 << 15);
+
+        switch (wparam)
+        {
+        case VK_SHIFT:
+        case VK_LSHIFT:
+        case VK_RSHIFT:
+            nk_input_key(&d3d12.ctx, NK_KEY_SHIFT, down);
+            return 1;
+
+        case VK_DELETE:
+            nk_input_key(&d3d12.ctx, NK_KEY_DEL, down);
+            return 1;
+
+        case VK_RETURN:
+            nk_input_key(&d3d12.ctx, NK_KEY_ENTER, down);
+            return 1;
+
+        case VK_TAB:
+            nk_input_key(&d3d12.ctx, NK_KEY_TAB, down);
+            return 1;
+
+        case VK_LEFT:
+            if (ctrl)
+                nk_input_key(&d3d12.ctx, NK_KEY_TEXT_WORD_LEFT, down);
+            else
+                nk_input_key(&d3d12.ctx, NK_KEY_LEFT, down);
+            return 1;
+
+        case VK_RIGHT:
+            if (ctrl)
+                nk_input_key(&d3d12.ctx, NK_KEY_TEXT_WORD_RIGHT, down);
+            else
+                nk_input_key(&d3d12.ctx, NK_KEY_RIGHT, down);
+            return 1;
+
+        case VK_BACK:
+            nk_input_key(&d3d12.ctx, NK_KEY_BACKSPACE, down);
+            return 1;
+
+        case VK_HOME:
+            nk_input_key(&d3d12.ctx, NK_KEY_TEXT_START, down);
+            nk_input_key(&d3d12.ctx, NK_KEY_SCROLL_START, down);
+            return 1;
+
+        case VK_END:
+            nk_input_key(&d3d12.ctx, NK_KEY_TEXT_END, down);
+            nk_input_key(&d3d12.ctx, NK_KEY_SCROLL_END, down);
+            return 1;
+
+        case VK_NEXT:
+            nk_input_key(&d3d12.ctx, NK_KEY_SCROLL_DOWN, down);
+            return 1;
+
+        case VK_PRIOR:
+            nk_input_key(&d3d12.ctx, NK_KEY_SCROLL_UP, down);
+            return 1;
+
+        case 'C':
+            if (ctrl) {
+                nk_input_key(&d3d12.ctx, NK_KEY_COPY, down);
+                return 1;
+            }
+            break;
+
+        case 'V':
+            if (ctrl) {
+                nk_input_key(&d3d12.ctx, NK_KEY_PASTE, down);
+                return 1;
+            }
+            break;
+
+        case 'X':
+            if (ctrl) {
+                nk_input_key(&d3d12.ctx, NK_KEY_CUT, down);
+                return 1;
+            }
+            break;
+
+        case 'Z':
+            if (ctrl) {
+                nk_input_key(&d3d12.ctx, NK_KEY_TEXT_UNDO, down);
+                return 1;
+            }
+            break;
+
+        case 'R':
+            if (ctrl) {
+                nk_input_key(&d3d12.ctx, NK_KEY_TEXT_REDO, down);
+                return 1;
+            }
+            break;
+        }
+        return 0;
+    }
+
+    case WM_CHAR:
+        if (wparam >= 32)
+        {
+            nk_input_unicode(&d3d12.ctx, (nk_rune)wparam);
+            return 1;
+        }
+        break;
+
+    case WM_LBUTTONDOWN:
+        nk_input_button(&d3d12.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+        SetCapture(wnd);
+        return 1;
+
+    case WM_LBUTTONUP:
+        nk_input_button(&d3d12.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+        nk_input_button(&d3d12.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+        ReleaseCapture();
+        return 1;
+
+    case WM_RBUTTONDOWN:
+        nk_input_button(&d3d12.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+        SetCapture(wnd);
+        return 1;
+
+    case WM_RBUTTONUP:
+        nk_input_button(&d3d12.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+        ReleaseCapture();
+        return 1;
+
+    case WM_MBUTTONDOWN:
+        nk_input_button(&d3d12.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+        SetCapture(wnd);
+        return 1;
+
+    case WM_MBUTTONUP:
+        nk_input_button(&d3d12.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
+        ReleaseCapture();
+        return 1;
+
+    case WM_MOUSEWHEEL:
+        nk_input_scroll(&d3d12.ctx, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA));
+        return 1;
+
+    case WM_MOUSEMOVE:
+        nk_input_motion(&d3d12.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));
+        return 1;
+
+    case WM_LBUTTONDBLCLK:
+        nk_input_button(&d3d12.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
+        return 1;
+    }
+
+    return 0;
+}
+
+static void
+nk_d3d12_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)
+{
+    (void)usr;
+    if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL))
+    {
+        HGLOBAL mem = GetClipboardData(CF_UNICODETEXT); 
+        if (mem)
+        {
+            SIZE_T size = GlobalSize(mem) - 1;
+            if (size)
+            {
+                LPCWSTR wstr = (LPCWSTR)GlobalLock(mem);
+                if (wstr)
+                {
+                    int utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, size / sizeof(wchar_t), NULL, 0, NULL, NULL);
+                    if (utf8size)
+                    {
+                        char* utf8 = (char*)malloc(utf8size);
+                        if (utf8)
+                        {
+                            WideCharToMultiByte(CP_UTF8, 0, wstr, size / sizeof(wchar_t), utf8, utf8size, NULL, NULL);
+                            nk_textedit_paste(edit, utf8, utf8size);
+                            free(utf8);
+                        }
+                    }
+                    GlobalUnlock(mem); 
+                }
+            }
+        }
+        CloseClipboard();
+    }
+}
+
+static void
+nk_d3d12_clipboard_copy(nk_handle usr, const char *text, int len)
+{
+    (void)usr;
+    if (OpenClipboard(NULL))
+    {
+        int wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
+        if (wsize)
+        {
+            HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));
+            if (mem)
+            {
+                wchar_t* wstr = (wchar_t*)GlobalLock(mem);
+                if (wstr)
+                {
+                    MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
+                    wstr[wsize] = 0;
+                    GlobalUnlock(mem);
+                    SetClipboardData(CF_UNICODETEXT, mem); 
+                }
+            }
+        }
+        CloseClipboard();
+    }
+}
+
+NK_API struct nk_context*
+nk_d3d12_init(ID3D12Device *device, int width, int height, unsigned int max_vertex_buffer, unsigned int max_index_buffer, unsigned int max_user_textures)
+{
+    HRESULT hr;
+    D3D12_CONSTANT_BUFFER_VIEW_DESC cbv;
+    D3D12_CPU_DESCRIPTOR_HANDLE cbv_handle;
+
+    /* Do plain object / ref copys */ 
+    d3d12.max_vertex_buffer = max_vertex_buffer;
+    d3d12.max_index_buffer = max_index_buffer;
+    d3d12.max_user_textures = max_user_textures;
+    d3d12.device = device;
+    ID3D12Device_AddRef(device);
+    d3d12.font_texture = NULL;
+    d3d12.font_upload_buffer = NULL;
+
+    /* Init nuklear context */
+    nk_init_default(&d3d12.ctx, 0);
+    d3d12.ctx.clip.copy = nk_d3d12_clipboard_copy;
+    d3d12.ctx.clip.paste = nk_d3d12_clipboard_paste;
+    d3d12.ctx.clip.userdata = nk_handle_ptr(0);
+
+    /* Init nuklear buffer */
+    nk_buffer_init_default(&d3d12.cmds);
+
+    /* Define Heap properties */
+    d3d12.heap_prop_default.Type = D3D12_HEAP_TYPE_DEFAULT;
+    d3d12.heap_prop_default.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
+    d3d12.heap_prop_default.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
+    d3d12.heap_prop_default.CreationNodeMask = 0;
+    d3d12.heap_prop_default.VisibleNodeMask = 0;
+    d3d12.heap_prop_upload.Type = D3D12_HEAP_TYPE_UPLOAD;
+    d3d12.heap_prop_upload.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
+    d3d12.heap_prop_upload.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
+    d3d12.heap_prop_upload.CreationNodeMask = 0;
+    d3d12.heap_prop_upload.VisibleNodeMask = 0;
+
+    /* Create data objects */
+    /* Create upload buffer */
+    {
+    D3D12_RESOURCE_DESC desc;
+    desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+    desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
+    desc.Width = (sizeof(float) * 4 * 4) + max_vertex_buffer + max_index_buffer; /* Needs to hold matrix + vertices + indicies */
+    desc.Height = 1;
+    desc.DepthOrArraySize = 1;
+    desc.MipLevels = 1;
+    desc.Format = DXGI_FORMAT_UNKNOWN;
+    desc.SampleDesc.Count = 1;
+    desc.SampleDesc.Quality = 0;
+    desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+    desc.Flags = D3D12_RESOURCE_FLAG_NONE;
+    hr = ID3D12Device_CreateCommittedResource(device, &d3d12.heap_prop_upload, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COPY_SOURCE, NULL, &IID_ID3D12Resource, &d3d12.upload_buffer);
+    NK_ASSERT(SUCCEEDED(hr));
+    }
+    /* Create constant buffer */
+    {
+    D3D12_RESOURCE_DESC desc;
+    desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+    desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
+    desc.Width = 256; /* Should be sizeof(float) * 4 * 4 - but this does not match how d3d12 works (min CBV size of 256) */
+    desc.Height = 1;
+    desc.DepthOrArraySize = 1;
+    desc.MipLevels = 1;
+    desc.Format = DXGI_FORMAT_UNKNOWN;
+    desc.SampleDesc.Count = 1;
+    desc.SampleDesc.Quality = 0;
+    desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+    desc.Flags = D3D12_RESOURCE_FLAG_NONE;
+    hr = ID3D12Device_CreateCommittedResource(device, &d3d12.heap_prop_default, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, &d3d12.const_buffer);
+    NK_ASSERT(SUCCEEDED(hr));
+    }
+    /* Create vertex buffer */
+    {
+    D3D12_RESOURCE_DESC desc;
+    desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+    desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
+    desc.Width = max_vertex_buffer;
+    desc.Height = 1;
+    desc.DepthOrArraySize = 1;
+    desc.MipLevels = 1;
+    desc.Format = DXGI_FORMAT_UNKNOWN;
+    desc.SampleDesc.Count = 1;
+    desc.SampleDesc.Quality = 0;
+    desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+    desc.Flags = D3D12_RESOURCE_FLAG_NONE;
+    hr = ID3D12Device_CreateCommittedResource(device, &d3d12.heap_prop_default, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, &d3d12.vertex_buffer);
+    NK_ASSERT(SUCCEEDED(hr));
+    }
+    /* Create index buffer */
+    {
+    D3D12_RESOURCE_DESC desc;
+    desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+    desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
+    desc.Width = max_index_buffer;
+    desc.Height = 1;
+    desc.DepthOrArraySize = 1;
+    desc.MipLevels = 1;
+    desc.Format = DXGI_FORMAT_UNKNOWN;
+    desc.SampleDesc.Count = 1;
+    desc.SampleDesc.Quality = 0;
+    desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+    desc.Flags = D3D12_RESOURCE_FLAG_NONE;
+    hr = ID3D12Device_CreateCommittedResource(device, &d3d12.heap_prop_default, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, &d3d12.index_buffer);
+    NK_ASSERT(SUCCEEDED(hr));
+    }
+
+    /* Create descriptor heap for shader root signature */
+    {
+        D3D12_DESCRIPTOR_HEAP_DESC desc;
+        desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
+        desc.NumDescriptors = 2 + max_user_textures;
+        desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
+        desc.NodeMask = 0;
+        ID3D12Device_CreateDescriptorHeap(device, &desc, &IID_ID3D12DescriptorHeap, &d3d12.desc_heap);
+    }
+
+    /* Get address of first handle (CPU and GPU) */
+    ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(d3d12.desc_heap, &d3d12.cpu_descriptor_handle);
+    ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(d3d12.desc_heap, &d3d12.gpu_descriptor_handle);
+    
+    /* Get addresses of vertex & index buffers */
+    d3d12.gpu_vertex_buffer_address = ID3D12Resource_GetGPUVirtualAddress(d3d12.vertex_buffer);
+    d3d12.gpu_index_buffer_address = ID3D12Resource_GetGPUVirtualAddress(d3d12.index_buffer);
+
+    /* Get handle increment */
+    d3d12.cbv_srv_uav_desc_increment = ID3D12Device_GetDescriptorHandleIncrementSize(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
+
+    /* Create view to constant buffer */
+    cbv.BufferLocation = ID3D12Resource_GetGPUVirtualAddress(d3d12.const_buffer);
+    cbv.SizeInBytes = 256;
+    cbv_handle = d3d12.cpu_descriptor_handle;
+    ID3D12Device_CreateConstantBufferView(device, &cbv, cbv_handle);
+
+    /* Create root signature */
+    hr = ID3D12Device_CreateRootSignature(device, 0, nk_d3d12_vertex_shader, sizeof(nk_d3d12_vertex_shader), &IID_ID3D12RootSignature, &d3d12.root_signature);
+    NK_ASSERT(SUCCEEDED(hr));
+
+    /* Create pipeline state */
+    {
+    /* Describe input layout */
+    const D3D12_INPUT_ELEMENT_DESC layout[] = {
+        { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, NK_OFFSETOF(struct nk_d3d12_vertex, position),  D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
+        { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,       0, NK_OFFSETOF(struct nk_d3d12_vertex, uv),        D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
+        { "COLOR",    0, DXGI_FORMAT_R8G8B8A8_UNORM,     0, NK_OFFSETOF(struct nk_d3d12_vertex, col),       D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
+    };
+
+    /* Describe pipeline state */
+    D3D12_GRAPHICS_PIPELINE_STATE_DESC desc;
+    memset(&desc, 0, sizeof(desc));
+    desc.pRootSignature = d3d12.root_signature;
+    desc.VS.pShaderBytecode = nk_d3d12_vertex_shader;
+    desc.VS.BytecodeLength = sizeof(nk_d3d12_vertex_shader);
+    desc.PS.pShaderBytecode = nk_d3d12_pixel_shader;
+    desc.PS.BytecodeLength = sizeof(nk_d3d12_pixel_shader);
+    desc.BlendState.RenderTarget[0].BlendEnable = TRUE;
+    desc.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
+    desc.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
+    desc.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
+    desc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
+    desc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ZERO;
+    desc.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
+    desc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
+    desc.SampleMask = UINT_MAX;
+    desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
+    desc.RasterizerState.CullMode= D3D12_CULL_MODE_NONE;
+    desc.RasterizerState.DepthClipEnable = TRUE;
+    desc.InputLayout.NumElements = _countof(layout);
+    desc.InputLayout.pInputElementDescs = layout;
+    desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
+    desc.NumRenderTargets = 1;
+    desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; /* NOTE: When using HDR rendering you might have a different framebuffer format */
+    desc.SampleDesc.Count = 1;
+    desc.SampleDesc.Quality = 0;
+    desc.NodeMask = 0;
+
+    /* Create PSO */
+    hr = ID3D12Device_CreateGraphicsPipelineState(device, &desc, &IID_ID3D12PipelineState, &d3d12.pipeline_state);
+    NK_ASSERT(SUCCEEDED(hr));
+    }
+
+    /* First time const buffer init */
+    nk_d3d12_resize(width, height);
+
+    /* viewport */
+    d3d12.viewport.TopLeftX = 0.0f;
+    d3d12.viewport.TopLeftY = 0.0f;
+    d3d12.viewport.Width = (float)width;
+    d3d12.viewport.Height = (float)height;
+    d3d12.viewport.MinDepth = 0.0f;
+    d3d12.viewport.MaxDepth = 1.0f;
+
+    return &d3d12.ctx;
+}
+
+NK_API void
+nk_d3d12_font_stash_begin(struct nk_font_atlas **atlas)
+{
+    /* Default nuklear font stash */
+    nk_font_atlas_init_default(&d3d12.atlas);
+    nk_font_atlas_begin(&d3d12.atlas);
+    *atlas = &d3d12.atlas;
+}
+
+NK_API void
+nk_d3d12_font_stash_end(ID3D12GraphicsCommandList *command_list)
+{
+    HRESULT hr;
+    D3D12_TEXTURE_COPY_LOCATION  cpy_src, cpy_dest;
+    D3D12_BOX cpy_box;
+    D3D12_RESOURCE_BARRIER resource_barrier;
+    D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc;
+    D3D12_CPU_DESCRIPTOR_HANDLE srv_handle;
+    const void *image;
+    void* ptr_data;
+    int w, h;
+
+    /* Bake nuklear font atlas */
+    image = nk_font_atlas_bake(&d3d12.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
+    NK_ASSERT(image);
+
+    /* Create font texture */
+    {
+    D3D12_RESOURCE_DESC desc;
+    desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
+    desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
+    desc.Width = w;
+    desc.Height = h;
+    desc.DepthOrArraySize = 1;
+    desc.MipLevels = 1;
+    desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+    desc.SampleDesc.Count = 1;
+    desc.SampleDesc.Quality = 0;
+    desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
+    desc.Flags = D3D12_RESOURCE_FLAG_NONE;
+    hr = ID3D12Device_CreateCommittedResource(d3d12.device, &d3d12.heap_prop_default, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COPY_DEST, NULL, &IID_ID3D12Resource, &d3d12.font_texture);
+    NK_ASSERT(SUCCEEDED(hr));
+    }
+
+    /* Create font upload buffer */
+    {
+    D3D12_RESOURCE_DESC desc;
+    desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
+    desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
+    desc.Width = w * h * 4;
+    desc.Height = 1;
+    desc.DepthOrArraySize = 1;
+    desc.MipLevels = 1;
+    desc.Format = DXGI_FORMAT_UNKNOWN;
+    desc.SampleDesc.Count = 1;
+    desc.SampleDesc.Quality = 0;
+    desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
+    desc.Flags = D3D12_RESOURCE_FLAG_NONE;
+    hr = ID3D12Device_CreateCommittedResource(d3d12.device, &d3d12.heap_prop_upload, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COPY_SOURCE, NULL, &IID_ID3D12Resource, &d3d12.font_upload_buffer);
+    NK_ASSERT(SUCCEEDED(hr));
+    }
+
+    /* Copy image data to upload buffer */
+    hr = ID3D12Resource_Map(d3d12.font_upload_buffer, 0, NULL, &ptr_data);
+    NK_ASSERT(SUCCEEDED(hr));
+    memcpy(ptr_data, image, w * h * 4);
+    ID3D12Resource_Unmap(d3d12.font_upload_buffer, 0, NULL);
+
+    /* Execute copy operation */
+    cpy_src.pResource = d3d12.font_upload_buffer;
+    cpy_src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
+    cpy_src.PlacedFootprint.Offset = 0;
+    cpy_src.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+    cpy_src.PlacedFootprint.Footprint.Width = w;
+    cpy_src.PlacedFootprint.Footprint.Height = h;
+    cpy_src.PlacedFootprint.Footprint.Depth = 1;
+    cpy_src.PlacedFootprint.Footprint.RowPitch = w * 4;
+    cpy_dest.pResource = d3d12.font_texture;
+    cpy_dest.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
+    cpy_dest.SubresourceIndex = 0;
+    cpy_box.top = 0;
+    cpy_box.left = 0;
+    cpy_box.back = 1;
+    cpy_box.bottom = h;
+    cpy_box.right = w;
+    cpy_box.front = 0;
+    ID3D12GraphicsCommandList_CopyTextureRegion(command_list, &cpy_dest, 0, 0, 0, &cpy_src, &cpy_box);
+
+    /* Bring texture in the right state for rendering */
+    resource_barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
+    resource_barrier.Transition.pResource = d3d12.font_texture;
+    resource_barrier.Transition.Subresource = 0;
+    resource_barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
+    resource_barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
+    resource_barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
+    ID3D12GraphicsCommandList_ResourceBarrier(command_list, 1, &resource_barrier);
+
+    /* Create the SRV for the font texture */
+    srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+    srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
+    srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
+    srv_desc.Texture2D.MipLevels = 1;
+    srv_desc.Texture2D.MostDetailedMip = 0;
+    srv_desc.Texture2D.PlaneSlice = 0;
+    srv_desc.Texture2D.ResourceMinLODClamp = 0.0f;
+    srv_handle.ptr = d3d12.cpu_descriptor_handle.ptr + d3d12.cbv_srv_uav_desc_increment;
+    ID3D12Device_CreateShaderResourceView(d3d12.device, d3d12.font_texture, &srv_desc, srv_handle);
+
+    /* Done with nk atlas data. Atlas will be served with texture id 0 */
+    nk_font_atlas_end(&d3d12.atlas, nk_handle_id(0), &d3d12.null);
+
+    /* Setup default font */
+    if (d3d12.atlas.default_font)
+        nk_style_set_font(&d3d12.ctx, &d3d12.atlas.default_font->handle);
+}
+
+NK_API 
+void nk_d3d12_font_stash_cleanup()
+{
+    if(d3d12.font_upload_buffer)
+    {
+        ID3D12Resource_Release(d3d12.font_upload_buffer);
+        d3d12.font_upload_buffer = NULL;
+    }
+}
+
+NK_API 
+nk_bool nk_d3d12_set_user_texture(unsigned int index, ID3D12Resource* texture, const D3D12_SHADER_RESOURCE_VIEW_DESC* description, nk_handle* handle_out)
+{
+    nk_bool result = nk_false;
+    if(index < d3d12.max_user_textures)
+    {
+        D3D12_CPU_DESCRIPTOR_HANDLE srv_handle;
+
+        /* Get handle to texture (0 - Const Buffer; 1 - Font Texture; 2 - First user texture) */
+        srv_handle.ptr = d3d12.cpu_descriptor_handle.ptr + ((2 + index) * d3d12.cbv_srv_uav_desc_increment);
+
+        /* Create SRV */
+        ID3D12Device_CreateShaderResourceView(d3d12.device, texture, description, srv_handle);
+
+        /* Set nk handle (0 - Font Texture; 1 - First user texture) */
+        *handle_out = nk_handle_id(1 + index);
+        result = nk_true;
+    }
+
+    return result;
+}
+
+NK_API
+void nk_d3d12_shutdown(void)
+{
+    /* Nuklear cleanup */
+    nk_font_atlas_clear(&d3d12.atlas);
+    nk_buffer_free(&d3d12.cmds);
+    nk_free(&d3d12.ctx);
+
+    /* DirectX 12 cleanup */
+    ID3D12Device_Release(d3d12.device);
+    ID3D12PipelineState_Release(d3d12.pipeline_state);
+    ID3D12RootSignature_Release(d3d12.root_signature);
+    ID3D12DescriptorHeap_Release(d3d12.desc_heap);
+    ID3D12Resource_Release(d3d12.upload_buffer);
+    ID3D12Resource_Release(d3d12.const_buffer);
+    ID3D12Resource_Release(d3d12.index_buffer);
+    ID3D12Resource_Release(d3d12.vertex_buffer);
+    if(d3d12.font_texture) 
+        ID3D12Resource_Release(d3d12.font_texture);
+    if(d3d12.font_upload_buffer)
+        ID3D12Resource_Release(d3d12.font_upload_buffer);
+}
+
+#endif

+ 53 - 0
demo/d3d12/nuklear_d3d12.hlsl

@@ -0,0 +1,53 @@
+#define NK_ROOTSIGNATURE ""\
+"RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT),"\
+"DescriptorTable("\
+  "CBV(b0, numDescriptors = 1, flags = DATA_VOLATILE),"\
+  "SRV(t0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE)"\
+"),"\
+"RootConstants(num32BitConstants = 1, b1),"\
+"StaticSampler(s0, "\
+  "filter = FILTER_MIN_MAG_MIP_LINEAR,"\
+  "addressU = TEXTURE_ADDRESS_CLAMP,"\
+  "addressV = TEXTURE_ADDRESS_CLAMP,"\
+  "addressW = TEXTURE_ADDRESS_CLAMP,"\
+  "comparisonFunc = COMPARISON_ALWAYS"\
+")"
+
+cbuffer buffer0 : register(b0)
+{
+  float4x4 ProjectionMatrix;
+};
+static uint texture_index : register(b1);
+
+sampler sampler0 : register(s0);
+Texture2D<float4> textures[] : register(t0);
+
+struct VS_INPUT
+{
+  float2 pos : POSITION;
+  float4 col : COLOR0;
+  float2 uv  : TEXCOORD0;
+};
+
+struct PS_INPUT
+{
+  float4 pos : SV_POSITION;
+  float4 col : COLOR0;
+  float2 uv  : TEXCOORD0;
+};
+
+[RootSignature(NK_ROOTSIGNATURE)]
+PS_INPUT vs(VS_INPUT input)
+{
+  PS_INPUT output;
+  output.pos = mul(ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));
+  output.col = input.col;
+  output.uv  = input.uv;
+  return output;
+}
+
+[RootSignature(NK_ROOTSIGNATURE)]
+float4 ps(PS_INPUT input) : SV_Target
+{
+  return input.col * textures[texture_index].Sample(sampler0, input.uv);
+}

+ 135 - 0
demo/d3d12/nuklear_d3d12_pixel_shader.h

@@ -0,0 +1,135 @@
+#if 0
+//
+// Generated by Microsoft (R) D3D Shader Disassembler
+//
+//
+// Input signature:
+//
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_POSITION              0   xyzw        0      POS   float       
+// COLOR                    0   xyzw        1     NONE   float   xyzw
+// TEXCOORD                 0   xy          2     NONE   float   xy  
+//
+//
+// Output signature:
+//
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_Target                0   xyzw        0   TARGET   float   xyzw
+//
+ps_5_1
+dcl_globalFlags refactoringAllowed
+dcl_sampler S0[0:0], mode_default, space=0
+dcl_resource_texture2d (float,float,float,float) T0[0:*], space=0
+dcl_input_ps linear v1.xyzw
+dcl_input_ps linear v2.xy
+dcl_output o0.xyzw
+dcl_temps 1
+sample r0.xyzw, v2.xyxx, T0[0].xyzw, S0[0]
+mul o0.xyzw, r0.xyzw, v1.xyzw
+ret 
+// Approximately 0 instruction slots used
+#endif
+
+const BYTE nk_d3d12_pixel_shader[] =
+{
+     68,  88,  66,  67, 228, 128, 
+    250,  93,  94, 248, 174, 160, 
+    102, 133, 107, 228,  84,  49, 
+    109, 253,   1,   0,   0,   0, 
+     72,   2,   0,   0,   4,   0, 
+      0,   0,  48,   0,   0,   0, 
+    164,   0,   0,   0, 216,   0, 
+      0,   0, 152,   1,   0,   0, 
+     73,  83,  71,  78, 108,   0, 
+      0,   0,   3,   0,   0,   0, 
+      8,   0,   0,   0,  80,   0, 
+      0,   0,   0,   0,   0,   0, 
+      1,   0,   0,   0,   3,   0, 
+      0,   0,   0,   0,   0,   0, 
+     15,   0,   0,   0,  92,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   3,   0, 
+      0,   0,   1,   0,   0,   0, 
+     15,  15,   0,   0,  98,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   3,   0, 
+      0,   0,   2,   0,   0,   0, 
+      3,   3,   0,   0,  83,  86, 
+     95,  80,  79,  83,  73,  84, 
+     73,  79,  78,   0,  67,  79, 
+     76,  79,  82,   0,  84,  69, 
+     88,  67,  79,  79,  82,  68, 
+      0, 171,  79,  83,  71,  78, 
+     44,   0,   0,   0,   1,   0, 
+      0,   0,   8,   0,   0,   0, 
+     32,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      3,   0,   0,   0,   0,   0, 
+      0,   0,  15,   0,   0,   0, 
+     83,  86,  95,  84,  97, 114, 
+    103, 101, 116,   0, 171, 171, 
+     83,  72,  69,  88, 184,   0, 
+      0,   0,  81,   0,   0,   0, 
+     46,   0,   0,   0, 106,   8, 
+      0,   1,  90,   0,   0,   6, 
+     70, 110,  48,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,  88,  24,   0,   7, 
+     70, 126,  48,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+    255, 255, 255, 255,  85,  85, 
+      0,   0,   0,   0,   0,   0, 
+     98,  16,   0,   3, 242,  16, 
+     16,   0,   1,   0,   0,   0, 
+     98,  16,   0,   3,  50,  16, 
+     16,   0,   2,   0,   0,   0, 
+    101,   0,   0,   3, 242,  32, 
+     16,   0,   0,   0,   0,   0, 
+    104,   0,   0,   2,   1,   0, 
+      0,   0,  69,   0,   0,  11, 
+    242,   0,  16,   0,   0,   0, 
+      0,   0,  70,  16,  16,   0, 
+      2,   0,   0,   0,  70, 126, 
+     32,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,  96, 
+     32,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,  56,   0, 
+      0,   7, 242,  32,  16,   0, 
+      0,   0,   0,   0,  70,  14, 
+     16,   0,   0,   0,   0,   0, 
+     70,  30,  16,   0,   1,   0, 
+      0,   0,  62,   0,   0,   1, 
+     82,  84,  83,  48, 168,   0, 
+      0,   0,   2,   0,   0,   0, 
+      2,   0,   0,   0,  24,   0, 
+      0,   0,   1,   0,   0,   0, 
+    116,   0,   0,   0,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,  48,   0, 
+      0,   0,   1,   0,   0,   0, 
+      0,   0,   0,   0, 104,   0, 
+      0,   0,   2,   0,   0,   0, 
+     56,   0,   0,   0,   2,   0, 
+      0,   0,   1,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   2,   0,   0,   0, 
+    255, 255, 255, 255,   0,   0, 
+      0,   0, 255, 255, 255, 255, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   1,   0,   0,   0, 
+    255, 255, 255, 255,   1,   0, 
+      0,   0,   0,   0,   0,   0, 
+      1,   0,   0,   0,  21,   0, 
+      0,   0,   3,   0,   0,   0, 
+      3,   0,   0,   0,   3,   0, 
+      0,   0,   0,   0,   0,   0, 
+     16,   0,   0,   0,   8,   0, 
+      0,   0,   2,   0,   0,   0, 
+      0,   0,   0,   0, 255, 255, 
+    127, 127,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0
+};

+ 168 - 0
demo/d3d12/nuklear_d3d12_vertex_shader.h

@@ -0,0 +1,168 @@
+#if 0
+//
+// Generated by Microsoft (R) D3D Shader Disassembler
+//
+//
+// Input signature:
+//
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// POSITION                 0   xy          0     NONE   float   xy  
+// COLOR                    0   xyzw        1     NONE   float   xyzw
+// TEXCOORD                 0   xy          2     NONE   float   xy  
+//
+//
+// Output signature:
+//
+// Name                 Index   Mask Register SysValue  Format   Used
+// -------------------- ----- ------ -------- -------- ------- ------
+// SV_POSITION              0   xyzw        0      POS   float   xyzw
+// COLOR                    0   xyzw        1     NONE   float   xyzw
+// TEXCOORD                 0   xy          2     NONE   float   xy  
+//
+vs_5_1
+dcl_globalFlags refactoringAllowed
+dcl_constantbuffer CB0[0:0][4], immediateIndexed, space=0
+dcl_input v0.xy
+dcl_input v1.xyzw
+dcl_input v2.xy
+dcl_output_siv o0.xyzw, position
+dcl_output o1.xyzw
+dcl_output o2.xy
+dcl_temps 1
+mul r0.xyzw, v0.yyyy, CB0[0][1].xyzw
+mad r0.xyzw, CB0[0][0].xyzw, v0.xxxx, r0.xyzw
+add o0.xyzw, r0.xyzw, CB0[0][3].xyzw
+mov o1.xyzw, v1.xyzw
+mov o2.xy, v2.xyxx
+ret 
+// Approximately 0 instruction slots used
+#endif
+
+const BYTE nk_d3d12_vertex_shader[] =
+{
+     68,  88,  66,  67, 187, 129, 
+    163,  57, 169,  94, 219, 158, 
+    174,  23,  30,  91, 108, 150, 
+    135, 141,   1,   0,   0,   0, 
+    232,   2,   0,   0,   4,   0, 
+      0,   0,  48,   0,   0,   0, 
+    160,   0,   0,   0,  20,   1, 
+      0,   0,  56,   2,   0,   0, 
+     73,  83,  71,  78, 104,   0, 
+      0,   0,   3,   0,   0,   0, 
+      8,   0,   0,   0,  80,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   3,   0, 
+      0,   0,   0,   0,   0,   0, 
+      3,   3,   0,   0,  89,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   3,   0, 
+      0,   0,   1,   0,   0,   0, 
+     15,  15,   0,   0,  95,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   3,   0, 
+      0,   0,   2,   0,   0,   0, 
+      3,   3,   0,   0,  80,  79, 
+     83,  73,  84,  73,  79,  78, 
+      0,  67,  79,  76,  79,  82, 
+      0,  84,  69,  88,  67,  79, 
+     79,  82,  68,   0,  79,  83, 
+     71,  78, 108,   0,   0,   0, 
+      3,   0,   0,   0,   8,   0, 
+      0,   0,  80,   0,   0,   0, 
+      0,   0,   0,   0,   1,   0, 
+      0,   0,   3,   0,   0,   0, 
+      0,   0,   0,   0,  15,   0, 
+      0,   0,  92,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   3,   0,   0,   0, 
+      1,   0,   0,   0,  15,   0, 
+      0,   0,  98,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   3,   0,   0,   0, 
+      2,   0,   0,   0,   3,  12, 
+      0,   0,  83,  86,  95,  80, 
+     79,  83,  73,  84,  73,  79, 
+     78,   0,  67,  79,  76,  79, 
+     82,   0,  84,  69,  88,  67, 
+     79,  79,  82,  68,   0, 171, 
+     83,  72,  69,  88,  28,   1, 
+      0,   0,  81,   0,   1,   0, 
+     71,   0,   0,   0, 106,   8, 
+      0,   1,  89,   0,   0,   7, 
+     70, 142,  48,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   4,   0, 
+      0,   0,   0,   0,   0,   0, 
+     95,   0,   0,   3,  50,  16, 
+     16,   0,   0,   0,   0,   0, 
+     95,   0,   0,   3, 242,  16, 
+     16,   0,   1,   0,   0,   0, 
+     95,   0,   0,   3,  50,  16, 
+     16,   0,   2,   0,   0,   0, 
+    103,   0,   0,   4, 242,  32, 
+     16,   0,   0,   0,   0,   0, 
+      1,   0,   0,   0, 101,   0, 
+      0,   3, 242,  32,  16,   0, 
+      1,   0,   0,   0, 101,   0, 
+      0,   3,  50,  32,  16,   0, 
+      2,   0,   0,   0, 104,   0, 
+      0,   2,   1,   0,   0,   0, 
+     56,   0,   0,   9, 242,   0, 
+     16,   0,   0,   0,   0,   0, 
+     86,  21,  16,   0,   0,   0, 
+      0,   0,  70, 142,  48,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   1,   0,   0,   0, 
+     50,   0,   0,  11, 242,   0, 
+     16,   0,   0,   0,   0,   0, 
+     70, 142,  48,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   6,  16, 
+     16,   0,   0,   0,   0,   0, 
+     70,  14,  16,   0,   0,   0, 
+      0,   0,   0,   0,   0,   9, 
+    242,  32,  16,   0,   0,   0, 
+      0,   0,  70,  14,  16,   0, 
+      0,   0,   0,   0,  70, 142, 
+     48,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   3,   0, 
+      0,   0,  54,   0,   0,   5, 
+    242,  32,  16,   0,   1,   0, 
+      0,   0,  70,  30,  16,   0, 
+      1,   0,   0,   0,  54,   0, 
+      0,   5,  50,  32,  16,   0, 
+      2,   0,   0,   0,  70,  16, 
+     16,   0,   2,   0,   0,   0, 
+     62,   0,   0,   1,  82,  84, 
+     83,  48, 168,   0,   0,   0, 
+      2,   0,   0,   0,   2,   0, 
+      0,   0,  24,   0,   0,   0, 
+      1,   0,   0,   0, 116,   0, 
+      0,   0,   1,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,  48,   0,   0,   0, 
+      1,   0,   0,   0,   0,   0, 
+      0,   0, 104,   0,   0,   0, 
+      2,   0,   0,   0,  56,   0, 
+      0,   0,   2,   0,   0,   0, 
+      1,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      2,   0,   0,   0, 255, 255, 
+    255, 255,   0,   0,   0,   0, 
+    255, 255, 255, 255,   0,   0, 
+      0,   0,   0,   0,   0,   0, 
+      1,   0,   0,   0, 255, 255, 
+    255, 255,   1,   0,   0,   0, 
+      0,   0,   0,   0,   1,   0, 
+      0,   0,  21,   0,   0,   0, 
+      3,   0,   0,   0,   3,   0, 
+      0,   0,   3,   0,   0,   0, 
+      0,   0,   0,   0,  16,   0, 
+      0,   0,   8,   0,   0,   0, 
+      2,   0,   0,   0,   0,   0, 
+      0,   0, 255, 255, 127, 127, 
+      0,   0,   0,   0,   0,   0, 
+      0,   0,   0,   0,   0,   0
+};