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