blob: b71640201d8b5bafc2a7ed186935989478555afe [file] [log] [blame]
yangsu@google.com688823f2011-08-30 19:14:13 +00001#import "SkSampleUIView.h"
2
3//#define SKWIND_CONFIG SkBitmap::kRGB_565_Config
4#define SKWIND_CONFIG SkBitmap::kARGB_8888_Config
5#define SKGL_CONFIG kEAGLColorFormatRGB565
6//#define SKGL_CONFIG kEAGLColorFormatRGBA8
7
8#define FORCE_REDRAW
9
10//#define USE_GL_1
11#define USE_GL_2
12
13#include "SkCanvas.h"
14#include "GrContext.h"
tomhudson@google.com02f90e82012-02-14 15:43:01 +000015#include "gl/GrGLInterface.h"
yangsu@google.com688823f2011-08-30 19:14:13 +000016#include "SkGpuDevice.h"
17#include "SkCGUtils.h"
bsalomon@google.com230504d2012-09-27 16:04:54 +000018#include "SampleApp.h"
19
yangsu@google.com688823f2011-08-30 19:14:13 +000020class SkiOSDeviceManager : public SampleWindow::DeviceManager {
21public:
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +000022 SkiOSDeviceManager(GLint layerFBO) {
bsalomon@google.com230504d2012-09-27 16:04:54 +000023#if SK_SUPPORT_GPU
24 fCurContext = NULL;
25 fCurIntf = NULL;
26 fCurRenderTarget = NULL;
27 fMSAASampleCount = 0;
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +000028 fLayerFBO = layerFBO;
bsalomon@google.com230504d2012-09-27 16:04:54 +000029#endif
30 fBackend = SkOSWindow::kNone_BackEndType;
yangsu@google.com688823f2011-08-30 19:14:13 +000031 }
32
bsalomon@google.com230504d2012-09-27 16:04:54 +000033 virtual ~SkiOSDeviceManager() {
34#if SK_SUPPORT_GPU
35 SkSafeUnref(fCurContext);
36 SkSafeUnref(fCurIntf);
37 SkSafeUnref(fCurRenderTarget);
yangsu@google.com688823f2011-08-30 19:14:13 +000038#endif
bsalomon@google.com230504d2012-09-27 16:04:54 +000039 }
40
41 virtual void setUpBackend(SampleWindow* win, int msaaSampleCount) SK_OVERRIDE {
42 SkASSERT(SkOSWindow::kNone_BackEndType == fBackend);
43
44 fBackend = SkOSWindow::kNone_BackEndType;
45
46#if SK_SUPPORT_GPU
47 switch (win->getDeviceType()) {
48 // these two don't use GL
49 case SampleWindow::kRaster_DeviceType:
50 case SampleWindow::kPicture_DeviceType:
51 break;
52 // these guys use the native backend
53 case SampleWindow::kGPU_DeviceType:
54 case SampleWindow::kNullGPU_DeviceType:
55 fBackend = SkOSWindow::kNativeGL_BackEndType;
56 break;
57 default:
58 SkASSERT(false);
59 break;
yangsu@google.com688823f2011-08-30 19:14:13 +000060 }
61
bsalomon@google.com230504d2012-09-27 16:04:54 +000062 bool result = win->attach(fBackend, msaaSampleCount);
63 if (!result) {
64 SkDebugf("Failed to initialize GL");
65 return;
yangsu@google.com688823f2011-08-30 19:14:13 +000066 }
bsalomon@google.com230504d2012-09-27 16:04:54 +000067 fMSAASampleCount = msaaSampleCount;
68
69 SkASSERT(NULL == fCurIntf);
70 switch (win->getDeviceType()) {
71 // these two don't use GL
yangsu@google.com688823f2011-08-30 19:14:13 +000072 case SampleWindow::kRaster_DeviceType:
bsalomon@google.com230504d2012-09-27 16:04:54 +000073 case SampleWindow::kPicture_DeviceType:
74 fCurIntf = NULL;
75 break;
yangsu@google.com688823f2011-08-30 19:14:13 +000076 case SampleWindow::kGPU_DeviceType:
bsalomon@google.com230504d2012-09-27 16:04:54 +000077 fCurIntf = GrGLCreateNativeInterface();
78 break;
79 case SampleWindow::kNullGPU_DeviceType:
80 fCurIntf = GrGLCreateNullInterface();
81 break;
yangsu@google.com688823f2011-08-30 19:14:13 +000082 default:
bsalomon@google.com230504d2012-09-27 16:04:54 +000083 SkASSERT(false);
84 break;
yangsu@google.com688823f2011-08-30 19:14:13 +000085 }
bsalomon@google.com230504d2012-09-27 16:04:54 +000086
87 SkASSERT(NULL == fCurContext);
88 if (SkOSWindow::kNone_BackEndType != fBackend) {
89 fCurContext = GrContext::Create(kOpenGL_Shaders_GrEngine,
90 (GrPlatform3DContext) fCurIntf);
91 }
92
93 if ((NULL == fCurContext || NULL == fCurIntf) &&
94 SkOSWindow::kNone_BackEndType != fBackend) {
95 // We need some context and interface to see results if we're using a GL backend
96 SkSafeUnref(fCurContext);
97 SkSafeUnref(fCurIntf);
98 SkDebugf("Failed to setup 3D");
99 win->detach();
100 }
101#endif // SK_SUPPORT_GPU
102 // call windowSizeChanged to create the render target
103 this->windowSizeChanged(win);
yangsu@google.com688823f2011-08-30 19:14:13 +0000104 }
bsalomon@google.com230504d2012-09-27 16:04:54 +0000105
106 virtual void tearDownBackend(SampleWindow *win) SK_OVERRIDE {
107#if SK_SUPPORT_GPU
108 SkSafeUnref(fCurContext);
109 fCurContext = NULL;
110
111 SkSafeUnref(fCurIntf);
112 fCurIntf = NULL;
113
114 SkSafeUnref(fCurRenderTarget);
115 fCurRenderTarget = NULL;
116#endif
117 win->detach();
118 fBackend = SampleWindow::kNone_BackEndType;
119 }
reed@google.com5957f472012-10-01 20:31:56 +0000120
121 virtual SkCanvas* createCanvas(SampleWindow::DeviceType dType,
122 SampleWindow* win) {
bsalomon@google.com230504d2012-09-27 16:04:54 +0000123 switch (dType) {
bsalomon@google.com230504d2012-09-27 16:04:54 +0000124 case SampleWindow::kRaster_DeviceType:
reed@google.com5957f472012-10-01 20:31:56 +0000125 // fallthrough
bsalomon@google.com230504d2012-09-27 16:04:54 +0000126 case SampleWindow::kPicture_DeviceType:
reed@google.com5957f472012-10-01 20:31:56 +0000127 // fallthrough
128#if SK_ANGLE
129 case SampleWindow::kANGLE_DeviceType:
130#endif
bsalomon@google.com230504d2012-09-27 16:04:54 +0000131 break;
132#if SK_SUPPORT_GPU
bsalomon@google.com230504d2012-09-27 16:04:54 +0000133 case SampleWindow::kGPU_DeviceType:
134 case SampleWindow::kNullGPU_DeviceType:
reed@google.com5957f472012-10-01 20:31:56 +0000135 if (fCurContext) {
136 SkAutoTUnref<SkDevice> device(new SkGpuDevice(fCurContext,
137 fCurRenderTarget));
138 return new SkCanvas(device);
bsalomon@google.com230504d2012-09-27 16:04:54 +0000139 } else {
reed@google.com5957f472012-10-01 20:31:56 +0000140 return NULL;
bsalomon@google.com230504d2012-09-27 16:04:54 +0000141 }
142 break;
143#endif
144 default:
145 SkASSERT(false);
reed@google.com5957f472012-10-01 20:31:56 +0000146 return NULL;
yangsu@google.com688823f2011-08-30 19:14:13 +0000147 }
reed@google.com5957f472012-10-01 20:31:56 +0000148 return NULL;
yangsu@google.com688823f2011-08-30 19:14:13 +0000149 }
bsalomon@google.com230504d2012-09-27 16:04:54 +0000150
yangsu@google.com688823f2011-08-30 19:14:13 +0000151 virtual void publishCanvas(SampleWindow::DeviceType dType,
152 SkCanvas* canvas,
bsalomon@google.com230504d2012-09-27 16:04:54 +0000153 SampleWindow* win) SK_OVERRIDE {
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +0000154 if (NULL != fCurContext) {
155 fCurContext->flush();
156 }
bsalomon@google.com230504d2012-09-27 16:04:54 +0000157 win->present();
yangsu@google.com688823f2011-08-30 19:14:13 +0000158 }
159
bsalomon@google.com230504d2012-09-27 16:04:54 +0000160 virtual void windowSizeChanged(SampleWindow* win) SK_OVERRIDE {
161#if SK_SUPPORT_GPU
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +0000162 if (NULL != fCurContext) {
bsalomon@google.com230504d2012-09-27 16:04:54 +0000163 win->attach(fBackend, fMSAASampleCount);
yangsu@google.com688823f2011-08-30 19:14:13 +0000164
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +0000165 glBindFramebuffer(GL_FRAMEBUFFER, fLayerFBO);
bsalomon@google.com230504d2012-09-27 16:04:54 +0000166 GrPlatformRenderTargetDesc desc;
yangsu@google.com688823f2011-08-30 19:14:13 +0000167 desc.fWidth = SkScalarRound(win->width());
168 desc.fHeight = SkScalarRound(win->height());
bsalomon@google.comc4364992011-11-07 15:54:49 +0000169 desc.fConfig = kSkia8888_PM_GrPixelConfig;
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +0000170 desc.fRenderTargetHandle = fLayerFBO;
bsalomon@google.com230504d2012-09-27 16:04:54 +0000171 glGetIntegerv(GL_SAMPLES, &desc.fSampleCnt);
172 glGetIntegerv(GL_STENCIL_BITS, &desc.fStencilBits);
yangsu@google.com688823f2011-08-30 19:14:13 +0000173
bsalomon@google.com230504d2012-09-27 16:04:54 +0000174 SkSafeUnref(fCurRenderTarget);
175 fCurRenderTarget = fCurContext->createPlatformRenderTarget(desc);
yangsu@google.com688823f2011-08-30 19:14:13 +0000176 }
bsalomon@google.com230504d2012-09-27 16:04:54 +0000177#endif
yangsu@google.com688823f2011-08-30 19:14:13 +0000178 }
179
bsalomon@google.com230504d2012-09-27 16:04:54 +0000180 virtual GrContext* getGrContext() SK_OVERRIDE {
181#if SK_SUPPORT_GPU
182 return fCurContext;
183#else
184 return NULL;
185#endif
186 }
yangsu@google.com688823f2011-08-30 19:14:13 +0000187
bsalomon@google.com11959252012-04-06 20:13:38 +0000188 virtual GrRenderTarget* getGrRenderTarget() SK_OVERRIDE {
bsalomon@google.com230504d2012-09-27 16:04:54 +0000189#if SK_SUPPORT_GPU
190 return fCurRenderTarget;
191#else
192 return NULL;
193#endif
bsalomon@google.com11959252012-04-06 20:13:38 +0000194 }
bsalomon@google.com230504d2012-09-27 16:04:54 +0000195
196 bool isUsingGL() const { return SkOSWindow::kNone_BackEndType != fBackend; }
197
yangsu@google.com688823f2011-08-30 19:14:13 +0000198private:
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +0000199
bsalomon@google.com230504d2012-09-27 16:04:54 +0000200#if SK_SUPPORT_GPU
201 GrContext* fCurContext;
202 const GrGLInterface* fCurIntf;
203 GrRenderTarget* fCurRenderTarget;
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +0000204 int fMSAASampleCount;
205 GLint fLayerFBO;
bsalomon@google.com230504d2012-09-27 16:04:54 +0000206#endif
207
208 SkOSWindow::SkBackEndTypes fBackend;
209
210 typedef SampleWindow::DeviceManager INHERITED;
yangsu@google.com688823f2011-08-30 19:14:13 +0000211};
212
213////////////////////////////////////////////////////////////////////////////////
214@implementation SkSampleUIView
215
216@synthesize fTitle, fRasterLayer, fGLLayer;
217
218#include "SkApplication.h"
219#include "SkEvent.h"
220#include "SkWindow.h"
221
222#define kREDRAW_UIVIEW_GL "sk_redraw_uiview_gl_iOS"
223
224extern bool gDoTraceDraw;
225#define DO_TRACE_DRAW_MAX 100
226
227struct FPSState {
228 static const int FRAME_COUNT = 60;
229
230 CFTimeInterval fNow0, fNow1;
231 CFTimeInterval fTime0, fTime1, fTotalTime;
232 int fFrameCounter;
233 int fDrawCounter;
234 SkString str;
235 FPSState() {
236 fTime0 = fTime1 = fTotalTime = 0;
237 fFrameCounter = 0;
238 }
239
240 void startDraw() {
241 fNow0 = CACurrentMediaTime();
242
243 if (0 == fDrawCounter && false) {
244 gDoTraceDraw = true;
245 SkDebugf("\n");
246 }
247 }
248
249 void endDraw() {
250 fNow1 = CACurrentMediaTime();
251
252 if (0 == fDrawCounter) {
253 gDoTraceDraw = true;
254 }
255 if (DO_TRACE_DRAW_MAX == ++fDrawCounter) {
256 fDrawCounter = 0;
257 }
258 }
259
260 void flush(SkOSWindow* hwnd) {
261 CFTimeInterval now2 = CACurrentMediaTime();
262
263 fTime0 += fNow1 - fNow0;
264 fTime1 += now2 - fNow1;
265
266 if (++fFrameCounter == FRAME_COUNT) {
267 CFTimeInterval totalNow = CACurrentMediaTime();
268 fTotalTime = totalNow - fTotalTime;
269
270 //SkMSec ms0 = (int)(1000 * fTime0 / FRAME_COUNT);
271 //SkMSec msTotal = (int)(1000 * fTotalTime / FRAME_COUNT);
272 //str.printf(" ms: %d [%d], fps: %3.1f", msTotal, ms0,
273 // FRAME_COUNT / fTotalTime);
274 str.printf(" fps:%3.1f", FRAME_COUNT / fTotalTime);
275 hwnd->setTitle(NULL);
276 fTotalTime = totalNow;
277 fTime0 = fTime1 = 0;
278 fFrameCounter = 0;
279 }
280 }
281};
282
283static FPSState gFPS;
284
285#define FPS_StartDraw() gFPS.startDraw()
286#define FPS_EndDraw() gFPS.endDraw()
287#define FPS_Flush(wind) gFPS.flush(wind)
288
289///////////////////////////////////////////////////////////////////////////////
290
291- (id)initWithDefaults {
292 if (self = [super initWithDefaults]) {
293 fRedrawRequestPending = false;
294 fFPSState = new FPSState;
295
296#ifdef USE_GL_1
297 fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
298#else
299 fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
300#endif
301
302 if (!fGL.fContext || ![EAGLContext setCurrentContext:fGL.fContext])
303 {
304 [self release];
305 return nil;
306 }
307
308 // Create default framebuffer object. The backing will be allocated for the current layer in -resizeFromLayer
309 glGenFramebuffers(1, &fGL.fFramebuffer);
310 glBindFramebuffer(GL_FRAMEBUFFER, fGL.fFramebuffer);
311
312 glGenRenderbuffers(1, &fGL.fRenderbuffer);
313 glGenRenderbuffers(1, &fGL.fStencilbuffer);
314
315 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
316 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fGL.fRenderbuffer);
317
318 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fStencilbuffer);
319 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fGL.fStencilbuffer);
320
321 self.fGLLayer = [CAEAGLLayer layer];
322 fGLLayer.bounds = self.bounds;
323 fGLLayer.anchorPoint = CGPointMake(0, 0);
324 fGLLayer.opaque = TRUE;
325 [self.layer addSublayer:fGLLayer];
326 fGLLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
327 [NSNumber numberWithBool:NO],
328 kEAGLDrawablePropertyRetainedBacking,
329 SKGL_CONFIG,
330 kEAGLDrawablePropertyColorFormat,
331 nil];
332
333 self.fRasterLayer = [CALayer layer];
334 fRasterLayer.anchorPoint = CGPointMake(0, 0);
335 fRasterLayer.opaque = TRUE;
336 [self.layer addSublayer:fRasterLayer];
337
338 NSMutableDictionary *newActions = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNull null], @"onOrderIn",
339 [NSNull null], @"onOrderOut",
340 [NSNull null], @"sublayers",
341 [NSNull null], @"contents",
342 [NSNull null], @"bounds",
343 nil];
344 fGLLayer.actions = newActions;
345 fRasterLayer.actions = newActions;
346 [newActions release];
347
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +0000348 fDevManager = new SkiOSDeviceManager(fGL.fFramebuffer);
bsalomon@google.com230504d2012-09-27 16:04:54 +0000349 static char* kDummyArgv = "dummyExecutableName";
350 fWind = new SampleWindow(self, 1, &kDummyArgv, fDevManager);
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +0000351
yangsu@google.com688823f2011-08-30 19:14:13 +0000352 fWind->resize(self.frame.size.width, self.frame.size.height, SKWIND_CONFIG);
353 }
354 return self;
355}
356
357- (void)dealloc {
358 delete fDevManager;
359 delete fFPSState;
360 self.fRasterLayer = nil;
361 self.fGLLayer = nil;
362 [fGL.fContext release];
363 [super dealloc];
364}
365
366- (void)layoutSubviews {
367 int W, H;
368
369 // Allocate color buffer backing based on the current layer size
370 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
371 [fGL.fContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:fGLLayer];
372
373 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &fGL.fWidth);
374 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &fGL.fHeight);
375
376 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fStencilbuffer);
377 glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, fGL.fWidth, fGL.fHeight);
378
379 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
380 NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
381 }
382
383 if (fDevManager->isUsingGL()) {
384 W = fGL.fWidth;
385 H = fGL.fHeight;
386 CGRect rect = CGRectMake(0, 0, W, H);
387 fGLLayer.bounds = rect;
388 }
389 else {
390 CGRect rect = self.bounds;
391 W = (int)CGRectGetWidth(rect);
392 H = (int)CGRectGetHeight(rect);
393 fRasterLayer.bounds = rect;
394 }
395
396 printf("---- layoutSubviews %d %d\n", W, H);
397 fWind->resize(W, H);
398 fWind->inval(NULL);
399}
400
401///////////////////////////////////////////////////////////////////////////////
402
403- (void)drawWithCanvas:(SkCanvas*)canvas {
404 fRedrawRequestPending = false;
405 fFPSState->startDraw();
406 fWind->draw(canvas);
407 fFPSState->endDraw();
408#ifdef FORCE_REDRAW
409 fWind->inval(NULL);
410#endif
411 fFPSState->flush(fWind);
412}
413
414- (void)drawInGL {
415 // This application only creates a single context which is already set current at this point.
416 // This call is redundant, but needed if dealing with multiple contexts.
417 [EAGLContext setCurrentContext:fGL.fContext];
418
419 // This application only creates a single default framebuffer which is already bound at this point.
420 // This call is redundant, but needed if dealing with multiple framebuffers.
421 glBindFramebuffer(GL_FRAMEBUFFER, fGL.fFramebuffer);
422
423 GLint scissorEnable;
424 glGetIntegerv(GL_SCISSOR_TEST, &scissorEnable);
425 glDisable(GL_SCISSOR_TEST);
426 glClearColor(0,0,0,0);
427 glClear(GL_COLOR_BUFFER_BIT);
428 if (scissorEnable) {
429 glEnable(GL_SCISSOR_TEST);
430 }
431 glViewport(0, 0, fGL.fWidth, fGL.fHeight);
432
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +0000433
reed@google.com5957f472012-10-01 20:31:56 +0000434 SkAutoTUnref<SkCanvas> canvas(fWind->createCanvas());
yangsu@google.com688823f2011-08-30 19:14:13 +0000435 // if we're not "retained", then we have to always redraw everything.
436 // This call forces us to ignore the fDirtyRgn, and draw everywhere.
437 // If we are "retained", we can skip this call (as the raster case does)
438 fWind->forceInvalAll();
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +0000439
reed@google.com5957f472012-10-01 20:31:56 +0000440 [self drawWithCanvas:canvas];
yangsu@google.com688823f2011-08-30 19:14:13 +0000441
442 // This application only creates a single color renderbuffer which is already bound at this point.
443 // This call is redundant, but needed if dealing with multiple renderbuffers.
444 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
445 [fGL.fContext presentRenderbuffer:GL_RENDERBUFFER];
446
yangsu@google.com688823f2011-08-30 19:14:13 +0000447}
448
449- (void)drawInRaster {
reed@google.com5957f472012-10-01 20:31:56 +0000450 SkAutoTUnref<SkCanvas> canvas(fWind->createCanvas());
451 [self drawWithCanvas:canvas];
yangsu@google.com688823f2011-08-30 19:14:13 +0000452 CGImageRef cgimage = SkCreateCGImageRef(fWind->getBitmap());
453 fRasterLayer.contents = (id)cgimage;
454 CGImageRelease(cgimage);
455}
456
457- (void)forceRedraw {
458 if (fDevManager->isUsingGL())
459 [self drawInGL];
460 else
461 [self drawInRaster];
462}
463
464///////////////////////////////////////////////////////////////////////////////
465
466- (void)setSkTitle:(const char *)title {
467 NSString* text = [NSString stringWithUTF8String:title];
468 if ([text length] > 0)
469 self.fTitle = text;
470
471 if (fTitleItem && fTitle) {
472 fTitleItem.title = [NSString stringWithFormat:@"%@%@", fTitle,
473 [NSString stringWithUTF8String:fFPSState->str.c_str()]];
474 }
475}
476
477- (void)postInvalWithRect:(const SkIRect*)r {
478 if (!fRedrawRequestPending) {
479 fRedrawRequestPending = true;
480 bool gl = fDevManager->isUsingGL();
481 [CATransaction begin];
482 [CATransaction setAnimationDuration:0];
483 fRasterLayer.hidden = gl;
484 fGLLayer.hidden = !gl;
485 [CATransaction commit];
486 if (gl) {
487 [self performSelector:@selector(drawInGL) withObject:nil afterDelay:0];
488 }
489 else {
490 [self performSelector:@selector(drawInRaster) withObject:nil afterDelay:0];
491 [self setNeedsDisplay];
492 }
493 }
494}
495
496@end