Skip to content

Commit

Permalink
Merge pull request #125 from crud89/decouple-framebuffers
Browse files Browse the repository at this point in the history
Dedicated frame buffers.
  • Loading branch information
crud89 authored Feb 19, 2024
2 parents 4f70932 + 286afb9 commit 864a2dc
Show file tree
Hide file tree
Showing 51 changed files with 3,001 additions and 2,939 deletions.
4 changes: 3 additions & 1 deletion docs/release-logs/0.4.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@
- Add support for static secondary command buffers aka. bundles. ([See PR #100](https://github.com/crud89/LiteFX/pull/100))
- Render targets are now created with a set of flags instead of individual boolean switches. ([See PR #114](https://github.com/crud89/LiteFX/pull/114))
- This also enables for more use cases, like using render targets in read-write bindings or sharing between different queues.
- Swap chains can now accept `present` calls without explicitly providing a frame buffer. ([See PR #114](https://github.com/crud89/LiteFX/pull/114))
- Swap chains can now accept `present` calls without explicitly providing a frame buffer. ([See PR #114](https://github.com/crud89/LiteFX/pull/114) and [PR #125](https://github.com/crud89/LiteFX/pull/125))
- 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))
- Frame buffers have been decoupled from render passes, allowing to share images between passes and binding resources of different sampling rates and resolutions to the same pass. ([See PR #125](https://github.com/crud89/LiteFX/pull/125))

**🌋 Vulkan:**

Expand All @@ -50,6 +51,7 @@
- Furthermore, the D3D interop version of the swap chain has been reworked to support proper frames in flight (as opposed to do a full CPU-wait before presenting).
- Descriptor set pool sizes are now determined dynamically, depending on the number of allocations. ([See PR #115](https://github.com/crud89/LiteFX/pull/115))
- Use *Synchronization2* primitives for synchronization. ([See PR #122](https://github.com/crud89/LiteFX/pull/122))
- Render passes have been replaced with dynamic rendering. ([See PR #125](https://github.com/crud89/LiteFX/pull/125))

**❎ DirectX 12:**

Expand Down
1 change: 0 additions & 1 deletion src/Backends/DirectX12/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ SET(DIRECTX12_BACKEND_SOURCES
"src/queue.cpp"
"src/swapchain.cpp"
"src/frame_buffer.cpp"
"src/render_pass_dependency.cpp"
"src/render_pass.cpp"
"src/command_buffer.cpp"
"src/barrier.cpp"
Expand Down
463 changes: 203 additions & 260 deletions src/Backends/DirectX12/include/litefx/backends/dx12.hpp

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ namespace LiteFX::Rendering::Backends {
class DirectX12RayTracingPipeline;
class DirectX12FrameBuffer;
class DirectX12RenderPass;
class DirectX12RenderPassDependency;
class DirectX12SwapChain;
class DirectX12Queue;
class DirectX12GraphicsFactory;
Expand Down
20 changes: 2 additions & 18 deletions src/Backends/DirectX12/include/litefx/backends/dx12_builders.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ namespace LiteFX::Rendering::Backends {
/// <summary>
/// Initializes a DirectX 12 render pipeline builder.
/// </summary>
/// <param name="renderPass">The parent render pass</param>
/// <param name="renderPass">The parent render pass.</param>
/// <param name="name">A debug name for the render pipeline.</param>
constexpr inline explicit DirectX12RenderPipelineBuilder(const DirectX12RenderPass& renderPass, const String& name = "");
DirectX12RenderPipelineBuilder(DirectX12RenderPipelineBuilder&&) = delete;
Expand Down Expand Up @@ -333,14 +333,6 @@ namespace LiteFX::Rendering::Backends {
/// <param name="name">A debug name for the render pass.</param>
constexpr inline explicit DirectX12RenderPassBuilder(const DirectX12Device& device, const String& name = "") noexcept;

/// <summary>
/// Initializes a DirectX 12 render pass builder.
/// </summary>
/// <param name="device">The parent device</param>
/// <param name="samples">The multi-sampling level for the render targets.</param>
/// <param name="name">A debug name for the render pass.</param>
constexpr inline explicit DirectX12RenderPassBuilder(const DirectX12Device& device, MultiSamplingLevel samples = MultiSamplingLevel::x1, const String& name = "") noexcept;

/// <summary>
/// Initializes a DirectX 12 render pass builder.
/// </summary>
Expand All @@ -349,14 +341,6 @@ namespace LiteFX::Rendering::Backends {
/// <param name="name">A debug name for the render pass.</param>
constexpr inline explicit DirectX12RenderPassBuilder(const DirectX12Device& device, UInt32 commandBuffers, const String& name = "") noexcept;

/// <summary>
/// Initializes a DirectX 12 render pass builder.
/// </summary>
/// <param name="device">The parent device</param>
/// <param name="commandBuffers">The number of command buffers to initialize.</param>
/// <param name="multiSamplingLevel">The multi-sampling level for the render targets.</param>
/// <param name="name">A debug name for the render pass.</param>
constexpr inline explicit DirectX12RenderPassBuilder(const DirectX12Device& device, UInt32 commandBuffers, MultiSamplingLevel multiSamplingLevel, const String& name = "") noexcept;
DirectX12RenderPassBuilder(const DirectX12RenderPassBuilder&) noexcept = delete;
DirectX12RenderPassBuilder(DirectX12RenderPassBuilder&&) noexcept = delete;
constexpr inline virtual ~DirectX12RenderPassBuilder() noexcept;
Expand All @@ -369,7 +353,7 @@ namespace LiteFX::Rendering::Backends {
// RenderPassBuilder interface.
protected:
/// <inheritdoc />
inline DirectX12RenderPassDependency makeInputAttachment(DescriptorBindingPoint binding, const DirectX12RenderPass& renderPass, const RenderTarget& renderTarget) override;
inline RenderPassDependency makeInputAttachment(DescriptorBindingPoint binding, const RenderTarget& renderTarget) override;
};

}
Expand Down
24 changes: 12 additions & 12 deletions src/Backends/DirectX12/src/command_buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ void DirectX12CommandBuffer::barrier(const DirectX12Barrier& barrier) const noex
barrier.execute(*this);
}

void DirectX12CommandBuffer::transfer(IDirectX12Buffer& source, IDirectX12Buffer& target, UInt32 sourceElement, UInt32 targetElement, UInt32 elements) const
void DirectX12CommandBuffer::transfer(const IDirectX12Buffer& source, const IDirectX12Buffer& target, UInt32 sourceElement, UInt32 targetElement, UInt32 elements) const
{
if (source.elements() < sourceElement + elements) [[unlikely]]
throw ArgumentOutOfRangeException("sourceElement", "The source buffer has only {0} elements, but a transfer for {1} elements starting from element {2} has been requested.", source.elements(), elements, sourceElement);
Expand All @@ -334,7 +334,7 @@ void DirectX12CommandBuffer::transfer(IDirectX12Buffer& source, IDirectX12Buffer
this->handle()->CopyBufferRegion(std::as_const(target).handle().Get(), targetElement * target.alignedElementSize(), std::as_const(source).handle().Get(), sourceElement * source.alignedElementSize(), elements * source.alignedElementSize());
}

void DirectX12CommandBuffer::transfer(const void* const data, size_t size, IDirectX12Buffer& target, UInt32 targetElement, UInt32 elements) const
void DirectX12CommandBuffer::transfer(const void* const data, size_t size, const IDirectX12Buffer& target, UInt32 targetElement, UInt32 elements) const
{
auto alignment = target.elementAlignment();
auto elementSize = target.elementSize();
Expand All @@ -346,7 +346,7 @@ void DirectX12CommandBuffer::transfer(const void* const data, size_t size, IDire
this->transfer(stagingBuffer, target, 0, targetElement, elements);
}

void DirectX12CommandBuffer::transfer(Span<const void* const> data, size_t elementSize, IDirectX12Buffer& target, UInt32 firstElement) const
void DirectX12CommandBuffer::transfer(Span<const void* const> data, size_t elementSize, const IDirectX12Buffer& target, UInt32 firstElement) const
{
auto elements = static_cast<UInt32>(data.size());
auto stagingBuffer = asShared(std::move(m_impl->m_queue.device().factory().createBuffer(target.type(), ResourceHeap::Staging, target.elementSize(), elements)));
Expand All @@ -355,7 +355,7 @@ void DirectX12CommandBuffer::transfer(Span<const void* const> data, size_t eleme
this->transfer(stagingBuffer, target, 0, firstElement, elements);
}

void DirectX12CommandBuffer::transfer(IDirectX12Buffer& source, IDirectX12Image& target, UInt32 sourceElement, UInt32 firstSubresource, UInt32 elements) const
void DirectX12CommandBuffer::transfer(const IDirectX12Buffer& source, const IDirectX12Image& target, UInt32 sourceElement, UInt32 firstSubresource, UInt32 elements) const
{
if (source.elements() < sourceElement + elements) [[unlikely]]
throw ArgumentOutOfRangeException("sourceElement", "The source buffer has only {0} elements, but a transfer for {1} elements starting from element {2} has been requested.", source.elements(), elements, sourceElement);
Expand All @@ -374,15 +374,15 @@ void DirectX12CommandBuffer::transfer(IDirectX12Buffer& source, IDirectX12Image&
}
}

void DirectX12CommandBuffer::transfer(const void* const data, size_t size, IDirectX12Image& target, UInt32 subresource) const
void DirectX12CommandBuffer::transfer(const void* const data, size_t size, const IDirectX12Image& target, UInt32 subresource) const
{
auto stagingBuffer = asShared(std::move(m_impl->m_queue.device().factory().createBuffer(BufferType::Other, ResourceHeap::Staging, size)));
stagingBuffer->map(data, size, 0);

this->transfer(stagingBuffer, target, 0, subresource, 1);
}

void DirectX12CommandBuffer::transfer(Span<const void* const> data, size_t elementSize, IDirectX12Image& target, UInt32 firstSubresource, UInt32 subresources) const
void DirectX12CommandBuffer::transfer(Span<const void* const> data, size_t elementSize, const IDirectX12Image& target, UInt32 firstSubresource, UInt32 subresources) const
{
auto elements = static_cast<UInt32>(data.size());
auto stagingBuffer = asShared(std::move(m_impl->m_queue.device().factory().createBuffer(BufferType::Other, ResourceHeap::Staging, elementSize, elements)));
Expand All @@ -391,7 +391,7 @@ void DirectX12CommandBuffer::transfer(Span<const void* const> data, size_t eleme
this->transfer(stagingBuffer, target, 0, firstSubresource, subresources);
}

void DirectX12CommandBuffer::transfer(IDirectX12Image& source, IDirectX12Image& target, UInt32 sourceSubresource, UInt32 targetSubresource, UInt32 subresources) const
void DirectX12CommandBuffer::transfer(const IDirectX12Image& source, const IDirectX12Image& target, UInt32 sourceSubresource, UInt32 targetSubresource, UInt32 subresources) const
{
if (source.elements() < sourceSubresource + subresources) [[unlikely]]
throw ArgumentOutOfRangeException("sourceElement", "The source image has only {0} sub-resources, but a transfer for {1} sub-resources starting from sub-resource {2} has been requested.", source.elements(), subresources, sourceSubresource);
Expand All @@ -406,7 +406,7 @@ void DirectX12CommandBuffer::transfer(IDirectX12Image& source, IDirectX12Image&
}
}

void DirectX12CommandBuffer::transfer(IDirectX12Image& source, IDirectX12Buffer& target, UInt32 firstSubresource, UInt32 targetElement, UInt32 subresources) const
void DirectX12CommandBuffer::transfer(const IDirectX12Image& source, const IDirectX12Buffer& target, UInt32 firstSubresource, UInt32 targetElement, UInt32 subresources) const
{
if (source.elements() < firstSubresource + subresources) [[unlikely]]
throw ArgumentOutOfRangeException("sourceElement", "The source image has only {0} sub-resources, but a transfer for {1} sub-resources starting from sub-resource {2} has been requested.", source.elements(), subresources, firstSubresource);
Expand All @@ -425,25 +425,25 @@ void DirectX12CommandBuffer::transfer(IDirectX12Image& source, IDirectX12Buffer&
}
}

void DirectX12CommandBuffer::transfer(SharedPtr<IDirectX12Buffer> source, IDirectX12Buffer& target, UInt32 sourceElement, UInt32 targetElement, UInt32 elements) const
void DirectX12CommandBuffer::transfer(SharedPtr<const IDirectX12Buffer> source, const IDirectX12Buffer& target, UInt32 sourceElement, UInt32 targetElement, UInt32 elements) const
{
this->transfer(*source, target, sourceElement, targetElement, elements);
m_impl->m_sharedResources.push_back(source);
}

void DirectX12CommandBuffer::transfer(SharedPtr<IDirectX12Buffer> source, IDirectX12Image& target, UInt32 sourceElement, UInt32 firstSubresource, UInt32 elements) const
void DirectX12CommandBuffer::transfer(SharedPtr<const IDirectX12Buffer> source, const IDirectX12Image& target, UInt32 sourceElement, UInt32 firstSubresource, UInt32 elements) const
{
this->transfer(*source, target, sourceElement, firstSubresource, elements);
m_impl->m_sharedResources.push_back(source);
}

void DirectX12CommandBuffer::transfer(SharedPtr<IDirectX12Image> source, IDirectX12Image& target, UInt32 sourceSubresource, UInt32 targetSubresource, UInt32 subresources) const
void DirectX12CommandBuffer::transfer(SharedPtr<const IDirectX12Image> source, const IDirectX12Image& target, UInt32 sourceSubresource, UInt32 targetSubresource, UInt32 subresources) const
{
this->transfer(*source, target, sourceSubresource, targetSubresource, subresources);
m_impl->m_sharedResources.push_back(source);
}

void DirectX12CommandBuffer::transfer(SharedPtr<IDirectX12Image> source, IDirectX12Buffer& target, UInt32 firstSubresource, UInt32 targetElement, UInt32 subresources) const
void DirectX12CommandBuffer::transfer(SharedPtr<const IDirectX12Image> source, const IDirectX12Buffer& target, UInt32 firstSubresource, UInt32 targetElement, UInt32 subresources) const
{
this->transfer(*source, target, firstSubresource, targetElement, subresources);
m_impl->m_sharedResources.push_back(source);
Expand Down
13 changes: 9 additions & 4 deletions src/Backends/DirectX12/src/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -456,14 +456,14 @@ DirectX12ComputePipeline& DirectX12Device::blitPipeline() const noexcept
}

#if defined(LITEFX_BUILD_DEFINE_BUILDERS)
DirectX12RenderPassBuilder DirectX12Device::buildRenderPass(MultiSamplingLevel samples, UInt32 commandBuffers) const
DirectX12RenderPassBuilder DirectX12Device::buildRenderPass(UInt32 commandBuffers) const
{
return DirectX12RenderPassBuilder(*this, commandBuffers, samples);
return DirectX12RenderPassBuilder(*this, commandBuffers);
}

DirectX12RenderPassBuilder DirectX12Device::buildRenderPass(const String& name, MultiSamplingLevel samples, UInt32 commandBuffers) const
DirectX12RenderPassBuilder DirectX12Device::buildRenderPass(const String& name, UInt32 commandBuffers) const
{
return DirectX12RenderPassBuilder(*this, commandBuffers, samples, name);
return DirectX12RenderPassBuilder(*this, commandBuffers, name);
}

DirectX12RenderPipelineBuilder DirectX12Device::buildRenderPipeline(const DirectX12RenderPass& renderPass, const String& name) const
Expand Down Expand Up @@ -565,6 +565,11 @@ UniquePtr<DirectX12Barrier> DirectX12Device::makeBarrier(PipelineStage syncBefor
return makeUnique<DirectX12Barrier>(syncBefore, syncAfter);
}

UniquePtr<DirectX12FrameBuffer> DirectX12Device::makeFrameBuffer(StringView name, const Size2d& renderArea) const noexcept
{
return makeUnique<DirectX12FrameBuffer>(*this, renderArea, name);
}

MultiSamplingLevel DirectX12Device::maximumMultiSamplingLevel(Format format) const noexcept
{
constexpr std::array<MultiSamplingLevel, 7> allLevels = { MultiSamplingLevel::x64, MultiSamplingLevel::x32, MultiSamplingLevel::x16, MultiSamplingLevel::x8, MultiSamplingLevel::x4, MultiSamplingLevel::x2, MultiSamplingLevel::x1 };
Expand Down
82 changes: 22 additions & 60 deletions src/Backends/DirectX12/src/factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,55 +217,6 @@ UniquePtr<IDirectX12IndexBuffer> DirectX12GraphicsFactory::createIndexBuffer(con
return DirectX12IndexBuffer::allocate(name, layout, m_impl->m_allocator, elements, usage, resourceDesc, allocationDesc);
}

UniquePtr<IDirectX12Image> DirectX12GraphicsFactory::createAttachment(const RenderTarget& target, const Size2d& size, MultiSamplingLevel samples) const
{
return this->createAttachment("", target, size, samples);
}

UniquePtr<IDirectX12Image> DirectX12GraphicsFactory::createAttachment(const String& name, const RenderTarget& target, const Size2d& size, MultiSamplingLevel samples) const
{
// Setup default usage.
ResourceUsage usage = ResourceUsage::TransferSource;

if (target.allowStorage())
usage |= ResourceUsage::TransferDestination | ResourceUsage::AllowWrite;

const auto format = target.format();
const auto width = std::max<UInt32>(1, size.width());
const auto height = std::max<UInt32>(1, size.height());

D3D12_RESOURCE_DESC1 resourceDesc { };
resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
resourceDesc.Alignment = 0;
resourceDesc.Width = width;
resourceDesc.Height = height;
resourceDesc.DepthOrArraySize = 1;
resourceDesc.MipLevels = 1;
resourceDesc.Format = DX12::getFormat(format);
resourceDesc.SampleDesc = samples == MultiSamplingLevel::x1 ? DXGI_SAMPLE_DESC{ 1, 0 } : DXGI_SAMPLE_DESC{ static_cast<UInt32>(samples), DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN };
resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;

if (target.allowStorage())
resourceDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;

//if (target.multiQueueAccess())
// resourceDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS;

D3D12MA::ALLOCATION_DESC allocationDesc { .HeapType = D3D12_HEAP_TYPE_DEFAULT };

if (::hasDepth(format) || ::hasStencil(format))
{
resourceDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
return DirectX12Image::allocate(name, m_impl->m_device, m_impl->m_allocator, { width, height, 1 }, format, ImageDimensions::DIM_2, 1, 1, samples, usage, resourceDesc, allocationDesc);
}
else
{
resourceDesc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
return DirectX12Image::allocate(name, m_impl->m_device, m_impl->m_allocator, { width, height, 1 }, format, ImageDimensions::DIM_2, 1, 1, samples, usage, resourceDesc, allocationDesc);
}
}

UniquePtr<IDirectX12Image> DirectX12GraphicsFactory::createTexture(Format format, const Size3d& size, ImageDimensions dimension, UInt32 levels, UInt32 layers, MultiSamplingLevel samples, ResourceUsage usage) const
{
return this->createTexture("", format, size, dimension, levels, layers, samples, usage);
Expand All @@ -287,17 +238,28 @@ UniquePtr<IDirectX12Image> DirectX12GraphicsFactory::createTexture(const String&
auto height = std::max<UInt32>(1, size.height());
auto depth = std::max<UInt32>(1, size.depth());

D3D12_RESOURCE_DESC1 resourceDesc { };
resourceDesc.Dimension = DX12::getImageType(dimension);
resourceDesc.Alignment = 0;
resourceDesc.Width = width;
resourceDesc.Height = height;
resourceDesc.DepthOrArraySize = dimension == ImageDimensions::DIM_3 ? depth : layers;
resourceDesc.MipLevels = levels;
resourceDesc.Format = DX12::getFormat(format);
resourceDesc.SampleDesc = samples == MultiSamplingLevel::x1 ? DXGI_SAMPLE_DESC{ 1, 0 } : DXGI_SAMPLE_DESC{ static_cast<UInt32>(samples), DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN };
resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
resourceDesc.Flags = LITEFX_FLAG_IS_SET(usage, ResourceUsage::AllowWrite) ? D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS : D3D12_RESOURCE_FLAG_NONE;
D3D12_RESOURCE_FLAGS flags = LITEFX_FLAG_IS_SET(usage, ResourceUsage::AllowWrite) ? D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS : D3D12_RESOURCE_FLAG_NONE;

if (LITEFX_FLAG_IS_SET(usage, ResourceUsage::RenderTarget))
{
if (::hasDepth(format) || ::hasStencil(format))
flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
else
flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
}

D3D12_RESOURCE_DESC1 resourceDesc = {
.Dimension = DX12::getImageType(dimension),
.Alignment = 0,
.Width = width,
.Height = height,
.DepthOrArraySize = static_cast<UInt16>(dimension == ImageDimensions::DIM_3 ? depth : layers),
.MipLevels = static_cast<UInt16>(levels),
.Format = DX12::getFormat(format),
.SampleDesc = samples == MultiSamplingLevel::x1 ? DXGI_SAMPLE_DESC{ 1, 0 } : DXGI_SAMPLE_DESC{ static_cast<UInt32>(samples), DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN },
.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,
.Flags = flags,
};

D3D12MA::ALLOCATION_DESC allocationDesc { .HeapType = D3D12_HEAP_TYPE_DEFAULT };

Expand Down
Loading

0 comments on commit 864a2dc

Please sign in to comment.