Enable MSAA for Metal.
Adds a separate resolve texture to GrMtlRenderTarget, which can be used
to do a resolve for the main multisample color texture. The resolve is
handled by setting a special Store action for the RenderCommandEncoder.
Bug: skia:8243
Change-Id: I1ffd756c01a9b363116ffefee2c4c50ba9a3e637
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/225536
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
diff --git a/src/gpu/mtl/GrMtlCaps.h b/src/gpu/mtl/GrMtlCaps.h
index 0acd33a..d431022 100644
--- a/src/gpu/mtl/GrMtlCaps.h
+++ b/src/gpu/mtl/GrMtlCaps.h
@@ -59,6 +59,9 @@
int srcSampleCount, const SkIRect& srcRect, const SkIPoint& dstPoint,
bool areDstSrcSameObj) const;
+ bool canCopyAsResolve(GrSurface* dst, int dstSampleCount, GrSurface* src, int srcSampleCount,
+ const SkIRect& srcRect, const SkIPoint& dstPoint) const;
+
bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc,
bool* rectsMustMatch, bool* disallowSubrect) const override {
return false;
@@ -104,9 +107,8 @@
kMSAA_Flag = 0x4,
kResolve_Flag = 0x8,
};
- // TODO: Put kMSAA_Flag back when MSAA is implemented
static const uint16_t kAllFlags = kTextureable_Flag | kRenderable_Flag |
- /*kMSAA_Flag |*/ kResolve_Flag;
+ kMSAA_Flag | kResolve_Flag;
uint16_t fFlags;
};
diff --git a/src/gpu/mtl/GrMtlCaps.mm b/src/gpu/mtl/GrMtlCaps.mm
index 5edc5b7..e8910c7 100644
--- a/src/gpu/mtl/GrMtlCaps.mm
+++ b/src/gpu/mtl/GrMtlCaps.mm
@@ -37,7 +37,6 @@
// doesn't support it.
fFenceSyncSupport = false; // Fences are not implemented yet
fSemaphoreSupport = false; // Semaphores are not implemented yet
- fMultisampleDisableSupport = true; // MSAA and resolving not implemented yet
fCrossContextTextureSupport = false; // GrMtlGpu::prepareTextureForCrossContextUsage() not impl
}
@@ -137,6 +136,30 @@
return true;
}
+bool GrMtlCaps::canCopyAsResolve(GrSurface* dst, int dstSampleCount,
+ GrSurface* src, int srcSampleCount,
+ const SkIRect& srcRect, const SkIPoint& dstPoint) const {
+ if (dst == src) {
+ return false;
+ }
+ if (dst->backendFormat() != src->backendFormat()) {
+ return false;
+ }
+ if (dstSampleCount > 1 || srcSampleCount == 1 || !src->asRenderTarget()) {
+ return false;
+ }
+
+ // TODO: Support copying subrectangles
+ if (dstPoint != SkIPoint::Make(0, 0)) {
+ return false;
+ }
+ if (srcRect != SkIRect::MakeXYWH(0, 0, src->width(), src->height())) {
+ return false;
+ }
+
+ return true;
+}
+
bool GrMtlCaps::onCanCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src,
const SkIRect& srcRect, const SkIPoint& dstPoint) const {
int dstSampleCnt = 0;
diff --git a/src/gpu/mtl/GrMtlCommandBuffer.mm b/src/gpu/mtl/GrMtlCommandBuffer.mm
index 7b4cd54..c6b3480 100644
--- a/src/gpu/mtl/GrMtlCommandBuffer.mm
+++ b/src/gpu/mtl/GrMtlCommandBuffer.mm
@@ -59,8 +59,9 @@
first.storeAction == MTLStoreActionDontCare;
bool loadActionsValid = second.loadAction == MTLLoadActionLoad ||
second.loadAction == MTLLoadActionDontCare;
- bool secondDoesntSampleFirst = !pipelineState ||
- pipelineState->doesntSampleAttachment(first);
+ bool secondDoesntSampleFirst = (!pipelineState ||
+ pipelineState->doesntSampleAttachment(first)) &&
+ second.storeAction != MTLStoreActionMultisampleResolve;
return renderTargetsMatch &&
(nil == first.texture ||
@@ -81,7 +82,9 @@
this->endAllEncoding();
fActiveRenderCommandEncoder = [fCmdBuffer renderCommandEncoderWithDescriptor:descriptor];
- gpuCommandBuffer->initRenderState(fActiveRenderCommandEncoder);
+ if (gpuCommandBuffer) {
+ gpuCommandBuffer->initRenderState(fActiveRenderCommandEncoder);
+ }
fPreviousRenderPassDescriptor = descriptor;
return fActiveRenderCommandEncoder;
diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h
index cd26919..209f73c 100644
--- a/src/gpu/mtl/GrMtlGpu.h
+++ b/src/gpu/mtl/GrMtlGpu.h
@@ -72,7 +72,9 @@
void testingOnly_flushGpuAndSync() override;
#endif
- bool copySurfaceAsBlit(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
+ void copySurfaceAsResolve(GrSurface* dst, GrSurface* src);
+
+ void copySurfaceAsBlit(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
const SkIPoint& dstPoint);
bool onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
@@ -114,6 +116,10 @@
this->didWriteToSurface(surface, origin, bounds);
}
+ void resolveRenderTargetNoFlush(GrRenderTarget* target) {
+ this->internalResolveRenderTarget(target, false);
+ }
+
private:
GrMtlGpu(GrContext* context, const GrContextOptions& options,
id<MTLDevice> device, id<MTLCommandQueue> queue, MTLFeatureSet featureSet);
@@ -171,7 +177,15 @@
bool onRegenerateMipMapLevels(GrTexture*) override;
- void onResolveRenderTarget(GrRenderTarget* target) override { return; }
+ void onResolveRenderTarget(GrRenderTarget* target) override {
+ // This resolve is called when we are preparing an msaa surface for external I/O. It is
+ // called after flushing, so we need to make sure we submit the command buffer after doing
+ // the resolve so that the resolve actually happens.
+ this->internalResolveRenderTarget(target, true);
+ }
+
+ void internalResolveRenderTarget(GrRenderTarget* target, bool requiresSubmit);
+ void resolveTexture(id<MTLTexture> colorTexture, id<MTLTexture> resolveTexture);
void onFinishFlush(GrSurfaceProxy*[], int n, SkSurface::BackendSurfaceAccess access,
const GrFlushInfo& info, const GrPrepareForExternalIORequests&) override {
diff --git a/src/gpu/mtl/GrMtlGpu.mm b/src/gpu/mtl/GrMtlGpu.mm
index 8761b95..1e869ce 100644
--- a/src/gpu/mtl/GrMtlGpu.mm
+++ b/src/gpu/mtl/GrMtlGpu.mm
@@ -436,7 +436,6 @@
texDesc.mipmapLevelCount = mipLevels;
texDesc.sampleCount = 1;
texDesc.arrayLength = 1;
- texDesc.cpuCacheMode = MTLCPUCacheModeWriteCombined;
// Make all textures have private gpu only access. We can use transfer buffers or textures
// to copy to them.
texDesc.storageMode = MTLStorageModePrivate;
@@ -455,10 +454,10 @@
}
if (renderTarget) {
- tex = GrMtlTextureRenderTarget::CreateNewTextureRenderTarget(this, budgeted,
- desc, texDesc, mipMapsStatus);
+ tex = GrMtlTextureRenderTarget::MakeNewTextureRenderTarget(this, budgeted,
+ desc, texDesc, mipMapsStatus);
} else {
- tex = GrMtlTexture::CreateNewTexture(this, budgeted, desc, texDesc, mipMapsStatus);
+ tex = GrMtlTexture::MakeNewTexture(this, budgeted, desc, texDesc, mipMapsStatus);
}
if (!tex) {
@@ -863,7 +862,23 @@
return 0;
}
-bool GrMtlGpu::copySurfaceAsBlit(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
+void GrMtlGpu::copySurfaceAsResolve(GrSurface* dst, GrSurface* src) {
+ // TODO: Add support for subrectangles
+ GrMtlRenderTarget* srcRT = static_cast<GrMtlRenderTarget*>(src->asRenderTarget());
+ GrRenderTarget* dstRT = dst->asRenderTarget();
+ id<MTLTexture> dstTexture;
+ if (dstRT) {
+ GrMtlRenderTarget* mtlRT = static_cast<GrMtlRenderTarget*>(dstRT);
+ dstTexture = mtlRT->mtlColorTexture();
+ } else {
+ SkASSERT(dst->asTexture());
+ dstTexture = static_cast<GrMtlTexture*>(dst->asTexture())->mtlTexture();
+ }
+
+ this->resolveTexture(dstTexture, srcRT->mtlColorTexture());
+}
+
+void GrMtlGpu::copySurfaceAsBlit(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
const SkIPoint& dstPoint) {
#ifdef SK_DEBUG
int dstSampleCnt = get_surface_sample_cnt(dst);
@@ -871,8 +886,8 @@
SkASSERT(this->mtlCaps().canCopyAsBlit(dst->config(), dstSampleCnt, src->config(), srcSampleCnt,
srcRect, dstPoint, dst == src));
#endif
- id<MTLTexture> dstTex = GrGetMTLTextureFromSurface(dst, false);
- id<MTLTexture> srcTex = GrGetMTLTextureFromSurface(src, false);
+ id<MTLTexture> dstTex = GrGetMTLTextureFromSurface(dst);
+ id<MTLTexture> srcTex = GrGetMTLTextureFromSurface(src);
id<MTLBlitCommandEncoder> blitCmdEncoder = this->commandBuffer()->getBlitCommandEncoder();
[blitCmdEncoder copyFromTexture: srcTex
@@ -884,12 +899,11 @@
destinationSlice: 0
destinationLevel: 0
destinationOrigin: MTLOriginMake(dstPoint.fX, dstPoint.fY, 0)];
-
- return true;
}
bool GrMtlGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
const SkIPoint& dstPoint, bool canDiscardOutsideDstRect) {
+ SkASSERT(!src->isProtected() && !dst->isProtected());
GrPixelConfig dstConfig = dst->config();
GrPixelConfig srcConfig = src->config();
@@ -897,15 +911,14 @@
int dstSampleCnt = get_surface_sample_cnt(dst);
int srcSampleCnt = get_surface_sample_cnt(src);
- if (dstSampleCnt > 1 || srcSampleCnt > 1) {
- SkASSERT(false); // Currently dont support MSAA. TODO: add copySurfaceAsResolve().
- return false;
- }
-
bool success = false;
- if (this->mtlCaps().canCopyAsBlit(dstConfig, dstSampleCnt, srcConfig, srcSampleCnt, srcRect,
- dstPoint, dst == src)) {
- success = this->copySurfaceAsBlit(dst, src, srcRect, dstPoint);
+ if (this->mtlCaps().canCopyAsResolve(dst, dstSampleCnt, src, srcSampleCnt, srcRect, dstPoint)) {
+ this->copySurfaceAsResolve(dst, src);
+ success = true;
+ } else if (this->mtlCaps().canCopyAsBlit(dstConfig, dstSampleCnt, srcConfig, srcSampleCnt,
+ srcRect, dstPoint, dst == src)) {
+ this->copySurfaceAsBlit(dst, src, srcRect, dstPoint);
+ success = true;
}
if (success) {
SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.x(), dstPoint.y(),
@@ -949,9 +962,32 @@
int bpp = GrColorTypeBytesPerPixel(dstColorType);
size_t transBufferRowBytes = bpp * width;
- bool doResolve = get_surface_sample_cnt(surface) > 1;
- id<MTLTexture> mtlTexture = GrGetMTLTextureFromSurface(surface, doResolve);
- if (!mtlTexture || [mtlTexture isFramebufferOnly]) {
+
+ id<MTLTexture> mtlTexture;
+ GrMtlRenderTarget* rt = static_cast<GrMtlRenderTarget*>(surface->asRenderTarget());
+ if (rt) {
+ // resolve the render target if necessary
+ switch (rt->getResolveType()) {
+ case GrMtlRenderTarget::kCantResolve_ResolveType:
+ return false;
+ case GrMtlRenderTarget::kAutoResolves_ResolveType:
+ mtlTexture = rt->mtlColorTexture();
+ break;
+ case GrMtlRenderTarget::kCanResolve_ResolveType:
+ this->resolveRenderTargetNoFlush(rt);
+ mtlTexture = rt->mtlResolveTexture();
+ break;
+ default:
+ SK_ABORT("Unknown resolve type");
+ }
+ } else {
+ GrMtlTexture* texture = static_cast<GrMtlTexture*>(surface->asTexture());
+ if (texture) {
+ mtlTexture = texture->mtlTexture();
+ }
+ }
+
+ if (!mtlTexture) {
return false;
}
@@ -988,6 +1024,33 @@
SkRectMemcpy(buffer, rowBytes, mappedMemory, transBufferRowBytes, transBufferRowBytes, height);
return true;
-
}
+void GrMtlGpu::internalResolveRenderTarget(GrRenderTarget* target, bool requiresSubmit) {
+ if (target->needsResolve()) {
+ this->resolveTexture(static_cast<GrMtlRenderTarget*>(target)->mtlResolveTexture(),
+ static_cast<GrMtlRenderTarget*>(target)->mtlColorTexture());
+ target->flagAsResolved();
+
+ if (requiresSubmit) {
+ this->submitCommandBuffer(kSkip_SyncQueue);
+ }
+ }
+}
+
+void GrMtlGpu::resolveTexture(id<MTLTexture> resolveTexture, id<MTLTexture> colorTexture) {
+ auto renderPassDesc = [MTLRenderPassDescriptor renderPassDescriptor];
+ renderPassDesc.colorAttachments[0].texture = colorTexture;
+ renderPassDesc.colorAttachments[0].slice = 0;
+ renderPassDesc.colorAttachments[0].level = 0;
+ renderPassDesc.colorAttachments[0].resolveTexture = resolveTexture;
+ renderPassDesc.colorAttachments[0].slice = 0;
+ renderPassDesc.colorAttachments[0].level = 0;
+ renderPassDesc.colorAttachments[0].loadAction = MTLLoadActionLoad;
+ renderPassDesc.colorAttachments[0].storeAction = MTLStoreActionMultisampleResolve;
+
+ id<MTLRenderCommandEncoder> cmdEncoder =
+ this->commandBuffer()->getRenderCommandEncoder(renderPassDesc, nullptr, nullptr);
+ SkASSERT(nil != cmdEncoder);
+ cmdEncoder.label = @"resolveTexture";
+}
diff --git a/src/gpu/mtl/GrMtlGpuCommandBuffer.mm b/src/gpu/mtl/GrMtlGpuCommandBuffer.mm
index 5acd422..e03efec 100644
--- a/src/gpu/mtl/GrMtlGpuCommandBuffer.mm
+++ b/src/gpu/mtl/GrMtlGpuCommandBuffer.mm
@@ -15,6 +15,7 @@
#include "src/gpu/mtl/GrMtlPipelineState.h"
#include "src/gpu/mtl/GrMtlPipelineStateBuilder.h"
#include "src/gpu/mtl/GrMtlRenderTarget.h"
+#include "src/gpu/mtl/GrMtlTexture.h"
#if !__has_feature(objc_arc)
#error This file must be compiled with Arc. Use -fobjc-arc flag
@@ -113,6 +114,13 @@
}
auto prepareSampledImage = [&](GrTexture* texture, GrSamplerState::Filter filter) {
+ GrMtlTexture* mtlTexture = static_cast<GrMtlTexture*>(texture);
+ // We may need to resolve the texture first if it is also a render target
+ GrMtlRenderTarget* texRT = static_cast<GrMtlRenderTarget*>(mtlTexture->asRenderTarget());
+ if (texRT) {
+ fGpu->resolveRenderTargetNoFlush(texRT);
+ }
+
// Check if we need to regenerate any mip maps
if (GrSamplerState::Filter::kMipMap == filter &&
(texture->width() != 1 || texture->height() != 1)) {
@@ -238,6 +246,7 @@
}
void GrMtlGpuRTCommandBuffer::initRenderState(id<MTLRenderCommandEncoder> encoder) {
+ [encoder pushDebugGroup:@"initRenderState"];
[encoder setFrontFacingWinding:MTLWindingCounterClockwise];
// Strictly speaking we shouldn't have to set this, as the default viewport is the size of
// the drawable used to generate the renderCommandEncoder -- but just in case.
@@ -246,6 +255,7 @@
0.0, 1.0 };
[encoder setViewport:viewport];
this->resetBufferBindings();
+ [encoder popDebugGroup];
}
void GrMtlGpuRTCommandBuffer::setupRenderPass(
@@ -273,7 +283,7 @@
auto renderPassDesc = [MTLRenderPassDescriptor renderPassDescriptor];
renderPassDesc.colorAttachments[0].texture =
- static_cast<GrMtlRenderTarget*>(fRenderTarget)->mtlRenderTexture();
+ static_cast<GrMtlRenderTarget*>(fRenderTarget)->mtlColorTexture();
renderPassDesc.colorAttachments[0].slice = 0;
renderPassDesc.colorAttachments[0].level = 0;
const SkPMColor4f& clearColor = colorInfo.fClearColor;
diff --git a/src/gpu/mtl/GrMtlPipelineState.mm b/src/gpu/mtl/GrMtlPipelineState.mm
index 9e3ac53..f7a9910 100644
--- a/src/gpu/mtl/GrMtlPipelineState.mm
+++ b/src/gpu/mtl/GrMtlPipelineState.mm
@@ -116,9 +116,11 @@
void GrMtlPipelineState::setDrawState(id<MTLRenderCommandEncoder> renderCmdEncoder,
const GrSwizzle& outputSwizzle,
const GrXferProcessor& xferProcessor) {
+ [renderCmdEncoder pushDebugGroup:@"setDrawState"];
this->bind(renderCmdEncoder);
this->setBlendConstants(renderCmdEncoder, outputSwizzle, xferProcessor);
this->setDepthStencilState(renderCmdEncoder);
+ [renderCmdEncoder popDebugGroup];
}
void GrMtlPipelineState::bind(id<MTLRenderCommandEncoder> renderCmdEncoder) {
diff --git a/src/gpu/mtl/GrMtlPipelineStateBuilder.mm b/src/gpu/mtl/GrMtlPipelineStateBuilder.mm
index 6f636a9..f580161 100644
--- a/src/gpu/mtl/GrMtlPipelineStateBuilder.mm
+++ b/src/gpu/mtl/GrMtlPipelineStateBuilder.mm
@@ -370,6 +370,7 @@
pipelineDescriptor.fragmentFunction = fragmentFunction;
pipelineDescriptor.vertexDescriptor = create_vertex_descriptor(primProc);
pipelineDescriptor.colorAttachments[0] = create_color_attachment(this->config(), pipeline);
+ pipelineDescriptor.sampleCount = renderTarget->numSamples();
bool hasStencilAttachment = SkToBool(renderTarget->renderTargetPriv().getStencilAttachment());
GrMtlCaps* mtlCaps = (GrMtlCaps*)this->caps();
pipelineDescriptor.stencilAttachmentPixelFormat =
diff --git a/src/gpu/mtl/GrMtlRenderTarget.h b/src/gpu/mtl/GrMtlRenderTarget.h
index 7b2c31b..5b1377c 100644
--- a/src/gpu/mtl/GrMtlRenderTarget.h
+++ b/src/gpu/mtl/GrMtlRenderTarget.h
@@ -26,20 +26,18 @@
// override of GrRenderTarget
ResolveType getResolveType() const override {
- return kCantResolve_ResolveType;
-#if 0 // TODO figure this once we support msaa
if (this->numSamples() > 1) {
return kCanResolve_ResolveType;
}
return kAutoResolves_ResolveType;
-#endif
}
bool canAttemptStencilAttachment() const override {
return true;
}
- id<MTLTexture> mtlRenderTexture() const { return fRenderTexture; }
+ id<MTLTexture> mtlColorTexture() const { return fColorTexture; }
+ id<MTLTexture> mtlResolveTexture() const { return fResolveTexture; }
GrBackendRenderTarget getBackendRenderTarget() const override;
@@ -48,7 +46,12 @@
protected:
GrMtlRenderTarget(GrMtlGpu* gpu,
const GrSurfaceDesc& desc,
- id<MTLTexture> renderTexture);
+ id<MTLTexture> colorTexture,
+ id<MTLTexture> resolveTexture);
+
+ GrMtlRenderTarget(GrMtlGpu* gpu,
+ const GrSurfaceDesc& desc,
+ id<MTLTexture> colorTexture);
GrMtlGpu* getMtlGpu() const;
@@ -68,7 +71,7 @@
numColorSamples, GrMipMapped::kNo);
}
- id<MTLTexture> fRenderTexture;
+ id<MTLTexture> fColorTexture;
id<MTLTexture> fResolveTexture;
private:
@@ -76,7 +79,12 @@
enum Wrapped { kWrapped };
GrMtlRenderTarget(GrMtlGpu* gpu,
const GrSurfaceDesc& desc,
- id<MTLTexture> renderTexture,
+ id<MTLTexture> colorTexture,
+ id<MTLTexture> resolveTexture,
+ Wrapped);
+ GrMtlRenderTarget(GrMtlGpu* gpu,
+ const GrSurfaceDesc& desc,
+ id<MTLTexture> colorTexture,
Wrapped);
bool completeStencilAttachment() override;
diff --git a/src/gpu/mtl/GrMtlRenderTarget.mm b/src/gpu/mtl/GrMtlRenderTarget.mm
index d549b6c..7d4d989 100644
--- a/src/gpu/mtl/GrMtlRenderTarget.mm
+++ b/src/gpu/mtl/GrMtlRenderTarget.mm
@@ -17,11 +17,24 @@
// Called for wrapped non-texture render targets.
GrMtlRenderTarget::GrMtlRenderTarget(GrMtlGpu* gpu,
const GrSurfaceDesc& desc,
- id<MTLTexture> renderTexture,
+ id<MTLTexture> colorTexture,
+ id<MTLTexture> resolveTexture,
Wrapped)
: GrSurface(gpu, desc)
, GrRenderTarget(gpu, desc)
- , fRenderTexture(renderTexture)
+ , fColorTexture(colorTexture)
+ , fResolveTexture(resolveTexture) {
+ SkASSERT(desc.fSampleCnt > 1);
+ this->registerWithCacheWrapped(GrWrapCacheable::kNo);
+}
+
+GrMtlRenderTarget::GrMtlRenderTarget(GrMtlGpu* gpu,
+ const GrSurfaceDesc& desc,
+ id<MTLTexture> colorTexture,
+ Wrapped)
+ : GrSurface(gpu, desc)
+ , GrRenderTarget(gpu, desc)
+ , fColorTexture(colorTexture)
, fResolveTexture(nil) {
SkASSERT(1 == desc.fSampleCnt);
this->registerWithCacheWrapped(GrWrapCacheable::kNo);
@@ -30,36 +43,76 @@
// Called by subclass constructors.
GrMtlRenderTarget::GrMtlRenderTarget(GrMtlGpu* gpu,
const GrSurfaceDesc& desc,
- id<MTLTexture> renderTexture)
+ id<MTLTexture> colorTexture,
+ id<MTLTexture> resolveTexture)
: GrSurface(gpu, desc)
, GrRenderTarget(gpu, desc)
- , fRenderTexture(renderTexture)
+ , fColorTexture(colorTexture)
+ , fResolveTexture(resolveTexture) {
+ SkASSERT(desc.fSampleCnt > 1);
+}
+
+GrMtlRenderTarget::GrMtlRenderTarget(GrMtlGpu* gpu,
+ const GrSurfaceDesc& desc,
+ id<MTLTexture> colorTexture)
+ : GrSurface(gpu, desc)
+ , GrRenderTarget(gpu, desc)
+ , fColorTexture(colorTexture)
, fResolveTexture(nil) {
SkASSERT(1 == desc.fSampleCnt);
}
sk_sp<GrMtlRenderTarget>
GrMtlRenderTarget::MakeWrappedRenderTarget(GrMtlGpu* gpu, const GrSurfaceDesc& desc,
- id<MTLTexture> renderTexture) {
- SkASSERT(nil != renderTexture);
- SkASSERT(1 == renderTexture.mipmapLevelCount);
- SkASSERT(MTLTextureUsageRenderTarget & renderTexture.usage);
- return sk_sp<GrMtlRenderTarget>(new GrMtlRenderTarget(gpu, desc, renderTexture, kWrapped));
+ id<MTLTexture> texture) {
+ SkASSERT(nil != texture);
+ SkASSERT(1 == texture.mipmapLevelCount);
+ SkASSERT(MTLTextureUsageRenderTarget & texture.usage);
+
+ GrMtlRenderTarget* mtlRT;
+ if (desc.fSampleCnt > 1) {
+ MTLPixelFormat format;
+ if (!GrPixelConfigToMTLFormat(desc.fConfig, &format)) {
+ return nullptr;
+ }
+ MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
+ texDesc.textureType = MTLTextureType2DMultisample;
+ texDesc.pixelFormat = format;
+ texDesc.width = desc.fWidth;
+ texDesc.height = desc.fHeight;
+ texDesc.depth = 1;
+ texDesc.mipmapLevelCount = 1;
+ texDesc.sampleCount = desc.fSampleCnt;
+ texDesc.arrayLength = 1;
+ texDesc.storageMode = MTLStorageModePrivate;
+ texDesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
+
+ id<MTLTexture> colorTexture = [gpu->device() newTextureWithDescriptor:texDesc];
+ if (!colorTexture) {
+ return nullptr;
+ }
+ SkASSERT((MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget) & colorTexture.usage);
+ mtlRT = new GrMtlRenderTarget(gpu, desc, colorTexture, texture, kWrapped);
+ } else {
+ mtlRT = new GrMtlRenderTarget(gpu, desc, texture, kWrapped);
+ }
+
+ return sk_sp<GrMtlRenderTarget>(mtlRT);
}
GrMtlRenderTarget::~GrMtlRenderTarget() {
- SkASSERT(nil == fRenderTexture);
+ SkASSERT(nil == fColorTexture);
SkASSERT(nil == fResolveTexture);
}
GrBackendRenderTarget GrMtlRenderTarget::getBackendRenderTarget() const {
GrMtlTextureInfo info;
- info.fTexture.reset(GrRetainPtrFromId(fRenderTexture));
- return GrBackendRenderTarget(this->width(), this->height(), fRenderTexture.sampleCount, info);
+ info.fTexture.reset(GrRetainPtrFromId(fColorTexture));
+ return GrBackendRenderTarget(this->width(), this->height(), fColorTexture.sampleCount, info);
}
GrBackendFormat GrMtlRenderTarget::backendFormat() const {
- return GrBackendFormat::MakeMtl(fRenderTexture.pixelFormat);
+ return GrBackendFormat::MakeMtl(fColorTexture.pixelFormat);
}
GrMtlGpu* GrMtlRenderTarget::getMtlGpu() const {
@@ -68,13 +121,13 @@
}
void GrMtlRenderTarget::onAbandon() {
- fRenderTexture = nil;
+ fColorTexture = nil;
fResolveTexture = nil;
INHERITED::onAbandon();
}
void GrMtlRenderTarget::onRelease() {
- fRenderTexture = nil;
+ fColorTexture = nil;
fResolveTexture = nil;
INHERITED::onRelease();
}
diff --git a/src/gpu/mtl/GrMtlStencilAttachment.mm b/src/gpu/mtl/GrMtlStencilAttachment.mm
index fdafdb4..27be2d8 100644
--- a/src/gpu/mtl/GrMtlStencilAttachment.mm
+++ b/src/gpu/mtl/GrMtlStencilAttachment.mm
@@ -34,6 +34,10 @@
mipmapped:NO];
desc.resourceOptions = MTLResourceStorageModePrivate;
desc.usage = MTLTextureUsageRenderTarget;
+ desc.sampleCount = sampleCnt;
+ if (sampleCnt > 1) {
+ desc.textureType = MTLTextureType2DMultisample;
+ }
return new GrMtlStencilAttachment(gpu, format, [gpu->device() newTextureWithDescriptor:desc]);
}
diff --git a/src/gpu/mtl/GrMtlTexture.h b/src/gpu/mtl/GrMtlTexture.h
index 4eb241d..c81aef0 100644
--- a/src/gpu/mtl/GrMtlTexture.h
+++ b/src/gpu/mtl/GrMtlTexture.h
@@ -16,10 +16,10 @@
class GrMtlTexture : public GrTexture {
public:
- static sk_sp<GrMtlTexture> CreateNewTexture(GrMtlGpu*, SkBudgeted budgeted,
- const GrSurfaceDesc&,
- MTLTextureDescriptor*,
- GrMipMapsStatus);
+ static sk_sp<GrMtlTexture> MakeNewTexture(GrMtlGpu*, SkBudgeted budgeted,
+ const GrSurfaceDesc&,
+ MTLTextureDescriptor*,
+ GrMipMapsStatus);
static sk_sp<GrMtlTexture> MakeWrappedTexture(GrMtlGpu*, const GrSurfaceDesc&, id<MTLTexture>,
GrWrapCacheable, GrIOType);
diff --git a/src/gpu/mtl/GrMtlTexture.mm b/src/gpu/mtl/GrMtlTexture.mm
index 9c8fd55..36cc835 100644
--- a/src/gpu/mtl/GrMtlTexture.mm
+++ b/src/gpu/mtl/GrMtlTexture.mm
@@ -54,16 +54,14 @@
SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == texture.mipmapLevelCount));
}
-sk_sp<GrMtlTexture> GrMtlTexture::CreateNewTexture(GrMtlGpu* gpu, SkBudgeted budgeted,
+sk_sp<GrMtlTexture> GrMtlTexture::MakeNewTexture(GrMtlGpu* gpu, SkBudgeted budgeted,
const GrSurfaceDesc& desc,
MTLTextureDescriptor* texDesc,
GrMipMapsStatus mipMapsStatus) {
- if (desc.fSampleCnt > 1) {
- SkASSERT(false); // Currently we don't support msaa
+ id<MTLTexture> texture = [gpu->device() newTextureWithDescriptor:texDesc];
+ if (!texture) {
return nullptr;
}
- id<MTLTexture> texture = [gpu->device() newTextureWithDescriptor:texDesc];
- SkASSERT(nil != texture);
SkASSERT(MTLTextureUsageShaderRead & texture.usage);
return sk_sp<GrMtlTexture>(new GrMtlTexture(gpu, budgeted, desc, texture, mipMapsStatus));
}
@@ -73,10 +71,6 @@
id<MTLTexture> texture,
GrWrapCacheable cacheable,
GrIOType ioType) {
- if (desc.fSampleCnt > 1) {
- SkASSERT(false); // Currently we don't support msaa
- return nullptr;
- }
SkASSERT(nil != texture);
SkASSERT(MTLTextureUsageShaderRead & texture.usage);
GrMipMapsStatus mipMapsStatus = texture.mipmapLevelCount > 1 ? GrMipMapsStatus::kValid
diff --git a/src/gpu/mtl/GrMtlTextureRenderTarget.h b/src/gpu/mtl/GrMtlTextureRenderTarget.h
index 68f716f..da73135 100644
--- a/src/gpu/mtl/GrMtlTextureRenderTarget.h
+++ b/src/gpu/mtl/GrMtlTextureRenderTarget.h
@@ -13,11 +13,11 @@
class GrMtlTextureRenderTarget: public GrMtlTexture, public GrMtlRenderTarget {
public:
- static sk_sp<GrMtlTextureRenderTarget> CreateNewTextureRenderTarget(GrMtlGpu*,
- SkBudgeted,
- const GrSurfaceDesc&,
- MTLTextureDescriptor*,
- GrMipMapsStatus);
+ static sk_sp<GrMtlTextureRenderTarget> MakeNewTextureRenderTarget(GrMtlGpu*,
+ SkBudgeted,
+ const GrSurfaceDesc&,
+ MTLTextureDescriptor*,
+ GrMipMapsStatus);
static sk_sp<GrMtlTextureRenderTarget> MakeWrappedTextureRenderTarget(GrMtlGpu*,
const GrSurfaceDesc&,
@@ -42,25 +42,26 @@
GrMtlTextureRenderTarget(GrMtlGpu* gpu,
SkBudgeted budgeted,
const GrSurfaceDesc& desc,
- id<MTLTexture> renderTexture,
+ id<MTLTexture> colorTexture,
id<MTLTexture> resolveTexture,
GrMipMapsStatus);
GrMtlTextureRenderTarget(GrMtlGpu* gpu,
SkBudgeted budgeted,
const GrSurfaceDesc& desc,
- id<MTLTexture> renderTexture,
+ id<MTLTexture> colorTexture,
GrMipMapsStatus);
GrMtlTextureRenderTarget(GrMtlGpu* gpu,
const GrSurfaceDesc& desc,
- id<MTLTexture> renderTexture,
+ id<MTLTexture> colorTexture,
id<MTLTexture> resolveTexture,
- GrMipMapsStatus);
+ GrMipMapsStatus,
+ GrWrapCacheable cacheable);
GrMtlTextureRenderTarget(GrMtlGpu* gpu,
const GrSurfaceDesc& desc,
- id<MTLTexture> renderTexture,
+ id<MTLTexture> colorTexture,
GrMipMapsStatus,
GrWrapCacheable cacheable);
diff --git a/src/gpu/mtl/GrMtlTextureRenderTarget.mm b/src/gpu/mtl/GrMtlTextureRenderTarget.mm
index 16202c9..828b04a 100644
--- a/src/gpu/mtl/GrMtlTextureRenderTarget.mm
+++ b/src/gpu/mtl/GrMtlTextureRenderTarget.mm
@@ -16,54 +16,117 @@
GrMtlTextureRenderTarget::GrMtlTextureRenderTarget(GrMtlGpu* gpu,
SkBudgeted budgeted,
const GrSurfaceDesc& desc,
- id<MTLTexture> renderTexture,
+ id<MTLTexture> colorTexture,
+ id<MTLTexture> resolveTexture,
GrMipMapsStatus mipMapsStatus)
: GrSurface(gpu, desc)
- , GrMtlTexture(gpu, desc, renderTexture, mipMapsStatus)
- , GrMtlRenderTarget(gpu, desc, renderTexture) {
+ , GrMtlTexture(gpu, desc, resolveTexture, mipMapsStatus)
+ , GrMtlRenderTarget(gpu, desc, colorTexture, resolveTexture) {
+ this->registerWithCache(budgeted);
+}
+
+GrMtlTextureRenderTarget::GrMtlTextureRenderTarget(GrMtlGpu* gpu,
+ SkBudgeted budgeted,
+ const GrSurfaceDesc& desc,
+ id<MTLTexture> colorTexture,
+ GrMipMapsStatus mipMapsStatus)
+ : GrSurface(gpu, desc)
+ , GrMtlTexture(gpu, desc, colorTexture, mipMapsStatus)
+ , GrMtlRenderTarget(gpu, desc, colorTexture) {
this->registerWithCache(budgeted);
}
GrMtlTextureRenderTarget::GrMtlTextureRenderTarget(GrMtlGpu* gpu,
const GrSurfaceDesc& desc,
- id<MTLTexture> renderTexture,
+ id<MTLTexture> colorTexture,
+ id<MTLTexture> resolveTexture,
GrMipMapsStatus mipMapsStatus,
GrWrapCacheable cacheable)
: GrSurface(gpu, desc)
- , GrMtlTexture(gpu, desc, renderTexture, mipMapsStatus)
- , GrMtlRenderTarget(gpu, desc, renderTexture) {
+ , GrMtlTexture(gpu, desc, resolveTexture, mipMapsStatus)
+ , GrMtlRenderTarget(gpu, desc, colorTexture, resolveTexture) {
this->registerWithCacheWrapped(cacheable);
}
-sk_sp<GrMtlTextureRenderTarget>
-GrMtlTextureRenderTarget::CreateNewTextureRenderTarget(GrMtlGpu* gpu,
- SkBudgeted budgeted,
- const GrSurfaceDesc& desc,
- MTLTextureDescriptor* texDesc,
- GrMipMapsStatus mipMapsStatus) {
- id<MTLTexture> renderTexture = [gpu->device() newTextureWithDescriptor:texDesc];
- SkASSERT(nil != renderTexture);
- if (desc.fSampleCnt > 1) {
+GrMtlTextureRenderTarget::GrMtlTextureRenderTarget(GrMtlGpu* gpu,
+ const GrSurfaceDesc& desc,
+ id<MTLTexture> colorTexture,
+ GrMipMapsStatus mipMapsStatus,
+ GrWrapCacheable cacheable)
+ : GrSurface(gpu, desc)
+ , GrMtlTexture(gpu, desc, colorTexture, mipMapsStatus)
+ , GrMtlRenderTarget(gpu, desc, colorTexture) {
+ this->registerWithCacheWrapped(cacheable);
+}
+
+id<MTLTexture> create_msaa_texture(GrMtlGpu* gpu, const GrSurfaceDesc& desc) {
+ MTLPixelFormat format;
+ if (!GrPixelConfigToMTLFormat(desc.fConfig, &format)) {
return nullptr;
}
- SkASSERT((MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget) & renderTexture.usage);
- return sk_sp<GrMtlTextureRenderTarget>(
- new GrMtlTextureRenderTarget(gpu, budgeted, desc, renderTexture, mipMapsStatus));
+ MTLTextureDescriptor* texDesc = [[MTLTextureDescriptor alloc] init];
+ texDesc.textureType = MTLTextureType2DMultisample;
+ texDesc.pixelFormat = format;
+ texDesc.width = desc.fWidth;
+ texDesc.height = desc.fHeight;
+ texDesc.depth = 1;
+ texDesc.mipmapLevelCount = 1;
+ texDesc.sampleCount = desc.fSampleCnt;
+ texDesc.arrayLength = 1;
+ texDesc.storageMode = MTLStorageModePrivate;
+ texDesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
+
+ return [gpu->device() newTextureWithDescriptor:texDesc];
+}
+
+sk_sp<GrMtlTextureRenderTarget>
+GrMtlTextureRenderTarget::MakeNewTextureRenderTarget(GrMtlGpu* gpu,
+ SkBudgeted budgeted,
+ const GrSurfaceDesc& desc,
+ MTLTextureDescriptor* texDesc,
+ GrMipMapsStatus mipMapsStatus) {
+ id<MTLTexture> texture = [gpu->device() newTextureWithDescriptor:texDesc];
+ if (!texture) {
+ return nullptr;
+ }
+ SkASSERT((MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget) & texture.usage);
+
+ if (desc.fSampleCnt > 1) {
+ id<MTLTexture> colorTexture = create_msaa_texture(gpu, desc);
+ if (!colorTexture) {
+ return nullptr;
+ }
+ SkASSERT((MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget) & colorTexture.usage);
+ return sk_sp<GrMtlTextureRenderTarget>(
+ new GrMtlTextureRenderTarget(gpu, budgeted, desc, colorTexture, texture,
+ mipMapsStatus));
+ } else {
+ return sk_sp<GrMtlTextureRenderTarget>(
+ new GrMtlTextureRenderTarget(gpu, budgeted, desc, texture, mipMapsStatus));
+ }
}
sk_sp<GrMtlTextureRenderTarget> GrMtlTextureRenderTarget::MakeWrappedTextureRenderTarget(
GrMtlGpu* gpu,
const GrSurfaceDesc& desc,
- id<MTLTexture> renderTexture,
+ id<MTLTexture> texture,
GrWrapCacheable cacheable) {
- SkASSERT(nil != renderTexture);
- GrMipMapsStatus mipMapsStatus = renderTexture.mipmapLevelCount > 1
+ SkASSERT(nil != texture);
+ SkASSERT((MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget) & texture.usage);
+ GrMipMapsStatus mipMapsStatus = texture.mipmapLevelCount > 1
? GrMipMapsStatus::kDirty
: GrMipMapsStatus::kNotAllocated;
if (desc.fSampleCnt > 1) {
- return nullptr;
+ id<MTLTexture> colorTexture = create_msaa_texture(gpu, desc);
+ if (!colorTexture) {
+ return nullptr;
+ }
+ SkASSERT((MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget) & colorTexture.usage);
+ return sk_sp<GrMtlTextureRenderTarget>(
+ new GrMtlTextureRenderTarget(gpu, desc, colorTexture, texture, mipMapsStatus,
+ cacheable));
+ } else {
+ return sk_sp<GrMtlTextureRenderTarget>(
+ new GrMtlTextureRenderTarget(gpu, desc, texture, mipMapsStatus, cacheable));
}
- SkASSERT((MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget) & renderTexture.usage);
- return sk_sp<GrMtlTextureRenderTarget>(
- new GrMtlTextureRenderTarget(gpu, desc, renderTexture, mipMapsStatus, cacheable));
}
diff --git a/src/gpu/mtl/GrMtlUtil.h b/src/gpu/mtl/GrMtlUtil.h
index 43a0b14..a8e2cd6 100644
--- a/src/gpu/mtl/GrMtlUtil.h
+++ b/src/gpu/mtl/GrMtlUtil.h
@@ -90,8 +90,8 @@
id<MTLDevice>, MTLRenderPipelineDescriptor*, bool* timedout);
/**
- * Returns a MTLTexture corresponding to the GrSurface. Optionally can do a resolve.
+ * Returns a MTLTexture corresponding to the GrSurface.
*/
-id<MTLTexture> GrGetMTLTextureFromSurface(GrSurface* surface, bool doResolve);
+id<MTLTexture> GrGetMTLTextureFromSurface(GrSurface* surface);
#endif
diff --git a/src/gpu/mtl/GrMtlUtil.mm b/src/gpu/mtl/GrMtlUtil.mm
index ed26f28..eeef445 100644
--- a/src/gpu/mtl/GrMtlUtil.mm
+++ b/src/gpu/mtl/GrMtlUtil.mm
@@ -257,19 +257,18 @@
return pipelineState;
}
-id<MTLTexture> GrGetMTLTextureFromSurface(GrSurface* surface, bool doResolve) {
+id<MTLTexture> GrGetMTLTextureFromSurface(GrSurface* surface) {
id<MTLTexture> mtlTexture = nil;
GrMtlRenderTarget* renderTarget = static_cast<GrMtlRenderTarget*>(surface->asRenderTarget());
GrMtlTexture* texture;
if (renderTarget) {
- if (doResolve) {
- // TODO: do resolve and set mtlTexture to resolved texture. As of now, we shouldn't
- // have any multisampled render targets.
+ // We should not be using this for multisampled rendertargets
+ if (renderTarget->numSamples() > 1) {
SkASSERT(false);
- } else {
- mtlTexture = renderTarget->mtlRenderTexture();
+ return nil;
}
+ mtlTexture = renderTarget->mtlColorTexture();
} else {
texture = static_cast<GrMtlTexture*>(surface->asTexture());
if (texture) {
diff --git a/tools/sk_app/MetalWindowContext.mm b/tools/sk_app/MetalWindowContext.mm
index e4947cd..78fbf61 100644
--- a/tools/sk_app/MetalWindowContext.mm
+++ b/tools/sk_app/MetalWindowContext.mm
@@ -39,8 +39,7 @@
return;
}
}
- // TODO: Multisampling not supported
- fSampleCount = 1; //fDisplayParams.fMSAASampleCount;
+ fSampleCount = fDisplayParams.fMSAASampleCount;
fStencilBits = 8;
fMetalLayer = [CAMetalLayer layer];
@@ -86,16 +85,28 @@
GrMtlTextureInfo fbInfo;
fbInfo.fTexture.retain((__bridge const void*)(fCurrentDrawable.texture));
- GrBackendRenderTarget backendRT(fWidth,
- fHeight,
- fSampleCount,
- fbInfo);
+ if (fSampleCount == 1) {
+ GrBackendRenderTarget backendRT(fWidth,
+ fHeight,
+ fSampleCount,
+ fbInfo);
- surface = SkSurface::MakeFromBackendRenderTarget(fContext.get(), backendRT,
- kTopLeft_GrSurfaceOrigin,
- kBGRA_8888_SkColorType,
- fDisplayParams.fColorSpace,
- &fDisplayParams.fSurfaceProps);
+ surface = SkSurface::MakeFromBackendRenderTarget(fContext.get(), backendRT,
+ kTopLeft_GrSurfaceOrigin,
+ kBGRA_8888_SkColorType,
+ fDisplayParams.fColorSpace,
+ &fDisplayParams.fSurfaceProps);
+ } else {
+ GrBackendTexture backendTexture(fWidth,
+ fHeight,
+ GrMipMapped::kNo,
+ fbInfo);
+
+ surface = SkSurface::MakeFromBackendTexture(
+ fContext.get(), backendTexture, kTopLeft_GrSurfaceOrigin, fSampleCount,
+ kBGRA_8888_SkColorType, fDisplayParams.fColorSpace,
+ &fDisplayParams.fSurfaceProps);
+ }
}
return surface;
diff --git a/tools/sk_app/mac/Window_mac.h b/tools/sk_app/mac/Window_mac.h
index 2eb37ad..761cd40 100644
--- a/tools/sk_app/mac/Window_mac.h
+++ b/tools/sk_app/mac/Window_mac.h
@@ -19,8 +19,7 @@
public:
Window_mac()
: INHERITED()
- , fWindow(nil)
- , fMSAASampleCount(1) {}
+ , fWindow(nil) {}
~Window_mac() override {
this->closeWindow();
}
@@ -50,7 +49,6 @@
private:
NSWindow* fWindow;
NSInteger fWindowNumber;
- int fMSAASampleCount;
static SkTDynamicHash<Window_mac, NSInteger> gWindowMap;
diff --git a/tools/sk_app/mac/Window_mac.mm b/tools/sk_app/mac/Window_mac.mm
index 65069d8..7fe48ea 100644
--- a/tools/sk_app/mac/Window_mac.mm
+++ b/tools/sk_app/mac/Window_mac.mm
@@ -41,10 +41,6 @@
}
bool Window_mac::initWindow() {
- if (fRequestedDisplayParams.fMSAASampleCount != fMSAASampleCount) {
- this->closeWindow();
- }
-
// we already have a window
if (fWindow) {
return true;