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