Skip to content

Commit

Permalink
Support read-only storage buffers
Browse files Browse the repository at this point in the history
  • Loading branch information
Nelarius committed Mar 29, 2024
1 parent 3d1c871 commit 70c89b9
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 80 deletions.
43 changes: 21 additions & 22 deletions src/pt/gpu_buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,22 @@ void bufferSafeRelease(WGPUBuffer buffer)
}
}

WGPUBufferBindingType bufferUsageToBufferBindingType(const WGPUBufferUsageFlags usage)
inline WGPUBufferBindingType gpuBufferUsageToWGPUBufferBindingType(const GpuBufferUsage usage)
{
assert(usage != WGPUBufferUsage_None);

// BufferUsage flags contains redundant binding type information that we can reuse, so that the
// user doesn't have to provide the additional flag.

if (usage & WGPUBufferUsage_Uniform)
if ((usage & GpuBufferUsage::Storage) == GpuBufferUsage::Storage)
{
return WGPUBufferBindingType_Uniform;
return WGPUBufferBindingType_Storage;
}
else if (usage & WGPUBufferUsage_Storage)
else if ((usage & GpuBufferUsage::ReadOnlyStorage) == GpuBufferUsage::ReadOnlyStorage)
{
return WGPUBufferBindingType_Storage;
return WGPUBufferBindingType_ReadOnlyStorage;
}
else if ((usage & GpuBufferUsage::Uniform) == GpuBufferUsage::Uniform)
{
return WGPUBufferBindingType_Uniform;
}

assert(!"No matching WGPUBufferBindingType for WGPUBufferUsage.");
NLRS_ASSERT("Invalid buffer usage for binding type!");

return WGPUBufferBindingType_Undefined;
}
Expand All @@ -45,7 +44,7 @@ GpuBuffer::GpuBuffer(GpuBuffer&& other) noexcept

other.mBuffer = nullptr;
other.mByteSize = 0;
other.mUsage = WGPUBufferUsage_None;
other.mUsage = GpuBufferUsage::None;
}
}

Expand All @@ -61,26 +60,26 @@ GpuBuffer& GpuBuffer::operator=(GpuBuffer&& other) noexcept

other.mBuffer = nullptr;
other.mByteSize = 0;
other.mUsage = WGPUBufferUsage_None;
other.mUsage = GpuBufferUsage::None;
}
return *this;
}

GpuBuffer::GpuBuffer(
const WGPUDevice device,
const char* const label,
const WGPUBufferUsageFlags usage,
const std::size_t byteSize)
const WGPUDevice device,
const char* const label,
const GpuBufferUsage usage,
const std::size_t byteSize)
: mBuffer(nullptr),
mByteSize(byteSize),
mUsage(usage)
{
assert(device != nullptr);
NLRS_ASSERT(device != nullptr);

const WGPUBufferDescriptor bufferDesc{
.nextInChain = nullptr,
.label = label,
.usage = mUsage,
.usage = gpuBufferUsageToWGPUBufferUsage(usage),
.size = mByteSize,
.mappedAtCreation = false,
};
Expand All @@ -103,14 +102,14 @@ WGPUBindGroupLayoutEntry GpuBuffer::bindGroupLayoutEntry(
const WGPUShaderStageFlags visibility,
const std::size_t minBindingSize) const
{
assert(mBuffer != nullptr);
const WGPUBufferBindingType bindingType = bufferUsageToBufferBindingType(mUsage);
NLRS_ASSERT(mBuffer != nullptr);
const WGPUBufferBindingType bindingType = gpuBufferUsageToWGPUBufferBindingType(mUsage);
return bufferBindGroupLayoutEntry(bindingIdx, visibility, bindingType, minBindingSize);
}

WGPUBindGroupEntry GpuBuffer::bindGroupEntry(const std::uint32_t bindingIdx) const
{
assert(mBuffer != nullptr);
NLRS_ASSERT(mBuffer != nullptr);
return bufferBindGroupEntry(bindingIdx, mBuffer, mByteSize);
}
} // namespace nlrs
122 changes: 99 additions & 23 deletions src/pt/gpu_buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

#include "webgpu_utils.hpp"

#include <common/assert.hpp>

#include <fmt/core.h>
#include <webgpu/webgpu.h>

#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
Expand All @@ -14,6 +15,22 @@

namespace nlrs
{
enum class GpuBufferUsage : uint32_t
{
None = 0,
CopySrc = 1 << 0,
CopyDst = 1 << 1,
MapRead = 1 << 2,
MapWrite = 1 << 3,
Index = 1 << 4,
Vertex = 1 << 5,
Uniform = 1 << 6,
Storage = 1 << 7,
ReadOnlyStorage = 1 << 8,
Indirect = 1 << 9,
QueryResolve = 1 << 10,
};

// A wrapper around WGPUBuffer with unique ownership semantics.
class GpuBuffer
{
Expand All @@ -26,31 +43,23 @@ class GpuBuffer
GpuBuffer(GpuBuffer&&) noexcept;
GpuBuffer& operator=(GpuBuffer&&) noexcept;

GpuBuffer(
WGPUDevice device,
const char* label,
WGPUBufferUsageFlags usage,
std::size_t byteSize);
GpuBuffer(WGPUDevice device, const char* label, GpuBufferUsage usage, std::size_t byteSize);

template<typename T>
GpuBuffer(
WGPUDevice device,
const char* label,
WGPUBufferUsageFlags usage,
std::span<const T> data);
GpuBuffer(WGPUDevice device, const char* label, GpuBufferUsage usage, std::span<const T> data);

~GpuBuffer();

// Raw access

inline WGPUBuffer ptr() const noexcept
{
assert(mBuffer != nullptr);
NLRS_ASSERT(mBuffer != nullptr);
return mBuffer;
}
inline std::size_t byteSize() const noexcept
{
assert(mByteSize > 0);
NLRS_ASSERT(mByteSize > 0);
return mByteSize;
}

Expand All @@ -63,27 +72,94 @@ class GpuBuffer
WGPUBindGroupEntry bindGroupEntry(std::uint32_t bindingIndex) const;

private:
WGPUBuffer mBuffer = nullptr;
std::size_t mByteSize = 0;
WGPUBufferUsageFlags mUsage = WGPUBufferUsage_None;
WGPUBuffer mBuffer = nullptr;
std::size_t mByteSize = 0;
GpuBufferUsage mUsage = GpuBufferUsage::None;
};

inline GpuBufferUsage operator|(GpuBufferUsage lhs, GpuBufferUsage rhs) noexcept
{
return static_cast<GpuBufferUsage>(static_cast<uint32_t>(lhs) | static_cast<uint32_t>(rhs));
}

inline GpuBufferUsage operator|=(GpuBufferUsage& lhs, GpuBufferUsage rhs) noexcept
{
return lhs = lhs | rhs;
}

inline GpuBufferUsage operator&(GpuBufferUsage lhs, GpuBufferUsage rhs) noexcept
{
return static_cast<GpuBufferUsage>(static_cast<uint32_t>(lhs) & static_cast<uint32_t>(rhs));
}

inline WGPUBufferUsageFlags gpuBufferUsageToWGPUBufferUsage(const GpuBufferUsage usage) noexcept
{
WGPUBufferUsageFlags wgpuUsage = WGPUBufferUsage_None;

if ((usage & GpuBufferUsage::CopySrc) == GpuBufferUsage::CopySrc)
{
wgpuUsage |= WGPUBufferUsage_CopySrc;
}
if ((usage & GpuBufferUsage::CopyDst) == GpuBufferUsage::CopyDst)
{
wgpuUsage |= WGPUBufferUsage_CopyDst;
}
if ((usage & GpuBufferUsage::MapRead) == GpuBufferUsage::MapRead)
{
wgpuUsage |= WGPUBufferUsage_MapRead;
}
if ((usage & GpuBufferUsage::MapWrite) == GpuBufferUsage::MapWrite)
{
wgpuUsage |= WGPUBufferUsage_MapWrite;
}
if ((usage & GpuBufferUsage::Index) == GpuBufferUsage::Index)
{
wgpuUsage |= WGPUBufferUsage_Index;
}
if ((usage & GpuBufferUsage::Vertex) == GpuBufferUsage::Vertex)
{
wgpuUsage |= WGPUBufferUsage_Vertex;
}
if ((usage & GpuBufferUsage::Uniform) == GpuBufferUsage::Uniform)
{
wgpuUsage |= WGPUBufferUsage_Uniform;
}
if ((usage & GpuBufferUsage::Storage) == GpuBufferUsage::Storage)
{
wgpuUsage |= WGPUBufferUsage_Storage;
}
if ((usage & GpuBufferUsage::ReadOnlyStorage) == GpuBufferUsage::ReadOnlyStorage)
{
wgpuUsage |= WGPUBufferUsage_Storage;
}
if ((usage & GpuBufferUsage::Indirect) == GpuBufferUsage::Indirect)
{
wgpuUsage |= WGPUBufferUsage_Indirect;
}
if ((usage & GpuBufferUsage::QueryResolve) == GpuBufferUsage::QueryResolve)
{
wgpuUsage |= WGPUBufferUsage_QueryResolve;
}

return wgpuUsage;
}

template<typename T>
GpuBuffer::GpuBuffer(
const WGPUDevice device,
const char* const label,
const WGPUBufferUsageFlags usage,
const std::span<const T> data)
const WGPUDevice device,
const char* const label,
const GpuBufferUsage usage,
const std::span<const T> data)
: mBuffer(nullptr),
mByteSize(sizeof(T) * data.size()),
mUsage(usage)
{
assert(device != nullptr);
NLRS_ASSERT(device != nullptr);

const WGPUBufferDescriptor bufferDesc{
.nextInChain = nullptr,
.label = label,
.usage = mUsage,
.usage = gpuBufferUsageToWGPUBufferUsage(usage),
.size = mByteSize,
.mappedAtCreation = true,
};
Expand All @@ -99,7 +175,7 @@ GpuBuffer::GpuBuffer(
// https://www.w3.org/TR/webgpu/#dom-gpubufferdescriptor-mappedatcreation

void* const mappedData = wgpuBufferGetMappedRange(mBuffer, 0, mByteSize);
assert(mappedData);
NLRS_ASSERT(mappedData);
std::memcpy(mappedData, data.data(), mByteSize);
wgpuBufferUnmap(mBuffer);
}
Expand Down
14 changes: 7 additions & 7 deletions src/pt/hybrid_renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ HybridRenderer::GbufferPass::GbufferPass(
std::back_inserter(buffers),
[&gpuContext](const std::span<const glm::vec4> vertices) -> GpuBuffer {
return GpuBuffer(
gpuContext.device, "Mesh Vertex Buffer", WGPUBufferUsage_Vertex, vertices);
gpuContext.device, "Mesh Vertex Buffer", GpuBufferUsage::Vertex, vertices);
});
return buffers;
}()),
Expand All @@ -313,7 +313,7 @@ HybridRenderer::GbufferPass::GbufferPass(
std::back_inserter(buffers),
[&gpuContext](const std::span<const glm::vec4> normals) -> GpuBuffer {
return GpuBuffer{
gpuContext.device, "Mesh normal buffer", WGPUBufferUsage_Vertex, normals};
gpuContext.device, "Mesh normal buffer", GpuBufferUsage::Vertex, normals};
});
return buffers;
}()),
Expand All @@ -325,7 +325,7 @@ HybridRenderer::GbufferPass::GbufferPass(
std::back_inserter(buffers),
[&gpuContext](const std::span<const glm::vec2> texCoords) {
return GpuBuffer(
gpuContext.device, "Mesh TexCoord Buffer", WGPUBufferUsage_Vertex, texCoords);
gpuContext.device, "Mesh TexCoord Buffer", GpuBufferUsage::Vertex, texCoords);
});
return buffers;
}()),
Expand All @@ -338,7 +338,7 @@ HybridRenderer::GbufferPass::GbufferPass(
[&gpuContext](const std::span<const std::uint32_t> indices) {
return IndexBuffer{
.buffer = GpuBuffer(
gpuContext.device, "Mesh Index Buffer", WGPUBufferUsage_Index, indices),
gpuContext.device, "Mesh Index Buffer", GpuBufferUsage::Index, indices),
.count = static_cast<std::uint32_t>(indices.size()),
.format = WGPUIndexFormat_Uint32,
};
Expand Down Expand Up @@ -425,7 +425,7 @@ HybridRenderer::GbufferPass::GbufferPass(
mUniformBuffer(
gpuContext.device,
"Uniform buffer",
WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform,
GpuBufferUsage::Uniform | GpuBufferUsage::CopyDst,
sizeof(glm::mat4)),
mUniformBindGroup(),
mSamplerBindGroup(),
Expand Down Expand Up @@ -790,7 +790,7 @@ HybridRenderer::DebugPass::DebugPass(
: mVertexBuffer(
gpuContext.device,
"Vertex buffer",
WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex,
GpuBufferUsage::Vertex | GpuBufferUsage::CopyDst,
std::span<const float[2]>(quadVertexData)),
mUniformBuffer(),
mUniformBindGroup(),
Expand All @@ -801,7 +801,7 @@ HybridRenderer::DebugPass::DebugPass(
mUniformBuffer = GpuBuffer{
gpuContext.device,
"Uniform buffer",
WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform,
GpuBufferUsage::Uniform | GpuBufferUsage::CopyDst,
std::span<const float>(&uniformData.x, sizeof(Extent2<float>))};
}

Expand Down
Loading

0 comments on commit 70c89b9

Please sign in to comment.