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