Home | History | Annotate | Download | only in sk_app
      1 
      2 /*
      3  * Copyright 2019 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 #include "MetalWindowContext.h"
     10 #include "GrBackendSurface.h"
     11 #include "GrCaps.h"
     12 #include "GrContext.h"
     13 #include "GrContextPriv.h"
     14 #include "SkCanvas.h"
     15 #include "SkImage_Base.h"
     16 #include "SkMathPriv.h"
     17 #include "SkSurface.h"
     18 #include "mtl/GrMtlTypes.h"
     19 
     20 namespace sk_app {
     21 
     22 static int kMaxBuffersInFlight = 3;
     23 
     24 MetalWindowContext::MetalWindowContext(const DisplayParams& params)
     25     : WindowContext(params)
     26     , fValid(false)
     27     , fSurface(nullptr) {
     28     fDisplayParams.fMSAASampleCount = GrNextPow2(fDisplayParams.fMSAASampleCount);
     29 }
     30 
     31 void MetalWindowContext::initializeContext() {
     32     SkASSERT(!fContext);
     33 
     34     // The subclass uses these to initialize their view
     35     fDevice = MTLCreateSystemDefaultDevice();
     36     fQueue = [fDevice newCommandQueue];
     37 
     38     fInFlightSemaphore = dispatch_semaphore_create(kMaxBuffersInFlight);
     39 
     40     fValid = this->onInitializeContext();
     41     fContext = GrContext::MakeMetal(fDevice, fQueue, fDisplayParams.fGrContextOptions);
     42     if (!fContext && fDisplayParams.fMSAASampleCount > 1) {
     43         fDisplayParams.fMSAASampleCount /= 2;
     44         this->initializeContext();
     45         return;
     46     }
     47 }
     48 
     49 void MetalWindowContext::destroyContext() {
     50     fSurface.reset(nullptr);
     51 
     52     if (fContext) {
     53         // in case we have outstanding refs to this guy (lua?)
     54         fContext->abandonContext();
     55         fContext.reset();
     56     }
     57 
     58     // TODO: Figure out who's releasing this
     59     // [fQueue release];
     60     [fDevice release];
     61 
     62     this->onDestroyContext();
     63 }
     64 
     65 sk_sp<SkSurface> MetalWindowContext::getBackbufferSurface() {
     66     sk_sp<SkSurface> surface;
     67     if (fContext) {
     68         GrMtlTextureInfo fbInfo;
     69         fbInfo.fTexture = [[fMTKView currentDrawable] texture];
     70 
     71         GrBackendRenderTarget backendRT(fWidth,
     72                                         fHeight,
     73                                         fSampleCount,
     74                                         fbInfo);
     75 
     76         surface = SkSurface::MakeFromBackendRenderTarget(fContext.get(), backendRT,
     77                                                           kTopLeft_GrSurfaceOrigin,
     78                                                           kBGRA_8888_SkColorType,
     79                                                           fDisplayParams.fColorSpace,
     80                                                           &fDisplayParams.fSurfaceProps);
     81     }
     82 
     83     return surface;
     84 }
     85 
     86 void MetalWindowContext::swapBuffers() {
     87     // Block to ensure we don't try to render to a frame that hasn't finished presenting
     88     dispatch_semaphore_wait(fInFlightSemaphore, DISPATCH_TIME_FOREVER);
     89 
     90     id<MTLCommandBuffer> commandBuffer = [fQueue commandBuffer];
     91     commandBuffer.label = @"Present";
     92 
     93     __block dispatch_semaphore_t block_sema = fInFlightSemaphore;
     94     [commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer)
     95      {
     96          dispatch_semaphore_signal(block_sema);
     97      }];
     98 
     99     id<MTLDrawable> drawable = [fMTKView currentDrawable];
    100     [commandBuffer presentDrawable:drawable];
    101     [commandBuffer commit];
    102 }
    103 
    104 void MetalWindowContext::resize(int w, int h) {
    105     this->destroyContext();
    106     this->initializeContext();
    107 }
    108 
    109 void MetalWindowContext::setDisplayParams(const DisplayParams& params) {
    110     this->destroyContext();
    111     fDisplayParams = params;
    112     this->initializeContext();
    113 }
    114 
    115 }   //namespace sk_app
    116