blink渲染知识12 - 硬件渲染之触发beginframe

本文深入探讨了Android系统中硬件渲染的过程,包括BeginMainFrame的触发、硬件渲染的调用栈以及不同场景下(如开启和关闭Tab)的渲染流程。详细解析了从ThreadProxy到SynchronousCompositor的各个关键步骤,揭示了硬件绘制如何与UI线程、合成器线程以及渲染线程协同工作,以实现高效流畅的图形渲染。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ThreadProxy::BeginMainFrame会触发renderlayer tree中各layerpaint.那么谁触发的BeginMainFrame?



ThreadProxy::ScheduledActionSendBeginMainFrame

-> Proxy::MainThreadTaskRunner()->PostTask(

FROM_HERE,

base::Bind(&ThreadProxy::BeginMainFrame,





硬件渲染触发的callstack:

注意,下面的callstack来自4.3机子:

#0 cc::ThreadProxy::ScheduledActionSendBeginMainFrame(this=0x641def38) at ../../cc/trees/thread_proxy.cc:691

#1 0x6078da14 in cc::Scheduler::ProcessScheduledActions

//这里只是向webcore申请paint操作。

(this=this@entry=0x64993cb8) at../../cc/scheduler/scheduler.cc:665

#2 0x6078df92 in cc::Scheduler::BeginImplFrame

//此函数不光要向webcore线程发出申请一paint操作。还要自己构造合成一个frame.

(this=this@entry=0x64993cb8, args=...) at../../cc/scheduler/scheduler.cc:520

#3 0x6078e304 in cc::Scheduler::BeginFrame(this=0x64993cb8, args=...) at ../../cc/scheduler/scheduler.cc:426

#4 0x6079795e in cc::LayerTreeHostImpl::BeginFrame(this=<optimized out>, args=...) at../../cc/trees/layer_tree_host_impl.cc:1408

#5 0x60b97c16 incontent::SynchronousCompositorOutputSurface::InvokeComposite(this=this@entry=0x642f4868, transform=..., viewport=..., clip=...,viewport_rect_for_tile_priority=...,

transform_for_tile_priority=..., hardware_draw=<optimizedout>, hardware_draw@entry=true) at../../content/browser/android/in_process/synchronous_compositor_output_surface.cc:227

#6 0x60b97e5e incontent::SynchronousCompositorOutputSurface::DemandDrawHw(this=0x642f4868, surface_size=..., transform=..., viewport=...,clip=..., viewport_rect_for_tile_priority=...,

transform_for_tile_priority=...) at../../content/browser/android/in_process/synchronous_compositor_output_surface.cc:178

#7 0x60b977b0 in content::SynchronousCompositorImpl::DemandDrawHw

//这个是同步compositor.此函数就会返回一个compositorframe.

this=0x6498e6c0, surface_size=..., transform=..., viewport=...,clip=..., viewport_rect_for_tile_priority=...,transform_for_tile_priority=...)

at../../content/browser/android/in_process/synchronous_compositor_impl.cc:139

#8 0x607f6cf0 inandroid_webview::BrowserViewRenderer::OnDrawHardware

注意,这个函数被调用的前提是我们是4.3,4.4系统,因为这个系统上,ui线程会调用drawGl,所以可以让他调用BrowserViewRender来合成一个compositorframe. 5.0系统上,应该又真正的ui线程去合成compositorframe,而不应该在drawGl执行时干这件事情。

BrowserViewRender据说就是处理webview相关的一切绘图操作的类。此函数会掉用browserchildcompositor合成出一份compositorframe并保存到draw_gl_input里面。供后续使用,后续先要commit他。

(this=this@entry=0x6498e540)at ../../android_webview/browser/browser_view_renderer.cc:304

#9 0x60e5a5f8 in android_webview::AwContents::DrawGL(this=0x6498e458, draw_info=0xbec91240) at../../android_webview/native/aw_contents.cc:429//这个是我们注册给系统的drawGL函数。在4.4,4.3上是ui线程调用,在androidL上是一个独立的系统的render线程调用。

#10 0x60f5e816 in draw_gl_normal(this=0x641ffeb0, data=<optimized out>, what=<optimizedout>) at../../third_party/android_plat_support/draw_gl_functor.cpp:139

#11 android::(anonymous namespace)::DrawGLFunctor::operator()(this=0x641ffeb0, what=<optimized out>, data=<optimizedout>) at../../third_party/android_plat_support/draw_gl_functor.cpp:60//怀疑这个函数被注册到系统,底层。

#12 0x40bf40b2 in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#13 0x40be80b0 in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#14 0x40be686c in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#15 0x40be6798 in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#16 0x40beee90 in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#17 0x4024caf6 in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libandroid_runtime.so

#18 0x408dec50 in dvmPlatformInvoke () from/tmp/tshao-adb-gdb-libs/system/lib/libdvm.so

#19 0x4090eed2 in dvmCallJNIMethod(unsigned int const*, JValue*,Method const*, Thread*) () from/tmp/tshao-adb-gdb-libs/system/lib/libdvm.so

#20 0x408e8064 in dvmJitToInterpNoChain () from/tmp/tshao-adb-gdb-libs/system/lib/libdvm.so

#21 0x408e8064 in dvmJitToInterpNoChain () from/tmp/tshao-adb-gdb-libs/system/lib/libdvm.so





关闭tab时,硬件渲染引发的callstack:

#0 cc::ThreadProxy::ScheduledActionSendBeginMainFrame(this=0x641def38) at ../../cc/trees/thread_proxy.cc:691

#1 0x6078da14 in cc::Scheduler::ProcessScheduledActions(this=0x64993cb8) at ../../cc/scheduler/scheduler.cc:665

#2 0x6078daca in cc::Scheduler::SetNeedsCommit (this=<optimizedout>) at ../../cc/scheduler/scheduler.cc:169

#3 0x607a2928 in cc::ThreadProxy::SetNeedsCommitOnImplThread(this=0x641def38) at ../../cc/trees/thread_proxy.cc:400

#4 0x6079ba64 in cc::LayerTreeHostImpl::ReleaseGL(this=0x64964948) at ../../cc/trees/layer_tree_host_impl.cc:2200

#5 0x6076a270 in cc::OutputSurface::ReleaseGL (this=<optimizedout>) at ../../cc/output/output_surface.cc:170

#6 0x60b97afe incontent::SynchronousCompositorOutputSurface::ReleaseHwDraw(this=<optimized out>) at../../content/browser/android/in_process/synchronous_compositor_output_surface.cc:157

#7 0x60b979c8 incontent::SynchronousCompositorImpl::ReleaseHwDraw (this=<optimizedout>) at../../content/browser/android/in_process/synchronous_compositor_impl.cc:114

#8 0x607f6682 inandroid_webview::BrowserViewRenderer::ReleaseHardware(this=this@entry=0x6498e540) at../../android_webview/browser/browser_view_renderer.cc:543

#9 0x60e5a82c inandroid_webview::AwContents::OnDetachedFromWindow (this=0x6498e458,env=<optimized out>, obj=<optimized out>) at../../android_webview/native/aw_contents.cc:956

#10 0x408dec50 in dvmPlatformInvoke () from/tmp/tshao-adb-gdb-libs/system/lib/libdvm.so

#11 0x4090eed2 in dvmCallJNIMethod(unsigned int const*, JValue*,Method const*, Thread*) () from/tmp/tshao-adb-gdb-libs/system/lib/libdvm.so

#12 0x409108be in dvmResolveNativeMethod(unsigned int const*,JValue*, Method const*, Thread*) () from/tmp/tshao-adb-gdb-libs/system/lib/libdvm.so

#13 0x408e8064 in dvmJitToInterpNoChain () from/tmp/tshao-adb-gdb-libs/system/lib/libdvm.so

#14 0x408e8064 in dvmJitToInterpNoChain () from/tmp/tshao-adb-gdb-libs/system/lib/libdvm.so

Backtrace stopped: previous frame identical to this frame (corruptstack?)





还可能出现的软件渲染触发的callstack:

#0 cc::ThreadProxy::ScheduledActionSendBeginMainFrame(this=0x641def38) at ../../cc/trees/thread_proxy.cc:691

#1 0x6078da14 in cc::Scheduler::ProcessScheduledActions(this=this@entry=0x64993cb8) at ../../cc/scheduler/scheduler.cc:665

#2 0x6078df92 in cc::Scheduler::BeginImplFrame(this=this@entry=0x64993cb8, args=...) at../../cc/scheduler/scheduler.cc:520

#3 0x6078e304 in cc::Scheduler::BeginFrame (this=0x64993cb8,args=...) at ../../cc/scheduler/scheduler.cc:426

#4 0x6079795e in cc::LayerTreeHostImpl::BeginFrame(this=<optimized out>, args=...) at../../cc/trees/layer_tree_host_impl.cc:1408

#5 0x60b97c16 incontent::SynchronousCompositorOutputSurface::InvokeComposite(this=this@entry=0x642f4868, transform=..., viewport=..., clip=...,viewport_rect_for_tile_priority=...,

transform_for_tile_priority=..., hardware_draw=<optimizedout>, hardware_draw@entry=false) at../../content/browser/android/in_process/synchronous_compositor_output_surface.cc:227

#6 0x60b97f28 incontent::SynchronousCompositorOutputSurface::DemandDrawSw(this=0x642f4868, canvas=<optimized out>) at../../content/browser/android/in_process/synchronous_compositor_output_surface.cc:202

#7 0x60b97800 in content::SynchronousCompositorImpl::DemandDrawSw(this=0x6498e6c0, canvas=<optimized out>) at../../content/browser/android/in_process/synchronous_compositor_impl.cc:155

#8 0x607f6a14 inandroid_webview::BrowserViewRenderer::CompositeSW(this=this@entry=0x6498e540, canvas=canvas@entry=0xbec912c8) at../../android_webview/browser/browser_view_renderer.cc:846

#9 0x607f7796 inandroid_webview::BrowserViewRenderer::ForceFakeCompositeSW(this=this@entry=0x6498e540) at../../android_webview/browser/browser_view_renderer.cc:840

#10 0x607f7914 inandroid_webview::BrowserViewRenderer::FallbackTickFired(this=0x6498e540) at../../android_webview/browser/browser_view_renderer.cc:826

#11 0x607f5afa in Run (object=<optimized out>,this=0xbec91420) at ../../base/bind_internal.h:134

#12 MakeItSo (a1=<optimized out>, runnable=...) at../../base/bind_internal.h:871

#13 base::internal::Invoker<1,base::internal::BindState<base::internal::RunnableAdapter<void(android_webview::BrowserViewRenderer::*)()>, void(android_webview::BrowserViewRenderer*), void (base::internal::Unret

ainedWrapper<android_webview::BrowserViewRenderer>)>,void(android_webview::BrowserViewRenderer*)>::Run(base::internal::BindStateBase*)(base=<optimized out>) at ../../base/bind_internal.h:1169

#14 0x6055cdf2 in Run (this=<optimized out>) at../../base/callback.h:401

#15 base::CancelableCallback<void ()>::Forward()(this=<optimized out>) at ../../base/cancelable_callback.h:106

#16 0x6055ce38 in Run (object=<optimized out>,this=0xbec91438) at ../../base/bind_internal.h:134

#17 MakeItSo (weak_ptr=..., runnable=...) at../../base/bind_internal.h:882

#18 base::internal::Invoker<1,base::internal::BindState<base::internal::RunnableAdapter<void(base::CancelableCallback<void ()>::*)()>, void(base::CancelableCallback<void ()>*), void(base::WeakPtr<base::Cancela

bleCallback<void ()> >)>, void(base::CancelableCallback<void()>*)>::Run(base::internal::BindStateBase*) (base=0x64215488)at ../../base/bind_internal.h:1169

#19 0x6100e280 in Run (this=0xbec91550) at../../base/callback.h:401

#20 base::MessageLoop::RunTask (this=this@entry=0x5c9415f8,pending_task=...) at ../../base/message_loop/message_loop.cc:464

#21 0x6100e338 in base::MessageLoop::DeferOrRunPendingTask(this=this@entry=0x5c9415f8, pending_task=...) at../../base/message_loop/message_loop.cc:482

#22 0x6100ebac in base::MessageLoop::DoDelayedWork(this=0x5c9415f8, next_delayed_work_time=0xbec91598) at../../base/message_loop/message_loop.cc:634

#23 0x60ff1b46 in DoRunLoopOnce(delayed_scheduled_time_ticks=34676111993, native_delegate=<optimizedout>, obj=0x4330001d, env=0x41f93cf0) at../../base/message_loop/message_pump_android.cc:60

#24Java_com_jetpack_dolphin_webkit_org_chromium_base_SystemMessageHandler_nativeDoRunLoopOnce(env=0x41f93cf0, jcaller=0x4330001d,messagePumpDelegateNative=<optimized out>,

delayedScheduledTimeTicks=34676111993) atgen/base/jni/SystemMessageHandler_jni.h:42

#25 0x408dec50 in dvmPlatformInvoke () from/tmp/tshao-adb-gdb-libs/system/lib/libdvm.so

#26 0x4090eed2 in dvmCallJNIMethod(unsigned int const*, JValue*,Method const*, Thread*) () from/tmp/tshao-adb-gdb-libs/system/lib/libdvm.so

#27 0x408e8064 in dvmJitToInterpNoChain () from/tmp/tshao-adb-gdb-libs/system/lib/libdvm.so

#28 0x408e8064 in dvmJitToInterpNoChain () from/tmp/tshao-adb-gdb-libs/system/lib/libdvm.so



看看DrawGLFunctor的使用和调用。

Native层和java层都有DrawGLFunctor他们相互关联。

native的在third_party/android_plat_support目录下。


DrawGLFunctor.java类的requestDrawGL函数会将nativedrawGL操作注册进系统,系统会在合适时间调用。


AwContents.java有函数requestDrawGL会被nativie调用。

->NativeGLDelegate接口的requestDrawGL函数,这个接口实际上是WebViewNativeGLDelegate。,定义在webviewchromium.java

->建立DrawGLFunctor并调用DrawGLFunctor.requestDrawGL().

->delegate的函数,delegateProxyDelegate(Api21CompatibilityDelegate)

ProxyDelegate继承自webviewDelegate,并且他只是一个adapter,他含有真正的delegate,

Api21CompatibilityDelegateApi21CompatibilityDelegate也继承自WebViewDelegate,并且定义在WebViewDelegateFactory.java里。


->WebViewDelegateFactory.javaApi21CompatibilityDelegate的:

@Override

public int callDrawGlFunction(Canvascanvas, long nativeDrawGLFunctor) {

try {

// DOLPHIN CHANGE BEGIN

if (mDetachFunctorMethod == null) return -1;


if (android.os.Build.VERSION.SDK_INT < 20) {

return(Integer)mCallDrawGLFunctionMethod.invoke(canvas,(int)nativeDrawGLFunctor);

}

// DOLPHIN CHANGE END

return(Integer)mCallDrawGLFunctionMethod.invoke(canvas,nativeDrawGLFunctor);//nativeDrawGLFunctor至此被传进入了系统内部。这样系统就会调用nativeDrawGLFunctor

} catch (Exception e) {

throw new RuntimeException("Invalid reflection",e);

}

}


或者

publicvoid invokeDrawGlFunctor(ViewcontainerView, long nativeDrawGLFunctor,

boolean waitForCompletion) {

try {

Object viewRootImpl =mGetViewRootImplMethod.invoke(containerView);

if (viewRootImpl != null &&mInvokeFunctorMethod != null) {

mInvokeFunctorMethod.invoke(viewRootImpl,nativeDrawGLFunctor,waitForCompletion);

}

} catch (Exception e) {

throw new RuntimeException("Invalid reflection",e);

}

}


上面的mCallDrawGLFunctionMethod可能是类android.view.HardwareCanvascallDrawGLFunction成员,或者callDrawGLFunction2成员。

上面的mInvokeFunctorMethod可能是android.view.ViewRootImpl类的invokeFunctor成员



那么awContents.ccrequestDrawGL函数被调用的stack;这里只是要求系统调用gl操作而发出一个申请。

#0 android_webview::AwContents::RequestDrawGL(this=0x5a7627a0,

canvas=0x70600021, wait_for_completion=false) at../../android_webview/native/aw_contents.cc:797

#1 0x61037086 in android_webview::BrowserViewRenderer::OnDraw

//这个函数要在childcompositor这边合成一个compositorframe, 此函数是ui线程执行。所以他可以合成compositorframe. 然后向系统注册申请下一个gl操作。

(this=this@entry=0x5a762888,java_canvas=java_canvas@entry=0x70600021,is_hardware_canvas=is_hardware_canvas@entry=true, scroll=...,

global_visible_rect=...) at../../android_webview/browser/browser_view_renderer.cc:239

#2 0x6169858e in android_webview::AwContents::OnDraw(this=0x5a7627a0, env=<optimized out>, obj=<optimized out>,canvas=0x70600021,is_hardware_accelerated=1'\001', scroll_x=0, scroll_y=0, visible_left=0,

visible_top=220, visible_right=720, visible_bottom=1184) at../../android_webview/native/aw_contents.cc:1058

#3 0x4092bc50 in dvmPlatformInvoke () from/tmp/tshao-adb-gdb-libs/system/lib/libdvm.so

#4 0x4095bed2 in dvmCallJNIMethod(unsigned int const*, JValue*, Methodconst*, Thread*) () from /tmp/tshao-adb-gdb-libs/system/lib/libdvm.so

#5 0x4095d8be in dvmResolveNativeMethod(unsigned int const*, JValue*,Method const*, Thread*) () from/tmp/tshao-adb-gdb-libs/system/lib/libdvm.so

#6 0x40935064 in dvmJitToInterpNoChain () from/tmp/tshao-adb-gdb-libs/system/lib/libdvm.so

#7 0x40935064 in dvmJitToInterpNoChain () from/tmp/tshao-adb-gdb-libs/system/lib/libdvm.so





下面的逻辑可能不正确

应该是来自java层的,下面是UI线程。

native觉得网页内容有变化,会调用WebViewinvalidate函数,告知系统,然后系统会调用onDraw到我们的view,然后我们会注册一个DrawGL到系统,并请求系统在合适的时候调用DrawGL,从而触发并推动一次渲染流水线开始work.

WebView.onDraw

->WebViewChromium.onDraw

AwContents.java,onDraw(canvas)

-----------native 在下面---------------

awContents.cc,onDraw

->BrowserViewRenderer::OnDraw

->AwContents::requestDrawGL5.0新系统可能直接调用BrowserViewRenderer::OnDrawHardware来调用childcompositor合成一个compositorframe之后,才调用requestdraw gl

->Java_AwContents_requestDrawGL,

-----------------下面java------------------

AwContents.java,requestDrawGL

->WebViewNativeGLDelegate.requestDrawGL

->WebViewDelegateFactory.javacallDrawGlFunction/invokeDrawGlFunctor

nativeDrawGLFunctor注册进系统....并调用系统的drawGl.

这里是通过调用android.view.HardwareCanvas一个隐藏apicallDrawGLFunction方法,把我们的一个native的函数DrawGLFunctor传递进去给系统的。


注意,此时函数就会立即返回,并且能够返回一份canvas数据,这个canvas数据应该是之前的历史数据。

但同时,又向系统发送了一个请求绘制的申请。而系统会在合适的时候调用之前我们注册到系统里面的函数。

-------------------系统--------------下面是native---------

一定时间之后,系统调用我们注册的函数:注意,此时所处的线程和之前我们应用向系统发送绘制申请的线程是一个,都是ui线程。4.3上是这样的,但是androidL应该就是系统的render线程调用这个callback.


注:HardwareCanvas允许客户端提供自己的GL回调函数,Android View系统在重放(playback)显示列表绘制View层次时会调用这个回调函数,在AndroidFramework内部实现中,当开始绘制HardwareCanvas时,当前GL上下文会绑定HardwareCanvasframebuffer对象,所以GL回调函数中所有的GL命令实际上在操作HardwareCanvasframebuffer对象.那么在drawGl函数中,parentcompositor合成所有内容,并绘制到glcontext的话,就会绘制到framebuffer上。

->DrawGLFunctor::operator()

->draw_gl_normal, 系统提供了尺寸,clip等数据,还有mode.这个函数指针来自于WebViewChromiumFactoryProvider.java中的initPlatSupportLibrary()函数中的DrawGLFunctor.setChromiumAwDrawGLFunction(AwContents.getAwDrawGLFunction());。本质上来于AwContents.

->AwContents.cc中的DrawGLFunction()

->AwContents::DrawGL 该看这里了。

如果是4.4,4.3先调用BrowserViewRender::onDrawHardware,否则如果5.0就不需要再调用BrowserViewRender::onDrawHardware了,因为childcompositor的合成工作不再drawGL下执行。

创建HardwareRenderer,再调用HardwareRenderer::DrawGL.


注意,4.3/4.4上才会调用下面操作:

->BrowserViewRenderer::OnDrawHardware

->SynchronousCompositorImpl::DemandDrawHw

->SynchronousCompositorOutputSurface::DemandDrawHw

本函数除了调用下面的invokeComposite之外,还会返回一个compositorFrame,并把它设置到sharedRenderStatedrawgl input里面。返回的这个frame应该是之前弄好的。并且来自于:voidSynchronousCompositorOutputSurface::SwapBuffers(frame)中的frame.



->:SynchronousCompositorOutputSurface::InvokeComposite

->cc::LayerTreeHostImpl::BeginFrame

->cc::Scheduler::BeginFrame

->cc::Scheduler::BeginImplFrame

推动statemachine

->cc::Scheduler::ProcessScheduledActions

->cc::ThreadProxy::ScheduledActionSendBeginMainFrame//这里schedule一个task,要求beginFrame,要求内核要开始绘制。当然是要把请求发给另外的线程。应该是webcore线程。




下面callstack4.3/4.4上执行drawGL时,顺带执行了childconmpositor的合成并触发webcore线程的BeginFramecallstack:


#0 cc::ThreadProxy::ScheduledActionSendBeginMainFrame(this=0x641def38) at ../../cc/trees/thread_proxy.cc:691

#1 0x6078da14 in cc::Scheduler::ProcessScheduledActions(this=this@entry=0x64993cb8) at ../../cc/scheduler/scheduler.cc:665

#2 0x6078df92 in cc::Scheduler::BeginImplFrame(this=this@entry=0x64993cb8, args=...) at../../cc/scheduler/scheduler.cc:520

#3 0x6078e304 in cc::Scheduler::BeginFrame(this=0x64993cb8, args=...) at ../../cc/scheduler/scheduler.cc:426

#4 0x6079795e in cc::LayerTreeHostImpl::BeginFrame(this=<optimized out>, args=...) at../../cc/trees/layer_tree_host_impl.cc:1408

#5 0x60b97c16 incontent::SynchronousCompositorOutputSurface::InvokeComposite(this=this@entry=0x642f4868, transform=..., viewport=..., clip=...,viewport_rect_for_tile_priority=...,

transform_for_tile_priority=..., hardware_draw=<optimizedout>, hardware_draw@entry=true) at../../content/browser/android/in_process/synchronous_compositor_output_surface.cc:227

#6 0x60b97e5e incontent::SynchronousCompositorOutputSurface::DemandDrawHw(this=0x642f4868, surface_size=..., transform=..., viewport=...,clip=..., viewport_rect_for_tile_priority=...,

transform_for_tile_priority=...) at../../content/browser/android/in_process/synchronous_compositor_output_surface.cc:178

#7 0x60b977b0 in content::SynchronousCompositorImpl::DemandDrawHw(this=0x6498e6c0, surface_size=..., transform=..., viewport=...,clip=..., viewport_rect_for_tile_priority=...,transform_for_tile_priority=...)

at../../content/browser/android/in_process/synchronous_compositor_impl.cc:139

#8 0x607f6cf0 inandroid_webview::BrowserViewRenderer::OnDrawHardware(this=this@entry=0x6498e540) at../../android_webview/browser/browser_view_renderer.cc:304

#9 0x60e5a5f8 in android_webview::AwContents::DrawGL(this=0x6498e458, draw_info=0xbec91240) at../../android_webview/native/aw_contents.cc:429

#10 0x60f5e816 indraw_gl_normal (this=0x641ffeb0,data=<optimized out>,




那么BeginFrame发送给了谁?谁处理?干设么事情?





5.0上调试到的callstacki:

可以看出,5.0上的callstack就较为清晰:ui线程的onDraw会发送一个请求beginFrame的操作。


#0 cc::ThreadProxy::ScheduledActionSendBeginMainFrame(this=0x94fa71c0) at../../cc/trees/thread_proxy.cc:691 //这里发送一个请求beginMainFrame

#1 0x9d226b3c in cc::Scheduler::ProcessScheduledActions(this=this@entry=0x98aec880) at ../../cc/scheduler/scheduler.cc:665

#2 0x9d2270ba in cc::Scheduler::BeginImplFrame(this=this@entry=0x98aec880, args=...) at../../cc/scheduler/scheduler.cc:520

#3 0x9d22742c in cc::Scheduler::BeginFrame(this=0x98aec880, args=...) at ../../cc/scheduler/scheduler.cc:426

#4 0x9d230a86 in cc::LayerTreeHostImpl::BeginFrame(this=<optimized out>, args=...) at../../cc/trees/layer_tree_host_impl.cc:1408

#5 0x9d630eee incontent::SynchronousCompositorOutputSurface::InvokeComposite(this=this@entry=0x94fa7700, transform=..., viewport=..., clip=...,viewport_rect_for_tile_priority=...,

transform_for_tile_priority=..., hardware_draw=<optimized out>,hardware_draw@entry=true) at../../content/browser/android/in_process/synchronous_compositor_output_surface.cc:227

#6 0x9d631136 incontent::SynchronousCompositorOutputSurface::DemandDrawHw(this=0x94fa7700, surface_size=..., transform=..., viewport=...,clip=..., viewport_rect_for_tile_priority=...,

transform_for_tile_priority=...) at../../content/browser/android/in_process/synchronous_compositor_output_surface.cc:178

#7 0x9d630a88 in content::SynchronousCompositorImpl::DemandDrawHw(this=0xa0319f60, surface_size=..., transform=..., viewport=...,clip=..., viewport_rect_for_tile_priority=...,transform_for_tile_priority=...)

at../../content/browser/android/in_process/synchronous_compositor_impl.cc:139

#8 0x9d290088 in android_webview::BrowserViewRenderer::OnDrawHardware(this=this@entry=0xaf2584e8,java_canvas=java_canvas@entry=0xbec49110) at../../android_webview/browser/browser_view_renderer.cc:374

#9 0x9d290194 in android_webview::BrowserViewRenderer::OnDraw(this=this@entry=0xaf2584e8,java_canvas=java_canvas@entry=0xbec49110,is_hardware_canvas=is_hardware_canvas@entry=true, scroll=...,

global_visible_rect=...) at../../android_webview/browser/browser_view_renderer.cc:241

#100x9d8f19ce in android_webview::AwContents::OnDraw(this=0xaf258400, env=<optimized out>, obj=<optimized out>,canvas=0xbec49110, is_hardware_accelerated=1 '\001', scroll_x=0,scroll_y=0, visible_left=0,

visible_top=330, visible_right=1080, visible_bottom=1776) at../../android_webview/native/aw_contents.cc:1058

#110xa09e527a in ?? ()

#120xa09e527a in ?? ()




那么5.0上的awContents.cc里面的DrawGL还会有人调用么?

会的,并且的确是本进程的系统给创建的render线程调用的,callstack:

#0 android_webview::AwContents::DrawGL(this=0xaf258400, draw_info=0xa1fffa58) at../../android_webview/native/aw_contents.cc:370

#1 0x9d9f7c4a in draw_gl_50(this=0xac3e0fa8, data=0x0, what=<optimized out>) at../../third_party/android_plat_support/draw_gl_functor.cpp:103

#2 android::(anonymous namespace)::DrawGLFunctor::operator()(this=0xac3e0fa8, what=<optimized out>, data=0x0) at../../third_party/android_plat_support/draw_gl_functor.cpp:58

#3 0xb66dd5c0 in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#4 0xb66de53e in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#5 0xb66de618 in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#6 0xb66de54a in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#7 0xb66de618 in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#8 0xb66de54a in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#9 0xb66de618 in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#100xb66de54a in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#110xb66de618 in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#120xb66de54a in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#130xb66de618 in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#140xb66de54a in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#150xb66de618 in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#160xb66de54a in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#170xb66de618 in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#180xb66de54a in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#190xb66de618 in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#200xb66de54a in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#210xb66de618 in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#220xb66de54a in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#230xb66de58e inandroid::uirenderer::RenderNode::prepareTree(android::uirenderer::TreeInfo&)() from /tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#240xb6e47bb4 in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libandroid_runtime.so

#250xb66e6ace in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#260xb66e76ac in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#270xb66e7738 in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#280xb66e927c inandroid::uirenderer::renderthread::RenderThread::threadLoop()() from /tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#290xb6c9f4d6 in android::Thread::_threadLoop(void*) () from/tmp/tshao-adb-gdb-libs/system/lib/libutils.so

#300xb6e29f4e in android::AndroidRuntime::javaThreadShell(void*) () from/tmp/tshao-adb-gdb-libs/system/lib/libandroid_runtime.so

#310xb6c9f046 in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libutils.so

#320xb6ee42e4 in __pthread_start(void*) () from/tmp/tshao-adb-gdb-libs/system/lib/libc.so

#330xb6ee22d4 in __start_thread () from/tmp/tshao-adb-gdb-libs/system/lib/libc.so

#340x00000000 in ?? ()


这个又是怎么注册到5.0里面的,并且他干了什么?

Requestdrawglcallstack:

这此之所以要requestdrawgl是因为ui线程在onDraw时,要创建gpumem buffer, 于是就创建了一个task,inprocess command buffer里面queue了一个task,并申请drawgl操作。queue的操作是voidGpuControlService::RegisterGpuMemoryBuffer(

下面是发起requestDrawGL的一个场景:


#0 android_webview::AwContents::RequestDrawGL(this=0xaf258400, canvas=0x0, wait_for_completion=false) at../../android_webview/native/aw_contents.cc:797

#1 0x9d2984f4 inandroid_webview::SharedRendererState::ClientRequestDrawGLOnUIThread(this=this@entry=0xaf25843c) at../../android_webview/browser/shared_renderer_state.cc:142

#2 0x9d2985ec inandroid_webview::SharedRendererState::ClientRequestDrawGL(this=0xaf25843c) at../../android_webview/browser/shared_renderer_state.cc:113

#3 0x9d2910ea inandroid_webview::DeferredGpuCommandService::RequestProcessGL() at../../android_webview/browser/deferred_gpu_command_service.cc:79

#4 0x9d29150c inandroid_webview::DeferredGpuCommandService::ScheduleTask(base::Callback<void()> const&) (this=0xa03c5ee0, task=...) at../../android_webview/browser/deferred_gpu_command_service.cc:105

#5 0x9e01f328 in QueueTask(task=..., this=0x94efe740) at../../gpu/command_buffer/service/in_process_command_buffer.h:177

#6 gpu::InProcessCommandBuffer::CreateGpuMemoryBuffer(this=0x94efe740, width=384, height=384, internalformat=32856,usage=30961, id=0xbec48884)

at../../gpu/command_buffer/service/in_process_command_buffer.cc:731//要创建gpucommand buffer,并把taskqueue到队列里面等待renderthread去处理和gl相关的操作。


#7 0x9d47d910 in gpu::gles2::GpuMemoryBufferTracker::CreateBuffer(this=0x96497ad8, width=width@entry=384,height=height@entry=384, internalformat=internalformat@entry=32856,usage=usage@entry=30961)

at ../../gpu/command_buffer/client/gpu_memory_buffer_tracker.cc:31

#8 0x9d47634e ingpu::gles2::GLES2Implementation::CreateImageCHROMIUMHelper(this=0x98aac200, width=384, height=384, internalformat=32856,usage=30961)

at ../../gpu/command_buffer/client/gles2_implementation.cc:4013

#9 0x9d218f1a in cc::ResourceProvider::AcquireImage(this=this@entry=0xa22d1e80, resource=resource@entry=0x96468908) at../../cc/resources/resource_provider.cc:2162

#100x9d21a1e8 in cc::ResourceProvider::MapImageRasterBuffer(this=0xa22d1e80, id=<optimized out>) at../../cc/resources/resource_provider.cc:1776

#110x9d2200fa in cc::(anonymousnamespace)::RasterTaskImpl::ScheduleOnOriginThread (this=0xac384970,client=<optimized out>) at../../cc/resources/tile_manager.cc:77

#120x9d217444 in cc::RasterWorkerPool::ScheduleTasksOnOriginThread(client=client@entry=0x956b5fa8, graph=graph@entry=0x956b5fd4) at../../cc/resources/raster_worker_pool.cc:238

#130x9d20b83e in cc::ImageRasterWorkerPool::ScheduleTasks(this=0x956b5fa0, queue=0x98aecb2c) at../../cc/resources/image_raster_worker_pool.cc:113

#140x9d2236c8 in cc::TileManager::ScheduleTasks (this=0x98aeca00,tiles_that_need_to_be_rasterized=...) at../../cc/resources/tile_manager.cc:963

#150x9d22301c in cc::TileManager::ManageTiles (this=0x98aeca00,state=...) at ../../cc/resources/tile_manager.cc:662

#160x9d230dfe in cc::LayerTreeHostImpl::ManageTiles (this=0x964f1e00) at../../cc/trees/layer_tree_host_impl.cc:431

#170x9d23bf8e in cc::ThreadProxy::ScheduledActionManageTiles(this=0x94fa71c0) at ../../cc/trees/thread_proxy.cc:1165

#180x9d226b3c in cc::Scheduler::ProcessScheduledActions(this=this@entry=0x98aec880) at ../../cc/scheduler/scheduler.cc:665

#190x9d226e70 in cc::Scheduler::OnBeginImplFrameDeadline(this=this@entry=0x98aec880) at ../../cc/scheduler/scheduler.cc:584

#200x9d226eb0 in cc::Scheduler::ScheduleBeginImplFrameDeadline(this=this@entry=0x98aec880, deadline=...) at../../cc/scheduler/scheduler.cc:559

#210x9d2270dc in cc::Scheduler::BeginImplFrame(this=this@entry=0x98aec880, args=...) at../../cc/scheduler/scheduler.cc:524

#220x9d22742c in cc::Scheduler::BeginFrame(this=0x98aec880, args=...) at ../../cc/scheduler/scheduler.cc:426

#230x9d230a86 in cc::LayerTreeHostImpl::BeginFrame(this=<optimized out>, args=...) at../../cc/trees/layer_tree_host_impl.cc:1408

#240x9d630eee incontent::SynchronousCompositorOutputSurface::InvokeComposite(this=this@entry=0x94fa7700, transform=..., viewport=..., clip=...,viewport_rect_for_tile_priority=...,

transform_for_tile_priority=..., hardware_draw=<optimized out>,hardware_draw@entry=true) at../../content/browser/android/in_process/synchronous_compositor_output_surface.cc:227

#250x9d631136 incontent::SynchronousCompositorOutputSurface::DemandDrawHw(this=0x94fa7700, surface_size=..., transform=...,viewport=..., clip=..., viewport_rect_for_tile_priority=...,

transform_for_tile_priority=...) at../../content/browser/android/in_process/synchronous_compositor_output_surface.cc:178

#260x9d630a88 in content::SynchronousCompositorImpl::DemandDrawHw(this=0xa0319f60, surface_size=..., transform=..., viewport=...,clip=..., viewport_rect_for_tile_priority=...,transform_for_tile_priority=...)

at../../content/browser/android/in_process/synchronous_compositor_impl.cc:139

#270x9d290088 in android_webview::BrowserViewRenderer::OnDrawHardware(this=this@entry=0xaf2584e8,java_canvas=java_canvas@entry=0xbec49110) at../../android_webview/browser/browser_view_renderer.cc:374

#280x9d290194 in android_webview::BrowserViewRenderer::OnDraw(this=this@entry=0xaf2584e8,java_canvas=java_canvas@entry=0xbec49110,is_hardware_canvas=is_hardware_canvas@entry=true, scroll=...,

global_visible_rect=...) at../../android_webview/browser/browser_view_renderer.cc:241

#290x9d8f19ce in android_webview::AwContents::OnDraw(this=0xaf258400, env=<optimized out>, obj=<optimized out>,canvas=0xbec49110, is_hardware_accelerated=1 '\001', scroll_x=0,scroll_y=0, visible_left=0,

visible_top=330, visible_right=1080, visible_bottom=1776) at../../android_webview/native/aw_contents.cc:1058

#300xa09e527a in ?? ()

#310xa09e527a in ?? ()



那么我们看看voidGpuControlService::RegisterGpuMemoryBuffer(这个操作是不是就是在renderthread上执行的?

的确,马上被renderthread执行了:

下面是DrawGL被调用并执行任务的一个场景:

#0 gpu::GpuControlService::RegisterGpuMemoryBuffer(this=0x95678f40, id=7, buffer=..., width=384, height=384,internalformat=32856) at../../gpu/command_buffer/service/gpu_control_service.cc:39

#1 0x9e01c1ac in Run (a5=@0x956ffdc0: 32856, a4=@0x956ffdbc: 384,a3=@0x956ffdb8: 384, a2=..., a1=@0x956ffd94: 7, object=<optimizedout>, this=0xa1fffaf8) at ../../base/bind_internal.h:452

#2 MakeItSo (a6=@0x956ffdc0: 32856, a5=@0x956ffdbc: 384,a4=@0x956ffdb8: 384, a3=..., a2=@0x956ffd94: 7, a1=<optimizedout>, runnable=...) at ../../base/bind_internal.h:1028

#3 base::internal::Invoker<6,base::internal::BindState<base::internal::RunnableAdapter<void(gpu::GpuControlService::*)(int, gfx::GpuMemoryBufferHandle, unsignedint, unsigned int, unsigned int)>, void (gpu::Gpu

ControlService*,int, gfx::GpuMemoryBufferHandle, unsigned int, unsigned int, unsignedint), void(base::internal::UnretainedWrapper<gpu::GpuControlService>,int, gfx::GpuMemoryBufferHandle, unsigned int, unsigned

int, unsigned int)>, void (gpu::GpuControlService*, int,gfx::GpuMemoryBufferHandle, unsigned int, unsigned int, unsignedint)>::Run(base::internal::BindStateBase*) (base=0x956ffd80)

at ../../base/bind_internal.h:2126

#4 0x9d291334 in Run (this=0xa1fffb20) at ../../base/callback.h:401

#5 android_webview::DeferredGpuCommandService::RunTasks(this=0xa03c5ee0) at../../android_webview/browser/deferred_gpu_command_service.cc:182

#6 0x9d29138a in android_webview::ScopedAllowGL::ScopedAllowGL

//在这个变量构造后,设置了全局flag后才允许执行gl操作。

(this=0xa1fffb5c)at ../../android_webview/browser/deferred_gpu_command_service.cc:34

#7 0x9d8f3a9e in android_webview::AwContents::DrawGL(this=0xaf258400, draw_info=0xa1fffc28) at../../android_webview/native/aw_contents.cc:390

#8 0x9d9f7c4a in draw_gl_50 (this=0xac3e0fa8, data=0x0, what=<optimizedout>) at../../third_party/android_plat_support/draw_gl_functor.cpp:103

#9 android::(anonymous namespace)::DrawGLFunctor::operator()(this=0xac3e0fa8, what=<optimized out>, data=0x0) at../../third_party/android_plat_support/draw_gl_functor.cpp:58

#100xb66e01ea in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#110xb66e695e in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#120xb66e7f68 in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#130xb66e7ea6 in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#140xb66e927c inandroid::uirenderer::renderthread::RenderThread::threadLoop()() from /tmp/tshao-adb-gdb-libs/system/lib/libhwui.so

#150xb6c9f4d6 in android::Thread::_threadLoop(void*) () from/tmp/tshao-adb-gdb-libs/system/lib/libutils.so

#160xb6e29f4e in android::AndroidRuntime::javaThreadShell(void*) () from/tmp/tshao-adb-gdb-libs/system/lib/libandroid_runtime.so

#170xb6c9f046 in ?? () from/tmp/tshao-adb-gdb-libs/system/lib/libutils.so

#180xb6ee42e4 in __pthread_start(void*) () from/tmp/tshao-adb-gdb-libs/system/lib/libc.so

#190xb6ee22d4 in __start_thread () from/tmp/tshao-adb-gdb-libs/system/lib/libc.so

#200x00000000 in ?? ()


那么既然我们由此可以看出,ui线程,或者别的线程,需要gl操作时,都会requestdrawgl,并把任务queue到一个task里面,然后系统的render线程会调用我们注册的drawGl函数从执行相关gl操作。


那么我们再看看beginFrame的实际操作是在哪里执行的?

#0 cc::ThreadProxy::BeginMainFrame(this=0x94fa71c0, begin_main_frame_state=...) at../../cc/trees/thread_proxy.cc:720

#1 0x9d23f606 in Run (a1=..., object=<optimized out>,this=0x9ac01ab8) at ../../base/bind_internal.h:190

#2 base::internal::InvokeHelper<true, void,base::internal::RunnableAdapter<void(cc::ThreadProxy::*)(scoped_ptr<cc::ThreadProxy::BeginMainFrameAndCommitState,base::DefaultDeleter<cc::ThreadProxy::BeginMainFrame

AndCommitState>>)>, void (base::WeakPtr<cc::ThreadProxy> const&,scoped_ptr<cc::ThreadProxy::BeginMainFrameAndCommitState,base::DefaultDeleter<cc::ThreadProxy::BeginMainFrameAndCommitState>>)>::MakeItSo(base::i

nternal::RunnableAdapter<void(cc::ThreadProxy::*)(scoped_ptr<cc::ThreadProxy::BeginMainFrameAndCommitState,base::DefaultDeleter<cc::ThreadProxy::BeginMainFrameAndCommitState>>)>, base::WeakPtr<cc::ThreadProxy>

const&,scoped_ptr<cc::ThreadProxy::BeginMainFrameAndCommitState,base::DefaultDeleter<cc::ThreadProxy::BeginMainFrameAndCommitState>>) (runnable=..., weak_ptr=..., a2=...) at../../base/bind_internal.h:909

#3 0x9d23f6be in base::internal::Invoker<2,base::internal::BindState<base::internal::RunnableAdapter<void(cc::ThreadProxy::*)(scoped_ptr<cc::ThreadProxy::BeginMainFrameAndCommitState,base::DefaultDeleter<cc::T

hreadProxy::BeginMainFrameAndCommitState>>)>, void (cc::ThreadProxy*,scoped_ptr<cc::ThreadProxy::BeginMainFrameAndCommitState,base::DefaultDeleter<cc::ThreadProxy::BeginMainFrameAndCommitState>>), void (base::

WeakPtr<cc::ThreadProxy>,base::internal::PassedWrapper<scoped_ptr<cc::ThreadProxy::BeginMainFrameAndCommitState,base::DefaultDeleter<cc::ThreadProxy::BeginMainFrameAndCommitState>> >)>, void (cc::ThreadProxy*,

scoped_ptr<cc::ThreadProxy::BeginMainFrameAndCommitState,base::DefaultDeleter<cc::ThreadProxy::BeginMainFrameAndCommitState>>)>::Run(base::internal::BindStateBase*) (base=0x956653e0)

at ../../base/bind_internal.h:1253

#4 0x9daa7810 in Run (this=0x9ac01cb0) at ../../base/callback.h:401

#5 base::MessageLoop::RunTask (this=this@entry=0xa206f280,pending_task=...) at ../../base/message_loop/message_loop.cc:464

#6 0x9daa78c8 in base::MessageLoop::DeferOrRunPendingTask(this=this@entry=0xa206f280, pending_task=...) at../../base/message_loop/message_loop.cc:482

#7 0x9daa7fde in base::MessageLoop::DoWork (this=0xa206f280) at../../base/message_loop/message_loop.cc:596

#8 0x9daa852e in base::MessagePumpDefault::Run (this=0x96286028,delegate=0xa206f280) at../../base/message_loop/message_pump_default.cc:32

#9 0x9daa7c02 in base::MessageLoop::RunHandler (this=0xa206f280) at../../base/message_loop/message_loop.cc:407

#100x9daaf1a0 in base::RunLoop::Run (this=this@entry=0x9ac01d20) at../../base/run_loop.cc:49

#110x9daa7214 in base::MessageLoop::Run (this=<optimized out>) at../../base/message_loop/message_loop.cc:300

#120x9dab7cfe in base::Thread::ThreadMain(this=0xa22ceab0) at ../../base/threading/thread.cc:225 //这个是webcore主线程。

#130x9dab5b26 in base::(anonymous namespace)::ThreadFunc(params=<optimized out>) at../../base/threading/platform_thread_posix.cc:80

#140xb6ee42e4 in __pthread_start(void*) () from/tmp/tshao-adb-gdb-libs/system/lib/libc.so

#150xb6ee22d4 in __start_thread () from/tmp/tshao-adb-gdb-libs/system/lib/libc.so

#160x00000000 in ?? ()



至此,我们在5.0上分明看到了3个线程,

ui线程响应onDraw,会调用childcompositor合成一个compositorframe.并会向webcore主线程发送申请beginMainFramerwebcore启动一个paint.并可能会requestDrawGL,发送任务到队列,申请系统的renderer线程执行drawGL任务。

系统的renderer线程会调用DrawGL执行gl任务。主要包括执行一些deferredtasks以及调用parentcompositor来完成合成。

Webcore主线程会执行beginFrame的实际操作。也就是paint自己的layers.paint完成之后要commitimpl线程,也就是childcompositor所在的ui线程里。供ui线程合成使用。



问题:

1.系统renderer线程绘制的结果如何下一步处理?

render线程执行操作时,已经绑定了framebuffer,所以绘制结果因该被系统使用了。

2.compositeframe是谁生成的,何时生成的,如何使用干什么的?

childcompositor生成的,也就是browserViewRender调用的synchronousCOmpositor完成合成工作。是ui线程上的,用于合成网页内容。

3.beginFrame绘制的结果如何下一步被使用的。

Webcore线程beginframe绘制的结果应该要被commitui线程/impl线程供合成使用。

4.最终的画面是如何合成和显示的?

最终的画面应该是renderer线程中的parentcompositor合成并绘制到framebuffer上的。供系统处理的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值