├── .gitignore ├── DXRPathTracer.sln ├── DXRPathTracer ├── Array.h ├── Camera.cpp ├── Camera.h ├── D3D12Screen.cpp ├── D3D12Screen.h ├── D3D12Screen.hlsl ├── DXRPathTracer.cpp ├── DXRPathTracer.h ├── DXRPathTracer.vcxproj ├── DXRPathTracer.vcxproj.filters ├── DXRPathTracer.vcxproj.user ├── DXRShader.hlsl ├── Error.h ├── IGRTCommon.h ├── IGRTScreen.h ├── IGRTTracer.h ├── Input.h ├── Material.h ├── Mesh.h ├── Scene.h ├── SceneLoader.cpp ├── SceneLoader.h ├── basic_math.h ├── basic_types.h ├── dxHelpers.cpp ├── dxHelpers.h ├── generateMesh.cpp ├── generateMesh.h ├── loadMesh.cpp ├── loadMesh.h ├── main.cpp ├── pch.cpp ├── pch.h ├── sampling.hlsli ├── timer.h └── tiny_obj_loader.h ├── README.md ├── data └── mesh │ ├── brain.obj │ ├── burrPuzzle.obj │ ├── golfball.obj │ ├── hippo.obj │ ├── lucy.obj │ ├── ring.obj │ └── teddy.obj └── images ├── diagram.png ├── hyperion.png ├── hyperion2.png └── hyperion3.png /.gitignore: -------------------------------------------------------------------------------- 1 | *.cso 2 | 3 | bin/ 4 | 5 | x64/ 6 | 7 | .vs/ 8 | -------------------------------------------------------------------------------- /DXRPathTracer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.705 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DXRPathTracer", "DXRPathTracer\DXRPathTracer.vcxproj", "{5E5F5505-83D3-4DC8-9232-FA5DBA34C383}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {5E5F5505-83D3-4DC8-9232-FA5DBA34C383}.Debug|x64.ActiveCfg = Debug|x64 17 | {5E5F5505-83D3-4DC8-9232-FA5DBA34C383}.Debug|x64.Build.0 = Debug|x64 18 | {5E5F5505-83D3-4DC8-9232-FA5DBA34C383}.Debug|x86.ActiveCfg = Debug|Win32 19 | {5E5F5505-83D3-4DC8-9232-FA5DBA34C383}.Debug|x86.Build.0 = Debug|Win32 20 | {5E5F5505-83D3-4DC8-9232-FA5DBA34C383}.Release|x64.ActiveCfg = Release|x64 21 | {5E5F5505-83D3-4DC8-9232-FA5DBA34C383}.Release|x64.Build.0 = Release|x64 22 | {5E5F5505-83D3-4DC8-9232-FA5DBA34C383}.Release|x86.ActiveCfg = Release|Win32 23 | {5E5F5505-83D3-4DC8-9232-FA5DBA34C383}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {4D7017E2-0430-4484-AB46-A5DDE77FF91D} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /DXRPathTracer/Array.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | template< class T > struct remove_ref {typedef T type;}; 5 | template< class T > struct remove_ref {typedef T type;}; 6 | template< class T > struct remove_ref {typedef T type;}; 7 | template< class T > using RefRemoved = typename remove_ref::type; 8 | 9 | template constexpr 10 | RefRemoved&& move2(T&& x) 11 | { 12 | return static_cast< RefRemoved&& > (x); 13 | } 14 | 15 | typedef unsigned int uint; 16 | typedef unsigned long long uint64; 17 | 18 | 19 | template 20 | class Array 21 | { 22 | SizeType _size = 0; 23 | SizeType _capacity = 0; 24 | T* _data = nullptr; 25 | 26 | public: 27 | ~Array() { clear(); } 28 | Array() {} 29 | Array(SizeType size) { resize(size); } 30 | Array(SizeType size, const T& value) { resize(size, value); } 31 | Array(std::initializer_list list) 32 | { 33 | reserve( (SizeType) list.size() ); 34 | for (auto ele : list) 35 | { 36 | push_back(ele); 37 | } 38 | } 39 | Array(const Array& arr) : _size(arr._size), _capacity(arr._capacity) 40 | { 41 | _data = static_cast(::operator new(sizeof(T) * _capacity)); 42 | for (SizeType i = 0; i < _size; ++i) 43 | { 44 | new (_data + i) T(arr._data[i]); 45 | } 46 | } 47 | Array(Array&& arr) : _size(arr._size), _capacity(arr._capacity) 48 | { 49 | _data = arr._data; 50 | arr._data = nullptr; 51 | arr._size = 0; 52 | arr._capacity = 0; 53 | } 54 | 55 | void swap(Array& arr) 56 | { 57 | SizeType tempSize = _size; 58 | SizeType tempCapacity = _capacity; 59 | T* tempData = _data; 60 | 61 | _size = arr._size; 62 | _capacity = arr._capacity; 63 | _data = arr._data; 64 | 65 | arr._size = tempSize; 66 | arr._capacity = tempCapacity; 67 | arr._data = tempData; 68 | } 69 | 70 | void reserve(SizeType capacity) 71 | { 72 | if (capacity <= _capacity) 73 | return; 74 | 75 | T* newData = static_cast(::operator new(sizeof(T) * capacity)); 76 | for (SizeType i = 0; i < _size; ++i) 77 | { 78 | new (newData + i) T(_data[i]); 79 | _data[i].~T(); 80 | } 81 | 82 | if(_data) 83 | ::operator delete(_data); 84 | 85 | _data = newData; 86 | _capacity = capacity; 87 | } 88 | 89 | void resize(SizeType size) 90 | { 91 | if (size <= _size) 92 | { 93 | for (SizeType i = size; i < _size; ++i) 94 | { 95 | _data[i].~T(); 96 | } 97 | } 98 | else 99 | { 100 | if (size > _capacity) 101 | reserve(size); 102 | 103 | for (SizeType i = _size; i < size; ++i) 104 | { 105 | new (_data + i) T; 106 | } 107 | } 108 | 109 | _size = size; 110 | } 111 | 112 | void resize(SizeType size, const T& value) 113 | { 114 | if (size <= _size) 115 | { 116 | for (SizeType i = size; i < _size; ++i) 117 | { 118 | _data[i].~T(); 119 | } 120 | } 121 | else 122 | { 123 | if (size > _capacity) 124 | reserve(size); 125 | 126 | for (SizeType i = _size; i < size; ++i) 127 | { 128 | new (_data + i) T(value); 129 | } 130 | } 131 | 132 | _size = size; 133 | } 134 | 135 | void push_back(const T& value) 136 | { 137 | if (_size == _capacity) 138 | { 139 | SizeType newCapacity = _capacity >= 4 ? (SizeType)((float)_capacity * 1.5f) : 4; 140 | reserve(newCapacity); 141 | } 142 | 143 | new (_data + _size) T(value); 144 | ++_size; 145 | } 146 | 147 | void push_back(T&& value) 148 | { 149 | if (_size == _capacity) 150 | { 151 | SizeType newCapacity = _capacity >= 4 ? (SizeType)((float)_capacity * 1.5f) : 4; 152 | reserve(newCapacity); 153 | } 154 | 155 | new (_data + _size) T(move2(value)); 156 | ++_size; 157 | } 158 | 159 | void clear() 160 | { 161 | for (SizeType i = 0; i < _size; ++i) 162 | { 163 | _data[i].~T(); 164 | } 165 | 166 | if(_data) 167 | ::operator delete(_data); 168 | _data = nullptr; 169 | _capacity = 0; 170 | _size = 0; 171 | } 172 | 173 | SizeType size() const {return _size;} 174 | T* data() {return _data;} 175 | T* begin() {return _data;} 176 | T* end() {return _data + _size;} 177 | T& operator[](SizeType idx) {return _data[idx];} 178 | const T* data() const {return _data;} 179 | const T* begin() const {return _data;} 180 | const T* end() const {return _data + _size;} 181 | const T& operator[](SizeType idx) const {return _data[idx];} 182 | }; 183 | -------------------------------------------------------------------------------- /DXRPathTracer/Camera.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Camera.h" 3 | #include "Input.h" 4 | 5 | 6 | const float OrbitCamera::minOrbitRadius = 0.01f; 7 | 8 | inline void OrbitCamera::updateCameraOrientation() 9 | { 10 | float A = azimuth * 2.0f * PI; 11 | float B = altitude * 0.5f * PI; 12 | float cA = cosf(A), sA = sinf(A), cB = cosf(B), sB = sinf(B); 13 | 14 | setCameraX(float3( cA, 0.0f, -sA )); 15 | setCameraY(float3( sB*sA, -cB, sB*cA )); 16 | setCameraZ(float3(-cB*sA, -sB, -cB*cA )); 17 | } 18 | 19 | inline void OrbitCamera::updateCameraPosition() 20 | { 21 | setCameraPos(orbitCenter - orbitRadius * getCameraZ()); 22 | } 23 | 24 | void OrbitCamera::initOrbit(const float3& target, float distanceToTarget, float azimuth, float altitude) 25 | { 26 | orbitCenter = target; 27 | orbitRadius = _max(distanceToTarget, minOrbitRadius); 28 | this->azimuth = azimuth; 29 | this->altitude = altitude; 30 | 31 | updateCameraOrientation(); 32 | updateCameraPosition(); 33 | } 34 | 35 | inline void OrbitCamera::orbit(float deltaAzimuth, float deltaAltitude) 36 | { 37 | azimuth = azimuth + deltaAzimuth; 38 | if (azimuth < 0.0f) azimuth += 1.0f; 39 | else if (azimuth > 1.0f) azimuth -= 1.0f; 40 | 41 | altitude = _clamp(altitude + deltaAltitude, -0.95f, 0.95f); 42 | 43 | updateCameraOrientation(); 44 | updateCameraPosition(); 45 | } 46 | 47 | inline void OrbitCamera::truck(float stepX, float stepY) 48 | { 49 | orbitCenter = orbitCenter + stepX * getCameraX() + stepY * getCameraY(); 50 | 51 | updateCameraPosition(); 52 | } 53 | 54 | inline void OrbitCamera::dolly(float deltaRadius) 55 | { 56 | orbitRadius = _max(orbitRadius + deltaRadius, minOrbitRadius); 57 | 58 | updateCameraPosition(); 59 | } 60 | 61 | void OrbitCamera::update(const InputEngine& input) 62 | { 63 | int2 screenDelta; 64 | 65 | screenDelta = input.getMouseDragged(LButton); 66 | if (screenDelta.x != 0 || screenDelta.y != 0) { 67 | orbit( float(-screenDelta.x) / getScreenWidth(), 68 | float( screenDelta.y) / (0.5f*getScreenHeight()) ); 69 | } 70 | 71 | screenDelta = input.getMouseDragged(MButton); 72 | if (screenDelta.x != 0 || screenDelta.y != 0) { 73 | truck( float(-screenDelta.x) / speedRatio, 74 | float(-screenDelta.y) / speedRatio ); 75 | } 76 | 77 | screenDelta = input.getMouseDragged(RButton); 78 | if (screenDelta.y != 0) { 79 | dolly( float(-screenDelta.y) / speedRatio ); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /DXRPathTracer/Camera.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | 4 | 5 | class InputEngine; 6 | class PinholeCamera 7 | { 8 | // Camera Intrinsic Parameters 9 | float fovY = 60.0f; 10 | float screenWidth = 1.0f; 11 | float screenHeight = 1.0f; 12 | 13 | // Camera Extrinsic Parameters 14 | float3 cameraPos; 15 | float3 cameraX; 16 | float3 cameraY; 17 | float3 cameraZ; 18 | 19 | float2 cameraAspect; 20 | void updateCameraAspect() { 21 | cameraAspect.y = tanf( (fovY*0.5f) * DEGREE ); 22 | cameraAspect.x = cameraAspect.y * screenWidth / screenHeight; 23 | } 24 | 25 | bool changed = false; 26 | 27 | public: 28 | const float2& getCameraAspect() const { return cameraAspect; } 29 | const float3& getCameraPos() const { return cameraPos; } 30 | const float3& getCameraX () const { return cameraX; } 31 | const float3& getCameraY () const { return cameraY; } 32 | const float3& getCameraZ () const { return cameraZ; } 33 | const float getScreenWidth() const { return screenWidth; } 34 | const float getScreenHeight() const { return screenHeight; } 35 | const float getFovY() const { return fovY; } 36 | 37 | void setCameraPos(const float3& pos ) { cameraPos = pos; changed = true; } 38 | void setCameraX (const float3& xDir) { cameraX = xDir; changed = true; } 39 | void setCameraY (const float3& yDir) { cameraY = yDir; changed = true; } 40 | void setCameraZ (const float3& zDir) { cameraZ = zDir; changed = true; } 41 | void setScreenSize(float w, float h) { 42 | assert(w>0.f && h>0.f); 43 | screenWidth = w; 44 | screenHeight = h; 45 | updateCameraAspect(); 46 | changed = true; 47 | } 48 | void setFovY(float fovY) { 49 | this->fovY = fovY; 50 | updateCameraAspect(); 51 | changed = true; 52 | } 53 | 54 | bool notifyChanged() { 55 | if (changed) { 56 | changed = false; 57 | return true; 58 | } 59 | return false; 60 | } 61 | 62 | virtual void update(const InputEngine& input) {} 63 | }; 64 | 65 | 66 | class OrbitCamera : public PinholeCamera 67 | { 68 | static const float minOrbitRadius; 69 | float3 orbitCenter; 70 | float orbitRadius; 71 | float azimuth; // [ 0, 2Pi] -> [ 0.0, 1.0] mapped angle measured from positive z-axis in zx-plane with origin at target. 72 | float altitude; // [-Pi/2, Pi/2] -> [-1.0, 1.0] mapped angle measured from azimuth-rotated z-axis. 73 | 74 | float speedRatio = 80.0f; 75 | 76 | void updateCameraOrientation(); 77 | void updateCameraPosition(); 78 | 79 | public: 80 | float getSpeedRatio() const { return speedRatio; } 81 | void setSpeedRatio(float speedRatio) { this->speedRatio = speedRatio; } 82 | void initOrbit(const float3& target, float distanceToTarget, float azimuth = 0.0f, float altitude = 0.1f); 83 | void orbit(float deltaAzimuth, float deltaAltitude); 84 | void truck(float deltaX, float deltaY); 85 | void dolly(float deltaRadius); 86 | virtual void update(const InputEngine& input); 87 | }; -------------------------------------------------------------------------------- /DXRPathTracer/D3D12Screen.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "D3D12Screen.h" 3 | 4 | 5 | namespace DescriptorID { 6 | enum { 7 | tracerOutTextureSRV = 0, 8 | 9 | maxDesciptors = 1 10 | }; 11 | } 12 | 13 | 14 | D3D12Screen::~D3D12Screen() 15 | { 16 | SAFE_RELEASE(mCmdQueue); 17 | SAFE_RELEASE(mCmdList); 18 | SAFE_RELEASE(mCmdAllocator); 19 | SAFE_RELEASE(mPipeline); 20 | SAFE_RELEASE(mDevice); 21 | } 22 | 23 | D3D12Screen::D3D12Screen(HWND hwnd, uint width, uint height) 24 | : IGRTScreen(hwnd, width, height) 25 | { 26 | tracerOutW = screenW; 27 | tracerOutH = screenH; 28 | 29 | initD3D12(); 30 | 31 | mSwapChain.create(mCmdQueue, targetWindow, backBufferCount, screenOutFormat, screenW, screenH, false); 32 | 33 | mSrvUavHeap.create(DescriptorID::maxDesciptors); 34 | 35 | declareRootSignature(); 36 | 37 | createPipeline(); 38 | 39 | initializeResources(); 40 | 41 | mFence.waitCommandQueue(mCmdQueue); 42 | } 43 | 44 | void D3D12Screen::initD3D12() 45 | { 46 | mDevice = createDX12Device(getRTXAdapter()); 47 | 48 | D3D12_COMMAND_QUEUE_DESC cqDesc = {}; 49 | cqDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; 50 | ThrowFailedHR(mDevice->CreateCommandQueue(&cqDesc, IID_PPV_ARGS(&mCmdQueue))); 51 | 52 | ThrowFailedHR(mDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&mCmdAllocator))); 53 | 54 | ThrowFailedHR(mDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, mCmdAllocator, nullptr, IID_PPV_ARGS(&mCmdList))); 55 | ThrowFailedHR(mCmdList->Close()); 56 | 57 | mFence.create(mDevice); 58 | } 59 | 60 | void D3D12Screen::declareRootSignature() 61 | { 62 | assert(mSrvUavHeap.get() != nullptr); 63 | 64 | mRootSig.resize(1); 65 | mRootSig[0] = new RootTable("t0", mSrvUavHeap[DescriptorID::tracerOutTextureSRV].getGpuHandle()); 66 | mRootSig.build(StaticSampler()); 67 | } 68 | 69 | void D3D12Screen::createPipeline() 70 | { 71 | D3D12_INPUT_LAYOUT_DESC inputLayout = { nullptr, 0 }; 72 | dxShader vertexShader(L"D3D12Screen.hlsl", "VSMain", "vs_5_0"); 73 | dxShader pixelShader(L"D3D12Screen.hlsl", "PSMain", "ps_5_0"); 74 | 75 | D3D12_GRAPHICS_PIPELINE_STATE_DESC pipelineDesc = 76 | Graphics_Pipeline_Desc(inputLayout, mRootSig.get(), vertexShader.getCode(), pixelShader.getCode(), mSwapChain.getBufferFormat()); 77 | 78 | ThrowFailedHR(mDevice->CreateGraphicsPipelineState(&pipelineDesc, IID_PPV_ARGS(&mPipeline))); 79 | } 80 | 81 | void D3D12Screen::initializeResources() 82 | { 83 | mTextureUploader.create(_textureDataSize(tracerOutFormat, 1920, 1080)); 84 | mTracerOutTexture.create(tracerOutFormat, tracerOutW, tracerOutH); 85 | 86 | mSrvUavHeap[DescriptorID::tracerOutTextureSRV].assignSRV(mTracerOutTexture, nullptr); 87 | } 88 | 89 | void D3D12Screen::fillCommandLists() 90 | { 91 | D3D12_VIEWPORT viewport = { 0.0f, 0.0f, (float)screenW, (float)screenH, 0.0f, 1.0f}; 92 | D3D12_RECT scissorRect = { 0, 0, (LONG)screenW, (LONG)screenH }; 93 | 94 | mCmdList->SetPipelineState(mPipeline); 95 | 96 | mSrvUavHeap.bind(mCmdList); 97 | mRootSig.bindGraphics(mCmdList); 98 | 99 | mCmdList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); 100 | mCmdList->RSSetViewports(1, &viewport); 101 | mCmdList->RSSetScissorRects(1, &scissorRect); 102 | mCmdList->OMSetRenderTargets(1, &mSwapChain.getRtv(), FALSE, nullptr); 103 | 104 | D3D12_RESOURCE_BARRIER barrier = Transition(mSwapChain.getRenderTatget(), 105 | D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET); 106 | mCmdList->ResourceBarrier(1, &barrier); 107 | 108 | mCmdList->DrawInstanced(4, 1, 0, 0); 109 | 110 | barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; 111 | barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; 112 | mCmdList->ResourceBarrier(1, &barrier); 113 | } 114 | 115 | void D3D12Screen::display(const TracedResult& trResult) 116 | { 117 | ThrowFailedHR(mCmdAllocator->Reset()); 118 | ThrowFailedHR(mCmdList->Reset(mCmdAllocator, nullptr)); 119 | 120 | uint64 trResultPitch = trResult.width * trResult.pixelSize; 121 | assert(trResultPitch == mTracerOutTexture.getRowDataSize()); 122 | 123 | memcpyPitch(mTextureUploader.map(), mTracerOutTexture.getRowPitch(), 124 | trResult.data, trResultPitch, trResultPitch, trResult.height); 125 | 126 | mTracerOutTexture.uploadData(mCmdList, mTextureUploader); 127 | 128 | fillCommandLists(); 129 | 130 | ThrowFailedHR(mCmdList->Close()); 131 | 132 | ID3D12CommandList* pCommandLists[] = { mCmdList }; 133 | mCmdQueue->ExecuteCommandLists(1, pCommandLists); 134 | 135 | mSwapChain.present(); 136 | 137 | mFence.waitCommandQueue(mCmdQueue); 138 | } 139 | 140 | void D3D12Screen::onSizeChanged(uint width, uint height) 141 | { 142 | if (width == screenW && height == screenH) 143 | return; 144 | 145 | if (width == 0 || height == 0) 146 | return; 147 | 148 | tracerOutW = screenW = width; 149 | tracerOutH = screenH = height; 150 | 151 | mSwapChain.resize(screenW, screenH); 152 | 153 | mTracerOutTexture.destroy(); 154 | mTracerOutTexture.create(tracerOutFormat, tracerOutW, tracerOutH); 155 | 156 | mSrvUavHeap[DescriptorID::tracerOutTextureSRV].assignSRV(mTracerOutTexture, nullptr); 157 | 158 | mFence.waitCommandQueue(mCmdQueue); 159 | } -------------------------------------------------------------------------------- /DXRPathTracer/D3D12Screen.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "IGRTScreen.h" 3 | #include "dxHelpers.h" 4 | 5 | 6 | class D3D12Screen : public IGRTScreen 7 | { 8 | static const DXGI_FORMAT tracerOutFormat = DXGI_FORMAT_R32G32B32A32_FLOAT; 9 | static const DXGI_FORMAT screenOutFormat = DXGI_FORMAT_R8G8B8A8_UNORM; 10 | static const uint backBufferCount = 2; 11 | 12 | ID3D12Device* mDevice; 13 | ID3D12CommandQueue* mCmdQueue; 14 | ID3D12GraphicsCommandList* mCmdList; 15 | ID3D12CommandAllocator* mCmdAllocator; 16 | BinaryFence mFence; 17 | void initD3D12(); 18 | 19 | SwapChain mSwapChain; 20 | 21 | DescriptorHeap mSrvUavHeap; 22 | 23 | RootSignature mRootSig; 24 | void declareRootSignature(); 25 | 26 | ID3D12PipelineState* mPipeline; 27 | void createPipeline(); 28 | 29 | DefaultTexture mTracerOutTexture; 30 | UploadBuffer mTextureUploader; 31 | void initializeResources(); 32 | 33 | void fillCommandLists(); 34 | 35 | public: 36 | ~D3D12Screen(); 37 | D3D12Screen(HWND hwnd, uint width, uint height); 38 | virtual void onSizeChanged(uint width, uint height); 39 | virtual void display(const TracedResult& trResult); 40 | }; -------------------------------------------------------------------------------- /DXRPathTracer/D3D12Screen.hlsl: -------------------------------------------------------------------------------- 1 | 2 | struct VSInput 3 | { 4 | uint vertexId : SV_VertexID; 5 | }; 6 | 7 | typedef struct VSOutput 8 | { 9 | float4 position : SV_POSITION; 10 | float2 uv : TEXCOORD; 11 | }PSInput; 12 | 13 | VSOutput VSMain(VSInput input) 14 | { 15 | const float4 screen[4] = { 16 | float4(-1, -1, 0, 1), 17 | float4(-1, 1, 0, 1), 18 | float4(1, -1, 0, 1), 19 | float4(1, 1, 0, 1) 20 | }; 21 | const float2 uv[4] = { 22 | float2(0, 1), 23 | float2(0, 0), 24 | float2(1, 1), 25 | float2(1, 0) 26 | }; 27 | 28 | VSOutput result; 29 | result.position = screen[input.vertexId]; 30 | result.uv = uv[input.vertexId]; 31 | 32 | return result; 33 | } 34 | 35 | Texture2D g_texture : register(t0); 36 | SamplerState g_sampler : register(s0); 37 | 38 | static const float exposure = 1.66; 39 | 40 | float4 PSMain(PSInput input) : SV_TARGET 41 | { 42 | float3 hdrColor = abs( g_texture.Sample(g_sampler, input.uv).rgb ); 43 | 44 | float3 ldrColor = 1.0 - exp(-exposure * hdrColor); 45 | 46 | float4 outColor = float4( pow(ldrColor, 1/2.2), 1 ); 47 | 48 | return outColor; 49 | 50 | /*float4 color = g_texture.Sample(g_sampler, input.uv); 51 | color.xyz = pow(abs(color.xyz), 1 / 2.2); 52 | return color;*/ 53 | } 54 | 55 | -------------------------------------------------------------------------------- /DXRPathTracer/DXRPathTracer.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "DXRPathTracer.h" 3 | #include "Camera.h" 4 | #include "Scene.h" 5 | 6 | 7 | namespace DescriptorID { 8 | enum { 9 | // First RootParameter 10 | outUAV = 0, 11 | 12 | // Third RootParameter 13 | sceneObjectBuff = 1, 14 | vertexBuff = 2, 15 | tridexBuff = 3, 16 | materialBuff = 4, 17 | cdfBuff = 5, 18 | transformBuff = 6, 19 | 20 | // Not used since we use RootPointer instead of RootTable 21 | accelerationStructure = 10, 22 | 23 | maxDesciptors = 32 24 | }; 25 | } 26 | 27 | namespace RootParamID { 28 | enum { 29 | tableForOutBuffer = 0, 30 | pointerForAccelerationStructure = 1, 31 | tableForGeometryInputs = 2, 32 | pointerForGlobalConstants = 3, 33 | numParams = 4 34 | }; 35 | } 36 | 37 | namespace HitGroupParamID { 38 | enum { 39 | constantsForObject = 0, 40 | numParams = 1 41 | }; 42 | } 43 | 44 | DXRPathTracer::~DXRPathTracer() 45 | { 46 | SAFE_RELEASE(mCmdQueue); 47 | SAFE_RELEASE(mCmdList); 48 | SAFE_RELEASE(mCmdAllocator); 49 | SAFE_RELEASE(mDevice); 50 | } 51 | 52 | DXRPathTracer::DXRPathTracer(uint width, uint height) 53 | : IGRTTracer(width, height) 54 | { 55 | initD3D12(); 56 | 57 | mSrvUavHeap.create(DescriptorID::maxDesciptors); 58 | 59 | declareRootSignatures(); 60 | 61 | buildRaytracingPipeline(); 62 | 63 | initializeApplication(); 64 | 65 | //mFence.waitCommandQueue(mCmdQueue); 66 | } 67 | 68 | void DXRPathTracer::initD3D12() 69 | { 70 | mDevice = (ID3D12Device5*) createDX12Device(getRTXAdapter()); 71 | 72 | D3D12_COMMAND_QUEUE_DESC cqDesc = {}; 73 | cqDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; 74 | 75 | ThrowFailedHR(mDevice->CreateCommandQueue(&cqDesc, IID_PPV_ARGS(&mCmdQueue))); 76 | 77 | ThrowFailedHR(mDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&mCmdAllocator))); 78 | 79 | ThrowFailedHR(mDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, mCmdAllocator, nullptr, IID_PPV_ARGS(&mCmdList))); 80 | 81 | ThrowFailedHR(mCmdList->Close()); 82 | ThrowFailedHR(mCmdAllocator->Reset()); 83 | ThrowFailedHR(mCmdList->Reset(mCmdAllocator, nullptr)); 84 | 85 | mFence.create(mDevice); 86 | } 87 | 88 | void DXRPathTracer::declareRootSignatures() 89 | { 90 | assert(mSrvUavHeap.get() != nullptr); 91 | 92 | // Global(usual) Root Signature 93 | mGlobalRS.resize(RootParamID::numParams); 94 | mGlobalRS[RootParamID::tableForOutBuffer] 95 | = new RootTable("u0", mSrvUavHeap[DescriptorID::outUAV].getGpuHandle()); 96 | mGlobalRS[RootParamID::pointerForAccelerationStructure] 97 | = new RootPointer("(100) t0"); // It will be bound to mAccelerationStructure that is not initialized yet. 98 | mGlobalRS[RootParamID::tableForGeometryInputs] 99 | = new RootTable("(0) t0-t5", mSrvUavHeap[DescriptorID::sceneObjectBuff].getGpuHandle()); 100 | mGlobalRS[RootParamID::pointerForGlobalConstants] 101 | = new RootPointer("b0"); // It will be bound to mGlobalConstantsBuffer that is not initialized yet. 102 | mGlobalRS.build(); 103 | 104 | // Local Root Sinatures 105 | mHitGroupRS.resize(HitGroupParamID::numParams); 106 | mHitGroupRS[HitGroupParamID::constantsForObject] 107 | = new RootConstants("b1"); // Every local root signature's parameter is bound to its values via shader table. 108 | mHitGroupRS.build(D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE); 109 | } 110 | 111 | void DXRPathTracer::buildRaytracingPipeline() 112 | { 113 | dxrLib.load(L"DXRShader.cso"); 114 | 115 | mRtPipeline.setDXRLib(&dxrLib); 116 | mRtPipeline.setGlobalRootSignature(&mGlobalRS); 117 | mRtPipeline.addHitGroup(HitGroup(L"hitGp", L"closestHit", nullptr)); 118 | mRtPipeline.addHitGroup(HitGroup(L"hitGpGlass", L"closestHitGlass", nullptr)); 119 | mRtPipeline.addLocalRootSignature(LocalRootSignature(&mHitGroupRS, { L"hitGp", L"hitGpGlass" })); 120 | mRtPipeline.setMaxPayloadSize(sizeof(float) * 16); 121 | mRtPipeline.setMaxRayDepth(2); 122 | mRtPipeline.build(); 123 | } 124 | 125 | void DXRPathTracer::initializeApplication() 126 | { 127 | camera.setFovY(60.0f); 128 | camera.setScreenSize((float) tracerOutW, (float) tracerOutH); 129 | camera.initOrbit(float3(0.0f, 1.5f, 0.0f), 10.0f, 0.0f, 0.0f); 130 | 131 | mGlobalConstants.rayTmin = 0.001f; // 1mm 132 | mGlobalConstants.accumulatedFrames = 0; 133 | mGlobalConstants.numSamplesPerFrame = 32; 134 | mGlobalConstants.maxPathLength = 6; 135 | mGlobalConstants.backgroundLight = float3(.0f); 136 | 137 | mGlobalConstantsBuffer.create(sizeof(GloabalContants)); 138 | * (RootPointer*) mGlobalRS[RootParamID::pointerForGlobalConstants] 139 | = mGlobalConstantsBuffer.getGpuAddress(); 140 | 141 | uint64 maxBufferSize = _bpp(tracerOutFormat) * 1920 *1080; 142 | mReadBackBuffer.create(maxBufferSize); 143 | 144 | uint64 bufferSize = _bpp(tracerOutFormat) * tracerOutW * tracerOutH; 145 | mTracerOutBuffer.create(bufferSize); 146 | 147 | D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; 148 | { 149 | uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; 150 | uavDesc.Format = tracerOutFormat; 151 | uavDesc.Buffer.NumElements = tracerOutW * tracerOutH; 152 | } 153 | mSrvUavHeap[DescriptorID::outUAV].assignUAV(mTracerOutBuffer, &uavDesc); 154 | } 155 | 156 | void DXRPathTracer::onSizeChanged(uint width, uint height) 157 | { 158 | if (width == tracerOutW && height == tracerOutH) 159 | return; 160 | 161 | width = width ? width : 1; 162 | height = height ? height : 1; 163 | 164 | tracerOutW = width; 165 | tracerOutH = height; 166 | 167 | camera.setScreenSize((float) tracerOutW, (float) tracerOutH); 168 | 169 | UINT64 bufferSize = _bpp(tracerOutFormat) * tracerOutW * tracerOutH; 170 | mTracerOutBuffer.destroy(); 171 | mTracerOutBuffer.create(bufferSize); 172 | 173 | D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; 174 | { 175 | uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; 176 | uavDesc.Format = tracerOutFormat; 177 | uavDesc.Buffer.NumElements = tracerOutW * tracerOutH; 178 | } 179 | mSrvUavHeap[DescriptorID::outUAV].assignUAV(mTracerOutBuffer, &uavDesc); 180 | } 181 | 182 | void DXRPathTracer::update(const InputEngine& input) 183 | { 184 | camera.update(input); 185 | 186 | if (camera.notifyChanged()) 187 | { 188 | mGlobalConstants.cameraPos = camera.getCameraPos(); 189 | mGlobalConstants.cameraX = camera.getCameraX(); 190 | mGlobalConstants.cameraY = camera.getCameraY(); 191 | mGlobalConstants.cameraZ = camera.getCameraZ(); 192 | mGlobalConstants.cameraAspect = camera.getCameraAspect(); 193 | mGlobalConstants.accumulatedFrames = 0; 194 | } 195 | else 196 | mGlobalConstants.accumulatedFrames++; 197 | 198 | 199 | * (GloabalContants*) mGlobalConstantsBuffer.map() = mGlobalConstants; 200 | } 201 | 202 | TracedResult DXRPathTracer::shootRays() 203 | { 204 | mReadBackBuffer.unmap(); 205 | 206 | mRtPipeline.bind(mCmdList); 207 | mSrvUavHeap.bind(mCmdList); 208 | mGlobalRS.bindCompute(mCmdList); 209 | 210 | D3D12_DISPATCH_RAYS_DESC desc = {}; 211 | { 212 | desc.Width = tracerOutW; 213 | desc.Height = tracerOutH; 214 | desc.Depth = 1; 215 | desc.RayGenerationShaderRecord = mShaderTable.getRecord(0); 216 | desc.MissShaderTable = mShaderTable.getSubTable(1, 2); 217 | desc.HitGroupTable = mShaderTable.getSubTable(3, scene->numObjects()); 218 | } 219 | mCmdList->DispatchRays(&desc); 220 | 221 | mReadBackBuffer.readback(mCmdList, mTracerOutBuffer); 222 | 223 | ThrowFailedHR(mCmdList->Close()); 224 | ID3D12CommandList* cmdLists[] = { mCmdList }; 225 | mCmdQueue->ExecuteCommandLists(1, cmdLists); 226 | mFence.waitCommandQueue(mCmdQueue); 227 | ThrowFailedHR(mCmdAllocator->Reset()); 228 | ThrowFailedHR(mCmdList->Reset(mCmdAllocator, nullptr)); 229 | 230 | TracedResult result; 231 | result.data = mReadBackBuffer.map(); 232 | result.width = tracerOutW; 233 | result.height = tracerOutH; 234 | result.pixelSize = _bpp(tracerOutFormat); 235 | 236 | return result; 237 | } 238 | 239 | void DXRPathTracer::setupScene(const Scene* scene) 240 | { 241 | uint numObjs = scene->numObjects(); 242 | 243 | const Array vtxArr = scene->getVertexArray(); 244 | const Array tdxArr = scene->getTridexArray(); 245 | const Array trmArr = scene->getTransformArray(); 246 | const Array cdfArr = scene->getCdfArray(); 247 | const Array mtlArr = scene->getMaterialArray(); 248 | 249 | assert(cdfArr.size() == 0 || cdfArr.size() == tdxArr.size()); 250 | 251 | uint64 vtxBuffSize = vtxArr.size() * sizeof(Vertex); 252 | uint64 tdxBuffSize = tdxArr.size() * sizeof(Tridex); 253 | uint64 trmBuffSize = trmArr.size() * sizeof(Transform); 254 | uint64 cdfBuffSize = cdfArr.size() * sizeof(float); 255 | uint64 mtlBuffSize = mtlArr.size() * sizeof(Material); 256 | uint64 objBuffSize = numObjs * sizeof(GPUSceneObject); 257 | 258 | UploadBuffer uploader(vtxBuffSize + tdxBuffSize + trmBuffSize + cdfBuffSize + mtlBuffSize + objBuffSize); 259 | uint64 uploaderOffset = 0; 260 | 261 | auto initBuffer = [&](DefaultBuffer& buff, uint64 buffSize, void* srcData) { 262 | if(buffSize == 0) 263 | return; 264 | buff.create(buffSize); 265 | memcpy((uint8*) uploader.map() + uploaderOffset, srcData, buffSize); 266 | buff.uploadData(mCmdList, uploader, uploaderOffset); 267 | uploaderOffset += buffSize; 268 | }; 269 | 270 | initBuffer(mVertexBuffer, vtxBuffSize, (void*) vtxArr.data()); 271 | initBuffer(mTridexBuffer, tdxBuffSize, (void*) tdxArr.data()); 272 | initBuffer(mTransformBuffer, trmBuffSize, (void*) trmArr.data()); 273 | initBuffer(mCdfBuffer, cdfBuffSize, (void*) cdfArr.data()); 274 | initBuffer(mMaterialBuffer, mtlBuffSize, (void*) mtlArr.data()); 275 | 276 | mSceneObjectBuffer.create(objBuffSize); 277 | GPUSceneObject* copyDst = (GPUSceneObject*) ((uint8*) uploader.map() + uploaderOffset); 278 | for (uint objIdx = 0; objIdx < numObjs; ++objIdx) 279 | { 280 | const SceneObject& obj = scene->getObject(objIdx); 281 | 282 | GPUSceneObject gpuObj = {}; 283 | gpuObj.vertexOffset = obj.vertexOffset; 284 | gpuObj.tridexOffset = obj.tridexOffset; 285 | gpuObj.numTridices = obj.numTridices; 286 | gpuObj.objectArea = obj.meshArea * obj.scale * obj.scale; 287 | gpuObj.twoSided = obj.twoSided; 288 | gpuObj.materialIdx = obj.materialIdx; 289 | gpuObj.backMaterialIdx = obj.backMaterialIdx; 290 | //gpuObj.material = obj.material; 291 | //gpuObj.emittance = obj.lightColor * obj.lightIntensity; 292 | gpuObj.modelMatrix = obj.modelMatrix; 293 | 294 | copyDst[objIdx] = gpuObj; 295 | } 296 | mSceneObjectBuffer.uploadData(mCmdList, uploader, uploaderOffset); 297 | 298 | ThrowFailedHR(mCmdList->Close()); 299 | ID3D12CommandList* cmdLists[] = { mCmdList }; 300 | mCmdQueue->ExecuteCommandLists(1, cmdLists); 301 | mFence.waitCommandQueue(mCmdQueue); 302 | ThrowFailedHR(mCmdAllocator->Reset()); 303 | ThrowFailedHR(mCmdList->Reset(mCmdAllocator, nullptr)); 304 | 305 | this->scene = const_cast(scene); 306 | 307 | D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; 308 | { 309 | srvDesc.Format = DXGI_FORMAT_UNKNOWN; 310 | srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; 311 | srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; 312 | srvDesc.Buffer.StructureByteStride = sizeof(GPUSceneObject); 313 | srvDesc.Buffer.NumElements = numObjs; 314 | } 315 | mSrvUavHeap[DescriptorID::sceneObjectBuff].assignSRV(mSceneObjectBuffer, &srvDesc); 316 | 317 | { 318 | srvDesc.Format = DXGI_FORMAT_UNKNOWN; 319 | srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; 320 | srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; 321 | srvDesc.Buffer.StructureByteStride = sizeof(Vertex); 322 | srvDesc.Buffer.NumElements = vtxArr.size(); 323 | } 324 | mSrvUavHeap[DescriptorID::vertexBuff].assignSRV(mVertexBuffer, &srvDesc); 325 | 326 | { 327 | srvDesc.Format = DXGI_FORMAT_R32G32B32_UINT; 328 | srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; 329 | srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; 330 | srvDesc.Buffer.StructureByteStride = 0; 331 | srvDesc.Buffer.NumElements = tdxArr.size(); 332 | } 333 | mSrvUavHeap[DescriptorID::tridexBuff].assignSRV(mTridexBuffer, &srvDesc); 334 | 335 | { 336 | srvDesc.Format = DXGI_FORMAT_UNKNOWN; 337 | srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; 338 | srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; 339 | srvDesc.Buffer.StructureByteStride = sizeof(Material); 340 | srvDesc.Buffer.NumElements = mtlArr.size(); 341 | } 342 | mSrvUavHeap[DescriptorID::materialBuff].assignSRV(mMaterialBuffer, &srvDesc); 343 | 344 | setupShaderTable(); 345 | 346 | buildAccelerationStructure(); 347 | 348 | * (RootPointer*) mGlobalRS[RootParamID::pointerForAccelerationStructure] 349 | = mAccelerationStructure.getGpuAddress(); 350 | } 351 | 352 | void DXRPathTracer::setupShaderTable() 353 | { 354 | ShaderIdentifier* rayGenID = mRtPipeline.getIdentifier(L"rayGen"); 355 | ShaderIdentifier* missRayID = mRtPipeline.getIdentifier(L"missRay"); 356 | ShaderIdentifier* missShadowID = mRtPipeline.getIdentifier(L"missShadow"); 357 | ShaderIdentifier* hitGpID = mRtPipeline.getIdentifier(L"hitGp"); 358 | ShaderIdentifier* hitGpGlassID = mRtPipeline.getIdentifier(L"hitGpGlass"); 359 | 360 | uint numObjs = scene->numObjects(); 361 | mShaderTable.create(recordSize, numObjs + 3); 362 | 363 | HitGroupRecord* table = (HitGroupRecord*) mShaderTable.map(); 364 | table[0].shaderIdentifier = *rayGenID; 365 | table[1].shaderIdentifier = *missRayID; 366 | table[2].shaderIdentifier = *missShadowID; 367 | 368 | auto& mtlArr = scene->getMaterialArray(); 369 | for (uint i = 0; i < numObjs; ++i) 370 | { 371 | if(mtlArr[ scene->getObject(i).materialIdx ].type == Glass) 372 | table[3 + i].shaderIdentifier = *hitGpGlassID; 373 | else 374 | table[3 + i].shaderIdentifier = *hitGpID; 375 | 376 | table[3 + i].objConsts.objectIdx = i; 377 | } 378 | 379 | mShaderTable.uploadData(mCmdList); 380 | } 381 | 382 | void DXRPathTracer::buildAccelerationStructure() 383 | { 384 | uint numObjs = scene->numObjects(); 385 | Array gpuMeshArr(numObjs); 386 | Array transformArr(numObjs); 387 | 388 | D3D12_GPU_VIRTUAL_ADDRESS vtxAddr = mVertexBuffer.getGpuAddress(); 389 | D3D12_GPU_VIRTUAL_ADDRESS tdxAddr = mTridexBuffer.getGpuAddress(); 390 | for (uint objIdx = 0; objIdx < numObjs; ++objIdx) 391 | { 392 | const SceneObject& obj = scene->getObject(objIdx); 393 | 394 | gpuMeshArr[objIdx].numVertices = obj.numVertices; 395 | gpuMeshArr[objIdx].vertexBufferVA = vtxAddr + obj.vertexOffset * sizeof(Vertex); 396 | gpuMeshArr[objIdx].numTridices = obj.numTridices; 397 | gpuMeshArr[objIdx].tridexBufferVA = tdxAddr + obj.tridexOffset * sizeof(Tridex); 398 | 399 | transformArr[objIdx] = obj.modelMatrix; 400 | } 401 | 402 | mAccelerationStructure.build(mCmdList, gpuMeshArr, transformArr, 403 | sizeof(Vertex), 1, buildMode, buildFlags); 404 | 405 | ThrowFailedHR(mCmdList->Close()); 406 | ID3D12CommandList* cmdLists[] = { mCmdList }; 407 | mCmdQueue->ExecuteCommandLists(1, cmdLists); 408 | mFence.waitCommandQueue(mCmdQueue); 409 | ThrowFailedHR(mCmdAllocator->Reset()); 410 | ThrowFailedHR(mCmdList->Reset(mCmdAllocator, nullptr)); 411 | 412 | //mAccelerationStructure.flush(); 413 | } 414 | -------------------------------------------------------------------------------- /DXRPathTracer/DXRPathTracer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "IGRTTracer.h" 3 | #include "dxHelpers.h" 4 | #include "Camera.h" 5 | #define NextAlignedLine __declspec(align(16)) 6 | 7 | 8 | // This structure will be bind to dxr shader directly via [global] root signature. 9 | struct GloabalContants 10 | { 11 | NextAlignedLine 12 | float3 backgroundLight; 13 | NextAlignedLine 14 | float3 cameraPos; 15 | NextAlignedLine 16 | float3 cameraX; 17 | NextAlignedLine 18 | float3 cameraY; 19 | NextAlignedLine 20 | float3 cameraZ; 21 | NextAlignedLine 22 | float2 cameraAspect; 23 | float rayTmin = 1e-4f; 24 | float rayTmax = 1e27f; 25 | NextAlignedLine 26 | uint accumulatedFrames; 27 | uint numSamplesPerFrame; 28 | uint maxPathLength; 29 | }; 30 | 31 | 32 | // This structure will be bind to dxr shader directly via [local] root signature. 33 | struct ObjectContants 34 | { 35 | uint objectIdx; 36 | }; 37 | 38 | static const uint xxx = sizeof(GloabalContants); 39 | static const uint identifierSize = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; 40 | static const uint hitGroupRecordSize = _align( 41 | identifierSize + (uint) sizeof(ObjectContants), D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT); 42 | 43 | 44 | union HitGroupRecord 45 | { 46 | struct { 47 | ShaderIdentifier shaderIdentifier; 48 | ObjectContants objConsts; 49 | }; 50 | private: 51 | char pad[hitGroupRecordSize]; 52 | }; 53 | 54 | 55 | class Scene; 56 | class InputEngine; 57 | class DXRPathTracer : public IGRTTracer 58 | { 59 | static const DXGI_FORMAT tracerOutFormat = DXGI_FORMAT_R32G32B32A32_FLOAT; 60 | static const uint recordSize = hitGroupRecordSize; 61 | 62 | ID3D12Device5* mDevice; 63 | ID3D12CommandQueue* mCmdQueue; 64 | ID3D12GraphicsCommandList4* mCmdList; 65 | ID3D12CommandAllocator* mCmdAllocator; 66 | BinaryFence mFence; 67 | void initD3D12(); 68 | 69 | DescriptorHeap mSrvUavHeap; 70 | 71 | RootSignature mGlobalRS; 72 | RootSignature mHitGroupRS; 73 | void declareRootSignatures(); 74 | 75 | dxShader dxrLib; 76 | RaytracingPipeline mRtPipeline; 77 | void buildRaytracingPipeline(); 78 | 79 | GloabalContants mGlobalConstants; 80 | UploadBuffer mGlobalConstantsBuffer; 81 | UnorderAccessBuffer mTracerOutBuffer; 82 | ReadbackBuffer mReadBackBuffer; 83 | void initializeApplication(); 84 | //------Until here, scene independent members-------------------------// 85 | 86 | OrbitCamera camera; 87 | 88 | //------From now, scene dependent members-----------------------------// 89 | DefaultBuffer mSceneObjectBuffer; 90 | DefaultBuffer mVertexBuffer; 91 | DefaultBuffer mTridexBuffer; 92 | DefaultBuffer mCdfBuffer; // Now not use. 93 | DefaultBuffer mTransformBuffer; // Now not use. 94 | DefaultBuffer mMaterialBuffer; // Now not use. 95 | 96 | ShaderTable mShaderTable; 97 | void setupShaderTable(); 98 | 99 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS buildFlags = 100 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_NONE; 101 | //D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE; 102 | AccelerationStructureBuildMode buildMode = 103 | //ONLY_ONE_BLAS; 104 | //BLAS_PER_OBJECT_AND_BOTTOM_LEVEL_TRANSFORM; 105 | BLAS_PER_OBJECT_AND_TOP_LEVEL_TRANSFORM; 106 | dxAccelerationStructure mAccelerationStructure; 107 | void buildAccelerationStructure(); 108 | //void buildAccelerationStructure1(); 109 | 110 | public: 111 | ~DXRPathTracer(); 112 | DXRPathTracer(uint width, uint height); 113 | virtual void onSizeChanged(uint width, uint height); 114 | virtual void update(const InputEngine& input); 115 | virtual TracedResult shootRays(); 116 | virtual void setupScene(const Scene* scene); 117 | }; 118 | -------------------------------------------------------------------------------- /DXRPathTracer/DXRPathTracer.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 | 15.0 23 | {5E5F5505-83D3-4DC8-9232-FA5DBA34C383} 24 | DXRPathTracer 25 | 10.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v143 32 | MultiByte 33 | 34 | 35 | Application 36 | false 37 | v143 38 | true 39 | MultiByte 40 | 41 | 42 | Application 43 | true 44 | v143 45 | MultiByte 46 | 47 | 48 | Application 49 | false 50 | v143 51 | true 52 | MultiByte 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | Disabled 77 | true 78 | true 79 | 80 | 81 | 82 | 83 | Level3 84 | Disabled 85 | true 86 | false 87 | _CRT_SECURE_NO_WARNINGS;_MBCS;%(PreprocessorDefinitions) 88 | Use 89 | pch.h 90 | false 91 | 92 | 93 | 94 | 95 | Level3 96 | MaxSpeed 97 | true 98 | true 99 | true 100 | true 101 | 102 | 103 | true 104 | true 105 | 106 | 107 | 108 | 109 | Level3 110 | MaxSpeed 111 | true 112 | true 113 | true 114 | false 115 | _CRT_SECURE_NO_WARNINGS;_MBCS;%(PreprocessorDefinitions) 116 | Use 117 | pch.h 118 | false 119 | 120 | 121 | true 122 | true 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | Create 157 | Create 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | true 167 | true 168 | 169 | 170 | Library 171 | 6.3 172 | Library 173 | 6.3 174 | $(ProjectDir)bin\cso\%(Filename).cso 175 | $(ProjectDir)bin\cso\%(Filename).cso 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /DXRPathTracer/DXRPathTracer.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 | {a0887646-622d-4c9c-9342-aa74b3e40ca0} 14 | 15 | 16 | {02d25e94-3b50-4ffe-b5f7-b18c26730757} 17 | 18 | 19 | {f9eff60c-4037-4cc5-bb69-85e7528b57cf} 20 | 21 | 22 | {91a5f396-30ce-4a8d-867d-b15cbe75c575} 23 | 24 | 25 | {61f64b26-cb34-4bed-85c6-62ce0ab15855} 26 | 27 | 28 | {bf5a7f8c-7b0f-45c6-aaae-8a2a592f1211} 29 | 30 | 31 | {66181d2e-2e7b-4a1f-b04e-4ca738dc5138} 32 | 33 | 34 | 35 | 36 | 소스 파일\UTIL 37 | 38 | 39 | 소스 파일\UTIL 40 | 41 | 42 | 소스 파일\UTIL 43 | 44 | 45 | 소스 파일\UTIL 46 | 47 | 48 | 소스 파일\UTIL 49 | 50 | 51 | 소스 파일\UTIL 52 | 53 | 54 | 소스 파일\UTIL 55 | 56 | 57 | 소스 파일\UTIL 58 | 59 | 60 | 소스 파일\DXRPathTracer 61 | 62 | 63 | 소스 파일\D3D12Screen 64 | 65 | 66 | 소스 파일\IGRT Framework 67 | 68 | 69 | 소스 파일\IGRT Framework 70 | 71 | 72 | 소스 파일\IGRT Framework 73 | 74 | 75 | 소스 파일\IGRT Framework 76 | 77 | 78 | 소스 파일\IGRT Framework 79 | 80 | 81 | 소스 파일\IGRT Framework 82 | 83 | 84 | 소스 파일\IGRT Framework\Mesh 85 | 86 | 87 | 소스 파일\IGRT Framework\Mesh 88 | 89 | 90 | 소스 파일\IGRT Framework\Mesh 91 | 92 | 93 | 소스 파일\IGRT Framework 94 | 95 | 96 | 97 | 98 | 소스 파일\UTIL 99 | 100 | 101 | 소스 파일\UTIL 102 | 103 | 104 | 소스 파일\DXRPathTracer 105 | 106 | 107 | 소스 파일\DXRPathTracer 108 | 109 | 110 | 소스 파일\D3D12Screen 111 | 112 | 113 | 소스 파일\IGRT Framework 114 | 115 | 116 | 소스 파일\IGRT Framework\Mesh 117 | 118 | 119 | 소스 파일\IGRT Framework\Mesh 120 | 121 | 122 | 소스 파일\IGRT Framework 123 | 124 | 125 | 126 | 127 | 소스 파일\DXRPathTracer\HLSL 128 | 129 | 130 | 131 | 132 | 소스 파일\DXRPathTracer\HLSL 133 | 134 | 135 | 소스 파일\D3D12Screen\HLSL 136 | 137 | 138 | -------------------------------------------------------------------------------- /DXRPathTracer/DXRPathTracer.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /DXRPathTracer/DXRShader.hlsl: -------------------------------------------------------------------------------- 1 | //#pragma pack_matrix( row_major ) // It does not work! 2 | #include "sampling.hlsli" 3 | 4 | RaytracingAccelerationStructure scene : register(t0, space100); 5 | RWBuffer tracerOutBuffer : register(u0); 6 | 7 | struct Vertex 8 | { 9 | float3 position; 10 | float3 normal; 11 | float2 texcoord; 12 | }; 13 | 14 | static const int Lambertian = 0; 15 | static const int Metal = 1; 16 | static const int Plastic = 2; 17 | static const int Glass = 3; 18 | struct Material 19 | { 20 | float3 emittance; 21 | uint type; 22 | float3 albedo; 23 | float roughness; 24 | float reflectivity; 25 | float transmittivity; 26 | }; 27 | 28 | struct GPUSceneObject 29 | { 30 | uint vertexOffset; 31 | uint tridexOffset; 32 | uint numTridices; 33 | float objectArea; 34 | uint twoSided; 35 | uint materialIdx; 36 | uint backMaterialIdx; 37 | //Material material; 38 | //float3 emittance; 39 | row_major float4x4 modelMatrix; 40 | }; 41 | StructuredBuffer objectBuffer : register(t0); 42 | StructuredBuffer vertexBuffer : register(t1); 43 | Buffer tridexBuffer : register(t2); //ByteAddressBuffer IndexBuffer : register(t2); 44 | StructuredBuffer materialBuffer : register(t3); 45 | 46 | 47 | cbuffer GLOBAL_CONSTANTS : register(b0) 48 | { 49 | float3 backgroundLight; 50 | float3 cameraPos; 51 | float3 cameraX; 52 | float3 cameraY; 53 | float3 cameraZ; 54 | float2 cameraAspect; 55 | float rayTmin; 56 | float rayTmax; 57 | uint accumulatedFrames; 58 | uint numSamplesPerFrame; 59 | uint maxPathLength; 60 | } 61 | 62 | cbuffer OBJECT_CONSTANTS : register(b1) 63 | { 64 | uint objIdx; 65 | }; 66 | 67 | struct RayPayload 68 | { 69 | float3 radiance; 70 | float3 attenuation; 71 | float3 hitPos; 72 | float3 bounceDir; 73 | //uint terminateRay; 74 | uint rayDepth; 75 | uint seed; 76 | }; 77 | 78 | struct ShadowPayload 79 | { 80 | uint occluded; 81 | }; 82 | 83 | RayDesc Ray(in float3 origin, in float3 direction, in float tMin, in float tMax) 84 | { 85 | RayDesc ray; 86 | ray.Origin = origin; 87 | ray.Direction = direction; 88 | ray.TMin = tMin; 89 | ray.TMax = tMax; 90 | return ray; 91 | } 92 | 93 | void computeNormal(out float3 normal, out float3 faceNormal, in BuiltInTriangleIntersectionAttributes attr) 94 | { 95 | GPUSceneObject obj = objectBuffer[objIdx]; 96 | 97 | uint3 tridex = tridexBuffer[obj.tridexOffset + PrimitiveIndex()]; 98 | Vertex vtx0 = vertexBuffer[obj.vertexOffset + tridex.x]; 99 | Vertex vtx1 = vertexBuffer[obj.vertexOffset + tridex.y]; 100 | Vertex vtx2 = vertexBuffer[obj.vertexOffset + tridex.z]; 101 | 102 | float t0 = 1.0f - attr.barycentrics.x - attr.barycentrics.y; 103 | float t1 = attr.barycentrics.x; 104 | float t2 = attr.barycentrics.y; 105 | 106 | float3x3 transform = (float3x3) obj.modelMatrix; 107 | 108 | faceNormal = normalize( mul(transform, 109 | cross(vtx1.position - vtx0.position, vtx2.position - vtx0.position) 110 | ) ); 111 | normal = normalize( mul(transform, 112 | t0 * vtx0.normal + t1 * vtx1.normal + t2 * vtx2.normal 113 | ) ); 114 | } 115 | 116 | void computeNormal(out float3 normal, in BuiltInTriangleIntersectionAttributes attr) 117 | { 118 | GPUSceneObject obj = objectBuffer[objIdx]; 119 | 120 | uint3 tridex = tridexBuffer[obj.tridexOffset + PrimitiveIndex()]; 121 | Vertex vtx0 = vertexBuffer[obj.vertexOffset + tridex.x]; 122 | Vertex vtx1 = vertexBuffer[obj.vertexOffset + tridex.y]; 123 | Vertex vtx2 = vertexBuffer[obj.vertexOffset + tridex.z]; 124 | 125 | float t0 = 1.0f - attr.barycentrics.x - attr.barycentrics.y; 126 | float t1 = attr.barycentrics.x; 127 | float t2 = attr.barycentrics.y; 128 | 129 | float3x3 transform = (float3x3) obj.modelMatrix; 130 | 131 | normal = normalize( mul(transform, 132 | t0 * vtx0.normal + t1 * vtx1.normal + t2 * vtx2.normal 133 | ) ); 134 | } 135 | 136 | float3 tracePath(in float3 startPos, in float3 startDir, inout uint seed) 137 | { 138 | float3 radiance = 0.0f; 139 | float3 attenuation = 1.0f; 140 | 141 | RayDesc ray = Ray(startPos, startDir, rayTmin, rayTmax); 142 | RayPayload prd; 143 | prd.seed = seed; 144 | prd.rayDepth = 0; 145 | //prd.terminateRay = false; 146 | 147 | while(prd.rayDepth < maxPathLength) 148 | { 149 | TraceRay(scene, 0, ~0, 0, 1, 0, ray, prd); 150 | 151 | radiance += attenuation * prd.radiance; 152 | attenuation *= prd.attenuation; 153 | 154 | /*if(prd.terminateRay) 155 | break;*/ 156 | 157 | ray.Origin = prd.hitPos; 158 | ray.Direction = prd.bounceDir; 159 | ++prd.rayDepth; 160 | } 161 | 162 | seed = prd.seed; 163 | 164 | return radiance; 165 | } 166 | 167 | [shader("raygeneration")] 168 | void rayGen() 169 | { 170 | uint2 launchIdx = DispatchRaysIndex().xy; 171 | uint2 launchDim = DispatchRaysDimensions().xy; 172 | uint bufferOffset = launchDim.x * launchIdx.y + launchIdx.x; 173 | 174 | uint seed = getNewSeed(bufferOffset, accumulatedFrames, 8); 175 | 176 | float3 newRadiance = 0.0f; 177 | for (uint i = 0; i < numSamplesPerFrame; ++i) 178 | { 179 | float2 screenCoord = float2(launchIdx) + float2(rnd(seed), rnd(seed)); 180 | float2 ndc = screenCoord / float2(launchDim) * 2.f - 1.f; 181 | float3 rayDir = normalize(ndc.x*cameraAspect.x*cameraX + ndc.y*cameraAspect.y*cameraY + cameraZ); 182 | 183 | newRadiance += tracePath(cameraPos, rayDir, seed); 184 | } 185 | newRadiance *= 1.0f / float(numSamplesPerFrame); 186 | 187 | float3 avrRadiance; 188 | if(accumulatedFrames == 0) 189 | avrRadiance = newRadiance; 190 | else 191 | avrRadiance = lerp( tracerOutBuffer[bufferOffset].xyz, newRadiance, 1.f / (accumulatedFrames + 1.0f) ); 192 | 193 | tracerOutBuffer[bufferOffset] = float4(avrRadiance, 1.0f); 194 | } 195 | 196 | void samplingBRDF(out float3 sampleDir, out float sampleProb, out float3 brdfCos, 197 | in float3 surfaceNormal, in float3 baseDir, in uint materialIdx, inout uint seed) 198 | { 199 | Material mtl = materialBuffer[materialIdx]; 200 | 201 | float3 brdfEval; 202 | float3 albedo = mtl.albedo; 203 | uint reflectType = mtl.type; 204 | 205 | float3 I, O = baseDir, N = surfaceNormal, H; 206 | float ON = dot(O, N), IN, HN, OH; 207 | float alpha2 = mtl.roughness * mtl.roughness; 208 | 209 | if (reflectType == Lambertian) 210 | { 211 | I = sample_hemisphere_cos(seed); 212 | IN = I.z; 213 | I = applyRotationMappingZToN(N, I); 214 | 215 | sampleProb = InvPi * IN; 216 | brdfEval = InvPi * albedo; 217 | } 218 | 219 | else if (reflectType == Metal) 220 | { 221 | H = sample_hemisphere_TrowbridgeReitzCos(alpha2, seed); 222 | HN = H.z; 223 | H = applyRotationMappingZToN(N, H); 224 | OH = dot(O, H); 225 | 226 | I = 2 * OH * H - O; 227 | IN = dot(I, N); 228 | 229 | if (IN < 0) 230 | { 231 | brdfEval = 0; 232 | sampleProb = 0; // sampleProb = D*HN / (4*abs(OH)); if allowing sample negative hemisphere 233 | } 234 | else 235 | { 236 | float D = TrowbridgeReitz(HN*HN, alpha2); 237 | float G = Smith_TrowbridgeReitz(I, O, H, N, alpha2); 238 | float3 F = albedo + (1 - albedo) * pow(max(0, 1-OH), 5); 239 | brdfEval = ((D * G) / (4 * IN * ON)) * F; 240 | sampleProb = D*HN / (4*OH); // IN > 0 imply OH > 0 241 | } 242 | } 243 | 244 | else if (reflectType == Plastic) 245 | { 246 | float r = mtl.reflectivity; 247 | 248 | if (rnd(seed) < r) 249 | { 250 | H = sample_hemisphere_TrowbridgeReitzCos(alpha2, seed); 251 | HN = H.z; 252 | H = applyRotationMappingZToN(N, H); 253 | OH = dot(O, H); 254 | 255 | I = 2 * OH * H - O; 256 | IN = dot(I, N); 257 | } 258 | else 259 | { 260 | I = sample_hemisphere_cos(seed); 261 | IN = I.z; 262 | I = applyRotationMappingZToN(N, I); 263 | 264 | H = O + I; 265 | H = (1/length(H)) * H; 266 | HN = dot(H, N); 267 | OH = dot(O, H); 268 | } 269 | 270 | if (IN < 0) 271 | { 272 | brdfEval = 0; 273 | sampleProb = 0; //sampleProb = r * (D*HN / (4*abs(OH))); if allowing sample negative hemisphere 274 | } 275 | else 276 | { 277 | float D = TrowbridgeReitz(HN*HN, alpha2); 278 | float G = Smith_TrowbridgeReitz(I, O, H, N, alpha2); 279 | float3 spec = ((D * G) / (4 * IN * ON)); 280 | brdfEval = r * spec + (1 - r) * InvPi * albedo; 281 | sampleProb = r * (D*HN / (4*OH)) + (1 - r) * (InvPi * IN); 282 | } 283 | } 284 | 285 | sampleDir = I; 286 | brdfCos = brdfEval * IN; 287 | } 288 | 289 | /* 290 | 1. Closed manifold assumption(except for emitting source): we can only consider the shading normal N, 291 | i.e ignoring the face nomal fN since dot(E, fN)<0 never occur. 292 | 2. The hit point should be considerd as being transparent in case dot(E, N)<0, but not yet implemented. 293 | 3. In case dot(R, fN)<0, where R is sampled reflected ray, we do not terminate ray, 294 | but do terminate when dot(R, N)<0 in which it force monte calro estimation to zero. 295 | 4. Note that in case 2 and 3 above, the next closest hit point might be in dot(E, fN)<0 && dot(E, N)>0, 296 | but this is rare so we ignore the codition dot(E, fN)<0 and only check dot(E, N)<0. 297 | 5. In results, we do not need the face nomal fN which take a little time to compute. 298 | */ 299 | [shader("closesthit")] 300 | void closestHit(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attr) 301 | { 302 | GPUSceneObject obj = objectBuffer[objIdx]; 303 | 304 | float3 N, fN, E = - WorldRayDirection(); 305 | computeNormal(N, fN, attr); 306 | float EN = dot(E, N), EfN = dot(E, fN); 307 | 308 | payload.radiance = 0.0f; 309 | payload.attenuation = 1.0f; 310 | payload.hitPos = WorldRayOrigin() - RayTCurrent() * E; 311 | 312 | uint mtlIdx = obj.materialIdx; 313 | 314 | if (obj.twoSided && EfN < 0) 315 | { 316 | mtlIdx = obj.backMaterialIdx; 317 | N = -N; 318 | EN = -EN; 319 | } 320 | 321 | if(EN < 0) 322 | { 323 | payload.bounceDir = WorldRayDirection(); 324 | --payload.rayDepth; 325 | return; 326 | } 327 | 328 | Material mtl = materialBuffer[mtlIdx]; 329 | 330 | if (any(mtl.emittance)) 331 | { 332 | payload.radiance += mtl.emittance; 333 | } 334 | 335 | float3 sampleDir, brdfCos; 336 | float sampleProb; 337 | samplingBRDF(sampleDir, sampleProb, brdfCos, N, E, mtlIdx, payload.seed); 338 | 339 | if(dot(sampleDir, N) <= 0) 340 | payload.rayDepth = maxPathLength; 341 | //payload.terminateRay = dot(sampleDir, N) <= 0.0f 342 | payload.attenuation = brdfCos / sampleProb; 343 | payload.bounceDir = sampleDir; 344 | } 345 | 346 | [shader("closesthit")] 347 | void closestHitGlass(inout RayPayload payload, in BuiltInTriangleIntersectionAttributes attr) 348 | { 349 | GPUSceneObject obj = objectBuffer[objIdx]; 350 | 351 | float3 N, fN, E = - WorldRayDirection(); 352 | computeNormal(N, fN, attr); 353 | float EN = dot(E, N), EfN = dot(E, fN); 354 | 355 | payload.radiance = 0.0f; 356 | payload.attenuation = 1.0f; 357 | payload.hitPos = WorldRayOrigin() - RayTCurrent() * E; 358 | 359 | if(EN * EfN < 0) 360 | { 361 | payload.bounceDir = WorldRayDirection(); 362 | --payload.rayDepth; 363 | return; 364 | } 365 | 366 | Material mtl = materialBuffer[obj.materialIdx]; 367 | 368 | if (any(mtl.emittance) && EN > 0) 369 | { 370 | payload.radiance += mtl.emittance; 371 | } 372 | 373 | float3 sampleDir; 374 | float sampleProb, Fresnel; 375 | 376 | float T0 = mtl.transmittivity; 377 | float n = sqrt(1 - T0); 378 | n = (1+n) / (1-n); // n <- refractive index of glass 379 | 380 | float R, g, x, y; 381 | float c1, gg; 382 | 383 | if (EN > 0) 384 | { 385 | n = 1 / n; // n <- relative index of air-to-glass (n_air/n_glass) 386 | c1 = EN; 387 | } 388 | else 389 | { 390 | n = n; // n <- relative index of glass-to-air (n_glass/n_air) 391 | c1 = -EN; 392 | } 393 | 394 | gg = 1/(n*n) - 1 + c1*c1; // gg == (c2/n)^2 395 | if (gg < 0) 396 | { 397 | R = 1; 398 | } 399 | else 400 | { 401 | g = sqrt(gg); 402 | x = (c1*(g + c1) - 1) / (c1*(g - c1) + 1); 403 | y = (g - c1) / (g + c1); 404 | R = 0.5 * y*y * (1 + x * x); 405 | } 406 | 407 | //if (rnd(payload.seed) < 0.5) 408 | if (rnd(payload.seed) < R) 409 | { 410 | sampleProb = R; 411 | Fresnel = R; 412 | sampleDir = 2 * EN * N - E; 413 | } 414 | else 415 | { 416 | sampleProb = 1 - R; 417 | Fresnel = 1 - R; 418 | 419 | if (gg < 0) 420 | { 421 | payload.rayDepth = maxPathLength; 422 | } 423 | else 424 | { 425 | //if (EN > 0) // Additional bounce only for the case of air-to-glass transmission 426 | // --payload.rayDepth; 427 | float ON = -sign(EN) * n * g; 428 | sampleDir = (ON + n * EN)*N - n * E; 429 | } 430 | } 431 | 432 | if (EN > 0) // Additional bounce for the case of air-to-glass. 433 | --payload.rayDepth; 434 | 435 | //sampleProb = 0.5; 436 | payload.attenuation = Fresnel / sampleProb; 437 | payload.bounceDir = sampleDir; 438 | } 439 | 440 | 441 | [shader("miss")] 442 | void missRay(inout RayPayload payload) 443 | { 444 | //payload.radiance = 0.1; 445 | payload.radiance = backgroundLight; 446 | payload.rayDepth = maxPathLength; 447 | } 448 | 449 | [shader("miss")] 450 | void missShadow(inout ShadowPayload payload) 451 | { 452 | payload.occluded = false; 453 | } 454 | -------------------------------------------------------------------------------- /DXRPathTracer/Error.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | inline void printError(const char* errorMessage) 5 | { 6 | if(errorMessage) 7 | puts(errorMessage); 8 | } 9 | 10 | class Error 11 | { 12 | public: 13 | Error() {} 14 | Error(const char* errorMessage) 15 | { 16 | printError(errorMessage); 17 | } 18 | }; 19 | 20 | #define DECLARE_ERROR(error_class) \ 21 | class error_class : public Error \ 22 | {\ 23 | public:\ 24 | error_class() {} \ 25 | error_class(const char* message) : Error(message) {}\ 26 | }; 27 | 28 | -------------------------------------------------------------------------------- /DXRPathTracer/IGRTCommon.h: -------------------------------------------------------------------------------- 1 | /* 2 | At the very beginning, this Integrated GPU Ray Tracing (IGRT) framework has been designed to support many GPU 3 | raytracing libraries(DirectX Raytracing, VulKan Raytracing, nVidia OptiX), and it consists of two stages. 4 | Firstly, Ray tracing stage which shoots several rays per each pixel to render a HDR image, and secondly 5 | the hdr image displays on an output window using any kinds of graphic libraries(DX12, DX11, OpenGL, Vulkan and etc) 6 | irregardless of the choice for the raytracing library. 7 | For example, 8 | [DXRPathTracer] [OpenGLScreen] 9 | [IGRTTracer] <-------- [VulkanPathTracer] =============> [VulkanScreen] --------> [IGRTScreen] 10 | (inherit) [OptiXPathTracer] (TracedResult) [D3D12Screen] (inherit) 11 | 12 | */ 13 | 14 | #pragma once 15 | #include "pch.h" 16 | 17 | 18 | struct TracedResult 19 | { 20 | void* data; 21 | uint width; 22 | uint height; 23 | uint pixelSize; 24 | }; -------------------------------------------------------------------------------- /DXRPathTracer/IGRTScreen.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "IGRTCommon.h" 3 | 4 | 5 | class IGRTScreen 6 | { 7 | protected: 8 | HWND targetWindow; 9 | uint screenW; 10 | uint screenH; 11 | 12 | uint tracerOutW; 13 | uint tracerOutH; 14 | 15 | public: 16 | IGRTScreen(HWND hwnd, uint w, uint h) : targetWindow(hwnd), screenW(w), screenH(h) {} 17 | virtual void onSizeChanged(uint width, uint height) = 0; 18 | virtual void display(const TracedResult& trResult) = 0; 19 | }; -------------------------------------------------------------------------------- /DXRPathTracer/IGRTTracer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "IGRTCommon.h" 3 | 4 | 5 | class Scene; 6 | class InputEngine; 7 | class IGRTTracer 8 | { 9 | protected: 10 | uint tracerOutW; 11 | uint tracerOutH; 12 | 13 | Scene* scene; 14 | 15 | public: 16 | IGRTTracer(uint w, uint h) : tracerOutW(w), tracerOutH(h) {} 17 | virtual void onSizeChanged(uint width, uint height) = 0; 18 | virtual void update(const InputEngine& input) = 0; 19 | virtual TracedResult shootRays() = 0; 20 | virtual void setupScene(const Scene* scene) = 0; 21 | }; -------------------------------------------------------------------------------- /DXRPathTracer/Input.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | 4 | 5 | enum MouseButton 6 | { 7 | LButton = 0, MButton = 1, RButton = 2, numButtons = 3 8 | }; 9 | 10 | class InputEngine 11 | { 12 | const HWND hwnd; 13 | 14 | int2 mousePos; 15 | int2 mousePosPrev; 16 | bool mousePressed[numButtons]; 17 | bool mousePressedPrev[numButtons]; 18 | int2 mouseLastClickedPos[numButtons]; 19 | 20 | public: 21 | InputEngine(const HWND hwnd) : hwnd(hwnd) { 22 | mousePosPrev = mousePos = int2(0.0f, 0.0f); 23 | for (uint i = 0; i < numButtons; ++i) { 24 | mousePressedPrev[i] = mousePressed[i] = false; 25 | mouseLastClickedPos[i] = int2(0.0f, 0.0f); 26 | } 27 | } 28 | 29 | int2 getMousePos() const { 30 | return mousePos; 31 | } 32 | 33 | bool getMousePressed(MouseButton btn) const { 34 | return mousePressed[btn]; 35 | } 36 | 37 | bool getMouseJustPressed(MouseButton btn) const { 38 | return !mousePressedPrev[btn] && mousePressed[btn]; 39 | } 40 | 41 | bool getMouseJustReleased(MouseButton btn) const { 42 | return mousePressedPrev[btn] && !mousePressed[btn]; 43 | } 44 | 45 | int2 getMouseDragged(MouseButton btn) const { 46 | if(mousePressedPrev[btn] && mousePressed[btn]) 47 | return mousePos - mousePosPrev; 48 | else 49 | return int2(0, 0); 50 | } 51 | 52 | int2 getMouseDraggedSum(MouseButton btn) const { 53 | if(mousePressed[btn]) 54 | return mousePos - mouseLastClickedPos[btn]; 55 | else 56 | return int2(0, 0); 57 | } 58 | 59 | void mouseUpdate() { 60 | mousePressedPrev[LButton] = mousePressed[LButton]; 61 | mousePressedPrev[MButton] = mousePressed[MButton]; 62 | mousePressedPrev[RButton] = mousePressed[RButton]; 63 | mousePosPrev = mousePos; 64 | 65 | if(GetForegroundWindow() != hwnd) 66 | return; 67 | 68 | POINT pos; 69 | GetCursorPos(&pos); 70 | ScreenToClient(hwnd, &pos); 71 | mousePos = int2(pos.x, pos.y); 72 | 73 | mousePressed[LButton] = (GetAsyncKeyState(VK_LBUTTON) & 0x8000) > 0; 74 | mousePressed[MButton] = (GetAsyncKeyState(VK_MBUTTON) & 0x8000) > 0; 75 | mousePressed[RButton] = (GetAsyncKeyState(VK_RBUTTON) & 0x8000) > 0; 76 | 77 | if(getMouseJustPressed(LButton)) 78 | mouseLastClickedPos[LButton] = mousePos; 79 | if(getMouseJustPressed(MButton)) 80 | mouseLastClickedPos[MButton] = mousePos; 81 | if(getMouseJustPressed(RButton)) 82 | mouseLastClickedPos[RButton] = mousePos; 83 | } 84 | 85 | void update() { 86 | mouseUpdate(); 87 | } 88 | }; 89 | -------------------------------------------------------------------------------- /DXRPathTracer/Material.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "basic_types.h" 3 | 4 | 5 | static const int Lambertian = 0; 6 | static const int Metal = 1; 7 | static const int Plastic = 2; 8 | static const int Glass = 3; 9 | static const int Plastic1 = 201; 10 | static const int Plastic2 = 202; 11 | static const int Plastic3 = 203; 12 | 13 | struct Material 14 | { 15 | float3 emittance = float3(0.0f); 16 | uint type = Lambertian; 17 | float3 albedo = float3(0.1f); 18 | float roughness = 0.01f; 19 | float reflectivity = 0.1f; 20 | float transmittivity = 0.96f; // transmittivity of glass at normal incidence 21 | }; 22 | -------------------------------------------------------------------------------- /DXRPathTracer/Mesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Array.h" 3 | #include "basic_types.h" 4 | 5 | 6 | struct Vertex 7 | { 8 | float3 position; 9 | float3 normal; 10 | float2 texcoord; 11 | }; 12 | 13 | typedef uint3 Tridex; 14 | 15 | /* 16 | We define the word 'tridex' for clarity. It means triple indices for a triangle w.r.t some vetex buffer. 17 | For example, the following structure could be defined. 18 | 19 | struct Triangle 20 | { 21 | uint3 tridex; 22 | float3 normal; 23 | float area; 24 | } 25 | */ 26 | 27 | struct Mesh 28 | { 29 | Array vtxArr; 30 | Array tdxArr; 31 | }; -------------------------------------------------------------------------------- /DXRPathTracer/Scene.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Mesh.h" 3 | #include "Material.h" 4 | 5 | 6 | struct GPUSceneObject 7 | { 8 | uint vertexOffset; 9 | uint tridexOffset; 10 | uint numTridices; 11 | 12 | float objectArea; // objectArea = meshArea * objectScale * objectScale 13 | 14 | uint twoSided; 15 | uint materialIdx; 16 | uint backMaterialIdx; 17 | //Material material; 18 | //float3 emittance; // emittance = lightColor * lightIntensity 19 | 20 | Transform modelMatrix; 21 | }; 22 | 23 | 24 | struct SceneObject 25 | { 26 | uint vertexOffset; 27 | uint tridexOffset; 28 | uint numVertices; 29 | uint numTridices; 30 | 31 | float meshArea = 0.0f; 32 | 33 | uint twoSided = 0; 34 | uint materialIdx = uint(-1); 35 | uint backMaterialIdx = uint(-1); 36 | //Material material; // Make sense only when materialIdx == uint(-1). 37 | //float3 lightColor = float3(1.0f); 38 | //float lightIntensity = 0.0f; 39 | 40 | float3 translation = float3(0.0f); 41 | float4 rotation = float4(0.f, 0.f, 0.f, 1.f); 42 | float scale = 1.0f; // Do not support anisotropic scale for several reasons (especially, cdf calculation). 43 | Transform modelMatrix = Transform::identity(); 44 | //uint transformIdx = 0; // zero transformIdx means identity matrix. 45 | }; 46 | 47 | 48 | class Scene 49 | { 50 | Array objArr; 51 | Array vtxArr; 52 | Array tdxArr; 53 | Array cdfArr; 54 | Array trmArr; 55 | Array mtlArr; 56 | 57 | friend class SceneLoader; 58 | 59 | public: 60 | void clear() { 61 | objArr.clear(); 62 | vtxArr.clear(); 63 | tdxArr.clear(); 64 | cdfArr.clear(); 65 | trmArr.clear(); 66 | mtlArr.clear(); 67 | } 68 | const Array& getVertexArray() const { return vtxArr; } 69 | const Array& getTridexArray() const { return tdxArr; } 70 | const Array& getCdfArray() const { return cdfArr; } 71 | const Array& getTransformArray() const { return trmArr; } 72 | const Array& getMaterialArray() const { return mtlArr; } 73 | const SceneObject& getObject(uint i) const { return objArr[i]; } 74 | uint numObjects() const { return objArr.size(); } 75 | }; 76 | -------------------------------------------------------------------------------- /DXRPathTracer/SceneLoader.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "SceneLoader.h" 3 | #include "generateMesh.h" 4 | #include "loadMesh.h" 5 | 6 | 7 | void SceneLoader::initializeGeometryFromMeshes(Scene* scene, const Array& meshes) 8 | { 9 | scene->clear(); 10 | 11 | uint numObjs = meshes.size(); 12 | Array& vtxArr = scene->vtxArr; 13 | Array& tdxArr = scene->tdxArr; 14 | Array& objArr = scene->objArr; 15 | 16 | objArr.resize(numObjs); 17 | 18 | uint totVertices = 0; 19 | uint totTridices = 0; 20 | 21 | for (uint i = 0; i < numObjs; ++i) 22 | { 23 | uint nowVertices = meshes[i]->vtxArr.size(); 24 | uint nowTridices = meshes[i]->tdxArr.size(); 25 | 26 | objArr[i].vertexOffset = totVertices; 27 | objArr[i].tridexOffset = totTridices; 28 | objArr[i].numVertices = nowVertices; 29 | objArr[i].numTridices = nowTridices; 30 | 31 | totVertices += nowVertices; 32 | totTridices += nowTridices; 33 | } 34 | 35 | vtxArr.resize(totVertices); 36 | tdxArr.resize(totTridices); 37 | 38 | for (uint i = 0; i < numObjs; ++i) 39 | { 40 | memcpy(&vtxArr[objArr[i].vertexOffset], &meshes[i]->vtxArr[0], sizeof(Vertex) * objArr[i].numVertices); 41 | memcpy(&tdxArr[objArr[i].tridexOffset], &meshes[i]->tdxArr[0], sizeof(Tridex) * objArr[i].numTridices); 42 | } 43 | } 44 | 45 | void SceneLoader::computeModelMatrices(Scene* scene) 46 | { 47 | for (auto& obj : scene->objArr) 48 | { 49 | obj.modelMatrix = composeMatrix(obj.translation, obj.rotation, obj.scale); 50 | } 51 | } 52 | 53 | Scene* SceneLoader::push_testScene1() 54 | { 55 | Scene* scene = new Scene; 56 | sceneArr.push_back(scene); 57 | 58 | Mesh ground = generateRectangleMesh(float3(0.0f), float3(20.f, 0.f, 20.f), FaceDir::up); 59 | Mesh box = generateCubeMesh(float3(0.0f, 1.0f, 0.0f), float3(5.f, 2.f, 3.f)); 60 | Mesh quadLight = generateRectangleMesh(float3(0.0f), float3(3.0f, 0.f, 3.0f), FaceDir::down); 61 | 62 | initializeGeometryFromMeshes(scene, { &ground, &box, &quadLight }); 63 | 64 | Array& mtlArr = scene->mtlArr; 65 | mtlArr.resize(3); 66 | 67 | mtlArr[0].albedo = float3(0.7f, 0.3f, 0.4f); 68 | 69 | mtlArr[1].type = Plastic; 70 | mtlArr[1].albedo = float3(0.1f); 71 | mtlArr[1].reflectivity = 0.01f; 72 | mtlArr[1].roughness = 0.2f; 73 | 74 | mtlArr[2].emittance = float3(200.0f); 75 | 76 | //scene->objArr[0].twoSided = true; 77 | scene->objArr[0].materialIdx = 0; 78 | scene->objArr[0].backMaterialIdx = 0; 79 | scene->objArr[1].materialIdx = 1; 80 | scene->objArr[2].materialIdx = 2; 81 | 82 | scene->objArr[0].translation = float3(0.0f); 83 | scene->objArr[1].translation = float3(0.0f, 0.5f, 0.0f); 84 | scene->objArr[2].translation = float3(-20.0f, 17.f, 0.0f); 85 | 86 | computeModelMatrices(scene); 87 | 88 | return scene; 89 | } 90 | 91 | 92 | Scene* SceneLoader::push_hyperionTestScene() 93 | { 94 | Scene* scene = new Scene; 95 | sceneArr.push_back(scene); 96 | 97 | Mesh groundM = generateRectangleMesh(float3(0.0, -0.4, 0.0), float3(40.0, 0.0, 40.0), FaceDir::up); 98 | Mesh tableM = generateBoxMesh(float3(-5.0, -0.38, -4.0), float3(5.0, -0.01, 3.0)); 99 | Mesh sphereM = generateSphereMesh(float3(0,1,0), 1.0f); 100 | Mesh ringM = loadMeshFromOBJFile("../data/mesh/ring.obj", true); 101 | Mesh golfBallM = loadMeshFromOBJFile("../data/mesh/golfball.obj", true); 102 | Mesh puzzleM = loadMeshFromOBJFile("../data/mesh/burrPuzzle.obj", true); 103 | initializeGeometryFromMeshes(scene, { &groundM, &tableM, &sphereM, &ringM, &golfBallM, &puzzleM }); 104 | 105 | enum SceneObjectId { 106 | ground, table, light, glass, metal, pingpong, bouncy, orange, wood, golfball, marble1, 107 | marble2, ring1, ring2, ring3, numObjs 108 | }; 109 | enum MaterialId { 110 | groundMtl, tableMtl, lightMtl, glassMtl, metalMtl, pingpongMtl, bouncyMtl, orangeMtl, woodMtl, golfballMtl, marble1Mtl, 111 | marble2Mtl, ringMtl, numMtls 112 | }; 113 | 114 | Array objArr(numObjs, scene->objArr[2]); 115 | objArr[ground ] = scene->objArr[0]; 116 | objArr[table ] = scene->objArr[1]; 117 | objArr[ring1 ] = scene->objArr[3]; 118 | objArr[ring2 ] = scene->objArr[3]; 119 | objArr[ring3 ] = scene->objArr[3]; 120 | objArr[golfball] = scene->objArr[4]; 121 | objArr[wood ] = scene->objArr[5]; 122 | 123 | objArr[light ].scale = 2.0f; 124 | objArr[light ].translation = float3(-20, 17, 0); 125 | 126 | objArr[ground ].translation = float3(0.0, -0.04, 0.0); 127 | objArr[table ].translation = float3(0.0, -0.02, 0.0); 128 | objArr[glass ].translation = float3(3.5, 0.0, 0.0); 129 | objArr[metal ].translation = float3(-3.5, 0.0, 0.0); 130 | objArr[pingpong].translation = float3(-1.5, 0.0, 1.1); 131 | objArr[bouncy ].translation = float3(-2.0, 0.0, -1.1); 132 | objArr[orange ].translation = float3(2.0, 0.0, -1.1); 133 | objArr[marble1 ].translation = float3(-0.5, 0.0, 2.0); 134 | objArr[marble2 ].translation = float3(0.5, 0.0, 2.0); 135 | objArr[ring1 ].translation = float3(0.0, -0.02, 0.0); 136 | objArr[ring2 ].translation = float3(0.6, -0.02, 0.3); 137 | objArr[ring3 ].translation = float3(-1.3, -0.02, -0.3); 138 | 139 | objArr[ground ].scale = 1.0f; 140 | objArr[table ].scale = 1.0f; 141 | objArr[glass ].scale = 0.55f; 142 | objArr[metal ].scale = 0.6f; 143 | objArr[pingpong].scale = 0.45f; 144 | objArr[bouncy ].scale = 0.25f; 145 | objArr[orange ].scale = 0.5f; 146 | objArr[marble1 ].scale = 0.1f; 147 | objArr[marble2 ].scale = 0.15f; 148 | objArr[ring1 ].scale = 0.005f; 149 | objArr[ring2 ].scale = 0.005f; 150 | objArr[ring3 ].scale = 0.005f; 151 | 152 | objArr[golfball].translation = float3(-12.3, -13.1, -140.0); 153 | objArr[golfball].scale = 0.25f; 154 | 155 | // burrPuzzle.obj 156 | objArr[wood ].translation = float3(-0.2, 1.0, -2.3); 157 | objArr[wood ].rotation = getRotationAsQuternion({0,1,0}, 30.0f); 158 | objArr[wood ].scale = 20.0f; 159 | 160 | objArr.swap(scene->objArr); 161 | 162 | 163 | Array& mtlArr = scene->mtlArr; 164 | mtlArr.resize(numMtls); 165 | mtlArr[groundMtl ].albedo = float3(0.75, 0.6585, 0.5582); 166 | mtlArr[tableMtl ].albedo = float3(0.87, 0.7785, 0.6782); 167 | mtlArr[lightMtl ].albedo = float3(0); 168 | mtlArr[glassMtl ].albedo = float3(0); 169 | mtlArr[metalMtl ].albedo = float3(0.3); 170 | //mtlArr[pingpongMtl].albedo = float3(0.93, 0.89, 0.85); 171 | mtlArr[pingpongMtl].albedo = float3(0.4, 0.2, 0.2); 172 | mtlArr[bouncyMtl ].albedo = float3(0.9828262, 0.180144, 0.0780565); 173 | mtlArr[orangeMtl ].albedo = float3(0.7175, 0.17, 0.005); 174 | mtlArr[woodMtl ].albedo = float3(0.3992, 0.21951971, 0.10871); 175 | mtlArr[golfballMtl].albedo = float3(0.9, 0.87, 0.95); 176 | mtlArr[marble1Mtl ].albedo = float3(0.276, 0.344, 0.2233); 177 | mtlArr[marble2Mtl ].albedo = float3(0.2549, 0.3537, 0.11926); 178 | mtlArr[ringMtl ].albedo = float3(0.95, 0.93, 0.88); 179 | 180 | 181 | mtlArr[lightMtl ].emittance = float3(200.0f); 182 | //mtlArr[woodMtl ].emittance = 5.0f * float3(0.3992, 0.21951971, 0.10871); 183 | //mtlArr[woodMtl ].albedo = float3(1); 184 | mtlArr[bouncyMtl ].emittance = 10.0f * float3(0.9828262, 0.180144, 0.0780565); 185 | mtlArr[marble1Mtl ].emittance = 10.0f * float3(0.276, 0.344, 0.2233); 186 | mtlArr[marble2Mtl ].emittance = 10.0f * float3(0.2549, 0.3537, 0.11926); 187 | 188 | /*scene->objArr[marble2 ].scale = 0.1f; 189 | scene->objArr[marble2 ].translation = float3(3.2, 0.7, 0.0); 190 | mtlArr[marble2Mtl ].emittance = float3(100.0f);*/ 191 | 192 | 193 | mtlArr[pingpongMtl].type = Metal; 194 | mtlArr[pingpongMtl].roughness = 0.2f; 195 | 196 | mtlArr[metalMtl ].type = Metal; 197 | mtlArr[metalMtl ].roughness = 0.003f; 198 | mtlArr[ringMtl ].type = Metal; 199 | mtlArr[ringMtl ].roughness = 0.02f; 200 | 201 | mtlArr[orangeMtl ].type = Plastic; 202 | mtlArr[orangeMtl ].roughness = 0.01f; 203 | mtlArr[orangeMtl ].reflectivity = 0.1f; 204 | 205 | mtlArr[woodMtl ].type = Plastic; 206 | mtlArr[woodMtl ].roughness = 0.3f; 207 | mtlArr[woodMtl ].reflectivity = 0.1f; 208 | 209 | mtlArr[golfballMtl].type = Plastic; 210 | mtlArr[golfballMtl].reflectivity = 0.1f; 211 | mtlArr[golfballMtl].roughness = 0.05f; 212 | 213 | mtlArr[glassMtl ].type = Glass; 214 | mtlArr[glassMtl ].transmittivity = 0.96f; 215 | 216 | 217 | for(uint i=0; iobjArr[i].materialIdx = i; 219 | scene->objArr[ring1].materialIdx = ringMtl; 220 | scene->objArr[ring2].materialIdx = ringMtl; 221 | scene->objArr[ring3].materialIdx = ringMtl; 222 | 223 | computeModelMatrices(scene); 224 | 225 | return scene; 226 | } -------------------------------------------------------------------------------- /DXRPathTracer/SceneLoader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include "Scene.h" 4 | 5 | 6 | class SceneLoader 7 | { 8 | Array sceneArr; 9 | 10 | void initializeGeometryFromMeshes(Scene* scene, const Array& meshes); 11 | void computeModelMatrices(Scene* scene); 12 | 13 | public: 14 | Scene* getScene(uint sceneIdx) const { return sceneArr[sceneIdx]; } 15 | Scene* push_testScene1(); 16 | Scene* push_hyperionTestScene(); 17 | }; 18 | -------------------------------------------------------------------------------- /DXRPathTracer/basic_math.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "basic_types.h" 3 | #include 4 | #define PI 3.14159265358979323846f 5 | #define DEGREE (PI / 180.0f) 6 | 7 | template inline constexpr T _min(T x, T y) 8 | { 9 | return x < y ? x : y; 10 | } 11 | 12 | template inline constexpr T _max(T x, T y) 13 | { 14 | return x > y ? x : y; 15 | } 16 | 17 | template inline constexpr T _clamp(T value, T lowerBound, T upperBound) 18 | { 19 | return _min( _max(lowerBound, value), upperBound); 20 | } 21 | 22 | inline int2 operator-(const int2& v, const int2& w) 23 | { 24 | return int2(v.x-w.x, v.y-w.y); 25 | } 26 | 27 | inline float3 operator+(const float3& v, const float3& w) 28 | { 29 | return float3(v.x+w.x, v.y+w.y, v.z+w.z); 30 | } 31 | inline float3 operator-(const float3& v, const float3& w) 32 | { 33 | return float3(v.x-w.x, v.y-w.y, v.z-w.z); 34 | } 35 | inline float3 operator-(const float3& v) 36 | { 37 | return float3(-v.x, -v.y, -v.z); 38 | } 39 | template 40 | inline float3 operator*(const float3& v, T s) 41 | { 42 | float ss = (float)s; 43 | return float3(v.x*ss, v.y*ss, v.z*ss); 44 | } 45 | template 46 | inline float3 operator*(T s, const float3& v) 47 | { 48 | float ss = (float)s; 49 | return float3(v.x*ss, v.y*ss, v.z*ss); 50 | } 51 | template 52 | inline float3 operator/(const float3& v, T s) 53 | { 54 | float ss = 1.0f / (float)s; 55 | return float3(v.x*ss, v.y*ss, v.z*ss); 56 | } 57 | inline float dot(const float3& v, const float3& w) 58 | { 59 | return v.x * w.x + v.y * w.y + v.z * w.z; 60 | } 61 | inline float squaredLength(const float3& v) 62 | { 63 | return v.x * v.x + v.y * v.y + v.z * v.z; 64 | } 65 | inline float length(const float3& v) 66 | { 67 | return sqrtf(squaredLength(v)); 68 | } 69 | inline float3 normalize(const float3& v) 70 | { 71 | return v / length(v); 72 | } 73 | inline float3 cross(const float3& v, const float3& w) 74 | { 75 | return float3(v.y*w.z - v.z*w.y, v.z*w.x - v.x*w.z, v.x*w.y - v.y*w.x); 76 | } 77 | 78 | inline Transform composeMatrix(const float3& translation, const float4& rotation, float scale) 79 | { 80 | Transform ret; 81 | ret.mat[0][0] = scale * (1.f - 2.f * (rotation.y*rotation.y + rotation.z*rotation.z)); 82 | ret.mat[0][1] = scale * (2.f * (rotation.x*rotation.y - rotation.z*rotation.w)); 83 | ret.mat[0][2] = scale * (2.f * (rotation.x*rotation.z + rotation.y*rotation.w)); 84 | ret.mat[0][3] = translation.x; 85 | ret.mat[1][0] = scale * (2.f * (rotation.x*rotation.y + rotation.z*rotation.w)); 86 | ret.mat[1][1] = scale * (1.f - 2.f * (rotation.x*rotation.x + rotation.z*rotation.z)); 87 | ret.mat[1][2] = scale * (2.f * (rotation.y*rotation.z - rotation.x*rotation.w)); 88 | ret.mat[1][3] = translation.y; 89 | ret.mat[2][0] = scale * (2.f * (rotation.x*rotation.z - rotation.y*rotation.w)); 90 | ret.mat[2][1] = scale * (2.f * (rotation.y*rotation.z + rotation.x*rotation.w)); 91 | ret.mat[2][2] = scale * (1.f - 2.f * (rotation.x*rotation.x + rotation.y*rotation.y)); 92 | ret.mat[2][3] = translation.z; 93 | ret.mat[3][0] = 0.f; 94 | ret.mat[3][1] = 0.f; 95 | ret.mat[3][2] = 0.f; 96 | ret.mat[3][3] = 1.f; 97 | return ret; 98 | } 99 | 100 | inline void composeMatrix(float matrix[16], const float3& translation, const float4& rotation, float scale) 101 | { 102 | matrix[ 0] = scale * (1.f - 2.f * (rotation.y*rotation.y + rotation.z*rotation.z)); 103 | matrix[ 1] = scale * (2.f * (rotation.x*rotation.y - rotation.z*rotation.w)); 104 | matrix[ 2] = scale * (2.f * (rotation.x*rotation.z + rotation.y*rotation.w)); 105 | matrix[ 3] = translation.x; 106 | matrix[ 4] = scale * (2.f * (rotation.x*rotation.y + rotation.z*rotation.w)); 107 | matrix[ 5] = scale * (1.f - 2.f * (rotation.x*rotation.x + rotation.z*rotation.z)); 108 | matrix[ 6] = scale * (2.f * (rotation.y*rotation.z - rotation.x*rotation.w)); 109 | matrix[ 7] = translation.y; 110 | matrix[ 8] = scale * (2.f * (rotation.x*rotation.z - rotation.y*rotation.w)); 111 | matrix[ 9] = scale * (2.f * (rotation.y*rotation.z + rotation.x*rotation.w)); 112 | matrix[10] = scale * (1.f - 2.f * (rotation.x*rotation.x + rotation.y*rotation.y)); 113 | matrix[11] = translation.z; 114 | matrix[12] = 0.f; 115 | matrix[13] = 0.f; 116 | matrix[14] = 0.f; 117 | matrix[15] = 1.f; 118 | } 119 | 120 | inline float4 getRotationAsQuternion(const float3& axis, float degree) 121 | { 122 | float angle = degree * DEGREE; 123 | 124 | return float4(sinf(0.5f*angle) * axis, cosf(0.5f*angle)); 125 | } -------------------------------------------------------------------------------- /DXRPathTracer/basic_types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef wchar_t wchar; 4 | typedef unsigned char uint8; 5 | typedef unsigned int uint; 6 | typedef unsigned long long uint64; 7 | 8 | struct float2 9 | { 10 | union { 11 | float data[2]; 12 | struct { float x, y; }; 13 | }; 14 | 15 | float2() {} 16 | //float2(const float2& v) :x(v.x), y(v.y) {} 17 | template 18 | float2(X x) : x((float)x), y((float)x) {} 19 | template 20 | float2(X x, Y y) : x((float)x), y((float)y) {} 21 | float& operator[](int order) { return data[order]; } 22 | float operator[](int order) const { return data[order]; } 23 | //float2& operator=(const float2& v) { x = v.x, y = v.y; return *this; } 24 | }; 25 | 26 | struct float3 27 | { 28 | union { 29 | float data[3]; 30 | struct { 31 | union { 32 | struct { float x, y; }; 33 | float2 xy; 34 | }; 35 | float z; 36 | }; 37 | }; 38 | 39 | float3() {} 40 | //float3(const float3& v) :x(v.x), y(v.y), z(v.z) {} 41 | template 42 | float3(X x) : x((float)x), y((float)x), z((float)x) {} 43 | template 44 | float3(X x, Y y, Z z) : x((float)x), y((float)y), z((float)z) {} 45 | float3(const float2& xy, float z) : xy(xy), z(z) {} 46 | float& operator[](int order) { return data[order]; } 47 | float operator[](int order) const { return data[order]; } 48 | //float3& operator=(const float3& v) { x = v.x, y = v.y, z = v.z; return *this; } 49 | }; 50 | 51 | struct float4 52 | { 53 | union { 54 | float data[4]; 55 | struct { 56 | union { 57 | struct { float x, y, z; }; 58 | float3 xyz; 59 | }; 60 | float w; 61 | }; 62 | }; 63 | 64 | float4() {} 65 | //float4(const float4& v) :x(v.x), y(v.y), z(v.z), w(v.w) {} 66 | template 67 | float4(X x) : x((float)x), y((float)x), z((float)x), w((float)x) {} 68 | template 69 | float4(X x, Y y, Z z, W w) : x((float)x), y((float)y), z((float)z), w((float)w) {} 70 | float4(const float3& xyz, float w) : xyz(xyz), w(w) {} 71 | float& operator[](int order) { return data[order]; } 72 | float operator[](int order) const { return data[order]; } 73 | //float4& operator=(const float4& v) { x = v.x, y = v.y, z = v.z, w = v.w; return *this; } 74 | }; 75 | 76 | struct uint2; 77 | struct int2 78 | { 79 | union { 80 | int data[2]; 81 | struct { int x, y; }; 82 | struct { int i, j; }; 83 | }; 84 | 85 | int2() {} 86 | //int2(const int2& v) :x(v.x), y(v.y) {} 87 | template 88 | int2(I i, J j) : i((int)i), j((int)j) {} 89 | int& operator[](int order) { return data[order]; } 90 | int operator[](int order) const { return data[order]; } 91 | explicit operator uint2(); 92 | //uint2& operator=(const uint2& v) { x = v.x, y = v.y; return *this; } 93 | }; 94 | 95 | struct uint2 96 | { 97 | union { 98 | uint data[2]; 99 | struct { uint x, y; }; 100 | struct { uint i, j; }; 101 | }; 102 | 103 | uint2() {} 104 | //uint2(const uint2& v) :x(v.x), y(v.y) {} 105 | template 106 | uint2(I i, J j) : i((uint)i), j((uint)j) {} 107 | uint& operator[](int order) { return data[order]; } 108 | uint operator[](int order) const { return data[order]; } 109 | explicit operator int2(); 110 | //uint2& operator=(const uint2& v) { x = v.x, y = v.y; return *this; } 111 | }; 112 | 113 | inline int2::operator uint2() 114 | { 115 | return uint2( (uint) i, (uint) j ); 116 | } 117 | 118 | inline uint2::operator int2() 119 | { 120 | return int2( (int) i, (int) j ); 121 | } 122 | 123 | struct uint3 124 | { 125 | union { 126 | uint data[3]; 127 | struct { uint x, y, z; }; 128 | struct { uint i, j, k; }; 129 | }; 130 | 131 | uint3() {} 132 | //uint3(const uint3& v) :x(v.x), y(v.y), z(v.z) {} 133 | template 134 | uint3(I i, J j, K k) : i((uint)i), j((uint)j), k((uint)k) {} 135 | uint& operator[](int order) { return data[order]; } 136 | uint operator[](int order) const { return data[order]; } 137 | //uint3& operator=(const uint3& v) { x = v.x, y = v.y, z = v.z; return *this; } 138 | }; 139 | 140 | struct Transform 141 | { 142 | float mat[4][4]; 143 | Transform() {} 144 | constexpr Transform(float scala) : mat{} 145 | { 146 | mat[0][0] = mat[1][1] = mat[2][2] = scala; 147 | mat[3][3] = 1.0f; 148 | } 149 | static constexpr Transform identity() 150 | { 151 | return Transform(1.0f); 152 | } 153 | }; 154 | -------------------------------------------------------------------------------- /DXRPathTracer/dxHelpers.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "dxHelpers.h" 3 | #include 4 | 5 | 6 | static IDXGIFactory2* gFactory = nullptr; 7 | static ID3D12Device* gDevice = nullptr; 8 | ID3D12DebugDevice* gDebugDevice = nullptr; 9 | 10 | 11 | IDXGIFactory2* getFactory() 12 | { 13 | if (!gFactory) 14 | { 15 | #ifdef _DEBUG 16 | ID3D12Debug* debuger; 17 | if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debuger)))) 18 | { 19 | debuger->EnableDebugLayer(); 20 | } 21 | #endif 22 | ThrowFailedHR(CreateDXGIFactory1(IID_PPV_ARGS(&gFactory))); 23 | } 24 | 25 | return gFactory; 26 | } 27 | 28 | 29 | IDXGIAdapter* getRTXAdapter() 30 | { 31 | static IDXGIAdapter* adapter = nullptr; 32 | 33 | if (!adapter) 34 | { 35 | for (uint i = 0; DXGI_ERROR_NOT_FOUND != getFactory()->EnumAdapters(i, &adapter); i++) 36 | { 37 | ID3D12Device* tempDevice; 38 | ThrowFailedHR(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_12_0, IID_PPV_ARGS(&tempDevice))); 39 | 40 | D3D12_FEATURE_DATA_D3D12_OPTIONS5 features5; 41 | HRESULT hr = tempDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &features5, sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS5)); 42 | 43 | if (FAILED(hr)) 44 | { 45 | throw Error("Your Window 10 version must be at least 1809 to support D3D12_FEATURE_D3D12_OPTIONS5."); 46 | } 47 | 48 | if (features5.RaytracingTier != D3D12_RAYTRACING_TIER_NOT_SUPPORTED) 49 | { 50 | return adapter; 51 | } 52 | } 53 | 54 | throw Error("There are not DXR supported adapters(video cards such as Nvidia's Volta or Turing RTX). Also, The DXR fallback layer is not supported in this application."); 55 | } 56 | 57 | return adapter; 58 | } 59 | 60 | 61 | ID3D12Device* createDX12Device(IDXGIAdapter* adapter) 62 | { 63 | ThrowFailedHR(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_12_0, IID_PPV_ARGS(&gDevice))); 64 | #ifdef _DEBUG 65 | gDevice->QueryInterface(IID_PPV_ARGS(&gDebugDevice)); 66 | #endif 67 | return gDevice; 68 | } 69 | 70 | 71 | D3D12_GRAPHICS_PIPELINE_STATE_DESC Graphics_Pipeline_Desc( 72 | D3D12_INPUT_LAYOUT_DESC inputLayout, 73 | ID3D12RootSignature* rootSig, 74 | D3D12_SHADER_BYTECODE vertexShader, 75 | D3D12_SHADER_BYTECODE pixelShader, 76 | DXGI_FORMAT renderTargetFormat, 77 | uint numRenderTargets) 78 | { 79 | D3D12_GRAPHICS_PIPELINE_STATE_DESC pipelineDesc = {}; 80 | 81 | pipelineDesc.InputLayout = inputLayout; 82 | pipelineDesc.pRootSignature = rootSig; 83 | pipelineDesc.VS = vertexShader; 84 | pipelineDesc.PS = pixelShader; 85 | pipelineDesc.SampleMask = UINT_MAX; 86 | pipelineDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; 87 | pipelineDesc.SampleDesc.Count = 1; 88 | pipelineDesc.NumRenderTargets = numRenderTargets; 89 | for(uint i=0; iCreateCommittedResource( 130 | &HeapProperty(heapType), D3D12_HEAP_FLAG_NONE, 131 | &BufferDesc(bufferSize, resourceFlags), resourceStates, 132 | nullptr, IID_PPV_ARGS(&resource))); 133 | return resource; 134 | } 135 | 136 | 137 | // [Descriptor] 138 | void Descriptor::assignSRV(ID3D12Resource* resource, const D3D12_SHADER_RESOURCE_VIEW_DESC* desc) 139 | { 140 | gDevice->CreateShaderResourceView(resource, desc, cpuAddr); 141 | } 142 | 143 | void Descriptor::assignUAV(ID3D12Resource* resource, const D3D12_UNORDERED_ACCESS_VIEW_DESC* desc, ID3D12Resource* counter) 144 | { 145 | gDevice->CreateUnorderedAccessView(resource, counter, desc, cpuAddr); 146 | } 147 | 148 | void Descriptor::assignRTV(ID3D12Resource* resource, const D3D12_RENDER_TARGET_VIEW_DESC* desc) 149 | { 150 | gDevice->CreateRenderTargetView(resource, desc, cpuAddr); 151 | } 152 | 153 | void Descriptor::assignCBV(const D3D12_CONSTANT_BUFFER_VIEW_DESC* desc) 154 | { 155 | gDevice->CreateConstantBufferView(desc, cpuAddr); 156 | } 157 | 158 | void Descriptor::assignSRV(dxResource& resource, const D3D12_SHADER_RESOURCE_VIEW_DESC* desc) 159 | { 160 | assignSRV(resource.get(), desc); 161 | resource.setSRV(this); 162 | } 163 | 164 | void Descriptor::assignUAV(dxResource& resource, const D3D12_UNORDERED_ACCESS_VIEW_DESC* desc, ID3D12Resource* counter) 165 | { 166 | assignUAV(resource.get(), desc, counter); 167 | resource.setUAV(this); 168 | } 169 | 170 | void Descriptor::assignRTV(dxResource& resource, const D3D12_RENDER_TARGET_VIEW_DESC* desc) 171 | { 172 | assignRTV(resource.get(), desc); 173 | resource.setRTV(this); 174 | } 175 | 176 | 177 | // [DescriptorHeap] 178 | void DescriptorHeap::destroy() 179 | { 180 | SAFE_RELEASE(heap); 181 | descriptorArr.clear(); 182 | } 183 | 184 | void DescriptorHeap::create(uint maxDescriptors, D3D12_DESCRIPTOR_HEAP_TYPE heapType) 185 | { 186 | if(heap != nullptr) 187 | throw Error("destroy() must be called before re-creating."); 188 | 189 | D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {}; 190 | { 191 | heapDesc.Type = heapType; 192 | heapDesc.NumDescriptors = maxDescriptors; 193 | heapDesc.Flags = (heapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV) ? 194 | D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE : D3D12_DESCRIPTOR_HEAP_FLAG_NONE; 195 | } 196 | gDevice->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&heap)); 197 | 198 | D3D12_CPU_DESCRIPTOR_HANDLE cpuAddr = heap->GetCPUDescriptorHandleForHeapStart(); 199 | D3D12_GPU_DESCRIPTOR_HANDLE gpuAddr = heap->GetGPUDescriptorHandleForHeapStart(); 200 | uint descriptorSize = gDevice->GetDescriptorHandleIncrementSize(heapType); 201 | 202 | descriptorArr.reserve(maxDescriptors); 203 | 204 | for (uint i = 0; i < maxDescriptors; ++i) 205 | { 206 | descriptorArr.push_back(Descriptor(cpuAddr, gpuAddr)); 207 | cpuAddr = cpuAddr + descriptorSize; 208 | gpuAddr = gpuAddr + descriptorSize; 209 | } 210 | } 211 | 212 | void DescriptorHeap::bind(ID3D12GraphicsCommandList* cmdList) 213 | { 214 | cmdList->SetDescriptorHeaps(1, &heap); 215 | } 216 | 217 | 218 | // [RootParameter] 219 | static inline uint findCommaOrNull(const char* codePos) 220 | { 221 | uint i=0; 222 | for (; codePos[i] != '\0'; ++i) 223 | { 224 | if(codePos[i] == ',') 225 | break; 226 | } 227 | return i; 228 | } 229 | 230 | static inline uint spaceRemoveCopy(char* dst, const char* src, uint length) 231 | { 232 | uint j = 0; 233 | for (uint i = 0; i < length; ++i) 234 | { 235 | if(src[i] == ' ' || src[i] == '\t') 236 | continue; 237 | dst[j++] = src[i]; 238 | } 239 | dst[j] = '\0'; 240 | return j; 241 | } 242 | 243 | static inline uint readDigit(const char* digitPos, uint* num) 244 | { 245 | *num = 0; 246 | 247 | uint i = 0; 248 | for ( ; digitPos[i] != '\0'; ++i) 249 | { 250 | if ('0' <= digitPos[i] && digitPos[i] <= '9') 251 | { 252 | *num *= 10; 253 | *num += (uint) (digitPos[i] - '0'); 254 | } 255 | else 256 | { 257 | if(i==0) 258 | throw Error("At least one digit must be placed even zero"); 259 | break; 260 | } 261 | } 262 | 263 | return i; 264 | } 265 | 266 | static void readRegisterInfo(const char* token, 267 | DescriptorType* type, uint* registerSpace, uint* registerBase, uint* numDescriptors) 268 | { 269 | uint i = 0; 270 | 271 | if (token[0] == '(') 272 | { 273 | ++i; 274 | i += readDigit(token + i, registerSpace); 275 | if(token[i] != ')') 276 | throw Error(); 277 | ++i; 278 | } 279 | else 280 | { 281 | *registerSpace = 0; 282 | } 283 | 284 | uint typePos = i; 285 | 286 | if (token[i] == 't') 287 | { 288 | *type = DescriptorType::SRV; 289 | } 290 | else if (token[i] == 'u') 291 | { 292 | *type = DescriptorType::UAV; 293 | } 294 | else if (token[i] == 'b') 295 | { 296 | *type = DescriptorType::CBV; 297 | } 298 | else 299 | throw Error(); 300 | 301 | ++i; 302 | 303 | i += readDigit(token + i, registerBase); 304 | 305 | if (token[i] == '\0') 306 | { 307 | *numDescriptors = 1; 308 | return; 309 | } 310 | else if (token[i] != '-') 311 | { 312 | throw Error(); 313 | } 314 | 315 | ++i; 316 | 317 | if (token[i] == '\0') 318 | { 319 | *numDescriptors = uint(-1); // unbounded number of descriptors 320 | return; 321 | } 322 | else if (token[i] != token[typePos]) 323 | { 324 | throw Error(); 325 | } 326 | 327 | ++i; 328 | 329 | uint registerEnd; 330 | i += readDigit(token + i, ®isterEnd); 331 | 332 | *numDescriptors = registerEnd - *registerBase + 1; 333 | 334 | if(token[i] != '\0') 335 | throw Error(); 336 | } 337 | 338 | 339 | // [RootTable] 340 | void RootTable::create(const char* code) 341 | { 342 | char token[256]; 343 | 344 | const char* codePos = code; 345 | 346 | while (*codePos != '\0') 347 | { 348 | DescriptorType type; 349 | uint registerBase; 350 | uint registerSpace; 351 | uint numDescriptors; 352 | 353 | uint tokenLengthWithSpace = findCommaOrNull(codePos); 354 | spaceRemoveCopy(token, codePos, tokenLengthWithSpace); 355 | readRegisterInfo(token, &type, ®isterSpace, ®isterBase, &numDescriptors); 356 | 357 | D3D12_DESCRIPTOR_RANGE range = {}; 358 | range.RangeType = 359 | (type == DescriptorType::SRV) ? D3D12_DESCRIPTOR_RANGE_TYPE_SRV : 360 | (type == DescriptorType::UAV) ? D3D12_DESCRIPTOR_RANGE_TYPE_UAV : D3D12_DESCRIPTOR_RANGE_TYPE_CBV; 361 | range.NumDescriptors = numDescriptors; 362 | range.BaseShaderRegister = registerBase; 363 | range.RegisterSpace = registerSpace; 364 | range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; 365 | rangeArr.push_back(range); 366 | 367 | codePos += tokenLengthWithSpace; 368 | } 369 | 370 | param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; 371 | param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; 372 | param.DescriptorTable.NumDescriptorRanges = rangeArr.size(); 373 | param.DescriptorTable.pDescriptorRanges = rangeArr.data(); 374 | } 375 | 376 | void RootTable::bindCompute(ID3D12GraphicsCommandList* cmdList, uint paramIdx) const 377 | { 378 | cmdList->SetComputeRootDescriptorTable(paramIdx, tableStart); 379 | } 380 | 381 | void RootTable::bindGraphics(ID3D12GraphicsCommandList* cmdList, uint paramIdx) const 382 | { 383 | cmdList->SetGraphicsRootDescriptorTable(paramIdx, tableStart); 384 | } 385 | 386 | 387 | // [RootPointer] 388 | void RootPointer::create(const char* code) 389 | { 390 | char token[256]; 391 | 392 | DescriptorType type; 393 | uint registerBase; 394 | uint registerSpace; 395 | uint numDescriptors; 396 | 397 | uint tokenLengthWithSpace = findCommaOrNull(code); 398 | spaceRemoveCopy(token, code, tokenLengthWithSpace); 399 | readRegisterInfo(token, &type, ®isterSpace, ®isterBase, &numDescriptors); 400 | 401 | assert(numDescriptors == 1 && code[tokenLengthWithSpace] == '\0'); 402 | 403 | param.ParameterType = 404 | (type == DescriptorType::SRV) ? D3D12_ROOT_PARAMETER_TYPE_SRV : 405 | (type == DescriptorType::UAV) ? D3D12_ROOT_PARAMETER_TYPE_UAV : D3D12_ROOT_PARAMETER_TYPE_CBV; 406 | param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; 407 | param.Descriptor.ShaderRegister = registerBase; 408 | param.Descriptor.RegisterSpace = registerSpace; 409 | } 410 | 411 | void RootPointer::bindCompute(ID3D12GraphicsCommandList* cmdList, uint paramIdx) const 412 | { 413 | if(param.ParameterType==D3D12_ROOT_PARAMETER_TYPE_SRV) 414 | cmdList->SetComputeRootShaderResourceView(paramIdx, resourceAddress); 415 | else if(param.ParameterType==D3D12_ROOT_PARAMETER_TYPE_UAV) 416 | cmdList->SetComputeRootUnorderedAccessView(paramIdx, resourceAddress); 417 | else if(param.ParameterType==D3D12_ROOT_PARAMETER_TYPE_CBV) 418 | cmdList->SetComputeRootConstantBufferView(paramIdx, resourceAddress); 419 | else throw Error(); 420 | } 421 | 422 | void RootPointer::bindGraphics(ID3D12GraphicsCommandList* cmdList, uint paramIdx) const 423 | { 424 | if(param.ParameterType==D3D12_ROOT_PARAMETER_TYPE_SRV) 425 | cmdList->SetGraphicsRootShaderResourceView(paramIdx, resourceAddress); 426 | else if(param.ParameterType==D3D12_ROOT_PARAMETER_TYPE_UAV) 427 | cmdList->SetGraphicsRootUnorderedAccessView(paramIdx, resourceAddress); 428 | else if(param.ParameterType==D3D12_ROOT_PARAMETER_TYPE_CBV) 429 | cmdList->SetGraphicsRootConstantBufferView(paramIdx, resourceAddress); 430 | else throw Error(); 431 | } 432 | 433 | 434 | // [RootConstants] 435 | void createRootConstantsParam(D3D12_ROOT_PARAMETER& param, const char* code, uint num32BitConsts) 436 | { 437 | char token[256]; 438 | 439 | DescriptorType type; 440 | uint registerBase; 441 | uint registerSpace; 442 | uint numDescriptors; 443 | 444 | uint tokenLengthWithSpace = findCommaOrNull(code); 445 | spaceRemoveCopy(token, code, tokenLengthWithSpace); 446 | readRegisterInfo(token, &type, ®isterSpace, ®isterBase, &numDescriptors); 447 | 448 | assert(type == DescriptorType::CBV); 449 | assert(numDescriptors == 1 && code[tokenLengthWithSpace] == '\0'); 450 | 451 | param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; 452 | param.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; 453 | param.Constants.Num32BitValues = num32BitConsts; 454 | param.Constants.RegisterSpace = registerSpace; 455 | param.Constants.ShaderRegister = registerBase; 456 | } 457 | 458 | 459 | // [RootSignature] 460 | RootSignature::~RootSignature() 461 | { 462 | for (uint i = 0; i < pRootParamArr.size(); ++i) 463 | { 464 | SAFE_DELETE(pRootParamArr[i]); 465 | } 466 | SAFE_RELEASE(rootSig); 467 | } 468 | 469 | void RootSignature::build(D3D12_ROOT_SIGNATURE_FLAGS flags) 470 | { 471 | Array empty; 472 | build(empty, flags); 473 | } 474 | 475 | void RootSignature::build(const D3D12_STATIC_SAMPLER_DESC& sampler, D3D12_ROOT_SIGNATURE_FLAGS flags) 476 | { 477 | Array samplers(1); 478 | samplers[0] = sampler; 479 | build(samplers, flags); 480 | } 481 | 482 | void RootSignature::build(const Array& samplerArr, D3D12_ROOT_SIGNATURE_FLAGS flags) 483 | { 484 | if(rootSig != nullptr) 485 | throw Error("It cannot be re-built."); 486 | 487 | Array paramArr(pRootParamArr.size()); 488 | for (uint i = 0; i < paramArr.size(); ++i) 489 | { 490 | assert(pRootParamArr[i] != nullptr); 491 | paramArr[i] = pRootParamArr[i]->param; 492 | } 493 | 494 | D3D12_ROOT_SIGNATURE_DESC rootSigDesc = {}; 495 | rootSigDesc.NumParameters = paramArr.size(); 496 | rootSigDesc.pParameters = paramArr.size() > 0 ? paramArr.data() : nullptr; 497 | rootSigDesc.NumStaticSamplers = samplerArr.size(); 498 | rootSigDesc.pStaticSamplers = samplerArr.size() > 0 ? samplerArr.data() : nullptr; 499 | rootSigDesc.Flags = flags; 500 | 501 | ID3DBlob* blob = nullptr, * error = nullptr; 502 | D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, &error); 503 | if (error) 504 | { 505 | throw Error((char*)error->GetBufferPointer()); 506 | } 507 | 508 | ThrowFailedHR(gDevice->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(&rootSig))); 509 | 510 | blob->Release(); 511 | } 512 | 513 | void RootSignature::bindCompute(ID3D12GraphicsCommandList* cmdList) const 514 | { 515 | cmdList->SetComputeRootSignature(rootSig); 516 | 517 | for (uint paramIdx = 0; paramIdx < pRootParamArr.size(); ++paramIdx) 518 | { 519 | pRootParamArr[paramIdx]->bindCompute(cmdList, paramIdx); 520 | } 521 | } 522 | 523 | void RootSignature::bindGraphics(ID3D12GraphicsCommandList* cmdList) const 524 | { 525 | cmdList->SetGraphicsRootSignature(rootSig); 526 | 527 | for (uint paramIdx = 0; paramIdx < pRootParamArr.size(); ++paramIdx) 528 | { 529 | pRootParamArr[paramIdx]->bindGraphics(cmdList, paramIdx); 530 | } 531 | } 532 | 533 | 534 | // [dxResource] 535 | void dxResource::destroy() 536 | { 537 | SAFE_RELEASE(resource); 538 | gpuAddress = 0; 539 | srv = nullptr; 540 | uav = nullptr; 541 | rtv = nullptr; 542 | } 543 | 544 | D3D12_RESOURCE_STATES dxResource::changeResourceState(ID3D12GraphicsCommandList* cmdList, D3D12_RESOURCE_STATES newState) 545 | { 546 | assert(resourceState != newState); 547 | D3D12_RESOURCE_STATES prevState = resourceState; 548 | resourceState = newState; 549 | cmdList->ResourceBarrier(1, &Transition(resource, prevState, newState)); 550 | return prevState; 551 | } 552 | 553 | 554 | // [dxBuffer] 555 | void dxBuffer::create(uint64 bufferSize, D3D12_HEAP_TYPE heapType, D3D12_RESOURCE_FLAGS rscFlag, D3D12_RESOURCE_STATES rscState) 556 | { 557 | if(resource != nullptr) 558 | throw Error("destroy() must be called before re-creating."); 559 | 560 | resourceState = rscState; 561 | resource = createCommittedBuffer(bufferSize, heapType, rscFlag, rscState); 562 | gpuAddress = resource->GetGPUVirtualAddress(); 563 | 564 | this->bufferSize = bufferSize; 565 | } 566 | 567 | 568 | // [UploadBuffer] 569 | void UploadBuffer::create(uint64 bufferSize, void* initData) 570 | { 571 | dxBuffer::create(bufferSize, D3D12_HEAP_TYPE_UPLOAD, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_GENERIC_READ); 572 | 573 | if (initData) 574 | { 575 | map(); 576 | memcpy(cpuAddress, initData, bufferSize); 577 | unmap(); 578 | } 579 | } 580 | 581 | void* UploadBuffer::map() 582 | { 583 | if (!cpuAddress) 584 | resource->Map(0, &Range(0), &cpuAddress); 585 | return cpuAddress; 586 | } 587 | 588 | void UploadBuffer::unmap() 589 | { 590 | if (cpuAddress) 591 | { 592 | resource->Unmap(0, nullptr); 593 | cpuAddress = nullptr; 594 | } 595 | } 596 | 597 | 598 | // [DefaultBuffer] 599 | void DefaultBuffer::uploadData( 600 | ID3D12GraphicsCommandList* cmdList, 601 | uint64 copyDstOffset, 602 | uint64 copySize, 603 | const UploadBuffer& srcBuffer, 604 | uint64 srcBufferOffset) 605 | { 606 | assert(copyDstOffset + copySize <= getBufferSize()); 607 | assert(srcBufferOffset + copySize <= srcBuffer.getBufferSize()); 608 | 609 | D3D12_RESOURCE_STATES prevState = changeResourceState(cmdList, D3D12_RESOURCE_STATE_COPY_DEST); 610 | cmdList->CopyBufferRegion( 611 | resource, copyDstOffset, srcBuffer.get(), srcBufferOffset, copySize); 612 | changeResourceState(cmdList, prevState); 613 | } 614 | 615 | 616 | // [DefaultTexture] 617 | void DefaultTexture::create(DXGI_FORMAT format, uint width, uint height, D3D12_RESOURCE_STATES state) 618 | { 619 | if(resource != nullptr) 620 | throw Error("destroy() must be called before re-creating."); 621 | 622 | resourceState = state; 623 | ThrowFailedHR(gDevice->CreateCommittedResource( 624 | &HeapProperty(D3D12_HEAP_TYPE_DEFAULT), 625 | D3D12_HEAP_FLAG_NONE, 626 | &TextureDesc(format, width, height, D3D12_RESOURCE_FLAG_NONE), 627 | resourceState, nullptr, IID_PPV_ARGS(&resource))); 628 | //gpuAddress = resource->GetGPUVirtualAddress(); 629 | 630 | this->format = format; 631 | this->width = width; 632 | this->height = height; 633 | this->rowDataSize = _bpp(format) * width; 634 | this->rowPitch = _align(rowDataSize, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); 635 | this->textureSize = (height - 1) * rowPitch + rowDataSize; 636 | 637 | #ifdef _DEBUG 638 | D3D12_PLACED_SUBRESOURCE_FOOTPRINT textureLayout; 639 | uint64 copyableSize; 640 | gDevice->GetCopyableFootprints(&resource->GetDesc(), 0, 1, 0, 641 | &textureLayout, nullptr, nullptr, ©ableSize); 642 | assert(rowPitch == textureLayout.Footprint.RowPitch && textureSize == copyableSize); 643 | #endif 644 | } 645 | 646 | void DefaultTexture::uploadData( 647 | ID3D12GraphicsCommandList* cmdList, 648 | const UploadBuffer& srcBuffer, 649 | uint64 srcBufferOffset) 650 | { 651 | assert(srcBufferOffset + textureSize <= srcBuffer.getBufferSize()); 652 | 653 | D3D12_TEXTURE_COPY_LOCATION dstDesc; 654 | dstDesc.pResource = resource; 655 | dstDesc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; 656 | dstDesc.SubresourceIndex = 0; 657 | 658 | D3D12_TEXTURE_COPY_LOCATION srcDesc; 659 | srcDesc.pResource = srcBuffer.get(); 660 | srcDesc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; 661 | srcDesc.PlacedFootprint.Footprint.Depth = 1; 662 | srcDesc.PlacedFootprint.Footprint.Format = format; 663 | srcDesc.PlacedFootprint.Footprint.Width = width; 664 | srcDesc.PlacedFootprint.Footprint.Height = height; 665 | srcDesc.PlacedFootprint.Footprint.RowPitch = rowPitch; 666 | srcDesc.PlacedFootprint.Offset = srcBufferOffset; 667 | 668 | D3D12_RESOURCE_STATES prevState = changeResourceState(cmdList, D3D12_RESOURCE_STATE_COPY_DEST); 669 | cmdList->CopyTextureRegion(&dstDesc, 0, 0, 0, &srcDesc, nullptr); 670 | changeResourceState(cmdList, prevState); 671 | } 672 | 673 | 674 | // [ReadbackBuffer] 675 | void ReadbackBuffer::destroy() 676 | { 677 | SAFE_RELEASE(readbackBuffer); 678 | cpuAddress = nullptr; 679 | } 680 | 681 | void ReadbackBuffer::create(uint64 requiredSize) 682 | { 683 | if(readbackBuffer != nullptr) 684 | throw Error("destroy() must be called before re-creating."); 685 | 686 | maxReadbackSize = _align(requiredSize, D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT); 687 | readbackBuffer = createCommittedBuffer(maxReadbackSize, D3D12_HEAP_TYPE_READBACK, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_COPY_DEST); 688 | } 689 | 690 | void* ReadbackBuffer::map() 691 | { 692 | if (!cpuAddress) 693 | readbackBuffer->Map(0, &Range(0), &cpuAddress); 694 | return cpuAddress; 695 | } 696 | 697 | void ReadbackBuffer::unmap() 698 | { 699 | if (cpuAddress) 700 | { 701 | readbackBuffer->Unmap(0, nullptr); 702 | cpuAddress = nullptr; 703 | } 704 | } 705 | 706 | void ReadbackBuffer::readback(ID3D12GraphicsCommandList* cmdList, dxResource& source) 707 | { 708 | D3D12_RESOURCE_DESC desc = source.get()->GetDesc(); 709 | 710 | if (desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER) 711 | { 712 | if(desc.Width > maxReadbackSize) 713 | create(desc.Width * 2); 714 | 715 | D3D12_RESOURCE_STATES prevState = source.changeResourceState(cmdList, D3D12_RESOURCE_STATE_COPY_SOURCE); 716 | cmdList->CopyBufferRegion(readbackBuffer, 0, source.get(), 0, desc.Width); 717 | source.changeResourceState(cmdList, prevState); 718 | } 719 | else if (desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D) 720 | { 721 | D3D12_PLACED_SUBRESOURCE_FOOTPRINT textureLayout; 722 | UINT64 rowPureSize; // width * bytesPerPixel 723 | UINT rowPitch; // align( width * bytesPerPixel, 256 ) 724 | UINT rows; // height 725 | UINT64 copyableSize; // (rows-1) * rowPitch + rowPureSize ( == _textureDataSize(desc.Format, desc.Width, desc.Height) ) 726 | 727 | gDevice->GetCopyableFootprints(&desc, 0, 1, 0, 728 | &textureLayout, &rows, &rowPureSize, ©ableSize); 729 | rowPitch = textureLayout.Footprint.RowPitch; 730 | 731 | if(copyableSize > maxReadbackSize) 732 | create(copyableSize * 2); 733 | 734 | D3D12_RESOURCE_STATES prevState = source.changeResourceState(cmdList, D3D12_RESOURCE_STATE_COPY_SOURCE); 735 | 736 | D3D12_TEXTURE_COPY_LOCATION srcTex; 737 | srcTex.pResource = source.get(); 738 | srcTex.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; 739 | srcTex.SubresourceIndex = 0; 740 | D3D12_TEXTURE_COPY_LOCATION dstBuff; 741 | dstBuff.pResource = readbackBuffer; 742 | dstBuff.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; 743 | dstBuff.PlacedFootprint = textureLayout; 744 | 745 | cmdList->CopyTextureRegion(&dstBuff, 0, 0, 0, &srcTex, nullptr); 746 | 747 | source.changeResourceState(cmdList, prevState); 748 | } 749 | else 750 | { 751 | assert(false); 752 | } 753 | } 754 | 755 | 756 | // [SwapChain] 757 | void SwapChain::destroy() 758 | { 759 | rtvHeap.destroy(); 760 | 761 | for (uint i = 0; i < numBuffers; ++i) 762 | { 763 | SAFE_RELEASE(renderTargetArr[i]); 764 | } 765 | renderTargetArr.clear(); 766 | 767 | SAFE_RELEASE(swapChain); 768 | } 769 | 770 | void SwapChain::present() 771 | { 772 | ThrowFailedHR(swapChain->Present(1, 0)); 773 | currentBufferIdx = swapChain->GetCurrentBackBufferIndex(); 774 | } 775 | 776 | void SwapChain::resize(uint width, uint height) 777 | { 778 | if (bufferW == width && bufferH == height) 779 | return; 780 | 781 | bufferW = width; 782 | bufferH = height; 783 | 784 | for (uint i = 0; i < numBuffers; ++i) 785 | { 786 | renderTargetArr[i]->Release(); 787 | } 788 | 789 | ThrowFailedHR(swapChain->ResizeBuffers(numBuffers, bufferW, bufferH, bufferFormat, flags)); 790 | 791 | for (UINT i = 0; i < numBuffers; ++i) 792 | { 793 | ThrowFailedHR(swapChain->GetBuffer(i, IID_PPV_ARGS(&renderTargetArr[i]))); 794 | 795 | rtvHeap[i].assignRTV(renderTargetArr[i]); 796 | } 797 | 798 | currentBufferIdx = swapChain->GetCurrentBackBufferIndex(); 799 | } 800 | 801 | void SwapChain::create( 802 | ID3D12CommandQueue* cmdQueue, 803 | HWND hwnd, 804 | uint numBackBuffers, 805 | DXGI_FORMAT format, 806 | uint width, 807 | uint height, 808 | bool allowTearing) 809 | { 810 | if(swapChain != nullptr) 811 | throw Error("destroy() must be called before re-creating."); 812 | 813 | numBuffers = numBackBuffers; 814 | bufferW = width; 815 | bufferH = height; 816 | bufferFormat = format; 817 | flags = allowTearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0; 818 | 819 | DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {}; 820 | swapChainDesc.BufferCount = numBuffers; 821 | swapChainDesc.Width = bufferW; 822 | swapChainDesc.Height = bufferH; 823 | swapChainDesc.Format = bufferFormat; 824 | swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 825 | swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; 826 | swapChainDesc.Flags = flags; 827 | swapChainDesc.SampleDesc.Count = 1; 828 | 829 | ThrowFailedHR(getFactory()->CreateSwapChainForHwnd( 830 | cmdQueue, hwnd, &swapChainDesc, nullptr, nullptr, 831 | (IDXGISwapChain1**)(IDXGISwapChain3**)&swapChain)); 832 | 833 | renderTargetArr.resize(numBuffers, nullptr); 834 | rtvHeap.create(numBuffers, D3D12_DESCRIPTOR_HEAP_TYPE_RTV); 835 | 836 | for (uint i = 0; i < numBuffers; ++i) 837 | { 838 | ThrowFailedHR(swapChain->GetBuffer(i, IID_PPV_ARGS(&renderTargetArr[i]))); 839 | 840 | rtvHeap[i].assignRTV(renderTargetArr[i]); 841 | } 842 | 843 | currentBufferIdx = swapChain->GetCurrentBackBufferIndex(); 844 | } 845 | 846 | 847 | // [dxShader] 848 | const LPCWSTR dxShader::csoFolder = L"bin/cso/"; 849 | const LPCWSTR dxShader::hlslFolder = L""; 850 | 851 | static inline uint length(const wchar* wstr) 852 | { 853 | uint idx = 0; 854 | for(const wchar* ch = wstr; *ch != L'\0'; ++ch) 855 | ++idx; 856 | return idx; 857 | } 858 | 859 | static inline void copy(wchar* dst, const wchar* src, uint num) 860 | { 861 | for (uint i = 0; i < num; ++i) 862 | { 863 | dst[i] = src[i]; 864 | } 865 | } 866 | 867 | static inline uint addStr(wchar* dst, const wchar* src1, const wchar* src2) 868 | { 869 | uint l1 = length(src1); 870 | uint l2 = length(src2); 871 | 872 | copy(dst, src1, l1); 873 | copy(dst + l1, src2, l2); 874 | dst[l1 + l2] = L'\0'; 875 | 876 | return l1 + l2; 877 | } 878 | 879 | void dxShader::flush() 880 | { 881 | SAFE_RELEASE(code); 882 | } 883 | 884 | void dxShader::load(LPCWSTR csoFile) 885 | { 886 | wchar filePath[256]; 887 | addStr(filePath, csoFolder, csoFile); 888 | ThrowFailedHR(D3DReadFileToBlob(filePath, &code)); 889 | } 890 | 891 | void dxShader::load(LPCWSTR hlslFile, const char* entryFtn, const char* target) 892 | { 893 | wchar filePath[256]; 894 | addStr(filePath, hlslFolder, hlslFile); 895 | 896 | ID3DBlob* error = nullptr; 897 | UINT compileFlags = 0; 898 | #if defined(_DEBUG) 899 | compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; 900 | #endif 901 | ThrowFailedHR(D3DCompileFromFile(filePath, nullptr, nullptr, entryFtn, target, compileFlags, 0, &code, &error)); 902 | if (error) 903 | { 904 | throw Error((char*)error->GetBufferPointer()); 905 | } 906 | } 907 | 908 | 909 | 910 | 911 | //---------------------From here, DXR related helper---------------------------------// 912 | 913 | ID3D12Resource* createAS( 914 | ID3D12GraphicsCommandList4* cmdList, 915 | const D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS& buildInput, 916 | ID3D12Resource** scrach) 917 | { 918 | ID3D12Device5* device; 919 | gDevice->QueryInterface(&device); 920 | 921 | ID3D12Resource* AS; 922 | 923 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO info; 924 | device->GetRaytracingAccelerationStructurePrebuildInfo(&buildInput, &info); 925 | 926 | *scrach = createCommittedBuffer(info.ScratchDataSizeInBytes, 927 | D3D12_HEAP_TYPE_DEFAULT, 928 | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, 929 | D3D12_RESOURCE_STATE_UNORDERED_ACCESS); 930 | 931 | AS = createCommittedBuffer(info.ResultDataMaxSizeInBytes, 932 | D3D12_HEAP_TYPE_DEFAULT, 933 | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, 934 | D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE); 935 | 936 | D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC asDesc = {}; 937 | asDesc.Inputs = buildInput; 938 | asDesc.DestAccelerationStructureData = AS->GetGPUVirtualAddress(); 939 | asDesc.ScratchAccelerationStructureData = (*scrach)->GetGPUVirtualAddress(); 940 | cmdList->BuildRaytracingAccelerationStructure(&asDesc, 0, nullptr); 941 | 942 | D3D12_RESOURCE_BARRIER uavBarrier = {}; 943 | uavBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; 944 | uavBarrier.UAV.pResource = AS; 945 | cmdList->ResourceBarrier(1, &uavBarrier); 946 | 947 | device->Release(); 948 | 949 | return AS; 950 | } 951 | 952 | 953 | void buildBLAS(ID3D12GraphicsCommandList4* cmdList, 954 | ID3D12Resource** blas, 955 | ID3D12Resource** scrach, 956 | const GPUMesh gpuMeshArr[], 957 | const D3D12_GPU_VIRTUAL_ADDRESS gpuTransformAddressArr[], 958 | uint numMeshes, 959 | uint vertexStride, 960 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS buildFlags) 961 | { 962 | D3D12_RAYTRACING_GEOMETRY_DESC meshDesc = {}; 963 | meshDesc.Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; 964 | meshDesc.Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE; 965 | meshDesc.Triangles.VertexFormat = DXGI_FORMAT_R32G32B32_FLOAT; 966 | meshDesc.Triangles.VertexBuffer.StrideInBytes = vertexStride; 967 | meshDesc.Triangles.IndexFormat = DXGI_FORMAT_R32_UINT; 968 | 969 | Array geoDesc(numMeshes); 970 | for (uint i = 0; i < numMeshes; ++i) 971 | { 972 | geoDesc[i] = meshDesc; 973 | geoDesc[i].Triangles.VertexCount = gpuMeshArr[i].numVertices; 974 | geoDesc[i].Triangles.VertexBuffer.StartAddress = gpuMeshArr[i].vertexBufferVA; 975 | geoDesc[i].Triangles.IndexCount = gpuMeshArr[i].numTridices * 3; 976 | geoDesc[i].Triangles.IndexBuffer = gpuMeshArr[i].tridexBufferVA; 977 | geoDesc[i].Triangles.Transform3x4 = gpuTransformAddressArr[i]; 978 | } 979 | 980 | D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS buildInput = {}; 981 | buildInput.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; 982 | buildInput.NumDescs = numMeshes; 983 | buildInput.Flags = buildFlags; 984 | // Below is necessary at this point. It must be placed before getting prebuild info. 985 | buildInput.pGeometryDescs = geoDesc.data(); 986 | 987 | *blas = createAS(cmdList, buildInput, scrach); 988 | 989 | } 990 | 991 | 992 | void buildTLAS(ID3D12GraphicsCommandList4* cmdList, 993 | ID3D12Resource** tlas, 994 | ID3D12Resource** scrach, 995 | ID3D12Resource** instanceDescArr, 996 | ID3D12Resource* const blasArr[], 997 | const dxTransform transformArr[], 998 | uint numBlas, 999 | uint instanceMultiplier, 1000 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS buildFlags) 1001 | { 1002 | *instanceDescArr = createCommittedBuffer(sizeof(D3D12_RAYTRACING_INSTANCE_DESC) * numBlas); 1003 | 1004 | D3D12_RAYTRACING_INSTANCE_DESC* pInsDescArr; 1005 | (*instanceDescArr)->Map(0, &Range(0), (void**)&pInsDescArr); 1006 | { 1007 | memset(pInsDescArr, 0, sizeof(D3D12_RAYTRACING_INSTANCE_DESC) * numBlas); 1008 | for (uint i = 0; i < numBlas; ++i) 1009 | { 1010 | pInsDescArr[i].InstanceMask = 0xFF; 1011 | pInsDescArr[i].InstanceContributionToHitGroupIndex = i * instanceMultiplier; 1012 | *(dxTransform*)(pInsDescArr[i].Transform) = transformArr[i]; 1013 | pInsDescArr[i].AccelerationStructure = const_cast(blasArr[i])->GetGPUVirtualAddress(); 1014 | } 1015 | } 1016 | (*instanceDescArr)->Unmap(0, nullptr); 1017 | 1018 | D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS buildInput = {}; 1019 | buildInput.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; 1020 | buildInput.NumDescs = numBlas; 1021 | buildInput.Flags = buildFlags; 1022 | // Below is not necessary at this point. It can be placed after getting prebuild info. 1023 | buildInput.InstanceDescs = (*instanceDescArr)->GetGPUVirtualAddress(); 1024 | 1025 | *tlas = createAS(cmdList, buildInput, scrach); 1026 | } 1027 | 1028 | 1029 | void dxAccelerationStructure::build( 1030 | ID3D12GraphicsCommandList4* cmdList, 1031 | const Array& gpuMeshArr, 1032 | const Array& transformArr, 1033 | //const Array& pTransformArr, 1034 | uint vertexStride, 1035 | uint instanceMultiplier, 1036 | AccelerationStructureBuildMode buildMode, 1037 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS buildFlags) 1038 | { 1039 | assert(tlas == nullptr); 1040 | assert(gpuMeshArr.size() == transformArr.size()); 1041 | 1042 | uint numObjs = gpuMeshArr.size(); 1043 | 1044 | Array transformAddressArr(numObjs, 0); 1045 | 1046 | if (buildMode != BLAS_PER_OBJECT_AND_TOP_LEVEL_TRANSFORM) 1047 | { 1048 | uint transformSize = (uint) _align(sizeof(dxTransform), D3D12_RAYTRACING_TRANSFORM3X4_BYTE_ALIGNMENT); 1049 | assert(transformSize==sizeof(dxTransform)); 1050 | 1051 | transformBuff.create(transformSize * numObjs, (void*) transformArr.data()); 1052 | 1053 | D3D12_GPU_VIRTUAL_ADDRESS gpuAddr = transformBuff.getGpuAddress(); 1054 | for (uint objIdx = 0; objIdx < numObjs; ++objIdx) 1055 | { 1056 | transformAddressArr[objIdx] = gpuAddr; 1057 | gpuAddr += transformSize; 1058 | } 1059 | } 1060 | 1061 | uint numObjsPerBlas = (buildMode == ONLY_ONE_BLAS) ? numObjs : 1; 1062 | uint numBottomLevels = (buildMode == ONLY_ONE_BLAS) ? 1 : numObjs; 1063 | blas.resize(numBottomLevels, nullptr); 1064 | scratch.resize(numBottomLevels + 1, nullptr); 1065 | 1066 | for (uint i = 0; i < numBottomLevels; ++i) 1067 | { 1068 | buildBLAS(cmdList, &blas[i], &scratch[i], 1069 | &gpuMeshArr[i], &transformAddressArr[i], numObjsPerBlas, vertexStride, buildFlags); 1070 | } 1071 | 1072 | const Array* topLevelTransform; 1073 | Array identityArr; 1074 | if (buildMode != BLAS_PER_OBJECT_AND_TOP_LEVEL_TRANSFORM) 1075 | { 1076 | identityArr.resize(numBottomLevels, dxTransform(1.0f)); 1077 | topLevelTransform = &identityArr; 1078 | } 1079 | else 1080 | { 1081 | topLevelTransform = &transformArr; 1082 | } 1083 | 1084 | buildTLAS(cmdList, &tlas, &scratch[numBottomLevels], &instances, 1085 | &blas[0], &(*topLevelTransform)[0], numBottomLevels, instanceMultiplier, buildFlags); 1086 | } 1087 | 1088 | void dxAccelerationStructure::destroy() 1089 | { 1090 | flush(); 1091 | for (uint i = 0; i < scratch.size(); ++i) 1092 | { 1093 | SAFE_RELEASE(blas[i]); 1094 | } 1095 | SAFE_RELEASE(tlas); 1096 | blas.clear(); 1097 | } 1098 | 1099 | void dxAccelerationStructure::flush() 1100 | { 1101 | for (uint i = 0; i < scratch.size(); ++i) 1102 | { 1103 | SAFE_RELEASE(scratch[i]); 1104 | } 1105 | SAFE_RELEASE(instances); 1106 | transformBuff.destroy(); 1107 | scratch.clear(); 1108 | } 1109 | 1110 | 1111 | // [RaytracingPipeline] 1112 | void RaytracingPipeline::destroy() 1113 | { 1114 | dxrLib = nullptr; 1115 | globalRS = nullptr; 1116 | maxPayloadSize = 0; 1117 | maxAttributeSize = 8; 1118 | maxRayDepth = 1; 1119 | hitGroupArr.clear(); 1120 | localRSArr.clear(); 1121 | SAFE_RELEASE(sop); 1122 | SAFE_RELEASE(rtPipeline); 1123 | } 1124 | 1125 | void RaytracingPipeline::build() 1126 | { 1127 | if(rtPipeline != nullptr) 1128 | throw Error("destroy() must be called before re-building."); 1129 | 1130 | ID3D12Device5* device; 1131 | gDevice->QueryInterface(&device); 1132 | 1133 | assert(dxrLib != nullptr); 1134 | assert(globalRS != nullptr); 1135 | 1136 | D3D12_STATE_SUBOBJECT subobj = {}; 1137 | Array subobjArr(4 + hitGroupArr.size() + localRSArr.size()*2); 1138 | uint subobjIdx = 0; 1139 | 1140 | D3D12_DXIL_LIBRARY_DESC dxilLibDesc = {}; 1141 | dxilLibDesc.DXILLibrary = dxrLib->getCode(); 1142 | subobj.Type = D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY; 1143 | subobj.pDesc = (void*) &dxilLibDesc; 1144 | subobjArr[subobjIdx++] = subobj; 1145 | 1146 | D3D12_GLOBAL_ROOT_SIGNATURE grsDesc = {}; 1147 | grsDesc.pGlobalRootSignature = globalRS->get(); 1148 | subobj.Type = D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE; 1149 | subobj.pDesc = (void*) &grsDesc; 1150 | subobjArr[subobjIdx++] = subobj; 1151 | 1152 | D3D12_RAYTRACING_PIPELINE_CONFIG pipelineConfig = {}; 1153 | pipelineConfig.MaxTraceRecursionDepth = maxRayDepth; 1154 | subobj.Type = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG; 1155 | subobj.pDesc = (void*) &pipelineConfig; 1156 | subobjArr[subobjIdx++] = subobj; 1157 | 1158 | D3D12_RAYTRACING_SHADER_CONFIG shaderConfig = {}; 1159 | shaderConfig.MaxPayloadSizeInBytes = maxPayloadSize; 1160 | shaderConfig.MaxAttributeSizeInBytes = maxAttributeSize; 1161 | subobj.Type = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG; 1162 | subobj.pDesc = (void*) &shaderConfig; 1163 | subobjArr[subobjIdx++] = subobj; 1164 | 1165 | Array hitGroupDesc(hitGroupArr.size()); 1166 | for (uint i = 0; i < hitGroupArr.size(); ++i) 1167 | { 1168 | hitGroupDesc[i].Type = D3D12_HIT_GROUP_TYPE_TRIANGLES; 1169 | hitGroupDesc[i].ClosestHitShaderImport = hitGroupArr[i].closestHit; 1170 | hitGroupDesc[i].AnyHitShaderImport = hitGroupArr[i].anyHit; 1171 | hitGroupDesc[i].HitGroupExport = hitGroupArr[i].groupName; 1172 | hitGroupDesc[i].IntersectionShaderImport = nullptr; 1173 | subobj.Type = D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP; 1174 | subobj.pDesc = (void*) &hitGroupDesc[i]; 1175 | subobjArr[subobjIdx++] = subobj; 1176 | } 1177 | 1178 | Array lrsDesc(localRSArr.size()); 1179 | Array accociationDesc(localRSArr.size()); 1180 | for (uint i = 0; i < localRSArr.size(); ++i) 1181 | { 1182 | lrsDesc[i].pLocalRootSignature = localRSArr[i].rootSig->get(); 1183 | subobj.Type = D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE; 1184 | subobj.pDesc = (void*) &lrsDesc[i]; 1185 | subobjArr[subobjIdx++] = subobj; 1186 | 1187 | accociationDesc[i].pSubobjectToAssociate = &subobjArr[subobjIdx-1]; 1188 | accociationDesc[i].NumExports = localRSArr[i].exportNames.size(); 1189 | accociationDesc[i].pExports = localRSArr[i].exportNames.data(); 1190 | subobj.Type = D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION; 1191 | subobj.pDesc = (void*) &accociationDesc[i]; 1192 | subobjArr[subobjIdx++] = subobj; 1193 | } 1194 | 1195 | assert(subobjIdx==subobjArr.size()); 1196 | 1197 | D3D12_STATE_OBJECT_DESC desc; 1198 | desc.NumSubobjects = subobjArr.size(); 1199 | desc.pSubobjects = subobjArr.data(); 1200 | desc.Type = D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE; 1201 | ThrowFailedHR(device->CreateStateObject(&desc, IID_PPV_ARGS(&rtPipeline))); 1202 | 1203 | rtPipeline->QueryInterface(IID_PPV_ARGS(&sop)); 1204 | 1205 | device->Release(); 1206 | const_cast(dxrLib)->flush(); 1207 | } 1208 | 1209 | void RaytracingPipeline::bind(ID3D12GraphicsCommandList4* cmdList) 1210 | { 1211 | cmdList->SetPipelineState1(rtPipeline); 1212 | } 1213 | 1214 | ShaderIdentifier* RaytracingPipeline::getIdentifier(LPCWSTR exportName) 1215 | { 1216 | return (ShaderIdentifier*) sop->GetShaderIdentifier(exportName); 1217 | } 1218 | 1219 | 1220 | // [ShaderTable] 1221 | void ShaderTable::create(uint recordSize, uint maxRecords, uint uploaderSizeFactor) 1222 | { 1223 | this->recordSize = recordSize; 1224 | this->maxRecords = maxRecords; 1225 | 1226 | D3D12_RESOURCE_STATES state = 1227 | D3D12_RESOURCE_STATE_COMMON; 1228 | //D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; 1229 | 1230 | SelfBuffer::create(recordSize * maxRecords, uploaderSizeFactor, state); 1231 | } 1232 | 1233 | D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE ShaderTable::getTable() const 1234 | { 1235 | return getSubTable(0, maxRecords); 1236 | } 1237 | 1238 | D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE ShaderTable::getSubTable(uint recordOffset, uint numRecords) const 1239 | { 1240 | D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE ret = {}; 1241 | ret.StartAddress = getGpuAddress() + recordOffset * recordSize; 1242 | ret.StrideInBytes = recordSize; 1243 | ret.SizeInBytes = recordSize * numRecords; 1244 | return ret; 1245 | } 1246 | 1247 | D3D12_GPU_VIRTUAL_ADDRESS_RANGE ShaderTable::getRecord(uint recordOffset) const 1248 | { 1249 | D3D12_GPU_VIRTUAL_ADDRESS_RANGE ret = {}; 1250 | ret.StartAddress = getGpuAddress() + recordOffset * recordSize; 1251 | ret.SizeInBytes = recordSize; 1252 | return ret; 1253 | } -------------------------------------------------------------------------------- /DXRPathTracer/dxHelpers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | #include 4 | #include 5 | 6 | 7 | #define SAFE_DELETE(x) if(x) delete x; x=nullptr 8 | #define SAFE_DELETE_ARR(x) if(x) delete[] x; x=nullptr 9 | #define SAFE_RELEASE(x) if(x) (x)->Release(); x=nullptr 10 | 11 | 12 | extern ID3D12DebugDevice* gDebugDevice; 13 | 14 | 15 | inline void ThrowFailedHR(HRESULT hr) 16 | { 17 | if (FAILED(hr)) 18 | { 19 | throw hr; 20 | } 21 | } 22 | 23 | inline constexpr uint _bpp(DXGI_FORMAT format) //bytes per pixel 24 | { 25 | switch (format) 26 | { 27 | case DXGI_FORMAT_R8G8B8A8_UNORM: 28 | case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: 29 | return 4; 30 | 31 | case DXGI_FORMAT_R32G32B32A32_FLOAT: 32 | return 16; 33 | 34 | default: 35 | assert(true); 36 | } 37 | } 38 | 39 | template 40 | inline constexpr UnsignedType _align(UnsignedType val, PowerOfTwo base) 41 | { 42 | return (val + (UnsignedType)base - 1) & ~((UnsignedType)base - 1); 43 | } 44 | 45 | inline constexpr uint64 _textureDataSize(DXGI_FORMAT format, uint width, uint height) 46 | { 47 | const uint64 rowSize = _bpp(format) * width; 48 | const uint64 rowPitch = _align(rowSize, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); 49 | const uint64 dataSize = (height - 1) * rowPitch + rowSize; 50 | return dataSize; 51 | } 52 | 53 | inline void memcpyPitch(void* dstData, uint64 dstPitch, void* srcData, uint64 srcPitch, uint64 rowSize, uint numRows) 54 | { 55 | assert(dstPitch >= rowSize && srcPitch >= rowSize); 56 | 57 | if (dstPitch == srcPitch) 58 | { 59 | memcpy(dstData, srcData, srcPitch * numRows); 60 | } 61 | else 62 | { 63 | for (uint j = 0; j < numRows; ++j) 64 | { 65 | memcpy( (uint8*) dstData + j * dstPitch, (uint8*) srcData + j * srcPitch, rowSize); 66 | } 67 | } 68 | } 69 | 70 | inline void memcpyPitch(void* dstData, uint64 dstPitch, void* srcData, uint64 srcPitch, uint numRows) 71 | { 72 | memcpyPitch(dstData, dstPitch, srcData, srcPitch, srcPitch, numRows); 73 | } 74 | 75 | inline D3D12_RESOURCE_DESC BufferDesc(uint64 width, D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE) 76 | { 77 | D3D12_RESOURCE_DESC desc = {}; 78 | desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; 79 | desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; 80 | desc.Format = DXGI_FORMAT_UNKNOWN; 81 | desc.Width = width; 82 | desc.Height = 1; 83 | desc.DepthOrArraySize = 1; 84 | desc.MipLevels = 1; 85 | desc.SampleDesc.Count = 1; 86 | desc.Flags = flags; 87 | return desc; 88 | } 89 | 90 | inline D3D12_RESOURCE_DESC TextureDesc(DXGI_FORMAT format, uint width, uint height, D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE) 91 | { 92 | D3D12_RESOURCE_DESC desc = {}; 93 | desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; 94 | desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; 95 | desc.Format = format; 96 | desc.Width = width; 97 | desc.Height = height; 98 | desc.DepthOrArraySize = 1; 99 | desc.MipLevels = 1; 100 | desc.SampleDesc.Count = 1; 101 | desc.SampleDesc.Quality = 0; 102 | desc.Flags = flags; 103 | return desc; 104 | } 105 | 106 | inline D3D12_HEAP_PROPERTIES HeapProperty(D3D12_HEAP_TYPE type) 107 | { 108 | D3D12_HEAP_PROPERTIES heapProp = {}; 109 | heapProp.Type = type; 110 | return heapProp; 111 | } 112 | 113 | inline D3D12_RANGE Range(SIZE_T end, SIZE_T begin = 0) 114 | { 115 | D3D12_RANGE range; 116 | range.Begin = begin; 117 | range.End = end; 118 | return range; 119 | } 120 | 121 | inline D3D12_RESOURCE_BARRIER Transition(ID3D12Resource* resource, 122 | D3D12_RESOURCE_STATES stateBefore, D3D12_RESOURCE_STATES stateAfter) 123 | { 124 | D3D12_RESOURCE_BARRIER barrier = {}; 125 | barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; 126 | barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; 127 | barrier.Transition.pResource = resource; 128 | barrier.Transition.StateBefore = stateBefore; 129 | barrier.Transition.StateAfter = stateAfter; 130 | barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; 131 | return barrier; 132 | } 133 | 134 | inline D3D12_INPUT_ELEMENT_DESC VertexAttribute(const char* semantic, DXGI_FORMAT format, uint offset=D3D12_APPEND_ALIGNED_ELEMENT) 135 | { 136 | D3D12_INPUT_ELEMENT_DESC vertexLayout = {}; 137 | vertexLayout.SemanticName = semantic; 138 | vertexLayout.Format = format; 139 | vertexLayout.AlignedByteOffset = offset; 140 | vertexLayout.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; 141 | return vertexLayout; 142 | } 143 | 144 | inline D3D12_STATIC_SAMPLER_DESC StaticSampler(uint registerBase=0, uint registerSpace=0, D3D12_SHADER_VISIBILITY visible = D3D12_SHADER_VISIBILITY_ALL) 145 | { 146 | D3D12_STATIC_SAMPLER_DESC sampler = {}; 147 | sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR; 148 | sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER; 149 | sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER; 150 | sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER; 151 | 152 | sampler.MipLODBias = 0.0f; 153 | sampler.MaxAnisotropy = 1; 154 | sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; 155 | sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK; 156 | sampler.MinLOD = 0; 157 | sampler.MaxLOD = D3D12_FLOAT32_MAX; 158 | 159 | sampler.ShaderRegister = registerBase; 160 | sampler.RegisterSpace = registerSpace; 161 | sampler.ShaderVisibility = visible; 162 | 163 | return sampler; 164 | } 165 | 166 | inline D3D12_GPU_DESCRIPTOR_HANDLE operator+(const D3D12_GPU_DESCRIPTOR_HANDLE& cpuAddr, uint offset) 167 | { 168 | return D3D12_GPU_DESCRIPTOR_HANDLE{ cpuAddr.ptr + offset }; 169 | } 170 | 171 | inline D3D12_CPU_DESCRIPTOR_HANDLE operator+(const D3D12_CPU_DESCRIPTOR_HANDLE& cpuAddr, uint offset) 172 | { 173 | return D3D12_CPU_DESCRIPTOR_HANDLE{ cpuAddr.ptr + offset }; 174 | } 175 | 176 | IDXGIFactory2* getFactory(); 177 | 178 | IDXGIAdapter* getRTXAdapter(); 179 | 180 | ID3D12Device* createDX12Device(IDXGIAdapter* adapter); 181 | 182 | D3D12_GRAPHICS_PIPELINE_STATE_DESC Graphics_Pipeline_Desc( 183 | D3D12_INPUT_LAYOUT_DESC inputLayout, 184 | ID3D12RootSignature* rootSig, 185 | D3D12_SHADER_BYTECODE vertexShader, 186 | D3D12_SHADER_BYTECODE pixelShader, 187 | DXGI_FORMAT renderTargetFormat, 188 | uint numRenderTargets = 1); 189 | 190 | ID3D12Resource* createCommittedBuffer( 191 | uint64 bufferSize, 192 | D3D12_HEAP_TYPE heapType = D3D12_HEAP_TYPE_UPLOAD, 193 | D3D12_RESOURCE_FLAGS resourceFlags = D3D12_RESOURCE_FLAG_NONE, 194 | D3D12_RESOURCE_STATES resourceStates = D3D12_RESOURCE_STATE_GENERIC_READ); 195 | 196 | 197 | class ResourceUploader; 198 | class DescriptorHeap; 199 | class Descriptor; 200 | class dxResource; 201 | 202 | enum class DescriptorType 203 | { 204 | SRV, UAV, CBV, RTV, DSV, Sampler 205 | }; 206 | 207 | 208 | class Descriptor 209 | { 210 | D3D12_CPU_DESCRIPTOR_HANDLE cpuAddr; 211 | D3D12_GPU_DESCRIPTOR_HANDLE gpuAddr; 212 | 213 | friend class DescriptorHeap; 214 | Descriptor(D3D12_CPU_DESCRIPTOR_HANDLE cpuAddr, D3D12_GPU_DESCRIPTOR_HANDLE gpuAddr) 215 | : cpuAddr(cpuAddr), gpuAddr(gpuAddr) {} 216 | public: 217 | Descriptor() = delete; 218 | D3D12_CPU_DESCRIPTOR_HANDLE getCpuHandle() const { return cpuAddr; } 219 | D3D12_GPU_DESCRIPTOR_HANDLE getGpuHandle() const { return gpuAddr; } 220 | 221 | void assignSRV(ID3D12Resource* resource, const D3D12_SHADER_RESOURCE_VIEW_DESC* desc); 222 | void assignUAV(ID3D12Resource* resource, const D3D12_UNORDERED_ACCESS_VIEW_DESC* desc, ID3D12Resource* counter=nullptr); 223 | void assignRTV(ID3D12Resource* resource, const D3D12_RENDER_TARGET_VIEW_DESC* desc = nullptr); 224 | void assignCBV(const D3D12_CONSTANT_BUFFER_VIEW_DESC* desc); 225 | 226 | void assignSRV(dxResource& resource, const D3D12_SHADER_RESOURCE_VIEW_DESC* desc); 227 | void assignUAV(dxResource& resource, const D3D12_UNORDERED_ACCESS_VIEW_DESC* desc, ID3D12Resource* counter=nullptr); 228 | void assignRTV(dxResource& resource, const D3D12_RENDER_TARGET_VIEW_DESC* desc = nullptr); 229 | }; 230 | 231 | 232 | class DescriptorHeap 233 | { 234 | ID3D12DescriptorHeap* heap = nullptr; 235 | Array descriptorArr; 236 | 237 | public: 238 | ~DescriptorHeap() { destroy(); } 239 | void destroy(); 240 | 241 | DescriptorHeap() {} 242 | DescriptorHeap(uint maxDescriptors, D3D12_DESCRIPTOR_HEAP_TYPE heapType = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV) { 243 | create(maxDescriptors, heapType); 244 | } 245 | void create(uint maxDescriptors, D3D12_DESCRIPTOR_HEAP_TYPE heapType = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); 246 | 247 | ID3D12DescriptorHeap* get() const { 248 | return heap; 249 | } 250 | Descriptor& operator[] (uint heapIdx) { 251 | assert(heapIdx < descriptorArr.size()); 252 | return descriptorArr[heapIdx]; 253 | } 254 | const Descriptor& operator[] (uint heapIdx) const { 255 | assert(heapIdx < descriptorArr.size()); 256 | return descriptorArr[heapIdx]; 257 | } 258 | 259 | void bind(ID3D12GraphicsCommandList* cmdList); 260 | }; 261 | 262 | 263 | class RootParameter 264 | { 265 | protected: 266 | D3D12_ROOT_PARAMETER param = {}; 267 | 268 | friend class RootSignature; 269 | virtual ~RootParameter() {} // Only RootSignature can delete it. 270 | 271 | public: 272 | virtual void bindCompute(ID3D12GraphicsCommandList* cmdList, uint paramIdx) const = 0; 273 | virtual void bindGraphics(ID3D12GraphicsCommandList* cmdList, uint paramIdx) const = 0; 274 | }; 275 | 276 | 277 | class RootTable : public RootParameter 278 | { 279 | D3D12_GPU_DESCRIPTOR_HANDLE tableStart; 280 | Array rangeArr; 281 | 282 | public: 283 | RootTable() = delete; 284 | RootTable(const char* code) { create(code); } 285 | RootTable(const char* code, D3D12_GPU_DESCRIPTOR_HANDLE handle) { create(code); setTableStart(handle); } 286 | void operator=(D3D12_GPU_DESCRIPTOR_HANDLE handle) { setTableStart(handle); } 287 | 288 | void setTableStart(D3D12_GPU_DESCRIPTOR_HANDLE handle) { 289 | tableStart = handle; 290 | } 291 | 292 | void create(const char* code); 293 | void bindCompute(ID3D12GraphicsCommandList* cmdList, uint paramIdx) const; 294 | void bindGraphics(ID3D12GraphicsCommandList* cmdList, uint paramIdx) const; 295 | }; 296 | 297 | 298 | class RootPointer : public RootParameter 299 | { 300 | D3D12_GPU_VIRTUAL_ADDRESS resourceAddress; 301 | 302 | public: 303 | RootPointer() = delete; 304 | RootPointer(const char* code) { create(code); } 305 | RootPointer(const char* code, D3D12_GPU_VIRTUAL_ADDRESS address){ create(code); setResourceAddress(address); } 306 | void operator=(D3D12_GPU_VIRTUAL_ADDRESS address) { setResourceAddress(address); } 307 | 308 | void setResourceAddress(D3D12_GPU_VIRTUAL_ADDRESS address) { 309 | resourceAddress = address; 310 | } 311 | 312 | void create(const char* code); 313 | void bindCompute(ID3D12GraphicsCommandList* cmdList, uint paramIdx) const; 314 | void bindGraphics(ID3D12GraphicsCommandList* cmdList, uint paramIdx) const; 315 | }; 316 | 317 | 318 | template 319 | class RootConstants : public RootParameter 320 | { 321 | Array _32BitConsts; 322 | 323 | public: 324 | RootConstants() = delete; 325 | RootConstants(const char* code) { create(code); } 326 | RootConstants(const char* code, const T& constants) { create(code); setConstants(constants); } 327 | void operator=(const T& constants) { setConstants(constants); } 328 | 329 | void setConstants(const T& constants) { 330 | memcpy(_32BitConsts.data(), &constants, sizeof(T)); 331 | } 332 | 333 | void create(const char* code) { 334 | _32BitConsts.resize((sizeof(T) + 3) / 4); 335 | 336 | void createRootConstantsParam(D3D12_ROOT_PARAMETER& param, const char* code, uint num32BitConsts); 337 | createRootConstantsParam(param, code, _32BitConsts.size()); 338 | } 339 | 340 | void bindCompute(ID3D12GraphicsCommandList* cmdList, uint paramIdx) const { 341 | cmdList->SetComputeRoot32BitConstants(paramIdx, _32BitConsts.size(), _32BitConsts.data(), 0); 342 | } 343 | void bindGraphics(ID3D12GraphicsCommandList* cmdList, uint paramIdx) const { 344 | cmdList->SetGraphicsRoot32BitConstants(paramIdx, _32BitConsts.size(), _32BitConsts.data(), 0); 345 | } 346 | }; 347 | 348 | 349 | class RootSignature 350 | { 351 | ID3D12RootSignature* rootSig = nullptr; 352 | Array pRootParamArr; 353 | 354 | public: 355 | ~RootSignature(); 356 | RootSignature() {} 357 | ID3D12RootSignature* get() const { 358 | return rootSig; 359 | } 360 | void resize(uint size) { 361 | assert(rootSig == nullptr); // It can be called before build. 362 | pRootParamArr.resize(size, nullptr); 363 | } 364 | void push_back(RootParameter* param) { 365 | assert(rootSig == nullptr); // It can be called before build. 366 | pRootParamArr.push_back(param); 367 | } 368 | RootParameter*& operator[](uint paramIdx) { 369 | assert(paramIdx < pRootParamArr.size()); 370 | return pRootParamArr[paramIdx]; 371 | } 372 | RootParameter* const& operator[](uint paramIdx) const { 373 | assert(paramIdx < pRootParamArr.size()); 374 | return pRootParamArr[paramIdx]; 375 | } 376 | 377 | void build(D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE); 378 | void build(const D3D12_STATIC_SAMPLER_DESC& sampler, D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE); 379 | void build(const Array& samplerArr, D3D12_ROOT_SIGNATURE_FLAGS flags = D3D12_ROOT_SIGNATURE_FLAG_NONE); 380 | void bindCompute(ID3D12GraphicsCommandList* cmdList) const; 381 | void bindGraphics(ID3D12GraphicsCommandList* cmdList) const; 382 | }; 383 | 384 | 385 | class dxResource 386 | { 387 | const Descriptor* srv = nullptr; 388 | const Descriptor* uav = nullptr; 389 | const Descriptor* rtv = nullptr; 390 | 391 | protected: 392 | ID3D12Resource* resource = nullptr; 393 | D3D12_RESOURCE_STATES resourceState; 394 | D3D12_GPU_VIRTUAL_ADDRESS gpuAddress = 0; 395 | 396 | public: 397 | virtual ~dxResource() { destroy(); } 398 | void destroy(); 399 | 400 | ID3D12Resource* get() const { return resource; } 401 | D3D12_GPU_VIRTUAL_ADDRESS getGpuAddress() const { return gpuAddress; } 402 | const Descriptor* getSRV() const { return srv; } 403 | const Descriptor* getUAV() const { return uav; } 404 | const Descriptor* getRTV() const { return rtv; } 405 | void setSRV(Descriptor* srv) { this->srv = srv; } 406 | void setUAV(Descriptor* uav) { this->uav = uav; } 407 | void setRTV(Descriptor* rtv) { this->rtv = rtv; } 408 | 409 | D3D12_RESOURCE_STATES changeResourceState(ID3D12GraphicsCommandList* cmdList, D3D12_RESOURCE_STATES newState); 410 | }; 411 | 412 | 413 | class dxBuffer : public dxResource 414 | { 415 | uint64 bufferSize = 0; 416 | 417 | public: 418 | ~dxBuffer() { partialDestroy(); } 419 | void destroy() { partialDestroy(); dxResource::destroy(); } 420 | void partialDestroy() { bufferSize = 0; } 421 | 422 | dxBuffer() {} 423 | dxBuffer(uint64 buffSize, D3D12_HEAP_TYPE heapType, D3D12_RESOURCE_FLAGS rscFlag, D3D12_RESOURCE_STATES rscState) { 424 | create(buffSize, heapType, rscFlag, rscState); 425 | } 426 | void create(uint64 bufferSize, D3D12_HEAP_TYPE heapType, D3D12_RESOURCE_FLAGS rscFlag, D3D12_RESOURCE_STATES rscState); 427 | 428 | uint64 getBufferSize() const { return bufferSize; } 429 | }; 430 | 431 | 432 | class UnorderAccessBuffer : public dxBuffer 433 | { 434 | public: 435 | ~UnorderAccessBuffer() { partialDestroy(); } 436 | void destroy() { partialDestroy(); dxBuffer::destroy(); } 437 | void partialDestroy() {} 438 | 439 | UnorderAccessBuffer() {} 440 | UnorderAccessBuffer(uint64 bufferSize, D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATE_UNORDERED_ACCESS) { 441 | create(bufferSize, state); 442 | } 443 | void create(uint64 bufferSize, D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATE_UNORDERED_ACCESS) { 444 | dxBuffer::create(bufferSize, D3D12_HEAP_TYPE_DEFAULT, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, state); 445 | } 446 | }; 447 | 448 | 449 | class UploadBuffer : public dxBuffer 450 | { 451 | void* cpuAddress = nullptr; 452 | 453 | public: 454 | ~UploadBuffer() { partialDestroy(); } 455 | void destroy() { partialDestroy(); dxBuffer::destroy(); } 456 | void partialDestroy() { cpuAddress = nullptr; } 457 | 458 | UploadBuffer() {} 459 | UploadBuffer(uint64 bufferSize, void* initData = nullptr) { 460 | create(bufferSize, initData); 461 | } 462 | void create(uint64 bufferSize, void* initData = nullptr); 463 | 464 | void* map(); 465 | void unmap(); 466 | }; 467 | 468 | 469 | class DefaultBuffer : public dxBuffer 470 | { 471 | public: 472 | ~DefaultBuffer() { partialDestroy(); } 473 | void destroy() { partialDestroy(); dxBuffer::destroy(); } 474 | void partialDestroy() {} 475 | 476 | DefaultBuffer() {} 477 | DefaultBuffer(uint64 bufferSize, D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATE_COMMON) { 478 | create(bufferSize, state); 479 | } 480 | void create(uint64 bufferSize, D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATE_COMMON) { 481 | dxBuffer::create(bufferSize, D3D12_HEAP_TYPE_DEFAULT, D3D12_RESOURCE_FLAG_NONE, state); 482 | } 483 | 484 | void uploadData(ID3D12GraphicsCommandList* cmdList, 485 | const UploadBuffer& srcBuffer, uint64 srcBufferOffset = 0) { 486 | uploadData(cmdList, 0, getBufferSize(), srcBuffer, srcBufferOffset); 487 | } 488 | void uploadData(ID3D12GraphicsCommandList* cmdList, uint64 copyDstOffset, uint64 copySize, 489 | const UploadBuffer& srcBuffer, uint64 srcBufferOffset); 490 | }; 491 | 492 | 493 | class SelfBuffer : public DefaultBuffer 494 | { 495 | UploadBuffer uploader; 496 | 497 | public: 498 | ~SelfBuffer() { partialDestroy(); } 499 | void destroy() { partialDestroy(); DefaultBuffer::destroy(); uploader.destroy(); } 500 | void partialDestroy() {} 501 | 502 | SelfBuffer() {} 503 | SelfBuffer(uint64 bufferSize, uint uploaderSizeFactor = 1, D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATE_COMMON) { 504 | create(bufferSize, uploaderSizeFactor, state); 505 | } 506 | void create(uint64 bufferSize, uint uploaderSizeFactor = 1, D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATE_COMMON) { 507 | DefaultBuffer::create(bufferSize, state); 508 | uploader.create(bufferSize * uploaderSizeFactor); 509 | } 510 | 511 | void* map() { return uploader.map(); } 512 | void unmap() { uploader.unmap(); } 513 | void uploadData(ID3D12GraphicsCommandList* cmdList, uint64 uploaderOffset = 0) { 514 | DefaultBuffer::uploadData(cmdList, uploader, uploaderOffset); 515 | } 516 | void uploadData(ID3D12GraphicsCommandList* cmdList, uint64 copyDstOffset, uint64 copySize, uint64 uploaderOffset) { 517 | DefaultBuffer::uploadData(cmdList, copyDstOffset, copySize, uploader, uploaderOffset); 518 | } 519 | }; 520 | 521 | 522 | class DefaultTexture : public dxResource 523 | { 524 | DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; 525 | uint width = 0; 526 | uint height = 0; 527 | uint rowDataSize = 0; // width * bytesPerPixel 528 | uint rowPitch = 0; // align( rowSize, 256 ) 529 | uint64 textureSize = 0; // (height - 1) * rowPitch + rowSize 530 | 531 | public: 532 | ~DefaultTexture() { partialDestroy(); } 533 | void destroy() { partialDestroy(); dxResource::destroy(); } 534 | void partialDestroy() { 535 | format = DXGI_FORMAT_UNKNOWN; 536 | width = height = rowDataSize = rowPitch = 0; 537 | textureSize = 0; 538 | } 539 | 540 | DefaultTexture() {} 541 | DefaultTexture(DXGI_FORMAT format, uint width, uint height, D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATE_COMMON) { 542 | create(format, width, height, state); 543 | } 544 | void create(DXGI_FORMAT format, uint width, uint height, D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATE_COMMON); 545 | 546 | DXGI_FORMAT getFormat() const { return format; } 547 | uint getWidth() const { return width; } 548 | uint getHeight() const { return height; } 549 | uint getRowDataSize() const { return rowDataSize; } 550 | uint getRowPitch() const { return rowPitch; } 551 | uint64 getTextureSize() const { return textureSize; } 552 | 553 | void uploadData(ID3D12GraphicsCommandList* cmdList, 554 | const UploadBuffer& srcBuffer, uint64 srcBufferOffset = 0); 555 | }; 556 | 557 | 558 | class ReadbackBuffer 559 | { 560 | protected: 561 | ID3D12Resource* readbackBuffer = nullptr; 562 | void* cpuAddress = nullptr; 563 | uint64 maxReadbackSize; 564 | 565 | public: 566 | ~ReadbackBuffer() { destroy(); } 567 | ReadbackBuffer() {} 568 | ReadbackBuffer(uint64 requiredSize) { create(requiredSize); } 569 | 570 | void destroy(); 571 | void create(uint64 requiredSize); 572 | void* map(); 573 | void unmap(); 574 | void readback(ID3D12GraphicsCommandList* cmdList, dxResource& source); 575 | }; 576 | 577 | 578 | class SwapChain { 579 | IDXGISwapChain3* swapChain = nullptr; 580 | uint numBuffers = 0; 581 | uint currentBufferIdx; 582 | DXGI_FORMAT bufferFormat; 583 | uint bufferW; 584 | uint bufferH; 585 | uint flags; 586 | 587 | Array renderTargetArr; 588 | DescriptorHeap rtvHeap; 589 | 590 | public: 591 | DXGI_FORMAT getBufferFormat() const { return bufferFormat; } 592 | uint getCurrentBufferIdx() const { return currentBufferIdx; } 593 | ID3D12Resource* getRenderTatget() const { return renderTargetArr[currentBufferIdx]; } 594 | D3D12_CPU_DESCRIPTOR_HANDLE getRtv() const { return rtvHeap[currentBufferIdx].getCpuHandle(); } 595 | 596 | ~SwapChain() { destroy(); } 597 | 598 | void present(); 599 | void resize(uint width, uint height); 600 | void destroy(); 601 | void create( 602 | ID3D12CommandQueue* cmdQueue, 603 | HWND hwnd, 604 | uint numBackBuffers, 605 | DXGI_FORMAT format, 606 | uint width, 607 | uint height, 608 | bool allowTearing = false); 609 | }; 610 | 611 | 612 | class dxShader 613 | { 614 | ID3DBlob* code; 615 | 616 | static const LPCWSTR csoFolder; 617 | static const LPCWSTR hlslFolder; 618 | 619 | public: 620 | ~dxShader() { flush(); } 621 | dxShader() {} 622 | dxShader(LPCWSTR csoFile) { load(csoFile); } 623 | dxShader(LPCWSTR hlslFile, const char* entryFtn, const char* target) { load(hlslFile, entryFtn, target); } 624 | 625 | D3D12_SHADER_BYTECODE getCode() const { 626 | D3D12_SHADER_BYTECODE shadercode; 627 | shadercode.pShaderBytecode = code->GetBufferPointer(); 628 | shadercode.BytecodeLength = code->GetBufferSize(); 629 | return shadercode; 630 | } 631 | 632 | void flush(); 633 | void load(LPCWSTR csoFile); 634 | void load(LPCWSTR hlslFile, const char* entryFtn, const char* target); 635 | }; 636 | 637 | 638 | class BinaryFence 639 | { 640 | ID3D12Fence* mFence; 641 | HANDLE mFenceEvent = nullptr; 642 | 643 | enum FenceValue { 644 | zero = 0, one = 1 645 | }; 646 | 647 | public: 648 | 649 | ~BinaryFence() 650 | { 651 | if(mFenceEvent) 652 | CloseHandle(mFenceEvent); 653 | SAFE_RELEASE(mFence); 654 | } 655 | 656 | void create(ID3D12Device* device) 657 | { 658 | ThrowFailedHR(device->CreateFence(zero, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&mFence))); 659 | mFenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); 660 | } 661 | 662 | void waitCommandQueue(ID3D12CommandQueue* cmdQueue) 663 | { 664 | ThrowFailedHR(cmdQueue->Signal(mFence, one)); 665 | 666 | if (mFence->GetCompletedValue() != one) 667 | { 668 | ThrowFailedHR(mFence->SetEventOnCompletion(one, mFenceEvent)); 669 | WaitForSingleObject(mFenceEvent, INFINITE); 670 | } 671 | 672 | ThrowFailedHR(cmdQueue->Signal(mFence, zero)); 673 | } 674 | }; 675 | 676 | 677 | //---------------------From here, DXR related helper---------------------------------// 678 | 679 | struct GPUMesh 680 | { 681 | UINT numVertices; 682 | D3D12_GPU_VIRTUAL_ADDRESS vertexBufferVA; 683 | UINT numTridices; 684 | D3D12_GPU_VIRTUAL_ADDRESS tridexBufferVA; 685 | }; 686 | 687 | 688 | using pFloat4 = float(*)[4]; 689 | struct dxTransform 690 | { 691 | float mat[3][4]; 692 | dxTransform() {} 693 | dxTransform(float scala) : mat{} 694 | { 695 | mat[0][0] = mat[1][1] = mat[2][2] = scala; 696 | } 697 | void operator=(const Transform& tm) 698 | { 699 | *this = *(dxTransform* ) &tm; 700 | } 701 | pFloat4 data() { return mat; } 702 | }; 703 | 704 | 705 | void buildBLAS(ID3D12GraphicsCommandList4* cmdList, 706 | ID3D12Resource** blas, 707 | ID3D12Resource** scrach, 708 | const GPUMesh gpuMeshArr[], 709 | const D3D12_GPU_VIRTUAL_ADDRESS gpuTransformAddressArr[], 710 | uint numMeshes, 711 | uint vertexStride, 712 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS buildFlags); 713 | 714 | 715 | void buildTLAS(ID3D12GraphicsCommandList4* cmdList, 716 | ID3D12Resource** tlas, 717 | ID3D12Resource** scrach, 718 | ID3D12Resource** instanceDescArr, 719 | ID3D12Resource* const blasArr[], 720 | //const ID3D12Resource* blasArr[], 721 | const dxTransform transformArr[], 722 | uint numBlas, 723 | uint instanceMultiplier, 724 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS buildFlags); 725 | 726 | 727 | enum AccelerationStructureBuildMode{ 728 | ONLY_ONE_BLAS, 729 | BLAS_PER_OBJECT_AND_BOTTOM_LEVEL_TRANSFORM, 730 | BLAS_PER_OBJECT_AND_TOP_LEVEL_TRANSFORM 731 | }; 732 | 733 | 734 | class dxAccelerationStructure 735 | { 736 | Array blas; 737 | ID3D12Resource* tlas = nullptr; 738 | Array scratch; 739 | ID3D12Resource* instances = nullptr; 740 | UploadBuffer transformBuff; 741 | 742 | public: 743 | ~dxAccelerationStructure() { destroy(); } 744 | ID3D12Resource* get() const { return tlas; } 745 | D3D12_GPU_VIRTUAL_ADDRESS getGpuAddress() const { return tlas->GetGPUVirtualAddress(); } 746 | void flush(); 747 | void destroy(); 748 | void build(ID3D12GraphicsCommandList4* cmdList, 749 | const Array& gpuMeshArr, 750 | const Array& transformArr, 751 | //const Array& pTransformArr, 752 | uint vertexStride, 753 | uint instanceMultiplier, 754 | AccelerationStructureBuildMode buildMode, 755 | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS buildFlags); 756 | }; 757 | 758 | 759 | struct HitGroup 760 | { 761 | LPCWSTR groupName = nullptr; 762 | LPCWSTR closestHit = nullptr; 763 | LPCWSTR anyHit = nullptr; 764 | HitGroup() = delete; 765 | HitGroup(LPCWSTR groupName, LPCWSTR cloestHit, LPCWSTR anyHit) 766 | : groupName(groupName), closestHit(cloestHit), anyHit(anyHit) {} 767 | }; 768 | 769 | 770 | struct LocalRootSignature 771 | { 772 | const RootSignature* rootSig = nullptr; 773 | Array exportNames; 774 | LocalRootSignature() = delete; 775 | LocalRootSignature(const RootSignature* rootSig, const Array& exportNames) 776 | : rootSig(rootSig), exportNames(exportNames) {} 777 | 778 | LocalRootSignature(const LocalRootSignature& lrs) 779 | : rootSig(lrs.rootSig), exportNames(lrs.exportNames) {} 780 | LocalRootSignature(LocalRootSignature&& lrs) 781 | : rootSig(lrs.rootSig), exportNames(move2(lrs.exportNames)) {} 782 | }; 783 | 784 | 785 | struct ShaderIdentifier 786 | { 787 | uint8 identifier[D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES]; 788 | }; 789 | 790 | 791 | class RaytracingPipeline 792 | { 793 | ID3D12StateObject* rtPipeline = nullptr; 794 | ID3D12StateObjectProperties* sop = nullptr; 795 | const dxShader* dxrLib = nullptr; 796 | const RootSignature* globalRS = nullptr; 797 | Array hitGroupArr; 798 | Array localRSArr; 799 | uint maxPayloadSize = 0; 800 | uint maxAttributeSize = 8; 801 | uint maxRayDepth = 2; 802 | 803 | public: 804 | ~RaytracingPipeline() { destroy(); } 805 | 806 | void destroy(); 807 | void setDXRLib(const dxShader* DXRShader) { 808 | assert(rtPipeline == nullptr); 809 | dxrLib = DXRShader; 810 | } 811 | void setGlobalRootSignature(RootSignature* globalRs) { 812 | assert(rtPipeline == nullptr); 813 | globalRS = globalRs; 814 | } 815 | void setMaxRayDepth(uint depth) { 816 | assert(rtPipeline == nullptr); 817 | maxRayDepth = depth; 818 | } 819 | void setMaxPayloadSize(uint size) { 820 | assert(rtPipeline == nullptr); 821 | maxPayloadSize = size; 822 | } 823 | void setMaxAttributeSize(uint size) { 824 | assert(rtPipeline == nullptr); 825 | maxAttributeSize = size; 826 | } 827 | void addHitGroup(HitGroup hitGp) { 828 | assert(rtPipeline == nullptr); 829 | hitGroupArr.push_back(hitGp); 830 | } 831 | void addLocalRootSignature(const LocalRootSignature& localRs) { 832 | assert(rtPipeline == nullptr); 833 | localRSArr.push_back(localRs); 834 | } 835 | void addLocalRootSignature(LocalRootSignature&& localRs) { 836 | assert(rtPipeline == nullptr); 837 | localRSArr.push_back(move2(localRs)); 838 | } 839 | 840 | void build(); 841 | void bind(ID3D12GraphicsCommandList4* cmdList); 842 | ShaderIdentifier* getIdentifier(LPCWSTR exportName); 843 | }; 844 | 845 | 846 | class ShaderTable : public SelfBuffer 847 | { 848 | protected: 849 | uint recordSize = 0; 850 | uint maxRecords = 0; 851 | 852 | public: 853 | ~ShaderTable() { partialDestroy(); } 854 | void destroy() { partialDestroy(); SelfBuffer::destroy(); } 855 | void partialDestroy() { recordSize = maxRecords = 0; } 856 | 857 | ShaderTable() {} 858 | ShaderTable(uint recordSize, uint maxRecords, uint uploaderSizeFactor = 1) { 859 | create(recordSize, maxRecords, uploaderSizeFactor); 860 | } 861 | void create(uint recordSize, uint maxRecords, uint uploaderSizeFactor = 1); 862 | 863 | D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE getTable() const; 864 | D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE getSubTable(uint recordOffset, uint numRecords) const; 865 | D3D12_GPU_VIRTUAL_ADDRESS_RANGE getRecord(uint recordOffset) const; 866 | }; -------------------------------------------------------------------------------- /DXRPathTracer/generateMesh.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meta-plane/DXR-PathTracer/1d8a9e03b357c551b3db75ba032a44e4107d4327/DXRPathTracer/generateMesh.cpp -------------------------------------------------------------------------------- /DXRPathTracer/generateMesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Mesh.h" 3 | #include "basic_types.h" 4 | 5 | enum FaceDir { unknown=-1, down, up, front, back, left, right }; 6 | 7 | Mesh generateParallelogramMesh(const float3& corner, const float3& side1, const float3& side2); 8 | Mesh generateRectangleMesh(const float3& center, const float3& size, FaceDir dir); 9 | Mesh generateBoxMesh(const float3& lowerCroner, const float3& upperCroner); 10 | Mesh generateCubeMesh(const float3& center, const float3& size, bool bottomCenter=false); 11 | Mesh generateSphereMesh(const float3& center, float radius, uint numSegmentsInMeridian=50, uint numSegmentsInEquator=100); -------------------------------------------------------------------------------- /DXRPathTracer/loadMesh.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #define TINYOBJLOADER_IMPLEMENTATION 3 | #include "tiny_obj_loader.h" 4 | #include "Mesh.h" 5 | #include 6 | 7 | class compTynyIdx 8 | { 9 | public: 10 | bool operator() (const tinyobj::index_t& a, const tinyobj::index_t& b) const 11 | { 12 | return 13 | (a.vertex_index != b.vertex_index) ? (a.vertex_index < b.vertex_index) : 14 | (a.normal_index != b.normal_index) ? (a.normal_index < b.normal_index) : (a.texcoord_index < b.texcoord_index); 15 | } 16 | 17 | }; 18 | 19 | Mesh loadMeshFromOBJFile(const char* filename, bool optimizeVertexxCount) 20 | { 21 | tinyobj::attrib_t attrib; 22 | std::vector shapes; 23 | std::vector materials; 24 | std::string warn, err; 25 | 26 | bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, filename); 27 | 28 | if (!err.empty()) 29 | { 30 | throw Error(err.c_str()); 31 | } 32 | 33 | if (shapes.size() != 1) 34 | { 35 | throw Error("The obj file includes several meshes.\n"); 36 | } 37 | 38 | std::vector& I = shapes[0].mesh.indices; 39 | uint numTri = (uint) shapes[0].mesh.num_face_vertices.size(); 40 | 41 | if (I.size() != 3 * numTri) 42 | { 43 | throw Error("The mesh includes non-triangle faces.\n"); 44 | } 45 | 46 | Mesh mesh; 47 | mesh.vtxArr.resize(numTri * 3); 48 | mesh.tdxArr.resize(numTri); 49 | 50 | std::map tinyIdxToVtxIdx; 51 | uint numVtx = 0; 52 | 53 | if (optimizeVertexxCount) 54 | { 55 | for (uint i = 0; i < 3 * numTri; ++i) 56 | { 57 | tinyobj::index_t& tinyIdx = I[i]; 58 | auto iterAndBool = tinyIdxToVtxIdx.insert({ tinyIdx, numVtx }); 59 | 60 | if (iterAndBool.second) 61 | { 62 | mesh.vtxArr[numVtx].position = *((float3*)&attrib.vertices[tinyIdx.vertex_index * 3]); 63 | mesh.vtxArr[numVtx].normal = *((float3*)&attrib.normals[tinyIdx.normal_index * 3]); 64 | mesh.vtxArr[numVtx].texcoord = (tinyIdx.texcoord_index == -1) ? float2(0, 0) : 65 | *((float2*)&attrib.texcoords[tinyIdx.texcoord_index * 2]); 66 | numVtx++; 67 | } 68 | 69 | ((uint*)mesh.tdxArr.data())[i] = iterAndBool.first->second; 70 | } 71 | mesh.vtxArr.resize(numVtx); 72 | } 73 | 74 | else 75 | { 76 | for (uint i = 0; i < 3 * numTri; ++i) 77 | { 78 | tinyobj::index_t& idx = I[i]; 79 | mesh.vtxArr[i].position = *((float3*) &attrib.vertices[idx.vertex_index*3]); 80 | mesh.vtxArr[i].normal = *((float3*) &attrib.normals[idx.normal_index*3]); 81 | mesh.vtxArr[i].texcoord = (idx.texcoord_index == -1) ? 82 | float2(0, 0) : *((float2*) &attrib.texcoords[idx.texcoord_index*2]) ; 83 | 84 | ((uint*) mesh.tdxArr.data()) [i] = i; 85 | } 86 | } 87 | 88 | return mesh; 89 | } -------------------------------------------------------------------------------- /DXRPathTracer/loadMesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Mesh.h" 3 | 4 | Mesh loadMeshFromOBJFile(const char* filename, bool optimizeVertexxCount); -------------------------------------------------------------------------------- /DXRPathTracer/main.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "DXRPathTracer.h" 3 | #include "D3D12Screen.h" 4 | #include "SceneLoader.h" 5 | #include "Input.h" 6 | #include "timer.h" 7 | 8 | 9 | HWND createWindow(const char* winTitle, uint width, uint height); 10 | 11 | IGRTTracer* tracer; 12 | IGRTScreen* screen; 13 | uint width = 1200; 14 | uint height = 900; 15 | bool minimized = false; 16 | 17 | int main() 18 | { 19 | HWND hwnd = createWindow("Integrated GPU Path Tracer", width, height); 20 | ShowWindow(hwnd, SW_SHOW); 21 | InputEngine input(hwnd); 22 | 23 | tracer = new DXRPathTracer(width, height); 24 | screen = new D3D12Screen(hwnd, width, height); 25 | 26 | SceneLoader sceneLoader; 27 | //Scene* scene = sceneLoader.push_testScene1(); 28 | Scene* scene = sceneLoader.push_hyperionTestScene(); 29 | tracer->setupScene(scene); 30 | 31 | double fps, old_fps = 0; 32 | while (IsWindow(hwnd)) 33 | { 34 | input.update(); 35 | 36 | if (!minimized) 37 | { 38 | tracer->update(input); 39 | TracedResult trResult = tracer->shootRays(); 40 | screen->display(trResult); 41 | } 42 | 43 | MSG msg; 44 | while(PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) 45 | { 46 | TranslateMessage(&msg); 47 | DispatchMessage(&msg); 48 | } 49 | 50 | fps = updateFPS(1.0); 51 | if (fps != old_fps) 52 | { 53 | printf("FPS: %f\n", fps); 54 | old_fps = fps; 55 | } 56 | } 57 | 58 | return 0; 59 | } 60 | 61 | LRESULT CALLBACK msgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); 62 | 63 | HWND createWindow(const char* winTitle, uint width, uint height) 64 | { 65 | WNDCLASSA wc = {}; 66 | wc.lpfnWndProc = msgProc; 67 | wc.hInstance = GetModuleHandle(nullptr); 68 | wc.lpszClassName = "anything"; 69 | wc.style = CS_HREDRAW | CS_VREDRAW; 70 | wc.hCursor = LoadCursor(NULL, IDC_ARROW); 71 | RegisterClass(&wc); 72 | 73 | RECT r{ 0, 0, (LONG)width, (LONG)height }; 74 | AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, false); 75 | 76 | HWND hWnd = CreateWindowA( 77 | wc.lpszClassName, 78 | winTitle, 79 | WS_OVERLAPPEDWINDOW, 80 | CW_USEDEFAULT, 81 | CW_USEDEFAULT, 82 | r.right - r.left, 83 | r.bottom - r.top, 84 | nullptr, 85 | nullptr, 86 | wc.hInstance, 87 | nullptr); 88 | 89 | return hWnd; 90 | } 91 | 92 | LRESULT CALLBACK msgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 93 | { 94 | switch (message) 95 | { 96 | case WM_SIZE: 97 | if (tracer && screen) 98 | { 99 | uint width = (uint) LOWORD(lParam); 100 | uint height = (uint) HIWORD(lParam); 101 | if (width == 0 || height == 0) 102 | { 103 | minimized = true; 104 | return 0; 105 | } 106 | else if (minimized) 107 | { 108 | minimized = false; 109 | } 110 | 111 | tracer->onSizeChanged(width, height); 112 | screen->onSizeChanged(width, height); 113 | } 114 | return 0; 115 | 116 | /*case WM_PAINT: 117 | if(tracer && screenOutFormat) 118 | { 119 | TracedResult trResult = tracer->shootRays(); 120 | screen->display(trResult); 121 | } 122 | return 0; 123 | 124 | case WM_DESTROY: 125 | PostQuitMessage(0); 126 | return 0;*/ 127 | } 128 | 129 | return DefWindowProc(hWnd, message, wParam, lParam); 130 | } 131 | -------------------------------------------------------------------------------- /DXRPathTracer/pch.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" -------------------------------------------------------------------------------- /DXRPathTracer/pch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #pragma comment(lib, "d3d12.lib") 4 | #pragma comment(lib, "d3dcompiler.lib") 5 | #pragma comment(lib, "dxgi.lib") 6 | 7 | 8 | #include 9 | #include 10 | #include 11 | #include "Error.h" 12 | #include "basic_types.h" 13 | #include "basic_math.h" 14 | #include "Array.h" 15 | -------------------------------------------------------------------------------- /DXRPathTracer/sampling.hlsli: -------------------------------------------------------------------------------- 1 | static const float Pi = 3.141592654f; 2 | static const float Pi2 = 6.283185307f; 3 | static const float Pi_2 = 1.570796327f; 4 | static const float Pi_4 = 0.7853981635f; 5 | static const float InvPi = 0.318309886f; 6 | static const float InvPi2 = 0.159154943f; 7 | 8 | 9 | uint getNewSeed(uint param1, uint param2, uint numPermutation) 10 | { 11 | uint s0 = 0; 12 | uint v0 = param1; 13 | uint v1 = param2; 14 | 15 | for(uint perm = 0; perm < numPermutation; perm++) 16 | { 17 | s0 += 0x9e3779b9; 18 | v0 += ((v1<<4) + 0xa341316c) ^ (v1+s0) ^ ((v1>>5) + 0xc8013ea4); 19 | v1 += ((v0<<4) + 0xad90777d) ^ (v0+s0) ^ ((v0>>5) + 0x7e95761e); 20 | } 21 | 22 | return v0; 23 | } 24 | 25 | float rnd(inout uint seed) 26 | { 27 | seed = (1664525u * seed + 1013904223u); 28 | return ((float) (seed & 0x00FFFFFF) / (float) 0x01000000); 29 | } 30 | 31 | float3 applyRotationMappingZToN(in float3 N, in float3 v) // --> https://math.stackexchange.com/questions/180418/calculate-rotation-matrix-to-align-vector-a-to-vector-b-in-3d 32 | { 33 | float s = (N.z >= 0.0f) ? 1.0f : -1.0f; 34 | v.z *= s; 35 | 36 | float3 h = float3(N.x, N.y, N.z + s); 37 | float k = dot(v, h) / (1.0f + abs(N.z)); 38 | 39 | return k * h - v; 40 | } 41 | 42 | float3 sample_hemisphere_cos(inout uint seed) 43 | { 44 | float3 sampleDir; 45 | 46 | float param1 = rnd(seed); 47 | float param2 = rnd(seed); 48 | 49 | // Uniformly sample disk. 50 | float r = sqrt( param1 ); 51 | float phi = 2.0f * Pi * param2; 52 | sampleDir.x = r * cos( phi ); 53 | sampleDir.y = r * sin( phi ); 54 | 55 | // Project up to hemisphere. 56 | sampleDir.z = sqrt( max(0.0f, 1.0f - r*r) ); 57 | 58 | return sampleDir; 59 | } 60 | 61 | float TrowbridgeReitz(in float cos2, in float alpha2) 62 | { 63 | float x = alpha2 + (1-cos2)/cos2; 64 | return alpha2 / (Pi*cos2*cos2*x*x); 65 | } 66 | 67 | float3 sample_hemisphere_TrowbridgeReitzCos(in float alpha2, inout uint seed) 68 | { 69 | float3 sampleDir; 70 | 71 | float u = rnd(seed); 72 | float v = rnd(seed); 73 | 74 | float tan2theta = alpha2 * (u / (1-u)); 75 | float cos2theta = 1 / (1 + tan2theta); 76 | float sinTheta = sqrt(1 - cos2theta); 77 | float phi = 2 * Pi * v; 78 | 79 | sampleDir.x = sinTheta * cos(phi); 80 | sampleDir.y = sinTheta * sin(phi); 81 | sampleDir.z = sqrt(cos2theta); 82 | 83 | return sampleDir; 84 | } 85 | 86 | float Smith_TrowbridgeReitz(in float3 wi, in float3 wo, in float3 wm, in float3 wn, in float alpha2) 87 | { 88 | if(dot(wo, wm) < 0 || dot(wi, wm) < 0) 89 | return 0.0f; 90 | 91 | float cos2 = dot(wn, wo); 92 | cos2 *= cos2; 93 | float lambda1 = 0.5 * ( -1 + sqrt(1 + alpha2*(1-cos2)/cos2) ); 94 | cos2 = dot(wn, wi); 95 | cos2 *= cos2; 96 | float lambda2 = 0.5 * ( -1 + sqrt(1 + alpha2*(1-cos2)/cos2) ); 97 | return 1 / (1 + lambda1 + lambda2); 98 | } 99 | 100 | -------------------------------------------------------------------------------- /DXRPathTracer/timer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "pch.h" 3 | 4 | 5 | inline double getCurrentTime() 6 | { 7 | static double inv_freq; 8 | static bool first = true; 9 | 10 | if (first) 11 | { 12 | LARGE_INTEGER freq; 13 | QueryPerformanceFrequency( &freq ); 14 | inv_freq = 1.0 / freq.QuadPart; 15 | first = false; 16 | } 17 | 18 | LARGE_INTEGER c_time; 19 | QueryPerformanceCounter( &c_time ); 20 | 21 | return c_time.QuadPart * inv_freq; 22 | } 23 | 24 | inline double updateFPS(double delta = 1.0) 25 | { 26 | static int frameCount = 0; 27 | static double lastTime = getCurrentTime(); 28 | static double old_fps = 0.0; 29 | 30 | double fps; 31 | double curTime = getCurrentTime(); 32 | 33 | ++frameCount; 34 | 35 | if( curTime - lastTime >= delta ) 36 | { 37 | fps = (double) frameCount / (curTime - lastTime); 38 | 39 | frameCount = 0; 40 | lastTime = curTime; 41 | old_fps = fps; 42 | } 43 | else 44 | { 45 | fps = old_fps; 46 | } 47 | 48 | return fps; 49 | } 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DXR PathTracer 2 | ============== 3 | A basic path tracer implementing the forward BRDF sampling using DirectX Ray Tracing (DXR) 4 | 5 | 6 | Features 7 | -------- 8 | 9 | - Useful DX12/DXR helpers that reduce your graphic code efficiently 10 | - Support various hierarchies for acceleration structure building 11 | - Forward BRDF sampling (GGX/glass) for light tranport 12 | - Every mesh can be a light 13 | 14 | 15 | DXR Acceleration Structure 16 | -------------------------- 17 |
18 | 19 | ![diagram](images/diagram.png) 20 |
21 |
22 | An acceleration structure(AS) is a tree-style data structure representing geometry data in a scene of interest for the fast ray-scene intersection test in ray tracing. Especially, DXR's AS consists of two stages. One top-level-acceleration-structure(TLAS) contains a number of bottom-level-acceleration-structures(BLASs). Also, if a geometry has own transformation, it is reflected in the building of TLAS or in the building of BLAS. Thus, when implementing ray tracing scene you have to design how to split your geometries into BLASs and where to place their transformation. Excluding the complex hybrid cases, there are three simple cases as in the above diagram. In this project, you can apply these three types of AS to the same scene by modifying the AS-building flag (ONLY_ONE_BLAS / BLAS_PER_OBJECT_AND_BOTTOM_LEVEL_TRANSFOR / BLAS_PER_OBJECT_AND_TOP_LEVEL_TRANSFORM). In real situations including dynamic objects, however, you would have to construct your own hybrid AS for your goal. 23 | 24 | 25 | 26 | Build Requirements 27 | ------------------ 28 | 29 | - Windows 10 version 1809 (10.0.17763.0) 30 | - Visual Studio 2017 31 | - A GPU/driver that supports DXR 32 | 33 | The repository contains a Visual Studio 2017 project and solution file that's ready to build on Windows 10 using SDK 10.0.17763.0. Also, since this project do not support DXR fallback layer, a DXR supporting GPU is necessary. 34 | 35 | 36 | Images 37 | ------ 38 | 39 | Disney Hyperion's table test scene (https://www.disneyanimation.com/technology/innovations/hyperion) 40 | 41 | ![Example Image1](images/hyperion.png) 42 | 43 | ![Example Image2](images/hyperion2.png) 44 | 45 | ![Example Image3](images/hyperion3.png) 46 | 47 | 48 | 49 | ToDo List 50 | --------- 51 | - Subsurface / Volume scattering 52 | - Denoising 53 | - Support Vulkan raytracing / nVidia OptiX API 54 | -------------------------------------------------------------------------------- /data/mesh/ring.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meta-plane/DXR-PathTracer/1d8a9e03b357c551b3db75ba032a44e4107d4327/data/mesh/ring.obj -------------------------------------------------------------------------------- /images/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meta-plane/DXR-PathTracer/1d8a9e03b357c551b3db75ba032a44e4107d4327/images/diagram.png -------------------------------------------------------------------------------- /images/hyperion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meta-plane/DXR-PathTracer/1d8a9e03b357c551b3db75ba032a44e4107d4327/images/hyperion.png -------------------------------------------------------------------------------- /images/hyperion2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meta-plane/DXR-PathTracer/1d8a9e03b357c551b3db75ba032a44e4107d4327/images/hyperion2.png -------------------------------------------------------------------------------- /images/hyperion3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meta-plane/DXR-PathTracer/1d8a9e03b357c551b3db75ba032a44e4107d4327/images/hyperion3.png --------------------------------------------------------------------------------