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老皮!!!欢迎大家来找我探讨交流👀

相关推荐
韩仔搭建5 小时前
第二章:安卓端启动流程详解与疑难杂症调试手册
android·ui·娱乐
A-花开堪折5 小时前
Android7 Input(七)App与input系统服务建立连接
android
冰糖葫芦三剑客5 小时前
Android 自定义悬浮拖动吸附按钮
android
吃汉堡吃到饱5 小时前
【Android】从Choreographer到UI渲染(二)
android·ui
微信公众号:AI创造财富5 小时前
显示的图标跟UI界面对应不上。
android·ui
aningxiaoxixi5 小时前
安卓 Audio Stream 类型
android
奔跑吧 android6 小时前
【android bluetooth 协议分析 01】【HCI 层介绍 3】【NUMBER_OF_COMPLETED_PACKETS 事件介绍】
android·bluetooth·hci·bt·gd·aosp13
_龙小鱼_8 小时前
Kotlin扩展简化Android动画开发
android·开发语言·kotlin
奔跑吧 android9 小时前
【android bluetooth 协议分析 01】【HCI 层介绍 6】【WriteLeHostSupport命令介绍】
android·bluetooth·bt·gd·aosp13·writelehostsup·hcicmd
uwvwko9 小时前
ctfshow——web入门254~258
android·前端·web·ctf·反序列化