Home | History | Annotate | Download | only in iOSSampleApp
      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 
     29 class SkiOSDeviceManager : public SampleWindow::DeviceManager {
     30 public:
     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 
    183 private:
    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 
    207 struct 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 
    250 static 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