Android View绘制原理-GrSurface

上一篇文章分析了SkSurface的两种生成方式,他们都需要使用GrSurfaceDrawContext来创建一个SkGpuDevice。生成GrSurfaceDrawContext时其中一种方式生成的是GrSurfaceProxy,另外一种生成的是GrTextureProxy,从它们的名字可以看出,他们是一个代理,他们代理的就是一个GrSurface对象。而这个GrSurface才是真正代表着GPU资源。这篇文章就是看看GrSurface是如何创建的。

1 GrSurface家族

GrSurface继承自GrGpuResource,代表GPU的资源,在skia库中,有好几个子类,比如GrRenderTarget,GrAttachment,GrTexture,以及基于OpenGL的GrGLRenderTarget,GrGLAttachment,GrGLTexture

java 复制代码
GrGpuResource
    -- GrSurface 
       --GrRenderTarget
           --GrGLRenderTarget
       --GrAttachment
            --GrGLAttachment
       --GrTexture
            --GrGLTexture

2. GrSurfaceProxy家族

GrSurface,GrRenderTarget,GrTexture有对应的Proxy,他们的关系如下:

java 复制代码
GrSurfaceProxy
  --GrRenderTargetProxy
  --GrTextureProxy

他们的主要作用就是持有创建GrSurface的参数,比如尺寸,格式等等,并在需要的时刻初始化它们所代理的fTarget,它的类型是sk_sp,是一个指针。

external/skia/src/gpu/GrSurfaceProxy.h

java 复制代码
sk_sp<GrSurface>       fTarget;

3. GrSurfaceProxy的包装流程

GrSurfaceProxy这里生成的是它的子类GrRenderTargetProxy

首先创建一个backendRT对象

java 复制代码
GrBackendRenderTarget backendRT(frame.width(), frame.height(), 0, STENCIL_BUFFER_SIZE, fboInfo);

GrBackendRenderTarget::GrBackendRenderTarget(int width,
                                             int height,
                                             int sampleCnt,
                                             int stencilBits,
                                             const GrGLFramebufferInfo& glInfo)
        : fWidth(width)
        , fHeight(height)
        , fSampleCnt(std::max(1, sampleCnt))
        , fStencilBits(stencilBits)
        , fBackend(GrBackendApi::kOpenGL)
        , fGLInfo(glInfo) {
    fIsValid = SkToBool(glInfo.fFormat); // the glInfo must have a valid format
}

创建backendRT时,第三个参数时sampleCnt ,传值为0;是第四个参数是stencilBits,传值为STENCIL_BUFFER_SIZE ,它的值为8,同时它的fBackend 设置为GrBackendApi::kOpenGL。

然后利用这个backendRT来创建GrSurfaceDrawContext。

java 复制代码
std::unique_ptr<GrSurfaceDrawContext> GrSurfaceDrawContext::MakeFromBackendRenderTarget(
        GrRecordingContext* context,
        GrColorType colorType,
        sk_sp<SkColorSpace> colorSpace,
        const GrBackendRenderTarget& rt,
        GrSurfaceOrigin origin,
        const SkSurfaceProps& surfaceProps,
        sk_sp<GrRefCntedCallback> releaseHelper) {
    sk_sp<GrSurfaceProxy> proxy(
            context->priv().proxyProvider()->wrapBackendRenderTarget(rt, std::move(releaseHelper)));
    if (!proxy) {
        return nullptr;
    }

    return GrSurfaceDrawContext::Make(context, colorType, std::move(colorSpace), std::move(proxy), origin, surfaceProps);
}

这里首先利用proxyProvider创建出GrSurfaceProxy,然后作为入参构建出GrSurfaceDrawContext返回。 构建GrSurfaceProxy的方法的定义如下:

external/skia/src/gpu/GrProxyProvider.cpp

java 复制代码
sk_sp<GrSurfaceProxy> GrProxyProvider::wrapBackendRenderTarget(
        const GrBackendRenderTarget& backendRT,
        sk_sp<GrRefCntedCallback> releaseHelper) {
     ...
    auto direct = fImageContext->asDirectContext();
    if (!direct) {
        return nullptr;
    }

    GrResourceProvider* resourceProvider = direct->priv().resourceProvider();

    sk_sp<GrRenderTarget> rt = resourceProvider->wrapBackendRenderTarget(backendRT);
    ...
    return sk_sp<GrRenderTargetProxy>(new GrRenderTargetProxy(std::move(rt), UseAllocator::kNo));
}

这里返回的是子类GrRenderTargetProxy的实例。构造这个实例要创建一个GrRenderTarget对象,它是由GrResourceProvider包装出来的。之后赋给这个代理的fTarget。
external/skia/src/gpu/GrRenderTargetProxy.cpp

java 复制代码
//Wrapped version
GrRenderTargetProxy::GrRenderTargetProxy(sk_sp<GrSurface> surf,
                                         UseAllocator useAllocator,
                                         WrapsVkSecondaryCB wrapsVkSecondaryCB)
        : INHERITED(std::move(surf), SkBackingFit::kExact, useAllocator)
        , fSampleCnt(fTarget->asRenderTarget()->numSamples())
        , fWrapsVkSecondaryCB(wrapsVkSecondaryCB) {
}

它是继承自GrSurfaceProxy
external/skia/src/gpu/GrSurfaceProxy.cpp

java 复制代码
GrSurfaceProxy::GrSurfaceProxy(sk_sp<GrSurface> surface,
                               SkBackingFit fit,
                               UseAllocator useAllocator)
        : fTarget(std::move(surface))
       ...){
}

GrRenderTarget的生成流程

external/skia/src/gpu/GrResourceProvider.cpp

java 复制代码
sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendRenderTarget(
        const GrBackendRenderTarget& backendRT) {
    return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(backendRT);
}

最后回到了fGpu上去,调用wrapBackendRenderTarget方法

external/skia/src/gpu/GrGpu.cpp

java 复制代码
sk_sp<GrRenderTarget> GrGpu::wrapBackendRenderTarget(const GrBackendRenderTarget& backendRT) {
    ...
    sk_sp<GrRenderTarget> rt = this->onWrapBackendRenderTarget(backendRT);
    if (backendRT.isFramebufferOnly()) {
        rt->setFramebufferOnly();
    }
    return rt;
}

onWrapBackendRenderTarget在子类GrGLGpu里实现
external/skia/src/gpu/gl/GrGLGpu.cpp

java 复制代码
sk_sp<GrRenderTarget> GrGLGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& backendRT) {
    GrGLFramebufferInfo info;
    if (!backendRT.getGLFramebufferInfo(&info)) {
        return nullptr;
    }
    GrGLRenderTarget::IDs rtIDs;
    if (sampleCount <= 1) {
        rtIDs.fSingleSampleFBOID = info.fFBOID;
        rtIDs.fMultisampleFBOID = GrGLRenderTarget::kUnresolvableFBOID;
    } else {
        rtIDs.fSingleSampleFBOID = GrGLRenderTarget::kUnresolvableFBOID;
        rtIDs.fMultisampleFBOID = info.fFBOID;
    }
    rtIDs.fMSColorRenderbufferID = 0;
    rtIDs.fRTFBOOwnership = GrBackendObjectOwnership::kBorrowed;
    rtIDs.fTotalMemorySamplesPerPixel = sampleCount;
    return GrGLRenderTarget::MakeWrapped(this, backendRT.dimensions(), format, sampleCount, rtIDs,
                                         backendRT.stencilBits());
}

这里将backendRT的属性设置到一个 GrGLRenderTarget::IDs类型的变量rtIDs,然后在调用GrGLRenderTarget::MakeWrapped生成GrGLRenderTarget。

external/skia/src/gpu/GrBackendSurface.cpp

java 复制代码
bool GrBackendRenderTarget::getGLFramebufferInfo(GrGLFramebufferInfo* outInfo) const {
    if (this->isValid() && GrBackendApi::kOpenGL == fBackend) {
        *outInfo = fGLInfo;
        return true;
    }
    return false;
}

因此fBackend == GrBackendApi::kOpenGL 因此满足第一个条件。同时得到info值。info.fFormat中包含有创建的GrSurface的格式,GrGLRenderTarget是GrSurface的子类,对应的是一个2D的纹理。

external/skia/src/gpu/gl/GrGLRenderTarget.cpp

java 复制代码
sk_sp<GrGLRenderTarget> GrGLRenderTarget::MakeWrapped(GrGLGpu* gpu,
                                                      const SkISize& dimensions,
                                                      GrGLFormat format,
                                                      int sampleCount,
                                                      const IDs& idDesc,
                                                      int stencilBits) {
    GrGLAttachment* sb = nullptr;
    if (stencilBits) {
        ...
        sb = new GrGLAttachment(gpu, sbDesc, dimensions,
                                GrAttachment::UsageFlags::kStencilAttachment, sampleCount, sFmt);
    }
    return sk_sp<GrGLRenderTarget>(
            new GrGLRenderTarget(gpu, dimensions, format, sampleCount, idDesc, sb));
}

因为上面传入的stencilBits == 8, 也因此这里会创建一个GrGLAttachment,它是GrAttachment的子类,因此也是GrSurface的子类。 GrGLRenderTarget的构造方法

java 复制代码
GrGLRenderTarget::GrGLRenderTarget(GrGLGpu* gpu,
                                   const SkISize& dimensions,
                                   GrGLFormat format,
                                   int sampleCount,
                                   const IDs& ids,
                                   GrGLAttachment* stencil)
        : GrSurface(gpu, dimensions, GrProtected::kNo)
        , INHERITED(gpu, dimensions, sampleCount, GrProtected::kNo, stencil) {
    this->init(format, ids);
    this->setFlags(gpu->glCaps(), ids);
    this->registerWithCacheWrapped(GrWrapCacheable::kNo);
}

它的继承自GrRenderTarget

java 复制代码
GrRenderTarget::GrRenderTarget(GrGpu* gpu,
                               const SkISize& dimensions,
                               int sampleCount,
                               GrProtected isProtected,
                               GrAttachment* stencil)
        : INHERITED(gpu, dimensions, isProtected)
        , fSampleCnt(sampleCount) {
    if (this->numSamples() > 1) {
        fMSAAStencilAttachment.reset(stencil);
    } else {
        fStencilAttachment.reset(stencil);
    }
}

numSamples返回的是fSampleCnt,此处为0, 因此attachment赋值给了fStencilAttachment。

GrRenderTarget继承自GrSurface
external/skia/src/gpu/GrSurface.h

java 复制代码
GrSurface(GrGpu* gpu, const SkISize& dimensions, GrProtected isProtected)
            : INHERITED(gpu)
            , fDimensions(dimensions)
            , fSurfaceFlags(GrInternalSurfaceFlags::kNone)
            , fIsProtected(isProtected) {}

它的父类就是GrGpuResource,INHERITED是GrGpuResource的别名,它最重要的属性就是fGpu

java 复制代码
typedef GrGpuResource INHERITED;

external/skqp/include/gpu/GrGpuResource.h

java 复制代码
GrGpu* fGpu;

到这里我们就弄清楚了GrGLRenderTargetProxy的创建流程,可以看到对于GrRenderTargetProxy来说,如果是调用MakeFromBackendRenderTarget的生成的话,构造的时候就创建了一个fTarget(是一个GrGLRenderTarget对象)并且这个fTarget的fStencilAttachment也指向了一个刚刚创建的GrGLAttachment对象。

4.总结

本文介绍GrSurface相关的概念,并进一步分析了GrRenderTargetProxy的包装流程,通过wrap的方式,创建出来的GrRenderTargetProxy中已经持有了一个GrSurface对象,它是一个GrGLRenderTarget的类型的对象,它持有的一个GrAttachment类型的成员fStencilAttachment也已经创建好。

👀关注公众号:Android老皮!!!欢迎大家来找我探讨交流👀

相关推荐
TheNextByte117 分钟前
Android USB文件传输无法使用?5种解决方法
android
quanyechacsdn1 小时前
Android Studio创建库文件用jitpack构建后使用implementation方式引用
android·ide·kotlin·android studio·implementation·android 库文件·使用jitpack
程序员陆业聪2 小时前
聊聊2026年Android开发会是什么样
android
编程大师哥2 小时前
Android分层
android
极客小云4 小时前
【深入理解 Android 中的 build.gradle 文件】
android·安卓·安全架构·安全性测试
Juskey iii4 小时前
Android Studio Electric Eel | 2022.1.1 Patch 2 版本下载
android·ide·android studio
Android技术之家4 小时前
2025年度Android行业总结:AI驱动生态重构,跨端融合开启新篇
android·人工智能·重构
洞见前行4 小时前
Android第二代加固技术原理详解(附源码)
android
风清云淡_A5 小时前
【JetCompose】入门教程实战基础案例01之显隐动画
android
2501_916007475 小时前
iPhone APP 性能测试怎么做,除了Instruments还有什么工具?
android·ios·小程序·https·uni-app·iphone·webview