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