Introduce a new Buffer type with DX,VK,MTL implementations.#976
Introduce a new Buffer type with DX,VK,MTL implementations.#976manon-traverse wants to merge 8 commits intollvm:mainfrom
Conversation
include/API/Device.h
Outdated
|
|
||
| struct BufferCreateDesc { | ||
| MemoryLocation Location; | ||
| BufferUsage Usage; |
There was a problem hiding this comment.
I don't think I see this Usage flag used anywhere. Is the idea that buffer usage describes the buffer as CBV/UAV/SRV (in DX12 parlance)?
There was a problem hiding this comment.
The Usage tag will later be used to specify the type of buffer (Storage, AccelerationStructure, Constant, etc). I included it here so that the field should be filled in from the start. Perhaps we should apply a constructor on this type to enforce filling in all fields?
There was a problem hiding this comment.
FWIW, I think I'd hold off on adding fields / enums until we can include code demonstrating what they're for, so I'd recommend just removing the Usage field & enum until we have a need for it.
There was a problem hiding this comment.
Let's go with that, I have removed the field.
| }; | ||
|
|
||
| enum class MemoryLocation { | ||
| GpuOnly, |
There was a problem hiding this comment.
This may be confusing if later on you want to add CPU-visible memory which is still GPU local (ReBAR).
I wonder if the memory locations should just be GpuLocal or HostLocal and then the usage of Readback, Upload, ShaderMutable, or ShaderVisible then dictates the heap/memory-type in conjunction with "MemoryLocation"
There was a problem hiding this comment.
In our closed-source render framework, we use CpuToGpu to express that the resource has to be HOST visible and won't be read from. Whether that resource is actually in GPU Local ReBAR, some form of shared memory or on HOST. I am basically using that as a starting point as it has proven to have worked so far, but I am open for suggestion and changes.
That's why the terms GpuLocal and HostLocal may not fit as well, since it's a detail that the rendering backend should deal with and not necessarily the cross-platform rendering code.
There was a problem hiding this comment.
Sure, but the enum name here is MemoryLocation after all. I think hiding that as an implementation detail totally makes sense, but it may make sense for the type name to then indicate as such. Personally, if the goal is to expose strictly semantics to the user of this API, and the specific memory location is an implementation detail, I would probably opt to just expose the BufferUsage flag alone.
There was a problem hiding this comment.
Fortunately, we can change code in the future if we decide that the abstraction we've picked doesn't work out well. At this point I think that categorizing memory as GpuOnly, CpuToGpu and GpuToCpu is a reasonable categorization that works well across all the APIs. I do agree that the name MemoryLocation could be tightened up - MemoryType perhaps? I'm biased as I'm more familiar with D3D12_HEAP_TYPE that has 1:1 mappings with these values :)
There was a problem hiding this comment.
MemoryType doesn't match with Vulkan memory types, though. The name of this enum is not as important to me as long as I can quickly understand if it's CpuToGpu, GpuOnly, or GpuToCpu.
The reason for MemoryLocation was just purely based on it being called that in our in-house rendering framework.
There was a problem hiding this comment.
Ah, trying to pick good names is hard, trying to pick good names that don't conflict with names used by 3 graphics APIs is even harder :)
I don't think we should block this PR going in on getting the right name. I agree that the abstraction here is a good one, and I think we'll have to accept that the name picked here is somewhat arbitrary and the least-obviously-bad one.
| } | ||
|
|
||
| const D3D12_RESOURCE_FLAGS Flags = | ||
| D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; |
There was a problem hiding this comment.
These flags aren't yet used, but I'm assuming UAV access should be conditional depending on usage
There was a problem hiding this comment.
On Buffers UAV access is kind-of the default. There is no special swizzling or compression like on textures. There may be some exceptions when it comes to acceleration structures that according to the spec shouldn't be UAV. However, I would like to solve that problem once we reach that point.
There was a problem hiding this comment.
Yea that's definitely true (re: difference between buffers and textures), although the semantic difference for buffers is often still meaningful in most engines -- you wouldn't expect to create a UAV descriptor for a read-only buffer for example (unless you live in a BDA-only world)
There was a problem hiding this comment.
From my experience, having worked in various game engines, I have never seen an advantage to marking buffers as read/SRV-only at buffer creation time. Just binding it as read or write has been sufficient as that also guides barrier placement.
I would also like to point out what this flag is for. This flag is just purely there to tell the driver what kind of optimizations (swizzling/compression) it can apply on a resource. That's why resources with no flags passed disallow a lot of use cases. However, in the case of buffers (which use the same resource creation API) there are no optimziations to apply. So there is no point to not passing this flag in the rendering backend.
llvm-beanz
left a comment
There was a problem hiding this comment.
A couple comments. As a meta-comment, we do use clang-tidy to enforce consistent style and coding standards. That is run with -Werror in our bots, so some of the CI failures you're seeing as build failures are Clang-Tidy failures.
Our ReadMe documents setting up Clang-Tidy once you have it installed: https://github.com/llvm/offload-test-suite?tab=readme-ov-file#enabling-clang-tidy
| class DXBuffer : public offloadtest::Buffer { | ||
| public: | ||
| ComPtr<ID3D12Resource> Buffer; | ||
| std::string Name; |
There was a problem hiding this comment.
Should we put the Name and SizeInBytes in the base class? Seems like all the sub-classes have those fields.
There was a problem hiding this comment.
I am not sure! I am a big fan of using Pure Virtual Classes and only doing functionality inheritance without any data inheritance, much like traits in Rust. What is the LLVM approach to this?
Yes I saw something along the lines of that. I'll check it out! <3 I have some local changes to the README with steps and pointers that I found difficult to figure out to improve the onboarding in the future. |
1bd0067 to
7f99fc7
Compare
7f99fc7 to
b67a337
Compare
damyanp
left a comment
There was a problem hiding this comment.
LGTM, just a couple of observations.
| ComPtr<ID3D12Resource> Buffer; | ||
| std::string Name; | ||
| BufferCreateDesc Desc; | ||
| size_t SizeInBytes; |
There was a problem hiding this comment.
Did we turn off the clang-tidy rule about public data members?
| Queue &getGraphicsQueue() override { return GraphicsQueue; } | ||
|
|
||
| llvm::Expected<std::shared_ptr<offloadtest::Buffer>> | ||
| createBuffer(llvm::StringRef Name, BufferCreateDesc &Desc, |
There was a problem hiding this comment.
I don't think we actually have any code calling createBuffer() with this PR, which does make it hard for me to guess on usage here. But...it does slightly bother me that I think we've got a potentially unnecessary string copy going on here. Is createBuffer took a std::string value, then that'd let the caller decide whether or not they want to move a string to it or create a copy of another string to give to it. The current implementation only supports copying the string.
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
Bufferhas been renamed toCPUBuffer.