├── DX12Application.png ├── Resources ├── texture.png ├── BlueNoise64x64.png ├── StaticSamplers.hlsl ├── cube.obj ├── MeshShader.hlsl ├── TestShader.hlsl └── RaytracingShaders.hlsl ├── .gitmodules ├── Application ├── packages.config ├── WinImgui.h ├── Game.h ├── WinImgui.cpp ├── Application.vcxproj.filters ├── WinMain.cpp ├── Application.vcxproj └── OBJ_Loader.h ├── DX12Base ├── packages.config ├── Dx12Math.h ├── WindowHelper.h ├── Dx12Utilities.h ├── DX12Base.vcxproj.filters ├── WindowInput.h ├── Dx12Utilities.cpp ├── Dx12RayTracing.h ├── DX12Base.vcxproj ├── WindowHelper.cpp └── Dx12Device.h ├── LICENSE ├── DirectXTex ├── LICENSE ├── WICTextureLoader │ ├── WICTextureLoader12.h │ └── WICTextureLoader12.cpp └── ReadMe.txt ├── DX12Base.sln ├── README.md └── .gitignore /DX12Application.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebh/Dx12Base/HEAD/DX12Application.png -------------------------------------------------------------------------------- /Resources/texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebh/Dx12Base/HEAD/Resources/texture.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "imgui"] 2 | path = imgui 3 | url = https://github.com/ocornut/imgui 4 | -------------------------------------------------------------------------------- /Resources/BlueNoise64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebh/Dx12Base/HEAD/Resources/BlueNoise64x64.png -------------------------------------------------------------------------------- /Application/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /DX12Base/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Resources/StaticSamplers.hlsl: -------------------------------------------------------------------------------- 1 | 2 | // Dx12 common static samplers 3 | // More can be added in RootSignature::RootSignature in Dx12Device.cpp 4 | 5 | 6 | 7 | SamplerState SamplerPointClamp : register(s0); 8 | SamplerState SamplerLinearClamp : register(s1); 9 | 10 | SamplerState SamplerPointRepeat : register(s2); 11 | SamplerState SamplerLinearRepeat : register(s3); 12 | 13 | 14 | -------------------------------------------------------------------------------- /Application/WinImgui.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #define D_ENABLE_IMGUI 1 5 | 6 | 7 | #include 8 | 9 | #if D_ENABLE_IMGUI 10 | #include 11 | #include 12 | #include 13 | extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 14 | #endif // D_ENABLE_IMGUI 15 | 16 | 17 | void WinImguiInitialise(const HWND hwnd); 18 | 19 | void WinImguiNewFrame(); 20 | 21 | void WinImguiRender(); 22 | 23 | void WinImguiShutdown(); 24 | 25 | -------------------------------------------------------------------------------- /Resources/cube.obj: -------------------------------------------------------------------------------- 1 | 2 | v -0.500000 -0.500000 0.500000 3 | v 0.500000 -0.500000 0.500000 4 | v -0.500000 0.500000 0.500000 5 | v 0.500000 0.500000 0.500000 6 | v -0.500000 0.500000 -0.500000 7 | v 0.500000 0.500000 -0.500000 8 | v -0.500000 -0.500000 -0.500000 9 | v 0.500000 -0.500000 -0.500000 10 | 11 | vt 0.000000 0.000000 12 | vt 1.000000 0.000000 13 | vt 0.000000 1.000000 14 | vt 1.000000 1.000000 15 | 16 | vn 0.000000 0.000000 1.000000 17 | vn 0.000000 1.000000 0.000000 18 | vn 0.000000 0.000000 -1.000000 19 | vn 0.000000 -1.000000 0.000000 20 | vn 1.000000 0.000000 0.000000 21 | vn -1.000000 0.000000 0.000000 22 | 23 | s 1 24 | f 1/1/1 2/2/1 3/3/1 25 | f 3/3/1 2/2/1 4/4/1 26 | s 2 27 | f 3/1/2 4/2/2 5/3/2 28 | f 5/3/2 4/2/2 6/4/2 29 | s 3 30 | f 5/4/3 6/3/3 7/2/3 31 | f 7/2/3 6/3/3 8/1/3 32 | s 4 33 | f 7/1/4 8/2/4 1/3/4 34 | f 1/3/4 8/2/4 2/4/4 35 | s 5 36 | f 2/1/5 8/2/5 4/3/5 37 | f 4/3/5 8/2/5 6/4/5 38 | s 6 39 | f 7/1/6 1/2/6 5/3/6 40 | f 5/3/6 1/2/6 3/4/6 41 | 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 SebH 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /DirectXTex/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Microsoft Corp 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | software and associated documentation files (the "Software"), to deal in the Software 7 | without restriction, including without limitation the rights to use, copy, modify, 8 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all copies 13 | or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 16 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 17 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 18 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 19 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE 20 | OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /DX12Base/Dx12Math.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "DirectXMath.h" 4 | using namespace DirectX; 5 | 6 | 7 | 8 | typedef signed char s8; 9 | typedef unsigned char u8; 10 | //typedef unsigned char byte; 11 | 12 | typedef unsigned int uint; 13 | typedef int sint; 14 | 15 | typedef UINT64 uint64; 16 | typedef INT64 sint64; 17 | 18 | typedef short word; 19 | typedef uint dword; 20 | 21 | typedef XMMATRIX float4x4; 22 | typedef XMVECTOR float4; 23 | 24 | 25 | 26 | const float Pi = 3.14159265359f; 27 | 28 | 29 | 30 | template 31 | inline T Clamp(T x, T MinX, T MaxX) 32 | { 33 | return x > MaxX ? MaxX : (x < MinX ? MinX : x); 34 | } 35 | 36 | template 37 | inline T Sqr(T x) { return x * x; } 38 | 39 | inline float Saturate(float x) 40 | { 41 | return x > 1.0f ? 1.0f : (x < 0.0f ? 0.0f : x); 42 | } 43 | 44 | inline float Lerp(float a, float b, float x) 45 | { 46 | return a + Saturate(x) * (b - a); 47 | } 48 | 49 | inline float DegToRad(float deg) 50 | { 51 | return deg / 180.0f * Pi; 52 | } 53 | 54 | inline float RadToDeg(float rad) 55 | { 56 | return rad * 180.0f / Pi; 57 | } 58 | 59 | inline uint RoundUp(uint Value, uint Alignement) 60 | { 61 | uint Var = Value + Alignement - 1; 62 | return Alignement * (Var / Alignement); 63 | } 64 | 65 | inline uint64 RoundUp(uint64 Value, uint64 Alignement) 66 | { 67 | uint64 Var = Value + Alignement - 1; 68 | return Alignement * (Var / Alignement); 69 | } 70 | 71 | 72 | -------------------------------------------------------------------------------- /Resources/MeshShader.hlsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #include "StaticSamplers.hlsl" 5 | 6 | 7 | 8 | struct MeshVertexInput 9 | { 10 | float3 Position : POSITION; 11 | float3 Normal : NORMAL; 12 | float2 UV : TEXCOORD0; 13 | }; 14 | 15 | struct MeshVertexOutput 16 | { 17 | float4 SvPosition : SV_POSITION; 18 | float3 Normal : NORMAL; 19 | float2 UV : TEXCOORD0; 20 | }; 21 | 22 | cbuffer MeshConstantBuffer : register(b0) 23 | { 24 | float4x4 ViewProjectionMatrix; 25 | float4x4 MeshWorldMatrix; 26 | float VoxelisationVolumeDepth; 27 | float pad0[3]; 28 | } 29 | 30 | Texture2D MeshTexture : register(t0); 31 | 32 | MeshVertexOutput MeshVertexShader(MeshVertexInput input) 33 | { 34 | MeshVertexOutput output; 35 | 36 | output.SvPosition = mul(ViewProjectionMatrix, mul(MeshWorldMatrix, float4(input.Position, 1.0))); 37 | 38 | output.Normal = input.Normal; 39 | output.UV = input.UV; 40 | 41 | return output; 42 | } 43 | 44 | float4 MeshPixelShader(MeshVertexOutput input) : SV_TARGET 45 | { 46 | //return float4(input.Normal.xyz, 1.0f); 47 | //return float4(input.UV.xy, 0.0f, 1.0f); 48 | return MeshTexture.Sample(SamplerLinearClamp, float2(input.UV.xy)); 49 | } 50 | 51 | RWTexture3D OutVolumeTexture : register(u0); 52 | 53 | void MeshVoxelisationPixelShader(MeshVertexOutput input) 54 | { 55 | const float4 Data = MeshTexture.Sample(SamplerLinearClamp, float2(input.UV.xy)); 56 | OutVolumeTexture[uint3(input.SvPosition.xy, input.SvPosition.z * VoxelisationVolumeDepth)] = Data; 57 | } 58 | 59 | 60 | -------------------------------------------------------------------------------- /DX12Base/WindowHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "WindowInput.h" 6 | 7 | #include 8 | 9 | 10 | // Return true if an event has been intercepted and should not be sent down to the game 11 | typedef bool(*WindowTopLayerProcHandler)(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); 12 | 13 | 14 | class WindowHelper 15 | { 16 | public: 17 | WindowHelper( 18 | HINSTANCE hInstance, 19 | const RECT& clientRect, 20 | int nCmdShow, 21 | LPCWSTR windowName); 22 | ~WindowHelper(); 23 | 24 | void showWindow(); 25 | 26 | bool translateSingleMessage(MSG& msg); 27 | 28 | const WindowInputData& getInputData() 29 | { 30 | return mInput; 31 | } 32 | void clearInputEvents() 33 | { 34 | mInput.mInputEvents.clear(); 35 | } 36 | 37 | const HWND getHwnd() { return mHWnd; } 38 | 39 | void processMouseMessage(UINT message, WPARAM wParam, LPARAM lParam); 40 | void processKeyMessage(UINT message, WPARAM wParam, LPARAM lParam); 41 | void processWindowSizeMessage(UINT message, WPARAM wParam, LPARAM lParam); 42 | 43 | void setWindowResizedCallback(std::function windowResizedCallback) { mWindowResizedCallback = windowResizedCallback; } 44 | 45 | private: 46 | WindowHelper(); 47 | 48 | HINSTANCE mHInstance; /// The application instance 49 | HWND mHWnd; /// The handle for the window, filled by a function 50 | WNDCLASSEX mWc; /// This struct holds information for the window class 51 | RECT mClientRect; /// The client rectangle where we render into 52 | int mNCmdShow; /// Window show cmd 53 | 54 | WindowInputData mInput; /// input event and status (mouse, keyboard, etc.) 55 | 56 | std::function mWindowResizedCallback = [&](LPARAM lParam) {}; 57 | }; 58 | 59 | 60 | -------------------------------------------------------------------------------- /DX12Base/Dx12Utilities.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Dx12Device.h" 4 | 5 | 6 | 7 | 8 | class RenderBufferGenericDynamic 9 | { 10 | public: 11 | RenderBufferGenericDynamic( 12 | uint64 TotalSizeInBytes, D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE); 13 | virtual ~RenderBufferGenericDynamic(); 14 | 15 | void* Map(); 16 | void UnmapAndUpload(); 17 | 18 | RenderBufferGeneric& getRenderBuffer() { return mRenderBuffer; } 19 | 20 | protected: 21 | 22 | private: 23 | RenderBufferGenericDynamic(); 24 | RenderBufferGenericDynamic(RenderBufferGenericDynamic&); 25 | 26 | RenderBufferGeneric* mFrameUploadBuffers[frameBufferCount]; 27 | RenderBufferGeneric mRenderBuffer; 28 | }; 29 | 30 | 31 | 32 | 33 | //////////////////////////////////////////////////////////////////////////////////////////////////// 34 | //////////////////////////////////////////////////////////////////////////////////////////////////// 35 | //////////////////////////////////////////////////////////////////////////////////////////////////// 36 | 37 | 38 | 39 | 40 | class RenderTextureDynamic 41 | { 42 | public: 43 | RenderTextureDynamic( 44 | unsigned int width, unsigned int height, 45 | unsigned int depth, DXGI_FORMAT format, 46 | D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE); 47 | virtual ~RenderTextureDynamic(); 48 | 49 | // Map and Unmpap have not been tested so far 50 | void* Map(); 51 | void UnmapAndUpload(); 52 | 53 | void Upload(void* DataPtr, unsigned int RowPitchByte, unsigned int SlicePitchByte); 54 | 55 | UINT64 getWidth() { return mRenderTexture.getD3D12Resource()->GetDesc().Width; } 56 | UINT64 getHeight() { return mRenderTexture.getD3D12Resource()->GetDesc().Height; } 57 | RenderTexture& getRenderTexture() { return mRenderTexture; } 58 | 59 | protected: 60 | 61 | private: 62 | RenderTextureDynamic(); 63 | RenderTextureDynamic(RenderTextureDynamic&); 64 | 65 | unsigned int mInitDataCopySizeByte = 0; 66 | unsigned int mRowPitchByte = 0; 67 | unsigned int mSlicePitchByte = 0; 68 | 69 | ID3D12Resource* mFrameUploadTextures[frameBufferCount]; 70 | RenderTexture mRenderTexture; 71 | }; 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /DX12Base/DX12Base.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 10 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 11 | 12 | 13 | 14 | 15 | Source Files 16 | 17 | 18 | Source Files 19 | 20 | 21 | Source Files 22 | 23 | 24 | Source Files 25 | 26 | 27 | Source Files 28 | 29 | 30 | 31 | 32 | Source Files 33 | 34 | 35 | Source Files 36 | 37 | 38 | Source Files 39 | 40 | 41 | Source Files 42 | 43 | 44 | Source Files 45 | 46 | 47 | Source Files 48 | 49 | 50 | Source Files 51 | 52 | 53 | Source Files 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Resources/TestShader.hlsl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #include "StaticSamplers.hlsl" 5 | 6 | 7 | 8 | cbuffer MyBuffer : register(b0) 9 | { 10 | float4 FloatVector; 11 | } 12 | 13 | 14 | struct VertexInput 15 | { 16 | uint VertexID : SV_VertexID; 17 | float3 position : POSITION; 18 | float2 uv : TEXCOORD0; 19 | }; 20 | 21 | struct VertexOutput 22 | { 23 | float4 position : SV_POSITION; 24 | float2 uv : TEXCOORD0; 25 | }; 26 | 27 | VertexOutput ColorVertexShader(VertexInput input) 28 | { 29 | VertexOutput output; // TODO init to 0 30 | 31 | output.position = float4(input.position.xyz, 1.0); 32 | output.uv = input.uv; 33 | 34 | return output; 35 | } 36 | 37 | //StructuredBuffer buffer : register(t0); 38 | Texture2D texture0 : register(t0); 39 | 40 | Texture2D BindlessTextures[ROOT_BINDLESS_SRV_COUNT] : register(ROOT_BINDLESS_SRV_START_REGISTER); 41 | 42 | float4 ColorPixelShader(VertexOutput input) : SV_TARGET 43 | { 44 | const uint TileCountXY = 8; 45 | const uint TilePixelSize = 32; 46 | if (ROOT_BINDLESS_SRV_COUNT==64 && 47 | all(input.position.xy >= 0) && all(input.position.xy < TileCountXY * TilePixelSize)) 48 | { 49 | uint textureIndex = (uint(input.position.y) / TilePixelSize) * TileCountXY + uint(input.position.x) / TilePixelSize; 50 | return BindlessTextures[NonUniformResourceIndex(textureIndex)].Sample(SamplerLinearRepeat, float2(float2(input.position.xy) / float(TilePixelSize))); 51 | } 52 | 53 | return texture0.Sample(SamplerLinearClamp, float2(input.uv.x, 1.0f - input.uv.y)); 54 | } 55 | 56 | 57 | VertexOutput TriangleVertexShader(uint VertexID : SV_VertexID) 58 | { 59 | VertexOutput output; // TODO init to 0 60 | 61 | output.position = float4(VertexID == 2 ? 3.0 : -1.0, VertexID == 1 ? 3.0 : -1.0, 0.1, 1.0); 62 | output.uv = (output.position.xy + 1.0) * 0.25; 63 | 64 | return output; 65 | } 66 | 67 | float4 TrianglePixelShader(VertexOutput input) : SV_TARGET 68 | { 69 | return float4(input.uv, 0, 0); 70 | } 71 | 72 | float4 ToneMapPS(VertexOutput input) : SV_TARGET 73 | { 74 | float4 RGBA = texture0.Sample(SamplerPointClamp, input.uv); 75 | return float4(pow(RGBA.rgb, 1.0f / 2.2f), RGBA.a); 76 | } 77 | 78 | 79 | RWBuffer myBuffer : register(u0); 80 | 81 | [numthreads(1, 1, 1)] 82 | void MainComputeShader(uint3 groupId : SV_GroupID, uint groupIndex : SV_GroupIndex) 83 | { 84 | myBuffer[0] = FloatVector; 85 | } 86 | 87 | 88 | -------------------------------------------------------------------------------- /DX12Base.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dx12Base", "DX12Base\dx12Base.vcxproj", "{9412077D-D368-4DBD-AACB-6DBA3618CF12}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Application", "Application\Application.vcxproj", "{2CA77969-0EC4-4607-93CC-C63915A2C01F}" 9 | ProjectSection(ProjectDependencies) = postProject 10 | {9412077D-D368-4DBD-AACB-6DBA3618CF12} = {9412077D-D368-4DBD-AACB-6DBA3618CF12} 11 | EndProjectSection 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|x64 = Debug|x64 16 | Debug|x86 = Debug|x86 17 | Release|x64 = Release|x64 18 | Release|x86 = Release|x86 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Debug|x64.ActiveCfg = Debug|x64 22 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Debug|x64.Build.0 = Debug|x64 23 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Debug|x64.Deploy.0 = Debug|x64 24 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Debug|x86.ActiveCfg = Debug|Win32 25 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Debug|x86.Build.0 = Debug|Win32 26 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Release|x64.ActiveCfg = Release|x64 27 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Release|x64.Build.0 = Release|x64 28 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Release|x86.ActiveCfg = Release|Win32 29 | {9412077D-D368-4DBD-AACB-6DBA3618CF12}.Release|x86.Build.0 = Release|Win32 30 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Debug|x64.ActiveCfg = Debug|x64 31 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Debug|x64.Build.0 = Debug|x64 32 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Debug|x86.ActiveCfg = Debug|Win32 33 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Debug|x86.Build.0 = Debug|Win32 34 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Release|x64.ActiveCfg = Release|x64 35 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Release|x64.Build.0 = Release|x64 36 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Release|x86.ActiveCfg = Release|Win32 37 | {2CA77969-0EC4-4607-93CC-C63915A2C01F}.Release|x86.Build.0 = Release|Win32 38 | EndGlobalSection 39 | GlobalSection(SolutionProperties) = preSolution 40 | HideSolutionNode = FALSE 41 | EndGlobalSection 42 | EndGlobal 43 | -------------------------------------------------------------------------------- /DirectXTex/WICTextureLoader/WICTextureLoader12.h: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------------------------------- 2 | // File: WICTextureLoader12.h 3 | // 4 | // Function for loading a WIC image and creating a Direct3D runtime texture for it 5 | // (auto-generating mipmaps if possible) 6 | // 7 | // Note: Assumes application has already called CoInitializeEx 8 | // 9 | // Note these functions are useful for images created as simple 2D textures. For 10 | // more complex resources, DDSTextureLoader is an excellent light-weight runtime loader. 11 | // For a full-featured DDS file reader, writer, and texture processing pipeline see 12 | // the 'Texconv' sample and the 'DirectXTex' library. 13 | // 14 | // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 15 | // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 16 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 17 | // PARTICULAR PURPOSE. 18 | // 19 | // Copyright (c) Microsoft Corporation. All rights reserved. 20 | // 21 | // http://go.microsoft.com/fwlink/?LinkId=248926 22 | // http://go.microsoft.com/fwlink/?LinkID=615561 23 | //-------------------------------------------------------------------------------------- 24 | 25 | // Modified by SebH 26 | 27 | #pragma once 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | namespace DirectX 34 | { 35 | enum WIC_LOADER_FLAGS 36 | { 37 | WIC_LOADER_DEFAULT = 0, 38 | WIC_LOADER_FORCE_SRGB = 0x1, 39 | WIC_LOADER_IGNORE_SRGB = 0x2, 40 | WIC_LOADER_MIP_AUTOGEN = 0x4, 41 | WIC_LOADER_MIP_RESERVE = 0x8, 42 | }; 43 | 44 | struct TextureData 45 | { 46 | UINT dataSizeInByte = 0; 47 | UINT width = 0; 48 | UINT height = 0; 49 | UINT mipCount = 0; 50 | DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; 51 | D3D12_SUBRESOURCE_DATA& subresource; 52 | std::unique_ptr& decodedData; 53 | 54 | TextureData(D3D12_SUBRESOURCE_DATA& _subresource, std::unique_ptr& _decodedData) 55 | : subresource(_subresource) 56 | , decodedData(_decodedData) 57 | {} 58 | 59 | private: 60 | TextureData(); 61 | TextureData(TextureData&); 62 | }; 63 | 64 | // Standard version 65 | HRESULT __cdecl LoadWICTextureFromFile( 66 | _In_z_ const wchar_t* szFileName, 67 | TextureData& texData, 68 | size_t maxsize = 0, 69 | unsigned int loadFlags = WIC_LOADER_DEFAULT); 70 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dx12Base 2 | 3 | ![dx12appscreenshot](https://github.com/sebh/Dx12Base/blob/master/DX12Application.png) 4 | 5 | A small DirectX 12 program I use to test shaders and techniques (so windows only). It is meant to be simple and straightforward. Nothing fancy to see here: plenty of _engines_ already exist out there. This is just a thin abstraction over DX12 so it is still important to understand its core before using it. But it makes development of demos and prototypes easier for me at least. The DX11 version of this is available [here](https://github.com/sebh/Dx11Base). 6 | 7 | Features are 8 | * Simple class helpers above DirectX 12.0 states and resources 9 | * Simple resource upload is in place for now. Utilies a given for per frame update of dynamic textures/buffers. 10 | * Simple RT support for mesh and material built in SBT with global and local shaders. 11 | * Simple PSO caching. 12 | * Live update of shaders with saving via `ctrl+s` 13 | * UI achieved with [Dear ImGui](https://github.com/ocornut/imgui) 14 | * Performance measured with GPU timers and reported in UI (tested on intel and nvidia so far) 15 | * Simple window and input management (could be improved) 16 | * Easy to debug with [RenderDoc](https://renderdoc.org/) or [nSight](https://developer.nvidia.com/nsight-graphics) for instance 17 | 18 | When cloning the project the first time: 19 | 1. Update submodules (run `git submodule update`) 20 | 2. Open the solution 21 | 3. In Visual Studio, change the _Application_ project _Working Directory_ from `$(ProjectDir)` to `$(SolutionDir)` 22 | 4. Make sure you select a windows SDK and a platform toolset you have locally on your computer for both projects 23 | 5. Copy dxcompiler.dll and dxil.dll from your windows SDK into $(SolutionDir) (I really need to fix that...) 24 | 6. Select _Application_ as the startup project, hit F5 25 | 26 | Submodules 27 | * [imgui](https://github.com/ocornut/imgui) V1.85 supported (change the submodule head to the commit corresponding to the version) 28 | 29 | Have fun and do not hesitate to send back suggestions. 30 | 31 | Seb 32 | 33 | 34 | PS: example of what could be improved: 35 | - Better uploading code (do not allocate one uploading resource per texture/buffer) 36 | - Delayed resource deletion when not needed anymore 37 | - Better desriptors management (instead of a simple linear allocation without reuse of released elements) 38 | - Texture mip generation 39 | - Cubemap textures 40 | - Sparse textures 41 | - Mesh shaders 42 | - etc. -------------------------------------------------------------------------------- /DX12Base/WindowInput.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | enum InputKey 6 | { 7 | kLeft, 8 | kRight, 9 | kUp, 10 | kDown, 11 | kSpace, 12 | kNumpad0, 13 | kNumpad1, 14 | kNumpad2, 15 | kNumpad3, 16 | kNumpad4, 17 | kNumpad5, 18 | kNumpad6, 19 | kNumpad7, 20 | kNumpad8, 21 | kNumpad9, 22 | kMultiply, 23 | kAdd, 24 | kSeparator, 25 | kSubtract, 26 | kDecimal, 27 | kDivide, 28 | kF1, 29 | kF2, 30 | kF3, 31 | kF4, 32 | kF5, 33 | kF6, 34 | kF7, 35 | kF8, 36 | kF9, 37 | kF10, 38 | kF11, 39 | kF12, 40 | 41 | kShift, // event and input status 42 | kControl, // event and input status 43 | kLshift, // never an event, only set on the input status 44 | kRshift, // never an event, only set on the input status 45 | kLcontrol, // never an event, only set on the input status 46 | kRcontrol, // never an event, only set on the input status 47 | 48 | k0, 49 | k1, 50 | k2, 51 | k3, 52 | k4, 53 | k5, 54 | k6, 55 | k7, 56 | k8, 57 | k9, 58 | kA, 59 | kB, 60 | kC, 61 | kD, 62 | kE, 63 | kF, 64 | kG, 65 | kH, 66 | kI, 67 | kJ, 68 | kK, 69 | kL, 70 | kM, 71 | kN, 72 | kO, 73 | kP, 74 | kQ, 75 | kR, 76 | kS, 77 | kT, 78 | kU, 79 | kV, 80 | kW, 81 | kX, 82 | kY, 83 | kZ, 84 | 85 | kCount, 86 | kUnknown 87 | }; 88 | enum InputMouseButton 89 | { 90 | mbLeft, 91 | mbMiddle, 92 | mbRight, 93 | mbCount 94 | }; 95 | enum InputEventType 96 | { 97 | etKeyUp, 98 | etKeyDown, 99 | etKeyChar, 100 | etMouseMoved, 101 | etMouseButtonUp, 102 | etMouseButtonDown, 103 | etMouseButtonDoubleClick, 104 | etCount 105 | }; 106 | 107 | struct InputEvent 108 | { 109 | InputEventType type; 110 | union 111 | { 112 | InputKey key; 113 | InputMouseButton mouseButton; 114 | }; 115 | int mouseX; 116 | int mouseY; 117 | }; 118 | 119 | struct WindowInputStatus 120 | { 121 | 122 | bool keys[kCount]; 123 | bool mouseButtons[mbCount]; 124 | int mouseX; 125 | int mouseY; 126 | 127 | void init() 128 | { 129 | memset(this, 0, sizeof(WindowInputStatus)); 130 | } 131 | 132 | }; 133 | 134 | typedef std::vector WindowInputEventList; 135 | 136 | struct WindowInputData 137 | { 138 | WindowInputStatus mInputStatus; /// status after all events in mInputEvents 139 | WindowInputEventList mInputEvents; /// every events that occured since last update 140 | 141 | void init() 142 | { 143 | mInputStatus.init(); 144 | mInputEvents.clear(); 145 | mInputEvents.reserve(16); 146 | } 147 | }; 148 | 149 | -------------------------------------------------------------------------------- /Application/Game.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Dx12Base/WindowInput.h" 4 | #include "Dx12Base/Dx12Device.h" 5 | #include "Dx12Base/Dx12RayTracing.h" 6 | 7 | struct ViewCamera 8 | { 9 | ViewCamera(); 10 | 11 | // Source state 12 | float4 mPos; 13 | float mYaw; 14 | float mPitch; 15 | 16 | // Derived data from source state 17 | float4 mLeft; 18 | float4 mForward; 19 | float4 mUp; 20 | 21 | // Movement status 22 | int mMoveForward; 23 | int mMoveLeft; 24 | int mMouseDx; 25 | int mMouseDy; 26 | 27 | void Update(); 28 | 29 | float4x4 GetViewMatrix() const; 30 | }; 31 | 32 | class Game 33 | { 34 | public: 35 | Game(); 36 | ~Game(); 37 | 38 | void initialise(); 39 | void reallocateResolutionDependent(uint newWidth, uint newHeight); 40 | void shutdown(); 41 | 42 | void update(const WindowInputData& inputData); 43 | void render(); 44 | 45 | private: 46 | 47 | /// Load/reload all shaders if compilation is succesful. 48 | /// @ReloadMode: true if we are simply trying to reload shaders. 49 | void loadShaders(bool ReloadMode); 50 | /// release all shaders 51 | void releaseShaders(); 52 | 53 | void allocateResolutionIndependentResources(); 54 | void releaseResolutionIndependentResources(); 55 | void allocateResolutionDependentResources(uint newWidth, uint newHeight); 56 | void releaseResolutionDependentResources(); 57 | 58 | ViewCamera View; 59 | bool mInitialisedMouse = false; 60 | int mLastMouseX = 0; 61 | int mLastMouseY = 0; 62 | int mMouseX = 0; 63 | int mMouseY = 0; 64 | 65 | InputLayout* layout; 66 | 67 | RenderBufferGeneric* vertexBuffer; 68 | RenderBufferGeneric* indexBuffer; 69 | 70 | uint SphereIndexCount; 71 | uint SphereVertexCount; 72 | InputLayout* SphereVertexLayout; 73 | StructuredBuffer* SphereVertexBuffer; 74 | TypedBuffer* SphereIndexBuffer; 75 | 76 | VertexShader* MeshVertexShader; 77 | PixelShader* MeshPixelShader; 78 | PixelShader* MeshVoxelisationPixelShader; 79 | 80 | VertexShader* TriangleVertexShader; 81 | PixelShader* TrianglePixelShader; 82 | 83 | #if D_ENABLE_DXR 84 | StaticBottomLevelAccelerationStructureBuffer* SphereBLAS; 85 | StaticTopLevelAccelerationStructureBuffer* SceneTLAS; 86 | 87 | RayTracingPipelineStateSimple* mRayTracingPipelineState; 88 | RayTracingPipelineStateClosestAndAnyHit* mRayTracingPipelineStateClosestAndHit; 89 | #endif 90 | 91 | TypedBuffer* UavBuffer; 92 | 93 | VertexShader* vertexShader; 94 | PixelShader* pixelShader; 95 | PixelShader* ToneMapShaderPS; 96 | ComputeShader* computeShader; 97 | 98 | RenderTexture* texture; 99 | RenderTexture* texture2; 100 | RenderTexture* HdrTexture; 101 | RenderTexture* HdrTexture2; 102 | RenderTexture* DepthTexture; 103 | 104 | RenderTexture* VolumeTexture; 105 | 106 | bool ShowRtResult = true; 107 | bool ShowRtWithAnyHit = true; 108 | }; 109 | 110 | 111 | -------------------------------------------------------------------------------- /Application/WinImgui.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "WinImgui.h" 3 | #include "Dx12Base/Dx12Device.h" 4 | 5 | 6 | static ID3D12DescriptorHeap* g_pd3dSrvDescHeap = NULL; 7 | 8 | 9 | void WinImguiInitialise(const HWND hwnd) 10 | { 11 | #if D_ENABLE_IMGUI 12 | 13 | // Setup Dear ImGui context 14 | IMGUI_CHECKVERSION(); 15 | ImGui::CreateContext(); 16 | ImGuiIO& io = ImGui::GetIO(); (void)io; 17 | //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls 18 | //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls 19 | 20 | // Setup Dear ImGui style 21 | ImGui::StyleColorsDark(); 22 | //ImGui::StyleColorsClassic(); 23 | 24 | D3D12_DESCRIPTOR_HEAP_DESC desc = {}; 25 | desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; 26 | desc.NumDescriptors = 1; 27 | desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; 28 | HRESULT hr = g_dx12Device->getDevice()->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&g_pd3dSrvDescHeap)); 29 | ATLASSERT(hr == S_OK); 30 | 31 | // Setup Platform/Renderer bindings 32 | ImGui_ImplWin32_Init(hwnd); 33 | ImGui_ImplDX12_Init(g_dx12Device->getDevice(), frameBufferCount, 34 | DXGI_FORMAT_R8G8B8A8_UNORM, g_pd3dSrvDescHeap, 35 | g_pd3dSrvDescHeap->GetCPUDescriptorHandleForHeapStart(), 36 | g_pd3dSrvDescHeap->GetGPUDescriptorHandleForHeapStart()); 37 | 38 | #endif 39 | } 40 | 41 | 42 | void WinImguiNewFrame() 43 | { 44 | #if D_ENABLE_IMGUI 45 | 46 | ImGui_ImplDX12_NewFrame(); 47 | ImGui_ImplWin32_NewFrame(); 48 | ImGui::NewFrame(); 49 | 50 | #endif 51 | } 52 | 53 | void WinImguiRender() 54 | { 55 | #if D_ENABLE_IMGUI 56 | SCOPED_GPU_TIMER(IMGUI, 100, 100, 255); 57 | 58 | // Render UI 59 | 60 | ID3D12GraphicsCommandList* commandList = g_dx12Device->getFrameCommandList(); 61 | ID3D12Resource* backBuffer = g_dx12Device->getBackBuffer(); 62 | 63 | D3D12_RESOURCE_BARRIER bbPresentToRt = {}; 64 | bbPresentToRt.Transition.pResource = backBuffer; 65 | bbPresentToRt.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; 66 | bbPresentToRt.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; 67 | bbPresentToRt.Transition.Subresource = 0; 68 | commandList->ResourceBarrier(1, &bbPresentToRt); 69 | 70 | D3D12_CPU_DESCRIPTOR_HANDLE descriptor = g_dx12Device->getBackBufferDescriptor(); 71 | commandList->OMSetRenderTargets(1, &descriptor, FALSE, NULL); 72 | commandList->SetDescriptorHeaps(1, &g_pd3dSrvDescHeap); 73 | ImGui::Render(); 74 | ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), commandList); 75 | 76 | D3D12_RESOURCE_BARRIER bbRtToPresent = {}; 77 | bbRtToPresent.Transition.pResource = backBuffer; 78 | bbRtToPresent.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; 79 | bbRtToPresent.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; 80 | bbRtToPresent.Transition.Subresource = 0; 81 | commandList->ResourceBarrier(1, &bbRtToPresent); 82 | 83 | #endif 84 | } 85 | 86 | void WinImguiShutdown() 87 | { 88 | #if D_ENABLE_IMGUI 89 | 90 | ImGui_ImplDX12_Shutdown(); 91 | ImGui_ImplWin32_Shutdown(); 92 | ImGui::DestroyContext(); 93 | resetComPtr(&g_pd3dSrvDescHeap); 94 | 95 | #endif 96 | } 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /Application/Application.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 10 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 11 | 12 | 13 | {26774f3f-a03e-4f83-9f4c-7164cccca514} 14 | 15 | 16 | {86000fa9-6b6a-46f9-ac8d-1c1708aba136} 17 | 18 | 19 | 20 | 21 | Source Files 22 | 23 | 24 | Source Files 25 | 26 | 27 | imgui 28 | 29 | 30 | imgui 31 | 32 | 33 | imgui 34 | 35 | 36 | imgui 37 | 38 | 39 | Source Files 40 | 41 | 42 | imgui 43 | 44 | 45 | imgui 46 | 47 | 48 | imgui 49 | 50 | 51 | 52 | 53 | Source Files 54 | 55 | 56 | imgui 57 | 58 | 59 | imgui 60 | 61 | 62 | imgui 63 | 64 | 65 | imgui 66 | 67 | 68 | imgui 69 | 70 | 71 | imgui 72 | 73 | 74 | Source Files 75 | 76 | 77 | Source Files 78 | 79 | 80 | imgui 81 | 82 | 83 | imgui 84 | 85 | 86 | 87 | 88 | HLSL 89 | 90 | 91 | HLSL 92 | 93 | 94 | HLSL 95 | 96 | 97 | HLSL 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /Resources/RaytracingShaders.hlsl: -------------------------------------------------------------------------------- 1 | 2 | cbuffer MeshConstantBuffer : register(b0, space1) 3 | { 4 | float4x4 ViewProjectionMatrix; 5 | float4x4 ViewProjectionMatrixInv; 6 | 7 | uint OutputWidth; 8 | uint OutputHeight; 9 | uint HitShaderClosestHitContribution; 10 | uint HitShaderAnyHitContribution; 11 | } 12 | 13 | 14 | 15 | // 16 | // Ray tracing global root signature parameters in space1 17 | // 18 | 19 | RaytracingAccelerationStructure Scene : register(t0, space1); 20 | RWTexture2D LuminanceRenderTarget : register(u0, space1); 21 | 22 | struct RayPayload 23 | { 24 | float4 Color; 25 | }; 26 | 27 | 28 | 29 | [shader("raygeneration")] 30 | void MyRaygenShader() 31 | { 32 | RayDesc Ray; 33 | Ray.TMin = 0.0001f; 34 | Ray.TMax = 1000.0f; 35 | Ray.Origin = float3(0.0f, 0.0f, 0.0f); 36 | Ray.Direction = float3(0.0f, 1.0f, 0.0f); 37 | 38 | // Compute clip space 39 | uint2 LaunchIndex = DispatchRaysIndex().xy; 40 | float2 DispatchDimension = float2(DispatchRaysDimensions().xy); 41 | float2 ClipXY = (((LaunchIndex.xy + 0.5f) / DispatchDimension.xy) * 2.0f - 1.0f); 42 | ClipXY.y *= -1.0f; 43 | 44 | // Compute start and end points from view matrix 45 | float4 StartPos = mul(ViewProjectionMatrixInv, float4(ClipXY, 0.0f, 1.0)); 46 | StartPos /= StartPos.wwww; 47 | float4 EndPos = mul(ViewProjectionMatrixInv, float4(ClipXY, 1.0f, 1.0)); 48 | EndPos /= EndPos.wwww; 49 | Ray.Origin = StartPos.xyz; 50 | Ray.Direction = normalize(EndPos.xyz - StartPos.xyz); 51 | 52 | // Trace 53 | RayPayload Payload = { float4(0.5f, 0.5f, 0.5f, 0.0f) }; 54 | uint InstanceInclusionMask = 0xFF; 55 | // RayFlags: see https://github.com/microsoft/DirectX-Specs/blob/master/d3d/Raytracing.md#ray-flags 56 | #if CLOSESTANDANYHIT==1 57 | // By default use the closest hit shader 58 | uint RayFlags = RAY_FLAG_CULL_BACK_FACING_TRIANGLES; 59 | uint RayContributionToHitGroupIndex = HitShaderClosestHitContribution; 60 | if (LaunchIndex.y < DispatchDimension.y / 2) 61 | { 62 | // If in the top part of the screen, use the any hit shader 63 | RayFlags = RAY_FLAG_FORCE_NON_OPAQUE; // force the execution of any hit shaders 64 | RayContributionToHitGroupIndex = HitShaderAnyHitContribution; 65 | } 66 | uint MultiplierForGeometryContributionToHitGroupIndex = 0; 67 | uint MissShaderIndex = 0; 68 | #else 69 | uint RayFlags = RAY_FLAG_CULL_BACK_FACING_TRIANGLES; 70 | uint RayContributionToHitGroupIndex = 0; 71 | uint MultiplierForGeometryContributionToHitGroupIndex = 0; 72 | uint MissShaderIndex = 0; 73 | #endif 74 | 75 | TraceRay(Scene, RayFlags, InstanceInclusionMask, RayContributionToHitGroupIndex, MultiplierForGeometryContributionToHitGroupIndex, MissShaderIndex, Ray, Payload); 76 | 77 | // Write the raytraced color to the output texture. 78 | LuminanceRenderTarget[DispatchRaysIndex().xy] = Payload.Color; 79 | } 80 | 81 | 82 | 83 | // 84 | // Ray tracing local root signature parameters in space0 85 | // 86 | 87 | struct VertexStruct 88 | { 89 | float3 Position; 90 | float3 Normal; 91 | float2 UV; 92 | }; 93 | StructuredBuffer VertexBuffer : register(t0, space0); 94 | Buffer IndexBuffer : register(t1, space0); 95 | 96 | #include "StaticSamplers.hlsl" 97 | Texture2D MeshTexture : register(t2, space0); 98 | 99 | 100 | [shader("closesthit")] 101 | void MyClosestHitShader(inout RayPayload Payload, in BuiltInTriangleIntersectionAttributes Attr) 102 | { 103 | float3 barycentrics = float3(1 - Attr.barycentrics.x - Attr.barycentrics.y, Attr.barycentrics.x, Attr.barycentrics.y); 104 | 105 | uint vertId = 3 * PrimitiveIndex(); 106 | float2 uv0 = VertexBuffer[IndexBuffer[vertId] + 0].UV; 107 | float2 uv1 = VertexBuffer[IndexBuffer[vertId] + 1].UV; 108 | float2 uv2 = VertexBuffer[IndexBuffer[vertId] + 2].UV; 109 | float2 uv = uv0 * barycentrics.x + uv1 * barycentrics.y + uv2 * barycentrics.z; 110 | 111 | Payload.Color = float4(MeshTexture.SampleLevel(SamplerLinearClamp, uv, 0).rgb, 1.0); 112 | //Payload.Color = float4(barycentrics, 1); 113 | //Payload.Color = float4(WorldRayOrigin() + RayTCurrent() * WorldRayDirection(), 1.0f); 114 | } 115 | 116 | [shader("anyhit")] 117 | void MyAnyHitShader(inout RayPayload Payload, in BuiltInTriangleIntersectionAttributes Attr) 118 | { 119 | float3 barycentrics = float3(1 - Attr.barycentrics.x - Attr.barycentrics.y, Attr.barycentrics.x, Attr.barycentrics.y); 120 | 121 | uint vertId = 3 * PrimitiveIndex(); 122 | float2 uv0 = VertexBuffer[IndexBuffer[vertId] + 0].UV; 123 | float2 uv1 = VertexBuffer[IndexBuffer[vertId] + 1].UV; 124 | float2 uv2 = VertexBuffer[IndexBuffer[vertId] + 2].UV; 125 | float2 uv = uv0 * barycentrics.x + uv1 * barycentrics.y + uv2 * barycentrics.z; 126 | 127 | Payload.Color = float4(barycentrics * 2 * MeshTexture.SampleLevel(SamplerLinearClamp, uv, 0).rgb, 1); 128 | AcceptHitAndEndSearch(); 129 | } 130 | 131 | [shader("miss")] 132 | void MyMissShader(inout RayPayload Payload) 133 | { 134 | Payload.Color = float4(0.1, 0, 0, 1); 135 | } 136 | 137 | -------------------------------------------------------------------------------- /DX12Base/Dx12Utilities.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Dx12Utilities.h" 3 | 4 | #include "d3dx12.h" 5 | 6 | 7 | 8 | 9 | RenderBufferGenericDynamic::RenderBufferGenericDynamic(uint64 TotalSizeInBytes, D3D12_RESOURCE_FLAGS flags) 10 | : mRenderBuffer(TotalSizeInBytes, nullptr, flags, RenderBufferType_Default) 11 | { 12 | for (int i = 0; i < frameBufferCount; ++i) 13 | { 14 | mFrameUploadBuffers[i] = new RenderBufferGeneric(TotalSizeInBytes, nullptr, D3D12_RESOURCE_FLAG_NONE, RenderBufferType_Upload); 15 | } 16 | } 17 | 18 | RenderBufferGenericDynamic::~RenderBufferGenericDynamic() 19 | { 20 | for (int i = 0; i < frameBufferCount; ++i) 21 | { 22 | delete mFrameUploadBuffers[i]; 23 | } 24 | } 25 | 26 | 27 | void* RenderBufferGenericDynamic::Map() 28 | { 29 | int frameIndex = g_dx12Device->getFrameIndex(); 30 | 31 | void* ptr; 32 | mFrameUploadBuffers[frameIndex]->getD3D12Resource()->Map(0, nullptr, &ptr); 33 | ATLASSERT(mRenderBuffer.GetSizeInBytes() <= UINT_MAX); 34 | return ptr; 35 | } 36 | 37 | void RenderBufferGenericDynamic::UnmapAndUpload() 38 | { 39 | int frameIndex = g_dx12Device->getFrameIndex(); 40 | mFrameUploadBuffers[frameIndex]->getD3D12Resource()->Unmap(0, nullptr); 41 | 42 | mRenderBuffer.resourceTransitionBarrier(D3D12_RESOURCE_STATE_COPY_DEST); 43 | g_dx12Device->getFrameCommandList()->CopyResource(mRenderBuffer.getD3D12Resource(), mFrameUploadBuffers[frameIndex]->getD3D12Resource()); 44 | } 45 | 46 | 47 | 48 | 49 | //////////////////////////////////////////////////////////////////////////////////////////////////// 50 | //////////////////////////////////////////////////////////////////////////////////////////////////// 51 | //////////////////////////////////////////////////////////////////////////////////////////////////// 52 | 53 | 54 | 55 | 56 | RenderTextureDynamic::RenderTextureDynamic( 57 | unsigned int width, unsigned int height, 58 | unsigned int depth, DXGI_FORMAT format, 59 | D3D12_RESOURCE_FLAGS flags) 60 | : mRenderTexture(width, height, depth, format, flags) 61 | { 62 | // TODO: dimension should be fetched from mRenderTexture 63 | D3D12_RESOURCE_DIMENSION dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; 64 | if (depth > 1) 65 | dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D; 66 | 67 | D3D12_RESOURCE_DESC resourceDesc = getRenderTextureResourceDesc(D3D12_RESOURCE_DIMENSION_TEXTURE2D, width, height, depth, format, flags); 68 | 69 | uint64 textureUploadBufferSize = 0; 70 | g_dx12Device->getDevice()->GetCopyableFootprints(&resourceDesc, 0, 1, 0, nullptr, nullptr, nullptr, &textureUploadBufferSize); 71 | 72 | D3D12_RESOURCE_DESC uploadBufferDesc; // TODO upload buffer desc 73 | uploadBufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; 74 | uploadBufferDesc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT; 75 | uploadBufferDesc.Width = textureUploadBufferSize; 76 | uploadBufferDesc.Height = uploadBufferDesc.DepthOrArraySize = uploadBufferDesc.MipLevels = 1; 77 | uploadBufferDesc.Format = DXGI_FORMAT_UNKNOWN; 78 | uploadBufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; 79 | uploadBufferDesc.Flags = D3D12_RESOURCE_FLAG_NONE; 80 | uploadBufferDesc.SampleDesc.Count = 1; 81 | uploadBufferDesc.SampleDesc.Quality = 0; 82 | D3D12_HEAP_PROPERTIES uploadHeapProperties = getUploadMemoryHeapProperties(); 83 | 84 | for (int i = 0; i < frameBufferCount; ++i) 85 | { 86 | g_dx12Device->getDevice()->CreateCommittedResource(&uploadHeapProperties, 87 | D3D12_HEAP_FLAG_NONE, 88 | &uploadBufferDesc, 89 | D3D12_RESOURCE_STATE_GENERIC_READ, 90 | nullptr, 91 | IID_PPV_ARGS(&mFrameUploadTextures[i])); 92 | setDxDebugName(mFrameUploadTextures[i], L"RenderTextureDynamicUploadHeap"); 93 | } 94 | 95 | } 96 | 97 | RenderTextureDynamic::~RenderTextureDynamic() 98 | { 99 | for (int i = 0; i < frameBufferCount; ++i) 100 | { 101 | resetComPtr(&mFrameUploadTextures[i]); 102 | } 103 | } 104 | 105 | void* RenderTextureDynamic::Map() 106 | { 107 | int frameIndex = g_dx12Device->getFrameIndex(); 108 | 109 | void* ptr; 110 | mFrameUploadTextures[frameIndex]->Map(0, nullptr, &ptr); 111 | return ptr; 112 | } 113 | 114 | void RenderTextureDynamic::UnmapAndUpload() 115 | { 116 | int frameIndex = g_dx12Device->getFrameIndex(); 117 | mFrameUploadTextures[frameIndex]->Unmap(0, nullptr); 118 | 119 | mRenderTexture.resourceTransitionBarrier(D3D12_RESOURCE_STATE_COPY_DEST); 120 | 121 | auto commandList = g_dx12Device->getFrameCommandList(); 122 | commandList->CopyResource(mRenderTexture.getD3D12Resource(), mFrameUploadTextures[frameIndex]); 123 | } 124 | 125 | void RenderTextureDynamic::Upload(void* DataPtr, unsigned int RowPitchByte, unsigned int SlicePitchByte) 126 | { 127 | int frameIndex = g_dx12Device->getFrameIndex(); 128 | auto commandList = g_dx12Device->getFrameCommandList(); 129 | 130 | D3D12_SUBRESOURCE_DATA SubResourceData; 131 | SubResourceData.pData = DataPtr; 132 | SubResourceData.RowPitch = RowPitchByte; 133 | SubResourceData.SlicePitch = SlicePitchByte; 134 | 135 | mRenderTexture.resourceTransitionBarrier(D3D12_RESOURCE_STATE_COPY_DEST); 136 | 137 | // using helper 138 | UpdateSubresources<1>( 139 | commandList, 140 | mRenderTexture.getD3D12Resource(), 141 | mFrameUploadTextures[frameIndex], 142 | 0, 143 | 0, 144 | 1, 145 | &SubResourceData); 146 | // UpdateSubresources changes the resources state 147 | } 148 | 149 | 150 | 151 | 152 | //////////////////////////////////////////////////////////////////////////////////////////////////// 153 | //////////////////////////////////////////////////////////////////////////////////////////////////// 154 | //////////////////////////////////////////////////////////////////////////////////////////////////// 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # .NET Core 46 | project.lock.json 47 | project.fragment.lock.json 48 | artifacts/ 49 | **/Properties/launchSettings.json 50 | 51 | *_i.c 52 | *_p.c 53 | *_i.h 54 | *.ilk 55 | *.meta 56 | *x64/*.obj 57 | *.pch 58 | *.pdb 59 | *.pgc 60 | *.pgd 61 | *.rsp 62 | *.sbr 63 | *.tlb 64 | *.tli 65 | *.tlh 66 | *.tmp 67 | *.tmp_proj 68 | *.log 69 | *.vspscc 70 | *.vssscc 71 | .builds 72 | *.pidb 73 | *.svclog 74 | *.scc 75 | 76 | # Chutzpah Test files 77 | _Chutzpah* 78 | 79 | # Visual C++ cache files 80 | ipch/ 81 | *.aps 82 | *.ncb 83 | *.opendb 84 | *.opensdf 85 | *.sdf 86 | *.cachefile 87 | *.VC.db 88 | *.VC.VC.opendb 89 | 90 | # Visual Studio profiler 91 | *.psess 92 | *.vsp 93 | *.vspx 94 | *.sap 95 | 96 | # TFS 2012 Local Workspace 97 | $tf/ 98 | 99 | # Guidance Automation Toolkit 100 | *.gpState 101 | 102 | # ReSharper is a .NET coding add-in 103 | _ReSharper*/ 104 | *.[Rr]e[Ss]harper 105 | *.DotSettings.user 106 | 107 | # JustCode is a .NET coding add-in 108 | .JustCode 109 | 110 | # TeamCity is a build add-in 111 | _TeamCity* 112 | 113 | # DotCover is a Code Coverage Tool 114 | *.dotCover 115 | 116 | # Visual Studio code coverage results 117 | *.coverage 118 | *.coveragexml 119 | 120 | # NCrunch 121 | _NCrunch_* 122 | .*crunch*.local.xml 123 | nCrunchTemp_* 124 | 125 | # MightyMoose 126 | *.mm.* 127 | AutoTest.Net/ 128 | 129 | # Web workbench (sass) 130 | .sass-cache/ 131 | 132 | # Installshield output folder 133 | [Ee]xpress/ 134 | 135 | # DocProject is a documentation generator add-in 136 | DocProject/buildhelp/ 137 | DocProject/Help/*.HxT 138 | DocProject/Help/*.HxC 139 | DocProject/Help/*.hhc 140 | DocProject/Help/*.hhk 141 | DocProject/Help/*.hhp 142 | DocProject/Help/Html2 143 | DocProject/Help/html 144 | 145 | # Click-Once directory 146 | publish/ 147 | 148 | # Publish Web Output 149 | *.[Pp]ublish.xml 150 | *.azurePubxml 151 | # TODO: Comment the next line if you want to checkin your web deploy settings 152 | # but database connection strings (with potential passwords) will be unencrypted 153 | *.pubxml 154 | *.publishproj 155 | 156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 157 | # checkin your Azure Web App publish settings, but sensitive information contained 158 | # in these scripts will be unencrypted 159 | PublishScripts/ 160 | 161 | # NuGet Packages 162 | *.nupkg 163 | # The packages folder can be ignored because of Package Restore 164 | **/packages/* 165 | # except build/, which is used as an MSBuild target. 166 | !**/packages/build/ 167 | # Uncomment if necessary however generally it will be regenerated when needed 168 | #!**/packages/repositories.config 169 | # NuGet v3's project.json files produces more ignorable files 170 | *.nuget.props 171 | *.nuget.targets 172 | 173 | # Microsoft Azure Build Output 174 | csx/ 175 | *.build.csdef 176 | 177 | # Microsoft Azure Emulator 178 | ecf/ 179 | rcf/ 180 | 181 | # Windows Store app package directories and files 182 | AppPackages/ 183 | BundleArtifacts/ 184 | Package.StoreAssociation.xml 185 | _pkginfo.txt 186 | 187 | # Visual Studio cache files 188 | # files ending in .cache can be ignored 189 | *.[Cc]ache 190 | # but keep track of directories ending in .cache 191 | !*.[Cc]ache/ 192 | 193 | # Others 194 | ClientBin/ 195 | ~$* 196 | *~ 197 | *.dbmdl 198 | *.dbproj.schemaview 199 | *.jfm 200 | *.pfx 201 | *.publishsettings 202 | orleans.codegen.cs 203 | 204 | # Since there are multiple workflows, uncomment next line to ignore bower_components 205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 206 | #bower_components/ 207 | 208 | # RIA/Silverlight projects 209 | Generated_Code/ 210 | 211 | # Backup & report files from converting an old project file 212 | # to a newer Visual Studio version. Backup files are not needed, 213 | # because we have git ;-) 214 | _UpgradeReport_Files/ 215 | Backup*/ 216 | UpgradeLog*.XML 217 | UpgradeLog*.htm 218 | 219 | # SQL Server files 220 | *.mdf 221 | *.ldf 222 | *.ndf 223 | 224 | # Business Intelligence projects 225 | *.rdl.data 226 | *.bim.layout 227 | *.bim_*.settings 228 | 229 | # Microsoft Fakes 230 | FakesAssemblies/ 231 | 232 | # GhostDoc plugin setting file 233 | *.GhostDoc.xml 234 | 235 | # Node.js Tools for Visual Studio 236 | .ntvs_analysis.dat 237 | node_modules/ 238 | 239 | # Typescript v1 declaration files 240 | typings/ 241 | 242 | # Visual Studio 6 build log 243 | *.plg 244 | 245 | # Visual Studio 6 workspace options file 246 | *.opt 247 | 248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 249 | *.vbw 250 | 251 | # Visual Studio LightSwitch build output 252 | **/*.HTMLClient/GeneratedArtifacts 253 | **/*.DesktopClient/GeneratedArtifacts 254 | **/*.DesktopClient/ModelManifest.xml 255 | **/*.Server/GeneratedArtifacts 256 | **/*.Server/ModelManifest.xml 257 | _Pvt_Extensions 258 | 259 | # Paket dependency manager 260 | .paket/paket.exe 261 | paket-files/ 262 | 263 | # FAKE - F# Make 264 | .fake/ 265 | 266 | # JetBrains Rider 267 | .idea/ 268 | *.sln.iml 269 | 270 | # CodeRush 271 | .cr/ 272 | 273 | # Python Tools for Visual Studio (PTVS) 274 | __pycache__/ 275 | *.pyc 276 | 277 | # Cake - Uncomment if you are using it 278 | # tools/** 279 | # !tools/packages.config 280 | 281 | # Telerik's JustMock configuration file 282 | *.jmconfig 283 | 284 | # BizTalk build output 285 | *.btp.cs 286 | *.btm.cs 287 | *.odx.cs 288 | *.xsd.cs 289 | 290 | *.cap 291 | 292 | imgui.ini 293 | -------------------------------------------------------------------------------- /DX12Base/Dx12RayTracing.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Dx12Device.h" 4 | 5 | 6 | 7 | #if D_ENABLE_DXR 8 | 9 | 10 | 11 | class AccelerationStructureBuffer : public RenderBufferGeneric 12 | { 13 | public: 14 | AccelerationStructureBuffer(uint64 TotalSizeInBytes); 15 | virtual ~AccelerationStructureBuffer(); 16 | 17 | private: 18 | AccelerationStructureBuffer(); 19 | AccelerationStructureBuffer(AccelerationStructureBuffer&); 20 | }; 21 | 22 | 23 | 24 | class StaticBottomLevelAccelerationStructureBuffer 25 | { 26 | public: 27 | StaticBottomLevelAccelerationStructureBuffer(D3D12_RAYTRACING_GEOMETRY_DESC* Meshes, uint MeshCount); 28 | virtual ~StaticBottomLevelAccelerationStructureBuffer(); 29 | 30 | AccelerationStructureBuffer& GetBuffer() { return *mBlasResult; } 31 | D3D12_GPU_VIRTUAL_ADDRESS GetGPUVirtualAddress() { return mBlasResult->getGPUVirtualAddress(); } 32 | 33 | private: 34 | StaticBottomLevelAccelerationStructureBuffer(); 35 | StaticBottomLevelAccelerationStructureBuffer(StaticBottomLevelAccelerationStructureBuffer&); 36 | 37 | RenderBufferGeneric* mBlasScratch; 38 | AccelerationStructureBuffer* mBlasResult; 39 | }; 40 | 41 | class StaticTopLevelAccelerationStructureBuffer 42 | { 43 | public: 44 | StaticTopLevelAccelerationStructureBuffer(D3D12_RAYTRACING_INSTANCE_DESC* Instances, uint InstanceCount); 45 | virtual ~StaticTopLevelAccelerationStructureBuffer(); 46 | 47 | AccelerationStructureBuffer& GetBuffer() { return *mTlasResult; } 48 | D3D12_GPU_VIRTUAL_ADDRESS GetGPUVirtualAddress() { return mTlasResult->getGPUVirtualAddress(); } 49 | 50 | private: 51 | StaticTopLevelAccelerationStructureBuffer(); 52 | StaticTopLevelAccelerationStructureBuffer(StaticTopLevelAccelerationStructureBuffer&); 53 | 54 | RenderBufferGeneric* mTlasScratch; 55 | AccelerationStructureBuffer* mTlasResult; 56 | RenderBufferGeneric* mTlasInstanceBuffer; 57 | uint mInstanceCount; 58 | }; 59 | 60 | 61 | 62 | class RayGenerationShader : public ShaderBase 63 | { 64 | public: 65 | RayGenerationShader(const TCHAR* filename, const TCHAR* entryFunction, const Macros* macros); 66 | virtual ~RayGenerationShader(); 67 | }; 68 | 69 | class ClosestHitShader : public ShaderBase 70 | { 71 | public: 72 | ClosestHitShader(const TCHAR* filename, const TCHAR* entryFunction, const Macros* macros); 73 | virtual ~ClosestHitShader(); 74 | }; 75 | 76 | class AnyHitShader : public ShaderBase 77 | { 78 | public: 79 | AnyHitShader(const TCHAR* filename, const TCHAR* entryFunction, const Macros* macros); 80 | virtual ~AnyHitShader(); 81 | }; 82 | 83 | class MissShader : public ShaderBase 84 | { 85 | public: 86 | MissShader(const TCHAR* filename, const TCHAR* entryFunction, const Macros* macros); 87 | virtual ~MissShader(); 88 | }; 89 | 90 | struct RayTracingPipelineStateShaderDesc 91 | { 92 | const TCHAR* mShaderFilepath; 93 | const TCHAR* mShaderEntryName; 94 | Macros mMacros; 95 | }; 96 | 97 | 98 | 99 | class RayTracingPipelineStateSimple 100 | { 101 | public: 102 | RayTracingPipelineStateSimple(); 103 | virtual ~RayTracingPipelineStateSimple(); 104 | 105 | // Create a simple RayGen, CLosestHit and Miss shader trio. 106 | void CreateRTState(RayTracingPipelineStateShaderDesc& RayGenShaderDesc, RayTracingPipelineStateShaderDesc& ClosestHitShaderDesc, RayTracingPipelineStateShaderDesc& MissShaderDesc); 107 | 108 | ID3D12StateObject* mRayTracingPipelineStateObject; // Ray tracing pipeline 109 | ID3D12StateObjectProperties* mRayTracingPipelineStateObjectProp; // Ray tracing pipeline properties intereface 110 | 111 | // SimpleRTState 112 | RayGenerationShader* mRayGenShader; 113 | ClosestHitShader* mClosestHitShader; 114 | MissShader* mMissShader; 115 | void* mRayGenShaderIdentifier; 116 | void* mHitGroupShaderIdentifier; 117 | void* mMissShaderIdentifier; 118 | }; 119 | 120 | class RayTracingPipelineStateClosestAndAnyHit 121 | { 122 | public: 123 | RayTracingPipelineStateClosestAndAnyHit(); 124 | virtual ~RayTracingPipelineStateClosestAndAnyHit(); 125 | 126 | // Create a simple RayGen, CLosestHit and Miss shader trio. 127 | void CreateRTState( 128 | RayTracingPipelineStateShaderDesc& RayGenShaderDesc, RayTracingPipelineStateShaderDesc& MissShaderDesc, 129 | RayTracingPipelineStateShaderDesc& ClosestHitShaderDesc, RayTracingPipelineStateShaderDesc& AnyHitShaderDesc); 130 | 131 | ID3D12StateObject* mRayTracingPipelineStateObject; // Ray tracing pipeline 132 | ID3D12StateObjectProperties* mRayTracingPipelineStateObjectProp; // Ray tracing pipeline properties intereface 133 | 134 | // SimpleRTState 135 | RayGenerationShader* mRayGenShader; 136 | MissShader* mMissShader; 137 | ClosestHitShader* mClosestHitShader; 138 | AnyHitShader* mAnyHitShader; 139 | void* mRayGenShaderIdentifier; 140 | void* mMissShaderIdentifier; 141 | void* mClosestHitGroupShaderIdentifier; 142 | void* mAnyHitGroupShaderIdentifier; 143 | }; 144 | 145 | 146 | 147 | class DispatchRaysCallSBTHeapCPU 148 | { 149 | public: 150 | DispatchRaysCallSBTHeapCPU(uint SizeBytes); 151 | virtual ~DispatchRaysCallSBTHeapCPU(); 152 | 153 | void BeginRecording(ID3D12GraphicsCommandList4& CommandList); 154 | void EndRecording(); 155 | 156 | struct SBTMemory 157 | { 158 | void* mPtr; 159 | D3D12_GPU_VIRTUAL_ADDRESS mGPUAddress; 160 | }; 161 | SBTMemory AllocateSBTMemory(const uint ByteCount); 162 | 163 | struct AllocatedSBTMemory 164 | { 165 | const RootSignature* mRtLocalRootSignature; 166 | 167 | uint mHitGroupCount; 168 | uint mHitGroupByteCount; 169 | 170 | uint mSBTByteCount; 171 | SBTMemory mSBTMemory; 172 | 173 | uint mSBTRGSStartOffsetInBytes; 174 | uint mSBTRGSSizeInBytes; 175 | uint mSBTMissStartOffsetInBytes; 176 | uint mSBTMissSizeInBytes; 177 | uint mSBTMissStrideInBytes ; 178 | uint mSBTHitGStartOffsetInBytes; 179 | uint mSBTHitGSizeInBytes; 180 | uint mSBTHitGStrideInBytes; 181 | 182 | D3D12_DISPATCH_RAYS_DESC mDispatchRayDesc; 183 | 184 | // Set local root signature parameter for hit group. 185 | void setHitGroupLocalRootSignatureParameter(uint HitGroupIndex, RootParameterByteOffset Param, void* PTR); 186 | // It is assumed that RayGen and Miss shaders only use global root parameters for now. This could be changed, they already have the local root signature assigned. 187 | }; 188 | 189 | // When SBT memory is allocated, the client is in charge of setting up the memory according to the RayTracingState pipeline it has been create from. 190 | // We do check boundary when writing local root parameters in setHitGroupLocalRootSignatureParameter and that is it. 191 | AllocatedSBTMemory AllocateSimpleSBT(const RootSignature& RtLocalRootSignature, uint HitGroupCount, const RayTracingPipelineStateSimple& RTPS); 192 | AllocatedSBTMemory AllocateClosestAndAnyHitSBT(const RootSignature& RtLocalRootSignature, uint MeshInstanceCount, const RayTracingPipelineStateClosestAndAnyHit& RTPS); 193 | 194 | private: 195 | DispatchRaysCallSBTHeapCPU(); 196 | DispatchRaysCallSBTHeapCPU(DispatchRaysCallSBTHeapCPU&); 197 | 198 | RenderBufferGeneric* mUploadHeapSBT; 199 | RenderBufferGeneric* mGPUSBT; 200 | 201 | byte* mCpuMemoryStart; 202 | uint mAllocatedBytes; 203 | }; 204 | 205 | 206 | 207 | #endif // D_ENABLE_DXR 208 | 209 | 210 | -------------------------------------------------------------------------------- /Application/WinMain.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Dx12Base/WindowHelper.h" 3 | #include "Dx12Base/Dx12Device.h" 4 | 5 | #include "Game.h" 6 | 7 | #include "WinImgui.h" 8 | 9 | 10 | bool ImguiTopLayerProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 11 | { 12 | ImGui_ImplWin32_WndProcHandler(hwnd, msg, wParam, lParam); 13 | return ImGui::GetIO().WantCaptureKeyboard || ImGui::GetIO().WantCaptureMouse; 14 | } 15 | 16 | static uint PreviousResolutionWidth = 0; 17 | static uint PreviousResolutionHeight = 0; 18 | 19 | // the entry point for any Windows program 20 | int WINAPI WinMain( 21 | HINSTANCE hInstance, 22 | HINSTANCE hPrevInstance, 23 | LPSTR lpCmdLine, 24 | int nCmdShow) 25 | { 26 | static bool sVSyncEnable = true; 27 | static bool sStablePowerEnable = false; 28 | static bool sPreviousStablePowerEnable = !sStablePowerEnable; 29 | static float sTimerGraphWidth = 18.0f; 30 | 31 | // Get a window size that matches the desired client size 32 | const unsigned int desiredPosX = 20; 33 | const unsigned int desiredPosY = 20; 34 | const unsigned int desiredClientWidth = 1280; 35 | const unsigned int desiredClientHeight = 720; 36 | RECT clientRect; 37 | clientRect.left = desiredPosX; 38 | clientRect.right = desiredPosX + desiredClientWidth; 39 | clientRect.bottom = desiredPosY + desiredClientHeight; 40 | clientRect.top = desiredPosY; 41 | 42 | // Create the window 43 | WindowHelper win(hInstance, clientRect, nCmdShow, L"D3D12 Application"); 44 | win.showWindow(); 45 | 46 | // Create the d3d device 47 | PreviousResolutionWidth = desiredClientWidth; 48 | PreviousResolutionHeight = desiredClientHeight; 49 | Dx12Device::initialise(win.getHwnd(), desiredClientWidth, desiredClientHeight); 50 | CachedPSOManager::initialise(); 51 | 52 | WinImguiInitialise(win.getHwnd()); 53 | 54 | // Create the game 55 | Game game; 56 | 57 | // Register the resize callback 58 | auto windowResizedCallback = [&](LPARAM lParam) 59 | { 60 | // No threading mechanism so safe to do update call from here. 61 | uint newWidth = LOWORD(lParam); 62 | uint newHeight = HIWORD(lParam); 63 | 64 | // When moving the window around, we can still get a size callback. So we check for an actual change of resolution. 65 | if (newWidth != PreviousResolutionWidth || newHeight != PreviousResolutionHeight) 66 | { 67 | // ImGui_ImplDX12_InvalidateDeviceObjects(); // This is in fact wrong: sone imgui resource can still be in flight in a commandlist. Also this is only needed if we recreate the device. 68 | const bool bRecreate = true; 69 | g_dx12Device->updateSwapChain(bRecreate, newWidth, newHeight); 70 | // ImGui_ImplDX12_CreateDeviceObjects(); 71 | 72 | game.reallocateResolutionDependent(newWidth, newHeight); 73 | 74 | PreviousResolutionWidth = newWidth; 75 | PreviousResolutionHeight = newHeight; 76 | } 77 | }; 78 | win.setWindowResizedCallback(windowResizedCallback); 79 | 80 | MSG msg = { 0 }; 81 | while (true) 82 | { 83 | bool msgValid = win.translateSingleMessage(msg); 84 | 85 | if (msgValid) 86 | { 87 | const bool bMessageInterceptedByTopLayer = ImguiTopLayerProcHandler(msg.hwnd, msg.message, msg.wParam, msg.lParam); 88 | if (!bMessageInterceptedByTopLayer) 89 | { 90 | if (msg.message == WM_KEYDOWN && msg.wParam == VK_ESCAPE) 91 | break;// process escape key 92 | 93 | if (msg.message == WM_QUIT) 94 | break; // time to quit 95 | 96 | // A message has been processed and not consumed by imgui. Send the message to the WindowProc function. 97 | DispatchMessage(&msg); 98 | } 99 | } 100 | else 101 | { 102 | // Game update 103 | game.update(win.getInputData()); 104 | 105 | // Game render 106 | g_dx12Device->beginFrame(); 107 | 108 | { 109 | SCOPED_GPU_TIMER(RenderFrame, 200, 200, 200); 110 | 111 | static bool initDone = false; 112 | if (!initDone) 113 | { 114 | game.initialise(); 115 | initDone = true; 116 | } 117 | 118 | WinImguiNewFrame(); 119 | game.render(); 120 | 121 | ImGui::SetNextWindowSize(ImVec2(400.0f, 400.0f), ImGuiCond_FirstUseEver); 122 | ImGui::Begin("GPU performance"); 123 | Dx12Device::GPUTimersReport TimerReport = g_dx12Device->GetGPUTimerReport(); 124 | if (TimerReport.mLastValidGPUTimerSlotCount > 0) 125 | { 126 | UINT64 StartTime = TimerReport.mLastValidTimeStamps[TimerReport.mLastValidGPUTimers[0].mQueryIndexStart]; 127 | double TickPerSeconds = double(TimerReport.mLastValidTimeStampTickPerSeconds); 128 | 129 | static float sTimerGraphWidthMs = 33.0f; 130 | ImGui::Checkbox("VSync", &sVSyncEnable); 131 | #ifdef _DEBUG 132 | ImGui::Checkbox("StablePower", &sStablePowerEnable); 133 | #endif 134 | ImGui::SliderFloat("TimerGraphWidth (ms)", &sTimerGraphWidthMs, 1.0, 60.0); 135 | 136 | ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f); 137 | ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 2.0f)); 138 | ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f)); 139 | ImGui::BeginChild("Timer graph", ImVec2(0, 150), true, ImGuiWindowFlags_HorizontalScrollbar); 140 | const float WindowPixelWidth = ImGui::GetWindowWidth(); 141 | const float PixelPerMs = WindowPixelWidth / sTimerGraphWidthMs; 142 | #if 1 143 | for (int targetLevel = 0; targetLevel < 8; ++targetLevel) 144 | { 145 | bool printDone = false; 146 | for (UINT i=0; i>8) & 0xFF, int(Timer.mRGBA>>16) & 0xFF, int(Timer.mRGBA>>24) & 0xFF); 159 | ImGui::PushStyleColor(ImGuiCol_Button, color); 160 | ImGui::PushStyleColor(ImGuiCol_ButtonHovered, color); 161 | ImGui::PushStyleColor(ImGuiCol_ButtonActive, color); 162 | { 163 | // Set cursor to the correct position and size according to when things started this day 164 | ImGui::SetCursorPosX(TimerStartMs * PixelPerMs); 165 | ImGui::PushItemWidth(TimerEndMs * PixelPerMs); 166 | 167 | char debugStr[128]; 168 | sprintf_s(debugStr, 128, "%ls %.3f ms\n", Timer.mEventName, DurationMs); 169 | ImGui::Button(debugStr, ImVec2(DurationMs * PixelPerMs, 0.0f)); 170 | if (ImGui::IsItemHovered()) 171 | { 172 | ImGui::SetTooltip(debugStr); 173 | } 174 | ImGui::SameLine(); 175 | ImGui::PopItemWidth(); 176 | } 177 | ImGui::PopStyleColor(3); 178 | printDone = true; 179 | } 180 | } 181 | if (printDone) 182 | ImGui::NewLine(); // start a new line if anything has been printed 183 | } 184 | #endif 185 | ImGui::EndChild(); 186 | ImGui::PopStyleVar(3); 187 | 188 | { 189 | char debugStr[256]; 190 | sprintf_s(debugStr, 256, "Cached Raster PSO count %zu", g_CachedPSOManager->GetCachedRasterPSOCount()); 191 | ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 1.0f), debugStr); 192 | sprintf_s(debugStr, 256, "Cached compute PSO count %zu", g_CachedPSOManager->GetCachedComputePSOCount()); 193 | ImGui::TextColored(ImVec4(1.0f, 1.0f, 1.0f, 1.0f), debugStr); 194 | } 195 | 196 | for (UINT i = 0; i < TimerReport.mLastValidGPUTimerSlotCount; ++i) 197 | { 198 | Dx12Device::GPUTimer& Timer = TimerReport.mLastValidGPUTimers[i]; 199 | float TimerStart = float(double(TimerReport.mLastValidTimeStamps[Timer.mQueryIndexStart] - StartTime) / TickPerSeconds); 200 | float TimerEnd = float(double(TimerReport.mLastValidTimeStamps[Timer.mQueryIndexEnd] - StartTime) / TickPerSeconds); 201 | float TimerStartMs = TimerStart * 1000.0f; 202 | float TimerEndMs = TimerEnd * 1000.0f; 203 | float DurationMs = TimerEndMs - TimerStartMs; 204 | 205 | char* levelOffset = "---------------"; // 16 chars 206 | unsigned int levelShift = 16 - 2 * Timer.mLevel - 1; 207 | char* levelOffsetPtr = levelOffset + (levelShift < 0 ? 0 : levelShift); // cheap way to add shifting to a printf 208 | 209 | char debugStr[128]; 210 | sprintf_s(debugStr, 128, "%s%ls %.3f ms\n", levelOffsetPtr, Timer.mEventName, DurationMs); 211 | ImU32 color = ImColor(int(Timer.mRGBA) & 0xFF, int(Timer.mRGBA >> 8) & 0xFF, int(Timer.mRGBA >> 16) & 0xFF, int(Timer.mRGBA >> 24) & 0xFF); 212 | ImGui::TextColored(ImVec4(float(int(Timer.mRGBA) & 0xFF) / 255.0f, float(int(Timer.mRGBA >> 8) & 0xFF) / 255.0f, float(int(Timer.mRGBA >> 16) & 0xFF) / 255.0f, 255.0f), debugStr); 213 | } 214 | } 215 | ImGui::End(); 216 | 217 | WinImguiRender(); 218 | } 219 | 220 | // Swap the back buffer 221 | g_dx12Device->endFrameAndSwap(sVSyncEnable); 222 | 223 | #if 0 // SetStablePowerState is only available when developer mode is enabled. So it is deisabled by default. 224 | if (sPreviousStablePowerEnable != sStablePowerEnable) 225 | { 226 | 227 | sPreviousStablePowerEnable = sStablePowerEnable; 228 | HRESULT hr = g_dx12Device->getDevice()->SetStablePowerState(sStablePowerEnable); 229 | ATLASSERT(hr == S_OK); 230 | } 231 | #endif 232 | 233 | // Events have all been processed in this path by the game 234 | win.clearInputEvents(); 235 | } 236 | } 237 | 238 | g_dx12Device->closeBufferedFramesBeforeShutdown(); // close all frames 239 | 240 | WinImguiShutdown(); 241 | game.shutdown(); // game release its resources 242 | CachedPSOManager::shutdown(); // release the cached PSOs 243 | Dx12Device::shutdown(); // now we can safely delete the dx12 device we hold 244 | 245 | // End of application 246 | return 0; 247 | } 248 | 249 | 250 | -------------------------------------------------------------------------------- /DX12Base/DX12Base.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {9412077D-D368-4DBD-AACB-6DBA3618CF12} 23 | Win32Proj 24 | DX12Base 25 | 10.0.18362.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v141 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v141 38 | true 39 | Unicode 40 | 41 | 42 | StaticLibrary 43 | true 44 | v141 45 | Unicode 46 | 47 | 48 | StaticLibrary 49 | false 50 | v141 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | 75 | 76 | true 77 | $(ProjectDir)..\$(Platform)\$(Configuration)\$(ProjectName)\ 78 | C:\Program Files (x86)\Windows Kits\10\Include\10.0.14393.0\um;$(ExecutablePath) 79 | 80 | 81 | false 82 | 83 | 84 | true 85 | $(ProjectDir)..\$(Platform)\$(Configuration)\$(ProjectName)\ 86 | C:\Program Files (x86)\Windows Kits\10\Include\10.0.14393.0\um;$(ExecutablePath) 87 | 88 | 89 | 90 | 91 | 92 | Level3 93 | Disabled 94 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 95 | true 96 | 97 | 98 | Windows 99 | true 100 | 101 | 102 | 103 | 104 | 105 | 106 | Level3 107 | Disabled 108 | _DEBUG;_WINDOWS;%(PreprocessorDefinitions) 109 | true 110 | 111 | 112 | 113 | 114 | Windows 115 | true 116 | D3DCompiler.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 117 | 118 | 119 | C:\Program Files %28x86%29\Windows Kits\10\bin\10.0.18362.0\x64;%(AdditionalLibraryDirectories) 120 | dxcompiler.lib;d3d12.lib;dxgi.lib;d3dcompiler.lib; 121 | 122 | 123 | 124 | 125 | Level3 126 | 127 | 128 | MaxSpeed 129 | true 130 | true 131 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 132 | true 133 | 134 | 135 | Windows 136 | true 137 | true 138 | true 139 | 140 | 141 | 142 | 143 | Level3 144 | 145 | 146 | Full 147 | true 148 | true 149 | NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 150 | true 151 | $(IntDir) 152 | $(IntDir) 153 | $(IntDir) 154 | $(IntDir) 155 | 156 | 157 | Windows 158 | true 159 | true 160 | DebugFastLink 161 | D3DCompiler.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 162 | 163 | 164 | C:\Program Files %28x86%29\Windows Kits\10\bin\10.0.18362.0\x64;%(AdditionalLibraryDirectories) 165 | dxcompiler.lib;d3d12.lib;dxgi.lib;d3dcompiler.lib; 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 195 | 196 | 197 | 198 | -------------------------------------------------------------------------------- /DX12Base/WindowHelper.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "WindowHelper.h" 3 | 4 | static UINT LastSizeMessage = 0; 5 | static WPARAM LastSizewParam = 0; 6 | static LPARAM LastSizelParam = 0; 7 | 8 | LRESULT CALLBACK WindowProcess(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 9 | { 10 | WindowHelper *window = (WindowHelper*)GetWindowLongPtr(hWnd, GWLP_USERDATA); 11 | 12 | switch (message) 13 | { 14 | case WM_DESTROY: 15 | PostQuitMessage(0); 16 | return 0; 17 | break; 18 | } 19 | 20 | switch (message) 21 | { 22 | case WM_MOUSEMOVE: 23 | case WM_LBUTTONDOWN: 24 | case WM_RBUTTONDOWN: 25 | case WM_MBUTTONDOWN: 26 | case WM_LBUTTONUP: 27 | case WM_RBUTTONUP: 28 | case WM_MBUTTONUP: 29 | case WM_LBUTTONDBLCLK: 30 | case WM_RBUTTONDBLCLK: 31 | case WM_MBUTTONDBLCLK: 32 | case WM_NCMOUSELEAVE: 33 | case WM_MOUSEWHEEL: 34 | case WM_MOUSEHWHEEL: 35 | window->processMouseMessage(message, wParam, lParam); 36 | break; 37 | 38 | case WM_KEYDOWN: 39 | case WM_KEYUP: 40 | case WM_CHAR: 41 | case WM_SYSCHAR: 42 | window->processKeyMessage(message, wParam, lParam); 43 | break; 44 | 45 | case WM_EXITSIZEMOVE: 46 | window->processWindowSizeMessage(LastSizeMessage, LastSizewParam, LastSizelParam); 47 | SetForegroundWindow(hWnd); 48 | return true; 49 | break; 50 | 51 | case WM_SIZE: 52 | if (wParam != SIZE_MINIMIZED) 53 | { 54 | // This is a spammy event, let's resize only when stopping the resizing using the WM_EXITSIZEMOVE event. 55 | // This has the benefit to not ask for too many resolutino depenent descriptors to be created and go out of the current limit (simple linear array) 56 | LastSizeMessage = message; 57 | LastSizewParam = wParam; 58 | LastSizelParam = lParam; 59 | // Disabled because this locks down the program 60 | // window->processWindowSizeMessage(message, wParam, lParam); 61 | // return true; 62 | } 63 | break; 64 | 65 | //case WM_SIZING: // When receiving that message, the backbuffer we get is null for some reason. Would be good to still see image on screen. 66 | //Also it seems that this is not even enough to handle a window going full screen. Using Atl+Enter make things crash of lock up. 67 | } 68 | 69 | // Handle any messages the switch statement didn't 70 | return DefWindowProc(hWnd, message, wParam, lParam); 71 | } 72 | 73 | 74 | WindowHelper::WindowHelper(HINSTANCE hInstance, const RECT& clientRect, int nCmdShow, LPCWSTR windowName) 75 | : mHInstance(hInstance) 76 | , mNCmdShow(nCmdShow) 77 | , mClientRect(clientRect) 78 | { 79 | mInput.init(); 80 | 81 | // And create the rectangle that will allow it 82 | RECT rect = { 0, 0, clientRect.right - clientRect.left, clientRect.bottom - clientRect.top }; // set the size, but not the position otherwise does not seem to work 83 | DWORD style = (WS_OVERLAPPEDWINDOW | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX); // WS_OVERLAPPED without edge resize, WS_OVERLAPPEDWINDOW with 84 | BOOL menu = false; 85 | AdjustWindowRect(&rect, style, menu); 86 | //Get the required window dimensions 87 | int WindowWidth = rect.right - rect.left; //Required width 88 | //WindowWidth += (2 * GetSystemMetrics(SM_CXFIXEDFRAME)); //Add frame widths 89 | int WindowHeight = rect.bottom - rect.top; //Required height 90 | //WindowHeight += GetSystemMetrics(SM_CYCAPTION); //Titlebar height 91 | //WindowHeight += GetSystemMetrics(SM_CYMENU); //Uncomment for menu bar height 92 | //WindowHeight += (2 * GetSystemMetrics(SM_CYFIXEDFRAME)); //Frame heights 93 | 94 | // clear out the window class for use 95 | ZeroMemory(&mWc, sizeof(WNDCLASSEX)); 96 | // fill in the struct with the needed information 97 | mWc.cbSize = sizeof(WNDCLASSEX); 98 | mWc.style = CS_HREDRAW | CS_VREDRAW; 99 | mWc.lpfnWndProc = WindowProcess; 100 | mWc.hInstance = mHInstance; 101 | mWc.hCursor = LoadCursor(NULL, IDC_ARROW); 102 | mWc.hbrBackground = (HBRUSH)COLOR_WINDOW; 103 | mWc.lpszClassName = L"WindowClass1"; 104 | 105 | // register the window class 106 | RegisterClassEx(&mWc); 107 | 108 | // create the window and use the result as the handle 109 | mHWnd = CreateWindowEx(NULL, 110 | L"WindowClass1", // name of the window class 111 | windowName, // title of the window 112 | style, // not resizable 113 | clientRect.top, // x-position of the window 114 | clientRect.left, // y-position of the window 115 | WindowWidth, // width of the window 116 | WindowHeight, // height of the window 117 | NULL, // we have no parent window, NULL 118 | NULL, // we aren't using menus, NULL 119 | hInstance, // application handle 120 | NULL); // used with multiple windows, NULL 121 | 122 | SetWindowLongPtr(mHWnd, GWLP_USERDATA, (LONG_PTR)(this)); 123 | SetWindowPos(mHWnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER); // Make sure the pointer is cached https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setwindowlongptra 124 | } 125 | 126 | WindowHelper::~WindowHelper() 127 | { 128 | } 129 | 130 | 131 | void WindowHelper::showWindow() 132 | { 133 | ShowWindow(mHWnd, mNCmdShow); 134 | } 135 | 136 | bool WindowHelper::translateSingleMessage(MSG& msg) 137 | { 138 | if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 139 | { 140 | // translate keystroke messages into the right format 141 | TranslateMessage(&msg); 142 | 143 | // Message translated 144 | return true; 145 | } 146 | 147 | // No message translated 148 | return false; 149 | } 150 | 151 | void WindowHelper::processMouseMessage(UINT message, WPARAM wParam, LPARAM lParam) 152 | { 153 | // TODO WM_NCMOUSELEAVE 154 | 155 | mInput.mInputStatus.mouseX = LOWORD(lParam); 156 | mInput.mInputStatus.mouseY = HIWORD(lParam); 157 | 158 | InputEvent event; 159 | event.mouseX = mInput.mInputStatus.mouseX; 160 | event.mouseY = mInput.mInputStatus.mouseY; 161 | switch (message) 162 | { 163 | case WM_MOUSEMOVE: 164 | event.type = etMouseMoved; 165 | break; 166 | case WM_LBUTTONDOWN: 167 | event.type = etMouseButtonDown; 168 | event.mouseButton = mbLeft; 169 | mInput.mInputStatus.mouseButtons[event.mouseButton] = true; 170 | break; 171 | case WM_MBUTTONDOWN: 172 | event.type = etMouseButtonDown; 173 | event.mouseButton = mbMiddle; 174 | mInput.mInputStatus.mouseButtons[event.mouseButton] = true; 175 | break; 176 | case WM_RBUTTONDOWN: 177 | event.type = etMouseButtonDown; 178 | event.mouseButton = mbRight; 179 | mInput.mInputStatus.mouseButtons[event.mouseButton] = true; 180 | break; 181 | case WM_LBUTTONUP: 182 | event.type = etMouseButtonUp; 183 | event.mouseButton = mbLeft; 184 | mInput.mInputStatus.mouseButtons[event.mouseButton] = false; 185 | break; 186 | case WM_MBUTTONUP: 187 | event.type = etMouseButtonUp; 188 | event.mouseButton = mbMiddle; 189 | mInput.mInputStatus.mouseButtons[event.mouseButton] = false; 190 | break; 191 | case WM_RBUTTONUP: 192 | event.type = etMouseButtonUp; 193 | event.mouseButton = mbRight; 194 | mInput.mInputStatus.mouseButtons[event.mouseButton] = false; 195 | break; 196 | case WM_LBUTTONDBLCLK: 197 | event.type = etMouseButtonDoubleClick; 198 | event.mouseButton = mbLeft; 199 | break; 200 | case WM_MBUTTONDBLCLK: 201 | event.type = etMouseButtonDoubleClick; 202 | event.mouseButton = mbMiddle; 203 | break; 204 | case WM_RBUTTONDBLCLK: 205 | event.type = etMouseButtonDoubleClick; 206 | event.mouseButton = mbRight; 207 | break; 208 | 209 | // TODO 210 | //case WM_MOUSEWHEEL: 211 | //case WM_MOUSEHWHEEL: 212 | } 213 | mInput.mInputEvents.push_back(event); 214 | } 215 | 216 | static InputKey translateKey(WPARAM wParam) 217 | { 218 | switch (wParam) 219 | { 220 | case VK_RIGHT: return kRight; 221 | case VK_LEFT: return kLeft; 222 | case VK_DOWN: return kDown; 223 | case VK_UP: return kUp; 224 | case VK_SPACE: return kSpace; 225 | case VK_NUMPAD0: return kNumpad0; 226 | case VK_NUMPAD1: return kNumpad1; 227 | case VK_NUMPAD2: return kNumpad2; 228 | case VK_NUMPAD3: return kNumpad3; 229 | case VK_NUMPAD4: return kNumpad4; 230 | case VK_NUMPAD5: return kNumpad5; 231 | case VK_NUMPAD6: return kNumpad6; 232 | case VK_NUMPAD7: return kNumpad7; 233 | case VK_NUMPAD8: return kNumpad8; 234 | case VK_NUMPAD9: return kNumpad9; 235 | case VK_MULTIPLY: return kMultiply; 236 | case VK_ADD: return kAdd; 237 | case VK_SEPARATOR: return kSeparator; 238 | case VK_SUBTRACT: return kSubtract; 239 | case VK_DECIMAL: return kDecimal; 240 | case VK_DIVIDE: return kDivide; 241 | case VK_F1: return kF1; 242 | case VK_F2: return kF2; 243 | case VK_F3: return kF3; 244 | case VK_F4: return kF4; 245 | case VK_F5: return kF5; 246 | case VK_F6: return kF6; 247 | case VK_F7: return kF7; 248 | case VK_F8: return kF8; 249 | case VK_F9: return kF9; 250 | case VK_F10: return kF10; 251 | case VK_F11: return kF11; 252 | case VK_F12: return kF12; 253 | case VK_SHIFT: return kShift; 254 | case VK_CONTROL: return kControl; 255 | 256 | case '0': return k0; 257 | case '1': return k1; 258 | case '2': return k2; 259 | case '3': return k3; 260 | case '4': return k4; 261 | case '5': return k5; 262 | case '6': return k6; 263 | case '7': return k7; 264 | case '8': return k8; 265 | case '9': return k9; 266 | case 'A': return kA; 267 | case 'B': return kB; 268 | case 'C': return kC; 269 | case 'D': return kD; 270 | case 'E': return kE; 271 | case 'F': return kF; 272 | case 'G': return kG; 273 | case 'H': return kH; 274 | case 'I': return kI; 275 | case 'J': return kJ; 276 | case 'K': return kK; 277 | case 'L': return kL; 278 | case 'M': return kM; 279 | case 'N': return kN; 280 | case 'O': return kO; 281 | case 'P': return kP; 282 | case 'Q': return kQ; 283 | case 'R': return kR; 284 | case 'S': return kS; 285 | case 'T': return kT; 286 | case 'U': return kU; 287 | case 'V': return kV; 288 | case 'W': return kW; 289 | case 'X': return kX; 290 | case 'Y': return kY; 291 | case 'Z': return kZ; 292 | 293 | // TODO VK_GAMEPAD 294 | 295 | default: 296 | return kUnknown; 297 | } 298 | } 299 | 300 | void WindowHelper::processKeyMessage(UINT message, WPARAM wParam, LPARAM lParam) 301 | { 302 | InputEvent event; 303 | event.mouseX = mInput.mInputStatus.mouseX; 304 | event.mouseY = mInput.mInputStatus.mouseY; 305 | 306 | event.key = translateKey(wParam); 307 | if (event.key == kUnknown) 308 | return; // unkown key so do not register the event. 309 | 310 | switch (message) 311 | { 312 | case WM_KEYDOWN: 313 | event.type = etKeyDown; 314 | mInput.mInputStatus.keys[event.key] = true; 315 | break; 316 | case WM_KEYUP: 317 | event.type = etKeyUp; 318 | mInput.mInputStatus.keys[event.key] = false; 319 | break; 320 | 321 | case WM_SYSCHAR: 322 | case WM_CHAR: 323 | event.type = etKeyChar; 324 | break; 325 | } 326 | 327 | if (event.key == kControl) 328 | { 329 | mInput.mInputStatus.keys[kLcontrol] = GetKeyState(VK_LCONTROL)!=0; 330 | mInput.mInputStatus.keys[kRcontrol] = GetKeyState(VK_RCONTROL)!=0; 331 | } 332 | else if (event.key == kShift) 333 | { 334 | mInput.mInputStatus.keys[kLshift] = GetKeyState(VK_LSHIFT)!=0; 335 | mInput.mInputStatus.keys[kRshift] = GetKeyState(VK_RSHIFT)!=0; 336 | } 337 | 338 | mInput.mInputEvents.push_back(event); 339 | } 340 | 341 | void WindowHelper::processWindowSizeMessage(UINT message, WPARAM wParam, LPARAM lParam) 342 | { 343 | mWindowResizedCallback(lParam); 344 | } 345 | 346 | 347 | -------------------------------------------------------------------------------- /Application/Application.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {2CA77969-0EC4-4607-93CC-C63915A2C01F} 23 | Win32Proj 24 | Application 25 | 10.0.18362.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v141 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v141 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v141 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v141 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | 75 | 76 | true 77 | $(ProjectDir)..\$(Platform)\$(Configuration)\$(ProjectName)\ 78 | 79 | 80 | false 81 | 82 | 83 | true 84 | $(ProjectDir)..\$(Platform)\$(Configuration)\$(ProjectName)\ 85 | 86 | 87 | 88 | 89 | 90 | Level3 91 | Disabled 92 | WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) 93 | true 94 | 95 | 96 | Windows 97 | true 98 | 99 | 100 | 101 | 102 | 103 | 104 | Level3 105 | Disabled 106 | _DEBUG;_WINDOWS;%(PreprocessorDefinitions);IMGUI_DISABLE_OBSOLETE_FUNCTIONS 107 | true 108 | $(SolutionDir)imgui;$(SolutionDir);%(AdditionalIncludeDirectories) 109 | 110 | 111 | Windows 112 | true 113 | dx12Base.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 114 | $(TargetDir) 115 | 116 | 117 | 118 | 119 | Level3 120 | 121 | 122 | MaxSpeed 123 | true 124 | true 125 | WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) 126 | true 127 | 128 | 129 | Windows 130 | true 131 | true 132 | true 133 | 134 | 135 | 136 | 137 | Level3 138 | 139 | 140 | Full 141 | true 142 | true 143 | NDEBUG;_WINDOWS;%(PreprocessorDefinitions);IMGUI_DISABLE_OBSOLETE_FUNCTIONS 144 | true 145 | $(IntDir) 146 | $(IntDir) 147 | $(IntDir) 148 | $(IntDir) 149 | $(SolutionDir)imgui;$(SolutionDir);%(AdditionalIncludeDirectories) 150 | 151 | 152 | Windows 153 | true 154 | true 155 | DebugFastLink 156 | dx12Base.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 157 | $(TargetDir) 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | true 188 | true 189 | 190 | 191 | true 192 | true 193 | 194 | 195 | true 196 | true 197 | 198 | 199 | true 200 | true 201 | true 202 | true 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 215 | 216 | 217 | 218 | -------------------------------------------------------------------------------- /DirectXTex/ReadMe.txt: -------------------------------------------------------------------------------- 1 | DIRECTX TEXTURE LIBRARY (DirectXTex) 2 | ------------------------------------ 3 | 4 | Copyright (c) Microsoft Corporation. All rights reserved. 5 | 6 | July 26, 2017 7 | 8 | This package contains DirectXTex, a shared source library for reading and writing DDS 9 | files, and performing various texture content processing operations including 10 | resizing, format conversion, mip-map generation, block compression for Direct3D runtime 11 | texture resources, and height-map to normal-map conversion. This library makes 12 | use of the Windows Image Component (WIC) APIs. It also includes simple .TGA and .HDR 13 | readers and writers since these image file formats are commonly used for texture content 14 | processing pipelines, but are not currently supported by a built-in WIC codec. 15 | 16 | The source is written for Visual Studio 2013 or 2015. It is recommended that you 17 | make use of VS 2013 Update 5 or VS 2015 Update 3 and Windows 7 Service Pack 1 or later. 18 | 19 | DirectXTex\ 20 | This contains the DirectXTex library. This includes a full-featured DDS reader and writer 21 | including legacy format conversions, a TGA reader and writer, a HDR reader and writer, 22 | a WIC-based bitmap reader and writer (BMP, JPEG, PNG, TIFF, and HD Photo), and various 23 | texture processing functions. This is intended primarily for tool usage. 24 | 25 | Note that the majority of the header files here are intended for internal implementation 26 | of the library only (BC.h, BCDirectCompute.h, DDS.h, DirectXTexP.h, filters.h, and scoped.h). 27 | Only DirectXTex.h is meant as a 'public' header for the library. 28 | 29 | Texconv\ 30 | This DirectXTex sample is an implementation of the "texconv" command-line texture utility 31 | from the DirectX SDK utilizing DirectXTex rather than D3DX. 32 | 33 | It supports the same arguments as the Texture Conversion Tool Extended (texconvex.exe) DirectX 34 | SDK utility. The primary differences are the -10 and -11 arguments are not applicable and the 35 | filter names (POINT, LINEAR, CUBIC, FANT or BOX, TRIANGLE, *_DITHER, *_DITHER_DIFFUSION). 36 | This also includes support for the JPEG XR (HD Photo) bitmap format. 37 | (see ) 38 | 39 | See for details. 40 | 41 | Texassemble\ 42 | This DirectXTex sample is a command-line utility for creating cubemaps, volume maps, or 43 | texture arrays from a set of individual input image files. 44 | 45 | See for details. 46 | 47 | Texdiag\ 48 | This DirectXTex sample is a command-line utility for analyzing image contents, primarily for 49 | debugging purposes. 50 | 51 | See 52 | 53 | DDSView\ 54 | This DirectXTex sample is a simple Direct3D 11-based viewer for DDS files. For array textures 55 | or volume maps, the "<" and ">" keyboard keys will show different images contained in the DDS. 56 | The "1" through "0" keys can also be used to jump to a specific image index. 57 | 58 | DDSTextureLoader\ 59 | This contains a streamlined version of the DirectX SDK sample DDSWithoutD3DX11 texture 60 | loading code for a simple light-weight runtime DDS loader. This version only supports 61 | Direct3D 11 or Direct3D 12 and performs no runtime pixel data conversions (i.e. 24bpp 62 | legacy DDS files always fail). This is ideal for runtime usage, and supports the full 63 | complement of Direct3D texture resources (1D, 2D, volume maps, cubemaps, mipmap levels, 64 | texture arrays, BC formats, etc.). 65 | 66 | ScreenGrab\ 67 | This contains screen grab modules for Direct3D 11 and Direct3D 12 primarily intended 68 | for creating screenshots. The images are written as a DDS or as an image file format 69 | using WIC. 70 | 71 | WICTextureLoader\ 72 | This contains a Direct3D 11 and Direct3D 12 2D texture loader that uses WIC to load a 73 | bitmap (BMP, JPEG, PNG, HD Photo, or other WIC supported file container), resize if needed 74 | based on the current feature level (or by explicit parameter), format convert to a 75 | DXGI_FORMAT if required, and then create a 2D texture. Note this does not support 1D textures, 76 | volume textures, cubemaps, or texture arrays. DDSTextureLoader is recommended for fully 77 | "precooked" textures for maximum performance and image quality, but this loader can be useful 78 | for creating simple 2D texture from standard image files at runtime. 79 | 80 | NOTE: DDSTextureLoader, ScreenGrab, and WICTextureLoader are 'stand-alone' versions of the same 81 | modules provided in the DirectX Tool Kit. 82 | 83 | All content and source code for this package are subject to the terms of the MIT License. 84 | . 85 | 86 | Documentation is available at . 87 | 88 | For the latest version of DirectXTex, bug reports, etc. please visit the project site. 89 | 90 | http://go.microsoft.com/fwlink/?LinkId=248926 91 | 92 | This project has adopted the Microsoft Open Source Code of Conduct. For more information see the 93 | Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments. 94 | 95 | https://opensource.microsoft.com/codeofconduct/ 96 | 97 | 98 | ------------------------------------ 99 | RELEASE NOTES 100 | 101 | * The alpha mode specification for DDS files was updated between the March 2013 and April 2013 releases. Any 102 | DDS files created using the DDS_FLAGS_FORCE_DX10_EXT_MISC2 flag or the texconv -dx10 switch using the 103 | March 2013 release should be refreshed. 104 | 105 | * Due to the underlying Windows BMP WIC codec, alpha channels are not supported for 16bpp or 32bpp BMP pixel format 106 | files. The Windows 8.x and Windows 10 version of the Windows BMP WIC codec does support 32bpp pixel formats with 107 | alpha when using the BITMAPV5HEADER file header. Note the updated WIC is available on Windows 7 SP1 with KB 2670838 108 | installed. 109 | 110 | * While DXGI 1.0 and DXGI 1.1 include 5:6:5 (DXGI_FORMAT_B5G6R5_UNORM) and 5:5:5:1 (DXGI_FORMAT_B5G5R5A1_UNORM) 111 | pixel format enumerations, the DirectX 10.x and 11.0 Runtimes do not support these formats for use with Direct3D. 112 | The DirectX 11.1 runtime, DXGI 1.2, and the WDDM 1.2 driver model fully support 16bpp formats (5:6:5, 5:5:5:1, and 113 | 4:4:4:4). 114 | 115 | * WICTextureLoader cannot load .TGA or .HDR files unless the system has a 3rd party WIC codec installed. You 116 | must use the DirectXTex library for TGA/HDR file format support without relying on an add-on WIC codec. 117 | 118 | * Loading of 96bpp floating-point TIFF files results in a corrupted image prior to Windows 8. This fix is available 119 | on Windows 7 SP1 with KB 2670838 installed. 120 | 121 | 122 | ------------------------------------ 123 | RELEASE HISTORY 124 | 125 | July 26, 2017 126 | Support for reading non-standard DDS files written by nVidia Texture Tools (NVTT) 127 | Fix for ComputeMSE when using CMSE_IMAGE2_X2_BIAS 128 | Fix for WIC writer then codec target format requires a palette 129 | Code cleanup 130 | 131 | April 24, 2017 132 | VS 2017 project updates 133 | Regenerated shaders using Windows 10 Creators Update SDK (15063) 134 | Updated D3DX12 internal copy to latest version 135 | 136 | April 7, 2017 137 | VS 2017 updated for Windows Creators Update SDK (15063) 138 | texassemble: -tonemap switch 139 | texconv: -wicmulti switch 140 | 141 | January 31, 2017 142 | DirectX 12 versions of IsSupported, CreateTexture (PrepareUpload), and CaptureTexture 143 | Update to DirectX 11 version of IsSupported 144 | WIC format 40bppCMYKAlpha should be converted to RGBA8 rather than RGBA16 145 | DDS support for L8A8 with bitcount 8 rather than 16 146 | DXGI_FORMAT_R32G8X24_TYPELESS and DXGI_FORMAT_R24G8_TYPELESS should be IsDepthStencil formats 147 | Updates to DDSTextureLoader, ScreenGrab, and WICTextureLoader 148 | Minor code cleanup 149 | 150 | December 5, 2016 151 | Fixed over-validation in DDS header parsing 152 | VS 2017 RC projects added 153 | Minor code cleanup 154 | 155 | October 5, 2016 156 | *breaking change* 157 | Renamed Evaluate to EvaluateImage, Transform to TransformImage 158 | texdiag: new command-line tool for texture debugging 159 | texconv: -bcmax, -bcquick, -tonemap, and -x2bias switches 160 | texconv: overwrite writing and -y switch 161 | texconv/texassemble: optional OpenEXR support 162 | texassemble: command syntax with support for generating strip and cross images from cubemap 163 | Updates to DDSTextureLoader, WICTextureLoader, and ScreenGrab 164 | Minor code cleanup 165 | 166 | September 14, 2016 167 | HDR (RGBE Radiance) file format reader and writer 168 | Evaluate and Transform functions for computing user-defined functions on images 169 | Fix BC6H GPU shaders on WARP device 170 | Fix for alignment issues on ARM devices in software compression codec 171 | Added TEX_THRESHOLD_DEFAULT (0.5f) constant default alpha threshold value for Convert & Compress 172 | Minor CaptureTexture optimization 173 | texconv/texassemble: Support for .hdr file format 174 | texconv: added -gpu switch to specify adapter to use for GPU-based compression codecs 175 | texconv: added -badtails switch to enable loading of legacy DXTn DDS files with incomplete mipchain tails 176 | texconv: added -c switch for old-school colorkey/chromakey transparency to alpha conversion 177 | texconv: added -alpha switch for reverse premultiply along with TEX_PMALPHA_REVERSE flag 178 | texconv: added wildcard support for input filename and optional -r switch for recursive search 179 | 180 | August 4, 2016 181 | CompileShader script updated to build external pdbs 182 | Regenerated shaders using Windows 10 Anniversary Update SDK (14393) 183 | 184 | August 2, 2016 185 | Updated for VS 2015 Update 3 and Windows 10 SDK (14393) 186 | 187 | August 1, 2016 188 | Workaround for bug in XMStoreFloat3SE (impacts conversions to DXGI_FORMAT_R9G9B9E5_SHAREDEXP) 189 | DDSTextureLoader12, WICTextureLoader12, and ScreenGrab12 for Direct3D 12 support 190 | Minor code cleanup 191 | 192 | June 27, 2016 193 | texconv command-line tool -wicq and -wiclossless switches 194 | Code cleanup 195 | 196 | April 26, 2016 197 | Optional callback from WIC reader functions to query additional metadata 198 | Retired obsolete adapter code 199 | Minor code cleanup 200 | 201 | February 23, 2016 202 | Fix to clean up partial or zero-length image files on failed write 203 | Retired VS 2012 projects 204 | 205 | November 30, 2015 206 | texconv command-line tool -fl switch now supports 12.0 and 12.1 feature levels 207 | Updated for VS 2015 Update 1 and Windows 10 SDK (10586) 208 | 209 | October 30, 2015 210 | DDS support for legacy bumpmap formats (V8U8, Q8W8V8U8, V16U16) 211 | Fix for buffer overread in BC CPU compressor 212 | Minor code cleanup 213 | 214 | August 18, 2015 215 | Added GetWICFactory and SetWICFactory 216 | Updates for new DXGI 1.3 types 217 | Xbox One platform updates 218 | 219 | July 29, 2015 220 | Fixed rounding problem with 32-bit RGBA/BGRA format conversions 221 | texconv: use CPU parallel compression for BC1-BC5 (-singleproc disables) 222 | Updated for VS 2015 and Windows 10 SDK RTM 223 | Retired VS 2010 and Windows 8.0 Store projects 224 | 225 | June 18, 2015 226 | New BC_FLAGS_USE_3SUBSETS option for BC7 compressors; now defaults to skipping 3 subset blocks 227 | Fixed bug with MakeTypeless and A8_UNORM 228 | Fixed file length validation problem in LoadDDSFromFile 229 | 230 | March 27, 2015 231 | Added projects for Windows apps Technical Preview 232 | Fixed bug with WIC-based mipmap generation for non-WIC supported formats 233 | Fixed bug with WIC multiframe loader when resizing required 234 | texconv: Added -nmap/-nmapamp for generating normal maps from height maps 235 | texconv/texassemble: Updated to load multiframe WIC files (tiff, gif) 236 | Minor code cleanup 237 | 238 | November 24, 2014 239 | Updates for Visual Studio 2015 Technical Preview 240 | Minor code cleanup 241 | 242 | September 22, 2014 243 | Format conversion improvements and bug fixes (depth/stencil, alpha-only, float16, RGB -> 1 channel) 244 | Fixed issue when BC decompressing non-standard compressed rowPitch images 245 | Explicit calling-convention annotation for all 'public' functions 246 | Code cleanup 247 | Xbox One platform updates 248 | 249 | July 15, 2014 250 | texconv command-line tool fixes 251 | Fixed problem with 'wide' images with CPU Compress 252 | Updates to Xbox One platform support 253 | 254 | April 3, 2014 255 | Windows phone 8.1 platform support 256 | 257 | February 24, 2014 258 | Direct3D 11 video and Xbox One extended format support 259 | New APIs: IsPlanar, IsPalettized, IsDepthStencil, ConvertToSinglePlane 260 | Added 'alphaWeight' parameter to GPU Compress [breaking change] 261 | texconv '-aw' switch to control the alpha weighting for the BC7 GPU compressor 262 | Fixed bug with ordered dithering in non-WIC conversion codepaths 263 | Fixed SaveToDDS* functions when using arbitrary row pitch values 264 | 265 | January 24, 2014 266 | Added sRGB flags for Compress (TEX_COMPRESS_SRGB*) 267 | Added 'compress' flag parameter to GPU versions of Compress [breaking change] 268 | Minor fix for potential rounding problem in GPU Compress 269 | Code cleanup (removed DXGI_1_2_FORMATS control define; ScopedObject typedef removed) 270 | Dropped VS 2010 support without the Windows 8.1 SDK (removed USE_XNAMATH control define) 271 | 272 | December 24, 2013 273 | texconv updated with -fl and -pow2 command-line switches 274 | Fixed bug in Resize when doing custom filtering which occurred when exactly doubling the image size 275 | Added move operators to ScratchImage and Blob classes 276 | Xbox One platform support 277 | 278 | October 21, 2013 279 | Updated for Visual Studio 2013 and Windows 8.1 SDK RTM 280 | PremultiplyAlpha updated with new 'flags' parameter and to use sRGB correct blending 281 | Fixed colorspace conversion issue with DirectCompute compressor when compressing for BC7 SRGB 282 | 283 | August 13, 2013 284 | DirectCompute 4.0 BC6H/BC7 compressor integration 285 | texconv utility uses DirectCompute compression by default for BC6H/BC7, -nogpu disables use of DirectCompute 286 | 287 | August 1, 2013 288 | Support for BC compression/decompression of non-power-of-2 mipmapped textures 289 | Fixes for BC6H / BC7 codecs to better match published standard 290 | Fix for BC4 / BC5 codecs when compressing RGB images 291 | Minor fix for the BC1-3 codec 292 | New optional flags for ComputeMSE to compare UNORM vs. SNORM images 293 | New WIC loading flag added to control use of WIC metadata to return sRGB vs. non-sRGB formats 294 | Code cleanup and /analyze fixes 295 | Project file cleanup 296 | Texconv utility uses parallel BC compression by default for BC6H/BC7, -singleproc disables multithreaded behavior 297 | 298 | July 1, 2013 299 | VS 2013 Preview projects added 300 | SaveToWIC functions updated with new optional setCustomProps parameter 301 | 302 | June 15, 2013 303 | Custom filtering implementation for Resize & GenerateMipMaps(3D) - Point, Box, Linear, Cubic, and Triangle 304 | TEX_FILTER_TRIANGLE finite low-pass triangle filter 305 | TEX_FILTER_WRAP, TEX_FILTER_MIRROR texture semantics for custom filtering 306 | TEX_FILTER_BOX alias for TEX_FILTER_FANT WIC 307 | Ordered and error diffusion dithering for non-WIC conversion 308 | sRGB gamma correct custom filtering and conversion 309 | DDS_FLAGS_EXPAND_LUMINANCE - Reader conversion option for L8, L16, and A8L8 legacy DDS files 310 | Added use of WIC metadata for sRGB pixel formats 311 | Added BitsPerColor utility function 312 | Fixed Convert threshold parameter usage 313 | Non-power-of-2 volume map support, fixed bug with non-square volume maps 314 | Texconv utility update with -xlum, -wrap, and -mirror options; reworked -if options for improved dithering 315 | Texassemble utility for creating cubemaps, volume maps, and texture arrays 316 | DDSTextureLoader and WICTextureLoader sync'd with DirectXTK versions 317 | 318 | April 16, 2013 319 | Updated alpha-mode metadata details in .DDS files 320 | Added new control flags for Convert 321 | Added new optional flags for ComputeMSE 322 | Fixed conversion handling for sRGB formats 323 | Fixed internal routines for handling R10G10B10_XR_BIAS_A2_UNORM, R9G9B9E5_SHAREDEXP, and FORMAT_R1_UNORM 324 | Fixed WIC I/O for GUID_WICPixelFormat32bppRGBE pixel format files (HD Photo) 325 | Fixed non-square image handling in GenerateMipMaps3D 326 | Fixed some error handling in the DDS load code 327 | 328 | March 22, 2013 329 | Supports reading and writing alpha-mode (straight, premultiplied, etc.) metadata in .DDS files 330 | Added build option to use WICCreateImagingFactory_Proxy instead of CoCreateInstance to obtain WIC factory 331 | 332 | January 29, 2013 333 | Added PremultiplyAlpha to DirectXTex; -pmalpha switch for texconv command-line tool 334 | Fixed problem with forceSRGB implementation for Ex versions of CreateTexture, CreateShaderResourceView, DDSTextureLoader and WICTextureLoader 335 | 336 | December 11, 2012 337 | Ex versions of CreateTexture, CreateShaderResourceView, DDSTextureLoader and WICTextureLoader 338 | Fixed BC2 and BC3 decompression issue for unusual color encoding case 339 | Converted annotation to SAL2 for improved VS 2012 /analyze experience 340 | Updated DirectXTex, DDSView, and Texconv with VS 2010 + Windows 8.0 SDK project using official 'property sheets' 341 | 342 | November 15, 2012 343 | Added support for WIC2 when available on Windows 8 and Windows 7 with KB 2670838 344 | Added optional targetGUID parameter to SaveWIC* APIs to influence final container pixel format choice 345 | Fixed bug in SaveDDS* which was generating invalid DDS files for 1D dimension textures 346 | Improved robustness of CaptureTexture when resolving MSAA source textures 347 | Sync'd DDSTextureLoader, ScreenGrab, and WICTextureLoader standalone versions with latest DirectXTK release 348 | 349 | September 28, 2012 350 | Added ScreenGrab module for creating runtime screenshots 351 | Renamed project files for better naming consistency 352 | New Typeless utilities for DirectXTex 353 | Some minor code cleanup for DirectXTex's WIC writer function 354 | Bug fixes and new -tu/-tf options for texconv 355 | 356 | June 22, 2012 357 | Moved to using XNA Math 2.05 instead of XNA Math 2.04 for USE_XNAMATH builds 358 | Fixed BGR vs. RGB color channel swizzle problem with 24bpp legacy .DDS files in DirectXTex 359 | Update to DirectXTex WIC and WICTextureLoader for additional 96bpp float format handling on Windows 8 360 | 361 | May 31, 2012 362 | Minor fix for DDSTextureLoader's retry fallback that can happen with 10level9 feature levels 363 | Switched to use "_DEBUG" instead of "DEBUG" and cleaned up debug warnings 364 | added Windows Store style application project files for DirectXTex 365 | 366 | April 20, 2012 367 | DirectTex's WIC-based writer opts-in for the Windows 8 BMP encoder option for writing 32 bpp RGBA files with the BITMAPV5HEADER 368 | 369 | March 30, 2012 370 | WICTextureLoader updated with Windows 8 WIC pixel formats 371 | DirectXTex updated with limited non-power-of-2 texture support and TEX_FILTER_SEPARATE_ALPHA option 372 | Texconv updated with '-sepalpha' command-line option 373 | Added USE_XNAMATH control define to build DirectXTex using either XNAMath or DirectXMath 374 | Added VS 2012 project files (which use DirectXMath instead of XNAMath and define DXGI_1_2_FORMATS) 375 | 376 | March 15, 2012 377 | Fix for resource leak in CreateShaderResourceView() Direct3D 11 helper function in DirectXTex 378 | 379 | March 5, 2012 380 | Fix for too much temp memory allocated by WICTextureLoader; cleaned up legacy 'min/max' macro usage in DirectXTex 381 | 382 | February 21, 2012 383 | WICTextureLoader updated to handle systems and device drivers without BGRA or 16bpp format support 384 | 385 | February 20, 2012 386 | Some code cleanup for DirectXTex and DDSTextureLoader 387 | Fixed bug in 10:10:10:2 format fixup in the LoadDDSFromMemory function 388 | Fixed bugs in "non-zero alpha" special-case handling in LoadTGAFromFile 389 | Fixed bug in _SwizzleScanline when copying alpha channel for BGRA<->RGBA swizzling 390 | 391 | February 11, 2012 392 | Update of DDSTextureLoader to also build in Windows Store style apps; added WICTextureLoader 393 | Added CMYK WIC pixel formats to the DirectXTex conversion table 394 | 395 | January 30, 2012 396 | Minor code-cleanup for DirectXTex to enable use of PCH through 'directxtexp.h' header 397 | 398 | January 24, 2011 399 | Some code-cleanup for DirectXTex 400 | Added DXGI 1.2 implementation for DDSTextureLoader and DirectXTex guarded with DXGI_1_2_FORMATS compiliation define 401 | 402 | December 16, 2011 403 | Fixed x64 compilation warnings in DDSTextureLoader 404 | 405 | November 30, 2011 406 | Fixed some of the constants used in IsSupportedTexture(), 407 | added ability to strip off top levels of mips in DDSTextureLoader, 408 | changed DirectXTex to use CoCreateInstance rather than LoadLibrary to obtain the WIC factory, 409 | a few minor /analyze related annotations for DirectXTex 410 | 411 | October 27, 2011 412 | Original release -------------------------------------------------------------------------------- /DirectXTex/WICTextureLoader/WICTextureLoader12.cpp: -------------------------------------------------------------------------------- 1 | //-------------------------------------------------------------------------------------- 2 | // File: WICTextureLoader12.cpp 3 | // 4 | // Function for loading a WIC image and creating a Direct3D 12 runtime texture for it 5 | // (auto-generating mipmaps if possible) 6 | // 7 | // Note: Assumes application has already called CoInitializeEx 8 | // 9 | // Note these functions are useful for images created as simple 2D textures. For 10 | // more complex resources, DDSTextureLoader is an excellent light-weight runtime loader. 11 | // For a full-featured DDS file reader, writer, and texture processing pipeline see 12 | // the 'Texconv' sample and the 'DirectXTex' library. 13 | // 14 | // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 15 | // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 16 | // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 17 | // PARTICULAR PURPOSE. 18 | // 19 | // Copyright (c) Microsoft Corporation. All rights reserved. 20 | // 21 | // http://go.microsoft.com/fwlink/?LinkId=248926 22 | // http://go.microsoft.com/fwlink/?LinkID=615561 23 | //-------------------------------------------------------------------------------------- 24 | 25 | // Modified by SebH 26 | 27 | // We could load multi-frame images (TIFF/GIF) into a texture array. 28 | // For now, we just load the first frame (note: DirectXTex supports multi-frame images) 29 | 30 | #include "WICTextureLoader12.h" 31 | 32 | #include 33 | #include 34 | 35 | #include 36 | 37 | #include 38 | 39 | #include 40 | 41 | using namespace DirectX; 42 | using Microsoft::WRL::ComPtr; 43 | 44 | namespace 45 | { 46 | //------------------------------------------------------------------------------------- 47 | // WIC Pixel Format Translation Data 48 | //------------------------------------------------------------------------------------- 49 | struct WICTranslate 50 | { 51 | GUID wic; 52 | DXGI_FORMAT format; 53 | }; 54 | 55 | const WICTranslate g_WICFormats[] = 56 | { 57 | { GUID_WICPixelFormat128bppRGBAFloat, DXGI_FORMAT_R32G32B32A32_FLOAT }, 58 | 59 | { GUID_WICPixelFormat64bppRGBAHalf, DXGI_FORMAT_R16G16B16A16_FLOAT }, 60 | { GUID_WICPixelFormat64bppRGBA, DXGI_FORMAT_R16G16B16A16_UNORM }, 61 | 62 | { GUID_WICPixelFormat32bppRGBA, DXGI_FORMAT_R8G8B8A8_UNORM }, 63 | { GUID_WICPixelFormat32bppBGRA, DXGI_FORMAT_B8G8R8A8_UNORM }, 64 | { GUID_WICPixelFormat32bppBGR, DXGI_FORMAT_B8G8R8X8_UNORM }, 65 | 66 | { GUID_WICPixelFormat32bppRGBA1010102XR, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM }, 67 | { GUID_WICPixelFormat32bppRGBA1010102, DXGI_FORMAT_R10G10B10A2_UNORM }, 68 | 69 | { GUID_WICPixelFormat16bppBGRA5551, DXGI_FORMAT_B5G5R5A1_UNORM }, 70 | { GUID_WICPixelFormat16bppBGR565, DXGI_FORMAT_B5G6R5_UNORM }, 71 | 72 | { GUID_WICPixelFormat32bppGrayFloat, DXGI_FORMAT_R32_FLOAT }, 73 | { GUID_WICPixelFormat16bppGrayHalf, DXGI_FORMAT_R16_FLOAT }, 74 | { GUID_WICPixelFormat16bppGray, DXGI_FORMAT_R16_UNORM }, 75 | { GUID_WICPixelFormat8bppGray, DXGI_FORMAT_R8_UNORM }, 76 | 77 | { GUID_WICPixelFormat8bppAlpha, DXGI_FORMAT_A8_UNORM }, 78 | 79 | { GUID_WICPixelFormat96bppRGBFloat, DXGI_FORMAT_R32G32B32_FLOAT }, 80 | }; 81 | 82 | //------------------------------------------------------------------------------------- 83 | // WIC Pixel Format nearest conversion table 84 | //------------------------------------------------------------------------------------- 85 | 86 | struct WICConvert 87 | { 88 | GUID source; 89 | GUID target; 90 | }; 91 | 92 | const WICConvert g_WICConvert[] = 93 | { 94 | // Note target GUID in this conversion table must be one of those directly supported formats (above). 95 | 96 | { GUID_WICPixelFormatBlackWhite, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM 97 | 98 | { GUID_WICPixelFormat1bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM 99 | { GUID_WICPixelFormat2bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM 100 | { GUID_WICPixelFormat4bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM 101 | { GUID_WICPixelFormat8bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM 102 | 103 | { GUID_WICPixelFormat2bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM 104 | { GUID_WICPixelFormat4bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM 105 | 106 | { GUID_WICPixelFormat16bppGrayFixedPoint, GUID_WICPixelFormat16bppGrayHalf }, // DXGI_FORMAT_R16_FLOAT 107 | { GUID_WICPixelFormat32bppGrayFixedPoint, GUID_WICPixelFormat32bppGrayFloat }, // DXGI_FORMAT_R32_FLOAT 108 | 109 | { GUID_WICPixelFormat16bppBGR555, GUID_WICPixelFormat16bppBGRA5551 }, // DXGI_FORMAT_B5G5R5A1_UNORM 110 | 111 | { GUID_WICPixelFormat32bppBGR101010, GUID_WICPixelFormat32bppRGBA1010102 }, // DXGI_FORMAT_R10G10B10A2_UNORM 112 | 113 | { GUID_WICPixelFormat24bppBGR, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM 114 | { GUID_WICPixelFormat24bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM 115 | { GUID_WICPixelFormat32bppPBGRA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM 116 | { GUID_WICPixelFormat32bppPRGBA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM 117 | 118 | { GUID_WICPixelFormat48bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM 119 | { GUID_WICPixelFormat48bppBGR, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM 120 | { GUID_WICPixelFormat64bppBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM 121 | { GUID_WICPixelFormat64bppPRGBA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM 122 | { GUID_WICPixelFormat64bppPBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM 123 | 124 | { GUID_WICPixelFormat48bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT 125 | { GUID_WICPixelFormat48bppBGRFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT 126 | { GUID_WICPixelFormat64bppRGBAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT 127 | { GUID_WICPixelFormat64bppBGRAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT 128 | { GUID_WICPixelFormat64bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT 129 | { GUID_WICPixelFormat64bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT 130 | { GUID_WICPixelFormat48bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT 131 | 132 | { GUID_WICPixelFormat128bppPRGBAFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT 133 | { GUID_WICPixelFormat128bppRGBFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT 134 | { GUID_WICPixelFormat128bppRGBAFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT 135 | { GUID_WICPixelFormat128bppRGBFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT 136 | { GUID_WICPixelFormat32bppRGBE, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT 137 | 138 | { GUID_WICPixelFormat32bppCMYK, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM 139 | { GUID_WICPixelFormat64bppCMYK, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM 140 | { GUID_WICPixelFormat40bppCMYKAlpha, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM 141 | { GUID_WICPixelFormat80bppCMYKAlpha, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM 142 | 143 | { GUID_WICPixelFormat32bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM 144 | { GUID_WICPixelFormat64bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM 145 | { GUID_WICPixelFormat64bppPRGBAHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT 146 | 147 | { GUID_WICPixelFormat96bppRGBFixedPoint, GUID_WICPixelFormat96bppRGBFloat }, // DXGI_FORMAT_R32G32B32_FLOAT 148 | 149 | // We don't support n-channel formats 150 | }; 151 | 152 | IWICImagingFactory2* _GetWIC() 153 | { 154 | static INIT_ONCE s_initOnce = INIT_ONCE_STATIC_INIT; 155 | 156 | IWICImagingFactory2* factory = nullptr; 157 | (void)InitOnceExecuteOnce(&s_initOnce, 158 | [](PINIT_ONCE, PVOID, PVOID *factory) -> BOOL 159 | { 160 | return SUCCEEDED( CoCreateInstance( 161 | CLSID_WICImagingFactory2, 162 | nullptr, 163 | CLSCTX_INPROC_SERVER, 164 | __uuidof(IWICImagingFactory2), 165 | factory) ) ? TRUE : FALSE; 166 | }, nullptr, reinterpret_cast(&factory)); 167 | 168 | return factory; 169 | } 170 | 171 | //--------------------------------------------------------------------------------- 172 | template 173 | inline void SetDebugObjectName(_In_ ID3D12DeviceChild* resource, _In_z_ const wchar_t(&name)[TNameLength]) 174 | { 175 | #if !defined(NO_D3D12_DEBUG_NAME) && ( defined(_DEBUG) || defined(PROFILE) ) 176 | resource->SetName(name); 177 | #else 178 | UNREFERENCED_PARAMETER(resource); 179 | UNREFERENCED_PARAMETER(name); 180 | #endif 181 | } 182 | 183 | inline uint32_t CountMips(uint32_t width, uint32_t height) 184 | { 185 | if (width == 0 || height == 0) 186 | return 0; 187 | 188 | uint32_t count = 1; 189 | while (width > 1 || height > 1) 190 | { 191 | width >>= 1; 192 | height >>= 1; 193 | count++; 194 | } 195 | return count; 196 | } 197 | 198 | //-------------------------------------------------------------------------------------- 199 | DXGI_FORMAT MakeSRGB(_In_ DXGI_FORMAT format) 200 | { 201 | switch (format) 202 | { 203 | case DXGI_FORMAT_R8G8B8A8_UNORM: 204 | return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; 205 | 206 | case DXGI_FORMAT_BC1_UNORM: 207 | return DXGI_FORMAT_BC1_UNORM_SRGB; 208 | 209 | case DXGI_FORMAT_BC2_UNORM: 210 | return DXGI_FORMAT_BC2_UNORM_SRGB; 211 | 212 | case DXGI_FORMAT_BC3_UNORM: 213 | return DXGI_FORMAT_BC3_UNORM_SRGB; 214 | 215 | case DXGI_FORMAT_B8G8R8A8_UNORM: 216 | return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; 217 | 218 | case DXGI_FORMAT_B8G8R8X8_UNORM: 219 | return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; 220 | 221 | case DXGI_FORMAT_BC7_UNORM: 222 | return DXGI_FORMAT_BC7_UNORM_SRGB; 223 | 224 | default: 225 | return format; 226 | } 227 | } 228 | 229 | //--------------------------------------------------------------------------------- 230 | DXGI_FORMAT _WICToDXGI(const GUID& guid) 231 | { 232 | for (size_t i = 0; i < _countof(g_WICFormats); ++i) 233 | { 234 | if (memcmp(&g_WICFormats[i].wic, &guid, sizeof(GUID)) == 0) 235 | return g_WICFormats[i].format; 236 | } 237 | 238 | return DXGI_FORMAT_UNKNOWN; 239 | } 240 | 241 | //--------------------------------------------------------------------------------- 242 | size_t _WICBitsPerPixel(REFGUID targetGuid) 243 | { 244 | auto pWIC = _GetWIC(); 245 | if (!pWIC) 246 | return 0; 247 | 248 | ComPtr cinfo; 249 | if (FAILED(pWIC->CreateComponentInfo(targetGuid, cinfo.GetAddressOf()))) 250 | return 0; 251 | 252 | WICComponentType type; 253 | if (FAILED(cinfo->GetComponentType(&type))) 254 | return 0; 255 | 256 | if (type != WICPixelFormat) 257 | return 0; 258 | 259 | ComPtr pfinfo; 260 | if (FAILED(cinfo.As(&pfinfo))) 261 | return 0; 262 | 263 | UINT bpp; 264 | if (FAILED(pfinfo->GetBitsPerPixel(&bpp))) 265 | return 0; 266 | 267 | return bpp; 268 | } 269 | 270 | //--------------------------------------------------------------------------------- 271 | HRESULT CreateTextureFromWIC( 272 | _In_ IWICBitmapFrameDecode *frame, 273 | size_t maxsize, 274 | unsigned int loadFlags, 275 | TextureData& texData) 276 | { 277 | UINT width, height; 278 | HRESULT hr = frame->GetSize(&width, &height); 279 | if (FAILED(hr)) 280 | return hr; 281 | 282 | assert(width > 0 && height > 0); 283 | 284 | if (!maxsize) 285 | { 286 | maxsize = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; 287 | } 288 | 289 | assert(maxsize > 0); 290 | 291 | UINT twidth, theight; 292 | if (width > maxsize || height > maxsize) 293 | { 294 | float ar = static_cast(height) / static_cast(width); 295 | if (width > height) 296 | { 297 | twidth = static_cast(maxsize); 298 | theight = std::max(1, static_cast(static_cast(maxsize) * ar)); 299 | } 300 | else 301 | { 302 | theight = static_cast(maxsize); 303 | twidth = std::max(1, static_cast(static_cast(maxsize) / ar)); 304 | } 305 | assert(twidth <= maxsize && theight <= maxsize); 306 | } 307 | else 308 | { 309 | twidth = width; 310 | theight = height; 311 | } 312 | 313 | // Determine format 314 | WICPixelFormatGUID pixelFormat; 315 | hr = frame->GetPixelFormat(&pixelFormat); 316 | if (FAILED(hr)) 317 | return hr; 318 | 319 | WICPixelFormatGUID convertGUID; 320 | memcpy(&convertGUID, &pixelFormat, sizeof(WICPixelFormatGUID)); 321 | 322 | size_t bpp = 0; 323 | 324 | DXGI_FORMAT format = _WICToDXGI(pixelFormat); 325 | if (format == DXGI_FORMAT_UNKNOWN) 326 | { 327 | for (size_t i = 0; i < _countof(g_WICConvert); ++i) 328 | { 329 | if (memcmp(&g_WICConvert[i].source, &pixelFormat, sizeof(WICPixelFormatGUID)) == 0) 330 | { 331 | memcpy(&convertGUID, &g_WICConvert[i].target, sizeof(WICPixelFormatGUID)); 332 | 333 | format = _WICToDXGI(g_WICConvert[i].target); 334 | assert(format != DXGI_FORMAT_UNKNOWN); 335 | bpp = _WICBitsPerPixel(convertGUID); 336 | break; 337 | } 338 | } 339 | 340 | if (format == DXGI_FORMAT_UNKNOWN) 341 | return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); 342 | } 343 | else 344 | { 345 | bpp = _WICBitsPerPixel(pixelFormat); 346 | } 347 | 348 | if (!bpp) 349 | return E_FAIL; 350 | 351 | // Handle sRGB formats 352 | if (loadFlags & WIC_LOADER_FORCE_SRGB) 353 | { 354 | format = MakeSRGB(format); 355 | } 356 | else if (!(loadFlags & WIC_LOADER_IGNORE_SRGB)) 357 | { 358 | ComPtr metareader; 359 | if (SUCCEEDED(frame->GetMetadataQueryReader(metareader.GetAddressOf()))) 360 | { 361 | GUID containerFormat; 362 | if (SUCCEEDED(metareader->GetContainerFormat(&containerFormat))) 363 | { 364 | // Check for sRGB colorspace metadata 365 | bool sRGB = false; 366 | 367 | PROPVARIANT value; 368 | PropVariantInit(&value); 369 | 370 | if (memcmp(&containerFormat, &GUID_ContainerFormatPng, sizeof(GUID)) == 0) 371 | { 372 | // Check for sRGB chunk 373 | if (SUCCEEDED(metareader->GetMetadataByName(L"/sRGB/RenderingIntent", &value)) && value.vt == VT_UI1) 374 | { 375 | sRGB = true; 376 | } 377 | } 378 | else if (SUCCEEDED(metareader->GetMetadataByName(L"System.Image.ColorSpace", &value)) && value.vt == VT_UI2 && value.uiVal == 1) 379 | { 380 | sRGB = true; 381 | } 382 | 383 | (void)PropVariantClear(&value); 384 | 385 | if (sRGB) 386 | format = MakeSRGB(format); 387 | } 388 | } 389 | } 390 | 391 | // Allocate memory for decoded image 392 | size_t rowPitch = (twidth * bpp + 7) / 8; 393 | texData.dataSizeInByte = UINT(rowPitch * theight); 394 | 395 | texData.decodedData.reset(new (std::nothrow) uint8_t[texData.dataSizeInByte]); 396 | if (!texData.decodedData) 397 | return E_OUTOFMEMORY; 398 | 399 | // Load image data 400 | if (memcmp(&convertGUID, &pixelFormat, sizeof(GUID)) == 0 401 | && twidth == width 402 | && theight == height) 403 | { 404 | // No format conversion or resize needed 405 | hr = frame->CopyPixels(0, static_cast(rowPitch), static_cast(texData.dataSizeInByte), texData.decodedData.get()); 406 | if (FAILED(hr)) 407 | return hr; 408 | } 409 | else if (twidth != width || theight != height) 410 | { 411 | // Resize 412 | auto pWIC = _GetWIC(); 413 | if (!pWIC) 414 | return E_NOINTERFACE; 415 | 416 | ComPtr scaler; 417 | hr = pWIC->CreateBitmapScaler(scaler.GetAddressOf()); 418 | if (FAILED(hr)) 419 | return hr; 420 | 421 | hr = scaler->Initialize(frame, twidth, theight, WICBitmapInterpolationModeFant); 422 | if (FAILED(hr)) 423 | return hr; 424 | 425 | WICPixelFormatGUID pfScaler; 426 | hr = scaler->GetPixelFormat(&pfScaler); 427 | if (FAILED(hr)) 428 | return hr; 429 | 430 | if (memcmp(&convertGUID, &pfScaler, sizeof(GUID)) == 0) 431 | { 432 | // No format conversion needed 433 | hr = scaler->CopyPixels(0, static_cast(rowPitch), static_cast(texData.dataSizeInByte), texData.decodedData.get()); 434 | if (FAILED(hr)) 435 | return hr; 436 | } 437 | else 438 | { 439 | ComPtr FC; 440 | hr = pWIC->CreateFormatConverter(FC.GetAddressOf()); 441 | if (FAILED(hr)) 442 | return hr; 443 | 444 | BOOL canConvert = FALSE; 445 | hr = FC->CanConvert(pfScaler, convertGUID, &canConvert); 446 | if (FAILED(hr) || !canConvert) 447 | { 448 | return E_UNEXPECTED; 449 | } 450 | 451 | hr = FC->Initialize(scaler.Get(), convertGUID, WICBitmapDitherTypeErrorDiffusion, nullptr, 0, WICBitmapPaletteTypeMedianCut); 452 | if (FAILED(hr)) 453 | return hr; 454 | 455 | hr = FC->CopyPixels(0, static_cast(rowPitch), static_cast(texData.dataSizeInByte), texData.decodedData.get()); 456 | if (FAILED(hr)) 457 | return hr; 458 | } 459 | } 460 | else 461 | { 462 | // Format conversion but no resize 463 | auto pWIC = _GetWIC(); 464 | if (!pWIC) 465 | return E_NOINTERFACE; 466 | 467 | ComPtr FC; 468 | hr = pWIC->CreateFormatConverter(FC.GetAddressOf()); 469 | if (FAILED(hr)) 470 | return hr; 471 | 472 | BOOL canConvert = FALSE; 473 | hr = FC->CanConvert(pixelFormat, convertGUID, &canConvert); 474 | if (FAILED(hr) || !canConvert) 475 | { 476 | return E_UNEXPECTED; 477 | } 478 | 479 | hr = FC->Initialize(frame, convertGUID, WICBitmapDitherTypeErrorDiffusion, nullptr, 0, WICBitmapPaletteTypeMedianCut); 480 | if (FAILED(hr)) 481 | return hr; 482 | 483 | hr = FC->CopyPixels(0, static_cast(rowPitch), static_cast(texData.dataSizeInByte), texData.decodedData.get()); 484 | if (FAILED(hr)) 485 | return hr; 486 | } 487 | 488 | // Count the number of mips 489 | texData.mipCount = (loadFlags & (WIC_LOADER_MIP_AUTOGEN|WIC_LOADER_MIP_RESERVE)) ? CountMips(twidth, theight) : 1; 490 | texData.width = twidth; 491 | texData.height = theight; 492 | texData.format = format; 493 | 494 | // Create texture 495 | /* D3D12_RESOURCE_DESC desc = {}; 496 | desc.Width = twidth; 497 | desc.Height = theight; 498 | desc.MipLevels = (uint16_t)mipCount; 499 | desc.DepthOrArraySize = 1; 500 | desc.Format = format; 501 | desc.SampleDesc.Count = 1; 502 | desc.SampleDesc.Quality = 0; 503 | desc.Flags = resFlags; 504 | desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; 505 | 506 | CD3DX12_HEAP_PROPERTIES defaultHeapProperties(D3D12_HEAP_TYPE_DEFAULT); 507 | 508 | ID3D12Resource* tex = nullptr; 509 | hr = d3dDevice->CreateCommittedResource( 510 | &defaultHeapProperties, 511 | D3D12_HEAP_FLAG_NONE, 512 | &desc, 513 | D3D12_RESOURCE_STATE_COPY_DEST, 514 | nullptr, 515 | IID_PPV_ARGS(&tex)); 516 | 517 | if (FAILED(hr)) 518 | { 519 | return hr; 520 | } 521 | 522 | _Analysis_assume_(tex != 0); 523 | */ 524 | 525 | texData.subresource.pData = texData.decodedData.get(); 526 | texData.subresource.RowPitch = rowPitch; 527 | texData.subresource.SlicePitch = texData.dataSizeInByte; 528 | 529 | // The texture us mirrored on Y so mirror it now to hqve Y up. 530 | BYTE* textureDataSource = new BYTE[texData.dataSizeInByte]; 531 | { 532 | BYTE* finalData = texData.decodedData.get(); 533 | memcpy(textureDataSource, finalData, texData.dataSizeInByte); 534 | // Now copy rows but in reverse order 535 | for (INT r = height - 1; r >= 0; --r) 536 | { 537 | INT dstR = height - 1 - r; 538 | memcpy(finalData + dstR * rowPitch, textureDataSource + r * rowPitch, rowPitch); 539 | } 540 | } 541 | delete [] textureDataSource; 542 | 543 | // *texture = tex; 544 | return hr; 545 | } 546 | } // anonymous namespace 547 | 548 | 549 | 550 | 551 | //-------------------------------------------------------------------------------------- 552 | _Use_decl_annotations_ 553 | HRESULT DirectX::LoadWICTextureFromFile( 554 | _In_z_ const wchar_t* fileName, 555 | TextureData& texData, 556 | size_t maxsize, 557 | unsigned int loadFlags) 558 | { 559 | if (!fileName ) 560 | return E_INVALIDARG; 561 | 562 | auto pWIC = _GetWIC(); 563 | if ( !pWIC ) 564 | return E_NOINTERFACE; 565 | 566 | // Initialize WIC 567 | ComPtr decoder; 568 | HRESULT hr = pWIC->CreateDecoderFromFilename( fileName, 0, GENERIC_READ, WICDecodeMetadataCacheOnDemand, decoder.GetAddressOf() ); 569 | if ( FAILED(hr) ) 570 | return hr; 571 | 572 | ComPtr frame; 573 | hr = decoder->GetFrame( 0, frame.GetAddressOf() ); 574 | if ( FAILED(hr) ) 575 | return hr; 576 | 577 | hr = CreateTextureFromWIC( frame.Get(), maxsize, 578 | loadFlags, texData); 579 | 580 | //#if !defined(NO_D3D12_DEBUG_NAME) && ( defined(_DEBUG) || defined(PROFILE) ) 581 | // if ( SUCCEEDED(hr) ) 582 | // { 583 | // const wchar_t* pstrName = wcsrchr(fileName, '\\' ); 584 | // if (!pstrName) 585 | // { 586 | // pstrName = fileName; 587 | // } 588 | // else 589 | // { 590 | // pstrName++; 591 | // } 592 | // 593 | // if (texture != 0 && *texture != 0) 594 | // { 595 | // (*texture)->SetName(pstrName); 596 | // } 597 | // } 598 | //#endif 599 | 600 | return hr; 601 | } 602 | 603 | 604 | 605 | 606 | -------------------------------------------------------------------------------- /Application/OBJ_Loader.h: -------------------------------------------------------------------------------- 1 | // OBJ_Loader.h - A Single Header OBJ Model Loader 2 | 3 | #pragma once 4 | 5 | #include 6 | 7 | // Vector - STD Vector/Array Library 8 | #include 9 | 10 | // String - STD String Library 11 | #include 12 | 13 | // fStream - STD File I/O Library 14 | #include 15 | 16 | // Print progress to console while loading (large models) 17 | #define OBJL_CONSOLE_OUTPUT 18 | 19 | // Namespace: OBJL 20 | // 21 | // Description: The namespace that holds eveyrthing that 22 | // is needed and used for the OBJ Model Loader 23 | namespace objl 24 | { 25 | // Structure: Vector2 26 | // 27 | // Description: A 2D Vector that Holds Positional Data 28 | struct Vector2 29 | { 30 | // Default Constructor 31 | Vector2() 32 | { 33 | X = 0.0f; 34 | Y = 0.0f; 35 | } 36 | // Variable Set Constructor 37 | Vector2(float X_, float Y_) 38 | { 39 | X = X_; 40 | Y = Y_; 41 | } 42 | // Bool Equals Operator Overload 43 | bool operator==(const Vector2& other) const 44 | { 45 | return (this->X == other.X && this->Y == other.Y); 46 | } 47 | // Bool Not Equals Operator Overload 48 | bool operator!=(const Vector2& other) const 49 | { 50 | return !(this->X == other.X && this->Y == other.Y); 51 | } 52 | // Addition Operator Overload 53 | Vector2 operator+(const Vector2& right) const 54 | { 55 | return Vector2(this->X + right.X, this->Y + right.Y); 56 | } 57 | // Subtraction Operator Overload 58 | Vector2 operator-(const Vector2& right) const 59 | { 60 | return Vector2(this->X - right.X, this->Y - right.Y); 61 | } 62 | // Float Multiplication Operator Overload 63 | Vector2 operator*(const float& other) const 64 | { 65 | return Vector2(this->X *other, this->Y * other); 66 | } 67 | 68 | // Positional Variables 69 | float X; 70 | float Y; 71 | }; 72 | 73 | // Structure: Vector3 74 | // 75 | // Description: A 3D Vector that Holds Positional Data 76 | struct Vector3 77 | { 78 | // Default Constructor 79 | Vector3() 80 | { 81 | X = 0.0f; 82 | Y = 0.0f; 83 | Z = 0.0f; 84 | } 85 | // Variable Set Constructor 86 | Vector3(float X_, float Y_, float Z_) 87 | { 88 | X = X_; 89 | Y = Y_; 90 | Z = Z_; 91 | } 92 | // Bool Equals Operator Overload 93 | bool operator==(const Vector3& other) const 94 | { 95 | return (this->X == other.X && this->Y == other.Y && this->Z == other.Z); 96 | } 97 | // Bool Not Equals Operator Overload 98 | bool operator!=(const Vector3& other) const 99 | { 100 | return !(this->X == other.X && this->Y == other.Y && this->Z == other.Z); 101 | } 102 | // Addition Operator Overload 103 | Vector3 operator+(const Vector3& right) const 104 | { 105 | return Vector3(this->X + right.X, this->Y + right.Y, this->Z + right.Z); 106 | } 107 | // Subtraction Operator Overload 108 | Vector3 operator-(const Vector3& right) const 109 | { 110 | return Vector3(this->X - right.X, this->Y - right.Y, this->Z - right.Z); 111 | } 112 | // Float Multiplication Operator Overload 113 | Vector3 operator*(const float& other) const 114 | { 115 | return Vector3(this->X *other, this->Y * other, this->Z - other); 116 | } 117 | 118 | // Positional Variables 119 | float X; 120 | float Y; 121 | float Z; 122 | }; 123 | 124 | // Structure: Vertex 125 | // 126 | // Description: Model Vertex object that holds 127 | // a Position, Normal, and Texture Coordinate 128 | struct Vertex 129 | { 130 | // Position Vector 131 | Vector3 Position; 132 | 133 | // Normal Vector 134 | Vector3 Normal; 135 | 136 | // Texture Coordinate Vector 137 | Vector2 TextureCoordinate; 138 | }; 139 | 140 | struct Material 141 | { 142 | Material() 143 | { 144 | name; 145 | Ns = 0.0f; 146 | Ni = 0.0f; 147 | d = 0.0f; 148 | illum = 0; 149 | } 150 | 151 | // Material Name 152 | std::string name; 153 | // Ambient Color 154 | Vector3 Ka; 155 | // Diffuse Color 156 | Vector3 Kd; 157 | // Specular Color 158 | Vector3 Ks; 159 | // Specular Exponent 160 | float Ns; 161 | // Optical Density 162 | float Ni; 163 | // Dissolve 164 | float d; 165 | // Illumination 166 | int illum; 167 | // Ambient Texture Map 168 | std::string map_Ka; 169 | // Diffuse Texture Map 170 | std::string map_Kd; 171 | // Specular Texture Map 172 | std::string map_Ks; 173 | // Specular Hightlight Map 174 | std::string map_Ns; 175 | // Alpha Texture Map 176 | std::string map_d; 177 | // Bump Map 178 | std::string map_bump; 179 | }; 180 | 181 | // Structure: Mesh 182 | // 183 | // Description: A Simple Mesh Object that holds 184 | // a name, a vertex list, and an index list 185 | struct Mesh 186 | { 187 | // Default Constructor 188 | Mesh() 189 | { 190 | 191 | } 192 | // Variable Set Constructor 193 | Mesh(std::vector& _Vertices, std::vector& _Indices) 194 | { 195 | Vertices = _Vertices; 196 | Indices = _Indices; 197 | } 198 | // Mesh Name 199 | std::string MeshName; 200 | // Vertex List 201 | std::vector Vertices; 202 | // Index List 203 | std::vector Indices; 204 | 205 | // Material 206 | Material MeshMaterial; 207 | }; 208 | 209 | // Namespace: Math 210 | // 211 | // Description: The namespace that holds all of the math 212 | // functions need for OBJL 213 | namespace math 214 | { 215 | // Vector3 Cross Product 216 | Vector3 CrossV3(const Vector3 a, const Vector3 b) 217 | { 218 | return Vector3(a.Y * b.Z - a.Z * b.Y, 219 | a.Z * b.X - a.X * b.Z, 220 | a.X * b.Y - a.Y * b.X); 221 | } 222 | 223 | // Vector3 Magnitude Calculation 224 | float MagnitudeV3(const Vector3 in) 225 | { 226 | return (sqrtf(powf(in.X, 2) + powf(in.Y, 2) + powf(in.Z, 2))); 227 | } 228 | 229 | // Vector3 DotProduct 230 | float DotV3(const Vector3 a, const Vector3 b) 231 | { 232 | return (a.X * b.X) + (a.Y * b.Y) + (a.Z * b.Z); 233 | } 234 | 235 | // Angle between 2 Vector3 Objects 236 | float AngleBetweenV3(const Vector3 a, const Vector3 b) 237 | { 238 | float angle = DotV3(a, b); 239 | angle /= (MagnitudeV3(a) * MagnitudeV3(b)); 240 | return angle = acosf(angle); 241 | } 242 | } 243 | 244 | // Namespace: Algorithm 245 | // 246 | // Description: The namespace that holds all of the 247 | // Algorithms needed for OBJL 248 | namespace algorithm 249 | { 250 | // Vector3 Multiplication Opertor Overload 251 | Vector3 operator*(const float& left, const Vector3& right) 252 | { 253 | return Vector3(right.X * left, right.Y * left, right.Z * left); 254 | } 255 | 256 | // Check to see if a Vector3 Point is within a 3 Vector3 Triangle 257 | bool inTriangle(Vector3 point, Vector3 tri1, Vector3 tri2, Vector3 tri3) 258 | { 259 | // Starting vars 260 | Vector3 u = tri2 - tri1; 261 | Vector3 v = tri3 - tri1; 262 | Vector3 w = point - tri1; 263 | Vector3 n = math::CrossV3(u, v); 264 | 265 | float y = (math::DotV3(math::CrossV3(u, w), n) / math::DotV3(n, n)); 266 | float b = (math::DotV3(math::CrossV3(u, w), n) / math::DotV3(n, n)); 267 | float a = 1 - y - b; 268 | 269 | // Projected point 270 | Vector3 p = (a * tri1) + (b * tri2) + (y * tri3); 271 | 272 | if (a >= 0 && a <= 1 273 | && b >= 0 && b <= 1 274 | && y >= 0 && y <= 1) 275 | { 276 | return true; 277 | } 278 | else 279 | return false; 280 | } 281 | 282 | // Split a String into a string array at a given token 283 | inline void split(const std::string &in, 284 | std::vector &out, 285 | std::string token) 286 | { 287 | out.clear(); 288 | 289 | std::string temp; 290 | 291 | for (int i = 0; i < int(in.size()); i++) 292 | { 293 | std::string test = in.substr(i, token.size()); 294 | 295 | if (test == token) 296 | { 297 | if (!temp.empty()) 298 | { 299 | out.push_back(temp); 300 | temp.clear(); 301 | i += (int)token.size() - 1; 302 | } 303 | else 304 | { 305 | out.push_back(""); 306 | } 307 | } 308 | else if (i + token.size() >= in.size()) 309 | { 310 | temp += in.substr(i, token.size()); 311 | out.push_back(temp); 312 | break; 313 | } 314 | else 315 | { 316 | temp += in[i]; 317 | } 318 | } 319 | } 320 | 321 | // Get tail of string after first token and possibly following spaces 322 | inline std::string tail(const std::string &in) 323 | { 324 | size_t token_start = in.find_first_not_of(" \t"); 325 | size_t space_start = in.find_first_of(" \t", token_start); 326 | size_t tail_start = in.find_first_not_of(" \t", space_start); 327 | size_t tail_end = in.find_last_not_of(" \t"); 328 | if (tail_start != std::string::npos && tail_end != std::string::npos) 329 | { 330 | return in.substr(tail_start, tail_end - tail_start + 1); 331 | } 332 | else if (tail_start != std::string::npos) 333 | { 334 | return in.substr(tail_start); 335 | } 336 | return ""; 337 | } 338 | 339 | // Get first token of string 340 | inline std::string firstToken(const std::string &in) 341 | { 342 | if (!in.empty()) 343 | { 344 | size_t token_start = in.find_first_not_of(" \t"); 345 | size_t token_end = in.find_first_of(" \t", token_start); 346 | if (token_start != std::string::npos && token_end != std::string::npos) 347 | { 348 | return in.substr(token_start, token_end - token_start); 349 | } 350 | else if (token_start != std::string::npos) 351 | { 352 | return in.substr(token_start); 353 | } 354 | } 355 | return ""; 356 | } 357 | 358 | // Get element at given index position 359 | template 360 | inline const T & getElement(const std::vector &elements, std::string &index) 361 | { 362 | int idx = std::stoi(index); 363 | if (idx < 0) 364 | idx = int(elements.size()) + idx; 365 | else 366 | idx--; 367 | return elements[idx]; 368 | } 369 | } 370 | 371 | // Class: Loader 372 | // 373 | // Description: The OBJ Model Loader 374 | class Loader 375 | { 376 | public: 377 | // Default Constructor 378 | Loader() 379 | { 380 | 381 | } 382 | ~Loader() 383 | { 384 | LoadedMeshes.clear(); 385 | } 386 | 387 | // Load a file into the loader 388 | // 389 | // If file is loaded return true 390 | // 391 | // If the file is unable to be found 392 | // or unable to be loaded return false 393 | bool LoadFile(std::string Path) 394 | { 395 | // If the file is not an .obj file return false 396 | if (Path.substr(Path.size() - 4, 4) != ".obj") 397 | return false; 398 | 399 | 400 | std::ifstream file(Path); 401 | 402 | if (!file.is_open()) 403 | return false; 404 | 405 | LoadedMeshes.clear(); 406 | LoadedVertices.clear(); 407 | LoadedIndices.clear(); 408 | 409 | std::vector Positions; 410 | std::vector TCoords; 411 | std::vector Normals; 412 | 413 | std::vector Vertices; 414 | std::vector Indices; 415 | 416 | std::vector MeshMatNames; 417 | 418 | bool listening = false; 419 | std::string meshname; 420 | 421 | Mesh tempMesh; 422 | 423 | #ifdef OBJL_CONSOLE_OUTPUT 424 | const unsigned int outputEveryNth = 1000; 425 | unsigned int outputIndicator = outputEveryNth; 426 | #endif 427 | 428 | std::string curline; 429 | while (std::getline(file, curline)) 430 | { 431 | #ifdef OBJL_CONSOLE_OUTPUT 432 | if ((outputIndicator = ((outputIndicator + 1) % outputEveryNth)) == 1) 433 | { 434 | if (!meshname.empty()) 435 | { 436 | std::cout 437 | << "\r- " << meshname 438 | << "\t| vertices > " << Positions.size() 439 | << "\t| texcoords > " << TCoords.size() 440 | << "\t| normals > " << Normals.size() 441 | << "\t| triangles > " << (Vertices.size() / 3) 442 | << (!MeshMatNames.empty() ? "\t| material: " + MeshMatNames.back() : ""); 443 | } 444 | } 445 | #endif 446 | 447 | // Generate a Mesh Object or Prepare for an object to be created 448 | if (algorithm::firstToken(curline) == "o" || algorithm::firstToken(curline) == "g" || curline[0] == 'g') 449 | { 450 | if (!listening) 451 | { 452 | listening = true; 453 | 454 | if (algorithm::firstToken(curline) == "o" || algorithm::firstToken(curline) == "g") 455 | { 456 | meshname = algorithm::tail(curline); 457 | } 458 | else 459 | { 460 | meshname = "unnamed"; 461 | } 462 | } 463 | else 464 | { 465 | // Generate the mesh to put into the array 466 | 467 | if (!Indices.empty() && !Vertices.empty()) 468 | { 469 | // Create Mesh 470 | tempMesh = Mesh(Vertices, Indices); 471 | tempMesh.MeshName = meshname; 472 | 473 | // Insert Mesh 474 | LoadedMeshes.push_back(tempMesh); 475 | 476 | // Cleanup 477 | Vertices.clear(); 478 | Indices.clear(); 479 | meshname.clear(); 480 | 481 | meshname = algorithm::tail(curline); 482 | } 483 | else 484 | { 485 | if (algorithm::firstToken(curline) == "o" || algorithm::firstToken(curline) == "g") 486 | { 487 | meshname = algorithm::tail(curline); 488 | } 489 | else 490 | { 491 | meshname = "unnamed"; 492 | } 493 | } 494 | } 495 | #ifdef OBJL_CONSOLE_OUTPUT 496 | std::cout << std::endl; 497 | outputIndicator = 0; 498 | #endif 499 | } 500 | // Generate a Vertex Position 501 | if (algorithm::firstToken(curline) == "v") 502 | { 503 | std::vector spos; 504 | Vector3 vpos; 505 | algorithm::split(algorithm::tail(curline), spos, " "); 506 | 507 | vpos.X = std::stof(spos[0]); 508 | vpos.Y = std::stof(spos[1]); 509 | vpos.Z = std::stof(spos[2]); 510 | 511 | Positions.push_back(vpos); 512 | } 513 | // Generate a Vertex Texture Coordinate 514 | if (algorithm::firstToken(curline) == "vt") 515 | { 516 | std::vector stex; 517 | Vector2 vtex; 518 | algorithm::split(algorithm::tail(curline), stex, " "); 519 | 520 | vtex.X = std::stof(stex[0]); 521 | vtex.Y = std::stof(stex[1]); 522 | 523 | TCoords.push_back(vtex); 524 | } 525 | // Generate a Vertex Normal; 526 | if (algorithm::firstToken(curline) == "vn") 527 | { 528 | std::vector snor; 529 | Vector3 vnor; 530 | algorithm::split(algorithm::tail(curline), snor, " "); 531 | 532 | vnor.X = std::stof(snor[0]); 533 | vnor.Y = std::stof(snor[1]); 534 | vnor.Z = std::stof(snor[2]); 535 | 536 | Normals.push_back(vnor); 537 | } 538 | // Generate a Face (vertices & indices) 539 | if (algorithm::firstToken(curline) == "f") 540 | { 541 | // Generate the vertices 542 | std::vector vVerts; 543 | GenVerticesFromRawOBJ(vVerts, Positions, TCoords, Normals, curline); 544 | 545 | // Add Vertices 546 | for (int i = 0; i < int(vVerts.size()); i++) 547 | { 548 | Vertices.push_back(vVerts[i]); 549 | 550 | LoadedVertices.push_back(vVerts[i]); 551 | } 552 | 553 | std::vector iIndices; 554 | 555 | VertexTriangluation(iIndices, vVerts); 556 | 557 | // Add Indices 558 | for (int i = 0; i < int(iIndices.size()); i++) 559 | { 560 | unsigned int indnum = (unsigned int)((Vertices.size()) - vVerts.size()) + iIndices[i]; 561 | Indices.push_back(indnum); 562 | 563 | indnum = (unsigned int)((LoadedVertices.size()) - vVerts.size()) + iIndices[i]; 564 | LoadedIndices.push_back(indnum); 565 | 566 | } 567 | } 568 | // Get Mesh Material Name 569 | if (algorithm::firstToken(curline) == "usemtl") 570 | { 571 | MeshMatNames.push_back(algorithm::tail(curline)); 572 | 573 | // Create new Mesh, if Material changes within a group 574 | if (!Indices.empty() && !Vertices.empty()) 575 | { 576 | // Create Mesh 577 | tempMesh = Mesh(Vertices, Indices); 578 | tempMesh.MeshName = meshname; 579 | int i = 2; 580 | while(1) { 581 | tempMesh.MeshName = meshname + "_" + std::to_string(i); 582 | 583 | for (auto &m : LoadedMeshes) 584 | if (m.MeshName == tempMesh.MeshName) 585 | continue; 586 | break; 587 | } 588 | 589 | // Insert Mesh 590 | LoadedMeshes.push_back(tempMesh); 591 | 592 | // Cleanup 593 | Vertices.clear(); 594 | Indices.clear(); 595 | } 596 | 597 | #ifdef OBJL_CONSOLE_OUTPUT 598 | outputIndicator = 0; 599 | #endif 600 | } 601 | // Load Materials 602 | if (algorithm::firstToken(curline) == "mtllib") 603 | { 604 | // Generate LoadedMaterial 605 | 606 | // Generate a path to the material file 607 | std::vector temp; 608 | algorithm::split(Path, temp, "/"); 609 | 610 | std::string pathtomat = ""; 611 | 612 | if (temp.size() != 1) 613 | { 614 | for (int i = 0; i < temp.size() - 1; i++) 615 | { 616 | pathtomat += temp[i] + "/"; 617 | } 618 | } 619 | 620 | 621 | pathtomat += algorithm::tail(curline); 622 | 623 | #ifdef OBJL_CONSOLE_OUTPUT 624 | std::cout << std::endl << "- find materials in: " << pathtomat << std::endl; 625 | #endif 626 | 627 | // Load Materials 628 | LoadMaterials(pathtomat); 629 | } 630 | } 631 | 632 | #ifdef OBJL_CONSOLE_OUTPUT 633 | std::cout << std::endl; 634 | #endif 635 | 636 | // Deal with last mesh 637 | 638 | if (!Indices.empty() && !Vertices.empty()) 639 | { 640 | // Create Mesh 641 | tempMesh = Mesh(Vertices, Indices); 642 | tempMesh.MeshName = meshname; 643 | 644 | // Insert Mesh 645 | LoadedMeshes.push_back(tempMesh); 646 | } 647 | 648 | file.close(); 649 | 650 | // Set Materials for each Mesh 651 | for (int i = 0; i < MeshMatNames.size(); i++) 652 | { 653 | std::string matname = MeshMatNames[i]; 654 | 655 | // Find corresponding material name in loaded materials 656 | // when found copy material variables into mesh material 657 | for (int j = 0; j < LoadedMaterials.size(); j++) 658 | { 659 | if (LoadedMaterials[j].name == matname) 660 | { 661 | LoadedMeshes[i].MeshMaterial = LoadedMaterials[j]; 662 | break; 663 | } 664 | } 665 | } 666 | 667 | if (LoadedMeshes.empty() && LoadedVertices.empty() && LoadedIndices.empty()) 668 | { 669 | return false; 670 | } 671 | else 672 | { 673 | return true; 674 | } 675 | } 676 | 677 | // Loaded Mesh Objects 678 | std::vector LoadedMeshes; 679 | // Loaded Vertex Objects 680 | std::vector LoadedVertices; 681 | // Loaded Index Positions 682 | std::vector LoadedIndices; 683 | // Loaded Material Objects 684 | std::vector LoadedMaterials; 685 | 686 | private: 687 | // Generate vertices from a list of positions, 688 | // tcoords, normals and a face line 689 | void GenVerticesFromRawOBJ(std::vector& oVerts, 690 | const std::vector& iPositions, 691 | const std::vector& iTCoords, 692 | const std::vector& iNormals, 693 | std::string icurline) 694 | { 695 | std::vector sface, svert; 696 | Vertex vVert; 697 | algorithm::split(algorithm::tail(icurline), sface, " "); 698 | 699 | bool noNormal = false; 700 | 701 | // For every given vertex do this 702 | for (int i = 0; i < int(sface.size()); i++) 703 | { 704 | // See What type the vertex is. 705 | int vtype; 706 | 707 | algorithm::split(sface[i], svert, "/"); 708 | 709 | // Check for just position - v1 710 | if (svert.size() == 1) 711 | { 712 | // Only position 713 | vtype = 1; 714 | } 715 | 716 | // Check for position & texture - v1/vt1 717 | if (svert.size() == 2) 718 | { 719 | // Position & Texture 720 | vtype = 2; 721 | } 722 | 723 | // Check for Position, Texture and Normal - v1/vt1/vn1 724 | // or if Position and Normal - v1//vn1 725 | if (svert.size() == 3) 726 | { 727 | if (svert[1] != "") 728 | { 729 | // Position, Texture, and Normal 730 | vtype = 4; 731 | } 732 | else 733 | { 734 | // Position & Normal 735 | vtype = 3; 736 | } 737 | } 738 | 739 | // Calculate and store the vertex 740 | switch (vtype) 741 | { 742 | case 1: // P 743 | { 744 | vVert.Position = algorithm::getElement(iPositions, svert[0]); 745 | vVert.TextureCoordinate = Vector2(0, 0); 746 | noNormal = true; 747 | oVerts.push_back(vVert); 748 | break; 749 | } 750 | case 2: // P/T 751 | { 752 | vVert.Position = algorithm::getElement(iPositions, svert[0]); 753 | vVert.TextureCoordinate = algorithm::getElement(iTCoords, svert[1]); 754 | noNormal = true; 755 | oVerts.push_back(vVert); 756 | break; 757 | } 758 | case 3: // P//N 759 | { 760 | vVert.Position = algorithm::getElement(iPositions, svert[0]); 761 | vVert.TextureCoordinate = Vector2(0, 0); 762 | vVert.Normal = algorithm::getElement(iNormals, svert[2]); 763 | oVerts.push_back(vVert); 764 | break; 765 | } 766 | case 4: // P/T/N 767 | { 768 | vVert.Position = algorithm::getElement(iPositions, svert[0]); 769 | vVert.TextureCoordinate = algorithm::getElement(iTCoords, svert[1]); 770 | vVert.Normal = algorithm::getElement(iNormals, svert[2]); 771 | oVerts.push_back(vVert); 772 | break; 773 | } 774 | default: 775 | { 776 | break; 777 | } 778 | } 779 | } 780 | 781 | // take care of missing normals 782 | // these may not be truly acurate but it is the 783 | // best they get for not compiling a mesh with normals 784 | if (noNormal) 785 | { 786 | Vector3 A = oVerts[0].Position - oVerts[1].Position; 787 | Vector3 B = oVerts[2].Position - oVerts[1].Position; 788 | 789 | Vector3 normal = math::CrossV3(A, B); 790 | 791 | for (int i = 0; i < int(oVerts.size()); i++) 792 | { 793 | oVerts[i].Normal = normal; 794 | } 795 | } 796 | } 797 | 798 | // Triangulate a list of vertices into a face by printing 799 | // inducies corresponding with triangles within it 800 | void VertexTriangluation(std::vector& oIndices, 801 | const std::vector& iVerts) 802 | { 803 | // If there are 2 or less verts, 804 | // no triangle can be created, 805 | // so exit 806 | if (iVerts.size() < 3) 807 | { 808 | return; 809 | } 810 | // If it is a triangle no need to calculate it 811 | if (iVerts.size() == 3) 812 | { 813 | oIndices.push_back(0); 814 | oIndices.push_back(1); 815 | oIndices.push_back(2); 816 | return; 817 | } 818 | 819 | // Create a list of vertices 820 | std::vector tVerts = iVerts; 821 | 822 | while (true) 823 | { 824 | // For every vertex 825 | for (int i = 0; i < int(tVerts.size()); i++) 826 | { 827 | // pPrev = the previous vertex in the list 828 | Vertex pPrev; 829 | if (i == 0) 830 | { 831 | pPrev = tVerts[tVerts.size() - 1]; 832 | } 833 | else 834 | { 835 | pPrev = tVerts[i - 1]; 836 | } 837 | 838 | // pCur = the current vertex; 839 | Vertex pCur = tVerts[i]; 840 | 841 | // pNext = the next vertex in the list 842 | Vertex pNext; 843 | if (i == tVerts.size() - 1) 844 | { 845 | pNext = tVerts[0]; 846 | } 847 | else 848 | { 849 | pNext = tVerts[i + 1]; 850 | } 851 | 852 | // Check to see if there are only 3 verts left 853 | // if so this is the last triangle 854 | if (tVerts.size() == 3) 855 | { 856 | // Create a triangle from pCur, pPrev, pNext 857 | for (int j = 0; j < int(tVerts.size()); j++) 858 | { 859 | if (iVerts[j].Position == pCur.Position) 860 | oIndices.push_back(j); 861 | if (iVerts[j].Position == pPrev.Position) 862 | oIndices.push_back(j); 863 | if (iVerts[j].Position == pNext.Position) 864 | oIndices.push_back(j); 865 | } 866 | 867 | tVerts.clear(); 868 | break; 869 | } 870 | if (tVerts.size() == 4) 871 | { 872 | // Create a triangle from pCur, pPrev, pNext 873 | for (int j = 0; j < int(iVerts.size()); j++) 874 | { 875 | if (iVerts[j].Position == pCur.Position) 876 | oIndices.push_back(j); 877 | if (iVerts[j].Position == pPrev.Position) 878 | oIndices.push_back(j); 879 | if (iVerts[j].Position == pNext.Position) 880 | oIndices.push_back(j); 881 | } 882 | 883 | Vector3 tempVec; 884 | for (int j = 0; j < int(tVerts.size()); j++) 885 | { 886 | if (tVerts[j].Position != pCur.Position 887 | && tVerts[j].Position != pPrev.Position 888 | && tVerts[j].Position != pNext.Position) 889 | { 890 | tempVec = tVerts[j].Position; 891 | break; 892 | } 893 | } 894 | 895 | // Create a triangle from pCur, pPrev, pNext 896 | for (int j = 0; j < int(iVerts.size()); j++) 897 | { 898 | if (iVerts[j].Position == pPrev.Position) 899 | oIndices.push_back(j); 900 | if (iVerts[j].Position == pNext.Position) 901 | oIndices.push_back(j); 902 | if (iVerts[j].Position == tempVec) 903 | oIndices.push_back(j); 904 | } 905 | 906 | tVerts.clear(); 907 | break; 908 | } 909 | 910 | // If Vertex is not an interior vertex 911 | float angle = math::AngleBetweenV3(pPrev.Position - pCur.Position, pNext.Position - pCur.Position) * (180.0f / 3.14159265359f); 912 | if (angle <= 0 && angle >= 180) 913 | continue; 914 | 915 | // If any vertices are within this triangle 916 | bool inTri = false; 917 | for (int j = 0; j < int(iVerts.size()); j++) 918 | { 919 | if (algorithm::inTriangle(iVerts[j].Position, pPrev.Position, pCur.Position, pNext.Position) 920 | && iVerts[j].Position != pPrev.Position 921 | && iVerts[j].Position != pCur.Position 922 | && iVerts[j].Position != pNext.Position) 923 | { 924 | inTri = true; 925 | break; 926 | } 927 | } 928 | if (inTri) 929 | continue; 930 | 931 | // Create a triangle from pCur, pPrev, pNext 932 | for (int j = 0; j < int(iVerts.size()); j++) 933 | { 934 | if (iVerts[j].Position == pCur.Position) 935 | oIndices.push_back(j); 936 | if (iVerts[j].Position == pPrev.Position) 937 | oIndices.push_back(j); 938 | if (iVerts[j].Position == pNext.Position) 939 | oIndices.push_back(j); 940 | } 941 | 942 | // Delete pCur from the list 943 | for (int j = 0; j < int(tVerts.size()); j++) 944 | { 945 | if (tVerts[j].Position == pCur.Position) 946 | { 947 | tVerts.erase(tVerts.begin() + j); 948 | break; 949 | } 950 | } 951 | 952 | // reset i to the start 953 | // -1 since loop will add 1 to it 954 | i = -1; 955 | } 956 | 957 | // if no triangles were created 958 | if (oIndices.size() == 0) 959 | break; 960 | 961 | // if no more vertices 962 | if (tVerts.size() == 0) 963 | break; 964 | } 965 | } 966 | 967 | // Load Materials from .mtl file 968 | bool LoadMaterials(std::string path) 969 | { 970 | // If the file is not a material file return false 971 | if (path.substr(path.size() - 4, path.size()) != ".mtl") 972 | return false; 973 | 974 | std::ifstream file(path); 975 | 976 | // If the file is not found return false 977 | if (!file.is_open()) 978 | return false; 979 | 980 | Material tempMaterial; 981 | 982 | bool listening = false; 983 | 984 | // Go through each line looking for material variables 985 | std::string curline; 986 | while (std::getline(file, curline)) 987 | { 988 | // new material and material name 989 | if (algorithm::firstToken(curline) == "newmtl") 990 | { 991 | if (!listening) 992 | { 993 | listening = true; 994 | 995 | if (curline.size() > 7) 996 | { 997 | tempMaterial.name = algorithm::tail(curline); 998 | } 999 | else 1000 | { 1001 | tempMaterial.name = "none"; 1002 | } 1003 | } 1004 | else 1005 | { 1006 | // Generate the material 1007 | 1008 | // Push Back loaded Material 1009 | LoadedMaterials.push_back(tempMaterial); 1010 | 1011 | // Clear Loaded Material 1012 | tempMaterial = Material(); 1013 | 1014 | if (curline.size() > 7) 1015 | { 1016 | tempMaterial.name = algorithm::tail(curline); 1017 | } 1018 | else 1019 | { 1020 | tempMaterial.name = "none"; 1021 | } 1022 | } 1023 | } 1024 | // Ambient Color 1025 | if (algorithm::firstToken(curline) == "Ka") 1026 | { 1027 | std::vector temp; 1028 | algorithm::split(algorithm::tail(curline), temp, " "); 1029 | 1030 | if (temp.size() != 3) 1031 | continue; 1032 | 1033 | tempMaterial.Ka.X = std::stof(temp[0]); 1034 | tempMaterial.Ka.Y = std::stof(temp[1]); 1035 | tempMaterial.Ka.Z = std::stof(temp[2]); 1036 | } 1037 | // Diffuse Color 1038 | if (algorithm::firstToken(curline) == "Kd") 1039 | { 1040 | std::vector temp; 1041 | algorithm::split(algorithm::tail(curline), temp, " "); 1042 | 1043 | if (temp.size() != 3) 1044 | continue; 1045 | 1046 | tempMaterial.Kd.X = std::stof(temp[0]); 1047 | tempMaterial.Kd.Y = std::stof(temp[1]); 1048 | tempMaterial.Kd.Z = std::stof(temp[2]); 1049 | } 1050 | // Specular Color 1051 | if (algorithm::firstToken(curline) == "Ks") 1052 | { 1053 | std::vector temp; 1054 | algorithm::split(algorithm::tail(curline), temp, " "); 1055 | 1056 | if (temp.size() != 3) 1057 | continue; 1058 | 1059 | tempMaterial.Ks.X = std::stof(temp[0]); 1060 | tempMaterial.Ks.Y = std::stof(temp[1]); 1061 | tempMaterial.Ks.Z = std::stof(temp[2]); 1062 | } 1063 | // Specular Exponent 1064 | if (algorithm::firstToken(curline) == "Ns") 1065 | { 1066 | tempMaterial.Ns = std::stof(algorithm::tail(curline)); 1067 | } 1068 | // Optical Density 1069 | if (algorithm::firstToken(curline) == "Ni") 1070 | { 1071 | tempMaterial.Ni = std::stof(algorithm::tail(curline)); 1072 | } 1073 | // Dissolve 1074 | if (algorithm::firstToken(curline) == "d") 1075 | { 1076 | tempMaterial.d = std::stof(algorithm::tail(curline)); 1077 | } 1078 | // Illumination 1079 | if (algorithm::firstToken(curline) == "illum") 1080 | { 1081 | tempMaterial.illum = std::stoi(algorithm::tail(curline)); 1082 | } 1083 | // Ambient Texture Map 1084 | if (algorithm::firstToken(curline) == "map_Ka") 1085 | { 1086 | tempMaterial.map_Ka = algorithm::tail(curline); 1087 | } 1088 | // Diffuse Texture Map 1089 | if (algorithm::firstToken(curline) == "map_Kd") 1090 | { 1091 | tempMaterial.map_Kd = algorithm::tail(curline); 1092 | } 1093 | // Specular Texture Map 1094 | if (algorithm::firstToken(curline) == "map_Ks") 1095 | { 1096 | tempMaterial.map_Ks = algorithm::tail(curline); 1097 | } 1098 | // Specular Hightlight Map 1099 | if (algorithm::firstToken(curline) == "map_Ns") 1100 | { 1101 | tempMaterial.map_Ns = algorithm::tail(curline); 1102 | } 1103 | // Alpha Texture Map 1104 | if (algorithm::firstToken(curline) == "map_d") 1105 | { 1106 | tempMaterial.map_d = algorithm::tail(curline); 1107 | } 1108 | // Bump Map 1109 | if (algorithm::firstToken(curline) == "map_Bump" || algorithm::firstToken(curline) == "map_bump") 1110 | { 1111 | tempMaterial.map_bump = algorithm::tail(curline); 1112 | } 1113 | } 1114 | 1115 | // Deal with last material 1116 | 1117 | // Push Back loaded Material 1118 | LoadedMaterials.push_back(tempMaterial); 1119 | 1120 | // Test to see if anything was loaded 1121 | // If not return false 1122 | if (LoadedMaterials.empty()) 1123 | return false; 1124 | // If so return true 1125 | else 1126 | return true; 1127 | } 1128 | }; 1129 | } 1130 | -------------------------------------------------------------------------------- /DX12Base/Dx12Device.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define DX_DEBUG_EVENT 1 4 | #define DX_DEBUG_RESOURCE_NAME 1 5 | 6 | // Windows and Dx12 includes 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include "DXGI1_4.h" 16 | #include "D3D12SDKLayers.h" 17 | #include "dxcapi.h" 18 | 19 | #include "Dx12Math.h" 20 | 21 | #if defined(_DEBUG) 22 | //#include "DXGIDebug.h" issue with DXGI_DEBUG_ALL :( 23 | #define DXDEBUG 1 24 | #else 25 | #define DXDEBUG 0 26 | #endif 27 | 28 | // Disable because PIX markers are only supported on x64 platforms 29 | #define D_ENABLE_PIX 1 30 | #if D_ENABLE_PIX 31 | // See https://devblogs.microsoft.com/pix/winpixeventruntime/ 32 | #define USE_PIX 1 33 | #include "pix3.h" 34 | #endif 35 | 36 | // This is interesting to disable in case one wants to capture using renderdoc. Otherwise, NSight Graphics will be required. 37 | #define D_ENABLE_DXR 1 38 | 39 | // Truncate to SIZE_T to handle 32 and 64 bits systems 40 | #define INVALID_DESCRIPTOR_HANDLE ((SIZE_T)0xFFFFFFFFFFFFFFFF) 41 | 42 | class RootSignature; 43 | class DescriptorHeap; 44 | class AllocatedResourceDecriptorHeap; 45 | class DispatchDrawCallCpuDescriptorHeap; 46 | class DispatchRaysCallSBTHeapCPU; 47 | class FrameConstantBuffers; 48 | class RenderResource; 49 | class RenderBufferGeneric; 50 | #if D_ENABLE_DXR 51 | class RayTracingPipelineStateSimple; 52 | class RayTracingPipelineStateClosestAndAnyHit; 53 | #endif 54 | 55 | static const int frameBufferCount = 2; // number of buffers we want, 2 for double buffering, 3 for tripple buffering... 56 | static const int GPUTimerMaxCount = 256; 57 | 58 | class Dx12Device 59 | { 60 | public: 61 | 62 | static void initialise(const HWND& hWnd, uint BackBufferWidth, uint BackBufferHeight); 63 | static void shutdown(); 64 | 65 | ID3D12Device5* getDevice() const { return mDev; } 66 | IDXGISwapChain3* getSwapChain() const { return mSwapchain; } 67 | 68 | IDxcLibrary* getDxcLibrary() const { return mDxcLibrary; } 69 | IDxcCompiler* getDxcCompiler() const { return mDxcCompiler; } 70 | IDxcIncludeHandler* getDxcIncludeHandler() const { return mDxcIncludeHandler; } 71 | 72 | ID3D12Resource* getBackBuffer() const { return mBackBufferResource[mFrameIndex]; } 73 | D3D12_CPU_DESCRIPTOR_HANDLE getBackBufferDescriptor() const; 74 | 75 | // The single command list per frame since we do not prepare command in parallel yet 76 | ID3D12GraphicsCommandList4* getFrameCommandList() const { return mCommandList[0]; } 77 | 78 | int getFrameIndex() const { return mFrameIndex; } 79 | 80 | void beginFrame(); 81 | void endFrameAndSwap(bool vsyncEnabled); 82 | void closeBufferedFramesBeforeShutdown(); 83 | 84 | const RootSignature& GetDefaultGraphicRootSignature() const { return *mGfxRootSignature; } 85 | const RootSignature& GetDefaultComputeRootSignature() const { return *mCptRootSignature; } 86 | #if D_ENABLE_DXR 87 | const RootSignature& GetDefaultRayTracingGlobalRootSignature() const { return *mRtGlobalRootSignature; } 88 | const RootSignature& GetDefaultRayTracingLocalRootSignature() const { return *mRtLocalRootSignature; } 89 | #endif 90 | 91 | uint getCbSrvUavDescriptorSize() const { return mCbSrvUavDescriptorSize; } 92 | uint getSamplerDescriptorSize() const { return mSamplerDescriptorSize; } 93 | uint getRtvDescriptorSize() const { return mRtvDescriptorSize; } 94 | uint getDsvDescriptorSize() const { return mDsvDescriptorSize; } 95 | 96 | AllocatedResourceDecriptorHeap& getAllocatedResourceDecriptorHeap() { return *mAllocatedResourcesDecriptorHeapCPU; } 97 | DispatchDrawCallCpuDescriptorHeap& getDispatchDrawCallCpuDescriptorHeap() { return *mDispatchDrawCallDescriptorHeapCPU[mFrameIndex]; } 98 | 99 | DispatchRaysCallSBTHeapCPU& getDispatchRaysCallCpuSBTHeap() { return *mDispatchRaysCallSBTHeapCPU[mFrameIndex]; } 100 | 101 | const DescriptorHeap* getFrameDispatchDrawCallGpuDescriptorHeap() { return mFrameDispatchDrawCallDescriptorHeapGPU[mFrameIndex]; } 102 | 103 | FrameConstantBuffers& getFrameConstantBuffers() const { return *mFrameConstantBuffers[mFrameIndex]; } 104 | 105 | struct GPUTimer 106 | { 107 | LPCWSTR mEventName; 108 | uint mQueryIndexStart; 109 | uint mQueryIndexEnd; 110 | uint mLevel; 111 | uint mRGBA; 112 | }; 113 | void StartGPUTimer(LPCWSTR Name, uint RGBA); 114 | void EndGPUTimer(LPCWSTR Name); 115 | struct GPUTimersReport 116 | { 117 | uint mLastValidGPUTimerSlotCount; 118 | GPUTimer* mLastValidGPUTimers; 119 | uint64* mLastValidTimeStamps; 120 | uint64 mLastValidTimeStampTickPerSeconds; 121 | }; 122 | GPUTimersReport GetGPUTimerReport(); 123 | 124 | #if D_ENABLE_DXR 125 | void AppendToGarbageCollector(RayTracingPipelineStateSimple* ToBeRemoved) { mFrameGarbageCollector[mFrameIndex].mRayTracingPipelineStateSimple.push_back(ToBeRemoved); } 126 | void AppendToGarbageCollector(RayTracingPipelineStateClosestAndAnyHit* ToBeRemoved) { mFrameGarbageCollector[mFrameIndex].mRayTracingPipelineStateClosestAndAnyHit.push_back(ToBeRemoved); } 127 | #endif 128 | 129 | void updateSwapChain(bool bRecreate, uint newWidth, uint newHeight, const HWND* OutputWindowhWnd = nullptr); 130 | 131 | private: 132 | Dx12Device(); 133 | Dx12Device(Dx12Device&); 134 | //Dx12Device(const Dx12Device&); 135 | ~Dx12Device(); 136 | 137 | void EnableShaderBasedValidationIfNeeded(uint& dxgiFactoryFlags); 138 | 139 | void internalInitialise(const HWND& hWnd, uint BackBufferWidth, uint BackBufferHeight); 140 | void internalShutdown(); 141 | 142 | void waitForPreviousFrame(int frameIndex = -1); 143 | 144 | ID3D12Device5* mDev; // the pointer to our Direct3D device interface 145 | IDXGIFactory4* mDxgiFactory; 146 | IDXGISwapChain3* mSwapchain; // the pointer to the swap chain interface 147 | int mFrameIndex=0; // Current swap chain frame index (back buffer) 148 | ID3D12CommandQueue* mCommandQueue; // command list container 149 | ID3D12CommandAllocator* mCommandAllocator[frameBufferCount]; // Command allocator in GPU memory. Need a many as frameCount as cannot rest while in use by GPU 150 | ID3D12GraphicsCommandList4* mCommandList[1]; // A command list to record commands into. No multi-thread so only one is needed 151 | 152 | DescriptorHeap* mBackBufferRTVDescriptorHeap; // a descriptor heap to hold back buffers ressource descriptors (equivalent to views) 153 | ID3D12Resource* mBackBufferResource[frameBufferCount]; // back buffer render target view 154 | 155 | ID3D12Fence* mFrameFence[frameBufferCount]; // locked while commandlist is being executed by the gpu. 156 | HANDLE mFrameFenceEvent; // a handle to an event when our fence is unlocked by the gpu 157 | uint64 mFrameFenceValue[frameBufferCount]; // Incremented each frame. each fence will have its own value 158 | 159 | 160 | IDxcLibrary* mDxcLibrary; 161 | IDxcCompiler* mDxcCompiler; 162 | IDxcIncludeHandler* mDxcIncludeHandler; 163 | 164 | 165 | // GPU information 166 | IDXGIAdapter3* mAdapter; // Current device adapter 167 | DXGI_ADAPTER_DESC2 mAdapterDesc; // Adapter information 168 | DXGI_QUERY_VIDEO_MEMORY_INFO mVideoMemInfo; // Last sampled video memory usage (allocations, etc) 169 | uint mCbSrvUavDescriptorSize; // CBV SRV UAV descriptor size for the selected GPU device 170 | uint mSamplerDescriptorSize; // Sampler descriptor size for the selected GPU device 171 | uint mRtvDescriptorSize; // RTV descriptor size for the selected GPU device 172 | uint mDsvDescriptorSize; // DSV descriptor size for the selected GPU device 173 | 174 | RootSignature* mGfxRootSignature; // Graphics default root signature 175 | RootSignature* mCptRootSignature; // Compute default root signature 176 | #if D_ENABLE_DXR 177 | RootSignature* mRtGlobalRootSignature; // Ray tracing global root signature 178 | RootSignature* mRtLocalRootSignature; // Ray tracing local root signature 179 | #endif 180 | 181 | AllocatedResourceDecriptorHeap* mAllocatedResourcesDecriptorHeapCPU; // All loaded resources allocate UAV/SRV if required in this CPU heap. 182 | 183 | DispatchDrawCallCpuDescriptorHeap* mDispatchDrawCallDescriptorHeapCPU[frameBufferCount];// All dispatch and draw calls have their descriptors set in this CPU heap. 184 | DescriptorHeap* mFrameDispatchDrawCallDescriptorHeapGPU[frameBufferCount];// GPU version of dispatch and draw calls descriptors. 185 | 186 | DispatchRaysCallSBTHeapCPU* mDispatchRaysCallSBTHeapCPU[frameBufferCount];// All dispatch rays have SBT generated using this. No SBT caching happens today. 187 | 188 | FrameConstantBuffers* mFrameConstantBuffers[frameBufferCount]; // Descriptor heaps for constant buffers. 189 | 190 | // Data used for GPU performance tracking 191 | ID3D12QueryHeap* mFrameTimeStampQueryHeaps[frameBufferCount];// Heaps storing time stamp query results 192 | RenderBufferGeneric* mFrameTimeStampQueryReadBackBuffers[frameBufferCount];// Time stamp readback heap 193 | uint mFrameTimeStampCount[frameBufferCount]; // Time stamp count, allocate in the query heap 194 | uint mFrameGPUTimerSlotCount[frameBufferCount]; // Timer allocation count. Only count, not start/end timer count (due to level hierarchy) 195 | uint mFrameGPUTimerLevel[frameBufferCount]; // Time stamp query count. 196 | GPUTimer mFrameGPUTimers[frameBufferCount][GPUTimerMaxCount];// GPUtimer for each frame 197 | uint mGPUTimersReadBackFrameId; // The last read back frame id 198 | // And the last valid timer state captured read to be displayed 199 | uint mLastValidGPUTimerCount; 200 | uint mLastValidTimeStampCount; 201 | uint64 mLastValidTimeStamps[GPUTimerMaxCount*2]; 202 | GPUTimer mLastValidGPUTimers[GPUTimerMaxCount]; 203 | uint64 mLastValidTimeStampTickPerSeconds; 204 | 205 | #if D_ENABLE_DXR 206 | // This is in fact a dumb garbage collector since the application must register the garbage to be deleted. 207 | struct FrameGarbageCollector 208 | { 209 | std::vector mRayTracingPipelineStateSimple; 210 | std::vector mRayTracingPipelineStateClosestAndAnyHit; 211 | }; 212 | FrameGarbageCollector mFrameGarbageCollector[frameBufferCount]; 213 | #endif 214 | }; 215 | 216 | extern Dx12Device* g_dx12Device; 217 | 218 | 219 | 220 | 221 | //////////////////////////////////////////////////////////////////////////////////////////////////// 222 | //////////////////////////////////////////////////////////////////////////////////////////////////// 223 | //////////////////////////////////////////////////////////////////////////////////////////////////// 224 | 225 | 226 | 227 | 228 | template 229 | void resetComPtr(type** ptr) 230 | { 231 | if (*ptr) 232 | { 233 | (*ptr)->Release(); 234 | (*ptr) = nullptr; 235 | } 236 | } 237 | 238 | template 239 | void resetPtr(type** ptr) 240 | { 241 | if (*ptr) 242 | { 243 | delete *ptr; 244 | (*ptr) = nullptr; 245 | } 246 | } 247 | 248 | template 249 | void setDxDebugName(type* obj, LPCWSTR name) 250 | { 251 | #ifdef _DEBUG 252 | HRESULT hr = obj->SetName(name); 253 | ATLASSERT(hr == S_OK); 254 | #endif 255 | } 256 | 257 | 258 | 259 | 260 | //////////////////////////////////////////////////////////////////////////////////////////////////// 261 | //////////////////////////////////////////////////////////////////////////////////////////////////// 262 | //////////////////////////////////////////////////////////////////////////////////////////////////// 263 | 264 | 265 | 266 | 267 | #define INPUT_LAYOUT_MAX_ELEMENTCOUNT 8 268 | class InputLayout 269 | { 270 | public: 271 | InputLayout(); 272 | ~InputLayout(); 273 | 274 | void appendSimpleVertexDataToInputLayout(const char* semanticName, uint semanticIndex, DXGI_FORMAT format); 275 | void appendPerInstanceVertexDataToInputLayout(const char* semanticName, uint semanticIndex, DXGI_FORMAT format, uint InstanceDataStepRate); 276 | 277 | const D3D12_INPUT_LAYOUT_DESC* getLayoutDesc() const { return &mInputLayout; } 278 | 279 | private: 280 | InputLayout(InputLayout&); 281 | 282 | D3D12_INPUT_ELEMENT_DESC mInputLayoutElements[INPUT_LAYOUT_MAX_ELEMENTCOUNT]; 283 | D3D12_INPUT_LAYOUT_DESC mInputLayout; 284 | }; 285 | 286 | 287 | struct ShaderMacro 288 | { 289 | // We use string here to own the memory. 290 | // This is a requirement for delayed loading with non static shader parameter (created on stack or heap with unkown lifetime) 291 | std::wstring mName; 292 | std::wstring mDefinition; 293 | }; 294 | typedef std::vector Macros; // D3D_SHADER_MACRO contains pointers to string so those string must be static as of today. 295 | 296 | class ShaderBase 297 | { 298 | public: 299 | ShaderBase(const TCHAR* filename, const TCHAR* entryFunction, const TCHAR* profileStr, const Macros* macros = nullptr); 300 | virtual ~ShaderBase(); 301 | 302 | const LPVOID GetShaderByteCode() const { return mShaderBytecode->GetBufferPointer(); } 303 | SIZE_T GetShaderByteCodeSize() const { return mShaderBytecode->GetBufferSize(); } 304 | const IDxcBlob* GetShaderByteBlob() const { return mShaderBytecode; }; 305 | 306 | void MarkDirty() { mDirty = true; } 307 | void ReCompileIfNeeded(); 308 | bool CompilationSuccessful() const { return mShaderBytecode != nullptr; } 309 | 310 | protected: 311 | const TCHAR* mFilename; 312 | const TCHAR* mEntryFunction; 313 | const TCHAR* mProfile; 314 | 315 | Macros mMacros; 316 | bool mDirty; // If dirty, needs to be recompiled 317 | 318 | IDxcBlob* mShaderBytecode; 319 | 320 | static bool TryCompile(const TCHAR* filename, const TCHAR* entryFunction, const TCHAR* profile, const Macros& mMacros, IDxcBlob** mShaderBytecode); 321 | 322 | private: 323 | ShaderBase(); 324 | ShaderBase(ShaderBase&); 325 | }; 326 | 327 | class VertexShader : public ShaderBase 328 | { 329 | public: 330 | VertexShader(const TCHAR* filename, const TCHAR* entryFunction, const Macros* macros); 331 | virtual ~VertexShader(); 332 | }; 333 | 334 | class PixelShader : public ShaderBase 335 | { 336 | public: 337 | PixelShader(const TCHAR* filename, const TCHAR* entryFunction, const Macros* macros); 338 | virtual ~PixelShader(); 339 | }; 340 | 341 | class ComputeShader : public ShaderBase 342 | { 343 | public: 344 | ComputeShader(const TCHAR* filename, const TCHAR* entryFunction, const Macros* macros); 345 | virtual ~ComputeShader(); 346 | }; 347 | 348 | 349 | class DescriptorHeap 350 | { 351 | public: 352 | DescriptorHeap(bool ShaderVisible, D3D12_DESCRIPTOR_HEAP_TYPE HeapType, uint DescriptorCount); 353 | virtual ~DescriptorHeap(); 354 | 355 | ID3D12DescriptorHeap* getHeap() const { return mDescriptorHeap; } 356 | D3D12_CPU_DESCRIPTOR_HANDLE getCPUHandle() const { return mDescriptorHeap->GetCPUDescriptorHandleForHeapStart(); } 357 | D3D12_GPU_DESCRIPTOR_HANDLE getGPUHandle() const { return mDescriptorHeap->GetGPUDescriptorHandleForHeapStart(); } 358 | 359 | uint GetDescriptorCount() const { return mDescriptorCount; } 360 | 361 | private: 362 | DescriptorHeap(); 363 | DescriptorHeap(DescriptorHeap&); 364 | 365 | uint mDescriptorCount; 366 | ID3D12DescriptorHeap* mDescriptorHeap; 367 | }; 368 | 369 | 370 | // Contains decriptors for allocated resources. 371 | // Not smart, descriptors are allocated linearly and assert when out of memory. 372 | // Only for CBVs, SRVs and UAVs. 373 | class AllocatedResourceDecriptorHeap 374 | { 375 | public: 376 | AllocatedResourceDecriptorHeap(uint DescriptorCount); 377 | virtual ~AllocatedResourceDecriptorHeap(); 378 | 379 | uint GetAllocatedDescriptorCount() const { return mAllocatedDescriptorCount; } 380 | const ID3D12DescriptorHeap* getHeap() const { return mDescriptorHeap->getHeap(); } 381 | 382 | void AllocateResourceDecriptors(D3D12_CPU_DESCRIPTOR_HANDLE* CPUHandle, D3D12_GPU_DESCRIPTOR_HANDLE* GPUHandle); 383 | 384 | private: 385 | AllocatedResourceDecriptorHeap(); 386 | AllocatedResourceDecriptorHeap(AllocatedResourceDecriptorHeap&); 387 | 388 | uint mAllocatedDescriptorCount; 389 | DescriptorHeap* mDescriptorHeap; 390 | }; 391 | 392 | 393 | 394 | class DispatchDrawCallCpuDescriptorHeap 395 | { 396 | public: 397 | DispatchDrawCallCpuDescriptorHeap(uint DescriptorCount); 398 | virtual ~DispatchDrawCallCpuDescriptorHeap(); 399 | 400 | void BeginRecording(); 401 | void EndRecording(const DescriptorHeap& CopyToDescriptoHeap); 402 | 403 | struct Call 404 | { 405 | Call(); 406 | 407 | void SetSRV(uint Register, RenderResource& Resource); 408 | void SetUAV(uint Register, RenderResource& Resource); 409 | 410 | D3D12_GPU_DESCRIPTOR_HANDLE getRootDescriptorTableGpuHandle() { return mGPUHandle; } 411 | 412 | private: 413 | friend class DispatchDrawCallCpuDescriptorHeap; 414 | 415 | const RootSignature* mRootSig; 416 | D3D12_CPU_DESCRIPTOR_HANDLE mCPUHandle; // From the upload heap 417 | D3D12_GPU_DESCRIPTOR_HANDLE mGPUHandle; // From the GPU heap 418 | }; 419 | 420 | Call AllocateCall(const RootSignature& RootSig); 421 | 422 | struct SRVsDescriptorArray 423 | { 424 | SRVsDescriptorArray(); 425 | 426 | void SetSRV(uint RegisterOffsetFromBase, RenderResource& Resource); 427 | 428 | D3D12_GPU_DESCRIPTOR_HANDLE getRootDescriptorTableGpuHandle() { return mGPUHandle; } 429 | 430 | private: 431 | friend class DispatchDrawCallCpuDescriptorHeap; 432 | 433 | D3D12_CPU_DESCRIPTOR_HANDLE mCPUHandle; // From the upload heap 434 | D3D12_GPU_DESCRIPTOR_HANDLE mGPUHandle; // From the GPU heap 435 | 436 | uint mDescriptorCountAllocated = 0; 437 | }; 438 | 439 | SRVsDescriptorArray AllocateSRVsDescriptorArray(uint DescriptorCount); 440 | 441 | private: 442 | DispatchDrawCallCpuDescriptorHeap(); 443 | DispatchDrawCallCpuDescriptorHeap(DispatchDrawCallCpuDescriptorHeap&); 444 | 445 | DescriptorHeap* mCpuDescriptorHeap; 446 | 447 | uint mFrameDescriptorCount; 448 | uint mMaxFrameDescriptorCount; 449 | }; 450 | 451 | 452 | class FrameConstantBuffers 453 | { 454 | public: 455 | FrameConstantBuffers(uint64 SizeByte); 456 | virtual ~FrameConstantBuffers(); 457 | 458 | void BeginRecording(); 459 | void EndRecording(); 460 | 461 | struct FrameConstantBuffer 462 | { 463 | FrameConstantBuffer() : mCpuMemory(nullptr) {} 464 | 465 | D3D12_GPU_VIRTUAL_ADDRESS getGPUVirtualAddress() const { return mGpuVirtualAddress; } 466 | void* getCPUMemory() const { return mCpuMemory; } 467 | 468 | private: 469 | friend class FrameConstantBuffers; 470 | D3D12_GPU_VIRTUAL_ADDRESS mGpuVirtualAddress; 471 | void* mCpuMemory; 472 | }; 473 | 474 | FrameConstantBuffer AllocateFrameConstantBuffer(uint64 SizeByte); 475 | 476 | private: 477 | FrameConstantBuffers(); 478 | FrameConstantBuffers(FrameConstantBuffers&); 479 | 480 | ID3D12Resource* mConstantBufferUploadHeap; 481 | 482 | uint64 mFrameByteCount; 483 | uint64 mFrameUsedBytes; 484 | D3D12_GPU_VIRTUAL_ADDRESS mGpuVirtualAddressStart; 485 | byte* mCpuMemoryStart; 486 | }; 487 | 488 | 489 | class RenderResource 490 | { 491 | public: 492 | RenderResource(); 493 | virtual ~RenderResource(); 494 | void resourceTransitionBarrier(D3D12_RESOURCE_STATES newState); 495 | void resourceUAVBarrier(); 496 | 497 | ID3D12Resource* getD3D12Resource() { return mResource; } 498 | 499 | const D3D12_CPU_DESCRIPTOR_HANDLE& getSRVCPUHandle() const { return mSRVCPUHandle; } 500 | const D3D12_CPU_DESCRIPTOR_HANDLE& getUAVCPUHandle() const { return mUAVCPUHandle; } 501 | const D3D12_GPU_DESCRIPTOR_HANDLE& getSRVGPUHandle() const { return mSRVGPUHandle; } 502 | const D3D12_GPU_DESCRIPTOR_HANDLE& getUAVGPUHandle() const { return mUAVGPUHandle; } 503 | 504 | void setDebugName(LPCWSTR debugName) { setDxDebugName(mResource, debugName); } 505 | 506 | protected: 507 | ID3D12Resource* mResource; 508 | 509 | D3D12_CPU_DESCRIPTOR_HANDLE mSRVCPUHandle; 510 | D3D12_GPU_DESCRIPTOR_HANDLE mSRVGPUHandle; 511 | D3D12_CPU_DESCRIPTOR_HANDLE mUAVCPUHandle; 512 | D3D12_GPU_DESCRIPTOR_HANDLE mUAVGPUHandle; 513 | 514 | D3D12_RESOURCE_STATES mResourceState; 515 | 516 | private: 517 | RenderResource(RenderResource&); 518 | }; 519 | 520 | 521 | enum RenderBufferType 522 | { 523 | RenderBufferType_Default, 524 | RenderBufferType_Upload, 525 | RenderBufferType_Readback, 526 | RenderBufferType_AccelerationStructure 527 | }; 528 | 529 | D3D12_HEAP_PROPERTIES getGpuOnlyMemoryHeapProperties(); 530 | D3D12_HEAP_PROPERTIES getUploadMemoryHeapProperties(); 531 | D3D12_HEAP_PROPERTIES getReadbackMemoryHeapProperties(); 532 | 533 | D3D12_RESOURCE_DESC getRenderTextureResourceDesc( 534 | D3D12_RESOURCE_DIMENSION Dimension, 535 | unsigned int width, unsigned int height, unsigned int depth, 536 | DXGI_FORMAT format, D3D12_RESOURCE_FLAGS flags); 537 | 538 | class RenderBufferGeneric : public RenderResource 539 | { 540 | public: 541 | RenderBufferGeneric(uint64 TotalSizeInBytes, void* initData = nullptr, D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE, RenderBufferType Type = RenderBufferType_Default); 542 | virtual ~RenderBufferGeneric(); 543 | 544 | D3D12_VERTEX_BUFFER_VIEW getVertexBufferView(uint strideInByte); 545 | D3D12_INDEX_BUFFER_VIEW getIndexBufferView(DXGI_FORMAT format); 546 | D3D12_GPU_VIRTUAL_ADDRESS getGPUVirtualAddress() { return mResource->GetGPUVirtualAddress(); } 547 | uint64 GetSizeInBytes() { return mSizeInBytes; } 548 | 549 | protected: 550 | void Upload(void* InitData); 551 | private: 552 | RenderBufferGeneric(); 553 | RenderBufferGeneric(RenderBufferGeneric&); 554 | 555 | ID3D12Resource* mUploadHeap; 556 | uint64 mSizeInBytes; 557 | }; 558 | 559 | class TypedBuffer : public RenderBufferGeneric 560 | { 561 | public: 562 | TypedBuffer(uint NumElement, uint TotalSizeInBytes, DXGI_FORMAT ViewFormat = DXGI_FORMAT_UNKNOWN, void* initData = nullptr, 563 | D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE, RenderBufferType Type = RenderBufferType_Default); 564 | virtual ~TypedBuffer() {} 565 | }; 566 | class StructuredBuffer : public RenderBufferGeneric 567 | { 568 | public: 569 | StructuredBuffer(uint NumElement, uint StructureByteStride, void* initData = nullptr, 570 | D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE, RenderBufferType Type = RenderBufferType_Default); 571 | virtual ~StructuredBuffer() {} 572 | }; 573 | class ByteAddressBuffer: public RenderBufferGeneric 574 | { 575 | public: 576 | ByteAddressBuffer(uint64 TotalSizeInBytes, void* initData = nullptr, 577 | D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE, RenderBufferType Type = RenderBufferType_Default); 578 | virtual ~ByteAddressBuffer() {} 579 | }; 580 | 581 | class RenderTexture : public RenderResource 582 | { 583 | public: 584 | RenderTexture( 585 | unsigned int width, unsigned int height, 586 | unsigned int depth, DXGI_FORMAT format, 587 | D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE, 588 | D3D12_CLEAR_VALUE* ClearValue = nullptr, 589 | unsigned int RowPitchByte = 0, unsigned int SlicePitchByte = 0, void* initData = nullptr); 590 | 591 | RenderTexture(const wchar_t* szFileName, D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE); 592 | 593 | virtual ~RenderTexture(); 594 | 595 | const D3D12_CPU_DESCRIPTOR_HANDLE getRTVCPUHandle() const { return mRTVHeap->getCPUHandle(); } 596 | const D3D12_CPU_DESCRIPTOR_HANDLE getDSVCPUHandle() const { return mDSVHeap->getCPUHandle(); } 597 | const D3D12_CLEAR_VALUE& getClearColor() const { return mClearValue; } 598 | private: 599 | RenderTexture(); 600 | RenderTexture(RenderTexture&); 601 | ID3D12Resource* mUploadHeap;// private dedicated upload heap, TODO: fix bad design, handle that on Dx12Device 602 | 603 | // All texture will have this RTV related data... But fine for such a small project. 604 | D3D12_CLEAR_VALUE mClearValue; 605 | union 606 | { 607 | DescriptorHeap* mRTVHeap; 608 | DescriptorHeap* mDSVHeap; 609 | }; 610 | }; 611 | 612 | 613 | enum RootSignatureType 614 | { 615 | RootSignatureType_Global, 616 | RootSignatureType_Global_IA, 617 | RootSignatureType_Global_RT, 618 | RootSignatureType_Local_RT 619 | }; 620 | 621 | // Static assignement of root parameters 622 | enum RootParameterIndex 623 | { 624 | RootParameterIndex_CBV0 = 0, // Main constanve buffer 625 | RootParameterIndex_DescriptorTable0 = 1, // Main SRVs/UAVs 626 | RootParameterIndex_BindlessSRVs = 2, // Bindless texture array 627 | RootParameterIndex_Count = 3 628 | }; 629 | 630 | // This is the default bindless texture SRV count for the dedicated descriptor table allocated in the root parameters. 631 | // It can be changed and you need your shaders to be updated accordingly. 632 | // This is also just an implementation exemple. 633 | #define ROOT_BINDLESS_SRV_START 64 634 | #define ROOT_BINDLESS_SRV_COUNT 64 635 | 636 | 637 | // https://docs.microsoft.com/en-us/windows/win32/direct3d12/root-signature-limits 638 | // A root signature can be up to 64 DWORD 639 | // if ia is used, only 63 are available 640 | // Descriptor tables: 1 DWORD 641 | // Root constants : 1 DWORD 642 | // Root descriptors : 2 DWORD // CBV, SRV, UAV, restiction on what those can be: see https://docs.microsoft.com/en-us/windows/win32/direct3d12/using-descriptors-directly-in-the-root-signature 643 | #define DWORD_BYTE_COUNT 4 644 | #define ROOTSIG_CONSTANT_DWORD_COUNT (1) 645 | #define ROOTSIG_DESCRIPTOR_DWORD_COUNT (2) 646 | #define ROOTSIG_DESCRIPTORTABLE_DWORD_COUNT (1) 647 | #define ROOTSIG_CONSTANT_DWORD_BYTE_COUNT (ROOTSIG_CONSTANT_DWORD_COUNT*DWORD_BYTE_COUNT) 648 | #define ROOTSIG_DESCRIPTOR_DWORD_BYTE_COUNT (ROOTSIG_DESCRIPTOR_DWORD_COUNT*DWORD_BYTE_COUNT) 649 | #define ROOTSIG_DESCRIPTORTABLE_DWORD_BYTE_COUNT (ROOTSIG_DESCRIPTORTABLE_DWORD_COUNT*DWORD_BYTE_COUNT) 650 | 651 | // Static assignement of root parameters 652 | enum RootParameterByteOffset 653 | { 654 | RootParameterByteOffset_CBV0 = (ROOTSIG_CONSTANT_DWORD_BYTE_COUNT * 0 + ROOTSIG_DESCRIPTOR_DWORD_BYTE_COUNT * 0 + ROOTSIG_DESCRIPTORTABLE_DWORD_BYTE_COUNT * 0), 655 | RootParameterByteOffset_DescriptorTable0 = (ROOTSIG_CONSTANT_DWORD_BYTE_COUNT * 0 + ROOTSIG_DESCRIPTOR_DWORD_BYTE_COUNT * 1 + ROOTSIG_DESCRIPTORTABLE_DWORD_BYTE_COUNT * 0), 656 | RootParameterByteOffset_DescriptorTableBindlessSRVs = (ROOTSIG_CONSTANT_DWORD_BYTE_COUNT * 0 + ROOTSIG_DESCRIPTOR_DWORD_BYTE_COUNT * 1 + ROOTSIG_DESCRIPTORTABLE_DWORD_BYTE_COUNT * 1), 657 | RootParameterByteOffset_Total = (ROOTSIG_CONSTANT_DWORD_BYTE_COUNT * 0 + ROOTSIG_DESCRIPTOR_DWORD_BYTE_COUNT * 1 + ROOTSIG_DESCRIPTORTABLE_DWORD_BYTE_COUNT * 2) 658 | }; 659 | 660 | class RootSignature 661 | { 662 | public: 663 | RootSignature(RootSignatureType InRootSignatureType); 664 | ~RootSignature(); 665 | ID3D12RootSignature* getRootsignature() const { return mRootSignature; } 666 | 667 | uint getRootCBVCount() const { return mRootCBVCount; } 668 | uint getRootDescriptorTable0SRVCount() const { return mDescriptorTable0SRVCount; } 669 | uint getRootDescriptorTable0UAVCount() const { return mDescriptorTable0UAVCount; } 670 | 671 | uint getRootSignatureSizeBytes() const { return mRootSignatureDWordUsed * 4; } 672 | 673 | void setDebugName(LPCWSTR debugName) { setDxDebugName(mRootSignature, debugName); } 674 | private: 675 | RootSignature(); 676 | RootSignature(RootSignature&); 677 | 678 | uint mRootCBVCount; 679 | uint mDescriptorTable0SRVCount; 680 | uint mDescriptorTable0UAVCount; 681 | 682 | ID3D12RootSignature* mRootSignature; 683 | uint mRootSignatureDWordUsed; 684 | }; 685 | 686 | 687 | 688 | 689 | typedef D3D12_DEPTH_STENCIL_DESC DepthStencilState; 690 | const DepthStencilState& getDepthStencilState_Default(); // Depth and depth write enabled 691 | const DepthStencilState& getDepthStencilState_ReadOnly(); 692 | const DepthStencilState& getDepthStencilState_Disabled(); 693 | 694 | typedef D3D12_BLEND_DESC BlendState; 695 | const BlendState& getBlendState_Default(); // Disabled 696 | const BlendState& getBlendState_PremultipledAlpha(); // Premultiplied alpha on destination buffer RGB. A contains transmittance (requires clearing to alpha=1). 697 | const BlendState& getBlendState_AlphaBlending(); // Alpha blending on destination buffer RGB. A contains transmittance (requires clearing to alpha=1). 698 | 699 | typedef D3D12_RASTERIZER_DESC RasterizerState; 700 | const RasterizerState& getRasterizerState_Default(); // solide, front=clockwise, cull back, everything else off. 701 | const RasterizerState& getRasterizerState_DefaultNoCulling(); 702 | 703 | struct CachedRasterPsoDesc; 704 | struct CachedComputePsoDesc; 705 | 706 | class PipelineStateObject 707 | { 708 | public: 709 | PipelineStateObject(const CachedRasterPsoDesc& PSODesc); 710 | 711 | PipelineStateObject(const CachedComputePsoDesc& PSODesc); 712 | 713 | ~PipelineStateObject(); 714 | ID3D12PipelineState* getPso() const { return mPso; } 715 | 716 | void setDebugName(LPCWSTR debugName) { setDxDebugName(mPso, debugName); } 717 | private: 718 | PipelineStateObject(); 719 | PipelineStateObject(PipelineStateObject&); 720 | 721 | ID3D12PipelineState* mPso; 722 | }; 723 | 724 | 725 | 726 | 727 | //////////////////////////////////////////////////////////////////////////////////////////////////// 728 | //////////////////////////////////////////////////////////////////////////////////////////////////// 729 | //////////////////////////////////////////////////////////////////////////////////////////////////// 730 | 731 | 732 | 733 | 734 | struct ScopedGpuEvent 735 | { 736 | ScopedGpuEvent(LPCWSTR name) 737 | { 738 | #if D_ENABLE_PIX 739 | PIXBeginEvent(g_dx12Device->getFrameCommandList(), PIX_COLOR(200, 200, 200), name); 740 | #endif 741 | } 742 | ~ScopedGpuEvent() 743 | { 744 | release(); 745 | } 746 | void release() 747 | { 748 | #if D_ENABLE_PIX 749 | if (!mReleased) 750 | { 751 | mReleased = true; 752 | PIXEndEvent(g_dx12Device->getFrameCommandList()); 753 | } 754 | #endif 755 | } 756 | private: 757 | ScopedGpuEvent() = delete; 758 | ScopedGpuEvent(ScopedGpuEvent&) = delete; 759 | bool mReleased = false; 760 | }; 761 | #define SCOPED_GPU_EVENT(eventName) ScopedGpuEvent gpuEvent##eventName##(L""#eventName) 762 | 763 | 764 | 765 | struct ScopedGpuTimer 766 | { 767 | ScopedGpuTimer(LPCWSTR name, byte R=100, byte G = 100, byte B = 100, byte A = 255) 768 | : mName(name) 769 | { 770 | g_dx12Device->StartGPUTimer(name, R | (G << 8) | (B << 16) | (A << 24)); 771 | } 772 | ~ScopedGpuTimer() 773 | { 774 | g_dx12Device->EndGPUTimer(mName); 775 | } 776 | void release() 777 | { 778 | #if D_ENABLE_PIX 779 | if (!mReleased) 780 | { 781 | mReleased = true; 782 | PIXEndEvent(g_dx12Device->getFrameCommandList()); 783 | } 784 | #endif // 785 | } 786 | private: 787 | ScopedGpuTimer() = delete; 788 | ScopedGpuTimer(ScopedGpuTimer&) = delete; 789 | LPCWSTR mName; 790 | bool mReleased = false; 791 | }; 792 | #define SCOPED_GPU_TIMER(timerName, R, G, B) ScopedGpuEvent gpuEvent##timerName##(L""#timerName); ScopedGpuTimer gpuTimer##timerName##(L""#timerName, R, G, B); 793 | 794 | 795 | 796 | 797 | //////////////////////////////////////////////////////////////////////////////////////////////////// 798 | //////////////////////////////////////////////////////////////////////////////////////////////////// 799 | //////////////////////////////////////////////////////////////////////////////////////////////////// 800 | 801 | 802 | 803 | 804 | // Pointers in that structure should point to static global elements (not stack). 805 | // This to avoid infinite PSOs creation because it is part of the hash key used to cache them. 806 | struct CachedRasterPsoDesc 807 | { 808 | const RootSignature* mRootSign = nullptr; 809 | 810 | const InputLayout* mLayout = nullptr; 811 | VertexShader* mVS = nullptr; 812 | PixelShader* mPS = nullptr; 813 | 814 | const DepthStencilState* mDepthStencilState = nullptr; 815 | const RasterizerState* mRasterizerState = nullptr; 816 | const BlendState* mBlendState = nullptr; 817 | 818 | uint mRenderTargetCount = 0; 819 | D3D12_CPU_DESCRIPTOR_HANDLE mRenderTargetDescriptors[8] = { { INVALID_DESCRIPTOR_HANDLE },{ INVALID_DESCRIPTOR_HANDLE },{ INVALID_DESCRIPTOR_HANDLE },{ INVALID_DESCRIPTOR_HANDLE },{ INVALID_DESCRIPTOR_HANDLE },{ INVALID_DESCRIPTOR_HANDLE },{ INVALID_DESCRIPTOR_HANDLE },{ INVALID_DESCRIPTOR_HANDLE } }; 820 | DXGI_FORMAT mRenderTargetFormats[8] = { DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN}; 821 | D3D12_CPU_DESCRIPTOR_HANDLE mDepthTextureDescriptor = { INVALID_DESCRIPTOR_HANDLE }; 822 | DXGI_FORMAT mDepthTextureFormat = DXGI_FORMAT_UNKNOWN; 823 | }; 824 | 825 | struct CachedComputePsoDesc 826 | { 827 | const RootSignature* mRootSign = nullptr; 828 | 829 | ComputeShader* mCS = nullptr; 830 | }; 831 | 832 | typedef uint PSOKEY; 833 | typedef std::map CachedPSOs; 834 | 835 | class CachedPSOManager 836 | { 837 | public: 838 | CachedPSOManager(); 839 | virtual ~CachedPSOManager(); 840 | 841 | static void initialise(); 842 | static void shutdown(); 843 | 844 | size_t GetCachedRasterPSOCount() const { return mCachedRasterPSOs.size(); } 845 | size_t GetCachedComputePSOCount() const { return mCachedComputePSOs.size(); } 846 | 847 | const PipelineStateObject& GetCachedPSO(const CachedRasterPsoDesc& PsoDesc); 848 | const PipelineStateObject& GetCachedPSO(const CachedComputePsoDesc& PsoDesc); 849 | 850 | void SetPipelineState(ID3D12GraphicsCommandList* commandList, const CachedRasterPsoDesc& PsoDesc); 851 | void SetPipelineState(ID3D12GraphicsCommandList* commandList, const CachedComputePsoDesc& PsoDesc); 852 | 853 | private: 854 | 855 | CachedPSOs mCachedRasterPSOs; 856 | CachedPSOs mCachedComputePSOs; 857 | }; 858 | 859 | extern CachedPSOManager* g_CachedPSOManager; 860 | 861 | 862 | 863 | 864 | //////////////////////////////////////////////////////////////////////////////////////////////////// 865 | //////////////////////////////////////////////////////////////////////////////////////////////////// 866 | //////////////////////////////////////////////////////////////////////////////////////////////////// 867 | 868 | 869 | 870 | --------------------------------------------------------------------------------