diff --git a/Source/Engine/Graphics/Enums.h b/Source/Engine/Graphics/Enums.h
index 01ac11667..1e2f09f97 100644
--- a/Source/Engine/Graphics/Enums.h
+++ b/Source/Engine/Graphics/Enums.h
@@ -308,6 +308,17 @@ API_ENUM() enum class GPUResourceUsage
/// - Any resources read or accessed randomly on host, e.g. CPU-side copy of vertex buffer used as source of transfer, but also used for collision detection.
///
StagingReadback = 3,
+
+ ///
+ /// A resource that supports both read and write from the CPU.
+ /// This is likely to be the common choice for read-write buffers to transfer data between GPU compute buffers and CPU memory.
+ /// It usually means CPU (system) memory.
+ ///
+ ///
+ /// Usage:
+ /// - Staging memory to upload to GPU for compute and gather results back after processing.
+ ///
+ Staging = 4,
};
///
diff --git a/Source/Engine/Graphics/GPUBuffer.cpp b/Source/Engine/Graphics/GPUBuffer.cpp
index 6a0221b14..1afdcb8b3 100644
--- a/Source/Engine/Graphics/GPUBuffer.cpp
+++ b/Source/Engine/Graphics/GPUBuffer.cpp
@@ -71,6 +71,15 @@ GPUBufferDescription GPUBufferDescription::ToStagingReadback() const
return desc;
}
+GPUBufferDescription GPUBufferDescription::ToStaging() const
+{
+ auto desc = *this;
+ desc.Usage = GPUResourceUsage::Staging;
+ desc.Flags = GPUBufferFlags::None;
+ desc.InitData = nullptr;
+ return desc;
+}
+
bool GPUBufferDescription::Equals(const GPUBufferDescription& other) const
{
return Size == other.Size
@@ -123,6 +132,16 @@ GPUBuffer::GPUBuffer()
_desc.Size = 0;
}
+bool GPUBuffer::IsStaging() const
+{
+ return _desc.Usage == GPUResourceUsage::StagingReadback || _desc.Usage == GPUResourceUsage::StagingUpload || _desc.Usage == GPUResourceUsage::Staging;
+}
+
+bool GPUBuffer::IsDynamic() const
+{
+ return _desc.Usage == GPUResourceUsage::Dynamic;
+}
+
bool GPUBuffer::Init(const GPUBufferDescription& desc)
{
ASSERT(Math::IsInRange(desc.Size, 1, MAX_int32)
@@ -215,7 +234,7 @@ bool GPUBuffer::DownloadData(BytesContainer& result)
LOG(Warning, "Cannot download GPU buffer data from an empty buffer.");
return true;
}
- if (_desc.Usage == GPUResourceUsage::StagingReadback || _desc.Usage == GPUResourceUsage::Dynamic)
+ if (_desc.Usage == GPUResourceUsage::StagingReadback || _desc.Usage == GPUResourceUsage::Dynamic || _desc.Usage == GPUResourceUsage::Staging)
{
// Use faster path for staging resources
return GetData(result);
diff --git a/Source/Engine/Graphics/GPUBuffer.h b/Source/Engine/Graphics/GPUBuffer.h
index d40b7744d..1d5e7bc93 100644
--- a/Source/Engine/Graphics/GPUBuffer.h
+++ b/Source/Engine/Graphics/GPUBuffer.h
@@ -86,20 +86,14 @@ public:
}
///
- /// Checks if buffer is a staging buffer (supports CPU readback).
+ /// Checks if buffer is a staging buffer (supports CPU access).
///
- API_PROPERTY() FORCE_INLINE bool IsStaging() const
- {
- return _desc.Usage == GPUResourceUsage::StagingReadback || _desc.Usage == GPUResourceUsage::StagingUpload;
- }
+ API_PROPERTY() bool IsStaging() const;
///
- /// Checks if buffer is a staging buffer (supports CPU readback).
+ /// Checks if buffer is a dynamic buffer.
///
- API_PROPERTY() FORCE_INLINE bool IsDynamic() const
- {
- return _desc.Usage == GPUResourceUsage::Dynamic;
- }
+ API_PROPERTY() bool IsDynamic() const;
///
/// Gets a value indicating whether this buffer is a shader resource.
@@ -173,7 +167,7 @@ public:
Task* DownloadDataAsync(BytesContainer& result);
///
- /// Gets the buffer data via map/memcpy/unmap sequence. Always supported for dynamic and staging readback buffers (other types support depends on graphics backend implementation).
+ /// Gets the buffer data via map/memcpy/unmap sequence. Always supported for dynamic and staging buffers (other types support depends on graphics backend implementation).
///
/// The output data container.
/// True if failed, otherwise false.
diff --git a/Source/Engine/Graphics/GPUBufferDescription.cs b/Source/Engine/Graphics/GPUBufferDescription.cs
index 6bc0051a8..c044344ec 100644
--- a/Source/Engine/Graphics/GPUBufferDescription.cs
+++ b/Source/Engine/Graphics/GPUBufferDescription.cs
@@ -271,7 +271,7 @@ namespace FlaxEngine
}
///
- /// Gets the staging upload description for this instance.
+ /// Gets the staging upload (CPU write) description for this instance.
///
/// A staging buffer description
public GPUBufferDescription ToStagingUpload()
@@ -284,7 +284,7 @@ namespace FlaxEngine
}
///
- /// Gets the staging readback description for this instance.
+ /// Gets the staging readback (CPU read) description for this instance.
///
/// A staging buffer description
public GPUBufferDescription ToStagingReadback()
@@ -296,6 +296,19 @@ namespace FlaxEngine
return desc;
}
+ ///
+ /// Gets the staging (CPU read/write) description for this instance.
+ ///
+ /// A staging buffer description
+ public GPUBufferDescription ToStaging()
+ {
+ var desc = this;
+ desc.Usage = GPUResourceUsage.Staging;
+ desc.Flags = GPUBufferFlags.None;
+ desc.InitData = IntPtr.Zero;
+ return desc;
+ }
+
///
public bool Equals(GPUBufferDescription other)
{
diff --git a/Source/Engine/Graphics/GPUBufferDescription.h b/Source/Engine/Graphics/GPUBufferDescription.h
index d4049ea5b..17ddffad7 100644
--- a/Source/Engine/Graphics/GPUBufferDescription.h
+++ b/Source/Engine/Graphics/GPUBufferDescription.h
@@ -335,6 +335,7 @@ public:
void Clear();
GPUBufferDescription ToStagingUpload() const;
GPUBufferDescription ToStagingReadback() const;
+ GPUBufferDescription ToStaging() const;
bool Equals(const GPUBufferDescription& other) const;
String ToString() const;
diff --git a/Source/Engine/Graphics/Textures/GPUTexture.cpp b/Source/Engine/Graphics/Textures/GPUTexture.cpp
index 23302deb8..a48da4244 100644
--- a/Source/Engine/Graphics/Textures/GPUTexture.cpp
+++ b/Source/Engine/Graphics/Textures/GPUTexture.cpp
@@ -142,6 +142,14 @@ GPUTextureDescription GPUTextureDescription::ToStagingReadback() const
return copy;
}
+GPUTextureDescription GPUTextureDescription::ToStaging() const
+{
+ auto copy = *this;
+ copy.Flags = GPUTextureFlags::None;
+ copy.Usage = GPUResourceUsage::Staging;
+ return copy;
+}
+
bool GPUTextureDescription::Equals(const GPUTextureDescription& other) const
{
return Dimensions == other.Dimensions
@@ -208,6 +216,11 @@ GPUTexture::GPUTexture()
_desc.Clear();
}
+bool GPUTexture::IsStaging() const
+{
+ return _desc.Usage == GPUResourceUsage::StagingUpload || _desc.Usage == GPUResourceUsage::StagingReadback || _desc.Usage == GPUResourceUsage::Staging;
+}
+
Float2 GPUTexture::Size() const
{
return Float2(static_cast(_desc.Width), static_cast(_desc.Height));
diff --git a/Source/Engine/Graphics/Textures/GPUTexture.h b/Source/Engine/Graphics/Textures/GPUTexture.h
index 685e59985..9aa6571e0 100644
--- a/Source/Engine/Graphics/Textures/GPUTexture.h
+++ b/Source/Engine/Graphics/Textures/GPUTexture.h
@@ -294,10 +294,7 @@ public:
///
/// Checks if texture is a staging buffer (supports direct CPU access).
///
- FORCE_INLINE bool IsStaging() const
- {
- return _desc.Usage == GPUResourceUsage::StagingUpload || _desc.Usage == GPUResourceUsage::StagingReadback;
- }
+ bool IsStaging() const;
///
/// Gets a boolean indicating whether this is a using a block compress format (BC1, BC2, BC3, BC4, BC5, BC6H, BC7, etc.).
diff --git a/Source/Engine/Graphics/Textures/GPUTextureDescription.cs b/Source/Engine/Graphics/Textures/GPUTextureDescription.cs
index c5fb409f0..c67c389d0 100644
--- a/Source/Engine/Graphics/Textures/GPUTextureDescription.cs
+++ b/Source/Engine/Graphics/Textures/GPUTextureDescription.cs
@@ -300,7 +300,7 @@ namespace FlaxEngine
}
///
- /// Gets the staging description for this instance.
+ /// Gets the staging upload (CPU write) description for this instance.
///
/// A staging texture description
public GPUTextureDescription ToStagingUpload()
@@ -312,7 +312,7 @@ namespace FlaxEngine
}
///
- /// Gets the staging description for this instance.
+ /// Gets the staging readback (CPU read) description for this instance.
///
/// A staging texture description
public GPUTextureDescription ToStagingReadback()
@@ -323,6 +323,18 @@ namespace FlaxEngine
return desc;
}
+ ///
+ /// Gets the staging (CPU read/write) description for this instance.
+ ///
+ /// A staging texture description
+ public GPUTextureDescription ToStaging()
+ {
+ var desc = this;
+ desc.Flags = GPUTextureFlags.None;
+ desc.Usage = GPUResourceUsage.Staging;
+ return desc;
+ }
+
///
public override string ToString()
{
diff --git a/Source/Engine/Graphics/Textures/GPUTextureDescription.h b/Source/Engine/Graphics/Textures/GPUTextureDescription.h
index 281cef8d8..9844e05a8 100644
--- a/Source/Engine/Graphics/Textures/GPUTextureDescription.h
+++ b/Source/Engine/Graphics/Textures/GPUTextureDescription.h
@@ -397,6 +397,7 @@ public:
void Clear();
GPUTextureDescription ToStagingUpload() const;
GPUTextureDescription ToStagingReadback() const;
+ GPUTextureDescription ToStaging() const;
bool Equals(const GPUTextureDescription& other) const;
String ToString() const;
diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUBufferDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUBufferDX12.cpp
index c38b3edef..066f019ae 100644
--- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUBufferDX12.cpp
+++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUBufferDX12.cpp
@@ -120,6 +120,7 @@ bool GPUBufferDX12::OnInit()
switch (_desc.Usage)
{
case GPUResourceUsage::StagingUpload:
+ case GPUResourceUsage::Staging:
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
break;
case GPUResourceUsage::StagingReadback:
@@ -152,7 +153,7 @@ bool GPUBufferDX12::OnInit()
// But if we are doing it during update or from the other thread we have to register resource data upload job.
// In both cases options.InitData data have to exist for a few next frames.
- if (_desc.Usage == GPUResourceUsage::StagingUpload)
+ if (_desc.Usage == GPUResourceUsage::StagingUpload || _desc.Usage == GPUResourceUsage::Staging)
{
// Modify staging resource data now
SetData(_desc.InitData, _desc.Size);
diff --git a/Source/Engine/GraphicsDevice/DirectX/RenderToolsDX.h b/Source/Engine/GraphicsDevice/DirectX/RenderToolsDX.h
index 5cfb5b4eb..cdcc55c9b 100644
--- a/Source/Engine/GraphicsDevice/DirectX/RenderToolsDX.h
+++ b/Source/Engine/GraphicsDevice/DirectX/RenderToolsDX.h
@@ -28,6 +28,7 @@ namespace RenderToolsDX
{
case GPUResourceUsage::Dynamic:
return D3D11_USAGE_DYNAMIC;
+ case GPUResourceUsage::Staging:
case GPUResourceUsage::StagingUpload:
case GPUResourceUsage::StagingReadback:
return D3D11_USAGE_STAGING;
@@ -47,6 +48,8 @@ namespace RenderToolsDX
{
case GPUResourceUsage::Dynamic:
return D3D11_CPU_ACCESS_WRITE;
+ case GPUResourceUsage::Staging:
+ return D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
case GPUResourceUsage::StagingReadback:
return D3D11_CPU_ACCESS_READ;
case GPUResourceUsage::StagingUpload:
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUBufferVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUBufferVulkan.cpp
index 99d993dcd..fbb3392ab 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUBufferVulkan.cpp
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUBufferVulkan.cpp
@@ -128,6 +128,9 @@ bool GPUBufferVulkan::OnInit()
case GPUResourceUsage::StagingReadback:
allocInfo.usage = VMA_MEMORY_USAGE_GPU_TO_CPU;
break;
+ case GPUResourceUsage::Staging:
+ allocInfo.usage = VMA_MEMORY_USAGE_CPU_COPY;
+ break;
default:
allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
}