1/* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#import "SkSampleUIView.h" 9 10//#define SKGL_CONFIG kEAGLColorFormatRGB565 11#define SKGL_CONFIG kEAGLColorFormatRGBA8 12 13#define FORCE_REDRAW 14 15#include "SkCanvas.h" 16#include "SkCGUtils.h" 17#include "SkSurface.h" 18#include "SampleApp.h" 19 20#if SK_SUPPORT_GPU 21//#define USE_GL_1 22#define USE_GL_2 23 24#include "gl/GrGLInterface.h" 25#include "GrContext.h" 26#include "SkGpuDevice.h" 27#endif 28 29class SkiOSDeviceManager : public SampleWindow::DeviceManager { 30public: 31 SkiOSDeviceManager(GLint layerFBO) { 32#if SK_SUPPORT_GPU 33 fCurContext = NULL; 34 fCurIntf = NULL; 35 fCurRenderTarget = NULL; 36 fMSAASampleCount = 0; 37 fLayerFBO = layerFBO; 38#endif 39 fBackend = SkOSWindow::kNone_BackEndType; 40 } 41 42 virtual ~SkiOSDeviceManager() { 43#if SK_SUPPORT_GPU 44 SkSafeUnref(fCurContext); 45 SkSafeUnref(fCurIntf); 46 SkSafeUnref(fCurRenderTarget); 47#endif 48 } 49 50 void setUpBackend(SampleWindow* win, int msaaSampleCount) override { 51 SkASSERT(SkOSWindow::kNone_BackEndType == fBackend); 52 53 fBackend = SkOSWindow::kNone_BackEndType; 54 55#if SK_SUPPORT_GPU 56 switch (win->getDeviceType()) { 57 // these two don't use GL 58 case SampleWindow::kRaster_DeviceType: 59 case SampleWindow::kPicture_DeviceType: 60 break; 61 // these guys use the native backend 62 case SampleWindow::kGPU_DeviceType: 63 fBackend = SkOSWindow::kNativeGL_BackEndType; 64 break; 65 default: 66 SkASSERT(false); 67 break; 68 } 69 SkOSWindow::AttachmentInfo info; 70 bool result = win->attach(fBackend, msaaSampleCount, &info); 71 if (!result) { 72 SkDebugf("Failed to initialize GL"); 73 return; 74 } 75 fMSAASampleCount = msaaSampleCount; 76 77 SkASSERT(NULL == fCurIntf); 78 switch (win->getDeviceType()) { 79 // these two don't use GL 80 case SampleWindow::kRaster_DeviceType: 81 case SampleWindow::kPicture_DeviceType: 82 fCurIntf = NULL; 83 break; 84 case SampleWindow::kGPU_DeviceType: 85 fCurIntf = GrGLCreateNativeInterface(); 86 break; 87 default: 88 SkASSERT(false); 89 break; 90 } 91 92 SkASSERT(NULL == fCurContext); 93 if (SkOSWindow::kNone_BackEndType != fBackend) { 94 fCurContext = GrContext::Create(kOpenGL_GrBackend, 95 (GrBackendContext) fCurIntf); 96 } 97 98 if ((NULL == fCurContext || NULL == fCurIntf) && 99 SkOSWindow::kNone_BackEndType != fBackend) { 100 // We need some context and interface to see results if we're using a GL backend 101 SkSafeUnref(fCurContext); 102 SkSafeUnref(fCurIntf); 103 SkDebugf("Failed to setup 3D"); 104 win->detach(); 105 } 106#endif // SK_SUPPORT_GPU 107 // call windowSizeChanged to create the render target 108 this->windowSizeChanged(win); 109 } 110 111 void tearDownBackend(SampleWindow *win) override { 112#if SK_SUPPORT_GPU 113 SkSafeUnref(fCurContext); 114 fCurContext = NULL; 115 116 SkSafeUnref(fCurIntf); 117 fCurIntf = NULL; 118 119 SkSafeUnref(fCurRenderTarget); 120 fCurRenderTarget = NULL; 121#endif 122 win->detach(); 123 fBackend = SampleWindow::kNone_BackEndType; 124 } 125 126 SkSurface* createSurface(SampleWindow::DeviceType dType, SampleWindow* win) override{ 127#if SK_SUPPORT_GPU 128 if (SampleWindow::IsGpuDeviceType(dType) && fCurContext) { 129 SkSurfaceProps props(win->getSurfaceProps()); 130 return SkSurface::NewRenderTargetDirect(fCurRenderTarget, &props); 131 } 132#endif 133 return NULL; 134 } 135 136 virtual void publishCanvas(SampleWindow::DeviceType dType, 137 SkCanvas* canvas, 138 SampleWindow* win) override { 139#if SK_SUPPORT_GPU 140 if (NULL != fCurContext) { 141 fCurContext->flush(); 142 } 143#endif 144 win->present(); 145 } 146 147 void windowSizeChanged(SampleWindow* win) override { 148#if SK_SUPPORT_GPU 149 if (NULL != fCurContext) { 150 SkOSWindow::AttachmentInfo info; 151 152 win->attach(fBackend, fMSAASampleCount, &info); 153 154 glBindFramebuffer(GL_FRAMEBUFFER, fLayerFBO); 155 GrBackendRenderTargetDesc desc; 156 desc.fWidth = SkScalarRoundToInt(win->width()); 157 desc.fHeight = SkScalarRoundToInt(win->height()); 158 desc.fConfig = kSkia8888_GrPixelConfig; 159 desc.fRenderTargetHandle = fLayerFBO; 160 desc.fSampleCnt = info.fSampleCount; 161 desc.fStencilBits = info.fStencilBits; 162 163 SkSafeUnref(fCurRenderTarget); 164 fCurRenderTarget = fCurContext->wrapBackendRenderTarget(desc); 165 } 166#endif 167 } 168 169 GrContext* getGrContext() override { 170#if SK_SUPPORT_GPU 171 return fCurContext; 172#else 173 return NULL; 174#endif 175 } 176 177 GrRenderTarget* getGrRenderTarget() override { 178#if SK_SUPPORT_GPU 179 return fCurRenderTarget; 180#else 181 return NULL; 182#endif 183 } 184 185 bool isUsingGL() const { return SkOSWindow::kNone_BackEndType != fBackend; } 186 187private: 188 189#if SK_SUPPORT_GPU 190 GrContext* fCurContext; 191 const GrGLInterface* fCurIntf; 192 GrRenderTarget* fCurRenderTarget; 193 int fMSAASampleCount; 194 GLint fLayerFBO; 195#endif 196 197 SkOSWindow::SkBackEndTypes fBackend; 198 199 typedef SampleWindow::DeviceManager INHERITED; 200}; 201 202//////////////////////////////////////////////////////////////////////////////// 203@implementation SkSampleUIView 204 205@synthesize fTitle, fRasterLayer, fGLLayer; 206 207#include "SkApplication.h" 208#include "SkEvent.h" 209#include "SkWindow.h" 210 211struct FPSState { 212 static const int FRAME_COUNT = 60; 213 214 CFTimeInterval fNow0, fNow1; 215 CFTimeInterval fTime0, fTime1, fTotalTime; 216 int fFrameCounter; 217 SkString str; 218 FPSState() { 219 fTime0 = fTime1 = fTotalTime = 0; 220 fFrameCounter = 0; 221 } 222 223 void startDraw() { 224 fNow0 = CACurrentMediaTime(); 225 } 226 227 void endDraw() { 228 fNow1 = CACurrentMediaTime(); 229 } 230 231 void flush(SkOSWindow* hwnd) { 232 CFTimeInterval now2 = CACurrentMediaTime(); 233 234 fTime0 += fNow1 - fNow0; 235 fTime1 += now2 - fNow1; 236 237 if (++fFrameCounter == FRAME_COUNT) { 238 CFTimeInterval totalNow = CACurrentMediaTime(); 239 fTotalTime = totalNow - fTotalTime; 240 241 //SkMSec ms0 = (int)(1000 * fTime0 / FRAME_COUNT); 242 //SkMSec msTotal = (int)(1000 * fTotalTime / FRAME_COUNT); 243 //str.printf(" ms: %d [%d], fps: %3.1f", msTotal, ms0, 244 // FRAME_COUNT / fTotalTime); 245 str.printf(" fps:%3.1f", FRAME_COUNT / fTotalTime); 246 hwnd->setTitle(NULL); 247 fTotalTime = totalNow; 248 fTime0 = fTime1 = 0; 249 fFrameCounter = 0; 250 } 251 } 252}; 253 254static FPSState gFPS; 255 256#define FPS_StartDraw() gFPS.startDraw() 257#define FPS_EndDraw() gFPS.endDraw() 258#define FPS_Flush(wind) gFPS.flush(wind) 259 260/////////////////////////////////////////////////////////////////////////////// 261 262- (id)initWithDefaults { 263 if (self = [super initWithDefaults]) { 264 fRedrawRequestPending = false; 265 fFPSState = new FPSState; 266 267#ifdef USE_GL_1 268 fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; 269#else 270 fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; 271#endif 272 273 if (!fGL.fContext || ![EAGLContext setCurrentContext:fGL.fContext]) 274 { 275 [self release]; 276 return nil; 277 } 278 279 // Create default framebuffer object. The backing will be allocated for the current layer in -resizeFromLayer 280 glGenFramebuffers(1, &fGL.fFramebuffer); 281 glBindFramebuffer(GL_FRAMEBUFFER, fGL.fFramebuffer); 282 283 glGenRenderbuffers(1, &fGL.fRenderbuffer); 284 glGenRenderbuffers(1, &fGL.fStencilbuffer); 285 286 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer); 287 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fGL.fRenderbuffer); 288 289 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fStencilbuffer); 290 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fGL.fStencilbuffer); 291 292 self.fGLLayer = [CAEAGLLayer layer]; 293 fGLLayer.bounds = self.bounds; 294 fGLLayer.anchorPoint = CGPointMake(0, 0); 295 fGLLayer.opaque = TRUE; 296 [self.layer addSublayer:fGLLayer]; 297 fGLLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: 298 [NSNumber numberWithBool:NO], 299 kEAGLDrawablePropertyRetainedBacking, 300 SKGL_CONFIG, 301 kEAGLDrawablePropertyColorFormat, 302 nil]; 303 304 self.fRasterLayer = [CALayer layer]; 305 fRasterLayer.anchorPoint = CGPointMake(0, 0); 306 fRasterLayer.opaque = TRUE; 307 [self.layer addSublayer:fRasterLayer]; 308 309 NSMutableDictionary *newActions = [[NSMutableDictionary alloc] initWithObjectsAndKeys:[NSNull null], @"onOrderIn", 310 [NSNull null], @"onOrderOut", 311 [NSNull null], @"sublayers", 312 [NSNull null], @"contents", 313 [NSNull null], @"bounds", 314 nil]; 315 fGLLayer.actions = newActions; 316 fRasterLayer.actions = newActions; 317 [newActions release]; 318 319 fDevManager = new SkiOSDeviceManager(fGL.fFramebuffer); 320 static char* kDummyArgv = const_cast<char*>("dummyExecutableName"); 321 fWind = new SampleWindow(self, 1, &kDummyArgv, fDevManager); 322 323 fWind->resize(self.frame.size.width, self.frame.size.height, 324 kN32_SkColorType); 325 } 326 return self; 327} 328 329- (void)dealloc { 330 delete fDevManager; 331 delete fFPSState; 332 self.fRasterLayer = nil; 333 self.fGLLayer = nil; 334 [fGL.fContext release]; 335 [super dealloc]; 336} 337 338- (void)layoutSubviews { 339 int W, H; 340 341 // Allocate color buffer backing based on the current layer size 342 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer); 343 [fGL.fContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:fGLLayer]; 344 345 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &fGL.fWidth); 346 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &fGL.fHeight); 347 348 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fStencilbuffer); 349 glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, fGL.fWidth, fGL.fHeight); 350 351 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { 352 NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER)); 353 } 354 355 if (fDevManager->isUsingGL()) { 356 W = fGL.fWidth; 357 H = fGL.fHeight; 358 CGRect rect = CGRectMake(0, 0, W, H); 359 fGLLayer.bounds = rect; 360 } 361 else { 362 CGRect rect = self.bounds; 363 W = (int)CGRectGetWidth(rect); 364 H = (int)CGRectGetHeight(rect); 365 fRasterLayer.bounds = rect; 366 } 367 368 printf("---- layoutSubviews %d %d\n", W, H); 369 fWind->resize(W, H); 370 fWind->inval(NULL); 371} 372 373/////////////////////////////////////////////////////////////////////////////// 374 375- (void)drawWithCanvas:(SkCanvas*)canvas { 376 fRedrawRequestPending = false; 377 fFPSState->startDraw(); 378 fWind->draw(canvas); 379 fFPSState->endDraw(); 380#ifdef FORCE_REDRAW 381 fWind->inval(NULL); 382#endif 383 fFPSState->flush(fWind); 384} 385 386- (void)drawInGL { 387 // This application only creates a single context which is already set current at this point. 388 // This call is redundant, but needed if dealing with multiple contexts. 389 [EAGLContext setCurrentContext:fGL.fContext]; 390 391 // This application only creates a single default framebuffer which is already bound at this point. 392 // This call is redundant, but needed if dealing with multiple framebuffers. 393 glBindFramebuffer(GL_FRAMEBUFFER, fGL.fFramebuffer); 394 395 GLint scissorEnable; 396 glGetIntegerv(GL_SCISSOR_TEST, &scissorEnable); 397 glDisable(GL_SCISSOR_TEST); 398 glClearColor(0,0,0,0); 399 glClear(GL_COLOR_BUFFER_BIT); 400 if (scissorEnable) { 401 glEnable(GL_SCISSOR_TEST); 402 } 403 glViewport(0, 0, fGL.fWidth, fGL.fHeight); 404 405 406 SkAutoTUnref<SkSurface> surface(fWind->createSurface()); 407 SkCanvas* canvas = surface->getCanvas(); 408 409 // if we're not "retained", then we have to always redraw everything. 410 // This call forces us to ignore the fDirtyRgn, and draw everywhere. 411 // If we are "retained", we can skip this call (as the raster case does) 412 fWind->forceInvalAll(); 413 414 [self drawWithCanvas:canvas]; 415 416 // This application only creates a single color renderbuffer which is already bound at this point. 417 // This call is redundant, but needed if dealing with multiple renderbuffers. 418 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer); 419 [fGL.fContext presentRenderbuffer:GL_RENDERBUFFER]; 420} 421 422- (void)drawInRaster { 423 SkAutoTUnref<SkSurface> surface(fWind->createSurface()); 424 SkCanvas* canvas = surface->getCanvas(); 425 [self drawWithCanvas:canvas]; 426 CGImageRef cgimage = SkCreateCGImageRef(fWind->getBitmap()); 427 fRasterLayer.contents = (id)cgimage; 428 CGImageRelease(cgimage); 429} 430 431- (void)forceRedraw { 432 if (fDevManager->isUsingGL()) 433 [self drawInGL]; 434 else 435 [self drawInRaster]; 436} 437 438/////////////////////////////////////////////////////////////////////////////// 439 440- (void)setSkTitle:(const char *)title { 441 NSString* text = [NSString stringWithUTF8String:title]; 442 if ([text length] > 0) 443 self.fTitle = text; 444 445 if (fTitleItem && fTitle) { 446 fTitleItem.title = [NSString stringWithFormat:@"%@%@", fTitle, 447 [NSString stringWithUTF8String:fFPSState->str.c_str()]]; 448 } 449} 450 451- (void)postInvalWithRect:(const SkIRect*)r { 452 if (!fRedrawRequestPending) { 453 fRedrawRequestPending = true; 454 bool gl = fDevManager->isUsingGL(); 455 [CATransaction begin]; 456 [CATransaction setAnimationDuration:0]; 457 fRasterLayer.hidden = gl; 458 fGLLayer.hidden = !gl; 459 [CATransaction commit]; 460 if (gl) { 461 [self performSelector:@selector(drawInGL) withObject:nil afterDelay:0]; 462 } 463 else { 464 [self performSelector:@selector(drawInRaster) withObject:nil afterDelay:0]; 465 [self setNeedsDisplay]; 466 } 467 } 468} 469 470- (void)getAttachmentInfo:(SkOSWindow::AttachmentInfo*)info { 471 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer); 472 glGetRenderbufferParameteriv(GL_RENDERBUFFER, 473 GL_RENDERBUFFER_STENCIL_SIZE, 474 &info->fStencilBits); 475 glGetRenderbufferParameteriv(GL_RENDERBUFFER, 476 GL_RENDERBUFFER_SAMPLES_APPLE, 477 &info->fSampleCount); 478} 479 480@end 481