Home | History | Annotate | Download | only in mtl
      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 
     24 void 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), GrGpuBufferType::kVertex,
     33                                                      kStatic_GrAccessPattern, vdata);
     34     fVertexAttributeBuffer = mtlBuffer->mtlBuffer();
     35 }
     36 
     37 void 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 
     98 void 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 
    117 void 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 
    128 bool 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 
    224 bool GrMtlCopyManager::IsCompatible(const GrMtlCopyPipelineState* pipelineState,
    225                                     MTLPixelFormat dstPixelFormat) {
    226     return pipelineState->fPixelFormat == dstPixelFormat;
    227 }
    228