tess.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933
  1. /*
  2. * Copyright 2019 Daniel Gavin. All rights reserved.
  3. * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
  4. */
  5. /*
  6. * Reference(s):
  7. *
  8. * - Adaptive GPU Tessellation with Compute Shaders by Jad Khoury, Jonathan Dupuy, and Christophe Riccio
  9. * http://onrendering.com/data/papers/isubd/isubd.pdf
  10. * https://github.com/jdupuy/opengl-framework/tree/master/demo-isubd-terrain#implicit-subdivision-on-the-gpu
  11. */
  12. #include <bx/allocator.h>
  13. #include <bx/debug.h>
  14. #include <bx/file.h>
  15. #include <bx/math.h>
  16. #include "bgfx_utils.h"
  17. #include "bounds.h"
  18. #include "camera.h"
  19. #include "common.h"
  20. #include "imgui/imgui.h"
  21. namespace
  22. {
  23. static const char* s_shaderOptions[] =
  24. {
  25. "Normal",
  26. "Diffuse"
  27. };
  28. static const float s_verticesL0[] =
  29. {
  30. 0.0f, 0.0f,
  31. 1.0f, 0.0f,
  32. 0.0f, 1.0f,
  33. };
  34. static const uint32_t s_indexesL0[] = { 0u, 1u, 2u };
  35. static const float s_verticesL1[] =
  36. {
  37. 0.0f, 1.0f,
  38. 0.5f, 0.5f,
  39. 0.0f, 0.5f,
  40. 0.0f, 0.0f,
  41. 0.5f, 0.0f,
  42. 1.0f, 0.0f,
  43. };
  44. static const uint32_t s_indexesL1[] =
  45. {
  46. 1u, 0u, 2u,
  47. 1u, 2u, 3u,
  48. 1u, 3u, 4u,
  49. 1u, 4u, 5u,
  50. };
  51. static const float s_verticesL2[] =
  52. {
  53. 0.25f, 0.75f,
  54. 0.0f, 1.0f,
  55. 0.0f, 0.75f,
  56. 0.0f, 0.5f,
  57. 0.25f, 0.5f,
  58. 0.5f, 0.5f,
  59. 0.25f, 0.25f,
  60. 0.0f, 0.25f,
  61. 0.0f, 0.0f,
  62. 0.25f, 0.0f,
  63. 0.5f, 0.0f,
  64. 0.5f, 0.25f,
  65. 0.75f, 0.25f,
  66. 0.75f, 0.0f,
  67. 1.0f, 0.0f,
  68. };
  69. static const uint32_t s_indexesL2[] =
  70. {
  71. 0u, 1u, 2u,
  72. 0u, 2u, 3u,
  73. 0u, 3u, 4u,
  74. 0u, 4u, 5u,
  75. 6u, 5u, 4u,
  76. 6u, 4u, 3u,
  77. 6u, 3u, 7u,
  78. 6u, 7u, 8u,
  79. 6u, 8u, 9u,
  80. 6u, 9u, 10u,
  81. 6u, 10u, 11u,
  82. 6u, 11u, 5u,
  83. 12u, 5u, 11u,
  84. 12u, 11u, 10u,
  85. 12u, 10u, 13u,
  86. 12u, 13u, 14u,
  87. };
  88. static const float s_verticesL3[] =
  89. {
  90. 0.25f*0.5f, 0.75f*0.5f + 0.5f,
  91. 0.0f*0.5f, 1.0f*0.5f + 0.5f,
  92. 0.0f*0.5f, 0.75f*0.5f + 0.5f,
  93. 0.0f*0.5f , 0.5f*0.5f + 0.5f,
  94. 0.25f*0.5f, 0.5f*0.5f + 0.5f,
  95. 0.5f*0.5f, 0.5f*0.5f + 0.5f,
  96. 0.25f*0.5f, 0.25f*0.5f + 0.5f,
  97. 0.0f*0.5f, 0.25f*0.5f + 0.5f,
  98. 0.0f*0.5f, 0.0f*0.5f + 0.5f,
  99. 0.25f*0.5f, 0.0f*0.5f + 0.5f,
  100. 0.5f*0.5f, 0.0f*0.5f + 0.5f,
  101. 0.5f*0.5f, 0.25f*0.5f + 0.5f,
  102. 0.75f*0.5f, 0.25f*0.5f + 0.5f,
  103. 0.75f*0.5f, 0.0f*0.5f + 0.5f,
  104. 1.0f*0.5f, 0.0f*0.5f + 0.5f, //14
  105. 0.375f, 0.375f,
  106. 0.25f, 0.375f,
  107. 0.25f, 0.25f,
  108. 0.375f, 0.25f,
  109. 0.5f, 0.25f,
  110. 0.5f, 0.375f, //20
  111. 0.125f, 0.375f,
  112. 0.0f, 0.375f,
  113. 0.0f, 0.25f,
  114. 0.125f, 0.25f, //24
  115. 0.125f, 0.125f,
  116. 0.0f, 0.125f,
  117. 0.0f, 0.0f,
  118. 0.125f, 0.0f,
  119. 0.25f, 0.0f,
  120. 0.25f, 0.125f, //30
  121. 0.375f, 0.125f,
  122. 0.375f, 0.0f,
  123. 0.5f, 0.0f,
  124. 0.5f, 0.125f, //34
  125. 0.625f, 0.375f,
  126. 0.625f, 0.25f,
  127. 0.75f, 0.25f, //37
  128. 0.625f, 0.125f,
  129. 0.625f, 0.0f,
  130. 0.75f, 0.0f,
  131. 0.75f, 0.125f, //41
  132. 0.875f, 0.125f,
  133. 0.875f, 0.0f,
  134. 1.0f, 0.0f, //44
  135. };
  136. static const uint32_t s_indexesL3[] =
  137. {
  138. 0u, 1u, 2u,
  139. 0u, 2u, 3u,
  140. 0u, 3u, 4u,
  141. 0u, 4u, 5u,
  142. 6u, 5u, 4u,
  143. 6u, 4u, 3u,
  144. 6u, 3u, 7u,
  145. 6u, 7u, 8u,
  146. 6u, 8u, 9u,
  147. 6u, 9u, 10u,
  148. 6u, 10u, 11u,
  149. 6u, 11u, 5u,
  150. 12u, 5u, 11u,
  151. 12u, 11u, 10u,
  152. 12u, 10u, 13u,
  153. 12u, 13u, 14u, //End fo first big triangle
  154. 15u, 14u, 13u,
  155. 15u, 13u, 10u,
  156. 15u, 10u, 16u,
  157. 15u, 16u, 17u,
  158. 15u, 17u, 18u,
  159. 15u, 18u, 19u,
  160. 15u, 19u, 20u,
  161. 15u, 20u, 14u,
  162. 21u, 10u, 9u,
  163. 21u, 9u, 8u,
  164. 21u, 8u, 22u,
  165. 21u, 22u, 23u,
  166. 21u, 23u, 24u,
  167. 21u, 24u, 17u,
  168. 21u, 17u, 16u,
  169. 21u, 16u, 10u,
  170. 25u, 17u, 24u,
  171. 25u, 24u, 23u,
  172. 25u, 23u, 26u,
  173. 25u, 26u, 27u,
  174. 25u, 27u, 28u,
  175. 25u, 28u, 29u,
  176. 25u, 29u, 30u,
  177. 25u, 30u, 17u,
  178. 31u, 19u, 18u,
  179. 31u, 18u, 17u,
  180. 31u, 17u, 30u,
  181. 31u, 30u, 29u,
  182. 31u, 29u, 32u,
  183. 31u, 32u, 33u,
  184. 31u, 33u, 34u,
  185. 31u, 34u, 19u,
  186. 35u, 14u, 20u,
  187. 35u, 20u, 19u,
  188. 35u, 19u, 36u,
  189. 35u, 36u, 37u,
  190. 38u, 37u, 36u,
  191. 38u, 36u, 19u,
  192. 38u, 19u, 34u,
  193. 38u, 34u, 33u,
  194. 38u, 33u, 39u,
  195. 38u, 39u, 40u,
  196. 38u, 40u, 41u,
  197. 38u, 41u, 37u,
  198. 42u, 37u, 41u,
  199. 42u, 41u, 40u,
  200. 42u, 40u, 43u,
  201. 42u, 43u, 44u,
  202. };
  203. enum
  204. {
  205. PROGRAM_TERRAIN_NORMAL,
  206. PROGRAM_TERRAIN,
  207. SHADING_COUNT
  208. };
  209. enum
  210. {
  211. BUFFER_SUBD
  212. };
  213. enum
  214. {
  215. PROGRAM_SUBD_CS_LOD,
  216. PROGRAM_UPDATE_INDIRECT,
  217. PROGRAM_INIT_INDIRECT,
  218. PROGRAM_UPDATE_DRAW,
  219. PROGRAM_COUNT
  220. };
  221. enum
  222. {
  223. TERRAIN_DMAP_SAMPLER,
  224. TERRAIN_SMAP_SAMPLER,
  225. SAMPLER_COUNT
  226. };
  227. enum
  228. {
  229. TEXTURE_DMAP,
  230. TEXTURE_SMAP,
  231. TEXTURE_COUNT
  232. };
  233. constexpr int32_t kNumVec4 = 2;
  234. struct Uniforms
  235. {
  236. void init()
  237. {
  238. u_params = bgfx::createUniform("u_params", bgfx::UniformType::Vec4, kNumVec4);
  239. cull = 1;
  240. freeze = 0;
  241. gpuSubd = 3;
  242. }
  243. void submit()
  244. {
  245. bgfx::setUniform(u_params, params, kNumVec4);
  246. }
  247. void destroy()
  248. {
  249. bgfx::destroy(u_params);
  250. }
  251. union
  252. {
  253. struct
  254. {
  255. float dmapFactor;
  256. float lodFactor;
  257. float cull;
  258. float freeze;
  259. float gpuSubd;
  260. float padding0;
  261. float padding1;
  262. float padding2;
  263. };
  264. float params[kNumVec4 * 4];
  265. };
  266. bgfx::UniformHandle u_params;
  267. };
  268. class ExampleTessellation : public entry::AppI
  269. {
  270. public:
  271. ExampleTessellation(const char* _name, const char* _description, const char* _url)
  272. : entry::AppI(_name, _description, _url)
  273. {
  274. }
  275. void init(int32_t _argc, const char* const* _argv, uint32_t _width, uint32_t _height) override
  276. {
  277. Args args(_argc, _argv);
  278. m_width = _width;
  279. m_height = _height;
  280. m_debug = BGFX_DEBUG_NONE;
  281. m_reset = BGFX_RESET_NONE;
  282. bgfx::Init init;
  283. init.type = args.m_type;
  284. init.vendorId = args.m_pciId;
  285. init.resolution.width = m_width;
  286. init.resolution.height = m_height;
  287. init.resolution.reset = m_reset;
  288. bgfx::init(init);
  289. m_dmap = { "textures/dmap.png", 0.45f };
  290. m_computeThreadCount = 5;
  291. m_shading = PROGRAM_TERRAIN;
  292. m_primitivePixelLengthTarget = 7.0f;
  293. m_fovy = 60.0f;
  294. m_pingPong = 0;
  295. m_restart = true;
  296. // Enable m_debug text.
  297. bgfx::setDebug(m_debug);
  298. // Set view 0 clear state.
  299. bgfx::setViewClear(0
  300. , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH
  301. , 0x303030ff
  302. , 1.0f
  303. , 0
  304. );
  305. bgfx::setViewClear(1
  306. , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH
  307. , 0x303030ff
  308. , 1.0f
  309. , 0
  310. );
  311. // Imgui.
  312. imguiCreate();
  313. m_timeOffset = bx::getHPCounter();
  314. m_oldWidth = 0;
  315. m_oldHeight = 0;
  316. m_oldReset = m_reset;
  317. cameraCreate();
  318. cameraSetPosition({ 0.0f, 0.5f, 0.0f });
  319. cameraSetVerticalAngle(0);
  320. m_wireframe = false;
  321. m_freeze = false;
  322. m_cull = true;
  323. loadPrograms();
  324. loadBuffers();
  325. loadTextures();
  326. createAtomicCounters();
  327. m_dispatchIndirect = bgfx::createIndirectBuffer(2);
  328. }
  329. virtual int shutdown() override
  330. {
  331. // Cleanup.
  332. cameraDestroy();
  333. imguiDestroy();
  334. m_uniforms.destroy();
  335. bgfx::destroy(m_bufferCounter);
  336. bgfx::destroy(m_bufferCulledSubd);
  337. bgfx::destroy(m_bufferSubd[0]);
  338. bgfx::destroy(m_bufferSubd[1]);
  339. bgfx::destroy(m_dispatchIndirect);
  340. bgfx::destroy(m_geometryIndices);
  341. bgfx::destroy(m_geometryVertices);
  342. bgfx::destroy(m_instancedGeometryIndices);
  343. bgfx::destroy(m_instancedGeometryVertices);
  344. for (uint32_t i = 0; i < PROGRAM_COUNT; ++i)
  345. {
  346. bgfx::destroy(m_programsCompute[i]);
  347. }
  348. for (uint32_t i = 0; i < SHADING_COUNT; ++i)
  349. {
  350. bgfx::destroy(m_programsDraw[i]);
  351. }
  352. for (uint32_t i = 0; i < SAMPLER_COUNT; ++i)
  353. {
  354. bgfx::destroy(m_samplers[i]);
  355. }
  356. for (uint32_t i = 0; i < TEXTURE_COUNT; ++i)
  357. {
  358. bgfx::destroy(m_textures[i]);
  359. }
  360. // Shutdown bgfx.
  361. bgfx::shutdown();
  362. return 0;
  363. }
  364. bool update() override
  365. {
  366. if (!entry::processEvents(m_width, m_height, m_debug, m_reset, &m_mouseState) )
  367. {
  368. int64_t now = bx::getHPCounter();
  369. static int64_t last = now;
  370. const int64_t frameTime = now - last;
  371. last = now;
  372. const double freq = double(bx::getHPFrequency() );
  373. const float deltaTime = float(frameTime / freq);
  374. imguiBeginFrame(
  375. m_mouseState.m_mx
  376. , m_mouseState.m_my
  377. , (m_mouseState.m_buttons[entry::MouseButton::Left] ? IMGUI_MBUT_LEFT : 0)
  378. | (m_mouseState.m_buttons[entry::MouseButton::Right] ? IMGUI_MBUT_RIGHT : 0)
  379. | (m_mouseState.m_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0)
  380. , m_mouseState.m_mz
  381. , uint16_t(m_width)
  382. , uint16_t(m_height)
  383. );
  384. showExampleDialog(this);
  385. ImGui::SetNextWindowPos(
  386. ImVec2(m_width - m_width / 5.0f - 10.0f, 10.0f)
  387. , ImGuiCond_FirstUseEver
  388. );
  389. ImGui::SetNextWindowSize(
  390. ImVec2(m_width / 5.0f, m_height / 3.0f)
  391. , ImGuiCond_FirstUseEver
  392. );
  393. ImGui::Begin("Settings", NULL, 0);
  394. if (ImGui::Checkbox("Debug wireframe", &m_wireframe) )
  395. {
  396. bgfx::setDebug(m_wireframe
  397. ? BGFX_DEBUG_WIREFRAME
  398. : BGFX_DEBUG_NONE
  399. );
  400. }
  401. ImGui::SameLine();
  402. if (ImGui::Checkbox("Cull", &m_cull) )
  403. {
  404. m_uniforms.cull = m_cull ? 1.0f : 0.0f;
  405. }
  406. ImGui::SameLine();
  407. if (ImGui::Checkbox("Freeze subdividing", &m_freeze) )
  408. {
  409. m_uniforms.freeze = m_freeze ? 1.0f : 0.0f;
  410. }
  411. ImGui::SliderFloat("Pixels per edge", &m_primitivePixelLengthTarget, 1, 20);
  412. int gpuSlider = (int)m_uniforms.gpuSubd;
  413. if (ImGui::SliderInt("Triangle Patch level", &gpuSlider, 0, 3) )
  414. {
  415. m_restart = true;
  416. m_uniforms.gpuSubd = float(gpuSlider);
  417. }
  418. ImGui::Combo("Shading", &m_shading, s_shaderOptions, 2);
  419. ImGui::Text("Some variables require rebuilding the subdivide buffers and causes a stutter.");
  420. ImGui::End();
  421. if (!ImGui::MouseOverArea() )
  422. {
  423. // Update camera.
  424. cameraUpdate(deltaTime*0.01f, m_mouseState);
  425. }
  426. bgfx::touch(0);
  427. bgfx::touch(1);
  428. configureUniforms();
  429. cameraGetViewMtx(m_viewMtx);
  430. float model[16];
  431. bx::mtxRotateX(model, bx::toRad(90) );
  432. bx::mtxProj(m_projMtx, m_fovy, float(m_width) / float(m_height), 0.0001f, 2000.0f, bgfx::getCaps()->homogeneousDepth);
  433. // Set view 0
  434. bgfx::setViewTransform(0, m_viewMtx, m_projMtx);
  435. // Set view 1
  436. bgfx::setViewRect(1, 0, 0, uint16_t(m_width), uint16_t(m_height) );
  437. bgfx::setViewTransform(1, m_viewMtx, m_projMtx);
  438. m_uniforms.submit();
  439. // update the subd buffers
  440. if (m_restart)
  441. {
  442. m_pingPong = 1;
  443. bgfx::destroy(m_instancedGeometryVertices);
  444. bgfx::destroy(m_instancedGeometryIndices);
  445. bgfx::destroy(m_bufferSubd[BUFFER_SUBD]);
  446. bgfx::destroy(m_bufferSubd[BUFFER_SUBD + 1]);
  447. bgfx::destroy(m_bufferCulledSubd);
  448. loadInstancedGeometryBuffers();
  449. loadSubdivisionBuffers();
  450. //init indirect
  451. bgfx::setBuffer(1, m_bufferSubd[m_pingPong], bgfx::Access::ReadWrite);
  452. bgfx::setBuffer(2, m_bufferCulledSubd, bgfx::Access::ReadWrite);
  453. bgfx::setBuffer(3, m_dispatchIndirect, bgfx::Access::ReadWrite);
  454. bgfx::setBuffer(4, m_bufferCounter, bgfx::Access::ReadWrite);
  455. bgfx::setBuffer(8, m_bufferSubd[1 - m_pingPong], bgfx::Access::ReadWrite);
  456. bgfx::dispatch(0, m_programsCompute[PROGRAM_INIT_INDIRECT], 1, 1, 1);
  457. m_restart = false;
  458. }
  459. else
  460. {
  461. // update batch
  462. bgfx::setBuffer(3, m_dispatchIndirect, bgfx::Access::ReadWrite);
  463. bgfx::setBuffer(4, m_bufferCounter, bgfx::Access::ReadWrite);
  464. bgfx::dispatch(0, m_programsCompute[PROGRAM_UPDATE_INDIRECT], 1, 1, 1);
  465. }
  466. bgfx::setBuffer(1, m_bufferSubd[m_pingPong], bgfx::Access::ReadWrite);
  467. bgfx::setBuffer(2, m_bufferCulledSubd, bgfx::Access::ReadWrite);
  468. bgfx::setBuffer(4, m_bufferCounter, bgfx::Access::ReadWrite);
  469. bgfx::setBuffer(6, m_geometryVertices, bgfx::Access::Read);
  470. bgfx::setBuffer(7, m_geometryIndices, bgfx::Access::Read);
  471. bgfx::setBuffer(8, m_bufferSubd[1 - m_pingPong], bgfx::Access::Read);
  472. bgfx::setTransform(model);
  473. bgfx::setTexture(0, m_samplers[TERRAIN_DMAP_SAMPLER], m_textures[TEXTURE_DMAP], BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP);
  474. m_uniforms.submit();
  475. // update the subd buffer
  476. bgfx::dispatch(0, m_programsCompute[PROGRAM_SUBD_CS_LOD], m_dispatchIndirect, 1);
  477. // update draw
  478. bgfx::setBuffer(3, m_dispatchIndirect, bgfx::Access::ReadWrite);
  479. bgfx::setBuffer(4, m_bufferCounter, bgfx::Access::ReadWrite);
  480. m_uniforms.submit();
  481. bgfx::dispatch(1, m_programsCompute[PROGRAM_UPDATE_DRAW], 1, 1, 1);
  482. // render the terrain
  483. bgfx::setTexture(0, m_samplers[TERRAIN_DMAP_SAMPLER], m_textures[TEXTURE_DMAP], BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP);
  484. bgfx::setTexture(1, m_samplers[TERRAIN_SMAP_SAMPLER], m_textures[TEXTURE_SMAP], BGFX_SAMPLER_MIN_ANISOTROPIC | BGFX_SAMPLER_MAG_ANISOTROPIC);
  485. bgfx::setTransform(model);
  486. bgfx::setVertexBuffer(0, m_instancedGeometryVertices);
  487. bgfx::setIndexBuffer(m_instancedGeometryIndices);
  488. bgfx::setBuffer(2, m_bufferCulledSubd, bgfx::Access::Read);
  489. bgfx::setBuffer(3, m_geometryVertices, bgfx::Access::Read);
  490. bgfx::setBuffer(4, m_geometryIndices, bgfx::Access::Read);
  491. bgfx::setState(BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_Z | BGFX_STATE_DEPTH_TEST_LESS);
  492. m_uniforms.submit();
  493. bgfx::submit(1, m_programsDraw[m_shading], m_dispatchIndirect, 0, true);
  494. m_pingPong = 1 - m_pingPong;
  495. imguiEndFrame();
  496. // Advance to next frame. Rendering thread will be kicked to
  497. // process submitted rendering primitives.
  498. bgfx::frame(false);
  499. return true;
  500. }
  501. return false;
  502. }
  503. void createAtomicCounters()
  504. {
  505. m_bufferCounter = bgfx::createDynamicIndexBuffer(3, BGFX_BUFFER_INDEX32 | BGFX_BUFFER_COMPUTE_READ_WRITE);
  506. }
  507. void configureUniforms()
  508. {
  509. float lodFactor = 2.0f * bx::tan(bx::toRad(m_fovy) / 2.0f)
  510. / m_width * (1 << (int)m_uniforms.gpuSubd)
  511. * m_primitivePixelLengthTarget;
  512. m_uniforms.lodFactor = lodFactor;
  513. m_uniforms.dmapFactor = m_dmap.scale;
  514. }
  515. /**
  516. * Load the Terrain Program
  517. *
  518. * This program renders an adaptive terrain using the implicit subdivision
  519. * technique discribed in GPU Zen 2.
  520. **/
  521. void loadPrograms()
  522. {
  523. m_samplers[TERRAIN_DMAP_SAMPLER] = bgfx::createUniform("u_DmapSampler", bgfx::UniformType::Sampler);
  524. m_samplers[TERRAIN_SMAP_SAMPLER] = bgfx::createUniform("u_SmapSampler", bgfx::UniformType::Sampler);
  525. m_uniforms.init();
  526. m_programsDraw[PROGRAM_TERRAIN] = loadProgram("vs_terrain_render", "fs_terrain_render");
  527. m_programsDraw[PROGRAM_TERRAIN_NORMAL] = loadProgram("vs_terrain_render", "fs_terrain_render_normal");
  528. m_programsCompute[PROGRAM_SUBD_CS_LOD] = bgfx::createProgram(loadShader("cs_terrain_lod"), true);
  529. m_programsCompute[PROGRAM_UPDATE_INDIRECT] = bgfx::createProgram(loadShader("cs_terrain_update_indirect"), true);
  530. m_programsCompute[PROGRAM_UPDATE_DRAW] = bgfx::createProgram(loadShader("cs_terrain_update_draw"), true);
  531. m_programsCompute[PROGRAM_INIT_INDIRECT] = bgfx::createProgram(loadShader("cs_terrain_init"), true);
  532. }
  533. void loadSmapTexture()
  534. {
  535. int w = dmap->m_width;
  536. int h = dmap->m_height;
  537. const uint16_t *texels = (const uint16_t *)dmap->m_data;
  538. int mipcnt = dmap->m_numMips;
  539. const bgfx::Memory* mem = bgfx::alloc(w * h * 2 * sizeof(float) );
  540. float* smap = (float*)mem->data;
  541. for (int j = 0; j < h; ++j)
  542. {
  543. for (int i = 0; i < w; ++i)
  544. {
  545. int i1 = bx::max(0, i - 1);
  546. int i2 = bx::min(w - 1, i + 1);
  547. int j1 = bx::max(0, j - 1);
  548. int j2 = bx::min(h - 1, j + 1);
  549. uint16_t px_l = texels[i1 + w * j]; // in [0,2^16-1]
  550. uint16_t px_r = texels[i2 + w * j]; // in [0,2^16-1]
  551. uint16_t px_b = texels[i + w * j1]; // in [0,2^16-1]
  552. uint16_t px_t = texels[i + w * j2]; // in [0,2^16-1]
  553. float z_l = (float)px_l / 65535.0f; // in [0, 1]
  554. float z_r = (float)px_r / 65535.0f; // in [0, 1]
  555. float z_b = (float)px_b / 65535.0f; // in [0, 1]
  556. float z_t = (float)px_t / 65535.0f; // in [0, 1]
  557. float slope_x = (float)w * 0.5f * (z_r - z_l);
  558. float slope_y = (float)h * 0.5f * (z_t - z_b);
  559. smap[2 * (i + w * j)] = slope_x;
  560. smap[1 + 2 * (i + w * j)] = slope_y;
  561. }
  562. }
  563. m_textures[TEXTURE_SMAP] = bgfx::createTexture2D(
  564. (uint16_t)w
  565. , (uint16_t)h
  566. , mipcnt > 1
  567. , 1
  568. , bgfx::TextureFormat::RG32F
  569. , BGFX_TEXTURE_NONE
  570. , mem
  571. );
  572. }
  573. /**
  574. * Load the Displacement Texture
  575. *
  576. * This loads an R16 texture used as a displacement map
  577. */
  578. void loadDmapTexture()
  579. {
  580. dmap = imageLoad(m_dmap.pathToFile.getCPtr(), bgfx::TextureFormat::R16);
  581. m_textures[TEXTURE_DMAP] = bgfx::createTexture2D(
  582. (uint16_t)dmap->m_width
  583. , (uint16_t)dmap->m_height
  584. , false
  585. , 1
  586. , bgfx::TextureFormat::R16
  587. , BGFX_TEXTURE_NONE
  588. , bgfx::makeRef(dmap->m_data, dmap->m_size)
  589. );
  590. }
  591. /**
  592. * Load All Textures
  593. */
  594. void loadTextures()
  595. {
  596. loadDmapTexture();
  597. loadSmapTexture();
  598. }
  599. /**
  600. * Load the Geometry Buffer
  601. *
  602. * This procedure loads the scene geometry into an index and
  603. * vertex buffer. Here, we only load 2 triangles to define the
  604. * terrain.
  605. **/
  606. void loadGeometryBuffers()
  607. {
  608. const float vertices[] =
  609. {
  610. -1.0f, -1.0f, 0.0f, 1.0f,
  611. +1.0f, -1.0f, 0.0f, 1.0f,
  612. +1.0f, +1.0f, 0.0f, 1.0f,
  613. -1.0f, +1.0f, 0.0f, 1.0f,
  614. };
  615. const uint32_t indices[] = { 0, 1, 3, 2, 3, 1 };
  616. m_geometryLayout.begin().add(bgfx::Attrib::Position, 4, bgfx::AttribType::Float).end();
  617. m_geometryVertices = bgfx::createVertexBuffer(
  618. bgfx::copy(vertices, sizeof(vertices) )
  619. , m_geometryLayout
  620. , BGFX_BUFFER_COMPUTE_READ
  621. );
  622. m_geometryIndices = bgfx::createIndexBuffer(
  623. bgfx::copy(indices, sizeof(indices) )
  624. , BGFX_BUFFER_COMPUTE_READ | BGFX_BUFFER_INDEX32
  625. );
  626. }
  627. void loadSubdivisionBuffers()
  628. {
  629. const uint32_t bufferCapacity = 1 << 27;
  630. m_bufferSubd[BUFFER_SUBD] = bgfx::createDynamicIndexBuffer(
  631. bufferCapacity
  632. , BGFX_BUFFER_COMPUTE_READ_WRITE | BGFX_BUFFER_INDEX32
  633. );
  634. m_bufferSubd[BUFFER_SUBD + 1] = bgfx::createDynamicIndexBuffer(
  635. bufferCapacity
  636. , BGFX_BUFFER_COMPUTE_READ_WRITE | BGFX_BUFFER_INDEX32
  637. );
  638. m_bufferCulledSubd = bgfx::createDynamicIndexBuffer(
  639. bufferCapacity
  640. , BGFX_BUFFER_COMPUTE_READ_WRITE | BGFX_BUFFER_INDEX32
  641. );
  642. }
  643. /**
  644. * Load All Buffers
  645. *
  646. */
  647. void loadBuffers()
  648. {
  649. loadSubdivisionBuffers();
  650. loadGeometryBuffers();
  651. loadInstancedGeometryBuffers();
  652. }
  653. /**
  654. * This will be used to instantiate a triangle grid for each subdivision
  655. * key present in the subd buffer.
  656. */
  657. void loadInstancedGeometryBuffers()
  658. {
  659. const float* vertices;
  660. const uint32_t* indexes;
  661. switch (int32_t(m_uniforms.gpuSubd) )
  662. {
  663. case 0:
  664. m_instancedMeshVertexCount = 3;
  665. m_instancedMeshPrimitiveCount = 1;
  666. vertices = s_verticesL0;
  667. indexes = s_indexesL0;
  668. break;
  669. case 1:
  670. m_instancedMeshVertexCount = 6;
  671. m_instancedMeshPrimitiveCount = 4;
  672. vertices = s_verticesL1;
  673. indexes = s_indexesL1;
  674. break;
  675. case 2:
  676. m_instancedMeshVertexCount = 15;
  677. m_instancedMeshPrimitiveCount = 16;
  678. vertices = s_verticesL2;
  679. indexes = s_indexesL2;
  680. break;
  681. default:
  682. m_instancedMeshVertexCount = 45;
  683. m_instancedMeshPrimitiveCount = 64;
  684. vertices = s_verticesL3;
  685. indexes = s_indexesL3;
  686. break;
  687. }
  688. m_instancedGeometryLayout
  689. .begin()
  690. .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float)
  691. .end();
  692. m_instancedGeometryVertices = bgfx::createVertexBuffer(
  693. bgfx::makeRef(vertices, sizeof(float) * 2 * m_instancedMeshVertexCount)
  694. , m_instancedGeometryLayout
  695. );
  696. m_instancedGeometryIndices = bgfx::createIndexBuffer(
  697. bgfx::makeRef(indexes, sizeof(uint32_t) * m_instancedMeshPrimitiveCount * 3)
  698. , BGFX_BUFFER_INDEX32
  699. );
  700. }
  701. Uniforms m_uniforms;
  702. bgfx::ProgramHandle m_programsCompute[PROGRAM_COUNT];
  703. bgfx::ProgramHandle m_programsDraw[SHADING_COUNT];
  704. bgfx::TextureHandle m_textures[TEXTURE_COUNT];
  705. bgfx::UniformHandle m_samplers[SAMPLER_COUNT];
  706. bgfx::DynamicIndexBufferHandle m_bufferSubd[2];
  707. bgfx::DynamicIndexBufferHandle m_bufferCulledSubd;
  708. bgfx::DynamicIndexBufferHandle m_bufferCounter;
  709. bgfx::IndexBufferHandle m_geometryIndices;
  710. bgfx::VertexBufferHandle m_geometryVertices;
  711. bgfx::VertexLayout m_geometryLayout;
  712. bgfx::IndexBufferHandle m_instancedGeometryIndices;
  713. bgfx::VertexBufferHandle m_instancedGeometryVertices;
  714. bgfx::VertexLayout m_instancedGeometryLayout;
  715. bgfx::IndirectBufferHandle m_dispatchIndirect;
  716. bimg::ImageContainer* dmap;
  717. float m_viewMtx[16];
  718. float m_projMtx[16];
  719. uint32_t m_width;
  720. uint32_t m_height;
  721. uint32_t m_debug;
  722. uint32_t m_reset;
  723. uint32_t m_oldWidth;
  724. uint32_t m_oldHeight;
  725. uint32_t m_oldReset;
  726. uint32_t m_instancedMeshVertexCount;
  727. uint32_t m_instancedMeshPrimitiveCount;
  728. entry::MouseState m_mouseState;
  729. int64_t m_timeOffset;
  730. struct DMap
  731. {
  732. bx::FilePath pathToFile;
  733. float scale;
  734. };
  735. DMap m_dmap;
  736. int m_computeThreadCount;
  737. int m_shading;
  738. int m_gpuSubd;
  739. int m_pingPong;
  740. float m_primitivePixelLengthTarget;
  741. float m_fovy;
  742. bool m_restart;
  743. bool m_wireframe;
  744. bool m_cull;
  745. bool m_freeze;
  746. };
  747. } // namespace
  748. ENTRY_IMPLEMENT_MAIN(
  749. ExampleTessellation
  750. , "41-tess"
  751. , "Adaptive Gpu Tessellation."
  752. , "https://bkaradzic.github.io/bgfx/examples.html#tess"
  753. );