summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngine
diff options
context:
space:
mode:
authorassiduous <assiduous@diligentgraphics.com>2020-12-15 19:32:55 +0000
committerassiduous <assiduous@diligentgraphics.com>2020-12-15 19:32:55 +0000
commit2cbe12c8541f63719ae3662cda827ed53004c0b2 (patch)
tree6ff68d7ee7d386d1c0e30c00fcd551fcbf819c6c /Graphics/GraphicsEngine
parentMath Lib: added Matrix4x4 constructor from float4 rows (diff)
parentBasicMath: minor code formatting (diff)
downloadDiligentCore-2cbe12c8541f63719ae3662cda827ed53004c0b2.tar.gz
DiligentCore-2cbe12c8541f63719ae3662cda827ed53004c0b2.zip
Merge branch 'azhirnov-ray_tracing_2'
Diffstat (limited to 'Graphics/GraphicsEngine')
-rw-r--r--Graphics/GraphicsEngine/CMakeLists.txt11
-rw-r--r--Graphics/GraphicsEngine/include/BottomLevelASBase.hpp256
-rw-r--r--Graphics/GraphicsEngine/include/BufferBase.hpp195
-rw-r--r--Graphics/GraphicsEngine/include/DeviceContextBase.hpp772
-rw-r--r--Graphics/GraphicsEngine/include/FramebufferBase.hpp4
-rw-r--r--Graphics/GraphicsEngine/include/PipelineStateBase.hpp240
-rw-r--r--Graphics/GraphicsEngine/include/RenderDeviceBase.hpp27
-rw-r--r--Graphics/GraphicsEngine/include/RenderPassBase.hpp4
-rw-r--r--Graphics/GraphicsEngine/include/ResourceMappingImpl.hpp106
-rw-r--r--Graphics/GraphicsEngine/include/ShaderBase.hpp3
-rw-r--r--Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp548
-rw-r--r--Graphics/GraphicsEngine/include/ShaderResourceBindingBase.hpp2
-rw-r--r--Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp74
-rw-r--r--Graphics/GraphicsEngine/include/TextureBase.hpp389
-rw-r--r--Graphics/GraphicsEngine/include/TopLevelASBase.hpp385
-rw-r--r--Graphics/GraphicsEngine/interface/APIInfo.h120
-rw-r--r--Graphics/GraphicsEngine/interface/BottomLevelAS.h290
-rw-r--r--Graphics/GraphicsEngine/interface/Buffer.h2
-rw-r--r--Graphics/GraphicsEngine/interface/Constants.h4
-rw-r--r--Graphics/GraphicsEngine/interface/DeviceContext.h712
-rw-r--r--Graphics/GraphicsEngine/interface/GraphicsTypes.h201
-rw-r--r--Graphics/GraphicsEngine/interface/PipelineState.h156
-rw-r--r--Graphics/GraphicsEngine/interface/RenderDevice.h90
-rw-r--r--Graphics/GraphicsEngine/interface/Shader.h33
-rw-r--r--Graphics/GraphicsEngine/interface/ShaderBindingTable.h282
-rw-r--r--Graphics/GraphicsEngine/interface/TopLevelAS.h218
-rw-r--r--Graphics/GraphicsEngine/src/APIInfo.cpp4
-rw-r--r--Graphics/GraphicsEngine/src/BottomLevelASBase.cpp188
-rw-r--r--Graphics/GraphicsEngine/src/BufferBase.cpp57
-rw-r--r--Graphics/GraphicsEngine/src/DefaultShaderSourceStreamFactory.cpp1
-rw-r--r--Graphics/GraphicsEngine/src/DeviceContextBase.cpp776
-rw-r--r--Graphics/GraphicsEngine/src/EngineMemory.cpp2
-rw-r--r--Graphics/GraphicsEngine/src/FramebufferBase.cpp3
-rw-r--r--Graphics/GraphicsEngine/src/PipelineStateBase.cpp97
-rw-r--r--Graphics/GraphicsEngine/src/RenderPassBase.cpp3
-rw-r--r--Graphics/GraphicsEngine/src/ResourceMappingBase.cpp16
-rw-r--r--Graphics/GraphicsEngine/src/ShaderBindingTableBase.cpp64
-rw-r--r--Graphics/GraphicsEngine/src/TextureBase.cpp230
-rw-r--r--Graphics/GraphicsEngine/src/TopLevelASBase.cpp (renamed from Graphics/GraphicsEngine/include/pch.h)56
39 files changed, 5524 insertions, 1097 deletions
diff --git a/Graphics/GraphicsEngine/CMakeLists.txt b/Graphics/GraphicsEngine/CMakeLists.txt
index d95257fe..604f3442 100644
--- a/Graphics/GraphicsEngine/CMakeLists.txt
+++ b/Graphics/GraphicsEngine/CMakeLists.txt
@@ -14,7 +14,6 @@ set(INCLUDE
include/EngineMemory.h
include/FenceBase.hpp
include/FramebufferBase.hpp
- include/pch.h
include/PipelineStateBase.hpp
include/QueryBase.hpp
include/RenderDeviceBase.hpp
@@ -28,6 +27,9 @@ set(INCLUDE
include/SwapChainBase.hpp
include/TextureBase.hpp
include/TextureViewBase.hpp
+ include/BottomLevelASBase.hpp
+ include/TopLevelASBase.hpp
+ include/ShaderBindingTableBase.hpp
)
set(INTERFACE
@@ -58,18 +60,25 @@ set(INTERFACE
interface/SwapChain.h
interface/Texture.h
interface/TextureView.h
+ interface/BottomLevelAS.h
+ interface/TopLevelAS.h
+ interface/ShaderBindingTable.h
)
set(SOURCE
src/APIInfo.cpp
+ src/BottomLevelASBase.cpp
src/BufferBase.cpp
src/DefaultShaderSourceStreamFactory.cpp
+ src/DeviceContextBase.cpp
src/EngineMemory.cpp
src/FramebufferBase.cpp
src/PipelineStateBase.cpp
src/ResourceMappingBase.cpp
+ src/ShaderBindingTableBase.cpp
src/RenderPassBase.cpp
src/TextureBase.cpp
+ src/TopLevelASBase.cpp
)
add_library(Diligent-GraphicsEngine STATIC ${SOURCE} ${INTERFACE} ${INCLUDE})
diff --git a/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp b/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp
new file mode 100644
index 00000000..4e061c4c
--- /dev/null
+++ b/Graphics/GraphicsEngine/include/BottomLevelASBase.hpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Implementation of the Diligent::BottomLevelASBase template class
+
+#include <unordered_map>
+#include <atomic>
+
+#include "BottomLevelAS.h"
+#include "DeviceObjectBase.hpp"
+#include "RenderDeviceBase.hpp"
+#include "FixedLinearAllocator.hpp"
+#include "HashUtils.hpp"
+
+namespace Diligent
+{
+
+struct BLASGeomIndex
+{
+ Uint32 IndexInDesc = INVALID_INDEX; // geometry index in description
+ Uint32 ActualIndex = INVALID_INDEX; // geometry index in build operation
+
+ BLASGeomIndex() {}
+ BLASGeomIndex(Uint32 _IndexInDesc, Uint32 _ActualIndex) :
+ IndexInDesc{_IndexInDesc}, ActualIndex{_ActualIndex} {}
+};
+using BLASNameToIndex = std::unordered_map<HashMapStringKey, BLASGeomIndex, HashMapStringKey::Hasher>;
+
+/// Validates bottom-level AS description and throws and exception in case of an error.
+void ValidateBottomLevelASDesc(const BottomLevelASDesc& Desc) noexcept(false);
+
+/// Copies bottom-level AS geometry description using MemPool to allocate required dynamic space.
+void CopyBLASGeometryDesc(const BottomLevelASDesc& SrcDesc,
+ BottomLevelASDesc& DstDesc,
+ FixedLinearAllocator& MemPool,
+ const BLASNameToIndex* pSrcNameToIndex,
+ BLASNameToIndex& DstNameToIndex) noexcept(false);
+
+
+/// Template class implementing base functionality for a bottom-level acceleration structure object.
+
+/// \tparam BaseInterface - base interface that this class will inheret
+/// (Diligent::IBottomLevelASD3D12 or Diligent::IBottomLevelASVk).
+/// \tparam RenderDeviceImplType - type of the render device implementation
+/// (Diligent::RenderDeviceD3D12Impl or Diligent::RenderDeviceVkImpl)
+template <class BaseInterface, class RenderDeviceImplType>
+class BottomLevelASBase : public DeviceObjectBase<BaseInterface, RenderDeviceImplType, BottomLevelASDesc>
+{
+public:
+ using TDeviceObjectBase = DeviceObjectBase<BaseInterface, RenderDeviceImplType, BottomLevelASDesc>;
+
+ /// \param pRefCounters - reference counters object that controls the lifetime of this BLAS.
+ /// \param pDevice - pointer to the device.
+ /// \param Desc - BLAS description.
+ /// \param bIsDeviceInternal - flag indicating if the BLAS is an internal device object and
+ /// must not keep a strong reference to the device.
+ BottomLevelASBase(IReferenceCounters* pRefCounters,
+ RenderDeviceImplType* pDevice,
+ const BottomLevelASDesc& Desc,
+ bool bIsDeviceInternal = false) :
+ TDeviceObjectBase{pRefCounters, pDevice, Desc, bIsDeviceInternal}
+ {
+ ValidateBottomLevelASDesc(this->m_Desc);
+
+ if (Desc.CompactedSize > 0)
+ {
+ }
+ else
+ {
+ CopyGeometryDescriptionUnsafe(Desc, nullptr);
+ }
+ }
+
+ ~BottomLevelASBase()
+ {
+ ClearGeometry();
+ }
+
+ IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_BottomLevelAS, TDeviceObjectBase)
+
+ // Maps geometry that was used in build operation to geometry description.
+ // Returns the geometry index in geometry description.
+ Uint32 UpdateGeometryIndex(const char* Name, Uint32& ActualIndex, bool OnUpdate)
+ {
+ VERIFY_EXPR(Name != nullptr && Name[0] != '\0');
+
+ auto iter = m_NameToIndex.find(Name);
+ if (iter != m_NameToIndex.end())
+ {
+ if (OnUpdate)
+ ActualIndex = iter->second.ActualIndex;
+ else
+ iter->second.ActualIndex = ActualIndex;
+ return iter->second.IndexInDesc;
+ }
+ LOG_ERROR_MESSAGE("Can't find geometry with name '", Name, '\'');
+ return INVALID_INDEX;
+ }
+
+ virtual Uint32 DILIGENT_CALL_TYPE GetGeometryDescIndex(const char* Name) const override final
+ {
+ VERIFY_EXPR(Name != nullptr && Name[0] != '\0');
+
+ auto iter = m_NameToIndex.find(Name);
+ if (iter != m_NameToIndex.end())
+ return iter->second.IndexInDesc;
+
+ LOG_ERROR_MESSAGE("Can't find geometry with name '", Name, '\'');
+ return INVALID_INDEX;
+ }
+
+ virtual Uint32 DILIGENT_CALL_TYPE GetGeometryIndex(const char* Name) const override final
+ {
+ VERIFY_EXPR(Name != nullptr && Name[0] != '\0');
+
+ auto iter = m_NameToIndex.find(Name);
+ if (iter != m_NameToIndex.end())
+ {
+ VERIFY(iter->second.ActualIndex != INVALID_INDEX, "Geometry with name '", Name, "', exists but was not enabled during last build");
+ return iter->second.ActualIndex;
+ }
+ LOG_ERROR_MESSAGE("Can't find geometry with name '", Name, '\'');
+ return INVALID_INDEX;
+ }
+
+ virtual void DILIGENT_CALL_TYPE SetState(RESOURCE_STATE State) override final
+ {
+ VERIFY(State == RESOURCE_STATE_UNKNOWN || State == RESOURCE_STATE_BUILD_AS_READ || State == RESOURCE_STATE_BUILD_AS_WRITE,
+ "Unsupported state for a bottom-level acceleration structure");
+ this->m_State = State;
+ }
+
+ virtual RESOURCE_STATE DILIGENT_CALL_TYPE GetState() const override final
+ {
+ return this->m_State;
+ }
+
+ /// Implementation of IBottomLevelAS::GetScratchBufferSizes()
+ virtual ScratchBufferSizes DILIGENT_CALL_TYPE GetScratchBufferSizes() const override final
+ {
+ return this->m_ScratchSize;
+ }
+
+ bool IsInKnownState() const
+ {
+ return this->m_State != RESOURCE_STATE_UNKNOWN;
+ }
+
+ bool CheckState(RESOURCE_STATE State) const
+ {
+ VERIFY((State & (State - 1)) == 0, "Single state is expected");
+ VERIFY(IsInKnownState(), "BLAS state is unknown");
+ return (this->m_State & State) == State;
+ }
+
+#ifdef DILIGENT_DEVELOPMENT
+ void UpdateVersion()
+ {
+ this->m_DbgVersion.fetch_add(1);
+ }
+
+ Uint32 GetVersion() const
+ {
+ return this->m_DbgVersion.load();
+ }
+#endif // DILIGENT_DEVELOPMENT
+
+ void CopyGeometryDescription(const BottomLevelASBase& SrcBLAS) noexcept
+ {
+ ClearGeometry();
+
+ try
+ {
+ CopyGeometryDescriptionUnsafe(SrcBLAS.GetDesc(), &SrcBLAS.m_NameToIndex);
+ }
+ catch (...)
+ {
+ ClearGeometry();
+ }
+ }
+
+ void SetActualGeometryCount(Uint32 Count)
+ {
+ m_GeometryCount = Count;
+ }
+
+ virtual Uint32 DILIGENT_CALL_TYPE GetActualGeometryCount() const override final
+ {
+ return m_GeometryCount;
+ }
+
+private:
+ void CopyGeometryDescriptionUnsafe(const BottomLevelASDesc& SrcDesc, const BLASNameToIndex* pSrcNameToIndex) noexcept(false)
+ {
+ FixedLinearAllocator MemPool{GetRawAllocator()};
+ CopyBLASGeometryDesc(SrcDesc, this->m_Desc, MemPool, pSrcNameToIndex, this->m_NameToIndex);
+ this->m_pRawPtr = MemPool.Release();
+ }
+
+ void ClearGeometry() noexcept
+ {
+ if (this->m_pRawPtr != nullptr)
+ {
+ GetRawAllocator().Free(this->m_pRawPtr);
+ this->m_pRawPtr = nullptr;
+ }
+
+ // Keep Name, Flags, CompactedSize, CommandQueueMask
+ this->m_Desc.pTriangles = nullptr;
+ this->m_Desc.TriangleCount = 0;
+ this->m_Desc.pBoxes = nullptr;
+ this->m_Desc.BoxCount = 0;
+
+ m_NameToIndex.clear();
+ }
+
+protected:
+ RESOURCE_STATE m_State = RESOURCE_STATE_UNKNOWN;
+ BLASNameToIndex m_NameToIndex;
+ void* m_pRawPtr = nullptr;
+ Uint32 m_GeometryCount = 0;
+ ScratchBufferSizes m_ScratchSize;
+
+#ifdef DILIGENT_DEVELOPMENT
+ std::atomic<Uint32> m_DbgVersion{0};
+#endif
+};
+
+} // namespace Diligent
diff --git a/Graphics/GraphicsEngine/include/BufferBase.hpp b/Graphics/GraphicsEngine/include/BufferBase.hpp
index 605bc2ed..f09e8fc5 100644
--- a/Graphics/GraphicsEngine/include/BufferBase.hpp
+++ b/Graphics/GraphicsEngine/include/BufferBase.hpp
@@ -42,8 +42,15 @@
namespace Diligent
{
-void ValidateBufferInitData(const BufferDesc& Desc, const BufferData* pBuffData);
-void ValidateBufferDesc(const BufferDesc& Desc, const DeviceCaps& deviceCaps);
+/// Validates buffer description and throws an exception in case of an error.
+void ValidateBufferDesc(const BufferDesc& Desc, const DeviceCaps& deviceCaps) noexcept(false);
+
+/// Validates initial buffer data parameters and throws an exception in case of an error.
+void ValidateBufferInitData(const BufferDesc& Desc, const BufferData* pBuffData) noexcept(false);
+
+/// Validates and corrects buffer view description; throws an exception in case of an error.
+void ValidateAndCorrectBufferViewDesc(const BufferDesc& BuffDesc, BufferViewDesc& ViewDesc) noexcept(false);
+
/// Template class implementing base functionality for a buffer object
@@ -93,10 +100,31 @@ public:
/// Implementation of IBuffer::CreateView(); calls CreateViewInternal() virtual function
/// that creates buffer view for the specific engine implementation.
- virtual void DILIGENT_CALL_TYPE CreateView(const struct BufferViewDesc& ViewDesc, IBufferView** ppView) override;
+ virtual void DILIGENT_CALL_TYPE CreateView(const struct BufferViewDesc& ViewDesc, IBufferView** ppView) override
+ {
+ DEV_CHECK_ERR(ViewDesc.ViewType != BUFFER_VIEW_UNDEFINED, "Buffer view type is not specified");
+ if (ViewDesc.ViewType == BUFFER_VIEW_SHADER_RESOURCE)
+ DEV_CHECK_ERR(this->m_Desc.BindFlags & BIND_SHADER_RESOURCE, "Attempting to create SRV for buffer '", this->m_Desc.Name, "' that was not created with BIND_SHADER_RESOURCE flag");
+ else if (ViewDesc.ViewType == BUFFER_VIEW_UNORDERED_ACCESS)
+ DEV_CHECK_ERR(this->m_Desc.BindFlags & BIND_UNORDERED_ACCESS, "Attempting to create UAV for buffer '", this->m_Desc.Name, "' that was not created with BIND_UNORDERED_ACCESS flag");
+ else
+ UNEXPECTED("Unexpected buffer view type");
+
+ CreateViewInternal(ViewDesc, ppView, false);
+ }
+
/// Implementation of IBuffer::GetDefaultView().
- virtual IBufferView* DILIGENT_CALL_TYPE GetDefaultView(BUFFER_VIEW_TYPE ViewType) override;
+ virtual IBufferView* DILIGENT_CALL_TYPE GetDefaultView(BUFFER_VIEW_TYPE ViewType) override
+ {
+ switch (ViewType)
+ {
+ case BUFFER_VIEW_SHADER_RESOURCE: return m_pDefaultSRV.get();
+ case BUFFER_VIEW_UNORDERED_ACCESS: return m_pDefaultUAV.get();
+ default: UNEXPECTED("Unknown view type"); return nullptr;
+ }
+ }
+
/// Creates default buffer views.
@@ -105,7 +133,53 @@ public:
/// - Creates default unordered access view addressing the entire buffer if Diligent::BIND_UNORDERED_ACCESS flag is set
///
/// The function calls CreateViewInternal().
- void CreateDefaultViews();
+ void CreateDefaultViews()
+ {
+ // Create default views for structured and raw buffers. For formatted buffers we do not know the view format, so
+ // cannot create views.
+
+ auto CreateDefaultView = [&](BUFFER_VIEW_TYPE ViewType) //
+ {
+ BufferViewDesc ViewDesc;
+ ViewDesc.ViewType = ViewType;
+
+ std::string ViewName;
+ switch (ViewType)
+ {
+ case BUFFER_VIEW_UNORDERED_ACCESS:
+ ViewName = "Default UAV of buffer '";
+ break;
+
+ case BUFFER_VIEW_SHADER_RESOURCE:
+ ViewName = "Default SRV of buffer '";
+ break;
+
+ default:
+ UNEXPECTED("Unexpected buffer view type");
+ }
+
+ ViewName += this->m_Desc.Name;
+ ViewName += '\'';
+ ViewDesc.Name = ViewName.c_str();
+
+ IBufferView* pView = nullptr;
+ CreateViewInternal(ViewDesc, &pView, true);
+ VERIFY(pView != nullptr, "Failed to create default view for buffer '", this->m_Desc.Name, "'");
+ VERIFY(pView->GetDesc().ViewType == ViewType, "Unexpected view type");
+
+ return static_cast<BufferViewImplType*>(pView);
+ };
+
+ if (this->m_Desc.BindFlags & BIND_UNORDERED_ACCESS && (this->m_Desc.Mode == BUFFER_MODE_STRUCTURED || this->m_Desc.Mode == BUFFER_MODE_RAW))
+ {
+ m_pDefaultUAV.reset(CreateDefaultView(BUFFER_VIEW_UNORDERED_ACCESS));
+ }
+
+ if (this->m_Desc.BindFlags & BIND_SHADER_RESOURCE && (this->m_Desc.Mode == BUFFER_MODE_STRUCTURED || this->m_Desc.Mode == BUFFER_MODE_RAW))
+ {
+ m_pDefaultSRV.reset(CreateDefaultView(BUFFER_VIEW_SHADER_RESOURCE));
+ }
+ }
virtual void DILIGENT_CALL_TYPE SetState(RESOURCE_STATE State) override final
{
@@ -133,9 +207,6 @@ protected:
/// Pure virtual function that creates buffer view for the specific engine implementation.
virtual void CreateViewInternal(const struct BufferViewDesc& ViewDesc, IBufferView** ppView, bool bIsDefaultView) = 0;
- /// Corrects buffer view description and validates view parameters.
- void CorrectBufferViewDesc(struct BufferViewDesc& ViewDesc);
-
#ifdef DILIGENT_DEBUG
TBuffViewObjAllocator& m_dbgBuffViewAllocator;
#endif
@@ -149,112 +220,4 @@ protected:
std::unique_ptr<BufferViewImplType, STDDeleter<BufferViewImplType, TBuffViewObjAllocator>> m_pDefaultSRV;
};
-
-
-
-template <class BaseInterface, class RenderDeviceImplType, class BufferViewImplType, class TBuffViewObjAllocator>
-void BufferBase<BaseInterface, RenderDeviceImplType, BufferViewImplType, TBuffViewObjAllocator>::CreateView(const struct BufferViewDesc& ViewDesc, IBufferView** ppView)
-{
- DEV_CHECK_ERR(ViewDesc.ViewType != BUFFER_VIEW_UNDEFINED, "Buffer view type is not specified");
- if (ViewDesc.ViewType == BUFFER_VIEW_SHADER_RESOURCE)
- DEV_CHECK_ERR(this->m_Desc.BindFlags & BIND_SHADER_RESOURCE, "Attempting to create SRV for buffer '", this->m_Desc.Name, "' that was not created with BIND_SHADER_RESOURCE flag");
- else if (ViewDesc.ViewType == BUFFER_VIEW_UNORDERED_ACCESS)
- DEV_CHECK_ERR(this->m_Desc.BindFlags & BIND_UNORDERED_ACCESS, "Attempting to create UAV for buffer '", this->m_Desc.Name, "' that was not created with BIND_UNORDERED_ACCESS flag");
- else
- UNEXPECTED("Unexpected buffer view type");
-
- CreateViewInternal(ViewDesc, ppView, false);
-}
-
-
-template <class BaseInterface, class RenderDeviceImplType, class BufferViewImplType, class TBuffViewObjAllocator>
-void BufferBase<BaseInterface, RenderDeviceImplType, BufferViewImplType, TBuffViewObjAllocator>::CorrectBufferViewDesc(struct BufferViewDesc& ViewDesc)
-{
- if (ViewDesc.ByteWidth == 0)
- {
- DEV_CHECK_ERR(this->m_Desc.uiSizeInBytes > ViewDesc.ByteOffset, "Byte offset (", ViewDesc.ByteOffset, ") exceeds buffer size (", this->m_Desc.uiSizeInBytes, ")");
- ViewDesc.ByteWidth = this->m_Desc.uiSizeInBytes - ViewDesc.ByteOffset;
- }
- if (ViewDesc.ByteOffset + ViewDesc.ByteWidth > this->m_Desc.uiSizeInBytes)
- LOG_ERROR_AND_THROW("Buffer view range [", ViewDesc.ByteOffset, ", ", ViewDesc.ByteOffset + ViewDesc.ByteWidth, ") is out of the buffer boundaries [0, ", this->m_Desc.uiSizeInBytes, ").");
- if ((this->m_Desc.BindFlags & BIND_UNORDERED_ACCESS) ||
- (this->m_Desc.BindFlags & BIND_SHADER_RESOURCE))
- {
- if (this->m_Desc.Mode == BUFFER_MODE_STRUCTURED || this->m_Desc.Mode == BUFFER_MODE_FORMATTED)
- {
- VERIFY(this->m_Desc.ElementByteStride != 0, "Element byte stride is zero");
- if ((ViewDesc.ByteOffset % this->m_Desc.ElementByteStride) != 0)
- LOG_ERROR_AND_THROW("Buffer view byte offset (", ViewDesc.ByteOffset, ") is not multiple of element byte stride (", this->m_Desc.ElementByteStride, ").");
- if ((ViewDesc.ByteWidth % this->m_Desc.ElementByteStride) != 0)
- LOG_ERROR_AND_THROW("Buffer view byte width (", ViewDesc.ByteWidth, ") is not multiple of element byte stride (", this->m_Desc.ElementByteStride, ").");
- }
-
- if (this->m_Desc.Mode == BUFFER_MODE_FORMATTED && ViewDesc.Format.ValueType == VT_UNDEFINED)
- LOG_ERROR_AND_THROW("Format must be specified when creating a view of a formatted buffer");
-
- if (this->m_Desc.Mode == BUFFER_MODE_FORMATTED || (this->m_Desc.Mode == BUFFER_MODE_RAW && ViewDesc.Format.ValueType != VT_UNDEFINED))
- {
- if (ViewDesc.Format.NumComponents <= 0 || ViewDesc.Format.NumComponents > 4)
- LOG_ERROR_AND_THROW("Incorrect number of components (", Uint32{ViewDesc.Format.NumComponents}, "). 1, 2, 3, or 4 are allowed values");
- if (ViewDesc.Format.ValueType == VT_FLOAT32 || ViewDesc.Format.ValueType == VT_FLOAT16)
- ViewDesc.Format.IsNormalized = false;
- auto ViewElementStride = GetValueSize(ViewDesc.Format.ValueType) * Uint32{ViewDesc.Format.NumComponents};
- if (this->m_Desc.Mode == BUFFER_MODE_RAW && this->m_Desc.ElementByteStride == 0)
- LOG_ERROR_AND_THROW("To enable formatted views of a raw buffer, element byte must be specified during buffer initialization");
- if (ViewElementStride != this->m_Desc.ElementByteStride)
- LOG_ERROR_AND_THROW("Buffer element byte stride (", this->m_Desc.ElementByteStride, ") is not consistent with the size (", ViewElementStride, ") defined by the format of the view (", GetBufferFormatString(ViewDesc.Format), ')');
- }
-
- if (this->m_Desc.Mode == BUFFER_MODE_RAW && ViewDesc.Format.ValueType == VT_UNDEFINED)
- {
- if ((ViewDesc.ByteOffset % 16) != 0)
- LOG_ERROR_AND_THROW("When creating a RAW view, the offset of the first element from the start of the buffer (", ViewDesc.ByteOffset, ") must be a multiple of 16 bytes");
- }
- }
-}
-
-template <class BaseInterface, class RenderDeviceImplType, class BufferViewImplType, class TBuffViewObjAllocator>
-IBufferView* BufferBase<BaseInterface, RenderDeviceImplType, BufferViewImplType, TBuffViewObjAllocator>::GetDefaultView(BUFFER_VIEW_TYPE ViewType)
-{
- switch (ViewType)
- {
- case BUFFER_VIEW_SHADER_RESOURCE: return m_pDefaultSRV.get();
- case BUFFER_VIEW_UNORDERED_ACCESS: return m_pDefaultUAV.get();
- default: UNEXPECTED("Unknown view type"); return nullptr;
- }
-}
-
-template <class BaseInterface, class RenderDeviceImplType, class BufferViewImplType, class TBuffViewObjAllocator>
-void BufferBase<BaseInterface, RenderDeviceImplType, BufferViewImplType, TBuffViewObjAllocator>::CreateDefaultViews()
-{
- // Create default views for structured and raw buffers. For formatted buffers we do not know the view format, so
- // cannot create views.
-
- if (this->m_Desc.BindFlags & BIND_UNORDERED_ACCESS && (this->m_Desc.Mode == BUFFER_MODE_STRUCTURED || this->m_Desc.Mode == BUFFER_MODE_RAW))
- {
- BufferViewDesc ViewDesc;
- ViewDesc.ViewType = BUFFER_VIEW_UNORDERED_ACCESS;
- auto UAVName = FormatString("Default UAV of buffer '", this->m_Desc.Name, '\'');
- ViewDesc.Name = UAVName.c_str();
-
- IBufferView* pUAV = nullptr;
- CreateViewInternal(ViewDesc, &pUAV, true);
- m_pDefaultUAV.reset(static_cast<BufferViewImplType*>(pUAV));
- VERIFY(m_pDefaultUAV->GetDesc().ViewType == BUFFER_VIEW_UNORDERED_ACCESS, "Unexpected view type");
- }
-
- if (this->m_Desc.BindFlags & BIND_SHADER_RESOURCE && (this->m_Desc.Mode == BUFFER_MODE_STRUCTURED || this->m_Desc.Mode == BUFFER_MODE_RAW))
- {
- BufferViewDesc ViewDesc;
- ViewDesc.ViewType = BUFFER_VIEW_SHADER_RESOURCE;
- auto SRVName = FormatString("Default SRV of buffer '", this->m_Desc.Name, '\'');
- ViewDesc.Name = SRVName.c_str();
-
- IBufferView* pSRV = nullptr;
- CreateViewInternal(ViewDesc, &pSRV, true);
- m_pDefaultSRV.reset(static_cast<BufferViewImplType*>(pSRV));
- VERIFY(m_pDefaultSRV->GetDesc().ViewType == BUFFER_VIEW_SHADER_RESOURCE, "Unexpected view type");
- }
-}
-
} // namespace Diligent
diff --git a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp
index dcc186b5..e57b8c8c 100644
--- a/Graphics/GraphicsEngine/include/DeviceContextBase.hpp
+++ b/Graphics/GraphicsEngine/include/DeviceContextBase.hpp
@@ -45,6 +45,36 @@
namespace Diligent
{
+// clang-format off
+bool VerifyDrawAttribs (const DrawAttribs& Attribs);
+bool VerifyDrawIndexedAttribs (const DrawIndexedAttribs& Attribs);
+bool VerifyDrawIndirectAttribs (const DrawIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer);
+bool VerifyDrawIndexedIndirectAttribs(const DrawIndexedIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer);
+
+bool VerifyDispatchComputeAttribs (const DispatchComputeAttribs& Attribs);
+bool VerifyDispatchComputeIndirectAttribs(const DispatchComputeIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer);
+// clang-format on
+
+bool VerifyDrawMeshAttribs(Uint32 MaxDrawMeshTasksCount, const DrawMeshAttribs& Attribs);
+bool VerifyDrawMeshIndirectAttribs(const DrawMeshIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer);
+
+bool VerifyResolveTextureSubresourceAttribs(const ResolveTextureSubresourceAttribs& ResolveAttribs,
+ const TextureDesc& SrcTexDesc,
+ const TextureDesc& DstTexDesc);
+
+bool VerifyBeginRenderPassAttribs(const BeginRenderPassAttribs& Attribs);
+bool VerifyStateTransitionDesc(const IRenderDevice* pDevice, const StateTransitionDesc& Barrier);
+
+bool VerifyBuildBLASAttribs(const BuildBLASAttribs& Attribs);
+bool VerifyBuildTLASAttribs(const BuildTLASAttribs& Attribs);
+bool VerifyCopyBLASAttribs(const IRenderDevice* pDevice, const CopyBLASAttribs& Attribs);
+bool VerifyCopyTLASAttribs(const CopyTLASAttribs& Attribs);
+bool VerifyWriteBLASCompactedSizeAttribs(const IRenderDevice* pDevice, const WriteBLASCompactedSizeAttribs& Attribs);
+bool VerifyWriteTLASCompactedSizeAttribs(const IRenderDevice* pDevice, const WriteTLASCompactedSizeAttribs& Attribs);
+bool VerifyTraceRaysAttribs(const TraceRaysAttribs& Attribs);
+
+
+
/// Describes input vertex stream
template <typename BufferImplType>
struct VertexStreamInfo
@@ -53,7 +83,9 @@ struct VertexStreamInfo
/// Strong reference to the buffer object
RefCntAutoPtr<BufferImplType> pBuffer;
- Uint32 Offset = 0; ///< Offset in bytes
+
+ /// Offset in bytes
+ Uint32 Offset = 0;
};
/// Base implementation of the device context.
@@ -62,7 +94,7 @@ struct VertexStreamInfo
/// \tparam ImplementationTraits - implementation traits that define specific implementation details
/// (texture implemenation type, buffer implementation type, etc.)
/// \remarks Device context keeps strong references to all objects currently bound to
-/// the pipeline: buffers, states, samplers, shaders, etc.
+/// the pipeline: buffers, tetxures, states, SRBs, etc.
/// The context also keeps strong references to the device and
/// the swap chain.
template <typename BaseInterface, typename ImplementationTraits>
@@ -78,10 +110,12 @@ public:
using QueryImplType = typename ImplementationTraits::QueryType;
using FramebufferImplType = typename ImplementationTraits::FramebufferType;
using RenderPassImplType = typename ImplementationTraits::RenderPassType;
+ using BottomLevelASType = typename ImplementationTraits::BottomLevelASType;
+ using TopLevelASType = typename ImplementationTraits::TopLevelASType;
- /// \param pRefCounters - reference counters object that controls the lifetime of this device context.
+ /// \param pRefCounters - reference counters object that controls the lifetime of this device context.
/// \param pRenderDevice - render device.
- /// \param bIsDeferred - flag indicating if this instance is a deferred context
+ /// \param bIsDeferred - flag indicating if this instance is a deferred context
DeviceContextBase(IReferenceCounters* pRefCounters, DeviceImplType* pRenderDevice, bool bIsDeferred) :
// clang-format off
TObjectBase {pRefCounters },
@@ -114,7 +148,9 @@ public:
int);
/// Base implementation of IDeviceContext::SetIndexBuffer(); caches the strong reference to the index buffer
- inline virtual void DILIGENT_CALL_TYPE SetIndexBuffer(IBuffer* pIndexBuffer, Uint32 ByteOffset, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) override = 0;
+ inline virtual void DILIGENT_CALL_TYPE SetIndexBuffer(IBuffer* pIndexBuffer,
+ Uint32 ByteOffset,
+ RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) override = 0;
/// Caches the viewports
inline void SetViewports(Uint32 NumViewports, const Viewport* pViewports, Uint32& RTWidth, Uint32& RTHeight);
@@ -251,20 +287,22 @@ protected:
#ifdef DILIGENT_DEVELOPMENT
// clang-format off
- bool DvpVerifyDrawArguments (const DrawAttribs& Attribs)const;
- bool DvpVerifyDrawIndexedArguments (const DrawIndexedAttribs& Attribs)const;
- bool DvpVerifyDrawMeshArguments (const DrawMeshAttribs& Attribs)const;
- bool DvpVerifyDrawIndirectArguments (const DrawIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)const;
- bool DvpVerifyDrawIndexedIndirectArguments(const DrawIndexedIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)const;
- bool DvpVerifyDrawMeshIndirectArguments (const DrawMeshIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)const;
-
- bool DvpVerifyDispatchArguments (const DispatchComputeAttribs& Attribs)const;
- bool DvpVerifyDispatchIndirectArguments(const DispatchComputeIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)const;
-
- void DvpVerifyRenderTargets()const;
- void DvpVerifyStateTransitionDesc(const StateTransitionDesc& Barrier)const;
- bool DvpVerifyTextureState(const TextureImplType& Texture, RESOURCE_STATE RequiredState, const char* OperationName)const;
- bool DvpVerifyBufferState (const BufferImplType& Buffer, RESOURCE_STATE RequiredState, const char* OperationName)const;
+ bool DvpVerifyDrawArguments (const DrawAttribs& Attribs) const;
+ bool DvpVerifyDrawIndexedArguments (const DrawIndexedAttribs& Attribs) const;
+ bool DvpVerifyDrawMeshArguments (const DrawMeshAttribs& Attribs) const;
+ bool DvpVerifyDrawIndirectArguments (const DrawIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) const;
+ bool DvpVerifyDrawIndexedIndirectArguments(const DrawIndexedIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) const;
+ bool DvpVerifyDrawMeshIndirectArguments (const DrawMeshIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) const;
+
+ bool DvpVerifyDispatchArguments (const DispatchComputeAttribs& Attribs) const;
+ bool DvpVerifyDispatchIndirectArguments(const DispatchComputeIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) const;
+
+ bool DvpVerifyRenderTargets() const;
+ bool DvpVerifyStateTransitionDesc(const StateTransitionDesc& Barrier) const;
+ bool DvpVerifyTextureState(const TextureImplType& Texture, RESOURCE_STATE RequiredState, const char* OperationName) const;
+ bool DvpVerifyBufferState (const BufferImplType& Buffer, RESOURCE_STATE RequiredState, const char* OperationName) const;
+ bool DvpVerifyBLASState (const BottomLevelASType& BLAS, RESOURCE_STATE RequiredState, const char* OperationName) const;
+ bool DvpVerifyTLASState (const TopLevelASType& TLAS, RESOURCE_STATE RequiredState, const char* OperationName) const;
#else
bool DvpVerifyDrawArguments (const DrawAttribs& Attribs)const {return true;}
bool DvpVerifyDrawIndexedArguments (const DrawIndexedAttribs& Attribs)const {return true;}
@@ -276,13 +314,23 @@ protected:
bool DvpVerifyDispatchArguments (const DispatchComputeAttribs& Attribs)const {return true;}
bool DvpVerifyDispatchIndirectArguments(const DispatchComputeIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)const {return true;}
- void DvpVerifyRenderTargets()const {}
- void DvpVerifyStateTransitionDesc(const StateTransitionDesc& Barrier)const {}
- bool DvpVerifyTextureState(const TextureImplType& Texture, RESOURCE_STATE RequiredState, const char* OperationName)const {return true;}
- bool DvpVerifyBufferState (const BufferImplType& Buffer, RESOURCE_STATE RequiredState, const char* OperationName)const {return true;}
+ bool DvpVerifyRenderTargets()const {return true;}
+ bool DvpVerifyStateTransitionDesc(const StateTransitionDesc& Barrier)const {return true;}
+ bool DvpVerifyTextureState(const TextureImplType& Texture, RESOURCE_STATE RequiredState, const char* OperationName)const {return true;}
+ bool DvpVerifyBufferState (const BufferImplType& Buffer, RESOURCE_STATE RequiredState, const char* OperationName)const {return true;}
+ bool DvpVerifyBLASState (const BottomLevelASType& BLAS, RESOURCE_STATE RequiredState, const char* OperationName)const {return true;}
+ bool DvpVerifyTLASState (const TopLevelASType& TLAS, RESOURCE_STATE RequiredState, const char* OperationName)const {return true;}
// clang-format on
#endif
+ bool BuildBLAS(const BuildBLASAttribs& Attribs, int) const;
+ bool BuildTLAS(const BuildTLASAttribs& Attribs, int) const;
+ bool CopyBLAS(const CopyBLASAttribs& Attribs, int) const;
+ bool CopyTLAS(const CopyTLASAttribs& Attribs, int) const;
+ bool WriteBLASCompactedSize(const WriteBLASCompactedSizeAttribs& Attribs, int) const;
+ bool WriteTLASCompactedSize(const WriteTLASCompactedSizeAttribs& Attribs, int) const;
+ bool TraceRays(const TraceRaysAttribs& Attribs, int) const;
+
/// Strong reference to the device.
RefCntAutoPtr<DeviceImplType> m_pDevice;
@@ -368,13 +416,13 @@ protected:
template <typename BaseInterface, typename ImplementationTraits>
-inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
- SetVertexBuffers(Uint32 StartSlot,
- Uint32 NumBuffersSet,
- IBuffer** ppBuffers,
- Uint32* pOffsets,
- RESOURCE_STATE_TRANSITION_MODE StateTransitionMode,
- SET_VERTEX_BUFFERS_FLAGS Flags)
+inline void DeviceContextBase<BaseInterface, ImplementationTraits>::SetVertexBuffers(
+ Uint32 StartSlot,
+ Uint32 NumBuffersSet,
+ IBuffer** ppBuffers,
+ Uint32* pOffsets,
+ RESOURCE_STATE_TRANSITION_MODE StateTransitionMode,
+ SET_VERTEX_BUFFERS_FLAGS Flags)
{
#ifdef DILIGENT_DEVELOPMENT
if (StartSlot >= MAX_BUFFER_SLOTS)
@@ -429,15 +477,18 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
}
template <typename BaseInterface, typename ImplementationTraits>
-inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
- SetPipelineState(PipelineStateImplType* pPipelineState, int /*Dummy*/)
+inline void DeviceContextBase<BaseInterface, ImplementationTraits>::SetPipelineState(
+ PipelineStateImplType* pPipelineState,
+ int /*Dummy*/)
{
m_pPipelineState = pPipelineState;
}
template <typename BaseInterface, typename ImplementationTraits>
-inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::
- CommitShaderResources(IShaderResourceBinding* pShaderResourceBinding, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode, int)
+inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::CommitShaderResources(
+ IShaderResourceBinding* pShaderResourceBinding,
+ RESOURCE_STATE_TRANSITION_MODE StateTransitionMode,
+ int)
{
#ifdef DILIGENT_DEVELOPMENT
VERIFY(!(m_pActiveRenderPass != nullptr && StateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION),
@@ -459,6 +510,7 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::
}
}
#endif
+
return true;
}
@@ -472,8 +524,10 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::InvalidateSt
}
template <typename BaseInterface, typename ImplementationTraits>
-inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
- SetIndexBuffer(IBuffer* pIndexBuffer, Uint32 ByteOffset, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode)
+inline void DeviceContextBase<BaseInterface, ImplementationTraits>::SetIndexBuffer(
+ IBuffer* pIndexBuffer,
+ Uint32 ByteOffset,
+ RESOURCE_STATE_TRANSITION_MODE StateTransitionMode)
{
m_pIndexBuffer = ValidatedCast<BufferImplType>(pIndexBuffer);
m_IndexDataStartOffset = ByteOffset;
@@ -538,8 +592,11 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::SetStencilRe
}
template <typename BaseInterface, typename ImplementationTraits>
-inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
- SetViewports(Uint32 NumViewports, const Viewport* pViewports, Uint32& RTWidth, Uint32& RTHeight)
+inline void DeviceContextBase<BaseInterface, ImplementationTraits>::SetViewports(
+ Uint32 NumViewports,
+ const Viewport* pViewports,
+ Uint32& RTWidth,
+ Uint32& RTHeight)
{
if (RTWidth == 0 || RTHeight == 0)
{
@@ -578,8 +635,11 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::GetViewports
}
template <typename BaseInterface, typename ImplementationTraits>
-inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
- SetScissorRects(Uint32 NumRects, const Rect* pRects, Uint32& RTWidth, Uint32& RTHeight)
+inline void DeviceContextBase<BaseInterface, ImplementationTraits>::SetScissorRects(
+ Uint32 NumRects,
+ const Rect* pRects,
+ Uint32& RTWidth,
+ Uint32& RTHeight)
{
if (RTWidth == 0 || RTHeight == 0)
{
@@ -599,8 +659,10 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
}
template <typename BaseInterface, typename ImplementationTraits>
-inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::
- SetRenderTargets(Uint32 NumRenderTargets, ITextureView* ppRenderTargets[], ITextureView* pDepthStencil)
+inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::SetRenderTargets(
+ Uint32 NumRenderTargets,
+ ITextureView* ppRenderTargets[],
+ ITextureView* pDepthStencil)
{
if (NumRenderTargets == 0 && pDepthStencil == nullptr)
{
@@ -776,8 +838,10 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::SetSubpassRe
template <typename BaseInterface, typename ImplementationTraits>
-inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
- GetRenderTargets(Uint32& NumRenderTargets, ITextureView** ppRTVs, ITextureView** ppDSV)
+inline void DeviceContextBase<BaseInterface, ImplementationTraits>::GetRenderTargets(
+ Uint32& NumRenderTargets,
+ ITextureView** ppRTVs,
+ ITextureView** ppDSV)
{
NumRenderTargets = m_NumBoundRenderTargets;
@@ -956,33 +1020,8 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::BeginRenderP
{
VERIFY(m_pActiveRenderPass == nullptr, "Attempting to begin render pass while another render pass ('", m_pActiveRenderPass->GetDesc().Name, "') is active.");
VERIFY(m_pBoundFramebuffer == nullptr, "Attempting to begin render pass while another framebuffer ('", m_pBoundFramebuffer->GetDesc().Name, "') is bound.");
- VERIFY(Attribs.pRenderPass != nullptr, "Render pass must not be null");
- VERIFY(Attribs.pFramebuffer != nullptr, "Framebuffer must not be null");
-#ifdef DILIGENT_DEBUG
- {
- const auto& RPDesc = Attribs.pRenderPass->GetDesc();
- Uint32 NumRequiredClearValues = 0;
- for (Uint32 i = 0; i < RPDesc.AttachmentCount; ++i)
- {
- const auto& Attchmnt = RPDesc.pAttachments[i];
- if (Attchmnt.LoadOp == ATTACHMENT_LOAD_OP_CLEAR)
- NumRequiredClearValues = i + 1;
-
- const auto& FmtAttribs = GetTextureFormatAttribs(Attchmnt.Format);
- if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL)
- {
- if (Attchmnt.StencilLoadOp == ATTACHMENT_LOAD_OP_CLEAR)
- NumRequiredClearValues = i + 1;
- }
- }
- VERIFY(Attribs.ClearValueCount >= NumRequiredClearValues,
- "Begin render pass operation requiers at least ", NumRequiredClearValues,
- " clear values, but only ", Attribs.ClearValueCount, " are given.");
- VERIFY(Attribs.ClearValueCount == 0 || Attribs.pClearValues != nullptr,
- "pClearValues must not be null when ClearValueCount is not zero");
- }
-#endif
+ VerifyBeginRenderPassAttribs(Attribs);
// Reset current render targets (in Vulkan backend, this may end current render pass).
ResetRenderTargets();
@@ -1023,6 +1062,7 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::BeginRenderP
m_pBoundFramebuffer = pNewFramebuffer;
m_SubpassIndex = 0;
m_RenderPassAttachmentsTransitionMode = Attribs.StateTransitionMode;
+
UpdateAttachmentStates(m_SubpassIndex);
SetSubpassRenderTargets();
}
@@ -1197,6 +1237,7 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::BeginQuery(I
return false;
}
+#ifdef DILIGENT_DEVELOPMENT
if (m_bIsDeferred)
{
LOG_ERROR_MESSAGE("IDeviceContext::BeginQuery: Deferred contexts do not support queries");
@@ -1208,6 +1249,7 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::BeginQuery(I
LOG_ERROR_MESSAGE("BeginQuery() is disabled for timestamp queries. Call EndQuery() to set the timestamp.");
return false;
}
+#endif
if (!ValidatedCast<QueryImplType>(pQuery)->OnBeginQuery(this))
return false;
@@ -1224,11 +1266,13 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::EndQuery(IQu
return false;
}
+#ifdef DILIGENT_DEVELOPMENT
if (m_bIsDeferred)
{
LOG_ERROR_MESSAGE("IDeviceContext::EndQuery: Deferred contexts do not support queries");
return false;
}
+#endif
if (!ValidatedCast<QueryImplType>(pQuery)->OnEndQuery(this))
return false;
@@ -1237,8 +1281,12 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::EndQuery(IQu
}
template <typename BaseInterface, typename ImplementationTraits>
-inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
- UpdateBuffer(IBuffer* pBuffer, Uint32 Offset, Uint32 Size, const void* pData, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode)
+inline void DeviceContextBase<BaseInterface, ImplementationTraits>::UpdateBuffer(
+ IBuffer* pBuffer,
+ Uint32 Offset,
+ Uint32 Size,
+ const void* pData,
+ RESOURCE_STATE_TRANSITION_MODE StateTransitionMode)
{
VERIFY(pBuffer != nullptr, "Buffer must not be null");
VERIFY(m_pActiveRenderPass == nullptr, "UpdateBuffer command must be used outside of render pass.");
@@ -1253,14 +1301,14 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
}
template <typename BaseInterface, typename ImplementationTraits>
-inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
- CopyBuffer(IBuffer* pSrcBuffer,
- Uint32 SrcOffset,
- RESOURCE_STATE_TRANSITION_MODE SrcBufferTransitionMode,
- IBuffer* pDstBuffer,
- Uint32 DstOffset,
- Uint32 Size,
- RESOURCE_STATE_TRANSITION_MODE DstBufferTransitionMode)
+inline void DeviceContextBase<BaseInterface, ImplementationTraits>::CopyBuffer(
+ IBuffer* pSrcBuffer,
+ Uint32 SrcOffset,
+ RESOURCE_STATE_TRANSITION_MODE SrcBufferTransitionMode,
+ IBuffer* pDstBuffer,
+ Uint32 DstOffset,
+ Uint32 Size,
+ RESOURCE_STATE_TRANSITION_MODE DstBufferTransitionMode)
{
VERIFY(pSrcBuffer != nullptr, "Source buffer must not be null");
VERIFY(pDstBuffer != nullptr, "Destination buffer must not be null");
@@ -1276,8 +1324,11 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
}
template <typename BaseInterface, typename ImplementationTraits>
-inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
- MapBuffer(IBuffer* pBuffer, MAP_TYPE MapType, MAP_FLAGS MapFlags, PVoid& pMappedData)
+inline void DeviceContextBase<BaseInterface, ImplementationTraits>::MapBuffer(
+ IBuffer* pBuffer,
+ MAP_TYPE MapType,
+ MAP_FLAGS MapFlags,
+ PVoid& pMappedData)
{
VERIFY(pBuffer, "pBuffer must not be null");
@@ -1331,8 +1382,7 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
}
template <typename BaseInterface, typename ImplementationTraits>
-inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
- UnmapBuffer(IBuffer* pBuffer, MAP_TYPE MapType)
+inline void DeviceContextBase<BaseInterface, ImplementationTraits>::UnmapBuffer(IBuffer* pBuffer, MAP_TYPE MapType)
{
VERIFY(pBuffer, "pBuffer must not be null");
#ifdef DILIGENT_DEBUG
@@ -1347,41 +1397,50 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
template <typename BaseInterface, typename ImplementationTraits>
-inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
- UpdateTexture(ITexture* pTexture, Uint32 MipLevel, Uint32 Slice, const Box& DstBox, const TextureSubResData& SubresData, RESOURCE_STATE_TRANSITION_MODE SrcBufferTransitionMode, RESOURCE_STATE_TRANSITION_MODE TextureTransitionMode)
+inline void DeviceContextBase<BaseInterface, ImplementationTraits>::UpdateTexture(
+ ITexture* pTexture,
+ Uint32 MipLevel,
+ Uint32 Slice,
+ const Box& DstBox,
+ const TextureSubResData& SubresData,
+ RESOURCE_STATE_TRANSITION_MODE SrcBufferTransitionMode,
+ RESOURCE_STATE_TRANSITION_MODE TextureTransitionMode)
{
VERIFY(pTexture != nullptr, "pTexture must not be null");
VERIFY(m_pActiveRenderPass == nullptr, "UpdateTexture command must be used outside of render pass.");
+
ValidateUpdateTextureParams(pTexture->GetDesc(), MipLevel, Slice, DstBox, SubresData);
}
template <typename BaseInterface, typename ImplementationTraits>
-inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
- CopyTexture(const CopyTextureAttribs& CopyAttribs)
+inline void DeviceContextBase<BaseInterface, ImplementationTraits>::CopyTexture(const CopyTextureAttribs& CopyAttribs)
{
VERIFY(CopyAttribs.pSrcTexture, "Src texture must not be null");
VERIFY(CopyAttribs.pDstTexture, "Dst texture must not be null");
VERIFY(m_pActiveRenderPass == nullptr, "CopyTexture command must be used outside of render pass.");
+
ValidateCopyTextureParams(CopyAttribs);
}
template <typename BaseInterface, typename ImplementationTraits>
-inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
- MapTextureSubresource(ITexture* pTexture,
- Uint32 MipLevel,
- Uint32 ArraySlice,
- MAP_TYPE MapType,
- MAP_FLAGS MapFlags,
- const Box* pMapRegion,
- MappedTextureSubresource& MappedData)
+inline void DeviceContextBase<BaseInterface, ImplementationTraits>::MapTextureSubresource(
+ ITexture* pTexture,
+ Uint32 MipLevel,
+ Uint32 ArraySlice,
+ MAP_TYPE MapType,
+ MAP_FLAGS MapFlags,
+ const Box* pMapRegion,
+ MappedTextureSubresource& MappedData)
{
VERIFY(pTexture, "pTexture must not be null");
ValidateMapTextureParams(pTexture->GetDesc(), MipLevel, ArraySlice, MapType, MapFlags, pMapRegion);
}
template <typename BaseInterface, typename ImplementationTraits>
-inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
- UnmapTextureSubresource(ITexture* pTexture, Uint32 MipLevel, Uint32 ArraySlice)
+inline void DeviceContextBase<BaseInterface, ImplementationTraits>::UnmapTextureSubresource(
+ ITexture* pTexture,
+ Uint32 MipLevel,
+ Uint32 ArraySlice)
{
VERIFY(pTexture, "pTexture must not be null");
DEV_CHECK_ERR(MipLevel < pTexture->GetDesc().MipLevels, "Mip level is out of range");
@@ -1389,8 +1448,7 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
}
template <typename BaseInterface, typename ImplementationTraits>
-inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
- GenerateMips(ITextureView* pTexView)
+inline void DeviceContextBase<BaseInterface, ImplementationTraits>::GenerateMips(ITextureView* pTexView)
{
VERIFY(pTexView != nullptr, "pTexView must not be null");
VERIFY(m_pActiveRenderPass == nullptr, "GenerateMips command must be used outside of render pass.");
@@ -1407,241 +1465,353 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
template <typename BaseInterface, typename ImplementationTraits>
-void DeviceContextBase<BaseInterface, ImplementationTraits>::
- ResolveTextureSubresource(ITexture* pSrcTexture,
- ITexture* pDstTexture,
- const ResolveTextureSubresourceAttribs& ResolveAttribs)
+void DeviceContextBase<BaseInterface, ImplementationTraits>::ResolveTextureSubresource(
+ ITexture* pSrcTexture,
+ ITexture* pDstTexture,
+ const ResolveTextureSubresourceAttribs& ResolveAttribs)
{
#ifdef DILIGENT_DEVELOPMENT
+ VERIFY(m_pActiveRenderPass == nullptr, "ResolveTextureSubresource command must be used outside of render pass.");
+
VERIFY_EXPR(pSrcTexture != nullptr && pDstTexture != nullptr);
const auto& SrcTexDesc = pSrcTexture->GetDesc();
const auto& DstTexDesc = pDstTexture->GetDesc();
- DEV_CHECK_ERR(SrcTexDesc.SampleCount > 1,
- "Source texture '", SrcTexDesc.Name, "' of a resolve operation is not multi-sampled");
- DEV_CHECK_ERR(DstTexDesc.SampleCount == 1,
- "Destination texture '", DstTexDesc.Name, "' of a resolve operation is multi-sampled");
- auto SrcMipLevelProps = GetMipLevelProperties(SrcTexDesc, ResolveAttribs.SrcMipLevel);
- auto DstMipLevelProps = GetMipLevelProperties(DstTexDesc, ResolveAttribs.DstMipLevel);
- DEV_CHECK_ERR(SrcMipLevelProps.LogicalWidth == DstMipLevelProps.LogicalWidth && SrcMipLevelProps.LogicalHeight == DstMipLevelProps.LogicalHeight,
- "The size (", SrcMipLevelProps.LogicalWidth, "x", SrcMipLevelProps.LogicalHeight,
- ") of the source subresource of a resolve operation (texture '",
- SrcTexDesc.Name, "', mip ", ResolveAttribs.SrcMipLevel, ", slice ", ResolveAttribs.SrcSlice,
- ") does not match the size (", DstMipLevelProps.LogicalWidth, "x", DstMipLevelProps.LogicalHeight,
- ") of the destination subresource (texture '", DstTexDesc.Name, "', mip ", ResolveAttribs.DstMipLevel, ", slice ",
- ResolveAttribs.DstSlice, ")");
-
- const auto& SrcFmtAttribs = GetTextureFormatAttribs(SrcTexDesc.Format);
- const auto& DstFmtAttribs = GetTextureFormatAttribs(DstTexDesc.Format);
- const auto& ResolveFmtAttribs = GetTextureFormatAttribs(ResolveAttribs.Format);
- if (!SrcFmtAttribs.IsTypeless && !DstFmtAttribs.IsTypeless)
- {
- DEV_CHECK_ERR(SrcTexDesc.Format == DstTexDesc.Format,
- "Source (", SrcFmtAttribs.Name, ") and destination (", DstFmtAttribs.Name,
- ") texture formats of a resolve operation must match exaclty or be compatible typeless formats");
- DEV_CHECK_ERR(ResolveAttribs.Format == TEX_FORMAT_UNKNOWN || SrcTexDesc.Format == ResolveAttribs.Format, "Invalid format of a resolve operation");
- }
- if (SrcFmtAttribs.IsTypeless && DstFmtAttribs.IsTypeless)
- {
- DEV_CHECK_ERR(ResolveAttribs.Format != TEX_FORMAT_UNKNOWN,
- "Format of a resolve operation must not be unknown when both src and dst texture formats are typeless");
- }
- if (SrcFmtAttribs.IsTypeless || DstFmtAttribs.IsTypeless)
- {
- DEV_CHECK_ERR(!ResolveFmtAttribs.IsTypeless,
- "Format of a resolve operation must not be typeless when one of the texture formats is typeless");
- }
- VERIFY(m_pActiveRenderPass == nullptr, "ResolveTextureSubresource command must be used outside of render pass.");
+
+ VerifyResolveTextureSubresourceAttribs(ResolveAttribs, SrcTexDesc, DstTexDesc);
#endif
}
+
+template <typename BaseInterface, typename ImplementationTraits>
+bool DeviceContextBase<BaseInterface, ImplementationTraits>::BuildBLAS(const BuildBLASAttribs& Attribs, int) const
+{
#ifdef DILIGENT_DEVELOPMENT
+ if (m_pDevice->GetDeviceCaps().Features.RayTracing != DEVICE_FEATURE_STATE_ENABLED)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS: ray tracing is not supported by this device");
+ return false;
+ }
+
+ if (m_pActiveRenderPass != nullptr)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildBLAS command must be performed outside of render pass");
+ return false;
+ }
+
+ if (!VerifyBuildBLASAttribs(Attribs))
+ return false;
+#endif
+
+ return true;
+}
+
template <typename BaseInterface, typename ImplementationTraits>
-inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::
- DvpVerifyDrawArguments(const DrawAttribs& Attribs) const
+bool DeviceContextBase<BaseInterface, ImplementationTraits>::BuildTLAS(const BuildTLASAttribs& Attribs, int) const
{
- if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0)
- return true;
+#ifdef DILIGENT_DEVELOPMENT
+ if (m_pDevice->GetDeviceCaps().Features.RayTracing != DEVICE_FEATURE_STATE_ENABLED)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS: ray tracing is not supported by this device");
+ return false;
+ }
- if (!m_pPipelineState)
+ if (m_pActiveRenderPass != nullptr)
{
- LOG_ERROR_MESSAGE("Draw command arguments are invalid: no pipeline state is bound.");
+ LOG_ERROR_MESSAGE("IDeviceContext::BuildTLAS command must be performed outside of render pass");
return false;
}
- if (m_pPipelineState->GetDesc().PipelineType != PIPELINE_TYPE_GRAPHICS)
+ if (!VerifyBuildTLASAttribs(Attribs))
+ return false;
+#endif
+
+ return true;
+}
+
+template <typename BaseInterface, typename ImplementationTraits>
+bool DeviceContextBase<BaseInterface, ImplementationTraits>::CopyBLAS(const CopyBLASAttribs& Attribs, int) const
+{
+#ifdef DILIGENT_DEVELOPMENT
+ if (m_pDevice->GetDeviceCaps().Features.RayTracing != DEVICE_FEATURE_STATE_ENABLED)
{
- LOG_ERROR_MESSAGE("Draw command arguments are invalid: pipeline state '", m_pPipelineState->GetDesc().Name, "' is not a graphics pipeline.");
+ LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: ray tracing is not supported by this device");
return false;
}
- if (Attribs.NumVertices == 0)
+ if (m_pActiveRenderPass != nullptr)
{
- LOG_WARNING_MESSAGE("Draw command arguments are invalid: number of vertices to draw is zero.");
+ LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS command must be performed outside of render pass");
+ return false;
}
+ if (!VerifyCopyBLASAttribs(m_pDevice, Attribs))
+ return false;
+#endif
+
return true;
}
template <typename BaseInterface, typename ImplementationTraits>
-inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::
- DvpVerifyDrawIndexedArguments(const DrawIndexedAttribs& Attribs) const
+bool DeviceContextBase<BaseInterface, ImplementationTraits>::CopyTLAS(const CopyTLASAttribs& Attribs, int) const
{
- if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0)
- return true;
+#ifdef DILIGENT_DEVELOPMENT
+ if (m_pDevice->GetDeviceCaps().Features.RayTracing != DEVICE_FEATURE_STATE_ENABLED)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS: ray tracing is not supported by this device");
+ return false;
+ }
- if (!m_pPipelineState)
+ if (m_pActiveRenderPass != nullptr)
{
- LOG_ERROR_MESSAGE("DrawIndexed command arguments are invalid: no pipeline state is bound.");
+ LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS command must be performed outside of render pass");
return false;
}
- if (m_pPipelineState->GetDesc().PipelineType != PIPELINE_TYPE_GRAPHICS)
+ if (!VerifyCopyTLASAttribs(Attribs))
+ return false;
+
+ if (!ValidatedCast<TopLevelASType>(Attribs.pSrc)->ValidateContent())
{
- LOG_ERROR_MESSAGE("DrawIndexed command arguments are invalid: pipeline state '",
- m_pPipelineState->GetDesc().Name, "' is not a graphics pipeline.");
+ LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS: pSrc acceleration structure is not valid");
return false;
}
+#endif
- if (Attribs.IndexType != VT_UINT16 && Attribs.IndexType != VT_UINT32)
+ return true;
+}
+
+template <typename BaseInterface, typename ImplementationTraits>
+bool DeviceContextBase<BaseInterface, ImplementationTraits>::WriteBLASCompactedSize(const WriteBLASCompactedSizeAttribs& Attribs, int) const
+{
+#ifdef DILIGENT_DEVELOPMENT
+ if (m_pDevice->GetDeviceCaps().Features.RayTracing != DEVICE_FEATURE_STATE_ENABLED)
{
- LOG_ERROR_MESSAGE("DrawIndexed command arguments are invalid: IndexType (",
- GetValueTypeString(Attribs.IndexType), ") must be VT_UINT16 or VT_UINT32.");
+ LOG_ERROR_MESSAGE("IDeviceContext::WriteBLASCompactedSize: ray tracing is not supported by this device");
return false;
}
- if (!m_pIndexBuffer)
+ if (m_pActiveRenderPass != nullptr)
{
- LOG_ERROR_MESSAGE("DrawIndexed command arguments are invalid: no index buffer is bound.");
+ LOG_ERROR_MESSAGE("IDeviceContext::WriteBLASCompactedSize: command must be performed outside of render pass");
return false;
}
- if (Attribs.NumIndices == 0)
+ if (!VerifyWriteBLASCompactedSizeAttribs(m_pDevice, Attribs))
+ return false;
+#endif
+
+ return true;
+}
+
+template <typename BaseInterface, typename ImplementationTraits>
+bool DeviceContextBase<BaseInterface, ImplementationTraits>::WriteTLASCompactedSize(const WriteTLASCompactedSizeAttribs& Attribs, int) const
+{
+#ifdef DILIGENT_DEVELOPMENT
+ if (m_pDevice->GetDeviceCaps().Features.RayTracing != DEVICE_FEATURE_STATE_ENABLED)
{
- LOG_WARNING_MESSAGE("DrawIndexed command arguments are invalid: number of indices to draw is zero.");
+ LOG_ERROR_MESSAGE("IDeviceContext::WriteTLASCompactedSize: ray tracing is not supported by this device");
+ return false;
}
+ if (m_pActiveRenderPass != nullptr)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::WriteTLASCompactedSize: command must be performed outside of render pass");
+ return false;
+ }
+
+ if (!VerifyWriteTLASCompactedSizeAttribs(m_pDevice, Attribs))
+ return false;
+#endif
+
return true;
}
template <typename BaseInterface, typename ImplementationTraits>
-inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::
- DvpVerifyDrawMeshArguments(const DrawMeshAttribs& Attribs) const
+bool DeviceContextBase<BaseInterface, ImplementationTraits>::TraceRays(const TraceRaysAttribs& Attribs, int) const
{
- if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0)
- return true;
+#ifdef DILIGENT_DEVELOPMENT
+ if (m_pDevice->GetDeviceCaps().Features.RayTracing != DEVICE_FEATURE_STATE_ENABLED)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::TraceRays: ray tracing is not supported by this device");
+ return false;
+ }
if (!m_pPipelineState)
{
- LOG_ERROR_MESSAGE("DrawMesh command arguments are invalid: no pipeline state is bound.");
+ LOG_ERROR_MESSAGE("IDeviceContext::TraceRays command arguments are invalid: no pipeline state is bound.");
return false;
}
- if (m_pPipelineState->GetDesc().PipelineType != PIPELINE_TYPE_MESH)
+ if (!m_pPipelineState->GetDesc().IsRayTracingPipeline())
{
- LOG_ERROR_MESSAGE("DrawMesh command arguments are invalid: pipeline state '",
- m_pPipelineState->GetDesc().Name, "' is not a mesh pipeline.");
+ LOG_ERROR_MESSAGE("IDeviceContext::TraceRays command arguments are invalid: pipeline state '", m_pPipelineState->GetDesc().Name, "' is not a ray tracing pipeline.");
+ return false;
+ }
+
+ if (m_pActiveRenderPass != nullptr && Attribs.SBTTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::TraceRays command uses resource state transition and must be performed outside of render pass");
+ return false;
+ }
+
+ if (!VerifyTraceRaysAttribs(Attribs))
+ return false;
+
+ if (m_pPipelineState.RawPtr() != Attribs.pSBT->GetDesc().pPSO)
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::TraceRays command arguments are invalid: currently bound pipeline ", m_pPipelineState->GetDesc().Name,
+ "doesn't match the pipeline ", Attribs.pSBT->GetDesc().pPSO->GetDesc().Name, " that was used in ShaderBindingTable");
return false;
}
- if (Attribs.ThreadGroupCount == 0)
+ if ((Attribs.DimensionX * Attribs.DimensionY * Attribs.DimensionZ) > m_pDevice->GetProperties().MaxRayGenThreads)
{
- LOG_WARNING_MESSAGE("DrawMesh command arguments are invalid: number of groups to dispatch is zero.");
+ LOG_ERROR_MESSAGE("IDeviceContext::TraceRays command arguments are invalid: the dimension must not exceed the ", m_pDevice->GetProperties().MaxRayGenThreads, " threads");
+ return false;
}
+#endif
return true;
}
+
+
+
+#ifdef DILIGENT_DEVELOPMENT
+
template <typename BaseInterface, typename ImplementationTraits>
-inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::
- DvpVerifyDrawIndirectArguments(const DrawIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) const
+inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyDrawArguments(const DrawAttribs& Attribs) const
{
if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0)
return true;
if (!m_pPipelineState)
{
- LOG_ERROR_MESSAGE("DrawIndirect command arguments are invalid: no pipeline state is bound.");
+ LOG_ERROR_MESSAGE("Draw command arguments are invalid: no pipeline state is bound.");
return false;
}
if (m_pPipelineState->GetDesc().PipelineType != PIPELINE_TYPE_GRAPHICS)
{
+ LOG_ERROR_MESSAGE("Draw command arguments are invalid: pipeline state '", m_pPipelineState->GetDesc().Name, "' is not a graphics pipeline.");
+ return false;
+ }
- LOG_ERROR_MESSAGE("DrawIndirect command arguments are invalid: pipeline state '",
+ return VerifyDrawAttribs(Attribs);
+}
+
+template <typename BaseInterface, typename ImplementationTraits>
+inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyDrawIndexedArguments(const DrawIndexedAttribs& Attribs) const
+{
+ if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0)
+ return true;
+
+ if (!m_pPipelineState)
+ {
+ LOG_ERROR_MESSAGE("DrawIndexed command arguments are invalid: no pipeline state is bound.");
+ return false;
+ }
+
+ if (m_pPipelineState->GetDesc().PipelineType != PIPELINE_TYPE_GRAPHICS)
+ {
+ LOG_ERROR_MESSAGE("DrawIndexed command arguments are invalid: pipeline state '",
m_pPipelineState->GetDesc().Name, "' is not a graphics pipeline.");
return false;
}
- if (pAttribsBuffer != nullptr)
+ if (!m_pIndexBuffer)
{
- if ((pAttribsBuffer->GetDesc().BindFlags & BIND_INDIRECT_DRAW_ARGS) == 0)
- {
- LOG_ERROR_MESSAGE("DrawIndirect command arguments are invalid: indirect draw arguments buffer '",
- pAttribsBuffer->GetDesc().Name, "' was not created with BIND_INDIRECT_DRAW_ARGS flag.");
- return false;
- }
+ LOG_ERROR_MESSAGE("DrawIndexed command arguments are invalid: no index buffer is bound.");
+ return false;
}
- else
+
+ return VerifyDrawIndexedAttribs(Attribs);
+}
+
+template <typename BaseInterface, typename ImplementationTraits>
+inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyDrawMeshArguments(const DrawMeshAttribs& Attribs) const
+{
+ if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0)
+ return true;
+
+ if (m_pDevice->GetDeviceCaps().Features.MeshShaders != DEVICE_FEATURE_STATE_ENABLED)
{
- LOG_ERROR_MESSAGE("DrawIndirect command arguments are invalid: indirect draw arguments buffer is null.");
+ LOG_ERROR_MESSAGE("DrawMesh: mesh shaders are not supported by this device");
return false;
}
- if (m_pActiveRenderPass != nullptr && Attribs.IndirectAttribsBufferStateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION)
+ if (!m_pPipelineState)
{
- LOG_ERROR_MESSAGE("Resource state transitons are not allowed inside a render pass and may result in an undefined behavior. "
- "Do not use RESOURCE_STATE_TRANSITION_MODE_TRANSITION or end the render pass first.");
+ LOG_ERROR_MESSAGE("DrawMesh command arguments are invalid: no pipeline state is bound.");
return false;
}
- return true;
+ if (m_pPipelineState->GetDesc().PipelineType != PIPELINE_TYPE_MESH)
+ {
+ LOG_ERROR_MESSAGE("DrawMesh command arguments are invalid: pipeline state '",
+ m_pPipelineState->GetDesc().Name, "' is not a mesh pipeline.");
+ return false;
+ }
+
+ return VerifyDrawMeshAttribs(m_pDevice->GetProperties().MaxDrawMeshTasksCount, Attribs);
}
template <typename BaseInterface, typename ImplementationTraits>
-inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::
- DvpVerifyDrawIndexedIndirectArguments(const DrawIndexedIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) const
+inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyDrawIndirectArguments(
+ const DrawIndirectAttribs& Attribs,
+ const IBuffer* pAttribsBuffer) const
{
if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0)
return true;
if (!m_pPipelineState)
{
- LOG_ERROR_MESSAGE("DrawIndexedIndirect command arguments are invalid: no pipeline state is bound.");
+ LOG_ERROR_MESSAGE("DrawIndirect command arguments are invalid: no pipeline state is bound.");
return false;
}
if (m_pPipelineState->GetDesc().PipelineType != PIPELINE_TYPE_GRAPHICS)
{
- LOG_ERROR_MESSAGE("DrawIndexedIndirect command arguments are invalid: pipeline state '",
+
+ LOG_ERROR_MESSAGE("DrawIndirect command arguments are invalid: pipeline state '",
m_pPipelineState->GetDesc().Name, "' is not a graphics pipeline.");
return false;
}
- if (Attribs.IndexType != VT_UINT16 && Attribs.IndexType != VT_UINT32)
+ if (m_pActiveRenderPass != nullptr && Attribs.IndirectAttribsBufferStateTransitionMode == RESOURCE_STATE_TRANSITION_MODE_TRANSITION)
{
- LOG_ERROR_MESSAGE("DrawIndexedIndirect command arguments are invalid: IndexType (",
- GetValueTypeString(Attribs.IndexType), ") must be VT_UINT16 or VT_UINT32.");
+ LOG_ERROR_MESSAGE("Resource state transitons are not allowed inside a render pass and may result in an undefined behavior. "
+ "Do not use RESOURCE_STATE_TRANSITION_MODE_TRANSITION or end the render pass first.");
return false;
}
- if (!m_pIndexBuffer)
+ return VerifyDrawIndirectAttribs(Attribs, pAttribsBuffer);
+}
+
+template <typename BaseInterface, typename ImplementationTraits>
+inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyDrawIndexedIndirectArguments(
+ const DrawIndexedIndirectAttribs& Attribs,
+ const IBuffer* pAttribsBuffer) const
+{
+ if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0)
+ return true;
+
+ if (!m_pPipelineState)
{
- LOG_ERROR_MESSAGE("DrawIndexedIndirect command arguments are invalid: no index buffer is bound.");
+ LOG_ERROR_MESSAGE("DrawIndexedIndirect command arguments are invalid: no pipeline state is bound.");
return false;
}
- if (pAttribsBuffer != nullptr)
+ if (m_pPipelineState->GetDesc().PipelineType != PIPELINE_TYPE_GRAPHICS)
{
- if ((pAttribsBuffer->GetDesc().BindFlags & BIND_INDIRECT_DRAW_ARGS) == 0)
- {
- LOG_ERROR_MESSAGE("DrawIndexedIndirect command arguments are invalid: indirect draw arguments buffer '",
- pAttribsBuffer->GetDesc().Name, "' was not created with BIND_INDIRECT_DRAW_ARGS flag.");
- return false;
- }
+ LOG_ERROR_MESSAGE("DrawIndexedIndirect command arguments are invalid: pipeline state '",
+ m_pPipelineState->GetDesc().Name, "' is not a graphics pipeline.");
+ return false;
}
- else
+
+ if (!m_pIndexBuffer)
{
- LOG_ERROR_MESSAGE("DrawIndexedIndirect command arguments are invalid: indirect draw arguments buffer is null.");
+ LOG_ERROR_MESSAGE("DrawIndexedIndirect command arguments are invalid: no index buffer is bound.");
return false;
}
@@ -1652,16 +1822,23 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::
return false;
}
- return true;
+ return VerifyDrawIndexedIndirectAttribs(Attribs, pAttribsBuffer);
}
template <typename BaseInterface, typename ImplementationTraits>
-inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::
- DvpVerifyDrawMeshIndirectArguments(const DrawMeshIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) const
+inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyDrawMeshIndirectArguments(
+ const DrawMeshIndirectAttribs& Attribs,
+ const IBuffer* pAttribsBuffer) const
{
if ((Attribs.Flags & DRAW_FLAG_VERIFY_DRAW_ATTRIBS) == 0)
return true;
+ if (m_pDevice->GetDeviceCaps().Features.MeshShaders != DEVICE_FEATURE_STATE_ENABLED)
+ {
+ LOG_ERROR_MESSAGE("DrawMeshIndirect: mesh shaders are not supported by this device");
+ return false;
+ }
+
if (!m_pPipelineState)
{
LOG_ERROR_MESSAGE("DrawMeshIndirect command arguments are invalid: no pipeline state is bound.");
@@ -1675,39 +1852,23 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::
return false;
}
- if (pAttribsBuffer != nullptr)
- {
- if ((pAttribsBuffer->GetDesc().BindFlags & BIND_INDIRECT_DRAW_ARGS) == 0)
- {
- LOG_ERROR_MESSAGE("DrawMeshIndirect command arguments are invalid: indirect draw arguments buffer '",
- pAttribsBuffer->GetDesc().Name, "' was not created with BIND_INDIRECT_DRAW_ARGS flag.");
- return false;
- }
- }
- else
- {
- LOG_ERROR_MESSAGE("DrawMeshIndirect command arguments are invalid: indirect draw arguments buffer is null.");
- return false;
- }
-
- return true;
+ return VerifyDrawMeshIndirectAttribs(Attribs, pAttribsBuffer);
}
template <typename BaseInterface, typename ImplementationTraits>
-inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
- DvpVerifyRenderTargets() const
+inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyRenderTargets() const
{
if (!m_pPipelineState)
{
LOG_ERROR_MESSAGE("No pipeline state is bound");
- return;
+ return false;
}
const auto& PSODesc = m_pPipelineState->GetDesc();
if (!PSODesc.IsAnyGraphicsPipeline())
{
LOG_ERROR_MESSAGE("Pipeline state '", PSODesc.Name, "' is not a graphics pipeline");
- return;
+ return false;
}
TEXTURE_FORMAT BoundRTVFormats[8] = {TEX_FORMAT_UNKNOWN};
@@ -1749,13 +1910,14 @@ inline void DeviceContextBase<BaseInterface, ImplementationTraits>::
"' (", GetTextureFormatAttribs(PSOFmt).Name, ").");
}
}
+
+ return true;
}
template <typename BaseInterface, typename ImplementationTraits>
-inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::
- DvpVerifyDispatchArguments(const DispatchComputeAttribs& Attribs) const
+inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyDispatchArguments(const DispatchComputeAttribs& Attribs) const
{
if (!m_pPipelineState)
{
@@ -1776,21 +1938,13 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::
return false;
}
- if (Attribs.ThreadGroupCountX == 0)
- LOG_WARNING_MESSAGE("DispatchCompute command arguments are invalid: ThreadGroupCountX is zero.");
-
- if (Attribs.ThreadGroupCountY == 0)
- LOG_WARNING_MESSAGE("DispatchCompute command arguments are invalid: ThreadGroupCountY is zero.");
-
- if (Attribs.ThreadGroupCountZ == 0)
- LOG_WARNING_MESSAGE("DispatchCompute command arguments are invalid: ThreadGroupCountZ is zero.");
-
- return true;
+ return VerifyDispatchComputeAttribs(Attribs);
}
template <typename BaseInterface, typename ImplementationTraits>
-inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::
- DvpVerifyDispatchIndirectArguments(const DispatchComputeIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer) const
+inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyDispatchIndirectArguments(
+ const DispatchComputeIndirectAttribs& Attribs,
+ const IBuffer* pAttribsBuffer) const
{
if (!m_pPipelineState)
{
@@ -1811,91 +1965,21 @@ inline bool DeviceContextBase<BaseInterface, ImplementationTraits>::
return false;
}
- if (pAttribsBuffer != nullptr)
- {
- if ((pAttribsBuffer->GetDesc().BindFlags & BIND_INDIRECT_DRAW_ARGS) == 0)
- {
- LOG_ERROR_MESSAGE("DispatchComputeIndirect command arguments are invalid: indirect dispatch arguments buffer '",
- pAttribsBuffer->GetDesc().Name, "' was not created with BIND_INDIRECT_DRAW_ARGS flag.");
- return false;
- }
- }
- else
- {
- LOG_ERROR_MESSAGE("DispatchComputeIndirect command arguments are invalid: indirect dispatch arguments buffer is null.");
- return false;
- }
-
- return true;
+ return VerifyDispatchComputeIndirectAttribs(Attribs, pAttribsBuffer);
}
template <typename BaseInterface, typename ImplementationTraits>
-void DeviceContextBase<BaseInterface, ImplementationTraits>::
- DvpVerifyStateTransitionDesc(const StateTransitionDesc& Barrier) const
+bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyStateTransitionDesc(const StateTransitionDesc& Barrier) const
{
- DEV_CHECK_ERR((Barrier.pTexture != nullptr) ^ (Barrier.pBuffer != nullptr), "Exactly one of pTexture or pBuffer members of StateTransitionDesc must not be null");
- DEV_CHECK_ERR(Barrier.NewState != RESOURCE_STATE_UNKNOWN, "New resource state can't be unknown");
- RESOURCE_STATE OldState = RESOURCE_STATE_UNKNOWN;
- if (Barrier.pTexture)
- {
- const auto& TexDesc = Barrier.pTexture->GetDesc();
-
- DEV_CHECK_ERR(VerifyResourceStates(Barrier.NewState, true), "Invlaid new state specified for texture '", TexDesc.Name, "'");
- OldState = Barrier.OldState != RESOURCE_STATE_UNKNOWN ? Barrier.OldState : Barrier.pTexture->GetState();
- DEV_CHECK_ERR(OldState != RESOURCE_STATE_UNKNOWN,
- "The state of texture '", TexDesc.Name,
- "' is unknown to the engine and is not explicitly specified in the barrier");
- DEV_CHECK_ERR(VerifyResourceStates(OldState, true), "Invlaid old state specified for texture '", TexDesc.Name, "'");
-
- DEV_CHECK_ERR(Barrier.FirstMipLevel < TexDesc.MipLevels, "First mip level (", Barrier.FirstMipLevel,
- ") specified by the barrier is out of range. Texture '",
- TexDesc.Name, "' has only ", TexDesc.MipLevels, " mip level(s)");
- DEV_CHECK_ERR(Barrier.MipLevelsCount == REMAINING_MIP_LEVELS || Barrier.FirstMipLevel + Barrier.MipLevelsCount <= TexDesc.MipLevels,
- "Mip level range ", Barrier.FirstMipLevel, "..", Barrier.FirstMipLevel + Barrier.MipLevelsCount - 1,
- " specified by the barrier is out of range. Texture '",
- TexDesc.Name, "' has only ", TexDesc.MipLevels, " mip level(s)");
-
- DEV_CHECK_ERR(Barrier.FirstArraySlice < TexDesc.ArraySize, "First array slice (", Barrier.FirstArraySlice,
- ") specified by the barrier is out of range. Array size of texture '",
- TexDesc.Name, "' is ", TexDesc.ArraySize);
- DEV_CHECK_ERR(Barrier.ArraySliceCount == REMAINING_ARRAY_SLICES || Barrier.FirstArraySlice + Barrier.ArraySliceCount <= TexDesc.ArraySize,
- "Array slice range ", Barrier.FirstArraySlice, "..", Barrier.FirstArraySlice + Barrier.ArraySliceCount - 1,
- " specified by the barrier is out of range. Array size of texture '",
- TexDesc.Name, "' is ", TexDesc.ArraySize);
-
- auto DevType = m_pDevice->GetDeviceCaps().DevType;
- if (DevType != RENDER_DEVICE_TYPE_D3D12 && DevType != RENDER_DEVICE_TYPE_VULKAN)
- {
- DEV_CHECK_ERR(Barrier.FirstMipLevel == 0 && (Barrier.MipLevelsCount == REMAINING_MIP_LEVELS || Barrier.MipLevelsCount == TexDesc.MipLevels),
- "Failed to transition texture '", TexDesc.Name, "': only whole resources can be transitioned on this device");
- DEV_CHECK_ERR(Barrier.FirstArraySlice == 0 && (Barrier.ArraySliceCount == REMAINING_ARRAY_SLICES || Barrier.ArraySliceCount == TexDesc.ArraySize),
- "Failed to transition texture '", TexDesc.Name, "': only whole resources can be transitioned on this device");
- }
- }
- else
- {
- const auto& BuffDesc = Barrier.pBuffer->GetDesc();
- DEV_CHECK_ERR(VerifyResourceStates(Barrier.NewState, false), "Invlaid new state specified for buffer '", BuffDesc.Name, "'");
- OldState = Barrier.OldState != RESOURCE_STATE_UNKNOWN ? Barrier.OldState : Barrier.pBuffer->GetState();
- DEV_CHECK_ERR(OldState != RESOURCE_STATE_UNKNOWN, "The state of buffer '", BuffDesc.Name, "' is unknown to the engine and is not explicitly specified in the barrier");
- DEV_CHECK_ERR(VerifyResourceStates(OldState, false), "Invlaid old state specified for buffer '", BuffDesc.Name, "'");
- }
-
- if (OldState == RESOURCE_STATE_UNORDERED_ACCESS && Barrier.NewState == RESOURCE_STATE_UNORDERED_ACCESS)
- {
- DEV_CHECK_ERR(Barrier.TransitionType == STATE_TRANSITION_TYPE_IMMEDIATE, "For UAV barriers, transition type must be STATE_TRANSITION_TYPE_IMMEDIATE");
- }
-
- if (Barrier.TransitionType == STATE_TRANSITION_TYPE_BEGIN)
- {
- DEV_CHECK_ERR(!Barrier.UpdateResourceState, "Resource state can't be updated in begin-split barrier");
- }
+ return VerifyStateTransitionDesc(m_pDevice, Barrier);
}
template <typename BaseInterface, typename ImplementationTraits>
-bool DeviceContextBase<BaseInterface, ImplementationTraits>::
- DvpVerifyTextureState(const TextureImplType& Texture, RESOURCE_STATE RequiredState, const char* OperationName) const
+bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyTextureState(
+ const TextureImplType& Texture,
+ RESOURCE_STATE RequiredState,
+ const char* OperationName) const
{
if (Texture.IsInKnownState() && !Texture.CheckState(RequiredState))
{
@@ -1909,8 +1993,10 @@ bool DeviceContextBase<BaseInterface, ImplementationTraits>::
}
template <typename BaseInterface, typename ImplementationTraits>
-bool DeviceContextBase<BaseInterface, ImplementationTraits>::
- DvpVerifyBufferState(const BufferImplType& Buffer, RESOURCE_STATE RequiredState, const char* OperationName) const
+bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyBufferState(
+ const BufferImplType& Buffer,
+ RESOURCE_STATE RequiredState,
+ const char* OperationName) const
{
if (Buffer.IsInKnownState() && !Buffer.CheckState(RequiredState))
{
@@ -1923,6 +2009,40 @@ bool DeviceContextBase<BaseInterface, ImplementationTraits>::
return true;
}
+template <typename BaseInterface, typename ImplementationTraits>
+bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyBLASState(
+ const BottomLevelASType& BLAS,
+ RESOURCE_STATE RequiredState,
+ const char* OperationName) const
+{
+ if (BLAS.IsInKnownState() && !BLAS.CheckState(RequiredState))
+ {
+ LOG_ERROR_MESSAGE(OperationName, " requires BLAS '", BLAS.GetDesc().Name, "' to be transitioned to ", GetResourceStateString(RequiredState),
+ " state. Actual BLAS state: ", GetResourceStateString(BLAS.GetState()),
+ ". Use appropriate state transiton flags or explicitly transition the BLAS using IDeviceContext::TransitionResourceStates() method.");
+ return false;
+ }
+
+ return true;
+}
+
+template <typename BaseInterface, typename ImplementationTraits>
+bool DeviceContextBase<BaseInterface, ImplementationTraits>::DvpVerifyTLASState(
+ const TopLevelASType& TLAS,
+ RESOURCE_STATE RequiredState,
+ const char* OperationName) const
+{
+ if (TLAS.IsInKnownState() && !TLAS.CheckState(RequiredState))
+ {
+ LOG_ERROR_MESSAGE(OperationName, " requires TLAS '", TLAS.GetDesc().Name, "' to be transitioned to ", GetResourceStateString(RequiredState),
+ " state. Actual TLAS state: ", GetResourceStateString(TLAS.GetState()),
+ ". Use appropriate state transiton flags or explicitly transition the TLAS using IDeviceContext::TransitionResourceStates() method.");
+ return false;
+ }
+
+ return true;
+}
+
#endif // DILIGENT_DEVELOPMENT
} // namespace Diligent
diff --git a/Graphics/GraphicsEngine/include/FramebufferBase.hpp b/Graphics/GraphicsEngine/include/FramebufferBase.hpp
index fc008d73..0cd484dc 100644
--- a/Graphics/GraphicsEngine/include/FramebufferBase.hpp
+++ b/Graphics/GraphicsEngine/include/FramebufferBase.hpp
@@ -39,7 +39,7 @@
namespace Diligent
{
-void ValidateFramebufferDesc(const FramebufferDesc& Desc);
+void ValidateFramebufferDesc(const FramebufferDesc& Desc) noexcept(false);
/// Template class implementing base functionality for the framebuffer object.
@@ -66,7 +66,7 @@ public:
TDeviceObjectBase{pRefCounters, pDevice, Desc, bIsDeviceInternal},
m_pRenderPass{Desc.pRenderPass}
{
- ValidateFramebufferDesc(Desc);
+ ValidateFramebufferDesc(this->m_Desc);
if (this->m_Desc.AttachmentCount > 0)
{
diff --git a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp
index a86fae07..54b9ba0c 100644
--- a/Graphics/GraphicsEngine/include/PipelineStateBase.hpp
+++ b/Graphics/GraphicsEngine/include/PipelineStateBase.hpp
@@ -32,19 +32,27 @@
#include <array>
#include <vector>
+#include <unordered_map>
+#include <unordered_set>
#include "PipelineState.h"
#include "DeviceObjectBase.hpp"
#include "STDAllocator.hpp"
#include "EngineMemory.h"
#include "GraphicsAccessories.hpp"
-#include "LinearAllocator.hpp"
+#include "FixedLinearAllocator.hpp"
+#include "HashUtils.hpp"
namespace Diligent
{
void ValidateGraphicsPipelineCreateInfo(const GraphicsPipelineStateCreateInfo& CreateInfo) noexcept(false);
void ValidateComputePipelineCreateInfo(const ComputePipelineStateCreateInfo& CreateInfo) noexcept(false);
+void ValidateRayTracingPipelineCreateInfo(IRenderDevice* pDevice, Uint32 MaxRecursion, const RayTracingPipelineStateCreateInfo& CreateInfo) noexcept(false);
+
+void CopyRayTracingShaderGroups(std::unordered_map<HashMapStringKey, Uint32, HashMapStringKey::Hasher>& NameToGroupIndex,
+ const RayTracingPipelineStateCreateInfo& CreateInfo,
+ FixedLinearAllocator& MemPool) noexcept(false);
void CorrectGraphicsPipelineDesc(GraphicsPipelineDesc& GraphicsPipeline) noexcept;
@@ -109,6 +117,20 @@ public:
ValidateComputePipelineCreateInfo(ComputePipelineCI);
}
+ /// \param pRefCounters - Reference counters object that controls the lifetime of this PSO
+ /// \param pDevice - Pointer to the device.
+ /// \param RayTracingPipelineCI - Ray tracing pipeline create information.
+ /// \param bIsDeviceInternal - Flag indicating if the pipeline state is an internal device object and
+ /// must not keep a strong reference to the device.
+ PipelineStateBase(IReferenceCounters* pRefCounters,
+ RenderDeviceImplType* pDevice,
+ const RayTracingPipelineStateCreateInfo& RayTracingPipelineCI,
+ bool bIsDeviceInternal = false) :
+ PipelineStateBase{pRefCounters, pDevice, RayTracingPipelineCI.PSODesc, bIsDeviceInternal}
+ {
+ ValidateRayTracingPipelineCreateInfo(pDevice, pDevice->GetProperties().MaxRayTracingRecursionDepth, RayTracingPipelineCI);
+ }
+
~PipelineStateBase()
{
@@ -129,6 +151,26 @@ public:
RasterizerStateRegistry.ReportDeletedObject();
DSSRegistry.ReportDeletedObject();
*/
+ VERIFY(m_IsDestructed, "This object must be explicitly destructed with Destruct()");
+ }
+
+ void Destruct()
+ {
+ VERIFY(!m_IsDestructed, "This object has already been destructed");
+
+ if (this->m_Desc.IsAnyGraphicsPipeline() && m_pGraphicsPipelineDesc != nullptr)
+ {
+ m_pGraphicsPipelineDesc->~GraphicsPipelineDesc();
+ m_pGraphicsPipelineDesc = nullptr;
+ }
+ else if (this->m_Desc.IsRayTracingPipeline() && m_pRayTracingPipelineData != nullptr)
+ {
+ m_pRayTracingPipelineData->~RayTracingPipelineData();
+ m_pRayTracingPipelineData = nullptr;
+ }
+#if DILIGENT_DEBUG
+ m_IsDestructed = true;
+#endif
}
IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_PipelineState, TDeviceObjectBase)
@@ -160,7 +202,41 @@ public:
return *m_pGraphicsPipelineDesc;
}
+ virtual const RayTracingPipelineDesc& DILIGENT_CALL_TYPE GetRayTracingPipelineDesc() const override final
+ {
+ VERIFY_EXPR(this->m_Desc.IsRayTracingPipeline());
+ VERIFY_EXPR(m_pRayTracingPipelineData != nullptr);
+ return m_pRayTracingPipelineData->Desc;
+ }
+
+ inline void CopyShaderHandle(const char* Name, void* pData, size_t DataSize) const
+ {
+ VERIFY_EXPR(this->m_Desc.IsRayTracingPipeline());
+ VERIFY_EXPR(m_pRayTracingPipelineData != nullptr);
+
+ const auto ShaderHandleSize = m_pRayTracingPipelineData->ShaderHandleSize;
+ VERIFY_EXPR(ShaderHandleSize <= DataSize);
+
+ if (Name == nullptr || Name[0] == '\0')
+ {
+ // set shader binding to zero to skip shader execution
+ std::memset(pData, 0, ShaderHandleSize);
+ return;
+ }
+
+ auto iter = m_pRayTracingPipelineData->NameToGroupIndex.find(Name);
+ if (iter != m_pRayTracingPipelineData->NameToGroupIndex.end())
+ {
+ VERIFY_EXPR(ShaderHandleSize * (iter->second + 1) <= m_pRayTracingPipelineData->ShaderDataSize);
+ std::memcpy(pData, &m_pRayTracingPipelineData->Shaders[ShaderHandleSize * iter->second], ShaderHandleSize);
+ return;
+ }
+ UNEXPECTED("Can't find shader group with specified name");
+ }
+
protected:
+ using TNameToGroupIndexMap = std::unordered_map<HashMapStringKey, Uint32, HashMapStringKey::Hasher>;
+
Int8 GetStaticVariableCountHelper(SHADER_TYPE ShaderType, const std::array<Int8, MAX_SHADERS_IN_PIPELINE>& ResourceLayoutIndex) const
{
if (!IsConsistentShaderType(ShaderType, this->m_Desc.PipelineType))
@@ -223,7 +299,7 @@ protected:
void ReserveSpaceForPipelineDesc(const GraphicsPipelineStateCreateInfo& CreateInfo,
- LinearAllocator& MemPool) noexcept
+ FixedLinearAllocator& MemPool) noexcept
{
MemPool.AddSpace<GraphicsPipelineDesc>();
ReserveResourceLayout(CreateInfo.PSODesc.ResourceLayout, MemPool);
@@ -238,20 +314,50 @@ protected:
}
MemPool.AddSpace<Uint32>(m_BufferSlotsUsed);
+
+ static_assert(std::is_trivially_destructible<decltype(*InputLayout.LayoutElements)>::value, "Add destructor for this object to Destruct()");
}
void ReserveSpaceForPipelineDesc(const ComputePipelineStateCreateInfo& CreateInfo,
- LinearAllocator& MemPool) const noexcept
+ FixedLinearAllocator& MemPool) const noexcept
{
ReserveResourceLayout(CreateInfo.PSODesc.ResourceLayout, MemPool);
}
+ void ReserveSpaceForPipelineDesc(const RayTracingPipelineStateCreateInfo& CreateInfo,
+ FixedLinearAllocator& MemPool) const noexcept
+ {
+ for (Uint32 i = 0; i < CreateInfo.GeneralShaderCount; ++i)
+ {
+ MemPool.AddSpaceForString(CreateInfo.pGeneralShaders[i].Name);
+ }
+ for (Uint32 i = 0; i < CreateInfo.TriangleHitShaderCount; ++i)
+ {
+ MemPool.AddSpaceForString(CreateInfo.pTriangleHitShaders[i].Name);
+ }
+ for (Uint32 i = 0; i < CreateInfo.ProceduralHitShaderCount; ++i)
+ {
+ MemPool.AddSpaceForString(CreateInfo.pProceduralHitShaders[i].Name);
+ }
+
+ ReserveResourceLayout(CreateInfo.PSODesc.ResourceLayout, MemPool);
+
+ size_t RTDataSize = sizeof(RayTracingPipelineData);
+ // reserve size for shader handles
+ const auto ShaderHandleSize = this->m_pDevice->GetProperties().ShaderGroupHandleSize;
+ RTDataSize += ShaderHandleSize * (CreateInfo.GeneralShaderCount + CreateInfo.TriangleHitShaderCount + CreateInfo.ProceduralHitShaderCount);
+ // Extra bytes are reserved to avoid compiler errors on zero-sized arrays
+ RTDataSize -= sizeof(RayTracingPipelineData::Shaders);
+ MemPool.AddSpace(RTDataSize, alignof(RayTracingPipelineData));
+ }
+
template <typename ShaderImplType, typename TShaderStages>
void ExtractShaders(const GraphicsPipelineStateCreateInfo& CreateInfo,
TShaderStages& ShaderStages)
{
VERIFY(m_NumShaderStages == 0, "The number of shader stages is not zero! ExtractShaders must only be called once.");
+ VERIFY_EXPR(this->m_Desc.IsAnyGraphicsPipeline());
ShaderStages.clear();
auto AddShaderStage = [&](IShader* pShader) {
@@ -298,6 +404,7 @@ protected:
TShaderStages& ShaderStages)
{
VERIFY(m_NumShaderStages == 0, "The number of shader stages is not zero! ExtractShaders must only be called once.");
+ VERIFY_EXPR(this->m_Desc.IsComputePipeline());
ShaderStages.clear();
@@ -311,9 +418,71 @@ protected:
VERIFY_EXPR(!ShaderStages.empty() && ShaderStages.size() == m_NumShaderStages);
}
+ template <typename ShaderImplType, typename TShaderStages>
+ void ExtractShaders(const RayTracingPipelineStateCreateInfo& CreateInfo,
+ TShaderStages& ShaderStages)
+ {
+ VERIFY(m_NumShaderStages == 0, "The number of shader stages is not zero! ExtractShaders must only be called once.");
+ VERIFY_EXPR(this->m_Desc.IsRayTracingPipeline());
+
+ std::unordered_set<IShader*> UniqueShaders;
+
+ auto AddShaderStage = [&ShaderStages, &UniqueShaders](IShader* pShader) {
+ if (pShader != nullptr && UniqueShaders.insert(pShader).second)
+ {
+ auto ShaderType = pShader->GetDesc().ShaderType;
+ auto StageInd = GetShaderTypePipelineIndex(ShaderType, PIPELINE_TYPE_RAY_TRACING);
+ auto& Stage = ShaderStages[StageInd];
+ Stage.Append(ValidatedCast<ShaderImplType>(pShader));
+ VERIFY_EXPR(Stage.Type == SHADER_TYPE_UNKNOWN || Stage.Type == ShaderType);
+ Stage.Type = ShaderType;
+ }
+ };
+
+ ShaderStages.clear();
+ ShaderStages.resize(6);
+
+ for (Uint32 i = 0; i < CreateInfo.GeneralShaderCount; ++i)
+ {
+ AddShaderStage(CreateInfo.pGeneralShaders[i].pShader);
+ }
+ for (Uint32 i = 0; i < CreateInfo.TriangleHitShaderCount; ++i)
+ {
+ AddShaderStage(CreateInfo.pTriangleHitShaders[i].pClosestHitShader);
+ AddShaderStage(CreateInfo.pTriangleHitShaders[i].pAnyHitShader);
+ }
+ for (Uint32 i = 0; i < CreateInfo.ProceduralHitShaderCount; ++i)
+ {
+ AddShaderStage(CreateInfo.pProceduralHitShaders[i].pIntersectionShader);
+ AddShaderStage(CreateInfo.pProceduralHitShaders[i].pClosestHitShader);
+ AddShaderStage(CreateInfo.pProceduralHitShaders[i].pAnyHitShader);
+ }
+
+ if (ShaderStages[GetShaderTypePipelineIndex(SHADER_TYPE_RAY_GEN, PIPELINE_TYPE_RAY_TRACING)].Count() == 0)
+ LOG_ERROR_AND_THROW("At least one shader with type SHADER_TYPE_RAY_GEN must be provided");
+
+ if (ShaderStages[GetShaderTypePipelineIndex(SHADER_TYPE_RAY_MISS, PIPELINE_TYPE_RAY_TRACING)].Count() == 0)
+ LOG_ERROR_AND_THROW("At least one shader with type SHADER_TYPE_RAY_MISS must be provided");
+
+ // remove empty stages
+ for (auto iter = ShaderStages.begin(); iter != ShaderStages.end();)
+ {
+ if (iter->Count() == 0)
+ {
+ iter = ShaderStages.erase(iter);
+ continue;
+ }
+
+ m_ShaderStageTypes[m_NumShaderStages++] = iter->Type;
+ ++iter;
+ }
+
+ VERIFY_EXPR(!ShaderStages.empty() && ShaderStages.size() == m_NumShaderStages);
+ }
+
void InitializePipelineDesc(const GraphicsPipelineStateCreateInfo& CreateInfo,
- LinearAllocator& MemPool)
+ FixedLinearAllocator& MemPool)
{
this->m_pGraphicsPipelineDesc = MemPool.Copy(CreateInfo.GraphicsPipeline);
@@ -352,7 +521,7 @@ protected:
}
const auto& InputLayout = GraphicsPipeline.InputLayout;
- LayoutElement* pLayoutElements = MemPool.Allocate<LayoutElement>(InputLayout.NumElements);
+ LayoutElement* pLayoutElements = MemPool.ConstructArray<LayoutElement>(InputLayout.NumElements);
for (size_t Elem = 0; Elem < InputLayout.NumElements; ++Elem)
{
const auto& SrcElem = InputLayout.LayoutElements[Elem];
@@ -432,7 +601,7 @@ protected:
LayoutElem.Stride = Strides[BuffSlot];
}
- m_pStrides = MemPool.Allocate<Uint32>(m_BufferSlotsUsed);
+ m_pStrides = MemPool.ConstructArray<Uint32>(m_BufferSlotsUsed);
// Set strides for all unused slots to 0
for (Uint32 i = 0; i < m_BufferSlotsUsed; ++i)
@@ -443,13 +612,37 @@ protected:
}
void InitializePipelineDesc(const ComputePipelineStateCreateInfo& CreateInfo,
- LinearAllocator& MemPool)
+ FixedLinearAllocator& MemPool)
{
CopyResourceLayout(CreateInfo.PSODesc.ResourceLayout, this->m_Desc.ResourceLayout, MemPool);
}
+ void InitializePipelineDesc(const RayTracingPipelineStateCreateInfo& CreateInfo,
+ FixedLinearAllocator& MemPool) noexcept
+ {
+ TNameToGroupIndexMap NameToGroupIndex;
+ CopyRayTracingShaderGroups(NameToGroupIndex, CreateInfo, MemPool);
+
+ CopyResourceLayout(CreateInfo.PSODesc.ResourceLayout, this->m_Desc.ResourceLayout, MemPool);
+
+ size_t RTDataSize = sizeof(RayTracingPipelineData);
+ // reserve size for shader handles
+ const auto ShaderHandleSize = this->m_pDevice->GetProperties().ShaderGroupHandleSize;
+ const auto ShaderDataSize = ShaderHandleSize * (CreateInfo.GeneralShaderCount + CreateInfo.TriangleHitShaderCount + CreateInfo.ProceduralHitShaderCount);
+ RTDataSize += ShaderDataSize;
+ // Extra bytes are reserved to avoid compiler errors on zero-sized arrays
+ RTDataSize -= sizeof(RayTracingPipelineData::Shaders);
+
+ this->m_pRayTracingPipelineData = static_cast<RayTracingPipelineData*>(MemPool.Allocate(RTDataSize, alignof(RayTracingPipelineData)));
+ new (this->m_pRayTracingPipelineData) RayTracingPipelineData{};
+ this->m_pRayTracingPipelineData->ShaderHandleSize = ShaderHandleSize;
+ this->m_pRayTracingPipelineData->Desc = CreateInfo.RayTracingPipeline;
+ this->m_pRayTracingPipelineData->ShaderDataSize = ShaderDataSize;
+ this->m_pRayTracingPipelineData->NameToGroupIndex = std::move(NameToGroupIndex);
+ }
+
private:
- static void ReserveResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, LinearAllocator& MemPool) noexcept
+ static void ReserveResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, FixedLinearAllocator& MemPool) noexcept
{
if (SrcLayout.Variables != nullptr)
{
@@ -470,13 +663,16 @@ private:
MemPool.AddSpaceForString(SrcLayout.ImmutableSamplers[i].SamplerOrTextureName);
}
}
+
+ static_assert(std::is_trivially_destructible<decltype(*SrcLayout.Variables)>::value, "Add destructor for this object to Destruct()");
+ static_assert(std::is_trivially_destructible<decltype(*SrcLayout.ImmutableSamplers)>::value, "Add destructor for this object to Destruct()");
}
- static void CopyResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, PipelineResourceLayoutDesc& DstLayout, LinearAllocator& MemPool)
+ static void CopyResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, PipelineResourceLayoutDesc& DstLayout, FixedLinearAllocator& MemPool)
{
if (SrcLayout.Variables != nullptr)
{
- auto* Variables = MemPool.Allocate<ShaderResourceVariableDesc>(SrcLayout.NumVariables);
+ auto* Variables = MemPool.ConstructArray<ShaderResourceVariableDesc>(SrcLayout.NumVariables);
DstLayout.Variables = Variables;
for (Uint32 i = 0; i < SrcLayout.NumVariables; ++i)
{
@@ -488,7 +684,7 @@ private:
if (SrcLayout.ImmutableSamplers != nullptr)
{
- auto* ImmutableSamplers = MemPool.Allocate<ImmutableSamplerDesc>(SrcLayout.NumImmutableSamplers);
+ auto* ImmutableSamplers = MemPool.ConstructArray<ImmutableSamplerDesc>(SrcLayout.NumImmutableSamplers);
DstLayout.ImmutableSamplers = ImmutableSamplers;
for (Uint32 i = 0; i < SrcLayout.NumImmutableSamplers; ++i)
{
@@ -526,7 +722,27 @@ protected:
RefCntAutoPtr<IRenderPass> m_pRenderPass; ///< Strong reference to the render pass object
- GraphicsPipelineDesc* m_pGraphicsPipelineDesc = nullptr;
+ struct RayTracingPipelineData
+ {
+ RayTracingPipelineDesc Desc;
+ TNameToGroupIndexMap NameToGroupIndex;
+
+ Uint32 ShaderHandleSize = 0;
+ Uint32 ShaderDataSize = 0;
+
+ Uint8 Shaders[sizeof(void*)] = {}; // The actual array size will be ShaderDataSize
+ };
+ static_assert(offsetof(RayTracingPipelineData, Shaders) % sizeof(void*) == 0, "Shaders member is expected to be sizeof(void*)-aligned");
+
+ union
+ {
+ GraphicsPipelineDesc* m_pGraphicsPipelineDesc = nullptr;
+ RayTracingPipelineData* m_pRayTracingPipelineData;
+ };
+
+#ifdef DILIGENT_DEBUG
+ bool m_IsDestructed = false;
+#endif
};
} // namespace Diligent
diff --git a/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp b/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp
index f406bf4e..cff25a92 100644
--- a/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp
+++ b/Graphics/GraphicsEngine/include/RenderDeviceBase.hpp
@@ -226,6 +226,15 @@ public:
/// Size of the framebuffer object (FramebufferD3D12Impl, FramebufferVkImpl, etc.), in bytes
const size_t FramebufferObjSize;
+
+ /// Size of the BLAS object (BottomLevelASD3D12Impl, BottomLevelASVkImpl, etc.), in bytes
+ const size_t BLASObjSize;
+
+ /// Size of the TLAS object (TopLevelASD3D12Impl, TopLevelASVkImpl, etc.), in bytes
+ const size_t TLASObjSize;
+
+ /// Size of the SBT object (ShaderBindingTableD3D12Impl, ShaderBindingtableVkImpl, etc.), in bytes
+ const size_t SBTObjSize;
};
/// \param pRefCounters - reference counters object that controls the lifetime of this render device
@@ -261,7 +270,11 @@ public:
m_FenceAllocator {RawMemAllocator, ObjectSizes.FenceSize, 16 },
m_QueryAllocator {RawMemAllocator, ObjectSizes.QuerySize, 16 },
m_RenderPassAllocator {RawMemAllocator, ObjectSizes.RenderPassObjSize, 16 },
- m_FramebufferAllocator {RawMemAllocator, ObjectSizes.FramebufferObjSize, 16 }
+ m_FramebufferAllocator {RawMemAllocator, ObjectSizes.FramebufferObjSize, 16 },
+ m_BLASAllocator {RawMemAllocator, ObjectSizes.BLASObjSize, 16 },
+ m_TLASAllocator {RawMemAllocator, ObjectSizes.TLASObjSize, 16 },
+ m_SBTAllocator {RawMemAllocator, ObjectSizes.SBTObjSize, 16 },
+ m_DeviceProperties {}
// clang-format on
{
// Initialize texture format info
@@ -335,6 +348,12 @@ public:
return m_DeviceCaps;
}
+ /// Implementation of IRenderDevice::GetDeviceProperties().
+ virtual const DeviceProperties& DILIGENT_CALL_TYPE GetDeviceProperties() const override final
+ {
+ return m_DeviceProperties;
+ }
+
/// Implementation of IRenderDevice::GetTextureFormatInfo().
virtual const TextureFormatInfo& DILIGENT_CALL_TYPE GetTextureFormatInfo(TEXTURE_FORMAT TexFormat) override final
{
@@ -406,7 +425,8 @@ protected:
RefCntAutoPtr<IEngineFactory> m_pEngineFactory;
- DeviceCaps m_DeviceCaps;
+ DeviceCaps m_DeviceCaps;
+ DeviceProperties m_DeviceProperties;
// All state object registries hold raw pointers.
// This is safe because every object unregisters itself
@@ -436,6 +456,9 @@ protected:
FixedBlockMemoryAllocator m_QueryAllocator; ///< Allocator for query objects
FixedBlockMemoryAllocator m_RenderPassAllocator; ///< Allocator for render pass objects
FixedBlockMemoryAllocator m_FramebufferAllocator; ///< Allocator for framebuffer objects
+ FixedBlockMemoryAllocator m_BLASAllocator; ///< Allocator for bottom-level acceleration structure objects
+ FixedBlockMemoryAllocator m_TLASAllocator; ///< Allocator for top-level acceleration structure objects
+ FixedBlockMemoryAllocator m_SBTAllocator; ///< Allocator for shader binding table objects
};
diff --git a/Graphics/GraphicsEngine/include/RenderPassBase.hpp b/Graphics/GraphicsEngine/include/RenderPassBase.hpp
index fbc65dd7..627c2094 100644
--- a/Graphics/GraphicsEngine/include/RenderPassBase.hpp
+++ b/Graphics/GraphicsEngine/include/RenderPassBase.hpp
@@ -40,7 +40,7 @@
namespace Diligent
{
-void ValidateRenderPassDesc(const RenderPassDesc& Desc);
+void ValidateRenderPassDesc(const RenderPassDesc& Desc) noexcept(false);
template <typename RenderDeviceImplType>
void _CorrectAttachmentState(RESOURCE_STATE& State) {}
@@ -81,7 +81,7 @@ public:
bool bIsDeviceInternal = false) :
TDeviceObjectBase{pRefCounters, pDevice, Desc, bIsDeviceInternal}
{
- ValidateRenderPassDesc(Desc);
+ ValidateRenderPassDesc(this->m_Desc);
if (Desc.AttachmentCount != 0)
{
diff --git a/Graphics/GraphicsEngine/include/ResourceMappingImpl.hpp b/Graphics/GraphicsEngine/include/ResourceMappingImpl.hpp
index 144ecdd5..ad70ae9d 100644
--- a/Graphics/GraphicsEngine/include/ResourceMappingImpl.hpp
+++ b/Graphics/GraphicsEngine/include/ResourceMappingImpl.hpp
@@ -30,68 +30,17 @@
/// \file
/// Declaration of the Diligent::ResourceMappingImpl class
+#include <unordered_map>
+
#include "ResourceMapping.h"
#include "ObjectBase.hpp"
-#include <unordered_map>
#include "HashUtils.hpp"
#include "STDAllocator.hpp"
+#include "RefCntAutoPtr.hpp"
namespace Diligent
{
-struct ResMappingHashKey
-{
- ResMappingHashKey(const Char* Str, bool bMakeCopy, Uint32 ArrInd) :
- StrKey{Str, bMakeCopy},
- ArrayIndex{ArrInd}
- {
- }
-
- ResMappingHashKey(ResMappingHashKey&& rhs) :
- StrKey{std::move(rhs.StrKey)},
- ArrayIndex{rhs.ArrayIndex}
- {}
-
- bool operator==(const ResMappingHashKey& RHS) const
- {
- return StrKey == RHS.StrKey && ArrayIndex == RHS.ArrayIndex;
- }
-
- size_t GetHash() const
- {
- if (Hash == 0)
- {
- Hash = ComputeHash(StrKey.GetHash(), ArrayIndex);
- }
-
- return Hash;
- }
-
- // clang-format off
- ResMappingHashKey ( const ResMappingHashKey& ) = delete;
- ResMappingHashKey& operator = ( const ResMappingHashKey& ) = delete;
- ResMappingHashKey& operator = ( ResMappingHashKey&& ) = delete;
- // clang-format on
-
- HashMapStringKey StrKey;
- Uint32 ArrayIndex;
- mutable size_t Hash = 0;
-};
-} // namespace Diligent
-
-namespace std
-{
-template <>
-struct hash<Diligent::ResMappingHashKey>
-{
- size_t operator()(const Diligent::ResMappingHashKey& Key) const
- {
- return Key.GetHash();
- }
-};
-} // namespace std
-namespace Diligent
-{
class FixedBlockMemoryAllocator;
/// Implementation of the resource mapping
@@ -103,13 +52,13 @@ public:
/// \param pRefCounters - reference counters object that controls the lifetime of this resource mapping
/// \param RawMemAllocator - raw memory allocator that is used by the m_HashTable member
ResourceMappingImpl(IReferenceCounters* pRefCounters, IMemoryAllocator& RawMemAllocator) :
- TObjectBase(pRefCounters),
- m_HashTable(STD_ALLOCATOR_RAW_MEM(HashTableElem, RawMemAllocator, "Allocator for unordered_map< ResMappingHashKey, RefCntAutoPtr<IDeviceObject> >"))
+ TObjectBase{pRefCounters},
+ m_HashTable{STD_ALLOCATOR_RAW_MEM(HashTableElem, RawMemAllocator, "Allocator for unordered_map<ResMappingHashKey, RefCntAutoPtr<IDeviceObject>>")}
{}
~ResourceMappingImpl();
- virtual void DILIGENT_CALL_TYPE QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface) override final;
+ IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_ResourceMapping, TObjectBase)
/// Implementation of IResourceMapping::AddResource()
virtual void DILIGENT_CALL_TYPE AddResource(const Char* Name,
@@ -135,10 +84,47 @@ public:
virtual size_t DILIGENT_CALL_TYPE GetSize() override final;
private:
+ struct ResMappingHashKey : public HashMapStringKey
+ {
+ using TBase = HashMapStringKey;
+
+ ResMappingHashKey(const Char* Str, bool bMakeCopy, Uint32 ArrInd) :
+ HashMapStringKey{Str, bMakeCopy},
+ ArrayIndex{ArrInd}
+ {
+ Ownership_Hash = (ComputeHash(GetHash(), ArrInd) & HashMask) | (Ownership_Hash & StrOwnershipMask);
+ }
+
+ ResMappingHashKey(ResMappingHashKey&& rhs) :
+ HashMapStringKey{std::move(rhs)},
+ ArrayIndex{rhs.ArrayIndex}
+ {}
+
+ // clang-format off
+ ResMappingHashKey ( const ResMappingHashKey& ) = delete;
+ ResMappingHashKey& operator = ( const ResMappingHashKey& ) = delete;
+ ResMappingHashKey& operator = ( ResMappingHashKey&& ) = delete;
+ // clang-format on
+
+ bool operator==(const ResMappingHashKey& RHS) const
+ {
+ return static_cast<const TBase&>(*this) == static_cast<const TBase&>(RHS) && ArrayIndex == RHS.ArrayIndex;
+ }
+
+ const Uint32 ArrayIndex;
+ };
+
ThreadingTools::LockHelper Lock();
- ThreadingTools::LockFlag m_LockFlag;
- typedef std::pair<const ResMappingHashKey, RefCntAutoPtr<IDeviceObject>> HashTableElem;
- std::unordered_map<ResMappingHashKey, RefCntAutoPtr<IDeviceObject>, std::hash<ResMappingHashKey>, std::equal_to<ResMappingHashKey>, STDAllocatorRawMem<HashTableElem>> m_HashTable;
+ ThreadingTools::LockFlag m_LockFlag;
+
+ using HashTableElem = std::pair<const ResMappingHashKey, RefCntAutoPtr<IDeviceObject>>;
+ std::unordered_map<ResMappingHashKey,
+ RefCntAutoPtr<IDeviceObject>,
+ ResMappingHashKey::Hasher,
+ std::equal_to<ResMappingHashKey>,
+ STDAllocatorRawMem<HashTableElem>>
+ m_HashTable;
};
+
} // namespace Diligent
diff --git a/Graphics/GraphicsEngine/include/ShaderBase.hpp b/Graphics/GraphicsEngine/include/ShaderBase.hpp
index 24ad92ee..8b6e9efa 100644
--- a/Graphics/GraphicsEngine/include/ShaderBase.hpp
+++ b/Graphics/GraphicsEngine/include/ShaderBase.hpp
@@ -79,6 +79,9 @@ public:
if ((ShdrDesc.ShaderType == SHADER_TYPE_AMPLIFICATION || ShdrDesc.ShaderType == SHADER_TYPE_MESH) && !deviceFeatures.MeshShaders)
LOG_ERROR_AND_THROW("Mesh shaders are not supported by this device");
+
+ if ((ShdrDesc.ShaderType >= SHADER_TYPE_RAY_GEN && ShdrDesc.ShaderType <= SHADER_TYPE_CALLABLE) && !deviceFeatures.RayTracing)
+ LOG_ERROR_AND_THROW("Ray tracing shaders are not supported by this device");
}
IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_Shader, TDeviceObjectBase)
diff --git a/Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp b/Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp
new file mode 100644
index 00000000..340d8821
--- /dev/null
+++ b/Graphics/GraphicsEngine/include/ShaderBindingTableBase.hpp
@@ -0,0 +1,548 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Implementation of the Diligent::ShaderBindingTableBase template class
+
+#include <unordered_map>
+
+#include "ShaderBindingTable.h"
+#include "TopLevelASBase.hpp"
+#include "DeviceObjectBase.hpp"
+#include "RenderDeviceBase.hpp"
+#include "StringPool.hpp"
+#include "HashUtils.hpp"
+
+namespace Diligent
+{
+
+/// Validates SBT description and throws an exception in case of an error.
+void ValidateShaderBindingTableDesc(const ShaderBindingTableDesc& Desc, Uint32 ShaderGroupHandleSize, Uint32 MaxShaderRecordStride) noexcept(false);
+
+/// Template class implementing base functionality for a shader binding table object.
+
+/// \tparam BaseInterface - base interface that this class will inheret
+/// (Diligent::IShaderBindingTableD3D12 or Diligent::IShaderBindingTableVk).
+/// \tparam RenderDeviceImplType - type of the render device implementation
+/// (Diligent::RenderDeviceD3D12Impl or Diligent::RenderDeviceVkImpl)
+template <class BaseInterface, class PipelineStateImplType, class TopLevelASImplType, class RenderDeviceImplType>
+class ShaderBindingTableBase : public DeviceObjectBase<BaseInterface, RenderDeviceImplType, ShaderBindingTableDesc>
+{
+public:
+ using TDeviceObjectBase = DeviceObjectBase<BaseInterface, RenderDeviceImplType, ShaderBindingTableDesc>;
+
+ /// \param pRefCounters - reference counters object that controls the lifetime of this SBT.
+ /// \param pDevice - pointer to the device.
+ /// \param Desc - SBT description.
+ /// \param bIsDeviceInternal - flag indicating if the BLAS is an internal device object and
+ /// must not keep a strong reference to the device.
+ ShaderBindingTableBase(IReferenceCounters* pRefCounters,
+ RenderDeviceImplType* pDevice,
+ const ShaderBindingTableDesc& Desc,
+ bool bIsDeviceInternal = false) :
+ TDeviceObjectBase{pRefCounters, pDevice, Desc, bIsDeviceInternal}
+ {
+ const auto& DeviceProps = this->m_pDevice->GetProperties();
+ ValidateShaderBindingTableDesc(this->m_Desc, DeviceProps.ShaderGroupHandleSize, DeviceProps.MaxShaderRecordStride);
+
+ this->m_pPSO = ValidatedCast<PipelineStateImplType>(this->m_Desc.pPSO);
+ this->m_ShaderRecordSize = this->m_pPSO->GetRayTracingPipelineDesc().ShaderRecordSize;
+ this->m_ShaderRecordStride = this->m_ShaderRecordSize + DeviceProps.ShaderGroupHandleSize;
+ }
+
+ ~ShaderBindingTableBase()
+ {
+ }
+
+ IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_ShaderBindingTable, TDeviceObjectBase)
+
+
+ void DILIGENT_CALL_TYPE Reset(IPipelineState* pPSO) override final
+ {
+#ifdef DILIGENT_DEVELOPMENT
+ this->m_DbgHitGroupBindings.clear();
+#endif
+ this->m_RayGenShaderRecord.clear();
+ this->m_MissShadersRecord.clear();
+ this->m_CallableShadersRecord.clear();
+ this->m_HitGroupsRecord.clear();
+ this->m_Changed = true;
+ this->m_pPSO = nullptr;
+
+ this->m_Desc.pPSO = pPSO;
+
+ const auto& DeviceProps = this->m_pDevice->GetProperties();
+ try
+ {
+ ValidateShaderBindingTableDesc(this->m_Desc, DeviceProps.ShaderGroupHandleSize, DeviceProps.MaxShaderRecordStride);
+ }
+ catch (const std::runtime_error&)
+ {
+ return;
+ }
+
+ this->m_pPSO = ValidatedCast<PipelineStateImplType>(this->m_Desc.pPSO);
+ this->m_ShaderRecordSize = this->m_pPSO->GetRayTracingPipelineDesc().ShaderRecordSize;
+ this->m_ShaderRecordStride = this->m_ShaderRecordSize + DeviceProps.ShaderGroupHandleSize;
+ }
+
+
+ void DILIGENT_CALL_TYPE ResetHitGroups() override final
+ {
+#ifdef DILIGENT_DEVELOPMENT
+ this->m_DbgHitGroupBindings.clear();
+#endif
+ this->m_HitGroupsRecord.clear();
+ this->m_Changed = true;
+ }
+
+
+ void DILIGENT_CALL_TYPE BindRayGenShader(const char* pShaderGroupName, const void* pData, Uint32 DataSize) override final
+ {
+ VERIFY_EXPR((pData == nullptr) == (DataSize == 0));
+ VERIFY_EXPR((pData == nullptr) || (DataSize == this->m_ShaderRecordSize));
+
+ this->m_RayGenShaderRecord.resize(this->m_ShaderRecordStride, Uint8{EmptyElem});
+ this->m_pPSO->CopyShaderHandle(pShaderGroupName, this->m_RayGenShaderRecord.data(), this->m_ShaderRecordStride);
+
+ const Uint32 GroupSize = this->m_pDevice->GetProperties().ShaderGroupHandleSize;
+ std::memcpy(this->m_RayGenShaderRecord.data() + GroupSize, pData, DataSize);
+ this->m_Changed = true;
+ }
+
+
+ void DILIGENT_CALL_TYPE BindMissShader(const char* pShaderGroupName, Uint32 MissIndex, const void* pData, Uint32 DataSize) override final
+ {
+ VERIFY_EXPR((pData == nullptr) == (DataSize == 0));
+ VERIFY_EXPR((pData == nullptr) || (DataSize == this->m_ShaderRecordSize));
+
+ const Uint32 GroupSize = this->m_pDevice->GetProperties().ShaderGroupHandleSize;
+ const size_t Stride = this->m_ShaderRecordStride;
+ const size_t Offset = MissIndex * Stride;
+ this->m_MissShadersRecord.resize(std::max(this->m_MissShadersRecord.size(), Offset + Stride), Uint8{EmptyElem});
+
+ this->m_pPSO->CopyShaderHandle(pShaderGroupName, this->m_MissShadersRecord.data() + Offset, Stride);
+ std::memcpy(this->m_MissShadersRecord.data() + Offset + GroupSize, pData, DataSize);
+ this->m_Changed = true;
+ }
+
+
+ void DILIGENT_CALL_TYPE BindHitGroupByIndex(Uint32 BindingIndex,
+ const char* pShaderGroupName,
+ const void* pData,
+ Uint32 DataSize) override final
+ {
+ VERIFY_EXPR((pData == nullptr) == (DataSize == 0));
+ VERIFY_EXPR((pData == nullptr) || (DataSize == this->m_ShaderRecordSize));
+
+ const size_t Stride = this->m_ShaderRecordStride;
+ const Uint32 GroupSize = this->m_pDevice->GetProperties().ShaderGroupHandleSize;
+ const size_t Offset = BindingIndex * Stride;
+
+ this->m_HitGroupsRecord.resize(std::max(this->m_HitGroupsRecord.size(), Offset + Stride), Uint8{EmptyElem});
+
+ this->m_pPSO->CopyShaderHandle(pShaderGroupName, this->m_HitGroupsRecord.data() + Offset, Stride);
+ std::memcpy(this->m_HitGroupsRecord.data() + Offset + GroupSize, pData, DataSize);
+ this->m_Changed = true;
+
+#ifdef DILIGENT_DEVELOPMENT
+ OnBindHitGroup(nullptr, BindingIndex);
+#endif
+ }
+
+
+ void DILIGENT_CALL_TYPE BindHitGroup(ITopLevelAS* pTLAS,
+ const char* pInstanceName,
+ const char* pGeometryName,
+ Uint32 RayOffsetInHitGroupIndex,
+ const char* pShaderGroupName,
+ const void* pData,
+ Uint32 DataSize) override final
+ {
+ VERIFY_EXPR((pData == nullptr) == (DataSize == 0));
+ VERIFY_EXPR((pData == nullptr) || (DataSize == this->m_ShaderRecordSize));
+ VERIFY_EXPR(pTLAS != nullptr);
+
+ auto* const pTLASImpl = ValidatedCast<TopLevelASImplType>(pTLAS);
+ const auto Info = pTLASImpl->GetBuildInfo();
+ const auto Desc = pTLASImpl->GetInstanceDesc(pInstanceName);
+
+ VERIFY_EXPR(Info.BindingMode == HIT_GROUP_BINDING_MODE_PER_GEOMETRY);
+ VERIFY_EXPR(RayOffsetInHitGroupIndex < Info.HitGroupStride);
+ VERIFY_EXPR(Desc.ContributionToHitGroupIndex != ~0u);
+ VERIFY_EXPR(Desc.pBLAS != nullptr);
+
+ const Uint32 InstanceOffset = Desc.ContributionToHitGroupIndex;
+ const Uint32 GeometryIndex = Desc.pBLAS->GetGeometryIndex(pGeometryName);
+ VERIFY_EXPR(GeometryIndex != INVALID_INDEX);
+
+ const Uint32 Index = InstanceOffset + GeometryIndex * Info.HitGroupStride + RayOffsetInHitGroupIndex;
+ const size_t Stride = this->m_ShaderRecordStride;
+ const Uint32 GroupSize = this->m_pDevice->GetProperties().ShaderGroupHandleSize;
+ const size_t Offset = Index * Stride;
+
+ this->m_HitGroupsRecord.resize(std::max(this->m_HitGroupsRecord.size(), Offset + Stride), Uint8{EmptyElem});
+
+ this->m_pPSO->CopyShaderHandle(pShaderGroupName, this->m_HitGroupsRecord.data() + Offset, Stride);
+ std::memcpy(this->m_HitGroupsRecord.data() + Offset + GroupSize, pData, DataSize);
+ this->m_Changed = true;
+
+#ifdef DILIGENT_DEVELOPMENT
+ VERIFY_EXPR(Index >= Info.FirstContributionToHitGroupIndex && Index <= Info.LastContributionToHitGroupIndex);
+ OnBindHitGroup(pTLASImpl, Index);
+#endif
+ }
+
+
+ void DILIGENT_CALL_TYPE BindHitGroups(ITopLevelAS* pTLAS,
+ const char* pInstanceName,
+ Uint32 RayOffsetInHitGroupIndex,
+ const char* pShaderGroupName,
+ const void* pData,
+ Uint32 DataSize) override final
+ {
+ VERIFY_EXPR((pData == nullptr) == (DataSize == 0));
+ VERIFY_EXPR((pData == nullptr) || (DataSize == this->m_ShaderRecordSize));
+ VERIFY_EXPR(pTLAS != nullptr);
+
+ auto* const pTLASImpl = ValidatedCast<TopLevelASImplType>(pTLAS);
+ const auto Info = pTLASImpl->GetBuildInfo();
+ const auto Desc = pTLASImpl->GetInstanceDesc(pInstanceName);
+
+ VERIFY_EXPR(Info.BindingMode == HIT_GROUP_BINDING_MODE_PER_GEOMETRY ||
+ Info.BindingMode == HIT_GROUP_BINDING_MODE_PER_INSTANCE);
+ VERIFY_EXPR(RayOffsetInHitGroupIndex < Info.HitGroupStride);
+ VERIFY_EXPR(Desc.ContributionToHitGroupIndex != INVALID_INDEX);
+ VERIFY_EXPR(Desc.pBLAS != nullptr);
+
+ const Uint32 InstanceOffset = Desc.ContributionToHitGroupIndex;
+ Uint32 GeometryCount = 0;
+
+ switch (Info.BindingMode)
+ {
+ // clang-format off
+ case HIT_GROUP_BINDING_MODE_PER_GEOMETRY: GeometryCount = Desc.pBLAS->GetActualGeometryCount(); break;
+ case HIT_GROUP_BINDING_MODE_PER_INSTANCE: GeometryCount = 1; break;
+ default: UNEXPECTED("unknown binding mode");
+ // clang-format on
+ }
+
+ const Uint32 BeginIndex = InstanceOffset;
+ const size_t EndIndex = InstanceOffset + GeometryCount * Info.HitGroupStride;
+ const Uint32 GroupSize = this->m_pDevice->GetProperties().ShaderGroupHandleSize;
+ const size_t Stride = this->m_ShaderRecordStride;
+
+ this->m_HitGroupsRecord.resize(std::max(this->m_HitGroupsRecord.size(), EndIndex * Stride), Uint8{EmptyElem});
+ this->m_Changed = true;
+
+ for (Uint32 i = 0; i < GeometryCount; ++i)
+ {
+ Uint32 Index = BeginIndex + i * Info.HitGroupStride + RayOffsetInHitGroupIndex;
+ size_t Offset = Index * Stride;
+ this->m_pPSO->CopyShaderHandle(pShaderGroupName, this->m_HitGroupsRecord.data() + Offset, Stride);
+
+ std::memcpy(this->m_HitGroupsRecord.data() + Offset + GroupSize, pData, DataSize);
+
+#ifdef DILIGENT_DEVELOPMENT
+ VERIFY_EXPR(Index >= Info.FirstContributionToHitGroupIndex && Index <= Info.LastContributionToHitGroupIndex);
+ OnBindHitGroup(pTLASImpl, BeginIndex + i);
+#endif
+ }
+ }
+
+
+ void DILIGENT_CALL_TYPE BindHitGroupForAll(ITopLevelAS* pTLAS,
+ Uint32 RayOffsetInHitGroupIndex,
+ const char* pShaderGroupName,
+ const void* pData,
+ Uint32 DataSize) override final
+ {
+ VERIFY_EXPR((pData == nullptr) == (DataSize == 0));
+ VERIFY_EXPR((pData == nullptr) || (DataSize == this->m_ShaderRecordSize));
+ VERIFY_EXPR(pTLAS != nullptr);
+
+ auto* pTLASImpl = ValidatedCast<TopLevelASImplType>(pTLAS);
+ const auto Info = pTLASImpl->GetBuildInfo();
+ VERIFY_EXPR(Info.BindingMode == HIT_GROUP_BINDING_MODE_PER_GEOMETRY ||
+ Info.BindingMode == HIT_GROUP_BINDING_MODE_PER_INSTANCE ||
+ Info.BindingMode == HIT_GROUP_BINDING_MODE_PER_ACCEL_STRUCT);
+ VERIFY_EXPR(RayOffsetInHitGroupIndex < Info.HitGroupStride);
+
+ const Uint32 GroupSize = this->m_pDevice->GetProperties().ShaderGroupHandleSize;
+ const size_t Stride = this->m_ShaderRecordStride;
+ this->m_HitGroupsRecord.resize(std::max(this->m_HitGroupsRecord.size(), (Info.LastContributionToHitGroupIndex + 1) * Stride), Uint8{EmptyElem});
+ this->m_Changed = true;
+
+ for (Uint32 Index = RayOffsetInHitGroupIndex + Info.FirstContributionToHitGroupIndex;
+ Index <= Info.LastContributionToHitGroupIndex;
+ Index += Info.HitGroupStride)
+ {
+ const size_t Offset = Index * Stride;
+ this->m_pPSO->CopyShaderHandle(pShaderGroupName, this->m_HitGroupsRecord.data() + Offset, Stride);
+ std::memcpy(this->m_HitGroupsRecord.data() + Offset + GroupSize, pData, DataSize);
+
+#ifdef DILIGENT_DEVELOPMENT
+ OnBindHitGroup(pTLASImpl, Index);
+#endif
+ }
+ }
+
+
+ void DILIGENT_CALL_TYPE BindCallableShader(const char* pShaderGroupName,
+ Uint32 CallableIndex,
+ const void* pData,
+ Uint32 DataSize) override final
+ {
+ VERIFY_EXPR((pData == nullptr) == (DataSize == 0));
+ VERIFY_EXPR((pData == nullptr) || (DataSize == this->m_ShaderRecordSize));
+
+ const Uint32 GroupSize = this->m_pDevice->GetProperties().ShaderGroupHandleSize;
+ const size_t Offset = CallableIndex * this->m_ShaderRecordStride;
+ this->m_CallableShadersRecord.resize(std::max(this->m_CallableShadersRecord.size(), Offset + this->m_ShaderRecordStride), Uint8{EmptyElem});
+
+ this->m_pPSO->CopyShaderHandle(pShaderGroupName, this->m_CallableShadersRecord.data() + Offset, this->m_ShaderRecordStride);
+ std::memcpy(this->m_CallableShadersRecord.data() + Offset + GroupSize, pData, DataSize);
+ this->m_Changed = true;
+ }
+
+
+ Bool DILIGENT_CALL_TYPE Verify(SHADER_BINDING_VALIDATION_FLAGS Flags) const override final
+ {
+#ifdef DILIGENT_DEVELOPMENT
+ static_assert(EmptyElem != 0, "must not be zero");
+
+ const auto Stride = this->m_ShaderRecordStride;
+ const auto ShSize = this->m_pDevice->GetProperties().ShaderGroupHandleSize;
+ const auto FindPattern = [&](const std::vector<Uint8>& Data, const char* GroupName) -> bool //
+ {
+ for (size_t i = 0; i < Data.size(); i += Stride)
+ {
+ if (Flags & SHADER_BINDING_VALIDATION_SHADER_ONLY)
+ {
+ Uint32 Count = 0;
+ for (size_t j = 0; j < ShSize; ++j)
+ Count += (Data[i + j] == EmptyElem);
+
+ if (Count == ShSize)
+ {
+ LOG_INFO_MESSAGE("Shader binding table '", this->m_Desc.Name, "' is not valid: shader in '", GroupName, "'(", i / Stride, ") is not bound");
+ return false;
+ }
+ }
+
+ if ((Flags & SHADER_BINDING_VALIDATION_SHADER_RECORD) && this->m_ShaderRecordSize > 0)
+ {
+ Uint32 Count = 0;
+ for (size_t j = ShSize; j < Stride; ++j)
+ Count += (Data[i + j] == EmptyElem);
+
+ // shader record data may not used in shader
+ if (Count == Stride - ShSize)
+ {
+ LOG_INFO_MESSAGE("Shader binding table '", this->m_Desc.Name, "' is not valid: shader record data in '", GroupName, "'(", i / Stride, ") is not initialized");
+ return false;
+ }
+ }
+ }
+ return true;
+ };
+
+ if (m_RayGenShaderRecord.empty())
+ {
+ LOG_INFO_MESSAGE("Shader binding table '", this->m_Desc.Name, "' is not valid: ray generation shader is not bound");
+ return false;
+ }
+
+ if (Flags & SHADER_BINDING_VALIDATION_TLAS)
+ {
+ for (size_t i = 0; i < m_DbgHitGroupBindings.size(); ++i)
+ {
+ auto& Binding = m_DbgHitGroupBindings[i];
+ auto pTLAS = Binding.pTLAS.Lock();
+ if (!Binding.IsBound)
+ {
+ LOG_INFO_MESSAGE("Shader binding table '", this->m_Desc.Name, "' is not valid: hit group at index (", i, ") is not bound");
+ return false;
+ }
+ if (!pTLAS)
+ {
+ LOG_INFO_MESSAGE("Shader binding table '", this->m_Desc.Name, "' is not valid: TLAS that was used to bind hit group at index (", i, ") was deleted");
+ return false;
+ }
+ if (pTLAS->GetVersion() != Binding.Version)
+ {
+ LOG_INFO_MESSAGE("Shader binding table '", this->m_Desc.Name, "' is not valid: TLAS that was used to bind hit group at index '(", i,
+ ") with name '", pTLAS->GetDesc().Name, " was changed and no longer compatible with SBT");
+ return false;
+ }
+ }
+ }
+
+ bool valid = true;
+ valid = valid && FindPattern(m_RayGenShaderRecord, "ray generation");
+ valid = valid && FindPattern(m_MissShadersRecord, "miss");
+ valid = valid && FindPattern(m_CallableShadersRecord, "callable");
+ valid = valid && FindPattern(m_HitGroupsRecord, "hit groups");
+ return valid;
+#else
+ return true;
+
+#endif // DILIGENT_DEVELOPMENT
+ }
+
+
+ struct BindingTable
+ {
+ const void* pData = nullptr;
+ Uint32 Size = 0;
+ Uint32 Offset = 0;
+ Uint32 Stride = 0;
+ };
+ void GetData(IBuffer*& pSBTBuffer,
+ BindingTable& RaygenShaderBindingTable,
+ BindingTable& MissShaderBindingTable,
+ BindingTable& HitShaderBindingTable,
+ BindingTable& CallableShaderBindingTable)
+ {
+ const auto ShaderGroupBaseAlignment = this->m_pDevice->GetProperties().ShaderGroupBaseAlignment;
+
+ const auto AlignToLarger = [ShaderGroupBaseAlignment](size_t offset) -> Uint32 {
+ return Align(static_cast<Uint32>(offset), ShaderGroupBaseAlignment);
+ };
+
+ const Uint32 RayGenOffset = 0;
+ const Uint32 MissShaderOffset = AlignToLarger(m_RayGenShaderRecord.size());
+ const Uint32 HitGroupOffset = AlignToLarger(MissShaderOffset + m_MissShadersRecord.size());
+ const Uint32 CallableShadersOffset = AlignToLarger(HitGroupOffset + m_HitGroupsRecord.size());
+ const Uint32 BufSize = AlignToLarger(CallableShadersOffset + m_CallableShadersRecord.size());
+
+ // recreate buffer
+ if (this->m_pBuffer == nullptr || this->m_pBuffer->GetDesc().uiSizeInBytes < BufSize)
+ {
+ this->m_pBuffer = nullptr;
+
+ String BuffName = String{this->m_Desc.Name} + " - internal buffer";
+ BufferDesc BuffDesc;
+ BuffDesc.Name = BuffName.c_str();
+ BuffDesc.Usage = USAGE_DEFAULT;
+ BuffDesc.BindFlags = BIND_RAY_TRACING;
+ BuffDesc.uiSizeInBytes = BufSize;
+
+ this->m_pDevice->CreateBuffer(BuffDesc, nullptr, &this->m_pBuffer);
+ VERIFY_EXPR(this->m_pBuffer != nullptr);
+ }
+
+ if (this->m_pBuffer == nullptr)
+ return; // Something went wrong
+
+ pSBTBuffer = this->m_pBuffer;
+
+ if (m_RayGenShaderRecord.size())
+ {
+ RaygenShaderBindingTable.pData = this->m_Changed ? m_RayGenShaderRecord.data() : nullptr;
+ RaygenShaderBindingTable.Offset = RayGenOffset;
+ RaygenShaderBindingTable.Size = static_cast<Uint32>(m_RayGenShaderRecord.size());
+ RaygenShaderBindingTable.Stride = this->m_ShaderRecordStride;
+ }
+
+ if (m_MissShadersRecord.size())
+ {
+ MissShaderBindingTable.pData = this->m_Changed ? m_MissShadersRecord.data() : nullptr;
+ MissShaderBindingTable.Offset = MissShaderOffset;
+ MissShaderBindingTable.Size = static_cast<Uint32>(m_MissShadersRecord.size());
+ MissShaderBindingTable.Stride = this->m_ShaderRecordStride;
+ }
+
+ if (m_HitGroupsRecord.size())
+ {
+ HitShaderBindingTable.pData = this->m_Changed ? m_HitGroupsRecord.data() : nullptr;
+ HitShaderBindingTable.Offset = HitGroupOffset;
+ HitShaderBindingTable.Size = static_cast<Uint32>(m_HitGroupsRecord.size());
+ HitShaderBindingTable.Stride = this->m_ShaderRecordStride;
+ }
+
+ if (m_CallableShadersRecord.size())
+ {
+ CallableShaderBindingTable.pData = this->m_Changed ? m_CallableShadersRecord.data() : nullptr;
+ CallableShaderBindingTable.Offset = CallableShadersOffset;
+ CallableShaderBindingTable.Size = static_cast<Uint32>(m_CallableShadersRecord.size());
+ CallableShaderBindingTable.Stride = this->m_ShaderRecordStride;
+ }
+
+ if (!this->m_Changed)
+ return;
+
+ this->m_Changed = false;
+ }
+
+
+protected:
+ std::vector<Uint8> m_RayGenShaderRecord;
+ std::vector<Uint8> m_MissShadersRecord;
+ std::vector<Uint8> m_CallableShadersRecord;
+ std::vector<Uint8> m_HitGroupsRecord;
+
+ RefCntAutoPtr<PipelineStateImplType> m_pPSO;
+ RefCntAutoPtr<IBuffer> m_pBuffer;
+
+ Uint32 m_ShaderRecordSize = 0;
+ Uint32 m_ShaderRecordStride = 0;
+ bool m_Changed = true;
+
+#ifdef DILIGENT_DEVELOPMENT
+ static constexpr Uint8 EmptyElem = 0xA7;
+#else
+ // In release mode clear uninitialized data by zeros.
+ // This makes shader inactive, wich hides errors but prevents crashes.
+ static constexpr Uint8 EmptyElem = 0;
+#endif
+
+private:
+#ifdef DILIGENT_DEVELOPMENT
+ struct HitGroupBinding
+ {
+ RefCntWeakPtr<TopLevelASImplType> pTLAS;
+ Uint32 Version = ~0u;
+ bool IsBound = false;
+ };
+ mutable std::vector<HitGroupBinding> m_DbgHitGroupBindings;
+
+ void OnBindHitGroup(TopLevelASImplType* pTLAS, size_t Index)
+ {
+ this->m_DbgHitGroupBindings.resize(std::max(this->m_DbgHitGroupBindings.size(), Index + 1));
+
+ auto& Binding = this->m_DbgHitGroupBindings[Index];
+ Binding.pTLAS = pTLAS;
+ Binding.Version = pTLAS ? pTLAS->GetVersion() : ~0u;
+ Binding.IsBound = true;
+ }
+#endif
+};
+
+} // namespace Diligent
diff --git a/Graphics/GraphicsEngine/include/ShaderResourceBindingBase.hpp b/Graphics/GraphicsEngine/include/ShaderResourceBindingBase.hpp
index f9adfe40..a8725fd0 100644
--- a/Graphics/GraphicsEngine/include/ShaderResourceBindingBase.hpp
+++ b/Graphics/GraphicsEngine/include/ShaderResourceBindingBase.hpp
@@ -128,7 +128,7 @@ protected:
return ResLayoutInd;
}
- Int8 GetVariableByIndexHelper(SHADER_TYPE ShaderType, Uint32 Index, const std::array<Int8, MAX_SHADERS_IN_PIPELINE>& ResourceLayoutIndex)
+ Int8 GetVariableByIndexHelper(SHADER_TYPE ShaderType, Uint32 Index, const std::array<Int8, MAX_SHADERS_IN_PIPELINE>& ResourceLayoutIndex) const
{
const auto PipelineType = m_pPSO->GetDesc().PipelineType;
if (!IsConsistentShaderType(ShaderType, PipelineType))
diff --git a/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp b/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp
index 1130fbff..fa322e30 100644
--- a/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp
+++ b/Graphics/GraphicsEngine/include/ShaderResourceVariableBase.hpp
@@ -364,6 +364,58 @@ bool VerifyResourceViewBinding(const ResourceAttribsType& Attribs,
return BindingOK;
}
+template <typename ResourceAttribsType>
+bool VerifyTLASResourceBinding(const ResourceAttribsType& Attribs,
+ SHADER_RESOURCE_VARIABLE_TYPE VarType,
+ Uint32 ArrayIndex,
+ const ITopLevelAS* pTLAS,
+ const IDeviceObject* pCachedAS,
+ const char* ShaderName = nullptr)
+{
+ if (!pTLAS)
+ {
+ std::stringstream ss;
+ ss << "Failed to bind resource '" << pTLAS->GetDesc().Name << "' to variable '" << Attribs.GetPrintName(ArrayIndex) << '\'';
+ if (ShaderName != nullptr)
+ {
+ ss << " in shader '" << ShaderName << '\'';
+ }
+ ss << ". Invalid resource type: TLAS is expected.";
+ LOG_ERROR_MESSAGE(ss.str());
+ return false;
+ }
+
+ bool BindingOK = true;
+
+ if (VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && pCachedAS != nullptr && pCachedAS != pTLAS)
+ {
+ const auto* VarTypeStr = GetShaderVariableTypeLiteralName(VarType);
+
+ std::stringstream ss;
+ ss << "Non-null resource '" << pCachedAS->GetDesc().Name << "' is already bound to " << VarTypeStr
+ << " shader variable '" << Attribs.GetPrintName(ArrayIndex) << '\'';
+ if (ShaderName != nullptr)
+ {
+ ss << " in shader '" << ShaderName << '\'';
+ }
+ ss << ". Attempting to bind ";
+ if (pTLAS)
+ {
+ ss << "another resource ('" << pTLAS->GetDesc().Name << "')";
+ }
+ else
+ {
+ ss << "null";
+ }
+ ss << " is an error and may cause unpredicted behavior. Use another shader resource binding instance or label the variable as dynamic.";
+ LOG_ERROR_MESSAGE(ss.str());
+
+ BindingOK = false;
+ }
+
+ return BindingOK;
+}
+
inline void VerifyAndCorrectSetArrayArguments(const char* Name, Uint32 ArraySize, Uint32& FirstElement, Uint32& NumElements)
{
if (FirstElement >= ArraySize)
@@ -381,6 +433,28 @@ inline void VerifyAndCorrectSetArrayArguments(const char* Name, Uint32 ArraySize
}
}
+template <typename ShaderVectorType>
+std::string GetShaderGroupName(const ShaderVectorType& Shaders)
+{
+ std::string Name;
+ if (Shaders.size() == 1)
+ {
+ Name = Shaders[0]->GetDesc().Name;
+ }
+ else
+ {
+ Name = "{";
+ for (size_t s = 0; s < Shaders.size(); ++s)
+ {
+ if (s > 0)
+ Name += ", ";
+ Name += Shaders[s]->GetDesc().Name;
+ }
+ Name += "}";
+ }
+ return Name;
+}
+
struct DefaultShaderVariableIDComparator
{
bool operator()(const INTERFACE_ID& IID) const
diff --git a/Graphics/GraphicsEngine/include/TextureBase.hpp b/Graphics/GraphicsEngine/include/TextureBase.hpp
index 559df1ea..ddd1a378 100644
--- a/Graphics/GraphicsEngine/include/TextureBase.hpp
+++ b/Graphics/GraphicsEngine/include/TextureBase.hpp
@@ -44,9 +44,19 @@ namespace Diligent
struct CopyTextureAttribs;
-void ValidateTextureDesc(const TextureDesc& TexDesc);
+/// Validates texture description and throws an exception in case of an error.
+void ValidateTextureDesc(const TextureDesc& TexDesc) noexcept(false);
+
+/// Validates and corrects texture view description; throws an exception in case of an error.
+void ValidatedAndCorrectTextureViewDesc(const TextureDesc& TexDesc, TextureViewDesc& ViewDesc) noexcept(false);
+
+/// Validates update texture command paramters.
void ValidateUpdateTextureParams(const TextureDesc& TexDesc, Uint32 MipLevel, Uint32 Slice, const Box& DstBox, const TextureSubResData& SubresData);
+
+/// Validates copy texture command paramters.
void ValidateCopyTextureParams(const CopyTextureAttribs& CopyAttribs);
+
+/// Validates map texture command paramters.
void ValidateMapTextureParams(const TextureDesc& TexDesc,
Uint32 MipLevel,
Uint32 ArraySlice,
@@ -88,10 +98,10 @@ public:
#ifdef DILIGENT_DEBUG
m_dbgTexViewObjAllocator(TexViewObjAllocator),
#endif
- m_pDefaultSRV(nullptr, STDDeleter<TTextureViewImpl, TTexViewObjAllocator>(TexViewObjAllocator)),
- m_pDefaultRTV(nullptr, STDDeleter<TTextureViewImpl, TTexViewObjAllocator>(TexViewObjAllocator)),
- m_pDefaultDSV(nullptr, STDDeleter<TTextureViewImpl, TTexViewObjAllocator>(TexViewObjAllocator)),
- m_pDefaultUAV(nullptr, STDDeleter<TTextureViewImpl, TTexViewObjAllocator>(TexViewObjAllocator))
+ m_pDefaultSRV{nullptr, STDDeleter<TTextureViewImpl, TTexViewObjAllocator>(TexViewObjAllocator)},
+ m_pDefaultRTV{nullptr, STDDeleter<TTextureViewImpl, TTexViewObjAllocator>(TexViewObjAllocator)},
+ m_pDefaultDSV{nullptr, STDDeleter<TTextureViewImpl, TTexViewObjAllocator>(TexViewObjAllocator)},
+ m_pDefaultUAV{nullptr, STDDeleter<TTextureViewImpl, TTexViewObjAllocator>(TexViewObjAllocator)}
{
if (this->m_Desc.MipLevels == 0)
{
@@ -161,7 +171,78 @@ public:
/// - Creates default unordered access view addressing the entire texture if Diligent::BIND_UNORDERED_ACCESS flag is set.
///
/// The function calls CreateViewInternal().
- void CreateDefaultViews();
+ void CreateDefaultViews()
+ {
+ const auto& TexFmtAttribs = GetTextureFormatAttribs(this->m_Desc.Format);
+ if (TexFmtAttribs.ComponentType == COMPONENT_TYPE_UNDEFINED)
+ {
+ // Cannot create default view for TYPELESS formats
+ return;
+ }
+
+ auto CreateDefaultView = [&](TEXTURE_VIEW_TYPE ViewType) //
+ {
+ TextureViewDesc ViewDesc;
+ ViewDesc.ViewType = ViewType;
+
+ std::string ViewName;
+ switch (ViewType)
+ {
+ case TEXTURE_VIEW_SHADER_RESOURCE:
+ if ((this->m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS) != 0)
+ ViewDesc.Flags |= TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION;
+ ViewName = "Default SRV of texture '";
+ break;
+
+ case TEXTURE_VIEW_RENDER_TARGET:
+ ViewName = "Default RTV of texture '";
+ break;
+
+ case TEXTURE_VIEW_DEPTH_STENCIL:
+ ViewName = "Default DSV of texture '";
+ break;
+
+ case TEXTURE_VIEW_UNORDERED_ACCESS:
+ ViewDesc.AccessFlags = UAV_ACCESS_FLAG_READ_WRITE;
+
+ ViewName = "Default UAV of texture '";
+ break;
+
+ default:
+ UNEXPECTED("Unexpected texture type");
+ }
+ ViewName += this->m_Desc.Name;
+ ViewName += '\'';
+ ViewDesc.Name = ViewName.c_str();
+
+ ITextureView* pView = nullptr;
+ CreateViewInternal(ViewDesc, &pView, true);
+ VERIFY(pView != nullptr, "Failed to create default view for texture '", this->m_Desc.Name, "'");
+ VERIFY(pView->GetDesc().ViewType == ViewType, "Unexpected view type");
+
+ return static_cast<TTextureViewImpl*>(pView);
+ };
+
+ if (this->m_Desc.BindFlags & BIND_SHADER_RESOURCE)
+ {
+ m_pDefaultSRV.reset(CreateDefaultView(TEXTURE_VIEW_SHADER_RESOURCE));
+ }
+
+ if (this->m_Desc.BindFlags & BIND_RENDER_TARGET)
+ {
+ m_pDefaultRTV.reset(CreateDefaultView(TEXTURE_VIEW_RENDER_TARGET));
+ }
+
+ if (this->m_Desc.BindFlags & BIND_DEPTH_STENCIL)
+ {
+ m_pDefaultDSV.reset(CreateDefaultView(TEXTURE_VIEW_DEPTH_STENCIL));
+ }
+
+ if (this->m_Desc.BindFlags & BIND_UNORDERED_ACCESS)
+ {
+ m_pDefaultUAV.reset(CreateDefaultView(TEXTURE_VIEW_UNORDERED_ACCESS));
+ }
+ }
virtual void DILIGENT_CALL_TYPE SetState(RESOURCE_STATE State) override final
{
@@ -223,303 +304,7 @@ protected:
/// Default UAV addressing the entire texture
std::unique_ptr<TTextureViewImpl, STDDeleter<TTextureViewImpl, TTexViewObjAllocator>> m_pDefaultUAV;
- void CorrectTextureViewDesc(struct TextureViewDesc& ViewDesc);
-
RESOURCE_STATE m_State = RESOURCE_STATE_UNKNOWN;
};
-
-template <class BaseInterface, class TRenderDeviceImpl, class TTextureViewImpl, class TTexViewObjAllocator>
-void TextureBase<BaseInterface, TRenderDeviceImpl, TTextureViewImpl, TTexViewObjAllocator>::CorrectTextureViewDesc(struct TextureViewDesc& ViewDesc)
-{
-#define TEX_VIEW_VALIDATION_ERROR(...) LOG_ERROR_AND_THROW("\n Failed to create texture view '", (ViewDesc.Name ? ViewDesc.Name : ""), "' for texture '", this->m_Desc.Name, "': ", ##__VA_ARGS__)
-
- if (!(ViewDesc.ViewType > TEXTURE_VIEW_UNDEFINED && ViewDesc.ViewType < TEXTURE_VIEW_NUM_VIEWS))
- TEX_VIEW_VALIDATION_ERROR("Texture view type is not specified");
-
- if (ViewDesc.MostDetailedMip >= this->m_Desc.MipLevels)
- TEX_VIEW_VALIDATION_ERROR("Most detailed mip (", ViewDesc.MostDetailedMip, ") is out of range. The texture has only ", this->m_Desc.MipLevels, " mip ", (this->m_Desc.MipLevels > 1 ? "levels." : "level."));
-
- if (ViewDesc.NumMipLevels != REMAINING_MIP_LEVELS && ViewDesc.MostDetailedMip + ViewDesc.NumMipLevels > this->m_Desc.MipLevels)
- TEX_VIEW_VALIDATION_ERROR("Most detailed mip (", ViewDesc.MostDetailedMip, ") and number of mip levels in the view (", ViewDesc.NumMipLevels, ") is out of range. The texture has only ", this->m_Desc.MipLevels, " mip ", (this->m_Desc.MipLevels > 1 ? "levels." : "level."));
-
- if (ViewDesc.Format == TEX_FORMAT_UNKNOWN)
- ViewDesc.Format = GetDefaultTextureViewFormat(this->m_Desc.Format, ViewDesc.ViewType, this->m_Desc.BindFlags);
-
- if (ViewDesc.TextureDim == RESOURCE_DIM_UNDEFINED)
- {
- if (this->m_Desc.Type == RESOURCE_DIM_TEX_CUBE || this->m_Desc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY)
- {
- switch (ViewDesc.ViewType)
- {
- case TEXTURE_VIEW_SHADER_RESOURCE:
- ViewDesc.TextureDim = this->m_Desc.Type;
- break;
-
- case TEXTURE_VIEW_RENDER_TARGET:
- case TEXTURE_VIEW_DEPTH_STENCIL:
- case TEXTURE_VIEW_UNORDERED_ACCESS:
- ViewDesc.TextureDim = RESOURCE_DIM_TEX_2D_ARRAY;
- break;
-
- default: UNEXPECTED("Unexpected view type");
- }
- }
- else
- {
- ViewDesc.TextureDim = this->m_Desc.Type;
- }
- }
-
- switch (this->m_Desc.Type)
- {
- case RESOURCE_DIM_TEX_1D:
- if (ViewDesc.TextureDim != RESOURCE_DIM_TEX_1D)
- {
- TEX_VIEW_VALIDATION_ERROR("Incorrect texture type for Texture 1D view: only Texture 1D is allowed");
- }
- break;
-
- case RESOURCE_DIM_TEX_1D_ARRAY:
- if (ViewDesc.TextureDim != RESOURCE_DIM_TEX_1D_ARRAY &&
- ViewDesc.TextureDim != RESOURCE_DIM_TEX_1D)
- {
- TEX_VIEW_VALIDATION_ERROR("Incorrect view type for Texture 1D Array: only Texture 1D or Texture 1D Array are allowed");
- }
- break;
-
- case RESOURCE_DIM_TEX_2D:
- if (ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D_ARRAY &&
- ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D)
- {
- TEX_VIEW_VALIDATION_ERROR("Incorrect texture type for Texture 2D view: only Texture 2D or Texture 2D Array are allowed");
- }
- break;
-
- case RESOURCE_DIM_TEX_2D_ARRAY:
- if (ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D_ARRAY &&
- ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D)
- {
- TEX_VIEW_VALIDATION_ERROR("Incorrect texture type for Texture 2D Array view: only Texture 2D or Texture 2D Array are allowed");
- }
- break;
-
- case RESOURCE_DIM_TEX_3D:
- if (ViewDesc.TextureDim != RESOURCE_DIM_TEX_3D)
- {
- TEX_VIEW_VALIDATION_ERROR("Incorrect texture type for Texture 3D view: only Texture 3D is allowed");
- }
- break;
-
- case RESOURCE_DIM_TEX_CUBE:
- if (ViewDesc.ViewType == TEXTURE_VIEW_SHADER_RESOURCE)
- {
- if (ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D &&
- ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D_ARRAY &&
- ViewDesc.TextureDim != RESOURCE_DIM_TEX_CUBE)
- {
- TEX_VIEW_VALIDATION_ERROR("Incorrect texture type for Texture cube SRV: Texture 2D, Texture 2D array or Texture Cube is allowed");
- }
- }
- else
- {
- if (ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D &&
- ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D_ARRAY)
- {
- TEX_VIEW_VALIDATION_ERROR("Incorrect texture type for Texture cube non-shader resource view: Texture 2D or Texture 2D array is allowed");
- }
- }
- break;
-
- case RESOURCE_DIM_TEX_CUBE_ARRAY:
- if (ViewDesc.ViewType == TEXTURE_VIEW_SHADER_RESOURCE)
- {
- if (ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D &&
- ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D_ARRAY &&
- ViewDesc.TextureDim != RESOURCE_DIM_TEX_CUBE &&
- ViewDesc.TextureDim != RESOURCE_DIM_TEX_CUBE_ARRAY)
- {
- TEX_VIEW_VALIDATION_ERROR("Incorrect texture type for Texture cube array SRV: Texture 2D, Texture 2D array, Texture Cube or Texture Cube Array is allowed");
- }
- }
- else
- {
- if (ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D &&
- ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D_ARRAY)
- {
- TEX_VIEW_VALIDATION_ERROR("Incorrect texture type for Texture cube array non-shader resource view: Texture 2D or Texture 2D array is allowed");
- }
- }
- break;
-
- default:
- UNEXPECTED("Unexpected texture type");
- break;
- }
-
- if (ViewDesc.TextureDim == RESOURCE_DIM_TEX_CUBE)
- {
- if (ViewDesc.ViewType != TEXTURE_VIEW_SHADER_RESOURCE)
- TEX_VIEW_VALIDATION_ERROR("Unexpected view type: SRV is expected");
- if (ViewDesc.NumArraySlices != 6 && ViewDesc.NumArraySlices != 0 && ViewDesc.NumArraySlices != REMAINING_ARRAY_SLICES)
- TEX_VIEW_VALIDATION_ERROR("Texture cube SRV is expected to have 6 array slices, while ", ViewDesc.NumArraySlices, " is provided");
- if (ViewDesc.FirstArraySlice != 0)
- TEX_VIEW_VALIDATION_ERROR("First slice (", ViewDesc.FirstArraySlice, ") must be 0 for non-array texture cube SRV");
- }
- if (ViewDesc.TextureDim == RESOURCE_DIM_TEX_CUBE_ARRAY)
- {
- if (ViewDesc.ViewType != TEXTURE_VIEW_SHADER_RESOURCE)
- TEX_VIEW_VALIDATION_ERROR("Unexpected view type: SRV is expected");
- if (ViewDesc.NumArraySlices != REMAINING_ARRAY_SLICES && (ViewDesc.NumArraySlices % 6) != 0)
- TEX_VIEW_VALIDATION_ERROR("Number of slices in texture cube array SRV is expected to be multiple of 6. ", ViewDesc.NumArraySlices, " slices is provided.");
- }
-
- if (ViewDesc.TextureDim == RESOURCE_DIM_TEX_1D ||
- ViewDesc.TextureDim == RESOURCE_DIM_TEX_2D)
- {
- if (ViewDesc.FirstArraySlice != 0)
- TEX_VIEW_VALIDATION_ERROR("First slice (", ViewDesc.FirstArraySlice, ") must be 0 for non-array texture 1D/2D views");
-
- if (ViewDesc.NumArraySlices != REMAINING_ARRAY_SLICES && ViewDesc.NumArraySlices > 1)
- TEX_VIEW_VALIDATION_ERROR("Number of slices in the view (", ViewDesc.NumArraySlices, ") must be 1 (or 0) for non-array texture 1D/2D views");
- }
- else if (ViewDesc.TextureDim == RESOURCE_DIM_TEX_1D_ARRAY ||
- ViewDesc.TextureDim == RESOURCE_DIM_TEX_2D_ARRAY ||
- ViewDesc.TextureDim == RESOURCE_DIM_TEX_CUBE ||
- ViewDesc.TextureDim == RESOURCE_DIM_TEX_CUBE_ARRAY)
- {
- if (ViewDesc.FirstArraySlice >= this->m_Desc.ArraySize)
- TEX_VIEW_VALIDATION_ERROR("First array slice (", ViewDesc.FirstArraySlice, ") exceeds the number of slices in the texture array (", this->m_Desc.ArraySize, ")");
-
- if (ViewDesc.NumArraySlices != REMAINING_ARRAY_SLICES && ViewDesc.FirstArraySlice + ViewDesc.NumArraySlices > this->m_Desc.ArraySize)
- TEX_VIEW_VALIDATION_ERROR("First slice (", ViewDesc.FirstArraySlice, ") and number of slices in the view (", ViewDesc.NumArraySlices, ") specify more slices than target texture has (", this->m_Desc.ArraySize, ")");
- }
- else if (ViewDesc.TextureDim == RESOURCE_DIM_TEX_3D)
- {
- auto MipDepth = this->m_Desc.Depth >> ViewDesc.MostDetailedMip;
- if (ViewDesc.FirstDepthSlice + ViewDesc.NumDepthSlices > MipDepth)
- TEX_VIEW_VALIDATION_ERROR("First slice (", ViewDesc.FirstDepthSlice, ") and number of slices in the view (", ViewDesc.NumDepthSlices, ") specify more slices than target 3D texture mip level has (", MipDepth, ")");
- }
- else
- {
- UNEXPECTED("Unexpected texture dimension");
- }
-
- if (GetTextureFormatAttribs(ViewDesc.Format).IsTypeless)
- {
- TEX_VIEW_VALIDATION_ERROR("Texture view format (", GetTextureFormatAttribs(ViewDesc.Format).Name, ") cannot be typeless");
- }
-
- if ((ViewDesc.Flags & TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION) != 0)
- {
- if ((this->m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS) == 0)
- TEX_VIEW_VALIDATION_ERROR("TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION flag can only set if the texture was created with MISC_TEXTURE_FLAG_GENERATE_MIPS flag");
-
- if (ViewDesc.ViewType != TEXTURE_VIEW_SHADER_RESOURCE)
- TEX_VIEW_VALIDATION_ERROR("TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION flag can only be used with TEXTURE_VIEW_SHADER_RESOURCE view type");
- }
-
-#undef TEX_VIEW_VALIDATION_ERROR
-
- if (ViewDesc.NumMipLevels == 0 || ViewDesc.NumMipLevels == REMAINING_MIP_LEVELS)
- {
- if (ViewDesc.ViewType == TEXTURE_VIEW_SHADER_RESOURCE)
- ViewDesc.NumMipLevels = this->m_Desc.MipLevels - ViewDesc.MostDetailedMip;
- else
- ViewDesc.NumMipLevels = 1;
- }
-
- if (ViewDesc.NumArraySlices == 0 || ViewDesc.NumArraySlices == REMAINING_ARRAY_SLICES)
- {
- if (ViewDesc.TextureDim == RESOURCE_DIM_TEX_1D_ARRAY ||
- ViewDesc.TextureDim == RESOURCE_DIM_TEX_2D_ARRAY ||
- ViewDesc.TextureDim == RESOURCE_DIM_TEX_CUBE ||
- ViewDesc.TextureDim == RESOURCE_DIM_TEX_CUBE_ARRAY)
- ViewDesc.NumArraySlices = this->m_Desc.ArraySize - ViewDesc.FirstArraySlice;
- else if (ViewDesc.TextureDim == RESOURCE_DIM_TEX_3D)
- {
- auto MipDepth = this->m_Desc.Depth >> ViewDesc.MostDetailedMip;
- ViewDesc.NumDepthSlices = MipDepth - ViewDesc.FirstDepthSlice;
- }
- else
- ViewDesc.NumArraySlices = 1;
- }
-
- if ((ViewDesc.ViewType == TEXTURE_VIEW_RENDER_TARGET) &&
- (ViewDesc.Format == TEX_FORMAT_R8_SNORM || ViewDesc.Format == TEX_FORMAT_RG8_SNORM || ViewDesc.Format == TEX_FORMAT_RGBA8_SNORM ||
- ViewDesc.Format == TEX_FORMAT_R16_SNORM || ViewDesc.Format == TEX_FORMAT_RG16_SNORM || ViewDesc.Format == TEX_FORMAT_RGBA16_SNORM))
- {
- const auto* FmtName = GetTextureFormatAttribs(ViewDesc.Format).Name;
- LOG_WARNING_MESSAGE(FmtName, " render target view is created.\n"
- "There might be an issue in OpenGL driver on NVidia hardware: when rendering to SNORM textures, all negative values are clamped to zero.\n"
- "Use UNORM format instead.");
- }
-}
-
-template <class BaseInterface, class TRenderDeviceImpl, class TTextureViewImpl, class TTexViewObjAllocator>
-void TextureBase<BaseInterface, TRenderDeviceImpl, TTextureViewImpl, TTexViewObjAllocator>::CreateDefaultViews()
-{
- const auto& TexFmtAttribs = GetTextureFormatAttribs(this->m_Desc.Format);
- if (TexFmtAttribs.ComponentType == COMPONENT_TYPE_UNDEFINED)
- {
- // Cannot create default view for TYPELESS formats
- return;
- }
-
- if (this->m_Desc.BindFlags & BIND_SHADER_RESOURCE)
- {
- TextureViewDesc ViewDesc;
- ViewDesc.ViewType = TEXTURE_VIEW_SHADER_RESOURCE;
- auto ViewName = FormatString("Default SRV of texture '", this->m_Desc.Name, "'");
- ViewDesc.Name = ViewName.c_str();
-
- ITextureView* pSRV = nullptr;
- if ((this->m_Desc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS) != 0)
- ViewDesc.Flags |= TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION;
- CreateViewInternal(ViewDesc, &pSRV, true);
- m_pDefaultSRV.reset(static_cast<TTextureViewImpl*>(pSRV));
- VERIFY(m_pDefaultSRV->GetDesc().ViewType == TEXTURE_VIEW_SHADER_RESOURCE, "Unexpected view type");
- }
-
- if (this->m_Desc.BindFlags & BIND_RENDER_TARGET)
- {
- TextureViewDesc ViewDesc;
- ViewDesc.ViewType = TEXTURE_VIEW_RENDER_TARGET;
- auto ViewName = FormatString("Default RTV of texture '", this->m_Desc.Name, "'");
- ViewDesc.Name = ViewName.c_str();
-
- ITextureView* pRTV = nullptr;
- CreateViewInternal(ViewDesc, &pRTV, true);
- m_pDefaultRTV.reset(static_cast<TTextureViewImpl*>(pRTV));
- VERIFY(m_pDefaultRTV->GetDesc().ViewType == TEXTURE_VIEW_RENDER_TARGET, "Unexpected view type");
- }
-
- if (this->m_Desc.BindFlags & BIND_DEPTH_STENCIL)
- {
- TextureViewDesc ViewDesc;
- ViewDesc.ViewType = TEXTURE_VIEW_DEPTH_STENCIL;
- auto ViewName = FormatString("Default DSV of texture '", this->m_Desc.Name, "'");
- ViewDesc.Name = ViewName.c_str();
-
- ITextureView* pDSV = nullptr;
- CreateViewInternal(ViewDesc, &pDSV, true);
- m_pDefaultDSV.reset(static_cast<TTextureViewImpl*>(pDSV));
- VERIFY(m_pDefaultDSV->GetDesc().ViewType == TEXTURE_VIEW_DEPTH_STENCIL, "Unexpected view type");
- }
-
- if (this->m_Desc.BindFlags & BIND_UNORDERED_ACCESS)
- {
- TextureViewDesc ViewDesc;
- ViewDesc.ViewType = TEXTURE_VIEW_UNORDERED_ACCESS;
- auto ViewName = FormatString("Default UAV of texture '", this->m_Desc.Name, "'");
- ViewDesc.Name = ViewName.c_str();
-
- ViewDesc.AccessFlags = UAV_ACCESS_FLAG_READ_WRITE;
- ITextureView* pUAV = nullptr;
- CreateViewInternal(ViewDesc, &pUAV, true);
- m_pDefaultUAV.reset(static_cast<TTextureViewImpl*>(pUAV));
- VERIFY(m_pDefaultUAV->GetDesc().ViewType == TEXTURE_VIEW_UNORDERED_ACCESS, "Unexpected view type");
- }
-}
-
} // namespace Diligent
diff --git a/Graphics/GraphicsEngine/include/TopLevelASBase.hpp b/Graphics/GraphicsEngine/include/TopLevelASBase.hpp
new file mode 100644
index 00000000..c1b73ebc
--- /dev/null
+++ b/Graphics/GraphicsEngine/include/TopLevelASBase.hpp
@@ -0,0 +1,385 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Implementation of the Diligent::TopLevelASBase template class
+
+#include <unordered_map>
+#include <atomic>
+
+#include "TopLevelAS.h"
+#include "BottomLevelASBase.hpp"
+#include "DeviceObjectBase.hpp"
+#include "RenderDeviceBase.hpp"
+#include "StringPool.hpp"
+#include "HashUtils.hpp"
+
+namespace Diligent
+{
+
+/// Validates top-level AS description and throws an exception in case of an error.
+void ValidateTopLevelASDesc(const TopLevelASDesc& Desc) noexcept(false);
+
+/// Template class implementing base functionality for a top-level acceleration structure object.
+
+/// \tparam BaseInterface - base interface that this class will inheret
+/// (Diligent::ITopLevelASD3D12 or Diligent::ITopLevelASVk).
+/// \tparam RenderDeviceImplType - type of the render device implementation
+/// (Diligent::RenderDeviceD3D12Impl or Diligent::RenderDeviceVkImpl)
+template <class BaseInterface, class BottomLevelASType, class RenderDeviceImplType>
+class TopLevelASBase : public DeviceObjectBase<BaseInterface, RenderDeviceImplType, TopLevelASDesc>
+{
+private:
+ struct InstanceDesc
+ {
+ Uint32 ContributionToHitGroupIndex = 0;
+ Uint32 InstanceIndex = 0;
+ RefCntAutoPtr<BottomLevelASType> pBLAS;
+#ifdef DILIGENT_DEVELOPMENT
+ Uint32 Version = 0;
+#endif
+ };
+
+public:
+ using TDeviceObjectBase = DeviceObjectBase<BaseInterface, RenderDeviceImplType, TopLevelASDesc>;
+
+ /// \param pRefCounters - reference counters object that controls the lifetime of this BLAS.
+ /// \param pDevice - pointer to the device.
+ /// \param Desc - TLAS description.
+ /// \param bIsDeviceInternal - flag indicating if the BLAS is an internal device object and
+ /// must not keep a strong reference to the device.
+ TopLevelASBase(IReferenceCounters* pRefCounters,
+ RenderDeviceImplType* pDevice,
+ const TopLevelASDesc& Desc,
+ bool bIsDeviceInternal = false) :
+ TDeviceObjectBase{pRefCounters, pDevice, Desc, bIsDeviceInternal}
+ {
+ ValidateTopLevelASDesc(this->m_Desc);
+ }
+
+ ~TopLevelASBase()
+ {
+ }
+
+ IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_TopLevelAS, TDeviceObjectBase)
+
+ bool SetInstanceData(const TLASBuildInstanceData* pInstances,
+ const Uint32 InstanceCount,
+ const Uint32 BaseContributionToHitGroupIndex,
+ const Uint32 HitGroupStride,
+ const HIT_GROUP_BINDING_MODE BindingMode) noexcept
+ {
+ try
+ {
+ ClearInstanceData();
+
+ size_t StringPoolSize = 0;
+ for (Uint32 i = 0; i < InstanceCount; ++i)
+ {
+ VERIFY_EXPR(pInstances[i].InstanceName != nullptr);
+ StringPoolSize += StringPool::GetRequiredReserveSize(pInstances[i].InstanceName);
+ }
+
+ this->m_StringPool.Reserve(StringPoolSize, GetRawAllocator());
+
+ Uint32 InstanceOffset = BaseContributionToHitGroupIndex;
+
+ for (Uint32 i = 0; i < InstanceCount; ++i)
+ {
+ const auto& Inst = pInstances[i];
+ const char* NameCopy = this->m_StringPool.CopyString(Inst.InstanceName);
+ InstanceDesc Desc = {};
+
+ Desc.pBLAS = ValidatedCast<BottomLevelASType>(Inst.pBLAS);
+ Desc.ContributionToHitGroupIndex = Inst.ContributionToHitGroupIndex;
+ Desc.InstanceIndex = i;
+ CalculateHitGroupIndex(Desc, InstanceOffset, HitGroupStride, BindingMode);
+
+#ifdef DILIGENT_DEVELOPMENT
+ Desc.Version = Desc.pBLAS->GetVersion();
+#endif
+ bool IsUniqueName = this->m_Instances.emplace(NameCopy, Desc).second;
+ if (!IsUniqueName)
+ LOG_ERROR_AND_THROW("Instance name must be unique!");
+ }
+
+ VERIFY_EXPR(this->m_StringPool.GetRemainingSize() == 0);
+
+ InstanceOffset = InstanceOffset + (BindingMode == HIT_GROUP_BINDING_MODE_PER_ACCEL_STRUCT ? HitGroupStride : 0) - 1;
+
+ this->m_BuildInfo.HitGroupStride = HitGroupStride;
+ this->m_BuildInfo.FirstContributionToHitGroupIndex = BaseContributionToHitGroupIndex;
+ this->m_BuildInfo.LastContributionToHitGroupIndex = InstanceOffset;
+ this->m_BuildInfo.BindingMode = BindingMode;
+ this->m_BuildInfo.InstanceCount = InstanceCount;
+
+#ifdef DILIGENT_DEVELOPMENT
+ this->m_DbgVersion.fetch_add(1);
+#endif
+ return true;
+ }
+ catch (...)
+ {
+#ifdef DILIGENT_DEVELOPMENT
+ this->m_DbgVersion.fetch_add(1);
+#endif
+ ClearInstanceData();
+ return false;
+ }
+ }
+
+ bool UpdateInstances(const TLASBuildInstanceData* pInstances,
+ const Uint32 InstanceCount,
+ const Uint32 BaseContributionToHitGroupIndex,
+ const Uint32 HitGroupStride,
+ const HIT_GROUP_BINDING_MODE BindingMode) noexcept
+ {
+ VERIFY_EXPR(this->m_BuildInfo.InstanceCount == InstanceCount);
+#ifdef DILIGENT_DEVELOPMENT
+ bool Changed = false;
+#endif
+ Uint32 InstanceOffset = BaseContributionToHitGroupIndex;
+
+ for (Uint32 i = 0; i < InstanceCount; ++i)
+ {
+ const auto& Inst = pInstances[i];
+ auto Iter = this->m_Instances.find(Inst.InstanceName);
+
+ if (Iter == this->m_Instances.end())
+ {
+ UNEXPECTED("Failed to find instance with name '", Inst.InstanceName, "' in instances from the previous build");
+ return false;
+ }
+
+ auto& Desc = Iter->second;
+ const auto PrevIndex = Desc.ContributionToHitGroupIndex;
+ const auto pPrevBLAS = Desc.pBLAS;
+
+ Desc.pBLAS = ValidatedCast<BottomLevelASType>(Inst.pBLAS);
+ Desc.ContributionToHitGroupIndex = Inst.ContributionToHitGroupIndex;
+ //Desc.InstanceIndex = i; // keep Desc.InstanceIndex unmodified
+ CalculateHitGroupIndex(Desc, InstanceOffset, HitGroupStride, BindingMode);
+
+#ifdef DILIGENT_DEVELOPMENT
+ Changed = Changed || (pPrevBLAS != Desc.pBLAS);
+ Changed = Changed || (PrevIndex != Desc.ContributionToHitGroupIndex);
+ Desc.Version = Desc.pBLAS->GetVersion();
+#endif
+ }
+
+ InstanceOffset = InstanceOffset + (BindingMode == HIT_GROUP_BINDING_MODE_PER_ACCEL_STRUCT ? HitGroupStride : 0) - 1;
+
+#ifdef DILIGENT_DEVELOPMENT
+ Changed = Changed || (this->m_BuildInfo.HitGroupStride != HitGroupStride);
+ Changed = Changed || (this->m_BuildInfo.FirstContributionToHitGroupIndex != BaseContributionToHitGroupIndex);
+ Changed = Changed || (this->m_BuildInfo.LastContributionToHitGroupIndex != InstanceOffset);
+ Changed = Changed || (this->m_BuildInfo.BindingMode != BindingMode);
+ if (Changed)
+ this->m_DbgVersion.fetch_add(1);
+#endif
+ this->m_BuildInfo.HitGroupStride = HitGroupStride;
+ this->m_BuildInfo.FirstContributionToHitGroupIndex = BaseContributionToHitGroupIndex;
+ this->m_BuildInfo.LastContributionToHitGroupIndex = InstanceOffset;
+ this->m_BuildInfo.BindingMode = BindingMode;
+
+ return true;
+ }
+
+ void CopyInstancceData(const TopLevelASBase& Src) noexcept
+ {
+ ClearInstanceData();
+
+ this->m_StringPool.Reserve(Src.m_StringPool.GetReservedSize(), GetRawAllocator());
+ this->m_BuildInfo = Src.m_BuildInfo;
+
+ for (auto& SrcInst : Src.m_Instances)
+ {
+ const char* NameCopy = this->m_StringPool.CopyString(SrcInst.first.GetStr());
+ this->m_Instances.emplace(NameCopy, SrcInst.second);
+ }
+
+ VERIFY_EXPR(this->m_StringPool.GetRemainingSize() == 0);
+
+#ifdef DILIGENT_DEVELOPMENT
+ this->m_DbgVersion.fetch_add(1);
+#endif
+ }
+
+ virtual TLASInstanceDesc DILIGENT_CALL_TYPE GetInstanceDesc(const char* Name) const override final
+ {
+ VERIFY_EXPR(Name != nullptr && Name[0] != '\0');
+
+ TLASInstanceDesc Result = {};
+
+ auto Iter = this->m_Instances.find(Name);
+ if (Iter != this->m_Instances.end())
+ {
+ const auto& Inst = Iter->second;
+ Result.ContributionToHitGroupIndex = Inst.ContributionToHitGroupIndex;
+ Result.InstanceIndex = Inst.InstanceIndex;
+ Result.pBLAS = Inst.pBLAS.template RawPtr<IBottomLevelAS>();
+ }
+ else
+ {
+ Result.ContributionToHitGroupIndex = INVALID_INDEX;
+ Result.InstanceIndex = INVALID_INDEX;
+ LOG_ERROR_MESSAGE("Can't find instance with the specified name ('", Name, "')");
+ }
+
+ return Result;
+ }
+
+ virtual TLASBuildInfo DILIGENT_CALL_TYPE GetBuildInfo() const override final
+ {
+ return m_BuildInfo;
+ }
+
+ virtual void DILIGENT_CALL_TYPE SetState(RESOURCE_STATE State) override final
+ {
+ VERIFY(State == RESOURCE_STATE_UNKNOWN || State == RESOURCE_STATE_BUILD_AS_READ || State == RESOURCE_STATE_BUILD_AS_WRITE || State == RESOURCE_STATE_RAY_TRACING,
+ "Unsupported state for top-level acceleration structure");
+ this->m_State = State;
+ }
+
+ virtual RESOURCE_STATE DILIGENT_CALL_TYPE GetState() const override final
+ {
+ return this->m_State;
+ }
+
+ /// Implementation of ITopLevelAS::GetScratchBufferSizes().
+ virtual ScratchBufferSizes DILIGENT_CALL_TYPE GetScratchBufferSizes() const override final
+ {
+ return this->m_ScratchSize;
+ }
+
+ bool IsInKnownState() const
+ {
+ return this->m_State != RESOURCE_STATE_UNKNOWN;
+ }
+
+ bool CheckState(RESOURCE_STATE State) const
+ {
+ VERIFY((State & (State - 1)) == 0, "Single state is expected");
+ VERIFY(IsInKnownState(), "TLAS state is unknown");
+ return (this->m_State & State) == State;
+ }
+
+#ifdef DILIGENT_DEVELOPMENT
+ bool ValidateContent() const
+ {
+ bool result = true;
+
+ if (this->m_Instances.empty())
+ {
+ LOG_ERROR_MESSAGE("TLAS with name ('", this->m_Desc.Name, "') doesn't have instances, use IDeviceContext::BuildTLAS() or IDeviceContext::CopyTLAS() to initialize TLAS content");
+ result = false;
+ }
+
+ // Validate instances
+ for (const auto& NameAndInst : this->m_Instances)
+ {
+ const InstanceDesc& Inst = NameAndInst.second;
+
+ if (Inst.Version != Inst.pBLAS->GetVersion())
+ {
+ LOG_ERROR_MESSAGE("Instance with name ('", NameAndInst.first.GetStr(), "') has BLAS with name ('", Inst.pBLAS->GetDesc().Name,
+ "') that was changed after TLAS build, you must rebuild TLAS");
+ result = false;
+ }
+
+ if (Inst.pBLAS->IsInKnownState() && Inst.pBLAS->GetState() != RESOURCE_STATE_BUILD_AS_READ)
+ {
+ LOG_ERROR_MESSAGE("Instance with name ('", NameAndInst.first.GetStr(), "') has BLAS with name ('", Inst.pBLAS->GetDesc().Name,
+ "') that must be in BUILD_AS_READ state, but current state is ",
+ GetResourceStateFlagString(Inst.pBLAS->GetState()));
+ result = false;
+ }
+ }
+ return result;
+ }
+
+ Uint32 GetVersion() const
+ {
+ return this->m_DbgVersion.load();
+ }
+#endif // DILIGENT_DEVELOPMENT
+
+private:
+ void ClearInstanceData()
+ {
+ this->m_Instances.clear();
+ this->m_StringPool.Clear();
+
+ this->m_BuildInfo.BindingMode = HIT_GROUP_BINDING_MODE_LAST;
+ this->m_BuildInfo.HitGroupStride = 0;
+ this->m_BuildInfo.FirstContributionToHitGroupIndex = INVALID_INDEX;
+ this->m_BuildInfo.LastContributionToHitGroupIndex = INVALID_INDEX;
+ }
+
+ static void CalculateHitGroupIndex(InstanceDesc& Desc, Uint32& InstanceOffset, const Uint32 HitGroupStride, const HIT_GROUP_BINDING_MODE BindingMode)
+ {
+ static_assert(HIT_GROUP_BINDING_MODE_LAST == HIT_GROUP_BINDING_MODE_USER_DEFINED, "Please update the switch below to handle the new shader binding mode");
+
+ if (Desc.ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO)
+ {
+ Desc.ContributionToHitGroupIndex = InstanceOffset;
+ switch (BindingMode)
+ {
+ // clang-format off
+ case HIT_GROUP_BINDING_MODE_PER_GEOMETRY: InstanceOffset += Desc.pBLAS->GetActualGeometryCount() * HitGroupStride; break;
+ case HIT_GROUP_BINDING_MODE_PER_INSTANCE: InstanceOffset += HitGroupStride; break;
+ case HIT_GROUP_BINDING_MODE_PER_ACCEL_STRUCT: /* InstanceOffset is a constant */ break;
+ case HIT_GROUP_BINDING_MODE_USER_DEFINED: UNEXPECTED("TLAS_INSTANCE_OFFSET_AUTO is not compatible with HIT_GROUP_BINDING_MODE_USER_DEFINED"); break;
+ default: UNEXPECTED("Unknown ray tracing shader binding mode");
+ // clang-format on
+ }
+ }
+ else
+ {
+ VERIFY(BindingMode == HIT_GROUP_BINDING_MODE_USER_DEFINED, "BindingMode must be HIT_GROUP_BINDING_MODE_USER_DEFINED");
+ }
+
+ constexpr Uint32 MaxIndex = (1u << 24);
+ VERIFY(Desc.ContributionToHitGroupIndex < MaxIndex, "ContributionToHitGroupIndex must be less than ", MaxIndex);
+ }
+
+protected:
+ RESOURCE_STATE m_State = RESOURCE_STATE_UNKNOWN;
+ TLASBuildInfo m_BuildInfo;
+ ScratchBufferSizes m_ScratchSize;
+
+ std::unordered_map<HashMapStringKey, InstanceDesc, HashMapStringKey::Hasher> m_Instances;
+ StringPool m_StringPool;
+
+#ifdef DILIGENT_DEVELOPMENT
+ std::atomic<Uint32> m_DbgVersion{0};
+#endif
+};
+
+} // namespace Diligent
diff --git a/Graphics/GraphicsEngine/interface/APIInfo.h b/Graphics/GraphicsEngine/interface/APIInfo.h
index 608c6fe3..3ade31f3 100644
--- a/Graphics/GraphicsEngine/interface/APIInfo.h
+++ b/Graphics/GraphicsEngine/interface/APIInfo.h
@@ -39,65 +39,67 @@ DILIGENT_BEGIN_NAMESPACE(Diligent)
/// Diligent API Info. This tructure can be used to verify API compatibility.
struct APIInfo
{
- size_t StructSize DEFAULT_INITIALIZER(0);
- int APIVersion DEFAULT_INITIALIZER(0);
- size_t RenderTargetBlendDescSize DEFAULT_INITIALIZER(0);
- size_t BlendStateDescSize DEFAULT_INITIALIZER(0);
- size_t BufferDescSize DEFAULT_INITIALIZER(0);
- size_t BufferDataSize DEFAULT_INITIALIZER(0);
- size_t BufferFormatSize DEFAULT_INITIALIZER(0);
- size_t BufferViewDescSize DEFAULT_INITIALIZER(0);
- size_t StencilOpDescSize DEFAULT_INITIALIZER(0);
- size_t DepthStencilStateDescSize DEFAULT_INITIALIZER(0);
- size_t SamplerCapsSize DEFAULT_INITIALIZER(0);
- size_t TextureCapsSize DEFAULT_INITIALIZER(0);
- size_t DeviceCapsSize DEFAULT_INITIALIZER(0);
- size_t DrawAttribsSize DEFAULT_INITIALIZER(0);
- size_t DispatchComputeAttribsSize DEFAULT_INITIALIZER(0);
- size_t ViewportSize DEFAULT_INITIALIZER(0);
- size_t RectSize DEFAULT_INITIALIZER(0);
- size_t CopyTextureAttribsSize DEFAULT_INITIALIZER(0);
- size_t DeviceObjectAttribsSize DEFAULT_INITIALIZER(0);
- size_t GraphicsAdapterInfoSize DEFAULT_INITIALIZER(0);
- size_t DisplayModeAttribsSize DEFAULT_INITIALIZER(0);
- size_t SwapChainDescSize DEFAULT_INITIALIZER(0);
- size_t FullScreenModeDescSize DEFAULT_INITIALIZER(0);
- size_t EngineCreateInfoSize DEFAULT_INITIALIZER(0);
- size_t EngineGLCreateInfoSize DEFAULT_INITIALIZER(0);
- size_t EngineD3D11CreateInfoSize DEFAULT_INITIALIZER(0);
- size_t EngineD3D12CreateInfoSize DEFAULT_INITIALIZER(0);
- size_t EngineVkCreateInfoSize DEFAULT_INITIALIZER(0);
- size_t EngineMtlCreateInfoSize DEFAULT_INITIALIZER(0);
- size_t BoxSize DEFAULT_INITIALIZER(0);
- size_t TextureFormatAttribsSize DEFAULT_INITIALIZER(0);
- size_t TextureFormatInfoSize DEFAULT_INITIALIZER(0);
- size_t TextureFormatInfoExtSize DEFAULT_INITIALIZER(0);
- size_t StateTransitionDescSize DEFAULT_INITIALIZER(0);
- size_t LayoutElementSize DEFAULT_INITIALIZER(0);
- size_t InputLayoutDescSize DEFAULT_INITIALIZER(0);
- size_t SampleDescSize DEFAULT_INITIALIZER(0);
- size_t ShaderResourceVariableDescSize DEFAULT_INITIALIZER(0);
- size_t ImmutableSamplerDescSize DEFAULT_INITIALIZER(0);
- size_t PipelineResourceLayoutDescSize DEFAULT_INITIALIZER(0);
- size_t GraphicsPipelineDescSize DEFAULT_INITIALIZER(0);
- size_t GraphicsPipelineStateCreateInfoSize DEFAULT_INITIALIZER(0);
- size_t ComputePipelineStateCreateInfoSize DEFAULT_INITIALIZER(0);
- size_t PipelineStateDescSize DEFAULT_INITIALIZER(0);
- size_t RasterizerStateDescSize DEFAULT_INITIALIZER(0);
- size_t ResourceMappingEntrySize DEFAULT_INITIALIZER(0);
- size_t ResourceMappingDescSize DEFAULT_INITIALIZER(0);
- size_t SamplerDescSize DEFAULT_INITIALIZER(0);
- size_t ShaderDescSize DEFAULT_INITIALIZER(0);
- size_t ShaderMacroSize DEFAULT_INITIALIZER(0);
- size_t ShaderCreateInfoSize DEFAULT_INITIALIZER(0);
- size_t ShaderResourceDescSize DEFAULT_INITIALIZER(0);
- size_t DepthStencilClearValueSize DEFAULT_INITIALIZER(0);
- size_t OptimizedClearValueSize DEFAULT_INITIALIZER(0);
- size_t TextureDescSize DEFAULT_INITIALIZER(0);
- size_t TextureSubResDataSize DEFAULT_INITIALIZER(0);
- size_t TextureDataSize DEFAULT_INITIALIZER(0);
- size_t MappedTextureSubresourceSize DEFAULT_INITIALIZER(0);
- size_t TextureViewDescSize DEFAULT_INITIALIZER(0);
+ size_t StructSize DEFAULT_INITIALIZER(0);
+ int APIVersion DEFAULT_INITIALIZER(0);
+ size_t RenderTargetBlendDescSize DEFAULT_INITIALIZER(0);
+ size_t BlendStateDescSize DEFAULT_INITIALIZER(0);
+ size_t BufferDescSize DEFAULT_INITIALIZER(0);
+ size_t BufferDataSize DEFAULT_INITIALIZER(0);
+ size_t BufferFormatSize DEFAULT_INITIALIZER(0);
+ size_t BufferViewDescSize DEFAULT_INITIALIZER(0);
+ size_t StencilOpDescSize DEFAULT_INITIALIZER(0);
+ size_t DepthStencilStateDescSize DEFAULT_INITIALIZER(0);
+ size_t SamplerCapsSize DEFAULT_INITIALIZER(0);
+ size_t TextureCapsSize DEFAULT_INITIALIZER(0);
+ size_t DeviceCapsSize DEFAULT_INITIALIZER(0);
+ size_t DrawAttribsSize DEFAULT_INITIALIZER(0);
+ size_t DispatchComputeAttribsSize DEFAULT_INITIALIZER(0);
+ size_t ViewportSize DEFAULT_INITIALIZER(0);
+ size_t RectSize DEFAULT_INITIALIZER(0);
+ size_t CopyTextureAttribsSize DEFAULT_INITIALIZER(0);
+ size_t DeviceObjectAttribsSize DEFAULT_INITIALIZER(0);
+ size_t GraphicsAdapterInfoSize DEFAULT_INITIALIZER(0);
+ size_t DisplayModeAttribsSize DEFAULT_INITIALIZER(0);
+ size_t SwapChainDescSize DEFAULT_INITIALIZER(0);
+ size_t FullScreenModeDescSize DEFAULT_INITIALIZER(0);
+ size_t EngineCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t EngineGLCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t EngineD3D11CreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t EngineD3D12CreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t EngineVkCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t EngineMtlCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t BoxSize DEFAULT_INITIALIZER(0);
+ size_t TextureFormatAttribsSize DEFAULT_INITIALIZER(0);
+ size_t TextureFormatInfoSize DEFAULT_INITIALIZER(0);
+ size_t TextureFormatInfoExtSize DEFAULT_INITIALIZER(0);
+ size_t StateTransitionDescSize DEFAULT_INITIALIZER(0);
+ size_t LayoutElementSize DEFAULT_INITIALIZER(0);
+ size_t InputLayoutDescSize DEFAULT_INITIALIZER(0);
+ size_t SampleDescSize DEFAULT_INITIALIZER(0);
+ size_t ShaderResourceVariableDescSize DEFAULT_INITIALIZER(0);
+ size_t ImmutableSamplerDescSize DEFAULT_INITIALIZER(0);
+ size_t PipelineResourceLayoutDescSize DEFAULT_INITIALIZER(0);
+ size_t PipelineStateDescSize DEFAULT_INITIALIZER(0);
+ size_t GraphicsPipelineDescSize DEFAULT_INITIALIZER(0);
+ size_t GraphicsPipelineStateCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t ComputePipelineStateCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t RayTracingPipelineDescSize DEFAULT_INITIALIZER(0);
+ size_t RayTracingPipelineStateCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t RasterizerStateDescSize DEFAULT_INITIALIZER(0);
+ size_t ResourceMappingEntrySize DEFAULT_INITIALIZER(0);
+ size_t ResourceMappingDescSize DEFAULT_INITIALIZER(0);
+ size_t SamplerDescSize DEFAULT_INITIALIZER(0);
+ size_t ShaderDescSize DEFAULT_INITIALIZER(0);
+ size_t ShaderMacroSize DEFAULT_INITIALIZER(0);
+ size_t ShaderCreateInfoSize DEFAULT_INITIALIZER(0);
+ size_t ShaderResourceDescSize DEFAULT_INITIALIZER(0);
+ size_t DepthStencilClearValueSize DEFAULT_INITIALIZER(0);
+ size_t OptimizedClearValueSize DEFAULT_INITIALIZER(0);
+ size_t TextureDescSize DEFAULT_INITIALIZER(0);
+ size_t TextureSubResDataSize DEFAULT_INITIALIZER(0);
+ size_t TextureDataSize DEFAULT_INITIALIZER(0);
+ size_t MappedTextureSubresourceSize DEFAULT_INITIALIZER(0);
+ size_t TextureViewDescSize DEFAULT_INITIALIZER(0);
};
typedef struct APIInfo APIInfo;
diff --git a/Graphics/GraphicsEngine/interface/BottomLevelAS.h b/Graphics/GraphicsEngine/interface/BottomLevelAS.h
new file mode 100644
index 00000000..f7190c93
--- /dev/null
+++ b/Graphics/GraphicsEngine/interface/BottomLevelAS.h
@@ -0,0 +1,290 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definition of the Diligent::IBottomLevelAS interface and related data structures
+
+#include "../../../Primitives/interface/Object.h"
+#include "../../../Primitives/interface/FlagEnum.h"
+#include "GraphicsTypes.h"
+#include "Constants.h"
+#include "Buffer.h"
+
+DILIGENT_BEGIN_NAMESPACE(Diligent)
+
+// {E56F5755-FE5E-496C-BFA7-BCD535360FF7}
+static const INTERFACE_ID IID_BottomLevelAS =
+ {0xe56f5755, 0xfe5e, 0x496c, {0xbf, 0xa7, 0xbc, 0xd5, 0x35, 0x36, 0xf, 0xf7}};
+
+// clang-format off
+
+static const Uint32 INVALID_INDEX = ~0u;
+
+
+/// Defines bottom level acceleration structure triangles description.
+
+/// Triangle geometry description.
+struct BLASTriangleDesc
+{
+ /// Geometry name.
+ /// The name is used to map triangle data (BLASBuildTriangleData) to this geometry.
+ const char* GeometryName DEFAULT_INITIALIZER(nullptr);
+
+ /// The maximum vertex count in this geometry.
+ /// Current number of vertices is defined in BLASBuildTriangleData::VertexCount.
+ Uint32 MaxVertexCount DEFAULT_INITIALIZER(0);
+
+ /// The type of vertices in this geometry, see Diligent::VALUE_TYPE.
+ ///
+ /// \remarks Only the following values are allowed: VT_FLOAT32, VT_FLOAT16, VT_INT16.
+ /// VT_INT16 defines 16-bit signed normalized vertex components.
+ VALUE_TYPE VertexValueType DEFAULT_INITIALIZER(VT_UNDEFINED);
+
+ /// The number of components in the vertex.
+ ///
+ /// \remarks Only 2 or 3 are allowed values. For 2-component formats, the third component is assumed 0.
+ Uint8 VertexComponentCount DEFAULT_INITIALIZER(0);
+
+ /// The maximum primitive count in this geometry.
+ /// The current number of primitives is defined in BLASBuildTriangleData::PrimitiveCount.
+ Uint32 MaxPrimitiveCount DEFAULT_INITIALIZER(0);
+
+ /// Index type of this geometry, see Diligent::VALUE_TYPE.
+ /// Must be VT_UINT16, VT_UINT32 or VT_UNDEFINED.
+ /// If not defined then vertex array is used instead of indexed vertices.
+ VALUE_TYPE IndexType DEFAULT_INITIALIZER(VT_UNDEFINED);
+
+ /// Vulkan only, allows to use transformations in BLASBuildTriangleData.
+ Bool AllowsTransforms DEFAULT_INITIALIZER(False);
+
+#if DILIGENT_CPP_INTERFACE
+ BLASTriangleDesc() noexcept {}
+#endif
+};
+typedef struct BLASTriangleDesc BLASTriangleDesc;
+
+
+/// Defines bottom level acceleration structure axis-aligned bounding boxes description.
+
+/// AABB geometry description.
+struct BLASBoundingBoxDesc
+{
+ /// Geometry name.
+ /// The name is used to map AABB data (BLASBuildBoundingBoxData) to this geometry.
+ const char* GeometryName DEFAULT_INITIALIZER(nullptr);
+
+ /// The maximum AABB count.
+ /// Current number of AABBs is defined in BLASBuildBoundingBoxData::BoxCount.
+ Uint32 MaxBoxCount DEFAULT_INITIALIZER(0);
+
+#if DILIGENT_CPP_INTERFACE
+ BLASBoundingBoxDesc() noexcept {}
+#endif
+};
+typedef struct BLASBoundingBoxDesc BLASBoundingBoxDesc;
+
+
+/// Defines acceleration structures build flags.
+DILIGENT_TYPED_ENUM(RAYTRACING_BUILD_AS_FLAGS, Uint8)
+{
+ RAYTRACING_BUILD_AS_NONE = 0,
+
+ /// Indicates that the specified acceleration structure can be updated
+ /// via IDeviceContext::BuildBLAS() or IDeviceContext::BuildTLAS().
+ /// With this flag, the acceleration structure may allocate more memory and take more time to build.
+ RAYTRACING_BUILD_AS_ALLOW_UPDATE = 0x01,
+
+ /// Indicates that the specified acceleration structure can act as the source for
+ /// a copy acceleration structure command IDeviceContext::CopyBLAS() or IDeviceContext::CopyTLAS()
+ /// with COPY_AS_MODE_COMPACT mode to produce a compacted acceleration structure.
+ /// With this flag acculeration structure may allocate more memory and take more time on build.
+ RAYTRACING_BUILD_AS_ALLOW_COMPACTION = 0x02,
+
+ /// Indicates that the given acceleration structure build should prioritize trace performance over build time.
+ RAYTRACING_BUILD_AS_PREFER_FAST_TRACE = 0x04,
+
+ /// Indicates that the given acceleration structure build should prioritize build time over trace performance.
+ RAYTRACING_BUILD_AS_PREFER_FAST_BUILD = 0x08,
+
+ /// Indicates that this acceleration structure should minimize the size of the scratch memory and the final
+ /// result build, potentially at the expense of build time or trace performance.
+ RAYTRACING_BUILD_AS_LOW_MEMORY = 0x10,
+
+ RAYTRACING_BUILD_AS_FLAGS_LAST = RAYTRACING_BUILD_AS_LOW_MEMORY
+};
+DEFINE_FLAG_ENUM_OPERATORS(RAYTRACING_BUILD_AS_FLAGS)
+
+
+/// Bottom-level AS description.
+struct BottomLevelASDesc DILIGENT_DERIVE(DeviceObjectAttribs)
+
+ /// Array of triangle geometry descriptions.
+ const BLASTriangleDesc* pTriangles DEFAULT_INITIALIZER(nullptr);
+
+ /// The number of triangle geometries in pTriangles array.
+ Uint32 TriangleCount DEFAULT_INITIALIZER(0);
+
+ /// Array of AABB geometry descriptions.
+ const BLASBoundingBoxDesc* pBoxes DEFAULT_INITIALIZER(nullptr);
+
+ /// The number of AABB geometries in pBoxes array.
+ Uint32 BoxCount DEFAULT_INITIALIZER(0);
+
+ /// Ray tracing build flags, see Diligent::RAYTRACING_BUILD_AS_FLAGS.
+ RAYTRACING_BUILD_AS_FLAGS Flags DEFAULT_INITIALIZER(RAYTRACING_BUILD_AS_NONE);
+
+ /// Size from the result of IDeviceContext::WriteBLASCompactedSize() if this acceleration structure
+ /// is going to be the target of a compacting copy (IDeviceContext::CopyBLAS() with COPY_AS_MODE_COMPACT).
+ Uint32 CompactedSize DEFAULT_INITIALIZER(0);
+
+ /// Defines which command queues this BLAS can be used with
+ Uint64 CommandQueueMask DEFAULT_INITIALIZER(1);
+
+#if DILIGENT_CPP_INTERFACE
+ BottomLevelASDesc() noexcept {}
+#endif
+};
+typedef struct BottomLevelASDesc BottomLevelASDesc;
+
+
+/// Defines the scratch buffer info for acceleration structure.
+struct ScratchBufferSizes
+{
+ /// Scratch buffer size for acceleration structure building,
+ /// see IDeviceContext::BuildBLAS(), IDeviceContext::BuildTLAS().
+ /// May be zero if the acceleration structure was created with non-zero CompactedSize.
+ Uint32 Build DEFAULT_INITIALIZER(0);
+
+ /// Scratch buffer size for acceleration structure updating,
+ /// see IDeviceContext::BuildBLAS(), IDeviceContext::BuildTLAS().
+ /// May be zero if acceleration structure was created without RAYTRACING_BUILD_AS_ALLOW_UPDATE flag.
+ /// May be zero if acceleration structure was created with non-zero CompactedSize.
+ Uint32 Update DEFAULT_INITIALIZER(0);
+
+#if DILIGENT_CPP_INTERFACE
+ ScratchBufferSizes() noexcept {}
+#endif
+};
+typedef struct ScratchBufferSizes ScratchBufferSizes;
+
+
+#define DILIGENT_INTERFACE_NAME IBottomLevelAS
+#include "../../../Primitives/interface/DefineInterfaceHelperMacros.h"
+
+#define IBottomLevelASInclusiveMethods \
+ IDeviceObjectInclusiveMethods; \
+ IBottomLevelASMethods BottomLevelAS
+
+/// Bottom-level AS interface
+
+/// Defines the methods to manipulate a BLAS object
+DILIGENT_BEGIN_INTERFACE(IBottomLevelAS, IDeviceObject)
+{
+#if DILIGENT_CPP_INTERFACE
+ /// Returns the bottom level AS description used to create the object
+ virtual const BottomLevelASDesc& DILIGENT_CALL_TYPE GetDesc() const override = 0;
+#endif
+
+ /// Returns the geometry description index in BottomLevelASDesc::pTriangles or BottomLevelASDesc::pBoxes.
+
+ /// \param [in] Name - Geometry name that is specified in BLASTriangleDesc or BLASBoundingBoxDesc.
+ /// \return Geometry index or INVALID_INDEX if geometry does not exist.
+ ///
+ /// \note Access to the BLAS must be externally synchronized.
+ VIRTUAL Uint32 METHOD(GetGeometryDescIndex)(THIS_
+ const char* Name) CONST PURE;
+
+
+ /// Returns the geometry index that can be used in a shader binding table.
+
+ /// \param [in] Name - Geometry name that is specified in BLASTriangleDesc or BLASBoundingBoxDesc.
+ /// \return Geometry index or INVALID_INDEX if geometry does not exist.
+ ///
+ /// \note Access to the BLAS must be externally synchronized.
+ VIRTUAL Uint32 METHOD(GetGeometryIndex)(THIS_
+ const char* Name) CONST PURE;
+
+
+ /// Returns the geometry count that was used to build AS.
+ /// Same as BuildBLASAttribs::TriangleDataCount or BuildBLASAttribs::BoxDataCount.
+
+ /// \return The number of geometries that was used to build AS.
+ ///
+ /// \note Access to the BLAS must be externally synchronized.
+ VIRTUAL Uint32 METHOD(GetActualGeometryCount)(THIS) CONST PURE;
+
+
+ /// Returns the scratch buffer info for the current acceleration structure.
+
+ /// \return ScratchBufferSizes object, see Diligent::ScratchBufferSizes.
+ VIRTUAL ScratchBufferSizes METHOD(GetScratchBufferSizes)(THIS) CONST PURE;
+
+
+ /// Returns the native acceleration structure handle specific to the underlying graphics API
+
+ /// \return pointer to ID3D12Resource interface, for D3D12 implementation\n
+ /// VkAccelerationStructure handle, for Vulkan implementation
+ VIRTUAL void* METHOD(GetNativeHandle)(THIS) PURE;
+
+
+ /// Sets the acceleration structure usage state.
+
+ /// \note This method does not perform state transition, but
+ /// resets the internal acceleration structure state to the given value.
+ /// This method should be used after the application finished
+ /// manually managing the acceleration structure state and wants to hand over
+ /// state management back to the engine.
+ VIRTUAL void METHOD(SetState)(THIS_
+ RESOURCE_STATE State) PURE;
+
+
+ /// Returns the internal acceleration structure state
+ VIRTUAL RESOURCE_STATE METHOD(GetState)(THIS) CONST PURE;
+};
+DILIGENT_END_INTERFACE
+
+#include "../../../Primitives/interface/UndefInterfaceHelperMacros.h"
+
+#if DILIGENT_C_INTERFACE
+
+// clang-format off
+
+# define IBottomLevelAS_GetGeometryDescIndex(This, ...) CALL_IFACE_METHOD(BottomLevelAS, GetGeometryDescIndex, This, __VA_ARGS__)
+# define IBottomLevelAS_GetGeometryIndex(This, ...) CALL_IFACE_METHOD(BottomLevelAS, GetGeometryIndex, This, __VA_ARGS__)
+# define IBottomLevelAS_GetActualGeometryCount(This) CALL_IFACE_METHOD(BottomLevelAS, GetActualGeometryCount, This)
+# define IBottomLevelAS_GetScratchBufferSizes(This) CALL_IFACE_METHOD(BottomLevelAS, GetScratchBufferSizes, This)
+# define IBottomLevelAS_GetNativeHandle(This) CALL_IFACE_METHOD(BottomLevelAS, GetNativeHandle, This)
+# define IBottomLevelAS_SetState(This, ...) CALL_IFACE_METHOD(BottomLevelAS, SetState, This, __VA_ARGS__)
+# define IBottomLevelAS_GetState(This) CALL_IFACE_METHOD(BottomLevelAS, GetState, This)
+
+// clang-format on
+
+#endif
+
+DILIGENT_END_NAMESPACE // namespace Diligent
diff --git a/Graphics/GraphicsEngine/interface/Buffer.h b/Graphics/GraphicsEngine/interface/Buffer.h
index 417b8ac3..dd7f0c84 100644
--- a/Graphics/GraphicsEngine/interface/Buffer.h
+++ b/Graphics/GraphicsEngine/interface/Buffer.h
@@ -81,7 +81,7 @@ struct BufferDesc DILIGENT_DERIVE(DeviceObjectAttribs)
/// The following bind flags are allowed:
/// Diligent::BIND_VERTEX_BUFFER, Diligent::BIND_INDEX_BUFFER, Diligent::BIND_UNIFORM_BUFFER,
/// Diligent::BIND_SHADER_RESOURCE, Diligent::BIND_STREAM_OUTPUT, Diligent::BIND_UNORDERED_ACCESS,
- /// Diligent::BIND_INDIRECT_DRAW_ARGS
+ /// Diligent::BIND_INDIRECT_DRAW_ARGS, Diligent::BIND_RAY_TRACING
BIND_FLAGS BindFlags DEFAULT_INITIALIZER(BIND_NONE);
/// Buffer usage, see Diligent::USAGE for details
diff --git a/Graphics/GraphicsEngine/interface/Constants.h b/Graphics/GraphicsEngine/interface/Constants.h
index 9cd45c4d..b00f2de2 100644
--- a/Graphics/GraphicsEngine/interface/Constants.h
+++ b/Graphics/GraphicsEngine/interface/Constants.h
@@ -51,8 +51,8 @@ static const Uint32 MAX_RENDER_TARGETS = DILIGENT_MAX_RENDER_TARGETS;
static const Uint32 MAX_VIEWPORTS = DILIGENT_MAX_VIEWPORTS;
/// Maximum number of shader stages in a pipeline.
-/// (Vertex, Hull, Domain, Geometry, Pixel) or (Amplification, Mesh, Pixel), or (Compute)
-static const Uint32 MAX_SHADERS_IN_PIPELINE = 5;
+/// (Vertex, Hull, Domain, Geometry, Pixel) or (Amplification, Mesh, Pixel), or (Compute) or (RayGen, Miss, ClosestHit, AnyHit, Intersection, Callable)
+static const Uint32 MAX_SHADERS_IN_PIPELINE = 6;
// clang-format on
diff --git a/Graphics/GraphicsEngine/interface/DeviceContext.h b/Graphics/GraphicsEngine/interface/DeviceContext.h
index 122661f0..73e2640c 100644
--- a/Graphics/GraphicsEngine/interface/DeviceContext.h
+++ b/Graphics/GraphicsEngine/interface/DeviceContext.h
@@ -53,6 +53,9 @@
#include "Framebuffer.h"
#include "CommandList.h"
#include "SwapChain.h"
+#include "BottomLevelAS.h"
+#include "TopLevelAS.h"
+#include "ShaderBindingTable.h"
DILIGENT_BEGIN_NAMESPACE(Diligent)
@@ -716,6 +719,645 @@ struct BeginRenderPassAttribs
};
typedef struct BeginRenderPassAttribs BeginRenderPassAttribs;
+
+/// TLAS instance flags that are used in IDeviceContext::BuildTLAS().
+DILIGENT_TYPED_ENUM(RAYTRACING_INSTANCE_FLAGS, Uint8)
+{
+ RAYTRACING_INSTANCE_NONE = 0,
+
+ /// Disables face culling for this instance.
+ RAYTRACING_INSTANCE_TRIANGLE_FACING_CULL_DISABLE = 0x01,
+
+ /// Indicates that the front face of the triangle for culling purposes is the face that is counter
+ /// clockwise in object space relative to the ray origin. Because the facing is determined in object
+ /// space, an instance transform matrix does not change the winding, but a geometry transform does.
+ RAYTRACING_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE = 0x02,
+
+ /// Causes this instance to act as though RAYTRACING_GEOMETRY_FLAGS_OPAQUE were specified on all
+ /// geometries referenced by this instance. This behavior can be overridden in the shader with ray flags.
+ RAYTRACING_INSTANCE_FORCE_OPAQUE = 0x04,
+
+ /// Causes this instance to act as though RAYTRACING_GEOMETRY_FLAGS_OPAQUE were not specified on all
+ /// geometries referenced by this instance. This behavior can be overridden in the shader with ray flags.
+ RAYTRACING_INSTANCE_FORCE_NO_OPAQUE = 0x08,
+
+ RAYTRACING_INSTANCE_FLAGS_LAST = RAYTRACING_INSTANCE_FORCE_NO_OPAQUE
+};
+DEFINE_FLAG_ENUM_OPERATORS(RAYTRACING_INSTANCE_FLAGS)
+
+
+/// Defines acceleration structure copy mode.
+
+/// These the flags used by IDeviceContext::CopyBLAS() and IDeviceContext::CopyTLAS().
+DILIGENT_TYPED_ENUM(COPY_AS_MODE, Uint8)
+{
+ /// Creates a direct copy of the acceleration structure specified in pSrc into the one specified by pDst.
+ /// The pDst acceleration structure must have been created with the same parameters as pSrc.
+ COPY_AS_MODE_CLONE = 0,
+
+ /// Creates a more compact version of an acceleration structure pSrc into pDst.
+ /// The acceleration structure pDst must have been created with a CompactedSize corresponding
+ /// to the one returned by IDeviceContext::WriteBLASCompactedSize() or IDeviceContext::WriteTLASCompactedSize()
+ /// after the build of the acceleration structure specified by pSrc.
+ COPY_AS_MODE_COMPACT,
+
+ COPY_AS_MODE_LAST = COPY_AS_MODE_COMPACT,
+};
+
+
+/// Defines geometry flags for ray tracing.
+DILIGENT_TYPED_ENUM(RAYTRACING_GEOMETRY_FLAGS, Uint8)
+{
+ RAYTRACING_GEOMETRY_FLAG_NONE = 0,
+
+ /// Indicates that this geometry does not invoke the any-hit shaders even if present in a hit group.
+ RAYTRACING_GEOMETRY_FLAG_OPAQUE = 0x01,
+
+ /// Indicates that the implementation must only call the any-hit shader a single time for each primitive in this geometry.
+ /// If this bit is absent an implementation may invoke the any-hit shader more than once for this geometry.
+ RAYTRACING_GEOMETRY_FLAG_NO_DUPLICATE_ANY_HIT_INVOCATION = 0x02,
+
+ RAYTRACING_GEOMETRY_FLAGS_LAST = RAYTRACING_GEOMETRY_FLAG_NO_DUPLICATE_ANY_HIT_INVOCATION
+};
+DEFINE_FLAG_ENUM_OPERATORS(RAYTRACING_GEOMETRY_FLAGS)
+
+
+/// Triangle geometry data description.
+struct BLASBuildTriangleData
+{
+ /// Geometry name used to map a geometry to a hit group in the shader binding table.
+ /// Add geometry data to the geometry that is allocated by BLASTriangleDesc with the same name.
+ const char* GeometryName DEFAULT_INITIALIZER(nullptr);
+
+ /// Triangle vertices data source.
+ /// Triangles are considered "inactive" if the x component of each vertex is NaN.
+ /// The buffer must be created with BIND_RAY_TRACING flag.
+ IBuffer* pVertexBuffer DEFAULT_INITIALIZER(nullptr);
+
+ /// Data offset in bytes in pVertexBuffer.
+ Uint32 VertexOffset DEFAULT_INITIALIZER(0);
+
+ /// Stride in bytes between vertices.
+ Uint32 VertexStride DEFAULT_INITIALIZER(0);
+
+ /// The number of triangle vertices.
+ /// Must be less than or equal to BLASTriangleDesc::MaxVertexCount.
+ Uint32 VertexCount DEFAULT_INITIALIZER(0);
+
+ /// The type of the vertex components.
+ /// This is an optional value. Must be undefined or same as in BLASTriangleDesc.
+ VALUE_TYPE VertexValueType DEFAULT_INITIALIZER(VT_UNDEFINED);
+
+ /// The number of vertex components.
+ /// This is an optional value. Must be undefined or same as in BLASTriangleDesc.
+ Uint8 VertexComponentCount DEFAULT_INITIALIZER(0);
+
+ /// The number of triangles.
+ /// Must equal to VertexCount / 3 if pIndexBuffer is null or must be equal to index count / 3.
+ Uint32 PrimitiveCount DEFAULT_INITIALIZER(0);
+
+ /// Triangle indices data source.
+ /// Must be null if BLASTriangleDesc::IndexType is undefined.
+ /// The buffer must be created with BIND_RAY_TRACING flag.
+ IBuffer* pIndexBuffer DEFAULT_INITIALIZER(nullptr);
+
+ /// Data offset in bytes in pIndexBuffer.
+ Uint32 IndexOffset DEFAULT_INITIALIZER(0);
+
+ /// The type of triangle indices, see Diligent::VALUE_TYPE.
+ /// This is an optional value. Must be undefined or same as in BLASTriangleDesc.
+ VALUE_TYPE IndexType DEFAULT_INITIALIZER(VT_UNDEFINED);
+
+ /// Geometry transformation data source.
+ /// The buffer must be created with BIND_RAY_TRACING flag.
+ IBuffer* pTransformBuffer DEFAULT_INITIALIZER(nullptr);
+
+ /// Data offset in bytes in pTransformBuffer.
+ Uint32 TransformBufferOffset DEFAULT_INITIALIZER(0);
+
+ /// Geometry flags, se Diligent::RAYTRACING_GEOMETRY_FLAGS.
+ RAYTRACING_GEOMETRY_FLAGS Flags DEFAULT_INITIALIZER(RAYTRACING_GEOMETRY_FLAG_NONE);
+
+#if DILIGENT_CPP_INTERFACE
+ BLASBuildTriangleData() noexcept {}
+#endif
+};
+typedef struct BLASBuildTriangleData BLASBuildTriangleData;
+
+
+/// AABB geometry data description.
+struct BLASBuildBoundingBoxData
+{
+ /// Geometry name used to map geometry to hit group in shader binding table.
+ /// Put geometry data to geometry that allocated by BLASBoundingBoxDesc with the same name.
+ const char* GeometryName DEFAULT_INITIALIZER(nullptr);
+
+ /// AABB data source.
+ /// Each AABB defined as { float3 Min; float3 Max } structure.
+ /// AABB are considered inactive if AABB.Min.x is NaN.
+ /// Buffer must be created with BIND_RAY_TRACING flag.
+ IBuffer* pBoxBuffer DEFAULT_INITIALIZER(nullptr);
+
+ /// Data offset in bytes in pBoxBuffer.
+ Uint32 BoxOffset DEFAULT_INITIALIZER(0);
+
+ /// Stride in bytes between each AABB.
+ Uint32 BoxStride DEFAULT_INITIALIZER(0);
+
+ /// Number of AABBs.
+ /// Must be less than or equal to BLASBoundingBoxDesc::MaxBoxCount.
+ Uint32 BoxCount DEFAULT_INITIALIZER(0);
+
+ /// Geometry flags, see Diligent::RAYTRACING_GEOMETRY_FLAGS.
+ RAYTRACING_GEOMETRY_FLAGS Flags DEFAULT_INITIALIZER(RAYTRACING_GEOMETRY_FLAG_NONE);
+
+#if DILIGENT_CPP_INTERFACE
+ BLASBuildBoundingBoxData() noexcept {}
+#endif
+};
+typedef struct BLASBuildBoundingBoxData BLASBuildBoundingBoxData;
+
+
+/// This structure is used by IDeviceContext::BuildBLAS().
+struct BuildBLASAttribs
+{
+ /// Target bottom-level AS.
+ /// Access to the BLAS must be externally synchronized.
+ IBottomLevelAS* pBLAS DEFAULT_INITIALIZER(nullptr);
+
+ /// Bottom-level AS state transition mode (see Diligent::RESOURCE_STATE_TRANSITION_MODE).
+ RESOURCE_STATE_TRANSITION_MODE BLASTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE);
+
+ /// Geometry data source buffers state transition mode (see Diligent::RESOURCE_STATE_TRANSITION_MODE).
+ RESOURCE_STATE_TRANSITION_MODE GeometryTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE);
+
+ /// A pointer to an array of TriangleDataCount BLASBuildTriangleData structures that contains triangle geometry data.
+ /// If Update is true:
+ /// - Only vertex positions (in pVertexBuffer) and transformation (in pTransformBuffer) can be changed.
+ /// - All other content in BLASBuildTriangleData and buffers must be the same as what was used to build BLAS.
+ /// - To disable geometry, make all triangles inactive, see BLASBuildTriangleData::pVertexBuffer description.
+ BLASBuildTriangleData const* pTriangleData DEFAULT_INITIALIZER(nullptr);
+
+ /// The number of triangle grometries.
+ /// Must be less than or equal to BottomLevelASDesc::TriangleCount.
+ /// If Update is true then the count must be the same as the one used to build BLAS.
+ Uint32 TriangleDataCount DEFAULT_INITIALIZER(0);
+
+ /// A pointer to an array of BoxDataCount BLASBuildBoundingBoxData structures that contain AABB geometry data.
+ /// If Update is true:
+ /// - AABB coordinates (in pBoxBuffer) can be changed.
+ /// - All other content in BLASBuildBoundingBoxData must be same as used to build BLAS.
+ /// - To disable geometry make all AAABBs inactive, see BLASBuildBoundingBoxData::pBoxBuffer description.
+ BLASBuildBoundingBoxData const* pBoxData DEFAULT_INITIALIZER(nullptr);
+
+ /// The number of AABB geometries.
+ /// Must be less than or equal to BottomLevelASDesc::BoxCount.
+ /// If Update is true then the count must be the same as the one used to build BLAS.
+ Uint32 BoxDataCount DEFAULT_INITIALIZER(0);
+
+ /// The buffer that is used for acceleration structure building.
+ /// Must be created with BIND_RAY_TRACING.
+ /// Call IBottomLevelAS::GetScratchBufferSizes().Build to get the minimal size for the scratch buffer.
+ IBuffer* pScratchBuffer DEFAULT_INITIALIZER(nullptr);
+
+ /// Offset from the beginning of the buffer.
+ Uint32 ScratchBufferOffset DEFAULT_INITIALIZER(0);
+
+ /// Scratch buffer state transition mode (see Diligent::RESOURCE_STATE_TRANSITION_MODE).
+ RESOURCE_STATE_TRANSITION_MODE ScratchBufferTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE);
+
+ /// if false then BLAS will be built from scratch.
+ /// If true then previous content of BLAS will be updated.
+ /// pBLAS must be created with RAYTRACING_BUILD_AS_ALLOW_UPDATE flag.
+ /// An update will be faster than building an acceleration structure from scratch.
+ Bool Update DEFAULT_INITIALIZER(False);
+
+#if DILIGENT_CPP_INTERFACE
+ BuildBLASAttribs() noexcept {}
+#endif
+};
+typedef struct BuildBLASAttribs BuildBLASAttribs;
+
+
+/// Can be used to calculate the TLASBuildInstanceData::ContributionToHitGroupIndex depending on instance count,
+/// geometry count in each instance (in TLASBuildInstanceData::pBLAS) and shader binding mode in BuildTLASAttribs::BindingMode.
+///
+/// Example:
+/// InstanceOffset = BaseContributionToHitGroupIndex;
+/// For each instance in TLAS
+/// if (Instance.ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO)
+/// Instance.ContributionToHitGroupIndex = InstanceOffset;
+/// if (BindingMode == HIT_GROUP_BINDING_MODE_PER_GEOMETRY) InstanceOffset += Instance.pBLAS->GeometryCount() * HitGroupStride;
+/// if (BindingMode == HIT_GROUP_BINDING_MODE_PER_INSTANCE) InstanceOffset += HitGroupStride;
+static const Uint32 TLAS_INSTANCE_OFFSET_AUTO = ~0u;
+
+
+/// Row-major matrix
+struct InstanceMatrix
+{
+ /// rotation translation
+ /// ([0,0] [0,1] [0,2]) ([0,3])
+ /// ([1,0] [1,1] [1,2]) ([1,3])
+ /// ([2,0] [2,1] [2,2]) ([2,3])
+ float data [3][4];
+
+#if DILIGENT_CPP_INTERFACE
+ /// Construct identity matrix.
+ InstanceMatrix() noexcept :
+ data{{1.0f, 0.0f, 0.0f, 0.0f},
+ {0.0f, 1.0f, 0.0f, 0.0f},
+ {0.0f, 0.0f, 1.0f, 0.0f}}
+ {}
+
+ InstanceMatrix(const InstanceMatrix&) noexcept = default;
+
+ /// Sets the translation part.
+ InstanceMatrix& SetTranslation(float x, float y, float z) noexcept
+ {
+ data[0][3] = x;
+ data[1][3] = y;
+ data[2][3] = z;
+ return *this;
+ }
+
+ /// Sets the rotation part.
+ InstanceMatrix& SetRotation(const float* pMatrix3x3) noexcept
+ {
+ data[0][0] = pMatrix3x3[0]; data[1][0] = pMatrix3x3[1]; data[2][0] = pMatrix3x3[2];
+ data[0][1] = pMatrix3x3[3]; data[1][1] = pMatrix3x3[4]; data[2][1] = pMatrix3x3[5];
+ data[0][2] = pMatrix3x3[6]; data[1][2] = pMatrix3x3[7]; data[2][2] = pMatrix3x3[8];
+ return *this;
+ }
+#endif
+};
+typedef struct InstanceMatrix InstanceMatrix;
+
+
+/// This structure is used by BuildTLASAttribs.
+struct TLASBuildInstanceData
+{
+ /// Instance name that is used to map an instance to a hit group in shader binding table.
+ const char* InstanceName DEFAULT_INITIALIZER(nullptr);
+
+ /// Bottom-level AS that represents instance geometry.
+ /// Once built, TLAS will hold strong reference to pBLAS until next build or copy operation.
+ /// Access to the BLAS must be externally synchronized.
+ IBottomLevelAS* pBLAS DEFAULT_INITIALIZER(nullptr);
+
+ /// Instace to world transformation.
+ InstanceMatrix Transform;
+
+ /// User-defined value that can be accessed in the shader via InstanceID() in HLSL and gl_InstanceCustomIndex in GLSL.
+ /// Only the lower 24 bits are used.
+ Uint32 CustomId DEFAULT_INITIALIZER(0);
+
+ /// Instance flags, see Diligent::RAYTRACING_INSTANCE_FLAGS.
+ RAYTRACING_INSTANCE_FLAGS Flags DEFAULT_INITIALIZER(RAYTRACING_INSTANCE_NONE);
+
+ /// Visibility mask for the geometry, the instance may only be hit if rayMask & instance.Mask != 0.
+ /// ('rayMask' in GLSL is a 'cullMask' argument of traceRay(), 'rayMask' in HLSL is an 'InstanceInclusionMask' argument of TraceRay()).
+ Uint8 Mask DEFAULT_INITIALIZER(0xFF);
+
+ /// The index used to calculate the hit group location in the shader binding table.
+ /// Must be TLAS_INSTANCE_OFFSET_AUTO if BuildTLASAttribs::BindingMode is not SHADER_BINDING_USER_DEFINED.
+ /// Only the lower 24 bits are used.
+ Uint32 ContributionToHitGroupIndex DEFAULT_INITIALIZER(TLAS_INSTANCE_OFFSET_AUTO);
+
+#if DILIGENT_CPP_INTERFACE
+ TLASBuildInstanceData() noexcept {}
+#endif
+};
+typedef struct TLASBuildInstanceData TLASBuildInstanceData;
+
+
+/// Top-level AS instance size in bytes in GPU side.
+/// Used to calculate size of BuildTLASAttribs::pInstanceBuffer.
+static const Uint32 TLAS_INSTANCE_DATA_SIZE = 64;
+
+
+/// This structure is used by IDeviceContext::BuildTLAS().
+struct BuildTLASAttribs
+{
+ /// Target top-level AS.
+ /// Access to the TLAS must be externally synchronized.
+ ITopLevelAS* pTLAS DEFAULT_INITIALIZER(nullptr);
+
+ /// Top-level AS state transition mode (see Diligent::RESOURCE_STATE_TRANSITION_MODE).
+ RESOURCE_STATE_TRANSITION_MODE TLASTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE);
+
+ /// Bottom-level AS (in TLASBuildInstanceData::pBLAS) state transition mode (see Diligent::RESOURCE_STATE_TRANSITION_MODE).
+ RESOURCE_STATE_TRANSITION_MODE BLASTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE);
+
+ /// A pointer to an array of InstanceCount TLASBuildInstanceData structures that contain instance data.
+ /// If Update is true:
+ /// - Any instance data can be changed.
+ /// - To disable an instance set TLASBuildInstanceData::Mask to zero or set empty TLASBuildInstanceData::BLAS to pBLAS.
+ TLASBuildInstanceData const* pInstances DEFAULT_INITIALIZER(nullptr);
+
+ /// The number of instances.
+ /// Must be less than or equal to TopLevelASDesc::MaxInstanceCount.
+ /// If Update is true then count must be the same as used to build TLAS.
+ Uint32 InstanceCount DEFAULT_INITIALIZER(0);
+
+ /// The buffer that will be used to store instance data during AS building.
+ /// The buffer size must be at least TLAS_INSTANCE_DATA_SIZE * InstanceCount.
+ /// The buffer must be created with BIND_RAY_TRACING flag.
+ IBuffer* pInstanceBuffer DEFAULT_INITIALIZER(nullptr);
+
+ /// Offset from the beginning of the buffer to the location of instance data.
+ Uint32 InstanceBufferOffset DEFAULT_INITIALIZER(0);
+
+ /// Instance buffer state transition mode (see Diligent::RESOURCE_STATE_TRANSITION_MODE).
+ RESOURCE_STATE_TRANSITION_MODE InstanceBufferTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE);
+
+ /// The number of hit shaders that can be bound for a single geometry or an instance (depends on BindingMode).
+ /// - Used to calculate TLASBuildInstanceData::ContributionToHitGroupIndex.
+ /// - Ignored if BindingMode is SHADER_BINDING_USER_DEFINED.
+ /// You should use the same value in a shader:
+ /// 'MultiplierForGeometryContributionToHitGroupIndex' argument in TraceRay() in HLSL, 'sbtRecordStride' argument in traceRay() in GLSL.
+ Uint32 HitGroupStride DEFAULT_INITIALIZER(1);
+
+ /// Base offset for hit group location.
+ /// Can be used to bind hit shaders for multiple acceleration structures, see IShaderBindingTable::BindHitGroup().
+ /// - Used to calculate TLASBuildInstanceData::ContributionToHitGroupIndex.
+ /// - Ignored if BindingMode is SHADER_BINDING_USER_DEFINED.
+ Uint32 BaseContributionToHitGroupIndex DEFAULT_INITIALIZER(0);
+
+ /// Hit shader binding mode, see Diligent::SHADER_BINDING_MODE.
+ /// Used to calculate TLASBuildInstanceData::ContributionToHitGroupIndex.
+ HIT_GROUP_BINDING_MODE BindingMode DEFAULT_INITIALIZER(HIT_GROUP_BINDING_MODE_PER_GEOMETRY);
+
+ /// Buffer that is used for acceleration structure building.
+ /// Must be created with BIND_RAY_TRACING.
+ /// Call ITopLevelAS::GetScratchBufferSizes().Build to get the minimal size for the scratch buffer.
+ /// Access to the TLAS must be externally synchronized.
+ IBuffer* pScratchBuffer DEFAULT_INITIALIZER(nullptr);
+
+ /// Offset from the beginning of the buffer.
+ Uint32 ScratchBufferOffset DEFAULT_INITIALIZER(0);
+
+ /// Scratch buffer state transition mode (see Diligent::RESOURCE_STATE_TRANSITION_MODE).
+ RESOURCE_STATE_TRANSITION_MODE ScratchBufferTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE);
+
+ /// if false then TLAS will be built from scratch.
+ /// If true then previous content of TLAS will be updated.
+ /// pTLAS must be created with RAYTRACING_BUILD_AS_ALLOW_UPDATE flag.
+ /// An update will be faster than building an acceleration structure from scratch.
+ Bool Update DEFAULT_INITIALIZER(False);
+
+#if DILIGENT_CPP_INTERFACE
+ BuildTLASAttribs() noexcept {}
+#endif
+};
+typedef struct BuildTLASAttribs BuildTLASAttribs;
+
+
+/// This structure is used by IDeviceContext::CopyBLAS().
+struct CopyBLASAttribs
+{
+ /// Source bottom-level AS.
+ /// Access to the BLAS must be externally synchronized.
+ IBottomLevelAS* pSrc DEFAULT_INITIALIZER(nullptr);
+
+ /// Destination bottom-level AS.
+ /// If Mode is COPY_AS_MODE_COMPACT then pDst must be created with CompactedSize
+ /// that is greater or equal to the size returned by IDeviceContext::WriteBLASCompactedSize.
+ /// Access to the BLAS must be externally synchronized.
+ IBottomLevelAS* pDst DEFAULT_INITIALIZER(nullptr);
+
+ /// Acceleration structure copy mode, see Diligent::COPY_AS_MODE.
+ COPY_AS_MODE Mode DEFAULT_INITIALIZER(COPY_AS_MODE_CLONE);
+
+ /// Source bottom-level AS state transition mode (see Diligent::RESOURCE_STATE_TRANSITION_MODE).
+ RESOURCE_STATE_TRANSITION_MODE SrcTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE);
+
+ /// Destination bottom-level AS state transition mode (see Diligent::RESOURCE_STATE_TRANSITION_MODE).
+ RESOURCE_STATE_TRANSITION_MODE DstTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE);
+
+#if DILIGENT_CPP_INTERFACE
+ CopyBLASAttribs() noexcept {}
+#endif
+};
+typedef struct CopyBLASAttribs CopyBLASAttribs;
+
+
+/// This structure is used by IDeviceContext::CopyTLAS().
+struct CopyTLASAttribs
+{
+ /// Source top-level AS.
+ /// Access to the TLAS must be externally synchronized.
+ ITopLevelAS* pSrc DEFAULT_INITIALIZER(nullptr);
+
+ /// Destination top-level AS.
+ /// If Mode is COPY_AS_MODE_COMPACT then pDst must be created with CompactedSize
+ /// that is greater or equal to size that returned by IDeviceContext::WriteTLASCompactedSize.
+ /// Access to the TLAS must be externally synchronized.
+ ITopLevelAS* pDst DEFAULT_INITIALIZER(nullptr);
+
+ /// Acceleration structure copy mode, see Diligent::COPY_AS_MODE.
+ COPY_AS_MODE Mode DEFAULT_INITIALIZER(COPY_AS_MODE_CLONE);
+
+ /// Source top-level AS state transition mode (see Diligent::RESOURCE_STATE_TRANSITION_MODE).
+ RESOURCE_STATE_TRANSITION_MODE SrcTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE);
+
+ /// Destination top-level AS state transition mode (see Diligent::RESOURCE_STATE_TRANSITION_MODE).
+ RESOURCE_STATE_TRANSITION_MODE DstTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE);
+
+#if DILIGENT_CPP_INTERFACE
+ CopyTLASAttribs() noexcept {}
+#endif
+};
+typedef struct CopyTLASAttribs CopyTLASAttribs;
+
+
+/// This structure is used by IDeviceContext::WriteBLASCompactedSize().
+struct WriteBLASCompactedSizeAttribs
+{
+ /// Bottom-level AS.
+ IBottomLevelAS* pBLAS DEFAULT_INITIALIZER(nullptr);
+
+ /// The destination buffer into which a 64-bit value representing the acceleration structure compacted size will be written to.
+ IBuffer* pDestBuffer DEFAULT_INITIALIZER(nullptr);
+
+ /// Offset from the beginning of the buffer to the location of the AS compacted size.
+ Uint32 DestBufferOffset DEFAULT_INITIALIZER(0);
+
+ /// Bottom-level AS state transition mode (see Diligent::RESOURCE_STATE_TRANSITION_MODE).
+ RESOURCE_STATE_TRANSITION_MODE BLASTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE);
+
+ /// Destination buffer state transition mode (see Diligent::RESOURCE_STATE_TRANSITION_MODE).
+ RESOURCE_STATE_TRANSITION_MODE BufferTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE);
+
+#if DILIGENT_CPP_INTERFACE
+ WriteBLASCompactedSizeAttribs() noexcept {}
+#endif
+};
+typedef struct WriteBLASCompactedSizeAttribs WriteBLASCompactedSizeAttribs;
+
+
+/// This structure is used by IDeviceContext::WriteTLASCompactedSize().
+struct WriteTLASCompactedSizeAttribs
+{
+ /// Top-level AS.
+ ITopLevelAS* pTLAS DEFAULT_INITIALIZER(nullptr);
+
+ /// The destination buffer into which a 64-bit value representing the acceleration structure compacted size will be written to.
+ IBuffer* pDestBuffer DEFAULT_INITIALIZER(nullptr);
+
+ /// Offset from the beginning of the buffer to the location of the AS compacted size.
+ Uint32 DestBufferOffset DEFAULT_INITIALIZER(0);
+
+ /// Top-level AS state transition mode (see Diligent::RESOURCE_STATE_TRANSITION_MODE).
+ RESOURCE_STATE_TRANSITION_MODE TLASTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE);
+
+ /// Destination buffer state transition mode (see Diligent::RESOURCE_STATE_TRANSITION_MODE).
+ RESOURCE_STATE_TRANSITION_MODE BufferTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE);
+
+#if DILIGENT_CPP_INTERFACE
+ WriteTLASCompactedSizeAttribs() noexcept {}
+#endif
+};
+typedef struct WriteTLASCompactedSizeAttribs WriteTLASCompactedSizeAttribs;
+
+
+/// This structure is used by IDeviceContext::TraceRays().
+struct TraceRaysAttribs
+{
+ /// Shader binding table.
+ IShaderBindingTable* pSBT DEFAULT_INITIALIZER(nullptr);
+
+ Uint32 DimensionX DEFAULT_INITIALIZER(1); ///< The number of rays dispatched in X direction.
+ Uint32 DimensionY DEFAULT_INITIALIZER(1); ///< The number of rays dispatched in Y direction.
+ Uint32 DimensionZ DEFAULT_INITIALIZER(1); ///< The number of rays dispatched in Z direction.
+
+ /// Shader binding table buffer state transition mode (see Diligent::RESOURCE_STATE_TRANSITION_MODE).
+ RESOURCE_STATE_TRANSITION_MODE SBTTransitionMode DEFAULT_INITIALIZER(RESOURCE_STATE_TRANSITION_MODE_NONE);
+
+#if DILIGENT_CPP_INTERFACE
+ TraceRaysAttribs() noexcept {}
+#endif
+};
+typedef struct TraceRaysAttribs TraceRaysAttribs;
+
+
+static const Uint32 REMAINING_MIP_LEVELS = ~0u;
+static const Uint32 REMAINING_ARRAY_SLICES = ~0u;
+
+/// Resource state transition barrier description
+struct StateTransitionDesc
+{
+ /// Resource to transition.
+ /// Can be ITexture, IBuffer, IBottomLevelAS, ITopLevelAS.
+ struct IDeviceObject* pResource DEFAULT_INITIALIZER(nullptr);
+
+ /// When transitioning a texture, first mip level of the subresource range to transition.
+ Uint32 FirstMipLevel DEFAULT_INITIALIZER(0);
+
+ /// When transitioning a texture, number of mip levels of the subresource range to transition.
+ Uint32 MipLevelsCount DEFAULT_INITIALIZER(REMAINING_MIP_LEVELS);
+
+ /// When transitioning a texture, first array slice of the subresource range to transition.
+ Uint32 FirstArraySlice DEFAULT_INITIALIZER(0);
+
+ /// When transitioning a texture, number of array slices of the subresource range to transition.
+ Uint32 ArraySliceCount DEFAULT_INITIALIZER(REMAINING_ARRAY_SLICES);
+
+ /// Resource state before transition. If this value is RESOURCE_STATE_UNKNOWN,
+ /// internal resource state will be used, which must be defined in this case.
+ RESOURCE_STATE OldState DEFAULT_INITIALIZER(RESOURCE_STATE_UNKNOWN);
+
+ /// Resource state after transition.
+ RESOURCE_STATE NewState DEFAULT_INITIALIZER(RESOURCE_STATE_UNKNOWN);
+
+ /// State transition type, see Diligent::STATE_TRANSITION_TYPE.
+
+ /// \note When issuing UAV barrier (i.e. OldState and NewState equal RESOURCE_STATE_UNORDERED_ACCESS),
+ /// TransitionType must be STATE_TRANSITION_TYPE_IMMEDIATE.
+ STATE_TRANSITION_TYPE TransitionType DEFAULT_INITIALIZER(STATE_TRANSITION_TYPE_IMMEDIATE);
+
+ /// If set to true, the internal resource state will be set to NewState and the engine
+ /// will be able to take over the resource state management. In this case it is the
+ /// responsibility of the application to make sure that all subresources are indeed in
+ /// designated state.
+ /// If set to false, internal resource state will be unchanged.
+ /// \note When TransitionType is STATE_TRANSITION_TYPE_BEGIN, this member must be false.
+ bool UpdateResourceState DEFAULT_INITIALIZER(false);
+
+#if DILIGENT_CPP_INTERFACE
+ StateTransitionDesc()noexcept{}
+
+ StateTransitionDesc(ITexture* _pTexture,
+ RESOURCE_STATE _OldState,
+ RESOURCE_STATE _NewState,
+ Uint32 _FirstMipLevel = 0,
+ Uint32 _MipLevelsCount = REMAINING_MIP_LEVELS,
+ Uint32 _FirstArraySlice = 0,
+ Uint32 _ArraySliceCount = REMAINING_ARRAY_SLICES,
+ STATE_TRANSITION_TYPE _TransitionType = STATE_TRANSITION_TYPE_IMMEDIATE,
+ bool _UpdateState = false)noexcept :
+ pResource {static_cast<IDeviceObject*>(_pTexture)},
+ FirstMipLevel {_FirstMipLevel },
+ MipLevelsCount {_MipLevelsCount },
+ FirstArraySlice {_FirstArraySlice},
+ ArraySliceCount {_ArraySliceCount},
+ OldState {_OldState },
+ NewState {_NewState },
+ TransitionType {_TransitionType },
+ UpdateResourceState {_UpdateState }
+ {}
+
+ StateTransitionDesc(ITexture* _pTexture,
+ RESOURCE_STATE _OldState,
+ RESOURCE_STATE _NewState,
+ bool _UpdateState)noexcept :
+ StateTransitionDesc
+ {
+ _pTexture,
+ _OldState,
+ _NewState,
+ 0,
+ REMAINING_MIP_LEVELS,
+ 0,
+ REMAINING_ARRAY_SLICES,
+ STATE_TRANSITION_TYPE_IMMEDIATE,
+ _UpdateState
+ }
+ {}
+
+ StateTransitionDesc(IBuffer* _pBuffer,
+ RESOURCE_STATE _OldState,
+ RESOURCE_STATE _NewState,
+ bool _UpdateState)noexcept :
+ pResource {_pBuffer },
+ OldState {_OldState },
+ NewState {_NewState },
+ UpdateResourceState {_UpdateState}
+ {}
+
+ StateTransitionDesc(IBottomLevelAS* _pBLAS,
+ RESOURCE_STATE _OldState,
+ RESOURCE_STATE _NewState,
+ bool _UpdateState)noexcept :
+ pResource {_pBLAS },
+ OldState {_OldState },
+ NewState {_NewState },
+ UpdateResourceState {_UpdateState}
+ {}
+
+ StateTransitionDesc(ITopLevelAS* _pTLAS,
+ RESOURCE_STATE _OldState,
+ RESOURCE_STATE _NewState,
+ bool _UpdateState)noexcept :
+ pResource {_pTLAS },
+ OldState {_OldState },
+ NewState {_NewState },
+ UpdateResourceState {_UpdateState}
+ {}
+#endif
+};
+typedef struct StateTransitionDesc StateTransitionDesc;
+
+
#define DILIGENT_INTERFACE_NAME IDeviceContext
#include "../../../Primitives/interface/DefineInterfaceHelperMacros.h"
@@ -1497,6 +2139,67 @@ DILIGENT_BEGIN_INTERFACE(IDeviceContext, IObject)
ITexture* pSrcTexture,
ITexture* pDstTexture,
const ResolveTextureSubresourceAttribs REF ResolveAttribs) PURE;
+
+
+ /// Builds a bottom-level acceleration structure with the specified geometries.
+
+ /// \param [in] Attribs - Structure describing build BLAS command attributes, see Diligent::BuildBLASAttribs for details.
+ ///
+ /// \note Don't call build or copy operation on the same BLAS in a different contexts, because BLAS has CPU-side data
+ /// that will not match with GPU-side, so shader binding were incorrect.
+ VIRTUAL void METHOD(BuildBLAS)(THIS_
+ const BuildBLASAttribs REF Attribs) PURE;
+
+
+ /// Builds a top-level acceleration structure with the specified instances.
+
+ /// \param [in] Attribs - Structure describing build TLAS command attributes, see Diligent::BuildTLASAttribs for details.
+ ///
+ /// \note Don't call build or copy operation on the same TLAS in a different contexts, because TLAS has CPU-side data
+ /// that will not match with GPU-side, so shader binding were incorrect.
+ VIRTUAL void METHOD(BuildTLAS)(THIS_
+ const BuildTLASAttribs REF Attribs) PURE;
+
+
+ /// Copies data from one acceleration structure to another.
+
+ /// \param [in] Attribs - Structure describing copy BLAS command attributes, see Diligent::CopyBLASAttribs for details.
+ ///
+ /// \note Don't call build or copy operation on the same BLAS in a different contexts, because BLAS has CPU-side data
+ /// that will not match with GPU-side, so shader binding were incorrect.
+ VIRTUAL void METHOD(CopyBLAS)(THIS_
+ const CopyBLASAttribs REF Attribs) PURE;
+
+
+ /// Copies data from one acceleration structure to another.
+
+ /// \param [in] Attribs - Structure describing copy TLAS command attributes, see Diligent::CopyTLASAttribs for details.
+ ///
+ /// \note Don't call build or copy operation on the same TLAS in a different contexts, because TLAS has CPU-side data
+ /// that will not match with GPU-side, so shader binding were incorrect.
+ VIRTUAL void METHOD(CopyTLAS)(THIS_
+ const CopyTLASAttribs REF Attribs) PURE;
+
+
+ /// Writes a bottom-level acceleration structure memory size required for compacting operation to a buffer.
+
+ /// \param [in] Attribs - Structure describing write BLAS compacted size command attributes, see Diligent::WriteBLASCompactedSizeAttribs for details.
+ VIRTUAL void METHOD(WriteBLASCompactedSize)(THIS_
+ const WriteBLASCompactedSizeAttribs REF Attribs) PURE;
+
+
+ /// Writes a top-level acceleration structure memory size required for compacting operation to a buffer.
+
+ /// \param [in] Attribs - Structure describing write TLAS compacted size command attributes, see Diligent::WriteTLASCompactedSizeAttribs for details.
+ VIRTUAL void METHOD(WriteTLASCompactedSize)(THIS_
+ const WriteTLASCompactedSizeAttribs REF Attribs) PURE;
+
+
+ /// Executes a trace rays command.
+
+ /// \param [in] Attribs - Trace rays command attributes, see Diligent::TraceRaysAttribs for details.
+ VIRTUAL void METHOD(TraceRays)(THIS_
+ const TraceRaysAttribs REF Attribs) PURE;
};
DILIGENT_END_INTERFACE
@@ -1521,6 +2224,8 @@ DILIGENT_END_INTERFACE
# define IDeviceContext_DrawIndexed(This, ...) CALL_IFACE_METHOD(DeviceContext, DrawIndexed, This, __VA_ARGS__)
# define IDeviceContext_DrawIndirect(This, ...) CALL_IFACE_METHOD(DeviceContext, DrawIndirect, This, __VA_ARGS__)
# define IDeviceContext_DrawIndexedIndirect(This, ...) CALL_IFACE_METHOD(DeviceContext, DrawIndexedIndirect, This, __VA_ARGS__)
+# define IDeviceContext_DrawMesh(This, ...) CALL_IFACE_METHOD(DeviceContext, DrawMesh, This, __VA_ARGS__)
+# define IDeviceContext_DrawMeshIndirect(This, ...) CALL_IFACE_METHOD(DeviceContext, DrawMeshIndirect, This, __VA_ARGS__)
# define IDeviceContext_DispatchCompute(This, ...) CALL_IFACE_METHOD(DeviceContext, DispatchCompute, This, __VA_ARGS__)
# define IDeviceContext_DispatchComputeIndirect(This, ...) CALL_IFACE_METHOD(DeviceContext, DispatchComputeIndirect, This, __VA_ARGS__)
# define IDeviceContext_ClearDepthStencil(This, ...) CALL_IFACE_METHOD(DeviceContext, ClearDepthStencil, This, __VA_ARGS__)
@@ -1546,6 +2251,13 @@ DILIGENT_END_INTERFACE
# define IDeviceContext_GetFrameNumber(This) CALL_IFACE_METHOD(DeviceContext, GetFrameNumber, This)
# define IDeviceContext_TransitionResourceStates(This, ...) CALL_IFACE_METHOD(DeviceContext, TransitionResourceStates, This, __VA_ARGS__)
# define IDeviceContext_ResolveTextureSubresource(This, ...) CALL_IFACE_METHOD(DeviceContext, ResolveTextureSubresource, This, __VA_ARGS__)
+# define IDeviceContext_BuildBLAS(This, ...) CALL_IFACE_METHOD(DeviceContext, BuildBLAS, This, __VA_ARGS__)
+# define IDeviceContext_BuildTLAS(This, ...) CALL_IFACE_METHOD(DeviceContext, BuildTLAS, This, __VA_ARGS__)
+# define IDeviceContext_CopyBLAS(This, ...) CALL_IFACE_METHOD(DeviceContext, CopyBLAS, This, __VA_ARGS__)
+# define IDeviceContext_CopyTLAS(This, ...) CALL_IFACE_METHOD(DeviceContext, CopyTLAS, This, __VA_ARGS__)
+# define IDeviceContext_WriteBLASCompactedSize(This, ...) CALL_IFACE_METHOD(DeviceContext, WriteBLASCompactedSize, This, __VA_ARGS__)
+# define IDeviceContext_WriteTLASCompactedSize(This, ...) CALL_IFACE_METHOD(DeviceContext, WriteTLASCompactedSize, This, __VA_ARGS__)
+# define IDeviceContext_TraceRays(This, ...) CALL_IFACE_METHOD(DeviceContext, TraceRays, This, __VA_ARGS__)
// clang-format on
diff --git a/Graphics/GraphicsEngine/interface/GraphicsTypes.h b/Graphics/GraphicsEngine/interface/GraphicsTypes.h
index 816d8194..701d4f14 100644
--- a/Graphics/GraphicsEngine/interface/GraphicsTypes.h
+++ b/Graphics/GraphicsEngine/interface/GraphicsTypes.h
@@ -41,9 +41,6 @@
/// Graphics engine namespace
DILIGENT_BEGIN_NAMESPACE(Diligent)
-struct ITexture;
-struct IBuffer;
-
/// Value type
/// This enumeration describes value type. It is used by
@@ -73,19 +70,22 @@ DILIGENT_TYPED_ENUM(VALUE_TYPE, Uint8)
/// - TextureDesc to describe bind flags for a texture
DILIGENT_TYPED_ENUM(BIND_FLAGS, Uint32)
{
- BIND_NONE = 0x0L, ///< Undefined binding
- BIND_VERTEX_BUFFER = 0x1L, ///< A buffer can be bound as a vertex buffer
- BIND_INDEX_BUFFER = 0x2L, ///< A buffer can be bound as an index buffer
- BIND_UNIFORM_BUFFER = 0x4L, ///< A buffer can be bound as a uniform buffer
- /// \warning This flag may not be combined with any other bind flag
- BIND_SHADER_RESOURCE = 0x8L, ///< A buffer or a texture can be bound as a shader resource
- /// \warning This flag cannot be used with MAP_WRITE_NO_OVERWRITE flag
- BIND_STREAM_OUTPUT = 0x10L,///< A buffer can be bound as a target for stream output stage
- BIND_RENDER_TARGET = 0x20L,///< A texture can be bound as a render target
- BIND_DEPTH_STENCIL = 0x40L,///< A texture can be bound as a depth-stencil target
- BIND_UNORDERED_ACCESS = 0x80L,///< A buffer or a texture can be bound as an unordered access view
- BIND_INDIRECT_DRAW_ARGS = 0x100L,///< A buffer can be bound as the source buffer for indirect draw commands
- BIND_INPUT_ATTACHMENT = 0x200L ///< A texture can be used as render pass input attachment
+ BIND_NONE = 0x0L, ///< Undefined binding
+ BIND_VERTEX_BUFFER = 0x1L, ///< A buffer can be bound as a vertex buffer
+ BIND_INDEX_BUFFER = 0x2L, ///< A buffer can be bound as an index buffer
+ BIND_UNIFORM_BUFFER = 0x4L, ///< A buffer can be bound as a uniform buffer
+ /// \warning This flag may not be combined with any other bind flag
+ BIND_SHADER_RESOURCE = 0x8L, ///< A buffer or a texture can be bound as a shader resource
+ /// \warning This flag cannot be used with MAP_WRITE_NO_OVERWRITE flag
+ BIND_STREAM_OUTPUT = 0x10L, ///< A buffer can be bound as a target for stream output stage
+ BIND_RENDER_TARGET = 0x20L, ///< A texture can be bound as a render target
+ BIND_DEPTH_STENCIL = 0x40L, ///< A texture can be bound as a depth-stencil target
+ BIND_UNORDERED_ACCESS = 0x80L, ///< A buffer or a texture can be bound as an unordered access view
+ BIND_INDIRECT_DRAW_ARGS = 0x100L, ///< A buffer can be bound as the source buffer for indirect draw commands
+ BIND_INPUT_ATTACHMENT = 0x200L, ///< A texture can be used as render pass input attachment
+ BIND_RAY_TRACING = 0x400L, ///< A buffer can be used as a scratch buffer or as the source of primitive data
+ /// for acceleration structure building
+ BIND_FLAGS_LAST = 0x400L
};
DEFINE_FLAG_ENUM_OPERATORS(BIND_FLAGS)
@@ -1251,16 +1251,18 @@ typedef struct DisplayModeAttribs DisplayModeAttribs;
DILIGENT_TYPED_ENUM(SWAP_CHAIN_USAGE_FLAGS, Uint32)
{
/// No allowed usage
- SWAP_CHAIN_USAGE_NONE = 0x00L,
+ SWAP_CHAIN_USAGE_NONE = 0x00L,
/// Swap chain can be used as render target ouput
- SWAP_CHAIN_USAGE_RENDER_TARGET = 0x01L,
+ SWAP_CHAIN_USAGE_RENDER_TARGET = 0x01L,
/// Swap chain images can be used as shader inputs
- SWAP_CHAIN_USAGE_SHADER_INPUT = 0x02L,
+ SWAP_CHAIN_USAGE_SHADER_INPUT = 0x02L,
/// Swap chain images can be used as source of copy operation
- SWAP_CHAIN_USAGE_COPY_SOURCE = 0x04L
+ SWAP_CHAIN_USAGE_COPY_SOURCE = 0x04L,
+
+ SWAP_CHAIN_USAGE_LAST = SWAP_CHAIN_USAGE_COPY_SOURCE,
};
DEFINE_FLAG_ENUM_OPERATORS(SWAP_CHAIN_USAGE_FLAGS)
@@ -1553,6 +1555,9 @@ struct DeviceFeatures
/// Indicates if device supports mesh and amplification shaders
DEVICE_FEATURE_STATE MeshShaders DEFAULT_INITIALIZER(DEVICE_FEATURE_STATE_DISABLED);
+
+ /// Indicates if device supports ray tracing shaders
+ DEVICE_FEATURE_STATE RayTracing DEFAULT_INITIALIZER(DEVICE_FEATURE_STATE_DISABLED);
/// Indicates if device supports bindless resources
DEVICE_FEATURE_STATE BindlessResources DEFAULT_INITIALIZER(DEVICE_FEATURE_STATE_DISABLED);
@@ -1642,6 +1647,7 @@ struct DeviceFeatures
GeometryShaders {State},
Tessellation {State},
MeshShaders {State},
+ RayTracing {State},
BindlessResources {State},
OcclusionQueries {State},
BinaryOcclusionQueries {State},
@@ -1666,7 +1672,7 @@ struct DeviceFeatures
UniformBuffer8BitAccess {State}
{
# if defined(_MSC_VER) && defined(_WIN64)
- static_assert(sizeof(*this) == 31, "Did you add a new feature to DeviceFeatures? Please handle its status above.");
+ static_assert(sizeof(*this) == 32, "Did you add a new feature to DeviceFeatures? Please handle its status above.");
# endif
}
#endif
@@ -1849,6 +1855,15 @@ struct DeviceCaps
typedef struct DeviceCaps DeviceCaps;
+/// Device properties
+struct DeviceProperties
+{
+ /// Maximum supported value for RayTracingPipelineDesc::MaxRecursionDepth.
+ Uint32 MaxRayTracingRecursionDepth;
+};
+typedef struct DeviceProperties DeviceProperties;
+
+
/// Engine creation attibutes
struct EngineCreateInfo
{
@@ -1885,8 +1900,8 @@ typedef struct EngineCreateInfo EngineCreateInfo;
/// Attributes of the OpenGL-based engine implementation
struct EngineGLCreateInfo DILIGENT_DERIVE(EngineCreateInfo)
- /// Native window wrapper
- NativeWindow Window;
+ /// Native window wrapper
+ NativeWindow Window;
/// Create debug OpenGL context and enable debug output.
@@ -2118,6 +2133,7 @@ struct VulkanDescriptorPoolSize
Uint32 NumUniformTexelBufferDescriptors DEFAULT_INITIALIZER(0);
Uint32 NumStorageTexelBufferDescriptors DEFAULT_INITIALIZER(0);
Uint32 NumInputAttachmentDescriptors DEFAULT_INITIALIZER(0);
+ Uint32 NumAccelStructDescriptors DEFAULT_INITIALIZER(0);
#if DILIGENT_CPP_INTERFACE
VulkanDescriptorPoolSize()noexcept {}
@@ -2131,7 +2147,8 @@ struct VulkanDescriptorPoolSize
Uint32 _NumStorageBufferDescriptors,
Uint32 _NumUniformTexelBufferDescriptors,
Uint32 _NumStorageTexelBufferDescriptors,
- Uint32 _NumInputAttachmentDescriptors)noexcept :
+ Uint32 _NumInputAttachmentDescriptors,
+ Uint32 _NumAccelStructDescriptors)noexcept :
MaxDescriptorSets {_MaxDescriptorSets },
NumSeparateSamplerDescriptors {_NumSeparateSamplerDescriptors },
NumCombinedSamplerDescriptors {_NumCombinedSamplerDescriptors },
@@ -2141,7 +2158,8 @@ struct VulkanDescriptorPoolSize
NumStorageBufferDescriptors {_NumStorageBufferDescriptors },
NumUniformTexelBufferDescriptors{_NumUniformTexelBufferDescriptors},
NumStorageTexelBufferDescriptors{_NumStorageTexelBufferDescriptors},
- NumInputAttachmentDescriptors {_NumInputAttachmentDescriptors }
+ NumInputAttachmentDescriptors {_NumInputAttachmentDescriptors },
+ NumAccelStructDescriptors {_NumAccelStructDescriptors }
{
// On clang aggregate initialization fails to compile if
// structure members have default initializers
@@ -2179,8 +2197,8 @@ struct EngineVkCreateInfo DILIGENT_DERIVE(EngineCreateInfo)
/// the engine creates another one.
VulkanDescriptorPoolSize MainDescriptorPoolSize
#if DILIGENT_CPP_INTERFACE
- //Max SepSm CmbSm SmpImg StrImg UB SB UTxB StTxB InptAtt
- {8192, 1024, 8192, 8192, 1024, 4096, 4096, 1024, 1024, 256}
+ //Max SepSm CmbSm SmpImg StrImg UB SB UTxB StTxB InptAtt AccelSt
+ {8192, 1024, 8192, 8192, 1024, 4096, 4096, 1024, 1024, 256, 256}
#endif
;
@@ -2191,8 +2209,8 @@ struct EngineVkCreateInfo DILIGENT_DERIVE(EngineCreateInfo)
VulkanDescriptorPoolSize DynamicDescriptorPoolSize
#if DILIGENT_CPP_INTERFACE
- //Max SepSm CmbSm SmpImg StrImg UB SB UTxB StTxB InptAtt
- {2048, 256, 2048, 2048, 256, 1024, 1024, 256, 256, 64}
+ //Max SepSm CmbSm SmpImg StrImg UB SB UTxB StTxB InptAtt AccelSt
+ {2048, 256, 2048, 2048, 256, 1024, 1024, 256, 256, 64, 64}
#endif
;
@@ -2697,16 +2715,16 @@ DILIGENT_TYPED_ENUM(RESOURCE_STATE, Uint32)
/// The resource state is known to the engine, but is undefined. A resource is typically in an undefined state right after initialization.
RESOURCE_STATE_UNDEFINED = 0x00001,
- /// The resource is accessed as vertex buffer
+ /// The resource is accessed as a vertex buffer
RESOURCE_STATE_VERTEX_BUFFER = 0x00002,
- /// The resource is accessed as constant (uniform) buffer
+ /// The resource is accessed as a constant (uniform) buffer
RESOURCE_STATE_CONSTANT_BUFFER = 0x00004,
- /// The resource is accessed as index buffer
+ /// The resource is accessed as an index buffer
RESOURCE_STATE_INDEX_BUFFER = 0x00008,
- /// The resource is accessed as render target
+ /// The resource is accessed as a render target
RESOURCE_STATE_RENDER_TARGET = 0x00010,
/// The resource is used for unordered access
@@ -2724,7 +2742,7 @@ DILIGENT_TYPED_ENUM(RESOURCE_STATE, Uint32)
/// The resource is used as the destination for stream output
RESOURCE_STATE_STREAM_OUT = 0x00200,
- /// The resource is used as indirect draw/dispatch arguments buffer
+ /// The resource is used as an indirect draw/dispatch arguments buffer
RESOURCE_STATE_INDIRECT_ARGUMENT = 0x00400,
/// The resource is used as the destination in a copy operation
@@ -2739,13 +2757,23 @@ DILIGENT_TYPED_ENUM(RESOURCE_STATE, Uint32)
/// The resource is used as the source in a resolve operation
RESOURCE_STATE_RESOLVE_SOURCE = 0x04000,
- /// The resource is used as input attachment in a render pass subpass
+ /// The resource is used as an input attachment in a render pass subpass
RESOURCE_STATE_INPUT_ATTACHMENT = 0x08000,
/// The resource is used for present
RESOURCE_STATE_PRESENT = 0x10000,
- RESOURCE_STATE_MAX_BIT = 0x10000,
+ /// The resource is used as vertex/index/instance buffer in an AS building operation
+ /// or as an acceleration structure source in an AS copy operation.
+ RESOURCE_STATE_BUILD_AS_READ = 0x20000,
+
+ /// The resource is used as the target for AS building or AS copy operations.
+ RESOURCE_STATE_BUILD_AS_WRITE = 0x40000,
+
+ /// The resource is used as a top-level AS shader resource in a trace rays operation.
+ RESOURCE_STATE_RAY_TRACING = 0x80000,
+
+ RESOURCE_STATE_MAX_BIT = RESOURCE_STATE_RAY_TRACING,
RESOURCE_STATE_GENERIC_READ = RESOURCE_STATE_VERTEX_BUFFER |
RESOURCE_STATE_CONSTANT_BUFFER |
@@ -2775,105 +2803,4 @@ DILIGENT_TYPED_ENUM(STATE_TRANSITION_TYPE, Uint8)
STATE_TRANSITION_TYPE_END
};
-static const Uint32 REMAINING_MIP_LEVELS = 0xFFFFFFFFU;
-static const Uint32 REMAINING_ARRAY_SLICES = 0xFFFFFFFFU;
-
-/// Resource state transition barrier description
-struct StateTransitionDesc
-{
- /// Texture to transition.
- /// \note Exactly one of pTexture or pBuffer must be non-null.
- struct ITexture* pTexture DEFAULT_INITIALIZER(nullptr);
-
- /// Buffer to transition.
- /// \note Exactly one of pTexture or pBuffer must be non-null.
- struct IBuffer* pBuffer DEFAULT_INITIALIZER(nullptr);
-
- /// When transitioning a texture, first mip level of the subresource range to transition.
- Uint32 FirstMipLevel DEFAULT_INITIALIZER(0);
-
- /// When transitioning a texture, number of mip levels of the subresource range to transition.
- Uint32 MipLevelsCount DEFAULT_INITIALIZER(REMAINING_MIP_LEVELS);
-
- /// When transitioning a texture, first array slice of the subresource range to transition.
- Uint32 FirstArraySlice DEFAULT_INITIALIZER(0);
-
- /// When transitioning a texture, number of array slices of the subresource range to transition.
- Uint32 ArraySliceCount DEFAULT_INITIALIZER(REMAINING_ARRAY_SLICES);
-
- /// Resource state before transition. If this value is RESOURCE_STATE_UNKNOWN,
- /// internal resource state will be used, which must be defined in this case.
- RESOURCE_STATE OldState DEFAULT_INITIALIZER(RESOURCE_STATE_UNKNOWN);
-
- /// Resource state after transition.
- RESOURCE_STATE NewState DEFAULT_INITIALIZER(RESOURCE_STATE_UNKNOWN);
-
- /// State transition type, see Diligent::STATE_TRANSITION_TYPE.
-
- /// \note When issuing UAV barrier (i.e. OldState and NewState equal RESOURCE_STATE_UNORDERED_ACCESS),
- /// TransitionType must be STATE_TRANSITION_TYPE_IMMEDIATE.
- STATE_TRANSITION_TYPE TransitionType DEFAULT_INITIALIZER(STATE_TRANSITION_TYPE_IMMEDIATE);
-
- /// If set to true, the internal resource state will be set to NewState and the engine
- /// will be able to take over the resource state management. In this case it is the
- /// responsibility of the application to make sure that all subresources are indeed in
- /// designated state.
- /// If set to false, internal resource state will be unchanged.
- /// \note When TransitionType is STATE_TRANSITION_TYPE_BEGIN, this member must be false.
- bool UpdateResourceState DEFAULT_INITIALIZER(false);
-
-#if DILIGENT_CPP_INTERFACE
- StateTransitionDesc()noexcept{}
-
- StateTransitionDesc(ITexture* _pTexture,
- RESOURCE_STATE _OldState,
- RESOURCE_STATE _NewState,
- Uint32 _FirstMipLevel = 0,
- Uint32 _MipLevelsCount = REMAINING_MIP_LEVELS,
- Uint32 _FirstArraySlice = 0,
- Uint32 _ArraySliceCount = REMAINING_ARRAY_SLICES,
- STATE_TRANSITION_TYPE _TransitionType = STATE_TRANSITION_TYPE_IMMEDIATE,
- bool _UpdateState = false)noexcept :
- pTexture {_pTexture },
- FirstMipLevel {_FirstMipLevel },
- MipLevelsCount {_MipLevelsCount },
- FirstArraySlice {_FirstArraySlice},
- ArraySliceCount {_ArraySliceCount},
- OldState {_OldState },
- NewState {_NewState },
- TransitionType {_TransitionType },
- UpdateResourceState {_UpdateState }
- {}
-
- StateTransitionDesc(ITexture* _pTexture,
- RESOURCE_STATE _OldState,
- RESOURCE_STATE _NewState,
- bool _UpdateState)noexcept :
- StateTransitionDesc
- {
- _pTexture,
- _OldState,
- _NewState,
- 0,
- REMAINING_MIP_LEVELS,
- 0,
- REMAINING_ARRAY_SLICES,
- STATE_TRANSITION_TYPE_IMMEDIATE,
- _UpdateState
- }
- {}
-
- StateTransitionDesc(IBuffer* _pBuffer,
- RESOURCE_STATE _OldState,
- RESOURCE_STATE _NewState,
- bool _UpdateState)noexcept :
- pBuffer {_pBuffer },
- OldState {_OldState },
- NewState {_NewState },
- UpdateResourceState {_UpdateState}
- {}
-#endif
-};
-typedef struct StateTransitionDesc StateTransitionDesc;
-
DILIGENT_END_NAMESPACE // namespace Diligent
diff --git a/Graphics/GraphicsEngine/interface/PipelineState.h b/Graphics/GraphicsEngine/interface/PipelineState.h
index 2d889c61..875c6a21 100644
--- a/Graphics/GraphicsEngine/interface/PipelineState.h
+++ b/Graphics/GraphicsEngine/interface/PipelineState.h
@@ -152,7 +152,7 @@ typedef struct PipelineResourceLayoutDesc PipelineResourceLayoutDesc;
/// Graphics pipeline state description
-/// This structure describes the graphics pipeline state and is part of the PipelineStateDesc structure.
+/// This structure describes the graphics pipeline state and is part of the GraphicsPipelineStateCreateInfo structure.
struct GraphicsPipelineDesc
{
/// Blend state description.
@@ -215,6 +215,107 @@ struct GraphicsPipelineDesc
typedef struct GraphicsPipelineDesc GraphicsPipelineDesc;
+/// Ray tracing general shader group description
+struct RayTracingGeneralShaderGroup
+{
+ /// Unique group name.
+ const char* Name DEFAULT_INITIALIZER(nullptr);
+
+ /// Shader type must be SHADER_TYPE_RAY_GEN, SHADER_TYPE_RAY_MISS or SHADER_TYPE_CALLABLE.
+ IShader* pShader DEFAULT_INITIALIZER(nullptr);
+
+#if DILIGENT_CPP_INTERFACE
+ RayTracingGeneralShaderGroup() noexcept
+ {}
+
+ RayTracingGeneralShaderGroup(const char* _Name,
+ IShader* _pShader) noexcept:
+ Name {_Name },
+ pShader{_pShader}
+ {}
+#endif
+};
+typedef struct RayTracingGeneralShaderGroup RayTracingGeneralShaderGroup;
+
+/// Ray tracing triangle hit shader group description.
+struct RayTracingTriangleHitShaderGroup
+{
+ /// Unique group name.
+ const char* Name DEFAULT_INITIALIZER(nullptr);
+
+ /// Closest hit shader.
+ /// The shader type must be SHADER_TYPE_RAY_CLOSEST_HIT.
+ IShader* pClosestHitShader DEFAULT_INITIALIZER(nullptr);
+
+ /// Any-hit shader. Can be null.
+ /// The shader type must be SHADER_TYPE_RAY_ANY_HIT.
+ IShader* pAnyHitShader DEFAULT_INITIALIZER(nullptr); // can be null
+
+#if DILIGENT_CPP_INTERFACE
+ RayTracingTriangleHitShaderGroup() noexcept
+ {}
+
+ RayTracingTriangleHitShaderGroup(const char* _Name,
+ IShader* _pClosestHitShader,
+ IShader* _pAnyHitShader = nullptr) noexcept:
+ Name {_Name },
+ pClosestHitShader{_pClosestHitShader},
+ pAnyHitShader {_pAnyHitShader }
+ {}
+#endif
+};
+typedef struct RayTracingTriangleHitShaderGroup RayTracingTriangleHitShaderGroup;
+
+/// Ray tracing procedural hit shader group description.
+struct RayTracingProceduralHitShaderGroup
+{
+ /// Unique group name.
+ const char* Name DEFAULT_INITIALIZER(nullptr);
+
+ /// Intersection shader.
+ /// The shader type must be SHADER_TYPE_RAY_INTERSECTION.
+ IShader* pIntersectionShader DEFAULT_INITIALIZER(nullptr);
+
+ /// Closest hit shader. Can be null.
+ /// The shader type must be SHADER_TYPE_RAY_CLOSEST_HIT.
+ IShader* pClosestHitShader DEFAULT_INITIALIZER(nullptr);
+
+ /// Any-hit shader. Can be null.
+ /// The shader type must be SHADER_TYPE_RAY_ANY_HIT.
+ IShader* pAnyHitShader DEFAULT_INITIALIZER(nullptr);
+
+#if DILIGENT_CPP_INTERFACE
+ RayTracingProceduralHitShaderGroup() noexcept
+ {}
+
+ RayTracingProceduralHitShaderGroup(const char* _Name,
+ IShader* _pIntersectionShader,
+ IShader* _pClosestHitShader = nullptr,
+ IShader* _pAnyHitShader = nullptr) noexcept:
+ Name {_Name },
+ pIntersectionShader{_pIntersectionShader},
+ pClosestHitShader {_pClosestHitShader },
+ pAnyHitShader {_pAnyHitShader }
+ {}
+#endif
+};
+typedef struct RayTracingProceduralHitShaderGroup RayTracingProceduralHitShaderGroup;
+
+/// This structure describes the ray tracing pipeline state and is part of the RayTracingPipelineStateCreateInfo structure.
+struct RayTracingPipelineDesc
+{
+ /// Size of the additional data passed to the shader.
+ /// Shader record size plus shader group size (32 bytes) must be aligned to 32 bytes.
+ /// Shader record size plus shader group size (32 bytes) must not exceed 4096 bytes.
+ Uint16 ShaderRecordSize DEFAULT_INITIALIZER(0);
+
+ /// Number of recursive calls of TraceRay() in HLSL or traceRay() in GLSL.
+ /// Zero means no tracing of rays at all, only ray-gen shader will be executed.
+ /// See DeviceProperties::MaxRayTracingRecursionDepth.
+ Uint8 MaxRecursionDepth DEFAULT_INITIALIZER(0);
+};
+typedef struct RayTracingPipelineDesc RayTracingPipelineDesc;
+
/// Pipeline type
DILIGENT_TYPED_ENUM(PIPELINE_TYPE, Uint8)
{
@@ -227,6 +328,11 @@ DILIGENT_TYPED_ENUM(PIPELINE_TYPE, Uint8)
/// Mesh pipeline, which is used by IDeviceContext::DrawMesh(), IDeviceContext::DrawMeshIndirect().
PIPELINE_TYPE_MESH,
+
+ /// Ray tracing pipeline, which is used by IDeviceContext::TraceRays().
+ PIPELINE_TYPE_RAY_TRACING,
+
+ PIPELINE_TYPE_LAST = PIPELINE_TYPE_RAY_TRACING
};
@@ -251,6 +357,7 @@ struct PipelineStateDesc DILIGENT_DERIVE(DeviceObjectAttribs)
#if DILIGENT_CPP_INTERFACE
bool IsAnyGraphicsPipeline() const { return PipelineType == PIPELINE_TYPE_GRAPHICS || PipelineType == PIPELINE_TYPE_MESH; }
bool IsComputePipeline() const { return PipelineType == PIPELINE_TYPE_COMPUTE; }
+ bool IsRayTracingPipeline() const { return PipelineType == PIPELINE_TYPE_RAY_TRACING; }
#endif
};
typedef struct PipelineStateDesc PipelineStateDesc;
@@ -339,6 +446,48 @@ struct ComputePipelineStateCreateInfo DILIGENT_DERIVE(PipelineStateCreateInfo)
typedef struct ComputePipelineStateCreateInfo ComputePipelineStateCreateInfo;
+/// Ray tracing pipeline state description.
+struct RayTracingPipelineStateCreateInfo DILIGENT_DERIVE(PipelineStateCreateInfo)
+
+ /// Ray tracing pipeline description.
+ RayTracingPipelineDesc RayTracingPipeline;
+
+ /// A pointer to an array of GeneralShaderCount RayTracingGeneralShaderGroup structures that contain shader group description.
+ const RayTracingGeneralShaderGroup* pGeneralShaders DEFAULT_INITIALIZER(nullptr);
+
+ /// The number of general shader groups.
+ Uint32 GeneralShaderCount DEFAULT_INITIALIZER(0);
+
+ /// A pointer to an array of TriangleHitShaderCount RayTracingTriangleHitShaderGroup structures that contain shader group description.
+ /// Can be null.
+ const RayTracingTriangleHitShaderGroup* pTriangleHitShaders DEFAULT_INITIALIZER(nullptr);
+
+ /// The number of triangle hit shader groups.
+ Uint32 TriangleHitShaderCount DEFAULT_INITIALIZER(0);
+
+ /// A pointer to an array of ProceduralHitShaderCount RayTracingProceduralHitShaderGroup structures that contain shader group description.
+ /// Can be null.
+ const RayTracingProceduralHitShaderGroup* pProceduralHitShaders DEFAULT_INITIALIZER(nullptr);
+
+ /// The number of procedural shader groups.
+ Uint32 ProceduralHitShaderCount DEFAULT_INITIALIZER(0);
+
+ /// Direct3D12 only: the name of the constant buffer that will be used by the local root signature.
+ /// Ignored if RayTracingPipelineDesc::ShaderRecordSize is zero.
+ /// In Vulkan backend in HLSL add [[vk::shader_record_nv]] attribute to the constant buffer, in GLSL add shaderRecord layout to buffer.
+ const char* pShaderRecordName DEFAULT_INITIALIZER(nullptr);
+
+ /// Direct3D12 only: the maximum hit shader attribute size in bytes.
+ /// If zero then maximum allowed size will be used.
+ Uint32 MaxAttributeSize DEFAULT_INITIALIZER(0);
+
+ /// Direct3D12 only: the maximum payload size in bytes.
+ /// If zero then maximum allowed size will be used.
+ Uint32 MaxPayloadSize DEFAULT_INITIALIZER(0);
+};
+typedef struct RayTracingPipelineStateCreateInfo RayTracingPipelineStateCreateInfo;
+
+
// {06084AE5-6A71-4FE8-84B9-395DD489A28C}
static const struct INTERFACE_ID IID_PipelineState =
{0x6084ae5, 0x6a71, 0x4fe8, {0x84, 0xb9, 0x39, 0x5d, 0xd4, 0x89, 0xa2, 0x8c}};
@@ -363,6 +512,10 @@ DILIGENT_BEGIN_INTERFACE(IPipelineState, IDeviceObject)
/// Returns the graphics pipeline description used to create the object.
/// This method must only be called for a graphics or mesh pipeline.
VIRTUAL const GraphicsPipelineDesc REF METHOD(GetGraphicsPipelineDesc)(THIS) CONST PURE;
+
+ /// Returns the ray tracing pipeline description used to create the object.
+ /// This method must only be called for a ray tracing pipeline.
+ VIRTUAL const RayTracingPipelineDesc REF METHOD(GetRayTracingPipelineDesc)(THIS) CONST PURE;
/// Binds resources for all shaders in the pipeline state
@@ -453,6 +606,7 @@ DILIGENT_END_INTERFACE
# define IPipelineState_GetDesc(This) (const struct PipelineStateDesc*)IDeviceObject_GetDesc(This)
# define IPipelineState_GetGraphicsPipelineDesc(This) CALL_IFACE_METHOD(PipelineState, GetGraphicsPipelineDesc, This)
+# define IPipelineState_GetRayTracingPipelineDesc(This) CALL_IFACE_METHOD(PipelineState, GetRayTracingPipelineDesc, This)
# define IPipelineState_BindStaticResources(This, ...) CALL_IFACE_METHOD(PipelineState, BindStaticResources, This, __VA_ARGS__)
# define IPipelineState_GetStaticVariableCount(This, ...) CALL_IFACE_METHOD(PipelineState, GetStaticVariableCount, This, __VA_ARGS__)
# define IPipelineState_GetStaticVariableByName(This, ...) CALL_IFACE_METHOD(PipelineState, GetStaticVariableByName, This, __VA_ARGS__)
diff --git a/Graphics/GraphicsEngine/interface/RenderDevice.h b/Graphics/GraphicsEngine/interface/RenderDevice.h
index 47c759db..deaaab71 100644
--- a/Graphics/GraphicsEngine/interface/RenderDevice.h
+++ b/Graphics/GraphicsEngine/interface/RenderDevice.h
@@ -47,6 +47,9 @@
#include "Query.h"
#include "RenderPass.h"
#include "Framebuffer.h"
+#include "BottomLevelAS.h"
+#include "TopLevelAS.h"
+#include "ShaderBindingTable.h"
#include "DepthStencilState.h"
#include "RasterizerState.h"
@@ -174,6 +177,17 @@ DILIGENT_BEGIN_INTERFACE(IRenderDevice, IObject)
VIRTUAL void METHOD(CreateComputePipelineState)(THIS_
const ComputePipelineStateCreateInfo REF PSOCreateInfo,
IPipelineState** ppPipelineState) PURE;
+
+ /// Creates a new ray tracing pipeline state object
+
+ /// \param [in] PSOCreateInfo - Ray tracing pipeline state create info, see Diligent::RayTracingPipelineStateCreateInfo for details.
+ /// \param [out] ppPipelineState - Address of the memory location where the pointer to the
+ /// pipeline state interface will be stored.
+ /// The function calls AddRef(), so that the new object will contain
+ /// one reference.
+ VIRTUAL void METHOD(CreateRayTracingPipelineState)(THIS_
+ const RayTracingPipelineStateCreateInfo REF PSOCreateInfo,
+ IPipelineState** ppPipelineState) PURE;
/// Creates a new fence object
@@ -224,8 +238,47 @@ DILIGENT_BEGIN_INTERFACE(IRenderDevice, IObject)
IFramebuffer** ppFramebuffer) PURE;
+ /// Creates a bottom-level acceleration structure object (BLAS).
+
+ /// \param [in] Desc - BLAS description, see Diligent::BottomLevelASDesc for details.
+ /// \param [out] ppBLAS - Address of the memory location where the pointer to the
+ /// BLAS interface will be stored.
+ /// The function calls AddRef(), so that the new object will contain
+ /// one reference.
+ VIRTUAL void METHOD(CreateBLAS)(THIS_
+ const BottomLevelASDesc REF Desc,
+ IBottomLevelAS** ppBLAS) PURE;
+
+
+ /// Creates a top-level acceleration structure object (TLAS).
+
+ /// \param [in] Desc - TLAS description, see Diligent::TopLevelASDesc for details.
+ /// \param [out] ppTLAS - Address of the memory location where the pointer to the
+ /// TLAS interface will be stored.
+ /// The function calls AddRef(), so that the new object will contain
+ /// one reference.
+ VIRTUAL void METHOD(CreateTLAS)(THIS_
+ const TopLevelASDesc REF Desc,
+ ITopLevelAS** ppTLAS) PURE;
+
+
+ /// Creates a shader resource binding table object (SBT).
+
+ /// \param [in] Desc - SBT description, see Diligent::ShaderBindingTableDesc for details.
+ /// \param [out] ppSBT - Address of the memory location where the pointer to the
+ /// SBT interface will be stored.
+ /// The function calls AddRef(), so that the new object will contain
+ /// one reference.
+ VIRTUAL void METHOD(CreateSBT)(THIS_
+ const ShaderBindingTableDesc REF Desc,
+ IShaderBindingTable** ppSBT) PURE;
+
+
/// Gets the device capabilities, see Diligent::DeviceCaps for details
VIRTUAL const DeviceCaps REF METHOD(GetDeviceCaps)(THIS) CONST PURE;
+
+ /// Gets the device properties, see Diligent::DeviceProperties for details
+ VIRTUAL const DeviceProperties REF METHOD(GetDeviceProperties)(THIS) CONST PURE;
/// Returns the basic texture format information.
@@ -282,25 +335,24 @@ DILIGENT_END_INTERFACE
#if DILIGENT_C_INTERFACE
// clang-format off
-
-# define IRenderDevice_CreateBuffer(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateBuffer, This, __VA_ARGS__)
-# define IRenderDevice_CreateShader(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateShader, This, __VA_ARGS__)
-# define IRenderDevice_CreateTexture(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateTexture, This, __VA_ARGS__)
-# define IRenderDevice_CreateSampler(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateSampler, This, __VA_ARGS__)
-# define IRenderDevice_CreateResourceMapping(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateResourceMapping, This, __VA_ARGS__)
-# define IRenderDevice_CreateGraphicsPipelineState(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateGraphicsPipelineState, This, __VA_ARGS__)
-# define IRenderDevice_CreateComputePipelineState(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateComputePipelineState, This, __VA_ARGS__)
-# define IRenderDevice_CreateFence(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateFence, This, __VA_ARGS__)
-# define IRenderDevice_CreateQuery(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateQuery, This, __VA_ARGS__)
-# define IRenderDevice_CreateRenderPass(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateRenderPass, This, __VA_ARGS__)
-# define IRenderDevice_CreateFramebuffer(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateFramebuffer, This, __VA_ARGS__)
-# define IRenderDevice_GetDeviceCaps(This) CALL_IFACE_METHOD(RenderDevice, GetDeviceCaps, This)
-# define IRenderDevice_GetTextureFormatInfo(This, ...) CALL_IFACE_METHOD(RenderDevice, GetTextureFormatInfo, This, __VA_ARGS__)
-# define IRenderDevice_GetTextureFormatInfoExt(This, ...) CALL_IFACE_METHOD(RenderDevice, GetTextureFormatInfoExt, This, __VA_ARGS__)
-# define IRenderDevice_ReleaseStaleResources(This, ...) CALL_IFACE_METHOD(RenderDevice, ReleaseStaleResources, This, __VA_ARGS__)
-# define IRenderDevice_IdleGPU(This) CALL_IFACE_METHOD(RenderDevice, IdleGPU, This)
-# define IRenderDevice_GetEngineFactory(This) CALL_IFACE_METHOD(RenderDevice, GetEngineFactory, This)
-
+# define IRenderDevice_CreateBuffer(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateBuffer, This, __VA_ARGS__)
+# define IRenderDevice_CreateShader(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateShader, This, __VA_ARGS__)
+# define IRenderDevice_CreateTexture(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateTexture, This, __VA_ARGS__)
+# define IRenderDevice_CreateSampler(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateSampler, This, __VA_ARGS__)
+# define IRenderDevice_CreateResourceMapping(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateResourceMapping, This, __VA_ARGS__)
+# define IRenderDevice_CreateGraphicsPipelineState(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateGraphicsPipelineState, This, __VA_ARGS__)
+# define IRenderDevice_CreateComputePipelineState(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateComputePipelineState, This, __VA_ARGS__)
+# define IRenderDevice_CreateRayTracingPipelineState(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateRayTracingPipelineState, This, __VA_ARGS__)
+# define IRenderDevice_CreateFence(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateFence, This, __VA_ARGS__)
+# define IRenderDevice_CreateQuery(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateQuery, This, __VA_ARGS__)
+# define IRenderDevice_CreateRenderPass(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateRenderPass, This, __VA_ARGS__)
+# define IRenderDevice_CreateFramebuffer(This, ...) CALL_IFACE_METHOD(RenderDevice, CreateFramebuffer, This, __VA_ARGS__)
+# define IRenderDevice_GetDeviceCaps(This) CALL_IFACE_METHOD(RenderDevice, GetDeviceCaps, This)
+# define IRenderDevice_GetTextureFormatInfo(This, ...) CALL_IFACE_METHOD(RenderDevice, GetTextureFormatInfo, This, __VA_ARGS__)
+# define IRenderDevice_GetTextureFormatInfoExt(This, ...) CALL_IFACE_METHOD(RenderDevice, GetTextureFormatInfoExt, This, __VA_ARGS__)
+# define IRenderDevice_ReleaseStaleResources(This, ...) CALL_IFACE_METHOD(RenderDevice, ReleaseStaleResources, This, __VA_ARGS__)
+# define IRenderDevice_IdleGPU(This) CALL_IFACE_METHOD(RenderDevice, IdleGPU, This)
+# define IRenderDevice_GetEngineFactory(This) CALL_IFACE_METHOD(RenderDevice, GetEngineFactory, This)
// clang-format on
#endif
diff --git a/Graphics/GraphicsEngine/interface/Shader.h b/Graphics/GraphicsEngine/interface/Shader.h
index bb4acc84..a2bc518d 100644
--- a/Graphics/GraphicsEngine/interface/Shader.h
+++ b/Graphics/GraphicsEngine/interface/Shader.h
@@ -45,16 +45,22 @@ static const INTERFACE_ID IID_Shader =
/// Describes the shader type
DILIGENT_TYPED_ENUM(SHADER_TYPE, Uint32)
{
- SHADER_TYPE_UNKNOWN = 0x000, ///< Unknown shader type
- SHADER_TYPE_VERTEX = 0x001, ///< Vertex shader
- SHADER_TYPE_PIXEL = 0x002, ///< Pixel (fragment) shader
- SHADER_TYPE_GEOMETRY = 0x004, ///< Geometry shader
- SHADER_TYPE_HULL = 0x008, ///< Hull (tessellation control) shader
- SHADER_TYPE_DOMAIN = 0x010, ///< Domain (tessellation evaluation) shader
- SHADER_TYPE_COMPUTE = 0x020, ///< Compute shader
- SHADER_TYPE_AMPLIFICATION = 0x040, ///< Amplification (task) shader
- SHADER_TYPE_MESH = 0x080, ///< Mesh shader
- SHADER_TYPE_LAST = SHADER_TYPE_MESH
+ SHADER_TYPE_UNKNOWN = 0x0000, ///< Unknown shader type
+ SHADER_TYPE_VERTEX = 0x0001, ///< Vertex shader
+ SHADER_TYPE_PIXEL = 0x0002, ///< Pixel (fragment) shader
+ SHADER_TYPE_GEOMETRY = 0x0004, ///< Geometry shader
+ SHADER_TYPE_HULL = 0x0008, ///< Hull (tessellation control) shader
+ SHADER_TYPE_DOMAIN = 0x0010, ///< Domain (tessellation evaluation) shader
+ SHADER_TYPE_COMPUTE = 0x0020, ///< Compute shader
+ SHADER_TYPE_AMPLIFICATION = 0x0040, ///< Amplification (task) shader
+ SHADER_TYPE_MESH = 0x0080, ///< Mesh shader
+ SHADER_TYPE_RAY_GEN = 0x0100, ///< Ray generation shader
+ SHADER_TYPE_RAY_MISS = 0x0200, ///< Ray miss shader
+ SHADER_TYPE_RAY_CLOSEST_HIT = 0x0400, ///< Ray closest hit shader
+ SHADER_TYPE_RAY_ANY_HIT = 0x0800, ///< Ray any hit shader
+ SHADER_TYPE_RAY_INTERSECTION = 0x1000, ///< Ray intersection shader
+ SHADER_TYPE_CALLABLE = 0x2000, ///< Callable shader
+ SHADER_TYPE_LAST = SHADER_TYPE_CALLABLE
};
DEFINE_FLAG_ENUM_OPERATORS(SHADER_TYPE);
@@ -106,6 +112,8 @@ DILIGENT_TYPED_ENUM(SHADER_COMPILER, Uint32)
/// Legacy HLSL compiler (FXC) for Direct3D11 and Direct3D12 supporting shader models up to 5.1.
SHADER_COMPILER_FXC,
+
+ SHADER_COMPILER_LAST = SHADER_COMPILER_FXC
};
@@ -351,7 +359,10 @@ DILIGENT_TYPED_ENUM(SHADER_RESOURCE_TYPE, Uint8)
/// Input attachment in a render pass
SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT,
- SHADER_RESOURCE_TYPE_LAST = SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT
+ /// Acceleration structure
+ SHADER_RESOURCE_TYPE_ACCEL_STRUCT,
+
+ SHADER_RESOURCE_TYPE_LAST = SHADER_RESOURCE_TYPE_ACCEL_STRUCT
};
// clang-format on
diff --git a/Graphics/GraphicsEngine/interface/ShaderBindingTable.h b/Graphics/GraphicsEngine/interface/ShaderBindingTable.h
new file mode 100644
index 00000000..214b4a17
--- /dev/null
+++ b/Graphics/GraphicsEngine/interface/ShaderBindingTable.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definition of the Diligent::IShaderBindingTable interface and related data structures
+
+#include "../../../Primitives/interface/Object.h"
+#include "../../../Primitives/interface/FlagEnum.h"
+#include "GraphicsTypes.h"
+#include "Constants.h"
+#include "Buffer.h"
+#include "PipelineState.h"
+#include "TopLevelAS.h"
+
+DILIGENT_BEGIN_NAMESPACE(Diligent)
+
+// {1EE12101-7010-4825-AA8E-AC6BB9858BD6}
+static const INTERFACE_ID IID_ShaderBindingTable =
+ {0x1ee12101, 0x7010, 0x4825, {0xaa, 0x8e, 0xac, 0x6b, 0xb9, 0x85, 0x8b, 0xd6}};
+
+// clang-format off
+
+/// Shader binding table description.
+struct ShaderBindingTableDesc DILIGENT_DERIVE(DeviceObjectAttribs)
+
+ /// Ray tracing pipeline state object from which shaders will be taken.
+ IPipelineState* pPSO DEFAULT_INITIALIZER(nullptr);
+
+#if DILIGENT_CPP_INTERFACE
+ ShaderBindingTableDesc() noexcept {}
+#endif
+};
+typedef struct ShaderBindingTableDesc ShaderBindingTableDesc;
+
+
+/// Defines shader binding table validation flags, see IShaderBindingTable::Verify().
+DILIGENT_TYPED_ENUM(SHADER_BINDING_VALIDATION_FLAGS, Uint8)
+{
+ /// Checks that all shaders are bound or inactive.
+ SHADER_BINDING_VALIDATION_SHADER_ONLY = 0x1,
+
+ /// Checks that shader record data are initialized.
+ SHADER_BINDING_VALIDATION_SHADER_RECORD = 0x2,
+
+ /// Checks that all TLAS that used in IShaderBindingTable::BindHitGroup() are alive and
+ /// shader binding indices have not changed.
+ SHADER_BINDING_VALIDATION_TLAS = 0x4,
+
+ // Enable all validations.
+ SHADER_BINDING_VALIDATION_ALL = SHADER_BINDING_VALIDATION_SHADER_ONLY |
+ SHADER_BINDING_VALIDATION_SHADER_RECORD |
+ SHADER_BINDING_VALIDATION_TLAS
+};
+DEFINE_FLAG_ENUM_OPERATORS(SHADER_BINDING_VALIDATION_FLAGS)
+
+
+#define DILIGENT_INTERFACE_NAME IShaderBindingTable
+#include "../../../Primitives/interface/DefineInterfaceHelperMacros.h"
+
+#define IShaderBindingTableInclusiveMethods \
+ IDeviceObjectInclusiveMethods; \
+ IShaderBindingTableMethods ShaderBindingTable
+
+/// Shader binding table interface
+
+/// Defines the methods to manipulate a SBT object
+DILIGENT_BEGIN_INTERFACE(IShaderBindingTable, IDeviceObject)
+{
+#if DILIGENT_CPP_INTERFACE
+ /// Returns the shader binding table description used to create the object
+ virtual const ShaderBindingTableDesc& DILIGENT_CALL_TYPE GetDesc() const override = 0;
+#endif
+
+ /// Check that all shaders are bound, instances and geometries are not changed, shader record data are initialized.
+
+ /// \param [in] Flags - Flags used for validation.
+ /// \return True if SBT content is valid.
+ ///
+ /// \note Access to the SBT must be externally synchronized.
+ /// This method implemented only for development build and has no effect in release build.
+ VIRTUAL Bool METHOD(Verify)(THIS_
+ SHADER_BINDING_VALIDATION_FLAGS Flags) CONST PURE;
+
+
+ /// Reset SBT with the new pipeline state. This is more effecient than creating a new SBT.
+
+ /// \note Access to the SBT must be externally synchronized.
+ VIRTUAL void METHOD(Reset)(THIS_
+ IPipelineState* pPSO) PURE;
+
+
+ /// When TLAS or BLAS was rebuilt or updated, hit group shader bindings may have become invalid,
+ /// you can reset only hit groups and keep ray-gen, miss and callable shader bindings intact.
+
+ /// \note Access to the SBT must be externally synchronized.
+ VIRTUAL void METHOD(ResetHitGroups)(THIS) PURE;
+
+
+ /// Bind ray-generation shader.
+
+ /// \param [in] pShaderGroupName - Ray-generation shader name that was specified in RayTracingGeneralShaderGroup::Name.
+ /// \param [in] pData - Shader record data, can be null.
+ /// \param [in] DataSize - Shader record data size, should be equal to RayTracingPipelineDesc::ShaderRecordSize.
+ ///
+ /// \note Access to the SBT must be externally synchronized.
+ VIRTUAL void METHOD(BindRayGenShader)(THIS_
+ const char* pShaderGroupName,
+ const void* pData DEFAULT_INITIALIZER(nullptr),
+ Uint32 DataSize DEFAULT_INITIALIZER(0)) PURE;
+
+
+ /// Bind ray-miss shader.
+
+ /// \param [in] pShaderGroupName - Ray-miss shader name that was specified in RayTracingGeneralShaderGroup::Name,
+ /// can be null to make shader inactive.
+ /// \param [in] MissIndex - Miss shader offset in shader binding table, use the same value as in the shader:
+ /// 'MissShaderIndex' argument in TraceRay() in HLSL, 'missIndex' in traceRay() in GLSL.
+ /// \param [in] pData - Shader record data, can be null.
+ /// \param [in] DataSize - Shader record data size, should be equal to RayTracingPipelineDesc::ShaderRecordSize.
+ ///
+ /// \note Access to the SBT must be externally synchronized.
+ VIRTUAL void METHOD(BindMissShader)(THIS_
+ const char* pShaderGroupName,
+ Uint32 MissIndex,
+ const void* pData DEFAULT_INITIALIZER(nullptr),
+ Uint32 DataSize DEFAULT_INITIALIZER(0)) PURE;
+
+
+ /// Bind hit group for the specified geometry in instance.
+
+ /// \param [in] pTLAS - Top-level AS, used to calculate offset for instance.
+ /// \param [in] pInstanceName - Instance name, see TLASBuildInstanceData::InstanceName.
+ /// \param [in] pGeometryName - Geometry name, see BLASBuildTriangleData::GeometryName and BLASBuildBoundingBoxData::GeometryName.
+ /// \param [in] RayOffsetInHitGroupIndex - Ray offset in shader binding table, use the same value as in the shader:
+ /// 'RayContributionToHitGroupIndex' argument in TraceRay() in HLSL, 'sbtRecordOffset' argument in traceRay() in GLSL.
+ /// Must be less than HitShadersPerInstance.
+ /// \param [in] pShaderGroupName - Hit group name that was specified in RayTracingTriangleHitShaderGroup::Name and RayTracingProceduralHitShaderGroup::Name,
+ /// can be null to make the shader inactive.
+ /// \param [in] pData - Shader record data, can be null.
+ /// \param [in] DataSize - Shader record data size, should be equal to RayTracingPipelineDesc::ShaderRecordSize.
+ ///
+ /// \note Access to the SBT must be externally synchronized.
+ /// Access to the TLAS must be externally synchronized.
+ /// Access to the BLAS that was used in TLAS instance with name pInstanceName must be externally synchronized.
+ VIRTUAL void METHOD(BindHitGroup)(THIS_
+ ITopLevelAS* pTLAS,
+ const char* pInstanceName,
+ const char* pGeometryName,
+ Uint32 RayOffsetInHitGroupIndex,
+ const char* pShaderGroupName,
+ const void* pData DEFAULT_INITIALIZER(nullptr),
+ Uint32 DataSize DEFAULT_INITIALIZER(0)) PURE;
+
+
+ /// Bind hit group to specified location.
+
+ /// \param [in] BindingIndex - location of the hit group.
+ /// \param [in] pShaderGroupName - hit group name that specified in RayTracingTriangleHitShaderGroup::Name and RayTracingProceduralHitShaderGroup::Name,
+ /// can be null to make shader inactive.
+ /// \param [in] pData - shader record data, can be null.
+ /// \param [in] DataSize - shader record data size, should equal to RayTracingPipelineDesc::ShaderRecordSize.
+ ///
+ /// \note Access to the SBT must be externally synchronized.
+ ///
+ /// \remarks Use IBottomLevelAS::GetGeometryIndex(), ITopLevelAS::GetBuildInfo(), ITopLevelAS::GetInstanceDesc().ContributionToHitGroupIndex to calculate binding index.
+ VIRTUAL void METHOD(BindHitGroupByIndex)(THIS_
+ Uint32 BindingIndex,
+ const char* pShaderGroupName,
+ const void* pData DEFAULT_INITIALIZER(nullptr),
+ Uint32 DataSize DEFAULT_INITIALIZER(0)) PURE;
+
+
+ /// Bind hit group for each geometries in specified instance.
+
+ /// \param [in] pTLAS - Top-level AS, used to calculate offset for instance.
+ /// \param [in] pInstanceName - Instance name, see TLASBuildInstanceData::InstanceName.
+ /// \param [in] RayOffsetInHitGroupIndex - Ray offset in shader binding table, use the same value as in the shader:
+ /// 'RayContributionToHitGroupIndex' argument in TraceRay() in HLSL, 'sbtRecordOffset' argument in traceRay() in GLSL.
+ /// Must be less than HitShadersPerInstance.
+ /// \param [in] pShaderGroupName - Hit group name that was specified in RayTracingTriangleHitShaderGroup::Name and RayTracingProceduralHitShaderGroup::Name,
+ /// can be null to make shader inactive.
+ /// \param [in] pData - Shader record data, can be null.
+ /// \param [in] DataSize - Shader record data size, should equal to RayTracingPipelineDesc::ShaderRecordSize.
+ ///
+ /// \note Access to the SBT must be externally synchronized.
+ /// Access to the TLAS must be externally synchronized.
+ VIRTUAL void METHOD(BindHitGroups)(THIS_
+ ITopLevelAS* pTLAS,
+ const char* pInstanceName,
+ Uint32 RayOffsetInHitGroupIndex,
+ const char* pShaderGroupName,
+ const void* pData DEFAULT_INITIALIZER(nullptr),
+ Uint32 DataSize DEFAULT_INITIALIZER(0)) PURE;
+
+
+ /// Bind hit group for each instances in top-level AS.
+
+ /// \param [in] pTLAS - Top-level AS, used to calculate offset for instance.
+ /// \param [in] RayOffsetInHitGroupIndex - Ray offset in shader binding table, use the same value as in the shader:
+ /// 'RayContributionToHitGroupIndex' argument in TraceRay() in HLSL, 'sbtRecordOffset' argument in traceRay() in GLSL.
+ /// Must be less than HitShadersPerInstance.
+ /// \param [in] pShaderGroupName - Hit group name that was specified in RayTracingTriangleHitShaderGroup::Name and RayTracingProceduralHitShaderGroup::Name,
+ /// can be null to make shader inactive.
+ /// \param [in] pData - Shader record data, can be null.
+ /// \param [in] DataSize - Shader record data size, should equal to RayTracingPipelineDesc::ShaderRecordSize.
+ ///
+ /// \note Access to the SBT must be externally synchronized.
+ /// Access to the TLAS must be externally synchronized.
+ VIRTUAL void METHOD(BindHitGroupForAll)(THIS_
+ ITopLevelAS* pTLAS,
+ Uint32 RayOffsetInHitGroupIndex,
+ const char* pShaderGroupName,
+ const void* pData DEFAULT_INITIALIZER(nullptr),
+ Uint32 DataSize DEFAULT_INITIALIZER(0)) PURE;
+
+
+ /// Bind callable shader.
+
+ /// \param [in] pShaderGroupName - Callable shader name that specified in RayTracingGeneralShaderGroup::Name,
+ /// can be null to make shader inactive.
+ /// \param [in] CallableIndex - Callable shader offset in shader binding table, use the same value as in the shader:
+ /// 'ShaderIndex' argument in CallShader() in HLSL, 'callable' argument in executeCallable() in GLSL.
+ /// \param [in] pData - Shader record data, can be null.
+ /// \param [in] DataSize - Shader record data size, should equal to RayTracingPipelineDesc::ShaderRecordSize.
+ ///
+ /// \note Access to the SBT must be externally synchronized.
+ VIRTUAL void METHOD(BindCallableShader)(THIS_
+ const char* pShaderGroupName,
+ Uint32 CallableIndex,
+ const void* pData DEFAULT_INITIALIZER(nullptr),
+ Uint32 DataSize DEFAULT_INITIALIZER(0)) PURE;
+};
+DILIGENT_END_INTERFACE
+
+#include "../../../Primitives/interface/UndefInterfaceHelperMacros.h"
+
+#if DILIGENT_C_INTERFACE
+
+// clang-format off
+
+# define IShaderBindingTable_Verify(This, ...) CALL_IFACE_METHOD(ShaderBindingTable, Verify, This, __VA_ARGS__)
+# define IShaderBindingTable_Reset(This, ...) CALL_IFACE_METHOD(ShaderBindingTable, Reset, This, __VA_ARGS__)
+# define IShaderBindingTable_ResetHitGroups(This) CALL_IFACE_METHOD(ShaderBindingTable, ResetHitGroups, This)
+# define IShaderBindingTable_BindRayGenShader(This, ...) CALL_IFACE_METHOD(ShaderBindingTable, BindRayGenShader, This, __VA_ARGS__)
+# define IShaderBindingTable_BindMissShader(This, ...) CALL_IFACE_METHOD(ShaderBindingTable, BindMissShader, This, __VA_ARGS__)
+# define IShaderBindingTable_BindHitGroupByIndex(This, ...) CALL_IFACE_METHOD(ShaderBindingTable, BindHitGroupByIndex, This, __VA_ARGS__)
+# define IShaderBindingTable_BindHitGroup(This, ...) CALL_IFACE_METHOD(ShaderBindingTable, BindHitGroup, This, __VA_ARGS__)
+# define IShaderBindingTable_BindHitGroups(This, ...) CALL_IFACE_METHOD(ShaderBindingTable, BindHitGroups, This, __VA_ARGS__)
+# define IShaderBindingTable_BindHitGroupForAll(This, ...) CALL_IFACE_METHOD(ShaderBindingTable, BindHitGroupForAll, This, __VA_ARGS__)
+# define IShaderBindingTable_BindCallableShader(This, ...) CALL_IFACE_METHOD(ShaderBindingTable, BindCallableShader, This, __VA_ARGS__)
+
+// clang-format on
+
+#endif
+
+DILIGENT_END_NAMESPACE // namespace Diligent
diff --git a/Graphics/GraphicsEngine/interface/TopLevelAS.h b/Graphics/GraphicsEngine/interface/TopLevelAS.h
new file mode 100644
index 00000000..272f6c61
--- /dev/null
+++ b/Graphics/GraphicsEngine/interface/TopLevelAS.h
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#pragma once
+
+/// \file
+/// Definition of the Diligent::ITopLevelAS interface and related data structures
+
+#include "../../../Primitives/interface/Object.h"
+#include "../../../Primitives/interface/FlagEnum.h"
+#include "GraphicsTypes.h"
+#include "Constants.h"
+#include "Buffer.h"
+#include "BottomLevelAS.h"
+
+DILIGENT_BEGIN_NAMESPACE(Diligent)
+
+// {16561861-294B-4804-96FA-1717333F769A}
+static const INTERFACE_ID IID_TopLevelAS =
+ {0x16561861, 0x294b, 0x4804, {0x96, 0xfa, 0x17, 0x17, 0x33, 0x3f, 0x76, 0x9a}};
+
+// clang-format off
+
+/// Top-level AS description.
+struct TopLevelASDesc DILIGENT_DERIVE(DeviceObjectAttribs)
+
+ /// Allocate space for specified number of instances.
+ Uint32 MaxInstanceCount DEFAULT_INITIALIZER(0);
+
+ /// Ray tracing build flags, see Diligent::RAYTRACING_BUILD_AS_FLAGS.
+ RAYTRACING_BUILD_AS_FLAGS Flags DEFAULT_INITIALIZER(RAYTRACING_BUILD_AS_NONE);
+
+ /// The size returned by IDeviceContext::WriteTLASCompactedSize(), if this acceleration structure
+ /// is going to be the target of a compacting copy command (IDeviceContext::CopyTLAS() with COPY_AS_MODE_COMPACT).
+ Uint32 CompactedSize DEFAULT_INITIALIZER(0);
+
+ /// Defines which command queues this BLAS can be used with.
+ Uint64 CommandQueueMask DEFAULT_INITIALIZER(1);
+
+#if DILIGENT_CPP_INTERFACE
+ TopLevelASDesc() noexcept {}
+#endif
+};
+typedef struct TopLevelASDesc TopLevelASDesc;
+
+
+/// Defines shader binding mode.
+DILIGENT_TYPED_ENUM(HIT_GROUP_BINDING_MODE, Uint8)
+{
+ /// Reserve space for actual geometry count for each instance in TLAS.
+ /// Each geometry can have unique hit shader group.
+ /// See IShaderBindingTable::BindHitGroup().
+ HIT_GROUP_BINDING_MODE_PER_GEOMETRY = 0,
+
+ /// Reserve space for each instance in TLAS so each instance can have a unique hit shader group.
+ /// In this mode SBT buffer will use less memory. See IShaderBindingTable::BindHitGroups().
+ HIT_GROUP_BINDING_MODE_PER_INSTANCE,
+
+ /// Reserve space for single hit group for each TLAS.
+ /// See IShaderBindingTable::BindHitGroupForAll().
+ HIT_GROUP_BINDING_MODE_PER_ACCEL_STRUCT,
+
+ /// The user must specify TLASBuildInstanceData::ContributionToHitGroupIndex and only use IShaderBindingTable::BindHitGroupByIndex().
+ HIT_GROUP_BINDING_MODE_USER_DEFINED,
+
+ HIT_GROUP_BINDING_MODE_LAST = HIT_GROUP_BINDING_MODE_USER_DEFINED,
+};
+
+
+/// Defines TLAS state that was used in the last build.
+struct TLASBuildInfo
+{
+ /// The number of instances, same as BuildTLASAttribs::InstanceCount.
+ Uint32 InstanceCount DEFAULT_INITIALIZER(0);
+
+ /// The number of hit shader groups, same as BuildTLASAttribs::HitGroupStride.
+ Uint32 HitGroupStride DEFAULT_INITIALIZER(0);
+
+ /// Hit shader binding mode, same as BuildTLASAttribs::BindingMode.
+ HIT_GROUP_BINDING_MODE BindingMode DEFAULT_INITIALIZER(HIT_GROUP_BINDING_MODE_PER_GEOMETRY);
+
+ /// First hit group location, same as BuildTLASAttribs::BaseContributionToHitGroupIndex.
+ Uint32 FirstContributionToHitGroupIndex DEFAULT_INITIALIZER(0);
+
+ /// Last hit group location.
+ Uint32 LastContributionToHitGroupIndex DEFAULT_INITIALIZER(0);
+};
+typedef struct TLASBuildInfo TLASBuildInfo;
+
+
+/// Top-level AS instance description.
+struct TLASInstanceDesc
+{
+ /// Index that corresponds to the one specified in TLASBuildInstanceData::ContributionToHitGroupIndex.
+ Uint32 ContributionToHitGroupIndex DEFAULT_INITIALIZER(0);
+
+ /// The autogenerated index of the instance.
+ /// Same as InstanceIndex() in HLSL and gl_InstanceID in GLSL.
+ Uint32 InstanceIndex DEFAULT_INITIALIZER(0);
+
+ /// Bottom-level AS that is specified in TLASBuildInstanceData::pBLAS.
+ IBottomLevelAS* pBLAS DEFAULT_INITIALIZER(nullptr);
+
+#if DILIGENT_CPP_INTERFACE
+ TLASInstanceDesc() noexcept {}
+#endif
+};
+typedef struct TLASInstanceDesc TLASInstanceDesc;
+
+
+#define DILIGENT_INTERFACE_NAME ITopLevelAS
+#include "../../../Primitives/interface/DefineInterfaceHelperMacros.h"
+
+#define ITopLevelASInclusiveMethods \
+ IDeviceObjectInclusiveMethods; \
+ ITopLevelASMethods TopLevelAS
+
+/// Top-level AS interface
+
+/// Defines the methods to manipulate a TLAS object
+DILIGENT_BEGIN_INTERFACE(ITopLevelAS, IDeviceObject)
+{
+#if DILIGENT_CPP_INTERFACE
+ /// Returns the top level AS description used to create the object
+ virtual const TopLevelASDesc& DILIGENT_CALL_TYPE GetDesc() const override = 0;
+#endif
+
+ /// Returns instance description that can be used in shader binding table.
+
+ /// \param [in] Name - Instance name that is specified in TLASBuildInstanceData::InstanceName.
+ /// \return TLASInstanceDesc object, see Diligent::TLASInstanceDesc.
+ /// If instance does not exist then TLASInstanceDesc::ContributionToHitGroupIndex
+ /// and TLASInstanceDesc::InstanceIndex are set to INVALID_INDEX.
+ ///
+ /// \note Access to the TLAS must be externally synchronized.
+ VIRTUAL TLASInstanceDesc METHOD(GetInstanceDesc)(THIS_
+ const char* Name) CONST PURE;
+
+
+ /// Returns TLAS state after the last build or update operation.
+
+ /// \return TLASBuildInfo object, see Diligent::TLASBuildInfo.
+ ///
+ /// \note Access to the TLAS must be externally synchronized.
+ VIRTUAL TLASBuildInfo METHOD(GetBuildInfo)(THIS) CONST PURE;
+
+
+ /// Returns scratch buffer info for the current acceleration structure.
+
+ /// \return ScratchBufferSizes object, see Diligent::ScratchBufferSizes.
+ VIRTUAL ScratchBufferSizes METHOD(GetScratchBufferSizes)(THIS) CONST PURE;
+
+
+ /// Returns native acceleration structure handle specific to the underlying graphics API
+
+ /// \return pointer to ID3D12Resource interface, for D3D12 implementation\n
+ /// VkAccelerationStructure handle, for Vulkan implementation
+ VIRTUAL void* METHOD(GetNativeHandle)(THIS) PURE;
+
+
+ /// Sets the acceleration structure usage state.
+
+ /// \note This method does not perform state transition, but
+ /// resets the internal acceleration structure state to the given value.
+ /// This method should be used after the application finished
+ /// manually managing the acceleration structure state and wants to hand over
+ /// state management back to the engine.
+ VIRTUAL void METHOD(SetState)(THIS_
+ RESOURCE_STATE State) PURE;
+
+
+ /// Returns the internal acceleration structure state
+ VIRTUAL RESOURCE_STATE METHOD(GetState)(THIS) CONST PURE;
+};
+DILIGENT_END_INTERFACE
+
+#include "../../../Primitives/interface/UndefInterfaceHelperMacros.h"
+
+#if DILIGENT_C_INTERFACE
+
+// clang-format off
+
+# define ITopLevelAS_GetInstanceDesc(This, ...) CALL_IFACE_METHOD(TopLevelAS, GetInstanceDesc, This, __VA_ARGS__)
+# define ITopLevelAS_GetBuildInfo(This) CALL_IFACE_METHOD(TopLevelAS, GetBuildInfo, This)
+# define ITopLevelAS_GetScratchBufferSizes(This) CALL_IFACE_METHOD(TopLevelAS, GetScratchBufferSizes, This)
+# define ITopLevelAS_GetNativeHandle(This) CALL_IFACE_METHOD(TopLevelAS, GetNativeHandle, This)
+# define ITopLevelAS_SetState(This, ...) CALL_IFACE_METHOD(TopLevelAS, SetState, This, __VA_ARGS__)
+# define ITopLevelAS_GetState(This) CALL_IFACE_METHOD(TopLevelAS, GetState, This)
+
+// clang-format on
+
+#endif
+
+DILIGENT_END_NAMESPACE // namespace Diligent
diff --git a/Graphics/GraphicsEngine/src/APIInfo.cpp b/Graphics/GraphicsEngine/src/APIInfo.cpp
index e4111327..4facdec4 100644
--- a/Graphics/GraphicsEngine/src/APIInfo.cpp
+++ b/Graphics/GraphicsEngine/src/APIInfo.cpp
@@ -89,10 +89,12 @@ static APIInfo InitAPIInfo()
INIT_STRUCTURE_SIZE(ShaderResourceVariableDesc);
INIT_STRUCTURE_SIZE(ImmutableSamplerDesc);
INIT_STRUCTURE_SIZE(PipelineResourceLayoutDesc);
+ INIT_STRUCTURE_SIZE(PipelineStateDesc);
INIT_STRUCTURE_SIZE(GraphicsPipelineDesc);
INIT_STRUCTURE_SIZE(GraphicsPipelineStateCreateInfo);
INIT_STRUCTURE_SIZE(ComputePipelineStateCreateInfo);
- INIT_STRUCTURE_SIZE(PipelineStateDesc);
+ INIT_STRUCTURE_SIZE(RayTracingPipelineDesc);
+ INIT_STRUCTURE_SIZE(RayTracingPipelineStateCreateInfo);
INIT_STRUCTURE_SIZE(RasterizerStateDesc);
INIT_STRUCTURE_SIZE(ResourceMappingEntry);
INIT_STRUCTURE_SIZE(ResourceMappingDesc);
diff --git a/Graphics/GraphicsEngine/src/BottomLevelASBase.cpp b/Graphics/GraphicsEngine/src/BottomLevelASBase.cpp
new file mode 100644
index 00000000..3d6e4fbc
--- /dev/null
+++ b/Graphics/GraphicsEngine/src/BottomLevelASBase.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include "BottomLevelASBase.hpp"
+
+namespace Diligent
+{
+
+void ValidateBottomLevelASDesc(const BottomLevelASDesc& Desc) noexcept(false)
+{
+#define LOG_BLAS_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of a bottom-level AS '", (Desc.Name ? Desc.Name : ""), "' is invalid: ", ##__VA_ARGS__)
+
+ if (Desc.CompactedSize > 0)
+ {
+ if (Desc.pTriangles != nullptr || Desc.pBoxes != nullptr)
+ LOG_BLAS_ERROR_AND_THROW("If non-zero CompactedSize is specified, pTriangles and pBoxes must both be null");
+
+ if (Desc.Flags != RAYTRACING_BUILD_AS_NONE)
+ LOG_BLAS_ERROR_AND_THROW("If non-zero CompactedSize is specified, Flags must be RAYTRACING_BUILD_AS_NONE");
+ }
+ else
+ {
+ if (!((Desc.pBoxes != nullptr) ^ (Desc.pTriangles != nullptr)))
+ LOG_BLAS_ERROR_AND_THROW("Exactly one of pTriangles and pBoxes must be defined");
+
+ if (Desc.pBoxes == nullptr && Desc.BoxCount > 0)
+ LOG_BLAS_ERROR_AND_THROW("pBoxes is null, but BoxCount is not 0");
+
+ if (Desc.pTriangles == nullptr && Desc.TriangleCount > 0)
+ LOG_BLAS_ERROR_AND_THROW("pTriangles is null, but TriangleCount is not 0");
+
+ if ((Desc.Flags & RAYTRACING_BUILD_AS_PREFER_FAST_TRACE) != 0 && (Desc.Flags & RAYTRACING_BUILD_AS_PREFER_FAST_BUILD) != 0)
+ LOG_BLAS_ERROR_AND_THROW("RAYTRACING_BUILD_AS_PREFER_FAST_TRACE and RAYTRACING_BUILD_AS_PREFER_FAST_BUILD flags are mutually exclusive");
+
+ for (Uint32 i = 0; i < Desc.TriangleCount; ++i)
+ {
+ const auto& tri = Desc.pTriangles[i];
+
+ if (tri.GeometryName == nullptr)
+ LOG_BLAS_ERROR_AND_THROW("pTriangles[", i, "].GeometryName must not be null");
+
+ if (tri.VertexValueType != VT_FLOAT32 && tri.VertexValueType != VT_FLOAT16 && tri.VertexValueType != VT_INT16)
+ LOG_BLAS_ERROR_AND_THROW("pTriangles[", i, "].VertexValueType (", GetValueTypeString(tri.VertexValueType),
+ ") is invalid. Only the following values are allowed: VT_FLOAT32, VT_FLOAT16, VT_INT16");
+
+ if (tri.VertexComponentCount != 2 && tri.VertexComponentCount != 3)
+ LOG_BLAS_ERROR_AND_THROW("pTriangles[", i, "].VertexComponentCount (", tri.VertexComponentCount, ") is invalid. Only 2 or 3 are allowed.");
+
+ if (tri.MaxVertexCount == 0)
+ LOG_BLAS_ERROR_AND_THROW("pTriangles[", i, "].MaxVertexCount must be greater than 0");
+
+ if (tri.MaxPrimitiveCount == 0)
+ LOG_BLAS_ERROR_AND_THROW("pTriangles[", i, "].MaxPrimitiveCount must be greater than 0");
+
+ if (tri.IndexType == VT_UNDEFINED)
+ {
+ if (tri.MaxVertexCount != tri.MaxPrimitiveCount * 3)
+ LOG_BLAS_ERROR_AND_THROW("pTriangles[", i, "].MaxVertexCount must equal to (MaxPrimitiveCount * 3)");
+ }
+ else
+ {
+ if (tri.IndexType != VT_UINT32 && tri.IndexType != VT_UINT16)
+ LOG_BLAS_ERROR_AND_THROW("pTriangles[", i, "].IndexType must be VT_UINT16 or VT_UINT32");
+ }
+ }
+
+ for (Uint32 i = 0; i < Desc.BoxCount; ++i)
+ {
+ const auto& box = Desc.pBoxes[i];
+
+ if (box.GeometryName == nullptr)
+ LOG_BLAS_ERROR_AND_THROW("pBoxes[", i, "].GeometryName must not be null");
+
+ if (box.MaxBoxCount == 0)
+ LOG_BLAS_ERROR_AND_THROW("pBoxes[", i, "].MaxBoxCount must be greater than 0");
+ }
+ }
+
+#undef LOG_BLAS_ERROR_AND_THROW
+}
+
+void CopyBLASGeometryDesc(const BottomLevelASDesc& SrcDesc,
+ BottomLevelASDesc& DstDesc,
+ FixedLinearAllocator& MemPool,
+ const BLASNameToIndex* pSrcNameToIndex,
+ BLASNameToIndex& DstNameToIndex) noexcept(false)
+{
+ if (SrcDesc.pTriangles != nullptr)
+ {
+ MemPool.AddSpace<decltype(*SrcDesc.pTriangles)>(SrcDesc.TriangleCount);
+
+ for (Uint32 i = 0; i < SrcDesc.TriangleCount; ++i)
+ MemPool.AddSpaceForString(SrcDesc.pTriangles[i].GeometryName);
+
+ MemPool.Reserve();
+
+ auto* pTriangles = MemPool.CopyArray(SrcDesc.pTriangles, SrcDesc.TriangleCount);
+
+ // Copy strings
+ for (Uint32 i = 0; i < SrcDesc.TriangleCount; ++i)
+ {
+ const auto* SrcGeoName = SrcDesc.pTriangles[i].GeometryName;
+ pTriangles[i].GeometryName = MemPool.CopyString(SrcGeoName);
+ Uint32 ActualIndex = INVALID_INDEX;
+
+ if (pSrcNameToIndex)
+ {
+ auto iter = pSrcNameToIndex->find(SrcGeoName);
+ VERIFY_EXPR(iter != pSrcNameToIndex->end());
+ ActualIndex = iter->second.ActualIndex;
+ }
+
+ bool IsUniqueName = DstNameToIndex.emplace(SrcGeoName, BLASGeomIndex{i, ActualIndex}).second;
+ if (!IsUniqueName)
+ LOG_ERROR_AND_THROW("Geometry name '", SrcGeoName, "' is not unique");
+ }
+
+ DstDesc.pTriangles = pTriangles;
+ DstDesc.TriangleCount = SrcDesc.TriangleCount;
+ DstDesc.pBoxes = nullptr;
+ DstDesc.BoxCount = 0;
+ }
+ else if (SrcDesc.pBoxes != nullptr)
+ {
+ MemPool.AddSpace<decltype(*SrcDesc.pBoxes)>(SrcDesc.BoxCount);
+
+ for (Uint32 i = 0; i < SrcDesc.BoxCount; ++i)
+ MemPool.AddSpaceForString(SrcDesc.pBoxes[i].GeometryName);
+
+ MemPool.Reserve();
+
+ auto* pBoxes = MemPool.CopyArray(SrcDesc.pBoxes, SrcDesc.BoxCount);
+
+ // Copy strings
+ for (Uint32 i = 0; i < SrcDesc.BoxCount; ++i)
+ {
+ const auto* SrcGeoName = SrcDesc.pBoxes[i].GeometryName;
+ pBoxes[i].GeometryName = MemPool.CopyString(SrcGeoName);
+ Uint32 ActualIndex = INVALID_INDEX;
+
+ if (pSrcNameToIndex)
+ {
+ auto iter = pSrcNameToIndex->find(SrcGeoName);
+ VERIFY_EXPR(iter != pSrcNameToIndex->end());
+ ActualIndex = iter->second.ActualIndex;
+ }
+
+ bool IsUniqueName = DstNameToIndex.emplace(SrcGeoName, BLASGeomIndex{i, ActualIndex}).second;
+ if (!IsUniqueName)
+ LOG_ERROR_AND_THROW("Geometry name '", SrcGeoName, "' is not unique");
+ }
+
+ DstDesc.pBoxes = pBoxes;
+ DstDesc.BoxCount = SrcDesc.BoxCount;
+ DstDesc.pTriangles = nullptr;
+ DstDesc.TriangleCount = 0;
+ }
+ else
+ {
+ LOG_ERROR_AND_THROW("Either pTriangles or pBoxes must not be null");
+ }
+}
+
+} // namespace Diligent
diff --git a/Graphics/GraphicsEngine/src/BufferBase.cpp b/Graphics/GraphicsEngine/src/BufferBase.cpp
index 0239ed92..5156764b 100644
--- a/Graphics/GraphicsEngine/src/BufferBase.cpp
+++ b/Graphics/GraphicsEngine/src/BufferBase.cpp
@@ -25,7 +25,6 @@
* of the possibility of such damages.
*/
-#include "pch.h"
#include "Buffer.h"
#include "GraphicsAccessories.hpp"
@@ -43,8 +42,10 @@ namespace Diligent
} while (false)
-void ValidateBufferDesc(const BufferDesc& Desc, const DeviceCaps& deviceCaps)
+void ValidateBufferDesc(const BufferDesc& Desc, const DeviceCaps& deviceCaps) noexcept(false)
{
+ static_assert(BIND_FLAGS_LAST == 0x400L, "Please update this function to handle the new bind flags");
+
constexpr Uint32 AllowedBindFlags =
BIND_VERTEX_BUFFER |
BIND_INDEX_BUFFER |
@@ -52,7 +53,8 @@ void ValidateBufferDesc(const BufferDesc& Desc, const DeviceCaps& deviceCaps)
BIND_SHADER_RESOURCE |
BIND_STREAM_OUTPUT |
BIND_UNORDERED_ACCESS |
- BIND_INDIRECT_DRAW_ARGS;
+ BIND_INDIRECT_DRAW_ARGS |
+ BIND_RAY_TRACING;
VERIFY_BUFFER((Desc.BindFlags & ~AllowedBindFlags) == 0, "the following bind flags are not allowed for a buffer: ", GetBindFlagsString(Desc.BindFlags & ~AllowedBindFlags, ", "), '.');
@@ -112,7 +114,7 @@ void ValidateBufferDesc(const BufferDesc& Desc, const DeviceCaps& deviceCaps)
}
}
-void ValidateBufferInitData(const BufferDesc& Desc, const BufferData* pBuffData)
+void ValidateBufferInitData(const BufferDesc& Desc, const BufferData* pBuffData) noexcept(false)
{
if (Desc.Usage == USAGE_IMMUTABLE && (pBuffData == nullptr || pBuffData->pData == nullptr))
LOG_BUFFER_ERROR_AND_THROW("initial data must not be null as immutable buffers must be initialized at creation time.");
@@ -140,4 +142,51 @@ void ValidateBufferInitData(const BufferDesc& Desc, const BufferData* pBuffData)
#undef VERIFY_BUFFER
#undef LOG_BUFFER_ERROR_AND_THROW
+void ValidateAndCorrectBufferViewDesc(const BufferDesc& BuffDesc, BufferViewDesc& ViewDesc) noexcept(false)
+{
+ if (ViewDesc.ByteWidth == 0)
+ {
+ DEV_CHECK_ERR(BuffDesc.uiSizeInBytes > ViewDesc.ByteOffset, "Byte offset (", ViewDesc.ByteOffset, ") exceeds buffer size (", BuffDesc.uiSizeInBytes, ")");
+ ViewDesc.ByteWidth = BuffDesc.uiSizeInBytes - ViewDesc.ByteOffset;
+ }
+
+ if (ViewDesc.ByteOffset + ViewDesc.ByteWidth > BuffDesc.uiSizeInBytes)
+ LOG_ERROR_AND_THROW("Buffer view range [", ViewDesc.ByteOffset, ", ", ViewDesc.ByteOffset + ViewDesc.ByteWidth, ") is out of the buffer boundaries [0, ", BuffDesc.uiSizeInBytes, ").");
+
+ if ((BuffDesc.BindFlags & BIND_UNORDERED_ACCESS) ||
+ (BuffDesc.BindFlags & BIND_SHADER_RESOURCE))
+ {
+ if (BuffDesc.Mode == BUFFER_MODE_STRUCTURED || BuffDesc.Mode == BUFFER_MODE_FORMATTED)
+ {
+ VERIFY(BuffDesc.ElementByteStride != 0, "Element byte stride is zero");
+ if ((ViewDesc.ByteOffset % BuffDesc.ElementByteStride) != 0)
+ LOG_ERROR_AND_THROW("Buffer view byte offset (", ViewDesc.ByteOffset, ") is not a multiple of element byte stride (", BuffDesc.ElementByteStride, ").");
+ if ((ViewDesc.ByteWidth % BuffDesc.ElementByteStride) != 0)
+ LOG_ERROR_AND_THROW("Buffer view byte width (", ViewDesc.ByteWidth, ") is not a multiple of element byte stride (", BuffDesc.ElementByteStride, ").");
+ }
+
+ if (BuffDesc.Mode == BUFFER_MODE_FORMATTED && ViewDesc.Format.ValueType == VT_UNDEFINED)
+ LOG_ERROR_AND_THROW("Format must be specified when creating a view of a formatted buffer");
+
+ if (BuffDesc.Mode == BUFFER_MODE_FORMATTED || (BuffDesc.Mode == BUFFER_MODE_RAW && ViewDesc.Format.ValueType != VT_UNDEFINED))
+ {
+ if (ViewDesc.Format.NumComponents <= 0 || ViewDesc.Format.NumComponents > 4)
+ LOG_ERROR_AND_THROW("Incorrect number of components (", Uint32{ViewDesc.Format.NumComponents}, "). 1, 2, 3, or 4 are allowed values");
+ if (ViewDesc.Format.ValueType == VT_FLOAT32 || ViewDesc.Format.ValueType == VT_FLOAT16)
+ ViewDesc.Format.IsNormalized = false;
+ auto ViewElementStride = GetValueSize(ViewDesc.Format.ValueType) * Uint32{ViewDesc.Format.NumComponents};
+ if (BuffDesc.Mode == BUFFER_MODE_RAW && BuffDesc.ElementByteStride == 0)
+ LOG_ERROR_AND_THROW("To enable formatted views of a raw buffer, element byte must be specified during buffer initialization");
+ if (ViewElementStride != BuffDesc.ElementByteStride)
+ LOG_ERROR_AND_THROW("Buffer element byte stride (", BuffDesc.ElementByteStride, ") is not consistent with the size (", ViewElementStride, ") defined by the format of the view (", GetBufferFormatString(ViewDesc.Format), ')');
+ }
+
+ if (BuffDesc.Mode == BUFFER_MODE_RAW && ViewDesc.Format.ValueType == VT_UNDEFINED)
+ {
+ if ((ViewDesc.ByteOffset % 16) != 0)
+ LOG_ERROR_AND_THROW("When creating a RAW view, the offset of the first element from the start of the buffer (", ViewDesc.ByteOffset, ") must be a multiple of 16 bytes");
+ }
+ }
+}
+
} // namespace Diligent
diff --git a/Graphics/GraphicsEngine/src/DefaultShaderSourceStreamFactory.cpp b/Graphics/GraphicsEngine/src/DefaultShaderSourceStreamFactory.cpp
index b14a1707..d9ab87ea 100644
--- a/Graphics/GraphicsEngine/src/DefaultShaderSourceStreamFactory.cpp
+++ b/Graphics/GraphicsEngine/src/DefaultShaderSourceStreamFactory.cpp
@@ -25,7 +25,6 @@
* of the possibility of such damages.
*/
-#include "pch.h"
#include "DefaultShaderSourceStreamFactory.h"
#include "ObjectBase.hpp"
#include "RefCntAutoPtr.hpp"
diff --git a/Graphics/GraphicsEngine/src/DeviceContextBase.cpp b/Graphics/GraphicsEngine/src/DeviceContextBase.cpp
new file mode 100644
index 00000000..72a05729
--- /dev/null
+++ b/Graphics/GraphicsEngine/src/DeviceContextBase.cpp
@@ -0,0 +1,776 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include "DeviceContextBase.hpp"
+#include "GraphicsAccessories.hpp"
+
+namespace Diligent
+{
+
+#if DILIGENT_DEBUG
+
+# define CHECK_PARAMETER(Expr, ...) \
+ do \
+ { \
+ VERIFY(Expr, __VA_ARGS__); \
+ if (!(Expr)) return false; \
+ } while (false)
+
+#else
+
+# define CHECK_PARAMETER(Expr, ...) \
+ do \
+ { \
+ if (!(Expr)) \
+ { \
+ LOG_ERROR_MESSAGE(__VA_ARGS__); \
+ return false; \
+ } \
+ } while (false)
+
+#endif
+
+bool VerifyDrawAttribs(const DrawAttribs& Attribs)
+{
+#define CHECK_DRAW_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Draw attribs are invalid: ", __VA_ARGS__)
+
+ CHECK_DRAW_ATTRIBS(Attribs.NumVertices != 0, "NumVertices must not be zero.");
+
+#undef CHECK_DRAW_ATTRIBS
+
+ return true;
+}
+
+bool VerifyDrawIndexedAttribs(const DrawIndexedAttribs& Attribs)
+{
+#define CHECK_DRAW_INDEXED_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Draw indexed attribs are invalid: ", __VA_ARGS__)
+
+ CHECK_DRAW_INDEXED_ATTRIBS(Attribs.IndexType == VT_UINT16 || Attribs.IndexType == VT_UINT32,
+ "IndexType (", GetValueTypeString(Attribs.IndexType), ") must be VT_UINT16 or VT_UINT32.");
+
+ CHECK_DRAW_INDEXED_ATTRIBS(Attribs.NumIndices != 0, "NumIndices must not be zero.");
+
+#undef CHECK_DRAW_INDEXED_ATTRIBS
+
+ return true;
+}
+
+bool VerifyDrawMeshAttribs(Uint32 MaxDrawMeshTasksCount, const DrawMeshAttribs& Attribs)
+{
+#define CHECK_DRAW_MESH_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Draw mesh attribs are invalid: ", __VA_ARGS__)
+
+ CHECK_DRAW_MESH_ATTRIBS(Attribs.ThreadGroupCount != 0, "ThreadGroupCount must not be zero.");
+ CHECK_DRAW_MESH_ATTRIBS(Attribs.ThreadGroupCount <= MaxDrawMeshTasksCount,
+ "ThreadGroupCount (", Attribs.ThreadGroupCount, ") must not exceed ", MaxDrawMeshTasksCount);
+
+#undef CHECK_DRAW_MESH_ATTRIBS
+
+ return true;
+}
+
+bool VerifyDrawIndirectAttribs(const DrawIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)
+{
+#define CHECK_DRAW_INDIRECT_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Draw indirect attribs are invalid: ", __VA_ARGS__)
+
+ CHECK_DRAW_INDIRECT_ATTRIBS(pAttribsBuffer != nullptr, "indirect draw arguments buffer must not be null.");
+ CHECK_DRAW_INDIRECT_ATTRIBS((pAttribsBuffer->GetDesc().BindFlags & BIND_INDIRECT_DRAW_ARGS) != 0,
+ "indirect draw arguments buffer '", pAttribsBuffer->GetDesc().Name, "' was not created with BIND_INDIRECT_DRAW_ARGS flag.");
+
+#undef CHECK_DRAW_INDIRECT_ATTRIBS
+
+ return true;
+}
+
+bool VerifyDrawIndexedIndirectAttribs(const DrawIndexedIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)
+{
+#define CHECK_DRAW_INDEXED_INDIRECT_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Draw indexed indirect attribs are invalid: ", __VA_ARGS__)
+
+ CHECK_DRAW_INDEXED_INDIRECT_ATTRIBS(pAttribsBuffer != nullptr, "indirect draw arguments buffer must not null.");
+ CHECK_DRAW_INDEXED_INDIRECT_ATTRIBS(Attribs.IndexType == VT_UINT16 || Attribs.IndexType == VT_UINT32,
+ "IndexType (", GetValueTypeString(Attribs.IndexType), ") must be VT_UINT16 or VT_UINT32.");
+ CHECK_DRAW_INDEXED_INDIRECT_ATTRIBS((pAttribsBuffer->GetDesc().BindFlags & BIND_INDIRECT_DRAW_ARGS) != 0,
+ "indirect draw arguments buffer '",
+ pAttribsBuffer->GetDesc().Name, "' was not created with BIND_INDIRECT_DRAW_ARGS flag.");
+
+#undef CHECK_DRAW_INDEXED_INDIRECT_ATTRIBS
+
+ return true;
+}
+
+bool VerifyDrawMeshIndirectAttribs(const DrawMeshIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)
+{
+#define CHECK_DRAW_MESH_INDIRECT_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Draw mesh indirect attribs are invalid: ", __VA_ARGS__)
+
+ CHECK_DRAW_MESH_INDIRECT_ATTRIBS(pAttribsBuffer != nullptr, "indirect draw arguments buffer must not be null.");
+ CHECK_DRAW_MESH_INDIRECT_ATTRIBS((pAttribsBuffer->GetDesc().BindFlags & BIND_INDIRECT_DRAW_ARGS) != 0,
+ "indirect draw arguments buffer '", pAttribsBuffer->GetDesc().Name,
+ "' was not created with BIND_INDIRECT_DRAW_ARGS flag.");
+
+#undef CHECK_DRAW_MESH_INDIRECT_ATTRIBS
+
+ return true;
+}
+
+
+bool VerifyDispatchComputeAttribs(const DispatchComputeAttribs& Attribs)
+{
+#define CHECK_DISPATCH_COMPUTE_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Dispatch compute attribs are invalid: ", __VA_ARGS__)
+
+ CHECK_DISPATCH_COMPUTE_ATTRIBS(Attribs.ThreadGroupCountX != 0, "ThreadGroupCountX must no be zero.");
+ CHECK_DISPATCH_COMPUTE_ATTRIBS(Attribs.ThreadGroupCountY != 0, "ThreadGroupCountY must no be zero.");
+ CHECK_DISPATCH_COMPUTE_ATTRIBS(Attribs.ThreadGroupCountZ != 0, "ThreadGroupCountZ must no be zero.");
+
+#undef CHECK_DISPATCH_COMPUTE_ATTRIBS
+
+ return true;
+}
+
+bool VerifyDispatchComputeIndirectAttribs(const DispatchComputeIndirectAttribs& Attribs, const IBuffer* pAttribsBuffer)
+{
+#define CHECK_DISPATCH_COMPUTE_INDIRECT_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Dispatch compute indirect attribs are invalid: ", __VA_ARGS__)
+
+ CHECK_DISPATCH_COMPUTE_INDIRECT_ATTRIBS(pAttribsBuffer != nullptr, "indirect dispatch arguments buffer must not be null.");
+ CHECK_DISPATCH_COMPUTE_INDIRECT_ATTRIBS((pAttribsBuffer->GetDesc().BindFlags & BIND_INDIRECT_DRAW_ARGS) != 0,
+ "indirect dispatch arguments buffer '",
+ pAttribsBuffer->GetDesc().Name, "' was not created with BIND_INDIRECT_DRAW_ARGS flag.");
+
+#undef CHECK_DISPATCH_COMPUTE_INDIRECT_ATTRIBS
+
+ return true;
+}
+
+bool VerifyResolveTextureSubresourceAttribs(const ResolveTextureSubresourceAttribs& ResolveAttribs,
+ const TextureDesc& SrcTexDesc,
+ const TextureDesc& DstTexDesc)
+{
+#define CHECK_RESOLVE_TEX_SUBRES_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Resolve texture subresource attribs are invalid: ", __VA_ARGS__)
+
+ CHECK_RESOLVE_TEX_SUBRES_ATTRIBS(SrcTexDesc.SampleCount > 1, "source texture '", SrcTexDesc.Name, "' of a resolve operation is not multi-sampled");
+ CHECK_RESOLVE_TEX_SUBRES_ATTRIBS(DstTexDesc.SampleCount == 1, "destination texture '", DstTexDesc.Name, "' of a resolve operation is multi-sampled");
+
+ auto SrcMipLevelProps = GetMipLevelProperties(SrcTexDesc, ResolveAttribs.SrcMipLevel);
+ auto DstMipLevelProps = GetMipLevelProperties(DstTexDesc, ResolveAttribs.DstMipLevel);
+ CHECK_RESOLVE_TEX_SUBRES_ATTRIBS(SrcMipLevelProps.LogicalWidth == DstMipLevelProps.LogicalWidth && SrcMipLevelProps.LogicalHeight == DstMipLevelProps.LogicalHeight,
+ "the size (", SrcMipLevelProps.LogicalWidth, "x", SrcMipLevelProps.LogicalHeight,
+ ") of the source subresource of a resolve operation (texture '",
+ SrcTexDesc.Name, "', mip ", ResolveAttribs.SrcMipLevel, ", slice ", ResolveAttribs.SrcSlice,
+ ") does not match the size (", DstMipLevelProps.LogicalWidth, "x", DstMipLevelProps.LogicalHeight,
+ ") of the destination subresource (texture '", DstTexDesc.Name, "', mip ", ResolveAttribs.DstMipLevel, ", slice ",
+ ResolveAttribs.DstSlice, ")");
+
+ const auto& SrcFmtAttribs = GetTextureFormatAttribs(SrcTexDesc.Format);
+ const auto& DstFmtAttribs = GetTextureFormatAttribs(DstTexDesc.Format);
+ const auto& ResolveFmtAttribs = GetTextureFormatAttribs(ResolveAttribs.Format);
+ if (!SrcFmtAttribs.IsTypeless && !DstFmtAttribs.IsTypeless)
+ {
+ CHECK_RESOLVE_TEX_SUBRES_ATTRIBS(SrcTexDesc.Format == DstTexDesc.Format,
+ "source (", SrcFmtAttribs.Name, ") and destination (", DstFmtAttribs.Name,
+ ") texture formats of a resolve operation must match exaclty or be compatible typeless formats");
+ CHECK_RESOLVE_TEX_SUBRES_ATTRIBS(ResolveAttribs.Format == TEX_FORMAT_UNKNOWN || SrcTexDesc.Format == ResolveAttribs.Format, "Invalid format of a resolve operation");
+ }
+ if (SrcFmtAttribs.IsTypeless && DstFmtAttribs.IsTypeless)
+ {
+ CHECK_RESOLVE_TEX_SUBRES_ATTRIBS(ResolveAttribs.Format != TEX_FORMAT_UNKNOWN,
+ "format of a resolve operation must not be unknown when both src and dst texture formats are typeless");
+ }
+ if (SrcFmtAttribs.IsTypeless || DstFmtAttribs.IsTypeless)
+ {
+ CHECK_RESOLVE_TEX_SUBRES_ATTRIBS(!ResolveFmtAttribs.IsTypeless,
+ "format of a resolve operation must not be typeless when one of the texture formats is typeless");
+ }
+#undef CHECK_RESOLVE_TEX_SUBRES_ATTRIBS
+
+ return true;
+}
+
+bool VerifyBeginRenderPassAttribs(const BeginRenderPassAttribs& Attribs)
+{
+#define CHECK_BEGIN_RENDER_PASS_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Begin render pass attribs are invalid: ", __VA_ARGS__)
+
+ CHECK_BEGIN_RENDER_PASS_ATTRIBS(Attribs.pRenderPass != nullptr, "pRenderPass pass must not be null");
+ CHECK_BEGIN_RENDER_PASS_ATTRIBS(Attribs.pFramebuffer != nullptr, "pFramebuffer must not be null");
+
+ const auto& RPDesc = Attribs.pRenderPass->GetDesc();
+
+ Uint32 NumRequiredClearValues = 0;
+ for (Uint32 i = 0; i < RPDesc.AttachmentCount; ++i)
+ {
+ const auto& Attchmnt = RPDesc.pAttachments[i];
+ if (Attchmnt.LoadOp == ATTACHMENT_LOAD_OP_CLEAR)
+ NumRequiredClearValues = i + 1;
+
+ const auto& FmtAttribs = GetTextureFormatAttribs(Attchmnt.Format);
+ if (FmtAttribs.ComponentType == COMPONENT_TYPE_DEPTH_STENCIL)
+ {
+ if (Attchmnt.StencilLoadOp == ATTACHMENT_LOAD_OP_CLEAR)
+ NumRequiredClearValues = i + 1;
+ }
+ }
+
+ CHECK_BEGIN_RENDER_PASS_ATTRIBS(Attribs.ClearValueCount >= NumRequiredClearValues,
+ "at least ", NumRequiredClearValues, " clear values are required, but only ",
+ Uint32{Attribs.ClearValueCount}, " are provided.");
+ CHECK_BEGIN_RENDER_PASS_ATTRIBS(Attribs.ClearValueCount == 0 || Attribs.pClearValues != nullptr,
+ "pClearValues must not be null when ClearValueCount (", Attribs.ClearValueCount, ") is not zero");
+
+#undef CHECK_BEGIN_RENDER_PASS_ATTRIBS
+
+ return true;
+}
+
+bool VerifyStateTransitionDesc(const IRenderDevice* pDevice, const StateTransitionDesc& Barrier)
+{
+#define CHECK_STATE_TRANSITION_DESC(Expr, ...) CHECK_PARAMETER(Expr, "State transition parameters are invalid: ", __VA_ARGS__)
+
+ CHECK_STATE_TRANSITION_DESC(Barrier.pResource != nullptr, "pResource must not be null");
+ CHECK_STATE_TRANSITION_DESC(Barrier.NewState != RESOURCE_STATE_UNKNOWN, "NewState state can't be UNKNOWN");
+
+ RESOURCE_STATE OldState = RESOURCE_STATE_UNKNOWN;
+
+ if (RefCntAutoPtr<ITexture> pTexture{Barrier.pResource, IID_Texture})
+ {
+ const auto& TexDesc = pTexture->GetDesc();
+
+ CHECK_STATE_TRANSITION_DESC(VerifyResourceStates(Barrier.NewState, true), "invlaid new state specified for texture '", TexDesc.Name, "'");
+ OldState = Barrier.OldState != RESOURCE_STATE_UNKNOWN ? Barrier.OldState : pTexture->GetState();
+ CHECK_STATE_TRANSITION_DESC(OldState != RESOURCE_STATE_UNKNOWN,
+ "the state of texture '", TexDesc.Name,
+ "' is unknown to the engine and is not explicitly specified in the barrier");
+ CHECK_STATE_TRANSITION_DESC(VerifyResourceStates(OldState, true), "invlaid old state specified for texture '", TexDesc.Name, "'");
+
+ CHECK_STATE_TRANSITION_DESC(Barrier.FirstMipLevel < TexDesc.MipLevels, "first mip level (", Barrier.FirstMipLevel,
+ ") specified by the barrier is out of range. Texture '",
+ TexDesc.Name, "' has only ", TexDesc.MipLevels, " mip level(s)");
+ CHECK_STATE_TRANSITION_DESC(Barrier.MipLevelsCount == REMAINING_MIP_LEVELS || Barrier.FirstMipLevel + Barrier.MipLevelsCount <= TexDesc.MipLevels,
+ "mip level range ", Barrier.FirstMipLevel, "..", Barrier.FirstMipLevel + Barrier.MipLevelsCount - 1,
+ " specified by the barrier is out of range. Texture '",
+ TexDesc.Name, "' has only ", TexDesc.MipLevels, " mip level(s)");
+
+ CHECK_STATE_TRANSITION_DESC(Barrier.FirstArraySlice < TexDesc.ArraySize, "first array slice (", Barrier.FirstArraySlice,
+ ") specified by the barrier is out of range. Array size of texture '",
+ TexDesc.Name, "' is ", TexDesc.ArraySize);
+ CHECK_STATE_TRANSITION_DESC(Barrier.ArraySliceCount == REMAINING_ARRAY_SLICES || Barrier.FirstArraySlice + Barrier.ArraySliceCount <= TexDesc.ArraySize,
+ "array slice range ", Barrier.FirstArraySlice, "..", Barrier.FirstArraySlice + Barrier.ArraySliceCount - 1,
+ " specified by the barrier is out of range. Array size of texture '",
+ TexDesc.Name, "' is ", TexDesc.ArraySize);
+
+ auto DevType = pDevice->GetDeviceCaps().DevType;
+ if (DevType != RENDER_DEVICE_TYPE_D3D12 && DevType != RENDER_DEVICE_TYPE_VULKAN)
+ {
+ CHECK_STATE_TRANSITION_DESC(Barrier.FirstMipLevel == 0 && (Barrier.MipLevelsCount == REMAINING_MIP_LEVELS || Barrier.MipLevelsCount == TexDesc.MipLevels),
+ "failed to transition texture '", TexDesc.Name, "': only whole resources can be transitioned on this device");
+ CHECK_STATE_TRANSITION_DESC(Barrier.FirstArraySlice == 0 && (Barrier.ArraySliceCount == REMAINING_ARRAY_SLICES || Barrier.ArraySliceCount == TexDesc.ArraySize),
+ "failed to transition texture '", TexDesc.Name, "': only whole resources can be transitioned on this device");
+ }
+ }
+ else if (RefCntAutoPtr<IBuffer> pBuffer{Barrier.pResource, IID_Buffer})
+ {
+ const auto& BuffDesc = pBuffer->GetDesc();
+ CHECK_STATE_TRANSITION_DESC(VerifyResourceStates(Barrier.NewState, false), "invlaid new state specified for buffer '", BuffDesc.Name, "'");
+ OldState = Barrier.OldState != RESOURCE_STATE_UNKNOWN ? Barrier.OldState : pBuffer->GetState();
+ CHECK_STATE_TRANSITION_DESC(OldState != RESOURCE_STATE_UNKNOWN, "the state of buffer '", BuffDesc.Name, "' is unknown to the engine and is not explicitly specified in the barrier");
+ CHECK_STATE_TRANSITION_DESC(VerifyResourceStates(OldState, false), "invlaid old state specified for buffer '", BuffDesc.Name, "'");
+ }
+ else if (RefCntAutoPtr<IBottomLevelAS> pBottomLevelAS{Barrier.pResource, IID_BottomLevelAS})
+ {
+ const auto& BLASDesc = pBottomLevelAS->GetDesc();
+ OldState = Barrier.OldState != RESOURCE_STATE_UNKNOWN ? Barrier.OldState : pBottomLevelAS->GetState();
+ CHECK_STATE_TRANSITION_DESC(OldState != RESOURCE_STATE_UNKNOWN, "the state of BLAS '", BLASDesc.Name, "' is unknown to the engine and is not explicitly specified in the barrier");
+ CHECK_STATE_TRANSITION_DESC(Barrier.NewState == RESOURCE_STATE_BUILD_AS_READ || Barrier.NewState == RESOURCE_STATE_BUILD_AS_WRITE,
+ "invlaid new state specified for BLAS '", BLASDesc.Name, "'");
+ CHECK_STATE_TRANSITION_DESC(Barrier.TransitionType != STATE_TRANSITION_TYPE_IMMEDIATE, "split barriers are not supported for BLAS");
+ }
+ else if (RefCntAutoPtr<ITopLevelAS> pTopLevelAS{Barrier.pResource, IID_TopLevelAS})
+ {
+ const auto& TLASDesc = pTopLevelAS->GetDesc();
+ OldState = Barrier.OldState != RESOURCE_STATE_UNKNOWN ? Barrier.OldState : pTopLevelAS->GetState();
+ CHECK_STATE_TRANSITION_DESC(OldState != RESOURCE_STATE_UNKNOWN, "the state of TLAS '", TLASDesc.Name, "' is unknown to the engine and is not explicitly specified in the barrier");
+ CHECK_STATE_TRANSITION_DESC(Barrier.NewState == RESOURCE_STATE_BUILD_AS_READ || Barrier.NewState == RESOURCE_STATE_BUILD_AS_WRITE || Barrier.NewState == RESOURCE_STATE_RAY_TRACING,
+ "invlaid new state specified for TLAS '", TLASDesc.Name, "'");
+ CHECK_STATE_TRANSITION_DESC(Barrier.TransitionType != STATE_TRANSITION_TYPE_IMMEDIATE, "split barriers are not supported for TLAS");
+ }
+ else
+ {
+ UNEXPECTED("unsupported resource type");
+ }
+
+ if (OldState == RESOURCE_STATE_UNORDERED_ACCESS && Barrier.NewState == RESOURCE_STATE_UNORDERED_ACCESS)
+ {
+ CHECK_STATE_TRANSITION_DESC(Barrier.TransitionType == STATE_TRANSITION_TYPE_IMMEDIATE, "for UAV barriers, transition type must be STATE_TRANSITION_TYPE_IMMEDIATE");
+ }
+
+ if (Barrier.TransitionType == STATE_TRANSITION_TYPE_BEGIN)
+ {
+ CHECK_STATE_TRANSITION_DESC(!Barrier.UpdateResourceState, "resource state can't be updated in begin-split barrier");
+ }
+
+#undef CHECK_STATE_TRANSITION_DESC
+
+ return true;
+}
+
+
+bool VerifyBuildBLASAttribs(const BuildBLASAttribs& Attribs)
+{
+#define CHECK_BUILD_BLAS_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Build BLAS attribs are invalid: ", __VA_ARGS__)
+
+ CHECK_BUILD_BLAS_ATTRIBS(Attribs.pBLAS != nullptr, "pBLAS must not be null");
+ CHECK_BUILD_BLAS_ATTRIBS(Attribs.pScratchBuffer != nullptr, "pScratchBuffer must not be null");
+ CHECK_BUILD_BLAS_ATTRIBS((Attribs.pTriangleData != nullptr) ^ (Attribs.pBoxData != nullptr), "exactly one of pTriangles and pBoxes must be defined");
+ CHECK_BUILD_BLAS_ATTRIBS(Attribs.pBoxData != nullptr || Attribs.BoxDataCount == 0, "pBoxData is null, but BoxDataCount is not 0");
+ CHECK_BUILD_BLAS_ATTRIBS(Attribs.pTriangleData != nullptr || Attribs.TriangleDataCount == 0, "pTriangleData is null, but TriangleDataCount is not 0");
+
+ const auto& BLASDesc = Attribs.pBLAS->GetDesc();
+
+ CHECK_BUILD_BLAS_ATTRIBS(Attribs.BoxDataCount <= BLASDesc.BoxCount, "BoxDataCount must be less than or equal to pBLAS->GetDesc().BoxCount");
+ CHECK_BUILD_BLAS_ATTRIBS(Attribs.TriangleDataCount <= BLASDesc.TriangleCount, "TriangleDataCount must be less than or equal to pBLAS->GetDesc().TriangleCount");
+
+ if (Attribs.Update)
+ {
+ CHECK_BUILD_BLAS_ATTRIBS((BLASDesc.Flags & RAYTRACING_BUILD_AS_ALLOW_UPDATE) == RAYTRACING_BUILD_AS_ALLOW_UPDATE,
+ "Update is true, but BLAS was created without RAYTRACING_BUILD_AS_ALLOW_UPDATE flag");
+
+ const Uint32 GeomCount = Attribs.pBLAS->GetActualGeometryCount();
+ CHECK_BUILD_BLAS_ATTRIBS(Attribs.BoxDataCount == 0 || Attribs.BoxDataCount == GeomCount,
+ "Update is true, but BoxDataCount (", Attribs.BoxDataCount, ") does not match the previous value (", GeomCount, ")");
+ CHECK_BUILD_BLAS_ATTRIBS(Attribs.TriangleDataCount == 0 || Attribs.TriangleDataCount == GeomCount,
+ "Update is true, but TriangleDataCount (", Attribs.TriangleDataCount, ") does not match the previous value (", GeomCount, ")");
+ }
+
+ for (Uint32 i = 0; i < Attribs.TriangleDataCount; ++i)
+ {
+ const auto& tri = Attribs.pTriangleData[i];
+ const Uint32 VertexSize = GetValueSize(tri.VertexValueType) * tri.VertexComponentCount;
+ const Uint32 VertexDataSize = tri.VertexStride * tri.VertexCount;
+ const Uint32 GeomIndex = Attribs.pBLAS->GetGeometryDescIndex(tri.GeometryName);
+
+ CHECK_BUILD_BLAS_ATTRIBS(GeomIndex != INVALID_INDEX,
+ "pTriangleData[", i, "].GeometryName (", tri.GeometryName, ") is not found in BLAS description");
+
+ const auto& TriDesc = BLASDesc.pTriangles[GeomIndex];
+
+ CHECK_BUILD_BLAS_ATTRIBS(tri.VertexValueType == VT_UNDEFINED || tri.VertexValueType == TriDesc.VertexValueType,
+ "pTriangleData[", i, "].VertexValueType must be undefined or match the VertexValueType in geometry description");
+
+ CHECK_BUILD_BLAS_ATTRIBS(tri.VertexComponentCount == 0 || tri.VertexComponentCount == TriDesc.VertexComponentCount,
+ "pTriangleData[", i, "].VertexComponentCount (", tri.VertexComponentCount, ") must be 0 or match the VertexComponentCount (",
+ TriDesc.VertexComponentCount, ") in geometry description");
+
+ CHECK_BUILD_BLAS_ATTRIBS(tri.VertexCount <= TriDesc.MaxVertexCount,
+ "pTriangleData[", i, "].VertexCount (", tri.VertexCount, ") must not be greater than MaxVertexCount(", TriDesc.MaxVertexCount, ")");
+
+ CHECK_BUILD_BLAS_ATTRIBS(tri.VertexStride >= VertexSize,
+ "pTriangleData[", i, "].VertexStride (", tri.VertexStride, ") must be at least ", VertexSize, " bytes");
+
+ CHECK_BUILD_BLAS_ATTRIBS(tri.pVertexBuffer != nullptr, "pTriangleData[", i, "].pVertexBuffer must not be null");
+
+ const BufferDesc& VertBufDesc = tri.pVertexBuffer->GetDesc();
+ CHECK_BUILD_BLAS_ATTRIBS((VertBufDesc.BindFlags & BIND_RAY_TRACING) == BIND_RAY_TRACING,
+ "pTriangleData[", i, "].pVertexBuffer was not created with BIND_RAY_TRACING flag");
+
+ CHECK_BUILD_BLAS_ATTRIBS(tri.VertexOffset + VertexDataSize <= VertBufDesc.uiSizeInBytes,
+ "pTriangleData[", i, "].pVertexBuffer is too small for the specified VertexStride (", tri.VertexStride, ") and VertexCount (",
+ tri.VertexCount, "): at least ", tri.VertexOffset + VertexDataSize, " bytes are required");
+
+ CHECK_BUILD_BLAS_ATTRIBS(tri.IndexType == VT_UNDEFINED || tri.IndexType == TriDesc.IndexType,
+ "pTriangleData[", i, "].IndexType (", GetValueTypeString(tri.IndexType), ") must match the IndexType (",
+ TriDesc.IndexType, ") in geometry description");
+
+ CHECK_BUILD_BLAS_ATTRIBS(tri.PrimitiveCount <= TriDesc.MaxPrimitiveCount,
+ "pTriangleData[", i, "].PrimitiveCount (", tri.PrimitiveCount, ") must not be greater than MaxPrimitiveCount (",
+ TriDesc.MaxPrimitiveCount, ")");
+
+ if (TriDesc.IndexType != VT_UNDEFINED)
+ {
+ CHECK_BUILD_BLAS_ATTRIBS(tri.pIndexBuffer != nullptr, "pTriangleData[", i, "].pIndexBuffer must not be null");
+
+ const BufferDesc& InstBufDesc = tri.pIndexBuffer->GetDesc();
+ const Uint32 IndexDataSize = tri.PrimitiveCount * 3 * GetValueSize(tri.IndexType);
+
+ CHECK_BUILD_BLAS_ATTRIBS((InstBufDesc.BindFlags & BIND_RAY_TRACING) == BIND_RAY_TRACING,
+ "pTriangleData[", i, "].pIndexBuffer was not created with BIND_RAY_TRACING flag");
+
+ CHECK_BUILD_BLAS_ATTRIBS(tri.IndexOffset + IndexDataSize <= InstBufDesc.uiSizeInBytes,
+ "pTriangleData[", i, "].pIndexBuffer is too small for specified IndexType and IndexCount: at least",
+ tri.IndexOffset + IndexDataSize, " bytes are required");
+ }
+ else
+ {
+ CHECK_BUILD_BLAS_ATTRIBS(tri.VertexCount == tri.PrimitiveCount * 3,
+ "pTriangleData[", i, "].VertexCount (", tri.VertexCount, ") must equal to PrimitiveCount * 3 (",
+ tri.PrimitiveCount * 3, ")");
+
+ CHECK_BUILD_BLAS_ATTRIBS(tri.pIndexBuffer == nullptr, "pTriangleData[", i, "].pIndexBuffer must be null if IndexType is VT_UNDEFINED");
+ }
+
+ if (tri.pTransformBuffer != nullptr)
+ {
+ CHECK_BUILD_BLAS_ATTRIBS((tri.pTransformBuffer->GetDesc().BindFlags & BIND_RAY_TRACING) == BIND_RAY_TRACING,
+ "pTriangleData[", i, "].pTransformBuffer was not created with BIND_RAY_TRACING flag");
+
+ CHECK_BUILD_BLAS_ATTRIBS(TriDesc.AllowsTransforms, "pTriangleData[", i, "] uses transform buffer, but AllowsTransforms is false");
+ }
+ }
+
+ for (Uint32 i = 0; i < Attribs.BoxDataCount; ++i)
+ {
+ const auto& box = Attribs.pBoxData[i];
+ const Uint32 BoxSize = sizeof(float) * 6;
+ const Uint32 GeomIndex = Attribs.pBLAS->GetGeometryDescIndex(box.GeometryName);
+
+ CHECK_BUILD_BLAS_ATTRIBS(GeomIndex != INVALID_INDEX,
+ "pBoxData[", i, "].GeometryName (", box.GeometryName, ") is not found in BLAS description");
+
+ const auto& BoxDesc = BLASDesc.pBoxes[GeomIndex];
+
+ CHECK_BUILD_BLAS_ATTRIBS(box.BoxCount <= BoxDesc.MaxBoxCount,
+ "pBoxData[", i, "].BoxCount (", box.BoxCount, ") must not be greated than MaxBoxCount (", BoxDesc.MaxBoxCount, ")");
+
+ CHECK_BUILD_BLAS_ATTRIBS(box.BoxStride >= BoxSize,
+ "pBoxData[", i, "].BoxStride (", box.BoxStride, ") must be at least ", BoxSize, " bytes");
+ CHECK_BUILD_BLAS_ATTRIBS(box.BoxStride % 8 == 0,
+ "pBoxData[", i, "].BoxStride (", box.BoxStride, ") must be aligned to 8 bytes");
+
+ CHECK_BUILD_BLAS_ATTRIBS(box.pBoxBuffer != nullptr, "pBoxData[", i, "].pBoxBuffer must not be null");
+
+ CHECK_BUILD_BLAS_ATTRIBS((box.pBoxBuffer->GetDesc().BindFlags & BIND_RAY_TRACING) == BIND_RAY_TRACING,
+ "pBoxData[", i, "].pBoxBuffer was not created with BIND_RAY_TRACING flag");
+ }
+
+ const auto& ScratchDesc = Attribs.pScratchBuffer->GetDesc();
+
+ CHECK_BUILD_BLAS_ATTRIBS(Attribs.ScratchBufferOffset <= ScratchDesc.uiSizeInBytes,
+ "ScratchBufferOffset (", Attribs.ScratchBufferOffset, ") is greater than the buffer size (", ScratchDesc.uiSizeInBytes, ")");
+
+ if (Attribs.Update)
+ {
+ CHECK_BUILD_BLAS_ATTRIBS(ScratchDesc.uiSizeInBytes - Attribs.ScratchBufferOffset >= Attribs.pBLAS->GetScratchBufferSizes().Update,
+ "pScratchBuffer size is too small, use pBLAS->GetScratchBufferSizes().Update to get the required size for the scratch buffer");
+ }
+ else
+ {
+ CHECK_BUILD_BLAS_ATTRIBS(ScratchDesc.uiSizeInBytes - Attribs.ScratchBufferOffset >= Attribs.pBLAS->GetScratchBufferSizes().Build,
+ "pScratchBuffer size is too small, use pBLAS->GetScratchBufferSizes().Build to get the required size for the scratch buffer");
+ }
+
+ CHECK_BUILD_BLAS_ATTRIBS((ScratchDesc.BindFlags & BIND_RAY_TRACING) == BIND_RAY_TRACING,
+ "pScratchBuffer was not created with BIND_RAY_TRACING flag");
+
+#undef CHECK_BUILD_BLAS_ATTRIBS
+
+ return true;
+}
+
+
+bool VerifyBuildTLASAttribs(const BuildTLASAttribs& Attribs)
+{
+#define CHECK_BUILD_TLAS_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Build TLAS attribs are invalid: ", __VA_ARGS__)
+
+ CHECK_BUILD_TLAS_ATTRIBS(Attribs.pTLAS != nullptr, "pTLAS must not be null");
+ CHECK_BUILD_TLAS_ATTRIBS(Attribs.pScratchBuffer != nullptr, "pScratchBuffer must not be null");
+ CHECK_BUILD_TLAS_ATTRIBS(Attribs.pInstances != nullptr, "pInstances must not be null");
+ CHECK_BUILD_TLAS_ATTRIBS(Attribs.pInstanceBuffer != nullptr, "pInstanceBuffer must not be null");
+
+ CHECK_BUILD_TLAS_ATTRIBS(Attribs.BindingMode == HIT_GROUP_BINDING_MODE_USER_DEFINED || Attribs.HitGroupStride != 0,
+ "HitGroupStride must be greater than 0 if BindingMode is not HIT_GROUP_BINDING_MODE_USER_DEFINED");
+
+ const auto& TLASDesc = Attribs.pTLAS->GetDesc();
+
+ CHECK_BUILD_TLAS_ATTRIBS(Attribs.InstanceCount <= TLASDesc.MaxInstanceCount,
+ "InstanceCount (", Attribs.InstanceCount, ") must be less than or equal to pTLAS->GetDesc().MaxInstanceCount (",
+ TLASDesc.MaxInstanceCount, ")");
+
+ if (Attribs.Update)
+ {
+ CHECK_BUILD_TLAS_ATTRIBS((TLASDesc.Flags & RAYTRACING_BUILD_AS_ALLOW_UPDATE) == RAYTRACING_BUILD_AS_ALLOW_UPDATE,
+ "Update is true, but TLAS created without RAYTRACING_BUILD_AS_ALLOW_UPDATE flag");
+
+ const Uint32 PrevInstanceCount = Attribs.pTLAS->GetBuildInfo().InstanceCount;
+ CHECK_BUILD_TLAS_ATTRIBS(PrevInstanceCount == Attribs.InstanceCount,
+ "Update is true, but InstanceCount (", Attribs.InstanceCount, ") does not match with the previous value (", PrevInstanceCount, ")");
+ }
+
+ const auto& InstDesc = Attribs.pInstanceBuffer->GetDesc();
+ const auto InstDataSize = size_t{Attribs.InstanceCount} * size_t{TLAS_INSTANCE_DATA_SIZE};
+ Uint32 AutoOffsetCounter = 0;
+
+ // Calculate instance data size
+ for (Uint32 i = 0; i < Attribs.InstanceCount; ++i)
+ {
+ constexpr Uint32 BitMask = (1u << 24) - 1;
+ const auto& Inst = Attribs.pInstances[i];
+
+ VERIFY((Inst.CustomId & ~BitMask) == 0, "Only the lower 24 bits are used");
+
+ VERIFY(Inst.ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO ||
+ (Inst.ContributionToHitGroupIndex & ~BitMask) == 0,
+ "Only the lower 24 bits are used");
+
+ CHECK_BUILD_TLAS_ATTRIBS(Inst.InstanceName != nullptr, "pInstances[", i, "].InstanceName must not be null");
+ CHECK_BUILD_TLAS_ATTRIBS(Inst.pBLAS != nullptr, "pInstances[", i, "].pBLAS must not be null");
+
+ if (Attribs.Update)
+ {
+ const TLASInstanceDesc IDesc = Attribs.pTLAS->GetInstanceDesc(Inst.InstanceName);
+ CHECK_BUILD_TLAS_ATTRIBS(IDesc.InstanceIndex != INVALID_INDEX, "Update is true, but pInstances[", i, "].InstanceName does not exists");
+ }
+
+ if (Inst.ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO)
+ ++AutoOffsetCounter;
+
+ CHECK_BUILD_TLAS_ATTRIBS(Attribs.BindingMode == HIT_GROUP_BINDING_MODE_USER_DEFINED || Inst.ContributionToHitGroupIndex == TLAS_INSTANCE_OFFSET_AUTO,
+ "pInstances[", i,
+ "].ContributionToHitGroupIndex must be TLAS_INSTANCE_OFFSET_AUTO "
+ "if BindingMode is not HIT_GROUP_BINDING_MODE_USER_DEFINED");
+ }
+
+ CHECK_BUILD_TLAS_ATTRIBS(AutoOffsetCounter == 0 || AutoOffsetCounter == Attribs.InstanceCount,
+ "all pInstances[i].ContributionToHitGroupIndex must be TLAS_INSTANCE_OFFSET_AUTO, or none of them should");
+
+ CHECK_BUILD_TLAS_ATTRIBS(Attribs.InstanceBufferOffset <= InstDesc.uiSizeInBytes,
+ "InstanceBufferOffset (", Attribs.InstanceBufferOffset, ") is greater than the buffer size (", InstDesc.uiSizeInBytes, ")");
+
+ CHECK_BUILD_TLAS_ATTRIBS(InstDesc.uiSizeInBytes - Attribs.InstanceBufferOffset >= InstDataSize,
+ "pInstanceBuffer size (", InstDesc.uiSizeInBytes, ") is too small: at least ",
+ InstDataSize + Attribs.InstanceBufferOffset, " bytes are required");
+
+ CHECK_BUILD_TLAS_ATTRIBS((InstDesc.BindFlags & BIND_RAY_TRACING) == BIND_RAY_TRACING,
+ "pInstanceBuffer was not created with BIND_RAY_TRACING flag");
+
+ const auto& ScratchDesc = Attribs.pScratchBuffer->GetDesc();
+
+ CHECK_BUILD_TLAS_ATTRIBS(Attribs.ScratchBufferOffset <= ScratchDesc.uiSizeInBytes,
+ "ScratchBufferOffset (", Attribs.ScratchBufferOffset, ") is greater than the buffer size (", ScratchDesc.uiSizeInBytes, ")");
+
+ if (Attribs.Update)
+ {
+ CHECK_BUILD_TLAS_ATTRIBS(ScratchDesc.uiSizeInBytes - Attribs.ScratchBufferOffset >= Attribs.pTLAS->GetScratchBufferSizes().Update,
+ "pScratchBuffer size is too small, use pTLAS->GetScratchBufferSizes().Update to get the required size for scratch buffer");
+ }
+ else
+ {
+ CHECK_BUILD_TLAS_ATTRIBS(ScratchDesc.uiSizeInBytes - Attribs.ScratchBufferOffset >= Attribs.pTLAS->GetScratchBufferSizes().Build,
+ "pScratchBuffer size is too small, use pTLAS->GetScratchBufferSizes().Build to get the required size for scratch buffer");
+ }
+
+ CHECK_BUILD_TLAS_ATTRIBS((ScratchDesc.BindFlags & BIND_RAY_TRACING) == BIND_RAY_TRACING,
+ "pScratchBuffer was not created with BIND_RAY_TRACING flag");
+#undef CHECK_BUILD_TLAS_ATTRIBS
+
+ return true;
+}
+
+
+bool VerifyCopyBLASAttribs(const IRenderDevice* pDevice, const CopyBLASAttribs& Attribs)
+{
+#define CHECK_COPY_BLAS_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Copy BLAS attribs are invalid: ", __VA_ARGS__)
+
+ CHECK_COPY_BLAS_ATTRIBS(Attribs.pSrc != nullptr, "pSrc must not be null");
+ CHECK_COPY_BLAS_ATTRIBS(Attribs.pDst != nullptr, "pDst must not be null");
+
+ if (Attribs.Mode == COPY_AS_MODE_CLONE)
+ {
+ if (pDevice->GetDeviceCaps().DevType == RENDER_DEVICE_TYPE_VULKAN)
+ {
+ auto& SrcDesc = Attribs.pSrc->GetDesc();
+ auto& DstDesc = Attribs.pDst->GetDesc();
+
+ CHECK_COPY_BLAS_ATTRIBS(SrcDesc.TriangleCount == DstDesc.TriangleCount,
+ "Src BLAS triangle count (", SrcDesc.TriangleCount, ") must be equal to the dst BLAS triangle count (", DstDesc.TriangleCount, ")");
+
+ CHECK_COPY_BLAS_ATTRIBS(SrcDesc.BoxCount == DstDesc.BoxCount,
+ "Src BLAS box count (", SrcDesc.BoxCount, ") must be equal to the dst BLAS box count (", DstDesc.BoxCount, ")");
+
+ CHECK_COPY_BLAS_ATTRIBS(SrcDesc.Flags == DstDesc.Flags,
+ "Source and destination BLASes must have been created with the same flags");
+
+ for (Uint32 i = 0; i < SrcDesc.TriangleCount; ++i)
+ {
+ const BLASTriangleDesc& SrcTri = SrcDesc.pTriangles[i];
+ const Uint32 Index = Attribs.pDst->GetGeometryDescIndex(SrcTri.GeometryName);
+ CHECK_COPY_BLAS_ATTRIBS(Index != INVALID_INDEX,
+ "Src GeometryName ('", SrcTri.GeometryName, "') at index ", i, " is not found in pDst");
+ const BLASTriangleDesc& DstTri = DstDesc.pTriangles[Index];
+
+ CHECK_COPY_BLAS_ATTRIBS(SrcTri.MaxVertexCount == DstTri.MaxVertexCount,
+ "MaxVertexCount value (", SrcTri.MaxVertexCount, ") in source triangle description at index ", i,
+ " does not match MaxVertexCount value (", DstTri.MaxVertexCount, ") in the destination description");
+ CHECK_COPY_BLAS_ATTRIBS(SrcTri.VertexValueType == DstTri.VertexValueType,
+ "VertexValueType value (", GetValueTypeString(SrcTri.VertexValueType), ") in source triangle description at index ", i,
+ " does not match VertexValueType value (", GetValueTypeString(DstTri.VertexValueType), ") in destination description");
+ CHECK_COPY_BLAS_ATTRIBS(SrcTri.VertexComponentCount == DstTri.VertexComponentCount,
+ "VertexComponentCount value (", Uint32{SrcTri.VertexComponentCount}, ") in source triangle description at index ", i,
+ " does not match VertexComponentCount value (", Uint32{DstTri.VertexComponentCount}, ") in destination description");
+ CHECK_COPY_BLAS_ATTRIBS(SrcTri.MaxPrimitiveCount == DstTri.MaxPrimitiveCount,
+ "MaxPrimitiveCount value (", SrcTri.MaxPrimitiveCount, ") in source triangle description at index ", i,
+ " does not match MaxPrimitiveCount value (", DstTri.MaxPrimitiveCount, ") in destination description");
+ CHECK_COPY_BLAS_ATTRIBS(SrcTri.IndexType == DstTri.IndexType,
+ "IndexType value (", GetValueTypeString(SrcTri.IndexType), ") in source triangle description at index ", i,
+ " does not match IndexType value (", GetValueTypeString(DstTri.IndexType), ") in destination description");
+ CHECK_COPY_BLAS_ATTRIBS(SrcTri.AllowsTransforms == DstTri.AllowsTransforms,
+ "AllowsTransforms value (", (SrcTri.AllowsTransforms ? "true" : "false"), ") in source triangle description at index ", i,
+ " does not match AllowsTransforms value (", (DstTri.AllowsTransforms ? "true" : "false"), ") in destination description");
+ }
+
+ for (Uint32 i = 0; i < SrcDesc.BoxCount; ++i)
+ {
+ const BLASBoundingBoxDesc& SrcBox = SrcDesc.pBoxes[i];
+ const Uint32 Index = Attribs.pDst->GetGeometryDescIndex(SrcBox.GeometryName);
+ if (Index == INVALID_INDEX)
+ {
+ LOG_ERROR_MESSAGE("Copy BLAS attribs are invalid: pSrc->GetDesc().pBoxes[", i, "].GeometryName ('", SrcBox.GeometryName, "') is not found in pDst");
+ return false;
+ }
+ const BLASBoundingBoxDesc& DstBox = DstDesc.pBoxes[Index];
+
+ CHECK_COPY_BLAS_ATTRIBS(SrcBox.MaxBoxCount == DstBox.MaxBoxCount,
+ "MaxBoxCountt value (", SrcBox.MaxBoxCount, ") in source box description at index ", i,
+ " does not match MaxBoxCount value (", DstBox.MaxBoxCount, ") in destination description");
+ }
+ }
+ }
+ else if (Attribs.Mode == COPY_AS_MODE_COMPACT)
+ {
+ auto& SrcDesc = Attribs.pSrc->GetDesc();
+ auto& DstDesc = Attribs.pDst->GetDesc();
+
+ CHECK_COPY_BLAS_ATTRIBS((SrcDesc.Flags & RAYTRACING_BUILD_AS_ALLOW_COMPACTION) == RAYTRACING_BUILD_AS_ALLOW_COMPACTION, "must be have been create with RAYTRACING_BUILD_AS_ALLOW_COMPACTION flag");
+ CHECK_COPY_BLAS_ATTRIBS(DstDesc.CompactedSize != 0, "pDst must have been create with non-zero CompactedSize");
+ }
+ else
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::CopyBLAS: unknown Mode");
+ return false;
+ }
+
+#undef CHECK_COPY_BLAS_ATTRIBS
+
+ return true;
+}
+
+
+bool VerifyCopyTLASAttribs(const CopyTLASAttribs& Attribs)
+{
+#define CHECK_COPY_TLAS_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Copy TLAS attribs are invalid: ", __VA_ARGS__)
+
+ CHECK_COPY_TLAS_ATTRIBS(Attribs.pSrc != nullptr, "pSrc must not be null");
+ CHECK_COPY_TLAS_ATTRIBS(Attribs.pDst != nullptr, "pDst must not be null");
+
+ if (Attribs.Mode == COPY_AS_MODE_CLONE)
+ {
+ auto& SrcDesc = Attribs.pSrc->GetDesc();
+ auto& DstDesc = Attribs.pDst->GetDesc();
+
+ CHECK_COPY_TLAS_ATTRIBS(SrcDesc.MaxInstanceCount == DstDesc.MaxInstanceCount && SrcDesc.Flags == DstDesc.Flags,
+ "pDst must have been created with the same parameters as pSrc");
+ }
+ else if (Attribs.Mode == COPY_AS_MODE_COMPACT)
+ {
+ auto& SrcDesc = Attribs.pSrc->GetDesc();
+ auto& DstDesc = Attribs.pDst->GetDesc();
+
+ CHECK_COPY_TLAS_ATTRIBS((SrcDesc.Flags & RAYTRACING_BUILD_AS_ALLOW_COMPACTION) == RAYTRACING_BUILD_AS_ALLOW_COMPACTION, "pSrc was not created with RAYTRACING_BUILD_AS_ALLOW_COMPACTION flag");
+ CHECK_COPY_TLAS_ATTRIBS(DstDesc.CompactedSize != 0, "pDst must have been create with non-zero CompactedSize");
+ }
+ else
+ {
+ LOG_ERROR_MESSAGE("IDeviceContext::CopyTLAS: unknown Mode");
+ return false;
+ }
+#undef CHECK_COPY_TLAS_ATTRIBS
+
+ return true;
+}
+
+bool VerifyWriteBLASCompactedSizeAttribs(const IRenderDevice* pDevice, const WriteBLASCompactedSizeAttribs& Attribs)
+{
+#define CHECK_WRITE_BLAS_SIZE_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Write compacted BLAS size attribs are invalid: ", __VA_ARGS__)
+
+ CHECK_WRITE_BLAS_SIZE_ATTRIBS(Attribs.pBLAS != nullptr, "pBLAS must not be null");
+ CHECK_WRITE_BLAS_SIZE_ATTRIBS((Attribs.pBLAS->GetDesc().Flags & RAYTRACING_BUILD_AS_ALLOW_COMPACTION) == RAYTRACING_BUILD_AS_ALLOW_COMPACTION,
+ "pBLAS was not created with RAYTRACING_BUILD_AS_ALLOW_COMPACTION flag");
+
+ CHECK_WRITE_BLAS_SIZE_ATTRIBS(Attribs.pDestBuffer != nullptr, "pDestBuffer must not be null");
+
+ const BufferDesc& DstDesc = Attribs.pDestBuffer->GetDesc();
+ CHECK_WRITE_BLAS_SIZE_ATTRIBS(Attribs.DestBufferOffset + sizeof(Uint64) <= DstDesc.uiSizeInBytes, "pDestBuffer is too small");
+
+ if (pDevice->GetDeviceCaps().DevType == RENDER_DEVICE_TYPE_D3D12)
+ {
+ CHECK_WRITE_BLAS_SIZE_ATTRIBS((DstDesc.BindFlags & BIND_UNORDERED_ACCESS) == BIND_UNORDERED_ACCESS,
+ "pDestBuffer must have been created with BIND_UNORDERED_ACCESS flag in Direct3D12");
+ }
+
+#undef CHECK_WRITE_BLAS_SIZE_ATTRIBS
+
+ return true;
+}
+
+bool VerifyWriteTLASCompactedSizeAttribs(const IRenderDevice* pDevice, const WriteTLASCompactedSizeAttribs& Attribs)
+{
+#define CHECK_WRITE_TLAS_SIZE_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Write compacted TLAS size attribs are invalid: ", __VA_ARGS__)
+
+ CHECK_WRITE_TLAS_SIZE_ATTRIBS(Attribs.pTLAS != nullptr, "pTLAS must not be null");
+ CHECK_WRITE_TLAS_SIZE_ATTRIBS((Attribs.pTLAS->GetDesc().Flags & RAYTRACING_BUILD_AS_ALLOW_COMPACTION) == RAYTRACING_BUILD_AS_ALLOW_COMPACTION,
+ "pTLAS was not created with RAYTRACING_BUILD_AS_ALLOW_COMPACTION flag");
+
+ CHECK_WRITE_TLAS_SIZE_ATTRIBS(Attribs.pDestBuffer != nullptr, "pDestBuffer must not be null");
+
+ const BufferDesc& DstDesc = Attribs.pDestBuffer->GetDesc();
+ CHECK_WRITE_TLAS_SIZE_ATTRIBS(Attribs.DestBufferOffset + sizeof(Uint64) <= DstDesc.uiSizeInBytes, "pDestBuffer is too small");
+
+ if (pDevice->GetDeviceCaps().DevType == RENDER_DEVICE_TYPE_D3D12)
+ {
+ CHECK_WRITE_TLAS_SIZE_ATTRIBS((DstDesc.BindFlags & BIND_UNORDERED_ACCESS) == BIND_UNORDERED_ACCESS,
+ "pDestBuffer must have been created with BIND_UNORDERED_ACCESS flag");
+ }
+
+#undef CHECK_WRITE_TLAS_SIZE_ATTRIBS
+
+ return true;
+}
+
+bool VerifyTraceRaysAttribs(const TraceRaysAttribs& Attribs)
+{
+#define CHECK_TRACE_RAYS_ATTRIBS(Expr, ...) CHECK_PARAMETER(Expr, "Trace rays attribs are invalid: ", __VA_ARGS__)
+ CHECK_TRACE_RAYS_ATTRIBS(Attribs.pSBT != nullptr, "pSBT must not be null");
+
+#ifdef DILIGENT_DEVELOPMENT
+ CHECK_TRACE_RAYS_ATTRIBS(Attribs.pSBT->Verify(SHADER_BINDING_VALIDATION_SHADER_ONLY | SHADER_BINDING_VALIDATION_TLAS),
+ "not all shaders in SBT are bound or instance to shader mapping is incorrect");
+#endif // DILIGENT_DEVELOPMENT
+
+ CHECK_TRACE_RAYS_ATTRIBS(Attribs.DimensionX != 0, "DimensionX must not be zero.");
+ CHECK_TRACE_RAYS_ATTRIBS(Attribs.DimensionY != 0, "DimensionY must not be zero.");
+ CHECK_TRACE_RAYS_ATTRIBS(Attribs.DimensionZ != 0, "DimensionZ must not be zero.");
+
+#undef CHECK_TRACE_RAYS_ATTRIBS
+
+ return true;
+}
+
+} // namespace Diligent
diff --git a/Graphics/GraphicsEngine/src/EngineMemory.cpp b/Graphics/GraphicsEngine/src/EngineMemory.cpp
index 198bf0ba..7e8ab0cc 100644
--- a/Graphics/GraphicsEngine/src/EngineMemory.cpp
+++ b/Graphics/GraphicsEngine/src/EngineMemory.cpp
@@ -29,9 +29,9 @@
// RenderEngine.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
-#include "pch.h"
#include "EngineMemory.h"
#include "DefaultRawMemoryAllocator.hpp"
+#include "Errors.hpp"
namespace Diligent
{
diff --git a/Graphics/GraphicsEngine/src/FramebufferBase.cpp b/Graphics/GraphicsEngine/src/FramebufferBase.cpp
index 41943b09..1a173910 100644
--- a/Graphics/GraphicsEngine/src/FramebufferBase.cpp
+++ b/Graphics/GraphicsEngine/src/FramebufferBase.cpp
@@ -25,14 +25,13 @@
* of the possibility of such damages.
*/
-#include "pch.h"
#include "FramebufferBase.hpp"
#include "GraphicsAccessories.hpp"
namespace Diligent
{
-void ValidateFramebufferDesc(const FramebufferDesc& Desc)
+void ValidateFramebufferDesc(const FramebufferDesc& Desc) noexcept(false)
{
#define LOG_FRAMEBUFFER_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of framebuffer '", (Desc.Name ? Desc.Name : ""), "' is invalid: ", ##__VA_ARGS__)
diff --git a/Graphics/GraphicsEngine/src/PipelineStateBase.cpp b/Graphics/GraphicsEngine/src/PipelineStateBase.cpp
index fedc332d..5adc101d 100644
--- a/Graphics/GraphicsEngine/src/PipelineStateBase.cpp
+++ b/Graphics/GraphicsEngine/src/PipelineStateBase.cpp
@@ -25,7 +25,6 @@
* of the possibility of such damages.
*/
-#include "pch.h"
#include "PipelineStateBase.hpp"
namespace Diligent
@@ -248,6 +247,102 @@ void ValidateComputePipelineCreateInfo(const ComputePipelineStateCreateInfo& Cre
VALIDATE_SHADER_TYPE(CreateInfo.pCS, SHADER_TYPE_COMPUTE, "compute");
}
+
+void ValidateRayTracingPipelineCreateInfo(IRenderDevice* pDevice, Uint32 MaxRecursion, const RayTracingPipelineStateCreateInfo& CreateInfo) noexcept(false)
+{
+ const auto& PSODesc = CreateInfo.PSODesc;
+ if (PSODesc.PipelineType != PIPELINE_TYPE_RAY_TRACING)
+ LOG_PSO_ERROR_AND_THROW("Pipeline type must be RAY_TRACING");
+
+ if (pDevice->GetDeviceCaps().DevType == RENDER_DEVICE_TYPE_D3D12)
+ {
+ if ((CreateInfo.pShaderRecordName != nullptr) != (CreateInfo.RayTracingPipeline.ShaderRecordSize > 0))
+ LOG_PSO_ERROR_AND_THROW("pShaderRecordName must not be null if RayTracingPipeline.ShaderRecordSize is not zero");
+ }
+
+ if (CreateInfo.RayTracingPipeline.MaxRecursionDepth > MaxRecursion)
+ {
+ LOG_PSO_ERROR_AND_THROW("MaxRecursionDepth must not exceed the ", MaxRecursion);
+ }
+
+ for (Uint32 i = 0; i < CreateInfo.GeneralShaderCount; ++i)
+ {
+ const auto& Group = CreateInfo.pGeneralShaders[i];
+ if (Group.pShader == nullptr)
+ LOG_PSO_ERROR_AND_THROW("pGeneralShaders[", i, "].pShader must not be null");
+ if (Group.Name == nullptr)
+ LOG_PSO_ERROR_AND_THROW("pGeneralShaders[", i, "].Name must not be null");
+
+ switch (Group.pShader->GetDesc().ShaderType)
+ {
+ case SHADER_TYPE_RAY_GEN:
+ case SHADER_TYPE_RAY_MISS:
+ case SHADER_TYPE_RAY_CLOSEST_HIT: break;
+ default:
+ LOG_ERROR_AND_THROW(GetShaderTypeLiteralName(Group.pShader->GetDesc().ShaderType), " is not a valid type for ray tracing general shader");
+ }
+ }
+
+ for (Uint32 i = 0; i < CreateInfo.TriangleHitShaderCount; ++i)
+ {
+ const auto& Group = CreateInfo.pTriangleHitShaders[i];
+ if (Group.pClosestHitShader == nullptr)
+ LOG_PSO_ERROR_AND_THROW("pTriangleHitShaders[", i, "].pClosestHitShader must not be null");
+ if (Group.Name == nullptr)
+ LOG_PSO_ERROR_AND_THROW("pTriangleHitShaders[", i, "].Name must not be null");
+
+ VALIDATE_SHADER_TYPE(Group.pClosestHitShader, SHADER_TYPE_RAY_CLOSEST_HIT, "ray tracing triangle closest hit");
+
+ if (Group.pAnyHitShader != nullptr)
+ VALIDATE_SHADER_TYPE(Group.pAnyHitShader, SHADER_TYPE_RAY_ANY_HIT, "ray tracing triangle any hit");
+ }
+
+ for (Uint32 i = 0; i < CreateInfo.ProceduralHitShaderCount; ++i)
+ {
+ const auto& Group = CreateInfo.pProceduralHitShaders[i];
+ if (Group.pIntersectionShader == nullptr)
+ LOG_PSO_ERROR_AND_THROW("pProceduralHitShaders[", i, "].pIntersectionShader must not be null");
+ if (Group.Name == nullptr)
+ LOG_PSO_ERROR_AND_THROW("pProceduralHitShaders[", i, "].Name must not be null");
+
+ VALIDATE_SHADER_TYPE(Group.pIntersectionShader, SHADER_TYPE_RAY_INTERSECTION, "ray tracing procedural intersection");
+
+ if (Group.pClosestHitShader != nullptr)
+ VALIDATE_SHADER_TYPE(Group.pClosestHitShader, SHADER_TYPE_RAY_CLOSEST_HIT, "ray tracing procedural closest hit");
+ if (Group.pAnyHitShader != nullptr)
+ VALIDATE_SHADER_TYPE(Group.pAnyHitShader, SHADER_TYPE_RAY_ANY_HIT, "ray tracing procedural any hit");
+ }
+}
+
+void CopyRayTracingShaderGroups(std::unordered_map<HashMapStringKey, Uint32, HashMapStringKey::Hasher>& NameToGroupIndex,
+ const RayTracingPipelineStateCreateInfo& CreateInfo,
+ FixedLinearAllocator& MemPool) noexcept(false)
+{
+ const auto& PSODesc = CreateInfo.PSODesc;
+ Uint32 GroupIndex = 0;
+
+ for (Uint32 i = 0; i < CreateInfo.GeneralShaderCount; ++i)
+ {
+ bool IsUniqueName = NameToGroupIndex.emplace(HashMapStringKey{MemPool.CopyString(CreateInfo.pGeneralShaders[i].Name)}, GroupIndex++).second;
+ if (!IsUniqueName)
+ LOG_PSO_ERROR_AND_THROW("pGeneralShaders[", i, "].Name must be unique");
+ }
+ for (Uint32 i = 0; i < CreateInfo.TriangleHitShaderCount; ++i)
+ {
+ bool IsUniqueName = NameToGroupIndex.emplace(HashMapStringKey{MemPool.CopyString(CreateInfo.pTriangleHitShaders[i].Name)}, GroupIndex++).second;
+ if (!IsUniqueName)
+ LOG_PSO_ERROR_AND_THROW("pTriangleHitShaders[", i, "].Name must be unique");
+ }
+ for (Uint32 i = 0; i < CreateInfo.ProceduralHitShaderCount; ++i)
+ {
+ bool IsUniqueName = NameToGroupIndex.emplace(HashMapStringKey{MemPool.CopyString(CreateInfo.pProceduralHitShaders[i].Name)}, GroupIndex++).second;
+ if (!IsUniqueName)
+ LOG_PSO_ERROR_AND_THROW("pProceduralHitShaders[", i, "].Name must be unique");
+ }
+
+ VERIFY_EXPR(Uint32{CreateInfo.GeneralShaderCount} + Uint32{CreateInfo.TriangleHitShaderCount} + Uint32{CreateInfo.ProceduralHitShaderCount} == GroupIndex);
+}
+
#undef VALIDATE_SHADER_TYPE
#undef LOG_PSO_ERROR_AND_THROW
diff --git a/Graphics/GraphicsEngine/src/RenderPassBase.cpp b/Graphics/GraphicsEngine/src/RenderPassBase.cpp
index b6b38dd0..d20ff071 100644
--- a/Graphics/GraphicsEngine/src/RenderPassBase.cpp
+++ b/Graphics/GraphicsEngine/src/RenderPassBase.cpp
@@ -25,7 +25,6 @@
* of the possibility of such damages.
*/
-#include "pch.h"
#include "RenderPassBase.hpp"
#include "GraphicsAccessories.hpp"
#include "Align.hpp"
@@ -33,7 +32,7 @@
namespace Diligent
{
-void ValidateRenderPassDesc(const RenderPassDesc& Desc)
+void ValidateRenderPassDesc(const RenderPassDesc& Desc) noexcept(false)
{
#define LOG_RENDER_PASS_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of render pass '", (Desc.Name ? Desc.Name : ""), "' is invalid: ", ##__VA_ARGS__)
diff --git a/Graphics/GraphicsEngine/src/ResourceMappingBase.cpp b/Graphics/GraphicsEngine/src/ResourceMappingBase.cpp
index bf34056c..859dcf88 100644
--- a/Graphics/GraphicsEngine/src/ResourceMappingBase.cpp
+++ b/Graphics/GraphicsEngine/src/ResourceMappingBase.cpp
@@ -25,20 +25,16 @@
* of the possibility of such damages.
*/
-#include "pch.h"
#include "ResourceMappingImpl.hpp"
#include "DeviceObjectBase.hpp"
-using namespace std;
-
namespace Diligent
{
+
ResourceMappingImpl::~ResourceMappingImpl()
{
}
-IMPLEMENT_QUERY_INTERFACE(ResourceMappingImpl, IID_ResourceMapping, TObjectBase)
-
ThreadingTools::LockHelper ResourceMappingImpl::Lock()
{
return ThreadingTools::LockHelper(m_LockFlag);
@@ -55,10 +51,7 @@ void ResourceMappingImpl::AddResourceArray(const Char* Name, Uint32 StartIndex,
auto* pObject = ppObjects[Elem];
// Try to construct new element in place
- auto Elems =
- m_HashTable.emplace(
- make_pair(Diligent::ResMappingHashKey(Name, true, StartIndex + Elem), // Make a copy of the source string
- Diligent::RefCntAutoPtr<IDeviceObject>(pObject)));
+ auto Elems = m_HashTable.emplace(ResMappingHashKey{Name, true /*Make copy*/, StartIndex + Elem}, pObject);
// If there is already element with the same name, replace it
if (!Elems.second && Elems.first->second != pObject)
{
@@ -88,7 +81,7 @@ void ResourceMappingImpl::RemoveResourceByName(const Char* Name, Uint32 ArrayInd
auto LockHelper = Lock();
// Remove object with the given name
// Name will be implicitly converted to HashMapStringKey without making a copy
- m_HashTable.erase(ResMappingHashKey(Name, false, ArrayIndex));
+ m_HashTable.erase(ResMappingHashKey{Name, false, ArrayIndex});
}
void ResourceMappingImpl::GetResource(const Char* Name, IDeviceObject** ppResource, Uint32 ArrayIndex)
@@ -108,7 +101,7 @@ void ResourceMappingImpl::GetResource(const Char* Name, IDeviceObject** ppResour
// Find an object with the requested name
// Name will be implicitly converted to HashMapStringKey without making a copy
- auto It = m_HashTable.find(ResMappingHashKey(Name, false, ArrayIndex));
+ auto It = m_HashTable.find(ResMappingHashKey{Name, false, ArrayIndex});
if (It != m_HashTable.end())
{
*ppResource = It->second.RawPtr();
@@ -121,4 +114,5 @@ size_t ResourceMappingImpl::GetSize()
{
return m_HashTable.size();
}
+
} // namespace Diligent
diff --git a/Graphics/GraphicsEngine/src/ShaderBindingTableBase.cpp b/Graphics/GraphicsEngine/src/ShaderBindingTableBase.cpp
new file mode 100644
index 00000000..e0cb3461
--- /dev/null
+++ b/Graphics/GraphicsEngine/src/ShaderBindingTableBase.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2019-2020 Diligent Graphics LLC
+ * Copyright 2015-2019 Egor Yusov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * In no event and under no legal theory, whether in tort (including negligence),
+ * contract, or otherwise, unless required by applicable law (such as deliberate
+ * and grossly negligent acts) or agreed to in writing, shall any Contributor be
+ * liable for any damages, including any direct, indirect, special, incidental,
+ * or consequential damages of any character arising as a result of this License or
+ * out of the use or inability to use the software (including but not limited to damages
+ * for loss of goodwill, work stoppage, computer failure or malfunction, or any and
+ * all other commercial damages or losses), even if such Contributor has been advised
+ * of the possibility of such damages.
+ */
+
+#include "ShaderBindingTableBase.hpp"
+
+namespace Diligent
+{
+
+void ValidateShaderBindingTableDesc(const ShaderBindingTableDesc& Desc, Uint32 ShaderGroupHandleSize, Uint32 MaxShaderRecordStride) noexcept(false)
+{
+#define LOG_SBT_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of Shader binding table '", (Desc.Name ? Desc.Name : ""), "' is invalid: ", ##__VA_ARGS__)
+
+ if (Desc.pPSO == nullptr)
+ {
+ LOG_SBT_ERROR_AND_THROW("pPSO must not be null");
+ }
+
+ if (Desc.pPSO->GetDesc().PipelineType != PIPELINE_TYPE_RAY_TRACING)
+ {
+ LOG_SBT_ERROR_AND_THROW("pPSO must be ray tracing pipeline");
+ }
+
+
+ const auto ShaderRecordSize = Desc.pPSO->GetRayTracingPipelineDesc().ShaderRecordSize;
+ const auto ShaderRecordStride = ShaderRecordSize + ShaderGroupHandleSize;
+
+ if (ShaderRecordStride > MaxShaderRecordStride)
+ {
+ LOG_SBT_ERROR_AND_THROW("ShaderRecordSize(", ShaderRecordSize, ") is too big, max size is: ", MaxShaderRecordStride - ShaderGroupHandleSize);
+ }
+
+ if (ShaderRecordStride % ShaderGroupHandleSize != 0)
+ {
+ LOG_SBT_ERROR_AND_THROW("ShaderRecordSize (", ShaderRecordSize, ") plus ShaderGroupHandleSize (", ShaderGroupHandleSize,
+ ") must be a multiple of ", ShaderGroupHandleSize);
+ }
+#undef LOG_SBT_ERROR_AND_THROW
+}
+
+} // namespace Diligent
diff --git a/Graphics/GraphicsEngine/src/TextureBase.cpp b/Graphics/GraphicsEngine/src/TextureBase.cpp
index 93050ff1..0ecfc538 100644
--- a/Graphics/GraphicsEngine/src/TextureBase.cpp
+++ b/Graphics/GraphicsEngine/src/TextureBase.cpp
@@ -25,14 +25,14 @@
* of the possibility of such damages.
*/
-#include "pch.h"
#include "Texture.h"
+#include "DeviceContext.h"
#include "GraphicsAccessories.hpp"
namespace Diligent
{
-void ValidateTextureDesc(const TextureDesc& Desc)
+void ValidateTextureDesc(const TextureDesc& Desc) noexcept(false)
{
#define LOG_TEXTURE_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Texture '", (Desc.Name ? Desc.Name : ""), "': ", ##__VA_ARGS__)
@@ -311,4 +311,230 @@ void ValidateMapTextureParams(const TextureDesc& TexDesc,
}
}
+void ValidatedAndCorrectTextureViewDesc(const TextureDesc& TexDesc, TextureViewDesc& ViewDesc) noexcept(false)
+{
+#define TEX_VIEW_VALIDATION_ERROR(...) LOG_ERROR_AND_THROW("\n Failed to create texture view '", (ViewDesc.Name ? ViewDesc.Name : ""), "' for texture '", TexDesc.Name, "': ", ##__VA_ARGS__)
+
+ if (!(ViewDesc.ViewType > TEXTURE_VIEW_UNDEFINED && ViewDesc.ViewType < TEXTURE_VIEW_NUM_VIEWS))
+ TEX_VIEW_VALIDATION_ERROR("Texture view type is not specified");
+
+ if (ViewDesc.MostDetailedMip >= TexDesc.MipLevels)
+ TEX_VIEW_VALIDATION_ERROR("Most detailed mip (", ViewDesc.MostDetailedMip, ") is out of range. The texture has only ", TexDesc.MipLevels, " mip ", (TexDesc.MipLevels > 1 ? "levels." : "level."));
+
+ if (ViewDesc.NumMipLevels != REMAINING_MIP_LEVELS && ViewDesc.MostDetailedMip + ViewDesc.NumMipLevels > TexDesc.MipLevels)
+ TEX_VIEW_VALIDATION_ERROR("Most detailed mip (", ViewDesc.MostDetailedMip, ") and number of mip levels in the view (", ViewDesc.NumMipLevels, ") is out of range. The texture has only ", TexDesc.MipLevels, " mip ", (TexDesc.MipLevels > 1 ? "levels." : "level."));
+
+ if (ViewDesc.Format == TEX_FORMAT_UNKNOWN)
+ ViewDesc.Format = GetDefaultTextureViewFormat(TexDesc.Format, ViewDesc.ViewType, TexDesc.BindFlags);
+
+ if (ViewDesc.TextureDim == RESOURCE_DIM_UNDEFINED)
+ {
+ if (TexDesc.Type == RESOURCE_DIM_TEX_CUBE || TexDesc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY)
+ {
+ switch (ViewDesc.ViewType)
+ {
+ case TEXTURE_VIEW_SHADER_RESOURCE:
+ ViewDesc.TextureDim = TexDesc.Type;
+ break;
+
+ case TEXTURE_VIEW_RENDER_TARGET:
+ case TEXTURE_VIEW_DEPTH_STENCIL:
+ case TEXTURE_VIEW_UNORDERED_ACCESS:
+ ViewDesc.TextureDim = RESOURCE_DIM_TEX_2D_ARRAY;
+ break;
+
+ default: UNEXPECTED("Unexpected view type");
+ }
+ }
+ else
+ {
+ ViewDesc.TextureDim = TexDesc.Type;
+ }
+ }
+
+ switch (TexDesc.Type)
+ {
+ case RESOURCE_DIM_TEX_1D:
+ if (ViewDesc.TextureDim != RESOURCE_DIM_TEX_1D)
+ {
+ TEX_VIEW_VALIDATION_ERROR("Incorrect texture type for Texture 1D view: only Texture 1D is allowed");
+ }
+ break;
+
+ case RESOURCE_DIM_TEX_1D_ARRAY:
+ if (ViewDesc.TextureDim != RESOURCE_DIM_TEX_1D_ARRAY &&
+ ViewDesc.TextureDim != RESOURCE_DIM_TEX_1D)
+ {
+ TEX_VIEW_VALIDATION_ERROR("Incorrect view type for Texture 1D Array: only Texture 1D or Texture 1D Array are allowed");
+ }
+ break;
+
+ case RESOURCE_DIM_TEX_2D:
+ if (ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D_ARRAY &&
+ ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D)
+ {
+ TEX_VIEW_VALIDATION_ERROR("Incorrect texture type for Texture 2D view: only Texture 2D or Texture 2D Array are allowed");
+ }
+ break;
+
+ case RESOURCE_DIM_TEX_2D_ARRAY:
+ if (ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D_ARRAY &&
+ ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D)
+ {
+ TEX_VIEW_VALIDATION_ERROR("Incorrect texture type for Texture 2D Array view: only Texture 2D or Texture 2D Array are allowed");
+ }
+ break;
+
+ case RESOURCE_DIM_TEX_3D:
+ if (ViewDesc.TextureDim != RESOURCE_DIM_TEX_3D)
+ {
+ TEX_VIEW_VALIDATION_ERROR("Incorrect texture type for Texture 3D view: only Texture 3D is allowed");
+ }
+ break;
+
+ case RESOURCE_DIM_TEX_CUBE:
+ if (ViewDesc.ViewType == TEXTURE_VIEW_SHADER_RESOURCE)
+ {
+ if (ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D &&
+ ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D_ARRAY &&
+ ViewDesc.TextureDim != RESOURCE_DIM_TEX_CUBE)
+ {
+ TEX_VIEW_VALIDATION_ERROR("Incorrect texture type for Texture cube SRV: Texture 2D, Texture 2D array or Texture Cube is allowed");
+ }
+ }
+ else
+ {
+ if (ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D &&
+ ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D_ARRAY)
+ {
+ TEX_VIEW_VALIDATION_ERROR("Incorrect texture type for Texture cube non-shader resource view: Texture 2D or Texture 2D array is allowed");
+ }
+ }
+ break;
+
+ case RESOURCE_DIM_TEX_CUBE_ARRAY:
+ if (ViewDesc.ViewType == TEXTURE_VIEW_SHADER_RESOURCE)
+ {
+ if (ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D &&
+ ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D_ARRAY &&
+ ViewDesc.TextureDim != RESOURCE_DIM_TEX_CUBE &&
+ ViewDesc.TextureDim != RESOURCE_DIM_TEX_CUBE_ARRAY)
+ {
+ TEX_VIEW_VALIDATION_ERROR("Incorrect texture type for Texture cube array SRV: Texture 2D, Texture 2D array, Texture Cube or Texture Cube Array is allowed");
+ }
+ }
+ else
+ {
+ if (ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D &&
+ ViewDesc.TextureDim != RESOURCE_DIM_TEX_2D_ARRAY)
+ {
+ TEX_VIEW_VALIDATION_ERROR("Incorrect texture type for Texture cube array non-shader resource view: Texture 2D or Texture 2D array is allowed");
+ }
+ }
+ break;
+
+ default:
+ UNEXPECTED("Unexpected texture type");
+ break;
+ }
+
+ if (ViewDesc.TextureDim == RESOURCE_DIM_TEX_CUBE)
+ {
+ if (ViewDesc.ViewType != TEXTURE_VIEW_SHADER_RESOURCE)
+ TEX_VIEW_VALIDATION_ERROR("Unexpected view type: SRV is expected");
+ if (ViewDesc.NumArraySlices != 6 && ViewDesc.NumArraySlices != 0 && ViewDesc.NumArraySlices != REMAINING_ARRAY_SLICES)
+ TEX_VIEW_VALIDATION_ERROR("Texture cube SRV is expected to have 6 array slices, while ", ViewDesc.NumArraySlices, " is provided");
+ if (ViewDesc.FirstArraySlice != 0)
+ TEX_VIEW_VALIDATION_ERROR("First slice (", ViewDesc.FirstArraySlice, ") must be 0 for non-array texture cube SRV");
+ }
+ if (ViewDesc.TextureDim == RESOURCE_DIM_TEX_CUBE_ARRAY)
+ {
+ if (ViewDesc.ViewType != TEXTURE_VIEW_SHADER_RESOURCE)
+ TEX_VIEW_VALIDATION_ERROR("Unexpected view type: SRV is expected");
+ if (ViewDesc.NumArraySlices != REMAINING_ARRAY_SLICES && (ViewDesc.NumArraySlices % 6) != 0)
+ TEX_VIEW_VALIDATION_ERROR("Number of slices in texture cube array SRV is expected to be multiple of 6. ", ViewDesc.NumArraySlices, " slices is provided.");
+ }
+
+ if (ViewDesc.TextureDim == RESOURCE_DIM_TEX_1D ||
+ ViewDesc.TextureDim == RESOURCE_DIM_TEX_2D)
+ {
+ if (ViewDesc.FirstArraySlice != 0)
+ TEX_VIEW_VALIDATION_ERROR("First slice (", ViewDesc.FirstArraySlice, ") must be 0 for non-array texture 1D/2D views");
+
+ if (ViewDesc.NumArraySlices != REMAINING_ARRAY_SLICES && ViewDesc.NumArraySlices > 1)
+ TEX_VIEW_VALIDATION_ERROR("Number of slices in the view (", ViewDesc.NumArraySlices, ") must be 1 (or 0) for non-array texture 1D/2D views");
+ }
+ else if (ViewDesc.TextureDim == RESOURCE_DIM_TEX_1D_ARRAY ||
+ ViewDesc.TextureDim == RESOURCE_DIM_TEX_2D_ARRAY ||
+ ViewDesc.TextureDim == RESOURCE_DIM_TEX_CUBE ||
+ ViewDesc.TextureDim == RESOURCE_DIM_TEX_CUBE_ARRAY)
+ {
+ if (ViewDesc.FirstArraySlice >= TexDesc.ArraySize)
+ TEX_VIEW_VALIDATION_ERROR("First array slice (", ViewDesc.FirstArraySlice, ") exceeds the number of slices in the texture array (", TexDesc.ArraySize, ")");
+
+ if (ViewDesc.NumArraySlices != REMAINING_ARRAY_SLICES && ViewDesc.FirstArraySlice + ViewDesc.NumArraySlices > TexDesc.ArraySize)
+ TEX_VIEW_VALIDATION_ERROR("First slice (", ViewDesc.FirstArraySlice, ") and number of slices in the view (", ViewDesc.NumArraySlices, ") specify more slices than target texture has (", TexDesc.ArraySize, ")");
+ }
+ else if (ViewDesc.TextureDim == RESOURCE_DIM_TEX_3D)
+ {
+ auto MipDepth = TexDesc.Depth >> ViewDesc.MostDetailedMip;
+ if (ViewDesc.FirstDepthSlice + ViewDesc.NumDepthSlices > MipDepth)
+ TEX_VIEW_VALIDATION_ERROR("First slice (", ViewDesc.FirstDepthSlice, ") and number of slices in the view (", ViewDesc.NumDepthSlices, ") specify more slices than target 3D texture mip level has (", MipDepth, ")");
+ }
+ else
+ {
+ UNEXPECTED("Unexpected texture dimension");
+ }
+
+ if (GetTextureFormatAttribs(ViewDesc.Format).IsTypeless)
+ {
+ TEX_VIEW_VALIDATION_ERROR("Texture view format (", GetTextureFormatAttribs(ViewDesc.Format).Name, ") cannot be typeless");
+ }
+
+ if ((ViewDesc.Flags & TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION) != 0)
+ {
+ if ((TexDesc.MiscFlags & MISC_TEXTURE_FLAG_GENERATE_MIPS) == 0)
+ TEX_VIEW_VALIDATION_ERROR("TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION flag can only set if the texture was created with MISC_TEXTURE_FLAG_GENERATE_MIPS flag");
+
+ if (ViewDesc.ViewType != TEXTURE_VIEW_SHADER_RESOURCE)
+ TEX_VIEW_VALIDATION_ERROR("TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION flag can only be used with TEXTURE_VIEW_SHADER_RESOURCE view type");
+ }
+
+#undef TEX_VIEW_VALIDATION_ERROR
+
+ if (ViewDesc.NumMipLevels == 0 || ViewDesc.NumMipLevels == REMAINING_MIP_LEVELS)
+ {
+ if (ViewDesc.ViewType == TEXTURE_VIEW_SHADER_RESOURCE)
+ ViewDesc.NumMipLevels = TexDesc.MipLevels - ViewDesc.MostDetailedMip;
+ else
+ ViewDesc.NumMipLevels = 1;
+ }
+
+ if (ViewDesc.NumArraySlices == 0 || ViewDesc.NumArraySlices == REMAINING_ARRAY_SLICES)
+ {
+ if (ViewDesc.TextureDim == RESOURCE_DIM_TEX_1D_ARRAY ||
+ ViewDesc.TextureDim == RESOURCE_DIM_TEX_2D_ARRAY ||
+ ViewDesc.TextureDim == RESOURCE_DIM_TEX_CUBE ||
+ ViewDesc.TextureDim == RESOURCE_DIM_TEX_CUBE_ARRAY)
+ ViewDesc.NumArraySlices = TexDesc.ArraySize - ViewDesc.FirstArraySlice;
+ else if (ViewDesc.TextureDim == RESOURCE_DIM_TEX_3D)
+ {
+ auto MipDepth = TexDesc.Depth >> ViewDesc.MostDetailedMip;
+ ViewDesc.NumDepthSlices = MipDepth - ViewDesc.FirstDepthSlice;
+ }
+ else
+ ViewDesc.NumArraySlices = 1;
+ }
+
+ if ((ViewDesc.ViewType == TEXTURE_VIEW_RENDER_TARGET) &&
+ (ViewDesc.Format == TEX_FORMAT_R8_SNORM || ViewDesc.Format == TEX_FORMAT_RG8_SNORM || ViewDesc.Format == TEX_FORMAT_RGBA8_SNORM ||
+ ViewDesc.Format == TEX_FORMAT_R16_SNORM || ViewDesc.Format == TEX_FORMAT_RG16_SNORM || ViewDesc.Format == TEX_FORMAT_RGBA16_SNORM))
+ {
+ const auto* FmtName = GetTextureFormatAttribs(ViewDesc.Format).Name;
+ LOG_WARNING_MESSAGE(FmtName, " render target view is created.\n"
+ "There might be an issue in OpenGL driver on NVidia hardware: when rendering to SNORM textures, all negative values are clamped to zero.\n"
+ "Use UNORM format instead.");
+ }
+}
+
} // namespace Diligent
diff --git a/Graphics/GraphicsEngine/include/pch.h b/Graphics/GraphicsEngine/src/TopLevelASBase.cpp
index 74889e44..5ccc51c4 100644
--- a/Graphics/GraphicsEngine/include/pch.h
+++ b/Graphics/GraphicsEngine/src/TopLevelASBase.cpp
@@ -25,21 +25,41 @@
* of the possibility of such damages.
*/
-/// \file
-/// Precomputed header
-
-#pragma once
-
-#include <vector>
-#include <list>
-#include <set>
-#include <map>
-#include <unordered_map>
-#include <memory>
-#include <algorithm>
-#include "GraphicsTypes.h"
-#include "RefCntAutoPtr.hpp"
-#include "Errors.hpp"
-#include "DebugUtilities.hpp"
-#include "RenderDeviceBase.hpp"
-#include "DeviceContextBase.hpp" \ No newline at end of file
+#include "TopLevelASBase.hpp"
+
+namespace Diligent
+{
+
+void ValidateTopLevelASDesc(const TopLevelASDesc& Desc) noexcept(false)
+{
+#define LOG_TLAS_ERROR_AND_THROW(...) LOG_ERROR_AND_THROW("Description of a top-level AS '", (Desc.Name ? Desc.Name : ""), "' is invalid: ", ##__VA_ARGS__)
+
+ if (Desc.CompactedSize > 0)
+ {
+ if (Desc.MaxInstanceCount != 0)
+ {
+ LOG_TLAS_ERROR_AND_THROW("If non-zero CompactedSize is specified, MaxInstanceCount must be zero");
+ }
+
+ if (Desc.Flags != RAYTRACING_BUILD_AS_NONE)
+ {
+ LOG_TLAS_ERROR_AND_THROW("If non-zero CompactedSize is specified, Flags must be RAYTRACING_BUILD_AS_NONE");
+ }
+ }
+ else
+ {
+ if (Desc.MaxInstanceCount == 0)
+ {
+ LOG_TLAS_ERROR_AND_THROW("MaxInstanceCount must not be zero");
+ }
+
+ if ((Desc.Flags & RAYTRACING_BUILD_AS_PREFER_FAST_TRACE) != 0 && (Desc.Flags & RAYTRACING_BUILD_AS_PREFER_FAST_BUILD) != 0)
+ {
+ LOG_TLAS_ERROR_AND_THROW("RAYTRACING_BUILD_AS_PREFER_FAST_TRACE and RAYTRACING_BUILD_AS_PREFER_FAST_BUILD flags are mutually exclusive");
+ }
+ }
+
+#undef LOG_TLAS_ERROR_AND_THROW
+}
+
+} // namespace Diligent