mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-05-15 11:51:22 +00:00
Revert "Metal: Add CommandRecordingContext"
This reverts commit 2b3975f808fd6f5afc5a52e58a3dcd5e73984b17. Reason for revert: causes the failure in crbug.com/1041358 Original change's description: > Metal: Add CommandRecordingContext > > Introduces the idea of a CommandRecordingContext to the Metal backend, > similar to other backends. This is a class to track which Metal encoder > is open on the device-global pending MTLCommandBuffer. > It will be needed to open/close encoders for lazy clearing. > > Bug: dawn:145 > Change-Id: Ief6b71a079d73943677d2b61382d1c36b88a4f87 > Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/14780 > Reviewed-by: Corentin Wallez <cwallez@chromium.org> > Reviewed-by: Kai Ninomiya <kainino@chromium.org> > Commit-Queue: Austin Eng <enga@chromium.org> TBR=cwallez@chromium.org,kainino@chromium.org,enga@chromium.org # Not skipping CQ checks because original CL landed > 1 day ago. Bug: dawn:145 Bug: chromium:1041358 Change-Id: I05c76cd96f723230d05cff65127dc8513d5e03c5 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/15060 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
df2ae16e59
commit
15c442e941
2
BUILD.gn
2
BUILD.gn
@ -354,8 +354,6 @@ source_set("libdawn_native_sources") {
|
|||||||
"src/dawn_native/metal/BufferMTL.mm",
|
"src/dawn_native/metal/BufferMTL.mm",
|
||||||
"src/dawn_native/metal/CommandBufferMTL.h",
|
"src/dawn_native/metal/CommandBufferMTL.h",
|
||||||
"src/dawn_native/metal/CommandBufferMTL.mm",
|
"src/dawn_native/metal/CommandBufferMTL.mm",
|
||||||
"src/dawn_native/metal/CommandRecordingContext.h",
|
|
||||||
"src/dawn_native/metal/CommandRecordingContext.mm",
|
|
||||||
"src/dawn_native/metal/ComputePipelineMTL.h",
|
"src/dawn_native/metal/ComputePipelineMTL.h",
|
||||||
"src/dawn_native/metal/ComputePipelineMTL.mm",
|
"src/dawn_native/metal/ComputePipelineMTL.mm",
|
||||||
"src/dawn_native/metal/DeviceMTL.h",
|
"src/dawn_native/metal/DeviceMTL.h",
|
||||||
|
@ -26,24 +26,25 @@ namespace dawn_native {
|
|||||||
|
|
||||||
namespace dawn_native { namespace metal {
|
namespace dawn_native { namespace metal {
|
||||||
|
|
||||||
class CommandRecordingContext;
|
|
||||||
class Device;
|
class Device;
|
||||||
|
struct GlobalEncoders;
|
||||||
|
|
||||||
class CommandBuffer : public CommandBufferBase {
|
class CommandBuffer : public CommandBufferBase {
|
||||||
public:
|
public:
|
||||||
CommandBuffer(CommandEncoder* encoder, const CommandBufferDescriptor* descriptor);
|
CommandBuffer(CommandEncoder* encoder, const CommandBufferDescriptor* descriptor);
|
||||||
~CommandBuffer();
|
~CommandBuffer();
|
||||||
|
|
||||||
void FillCommands(CommandRecordingContext* commandContext);
|
void FillCommands(id<MTLCommandBuffer> commandBuffer);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void EncodeComputePass(CommandRecordingContext* commandContext);
|
void EncodeComputePass(id<MTLCommandBuffer> commandBuffer);
|
||||||
void EncodeRenderPass(CommandRecordingContext* commandContext,
|
void EncodeRenderPass(id<MTLCommandBuffer> commandBuffer,
|
||||||
MTLRenderPassDescriptor* mtlRenderPass,
|
MTLRenderPassDescriptor* mtlRenderPass,
|
||||||
|
GlobalEncoders* globalEncoders,
|
||||||
uint32_t width,
|
uint32_t width,
|
||||||
uint32_t height);
|
uint32_t height);
|
||||||
|
|
||||||
void EncodeRenderPassInternal(CommandRecordingContext* commandContext,
|
void EncodeRenderPassInternal(id<MTLCommandBuffer> commandBuffer,
|
||||||
MTLRenderPassDescriptor* mtlRenderPass,
|
MTLRenderPassDescriptor* mtlRenderPass,
|
||||||
uint32_t width,
|
uint32_t width,
|
||||||
uint32_t height);
|
uint32_t height);
|
||||||
|
@ -29,6 +29,23 @@
|
|||||||
|
|
||||||
namespace dawn_native { namespace metal {
|
namespace dawn_native { namespace metal {
|
||||||
|
|
||||||
|
struct GlobalEncoders {
|
||||||
|
id<MTLBlitCommandEncoder> blit = nil;
|
||||||
|
|
||||||
|
void Finish() {
|
||||||
|
if (blit != nil) {
|
||||||
|
[blit endEncoding];
|
||||||
|
blit = nil; // This will be autoreleased.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EnsureBlit(id<MTLCommandBuffer> commandBuffer) {
|
||||||
|
if (blit == nil) {
|
||||||
|
blit = [commandBuffer blitCommandEncoder];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Allows this file to use MTLStoreActionStoreAndMultismapleResolve because the logic is
|
// Allows this file to use MTLStoreActionStoreAndMultismapleResolve because the logic is
|
||||||
@ -116,7 +133,7 @@ namespace dawn_native { namespace metal {
|
|||||||
|
|
||||||
// Helper function for Toggle EmulateStoreAndMSAAResolve
|
// Helper function for Toggle EmulateStoreAndMSAAResolve
|
||||||
void ResolveInAnotherRenderPass(
|
void ResolveInAnotherRenderPass(
|
||||||
CommandRecordingContext* commandContext,
|
id<MTLCommandBuffer> commandBuffer,
|
||||||
const MTLRenderPassDescriptor* mtlRenderPass,
|
const MTLRenderPassDescriptor* mtlRenderPass,
|
||||||
const std::array<id<MTLTexture>, kMaxColorAttachments>& resolveTextures) {
|
const std::array<id<MTLTexture>, kMaxColorAttachments>& resolveTextures) {
|
||||||
MTLRenderPassDescriptor* mtlRenderPassForResolve =
|
MTLRenderPassDescriptor* mtlRenderPassForResolve =
|
||||||
@ -138,8 +155,9 @@ namespace dawn_native { namespace metal {
|
|||||||
mtlRenderPass.colorAttachments[i].resolveSlice;
|
mtlRenderPass.colorAttachments[i].resolveSlice;
|
||||||
}
|
}
|
||||||
|
|
||||||
commandContext->BeginRender(mtlRenderPassForResolve);
|
id<MTLRenderCommandEncoder> encoder =
|
||||||
commandContext->EndRender();
|
[commandBuffer renderCommandEncoderWithDescriptor:mtlRenderPassForResolve];
|
||||||
|
[encoder endEncoding];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper functions for Toggle AlwaysResolveIntoZeroLevelAndLayer
|
// Helper functions for Toggle AlwaysResolveIntoZeroLevelAndLayer
|
||||||
@ -164,14 +182,16 @@ namespace dawn_native { namespace metal {
|
|||||||
return resolveTexture;
|
return resolveTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CopyIntoTrueResolveTarget(CommandRecordingContext* commandContext,
|
void CopyIntoTrueResolveTarget(id<MTLCommandBuffer> commandBuffer,
|
||||||
id<MTLTexture> mtlTrueResolveTexture,
|
id<MTLTexture> mtlTrueResolveTexture,
|
||||||
uint32_t trueResolveLevel,
|
uint32_t trueResolveLevel,
|
||||||
uint32_t trueResolveSlice,
|
uint32_t trueResolveSlice,
|
||||||
id<MTLTexture> temporaryResolveTexture,
|
id<MTLTexture> temporaryResolveTexture,
|
||||||
uint32_t width,
|
uint32_t width,
|
||||||
uint32_t height) {
|
uint32_t height,
|
||||||
[commandContext->EnsureBlit() copyFromTexture:temporaryResolveTexture
|
GlobalEncoders* encoders) {
|
||||||
|
encoders->EnsureBlit(commandBuffer);
|
||||||
|
[encoders->blit copyFromTexture:temporaryResolveTexture
|
||||||
sourceSlice:0
|
sourceSlice:0
|
||||||
sourceLevel:0
|
sourceLevel:0
|
||||||
sourceOrigin:MTLOriginMake(0, 0, 0)
|
sourceOrigin:MTLOriginMake(0, 0, 0)
|
||||||
@ -588,29 +608,30 @@ namespace dawn_native { namespace metal {
|
|||||||
FreeCommands(&mCommands);
|
FreeCommands(&mCommands);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandBuffer::FillCommands(CommandRecordingContext* commandContext) {
|
void CommandBuffer::FillCommands(id<MTLCommandBuffer> commandBuffer) {
|
||||||
|
GlobalEncoders encoders;
|
||||||
|
|
||||||
Command type;
|
Command type;
|
||||||
while (mCommands.NextCommandId(&type)) {
|
while (mCommands.NextCommandId(&type)) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Command::BeginComputePass: {
|
case Command::BeginComputePass: {
|
||||||
mCommands.NextCommand<BeginComputePassCmd>();
|
mCommands.NextCommand<BeginComputePassCmd>();
|
||||||
|
encoders.Finish();
|
||||||
commandContext->EndBlit();
|
EncodeComputePass(commandBuffer);
|
||||||
EncodeComputePass(commandContext);
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Command::BeginRenderPass: {
|
case Command::BeginRenderPass: {
|
||||||
BeginRenderPassCmd* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
|
BeginRenderPassCmd* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
|
||||||
commandContext->EndBlit();
|
encoders.Finish();
|
||||||
MTLRenderPassDescriptor* descriptor = CreateMTLRenderPassDescriptor(cmd);
|
MTLRenderPassDescriptor* descriptor = CreateMTLRenderPassDescriptor(cmd);
|
||||||
EncodeRenderPass(commandContext, descriptor, cmd->width, cmd->height);
|
EncodeRenderPass(commandBuffer, descriptor, &encoders, cmd->width, cmd->height);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Command::CopyBufferToBuffer: {
|
case Command::CopyBufferToBuffer: {
|
||||||
CopyBufferToBufferCmd* copy = mCommands.NextCommand<CopyBufferToBufferCmd>();
|
CopyBufferToBufferCmd* copy = mCommands.NextCommand<CopyBufferToBufferCmd>();
|
||||||
|
|
||||||
[commandContext->EnsureBlit()
|
encoders.EnsureBlit(commandBuffer);
|
||||||
copyFromBuffer:ToBackend(copy->source)->GetMTLBuffer()
|
[encoders.blit copyFromBuffer:ToBackend(copy->source)->GetMTLBuffer()
|
||||||
sourceOffset:copy->sourceOffset
|
sourceOffset:copy->sourceOffset
|
||||||
toBuffer:ToBackend(copy->destination)->GetMTLBuffer()
|
toBuffer:ToBackend(copy->destination)->GetMTLBuffer()
|
||||||
destinationOffset:copy->destinationOffset
|
destinationOffset:copy->destinationOffset
|
||||||
@ -630,9 +651,10 @@ namespace dawn_native { namespace metal {
|
|||||||
dst.origin, copySize, texture->GetFormat(), virtualSizeAtLevel,
|
dst.origin, copySize, texture->GetFormat(), virtualSizeAtLevel,
|
||||||
buffer->GetSize(), src.offset, src.rowPitch, src.imageHeight);
|
buffer->GetSize(), src.offset, src.rowPitch, src.imageHeight);
|
||||||
|
|
||||||
|
encoders.EnsureBlit(commandBuffer);
|
||||||
for (uint32_t i = 0; i < splittedCopies.count; ++i) {
|
for (uint32_t i = 0; i < splittedCopies.count; ++i) {
|
||||||
const TextureBufferCopySplit::CopyInfo& copyInfo = splittedCopies.copies[i];
|
const TextureBufferCopySplit::CopyInfo& copyInfo = splittedCopies.copies[i];
|
||||||
[commandContext->EnsureBlit() copyFromBuffer:buffer->GetMTLBuffer()
|
[encoders.blit copyFromBuffer:buffer->GetMTLBuffer()
|
||||||
sourceOffset:copyInfo.bufferOffset
|
sourceOffset:copyInfo.bufferOffset
|
||||||
sourceBytesPerRow:copyInfo.bytesPerRow
|
sourceBytesPerRow:copyInfo.bytesPerRow
|
||||||
sourceBytesPerImage:copyInfo.bytesPerImage
|
sourceBytesPerImage:copyInfo.bytesPerImage
|
||||||
@ -657,9 +679,10 @@ namespace dawn_native { namespace metal {
|
|||||||
src.origin, copySize, texture->GetFormat(), virtualSizeAtLevel,
|
src.origin, copySize, texture->GetFormat(), virtualSizeAtLevel,
|
||||||
buffer->GetSize(), dst.offset, dst.rowPitch, dst.imageHeight);
|
buffer->GetSize(), dst.offset, dst.rowPitch, dst.imageHeight);
|
||||||
|
|
||||||
|
encoders.EnsureBlit(commandBuffer);
|
||||||
for (uint32_t i = 0; i < splittedCopies.count; ++i) {
|
for (uint32_t i = 0; i < splittedCopies.count; ++i) {
|
||||||
const TextureBufferCopySplit::CopyInfo& copyInfo = splittedCopies.copies[i];
|
const TextureBufferCopySplit::CopyInfo& copyInfo = splittedCopies.copies[i];
|
||||||
[commandContext->EnsureBlit() copyFromTexture:texture->GetMTLTexture()
|
[encoders.blit copyFromTexture:texture->GetMTLTexture()
|
||||||
sourceSlice:src.arrayLayer
|
sourceSlice:src.arrayLayer
|
||||||
sourceLevel:src.mipLevel
|
sourceLevel:src.mipLevel
|
||||||
sourceOrigin:copyInfo.textureOrigin
|
sourceOrigin:copyInfo.textureOrigin
|
||||||
@ -677,8 +700,9 @@ namespace dawn_native { namespace metal {
|
|||||||
Texture* srcTexture = ToBackend(copy->source.texture.Get());
|
Texture* srcTexture = ToBackend(copy->source.texture.Get());
|
||||||
Texture* dstTexture = ToBackend(copy->destination.texture.Get());
|
Texture* dstTexture = ToBackend(copy->destination.texture.Get());
|
||||||
|
|
||||||
[commandContext->EnsureBlit()
|
encoders.EnsureBlit(commandBuffer);
|
||||||
copyFromTexture:srcTexture->GetMTLTexture()
|
|
||||||
|
[encoders.blit copyFromTexture:srcTexture->GetMTLTexture()
|
||||||
sourceSlice:copy->source.arrayLayer
|
sourceSlice:copy->source.arrayLayer
|
||||||
sourceLevel:copy->source.mipLevel
|
sourceLevel:copy->source.mipLevel
|
||||||
sourceOrigin:MakeMTLOrigin(copy->source.origin)
|
sourceOrigin:MakeMTLOrigin(copy->source.origin)
|
||||||
@ -693,22 +717,23 @@ namespace dawn_native { namespace metal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
commandContext->EndBlit();
|
encoders.Finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandBuffer::EncodeComputePass(CommandRecordingContext* commandContext) {
|
void CommandBuffer::EncodeComputePass(id<MTLCommandBuffer> commandBuffer) {
|
||||||
ComputePipeline* lastPipeline = nullptr;
|
ComputePipeline* lastPipeline = nullptr;
|
||||||
StorageBufferLengthTracker storageBufferLengths = {};
|
StorageBufferLengthTracker storageBufferLengths = {};
|
||||||
BindGroupTracker bindGroups(&storageBufferLengths);
|
BindGroupTracker bindGroups(&storageBufferLengths);
|
||||||
|
|
||||||
id<MTLComputeCommandEncoder> encoder = commandContext->BeginCompute();
|
// Will be autoreleased
|
||||||
|
id<MTLComputeCommandEncoder> encoder = [commandBuffer computeCommandEncoder];
|
||||||
|
|
||||||
Command type;
|
Command type;
|
||||||
while (mCommands.NextCommandId(&type)) {
|
while (mCommands.NextCommandId(&type)) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Command::EndComputePass: {
|
case Command::EndComputePass: {
|
||||||
mCommands.NextCommand<EndComputePassCmd>();
|
mCommands.NextCommand<EndComputePassCmd>();
|
||||||
commandContext->EndCompute();
|
[encoder endEncoding];
|
||||||
return;
|
return;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@ -788,11 +813,12 @@ namespace dawn_native { namespace metal {
|
|||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandBuffer::EncodeRenderPass(CommandRecordingContext* commandContext,
|
void CommandBuffer::EncodeRenderPass(id<MTLCommandBuffer> commandBuffer,
|
||||||
MTLRenderPassDescriptor* mtlRenderPass,
|
MTLRenderPassDescriptor* mtlRenderPass,
|
||||||
|
GlobalEncoders* globalEncoders,
|
||||||
uint32_t width,
|
uint32_t width,
|
||||||
uint32_t height) {
|
uint32_t height) {
|
||||||
ASSERT(mtlRenderPass);
|
ASSERT(mtlRenderPass && globalEncoders);
|
||||||
|
|
||||||
Device* device = ToBackend(GetDevice());
|
Device* device = ToBackend(GetDevice());
|
||||||
|
|
||||||
@ -835,16 +861,17 @@ namespace dawn_native { namespace metal {
|
|||||||
// If we need to use a temporary resolve texture we need to copy the result of MSAA
|
// If we need to use a temporary resolve texture we need to copy the result of MSAA
|
||||||
// resolve back to the true resolve targets.
|
// resolve back to the true resolve targets.
|
||||||
if (useTemporaryResolveTexture) {
|
if (useTemporaryResolveTexture) {
|
||||||
EncodeRenderPass(commandContext, mtlRenderPass, width, height);
|
EncodeRenderPass(commandBuffer, mtlRenderPass, globalEncoders, width, height);
|
||||||
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
|
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
|
||||||
if (trueResolveTextures[i] == nil) {
|
if (trueResolveTextures[i] == nil) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(temporaryResolveTextures[i] != nil);
|
ASSERT(temporaryResolveTextures[i] != nil);
|
||||||
CopyIntoTrueResolveTarget(commandContext, trueResolveTextures[i],
|
CopyIntoTrueResolveTarget(commandBuffer, trueResolveTextures[i],
|
||||||
trueResolveLevels[i], trueResolveSlices[i],
|
trueResolveLevels[i], trueResolveSlices[i],
|
||||||
temporaryResolveTextures[i], width, height);
|
temporaryResolveTextures[i], width, height,
|
||||||
|
globalEncoders);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -869,16 +896,16 @@ namespace dawn_native { namespace metal {
|
|||||||
|
|
||||||
// If we found a store + MSAA resolve we need to resolve in a different render pass.
|
// If we found a store + MSAA resolve we need to resolve in a different render pass.
|
||||||
if (hasStoreAndMSAAResolve) {
|
if (hasStoreAndMSAAResolve) {
|
||||||
EncodeRenderPass(commandContext, mtlRenderPass, width, height);
|
EncodeRenderPass(commandBuffer, mtlRenderPass, globalEncoders, width, height);
|
||||||
ResolveInAnotherRenderPass(commandContext, mtlRenderPass, resolveTextures);
|
ResolveInAnotherRenderPass(commandBuffer, mtlRenderPass, resolveTextures);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EncodeRenderPassInternal(commandContext, mtlRenderPass, width, height);
|
EncodeRenderPassInternal(commandBuffer, mtlRenderPass, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandBuffer::EncodeRenderPassInternal(CommandRecordingContext* commandContext,
|
void CommandBuffer::EncodeRenderPassInternal(id<MTLCommandBuffer> commandBuffer,
|
||||||
MTLRenderPassDescriptor* mtlRenderPass,
|
MTLRenderPassDescriptor* mtlRenderPass,
|
||||||
uint32_t width,
|
uint32_t width,
|
||||||
uint32_t height) {
|
uint32_t height) {
|
||||||
@ -889,7 +916,9 @@ namespace dawn_native { namespace metal {
|
|||||||
StorageBufferLengthTracker storageBufferLengths = {};
|
StorageBufferLengthTracker storageBufferLengths = {};
|
||||||
BindGroupTracker bindGroups(&storageBufferLengths);
|
BindGroupTracker bindGroups(&storageBufferLengths);
|
||||||
|
|
||||||
id<MTLRenderCommandEncoder> encoder = commandContext->BeginRender(mtlRenderPass);
|
// This will be autoreleased
|
||||||
|
id<MTLRenderCommandEncoder> encoder =
|
||||||
|
[commandBuffer renderCommandEncoderWithDescriptor:mtlRenderPass];
|
||||||
|
|
||||||
auto EncodeRenderBundleCommand = [&](CommandIterator* iter, Command type) {
|
auto EncodeRenderBundleCommand = [&](CommandIterator* iter, Command type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -1039,7 +1068,7 @@ namespace dawn_native { namespace metal {
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case Command::EndRenderPass: {
|
case Command::EndRenderPass: {
|
||||||
mCommands.NextCommand<EndRenderPassCmd>();
|
mCommands.NextCommand<EndRenderPassCmd>();
|
||||||
commandContext->EndRender();
|
[encoder endEncoding];
|
||||||
return;
|
return;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -1,59 +0,0 @@
|
|||||||
// Copyright 2020 The Dawn Authors
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
#ifndef DAWNNATIVE_METAL_COMMANDRECORDINGCONTEXT_H_
|
|
||||||
#define DAWNNATIVE_METAL_COMMANDRECORDINGCONTEXT_H_
|
|
||||||
|
|
||||||
#import <Metal/Metal.h>
|
|
||||||
|
|
||||||
namespace dawn_native { namespace metal {
|
|
||||||
|
|
||||||
// This class wraps a MTLCommandBuffer and tracks which Metal encoder is open.
|
|
||||||
// Only one encoder may be open at a time.
|
|
||||||
class CommandRecordingContext {
|
|
||||||
public:
|
|
||||||
CommandRecordingContext();
|
|
||||||
CommandRecordingContext(id<MTLCommandBuffer> commands);
|
|
||||||
|
|
||||||
CommandRecordingContext(const CommandRecordingContext& rhs) = delete;
|
|
||||||
CommandRecordingContext& operator=(const CommandRecordingContext& rhs) = delete;
|
|
||||||
|
|
||||||
CommandRecordingContext(CommandRecordingContext&& rhs);
|
|
||||||
CommandRecordingContext& operator=(CommandRecordingContext&& rhs);
|
|
||||||
|
|
||||||
~CommandRecordingContext();
|
|
||||||
|
|
||||||
id<MTLCommandBuffer> GetCommands();
|
|
||||||
|
|
||||||
id<MTLCommandBuffer> AcquireCommands();
|
|
||||||
|
|
||||||
id<MTLBlitCommandEncoder> EnsureBlit();
|
|
||||||
void EndBlit();
|
|
||||||
|
|
||||||
id<MTLComputeCommandEncoder> BeginCompute();
|
|
||||||
void EndCompute();
|
|
||||||
|
|
||||||
id<MTLRenderCommandEncoder> BeginRender(MTLRenderPassDescriptor* descriptor);
|
|
||||||
void EndRender();
|
|
||||||
|
|
||||||
private:
|
|
||||||
id<MTLCommandBuffer> mCommands = nil;
|
|
||||||
id<MTLBlitCommandEncoder> mBlit = nil;
|
|
||||||
id<MTLComputeCommandEncoder> mCompute = nil;
|
|
||||||
id<MTLRenderCommandEncoder> mRender = nil;
|
|
||||||
bool mInEncoder = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
}} // namespace dawn_native::metal
|
|
||||||
|
|
||||||
#endif // DAWNNATIVE_METAL_COMMANDRECORDINGCONTEXT_H_
|
|
@ -1,113 +0,0 @@
|
|||||||
// Copyright 2020 The Dawn Authors
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
#include "dawn_native/metal/CommandRecordingContext.h"
|
|
||||||
|
|
||||||
#include "common/Assert.h"
|
|
||||||
|
|
||||||
namespace dawn_native { namespace metal {
|
|
||||||
|
|
||||||
CommandRecordingContext::CommandRecordingContext() = default;
|
|
||||||
|
|
||||||
CommandRecordingContext::CommandRecordingContext(id<MTLCommandBuffer> commands)
|
|
||||||
: mCommands(commands) {
|
|
||||||
}
|
|
||||||
|
|
||||||
CommandRecordingContext::CommandRecordingContext(CommandRecordingContext&& rhs)
|
|
||||||
: mCommands(rhs.AcquireCommands()) {
|
|
||||||
}
|
|
||||||
|
|
||||||
CommandRecordingContext& CommandRecordingContext::operator=(CommandRecordingContext&& rhs) {
|
|
||||||
mCommands = rhs.AcquireCommands();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
CommandRecordingContext::~CommandRecordingContext() {
|
|
||||||
// Commands must be acquired.
|
|
||||||
ASSERT(mCommands == nil);
|
|
||||||
}
|
|
||||||
|
|
||||||
id<MTLCommandBuffer> CommandRecordingContext::GetCommands() {
|
|
||||||
return mCommands;
|
|
||||||
}
|
|
||||||
|
|
||||||
id<MTLCommandBuffer> CommandRecordingContext::AcquireCommands() {
|
|
||||||
ASSERT(!mInEncoder);
|
|
||||||
|
|
||||||
id<MTLCommandBuffer> commands = mCommands;
|
|
||||||
mCommands = nil;
|
|
||||||
return commands;
|
|
||||||
}
|
|
||||||
|
|
||||||
id<MTLBlitCommandEncoder> CommandRecordingContext::EnsureBlit() {
|
|
||||||
ASSERT(mCommands != nil);
|
|
||||||
|
|
||||||
if (mBlit == nil) {
|
|
||||||
ASSERT(!mInEncoder);
|
|
||||||
mInEncoder = true;
|
|
||||||
mBlit = [mCommands blitCommandEncoder];
|
|
||||||
}
|
|
||||||
return mBlit;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommandRecordingContext::EndBlit() {
|
|
||||||
ASSERT(mCommands != nil);
|
|
||||||
|
|
||||||
if (mBlit != nil) {
|
|
||||||
[mBlit endEncoding];
|
|
||||||
mBlit = nil; // This will be autoreleased.
|
|
||||||
mInEncoder = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
id<MTLComputeCommandEncoder> CommandRecordingContext::BeginCompute() {
|
|
||||||
ASSERT(mCommands != nil);
|
|
||||||
ASSERT(mCompute == nil);
|
|
||||||
ASSERT(!mInEncoder);
|
|
||||||
|
|
||||||
mInEncoder = true;
|
|
||||||
mCompute = [mCommands computeCommandEncoder];
|
|
||||||
return mCompute;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommandRecordingContext::EndCompute() {
|
|
||||||
ASSERT(mCommands != nil);
|
|
||||||
ASSERT(mCompute != nil);
|
|
||||||
|
|
||||||
[mCompute endEncoding];
|
|
||||||
mCompute = nil; // This will be autoreleased.
|
|
||||||
mInEncoder = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
id<MTLRenderCommandEncoder> CommandRecordingContext::BeginRender(
|
|
||||||
MTLRenderPassDescriptor* descriptor) {
|
|
||||||
ASSERT(mCommands != nil);
|
|
||||||
ASSERT(mRender == nil);
|
|
||||||
ASSERT(!mInEncoder);
|
|
||||||
|
|
||||||
mInEncoder = true;
|
|
||||||
mRender = [mCommands renderCommandEncoderWithDescriptor:descriptor];
|
|
||||||
return mRender;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CommandRecordingContext::EndRender() {
|
|
||||||
ASSERT(mCommands != nil);
|
|
||||||
ASSERT(mRender != nil);
|
|
||||||
|
|
||||||
[mRender endEncoding];
|
|
||||||
mRender = nil; // This will be autoreleased.
|
|
||||||
mInEncoder = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}} // namespace dawn_native::metal
|
|
@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include "common/Serial.h"
|
#include "common/Serial.h"
|
||||||
#include "dawn_native/Device.h"
|
#include "dawn_native/Device.h"
|
||||||
#include "dawn_native/metal/CommandRecordingContext.h"
|
|
||||||
#include "dawn_native/metal/Forward.h"
|
#include "dawn_native/metal/Forward.h"
|
||||||
|
|
||||||
#import <IOSurface/IOSurfaceRef.h>
|
#import <IOSurface/IOSurfaceRef.h>
|
||||||
@ -49,7 +48,7 @@ namespace dawn_native { namespace metal {
|
|||||||
id<MTLDevice> GetMTLDevice();
|
id<MTLDevice> GetMTLDevice();
|
||||||
id<MTLCommandQueue> GetMTLQueue();
|
id<MTLCommandQueue> GetMTLQueue();
|
||||||
|
|
||||||
CommandRecordingContext* GetPendingCommandContext();
|
id<MTLCommandBuffer> GetPendingCommandBuffer();
|
||||||
Serial GetPendingCommandSerial() const override;
|
Serial GetPendingCommandSerial() const override;
|
||||||
void SubmitPendingCommandBuffer();
|
void SubmitPendingCommandBuffer();
|
||||||
|
|
||||||
@ -99,7 +98,7 @@ namespace dawn_native { namespace metal {
|
|||||||
std::unique_ptr<MapRequestTracker> mMapTracker;
|
std::unique_ptr<MapRequestTracker> mMapTracker;
|
||||||
|
|
||||||
Serial mLastSubmittedSerial = 0;
|
Serial mLastSubmittedSerial = 0;
|
||||||
CommandRecordingContext mCommandContext;
|
id<MTLCommandBuffer> mPendingCommands = nil;
|
||||||
|
|
||||||
// The completed serial is updated in a Metal completion handler that can be fired on a
|
// The completed serial is updated in a Metal completion handler that can be fired on a
|
||||||
// different thread, so it needs to be atomic.
|
// different thread, so it needs to be atomic.
|
||||||
|
@ -144,7 +144,7 @@ namespace dawn_native { namespace metal {
|
|||||||
mDynamicUploader->Deallocate(completedSerial);
|
mDynamicUploader->Deallocate(completedSerial);
|
||||||
mMapTracker->Tick(completedSerial);
|
mMapTracker->Tick(completedSerial);
|
||||||
|
|
||||||
if (mCommandContext.GetCommands() != nil) {
|
if (mPendingCommands != nil) {
|
||||||
SubmitPendingCommandBuffer();
|
SubmitPendingCommandBuffer();
|
||||||
} else if (completedSerial == mLastSubmittedSerial) {
|
} else if (completedSerial == mLastSubmittedSerial) {
|
||||||
// If there's no GPU work in flight we still need to artificially increment the serial
|
// If there's no GPU work in flight we still need to artificially increment the serial
|
||||||
@ -164,43 +164,45 @@ namespace dawn_native { namespace metal {
|
|||||||
return mCommandQueue;
|
return mCommandQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandRecordingContext* Device::GetPendingCommandContext() {
|
id<MTLCommandBuffer> Device::GetPendingCommandBuffer() {
|
||||||
if (mCommandContext.GetCommands() == nil) {
|
TRACE_EVENT0(GetPlatform(), General, "DeviceMTL::GetPendingCommandBuffer");
|
||||||
TRACE_EVENT0(GetPlatform(), General, "[MTLCommandQueue commandBuffer]");
|
if (mPendingCommands == nil) {
|
||||||
mCommandContext = CommandRecordingContext([mCommandQueue commandBuffer]);
|
mPendingCommands = [mCommandQueue commandBuffer];
|
||||||
|
[mPendingCommands retain];
|
||||||
}
|
}
|
||||||
return &mCommandContext;
|
return mPendingCommands;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::SubmitPendingCommandBuffer() {
|
void Device::SubmitPendingCommandBuffer() {
|
||||||
if (mCommandContext.GetCommands() == nil) {
|
if (mPendingCommands == nil) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mLastSubmittedSerial++;
|
mLastSubmittedSerial++;
|
||||||
|
|
||||||
// Ensure the blit encoder is ended. It may have been opened to perform a lazy clear or
|
|
||||||
// buffer upload.
|
|
||||||
mCommandContext.EndBlit();
|
|
||||||
|
|
||||||
// Acquire and retain the pending commands. We must keep them alive until scheduled.
|
|
||||||
id<MTLCommandBuffer> pendingCommands = [mCommandContext.AcquireCommands() retain];
|
|
||||||
|
|
||||||
// Replace mLastSubmittedCommands with the mutex held so we avoid races between the
|
// Replace mLastSubmittedCommands with the mutex held so we avoid races between the
|
||||||
// schedule handler and this code.
|
// schedule handler and this code.
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mLastSubmittedCommandsMutex);
|
std::lock_guard<std::mutex> lock(mLastSubmittedCommandsMutex);
|
||||||
[mLastSubmittedCommands release];
|
[mLastSubmittedCommands release];
|
||||||
mLastSubmittedCommands = pendingCommands;
|
mLastSubmittedCommands = mPendingCommands;
|
||||||
}
|
}
|
||||||
|
|
||||||
[pendingCommands addScheduledHandler:^(id<MTLCommandBuffer>) {
|
// Ok, ObjC blocks are weird. My understanding is that local variables are captured by
|
||||||
|
// value so this-> works as expected. However it is unclear how members are captured, (are
|
||||||
|
// they captured using this-> or by value?). To be safe we copy members to local variables
|
||||||
|
// to ensure they are captured "by value".
|
||||||
|
|
||||||
|
// Free mLastSubmittedCommands as soon as it is scheduled so that it doesn't hold
|
||||||
|
// references to its resources. Make a local copy of pendingCommands first so it is
|
||||||
|
// captured "by-value" by the block.
|
||||||
|
id<MTLCommandBuffer> pendingCommands = mPendingCommands;
|
||||||
|
|
||||||
|
[mPendingCommands addScheduledHandler:^(id<MTLCommandBuffer>) {
|
||||||
// This is DRF because we hold the mutex for mLastSubmittedCommands and pendingCommands
|
// This is DRF because we hold the mutex for mLastSubmittedCommands and pendingCommands
|
||||||
// is a local value (and not the member itself).
|
// is a local value (and not the member itself).
|
||||||
std::lock_guard<std::mutex> lock(mLastSubmittedCommandsMutex);
|
std::lock_guard<std::mutex> lock(mLastSubmittedCommandsMutex);
|
||||||
if (this->mLastSubmittedCommands == pendingCommands) {
|
if (this->mLastSubmittedCommands == pendingCommands) {
|
||||||
// Free mLastSubmittedCommands as soon as it is scheduled so that it doesn't hold
|
|
||||||
// references to its resources.
|
|
||||||
[this->mLastSubmittedCommands release];
|
[this->mLastSubmittedCommands release];
|
||||||
this->mLastSubmittedCommands = nil;
|
this->mLastSubmittedCommands = nil;
|
||||||
}
|
}
|
||||||
@ -209,7 +211,7 @@ namespace dawn_native { namespace metal {
|
|||||||
// Update the completed serial once the completed handler is fired. Make a local copy of
|
// Update the completed serial once the completed handler is fired. Make a local copy of
|
||||||
// mLastSubmittedSerial so it is captured by value.
|
// mLastSubmittedSerial so it is captured by value.
|
||||||
Serial pendingSerial = mLastSubmittedSerial;
|
Serial pendingSerial = mLastSubmittedSerial;
|
||||||
[pendingCommands addCompletedHandler:^(id<MTLCommandBuffer>) {
|
[mPendingCommands addCompletedHandler:^(id<MTLCommandBuffer>) {
|
||||||
TRACE_EVENT_ASYNC_END0(GetPlatform(), GPUWork, "DeviceMTL::SubmitPendingCommandBuffer",
|
TRACE_EVENT_ASYNC_END0(GetPlatform(), GPUWork, "DeviceMTL::SubmitPendingCommandBuffer",
|
||||||
pendingSerial);
|
pendingSerial);
|
||||||
ASSERT(pendingSerial > mCompletedSerial.load());
|
ASSERT(pendingSerial > mCompletedSerial.load());
|
||||||
@ -218,7 +220,8 @@ namespace dawn_native { namespace metal {
|
|||||||
|
|
||||||
TRACE_EVENT_ASYNC_BEGIN0(GetPlatform(), GPUWork, "DeviceMTL::SubmitPendingCommandBuffer",
|
TRACE_EVENT_ASYNC_BEGIN0(GetPlatform(), GPUWork, "DeviceMTL::SubmitPendingCommandBuffer",
|
||||||
pendingSerial);
|
pendingSerial);
|
||||||
[pendingCommands commit];
|
[mPendingCommands commit];
|
||||||
|
mPendingCommands = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
MapRequestTracker* Device::GetMapTracker() const {
|
MapRequestTracker* Device::GetMapTracker() const {
|
||||||
@ -239,11 +242,15 @@ namespace dawn_native { namespace metal {
|
|||||||
uint64_t size) {
|
uint64_t size) {
|
||||||
id<MTLBuffer> uploadBuffer = ToBackend(source)->GetBufferHandle();
|
id<MTLBuffer> uploadBuffer = ToBackend(source)->GetBufferHandle();
|
||||||
id<MTLBuffer> buffer = ToBackend(destination)->GetMTLBuffer();
|
id<MTLBuffer> buffer = ToBackend(destination)->GetMTLBuffer();
|
||||||
[GetPendingCommandContext()->EnsureBlit() copyFromBuffer:uploadBuffer
|
id<MTLCommandBuffer> commandBuffer = GetPendingCommandBuffer();
|
||||||
|
id<MTLBlitCommandEncoder> encoder = [commandBuffer blitCommandEncoder];
|
||||||
|
[encoder copyFromBuffer:uploadBuffer
|
||||||
sourceOffset:sourceOffset
|
sourceOffset:sourceOffset
|
||||||
toBuffer:buffer
|
toBuffer:buffer
|
||||||
destinationOffset:destinationOffset
|
destinationOffset:destinationOffset
|
||||||
size:size];
|
size:size];
|
||||||
|
[encoder endEncoding];
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,7 +273,8 @@ namespace dawn_native { namespace metal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MaybeError Device::WaitForIdleForDestruction() {
|
MaybeError Device::WaitForIdleForDestruction() {
|
||||||
[mCommandContext.AcquireCommands() release];
|
[mPendingCommands release];
|
||||||
|
mPendingCommands = nil;
|
||||||
|
|
||||||
// Wait for all commands to be finished so we can free resources
|
// Wait for all commands to be finished so we can free resources
|
||||||
while (GetCompletedCommandSerial() != mLastSubmittedSerial) {
|
while (GetCompletedCommandSerial() != mLastSubmittedSerial) {
|
||||||
@ -277,7 +285,10 @@ namespace dawn_native { namespace metal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Device::Destroy() {
|
void Device::Destroy() {
|
||||||
[mCommandContext.AcquireCommands() release];
|
if (mPendingCommands != nil) {
|
||||||
|
[mPendingCommands release];
|
||||||
|
mPendingCommands = nil;
|
||||||
|
}
|
||||||
|
|
||||||
mMapTracker = nullptr;
|
mMapTracker = nullptr;
|
||||||
mDynamicUploader = nullptr;
|
mDynamicUploader = nullptr;
|
||||||
|
@ -27,11 +27,11 @@ namespace dawn_native { namespace metal {
|
|||||||
MaybeError Queue::SubmitImpl(uint32_t commandCount, CommandBufferBase* const* commands) {
|
MaybeError Queue::SubmitImpl(uint32_t commandCount, CommandBufferBase* const* commands) {
|
||||||
Device* device = ToBackend(GetDevice());
|
Device* device = ToBackend(GetDevice());
|
||||||
device->Tick();
|
device->Tick();
|
||||||
CommandRecordingContext* commandContext = device->GetPendingCommandContext();
|
id<MTLCommandBuffer> commandBuffer = device->GetPendingCommandBuffer();
|
||||||
|
|
||||||
TRACE_EVENT_BEGIN0(GetDevice()->GetPlatform(), Recording, "CommandBufferMTL::FillCommands");
|
TRACE_EVENT_BEGIN0(GetDevice()->GetPlatform(), Recording, "CommandBufferMTL::FillCommands");
|
||||||
for (uint32_t i = 0; i < commandCount; ++i) {
|
for (uint32_t i = 0; i < commandCount; ++i) {
|
||||||
ToBackend(commands[i])->FillCommands(commandContext);
|
ToBackend(commands[i])->FillCommands(commandBuffer);
|
||||||
}
|
}
|
||||||
TRACE_EVENT_END0(GetDevice()->GetPlatform(), Recording, "CommandBufferMTL::FillCommands");
|
TRACE_EVENT_END0(GetDevice()->GetPlatform(), Recording, "CommandBufferMTL::FillCommands");
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user