blob: 84f8f396cae4484b809b21971519b72076a48c06 [file] [log] [blame]
Timothy Liange30739a2018-07-31 10:51:17 -04001/*
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
Timothy Liang49528b62018-08-02 14:18:37 -040012#include "GrMtlBuffer.h"
Timothy Liange30739a2018-07-31 10:51:17 -040013#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 };
Timothy Liang49528b62018-08-02 14:18:37 -040032 sk_sp<GrMtlBuffer> mtlBuffer(GrMtlBuffer::Create(fGpu, sizeof(vdata), kVertex_GrBufferType,
33 kStatic_GrAccessPattern, vdata));
34 fVertexAttributeBuffer = mtlBuffer->mtlBuffer();
Timothy Liange30739a2018-07-31 10:51:17 -040035}
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}