blink渲染知识16 - raster干了什么

我们知道,在childcompositor里,implthread里,pendingtree被raster之后,才会被activate成activetree. 而且raster任务由一些rasterthread执行,那么这些raster操作干了什么?

看看这篇chromium的官方英文文章:

https://www.chromium.org/developers/design-documents/impl-side-painting

引入了impl-sidepainting之后,raster操作从webcore线程挪到了impl线程,impl线程安排rastertask让rasterthread去真正执行。webcore线程绘制到skpicture里面。里面都是displaylist. 并且划分了picturepile,针对一个layer,划分成多个tile,每个tile有不同的位置,优先级,还有不同的resolution.impl线程针对tile排序,产生rastertask让raster线程去操作。

绘制的结果产生texture,通过sharedmemory供给gpumemory.

impl 线程合成时,根据resourceid, (textureid)来检查该tile对应texture是否已经在gpu中了,而后可以合成。



1.30.1 Multithreaded Rasterization





Implementationstatus:

crbug.com/169282,andhttps://code.google.com/p/chromium/issues/list?q=label:Cr-Internals-Compositing-Rasterization

Thisfeature is referred to as "multithreaded painting" and"impl-side painting" in some forums.

Background& Problem Statement
Ourcurrent compositor thread architecture is built around the ideaof rasterizing layers on the main webkit thread and then, on thecompositor thread, drawing the bits of the layers that we havebased on their various animated and scrolled positions. Thisallows us to move the page up and down, e.g. due to fingerdragging, without having to block on the webkit thread. When atile is exposed that does not have contents, we draw acheckerboard and wait for the main thread to rasterize thattile.

    1. Wewant to be able to fill in checkerboards without requiring anew commit, since that requires going to a busy webkitthread and pulling in a whole new tree + damage. We also wantto be able to render tiles at multiple resolutions, andquality levels. These kinds of tricks reduce memory pressure,avoid the jarring interruption of checkerboards.

TheExcessive Checkerboarding Problem

A lot of our unwanted checkerboarding comes from invalidatesgetting intermixed with "requests" from the implthread to fill in missing tiles. In the current architecture, wecan only rasterize tiles on the main thread, using webkit'srendering data structures. If webkit's rendering tree iscompletely unchanged, then the page scrolls, all therasterization requests that go to the main thread are easilysatisifed by webkit.

However, any time javascript changes the rendering tree, we havethe following problem: we have some "newly exposed tiles"that the compositor thread needs to prevent checkerboarding.But, annoyingly, any of the previously-painted tiles that webkitsays were invalidated. We can only paint the new rendering tree-- the old rendering tree is gone. So, we have two options atthis point:

1.Draw the new tiles with the new rendering tree, and redraw theold tiles with the new rendering tree

2.Draw only the new tiles, and let the old tiles stick around.


#2doesn't work well at all, of course: if you have a page thattoggles between green and blue constantly, what you'd see is arandom mix of green and blue page at any given moment. We wantto preserve the "atomicity of rendering" --- meaningthat the complete state of a web page at rAF time is what getsput on the screen.


Thereis a variant on 2 where we draw the new tiles, as well as anyold tiles that are *onscreen*. If a tile is offscreen, then wemake a note that is is invalid, but dont repaint it. In thegreen-blue scenario, this causes the screen to be green or blue,but never both, as long as you dont scroll. We ship thison Chrome Android m18. Even so, this is undesirable: if youscroll, you'll see a mix of content. This is expedientperformance wise, but makes us all feel dirty.



Our other source of heavy checkerboarding is latency related.The work we do on the main thread is based on as scroll positionupdate message that comes from the impl thread. This message isitself not very latent, arriving on the main thread millisecondsafter it is sent. However, paints for a new set of tiles cantake 300ms + to complete, even with the relaxed atomicityapproach described above. By the time we have painted all 300msworth of work, the page has scrolled way past the originalscroll position, and half of the tiles we worked hard to prepareare irrelevant. We have discussed a variety of solutions here,but the real core problem is that the main thread cannot beupdated fast enough with the new scroll positions to really everkeep up properly.



Planned Solution

Displaylists. Namely, SkPictures,modified a bit to support partial updating. We call this aPicturepile,a name borrowed from the awesome folks behind Android Browser.Theidea is to only capture a display list of the webkit renderingtree on the main thread. Then, do rasterization on the implthread, which is much more responsive.

Onmain thread, web content is turned into PictureLayers. Picturelayers make a recording of the layer into a PicturePile.We track invalidations in SkRegions and during the display listcapture process, decide between re-capturing the entire layer orjust grabbing the invalidated area and drawing it on-top of thepreviously recorded base layer.

Duringcommit, we pass these PicturePiles to aPictureLayerImpl. Recall,layers can change in scale over time, under animation, pinchzoom, etc. To handle this, a PictureLayerImpl manages one ormore PictureLayerTiling objects (via a PictureLayerTilingSet),which is a decomposition of the layer's entire contents intotiles at a picture screenspace resolution. So for example, a512x512 layer might have a tiling into 4 256x256 tiles for a 1:1ratio of screenspace pixels to content pixels, but also 1256x256 tile for a 1:2 ratio of screenspace to conten space.We manage these tilings dyanmically.

一个layer可能被分成不同scale级别的tile.



A tiling itself takes thelayers entire size, not just the visible part, and breaks it upinto Tiles. Each tile represents a rectangle of the PicturePilepainted into a Resource ID [think, GL texture], at a givenresolution and quality setting.

Everytile is given a set of TilePriority values by thePictureLayerImpl based on its screen space position, animationand scroll velocity, and picture contents. Thesedifferent priorities encode how soon, in time units, the tilecould be visually useful onscreen. Key metrics are things like"how soon will it be visible" and "how soon willit be crisp" and "is this a tile we'd use if a crispone wasn't available?"


TheseTiles are registered to the TileManager, which keeps these tilessorted based on their priority and some global priority states.Tiles are binned in orders of urgency (needed now, needed in thenext second, needed eventually, never going to be needed) andthen sorted within their bin.The total GPU Memory budget is then assigned in decreasingpriority order to these tiles. Tiles that are given permissionto use memory are then added to a rasterization queue if needed.

tile都有优先级排序,根据优先级决定是否给一个tile分配gpumemory.


Theraster thread scheduler is a very simple solution: on the implthread, we simply pop from the raster queue, dispatch the rastertask. We keep a certain number of jobs enqueued per thread,opting to not enqueue them all so that if the prioritizationchanges much in the future, we wont do redundant work.


JPEG/PNG/etcbitmaps are stored in the display lists in still-encoded (notdecoded)formto keep display list recording cost low and memory footprintsmall. Thus, the first time we draw a bitmap, a costly decodeand downsample operation may be needed. Thus, before dispatch,tiles are "cracked open" to determine whether anybitmaps need to be decompressed, using the SkLazyPixelRefinterface to WebCore's ImageDecodingStore. If decoding isneeded, the tile is held in a side queue while a decoding taskis dispatched to the raster threads. When the decodes are done,raster tasks are enqueued. webcore线程并不decodejpeg图片,当rastertask发现有图片需要解码时,会将此task挪到另一queue里,等decode完成后才从新enqueue此task.

This approach fixes the “atomicity of commits” problem byallowing us to servie checkerboard misses without havin to go tothe laggy, potentially changed main thread. Inthe previous example, when the compositor sees a checkerboardedtile, we can rasterize it without having to start a commit flow,allowing us to disallow commits entirely during flings and otherheavy animation use cases.

当compositor线程发现一个tile没有内容显示时,可以触发raster工作,而不用让webcore线程去从新走一遍。这提高了效率,尤其当用户快速滚动时。

Hitch-free commits

A key challenge with thisapproach is switching from the old tree to the new tree. Inthe existingarchitecture, when we go to switch to the new tree, we havepainted and uploaded all the tiles, so the tree can beimmediately switched.

In the impl-side painting architecture, we need to createPictureLayerImpl's in order to begin rasterizing them. Moreover,those impls need to be attached together to theLayerTreeHostImpl in order to get their screenspace positions,which are essential in computing their priorities.



The obvious way to do this is to simply commit the main treeto the impl tree like we usually do. However, if we do that,then the impl tree now has holes in it where there wereinvalidations. At this point, the impl-side has two options whenvsync comes around: checkerboard, or drop the frame. Neither isvery cool.



Our solution is the LayerTreeImpl. Whereas the previousarchitecture's LayerTreeHostImpl had a root layer and all itsassociated state, we instead introduce LayerTreeImpl, which hasall the state associated with a layer tree: scrolling info,viewport, background color, etc. The LTHI then stores not one,but two LayerTreeImpl's: theactive tree is the one we are drawing, while the pending tree isthe one we are rasterizing. Priorityis given to the active tree, but once the pending tree is fullypainted, we activate it and throw away the old one. This allowsus to switch between old and new trees without janking.

我们在activetree上合成,在pendingtree上raster,当pendingtree raster完成,就替换成activetree.这样提高了合成速度。

Handling GiantSkPictures

Onepotential challenge to impl-side painting compared to ourexisting painting model is that the SkPicture for a given layerare potentially unbounded. We plan to mitigate this by limitingthe PicturePile's size to a 10,000px (emperically determined)portion of the total layer size cenetered around the viewport atthe time of the picture pile's first creation. When the implthread starts needing tiles outside the pile's area, we willasynchronously trigger the main thread to go update the pilearound the new viewport center.

Choosingthe scale at which to raster


Wheneverwe compute the draw properties for a PictureLayerImpl, we alsodecide what tilings it should have, or in other words, at whatscales it should have sets of tiles. To do this we track twoscale values: The ideal scale, and the raster scale. The idealscale is the scale at which we should create tiles to give thetexels in the tile a 1:1 correspondence with pixels on thescreen. The raster scale is the high-resolution scale at whichwe are currently creating tiles. When we set the raster scale tobe equal to the ideal scale, we get crisp tiles. This is whatwe'd like to have at all times, but we limit this forperformance reasons. During a pinch gesture, or an acceleratedanimation, the raster scale lags behind the ideal scale. CSS canchange the scale of a layer through the DOM, and we limit howoften it is allowed to change the raster scale. Thisdecision to reset the raster scale to the ideal or leave italone is made in PictureLayerImpl::ManageTilings.Whenever the raster scale changes, we add a tiling both at theraster scale, and at a low resolution related to the rasterscale. These tilings aremarked as HIGH_RESOLUTION and LOW_RESOLUTION and are givenpriority as we raster tiles for the layer.

rasterscale是在manageTilings里面设置的,当改动时,我们会创建高/低resolution的tile



Texture Upload

Onekey challenge on lowend devcies is that uploading a single256x256 texture can take many milliseconds, sometimes as crazyas 3-5ms. Because of this, we have to carefully throttleour texture uploads so that we dont drop a frame. To do this, weare adopting a new approach of async texture uploads. Instad ofissuing standard glTexImage calls, we instead place texturesinto shared memory and then instruct the GPU process to do theupload when-convenient. This enables the GPU process todo the upload during idle times, or even on another thread. Thecompositor then polls the GPU process via the queryinfrastructure to determine if the upload is complete. Only whenthe upload is complete will we draw with it.

Rasterthread并不把绘制完成的内容直接调用gltextImage提交给gpu,因为比较慢,而是把结果用sharedmemory共享给gpu线程,其实就是render线程。render线程会拿到raster结果,并提交到gpu.Compositor向gpu线程查询该资源是否已经被提交,如果已经提交就拿来合成。



HandlingsetPictureListener

Ifthe embedder has a picture listener, we need to send aserialized SkPicture to the embedding process. We would need to,at every impl-side swapbuffers, serialize our SkPictures for allthe active layers (plus the bitmaps) and send them to the mainthread.



FollowupWork

Theinitial impl-side painting implementation is expected to enablethe following followup use cases:

Low-restiles: Fortiles that take a long time to rasterize, we may want torasterize them at half or third resolution. This oftendramatically reduces (5-6x anecdotally) raster cost and allowsus to avoid checkerboarding during fling. However, it is worthnoting that some Android users criticized this behavior on ICSdevices as making fonts look too ugly. High-dpi devices maychange the UX impact of this behavior on users.



Just-in-timescaling: Wecurrently do resizing of content at many layers in the pipeline.For example, we rasterize layers at their content resolutionwithout consideration to their screenspace transform. Thus, alayer that is -webkit-transform: scale(0.5)’d will actuallypaint at its full size. Similarly, we resize images insidewebkit at their content resolution. We could reducerasterization/decode costs and memory footprint if we could doall of this scaling using the draw-time transforms on the implthread.


Acceleratedpainting: Aninteresting property of impl-side painting is that it cleans upour accelerated painting story. We would store the SkPicture fora layer, and then can decide to rasterize a layer with the GPUwithout having to involve the main thread at all in the process.








触发raster的callstack:

等待之后,在ThreadProxy::ScheduledActionCommit()函数中还会创建rastertask:

#0 cc::TileManager::ScheduleTasks(this=0xa1c0fc00,

//这里应该会为每个需要raster的tile创建一个rastertask 放入队列中。

tiles_that_need_to_be_rasterized=...) at../../cc/resources/tile_manager.cc:924

#1 0x9b7b301c in cc::TileManager::ManageTiles (this=0xa1c0fc00,state=...) at ../../cc/resources/tile_manager.cc:662

#2 0x9b7c0dfe in cc::LayerTreeHostImpl::ManageTiles(this=0x9e5f3600)

//这里调用tilemanger来处理managertiles

at ../../cc/trees/layer_tree_host_impl.cc:431

#3 0x9b7c53f2 in cc::LayerTreeHostImpl::CommitComplete(this=0x9e5f3600)

//commit完成。

at ../../cc/trees/layer_tree_host_impl.cc:346

#4 0x9b7ced86 in cc::ThreadProxy::ScheduledActionCommit(this=0x971cc1c0) at ../../cc/trees/thread_proxy.cc:1004

#5 0x9b7b6b3c in cc::Scheduler::ProcessScheduledActions





Raster task类:

class RasterTaskImpl : public RasterTask {定义在tile_manager.cc中。

而实际的raster操作都给了classCC_EXPORT PicturePileImpl : public PicturePileBase

先1.PicturePileImpl::AnalyzeInRect

后2.void PicturePileImpl::RasterToBitmap(



PicturePileImpl::AnalyzeInRect

->RasterForAnalysis()

->void PicturePileImpl::RasterCommon(

有一个PictureRegionMap,维护了一堆picture,下面调用picture的raster.

->int Picture::Raster(













那么,picturePileImpl中的picture哪里来的?

bool PicturePile::UpdateAndExpandInvalidation(

中会调用Picture::Create函数。

貌似是要invalidate,然后根据rects算出需要创建一些picture.

看看callstack:



#0 cc::PicturePile::UpdateAndExpandInvalidation

//每个pictureLayer有一个picturePile. 这个函数会针对这个picturePile建立一系列Picture对象。逻辑上会针对rect判断是否创建Picture。

这个函数的具体逻辑就是根据他的rect,计算出一堆invalid的或者说有变化的tile,其实也是子rect,这一堆tile就够成了invalidtiles. 然后把这些tile按照x,y坐标排序,也就是cluster操作,排完序后,针对每个tile建立一个picture.这些picture都存储到了picture_map_里面,这个map存储了PictureInfo

那么是否可以认为一个picturelayer 对应一个picturepile

(this=this@entry=0x94d96c00, painter=painter@entry=0x94d8e374,invalidation=invalidation@entry=0x94d1a880,background_color=background_color@entry=0,

contents_opaque=contents_opaque@entry=false,contents_fill_bounds_completely=contents_fill_bounds_completely@entry=false,visible_layer_rect=..., frame_number=frame_number@entry=2,

recording_mode=recording_mode@entry=cc::Picture::RECORD_NORMALLY,stats_instrumentation=0x96461300) at../../cc/resources/picture_pile.cc:159

#1 0x9d260696 in cc::PictureLayer::Update(this=0x94d1a600, queue=<optimized out>,occlusion=<optimized out>) at../../cc/layers/picture_layer.cc:139

#2 0x9d29e472 in cc::LayerTreeHost::PaintLayerContents(this=this@entry=0x9648a800, render_surface_layer_list=...,queue=queue@entry=0x94da28e0,did_paint_content=did_paint_content@entry=0x9a4c485e,

need_more_updates=need_more_updates@entry=0x9a4c485f) at../../cc/trees/layer_tree_host.cc:994

#3 0x9d29e858 in cc::LayerTreeHost::UpdateLayers(this=this@entry=0x9648a800, root_layer=0x9648ab00, queue=0x94da28e0)at ../../cc/trees/layer_tree_host.cc:830

#4 0x9d29ea96 in cc::LayerTreeHost::UpdateLayers(this=0x9648a800, queue=<optimized out>) at../../cc/trees/layer_tree_host.cc:696

#5 0x9d2b092e in cc::ThreadProxy::BeginMainFrame(this=0x94d861c0, begin_main_frame_state=...) at../../cc/trees/thread_proxy.cc:817

#6 0x9d2b1792 in Run (a1=..., object=<optimized out>,this=0x9a4c4ab8) at ../../base/bind_internal.h:190

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

#8 0x9d2b184a 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,

//webcore线程要paint所有layer

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

#9 0x9db19c48 in Run (this=0x9a4c4cb0) at../../base/callback.h:401

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

#11 0x9db19d00 in base::MessageLoop::DeferOrRunPendingTask(this=this@entry=0xafe34440, pending_task=...) at../../base/message_loop/message_loop.cc:482

#12 0x9db1a416 in base::MessageLoop::DoWork (this=0xafe34440) at../../base/message_loop/message_loop.cc:596

#13 0x9db1a966 in base::MessagePumpDefault::Run (this=0x94d8e4a8,delegate=0xafe34440) at../../base/message_loop/message_pump_default.cc:32

#14 0x9db1a03a in base::MessageLoop::RunHandler (this=0xafe34440)at ../../base/message_loop/message_loop.cc:407

#15 0x9db215d8 in base::RunLoop::Run (this=this@entry=0x9a4c4d20)at ../../base/run_loop.cc:49

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

#17 0x9db2a136 inbase::Thread::ThreadMain (this=0xa1fd4b50) at

//webcore线程

../../base/threading/thread.cc:225

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

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

#20 0xb6eb02d4 in __start_thread () from/tmp/tshao-adb-gdb-libs/system/lib/libc.so

#21 0x00000000 in ?? ()



还是需要看看webcore线程除了创建Picture还干了什么。

picture.cc中有raster和record函数,先看看Picture::Create干了什么:

Picture::Create

->1. new Picture(layer_rect)

  1. Picture::Record

    ->1. SkPictureRecorder::beginRecording

    1. 2. 拿到SkCanvas

    3. WebContentLayerImpl::PaintContents( SkCanvas* canvas,

    const gfx::Rect& clip,//这个cliprect就是要画的picture的rect.

    gfx::RectF* opaque,

    ContentLayerClient::GraphicsContextStatusgraphics_context_status)

    -->OpaqueRectTrackingContentLayerDelegate::paintContents

    //这里已经是webcore,Webkit的代码了。

    ->GraphicsLayer::paint(), Graphicslayer是OpaqueRectTrackingContentLayerDelegate的m_painter.

    ->GraphicsLayer::paintGraphicsLayerContents

    ->CompositedLayerMapping::paintContents

    ->CompositedLayerMapping::doPaintTask

    ->RenderLayer::paintLayerContents































tile分成很多类型,有优先级:

// Tile manager classifying tiles into a few basic bins:

enum ManagedTileBin {

NOW_AND_READY_TO_DRAW_BIN = 0, // Ready to draw and withinviewport.

NOW_BIN = 1, // Needed ASAP.

SOON_BIN = 2, // Impl-side version ofprepainting.

EVENTUALLY_AND_ACTIVE_BIN = 3, // Nice to have, and has a taskor resource.

EVENTUALLY_BIN = 4, // Nice to have, if we've gotmemory and time.

AT_LAST_AND_ACTIVE_BIN = 5, // Only do this after all otherbins.

AT_LAST_BIN = 6, // Only do this after all otherbins.

NEVER_BIN = 7, // Dont bother.

NUM_BINS = 8

// NOTE: Be sure to update ManagedTileBinAsValue andkBinPolicyMap when adding

// or reordering fields.

};



tile raster mode 和tile的priority都是怎么计算的?

Tile 的priority是分tree的:一个tile有一个数组存储priority:

TilePriority priority_[NUM_TREES];

每个priority实例存有一个prioritybin:

enum PriorityBin { NOW, SOON, EVENTUALLY };





enum WhichTree {

// Note: these must be 0 and 1 because we index with them invarious places,

// e.g. in Tile::priority_.

ACTIVE_TREE = 0,

PENDING_TREE = 1,

NUM_TREES = 2

// Be sure to update WhichTreeAsValue when adding new fields.

};



而tree也有treepriority:

enum TreePriority {

SAME_PRIORITY_FOR_BOTH_TREES,

SMOOTHNESS_TAKES_PRIORITY,

NEW_CONTENT_TAKES_PRIORITY







tile 的readyto draw如何评判?

bool ManagedTileState::TileVersion::IsReadyToDraw() const {

switch (mode_) {

case RESOURCE_MODE:

return !!resource_;

case SOLID_COLOR_MODE:

case PICTURE_PILE_MODE:

return true; //如果是solidcolor或者picturepile mode,直接返回true.

}

NOTREACHED();

return false;

}





一个tile的state里有rastermode:

enum RasterMode {

HIGH_QUALITY_RASTER_MODE = 0,

LOW_QUALITY_RASTER_MODE = 1,

NUM_RASTER_MODES = 2

};



针对每个rastemode有一个TileVersion.

每个tileVersion有一个mode:

enum Mode { RESOURCE_MODE, SOLID_COLOR_MODE, PICTURE_PILE_MODE };



所谓resource就是gpumemory.





仔细看看voidTileManager::ManageTiles干了什么?

→ 1. UpdatePrioritizedTileSetIfNeeded 根据设置的优先级获取指定优先级的tiles

  1. AssignGpuMemoryToTiles()这里并没有实际给上述得到的tiles分配gpumem, 成功分配了mem的tiles存储到tiles_that_need_to_be_rasterized里。而是根据resourcepool计算当前内存是否够分配,如果够,就更新数据量。而并没有实际分配。使用的resource_pool_是ResourcePool.

  2. ScheduleTasks(tiles_that_need_to_be_rasterized);为这些tile建立rastertask.

    每个tile都有picturepile,









ResourcePool:

这个resourcepool是在LayerTreeHostImpl::CreateAndSetTileManager()里面建立的。且使用zerocopy(是指不需要把raster的结果copy到gpu线程,而是采用sharedmem,直接raster到sharedmem上),建立ResourcePool时的target是GL_TEXTURE_EXTERNAL_OES。而分配resource时,会走到ResourceProvider::CreateManagedResource.

一个调用ResourcePool分配资源的callstack;

#0 cc::ResourceProvider::Resource::Resource (this=0xbe9afb00,texture_id=0, size=...,origin=cc::ResourceProvider::Resource::Internal, target=36197,filter=9729, texture_pool=24577, wrap_mode=33071,

hint=cc::ResourceProvider::TextureUsageAny,format=cc::RGBA_8888) at ../../cc/resources/resource_provider.cc:298

#1 0x9d52e3de in cc::ResourceProvider::CreateGLTexture(this=0x9a77fb60, size=..., target=<optimized out>,texture_pool=texture_pool@entry=24577,wrap_mode=wrap_mode@entry=33071,

hint=hint@entry=cc::ResourceProvider::TextureUsageAny,format=format@entry=cc::RGBA_8888) at../../cc/resources/resource_provider.cc:709

#2 0x9d52e59a in cc::ResourceProvider::CreateManagedResource(this=<optimized out>, size=..., target=<optimized out>,wrap_mode=wrap_mode@entry=33071,hint=hint@entry=cc::ResourceProvider::TextureUsageAny,

format=cc::RGBA_8888) at../../cc/resources/resource_provider.cc:677

#3 0x9d530376 in cc::ScopedResource::AllocateManaged(this=0x7f660da8, size=..., target=<optimized out>,format=<optimized out>) at../../cc/resources/scoped_resource.cc:45

#4 0x9d52b160 in cc::ResourcePool::AcquireResource(this=0x7f616eb0, size=...) at ../../cc/resources/resource_pool.cc:69

#5 0x9d536330 in cc::TileManager::CreateRasterTask(this=this@entry=0xa0f09080, tile=tile@entry=0x7f1813c0) at../../cc/resources/tile_manager.cc:990

#6 0x9d5366b2 in cc::TileManager::ScheduleTasks(this=0xa0f09080, tiles_that_need_to_be_rasterized=...) at../../cc/resources/tile_manager.cc:948

#7 0x9d53611c in cc::TileManager::ManageTiles(this=0xa0f09080, state=...) at../../cc/resources/tile_manager.cc:662

#8 0x9d543f28 in cc::LayerTreeHostImpl::ManageTiles(this=0x900b2b00) at ../../cc/trees/layer_tree_host_impl.cc:433

#9 0x9d548566 in cc::LayerTreeHostImpl::CommitComplete(this=0x900b2b00)

//commit完成,正准备要创建raster工作。

at ../../cc/trees/layer_tree_host_impl.cc:348

#10 0x9d551f12 in cc::ThreadProxy::ScheduledActionCommit(this=0x95d3ce00) at ../../cc/trees/thread_proxy.cc:1004

#11 0x9d539c3c in cc::Scheduler::ProcessScheduledActions(this=this@entry=0xa0370a00) at ../../cc/scheduler/scheduler.cc:665

#12 0x9d539dd6 in cc::Scheduler::NotifyReadyToCommit(this=0xa0370a00) at ../../cc/scheduler/scheduler.cc:220

#13 0x9d52fdc6 in cc::ResourceUpdateController::OnTimerFired(this=0x98470900) at../../cc/resources/resource_update_controller.cc:111

#14 0x9d52fa7a in Run (object=<optimized out>,this=0xbe9b00e0) at ../../base/bind_internal.h:134

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

#16 base::internal::Invoker<1,base::internal::BindState<base::internal::RunnableAdapter<void(cc::ResourceUpdateController::*)()>, void(cc::ResourceUpdateController*), void(base::WeakPtr<cc::ResourceUpdateContr

oller>)>, void(cc::ResourceUpdateController*)>::Run(base::internal::BindStateBase*)(base=0x7f660b38) at ../../base/bind_internal.h:1169

#17 0x9ddbac48 in Run (this=0xbe9b01f0) at../../base/callback.h:401

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

#19 0x9ddbad00 in base::MessageLoop::DeferOrRunPendingTask(this=this@entry=0xa031da20, pending_task=...) at../../base/message_loop/message_loop.cc:482

#20 0x9ddbb416 in base::MessageLoop::DoWork (this=0xa031da20) at../../base/message_loop/message_loop.cc:596

#21 0x9dd9e4f8 in DoRunLoopOnce (delayed_scheduled_time_ticks=0,native_delegate=<optimized out>, obj=0xbe9b028c,env=0xb4f51240) at ../../base/message_loop/message_pump_android.cc:35

#22Java_com_jetpack_dolphin_webkit_org_chromium_base_SystemMessageHandler_nativeDoRunLoopOnce(env=0xb4f51240, jcaller=0xbe9b028c,messagePumpDelegateNative=<optimized out>,delayedScheduledTimeTicks=0)

at gen/base/jni/SystemMessageHandler_jni.h:42

#23 0xa09ba6c8 in ?? ()

#24 0xa09ba6c8 in ?? ()







一个实际raster工作的callstack:

#0 SkPicture::draw(this=0x93559c60, surface=0x91b01a7c, callback=0x91b01b74) at../../third_party/skia/src/core/SkPicture.cpp:281

#1 0x9d520c58 in cc::Picture::Raster (this=this@entry=0x95ff5c50,canvas=canvas@entry=0x91b01a7c, callback=callback@entry=0x91b01b74,negated_content_region=..., contents_scale=contents_scale@entry=1)

at ../../cc/resources/picture.cc:411

#2 0x9d526a6c in cc::PicturePileImpl::RasterCommon(this=0x9a780380, canvas=0x91b01a7c, callback=0x91b01b74,canvas_rect=..., contents_scale=contents_scale@entry=1,

rendering_stats_instrumentation=rendering_stats_instrumentation@entry=0x95f8ba80,is_analysis=is_analysis@entry=true) at../../cc/resources/picture_pile_impl.cc:312

#3 0x9d526b26 in cc::PicturePileImpl::RasterForAnalysis(this=this@entry=0x9a780380, canvas=canvas@entry=0x91b01a7c,canvas_rect=..., contents_scale=contents_scale@entry=1,

stats_instrumentation=stats_instrumentation@entry=0x95f8ba80)at ../../cc/resources/picture_pile_impl.cc:93

#4 0x9d526ebe in cc::PicturePileImpl::AnalyzeInRect(this=this@entry=0x9a780380, content_rect=...,contents_scale=<optimized out>,analysis=analysis@entry=0x9000c72c, stats_instrumentation=0x95f8ba80)

at ../../cc/resources/picture_pile_impl.cc:381

#5 0x9d533dd4 in Analyze(picture_pile=0x9a780380, this=0x9000c710) at../../cc/resources/tile_manager.cc:112

#6 AnalyzeAndRaster(picture_pile=0x9a780380, this=0x9000c710) at../../cc/resources/tile_manager.cc:97

#7 cc::(anonymous namespace)::RasterTaskImpl::RunOnWorkerThread(this=0x9000c710) at ../../cc/resources/tile_manager.cc:70

#8 0x9d531742 in cc::TaskGraphRunner::RunTaskWithLockAcquired(this=this@entry=0x9ea4a0bc <cc::(anonymousnamespace)::g_task_graph_runner+4>) at../../cc/resources/task_graph_runner.cc:419

#9 0x9d53187a in cc::TaskGraphRunner::Run(this=0x9ea4a0bc <cc::(anonymousnamespace)::g_task_graph_runner+4>) at../../cc/resources/task_graph_runner.cc:362

#10 0x9ddcab80 in base::DelegateSimpleThread::Run(this=0x9652aa60) at ../../base/threading/simple_thread.cc:81

#11 0x9ddcad8c in base::SimpleThread::ThreadMain(this=0x9652aa60) at ../../base/threading/simple_thread.cc:60

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

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

#14 0xb6eb02d4 in __start_thread () from/tmp/tshao-adb-gdb-libs/system/lib/libc.so

#15 0x00000000 in ?? ()



在analysis阶段执行一些类似下面的逻辑:

有时候,analyze阶段就直接raster了。实际操作会调用到skPicture,SkPicturePlayback, 最终操作在skCanvas里面。

#0 SkCanvas::clipRect(this=0x91b01a7c, rect=...,

//canvas是skCanvas

op=SkRegion::kIntersect_Op, doAA=false) at../../third_party/skia/src/core/SkCanvas.cpp:1330

#1 0x9d3765ea in SkPicturePlayback::draw(this=0x7ee35900, canvas=..., callback=0x91b01b74) at../../third_party/skia/src/core/SkPicturePlayback.cpp:1033

#2 0x9d520c58 in cc::Picture::Raster(this=this@entry=0x95ff5c50, canvas=canvas@entry=0x91b01a7c,callback=callback@entry=0x91b01b74, negated_content_region=...,contents_scale=contents_scale@entry=1)

at ../../cc/resources/picture.cc:411

#3 0x9d526a6c in cc::PicturePileImpl::RasterCommon(this=0x9a780380, canvas=0x91b01a7c, callback=0x91b01b74,canvas_rect=..., contents_scale=contents_scale@entry=1,

#3 0x9d526a6c in cc::PicturePileImpl::RasterCommon(this=0x9a780380, canvas=0x91b01a7c, callback=0x91b01b74,canvas_rect=..., contents_scale=contents_scale@entry=1,

rendering_stats_instrumentation=rendering_stats_instrumentation@entry=0x95f8ba80,is_analysis=is_analysis@entry=true) at../../cc/resources/picture_pile_impl.cc:312

#4 0x9d526b26 in cc::PicturePileImpl::RasterForAnalysis(this=this@entry=0x9a780380, canvas=canvas@entry=0x91b01a7c,canvas_rect=..., contents_scale=contents_scale@entry=1,

stats_instrumentation=stats_instrumentation@entry=0x95f8ba80)at ../../cc/resources/picture_pile_impl.cc:93

#5 0x9d526ebe in cc::PicturePileImpl::AnalyzeInRect(this=this@entry=0x9a780380, content_rect=...,contents_scale=<optimized out>,analysis=analysis@entry=0x9000c72c, stats_instrumentation=0x95f8ba80)

at ../../cc/resources/picture_pile_impl.cc:381

#6 0x9d533dd4 in Analyze(picture_pile=0x9a780380, this=0x9000c710)

//此时在analyze阶段

at ../../cc/resources/tile_manager.cc:112

#7 AnalyzeAndRaster(picture_pile=0x9a780380, this=0x9000c710) at../../cc/resources/tile_manager.cc:97





可以跟踪一下skCanvas的drawColor看看skCanvas的使用情况:

#0 0x9d362b2a in CallBitmapXferProc (procData=<optimized out>,proc=<optimized out>, rect=..., bitmap=...) at../../third_party/skia/src/core/SkDraw.cpp:247

#1 SkDraw::drawPaint(this=0x91b019c0, paint=...) at../../third_party/skia/src/core/SkDraw.cpp:279

实际是先调用SkBitmapDevice::drawPaint,然后SkBitmapDevice::drawPaint会调用SkDraw::drawPaint.而且SkBitmapDevice都会关联一个SkBitmap.而这个bitmap就是作为backend.

#2 0x9d35d466 in SkCanvas::internalDrawPaint (this=0x935f8900,paint=...) at ../../third_party/skia/src/core/SkCanvas.cpp:1867

#3 0x9d35c7dc in SkCanvas::drawColor(this=0x935f8900, c=4294572537, mode=SkXfermode::kSrc_Mode) at../../third_party/skia/src/core/SkCanvas.cpp:2375

#4 0x9d526ce4 in cc::PicturePileImpl::RasterToBitmap(this=this@entry=0x7eee9e20, canvas=0x935f8900,canvas_rect=..., contents_scale=3,rendering_stats_instrumentation=0x9946f380)

at ../../cc/resources/picture_pile_impl.cc:148

#5 0x9d533f2a in Raster (picture_pile=0x7eee9e20,this=0x980e0160) at ../../cc/resources/tile_manager.cc:156

#6 AnalyzeAndRaster(picture_pile=0x7eee9e20, this=0x980e0160) at../../cc/resources/tile_manager.cc:102

#7 cc::(anonymous namespace)::RasterTaskImpl::RunOnWorkerThread(this=0x980e0160) at ../../cc/resources/tile_manager.cc:70

#8 0x9d531742 in cc::TaskGraphRunner::RunTaskWithLockAcquired(this=this@entry=0x9ea4a0bc <cc::(anonymousnamespace)::g_task_graph_runner+4>) at../../cc/resources/task_graph_runner.cc:419

#9 0x9d53187a in cc::TaskGraphRunner::Run (this=0x9ea4a0bc<cc::(anonymous namespace)::g_task_graph_runner+4>) at../../cc/resources/task_graph_runner.cc:362

#10 0x9ddcab80 in base::DelegateSimpleThread::Run(this=0x9652aa60) at ../../base/threading/simple_thread.cc:81

#11 0x9ddcad8c in base::SimpleThread::ThreadMain (this=0x9652aa60)at ../../base/threading/simple_thread.cc:60

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

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

#14 0xb6eb02d4 in __start_thread () from/tmp/tshao-adb-gdb-libs/system/lib/libc.so



研究一下skCanvas在raster中的作用。

SkCanvas可以向backend中绘制一个bitmap,那么我们需要看看backend是怎么创建的?究竟绘制到哪里了?继续往下跟。



void SkDraw::drawPaint(const SkPaint& paint) const {

->void SkScan::FillIRect(const SkIRect& r, const SkRegion*clip,

SkBlitter* blitter) {

->调用blitter的blitrect操作,blitter根据device的颜色模式,有多种blitter,我们使用的是:

SkBlitter* SkBlitter::Choose函数返回的blitter.是SkARGB32_Blitter。

->SkARGB32_Blitter::blitRect(x,y,width,height)

->SkBlitRow::ColorRect32

->Color32_arm_neon, 这个函数平台相关了,是SkBlitRow::ColorProc的proc.

->sk_memset32

->memset32_neon 汇编代码。位于memset32_neon.s









下面是一个raster线程在raster时选择blitter的callstacK:

#0 SkBlitter::Choose(device=..., matrix=..., origPaint=...,allocator=allocator@entry=0x96cff344,drawCoverage=drawCoverage@entry=false) at

选择blitter,在SkBlitter里面shader是空的,颜色模式是kN32_SkColorType:,并且建立的blitter是SkARGB32_Blitter。

../../third_party/skia/src/core/SkBlitter.cpp:854

#1 0x9cb52036 in SkAutoBlitterChoose::SkAutoBlitterChoose(this=0x96cff340, device=..., matrix=..., paint=...,drawCoverage=false) at ../../third_party/skia/src/core/SkDraw.cpp:50

#2 0x9cb52d7c in SkDraw::drawPath (this=0x96cff758,origSrcPath=..., origPaint=..., prePathMatrix=<optimized out>,pathIsMutable=true, drawCoverage=false) at../../third_party/skia/src/core/SkDraw.cpp:1081

#3 0x9cb3e79c in SkBitmapDevice::drawRRect (this=0x98dade20,draw=..., rrect=..., paint=...) at../../third_party/skia/src/core/SkBitmapDevice.cpp:222

#4 0x9cb4d7d0 in SkCanvas::drawRRect (this=0x98d3d900, rrect=...,paint=...) at ../../third_party/skia/src/core/SkCanvas.cpp:1966

#5 0x9cb667f8 in SkPicturePlayback::draw (this=0xa3faf500,canvas=..., callback=0x0) at../../third_party/skia/src/core/SkPicturePlayback.cpp:1129

#6 0x9cd10c98 in cc::Picture::Raster (this=this@entry=0x9675ecc0,canvas=canvas@entry=0x98d3d900, callback=callback@entry=0x0,negated_content_region=..., contents_scale=contents_scale@entry=3)

at ../../cc/resources/picture.cc:411

#7 0x9cd16aac in cc::PicturePileImpl::RasterCommon(this=this@entry=0x9fe44b00, canvas=canvas@entry=0x98d3d900,callback=callback@entry=0x0, canvas_rect=...,contents_scale=contents_scale@entry=3,

rendering_stats_instrumentation=rendering_stats_instrumentation@entry=0x9673e3c0,is_analysis=is_analysis@entry=false) at../../cc/resources/picture_pile_impl.cc:312

#8 0x9cd16d78 in cc::PicturePileImpl::RasterToBitmap(this=this@entry=0x9fe44b00, canvas=0x98d3d900, canvas_rect=...,contents_scale=3, rendering_stats_instrumentation=0x9673e3c0)

at ../../cc/resources/picture_pile_impl.cc:163

#9 0x9cd23f6a in Raster (picture_pile=0x9fe44b00,this=0x98da0e40) at ../../cc/resources/tile_manager.cc:156

#10 AnalyzeAndRaster (picture_pile=0x9fe44b00, this=0x98da0e40) at../../cc/resources/tile_manager.cc:102

#11 cc::(anonymous namespace)::RasterTaskImpl::RunOnWorkerThread(this=0x98da0e40) at ../../cc/resources/tile_manager.cc:70

#12 0x9cd21782 in cc::TaskGraphRunner::RunTaskWithLockAcquired(this=this@entry=0x9e23a0bc <cc::(anonymousnamespace)::g_task_graph_runner+4>) at../../cc/resources/task_graph_runner.cc:419

#13 0x9cd218ba in cc::TaskGraphRunner::Run (this=0x9e23a0bc<cc::(anonymous namespace)::g_task_graph_runner+4>) at../../cc/resources/task_graph_runner.cc:362

#14 0x9d5bafe8 in base::DelegateSimpleThread::Run(this=0x94d572e0) at ../../base/threading/simple_thread.cc:81







下面是一个调用blitter操作的callstack:

#0 memset32_neon () at../../third_party/skia/src/opts/memset32_neon.S:16

汇编的memset函数。

#1 0x9cb78b8a in sk_memset32(dst=0x96e74824, value=4294967295, count=375) at../../third_party/skia/src/core/SkUtils.cpp:144

#2 0x9cb4613e in SkBlitRow::ColorRect32(dst=0x96e74824, width=375, height=371, rowBytes=1536,color=4294967295) at../../third_party/skia/src/core/SkBlitRow_D32.cpp:209

#3 0x9cb4856e in SkARGB32_Blitter::blitRect(this=<optimized out>, x=<optimized out>, y=<optimizedout>, width=375, height=372) at../../third_party/skia/src/core/SkBlitter_ARGB32.cpp:218

#4 0x9cb46d1e in SkRectClipBlitter::blitAntiRect(this=<optimized out>, left=9, y=<optimized out>,width=<optimized out>, height=372, leftAlpha=<optimizedout>, rightAlpha=<optimized out>)

at ../../third_party/skia/src/core/SkBlitter.cpp:381

#5 0x9cb70c60 in SuperBlitter::blitRect(this=0x96cfe9f0, x=<optimized out>, y=1536, width=1500,height=0) at ../../third_party/skia/src/core/SkScan_AntiPath.cpp:354

#6 0x9cb72ea8 in walk_convex_edges(blitter=blitter@entry=0x96cfe9f0, stop_y=stop_y@entry=1536,proc=0x0, start_y=<optimized out>, prevHead=0x96cfe8cc) at../../third_party/skia/src/core/SkScan_Path.cpp:262

#7 0x9cb73366 in sk_fill_path(path=..., clipRect=0x96cfe990, blitter=0x96cfe9f0, start_y=24,stop_y=1536, shiftEdgesUp=2, clipRgn=...) at../../third_party/skia/src/core/SkScan_Path.cpp:504

#8 0x9cb7106e in SkScan::AntiFillPath (path=..., origClip=...,blitter=0x96cfe9c4, blitter@entry=0x96cff348, forceRLE=<optimizedout>) at ../../third_party/skia/src/core/SkScan_AntiPath.cpp:695

#9 0x9cb71148 in SkScan::AntiFillPath(path=..., clip=..., blitter=0x96cff348) at../../third_party/skia/src/core/SkScan_AntiPath.cpp:732

#10 0x9cb52dda in SkDraw::drawPath(this=0x96cff758, origSrcPath=..., origPaint=...,prePathMatrix=<optimized out>, pathIsMutable=true,drawCoverage=false) at../../third_party/skia/src/core/SkDraw.cpp:1105

#11 0x9cb3e79c in SkBitmapDevice::drawRRect(this=0x98dade20, draw=..., rrect=..., paint=...) at../../third_party/skia/src/core/SkBitmapDevice.cpp:222

#12 0x9cb4d7d0 in SkCanvas::drawRRect(this=0x98d3d900, rrect=..., paint=...) at../../third_party/skia/src/core/SkCanvas.cpp:1966

#13 0x9cb667f8 in SkPicturePlayback::draw(this=0xa3faf500, canvas=..., callback=0x0) at../../third_party/skia/src/core/SkPicturePlayback.cpp:1129

//这里到了skia里面了,这里playback之前record的skpicture内容到bitmap里面。

#14 0x9cd10c98 in cc::Picture::Raster(this=this@entry=0x9675ecc0, canvas=canvas@entry=0x98d3d900,callback=callback@entry=0x0, negated_content_region=...,contents_scale=contents_scale@entry=3)

at ../../cc/resources/picture.cc:411

#15 0x9cd16aac in cc::PicturePileImpl::RasterCommon(this=this@entry=0x9fe44b00, canvas=canvas@entry=0x98d3d900,callback=callback@entry=0x0, canvas_rect=...,contents_scale=contents_scale@entry=3,

#16 0x9cd16d78 in cc::PicturePileImpl::RasterToBitmap(this=this@entry=0x9fe44b00, canvas=0x98d3d900, canvas_rect=...,contents_scale=3, rendering_stats_instrumentation=0x9673e3c0)

at ../../cc/resources/picture_pile_impl.cc:163

#17 0x9cd23f6a in Raster(picture_pile=0x9fe44b00, this=0x98da0e40) at../../cc/resources/tile_manager.cc:156

#18 AnalyzeAndRaster(picture_pile=0x9fe44b00, this=0x98da0e40) at../../cc/resources/tile_manager.cc:102

#19 cc::(anonymous namespace)::RasterTaskImpl::RunOnWorkerThread(this=0x98da0e40) at ../../cc/resources/tile_manager.cc:70

#20 0x9cd21782 in cc::TaskGraphRunner::RunTaskWithLockAcquired(this=this@entry=0x9e23a0bc <cc::(anonymousnamespace)::g_task_graph_runner+4>) at../../cc/resources/task_graph_runner.cc:419

#21 0x9cd218ba in cc::TaskGraphRunner::Run (this=0x9e23a0bc<cc::(anonymous namespace)::g_task_graph_runner+4>) at../../cc/resources/task_graph_runner.cc:362

#22 0x9d5bafe8 in base::DelegateSimpleThread::Run(this=0x94d572e0) at ../../base/threading/simple_thread.cc:81

#23 0x9d5bb1f4 in base::SimpleThread::ThreadMain(this=0x94d572e0) at

raster线程

../../base/threading/simple_thread.cc:60

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

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

#26 0xb6e9b2d4 in __start_thread () from/tmp/tshao-adb-gdb-libs/system/lib/libc.so

#27 0x00000000 in ?? ()







那么一张普通的图片是如何raster的?

可以浏览一下我自己的带一张图片的网页。

#0 S32A_Opaque_BlitRow32_neon_src_alpha(dst=0x9596c000,

//平台相关的code

src=0x97397e00, count=384, alpha=255) at../../third_party/skia/src/opts/SkBlitRow_opts_arm_neon.cpp:764

#1 0x9cb487c0 in SkARGB32_Shader_Blitter::blitRect(this=<optimized out>, x=0, y=0, width=384, height=384) at../../third_party/skia/src/core/SkBlitter_ARGB32.cpp:404

#2 0x9cb70552 in blitrect(blitter=<optimized out>, r=...) at../../third_party/skia/src/core/SkScan.cpp:15

#3 0x9cb7061e in SkScan::FillIRect (r=...,clip=clip@entry=0x9451f638, blitter=blitter@entry=0x96cfef10) at../../third_party/skia/src/core/SkScan.cpp:30

#4 0x9cb706e6 in SkScan::FillRect (r=..., clip=0x9451f638,blitter=0x96cfef10) at ../../third_party/skia/src/core/SkScan.cpp:61

#5 0x9cb707d6 in SkScan::FillRect(r=..., clip=..., blitter=<optimized out>) at../../third_party/skia/src/core/SkScan.cpp:103

#6 0x9cb53526 in SkDraw::drawRect(this=this@entry=0x96cff13c, rect=..., paint=...) at../../third_party/skia/src/core/SkDraw.cpp:845

#7 0x9cb548c2 in SkDraw::drawBitmap(this=0x96cff6f4, bitmap=..., prematrix=..., origPaint=...) at../../third_party/skia/src/core/SkDraw.cpp:1280

#8 0x9cb3eacc in SkBitmapDevice::drawBitmapRect(this=0x7c6afc90, draw=..., bitmap=..., src=<optimized out>,dst=..., paint=..., flags=SkCanvas::kNone_DrawBitmapRectFlag)

at ../../third_party/skia/src/core/SkBitmapDevice.cpp:305

#9 0x9cb4df54 in SkCanvas::internalDrawBitmapRect(this=0x96944f00,

//这里绘制bitmap的一部分。

bitmap=..., src=0x7f0110c4, dst=..., paint=<optimized out>,flags=SkCanvas::kNone_DrawBitmapRectFlag)

at ../../third_party/skia/src/core/SkCanvas.cpp:2076

#10 0x9cb66718 in SkPicturePlayback::draw(this=0x7ab12f80, canvas=..., callback=0x0) at../../third_party/skia/src/core/SkPicturePlayback.cpp:1091

#11 0x9cd10c98 in cc::Picture::Raster(this=this@entry=0x7d40fb30, canvas=canvas@entry=0x96944f00,callback=callback@entry=0x0, negated_content_region=...,contents_scale=contents_scale@entry=1.04651165)

at ../../cc/resources/picture.cc:411

#12 0x9cd16aac in cc::PicturePileImpl::RasterCommon(this=this@entry=0x7f013de0, canvas=canvas@entry=0x96944f00,callback=callback@entry=0x0, canvas_rect=...,contents_scale=contents_scale@entry=1.04651165,

rendering_stats_instrumentation=rendering_stats_instrumentation@entry=0x7ab11cc0,is_analysis=is_analysis@entry=false) at../../cc/resources/picture_pile_impl.cc:312

#13 0x9cd16d78 in cc::PicturePileImpl::RasterToBitmap(this=this@entry=0x7f013de0, canvas=0x96944f00, canvas_rect=...,contents_scale=1.04651165,rendering_stats_instrumentation=0x7ab11cc0)

#14 0x9cd23f6a in Raster (picture_pile=0x7f013de0,this=0x90ff33c0) at ../../cc/resources/tile_manager.cc:156

#15 AnalyzeAndRaster(picture_pile=0x7f013de0, this=0x90ff33c0) at../../cc/resources/tile_manager.cc:102

#16 cc::(anonymous namespace)::RasterTaskImpl::RunOnWorkerThread(this=0x90ff33c0) at ../../cc/resources/tile_manager.cc:70

#17 0x9cd21782 in cc::TaskGraphRunner::RunTaskWithLockAcquired(this=this@entry=0x9e23a0bc <cc::(anonymousnamespace)::g_task_graph_runner+4>) at../../cc/resources/task_graph_runner.cc:419

#18 0x9cd218ba in cc::TaskGraphRunner::Run (this=0x9e23a0bc<cc::(anonymous namespace)::g_task_graph_runner+4>) at../../cc/resources/task_graph_runner.cc:362

#19 0x9d5bafe8 in base::DelegateSimpleThread::Run(this=0x94d572e0) at ../../base/threading/simple_thread.cc:81

#20 0x9d5bb1f4 in base::SimpleThread::ThreadMain(this=0x94d572e0) at ../../base/threading/simple_thread.cc:60

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

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

#23 0xb6e9b2d4 in __start_thread () from/tmp/tshao-adb-gdb-libs/system/lib/libc.so

#24 0x00000000 in ?? ()



相关推荐

Chrome内核解析 -- 背景篇:Chromium的多进程多线程构架

转载请注明出处:http://blog.youkuaiyun.com/yunchao_he/article/details/41695497 Chromium采用多进程构架,以Desktop Chromium为例,它包括一个Browser Process(也称为UI Process), 一个或多个Render Process(也称为Web Process), 零个或一个GPU Process, 以及一个或多个NPAPI Plugin Process, 一个或多个Pepper Plugin进程。

yunchao的专栏: HTML5/Chromium/Web, Graphics, Android 3577

flutter - 光栅(Raster)&性能优化

光栅(Raster)&性能优化 光栅化是把绘制指令转换成对应的像素数据,合成是把各图层栅格化后的数据进行相关的叠加和特性处理。这个流程称为 Graphics Pipeline。 Flutter 采用的是异步分快光栅化 光栅化和合成在一个线程,或者通过线程同步等方式来保证光栅化和合成的的顺序。 直接光栅化:直接执行可见图层的 DisplayList 中可见区域的绘制指令进行光栅化,在目标 Surface 的像素缓冲区上生成像素的颜色值。 间接光栅化:为指定图层分配额外的像素缓冲区(例如 A

ifredom 3983

Skia绘制代码分析

路径绘制尽管使用频率相对于图像绘制、文本绘制低,但却是非常重要的一个基本特性。所有不规则图形(椭圆、圆角矩形、三角形、简单的文字),最后都避不开路径绘制。 而且,若自己实现一个2D引擎,这块内容是很具有参考意义的,用OpenGL的话,图像采样等都很少关注了,对对坐标就好。但菱角、圆弧、曲线等如何绘制仍然是一个难题,这时就可以参考Skia中drawPath的实现。 由于涉及较多的图形学知识,本章

hgl868的专栏 9272

Flutter 性能优化

Flutter 作为目前最火爆的移动端跨平台框架,能够帮助开发者通过一套代码库高效地构建多平台的精美应用,并支持移动、Web、桌面和嵌入式平台。对于 Android 来说,Flutter 能够创作媲美原生的高性能应用,但是,在较为复杂的 App 中,使用 Flutter 开发也很难避免产生各种各样的性能问题。在这篇文章中,我将和你一起全方位地深入探索 Flutter 性能优化的疆域。以 profile 模式启动应用,如果是混合 Flutter 应用,在 flutter/packages/flutter_to

Dream It Possible 6454

用Arduino和8个舵机,从零搭建一台能走路的并联腿机器狗(附完整代码与3D模型)

本文详细介绍了如何用Arduino和8个舵机从零搭建一台能走路的并联腿机器狗,包括硬件准备、结构组装、电路系统搭建、运动算法实现和Arduino编程。通过完整的代码与3D模型,帮助创客深入理解机器人运动原理,实现稳健行走的8自由度机器狗。

weixin_30482383的博客 702

FOC电机控制中电流采样延迟补偿的原理和方法

摘要: FOC电机控制中,电流采样、计算与PWM更新存在固有延迟(约1.5个PWM周期),导致相位滞后,限制电流环带宽。主流补偿方法包括: 一阶前向预测法:基于历史电流值预测未来电流,抵消延迟,工程应用广泛; 相位超前补偿:通过s/z域校正器设计实现等效预测; 状态观测器法(如龙伯格观测器):通过电机模型闭环估计状态,兼具噪声抑制和参数辨识能力,但复杂度高。实际需注意参数敏感性、离散化精度及延迟时间校准,避免过补偿风险。一阶预测法因平衡效果与复杂度成为工业首选。

jifengzhiling的博客 2234

深入探索Flutter性能优化

目录 一、检测手段 1、Flutter Inspector 2、性能图层 3、Raster 线程问题 4、UI 线程问题定位 5、检查多视图叠加的视图渲染开关 checkerboardOffscreenLayers 6、检查缓存的图像开关 checkerboardRasterCacheImages 二、关键优化指标 1、页面异常率 2、页面帧率 3、页面加载时长 三、布局加载优化 1...

IT元老的博客 484

手把手教你用Python+GDAL处理0.5米吉林一号卫星影像(附代码)

本文详细介绍了如何使用Python和GDAL处理吉林一号0.5米高分辨率卫星影像,包括环境配置、数据预处理、分辨率融合、植被指数计算及地物分类等关键步骤。通过实战代码示例,帮助开发者高效处理大尺寸遥感数据,解决资源崩溃和算法选择问题,提升遥感影像分析能力。

weixin_30892037的博客 129

详解 Flutter engine多线程、Dart isolate和异步

随着Flutter的使用越来越广泛,相信很多人包括我自己对flutter的线程一直存一些疑问, dart为什么默认是单线程任务处理、在单线程下dart的异步是如何实现的、flutter线程有哪些、如何使用多线程处理耗时操作... 带着这些疑问去探索下flutter engine多线程、 dart isolate 和 异步 三者之前的关系。

三翼鸟数字化平台的技术实践分享 2380

sid图像数据_遥感影像数据

影像数据基本概念影像数据是由卫星或飞机上的成像系统获得的影像,多为遥感影像数据。影像数据的每个像元都有一个值,表示传感器探测到像素对应地面面积上目标物的电磁辐射强度,也叫亮度值、灰度值。SuperMap支持的影像数据格式有:*.img、*.tif、*.tiff、*.bmp、*.jpg、*.png、*.gif、*.raw、*.sid等。计算机以二进制记录数据,所以其量化的等级以二进制来划分,即2n。...

weixin_39534395的博客 1627

当AI学会写“自传”:OpenClaw 的 SOUL.md 如何把配置文件变成一颗会变形的心

SOUL.md。

步子哥的博客 1311

宝塔Mysql无法启动

【代码】宝塔Mysql无法启动。

m0_52796585的博客 1048

《点云进阶》专栏文章目录

点云进阶》专栏文章目录

点云侠的博客 4905

浏览器内核为何有千万行代码?从渲染引擎到JavaScript引擎全解析

从“软件如何变得复杂”这一通用疑问出发,解析大型系统应对多平台、多标准与兼容性时的必然设计。浏览器内核并非单一仓库,而是由操作系统抽象层、渲染引擎、JavaScript引擎、网络栈、GPU合成等子系统共同构成的超级运行时。HTML解析、样式计算、布局与绘制需要遵循Web标准并兼容20年历史网页;V8等JS引擎还要完成JIT编译、垃圾回收与安全隔离。作为通用软件开发原则,分层、多进程、灰度与边界测试是控制复杂度的关键。理解这种千万行工程背后的权衡策略,对前端性能调优、客户端架构乃至后端高并发系统设计都有参考价

weixin_34160277的博客 512

使用timeROC包的compare函数比较不同标记物下两个多时间AUC值是否具有统计显著性

时间依赖的接收器操作特征曲线(time-dependent receiver operating characteristic curve, time-dependent ROC curve)是评估和比较标记物在不同时间点上预测能力的重要工具。在R语言中,timeROC包提供了丰富的函数和工具,可用于分析和比较多时间点的AUC值。时间点(timepoints)表示观察的时间点,标记物1(marker1)和标记物2(marker2)分别表示在每个时间点上的预测概率。最后,我们输出比较结果。

2301_79331387的博客 922

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Skia CanvasKit 结合 Web ImageDecoder API:把图像解码交给浏览器的新路径

本文基于 CanvasKit 的 Future APIs 笔记 `modules/canvaskit/future_apis/ImageDecoder.md` 展开,讲清 Web 标准的 ImageDecoder API 与 CanvasKit 图像解码路径的对接方式:你将了解如何用 `ImageDecoder` 逐帧解码静态与动画图像、再经 `CanvasKit.MakeImageFromCan

gitblog_00482的博客 199

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

FastLED 嵌入式 LED 控制库完全指南:从 Arduino 点灯到大规模并行驱动

FastLED 是面向 Arduino 与嵌入式平台的通用 LED 动画库,可驱动 WS2812/APA102 等几乎所有主流 LED 芯片组,覆盖从不到 1 美元的 ATtiny 芯片到可同时输出 50 路并行灯带的 Teensy 4.1 全谱系硬件。本文以仓库根目录 [README.md](https://link.gitcode.com/i/4e11dd85e8e983f74f9c7cfc1

gitblog_01045的博客 1194

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

阅读笔记:Multi-threaded Rasterization in the Chromium Compositor

对于图块化的内容,每个图块可以独立光栅化。:文档也提到了一些实施多线程光栅化带来的挑战,比如遮挡剔除(occlusion culling)的架构难题、更多并行可能导致的额外延迟,以及对Blink中像素级优化的无效化。:强调了“无特殊案例”原则,即Tile Manager需要考虑所有可能的图块,包括那些暂时不可见但未来可能需要的,以支持预渲染和减少页面滚动时的空白现象。: 这里提到的是一个编译时的设置,它可能属于Chrome的组件(cc代表Chrome Compositor),用于调试和查看图层记录的边界。

hebhljdx的博客 891

Flutter性能分析概要

文章目录Connect to a physical device 连接真机Run in profile modeLaunch DevToolsThe performance overlayInterpreting the graphsFlutter’s threadsPlatform threadUI threadRaster thread (previously known as the GPU thread)I/O threadDisplaying the performance overlayUsin

m0_53337932的博客 1535

栅格那点儿事(二)---细看Raster属性

细看Raster属性   如果你已经看完了上一章,你已经了解了栅格数据是由一个个像元(Cell)按照行列方式构成的,每一个像元都有自己的像元值,并且这些像元值根据栅格类型的不同,可以代表反射值,或高程值,或分类类别等等。But,关于栅格数据属性的细节还是有很多问题。好像是像元值是不是也可以分成Integer, Float,或者Double?为什么栅格数据有的只有一个band,有的确有多个b

redhairp的专栏 3万+

栅格那点儿事(一)---Raster是个啥子东西

Raster是个啥子东西   现如今,不仅是在遥感应用中能看到花花绿绿的影像了,在GIS应用中也能随处看到她们的身影。在各种在线地图中,卫星影像作为底图与矢量的道路层叠加;高程DEM作为高程来源实现地形的山影效果。相信大家对影像这个词,应该一点儿也不感到陌生。   那么栅格呢?相对与我们熟悉的影像,这俩只是名词上的区别么? 栅格(Raster)和影像(Images/Imagery)在

redhairp的专栏 4万+

Skia深入分析2——skia渲染架构

一、渲染层级从渲染流程上分,Skia可分为如下三个层级: 1、指令层:SkPicture、SkDeferredCanvas->SkCanvas 这一层决定需要执行哪些绘图操作,绘图操作的预变换矩阵,当前裁剪区域,绘图操作产生在哪些layer上,Layer的生成与合并。 2、解析层:SkBitmapDevice->SkDraw->SkS...

weixin_33853827的博客 2076

Skia深入分析

一、渲染层级 从渲染流程上分,Skia可分为如下三个层级: 1、指令层:SkPicture、SkDeferredCanvas->SkCanvas 这一层决定需要执行哪些绘图操作,绘图操作的预变换矩阵,当前裁剪区域,绘图操作产生在哪些layer上,Layer的生成与合并。 2、解析层:SkBitmapDevice->SkDraw->SkScan、SkDraw1Glyph::Proc 这一层

hgl868的专栏 2万+

GPU的架构(一)

gpu的驱动框架: 1、窗口标准的实现是与操作系统强相关的,它为图形渲染提供目标内存。一般来说,只要支持的标准不变,操作系统更换/升级,对驱动的代码影响就只限在窗口这一块。 2、编译器用于编译shader或kernel,编译kernel需要用llvm预编译,编译器会大一些。低端GPU的编译器特别容易出现各种语法不支持,让写shader的人痛苦万分。 3、通用计算的实现就是把kernel编译后转成任务扔给内核去跑,相对简单。 4、图形渲染的实现则需要考虑到一帧中可能有重复渲染/过度绘制的情况,为了这方面做优

微小的鱼的博客 1万+

7大浏览器引擎的对决,你最看好哪个?

在浏览器技术发展的过程中,浏览器引擎扮演着至关重要的角色。不同的浏览器引擎在性能、安全性、标准支持等方面各具特色。本文将浅浅的对比一下 WebKit、Blink、Gecko、Trident、EdgeHTML、Servo 和 WebKit2 这几大浏览器引擎。这些浏览器引擎在架构、性能优化、安全性、标准支持、扩展性和历史发展等方面各有优劣。现代浏览器引擎(如Blink和Gecko)通常采用多进程架构,提高了安全性和性能;而较老的引擎(如Trident)则相对较弱。

2401_86113453的博客 1785
上一篇: blink渲染知识15- gl命令的生成和处理(command buffer)
下一篇: chromium网络栈学习
csshell2002
博客等级 码龄11年 30粉丝 41原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值