Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
79f9fd7
WIP of a bunch of buffer/texture creation code.
manon-traverse May 18, 2026
8314fe4
More WIP.
manon-traverse May 18, 2026
eb53bfb
Almost completed refactor in DX12.
manon-traverse May 27, 2026
16f7533
Implement mapping and unmapping of vulkan textures.
manon-traverse May 27, 2026
2572eec
Implement copyTextureToBuffer in DX12 and Vulkan.
manon-traverse May 27, 2026
bfe090b
Use llvm::cast instead of static_cast.
manon-traverse May 27, 2026
dfedd92
Lots of progress in making agnostic buffers and textures fully work!
manon-traverse May 29, 2026
2c30382
Fix resource state issue.
manon-traverse May 29, 2026
a14fe0d
Remove incorrect shadowed variable.
manon-traverse May 29, 2026
99cf89d
Use correct strides when uploading textures.
manon-traverse Jun 1, 2026
4ca20b6
Formatting.
manon-traverse Jun 1, 2026
ba7980a
Store the size in bytes in the Texture and use that for the memory map.
manon-traverse Jun 1, 2026
852eb66
Use correct stride for computing the readback buffer size.
manon-traverse Jun 1, 2026
ae419f4
Counter Buffer WIP.
manon-traverse Jun 1, 2026
a11240c
Get basically all tests passing on DX12.
manon-traverse Jun 2, 2026
bf1965e
Clean up transition barriers.
manon-traverse Jun 2, 2026
b587eb4
Remove dead code.
manon-traverse Jun 2, 2026
5a81aea
Use API agnostic code to readback render target.
manon-traverse Jun 2, 2026
3d094aa
Add missing Texture.cpp file.
manon-traverse Jun 2, 2026
1d3ab08
Add AccelerationStructure entry to isBuffer.
manon-traverse Jun 3, 2026
37a52c6
Add vulkan image transitions to the render encoder
manon-traverse Jun 3, 2026
76635d2
Remove dead code.
manon-traverse Jun 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions include/API/Buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,49 @@

namespace offloadtest {

enum class BufferUsage {
enum class BufferShaderAccessType : uint32_t {
Raw,
Typed,
Structured,
};

union BufferShaderAccessTypeParams {
Format Fmt; // Typed Only
uint32_t StructureStride; // Structured Only
};

enum class BufferUsage : uint32_t {
Storage,
ConstantBuffer,
IndexBuffer,
VertexBuffer,
IndirectArgs,
};

struct BufferCreateDesc {
MemoryLocation Location;
MemoryBacking Backing;
BufferUsage Usage;
BufferShaderAccessType AccessType;
BufferShaderAccessTypeParams AccessTypeParams;
bool HasCounter;

static BufferCreateDesc uploadBuffer() {
return BufferCreateDesc{MemoryLocation::CpuToGpu, BufferUsage::Storage};
return BufferCreateDesc{MemoryLocation::CpuToGpu,
MemoryBacking::Automatic,
BufferUsage::Storage,
BufferShaderAccessType::Raw,
{},
false};
}

static BufferCreateDesc readbackBuffer() {
return BufferCreateDesc{MemoryLocation::GpuToCpu, BufferUsage::Storage};
return BufferCreateDesc{MemoryLocation::GpuToCpu,
MemoryBacking::Automatic,
BufferUsage::Storage,
BufferShaderAccessType::Raw,
{},
false};
}
};

Expand All @@ -55,6 +83,7 @@ class Buffer {
Buffer &operator=(const Buffer &) = delete;

GPUAPI getAPI() const { return API; }
virtual const BufferCreateDesc &getDesc() const = 0;

protected:
explicit Buffer(GPUAPI API) : API(API) {}
Expand Down
17 changes: 17 additions & 0 deletions include/API/Device.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@ class Device {
virtual llvm::Expected<std::unique_ptr<Texture>>
createTexture(std::string Name, const TextureCreateDesc &Desc) = 0;

// The row stride required when uploading data to (or reading back from) a
// texture created with the given description, via an upload buffer.
virtual uint32_t
getTextureUploadRowStrideInBytes(const TextureCreateDesc &Desc) const = 0;

virtual llvm::Expected<std::unique_ptr<RenderPass>>
createRenderPass(const RenderPassDesc &Desc) = 0;

Expand Down Expand Up @@ -316,6 +321,18 @@ createBufferWithData(Device &Dev, std::string Name,
size_t SizeInBytes, ComputeEncoder *Encoder,
std::unique_ptr<offloadtest::Buffer> *OutUploadBuffer);

llvm::Expected<std::unique_ptr<offloadtest::Buffer>>
createBufferWithData(Device &Dev, std::string Name,
const BufferCreateDesc &Desc, const void *Data,
size_t SizeInBytes, ComputeEncoder *Encoder,
std::unique_ptr<offloadtest::Buffer> *OutUploadBuffer);

llvm::Expected<std::unique_ptr<offloadtest::Texture>>
createTextureWithData(Device &Dev, std::string Name,
const TextureCreateDesc &Desc, const void *Data,
size_t SizeInBytes, ComputeEncoder *Encoder,
std::unique_ptr<offloadtest::Buffer> *OutUploadBuffer);

} // namespace offloadtest

#endif // OFFLOADTEST_API_DEVICE_H
6 changes: 6 additions & 0 deletions include/API/Encoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace offloadtest {

class Buffer;
class PipelineState;
class Texture;

/// Base class for all command encoders. An encoder records commands into a
/// command buffer. Call endEncoding() when done recording. Barriers are
Expand Down Expand Up @@ -82,6 +83,11 @@ class ComputeEncoder : public CommandEncoder {
virtual llvm::Error copyBufferToBuffer(Buffer &Src, size_t SrcOffset,
Buffer &Dst, size_t DstOffset,
size_t Size) = 0;
virtual llvm::Error copyCounterToBuffer(Buffer &Src, Buffer &Dst) = 0;

virtual llvm::Error copyBufferToTexture(Buffer &Src, Texture &Dst) = 0;

virtual llvm::Error copyTextureToBuffer(Texture &Src, Buffer &Dst) = 0;
};

struct Viewport {
Expand Down
18 changes: 16 additions & 2 deletions include/API/FormatConversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,27 @@ inline llvm::Expected<Format> toFormat(DataFormat Format, int Channels) {
if (Channels == 1)
return Format::D32Float;
break;
case DataFormat::UInt64:
switch (Channels) {
case 1:
return Format::R64Uint;
case 2:
return Format::RG64Uint;
}
break;
case DataFormat::Int64:
switch (Channels) {
case 1:
return Format::R64Sint;
case 2:
return Format::RG64Sint;
}
break;
// No Format mapping for these DataFormats.
case DataFormat::Hex8:
case DataFormat::Hex16:
case DataFormat::Hex32:
case DataFormat::Hex64:
case DataFormat::UInt64:
case DataFormat::Int64:
case DataFormat::Float16:
case DataFormat::Float64:
case DataFormat::Bool:
Expand Down
49 changes: 49 additions & 0 deletions include/API/Resources.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ enum class MemoryLocation {
GpuToCpu,
};

enum class MemoryBacking {
// Allocates all memory for this resource.
Automatic,

// No memory allocated; physical pages mapped manually on demand.
// DX: CreateReservedResource + UpdateTileMappings.
// VK: VK_IMAGE_CREATE_SPARSE_BINDING_BIT + vkQueueBindSparse.
// Metal: MTLTextureDescriptor.sparseLevel + heap tile mapping
// (requires Apple Silicon).
Sparse,
};

enum class IndexFormat { Uint16, Uint32 };

// TODO: Add Unorm types (e.g. R8Unorm, RGBA8Unorm) which can be sampled as
Expand All @@ -47,6 +59,10 @@ enum class Format {
RGBA32Sint,
RGBA32Uint,
RGBA32Float,
R64Uint,
R64Sint,
RG64Uint,
RG64Sint,
D32Float,
D32FloatS8Uint,
};
Expand Down Expand Up @@ -85,6 +101,14 @@ inline llvm::StringRef getFormatName(Format Format) {
return "RGBA32Uint";
case Format::RGBA32Float:
return "RGBA32Float";
case Format::R64Uint:
return "R64Uint";
case Format::R64Sint:
return "R64Sint";
case Format::RG64Uint:
return "RG64Uint";
case Format::RG64Sint:
return "RG64Sint";
case Format::D32Float:
return "D32Float";
case Format::D32FloatS8Uint:
Expand Down Expand Up @@ -112,12 +136,16 @@ inline uint32_t getFormatSizeInBytes(Format Format) {
case Format::RG32Uint:
case Format::RG32Float:
case Format::D32FloatS8Uint:
case Format::R64Uint:
case Format::R64Sint:
return 8;
case Format::RGB32Float:
return 12;
case Format::RGBA32Sint:
case Format::RGBA32Uint:
case Format::RGBA32Float:
case Format::RG64Uint:
case Format::RG64Sint:
return 16;
}
llvm_unreachable("All Format cases handled");
Expand All @@ -141,6 +169,10 @@ inline bool isDepthFormat(Format Format) {
case Format::RGBA32Sint:
case Format::RGBA32Uint:
case Format::RGBA32Float:
case Format::R64Uint:
case Format::R64Sint:
case Format::RG64Uint:
case Format::RG64Sint:
return false;
case Format::D32Float:
case Format::D32FloatS8Uint:
Expand All @@ -167,6 +199,10 @@ inline bool isStencilFormat(Format Format) {
case Format::RGBA32Sint:
case Format::RGBA32Uint:
case Format::RGBA32Float:
case Format::R64Uint:
case Format::R64Sint:
case Format::RG64Uint:
case Format::RG64Sint:
case Format::D32Float:
return false;
case Format::D32FloatS8Uint:
Expand Down Expand Up @@ -199,6 +235,11 @@ inline bool isTextureCompatible(Format Format) {
case Format::RGBA32Float:
case Format::D32Float:
case Format::D32FloatS8Uint:
// Only for RWTextures
case Format::R64Uint:
case Format::R64Sint:
case Format::RG64Uint:
case Format::RG64Sint:
return true;
}
llvm_unreachable("All Format cases handled");
Expand All @@ -224,6 +265,10 @@ inline bool isVertexCompatible(Format Format) {
case Format::RGBA32Uint:
case Format::RGBA32Float:
return true;
case Format::R64Uint:
case Format::R64Sint:
case Format::RG64Uint:
case Format::RG64Sint:
case Format::D32Float:
case Format::D32FloatS8Uint:
return false;
Expand Down Expand Up @@ -253,6 +298,10 @@ inline bool isPositionCompatible(Format Format) {
case Format::RG32Uint:
case Format::RGBA32Sint:
case Format::RGBA32Uint:
case Format::R64Uint:
case Format::R64Sint:
case Format::RG64Uint:
case Format::RG64Sint:
case Format::D32Float:
case Format::D32FloatS8Uint:
return false;
Expand Down
18 changes: 18 additions & 0 deletions include/API/Texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
namespace offloadtest {
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();

class Device;

enum TextureUsage : uint32_t {
Sampled = 1 << 0,
Storage = 1 << 1,
Expand Down Expand Up @@ -150,9 +152,25 @@ class Texture {
Texture(const Texture &) = delete;
Texture &operator=(const Texture &) = delete;

// Calculate the size in bytes of the texture data given a linear layout
// Useful for calculating the size for an upload or readback buffer.
size_t calculateLinearSizeInBytes(Device &Dev) const;

// Maps the texture's memory for host access. Only valid for CpuToGpu and
// GpuToCpu textures; returns an error for GpuOnly. Each successful map() must
// be paired with a call to unmap() before the texture is used on the GPU.
virtual llvm::Expected<void *> map() = 0;
virtual void unmap() = 0;

GPUAPI getAPI() const { return API; }
virtual const TextureCreateDesc &getDesc() const = 0;

// The byte stride between consecutive rows when the texture is mapped for
// direct host access. Errors if the texture is not host-visible, or if its
// memory layout is not linear (the mapped bytes have no well-defined row
// stride otherwise).
virtual llvm::Expected<uint32_t> getMappedRowPitchInBytes() const = 0;

protected:
explicit Texture(GPUAPI API) : API(API) {}
};
Expand Down
22 changes: 21 additions & 1 deletion include/Support/Pipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ struct Resource {
std::optional<VulkanBinding> VKBinding;
CPUBuffer *BufferPtr = nullptr;
Sampler *SamplerPtr = nullptr;
bool HasCounter;
bool HasCounter = false;
std::optional<uint32_t> TilesMapped;
bool IsReserved = false;
TLASDesc *TLASPtr = nullptr;
Expand Down Expand Up @@ -281,6 +281,26 @@ struct Resource {
llvm_unreachable("All cases handled");
}

bool isBuffer() const {
switch (Kind) {
case ResourceKind::Buffer:
case ResourceKind::RWBuffer:
case ResourceKind::StructuredBuffer:
case ResourceKind::RWStructuredBuffer:
case ResourceKind::ByteAddressBuffer:
case ResourceKind::RWByteAddressBuffer:
case ResourceKind::ConstantBuffer:
return true;
case ResourceKind::Sampler:
case ResourceKind::Texture2D:
case ResourceKind::RWTexture2D:
case ResourceKind::SampledTexture2D:
case ResourceKind::AccelerationStructure:
return false;
}
llvm_unreachable("All cases handled");
}

bool isTexture() const {
switch (Kind) {
case ResourceKind::Buffer:
Expand Down
1 change: 1 addition & 0 deletions lib/API/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ endif()
add_offloadtest_library(API
Capabilities.cpp
Device.cpp
Texture.cpp
Util.cpp
${api_sources})

Expand Down
23 changes: 21 additions & 2 deletions lib/API/DX/DXResources.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ inline D3D12_HEAP_TYPE getDXHeapType(MemoryLocation Location) {
llvm_unreachable("All MemoryLocation cases handled");
}

inline DXGI_FORMAT getDXGIFormat(Format Format) {
switch (Format) {
inline DXGI_FORMAT getDXGIFormat(Format Fmt) {
switch (Fmt) {
case Format::R16Sint:
return DXGI_FORMAT_R16_SINT;
case Format::R16Uint:
Expand Down Expand Up @@ -65,6 +65,14 @@ inline DXGI_FORMAT getDXGIFormat(Format Format) {
return DXGI_FORMAT_R32G32B32A32_UINT;
case Format::RGBA32Float:
return DXGI_FORMAT_R32G32B32A32_FLOAT;
case Format::R64Uint:
return DXGI_FORMAT_R32G32_UINT;
case Format::R64Sint:
return DXGI_FORMAT_R32G32_SINT;
case Format::RG64Uint:
return DXGI_FORMAT_R32G32B32A32_UINT;
case Format::RG64Sint:
return DXGI_FORMAT_R32G32B32A32_SINT;
case Format::D32Float:
return DXGI_FORMAT_D32_FLOAT;
case Format::D32FloatS8Uint:
Expand All @@ -73,6 +81,17 @@ inline DXGI_FORMAT getDXGIFormat(Format Format) {
llvm_unreachable("All Format cases handled");
}

inline DXGI_FORMAT getDXGIFormatSRV(Format Fmt) {
switch (Fmt) {
case Format::D32Float:
return DXGI_FORMAT_R32_FLOAT;
case Format::D32FloatS8Uint:
return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
default:
return getDXGIFormat(Fmt);
}
}

inline D3D12_RESOURCE_FLAGS getDXResourceFlags(TextureUsage Usage) {
D3D12_RESOURCE_FLAGS Flags = D3D12_RESOURCE_FLAG_NONE;
if ((Usage & TextureUsage::Storage) != 0)
Expand Down
Loading
Loading