├── .gitignore ├── .gitmodules ├── .vs └── config │ └── applicationhost.config ├── Application ├── Application.vcxproj ├── Application.vcxproj.filters ├── Game.cpp ├── Game.h └── WinMain.cpp ├── DX11Application.png ├── DX11Base.sln ├── DX11Base ├── DX11Base.vcxproj ├── DX11Base.vcxproj.filters ├── Dx11Device.cpp ├── Dx11Device.h ├── DxMath.h ├── WindowHelper.cpp ├── WindowHelper.h └── WindowInput.h ├── LICENSE.md ├── README.md └── Resources ├── ColoredTriangles.hlsl ├── Common.hlsl ├── PostProcess.hlsl └── ToyShader.hlsl /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | *.smod 19 | 20 | # Compiled Static libraries 21 | *.lai 22 | *.la 23 | *.a 24 | *.lib 25 | 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | 31 | # Build folder 32 | x64 33 | 34 | # Visual Studio 35 | *.opendb 36 | *.db 37 | 38 | # RenderDoc 39 | *.cap 40 | 41 | # Imgui 42 | imgui.ini 43 | 44 | # Visual studio new 45 | *.ipch 46 | *.db-shm 47 | *.db-wal 48 | 49 | 50 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "imgui"] 2 | path = imgui 3 | url = https://github.com/ocornut/imgui 4 | -------------------------------------------------------------------------------- /.vs/config/applicationhost.config: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 22 | 49 | 50 | 51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | 60 | 61 | 62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | 81 |
82 |
83 | 84 |
85 |
86 |
87 |
88 |
89 |
90 | 91 |
92 |
93 |
94 |
95 |
96 | 97 |
98 |
99 |
100 | 101 |
102 |
103 | 104 |
105 |
106 | 107 |
108 |
109 |
110 | 111 | 112 |
113 |
114 |
115 |
116 |
117 |
118 | 119 |
120 |
121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 | 826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | 843 | 844 | 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 | 854 | 855 | 856 | 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | 865 | 866 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 904 | 905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | 914 | 915 | 916 | 917 | 918 | 919 | 920 | 921 | 922 | 923 | 924 | 925 | 926 | 927 | 928 | 929 | 930 | 931 | 932 | 933 | 934 | 935 | 936 | 937 | 938 | 939 | 940 | 941 | 942 | 943 | 944 | 945 | 946 | 947 | 948 | 949 | 950 | 951 | 952 | 953 | 954 | 955 | 956 | 957 | 958 | 959 | 960 | 961 | 962 | 963 | 964 | 965 | 966 | 967 | 968 | 969 | 970 | 971 | 972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 | 980 | 981 | 982 | 983 | 984 | 985 | 986 | 987 | 988 | 989 | 990 | 991 | 992 | 993 | 994 | 995 | 996 | 997 | 998 | 999 | 1000 | 1001 | 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | 1010 | 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | 1022 | 1023 | -------------------------------------------------------------------------------- /Application/Application.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {2CA77969-0EC4-4607-93CC-C63915A2C01F} 23 | Win32Proj 24 | Application 25 | 10.0.17134.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v141 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v141 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v141 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v141 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | 75 | 76 | true 77 | $(ProjectDir)..\$(Platform)\$(Configuration)\$(ProjectName)\ 78 | 79 | 80 | false 81 | 82 | 83 | true 84 | $(ProjectDir)..\$(Platform)\$(Configuration)\$(ProjectName)\ 85 | 86 | 87 | 88 | 89 | 90 | Level3 91 | Disabled 92 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 93 | true 94 | 95 | 96 | Windows 97 | true 98 | 99 | 100 | 101 | 102 | 103 | 104 | Level3 105 | Disabled 106 | _DEBUG;_WINDOWS;%(PreprocessorDefinitions);IMGUI_DISABLE_OBSOLETE_FUNCTIONS 107 | true 108 | $(SolutionDir)imgui;$(SolutionDir);%(AdditionalIncludeDirectories) 109 | 110 | 111 | Windows 112 | true 113 | dx11Base.lib;D3DCompiler.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 114 | $(TargetDir) 115 | 116 | 117 | 118 | 119 | Level3 120 | 121 | 122 | MaxSpeed 123 | true 124 | true 125 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 126 | true 127 | 128 | 129 | Windows 130 | true 131 | true 132 | true 133 | 134 | 135 | 136 | 137 | Level3 138 | 139 | 140 | Full 141 | true 142 | true 143 | NDEBUG;_WINDOWS;%(PreprocessorDefinitions);IMGUI_DISABLE_OBSOLETE_FUNCTIONS 144 | true 145 | $(IntDir) 146 | $(IntDir) 147 | $(IntDir) 148 | $(IntDir) 149 | $(SolutionDir)imgui;$(SolutionDir);%(AdditionalIncludeDirectories) 150 | 151 | 152 | Windows 153 | true 154 | true 155 | DebugFastLink 156 | dx11Base.lib;D3DCompiler.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 157 | $(TargetDir) 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | true 184 | true 185 | 186 | 187 | true 188 | true 189 | 190 | 191 | true 192 | true 193 | true 194 | true 195 | 196 | 197 | true 198 | true 199 | 200 | 201 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /Application/Application.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 10 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 11 | 12 | 13 | {26774f3f-a03e-4f83-9f4c-7164cccca514} 14 | 15 | 16 | {186851fc-d34f-4cc2-8b98-48bef49025e6} 17 | 18 | 19 | 20 | 21 | Source Files 22 | 23 | 24 | Source Files 25 | 26 | 27 | Imgui 28 | 29 | 30 | Imgui 31 | 32 | 33 | Imgui 34 | 35 | 36 | Imgui 37 | 38 | 39 | Imgui 40 | 41 | 42 | Imgui 43 | 44 | 45 | 46 | 47 | Source Files 48 | 49 | 50 | Imgui 51 | 52 | 53 | Imgui 54 | 55 | 56 | Imgui 57 | 58 | 59 | Imgui 60 | 61 | 62 | Imgui 63 | 64 | 65 | Imgui 66 | 67 | 68 | Imgui 69 | 70 | 71 | Imgui 72 | 73 | 74 | 75 | 76 | HLSL 77 | 78 | 79 | HLSL 80 | 81 | 82 | HLSL 83 | 84 | 85 | HLSL 86 | 87 | 88 | -------------------------------------------------------------------------------- /Application/Game.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Game.h" 3 | 4 | #include "windows.h" 5 | 6 | #include 7 | 8 | 9 | Game::Game() 10 | { 11 | } 12 | 13 | 14 | Game::~Game() 15 | { 16 | } 17 | 18 | 19 | void Game::loadShaders(bool firstTimeLoadShaders) 20 | { 21 | bool success = true; 22 | 23 | auto reloadShader = [&](auto** previousShader, const TCHAR* filename, const char* entryFunction, bool firstTimeLoadShaders, const Macros* macros = NULL, bool lazyCompilation = false) 24 | { 25 | if (firstTimeLoadShaders) 26 | { 27 | // The first time we want to compile the shader and make sure we fail if not succesful 28 | return reload(previousShader, filename, entryFunction, true, macros, lazyCompilation); 29 | } 30 | else 31 | { 32 | // other time we only want to make the shader dirty to schedule compilation when used 33 | (*previousShader)->markDirty(); 34 | return true; 35 | } 36 | }; 37 | 38 | const bool lazyCompilation = true; 39 | success &= reloadShader(&mVertexShader, L"Resources\\Common.hlsl", "DefaultVertexShader", firstTimeLoadShaders, nullptr, false); // No lazy compilation because it is used to create a layout 40 | success &= reloadShader(&mScreenVertexShader, L"Resources\\Common.hlsl", "ScreenTriangleVertexShader", firstTimeLoadShaders, nullptr, false); // No lazy compilation because it is used to create a layout 41 | success &= reload(&mColoredTrianglesShader, L"Resources\\ColoredTriangles.hlsl", "ColoredTrianglesPixelShader", firstTimeLoadShaders, nullptr, lazyCompilation); 42 | success &= reload(&mToyShader, L"Resources\\ToyShader.hlsl", "ToyShaderCS", firstTimeLoadShaders, nullptr, lazyCompilation); 43 | success &= reload(&mPostProcessShader, L"Resources\\PostProcess.hlsl", "PostProcessPS", firstTimeLoadShaders, nullptr, lazyCompilation); 44 | 45 | InputLayoutDesc inputLayout; 46 | appendSimpleVertexDataToInputLayout(inputLayout, "POSITION", DXGI_FORMAT_R32G32B32_FLOAT); 47 | resetComPtr(&mLayout); 48 | mVertexShader->createInputLayout(inputLayout, &mLayout); // Have a layout object with vertex stride in it 49 | } 50 | 51 | void Game::releaseShaders() 52 | { 53 | resetComPtr(&mLayout); 54 | 55 | resetPtr(&mVertexShader); 56 | resetPtr(&mScreenVertexShader); 57 | 58 | resetPtr(&mColoredTrianglesShader); 59 | resetPtr(&mToyShader); 60 | resetPtr(&mPostProcessShader); 61 | } 62 | 63 | 64 | void Game::initialise() 65 | { 66 | ////////// Load and compile shaders 67 | 68 | loadShaders(true); 69 | 70 | ////////// Create other resources 71 | 72 | D3dDevice* device = g_dx11Device->getDevice(); 73 | const D3dViewport& viewport = g_dx11Device->getBackBufferViewport(); 74 | allocateResolutionIndependentResources(); 75 | allocateResolutionDependentResources(uint32(viewport.Width), uint32(viewport.Height)); 76 | } 77 | 78 | void Game::reallocateResolutionDependent(uint32 newWidth, uint32 newHeight) 79 | { 80 | releaseResolutionDependentResources(); 81 | allocateResolutionDependentResources(newWidth, newHeight); 82 | } 83 | 84 | 85 | void Game::allocateResolutionIndependentResources() 86 | { 87 | D3dDevice* device = g_dx11Device->getDevice(); 88 | 89 | // Simple triangle geometry 90 | VertexType vertices[3]; 91 | vertices[0] = { { 0.0f, 0.0f, 0.0f } }; 92 | vertices[1] = { { 0.0f, 0.5f, 0.0f } }; 93 | vertices[2] = { { 0.5f, 0.0f, 0.0f } }; 94 | uint32 indices[3]; 95 | indices[0] = 0; 96 | indices[1] = 1; 97 | indices[2] = 2; 98 | vertexBuffer = new RenderBuffer(RenderBuffer::initVertexBufferDesc_default(sizeof(vertices)), vertices); 99 | indexBuffer = new RenderBuffer(RenderBuffer::initIndexBufferDesc_default(sizeof(indices)), indices); 100 | 101 | mConstantBuffer = new CommonConstantBuffer(); 102 | 103 | uint32 bufferElementSize = (sizeof(float) * 4); 104 | uint32 bufferElementCount = 1024; 105 | D3dBufferDesc someBufferDesc = { bufferElementCount * bufferElementSize , D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS, 0, 0, 0 }; 106 | mSomeBuffer = new RenderBuffer(someBufferDesc); 107 | 108 | D3dUnorderedAccessViewDesc someBufferUavViewDesc; 109 | someBufferUavViewDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; 110 | someBufferUavViewDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; 111 | someBufferUavViewDesc.Buffer.FirstElement = 0; 112 | someBufferUavViewDesc.Buffer.NumElements = bufferElementCount; 113 | someBufferUavViewDesc.Buffer.Flags = 0; // D3D11_BUFFER_UAV_FLAG_RAW 114 | HRESULT hr = device->CreateUnorderedAccessView(mSomeBuffer->mBuffer, &someBufferUavViewDesc, &mSomeBufferUavView); 115 | ATLASSERT(hr == S_OK); 116 | 117 | mDefaultDepthStencilState = new DepthStencilState(DepthStencilState::initDefaultDepthOnStencilOff()); 118 | mDefaultRasterizerState = new RasterizerState(RasterizerState::initDefaultState()); 119 | mDefaultBlendState = new BlendState(BlendState::initDisabledState()); 120 | } 121 | 122 | void Game::releaseResolutionIndependentResources() 123 | { 124 | resetPtr(&mConstantBuffer); 125 | resetPtr(&indexBuffer); 126 | resetPtr(&vertexBuffer); 127 | 128 | resetComPtr(&mSomeBufferUavView); 129 | resetPtr(&mSomeBuffer); 130 | 131 | resetPtr(&mDefaultDepthStencilState); 132 | resetPtr(&mDefaultBlendState); 133 | resetPtr(&mDefaultRasterizerState); 134 | } 135 | 136 | void Game::allocateResolutionDependentResources(uint32 newWidth, uint32 newHeight) 137 | { 138 | mBackBufferDepth = new Texture2D(Texture2D::initDepthStencilBuffer(newWidth, newHeight, false)); 139 | mBackBufferHdr = new Texture2D(Texture2D::initDefault(DXGI_FORMAT_R32G32B32A32_FLOAT, newWidth, newHeight, true, true)); 140 | } 141 | 142 | void Game::releaseResolutionDependentResources() 143 | { 144 | resetPtr(&mBackBufferHdr); 145 | resetPtr(&mBackBufferDepth); 146 | } 147 | 148 | void Game::shutdown() 149 | { 150 | ////////// Release resources 151 | 152 | releaseResolutionIndependentResources(); 153 | releaseResolutionDependentResources(); 154 | 155 | ////////// Release shaders 156 | 157 | releaseShaders(); 158 | } 159 | 160 | void Game::update(const WindowInputData& inputData) 161 | { 162 | for (auto& event : inputData.mInputEvents) 163 | { 164 | // Process events 165 | } 166 | 167 | // Listen to CTRL+S for shader live update in a very simple fashion (from http://www.lofibucket.com/articles/64k_intro.html) 168 | static ULONGLONG lastLoadTime = GetTickCount64(); 169 | if (GetAsyncKeyState(VK_CONTROL) && GetAsyncKeyState('S')) 170 | { 171 | const ULONGLONG tickCount = GetTickCount64(); 172 | if (tickCount - lastLoadTime > 200) 173 | { 174 | Sleep(100); // Wait for a while to let the file system finish the file write. 175 | loadShaders(false); // Reload (all) the shaders 176 | } 177 | lastLoadTime = tickCount; 178 | } 179 | } 180 | 181 | 182 | void Game::render() 183 | { 184 | GPU_SCOPED_TIMEREVENT(GameRender, 75, 75, 75); 185 | 186 | const D3dViewport& backBufferViewport = g_dx11Device->getBackBufferViewport(); 187 | D3dRenderContext* context = g_dx11Device->getDeviceContext(); 188 | D3dRenderTargetView* backBuffer = g_dx11Device->getBackBufferRT(); 189 | 190 | // Constant buffer update 191 | { 192 | XMMATRIX viewMatrix = XMMatrixIdentity(); 193 | XMMATRIX projMatrix = XMMatrixOrthographicLH(1.0, 1.0, -1.0, 1.0); 194 | XMMATRIX mViewProjMat = XMMatrixMultiply(viewMatrix, projMatrix); 195 | 196 | CommonConstantBufferStructure cb; 197 | cb.gViewProjMat = mViewProjMat; 198 | cb.gColor = { 0.0, 1.0, 1.0, 1.0 }; 199 | cb.gResolution[0] = uint32(backBufferViewport.Width); 200 | cb.gResolution[1] = uint32(backBufferViewport.Height); 201 | mConstantBuffer->update(cb); 202 | } 203 | 204 | // Set default state 205 | { 206 | context->OMSetDepthStencilState(mDefaultDepthStencilState->mState, 0); 207 | context->OMSetBlendState(mDefaultBlendState->mState, nullptr, 0xffffffff); 208 | context->RSSetState(mDefaultRasterizerState->mState); 209 | context->RSSetViewports(1, &backBufferViewport); 210 | } 211 | 212 | // Clear the HDR back buffer 213 | { 214 | GPU_SCOPED_TIMER(Clear, 34, 177, 76); 215 | 216 | D3DCOLORVALUE clearColor = { 0.1f, 0.2f, 0.4f, 1.0f }; 217 | context->ClearRenderTargetView(mBackBufferHdr->mRenderTargetView, &clearColor.r); 218 | context->ClearDepthStencilView(mBackBufferDepth->mDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);; 219 | } 220 | 221 | // Render a shader toy using compute 222 | { 223 | GPU_SCOPED_TIMEREVENT(ShaderToy, 34, 177, 76); 224 | 225 | mToyShader->setShader(*context); 226 | context->CSSetConstantBuffers(0, 1, &mConstantBuffer->mBuffer); 227 | context->CSSetUnorderedAccessViews(0, 1, &mBackBufferHdr->mUnorderedAccessView, nullptr); 228 | 229 | int32 sX = divRoundUp(uint32(backBufferViewport.Width), 8); 230 | int32 sY = divRoundUp(uint32(backBufferViewport.Height), 8); 231 | 232 | context->Dispatch(sX, sY, 1); 233 | g_dx11Device->setNullCsResources(context); 234 | g_dx11Device->setNullCsUnorderedAccessViews(context); 235 | } 236 | 237 | context->OMSetRenderTargetsAndUnorderedAccessViews(1, &mBackBufferHdr->mRenderTargetView, mBackBufferDepth->mDepthStencilView, 0, 0, nullptr, nullptr); 238 | 239 | // Render some triangles using the rasterizer 240 | { 241 | GPU_SCOPED_TIMEREVENT(Triangles, 34, 177, 76); 242 | 243 | // Set vertex buffer stride and offset. 244 | uint32 stride = sizeof(VertexType); 245 | uint32 offset = 0; 246 | context->IASetVertexBuffers(0, 1, &vertexBuffer->mBuffer, &stride, &offset); 247 | context->IASetIndexBuffer(indexBuffer->mBuffer, DXGI_FORMAT_R32_UINT, 0); 248 | context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); 249 | // Set the vertex input layout. 250 | context->IASetInputLayout(mLayout); 251 | 252 | // Final view 253 | mVertexShader->setShader(*context); 254 | mColoredTrianglesShader->setShader(*context); 255 | context->VSSetConstantBuffers(0, 1, &mConstantBuffer->mBuffer); 256 | context->PSSetConstantBuffers(0, 1, &mConstantBuffer->mBuffer); 257 | 258 | context->DrawIndexed(3, 0, 0); 259 | } 260 | 261 | // Post process into the back buffer using a pixel shader 262 | { 263 | GPU_SCOPED_TIMEREVENT(Post, 34, 177, 76); 264 | 265 | const uint32* initialCount = 0; 266 | context->OMSetRenderTargetsAndUnorderedAccessViews(1, &backBuffer, nullptr, 1, 1, &mSomeBufferUavView, initialCount); 267 | 268 | // Set null input assembly and layout 269 | context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); 270 | context->IASetInputLayout(nullptr); 271 | 272 | // Final view 273 | mScreenVertexShader->setShader(*context); 274 | mPostProcessShader->setShader(*context); 275 | context->VSSetConstantBuffers(0, 1, &mConstantBuffer->mBuffer); 276 | context->PSSetConstantBuffers(0, 1, &mConstantBuffer->mBuffer); 277 | 278 | context->PSSetShaderResources(0, 1, &mBackBufferHdr->mShaderResourceView); 279 | 280 | context->Draw(3, 0); 281 | g_dx11Device->setNullPsResources(context); 282 | } 283 | } 284 | 285 | 286 | 287 | -------------------------------------------------------------------------------- /Application/Game.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Dx11Base/WindowInput.h" 4 | #include "Dx11Base/Dx11Device.h" 5 | 6 | 7 | 8 | class Game 9 | { 10 | public: 11 | Game(); 12 | ~Game(); 13 | 14 | void initialise(); 15 | void reallocateResolutionDependent(uint32 newWidth, uint32 newHeight); 16 | void shutdown(); 17 | 18 | void update(const WindowInputData& inputData); 19 | void render(); 20 | 21 | private: 22 | 23 | /// Load/reload all shaders if compilation is succesful. 24 | /// @firstTimeLoadShaders: calls exit(0) if any of the reload/compilation failed. 25 | void loadShaders(bool firstTimeLoadShaders); 26 | /// release all shaders 27 | void releaseShaders(); 28 | 29 | void allocateResolutionIndependentResources(); 30 | void releaseResolutionIndependentResources(); 31 | void allocateResolutionDependentResources(uint32 newWidth, uint32 newHeight); 32 | void releaseResolutionDependentResources(); 33 | 34 | // Test vertex buffer 35 | struct VertexType 36 | { 37 | float position[3]; 38 | }; 39 | RenderBuffer* vertexBuffer; 40 | RenderBuffer* indexBuffer; 41 | 42 | // 43 | // Testing some GPU buffers and shaders 44 | // 45 | 46 | struct CommonConstantBufferStructure 47 | { 48 | float4x4 gViewProjMat; 49 | 50 | float4 gColor; 51 | 52 | unsigned int gResolution[2]; 53 | unsigned int pad; 54 | }; 55 | typedef ConstantBuffer CommonConstantBuffer; 56 | CommonConstantBuffer* mConstantBuffer; 57 | 58 | RenderBuffer* mSomeBuffer; 59 | D3dUnorderedAccessView* mSomeBufferUavView; 60 | 61 | DepthStencilState* mDefaultDepthStencilState; 62 | BlendState* mDefaultBlendState; 63 | RasterizerState* mDefaultRasterizerState; 64 | 65 | VertexShader* mVertexShader; 66 | VertexShader* mScreenVertexShader; 67 | PixelShader* mColoredTrianglesShader; 68 | ComputeShader*mToyShader; 69 | PixelShader* mPostProcessShader; 70 | 71 | D3dInputLayout* mLayout; 72 | 73 | Texture2D* mBackBufferHdr; 74 | Texture2D* mBackBufferDepth; 75 | 76 | }; 77 | 78 | 79 | -------------------------------------------------------------------------------- /Application/WinMain.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Dx11Base/WindowHelper.h" 3 | #include "Dx11Base/Dx11Device.h" 4 | 5 | #include "Game.h" 6 | 7 | #include 8 | #include "imgui\examples\imgui_impl_dx11.h" 9 | #include "imgui\examples\imgui_impl_win32.h" 10 | 11 | // Declaration of a Imgui function we need (see imgui_impl_win32.h) 12 | IMGUI_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); 13 | 14 | 15 | // the entry point for any Windows program 16 | int WINAPI WinMain(HINSTANCE hInstance, 17 | HINSTANCE hPrevInstance, 18 | LPSTR lpCmdLine, 19 | int nCmdShow) 20 | { 21 | static bool sVSyncEnable = true; 22 | static float sTimerGraphWidth = 16.7f; // 60FPS 23 | 24 | // Get a window size that matches the desired client size 25 | const unsigned int desiredPosX = 20; 26 | const unsigned int desiredPosY = 20; 27 | const unsigned int desiredClientWidth = 1280; 28 | const unsigned int desiredClientHeight = 720; 29 | RECT clientRect; 30 | clientRect.left = desiredPosX; 31 | clientRect.right = desiredPosX + desiredClientWidth; 32 | clientRect.bottom = desiredPosY + desiredClientHeight; 33 | clientRect.top = desiredPosY; 34 | 35 | // Create the window 36 | WindowHelper win(hInstance, clientRect, nCmdShow, L"D3D11 Application"); 37 | win.showWindow(); 38 | 39 | // Create the d3d device (a singleton since we only consider a single window) 40 | Dx11Device::initialise(win.getHwnd()); 41 | DxGpuPerformance::initialise(); 42 | 43 | // Initialise imgui 44 | ImGuiContext* imguiContext = ImGui::CreateContext(); 45 | ImGui::SetCurrentContext(imguiContext); 46 | ImGui_ImplWin32_Init(win.getHwnd()); 47 | ImGui_ImplDX11_Init(g_dx11Device->getDevice(), g_dx11Device->getDeviceContext()); 48 | // Setup style 49 | ImGui::StyleColorsDark(); 50 | //ImGui::StyleColorsClassic(); 51 | 52 | // Create the game 53 | Game game; 54 | game.initialise(); 55 | 56 | 57 | auto windowResizedCallback = [&](LPARAM lParam) 58 | { 59 | // No threading mechanism so safe to do update call from here. 60 | 61 | uint32 newWidth = LOWORD(lParam); 62 | uint32 newHeight = HIWORD(lParam); 63 | 64 | ImGui_ImplDX11_InvalidateDeviceObjects(); 65 | g_dx11Device->updateSwapChain(newWidth, newHeight); 66 | ImGui_ImplDX11_CreateDeviceObjects(); 67 | 68 | game.reallocateResolutionDependent(newWidth, newHeight); 69 | }; 70 | win.setWindowResizedCallback(windowResizedCallback); 71 | 72 | 73 | MSG msg = { 0 }; 74 | while (true) 75 | { 76 | bool msgValid = win.translateSingleMessage(msg); 77 | 78 | if (msgValid) 79 | { 80 | // Update imgui 81 | ImGui_ImplWin32_WndProcHandler(msg.hwnd, msg.message, msg.wParam, msg.lParam); 82 | ImGuiIO& io = ImGui::GetIO(); 83 | if (!(io.WantCaptureMouse || io.WantCaptureKeyboard)) 84 | { 85 | if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE) 86 | break;// process escape key 87 | 88 | if (msg.message == WM_QUIT) 89 | break; // time to quit 90 | 91 | // A message has been processed and not consumed by imgui. Send the message to the WindowProc function. 92 | DispatchMessage(&msg); 93 | } 94 | } 95 | else 96 | { 97 | DxGpuPerformance::startFrame(); 98 | const char* frameGpuTimerName = "Frame"; 99 | DxGpuPerformance::startGpuTimer(frameGpuTimerName, 150, 150, 150); 100 | 101 | ImGui_ImplWin32_NewFrame(); 102 | ImGui_ImplDX11_NewFrame(); 103 | ImGui::NewFrame(); 104 | 105 | // Game update 106 | game.update(win.getInputData()); 107 | 108 | // Game render 109 | game.render(); 110 | 111 | // Render UI 112 | { 113 | //ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiSetCond_FirstUseEver); // Normally user code doesn't need/want to call it because positions are saved in .ini file anyway. Here we just want to make the demo initial state a bit more friendly! 114 | //ImGui::ShowTestWindow(); 115 | 116 | // Gpu performance timer graph debug print 117 | const DxGpuPerformance::TimerGraphNode* timerGraphRootNode = DxGpuPerformance::getLastUpdatedTimerGraphRootNode(); 118 | if(timerGraphRootNode) 119 | { 120 | ImGui::SetNextWindowSize(ImVec2(400.0f, 400.0f), ImGuiCond_FirstUseEver); 121 | ImGui::Begin("GPU performance"); 122 | 123 | ////////////////////////////////////////////////////////////// 124 | 125 | ImGui::Checkbox("VSync", &sVSyncEnable); 126 | ImGui::SliderFloat("TimerGraphWidth (ms)", &sTimerGraphWidth, 1.0, 60.0); 127 | 128 | // Lambda function parsing the timer graph and displaying it using horizontal bars 129 | static bool(*imguiPrintTimerGraphRecurse)(const DxGpuPerformance::TimerGraphNode*, int, int) 130 | = [](const DxGpuPerformance::TimerGraphNode* node, int level, int targetLevel) -> bool 131 | { 132 | const float maxWith = ImGui::GetWindowWidth(); 133 | const float msToPixel = maxWith / sTimerGraphWidth; 134 | 135 | bool printDone = false; 136 | if (level == targetLevel) 137 | { 138 | ImU32 color = ImColor(node->r, node->g, node->b); 139 | ImGui::PushStyleColor(ImGuiCol_Button, color); 140 | ImGui::PushStyleColor(ImGuiCol_ButtonHovered, color); 141 | ImGui::PushStyleColor(ImGuiCol_ButtonActive, color); 142 | if (node->mLastDurationMs > 0.0f) 143 | { 144 | // Set cursor to the correct position and size according to when things started this day 145 | ImGui::SetCursorPosX(node->mBeginMs * msToPixel); 146 | ImGui::PushItemWidth(node->mLastDurationMs * msToPixel); 147 | 148 | char debugStr[128]; 149 | sprintf_s(debugStr, 128, "%s %.3f ms\n", node->name.c_str(), node->mLastDurationMs); 150 | ImGui::Button(debugStr, ImVec2(node->mLastDurationMs * msToPixel, 0.0f)); 151 | if (ImGui::IsItemHovered()) 152 | { 153 | ImGui::SetTooltip(debugStr); 154 | } 155 | ImGui::SameLine(); 156 | ImGui::PopItemWidth(); 157 | } 158 | printDone = true; 159 | ImGui::PopStyleColor(3); 160 | } 161 | 162 | if (level >= targetLevel) 163 | return printDone; 164 | 165 | for (auto& node : node->subGraph) 166 | { 167 | printDone |= imguiPrintTimerGraphRecurse(node, level + 1, targetLevel); 168 | } 169 | 170 | return printDone; 171 | }; 172 | 173 | ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); 174 | ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 2.0f)); 175 | ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f)); 176 | ImGui::BeginChild("Timer graph", ImVec2(0, 150), true, ImGuiWindowFlags_HorizontalScrollbar); 177 | for (int targetLevel = 0; targetLevel < 16; ++targetLevel) 178 | { 179 | bool printDone = false; 180 | for (auto& node : timerGraphRootNode->subGraph) 181 | { 182 | printDone |= imguiPrintTimerGraphRecurse(node, 0, targetLevel); 183 | } 184 | if(printDone) 185 | ImGui::NewLine(); // start a new line if anything has been printed 186 | } 187 | ImGui::EndChild(); 188 | ImGui::PopStyleVar(3); 189 | 190 | ////////////////////////////////////////////////////////////// 191 | 192 | // Lambda function parsing the timer graph and displaying it as text 193 | static void(*textPrintTimerGraphRecurse)(const DxGpuPerformance::TimerGraphNode*, int) 194 | = [](const DxGpuPerformance::TimerGraphNode* node, int level) -> void 195 | { 196 | char* levelOffset = "---------------"; // 16 chars 197 | unsigned int levelShift = 16 - 2 * level - 1; 198 | char* levelOffsetPtr = levelOffset + (levelShift<0 ? 0 : levelShift); // cheap way to add shifting to a printf 199 | 200 | char debugStr[128]; 201 | sprintf_s(debugStr, 128, "%s%s %.3f ms\n", levelOffsetPtr, node->name.c_str(), node->mLastDurationMs); 202 | #if 0 203 | OutputDebugStringA(debugStr); 204 | #else 205 | ImGui::TextColored(ImVec4(node->r, node->g, node->b, 1.0f), debugStr); 206 | #endif 207 | 208 | for (auto& node : node->subGraph) 209 | { 210 | textPrintTimerGraphRecurse(node, level + 1); 211 | } 212 | }; 213 | for (auto& node : timerGraphRootNode->subGraph) 214 | { 215 | textPrintTimerGraphRecurse(node, 0); 216 | } 217 | 218 | ////////////////////////////////////////////////////////////// 219 | 220 | ImGui::End(); 221 | } 222 | 223 | GPU_SCOPED_TIMEREVENT(Imgui, 0, 162, 232); 224 | ImGui::Render(); 225 | ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); 226 | } 227 | 228 | // Swap the back buffer 229 | g_dx11Device->swap(sVSyncEnable); 230 | DxGpuPerformance::endGpuTimer(frameGpuTimerName); 231 | DxGpuPerformance::endFrame(); 232 | 233 | // Events have all been processed in this path by the game 234 | win.clearInputEvents(); 235 | } 236 | } 237 | 238 | ImGui_ImplDX11_Shutdown(); 239 | ImGui_ImplWin32_Shutdown(); 240 | ImGui::DestroyContext(imguiContext); 241 | 242 | game.shutdown(); 243 | DxGpuPerformance::shutdown(); 244 | Dx11Device::shutdown(); 245 | 246 | // End of application 247 | return (int)msg.wParam; 248 | } 249 | 250 | 251 | -------------------------------------------------------------------------------- /DX11Application.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebh/Dx11Base/497ba82ded6c6beb169446ce03df328b984b6751/DX11Application.png -------------------------------------------------------------------------------- /DX11Base.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dx11Base", "DX11Base\dx11Base.vcxproj", "{9412077D-D368-4DBD-AACB-6DBA3618CF12}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Application", "Application\Application.vcxproj", "{2CA77969-0EC4-4607-93CC-C63915A2C01F}" 9 | ProjectSection(ProjectDependencies) = postProject 10 | {9412077D-D368-4DBD-AACB-6DBA3618CF12} = {9412077D-D368-4DBD-AACB-6DBA3618CF12} 11 | EndProjectSection 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|x64 = Debug|x64 16 | Debug|x86 = Debug|x86 17 | Release|x64 = Release|x64 18 | Release|x86 = Release|x86 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Debug|x64.ActiveCfg = Debug|x64 22 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Debug|x64.Build.0 = Debug|x64 23 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Debug|x64.Deploy.0 = Debug|x64 24 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Debug|x86.ActiveCfg = Debug|Win32 25 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Debug|x86.Build.0 = Debug|Win32 26 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Release|x64.ActiveCfg = Release|x64 27 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Release|x64.Build.0 = Release|x64 28 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Release|x86.ActiveCfg = Release|Win32 29 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Release|x86.Build.0 = Release|Win32 30 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Debug|x64.ActiveCfg = Debug|x64 31 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Debug|x64.Build.0 = Debug|x64 32 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Debug|x86.ActiveCfg = Debug|Win32 33 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Debug|x86.Build.0 = Debug|Win32 34 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Release|x64.ActiveCfg = Release|x64 35 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Release|x64.Build.0 = Release|x64 36 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Release|x86.ActiveCfg = Release|Win32 37 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Release|x86.Build.0 = Release|Win32 38 | EndGlobalSection 39 | GlobalSection(SolutionProperties) = preSolution 40 | HideSolutionNode = FALSE 41 | EndGlobalSection 42 | EndGlobal 43 | -------------------------------------------------------------------------------- /DX11Base/DX11Base.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {9412077D-D368-4DBD-AACB-6DBA3618CF12} 23 | Win32Proj 24 | DX11Base 25 | 10.0.17134.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v141 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v141 38 | true 39 | Unicode 40 | 41 | 42 | StaticLibrary 43 | true 44 | v141 45 | Unicode 46 | 47 | 48 | StaticLibrary 49 | false 50 | v141 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | 75 | 76 | true 77 | $(ProjectDir)..\$(Platform)\$(Configuration)\$(ProjectName)\ 78 | 79 | 80 | false 81 | 82 | 83 | true 84 | $(ProjectDir)..\$(Platform)\$(Configuration)\$(ProjectName)\ 85 | 86 | 87 | 88 | 89 | 90 | Level3 91 | Disabled 92 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 93 | true 94 | 95 | 96 | Windows 97 | true 98 | 99 | 100 | 101 | 102 | 103 | 104 | Level3 105 | Disabled 106 | _DEBUG;_WINDOWS;%(PreprocessorDefinitions) 107 | true 108 | 109 | 110 | Windows 111 | true 112 | D3DCompiler.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 113 | 114 | 115 | 116 | 117 | Level3 118 | 119 | 120 | MaxSpeed 121 | true 122 | true 123 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 124 | true 125 | 126 | 127 | Windows 128 | true 129 | true 130 | true 131 | 132 | 133 | 134 | 135 | Level3 136 | 137 | 138 | Full 139 | true 140 | true 141 | NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 142 | true 143 | $(IntDir) 144 | $(IntDir) 145 | $(IntDir) 146 | $(IntDir) 147 | 148 | 149 | Windows 150 | true 151 | true 152 | DebugFastLink 153 | D3DCompiler.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /DX11Base/DX11Base.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 10 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 11 | 12 | 13 | 14 | 15 | Source Files 16 | 17 | 18 | Source Files 19 | 20 | 21 | 22 | 23 | Source Files 24 | 25 | 26 | Source Files 27 | 28 | 29 | Source Files 30 | 31 | 32 | Source Files 33 | 34 | 35 | -------------------------------------------------------------------------------- /DX11Base/Dx11Device.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Dx11Device.h" 3 | #include "D3Dcompiler.h" 4 | #include "Strsafe.h" 5 | #include // _com_error 6 | #include 7 | 8 | // Good dx tutorial: http://www.directxtutorial.com/Lesson.aspx?lessonid=11-4-2 9 | // Dx debug API http://seanmiddleditch.com/direct3d-11-debug-api-tricks/, also https://msdn.microsoft.com/en-us/library/windows/desktop/ff476881(v=vs.85).aspx#Debug 10 | 11 | 12 | Dx11Device* g_dx11Device = nullptr; 13 | 14 | Dx11Device::Dx11Device() 15 | { 16 | } 17 | 18 | Dx11Device::~Dx11Device() 19 | { 20 | internalShutdown(); 21 | } 22 | 23 | void Dx11Device::initialise(const HWND& hWnd) 24 | { 25 | Dx11Device::shutdown(); 26 | 27 | g_dx11Device = new Dx11Device(); 28 | g_dx11Device->internalInitialise(hWnd); 29 | } 30 | 31 | void Dx11Device::shutdown() 32 | { 33 | delete g_dx11Device; 34 | g_dx11Device = nullptr; 35 | } 36 | 37 | void Dx11Device::internalInitialise(const HWND& hWnd) 38 | { 39 | HRESULT hr; 40 | 41 | // create a struct to hold information about the swap chain 42 | DXGI_SWAP_CHAIN_DESC scd; 43 | ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC)); 44 | 45 | // fill the swap chain description struct 46 | scd.BufferCount = 1; // one back buffer 47 | scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color 48 | scd.BufferDesc.RefreshRate.Numerator = 1; // 60fps target 49 | scd.BufferDesc.RefreshRate.Denominator = 60; // 60fps target 50 | scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used 51 | scd.OutputWindow = hWnd; // the window to be used 52 | scd.SampleDesc.Count = 1; // multisample 53 | scd.Windowed = TRUE; // windowed/full-screen mode 54 | 55 | const uint32 requestedFeatureLevelsCount = 3; 56 | const D3D_FEATURE_LEVEL requestedFeatureLevels[requestedFeatureLevelsCount] = 57 | { 58 | D3D_FEATURE_LEVEL_12_1, // Always ask for 12.1 feature level if available 59 | // other fallbacks 60 | D3D_FEATURE_LEVEL_12_0, 61 | D3D_FEATURE_LEVEL_11_1, // Always ask for 11.1 (or higher) if available 62 | }; 63 | 64 | // create a device, device context and swap chain using the information in the scd struct 65 | hr = D3D11CreateDeviceAndSwapChain(NULL, 66 | D3D_DRIVER_TYPE_HARDWARE, 67 | NULL, 68 | DX_DEBUG_EVENT|DX_DEBUG_RESOURCE_NAME ? D3D11_CREATE_DEVICE_DEBUG : NULL, 69 | requestedFeatureLevels, 70 | requestedFeatureLevelsCount, 71 | D3D11_SDK_VERSION, 72 | &scd, 73 | &mSwapchain, 74 | &mDev, 75 | NULL, 76 | &mDevcon); 77 | ATLASSERT(hr == S_OK); 78 | 79 | #if DX_DEBUG_EVENT 80 | // Could do more https://blogs.msdn.microsoft.com/chuckw/2012/11/30/direct3d-sdk-debug-layer-tricks/ 81 | // If this fails, make sure you have the graphic tools installed. (Apps/Manage optional features windows settings) 82 | hr = mDevcon->QueryInterface(__uuidof(mUserDefinedAnnotation), reinterpret_cast(&mUserDefinedAnnotation)); 83 | ATLASSERT( hr == S_OK ); 84 | #endif // DX_DEBUG_EVENT 85 | 86 | updateSwapChain(0, 0); 87 | 88 | // By default, set the back buffer as current render target and viewport (no state tracking for now...) 89 | mDevcon->OMSetRenderTargets(1, &mBackBufferRT, NULL); 90 | mDevcon->RSSetViewports(1, &mBackBufferViewport); 91 | 92 | D3D_FEATURE_LEVEL deviceFeatureLevel = mDev->GetFeatureLevel(); 93 | OutputDebugStringA("\n\nSelected D3D feature level: "); 94 | switch (deviceFeatureLevel) 95 | { 96 | case D3D_FEATURE_LEVEL_12_1: 97 | OutputDebugStringA("D3D_FEATURE_LEVEL_12_1\n\n"); 98 | break; 99 | case D3D_FEATURE_LEVEL_12_0: 100 | OutputDebugStringA("D3D_FEATURE_LEVEL_12_0\n\n"); 101 | break; 102 | case D3D_FEATURE_LEVEL_11_1: 103 | OutputDebugStringA("D3D_FEATURE_LEVEL_11_1\n\n"); 104 | break; 105 | default: 106 | ATLASSERT(false); // unhandled level string 107 | } 108 | 109 | /*D3D11_FEATURE_DATA_D3D11_OPTIONS2 featuretest; 110 | hr = mDev->CheckFeatureSupport( 111 | D3D11_FEATURE_D3D11_OPTIONS2, 112 | &featuretest, 113 | sizeof(D3D11_FEATURE_DATA_D3D11_OPTIONS2)); 114 | ATLASSERT(hr == S_OK);*/ 115 | 116 | /*D3D11_FEATURE_DATA_DOUBLES dataDouble; 117 | hr = mDev->CheckFeatureSupport(D3D11_FEATURE_DOUBLES, &dataDouble, sizeof(dataDouble)); 118 | ATLASSERT(hr == S_OK); 119 | if (!dataDouble.DoublePrecisionFloatShaderOps) 120 | { 121 | printf("No hardware support for double-precision.\n"); 122 | }*/ 123 | } 124 | 125 | void Dx11Device::internalShutdown() 126 | { 127 | // close and release all existing COM objects 128 | resetComPtr(&mBackBufferRT); 129 | resetComPtr(&mSwapchain); 130 | resetComPtr(&mDev); 131 | resetComPtr(&mDevcon); 132 | } 133 | 134 | void Dx11Device::updateSwapChain(uint32 newWidth, uint32 newHeight) 135 | { 136 | resetComPtr(&mBackBufferRT); 137 | 138 | if (newWidth > 0 && newHeight > 0) 139 | { 140 | mSwapchain->ResizeBuffers(0, newWidth, newHeight, DXGI_FORMAT_UNKNOWN, 0); 141 | 142 | // Update the back buffer RT 143 | ID3D11Texture2D* backBufferTexture;// back buffer texture 144 | mSwapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBufferTexture); 145 | mDev->CreateRenderTargetView(backBufferTexture, NULL, &mBackBufferRT); 146 | resetComPtr(&backBufferTexture); // This does not delete the object. Just release the ref we just got. 147 | 148 | mBackBufferViewport.Width = (float)newWidth; 149 | mBackBufferViewport.Height = (float)newHeight; 150 | } 151 | else 152 | { 153 | // We get here when creating a Dx11Device 154 | ID3D11Texture2D* backBufferTexture;// back buffer texture 155 | mSwapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBufferTexture); 156 | mDev->CreateRenderTargetView(backBufferTexture, NULL, &mBackBufferRT); 157 | 158 | D3dTexture2dDesc texDesc; 159 | backBufferTexture->GetDesc(&texDesc); 160 | mBackBufferViewport.TopLeftX = 0.0f; 161 | mBackBufferViewport.TopLeftY = 0.0f; 162 | mBackBufferViewport.Width = (float)texDesc.Width; 163 | mBackBufferViewport.Height = (float)texDesc.Height; 164 | mBackBufferViewport.MinDepth = 0.0f; 165 | mBackBufferViewport.MaxDepth = 1.0f; 166 | 167 | resetComPtr(&backBufferTexture); // See description above. 168 | } 169 | } 170 | 171 | void Dx11Device::swap(bool vsyncEnabled) 172 | { 173 | mSwapchain->Present(vsyncEnabled ? 1 : 0, 0); 174 | } 175 | 176 | //////////////////////////////////////////////////////////////////////////////////////////////////// 177 | //////////////////////////////////////////////////////////////////////////////////////////////////// 178 | //////////////////////////////////////////////////////////////////////////////////////////////////// 179 | 180 | 181 | RenderBuffer::RenderBuffer(D3dBufferDesc& bufferDesc, void* initialData) : 182 | mDesc(bufferDesc) 183 | { 184 | ID3D11Device* device = g_dx11Device->getDevice(); 185 | 186 | D3dSubResourceData data; 187 | data.pSysMem = initialData; 188 | data.SysMemPitch = 0; 189 | data.SysMemSlicePitch = 0; 190 | 191 | HRESULT hr = device->CreateBuffer( &mDesc, initialData ? &data : nullptr, &mBuffer); 192 | ATLASSERT(hr == S_OK); 193 | } 194 | 195 | RenderBuffer::~RenderBuffer() 196 | { 197 | resetComPtr(&mBuffer); 198 | } 199 | 200 | void RenderBuffer::map(D3D11_MAP map, ScopedMappedRenderbuffer& mappedBuffer) 201 | { 202 | // Check some state 203 | ATLASSERT( mDesc.Usage == D3D11_USAGE_DYNAMIC && (mDesc.CPUAccessFlags&D3D11_CPU_ACCESS_WRITE)!=0 ); 204 | 205 | // Reset to 0 206 | ZeroMemory(&mappedBuffer.mMappedResource, sizeof(D3D11_MAPPED_SUBRESOURCE)); 207 | 208 | D3dRenderContext* context = g_dx11Device->getDeviceContext(); 209 | context->Map(mBuffer, 0, map, 0, &mappedBuffer.mMappedResource); 210 | mappedBuffer.mMappedBuffer = mBuffer; 211 | } 212 | 213 | void RenderBuffer::unmap(ScopedMappedRenderbuffer& mappedBuffer) 214 | { 215 | if (mappedBuffer.mMappedBuffer) 216 | { 217 | D3dRenderContext* context = g_dx11Device->getDeviceContext(); 218 | context->Unmap(mappedBuffer.mMappedBuffer, 0); 219 | mappedBuffer.mMappedBuffer = nullptr; 220 | } 221 | } 222 | 223 | D3dBufferDesc RenderBuffer::initConstantBufferDesc_dynamic(uint32 byteSize) 224 | { 225 | D3dBufferDesc desc = { byteSize , D3D11_USAGE_DYNAMIC, D3D11_BIND_CONSTANT_BUFFER, D3D11_CPU_ACCESS_WRITE, 0, 0 }; 226 | return desc; 227 | } 228 | D3dBufferDesc RenderBuffer::initVertexBufferDesc_default(uint32 byteSize) 229 | { 230 | D3dBufferDesc desc = { byteSize , D3D11_USAGE_DEFAULT, D3D11_BIND_VERTEX_BUFFER, 0, 0, 0 }; 231 | return desc; 232 | } 233 | D3dBufferDesc RenderBuffer::initIndexBufferDesc_default(uint32 byteSize) 234 | { 235 | D3dBufferDesc desc = { byteSize , D3D11_USAGE_DEFAULT, D3D11_BIND_INDEX_BUFFER, 0, 0, 0 }; 236 | return desc; 237 | } 238 | D3dBufferDesc RenderBuffer::initBufferDesc_default(uint32 byteSize) 239 | { 240 | D3dBufferDesc desc = { byteSize , D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0, 0 }; 241 | return desc; 242 | } 243 | D3dBufferDesc RenderBuffer::initBufferDesc_uav(uint32 byteSize) 244 | { 245 | D3dBufferDesc desc = { byteSize , D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS, 0, 0, 0 }; 246 | return desc; 247 | } 248 | 249 | 250 | //////////////////////////////////////////////////////////////////////////////////////////////////// 251 | //////////////////////////////////////////////////////////////////////////////////////////////////// 252 | //////////////////////////////////////////////////////////////////////////////////////////////////// 253 | 254 | DXGI_FORMAT getDepthStencilViewFormatFromTypeless(DXGI_FORMAT format) 255 | { 256 | switch (format) 257 | { 258 | case DXGI_FORMAT_R16_TYPELESS: 259 | return DXGI_FORMAT_D16_UNORM; 260 | break; 261 | case DXGI_FORMAT_R24G8_TYPELESS: 262 | return DXGI_FORMAT_D24_UNORM_S8_UINT; 263 | break; 264 | case DXGI_FORMAT_R32_TYPELESS: 265 | return DXGI_FORMAT_D32_FLOAT; 266 | break; 267 | } 268 | ATLASSERT(false); // unknown format 269 | return DXGI_FORMAT_UNKNOWN; 270 | } 271 | DXGI_FORMAT getDepthShaderResourceFormatFromTypeless(DXGI_FORMAT format) 272 | { 273 | switch (format) 274 | { 275 | case DXGI_FORMAT_R16_TYPELESS: 276 | return DXGI_FORMAT_R16_UNORM; 277 | break; 278 | case DXGI_FORMAT_R24G8_TYPELESS: 279 | return DXGI_FORMAT_R24_UNORM_X8_TYPELESS; 280 | break; 281 | case DXGI_FORMAT_R32_TYPELESS: 282 | return DXGI_FORMAT_D32_FLOAT; 283 | break; 284 | } 285 | ATLASSERT(false); // unknown format 286 | return DXGI_FORMAT_UNKNOWN; 287 | } 288 | 289 | bool isFormatTypeless(DXGI_FORMAT format) 290 | { 291 | switch (format) 292 | { 293 | case DXGI_FORMAT_R32G32B32A32_TYPELESS: 294 | case DXGI_FORMAT_R32G32B32_TYPELESS: 295 | case DXGI_FORMAT_R16G16B16A16_TYPELESS: 296 | case DXGI_FORMAT_R32G32_TYPELESS: 297 | case DXGI_FORMAT_R32G8X24_TYPELESS: 298 | case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: 299 | case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: 300 | case DXGI_FORMAT_R10G10B10A2_TYPELESS: 301 | case DXGI_FORMAT_R8G8B8A8_TYPELESS: 302 | case DXGI_FORMAT_R16G16_TYPELESS: 303 | case DXGI_FORMAT_R32_TYPELESS: 304 | case DXGI_FORMAT_R24G8_TYPELESS: 305 | //case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: 306 | //case DXGI_FORMAT_X24_TYPELESS_G8_UINT: 307 | case DXGI_FORMAT_R8G8_TYPELESS: 308 | case DXGI_FORMAT_R16_TYPELESS: 309 | case DXGI_FORMAT_R8_TYPELESS: 310 | case DXGI_FORMAT_BC1_TYPELESS: 311 | case DXGI_FORMAT_BC2_TYPELESS: 312 | case DXGI_FORMAT_BC3_TYPELESS: 313 | case DXGI_FORMAT_BC4_TYPELESS: 314 | case DXGI_FORMAT_BC5_TYPELESS: 315 | case DXGI_FORMAT_B8G8R8A8_TYPELESS: 316 | case DXGI_FORMAT_B8G8R8X8_TYPELESS: 317 | case DXGI_FORMAT_BC6H_TYPELESS: 318 | case DXGI_FORMAT_BC7_TYPELESS: 319 | return true; 320 | } 321 | return false; 322 | } 323 | 324 | Texture2D::Texture2D(D3dTexture2dDesc& desc, D3dSubResourceData* initialData) : 325 | mDesc(desc) 326 | { 327 | ID3D11Device* device = g_dx11Device->getDevice(); 328 | HRESULT hr = device->CreateTexture2D(&mDesc, initialData, &mTexture); 329 | ATLASSERT(hr == S_OK); 330 | 331 | DXGI_FORMAT format = desc.Format; 332 | if (mDesc.BindFlags & D3D11_BIND_DEPTH_STENCIL) 333 | { 334 | CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(D3D11_DSV_DIMENSION_TEXTURE2D); 335 | depthStencilViewDesc.Format = getDepthStencilViewFormatFromTypeless(format); 336 | HRESULT hr = device->CreateDepthStencilView(mTexture, &depthStencilViewDesc, &mDepthStencilView); 337 | ATLASSERT(hr == S_OK); 338 | 339 | format = getDepthShaderResourceFormatFromTypeless(format); 340 | } 341 | 342 | ATLASSERT(!isFormatTypeless(format)); 343 | 344 | if (mDesc.BindFlags & D3D11_BIND_SHADER_RESOURCE) 345 | { 346 | CD3D11_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc(D3D11_SRV_DIMENSION_TEXTURE2D); 347 | shaderResourceViewDesc.Format = format; 348 | HRESULT hr = device->CreateShaderResourceView(mTexture, &shaderResourceViewDesc, &mShaderResourceView); 349 | ATLASSERT(hr == S_OK); 350 | } 351 | if (mDesc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) 352 | { 353 | CD3D11_UNORDERED_ACCESS_VIEW_DESC unorderedAccessViewDesc(D3D11_UAV_DIMENSION_TEXTURE2D); 354 | unorderedAccessViewDesc.Format = format; 355 | HRESULT hr = device->CreateUnorderedAccessView(mTexture, &unorderedAccessViewDesc, &mUnorderedAccessView); 356 | ATLASSERT(hr == S_OK); 357 | } 358 | if (mDesc.BindFlags & D3D11_BIND_RENDER_TARGET) 359 | { 360 | CD3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc(D3D11_RTV_DIMENSION_TEXTURE2D); 361 | renderTargetViewDesc.Format = format; 362 | HRESULT hr = device->CreateRenderTargetView(mTexture, &renderTargetViewDesc, &mRenderTargetView); 363 | ATLASSERT(hr == S_OK); 364 | } 365 | } 366 | Texture2D::~Texture2D() 367 | { 368 | if (mDesc.BindFlags & D3D11_BIND_DEPTH_STENCIL) 369 | { 370 | resetComPtr(&mDepthStencilView); 371 | } 372 | if (mDesc.BindFlags & D3D11_BIND_SHADER_RESOURCE) 373 | { 374 | resetComPtr(&mShaderResourceView); 375 | } 376 | if (mDesc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) 377 | { 378 | resetComPtr(&mUnorderedAccessView); 379 | } 380 | if (mDesc.BindFlags & D3D11_BIND_RENDER_TARGET) 381 | { 382 | resetComPtr(&mRenderTargetView); 383 | } 384 | resetComPtr(&mTexture); 385 | } 386 | D3dTexture2dDesc Texture2D::initDepthStencilBuffer(uint32 width, uint32 height, bool uav) 387 | { 388 | D3dTexture2dDesc desc = { 0 }; 389 | desc.Width = width; 390 | desc.Height = height; 391 | desc.MipLevels = 1; 392 | desc.ArraySize = 1; 393 | desc.Format = DXGI_FORMAT_R24G8_TYPELESS; // DXGI_FORMAT_D24_UNORM_S8_UINT; 394 | desc.SampleDesc.Count = 1; 395 | desc.SampleDesc.Quality = 0; 396 | desc.Usage = D3D11_USAGE_DEFAULT; 397 | desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_DEPTH_STENCIL | (uav ? D3D11_BIND_UNORDERED_ACCESS : 0); // cannot be D3D11_BIND_SHADER_RESOURCE 398 | desc.CPUAccessFlags = 0; 399 | desc.MiscFlags = 0; 400 | return desc; 401 | } 402 | 403 | D3dTexture2dDesc Texture2D::initDefault(DXGI_FORMAT format, uint32 width, uint32 height, bool renderTarget, bool uav) 404 | { 405 | D3dTexture2dDesc desc = { 0 }; 406 | desc.Width = width; 407 | desc.Height = height; 408 | desc.MipLevels = 1; 409 | desc.ArraySize = 1; 410 | desc.Format = format; 411 | desc.SampleDesc.Count = 1; 412 | desc.SampleDesc.Quality = 0; 413 | desc.Usage = D3D11_USAGE_DEFAULT; 414 | desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | (renderTarget ? D3D11_BIND_RENDER_TARGET : 0) | (uav ? D3D11_BIND_UNORDERED_ACCESS : 0); 415 | desc.CPUAccessFlags = 0; 416 | desc.MiscFlags = 0; 417 | return desc; 418 | } 419 | 420 | 421 | 422 | 423 | 424 | Texture3D::Texture3D(D3dTexture3dDesc& desc, D3dSubResourceData* initialData) : 425 | mDesc(desc) 426 | { 427 | ID3D11Device* device = g_dx11Device->getDevice(); 428 | HRESULT hr = device->CreateTexture3D(&mDesc, initialData, &mTexture); 429 | ATLASSERT(hr == S_OK); 430 | 431 | if (mDesc.BindFlags & D3D11_BIND_SHADER_RESOURCE) 432 | { 433 | CD3D11_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc(D3D11_SRV_DIMENSION_TEXTURE3D); 434 | shaderResourceViewDesc.Format = desc.Format; 435 | HRESULT hr = device->CreateShaderResourceView(mTexture, &shaderResourceViewDesc, &mShaderResourceView); 436 | ATLASSERT(hr == S_OK); 437 | if (desc.MipLevels > 1) 438 | { 439 | for (uint32 l = 0; l < desc.MipLevels; ++l) 440 | { 441 | shaderResourceViewDesc.Texture3D.MostDetailedMip = l; 442 | shaderResourceViewDesc.Texture3D.MipLevels = 1; 443 | 444 | ID3D11ShaderResourceView* mipShaderResourceView; 445 | hr = device->CreateShaderResourceView(mTexture, &shaderResourceViewDesc, &mipShaderResourceView); 446 | ATLASSERT(hr == S_OK); 447 | mShaderResourceViewMips.push_back(mipShaderResourceView); 448 | } 449 | } 450 | } 451 | if (mDesc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) 452 | { 453 | CD3D11_UNORDERED_ACCESS_VIEW_DESC unorderedAccessViewDesc(D3D11_UAV_DIMENSION_TEXTURE3D); 454 | unorderedAccessViewDesc.Format = desc.Format; 455 | HRESULT hr = device->CreateUnorderedAccessView(mTexture, &unorderedAccessViewDesc, &mUnorderedAccessView); 456 | ATLASSERT(hr == S_OK); 457 | if (desc.MipLevels > 1) 458 | { 459 | for (uint32 l = 0; l < desc.MipLevels; ++l) 460 | { 461 | unorderedAccessViewDesc.Texture3D.MipSlice = l; 462 | 463 | ID3D11UnorderedAccessView* mipUnorderedAccessView; 464 | hr = device->CreateUnorderedAccessView(mTexture, &unorderedAccessViewDesc, &mipUnorderedAccessView); 465 | ATLASSERT(hr == S_OK); 466 | mUnorderedAccessViewMips.push_back(mipUnorderedAccessView); 467 | } 468 | } 469 | } 470 | if (mDesc.BindFlags & D3D11_BIND_RENDER_TARGET) 471 | { 472 | CD3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc(D3D11_RTV_DIMENSION_TEXTURE3D); 473 | renderTargetViewDesc.Format = desc.Format; 474 | renderTargetViewDesc.Texture3D.MipSlice = 0; 475 | renderTargetViewDesc.Texture3D.FirstWSlice = 0; 476 | renderTargetViewDesc.Texture3D.WSize = desc.Depth; 477 | HRESULT hr = device->CreateRenderTargetView(mTexture, &renderTargetViewDesc, &mRenderTargetView); 478 | ATLASSERT(hr == S_OK); 479 | } 480 | } 481 | Texture3D::~Texture3D() 482 | { 483 | if (mDesc.BindFlags & D3D11_BIND_SHADER_RESOURCE) 484 | { 485 | resetComPtr(&mShaderResourceView); 486 | for (auto view : mShaderResourceViewMips) 487 | { 488 | resetComPtr(&view); 489 | } 490 | mShaderResourceViewMips.clear(); 491 | } 492 | if (mDesc.BindFlags & D3D11_BIND_UNORDERED_ACCESS) 493 | { 494 | resetComPtr(&mUnorderedAccessView); 495 | for (auto view : mUnorderedAccessViewMips) 496 | { 497 | resetComPtr(&view); 498 | } 499 | mUnorderedAccessViewMips.clear(); 500 | } 501 | resetComPtr(&mTexture); 502 | if (mDesc.BindFlags & D3D11_BIND_RENDER_TARGET) 503 | { 504 | resetComPtr(&mRenderTargetView); 505 | } 506 | } 507 | D3dTexture3dDesc Texture3D::initDefault(DXGI_FORMAT format, uint32 width, uint32 height, uint32 depth, bool renderTarget, bool uav) 508 | { 509 | D3dTexture3dDesc desc = { 0 }; 510 | desc.Width = width; 511 | desc.Height = height; 512 | desc.Depth = depth; 513 | desc.MipLevels = 1; 514 | desc.Format = format; 515 | desc.Usage = D3D11_USAGE_DEFAULT; 516 | desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | (renderTarget ? D3D11_BIND_RENDER_TARGET : 0) | (uav ? D3D11_BIND_UNORDERED_ACCESS : 0); 517 | desc.CPUAccessFlags = 0; 518 | desc.MiscFlags = 0; 519 | return desc; 520 | } 521 | 522 | 523 | 524 | SamplerState::SamplerState(D3dSamplerDesc& desc) 525 | { 526 | ID3D11Device* device = g_dx11Device->getDevice(); 527 | HRESULT hr = device->CreateSamplerState(&desc, &mSampler); 528 | ATLASSERT(hr == S_OK); 529 | } 530 | SamplerState::~SamplerState() 531 | { 532 | resetComPtr(&mSampler); 533 | } 534 | D3dSamplerDesc SamplerState::initLinearClamp() 535 | { 536 | D3dSamplerDesc desc = { 0 }; 537 | desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; 538 | desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; 539 | desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; 540 | desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; 541 | desc.MipLODBias = 0.0f; 542 | desc.MaxAnisotropy = 1; 543 | desc.ComparisonFunc = D3D11_COMPARISON_NEVER; 544 | desc.BorderColor[0] = desc.BorderColor[1] = desc.BorderColor[2] = desc.BorderColor[3] = 1.0f; 545 | desc.MinLOD = -FLT_MAX; 546 | desc.MaxLOD = FLT_MAX; 547 | return desc; 548 | } 549 | D3dSamplerDesc SamplerState::initPointClamp() 550 | { 551 | D3dSamplerDesc desc = { 0 }; 552 | desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; 553 | desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; 554 | desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; 555 | desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; 556 | desc.MipLODBias = 0.0f; 557 | desc.MaxAnisotropy = 1; 558 | desc.ComparisonFunc = D3D11_COMPARISON_NEVER; 559 | desc.BorderColor[0] = desc.BorderColor[1] = desc.BorderColor[2] = desc.BorderColor[3] = 1.0f; 560 | desc.MinLOD = -FLT_MAX; 561 | desc.MaxLOD = FLT_MAX; 562 | return desc; 563 | } 564 | D3dSamplerDesc SamplerState::initShadowCmpClamp() 565 | { 566 | D3dSamplerDesc desc = { 0 }; 567 | desc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT; 568 | desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; 569 | desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; 570 | desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; 571 | desc.MipLODBias = 0.0f; 572 | desc.MaxAnisotropy = 1; 573 | desc.ComparisonFunc = D3D11_COMPARISON_LESS; 574 | desc.BorderColor[0] = desc.BorderColor[1] = desc.BorderColor[2] = desc.BorderColor[3] = 1.0f; 575 | desc.MinLOD = -FLT_MAX; 576 | desc.MaxLOD = FLT_MAX; 577 | return desc; 578 | } 579 | 580 | 581 | //////////////////////////////////////////////////////////////////////////////////////////////////// 582 | //////////////////////////////////////////////////////////////////////////////////////////////////// 583 | //////////////////////////////////////////////////////////////////////////////////////////////////// 584 | 585 | 586 | DepthStencilState::DepthStencilState(D3dDepthStencilDesc& desc) 587 | { 588 | ID3D11Device* device = g_dx11Device->getDevice(); 589 | HRESULT hr = device->CreateDepthStencilState(&desc, &mState); 590 | ATLASSERT(hr == S_OK); 591 | } 592 | DepthStencilState::~DepthStencilState() 593 | { 594 | resetComPtr(&mState); 595 | } 596 | D3dDepthStencilDesc DepthStencilState::initDefaultDepthOnStencilOff() 597 | { 598 | D3dDepthStencilDesc desc = { 0 }; 599 | // Depth test parameters 600 | desc.DepthEnable = true; 601 | desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; 602 | desc.DepthFunc = D3D11_COMPARISON_LESS; 603 | // Stencil test parameters 604 | desc.StencilEnable = false; 605 | desc.StencilReadMask = 0xFF; 606 | desc.StencilWriteMask = 0xFF; 607 | // Stencil operations if pixel is front-facing 608 | desc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; 609 | desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR; 610 | desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; 611 | desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; 612 | // Stencil operations if pixel is back-facing 613 | desc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; 614 | desc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR; 615 | desc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; 616 | desc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; 617 | return desc; 618 | } 619 | D3dDepthStencilDesc DepthStencilState::initDepthNoWriteStencilOff() 620 | { 621 | D3dDepthStencilDesc desc = { 0 }; 622 | // Depth test parameters 623 | desc.DepthEnable = true; 624 | desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; 625 | desc.DepthFunc = D3D11_COMPARISON_LESS; 626 | // Stencil test parameters 627 | desc.StencilEnable = false; 628 | desc.StencilReadMask = 0xFF; 629 | desc.StencilWriteMask = 0xFF; 630 | // Stencil operations if pixel is front-facing 631 | desc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; 632 | desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR; 633 | desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; 634 | desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; 635 | // Stencil operations if pixel is back-facing 636 | desc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; 637 | desc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR; 638 | desc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; 639 | desc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; 640 | return desc; 641 | } 642 | 643 | RasterizerState::RasterizerState(D3dRasterizerDesc& desc) 644 | { 645 | ID3D11Device* device = g_dx11Device->getDevice(); 646 | HRESULT hr = device->CreateRasterizerState(&desc, &mState); 647 | ATLASSERT(hr == S_OK); 648 | } 649 | RasterizerState::~RasterizerState() 650 | { 651 | resetComPtr(&mState); 652 | } 653 | D3dRasterizerDesc RasterizerState::initDefaultState() 654 | { 655 | D3dRasterizerDesc desc = { 0 }; 656 | ZeroMemory(&desc, sizeof(D3dRasterizerDesc)); 657 | desc.AntialiasedLineEnable = FALSE; 658 | desc.CullMode = D3D11_CULL_BACK; 659 | desc.DepthBias = 0; 660 | desc.DepthBiasClamp = 0.0f; 661 | desc.DepthClipEnable = TRUE; 662 | desc.FillMode = D3D11_FILL_SOLID; 663 | desc.FrontCounterClockwise = FALSE; 664 | desc.MultisampleEnable = FALSE; 665 | desc.ScissorEnable = FALSE; 666 | desc.SlopeScaledDepthBias = 0.0f; 667 | return desc; 668 | } 669 | 670 | 671 | BlendState::BlendState(D3dBlendDesc & desc) 672 | { 673 | ID3D11Device* device = g_dx11Device->getDevice(); 674 | HRESULT hr = device->CreateBlendState(&desc, &mState); 675 | ATLASSERT(hr == S_OK); 676 | } 677 | BlendState::~BlendState() 678 | { 679 | resetComPtr(&mState); 680 | } 681 | D3dBlendDesc BlendState::initDisabledState() 682 | { 683 | D3dBlendDesc desc = { 0 }; 684 | desc.AlphaToCoverageEnable = false; 685 | desc.IndependentBlendEnable = false; 686 | desc.RenderTarget[0].BlendEnable = false; 687 | desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; 688 | desc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO; 689 | desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; 690 | desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; 691 | desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; 692 | desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; 693 | desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; 694 | return desc; 695 | } 696 | D3dBlendDesc BlendState::initPreMultBlendState() 697 | { 698 | D3dBlendDesc desc = { 0 }; 699 | desc.AlphaToCoverageEnable = false; 700 | desc.IndependentBlendEnable = false; 701 | desc.RenderTarget[0].BlendEnable = true; 702 | desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; 703 | desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; 704 | desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; // src*1 + dst*(1.0 - srcA) 705 | desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ZERO; 706 | desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA; 707 | desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; // src*0 + dst * (1.0 - srcA) 708 | desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; 709 | return desc; 710 | } 711 | D3dBlendDesc BlendState::initPreMultDualBlendState() 712 | { 713 | D3dBlendDesc desc = { 0 }; 714 | desc.AlphaToCoverageEnable = false; 715 | desc.IndependentBlendEnable = false; 716 | desc.RenderTarget[0].BlendEnable = true; 717 | desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; 718 | desc.RenderTarget[0].DestBlend = D3D11_BLEND_SRC1_COLOR; 719 | desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; // src0*1 + dst*src1 , colored transmittance + color 720 | desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ZERO; 721 | desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE; 722 | desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; // src*0 + dst*1 , keep alpha intact 723 | desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; 724 | return desc; 725 | } 726 | D3dBlendDesc BlendState::initAdditiveState() 727 | { 728 | D3dBlendDesc desc = { 0 }; 729 | desc.AlphaToCoverageEnable = false; 730 | desc.IndependentBlendEnable = false; 731 | desc.RenderTarget[0].BlendEnable = true; 732 | desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; 733 | desc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE; 734 | desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; 735 | desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; 736 | desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE; 737 | desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; 738 | desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; 739 | return desc; 740 | } 741 | 742 | 743 | //////////////////////////////////////////////////////////////////////////////////////////////////// 744 | //////////////////////////////////////////////////////////////////////////////////////////////////// 745 | //////////////////////////////////////////////////////////////////////////////////////////////////// 746 | 747 | 748 | void appendSimpleVertexDataToInputLayout(InputLayoutDesc& inputLayout, const char* semanticName, DXGI_FORMAT format) 749 | { 750 | D3dInputElementDesc desc; 751 | 752 | desc.SemanticName = semanticName; 753 | desc.SemanticIndex = 0; 754 | desc.Format = format; 755 | desc.InputSlot = 0; 756 | desc.AlignedByteOffset = inputLayout.empty() ? 0 : D3D11_APPEND_ALIGNED_ELEMENT; 757 | desc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA; 758 | desc.InstanceDataStepRate = 0; 759 | 760 | inputLayout.push_back(desc); 761 | } 762 | 763 | 764 | //////////////////////////////////////////////////////////////////////////////////////////////////// 765 | //////////////////////////////////////////////////////////////////////////////////////////////////// 766 | //////////////////////////////////////////////////////////////////////////////////////////////////// 767 | 768 | static ID3D10Blob* compileShader(const TCHAR* filename, const char* entryFunction, const char* profile, const Macros* macros = NULL) 769 | { 770 | ID3D10Blob* shaderBuffer = NULL; 771 | ID3DBlob * errorbuffer = NULL; 772 | const uint32 defaultFlags = 0; 773 | 774 | #define MAX_SHADER_MACRO 64 775 | D3D_SHADER_MACRO shaderMacros[MAX_SHADER_MACRO]; 776 | shaderMacros[0] = { NULL, NULL }; // in case there is no macros 777 | if (macros != NULL) 778 | { 779 | size_t macrosCount = macros->size(); 780 | bool validMacroCount = macros->size() <= MAX_SHADER_MACRO-1; // -1 to handle the null end of list macro 781 | ATLASSERT(validMacroCount); 782 | if (!validMacroCount) 783 | { 784 | OutputDebugStringA("\nNumber of macro is too high for shader "); 785 | OutputDebugStringW(filename); 786 | OutputDebugStringA("\n"); 787 | return NULL; 788 | } 789 | for (int32 m = 0; m < macrosCount; ++m) 790 | { 791 | const ShaderMacro& sm = macros->at(m); 792 | shaderMacros[m] = { sm.Name.c_str() , sm.Definition.c_str() }; 793 | } 794 | shaderMacros[macrosCount] = { NULL, NULL }; 795 | } 796 | 797 | HRESULT hr = D3DCompileFromFile( 798 | filename, // filename 799 | shaderMacros, // defines 800 | D3D_COMPILE_STANDARD_FILE_INCLUDE, // default include handler (includes relative to the compiled file) 801 | entryFunction, // function name 802 | profile, // target profile 803 | defaultFlags, // flag1 804 | defaultFlags, // flag2 805 | &shaderBuffer, // ouput 806 | &errorbuffer); // errors 807 | 808 | if (FAILED(hr)) 809 | { 810 | OutputDebugStringA("\n===> Failed to compile shader: function="); 811 | OutputDebugStringA(entryFunction); 812 | OutputDebugStringA(", profile="); 813 | OutputDebugStringA(profile); 814 | OutputDebugStringA(", file="); 815 | OutputDebugStringW(filename); 816 | OutputDebugStringA(" :\n"); 817 | OutputDebugStringA(" HResult = "); 818 | _com_error err(hr); 819 | OutputDebugStringW(err.ErrorMessage()); 820 | OutputDebugStringA("\n"); 821 | if (errorbuffer) 822 | { 823 | OutputDebugStringA((char*)errorbuffer->GetBufferPointer()); 824 | resetComPtr(&errorbuffer); 825 | } 826 | resetComPtr(&shaderBuffer); 827 | OutputDebugStringA("\n\n"); 828 | return NULL; 829 | } 830 | return shaderBuffer; 831 | } 832 | 833 | ShaderBase::ShaderBase(const TCHAR* filename, const char* entryFunction, const char* profile, const Macros* macros, bool lazyCompilation) 834 | : mShaderBuffer(nullptr) 835 | , mFilename(filename) 836 | , mEntryFunction(entryFunction) 837 | , mProfile(profile) 838 | { 839 | if(macros) 840 | mMacros = *macros; 841 | if(!lazyCompilation) 842 | mShaderBuffer = compileShader(mFilename, mEntryFunction, mProfile, macros); 843 | } 844 | 845 | ShaderBase::~ShaderBase() 846 | { 847 | resetComPtr(&mShaderBuffer); 848 | } 849 | 850 | bool ShaderBase::recompileShaderIfNeeded() 851 | { 852 | ID3D10Blob* compiledShaderBuffer; 853 | bool newShaderBinaryAvailable = false; 854 | if (mDirty && (compiledShaderBuffer = compileShader(mFilename, mEntryFunction, mProfile, &mMacros))) 855 | { 856 | resetComPtr(&mShaderBuffer); 857 | mShaderBuffer = compiledShaderBuffer; 858 | newShaderBinaryAvailable = true; 859 | } 860 | mDirty = false; // we always remove dirtiness to avoid try to recompile each frame. 861 | return newShaderBinaryAvailable; 862 | } 863 | 864 | VertexShader::VertexShader(const TCHAR* filename, const char* entryFunction, const Macros* macros, bool lazyCompilation) 865 | : ShaderBase(filename, entryFunction, "vs_5_0", macros, lazyCompilation) 866 | { 867 | if (!compilationSuccessful()) return; // failed compilation 868 | ID3D11Device* device = g_dx11Device->getDevice(); 869 | HRESULT hr = device->CreateVertexShader(mShaderBuffer->GetBufferPointer(), mShaderBuffer->GetBufferSize(), NULL, &mVertexShader); 870 | ATLASSERT(hr == S_OK); 871 | mDirty = false; 872 | } 873 | VertexShader::~VertexShader() 874 | { 875 | resetComPtr(&mVertexShader); 876 | } 877 | 878 | void VertexShader::createInputLayout(InputLayoutDesc inputLayout, D3dInputLayout** layout) 879 | { 880 | ID3D11Device* device = g_dx11Device->getDevice(); 881 | HRESULT hr = device->CreateInputLayout(inputLayout.data(), uint32(inputLayout.size()), mShaderBuffer->GetBufferPointer(), mShaderBuffer->GetBufferSize(), layout); 882 | ATLASSERT(hr == S_OK); 883 | } 884 | 885 | void VertexShader::setShader(D3dRenderContext& context) 886 | { 887 | if (recompileShaderIfNeeded()) 888 | { 889 | resetComPtr(&mVertexShader); 890 | ID3D11Device* device = g_dx11Device->getDevice(); 891 | HRESULT hr = device->CreateVertexShader(mShaderBuffer->GetBufferPointer(), mShaderBuffer->GetBufferSize(), NULL, &mVertexShader); 892 | ATLASSERT(hr == S_OK); 893 | } 894 | context.VSSetShader(mVertexShader, nullptr, 0); 895 | } 896 | 897 | PixelShader::PixelShader(const TCHAR* filename, const char* entryFunction, const Macros* macros, bool lazyCompilation) 898 | : ShaderBase(filename, entryFunction, "ps_5_0", macros, lazyCompilation) 899 | { 900 | if (!compilationSuccessful()) return; // failed compilation 901 | ID3D11Device* device = g_dx11Device->getDevice(); 902 | HRESULT hr = device->CreatePixelShader(mShaderBuffer->GetBufferPointer(), mShaderBuffer->GetBufferSize(), NULL, &mPixelShader); 903 | ATLASSERT(hr == S_OK); 904 | mDirty = false; 905 | } 906 | PixelShader::~PixelShader() 907 | { 908 | resetComPtr(&mPixelShader); 909 | } 910 | void PixelShader::setShader(D3dRenderContext& context) 911 | { 912 | if (recompileShaderIfNeeded()) 913 | { 914 | resetComPtr(&mPixelShader); 915 | ID3D11Device* device = g_dx11Device->getDevice(); 916 | HRESULT hr = device->CreatePixelShader(mShaderBuffer->GetBufferPointer(), mShaderBuffer->GetBufferSize(), NULL, &mPixelShader); 917 | ATLASSERT(hr == S_OK); 918 | } 919 | context.PSSetShader(mPixelShader, nullptr, 0); 920 | } 921 | 922 | HullShader::HullShader(const TCHAR* filename, const char* entryFunction, const Macros* macros, bool lazyCompilation) 923 | : ShaderBase(filename, entryFunction, "hs_5_0", macros, lazyCompilation) 924 | { 925 | if (!compilationSuccessful()) return; // failed compilation 926 | ID3D11Device* device = g_dx11Device->getDevice(); 927 | HRESULT hr = device->CreateHullShader(mShaderBuffer->GetBufferPointer(), mShaderBuffer->GetBufferSize(), NULL, &mHullShader); 928 | ATLASSERT(hr == S_OK); 929 | mDirty = false; 930 | } 931 | HullShader::~HullShader() 932 | { 933 | resetComPtr(&mHullShader); 934 | } 935 | void HullShader::setShader(D3dRenderContext& context) 936 | { 937 | if (recompileShaderIfNeeded()) 938 | { 939 | resetComPtr(&mHullShader); 940 | ID3D11Device* device = g_dx11Device->getDevice(); 941 | HRESULT hr = device->CreateHullShader(mShaderBuffer->GetBufferPointer(), mShaderBuffer->GetBufferSize(), NULL, &mHullShader); 942 | ATLASSERT(hr == S_OK); 943 | } 944 | context.HSSetShader(mHullShader, nullptr, 0); 945 | } 946 | 947 | DomainShader::DomainShader(const TCHAR* filename, const char* entryFunction, const Macros* macros, bool lazyCompilation) 948 | : ShaderBase(filename, entryFunction, "ds_5_0", macros, lazyCompilation) 949 | { 950 | if (!compilationSuccessful()) return; // failed compilation 951 | ID3D11Device* device = g_dx11Device->getDevice(); 952 | HRESULT hr = device->CreateDomainShader(mShaderBuffer->GetBufferPointer(), mShaderBuffer->GetBufferSize(), NULL, &mDomainShader); 953 | ATLASSERT(hr == S_OK); 954 | mDirty = false; 955 | } 956 | DomainShader::~DomainShader() 957 | { 958 | resetComPtr(&mDomainShader); 959 | } 960 | void DomainShader::setShader(D3dRenderContext& context) 961 | { 962 | if (recompileShaderIfNeeded()) 963 | { 964 | resetComPtr(&mDomainShader); 965 | ID3D11Device* device = g_dx11Device->getDevice(); 966 | HRESULT hr = device->CreateDomainShader(mShaderBuffer->GetBufferPointer(), mShaderBuffer->GetBufferSize(), NULL, &mDomainShader); 967 | ATLASSERT(hr == S_OK); 968 | } 969 | context.DSSetShader(mDomainShader, nullptr, 0); 970 | } 971 | 972 | GeometryShader::GeometryShader(const TCHAR* filename, const char* entryFunction, const Macros* macros, bool lazyCompilation) 973 | : ShaderBase(filename, entryFunction, "gs_5_0", macros, lazyCompilation) 974 | { 975 | if (!compilationSuccessful()) return; // failed compilation 976 | ID3D11Device* device = g_dx11Device->getDevice(); 977 | HRESULT hr = device->CreateGeometryShader(mShaderBuffer->GetBufferPointer(), mShaderBuffer->GetBufferSize(), NULL, &mGeometryShader); 978 | ATLASSERT(hr == S_OK); 979 | mDirty = false; 980 | } 981 | GeometryShader::~GeometryShader() 982 | { 983 | resetComPtr(&mGeometryShader); 984 | } 985 | void GeometryShader::setShader(D3dRenderContext& context) 986 | { 987 | if (recompileShaderIfNeeded()) 988 | { 989 | resetComPtr(&mGeometryShader); 990 | ID3D11Device* device = g_dx11Device->getDevice(); 991 | HRESULT hr = device->CreateGeometryShader(mShaderBuffer->GetBufferPointer(), mShaderBuffer->GetBufferSize(), NULL, &mGeometryShader); 992 | ATLASSERT(hr == S_OK); 993 | } 994 | context.GSSetShader(mGeometryShader, nullptr, 0); 995 | } 996 | 997 | ComputeShader::ComputeShader(const TCHAR* filename, const char* entryFunction, const Macros* macros, bool lazyCompilation) 998 | : ShaderBase(filename, entryFunction, "cs_5_0", macros, lazyCompilation) 999 | { 1000 | if (!compilationSuccessful()) return; // failed compilation 1001 | ID3D11Device* device = g_dx11Device->getDevice(); 1002 | HRESULT hr = device->CreateComputeShader(mShaderBuffer->GetBufferPointer(), mShaderBuffer->GetBufferSize(), NULL, &mComputeShader); 1003 | ATLASSERT(hr == S_OK); 1004 | mDirty = false; 1005 | } 1006 | ComputeShader::~ComputeShader() 1007 | { 1008 | resetComPtr(&mComputeShader); 1009 | } 1010 | void ComputeShader::setShader(D3dRenderContext& context) 1011 | { 1012 | if (recompileShaderIfNeeded()) 1013 | { 1014 | resetComPtr(&mComputeShader); 1015 | ID3D11Device* device = g_dx11Device->getDevice(); 1016 | HRESULT hr = device->CreateComputeShader(mShaderBuffer->GetBufferPointer(), mShaderBuffer->GetBufferSize(), NULL, &mComputeShader); 1017 | ATLASSERT(hr == S_OK); 1018 | } 1019 | context.CSSetShader(mComputeShader, nullptr, 0); 1020 | } 1021 | 1022 | 1023 | //////////////////////////////////////////////////////////////////////////////////////////////////// 1024 | //////////////////////////////////////////////////////////////////////////////////////////////////// 1025 | //////////////////////////////////////////////////////////////////////////////////////////////////// 1026 | 1027 | // static members 1028 | DxGpuPerformance::GpuTimerMap DxGpuPerformance::mTimers; 1029 | int32 DxGpuPerformance::mMeasureTimerFrameId; 1030 | int32 DxGpuPerformance::mReadTimerFrameId; 1031 | int32 DxGpuPerformance::mLastReadTimerFrameId; 1032 | 1033 | DxGpuPerformance::DxGpuTimer DxGpuPerformance::mTimerArray[V_TIMER_MAX_COUNT]; 1034 | int32 DxGpuPerformance::mAllocatedTimers; 1035 | 1036 | DxGpuPerformance::TimerGraphNode DxGpuPerformance::mTimerGraphNodeArray[V_GPU_TIMER_FRAMECOUNT][V_TIMER_MAX_COUNT]; 1037 | int32 DxGpuPerformance::mAllocatedTimerGraphNodes[V_GPU_TIMER_FRAMECOUNT]; 1038 | 1039 | DxGpuPerformance::GpuTimerGraph DxGpuPerformance::mTimerGraphs[V_GPU_TIMER_FRAMECOUNT]; 1040 | DxGpuPerformance::TimerGraphNode* DxGpuPerformance::mCurrentTimeGraph = nullptr; 1041 | 1042 | void DxGpuPerformance::initialise() 1043 | { 1044 | mTimers.clear(); 1045 | mAllocatedTimers = 0; 1046 | 1047 | mMeasureTimerFrameId = 0; // first frame 1048 | mReadTimerFrameId = -V_GPU_TIMER_FRAMECOUNT+1; // invalid 1049 | mLastReadTimerFrameId = -V_GPU_TIMER_FRAMECOUNT-1; // invalid 1050 | } 1051 | void DxGpuPerformance::shutdown() 1052 | { 1053 | for (int32 i = 0; i < mAllocatedTimers; ++i) 1054 | mTimerArray[i].release(); 1055 | mTimers.clear(); 1056 | } 1057 | 1058 | void DxGpuPerformance::startFrame() 1059 | { 1060 | // Clear the frame we are going to measure and append root timer node 1061 | for (int32 i = 0, cnt = mAllocatedTimerGraphNodes[mMeasureTimerFrameId]; i < cnt; ++i) 1062 | mTimerGraphNodeArray[mMeasureTimerFrameId][i].subGraph.clear(); 1063 | mAllocatedTimerGraphNodes[mMeasureTimerFrameId] = 0; // reset the counter 1064 | TimerGraphNode* root = &mTimerGraphNodeArray [mMeasureTimerFrameId] [mAllocatedTimerGraphNodes[mMeasureTimerFrameId]++]; 1065 | root->name = "root"; 1066 | root->r = root->g = root->b = 127; 1067 | mTimerGraphs[mMeasureTimerFrameId].clear(); 1068 | 1069 | mTimerGraphs[mMeasureTimerFrameId].push_back(root); 1070 | mCurrentTimeGraph = (*mTimerGraphs[mMeasureTimerFrameId].begin()); 1071 | } 1072 | 1073 | void DxGpuPerformance::startGpuTimer(const char* name, unsigned char r, unsigned char g, unsigned char b) 1074 | { 1075 | GpuTimerMap::iterator it = mTimers.find(name); 1076 | DxGpuTimer* timer = nullptr; 1077 | if (it == mTimers.end()) 1078 | { 1079 | // Allocate a timer and insert into the map 1080 | ATLASSERT(mAllocatedTimers<(V_TIMER_MAX_COUNT-1)); 1081 | timer = &mTimerArray[mAllocatedTimers++]; 1082 | mTimers[name] = timer; 1083 | timer->initialize(); 1084 | } 1085 | else 1086 | { 1087 | ATLASSERT(!(*it).second->mUsedThisFrame); // a timer can only be used once a frame 1088 | timer = (*it).second; 1089 | } 1090 | 1091 | D3dRenderContext* context = g_dx11Device->getDeviceContext(); 1092 | context->Begin(timer->mDisjointQueries[mMeasureTimerFrameId]); 1093 | context->End(timer->mBeginQueries[mMeasureTimerFrameId]); 1094 | 1095 | // Make sure we do not add the timer twice per frame 1096 | ATLASSERT(!timer->mUsedThisFrame); 1097 | timer->mUsedThisFrame = true; 1098 | 1099 | // Push the timer node we just started 1100 | ATLASSERT(mAllocatedTimerGraphNodes[mMeasureTimerFrameId]<(V_TIMER_MAX_COUNT - 1)); 1101 | TimerGraphNode* node = &mTimerGraphNodeArray[mMeasureTimerFrameId][mAllocatedTimerGraphNodes[mMeasureTimerFrameId]++]; 1102 | node->name = name; 1103 | node->r = float(r) / 255.0f; 1104 | node->g = float(g) / 255.0f; 1105 | node->b = float(b) / 255.0f; 1106 | node->timer = timer; 1107 | node->parent = mCurrentTimeGraph; 1108 | mCurrentTimeGraph->subGraph.push_back(node); 1109 | mCurrentTimeGraph = (*mCurrentTimeGraph->subGraph.rbegin()); 1110 | timer->mNode[mMeasureTimerFrameId] = mCurrentTimeGraph; 1111 | // TO SOLVE: have static array of node 1112 | } 1113 | 1114 | void DxGpuPerformance::endGpuTimer(const char* name) 1115 | { 1116 | DxGpuTimer* timer = mTimers[name]; 1117 | 1118 | D3dRenderContext* context = g_dx11Device->getDeviceContext(); 1119 | context->End(timer->mDisjointQueries[mMeasureTimerFrameId]); 1120 | context->End(timer->mEndQueries[mMeasureTimerFrameId]); 1121 | timer->mEnded = true; 1122 | 1123 | // Pop to the parent of the timer node that has just ended 1124 | mCurrentTimeGraph = mCurrentTimeGraph->parent; 1125 | ATLASSERT(mCurrentTimeGraph!=nullptr); 1126 | } 1127 | 1128 | void DxGpuPerformance::endFrame() 1129 | { 1130 | // Fetch data from ready timer 1131 | if (mReadTimerFrameId >= 0) 1132 | { 1133 | int32 localReadTimerFrameId = mReadTimerFrameId%V_GPU_TIMER_FRAMECOUNT; 1134 | 1135 | D3dRenderContext* context = g_dx11Device->getDeviceContext(); 1136 | DxGpuPerformance::GpuTimerMap::iterator it; 1137 | 1138 | // Get all the data first 1139 | for (it = mTimers.begin(); it != mTimers.end(); it++) 1140 | { 1141 | DxGpuPerformance::DxGpuTimer* timer = (*it).second; 1142 | if (!timer->mUsedThisFrame) // we should test usePreviousFrame but that will be enough for now 1143 | continue; 1144 | ATLASSERT(timer->mEnded); // the timer must have been ended this frame 1145 | 1146 | TimerGraphNode* node = timer->mNode[localReadTimerFrameId]; 1147 | if (!node) 1148 | continue; // This can happen when a timer is registered later when some features are enabled. 1149 | 1150 | while (context->GetData(timer->mBeginQueries[localReadTimerFrameId], &node->mBeginTick, sizeof(UINT64), 0) != S_OK); 1151 | while (context->GetData(timer->mEndQueries[localReadTimerFrameId], &node->mEndTick, sizeof(UINT64), 0) != S_OK); 1152 | while (context->GetData(timer->mDisjointQueries[localReadTimerFrameId], &node->disjointData, sizeof(D3D11_QUERY_DATA_TIMESTAMP_DISJOINT), 0) != S_OK); 1153 | } 1154 | 1155 | // Get the begining of the frame measurement 1156 | UINT64 minBeginTime = 0xFFFFFFFFFFFFFFFF; 1157 | for (it = mTimers.begin(); it != mTimers.end(); it++) 1158 | { 1159 | DxGpuPerformance::DxGpuTimer* timer = (*it).second; 1160 | if (!timer->mUsedThisFrame) // we should test usePreviousFrame but that will be enough for now 1161 | continue; 1162 | 1163 | TimerGraphNode* node = timer->mNode[localReadTimerFrameId]; 1164 | if (!node) 1165 | continue; // This can happen when a timer is registered later when some features are enabled. 1166 | 1167 | minBeginTime = min(minBeginTime, node->mBeginTick); 1168 | } 1169 | 1170 | 1171 | for (it = mTimers.begin(); it != mTimers.end(); it++) 1172 | { 1173 | DxGpuPerformance::DxGpuTimer* timer = (*it).second; 1174 | 1175 | if (!timer->mUsedThisFrame) // we should test usePreviousFrame but that will be enough for now 1176 | continue; 1177 | 1178 | // Reset the safety checks 1179 | timer->mUsedThisFrame = false; 1180 | timer->mEnded = false; 1181 | 1182 | TimerGraphNode* node = timer->mNode[localReadTimerFrameId]; 1183 | if (!node) 1184 | continue; // This can happen when a timer is registered later when some features are enabled. 1185 | 1186 | float beginMs = 0.0f; 1187 | float endMs = 0.0f; 1188 | float lastDurationMs = 0.0f; 1189 | if (node->disjointData.Disjoint == FALSE) 1190 | { 1191 | float factor = 1000.0f / float(node->disjointData.Frequency); 1192 | beginMs = (node->mBeginTick - minBeginTime) * factor; 1193 | endMs = (node->mEndTick - minBeginTime) * factor; 1194 | lastDurationMs = (node->mEndTick - node->mBeginTick) * factor; 1195 | } 1196 | node->mBeginMs = beginMs; 1197 | node->mEndMs = endMs; 1198 | node->mLastDurationMs = lastDurationMs; 1199 | } 1200 | } 1201 | else 1202 | { 1203 | // At least reset timers safety checks 1204 | DxGpuPerformance::GpuTimerMap::iterator it; 1205 | for (it = mTimers.begin(); it != mTimers.end(); it++) 1206 | { 1207 | DxGpuPerformance::DxGpuTimer* timer = (*it).second; 1208 | timer->mUsedThisFrame = false; 1209 | timer->mEnded = false; 1210 | } 1211 | } 1212 | 1213 | // Move onto next frame 1214 | mReadTimerFrameId++; 1215 | mMeasureTimerFrameId = (mMeasureTimerFrameId + 1) % V_GPU_TIMER_FRAMECOUNT; 1216 | mLastReadTimerFrameId++; 1217 | } 1218 | 1219 | const DxGpuPerformance::TimerGraphNode* DxGpuPerformance::getLastUpdatedTimerGraphRootNode() 1220 | { 1221 | if (mLastReadTimerFrameId >= 0) 1222 | { 1223 | return *mTimerGraphs[mLastReadTimerFrameId%V_GPU_TIMER_FRAMECOUNT].begin(); 1224 | } 1225 | return nullptr; 1226 | } 1227 | 1228 | DxGpuPerformance::DxGpuTimer::DxGpuTimer() 1229 | { 1230 | } 1231 | 1232 | DxGpuPerformance::DxGpuTimer::~DxGpuTimer() 1233 | { 1234 | } 1235 | 1236 | void DxGpuPerformance::DxGpuTimer::initialize() 1237 | { 1238 | ID3D11Device* device = g_dx11Device->getDevice(); 1239 | D3D11_QUERY_DESC queryDesc; 1240 | queryDesc.Query = D3D11_QUERY_TIMESTAMP; 1241 | queryDesc.MiscFlags = 0; 1242 | D3D11_QUERY_DESC disjointQueryDesc; 1243 | disjointQueryDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT; 1244 | disjointQueryDesc.MiscFlags = 0; 1245 | for (int32 i = 0; i < V_GPU_TIMER_FRAMECOUNT; ++i) 1246 | { 1247 | device->CreateQuery(&disjointQueryDesc, &mDisjointQueries[i]); 1248 | device->CreateQuery(&queryDesc, &mBeginQueries[i]); 1249 | device->CreateQuery(&queryDesc, &mEndQueries[i]); 1250 | } 1251 | } 1252 | void DxGpuPerformance::DxGpuTimer::release() 1253 | { 1254 | ID3D11Device* device = g_dx11Device->getDevice(); 1255 | for (int32 i = 0; i < V_GPU_TIMER_FRAMECOUNT; ++i) 1256 | { 1257 | resetComPtr(&mDisjointQueries[i]); 1258 | resetComPtr(&mBeginQueries[i]); 1259 | resetComPtr(&mEndQueries[i]); 1260 | } 1261 | } 1262 | 1263 | 1264 | //////////////////////////////////////////////////////////////////////////////////////////////////// 1265 | //////////////////////////////////////////////////////////////////////////////////////////////////// 1266 | //////////////////////////////////////////////////////////////////////////////////////////////////// 1267 | 1268 | 1269 | 1270 | int32 divRoundUp(int32 numer, int32 denum) 1271 | { 1272 | return (numer + denum - 1) / denum; 1273 | } 1274 | 1275 | 1276 | 1277 | //////////////////////////////////////////////////////////////////////////////////////////////////// 1278 | //////////////////////////////////////////////////////////////////////////////////////////////////// 1279 | //////////////////////////////////////////////////////////////////////////////////////////////////// 1280 | 1281 | 1282 | //buffer, constant, view, render target and shader creation 1283 | // http://www.rastertek.com/dx11tut04.html 1284 | // https://msdn.microsoft.com/en-us/library/windows/desktop/dn508285(v=vs.85).aspx 1285 | 1286 | 1287 | 1288 | 1289 | 1290 | 1291 | 1292 | 1293 | 1294 | -------------------------------------------------------------------------------- /DX11Base/Dx11Device.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define DX_DEBUG_EVENT 1 4 | #define DX_DEBUG_RESOURCE_NAME 1 5 | 6 | // Windows and Dx11 includes 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "DxMath.h" 18 | 19 | // include the Direct3D Library file 20 | #pragma comment (lib, "d3d11.lib") 21 | #if DX_DEBUG_EVENT || DX_DEBUG_RESOURCE_NAME 22 | #pragma comment( lib, "dxguid.lib") // For debug name guid 23 | #endif 24 | 25 | 26 | typedef ID3D11Device D3dDevice; 27 | typedef ID3D11DeviceContext D3dRenderContext; 28 | 29 | typedef ID3D11InputLayout D3dInputLayout; 30 | typedef D3D11_INPUT_ELEMENT_DESC D3dInputElementDesc; 31 | typedef D3D11_VIEWPORT D3dViewport; 32 | 33 | typedef ID3D11ShaderResourceView D3dShaderResourceView; 34 | typedef D3D11_UNORDERED_ACCESS_VIEW_DESC D3dUnorderedAccessViewDesc; 35 | typedef ID3D11UnorderedAccessView D3dUnorderedAccessView; 36 | typedef ID3D11RenderTargetView D3dRenderTargetView; 37 | typedef ID3D11DepthStencilView D3dDepthStencilView; 38 | 39 | typedef D3D11_BUFFER_DESC D3dBufferDesc; 40 | typedef D3D11_TEXTURE2D_DESC D3dTexture2dDesc; 41 | typedef D3D11_TEXTURE3D_DESC D3dTexture3dDesc; 42 | typedef D3D11_SUBRESOURCE_DATA D3dSubResourceData; 43 | typedef D3D11_SAMPLER_DESC D3dSamplerDesc; 44 | 45 | typedef D3D11_DEPTH_STENCIL_DESC D3dDepthStencilDesc; 46 | typedef D3D11_RASTERIZER_DESC D3dRasterizerDesc; 47 | typedef D3D11_BLEND_DESC D3dBlendDesc; 48 | 49 | 50 | 51 | class Dx11Device 52 | { 53 | public: 54 | 55 | static void initialise(const HWND& hWnd); 56 | static void shutdown(); 57 | 58 | D3dDevice* getDevice() { return mDev; } 59 | D3dRenderContext* getDeviceContext() { return mDevcon; } 60 | IDXGISwapChain* getSwapChain() { return mSwapchain; } 61 | D3dRenderTargetView* getBackBufferRT() { return mBackBufferRT; } 62 | 63 | #if DX_DEBUG_EVENT 64 | CComPtr mUserDefinedAnnotation; 65 | #endif 66 | 67 | void swap(bool vsyncEnabled); 68 | 69 | static void setNullRenderTarget(D3dRenderContext* devcon) 70 | { 71 | D3dRenderTargetView* nullRTV = nullptr; 72 | D3dUnorderedAccessView* nullUAV = nullptr; 73 | //devcon->OMSetRenderTargets(1, &nullRTV, nullptr); 74 | devcon->OMSetRenderTargetsAndUnorderedAccessViews(1, &nullRTV, nullptr, 1, 0, &nullUAV, nullptr); 75 | } 76 | static void setNullPsResources(D3dRenderContext* devcon) 77 | { 78 | static D3dShaderResourceView* null[16] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; // not good, only 8, would need something smarter maybe... 79 | devcon->PSSetShaderResources(0, 16, null); 80 | } 81 | static void setNullVsResources(D3dRenderContext* devcon) 82 | { 83 | static D3dShaderResourceView* null[16] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; 84 | devcon->VSSetShaderResources(0, 16, null); 85 | } 86 | static void setNullCsResources(D3dRenderContext* devcon) 87 | { 88 | static D3dShaderResourceView* null[16] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; 89 | devcon->CSSetShaderResources(0, 16, null); 90 | } 91 | static void setNullCsUnorderedAccessViews(D3dRenderContext* devcon) 92 | { 93 | static D3dUnorderedAccessView* null[8] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; 94 | devcon->CSSetUnorderedAccessViews(0, 8, null, nullptr); 95 | } 96 | 97 | const D3dViewport& getBackBufferViewport() const { return mBackBufferViewport; } 98 | void updateSwapChain(uint32 newWidth, uint32 newHeight); 99 | 100 | private: 101 | Dx11Device(); 102 | Dx11Device(Dx11Device&); 103 | //Dx11Device(const Dx11Device&); 104 | ~Dx11Device(); 105 | 106 | void internalInitialise(const HWND& hWnd); 107 | void internalShutdown(); 108 | 109 | IDXGISwapChain* mSwapchain; // the pointer to the swap chain interface 110 | D3dDevice* mDev; // the pointer to our Direct3D device interface 111 | D3dRenderContext* mDevcon; // the pointer to our Direct3D device context 112 | 113 | D3dRenderTargetView* mBackBufferRT; // back buffer render target 114 | 115 | D3dViewport mBackBufferViewport; 116 | }; 117 | 118 | extern Dx11Device* g_dx11Device; 119 | 120 | 121 | #if DX_DEBUG_RESOURCE_NAME 122 | #define DX_SET_DEBUG_NAME(obj, debugName) obj->SetPrivateData(WKPDID_D3DDebugObjectName, sizeof(debugName), debugName) 123 | #else 124 | #define DX_SET_DEBUG_NAME(obj, debugName) 125 | #endif 126 | 127 | #if DX_DEBUG_EVENT 128 | #define GPU_BEGIN_EVENT(eventName) g_dx11Device->mUserDefinedAnnotation->BeginEvent(L""#eventName) 129 | #define GPU_END_EVENT() g_dx11Device->mUserDefinedAnnotation->EndEvent() 130 | #else 131 | #define GPU_BEGIN_EVENT(eventName) 132 | #define GPU_END_EVENT() 133 | #endif 134 | 135 | struct ScopedGpuEvent 136 | { 137 | ScopedGpuEvent(LPCWSTR name) 138 | : mName(name) 139 | { 140 | g_dx11Device->mUserDefinedAnnotation->BeginEvent(mName); 141 | } 142 | ~ScopedGpuEvent() 143 | { 144 | release(); 145 | } 146 | void release() 147 | { 148 | if (!released) 149 | { 150 | released = true; 151 | g_dx11Device->mUserDefinedAnnotation->EndEvent(); 152 | } 153 | } 154 | private: 155 | ScopedGpuEvent() = delete; 156 | ScopedGpuEvent(ScopedGpuEvent&) = delete; 157 | LPCWSTR mName; 158 | bool released = false; 159 | }; 160 | #define GPU_SCOPED_EVENT(timerName) ScopedGpuEvent gpuEvent##timerName##(L""#timerName) 161 | 162 | 163 | //////////////////////////////////////////////////////////////////////////////////////////////////// 164 | //////////////////////////////////////////////////////////////////////////////////////////////////// 165 | //////////////////////////////////////////////////////////////////////////////////////////////////// 166 | 167 | 168 | class RenderBuffer 169 | { 170 | public: 171 | 172 | RenderBuffer(D3dBufferDesc& mBufferDesc, void* initialData=nullptr); 173 | virtual ~RenderBuffer(); 174 | 175 | 176 | // Usage of dynamic resources and mapping 177 | 178 | struct ScopedMappedRenderbuffer 179 | { 180 | ScopedMappedRenderbuffer() 181 | : mMappedBuffer(nullptr) 182 | {} 183 | ~ScopedMappedRenderbuffer() 184 | { RenderBuffer::unmap(*this); } 185 | 186 | void* getDataPtr() { return mMappedResource.pData; } 187 | private: 188 | friend class RenderBuffer; 189 | D3D11_MAPPED_SUBRESOURCE mMappedResource; 190 | ID3D11Buffer* mMappedBuffer; 191 | }; 192 | void map(D3D11_MAP map, ScopedMappedRenderbuffer& mappedBuffer); 193 | static void unmap(ScopedMappedRenderbuffer& mappedBuffer); 194 | 195 | 196 | // Some basic descriptor initialisation methods 197 | 198 | static D3dBufferDesc initConstantBufferDesc_dynamic(uint32 byteSize); 199 | static D3dBufferDesc initVertexBufferDesc_default(uint32 byteSize); 200 | static D3dBufferDesc initIndexBufferDesc_default(uint32 byteSize); 201 | static D3dBufferDesc initBufferDesc_default(uint32 byteSize); 202 | static D3dBufferDesc initBufferDesc_uav(uint32 byteSize); 203 | 204 | public:///////////////////////////////////protected: 205 | D3dBufferDesc mDesc; 206 | ID3D11Buffer* mBuffer; 207 | 208 | private: 209 | RenderBuffer(); 210 | RenderBuffer(RenderBuffer&); 211 | }; 212 | 213 | 214 | template 215 | class ConstantBuffer : public RenderBuffer 216 | { 217 | public: 218 | ConstantBuffer() : RenderBuffer(getDesc(), nullptr) {} 219 | 220 | void update(const T& content) 221 | { 222 | ATLASSERT(mBuffer != nullptr); 223 | RenderBuffer::ScopedMappedRenderbuffer bufferMap; 224 | map(D3D11_MAP_WRITE_DISCARD, bufferMap); 225 | T* cb = (T*)bufferMap.getDataPtr(); 226 | memcpy(cb, &content, sizeof(T)); 227 | } 228 | private: 229 | 230 | static D3dBufferDesc getDesc() 231 | { 232 | ATLASSERT(sizeof(T) % 16 == 0); 233 | return initConstantBufferDesc_dynamic(sizeof(T)); 234 | } 235 | }; 236 | 237 | //////////////////////////////////////////////////////////////////////////////////////////////////// 238 | //////////////////////////////////////////////////////////////////////////////////////////////////// 239 | //////////////////////////////////////////////////////////////////////////////////////////////////// 240 | 241 | 242 | class Texture2D 243 | { 244 | public: 245 | Texture2D(D3dTexture2dDesc& desc, D3dSubResourceData* initialData = nullptr); 246 | virtual ~Texture2D(); 247 | static D3dTexture2dDesc initDepthStencilBuffer(uint32 width, uint32 height, bool uav); 248 | static D3dTexture2dDesc initDefault(DXGI_FORMAT format, uint32 width, uint32 height, bool renderTarget, bool uav); 249 | D3dTexture2dDesc mDesc; 250 | ID3D11Texture2D* mTexture = nullptr; 251 | D3dDepthStencilView* mDepthStencilView = nullptr; 252 | D3dRenderTargetView* mRenderTargetView = nullptr; 253 | D3dShaderResourceView* mShaderResourceView = nullptr; 254 | D3dUnorderedAccessView* mUnorderedAccessView = nullptr; 255 | private: 256 | Texture2D(); 257 | Texture2D(Texture2D&); 258 | }; 259 | 260 | class Texture3D 261 | { 262 | public: 263 | Texture3D(D3dTexture3dDesc& desc, D3dSubResourceData* initialData = nullptr); 264 | virtual ~Texture3D(); 265 | static D3dTexture3dDesc initDefault(DXGI_FORMAT format, uint32 width, uint32 height, uint32 depth, bool renderTarget, bool uav); 266 | D3dTexture3dDesc mDesc; 267 | ID3D11Texture3D* mTexture = nullptr; 268 | D3dRenderTargetView* mRenderTargetView = nullptr; // level 0 269 | D3dShaderResourceView* mShaderResourceView = nullptr; // level 0 270 | D3dUnorderedAccessView* mUnorderedAccessView = nullptr; // level 0 271 | std::vector mShaderResourceViewMips; // all levels 272 | std::vector mUnorderedAccessViewMips; // all levels 273 | private: 274 | Texture3D(); 275 | Texture3D(Texture3D&); 276 | }; 277 | 278 | class SamplerState 279 | { 280 | public: 281 | SamplerState(D3dSamplerDesc& desc); 282 | virtual ~SamplerState(); 283 | static D3dSamplerDesc initLinearClamp(); 284 | static D3dSamplerDesc initPointClamp(); 285 | static D3dSamplerDesc initShadowCmpClamp(); 286 | ID3D11SamplerState* mSampler = nullptr; 287 | private: 288 | SamplerState(); 289 | SamplerState(SamplerState&); 290 | }; 291 | 292 | 293 | //////////////////////////////////////////////////////////////////////////////////////////////////// 294 | //////////////////////////////////////////////////////////////////////////////////////////////////// 295 | //////////////////////////////////////////////////////////////////////////////////////////////////// 296 | 297 | 298 | class DepthStencilState 299 | { 300 | public: 301 | DepthStencilState(D3dDepthStencilDesc& desc); 302 | virtual ~DepthStencilState(); 303 | static D3dDepthStencilDesc initDefaultDepthOnStencilOff(); 304 | static D3dDepthStencilDesc initDepthNoWriteStencilOff(); 305 | ID3D11DepthStencilState* mState; 306 | private: 307 | DepthStencilState(); 308 | DepthStencilState(DepthStencilState&); 309 | }; 310 | 311 | class RasterizerState 312 | { 313 | public: 314 | RasterizerState(D3dRasterizerDesc& desc); 315 | virtual ~RasterizerState(); 316 | static D3dRasterizerDesc initDefaultState(); 317 | ID3D11RasterizerState* mState; 318 | private: 319 | RasterizerState(); 320 | RasterizerState(RasterizerState&); 321 | }; 322 | 323 | class BlendState 324 | { 325 | public: 326 | BlendState(D3dBlendDesc & desc); 327 | virtual ~BlendState(); 328 | static D3dBlendDesc initDisabledState(); 329 | static D3dBlendDesc initPreMultBlendState(); 330 | static D3dBlendDesc initPreMultDualBlendState(); 331 | static D3dBlendDesc initAdditiveState(); 332 | ID3D11BlendState* mState; 333 | private: 334 | BlendState(); 335 | BlendState(BlendState&); 336 | }; 337 | 338 | 339 | //////////////////////////////////////////////////////////////////////////////////////////////////// 340 | //////////////////////////////////////////////////////////////////////////////////////////////////// 341 | //////////////////////////////////////////////////////////////////////////////////////////////////// 342 | 343 | 344 | typedef std::vector InputLayoutDesc; 345 | 346 | // Append a simple per vertex data layout input 347 | void appendSimpleVertexDataToInputLayout(InputLayoutDesc& inputLayout, const char* semanticName, DXGI_FORMAT format); 348 | 349 | // Semantic names: https://msdn.microsoft.com/en-us/library/windows/desktop/bb509647(v=vs.85).aspx 350 | 351 | 352 | //////////////////////////////////////////////////////////////////////////////////////////////////// 353 | //////////////////////////////////////////////////////////////////////////////////////////////////// 354 | //////////////////////////////////////////////////////////////////////////////////////////////////// 355 | 356 | struct ShaderMacro 357 | { 358 | // We use string here to own the memory. 359 | // This is a requirement for delayed loading with non static shader parameter (created on stack or heap with unkown lifetime) 360 | std::string Name; 361 | std::string Definition; 362 | }; 363 | typedef std::vector Macros; // D3D_SHADER_MACRO contains pointers to string so those string must be static as of today. 364 | class ShaderBase 365 | { 366 | public: 367 | ShaderBase(const TCHAR* filename, const char* entryFunction, const char* profile, const Macros* macros = nullptr, bool lazyCompilation = false); 368 | virtual ~ShaderBase(); 369 | bool compilationSuccessful() { return mShaderBuffer != nullptr; } 370 | void markDirty() { mDirty = true; } 371 | 372 | protected: 373 | ID3D10Blob* mShaderBuffer; 374 | const TCHAR* mFilename; 375 | const char* mEntryFunction; 376 | const char* mProfile; 377 | Macros mMacros; 378 | bool mDirty = true; // If dirty, needs to be recompiled 379 | 380 | inline bool recompileShaderIfNeeded(); 381 | 382 | private: 383 | ShaderBase(); 384 | ShaderBase(ShaderBase&); 385 | }; 386 | 387 | class VertexShader : public ShaderBase 388 | { 389 | public: 390 | VertexShader(const TCHAR* filename, const char* entryFunction, const Macros* macros = nullptr, bool lazyCompilation = false); 391 | virtual ~VertexShader(); 392 | void createInputLayout(InputLayoutDesc inputLayout, D3dInputLayout** layout); // abstract that better 393 | void setShader(D3dRenderContext& context); 394 | private: 395 | ID3D11VertexShader* mVertexShader; 396 | }; 397 | 398 | class PixelShader : public ShaderBase 399 | { 400 | public: 401 | PixelShader(const TCHAR* filename, const char* entryFunction, const Macros* macros = nullptr, bool lazyCompilation = false); 402 | virtual ~PixelShader(); 403 | void setShader(D3dRenderContext& context); 404 | private: 405 | ID3D11PixelShader* mPixelShader; 406 | }; 407 | 408 | class HullShader : public ShaderBase 409 | { 410 | public: 411 | HullShader(const TCHAR* filename, const char* entryFunction, const Macros* macros = nullptr, bool lazyCompilation = false); 412 | virtual ~HullShader(); 413 | void setShader(D3dRenderContext& context); 414 | private: 415 | ID3D11HullShader* mHullShader; 416 | }; 417 | 418 | class DomainShader : public ShaderBase 419 | { 420 | public: 421 | DomainShader(const TCHAR* filename, const char* entryFunction, const Macros* macros = nullptr, bool lazyCompilation = false); 422 | virtual ~DomainShader(); 423 | void setShader(D3dRenderContext& context); 424 | private: 425 | ID3D11DomainShader* mDomainShader; 426 | }; 427 | 428 | class GeometryShader : public ShaderBase 429 | { 430 | public: 431 | GeometryShader(const TCHAR* filename, const char* entryFunction, const Macros* macros = nullptr, bool lazyCompilation = false); 432 | virtual ~GeometryShader(); 433 | void setShader(D3dRenderContext& context); 434 | private: 435 | ID3D11GeometryShader* mGeometryShader; 436 | }; 437 | 438 | class ComputeShader : public ShaderBase 439 | { 440 | public: 441 | ComputeShader(const TCHAR* filename, const char* entryFunction, const Macros* macros = nullptr, bool lazyCompilation = false); 442 | virtual ~ComputeShader(); 443 | void setShader(D3dRenderContext& context); 444 | private: 445 | ID3D11ComputeShader* mComputeShader; 446 | }; 447 | 448 | 449 | 450 | //////////////////////////////////////////////////////////////////////////////////////////////////// 451 | //////////////////////////////////////////////////////////////////////////////////////////////////// 452 | //////////////////////////////////////////////////////////////////////////////////////////////////// 453 | 454 | /// Example with double buffering on why we should use at least 3 timer query in this case (2 still works) 455 | /// 2: current frame added to context commend buffer 456 | /// 1: frame currently in flight 457 | /// 0: frame previous to current one in flight, done, data should be available 458 | #define V_GPU_TIMER_FRAMECOUNT 3 459 | 460 | /// Maximum number of timer in a frame and timer graph 461 | #define V_TIMER_MAX_COUNT 512 462 | 463 | class DxGpuPerformance 464 | { 465 | private: 466 | struct DxGpuTimer; 467 | public: 468 | struct TimerGraphNode; 469 | 470 | static void initialise(); 471 | static void shutdown(); 472 | 473 | /// Limitation as of today: each timer in a single frame must have different names 474 | static void startGpuTimer(const char* name, unsigned char r, unsigned char g, unsigned char b); 475 | static void endGpuTimer(const char* name); 476 | 477 | /// To call when starting to build render commands 478 | static void startFrame(); 479 | /// To call after the back buffer swap 480 | static void endFrame(); 481 | 482 | // TODO: add a reset function for when resources needs to all be re-allocated 483 | 484 | /// Some public structure that can be used to print out a frame timer graph 485 | struct TimerGraphNode 486 | { 487 | std::string name; 488 | float r, g, b; 489 | DxGpuTimer* timer = nullptr; 490 | std::vector subGraph; // will result in lots of allocations but that will do for now... 491 | TimerGraphNode* parent = nullptr; 492 | 493 | // Converted and extracted data 494 | float mBeginMs; 495 | float mEndMs; 496 | float mLastDurationMs; 497 | 498 | private: 499 | friend class DxGpuPerformance; 500 | // A bit too much to store all that raw data but convenient for now 501 | UINT64 mBeginTick; 502 | UINT64 mEndTick; 503 | UINT64 mLastDurationTick; 504 | D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjointData; 505 | }; 506 | typedef std::vector GpuTimerGraph; 507 | 508 | /// Returns the root node of the performance timer graph. This first root node contains nothing valid appart from childrens sub graphs. 509 | static const TimerGraphNode* getLastUpdatedTimerGraphRootNode(); 510 | 511 | private: 512 | DxGpuPerformance() = delete; 513 | DxGpuPerformance(DxGpuPerformance&) = delete; 514 | 515 | /// The actual timer data storing the dx11 queries 516 | struct DxGpuTimer 517 | { 518 | DxGpuTimer(); 519 | ~DxGpuTimer(); 520 | 521 | void initialize(); 522 | void release(); 523 | 524 | ID3D11Query* mDisjointQueries[V_GPU_TIMER_FRAMECOUNT]; 525 | ID3D11Query* mBeginQueries[V_GPU_TIMER_FRAMECOUNT]; 526 | ID3D11Query* mEndQueries[V_GPU_TIMER_FRAMECOUNT]; 527 | 528 | /// The graph node associated to this timer 529 | TimerGraphNode* mNode[V_GPU_TIMER_FRAMECOUNT]; 530 | 531 | bool mUsedThisFrame = false; ///! should be checked before querying data in case it is not used in some frames (also we only support one timer per name) 532 | bool mEnded = false; ///! sanity check to make sure a stared element is ended 533 | }; 534 | 535 | typedef std::map GpuTimerMap; 536 | static GpuTimerMap mTimers; ///! All the timers mapped using their name 537 | static int32 mMeasureTimerFrameId; ///! Last measured frame (appended timer to command buffer) 538 | static int32 mReadTimerFrameId; ///! Last frame we read the timer values from the api 539 | static int32 mLastReadTimerFrameId; ///! Last frame we read the timers and they are still valid for debug print on screen (data from previous finished frame) 540 | 541 | // Double buffer so that we can display the previous frame timers while the current frame is being processed 542 | static GpuTimerGraph mTimerGraphs[V_GPU_TIMER_FRAMECOUNT]; ///! Timer graphs of the last frames 543 | static TimerGraphNode* mCurrentTimeGraph; ///! The current graph being filled up this frame 544 | 545 | // Basically, node object are not in container as this can result in invalid/stale pointer when reallocated. Instead we allocate in static arrays 546 | // and container point to the static array. With such an approach, all pointers will remain valid over the desired lifetime (several frames). 547 | static DxGpuTimer mTimerArray[V_TIMER_MAX_COUNT]; 548 | static int32 mAllocatedTimers; 549 | static TimerGraphNode mTimerGraphNodeArray[V_GPU_TIMER_FRAMECOUNT][V_TIMER_MAX_COUNT]; 550 | static int32 mAllocatedTimerGraphNodes[V_GPU_TIMER_FRAMECOUNT]; 551 | }; 552 | 553 | struct ScopedGpuTimer 554 | { 555 | ScopedGpuTimer(const char* name, unsigned char r, unsigned char g, unsigned char b) 556 | : mName(name) 557 | { 558 | DxGpuPerformance::startGpuTimer(mName, r, g, b); 559 | } 560 | ~ScopedGpuTimer() 561 | { 562 | release(); 563 | } 564 | void release() 565 | { 566 | if (!released) 567 | { 568 | released = true; 569 | DxGpuPerformance::endGpuTimer(mName); 570 | } 571 | } 572 | private: 573 | ScopedGpuTimer() = delete; 574 | ScopedGpuTimer(ScopedGpuTimer&) = delete; 575 | const char* mName; 576 | bool released = false; 577 | }; 578 | 579 | #define GPU_SCOPED_TIMER(timerName, r, g, b) ScopedGpuTimer gpuTimer##timerName##(#timerName, r, g, b) 580 | #define GPU_SCOPED_TIMEREVENT(teName, r, g, b) GPU_SCOPED_EVENT(teName);GPU_SCOPED_TIMER(teName, r, g, b); 581 | 582 | 583 | //////////////////////////////////////////////////////////////////////////////////////////////////// 584 | //////////////////////////////////////////////////////////////////////////////////////////////////// 585 | //////////////////////////////////////////////////////////////////////////////////////////////////// 586 | 587 | 588 | template 589 | void resetComPtr(type** ptr) 590 | { 591 | if (*ptr) 592 | { 593 | (*ptr)->Release(); 594 | (*ptr) = nullptr; 595 | } 596 | } 597 | 598 | template 599 | void resetPtr(type** ptr) 600 | { 601 | if (*ptr) 602 | { 603 | delete *ptr; 604 | (*ptr) = nullptr; 605 | } 606 | } 607 | 608 | // Can be used to load and reload (live update) a shader 609 | template 610 | bool reload(type** previousShader, const TCHAR* filename, const char* entryFunction, bool exitIfFail, const Macros* macros = NULL, bool lazyCompilation = false) 611 | { 612 | type* newShader = new type(filename, entryFunction, macros, lazyCompilation); 613 | if (newShader->compilationSuccessful() || lazyCompilation) 614 | { 615 | // if lazyCompilation, we need to assign the newly create object. Later compilation that do not want to recreate object should just mark the shader object as dirty. 616 | // If compilation succesful also. 617 | resetPtr(previousShader); 618 | *previousShader = newShader; 619 | return true; 620 | } 621 | else 622 | { 623 | delete newShader; 624 | if (exitIfFail) 625 | exit(0); 626 | return false; 627 | } 628 | } 629 | 630 | 631 | //////////////////////////////////////////////////////////////////////////////////////////////////// 632 | //////////////////////////////////////////////////////////////////////////////////////////////////// 633 | //////////////////////////////////////////////////////////////////////////////////////////////////// 634 | 635 | 636 | 637 | int32 divRoundUp(int32 numer, int32 denum); 638 | 639 | 640 | -------------------------------------------------------------------------------- /DX11Base/DxMath.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #include "DirectXMath.h" 5 | using namespace DirectX; 6 | 7 | typedef unsigned char uint8; 8 | typedef unsigned short uint16; 9 | typedef unsigned int uint32; 10 | typedef char int8; 11 | typedef short int16; 12 | typedef long int32; 13 | //typedef float float; 14 | 15 | typedef XMMATRIX float4x4; 16 | typedef XMVECTOR Vector4; 17 | typedef XMFLOAT4 float4; 18 | typedef XMFLOAT3 float3; 19 | 20 | #define CLAMP(x, x0, x1) (x < x0 ? x0 : (x > x1 ? x1 : x)) 21 | 22 | 23 | -------------------------------------------------------------------------------- /DX11Base/WindowHelper.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "WindowHelper.h" 3 | 4 | 5 | LRESULT CALLBACK WindowProcess(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 6 | { 7 | WindowHelper *window = (WindowHelper*)GetWindowLongPtr(hWnd, GWLP_USERDATA); 8 | 9 | switch (message) 10 | { 11 | case WM_DESTROY: 12 | PostQuitMessage(0); 13 | return 0; 14 | break; 15 | } 16 | 17 | switch (message) 18 | { 19 | case WM_MOUSEMOVE: 20 | case WM_LBUTTONDOWN: 21 | case WM_RBUTTONDOWN: 22 | case WM_MBUTTONDOWN: 23 | case WM_LBUTTONUP: 24 | case WM_RBUTTONUP: 25 | case WM_MBUTTONUP: 26 | case WM_LBUTTONDBLCLK: 27 | case WM_RBUTTONDBLCLK: 28 | case WM_MBUTTONDBLCLK: 29 | case WM_NCMOUSELEAVE: 30 | case WM_MOUSEWHEEL: 31 | case WM_MOUSEHWHEEL: 32 | window->processMouseMessage(message, wParam, lParam); 33 | break; 34 | 35 | case WM_KEYDOWN: 36 | case WM_KEYUP: 37 | case WM_CHAR: 38 | case WM_SYSCHAR: 39 | window->processKeyMessage(message, wParam, lParam); 40 | break; 41 | 42 | case WM_SIZE: 43 | //case WM_SIZING: // When receiving that message, the backbuffer we get is null for some reason. Would be good to still see image on screen. 44 | // Also it seems that this is not even enough to handle a windo going full screen. Using Atl+Enter make things crash of lock up. 45 | if (wParam != SIZE_MINIMIZED) 46 | { 47 | window->processWindowSizeMessage(message, wParam, lParam); 48 | } 49 | break; 50 | } 51 | 52 | // Handle any messages the switch statement didn't 53 | return DefWindowProc(hWnd, message, wParam, lParam); 54 | } 55 | 56 | 57 | WindowHelper::WindowHelper(HINSTANCE hInstance, const RECT& clientRect, int nCmdShow, LPCWSTR windowName) 58 | : mHInstance(hInstance) 59 | , mNCmdShow(nCmdShow) 60 | , mClientRect(clientRect) 61 | { 62 | mInput.init(); 63 | 64 | // And create the rectangle that will allow it 65 | RECT rect = { 0, 0, clientRect.right - clientRect.left, clientRect.bottom - clientRect.top }; // set the size, but not the position otherwise does not seem to work 66 | DWORD style = (WS_OVERLAPPEDWINDOW | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX); // WS_OVERLAPPED without edge resize, WS_OVERLAPPEDWINDOW with 67 | BOOL menu = false; 68 | AdjustWindowRect(&rect, style, menu); 69 | //Get the required window dimensions 70 | int WindowWidth = rect.right - rect.left; //Required width 71 | //WindowWidth += (2 * GetSystemMetrics(SM_CXFIXEDFRAME)); //Add frame widths 72 | int WindowHeight = rect.bottom - rect.top; //Required height 73 | //WindowHeight += GetSystemMetrics(SM_CYCAPTION); //Titlebar height 74 | //WindowHeight += GetSystemMetrics(SM_CYMENU); //Uncomment for menu bar height 75 | //WindowHeight += (2 * GetSystemMetrics(SM_CYFIXEDFRAME)); //Frame heights 76 | 77 | // clear out the window class for use 78 | ZeroMemory(&mWc, sizeof(WNDCLASSEX)); 79 | // fill in the struct with the needed information 80 | mWc.cbSize = sizeof(WNDCLASSEX); 81 | mWc.style = CS_HREDRAW | CS_VREDRAW; 82 | mWc.lpfnWndProc = WindowProcess; 83 | mWc.hInstance = mHInstance; 84 | mWc.hCursor = LoadCursor(NULL, IDC_ARROW); 85 | mWc.hbrBackground = (HBRUSH)COLOR_WINDOW; 86 | mWc.lpszClassName = L"WindowClass1"; 87 | 88 | // register the window class 89 | RegisterClassEx(&mWc); 90 | 91 | // create the window and use the result as the handle 92 | mHWnd = CreateWindowEx(NULL, 93 | L"WindowClass1", // name of the window class 94 | windowName, // title of the window 95 | style, // not resizable 96 | clientRect.top, // x-position of the window 97 | clientRect.left, // y-position of the window 98 | WindowWidth, // width of the window 99 | WindowHeight, // height of the window 100 | NULL, // we have no parent window, NULL 101 | NULL, // we aren't using menus, NULL 102 | hInstance, // application handle 103 | NULL); // used with multiple windows, NULL 104 | 105 | SetWindowLongPtr(mHWnd, GWLP_USERDATA, (LONG_PTR)(this)); 106 | SetWindowPos(mHWnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER); // Make sure the pointer is cached https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setwindowlongptra 107 | } 108 | 109 | WindowHelper::~WindowHelper() 110 | { 111 | } 112 | 113 | 114 | void WindowHelper::showWindow() 115 | { 116 | ShowWindow(mHWnd, mNCmdShow); 117 | } 118 | 119 | 120 | void WindowHelper::processMouseMessage(UINT message, WPARAM wParam, LPARAM lParam) 121 | { 122 | // TODO WM_NCMOUSELEAVE 123 | 124 | mInput.mInputStatus.mouseX = LOWORD(lParam); 125 | mInput.mInputStatus.mouseY = HIWORD(lParam); 126 | 127 | InputEvent event; 128 | event.mouseX = mInput.mInputStatus.mouseX; 129 | event.mouseY = mInput.mInputStatus.mouseY; 130 | switch (message) 131 | { 132 | case WM_MOUSEMOVE: 133 | event.type = etMouseMoved; 134 | break; 135 | case WM_LBUTTONDOWN: 136 | event.type = etMouseButtonDown; 137 | event.mouseButton = mbLeft; 138 | mInput.mInputStatus.mouseButtons[event.mouseButton] = true; 139 | break; 140 | case WM_MBUTTONDOWN: 141 | event.type = etMouseButtonDown; 142 | event.mouseButton = mbMiddle; 143 | mInput.mInputStatus.mouseButtons[event.mouseButton] = true; 144 | break; 145 | case WM_RBUTTONDOWN: 146 | event.type = etMouseButtonDown; 147 | event.mouseButton = mbRight; 148 | mInput.mInputStatus.mouseButtons[event.mouseButton] = true; 149 | break; 150 | case WM_LBUTTONUP: 151 | event.type = etMouseButtonUp; 152 | event.mouseButton = mbLeft; 153 | mInput.mInputStatus.mouseButtons[event.mouseButton] = false; 154 | break; 155 | case WM_MBUTTONUP: 156 | event.type = etMouseButtonUp; 157 | event.mouseButton = mbMiddle; 158 | mInput.mInputStatus.mouseButtons[event.mouseButton] = false; 159 | break; 160 | case WM_RBUTTONUP: 161 | event.type = etMouseButtonUp; 162 | event.mouseButton = mbRight; 163 | mInput.mInputStatus.mouseButtons[event.mouseButton] = false; 164 | break; 165 | case WM_LBUTTONDBLCLK: 166 | event.type = etMouseButtonDoubleClick; 167 | event.mouseButton = mbLeft; 168 | break; 169 | case WM_MBUTTONDBLCLK: 170 | event.type = etMouseButtonDoubleClick; 171 | event.mouseButton = mbMiddle; 172 | break; 173 | case WM_RBUTTONDBLCLK: 174 | event.type = etMouseButtonDoubleClick; 175 | event.mouseButton = mbRight; 176 | break; 177 | 178 | // TODO 179 | //case WM_MOUSEWHEEL: 180 | //case WM_MOUSEHWHEEL: 181 | } 182 | mInput.mInputEvents.push_back(event); 183 | } 184 | 185 | static InputKey translateKey(WPARAM wParam) 186 | { 187 | switch (wParam) 188 | { 189 | case VK_RIGHT: return kRight; 190 | case VK_LEFT: return kLeft; 191 | case VK_DOWN: return kDown; 192 | case VK_UP: return kUp; 193 | case VK_SPACE: return kSpace; 194 | case VK_NUMPAD0: return kNumpad0; 195 | case VK_NUMPAD1: return kNumpad1; 196 | case VK_NUMPAD2: return kNumpad2; 197 | case VK_NUMPAD3: return kNumpad3; 198 | case VK_NUMPAD4: return kNumpad4; 199 | case VK_NUMPAD5: return kNumpad5; 200 | case VK_NUMPAD6: return kNumpad6; 201 | case VK_NUMPAD7: return kNumpad7; 202 | case VK_NUMPAD8: return kNumpad8; 203 | case VK_NUMPAD9: return kNumpad9; 204 | case VK_MULTIPLY: return kMultiply; 205 | case VK_ADD: return kAdd; 206 | case VK_SEPARATOR: return kSeparator; 207 | case VK_SUBTRACT: return kSubtract; 208 | case VK_DECIMAL: return kDecimal; 209 | case VK_DIVIDE: return kDivide; 210 | case VK_F1: return kF1; 211 | case VK_F2: return kF2; 212 | case VK_F3: return kF3; 213 | case VK_F4: return kF4; 214 | case VK_F5: return kF5; 215 | case VK_F6: return kF6; 216 | case VK_F7: return kF7; 217 | case VK_F8: return kF8; 218 | case VK_F9: return kF9; 219 | case VK_F10: return kF10; 220 | case VK_F11: return kF11; 221 | case VK_F12: return kF12; 222 | case VK_SHIFT: return kShift; 223 | case VK_CONTROL: return kControl; 224 | 225 | case '0': return k0; 226 | case '1': return k1; 227 | case '2': return k2; 228 | case '3': return k3; 229 | case '4': return k4; 230 | case '5': return k5; 231 | case '6': return k6; 232 | case '7': return k7; 233 | case '8': return k8; 234 | case '9': return k9; 235 | case 'A': return kA; 236 | case 'B': return kB; 237 | case 'C': return kC; 238 | case 'D': return kD; 239 | case 'E': return kE; 240 | case 'F': return kF; 241 | case 'G': return kG; 242 | case 'H': return kH; 243 | case 'I': return kI; 244 | case 'J': return kJ; 245 | case 'K': return kK; 246 | case 'L': return kL; 247 | case 'M': return kM; 248 | case 'N': return kN; 249 | case 'O': return kO; 250 | case 'P': return kP; 251 | case 'Q': return kQ; 252 | case 'R': return kR; 253 | case 'S': return kS; 254 | case 'T': return kT; 255 | case 'U': return kU; 256 | case 'V': return kV; 257 | case 'W': return kW; 258 | case 'X': return kX; 259 | case 'Y': return kY; 260 | case 'Z': return kZ; 261 | 262 | // TODO VK_GAMEPAD 263 | 264 | default: 265 | return kUnknown; 266 | } 267 | } 268 | 269 | void WindowHelper::processKeyMessage(UINT message, WPARAM wParam, LPARAM lParam) 270 | { 271 | InputEvent event; 272 | event.mouseX = mInput.mInputStatus.mouseX; 273 | event.mouseY = mInput.mInputStatus.mouseY; 274 | 275 | event.key = translateKey(wParam); 276 | if (event.key == kUnknown) 277 | return; // unkown key so do not register the event. 278 | 279 | switch (message) 280 | { 281 | case WM_KEYDOWN: 282 | event.type = etKeyDown; 283 | mInput.mInputStatus.keys[event.key] = true; 284 | break; 285 | case WM_KEYUP: 286 | event.type = etKeyUp; 287 | mInput.mInputStatus.keys[event.key] = false; 288 | break; 289 | 290 | case WM_SYSCHAR: 291 | case WM_CHAR: 292 | event.type = etKeyChar; 293 | break; 294 | } 295 | 296 | if (event.key == kControl) 297 | { 298 | mInput.mInputStatus.keys[kLcontrol] = GetKeyState(VK_LCONTROL)!=0; 299 | mInput.mInputStatus.keys[kRcontrol] = GetKeyState(VK_RCONTROL)!=0; 300 | } 301 | else if (event.key == kShift) 302 | { 303 | mInput.mInputStatus.keys[kLshift] = GetKeyState(VK_LSHIFT)!=0; 304 | mInput.mInputStatus.keys[kRshift] = GetKeyState(VK_RSHIFT)!=0; 305 | } 306 | 307 | mInput.mInputEvents.push_back(event); 308 | } 309 | 310 | void WindowHelper::processWindowSizeMessage(UINT message, WPARAM wParam, LPARAM lParam) 311 | { 312 | mWindowResizedCallback(lParam); 313 | } 314 | 315 | bool WindowHelper::translateSingleMessage(MSG& msg) 316 | { 317 | if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 318 | { 319 | // translate keystroke messages into the right format 320 | TranslateMessage(&msg); 321 | 322 | // Message translated 323 | return true; 324 | } 325 | 326 | // No message translated 327 | return false; 328 | } 329 | -------------------------------------------------------------------------------- /DX11Base/WindowHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "WindowInput.h" 6 | 7 | #include 8 | 9 | class WindowHelper 10 | { 11 | public: 12 | WindowHelper( 13 | HINSTANCE hInstance, 14 | const RECT& clientRect, 15 | int nCmdShow, 16 | LPCWSTR windowName); 17 | ~WindowHelper(); 18 | 19 | void showWindow(); 20 | 21 | bool translateSingleMessage(MSG& msg); 22 | 23 | const WindowInputData& getInputData() 24 | { 25 | return mInput; 26 | } 27 | void clearInputEvents() 28 | { 29 | mInput.mInputEvents.clear(); 30 | } 31 | 32 | const HWND getHwnd() { return mHWnd; } 33 | 34 | void processMouseMessage(UINT message, WPARAM wParam, LPARAM lParam); 35 | void processKeyMessage(UINT message, WPARAM wParam, LPARAM lParam); 36 | void processWindowSizeMessage(UINT message, WPARAM wParam, LPARAM lParam); 37 | 38 | void setWindowResizedCallback(std::function windowResizedCallback) { mWindowResizedCallback = windowResizedCallback; } 39 | 40 | private: 41 | WindowHelper(); 42 | 43 | 44 | HINSTANCE mHInstance; /// The application instance 45 | HWND mHWnd; /// The handle for the window, filled by a function 46 | WNDCLASSEX mWc; /// This struct holds information for the window class 47 | RECT mClientRect; /// The client rectangle where we render into 48 | int mNCmdShow; /// Window show cmd 49 | 50 | WindowInputData mInput; /// input event and status (mouse, keyboard, etc.) 51 | 52 | std::function mWindowResizedCallback = [&](LPARAM lParam){}; 53 | }; 54 | 55 | 56 | -------------------------------------------------------------------------------- /DX11Base/WindowInput.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | enum InputKey 6 | { 7 | kLeft, 8 | kRight, 9 | kUp, 10 | kDown, 11 | kSpace, 12 | kNumpad0, 13 | kNumpad1, 14 | kNumpad2, 15 | kNumpad3, 16 | kNumpad4, 17 | kNumpad5, 18 | kNumpad6, 19 | kNumpad7, 20 | kNumpad8, 21 | kNumpad9, 22 | kMultiply, 23 | kAdd, 24 | kSeparator, 25 | kSubtract, 26 | kDecimal, 27 | kDivide, 28 | kF1, 29 | kF2, 30 | kF3, 31 | kF4, 32 | kF5, 33 | kF6, 34 | kF7, 35 | kF8, 36 | kF9, 37 | kF10, 38 | kF11, 39 | kF12, 40 | 41 | kShift, // event and input status 42 | kControl, // event and input status 43 | kLshift, // never an event, only set on the input status 44 | kRshift, // never an event, only set on the input status 45 | kLcontrol, // never an event, only set on the input status 46 | kRcontrol, // never an event, only set on the input status 47 | 48 | k0, 49 | k1, 50 | k2, 51 | k3, 52 | k4, 53 | k5, 54 | k6, 55 | k7, 56 | k8, 57 | k9, 58 | kA, 59 | kB, 60 | kC, 61 | kD, 62 | kE, 63 | kF, 64 | kG, 65 | kH, 66 | kI, 67 | kJ, 68 | kK, 69 | kL, 70 | kM, 71 | kN, 72 | kO, 73 | kP, 74 | kQ, 75 | kR, 76 | kS, 77 | kT, 78 | kU, 79 | kV, 80 | kW, 81 | kX, 82 | kY, 83 | kZ, 84 | 85 | kCount, 86 | kUnknown 87 | }; 88 | enum InputMouseButton 89 | { 90 | mbLeft, 91 | mbMiddle, 92 | mbRight, 93 | mbCount 94 | }; 95 | enum InputEventType 96 | { 97 | etKeyUp, 98 | etKeyDown, 99 | etKeyChar, 100 | etMouseMoved, 101 | etMouseButtonUp, 102 | etMouseButtonDown, 103 | etMouseButtonDoubleClick, 104 | etCount 105 | }; 106 | 107 | struct InputEvent 108 | { 109 | InputEventType type; 110 | union 111 | { 112 | InputKey key; 113 | InputMouseButton mouseButton; 114 | }; 115 | int mouseX; 116 | int mouseY; 117 | }; 118 | 119 | struct WindowInputStatus 120 | { 121 | 122 | bool keys[kCount]; 123 | bool mouseButtons[mbCount]; 124 | int mouseX; 125 | int mouseY; 126 | 127 | void init() 128 | { 129 | memset(this, 0, sizeof(WindowInputStatus)); 130 | } 131 | 132 | }; 133 | 134 | typedef std::vector WindowInputEventList; 135 | 136 | struct WindowInputData 137 | { 138 | WindowInputStatus mInputStatus; /// status after all events in mInputEvents 139 | WindowInputEventList mInputEvents; /// every events that occured ince last update 140 | 141 | void init() 142 | { 143 | mInputStatus.init(); 144 | mInputEvents.clear(); 145 | mInputEvents.reserve(16); 146 | } 147 | }; 148 | 149 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebh/Dx11Base/497ba82ded6c6beb169446ce03df328b984b6751/LICENSE.md -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dx11Base 2 | 3 | ![dx11appscreenshot](https://github.com/sebh/Dx11Base/blob/master/DX11Application.png) 4 | 5 | A small DirectX 11 program I use to test shaders and techniques (windows only). It is meant to be simple and straightforward. Nothing fancy to see here: plenty of _engines_ already exist out there. 6 | 7 | Features are 8 | * Simple class helpers above DirectX 11.X functions 9 | * Live update of shaders with saving via `ctrl+s` 10 | * UI achieved with [Dear ImGui](https://github.com/ocornut/imgui) 11 | * Performance measured with GPU timers and reported in UI (tested on intel and nvidia so far) 12 | * Simple window and input management (could be improved) 13 | * Works well with ![RenderDoc](https://renderdoc.org/) 14 | 15 | When cloning the project the first time: 16 | 1. Update submodules (run `git submodule update`) 17 | 1. Open the solution 18 | 2. In Visual Studio, change the _Application_ project _Working Directory_ from `$(ProjectDir)` to `$(SolutionDir)` 19 | 3. Make sure you select a windows SDK and a platform toolset you have locally on your computer for both projects 20 | 4. Select _Application_ as the startup project, hit F5 21 | 22 | Submodules 23 | * [imgui](https://github.com/ocornut/imgui) V1.62 supported 24 | 25 | Have fun and do not hesitate to send back suggestions. 26 | 27 | Seb 28 | -------------------------------------------------------------------------------- /Resources/ColoredTriangles.hlsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #include "./Resources/Common.hlsl" 5 | 6 | 7 | 8 | float4 ColoredTrianglesPixelShader(VertexOutput input) : SV_TARGET 9 | { 10 | return gColor; 11 | } 12 | 13 | 14 | -------------------------------------------------------------------------------- /Resources/Common.hlsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | cbuffer CONSTANT_BUFFER : register(b0) 5 | { 6 | float4x4 gViewProjMat; 7 | 8 | float4 gColor; 9 | 10 | uint2 gResolution; 11 | uint2 pad; 12 | }; 13 | 14 | SamplerState samplerLinearClamp : register(s0); 15 | 16 | Texture2D texture2d : register(t0); 17 | 18 | RWTexture2D rwTexture2d : register(u0); 19 | //RWBuffer buffer : register(u0); 20 | //RasterizerOrderedBuffer buffer : register(u0); 21 | 22 | 23 | 24 | //////////////////////////////////////////////////////////////////////////////////////////////////// 25 | 26 | 27 | 28 | struct VertexInput 29 | { 30 | float4 position : POSITION; 31 | }; 32 | 33 | struct VertexOutput 34 | { 35 | float4 position : SV_POSITION; 36 | }; 37 | 38 | 39 | 40 | VertexOutput DefaultVertexShader(VertexInput input) 41 | { 42 | VertexOutput output = (VertexOutput)0; 43 | 44 | // Calculate the position of the vertex against the world, view, and projection matrices. 45 | output.position = mul(input.position, gViewProjMat); 46 | 47 | return output; 48 | } 49 | 50 | 51 | 52 | VertexOutput ScreenTriangleVertexShader(uint vertexId : SV_VertexID) 53 | { 54 | VertexOutput output = (VertexOutput)0; 55 | 56 | // For a range on screen in [-0.5,0.5] 57 | float2 uv = -1.0f; 58 | uv = vertexId == 1 ? float2(-1.0f, 3.0f) : uv; 59 | uv = vertexId == 2 ? float2( 3.0f,-1.0f) : uv; 60 | output.position = float4(uv, 0.0f, 1.0f); 61 | 62 | return output; 63 | } 64 | 65 | 66 | -------------------------------------------------------------------------------- /Resources/PostProcess.hlsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #include "./Resources/Common.hlsl" 5 | 6 | 7 | 8 | float sRGB(float x) 9 | { 10 | if (x <= 0.00031308) 11 | return 12.92 * x; 12 | else 13 | return 1.055*pow(x, (1.0 / 2.4)) - 0.055; 14 | } 15 | 16 | float4 sRGB(float4 vec) 17 | { 18 | return float4(sRGB(vec.x), sRGB(vec.y), sRGB(vec.z), vec.w); 19 | } 20 | 21 | 22 | 23 | float4 PostProcessPS(VertexOutput input) : SV_TARGET 24 | { 25 | uint2 texCoord = input.position.xy; 26 | float4 rgbA = texture2d.Load(uint3(texCoord,0)); 27 | return sRGB(rgbA); 28 | } 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Resources/ToyShader.hlsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #include "./Resources/Common.hlsl" 5 | 6 | 7 | 8 | [numthreads(8, 8, 1)] 9 | void ToyShaderCS(uint3 threadId : SV_DispatchThreadID) 10 | { 11 | uint2 texCoord = threadId.xy; 12 | 13 | rwTexture2d[texCoord] = float4(texCoord / float2(gResolution), 0.0, 1.0);; 14 | } 15 | 16 | 17 | --------------------------------------------------------------------------------