skia2/experimental/iOSSampleApp/SkSampleUIView.mm
kkinnunen 8686a5eeef SampleApp: remove Picture_DeviceType
Remove Picture_DeviceType from SampleApp SampleWindow DeviceType
enumeration.

Use a bool variable to control whether the drawing happens via
MultiPictureDraw.

The MultiPictureDraw mode can be activated by 'M', and title
is updated to contain "<MPD>". Previously the MPD mode was
inaccessible.

This works towards removing backend specific code from
SampleApp and VisualBench with the aim to move the code
to the common SkView framework (SkWindow in particular).
The grand goal is to be able to use command buffer GPU
API and NVPR in these apps.

BUG=skia:4733
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1538343002

Review URL: https://codereview.chromium.org/1538343002
2016-01-05 00:04:33 -08:00

492 lines
16 KiB
Plaintext

/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#import "SkSampleUIView.h"
//#define SKGL_CONFIG kEAGLColorFormatRGB565
#define SKGL_CONFIG kEAGLColorFormatRGBA8
#define FORCE_REDRAW
#include "SkCanvas.h"
#include "SkCGUtils.h"
#include "SkSurface.h"
#include "SampleApp.h"
#if SK_SUPPORT_GPU
//#define USE_GL_1
#define USE_GL_2
#include "gl/GrGLInterface.h"
#include "GrContext.h"
#include "SkGpuDevice.h"
#endif
class SkiOSDeviceManager : public SampleWindow::DeviceManager {
public:
SkiOSDeviceManager(GLint layerFBO) {
#if SK_SUPPORT_GPU
fCurContext = NULL;
fCurIntf = NULL;
fCurRenderTarget = NULL;
fMSAASampleCount = 0;
fLayerFBO = layerFBO;
#endif
fBackend = SkOSWindow::kNone_BackEndType;
}
virtual ~SkiOSDeviceManager() {
#if SK_SUPPORT_GPU
SkSafeUnref(fCurContext);
SkSafeUnref(fCurIntf);
SkSafeUnref(fCurRenderTarget);
#endif
}
void setUpBackend(SampleWindow* win, int msaaSampleCount) override {
SkASSERT(SkOSWindow::kNone_BackEndType == fBackend);
fBackend = SkOSWindow::kNone_BackEndType;
#if SK_SUPPORT_GPU
switch (win->getDeviceType()) {
case SampleWindow::kRaster_DeviceType:
break;
// these guys use the native backend
case SampleWindow::kGPU_DeviceType:
fBackend = SkOSWindow::kNativeGL_BackEndType;
break;
default:
SkASSERT(false);
break;
}
SkOSWindow::AttachmentInfo info;
bool result = win->attach(fBackend, msaaSampleCount, &info);
if (!result) {
SkDebugf("Failed to initialize GL");
return;
}
fMSAASampleCount = msaaSampleCount;
SkASSERT(NULL == fCurIntf);
switch (win->getDeviceType()) {
case SampleWindow::kRaster_DeviceType:
fCurIntf = NULL;
break;
case SampleWindow::kGPU_DeviceType:
fCurIntf = GrGLCreateNativeInterface();
break;
default:
SkASSERT(false);
break;
}
SkASSERT(NULL == fCurContext);
if (SkOSWindow::kNone_BackEndType != fBackend) {
fCurContext = GrContext::Create(kOpenGL_GrBackend,
(GrBackendContext) fCurIntf);
}
if ((NULL == fCurContext || NULL == fCurIntf) &&
SkOSWindow::kNone_BackEndType != fBackend) {
// We need some context and interface to see results if we're using a GL backend
SkSafeUnref(fCurContext);
SkSafeUnref(fCurIntf);
SkDebugf("Failed to setup 3D");
win->detach();
}
#endif // SK_SUPPORT_GPU
// call windowSizeChanged to create the render target
this->windowSizeChanged(win);
}
void tearDownBackend(SampleWindow *win) override {
#if SK_SUPPORT_GPU
SkSafeUnref(fCurContext);
fCurContext = NULL;
SkSafeUnref(fCurIntf);
fCurIntf = NULL;
SkSafeUnref(fCurRenderTarget);
fCurRenderTarget = NULL;
#endif
win->detach();
fBackend = SampleWindow::kNone_BackEndType;
}
SkSurface* createSurface(SampleWindow::DeviceType dType, SampleWindow* win) override{
#if SK_SUPPORT_GPU
if (SampleWindow::IsGpuDeviceType(dType) && fCurContext) {
SkSurfaceProps props(win->getSurfaceProps());
return SkSurface::NewRenderTargetDirect(fCurRenderTarget, &props);
}
#endif
return NULL;
}
virtual void publishCanvas(SampleWindow::DeviceType dType,
SkCanvas* canvas,
SampleWindow* win) override {
#if SK_SUPPORT_GPU
if (NULL != fCurContext) {
fCurContext->flush();
}
#endif
win->present();
}
void windowSizeChanged(SampleWindow* win) override {
#if SK_SUPPORT_GPU
if (NULL != fCurContext) {
SkOSWindow::AttachmentInfo info;
win->attach(fBackend, fMSAASampleCount, &info);
glBindFramebuffer(GL_FRAMEBUFFER, fLayerFBO);
GrBackendRenderTargetDesc desc;
desc.fWidth = SkScalarRoundToInt(win->width());
desc.fHeight = SkScalarRoundToInt(win->height());
desc.fConfig = kSkia8888_GrPixelConfig;
desc.fRenderTargetHandle = fLayerFBO;
desc.fSampleCnt = info.fSampleCount;
desc.fStencilBits = info.fStencilBits;
SkSafeUnref(fCurRenderTarget);
fCurRenderTarget = fCurContext->textureProvider()->wrapBackendRenderTarget(desc);
}
#endif
}
GrContext* getGrContext() override {
#if SK_SUPPORT_GPU
return fCurContext;
#else
return NULL;
#endif
}
GrRenderTarget* getGrRenderTarget() override {
#if SK_SUPPORT_GPU
return fCurRenderTarget;
#else
return NULL;
#endif
}
bool isUsingGL() const { return SkOSWindow::kNone_BackEndType != fBackend; }
private:
#if SK_SUPPORT_GPU
GrContext* fCurContext;
const GrGLInterface* fCurIntf;
GrRenderTarget* fCurRenderTarget;
int fMSAASampleCount;
GLint fLayerFBO;
#endif
SkOSWindow::SkBackEndTypes fBackend;
typedef SampleWindow::DeviceManager INHERITED;
};
////////////////////////////////////////////////////////////////////////////////
@implementation SkSampleUIView
@synthesize fTitle, fRasterLayer, fGLLayer;
#include "SkApplication.h"
#include "SkEvent.h"
#include "SkWindow.h"
struct FPSState {
static const int FRAME_COUNT = 60;
CFTimeInterval fNow0, fNow1;
CFTimeInterval fTime0, fTime1, fTotalTime;
int fFrameCounter;
SkString str;
FPSState() {
fTime0 = fTime1 = fTotalTime = 0;
fFrameCounter = 0;
}
void startDraw() {
fNow0 = CACurrentMediaTime();
}
void endDraw() {
fNow1 = CACurrentMediaTime();
}
void flush(SkOSWindow* hwnd) {
CFTimeInterval now2 = CACurrentMediaTime();
fTime0 += fNow1 - fNow0;
fTime1 += now2 - fNow1;
if (++fFrameCounter == FRAME_COUNT) {
CFTimeInterval totalNow = CACurrentMediaTime();
fTotalTime = totalNow - fTotalTime;
//SkMSec ms0 = (int)(1000 * fTime0 / FRAME_COUNT);
//SkMSec msTotal = (int)(1000 * fTotalTime / FRAME_COUNT);
//str.printf(" ms: %d [%d], fps: %3.1f", msTotal, ms0,
// FRAME_COUNT / fTotalTime);
str.printf(" fps:%3.1f", FRAME_COUNT / fTotalTime);
hwnd->setTitle(NULL);
fTotalTime = totalNow;
fTime0 = fTime1 = 0;
fFrameCounter = 0;
}
}
};
static FPSState gFPS;
#define FPS_StartDraw() gFPS.startDraw()
#define FPS_EndDraw() gFPS.endDraw()
#define FPS_Flush(wind) gFPS.flush(wind)
///////////////////////////////////////////////////////////////////////////////
- (id)initWithDefaults {
if (self = [super initWithDefaults]) {
fRedrawRequestPending = false;
fFPSState = new FPSState;
#ifdef USE_GL_1
fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
#else
fGL.fContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
#endif
if (!fGL.fContext || ![EAGLContext setCurrentContext:fGL.fContext])
{
[self release];
return nil;
}
// Create default framebuffer object. The backing will be allocated for the current layer in -resizeFromLayer
glGenFramebuffers(1, &fGL.fFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, fGL.fFramebuffer);
glGenRenderbuffers(1, &fGL.fRenderbuffer);
glGenRenderbuffers(1, &fGL.fStencilbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fGL.fRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, fGL.fStencilbuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fGL.fStencilbuffer);
self.fGLLayer = [CAEAGLLayer layer];
fGLLayer.bounds = self.bounds;
fGLLayer.anchorPoint = CGPointMake(0, 0);
fGLLayer.opaque = TRUE;
[self.layer addSublayer:fGLLayer];
fGLLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO],
kEAGLDrawablePropertyRetainedBacking,
SKGL_CONFIG,
kEAGLDrawablePropertyColorFormat,
nil];
self.fRasterLayer = [CALayer layer];
fRasterLayer.anchorPoint = CGPointMake(0, 0);
fRasterLayer.opaque = TRUE;
[self.layer addSublayer:fRasterLayer];
NSMutableDictionary *newActions = [[NSMutableDictionary alloc] initWithObjectsAndKeys:[NSNull null], @"onOrderIn",
[NSNull null], @"onOrderOut",
[NSNull null], @"sublayers",
[NSNull null], @"contents",
[NSNull null], @"bounds",
nil];
fGLLayer.actions = newActions;
fRasterLayer.actions = newActions;
[newActions release];
// rebuild argc and argv from process info
NSArray* arguments = [[NSProcessInfo processInfo] arguments];
int argc = [arguments count];
char** argv = new char*[argc];
for (int i = 0; i < argc; ++i) {
NSString* arg = [arguments objectAtIndex:i];
int strlen = [arg lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
argv[i] = new char[strlen+1];
[arg getCString:argv[i] maxLength:strlen+1 encoding:NSUTF8StringEncoding];
}
fDevManager = new SkiOSDeviceManager(fGL.fFramebuffer);
fWind = new SampleWindow(self, argc, argv, fDevManager);
fWind->resize(self.frame.size.width, self.frame.size.height,
kN32_SkColorType);
for (int i = 0; i < argc; ++i) {
delete [] argv[i];
}
delete [] argv;
}
return self;
}
- (void)dealloc {
delete fDevManager;
delete fFPSState;
self.fRasterLayer = nil;
self.fGLLayer = nil;
[fGL.fContext release];
[super dealloc];
}
- (void)layoutSubviews {
int W, H;
// Allocate color buffer backing based on the current layer size
glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
[fGL.fContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:fGLLayer];
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &fGL.fWidth);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &fGL.fHeight);
glBindRenderbuffer(GL_RENDERBUFFER, fGL.fStencilbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, fGL.fWidth, fGL.fHeight);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
}
if (fDevManager->isUsingGL()) {
W = fGL.fWidth;
H = fGL.fHeight;
CGRect rect = CGRectMake(0, 0, W, H);
fGLLayer.bounds = rect;
}
else {
CGRect rect = self.bounds;
W = (int)CGRectGetWidth(rect);
H = (int)CGRectGetHeight(rect);
fRasterLayer.bounds = rect;
}
printf("---- layoutSubviews %d %d\n", W, H);
fWind->resize(W, H);
fWind->inval(NULL);
}
///////////////////////////////////////////////////////////////////////////////
- (void)drawWithCanvas:(SkCanvas*)canvas {
fRedrawRequestPending = false;
fFPSState->startDraw();
fWind->draw(canvas);
fFPSState->endDraw();
#ifdef FORCE_REDRAW
fWind->inval(NULL);
#endif
fFPSState->flush(fWind);
}
- (void)drawInGL {
// This application only creates a single context which is already set current at this point.
// This call is redundant, but needed if dealing with multiple contexts.
[EAGLContext setCurrentContext:fGL.fContext];
// This application only creates a single default framebuffer which is already bound at this point.
// This call is redundant, but needed if dealing with multiple framebuffers.
glBindFramebuffer(GL_FRAMEBUFFER, fGL.fFramebuffer);
GLint scissorEnable;
glGetIntegerv(GL_SCISSOR_TEST, &scissorEnable);
glDisable(GL_SCISSOR_TEST);
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
if (scissorEnable) {
glEnable(GL_SCISSOR_TEST);
}
glViewport(0, 0, fGL.fWidth, fGL.fHeight);
SkAutoTUnref<SkSurface> surface(fWind->createSurface());
SkCanvas* canvas = surface->getCanvas();
// if we're not "retained", then we have to always redraw everything.
// This call forces us to ignore the fDirtyRgn, and draw everywhere.
// If we are "retained", we can skip this call (as the raster case does)
fWind->forceInvalAll();
[self drawWithCanvas:canvas];
// This application only creates a single color renderbuffer which is already bound at this point.
// This call is redundant, but needed if dealing with multiple renderbuffers.
glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
[fGL.fContext presentRenderbuffer:GL_RENDERBUFFER];
}
- (void)drawInRaster {
SkAutoTUnref<SkSurface> surface(fWind->createSurface());
SkCanvas* canvas = surface->getCanvas();
[self drawWithCanvas:canvas];
CGImageRef cgimage = SkCreateCGImageRef(fWind->getBitmap());
fRasterLayer.contents = (id)cgimage;
CGImageRelease(cgimage);
}
- (void)forceRedraw {
if (fDevManager->isUsingGL())
[self drawInGL];
else
[self drawInRaster];
}
///////////////////////////////////////////////////////////////////////////////
- (void)setSkTitle:(const char *)title {
NSString* text = [NSString stringWithUTF8String:title];
if ([text length] > 0)
self.fTitle = text;
if (fTitleItem && fTitle) {
fTitleItem.title = [NSString stringWithFormat:@"%@%@", fTitle,
[NSString stringWithUTF8String:fFPSState->str.c_str()]];
}
}
- (void)postInvalWithRect:(const SkIRect*)r {
if (!fRedrawRequestPending) {
fRedrawRequestPending = true;
bool gl = fDevManager->isUsingGL();
[CATransaction begin];
[CATransaction setAnimationDuration:0];
fRasterLayer.hidden = gl;
fGLLayer.hidden = !gl;
[CATransaction commit];
if (gl) {
[self performSelector:@selector(drawInGL) withObject:nil afterDelay:0];
}
else {
[self performSelector:@selector(drawInRaster) withObject:nil afterDelay:0];
[self setNeedsDisplay];
}
}
}
- (void)getAttachmentInfo:(SkOSWindow::AttachmentInfo*)info {
glBindRenderbuffer(GL_RENDERBUFFER, fGL.fRenderbuffer);
glGetRenderbufferParameteriv(GL_RENDERBUFFER,
GL_RENDERBUFFER_STENCIL_SIZE,
&info->fStencilBits);
glGetRenderbufferParameteriv(GL_RENDERBUFFER,
GL_RENDERBUFFER_SAMPLES_APPLE,
&info->fSampleCount);
}
@end