Add MetalRenderR8RG8UnormSmallMipToTempTexture workaround
This workaround replaces the toggle that forbids creating mipmapped R8Unorm and RG8Unorm textures on Metal. Instead it adds a Metal render pass workaround that renders to a temporary texture under certain conditions, then copies back to the correct mip level. The texture lazy-clearing code is also changed to use the helper that does workarounds for Metal render passes. A test is added that triggers the issue with a small amount of code, but more extensive coverage is left to the CTS. For example texture_zero tests caught multiple issues during the creation of this CL. Bug: dawn:1071 Change-Id: I7ef1151524e71e5a9a8e8f5205d9b554bee438b3 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/87864 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
01004b7732
commit
bd8de5d2a4
|
@ -394,13 +394,6 @@ namespace dawn::native {
|
||||||
"https://crbug.com/dawn/838: Stencil textures with more than one mip level are "
|
"https://crbug.com/dawn/838: Stencil textures with more than one mip level are "
|
||||||
"disabled on Metal.");
|
"disabled on Metal.");
|
||||||
|
|
||||||
DAWN_INVALID_IF(
|
|
||||||
device->IsToggleEnabled(Toggle::DisableR8RG8Mipmaps) && descriptor->mipLevelCount > 1 &&
|
|
||||||
(descriptor->format == wgpu::TextureFormat::R8Unorm ||
|
|
||||||
descriptor->format == wgpu::TextureFormat::RG8Unorm),
|
|
||||||
"https://crbug.com/dawn/1071: r8unorm and rg8unorm textures with more than one mip "
|
|
||||||
"level are disabled on Metal.");
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -231,11 +231,6 @@ namespace dawn::native {
|
||||||
"Enables calls to SetLabel to be forwarded to backend-specific APIs that label "
|
"Enables calls to SetLabel to be forwarded to backend-specific APIs that label "
|
||||||
"objects.",
|
"objects.",
|
||||||
"https://crbug.com/dawn/840"}},
|
"https://crbug.com/dawn/840"}},
|
||||||
{Toggle::DisableR8RG8Mipmaps,
|
|
||||||
{"disable_r8_rg8_mipmaps",
|
|
||||||
"Disables mipmaps for r8unorm and rg8unorm textures, which are known on some drivers "
|
|
||||||
"to not clear correctly.",
|
|
||||||
"https://crbug.com/dawn/1071"}},
|
|
||||||
{Toggle::UsePlaceholderFragmentInVertexOnlyPipeline,
|
{Toggle::UsePlaceholderFragmentInVertexOnlyPipeline,
|
||||||
{"use_placeholder_fragment_in_vertex_only_pipeline",
|
{"use_placeholder_fragment_in_vertex_only_pipeline",
|
||||||
"Use a placeholder empty fragment shader in vertex only render pipeline. This toggle "
|
"Use a placeholder empty fragment shader in vertex only render pipeline. This toggle "
|
||||||
|
@ -272,7 +267,14 @@ namespace dawn::native {
|
||||||
"it via split the copy operation into two copies, in order to make B2T/T2B copy "
|
"it via split the copy operation into two copies, in order to make B2T/T2B copy "
|
||||||
"being done correctly on D3D12.",
|
"being done correctly on D3D12.",
|
||||||
"https://crbug.com/dawn/1289"}},
|
"https://crbug.com/dawn/1289"}},
|
||||||
|
{Toggle::MetalRenderR8RG8UnormSmallMipToTempTexture,
|
||||||
|
{"metal_render_r8_rg8_unorm_small_mip_to_temp_texture",
|
||||||
|
"Metal Intel devices have issues with r8unorm and rg8unorm textures where rendering "
|
||||||
|
"to small mips (level >= 2) doesn't work correctly. Workaround this issue by "
|
||||||
|
"detecting this case and rendering to a temporary texture instead (with copies "
|
||||||
|
"before "
|
||||||
|
"and after if needed).",
|
||||||
|
"https://crbug.com/dawn/1071"}},
|
||||||
// Comment to separate the }} so it is clearer what to copy-paste to add a toggle.
|
// Comment to separate the }} so it is clearer what to copy-paste to add a toggle.
|
||||||
}};
|
}};
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
|
@ -62,13 +62,13 @@ namespace dawn::native {
|
||||||
DisableWorkgroupInit,
|
DisableWorkgroupInit,
|
||||||
DisableSymbolRenaming,
|
DisableSymbolRenaming,
|
||||||
UseUserDefinedLabelsInBackend,
|
UseUserDefinedLabelsInBackend,
|
||||||
DisableR8RG8Mipmaps,
|
|
||||||
UsePlaceholderFragmentInVertexOnlyPipeline,
|
UsePlaceholderFragmentInVertexOnlyPipeline,
|
||||||
FxcOptimizations,
|
FxcOptimizations,
|
||||||
RecordDetailedTimingInTraceEvents,
|
RecordDetailedTimingInTraceEvents,
|
||||||
DisableTimestampQueryConversion,
|
DisableTimestampQueryConversion,
|
||||||
VulkanUseZeroInitializeWorkgroupMemoryExtension,
|
VulkanUseZeroInitializeWorkgroupMemoryExtension,
|
||||||
D3D12SplitBufferTextureCopyForRowsPerImagePaddings,
|
D3D12SplitBufferTextureCopyForRowsPerImagePaddings,
|
||||||
|
MetalRenderR8RG8UnormSmallMipToTempTexture,
|
||||||
|
|
||||||
EnumCount,
|
EnumCount,
|
||||||
InvalidEnum = EnumCount,
|
InvalidEnum = EnumCount,
|
||||||
|
|
|
@ -210,10 +210,10 @@ namespace dawn::native::metal {
|
||||||
SetToggle(Toggle::MetalUseSharedModeForCounterSampleBuffer, useSharedMode);
|
SetToggle(Toggle::MetalUseSharedModeForCounterSampleBuffer, useSharedMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(crbug.com/dawn/1071): r8unorm and rg8unorm textures with multiple mip levels don't
|
// Rendering R8Unorm and RG8Unorm to small mip doesn't work properly on Intel.
|
||||||
// clear properly on Intel Macs.
|
// TODO(crbug.com/dawn/1071): Tighten the workaround when this issue is fixed.
|
||||||
if (gpu_info::IsIntel(vendorId)) {
|
if (gpu_info::IsIntel(vendorId)) {
|
||||||
SetToggle(Toggle::DisableR8RG8Mipmaps, true);
|
SetToggle(Toggle::MetalRenderR8RG8UnormSmallMipToTempTexture, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// On some Intel GPU vertex only render pipeline get wrong depth result if no fragment
|
// On some Intel GPU vertex only render pipeline get wrong depth result if no fragment
|
||||||
|
|
|
@ -875,8 +875,8 @@ namespace dawn::native::metal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
commandContext->BeginRender(descriptor);
|
DAWN_TRY(EncodeEmptyMetalRenderPass(device, commandContext, descriptor,
|
||||||
commandContext->EndRender();
|
GetMipLevelVirtualSize(level)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -923,16 +923,18 @@ namespace dawn::native::metal {
|
||||||
|
|
||||||
if (attachment == kMaxColorAttachments) {
|
if (attachment == kMaxColorAttachments) {
|
||||||
attachment = 0;
|
attachment = 0;
|
||||||
commandContext->BeginRender(descriptor.Get());
|
DAWN_TRY(EncodeEmptyMetalRenderPass(device, commandContext,
|
||||||
commandContext->EndRender();
|
descriptor.Get(),
|
||||||
|
GetMipLevelVirtualSize(level)));
|
||||||
descriptor = nullptr;
|
descriptor = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (descriptor != nullptr) {
|
if (descriptor != nullptr) {
|
||||||
commandContext->BeginRender(descriptor.Get());
|
DAWN_TRY(EncodeEmptyMetalRenderPass(device, commandContext,
|
||||||
commandContext->EndRender();
|
descriptor.Get(),
|
||||||
|
GetMipLevelVirtualSize(level)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,6 +102,11 @@ namespace dawn::native::metal {
|
||||||
uint32_t height,
|
uint32_t height,
|
||||||
EncodeInsideRenderPass encodeInside);
|
EncodeInsideRenderPass encodeInside);
|
||||||
|
|
||||||
|
MaybeError EncodeEmptyMetalRenderPass(Device* device,
|
||||||
|
CommandRecordingContext* commandContext,
|
||||||
|
MTLRenderPassDescriptor* mtlRenderPass,
|
||||||
|
Extent3D size);
|
||||||
|
|
||||||
} // namespace dawn::native::metal
|
} // namespace dawn::native::metal
|
||||||
|
|
||||||
#endif // SRC_DAWN_NATIVE_METAL_UTILSMETAL_H_
|
#endif // SRC_DAWN_NATIVE_METAL_UTILSMETAL_H_
|
||||||
|
|
|
@ -13,15 +13,126 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "dawn/native/metal/UtilsMetal.h"
|
#include "dawn/native/metal/UtilsMetal.h"
|
||||||
|
|
||||||
|
#include "dawn/common/Assert.h"
|
||||||
#include "dawn/native/CommandBuffer.h"
|
#include "dawn/native/CommandBuffer.h"
|
||||||
#include "dawn/native/Pipeline.h"
|
#include "dawn/native/Pipeline.h"
|
||||||
#include "dawn/native/ShaderModule.h"
|
#include "dawn/native/ShaderModule.h"
|
||||||
|
|
||||||
#include "dawn/common/Assert.h"
|
|
||||||
|
|
||||||
namespace dawn::native::metal {
|
namespace dawn::native::metal {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
// A helper struct to track state while doing workarounds for Metal render passes. It
|
||||||
|
// contains a temporary texture and information about the attachment it replaces.
|
||||||
|
// Helper methods encode copies between the two textures.
|
||||||
|
struct SavedMetalAttachment {
|
||||||
|
id<MTLTexture> texture = nil;
|
||||||
|
NSUInteger level;
|
||||||
|
NSUInteger slice;
|
||||||
|
|
||||||
|
NSPRef<id<MTLTexture>> temporary;
|
||||||
|
|
||||||
|
void CopyFromTemporaryToAttachment(CommandRecordingContext* commandContext) {
|
||||||
|
[commandContext->EnsureBlit()
|
||||||
|
copyFromTexture:temporary.Get()
|
||||||
|
sourceSlice:0
|
||||||
|
sourceLevel:0
|
||||||
|
sourceOrigin:MTLOriginMake(0, 0, 0)
|
||||||
|
sourceSize:MTLSizeMake([temporary.Get() width], [temporary.Get() height],
|
||||||
|
1)
|
||||||
|
toTexture:texture
|
||||||
|
destinationSlice:slice
|
||||||
|
destinationLevel:level
|
||||||
|
destinationOrigin:MTLOriginMake(0, 0, 0)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopyFromAttachmentToTemporary(CommandRecordingContext* commandContext) {
|
||||||
|
[commandContext->EnsureBlit()
|
||||||
|
copyFromTexture:texture
|
||||||
|
sourceSlice:slice
|
||||||
|
sourceLevel:level
|
||||||
|
sourceOrigin:MTLOriginMake(0, 0, 0)
|
||||||
|
sourceSize:MTLSizeMake([temporary.Get() width], [temporary.Get() height],
|
||||||
|
1)
|
||||||
|
toTexture:temporary.Get()
|
||||||
|
destinationSlice:0
|
||||||
|
destinationLevel:0
|
||||||
|
destinationOrigin:MTLOriginMake(0, 0, 0)];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Common code between both kinds of attachments swaps.
|
||||||
|
ResultOrError<SavedMetalAttachment> SaveAttachmentCreateTemporary(
|
||||||
|
Device* device,
|
||||||
|
id<MTLTexture> attachmentTexture,
|
||||||
|
NSUInteger attachmentLevel,
|
||||||
|
NSUInteger attachmentSlice) {
|
||||||
|
// Save the attachment.
|
||||||
|
SavedMetalAttachment result;
|
||||||
|
result.texture = attachmentTexture;
|
||||||
|
result.level = attachmentLevel;
|
||||||
|
result.slice = attachmentSlice;
|
||||||
|
|
||||||
|
// Create the temporary texture.
|
||||||
|
NSRef<MTLTextureDescriptor> mtlDescRef = AcquireNSRef([MTLTextureDescriptor new]);
|
||||||
|
MTLTextureDescriptor* mtlDesc = mtlDescRef.Get();
|
||||||
|
|
||||||
|
mtlDesc.textureType = MTLTextureType2D;
|
||||||
|
mtlDesc.usage = MTLTextureUsageRenderTarget;
|
||||||
|
mtlDesc.pixelFormat = [result.texture pixelFormat];
|
||||||
|
mtlDesc.width = std::max([result.texture width] >> attachmentLevel, NSUInteger(1));
|
||||||
|
mtlDesc.height = std::max([result.texture height] >> attachmentLevel, NSUInteger(1));
|
||||||
|
mtlDesc.depth = 1;
|
||||||
|
mtlDesc.mipmapLevelCount = 1;
|
||||||
|
mtlDesc.arrayLength = 1;
|
||||||
|
mtlDesc.storageMode = MTLStorageModePrivate;
|
||||||
|
mtlDesc.sampleCount = [result.texture sampleCount];
|
||||||
|
|
||||||
|
result.temporary =
|
||||||
|
AcquireNSPRef([device->GetMTLDevice() newTextureWithDescriptor:mtlDesc]);
|
||||||
|
if (result.temporary == nil) {
|
||||||
|
return DAWN_OUT_OF_MEMORY_ERROR("Allocation of temporary texture failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Patches the render pass attachment to replace it with a temporary texture. Returns a
|
||||||
|
// SavedMetalAttachment that can be used to easily copy between the original attachment and
|
||||||
|
// the temporary.
|
||||||
|
ResultOrError<SavedMetalAttachment> PatchAttachmentWithTemporary(
|
||||||
|
Device* device,
|
||||||
|
MTLRenderPassAttachmentDescriptor* attachment) {
|
||||||
|
SavedMetalAttachment result;
|
||||||
|
DAWN_TRY_ASSIGN(
|
||||||
|
result, SaveAttachmentCreateTemporary(device, attachment.texture, attachment.level,
|
||||||
|
attachment.slice));
|
||||||
|
|
||||||
|
// Replace the attachment with the temporary
|
||||||
|
attachment.texture = result.temporary.Get();
|
||||||
|
attachment.level = 0;
|
||||||
|
attachment.slice = 0;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same as PatchAttachmentWithTemporary but for the resolve attachment.
|
||||||
|
ResultOrError<SavedMetalAttachment> PatchResolveAttachmentWithTemporary(
|
||||||
|
Device* device,
|
||||||
|
MTLRenderPassAttachmentDescriptor* attachment) {
|
||||||
|
SavedMetalAttachment result;
|
||||||
|
DAWN_TRY_ASSIGN(result, SaveAttachmentCreateTemporary(device, attachment.resolveTexture,
|
||||||
|
attachment.resolveLevel,
|
||||||
|
attachment.resolveSlice));
|
||||||
|
|
||||||
|
// Replace the resolve attachment with the tempoary.
|
||||||
|
attachment.resolveTexture = result.temporary.Get();
|
||||||
|
attachment.resolveLevel = 0;
|
||||||
|
attachment.resolveSlice = 0;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Helper function for Toggle EmulateStoreAndMSAAResolve
|
// Helper function for Toggle EmulateStoreAndMSAAResolve
|
||||||
void ResolveInAnotherRenderPass(
|
void ResolveInAnotherRenderPass(
|
||||||
CommandRecordingContext* commandContext,
|
CommandRecordingContext* commandContext,
|
||||||
|
@ -52,52 +163,6 @@ namespace dawn::native::metal {
|
||||||
commandContext->BeginRender(mtlRenderPassForResolve);
|
commandContext->BeginRender(mtlRenderPassForResolve);
|
||||||
commandContext->EndRender();
|
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
|
} // anonymous namespace
|
||||||
|
|
||||||
MTLCompareFunction ToMetalCompareFunction(wgpu::CompareFunction compareFunction) {
|
MTLCompareFunction ToMetalCompareFunction(wgpu::CompareFunction compareFunction) {
|
||||||
|
@ -370,18 +435,16 @@ namespace dawn::native::metal {
|
||||||
uint32_t width,
|
uint32_t width,
|
||||||
uint32_t height,
|
uint32_t height,
|
||||||
EncodeInsideRenderPass encodeInside) {
|
EncodeInsideRenderPass encodeInside) {
|
||||||
|
// This function handles multiple workarounds. Because some cases requires multiple
|
||||||
|
// workarounds to happen at the same time, it handles workarounds one by one and calls
|
||||||
|
// itself recursively to handle the next workaround if needed.
|
||||||
|
|
||||||
// Handle Toggle AlwaysResolveIntoZeroLevelAndLayer. We must handle this before applying
|
// Handle Toggle AlwaysResolveIntoZeroLevelAndLayer. We must handle this before applying
|
||||||
// the store + MSAA resolve workaround, otherwise this toggle will never be handled because
|
// 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.
|
// the resolve texture is removed when applying the store + MSAA resolve workaround.
|
||||||
if (device->IsToggleEnabled(Toggle::AlwaysResolveIntoZeroLevelAndLayer)) {
|
if (device->IsToggleEnabled(Toggle::AlwaysResolveIntoZeroLevelAndLayer)) {
|
||||||
std::array<id<MTLTexture>, kMaxColorAttachments> trueResolveTextures = {};
|
std::array<SavedMetalAttachment, kMaxColorAttachments> trueResolveAttachments = {};
|
||||||
std::array<uint32_t, kMaxColorAttachments> trueResolveLevels = {};
|
bool workaroundUsed = false;
|
||||||
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) {
|
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
|
||||||
if (mtlRenderPass.colorAttachments[i].resolveTexture == nullptr) {
|
if (mtlRenderPass.colorAttachments[i].resolveTexture == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -392,42 +455,80 @@ namespace dawn::native::metal {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
trueResolveTextures[i] = mtlRenderPass.colorAttachments[i].resolveTexture;
|
DAWN_TRY_ASSIGN(
|
||||||
trueResolveLevels[i] = mtlRenderPass.colorAttachments[i].resolveLevel;
|
trueResolveAttachments[i],
|
||||||
trueResolveSlices[i] = mtlRenderPass.colorAttachments[i].resolveSlice;
|
PatchResolveAttachmentWithTemporary(device, mtlRenderPass.colorAttachments[i]));
|
||||||
|
workaroundUsed = true;
|
||||||
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
|
// 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 (workaroundUsed) {
|
||||||
DAWN_TRY(EncodeMetalRenderPass(device, commandContext, mtlRenderPass, width, height,
|
DAWN_TRY(EncodeMetalRenderPass(device, commandContext, mtlRenderPass, width, height,
|
||||||
std::move(encodeInside)));
|
std::move(encodeInside)));
|
||||||
|
|
||||||
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
|
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
|
||||||
if (trueResolveTextures[i] == nullptr) {
|
if (trueResolveAttachments[i].texture == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(temporaryResolveTextures[i] != nullptr);
|
trueResolveAttachments[i].CopyFromTemporaryToAttachment(commandContext);
|
||||||
CopyIntoTrueResolveTarget(commandContext, trueResolveTextures[i],
|
}
|
||||||
trueResolveLevels[i], trueResolveSlices[i],
|
return {};
|
||||||
temporaryResolveTextures[i].Get(), width, height);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handles the workaround for r8unorm rg8unorm mipmap rendering being broken on some
|
||||||
|
// devices. Render to a temporary texture instead and then copy back to the attachment.
|
||||||
|
if (device->IsToggleEnabled(Toggle::MetalRenderR8RG8UnormSmallMipToTempTexture)) {
|
||||||
|
std::array<SavedMetalAttachment, kMaxColorAttachments> originalAttachments;
|
||||||
|
bool workaroundUsed = false;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
|
||||||
|
if (mtlRenderPass.colorAttachments[i].texture == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([mtlRenderPass.colorAttachments[i].texture pixelFormat] !=
|
||||||
|
MTLPixelFormatR8Unorm &&
|
||||||
|
[mtlRenderPass.colorAttachments[i].texture pixelFormat] !=
|
||||||
|
MTLPixelFormatRG8Unorm) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mtlRenderPass.colorAttachments[i].level < 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
DAWN_TRY_ASSIGN(
|
||||||
|
originalAttachments[i],
|
||||||
|
PatchAttachmentWithTemporary(device, mtlRenderPass.colorAttachments[i]));
|
||||||
|
workaroundUsed = true;
|
||||||
|
|
||||||
|
if (mtlRenderPass.colorAttachments[i].loadAction == MTLLoadActionLoad) {
|
||||||
|
originalAttachments[i].CopyFromAttachmentToTemporary(commandContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workaroundUsed) {
|
||||||
|
DAWN_TRY(EncodeMetalRenderPass(device, commandContext, mtlRenderPass, width, height,
|
||||||
|
std::move(encodeInside)));
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
|
||||||
|
if (originalAttachments[i].texture == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
originalAttachments[i].CopyFromTemporaryToAttachment(commandContext);
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Store + MSAA resolve workaround (Toggle EmulateStoreAndMSAAResolve).
|
// Handle Store + MSAA resolve workaround (Toggle EmulateStoreAndMSAAResolve).
|
||||||
|
// Done after the workarounds that modify the non-resolve attachments so that
|
||||||
|
// ResolveInAnotherRenderPass uses the temporary attachments if needed instead of the
|
||||||
|
// original ones.
|
||||||
if (device->IsToggleEnabled(Toggle::EmulateStoreAndMSAAResolve)) {
|
if (device->IsToggleEnabled(Toggle::EmulateStoreAndMSAAResolve)) {
|
||||||
bool hasStoreAndMSAAResolve = false;
|
bool hasStoreAndMSAAResolve = false;
|
||||||
|
|
||||||
|
@ -454,8 +555,19 @@ namespace dawn::native::metal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No (more) workarounds needed! We can finally encode the actual render pass.
|
||||||
|
commandContext->EndBlit();
|
||||||
DAWN_TRY(encodeInside(commandContext->BeginRender(mtlRenderPass)));
|
DAWN_TRY(encodeInside(commandContext->BeginRender(mtlRenderPass)));
|
||||||
commandContext->EndRender();
|
commandContext->EndRender();
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeError EncodeEmptyMetalRenderPass(Device* device,
|
||||||
|
CommandRecordingContext* commandContext,
|
||||||
|
MTLRenderPassDescriptor* mtlRenderPass,
|
||||||
|
Extent3D size) {
|
||||||
|
return EncodeMetalRenderPass(device, commandContext, mtlRenderPass, size.width, size.height,
|
||||||
|
[&](id<MTLRenderCommandEncoder>) -> MaybeError { return {}; });
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dawn::native::metal
|
} // namespace dawn::native::metal
|
||||||
|
|
|
@ -163,6 +163,8 @@ TEST_P(RenderPassTest, NoCorrespondingFragmentShaderOutputs) {
|
||||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kRed, renderTarget, kRTSize - 1, 1);
|
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kRed, renderTarget, kRTSize - 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class RenderPassTest_RegressionDawn1071 : public RenderPassTest {};
|
||||||
|
|
||||||
DAWN_INSTANTIATE_TEST(RenderPassTest,
|
DAWN_INSTANTIATE_TEST(RenderPassTest,
|
||||||
D3D12Backend(),
|
D3D12Backend(),
|
||||||
D3D12Backend({}, {"use_d3d12_render_pass"}),
|
D3D12Backend({}, {"use_d3d12_render_pass"}),
|
||||||
|
@ -170,3 +172,61 @@ DAWN_INSTANTIATE_TEST(RenderPassTest,
|
||||||
OpenGLBackend(),
|
OpenGLBackend(),
|
||||||
OpenGLESBackend(),
|
OpenGLESBackend(),
|
||||||
VulkanBackend());
|
VulkanBackend());
|
||||||
|
|
||||||
|
// Test that clearing the lower mips of an R8Unorm texture works. This is a regression test for
|
||||||
|
// dawn:1071 where Intel Metal devices fail to do that correctly, requiring a workaround.
|
||||||
|
TEST_P(RenderPassTest_RegressionDawn1071, ClearLowestMipOfR8Unorm) {
|
||||||
|
const uint32_t kLastMipLevel = 2;
|
||||||
|
|
||||||
|
// Create the texture and buffer used for readback.
|
||||||
|
wgpu::TextureDescriptor texDesc;
|
||||||
|
texDesc.format = wgpu::TextureFormat::R8Unorm;
|
||||||
|
texDesc.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc;
|
||||||
|
texDesc.size = {32, 32};
|
||||||
|
texDesc.mipLevelCount = kLastMipLevel + 1;
|
||||||
|
wgpu::Texture tex = device.CreateTexture(&texDesc);
|
||||||
|
|
||||||
|
wgpu::BufferDescriptor bufDesc;
|
||||||
|
bufDesc.size = 4;
|
||||||
|
bufDesc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::CopySrc;
|
||||||
|
wgpu::Buffer buf = device.CreateBuffer(&bufDesc);
|
||||||
|
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
|
||||||
|
// Clear the texture with a render pass.
|
||||||
|
{
|
||||||
|
wgpu::TextureViewDescriptor viewDesc;
|
||||||
|
viewDesc.baseMipLevel = kLastMipLevel;
|
||||||
|
|
||||||
|
utils::ComboRenderPassDescriptor renderPass({tex.CreateView(&viewDesc)});
|
||||||
|
renderPass.cColorAttachments[0].clearValue = {1.0f, 0.0f, 0.0f, 1.0f};
|
||||||
|
renderPass.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear;
|
||||||
|
renderPass.cColorAttachments[0].storeOp = wgpu::StoreOp::Store;
|
||||||
|
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
|
||||||
|
pass.End();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the texture in the buffer.
|
||||||
|
{
|
||||||
|
wgpu::Extent3D copySize = {1, 1};
|
||||||
|
wgpu::ImageCopyTexture src = utils::CreateImageCopyTexture(tex, kLastMipLevel);
|
||||||
|
wgpu::ImageCopyBuffer dst = utils::CreateImageCopyBuffer(buf);
|
||||||
|
|
||||||
|
encoder.CopyTextureToBuffer(&src, &dst, ©Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::CommandBuffer commands = encoder.Finish();
|
||||||
|
queue.Submit(1, &commands);
|
||||||
|
|
||||||
|
// The content of the texture should be reflected in the buffer (prior to the workaround it
|
||||||
|
// would be 0s).
|
||||||
|
EXPECT_BUFFER_U8_EQ(255, buf, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
DAWN_INSTANTIATE_TEST(RenderPassTest_RegressionDawn1071,
|
||||||
|
D3D12Backend(),
|
||||||
|
MetalBackend(),
|
||||||
|
MetalBackend({"metal_render_r8_rg8_unorm_small_mip_to_temp_texture"}),
|
||||||
|
OpenGLBackend(),
|
||||||
|
OpenGLESBackend(),
|
||||||
|
VulkanBackend());
|
||||||
|
|
|
@ -77,13 +77,6 @@ crbug.com/dawn/1111 [ intel-0x5912 ] webgpu:shader,execution,zero_init:compute,z
|
||||||
crbug.com/dawn/1111 [ intel-0x5912 ] webgpu:shader,execution,zero_init:compute,zero_init:storageClass="workgroup";workgroupSize=[7,7,3];batch__=1 [ Failure ]
|
crbug.com/dawn/1111 [ intel-0x5912 ] webgpu:shader,execution,zero_init:compute,zero_init:storageClass="workgroup";workgroupSize=[7,7,3];batch__=1 [ Failure ]
|
||||||
crbug.com/dawn/1111 [ intel-0x5912 ] webgpu:shader,execution,zero_init:compute,zero_init:storageClass="workgroup";workgroupSize=[8,8,2];batch__=1 [ Failure ]
|
crbug.com/dawn/1111 [ intel-0x5912 ] webgpu:shader,execution,zero_init:compute,zero_init:storageClass="workgroup";workgroupSize=[8,8,2];batch__=1 [ Failure ]
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# webgpu:api,operation,command_buffer,image_copy:mip_levels
|
|
||||||
# Partial failures on all platforms
|
|
||||||
# KEEP
|
|
||||||
################################################################################
|
|
||||||
crbug.com/dawn/0000 webgpu:api,operation,command_buffer,image_copy:mip_levels:* [ Failure ]
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero
|
# webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero
|
||||||
# Spec / CTS bugs because depth24unorm-stencil8 depth-specific format is depth24plus
|
# Spec / CTS bugs because depth24unorm-stencil8 depth-specific format is depth24plus
|
||||||
|
@ -112,18 +105,6 @@ crbug.com/dawn/1389 [ mac ] webgpu:api,operation,resource_init,texture_zero:unin
|
||||||
crbug.com/dawn/1389 [ mac ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";readMethod="CopyToBuffer";format="stencil8" [ Failure ]
|
crbug.com/dawn/1389 [ mac ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";readMethod="CopyToBuffer";format="stencil8" [ Failure ]
|
||||||
crbug.com/dawn/1389 [ mac ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";readMethod="CopyToTexture";format="stencil8" [ Failure ]
|
crbug.com/dawn/1389 [ mac ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";readMethod="CopyToTexture";format="stencil8" [ Failure ]
|
||||||
crbug.com/dawn/1389 [ mac ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";readMethod="StencilTest";format="stencil8" [ Failure ]
|
crbug.com/dawn/1389 [ mac ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";readMethod="StencilTest";format="stencil8" [ Failure ]
|
||||||
crbug.com/dawn/1071 [ mac ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";readMethod="CopyToBuffer";format="r8unorm" [ Failure ]
|
|
||||||
crbug.com/dawn/1071 [ mac ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";readMethod="CopyToTexture";format="r8unorm" [ Failure ]
|
|
||||||
crbug.com/dawn/1071 [ mac ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";readMethod="Sample";format="r8unorm" [ Failure ]
|
|
||||||
crbug.com/dawn/1071 [ mac ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";readMethod="CopyToBuffer";format="rg8unorm" [ Failure ]
|
|
||||||
crbug.com/dawn/1071 [ mac ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";readMethod="CopyToTexture";format="rg8unorm" [ Failure ]
|
|
||||||
crbug.com/dawn/1071 [ mac ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="2d";readMethod="Sample";format="rg8unorm" [ Failure ]
|
|
||||||
crbug.com/dawn/1071 [ mac ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="3d";readMethod="CopyToBuffer";format="r8unorm" [ Failure ]
|
|
||||||
crbug.com/dawn/1071 [ mac ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="3d";readMethod="CopyToTexture";format="r8unorm" [ Failure ]
|
|
||||||
crbug.com/dawn/1071 [ mac ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="3d";readMethod="Sample";format="r8unorm" [ Failure ]
|
|
||||||
crbug.com/dawn/1071 [ mac ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="3d";readMethod="CopyToBuffer";format="rg8unorm" [ Failure ]
|
|
||||||
crbug.com/dawn/1071 [ mac ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="3d";readMethod="CopyToTexture";format="rg8unorm" [ Failure ]
|
|
||||||
crbug.com/dawn/1071 [ mac ] webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero:dimension="3d";readMethod="Sample";format="rg8unorm" [ Failure ]
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero
|
# webgpu:api,operation,resource_init,texture_zero:uninitialized_texture_is_zero
|
||||||
|
@ -355,18 +336,12 @@ crbug.com/dawn/1325 webgpu:api,validation,attachment_compatibility:render_pass_o
|
||||||
################################################################################
|
################################################################################
|
||||||
crbug.com/dawn/0000 [ mac ] webgpu:api,operation,command_buffer,copyTextureToTexture:copy_depth_stencil:format="depth32float" [ Failure ]
|
crbug.com/dawn/0000 [ mac ] webgpu:api,operation,command_buffer,copyTextureToTexture:copy_depth_stencil:format="depth32float" [ Failure ]
|
||||||
crbug.com/dawn/0000 [ win ] webgpu:api,operation,render_pass,resolve:* [ Failure ]
|
crbug.com/dawn/0000 [ win ] webgpu:api,operation,render_pass,resolve:* [ Failure ]
|
||||||
crbug.com/dawn/0000 [ mac ] webgpu:api,operation,render_pass,storeOp:render_pass_store_op,color_attachment_only:colorFormat="r8unorm";* [ Failure ]
|
|
||||||
crbug.com/dawn/0000 [ mac ] webgpu:api,operation,render_pass,storeOp:render_pass_store_op,color_attachment_only:colorFormat="rg8unorm";* [ Failure ]
|
|
||||||
crbug.com/dawn/0000 [ win ] webgpu:api,operation,render_pipeline,pipeline_output_targets:color,component_count,blend:format="rg8unorm" [ Failure ]
|
crbug.com/dawn/0000 [ win ] webgpu:api,operation,render_pipeline,pipeline_output_targets:color,component_count,blend:format="rg8unorm" [ Failure ]
|
||||||
crbug.com/dawn/0000 [ win ] webgpu:shader,execution,robust_access_vertex:vertex_buffer_access:indexed=true;indirect=true;drawCallTestParameter="baseVertex";* [ Failure ]
|
crbug.com/dawn/0000 [ win ] webgpu:shader,execution,robust_access_vertex:vertex_buffer_access:indexed=true;indirect=true;drawCallTestParameter="baseVertex";* [ Failure ]
|
||||||
crbug.com/1236130 [ linux ] webgpu:web_platform,canvas,readbackFromWebGPUCanvas:* [ Skip ] # crashes (skip because there are very many)
|
crbug.com/1236130 [ linux ] webgpu:web_platform,canvas,readbackFromWebGPUCanvas:* [ Skip ] # crashes (skip because there are very many)
|
||||||
crbug.com/dawn/0000 [ mac ] webgpu:web_platform,canvas,readbackFromWebGPUCanvas:* [ Failure ]
|
crbug.com/dawn/0000 [ mac ] webgpu:web_platform,canvas,readbackFromWebGPUCanvas:* [ Failure ]
|
||||||
crbug.com/1309194 [ linux ] webgpu:web_platform,copyToTexture,canvas:copy_contents_from_2d_context_canvas:* [ Skip ] # crashes (skip because there are very many)
|
crbug.com/1309194 [ linux ] webgpu:web_platform,copyToTexture,canvas:copy_contents_from_2d_context_canvas:* [ Skip ] # crashes (skip because there are very many)
|
||||||
crbug.com/1309194 [ linux ] webgpu:web_platform,copyToTexture,canvas:copy_contents_from_gl_context_canvas:* [ Skip ] # crashes (skip because there are very many)
|
crbug.com/1309194 [ linux ] webgpu:web_platform,copyToTexture,canvas:copy_contents_from_gl_context_canvas:* [ Skip ] # crashes (skip because there are very many)
|
||||||
crbug.com/dawn/0000 [ mac ] worker_webgpu:api,operation,render_pass,storeOp:render_pass_store_op,color_attachment_only:colorFormat="r8unorm";storeOperation="discard" [ Failure ]
|
|
||||||
crbug.com/dawn/0000 [ mac ] worker_webgpu:api,operation,render_pass,storeOp:render_pass_store_op,color_attachment_only:colorFormat="r8unorm";storeOperation="store" [ Failure ]
|
|
||||||
crbug.com/dawn/0000 [ mac ] worker_webgpu:api,operation,render_pass,storeOp:render_pass_store_op,color_attachment_only:colorFormat="rg8unorm";storeOperation="discard" [ Failure ]
|
|
||||||
crbug.com/dawn/0000 [ mac ] worker_webgpu:api,operation,render_pass,storeOp:render_pass_store_op,color_attachment_only:colorFormat="rg8unorm";storeOperation="store" [ Failure ]
|
|
||||||
crbug.com/dawn/0000 [ mac ] worker_webgpu:api,operation,render_pass,storeOp:render_pass_store_op,depth_stencil_attachment_only:depthStencilFormat="stencil8";* [ Failure ]
|
crbug.com/dawn/0000 [ mac ] worker_webgpu:api,operation,render_pass,storeOp:render_pass_store_op,depth_stencil_attachment_only:depthStencilFormat="stencil8";* [ Failure ]
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
Loading…
Reference in New Issue