Renderer.h 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #pragma once
  5. #include <Jolt/Core/UnorderedMap.h>
  6. #include <Image/Surface.h>
  7. #include <Renderer/Frustum.h>
  8. #include <Renderer/ConstantBuffer.h>
  9. #include <Renderer/PipelineState.h>
  10. #include <Renderer/CommandQueue.h>
  11. #include <Renderer/DescriptorHeap.h>
  12. #include <memory>
  13. // Forward declares
  14. class Texture;
  15. /// Camera setup
  16. struct CameraState
  17. {
  18. CameraState() : mPos(RVec3::sZero()), mForward(0, 0, -1), mUp(0, 1, 0), mFOVY(DegreesToRadians(70.0f)), mFarPlane(100.0f) { }
  19. RVec3 mPos; ///< Camera position
  20. Vec3 mForward; ///< Camera forward vector
  21. Vec3 mUp; ///< Camera up vector
  22. float mFOVY; ///< Field of view in radians in up direction
  23. float mFarPlane; ///< Distance of far plane
  24. };
  25. /// Responsible for rendering primitives to the screen
  26. class Renderer
  27. {
  28. public:
  29. /// Destructor
  30. ~Renderer();
  31. /// Initialize DirectX
  32. void Initialize();
  33. /// Callback when the window resizes and the back buffer needs to be adjusted
  34. void OnWindowResize();
  35. /// Get window size
  36. int GetWindowWidth() { return mWindowWidth; }
  37. int GetWindowHeight() { return mWindowHeight; }
  38. /// Access to the window handle
  39. HWND GetWindowHandle() const { return mhWnd; }
  40. /// Access to the most important DirectX structures
  41. ID3D12Device * GetDevice() { return mDevice.Get(); }
  42. ID3D12RootSignature * GetRootSignature() { return mRootSignature.Get(); }
  43. ID3D12GraphicsCommandList * GetCommandList() { return mCommandList.Get(); }
  44. CommandQueue & GetUploadQueue() { return mUploadQueue; }
  45. DescriptorHeap & GetDSVHeap() { return mDSVHeap; }
  46. DescriptorHeap & GetSRVHeap() { return mSRVHeap; }
  47. /// Start / end drawing a frame
  48. void BeginFrame(const CameraState &inCamera, float inWorldScale);
  49. void EndFrame();
  50. /// Switch between orthographic and 3D projection mode
  51. void SetProjectionMode();
  52. void SetOrthoMode();
  53. /// Create texture from an image surface
  54. Ref<Texture> CreateTexture(const Surface *inSurface);
  55. /// Create a texture to render to (currently depth buffer only)
  56. Ref<Texture> CreateRenderTarget(int inWidth, int inHeight);
  57. /// Change the render target to a texture. Use nullptr to set back to the main render target.
  58. void SetRenderTarget(Texture *inRenderTarget);
  59. /// Compile a vertex shader
  60. ComPtr<ID3DBlob> CreateVertexShader(const char *inFileName);
  61. /// Compile a pixel shader
  62. ComPtr<ID3DBlob> CreatePixelShader(const char *inFileName);
  63. /// Create a constant buffer for the shader
  64. unique_ptr<ConstantBuffer> CreateConstantBuffer(uint inBufferSize);
  65. /// Create pipeline state object that defines the complete state of how primitives should be rendered
  66. unique_ptr<PipelineState> CreatePipelineState(ID3DBlob *inVertexShader, const D3D12_INPUT_ELEMENT_DESC *inInputDescription, uint inInputDescriptionCount, ID3DBlob *inPixelShader, D3D12_FILL_MODE inFillMode, D3D12_PRIMITIVE_TOPOLOGY_TYPE inTopology, PipelineState::EDepthTest inDepthTest, PipelineState::EBlendMode inBlendMode, PipelineState::ECullMode inCullMode);
  67. /// Get the camera state / frustum (only valid between BeginFrame() / EndFrame())
  68. const CameraState & GetCameraState() const { return mCameraState; }
  69. const Frustum & GetCameraFrustum() const { return mCameraFrustum; }
  70. /// Offset relative to which the world is rendered, helps avoiding rendering artifacts at big distances
  71. RVec3 GetBaseOffset() const { return mBaseOffset; }
  72. void SetBaseOffset(RVec3 inOffset) { mBaseOffset = inOffset; }
  73. /// Get the light frustum (only valid between BeginFrame() / EndFrame())
  74. const Frustum & GetLightFrustum() const { return mLightFrustum; }
  75. /// How many frames our pipeline is
  76. static const uint cFrameCount = 2;
  77. /// Which frame is currently rendering (to keep track of which buffers are free to overwrite)
  78. uint GetCurrentFrameIndex() const { return mFrameIndex; }
  79. /// Create a buffer on the default heap (usable for permanent buffers)
  80. ComPtr<ID3D12Resource> CreateD3DResourceOnDefaultHeap(const void *inData, uint64 inSize);
  81. /// Create buffer on the upload heap (usable for temporary buffers).
  82. ComPtr<ID3D12Resource> CreateD3DResourceOnUploadHeap(uint64 inSize);
  83. /// Recycle a buffer on the upload heap. This puts it back in a cache and will reuse it when it is certain the GPU is no longer referencing it.
  84. void RecycleD3DResourceOnUploadHeap(ID3D12Resource *inResource, uint64 inSize);
  85. /// Keeps a reference to the resource until the current frame has finished
  86. void RecycleD3DObject(ID3D12Object *inResource);
  87. private:
  88. // Wait for pending GPU work to complete
  89. void WaitForGpu();
  90. // Create render targets and their views
  91. void CreateRenterTargets();
  92. // Create a depth buffer for the back buffer
  93. void CreateDepthBuffer();
  94. // Function to create a ID3D12Resource on specified heap with specified state
  95. ComPtr<ID3D12Resource> CreateD3DResource(D3D12_HEAP_TYPE inHeapType, D3D12_RESOURCE_STATES inResourceState, uint64 inSize);
  96. // Copy CPU memory into a ID3D12Resource
  97. void CopyD3DResource(ID3D12Resource *inDest, const void *inSrc, uint64 inSize);
  98. // Copy a CPU resource to a GPU resource
  99. void CopyD3DResource(ID3D12Resource *inDest, ID3D12Resource *inSrc, uint64 inSize);
  100. HWND mhWnd;
  101. int mWindowWidth = 1920;
  102. int mWindowHeight = 1080;
  103. unique_ptr<ConstantBuffer> mVertexShaderConstantBufferProjection[cFrameCount];
  104. unique_ptr<ConstantBuffer> mVertexShaderConstantBufferOrtho[cFrameCount];
  105. unique_ptr<ConstantBuffer> mPixelShaderConstantBuffer[cFrameCount];
  106. CameraState mCameraState;
  107. RVec3 mBaseOffset { RVec3::sZero() }; ///< Offset to subtract from the camera position to deal with large worlds
  108. Frustum mCameraFrustum;
  109. Frustum mLightFrustum;
  110. // DirectX interfaces
  111. ComPtr<IDXGIFactory4> mDXGIFactory;
  112. ComPtr<ID3D12Device> mDevice;
  113. DescriptorHeap mRTVHeap; ///< Render target view heap
  114. DescriptorHeap mDSVHeap; ///< Depth stencil view heap
  115. DescriptorHeap mSRVHeap; ///< Shader resource view heap
  116. ComPtr<IDXGISwapChain3> mSwapChain;
  117. ComPtr<ID3D12Resource> mRenderTargets[cFrameCount]; ///< Two render targets (we're double buffering in order for the CPU to continue while the GPU is rendering)
  118. D3D12_CPU_DESCRIPTOR_HANDLE mRenderTargetViews[cFrameCount]; ///< The two render views corresponding to the render targets
  119. ComPtr<ID3D12Resource> mDepthStencilBuffer; ///< The main depth buffer
  120. D3D12_CPU_DESCRIPTOR_HANDLE mDepthStencilView { 0 }; ///< A view for binding the depth buffer
  121. ComPtr<ID3D12CommandAllocator> mCommandAllocators[cFrameCount]; ///< Two command allocator lists (one per frame)
  122. ComPtr<ID3D12CommandQueue> mCommandQueue; ///< The command queue that will execute commands (there's only 1 since we want to finish rendering 1 frame before moving onto the next)
  123. ComPtr<ID3D12GraphicsCommandList> mCommandList; ///< The command list
  124. ComPtr<ID3D12RootSignature> mRootSignature; ///< The root signature, we have a simple application so we only need 1, which is suitable for all our shaders
  125. Ref<Texture> mRenderTargetTexture; ///< When rendering to a texture, this is the active texture
  126. CommandQueue mUploadQueue; ///< Queue used to upload resources to GPU memory
  127. // Synchronization objects used to finish rendering and swapping before reusing a command queue
  128. uint mFrameIndex; ///< Current frame index (0 or 1)
  129. HANDLE mFenceEvent; ///< Fence event to wait for the previous frame rendering to complete (in order to free 1 of the buffers)
  130. ComPtr<ID3D12Fence> mFence; ///< Fence object, used to signal the end of a frame
  131. UINT64 mFenceValues[cFrameCount] = {}; ///< Values that were used to signal completion of one of the two frames
  132. using ResourceCache = UnorderedMap<uint64, Array<ComPtr<ID3D12Resource>>>;
  133. ResourceCache mResourceCache; ///< Cache items ready to be reused
  134. ResourceCache mDelayCached[cFrameCount]; ///< List of reusable ID3D12Resources that are potentially referenced by the GPU so can be used only when the GPU finishes
  135. Array<ComPtr<ID3D12Object>> mDelayReleased[cFrameCount]; ///< Objects that are potentially referenced by the GPU so can only be freed when the GPU finishes
  136. bool mIsExiting = false; ///< When exiting we don't want to add references too buffers
  137. };