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 "include/core/SkCanvas.h" 10#include "include/core/SkColorFilter.h" 11#include "include/gpu/GrDirectContext.h" 12#include "include/gpu/GrRecordingContext.h" 13#include "include/gpu/gl/GrGLInterface.h" 14#include "tools/ToolUtils.h" 15#include "tools/window/GLWindowContext.h" 16#include "tools/window/ios/WindowContextFactory_ios.h" 17#include "include/gpu/ganesh/gl/ios/GrGLMakeIOSInterface.h" 18 19#import <OpenGLES/ES3/gl.h> 20#import <UIKit/UIKit.h> 21 22using skwindow::DisplayParams; 23using skwindow::IOSWindowInfo; 24using skwindow::internal::GLWindowContext; 25 26@interface RasterView : MainView 27@end 28 29@implementation RasterView 30+ (Class) layerClass { 31 return [CAEAGLLayer class]; 32} 33@end 34 35namespace { 36 37// TODO: This still uses GL to handle the update rather than using a purely raster backend, 38// for historical reasons. Writing a pure raster backend would be better in the long run. 39 40class RasterWindowContext_ios : public GLWindowContext { 41public: 42 RasterWindowContext_ios(const IOSWindowInfo&, const DisplayParams&); 43 44 ~RasterWindowContext_ios() override; 45 46 sk_sp<SkSurface> getBackbufferSurface() override; 47 48 sk_sp<const GrGLInterface> onInitializeContext() override; 49 void onDestroyContext() override; 50 51 void resize(int w, int h) override; 52 53private: 54 void onSwapBuffers() override; 55 56 sk_app::Window_ios* fWindow; 57 UIViewController* fViewController; 58 RasterView* fRasterView; 59 EAGLContext* fGLContext; 60 GLuint fFramebuffer; 61 GLuint fRenderbuffer; 62 sk_sp<SkSurface> fBackbufferSurface; 63}; 64 65RasterWindowContext_ios::RasterWindowContext_ios(const IOSWindowInfo& info, 66 const DisplayParams& params) 67 : GLWindowContext(params) 68 , fWindow(info.fWindow) 69 , fViewController(info.fViewController) 70 , fGLContext(nil) { 71 72 // any config code here (particularly for msaa)? 73 74 this->initializeContext(); 75} 76 77RasterWindowContext_ios::~RasterWindowContext_ios() { 78 this->destroyContext(); 79 [fRasterView removeFromSuperview]; 80 [fRasterView release]; 81} 82 83sk_sp<const GrGLInterface> RasterWindowContext_ios::onInitializeContext() { 84 SkASSERT(nil != fViewController); 85 SkASSERT(!fGLContext); 86 87 CGRect frameRect = [fViewController.view frame]; 88 fRasterView = [[[RasterView alloc] initWithFrame:frameRect] initWithWindow:fWindow]; 89 [fViewController.view addSubview:fRasterView]; 90 91 fGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; 92 93 if (!fGLContext) 94 { 95 SkDebugf("Could Not Create OpenGL ES Context\n"); 96 return nullptr; 97 } 98 99 if (![EAGLContext setCurrentContext:fGLContext]) { 100 SkDebugf("Could Not Set OpenGL ES Context As Current\n"); 101 this->onDestroyContext(); 102 return nullptr; 103 } 104 105 // Set up EAGLLayer 106 CAEAGLLayer* eaglLayer = (CAEAGLLayer*)fRasterView.layer; 107 eaglLayer.drawableProperties = @{kEAGLDrawablePropertyRetainedBacking : @NO, 108 kEAGLDrawablePropertyColorFormat : kEAGLColorFormatRGBA8 }; 109 eaglLayer.opaque = YES; 110 eaglLayer.frame = frameRect; 111 eaglLayer.contentsGravity = kCAGravityTopLeft; 112 113 // Set up framebuffer 114 glGenFramebuffers(1, &fFramebuffer); 115 glBindFramebuffer(GL_FRAMEBUFFER, fFramebuffer); 116 117 glGenRenderbuffers(1, &fRenderbuffer); 118 glBindRenderbuffer(GL_RENDERBUFFER, fRenderbuffer); 119 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fRenderbuffer); 120 121 [fGLContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:eaglLayer]; 122 123 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 124 if (status != GL_FRAMEBUFFER_COMPLETE) { 125 SkDebugf("Invalid Framebuffer\n"); 126 this->onDestroyContext(); 127 return nullptr; 128 } 129 130 glClearStencil(0); 131 glClearColor(0, 0, 0, 255); 132 glStencilMask(0xffffffff); 133 glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 134 135 fStencilBits = 8; 136 fSampleCount = 1; // TODO: handle multisampling 137 138 fWidth = fViewController.view.frame.size.width; 139 fHeight = fViewController.view.frame.size.height; 140 141 glViewport(0, 0, fWidth, fHeight); 142 143 // make the offscreen image 144 SkImageInfo info = SkImageInfo::Make(fWidth, fHeight, fDisplayParams.fColorType, 145 kPremul_SkAlphaType, fDisplayParams.fColorSpace); 146 fBackbufferSurface = SkSurfaces::Raster(info); 147 return GrGLInterfaces::MakeIOS(); 148} 149 150void RasterWindowContext_ios::onDestroyContext() { 151 glDeleteFramebuffers(1, &fFramebuffer); 152 glDeleteRenderbuffers(1, &fRenderbuffer); 153 [EAGLContext setCurrentContext:nil]; 154 [fGLContext release]; 155 fGLContext = nil; 156} 157 158sk_sp<SkSurface> RasterWindowContext_ios::getBackbufferSurface() { 159 return fBackbufferSurface; 160} 161 162void RasterWindowContext_ios::onSwapBuffers() { 163 if (fBackbufferSurface) { 164 // We made/have an off-screen surface. Get the contents as an SkImage: 165 sk_sp<SkImage> snapshot = fBackbufferSurface->makeImageSnapshot(); 166 167 sk_sp<SkSurface> gpuSurface = GLWindowContext::getBackbufferSurface(); 168 SkCanvas* gpuCanvas = gpuSurface->getCanvas(); 169 gpuCanvas->drawImage(snapshot, 0, 0); 170 auto dContext = GrAsDirectContext(gpuCanvas->recordingContext()); 171 dContext->flushAndSubmit(); 172 173 glBindRenderbuffer(GL_RENDERBUFFER, fRenderbuffer); 174 [fGLContext presentRenderbuffer:GL_RENDERBUFFER]; 175 } 176} 177 178void RasterWindowContext_ios::resize(int w, int h) { 179 // TODO: handle rotation 180 // [fGLContext update]; 181 GLWindowContext::resize(w, h); 182} 183 184} // anonymous namespace 185 186namespace skwindow { 187 188std::unique_ptr<WindowContext> MakeRasterForIOS(const IOSWindowInfo& info, 189 const DisplayParams& params) { 190 std::unique_ptr<WindowContext> ctx(new RasterWindowContext_ios(info, params)); 191 if (!ctx->isValid()) { 192 return nullptr; 193 } 194 return ctx; 195} 196 197} // namespace skwindow 198