Skip to content

Commit

Permalink
Merge pull request #124 from crud89/render-pass-dependencies
Browse files Browse the repository at this point in the history
Render pass dependencies
  • Loading branch information
crud89 authored Feb 9, 2024
2 parents f64f108 + 1369646 commit 95afd04
Show file tree
Hide file tree
Showing 42 changed files with 1,064 additions and 601 deletions.
1 change: 1 addition & 0 deletions docs/release-logs/0.4.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
- Build macros are now prefixed with `LITEFX_` to support portability. ([See PR #117](https://github.com/crud89/LiteFX/pull/117))
- Add optional support for mesh shaders (enable `GraphicsDeviceFeatures::MeshShaders` to turn it on). ([See PR #116](https://github.com/crud89/LiteFX/pull/116))
- Add optional support for ray-tracing and ray queries (enable `GraphicsDeviceFeatures::RayTracing` and/or `GraphicsDeviceFeatures::RayQueries` to turn it on). ([See PR #122](https://github.com/crud89/LiteFX/pull/122))
- Render passes have been improved and simplified, now supporting automatic input attachment binding and event-based resize handlers. ([See PR #124](https://github.com/crud89/LiteFX/pull/124))

**🌋 Vulkan:**

Expand Down
3 changes: 1 addition & 2 deletions docs/tutorials/quick-start.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -659,11 +659,10 @@ auto surfaceFormat = m_device->swapChain().surfaceFormat();
auto renderArea = Size2d(width, height);
```

Again, we first wait for the device to finish all submitted work. This ensures that we do not destroy any back buffers, that might be still used by command buffers that are yet to be executed. Next we request the surface format from the current swap chain and initialize the new render area extent. We then can go ahead and re-create the swap chain, which causes the back buffers to be re-allocated with the new size and format. Furthermore, we can resize the frame buffers of our render pass. Note that you have to decide whether or not you want to do this, because you might have a render pass, that renders into a target that is deliberately at a different size than the swap chain back buffer. However, you almost certainly want to at least resize the frame buffer of the render pass that writes your present target.
Again, we first wait for the device to finish all submitted work. This ensures that we do not destroy any back buffers, that might be still used by command buffers that are yet to be executed. Next we request the surface format from the current swap chain and initialize the new render area extent. We then can go ahead and re-create the swap chain, which causes the back buffers to be re-allocated with the new size and format.

```cxx
m_device->swapChain().reset(surfaceFormat, renderArea, 3);
m_renderPass->resizeFrameBuffers(renderArea);
```
We then also resize the viewport and scissor rectangles, so that the image is drawn over the whole area of our resized window:
Expand Down
2 changes: 1 addition & 1 deletion src/Backends/DirectX12/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ SET(DIRECTX12_BACKEND_SOURCES
"src/queue.cpp"
"src/swapchain.cpp"
"src/frame_buffer.cpp"
"src/input_attachment_mapping.cpp"
"src/render_pass_dependency.cpp"
"src/render_pass.cpp"
"src/command_buffer.cpp"
"src/barrier.cpp"
Expand Down
72 changes: 43 additions & 29 deletions src/Backends/DirectX12/include/litefx/backends/dx12.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,6 @@ namespace LiteFX::Rendering::Backends {
public:
using base_type = DescriptorSet<IDirectX12Buffer, IDirectX12Image, IDirectX12Sampler, IDirectX12AccelerationStructure>;
using base_type::update;
using base_type::attach;

public:
/// <summary>
Expand Down Expand Up @@ -531,9 +530,6 @@ namespace LiteFX::Rendering::Backends {
/// <inheritdoc />
void update(UInt32 binding, const IDirectX12AccelerationStructure& accelerationStructure, UInt32 descriptor = 0) const override;

/// <inheritdoc />
void attach(UInt32 binding, const IDirectX12Image& image) const override;

public:
/// <summary>
/// Returns the local (CPU-visible) heap that contains the buffer descriptors.
Expand Down Expand Up @@ -1471,13 +1467,12 @@ namespace LiteFX::Rendering::Backends {
/// Implements a DirectX 12 render pass.
/// </summary>
/// <seealso cref="DirectX12RenderPassBuilder" />
class LITEFX_DIRECTX12_API DirectX12RenderPass final : public RenderPass<DirectX12RenderPipeline, DirectX12Queue, DirectX12FrameBuffer, DirectX12InputAttachmentMapping> {
class LITEFX_DIRECTX12_API DirectX12RenderPass final : public RenderPass<DirectX12RenderPipeline, DirectX12Queue, DirectX12FrameBuffer, DirectX12RenderPassDependency> {
LITEFX_IMPLEMENTATION(DirectX12RenderPassImpl);
LITEFX_BUILDER(DirectX12RenderPassBuilder);

public:
using base_type = RenderPass<DirectX12RenderPipeline, DirectX12Queue, DirectX12FrameBuffer, DirectX12InputAttachmentMapping>;
using base_type::updateAttachments;
using base_type = RenderPass<DirectX12RenderPipeline, DirectX12Queue, DirectX12FrameBuffer, DirectX12RenderPassDependency>;

public:
/// <summary>
Expand All @@ -1488,7 +1483,8 @@ namespace LiteFX::Rendering::Backends {
/// <param name="renderTargets">The render targets that are output by the render pass.</param>
/// <param name="samples">The number of samples for the render targets in this render pass.</param>
/// <param name="inputAttachments">The input attachments that are read by the render pass.</param>
explicit DirectX12RenderPass(const DirectX12Device& device, Span<RenderTarget> renderTargets, UInt32 commandBuffers = 1, MultiSamplingLevel samples = MultiSamplingLevel::x1, Span<DirectX12InputAttachmentMapping> inputAttachments = { });
/// <param name="inputAttachmentSamplerBinding">The binding point for the input attachment sampler.</param>
explicit DirectX12RenderPass(const DirectX12Device& device, Span<RenderTarget> renderTargets, UInt32 commandBuffers = 1, MultiSamplingLevel samples = MultiSamplingLevel::x1, Span<DirectX12RenderPassDependency> inputAttachments = { }, Optional<DescriptorBindingPoint> inputAttachmentSamplerBinding = std::nullopt);

/// <summary>
/// Creates and initializes a new DirectX 12 render pass instance that executes on the default graphics queue.
Expand All @@ -1499,7 +1495,8 @@ namespace LiteFX::Rendering::Backends {
/// <param name="renderTargets">The render targets that are output by the render pass.</param>
/// <param name="samples">The number of samples for the render targets in this render pass.</param>
/// <param name="inputAttachments">The input attachments that are read by the render pass.</param>
explicit DirectX12RenderPass(const DirectX12Device& device, const String& name, Span<RenderTarget> renderTargets, UInt32 commandBuffers = 1, MultiSamplingLevel samples = MultiSamplingLevel::x1, Span<DirectX12InputAttachmentMapping> inputAttachments = { });
/// <param name="inputAttachmentSamplerBinding">The binding point for the input attachment sampler.</param>
explicit DirectX12RenderPass(const DirectX12Device& device, const String& name, Span<RenderTarget> renderTargets, UInt32 commandBuffers = 1, MultiSamplingLevel samples = MultiSamplingLevel::x1, Span<DirectX12RenderPassDependency> inputAttachments = { }, Optional<DescriptorBindingPoint> inputAttachmentSamplerBinding = std::nullopt);

/// <summary>
/// Creates and initializes a new DirectX 12 render pass instance.
Expand All @@ -1510,7 +1507,8 @@ namespace LiteFX::Rendering::Backends {
/// <param name="renderTargets">The render targets that are output by the render pass.</param>
/// <param name="samples">The number of samples for the render targets in this render pass.</param>
/// <param name="inputAttachments">The input attachments that are read by the render pass.</param>
explicit DirectX12RenderPass(const DirectX12Device& device, const DirectX12Queue& queue, Span<RenderTarget> renderTargets, UInt32 commandBuffers = 1, MultiSamplingLevel samples = MultiSamplingLevel::x1, Span<DirectX12InputAttachmentMapping> inputAttachments = { });
/// <param name="inputAttachmentSamplerBinding">The binding point for the input attachment sampler.</param>
explicit DirectX12RenderPass(const DirectX12Device& device, const DirectX12Queue& queue, Span<RenderTarget> renderTargets, UInt32 commandBuffers = 1, MultiSamplingLevel samples = MultiSamplingLevel::x1, Span<DirectX12RenderPassDependency> inputAttachments = { }, Optional<DescriptorBindingPoint> inputAttachmentSamplerBinding = std::nullopt);

/// <summary>
/// Creates and initializes a new DirectX 12 render pass instance.
Expand All @@ -1522,7 +1520,8 @@ namespace LiteFX::Rendering::Backends {
/// <param name="renderTargets">The render targets that are output by the render pass.</param>
/// <param name="samples">The number of samples for the render targets in this render pass.</param>
/// <param name="inputAttachments">The input attachments that are read by the render pass.</param>
explicit DirectX12RenderPass(const DirectX12Device& device, const String& name, const DirectX12Queue& queue, Span<RenderTarget> renderTargets, UInt32 commandBuffers = 1, MultiSamplingLevel samples = MultiSamplingLevel::x1, Span<DirectX12InputAttachmentMapping> inputAttachments = { });
/// <param name="inputAttachmentSamplerBinding">The binding point for the input attachment sampler.</param>
explicit DirectX12RenderPass(const DirectX12Device& device, const String& name, const DirectX12Queue& queue, Span<RenderTarget> renderTargets, UInt32 commandBuffers = 1, MultiSamplingLevel samples = MultiSamplingLevel::x1, Span<DirectX12RenderPassDependency> inputAttachments = { }, Optional<DescriptorBindingPoint> inputAttachmentSamplerBinding = std::nullopt);

DirectX12RenderPass(const DirectX12RenderPass&) = delete;
DirectX12RenderPass(DirectX12RenderPass&&) = delete;
Expand All @@ -1540,7 +1539,7 @@ namespace LiteFX::Rendering::Backends {
/// <param name="name">The name of the render pass state resource.</param>
explicit DirectX12RenderPass(const DirectX12Device& device, const String& name = "") noexcept;

// InputAttachmentMappingSource interface.
// RenderPassDependencySource interface.
public:
/// <inheritdoc />
const DirectX12FrameBuffer& frameBuffer(UInt32 buffer) const override;
Expand All @@ -1556,6 +1555,9 @@ namespace LiteFX::Rendering::Backends {
/// <inheritdoc />
const DirectX12FrameBuffer& activeFrameBuffer() const override;

/// <inheritdoc />
UInt32 activeBackBuffer() const override;

/// <inheritdoc />
const DirectX12Queue& commandQueue() const noexcept override;

Expand All @@ -1575,72 +1577,84 @@ namespace LiteFX::Rendering::Backends {
bool hasPresentTarget() const noexcept override;

/// <inheritdoc />
Span<const DirectX12InputAttachmentMapping> inputAttachments() const noexcept override;
Span<const DirectX12RenderPassDependency> inputAttachments() const noexcept override;

/// <inheritdoc />
const Optional<DescriptorBindingPoint>& inputAttachmentSamplerBinding() const noexcept override;

/// <inheritdoc />
MultiSamplingLevel multiSamplingLevel() const noexcept override;

public:
/// <inheritdoc />
Size2d renderArea() const noexcept override;

/// <inheritdoc />
bool usesSwapChainRenderArea() const noexcept override;

/// <inheritdoc />
void begin(UInt32 buffer) override;

/// <inheritdoc />
UInt64 end() const override;

/// <inheritdoc />
void resizeFrameBuffers(const Size2d& renderArea) override;
void resizeRenderArea(const Size2d& renderArea) override;

/// <inheritdoc />
void changeMultiSamplingLevel(MultiSamplingLevel samples) override;
void resizeWithSwapChain(bool enable) override;

/// <inheritdoc />
void updateAttachments(const DirectX12DescriptorSet& descriptorSet) const override;
void changeMultiSamplingLevel(MultiSamplingLevel samples) override;
};

/// <summary>
/// Implements a <see cref="IInputAttachmentMapping" />.
/// Implements a <see cref="IRenderPassDependency" />.
/// </summary>
/// <seealso cref="DirectX12RenderPass" />
/// <seealso cref="DirectX12RenderPassBuilder" />
class LITEFX_DIRECTX12_API DirectX12InputAttachmentMapping final : public IInputAttachmentMapping<DirectX12RenderPass> {
LITEFX_IMPLEMENTATION(DirectX12InputAttachmentMappingImpl);
class LITEFX_DIRECTX12_API DirectX12RenderPassDependency final : public IRenderPassDependency<DirectX12RenderPass> {
LITEFX_IMPLEMENTATION(DirectX12RenderPassDependencyImpl);

public:
/// <summary>
/// Creates a new DirectX 12 input attachment mapping.
/// </summary>
DirectX12InputAttachmentMapping() noexcept;
/// <param name="renderPass">The render pass to fetch the input attachment from.</param>
/// <param name="renderTarget">The render target of the <paramref name="renderPass"/> that is used for the input attachment.</param>
/// <param name="binding">The binding point to bind the input attachment to.</param>
DirectX12RenderPassDependency(const DirectX12RenderPass& renderPass, const RenderTarget& renderTarget, DescriptorBindingPoint binding);

/// <summary>
/// Creates a new DirectX 12 input attachment mapping.
/// </summary>
/// <param name="renderPass">The render pass to fetch the input attachment from.</param>
/// <param name="renderTarget">The render target of the <paramref name="renderPass"/> that is used for the input attachment.</param>
/// <param name="location">The location to bind the input attachment to.</param>
DirectX12InputAttachmentMapping(const DirectX12RenderPass& renderPass, const RenderTarget& renderTarget, UInt32 location);
/// <param name="bindingRegister">The register to bind the input attachment to.</param>
/// <param name="space">The space to bind the input attachment to.</param>
DirectX12RenderPassDependency(const DirectX12RenderPass& renderPass, const RenderTarget& renderTarget, UInt32 bindingRegister, UInt32 space);

/// <summary>
/// Copies another input attachment mapping.
/// </summary>
DirectX12InputAttachmentMapping(const DirectX12InputAttachmentMapping&) noexcept;
DirectX12RenderPassDependency(const DirectX12RenderPassDependency&) noexcept;

/// <summary>
/// Takes over another input attachment mapping.
/// </summary>
DirectX12InputAttachmentMapping(DirectX12InputAttachmentMapping&&) noexcept;
DirectX12RenderPassDependency(DirectX12RenderPassDependency&&) noexcept;

virtual ~DirectX12InputAttachmentMapping() noexcept;
virtual ~DirectX12RenderPassDependency() noexcept;

public:
/// <summary>
/// Copies another input attachment mapping.
/// </summary>
inline DirectX12InputAttachmentMapping& operator=(const DirectX12InputAttachmentMapping&) noexcept;
inline DirectX12RenderPassDependency& operator=(const DirectX12RenderPassDependency&) noexcept;

/// <summary>
/// Takes over another input attachment mapping.
/// </summary>
inline DirectX12InputAttachmentMapping& operator=(DirectX12InputAttachmentMapping&&) noexcept;
inline DirectX12RenderPassDependency& operator=(DirectX12RenderPassDependency&&) noexcept;

public:
/// <inheritdoc />
Expand All @@ -1650,7 +1664,7 @@ namespace LiteFX::Rendering::Backends {
const RenderTarget& renderTarget() const noexcept override;

/// <inheritdoc />
UInt32 location() const noexcept override;
const DescriptorBindingPoint& binding() const noexcept override;
};

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ namespace LiteFX::Rendering::Backends {
class DirectX12RayTracingPipeline;
class DirectX12FrameBuffer;
class DirectX12RenderPass;
class DirectX12InputAttachmentMapping;
class DirectX12RenderPassDependency;
class DirectX12SwapChain;
class DirectX12Queue;
class DirectX12GraphicsFactory;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ namespace LiteFX::Rendering::Backends {
// RenderPassBuilder interface.
protected:
/// <inheritdoc />
inline DirectX12InputAttachmentMapping makeInputAttachment(UInt32 inputLocation, const DirectX12RenderPass& renderPass, const RenderTarget& renderTarget) override;
inline DirectX12RenderPassDependency makeInputAttachment(DescriptorBindingPoint binding, const DirectX12RenderPass& renderPass, const RenderTarget& renderTarget) override;
};

}
Expand Down
47 changes: 15 additions & 32 deletions src/Backends/DirectX12/src/descriptor_set.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,13 +231,27 @@ void DirectX12DescriptorSet::update(UInt32 binding, const IDirectX12Image& textu
const UInt32 numLevels = levels == 0 ? texture.levels() - firstLevel : levels;
const UInt32 numLayers = layers == 0 ? texture.layers() - firstLayer : layers;

if (descriptorLayout.descriptorType() == DescriptorType::Texture)
if (descriptorLayout.descriptorType() == DescriptorType::Texture || descriptorLayout.descriptorType() == DescriptorType::InputAttachment)
{
D3D12_SHADER_RESOURCE_VIEW_DESC textureView = {
.Format = DX12::getFormat(texture.format()),
.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING,
};

// Handle depth images.
if (::hasDepth(texture.format()))
{
switch (texture.format())
{
case Format::D16_UNORM: textureView.Format = DXGI_FORMAT_R16_UNORM; break;
case Format::D32_SFLOAT: textureView.Format = DXGI_FORMAT_R32_FLOAT; break;
case Format::D24_UNORM_S8_UINT: textureView.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS; break;
case Format::D32_SFLOAT_S8_UINT: textureView.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; break;
//case Format::D16_UNORM_S8_UINT: ??
//case Format::X8_D24_UNORM: ??
}
}

switch (texture.dimensions())
{
case ImageDimensions::DIM_1:
Expand Down Expand Up @@ -418,37 +432,6 @@ void DirectX12DescriptorSet::update(UInt32 binding, const IDirectX12Acceleration
m_impl->updateGlobalBuffers(offset, 1);
}

void DirectX12DescriptorSet::attach(UInt32 binding, const IDirectX12Image& image) const
{
auto offset = m_impl->m_layout.descriptorOffsetForBinding(binding);

D3D12_SHADER_RESOURCE_VIEW_DESC inputAttachmentView = {
.Format = DX12::getFormat(image.format()),
.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D,
.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING,
.Texture2D = { .MostDetailedMip = 0, .MipLevels = 1, .PlaneSlice = 0, .ResourceMinLODClamp = 0 },
};

// DSV needs special care.
// TODO: Support stencil targets, which require a separate view.
if (::hasDepth(image.format()))
{
switch (image.format())
{
case Format::D16_UNORM: inputAttachmentView.Format = DXGI_FORMAT_R16_UNORM; break;
case Format::D32_SFLOAT: inputAttachmentView.Format = DXGI_FORMAT_R32_FLOAT; break;
case Format::D24_UNORM_S8_UINT: inputAttachmentView.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS; break;
case Format::D32_SFLOAT_S8_UINT: inputAttachmentView.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; break;
//case Format::D16_UNORM_S8_UINT: ??
//case Format::X8_D24_UNORM: ??
}
}

CD3DX12_CPU_DESCRIPTOR_HANDLE descriptorHandle(m_impl->m_bufferHeap->GetCPUDescriptorHandleForHeapStart(), offset, m_impl->m_layout.device().handle()->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV));
m_impl->m_layout.device().handle()->CreateShaderResourceView(image.handle().Get(), &inputAttachmentView, descriptorHandle);
m_impl->updateGlobalBuffers(offset, 1);
}

const ComPtr<ID3D12DescriptorHeap>& DirectX12DescriptorSet::bufferHeap() const noexcept
{
return m_impl->m_bufferHeap;
Expand Down
Loading

0 comments on commit 95afd04

Please sign in to comment.