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/gl/GrGLInterface.h" 12#include "tools/ToolUtils.h" 13#include "tools/sk_app/GLWindowContext.h" 14#include "tools/sk_app/ios/WindowContextFactory_ios.h" 15 16#import <OpenGLES/ES3/gl.h> 17#import <UIKit/UIKit.h> 18 19using sk_app::DisplayParams; 20using sk_app::window_context_factory::IOSWindowInfo; 21using sk_app::GLWindowContext; 22 23@interface RasterView : MainView 24@end 25 26@implementation RasterView 27+ (Class) layerClass { 28 return [CAEAGLLayer class]; 29} 30@end 31 32namespace { 33 34// TODO: This still uses GL to handle the update rather than using a purely raster backend, 35// for historical reasons. Writing a pure raster backend would be better in the long run. 36 37class RasterWindowContext_ios : public GLWindowContext { 38public: 39 RasterWindowContext_ios(const IOSWindowInfo&, const DisplayParams&); 40 41 ~RasterWindowContext_ios() override; 42 43 sk_sp<SkSurface> getBackbufferSurface() override; 44 45 void onSwapBuffers() override; 46 47 sk_sp<const GrGLInterface> onInitializeContext() override; 48 void onDestroyContext() override; 49 50 void resize(int w, int h) override; 51 52private: 53 sk_app::Window_ios* fWindow; 54 UIViewController* fViewController; 55 RasterView* fRasterView; 56 EAGLContext* fGLContext; 57 GLuint fFramebuffer; 58 GLuint fRenderbuffer; 59 sk_sp<SkSurface> fBackbufferSurface; 60 61 using INHERITED = GLWindowContext; 62}; 63 64RasterWindowContext_ios::RasterWindowContext_ios(const IOSWindowInfo& info, 65 const DisplayParams& params) 66 : INHERITED(params) 67 , fWindow(info.fWindow) 68 , fViewController(info.fViewController) 69 , fGLContext(nil) { 70 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, fHeight, fDisplayParams.fColorType, 144 kPremul_SkAlphaType, fDisplayParams.fColorSpace); 145 fBackbufferSurface = SkSurface::MakeRaster(info); 146 return GrGLMakeNativeInterface(); 147} 148 149void RasterWindowContext_ios::onDestroyContext() { 150 glDeleteFramebuffers(1, &fFramebuffer); 151 glDeleteRenderbuffers(1, &fRenderbuffer); 152 [EAGLContext setCurrentContext:nil]; 153 [fGLContext release]; 154 fGLContext = nil; 155} 156 157sk_sp<SkSurface> RasterWindowContext_ios::getBackbufferSurface() { 158 return fBackbufferSurface; 159} 160 161void RasterWindowContext_ios::onSwapBuffers() { 162 if (fBackbufferSurface) { 163 // We made/have an off-screen surface. Get the contents as an SkImage: 164 sk_sp<SkImage> snapshot = fBackbufferSurface->makeImageSnapshot(); 165 166 sk_sp<SkSurface> gpuSurface = INHERITED::getBackbufferSurface(); 167 SkCanvas* gpuCanvas = gpuSurface->getCanvas(); 168 gpuCanvas->drawImage(snapshot, 0, 0); 169 gpuCanvas->flush(); 170 glBindRenderbuffer(GL_RENDERBUFFER, fRenderbuffer); 171 [fGLContext presentRenderbuffer:GL_RENDERBUFFER]; 172 } 173} 174 175void RasterWindowContext_ios::resize(int w, int h) { 176 // TODO: handle rotation 177 // [fGLContext update]; 178 INHERITED::resize(w, h); 179} 180 181} // anonymous namespace 182 183namespace sk_app { 184namespace window_context_factory { 185 186std::unique_ptr<WindowContext> MakeRasterForIOS(const IOSWindowInfo& info, 187 const DisplayParams& params) { 188 std::unique_ptr<WindowContext> ctx(new RasterWindowContext_ios(info, params)); 189 if (!ctx->isValid()) { 190 return nullptr; 191 } 192 return ctx; 193} 194 195} // namespace window_context_factory 196} // namespace sk_app 197