diff --git a/next.json b/next.json index bdb7351cd6..016e30ecf6 100644 --- a/next.json +++ b/next.json @@ -260,6 +260,19 @@ { "name": "end render pass" }, + { + "name": "copy buffer to buffer", + "args": [ + {"name": "source", "type": "buffer"}, + {"name": "source offset", "type": "uint32_t"}, + {"name": "destination", "type": "buffer"}, + {"name": "destination offset", "type": "uint32_t"}, + {"name": "size", "type": "uint32_t"} + ], + "TODO": [ + "Restrictions on the alignment of the copy? Cf Metal on OSX" + ] + }, { "name": "copy buffer to texture", "args": [ diff --git a/src/backend/common/CommandBuffer.cpp b/src/backend/common/CommandBuffer.cpp index 925f8bb330..c24a42a1b2 100644 --- a/src/backend/common/CommandBuffer.cpp +++ b/src/backend/common/CommandBuffer.cpp @@ -67,6 +67,12 @@ namespace backend { begin->~BeginRenderPassCmd(); } break; + case Command::CopyBufferToBuffer: + { + CopyBufferToBufferCmd* copy = commands->NextCommand(); + copy->~CopyBufferToBufferCmd(); + } + break; case Command::CopyBufferToTexture: { CopyBufferToTextureCmd* copy = commands->NextCommand(); @@ -201,6 +207,35 @@ namespace backend { } break; + case Command::CopyBufferToBuffer: + { + CopyBufferToBufferCmd* copy = iterator.NextCommand(); + BufferBase* source = copy->source.Get(); + BufferBase* destination = copy->destination.Get(); + uint32_t sourceOffset = copy->sourceOffset; + uint32_t destinationOffset = copy->destinationOffset; + uint32_t size = copy->size; + + uint64_t sourceEnd = uint64_t(sourceOffset) + uint64_t(size); + if (sourceEnd > uint64_t(source->GetSize())) { + HandleError("Copy would read after end of the source buffer"); + return false; + } + + uint64_t destinationEnd = uint64_t(destinationOffset) + uint64_t(size); + if (destinationEnd > uint64_t(destination->GetSize())) { + HandleError("Copy would read after end of the destination buffer"); + return false; + } + + if (!state->ValidateCanCopy() || + !state->ValidateCanUseBufferAs(source, nxt::BufferUsageBit::TransferSrc) || + !state->ValidateCanUseBufferAs(destination, nxt::BufferUsageBit::TransferDst)) { + return false; + } + } + break; + case Command::CopyBufferToTexture: { CopyBufferToTextureCmd* copy = iterator.NextCommand(); @@ -391,6 +426,16 @@ namespace backend { cmd->framebuffer = framebuffer; } + void CommandBufferBuilder::CopyBufferToBuffer(BufferBase* source, uint32_t sourceOffset, BufferBase* destination, uint32_t destinationOffset, uint32_t size) { + CopyBufferToBufferCmd* copy = allocator.Allocate(Command::CopyBufferToBuffer); + new(copy) CopyBufferToBufferCmd; + copy->source = source; + copy->sourceOffset = sourceOffset; + copy->destination = destination; + copy->destinationOffset = destinationOffset; + copy->size = size; + } + void CommandBufferBuilder::CopyBufferToTexture(BufferBase* buffer, uint32_t bufferOffset, TextureBase* texture, uint32_t x, uint32_t y, uint32_t z, uint32_t width, uint32_t height, uint32_t depth, uint32_t level) { diff --git a/src/backend/common/CommandBuffer.h b/src/backend/common/CommandBuffer.h index 485d1f3cd0..8c85ec37ac 100644 --- a/src/backend/common/CommandBuffer.h +++ b/src/backend/common/CommandBuffer.h @@ -61,6 +61,7 @@ namespace backend { // NXT API void AdvanceSubpass(); void BeginRenderPass(RenderPassBase* renderPass, FramebufferBase* framebuffer); + void CopyBufferToBuffer(BufferBase* source, uint32_t sourceOffset, BufferBase* destination, uint32_t destinationOffset, uint32_t size); void CopyBufferToTexture(BufferBase* buffer, uint32_t bufferOffset, TextureBase* texture, uint32_t x, uint32_t y, uint32_t z, uint32_t width, uint32_t height, uint32_t depth, uint32_t level); diff --git a/src/backend/common/Commands.h b/src/backend/common/Commands.h index cc3217b7f0..d1b1ecb736 100644 --- a/src/backend/common/Commands.h +++ b/src/backend/common/Commands.h @@ -30,6 +30,7 @@ namespace backend { enum class Command { AdvanceSubpass, BeginRenderPass, + CopyBufferToBuffer, CopyBufferToTexture, Dispatch, DrawArrays, @@ -53,6 +54,14 @@ namespace backend { Ref framebuffer; }; + struct CopyBufferToBufferCmd { + Ref source; + Ref destination; + uint32_t sourceOffset; + uint32_t destinationOffset; + uint32_t size; + }; + struct CopyBufferToTextureCmd { Ref buffer; uint32_t bufferOffset; diff --git a/src/backend/d3d12/CommandBufferD3D12.cpp b/src/backend/d3d12/CommandBufferD3D12.cpp index 417469708d..95306a6d09 100644 --- a/src/backend/d3d12/CommandBufferD3D12.cpp +++ b/src/backend/d3d12/CommandBufferD3D12.cpp @@ -61,6 +61,12 @@ namespace d3d12 { } break; + case Command::CopyBufferToBuffer: + { + CopyBufferToBufferCmd* copy = commands.NextCommand(); + } + break; + case Command::CopyBufferToTexture: { CopyBufferToTextureCmd* copy = commands.NextCommand(); diff --git a/src/backend/metal/MetalBackend.mm b/src/backend/metal/MetalBackend.mm index 317f1a9668..96069b4081 100644 --- a/src/backend/metal/MetalBackend.mm +++ b/src/backend/metal/MetalBackend.mm @@ -376,6 +376,20 @@ namespace metal { } break; + case Command::CopyBufferToBuffer: + { + CopyBufferToBufferCmd* copy = commands.NextCommand(); + + encoders.EnsureBlit(commandBuffer); + [encoders.blit + copyFromBuffer:ToBackend(copy->source)->GetMTLBuffer() + sourceOffset:copy->sourceOffset + toBuffer:ToBackend(copy->destination)->GetMTLBuffer() + destinationOffset:copy->destinationOffset + size:copy->size]; + } + break; + case Command::CopyBufferToTexture: { CopyBufferToTextureCmd* copy = commands.NextCommand(); diff --git a/src/backend/opengl/CommandBufferGL.cpp b/src/backend/opengl/CommandBufferGL.cpp index 876d616eaf..241afea93f 100644 --- a/src/backend/opengl/CommandBufferGL.cpp +++ b/src/backend/opengl/CommandBufferGL.cpp @@ -78,6 +78,19 @@ namespace opengl { } break; + case Command::CopyBufferToBuffer: + { + CopyBufferToBufferCmd* copy = commands.NextCommand(); + + glBindBuffer(GL_PIXEL_PACK_BUFFER, ToBackend(copy->source)->GetHandle()); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, ToBackend(copy->destination)->GetHandle()); + glCopyBufferSubData(GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER, copy->sourceOffset, copy->destinationOffset, copy->size); + + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + } + break; + case Command::CopyBufferToTexture: { CopyBufferToTextureCmd* copy = commands.NextCommand();