skia2/experimental/iOSSampleApp/SkSampleUIView.mm
kkinnunen 973d92cf91 SampleApp: Remove SkWindow::setColorType
Remove SkWindow::setColorType, it is used wrong and inconsistently.

The color type is actually property of window backbuffer, used when the
window is painted with software. This is as opposed to a generic window
property that would affect all operation.

Similar to MSAA sample count for window GPU backbuffer, the bitmap
backbuffer color type should be a parameter of "attach" or "create
window" functions, should this property ever be added back.

The apps use the call wrong, setting the type as kRGBA_8888
or kBGRRA_8888 without no apparent rationale. These color types
are incorrect, as the raster surface can not work with these.

Reorganize the SkWindow::resize, since no change in SkWindow backbuffer size does not neccessarily mean that SkView would not need the call.

Do not show the sw backbuffer color type in SampleApp title, as
it does not really provide any information. On small screens,
kBGRA_8888_ColorType fills up the whole title.

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

Review URL: https://codereview.chromium.org/1595503002
2016-01-18 01:18:35 -08:00

491 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);
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