diff --git a/include/API/Buffer.h b/include/API/Buffer.h index 18e6fac72..710b4eb1d 100644 --- a/include/API/Buffer.h +++ b/include/API/Buffer.h @@ -28,6 +28,10 @@ enum class BufferUsage { struct BufferCreateDesc { MemoryLocation Location; BufferUsage Usage; + + static BufferCreateDesc uploadBuffer() { + return BufferCreateDesc{MemoryLocation::CpuToGpu, BufferUsage::Storage}; + } }; class Buffer { diff --git a/include/API/Device.h b/include/API/Device.h index 050dab32d..20b6b5fc1 100644 --- a/include/API/Device.h +++ b/include/API/Device.h @@ -208,9 +208,11 @@ createRenderTargetFromCPUBuffer(Device &Dev, const CPUBuffer &Buf); llvm::Expected> createDefaultDepthStencilTarget(Device &Dev, uint32_t Width, uint32_t Height); -// Creates a vertex buffer and uploads the given CPU-side vertex data into it. -llvm::Expected> -createVertexBufferFromCPUBuffer(Device &Dev, const CPUBuffer &Buf); +llvm::Expected> +createBufferWithData(Device &Dev, std::string Name, + const BufferCreateDesc &Desc, const void *Data, + size_t SizeInBytes, ComputeEncoder *Encoder, + std::unique_ptr *OutUploadBuffer); } // namespace offloadtest diff --git a/lib/API/DX/Device.cpp b/lib/API/DX/Device.cpp index 24cfa7088..6b21c8399 100644 --- a/lib/API/DX/Device.cpp +++ b/lib/API/DX/Device.cpp @@ -1640,11 +1640,17 @@ class DXDevice : public offloadtest::Device { } if (P.isTraditionalRaster() && P.Bindings.VertexBufferPtr) { - auto VBOrErr = offloadtest::createVertexBufferFromCPUBuffer( - *this, *P.Bindings.VertexBufferPtr); - if (!VBOrErr) - return VBOrErr.takeError(); - IS.VB = std::move(*VBOrErr); + const CPUBuffer *VBuffer = P.Bindings.VertexBufferPtr; + + BufferCreateDesc BufDesc = {}; + BufDesc.Location = MemoryLocation::CpuToGpu; + BufDesc.Usage = BufferUsage::VertexBuffer; + auto BufOrErr = createBufferWithData(*this, "VertexBuffer", BufDesc, + VBuffer->Data[0].get(), + VBuffer->size(), nullptr, nullptr); + if (!BufOrErr) + return BufOrErr.takeError(); + IS.VB = std::move(*BufOrErr); llvm::outs() << "Vertex buffer created.\n"; } diff --git a/lib/API/Device.cpp b/lib/API/Device.cpp index 72d1867ab..0af5c1012 100644 --- a/lib/API/Device.cpp +++ b/lib/API/Device.cpp @@ -90,29 +90,6 @@ offloadtest::createRenderTargetFromCPUBuffer(Device &Dev, return Dev.createTexture("RenderTarget", Desc); } -llvm::Expected> -offloadtest::createVertexBufferFromCPUBuffer(Device &Dev, - const CPUBuffer &Buf) { - BufferCreateDesc BufDesc = {}; - BufDesc.Location = MemoryLocation::CpuToGpu; - BufDesc.Usage = BufferUsage::VertexBuffer; - auto BufOrErr = Dev.createBuffer("VertexBuffer", BufDesc, Buf.size()); - if (!BufOrErr) - return BufOrErr.takeError(); - auto VB = std::move(*BufOrErr); - - // TODO: Currently uses a single CpuToGpu mapped buffer. - // On discrete GPUs consider using a staging buffer + copy to a GpuOnly vertex - // buffer for optimal GPU read performance. - auto PtrOrErr = VB->map(); - if (!PtrOrErr) - return PtrOrErr.takeError(); - memcpy(*PtrOrErr, Buf.Data[0].get(), Buf.size()); - VB->unmap(); - - return VB; -} - llvm::Expected> offloadtest::createDefaultDepthStencilTarget(Device &Dev, uint32_t Width, uint32_t Height) { @@ -127,3 +104,70 @@ offloadtest::createDefaultDepthStencilTarget(Device &Dev, uint32_t Width, return Dev.createTexture("DepthStencil", Desc); } + +// This is a separate function because recursion is not allowed in this code +// base. +static llvm::Expected> +createUploadBufferWithData(Device &Dev, std::string Name, const void *Data, + size_t SizeInBytes) { + + // Create Upload buffer + const BufferCreateDesc UploadDesc = BufferCreateDesc::uploadBuffer(); + const std::string UploadBufferName = Name + " (Upload Buffer)"; + + auto UploadBufferOrErr = + Dev.createBuffer(UploadBufferName, UploadDesc, SizeInBytes); + if (!UploadBufferOrErr) + return UploadBufferOrErr.takeError(); + auto UploadBuffer = std::move(*UploadBufferOrErr); + + // Copy data over + auto MappedPtrOrErr = UploadBuffer->map(); + if (!MappedPtrOrErr) + return MappedPtrOrErr.takeError(); + void *MappedPtr = *MappedPtrOrErr; + memcpy(MappedPtr, Data, SizeInBytes); + UploadBuffer->unmap(); + + return std::move(UploadBuffer); +} + +llvm::Expected> +offloadtest::createBufferWithData( + Device &Dev, std::string Name, const BufferCreateDesc &Desc, + const void *Data, size_t SizeInBytes, ComputeEncoder *Encoder, + std::unique_ptr *OutUploadBuffer) { + auto BufferOrErr = Dev.createBuffer(Name, Desc, SizeInBytes); + if (!BufferOrErr) + return BufferOrErr.takeError(); + auto Buffer = std::move(*BufferOrErr); + + if (Desc.Location == MemoryLocation::GpuOnly) { + if (OutUploadBuffer == nullptr) + return llvm::createStringError( + "An upload buffer is required to create a GpuOnly buffer with data."); + + // Create Upload buffer + auto UploadBufferOrErr = + createUploadBufferWithData(Dev, Name, Data, SizeInBytes); + if (!UploadBufferOrErr) + return UploadBufferOrErr.takeError(); + *OutUploadBuffer = std::move(*UploadBufferOrErr); + + // Copy Buffer to Buffer + if (auto Err = Encoder->copyBufferToBuffer(**OutUploadBuffer, 0, *Buffer, 0, + SizeInBytes)) + return Err; + + } else { + // Copy data over + auto MappedPtrOrErr = Buffer->map(); + if (!MappedPtrOrErr) + return MappedPtrOrErr.takeError(); + void *MappedPtr = *MappedPtrOrErr; + memcpy(MappedPtr, Data, SizeInBytes); + Buffer->unmap(); + } + + return Buffer; +} diff --git a/lib/API/MTL/MTLDevice.cpp b/lib/API/MTL/MTLDevice.cpp index cfd81468f..621323314 100644 --- a/lib/API/MTL/MTLDevice.cpp +++ b/lib/API/MTL/MTLDevice.cpp @@ -956,11 +956,17 @@ class MTLDevice : public offloadtest::Device { } if (P.isTraditionalRaster() && P.Bindings.VertexBufferPtr) { - auto VBOrErr = offloadtest::createVertexBufferFromCPUBuffer( - *this, *P.Bindings.VertexBufferPtr); - if (!VBOrErr) - return VBOrErr.takeError(); - IS.VB = std::move(*VBOrErr); + const CPUBuffer *VBuffer = P.Bindings.VertexBufferPtr; + + BufferCreateDesc BufDesc = {}; + BufDesc.Location = MemoryLocation::CpuToGpu; + BufDesc.Usage = BufferUsage::VertexBuffer; + auto BufOrErr = createBufferWithData(*this, "VertexBuffer", BufDesc, + VBuffer->Data[0].get(), + VBuffer->size(), nullptr, nullptr); + if (!BufOrErr) + return BufOrErr.takeError(); + IS.VB = std::move(*BufOrErr); llvm::outs() << "Vertex buffer created.\n"; } return llvm::Error::success(); diff --git a/lib/API/VK/Device.cpp b/lib/API/VK/Device.cpp index 0f1ad5633..a2a4cebf6 100644 --- a/lib/API/VK/Device.cpp +++ b/lib/API/VK/Device.cpp @@ -1934,11 +1934,17 @@ class VulkanDevice : public offloadtest::Device { } if (P.isTraditionalRaster() && P.Bindings.VertexBufferPtr) { - auto VBOrErr = offloadtest::createVertexBufferFromCPUBuffer( - *this, *P.Bindings.VertexBufferPtr); - if (!VBOrErr) - return VBOrErr.takeError(); - IS.VB = std::move(*VBOrErr); + const CPUBuffer *VBuffer = P.Bindings.VertexBufferPtr; + + BufferCreateDesc BufDesc = {}; + BufDesc.Location = MemoryLocation::CpuToGpu; + BufDesc.Usage = BufferUsage::VertexBuffer; + auto BufOrErr = createBufferWithData(*this, "VertexBuffer", BufDesc, + VBuffer->Data[0].get(), + VBuffer->size(), nullptr, nullptr); + if (!BufOrErr) + return BufOrErr.takeError(); + IS.VB = std::move(*BufOrErr); llvm::outs() << "Vertex buffer created.\n"; }