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/ganesh/GrDirectContext.h" 12#include "include/gpu/ganesh/GrRecordingContext.h" 13#include "include/gpu/ganesh/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&, std::unique_ptr<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 std::unique_ptr<const DisplayParams> params) 67 : GLWindowContext(std::move(params)) 68 , fWindow(info.fWindow) 69 , fViewController(info.fViewController) 70 , fGLContext(nil) { 71 // any config code here (particularly for msaa)? 72 73 this->initializeContext(); 74} 75 76RasterWindowContext_ios::~RasterWindowContext_ios() { 77 this->destroyContext(); 78 [fRasterView removeFromSuperview]; 79 [fRasterView release]; 80} 81 82sk_sp<const GrGLInterface> RasterWindowContext_ios::onInitializeContext() { 83 SkASSERT(nil != fViewController); 84 SkASSERT(!fGLContext); 85 86 CGRect frameRect = [fViewController.view frame]; 87 fRasterView = [[[RasterView alloc] initWithFrame:frameRect] initWithWindow:fWindow]; 88 [fViewController.view addSubview:fRasterView]; 89 90 fGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; 91 92 if (!fGLContext) 93 { 94 SkDebugf("Could Not Create OpenGL ES Context\n"); 95 return nullptr; 96 } 97 98 if (![EAGLContext setCurrentContext:fGLContext]) { 99 SkDebugf("Could Not Set OpenGL ES Context As Current\n"); 100 this->onDestroyContext(); 101 return nullptr; 102 } 103 104 // Set up EAGLLayer 105 CAEAGLLayer* eaglLayer = (CAEAGLLayer*)fRasterView.layer; 106 eaglLayer.drawableProperties = @{kEAGLDrawablePropertyRetainedBacking : @NO, 107 kEAGLDrawablePropertyColorFormat : kEAGLColorFormatRGBA8 }; 108 eaglLayer.opaque = YES; 109 eaglLayer.frame = frameRect; 110 eaglLayer.contentsGravity = kCAGravityTopLeft; 111 112 // Set up framebuffer 113 glGenFramebuffers(1, &fFramebuffer); 114 glBindFramebuffer(GL_FRAMEBUFFER, fFramebuffer); 115 116 glGenRenderbuffers(1, &fRenderbuffer); 117 glBindRenderbuffer(GL_RENDERBUFFER, fRenderbuffer); 118 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fRenderbuffer); 119 120 [fGLContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:eaglLayer]; 121 122 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 123 if (status != GL_FRAMEBUFFER_COMPLETE) { 124 SkDebugf("Invalid Framebuffer\n"); 125 this->onDestroyContext(); 126 return nullptr; 127 } 128 129 glClearStencil(0); 130 glClearColor(0, 0, 0, 255); 131 glStencilMask(0xffffffff); 132 glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 133 134 fStencilBits = 8; 135 fSampleCount = 1; // TODO: handle multisampling 136 137 fWidth = fViewController.view.frame.size.width; 138 fHeight = fViewController.view.frame.size.height; 139 140 glViewport(0, 0, fWidth, fHeight); 141 142 // make the offscreen image 143 SkImageInfo info = SkImageInfo::Make(fWidth, 144 fHeight, 145 fDisplayParams->colorType(), 146 kPremul_SkAlphaType, 147 fDisplayParams->colorSpace()); 148 fBackbufferSurface = SkSurfaces::Raster(info); 149 return GrGLInterfaces::MakeIOS(); 150} 151 152void RasterWindowContext_ios::onDestroyContext() { 153 glDeleteFramebuffers(1, &fFramebuffer); 154 glDeleteRenderbuffers(1, &fRenderbuffer); 155 [EAGLContext setCurrentContext:nil]; 156 [fGLContext release]; 157 fGLContext = nil; 158} 159 160sk_sp<SkSurface> RasterWindowContext_ios::getBackbufferSurface() { 161 return fBackbufferSurface; 162} 163 164void RasterWindowContext_ios::onSwapBuffers() { 165 if (fBackbufferSurface) { 166 // We made/have an off-screen surface. Get the contents as an SkImage: 167 sk_sp<SkImage> snapshot = fBackbufferSurface->makeImageSnapshot(); 168 169 sk_sp<SkSurface> gpuSurface = GLWindowContext::getBackbufferSurface(); 170 SkCanvas* gpuCanvas = gpuSurface->getCanvas(); 171 gpuCanvas->drawImage(snapshot, 0, 0); 172 auto dContext = GrAsDirectContext(gpuCanvas->recordingContext()); 173 dContext->flushAndSubmit(); 174 175 glBindRenderbuffer(GL_RENDERBUFFER, fRenderbuffer); 176 [fGLContext presentRenderbuffer:GL_RENDERBUFFER]; 177 } 178} 179 180void RasterWindowContext_ios::resize(int w, int h) { 181 // TODO: handle rotation 182 // [fGLContext update]; 183 GLWindowContext::resize(w, h); 184} 185 186} // anonymous namespace 187 188namespace skwindow { 189 190std::unique_ptr<WindowContext> MakeRasterForIOS(const IOSWindowInfo& info, 191 std::unique_ptr<const DisplayParams> params) { 192 std::unique_ptr<WindowContext> ctx(new RasterWindowContext_ios(info, std::move(params))); 193 if (!ctx->isValid()) { 194 return nullptr; 195 } 196 return ctx; 197} 198 199} // namespace skwindow 200