aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Timothy Liang <timliang@google.com>2018-07-31 10:51:17 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-07-31 16:25:55 +0000
commite30739a1e1d90183bc6bf7414e409e89016881f5 (patch)
tree4b84aeadee82fde5b45ec75aa1782897e2c9625f /src
parentc8ece3d5f877d67114dfda51a336dfdf7838095a (diff)
implemented copy surface as draw for metal gpu backend
Bug: skia: Change-Id: Ie61bd6ad9f288b8a025d44f887a0954101a7d710 Reviewed-on: https://skia-review.googlesource.com/142687 Commit-Queue: Timothy Liang <timliang@google.com> Reviewed-by: Greg Daniel <egdaniel@google.com>
Diffstat (limited to 'src')
-rw-r--r--src/gpu/mtl/GrMtlCaps.h3
-rw-r--r--src/gpu/mtl/GrMtlCaps.mm18
-rw-r--r--src/gpu/mtl/GrMtlCopyManager.h53
-rw-r--r--src/gpu/mtl/GrMtlCopyManager.mm237
-rw-r--r--src/gpu/mtl/GrMtlCopyPipelineState.h37
-rw-r--r--src/gpu/mtl/GrMtlCopyPipelineState.mm37
-rw-r--r--src/gpu/mtl/GrMtlGpu.h16
-rw-r--r--src/gpu/mtl/GrMtlGpu.mm46
-rw-r--r--src/gpu/mtl/GrMtlResourceProvider.h33
-rw-r--r--src/gpu/mtl/GrMtlResourceProvider.mm31
-rw-r--r--src/gpu/mtl/GrMtlUtil.h17
-rw-r--r--src/gpu/mtl/GrMtlUtil.mm84
12 files changed, 581 insertions, 31 deletions
diff --git a/src/gpu/mtl/GrMtlCaps.h b/src/gpu/mtl/GrMtlCaps.h
index 5d6c82bea8..11eb322442 100644
--- a/src/gpu/mtl/GrMtlCaps.h
+++ b/src/gpu/mtl/GrMtlCaps.h
@@ -51,6 +51,9 @@ public:
const SkIRect& srcRect, const SkIPoint& dstPoint,
bool areDstSrcSameObj) const;
+ bool canCopyAsDraw(GrPixelConfig dstConfig, bool dstIsRenderable,
+ GrPixelConfig srcConfig, bool srcIsTextureable) const;
+
bool canCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src,
const SkIRect& srcRect, const SkIPoint& dstPoint) const override;
diff --git a/src/gpu/mtl/GrMtlCaps.mm b/src/gpu/mtl/GrMtlCaps.mm
index 3093352272..dc70d28e2a 100644
--- a/src/gpu/mtl/GrMtlCaps.mm
+++ b/src/gpu/mtl/GrMtlCaps.mm
@@ -129,6 +129,20 @@ bool GrMtlCaps::canCopyAsBlit(GrPixelConfig dstConfig, int dstSampleCount,
return true;
}
+bool GrMtlCaps::canCopyAsDraw(GrPixelConfig dstConfig, bool dstIsRenderable,
+ GrPixelConfig srcConfig, bool srcIsTextureable) const {
+ // TODO: Make copySurfaceAsDraw handle the swizzle
+ if (this->shaderCaps()->configOutputSwizzle(srcConfig) !=
+ this->shaderCaps()->configOutputSwizzle(dstConfig)) {
+ return false;
+ }
+
+ if (!dstIsRenderable || !srcIsTextureable) {
+ return false;
+ }
+ return true;
+}
+
bool GrMtlCaps::canCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src,
const SkIRect& srcRect, const SkIPoint& dstPoint) const {
GrSurfaceOrigin dstOrigin = dst->origin();
@@ -147,7 +161,9 @@ bool GrMtlCaps::canCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy*
return this->canCopyAsBlit(dst->config(), dstSampleCnt, dstOrigin,
src->config(), srcSampleCnt, srcOrigin,
- srcRect, dstPoint, dst == src);
+ srcRect, dstPoint, dst == src) ||
+ this->canCopyAsDraw(dst->config(), SkToBool(dst->asRenderTargetProxy()),
+ src->config(), SkToBool(src->asTextureProxy()));
}
void GrMtlCaps::initGrCaps(const id<MTLDevice> device) {
diff --git a/src/gpu/mtl/GrMtlCopyManager.h b/src/gpu/mtl/GrMtlCopyManager.h
new file mode 100644
index 0000000000..7899397e1c
--- /dev/null
+++ b/src/gpu/mtl/GrMtlCopyManager.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+*/
+
+#ifndef GrMtlCopyManager_DEFINED
+#define GrMtlCopyManager_DEFINED
+
+#include "GrTypes.h"
+
+#import <metal/metal.h>
+
+class GrMtlCopyPipelineState;
+class GrMtlGpu;
+class GrSurface;
+struct SkIPoint;
+struct SkIRect;
+
+class GrMtlCopyManager {
+public:
+ GrMtlCopyManager(GrMtlGpu* gpu) : fGpu(gpu) {}
+
+ bool copySurfaceAsDraw(GrSurface* dst, GrSurfaceOrigin dstOrigin,
+ GrSurface* src, GrSurfaceOrigin srcOrigin,
+ const SkIRect& srcRect, const SkIPoint& dstPoint,
+ bool canDiscardOutsideDstRect);
+
+ static bool IsCompatible(const GrMtlCopyPipelineState*, MTLPixelFormat dstPixelFormat);
+
+private:
+ enum BufferIndex {
+ kUniform_BufferIndex,
+ kAttribute_BufferIndex,
+ };
+
+ void createCopyProgramBuffer();
+ void createCopyProgramShaders();
+ void createCopyProgramVertexDescriptor();
+
+ void createCopyProgram();
+
+ id<MTLSamplerState> fSamplerState;
+ id<MTLBuffer> fVertexAttributeBuffer;
+ id<MTLFunction> fVertexFunction;
+ id<MTLFunction> fFragmentFunction;
+ MTLVertexDescriptor* fVertexDescriptor;
+
+ GrMtlGpu* fGpu;
+};
+
+#endif
diff --git a/src/gpu/mtl/GrMtlCopyManager.mm b/src/gpu/mtl/GrMtlCopyManager.mm
new file mode 100644
index 0000000000..529bdc1ca1
--- /dev/null
+++ b/src/gpu/mtl/GrMtlCopyManager.mm
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrMtlCopyManager.h"
+
+#include "GrSurface.h"
+
+#include "GrMtlCopyPipelineState.h"
+#include "GrMtlGpu.h"
+#include "GrMtlResourceProvider.h"
+#include "GrMtlUtil.h"
+
+#include "SkPoint.h"
+#include "SkRect.h"
+#include "SkTraceEvent.h"
+
+#import <simd/simd.h>
+
+void GrMtlCopyManager::createCopyProgramBuffer() {
+ // Create per vertex attribute data for copy as draw
+ static const simd::float2 vdata[4] = {
+ {0, 0},
+ {0, 1},
+ {1, 0},
+ {1, 1},
+ };
+ fVertexAttributeBuffer = [fGpu->device() newBufferWithLength: sizeof(vdata)
+ options: MTLResourceStorageModePrivate];
+ id<MTLBuffer> transferBuffer =
+ [fGpu->device() newBufferWithBytes: vdata
+ length: sizeof(vdata)
+ options: MTLResourceStorageModeManaged];
+
+ id<MTLBlitCommandEncoder> blitCmdEncoder = [fGpu->commandBuffer() blitCommandEncoder];
+ [blitCmdEncoder copyFromBuffer: transferBuffer
+ sourceOffset: 0
+ toBuffer: fVertexAttributeBuffer
+ destinationOffset: 0
+ size: sizeof(vdata)];
+ [blitCmdEncoder endEncoding];
+}
+
+void GrMtlCopyManager::createCopyProgramShaders() {
+ // Create shaders required by pipeline state
+ const GrShaderCaps* shaderCaps = fGpu->caps()->shaderCaps();
+ const char* version = shaderCaps->versionDeclString();
+ SkString vertShaderText(version);
+ vertShaderText.appendf(
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+ "layout(set = %d"/*kUniform_BufferIndex*/", binding = 0) uniform vertexUniformBuffer {"
+ "float4 uPosXform;"
+ "float4 uTexCoordXform;"
+ "};"
+ "layout(location = 0) in float2 inPosition;"
+ "layout(location = 1) out float2 vTexCoord;"
+
+ "// Copy Program VS\n"
+ "void main() {"
+ "vTexCoord = inPosition * uTexCoordXform.xy + uTexCoordXform.zw;"
+ "sk_Position.xy = inPosition * uPosXform.xy + uPosXform.zw;"
+ "sk_Position.zw = float2(0, 1);"
+ "}",
+ kUniform_BufferIndex
+ );
+
+ SkString fragShaderText(version);
+ fragShaderText.append(
+ "#extension GL_ARB_separate_shader_objects : enable\n"
+ "#extension GL_ARB_shading_language_420pack : enable\n"
+
+ "layout(set = 1, binding = 0) uniform sampler2D uTexture;"
+ "layout(location = 1) in float2 vTexCoord;"
+
+ "// Copy Program FS\n"
+ "void main() {"
+ "sk_FragColor = texture(uTexture, vTexCoord);"
+ "}"
+ );
+
+ SkSL::Program::Settings settings;
+ SkSL::Program::Inputs inputs;
+ id<MTLLibrary> vertexLibrary = GrCompileMtlShaderLibrary(fGpu, vertShaderText.c_str(),
+ SkSL::Program::kVertex_Kind,
+ settings, &inputs);
+ SkASSERT(inputs.isEmpty());
+ SkASSERT(vertexLibrary);
+
+ id<MTLLibrary> fragmentLibrary = GrCompileMtlShaderLibrary(fGpu, fragShaderText.c_str(),
+ SkSL::Program::kFragment_Kind,
+ settings, &inputs);
+ SkASSERT(inputs.isEmpty());
+ SkASSERT(fragmentLibrary);
+
+ id<MTLFunction> vertexFunction = [vertexLibrary newFunctionWithName: @"vertexMain"];
+ id<MTLFunction> fragmentFunction = [fragmentLibrary newFunctionWithName: @"fragmentMain"];
+ SkASSERT(vertexFunction);
+ SkASSERT(fragmentFunction);
+
+ fVertexFunction = vertexFunction;
+ fFragmentFunction = fragmentFunction;
+}
+
+void GrMtlCopyManager::createCopyProgramVertexDescriptor() {
+ // Create vertex descriptor for pipeline state
+ // Expected [[stage_in]] (vertex attribute) MSL format for copies:
+ //
+ // struct Input {
+ // float2 inPosition [[attribute(0)]];
+ // };
+ MTLVertexDescriptor* vertexDescriptor = [[MTLVertexDescriptor alloc] init];
+ vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2;
+ vertexDescriptor.attributes[0].offset = 0;
+ vertexDescriptor.attributes[0].bufferIndex = kAttribute_BufferIndex;
+
+ vertexDescriptor.layouts[kAttribute_BufferIndex].stepFunction = MTLVertexStepFunctionPerVertex;
+ vertexDescriptor.layouts[kAttribute_BufferIndex].stepRate = 1;
+ vertexDescriptor.layouts[kAttribute_BufferIndex].stride = sizeof(simd::float2);
+
+ fVertexDescriptor = vertexDescriptor;
+}
+
+void GrMtlCopyManager::createCopyProgram() {
+ TRACE_EVENT0("skia", TRACE_FUNC);
+
+ MTLSamplerDescriptor* samplerDescriptor = [[MTLSamplerDescriptor alloc] init];
+ fSamplerState = [fGpu->device() newSamplerStateWithDescriptor: samplerDescriptor];
+
+ this->createCopyProgramBuffer();
+ this->createCopyProgramShaders();
+ this->createCopyProgramVertexDescriptor();
+}
+
+bool GrMtlCopyManager::copySurfaceAsDraw(GrSurface* dst, GrSurfaceOrigin dstOrigin,
+ GrSurface* src, GrSurfaceOrigin srcOrigin,
+ const SkIRect& srcRect, const SkIPoint& dstPoint,
+ bool canDiscardOutsideDstRect) {
+ SkASSERT(fGpu->mtlCaps().canCopyAsDraw(dst->config(), SkToBool(dst->asRenderTarget()),
+ src->config(), SkToBool(src->asTexture())));
+
+ id<MTLTexture> dstTex = GrGetMTLTextureFromSurface(dst, false);
+ id<MTLTexture> srcTex = GrGetMTLTextureFromSurface(src, false);
+
+ if (fSamplerState == nil) {
+ SkASSERT(fVertexAttributeBuffer == nil);
+ SkASSERT(fVertexFunction == nil);
+ SkASSERT(fFragmentFunction == nil);
+ SkASSERT(fVertexDescriptor == nil);
+
+ this->createCopyProgram();
+ }
+
+ if (!(fSamplerState && fVertexAttributeBuffer && fVertexFunction &&
+ fFragmentFunction && fVertexDescriptor)) {
+ SkASSERT(false);
+ return false;
+ }
+
+ // UPDATE UNIFORM DESCRIPTOR SET
+ int w = srcRect.width();
+ int h = srcRect.height();
+
+ // dst rect edges in NDC (-1 to 1)
+ int dw = dstTex.width;
+ int dh = dstTex.height;
+ float dx0 = 2.f * dstPoint.fX / dw - 1.f;
+ float dx1 = 2.f * (dstPoint.fX + w) / dw - 1.f;
+ float dy0 = 2.f * dstPoint.fY / dh - 1.f;
+ float dy1 = 2.f * (dstPoint.fY + h) / dh - 1.f;
+ if (kBottomLeft_GrSurfaceOrigin == dstOrigin) {
+ dy0 = -dy0;
+ dy1 = -dy1;
+ }
+
+ float sx0 = (float)srcRect.fLeft;
+ float sx1 = (float)(srcRect.fLeft + w);
+ float sy0 = (float)srcRect.fTop;
+ float sy1 = (float)(srcRect.fTop + h);
+ int sh = srcTex.height;
+ if (kBottomLeft_GrSurfaceOrigin == srcOrigin) {
+ sy0 = sh - sy0;
+ sy1 = sh - sy1;
+ }
+
+ // src rect edges in normalized texture space (0 to 1).
+ int sw = srcTex.width;
+ sx0 /= sw;
+ sx1 /= sw;
+ sy0 /= sh;
+ sy1 /= sh;
+
+ const simd::float4 vertexUniformBuffer[2] = {
+ {dx1 - dx0, dy1 - dy0, dx0, dy0}, // posXform
+ {sx1 - sx0, sy1 - sy0, sx0, sy0}, // texCoordXform
+ };
+
+ MTLRenderPassDescriptor* renderPassDesc = [[MTLRenderPassDescriptor alloc] init];
+ renderPassDesc.colorAttachments[0].texture = dstTex;
+ renderPassDesc.colorAttachments[0].slice = 0;
+ renderPassDesc.colorAttachments[0].level = 0;
+ renderPassDesc.colorAttachments[0].loadAction = canDiscardOutsideDstRect ? MTLLoadActionDontCare
+ : MTLLoadActionLoad;
+ renderPassDesc.colorAttachments[0].storeAction = MTLStoreActionStore;
+
+ id<MTLRenderCommandEncoder> renderCmdEncoder =
+ [fGpu->commandBuffer() renderCommandEncoderWithDescriptor: renderPassDesc];
+ GrMtlCopyPipelineState* copyPipelineState =
+ fGpu->resourceProvider().findOrCreateCopyPipelineState(dstTex.pixelFormat,
+ fVertexFunction,
+ fFragmentFunction,
+ fVertexDescriptor);
+ [renderCmdEncoder setRenderPipelineState: copyPipelineState->mtlCopyPipelineState()];
+ [renderCmdEncoder setVertexBuffer: fVertexAttributeBuffer
+ offset: 0
+ atIndex: kAttribute_BufferIndex];
+ [renderCmdEncoder setVertexBytes: vertexUniformBuffer
+ length: sizeof(vertexUniformBuffer)
+ atIndex: kUniform_BufferIndex];
+ [renderCmdEncoder setFragmentTexture: srcTex
+ atIndex: 0];
+ [renderCmdEncoder setFragmentSamplerState: fSamplerState
+ atIndex: 0];
+ [renderCmdEncoder drawPrimitives: MTLPrimitiveTypeTriangleStrip
+ vertexStart: 0
+ vertexCount: 4];
+ [renderCmdEncoder endEncoding];
+ return true;
+}
+
+bool GrMtlCopyManager::IsCompatible(const GrMtlCopyPipelineState* pipelineState,
+ MTLPixelFormat dstPixelFormat) {
+ return pipelineState->fPixelFormat == dstPixelFormat;
+}
diff --git a/src/gpu/mtl/GrMtlCopyPipelineState.h b/src/gpu/mtl/GrMtlCopyPipelineState.h
new file mode 100644
index 0000000000..ce4cbb2bf7
--- /dev/null
+++ b/src/gpu/mtl/GrMtlCopyPipelineState.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrMtlCopyPipelineState_DEFINED
+#define GrMtlCopyPipelineState_DEFINED
+
+#import <metal/metal.h>
+
+class GrMtlGpu;
+
+class GrMtlCopyPipelineState {
+public:
+ static GrMtlCopyPipelineState* CreateCopyPipelineState(GrMtlGpu* gpu,
+ MTLPixelFormat dstPixelFormat,
+ id<MTLFunction> vertexFunction,
+ id<MTLFunction> fragmentFunction,
+ MTLVertexDescriptor* vertexDescriptor);
+
+ id<MTLRenderPipelineState> mtlCopyPipelineState() { return fPipelineState; }
+
+private:
+ GrMtlCopyPipelineState(id<MTLRenderPipelineState> pipelineState,
+ MTLPixelFormat pixelFormat)
+ : fPipelineState(pipelineState)
+ , fPixelFormat(pixelFormat) {}
+
+ id<MTLRenderPipelineState> fPipelineState;
+ MTLPixelFormat fPixelFormat;
+
+ friend class GrMtlCopyManager;
+};
+
+#endif
diff --git a/src/gpu/mtl/GrMtlCopyPipelineState.mm b/src/gpu/mtl/GrMtlCopyPipelineState.mm
new file mode 100644
index 0000000000..27b52e60f2
--- /dev/null
+++ b/src/gpu/mtl/GrMtlCopyPipelineState.mm
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrMtlCopyPipelineState.h"
+#include "GrMtlGpu.h"
+
+GrMtlCopyPipelineState* GrMtlCopyPipelineState::CreateCopyPipelineState(
+ GrMtlGpu* gpu,
+ MTLPixelFormat dstPixelFormat,
+ id<MTLFunction> vertexFunction,
+ id<MTLFunction> fragmentFunction,
+ MTLVertexDescriptor* vertexDescriptor) {
+
+ // Create pipeline state for copy as draw
+ MTLRenderPipelineDescriptor* pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
+ pipelineDescriptor.vertexFunction = vertexFunction;
+ pipelineDescriptor.fragmentFunction = fragmentFunction;
+ pipelineDescriptor.vertexDescriptor = vertexDescriptor;
+ pipelineDescriptor.colorAttachments[0].pixelFormat = dstPixelFormat;
+
+ NSError* error = nil;
+ id<MTLRenderPipelineState> pipelineState =
+ [gpu->device() newRenderPipelineStateWithDescriptor: pipelineDescriptor
+ error: &error];
+ if (error) {
+ SkDebugf("Error creating pipeline: %s\n",
+ [[error localizedDescription] cStringUsingEncoding: NSASCIIStringEncoding]);
+ return nil;
+ }
+
+ SkASSERT(pipelineState);
+ return new GrMtlCopyPipelineState(pipelineState, dstPixelFormat);
+}
diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h
index 98132fa725..4ba07205e4 100644
--- a/src/gpu/mtl/GrMtlGpu.h
+++ b/src/gpu/mtl/GrMtlGpu.h
@@ -14,6 +14,8 @@
#include "GrTexture.h"
#include "GrMtlCaps.h"
+#include "GrMtlCopyManager.h"
+#include "GrMtlResourceProvider.h"
#import <Metal/Metal.h>
@@ -21,12 +23,16 @@ class GrMtlTexture;
class GrSemaphore;
struct GrMtlBackendContext;
+namespace SkSL {
+ class Compiler;
+}
+
class GrMtlGpu : public GrGpu {
public:
static sk_sp<GrGpu> Make(GrContext* context, const GrContextOptions& options,
id<MTLDevice> device, id<MTLCommandQueue> queue);
- ~GrMtlGpu() override {}
+ ~GrMtlGpu() override = default;
const GrMtlCaps& mtlCaps() const { return *fMtlCaps.get(); }
@@ -34,6 +40,8 @@ public:
id<MTLCommandBuffer> commandBuffer() const { return fCmdBuffer; }
+ GrMtlResourceProvider& resourceProvider() { return fResourceProvider; }
+
enum SyncQueue {
kForce_SyncQueue,
kSkip_SyncQueue
@@ -73,6 +81,8 @@ public:
GrGpuTextureCommandBuffer* createCommandBuffer(GrTexture*, GrSurfaceOrigin) override;
+ SkSL::Compiler* shaderCompiler() const { return fCompiler.get(); }
+
GrFence SK_WARN_UNUSED_RESULT insertFence() override { return 0; }
bool waitFence(GrFence, uint64_t) override { return true; }
void deleteFence(GrFence) const override {}
@@ -162,6 +172,10 @@ private:
id<MTLCommandBuffer> fCmdBuffer;
+ std::unique_ptr<SkSL::Compiler> fCompiler;
+ GrMtlCopyManager fCopyManager;
+ GrMtlResourceProvider fResourceProvider;
+
typedef GrGpu INHERITED;
};
diff --git a/src/gpu/mtl/GrMtlGpu.mm b/src/gpu/mtl/GrMtlGpu.mm
index 79eeb3ad6b..2c47c3c7aa 100644
--- a/src/gpu/mtl/GrMtlGpu.mm
+++ b/src/gpu/mtl/GrMtlGpu.mm
@@ -13,6 +13,9 @@
#include "GrMtlUtil.h"
#include "GrTexturePriv.h"
#include "SkConvertPixels.h"
+#include "SkSLCompiler.h"
+
+#import <simd/simd.h>
#if !__has_feature(objc_arc)
#error This file must be compiled with Arc. Use -fobjc-arc flag
@@ -90,7 +93,10 @@ GrMtlGpu::GrMtlGpu(GrContext* context, const GrContextOptions& options,
id<MTLDevice> device, id<MTLCommandQueue> queue, MTLFeatureSet featureSet)
: INHERITED(context)
, fDevice(device)
- , fQueue(queue) {
+ , fQueue(queue)
+ , fCompiler(new SkSL::Compiler())
+ , fCopyManager(this)
+ , fResourceProvider(this) {
fMtlCaps.reset(new GrMtlCaps(options, fDevice, featureSet));
fCaps = fMtlCaps;
@@ -527,28 +533,6 @@ void GrMtlGpu::testingOnly_flushGpuAndSync() {
}
#endif // GR_TEST_UTILS
-id<MTLTexture> get_mtl_texture_from_surface(GrSurface* surface, bool doResolve) {
- 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.
- SkASSERT(false);
- } else {
- mtlTexture = renderTarget->mtlRenderTexture();
- }
- } else {
- texture = static_cast<GrMtlTexture*>(surface->asTexture());
- if (texture) {
- mtlTexture = texture->mtlTexture();
- }
- }
- return mtlTexture;
-}
-
static int get_surface_sample_cnt(GrSurface* surf) {
if (const GrRenderTarget* rt = surf->asRenderTarget()) {
return rt->numColorSamples();
@@ -566,8 +550,8 @@ bool GrMtlGpu::copySurfaceAsBlit(GrSurface* dst, GrSurfaceOrigin dstOrigin,
src->config(), srcSampleCnt, srcOrigin,
srcRect, dstPoint, dst == src));
#endif
- id<MTLTexture> dstTex = get_mtl_texture_from_surface(dst, false);
- id<MTLTexture> srcTex = get_mtl_texture_from_surface(src, false);
+ id<MTLTexture> dstTex = GrGetMTLTextureFromSurface(dst, false);
+ id<MTLTexture> srcTex = GrGetMTLTextureFromSurface(src, false);
// Flip rect if necessary
SkIRect srcMtlRect;
@@ -625,9 +609,13 @@ bool GrMtlGpu::onCopySurface(GrSurface* dst, GrSurfaceOrigin dstOrigin,
}
bool success = false;
- if (this->mtlCaps().canCopyAsBlit(dstConfig, dstSampleCnt, dstOrigin,
- srcConfig, srcSampleCnt, srcOrigin,
- srcRect, dstPoint, dst == src)) {
+ if (this->mtlCaps().canCopyAsDraw(dst->config(), SkToBool(dst->asRenderTarget()),
+ src->config(), SkToBool(src->asTexture()))) {
+ success = fCopyManager.copySurfaceAsDraw(dst, dstOrigin, src, srcOrigin, srcRect, dstPoint,
+ canDiscardOutsideDstRect);
+ } else if (this->mtlCaps().canCopyAsBlit(dstConfig, dstSampleCnt, dstOrigin,
+ srcConfig, srcSampleCnt, srcOrigin,
+ srcRect, dstPoint, dst == src)) {
success = this->copySurfaceAsBlit(dst, dstOrigin, src, srcOrigin, srcRect, dstPoint);
}
if (success) {
@@ -668,7 +656,7 @@ bool GrMtlGpu::onReadPixels(GrSurface* surface, int left, int top, int width, in
}
bool doResolve = get_surface_sample_cnt(surface) > 1;
- id<MTLTexture> mtlTexture = get_mtl_texture_from_surface(surface, doResolve);
+ id<MTLTexture> mtlTexture = GrGetMTLTextureFromSurface(surface, doResolve);
if (!mtlTexture) {
return false;
}
diff --git a/src/gpu/mtl/GrMtlResourceProvider.h b/src/gpu/mtl/GrMtlResourceProvider.h
new file mode 100644
index 0000000000..d5b66ede66
--- /dev/null
+++ b/src/gpu/mtl/GrMtlResourceProvider.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+*/
+
+#ifndef GrMtlResourceProvider_DEFINED
+#define GrMtlResourceProvider_DEFINED
+
+#include "GrMtlCopyPipelineState.h"
+#include "SkTArray.h"
+
+#import <metal/metal.h>
+
+class GrMtlGpu;
+
+class GrMtlResourceProvider {
+public:
+ GrMtlResourceProvider(GrMtlGpu* gpu) : fGpu(gpu) {}
+
+ GrMtlCopyPipelineState* findOrCreateCopyPipelineState(MTLPixelFormat dstPixelFormat,
+ id<MTLFunction> vertexFunction,
+ id<MTLFunction> fragmentFunction,
+ MTLVertexDescriptor* vertexDescriptor);
+
+private:
+ SkTArray<std::unique_ptr<GrMtlCopyPipelineState>> fCopyPipelineStateCache;
+
+ GrMtlGpu* fGpu;
+};
+
+#endif
diff --git a/src/gpu/mtl/GrMtlResourceProvider.mm b/src/gpu/mtl/GrMtlResourceProvider.mm
new file mode 100644
index 0000000000..2e1e40dfe9
--- /dev/null
+++ b/src/gpu/mtl/GrMtlResourceProvider.mm
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrMtlResourceProvider.h"
+
+#include "GrMtlCopyManager.h"
+#include "GrMtlGpu.h"
+#include "GrMtlUtil.h"
+
+#include "SkSLCompiler.h"
+
+GrMtlCopyPipelineState* GrMtlResourceProvider::findOrCreateCopyPipelineState(
+ MTLPixelFormat dstPixelFormat,
+ id<MTLFunction> vertexFunction,
+ id<MTLFunction> fragmentFunction,
+ MTLVertexDescriptor* vertexDescriptor) {
+
+ for (const auto& copyPipelineState: fCopyPipelineStateCache) {
+ if (GrMtlCopyManager::IsCompatible(copyPipelineState.get(), dstPixelFormat)) {
+ return copyPipelineState.get();
+ }
+ }
+
+ fCopyPipelineStateCache.emplace_back(GrMtlCopyPipelineState::CreateCopyPipelineState(
+ fGpu, dstPixelFormat, vertexFunction, fragmentFunction, vertexDescriptor));
+ return fCopyPipelineStateCache.back().get();
+}
diff --git a/src/gpu/mtl/GrMtlUtil.h b/src/gpu/mtl/GrMtlUtil.h
index b3a7829531..fa43295ba1 100644
--- a/src/gpu/mtl/GrMtlUtil.h
+++ b/src/gpu/mtl/GrMtlUtil.h
@@ -11,7 +11,10 @@
#import <Metal/Metal.h>
#include "GrTypesPriv.h"
+#include "ir/SkSLProgram.h"
+class GrMtlGpu;
+class GrSurface;
/**
* Returns the Metal texture format for the given GrPixelConfig
@@ -45,4 +48,18 @@ const void* GrReleaseId(id idObject);
*/
MTLTextureDescriptor* GrGetMTLTextureDescriptor(id<MTLTexture> mtlTexture);
+/**
+ * Returns a compiled MTLLibrary created from MSL code generated by SkSLC
+ */
+id<MTLLibrary> GrCompileMtlShaderLibrary(const GrMtlGpu* gpu,
+ const char* shaderString,
+ SkSL::Program::Kind kind,
+ const SkSL::Program::Settings& settings,
+ SkSL::Program::Inputs* outInputs);
+
+/**
+ * Returns a MTLTexture corresponding to the GrSurface. Optionally can do a resolve.
+ */
+id<MTLTexture> GrGetMTLTextureFromSurface(GrSurface* surface, bool doResolve);
+
#endif
diff --git a/src/gpu/mtl/GrMtlUtil.mm b/src/gpu/mtl/GrMtlUtil.mm
index 5a58a259d4..f544421adc 100644
--- a/src/gpu/mtl/GrMtlUtil.mm
+++ b/src/gpu/mtl/GrMtlUtil.mm
@@ -8,6 +8,15 @@
#include "GrMtlUtil.h"
#include "GrTypesPriv.h"
+#include "GrSurface.h"
+#include "mtl/GrMtlGpu.h"
+#include "mtl/GrMtlTexture.h"
+#include "mtl/GrMtlRenderTarget.h"
+#include "SkSLCompiler.h"
+
+#import <Metal/Metal.h>
+
+#define PRINT_MSL 0 // print out the MSL code generated
bool GrPixelConfigToMTLFormat(GrPixelConfig config, MTLPixelFormat* format) {
MTLPixelFormat dontCare;
@@ -143,3 +152,78 @@ MTLTextureDescriptor* GrGetMTLTextureDescriptor(id<MTLTexture> mtlTexture) {
texDesc.usage = mtlTexture.usage;
return texDesc;
}
+
+#if PRINT_MSL
+void print_msl(const char* source) {
+ SkTArray<SkString> lines;
+ SkStrSplit(source, "\n", kStrict_SkStrSplitMode, &lines);
+ for (int i = 0; i < lines.count(); i++) {
+ SkString& line = lines[i];
+ line.prependf("%4i\t", i + 1);
+ SkDebugf("%s\n", line.c_str());
+ }
+}
+#endif
+
+id<MTLLibrary> GrCompileMtlShaderLibrary(const GrMtlGpu* gpu,
+ const char* shaderString,
+ SkSL::Program::Kind kind,
+ const SkSL::Program::Settings& settings,
+ SkSL::Program::Inputs* outInputs) {
+ std::unique_ptr<SkSL::Program> program =
+ gpu->shaderCompiler()->convertProgram(kind,
+ SkSL::String(shaderString),
+ settings);
+
+ if (!program) {
+ SkDebugf("SkSL error:\n%s\n", gpu->shaderCompiler()->errorText().c_str());
+ SkASSERT(false);
+ }
+
+ *outInputs = program->fInputs;
+ SkSL::String code;
+ if (!gpu->shaderCompiler()->toMetal(*program, &code)) {
+ SkDebugf("%s\n", gpu->shaderCompiler()->errorText().c_str());
+ SkASSERT(false);
+ return nil;
+ }
+ NSString* mtlCode = [[NSString alloc] initWithCString: code.c_str()
+ encoding: NSASCIIStringEncoding];
+#if PRINT_MSL
+ print_msl([mtlCode cStringUsingEncoding: NSASCIIStringEncoding]);
+#endif
+
+ MTLCompileOptions* defaultOptions = [[MTLCompileOptions alloc] init];
+ NSError* error = nil;
+ id<MTLLibrary> compiledLibrary = [gpu->device() newLibraryWithSource: mtlCode
+ options: defaultOptions
+ error: &error];
+ if (error) {
+ SkDebugf("Error compiling MSL shader: %s\n",
+ [[error localizedDescription] cStringUsingEncoding: NSASCIIStringEncoding]);
+ return nil;
+ }
+ return compiledLibrary;
+}
+
+id<MTLTexture> GrGetMTLTextureFromSurface(GrSurface* surface, bool doResolve) {
+ 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.
+ SkASSERT(false);
+ } else {
+ mtlTexture = renderTarget->mtlRenderTexture();
+ }
+ } else {
+ texture = static_cast<GrMtlTexture*>(surface->asTexture());
+ if (texture) {
+ mtlTexture = texture->mtlTexture();
+ }
+ }
+ return mtlTexture;
+}