Android View绘制原理-GrSurface
  mkIZDEUN7jdf 2023年11月02日 117 0

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

1 GrSurface家族

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

GrGpuResource
    -- GrSurface 
       --GrRenderTarget
           --GrGLRenderTarget
       --GrAttachment
            --GrGLAttachment
       --GrTexture
            --GrGLTexture

2. GrSurfaceProxy家族

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

GrSurfaceProxy
  --GrRenderTargetProxy
  --GrTextureProxy

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

external/skia/src/gpu/GrSurfaceProxy.h

sk_sp<GrSurface>       fTarget;

3. GrSurfaceProxy的包装流程

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

首先创建一个backendRT对象

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。


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

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

//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

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

GrRenderTarget的生成流程

external/skia/src/gpu/GrResourceProvider.cpp

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

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

external/skia/src/gpu/GrGpu.cpp

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

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

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

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的构造方法

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

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

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

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

typedef GrGpuResource INHERITED;

external/skqp/include/gpu/GrGpuResource.h

GrGpu* fGpu;

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

4.总结

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

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  a1POfVYpMOW2   2023年12月23日   136   0   0 flutterciflutterideciide
mkIZDEUN7jdf