Skip to content

Commit 60b8173

Browse files
Introduce a new Buffer type with DX,VK,MTL implementations. (#976)
A first small step towards creating a Render Backend API layer on top of DX12, Vulkan, and Metal. This introduces a new Buffer type with an implementation for each API as well as a function on the Device class to create one. The change is smaller than it looks due to a naming conflict that needed to be resolved. The type previously called `Buffer` has been renamed to `CPUBuffer`.
1 parent 4aa5dfa commit 60b8173

8 files changed

Lines changed: 231 additions & 44 deletions

File tree

include/API/Device.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,27 @@ struct DeviceConfig {
3535
bool EnableValidationLayer = false;
3636
};
3737

38+
enum class MemoryLocation {
39+
GpuOnly,
40+
CpuToGpu,
41+
GpuToCpu,
42+
};
43+
44+
struct BufferCreateDesc {
45+
MemoryLocation Location;
46+
};
47+
48+
class Buffer {
49+
public:
50+
virtual ~Buffer() = default;
51+
52+
Buffer(const Buffer &) = delete;
53+
Buffer &operator=(const Buffer &) = delete;
54+
55+
protected:
56+
Buffer() = default;
57+
};
58+
3859
class Queue {
3960
public:
4061
virtual ~Queue() = 0;
@@ -56,6 +77,9 @@ class Device {
5677

5778
virtual Queue &getGraphicsQueue() = 0;
5879

80+
virtual llvm::Expected<std::shared_ptr<Buffer>>
81+
createBuffer(std::string Name, BufferCreateDesc &Desc,
82+
size_t SizeInBytes) = 0;
5983
virtual void printExtra(llvm::raw_ostream &OS) {}
6084

6185
virtual ~Device() = 0;

include/Image/Image.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class ImageRef {
8585
assert(Data.size() == size() && "Data size does not match properties");
8686
}
8787

88-
ImageRef(const Buffer &B)
88+
ImageRef(const CPUBuffer &B)
8989
: ImageRef(B.OutputProps.Height, B.OutputProps.Width,
9090
B.getSingleElementSize(), B.Channels,
9191
B.Format == DataFormat::Float32 ||

include/Support/Pipeline.h

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ static inline uint32_t getFormatSize(DataFormat Format) {
130130
llvm_unreachable("All cases covered.");
131131
}
132132

133-
struct Buffer {
133+
struct CPUBuffer {
134134
std::string Name;
135135
DataFormat Format;
136136
int Channels;
@@ -161,8 +161,8 @@ struct Result {
161161
Rule ComparisonRule;
162162
std::string Actual;
163163
std::string Expected;
164-
Buffer *ActualPtr = nullptr;
165-
Buffer *ExpectedPtr = nullptr;
164+
CPUBuffer *ActualPtr = nullptr;
165+
CPUBuffer *ExpectedPtr = nullptr;
166166
DenormMode DM = DenormMode::Any;
167167
unsigned ULPT; // ULP Tolerance
168168
double Epsilon;
@@ -173,7 +173,7 @@ struct Resource {
173173
std::string Name;
174174
DirectXBinding DXBinding;
175175
std::optional<VulkanBinding> VKBinding;
176-
Buffer *BufferPtr = nullptr;
176+
CPUBuffer *BufferPtr = nullptr;
177177
Sampler *SamplerPtr = nullptr;
178178
bool HasCounter;
179179
std::optional<uint32_t> TilesMapped;
@@ -306,7 +306,7 @@ enum class RootParamKind {
306306
struct RootResource : public Resource {};
307307

308308
struct RootConstant {
309-
Buffer *BufferPtr;
309+
CPUBuffer *BufferPtr;
310310
std::string Name;
311311
};
312312

@@ -335,11 +335,11 @@ struct VertexAttribute {
335335

336336
struct IOBindings {
337337
std::string VertexBuffer;
338-
Buffer *VertexBufferPtr;
338+
CPUBuffer *VertexBufferPtr;
339339
llvm::SmallVector<VertexAttribute> VertexAttributes;
340340

341341
std::string RenderTarget;
342-
Buffer *RTargetBufferPtr;
342+
CPUBuffer *RTargetBufferPtr;
343343

344344
uint32_t getVertexStride() const {
345345
uint32_t Stride = 0;
@@ -402,7 +402,7 @@ struct Pipeline {
402402

403403
IOBindings Bindings;
404404
llvm::SmallVector<PushConstantBlock> PushConstants;
405-
llvm::SmallVector<Buffer> Buffers;
405+
llvm::SmallVector<CPUBuffer> Buffers;
406406
llvm::SmallVector<Sampler> Samplers;
407407
llvm::SmallVector<Result> Results;
408408
llvm::SmallVector<DescriptorSet> Sets;
@@ -422,7 +422,7 @@ struct Pipeline {
422422
return DescriptorCount;
423423
}
424424

425-
Buffer *getBuffer(llvm::StringRef Name) {
425+
CPUBuffer *getBuffer(llvm::StringRef Name) {
426426
for (auto &B : Buffers)
427427
if (Name == B.Name)
428428
return &B;
@@ -446,7 +446,7 @@ struct Pipeline {
446446

447447
LLVM_YAML_IS_SEQUENCE_VECTOR(offloadtest::DescriptorSet)
448448
LLVM_YAML_IS_SEQUENCE_VECTOR(offloadtest::Resource)
449-
LLVM_YAML_IS_SEQUENCE_VECTOR(offloadtest::Buffer)
449+
LLVM_YAML_IS_SEQUENCE_VECTOR(offloadtest::CPUBuffer)
450450
LLVM_YAML_IS_SEQUENCE_VECTOR(offloadtest::Sampler)
451451
LLVM_YAML_IS_SEQUENCE_VECTOR(offloadtest::Shader)
452452
LLVM_YAML_IS_SEQUENCE_VECTOR(offloadtest::dx::RootParameter)
@@ -467,8 +467,8 @@ template <> struct MappingTraits<offloadtest::DescriptorSet> {
467467
static void mapping(IO &I, offloadtest::DescriptorSet &D);
468468
};
469469

470-
template <> struct MappingTraits<offloadtest::Buffer> {
471-
static void mapping(IO &I, offloadtest::Buffer &R);
470+
template <> struct MappingTraits<offloadtest::CPUBuffer> {
471+
static void mapping(IO &I, offloadtest::CPUBuffer &R);
472472
};
473473

474474
template <> struct MappingTraits<offloadtest::Sampler> {

lib/API/DX/Device.cpp

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ static DXResourceKind getDXKind(offloadtest::ResourceKind RK) {
169169
static llvm::Expected<D3D12_RESOURCE_DESC>
170170
getResourceDescription(const Resource &R) {
171171
const D3D12_RESOURCE_DIMENSION Dimension = getDXDimension(R.Kind);
172-
const offloadtest::Buffer &B = *R.BufferPtr;
172+
const offloadtest::CPUBuffer &B = *R.BufferPtr;
173173

174174
if (B.OutputProps.MipLevels != 1)
175175
return llvm::createStringError(std::errc::not_supported,
@@ -277,6 +277,18 @@ static D3D12_UNORDERED_ACCESS_VIEW_DESC getUAVDescription(const Resource &R) {
277277

278278
namespace {
279279

280+
class DXBuffer : public offloadtest::Buffer {
281+
public:
282+
ComPtr<ID3D12Resource> Buffer;
283+
std::string Name;
284+
BufferCreateDesc Desc;
285+
size_t SizeInBytes;
286+
287+
DXBuffer(ComPtr<ID3D12Resource> Buffer, llvm::StringRef Name,
288+
BufferCreateDesc Desc, size_t SizeInBytes)
289+
: Buffer(Buffer), Name(Name), Desc(Desc), SizeInBytes(SizeInBytes) {}
290+
};
291+
280292
class DXQueue : public offloadtest::Queue {
281293
public:
282294
ComPtr<ID3D12CommandQueue> Queue;
@@ -362,6 +374,41 @@ class DXDevice : public offloadtest::Device {
362374

363375
Queue &getGraphicsQueue() override { return GraphicsQueue; }
364376

377+
llvm::Expected<std::shared_ptr<offloadtest::Buffer>>
378+
createBuffer(std::string Name, BufferCreateDesc &Desc,
379+
size_t SizeInBytes) override {
380+
381+
D3D12_HEAP_TYPE HeapType = D3D12_HEAP_TYPE_DEFAULT;
382+
switch (Desc.Location) {
383+
case MemoryLocation::GpuOnly:
384+
HeapType = D3D12_HEAP_TYPE_DEFAULT;
385+
break;
386+
case MemoryLocation::CpuToGpu:
387+
HeapType = D3D12_HEAP_TYPE_UPLOAD;
388+
break;
389+
case MemoryLocation::GpuToCpu:
390+
HeapType = D3D12_HEAP_TYPE_READBACK;
391+
break;
392+
}
393+
394+
const D3D12_RESOURCE_FLAGS Flags =
395+
D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
396+
397+
const D3D12_HEAP_PROPERTIES HeapProps = CD3DX12_HEAP_PROPERTIES(HeapType);
398+
const D3D12_RESOURCE_DESC BufferDesc =
399+
CD3DX12_RESOURCE_DESC::Buffer(SizeInBytes, Flags);
400+
401+
ComPtr<ID3D12Resource> DeviceBuffer;
402+
if (auto Err = HR::toError(Device->CreateCommittedResource(
403+
&HeapProps, D3D12_HEAP_FLAG_NONE,
404+
&BufferDesc, D3D12_RESOURCE_STATE_COMMON,
405+
nullptr, IID_PPV_ARGS(&DeviceBuffer)),
406+
"Failed to create buffer."))
407+
return Err;
408+
409+
return std::make_shared<DXBuffer>(DeviceBuffer, Name, Desc, SizeInBytes);
410+
}
411+
365412
static llvm::Expected<DXDevice> create(ComPtr<IDXCoreAdapter> Adapter,
366413
const DeviceConfig &Config) {
367414
ComPtr<ID3D12Device> Device;
@@ -576,7 +623,7 @@ class DXDevice : public offloadtest::Device {
576623
ComPtr<ID3D12Resource> Source) {
577624
addUploadBeginBarrier(IS, Destination);
578625
if (R.isTexture()) {
579-
const offloadtest::Buffer &B = *R.BufferPtr;
626+
const offloadtest::CPUBuffer &B = *R.BufferPtr;
580627
const D3D12_PLACED_SUBRESOURCE_FOOTPRINT Footprint{
581628
0, CD3DX12_SUBRESOURCE_FOOTPRINT(
582629
getDXFormat(B.Format, B.Channels), B.OutputProps.Width,
@@ -1234,7 +1281,7 @@ class DXDevice : public offloadtest::Device {
12341281

12351282
auto CopyBackResource = [&IS, this](ResourcePair &R) {
12361283
if (R.first->isTexture()) {
1237-
const offloadtest::Buffer &B = *R.first->BufferPtr;
1284+
const offloadtest::CPUBuffer &B = *R.first->BufferPtr;
12381285
const D3D12_PLACED_SUBRESOURCE_FOOTPRINT Footprint{
12391286
0, CD3DX12_SUBRESOURCE_FOOTPRINT(
12401287
getDXFormat(B.Format, B.Channels), B.OutputProps.Width,
@@ -1316,7 +1363,7 @@ class DXDevice : public offloadtest::Device {
13161363
// Map readback and copy into host buffer, accounting for row pitch and
13171364
// flipping vertical orientation. DirectX render target origin is top-left,
13181365
// while our image writer expects bottom-left.
1319-
const Buffer &B = *P.Bindings.RTargetBufferPtr;
1366+
const CPUBuffer &B = *P.Bindings.RTargetBufferPtr;
13201367
void *Mapped = nullptr;
13211368
if (auto Err = HR::toError(IS.RTReadback->Map(0, nullptr, &Mapped),
13221369
"Failed to map render target readback"))
@@ -1358,7 +1405,7 @@ class DXDevice : public offloadtest::Device {
13581405
return llvm::createStringError(
13591406
std::errc::invalid_argument,
13601407
"No render target bound for graphics pipeline.");
1361-
const Buffer &OutBuf = *P.Bindings.RTargetBufferPtr;
1408+
const CPUBuffer &OutBuf = *P.Bindings.RTargetBufferPtr;
13621409
if (OutBuf.OutputProps.MipLevels != 1)
13631410
return llvm::createStringError(
13641411
std::errc::not_supported,
@@ -1412,7 +1459,7 @@ class DXDevice : public offloadtest::Device {
14121459
return llvm::createStringError(
14131460
std::errc::invalid_argument,
14141461
"No vertex buffer bound for graphics pipeline.");
1415-
const Buffer &VB = *P.Bindings.VertexBufferPtr;
1462+
const CPUBuffer &VB = *P.Bindings.VertexBufferPtr;
14161463
const uint64_t VBSize = VB.size();
14171464
D3D12_RESOURCE_DESC const Desc = CD3DX12_RESOURCE_DESC::Buffer(VBSize);
14181465
CD3DX12_HEAP_PROPERTIES HeapProps =
@@ -1549,7 +1596,7 @@ class DXDevice : public offloadtest::Device {
15491596
D3D12_RESOURCE_STATE_COPY_SOURCE);
15501597
IS.CmdList->ResourceBarrier(1, &Barrier);
15511598

1552-
const Buffer &B = *P.Bindings.RTargetBufferPtr;
1599+
const CPUBuffer &B = *P.Bindings.RTargetBufferPtr;
15531600
const D3D12_PLACED_SUBRESOURCE_FOOTPRINT Footprint{
15541601
0,
15551602
CD3DX12_SUBRESOURCE_FOOTPRINT(
@@ -1562,7 +1609,7 @@ class DXDevice : public offloadtest::Device {
15621609

15631610
auto CopyBackResource = [&IS, this](ResourcePair &R) {
15641611
if (R.first->isTexture()) {
1565-
const offloadtest::Buffer &B = *R.first->BufferPtr;
1612+
const offloadtest::CPUBuffer &B = *R.first->BufferPtr;
15661613
const D3D12_PLACED_SUBRESOURCE_FOOTPRINT Footprint{
15671614
0, CD3DX12_SUBRESOURCE_FOOTPRINT(
15681615
getDXFormat(B.Format, B.Channels), B.OutputProps.Width,

lib/API/MTL/MTLDevice.cpp

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,23 @@ class MTLQueue : public offloadtest::Queue {
8383
}
8484
};
8585

86+
class MTLBuffer : public offloadtest::Buffer {
87+
public:
88+
MTL::Buffer *Buf;
89+
std::string Name;
90+
BufferCreateDesc Desc;
91+
size_t SizeInBytes;
92+
93+
MTLBuffer(MTL::Buffer *Buf, llvm::StringRef Name, BufferCreateDesc Desc,
94+
size_t SizeInBytes)
95+
: Buf(Buf), Name(Name), Desc(Desc), SizeInBytes(SizeInBytes) {}
96+
97+
~MTLBuffer() override {
98+
if (Buf)
99+
Buf->release();
100+
}
101+
};
102+
86103
class MTLDevice : public offloadtest::Device {
87104
Capabilities Caps;
88105
MTL::Device *Device;
@@ -424,7 +441,7 @@ class MTLDevice : public offloadtest::Device {
424441
MTL::RenderPassDescriptor::alloc()->init();
425442

426443
// Setup the render target texture.
427-
Buffer *RTarget = P.Bindings.RTargetBufferPtr;
444+
CPUBuffer *RTarget = P.Bindings.RTargetBufferPtr;
428445

429446
const MTL::PixelFormat Format =
430447
getMTLFormat(RTarget->Format, RTarget->Channels);
@@ -510,7 +527,7 @@ class MTLDevice : public offloadtest::Device {
510527
}
511528
}
512529
if (P.isGraphics()) {
513-
Buffer *RTarget = P.Bindings.RTargetBufferPtr;
530+
CPUBuffer *RTarget = P.Bindings.RTargetBufferPtr;
514531
const uint64_t Width = RTarget->OutputProps.Width;
515532
const uint64_t Height = RTarget->OutputProps.Height;
516533
const size_t ElemSize = RTarget->getElementSize();
@@ -547,6 +564,27 @@ class MTLDevice : public offloadtest::Device {
547564

548565
Queue &getGraphicsQueue() override { return GraphicsQueue; }
549566

567+
llvm::Expected<std::shared_ptr<offloadtest::Buffer>>
568+
createBuffer(std::string Name, BufferCreateDesc &Desc,
569+
size_t SizeInBytes) override {
570+
MTL::ResourceOptions StorageMode;
571+
switch (Desc.Location) {
572+
case MemoryLocation::GpuOnly:
573+
StorageMode = MTL::ResourceStorageModePrivate;
574+
break;
575+
case MemoryLocation::CpuToGpu:
576+
case MemoryLocation::GpuToCpu:
577+
StorageMode = MTL::ResourceStorageModeManaged;
578+
break;
579+
}
580+
581+
MTL::Buffer *Buf = Device->newBuffer(SizeInBytes, StorageMode);
582+
if (!Buf)
583+
return llvm::createStringError(std::errc::not_enough_memory,
584+
"Failed to create Metal buffer.");
585+
return std::make_shared<MTLBuffer>(Buf, Name, Desc, SizeInBytes);
586+
}
587+
550588
llvm::Error executeProgram(Pipeline &P) override {
551589
InvocationState IS;
552590

0 commit comments

Comments
 (0)