nuklear_d3d12.h 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930
  1. /*
  2. * Nuklear - 1.32.0 - public domain
  3. * no warrenty implied; use at your own risk.
  4. * authored from 2015-2016 by Micha Mettke
  5. *
  6. * D3D12 backend created by Ludwig Fuechsl (2022)
  7. */
  8. /*
  9. * ==============================================================
  10. *
  11. * API
  12. *
  13. * ===============================================================
  14. */
  15. #ifndef NK_D3D12_H_
  16. #define NK_D3D12_H_
  17. #define WIN32_LEAN_AND_MEAN
  18. #include <windows.h>
  19. /*
  20. * USAGE:
  21. * - This function will initialize a new nuklear rendering context. The context will be bound to a GLOBAL DirectX 12 rendering state.
  22. */
  23. 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);
  24. /*
  25. * USAGE:
  26. * - 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.
  27. */
  28. NK_API void nk_d3d12_font_stash_begin(struct nk_font_atlas **atlas);
  29. /*
  30. * USAGE:
  31. * - Call this function after a call to nk_d3d12_font_stash_begin(...) when all fonts have been loaded and configured.
  32. * - This function will place commands on the supplied ID3D12GraphicsCommandList.
  33. * - 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(...)
  34. */
  35. NK_API void nk_d3d12_font_stash_end(ID3D12GraphicsCommandList *command_list);
  36. /*
  37. * USAGE:
  38. * - This function will free temporary data that was allocated by nk_d3d12_font_stash_begin(...)
  39. * - Only call this function after the command list used in the nk_d3d12_font_stash_begin(...) function call has finished executing.
  40. * - It is NOT required to call this function but highly recommended.
  41. */
  42. NK_API void nk_d3d12_font_stash_cleanup();
  43. /*
  44. * USAGE:
  45. * - This function will setup the supplied texture (ID3D12Resource) for rendering custom images using the supplied D3D12_SHADER_RESOURCE_VIEW_DESC.
  46. * - This function may override any previous calls to nk_d3d12_set_user_texture(...) while using the same index.
  47. * - The returned handle can be used as texture handle to render custom images.
  48. * - The caller must keep track of the state of the texture when it comes to rendering with nk_d3d12_render(...).
  49. */
  50. 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);
  51. /*
  52. * USAGE:
  53. * - This function should be called within the user window proc to allow nuklear to listen to window events
  54. */
  55. NK_API int nk_d3d12_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
  56. /*
  57. * USAGE:
  58. * - A call to this function renders any previous placed nuklear draw calls and will flush all nuklear buffers for the next frame
  59. * - This function will place commands on the supplied ID3D12GraphicsCommandList.
  60. * - 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.
  61. * - This function will upload data to the gpu (64 + max_vertex_buffer + max_index_buffer BYTES).
  62. */
  63. NK_API void nk_d3d12_render(ID3D12GraphicsCommandList *command_list, enum nk_anti_aliasing AA);
  64. /*
  65. * USAGE:
  66. * - This function will notify nuklear that the framebuffer dimensions have changed.
  67. */
  68. NK_API void nk_d3d12_resize(int width, int height);
  69. /*
  70. * USAGE:
  71. * - This function will free the global d3d12 rendering state.
  72. */
  73. NK_API void nk_d3d12_shutdown(void);
  74. #endif
  75. /*
  76. * ==============================================================
  77. *
  78. * IMPLEMENTATION
  79. *
  80. * ===============================================================
  81. */
  82. #ifdef NK_D3D12_IMPLEMENTATION
  83. #define WIN32_LEAN_AND_MEAN
  84. #define COBJMACROS
  85. #include <d3d12.h>
  86. #include <stdlib.h>
  87. #include <stddef.h>
  88. #include <string.h>
  89. #include <float.h>
  90. #include <assert.h>
  91. #include "nuklear_d3d12_vertex_shader.h"
  92. #include "nuklear_d3d12_pixel_shader.h"
  93. struct nk_d3d12_vertex
  94. {
  95. float position[2];
  96. float uv[2];
  97. nk_byte col[4];
  98. };
  99. static struct
  100. {
  101. struct nk_context ctx;
  102. struct nk_font_atlas atlas;
  103. struct nk_buffer cmds;
  104. struct nk_draw_null_texture tex_null;
  105. unsigned int max_vertex_buffer;
  106. unsigned int max_index_buffer;
  107. unsigned int max_user_textures;
  108. D3D12_HEAP_PROPERTIES heap_prop_default;
  109. D3D12_HEAP_PROPERTIES heap_prop_upload;
  110. UINT cbv_srv_uav_desc_increment;
  111. D3D12_VIEWPORT viewport;
  112. ID3D12Device *device;
  113. ID3D12RootSignature *root_signature;
  114. ID3D12PipelineState *pipeline_state;
  115. ID3D12DescriptorHeap *desc_heap;
  116. ID3D12Resource *font_texture;
  117. ID3D12Resource *font_upload_buffer;
  118. ID3D12Resource *upload_buffer;
  119. ID3D12Resource *const_buffer;
  120. ID3D12Resource *index_buffer;
  121. ID3D12Resource *vertex_buffer;
  122. D3D12_CPU_DESCRIPTOR_HANDLE cpu_descriptor_handle;
  123. D3D12_GPU_DESCRIPTOR_HANDLE gpu_descriptor_handle;
  124. D3D12_GPU_VIRTUAL_ADDRESS gpu_vertex_buffer_address;
  125. D3D12_GPU_VIRTUAL_ADDRESS gpu_index_buffer_address;
  126. } d3d12;
  127. NK_API void
  128. nk_d3d12_render(ID3D12GraphicsCommandList *command_list, enum nk_anti_aliasing AA)
  129. {
  130. HRESULT hr;
  131. #ifdef NK_UINT_DRAW_INDEX
  132. DXGI_FORMAT index_buffer_format = DXGI_FORMAT_R32_UINT;
  133. #else
  134. DXGI_FORMAT index_buffer_format = DXGI_FORMAT_R16_UINT;
  135. #endif
  136. const UINT stride = sizeof(struct nk_d3d12_vertex);
  137. const struct nk_draw_command *cmd;
  138. UINT offset = 0;
  139. D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view;
  140. D3D12_INDEX_BUFFER_VIEW index_buffer_view;
  141. unsigned char* ptr_data;
  142. D3D12_RANGE map_range;
  143. D3D12_RESOURCE_BARRIER resource_barriers[3];
  144. /* Activate D3D12 pipeline state and config root signature */
  145. ID3D12GraphicsCommandList_SetPipelineState(command_list, d3d12.pipeline_state);
  146. ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, d3d12.root_signature);
  147. ID3D12GraphicsCommandList_SetDescriptorHeaps(command_list, 1, &d3d12.desc_heap);
  148. ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(command_list, 0, d3d12.gpu_descriptor_handle);
  149. /* Configure rendering pipeline */
  150. ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
  151. vertex_buffer_view.BufferLocation = d3d12.gpu_vertex_buffer_address;
  152. vertex_buffer_view.SizeInBytes = d3d12.max_vertex_buffer;
  153. vertex_buffer_view.StrideInBytes = stride;
  154. ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, 1, &vertex_buffer_view);
  155. index_buffer_view.BufferLocation = d3d12.gpu_index_buffer_address;
  156. index_buffer_view.Format = index_buffer_format;
  157. index_buffer_view.SizeInBytes = d3d12.max_index_buffer;
  158. ID3D12GraphicsCommandList_IASetIndexBuffer(command_list, &index_buffer_view);
  159. ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &d3d12.viewport);
  160. /* Map upload buffer to cpu accessible pointer */
  161. map_range.Begin = sizeof(float) * 4 * 4;
  162. map_range.End = map_range.Begin + d3d12.max_vertex_buffer + d3d12.max_index_buffer;
  163. hr = ID3D12Resource_Map(d3d12.upload_buffer, 0, &map_range, &ptr_data);
  164. NK_ASSERT(SUCCEEDED(hr));
  165. /* Nuklear convert and copy to upload buffer */
  166. {
  167. struct nk_convert_config config;
  168. NK_STORAGE const struct nk_draw_vertex_layout_element vertex_layout[] = {
  169. {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_d3d12_vertex, position)},
  170. {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_d3d12_vertex, uv)},
  171. {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_d3d12_vertex, col)},
  172. {NK_VERTEX_LAYOUT_END}
  173. };
  174. memset(&config, 0, sizeof(config));
  175. config.vertex_layout = vertex_layout;
  176. config.vertex_size = sizeof(struct nk_d3d12_vertex);
  177. config.vertex_alignment = NK_ALIGNOF(struct nk_d3d12_vertex);
  178. config.global_alpha = 1.0f;
  179. config.shape_AA = AA;
  180. config.line_AA = AA;
  181. config.circle_segment_count = 22;
  182. config.curve_segment_count = 22;
  183. config.arc_segment_count = 22;
  184. config.tex_null = d3d12.tex_null;
  185. struct nk_buffer vbuf, ibuf;
  186. nk_buffer_init_fixed(&vbuf, &ptr_data[sizeof(float) * 4 * 4], (size_t)d3d12.max_vertex_buffer);
  187. nk_buffer_init_fixed(&ibuf, &ptr_data[sizeof(float) * 4 * 4 + d3d12.max_vertex_buffer], (size_t)d3d12.max_index_buffer);
  188. nk_convert(&d3d12.ctx, &d3d12.cmds, &vbuf, &ibuf, &config);
  189. }
  190. /* Close mapping range */
  191. ID3D12Resource_Unmap(d3d12.upload_buffer, 0, &map_range);
  192. /* Issue GPU resource change for copying */
  193. resource_barriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
  194. resource_barriers[0].Transition.pResource = d3d12.const_buffer;
  195. resource_barriers[0].Transition.Subresource = 0;
  196. resource_barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
  197. resource_barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
  198. resource_barriers[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
  199. resource_barriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
  200. resource_barriers[1].Transition.pResource = d3d12.vertex_buffer;
  201. resource_barriers[1].Transition.Subresource = 0;
  202. resource_barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
  203. resource_barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
  204. resource_barriers[1].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
  205. resource_barriers[2].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
  206. resource_barriers[2].Transition.pResource = d3d12.index_buffer;
  207. resource_barriers[2].Transition.Subresource = 0;
  208. resource_barriers[2].Transition.StateBefore = D3D12_RESOURCE_STATE_INDEX_BUFFER;
  209. resource_barriers[2].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
  210. resource_barriers[2].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
  211. ID3D12GraphicsCommandList_ResourceBarrier(command_list, 3, resource_barriers);
  212. /* Copy from upload buffer to gpu buffers */
  213. ID3D12GraphicsCommandList_CopyBufferRegion(command_list, d3d12.const_buffer, 0, d3d12.upload_buffer, 0, sizeof(float) * 4 * 4);
  214. ID3D12GraphicsCommandList_CopyBufferRegion(command_list, d3d12.vertex_buffer, 0, d3d12.upload_buffer, sizeof(float) * 4 * 4, d3d12.max_vertex_buffer);
  215. ID3D12GraphicsCommandList_CopyBufferRegion(command_list, d3d12.index_buffer, 0, d3d12.upload_buffer, sizeof(float) * 4 * 4 + d3d12.max_vertex_buffer, d3d12.max_index_buffer);
  216. /* Issue GPU resource change for rendering */
  217. resource_barriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
  218. resource_barriers[0].Transition.pResource = d3d12.const_buffer;
  219. resource_barriers[0].Transition.Subresource = 0;
  220. resource_barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
  221. resource_barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
  222. resource_barriers[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
  223. resource_barriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
  224. resource_barriers[1].Transition.pResource = d3d12.vertex_buffer;
  225. resource_barriers[1].Transition.Subresource = 0;
  226. resource_barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
  227. resource_barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
  228. resource_barriers[1].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
  229. resource_barriers[2].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
  230. resource_barriers[2].Transition.pResource = d3d12.index_buffer;
  231. resource_barriers[2].Transition.Subresource = 0;
  232. resource_barriers[2].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
  233. resource_barriers[2].Transition.StateAfter = D3D12_RESOURCE_STATE_INDEX_BUFFER;
  234. resource_barriers[2].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
  235. ID3D12GraphicsCommandList_ResourceBarrier(command_list, 3, resource_barriers);
  236. /* Issue draw commands */
  237. nk_draw_foreach(cmd, &d3d12.ctx, &d3d12.cmds)
  238. {
  239. D3D12_RECT scissor;
  240. UINT32 texture_id;
  241. /* Only place a drawcall in case the command contains drawable data */
  242. if(cmd->elem_count)
  243. {
  244. /* Setup scissor rect */
  245. scissor.left = (LONG)cmd->clip_rect.x;
  246. scissor.right = (LONG)(cmd->clip_rect.x + cmd->clip_rect.w);
  247. scissor.top = (LONG)cmd->clip_rect.y;
  248. scissor.bottom = (LONG)(cmd->clip_rect.y + cmd->clip_rect.h);
  249. ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &scissor);
  250. /* Setup texture (index to descriptor heap table) to use for draw call */
  251. texture_id = (UINT32)cmd->texture.id;
  252. ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 1, 1, &texture_id, 0);
  253. /* Dispatch draw call */
  254. ID3D12GraphicsCommandList_DrawIndexedInstanced(command_list, (UINT)cmd->elem_count, 1, offset, 0, 0);
  255. offset += cmd->elem_count;
  256. }
  257. }
  258. /* Default nuklear context and command buffer clear */
  259. nk_clear(&d3d12.ctx);
  260. nk_buffer_clear(&d3d12.cmds);
  261. }
  262. static void
  263. nk_d3d12_get_projection_matrix(int width, int height, float *result)
  264. {
  265. const float L = 0.0f;
  266. const float R = (float)width;
  267. const float T = 0.0f;
  268. const float B = (float)height;
  269. float matrix[4][4] =
  270. {
  271. { 0.0f, 0.0f, 0.0f, 0.0f },
  272. { 0.0f, 0.0f, 0.0f, 0.0f },
  273. { 0.0f, 0.0f, 0.5f, 0.0f },
  274. { 0.0f, 0.0f, 0.5f, 1.0f },
  275. };
  276. matrix[0][0] = 2.0f / (R - L);
  277. matrix[1][1] = 2.0f / (T - B);
  278. matrix[3][0] = (R + L) / (L - R);
  279. matrix[3][1] = (T + B) / (B - T);
  280. memcpy(result, matrix, sizeof(matrix));
  281. }
  282. NK_API void
  283. nk_d3d12_resize(int width, int height)
  284. {
  285. D3D12_RANGE map_range;
  286. void* ptr_data;
  287. /* Describe area to be mapped (the upload buffer region where the constant buffer / projection matrix) lives */
  288. map_range.Begin = 0;
  289. map_range.End = sizeof(float) * 4 * 4;
  290. /* Map area to cpu accassible pointer (from upload buffer) */
  291. if (SUCCEEDED(ID3D12Resource_Map(d3d12.upload_buffer, 0, &map_range, &ptr_data)))
  292. {
  293. /* Compute projection matrix into upload buffer */
  294. nk_d3d12_get_projection_matrix(width, height, (float*)ptr_data);
  295. ID3D12Resource_Unmap(d3d12.upload_buffer, 0, &map_range);
  296. /* Update internal viewport state to relect resize changes */
  297. d3d12.viewport.Width = (float)width;
  298. d3d12.viewport.Height = (float)height;
  299. }
  300. /*
  301. NOTE:
  302. When mapping and copying succeeds, the data will still be in CPU sided memory
  303. copying to the GPU is done in the nk_d3d12_render function
  304. */
  305. }
  306. NK_API int
  307. nk_d3d12_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
  308. {
  309. switch (msg)
  310. {
  311. case WM_KEYDOWN:
  312. case WM_KEYUP:
  313. case WM_SYSKEYDOWN:
  314. case WM_SYSKEYUP:
  315. {
  316. int down = !((lparam >> 31) & 1);
  317. int ctrl = GetKeyState(VK_CONTROL) & (1 << 15);
  318. switch (wparam)
  319. {
  320. case VK_SHIFT:
  321. case VK_LSHIFT:
  322. case VK_RSHIFT:
  323. nk_input_key(&d3d12.ctx, NK_KEY_SHIFT, down);
  324. return 1;
  325. case VK_DELETE:
  326. nk_input_key(&d3d12.ctx, NK_KEY_DEL, down);
  327. return 1;
  328. case VK_RETURN:
  329. case VK_SEPARATOR:
  330. nk_input_key(&d3d12.ctx, NK_KEY_ENTER, down);
  331. return 1;
  332. case VK_TAB:
  333. nk_input_key(&d3d12.ctx, NK_KEY_TAB, down);
  334. return 1;
  335. case VK_LEFT:
  336. if (ctrl)
  337. nk_input_key(&d3d12.ctx, NK_KEY_TEXT_WORD_LEFT, down);
  338. else
  339. nk_input_key(&d3d12.ctx, NK_KEY_LEFT, down);
  340. return 1;
  341. case VK_RIGHT:
  342. if (ctrl)
  343. nk_input_key(&d3d12.ctx, NK_KEY_TEXT_WORD_RIGHT, down);
  344. else
  345. nk_input_key(&d3d12.ctx, NK_KEY_RIGHT, down);
  346. return 1;
  347. case VK_BACK:
  348. nk_input_key(&d3d12.ctx, NK_KEY_BACKSPACE, down);
  349. return 1;
  350. case VK_HOME:
  351. nk_input_key(&d3d12.ctx, NK_KEY_TEXT_START, down);
  352. nk_input_key(&d3d12.ctx, NK_KEY_SCROLL_START, down);
  353. return 1;
  354. case VK_END:
  355. nk_input_key(&d3d12.ctx, NK_KEY_TEXT_END, down);
  356. nk_input_key(&d3d12.ctx, NK_KEY_SCROLL_END, down);
  357. return 1;
  358. case VK_NEXT:
  359. nk_input_key(&d3d12.ctx, NK_KEY_SCROLL_DOWN, down);
  360. return 1;
  361. case VK_PRIOR:
  362. nk_input_key(&d3d12.ctx, NK_KEY_SCROLL_UP, down);
  363. return 1;
  364. case 'C':
  365. if (ctrl) {
  366. nk_input_key(&d3d12.ctx, NK_KEY_COPY, down);
  367. return 1;
  368. }
  369. break;
  370. case 'V':
  371. if (ctrl) {
  372. nk_input_key(&d3d12.ctx, NK_KEY_PASTE, down);
  373. return 1;
  374. }
  375. break;
  376. case 'X':
  377. if (ctrl) {
  378. nk_input_key(&d3d12.ctx, NK_KEY_CUT, down);
  379. return 1;
  380. }
  381. break;
  382. case 'Z':
  383. if (ctrl) {
  384. nk_input_key(&d3d12.ctx, NK_KEY_TEXT_UNDO, down);
  385. return 1;
  386. }
  387. break;
  388. case 'R':
  389. if (ctrl) {
  390. nk_input_key(&d3d12.ctx, NK_KEY_TEXT_REDO, down);
  391. return 1;
  392. }
  393. break;
  394. }
  395. return 0;
  396. }
  397. case WM_CHAR:
  398. if (wparam >= 32)
  399. {
  400. nk_input_unicode(&d3d12.ctx, (nk_rune)wparam);
  401. return 1;
  402. }
  403. break;
  404. case WM_LBUTTONDOWN:
  405. nk_input_button(&d3d12.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
  406. SetCapture(wnd);
  407. return 1;
  408. case WM_LBUTTONUP:
  409. nk_input_button(&d3d12.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
  410. nk_input_button(&d3d12.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
  411. ReleaseCapture();
  412. return 1;
  413. case WM_RBUTTONDOWN:
  414. nk_input_button(&d3d12.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
  415. SetCapture(wnd);
  416. return 1;
  417. case WM_RBUTTONUP:
  418. nk_input_button(&d3d12.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
  419. ReleaseCapture();
  420. return 1;
  421. case WM_MBUTTONDOWN:
  422. nk_input_button(&d3d12.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
  423. SetCapture(wnd);
  424. return 1;
  425. case WM_MBUTTONUP:
  426. nk_input_button(&d3d12.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
  427. ReleaseCapture();
  428. return 1;
  429. case WM_MOUSEWHEEL:
  430. nk_input_scroll(&d3d12.ctx, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA));
  431. return 1;
  432. case WM_MOUSEMOVE:
  433. nk_input_motion(&d3d12.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));
  434. return 1;
  435. case WM_LBUTTONDBLCLK:
  436. nk_input_button(&d3d12.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
  437. return 1;
  438. }
  439. return 0;
  440. }
  441. static void
  442. nk_d3d12_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)
  443. {
  444. (void)usr;
  445. if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL))
  446. {
  447. HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
  448. if (mem)
  449. {
  450. SIZE_T size = GlobalSize(mem) - 1;
  451. if (size)
  452. {
  453. LPCWSTR wstr = (LPCWSTR)GlobalLock(mem);
  454. if (wstr)
  455. {
  456. int utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, size / sizeof(wchar_t), NULL, 0, NULL, NULL);
  457. if (utf8size)
  458. {
  459. char* utf8 = (char*)malloc(utf8size);
  460. if (utf8)
  461. {
  462. WideCharToMultiByte(CP_UTF8, 0, wstr, size / sizeof(wchar_t), utf8, utf8size, NULL, NULL);
  463. nk_textedit_paste(edit, utf8, utf8size);
  464. free(utf8);
  465. }
  466. }
  467. GlobalUnlock(mem);
  468. }
  469. }
  470. }
  471. CloseClipboard();
  472. }
  473. }
  474. static void
  475. nk_d3d12_clipboard_copy(nk_handle usr, const char *text, int len)
  476. {
  477. (void)usr;
  478. if (OpenClipboard(NULL))
  479. {
  480. int wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
  481. if (wsize)
  482. {
  483. HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));
  484. if (mem)
  485. {
  486. wchar_t* wstr = (wchar_t*)GlobalLock(mem);
  487. if (wstr)
  488. {
  489. MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
  490. wstr[wsize] = 0;
  491. GlobalUnlock(mem);
  492. SetClipboardData(CF_UNICODETEXT, mem);
  493. }
  494. }
  495. }
  496. CloseClipboard();
  497. }
  498. }
  499. NK_API struct nk_context*
  500. nk_d3d12_init(ID3D12Device *device, int width, int height, unsigned int max_vertex_buffer, unsigned int max_index_buffer, unsigned int max_user_textures)
  501. {
  502. HRESULT hr;
  503. D3D12_CONSTANT_BUFFER_VIEW_DESC cbv;
  504. D3D12_CPU_DESCRIPTOR_HANDLE cbv_handle;
  505. /* Do plain object / ref copys */
  506. d3d12.max_vertex_buffer = max_vertex_buffer;
  507. d3d12.max_index_buffer = max_index_buffer;
  508. d3d12.max_user_textures = max_user_textures;
  509. d3d12.device = device;
  510. ID3D12Device_AddRef(device);
  511. d3d12.font_texture = NULL;
  512. d3d12.font_upload_buffer = NULL;
  513. /* Init nuklear context */
  514. nk_init_default(&d3d12.ctx, 0);
  515. d3d12.ctx.clip.copy = nk_d3d12_clipboard_copy;
  516. d3d12.ctx.clip.paste = nk_d3d12_clipboard_paste;
  517. d3d12.ctx.clip.userdata = nk_handle_ptr(0);
  518. /* Init nuklear buffer */
  519. nk_buffer_init_default(&d3d12.cmds);
  520. /* Define Heap properties */
  521. d3d12.heap_prop_default.Type = D3D12_HEAP_TYPE_DEFAULT;
  522. d3d12.heap_prop_default.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
  523. d3d12.heap_prop_default.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
  524. d3d12.heap_prop_default.CreationNodeMask = 0;
  525. d3d12.heap_prop_default.VisibleNodeMask = 0;
  526. d3d12.heap_prop_upload.Type = D3D12_HEAP_TYPE_UPLOAD;
  527. d3d12.heap_prop_upload.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
  528. d3d12.heap_prop_upload.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
  529. d3d12.heap_prop_upload.CreationNodeMask = 0;
  530. d3d12.heap_prop_upload.VisibleNodeMask = 0;
  531. /* Create data objects */
  532. /* Create upload buffer */
  533. {
  534. D3D12_RESOURCE_DESC desc;
  535. desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
  536. desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
  537. desc.Width = (sizeof(float) * 4 * 4) + max_vertex_buffer + max_index_buffer; /* Needs to hold matrix + vertices + indicies */
  538. desc.Height = 1;
  539. desc.DepthOrArraySize = 1;
  540. desc.MipLevels = 1;
  541. desc.Format = DXGI_FORMAT_UNKNOWN;
  542. desc.SampleDesc.Count = 1;
  543. desc.SampleDesc.Quality = 0;
  544. desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
  545. desc.Flags = D3D12_RESOURCE_FLAG_NONE;
  546. hr = ID3D12Device_CreateCommittedResource(device, &d3d12.heap_prop_upload, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COPY_SOURCE, NULL, &IID_ID3D12Resource, &d3d12.upload_buffer);
  547. NK_ASSERT(SUCCEEDED(hr));
  548. }
  549. /* Create constant buffer */
  550. {
  551. D3D12_RESOURCE_DESC desc;
  552. desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
  553. desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
  554. desc.Width = 256; /* Should be sizeof(float) * 4 * 4 - but this does not match how d3d12 works (min CBV size of 256) */
  555. desc.Height = 1;
  556. desc.DepthOrArraySize = 1;
  557. desc.MipLevels = 1;
  558. desc.Format = DXGI_FORMAT_UNKNOWN;
  559. desc.SampleDesc.Count = 1;
  560. desc.SampleDesc.Quality = 0;
  561. desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
  562. desc.Flags = D3D12_RESOURCE_FLAG_NONE;
  563. hr = ID3D12Device_CreateCommittedResource(device, &d3d12.heap_prop_default, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, &d3d12.const_buffer);
  564. NK_ASSERT(SUCCEEDED(hr));
  565. }
  566. /* Create vertex buffer */
  567. {
  568. D3D12_RESOURCE_DESC desc;
  569. desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
  570. desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
  571. desc.Width = max_vertex_buffer;
  572. desc.Height = 1;
  573. desc.DepthOrArraySize = 1;
  574. desc.MipLevels = 1;
  575. desc.Format = DXGI_FORMAT_UNKNOWN;
  576. desc.SampleDesc.Count = 1;
  577. desc.SampleDesc.Quality = 0;
  578. desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
  579. desc.Flags = D3D12_RESOURCE_FLAG_NONE;
  580. hr = ID3D12Device_CreateCommittedResource(device, &d3d12.heap_prop_default, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, &d3d12.vertex_buffer);
  581. NK_ASSERT(SUCCEEDED(hr));
  582. }
  583. /* Create index buffer */
  584. {
  585. D3D12_RESOURCE_DESC desc;
  586. desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
  587. desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
  588. desc.Width = max_index_buffer;
  589. desc.Height = 1;
  590. desc.DepthOrArraySize = 1;
  591. desc.MipLevels = 1;
  592. desc.Format = DXGI_FORMAT_UNKNOWN;
  593. desc.SampleDesc.Count = 1;
  594. desc.SampleDesc.Quality = 0;
  595. desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
  596. desc.Flags = D3D12_RESOURCE_FLAG_NONE;
  597. hr = ID3D12Device_CreateCommittedResource(device, &d3d12.heap_prop_default, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, &d3d12.index_buffer);
  598. NK_ASSERT(SUCCEEDED(hr));
  599. }
  600. /* Create descriptor heap for shader root signature */
  601. {
  602. D3D12_DESCRIPTOR_HEAP_DESC desc;
  603. desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
  604. desc.NumDescriptors = 2 + max_user_textures;
  605. desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
  606. desc.NodeMask = 0;
  607. ID3D12Device_CreateDescriptorHeap(device, &desc, &IID_ID3D12DescriptorHeap, &d3d12.desc_heap);
  608. }
  609. /* Get address of first handle (CPU and GPU) */
  610. ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(d3d12.desc_heap, &d3d12.cpu_descriptor_handle);
  611. ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(d3d12.desc_heap, &d3d12.gpu_descriptor_handle);
  612. /* Get addresses of vertex & index buffers */
  613. d3d12.gpu_vertex_buffer_address = ID3D12Resource_GetGPUVirtualAddress(d3d12.vertex_buffer);
  614. d3d12.gpu_index_buffer_address = ID3D12Resource_GetGPUVirtualAddress(d3d12.index_buffer);
  615. /* Get handle increment */
  616. d3d12.cbv_srv_uav_desc_increment = ID3D12Device_GetDescriptorHandleIncrementSize(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
  617. /* Create view to constant buffer */
  618. cbv.BufferLocation = ID3D12Resource_GetGPUVirtualAddress(d3d12.const_buffer);
  619. cbv.SizeInBytes = 256;
  620. cbv_handle = d3d12.cpu_descriptor_handle;
  621. ID3D12Device_CreateConstantBufferView(device, &cbv, cbv_handle);
  622. /* Create root signature */
  623. hr = ID3D12Device_CreateRootSignature(device, 0, nk_d3d12_vertex_shader, sizeof(nk_d3d12_vertex_shader), &IID_ID3D12RootSignature, &d3d12.root_signature);
  624. NK_ASSERT(SUCCEEDED(hr));
  625. /* Create pipeline state */
  626. {
  627. /* Describe input layout */
  628. const D3D12_INPUT_ELEMENT_DESC layout[] = {
  629. { "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, NK_OFFSETOF(struct nk_d3d12_vertex, position), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  630. { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, NK_OFFSETOF(struct nk_d3d12_vertex, uv), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  631. { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, NK_OFFSETOF(struct nk_d3d12_vertex, col), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  632. };
  633. /* Describe pipeline state */
  634. D3D12_GRAPHICS_PIPELINE_STATE_DESC desc;
  635. memset(&desc, 0, sizeof(desc));
  636. desc.pRootSignature = d3d12.root_signature;
  637. desc.VS.pShaderBytecode = nk_d3d12_vertex_shader;
  638. desc.VS.BytecodeLength = sizeof(nk_d3d12_vertex_shader);
  639. desc.PS.pShaderBytecode = nk_d3d12_pixel_shader;
  640. desc.PS.BytecodeLength = sizeof(nk_d3d12_pixel_shader);
  641. desc.BlendState.RenderTarget[0].BlendEnable = TRUE;
  642. desc.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
  643. desc.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
  644. desc.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
  645. desc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
  646. desc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ZERO;
  647. desc.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
  648. desc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
  649. desc.SampleMask = UINT_MAX;
  650. desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;
  651. desc.RasterizerState.CullMode= D3D12_CULL_MODE_NONE;
  652. desc.RasterizerState.DepthClipEnable = TRUE;
  653. desc.InputLayout.NumElements = _countof(layout);
  654. desc.InputLayout.pInputElementDescs = layout;
  655. desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
  656. desc.NumRenderTargets = 1;
  657. desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; /* NOTE: When using HDR rendering you might have a different framebuffer format */
  658. desc.SampleDesc.Count = 1;
  659. desc.SampleDesc.Quality = 0;
  660. desc.NodeMask = 0;
  661. /* Create PSO */
  662. hr = ID3D12Device_CreateGraphicsPipelineState(device, &desc, &IID_ID3D12PipelineState, &d3d12.pipeline_state);
  663. NK_ASSERT(SUCCEEDED(hr));
  664. }
  665. /* First time const buffer init */
  666. nk_d3d12_resize(width, height);
  667. /* viewport */
  668. d3d12.viewport.TopLeftX = 0.0f;
  669. d3d12.viewport.TopLeftY = 0.0f;
  670. d3d12.viewport.Width = (float)width;
  671. d3d12.viewport.Height = (float)height;
  672. d3d12.viewport.MinDepth = 0.0f;
  673. d3d12.viewport.MaxDepth = 1.0f;
  674. return &d3d12.ctx;
  675. }
  676. NK_API void
  677. nk_d3d12_font_stash_begin(struct nk_font_atlas **atlas)
  678. {
  679. /* Default nuklear font stash */
  680. nk_font_atlas_init_default(&d3d12.atlas);
  681. nk_font_atlas_begin(&d3d12.atlas);
  682. *atlas = &d3d12.atlas;
  683. }
  684. NK_API void
  685. nk_d3d12_font_stash_end(ID3D12GraphicsCommandList *command_list)
  686. {
  687. HRESULT hr;
  688. D3D12_TEXTURE_COPY_LOCATION cpy_src, cpy_dest;
  689. D3D12_BOX cpy_box;
  690. D3D12_RESOURCE_BARRIER resource_barrier;
  691. D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc;
  692. D3D12_CPU_DESCRIPTOR_HANDLE srv_handle;
  693. const void *image;
  694. void* ptr_data;
  695. int w, h;
  696. /* Bake nuklear font atlas */
  697. image = nk_font_atlas_bake(&d3d12.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
  698. NK_ASSERT(image);
  699. /* Create font texture */
  700. {
  701. D3D12_RESOURCE_DESC desc;
  702. desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
  703. desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
  704. desc.Width = w;
  705. desc.Height = h;
  706. desc.DepthOrArraySize = 1;
  707. desc.MipLevels = 1;
  708. desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
  709. desc.SampleDesc.Count = 1;
  710. desc.SampleDesc.Quality = 0;
  711. desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
  712. desc.Flags = D3D12_RESOURCE_FLAG_NONE;
  713. 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);
  714. NK_ASSERT(SUCCEEDED(hr));
  715. }
  716. /* Create font upload buffer */
  717. {
  718. D3D12_RESOURCE_DESC desc;
  719. desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
  720. desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
  721. desc.Width = w * h * 4;
  722. desc.Height = 1;
  723. desc.DepthOrArraySize = 1;
  724. desc.MipLevels = 1;
  725. desc.Format = DXGI_FORMAT_UNKNOWN;
  726. desc.SampleDesc.Count = 1;
  727. desc.SampleDesc.Quality = 0;
  728. desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
  729. desc.Flags = D3D12_RESOURCE_FLAG_NONE;
  730. 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);
  731. NK_ASSERT(SUCCEEDED(hr));
  732. }
  733. /* Copy image data to upload buffer */
  734. hr = ID3D12Resource_Map(d3d12.font_upload_buffer, 0, NULL, &ptr_data);
  735. NK_ASSERT(SUCCEEDED(hr));
  736. memcpy(ptr_data, image, w * h * 4);
  737. ID3D12Resource_Unmap(d3d12.font_upload_buffer, 0, NULL);
  738. /* Execute copy operation */
  739. cpy_src.pResource = d3d12.font_upload_buffer;
  740. cpy_src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
  741. cpy_src.PlacedFootprint.Offset = 0;
  742. cpy_src.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
  743. cpy_src.PlacedFootprint.Footprint.Width = w;
  744. cpy_src.PlacedFootprint.Footprint.Height = h;
  745. cpy_src.PlacedFootprint.Footprint.Depth = 1;
  746. cpy_src.PlacedFootprint.Footprint.RowPitch = w * 4;
  747. cpy_dest.pResource = d3d12.font_texture;
  748. cpy_dest.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
  749. cpy_dest.SubresourceIndex = 0;
  750. cpy_box.top = 0;
  751. cpy_box.left = 0;
  752. cpy_box.back = 1;
  753. cpy_box.bottom = h;
  754. cpy_box.right = w;
  755. cpy_box.front = 0;
  756. ID3D12GraphicsCommandList_CopyTextureRegion(command_list, &cpy_dest, 0, 0, 0, &cpy_src, &cpy_box);
  757. /* Bring texture in the right state for rendering */
  758. resource_barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
  759. resource_barrier.Transition.pResource = d3d12.font_texture;
  760. resource_barrier.Transition.Subresource = 0;
  761. resource_barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
  762. resource_barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
  763. resource_barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
  764. ID3D12GraphicsCommandList_ResourceBarrier(command_list, 1, &resource_barrier);
  765. /* Create the SRV for the font texture */
  766. srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
  767. srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
  768. srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
  769. srv_desc.Texture2D.MipLevels = 1;
  770. srv_desc.Texture2D.MostDetailedMip = 0;
  771. srv_desc.Texture2D.PlaneSlice = 0;
  772. srv_desc.Texture2D.ResourceMinLODClamp = 0.0f;
  773. srv_handle.ptr = d3d12.cpu_descriptor_handle.ptr + d3d12.cbv_srv_uav_desc_increment;
  774. ID3D12Device_CreateShaderResourceView(d3d12.device, d3d12.font_texture, &srv_desc, srv_handle);
  775. /* Done with nk atlas data. Atlas will be served with texture id 0 */
  776. nk_font_atlas_end(&d3d12.atlas, nk_handle_id(0), &d3d12.tex_null);
  777. /* Setup default font */
  778. if (d3d12.atlas.default_font)
  779. nk_style_set_font(&d3d12.ctx, &d3d12.atlas.default_font->handle);
  780. }
  781. NK_API
  782. void nk_d3d12_font_stash_cleanup()
  783. {
  784. if(d3d12.font_upload_buffer)
  785. {
  786. ID3D12Resource_Release(d3d12.font_upload_buffer);
  787. d3d12.font_upload_buffer = NULL;
  788. }
  789. }
  790. NK_API
  791. nk_bool nk_d3d12_set_user_texture(unsigned int index, ID3D12Resource* texture, const D3D12_SHADER_RESOURCE_VIEW_DESC* description, nk_handle* handle_out)
  792. {
  793. nk_bool result = nk_false;
  794. if(index < d3d12.max_user_textures)
  795. {
  796. D3D12_CPU_DESCRIPTOR_HANDLE srv_handle;
  797. /* Get handle to texture (0 - Const Buffer; 1 - Font Texture; 2 - First user texture) */
  798. srv_handle.ptr = d3d12.cpu_descriptor_handle.ptr + ((2 + index) * d3d12.cbv_srv_uav_desc_increment);
  799. /* Create SRV */
  800. ID3D12Device_CreateShaderResourceView(d3d12.device, texture, description, srv_handle);
  801. /* Set nk handle (0 - Font Texture; 1 - First user texture) */
  802. *handle_out = nk_handle_id(1 + index);
  803. result = nk_true;
  804. }
  805. return result;
  806. }
  807. NK_API
  808. void nk_d3d12_shutdown(void)
  809. {
  810. /* Nuklear cleanup */
  811. nk_font_atlas_clear(&d3d12.atlas);
  812. nk_buffer_free(&d3d12.cmds);
  813. nk_free(&d3d12.ctx);
  814. /* DirectX 12 cleanup */
  815. ID3D12Device_Release(d3d12.device);
  816. ID3D12PipelineState_Release(d3d12.pipeline_state);
  817. ID3D12RootSignature_Release(d3d12.root_signature);
  818. ID3D12DescriptorHeap_Release(d3d12.desc_heap);
  819. ID3D12Resource_Release(d3d12.upload_buffer);
  820. ID3D12Resource_Release(d3d12.const_buffer);
  821. ID3D12Resource_Release(d3d12.index_buffer);
  822. ID3D12Resource_Release(d3d12.vertex_buffer);
  823. if(d3d12.font_texture)
  824. ID3D12Resource_Release(d3d12.font_texture);
  825. if(d3d12.font_upload_buffer)
  826. ID3D12Resource_Release(d3d12.font_upload_buffer);
  827. }
  828. #endif