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>
This commit is contained in:
Jim Van Verth 2019-07-11 15:40:53 -04:00 committed by Skia Commit-Bot
parent 649774b686
commit d361e64326
20 changed files with 371 additions and 126 deletions

View File

@ -59,6 +59,9 @@ public:
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 @@ private:
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;
};

View File

@ -37,7 +37,6 @@ GrMtlCaps::GrMtlCaps(const GrContextOptions& contextOptions, const id<MTLDevice>
// 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 @@ bool GrMtlCaps::canCopyAsBlit(GrPixelConfig dstConfig, int dstSampleCount,
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;

View File

@ -59,8 +59,9 @@ static bool compatible(const MTLRenderPassAttachmentDescriptor* first,
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 @@ id<MTLRenderCommandEncoder> GrMtlCommandBuffer::getRenderCommandEncoder(
this->endAllEncoding();
fActiveRenderCommandEncoder = [fCmdBuffer renderCommandEncoderWithDescriptor:descriptor];
if (gpuCommandBuffer) {
gpuCommandBuffer->initRenderState(fActiveRenderCommandEncoder);
}
fPreviousRenderPassDescriptor = descriptor;
return fActiveRenderCommandEncoder;

View File

@ -72,7 +72,9 @@ public:
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 @@ public:
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 @@ private:
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 {

View File

@ -436,7 +436,6 @@ sk_sp<GrTexture> GrMtlGpu::onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted
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 @@ sk_sp<GrTexture> GrMtlGpu::onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted
}
if (renderTarget) {
tex = GrMtlTextureRenderTarget::CreateNewTextureRenderTarget(this, budgeted,
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 @@ static int get_surface_sample_cnt(GrSurface* surf) {
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 @@ bool GrMtlGpu::copySurfaceAsBlit(GrSurface* dst, GrSurface* src, const SkIRect&
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 @@ bool GrMtlGpu::copySurfaceAsBlit(GrSurface* dst, GrSurface* src, const SkIRect&
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 @@ bool GrMtlGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcR
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 @@ bool GrMtlGpu::onReadPixels(GrSurface* surface, int left, int top, int width, in
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 @@ bool GrMtlGpu::onReadPixels(GrSurface* surface, int left, int top, int width, in
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";
}

View File

@ -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 @@ void GrMtlGpuRTCommandBuffer::onDraw(const GrPrimitiveProcessor& primProc,
}
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::onClearStencilClip(const GrFixedClip& clip, bool i
}
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 @@ void GrMtlGpuRTCommandBuffer::initRenderState(id<MTLRenderCommandEncoder> encode
0.0, 1.0 };
[encoder setViewport:viewport];
this->resetBufferBindings();
[encoder popDebugGroup];
}
void GrMtlGpuRTCommandBuffer::setupRenderPass(
@ -273,7 +283,7 @@ void GrMtlGpuRTCommandBuffer::setupRenderPass(
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;

View File

@ -116,9 +116,11 @@ void GrMtlPipelineState::setData(const GrRenderTarget* renderTarget,
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) {

View File

@ -370,6 +370,7 @@ GrMtlPipelineState* GrMtlPipelineStateBuilder::finalize(GrRenderTarget* renderTa
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 =

View File

@ -26,20 +26,18 @@ public:
// 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 @@ public:
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 @@ protected:
numColorSamples, GrMipMapped::kNo);
}
id<MTLTexture> fRenderTexture;
id<MTLTexture> fColorTexture;
id<MTLTexture> fResolveTexture;
private:
@ -76,7 +79,12 @@ private:
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;

View File

@ -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 @@ GrMtlRenderTarget::GrMtlRenderTarget(GrMtlGpu* gpu,
// 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 @@ GrMtlGpu* GrMtlRenderTarget::getMtlGpu() const {
}
void GrMtlRenderTarget::onAbandon() {
fRenderTexture = nil;
fColorTexture = nil;
fResolveTexture = nil;
INHERITED::onAbandon();
}
void GrMtlRenderTarget::onRelease() {
fRenderTexture = nil;
fColorTexture = nil;
fResolveTexture = nil;
INHERITED::onRelease();
}

View File

@ -34,6 +34,10 @@ GrMtlStencilAttachment* GrMtlStencilAttachment::Create(GrMtlGpu* gpu,
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]);
}

View File

@ -16,7 +16,7 @@ class GrMtlGpu;
class GrMtlTexture : public GrTexture {
public:
static sk_sp<GrMtlTexture> CreateNewTexture(GrMtlGpu*, SkBudgeted budgeted,
static sk_sp<GrMtlTexture> MakeNewTexture(GrMtlGpu*, SkBudgeted budgeted,
const GrSurfaceDesc&,
MTLTextureDescriptor*,
GrMipMapsStatus);

View File

@ -54,16 +54,14 @@ GrMtlTexture::GrMtlTexture(GrMtlGpu* gpu,
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 @@ sk_sp<GrMtlTexture> GrMtlTexture::MakeWrappedTexture(GrMtlGpu* gpu,
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

View File

@ -13,7 +13,7 @@
class GrMtlTextureRenderTarget: public GrMtlTexture, public GrMtlRenderTarget {
public:
static sk_sp<GrMtlTextureRenderTarget> CreateNewTextureRenderTarget(GrMtlGpu*,
static sk_sp<GrMtlTextureRenderTarget> MakeNewTextureRenderTarget(GrMtlGpu*,
SkBudgeted,
const GrSurfaceDesc&,
MTLTextureDescriptor*,
@ -42,25 +42,26 @@ private:
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);

View File

@ -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);
}
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;
}
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::CreateNewTextureRenderTarget(GrMtlGpu* gpu,
GrMtlTextureRenderTarget::MakeNewTextureRenderTarget(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) {
id<MTLTexture> texture = [gpu->device() newTextureWithDescriptor:texDesc];
if (!texture) {
return nullptr;
}
SkASSERT((MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget) & renderTexture.usage);
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, renderTexture, mipMapsStatus));
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) {
id<MTLTexture> colorTexture = create_msaa_texture(gpu, desc);
if (!colorTexture) {
return nullptr;
}
SkASSERT((MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget) & renderTexture.usage);
SkASSERT((MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget) & colorTexture.usage);
return sk_sp<GrMtlTextureRenderTarget>(
new GrMtlTextureRenderTarget(gpu, desc, renderTexture, mipMapsStatus, cacheable));
new GrMtlTextureRenderTarget(gpu, desc, colorTexture, texture, mipMapsStatus,
cacheable));
} else {
return sk_sp<GrMtlTextureRenderTarget>(
new GrMtlTextureRenderTarget(gpu, desc, texture, mipMapsStatus, cacheable));
}
}

View File

@ -90,8 +90,8 @@ id<MTLRenderPipelineState> GrMtlNewRenderPipelineStateWithDescriptor(
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

View File

@ -257,19 +257,18 @@ id<MTLRenderPipelineState> GrMtlNewRenderPipelineStateWithDescriptor(
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) {

View File

@ -39,8 +39,7 @@ void MetalWindowContext::initializeContext() {
return;
}
}
// TODO: Multisampling not supported
fSampleCount = 1; //fDisplayParams.fMSAASampleCount;
fSampleCount = fDisplayParams.fMSAASampleCount;
fStencilBits = 8;
fMetalLayer = [CAMetalLayer layer];
@ -86,6 +85,7 @@ sk_sp<SkSurface> MetalWindowContext::getBackbufferSurface() {
GrMtlTextureInfo fbInfo;
fbInfo.fTexture.retain((__bridge const void*)(fCurrentDrawable.texture));
if (fSampleCount == 1) {
GrBackendRenderTarget backendRT(fWidth,
fHeight,
fSampleCount,
@ -96,6 +96,17 @@ sk_sp<SkSurface> MetalWindowContext::getBackbufferSurface() {
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;

View File

@ -19,8 +19,7 @@ class Window_mac : public Window {
public:
Window_mac()
: INHERITED()
, fWindow(nil)
, fMSAASampleCount(1) {}
, fWindow(nil) {}
~Window_mac() override {
this->closeWindow();
}
@ -50,7 +49,6 @@ public:
private:
NSWindow* fWindow;
NSInteger fWindowNumber;
int fMSAASampleCount;
static SkTDynamicHash<Window_mac, NSInteger> gWindowMap;

View File

@ -41,10 +41,6 @@ Window* Window::CreateNativeWindow(void*) {
}
bool Window_mac::initWindow() {
if (fRequestedDisplayParams.fMSAASampleCount != fMSAASampleCount) {
this->closeWindow();
}
// we already have a window
if (fWindow) {
return true;