blob: 9a9b07f6ae212926a9d6295f1a9e1dd49c5e477b [file] [log] [blame]
yangsu@google.comc5aeccd2011-07-17 14:42:08 +00001#import "SkUIView.h"
yangsu@google.comc5aeccd2011-07-17 14:42:08 +00002
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
yangsu@google.comef7bdfa2011-08-12 14:27:47 +00008#define FORCE_REDRAW
yangsu@google.comc5aeccd2011-07-17 14:42:08 +00009
10//#define USE_GL_1
yangsu@google.com74d25b12011-07-17 14:51:52 +000011#define USE_GL_2
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000012
13#include "SkCanvas.h"
14#include "GrContext.h"
15#include "GrGLInterface.h"
16#include "SkGpuDevice.h"
17#include "SkCGUtils.h"
yangsu@google.comf3493f02011-08-08 15:12:05 +000018class SkiOSDeviceManager : public SampleWindow::DeviceManager {
19public:
20 SkiOSDeviceManager() {
21 fGrContext = NULL;
22 fGrRenderTarget = NULL;
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000023 usingGL = false;
24 }
yangsu@google.comf3493f02011-08-08 15:12:05 +000025 virtual ~SkiOSDeviceManager() {
26 SkSafeUnref(fGrContext);
27 SkSafeUnref(fGrRenderTarget);
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000028 }
yangsu@google.comf3493f02011-08-08 15:12:05 +000029
30 virtual void init(SampleWindow* win) {
31 win->attachGL();
32 if (NULL == fGrContext) {
33#ifdef USE_GL_1
34 fGrContext = GrContext::Create(kOpenGL_Fixed_GrEngine, NULL);
35#else
36 fGrContext = GrContext::Create(kOpenGL_Shaders_GrEngine, NULL);
37#endif
38 }
yangsu@google.com69f2e052011-08-30 17:08:08 +000039
yangsu@google.comf3493f02011-08-08 15:12:05 +000040 if (NULL == fGrContext) {
41 SkDebugf("Failed to setup 3D");
42 win->detachGL();
43 }
44 }
45
46 virtual bool supportsDeviceType(SampleWindow::DeviceType dType) {
47 switch (dType) {
48 case SampleWindow::kRaster_DeviceType:
49 case SampleWindow::kPicture_DeviceType: // fallthru
50 return true;
51 case SampleWindow::kGPU_DeviceType:
52 return NULL != fGrContext;
53 default:
54 return false;
55 }
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000056 }
yangsu@google.comf3493f02011-08-08 15:12:05 +000057 virtual bool prepareCanvas(SampleWindow::DeviceType dType,
58 SkCanvas* canvas,
59 SampleWindow* win) {
60 if (SampleWindow::kGPU_DeviceType == dType) {
61 canvas->setDevice(new SkGpuDevice(fGrContext, fGrRenderTarget))->unref();
62 usingGL = true;
63 }
64 else {
65 //The clip needs to be applied with a device attached to the canvas
66 canvas->setBitmapDevice(win->getBitmap());
67 usingGL = false;
68 }
69 return true;
70 }
71 virtual void publishCanvas(SampleWindow::DeviceType dType,
72 SkCanvas* canvas,
73 SampleWindow* win) {
74 if (SampleWindow::kGPU_DeviceType == dType) {
75 fGrContext->flush();
76 }
77 else {
78 //CGContextRef cg = UIGraphicsGetCurrentContext();
79 //SkCGDrawBitmap(cg, win->getBitmap(), 0, 0);
80 }
81 win->presentGL();
82 }
83
yangsu@google.com69f2e052011-08-30 17:08:08 +000084 virtual void windowSizeChanged(SampleWindow* win) {
85 if (fGrContext) {
86 win->attachGL();
87
88 GrPlatformSurfaceDesc desc;
89 desc.reset();
90 desc.fSurfaceType = kRenderTarget_GrPlatformSurfaceType;
91 desc.fWidth = SkScalarRound(win->width());
92 desc.fHeight = SkScalarRound(win->height());
93 desc.fConfig = kRGBA_8888_GrPixelConfig;
94 const GrGLInterface* gl = GrGLGetDefaultGLInterface();
95 GrAssert(NULL != gl);
96 GR_GL_GetIntegerv(gl, GR_GL_STENCIL_BITS, &desc.fStencilBits);
97 GR_GL_GetIntegerv(gl, GR_GL_SAMPLES, &desc.fSampleCnt);
98 GrGLint buffer;
99 GR_GL_GetIntegerv(gl, GR_GL_FRAMEBUFFER_BINDING, &buffer);
100 desc.fPlatformRenderTarget = buffer;
101
102 SkSafeUnref(fGrRenderTarget);
103 fGrRenderTarget = static_cast<GrRenderTarget*>(
104 fGrContext->createPlatformSurface(desc));
105 }
106 }
107
yangsu@google.comf3493f02011-08-08 15:12:05 +0000108 bool isUsingGL() { return usingGL; }
109
110 virtual GrContext* getGrContext() { return fGrContext; }
111private:
112 bool usingGL;
113 GrContext* fGrContext;
114 GrRenderTarget* fGrRenderTarget;
115};
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000116
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000117////////////////////////////////////////////////////////////////////////////////
118@implementation SkUIView
119
yangsu@google.com59870452011-08-02 13:20:22 +0000120@synthesize fWind, fTitle, fTitleItem, fRasterLayer, fGLLayer, fOptionsDelegate;
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000121
122#include "SkApplication.h"
123#include "SkEvent.h"
124#include "SkWindow.h"
125
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000126#define kREDRAW_UIVIEW_GL "sk_redraw_uiview_gl_iOS"
127
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000128extern bool gDoTraceDraw;
129#define DO_TRACE_DRAW_MAX 100
130
131struct FPSState {
132 static const int FRAME_COUNT = 60;
133
134 CFTimeInterval fNow0, fNow1;
135 CFTimeInterval fTime0, fTime1, fTotalTime;
136 int fFrameCounter;
137 int fDrawCounter;
138 SkString str;
139 FPSState() {
140 fTime0 = fTime1 = fTotalTime = 0;
141 fFrameCounter = 0;
142 }
143
144 void startDraw() {
145 fNow0 = CACurrentMediaTime();
146
147 if (0 == fDrawCounter && false) {
148 gDoTraceDraw = true;
149 SkDebugf("\n");
150 }
151 }
152
153 void endDraw() {
154 fNow1 = CACurrentMediaTime();
155
156 if (0 == fDrawCounter) {
157 gDoTraceDraw = true;
158 }
159 if (DO_TRACE_DRAW_MAX == ++fDrawCounter) {
160 fDrawCounter = 0;
161 }
162 }
163
164 void flush(SkOSWindow* hwnd) {
165 CFTimeInterval now2 = CACurrentMediaTime();
166
167 fTime0 += fNow1 - fNow0;
168 fTime1 += now2 - fNow1;
169
170 if (++fFrameCounter == FRAME_COUNT) {
171 CFTimeInterval totalNow = CACurrentMediaTime();
172 fTotalTime = totalNow - fTotalTime;
173
174 //SkMSec ms0 = (int)(1000 * fTime0 / FRAME_COUNT);
175 //SkMSec msTotal = (int)(1000 * fTotalTime / FRAME_COUNT);
176 //str.printf(" ms: %d [%d], fps: %3.1f", msTotal, ms0,
177 // FRAME_COUNT / fTotalTime);
178 str.printf(" fps:%3.1f", FRAME_COUNT / fTotalTime);
179 hwnd->setTitle(NULL);
180 fTotalTime = totalNow;
181 fTime0 = fTime1 = 0;
182 fFrameCounter = 0;
183 }
184 }
185};
186
187static FPSState gFPS;
188
189#define FPS_StartDraw() gFPS.startDraw()
190#define FPS_EndDraw() gFPS.endDraw()
191#define FPS_Flush(wind) gFPS.flush(wind)
192
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000193///////////////////////////////////////////////////////////////////////////////
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000194
195- (id)initWithMyDefaults {
196 fRedrawRequestPending = false;
197 fFPSState = new FPSState;
yangsu@google.comf3493f02011-08-08 15:12:05 +0000198
199 //Add gesture recognizer for single taps. Taps on the right half of the view
200 //will cause SampleApp to go to the next sample, taps on the left will go to
201 //the previous sample
202 UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc]
203 initWithTarget:self
204 action:@selector(handleTap:)];
205 [self addGestureRecognizer:tap];
206 [tap release];
207
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000208#ifdef USE_GL_1
209 fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
210#else
211 fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
212#endif
213
214 if (!fGL.fContext || ![EAGLContext setCurrentContext:fGL.fContext])
215 {
216 [self release];
217 return nil;
218 }
219
220 // Create default framebuffer object. The backing will be allocated for the current layer in -resizeFromLayer
221 glGenFramebuffers(1, &fGL.fFramebuffer);
222 glBindFramebuffer(GL_FRAMEBUFFER, fGL.fFramebuffer);
223
224 glGenRenderbuffers(1, &fGL.fRenderbuffer);
225 glGenRenderbuffers(1, &fGL.fStencilbuffer);
226
227 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
228 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fGL.fRenderbuffer);
229
230 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fStencilbuffer);
231 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fGL.fStencilbuffer);
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000232
yangsu@google.com59870452011-08-02 13:20:22 +0000233 self.fGLLayer = [CAEAGLLayer layer];
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000234 fGLLayer.bounds = self.bounds;
235 fGLLayer.anchorPoint = CGPointMake(0, 0);
236 fGLLayer.opaque = TRUE;
237 [self.layer addSublayer:fGLLayer];
238 fGLLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
239 [NSNumber numberWithBool:NO],
240 kEAGLDrawablePropertyRetainedBacking,
241 SKGL_CONFIG,
242 kEAGLDrawablePropertyColorFormat,
243 nil];
244
yangsu@google.com59870452011-08-02 13:20:22 +0000245 self.fRasterLayer = [CALayer layer];
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000246 fRasterLayer.anchorPoint = CGPointMake(0, 0);
247 fRasterLayer.opaque = TRUE;
248 [self.layer addSublayer:fRasterLayer];
249
250 NSMutableDictionary *newActions = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNull null], @"onOrderIn",
251 [NSNull null], @"onOrderOut",
252 [NSNull null], @"sublayers",
253 [NSNull null], @"contents",
254 [NSNull null], @"bounds",
255 nil];
256 fGLLayer.actions = newActions;
257 fRasterLayer.actions = newActions;
258 [newActions release];
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000259
260 fDevManager = new SkiOSDeviceManager;
261 fWind = new SampleWindow(self, NULL, NULL, fDevManager);
262 application_init();
263 fWind->resize(self.frame.size.width, self.frame.size.height, SKWIND_CONFIG);
yangsu@google.comf3493f02011-08-08 15:12:05 +0000264
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000265 return self;
266}
267
268- (id)initWithCoder:(NSCoder*)coder {
269 if ((self = [super initWithCoder:coder])) {
270 self = [self initWithMyDefaults];
271 }
272 return self;
273}
274
275- (id)initWithFrame:(CGRect)frame {
276 if (self = [super initWithFrame:frame]) {
277 self = [self initWithMyDefaults];
278 }
279 return self;
280}
281
282- (void)dealloc {
283 delete fWind;
284 delete fDevManager;
285 delete fFPSState;
yangsu@google.com59870452011-08-02 13:20:22 +0000286 self.fRasterLayer = nil;
287 self.fGLLayer = nil;
288 [fGL.fContext release];
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000289 application_term();
290 [fTitleItem release];
291 [super dealloc];
292}
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000293
294- (void)layoutSubviews {
295 int W, H;
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000296
297 // Allocate color buffer backing based on the current layer size
298 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
299 [fGL.fContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:fGLLayer];
300
301 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &fGL.fWidth);
302 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &fGL.fHeight);
303
304 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fStencilbuffer);
305 glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, fGL.fWidth, fGL.fHeight);
306
307 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
308 NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
309 }
310
311 if (fDevManager->isUsingGL()) {
312 W = fGL.fWidth;
313 H = fGL.fHeight;
314 CGRect rect = CGRectMake(0, 0, W, H);
315 fGLLayer.bounds = rect;
316 }
317 else {
318 CGRect rect = self.bounds;
319 W = (int)CGRectGetWidth(rect);
320 H = (int)CGRectGetHeight(rect);
321 fRasterLayer.bounds = rect;
322 }
323
324 printf("---- layoutSubviews %d %d\n", W, H);
325 fWind->resize(W, H);
326 fWind->inval(NULL);
327}
328
329///////////////////////////////////////////////////////////////////////////////
330
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000331- (void)drawWithCanvas:(SkCanvas*)canvas {
332 fRedrawRequestPending = false;
333 fFPSState->startDraw();
334 fWind->draw(canvas);
335 fFPSState->endDraw();
336#ifdef FORCE_REDRAW
337 fWind->inval(NULL);
338#endif
339 fFPSState->flush(fWind);
340}
341
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000342- (void)drawInGL {
343 // This application only creates a single context which is already set current at this point.
344 // This call is redundant, but needed if dealing with multiple contexts.
345 [EAGLContext setCurrentContext:fGL.fContext];
346
347 // This application only creates a single default framebuffer which is already bound at this point.
348 // This call is redundant, but needed if dealing with multiple framebuffers.
349 glBindFramebuffer(GL_FRAMEBUFFER, fGL.fFramebuffer);
350
351 GLint scissorEnable;
352 glGetIntegerv(GL_SCISSOR_TEST, &scissorEnable);
353 glDisable(GL_SCISSOR_TEST);
354 glClearColor(0,0,0,0);
355 glClear(GL_COLOR_BUFFER_BIT);
356 if (scissorEnable) {
357 glEnable(GL_SCISSOR_TEST);
358 }
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000359 glViewport(0, 0, fGL.fWidth, fGL.fHeight);
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000360
361
362 GrContext* ctx = fDevManager->getGrContext();
363 SkASSERT(NULL != ctx);
364
365 SkCanvas canvas;
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000366
367 // if we're not "retained", then we have to always redraw everything.
368 // This call forces us to ignore the fDirtyRgn, and draw everywhere.
369 // If we are "retained", we can skip this call (as the raster case does)
370 fWind->forceInvalAll();
371
372 [self drawWithCanvas:&canvas];
373
374 // This application only creates a single color renderbuffer which is already bound at this point.
375 // This call is redundant, but needed if dealing with multiple renderbuffers.
376 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
377 [fGL.fContext presentRenderbuffer:GL_RENDERBUFFER];
378
379#if GR_COLLECT_STATS
380// static int frame = 0;
381// if (!(frame % 100)) {
382// ctx->printStats();
383// }
384// ctx->resetStats();
385// ++frame;
386#endif
387}
388
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000389- (void)drawInRaster {
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000390 SkCanvas canvas;
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000391 [self drawWithCanvas:&canvas];
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000392 CGImageRef cgimage = SkCreateCGImageRef(fWind->getBitmap());
393 fRasterLayer.contents = (id)cgimage;
394 CGImageRelease(cgimage);
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000395}
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000396
397- (void)forceRedraw {
398 if (fDevManager->isUsingGL())
399 [self drawInGL];
400 else
401 [self drawInRaster];
402}
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000403
404//Gesture Handlers
405- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
406 for (UITouch *touch in touches) {
407 CGPoint loc = [touch locationInView:self];
408 fWind->handleClick(loc.x, loc.y, SkView::Click::kDown_State, touch);
409 }
410}
411
412- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
413 for (UITouch *touch in touches) {
414 CGPoint loc = [touch locationInView:self];
415 fWind->handleClick(loc.x, loc.y, SkView::Click::kMoved_State, touch);
416 }
417}
418
419- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
420 for (UITouch *touch in touches) {
421 CGPoint loc = [touch locationInView:self];
422 fWind->handleClick(loc.x, loc.y, SkView::Click::kUp_State, touch);
423 }
424}
425
426- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
427 for (UITouch *touch in touches) {
428 CGPoint loc = [touch locationInView:self];
429 fWind->handleClick(loc.x, loc.y, SkView::Click::kUp_State, touch);
430 }
431}
432
yangsu@google.comf3493f02011-08-08 15:12:05 +0000433- (void)handleTap:(UISwipeGestureRecognizer *)sender {
434// CGPoint loc = [sender locationInView:self];
435// if (loc.x > self.bounds.size.width/2)
436// ((SampleWindow*)fWind)->nextSample();
437// else
438// ((SampleWindow*)fWind)->previousSample();
439}
440
441
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000442///////////////////////////////////////////////////////////////////////////////
443
444- (void)setSkTitle:(const char *)title {
445 NSString* text = [NSString stringWithUTF8String:title];
446 if ([text length] > 0)
447 self.fTitle = text;
448
449 if (fTitleItem && fTitle) {
450 fTitleItem.title = [NSString stringWithFormat:@"%@%@", fTitle,
451 [NSString stringWithUTF8String:fFPSState->str.c_str()]];
452 }
453}
454
455- (BOOL)onHandleEvent:(const SkEvent&)evt {
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000456 return false;
457}
458
yangsu@google.com59870452011-08-02 13:20:22 +0000459#include "SkOSMenu.h"
460- (void)onAddMenu:(const SkOSMenu*)menu {
461 [self.fOptionsDelegate view:self didAddMenu:menu];
462}
463- (void)onUpdateMenu:(const SkOSMenu*)menu {
464 [self.fOptionsDelegate view:self didUpdateMenu:menu];
465}
466
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000467- (void)postInvalWithRect:(const SkIRect*)r {
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000468 if (!fRedrawRequestPending) {
469 fRedrawRequestPending = true;
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000470 bool gl = fDevManager->isUsingGL();
471 [CATransaction begin];
472 [CATransaction setAnimationDuration:0];
473 fRasterLayer.hidden = gl;
474 fGLLayer.hidden = !gl;
475 [CATransaction commit];
476 if (gl) {
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000477 [self performSelector:@selector(drawInGL) withObject:nil afterDelay:0];
478 }
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000479 else {
480 [self performSelector:@selector(drawInRaster) withObject:nil afterDelay:0];
yangsu@google.com59870452011-08-02 13:20:22 +0000481 [self setNeedsDisplay];
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000482 }
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000483 }
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000484}
485
486@end