android渲染是skia与egl,Android 重学系列 SurfaceView和TextureView 源码浅析(下)

前言

上一篇文章和大家论述了SurfaceView的核心原理,本文和大家聊聊TextureView的核心原理。

正文

TextureView的用法这里稍微解释一下。用一个官方的demo看看。

public class LiveCameraActivity extends Activity implements TextureView.SurfaceTextureListener {

private Camera mCamera;

private TextureView mTextureView;

SurfaceTexture.OnFrameAvailableListener mFrameAvailableListener;

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

mTextureView = new TextureView(this);

mTextureView.setSurfaceTextureListener(this);

setContentView(mTextureView);

}

public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {

mCamera = Camera.open();

try {

surface.setOnFrameAvailableListener(mFrameAvailableListener);

mCamera.setPreviewTexture(surface);

mCamera.startPreview();

} catch (IOException ioe) {

// Something bad happened

}

}

public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

// Ignored, Camera does all the work for us

}

public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {

mCamera.stopPreview();

mCamera.release();

return true;

}

public void onSurfaceTextureUpdated(SurfaceTexture surface) {

// Invoked every time there's a new Camera preview frame

}

}

这是一个最简单的相机预览功能模型。首先通过setSurfaceTextureListener监听TextureView的生命周期:

1.onSurfaceTextureAvailable(TextureView可用).

2.onSurfaceTextureSizeChanged TextureView大小发生了变化

3.onSurfaceTextureUpdated TextureView有视图数据进行了更新。

4.onSurfaceTextureDestroyed TextureView销毁了。

5.setOnFrameAvailableListener 监听TextureView绘制每一帧结束后的回调。

在每一个生命周期中,分别处理了Camera的对应的行为。详细的就不铺开说了。我们主要来关注TextureView,在整个View的绘制流程中做了什么?

TextureView 源码解析

老规矩,我们根据上一篇文章总结的,如何阅读View源码方式进行解析。本文将着重的解析TextureView中lockCanvas,unlockCanvasAndPost,以及draw的方法。

TextureView onMeasure,onLayout,onDraw

TextureView 在 onMeasure,onLayout两个流程并没有什么可说的。我们来看看draw方法。

@Override

public final void draw(Canvas canvas) {

// NOTE: Maintain this carefully (see View#draw)

mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;

if (canvas.isHardwareAccelerated()) {

DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;

TextureLayer layer = getTextureLayer();

if (layer != null) {

applyUpdate();

applyTransformMatrix();

mLayer.setLayerPaint(mLayerPaint); // ensure layer paint is up to date

displayListCanvas.drawTextureLayer(layer);

}

}

}

和SurfaceView不同,TextureView确实是跟着ViewRootImpl 绘制View 树时候的三大流程走。不过有一点不同的是,ViewRootImpl的draw流程时候,都是绘制在从ViewRootImpl中生成的Canvas中。但是TextureView并直接没有使用从上层传递下来的Canvas,而是通过TextureLayer绘制的。

第二点不同的是,TextureView想要可以正常绘制,当前Activity必须要打开硬件渲染。因为这里面必须使用硬件渲染独有的Canvas DisplayListCanvas进行绘制。否则标志位没进来,TextureView跳过draw的方法就是背景色。

让我们来看看TextureLayer是什么吧。

TextureLayer TextureView的画笔的初始化

TextureLayer getTextureLayer() {

if (mLayer == null) {

if (mAttachInfo == null || mAttachInfo.mThreadedRenderer == null) {

return null;

}

mLayer = mAttachInfo.mThreadedRenderer.createTextureLayer();

boolean createNewSurface = (mSurface == null);

if (createNewSurface) {

// Create a new SurfaceTexture for the layer.

mSurface = new SurfaceTexture(false);

nCreateNativeWindow(mSurface);

}

mLayer.setSurfaceTexture(mSurface);

mSurface.setDefaultBufferSize(getWidth(), getHeight());

mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);

if (mListener != null && createNewSurface) {

mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight());

}

mLayer.setLayerPaint(mLayerPaint);

}

if (mUpdateSurface) {

// Someone has requested that we use a specific SurfaceTexture, so

// tell mLayer about it and set the SurfaceTexture to use the

// current view size.

mUpdateSurface = false;

// Since we are updating the layer, force an update to ensure its

// parameters are correct (width, height, transform, etc.)

updateLayer();

mMatrixChanged = true;

mLayer.setSurfaceTexture(mSurface);

mSurface.setDefaultBufferSize(getWidth(), getHeight());

}

return mLayer;

}

一旦发现mLayer没有初始化,这里做的事情分为如下几个步骤:

1.通过从ViewRootImpl传下来的AttchInfo中的ThreadedRenderer调用createTextureLayer()进行生成一个TextureLayer。ThreadedRenderer这个类是硬件渲染的核心类,所有的硬件渲染都是从这个类开始触发。

2.检查是否创建了SurfaceTexture,没有创建则先创建后调用native方法nCreateNativeWindow 保存起来。并保存到TextureLayer。

3.设置SurfaceTexture的宽高,setOnFrameAvailableListener监听SurfaceTexture的回调,并且回调第一个生命周期onSurfaceTextureAvailable。

4.如果需要更新SurfaceTexture,调用updateLayer更新标志位后,更新TextureLayer中的SurfaceTexture以及重新设置宽高。

这里面涉及了两个比较关键的函数ThreadedRenderer.createTextureLayer以及nCreateNativeWindow,以及一个对象SurfaceTexture。从名字上来看叫做Surface纹理,感觉绘制内容都在里面。我们先来看看SurfaceTexture究竟是什么东西?

SurfaceTexture的初始化

public SurfaceTexture(boolean singleBufferMode) {

mCreatorLooper = Looper.myLooper();

mIsSingleBuffered = singleBufferMode;

nativeInit(true, 0, singleBufferMode, new WeakReference(this));

}

关键是调用nativeInit在native层进行初始化。默认是设置的mIsSingleBuffered为false,mCreatorLooper则为当前线程对应的Looper。所以我们想要创建一个SurfaceTexture,可以不是当前的ui主线程,但是当前线程必须存在初始化好的Looper。

SurfaceTexture native层的初始化

static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached,

jint texName, jboolean singleBufferMode, jobject weakThiz)

{

sp producer;

sp consumer;

BufferQueue::createBufferQueue(&producer, &consumer);

if (singleBufferMode) {

consumer->setMaxBufferCount(1);

}

sp surfaceTexture;

if (isDetached) {

surfaceTexture = new GLConsumer(consumer, GL_TEXTURE_EXTERNAL_OES,

true, !singleBufferMode);

} else {

surfaceTexture = new GLConsumer(consumer, texName,

GL_TEXTURE_EXTERNAL_OES, true, !singleBufferMode);

}

if (surfaceTexture == 0) {

jniThrowException(env, OutOfResourcesException,

"Unable to create native SurfaceTexture");

return;

}

surfaceTexture->setName(String8::format("SurfaceTexture-%d-%d-%d",

(isDetached ? 0 : texName),

getpid(),

createProcessUniqueId()));

// If the current context is protected, inform the producer.

consumer->setConsumerIsProtected(isProtectedContext());

SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);

SurfaceTexture_setProducer(env, thiz, producer);

jclass clazz = env->GetObjectClass(thiz);

if (clazz == NULL) {

jniThrowRuntimeException(env,

"Can't find android/graphics/SurfaceTexture");

return;

}

sp ctx(new JNISurfaceTextureContext(env, weakThiz,

clazz));

surfaceTexture->setFrameAvailableListener(ctx);

SurfaceTexture_setFrameAvailableListener(env, thiz, ctx);

}

首先通过createBufferQueue初始化了两个极其重要的角色:

1.IGraphicBufferProducer 图元生产者

2.IGraphicBufferConsumer 图元消费者

接着,使用初始化好的图元消费者,在SurfaceTexture在native层中初始化了一个极其重要的角色GLConsumer。当然在SurfaceTexture这里面图元生产者和图元消费者要区别于SF进程的图元生产者和图元消费者。具体有什么区别稍后再来聊聊。

最后把IGraphicBufferProducer和GLConsumer以及FrameAvailableListener的地址设置在SurfaceTexture的long类型中。

private long mSurfaceTexture;

private long mProducer;

private long mFrameAvailableListener;

GLConsumer的初始化

GLConsumer::GLConsumer(const sp& bq, uint32_t tex,

uint32_t texTarget, bool useFenceSync, bool isControlledByApp) :

ConsumerBase(bq, isControlledByApp),

mCurrentCrop(Rect::EMPTY_RECT),

mCurrentTransform(0),

mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),

mCurrentFence(Fence::NO_FENCE),

mCurrentTimestamp(0),

mCurrentDataSpace(HAL_DATASPACE_UNKNOWN),

mCurrentFrameNumber(0),

mDefaultWidth(1),

mDefaultHeight(1),

mFilteringEnabled(true),

mTexName(tex),

mUseFenceSync(useFenceSync),

mTexTarget(texTarget),

mEglDisplay(EGL_NO_DISPLAY),

mEglContext(EGL_NO_CONTEXT),

mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),

mAttached(true)

{

GLC_LOGV("GLConsumer");

memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(),

sizeof(mCurrentTransformMatrix));

mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);

}

GLConsumer的构造函数,我们能看到有这么几个参数:

1.consumer IGraphicBufferConsumer图元消费者

2.texName 一个int型,实际上设置一个纹理id。

3.GL_TEXTURE_EXTERNAL_OES 这是指渲染在屏幕上的纹理类型,就像OpenGL es的GL_TEXTURE_2D这种类型一样。这也是为什么,我们自定义TextureView的渲染纹理时候,往往需要GL_TEXTURE_EXTERNAL_OES这种类型进行承载。

4.useFenceSync 一个boolean型,他的作用是是否使用fence同步栅,一般都为true。

5.isControlledByApp 在这里面被singleBufferMode所控制。singleBufferMode为true的时候,也就是isControlledByApp为false:代表这个GLConsumer最大只能分配一个图元给SurfaceTexture。不过这里一般为false,代表isControlledByApp为true,可以根据需求获取更多的图元。

当然在初始化GLConsumer过程中,分为2种方式一种是detach一种是非detach。这两个有什么区别呢?最主要的区别就是可以设置texName纹理id。因为OpenGL es的纹理是跟着线程的OpenGL的上下文走的。因此,在TextureView在不同线程渲染同一个SurfaceTexture,需要进行一次detach,重新绑定一次当前线程新的纹理。

了解了SurfaceTexture内部其实控制着自己内部的图元生产者和消费者,我们继续看看TextureLayer是什么东西。

ThreadedRenderer.createTextureLayer

TextureLayer createTextureLayer() {

long layer = nCreateTextureLayer(mNativeProxy);

return TextureLayer.adoptTextureLayer(this, layer);

}

在native层创建了一个对应的TextureLayer之后,保存在java层中返回。

native层创建TextureLayer

static jlong android_view_ThreadedRenderer_createTextureLayer(JNIEnv* env, jobject clazz,

jlong proxyPtr) {

RenderProxy* proxy = reinterpret_cast(proxyPtr);

DeferredLayerUpdater* layer = proxy->createTextureLayer();

return reinterpret_cast(layer);

}

RenderProxy这个对象是ThreadedRenderer在初始化的时候,根据RootNode(可以看成硬件绘制的根节点,硬件绘制将会绘制每一个View中的

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值