Metal: Move Metal render pass workarounds to UtilsMetal
In follow-up commits these workarounds will be used in more than just the CommandBuffer but also for lazy-texture clearing. In this CL the helpers are just moved and changed to take `encodeInside` as a std::function. Bug: dawn:1071 Change-Id: Ib3b90826c89e12edca41223b3c8b5a4cfc6fed04 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/87863 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Austin Eng <enga@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
a9b856e10e
commit
dc87f2ac66
|
@ -53,15 +53,7 @@ namespace dawn::native::metal {
|
||||||
using CommandBufferBase::CommandBufferBase;
|
using CommandBufferBase::CommandBufferBase;
|
||||||
|
|
||||||
MaybeError EncodeComputePass(CommandRecordingContext* commandContext);
|
MaybeError EncodeComputePass(CommandRecordingContext* commandContext);
|
||||||
MaybeError EncodeRenderPass(CommandRecordingContext* commandContext,
|
MaybeError EncodeRenderPass(id<MTLRenderCommandEncoder> encoder);
|
||||||
MTLRenderPassDescriptor* mtlRenderPass,
|
|
||||||
uint32_t width,
|
|
||||||
uint32_t height);
|
|
||||||
|
|
||||||
MaybeError EncodeRenderPassInternal(CommandRecordingContext* commandContext,
|
|
||||||
MTLRenderPassDescriptor* mtlRenderPass,
|
|
||||||
uint32_t width,
|
|
||||||
uint32_t height);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dawn::native::metal
|
} // namespace dawn::native::metal
|
||||||
|
|
|
@ -38,15 +38,6 @@ namespace dawn::native::metal {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// Allows this file to use MTLStoreActionStoreAndMultismapleResolve because the logic is
|
|
||||||
// first to compute what the "best" Metal render pass descriptor is, then fix it up if we
|
|
||||||
// are not on macOS 10.12 (i.e. the EmulateStoreAndMSAAResolve toggle is on).
|
|
||||||
#pragma clang diagnostic push
|
|
||||||
#pragma clang diagnostic ignored "-Wunguarded-availability"
|
|
||||||
constexpr MTLStoreAction kMTLStoreActionStoreAndMultisampleResolve =
|
|
||||||
MTLStoreActionStoreAndMultisampleResolve;
|
|
||||||
#pragma clang diagnostic pop
|
|
||||||
|
|
||||||
MTLIndexType MTLIndexFormat(wgpu::IndexFormat format) {
|
MTLIndexType MTLIndexFormat(wgpu::IndexFormat format) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case wgpu::IndexFormat::Uint16:
|
case wgpu::IndexFormat::Uint16:
|
||||||
|
@ -213,83 +204,6 @@ namespace dawn::native::metal {
|
||||||
return descriptorRef;
|
return descriptorRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function for Toggle EmulateStoreAndMSAAResolve
|
|
||||||
void ResolveInAnotherRenderPass(
|
|
||||||
CommandRecordingContext* commandContext,
|
|
||||||
const MTLRenderPassDescriptor* mtlRenderPass,
|
|
||||||
const std::array<id<MTLTexture>, kMaxColorAttachments>& resolveTextures) {
|
|
||||||
// Note that this creates a descriptor that's autoreleased so we don't use AcquireNSRef
|
|
||||||
NSRef<MTLRenderPassDescriptor> mtlRenderPassForResolveRef =
|
|
||||||
[MTLRenderPassDescriptor renderPassDescriptor];
|
|
||||||
MTLRenderPassDescriptor* mtlRenderPassForResolve = mtlRenderPassForResolveRef.Get();
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
|
|
||||||
if (resolveTextures[i] == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
mtlRenderPassForResolve.colorAttachments[i].texture =
|
|
||||||
mtlRenderPass.colorAttachments[i].texture;
|
|
||||||
mtlRenderPassForResolve.colorAttachments[i].loadAction = MTLLoadActionLoad;
|
|
||||||
mtlRenderPassForResolve.colorAttachments[i].storeAction =
|
|
||||||
MTLStoreActionMultisampleResolve;
|
|
||||||
mtlRenderPassForResolve.colorAttachments[i].resolveTexture = resolveTextures[i];
|
|
||||||
mtlRenderPassForResolve.colorAttachments[i].resolveLevel =
|
|
||||||
mtlRenderPass.colorAttachments[i].resolveLevel;
|
|
||||||
mtlRenderPassForResolve.colorAttachments[i].resolveSlice =
|
|
||||||
mtlRenderPass.colorAttachments[i].resolveSlice;
|
|
||||||
}
|
|
||||||
|
|
||||||
commandContext->BeginRender(mtlRenderPassForResolve);
|
|
||||||
commandContext->EndRender();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper functions for Toggle AlwaysResolveIntoZeroLevelAndLayer
|
|
||||||
ResultOrError<NSPRef<id<MTLTexture>>> CreateResolveTextureForWorkaround(
|
|
||||||
Device* device,
|
|
||||||
MTLPixelFormat mtlFormat,
|
|
||||||
uint32_t width,
|
|
||||||
uint32_t height) {
|
|
||||||
NSRef<MTLTextureDescriptor> mtlDescRef = AcquireNSRef([MTLTextureDescriptor new]);
|
|
||||||
MTLTextureDescriptor* mtlDesc = mtlDescRef.Get();
|
|
||||||
|
|
||||||
mtlDesc.textureType = MTLTextureType2D;
|
|
||||||
mtlDesc.usage = MTLTextureUsageRenderTarget;
|
|
||||||
mtlDesc.pixelFormat = mtlFormat;
|
|
||||||
mtlDesc.width = width;
|
|
||||||
mtlDesc.height = height;
|
|
||||||
mtlDesc.depth = 1;
|
|
||||||
mtlDesc.mipmapLevelCount = 1;
|
|
||||||
mtlDesc.arrayLength = 1;
|
|
||||||
mtlDesc.storageMode = MTLStorageModePrivate;
|
|
||||||
mtlDesc.sampleCount = 1;
|
|
||||||
|
|
||||||
id<MTLTexture> texture = [device->GetMTLDevice() newTextureWithDescriptor:mtlDesc];
|
|
||||||
if (texture == nil) {
|
|
||||||
return DAWN_OUT_OF_MEMORY_ERROR("Allocation of temporary texture failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return AcquireNSPRef(texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CopyIntoTrueResolveTarget(CommandRecordingContext* commandContext,
|
|
||||||
id<MTLTexture> mtlTrueResolveTexture,
|
|
||||||
uint32_t trueResolveLevel,
|
|
||||||
uint32_t trueResolveSlice,
|
|
||||||
id<MTLTexture> temporaryResolveTexture,
|
|
||||||
uint32_t width,
|
|
||||||
uint32_t height) {
|
|
||||||
[commandContext->EnsureBlit() copyFromTexture:temporaryResolveTexture
|
|
||||||
sourceSlice:0
|
|
||||||
sourceLevel:0
|
|
||||||
sourceOrigin:MTLOriginMake(0, 0, 0)
|
|
||||||
sourceSize:MTLSizeMake(width, height, 1)
|
|
||||||
toTexture:mtlTrueResolveTexture
|
|
||||||
destinationSlice:trueResolveSlice
|
|
||||||
destinationLevel:trueResolveLevel
|
|
||||||
destinationOrigin:MTLOriginMake(0, 0, 0)];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Metal uses a physical addressing mode which means buffers in the shading language are
|
// Metal uses a physical addressing mode which means buffers in the shading language are
|
||||||
// just pointers to the virtual address of their start. This means there is no way to know
|
// just pointers to the virtual address of their start. This means there is no way to know
|
||||||
// the length of a buffer to compute the length() of unsized arrays at the end of storage
|
// the length of a buffer to compute the length() of unsized arrays at the end of storage
|
||||||
|
@ -731,8 +645,11 @@ namespace dawn::native::metal {
|
||||||
|
|
||||||
LazyClearRenderPassAttachments(cmd);
|
LazyClearRenderPassAttachments(cmd);
|
||||||
NSRef<MTLRenderPassDescriptor> descriptor = CreateMTLRenderPassDescriptor(cmd);
|
NSRef<MTLRenderPassDescriptor> descriptor = CreateMTLRenderPassDescriptor(cmd);
|
||||||
DAWN_TRY(EncodeRenderPass(commandContext, descriptor.Get(), cmd->width,
|
DAWN_TRY(EncodeMetalRenderPass(
|
||||||
cmd->height));
|
ToBackend(GetDevice()), commandContext, descriptor.Get(), cmd->width,
|
||||||
|
cmd->height, [this](id<MTLRenderCommandEncoder> encoder) -> MaybeError {
|
||||||
|
return this->EncodeRenderPass(encoder);
|
||||||
|
}));
|
||||||
|
|
||||||
nextRenderPassNumber++;
|
nextRenderPassNumber++;
|
||||||
break;
|
break;
|
||||||
|
@ -1192,102 +1109,7 @@ namespace dawn::native::metal {
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
MaybeError CommandBuffer::EncodeRenderPass(CommandRecordingContext* commandContext,
|
MaybeError CommandBuffer::EncodeRenderPass(id<MTLRenderCommandEncoder> encoder) {
|
||||||
MTLRenderPassDescriptor* mtlRenderPass,
|
|
||||||
uint32_t width,
|
|
||||||
uint32_t height) {
|
|
||||||
ASSERT(mtlRenderPass);
|
|
||||||
|
|
||||||
Device* device = ToBackend(GetDevice());
|
|
||||||
|
|
||||||
// Handle Toggle AlwaysResolveIntoZeroLevelAndLayer. We must handle this before applying
|
|
||||||
// the store + MSAA resolve workaround, otherwise this toggle will never be handled because
|
|
||||||
// the resolve texture is removed when applying the store + MSAA resolve workaround.
|
|
||||||
if (device->IsToggleEnabled(Toggle::AlwaysResolveIntoZeroLevelAndLayer)) {
|
|
||||||
std::array<id<MTLTexture>, kMaxColorAttachments> trueResolveTextures = {};
|
|
||||||
std::array<uint32_t, kMaxColorAttachments> trueResolveLevels = {};
|
|
||||||
std::array<uint32_t, kMaxColorAttachments> trueResolveSlices = {};
|
|
||||||
|
|
||||||
// Use temporary resolve texture on the resolve targets with non-zero resolveLevel or
|
|
||||||
// resolveSlice.
|
|
||||||
bool useTemporaryResolveTexture = false;
|
|
||||||
std::array<NSPRef<id<MTLTexture>>, kMaxColorAttachments> temporaryResolveTextures = {};
|
|
||||||
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
|
|
||||||
if (mtlRenderPass.colorAttachments[i].resolveTexture == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mtlRenderPass.colorAttachments[i].resolveLevel == 0 &&
|
|
||||||
mtlRenderPass.colorAttachments[i].resolveSlice == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
trueResolveTextures[i] = mtlRenderPass.colorAttachments[i].resolveTexture;
|
|
||||||
trueResolveLevels[i] = mtlRenderPass.colorAttachments[i].resolveLevel;
|
|
||||||
trueResolveSlices[i] = mtlRenderPass.colorAttachments[i].resolveSlice;
|
|
||||||
|
|
||||||
const MTLPixelFormat mtlFormat = trueResolveTextures[i].pixelFormat;
|
|
||||||
DAWN_TRY_ASSIGN(temporaryResolveTextures[i], CreateResolveTextureForWorkaround(
|
|
||||||
device, mtlFormat, width, height));
|
|
||||||
|
|
||||||
mtlRenderPass.colorAttachments[i].resolveTexture =
|
|
||||||
temporaryResolveTextures[i].Get();
|
|
||||||
mtlRenderPass.colorAttachments[i].resolveLevel = 0;
|
|
||||||
mtlRenderPass.colorAttachments[i].resolveSlice = 0;
|
|
||||||
useTemporaryResolveTexture = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we need to use a temporary resolve texture we need to copy the result of MSAA
|
|
||||||
// resolve back to the true resolve targets.
|
|
||||||
if (useTemporaryResolveTexture) {
|
|
||||||
DAWN_TRY(EncodeRenderPass(commandContext, mtlRenderPass, width, height));
|
|
||||||
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
|
|
||||||
if (trueResolveTextures[i] == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(temporaryResolveTextures[i] != nullptr);
|
|
||||||
CopyIntoTrueResolveTarget(commandContext, trueResolveTextures[i],
|
|
||||||
trueResolveLevels[i], trueResolveSlices[i],
|
|
||||||
temporaryResolveTextures[i].Get(), width, height);
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle Store + MSAA resolve workaround (Toggle EmulateStoreAndMSAAResolve).
|
|
||||||
if (device->IsToggleEnabled(Toggle::EmulateStoreAndMSAAResolve)) {
|
|
||||||
bool hasStoreAndMSAAResolve = false;
|
|
||||||
|
|
||||||
// Remove any store + MSAA resolve and remember them.
|
|
||||||
std::array<id<MTLTexture>, kMaxColorAttachments> resolveTextures = {};
|
|
||||||
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
|
|
||||||
if (mtlRenderPass.colorAttachments[i].storeAction ==
|
|
||||||
kMTLStoreActionStoreAndMultisampleResolve) {
|
|
||||||
hasStoreAndMSAAResolve = true;
|
|
||||||
resolveTextures[i] = mtlRenderPass.colorAttachments[i].resolveTexture;
|
|
||||||
|
|
||||||
mtlRenderPass.colorAttachments[i].storeAction = MTLStoreActionStore;
|
|
||||||
mtlRenderPass.colorAttachments[i].resolveTexture = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we found a store + MSAA resolve we need to resolve in a different render pass.
|
|
||||||
if (hasStoreAndMSAAResolve) {
|
|
||||||
DAWN_TRY(EncodeRenderPass(commandContext, mtlRenderPass, width, height));
|
|
||||||
ResolveInAnotherRenderPass(commandContext, mtlRenderPass, resolveTextures);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DAWN_TRY(EncodeRenderPassInternal(commandContext, mtlRenderPass, width, height));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
MaybeError CommandBuffer::EncodeRenderPassInternal(CommandRecordingContext* commandContext,
|
|
||||||
MTLRenderPassDescriptor* mtlRenderPass,
|
|
||||||
uint32_t width,
|
|
||||||
uint32_t height) {
|
|
||||||
bool enableVertexPulling = GetDevice()->IsToggleEnabled(Toggle::MetalEnableVertexPulling);
|
bool enableVertexPulling = GetDevice()->IsToggleEnabled(Toggle::MetalEnableVertexPulling);
|
||||||
RenderPipeline* lastPipeline = nullptr;
|
RenderPipeline* lastPipeline = nullptr;
|
||||||
id<MTLBuffer> indexBuffer = nullptr;
|
id<MTLBuffer> indexBuffer = nullptr;
|
||||||
|
@ -1299,8 +1121,6 @@ namespace dawn::native::metal {
|
||||||
VertexBufferTracker vertexBuffers(&storageBufferLengths);
|
VertexBufferTracker vertexBuffers(&storageBufferLengths);
|
||||||
BindGroupTracker bindGroups(&storageBufferLengths);
|
BindGroupTracker bindGroups(&storageBufferLengths);
|
||||||
|
|
||||||
id<MTLRenderCommandEncoder> encoder = commandContext->BeginRender(mtlRenderPass);
|
|
||||||
|
|
||||||
auto EncodeRenderBundleCommand = [&](CommandIterator* iter, Command type) {
|
auto EncodeRenderBundleCommand = [&](CommandIterator* iter, Command type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Command::Draw: {
|
case Command::Draw: {
|
||||||
|
@ -1489,7 +1309,6 @@ namespace dawn::native::metal {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Command::EndRenderPass: {
|
case Command::EndRenderPass: {
|
||||||
mCommands.NextCommand<EndRenderPassCmd>();
|
mCommands.NextCommand<EndRenderPassCmd>();
|
||||||
commandContext->EndRender();
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,27 @@ namespace dawn::native::metal {
|
||||||
uint32_t sampleMask = 0xFFFFFFFF,
|
uint32_t sampleMask = 0xFFFFFFFF,
|
||||||
const RenderPipeline* renderPipeline = nullptr);
|
const RenderPipeline* renderPipeline = nullptr);
|
||||||
|
|
||||||
|
// Allow use MTLStoreActionStoreAndMultismapleResolve because the logic in the backend is
|
||||||
|
// first to compute what the "best" Metal render pass descriptor is, then fix it up if we
|
||||||
|
// are not on macOS 10.12 (i.e. the EmulateStoreAndMSAAResolve toggle is on).
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wunguarded-availability"
|
||||||
|
constexpr MTLStoreAction kMTLStoreActionStoreAndMultisampleResolve =
|
||||||
|
MTLStoreActionStoreAndMultisampleResolve;
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
|
||||||
|
// Helper functions to encode Metal render passes that take care of multiple workarounds that
|
||||||
|
// happen at the render pass start and end. Because workarounds wrap the encoding of the render
|
||||||
|
// pass, the encoding must be entirely done by the `encodeInside` callback.
|
||||||
|
// At the end of this function, `commandContext` will have no encoder open.
|
||||||
|
using EncodeInsideRenderPass = std::function<MaybeError(id<MTLRenderCommandEncoder>)>;
|
||||||
|
MaybeError EncodeMetalRenderPass(Device* device,
|
||||||
|
CommandRecordingContext* commandContext,
|
||||||
|
MTLRenderPassDescriptor* mtlRenderPass,
|
||||||
|
uint32_t width,
|
||||||
|
uint32_t height,
|
||||||
|
EncodeInsideRenderPass encodeInside);
|
||||||
|
|
||||||
} // namespace dawn::native::metal
|
} // namespace dawn::native::metal
|
||||||
|
|
||||||
#endif // SRC_DAWN_NATIVE_METAL_UTILSMETAL_H_
|
#endif // SRC_DAWN_NATIVE_METAL_UTILSMETAL_H_
|
||||||
|
|
|
@ -21,6 +21,85 @@
|
||||||
|
|
||||||
namespace dawn::native::metal {
|
namespace dawn::native::metal {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Helper function for Toggle EmulateStoreAndMSAAResolve
|
||||||
|
void ResolveInAnotherRenderPass(
|
||||||
|
CommandRecordingContext* commandContext,
|
||||||
|
const MTLRenderPassDescriptor* mtlRenderPass,
|
||||||
|
const std::array<id<MTLTexture>, kMaxColorAttachments>& resolveTextures) {
|
||||||
|
// Note that this creates a descriptor that's autoreleased so we don't use AcquireNSRef
|
||||||
|
NSRef<MTLRenderPassDescriptor> mtlRenderPassForResolveRef =
|
||||||
|
[MTLRenderPassDescriptor renderPassDescriptor];
|
||||||
|
MTLRenderPassDescriptor* mtlRenderPassForResolve = mtlRenderPassForResolveRef.Get();
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
|
||||||
|
if (resolveTextures[i] == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
mtlRenderPassForResolve.colorAttachments[i].texture =
|
||||||
|
mtlRenderPass.colorAttachments[i].texture;
|
||||||
|
mtlRenderPassForResolve.colorAttachments[i].loadAction = MTLLoadActionLoad;
|
||||||
|
mtlRenderPassForResolve.colorAttachments[i].storeAction =
|
||||||
|
MTLStoreActionMultisampleResolve;
|
||||||
|
mtlRenderPassForResolve.colorAttachments[i].resolveTexture = resolveTextures[i];
|
||||||
|
mtlRenderPassForResolve.colorAttachments[i].resolveLevel =
|
||||||
|
mtlRenderPass.colorAttachments[i].resolveLevel;
|
||||||
|
mtlRenderPassForResolve.colorAttachments[i].resolveSlice =
|
||||||
|
mtlRenderPass.colorAttachments[i].resolveSlice;
|
||||||
|
}
|
||||||
|
|
||||||
|
commandContext->BeginRender(mtlRenderPassForResolve);
|
||||||
|
commandContext->EndRender();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper functions for Toggle AlwaysResolveIntoZeroLevelAndLayer
|
||||||
|
ResultOrError<NSPRef<id<MTLTexture>>> CreateResolveTextureForWorkaround(
|
||||||
|
Device* device,
|
||||||
|
MTLPixelFormat mtlFormat,
|
||||||
|
uint32_t width,
|
||||||
|
uint32_t height) {
|
||||||
|
NSRef<MTLTextureDescriptor> mtlDescRef = AcquireNSRef([MTLTextureDescriptor new]);
|
||||||
|
MTLTextureDescriptor* mtlDesc = mtlDescRef.Get();
|
||||||
|
|
||||||
|
mtlDesc.textureType = MTLTextureType2D;
|
||||||
|
mtlDesc.usage = MTLTextureUsageRenderTarget;
|
||||||
|
mtlDesc.pixelFormat = mtlFormat;
|
||||||
|
mtlDesc.width = width;
|
||||||
|
mtlDesc.height = height;
|
||||||
|
mtlDesc.depth = 1;
|
||||||
|
mtlDesc.mipmapLevelCount = 1;
|
||||||
|
mtlDesc.arrayLength = 1;
|
||||||
|
mtlDesc.storageMode = MTLStorageModePrivate;
|
||||||
|
mtlDesc.sampleCount = 1;
|
||||||
|
|
||||||
|
id<MTLTexture> texture = [device->GetMTLDevice() newTextureWithDescriptor:mtlDesc];
|
||||||
|
if (texture == nil) {
|
||||||
|
return DAWN_OUT_OF_MEMORY_ERROR("Allocation of temporary texture failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return AcquireNSPRef(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopyIntoTrueResolveTarget(CommandRecordingContext* commandContext,
|
||||||
|
id<MTLTexture> mtlTrueResolveTexture,
|
||||||
|
uint32_t trueResolveLevel,
|
||||||
|
uint32_t trueResolveSlice,
|
||||||
|
id<MTLTexture> temporaryResolveTexture,
|
||||||
|
uint32_t width,
|
||||||
|
uint32_t height) {
|
||||||
|
[commandContext->EnsureBlit() copyFromTexture:temporaryResolveTexture
|
||||||
|
sourceSlice:0
|
||||||
|
sourceLevel:0
|
||||||
|
sourceOrigin:MTLOriginMake(0, 0, 0)
|
||||||
|
sourceSize:MTLSizeMake(width, height, 1)
|
||||||
|
toTexture:mtlTrueResolveTexture
|
||||||
|
destinationSlice:trueResolveSlice
|
||||||
|
destinationLevel:trueResolveLevel
|
||||||
|
destinationOrigin:MTLOriginMake(0, 0, 0)];
|
||||||
|
}
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
MTLCompareFunction ToMetalCompareFunction(wgpu::CompareFunction compareFunction) {
|
MTLCompareFunction ToMetalCompareFunction(wgpu::CompareFunction compareFunction) {
|
||||||
switch (compareFunction) {
|
switch (compareFunction) {
|
||||||
case wgpu::CompareFunction::Never:
|
case wgpu::CompareFunction::Never:
|
||||||
|
@ -285,4 +364,98 @@ namespace dawn::native::metal {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeError EncodeMetalRenderPass(Device* device,
|
||||||
|
CommandRecordingContext* commandContext,
|
||||||
|
MTLRenderPassDescriptor* mtlRenderPass,
|
||||||
|
uint32_t width,
|
||||||
|
uint32_t height,
|
||||||
|
EncodeInsideRenderPass encodeInside) {
|
||||||
|
// Handle Toggle AlwaysResolveIntoZeroLevelAndLayer. We must handle this before applying
|
||||||
|
// the store + MSAA resolve workaround, otherwise this toggle will never be handled because
|
||||||
|
// the resolve texture is removed when applying the store + MSAA resolve workaround.
|
||||||
|
if (device->IsToggleEnabled(Toggle::AlwaysResolveIntoZeroLevelAndLayer)) {
|
||||||
|
std::array<id<MTLTexture>, kMaxColorAttachments> trueResolveTextures = {};
|
||||||
|
std::array<uint32_t, kMaxColorAttachments> trueResolveLevels = {};
|
||||||
|
std::array<uint32_t, kMaxColorAttachments> trueResolveSlices = {};
|
||||||
|
|
||||||
|
// Use temporary resolve texture on the resolve targets with non-zero resolveLevel or
|
||||||
|
// resolveSlice.
|
||||||
|
bool useTemporaryResolveTexture = false;
|
||||||
|
std::array<NSPRef<id<MTLTexture>>, kMaxColorAttachments> temporaryResolveTextures = {};
|
||||||
|
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
|
||||||
|
if (mtlRenderPass.colorAttachments[i].resolveTexture == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mtlRenderPass.colorAttachments[i].resolveLevel == 0 &&
|
||||||
|
mtlRenderPass.colorAttachments[i].resolveSlice == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
trueResolveTextures[i] = mtlRenderPass.colorAttachments[i].resolveTexture;
|
||||||
|
trueResolveLevels[i] = mtlRenderPass.colorAttachments[i].resolveLevel;
|
||||||
|
trueResolveSlices[i] = mtlRenderPass.colorAttachments[i].resolveSlice;
|
||||||
|
|
||||||
|
const MTLPixelFormat mtlFormat = trueResolveTextures[i].pixelFormat;
|
||||||
|
DAWN_TRY_ASSIGN(temporaryResolveTextures[i], CreateResolveTextureForWorkaround(
|
||||||
|
device, mtlFormat, width, height));
|
||||||
|
|
||||||
|
mtlRenderPass.colorAttachments[i].resolveTexture =
|
||||||
|
temporaryResolveTextures[i].Get();
|
||||||
|
mtlRenderPass.colorAttachments[i].resolveLevel = 0;
|
||||||
|
mtlRenderPass.colorAttachments[i].resolveSlice = 0;
|
||||||
|
useTemporaryResolveTexture = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we need to use a temporary resolve texture we need to copy the result of MSAA
|
||||||
|
// resolve back to the true resolve targets.
|
||||||
|
if (useTemporaryResolveTexture) {
|
||||||
|
DAWN_TRY(EncodeMetalRenderPass(device, commandContext, mtlRenderPass, width, height,
|
||||||
|
std::move(encodeInside)));
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
|
||||||
|
if (trueResolveTextures[i] == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(temporaryResolveTextures[i] != nullptr);
|
||||||
|
CopyIntoTrueResolveTarget(commandContext, trueResolveTextures[i],
|
||||||
|
trueResolveLevels[i], trueResolveSlices[i],
|
||||||
|
temporaryResolveTextures[i].Get(), width, height);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle Store + MSAA resolve workaround (Toggle EmulateStoreAndMSAAResolve).
|
||||||
|
if (device->IsToggleEnabled(Toggle::EmulateStoreAndMSAAResolve)) {
|
||||||
|
bool hasStoreAndMSAAResolve = false;
|
||||||
|
|
||||||
|
// Remove any store + MSAA resolve and remember them.
|
||||||
|
std::array<id<MTLTexture>, kMaxColorAttachments> resolveTextures = {};
|
||||||
|
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
|
||||||
|
if (mtlRenderPass.colorAttachments[i].storeAction ==
|
||||||
|
kMTLStoreActionStoreAndMultisampleResolve) {
|
||||||
|
hasStoreAndMSAAResolve = true;
|
||||||
|
resolveTextures[i] = mtlRenderPass.colorAttachments[i].resolveTexture;
|
||||||
|
|
||||||
|
mtlRenderPass.colorAttachments[i].storeAction = MTLStoreActionStore;
|
||||||
|
mtlRenderPass.colorAttachments[i].resolveTexture = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we found a store + MSAA resolve we need to resolve in a different render pass.
|
||||||
|
if (hasStoreAndMSAAResolve) {
|
||||||
|
DAWN_TRY(EncodeMetalRenderPass(device, commandContext, mtlRenderPass, width, height,
|
||||||
|
std::move(encodeInside)));
|
||||||
|
|
||||||
|
ResolveInAnotherRenderPass(commandContext, mtlRenderPass, resolveTextures);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DAWN_TRY(encodeInside(commandContext->BeginRender(mtlRenderPass)));
|
||||||
|
commandContext->EndRender();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
} // namespace dawn::native::metal
|
} // namespace dawn::native::metal
|
||||||
|
|
Loading…
Reference in New Issue