• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrMtlCopyManager.h"
9
10#include "GrSurface.h"
11
12#include "GrMtlBuffer.h"
13#include "GrMtlCopyPipelineState.h"
14#include "GrMtlGpu.h"
15#include "GrMtlResourceProvider.h"
16#include "GrMtlUtil.h"
17
18#include "SkPoint.h"
19#include "SkRect.h"
20#include "SkTraceEvent.h"
21
22#import <simd/simd.h>
23
24void GrMtlCopyManager::createCopyProgramBuffer() {
25    // Create per vertex attribute data for copy as draw
26    static const simd::float2 vdata[4] = {
27        {0, 0},
28        {0, 1},
29        {1, 0},
30        {1, 1},
31    };
32    sk_sp<GrMtlBuffer> mtlBuffer = GrMtlBuffer::Make(fGpu, sizeof(vdata), kVertex_GrBufferType,
33                                                     kStatic_GrAccessPattern, vdata);
34    fVertexAttributeBuffer = mtlBuffer->mtlBuffer();
35}
36
37void GrMtlCopyManager::createCopyProgramShaders() {
38     // Create shaders required by pipeline state
39    const GrShaderCaps* shaderCaps = fGpu->caps()->shaderCaps();
40    const char* version = shaderCaps->versionDeclString();
41    SkString vertShaderText(version);
42    vertShaderText.appendf(
43        "#extension GL_ARB_separate_shader_objects : enable\n"
44        "#extension GL_ARB_shading_language_420pack : enable\n"
45        "layout(set = %d"/*kUniform_BufferIndex*/", binding = 0) uniform vertexUniformBuffer {"
46            "float4 uPosXform;"
47            "float4 uTexCoordXform;"
48        "};"
49        "layout(location = 0) in float2 inPosition;"
50        "layout(location = 1) out float2 vTexCoord;"
51
52        "// Copy Program VS\n"
53        "void main() {"
54            "vTexCoord = inPosition * uTexCoordXform.xy + uTexCoordXform.zw;"
55            "sk_Position.xy = inPosition * uPosXform.xy + uPosXform.zw;"
56            "sk_Position.zw = float2(0, 1);"
57        "}",
58        kUniform_BufferIndex
59    );
60
61    SkString fragShaderText(version);
62    fragShaderText.append(
63        "#extension GL_ARB_separate_shader_objects : enable\n"
64        "#extension GL_ARB_shading_language_420pack : enable\n"
65
66        "layout(set = 1, binding = 0) uniform sampler2D uTexture;"
67        "layout(location = 1) in float2 vTexCoord;"
68
69        "// Copy Program FS\n"
70        "void main() {"
71            "sk_FragColor = texture(uTexture, vTexCoord);"
72        "}"
73    );
74
75    SkSL::Program::Settings settings;
76    SkSL::Program::Inputs inputs;
77    id<MTLLibrary> vertexLibrary = GrCompileMtlShaderLibrary(fGpu, vertShaderText.c_str(),
78                                                             SkSL::Program::kVertex_Kind,
79                                                             settings, &inputs);
80    SkASSERT(inputs.isEmpty());
81    SkASSERT(vertexLibrary);
82
83    id<MTLLibrary> fragmentLibrary = GrCompileMtlShaderLibrary(fGpu, fragShaderText.c_str(),
84                                                               SkSL::Program::kFragment_Kind,
85                                                               settings, &inputs);
86    SkASSERT(inputs.isEmpty());
87    SkASSERT(fragmentLibrary);
88
89    id<MTLFunction> vertexFunction = [vertexLibrary newFunctionWithName: @"vertexMain"];
90    id<MTLFunction> fragmentFunction = [fragmentLibrary newFunctionWithName: @"fragmentMain"];
91    SkASSERT(vertexFunction);
92    SkASSERT(fragmentFunction);
93
94    fVertexFunction = vertexFunction;
95    fFragmentFunction = fragmentFunction;
96}
97
98void GrMtlCopyManager::createCopyProgramVertexDescriptor() {
99    // Create vertex descriptor for pipeline state
100    // Expected [[stage_in]] (vertex attribute) MSL format for copies:
101    //
102    // struct Input {
103    //     float2 inPosition [[attribute(0)]];
104    // };
105    MTLVertexDescriptor* vertexDescriptor = [[MTLVertexDescriptor alloc] init];
106    vertexDescriptor.attributes[0].format = MTLVertexFormatFloat2;
107    vertexDescriptor.attributes[0].offset = 0;
108    vertexDescriptor.attributes[0].bufferIndex = kAttribute_BufferIndex;
109
110    vertexDescriptor.layouts[kAttribute_BufferIndex].stepFunction = MTLVertexStepFunctionPerVertex;
111    vertexDescriptor.layouts[kAttribute_BufferIndex].stepRate = 1;
112    vertexDescriptor.layouts[kAttribute_BufferIndex].stride = sizeof(simd::float2);
113
114    fVertexDescriptor = vertexDescriptor;
115}
116
117void GrMtlCopyManager::createCopyProgram() {
118    TRACE_EVENT0("skia", TRACE_FUNC);
119
120    MTLSamplerDescriptor* samplerDescriptor = [[MTLSamplerDescriptor alloc] init];
121    fSamplerState = [fGpu->device() newSamplerStateWithDescriptor: samplerDescriptor];
122
123    this->createCopyProgramBuffer();
124    this->createCopyProgramShaders();
125    this->createCopyProgramVertexDescriptor();
126}
127
128bool GrMtlCopyManager::copySurfaceAsDraw(GrSurface* dst, GrSurfaceOrigin dstOrigin,
129                                         GrSurface* src, GrSurfaceOrigin srcOrigin,
130                                         const SkIRect& srcRect, const SkIPoint& dstPoint,
131                                         bool canDiscardOutsideDstRect) {
132    SkASSERT(fGpu->mtlCaps().canCopyAsDraw(dst->config(), SkToBool(dst->asRenderTarget()),
133                                           src->config(), SkToBool(src->asTexture())));
134
135    id<MTLTexture> dstTex = GrGetMTLTextureFromSurface(dst, false);
136    id<MTLTexture> srcTex = GrGetMTLTextureFromSurface(src, false);
137
138    if (fSamplerState == nil) {
139        SkASSERT(fVertexAttributeBuffer == nil);
140        SkASSERT(fVertexFunction == nil);
141        SkASSERT(fFragmentFunction == nil);
142        SkASSERT(fVertexDescriptor == nil);
143
144        this->createCopyProgram();
145    }
146
147    if (!(fSamplerState && fVertexAttributeBuffer && fVertexFunction &&
148          fFragmentFunction && fVertexDescriptor)) {
149        SkASSERT(false);
150        return false;
151    }
152
153    // UPDATE UNIFORM DESCRIPTOR SET
154    int w = srcRect.width();
155    int h = srcRect.height();
156
157    // dst rect edges in NDC (-1 to 1)
158    int dw = dstTex.width;
159    int dh = dstTex.height;
160    float dx0 = 2.f * dstPoint.fX / dw - 1.f;
161    float dx1 = 2.f * (dstPoint.fX + w) / dw - 1.f;
162    float dy0 = 2.f * dstPoint.fY / dh - 1.f;
163    float dy1 = 2.f * (dstPoint.fY + h) / dh - 1.f;
164    if (kBottomLeft_GrSurfaceOrigin == dstOrigin) {
165        dy0 = -dy0;
166        dy1 = -dy1;
167    }
168
169    float sx0 = (float)srcRect.fLeft;
170    float sx1 = (float)(srcRect.fLeft + w);
171    float sy0 = (float)srcRect.fTop;
172    float sy1 = (float)(srcRect.fTop + h);
173    int sh = srcTex.height;
174    if (kBottomLeft_GrSurfaceOrigin == srcOrigin) {
175        sy0 = sh - sy0;
176        sy1 = sh - sy1;
177    }
178
179    // src rect edges in normalized texture space (0 to 1).
180    int sw = srcTex.width;
181    sx0 /= sw;
182    sx1 /= sw;
183    sy0 /= sh;
184    sy1 /= sh;
185
186    const simd::float4 vertexUniformBuffer[2] = {
187        {dx1 - dx0, dy1 - dy0, dx0, dy0}, // posXform
188        {sx1 - sx0, sy1 - sy0, sx0, sy0}, // texCoordXform
189    };
190
191    MTLRenderPassDescriptor* renderPassDesc = [[MTLRenderPassDescriptor alloc] init];
192    renderPassDesc.colorAttachments[0].texture = dstTex;
193    renderPassDesc.colorAttachments[0].slice = 0;
194    renderPassDesc.colorAttachments[0].level = 0;
195    renderPassDesc.colorAttachments[0].loadAction = canDiscardOutsideDstRect ? MTLLoadActionDontCare
196                                                                             : MTLLoadActionLoad;
197    renderPassDesc.colorAttachments[0].storeAction = MTLStoreActionStore;
198
199    id<MTLRenderCommandEncoder> renderCmdEncoder =
200            [fGpu->commandBuffer() renderCommandEncoderWithDescriptor: renderPassDesc];
201    GrMtlCopyPipelineState* copyPipelineState =
202            fGpu->resourceProvider().findOrCreateCopyPipelineState(dstTex.pixelFormat,
203                                                                   fVertexFunction,
204                                                                   fFragmentFunction,
205                                                                   fVertexDescriptor);
206    [renderCmdEncoder setRenderPipelineState: copyPipelineState->mtlCopyPipelineState()];
207    [renderCmdEncoder setVertexBuffer: fVertexAttributeBuffer
208                               offset: 0
209                              atIndex: kAttribute_BufferIndex];
210    [renderCmdEncoder setVertexBytes: vertexUniformBuffer
211                              length: sizeof(vertexUniformBuffer)
212                             atIndex: kUniform_BufferIndex];
213    [renderCmdEncoder setFragmentTexture: srcTex
214                                 atIndex: 0];
215    [renderCmdEncoder setFragmentSamplerState: fSamplerState
216                                      atIndex: 0];
217    [renderCmdEncoder drawPrimitives: MTLPrimitiveTypeTriangleStrip
218                         vertexStart: 0
219                         vertexCount: 4];
220    [renderCmdEncoder endEncoding];
221    return true;
222}
223
224bool GrMtlCopyManager::IsCompatible(const GrMtlCopyPipelineState* pipelineState,
225                                    MTLPixelFormat dstPixelFormat) {
226    return pipelineState->fPixelFormat == dstPixelFormat;
227}
228