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