blob: b1ec537c51921560bea8e4acb2555d3f277a7a36 [file] [log] [blame]
yangsu@google.com688823f2011-08-30 19:14:13 +00001#import "SkSampleUIView.h"
2
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
8#define FORCE_REDRAW
9
10//#define USE_GL_1
11#define USE_GL_2
12
13#include "SkCanvas.h"
14#include "GrContext.h"
tomhudson@google.com02f90e82012-02-14 15:43:01 +000015#include "gl/GrGLInterface.h"
yangsu@google.com688823f2011-08-30 19:14:13 +000016#include "SkGpuDevice.h"
17#include "SkCGUtils.h"
18class SkiOSDeviceManager : public SampleWindow::DeviceManager {
19public:
20 SkiOSDeviceManager() {
21 fGrContext = NULL;
22 fGrRenderTarget = NULL;
23 usingGL = false;
24 }
25 virtual ~SkiOSDeviceManager() {
26 SkSafeUnref(fGrContext);
27 SkSafeUnref(fGrRenderTarget);
28 }
29
30 virtual void init(SampleWindow* win) {
robertphillips@google.comd5b05ef2012-04-02 20:19:28 +000031 win->attach(kNativeGL_BackEndType);
yangsu@google.com688823f2011-08-30 19:14:13 +000032 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
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 }
56 }
57 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 if (fGrContext) {
robertphillips@google.comd5b05ef2012-04-02 20:19:28 +000086 win->attach(kNativeGL_BackEndType);
yangsu@google.com688823f2011-08-30 19:14:13 +000087
88 GrPlatformSurfaceDesc desc;
89 desc.reset();
90 desc.fSurfaceType = kRenderTarget_GrPlatformSurfaceType;
91 desc.fWidth = SkScalarRound(win->width());
92 desc.fHeight = SkScalarRound(win->height());
bsalomon@google.comc4364992011-11-07 15:54:49 +000093 desc.fConfig = kSkia8888_PM_GrPixelConfig;
yangsu@google.com688823f2011-08-30 19:14:13 +000094 const GrGLInterface* gl = GrGLGetDefaultGLInterface();
95 GrAssert(NULL != gl);
96 GR_GL_GetIntegerv(gl, GR_GL_STENCIL_BITS, &desc.fStencilBits);
97 GR_GL_GetIntegerv(gl, GR_GL_SAMPLES, &desc.fSampleCnt);
98 GrGLint buffer;
99 GR_GL_GetIntegerv(gl, GR_GL_FRAMEBUFFER_BINDING, &buffer);
100 desc.fPlatformRenderTarget = buffer;
101
102 SkSafeUnref(fGrRenderTarget);
103 fGrRenderTarget = static_cast<GrRenderTarget*>(
104 fGrContext->createPlatformSurface(desc));
105 }
106 }
107
108 bool isUsingGL() { return usingGL; }
109
110 virtual GrContext* getGrContext() { return fGrContext; }
bsalomon@google.com11959252012-04-06 20:13:38 +0000111
112 virtual GrRenderTarget* getGrRenderTarget() SK_OVERRIDE {
113 return fGrRenderTarget;
114 }
yangsu@google.com688823f2011-08-30 19:14:13 +0000115private:
116 bool usingGL;
117 GrContext* fGrContext;
118 GrRenderTarget* fGrRenderTarget;
119};
120
121////////////////////////////////////////////////////////////////////////////////
122@implementation SkSampleUIView
123
124@synthesize fTitle, fRasterLayer, fGLLayer;
125
126#include "SkApplication.h"
127#include "SkEvent.h"
128#include "SkWindow.h"
129
130#define kREDRAW_UIVIEW_GL "sk_redraw_uiview_gl_iOS"
131
132extern bool gDoTraceDraw;
133#define DO_TRACE_DRAW_MAX 100
134
135struct FPSState {
136 static const int FRAME_COUNT = 60;
137
138 CFTimeInterval fNow0, fNow1;
139 CFTimeInterval fTime0, fTime1, fTotalTime;
140 int fFrameCounter;
141 int fDrawCounter;
142 SkString str;
143 FPSState() {
144 fTime0 = fTime1 = fTotalTime = 0;
145 fFrameCounter = 0;
146 }
147
148 void startDraw() {
149 fNow0 = CACurrentMediaTime();
150
151 if (0 == fDrawCounter && false) {
152 gDoTraceDraw = true;
153 SkDebugf("\n");
154 }
155 }
156
157 void endDraw() {
158 fNow1 = CACurrentMediaTime();
159
160 if (0 == fDrawCounter) {
161 gDoTraceDraw = true;
162 }
163 if (DO_TRACE_DRAW_MAX == ++fDrawCounter) {
164 fDrawCounter = 0;
165 }
166 }
167
168 void flush(SkOSWindow* hwnd) {
169 CFTimeInterval now2 = CACurrentMediaTime();
170
171 fTime0 += fNow1 - fNow0;
172 fTime1 += now2 - fNow1;
173
174 if (++fFrameCounter == FRAME_COUNT) {
175 CFTimeInterval totalNow = CACurrentMediaTime();
176 fTotalTime = totalNow - fTotalTime;
177
178 //SkMSec ms0 = (int)(1000 * fTime0 / FRAME_COUNT);
179 //SkMSec msTotal = (int)(1000 * fTotalTime / FRAME_COUNT);
180 //str.printf(" ms: %d [%d], fps: %3.1f", msTotal, ms0,
181 // FRAME_COUNT / fTotalTime);
182 str.printf(" fps:%3.1f", FRAME_COUNT / fTotalTime);
183 hwnd->setTitle(NULL);
184 fTotalTime = totalNow;
185 fTime0 = fTime1 = 0;
186 fFrameCounter = 0;
187 }
188 }
189};
190
191static FPSState gFPS;
192
193#define FPS_StartDraw() gFPS.startDraw()
194#define FPS_EndDraw() gFPS.endDraw()
195#define FPS_Flush(wind) gFPS.flush(wind)
196
197///////////////////////////////////////////////////////////////////////////////
198
199- (id)initWithDefaults {
200 if (self = [super initWithDefaults]) {
201 fRedrawRequestPending = false;
202 fFPSState = new FPSState;
203
204#ifdef USE_GL_1
205 fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
206#else
207 fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
208#endif
209
210 if (!fGL.fContext || ![EAGLContext setCurrentContext:fGL.fContext])
211 {
212 [self release];
213 return nil;
214 }
215
216 // Create default framebuffer object. The backing will be allocated for the current layer in -resizeFromLayer
217 glGenFramebuffers(1, &fGL.fFramebuffer);
218 glBindFramebuffer(GL_FRAMEBUFFER, fGL.fFramebuffer);
219
220 glGenRenderbuffers(1, &fGL.fRenderbuffer);
221 glGenRenderbuffers(1, &fGL.fStencilbuffer);
222
223 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
224 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fGL.fRenderbuffer);
225
226 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fStencilbuffer);
227 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fGL.fStencilbuffer);
228
229 self.fGLLayer = [CAEAGLLayer layer];
230 fGLLayer.bounds = self.bounds;
231 fGLLayer.anchorPoint = CGPointMake(0, 0);
232 fGLLayer.opaque = TRUE;
233 [self.layer addSublayer:fGLLayer];
234 fGLLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
235 [NSNumber numberWithBool:NO],
236 kEAGLDrawablePropertyRetainedBacking,
237 SKGL_CONFIG,
238 kEAGLDrawablePropertyColorFormat,
239 nil];
240
241 self.fRasterLayer = [CALayer layer];
242 fRasterLayer.anchorPoint = CGPointMake(0, 0);
243 fRasterLayer.opaque = TRUE;
244 [self.layer addSublayer:fRasterLayer];
245
246 NSMutableDictionary *newActions = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNull null], @"onOrderIn",
247 [NSNull null], @"onOrderOut",
248 [NSNull null], @"sublayers",
249 [NSNull null], @"contents",
250 [NSNull null], @"bounds",
251 nil];
252 fGLLayer.actions = newActions;
253 fRasterLayer.actions = newActions;
254 [newActions release];
255
256 fDevManager = new SkiOSDeviceManager;
257 fWind = new SampleWindow(self, NULL, NULL, fDevManager);
258 fWind->resize(self.frame.size.width, self.frame.size.height, SKWIND_CONFIG);
259 }
260 return self;
261}
262
263- (void)dealloc {
264 delete fDevManager;
265 delete fFPSState;
266 self.fRasterLayer = nil;
267 self.fGLLayer = nil;
268 [fGL.fContext release];
269 [super dealloc];
270}
271
272- (void)layoutSubviews {
273 int W, H;
274
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
309- (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
320- (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 }
337 glViewport(0, 0, fGL.fWidth, fGL.fHeight);
338
339
340 GrContext* ctx = fDevManager->getGrContext();
341 SkASSERT(NULL != ctx);
342
343 SkCanvas canvas;
344
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
367- (void)drawInRaster {
368 SkCanvas canvas;
369 [self drawWithCanvas:&canvas];
370 CGImageRef cgimage = SkCreateCGImageRef(fWind->getBitmap());
371 fRasterLayer.contents = (id)cgimage;
372 CGImageRelease(cgimage);
373}
374
375- (void)forceRedraw {
376 if (fDevManager->isUsingGL())
377 [self drawInGL];
378 else
379 [self drawInRaster];
380}
381
382///////////////////////////////////////////////////////////////////////////////
383
384- (void)setSkTitle:(const char *)title {
385 NSString* text = [NSString stringWithUTF8String:title];
386 if ([text length] > 0)
387 self.fTitle = text;
388
389 if (fTitleItem && fTitle) {
390 fTitleItem.title = [NSString stringWithFormat:@"%@%@", fTitle,
391 [NSString stringWithUTF8String:fFPSState->str.c_str()]];
392 }
393}
394
395- (void)postInvalWithRect:(const SkIRect*)r {
396 if (!fRedrawRequestPending) {
397 fRedrawRequestPending = true;
398 bool gl = fDevManager->isUsingGL();
399 [CATransaction begin];
400 [CATransaction setAnimationDuration:0];
401 fRasterLayer.hidden = gl;
402 fGLLayer.hidden = !gl;
403 [CATransaction commit];
404 if (gl) {
405 [self performSelector:@selector(drawInGL) withObject:nil afterDelay:0];
406 }
407 else {
408 [self performSelector:@selector(drawInRaster) withObject:nil afterDelay:0];
409 [self setNeedsDisplay];
410 }
411 }
412}
413
414@end