Android

您所在的位置:网站首页 view绘制原理 Android

Android

2023-12-23 09:57| 来源: 网络整理| 查看: 265

前面的文章介绍了绘制的RenderPipleline,它将整个RenderNode树通过RenderNodeDrawable将DisplayListData中的绘制到了一个SkSurface,具体来说,是转录到了一个GrOpsTask中去。这个再前面介绍SkCanvas中已经介绍过了。也是说还没有还没有真正提交到GPU进行渲染。当然如果这个RendeNode树中如果有RenderLayer的话,这些layer已经提交到GPU中渲染过了,但是还没有拼接到整个画面。本文将介绍这个SkSurface

SkSurface

SKSurface是管理像素的组件,因此它实际持有对应的像素的内存,它的内存可以来自于CPU,也可以来自GPU,由构造方传入的参数决定定,比如前面我们介绍过的,通过MakeFromBackendRenderTarget创建的SkSurface,它的内存就来自于GPU。我们来看看SkSurface的定义。在skia中,首先定义了SkSurface,然后提供了一个SkSurface_base作为真正的基类,然后派生了四个子类,分别是SkSurface_Gpu, SkSurface_GpuMtl, SkNullSurface, SkSurface_Raster,SkNullSurface.他们分别提供不同的绘制能力。其SkSurface_Gpu使用个GPU进行绘制,SkSurface_Raster使用CPU进行绘制,而SkSurface_GpuMtl是利用IOS平台的绘制能力。SkNullSurface是不进行渲染的Surface的

SKSurface ---SkSurface_base ---SkSurface_Gpu ---SKSurface_Raster ---SkSurface_GpuMtl ---SkNullSurface

因为我们主要来看GPU绘制的流程,因此这里就只研究一下SkSurface_Gpu。本文仅仅介绍几个重要的方法。

1 SkSurface_Gpu

SkSurface_Gpu在继承了SkSurface的属性之外,自己也定义了一个重要的属性

external/skia/src/image/SkSurface_Gpu.h

sk_sp fDevice

这个成员变量是Make的时候创建出来的,有了这个SkGpuDevice对象,才能基于它创建出SkCanvas。

SkCanvas* SkSurface_Gpu::onNewCanvas() { return new SkCanvas(fDevice); }

external/skia/src/image/SkSurface_Gpu.cpp 在前面的分析中,总共有两处构造了SkSurface对象,一个是为设置为RENDER_LAYER的子RenderNode, 一个是绘制RootRenderNode的时候。第一种情况是相当于一个缓存image,第二种情况是是对应于整个应用的界面的image。我们再看看这两处代码

RENDER_LAYER 的情况: frameworks/base/libs/hwui/pipeline/skia/SkiaPipeline.cpp bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,ErrorHandler* errorHandler) { ... SkImageInfo info; info = SkImageInfo::Make(surfaceWidth, surfaceHeight, getSurfaceColorType(), kPremul_SkAlphaType, getSurfaceColorSpace()); SkSurfaceProps props(0, kUnknown_SkPixelGeometry); SkASSERT(mRenderThread.getGrContext() != nullptr); node->setLayerSurface(SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes, info, 0, this->getSurfaceOrigin(), &props)); ... RootRenderNode的情况 GrBackendRenderTarget backendRT(frame.width(), frame.height(), 0, STENCIL_BUFFER_SIZE, fboInfo); sk_sp surface(SkSurface::MakeFromBackendRenderTarget( mRenderThread.getGrContext(), backendRT, this->getSurfaceOrigin(), colorType, mSurfaceColorSpace, &props));

这里分别调用了两个函数MakeRenderTarget 和 MakeFromBackendRenderTarget来生成一个SkSurface对象。这里需要注意一下第一个参数都是mRenderThread.getGrContext(),这个方法返回的是一个GrDirectContext对象,它是在mRenderThread初始化时创建的一个GrDirectContext对象,这个对象有一个GrGLGpu类型的fGpu成员变量,它封装了EGL的接口,具备GPU绘制的能力。 我们来看看这两个函数

2 SkSurface::MakeRenderTarget sk_sp SkSurface::MakeRenderTarget(GrRecordingContext* ctx, SkBudgeted budgeted, const SkImageInfo& info, int sampleCount, GrSurfaceOrigin origin, const SkSurfaceProps* props, bool shouldCreateWithMips) { ... sk_sp device(SkGpuDevice::Make( ctx, budgeted, info, sampleCount, origin, props, mipMapped, SkGpuDevice::kClear_InitContents)); if (!device) { return nullptr; } return sk_make_sp(std::move(device)); }

这里可以看到,经过了两层的包装,GrRecordingContext(GrDirectContext的父类)被包装成SkGpuDevice,最后包装成SkSurface_Gpu对象。也就是说SkSurface_Gpu或者SkGpuDevice最后都是靠这个GrDirectContext来进行GPU绘制的。这里调用SkGpuDevice的Make方法将创建一个GPU上的纹理代理 external/skia/src/gpu/SkGpuDevice.cpp

sk_sp SkGpuDevice::Make(GrRecordingContext* context, SkBudgeted budgeted, const SkImageInfo& info, int sampleCount, GrSurfaceOrigin origin, const SkSurfaceProps* props, GrMipmapped mipMapped, InitContents init) { ... auto surfaceDrawContext = MakeSurfaceDrawContext(context, budgeted, info, sampleCount, origin, props, mipMapped); ... return sk_sp(new SkGpuDevice(std::move(surfaceDrawContext), flags)); } std::unique_ptr SkGpuDevice::MakeSurfaceDrawContext( GrRecordingContext* context, SkBudgeted budgeted, const SkImageInfo& origInfo, int sampleCount, GrSurfaceOrigin origin, const SkSurfaceProps* surfaceProps, GrMipmapped mipmapped) { ... return GrSurfaceDrawContext::Make( context, SkColorTypeToGrColorType(origInfo.colorType()), origInfo.refColorSpace(), SkBackingFit::kExact, origInfo.dimensions(), SkSurfacePropsCopyOrDefault(surfaceProps), sampleCount, mipmapped, GrProtected::kNo, origin, budgeted); }

返回一个GrSurfaceDrawContext::Make创建的GrSurfaceDrawContext对象 external/skia/src/gpu/GrSurfaceDrawContext.cpp

std::unique_ptr GrSurfaceDrawContext::Make( GrRecordingContext* context, GrColorType colorType, sk_sp colorSpace, SkBackingFit fit, SkISize dimensions, const SkSurfaceProps& surfaceProps, int sampleCnt, GrMipmapped mipMapped, GrProtected isProtected, GrSurfaceOrigin origin, SkBudgeted budgeted) { sk_sp proxy = context->priv().proxyProvider()->createProxy(format, dimensions, GrRenderable::kYes, sampleCnt, mipMapped, fit, budgeted, isProtected); if (!proxy) { return nullptr; } return GrSurfaceDrawContext::Make(context, colorType, std::move(colorSpace), std::move(proxy), origin, surfaceProps); }

也就是说这个时候实际上是SkSurface_Gpu对应一个GrTextureProxy对象。

3 SkSurface::MakeFromBackendRenderTarget sk_sp SkSurface::MakeFromBackendRenderTarget(GrRecordingContext* context, const GrBackendRenderTarget& rt, GrSurfaceOrigin origin, SkColorType colorType, sk_sp colorSpace, const SkSurfaceProps* props, SkSurface::RenderTargetReleaseProc relProc, SkSurface::ReleaseContext releaseContext) { ... auto sdc = GrSurfaceDrawContext::MakeFromBackendRenderTarget(context, grColorType, std::move(colorSpace), rt, origin, SkSurfacePropsCopyOrDefault(props), std::move(releaseHelper)); ... auto device = SkGpuDevice::Make(std::move(sdc), SkGpuDevice::kUninit_InitContents); if (!device) { return nullptr; } return sk_make_sp(std::move(device)); }

这里经过另外一层的封装,首先是将一个GrRecordingContext对象和一个GrBackendRenderTarget对象封装成一个GrSurfaceDrawContext,接着以此生成一个SkGpuDevice,然后在生成SkSurface_Gpu对象。这里因为传入的是一个GrBackendRenderTarget,它的用处是什么呢?需要进入到GrSurfaceDrawContext去研究一下。

external/skia/src/gpu/GrSurfaceDrawContext.cpp

std::unique_ptr GrSurfaceDrawContext::MakeFromBackendRenderTarget( GrRecordingContext* context, GrColorType colorType, sk_sp colorSpace, const GrBackendRenderTarget& rt, GrSurfaceOrigin origin, const SkSurfaceProps& surfaceProps, sk_sp releaseHelper) { sk_sp 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); }

也就是说这个SkSurface对应着的是一个GrSurfaceProxy对象

4 surface:: flushAndSubmit

它的定义如下: external/skia/include/core/SkSurface.h

void flushAndSubmit(bool syncCpu = false);

SkSurface_Gpu里的实现如下: external/skia/src/image/SkSurface_Gpu.cpp

void SkSurface::flushAndSubmit(bool syncCpu) { this->flush(BackendSurfaceAccess::kNoAccess, GrFlushInfo()); auto direct = GrAsDirectContext(this->recordingContext()); if (direct) { direct->submit(syncCpu); } }

external/skia/include/gpu/GrRecordingContext.h

static inline GrDirectContext* GrAsDirectContext(GrContext_Base* base) { return base ? base->asDirectContext() : nullptr; }

首先调用flush方法,通过调用GrAsDirectContext方法转换成一个GrDirectContext对象后调用submit方法。

这里的syncCpu为false。 external/skia/src/image/SkSurface.cpp

GrSemaphoresSubmitted SkSurface::flush(BackendSurfaceAccess access, const GrFlushInfo& flushInfo) { return asSB(this)->onFlush(access, flushInfo, nullptr); }

这又会进入子类SkSurface_Gpu的onFlush方法

GrSemaphoresSubmitted SkSurface_Gpu::onFlush(BackendSurfaceAccess access, const GrFlushInfo& info, const GrBackendSurfaceMutableState* newState) { auto dContext = fDevice->recordingContext()->asDirectContext(); if (!dContext) { return GrSemaphoresSubmitted::kNo; } GrSurfaceDrawContext* sdc = fDevice->surfaceDrawContext(); return dContext->priv().flushSurface(sdc->asSurfaceProxy(), access, info, newState); }

这里的fDevice是一个SkGpuDevice对象,从它里面获取的dContext就是上面提到的从RenderThread初始化时创建的GrDirectContext对象,它持有一个GrGLGpu类型的fGpu的成员变量,具备使用GPU绘图的能力。

之后调用dContext->priv().flushSurface(sdc->asSurfaceProxy(), access, info, newState)。

priv()的方法定义如下:它返回一个GrDirectContextPriv,于是调用它的flushSurface方法 external/skia/src/gpu/GrDirectContextPriv.h

inline GrDirectContextPriv GrDirectContext::priv() { return GrDirectContextPriv(this); } // NOLINTNEXTLINE(readability-const-return-type) inline const GrDirectContextPriv GrDirectContext::priv() const { return GrDirectContextPriv(const_cast(this)); } GrSemaphoresSubmitted flushSurface( GrSurfaceProxy* proxy, SkSurface::BackendSurfaceAccess access = SkSurface::BackendSurfaceAccess::kNoAccess, const GrFlushInfo& info = {}, const GrBackendSurfaceMutableState* newState = nullptr) { size_t size = proxy ? 1 : 0; return this->flushSurfaces({&proxy, size}, access, info, newState); } GrSemaphoresSubmitted GrDirectContextPriv::flushSurfaces( SkSpan proxies, SkSurface::BackendSurfaceAccess access, const GrFlushInfo& info, const GrBackendSurfaceMutableState* newState) { ... return fContext->drawingManager()->flushSurfaces(proxies, access, info, newState); }

这里继续调用的drawingManager的flushSurfaces方法,进行刷新之后再通过GrDirectContext进行submit提交到GPU

5 总结

本文主要介绍了SkSurface这个组件,它封装了GPU绘制的资源,可以进行像素渲染。主要分析了它相关的2个创建的过程,通过提供不同的参数,分别创建出一个GrTextureProxy和GrSurfaceProxy,他们最后都会封装成一个SkGpuDevice对象,他们都代表这GPU上的绘制资源。而SkSurface可以创建出一个SkCanvas,这个SkCanvas就是建立在这个SkGpuDevice上的,因此SkCanvas上的绘制操作,即被录制到SkGpuDevice上,随后通过drawingManager的flushSurfaces和GrDirectContext.submit提交到GPU进行渲染。 SkSurface还有一些重要的方法,比如onDraw,onWritePixels, readPixels, onNewImageSnapshot 等, 由于篇幅问题,这里就不再展开。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3