上一篇文章分析了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老皮!!!欢迎大家来找我探讨交流👀