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