Metal: Validate max render target size without an allocation

We would allocate a MTLRenderPassDescriptor for validating an internal
error case only to throw it away immediately afterwards. This happened
on every new render pass.

This allocation/release amounts to about 10% of ANGLE's CPU time when
running Chrome.

Bug: chromium:1466696
Change-Id: I0bbe086c0b8006d2ff15ae57f25b591f791acb60
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4706925
Commit-Queue: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
This commit is contained in:
Geoff Lang
2023-07-20 17:24:09 -04:00
committed by Angle LUCI CQ
parent 085f25bbb1
commit f586ec98d9
3 changed files with 39 additions and 51 deletions

View File

@@ -1907,22 +1907,16 @@ mtl::RenderCommandEncoder *ContextMtl::getRenderPassCommandEncoder(const mtl::Re
const mtl::ContextDevice &metalDevice = getMetalDevice();
if (mtl::DeviceHasMaximumRenderTargetSize(metalDevice))
{
ANGLE_MTL_OBJC_SCOPE
NSUInteger maxSize = mtl::GetMaxRenderTargetSizeForDeviceInBytes(metalDevice);
NSUInteger renderTargetSize =
ComputeTotalSizeUsedForMTLRenderPassDescriptor(desc, this, metalDevice);
if (renderTargetSize > maxSize)
{
MTLRenderPassDescriptor *objCDesc = [MTLRenderPassDescriptor renderPassDescriptor];
desc.convertToMetalDesc(objCDesc, getNativeCaps().maxColorAttachments);
NSUInteger maxSize = mtl::GetMaxRenderTargetSizeForDeviceInBytes(metalDevice);
NSUInteger renderTargetSize =
ComputeTotalSizeUsedForMTLRenderPassDescriptor(objCDesc, this, metalDevice);
if (renderTargetSize > maxSize)
{
std::stringstream errorStream;
errorStream << "This set of render targets requires " << renderTargetSize
<< " bytes of pixel storage. This device supports " << maxSize
<< " bytes.";
ANGLE_MTL_HANDLE_ERROR(this, errorStream.str().c_str(), GL_INVALID_OPERATION);
return nil;
}
std::stringstream errorStream;
errorStream << "This set of render targets requires " << renderTargetSize
<< " bytes of pixel storage. This device supports " << maxSize << " bytes.";
ANGLE_MTL_HANDLE_ERROR(this, errorStream.str().c_str(), GL_INVALID_OPERATION);
return nullptr;
}
}
return &mRenderEncoder.restart(desc, getNativeCaps().maxColorAttachments);

View File

@@ -185,7 +185,7 @@ bool DeviceHasMaximumRenderTargetSize(id<MTLDevice> device);
// has alpha channel.
MTLClearColor EmulatedAlphaClearColor(MTLClearColor color, MTLColorWriteMask colorMask);
NSUInteger ComputeTotalSizeUsedForMTLRenderPassDescriptor(const MTLRenderPassDescriptor *descriptor,
NSUInteger ComputeTotalSizeUsedForMTLRenderPassDescriptor(const mtl::RenderPassDesc &descriptor,
const Context *context,
const mtl::ContextDevice &device);

View File

@@ -1577,7 +1577,24 @@ static NSUInteger getNextLocationForFormat(const FormatCaps &caps,
return currentRenderTargetSize;
}
NSUInteger ComputeTotalSizeUsedForMTLRenderPassDescriptor(const MTLRenderPassDescriptor *descriptor,
static NSUInteger getNextLocationForAttachment(const mtl::RenderPassAttachmentDesc &attachment,
const Context *context,
NSUInteger currentRenderTargetSize)
{
mtl::TextureRef texture =
attachment.implicitMSTexture ? attachment.implicitMSTexture : attachment.texture;
if (texture)
{
MTLPixelFormat pixelFormat = texture->pixelFormat();
bool isMsaa = texture->samples();
const FormatCaps &caps = context->getDisplay()->getNativeFormatCaps(pixelFormat);
currentRenderTargetSize = getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize);
}
return currentRenderTargetSize;
}
NSUInteger ComputeTotalSizeUsedForMTLRenderPassDescriptor(const mtl::RenderPassDesc &descriptor,
const Context *context,
const mtl::ContextDevice &device)
{
@@ -1585,48 +1602,25 @@ NSUInteger ComputeTotalSizeUsedForMTLRenderPassDescriptor(const MTLRenderPassDes
for (NSUInteger i = 0; i < GetMaxNumberOfRenderTargetsForDevice(device); i++)
{
MTLPixelFormat pixelFormat = descriptor.colorAttachments[i].texture.pixelFormat;
bool isMsaa = descriptor.colorAttachments[i].texture.sampleCount > 1;
if (pixelFormat != MTLPixelFormatInvalid)
{
const FormatCaps &caps = context->getDisplay()->getNativeFormatCaps(pixelFormat);
currentRenderTargetSize =
getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize);
}
currentRenderTargetSize = getNextLocationForAttachment(descriptor.colorAttachments[i],
context, currentRenderTargetSize);
}
if (descriptor.depthAttachment.texture.pixelFormat ==
descriptor.stencilAttachment.texture.pixelFormat)
if (descriptor.depthAttachment.texture == descriptor.stencilAttachment.texture)
{
bool isMsaa = descriptor.depthAttachment.texture.sampleCount > 1;
if (descriptor.depthAttachment.texture.pixelFormat != MTLPixelFormatInvalid)
{
const FormatCaps &caps = context->getDisplay()->getNativeFormatCaps(
descriptor.depthAttachment.texture.pixelFormat);
currentRenderTargetSize =
getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize);
}
currentRenderTargetSize = getNextLocationForAttachment(descriptor.depthAttachment, context,
currentRenderTargetSize);
}
else
{
if (descriptor.depthAttachment.texture.pixelFormat != MTLPixelFormatInvalid)
{
bool isMsaa = descriptor.depthAttachment.texture.sampleCount > 1;
const FormatCaps &caps = context->getDisplay()->getNativeFormatCaps(
descriptor.depthAttachment.texture.pixelFormat);
currentRenderTargetSize =
getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize);
}
if (descriptor.stencilAttachment.texture.pixelFormat != MTLPixelFormatInvalid)
{
bool isMsaa = descriptor.stencilAttachment.texture.sampleCount > 1;
const FormatCaps &caps = context->getDisplay()->getNativeFormatCaps(
descriptor.stencilAttachment.texture.pixelFormat);
currentRenderTargetSize =
getNextLocationForFormat(caps, isMsaa, currentRenderTargetSize);
}
currentRenderTargetSize = getNextLocationForAttachment(descriptor.depthAttachment, context,
currentRenderTargetSize);
currentRenderTargetSize = getNextLocationForAttachment(descriptor.stencilAttachment,
context, currentRenderTargetSize);
}
return currentRenderTargetSize;
}
NSUInteger ComputeTotalSizeUsedForMTLRenderPipelineDescriptor(
const MTLRenderPipelineDescriptor *descriptor,
const Context *context,