Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Render pass dependencies #124

Merged
merged 22 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d55ce8a
Release image views when updating input attachments.
crud89 Feb 6, 2024
9248f4b
Rename input attachment mappings to render pass dependencies.
crud89 Feb 6, 2024
78ffbfa
Add input attachment sampler binding point to render pass interface.
crud89 Feb 6, 2024
a6b1fc7
Add sampler binding point for input attachments.
crud89 Feb 7, 2024
d48f1e8
Rename frame buffer resize method.
crud89 Feb 7, 2024
1a2dac6
Add method to pImpl-pointer to access raw pointer.
crud89 Feb 7, 2024
e1a2579
Listen to swap chain resets and allow independent render area sizes.
crud89 Feb 7, 2024
b6da877
Remove attachment update method from render pass.
crud89 Feb 7, 2024
70e4a77
Add input attachment index to Vulkan descriptor layout.
crud89 Feb 7, 2024
875cedf
Use binding point for render pass dependency description in builders.
crud89 Feb 7, 2024
14695f4
Raise event if render pass has been reset.
crud89 Feb 7, 2024
f36f9d1
Remove validation checks for input attachment ordering.
crud89 Feb 7, 2024
a6d6fd6
Expose active back buffer through render pass.
crud89 Feb 7, 2024
25f2010
Implement implicit descriptor set management by render pipelines.
crud89 Feb 7, 2024
045c558
Remove manual resizing of frame buffers.
crud89 Feb 7, 2024
5fbd8c6
Fix barrier image layout.
crud89 Feb 7, 2024
05b28f5
Handle input attachment binding just the same way as normal images.
crud89 Feb 8, 2024
17c2c9a
Bind the input attachment sampler.
crud89 Feb 8, 2024
5f749d0
Merge changes from command buffer improvements.
crud89 Feb 9, 2024
a79536b
Simplify binding of dependency descriptors.
crud89 Feb 9, 2024
0942b49
Merge remote-tracking branch 'origin/main' into render-pass-dependencies
crud89 Feb 9, 2024
1369646
Document render pass improvements.
crud89 Feb 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading