973d92cf91
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
491 lines
16 KiB
Plaintext
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
|