├── .clang-format ├── .gitignore ├── Chapter1 ├── .vscode │ └── settings.json ├── shader │ └── shaders.hlsl ├── src │ ├── D3D12HelloTriangle.cpp │ ├── D3D12HelloTriangle.h │ ├── DXSample.cpp │ ├── DXSample.h │ ├── DXSampleHelper.h │ ├── Main.cpp │ ├── Metalib.h │ ├── Win32Application.cpp │ ├── Win32Application.h │ ├── d3dx12.h │ ├── stdafx.h │ └── xmake.lua └── xmake.lua ├── Chapter2 ├── .vscode │ └── settings.json ├── shader │ └── shaders.hlsl ├── src │ ├── D3D12HelloTriangle.cpp │ ├── D3D12HelloTriangle.h │ ├── DXRuntime │ │ ├── Device.cpp │ │ └── Device.h │ ├── DXSample.cpp │ ├── DXSample.h │ ├── DXSampleHelper.h │ ├── Main.cpp │ ├── Metalib.h │ ├── Resource │ │ ├── Buffer.cpp │ │ ├── Buffer.h │ │ ├── BufferView.h │ │ ├── DefaultBuffer.cpp │ │ ├── DefaultBuffer.h │ │ ├── Mesh.cpp │ │ ├── Mesh.h │ │ ├── ReadbackBuffer.cpp │ │ ├── ReadbackBuffer.h │ │ ├── Resource.h │ │ ├── UploadBuffer.cpp │ │ └── UploadBuffer.h │ ├── Utility │ │ ├── ReflactableStruct.cpp │ │ └── ReflactableStruct.h │ ├── Win32Application.cpp │ ├── Win32Application.h │ ├── d3dx12.h │ ├── stdafx.h │ └── xmake.lua └── xmake.lua ├── Chapter3 ├── .vscode │ └── settings.json ├── shader │ └── shaders.hlsl ├── src │ ├── Component │ │ ├── Camera.cpp │ │ └── Camera.h │ ├── D3D12SimpleBox.cpp │ ├── D3D12SimpleBox.h │ ├── DXMath │ │ ├── Common.h │ │ ├── DXMath.cpp │ │ ├── DXMath.h │ │ ├── DXMathConfig.h │ │ ├── MathHelper.cpp │ │ ├── MathHelper.h │ │ ├── Matrix3.h │ │ ├── Matrix4.h │ │ ├── Quaternion.h │ │ ├── Scalar.h │ │ ├── Swizzle.h │ │ └── Vector.h │ ├── DXRuntime │ │ ├── CommandListHandle.cpp │ │ ├── CommandListHandle.h │ │ ├── Device.cpp │ │ ├── Device.h │ │ ├── FrameResource.cpp │ │ └── FrameResource.h │ ├── DXSample.cpp │ ├── DXSample.h │ ├── DXSampleHelper.h │ ├── Main.cpp │ ├── Metalib.h │ ├── Resource │ │ ├── Buffer.cpp │ │ ├── Buffer.h │ │ ├── BufferView.h │ │ ├── DefaultBuffer.cpp │ │ ├── DefaultBuffer.h │ │ ├── DescriptorHeap.cpp │ │ ├── DescriptorHeap.h │ │ ├── DescriptorHeapView.h │ │ ├── Mesh.cpp │ │ ├── Mesh.h │ │ ├── ReadbackBuffer.cpp │ │ ├── ReadbackBuffer.h │ │ ├── Resource.h │ │ ├── UploadBuffer.cpp │ │ └── UploadBuffer.h │ ├── Utility │ │ ├── Hash.h │ │ ├── ReflactableStruct.cpp │ │ ├── ReflactableStruct.h │ │ └── xxhash.cpp │ ├── Win32Application.cpp │ ├── Win32Application.h │ ├── d3dx12.h │ ├── stdafx.h │ └── xmake.lua └── xmake.lua └── Chapter4 ├── .vscode └── settings.json ├── shader └── shaders.hlsl ├── src ├── Component │ ├── Camera.cpp │ └── Camera.h ├── D3D12BetterSimpleBox.cpp ├── D3D12BetterSimpleBox.h ├── DXMath │ ├── Common.h │ ├── DXMath.cpp │ ├── DXMath.h │ ├── MathHelper.cpp │ ├── MathHelper.h │ ├── Matrix3.h │ ├── Matrix4.h │ ├── Quaternion.h │ ├── Scalar.h │ ├── Swizzle.h │ └── Vector.h ├── DXRuntime │ ├── BindProperty.h │ ├── CommandListHandle.cpp │ ├── CommandListHandle.h │ ├── Device.cpp │ ├── Device.h │ ├── FrameResource.cpp │ ├── FrameResource.h │ ├── ResourceStateTracker.cpp │ └── ResourceStateTracker.h ├── DXSample.cpp ├── DXSample.h ├── DXSampleHelper.h ├── Main.cpp ├── Metalib.h ├── Resource │ ├── Buffer.cpp │ ├── Buffer.h │ ├── BufferView.h │ ├── DefaultBuffer.cpp │ ├── DefaultBuffer.h │ ├── DescriptorHeap.cpp │ ├── DescriptorHeap.h │ ├── DescriptorHeapView.h │ ├── Mesh.cpp │ ├── Mesh.h │ ├── ReadbackBuffer.cpp │ ├── ReadbackBuffer.h │ ├── Resource.h │ ├── Texture.cpp │ ├── Texture.h │ ├── UploadBuffer.cpp │ └── UploadBuffer.h ├── Shader │ ├── GlobalSamplers.cpp │ ├── GlobalSamplers.h │ ├── PSOManager.cpp │ ├── PSOManager.h │ ├── RasterShader.cpp │ ├── RasterShader.h │ ├── Shader.cpp │ ├── Shader.h │ └── ShaderVariableType.h ├── Utility │ ├── Hash.h │ ├── ReflactableStruct.cpp │ ├── ReflactableStruct.h │ ├── StackAllocator.cpp │ ├── StackAllocator.h │ └── xxhash.cpp ├── Win32Application.cpp ├── Win32Application.h ├── d3dx12.h ├── stdafx.h └── xmake.lua └── xmake.lua /.clang-format: -------------------------------------------------------------------------------- 1 | # Generated from CLion C/C++ Code Style settings 2 | BasedOnStyle: LLVM 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: false 6 | AlignOperands: true 7 | AllowAllArgumentsOnNextLine: false 8 | AllowAllConstructorInitializersOnNextLine: false 9 | AllowAllParametersOfDeclarationOnNextLine: false 10 | AllowShortBlocksOnASingleLine: Always 11 | AllowShortCaseLabelsOnASingleLine: true 12 | AllowShortFunctionsOnASingleLine: All 13 | AllowShortIfStatementsOnASingleLine: Always 14 | AllowShortLambdasOnASingleLine: All 15 | AllowShortLoopsOnASingleLine: true 16 | AlwaysBreakAfterReturnType: None 17 | AlwaysBreakTemplateDeclarations: Yes 18 | BreakBeforeBraces: Custom 19 | BraceWrapping: 20 | AfterCaseLabel: false 21 | AfterClass: false 22 | AfterControlStatement: Never 23 | AfterEnum: false 24 | AfterFunction: false 25 | AfterNamespace: false 26 | AfterUnion: false 27 | BeforeCatch: false 28 | BeforeElse: false 29 | IndentBraces: false 30 | SplitEmptyFunction: false 31 | SplitEmptyRecord: true 32 | BreakBeforeBinaryOperators: NonAssignment 33 | BreakBeforeTernaryOperators: true 34 | BreakConstructorInitializers: BeforeColon 35 | BreakInheritanceList: BeforeColon 36 | ColumnLimit: 0 37 | SortIncludes: false 38 | CompactNamespaces: true 39 | ContinuationIndentWidth: 4 40 | IndentCaseLabels: true 41 | IndentPPDirectives: None 42 | IndentWidth: 4 43 | KeepEmptyLinesAtTheStartOfBlocks: true 44 | MaxEmptyLinesToKeep: 1 45 | NamespaceIndentation: None 46 | ObjCSpaceAfterProperty: false 47 | ObjCSpaceBeforeProtocolList: false 48 | PointerAlignment: Left 49 | ReflowComments: false 50 | SpaceAfterCStyleCast: false 51 | SpaceAfterLogicalNot: false 52 | SpaceAfterTemplateKeyword: false 53 | SpaceBeforeAssignmentOperators: true 54 | SpaceBeforeCpp11BracedList: false 55 | SpaceBeforeCtorInitializerColon: true 56 | SpaceBeforeInheritanceColon: true 57 | SpaceBeforeParens: ControlStatements 58 | SpaceBeforeRangeBasedForLoopColon: true 59 | SpaceInEmptyParentheses: false 60 | SpacesBeforeTrailingComments: 0 61 | SpacesInAngles: false 62 | SpacesInCStyleCastParentheses: false 63 | SpacesInContainerLiterals: false 64 | SpacesInParentheses: false 65 | SpacesInSquareBrackets: false 66 | TabWidth: 4 67 | UseTab: Always 68 | -------------------------------------------------------------------------------- /Chapter1/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "C_Cpp.codeAnalysis.runAutomatically": false, 3 | "C_Cpp.intelliSenseEngine": "Disabled", 4 | "C_Cpp.formatting": "Disabled", 5 | "C_Cpp.autoAddFileAssociations": false, 6 | "C_Cpp.autocompleteAddParentheses": false, 7 | "C_Cpp.autocomplete": "Disabled", 8 | "C_Cpp.errorSquiggles": "Disabled", 9 | "clangd.arguments": [ 10 | "--compile-commands-dir=.vscode", 11 | "-j=24", 12 | "--log=error", 13 | "--completion-style=bundled", 14 | "--background-index", 15 | "--header-insertion=never", 16 | "--pch-storage=memory", 17 | "--offset-encoding=utf-8" 18 | ], 19 | "editor.accessibilitySupport": "off" 20 | } -------------------------------------------------------------------------------- /Chapter1/shader/shaders.hlsl: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | struct PSInput 13 | { 14 | float4 position : SV_POSITION; 15 | float4 color : COLOR; 16 | }; 17 | 18 | PSInput VSMain(float4 position : POSITION, float4 color : COLOR) 19 | { 20 | PSInput result; 21 | 22 | result.position = position; 23 | result.color = color; 24 | 25 | return result; 26 | } 27 | 28 | float4 PSMain(PSInput input) : SV_TARGET 29 | { 30 | return input.color; 31 | } 32 | -------------------------------------------------------------------------------- /Chapter1/src/D3D12HelloTriangle.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | //0 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #pragma once 13 | 14 | #include "DXSample.h" 15 | 16 | using namespace DirectX; 17 | // Note that while ComPtr is used to manage the lifetime of resources on the CPU, 18 | // it has no understanding of the lifetime of resources on the GPU. Apps must account 19 | // for the GPU lifetime of resources to avoid destroying objects that may still be 20 | // referenced by the GPU. 21 | // An example of this can be found in the class method: OnDestroy(). 22 | using Microsoft::WRL::ComPtr; 23 | class D3D12HelloTriangle : public DXSample { 24 | public: 25 | D3D12HelloTriangle(uint32_t width, uint32_t height, std::wstring name); 26 | void OnInit() override; 27 | void OnUpdate() override; 28 | void OnRender() override; 29 | void OnDestroy() override; 30 | 31 | private: 32 | static const uint32_t FrameCount = 2; 33 | 34 | struct Vertex { 35 | XMFLOAT3 position; 36 | XMFLOAT4 color; 37 | }; 38 | 39 | // Pipeline objects. 40 | CD3DX12_VIEWPORT m_viewport; 41 | CD3DX12_RECT m_scissorRect; 42 | ComPtr m_swapChain; 43 | ComPtr m_device; 44 | ComPtr m_renderTargets[FrameCount]; 45 | ComPtr m_commandAllocator; 46 | ComPtr m_commandQueue; 47 | ComPtr m_rootSignature; 48 | ComPtr m_rtvHeap; 49 | ComPtr m_pipelineState; 50 | ComPtr m_commandList; 51 | uint32_t m_rtvDescriptorSize; 52 | 53 | // App resources. 54 | ComPtr m_vertexBuffer; 55 | D3D12_VERTEX_BUFFER_VIEW m_vertexBufferView; 56 | 57 | // Synchronization objects. 58 | uint32_t m_frameIndex; 59 | HANDLE m_fenceEvent; 60 | ComPtr m_fence; 61 | uint64_t m_fenceValue; 62 | 63 | void LoadPipeline(); 64 | void LoadAssets(); 65 | void PopulateCommandList(); 66 | void WaitForPreviousFrame(); 67 | }; 68 | -------------------------------------------------------------------------------- /Chapter1/src/DXSample.cpp: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #include "stdafx.h" 13 | #include "DXSample.h" 14 | 15 | using namespace Microsoft::WRL; 16 | 17 | DXSample::DXSample(uint32_t width, uint32_t height, std::wstring name) : 18 | m_width(width), 19 | m_height(height), 20 | m_title(name), 21 | m_useWarpDevice(false) 22 | { 23 | wchar_t assetsPath[512]; 24 | GetAssetsPath(assetsPath, _countof(assetsPath)); 25 | m_assetsPath = assetsPath; 26 | 27 | m_aspectRatio = static_cast(width) / static_cast(height); 28 | } 29 | 30 | DXSample::~DXSample() 31 | { 32 | } 33 | 34 | // Helper function for resolving the full path of assets. 35 | std::wstring DXSample::GetAssetFullPath(LPCWSTR assetName) 36 | { 37 | return m_assetsPath + assetName; 38 | } 39 | 40 | // Helper function for acquiring the first available hardware adapter that supports Direct3D 12. 41 | // If no such adapter can be found, *ppAdapter will be set to nullptr. 42 | _Use_decl_annotations_ 43 | void DXSample::GetHardwareAdapter( 44 | IDXGIFactory1* pFactory, 45 | IDXGIAdapter1** ppAdapter, 46 | bool requestHighPerformanceAdapter) 47 | { 48 | *ppAdapter = nullptr; 49 | 50 | ComPtr adapter; 51 | 52 | ComPtr factory6; 53 | if (SUCCEEDED(pFactory->QueryInterface(IID_PPV_ARGS(&factory6)))) 54 | { 55 | for ( 56 | uint32_t adapterIndex = 0; 57 | SUCCEEDED(factory6->EnumAdapterByGpuPreference( 58 | adapterIndex, 59 | requestHighPerformanceAdapter == true ? DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE : DXGI_GPU_PREFERENCE_UNSPECIFIED, 60 | IID_PPV_ARGS(&adapter))); 61 | ++adapterIndex) 62 | { 63 | DXGI_ADAPTER_DESC1 desc; 64 | adapter->GetDesc1(&desc); 65 | 66 | if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) 67 | { 68 | // Don't select the Basic Render Driver adapter. 69 | // If you want a software adapter, pass in "/warp" on the command line. 70 | continue; 71 | } 72 | 73 | // Check to see whether the adapter supports Direct3D 12, but don't create the 74 | // actual device yet. 75 | if (SUCCEEDED(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr))) 76 | { 77 | break; 78 | } 79 | } 80 | } 81 | 82 | if(adapter.Get() == nullptr) 83 | { 84 | for (uint32_t adapterIndex = 0; SUCCEEDED(pFactory->EnumAdapters1(adapterIndex, &adapter)); ++adapterIndex) 85 | { 86 | DXGI_ADAPTER_DESC1 desc; 87 | adapter->GetDesc1(&desc); 88 | 89 | if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) 90 | { 91 | // Don't select the Basic Render Driver adapter. 92 | // If you want a software adapter, pass in "/warp" on the command line. 93 | continue; 94 | } 95 | 96 | // Check to see whether the adapter supports Direct3D 12, but don't create the 97 | // actual device yet. 98 | if (SUCCEEDED(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr))) 99 | { 100 | break; 101 | } 102 | } 103 | } 104 | 105 | *ppAdapter = adapter.Detach(); 106 | } 107 | 108 | // Helper function for setting the window's title text. 109 | void DXSample::SetCustomWindowText(LPCWSTR text) 110 | { 111 | std::wstring windowText = m_title + L": " + text; 112 | SetWindowText(Win32Application::GetHwnd(), windowText.c_str()); 113 | } 114 | 115 | // Helper function for parsing any supplied command line args. 116 | _Use_decl_annotations_ 117 | void DXSample::ParseCommandLineArgs(wchar_t* argv[], int argc) 118 | { 119 | for (int i = 1; i < argc; ++i) 120 | { 121 | if (_wcsnicmp(argv[i], L"-warp", wcslen(argv[i])) == 0 || 122 | _wcsnicmp(argv[i], L"/warp", wcslen(argv[i])) == 0) 123 | { 124 | m_useWarpDevice = true; 125 | m_title = m_title + L" (WARP)"; 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /Chapter1/src/DXSample.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #pragma once 13 | 14 | #include "DXSampleHelper.h" 15 | #include "Win32Application.h" 16 | 17 | class DXSample 18 | { 19 | public: 20 | DXSample(uint32_t width, uint32_t height, std::wstring name); 21 | virtual ~DXSample(); 22 | 23 | virtual void OnInit() = 0; 24 | virtual void OnUpdate() = 0; 25 | virtual void OnRender() = 0; 26 | virtual void OnDestroy() = 0; 27 | 28 | // Samples override the event handlers to handle specific messages. 29 | virtual void OnKeyDown(UINT8 /*key*/) {} 30 | virtual void OnKeyUp(UINT8 /*key*/) {} 31 | 32 | // Accessors. 33 | uint32_t GetWidth() const { return m_width; } 34 | uint32_t GetHeight() const { return m_height; } 35 | const wchar_t* GetTitle() const { return m_title.c_str(); } 36 | 37 | void ParseCommandLineArgs(_In_reads_(argc) wchar_t* argv[], int argc); 38 | 39 | protected: 40 | std::wstring GetAssetFullPath(LPCWSTR assetName); 41 | 42 | void GetHardwareAdapter( 43 | _In_ IDXGIFactory1* pFactory, 44 | _Outptr_result_maybenull_ IDXGIAdapter1** ppAdapter, 45 | bool requestHighPerformanceAdapter = false); 46 | 47 | void SetCustomWindowText(LPCWSTR text); 48 | 49 | // Viewport dimensions. 50 | uint32_t m_width; 51 | uint32_t m_height; 52 | float m_aspectRatio; 53 | 54 | // Adapter info. 55 | bool m_useWarpDevice; 56 | 57 | private: 58 | // Root assets path. 59 | std::wstring m_assetsPath; 60 | 61 | // Window title. 62 | std::wstring m_title; 63 | }; 64 | -------------------------------------------------------------------------------- /Chapter1/src/Main.cpp: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #include "stdafx.h" 13 | #include "D3D12HelloTriangle.h" 14 | 15 | _Use_decl_annotations_ 16 | int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) 17 | { 18 | D3D12HelloTriangle sample(1280, 720, L"D3D12 Hello Triangle"); 19 | return Win32Application::Run(&sample, hInstance, nCmdShow); 20 | } 21 | -------------------------------------------------------------------------------- /Chapter1/src/Metalib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | template 4 | requires(!std::is_lvalue_reference_v) 5 | T* get_rvalue_ptr(T&& v) { 6 | return &v; 7 | } 8 | template 9 | struct array_meta; 10 | template 11 | struct array_meta { 12 | static constexpr size_t array_size = N; 13 | static constexpr size_t byte_size = N * sizeof(T); 14 | }; 15 | 16 | template 17 | requires(std::is_bounded_array_v) constexpr size_t array_count(T const& t) { 18 | return array_meta::array_size; 19 | } 20 | template 21 | requires(std::is_bounded_array_v) constexpr size_t array_byte_size(T const& t) { 22 | return array_meta::byte_size; 23 | } -------------------------------------------------------------------------------- /Chapter1/src/Win32Application.cpp: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #include "stdafx.h" 13 | #include "Win32Application.h" 14 | 15 | HWND Win32Application::m_hwnd = nullptr; 16 | 17 | int Win32Application::Run(DXSample* pSample, HINSTANCE hInstance, int nCmdShow) 18 | { 19 | // Parse the command line parameters 20 | int argc; 21 | LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc); 22 | pSample->ParseCommandLineArgs(argv, argc); 23 | LocalFree(argv); 24 | 25 | // Initialize the window class. 26 | WNDCLASSEX windowClass = { 0 }; 27 | windowClass.cbSize = sizeof(WNDCLASSEX); 28 | windowClass.style = CS_HREDRAW | CS_VREDRAW; 29 | windowClass.lpfnWndProc = WindowProc; 30 | windowClass.hInstance = hInstance; 31 | windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); 32 | windowClass.lpszClassName = L"DXSampleClass"; 33 | RegisterClassEx(&windowClass); 34 | 35 | RECT windowRect = { 0, 0, static_cast(pSample->GetWidth()), static_cast(pSample->GetHeight()) }; 36 | AdjustWindowRect(&windowRect, WS_OVERLAPPEDWINDOW, FALSE); 37 | 38 | // Create the window and store a handle to it. 39 | m_hwnd = CreateWindow( 40 | windowClass.lpszClassName, 41 | pSample->GetTitle(), 42 | WS_OVERLAPPEDWINDOW, 43 | CW_USEDEFAULT, 44 | CW_USEDEFAULT, 45 | windowRect.right - windowRect.left, 46 | windowRect.bottom - windowRect.top, 47 | nullptr, // We have no parent window. 48 | nullptr, // We aren't using menus. 49 | hInstance, 50 | pSample); 51 | 52 | // Initialize the sample. OnInit is defined in each child-implementation of DXSample. 53 | pSample->OnInit(); 54 | 55 | ShowWindow(m_hwnd, nCmdShow); 56 | 57 | // Main sample loop. 58 | MSG msg = {}; 59 | while (msg.message != WM_QUIT) 60 | { 61 | // Process any messages in the queue. 62 | if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 63 | { 64 | TranslateMessage(&msg); 65 | DispatchMessage(&msg); 66 | } 67 | } 68 | 69 | pSample->OnDestroy(); 70 | 71 | // Return this part of the WM_QUIT message to Windows. 72 | return static_cast(msg.wParam); 73 | } 74 | 75 | // Main message handler for the sample. 76 | LRESULT CALLBACK Win32Application::WindowProc(HWND hWnd, uint32_t message, WPARAM wParam, LPARAM lParam) 77 | { 78 | DXSample* pSample = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); 79 | 80 | switch (message) 81 | { 82 | case WM_CREATE: 83 | { 84 | // Save the DXSample* passed in to CreateWindow. 85 | LPCREATESTRUCT pCreateStruct = reinterpret_cast(lParam); 86 | SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast(pCreateStruct->lpCreateParams)); 87 | } 88 | return 0; 89 | 90 | case WM_KEYDOWN: 91 | if (pSample) 92 | { 93 | pSample->OnKeyDown(static_cast(wParam)); 94 | } 95 | return 0; 96 | 97 | case WM_KEYUP: 98 | if (pSample) 99 | { 100 | pSample->OnKeyUp(static_cast(wParam)); 101 | } 102 | return 0; 103 | 104 | case WM_PAINT: 105 | if (pSample) 106 | { 107 | pSample->OnUpdate(); 108 | pSample->OnRender(); 109 | } 110 | return 0; 111 | 112 | case WM_DESTROY: 113 | PostQuitMessage(0); 114 | return 0; 115 | } 116 | 117 | // Handle any messages the switch statement didn't. 118 | return DefWindowProc(hWnd, message, wParam, lParam); 119 | } 120 | -------------------------------------------------------------------------------- /Chapter1/src/Win32Application.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #pragma once 13 | 14 | #include "DXSample.h" 15 | 16 | class DXSample; 17 | 18 | class Win32Application 19 | { 20 | public: 21 | static int Run(DXSample* pSample, HINSTANCE hInstance, int nCmdShow); 22 | static HWND GetHwnd() { return m_hwnd; } 23 | 24 | protected: 25 | static LRESULT CALLBACK WindowProc(HWND hWnd, uint32_t message, WPARAM wParam, LPARAM lParam); 26 | 27 | private: 28 | static HWND m_hwnd; 29 | }; 30 | -------------------------------------------------------------------------------- /Chapter1/src/stdafx.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | // stdafx.h : include file for standard system include files, 13 | // or project specific include files that are used frequently, but 14 | // are changed infrequently. 15 | 16 | #pragma once 17 | 18 | #ifndef WIN32_LEAN_AND_MEAN 19 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers. 20 | #endif 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "d3dx12.h" 29 | 30 | #include 31 | #include 32 | #include 33 | -------------------------------------------------------------------------------- /Chapter1/src/xmake.lua: -------------------------------------------------------------------------------- 1 | BuildProject({ 2 | projectName = "Hello-Triangle", 3 | projectType = "binary", 4 | debugEvent = function() 5 | add_defines("_DEBUG") 6 | end, 7 | releaseEvent = function() 8 | add_defines("NDEBUG") 9 | end, 10 | exception = true 11 | }) 12 | add_defines("_XM_NO_INTRINSICS_=1", "NOMINMAX", "UNICODE", "m128_f32=vector4_f32", "m128_u32=vector4_u32") 13 | add_files("**.cpp") 14 | add_includedirs("./") 15 | add_syslinks("User32", "kernel32", "Gdi32", "Shell32", "DXGI", "D3D12", "D3DCompiler") 16 | after_build(function(target) 17 | src_path = "shader/" 18 | os.cp(src_path .. "*", target:targetdir() .. "/shader/") 19 | end) -------------------------------------------------------------------------------- /Chapter1/xmake.lua: -------------------------------------------------------------------------------- 1 | set_config("toolchain", "clang-cl") 2 | add_rules("mode.release", "mode.debug") 3 | option("is_clang") 4 | add_csnippets("is_clang", "return (__clang__)?0:-1;", { 5 | tryrun = true 6 | }) 7 | option_end() 8 | option("is_msvc") 9 | add_csnippets("is_msvc", "return (_MSC_VER)?0:-1;", { 10 | tryrun = true 11 | }) 12 | option_end() 13 | 14 | 15 | option_end() 16 | function GetValue(funcOrValue) 17 | if type(funcOrValue) == 'function' then 18 | return funcOrValue() 19 | else 20 | return funcOrValue 21 | end 22 | end 23 | 24 | --[[ 25 | BuildProject({ 26 | projectName = xxx, 27 | projectType = xxx, 28 | unityBuildBatch = n, 29 | exception = true/false, 30 | releaseEvent = function() 31 | end, 32 | debugEvent = function() 33 | end 34 | }) 35 | ]] 36 | if is_mode("debug") then 37 | set_targetdir("bin/debug") 38 | else 39 | set_targetdir("bin/release") 40 | end 41 | 42 | function BuildProject(config) 43 | local projectName = GetValue(config.projectName) 44 | if projectName == nil then 45 | return 46 | end 47 | target(projectName) 48 | set_languages("clatest", "cxx20") 49 | local projectType = GetValue(config.projectType) 50 | if projectType ~= nil then 51 | set_kind(projectType) 52 | end 53 | if UseUnityBuild then 54 | local unityBuildBatch = GetValue(config.unityBuildBatch) 55 | if (unityBuildBatch ~= nil) and (unityBuildBatch > 1) then 56 | add_rules("c.unity_build", { 57 | batchsize = unityBuildBatch 58 | }) 59 | add_rules("c++.unity_build", { 60 | batchsize = unityBuildBatch 61 | }) 62 | end 63 | end 64 | local value = GetValue(config.exception) 65 | if (value ~= nil) and value then 66 | if has_config("is_msvc") then 67 | add_cxflags("/EHsc") 68 | else 69 | add_cxflags("-fexceptions") 70 | end 71 | elseif not has_config("is_msvc") then 72 | add_cxflags("-fno-exceptions") 73 | end 74 | set_warnings("none") 75 | if is_mode("debug") then 76 | set_optimize("none") 77 | if is_plat("windows") then 78 | set_runtimes("MDd") 79 | end 80 | if has_config("is_msvc") then 81 | add_cxflags("/GS", "/Gd"); 82 | -- Not Clang-cl 83 | if not has_config("is_clang") then 84 | add_cxflags("/Zc:preprocessor") 85 | end 86 | end 87 | local event = GetValue(config.debugEvent) 88 | if (type(event) == "function") then 89 | event() 90 | end 91 | else 92 | set_optimize("fastest") 93 | if is_plat("windows") then 94 | set_runtimes("MD") 95 | end 96 | if has_config("is_msvc") then 97 | add_cxflags("/Oy", "/GS-", "/Gd", "/Oi", "/Ot", "/GT", "/Ob2") 98 | -- Not Clang-cl 99 | if not has_config("is_clang") then 100 | add_cxflags("/GL", "/Zc:preprocessor", "/QIntel-jcc-erratum") 101 | end 102 | end 103 | local event = GetValue(config.releaseEvent) 104 | if (type(event) == "function") then 105 | event() 106 | end 107 | end 108 | end 109 | add_subdirs("src") 110 | -------------------------------------------------------------------------------- /Chapter2/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "C_Cpp.codeAnalysis.runAutomatically": false, 3 | "C_Cpp.intelliSenseEngine": "Disabled", 4 | "C_Cpp.formatting": "Disabled", 5 | "C_Cpp.autoAddFileAssociations": false, 6 | "C_Cpp.autocompleteAddParentheses": false, 7 | "C_Cpp.autocomplete": "Disabled", 8 | "C_Cpp.errorSquiggles": "Disabled", 9 | "clangd.arguments": [ 10 | "--compile-commands-dir=.vscode", 11 | "-j=24", 12 | "--log=error", 13 | "--completion-style=bundled", 14 | "--background-index", 15 | "--header-insertion=never", 16 | "--pch-storage=memory", 17 | "--offset-encoding=utf-8" 18 | ], 19 | "editor.accessibilitySupport": "off" 20 | } -------------------------------------------------------------------------------- /Chapter2/shader/shaders.hlsl: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | struct PSInput 13 | { 14 | float4 position : SV_POSITION; 15 | float4 color : COLOR; 16 | }; 17 | 18 | PSInput VSMain(float4 position : POSITION, float4 color : COLOR) 19 | { 20 | PSInput result; 21 | 22 | result.position = position; 23 | result.color = color; 24 | 25 | return result; 26 | } 27 | 28 | float4 PSMain(PSInput input) : SV_TARGET 29 | { 30 | return input.color; 31 | } 32 | -------------------------------------------------------------------------------- /Chapter2/src/D3D12HelloTriangle.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | //0 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #pragma once 13 | 14 | #include "DXSample.h" 15 | #include 16 | #include 17 | #include 18 | 19 | using namespace DirectX; 20 | // Note that while ComPtr is used to manage the lifetime of resources on the CPU, 21 | // it has no understanding of the lifetime of resources on the GPU. Apps must account 22 | // for the GPU lifetime of resources to avoid destroying objects that may still be 23 | // referenced by the GPU. 24 | // An example of this can be found in the class method: OnDestroy(). 25 | using Microsoft::WRL::ComPtr; 26 | class D3D12HelloTriangle : public DXSample { 27 | public: 28 | D3D12HelloTriangle(uint32_t width, uint32_t height, std::wstring name); 29 | void OnInit() override; 30 | void OnUpdate() override; 31 | void OnRender() override; 32 | void OnDestroy() override; 33 | 34 | private: 35 | static const uint32_t FrameCount = 2; 36 | 37 | struct Vertex : public rtti::Struct { 38 | rtti::Var position = "POSITION"; 39 | rtti::Var color = "COLOR"; 40 | }; 41 | std::unique_ptr device; 42 | // Pipeline objects. 43 | CD3DX12_VIEWPORT m_viewport; 44 | CD3DX12_RECT m_scissorRect; 45 | ComPtr m_swapChain; 46 | ComPtr m_renderTargets[FrameCount]; 47 | ComPtr m_commandAllocator; 48 | ComPtr m_commandQueue; 49 | ComPtr m_rootSignature; 50 | ComPtr m_rtvHeap; 51 | ComPtr m_pipelineState; 52 | ComPtr m_commandList; 53 | uint32_t m_rtvDescriptorSize; 54 | 55 | // App resources. 56 | std::unique_ptr triangleMesh; 57 | // Synchronization objects. 58 | uint32_t m_frameIndex; 59 | HANDLE m_fenceEvent; 60 | ComPtr m_fence; 61 | uint64_t m_fenceValue; 62 | 63 | void LoadPipeline(); 64 | void LoadAssets(); 65 | void PopulateCommandList(); 66 | void WaitForPreviousFrame(); 67 | }; 68 | -------------------------------------------------------------------------------- /Chapter2/src/DXRuntime/Device.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | Device::~Device() { 5 | } 6 | 7 | Device::Device() { 8 | using Microsoft::WRL::ComPtr; 9 | uint32_t dxgiFactoryFlags = 0; 10 | 11 | #if defined(_DEBUG) 12 | // Enable the debug layer (requires the Graphics Tools "optional feature"). 13 | // NOTE: Enabling the debug layer after device creation will invalidate the active device. 14 | { 15 | ComPtr debugController; 16 | if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) { 17 | debugController->EnableDebugLayer(); 18 | 19 | // Enable additional debug layers. 20 | dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG; 21 | } 22 | } 23 | #endif 24 | ThrowIfFailed(CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&dxgiFactory))); 25 | uint adapterIndex = 0; // we'll start looking for directx 12 compatible graphics devices starting at index 0 26 | bool adapterFound = false;// set this to true when a good one was found 27 | while (dxgiFactory->EnumAdapters1(adapterIndex, &adapter) != DXGI_ERROR_NOT_FOUND) { 28 | DXGI_ADAPTER_DESC1 desc; 29 | adapter->GetDesc1(&desc); 30 | if ((desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) == 0) { 31 | HRESULT hr = D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_12_1, 32 | IID_PPV_ARGS(&dxDevice)); 33 | if (SUCCEEDED(hr)) { 34 | adapterFound = true; 35 | break; 36 | } 37 | } 38 | adapter = nullptr; 39 | adapterIndex++; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Chapter2/src/DXRuntime/Device.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | class Device { 4 | Microsoft::WRL::ComPtr adapter; 5 | Microsoft::WRL::ComPtr dxDevice; 6 | Microsoft::WRL::ComPtr dxgiFactory; 7 | 8 | public: 9 | IDXGIAdapter1* Adapter() const { return adapter.Get(); } 10 | ID3D12Device5* DxDevice() const { return dxDevice.Get(); } 11 | IDXGIFactory4* DxgiFactory() const { return dxgiFactory.Get(); } 12 | Device(); 13 | ~Device(); 14 | }; 15 | -------------------------------------------------------------------------------- /Chapter2/src/DXSample.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #pragma once 13 | 14 | #include "DXSampleHelper.h" 15 | #include "Win32Application.h" 16 | 17 | class DXSample 18 | { 19 | public: 20 | DXSample(uint32_t width, uint32_t height, std::wstring name); 21 | virtual ~DXSample(); 22 | 23 | virtual void OnInit() = 0; 24 | virtual void OnUpdate() = 0; 25 | virtual void OnRender() = 0; 26 | virtual void OnDestroy() = 0; 27 | 28 | // Samples override the event handlers to handle specific messages. 29 | virtual void OnKeyDown(UINT8 /*key*/) {} 30 | virtual void OnKeyUp(UINT8 /*key*/) {} 31 | 32 | // Accessors. 33 | uint32_t GetWidth() const { return m_width; } 34 | uint32_t GetHeight() const { return m_height; } 35 | const wchar_t* GetTitle() const { return m_title.c_str(); } 36 | 37 | void ParseCommandLineArgs(_In_reads_(argc) wchar_t* argv[], int argc); 38 | 39 | protected: 40 | std::wstring GetAssetFullPath(LPCWSTR assetName); 41 | 42 | void GetHardwareAdapter( 43 | _In_ IDXGIFactory1* pFactory, 44 | _Outptr_result_maybenull_ IDXGIAdapter1** ppAdapter, 45 | bool requestHighPerformanceAdapter = false); 46 | 47 | void SetCustomWindowText(LPCWSTR text); 48 | 49 | // Viewport dimensions. 50 | uint32_t m_width; 51 | uint32_t m_height; 52 | float m_aspectRatio; 53 | 54 | // Adapter info. 55 | bool m_useWarpDevice; 56 | 57 | private: 58 | // Root assets path. 59 | std::wstring m_assetsPath; 60 | 61 | // Window title. 62 | std::wstring m_title; 63 | }; 64 | -------------------------------------------------------------------------------- /Chapter2/src/Main.cpp: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #include "stdafx.h" 13 | #include "D3D12HelloTriangle.h" 14 | 15 | _Use_decl_annotations_ 16 | int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) 17 | { 18 | D3D12HelloTriangle sample(1280, 720, L"D3D12 Hello Triangle"); 19 | return Win32Application::Run(&sample, hInstance, nCmdShow); 20 | } 21 | -------------------------------------------------------------------------------- /Chapter2/src/Metalib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | template 4 | requires(!std::is_lvalue_reference_v) 5 | T* get_rvalue_ptr(T&& v) { 6 | return &v; 7 | } 8 | template 9 | struct array_meta; 10 | template 11 | struct array_meta { 12 | static constexpr size_t array_size = N; 13 | static constexpr size_t byte_size = N * sizeof(T); 14 | }; 15 | 16 | template 17 | requires(std::is_bounded_array_v) constexpr size_t array_count(T const& t) { 18 | return array_meta::array_size; 19 | } 20 | template 21 | requires(std::is_bounded_array_v) constexpr size_t array_byte_size(T const& t) { 22 | return array_meta::byte_size; 23 | } 24 | 25 | using vbyte = uint8_t; 26 | using uint = uint32_t; 27 | using uint64 = uint64_t; 28 | using int32 = int32_t; 29 | -------------------------------------------------------------------------------- /Chapter2/src/Resource/Buffer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | BufferView::BufferView(Buffer const* buffer) 4 | : buffer(buffer), 5 | byteSize(buffer ? buffer->GetByteSize() : 0), 6 | offset(0) { 7 | } 8 | BufferView::BufferView( 9 | Buffer const* buffer, 10 | uint64 offset, 11 | uint64 byteSize) 12 | : buffer(buffer), 13 | offset(offset), 14 | byteSize(byteSize) {} 15 | Buffer::Buffer( 16 | Device* device) 17 | : Resource(device){ 18 | } 19 | Buffer::~Buffer() { 20 | } 21 | -------------------------------------------------------------------------------- /Chapter2/src/Resource/Buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | class Buffer : public Resource{ 6 | public: 7 | Buffer(Device* device); 8 | virtual D3D12_GPU_VIRTUAL_ADDRESS GetAddress() const = 0; 9 | virtual uint64 GetByteSize() const = 0; 10 | virtual ~Buffer(); 11 | Buffer(Buffer&&) = default; 12 | }; 13 | -------------------------------------------------------------------------------- /Chapter2/src/Resource/BufferView.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class Buffer; 5 | struct BufferView { 6 | Buffer const* buffer = nullptr; 7 | uint64 offset = 0; 8 | uint64 byteSize = 0; 9 | BufferView() {} 10 | BufferView(Buffer const* buffer); 11 | BufferView( 12 | Buffer const* buffer, 13 | uint64 offset, 14 | uint64 byteSize); 15 | bool operator==(BufferView const& a) const { 16 | return memcmp(this, &a, sizeof(BufferView)) == 0; 17 | } 18 | bool operator!=(BufferView const& a) const { 19 | return !operator==(a); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /Chapter2/src/Resource/DefaultBuffer.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | DefaultBuffer::DefaultBuffer( 6 | Device* device, 7 | uint64 byteSize, 8 | D3D12_RESOURCE_STATES initState) 9 | : Buffer(device), 10 | initState(initState), 11 | byteSize(byteSize) { 12 | auto prop = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT); 13 | auto buffer = CD3DX12_RESOURCE_DESC::Buffer(byteSize, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); 14 | ThrowIfFailed(device->DxDevice()->CreateCommittedResource( 15 | &prop, 16 | D3D12_HEAP_FLAG_NONE, 17 | &buffer, 18 | initState, 19 | nullptr, 20 | IID_PPV_ARGS(&resource))); 21 | } 22 | DefaultBuffer::~DefaultBuffer() { 23 | } 24 | -------------------------------------------------------------------------------- /Chapter2/src/Resource/DefaultBuffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class DefaultBuffer final : public Buffer { 5 | private: 6 | uint64 byteSize; 7 | D3D12_RESOURCE_STATES initState; 8 | ComPtr resource; 9 | 10 | public: 11 | ID3D12Resource* GetResource() const override { return resource.Get(); } 12 | D3D12_GPU_VIRTUAL_ADDRESS GetAddress() const override { return resource->GetGPUVirtualAddress(); } 13 | uint64 GetByteSize() const override { return byteSize; } 14 | DefaultBuffer( 15 | Device* device, 16 | uint64 byteSize, 17 | D3D12_RESOURCE_STATES initState = D3D12_RESOURCE_STATE_COMMON); 18 | ~DefaultBuffer(); 19 | D3D12_RESOURCE_STATES GetInitState() const override { 20 | return initState; 21 | } 22 | 23 | DefaultBuffer(DefaultBuffer&&) = default; 24 | DefaultBuffer(DefaultBuffer const&) = delete; 25 | }; 26 | -------------------------------------------------------------------------------- /Chapter2/src/Resource/Mesh.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | Mesh::Mesh( 3 | Device* device, 4 | std::span vbStructs, 5 | uint64 vertexCount) 6 | : Resource(device), 7 | vertexCount(vertexCount), 8 | vertexStructs(vbStructs) { 9 | vertexBuffers.reserve(vertexStructs.size()); 10 | uint slotCount = 0; 11 | for (auto&& i : vertexStructs) { 12 | vertexBuffers.emplace_back(device, i->structSize * vertexCount); 13 | i->GetMeshLayout(slotCount, layout); 14 | ++slotCount; 15 | } 16 | } 17 | void Mesh::GetVertexBufferView(std::vector& result) const { 18 | result.clear(); 19 | result.resize(vertexBuffers.size()); 20 | for (size_t i = 0; i < vertexBuffers.size(); ++i) { 21 | auto& r = result[i]; 22 | auto& v = vertexBuffers[i]; 23 | r.BufferLocation = v.GetAddress(); 24 | r.SizeInBytes = v.GetByteSize(); 25 | r.StrideInBytes = r.SizeInBytes / vertexCount; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Chapter2/src/Resource/Mesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | class Mesh : public Resource { 6 | std::vector vertexBuffers; 7 | std::span vertexStructs; 8 | std::vector layout; 9 | uint64 vertexCount; 10 | 11 | public: 12 | std::span VertexBuffers() const { return vertexBuffers; } 13 | std::span Layout() const { return layout; } 14 | Mesh( 15 | Device* device, 16 | std::span vbStructs, 17 | uint64 vertexCount); 18 | void GetVertexBufferView(std::vector& result) const; 19 | }; -------------------------------------------------------------------------------- /Chapter2/src/Resource/ReadbackBuffer.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | namespace toolhub::directx { 5 | ReadbackBuffer::ReadbackBuffer( 6 | Device* device, 7 | uint64 byteSize) 8 | : Buffer(device), 9 | byteSize(byteSize) { 10 | auto prop = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK); 11 | auto buffer = CD3DX12_RESOURCE_DESC::Buffer(byteSize); 12 | ThrowIfFailed(device->DxDevice()->CreateCommittedResource( 13 | &prop, 14 | D3D12_HEAP_FLAG_NONE, 15 | &buffer, 16 | D3D12_RESOURCE_STATE_COPY_DEST, 17 | nullptr, 18 | IID_PPV_ARGS(&resource))); 19 | } 20 | ReadbackBuffer::~ReadbackBuffer() { 21 | } 22 | void ReadbackBuffer::CopyData( 23 | uint64 offset, 24 | std::span data) const { 25 | void* mapPtr; 26 | D3D12_RANGE range; 27 | range.Begin = offset; 28 | range.End = std::min(byteSize, offset + data.size()); 29 | ThrowIfFailed(resource->Map(0, &range, (void**)(&mapPtr))); 30 | memcpy(data.data(), reinterpret_cast(mapPtr) + offset, range.End - range.Begin); 31 | resource->Unmap(0, nullptr); 32 | } 33 | 34 | }// namespace toolhub::directx -------------------------------------------------------------------------------- /Chapter2/src/Resource/ReadbackBuffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace toolhub::directx { 5 | class ReadbackBuffer final : public Buffer { 6 | private: 7 | ComPtr resource; 8 | uint64 byteSize; 9 | 10 | public: 11 | ID3D12Resource* GetResource() const override { return resource.Get(); } 12 | D3D12_GPU_VIRTUAL_ADDRESS GetAddress() const override { return resource->GetGPUVirtualAddress(); } 13 | uint64 GetByteSize() const override { return byteSize; } 14 | ReadbackBuffer( 15 | Device* device, 16 | uint64 byteSize); 17 | ~ReadbackBuffer(); 18 | void CopyData(uint64 offset, std::span data) const; 19 | D3D12_RESOURCE_STATES GetInitState() const override { 20 | return D3D12_RESOURCE_STATE_COPY_DEST; 21 | } 22 | ReadbackBuffer(ReadbackBuffer&&) = default; 23 | ReadbackBuffer(ReadbackBuffer const&) = delete; 24 | }; 25 | }// namespace toolhub::directx -------------------------------------------------------------------------------- /Chapter2/src/Resource/Resource.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | using Microsoft::WRL::ComPtr; 5 | 6 | class Resource { 7 | protected: 8 | Device* device; 9 | 10 | public: 11 | Device* GetDevice() const { return device; } 12 | Resource(Device* device) 13 | : device(device) {} 14 | Resource(Resource&&) = default; 15 | Resource(Resource const&) = delete; 16 | virtual ~Resource() = default; 17 | virtual ID3D12Resource* GetResource() const { return nullptr; } 18 | virtual D3D12_RESOURCE_STATES GetInitState() const { return D3D12_RESOURCE_STATE_COMMON; } 19 | }; 20 | -------------------------------------------------------------------------------- /Chapter2/src/Resource/UploadBuffer.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | UploadBuffer::UploadBuffer( 6 | Device* device, 7 | uint64 byteSize) 8 | : Buffer(device), 9 | byteSize(byteSize) { 10 | auto prop = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD); 11 | auto buffer = CD3DX12_RESOURCE_DESC::Buffer(byteSize); 12 | ThrowIfFailed(device->DxDevice()->CreateCommittedResource( 13 | &prop, 14 | D3D12_HEAP_FLAG_NONE, 15 | &buffer, 16 | D3D12_RESOURCE_STATE_GENERIC_READ, 17 | nullptr, 18 | IID_PPV_ARGS(&resource))); 19 | } 20 | UploadBuffer::~UploadBuffer() { 21 | } 22 | void UploadBuffer::CopyData(uint64 offset, std::span data) const { 23 | void* mappedPtr; 24 | D3D12_RANGE range; 25 | range.Begin = offset; 26 | range.End = std::min(byteSize, offset + data.size()); 27 | ThrowIfFailed(resource->Map(0, &range, reinterpret_cast(&mappedPtr))); 28 | memcpy(reinterpret_cast(mappedPtr) + offset, data.data(), range.End - range.Begin); 29 | resource->Unmap(0, &range); 30 | } 31 | 32 | -------------------------------------------------------------------------------- /Chapter2/src/Resource/UploadBuffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class UploadBuffer final : public Buffer { 5 | private: 6 | ComPtr resource; 7 | uint64 byteSize; 8 | 9 | public: 10 | ID3D12Resource* GetResource() const override { return resource.Get(); } 11 | D3D12_GPU_VIRTUAL_ADDRESS GetAddress() const override { return resource->GetGPUVirtualAddress(); } 12 | uint64 GetByteSize() const override { return byteSize; } 13 | UploadBuffer( 14 | Device* device, 15 | uint64 byteSize); 16 | ~UploadBuffer(); 17 | void CopyData(uint64 offset, std::span data) const; 18 | D3D12_RESOURCE_STATES GetInitState() const override { 19 | return D3D12_RESOURCE_STATE_GENERIC_READ; 20 | } 21 | UploadBuffer(UploadBuffer&&) = default; 22 | UploadBuffer(UploadBuffer const&) = delete; 23 | }; 24 | 25 | -------------------------------------------------------------------------------- /Chapter2/src/Utility/ReflactableStruct.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | namespace rtti { 4 | static thread_local Struct* curStruct = nullptr; 5 | size_t VarTypeData::GetSize() const { 6 | return dimension * 4; 7 | } 8 | Struct::Struct() { 9 | curStruct = this; 10 | } 11 | VarTypeBase::VarTypeBase(VarTypeData&& varData) { 12 | offset = curStruct->structSize; 13 | //A Simple parser 14 | //Split Semantic, get index 15 | if (!varData.semantic.empty()) { 16 | uint rate = 1; 17 | uint semanticIndex = 0; 18 | char const* ptr = varData.semantic.data() + varData.semantic.size() - 1; 19 | while (ptr != (varData.semantic.data() - 1)) { 20 | if (*ptr >= '0' && *ptr <= '9') { 21 | semanticIndex += rate * (int(*ptr) - int('0')); 22 | rate *= 10; 23 | } else { 24 | break; 25 | } 26 | --ptr; 27 | } 28 | auto leftSize = reinterpret_cast(ptr) - reinterpret_cast(varData.semantic.data()) + 1; 29 | varData.semantic.resize(leftSize); 30 | varData.semanticIndex = semanticIndex; 31 | } 32 | curStruct->variables.emplace_back(std::move(varData)); 33 | curStruct->structSize += varData.GetSize(); 34 | } 35 | void Struct::GetMeshLayout(uint slot, std::vector& resultVector) const { 36 | auto getFormat = [](VarTypeData const& d) -> DXGI_FORMAT { 37 | switch (d.scale) { 38 | case VarTypeData::ScaleType::Float: 39 | switch (d.dimension) { 40 | case 1: 41 | return DXGI_FORMAT_R32_FLOAT; 42 | case 2: 43 | return DXGI_FORMAT_R32G32_FLOAT; 44 | case 3: 45 | return DXGI_FORMAT_R32G32B32_FLOAT; 46 | case 4: 47 | return DXGI_FORMAT_R32G32B32A32_FLOAT; 48 | default: 49 | return DXGI_FORMAT_UNKNOWN; 50 | } 51 | case VarTypeData::ScaleType::UInt: 52 | switch (d.dimension) { 53 | case 1: 54 | return DXGI_FORMAT_R32_UINT; 55 | case 2: 56 | return DXGI_FORMAT_R32G32_UINT; 57 | case 3: 58 | return DXGI_FORMAT_R32G32B32_UINT; 59 | case 4: 60 | return DXGI_FORMAT_R32G32B32A32_UINT; 61 | default: 62 | return DXGI_FORMAT_UNKNOWN; 63 | } 64 | case VarTypeData::ScaleType::Int: 65 | switch (d.dimension) { 66 | case 1: 67 | return DXGI_FORMAT_R32_SINT; 68 | case 2: 69 | return DXGI_FORMAT_R32G32_SINT; 70 | case 3: 71 | return DXGI_FORMAT_R32G32B32_SINT; 72 | case 4: 73 | return DXGI_FORMAT_R32G32B32A32_SINT; 74 | default: 75 | return DXGI_FORMAT_UNKNOWN; 76 | } 77 | default: 78 | return DXGI_FORMAT_UNKNOWN; 79 | } 80 | }; 81 | uint offset = 0; 82 | for (size_t i = 0; i < variables.size(); ++i) { 83 | auto& result = resultVector.emplace_back(); 84 | auto& var = variables[i]; 85 | result = {var.semantic.c_str(), 86 | uint(var.semanticIndex), 87 | getFormat(var), 88 | slot, 89 | offset, 90 | D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 91 | uint(0)}; 92 | offset += var.GetSize(); 93 | } 94 | } 95 | }// namespace rtti -------------------------------------------------------------------------------- /Chapter2/src/Utility/ReflactableStruct.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | namespace rtti { 7 | //Interpret a variable's type in structure 8 | struct VarTypeData { 9 | enum class ScaleType : vbyte { 10 | Float, 11 | Int, 12 | UInt 13 | }; 14 | 15 | ScaleType scale; 16 | vbyte dimension; 17 | uint semanticIndex; 18 | std::string semantic; 19 | size_t GetSize() const; 20 | }; 21 | class VarTypeBase; 22 | class Struct { 23 | friend class VarTypeBase; 24 | std::vector variables; 25 | 26 | public: 27 | std::span Variables() const { return variables; } 28 | size_t structSize = 0; 29 | 30 | Struct(); 31 | Struct(Struct const&) = delete; 32 | Struct(Struct&&) = default; 33 | void GetMeshLayout(uint slot, std::vector& resultVector) const; 34 | }; 35 | class VarTypeBase { 36 | size_t offset; 37 | 38 | protected: 39 | VarTypeBase(VarTypeData&& varData); 40 | 41 | public: 42 | size_t Offset() const { return offset; } 43 | }; 44 | template 45 | class VarType : public VarTypeBase { 46 | protected: 47 | VarType(VarTypeData&& varData) : VarTypeBase(std::move(varData)) {} 48 | 49 | public: 50 | T const& Get(void const* structPtr) const { 51 | size_t ptrNum = reinterpret_cast(structPtr); 52 | return *reinterpret_cast(ptrNum + Offset()); 53 | } 54 | T& Get(void* structPtr) const { 55 | size_t ptrNum = reinterpret_cast(structPtr); 56 | return *reinterpret_cast(ptrNum + Offset()); 57 | } 58 | }; 59 | template 60 | struct Var {}; 61 | 62 | template<> 63 | struct Var : public VarType { 64 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Int, vbyte(1), uint(0), std::string(semantic)}) {} 65 | }; 66 | template<> 67 | struct Var : public VarType { 68 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::UInt, vbyte(1), uint(0), std::string(semantic)}) {} 69 | }; 70 | template<> 71 | struct Var : public VarType { 72 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Float, vbyte(1), uint(0), std::string(semantic)}) {} 73 | }; 74 | template<> 75 | struct Var : public VarType { 76 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Float, vbyte(2), uint(0), std::string(semantic)}) {} 77 | }; 78 | template<> 79 | struct Var : public VarType { 80 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Float, vbyte(3), uint(0), std::string(semantic)}) {} 81 | }; 82 | template<> 83 | struct Var : public VarType { 84 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Float, vbyte(4), uint(0), std::string(semantic)}) {} 85 | }; 86 | template<> 87 | struct Var : public VarType { 88 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::UInt, vbyte(2), uint(0), std::string(semantic)}) {} 89 | }; 90 | template<> 91 | struct Var : public VarType { 92 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::UInt, vbyte(3), uint(0), std::string(semantic)}) {} 93 | }; 94 | template<> 95 | struct Var : public VarType { 96 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::UInt, vbyte(4), uint(0), std::string(semantic)}) {} 97 | }; 98 | template<> 99 | struct Var : public VarType { 100 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Int, vbyte(2), uint(0), std::string(semantic)}) {} 101 | }; 102 | template<> 103 | struct Var : public VarType { 104 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Int, vbyte(3), uint(0), std::string(semantic)}) {} 105 | }; 106 | template<> 107 | struct Var : public VarType { 108 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Int, vbyte(4), uint(0), std::string(semantic)}) {} 109 | }; 110 | }// namespace rtti -------------------------------------------------------------------------------- /Chapter2/src/Win32Application.cpp: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #include "stdafx.h" 13 | #include "Win32Application.h" 14 | 15 | HWND Win32Application::m_hwnd = nullptr; 16 | 17 | int Win32Application::Run(DXSample* pSample, HINSTANCE hInstance, int nCmdShow) 18 | { 19 | // Parse the command line parameters 20 | int argc; 21 | LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc); 22 | pSample->ParseCommandLineArgs(argv, argc); 23 | LocalFree(argv); 24 | 25 | // Initialize the window class. 26 | WNDCLASSEX windowClass = { 0 }; 27 | windowClass.cbSize = sizeof(WNDCLASSEX); 28 | windowClass.style = CS_HREDRAW | CS_VREDRAW; 29 | windowClass.lpfnWndProc = WindowProc; 30 | windowClass.hInstance = hInstance; 31 | windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); 32 | windowClass.lpszClassName = L"DXSampleClass"; 33 | RegisterClassEx(&windowClass); 34 | 35 | RECT windowRect = { 0, 0, static_cast(pSample->GetWidth()), static_cast(pSample->GetHeight()) }; 36 | AdjustWindowRect(&windowRect, WS_OVERLAPPEDWINDOW, FALSE); 37 | 38 | // Create the window and store a handle to it. 39 | m_hwnd = CreateWindow( 40 | windowClass.lpszClassName, 41 | pSample->GetTitle(), 42 | WS_OVERLAPPEDWINDOW, 43 | CW_USEDEFAULT, 44 | CW_USEDEFAULT, 45 | windowRect.right - windowRect.left, 46 | windowRect.bottom - windowRect.top, 47 | nullptr, // We have no parent window. 48 | nullptr, // We aren't using menus. 49 | hInstance, 50 | pSample); 51 | 52 | // Initialize the sample. OnInit is defined in each child-implementation of DXSample. 53 | pSample->OnInit(); 54 | 55 | ShowWindow(m_hwnd, nCmdShow); 56 | 57 | // Main sample loop. 58 | MSG msg = {}; 59 | while (msg.message != WM_QUIT) 60 | { 61 | // Process any messages in the queue. 62 | if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 63 | { 64 | TranslateMessage(&msg); 65 | DispatchMessage(&msg); 66 | } 67 | } 68 | 69 | pSample->OnDestroy(); 70 | 71 | // Return this part of the WM_QUIT message to Windows. 72 | return static_cast(msg.wParam); 73 | } 74 | 75 | // Main message handler for the sample. 76 | LRESULT CALLBACK Win32Application::WindowProc(HWND hWnd, uint32_t message, WPARAM wParam, LPARAM lParam) 77 | { 78 | DXSample* pSample = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); 79 | 80 | switch (message) 81 | { 82 | case WM_CREATE: 83 | { 84 | // Save the DXSample* passed in to CreateWindow. 85 | LPCREATESTRUCT pCreateStruct = reinterpret_cast(lParam); 86 | SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast(pCreateStruct->lpCreateParams)); 87 | } 88 | return 0; 89 | 90 | case WM_KEYDOWN: 91 | if (pSample) 92 | { 93 | pSample->OnKeyDown(static_cast(wParam)); 94 | } 95 | return 0; 96 | 97 | case WM_KEYUP: 98 | if (pSample) 99 | { 100 | pSample->OnKeyUp(static_cast(wParam)); 101 | } 102 | return 0; 103 | 104 | case WM_PAINT: 105 | if (pSample) 106 | { 107 | pSample->OnUpdate(); 108 | pSample->OnRender(); 109 | } 110 | return 0; 111 | 112 | case WM_DESTROY: 113 | PostQuitMessage(0); 114 | return 0; 115 | } 116 | 117 | // Handle any messages the switch statement didn't. 118 | return DefWindowProc(hWnd, message, wParam, lParam); 119 | } 120 | -------------------------------------------------------------------------------- /Chapter2/src/Win32Application.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #pragma once 13 | 14 | #include "DXSample.h" 15 | 16 | class DXSample; 17 | 18 | class Win32Application 19 | { 20 | public: 21 | static int Run(DXSample* pSample, HINSTANCE hInstance, int nCmdShow); 22 | static HWND GetHwnd() { return m_hwnd; } 23 | 24 | protected: 25 | static LRESULT CALLBACK WindowProc(HWND hWnd, uint32_t message, WPARAM wParam, LPARAM lParam); 26 | 27 | private: 28 | static HWND m_hwnd; 29 | }; 30 | -------------------------------------------------------------------------------- /Chapter2/src/stdafx.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | // stdafx.h : include file for standard system include files, 13 | // or project specific include files that are used frequently, but 14 | // are changed infrequently. 15 | 16 | #pragma once 17 | 18 | #ifndef WIN32_LEAN_AND_MEAN 19 | #define WIN32_LEAN_AND_MEAN// Exclude rarely-used stuff from Windows headers. 20 | #endif 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "d3dx12.h" 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | -------------------------------------------------------------------------------- /Chapter2/src/xmake.lua: -------------------------------------------------------------------------------- 1 | BuildProject({ 2 | projectName = "Better-Triangle", 3 | projectType = "binary", 4 | debugEvent = function() 5 | add_defines("_DEBUG") 6 | end, 7 | releaseEvent = function() 8 | add_defines("NDEBUG") 9 | end, 10 | exception = true 11 | }) 12 | add_defines("_XM_NO_INTRINSICS_=1", "NOMINMAX", "UNICODE", "m128_f32=vector4_f32", "m128_u32=vector4_u32") 13 | add_files("**.cpp") 14 | add_includedirs("./") 15 | add_syslinks("User32", "kernel32", "Gdi32", "Shell32", "DXGI", "D3D12", "D3DCompiler") 16 | after_build(function(target) 17 | src_path = "shader/" 18 | os.cp(src_path .. "*", target:targetdir() .. "/shader/") 19 | end) -------------------------------------------------------------------------------- /Chapter2/xmake.lua: -------------------------------------------------------------------------------- 1 | set_config("toolchain", "clang-cl") 2 | add_rules("mode.release", "mode.debug") 3 | option("is_clang") 4 | add_csnippets("is_clang", "return (__clang__)?0:-1;", { 5 | tryrun = true 6 | }) 7 | option_end() 8 | option("is_msvc") 9 | add_csnippets("is_msvc", "return (_MSC_VER)?0:-1;", { 10 | tryrun = true 11 | }) 12 | option_end() 13 | 14 | 15 | option_end() 16 | function GetValue(funcOrValue) 17 | if type(funcOrValue) == 'function' then 18 | return funcOrValue() 19 | else 20 | return funcOrValue 21 | end 22 | end 23 | 24 | --[[ 25 | BuildProject({ 26 | projectName = xxx, 27 | projectType = xxx, 28 | unityBuildBatch = n, 29 | exception = true/false, 30 | releaseEvent = function() 31 | end, 32 | debugEvent = function() 33 | end 34 | }) 35 | ]] 36 | if is_mode("debug") then 37 | set_targetdir("bin/debug") 38 | else 39 | set_targetdir("bin/release") 40 | end 41 | 42 | function BuildProject(config) 43 | local projectName = GetValue(config.projectName) 44 | if projectName == nil then 45 | return 46 | end 47 | target(projectName) 48 | set_languages("clatest", "cxx20") 49 | local projectType = GetValue(config.projectType) 50 | if projectType ~= nil then 51 | set_kind(projectType) 52 | end 53 | if UseUnityBuild then 54 | local unityBuildBatch = GetValue(config.unityBuildBatch) 55 | if (unityBuildBatch ~= nil) and (unityBuildBatch > 1) then 56 | add_rules("c.unity_build", { 57 | batchsize = unityBuildBatch 58 | }) 59 | add_rules("c++.unity_build", { 60 | batchsize = unityBuildBatch 61 | }) 62 | end 63 | end 64 | local value = GetValue(config.exception) 65 | if (value ~= nil) and value then 66 | if has_config("is_msvc") then 67 | add_cxflags("/EHsc") 68 | else 69 | add_cxflags("-fexceptions") 70 | end 71 | elseif not has_config("is_msvc") then 72 | add_cxflags("-fno-exceptions") 73 | end 74 | set_warnings("none") 75 | if is_mode("debug") then 76 | set_optimize("none") 77 | if is_plat("windows") then 78 | set_runtimes("MDd") 79 | end 80 | if has_config("is_msvc") then 81 | add_cxflags("/GS", "/Gd"); 82 | -- Not Clang-cl 83 | if not has_config("is_clang") then 84 | add_cxflags("/Zc:preprocessor") 85 | end 86 | end 87 | local event = GetValue(config.debugEvent) 88 | if (type(event) == "function") then 89 | event() 90 | end 91 | else 92 | set_optimize("fastest") 93 | if is_plat("windows") then 94 | set_runtimes("MD") 95 | end 96 | if has_config("is_msvc") then 97 | add_cxflags("/Oy", "/GS-", "/Gd", "/Oi", "/Ot", "/GT", "/Ob2") 98 | -- Not Clang-cl 99 | if not has_config("is_clang") then 100 | add_cxflags("/GL", "/Zc:preprocessor", "/QIntel-jcc-erratum") 101 | end 102 | end 103 | local event = GetValue(config.releaseEvent) 104 | if (type(event) == "function") then 105 | event() 106 | end 107 | end 108 | end 109 | add_subdirs("src") 110 | -------------------------------------------------------------------------------- /Chapter3/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "C_Cpp.codeAnalysis.runAutomatically": false, 3 | "C_Cpp.intelliSenseEngine": "Disabled", 4 | "C_Cpp.formatting": "Disabled", 5 | "C_Cpp.autoAddFileAssociations": false, 6 | "C_Cpp.autocompleteAddParentheses": false, 7 | "C_Cpp.autocomplete": "Disabled", 8 | "C_Cpp.errorSquiggles": "Disabled", 9 | "clangd.arguments": [ 10 | "--compile-commands-dir=.vscode", 11 | "-j=24", 12 | "--log=error", 13 | "--completion-style=bundled", 14 | "--background-index", 15 | "--header-insertion=never", 16 | "--pch-storage=memory", 17 | "--offset-encoding=utf-8" 18 | ], 19 | "editor.accessibilitySupport": "off" 20 | } -------------------------------------------------------------------------------- /Chapter3/shader/shaders.hlsl: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | struct PSInput { 13 | float4 position : SV_POSITION; 14 | float4 color : COLOR; 15 | }; 16 | cbuffer _Global : register(b0){ 17 | float4x4 _CameraWorldToViewMatrix; 18 | }; 19 | 20 | PSInput VSMain(float3 position 21 | : POSITION, float4 color 22 | : COLOR) { 23 | PSInput result; 24 | 25 | result.position = mul(_CameraWorldToViewMatrix, float4(position, 1)); 26 | result.color = color; 27 | 28 | return result; 29 | } 30 | 31 | float4 PSMain(PSInput input) : SV_TARGET { 32 | return input.color; 33 | } 34 | -------------------------------------------------------------------------------- /Chapter3/src/Component/Camera.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace DirectX; 3 | using namespace Math; 4 | Camera::Camera() { 5 | SetLens(0.25f * MathHelper::Pi, 1.0f, 1000.0f); 6 | } 7 | Camera::~Camera() { 8 | } 9 | void Camera::SetLens(float fovY, float zn, float zf) { 10 | // cache properties 11 | mFovY = fovY; 12 | mNearZ = zn; 13 | mFarZ = zf; 14 | mNearWindowHeight = 2.0f * mNearZ * tan(0.5f * mFovY); 15 | mFarWindowHeight = 2.0f * mFarZ * tan(0.5f * mFovY); 16 | } 17 | void Camera::SetAspect(float aspect) { 18 | mAspect = aspect; 19 | } 20 | 21 | void Camera::LookAt(const Math::Vector3& pos, const Math::Vector3& target, const Math::Vector3& worldUp) { 22 | Forward = normalize(target - pos); 23 | Right = normalize(cross(worldUp, Forward)); 24 | Up = cross(Forward, Right); 25 | Position = pos; 26 | } 27 | void Camera::UpdateProjectionMatrix() { 28 | if (isOrtho) { 29 | mFarZ = Max(mFarZ, mNearZ + 0.1f); 30 | Matrix4 P = XMMatrixOrthographicLH(orthoSize, orthoSize, mNearZ, mFarZ); 31 | Proj = P; 32 | } else { 33 | mNearZ = Max(mNearZ, 0.01f); 34 | mFarZ = Max(mFarZ, mNearZ + 0.1f); 35 | Matrix4 P = XMMatrixPerspectiveFovLH(mFovY, mAspect, mNearZ, mFarZ); 36 | Proj = P; 37 | } 38 | } 39 | void Camera::UpdateViewMatrix() { 40 | View = GetInverseTransformMatrix(Right, Up, Forward, Position); 41 | } 42 | -------------------------------------------------------------------------------- /Chapter3/src/Component/Camera.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | class Camera final { 6 | public: 7 | ~Camera(); 8 | Camera(); 9 | // frustum properties. 10 | float NearZ() const { return mNearZ; } 11 | float FarZ() const { return mFarZ; } 12 | float Aspect() const { return mAspect; } 13 | float FovY() const { return mFovY; } 14 | float FovX() const { 15 | float halfWidth = 0.5 * NearWindowWidth(); 16 | return 2.0 * atan(halfWidth / mNearZ); 17 | } 18 | 19 | // near and far plane dimensions in view space coordinates. 20 | float NearWindowWidth() const { return mAspect * mNearWindowHeight; } 21 | float NearWindowHeight() const { return mNearWindowHeight; } 22 | float FarWindowWidth() const { return mAspect * mFarWindowHeight; } 23 | float FarWindowHeight() const { return mFarWindowHeight; } 24 | 25 | // Set frustum. 26 | void SetLens(float fovY, float zn, float zf); 27 | void SetAspect(float aspect); 28 | // Define camera space via LookAt parameters. 29 | void LookAt(const Math::Vector3& pos, const Math::Vector3& target, const Math::Vector3& worldUp); 30 | void UpdateViewMatrix(); 31 | void UpdateProjectionMatrix(); 32 | Math::Matrix4 View = MathHelper::Identity4x4(); 33 | Math::Matrix4 Proj = MathHelper::Identity4x4(); 34 | Math::Vector3 Position = {0.0f, 0.0f, 0.0f}; 35 | Math::Vector3 Right = {1.0f, 0.0f, 0.0f}; 36 | Math::Vector3 Up = {0.0f, 1.0f, 0.0f}; 37 | Math::Vector3 Forward = {0.0f, 0.0f, 1.0f}; 38 | float orthoSize = 5; 39 | bool isOrtho = false; 40 | 41 | private: 42 | float mNearZ = 0.0f; 43 | float mFarZ = 0.0f; 44 | float mAspect = 1.0f; 45 | float mFovY = 0.0f; 46 | float mNearWindowHeight = 0.0f; 47 | float mFarWindowHeight = 0.0f; 48 | 49 | }; 50 | -------------------------------------------------------------------------------- /Chapter3/src/D3D12SimpleBox.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | //0 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #pragma once 13 | 14 | #include "DXSample.h" 15 | #include 16 | #include 17 | #include 18 | 19 | using namespace DirectX; 20 | // Note that while ComPtr is used to manage the lifetime of resources on the CPU, 21 | // it has no understanding of the lifetime of resources on the GPU. Apps must account 22 | // for the GPU lifetime of resources to avoid destroying objects that may still be 23 | // referenced by the GPU. 24 | // An example of this can be found in the class method: OnDestroy(). 25 | using Microsoft::WRL::ComPtr; 26 | class FrameResource; 27 | class Camera; 28 | class CommandListHandle; 29 | class DefaultBuffer; 30 | struct Vertex : public rtti::Struct { 31 | rtti::Var position = "POSITION"; 32 | rtti::Var color = "COLOR"; 33 | }; 34 | class D3D12SimpleBox : public DXSample { 35 | public: 36 | D3D12SimpleBox(uint32_t width, uint32_t height, std::wstring name); 37 | D3D12SimpleBox(D3D12SimpleBox const&) = delete; 38 | D3D12SimpleBox(D3D12SimpleBox&&) = delete; 39 | void OnInit() override; 40 | void OnUpdate() override; 41 | void OnRender() override; 42 | void OnDestroy() override; 43 | ~D3D12SimpleBox(); 44 | 45 | private: 46 | static const uint32_t FrameCount = 3; 47 | std::unique_ptr device; 48 | std::unique_ptr mainCamera; 49 | // Pipeline objects. 50 | CD3DX12_VIEWPORT m_viewport; 51 | CD3DX12_RECT m_scissorRect; 52 | ComPtr m_swapChain; 53 | ComPtr m_renderTargets[FrameCount]; 54 | ComPtr m_depthTarget; 55 | ComPtr m_commandQueue; 56 | ComPtr m_rootSignature; 57 | ComPtr m_rtvHeap; 58 | ComPtr m_dsvHeap; 59 | ComPtr m_pipelineState; 60 | uint32_t m_rtvDescriptorSize; 61 | uint32_t m_dsvDescriptorSize; 62 | std::unique_ptr frameResources[FrameCount]; 63 | 64 | // App resources. 65 | std::unique_ptr triangleMesh; 66 | std::unique_ptr constBuffer; 67 | // Synchronization objects. 68 | uint32_t m_backBufferIndex; 69 | ComPtr m_fence; 70 | uint64_t m_fenceValue; 71 | void LoadPipeline(); 72 | void LoadAssets(); 73 | void PopulateCommandList(CommandListHandle const& cmdListHandle, uint frameIndex) const; 74 | }; 75 | -------------------------------------------------------------------------------- /Chapter3/src/DXMath/DXMathConfig.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #define NOMINMAX 5 | ///////////////////////// Clang 6 | #define _XM_NO_INTRINSICS_ 7 | #define m128_f32 vector4_f32 8 | #define m128_u32 vector4_u32 9 | -------------------------------------------------------------------------------- /Chapter3/src/DXMath/MathHelper.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace DirectX; 5 | const float MathHelper::Infinity = FLT_MAX; 6 | const float MathHelper::Pi = 3.1415926535f; 7 | float MathHelper::AngleFromXY(float x, float y) { 8 | float theta = 0.0f; 9 | 10 | // Quadrant I or IV 11 | if (x >= 0.0f) { 12 | // If x = 0, then atanf(y/x) = +pi/2 if y > 0 13 | // atanf(y/x) = -pi/2 if y < 0 14 | theta = atanf(y / x);// in [-pi/2, +pi/2] 15 | if (theta < 0.0f) 16 | theta += 2.0f * Pi;// in [0, 2*pi). 17 | } 18 | // Quadrant II or III 19 | else 20 | theta = atanf(y / x) + Pi;// in [0, 2*pi). 21 | return theta; 22 | } 23 | XMVECTOR MathHelper::RandUnitVec3() { 24 | XMVECTOR One = XMVectorSet(1.0f, 1.0f, 1.0f, 1.0f); 25 | XMVECTOR Zero = XMVectorZero(); 26 | // Keep trying until we get a point on/in the hemisphere. 27 | while (true) { 28 | // Generate random point in the cube [-1,1]^3. 29 | XMVECTOR v = XMVectorSet(MathHelper::RandF(-1.0f, 1.0f), MathHelper::RandF(-1.0f, 1.0f), MathHelper::RandF(-1.0f, 1.0f), 0.0f); 30 | // Ignore points outside the unit sphere in order to get an even distribution 31 | // over the unit sphere. Otherwise points will clump more on the sphere near 32 | // the corners of the cube. 33 | if (XMVector3Greater(XMVector3LengthSq(v), One)) 34 | continue; 35 | return XMVector3Normalize(v); 36 | } 37 | } 38 | XMVECTOR MathHelper::RandHemisphereUnitVec3(XMVECTOR n) { 39 | XMVECTOR One = XMVectorSet(1.0f, 1.0f, 1.0f, 1.0f); 40 | XMVECTOR Zero = XMVectorZero(); 41 | // Keep trying until we get a point on/in the hemisphere. 42 | while (true) { 43 | // Generate random point in the cube [-1,1]^3. 44 | XMVECTOR v = XMVectorSet(MathHelper::RandF(-1.0f, 1.0f), MathHelper::RandF(-1.0f, 1.0f), MathHelper::RandF(-1.0f, 1.0f), 0.0f); 45 | // Ignore points outside the unit sphere in order to get an even distribution 46 | // over the unit sphere. Otherwise points will clump more on the sphere near 47 | // the corners of the cube. 48 | 49 | if (XMVector3Greater(XMVector3LengthSq(v), One)) 50 | continue; 51 | // Ignore points in the bottom hemisphere. 52 | if (XMVector3Less(XMVector3Dot(n, v), Zero)) 53 | continue; 54 | return XMVector3Normalize(v); 55 | } 56 | } 57 | 58 | DirectX::XMVECTOR MathHelper::SphericalToCartesian(float radius, float theta, float phi) { 59 | return DirectX::XMVectorSet( 60 | radius * sinf(phi) * cosf(theta), 61 | radius * cosf(phi), 62 | radius * sinf(phi) * sinf(theta), 63 | 1.0f); 64 | } 65 | 66 | DirectX::XMMATRIX MathHelper::InverseTranspose(DirectX::CXMMATRIX M) { 67 | // Inverse-transpose is just applied to normals. So zero out 68 | // translation row so that it doesn't get into our inverse-transpose 69 | // calculation--we don't want the inverse-transpose of the translation. 70 | DirectX::XMMATRIX A = M; 71 | A.r[3] = DirectX::XMVectorSet(0.0f, 0.0f, 0.0f, 1.0f); 72 | 73 | DirectX::XMVECTOR det = DirectX::XMMatrixDeterminant(A); 74 | return DirectX::XMMatrixTranspose(DirectX::XMMatrixInverse(&det, A)); 75 | } 76 | 77 | float4x4 MathHelper::Identity4x4() { 78 | static float4x4 I( 79 | 1.0f, 0.0f, 0.0f, 0.0f, 80 | 0.0f, 1.0f, 0.0f, 0.0f, 81 | 0.0f, 0.0f, 1.0f, 0.0f, 82 | 0.0f, 0.0f, 0.0f, 1.0f); 83 | 84 | return I; 85 | } -------------------------------------------------------------------------------- /Chapter3/src/DXMath/MathHelper.h: -------------------------------------------------------------------------------- 1 | //*************************************************************************************** 2 | // MathHelper.h by Frank Luna (C) 2011 All Rights Reserved. 3 | // 4 | // Helper math class. 5 | //*************************************************************************************** 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | class MathHelper { 13 | public: 14 | // Returns random float in [0, 1). 15 | static float RandF() { 16 | return (float)(rand()) / (float)RAND_MAX; 17 | } 18 | 19 | // Returns random float in [a, b). 20 | static float RandF(float a, float b) { 21 | return a + RandF() * (b - a); 22 | } 23 | 24 | static int32_t Rand(int32_t a, int32_t b) { 25 | return a + rand() % ((b - a) + 1); 26 | } 27 | 28 | template 29 | static T Min(const T& a, const T& b) { 30 | return a < b ? a : b; 31 | } 32 | 33 | template 34 | static T Max(const T& a, const T& b) { 35 | return a > b ? a : b; 36 | } 37 | 38 | template 39 | static T Lerp(const T& a, const T& b, float t) { 40 | return a + (b - a) * t; 41 | } 42 | 43 | template 44 | static T Clamp(const T& x, const T& low, const T& high) { 45 | return x < low ? low : (x > high ? high : x); 46 | } 47 | 48 | // Returns the polar angle of the point (x,y) in [0, 2*PI). 49 | static float AngleFromXY(float x, float y); 50 | 51 | static DirectX::XMVECTOR SphericalToCartesian(float radius, float theta, float phi); 52 | 53 | static DirectX::XMMATRIX InverseTranspose(DirectX::CXMMATRIX M); 54 | 55 | static float4x4 Identity4x4(); 56 | 57 | static DirectX::XMVECTOR RandUnitVec3(); 58 | static DirectX::XMVECTOR RandHemisphereUnitVec3(DirectX::XMVECTOR n); 59 | 60 | static const float Infinity; 61 | static const float Pi; 62 | }; 63 | -------------------------------------------------------------------------------- /Chapter3/src/DXMath/Matrix3.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Microsoft. All rights reserved. 3 | // This code is licensed under the MIT License (MIT). 4 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 5 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 6 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 7 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 8 | // 9 | // Developed by Minigraph 10 | // 11 | // Author: James Stanard 12 | // 13 | 14 | #pragma once 15 | 16 | #include 17 | 18 | namespace Math { 19 | // Represents a 3x3 matrix while occuping a 4x4 memory footprint. The unused row and column are undefined but implicitly 20 | // (0, 0, 0, 1). Constructing a Matrix4 will make those values explicit. 21 | class alignas(16) Matrix3 { 22 | public: 23 | INLINE XM_CALLCONV Matrix3() {} 24 | INLINE XM_CALLCONV Matrix3(const Vector3& x, const Vector3& y, const Vector3& z) { 25 | m_mat[0] = x; 26 | m_mat[1] = y; 27 | m_mat[2] = z; 28 | } 29 | INLINE XM_CALLCONV Matrix3(const Matrix3& m) { 30 | m_mat[0] = m.m_mat[0]; 31 | m_mat[1] = m.m_mat[1]; 32 | m_mat[2] = m.m_mat[2]; 33 | } 34 | INLINE XM_CALLCONV Matrix3(Quaternion q) { *this = Matrix3(XMMatrixRotationQuaternion(q)); } 35 | INLINE explicit XM_CALLCONV Matrix3(const XMMATRIX& m) { 36 | m_mat[0] = Vector3(m.r[0]); 37 | m_mat[1] = Vector3(m.r[1]); 38 | m_mat[2] = Vector3(m.r[2]); 39 | } 40 | INLINE explicit XM_CALLCONV Matrix3(EIdentityTag) { 41 | m_mat[0] = Vector3(kXUnitVector); 42 | m_mat[1] = Vector3(kYUnitVector); 43 | m_mat[2] = Vector3(kZUnitVector); 44 | } 45 | INLINE explicit XM_CALLCONV Matrix3(EZeroTag) { m_mat[0] = m_mat[1] = m_mat[2] = Vector3(kZero); } 46 | 47 | INLINE void XM_CALLCONV SetX(const Vector3& x) { m_mat[0] = x; } 48 | INLINE void XM_CALLCONV SetY(const Vector3& y) { m_mat[1] = y; } 49 | INLINE void XM_CALLCONV SetZ(const Vector3& z) { m_mat[2] = z; } 50 | 51 | INLINE Vector3 XM_CALLCONV GetX() const { return m_mat[0]; } 52 | INLINE Vector3 XM_CALLCONV GetY() const { return m_mat[1]; } 53 | INLINE Vector3 XM_CALLCONV GetZ() const { return m_mat[2]; } 54 | 55 | static INLINE Matrix3 XM_CALLCONV MakeXRotation(float angle) { return Matrix3(XMMatrixRotationX(angle)); } 56 | static INLINE Matrix3 XM_CALLCONV MakeYRotation(float angle) { return Matrix3(XMMatrixRotationY(angle)); } 57 | static INLINE Matrix3 XM_CALLCONV MakeZRotation(float angle) { return Matrix3(XMMatrixRotationZ(angle)); } 58 | static INLINE Matrix3 XM_CALLCONV MakeScale(float scale) { return Matrix3(XMMatrixScaling(scale, scale, scale)); } 59 | static INLINE Matrix3 XM_CALLCONV MakeScale(float sx, float sy, float sz) { return Matrix3(XMMatrixScaling(sx, sy, sz)); } 60 | static INLINE Matrix3 XM_CALLCONV MakeScale(const Vector3& scale) { return Matrix3(XMMatrixScalingFromVector(scale)); } 61 | 62 | INLINE XM_CALLCONV operator XMMATRIX&() const { return (XMMATRIX&)m_mat[0]; } 63 | INLINE XMVECTOR& XM_CALLCONV operator[](uint i) { 64 | return m_mat[i].m_vec; 65 | } 66 | INLINE const XMVECTOR& XM_CALLCONV operator[](uint i) const { 67 | return m_mat[i].m_vec; 68 | } 69 | INLINE Vector3 XM_CALLCONV operator*(Vector3 vec) const { return Vector3(XMVector3TransformNormal(vec, *this)); } 70 | INLINE Matrix3 XM_CALLCONV operator*(const Matrix3& mat) const { return Matrix3(*this * mat.GetX(), *this * mat.GetY(), *this * mat.GetZ()); } 71 | 72 | private: 73 | Vector3 m_mat[3]; 74 | }; 75 | 76 | }// namespace Math -------------------------------------------------------------------------------- /Chapter3/src/DXMath/Matrix4.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Microsoft. All rights reserved. 3 | // This code is licensed under the MIT License (MIT). 4 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 5 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 6 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 7 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 8 | // 9 | // Developed by Minigraph 10 | // 11 | // Author: James Stanard 12 | // 13 | 14 | #pragma once 15 | 16 | #include 17 | namespace Math 18 | { 19 | class alignas(16) Matrix4 20 | { 21 | public: 22 | INLINE XM_CALLCONV Matrix4() {} 23 | INLINE XM_CALLCONV Matrix4(const Vector3& x, const Vector3& y, const Vector3& z, const Vector3& w) 24 | { 25 | m_mat.r[0] = SetWToZero(x); m_mat.r[1] = SetWToZero(y); 26 | m_mat.r[2] = SetWToZero(z); m_mat.r[3] = SetWToOne(w); 27 | } 28 | INLINE XM_CALLCONV Matrix4(const Vector4& x, const Vector4& y, const Vector4& z, const Vector4& w) { m_mat.r[0] = x; m_mat.r[1] = y; m_mat.r[2] = z; m_mat.r[3] = w; } 29 | INLINE XM_CALLCONV Matrix4(const Matrix4& mat) : m_mat(mat.m_mat) { } 30 | INLINE XM_CALLCONV Matrix4(const Matrix3& mat) 31 | { 32 | m_mat.r[0] = SetWToZero(mat.GetX()); 33 | m_mat.r[1] = SetWToZero(mat.GetY()); 34 | m_mat.r[2] = SetWToZero(mat.GetZ()); 35 | m_mat.r[3] = CreateWUnitVector(); 36 | } 37 | INLINE XM_CALLCONV Matrix4(const XMMATRIX& mat) : m_mat(mat) {} 38 | INLINE XM_CALLCONV Matrix4(const Matrix3& xyz, const Vector3& w) 39 | { 40 | m_mat.r[0] = SetWToZero(xyz.GetX()); 41 | m_mat.r[1] = SetWToZero(xyz.GetY()); 42 | m_mat.r[2] = SetWToZero(xyz.GetZ()); 43 | m_mat.r[3] = SetWToOne(w); 44 | } 45 | INLINE XM_CALLCONV Matrix4(EIdentityTag) { m_mat = XMMatrixIdentity(); } 46 | INLINE XM_CALLCONV Matrix4(EZeroTag) { m_mat.r[0] = m_mat.r[1] = m_mat.r[2] = m_mat.r[3] = SplatZero(); } 47 | INLINE XM_CALLCONV Matrix4(const float4x4& f) 48 | { 49 | m_mat = XMLoadFloat4x4(&f); 50 | } 51 | 52 | INLINE XM_CALLCONV operator float4x4() const 53 | { 54 | float4x4 f; 55 | XMStoreFloat4x4(&f, m_mat); 56 | return f; 57 | } 58 | 59 | INLINE const Matrix3& XM_CALLCONV Get3x3() const { return (const Matrix3&)*this; } 60 | 61 | INLINE Vector4 XM_CALLCONV GetX() const { return Vector4(m_mat.r[0]); } 62 | INLINE Vector4 XM_CALLCONV GetY() const { return Vector4(m_mat.r[1]); } 63 | INLINE Vector4 XM_CALLCONV GetZ() const { return Vector4(m_mat.r[2]); } 64 | INLINE Vector4 XM_CALLCONV GetW() const { return Vector4(m_mat.r[3]); } 65 | 66 | INLINE void XM_CALLCONV SetX(const Vector4& x) { m_mat.r[0] = x; } 67 | INLINE void XM_CALLCONV SetY(const Vector4& y) { m_mat.r[1] = y; } 68 | INLINE void XM_CALLCONV SetZ(const Vector4& z) { m_mat.r[2] = z; } 69 | INLINE void XM_CALLCONV SetW(const Vector4& w) { m_mat.r[3] = w; } 70 | 71 | INLINE XM_CALLCONV operator XMMATRIX& () const { return (XMMATRIX&)m_mat; } 72 | INLINE XMVECTOR& XM_CALLCONV operator[] (uint i) 73 | { 74 | return m_mat.r[i]; 75 | } 76 | INLINE const XMVECTOR& XM_CALLCONV operator[] (uint i) const 77 | { 78 | return m_mat.r[i]; 79 | } 80 | 81 | INLINE Vector4 XM_CALLCONV operator* (const Vector3& vec) const { return Vector4(XMVector3Transform(vec, m_mat)); } 82 | INLINE Vector4 XM_CALLCONV operator* (const Vector4& vec) const { return Vector4(XMVector4Transform(vec, m_mat)); } 83 | INLINE Matrix4 XM_CALLCONV operator* (const Matrix4& mat) const { return Matrix4(XMMatrixMultiply(mat, m_mat)); } 84 | 85 | static INLINE Matrix4 XM_CALLCONV MakeScale(float scale) { return Matrix4(XMMatrixScaling(scale, scale, scale)); } 86 | static INLINE Matrix4 XM_CALLCONV MakeScale(const Vector3& scale) { return Matrix4(XMMatrixScalingFromVector(scale)); } 87 | 88 | 89 | private: 90 | XMMATRIX m_mat; 91 | }; 92 | } -------------------------------------------------------------------------------- /Chapter3/src/DXMath/Quaternion.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Microsoft. All rights reserved. 3 | // This code is licensed under the MIT License (MIT). 4 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 5 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 6 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 7 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 8 | // 9 | // Developed by Minigraph 10 | // 11 | // Author: James Stanard 12 | // 13 | 14 | #pragma once 15 | 16 | #include 17 | 18 | namespace Math { 19 | class alignas(16) Quaternion { 20 | public: 21 | INLINE XM_CALLCONV Quaternion() { m_vec = XMQuaternionIdentity(); } 22 | INLINE XM_CALLCONV Quaternion(const Vector3& axis, const Scalar& angle) { m_vec = XMQuaternionRotationAxis(axis, angle); } 23 | INLINE XM_CALLCONV Quaternion(float pitch, float yaw, float roll) { m_vec = XMQuaternionRotationRollPitchYaw(pitch, yaw, roll); } 24 | INLINE explicit XM_CALLCONV Quaternion(const XMMATRIX& matrix) { m_vec = XMQuaternionRotationMatrix(matrix); } 25 | INLINE explicit XM_CALLCONV Quaternion(FXMVECTOR vec) { m_vec = vec; } 26 | INLINE explicit XM_CALLCONV Quaternion(EIdentityTag) { m_vec = XMQuaternionIdentity(); } 27 | 28 | INLINE XM_CALLCONV operator XMVECTOR() const { return m_vec; } 29 | 30 | INLINE Quaternion XM_CALLCONV operator~(void) const { return Quaternion(XMQuaternionConjugate(m_vec)); } 31 | INLINE Quaternion XM_CALLCONV operator-(void) const { return Quaternion(XMVectorNegate(m_vec)); } 32 | 33 | INLINE Quaternion XM_CALLCONV operator*(Quaternion rhs) const { return Quaternion(XMQuaternionMultiply(rhs, m_vec)); } 34 | INLINE Vector3 XM_CALLCONV operator*(Vector3 rhs) const { return Vector3(XMVector3Rotate(rhs, m_vec)); } 35 | 36 | INLINE Quaternion& XM_CALLCONV operator=(Quaternion rhs) { 37 | m_vec = rhs; 38 | return *this; 39 | } 40 | INLINE Quaternion& XM_CALLCONV operator*=(Quaternion rhs) { 41 | *this = *this * rhs; 42 | return *this; 43 | } 44 | 45 | protected: 46 | XMVECTOR m_vec; 47 | }; 48 | 49 | }// namespace Math -------------------------------------------------------------------------------- /Chapter3/src/DXMath/Scalar.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Microsoft. All rights reserved. 3 | // This code is licensed under the MIT License (MIT). 4 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 5 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 6 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 7 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 8 | // 9 | // Developed by Minigraph 10 | // 11 | // Author: James Stanard 12 | // 13 | 14 | #pragma once 15 | 16 | #include 17 | 18 | namespace Math 19 | { 20 | class Scalar 21 | { 22 | public: 23 | INLINE XM_CALLCONV Scalar() {} 24 | INLINE XM_CALLCONV Scalar(const Scalar& s) { m_vec = s; } 25 | INLINE XM_CALLCONV Scalar(float f) { m_vec = XMVectorReplicate(f); } 26 | INLINE explicit XM_CALLCONV Scalar(const FXMVECTOR& vec) { m_vec = vec; } 27 | 28 | INLINE XM_CALLCONV operator const XMVECTOR&() const { return m_vec; } 29 | INLINE XM_CALLCONV operator float() const { return XMVectorGetX(m_vec); } 30 | 31 | private: 32 | XMVECTOR m_vec; 33 | }; 34 | 35 | INLINE Scalar XM_CALLCONV operator- (const Scalar& s) { return Scalar(XMVectorNegate(s)); } 36 | INLINE Scalar XM_CALLCONV operator+ (const Scalar& s1, const Scalar& s2) { return Scalar(XMVectorAdd(s1, s2)); } 37 | INLINE Scalar XM_CALLCONV operator- (const Scalar& s1, const Scalar& s2) { return Scalar(XMVectorSubtract(s1, s2)); } 38 | INLINE Scalar XM_CALLCONV operator* (const Scalar& s1, const Scalar& s2) { return Scalar(XMVectorMultiply(s1, s2)); } 39 | INLINE Scalar XM_CALLCONV operator/ (const Scalar& s1, const Scalar& s2) { return Scalar(XMVectorDivide(s1, s2)); } 40 | INLINE Scalar XM_CALLCONV operator+ (const Scalar& s1, float s2) { return s1 + Scalar(s2); } 41 | INLINE Scalar XM_CALLCONV operator- (const Scalar& s1, float s2) { return s1 - Scalar(s2); } 42 | INLINE Scalar XM_CALLCONV operator* (const Scalar& s1, float s2) { return s1 * Scalar(s2); } 43 | INLINE Scalar XM_CALLCONV operator/ (const Scalar& s1, float s2) { return s1 / Scalar(s2); } 44 | INLINE Scalar XM_CALLCONV operator+ (float s1, const Scalar& s2) { return Scalar(s1) + s2; } 45 | INLINE Scalar XM_CALLCONV operator- (float s1, const Scalar& s2) { return Scalar(s1) - s2; } 46 | INLINE Scalar XM_CALLCONV operator* (float s1, const Scalar& s2) { return Scalar(s1) * s2; } 47 | INLINE Scalar XM_CALLCONV operator/ (float s1, const Scalar& s2) { return Scalar(s1) / s2; } 48 | 49 | } // namespace Math -------------------------------------------------------------------------------- /Chapter3/src/DXMath/Swizzle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | template 5 | struct Swizzle; 6 | 7 | template 8 | struct Swizzle { 9 | inline operator target_type() const { 10 | const base_type* self = reinterpret_cast(this); 11 | base_type pad[sizeof...(sequence)] = {self[sequence]...}; 12 | return *reinterpret_cast(pad); 13 | } 14 | 15 | inline target_type operator=(target_type rhs) { 16 | base_type* self = reinterpret_cast(this); 17 | base_type* prhs = reinterpret_cast(&rhs); 18 | 19 | assign(self, prhs, std::make_index_sequence()); 20 | 21 | return *reinterpret_cast(this); 22 | } 23 | 24 | private: 25 | template 26 | inline void assign(base_type* self, base_type* rhs, std::index_sequence seq) { 27 | base_type tmp[] = {self[sequence] = rhs[indices]...}; 28 | } 29 | }; 30 | template 31 | struct Swizzle { 32 | inline operator target_type() const { 33 | const base_type* self = reinterpret_cast(this); 34 | base_type pad[sizeof...(sequence)] = {self[sequence]...}; 35 | return *reinterpret_cast(pad); 36 | } 37 | 38 | private: 39 | template 40 | inline void assign(base_type* self, base_type* rhs, std::index_sequence seq) { 41 | base_type tmp[] = {self[sequence] = rhs[indices]...}; 42 | } 43 | }; -------------------------------------------------------------------------------- /Chapter3/src/DXRuntime/CommandListHandle.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | CommandListHandle::CommandListHandle(CommandListHandle&& v) 4 | : cmdList(v.cmdList) { 5 | v.cmdList = nullptr; 6 | } 7 | CommandListHandle::CommandListHandle( 8 | ID3D12CommandAllocator* allocator, 9 | ID3D12GraphicsCommandList* cmdList) 10 | : cmdList(cmdList) { 11 | ThrowIfFailed(allocator->Reset()); 12 | ThrowIfFailed(cmdList->Reset(allocator, nullptr)); 13 | } 14 | CommandListHandle::~CommandListHandle() { 15 | if (cmdList) 16 | cmdList->Close(); 17 | } 18 | -------------------------------------------------------------------------------- /Chapter3/src/DXRuntime/CommandListHandle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | class CommandListHandle { 4 | ID3D12GraphicsCommandList* cmdList; 5 | 6 | public: 7 | ID3D12GraphicsCommandList* CmdList() const { return cmdList; } 8 | CommandListHandle(CommandListHandle const&) = delete; 9 | CommandListHandle(CommandListHandle&&); 10 | CommandListHandle( 11 | ID3D12CommandAllocator* allocator, 12 | ID3D12GraphicsCommandList* cmdList); 13 | ~CommandListHandle(); 14 | }; -------------------------------------------------------------------------------- /Chapter3/src/DXRuntime/Device.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | Device::~Device() { 5 | } 6 | 7 | Device::Device() { 8 | using Microsoft::WRL::ComPtr; 9 | uint32_t dxgiFactoryFlags = 0; 10 | 11 | #if defined(_DEBUG) 12 | // Enable the debug layer (requires the Graphics Tools "optional feature"). 13 | // NOTE: Enabling the debug layer after device creation will invalidate the active device. 14 | { 15 | ComPtr debugController; 16 | if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) { 17 | debugController->EnableDebugLayer(); 18 | 19 | // Enable additional debug layers. 20 | dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG; 21 | } 22 | } 23 | #endif 24 | ThrowIfFailed(CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&dxgiFactory))); 25 | uint adapterIndex = 0; // we'll start looking for directx 12 compatible graphics devices starting at index 0 26 | bool adapterFound = false;// set this to true when a good one was found 27 | while (dxgiFactory->EnumAdapters1(adapterIndex, &adapter) != DXGI_ERROR_NOT_FOUND) { 28 | DXGI_ADAPTER_DESC1 desc; 29 | adapter->GetDesc1(&desc); 30 | if ((desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) == 0) { 31 | HRESULT hr = D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_12_1, 32 | IID_PPV_ARGS(&dxDevice)); 33 | if (SUCCEEDED(hr)) { 34 | adapterFound = true; 35 | break; 36 | } 37 | } 38 | adapter = nullptr; 39 | adapterIndex++; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Chapter3/src/DXRuntime/Device.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | class Device { 4 | Microsoft::WRL::ComPtr adapter; 5 | Microsoft::WRL::ComPtr dxDevice; 6 | Microsoft::WRL::ComPtr dxgiFactory; 7 | 8 | public: 9 | IDXGIAdapter1* Adapter() const { return adapter.Get(); } 10 | ID3D12Device5* DxDevice() const { return dxDevice.Get(); } 11 | IDXGIFactory4* DxgiFactory() const { return dxgiFactory.Get(); } 12 | Device(); 13 | ~Device(); 14 | }; 15 | -------------------------------------------------------------------------------- /Chapter3/src/DXRuntime/FrameResource.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | FrameResource::FrameResource(Device* device) { 4 | ThrowIfFailed( 5 | device 6 | ->DxDevice() 7 | ->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(cmdAllocator.GetAddressOf()))); 8 | ThrowIfFailed( 9 | device 10 | ->DxDevice() 11 | ->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAllocator.Get(), nullptr, IID_PPV_ARGS(&cmdList))); 12 | ThrowIfFailed( 13 | cmdList->Close()); 14 | } 15 | FrameResource::~FrameResource() { 16 | } 17 | void FrameResource::AddDelayDisposeResource(ComPtr const& ptr) { 18 | delayDisposeResources.push_back(ptr); 19 | } 20 | void FrameResource::Signal( 21 | ID3D12CommandQueue* queue, 22 | ID3D12Fence* fence) { 23 | if (!populated) return; 24 | queue->Signal(fence, lastFenceIndex); 25 | } 26 | void FrameResource::Execute( 27 | ID3D12CommandQueue* queue, 28 | ID3D12Fence* fence, 29 | uint64& fenceIndex) { 30 | if (!populated) return; 31 | lastFenceIndex = ++fenceIndex; 32 | ID3D12CommandList* ppCommandLists[] = {cmdList.Get()}; 33 | queue->ExecuteCommandLists(array_count(ppCommandLists), ppCommandLists); 34 | } 35 | void FrameResource::Sync( 36 | ID3D12Fence* fence) { 37 | if (!populated || lastFenceIndex == 0) return; 38 | if (fence->GetCompletedValue() < lastFenceIndex) { 39 | LPCWSTR falseValue = 0; 40 | HANDLE eventHandle = CreateEventEx(nullptr, falseValue, false, EVENT_ALL_ACCESS); 41 | ThrowIfFailed(fence->SetEventOnCompletion(lastFenceIndex, eventHandle)); 42 | WaitForSingleObject(eventHandle, INFINITE); 43 | CloseHandle(eventHandle); 44 | } 45 | delayDisposeResources.clear(); 46 | } 47 | CommandListHandle FrameResource::Command() { 48 | populated = true; 49 | return {cmdAllocator.Get(), cmdList.Get()}; 50 | } -------------------------------------------------------------------------------- /Chapter3/src/DXRuntime/FrameResource.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | using Microsoft::WRL::ComPtr; 5 | 6 | class FrameResource { 7 | ComPtr cmdAllocator; 8 | ComPtr cmdList; 9 | std::vector> delayDisposeResources; 10 | uint64 lastFenceIndex = 0; 11 | bool populated = false; 12 | 13 | public: 14 | CommandListHandle Command(); 15 | FrameResource(Device* device); 16 | ~FrameResource(); 17 | void AddDelayDisposeResource(ComPtr const& ptr); 18 | void Execute( 19 | ID3D12CommandQueue* queue, 20 | ID3D12Fence* fence, 21 | uint64& fenceIndex); 22 | void Signal( 23 | ID3D12CommandQueue* queue, 24 | ID3D12Fence* fence); 25 | void Sync( 26 | ID3D12Fence* fence); 27 | }; 28 | -------------------------------------------------------------------------------- /Chapter3/src/DXSample.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #pragma once 13 | 14 | #include "DXSampleHelper.h" 15 | #include "Win32Application.h" 16 | 17 | class DXSample 18 | { 19 | public: 20 | DXSample(uint32_t width, uint32_t height, std::wstring name); 21 | virtual ~DXSample(); 22 | 23 | virtual void OnInit() = 0; 24 | virtual void OnUpdate() = 0; 25 | virtual void OnRender() = 0; 26 | virtual void OnDestroy() = 0; 27 | 28 | // Samples override the event handlers to handle specific messages. 29 | virtual void OnKeyDown(UINT8 /*key*/) {} 30 | virtual void OnKeyUp(UINT8 /*key*/) {} 31 | 32 | // Accessors. 33 | uint32_t GetWidth() const { return m_width; } 34 | uint32_t GetHeight() const { return m_height; } 35 | const wchar_t* GetTitle() const { return m_title.c_str(); } 36 | 37 | void ParseCommandLineArgs(_In_reads_(argc) wchar_t* argv[], int argc); 38 | 39 | protected: 40 | std::wstring GetAssetFullPath(LPCWSTR assetName); 41 | 42 | void GetHardwareAdapter( 43 | _In_ IDXGIFactory1* pFactory, 44 | _Outptr_result_maybenull_ IDXGIAdapter1** ppAdapter, 45 | bool requestHighPerformanceAdapter = false); 46 | 47 | void SetCustomWindowText(LPCWSTR text); 48 | 49 | // Viewport dimensions. 50 | uint32_t m_width; 51 | uint32_t m_height; 52 | float m_aspectRatio; 53 | 54 | // Adapter info. 55 | bool m_useWarpDevice; 56 | 57 | private: 58 | // Root assets path. 59 | std::wstring m_assetsPath; 60 | 61 | // Window title. 62 | std::wstring m_title; 63 | }; 64 | -------------------------------------------------------------------------------- /Chapter3/src/Main.cpp: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #include "stdafx.h" 13 | #include "D3D12SimpleBox.h" 14 | 15 | _Use_decl_annotations_ 16 | int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) 17 | { 18 | D3D12SimpleBox sample(1280, 720, L"D3D12 Simple Box"); 19 | return Win32Application::Run(&sample, hInstance, nCmdShow); 20 | } 21 | -------------------------------------------------------------------------------- /Chapter3/src/Metalib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | template 4 | requires(!std::is_lvalue_reference_v) 5 | T* get_rvalue_ptr(T&& v) { 6 | return &v; 7 | } 8 | template 9 | struct array_meta; 10 | template 11 | struct array_meta { 12 | static constexpr size_t array_size = N; 13 | static constexpr size_t byte_size = N * sizeof(T); 14 | }; 15 | 16 | template 17 | requires(std::is_bounded_array_v) constexpr size_t array_count(T const& t) { 18 | return array_meta::array_size; 19 | } 20 | template 21 | requires(std::is_bounded_array_v) constexpr size_t array_byte_size(T const& t) { 22 | return array_meta::byte_size; 23 | } 24 | 25 | using vbyte = uint8_t; 26 | using uint = uint32_t; 27 | using uint64 = uint64_t; 28 | using int32 = int32_t; 29 | -------------------------------------------------------------------------------- /Chapter3/src/Resource/Buffer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | BufferView::BufferView(Buffer const* buffer) 4 | : buffer(buffer), 5 | byteSize(buffer ? buffer->GetByteSize() : 0), 6 | offset(0) { 7 | } 8 | BufferView::BufferView( 9 | Buffer const* buffer, 10 | uint64 offset, 11 | uint64 byteSize) 12 | : buffer(buffer), 13 | offset(offset), 14 | byteSize(byteSize) {} 15 | Buffer::Buffer( 16 | Device* device) 17 | : Resource(device){ 18 | } 19 | Buffer::~Buffer() { 20 | } 21 | -------------------------------------------------------------------------------- /Chapter3/src/Resource/Buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | class Buffer : public Resource{ 6 | public: 7 | Buffer(Device* device); 8 | virtual D3D12_GPU_VIRTUAL_ADDRESS GetAddress() const = 0; 9 | virtual uint64 GetByteSize() const = 0; 10 | virtual ~Buffer(); 11 | Buffer(Buffer&&) = default; 12 | }; 13 | -------------------------------------------------------------------------------- /Chapter3/src/Resource/BufferView.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class Buffer; 5 | struct BufferView { 6 | Buffer const* buffer = nullptr; 7 | uint64 offset = 0; 8 | uint64 byteSize = 0; 9 | BufferView() {} 10 | BufferView(Buffer const* buffer); 11 | BufferView( 12 | Buffer const* buffer, 13 | uint64 offset, 14 | uint64 byteSize); 15 | bool operator==(BufferView const& a) const { 16 | return memcmp(this, &a, sizeof(BufferView)) == 0; 17 | } 18 | bool operator!=(BufferView const& a) const { 19 | return !operator==(a); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /Chapter3/src/Resource/DefaultBuffer.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | DefaultBuffer::DefaultBuffer( 7 | Device* device, 8 | uint64 byteSize, 9 | D3D12_RESOURCE_STATES initState) 10 | : Buffer(device), 11 | initState(initState), 12 | byteSize(byteSize) { 13 | auto prop = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT); 14 | auto buffer = CD3DX12_RESOURCE_DESC::Buffer(byteSize, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); 15 | ThrowIfFailed(device->DxDevice()->CreateCommittedResource( 16 | &prop, 17 | D3D12_HEAP_FLAG_NONE, 18 | &buffer, 19 | initState, 20 | nullptr, 21 | IID_PPV_ARGS(&resource))); 22 | } 23 | DefaultBuffer::~DefaultBuffer() { 24 | } 25 | void DefaultBuffer::DelayDispose(FrameResource* frameRes) const { 26 | frameRes->AddDelayDisposeResource(resource); 27 | } -------------------------------------------------------------------------------- /Chapter3/src/Resource/DefaultBuffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class DefaultBuffer final : public Buffer { 5 | private: 6 | uint64 byteSize; 7 | D3D12_RESOURCE_STATES initState; 8 | ComPtr resource; 9 | 10 | public: 11 | ID3D12Resource* GetResource() const override { return resource.Get(); } 12 | D3D12_GPU_VIRTUAL_ADDRESS GetAddress() const override { return resource->GetGPUVirtualAddress(); } 13 | uint64 GetByteSize() const override { return byteSize; } 14 | DefaultBuffer( 15 | Device* device, 16 | uint64 byteSize, 17 | D3D12_RESOURCE_STATES initState = D3D12_RESOURCE_STATE_COMMON); 18 | ~DefaultBuffer(); 19 | D3D12_RESOURCE_STATES GetInitState() const override { 20 | return initState; 21 | } 22 | 23 | DefaultBuffer(DefaultBuffer&&) = default; 24 | DefaultBuffer(DefaultBuffer const&) = delete; 25 | void DelayDispose(FrameResource* frameRes) const override; 26 | }; 27 | -------------------------------------------------------------------------------- /Chapter3/src/Resource/DescriptorHeap.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | DescriptorHeap::DescriptorHeap( 4 | Device* device, 5 | D3D12_DESCRIPTOR_HEAP_TYPE Type, 6 | uint64 numDescriptors, 7 | bool bShaderVisible) 8 | : Resource(device), 9 | allocatePool(numDescriptors), 10 | numDescriptors(numDescriptors) { 11 | Desc.Type = Type; 12 | Desc.NumDescriptors = numDescriptors; 13 | Desc.Flags = (bShaderVisible ? D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE : D3D12_DESCRIPTOR_HEAP_FLAG_NONE); 14 | Desc.NodeMask = 0; 15 | { 16 | for (size_t i = 0; i < numDescriptors; ++i) { 17 | allocatePool[i] = i; 18 | } 19 | } 20 | ThrowIfFailed(device->DxDevice()->CreateDescriptorHeap( 21 | &Desc, 22 | IID_PPV_ARGS(&pDH))); 23 | hCPUHeapStart = pDH->GetCPUDescriptorHandleForHeapStart(); 24 | hGPUHeapStart = pDH->GetGPUDescriptorHandleForHeapStart(); 25 | HandleIncrementSize = device->DxDevice()->GetDescriptorHandleIncrementSize(Desc.Type); 26 | } 27 | DescriptorHeap::~DescriptorHeap() { 28 | } 29 | uint DescriptorHeap::AllocateIndex() { 30 | std::lock_guard lck(heapMtx); 31 | #ifdef _DEBUG 32 | if (allocatePool.empty()) { 33 | throw "bindless allocator out or range!\n"; 34 | } 35 | #endif 36 | auto last = allocatePool.end() - 1; 37 | uint v = *last; 38 | allocatePool.erase(last); 39 | return v; 40 | } 41 | void DescriptorHeap::ReturnIndex(uint v) { 42 | std::lock_guard lck(heapMtx); 43 | allocatePool.emplace_back(v); 44 | } 45 | void DescriptorHeap::Reset() { 46 | allocatePool.resize(numDescriptors); 47 | for (size_t i = 0; i < numDescriptors; ++i) { 48 | allocatePool[i] = i; 49 | } 50 | } 51 | void DescriptorHeap::CreateUAV(ID3D12Resource* resource, const D3D12_UNORDERED_ACCESS_VIEW_DESC& pDesc, uint64 index) { 52 | device->DxDevice()->CreateUnorderedAccessView(resource, nullptr, &pDesc, hCPU(index)); 53 | } 54 | void DescriptorHeap::CreateSRV(ID3D12Resource* resource, const D3D12_SHADER_RESOURCE_VIEW_DESC& pDesc, uint64 index) { 55 | device->DxDevice()->CreateShaderResourceView(resource, &pDesc, hCPU(index)); 56 | } 57 | -------------------------------------------------------------------------------- /Chapter3/src/Resource/DescriptorHeap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | class DescriptorHeap final : public Resource { 10 | private: 11 | Microsoft::WRL::ComPtr pDH; 12 | D3D12_DESCRIPTOR_HEAP_DESC Desc; 13 | D3D12_CPU_DESCRIPTOR_HANDLE hCPUHeapStart; 14 | D3D12_GPU_DESCRIPTOR_HANDLE hGPUHeapStart; 15 | uint HandleIncrementSize; 16 | uint64 numDescriptors; 17 | std::vector allocatePool; 18 | std::mutex heapMtx; 19 | 20 | public: 21 | uint64 Length() const { return numDescriptors; } 22 | ID3D12DescriptorHeap* GetHeap() const { return pDH.Get(); } 23 | D3D12_GPU_DESCRIPTOR_HANDLE hGPU(uint64 index) const { 24 | if (index >= Desc.NumDescriptors) index = Desc.NumDescriptors - 1; 25 | D3D12_GPU_DESCRIPTOR_HANDLE h = {hGPUHeapStart.ptr + index * HandleIncrementSize}; 26 | return h; 27 | } 28 | D3D12_CPU_DESCRIPTOR_HANDLE hCPU(uint64 index) const { 29 | if (index >= Desc.NumDescriptors) index = Desc.NumDescriptors - 1; 30 | D3D12_CPU_DESCRIPTOR_HANDLE h = {hCPUHeapStart.ptr + index * HandleIncrementSize}; 31 | return h; 32 | } 33 | 34 | DescriptorHeap( 35 | Device* pDevice, 36 | D3D12_DESCRIPTOR_HEAP_TYPE Type, 37 | uint64 numDescriptors, 38 | bool bShaderVisible); 39 | uint AllocateIndex(); 40 | void ReturnIndex(uint v); 41 | void Reset(); 42 | void CreateUAV(ID3D12Resource* resource, const D3D12_UNORDERED_ACCESS_VIEW_DESC& pDesc, uint64 index); 43 | void CreateSRV(ID3D12Resource* resource, const D3D12_SHADER_RESOURCE_VIEW_DESC& pDesc, uint64 index); 44 | ~DescriptorHeap(); 45 | }; 46 | -------------------------------------------------------------------------------- /Chapter3/src/Resource/DescriptorHeapView.h: -------------------------------------------------------------------------------- 1 | #include 2 | class DescriptorHeap; 3 | struct DescriptorHeapView { 4 | DescriptorHeap const* heap; 5 | uint64 index; 6 | DescriptorHeapView( 7 | DescriptorHeap const* heap, 8 | uint64 index) 9 | : heap(heap), 10 | index(index) {} 11 | DescriptorHeapView( 12 | DescriptorHeap const* heap) 13 | : heap(heap), 14 | index(0) {} 15 | }; 16 | -------------------------------------------------------------------------------- /Chapter3/src/Resource/Mesh.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | Mesh::Mesh( 3 | Device* device, 4 | std::span vbStructs, 5 | uint vertexCount, 6 | uint indexCount) 7 | : Resource(device), 8 | vertexCount(vertexCount), 9 | vertexStructs(vbStructs), 10 | indexCount(indexCount), 11 | indexBuffer(device, sizeof(uint) * indexCount) { 12 | vertexBuffers.reserve(vertexStructs.size()); 13 | uint slotCount = 0; 14 | for (auto&& i : vertexStructs) { 15 | vertexBuffers.emplace_back(device, i->structSize * vertexCount); 16 | i->GetMeshLayout(slotCount, layout); 17 | ++slotCount; 18 | } 19 | } 20 | void Mesh::GetVertexBufferView(std::vector& result) const { 21 | result.clear(); 22 | result.resize(vertexBuffers.size()); 23 | for (size_t i = 0; i < vertexBuffers.size(); ++i) { 24 | auto& r = result[i]; 25 | auto& v = vertexBuffers[i]; 26 | r.BufferLocation = v.GetAddress(); 27 | r.SizeInBytes = v.GetByteSize(); 28 | r.StrideInBytes = r.SizeInBytes / vertexCount; 29 | } 30 | } 31 | 32 | D3D12_INDEX_BUFFER_VIEW Mesh::GetIndexBufferView() const { 33 | D3D12_INDEX_BUFFER_VIEW v; 34 | v.BufferLocation = indexBuffer.GetAddress(); 35 | v.SizeInBytes = indexBuffer.GetByteSize(); 36 | v.Format = DXGI_FORMAT_R32_UINT; 37 | return v; 38 | } -------------------------------------------------------------------------------- /Chapter3/src/Resource/Mesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | class Mesh : public Resource { 6 | std::vector vertexBuffers; 7 | DefaultBuffer indexBuffer; 8 | std::span vertexStructs; 9 | std::vector layout; 10 | uint vertexCount; 11 | uint indexCount; 12 | 13 | public: 14 | std::span VertexBuffers() const { return vertexBuffers; } 15 | DefaultBuffer const& IndexBuffer() const { return indexBuffer; } 16 | std::span Layout() const { return layout; } 17 | Mesh( 18 | Device* device, 19 | std::span vbStructs, 20 | uint vertexCount, 21 | uint indexCount); 22 | void GetVertexBufferView(std::vector& result) const; 23 | D3D12_INDEX_BUFFER_VIEW GetIndexBufferView() const; 24 | }; -------------------------------------------------------------------------------- /Chapter3/src/Resource/ReadbackBuffer.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | ReadbackBuffer::ReadbackBuffer( 7 | Device* device, 8 | uint64 byteSize) 9 | : Buffer(device), 10 | byteSize(byteSize) { 11 | auto prop = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK); 12 | auto buffer = CD3DX12_RESOURCE_DESC::Buffer(byteSize); 13 | ThrowIfFailed(device->DxDevice()->CreateCommittedResource( 14 | &prop, 15 | D3D12_HEAP_FLAG_NONE, 16 | &buffer, 17 | D3D12_RESOURCE_STATE_COPY_DEST, 18 | nullptr, 19 | IID_PPV_ARGS(&resource))); 20 | } 21 | ReadbackBuffer::~ReadbackBuffer() { 22 | } 23 | void ReadbackBuffer::CopyData( 24 | uint64 offset, 25 | std::span data) const { 26 | void* mapPtr; 27 | D3D12_RANGE range; 28 | range.Begin = offset; 29 | range.End = std::min(byteSize, offset + data.size()); 30 | ThrowIfFailed(resource->Map(0, &range, (void**)(&mapPtr))); 31 | memcpy(data.data(), reinterpret_cast(mapPtr) + offset, range.End - range.Begin); 32 | resource->Unmap(0, nullptr); 33 | } 34 | 35 | void ReadbackBuffer::DelayDispose(FrameResource* frameRes) const { 36 | frameRes->AddDelayDisposeResource(resource); 37 | } -------------------------------------------------------------------------------- /Chapter3/src/Resource/ReadbackBuffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | 5 | class ReadbackBuffer final : public Buffer { 6 | private: 7 | ComPtr resource; 8 | uint64 byteSize; 9 | 10 | public: 11 | ID3D12Resource* GetResource() const override { return resource.Get(); } 12 | D3D12_GPU_VIRTUAL_ADDRESS GetAddress() const override { return resource->GetGPUVirtualAddress(); } 13 | uint64 GetByteSize() const override { return byteSize; } 14 | ReadbackBuffer( 15 | Device* device, 16 | uint64 byteSize); 17 | ~ReadbackBuffer(); 18 | void CopyData(uint64 offset, std::span data) const; 19 | D3D12_RESOURCE_STATES GetInitState() const override { 20 | return D3D12_RESOURCE_STATE_COPY_DEST; 21 | } 22 | ReadbackBuffer(ReadbackBuffer&&) = default; 23 | ReadbackBuffer(ReadbackBuffer const&) = delete; 24 | void DelayDispose(FrameResource* frameRes) const override; 25 | }; 26 | -------------------------------------------------------------------------------- /Chapter3/src/Resource/Resource.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | using Microsoft::WRL::ComPtr; 5 | class FrameResource; 6 | class Resource { 7 | protected: 8 | Device* device; 9 | 10 | public: 11 | Device* GetDevice() const { return device; } 12 | Resource(Device* device) 13 | : device(device) {} 14 | Resource(Resource&&) = default; 15 | Resource(Resource const&) = delete; 16 | virtual ~Resource() = default; 17 | virtual ID3D12Resource* GetResource() const { return nullptr; } 18 | virtual D3D12_RESOURCE_STATES GetInitState() const { return D3D12_RESOURCE_STATE_COMMON; } 19 | virtual void DelayDispose(FrameResource* frameRes) const {} 20 | }; 21 | -------------------------------------------------------------------------------- /Chapter3/src/Resource/UploadBuffer.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | UploadBuffer::UploadBuffer( 6 | Device* device, 7 | uint64 byteSize) 8 | : Buffer(device), 9 | byteSize(byteSize) { 10 | auto prop = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD); 11 | auto buffer = CD3DX12_RESOURCE_DESC::Buffer(byteSize); 12 | ThrowIfFailed(device->DxDevice()->CreateCommittedResource( 13 | &prop, 14 | D3D12_HEAP_FLAG_NONE, 15 | &buffer, 16 | D3D12_RESOURCE_STATE_GENERIC_READ, 17 | nullptr, 18 | IID_PPV_ARGS(&resource))); 19 | } 20 | UploadBuffer::~UploadBuffer() { 21 | } 22 | void UploadBuffer::CopyData(uint64 offset, std::span data) const { 23 | void* mappedPtr; 24 | D3D12_RANGE range; 25 | range.Begin = offset; 26 | range.End = std::min(byteSize, offset + data.size()); 27 | ThrowIfFailed(resource->Map(0, &range, reinterpret_cast(&mappedPtr))); 28 | memcpy(reinterpret_cast(mappedPtr) + offset, data.data(), range.End - range.Begin); 29 | resource->Unmap(0, &range); 30 | } 31 | 32 | void UploadBuffer::DelayDispose(FrameResource* frameRes) const { 33 | frameRes->AddDelayDisposeResource(resource); 34 | } -------------------------------------------------------------------------------- /Chapter3/src/Resource/UploadBuffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class UploadBuffer final : public Buffer { 5 | private: 6 | ComPtr resource; 7 | uint64 byteSize; 8 | 9 | public: 10 | ID3D12Resource* GetResource() const override { return resource.Get(); } 11 | D3D12_GPU_VIRTUAL_ADDRESS GetAddress() const override { return resource->GetGPUVirtualAddress(); } 12 | uint64 GetByteSize() const override { return byteSize; } 13 | UploadBuffer( 14 | Device* device, 15 | uint64 byteSize); 16 | ~UploadBuffer(); 17 | void CopyData(uint64 offset, std::span data) const; 18 | D3D12_RESOURCE_STATES GetInitState() const override { 19 | return D3D12_RESOURCE_STATE_GENERIC_READ; 20 | } 21 | UploadBuffer(UploadBuffer&&) = default; 22 | UploadBuffer(UploadBuffer const&) = delete; 23 | void DelayDispose(FrameResource* frameRes) const override; 24 | }; 25 | 26 | -------------------------------------------------------------------------------- /Chapter3/src/Utility/Hash.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | namespace xxh { 5 | size_t xxhash_gethash(void const* ptr, size_t sz); 6 | //Size must less than 32 in x64 7 | size_t xxhash_gethash_small(void const* ptr, size_t sz); 8 | }// namespace xxh 9 | template 10 | requires(std::is_trivial_v && (!std::is_reference_v)) 11 | size_t GetHash(T const& v) { 12 | if constexpr (sizeof(T) < 32) { 13 | return xxh::xxhash_gethash_small(&v, sizeof(T)); 14 | } else { 15 | return xxh::xxhash_gethash(&v, sizeof(T)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter3/src/Utility/ReflactableStruct.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | namespace rtti { 4 | static thread_local Struct* curStruct = nullptr; 5 | size_t VarTypeData::GetSize() const { 6 | return dimension * 4; 7 | } 8 | Struct::Struct() { 9 | curStruct = this; 10 | } 11 | VarTypeBase::VarTypeBase(VarTypeData&& varData) { 12 | offset = curStruct->structSize; 13 | //A Simple parser 14 | //Split Semantic, get index 15 | if (!varData.semantic.empty()) { 16 | uint rate = 1; 17 | uint semanticIndex = 0; 18 | char const* ptr = varData.semantic.data() + varData.semantic.size() - 1; 19 | while (ptr != (varData.semantic.data() - 1)) { 20 | if (*ptr >= '0' && *ptr <= '9') { 21 | semanticIndex += rate * (int(*ptr) - int('0')); 22 | rate *= 10; 23 | } else { 24 | break; 25 | } 26 | --ptr; 27 | } 28 | auto leftSize = reinterpret_cast(ptr) - reinterpret_cast(varData.semantic.data()) + 1; 29 | varData.semantic.resize(leftSize); 30 | varData.semanticIndex = semanticIndex; 31 | } 32 | curStruct->variables.emplace_back(std::move(varData)); 33 | curStruct->structSize += varData.GetSize(); 34 | } 35 | void Struct::GetMeshLayout(uint slot, std::vector& resultVector) const { 36 | auto getFormat = [](VarTypeData const& d) -> DXGI_FORMAT { 37 | switch (d.scale) { 38 | case VarTypeData::ScaleType::Float: 39 | switch (d.dimension) { 40 | case 1: 41 | return DXGI_FORMAT_R32_FLOAT; 42 | case 2: 43 | return DXGI_FORMAT_R32G32_FLOAT; 44 | case 3: 45 | return DXGI_FORMAT_R32G32B32_FLOAT; 46 | case 4: 47 | return DXGI_FORMAT_R32G32B32A32_FLOAT; 48 | default: 49 | return DXGI_FORMAT_UNKNOWN; 50 | } 51 | case VarTypeData::ScaleType::UInt: 52 | switch (d.dimension) { 53 | case 1: 54 | return DXGI_FORMAT_R32_UINT; 55 | case 2: 56 | return DXGI_FORMAT_R32G32_UINT; 57 | case 3: 58 | return DXGI_FORMAT_R32G32B32_UINT; 59 | case 4: 60 | return DXGI_FORMAT_R32G32B32A32_UINT; 61 | default: 62 | return DXGI_FORMAT_UNKNOWN; 63 | } 64 | case VarTypeData::ScaleType::Int: 65 | switch (d.dimension) { 66 | case 1: 67 | return DXGI_FORMAT_R32_SINT; 68 | case 2: 69 | return DXGI_FORMAT_R32G32_SINT; 70 | case 3: 71 | return DXGI_FORMAT_R32G32B32_SINT; 72 | case 4: 73 | return DXGI_FORMAT_R32G32B32A32_SINT; 74 | default: 75 | return DXGI_FORMAT_UNKNOWN; 76 | } 77 | default: 78 | return DXGI_FORMAT_UNKNOWN; 79 | } 80 | }; 81 | uint offset = 0; 82 | for (size_t i = 0; i < variables.size(); ++i) { 83 | auto& result = resultVector.emplace_back(); 84 | auto& var = variables[i]; 85 | result = {var.semantic.c_str(), 86 | uint(var.semanticIndex), 87 | getFormat(var), 88 | slot, 89 | offset, 90 | D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 91 | uint(0)}; 92 | offset += var.GetSize(); 93 | } 94 | } 95 | }// namespace rtti -------------------------------------------------------------------------------- /Chapter3/src/Utility/ReflactableStruct.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | namespace rtti { 7 | //Interpret a variable's type in structure 8 | struct VarTypeData { 9 | enum class ScaleType : vbyte { 10 | Float, 11 | Int, 12 | UInt 13 | }; 14 | 15 | ScaleType scale; 16 | vbyte dimension; 17 | uint semanticIndex; 18 | std::string semantic; 19 | size_t GetSize() const; 20 | }; 21 | class VarTypeBase; 22 | class Struct { 23 | friend class VarTypeBase; 24 | std::vector variables; 25 | 26 | public: 27 | std::span Variables() const { return variables; } 28 | size_t structSize = 0; 29 | 30 | Struct(); 31 | Struct(Struct const&) = delete; 32 | Struct(Struct&&) = default; 33 | void GetMeshLayout(uint slot, std::vector& resultVector) const; 34 | }; 35 | class VarTypeBase { 36 | size_t offset; 37 | 38 | protected: 39 | VarTypeBase(VarTypeData&& varData); 40 | 41 | public: 42 | size_t Offset() const { return offset; } 43 | }; 44 | template 45 | class VarType : public VarTypeBase { 46 | protected: 47 | VarType(VarTypeData&& varData) : VarTypeBase(std::move(varData)) {} 48 | 49 | public: 50 | T const& Get(void const* structPtr) const { 51 | size_t ptrNum = reinterpret_cast(structPtr); 52 | return *reinterpret_cast(ptrNum + Offset()); 53 | } 54 | T& Get(void* structPtr) const { 55 | size_t ptrNum = reinterpret_cast(structPtr); 56 | return *reinterpret_cast(ptrNum + Offset()); 57 | } 58 | }; 59 | template 60 | struct Var {}; 61 | 62 | template<> 63 | struct Var : public VarType { 64 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Int, vbyte(1), uint(0), std::string(semantic)}) {} 65 | }; 66 | template<> 67 | struct Var : public VarType { 68 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::UInt, vbyte(1), uint(0), std::string(semantic)}) {} 69 | }; 70 | template<> 71 | struct Var : public VarType { 72 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Float, vbyte(1), uint(0), std::string(semantic)}) {} 73 | }; 74 | template<> 75 | struct Var : public VarType { 76 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Float, vbyte(2), uint(0), std::string(semantic)}) {} 77 | }; 78 | template<> 79 | struct Var : public VarType { 80 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Float, vbyte(3), uint(0), std::string(semantic)}) {} 81 | }; 82 | template<> 83 | struct Var : public VarType { 84 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Float, vbyte(4), uint(0), std::string(semantic)}) {} 85 | }; 86 | template<> 87 | struct Var : public VarType { 88 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::UInt, vbyte(2), uint(0), std::string(semantic)}) {} 89 | }; 90 | template<> 91 | struct Var : public VarType { 92 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::UInt, vbyte(3), uint(0), std::string(semantic)}) {} 93 | }; 94 | template<> 95 | struct Var : public VarType { 96 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::UInt, vbyte(4), uint(0), std::string(semantic)}) {} 97 | }; 98 | template<> 99 | struct Var : public VarType { 100 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Int, vbyte(2), uint(0), std::string(semantic)}) {} 101 | }; 102 | template<> 103 | struct Var : public VarType { 104 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Int, vbyte(3), uint(0), std::string(semantic)}) {} 105 | }; 106 | template<> 107 | struct Var : public VarType { 108 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Int, vbyte(4), uint(0), std::string(semantic)}) {} 109 | }; 110 | }// namespace rtti -------------------------------------------------------------------------------- /Chapter3/src/Win32Application.cpp: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #include "stdafx.h" 13 | #include "Win32Application.h" 14 | 15 | HWND Win32Application::m_hwnd = nullptr; 16 | 17 | int Win32Application::Run(DXSample* pSample, HINSTANCE hInstance, int nCmdShow) 18 | { 19 | // Parse the command line parameters 20 | int argc; 21 | LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc); 22 | pSample->ParseCommandLineArgs(argv, argc); 23 | LocalFree(argv); 24 | 25 | // Initialize the window class. 26 | WNDCLASSEX windowClass = { 0 }; 27 | windowClass.cbSize = sizeof(WNDCLASSEX); 28 | windowClass.style = CS_HREDRAW | CS_VREDRAW; 29 | windowClass.lpfnWndProc = WindowProc; 30 | windowClass.hInstance = hInstance; 31 | windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); 32 | windowClass.lpszClassName = L"DXSampleClass"; 33 | RegisterClassEx(&windowClass); 34 | 35 | RECT windowRect = { 0, 0, static_cast(pSample->GetWidth()), static_cast(pSample->GetHeight()) }; 36 | AdjustWindowRect(&windowRect, WS_OVERLAPPEDWINDOW, FALSE); 37 | 38 | // Create the window and store a handle to it. 39 | m_hwnd = CreateWindow( 40 | windowClass.lpszClassName, 41 | pSample->GetTitle(), 42 | WS_OVERLAPPEDWINDOW, 43 | CW_USEDEFAULT, 44 | CW_USEDEFAULT, 45 | windowRect.right - windowRect.left, 46 | windowRect.bottom - windowRect.top, 47 | nullptr, // We have no parent window. 48 | nullptr, // We aren't using menus. 49 | hInstance, 50 | pSample); 51 | 52 | // Initialize the sample. OnInit is defined in each child-implementation of DXSample. 53 | pSample->OnInit(); 54 | 55 | ShowWindow(m_hwnd, nCmdShow); 56 | 57 | // Main sample loop. 58 | MSG msg = {}; 59 | while (msg.message != WM_QUIT) 60 | { 61 | // Process any messages in the queue. 62 | if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 63 | { 64 | TranslateMessage(&msg); 65 | DispatchMessage(&msg); 66 | } 67 | } 68 | 69 | pSample->OnDestroy(); 70 | 71 | // Return this part of the WM_QUIT message to Windows. 72 | return static_cast(msg.wParam); 73 | } 74 | 75 | // Main message handler for the sample. 76 | LRESULT CALLBACK Win32Application::WindowProc(HWND hWnd, uint32_t message, WPARAM wParam, LPARAM lParam) 77 | { 78 | DXSample* pSample = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); 79 | 80 | switch (message) 81 | { 82 | case WM_CREATE: 83 | { 84 | // Save the DXSample* passed in to CreateWindow. 85 | LPCREATESTRUCT pCreateStruct = reinterpret_cast(lParam); 86 | SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast(pCreateStruct->lpCreateParams)); 87 | } 88 | return 0; 89 | 90 | case WM_KEYDOWN: 91 | if (pSample) 92 | { 93 | pSample->OnKeyDown(static_cast(wParam)); 94 | } 95 | return 0; 96 | 97 | case WM_KEYUP: 98 | if (pSample) 99 | { 100 | pSample->OnKeyUp(static_cast(wParam)); 101 | } 102 | return 0; 103 | 104 | case WM_PAINT: 105 | if (pSample) 106 | { 107 | pSample->OnUpdate(); 108 | pSample->OnRender(); 109 | } 110 | return 0; 111 | 112 | case WM_DESTROY: 113 | PostQuitMessage(0); 114 | return 0; 115 | } 116 | 117 | // Handle any messages the switch statement didn't. 118 | return DefWindowProc(hWnd, message, wParam, lParam); 119 | } 120 | -------------------------------------------------------------------------------- /Chapter3/src/Win32Application.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #pragma once 13 | 14 | #include "DXSample.h" 15 | 16 | class DXSample; 17 | 18 | class Win32Application 19 | { 20 | public: 21 | static int Run(DXSample* pSample, HINSTANCE hInstance, int nCmdShow); 22 | static HWND GetHwnd() { return m_hwnd; } 23 | 24 | protected: 25 | static LRESULT CALLBACK WindowProc(HWND hWnd, uint32_t message, WPARAM wParam, LPARAM lParam); 26 | 27 | private: 28 | static HWND m_hwnd; 29 | }; 30 | -------------------------------------------------------------------------------- /Chapter3/src/stdafx.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | // stdafx.h : include file for standard system include files, 13 | // or project specific include files that are used frequently, but 14 | // are changed infrequently. 15 | 16 | #pragma once 17 | 18 | #ifndef WIN32_LEAN_AND_MEAN 19 | #define WIN32_LEAN_AND_MEAN// Exclude rarely-used stuff from Windows headers. 20 | #endif 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "d3dx12.h" 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | -------------------------------------------------------------------------------- /Chapter3/src/xmake.lua: -------------------------------------------------------------------------------- 1 | BuildProject({ 2 | projectName = "Simple-Box", 3 | projectType = "binary", 4 | debugEvent = function() 5 | add_defines("_DEBUG") 6 | end, 7 | releaseEvent = function() 8 | add_defines("NDEBUG") 9 | end, 10 | exception = true 11 | }) 12 | add_defines("_XM_NO_INTRINSICS_=1", "NOMINMAX", "UNICODE", "m128_f32=vector4_f32", "m128_u32=vector4_u32") 13 | add_files("**.cpp") 14 | add_includedirs("./") 15 | add_syslinks("User32", "kernel32", "Gdi32", "Shell32", "DXGI", "D3D12", "D3DCompiler") 16 | after_build(function(target) 17 | src_path = "shader/" 18 | os.cp(src_path .. "*", target:targetdir() .. "/shader/") 19 | end) -------------------------------------------------------------------------------- /Chapter3/xmake.lua: -------------------------------------------------------------------------------- 1 | set_config("toolchain", "clang-cl") 2 | add_rules("mode.release", "mode.debug") 3 | option("is_clang") 4 | add_csnippets("is_clang", "return (__clang__)?0:-1;", { 5 | tryrun = true 6 | }) 7 | option_end() 8 | option("is_msvc") 9 | add_csnippets("is_msvc", "return (_MSC_VER)?0:-1;", { 10 | tryrun = true 11 | }) 12 | option_end() 13 | 14 | 15 | option_end() 16 | function GetValue(funcOrValue) 17 | if type(funcOrValue) == 'function' then 18 | return funcOrValue() 19 | else 20 | return funcOrValue 21 | end 22 | end 23 | 24 | --[[ 25 | BuildProject({ 26 | projectName = xxx, 27 | projectType = xxx, 28 | unityBuildBatch = n, 29 | exception = true/false, 30 | releaseEvent = function() 31 | end, 32 | debugEvent = function() 33 | end 34 | }) 35 | ]] 36 | if is_mode("debug") then 37 | set_targetdir("bin/debug") 38 | else 39 | set_targetdir("bin/release") 40 | end 41 | 42 | function BuildProject(config) 43 | local projectName = GetValue(config.projectName) 44 | if projectName == nil then 45 | return 46 | end 47 | target(projectName) 48 | set_languages("clatest", "cxx20") 49 | local projectType = GetValue(config.projectType) 50 | if projectType ~= nil then 51 | set_kind(projectType) 52 | end 53 | if UseUnityBuild then 54 | local unityBuildBatch = GetValue(config.unityBuildBatch) 55 | if (unityBuildBatch ~= nil) and (unityBuildBatch > 1) then 56 | add_rules("c.unity_build", { 57 | batchsize = unityBuildBatch 58 | }) 59 | add_rules("c++.unity_build", { 60 | batchsize = unityBuildBatch 61 | }) 62 | end 63 | end 64 | local value = GetValue(config.exception) 65 | if (value ~= nil) and value then 66 | if has_config("is_msvc") then 67 | add_cxflags("/EHsc") 68 | else 69 | add_cxflags("-fexceptions") 70 | end 71 | elseif not has_config("is_msvc") then 72 | add_cxflags("-fno-exceptions") 73 | end 74 | set_warnings("none") 75 | if is_mode("debug") then 76 | set_optimize("none") 77 | if is_plat("windows") then 78 | set_runtimes("MDd") 79 | end 80 | if has_config("is_msvc") then 81 | add_cxflags("/GS", "/Gd"); 82 | -- Not Clang-cl 83 | if not has_config("is_clang") then 84 | add_cxflags("/Zc:preprocessor") 85 | end 86 | end 87 | local event = GetValue(config.debugEvent) 88 | if (type(event) == "function") then 89 | event() 90 | end 91 | else 92 | set_optimize("fastest") 93 | if is_plat("windows") then 94 | set_runtimes("MD") 95 | end 96 | if has_config("is_msvc") then 97 | add_cxflags("/Oy", "/GS-", "/Gd", "/Oi", "/Ot", "/GT", "/Ob2") 98 | -- Not Clang-cl 99 | if not has_config("is_clang") then 100 | add_cxflags("/GL", "/Zc:preprocessor", "/QIntel-jcc-erratum") 101 | end 102 | end 103 | local event = GetValue(config.releaseEvent) 104 | if (type(event) == "function") then 105 | event() 106 | end 107 | end 108 | end 109 | add_subdirs("src") 110 | -------------------------------------------------------------------------------- /Chapter4/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "C_Cpp.codeAnalysis.runAutomatically": false, 3 | "C_Cpp.intelliSenseEngine": "Disabled", 4 | "C_Cpp.formatting": "Disabled", 5 | "C_Cpp.autoAddFileAssociations": false, 6 | "C_Cpp.autocompleteAddParentheses": false, 7 | "C_Cpp.autocomplete": "Disabled", 8 | "C_Cpp.errorSquiggles": "Disabled", 9 | "clangd.arguments": [ 10 | "--compile-commands-dir=.vscode", 11 | "-j=24", 12 | "--log=error", 13 | "--completion-style=bundled", 14 | "--background-index", 15 | "--header-insertion=never", 16 | "--pch-storage=memory", 17 | "--offset-encoding=utf-8" 18 | ], 19 | "editor.accessibilitySupport": "off" 20 | } -------------------------------------------------------------------------------- /Chapter4/shader/shaders.hlsl: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | struct PSInput { 13 | float4 position : SV_POSITION; 14 | float4 color : COLOR; 15 | }; 16 | cbuffer _Global : register(b0){ 17 | float4x4 _CameraWorldToViewMatrix; 18 | }; 19 | 20 | PSInput VSMain(float3 position 21 | : POSITION, float4 color 22 | : COLOR) { 23 | PSInput result; 24 | 25 | result.position = mul(_CameraWorldToViewMatrix, float4(position, 1)); 26 | result.color = color; 27 | 28 | return result; 29 | } 30 | 31 | float4 PSMain(PSInput input) : SV_TARGET { 32 | return input.color; 33 | } 34 | -------------------------------------------------------------------------------- /Chapter4/src/Component/Camera.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace DirectX; 3 | using namespace Math; 4 | Camera::Camera() { 5 | SetLens(0.25f * MathHelper::Pi, 1.0f, 1000.0f); 6 | } 7 | Camera::~Camera() { 8 | } 9 | void Camera::SetLens(float fovY, float zn, float zf) { 10 | // cache properties 11 | mFovY = fovY; 12 | mNearZ = zn; 13 | mFarZ = zf; 14 | mNearWindowHeight = 2.0f * mNearZ * tan(0.5f * mFovY); 15 | mFarWindowHeight = 2.0f * mFarZ * tan(0.5f * mFovY); 16 | } 17 | void Camera::SetAspect(float aspect) { 18 | mAspect = aspect; 19 | } 20 | 21 | void Camera::LookAt(const Math::Vector3& pos, const Math::Vector3& target, const Math::Vector3& worldUp) { 22 | Forward = normalize(target - pos); 23 | Right = normalize(cross(worldUp, Forward)); 24 | Up = cross(Forward, Right); 25 | Position = pos; 26 | } 27 | void Camera::UpdateProjectionMatrix() { 28 | if (isOrtho) { 29 | mFarZ = Max(mFarZ, mNearZ + 0.1f); 30 | Matrix4 P = XMMatrixOrthographicLH(orthoSize, orthoSize, mNearZ, mFarZ); 31 | Proj = P; 32 | } else { 33 | mNearZ = Max(mNearZ, 0.01f); 34 | mFarZ = Max(mFarZ, mNearZ + 0.1f); 35 | Matrix4 P = XMMatrixPerspectiveFovLH(mFovY, mAspect, mNearZ, mFarZ); 36 | Proj = P; 37 | } 38 | } 39 | void Camera::UpdateViewMatrix() { 40 | View = GetInverseTransformMatrix(Right, Up, Forward, Position); 41 | } 42 | -------------------------------------------------------------------------------- /Chapter4/src/Component/Camera.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | class Camera final { 6 | public: 7 | ~Camera(); 8 | Camera(); 9 | // frustum properties. 10 | float NearZ() const { return mNearZ; } 11 | float FarZ() const { return mFarZ; } 12 | float Aspect() const { return mAspect; } 13 | float FovY() const { return mFovY; } 14 | float FovX() const { 15 | float halfWidth = 0.5 * NearWindowWidth(); 16 | return 2.0 * atan(halfWidth / mNearZ); 17 | } 18 | 19 | // near and far plane dimensions in view space coordinates. 20 | float NearWindowWidth() const { return mAspect * mNearWindowHeight; } 21 | float NearWindowHeight() const { return mNearWindowHeight; } 22 | float FarWindowWidth() const { return mAspect * mFarWindowHeight; } 23 | float FarWindowHeight() const { return mFarWindowHeight; } 24 | 25 | // Set frustum. 26 | void SetLens(float fovY, float zn, float zf); 27 | void SetAspect(float aspect); 28 | // Define camera space via LookAt parameters. 29 | void LookAt(const Math::Vector3& pos, const Math::Vector3& target, const Math::Vector3& worldUp); 30 | void UpdateViewMatrix(); 31 | void UpdateProjectionMatrix(); 32 | Math::Matrix4 View = MathHelper::Identity4x4(); 33 | Math::Matrix4 Proj = MathHelper::Identity4x4(); 34 | Math::Vector3 Position = {0.0f, 0.0f, 0.0f}; 35 | Math::Vector3 Right = {1.0f, 0.0f, 0.0f}; 36 | Math::Vector3 Up = {0.0f, 1.0f, 0.0f}; 37 | Math::Vector3 Forward = {0.0f, 0.0f, 1.0f}; 38 | float orthoSize = 5; 39 | bool isOrtho = false; 40 | 41 | private: 42 | float mNearZ = 0.0f; 43 | float mFarZ = 0.0f; 44 | float mAspect = 1.0f; 45 | float mFovY = 0.0f; 46 | float mNearWindowHeight = 0.0f; 47 | float mFarWindowHeight = 0.0f; 48 | 49 | }; 50 | -------------------------------------------------------------------------------- /Chapter4/src/D3D12BetterSimpleBox.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | //0 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #pragma once 13 | 14 | #include "DXSample.h" 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | using namespace DirectX; 22 | // Note that while ComPtr is used to manage the lifetime of resources on the CPU, 23 | // it has no understanding of the lifetime of resources on the GPU. Apps must account 24 | // for the GPU lifetime of resources to avoid destroying objects that may still be 25 | // referenced by the GPU. 26 | // An example of this can be found in the class method: OnDestroy(). 27 | using Microsoft::WRL::ComPtr; 28 | class FrameResource; 29 | class Camera; 30 | class PSOManager; 31 | class RasterShader; 32 | class CommandListHandle; 33 | class DefaultBuffer; 34 | struct Vertex : public rtti::Struct { 35 | rtti::Var position = "POSITION"; 36 | rtti::Var color = "COLOR"; 37 | }; 38 | class D3D12BetterSimpleBox : public DXSample { 39 | public: 40 | D3D12BetterSimpleBox(uint32_t width, uint32_t height, std::wstring name); 41 | D3D12BetterSimpleBox(D3D12BetterSimpleBox const&) = delete; 42 | D3D12BetterSimpleBox(D3D12BetterSimpleBox&&) = delete; 43 | void OnInit() override; 44 | void OnUpdate() override; 45 | void OnRender() override; 46 | void OnDestroy() override; 47 | ~D3D12BetterSimpleBox(); 48 | 49 | private: 50 | static const uint32_t FrameCount = 3; 51 | std::unique_ptr device; 52 | std::unique_ptr mainCamera; 53 | // Pipeline objects. 54 | CD3DX12_VIEWPORT m_viewport; 55 | CD3DX12_RECT m_scissorRect; 56 | ComPtr m_swapChain; 57 | std::unique_ptr m_renderTargets[FrameCount]; 58 | std::unique_ptr m_depthTargets[FrameCount]; 59 | ComPtr m_commandQueue; 60 | ComPtr m_rtvHeap; 61 | ComPtr m_dsvHeap; 62 | std::unique_ptr psoManager; 63 | std::unique_ptr colorShader; 64 | uint32_t m_rtvDescriptorSize; 65 | uint32_t m_dsvDescriptorSize; 66 | std::unique_ptr frameResources[FrameCount]; 67 | ResourceStateTracker stateTracker; 68 | // App resources. 69 | std::unique_ptr triangleMesh; 70 | // Synchronization objects. 71 | uint32_t m_backBufferIndex; 72 | ComPtr m_fence; 73 | uint64_t m_fenceValue; 74 | std::vector bindProperties; 75 | void LoadPipeline(); 76 | void LoadAssets(); 77 | void PopulateCommandList(FrameResource& frameRes, uint frameIndex); 78 | }; 79 | -------------------------------------------------------------------------------- /Chapter4/src/DXMath/MathHelper.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace DirectX; 5 | const float MathHelper::Infinity = FLT_MAX; 6 | const float MathHelper::Pi = 3.1415926535f; 7 | float MathHelper::AngleFromXY(float x, float y) { 8 | float theta = 0.0f; 9 | 10 | // Quadrant I or IV 11 | if (x >= 0.0f) { 12 | // If x = 0, then atanf(y/x) = +pi/2 if y > 0 13 | // atanf(y/x) = -pi/2 if y < 0 14 | theta = atanf(y / x);// in [-pi/2, +pi/2] 15 | if (theta < 0.0f) 16 | theta += 2.0f * Pi;// in [0, 2*pi). 17 | } 18 | // Quadrant II or III 19 | else 20 | theta = atanf(y / x) + Pi;// in [0, 2*pi). 21 | return theta; 22 | } 23 | XMVECTOR MathHelper::RandUnitVec3() { 24 | XMVECTOR One = XMVectorSet(1.0f, 1.0f, 1.0f, 1.0f); 25 | XMVECTOR Zero = XMVectorZero(); 26 | // Keep trying until we get a point on/in the hemisphere. 27 | while (true) { 28 | // Generate random point in the cube [-1,1]^3. 29 | XMVECTOR v = XMVectorSet(MathHelper::RandF(-1.0f, 1.0f), MathHelper::RandF(-1.0f, 1.0f), MathHelper::RandF(-1.0f, 1.0f), 0.0f); 30 | // Ignore points outside the unit sphere in order to get an even distribution 31 | // over the unit sphere. Otherwise points will clump more on the sphere near 32 | // the corners of the cube. 33 | if (XMVector3Greater(XMVector3LengthSq(v), One)) 34 | continue; 35 | return XMVector3Normalize(v); 36 | } 37 | } 38 | XMVECTOR MathHelper::RandHemisphereUnitVec3(XMVECTOR n) { 39 | XMVECTOR One = XMVectorSet(1.0f, 1.0f, 1.0f, 1.0f); 40 | XMVECTOR Zero = XMVectorZero(); 41 | // Keep trying until we get a point on/in the hemisphere. 42 | while (true) { 43 | // Generate random point in the cube [-1,1]^3. 44 | XMVECTOR v = XMVectorSet(MathHelper::RandF(-1.0f, 1.0f), MathHelper::RandF(-1.0f, 1.0f), MathHelper::RandF(-1.0f, 1.0f), 0.0f); 45 | // Ignore points outside the unit sphere in order to get an even distribution 46 | // over the unit sphere. Otherwise points will clump more on the sphere near 47 | // the corners of the cube. 48 | 49 | if (XMVector3Greater(XMVector3LengthSq(v), One)) 50 | continue; 51 | // Ignore points in the bottom hemisphere. 52 | if (XMVector3Less(XMVector3Dot(n, v), Zero)) 53 | continue; 54 | return XMVector3Normalize(v); 55 | } 56 | } 57 | 58 | DirectX::XMVECTOR MathHelper::SphericalToCartesian(float radius, float theta, float phi) { 59 | return DirectX::XMVectorSet( 60 | radius * sinf(phi) * cosf(theta), 61 | radius * cosf(phi), 62 | radius * sinf(phi) * sinf(theta), 63 | 1.0f); 64 | } 65 | 66 | DirectX::XMMATRIX MathHelper::InverseTranspose(DirectX::CXMMATRIX M) { 67 | // Inverse-transpose is just applied to normals. So zero out 68 | // translation row so that it doesn't get into our inverse-transpose 69 | // calculation--we don't want the inverse-transpose of the translation. 70 | DirectX::XMMATRIX A = M; 71 | A.r[3] = DirectX::XMVectorSet(0.0f, 0.0f, 0.0f, 1.0f); 72 | 73 | DirectX::XMVECTOR det = DirectX::XMMatrixDeterminant(A); 74 | return DirectX::XMMatrixTranspose(DirectX::XMMatrixInverse(&det, A)); 75 | } 76 | 77 | float4x4 MathHelper::Identity4x4() { 78 | static float4x4 I( 79 | 1.0f, 0.0f, 0.0f, 0.0f, 80 | 0.0f, 1.0f, 0.0f, 0.0f, 81 | 0.0f, 0.0f, 1.0f, 0.0f, 82 | 0.0f, 0.0f, 0.0f, 1.0f); 83 | 84 | return I; 85 | } -------------------------------------------------------------------------------- /Chapter4/src/DXMath/MathHelper.h: -------------------------------------------------------------------------------- 1 | //*************************************************************************************** 2 | // MathHelper.h by Frank Luna (C) 2011 All Rights Reserved. 3 | // 4 | // Helper math class. 5 | //*************************************************************************************** 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | class MathHelper { 13 | public: 14 | // Returns random float in [0, 1). 15 | static float RandF() { 16 | return (float)(rand()) / (float)RAND_MAX; 17 | } 18 | 19 | // Returns random float in [a, b). 20 | static float RandF(float a, float b) { 21 | return a + RandF() * (b - a); 22 | } 23 | 24 | static int32_t Rand(int32_t a, int32_t b) { 25 | return a + rand() % ((b - a) + 1); 26 | } 27 | 28 | template 29 | static T Min(const T& a, const T& b) { 30 | return a < b ? a : b; 31 | } 32 | 33 | template 34 | static T Max(const T& a, const T& b) { 35 | return a > b ? a : b; 36 | } 37 | 38 | template 39 | static T Lerp(const T& a, const T& b, float t) { 40 | return a + (b - a) * t; 41 | } 42 | 43 | template 44 | static T Clamp(const T& x, const T& low, const T& high) { 45 | return x < low ? low : (x > high ? high : x); 46 | } 47 | 48 | // Returns the polar angle of the point (x,y) in [0, 2*PI). 49 | static float AngleFromXY(float x, float y); 50 | 51 | static DirectX::XMVECTOR SphericalToCartesian(float radius, float theta, float phi); 52 | 53 | static DirectX::XMMATRIX InverseTranspose(DirectX::CXMMATRIX M); 54 | 55 | static float4x4 Identity4x4(); 56 | 57 | static DirectX::XMVECTOR RandUnitVec3(); 58 | static DirectX::XMVECTOR RandHemisphereUnitVec3(DirectX::XMVECTOR n); 59 | 60 | static const float Infinity; 61 | static const float Pi; 62 | }; 63 | -------------------------------------------------------------------------------- /Chapter4/src/DXMath/Matrix3.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Microsoft. All rights reserved. 3 | // This code is licensed under the MIT License (MIT). 4 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 5 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 6 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 7 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 8 | // 9 | // Developed by Minigraph 10 | // 11 | // Author: James Stanard 12 | // 13 | 14 | #pragma once 15 | 16 | #include 17 | 18 | namespace Math { 19 | // Represents a 3x3 matrix while occuping a 4x4 memory footprint. The unused row and column are undefined but implicitly 20 | // (0, 0, 0, 1). Constructing a Matrix4 will make those values explicit. 21 | class alignas(16) Matrix3 { 22 | public: 23 | INLINE XM_CALLCONV Matrix3() {} 24 | INLINE XM_CALLCONV Matrix3(const Vector3& x, const Vector3& y, const Vector3& z) { 25 | m_mat[0] = x; 26 | m_mat[1] = y; 27 | m_mat[2] = z; 28 | } 29 | INLINE XM_CALLCONV Matrix3(const Matrix3& m) { 30 | m_mat[0] = m.m_mat[0]; 31 | m_mat[1] = m.m_mat[1]; 32 | m_mat[2] = m.m_mat[2]; 33 | } 34 | INLINE XM_CALLCONV Matrix3(Quaternion q) { *this = Matrix3(XMMatrixRotationQuaternion(q)); } 35 | INLINE explicit XM_CALLCONV Matrix3(const XMMATRIX& m) { 36 | m_mat[0] = Vector3(m.r[0]); 37 | m_mat[1] = Vector3(m.r[1]); 38 | m_mat[2] = Vector3(m.r[2]); 39 | } 40 | INLINE explicit XM_CALLCONV Matrix3(EIdentityTag) { 41 | m_mat[0] = Vector3(kXUnitVector); 42 | m_mat[1] = Vector3(kYUnitVector); 43 | m_mat[2] = Vector3(kZUnitVector); 44 | } 45 | INLINE explicit XM_CALLCONV Matrix3(EZeroTag) { m_mat[0] = m_mat[1] = m_mat[2] = Vector3(kZero); } 46 | 47 | INLINE void XM_CALLCONV SetX(const Vector3& x) { m_mat[0] = x; } 48 | INLINE void XM_CALLCONV SetY(const Vector3& y) { m_mat[1] = y; } 49 | INLINE void XM_CALLCONV SetZ(const Vector3& z) { m_mat[2] = z; } 50 | 51 | INLINE Vector3 XM_CALLCONV GetX() const { return m_mat[0]; } 52 | INLINE Vector3 XM_CALLCONV GetY() const { return m_mat[1]; } 53 | INLINE Vector3 XM_CALLCONV GetZ() const { return m_mat[2]; } 54 | 55 | static INLINE Matrix3 XM_CALLCONV MakeXRotation(float angle) { return Matrix3(XMMatrixRotationX(angle)); } 56 | static INLINE Matrix3 XM_CALLCONV MakeYRotation(float angle) { return Matrix3(XMMatrixRotationY(angle)); } 57 | static INLINE Matrix3 XM_CALLCONV MakeZRotation(float angle) { return Matrix3(XMMatrixRotationZ(angle)); } 58 | static INLINE Matrix3 XM_CALLCONV MakeScale(float scale) { return Matrix3(XMMatrixScaling(scale, scale, scale)); } 59 | static INLINE Matrix3 XM_CALLCONV MakeScale(float sx, float sy, float sz) { return Matrix3(XMMatrixScaling(sx, sy, sz)); } 60 | static INLINE Matrix3 XM_CALLCONV MakeScale(const Vector3& scale) { return Matrix3(XMMatrixScalingFromVector(scale)); } 61 | 62 | INLINE XM_CALLCONV operator XMMATRIX&() const { return (XMMATRIX&)m_mat[0]; } 63 | INLINE XMVECTOR& XM_CALLCONV operator[](uint i) { 64 | return m_mat[i].m_vec; 65 | } 66 | INLINE const XMVECTOR& XM_CALLCONV operator[](uint i) const { 67 | return m_mat[i].m_vec; 68 | } 69 | INLINE Vector3 XM_CALLCONV operator*(Vector3 vec) const { return Vector3(XMVector3TransformNormal(vec, *this)); } 70 | INLINE Matrix3 XM_CALLCONV operator*(const Matrix3& mat) const { return Matrix3(*this * mat.GetX(), *this * mat.GetY(), *this * mat.GetZ()); } 71 | 72 | private: 73 | Vector3 m_mat[3]; 74 | }; 75 | 76 | }// namespace Math -------------------------------------------------------------------------------- /Chapter4/src/DXMath/Matrix4.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Microsoft. All rights reserved. 3 | // This code is licensed under the MIT License (MIT). 4 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 5 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 6 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 7 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 8 | // 9 | // Developed by Minigraph 10 | // 11 | // Author: James Stanard 12 | // 13 | 14 | #pragma once 15 | 16 | #include 17 | namespace Math 18 | { 19 | class alignas(16) Matrix4 20 | { 21 | public: 22 | INLINE XM_CALLCONV Matrix4() {} 23 | INLINE XM_CALLCONV Matrix4(const Vector3& x, const Vector3& y, const Vector3& z, const Vector3& w) 24 | { 25 | m_mat.r[0] = SetWToZero(x); m_mat.r[1] = SetWToZero(y); 26 | m_mat.r[2] = SetWToZero(z); m_mat.r[3] = SetWToOne(w); 27 | } 28 | INLINE XM_CALLCONV Matrix4(const Vector4& x, const Vector4& y, const Vector4& z, const Vector4& w) { m_mat.r[0] = x; m_mat.r[1] = y; m_mat.r[2] = z; m_mat.r[3] = w; } 29 | INLINE XM_CALLCONV Matrix4(const Matrix4& mat) : m_mat(mat.m_mat) { } 30 | INLINE XM_CALLCONV Matrix4(const Matrix3& mat) 31 | { 32 | m_mat.r[0] = SetWToZero(mat.GetX()); 33 | m_mat.r[1] = SetWToZero(mat.GetY()); 34 | m_mat.r[2] = SetWToZero(mat.GetZ()); 35 | m_mat.r[3] = CreateWUnitVector(); 36 | } 37 | INLINE XM_CALLCONV Matrix4(const XMMATRIX& mat) : m_mat(mat) {} 38 | INLINE XM_CALLCONV Matrix4(const Matrix3& xyz, const Vector3& w) 39 | { 40 | m_mat.r[0] = SetWToZero(xyz.GetX()); 41 | m_mat.r[1] = SetWToZero(xyz.GetY()); 42 | m_mat.r[2] = SetWToZero(xyz.GetZ()); 43 | m_mat.r[3] = SetWToOne(w); 44 | } 45 | INLINE XM_CALLCONV Matrix4(EIdentityTag) { m_mat = XMMatrixIdentity(); } 46 | INLINE XM_CALLCONV Matrix4(EZeroTag) { m_mat.r[0] = m_mat.r[1] = m_mat.r[2] = m_mat.r[3] = SplatZero(); } 47 | INLINE XM_CALLCONV Matrix4(const float4x4& f) 48 | { 49 | m_mat = XMLoadFloat4x4(&f); 50 | } 51 | 52 | INLINE XM_CALLCONV operator float4x4() const 53 | { 54 | float4x4 f; 55 | XMStoreFloat4x4(&f, m_mat); 56 | return f; 57 | } 58 | 59 | INLINE const Matrix3& XM_CALLCONV Get3x3() const { return (const Matrix3&)*this; } 60 | 61 | INLINE Vector4 XM_CALLCONV GetX() const { return Vector4(m_mat.r[0]); } 62 | INLINE Vector4 XM_CALLCONV GetY() const { return Vector4(m_mat.r[1]); } 63 | INLINE Vector4 XM_CALLCONV GetZ() const { return Vector4(m_mat.r[2]); } 64 | INLINE Vector4 XM_CALLCONV GetW() const { return Vector4(m_mat.r[3]); } 65 | 66 | INLINE void XM_CALLCONV SetX(const Vector4& x) { m_mat.r[0] = x; } 67 | INLINE void XM_CALLCONV SetY(const Vector4& y) { m_mat.r[1] = y; } 68 | INLINE void XM_CALLCONV SetZ(const Vector4& z) { m_mat.r[2] = z; } 69 | INLINE void XM_CALLCONV SetW(const Vector4& w) { m_mat.r[3] = w; } 70 | 71 | INLINE XM_CALLCONV operator XMMATRIX& () const { return (XMMATRIX&)m_mat; } 72 | INLINE XMVECTOR& XM_CALLCONV operator[] (uint i) 73 | { 74 | return m_mat.r[i]; 75 | } 76 | INLINE const XMVECTOR& XM_CALLCONV operator[] (uint i) const 77 | { 78 | return m_mat.r[i]; 79 | } 80 | 81 | INLINE Vector4 XM_CALLCONV operator* (const Vector3& vec) const { return Vector4(XMVector3Transform(vec, m_mat)); } 82 | INLINE Vector4 XM_CALLCONV operator* (const Vector4& vec) const { return Vector4(XMVector4Transform(vec, m_mat)); } 83 | INLINE Matrix4 XM_CALLCONV operator* (const Matrix4& mat) const { return Matrix4(XMMatrixMultiply(mat, m_mat)); } 84 | 85 | static INLINE Matrix4 XM_CALLCONV MakeScale(float scale) { return Matrix4(XMMatrixScaling(scale, scale, scale)); } 86 | static INLINE Matrix4 XM_CALLCONV MakeScale(const Vector3& scale) { return Matrix4(XMMatrixScalingFromVector(scale)); } 87 | 88 | 89 | private: 90 | XMMATRIX m_mat; 91 | }; 92 | } -------------------------------------------------------------------------------- /Chapter4/src/DXMath/Quaternion.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Microsoft. All rights reserved. 3 | // This code is licensed under the MIT License (MIT). 4 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 5 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 6 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 7 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 8 | // 9 | // Developed by Minigraph 10 | // 11 | // Author: James Stanard 12 | // 13 | 14 | #pragma once 15 | 16 | #include 17 | 18 | namespace Math { 19 | class alignas(16) Quaternion { 20 | public: 21 | INLINE XM_CALLCONV Quaternion() { m_vec = XMQuaternionIdentity(); } 22 | INLINE XM_CALLCONV Quaternion(const Vector3& axis, const Scalar& angle) { m_vec = XMQuaternionRotationAxis(axis, angle); } 23 | INLINE XM_CALLCONV Quaternion(float pitch, float yaw, float roll) { m_vec = XMQuaternionRotationRollPitchYaw(pitch, yaw, roll); } 24 | INLINE explicit XM_CALLCONV Quaternion(const XMMATRIX& matrix) { m_vec = XMQuaternionRotationMatrix(matrix); } 25 | INLINE explicit XM_CALLCONV Quaternion(FXMVECTOR vec) { m_vec = vec; } 26 | INLINE explicit XM_CALLCONV Quaternion(EIdentityTag) { m_vec = XMQuaternionIdentity(); } 27 | 28 | INLINE XM_CALLCONV operator XMVECTOR() const { return m_vec; } 29 | 30 | INLINE Quaternion XM_CALLCONV operator~(void) const { return Quaternion(XMQuaternionConjugate(m_vec)); } 31 | INLINE Quaternion XM_CALLCONV operator-(void) const { return Quaternion(XMVectorNegate(m_vec)); } 32 | 33 | INLINE Quaternion XM_CALLCONV operator*(Quaternion rhs) const { return Quaternion(XMQuaternionMultiply(rhs, m_vec)); } 34 | INLINE Vector3 XM_CALLCONV operator*(Vector3 rhs) const { return Vector3(XMVector3Rotate(rhs, m_vec)); } 35 | 36 | INLINE Quaternion& XM_CALLCONV operator=(Quaternion rhs) { 37 | m_vec = rhs; 38 | return *this; 39 | } 40 | INLINE Quaternion& XM_CALLCONV operator*=(Quaternion rhs) { 41 | *this = *this * rhs; 42 | return *this; 43 | } 44 | 45 | protected: 46 | XMVECTOR m_vec; 47 | }; 48 | 49 | }// namespace Math -------------------------------------------------------------------------------- /Chapter4/src/DXMath/Scalar.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Microsoft. All rights reserved. 3 | // This code is licensed under the MIT License (MIT). 4 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 5 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 6 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 7 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 8 | // 9 | // Developed by Minigraph 10 | // 11 | // Author: James Stanard 12 | // 13 | 14 | #pragma once 15 | 16 | #include 17 | 18 | namespace Math 19 | { 20 | class Scalar 21 | { 22 | public: 23 | INLINE XM_CALLCONV Scalar() {} 24 | INLINE XM_CALLCONV Scalar(const Scalar& s) { m_vec = s; } 25 | INLINE XM_CALLCONV Scalar(float f) { m_vec = XMVectorReplicate(f); } 26 | INLINE explicit XM_CALLCONV Scalar(const FXMVECTOR& vec) { m_vec = vec; } 27 | 28 | INLINE XM_CALLCONV operator const XMVECTOR&() const { return m_vec; } 29 | INLINE XM_CALLCONV operator float() const { return XMVectorGetX(m_vec); } 30 | 31 | private: 32 | XMVECTOR m_vec; 33 | }; 34 | 35 | INLINE Scalar XM_CALLCONV operator- (const Scalar& s) { return Scalar(XMVectorNegate(s)); } 36 | INLINE Scalar XM_CALLCONV operator+ (const Scalar& s1, const Scalar& s2) { return Scalar(XMVectorAdd(s1, s2)); } 37 | INLINE Scalar XM_CALLCONV operator- (const Scalar& s1, const Scalar& s2) { return Scalar(XMVectorSubtract(s1, s2)); } 38 | INLINE Scalar XM_CALLCONV operator* (const Scalar& s1, const Scalar& s2) { return Scalar(XMVectorMultiply(s1, s2)); } 39 | INLINE Scalar XM_CALLCONV operator/ (const Scalar& s1, const Scalar& s2) { return Scalar(XMVectorDivide(s1, s2)); } 40 | INLINE Scalar XM_CALLCONV operator+ (const Scalar& s1, float s2) { return s1 + Scalar(s2); } 41 | INLINE Scalar XM_CALLCONV operator- (const Scalar& s1, float s2) { return s1 - Scalar(s2); } 42 | INLINE Scalar XM_CALLCONV operator* (const Scalar& s1, float s2) { return s1 * Scalar(s2); } 43 | INLINE Scalar XM_CALLCONV operator/ (const Scalar& s1, float s2) { return s1 / Scalar(s2); } 44 | INLINE Scalar XM_CALLCONV operator+ (float s1, const Scalar& s2) { return Scalar(s1) + s2; } 45 | INLINE Scalar XM_CALLCONV operator- (float s1, const Scalar& s2) { return Scalar(s1) - s2; } 46 | INLINE Scalar XM_CALLCONV operator* (float s1, const Scalar& s2) { return Scalar(s1) * s2; } 47 | INLINE Scalar XM_CALLCONV operator/ (float s1, const Scalar& s2) { return Scalar(s1) / s2; } 48 | 49 | } // namespace Math -------------------------------------------------------------------------------- /Chapter4/src/DXMath/Swizzle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | template 5 | struct Swizzle; 6 | 7 | template 8 | struct Swizzle { 9 | inline operator target_type() const { 10 | const base_type* self = reinterpret_cast(this); 11 | base_type pad[sizeof...(sequence)] = {self[sequence]...}; 12 | return *reinterpret_cast(pad); 13 | } 14 | 15 | inline target_type operator=(target_type rhs) { 16 | base_type* self = reinterpret_cast(this); 17 | base_type* prhs = reinterpret_cast(&rhs); 18 | 19 | assign(self, prhs, std::make_index_sequence()); 20 | 21 | return *reinterpret_cast(this); 22 | } 23 | 24 | private: 25 | template 26 | inline void assign(base_type* self, base_type* rhs, std::index_sequence seq) { 27 | base_type tmp[] = {self[sequence] = rhs[indices]...}; 28 | } 29 | }; 30 | template 31 | struct Swizzle { 32 | inline operator target_type() const { 33 | const base_type* self = reinterpret_cast(this); 34 | base_type pad[sizeof...(sequence)] = {self[sequence]...}; 35 | return *reinterpret_cast(pad); 36 | } 37 | 38 | private: 39 | template 40 | inline void assign(base_type* self, base_type* rhs, std::index_sequence seq) { 41 | base_type tmp[] = {self[sequence] = rhs[indices]...}; 42 | } 43 | }; -------------------------------------------------------------------------------- /Chapter4/src/DXRuntime/BindProperty.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | struct BindProperty { 7 | std::string name; 8 | std::variant< 9 | BufferView, 10 | DescriptorHeapView> 11 | prop; 12 | BindProperty() {} 13 | template 14 | requires( 15 | std::is_constructible_v || std::is_constructible_v) 16 | BindProperty( 17 | A&& a, 18 | B&& b) 19 | : name(std::forward(a)), 20 | prop(std::forward(b)) {} 21 | }; -------------------------------------------------------------------------------- /Chapter4/src/DXRuntime/CommandListHandle.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | CommandListHandle::CommandListHandle(CommandListHandle&& v) 4 | : cmdList(v.cmdList) { 5 | v.cmdList = nullptr; 6 | } 7 | CommandListHandle::CommandListHandle( 8 | ID3D12CommandAllocator* allocator, 9 | ID3D12GraphicsCommandList* cmdList) 10 | : cmdList(cmdList) { 11 | ThrowIfFailed(allocator->Reset()); 12 | ThrowIfFailed(cmdList->Reset(allocator, nullptr)); 13 | } 14 | CommandListHandle::~CommandListHandle() { 15 | if (cmdList) 16 | cmdList->Close(); 17 | } 18 | -------------------------------------------------------------------------------- /Chapter4/src/DXRuntime/CommandListHandle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | class CommandListHandle { 4 | ID3D12GraphicsCommandList* cmdList; 5 | 6 | public: 7 | ID3D12GraphicsCommandList* CmdList() const { return cmdList; } 8 | CommandListHandle(CommandListHandle const&) = delete; 9 | CommandListHandle(CommandListHandle&&); 10 | CommandListHandle( 11 | ID3D12CommandAllocator* allocator, 12 | ID3D12GraphicsCommandList* cmdList); 13 | ~CommandListHandle(); 14 | }; -------------------------------------------------------------------------------- /Chapter4/src/DXRuntime/Device.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | Device::~Device() { 5 | } 6 | 7 | Device::Device() { 8 | using Microsoft::WRL::ComPtr; 9 | uint32_t dxgiFactoryFlags = 0; 10 | 11 | #if defined(_DEBUG) 12 | // Enable the debug layer (requires the Graphics Tools "optional feature"). 13 | // NOTE: Enabling the debug layer after device creation will invalidate the active device. 14 | { 15 | ComPtr debugController; 16 | if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) { 17 | debugController->EnableDebugLayer(); 18 | 19 | // Enable additional debug layers. 20 | dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG; 21 | } 22 | } 23 | #endif 24 | ThrowIfFailed(CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&dxgiFactory))); 25 | uint adapterIndex = 0; // we'll start looking for directx 12 compatible graphics devices starting at index 0 26 | bool adapterFound = false;// set this to true when a good one was found 27 | while (dxgiFactory->EnumAdapters1(adapterIndex, &adapter) != DXGI_ERROR_NOT_FOUND) { 28 | DXGI_ADAPTER_DESC1 desc; 29 | adapter->GetDesc1(&desc); 30 | if ((desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) == 0) { 31 | HRESULT hr = D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_12_1, 32 | IID_PPV_ARGS(&dxDevice)); 33 | if (SUCCEEDED(hr)) { 34 | adapterFound = true; 35 | break; 36 | } 37 | } 38 | adapter = nullptr; 39 | adapterIndex++; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Chapter4/src/DXRuntime/Device.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | class Device { 4 | Microsoft::WRL::ComPtr adapter; 5 | Microsoft::WRL::ComPtr dxDevice; 6 | Microsoft::WRL::ComPtr dxgiFactory; 7 | 8 | public: 9 | IDXGIAdapter1* Adapter() const { return adapter.Get(); } 10 | ID3D12Device5* DxDevice() const { return dxDevice.Get(); } 11 | IDXGIFactory4* DxgiFactory() const { return dxgiFactory.Get(); } 12 | Device(); 13 | ~Device(); 14 | }; 15 | -------------------------------------------------------------------------------- /Chapter4/src/DXRuntime/FrameResource.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | using Microsoft::WRL::ComPtr; 12 | class Texture; 13 | class Mesh; 14 | class PSOManager; 15 | class RasterShader; 16 | class FrameResource { 17 | ComPtr cmdAllocator; 18 | ComPtr cmdList; 19 | std::vector> delayDisposeResources; 20 | std::vector> afterSyncEvents; 21 | uint64 lastFenceIndex = 0; 22 | bool populated = false; 23 | static constexpr size_t TEMP_SIZE = 1024ull * 1024ull; 24 | template 25 | class Visitor : public IStackAllocVisitor { 26 | public: 27 | FrameResource* self; 28 | uint64 Allocate(uint64 size) override; 29 | void DeAllocate(uint64 handle) override; 30 | }; 31 | Visitor tempUBVisitor; 32 | Visitor tempVisitor; 33 | Visitor tempRBVisitor; 34 | StackAllocator ubAlloc; 35 | StackAllocator rbAlloc; 36 | StackAllocator dbAlloc; 37 | Device* device; 38 | std::vector vertexBufferView; 39 | BufferView GetTempBuffer(size_t size, size_t align, StackAllocator& alloc); 40 | 41 | 42 | public: 43 | CommandListHandle Command(); 44 | FrameResource(Device* device); 45 | ~FrameResource(); 46 | void AddDelayDisposeResource(ComPtr const& ptr); 47 | void Execute( 48 | ID3D12CommandQueue* queue, 49 | ID3D12Fence* fence, 50 | uint64& fenceIndex); 51 | void Signal( 52 | ID3D12CommandQueue* queue, 53 | ID3D12Fence* fence); 54 | void Sync( 55 | ID3D12Fence* fence); 56 | void Upload(BufferView const& buffer, void const* src); 57 | void Download(BufferView const& buffer, void* dst); 58 | BufferView AllocateConstBuffer(std::span data); 59 | void CopyBuffer( 60 | Buffer const* src, 61 | Buffer const* dst, 62 | uint64 srcOffset, 63 | uint64 dstOffset, 64 | uint64 byteSize); 65 | void SetRenderTarget( 66 | Texture const* tex, 67 | CD3DX12_CPU_DESCRIPTOR_HANDLE const* rtvHandle, 68 | CD3DX12_CPU_DESCRIPTOR_HANDLE const* dsvHandle = nullptr); 69 | void ClearRTV(CD3DX12_CPU_DESCRIPTOR_HANDLE const& rtv); 70 | void ClearDSV(CD3DX12_CPU_DESCRIPTOR_HANDLE const& dsv); 71 | void DrawMesh( 72 | RasterShader const* shader, 73 | PSOManager* psoManager, 74 | Mesh* mesh, 75 | DXGI_FORMAT colorFormat, 76 | DXGI_FORMAT depthFormat, 77 | std::span properties); 78 | }; 79 | -------------------------------------------------------------------------------- /Chapter4/src/DXRuntime/ResourceStateTracker.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | namespace detail { 4 | static bool IsWriteState(D3D12_RESOURCE_STATES state) { 5 | switch (state) { 6 | case D3D12_RESOURCE_STATE_UNORDERED_ACCESS: 7 | case D3D12_RESOURCE_STATE_COPY_DEST: 8 | return true; 9 | default: 10 | return false; 11 | } 12 | } 13 | }// namespace detail 14 | ResourceStateTracker::ResourceStateTracker() { 15 | } 16 | ResourceStateTracker::~ResourceStateTracker() = default; 17 | void ResourceStateTracker::RecordState(Resource const* resource, D3D12_RESOURCE_STATES state) { 18 | auto initState = resource->GetInitState(); 19 | auto ite = stateMap.try_emplace(resource); 20 | bool isWrite = detail::IsWriteState(state); 21 | if (ite.second) { 22 | if (isWrite) { 23 | writeStateMap.emplace(resource); 24 | } 25 | ite.first->second = State{ 26 | .lastState = initState, 27 | .curState = state, 28 | .uavBarrier = (state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS && initState == state), 29 | .isWrite = isWrite}; 30 | } else { 31 | auto&& st = ite.first->second; 32 | st.uavBarrier = (state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS && st.lastState == state); 33 | st.curState = state; 34 | if (isWrite != st.isWrite) { 35 | st.isWrite = isWrite; 36 | MarkWritable(resource, isWrite); 37 | } 38 | } 39 | } 40 | void ResourceStateTracker::RecordState(Resource const* resource) { 41 | RecordState(resource, resource->GetInitState()); 42 | } 43 | void ResourceStateTracker::ExecuteStateMap() { 44 | for (auto&& i : stateMap) { 45 | if (i.second.uavBarrier) { 46 | D3D12_RESOURCE_BARRIER& uavBarrier = states.emplace_back(); 47 | uavBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; 48 | uavBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; 49 | uavBarrier.UAV.pResource = i.first->GetResource(); 50 | i.second.uavBarrier = false; 51 | } else if (i.second.curState != i.second.lastState) { 52 | D3D12_RESOURCE_BARRIER& transBarrier = states.emplace_back(); 53 | transBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; 54 | transBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; 55 | transBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; 56 | transBarrier.Transition.pResource = i.first->GetResource(); 57 | transBarrier.Transition.StateBefore = i.second.lastState; 58 | transBarrier.Transition.StateAfter = i.second.curState; 59 | } 60 | i.second.lastState = i.second.curState; 61 | } 62 | } 63 | void ResourceStateTracker::RestoreStateMap() { 64 | for (auto&& i : stateMap) { 65 | i.second.curState = i.first->GetInitState(); 66 | bool isWrite = detail::IsWriteState(i.second.curState); 67 | if (isWrite != i.second.isWrite) { 68 | MarkWritable(i.first, isWrite); 69 | } 70 | bool useUavBarrier = 71 | (i.second.lastState == D3D12_RESOURCE_STATE_UNORDERED_ACCESS && i.second.curState == D3D12_RESOURCE_STATE_UNORDERED_ACCESS); 72 | 73 | if (useUavBarrier) { 74 | D3D12_RESOURCE_BARRIER& uavBarrier = states.emplace_back(); 75 | uavBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; 76 | uavBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; 77 | uavBarrier.UAV.pResource = i.first->GetResource(); 78 | } else if (i.second.curState != i.second.lastState) { 79 | D3D12_RESOURCE_BARRIER& transBarrier = states.emplace_back(); 80 | transBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; 81 | transBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; 82 | transBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; 83 | transBarrier.Transition.pResource = i.first->GetResource(); 84 | transBarrier.Transition.StateBefore = i.second.lastState; 85 | transBarrier.Transition.StateAfter = i.second.curState; 86 | } 87 | } 88 | stateMap.clear(); 89 | } 90 | 91 | void ResourceStateTracker::UpdateState(ID3D12GraphicsCommandList* cmdList) { 92 | ExecuteStateMap(); 93 | if (!states.empty()) { 94 | cmdList->ResourceBarrier( 95 | states.size(), 96 | states.data()); 97 | states.clear(); 98 | } 99 | } 100 | void ResourceStateTracker::RestoreState(ID3D12GraphicsCommandList* cmdList) { 101 | RestoreStateMap(); 102 | if (!states.empty()) { 103 | cmdList->ResourceBarrier( 104 | states.size(), 105 | states.data()); 106 | states.clear(); 107 | } 108 | } 109 | 110 | void ResourceStateTracker::MarkWritable(Resource const* res, bool writable) { 111 | if (writable) { 112 | writeStateMap.emplace(res); 113 | } else { 114 | writeStateMap.erase(res); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Chapter4/src/DXRuntime/ResourceStateTracker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | class Resource; 6 | class ResourceStateTracker { 7 | private: 8 | struct State { 9 | D3D12_RESOURCE_STATES lastState; 10 | D3D12_RESOURCE_STATES curState; 11 | bool uavBarrier; 12 | bool isWrite; 13 | }; 14 | std::unordered_map stateMap; 15 | std::unordered_set writeStateMap; 16 | std::vector states; 17 | void ExecuteStateMap(); 18 | void RestoreStateMap(); 19 | void MarkWritable(Resource const *res, bool writable); 20 | 21 | public: 22 | std::unordered_set const& WriteStateMap() const { return writeStateMap; } 23 | ResourceStateTracker(); 24 | ~ResourceStateTracker(); 25 | void RecordState( 26 | Resource const *resource, 27 | D3D12_RESOURCE_STATES state); 28 | void RecordState(Resource const *resource); 29 | void UpdateState(ID3D12GraphicsCommandList* cmdList); 30 | void RestoreState(ID3D12GraphicsCommandList* cmdList); 31 | }; 32 | -------------------------------------------------------------------------------- /Chapter4/src/DXSample.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #pragma once 13 | 14 | #include "DXSampleHelper.h" 15 | #include "Win32Application.h" 16 | 17 | class DXSample 18 | { 19 | public: 20 | DXSample(uint32_t width, uint32_t height, std::wstring name); 21 | virtual ~DXSample(); 22 | 23 | virtual void OnInit() = 0; 24 | virtual void OnUpdate() = 0; 25 | virtual void OnRender() = 0; 26 | virtual void OnDestroy() = 0; 27 | 28 | // Samples override the event handlers to handle specific messages. 29 | virtual void OnKeyDown(UINT8 /*key*/) {} 30 | virtual void OnKeyUp(UINT8 /*key*/) {} 31 | 32 | // Accessors. 33 | uint32_t GetWidth() const { return m_width; } 34 | uint32_t GetHeight() const { return m_height; } 35 | const wchar_t* GetTitle() const { return m_title.c_str(); } 36 | 37 | void ParseCommandLineArgs(_In_reads_(argc) wchar_t* argv[], int argc); 38 | 39 | protected: 40 | std::wstring GetAssetFullPath(LPCWSTR assetName); 41 | 42 | void GetHardwareAdapter( 43 | _In_ IDXGIFactory1* pFactory, 44 | _Outptr_result_maybenull_ IDXGIAdapter1** ppAdapter, 45 | bool requestHighPerformanceAdapter = false); 46 | 47 | void SetCustomWindowText(LPCWSTR text); 48 | 49 | // Viewport dimensions. 50 | uint32_t m_width; 51 | uint32_t m_height; 52 | float m_aspectRatio; 53 | 54 | // Adapter info. 55 | bool m_useWarpDevice; 56 | 57 | private: 58 | // Root assets path. 59 | std::wstring m_assetsPath; 60 | 61 | // Window title. 62 | std::wstring m_title; 63 | }; 64 | -------------------------------------------------------------------------------- /Chapter4/src/Main.cpp: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #include "stdafx.h" 13 | #include "D3D12BetterSimpleBox.h" 14 | 15 | _Use_decl_annotations_ 16 | int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) 17 | { 18 | D3D12BetterSimpleBox sample(1280, 720, L"D3D12 Better Simple Box"); 19 | return Win32Application::Run(&sample, hInstance, nCmdShow); 20 | } 21 | -------------------------------------------------------------------------------- /Chapter4/src/Metalib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | template 4 | requires(!std::is_lvalue_reference_v) 5 | T* get_rvalue_ptr(T&& v) { 6 | return &v; 7 | } 8 | template 9 | struct array_meta; 10 | template 11 | struct array_meta { 12 | static constexpr size_t array_size = N; 13 | static constexpr size_t byte_size = N * sizeof(T); 14 | }; 15 | 16 | template 17 | requires(std::is_bounded_array_v) constexpr size_t array_count(T const& t) { 18 | return array_meta::array_size; 19 | } 20 | template 21 | requires(std::is_bounded_array_v) constexpr size_t array_byte_size(T const& t) { 22 | return array_meta::byte_size; 23 | } 24 | 25 | using vbyte = uint8_t; 26 | using uint = uint32_t; 27 | using uint64 = uint64_t; 28 | using int32 = int32_t; 29 | -------------------------------------------------------------------------------- /Chapter4/src/Resource/Buffer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | BufferView::BufferView(Buffer const* buffer) 4 | : buffer(buffer), 5 | byteSize(buffer ? buffer->GetByteSize() : 0), 6 | offset(0) { 7 | } 8 | BufferView::BufferView( 9 | Buffer const* buffer, 10 | uint64 offset, 11 | uint64 byteSize) 12 | : buffer(buffer), 13 | offset(offset), 14 | byteSize(byteSize) {} 15 | Buffer::Buffer( 16 | Device* device) 17 | : Resource(device){ 18 | } 19 | Buffer::~Buffer() { 20 | } 21 | -------------------------------------------------------------------------------- /Chapter4/src/Resource/Buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | class Buffer : public Resource{ 6 | public: 7 | Buffer(Device* device); 8 | virtual D3D12_GPU_VIRTUAL_ADDRESS GetAddress() const = 0; 9 | virtual uint64 GetByteSize() const = 0; 10 | virtual ~Buffer(); 11 | Buffer(Buffer&&) = default; 12 | }; 13 | -------------------------------------------------------------------------------- /Chapter4/src/Resource/BufferView.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class Buffer; 5 | struct BufferView { 6 | Buffer const* buffer = nullptr; 7 | uint64 offset = 0; 8 | uint64 byteSize = 0; 9 | BufferView() {} 10 | BufferView(Buffer const* buffer); 11 | BufferView( 12 | Buffer const* buffer, 13 | uint64 offset, 14 | uint64 byteSize); 15 | bool operator==(BufferView const& a) const { 16 | return memcmp(this, &a, sizeof(BufferView)) == 0; 17 | } 18 | bool operator!=(BufferView const& a) const { 19 | return !operator==(a); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /Chapter4/src/Resource/DefaultBuffer.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | DefaultBuffer::DefaultBuffer( 7 | Device* device, 8 | uint64 byteSize, 9 | D3D12_RESOURCE_STATES initState) 10 | : Buffer(device), 11 | initState(initState), 12 | byteSize(byteSize) { 13 | auto prop = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT); 14 | auto buffer = CD3DX12_RESOURCE_DESC::Buffer(byteSize, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); 15 | ThrowIfFailed(device->DxDevice()->CreateCommittedResource( 16 | &prop, 17 | D3D12_HEAP_FLAG_NONE, 18 | &buffer, 19 | initState, 20 | nullptr, 21 | IID_PPV_ARGS(&resource))); 22 | } 23 | DefaultBuffer::~DefaultBuffer() { 24 | } 25 | void DefaultBuffer::DelayDispose(FrameResource* frameRes) const { 26 | frameRes->AddDelayDisposeResource(resource); 27 | } -------------------------------------------------------------------------------- /Chapter4/src/Resource/DefaultBuffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class DefaultBuffer final : public Buffer { 5 | private: 6 | uint64 byteSize; 7 | D3D12_RESOURCE_STATES initState; 8 | ComPtr resource; 9 | 10 | public: 11 | ID3D12Resource* GetResource() const override { return resource.Get(); } 12 | D3D12_GPU_VIRTUAL_ADDRESS GetAddress() const override { return resource->GetGPUVirtualAddress(); } 13 | uint64 GetByteSize() const override { return byteSize; } 14 | DefaultBuffer( 15 | Device* device, 16 | uint64 byteSize, 17 | D3D12_RESOURCE_STATES initState = D3D12_RESOURCE_STATE_COMMON); 18 | ~DefaultBuffer(); 19 | D3D12_RESOURCE_STATES GetInitState() const override { 20 | return initState; 21 | } 22 | 23 | DefaultBuffer(DefaultBuffer&&) = default; 24 | DefaultBuffer(DefaultBuffer const&) = delete; 25 | void DelayDispose(FrameResource* frameRes) const override; 26 | }; 27 | -------------------------------------------------------------------------------- /Chapter4/src/Resource/DescriptorHeap.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | DescriptorHeap::DescriptorHeap( 4 | Device* device, 5 | D3D12_DESCRIPTOR_HEAP_TYPE Type, 6 | uint64 numDescriptors, 7 | bool bShaderVisible) 8 | : Resource(device), 9 | allocatePool(numDescriptors), 10 | numDescriptors(numDescriptors) { 11 | Desc.Type = Type; 12 | Desc.NumDescriptors = numDescriptors; 13 | Desc.Flags = (bShaderVisible ? D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE : D3D12_DESCRIPTOR_HEAP_FLAG_NONE); 14 | Desc.NodeMask = 0; 15 | { 16 | for (size_t i = 0; i < numDescriptors; ++i) { 17 | allocatePool[i] = i; 18 | } 19 | } 20 | ThrowIfFailed(device->DxDevice()->CreateDescriptorHeap( 21 | &Desc, 22 | IID_PPV_ARGS(&pDH))); 23 | hCPUHeapStart = pDH->GetCPUDescriptorHandleForHeapStart(); 24 | hGPUHeapStart = pDH->GetGPUDescriptorHandleForHeapStart(); 25 | HandleIncrementSize = device->DxDevice()->GetDescriptorHandleIncrementSize(Desc.Type); 26 | } 27 | DescriptorHeap::~DescriptorHeap() { 28 | } 29 | uint DescriptorHeap::AllocateIndex() { 30 | std::lock_guard lck(heapMtx); 31 | #ifdef _DEBUG 32 | if (allocatePool.empty()) { 33 | throw "bindless allocator out or range!\n"; 34 | } 35 | #endif 36 | auto last = allocatePool.end() - 1; 37 | uint v = *last; 38 | allocatePool.erase(last); 39 | return v; 40 | } 41 | void DescriptorHeap::ReturnIndex(uint v) { 42 | std::lock_guard lck(heapMtx); 43 | allocatePool.emplace_back(v); 44 | } 45 | void DescriptorHeap::Reset() { 46 | allocatePool.resize(numDescriptors); 47 | for (size_t i = 0; i < numDescriptors; ++i) { 48 | allocatePool[i] = i; 49 | } 50 | } 51 | void DescriptorHeap::CreateUAV(ID3D12Resource* resource, const D3D12_UNORDERED_ACCESS_VIEW_DESC& pDesc, uint64 index) { 52 | device->DxDevice()->CreateUnorderedAccessView(resource, nullptr, &pDesc, hCPU(index)); 53 | } 54 | void DescriptorHeap::CreateSRV(ID3D12Resource* resource, const D3D12_SHADER_RESOURCE_VIEW_DESC& pDesc, uint64 index) { 55 | device->DxDevice()->CreateShaderResourceView(resource, &pDesc, hCPU(index)); 56 | } 57 | -------------------------------------------------------------------------------- /Chapter4/src/Resource/DescriptorHeap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | class DescriptorHeap final : public Resource { 10 | private: 11 | Microsoft::WRL::ComPtr pDH; 12 | D3D12_DESCRIPTOR_HEAP_DESC Desc; 13 | D3D12_CPU_DESCRIPTOR_HANDLE hCPUHeapStart; 14 | D3D12_GPU_DESCRIPTOR_HANDLE hGPUHeapStart; 15 | uint HandleIncrementSize; 16 | uint64 numDescriptors; 17 | std::vector allocatePool; 18 | std::mutex heapMtx; 19 | 20 | public: 21 | uint64 Length() const { return numDescriptors; } 22 | ID3D12DescriptorHeap* GetHeap() const { return pDH.Get(); } 23 | D3D12_GPU_DESCRIPTOR_HANDLE hGPU(uint64 index) const { 24 | if (index >= Desc.NumDescriptors) index = Desc.NumDescriptors - 1; 25 | D3D12_GPU_DESCRIPTOR_HANDLE h = {hGPUHeapStart.ptr + index * HandleIncrementSize}; 26 | return h; 27 | } 28 | D3D12_CPU_DESCRIPTOR_HANDLE hCPU(uint64 index) const { 29 | if (index >= Desc.NumDescriptors) index = Desc.NumDescriptors - 1; 30 | D3D12_CPU_DESCRIPTOR_HANDLE h = {hCPUHeapStart.ptr + index * HandleIncrementSize}; 31 | return h; 32 | } 33 | 34 | DescriptorHeap( 35 | Device* pDevice, 36 | D3D12_DESCRIPTOR_HEAP_TYPE Type, 37 | uint64 numDescriptors, 38 | bool bShaderVisible); 39 | uint AllocateIndex(); 40 | void ReturnIndex(uint v); 41 | void Reset(); 42 | void CreateUAV(ID3D12Resource* resource, const D3D12_UNORDERED_ACCESS_VIEW_DESC& pDesc, uint64 index); 43 | void CreateSRV(ID3D12Resource* resource, const D3D12_SHADER_RESOURCE_VIEW_DESC& pDesc, uint64 index); 44 | ~DescriptorHeap(); 45 | }; 46 | -------------------------------------------------------------------------------- /Chapter4/src/Resource/DescriptorHeapView.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | class DescriptorHeap; 4 | struct DescriptorHeapView { 5 | DescriptorHeap const* heap; 6 | uint64 index; 7 | DescriptorHeapView( 8 | DescriptorHeap const* heap, 9 | uint64 index) 10 | : heap(heap), 11 | index(index) {} 12 | DescriptorHeapView( 13 | DescriptorHeap const* heap) 14 | : heap(heap), 15 | index(0) {} 16 | }; 17 | -------------------------------------------------------------------------------- /Chapter4/src/Resource/Mesh.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | Mesh::Mesh( 3 | Device* device, 4 | std::span vbStructs, 5 | uint vertexCount, 6 | uint indexCount) 7 | : Resource(device), 8 | vertexCount(vertexCount), 9 | vertexStructs(vbStructs), 10 | indexCount(indexCount), 11 | indexBuffer(device, sizeof(uint) * indexCount) { 12 | vertexBuffers.reserve(vertexStructs.size()); 13 | uint slotCount = 0; 14 | for (auto&& i : vertexStructs) { 15 | vertexBuffers.emplace_back(device, i->structSize * vertexCount); 16 | i->GetMeshLayout(slotCount, layout); 17 | ++slotCount; 18 | } 19 | } 20 | void Mesh::GetVertexBufferView(std::vector& result) const { 21 | result.clear(); 22 | result.resize(vertexBuffers.size()); 23 | for (size_t i = 0; i < vertexBuffers.size(); ++i) { 24 | auto& r = result[i]; 25 | auto& v = vertexBuffers[i]; 26 | r.BufferLocation = v.GetAddress(); 27 | r.SizeInBytes = v.GetByteSize(); 28 | r.StrideInBytes = r.SizeInBytes / vertexCount; 29 | } 30 | } 31 | 32 | D3D12_INDEX_BUFFER_VIEW Mesh::GetIndexBufferView() const { 33 | D3D12_INDEX_BUFFER_VIEW v; 34 | v.BufferLocation = indexBuffer.GetAddress(); 35 | v.SizeInBytes = indexBuffer.GetByteSize(); 36 | v.Format = DXGI_FORMAT_R32_UINT; 37 | return v; 38 | } -------------------------------------------------------------------------------- /Chapter4/src/Resource/Mesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | class Mesh : public Resource { 6 | std::vector vertexBuffers; 7 | DefaultBuffer indexBuffer; 8 | std::span vertexStructs; 9 | std::vector layout; 10 | uint vertexCount; 11 | uint indexCount; 12 | 13 | public: 14 | std::span VertexBuffers() const { return vertexBuffers; } 15 | DefaultBuffer const& IndexBuffer() const { return indexBuffer; } 16 | std::span Layout() const { return layout; } 17 | Mesh( 18 | Device* device, 19 | std::span vbStructs, 20 | uint vertexCount, 21 | uint indexCount); 22 | void GetVertexBufferView(std::vector& result) const; 23 | D3D12_INDEX_BUFFER_VIEW GetIndexBufferView() const; 24 | }; -------------------------------------------------------------------------------- /Chapter4/src/Resource/ReadbackBuffer.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | ReadbackBuffer::ReadbackBuffer( 7 | Device* device, 8 | uint64 byteSize) 9 | : Buffer(device), 10 | byteSize(byteSize) { 11 | auto prop = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK); 12 | auto buffer = CD3DX12_RESOURCE_DESC::Buffer(byteSize); 13 | ThrowIfFailed(device->DxDevice()->CreateCommittedResource( 14 | &prop, 15 | D3D12_HEAP_FLAG_NONE, 16 | &buffer, 17 | D3D12_RESOURCE_STATE_COPY_DEST, 18 | nullptr, 19 | IID_PPV_ARGS(&resource))); 20 | } 21 | ReadbackBuffer::~ReadbackBuffer() { 22 | } 23 | void ReadbackBuffer::CopyData( 24 | uint64 offset, 25 | std::span data) const { 26 | void* mapPtr; 27 | D3D12_RANGE range; 28 | range.Begin = offset; 29 | range.End = std::min(byteSize, offset + data.size()); 30 | ThrowIfFailed(resource->Map(0, &range, (void**)(&mapPtr))); 31 | memcpy(data.data(), reinterpret_cast(mapPtr) + offset, range.End - range.Begin); 32 | resource->Unmap(0, nullptr); 33 | } 34 | 35 | void ReadbackBuffer::DelayDispose(FrameResource* frameRes) const { 36 | frameRes->AddDelayDisposeResource(resource); 37 | } -------------------------------------------------------------------------------- /Chapter4/src/Resource/ReadbackBuffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | 5 | class ReadbackBuffer final : public Buffer { 6 | private: 7 | ComPtr resource; 8 | uint64 byteSize; 9 | 10 | public: 11 | ID3D12Resource* GetResource() const override { return resource.Get(); } 12 | D3D12_GPU_VIRTUAL_ADDRESS GetAddress() const override { return resource->GetGPUVirtualAddress(); } 13 | uint64 GetByteSize() const override { return byteSize; } 14 | ReadbackBuffer( 15 | Device* device, 16 | uint64 byteSize); 17 | ~ReadbackBuffer(); 18 | void CopyData(uint64 offset, std::span data) const; 19 | D3D12_RESOURCE_STATES GetInitState() const override { 20 | return D3D12_RESOURCE_STATE_COPY_DEST; 21 | } 22 | ReadbackBuffer(ReadbackBuffer&&) = default; 23 | ReadbackBuffer(ReadbackBuffer const&) = delete; 24 | void DelayDispose(FrameResource* frameRes) const override; 25 | }; 26 | -------------------------------------------------------------------------------- /Chapter4/src/Resource/Resource.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | using Microsoft::WRL::ComPtr; 5 | class FrameResource; 6 | class Resource { 7 | protected: 8 | Device* device; 9 | 10 | public: 11 | Device* GetDevice() const { return device; } 12 | Resource(Device* device) 13 | : device(device) {} 14 | Resource(Resource&&) = default; 15 | Resource(Resource const&) = delete; 16 | virtual ~Resource() = default; 17 | virtual ID3D12Resource* GetResource() const { return nullptr; } 18 | virtual D3D12_RESOURCE_STATES GetInitState() const { return D3D12_RESOURCE_STATE_COMMON; } 19 | virtual void DelayDispose(FrameResource* frameRes) const {} 20 | }; 21 | -------------------------------------------------------------------------------- /Chapter4/src/Resource/Texture.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | enum class TextureDimension : vbyte { 4 | None, 5 | Tex1D, 6 | Tex2D, 7 | Tex3D, 8 | Cubemap, 9 | Tex2DArray, 10 | }; 11 | class Texture final : public Resource { 12 | public: 13 | enum class TextureUsage : uint { 14 | None = 0, 15 | RenderTarget = 0x1, 16 | DepthStencil = 0x2, 17 | UnorderedAccess = 0x4, 18 | GenericColor = (0x4 | 0x1) // Both render target and unordered access 19 | }; 20 | static constexpr float CLEAR_COLOR[4] = {0,0,0,0}; 21 | static constexpr float CLEAR_DEPTH = 1; 22 | static constexpr uint8_t CLEAR_STENCIL = 0; 23 | 24 | private: 25 | ComPtr resource; 26 | D3D12_RESOURCE_STATES initState; 27 | TextureDimension dimension; 28 | TextureUsage usage; 29 | 30 | public: 31 | Texture( 32 | Device* device, 33 | uint width, 34 | uint height, 35 | DXGI_FORMAT format, 36 | TextureDimension dimension, 37 | uint depth, 38 | uint mip, 39 | TextureUsage usage, 40 | D3D12_RESOURCE_STATES resourceState); 41 | Texture( 42 | Device* device, 43 | IDXGISwapChain3* swapchain, 44 | uint frame); 45 | ~Texture(); 46 | ID3D12Resource* GetResource() const override { 47 | return resource.Get(); 48 | } 49 | D3D12_RESOURCE_STATES GetInitState() const { 50 | return initState; 51 | } 52 | D3D12_SHADER_RESOURCE_VIEW_DESC GetColorSrvDesc(uint mipOffset) const; 53 | D3D12_UNORDERED_ACCESS_VIEW_DESC GetColorUavDesc(uint targetMipLevel) const; 54 | void DelayDispose(FrameResource* frameRes) const override; 55 | }; 56 | -------------------------------------------------------------------------------- /Chapter4/src/Resource/UploadBuffer.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | UploadBuffer::UploadBuffer( 6 | Device* device, 7 | uint64 byteSize) 8 | : Buffer(device), 9 | byteSize(byteSize) { 10 | auto prop = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD); 11 | auto buffer = CD3DX12_RESOURCE_DESC::Buffer(byteSize); 12 | ThrowIfFailed(device->DxDevice()->CreateCommittedResource( 13 | &prop, 14 | D3D12_HEAP_FLAG_NONE, 15 | &buffer, 16 | D3D12_RESOURCE_STATE_GENERIC_READ, 17 | nullptr, 18 | IID_PPV_ARGS(&resource))); 19 | } 20 | UploadBuffer::~UploadBuffer() { 21 | } 22 | void UploadBuffer::CopyData(uint64 offset, std::span data) const { 23 | void* mappedPtr; 24 | D3D12_RANGE range; 25 | range.Begin = offset; 26 | range.End = std::min(byteSize, offset + data.size()); 27 | ThrowIfFailed(resource->Map(0, &range, reinterpret_cast(&mappedPtr))); 28 | memcpy(reinterpret_cast(mappedPtr) + offset, data.data(), range.End - range.Begin); 29 | resource->Unmap(0, &range); 30 | } 31 | 32 | void UploadBuffer::DelayDispose(FrameResource* frameRes) const { 33 | frameRes->AddDelayDisposeResource(resource); 34 | } -------------------------------------------------------------------------------- /Chapter4/src/Resource/UploadBuffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class UploadBuffer final : public Buffer { 5 | private: 6 | ComPtr resource; 7 | uint64 byteSize; 8 | 9 | public: 10 | ID3D12Resource* GetResource() const override { return resource.Get(); } 11 | D3D12_GPU_VIRTUAL_ADDRESS GetAddress() const override { return resource->GetGPUVirtualAddress(); } 12 | uint64 GetByteSize() const override { return byteSize; } 13 | UploadBuffer( 14 | Device* device, 15 | uint64 byteSize); 16 | ~UploadBuffer(); 17 | void CopyData(uint64 offset, std::span data) const; 18 | D3D12_RESOURCE_STATES GetInitState() const override { 19 | return D3D12_RESOURCE_STATE_GENERIC_READ; 20 | } 21 | UploadBuffer(UploadBuffer&&) = default; 22 | UploadBuffer(UploadBuffer const&) = delete; 23 | void DelayDispose(FrameResource* frameRes) const override; 24 | }; 25 | 26 | -------------------------------------------------------------------------------- /Chapter4/src/Shader/GlobalSamplers.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | struct GlobalSampleData { 5 | std::array arr; 6 | GlobalSampleData() { 7 | D3D12_FILTER filters[] = { 8 | D3D12_FILTER_MIN_MAG_MIP_POINT, 9 | D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT, 10 | D3D12_FILTER_MIN_MAG_MIP_LINEAR, 11 | D3D12_FILTER_ANISOTROPIC}; 12 | D3D12_TEXTURE_ADDRESS_MODE addressMode[] = { 13 | D3D12_TEXTURE_ADDRESS_MODE_CLAMP, 14 | D3D12_TEXTURE_ADDRESS_MODE_WRAP, 15 | D3D12_TEXTURE_ADDRESS_MODE_MIRROR, 16 | D3D12_TEXTURE_ADDRESS_MODE_BORDER}; 17 | memset(arr.data(), 0, sizeof(D3D12_STATIC_SAMPLER_DESC) * arr.size()); 18 | size_t idx = 0; 19 | for (size_t x = 0; x < 4; ++x) 20 | for (size_t y = 0; y < 4; ++y) { 21 | auto&& v = arr[idx]; 22 | v.Filter = filters[y]; 23 | auto address = addressMode[x]; 24 | v.BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK; 25 | v.AddressU = address; 26 | v.AddressV = address; 27 | v.AddressW = address; 28 | v.MipLODBias = 0; 29 | v.MaxAnisotropy = 16; 30 | v.MinLOD = 0; 31 | v.MaxLOD = 16; 32 | v.ShaderRegister = idx; 33 | v.RegisterSpace = 0; 34 | v.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; 35 | ++idx; 36 | } 37 | } 38 | }; 39 | static GlobalSampleData sampleData; 40 | 41 | std::span GlobalSamplers::GetSamplers() { 42 | return {sampleData.arr.data(), sampleData.arr.size()}; 43 | } 44 | -------------------------------------------------------------------------------- /Chapter4/src/Shader/GlobalSamplers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | class GlobalSamplers { 6 | public: 7 | static std::span GetSamplers(); 8 | }; 9 | -------------------------------------------------------------------------------- /Chapter4/src/Shader/PSOManager.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | PSOManager::PSOManager(Device* device) 5 | : device(device) { 6 | } 7 | PSOManager::~PSOManager() { 8 | } 9 | ID3D12PipelineState* PSOManager::GetPipelineState(D3D12_GRAPHICS_PIPELINE_STATE_DESC const& stateDesc) { 10 | auto emplaceResult = pipelineStates.try_emplace(stateDesc); 11 | // New pipeline state 12 | if (emplaceResult.second) { 13 | ThrowIfFailed(device->DxDevice()->CreateGraphicsPipelineState(&stateDesc, IID_PPV_ARGS(&emplaceResult.first->second))); 14 | } 15 | return emplaceResult.first->second.Get(); 16 | } 17 | ID3D12PipelineState* PSOManager::GetPipelineState( 18 | std::span meshLayout, 19 | RasterShader const* shader, 20 | std::span rtvFormats, 21 | DXGI_FORMAT depthFormat, 22 | D3D12_PRIMITIVE_TOPOLOGY_TYPE topologyType) { 23 | D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; 24 | psoDesc.InputLayout = {meshLayout.data(), uint(meshLayout.size())}; 25 | psoDesc.pRootSignature = shader->RootSig(); 26 | auto GetByteCode = [](ComPtr const& blob) -> D3D12_SHADER_BYTECODE { 27 | if (blob) { 28 | return CD3DX12_SHADER_BYTECODE(blob.Get()); 29 | } else { 30 | return CD3DX12_SHADER_BYTECODE(nullptr, 0); 31 | } 32 | }; 33 | psoDesc.VS = GetByteCode(shader->vsShader); 34 | psoDesc.PS = GetByteCode(shader->psShader); 35 | psoDesc.HS = GetByteCode(shader->hsShader); 36 | psoDesc.DS = GetByteCode(shader->dsShader); 37 | psoDesc.RasterizerState = shader->rasterizeState; 38 | psoDesc.DepthStencilState = shader->depthStencilState; 39 | psoDesc.BlendState = shader->blendState; 40 | psoDesc.SampleMask = UINT_MAX; 41 | psoDesc.PrimitiveTopologyType = topologyType; 42 | 43 | size_t rtSize = std::min(rtvFormats.size(), 8); 44 | psoDesc.NumRenderTargets = rtSize; 45 | for (size_t i = 0; i < rtSize; ++i) { 46 | psoDesc.RTVFormats[i] = rtvFormats[i]; 47 | } 48 | psoDesc.DSVFormat = depthFormat; 49 | psoDesc.SampleDesc.Count = 1; 50 | return GetPipelineState(psoDesc); 51 | } -------------------------------------------------------------------------------- /Chapter4/src/Shader/PSOManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | //hash 9 | namespace std { 10 | template<> 11 | struct hash { 12 | using argument_type = D3D12_GRAPHICS_PIPELINE_STATE_DESC; 13 | using result_type = size_t; 14 | size_t operator()(argument_type const& v) const { 15 | return GetHash(v); 16 | } 17 | }; 18 | template<> 19 | struct equal_to { 20 | using argument_type = D3D12_GRAPHICS_PIPELINE_STATE_DESC; 21 | using result_type = size_t; 22 | bool operator()(argument_type const& a, argument_type const& b) const { 23 | return memcmp(&a, &b, sizeof(argument_type)) == 0; 24 | } 25 | }; 26 | }// namespace std 27 | using Microsoft::WRL::ComPtr; 28 | class RasterShader; 29 | class PSOManager { 30 | std::unordered_map> pipelineStates; 31 | Device* device; 32 | ID3D12PipelineState* GetPipelineState(D3D12_GRAPHICS_PIPELINE_STATE_DESC const& stateDesc); 33 | 34 | public: 35 | PSOManager(Device* device); 36 | ~PSOManager(); 37 | ID3D12PipelineState* GetPipelineState( 38 | std::span meshLayout, 39 | RasterShader const* shader, 40 | std::span rtvFormats, 41 | DXGI_FORMAT depthFormat, 42 | D3D12_PRIMITIVE_TOPOLOGY_TYPE topologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE); 43 | }; -------------------------------------------------------------------------------- /Chapter4/src/Shader/RasterShader.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | RasterShader::RasterShader( 3 | std::span const> properties, 4 | Device* device) 5 | : Shader(properties, device) {} 6 | RasterShader::RasterShader( 7 | std::span const> properties, 8 | ComPtr&& rootSig) 9 | : Shader(properties, std::move(rootSig)) {} -------------------------------------------------------------------------------- /Chapter4/src/Shader/RasterShader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | class RasterShader : public Shader { 5 | public: 6 | Microsoft::WRL::ComPtr vsShader = nullptr; 7 | Microsoft::WRL::ComPtr psShader = nullptr; 8 | Microsoft::WRL::ComPtr hsShader = nullptr; 9 | Microsoft::WRL::ComPtr dsShader = nullptr; 10 | D3D12_RASTERIZER_DESC rasterizeState; 11 | D3D12_DEPTH_STENCIL_DESC depthStencilState; 12 | D3D12_BLEND_DESC blendState; 13 | RasterShader( 14 | std::span const> properties, 15 | Device* device); 16 | RasterShader( 17 | std::span const> properties, 18 | ComPtr&& rootSig); 19 | }; -------------------------------------------------------------------------------- /Chapter4/src/Shader/Shader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using Microsoft::WRL::ComPtr; 13 | class TopAccel; 14 | class Shader { 15 | public: 16 | struct Property { 17 | ShaderVariableType type; 18 | uint spaceIndex; 19 | uint registerIndex; 20 | uint arrSize; 21 | }; 22 | protected: 23 | struct InsideProperty : public Property { 24 | uint rootSigPos; 25 | InsideProperty(Property const& p) 26 | : Property(p) {} 27 | }; 28 | Microsoft::WRL::ComPtr rootSig; 29 | std::unordered_map properties; 30 | std::optional GetProperty(std::string_view str) const; 31 | 32 | public: 33 | Shader( 34 | std::span const> properties, 35 | Device* device); 36 | Shader( 37 | std::span const> properties, 38 | ComPtr&& rootSig); 39 | Shader(Shader&& v) = default; 40 | ID3D12RootSignature* RootSig() const { return rootSig.Get(); } 41 | 42 | bool SetResource( 43 | std::string_view propertyName, 44 | ID3D12GraphicsCommandList* cmdList, 45 | BufferView buffer) const; 46 | bool SetResource( 47 | std::string_view propertyName, 48 | ID3D12GraphicsCommandList* cmdList, 49 | DescriptorHeapView buffer) const; 50 | virtual ~Shader() = default; 51 | }; 52 | -------------------------------------------------------------------------------- /Chapter4/src/Shader/ShaderVariableType.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | enum class ShaderVariableType : uint8_t { 6 | ConstantBuffer, 7 | SRVDescriptorHeap, 8 | UAVDescriptorHeap, 9 | CBVDescriptorHeap, 10 | StructuredBuffer, 11 | RWStructuredBuffer 12 | }; 13 | struct ShaderVariable { 14 | std::string name; 15 | ShaderVariableType type; 16 | uint tableSize; 17 | uint registerPos; 18 | uint space; 19 | ShaderVariable() {} 20 | ShaderVariable( 21 | const std::string& name, 22 | ShaderVariableType type, 23 | uint tableSize, 24 | uint registerPos, 25 | uint space) 26 | : name(name), 27 | type(type), 28 | tableSize(tableSize), 29 | registerPos(registerPos), 30 | space(space) {} 31 | }; -------------------------------------------------------------------------------- /Chapter4/src/Utility/Hash.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | namespace xxh { 5 | size_t xxhash_gethash(void const* ptr, size_t sz); 6 | //Size must less than 32 in x64 7 | size_t xxhash_gethash_small(void const* ptr, size_t sz); 8 | }// namespace xxh 9 | template 10 | requires(std::is_trivial_v && (!std::is_reference_v)) 11 | size_t GetHash(T const& v) { 12 | if constexpr (sizeof(T) < 32) { 13 | return xxh::xxhash_gethash_small(&v, sizeof(T)); 14 | } else { 15 | return xxh::xxhash_gethash(&v, sizeof(T)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Chapter4/src/Utility/ReflactableStruct.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | namespace rtti { 4 | static thread_local Struct* curStruct = nullptr; 5 | size_t VarTypeData::GetSize() const { 6 | return dimension * 4; 7 | } 8 | Struct::Struct() { 9 | curStruct = this; 10 | } 11 | VarTypeBase::VarTypeBase(VarTypeData&& varData) { 12 | offset = curStruct->structSize; 13 | //A Simple parser 14 | //Split Semantic, get index 15 | if (!varData.semantic.empty()) { 16 | uint rate = 1; 17 | uint semanticIndex = 0; 18 | char const* ptr = varData.semantic.data() + varData.semantic.size() - 1; 19 | while (ptr != (varData.semantic.data() - 1)) { 20 | if (*ptr >= '0' && *ptr <= '9') { 21 | semanticIndex += rate * (int(*ptr) - int('0')); 22 | rate *= 10; 23 | } else { 24 | break; 25 | } 26 | --ptr; 27 | } 28 | auto leftSize = reinterpret_cast(ptr) - reinterpret_cast(varData.semantic.data()) + 1; 29 | varData.semantic.resize(leftSize); 30 | varData.semanticIndex = semanticIndex; 31 | } 32 | curStruct->variables.emplace_back(std::move(varData)); 33 | curStruct->structSize += varData.GetSize(); 34 | } 35 | void Struct::GetMeshLayout(uint slot, std::vector& resultVector) const { 36 | auto getFormat = [](VarTypeData const& d) -> DXGI_FORMAT { 37 | switch (d.scale) { 38 | case VarTypeData::ScaleType::Float: 39 | switch (d.dimension) { 40 | case 1: 41 | return DXGI_FORMAT_R32_FLOAT; 42 | case 2: 43 | return DXGI_FORMAT_R32G32_FLOAT; 44 | case 3: 45 | return DXGI_FORMAT_R32G32B32_FLOAT; 46 | case 4: 47 | return DXGI_FORMAT_R32G32B32A32_FLOAT; 48 | default: 49 | return DXGI_FORMAT_UNKNOWN; 50 | } 51 | case VarTypeData::ScaleType::UInt: 52 | switch (d.dimension) { 53 | case 1: 54 | return DXGI_FORMAT_R32_UINT; 55 | case 2: 56 | return DXGI_FORMAT_R32G32_UINT; 57 | case 3: 58 | return DXGI_FORMAT_R32G32B32_UINT; 59 | case 4: 60 | return DXGI_FORMAT_R32G32B32A32_UINT; 61 | default: 62 | return DXGI_FORMAT_UNKNOWN; 63 | } 64 | case VarTypeData::ScaleType::Int: 65 | switch (d.dimension) { 66 | case 1: 67 | return DXGI_FORMAT_R32_SINT; 68 | case 2: 69 | return DXGI_FORMAT_R32G32_SINT; 70 | case 3: 71 | return DXGI_FORMAT_R32G32B32_SINT; 72 | case 4: 73 | return DXGI_FORMAT_R32G32B32A32_SINT; 74 | default: 75 | return DXGI_FORMAT_UNKNOWN; 76 | } 77 | default: 78 | return DXGI_FORMAT_UNKNOWN; 79 | } 80 | }; 81 | uint offset = 0; 82 | for (size_t i = 0; i < variables.size(); ++i) { 83 | auto& result = resultVector.emplace_back(); 84 | auto& var = variables[i]; 85 | result = {var.semantic.c_str(), 86 | uint(var.semanticIndex), 87 | getFormat(var), 88 | slot, 89 | offset, 90 | D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 91 | uint(0)}; 92 | offset += var.GetSize(); 93 | } 94 | } 95 | }// namespace rtti -------------------------------------------------------------------------------- /Chapter4/src/Utility/ReflactableStruct.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | namespace rtti { 7 | //Interpret a variable's type in structure 8 | struct VarTypeData { 9 | enum class ScaleType : vbyte { 10 | Float, 11 | Int, 12 | UInt 13 | }; 14 | 15 | ScaleType scale; 16 | vbyte dimension; 17 | uint semanticIndex; 18 | std::string semantic; 19 | size_t GetSize() const; 20 | }; 21 | class VarTypeBase; 22 | class Struct { 23 | friend class VarTypeBase; 24 | std::vector variables; 25 | 26 | public: 27 | std::span Variables() const { return variables; } 28 | size_t structSize = 0; 29 | 30 | Struct(); 31 | Struct(Struct const&) = delete; 32 | Struct(Struct&&) = default; 33 | void GetMeshLayout(uint slot, std::vector& resultVector) const; 34 | }; 35 | class VarTypeBase { 36 | size_t offset; 37 | 38 | protected: 39 | VarTypeBase(VarTypeData&& varData); 40 | 41 | public: 42 | size_t Offset() const { return offset; } 43 | }; 44 | template 45 | class VarType : public VarTypeBase { 46 | protected: 47 | VarType(VarTypeData&& varData) : VarTypeBase(std::move(varData)) {} 48 | 49 | public: 50 | T const& Get(void const* structPtr) const { 51 | size_t ptrNum = reinterpret_cast(structPtr); 52 | return *reinterpret_cast(ptrNum + Offset()); 53 | } 54 | T& Get(void* structPtr) const { 55 | size_t ptrNum = reinterpret_cast(structPtr); 56 | return *reinterpret_cast(ptrNum + Offset()); 57 | } 58 | }; 59 | template 60 | struct Var {}; 61 | 62 | template<> 63 | struct Var : public VarType { 64 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Int, vbyte(1), uint(0), std::string(semantic)}) {} 65 | }; 66 | template<> 67 | struct Var : public VarType { 68 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::UInt, vbyte(1), uint(0), std::string(semantic)}) {} 69 | }; 70 | template<> 71 | struct Var : public VarType { 72 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Float, vbyte(1), uint(0), std::string(semantic)}) {} 73 | }; 74 | template<> 75 | struct Var : public VarType { 76 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Float, vbyte(2), uint(0), std::string(semantic)}) {} 77 | }; 78 | template<> 79 | struct Var : public VarType { 80 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Float, vbyte(3), uint(0), std::string(semantic)}) {} 81 | }; 82 | template<> 83 | struct Var : public VarType { 84 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Float, vbyte(4), uint(0), std::string(semantic)}) {} 85 | }; 86 | template<> 87 | struct Var : public VarType { 88 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::UInt, vbyte(2), uint(0), std::string(semantic)}) {} 89 | }; 90 | template<> 91 | struct Var : public VarType { 92 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::UInt, vbyte(3), uint(0), std::string(semantic)}) {} 93 | }; 94 | template<> 95 | struct Var : public VarType { 96 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::UInt, vbyte(4), uint(0), std::string(semantic)}) {} 97 | }; 98 | template<> 99 | struct Var : public VarType { 100 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Int, vbyte(2), uint(0), std::string(semantic)}) {} 101 | }; 102 | template<> 103 | struct Var : public VarType { 104 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Int, vbyte(3), uint(0), std::string(semantic)}) {} 105 | }; 106 | template<> 107 | struct Var : public VarType { 108 | Var(char const* semantic) : VarType(VarTypeData{VarTypeData::ScaleType::Int, vbyte(4), uint(0), std::string(semantic)}) {} 109 | }; 110 | }// namespace rtti -------------------------------------------------------------------------------- /Chapter4/src/Utility/StackAllocator.cpp: -------------------------------------------------------------------------------- 1 | #pragma vengine_package vengine_dll 2 | #include 3 | #include 4 | StackAllocator::StackAllocator( 5 | uint64 initCapacity, 6 | IStackAllocVisitor* visitor) 7 | : capacity(initCapacity), 8 | visitor(visitor) { 9 | } 10 | StackAllocator::Chunk StackAllocator::Allocate(uint64 targetSize) { 11 | Buffer* bf = nullptr; 12 | uint64 minSize = std::numeric_limits::max(); 13 | for (auto&& i : allocatedBuffers) { 14 | if (i.leftSize >= targetSize && i.leftSize < minSize) { 15 | minSize = i.leftSize; 16 | bf = &i; 17 | } 18 | } 19 | if (bf) { 20 | auto ofst = bf->fullSize - bf->leftSize; 21 | bf->leftSize -= targetSize; 22 | return { 23 | bf->handle, 24 | ofst}; 25 | } 26 | while (capacity < targetSize) { 27 | capacity = std::max(capacity + 1, capacity * 1.5); 28 | } 29 | auto newHandle = visitor->Allocate(capacity); 30 | allocatedBuffers.push_back(Buffer{ 31 | newHandle, 32 | capacity, 33 | capacity - targetSize}); 34 | return { 35 | newHandle, 36 | 0}; 37 | //TODO: return 38 | } 39 | StackAllocator::Chunk StackAllocator::Allocate( 40 | uint64 targetSize, 41 | uint64 align) { 42 | targetSize = std::max(targetSize, align); 43 | Buffer* bf = nullptr; 44 | uint64 offset = 0; 45 | uint64 minLeftSize = std::numeric_limits::max(); 46 | auto CalcAlign = [](uint64 value, uint64 align) -> uint64 { 47 | return (value + (align - 1)) & ~(align - 1); 48 | }; 49 | struct Result { 50 | uint64 offset; 51 | uint64 leftSize; 52 | }; 53 | auto GetLeftSize = [&](uint64 leftSize, uint64 size) -> std::optional { 54 | uint64 offset = size - leftSize; 55 | uint64 alignedOffset = CalcAlign(offset, align); 56 | uint64 afterAllocSize = targetSize + alignedOffset; 57 | if (afterAllocSize > size) return {}; 58 | return Result{alignedOffset, size - afterAllocSize}; 59 | }; 60 | for (auto&& i : allocatedBuffers) { 61 | auto result = GetLeftSize(i.leftSize, i.fullSize); 62 | if (!result.has_value()) continue; 63 | auto resultValue = result.value(); 64 | if (resultValue.leftSize < minLeftSize) { 65 | minLeftSize = resultValue.leftSize; 66 | offset = resultValue.offset; 67 | bf = &i; 68 | } 69 | } 70 | if (bf) { 71 | bf->leftSize = minLeftSize; 72 | return { 73 | bf->handle, 74 | offset}; 75 | } 76 | while (capacity < targetSize) { 77 | capacity = std::max(capacity + 1, capacity * 1.5); 78 | } 79 | auto newHandle = visitor->Allocate(capacity); 80 | allocatedBuffers.push_back(Buffer{ 81 | newHandle, 82 | capacity, 83 | capacity - targetSize}); 84 | return { 85 | newHandle, 86 | 0}; 87 | } 88 | void StackAllocator::Clear() { 89 | for (auto&& i : allocatedBuffers) { 90 | i.leftSize = i.fullSize; 91 | } 92 | } 93 | StackAllocator::~StackAllocator() { 94 | for (auto&& i : allocatedBuffers) { 95 | visitor->DeAllocate(i.handle); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Chapter4/src/Utility/StackAllocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | class IStackAllocVisitor { 4 | public: 5 | virtual uint64 Allocate(uint64 size) = 0; 6 | virtual void DeAllocate(uint64 handle) = 0; 7 | }; 8 | class StackAllocator { 9 | IStackAllocVisitor* visitor; 10 | uint64 capacity; 11 | struct Buffer { 12 | uint64 handle; 13 | uint64 fullSize; 14 | uint64 leftSize; 15 | }; 16 | std::vector allocatedBuffers; 17 | 18 | public: 19 | StackAllocator( 20 | uint64 initCapacity, 21 | IStackAllocVisitor* visitor); 22 | ~StackAllocator(); 23 | struct Chunk { 24 | uint64 handle; 25 | uint64 offset; 26 | }; 27 | Chunk Allocate( 28 | uint64 targetSize); 29 | Chunk Allocate( 30 | uint64 targetSize, 31 | uint64 align); 32 | void Clear(); 33 | }; 34 | -------------------------------------------------------------------------------- /Chapter4/src/Win32Application.cpp: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #include "stdafx.h" 13 | #include "Win32Application.h" 14 | 15 | HWND Win32Application::m_hwnd = nullptr; 16 | 17 | int Win32Application::Run(DXSample* pSample, HINSTANCE hInstance, int nCmdShow) 18 | { 19 | // Parse the command line parameters 20 | int argc; 21 | LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc); 22 | pSample->ParseCommandLineArgs(argv, argc); 23 | LocalFree(argv); 24 | 25 | // Initialize the window class. 26 | WNDCLASSEX windowClass = { 0 }; 27 | windowClass.cbSize = sizeof(WNDCLASSEX); 28 | windowClass.style = CS_HREDRAW | CS_VREDRAW; 29 | windowClass.lpfnWndProc = WindowProc; 30 | windowClass.hInstance = hInstance; 31 | windowClass.hCursor = LoadCursor(NULL, IDC_ARROW); 32 | windowClass.lpszClassName = L"DXSampleClass"; 33 | RegisterClassEx(&windowClass); 34 | 35 | RECT windowRect = { 0, 0, static_cast(pSample->GetWidth()), static_cast(pSample->GetHeight()) }; 36 | AdjustWindowRect(&windowRect, WS_OVERLAPPEDWINDOW, FALSE); 37 | 38 | // Create the window and store a handle to it. 39 | m_hwnd = CreateWindow( 40 | windowClass.lpszClassName, 41 | pSample->GetTitle(), 42 | WS_OVERLAPPEDWINDOW, 43 | CW_USEDEFAULT, 44 | CW_USEDEFAULT, 45 | windowRect.right - windowRect.left, 46 | windowRect.bottom - windowRect.top, 47 | nullptr, // We have no parent window. 48 | nullptr, // We aren't using menus. 49 | hInstance, 50 | pSample); 51 | 52 | // Initialize the sample. OnInit is defined in each child-implementation of DXSample. 53 | pSample->OnInit(); 54 | 55 | ShowWindow(m_hwnd, nCmdShow); 56 | 57 | // Main sample loop. 58 | MSG msg = {}; 59 | while (msg.message != WM_QUIT) 60 | { 61 | // Process any messages in the queue. 62 | if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 63 | { 64 | TranslateMessage(&msg); 65 | DispatchMessage(&msg); 66 | } 67 | } 68 | 69 | pSample->OnDestroy(); 70 | 71 | // Return this part of the WM_QUIT message to Windows. 72 | return static_cast(msg.wParam); 73 | } 74 | 75 | // Main message handler for the sample. 76 | LRESULT CALLBACK Win32Application::WindowProc(HWND hWnd, uint32_t message, WPARAM wParam, LPARAM lParam) 77 | { 78 | DXSample* pSample = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); 79 | 80 | switch (message) 81 | { 82 | case WM_CREATE: 83 | { 84 | // Save the DXSample* passed in to CreateWindow. 85 | LPCREATESTRUCT pCreateStruct = reinterpret_cast(lParam); 86 | SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast(pCreateStruct->lpCreateParams)); 87 | } 88 | return 0; 89 | 90 | case WM_KEYDOWN: 91 | if (pSample) 92 | { 93 | pSample->OnKeyDown(static_cast(wParam)); 94 | } 95 | return 0; 96 | 97 | case WM_KEYUP: 98 | if (pSample) 99 | { 100 | pSample->OnKeyUp(static_cast(wParam)); 101 | } 102 | return 0; 103 | 104 | case WM_PAINT: 105 | if (pSample) 106 | { 107 | pSample->OnUpdate(); 108 | pSample->OnRender(); 109 | } 110 | return 0; 111 | 112 | case WM_DESTROY: 113 | PostQuitMessage(0); 114 | return 0; 115 | } 116 | 117 | // Handle any messages the switch statement didn't. 118 | return DefWindowProc(hWnd, message, wParam, lParam); 119 | } 120 | -------------------------------------------------------------------------------- /Chapter4/src/Win32Application.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | #pragma once 13 | 14 | #include "DXSample.h" 15 | 16 | class DXSample; 17 | 18 | class Win32Application 19 | { 20 | public: 21 | static int Run(DXSample* pSample, HINSTANCE hInstance, int nCmdShow); 22 | static HWND GetHwnd() { return m_hwnd; } 23 | 24 | protected: 25 | static LRESULT CALLBACK WindowProc(HWND hWnd, uint32_t message, WPARAM wParam, LPARAM lParam); 26 | 27 | private: 28 | static HWND m_hwnd; 29 | }; 30 | -------------------------------------------------------------------------------- /Chapter4/src/stdafx.h: -------------------------------------------------------------------------------- 1 | //********************************************************* 2 | // 3 | // Copyright (c) Microsoft. All rights reserved. 4 | // This code is licensed under the MIT License (MIT). 5 | // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 6 | // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY 7 | // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR 8 | // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. 9 | // 10 | //********************************************************* 11 | 12 | // stdafx.h : include file for standard system include files, 13 | // or project specific include files that are used frequently, but 14 | // are changed infrequently. 15 | 16 | #pragma once 17 | 18 | #ifndef WIN32_LEAN_AND_MEAN 19 | #define WIN32_LEAN_AND_MEAN// Exclude rarely-used stuff from Windows headers. 20 | #endif 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "d3dx12.h" 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | -------------------------------------------------------------------------------- /Chapter4/src/xmake.lua: -------------------------------------------------------------------------------- 1 | BuildProject({ 2 | projectName = "Better-SimpleBox", 3 | projectType = "binary", 4 | debugEvent = function() 5 | add_defines("_DEBUG") 6 | end, 7 | releaseEvent = function() 8 | add_defines("NDEBUG") 9 | end, 10 | exception = true 11 | }) 12 | add_defines("_XM_NO_INTRINSICS_=1", "NOMINMAX", "UNICODE", "m128_f32=vector4_f32", "m128_u32=vector4_u32") 13 | add_files("**.cpp") 14 | add_includedirs("./") 15 | add_syslinks("User32", "kernel32", "Gdi32", "Shell32", "DXGI", "D3D12", "D3DCompiler") 16 | after_build(function(target) 17 | src_path = "shader/" 18 | os.cp(src_path .. "*", target:targetdir() .. "/shader/") 19 | end) -------------------------------------------------------------------------------- /Chapter4/xmake.lua: -------------------------------------------------------------------------------- 1 | set_config("toolchain", "clang-cl") 2 | add_rules("mode.release", "mode.debug") 3 | option("is_clang") 4 | add_csnippets("is_clang", "return (__clang__)?0:-1;", { 5 | tryrun = true 6 | }) 7 | option_end() 8 | option("is_msvc") 9 | add_csnippets("is_msvc", "return (_MSC_VER)?0:-1;", { 10 | tryrun = true 11 | }) 12 | option_end() 13 | 14 | 15 | option_end() 16 | function GetValue(funcOrValue) 17 | if type(funcOrValue) == 'function' then 18 | return funcOrValue() 19 | else 20 | return funcOrValue 21 | end 22 | end 23 | 24 | --[[ 25 | BuildProject({ 26 | projectName = xxx, 27 | projectType = xxx, 28 | unityBuildBatch = n, 29 | exception = true/false, 30 | releaseEvent = function() 31 | end, 32 | debugEvent = function() 33 | end 34 | }) 35 | ]] 36 | if is_mode("debug") then 37 | set_targetdir("bin/debug") 38 | else 39 | set_targetdir("bin/release") 40 | end 41 | 42 | function BuildProject(config) 43 | local projectName = GetValue(config.projectName) 44 | if projectName == nil then 45 | return 46 | end 47 | target(projectName) 48 | set_languages("clatest", "cxx20") 49 | local projectType = GetValue(config.projectType) 50 | if projectType ~= nil then 51 | set_kind(projectType) 52 | end 53 | if UseUnityBuild then 54 | local unityBuildBatch = GetValue(config.unityBuildBatch) 55 | if (unityBuildBatch ~= nil) and (unityBuildBatch > 1) then 56 | add_rules("c.unity_build", { 57 | batchsize = unityBuildBatch 58 | }) 59 | add_rules("c++.unity_build", { 60 | batchsize = unityBuildBatch 61 | }) 62 | end 63 | end 64 | local value = GetValue(config.exception) 65 | if (value ~= nil) and value then 66 | if has_config("is_msvc") then 67 | add_cxflags("/EHsc") 68 | else 69 | add_cxflags("-fexceptions") 70 | end 71 | elseif not has_config("is_msvc") then 72 | add_cxflags("-fno-exceptions") 73 | end 74 | set_warnings("none") 75 | if is_mode("debug") then 76 | set_optimize("none") 77 | if is_plat("windows") then 78 | set_runtimes("MDd") 79 | end 80 | if has_config("is_msvc") then 81 | add_cxflags("/GS", "/Gd"); 82 | -- Not Clang-cl 83 | if not has_config("is_clang") then 84 | add_cxflags("/Zc:preprocessor") 85 | end 86 | end 87 | local event = GetValue(config.debugEvent) 88 | if (type(event) == "function") then 89 | event() 90 | end 91 | else 92 | set_optimize("fastest") 93 | if is_plat("windows") then 94 | set_runtimes("MD") 95 | end 96 | if has_config("is_msvc") then 97 | add_cxflags("/Oy", "/GS-", "/Gd", "/Oi", "/Ot", "/GT", "/Ob2") 98 | -- Not Clang-cl 99 | if not has_config("is_clang") then 100 | add_cxflags("/GL", "/Zc:preprocessor", "/QIntel-jcc-erratum") 101 | end 102 | end 103 | local event = GetValue(config.releaseEvent) 104 | if (type(event) == "function") then 105 | event() 106 | end 107 | end 108 | end 109 | add_subdirs("src") 110 | --------------------------------------------------------------------------------