Add warnings on incorrect GPUBuffer or GPUTexture usage when binding to GPUContext (in non-release builds)

This commit is contained in:
Wojtek Figat
2025-01-30 22:03:21 +01:00
parent 44fae3838e
commit 04dde7a3f2
18 changed files with 121 additions and 31 deletions

View File

@@ -11,6 +11,53 @@ GPUContext::GPUContext(GPUDevice* device)
{
}
#if !BUILD_RELEASE
#include "Engine/Core/Log.h"
void GPUContext::LogInvalidResourceUsage(int32 slot, const GPUResourceView* view, InvalidBindPoint bindPoint)
{
GPUResource* resource = view ? view->GetParent() : nullptr;
const Char* resourceType = TEXT("resource");
const Char* flagType = TEXT("flags");
if (resource)
{
switch (resource->GetResourceType())
{
case GPUResourceType::RenderTarget:
case GPUResourceType::Texture:
case GPUResourceType::CubeTexture:
case GPUResourceType::VolumeTexture:
resourceType = TEXT("texture");
flagType = TEXT("GPUTextureFlags");
break;
case GPUResourceType::Buffer:
resourceType = TEXT("buffer");
flagType = TEXT("GPUBufferFlags");
break;
}
}
const Char* usage = TEXT("-");
switch (bindPoint)
{
case InvalidBindPoint::SRV:
usage = TEXT("shader resource");
break;
case InvalidBindPoint::UAV:
usage = TEXT("unordered access");
break;
case InvalidBindPoint::DSV:
usage = TEXT("depth stencil");
break;
case InvalidBindPoint::RTV:
usage = TEXT("render target");
break;
}
LOG(Error, "Incorrect {} bind at slot {} as {} (ensure to setup correct {} when creating that resource)", resourceType, slot, usage, flagType);
}
#endif
void GPUContext::FrameBegin()
{
_lastRenderTime = Platform::GetTimeSeconds();

View File

@@ -121,6 +121,12 @@ protected:
double _lastRenderTime = -1;
GPUContext(GPUDevice* device);
#if !BUILD_RELEASE
enum class InvalidBindPoint { SRV, UAV, DSV, RTV };
static void LogInvalidResourceUsage(int32 slot, const GPUResourceView* view, InvalidBindPoint bindPoint);
#endif
public:
/// <summary>
/// Gets the graphics device.
@@ -143,7 +149,6 @@ public:
public:
#if GPU_ALLOW_PROFILE_EVENTS
/// <summary>
/// Begins the profile event.
/// </summary>
@@ -158,7 +163,6 @@ public:
virtual void EventEnd()
{
}
#endif
public:

View File

@@ -190,6 +190,7 @@ API_CLASS(Abstract, NoSpawn, Attributes="HideInEditor") class FLAXENGINE_API GPU
DECLARE_SCRIPTING_TYPE_NO_SPAWN(GPUResourceView);
protected:
static double DummyLastRenderTime;
GPUResource* _parent = nullptr;
explicit GPUResourceView(const SpawnParams& params)
: ScriptingObject(params)
@@ -201,6 +202,14 @@ public:
// Points to the cache used by the resource for the resource visibility/usage detection. Written during rendering when resource view is used.
double* LastRenderTime;
/// <summary>
/// Gets parent GPU resource owning that view.
/// </summary>
API_PROPERTY() FORCE_INLINE GPUResource* GetParent() const
{
return _parent;
}
/// <summary>
/// Gets the native pointer to the underlying view. It's a platform-specific handle.
/// </summary>

View File

@@ -21,7 +21,6 @@ API_CLASS(Sealed, NoSpawn) class FLAXENGINE_API GPUTextureView : public GPUResou
{
DECLARE_SCRIPTING_TYPE_NO_SPAWN(GPUTextureView);
protected:
GPUResource* _parent = nullptr;
PixelFormat _format = PixelFormat::Unknown;
MSAALevel _msaa = MSAALevel::None;
@@ -40,14 +39,6 @@ protected:
}
public:
/// <summary>
/// Gets parent GPU resource owning that view.
/// </summary>
API_PROPERTY() FORCE_INLINE GPUResource* GetParent() const
{
return _parent;
}
/// <summary>
/// Gets the view format.
/// </summary>

View File

@@ -10,6 +10,7 @@
GPUBufferDX11::GPUBufferDX11(GPUDeviceDX11* device, const StringView& name)
: GPUResourceDX11(device, name)
{
_view.SetParnet(this);
}
GPUBufferView* GPUBufferDX11::View() const

View File

@@ -40,6 +40,11 @@ public:
public:
void SetParnet(GPUBuffer* parent)
{
_parent = parent;
}
/// <summary>
/// Release the view.
/// </summary>

View File

@@ -355,7 +355,11 @@ void GPUContextDX11::BindCB(int32 slot, GPUConstantBuffer* cb)
void GPUContextDX11::BindSR(int32 slot, GPUResourceView* view)
{
#if !BUILD_RELEASE
ASSERT(slot >= 0 && slot < GPU_MAX_SR_BINDED);
if (view && ((IShaderResourceDX11*)view->GetNativePtr())->SRV() == nullptr)
LogInvalidResourceUsage(slot, view, InvalidBindPoint::SRV);
#endif
auto handle = view ? ((IShaderResourceDX11*)view->GetNativePtr())->SRV() : nullptr;
if (_srHandles[slot] != handle)
{
@@ -369,7 +373,11 @@ void GPUContextDX11::BindSR(int32 slot, GPUResourceView* view)
void GPUContextDX11::BindUA(int32 slot, GPUResourceView* view)
{
#if !BUILD_RELEASE
ASSERT(slot >= 0 && slot < GPU_MAX_UA_BINDED);
if (view && ((IShaderResourceDX11*)view->GetNativePtr())->UAV() == nullptr)
LogInvalidResourceUsage(slot, view, InvalidBindPoint::UAV);
#endif
auto handle = view ? ((IShaderResourceDX11*)view->GetNativePtr())->UAV() : nullptr;
if (_uaHandles[slot] != handle)
{

View File

@@ -12,13 +12,11 @@
class IShaderResourceDX11
{
public:
IShaderResourceDX11()
{
}
public:
/// <summary>
/// Gets handle to the shader resource view object.
/// </summary>
@@ -28,7 +26,6 @@ public:
/// <summary>
/// Gets CPU to the unordered access view object.
/// </summary>
/// <returns>UAV</returns>
virtual ID3D11UnorderedAccessView* UAV() const = 0;
};

View File

@@ -6,18 +6,6 @@
#include "GPUDeviceDX12.h"
#include "Engine/GraphicsDevice/DirectX/RenderToolsDX.h"
D3D12_CPU_DESCRIPTOR_HANDLE DescriptorHeapWithSlotsDX12::Slot::CPU() const
{
ASSERT_LOW_LAYER(Heap);
return Heap->CPU(Index);
}
D3D12_GPU_DESCRIPTOR_HANDLE DescriptorHeapWithSlotsDX12::Slot::GPU() const
{
ASSERT_LOW_LAYER(Heap);
return Heap->GPU(Index);
}
void DescriptorHeapWithSlotsDX12::Slot::CreateSRV(GPUDeviceDX12* device, ID3D12Resource* resource, D3D12_SHADER_RESOURCE_VIEW_DESC* desc)
{
if (Heap == nullptr)

View File

@@ -35,8 +35,15 @@ public:
}
#endif
D3D12_CPU_DESCRIPTOR_HANDLE CPU() const;
D3D12_GPU_DESCRIPTOR_HANDLE GPU() const;
FORCE_INLINE D3D12_CPU_DESCRIPTOR_HANDLE CPU() const
{
return Heap ? Heap->CPU(Index) : D3D12_CPU_DESCRIPTOR_HANDLE {};
}
FORCE_INLINE D3D12_GPU_DESCRIPTOR_HANDLE GPU() const
{
return Heap ? Heap->GPU(Index) : D3D12_GPU_DESCRIPTOR_HANDLE {};
}
void CreateSRV(GPUDeviceDX12* device, ID3D12Resource* resource, D3D12_SHADER_RESOURCE_VIEW_DESC* desc = nullptr);
void CreateRTV(GPUDeviceDX12* device, ID3D12Resource* resource, D3D12_RENDER_TARGET_VIEW_DESC* desc = nullptr);

View File

@@ -189,7 +189,7 @@ bool GPUBufferDX12::OnInit()
}
// Create views
_view.Init(_device, this);
_view.Init(_device, this, this);
if (useSRV)
{
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;

View File

@@ -46,10 +46,12 @@ public:
/// </summary>
/// <param name="device">The graphics device.</param>
/// <param name="owner">The resource owner.</param>
void Init(GPUDeviceDX12* device, ResourceOwnerDX12* owner)
/// <param name="parent">The parent resource.</param>
void Init(GPUDeviceDX12* device, ResourceOwnerDX12* owner, GPUResource* parent)
{
_device = device;
_owner = owner;
_parent = parent;
}
/// <summary>

View File

@@ -926,9 +926,13 @@ void GPUContextDX12::BindCB(int32 slot, GPUConstantBuffer* cb)
void GPUContextDX12::BindSR(int32 slot, GPUResourceView* view)
{
#if !BUILD_RELEASE
ASSERT(slot >= 0 && slot < GPU_MAX_SR_BINDED);
if (view && ((IShaderResourceDX12*)view->GetNativePtr())->SRV().ptr == 0)
LogInvalidResourceUsage(slot, view, InvalidBindPoint::SRV);
#endif
auto handle = view ? (IShaderResourceDX12*)view->GetNativePtr() : nullptr;
if (_srHandles[slot] != handle || !handle)
if (_srHandles[slot] != handle)
{
_srMaskDirtyGraphics |= 1 << slot;
_srMaskDirtyCompute |= 1 << slot;
@@ -940,7 +944,11 @@ void GPUContextDX12::BindSR(int32 slot, GPUResourceView* view)
void GPUContextDX12::BindUA(int32 slot, GPUResourceView* view)
{
#if !BUILD_RELEASE
ASSERT(slot >= 0 && slot < GPU_MAX_UA_BINDED);
if (view && ((IShaderResourceDX12*)view->GetNativePtr())->UAV().ptr == 0)
LogInvalidResourceUsage(slot, view, InvalidBindPoint::UAV);
#endif
_uaHandles[slot] = view ? (IShaderResourceDX12*)view->GetNativePtr() : nullptr;
if (view)
*view->LastRenderTime = _lastRenderTime;

View File

@@ -13,6 +13,7 @@ void GPUBufferViewVulkan::Init(GPUDeviceVulkan* device, GPUBufferVulkan* owner,
{
ASSERT(View == VK_NULL_HANDLE);
_parent = owner;
Device = device;
Owner = owner;
Buffer = buffer;

View File

@@ -46,6 +46,10 @@ public:
void DescriptorAsUniformTexelBuffer(GPUContextVulkan* context, VkBufferView& bufferView) override;
void DescriptorAsStorageBuffer(GPUContextVulkan* context, VkBuffer& buffer, VkDeviceSize& offset, VkDeviceSize& range) override;
void DescriptorAsStorageTexelBuffer(GPUContextVulkan* context, VkBufferView& bufferView) override;
#if !BUILD_RELEASE
bool HasSRV() const override { return ((GPUBuffer*)_parent)->IsShaderResource(); }
bool HasUAV() const override { return ((GPUBuffer*)_parent)->IsUnorderedAccess(); }
#endif
};
/// <summary>

View File

@@ -1001,7 +1001,11 @@ void GPUContextVulkan::BindCB(int32 slot, GPUConstantBuffer* cb)
void GPUContextVulkan::BindSR(int32 slot, GPUResourceView* view)
{
#if !BUILD_RELEASE
ASSERT(slot >= 0 && slot < GPU_MAX_SR_BINDED);
if (view && ((DescriptorOwnerResourceVulkan*)view->GetNativePtr())->HasSRV() == false)
LogInvalidResourceUsage(slot, view, InvalidBindPoint::SRV);
#endif
const auto handle = view ? (DescriptorOwnerResourceVulkan*)view->GetNativePtr() : nullptr;
if (_srHandles[slot] != handle)
{
@@ -1013,7 +1017,11 @@ void GPUContextVulkan::BindSR(int32 slot, GPUResourceView* view)
void GPUContextVulkan::BindUA(int32 slot, GPUResourceView* view)
{
#if !BUILD_RELEASE
ASSERT(slot >= 0 && slot < GPU_MAX_UA_BINDED);
if (view && ((DescriptorOwnerResourceVulkan*)view->GetNativePtr())->HasUAV() == false)
LogInvalidResourceUsage(slot, view, InvalidBindPoint::UAV);
#endif
const auto handle = view ? (DescriptorOwnerResourceVulkan*)view->GetNativePtr() : nullptr;
if (_uaHandles[slot] != handle)
{

View File

@@ -722,6 +722,12 @@ public:
{
CRASH;
}
#if !BUILD_RELEASE
// Utilities for incorrect resource usage.
virtual bool HasSRV() const { return false; }
virtual bool HasUAV() const { return false; }
#endif
};
extern GPUDevice* CreateGPUDeviceVulkan();

View File

@@ -77,6 +77,10 @@ public:
// [DescriptorOwnerResourceVulkan]
void DescriptorAsImage(GPUContextVulkan* context, VkImageView& imageView, VkImageLayout& layout) override;
void DescriptorAsStorageImage(GPUContextVulkan* context, VkImageView& imageView, VkImageLayout& layout) override;
#if !BUILD_RELEASE
bool HasSRV() const override { return ((GPUTexture*)_parent)->IsShaderResource(); }
bool HasUAV() const override { return ((GPUTexture*)_parent)->IsUnorderedAccess(); }
#endif
};
/// <summary>