Skip to content

Commit

Permalink
Refactored binding model by deprecating "ResetResourceSlots()".
Browse files Browse the repository at this point in the history
This is a larger refactoring first and foremost in the D3D11 backend since all other backends don't need to unbind resources when used simultaneously as read-only and read-write resources.
With this change, LLGL automatically unbinds resources in the D3D11 backend so client code doesn't have to track SRV and UAV resources anymore.
Only constant buffers and samplers are bound just as before, since those resources cannot be bound as read-write resources.
- Deprecated "ResetResourceSlots()" as primary goal of this change.
- Added default dummy implementation of ResetResourceSlots() and removed implementations from all backends.
- Added thin (8 bytes) class "D3D11BindingLocator" to D3D11Buffer, D3D11BufferArray, and D3D11Texture: Stores information and range about the global binding tables.
- Added D3D11BindingTable class: This is the main class for this new mechanism and automatically evicts resources from output slots when used as input (and vice-versa).
- Added "D3D11RenderTargetHandles" class to better handle array of RTV, DSV, binding locators, and subresource ranges.
- Added SparseForwardIterator<T> template to simplify iterating over binding tables with lots of null entries.
- Integrated D3D11BindingLocator and D3D11SubresourceRange entries into D3D11ResourceHeap: Included in every heap section
  (TODO: don't include in heap section if none of the resources could ever have a binding locatorl, such as samplers and cbuffers).
- Moved "SetShaderResources()" and "SetUnorderedAccessViews()" from D3D11StateManager to D3D11BindingTable.
- Removed GLCmdUnbindResources and GLOpcodeUnbindResources from GL backend.
- Removed Unbind* functions from GLStateManager.
  • Loading branch information
LukasBanana committed May 10, 2024
1 parent 591fb23 commit f492217
Show file tree
Hide file tree
Showing 51 changed files with 2,688 additions and 898 deletions.
13 changes: 13 additions & 0 deletions docu/ChangeLog/ChangeLog-v0.04.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Version 0.04 introduced deprecated attributes (via `LLGL_DEPRECATED`) to keep co
- [Video adapter descriptors](#video-adapter-descriptors)
- [Rendering features](#rendering-features)
- [`FrameProfile` structure](#frameprofile-structure)
- [Binding model](#binding-model)
- [Renamed identifiers](#renamed-identifiers)


Expand Down Expand Up @@ -69,6 +70,18 @@ The following entries from `RenderingFeatures` have been deprecated:
The entire union inside the `LLGL::FrameProfile` structure has been deprecated and replaced by `LLGL::ProfileCommandQueueRecord` and `LLGL::ProfileCommandBufferRecord`.


## Binding model

The binding model in LLGL is finally fully abstracted from the rendering API to the point where the actual binding slots are only defined in the `PipelineLayout`.
This only affects one function that has been deprecated, which is `ResetResourceSlots`. Simply remove the function call, no replacement is needed.
Said function was only needed for the D3D11 backend which is now managed to automatically unbind resources to avoid overlapping read-only and read-write resource views.

Rationale:
1. `ResetResourceSlots` used backend specific resource slots instead of the descriptor slots from a `PipelineLayout`. This is opposed to the `SetResource` and `SetResourceHeap` interfaces.
2. Changing `ResetResourceSlots` to use the same binding model as `SetResource(-Heap)` requires a depedency to the active PSO, which doesn't include stream-outputs and render-targets.
3. Modern rendering APIs (i.e. Vulkan, D3D12, Metal) either use a resource heap binding model or command encoder that don't save the binding state across multiple frames (or across multiple render-passes). Since LLGL aims to be aligned towards the newer APIs, the older backends should emulate that same functionality and not require to manually unbind resources.


## Renamed identifiers

The following identifiers have also been renamed and their old names have been deprecated as type aliases, i.e. they are still available but will be removed in the next version of LLGL:
Expand Down
12 changes: 0 additions & 12 deletions examples/Cpp/ClothPhysics/Example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -610,12 +610,6 @@ class Example_ClothPhysics : public ExampleBase
commands->Dispatch(clothSegmentsU + 1, clothSegmentsV + 1, 1);
}
commands->PopDebugGroup();

#ifdef ENABLE_STORAGE_TEXTURES
commands->ResetResourceSlots(LLGL::ResourceType::Texture, 2, 5, LLGL::BindFlags::Storage, LLGL::StageFlags::ComputeStage);
#else
commands->ResetResourceSlots(LLGL::ResourceType::Buffer, 4, 3, LLGL::BindFlags::Storage, LLGL::StageFlags::ComputeStage);
#endif
}
commands->End();
commandQueue->Submit(*commands);
Expand Down Expand Up @@ -643,12 +637,6 @@ class Example_ClothPhysics : public ExampleBase
commands->SetPipelineState(*graphicsPipeline);
commands->SetResourceHeap(*graphicsResourceHeap);
commands->DrawIndexed(numClothIndices, 0);

#ifdef ENABLE_STORAGE_TEXTURES
commands->ResetResourceSlots(LLGL::ResourceType::Texture, 1, 3, LLGL::BindFlags::Sampled, LLGL::StageFlags::VertexStage);
#else
commands->ResetResourceSlots(LLGL::ResourceType::Buffer, 0, 2, LLGL::BindFlags::VertexBuffer, LLGL::StageFlags::VertexStage);
#endif
}
commands->EndRenderPass();
}
Expand Down
6 changes: 0 additions & 6 deletions examples/Cpp/ComputeShader/Example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,6 @@ class Example_ComputeShader : public ExampleBase
// Add debugging names
computeLayout->SetDebugName("Compute.Layout");
computeResourceHeap->SetDebugName("Compute.ResourceHeap");
graphicsVertexShader->SetDebugName("Graphics.VertexShader");
graphicsFragmentShader->SetDebugName("Graphics.FragmentShader");
}

void CreateBuffers()
Expand Down Expand Up @@ -244,8 +242,6 @@ class Example_ComputeShader : public ExampleBase
commands->SetPipelineState(*computePipeline);
commands->SetResourceHeap(*computeResourceHeap);
commands->Dispatch(sceneState.numSceneObjects, 1, 1);

commands->ResetResourceSlots(LLGL::ResourceType::Buffer, 3, 1, LLGL::BindFlags::Storage, LLGL::StageFlags::ComputeStage);
}
commands->End();
commandQueue->Submit(*commands);
Expand All @@ -266,8 +262,6 @@ class Example_ComputeShader : public ExampleBase
// Draw scene with indirect argument buffer
commands->SetPipelineState(*graphicsPipeline);
commands->DrawIndirect(*indirectArgBuffer, 0, 2, sizeof(LLGL::DrawIndirectArguments));

commands->ResetResourceSlots(LLGL::ResourceType::Buffer, 1, 1, LLGL::BindFlags::VertexBuffer, LLGL::StageFlags::VertexStage);
}
commands->EndRenderPass();
}
Expand Down
8 changes: 0 additions & 8 deletions examples/Cpp/RenderTarget/Example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -438,10 +438,6 @@ class Example_RenderTarget : public ExampleBase

#endif // /ENABLE_CBUFFER_RANGE

#ifdef ENABLE_CUSTOM_MULTISAMPLING
commands->ResetResourceSlots(LLGL::ResourceType::Texture, 3, 1, LLGL::BindFlags::Sampled, LLGL::StageFlags::FragmentStage);
#endif

// Begin render pass for render target
commands->BeginRenderPass(*renderTarget);
{
Expand Down Expand Up @@ -493,10 +489,6 @@ class Example_RenderTarget : public ExampleBase
// Generate MIP-maps again after texture has been written by the render-target
commands->GenerateMips(*renderTargetTex);

#ifdef ENABLE_CUSTOM_MULTISAMPLING
commands->ResetResourceSlots(LLGL::ResourceType::Texture, 3, 1, LLGL::BindFlags::Sampled, LLGL::StageFlags::FragmentStage);
#endif

// Begin render pass for swap-chain
commands->BeginRenderPass(*swapChain);
{
Expand Down
3 changes: 0 additions & 3 deletions examples/Cpp/ShadowMapping/Example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,9 +345,6 @@ class Example_ShadowMapping : public ExampleBase
// Bind common input assembly
commands->SetVertexBuffer(*vertexBuffer);

// Unbind shadow texture before rendering into it
commands->ResetResourceSlots(LLGL::ResourceType::Texture, 2, 1, LLGL::BindFlags::Sampled, LLGL::StageFlags::FragmentStage);

// Draw scene into shadow-map, then draw scene onto screen
commands->PushDebugGroup("Shadow Map Pass");
RenderShadowMap();
Expand Down
6 changes: 1 addition & 5 deletions examples/Cpp/VolumeRendering/Example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ class Example_VolumeRendering : public ExampleBase

void CreatePipelineLayouts()
{
// Create pipeline layout with only a single constnat buffer for depth-range pass and Z-pre pass
// Create pipeline layout with only a single constant buffer for depth-range pass and Z-pre pass
pipelineLayoutCbuffer = renderer->CreatePipelineLayout(LLGL::Parse("heap{ cbuffer(Settings@1):frag:vert }"));

// Create pipeline layout for final scene rendering
Expand Down Expand Up @@ -376,8 +376,6 @@ class Example_VolumeRendering : public ExampleBase
}
commands->EndRenderPass();

commands->ResetResourceSlots(LLGL::ResourceType::Texture, 3, 1, LLGL::BindFlags::Sampled, LLGL::StageFlags::FragmentStage);

// Render everything directly into the swap-chain
commands->BeginRenderPass(*swapChain);
{
Expand All @@ -403,8 +401,6 @@ class Example_VolumeRendering : public ExampleBase
commands->PopDebugGroup();
}
commands->EndRenderPass();

commands->ResetResourceSlots(LLGL::ResourceType::Texture, 3, 1, LLGL::BindFlags::Sampled, LLGL::StageFlags::FragmentStage);
}
commands->End();
commandQueue->Submit(*commands);
Expand Down
1 change: 1 addition & 0 deletions include/LLGL-C/CommandBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ LLGL_C_EXPORT void llglSetIndexBuffer(LLGLBuffer buffer);
LLGL_C_EXPORT void llglSetIndexBufferExt(LLGLBuffer buffer, LLGLFormat format, uint64_t offset);
LLGL_C_EXPORT void llglSetResourceHeap(LLGLResourceHeap resourceHeap, uint32_t descriptorSet);
LLGL_C_EXPORT void llglSetResource(uint32_t descriptor, LLGLResource resource);
//LLGL_DEPRECATED("llglResetResourceSlots is deprecated since 0.04b; No need to reset resource slots manually anymore!")
LLGL_C_EXPORT void llglResetResourceSlots(LLGLResourceType resourceType, uint32_t firstSlot, uint32_t numSlots, long bindFlags, long stageFlags);
LLGL_C_EXPORT void llglBeginRenderPass(LLGLRenderTarget renderTarget);
LLGL_C_EXPORT void llglBeginRenderPassWithClear(LLGLRenderTarget renderTarget, LLGLRenderPass renderPass, uint32_t numClearValues, const LLGLClearValue* clearValues LLGL_ANNOTATE([numClearValues]), uint32_t swapBufferIndex);
Expand Down
8 changes: 0 additions & 8 deletions include/LLGL/Backend/CommandBuffer.Resources.inl
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,6 @@ virtual void SetResource(
LLGL::Resource& resource
) override final;

virtual void ResetResourceSlots(
const LLGL::ResourceType resourceType,
std::uint32_t firstSlot,
std::uint32_t numSlots,
long bindFlags,
long stageFlags = LLGL::StageFlags::AllStages
) override final;



// ================================================================================
28 changes: 3 additions & 25 deletions include/LLGL/CommandBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -456,37 +456,15 @@ class LLGL_EXPORT CommandBuffer : public RenderSystemChild
*/
virtual void SetResource(std::uint32_t descriptor, Resource& resource) = 0;

/**
\brief Resets the binding slots for the specified resources.
\param[in] resourceType Specifies the type of resources to unbind.
\param[in] firstSlot Specifies the first binding slot beginning with zero.
This must be zero for the following resource types: ResourceType::IndexBuffer, ResourceType::StreamOutputBuffer.
\param[in] numSlots Specifies the number of binding slots to reset. If this is zero, the function has no effect.
\param[in] bindFlags Specifies which kind of binding slots to reset.
This can be a bitwise OR combinations of the BindFlags entries.
To reset a vertex buffer slot for instance, it must contain the BindFlags::VertexBuffer flag.
\param[in] stageFlags Specifies which shader stages are affected.
This can be a bitwise OR combination of the StageFlags entries. By default StageFlags::AllStages.
\remarks This should be called when a resource is currently bound as shader output and will be bound as shader input for the next draw or compute commands.
\remarks If direct resource binding is not supported by the render system, this function has no effect.
\note Only supported with: OpenGL, Direct3D 11, Metal.
\see BindFlags
\see StageFlags
*/
//! \deprecated
LLGL_DEPRECATED("CommandBuffer::ResetResourceSlots is deprecated since 0.04b; No need to reset resource slots manually anymore!")
virtual void ResetResourceSlots(
const ResourceType resourceType,
std::uint32_t firstSlot,
std::uint32_t numSlots,
long bindFlags,
long stageFlags = StageFlags::AllStages
) = 0;
);

/* ----- Render Passes ----- */

Expand Down
10 changes: 10 additions & 0 deletions sources/Core/CompilerExtensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@
# define LLGL_MAYBE_UNUSED
#endif

#if __cplusplus >= 201703L // C++17
# define LLGL_NODISCARD [[nodiscard]]
#elif defined __GNUC__ || defined __clang__ // GNU/Clang extensions
# define LLGL_NODISCARD __attribute__((warn_unused_result))
#elif _MSC_VER >= 1700 // MSVC extensions
# define LLGL_NODISCARD _Check_return_
#else
# define LLGL_NODISCARD
#endif


#endif

Expand Down
103 changes: 103 additions & 0 deletions sources/Core/SparseForwardIterator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* SparseForwardIterator.h
*
* Copyright (c) 2015 Lukas Hermanns. All rights reserved.
* Licensed under the terms of the BSD 3-Clause license (see LICENSE.txt).
*/

#ifndef LLGL_SPARSE_FORWARD_ITERATOR_H
#define LLGL_SPARSE_FORWARD_ITERATOR_H


namespace LLGL
{


// Forward iterator over a range of objects that skips over null pointers. See D3D11BindingTable.
template <typename T>
class SparseForwardIterator
{

public:

using value_type = T;
using pointer = T*;
using reference = T&;

public:

SparseForwardIterator() noexcept = default;
SparseForwardIterator(const SparseForwardIterator&) noexcept = default;
SparseForwardIterator& operator = (const SparseForwardIterator&) noexcept = default;

SparseForwardIterator(pointer end) noexcept :
cur_ { end },
end_ { end }
{
}

SparseForwardIterator(pointer cur, pointer end) noexcept :
cur_ { cur },
end_ { end }
{
SkipNullEntries();
}

SparseForwardIterator& operator ++ ()
{
++cur_;
SkipNullEntries();
return *this;
}

SparseForwardIterator operator ++ (int)
{
SparseForwardIterator result = *this;
this->operator++();
return result;
}

bool operator == (const SparseForwardIterator& rhs) const noexcept
{
return (cur_ == rhs.cur_);
}

bool operator != (const SparseForwardIterator& rhs) const noexcept
{
return (cur_ != rhs.cur_);
}

reference operator * () const noexcept
{
return *cur_;
}

pointer operator -> () const noexcept
{
return cur_;
}

private:

void SkipNullEntries() noexcept
{
while (*cur_ == nullptr && cur_ != end_)
++cur_;
}

private:

pointer cur_ = nullptr;
pointer end_ = nullptr;

};


} // /namespace LLGL


#endif



// ================================================================================
24 changes: 8 additions & 16 deletions sources/Renderer/DXCommon/DXManagedComPtrArray.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@


#include "ComPtr.h"
#include "../../Core/Assertion.h"
#include <LLGL/Utils/ForRange.h>
#include <vector>
#include <algorithm>
#include <stdexcept>
#include <string>


Expand Down Expand Up @@ -62,26 +62,18 @@ class DXManagedComPtrArray
// Replaces the entry at the specified position.
void Exchange(std::size_t index, const ComPtr<T>& object)
{
if (index < container_.size())
{
container_[index] = object;
if (object == nullptr)
lowerFreeBound_ = std::min(lowerFreeBound_, index);
}
else
throw std::out_of_range("DXManagedComPtrArray<T>::Exchange(" + std::to_string(index) + "): index out of range");
LLGL_ASSERT(index < container_.size());
container_[index] = object;
if (object == nullptr)
lowerFreeBound_ = std::min(lowerFreeBound_, index);
}

// Removes the entry at the specified location.
void Remove(std::size_t index)
{
if (index < container_.size())
{
container_[index] = nullptr;
lowerFreeBound_ = std::min(lowerFreeBound_, index);
}
else
throw std::out_of_range("DXManagedComPtrArray<T>::Remove(" + std::to_string(index) + "): index out of range");
LLGL_ASSERT(index < container_.size());
container_[index] = nullptr;
lowerFreeBound_ = std::min(lowerFreeBound_, index);
}

public:
Expand Down
18 changes: 0 additions & 18 deletions sources/Renderer/DebugLayer/DbgCommandBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -666,24 +666,6 @@ void DbgCommandBuffer::SetResource(std::uint32_t descriptor, Resource& resource)
}
}

void DbgCommandBuffer::ResetResourceSlots(
const ResourceType resourceType,
std::uint32_t firstSlot,
std::uint32_t numSlots,
long bindFlags,
long stageFlags)
{
if (debugger_)
{
LLGL_DBG_SOURCE();
if (numSlots == 0)
LLGL_DBG_WARN(WarningType::PointlessOperation, "no slots are specified to reset");
ValidateStageFlags(stageFlags, StageFlags::AllStages);
}

LLGL_DBG_COMMAND( "ResetResourceSlots", instance.ResetResourceSlots(resourceType, firstSlot, numSlots, bindFlags, stageFlags) );
}

/* ----- Render Passes ----- */

void DbgCommandBuffer::BeginRenderPass(
Expand Down
Loading

0 comments on commit f492217

Please sign in to comment.