/* * Copyright 2019 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "MetalWindowContext.h" #include "GrBackendSurface.h" #include "GrCaps.h" #include "GrContext.h" #include "GrContextPriv.h" #include "SkCanvas.h" #include "SkImage_Base.h" #include "SkMathPriv.h" #include "SkSurface.h" #include "mtl/GrMtlTypes.h" namespace sk_app { static int kMaxBuffersInFlight = 3; MetalWindowContext::MetalWindowContext(const DisplayParams& params) : WindowContext(params) , fValid(false) , fSurface(nullptr) { fDisplayParams.fMSAASampleCount = GrNextPow2(fDisplayParams.fMSAASampleCount); } void MetalWindowContext::initializeContext() { SkASSERT(!fContext); // The subclass uses these to initialize their view fDevice = MTLCreateSystemDefaultDevice(); fQueue = [fDevice newCommandQueue]; fInFlightSemaphore = dispatch_semaphore_create(kMaxBuffersInFlight); fValid = this->onInitializeContext(); fContext = GrContext::MakeMetal(fDevice, fQueue, fDisplayParams.fGrContextOptions); if (!fContext && fDisplayParams.fMSAASampleCount > 1) { fDisplayParams.fMSAASampleCount /= 2; this->initializeContext(); return; } } void MetalWindowContext::destroyContext() { fSurface.reset(nullptr); if (fContext) { // in case we have outstanding refs to this guy (lua?) fContext->abandonContext(); fContext.reset(); } // TODO: Figure out who's releasing this // [fQueue release]; [fDevice release]; this->onDestroyContext(); } sk_sp MetalWindowContext::getBackbufferSurface() { sk_sp surface; if (fContext) { GrMtlTextureInfo fbInfo; fbInfo.fTexture = [[fMTKView currentDrawable] texture]; GrBackendRenderTarget backendRT(fWidth, fHeight, fSampleCount, fbInfo); surface = SkSurface::MakeFromBackendRenderTarget(fContext.get(), backendRT, kTopLeft_GrSurfaceOrigin, kBGRA_8888_SkColorType, fDisplayParams.fColorSpace, &fDisplayParams.fSurfaceProps); } return surface; } void MetalWindowContext::swapBuffers() { // Block to ensure we don't try to render to a frame that hasn't finished presenting dispatch_semaphore_wait(fInFlightSemaphore, DISPATCH_TIME_FOREVER); id commandBuffer = [fQueue commandBuffer]; commandBuffer.label = @"Present"; __block dispatch_semaphore_t block_sema = fInFlightSemaphore; [commandBuffer addCompletedHandler:^(id buffer) { dispatch_semaphore_signal(block_sema); }]; id drawable = [fMTKView currentDrawable]; [commandBuffer presentDrawable:drawable]; [commandBuffer commit]; } void MetalWindowContext::resize(int w, int h) { this->destroyContext(); this->initializeContext(); } void MetalWindowContext::setDisplayParams(const DisplayParams& params) { this->destroyContext(); fDisplayParams = params; this->initializeContext(); } } //namespace sk_app