blob: a6ab105005f8c683f79424f49706c5ce9abb2c21 [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 }
120
yangsu@google.com688823f2011-08-30 19:14:13 +0000121 virtual bool prepareCanvas(SampleWindow::DeviceType dType,
122 SkCanvas* canvas,
bsalomon@google.com230504d2012-09-27 16:04:54 +0000123 SampleWindow* win) SK_OVERRIDE {
124 switch (dType) {
125 // use the window's bmp for these two
126 case SampleWindow::kRaster_DeviceType:
127 case SampleWindow::kPicture_DeviceType:
bsalomon@google.com17a595a2012-10-01 19:06:09 +0000128 canvas->setDevice(SkNEW_ARGS(SkDevice, (win->getBitmap())))->unref();
bsalomon@google.com230504d2012-09-27 16:04:54 +0000129 break;
130#if SK_SUPPORT_GPU
131 // create a GPU device for these two
132 case SampleWindow::kGPU_DeviceType:
133 case SampleWindow::kNullGPU_DeviceType:
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +0000134 if (NULL != fCurContext) {
bsalomon@google.com230504d2012-09-27 16:04:54 +0000135 canvas->setDevice(new SkGpuDevice(fCurContext, fCurRenderTarget))->unref();
136 } else {
137 return false;
138 }
139 break;
140#endif
141 default:
142 SkASSERT(false);
143 return false;
yangsu@google.com688823f2011-08-30 19:14:13 +0000144 }
145 return true;
146 }
bsalomon@google.com230504d2012-09-27 16:04:54 +0000147
yangsu@google.com688823f2011-08-30 19:14:13 +0000148 virtual void publishCanvas(SampleWindow::DeviceType dType,
149 SkCanvas* canvas,
bsalomon@google.com230504d2012-09-27 16:04:54 +0000150 SampleWindow* win) SK_OVERRIDE {
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +0000151 if (NULL != fCurContext) {
152 fCurContext->flush();
153 }
bsalomon@google.com230504d2012-09-27 16:04:54 +0000154 win->present();
yangsu@google.com688823f2011-08-30 19:14:13 +0000155 }
156
bsalomon@google.com230504d2012-09-27 16:04:54 +0000157 virtual void windowSizeChanged(SampleWindow* win) SK_OVERRIDE {
158#if SK_SUPPORT_GPU
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +0000159 if (NULL != fCurContext) {
bsalomon@google.com230504d2012-09-27 16:04:54 +0000160 win->attach(fBackend, fMSAASampleCount);
yangsu@google.com688823f2011-08-30 19:14:13 +0000161
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +0000162 glBindFramebuffer(GL_FRAMEBUFFER, fLayerFBO);
bsalomon@google.com230504d2012-09-27 16:04:54 +0000163 GrPlatformRenderTargetDesc desc;
yangsu@google.com688823f2011-08-30 19:14:13 +0000164 desc.fWidth = SkScalarRound(win->width());
165 desc.fHeight = SkScalarRound(win->height());
bsalomon@google.comc4364992011-11-07 15:54:49 +0000166 desc.fConfig = kSkia8888_PM_GrPixelConfig;
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +0000167 desc.fRenderTargetHandle = fLayerFBO;
bsalomon@google.com230504d2012-09-27 16:04:54 +0000168 glGetIntegerv(GL_SAMPLES, &desc.fSampleCnt);
169 glGetIntegerv(GL_STENCIL_BITS, &desc.fStencilBits);
yangsu@google.com688823f2011-08-30 19:14:13 +0000170
bsalomon@google.com230504d2012-09-27 16:04:54 +0000171 SkSafeUnref(fCurRenderTarget);
172 fCurRenderTarget = fCurContext->createPlatformRenderTarget(desc);
yangsu@google.com688823f2011-08-30 19:14:13 +0000173 }
bsalomon@google.com230504d2012-09-27 16:04:54 +0000174#endif
yangsu@google.com688823f2011-08-30 19:14:13 +0000175 }
176
bsalomon@google.com230504d2012-09-27 16:04:54 +0000177 virtual GrContext* getGrContext() SK_OVERRIDE {
178#if SK_SUPPORT_GPU
179 return fCurContext;
180#else
181 return NULL;
182#endif
183 }
yangsu@google.com688823f2011-08-30 19:14:13 +0000184
bsalomon@google.com11959252012-04-06 20:13:38 +0000185 virtual GrRenderTarget* getGrRenderTarget() SK_OVERRIDE {
bsalomon@google.com230504d2012-09-27 16:04:54 +0000186#if SK_SUPPORT_GPU
187 return fCurRenderTarget;
188#else
189 return NULL;
190#endif
bsalomon@google.com11959252012-04-06 20:13:38 +0000191 }
bsalomon@google.com230504d2012-09-27 16:04:54 +0000192
193 bool isUsingGL() const { return SkOSWindow::kNone_BackEndType != fBackend; }
194
yangsu@google.com688823f2011-08-30 19:14:13 +0000195private:
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +0000196
bsalomon@google.com230504d2012-09-27 16:04:54 +0000197#if SK_SUPPORT_GPU
198 GrContext* fCurContext;
199 const GrGLInterface* fCurIntf;
200 GrRenderTarget* fCurRenderTarget;
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +0000201 int fMSAASampleCount;
202 GLint fLayerFBO;
bsalomon@google.com230504d2012-09-27 16:04:54 +0000203#endif
204
205 SkOSWindow::SkBackEndTypes fBackend;
206
207 typedef SampleWindow::DeviceManager INHERITED;
yangsu@google.com688823f2011-08-30 19:14:13 +0000208};
209
210////////////////////////////////////////////////////////////////////////////////
211@implementation SkSampleUIView
212
213@synthesize fTitle, fRasterLayer, fGLLayer;
214
215#include "SkApplication.h"
216#include "SkEvent.h"
217#include "SkWindow.h"
218
219#define kREDRAW_UIVIEW_GL "sk_redraw_uiview_gl_iOS"
220
221extern bool gDoTraceDraw;
222#define DO_TRACE_DRAW_MAX 100
223
224struct FPSState {
225 static const int FRAME_COUNT = 60;
226
227 CFTimeInterval fNow0, fNow1;
228 CFTimeInterval fTime0, fTime1, fTotalTime;
229 int fFrameCounter;
230 int fDrawCounter;
231 SkString str;
232 FPSState() {
233 fTime0 = fTime1 = fTotalTime = 0;
234 fFrameCounter = 0;
235 }
236
237 void startDraw() {
238 fNow0 = CACurrentMediaTime();
239
240 if (0 == fDrawCounter && false) {
241 gDoTraceDraw = true;
242 SkDebugf("\n");
243 }
244 }
245
246 void endDraw() {
247 fNow1 = CACurrentMediaTime();
248
249 if (0 == fDrawCounter) {
250 gDoTraceDraw = true;
251 }
252 if (DO_TRACE_DRAW_MAX == ++fDrawCounter) {
253 fDrawCounter = 0;
254 }
255 }
256
257 void flush(SkOSWindow* hwnd) {
258 CFTimeInterval now2 = CACurrentMediaTime();
259
260 fTime0 += fNow1 - fNow0;
261 fTime1 += now2 - fNow1;
262
263 if (++fFrameCounter == FRAME_COUNT) {
264 CFTimeInterval totalNow = CACurrentMediaTime();
265 fTotalTime = totalNow - fTotalTime;
266
267 //SkMSec ms0 = (int)(1000 * fTime0 / FRAME_COUNT);
268 //SkMSec msTotal = (int)(1000 * fTotalTime / FRAME_COUNT);
269 //str.printf(" ms: %d [%d], fps: %3.1f", msTotal, ms0,
270 // FRAME_COUNT / fTotalTime);
271 str.printf(" fps:%3.1f", FRAME_COUNT / fTotalTime);
272 hwnd->setTitle(NULL);
273 fTotalTime = totalNow;
274 fTime0 = fTime1 = 0;
275 fFrameCounter = 0;
276 }
277 }
278};
279
280static FPSState gFPS;
281
282#define FPS_StartDraw() gFPS.startDraw()
283#define FPS_EndDraw() gFPS.endDraw()
284#define FPS_Flush(wind) gFPS.flush(wind)
285
286///////////////////////////////////////////////////////////////////////////////
287
288- (id)initWithDefaults {
289 if (self = [super initWithDefaults]) {
290 fRedrawRequestPending = false;
291 fFPSState = new FPSState;
292
293#ifdef USE_GL_1
294 fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
295#else
296 fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
297#endif
298
299 if (!fGL.fContext || ![EAGLContext setCurrentContext:fGL.fContext])
300 {
301 [self release];
302 return nil;
303 }
304
305 // Create default framebuffer object. The backing will be allocated for the current layer in -resizeFromLayer
306 glGenFramebuffers(1, &fGL.fFramebuffer);
307 glBindFramebuffer(GL_FRAMEBUFFER, fGL.fFramebuffer);
308
309 glGenRenderbuffers(1, &fGL.fRenderbuffer);
310 glGenRenderbuffers(1, &fGL.fStencilbuffer);
311
312 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
313 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fGL.fRenderbuffer);
314
315 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fStencilbuffer);
316 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fGL.fStencilbuffer);
317
318 self.fGLLayer = [CAEAGLLayer layer];
319 fGLLayer.bounds = self.bounds;
320 fGLLayer.anchorPoint = CGPointMake(0, 0);
321 fGLLayer.opaque = TRUE;
322 [self.layer addSublayer:fGLLayer];
323 fGLLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
324 [NSNumber numberWithBool:NO],
325 kEAGLDrawablePropertyRetainedBacking,
326 SKGL_CONFIG,
327 kEAGLDrawablePropertyColorFormat,
328 nil];
329
330 self.fRasterLayer = [CALayer layer];
331 fRasterLayer.anchorPoint = CGPointMake(0, 0);
332 fRasterLayer.opaque = TRUE;
333 [self.layer addSublayer:fRasterLayer];
334
335 NSMutableDictionary *newActions = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNull null], @"onOrderIn",
336 [NSNull null], @"onOrderOut",
337 [NSNull null], @"sublayers",
338 [NSNull null], @"contents",
339 [NSNull null], @"bounds",
340 nil];
341 fGLLayer.actions = newActions;
342 fRasterLayer.actions = newActions;
343 [newActions release];
344
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +0000345 fDevManager = new SkiOSDeviceManager(fGL.fFramebuffer);
bsalomon@google.com230504d2012-09-27 16:04:54 +0000346 static char* kDummyArgv = "dummyExecutableName";
347 fWind = new SampleWindow(self, 1, &kDummyArgv, fDevManager);
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +0000348
yangsu@google.com688823f2011-08-30 19:14:13 +0000349 fWind->resize(self.frame.size.width, self.frame.size.height, SKWIND_CONFIG);
350 }
351 return self;
352}
353
354- (void)dealloc {
355 delete fDevManager;
356 delete fFPSState;
357 self.fRasterLayer = nil;
358 self.fGLLayer = nil;
359 [fGL.fContext release];
360 [super dealloc];
361}
362
363- (void)layoutSubviews {
364 int W, H;
365
366 // Allocate color buffer backing based on the current layer size
367 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
368 [fGL.fContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:fGLLayer];
369
370 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &fGL.fWidth);
371 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &fGL.fHeight);
372
373 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fStencilbuffer);
374 glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, fGL.fWidth, fGL.fHeight);
375
376 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
377 NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
378 }
379
380 if (fDevManager->isUsingGL()) {
381 W = fGL.fWidth;
382 H = fGL.fHeight;
383 CGRect rect = CGRectMake(0, 0, W, H);
384 fGLLayer.bounds = rect;
385 }
386 else {
387 CGRect rect = self.bounds;
388 W = (int)CGRectGetWidth(rect);
389 H = (int)CGRectGetHeight(rect);
390 fRasterLayer.bounds = rect;
391 }
392
393 printf("---- layoutSubviews %d %d\n", W, H);
394 fWind->resize(W, H);
395 fWind->inval(NULL);
396}
397
398///////////////////////////////////////////////////////////////////////////////
399
400- (void)drawWithCanvas:(SkCanvas*)canvas {
401 fRedrawRequestPending = false;
402 fFPSState->startDraw();
403 fWind->draw(canvas);
404 fFPSState->endDraw();
405#ifdef FORCE_REDRAW
406 fWind->inval(NULL);
407#endif
408 fFPSState->flush(fWind);
409}
410
411- (void)drawInGL {
412 // This application only creates a single context which is already set current at this point.
413 // This call is redundant, but needed if dealing with multiple contexts.
414 [EAGLContext setCurrentContext:fGL.fContext];
415
416 // This application only creates a single default framebuffer which is already bound at this point.
417 // This call is redundant, but needed if dealing with multiple framebuffers.
418 glBindFramebuffer(GL_FRAMEBUFFER, fGL.fFramebuffer);
419
420 GLint scissorEnable;
421 glGetIntegerv(GL_SCISSOR_TEST, &scissorEnable);
422 glDisable(GL_SCISSOR_TEST);
423 glClearColor(0,0,0,0);
424 glClear(GL_COLOR_BUFFER_BIT);
425 if (scissorEnable) {
426 glEnable(GL_SCISSOR_TEST);
427 }
428 glViewport(0, 0, fGL.fWidth, fGL.fHeight);
429
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +0000430
yangsu@google.com688823f2011-08-30 19:14:13 +0000431 SkCanvas canvas;
yangsu@google.com688823f2011-08-30 19:14:13 +0000432 // if we're not "retained", then we have to always redraw everything.
433 // This call forces us to ignore the fDirtyRgn, and draw everywhere.
434 // If we are "retained", we can skip this call (as the raster case does)
435 fWind->forceInvalAll();
bsalomon@google.comcca3c8f2012-09-28 16:56:28 +0000436
yangsu@google.com688823f2011-08-30 19:14:13 +0000437 [self drawWithCanvas:&canvas];
438
439 // This application only creates a single color renderbuffer which is already bound at this point.
440 // This call is redundant, but needed if dealing with multiple renderbuffers.
441 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
442 [fGL.fContext presentRenderbuffer:GL_RENDERBUFFER];
443
yangsu@google.com688823f2011-08-30 19:14:13 +0000444}
445
446- (void)drawInRaster {
447 SkCanvas canvas;
448 [self drawWithCanvas:&canvas];
449 CGImageRef cgimage = SkCreateCGImageRef(fWind->getBitmap());
450 fRasterLayer.contents = (id)cgimage;
451 CGImageRelease(cgimage);
452}
453
454- (void)forceRedraw {
455 if (fDevManager->isUsingGL())
456 [self drawInGL];
457 else
458 [self drawInRaster];
459}
460
461///////////////////////////////////////////////////////////////////////////////
462
463- (void)setSkTitle:(const char *)title {
464 NSString* text = [NSString stringWithUTF8String:title];
465 if ([text length] > 0)
466 self.fTitle = text;
467
468 if (fTitleItem && fTitle) {
469 fTitleItem.title = [NSString stringWithFormat:@"%@%@", fTitle,
470 [NSString stringWithUTF8String:fFPSState->str.c_str()]];
471 }
472}
473
474- (void)postInvalWithRect:(const SkIRect*)r {
475 if (!fRedrawRequestPending) {
476 fRedrawRequestPending = true;
477 bool gl = fDevManager->isUsingGL();
478 [CATransaction begin];
479 [CATransaction setAnimationDuration:0];
480 fRasterLayer.hidden = gl;
481 fGLLayer.hidden = !gl;
482 [CATransaction commit];
483 if (gl) {
484 [self performSelector:@selector(drawInGL) withObject:nil afterDelay:0];
485 }
486 else {
487 [self performSelector:@selector(drawInRaster) withObject:nil afterDelay:0];
488 [self setNeedsDisplay];
489 }
490 }
491}
492
493@end