blob: 05b6edd60f97f91498227089e52340f08caab6a4 [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 }
39 fGrRenderTarget = SkGpuDevice::Current3DApiRenderTarget();
40 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
84 virtual void windowSizeChanged(SampleWindow* win) {}
85
86 bool isUsingGL() { return usingGL; }
87
88 virtual GrContext* getGrContext() { return fGrContext; }
89private:
90 bool usingGL;
91 GrContext* fGrContext;
92 GrRenderTarget* fGrRenderTarget;
93};
yangsu@google.com2ba30c02011-07-19 15:17:44 +000094
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000095////////////////////////////////////////////////////////////////////////////////
96@implementation SkUIView
97
yangsu@google.com59870452011-08-02 13:20:22 +000098@synthesize fWind, fTitle, fTitleItem, fRasterLayer, fGLLayer, fOptionsDelegate;
yangsu@google.comc5aeccd2011-07-17 14:42:08 +000099
100#include "SkApplication.h"
101#include "SkEvent.h"
102#include "SkWindow.h"
103
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000104#define kREDRAW_UIVIEW_GL "sk_redraw_uiview_gl_iOS"
105
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000106extern bool gDoTraceDraw;
107#define DO_TRACE_DRAW_MAX 100
108
109struct FPSState {
110 static const int FRAME_COUNT = 60;
111
112 CFTimeInterval fNow0, fNow1;
113 CFTimeInterval fTime0, fTime1, fTotalTime;
114 int fFrameCounter;
115 int fDrawCounter;
116 SkString str;
117 FPSState() {
118 fTime0 = fTime1 = fTotalTime = 0;
119 fFrameCounter = 0;
120 }
121
122 void startDraw() {
123 fNow0 = CACurrentMediaTime();
124
125 if (0 == fDrawCounter && false) {
126 gDoTraceDraw = true;
127 SkDebugf("\n");
128 }
129 }
130
131 void endDraw() {
132 fNow1 = CACurrentMediaTime();
133
134 if (0 == fDrawCounter) {
135 gDoTraceDraw = true;
136 }
137 if (DO_TRACE_DRAW_MAX == ++fDrawCounter) {
138 fDrawCounter = 0;
139 }
140 }
141
142 void flush(SkOSWindow* hwnd) {
143 CFTimeInterval now2 = CACurrentMediaTime();
144
145 fTime0 += fNow1 - fNow0;
146 fTime1 += now2 - fNow1;
147
148 if (++fFrameCounter == FRAME_COUNT) {
149 CFTimeInterval totalNow = CACurrentMediaTime();
150 fTotalTime = totalNow - fTotalTime;
151
152 //SkMSec ms0 = (int)(1000 * fTime0 / FRAME_COUNT);
153 //SkMSec msTotal = (int)(1000 * fTotalTime / FRAME_COUNT);
154 //str.printf(" ms: %d [%d], fps: %3.1f", msTotal, ms0,
155 // FRAME_COUNT / fTotalTime);
156 str.printf(" fps:%3.1f", FRAME_COUNT / fTotalTime);
157 hwnd->setTitle(NULL);
158 fTotalTime = totalNow;
159 fTime0 = fTime1 = 0;
160 fFrameCounter = 0;
161 }
162 }
163};
164
165static FPSState gFPS;
166
167#define FPS_StartDraw() gFPS.startDraw()
168#define FPS_EndDraw() gFPS.endDraw()
169#define FPS_Flush(wind) gFPS.flush(wind)
170
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000171///////////////////////////////////////////////////////////////////////////////
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000172
173- (id)initWithMyDefaults {
174 fRedrawRequestPending = false;
175 fFPSState = new FPSState;
yangsu@google.comf3493f02011-08-08 15:12:05 +0000176
177 //Add gesture recognizer for single taps. Taps on the right half of the view
178 //will cause SampleApp to go to the next sample, taps on the left will go to
179 //the previous sample
180 UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc]
181 initWithTarget:self
182 action:@selector(handleTap:)];
183 [self addGestureRecognizer:tap];
184 [tap release];
185
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000186#ifdef USE_GL_1
187 fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
188#else
189 fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
190#endif
191
192 if (!fGL.fContext || ![EAGLContext setCurrentContext:fGL.fContext])
193 {
194 [self release];
195 return nil;
196 }
197
198 // Create default framebuffer object. The backing will be allocated for the current layer in -resizeFromLayer
199 glGenFramebuffers(1, &fGL.fFramebuffer);
200 glBindFramebuffer(GL_FRAMEBUFFER, fGL.fFramebuffer);
201
202 glGenRenderbuffers(1, &fGL.fRenderbuffer);
203 glGenRenderbuffers(1, &fGL.fStencilbuffer);
204
205 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
206 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fGL.fRenderbuffer);
207
208 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fStencilbuffer);
209 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fGL.fStencilbuffer);
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000210
yangsu@google.com59870452011-08-02 13:20:22 +0000211 self.fGLLayer = [CAEAGLLayer layer];
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000212 fGLLayer.bounds = self.bounds;
213 fGLLayer.anchorPoint = CGPointMake(0, 0);
214 fGLLayer.opaque = TRUE;
215 [self.layer addSublayer:fGLLayer];
216 fGLLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
217 [NSNumber numberWithBool:NO],
218 kEAGLDrawablePropertyRetainedBacking,
219 SKGL_CONFIG,
220 kEAGLDrawablePropertyColorFormat,
221 nil];
222
yangsu@google.com59870452011-08-02 13:20:22 +0000223 self.fRasterLayer = [CALayer layer];
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000224 fRasterLayer.anchorPoint = CGPointMake(0, 0);
225 fRasterLayer.opaque = TRUE;
226 [self.layer addSublayer:fRasterLayer];
227
228 NSMutableDictionary *newActions = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNull null], @"onOrderIn",
229 [NSNull null], @"onOrderOut",
230 [NSNull null], @"sublayers",
231 [NSNull null], @"contents",
232 [NSNull null], @"bounds",
233 nil];
234 fGLLayer.actions = newActions;
235 fRasterLayer.actions = newActions;
236 [newActions release];
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000237
238 fDevManager = new SkiOSDeviceManager;
239 fWind = new SampleWindow(self, NULL, NULL, fDevManager);
240 application_init();
241 fWind->resize(self.frame.size.width, self.frame.size.height, SKWIND_CONFIG);
yangsu@google.comf3493f02011-08-08 15:12:05 +0000242
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000243 return self;
244}
245
246- (id)initWithCoder:(NSCoder*)coder {
247 if ((self = [super initWithCoder:coder])) {
248 self = [self initWithMyDefaults];
249 }
250 return self;
251}
252
253- (id)initWithFrame:(CGRect)frame {
254 if (self = [super initWithFrame:frame]) {
255 self = [self initWithMyDefaults];
256 }
257 return self;
258}
259
260- (void)dealloc {
261 delete fWind;
262 delete fDevManager;
263 delete fFPSState;
yangsu@google.com59870452011-08-02 13:20:22 +0000264 self.fRasterLayer = nil;
265 self.fGLLayer = nil;
266 [fGL.fContext release];
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000267 application_term();
268 [fTitleItem release];
269 [super dealloc];
270}
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000271
272- (void)layoutSubviews {
273 int W, H;
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000274
275 // Allocate color buffer backing based on the current layer size
276 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
277 [fGL.fContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:fGLLayer];
278
279 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &fGL.fWidth);
280 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &fGL.fHeight);
281
282 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fStencilbuffer);
283 glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, fGL.fWidth, fGL.fHeight);
284
285 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
286 NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
287 }
288
289 if (fDevManager->isUsingGL()) {
290 W = fGL.fWidth;
291 H = fGL.fHeight;
292 CGRect rect = CGRectMake(0, 0, W, H);
293 fGLLayer.bounds = rect;
294 }
295 else {
296 CGRect rect = self.bounds;
297 W = (int)CGRectGetWidth(rect);
298 H = (int)CGRectGetHeight(rect);
299 fRasterLayer.bounds = rect;
300 }
301
302 printf("---- layoutSubviews %d %d\n", W, H);
303 fWind->resize(W, H);
304 fWind->inval(NULL);
305}
306
307///////////////////////////////////////////////////////////////////////////////
308
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000309- (void)drawWithCanvas:(SkCanvas*)canvas {
310 fRedrawRequestPending = false;
311 fFPSState->startDraw();
312 fWind->draw(canvas);
313 fFPSState->endDraw();
314#ifdef FORCE_REDRAW
315 fWind->inval(NULL);
316#endif
317 fFPSState->flush(fWind);
318}
319
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000320- (void)drawInGL {
321 // This application only creates a single context which is already set current at this point.
322 // This call is redundant, but needed if dealing with multiple contexts.
323 [EAGLContext setCurrentContext:fGL.fContext];
324
325 // This application only creates a single default framebuffer which is already bound at this point.
326 // This call is redundant, but needed if dealing with multiple framebuffers.
327 glBindFramebuffer(GL_FRAMEBUFFER, fGL.fFramebuffer);
328
329 GLint scissorEnable;
330 glGetIntegerv(GL_SCISSOR_TEST, &scissorEnable);
331 glDisable(GL_SCISSOR_TEST);
332 glClearColor(0,0,0,0);
333 glClear(GL_COLOR_BUFFER_BIT);
334 if (scissorEnable) {
335 glEnable(GL_SCISSOR_TEST);
336 }
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000337 glViewport(0, 0, fGL.fWidth, fGL.fHeight);
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000338
339
340 GrContext* ctx = fDevManager->getGrContext();
341 SkASSERT(NULL != ctx);
342
343 SkCanvas canvas;
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000344
345 // if we're not "retained", then we have to always redraw everything.
346 // This call forces us to ignore the fDirtyRgn, and draw everywhere.
347 // If we are "retained", we can skip this call (as the raster case does)
348 fWind->forceInvalAll();
349
350 [self drawWithCanvas:&canvas];
351
352 // This application only creates a single color renderbuffer which is already bound at this point.
353 // This call is redundant, but needed if dealing with multiple renderbuffers.
354 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
355 [fGL.fContext presentRenderbuffer:GL_RENDERBUFFER];
356
357#if GR_COLLECT_STATS
358// static int frame = 0;
359// if (!(frame % 100)) {
360// ctx->printStats();
361// }
362// ctx->resetStats();
363// ++frame;
364#endif
365}
366
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000367- (void)drawInRaster {
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000368 SkCanvas canvas;
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000369 [self drawWithCanvas:&canvas];
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000370 CGImageRef cgimage = SkCreateCGImageRef(fWind->getBitmap());
371 fRasterLayer.contents = (id)cgimage;
372 CGImageRelease(cgimage);
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000373}
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000374
375- (void)forceRedraw {
376 if (fDevManager->isUsingGL())
377 [self drawInGL];
378 else
379 [self drawInRaster];
380}
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000381
382//Gesture Handlers
383- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
384 for (UITouch *touch in touches) {
385 CGPoint loc = [touch locationInView:self];
386 fWind->handleClick(loc.x, loc.y, SkView::Click::kDown_State, touch);
387 }
388}
389
390- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
391 for (UITouch *touch in touches) {
392 CGPoint loc = [touch locationInView:self];
393 fWind->handleClick(loc.x, loc.y, SkView::Click::kMoved_State, touch);
394 }
395}
396
397- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
398 for (UITouch *touch in touches) {
399 CGPoint loc = [touch locationInView:self];
400 fWind->handleClick(loc.x, loc.y, SkView::Click::kUp_State, touch);
401 }
402}
403
404- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
405 for (UITouch *touch in touches) {
406 CGPoint loc = [touch locationInView:self];
407 fWind->handleClick(loc.x, loc.y, SkView::Click::kUp_State, touch);
408 }
409}
410
yangsu@google.comf3493f02011-08-08 15:12:05 +0000411- (void)handleTap:(UISwipeGestureRecognizer *)sender {
412// CGPoint loc = [sender locationInView:self];
413// if (loc.x > self.bounds.size.width/2)
414// ((SampleWindow*)fWind)->nextSample();
415// else
416// ((SampleWindow*)fWind)->previousSample();
417}
418
419
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000420///////////////////////////////////////////////////////////////////////////////
421
422- (void)setSkTitle:(const char *)title {
423 NSString* text = [NSString stringWithUTF8String:title];
424 if ([text length] > 0)
425 self.fTitle = text;
426
427 if (fTitleItem && fTitle) {
428 fTitleItem.title = [NSString stringWithFormat:@"%@%@", fTitle,
429 [NSString stringWithUTF8String:fFPSState->str.c_str()]];
430 }
431}
432
433- (BOOL)onHandleEvent:(const SkEvent&)evt {
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000434 return false;
435}
436
yangsu@google.com59870452011-08-02 13:20:22 +0000437#include "SkOSMenu.h"
438- (void)onAddMenu:(const SkOSMenu*)menu {
439 [self.fOptionsDelegate view:self didAddMenu:menu];
440}
441- (void)onUpdateMenu:(const SkOSMenu*)menu {
442 [self.fOptionsDelegate view:self didUpdateMenu:menu];
443}
444
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000445- (void)postInvalWithRect:(const SkIRect*)r {
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000446 if (!fRedrawRequestPending) {
447 fRedrawRequestPending = true;
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000448 bool gl = fDevManager->isUsingGL();
449 [CATransaction begin];
450 [CATransaction setAnimationDuration:0];
451 fRasterLayer.hidden = gl;
452 fGLLayer.hidden = !gl;
453 [CATransaction commit];
454 if (gl) {
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000455 [self performSelector:@selector(drawInGL) withObject:nil afterDelay:0];
456 }
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000457 else {
458 [self performSelector:@selector(drawInRaster) withObject:nil afterDelay:0];
yangsu@google.com59870452011-08-02 13:20:22 +0000459 [self setNeedsDisplay];
yangsu@google.com2ba30c02011-07-19 15:17:44 +0000460 }
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000461 }
yangsu@google.comc5aeccd2011-07-17 14:42:08 +0000462}
463
464@end