如何在通常的 iOS 应用程序(基于 UIWindow)中使用 GPU 加速的 SkCanvas?

Posted

技术标签:

【中文标题】如何在通常的 iOS 应用程序(基于 UIWindow)中使用 GPU 加速的 SkCanvas?【英文标题】:How to use GPU accelerated SkCanvas in usual iOS application (based on UIWindow)? 【发布时间】:2017-02-07 17:39:55 【问题描述】:

是否可以将 OpenGL 视图添加到 UIWindow 并使用 Skia 在其上进行绘制?

我找到了一个例子,我们在其中初始化了这样的视图:

 - (void)initialize 
     CAEAGLLayer* layer = (CAEAGLLayer*)self.layer;

     layer.opaque = NO;
     layer.drawableProperties = @kEAGLDrawablePropertyRetainedBacking: @(NO),
                                  kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8;

     self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
      if (!self.context || ![EAGLContext setCurrentContext:self.context])
         NSLog(@"Cannot create EAGLContext!");

     GLuint framebuffer;
     GLuint renderbuffer;
     glGenFramebuffers(1, &framebuffer);
     glGenRenderbuffers(1, &renderbuffer);
     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
     glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);

     [self.context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)layer];
     glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);

     GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
     if (status != GL_FRAMEBUFFER_COMPLETE)
         NSLog(@"Failed to make complete frame buffer: %x", status);

     CADisplayLink* displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawFrame:)];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];


- (void)drawFrame:(CADisplayLink*)sender 
    glClearColor(1.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);

    [self.context presentRenderbuffer:GL_RENDERBUFFER];

绘制了红色背景,但我无法让 Skia 使用此视图。

我的滑雪代码:

const GrGLInterface* glInterface = GrGLCreateNativeInterface();
NSAssert(glInterface->validate(), nil);

GrContextOptions contextOptions;
GrContext* grContext = GrContext::Create(kOpenGL_GrBackend, (intptr_t)glInterface, contextOptions);
sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);

GrBackendRenderTargetDesc grBackendRenderTargetDesc;

// This is GLuint framebuffer value from view setup code above.
grBackendRenderTargetDesc.fRenderTargetHandle = self.framebufferID; 

grBackendRenderTargetDesc.fWidth = self.rboWidth;
grBackendRenderTargetDesc.fHeight = self.rboHeight;
grBackendRenderTargetDesc.fConfig = kRGBA_8888_GrPixelConfig;
grBackendRenderTargetDesc.fOrigin = kTopLeft_GrSurfaceOrigin;
grBackendRenderTargetDesc.fSampleCnt = 0;
grBackendRenderTargetDesc.fStencilBits = 0;

SkSurfaceProps skSurfaceProps(0, kUnknown_SkPixelGeometry);
sk_sp<SkSurface> skSurface = SkSurface::MakeFromBackendRenderTarget(grContext, grBackendRenderTargetDesc, &skSurfaceProps);

if (skSurface)

    skCanvas = skSurface->getCanvas();

    SkPaint paint;
    paint.setColor(SK_ColorGREEN);
    skCanvas->drawPaint(paint);

当我在 [self.context presentRenderbuffer:GL_RENDERBUFFER] 之前的 [... drawFrame:] 中放置画布绘制代码时,它不会绘制任何东西。

我错过了什么?我应该如何将 SkSurface/SkCanvas 与给定的 EAGLContext 链接,我应该如何调用skia 绘图代码以使其正常工作?

【问题讨论】:

【参考方案1】:

当我打电话时它按预期工作

skSurface->prepareForExternalIO() 

在所有 Skia 绘图代码之后,在我调用之前

[self.context presentRenderbuffer:GL_RENDERBUFFER];

【讨论】:

以上是关于如何在通常的 iOS 应用程序(基于 UIWindow)中使用 GPU 加速的 SkCanvas?的主要内容,如果未能解决你的问题,请参考以下文章

基于视图的 iOS 应用程序模板

如何在KIOSK模式下打开基于Java的Web应用程序?

如何使 PhoneGap iOS 应用程序的主窗口不可拖动?

iOS开发 - 基于Token的身份验证-JWT

iOS 中基于位置的功能

如何在基于 SwiftUI 的 iOS 应用中呈现连续视图?