blob: e06ccebc2e0004687418acb5441961058b29e4c4 [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"
15#include "GrGLInterface.h"
16#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) {
31 win->attachGL();
32 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) {
86 win->attachGL();
87
88 GrPlatformSurfaceDesc desc;
89 desc.reset();
90 desc.fSurfaceType = kRenderTarget_GrPlatformSurfaceType;
91 desc.fWidth = SkScalarRound(win->width());
92 desc.fHeight = SkScalarRound(win->height());
93 desc.fConfig = kRGBA_8888_GrPixelConfig;
94 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; }
111private:
112 bool usingGL;
113 GrContext* fGrContext;
114 GrRenderTarget* fGrRenderTarget;
115};
116
117////////////////////////////////////////////////////////////////////////////////
118@implementation SkSampleUIView
119
120@synthesize fTitle, fRasterLayer, fGLLayer;
121
122#include "SkApplication.h"
123#include "SkEvent.h"
124#include "SkWindow.h"
125
126#define kREDRAW_UIVIEW_GL "sk_redraw_uiview_gl_iOS"
127
128extern bool gDoTraceDraw;
129#define DO_TRACE_DRAW_MAX 100
130
131struct FPSState {
132 static const int FRAME_COUNT = 60;
133
134 CFTimeInterval fNow0, fNow1;
135 CFTimeInterval fTime0, fTime1, fTotalTime;
136 int fFrameCounter;
137 int fDrawCounter;
138 SkString str;
139 FPSState() {
140 fTime0 = fTime1 = fTotalTime = 0;
141 fFrameCounter = 0;
142 }
143
144 void startDraw() {
145 fNow0 = CACurrentMediaTime();
146
147 if (0 == fDrawCounter && false) {
148 gDoTraceDraw = true;
149 SkDebugf("\n");
150 }
151 }
152
153 void endDraw() {
154 fNow1 = CACurrentMediaTime();
155
156 if (0 == fDrawCounter) {
157 gDoTraceDraw = true;
158 }
159 if (DO_TRACE_DRAW_MAX == ++fDrawCounter) {
160 fDrawCounter = 0;
161 }
162 }
163
164 void flush(SkOSWindow* hwnd) {
165 CFTimeInterval now2 = CACurrentMediaTime();
166
167 fTime0 += fNow1 - fNow0;
168 fTime1 += now2 - fNow1;
169
170 if (++fFrameCounter == FRAME_COUNT) {
171 CFTimeInterval totalNow = CACurrentMediaTime();
172 fTotalTime = totalNow - fTotalTime;
173
174 //SkMSec ms0 = (int)(1000 * fTime0 / FRAME_COUNT);
175 //SkMSec msTotal = (int)(1000 * fTotalTime / FRAME_COUNT);
176 //str.printf(" ms: %d [%d], fps: %3.1f", msTotal, ms0,
177 // FRAME_COUNT / fTotalTime);
178 str.printf(" fps:%3.1f", FRAME_COUNT / fTotalTime);
179 hwnd->setTitle(NULL);
180 fTotalTime = totalNow;
181 fTime0 = fTime1 = 0;
182 fFrameCounter = 0;
183 }
184 }
185};
186
187static FPSState gFPS;
188
189#define FPS_StartDraw() gFPS.startDraw()
190#define FPS_EndDraw() gFPS.endDraw()
191#define FPS_Flush(wind) gFPS.flush(wind)
192
193///////////////////////////////////////////////////////////////////////////////
194
195- (id)initWithDefaults {
196 if (self = [super initWithDefaults]) {
197 fRedrawRequestPending = false;
198 fFPSState = new FPSState;
199
200#ifdef USE_GL_1
201 fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
202#else
203 fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
204#endif
205
206 if (!fGL.fContext || ![EAGLContext setCurrentContext:fGL.fContext])
207 {
208 [self release];
209 return nil;
210 }
211
212 // Create default framebuffer object. The backing will be allocated for the current layer in -resizeFromLayer
213 glGenFramebuffers(1, &fGL.fFramebuffer);
214 glBindFramebuffer(GL_FRAMEBUFFER, fGL.fFramebuffer);
215
216 glGenRenderbuffers(1, &fGL.fRenderbuffer);
217 glGenRenderbuffers(1, &fGL.fStencilbuffer);
218
219 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
220 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fGL.fRenderbuffer);
221
222 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fStencilbuffer);
223 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fGL.fStencilbuffer);
224
225 self.fGLLayer = [CAEAGLLayer layer];
226 fGLLayer.bounds = self.bounds;
227 fGLLayer.anchorPoint = CGPointMake(0, 0);
228 fGLLayer.opaque = TRUE;
229 [self.layer addSublayer:fGLLayer];
230 fGLLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
231 [NSNumber numberWithBool:NO],
232 kEAGLDrawablePropertyRetainedBacking,
233 SKGL_CONFIG,
234 kEAGLDrawablePropertyColorFormat,
235 nil];
236
237 self.fRasterLayer = [CALayer layer];
238 fRasterLayer.anchorPoint = CGPointMake(0, 0);
239 fRasterLayer.opaque = TRUE;
240 [self.layer addSublayer:fRasterLayer];
241
242 NSMutableDictionary *newActions = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNull null], @"onOrderIn",
243 [NSNull null], @"onOrderOut",
244 [NSNull null], @"sublayers",
245 [NSNull null], @"contents",
246 [NSNull null], @"bounds",
247 nil];
248 fGLLayer.actions = newActions;
249 fRasterLayer.actions = newActions;
250 [newActions release];
251
252 fDevManager = new SkiOSDeviceManager;
253 fWind = new SampleWindow(self, NULL, NULL, fDevManager);
254 fWind->resize(self.frame.size.width, self.frame.size.height, SKWIND_CONFIG);
255 }
256 return self;
257}
258
259- (void)dealloc {
260 delete fDevManager;
261 delete fFPSState;
262 self.fRasterLayer = nil;
263 self.fGLLayer = nil;
264 [fGL.fContext release];
265 [super dealloc];
266}
267
268- (void)layoutSubviews {
269 int W, H;
270
271 // Allocate color buffer backing based on the current layer size
272 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
273 [fGL.fContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:fGLLayer];
274
275 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &fGL.fWidth);
276 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &fGL.fHeight);
277
278 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fStencilbuffer);
279 glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, fGL.fWidth, fGL.fHeight);
280
281 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
282 NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
283 }
284
285 if (fDevManager->isUsingGL()) {
286 W = fGL.fWidth;
287 H = fGL.fHeight;
288 CGRect rect = CGRectMake(0, 0, W, H);
289 fGLLayer.bounds = rect;
290 }
291 else {
292 CGRect rect = self.bounds;
293 W = (int)CGRectGetWidth(rect);
294 H = (int)CGRectGetHeight(rect);
295 fRasterLayer.bounds = rect;
296 }
297
298 printf("---- layoutSubviews %d %d\n", W, H);
299 fWind->resize(W, H);
300 fWind->inval(NULL);
301}
302
303///////////////////////////////////////////////////////////////////////////////
304
305- (void)drawWithCanvas:(SkCanvas*)canvas {
306 fRedrawRequestPending = false;
307 fFPSState->startDraw();
308 fWind->draw(canvas);
309 fFPSState->endDraw();
310#ifdef FORCE_REDRAW
311 fWind->inval(NULL);
312#endif
313 fFPSState->flush(fWind);
314}
315
316- (void)drawInGL {
317 // This application only creates a single context which is already set current at this point.
318 // This call is redundant, but needed if dealing with multiple contexts.
319 [EAGLContext setCurrentContext:fGL.fContext];
320
321 // This application only creates a single default framebuffer which is already bound at this point.
322 // This call is redundant, but needed if dealing with multiple framebuffers.
323 glBindFramebuffer(GL_FRAMEBUFFER, fGL.fFramebuffer);
324
325 GLint scissorEnable;
326 glGetIntegerv(GL_SCISSOR_TEST, &scissorEnable);
327 glDisable(GL_SCISSOR_TEST);
328 glClearColor(0,0,0,0);
329 glClear(GL_COLOR_BUFFER_BIT);
330 if (scissorEnable) {
331 glEnable(GL_SCISSOR_TEST);
332 }
333 glViewport(0, 0, fGL.fWidth, fGL.fHeight);
334
335
336 GrContext* ctx = fDevManager->getGrContext();
337 SkASSERT(NULL != ctx);
338
339 SkCanvas canvas;
340
341 // if we're not "retained", then we have to always redraw everything.
342 // This call forces us to ignore the fDirtyRgn, and draw everywhere.
343 // If we are "retained", we can skip this call (as the raster case does)
344 fWind->forceInvalAll();
345
346 [self drawWithCanvas:&canvas];
347
348 // This application only creates a single color renderbuffer which is already bound at this point.
349 // This call is redundant, but needed if dealing with multiple renderbuffers.
350 glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
351 [fGL.fContext presentRenderbuffer:GL_RENDERBUFFER];
352
353#if GR_COLLECT_STATS
354 // static int frame = 0;
355 // if (!(frame % 100)) {
356 // ctx->printStats();
357 // }
358 // ctx->resetStats();
359 // ++frame;
360#endif
361}
362
363- (void)drawInRaster {
364 SkCanvas canvas;
365 [self drawWithCanvas:&canvas];
366 CGImageRef cgimage = SkCreateCGImageRef(fWind->getBitmap());
367 fRasterLayer.contents = (id)cgimage;
368 CGImageRelease(cgimage);
369}
370
371- (void)forceRedraw {
372 if (fDevManager->isUsingGL())
373 [self drawInGL];
374 else
375 [self drawInRaster];
376}
377
378///////////////////////////////////////////////////////////////////////////////
379
380- (void)setSkTitle:(const char *)title {
381 NSString* text = [NSString stringWithUTF8String:title];
382 if ([text length] > 0)
383 self.fTitle = text;
384
385 if (fTitleItem && fTitle) {
386 fTitleItem.title = [NSString stringWithFormat:@"%@%@", fTitle,
387 [NSString stringWithUTF8String:fFPSState->str.c_str()]];
388 }
389}
390
391- (void)postInvalWithRect:(const SkIRect*)r {
392 if (!fRedrawRequestPending) {
393 fRedrawRequestPending = true;
394 bool gl = fDevManager->isUsingGL();
395 [CATransaction begin];
396 [CATransaction setAnimationDuration:0];
397 fRasterLayer.hidden = gl;
398 fGLLayer.hidden = !gl;
399 [CATransaction commit];
400 if (gl) {
401 [self performSelector:@selector(drawInGL) withObject:nil afterDelay:0];
402 }
403 else {
404 [self performSelector:@selector(drawInRaster) withObject:nil afterDelay:0];
405 [self setNeedsDisplay];
406 }
407 }
408}
409
410@end