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