1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207 |
- // Copyright 2011 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "cc/scheduler/scheduler.h"
- #include <stddef.h>
- #include <memory>
- #include <string>
- #include <utility>
- #include <vector>
- #include "base/auto_reset.h"
- #include "base/bind.h"
- #include "base/check_op.h"
- #include "base/memory/ptr_util.h"
- #include "base/memory/raw_ptr.h"
- #include "base/notreached.h"
- #include "base/numerics/safe_conversions.h"
- #include "base/run_loop.h"
- #include "base/test/test_mock_time_task_runner.h"
- #include "base/time/time.h"
- #include "base/time/time_override.h"
- #include "base/trace_event/trace_event.h"
- #include "cc/metrics/begin_main_frame_metrics.h"
- #include "cc/metrics/event_metrics.h"
- #include "cc/test/fake_compositor_frame_reporting_controller.h"
- #include "cc/test/scheduler_test_common.h"
- #include "components/power_scheduler/power_mode_arbiter.h"
- #include "components/viz/common/frame_sinks/begin_frame_args.h"
- #include "components/viz/test/begin_frame_args_test.h"
- #include "components/viz/test/fake_delay_based_time_source.h"
- #include "components/viz/test/fake_external_begin_frame_source.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #define EXPECT_ACTIONS(...) \
- EXPECT_THAT(client_->Actions(), ::testing::ElementsAre(__VA_ARGS__))
- #define EXPECT_NO_ACTION() EXPECT_THAT(client_->Actions(), ::testing::IsEmpty())
- #define EXPECT_SCOPED(statements) \
- { \
- SCOPED_TRACE(""); \
- statements; \
- }
- namespace cc {
- namespace {
- using power_scheduler::PowerMode;
- using power_scheduler::PowerModeArbiter;
- using power_scheduler::PowerModeVoter;
- base::TimeDelta kSlowDuration = base::Seconds(1);
- base::TimeDelta kFastDuration = base::Milliseconds(1);
- class FakeSchedulerClient : public SchedulerClient,
- public viz::FakeExternalBeginFrameSource::Client {
- public:
- FakeSchedulerClient() { Reset(); }
- void Reset() {
- actions_.clear();
- will_begin_impl_frame_causes_redraw_ = false;
- will_begin_impl_frame_requests_one_begin_impl_frame_ = false;
- invalidate_needs_redraw_ = true;
- draw_will_happen_ = true;
- swap_will_happen_if_draw_happens_ = true;
- num_draws_ = 0;
- last_begin_main_frame_args_ = viz::BeginFrameArgs();
- last_begin_frame_ack_ = viz::BeginFrameAck();
- last_frame_skipped_reason_.reset();
- }
- void set_scheduler(TestScheduler* scheduler) { scheduler_ = scheduler; }
- bool needs_begin_frames() { return scheduler_->begin_frames_expected(); }
- int num_draws() const { return num_draws_; }
- bool invalidate_needs_redraw() const { return invalidate_needs_redraw_; }
- const std::vector<std::string> Actions() const {
- return std::vector<std::string>(actions_.begin(), actions_.end());
- }
- base::TimeTicks posted_begin_impl_frame_deadline() const {
- return posted_begin_impl_frame_deadline_;
- }
- base::TimeDelta frame_interval() const { return frame_interval_; }
- int ActionIndex(const char* action) const {
- for (size_t i = 0; i < actions_.size(); i++)
- if (!strcmp(actions_[i], action))
- return base::checked_cast<int>(i);
- return -1;
- }
- bool HasAction(const char* action) const { return ActionIndex(action) >= 0; }
- void SetWillBeginImplFrameRequestsOneBeginImplFrame(bool request) {
- will_begin_impl_frame_requests_one_begin_impl_frame_ = request;
- }
- void SetWillBeginImplFrameCausesRedraw(bool causes_redraw) {
- will_begin_impl_frame_causes_redraw_ = causes_redraw;
- }
- void SetInvalidateNeedsRedraw(bool needs_redraw) {
- invalidate_needs_redraw_ = needs_redraw;
- }
- void SetDrawWillHappen(bool draw_will_happen) {
- draw_will_happen_ = draw_will_happen;
- }
- void SetSwapWillHappenIfDrawHappens(bool swap_will_happen_if_draw_happens) {
- swap_will_happen_if_draw_happens_ = swap_will_happen_if_draw_happens;
- }
- void SetAutomaticSubmitCompositorFrameAck(bool automatic_ack) {
- automatic_ack_ = automatic_ack;
- }
- void SetWillBeginImplFrameMightHaveDamage(bool might_have_damage) {
- will_begin_impl_frame_might_have_damage_ = might_have_damage;
- }
- // SchedulerClient implementation.
- bool WillBeginImplFrame(const viz::BeginFrameArgs& args) override {
- EXPECT_FALSE(inside_begin_impl_frame_);
- EXPECT_FALSE(inside_action_);
- base::AutoReset<bool> mark_inside(&inside_action_, true);
- inside_begin_impl_frame_ = true;
- PushAction("WillBeginImplFrame");
- if (will_begin_impl_frame_requests_one_begin_impl_frame_)
- scheduler_->SetNeedsOneBeginImplFrame();
- if (will_begin_impl_frame_causes_redraw_)
- scheduler_->SetNeedsRedraw();
- return will_begin_impl_frame_might_have_damage_;
- }
- void DidFinishImplFrame(
- const viz::BeginFrameArgs& last_activated_args) override {
- EXPECT_TRUE(inside_begin_impl_frame_);
- EXPECT_FALSE(inside_action_);
- base::AutoReset<bool> mark_inside(&inside_action_, true);
- inside_begin_impl_frame_ = false;
- }
- void DidNotProduceFrame(const viz::BeginFrameAck& ack,
- FrameSkippedReason reason) override {
- EXPECT_FALSE(inside_action_);
- base::AutoReset<bool> mark_inside(&inside_action_, true);
- last_begin_frame_ack_ = ack;
- last_frame_skipped_reason_ = reason;
- }
- void WillNotReceiveBeginFrame() override {}
- void ScheduledActionSendBeginMainFrame(
- const viz::BeginFrameArgs& args) override {
- EXPECT_FALSE(inside_action_);
- base::AutoReset<bool> mark_inside(&inside_action_, true);
- PushAction("ScheduledActionSendBeginMainFrame");
- last_begin_main_frame_args_ = args;
- }
- void FrameIntervalUpdated(base::TimeDelta interval) override {
- frame_interval_ = interval;
- }
- const viz::BeginFrameArgs& last_begin_main_frame_args() {
- return last_begin_main_frame_args_;
- }
- const viz::BeginFrameAck& last_begin_frame_ack() {
- return last_begin_frame_ack_;
- }
- FrameSkippedReason last_frame_skipped_reason() const {
- return last_frame_skipped_reason_.value();
- }
- DrawResult ScheduledActionDrawIfPossible() override {
- EXPECT_FALSE(inside_action_);
- base::AutoReset<bool> mark_inside(&inside_action_, true);
- PushAction("ScheduledActionDrawIfPossible");
- num_draws_++;
- if (!draw_will_happen_)
- return DRAW_ABORTED_CHECKERBOARD_ANIMATIONS;
- if (swap_will_happen_if_draw_happens_) {
- last_begin_frame_ack_ = scheduler_->CurrentBeginFrameAckForActiveTree();
- scheduler_->DidSubmitCompositorFrame(0, base::TimeTicks::Now(),
- EventMetricsSet(),
- /*has_missing_content=*/false);
- if (automatic_ack_)
- scheduler_->DidReceiveCompositorFrameAck();
- }
- return DRAW_SUCCESS;
- }
- DrawResult ScheduledActionDrawForced() override {
- EXPECT_FALSE(inside_action_);
- base::AutoReset<bool> mark_inside(&inside_action_, true);
- PushAction("ScheduledActionDrawForced");
- last_begin_frame_ack_ = scheduler_->CurrentBeginFrameAckForActiveTree();
- return DRAW_SUCCESS;
- }
- void ScheduledActionCommit() override {
- EXPECT_FALSE(inside_action_);
- base::AutoReset<bool> mark_inside(&inside_action_, true);
- PushAction("ScheduledActionCommit");
- }
- void ScheduledActionPostCommit() override {
- EXPECT_FALSE(inside_action_);
- base::AutoReset<bool> mark_inside(&inside_action_, true);
- PushAction("ScheduledActionPostCommit");
- }
- void ScheduledActionActivateSyncTree() override {
- EXPECT_FALSE(inside_action_);
- base::AutoReset<bool> mark_inside(&inside_action_, true);
- PushAction("ScheduledActionActivateSyncTree");
- }
- void ScheduledActionBeginLayerTreeFrameSinkCreation() override {
- EXPECT_FALSE(inside_action_);
- base::AutoReset<bool> mark_inside(&inside_action_, true);
- PushAction("ScheduledActionBeginLayerTreeFrameSinkCreation");
- }
- void ScheduledActionPrepareTiles() override {
- EXPECT_FALSE(inside_action_);
- base::AutoReset<bool> mark_inside(&inside_action_, true);
- PushAction("ScheduledActionPrepareTiles");
- scheduler_->WillPrepareTiles();
- scheduler_->DidPrepareTiles();
- }
- void ScheduledActionInvalidateLayerTreeFrameSink(bool needs_redraw) override {
- EXPECT_FALSE(inside_action_);
- base::AutoReset<bool> mark_inside(&inside_action_, true);
- invalidate_needs_redraw_ = needs_redraw;
- actions_.push_back("ScheduledActionInvalidateLayerTreeFrameSink");
- }
- void ScheduledActionPerformImplSideInvalidation() override {
- EXPECT_FALSE(inside_action_);
- base::AutoReset<bool> mark_inside(&inside_action_, true);
- PushAction("ScheduledActionPerformImplSideInvalidation");
- }
- void SendBeginMainFrameNotExpectedSoon() override {
- EXPECT_FALSE(inside_action_);
- base::AutoReset<bool> mark_inside(&inside_action_, true);
- PushAction("SendBeginMainFrameNotExpectedSoon");
- }
- void ScheduledActionBeginMainFrameNotExpectedUntil(
- base::TimeTicks time) override {
- EXPECT_FALSE(inside_action_);
- base::AutoReset<bool> mark_inside(&inside_action_, true);
- PushAction("ScheduledActionBeginMainFrameNotExpectedUntil");
- }
- bool IsInsideBeginImplFrame() const { return inside_begin_impl_frame_; }
- base::RepeatingCallback<bool(void)> InsideBeginImplFrame(bool state) {
- return base::BindRepeating(
- &FakeSchedulerClient::InsideBeginImplFrameCallback,
- base::Unretained(this), state);
- }
- bool IsCurrentFrame(int last_frame_number) const {
- return scheduler_->current_frame_number() == last_frame_number;
- }
- base::RepeatingCallback<bool(void)> FrameHasNotAdvancedCallback() {
- return base::BindRepeating(&FakeSchedulerClient::IsCurrentFrame,
- base::Unretained(this),
- scheduler_->current_frame_number());
- }
- void PushAction(const char* description) {
- actions_.push_back(description);
- }
- // FakeExternalBeginFrameSource::Client implementation.
- void OnAddObserver(viz::BeginFrameObserver* obs) override {
- PushAction("AddObserver(this)");
- }
- void OnRemoveObserver(viz::BeginFrameObserver* obs) override {
- PushAction("RemoveObserver(this)");
- }
- bool HasInvalidationAnimation() const override { return false; }
- protected:
- bool InsideBeginImplFrameCallback(bool state) {
- return inside_begin_impl_frame_ == state;
- }
- bool inside_action_ = false;
- bool inside_begin_impl_frame_ = false;
- bool will_begin_impl_frame_causes_redraw_;
- bool will_begin_impl_frame_requests_one_begin_impl_frame_;
- bool invalidate_needs_redraw_ = true;
- bool draw_will_happen_;
- bool swap_will_happen_if_draw_happens_;
- bool automatic_ack_ = true;
- bool will_begin_impl_frame_might_have_damage_ = true;
- int num_draws_;
- viz::BeginFrameArgs last_begin_main_frame_args_;
- viz::BeginFrameAck last_begin_frame_ack_;
- base::TimeTicks posted_begin_impl_frame_deadline_;
- std::vector<const char*> actions_;
- raw_ptr<TestScheduler> scheduler_ = nullptr;
- base::TimeDelta frame_interval_;
- absl::optional<FrameSkippedReason> last_frame_skipped_reason_;
- };
- enum BeginFrameSourceType {
- EXTERNAL_BFS,
- UNTHROTTLED_BFS,
- THROTTLED_BFS,
- };
- class SchedulerTestTaskRunner : public base::TestMockTimeTaskRunner {
- public:
- SchedulerTestTaskRunner()
- : base::TestMockTimeTaskRunner(
- base::TestMockTimeTaskRunner::Type::kStandalone) {
- AdvanceMockTickClock(base::Microseconds(110000));
- }
- void RunUntilTime(base::TimeTicks end_time) {
- FastForwardBy(end_time - NowTicks());
- }
- // Runs all tasks posted before this call.
- void RunPendingTasks() {
- base::circular_deque<base::TestPendingTask> tasks = TakePendingTasks();
- while (!tasks.empty()) {
- base::TestPendingTask task = std::move(tasks.front());
- tasks.pop_front();
- // Set clock to the beginning of task and run it.
- AdvanceMockTickClock(task.GetTimeToRun() - NowTicks());
- std::move(task.task).Run();
- }
- }
- // Runs tasks while condition is met.
- // Condition is being checked when task exists and before it gets selected.
- void RunTasksWhile(base::RepeatingCallback<bool()> condition) {
- run_condition_ = condition;
- FastForwardUntilNoTasksRemain();
- run_condition_ = absl::nullopt;
- // We've moved all the pending tasks away to break the execution loop,
- // now we should restore them.
- while (!tasks_to_requeue_.empty()) {
- base::TestPendingTask task = std::move(tasks_to_requeue_.front());
- tasks_to_requeue_.pop_front();
- PostDelayedTask(task.location, std::move(task.task),
- task.GetTimeToRun() - NowTicks());
- }
- }
- protected:
- void OnBeforeSelectingTask() override {
- // Avoid potential infinite loops.
- ASSERT_LT(++task_count_, 100u);
- if (run_condition_ && HasPendingTask() && !run_condition_->Run()) {
- // Execution will not continue because we move all the pending tasks away.
- tasks_to_requeue_ = TakePendingTasks();
- }
- }
- private:
- ~SchedulerTestTaskRunner() override = default; // Ref-counted.
- size_t task_count_ = 0u;
- absl::optional<base::RepeatingCallback<bool()>> run_condition_;
- base::circular_deque<base::TestPendingTask> tasks_to_requeue_;
- };
- class SchedulerTest : public testing::Test {
- public:
- SchedulerTest()
- : task_runner_(base::MakeRefCounted<SchedulerTestTaskRunner>()),
- fake_external_begin_frame_source_(nullptr) {}
- ~SchedulerTest() override = default;
- protected:
- TestScheduler* CreateScheduler(BeginFrameSourceType bfs_type) {
- viz::BeginFrameSource* frame_source = nullptr;
- unthrottled_frame_source_ =
- std::make_unique<viz::BackToBackBeginFrameSource>(
- std::make_unique<viz::FakeDelayBasedTimeSource>(
- task_runner_->GetMockTickClock(), task_runner_.get()));
- fake_external_begin_frame_source_ =
- std::make_unique<viz::FakeExternalBeginFrameSource>(1.0, false);
- fake_external_begin_frame_source_->SetClient(client_.get());
- synthetic_frame_source_ = std::make_unique<viz::DelayBasedBeginFrameSource>(
- std::make_unique<viz::FakeDelayBasedTimeSource>(
- task_runner_->GetMockTickClock(), task_runner_.get()),
- viz::BeginFrameSource::kNotRestartableId);
- switch (bfs_type) {
- case EXTERNAL_BFS:
- frame_source = fake_external_begin_frame_source_.get();
- break;
- case UNTHROTTLED_BFS:
- frame_source = unthrottled_frame_source_.get();
- break;
- case THROTTLED_BFS:
- frame_source = synthetic_frame_source_.get();
- break;
- }
- DCHECK(frame_source);
- std::unique_ptr<FakeCompositorTimingHistory>
- fake_compositor_timing_history = FakeCompositorTimingHistory::Create(
- scheduler_settings_.using_synchronous_renderer_compositor);
- fake_compositor_timing_history_ = fake_compositor_timing_history.get();
- reporting_controller =
- std::make_unique<FakeCompositorFrameReportingController>();
- reporting_controller->SetDroppedFrameCounter(&dropped_counter);
- scheduler_ = std::make_unique<TestScheduler>(
- task_runner_->GetMockTickClock(), client_.get(), scheduler_settings_, 0,
- task_runner_.get(), std::move(fake_compositor_timing_history),
- reporting_controller.get(), &power_mode_arbiter_);
- client_->set_scheduler(scheduler_.get());
- scheduler_->SetBeginFrameSource(frame_source);
- return scheduler_.get();
- }
- void SetUpScheduler(BeginFrameSourceType bfs_type,
- std::unique_ptr<FakeSchedulerClient> client) {
- client_ = std::move(client);
- CreateScheduler(bfs_type);
- EXPECT_SCOPED(InitializeLayerTreeFrameSinkAndFirstCommit());
- }
- void SetUpScheduler(BeginFrameSourceType bfs_type) {
- SetUpScheduler(bfs_type, std::make_unique<FakeSchedulerClient>());
- }
- void SetUpSchedulerWithNoLayerTreeFrameSink(BeginFrameSourceType bfs_type) {
- client_ = std::make_unique<FakeSchedulerClient>();
- CreateScheduler(bfs_type);
- }
- // As this function contains EXPECT macros, to allow debugging it should be
- // called inside EXPECT_SCOPED like so;
- // EXPECT_SCOPED(
- // client.InitializeLayerTreeFrameSinkAndFirstCommit(scheduler));
- void InitializeLayerTreeFrameSinkAndFirstCommit() {
- TRACE_EVENT0(
- "cc", "SchedulerUnitTest::InitializeLayerTreeFrameSinkAndFirstCommit");
- DCHECK(scheduler_);
- // Check the client doesn't have any actions queued when calling this
- // function.
- EXPECT_NO_ACTION();
- EXPECT_FALSE(scheduler_->begin_frames_expected());
- // Start the initial LayerTreeFrameSink creation.
- scheduler_->SetVisible(true);
- scheduler_->SetCanDraw(true);
- EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation");
- client_->Reset();
- // We don't see anything happening until the first impl frame.
- scheduler_->DidCreateAndInitializeLayerTreeFrameSink();
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- {
- SCOPED_TRACE("Do first frame to commit after initialize.");
- AdvanceFrame();
- task_runner_->AdvanceMockTickClock(base::Milliseconds(1));
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- scheduler_->NotifyReadyToActivate();
- scheduler_->NotifyReadyToDraw();
- EXPECT_FALSE(scheduler_->CommitPending());
- if (scheduler_settings_.using_synchronous_renderer_compositor) {
- scheduler_->SetNeedsRedraw();
- bool resourceless_software_draw = false;
- bool skip_draw = false;
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
- skip_draw);
- } else {
- // Run the posted deadline task.
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- }
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- }
- client_->Reset();
- {
- SCOPED_TRACE(
- "Run second frame so Scheduler calls SetNeedsBeginFrame(false).");
- AdvanceFrame();
- if (!scheduler_settings_.using_synchronous_renderer_compositor) {
- // Run the posted deadline task.
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- }
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- }
- EXPECT_FALSE(scheduler_->begin_frames_expected());
- if (scheduler_->begin_frame_source() ==
- fake_external_begin_frame_source_.get()) {
- // Expect the last viz::BeginFrameAck to be for last BeginFrame, which
- // didn't cause damage.
- uint64_t last_begin_frame_number =
- fake_external_begin_frame_source_->next_begin_frame_number() - 1;
- bool has_damage = false;
- EXPECT_EQ(
- viz::BeginFrameAck(fake_external_begin_frame_source_->source_id(),
- last_begin_frame_number, has_damage),
- client_->last_begin_frame_ack());
- }
- client_->Reset();
- }
- // As this function contains EXPECT macros, to allow debugging it should be
- // called inside EXPECT_SCOPED like so;
- // EXPECT_SCOPED(client.AdvanceFrame());
- void AdvanceFrame(bool animate_only = false) {
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"),
- "FakeSchedulerClient::AdvanceFrame");
- // Send the next BeginFrame message if using an external source, otherwise
- // it will be already in the task queue.
- if (scheduler_->begin_frame_source() ==
- fake_external_begin_frame_source_.get()) {
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- // Run the deadline first if we're inside the previous frame.
- if (client_->IsInsideBeginImplFrame())
- task_runner_->RunPendingTasks();
- SendNextBeginFrame(animate_only);
- } else {
- task_runner_->RunTasksWhile(client_->FrameHasNotAdvancedCallback());
- }
- }
- viz::BeginFrameArgs SendNextBeginFrame(bool animate_only = false) {
- DCHECK_EQ(scheduler_->begin_frame_source(),
- fake_external_begin_frame_source_.get());
- // Creep the time forward so that any viz::BeginFrameArgs is not equal to
- // the last one otherwise we violate the viz::BeginFrameSource contract.
- task_runner_->AdvanceMockTickClock(viz::BeginFrameArgs::DefaultInterval());
- viz::BeginFrameArgs args =
- fake_external_begin_frame_source_->CreateBeginFrameArgs(
- BEGINFRAME_FROM_HERE, task_runner_->GetMockTickClock());
- args.animate_only = animate_only;
- fake_external_begin_frame_source_->TestOnBeginFrame(args);
- return args;
- }
- viz::FakeExternalBeginFrameSource* fake_external_begin_frame_source() const {
- return fake_external_begin_frame_source_.get();
- }
- void SetShouldDeferInvalidationForMainFrame(bool defer) {
- // Set the CompositorTimingHistory so that main thread is identified to be
- // fast or slow.
- base::TimeDelta delta;
- if (!defer)
- delta = base::Seconds(1);
- fake_compositor_timing_history_
- ->SetBeginMainFrameStartToReadyToCommitDurationEstimate(delta);
- fake_compositor_timing_history_
- ->SetBeginMainFrameQueueDurationCriticalEstimate(delta);
- fake_compositor_timing_history_
- ->SetBeginMainFrameQueueDurationNotCriticalEstimate(delta);
- fake_compositor_timing_history_->SetDrawDurationEstimate(base::TimeDelta());
- }
- void AdvanceAndMissOneFrame();
- void CheckMainFrameNotSkippedAfterLateCommit();
- void ImplFrameNotSkippedAfterLateAck();
- void BeginFramesNotFromClient(BeginFrameSourceType bfs_type);
- void BeginFramesNotFromClient_IsDrawThrottled(BeginFrameSourceType bfs_type);
- bool BeginMainFrameOnCriticalPath(TreePriority tree_priority,
- ScrollHandlerState scroll_handler_state,
- base::TimeDelta durations);
- scoped_refptr<SchedulerTestTaskRunner> task_runner_;
- std::unique_ptr<viz::FakeExternalBeginFrameSource>
- fake_external_begin_frame_source_;
- std::unique_ptr<viz::SyntheticBeginFrameSource> synthetic_frame_source_;
- std::unique_ptr<viz::SyntheticBeginFrameSource> unthrottled_frame_source_;
- SchedulerSettings scheduler_settings_;
- std::unique_ptr<FakeSchedulerClient> client_;
- PowerModeArbiter power_mode_arbiter_;
- std::unique_ptr<TestScheduler> scheduler_;
- raw_ptr<FakeCompositorTimingHistory> fake_compositor_timing_history_;
- DroppedFrameCounter dropped_counter;
- std::unique_ptr<CompositorFrameReportingController> reporting_controller;
- };
- TEST_F(SchedulerTest, InitializeLayerTreeFrameSinkDoesNotBeginImplFrame) {
- SetUpSchedulerWithNoLayerTreeFrameSink(EXTERNAL_BFS);
- scheduler_->SetVisible(true);
- scheduler_->SetCanDraw(true);
- EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation");
- client_->Reset();
- scheduler_->DidCreateAndInitializeLayerTreeFrameSink();
- EXPECT_NO_ACTION();
- }
- TEST_F(SchedulerTest, Stop) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- // No scheduled actions are performed after Stop. WillBeginImplFrame is only
- // a notification and not an action performed by the scheduler.
- scheduler_->Stop();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- client_->Reset();
- }
- TEST_F(SchedulerTest, VideoNeedsBeginFrames) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetVideoNeedsBeginFrames(true);
- EXPECT_ACTIONS("AddObserver(this)");
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- // WillBeginImplFrame is responsible for sending BeginFrames to video.
- EXPECT_ACTIONS("WillBeginImplFrame");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- client_->Reset();
- scheduler_->SetVideoNeedsBeginFrames(false);
- EXPECT_NO_ACTION();
- client_->Reset();
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- EXPECT_ACTIONS("RemoveObserver(this)");
- EXPECT_FALSE(scheduler_->begin_frames_expected());
- }
- TEST_F(SchedulerTest, RequestCommit) {
- SetUpScheduler(EXTERNAL_BFS);
- // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- // If we don't swap on the deadline, we wait for the next BeginFrame.
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_NO_ACTION();
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- // NotifyReadyToCommit should trigger the commit.
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- // NotifyReadyToActivate should trigger the activation.
- scheduler_->NotifyReadyToActivate();
- EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- // BeginImplFrame should prepare the draw.
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- // BeginImplFrame deadline should draw.
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- // The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
- // to avoid excessive toggles.
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("RemoveObserver(this)");
- client_->Reset();
- }
- TEST_F(SchedulerTest, RequestCommitAfterSetDeferBeginMainFrame) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetDeferBeginMainFrame(true);
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_NO_ACTION();
- client_->Reset();
- task_runner_->RunPendingTasks();
- // There are no pending tasks or actions.
- EXPECT_NO_ACTION();
- EXPECT_FALSE(scheduler_->begin_frames_expected());
- client_->Reset();
- scheduler_->SetDeferBeginMainFrame(false);
- EXPECT_ACTIONS("AddObserver(this)");
- // Start new BeginMainFrame after defer commit is off.
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- }
- TEST_F(SchedulerTest, DeferBeginMainFrameWithRedraw) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetDeferBeginMainFrame(true);
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_NO_ACTION();
- // The SetNeedsRedraw will override the SetDeferBeginMainFrame(true), to
- // allow a begin frame to be needed.
- client_->Reset();
- scheduler_->SetNeedsRedraw();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- AdvanceFrame();
- // BeginMainFrame is not sent during the defer commit is on.
- EXPECT_ACTIONS("WillBeginImplFrame");
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- AdvanceFrame();
- EXPECT_ACTIONS("WillBeginImplFrame");
- }
- TEST_F(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
- SetUpScheduler(EXTERNAL_BFS);
- // SetNeedsBeginMainFrame should begin the frame.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- // Now SetNeedsBeginMainFrame again. Calling here means we need a second
- // commit.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_NO_ACTION();
- client_->Reset();
- // Finish the first commit.
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // Activate it.
- scheduler_->NotifyReadyToActivate();
- EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- // Because we just swapped, the Scheduler should also request the next
- // BeginImplFrame from the LayerTreeFrameSink.
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- // Since another commit is needed, the next BeginImplFrame should initiate
- // the second commit.
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // Finishing the commit before the deadline should post a new deadline task
- // to trigger the deadline early.
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- scheduler_->NotifyReadyToActivate();
- EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- // On the next BeginImplFrame, verify we go back to a quiescent state and
- // no longer request BeginImplFrames.
- EXPECT_SCOPED(AdvanceFrame());
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_FALSE(scheduler_->begin_frames_expected());
- client_->Reset();
- }
- class SchedulerClientThatsetNeedsDrawInsideDraw : public FakeSchedulerClient {
- public:
- SchedulerClientThatsetNeedsDrawInsideDraw()
- : FakeSchedulerClient(), request_redraws_(false) {}
- void SetRequestRedrawsInsideDraw(bool enable) { request_redraws_ = enable; }
- DrawResult ScheduledActionDrawIfPossible() override {
- // Only SetNeedsRedraw the first time this is called
- if (request_redraws_) {
- scheduler_->SetNeedsRedraw();
- }
- return FakeSchedulerClient::ScheduledActionDrawIfPossible();
- }
- DrawResult ScheduledActionDrawForced() override {
- NOTREACHED();
- return DRAW_SUCCESS;
- }
- private:
- bool request_redraws_;
- };
- // Tests for two different situations:
- // 1. the scheduler dropping SetNeedsRedraw requests that happen inside
- // a ScheduledActionDraw
- // 2. the scheduler drawing twice inside a single tick
- TEST_F(SchedulerTest, RequestRedrawInsideDraw) {
- SchedulerClientThatsetNeedsDrawInsideDraw* client =
- new SchedulerClientThatsetNeedsDrawInsideDraw;
- SetUpScheduler(EXTERNAL_BFS, base::WrapUnique(client));
- client->SetRequestRedrawsInsideDraw(true);
- scheduler_->SetNeedsRedraw();
- EXPECT_TRUE(scheduler_->RedrawPending());
- EXPECT_TRUE(client->needs_begin_frames());
- EXPECT_EQ(0, client->num_draws());
- EXPECT_SCOPED(AdvanceFrame());
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client->num_draws());
- EXPECT_TRUE(scheduler_->RedrawPending());
- EXPECT_TRUE(client->needs_begin_frames());
- client->SetRequestRedrawsInsideDraw(false);
- EXPECT_SCOPED(AdvanceFrame());
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(2, client_->num_draws());
- EXPECT_FALSE(scheduler_->RedrawPending());
- EXPECT_TRUE(client->needs_begin_frames());
- // We stop requesting BeginImplFrames after a BeginImplFrame where we don't
- // swap.
- EXPECT_SCOPED(AdvanceFrame());
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(2, client->num_draws());
- EXPECT_FALSE(scheduler_->RedrawPending());
- EXPECT_FALSE(client->needs_begin_frames());
- }
- // Test that requesting redraw inside a failed draw doesn't lose the request.
- TEST_F(SchedulerTest, RequestRedrawInsideFailedDraw) {
- SchedulerClientThatsetNeedsDrawInsideDraw* client =
- new SchedulerClientThatsetNeedsDrawInsideDraw;
- SetUpScheduler(EXTERNAL_BFS, base::WrapUnique(client));
- client->SetRequestRedrawsInsideDraw(true);
- client->SetDrawWillHappen(false);
- scheduler_->SetNeedsRedraw();
- EXPECT_TRUE(scheduler_->RedrawPending());
- EXPECT_TRUE(client->needs_begin_frames());
- EXPECT_EQ(0, client->num_draws());
- // Fail the draw.
- EXPECT_SCOPED(AdvanceFrame());
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client->num_draws());
- // We have a commit pending and the draw failed, and we didn't lose the redraw
- // request.
- EXPECT_TRUE(scheduler_->CommitPending());
- EXPECT_TRUE(scheduler_->RedrawPending());
- EXPECT_TRUE(client->needs_begin_frames());
- client->SetRequestRedrawsInsideDraw(false);
- // Fail the draw again.
- EXPECT_SCOPED(AdvanceFrame());
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(2, client->num_draws());
- EXPECT_TRUE(scheduler_->CommitPending());
- EXPECT_TRUE(scheduler_->RedrawPending());
- EXPECT_TRUE(client->needs_begin_frames());
- // Draw successfully.
- client->SetDrawWillHappen(true);
- EXPECT_SCOPED(AdvanceFrame());
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(3, client->num_draws());
- EXPECT_TRUE(scheduler_->CommitPending());
- EXPECT_FALSE(scheduler_->RedrawPending());
- EXPECT_TRUE(client->needs_begin_frames());
- }
- class SchedulerClientThatSetNeedsBeginMainFrameInsideDraw
- : public FakeSchedulerClient {
- public:
- SchedulerClientThatSetNeedsBeginMainFrameInsideDraw()
- : set_needs_commit_on_next_draw_(false) {}
- DrawResult ScheduledActionDrawIfPossible() override {
- // Only SetNeedsBeginMainFrame the first time this is called
- if (set_needs_commit_on_next_draw_) {
- scheduler_->SetNeedsBeginMainFrame();
- set_needs_commit_on_next_draw_ = false;
- }
- return FakeSchedulerClient::ScheduledActionDrawIfPossible();
- }
- DrawResult ScheduledActionDrawForced() override {
- NOTREACHED();
- return DRAW_SUCCESS;
- }
- void SetNeedsBeginMainFrameOnNextDraw() {
- set_needs_commit_on_next_draw_ = true;
- }
- private:
- bool set_needs_commit_on_next_draw_;
- };
- // Tests for the scheduler infinite-looping on SetNeedsBeginMainFrame requests
- // that happen inside a ScheduledActionDraw
- TEST_F(SchedulerTest, RequestCommitInsideDraw) {
- SchedulerClientThatSetNeedsBeginMainFrameInsideDraw* client =
- new SchedulerClientThatSetNeedsBeginMainFrameInsideDraw;
- SetUpScheduler(EXTERNAL_BFS, base::WrapUnique(client));
- EXPECT_FALSE(client->needs_begin_frames());
- scheduler_->SetNeedsRedraw();
- EXPECT_TRUE(scheduler_->RedrawPending());
- EXPECT_EQ(0, client->num_draws());
- EXPECT_TRUE(client->needs_begin_frames());
- client->SetNeedsBeginMainFrameOnNextDraw();
- EXPECT_SCOPED(AdvanceFrame());
- client->SetNeedsBeginMainFrameOnNextDraw();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client->num_draws());
- EXPECT_TRUE(scheduler_->CommitPending());
- EXPECT_TRUE(client->needs_begin_frames());
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- scheduler_->NotifyReadyToActivate();
- EXPECT_SCOPED(AdvanceFrame());
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(2, client->num_draws());
- EXPECT_FALSE(scheduler_->RedrawPending());
- EXPECT_FALSE(scheduler_->CommitPending());
- EXPECT_TRUE(client->needs_begin_frames());
- // We stop requesting BeginImplFrames after a BeginImplFrame where we don't
- // swap.
- EXPECT_SCOPED(AdvanceFrame());
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(2, client->num_draws());
- EXPECT_FALSE(scheduler_->RedrawPending());
- EXPECT_FALSE(scheduler_->CommitPending());
- EXPECT_FALSE(client->needs_begin_frames());
- }
- // Tests that when a draw fails then the pending commit should not be dropped.
- TEST_F(SchedulerTest, RequestCommitInsideFailedDraw) {
- SchedulerClientThatsetNeedsDrawInsideDraw* client =
- new SchedulerClientThatsetNeedsDrawInsideDraw;
- SetUpScheduler(EXTERNAL_BFS, base::WrapUnique(client));
- client->SetDrawWillHappen(false);
- scheduler_->SetNeedsRedraw();
- EXPECT_TRUE(scheduler_->RedrawPending());
- EXPECT_TRUE(client->needs_begin_frames());
- EXPECT_EQ(0, client->num_draws());
- // Fail the draw.
- EXPECT_SCOPED(AdvanceFrame());
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client->num_draws());
- // We have a commit pending and the draw failed, and we didn't lose the commit
- // request.
- EXPECT_TRUE(scheduler_->CommitPending());
- EXPECT_TRUE(scheduler_->RedrawPending());
- EXPECT_TRUE(client->needs_begin_frames());
- // Fail the draw again.
- EXPECT_SCOPED(AdvanceFrame());
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(2, client->num_draws());
- EXPECT_TRUE(scheduler_->CommitPending());
- EXPECT_TRUE(scheduler_->RedrawPending());
- EXPECT_TRUE(client->needs_begin_frames());
- // Draw successfully.
- client->SetDrawWillHappen(true);
- EXPECT_SCOPED(AdvanceFrame());
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(3, client->num_draws());
- EXPECT_TRUE(scheduler_->CommitPending());
- EXPECT_FALSE(scheduler_->RedrawPending());
- EXPECT_TRUE(client->needs_begin_frames());
- }
- TEST_F(SchedulerTest, NoSwapWhenDrawFails) {
- SchedulerClientThatSetNeedsBeginMainFrameInsideDraw* client =
- new SchedulerClientThatSetNeedsBeginMainFrameInsideDraw;
- SetUpScheduler(EXTERNAL_BFS, base::WrapUnique(client));
- scheduler_->SetNeedsRedraw();
- EXPECT_TRUE(scheduler_->RedrawPending());
- EXPECT_TRUE(client->needs_begin_frames());
- EXPECT_EQ(0, client->num_draws());
- // Draw successfully, this starts a new frame.
- client->SetNeedsBeginMainFrameOnNextDraw();
- EXPECT_SCOPED(AdvanceFrame());
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client->num_draws());
- scheduler_->SetNeedsRedraw();
- EXPECT_TRUE(scheduler_->RedrawPending());
- EXPECT_TRUE(client->needs_begin_frames());
- // Fail to draw, this should not start a frame.
- client->SetDrawWillHappen(false);
- client->SetNeedsBeginMainFrameOnNextDraw();
- EXPECT_SCOPED(AdvanceFrame());
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(2, client->num_draws());
- }
- class SchedulerClientNeedsPrepareTilesInDraw : public FakeSchedulerClient {
- public:
- DrawResult ScheduledActionDrawIfPossible() override {
- scheduler_->SetNeedsPrepareTiles();
- return FakeSchedulerClient::ScheduledActionDrawIfPossible();
- }
- };
- // Test prepare tiles is independant of draws.
- TEST_F(SchedulerTest, PrepareTiles) {
- SchedulerClientNeedsPrepareTilesInDraw* client =
- new SchedulerClientNeedsPrepareTilesInDraw;
- SetUpScheduler(EXTERNAL_BFS, base::WrapUnique(client));
- // Request both draw and prepare tiles. PrepareTiles shouldn't
- // be trigged until BeginImplFrame.
- client->Reset();
- scheduler_->SetNeedsPrepareTiles();
- scheduler_->SetNeedsRedraw();
- EXPECT_TRUE(scheduler_->RedrawPending());
- EXPECT_TRUE(scheduler_->PrepareTilesPending());
- EXPECT_TRUE(client->needs_begin_frames());
- EXPECT_EQ(0, client->num_draws());
- EXPECT_FALSE(client->HasAction("ScheduledActionPrepareTiles"));
- EXPECT_FALSE(client->HasAction("ScheduledActionDrawIfPossible"));
- // We have no immediate actions to perform, so the BeginImplFrame should post
- // the deadline task.
- client->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- // On the deadline, the actions should have occured in the right order.
- client->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client->num_draws());
- EXPECT_TRUE(client->HasAction("ScheduledActionDrawIfPossible"));
- EXPECT_TRUE(client->HasAction("ScheduledActionPrepareTiles"));
- EXPECT_LT(client->ActionIndex("ScheduledActionDrawIfPossible"),
- client->ActionIndex("ScheduledActionPrepareTiles"));
- EXPECT_FALSE(scheduler_->RedrawPending());
- EXPECT_FALSE(scheduler_->PrepareTilesPending());
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- // Request a draw. We don't need a PrepareTiles yet.
- client->Reset();
- scheduler_->SetNeedsRedraw();
- EXPECT_TRUE(scheduler_->RedrawPending());
- EXPECT_FALSE(scheduler_->PrepareTilesPending());
- EXPECT_TRUE(client->needs_begin_frames());
- EXPECT_EQ(0, client->num_draws());
- // We have no immediate actions to perform, so the BeginImplFrame should post
- // the deadline task.
- client->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- // Draw. The draw will trigger SetNeedsPrepareTiles, and
- // then the PrepareTiles action will be triggered after the Draw.
- // Afterwards, neither a draw nor PrepareTiles are pending.
- client->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client->num_draws());
- EXPECT_TRUE(client->HasAction("ScheduledActionDrawIfPossible"));
- EXPECT_TRUE(client->HasAction("ScheduledActionPrepareTiles"));
- EXPECT_LT(client->ActionIndex("ScheduledActionDrawIfPossible"),
- client->ActionIndex("ScheduledActionPrepareTiles"));
- EXPECT_FALSE(scheduler_->RedrawPending());
- EXPECT_FALSE(scheduler_->PrepareTilesPending());
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- // We need a BeginImplFrame where we don't swap to go idle.
- client->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("RemoveObserver(this)");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- EXPECT_EQ(0, client->num_draws());
- // Now trigger a PrepareTiles outside of a draw. We will then need
- // a begin-frame for the PrepareTiles, but we don't need a draw.
- client->Reset();
- EXPECT_FALSE(client->needs_begin_frames());
- scheduler_->SetNeedsPrepareTiles();
- EXPECT_TRUE(client->needs_begin_frames());
- EXPECT_TRUE(scheduler_->PrepareTilesPending());
- EXPECT_FALSE(scheduler_->RedrawPending());
- // BeginImplFrame. There will be no draw, only PrepareTiles.
- client->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(0, client->num_draws());
- EXPECT_FALSE(client->HasAction("ScheduledActionDrawIfPossible"));
- EXPECT_TRUE(client->HasAction("ScheduledActionPrepareTiles"));
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- }
- // Test that PrepareTiles only happens once per frame. If an external caller
- // initiates it, then the state machine should not PrepareTiles on that frame.
- TEST_F(SchedulerTest, PrepareTilesOncePerFrame) {
- SetUpScheduler(EXTERNAL_BFS);
- // If DidPrepareTiles during a frame, then PrepareTiles should not occur
- // again.
- scheduler_->SetNeedsPrepareTiles();
- scheduler_->SetNeedsRedraw();
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- EXPECT_TRUE(scheduler_->PrepareTilesPending());
- scheduler_->WillPrepareTiles();
- scheduler_->DidPrepareTiles(); // An explicit PrepareTiles.
- EXPECT_FALSE(scheduler_->PrepareTilesPending());
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client_->num_draws());
- EXPECT_TRUE(client_->HasAction("ScheduledActionDrawIfPossible"));
- EXPECT_FALSE(client_->HasAction("ScheduledActionPrepareTiles"));
- EXPECT_FALSE(scheduler_->RedrawPending());
- EXPECT_FALSE(scheduler_->PrepareTilesPending());
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- // Next frame without DidPrepareTiles should PrepareTiles with draw.
- scheduler_->SetNeedsPrepareTiles();
- scheduler_->SetNeedsRedraw();
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client_->num_draws());
- EXPECT_TRUE(client_->HasAction("ScheduledActionDrawIfPossible"));
- EXPECT_TRUE(client_->HasAction("ScheduledActionPrepareTiles"));
- EXPECT_LT(client_->ActionIndex("ScheduledActionDrawIfPossible"),
- client_->ActionIndex("ScheduledActionPrepareTiles"));
- EXPECT_FALSE(scheduler_->RedrawPending());
- EXPECT_FALSE(scheduler_->PrepareTilesPending());
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- // If we get another DidPrepareTiles within the same frame, we should
- // not PrepareTiles on the next frame.
- scheduler_->WillPrepareTiles();
- scheduler_->DidPrepareTiles(); // An explicit PrepareTiles.
- scheduler_->SetNeedsPrepareTiles();
- scheduler_->SetNeedsRedraw();
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- EXPECT_TRUE(scheduler_->PrepareTilesPending());
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client_->num_draws());
- EXPECT_TRUE(client_->HasAction("ScheduledActionDrawIfPossible"));
- EXPECT_FALSE(client_->HasAction("ScheduledActionPrepareTiles"));
- EXPECT_FALSE(scheduler_->RedrawPending());
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- // If we get another DidPrepareTiles, we should not PrepareTiles on the next
- // frame. This verifies we don't alternate calling PrepareTiles once and
- // twice.
- EXPECT_TRUE(scheduler_->PrepareTilesPending());
- scheduler_->WillPrepareTiles();
- scheduler_->DidPrepareTiles(); // An explicit PrepareTiles.
- EXPECT_FALSE(scheduler_->PrepareTilesPending());
- scheduler_->SetNeedsPrepareTiles();
- scheduler_->SetNeedsRedraw();
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- EXPECT_TRUE(scheduler_->PrepareTilesPending());
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client_->num_draws());
- EXPECT_TRUE(client_->HasAction("ScheduledActionDrawIfPossible"));
- EXPECT_FALSE(client_->HasAction("ScheduledActionPrepareTiles"));
- EXPECT_FALSE(scheduler_->RedrawPending());
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- // Next frame without DidPrepareTiles should PrepareTiles with draw.
- scheduler_->SetNeedsPrepareTiles();
- scheduler_->SetNeedsRedraw();
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client_->num_draws());
- EXPECT_TRUE(client_->HasAction("ScheduledActionDrawIfPossible"));
- EXPECT_TRUE(client_->HasAction("ScheduledActionPrepareTiles"));
- EXPECT_LT(client_->ActionIndex("ScheduledActionDrawIfPossible"),
- client_->ActionIndex("ScheduledActionPrepareTiles"));
- EXPECT_FALSE(scheduler_->RedrawPending());
- EXPECT_FALSE(scheduler_->PrepareTilesPending());
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- }
- TEST_F(SchedulerTest, DidPrepareTilesPreventsPrepareTilesForOneFrame) {
- std::unique_ptr<SchedulerClientNeedsPrepareTilesInDraw> client =
- base::WrapUnique(new SchedulerClientNeedsPrepareTilesInDraw);
- SetUpScheduler(EXTERNAL_BFS, std::move(client));
- client_->Reset();
- scheduler_->SetNeedsRedraw();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible",
- "ScheduledActionPrepareTiles");
- // We don't want to hinder scheduled prepare tiles for more than one frame
- // even if we call unscheduled prepare tiles many times.
- for (int i = 0; i < 10; i++) {
- scheduler_->WillPrepareTiles();
- scheduler_->DidPrepareTiles();
- }
- client_->Reset();
- scheduler_->SetNeedsRedraw();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- // No scheduled prepare tiles because we've already counted a prepare tiles in
- // between frames.
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- client_->Reset();
- scheduler_->SetNeedsRedraw();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- // Resume scheduled prepare tiles.
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible",
- "ScheduledActionPrepareTiles");
- }
- TEST_F(SchedulerTest, TriggerBeginFrameDeadlineEarly) {
- SchedulerClientNeedsPrepareTilesInDraw* client =
- new SchedulerClientNeedsPrepareTilesInDraw;
- SetUpScheduler(EXTERNAL_BFS, base::WrapUnique(client));
- scheduler_->SetNeedsRedraw();
- EXPECT_SCOPED(AdvanceFrame());
- // The deadline should be zero since there is no work other than drawing
- // pending.
- EXPECT_EQ(base::TimeTicks(), client->posted_begin_impl_frame_deadline());
- }
- TEST_F(SchedulerTest, WaitForReadyToDrawDoNotPostDeadline) {
- SchedulerClientNeedsPrepareTilesInDraw* client =
- new SchedulerClientNeedsPrepareTilesInDraw;
- scheduler_settings_.commit_to_active_tree = true;
- SetUpScheduler(EXTERNAL_BFS, base::WrapUnique(client));
- // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- // Begin new frame.
- EXPECT_SCOPED(AdvanceFrame());
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- client_->Reset();
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
- client_->Reset();
- scheduler_->NotifyReadyToActivate();
- EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
- // Scheduler won't post deadline in the mode.
- client_->Reset();
- task_runner_->RunPendingTasks(); // Try to run posted deadline.
- // There is no posted deadline.
- EXPECT_NO_ACTION();
- // Scheduler received ready to draw signal, and posted deadline.
- scheduler_->NotifyReadyToDraw();
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(1, client_->num_draws());
- EXPECT_TRUE(client_->HasAction("ScheduledActionDrawIfPossible"));
- }
- TEST_F(SchedulerTest, WaitForReadyToDrawCancelledWhenLostLayerTreeFrameSink) {
- SchedulerClientNeedsPrepareTilesInDraw* client =
- new SchedulerClientNeedsPrepareTilesInDraw;
- scheduler_settings_.commit_to_active_tree = true;
- SetUpScheduler(EXTERNAL_BFS, base::WrapUnique(client));
- // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- // Begin new frame.
- EXPECT_SCOPED(AdvanceFrame());
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- client_->Reset();
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
- client_->Reset();
- scheduler_->NotifyReadyToActivate();
- EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
- // Scheduler won't post deadline in the mode.
- client_->Reset();
- task_runner_->RunPendingTasks(); // Try to run posted deadline.
- // There is no posted deadline.
- EXPECT_NO_ACTION();
- // Scheduler loses LayerTreeFrameSink, and stops waiting for ready to draw
- // signal.
- client_->Reset();
- scheduler_->DidLoseLayerTreeFrameSink();
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation",
- "RemoveObserver(this)");
- }
- void SchedulerTest::AdvanceAndMissOneFrame() {
- // Impl thread hits deadline before commit finishes.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- scheduler_->NotifyReadyToActivate();
- EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame",
- "ScheduledActionSendBeginMainFrame", "ScheduledActionCommit",
- "ScheduledActionPostCommit",
- "ScheduledActionActivateSyncTree");
- EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- client_->Reset();
- }
- void SchedulerTest::CheckMainFrameNotSkippedAfterLateCommit() {
- AdvanceAndMissOneFrame();
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- EXPECT_TRUE(client_->HasAction("WillBeginImplFrame"));
- EXPECT_TRUE(client_->HasAction("ScheduledActionSendBeginMainFrame"));
- }
- TEST_F(SchedulerTest, MainFrameNotSkippedAfterLateBeginFrame) {
- // If a begin frame is delivered extremely late (because the browser has
- // some contention), make sure that the main frame is not skipped even
- // if it can activate before the deadline.
- SetUpScheduler(EXTERNAL_BFS);
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- AdvanceAndMissOneFrame();
- EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- scheduler_->SetNeedsBeginMainFrame();
- // Advance frame and create a begin frame.
- task_runner_->AdvanceMockTickClock(viz::BeginFrameArgs::DefaultInterval());
- viz::BeginFrameArgs args =
- fake_external_begin_frame_source_->CreateBeginFrameArgs(
- BEGINFRAME_FROM_HERE, task_runner_->GetMockTickClock());
- // Deliver this begin frame super late.
- task_runner_->AdvanceMockTickClock(viz::BeginFrameArgs::DefaultInterval() *
- 100);
- fake_external_begin_frame_source_->TestOnBeginFrame(args);
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_EQ(true, scheduler_->MainThreadMissedLastDeadline());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
- "ScheduledActionDrawIfPossible");
- }
- TEST_F(SchedulerTest, FrameIntervalUpdated) {
- // Verify that the SchedulerClient gets updates when the begin frame interval
- // changes.
- SetUpScheduler(EXTERNAL_BFS);
- constexpr uint64_t kSourceId = viz::BeginFrameArgs::kStartingSourceId;
- uint64_t sequence_number = viz::BeginFrameArgs::kStartingFrameNumber;
- base::TimeDelta interval =
- base::Microseconds(base::Time::kMicrosecondsPerSecond / 120.0);
- // Send BeginFrameArgs with 120hz refresh rate and confirm client gets update.
- scheduler_->SetNeedsRedraw();
- task_runner_->AdvanceMockTickClock(interval);
- viz::BeginFrameArgs args1 = viz::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, kSourceId, sequence_number++,
- task_runner_->NowTicks(), task_runner_->NowTicks() + interval, interval,
- viz::BeginFrameArgs::NORMAL);
- fake_external_begin_frame_source_->TestOnBeginFrame(args1);
- EXPECT_EQ(client_->frame_interval(), interval);
- // Send another BeginFrameArgs with 120hz refresh rate that arrives late. Even
- // though the interval between begin frames arriving is bigger than |interval|
- // the client only hears the interval specified in BeginFrameArgs.
- scheduler_->SetNeedsRedraw();
- const base::TimeDelta late_delta = base::Milliseconds(4);
- task_runner_->AdvanceMockTickClock(interval + late_delta);
- viz::BeginFrameArgs args2 = viz::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, kSourceId, sequence_number++, args1.deadline,
- args1.deadline + interval, interval, viz::BeginFrameArgs::NORMAL);
- fake_external_begin_frame_source_->TestOnBeginFrame(args2);
- EXPECT_EQ(client_->frame_interval(), interval);
- // Change the interval for 90hz refresh rate.
- interval = base::Microseconds(base::Time::kMicrosecondsPerSecond / 90.0);
- // Send BeginFrameArgs with 90hz refresh rate and confirm client gets update.
- scheduler_->SetNeedsRedraw();
- task_runner_->AdvanceMockTickClock(args2.deadline - task_runner_->NowTicks());
- viz::BeginFrameArgs args3 = viz::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, kSourceId, sequence_number++, args2.deadline,
- args2.deadline + interval, interval, viz::BeginFrameArgs::NORMAL);
- fake_external_begin_frame_source_->TestOnBeginFrame(args3);
- EXPECT_EQ(client_->frame_interval(), interval);
- // Send BeginFrameArgs with zero interval. This isn't a valid interval and
- // client shouldn't find out about it.
- scheduler_->SetNeedsRedraw();
- task_runner_->AdvanceMockTickClock(interval);
- viz::BeginFrameArgs args4 = viz::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, kSourceId, sequence_number++, args3.deadline,
- args3.deadline + interval, base::TimeDelta(),
- viz::BeginFrameArgs::NORMAL);
- fake_external_begin_frame_source_->TestOnBeginFrame(args4);
- EXPECT_EQ(client_->frame_interval(), interval);
- }
- TEST_F(SchedulerTest, MainFrameNotSkippedAfterLateCommit) {
- SetUpScheduler(EXTERNAL_BFS);
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- EXPECT_SCOPED(CheckMainFrameNotSkippedAfterLateCommit());
- }
- // Response times of BeginMainFrame's without the critical path flag set
- // should not affect whether we recover latency or not.
- TEST_F(
- SchedulerTest,
- MainFrameNotSkippedAfterLateCommit_LongMainFrameQueueDurationNotCritical) {
- SetUpScheduler(EXTERNAL_BFS);
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- fake_compositor_timing_history_
- ->SetBeginMainFrameQueueDurationNotCriticalEstimate(kSlowDuration);
- EXPECT_SCOPED(CheckMainFrameNotSkippedAfterLateCommit());
- }
- // Response times of BeginMainFrame's with the critical path flag set
- // should affect whether we recover latency or not.
- TEST_F(SchedulerTest,
- MainFrameNotSkippedAfterLateCommit_LongMainFrameQueueDurationCritical) {
- SetUpScheduler(EXTERNAL_BFS);
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- fake_compositor_timing_history_
- ->SetBeginMainFrameQueueDurationCriticalEstimate(kSlowDuration);
- fake_compositor_timing_history_
- ->SetBeginMainFrameQueueDurationNotCriticalEstimate(kSlowDuration);
- EXPECT_SCOPED(CheckMainFrameNotSkippedAfterLateCommit());
- }
- TEST_F(SchedulerTest,
- MainFrameNotSkippedAfterLateCommitInPreferImplLatencyMode) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetTreePrioritiesAndScrollState(
- SMOOTHNESS_TAKES_PRIORITY,
- ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER);
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- EXPECT_SCOPED(CheckMainFrameNotSkippedAfterLateCommit());
- }
- TEST_F(SchedulerTest,
- MainFrameNotSkippedAfterLateCommit_CommitEstimateTooLong) {
- SetUpScheduler(EXTERNAL_BFS);
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- fake_compositor_timing_history_
- ->SetBeginMainFrameStartToReadyToCommitDurationEstimate(kSlowDuration);
- EXPECT_SCOPED(CheckMainFrameNotSkippedAfterLateCommit());
- }
- TEST_F(SchedulerTest,
- MainFrameNotSkippedAfterLateCommit_ReadyToActivateEstimateTooLong) {
- SetUpScheduler(EXTERNAL_BFS);
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- fake_compositor_timing_history_->SetCommitToReadyToActivateDurationEstimate(
- kSlowDuration);
- EXPECT_SCOPED(CheckMainFrameNotSkippedAfterLateCommit());
- }
- TEST_F(SchedulerTest,
- MainFrameNotSkippedAfterLateCommit_ActivateEstimateTooLong) {
- SetUpScheduler(EXTERNAL_BFS);
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- fake_compositor_timing_history_->SetActivateDurationEstimate(kSlowDuration);
- EXPECT_SCOPED(CheckMainFrameNotSkippedAfterLateCommit());
- }
- TEST_F(SchedulerTest, MainFrameNotSkippedAfterLateCommit_DrawEstimateTooLong) {
- SetUpScheduler(EXTERNAL_BFS);
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- fake_compositor_timing_history_->SetDrawDurationEstimate(kSlowDuration);
- EXPECT_SCOPED(CheckMainFrameNotSkippedAfterLateCommit());
- }
- // If the BeginMainFrame aborts, it doesn't actually insert a frame into the
- // queue, which means there is no latency to recover.
- TEST_F(SchedulerTest, MainFrameNotSkippedAfterLateBeginMainFrameAbort) {
- SetUpScheduler(EXTERNAL_BFS);
- // Use fast estimates so we think we can recover latency if needed.
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- // Impl thread hits deadline before BeginMainFrame aborts.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame",
- "ScheduledActionSendBeginMainFrame");
- EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- // After aborting the frame, make sure we don't skip the
- // next BeginMainFrame.
- client_->Reset();
- scheduler_->BeginMainFrameAborted(CommitEarlyOutReason::FINISHED_NO_UPDATES);
- EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_TRUE(client_->HasAction("WillBeginImplFrame"));
- EXPECT_TRUE(client_->HasAction("ScheduledActionSendBeginMainFrame"));
- EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- }
- // If the BeginMainFrame aborts, it doesn't actually insert a frame into the
- // queue, which means there is no latency to recover.
- TEST_F(SchedulerTest, MainFrameNotSkippedAfterCanDrawChanges) {
- SetUpScheduler(EXTERNAL_BFS);
- // Use fast estimates so we think we can recover latency if needed.
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- // Impl thread hits deadline before BeginMainFrame aborts.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame",
- "ScheduledActionSendBeginMainFrame");
- EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- // Make us abort the upcoming draw.
- client_->Reset();
- scheduler_->NotifyReadyToCommit(nullptr);
- scheduler_->NotifyReadyToActivate();
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit",
- "ScheduledActionActivateSyncTree");
- EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- scheduler_->SetCanDraw(false);
- EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- // Make CanDraw true after activation.
- client_->Reset();
- scheduler_->SetCanDraw(true);
- EXPECT_NO_ACTION();
- EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- // Make sure we don't skip the next BeginMainFrame.
- client_->Reset();
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_TRUE(client_->HasAction("WillBeginImplFrame"));
- EXPECT_TRUE(client_->HasAction("ScheduledActionSendBeginMainFrame"));
- EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- }
- TEST_F(SchedulerTest, MainFrameNotSkippedWhenNoTimingHistory) {
- SetUpScheduler(EXTERNAL_BFS);
- // Use fast estimates so we think we can recover latency if needed.
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- // Impl thread hits deadline before BeginMainFrame commits.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame",
- "ScheduledActionSendBeginMainFrame");
- EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- // Commit after the deadline.
- client_->Reset();
- scheduler_->NotifyReadyToCommit(nullptr);
- scheduler_->NotifyReadyToActivate();
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit",
- "ScheduledActionActivateSyncTree");
- EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
- // Clear the timing history. Make sure we don't skip the main frame until we
- // have history from at least one frame.
- client_->Reset();
- scheduler_->SetNeedsBeginMainFrame();
- scheduler_->ClearHistory();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- }
- void SchedulerTest::ImplFrameNotSkippedAfterLateAck() {
- // To get into a high latency state, this test disables automatic swap acks.
- client_->SetAutomaticSubmitCompositorFrameAck(false);
- // Draw and swap for first BeginFrame
- client_->Reset();
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- SendNextBeginFrame();
- EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame",
- "ScheduledActionSendBeginMainFrame");
- client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- scheduler_->NotifyReadyToActivate();
- EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit",
- "ScheduledActionActivateSyncTree",
- "ScheduledActionDrawIfPossible");
- // Verify impl thread consistently operates in high latency mode
- // without skipping any frames.
- for (int i = 0; i < 10; i++) {
- // Not calling scheduler_->DidReceiveCompositorFrameAck() until after next
- // frame
- // puts the impl thread in high latency mode.
- client_->Reset();
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- SendNextBeginFrame();
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
- client_->Reset();
- scheduler_->DidReceiveCompositorFrameAck();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- scheduler_->NotifyReadyToActivate();
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- // Verify that we don't skip the actions of the BeginImplFrame
- EXPECT_ACTIONS("ScheduledActionSendBeginMainFrame", "ScheduledActionCommit",
- "ScheduledActionPostCommit",
- "ScheduledActionActivateSyncTree",
- "ScheduledActionDrawIfPossible");
- }
- }
- TEST_F(SchedulerTest,
- ImplFrameNotSkippedAfterLateAck_MainFrameQueueDurationCriticalTooLong) {
- SetUpScheduler(EXTERNAL_BFS);
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- fake_compositor_timing_history_
- ->SetBeginMainFrameQueueDurationCriticalEstimate(kSlowDuration);
- fake_compositor_timing_history_
- ->SetBeginMainFrameQueueDurationNotCriticalEstimate(kSlowDuration);
- EXPECT_SCOPED(ImplFrameNotSkippedAfterLateAck());
- }
- TEST_F(SchedulerTest, ImplFrameNotSkippedAfterLateAck_CommitEstimateTooLong) {
- SetUpScheduler(EXTERNAL_BFS);
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- fake_compositor_timing_history_
- ->SetBeginMainFrameStartToReadyToCommitDurationEstimate(kSlowDuration);
- EXPECT_SCOPED(ImplFrameNotSkippedAfterLateAck());
- }
- TEST_F(SchedulerTest,
- ImplFrameNotSkippedAfterLateAck_ReadyToActivateEstimateTooLong) {
- SetUpScheduler(EXTERNAL_BFS);
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- fake_compositor_timing_history_->SetCommitToReadyToActivateDurationEstimate(
- kSlowDuration);
- EXPECT_SCOPED(ImplFrameNotSkippedAfterLateAck());
- }
- TEST_F(SchedulerTest, ImplFrameNotSkippedAfterLateAck_ActivateEstimateTooLong) {
- SetUpScheduler(EXTERNAL_BFS);
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- fake_compositor_timing_history_->SetActivateDurationEstimate(kSlowDuration);
- EXPECT_SCOPED(ImplFrameNotSkippedAfterLateAck());
- }
- TEST_F(SchedulerTest, ImplFrameNotSkippedAfterLateAck_DrawEstimateTooLong) {
- SetUpScheduler(EXTERNAL_BFS);
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- fake_compositor_timing_history_->SetDrawDurationEstimate(kSlowDuration);
- EXPECT_SCOPED(ImplFrameNotSkippedAfterLateAck());
- }
- void SchedulerTest::BeginFramesNotFromClient(BeginFrameSourceType bfs_type) {
- SetUpScheduler(bfs_type);
- // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame
- // without calling SetNeedsBeginFrame.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_NO_ACTION();
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // Can't run the deadline task because it can race with begin frame for the
- // SyntheticBFS case.
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // NotifyReadyToCommit should trigger the commit.
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
- client_->Reset();
- // NotifyReadyToActivate should trigger the activation.
- scheduler_->NotifyReadyToActivate();
- EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
- client_->Reset();
- // BeginImplFrame deadline should draw. The following BeginImplFrame deadline
- // should SetNeedsBeginFrame(false) to avoid excessive toggles.
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible", "WillBeginImplFrame");
- client_->Reset();
- // Make sure SetNeedsBeginFrame isn't called on the client
- // when the BeginFrame is no longer needed.
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_NO_ACTION();
- client_->Reset();
- }
- TEST_F(SchedulerTest, SyntheticBeginFrames) {
- BeginFramesNotFromClient(THROTTLED_BFS);
- }
- TEST_F(SchedulerTest, UnthrottledBeginFrames) {
- BeginFramesNotFromClient(UNTHROTTLED_BFS);
- }
- void SchedulerTest::BeginFramesNotFromClient_IsDrawThrottled(
- BeginFrameSourceType bfs_type) {
- SetUpScheduler(bfs_type);
- // Set the draw duration estimate to zero so that deadlines are accurate.
- fake_compositor_timing_history_->SetDrawDurationEstimate(base::TimeDelta());
- // To test swap ack throttling, this test disables automatic swap acks.
- client_->SetAutomaticSubmitCompositorFrameAck(false);
- // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame.
- client_->Reset();
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_NO_ACTION();
- client_->Reset();
- // Trigger the first BeginImplFrame and BeginMainFrame
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // NotifyReadyToCommit should trigger the pending commit.
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
- client_->Reset();
- // NotifyReadyToActivate should trigger the activation and draw.
- scheduler_->NotifyReadyToActivate();
- EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
- client_->Reset();
- // Swapping will put us into a swap throttled state.
- // Run posted deadline.
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // While swap throttled, BeginFrames should trigger BeginImplFrames,
- // but not a BeginMainFrame or draw.
- scheduler_->SetNeedsBeginMainFrame();
- scheduler_->SetNeedsRedraw();
- EXPECT_SCOPED(AdvanceFrame()); // Run posted BeginFrame.
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- base::TimeTicks before_deadline, after_deadline;
- // The deadline is set to the regular deadline.
- before_deadline = task_runner_->NowTicks();
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- after_deadline = task_runner_->NowTicks();
- // We can't do an equality comparison here because the scheduler uses a fudge
- // factor that's an internal implementation detail.
- EXPECT_GT(after_deadline, before_deadline);
- EXPECT_LT(after_deadline,
- before_deadline + viz::BeginFrameArgs::DefaultInterval());
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame()); // Run posted BeginFrame.
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // Take us out of a swap throttled state.
- scheduler_->DidReceiveCompositorFrameAck();
- EXPECT_ACTIONS("ScheduledActionSendBeginMainFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // The deadline is set to the regular deadline.
- before_deadline = task_runner_->NowTicks();
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- after_deadline = task_runner_->NowTicks();
- // We can't do an equality comparison here because the scheduler uses a fudge
- // factor that's an internal implementation detail.
- EXPECT_GT(after_deadline, before_deadline);
- EXPECT_LT(after_deadline,
- before_deadline + viz::BeginFrameArgs::DefaultInterval());
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- }
- TEST_F(SchedulerTest, SyntheticBeginFrames_IsDrawThrottled) {
- BeginFramesNotFromClient_IsDrawThrottled(THROTTLED_BFS);
- }
- TEST_F(SchedulerTest, UnthrottledBeginFrames_IsDrawThrottled) {
- BeginFramesNotFromClient_IsDrawThrottled(UNTHROTTLED_BFS);
- }
- TEST_F(SchedulerTest,
- DidLoseLayerTreeFrameSinkAfterLayerTreeFrameSinkIsInitialized) {
- SetUpSchedulerWithNoLayerTreeFrameSink(EXTERNAL_BFS);
- scheduler_->SetVisible(true);
- scheduler_->SetCanDraw(true);
- EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation");
- client_->Reset();
- scheduler_->DidCreateAndInitializeLayerTreeFrameSink();
- EXPECT_NO_ACTION();
- scheduler_->DidLoseLayerTreeFrameSink();
- EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation");
- }
- TEST_F(SchedulerTest, DidLoseLayerTreeFrameSinkAfterBeginFrameStarted) {
- SetUpScheduler(EXTERNAL_BFS);
- // SetNeedsBeginMainFrame should begin the frame.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- scheduler_->DidLoseLayerTreeFrameSink();
- // RemoveObserver(this) is not called until the end of the frame.
- EXPECT_NO_ACTION();
- client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit",
- "ScheduledActionActivateSyncTree");
- client_->Reset();
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation",
- "RemoveObserver(this)");
- }
- TEST_F(SchedulerTest,
- DidLoseLayerTreeFrameSinkAfterBeginFrameStartedWithHighLatency) {
- SetUpScheduler(EXTERNAL_BFS);
- // SetNeedsBeginMainFrame should begin the frame.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- scheduler_->DidLoseLayerTreeFrameSink();
- // Do nothing when impl frame is in deadine pending state.
- EXPECT_NO_ACTION();
- client_->Reset();
- // Run posted deadline.
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- // OnBeginImplFrameDeadline didn't schedule LayerTreeFrameSink creation
- // because
- // main frame is not yet completed.
- EXPECT_ACTIONS("RemoveObserver(this)");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- // BeginImplFrame is not started.
- client_->Reset();
- task_runner_->RunUntilTime(task_runner_->NowTicks() + base::Milliseconds(10));
- EXPECT_NO_ACTION();
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit",
- "ScheduledActionActivateSyncTree",
- "ScheduledActionBeginLayerTreeFrameSinkCreation");
- }
- TEST_F(SchedulerTest, DidLoseLayerTreeFrameSinkAfterReadyToCommit) {
- SetUpScheduler(EXTERNAL_BFS);
- // SetNeedsBeginMainFrame should begin the frame.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
- client_->Reset();
- scheduler_->DidLoseLayerTreeFrameSink();
- // Sync tree should be forced to activate.
- EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
- // RemoveObserver(this) is not called until the end of the frame.
- client_->Reset();
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation",
- "RemoveObserver(this)");
- }
- TEST_F(SchedulerTest, DidLoseLayerTreeFrameSinkAfterSetNeedsPrepareTiles) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsPrepareTiles();
- scheduler_->SetNeedsRedraw();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- scheduler_->DidLoseLayerTreeFrameSink();
- // RemoveObserver(this) is not called until the end of the frame.
- EXPECT_NO_ACTION();
- client_->Reset();
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_ACTIONS("ScheduledActionPrepareTiles",
- "ScheduledActionBeginLayerTreeFrameSinkCreation",
- "RemoveObserver(this)");
- }
- TEST_F(SchedulerTest, DidLoseLayerTreeFrameSinkWithDelayBasedBeginFrameSource) {
- SetUpScheduler(THROTTLED_BFS);
- // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame.
- EXPECT_FALSE(scheduler_->begin_frames_expected());
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- AdvanceFrame();
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- // NotifyReadyToCommit should trigger the commit.
- client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- // NotifyReadyToActivate should trigger the activation.
- client_->Reset();
- scheduler_->NotifyReadyToActivate();
- EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- scheduler_->DidLoseLayerTreeFrameSink();
- // RemoveObserver(this) is not called until the end of the frame.
- EXPECT_NO_ACTION();
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation");
- EXPECT_FALSE(scheduler_->begin_frames_expected());
- }
- TEST_F(SchedulerTest, DidLoseLayerTreeFrameSinkWhenIdle) {
- SetUpScheduler(EXTERNAL_BFS);
- // SetNeedsBeginMainFrame should begin the frame.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
- client_->Reset();
- scheduler_->NotifyReadyToActivate();
- EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
- client_->Reset();
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- // Idle time between BeginFrames.
- client_->Reset();
- scheduler_->DidLoseLayerTreeFrameSink();
- EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation",
- "RemoveObserver(this)");
- }
- TEST_F(SchedulerTest, ScheduledActionActivateAfterBecomingInvisible) {
- SetUpScheduler(EXTERNAL_BFS);
- // SetNeedsBeginMainFrame should begin the frame.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- scheduler_->SetVisible(false);
- task_runner_->RunPendingTasks(); // Run posted deadline.
- // Sync tree should be forced to activate.
- EXPECT_ACTIONS("ScheduledActionActivateSyncTree", "RemoveObserver(this)");
- }
- TEST_F(SchedulerTest, ScheduledActionActivateAfterBeginFrameSourcePaused) {
- SetUpScheduler(EXTERNAL_BFS);
- // SetNeedsBeginMainFrame should begin the frame.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- fake_external_begin_frame_source_->SetPaused(true);
- task_runner_->RunPendingTasks(); // Run posted deadline.
- // Sync tree should be forced to activate.
- // Pausing the begin frame source aborts the draw. Then
- // ProactiveBeginFrameWanted is no longer true, so the scheduler stops
- // listening for begin frames.
- EXPECT_ACTIONS("ScheduledActionActivateSyncTree", "RemoveObserver(this)");
- }
- // Tests to ensure frame sources can be successfully changed while drawing.
- TEST_F(SchedulerTest, SwitchFrameSourceToUnthrottled) {
- SetUpScheduler(EXTERNAL_BFS);
- // SetNeedsRedraw should begin the frame on the next BeginImplFrame.
- scheduler_->SetNeedsRedraw();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- scheduler_->SetNeedsRedraw();
- // Switch to an unthrottled frame source.
- scheduler_->SetBeginFrameSource(unthrottled_frame_source_.get());
- client_->Reset();
- // Unthrottled frame source will immediately begin a new frame.
- task_runner_->RunPendingTasks(); // Run posted BeginFrame.
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // If we don't swap on the deadline, we wait for the next BeginFrame.
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- }
- // Tests to ensure frame sources can be successfully changed while a frame
- // deadline is pending.
- TEST_F(SchedulerTest, SwitchFrameSourceToUnthrottledBeforeDeadline) {
- SetUpScheduler(EXTERNAL_BFS);
- // SetNeedsRedraw should begin the frame on the next BeginImplFrame.
- scheduler_->SetNeedsRedraw();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- // Switch to an unthrottled frame source before the frame deadline is hit.
- scheduler_->SetBeginFrameSource(unthrottled_frame_source_.get());
- client_->Reset();
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible",
- // Unthrottled frame source will immediately begin a new frame.
- "WillBeginImplFrame");
- scheduler_->SetNeedsRedraw();
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- }
- // Tests to ensure that the active frame source can successfully be changed from
- // unthrottled to throttled.
- TEST_F(SchedulerTest, SwitchFrameSourceToThrottled) {
- SetUpScheduler(UNTHROTTLED_BFS);
- scheduler_->SetNeedsRedraw();
- EXPECT_NO_ACTION();
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run posted BeginFrame.
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // Switch to a throttled frame source.
- scheduler_->SetBeginFrameSource(fake_external_begin_frame_source_.get());
- client_->Reset();
- // SetNeedsRedraw should begin the frame on the next BeginImplFrame.
- scheduler_->SetNeedsRedraw();
- task_runner_->RunPendingTasks();
- EXPECT_NO_ACTION();
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- }
- TEST_F(SchedulerTest, SwitchFrameSourceToNullInsideDeadline) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsRedraw();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- client_->Reset();
- // Switch to a null frame source.
- scheduler_->SetBeginFrameSource(nullptr);
- EXPECT_ACTIONS("RemoveObserver(this)");
- client_->Reset();
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- EXPECT_FALSE(scheduler_->begin_frames_expected());
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // AdvanceFrame helper can't be used here because there's no deadline posted.
- scheduler_->SetNeedsRedraw();
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- EXPECT_NO_ACTION();
- client_->Reset();
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- EXPECT_NO_ACTION();
- client_->Reset();
- // Switch back to the same source, make sure frames continue to be produced.
- scheduler_->SetBeginFrameSource(fake_external_begin_frame_source_.get());
- EXPECT_ACTIONS("AddObserver(this)");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- task_runner_->RunPendingTasks();
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- }
- // This test maskes sure that switching a frame source when not observing
- // such as when not visible also works.
- TEST_F(SchedulerTest, SwitchFrameSourceWhenNotObserving) {
- SetUpScheduler(EXTERNAL_BFS);
- // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- // Begin new frame.
- EXPECT_SCOPED(AdvanceFrame());
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- client_->Reset();
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
- client_->Reset();
- scheduler_->NotifyReadyToActivate();
- EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
- // Scheduler loses LayerTreeFrameSink, and stops waiting for ready to draw
- // signal.
- client_->Reset();
- scheduler_->DidLoseLayerTreeFrameSink();
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- task_runner_->RunPendingTasks();
- EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation",
- "RemoveObserver(this)");
- // Changing begin frame source doesn't do anything.
- // The unthrottled source doesn't print Add/RemoveObserver like the fake one.
- client_->Reset();
- scheduler_->SetBeginFrameSource(unthrottled_frame_source_.get());
- EXPECT_NO_ACTION();
- client_->Reset();
- scheduler_->DidCreateAndInitializeLayerTreeFrameSink();
- EXPECT_NO_ACTION();
- client_->Reset();
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_NO_ACTION();
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- }
- // Tests to ensure that we send a ScheduledActionBeginMainFrameNotExpectedUntil
- // when expected.
- TEST_F(SchedulerTest, ScheduledActionBeginMainFrameNotExpectedUntil) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsRedraw();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
- task_runner_->RunPendingTasks();
- EXPECT_ACTIONS("WillBeginImplFrame",
- "ScheduledActionBeginMainFrameNotExpectedUntil",
- "ScheduledActionDrawIfPossible");
- }
- // Tests to ensure that BeginMainFrameNotExpectedUntil is only sent once within
- // the same frame.
- TEST_F(SchedulerTest,
- ScheduledActionBeginMainFrameNotExpectedUntilSentOnlyOncePerFrame) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsRedraw();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
- task_runner_->RunPendingTasks();
- EXPECT_ACTIONS("WillBeginImplFrame",
- "ScheduledActionBeginMainFrameNotExpectedUntil",
- "ScheduledActionDrawIfPossible");
- client_->Reset();
- scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(false);
- task_runner_->RunPendingTasks();
- EXPECT_NO_ACTION();
- scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
- task_runner_->RunPendingTasks();
- EXPECT_NO_ACTION();
- }
- // Tests to ensure that we send a BeginMainFrameNotExpectedSoon when expected.
- TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon_Requested) {
- SetUpScheduler(EXTERNAL_BFS);
- // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- // Trigger a frame draw.
- EXPECT_SCOPED(AdvanceFrame());
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- scheduler_->NotifyReadyToActivate();
- task_runner_->RunPendingTasks();
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
- "ScheduledActionCommit", "ScheduledActionPostCommit",
- "ScheduledActionActivateSyncTree",
- "ScheduledActionDrawIfPossible");
- client_->Reset();
- scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame",
- "ScheduledActionBeginMainFrameNotExpectedUntil");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // The BeginImplFrame deadline should SetNeedsBeginFrame(false) and send a
- // SendBeginMainFrameNotExpectedSoon.
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("SendBeginMainFrameNotExpectedSoon", "RemoveObserver(this)");
- client_->Reset();
- }
- // Tests to ensure that we dont't send a BeginMainFrameNotExpectedSoon when
- // possible but not requested.
- TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon_Unrequested) {
- SetUpScheduler(EXTERNAL_BFS);
- // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- // Trigger a frame draw.
- EXPECT_SCOPED(AdvanceFrame());
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- scheduler_->NotifyReadyToActivate();
- task_runner_->RunPendingTasks();
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
- "ScheduledActionCommit", "ScheduledActionPostCommit",
- "ScheduledActionActivateSyncTree",
- "ScheduledActionDrawIfPossible");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // The BeginImplFrame deadline should SetNeedsBeginFrame(false), but doesn't
- // send a SendBeginMainFrameNotExpectedSoon as it's not been requested by the
- // main thread.
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("RemoveObserver(this)");
- client_->Reset();
- scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
- EXPECT_ACTIONS("SendBeginMainFrameNotExpectedSoon");
- }
- // Tests to ensure that we send a BeginMainFrameNotExpectedSoon only once per
- // frame.
- TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoonOnlyOncePerFrame) {
- SetUpScheduler(EXTERNAL_BFS);
- // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- // Trigger a frame draw.
- EXPECT_SCOPED(AdvanceFrame());
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- scheduler_->NotifyReadyToActivate();
- task_runner_->RunPendingTasks();
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
- "ScheduledActionCommit", "ScheduledActionPostCommit",
- "ScheduledActionActivateSyncTree",
- "ScheduledActionDrawIfPossible");
- client_->Reset();
- scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame",
- "ScheduledActionBeginMainFrameNotExpectedUntil");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("SendBeginMainFrameNotExpectedSoon", "RemoveObserver(this)");
- client_->Reset();
- scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(false);
- EXPECT_NO_ACTION();
- scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
- EXPECT_NO_ACTION();
- }
- // Tests to ensure that we send a BeginMainFrameNotExpectedSoon in situations
- // where the client doesn't want messages when we first stopped observing
- // BeginFrames but later does.
- TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon_AlreadyIdle) {
- SetUpScheduler(EXTERNAL_BFS);
- // SetNeedsBeginMainFrame should begin the frame on the next BeginImplFrame.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- // Trigger a frame draw.
- EXPECT_SCOPED(AdvanceFrame());
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- scheduler_->NotifyReadyToActivate();
- task_runner_->RunPendingTasks();
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
- "ScheduledActionCommit", "ScheduledActionPostCommit",
- "ScheduledActionActivateSyncTree",
- "ScheduledActionDrawIfPossible");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("WillBeginImplFrame", "RemoveObserver(this)");
- client_->Reset();
- scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
- EXPECT_ACTIONS("SendBeginMainFrameNotExpectedSoon");
- }
- // This tests to ensure BeginMainFrameNotExpectedSoon is sent during idle
- // periods if (1) it initially wasn't sent because the message wasn't needed at
- // the time, and (2) the BeginMainFrameNotExpectedUntil was already sent in the
- // frame (crbug.com/893653).
- TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoonDuringIdleIfNeeded) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsRedraw();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- task_runner_->RunPendingTasks();
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionDrawIfPossible");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // Toggle WantsBeginMainFrameNotExpected while inside BeginImplFrame. This
- // causes the BeginMainFrameNotExpectedUntil message to get sent and the
- // BeginMainFrameNotExpectedSoon message to be withheld.
- scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
- EXPECT_ACTIONS("ScheduledActionBeginMainFrameNotExpectedUntil");
- client_->Reset();
- scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(false);
- task_runner_->RunPendingTasks();
- EXPECT_ACTIONS("RemoveObserver(this)");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
- EXPECT_ACTIONS("SendBeginMainFrameNotExpectedSoon");
- }
- // This tests to ensure BeginMainFrameNotExpectedSoon is sent during idle
- // periods if (1) it initially wasn't sent because the message wasn't needed at
- // the time, and (2) |scheduler_|.visible() is false.
- TEST_F(SchedulerTest,
- ScheduledActionBeginMainFrameNotSoonSentDuringIdleIfNeededNotVisible) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsRedraw();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- task_runner_->RunPendingTasks();
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionDrawIfPossible");
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- scheduler_->SetVisible(false);
- task_runner_->RunPendingTasks();
- EXPECT_ACTIONS("RemoveObserver(this)");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- // The scheduler won't send BeginMainFrameNotExpectedUntil messages while not
- // visible, but it needs to send a BeginMainFrameNotExpectedSoon to let the
- // client know it's gone idle.
- client_->Reset();
- scheduler_->SetMainThreadWantsBeginMainFrameNotExpected(true);
- EXPECT_ACTIONS("SendBeginMainFrameNotExpectedSoon");
- }
- TEST_F(SchedulerTest, SynchronousCompositorAnimation) {
- scheduler_settings_.using_synchronous_renderer_compositor = true;
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsOneBeginImplFrame();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- // Testing the case where animation ticks a fling scroll.
- client_->SetWillBeginImplFrameCausesRedraw(true);
- // The animation isn't done so it'll cause another tick in the future.
- client_->SetWillBeginImplFrameRequestsOneBeginImplFrame(true);
- // Next vsync.
- AdvanceFrame();
- EXPECT_ACTIONS("WillBeginImplFrame",
- "ScheduledActionInvalidateLayerTreeFrameSink");
- // Finish frame is deferred until next draw since there was invalidation.
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // Android onDraw. This doesn't consume the single begin frame request.
- scheduler_->SetNeedsRedraw();
- bool resourceless_software_draw = false;
- bool skip_draw = false;
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
- skip_draw);
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // The animation inside of WillBeginImplFrame changes stuff on the screen, but
- // ends here, so does not cause another frame to happen.
- client_->SetWillBeginImplFrameCausesRedraw(true);
- // Next vsync.
- AdvanceFrame();
- EXPECT_ACTIONS("WillBeginImplFrame",
- "ScheduledActionInvalidateLayerTreeFrameSink");
- // Finish frame is deferred until next draw since there was invalidation.
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // Android onDraw.
- scheduler_->SetNeedsRedraw();
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
- skip_draw);
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // Idle on next vsync, as the animation has completed.
- AdvanceFrame();
- EXPECT_ACTIONS("WillBeginImplFrame", "RemoveObserver(this)");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- }
- TEST_F(SchedulerTest, SynchronousCompositorOnDrawDuringIdle) {
- scheduler_settings_.using_synchronous_renderer_compositor = true;
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsRedraw();
- bool resourceless_software_draw = false;
- bool skip_draw = false;
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
- skip_draw);
- EXPECT_ACTIONS("AddObserver(this)", "ScheduledActionDrawIfPossible");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // Idle on next vsync.
- AdvanceFrame();
- EXPECT_ACTIONS("WillBeginImplFrame", "RemoveObserver(this)");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- }
- TEST_F(SchedulerTest, InvalidateLayerTreeFrameSinkWhenCannotDraw) {
- scheduler_settings_.using_synchronous_renderer_compositor = true;
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetCanDraw(false);
- scheduler_->SetNeedsRedraw();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- // Do not invalidate in next BeginFrame.
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- // Redraw is not cleared.
- EXPECT_TRUE(scheduler_->RedrawPending());
- scheduler_->SetCanDraw(true);
- client_->Reset();
- // Do invalidate in next BeginFrame.
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame",
- "ScheduledActionInvalidateLayerTreeFrameSink");
- client_->Reset();
- bool resourceless_software_draw = false;
- bool skip_draw = false;
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
- skip_draw);
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- EXPECT_FALSE(scheduler_->RedrawPending());
- }
- TEST_F(SchedulerTest, NeedsPrepareTilesInvalidates) {
- // This is to test that SetNeedsPrepareTiles causes invalidates even if
- // CanDraw is false.
- scheduler_settings_.using_synchronous_renderer_compositor = true;
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetCanDraw(false);
- scheduler_->SetNeedsPrepareTiles();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- // Do not invalidate in next BeginFrame.
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame",
- "ScheduledActionInvalidateLayerTreeFrameSink");
- client_->Reset();
- }
- TEST_F(SchedulerTest, SetNeedsOneBeginImplFrame) {
- SetUpScheduler(EXTERNAL_BFS);
- EXPECT_FALSE(scheduler_->begin_frames_expected());
- // Request a frame, should kick the source.
- scheduler_->SetNeedsOneBeginImplFrame();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- // The incoming WillBeginImplFrame will request another one.
- client_->SetWillBeginImplFrameRequestsOneBeginImplFrame(true);
- // Next vsync, the first requested frame happens.
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // We don't request another frame here.
- // Next vsync, the second requested frame happens (the one requested inside
- // the previous frame's begin impl frame step).
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // End that frame's deadline.
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- // Scheduler shuts down the source now that no begin frame is requested.
- EXPECT_ACTIONS("RemoveObserver(this)");
- }
- TEST_F(SchedulerTest, AbortEarlyIfNoDamage) {
- SetUpScheduler(EXTERNAL_BFS);
- // WillBeginImplFrame will return false, so draws should never be scheduled
- // and client_->num_draws() should stay at 0.
- client_->SetWillBeginImplFrameMightHaveDamage(false);
- scheduler_->SetNeedsRedraw();
- EXPECT_EQ(0, client_->num_draws());
- EXPECT_ACTIONS("AddObserver(this)");
- EXPECT_SCOPED(AdvanceFrame());
- task_runner_->RunPendingTasks(); // Run posted deadline.
- // Should not try to schedule a draw. (ScheduledActionDrawIfPossible should
- // not appear.)
- // When the frame is aborted, the scheduler does not ask for a proactive begin
- // frame, so stop listening for begin frames.
- EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame",
- "RemoveObserver(this)");
- EXPECT_EQ(0, client_->num_draws());
- scheduler_->SetNeedsRedraw();
- EXPECT_SCOPED(AdvanceFrame());
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_EQ(0, client_->num_draws());
- }
- TEST_F(SchedulerTest, SkipDraw) {
- scheduler_settings_.using_synchronous_renderer_compositor = true;
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsOneBeginImplFrame();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- client_->SetWillBeginImplFrameCausesRedraw(true);
- // Next vsync.
- AdvanceFrame();
- EXPECT_ACTIONS("WillBeginImplFrame",
- "ScheduledActionInvalidateLayerTreeFrameSink");
- EXPECT_TRUE(client_->invalidate_needs_redraw());
- client_->Reset();
- // Android onDraw. This doesn't consume the single begin frame request.
- scheduler_->SetNeedsPrepareTiles();
- bool resourceless_software_draw = false;
- bool skip_draw = false;
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
- skip_draw);
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible",
- "ScheduledActionPrepareTiles");
- client_->Reset();
- // Next vsync.
- scheduler_->SetNeedsPrepareTiles();
- AdvanceFrame();
- EXPECT_ACTIONS("WillBeginImplFrame",
- "ScheduledActionInvalidateLayerTreeFrameSink");
- EXPECT_FALSE(client_->invalidate_needs_redraw());
- client_->Reset();
- // Android onDraw.
- scheduler_->SetNeedsRedraw();
- scheduler_->SetNeedsPrepareTiles();
- client_->SetInvalidateNeedsRedraw(false);
- skip_draw = true;
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
- skip_draw);
- EXPECT_ACTIONS("ScheduledActionPrepareTiles");
- client_->Reset();
- }
- TEST_F(SchedulerTest, SynchronousCompositorCommitAndVerifyBeginFrameAcks) {
- scheduler_settings_.using_synchronous_renderer_compositor = true;
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- // Next vsync.
- viz::BeginFrameArgs args = SendNextBeginFrame();
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- bool has_damage = false;
- EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
- client_->last_begin_frame_ack());
- client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- EXPECT_NO_ACTION();
- // Next vsync.
- args = SendNextBeginFrame();
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- has_damage = false;
- EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
- client_->last_begin_frame_ack());
- client_->Reset();
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
- client_->Reset();
- scheduler_->NotifyReadyToActivate();
- EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
- client_->Reset();
- // Next vsync.
- args = SendNextBeginFrame();
- EXPECT_ACTIONS("WillBeginImplFrame",
- "ScheduledActionInvalidateLayerTreeFrameSink");
- // Finish frame is deferred until next draw since there was invalidation.
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // Android onDraw.
- scheduler_->SetNeedsRedraw();
- bool resourceless_software_draw = false;
- bool skip_draw = false;
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
- skip_draw);
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // Idle on next vsync.
- args = SendNextBeginFrame();
- EXPECT_ACTIONS("WillBeginImplFrame", "RemoveObserver(this)");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- has_damage = false;
- EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
- client_->last_begin_frame_ack());
- client_->Reset();
- }
- class SchedulerClientSetNeedsPrepareTilesOnDraw : public FakeSchedulerClient {
- public:
- SchedulerClientSetNeedsPrepareTilesOnDraw() : FakeSchedulerClient() {}
- protected:
- DrawResult ScheduledActionDrawIfPossible() override {
- scheduler_->SetNeedsPrepareTiles();
- return FakeSchedulerClient::ScheduledActionDrawIfPossible();
- }
- };
- TEST_F(SchedulerTest, SynchronousCompositorPrepareTilesOnDraw) {
- scheduler_settings_.using_synchronous_renderer_compositor = true;
- std::unique_ptr<FakeSchedulerClient> client =
- base::WrapUnique(new SchedulerClientSetNeedsPrepareTilesOnDraw);
- SetUpScheduler(EXTERNAL_BFS, std::move(client));
- scheduler_->SetNeedsRedraw();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- // Next vsync.
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame",
- "ScheduledActionInvalidateLayerTreeFrameSink");
- client_->Reset();
- // Android onDraw.
- scheduler_->SetNeedsRedraw();
- bool resourceless_software_draw = false;
- bool skip_draw = false;
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
- skip_draw);
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible",
- "ScheduledActionPrepareTiles");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- EXPECT_FALSE(scheduler_->PrepareTilesPending());
- client_->Reset();
- // Android onDraw.
- scheduler_->SetNeedsRedraw();
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
- skip_draw);
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible",
- "ScheduledActionPrepareTiles");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- EXPECT_FALSE(scheduler_->PrepareTilesPending());
- client_->Reset();
- // Next vsync.
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_FALSE(scheduler_->PrepareTilesPending());
- EXPECT_ACTIONS("WillBeginImplFrame", "RemoveObserver(this)");
- EXPECT_FALSE(scheduler_->begin_frames_expected());
- client_->Reset();
- }
- // Synchronous compositor does not require the active tree to be drawn at least
- // once before the next activation. This test verifies two commit-activate
- // cycles without draw work correctly.
- TEST_F(SchedulerTest, SynchronousCompositorAllowsActivateBeforeDraw) {
- scheduler_settings_.using_synchronous_renderer_compositor = true;
- std::unique_ptr<FakeSchedulerClient> client =
- base::WrapUnique(new SchedulerClientSetNeedsPrepareTilesOnDraw);
- SetUpScheduler(EXTERNAL_BFS, std::move(client));
- scheduler_->SetNeedsRedraw();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- // Next vsync.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
- "ScheduledActionInvalidateLayerTreeFrameSink");
- client_->Reset();
- // Commit and activate.
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
- client_->Reset();
- scheduler_->NotifyReadyToActivate();
- EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
- client_->Reset();
- // No Draw.
- // Next vsync.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
- "ScheduledActionInvalidateLayerTreeFrameSink");
- client_->Reset();
- // Commit and activate.
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
- client_->Reset();
- scheduler_->NotifyReadyToActivate();
- EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
- client_->Reset();
- }
- TEST_F(SchedulerTest, SetNeedsRedrawFromWillBeginImplFrame) {
- client_ = std::make_unique<FakeSchedulerClient>();
- CreateScheduler(EXTERNAL_BFS);
- scheduler_->SetVisible(true);
- scheduler_->SetCanDraw(true);
- client_->SetWillBeginImplFrameCausesRedraw(true);
- scheduler_->DidCreateAndInitializeLayerTreeFrameSink();
- scheduler_->SetNeedsBeginMainFrame();
- AdvanceFrame();
- EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation",
- "AddObserver(this)", "WillBeginImplFrame",
- "ScheduledActionSendBeginMainFrame");
- EXPECT_TRUE(scheduler_->RedrawPending());
- // WillBeginFrame calls Scheduler::SetNeedsRedraw, which could try to run
- // another action. If none of the EXPECT_FALSE(inside_action_)s in
- // FakeSchedulerClient fail, we know we didn't re-enter the scheduler.
- }
- TEST_F(SchedulerTest, SynchronousCompositorSendBeginMainFrameWhileIdle) {
- scheduler_settings_.using_synchronous_renderer_compositor = true;
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsRedraw();
- EXPECT_ACTIONS("AddObserver(this)");
- client_->Reset();
- // Next vsync.
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame",
- "ScheduledActionInvalidateLayerTreeFrameSink");
- client_->Reset();
- // Android onDraw.
- scheduler_->SetNeedsRedraw();
- bool resourceless_software_draw = false;
- bool skip_draw = false;
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
- skip_draw);
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- EXPECT_FALSE(scheduler_->PrepareTilesPending());
- client_->Reset();
- // Simulate SetNeedsBeginMainFrame due to input event.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_ACTIONS("ScheduledActionSendBeginMainFrame");
- client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
- client_->Reset();
- scheduler_->NotifyReadyToActivate();
- EXPECT_ACTIONS("ScheduledActionActivateSyncTree");
- client_->Reset();
- // Next vsync.
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame",
- "ScheduledActionInvalidateLayerTreeFrameSink");
- client_->Reset();
- // Android onDraw.
- scheduler_->SetNeedsRedraw();
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
- skip_draw);
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- EXPECT_FALSE(scheduler_->PrepareTilesPending());
- client_->Reset();
- // Simulate SetNeedsBeginMainFrame due to input event.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_ACTIONS("ScheduledActionSendBeginMainFrame");
- client_->Reset();
- }
- TEST_F(SchedulerTest, SynchronousCompositorResourcelessOnDrawWhenInvisible) {
- scheduler_settings_.using_synchronous_renderer_compositor = true;
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetVisible(false);
- scheduler_->SetNeedsRedraw();
- bool resourceless_software_draw = true;
- bool skip_draw = false;
- scheduler_->OnDrawForLayerTreeFrameSink(resourceless_software_draw,
- skip_draw);
- // SynchronousCompositor has to draw regardless of visibility.
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- }
- TEST_F(SchedulerTest, AuthoritativeVSyncInterval) {
- SetUpScheduler(THROTTLED_BFS);
- base::TimeDelta initial_interval = scheduler_->BeginImplFrameInterval();
- base::TimeDelta authoritative_interval = base::Milliseconds(33);
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_EQ(initial_interval, scheduler_->BeginImplFrameInterval());
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- scheduler_->NotifyReadyToActivate();
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- // Test changing the interval on the frame source external to the scheduler.
- synthetic_frame_source_->OnUpdateVSyncParameters(task_runner_->NowTicks(),
- authoritative_interval);
- EXPECT_SCOPED(AdvanceFrame());
- // At the next BeginFrame, authoritative interval is used instead of previous
- // interval.
- EXPECT_NE(initial_interval, scheduler_->BeginImplFrameInterval());
- EXPECT_EQ(authoritative_interval, scheduler_->BeginImplFrameInterval());
- }
- TEST_F(SchedulerTest, ImplLatencyTakesPriority) {
- SetUpScheduler(THROTTLED_BFS);
- scheduler_->SetTreePrioritiesAndScrollState(
- SMOOTHNESS_TAKES_PRIORITY,
- ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER);
- scheduler_->SetCriticalBeginMainFrameToActivateIsFast(true);
- EXPECT_TRUE(scheduler_->ImplLatencyTakesPriority());
- scheduler_->SetCriticalBeginMainFrameToActivateIsFast(false);
- EXPECT_TRUE(scheduler_->ImplLatencyTakesPriority());
- scheduler_->SetTreePrioritiesAndScrollState(
- SMOOTHNESS_TAKES_PRIORITY,
- ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER);
- scheduler_->SetCriticalBeginMainFrameToActivateIsFast(true);
- EXPECT_FALSE(scheduler_->ImplLatencyTakesPriority());
- scheduler_->SetCriticalBeginMainFrameToActivateIsFast(false);
- EXPECT_TRUE(scheduler_->ImplLatencyTakesPriority());
- scheduler_->SetTreePrioritiesAndScrollState(
- SAME_PRIORITY_FOR_BOTH_TREES,
- ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER);
- scheduler_->SetCriticalBeginMainFrameToActivateIsFast(true);
- EXPECT_FALSE(scheduler_->ImplLatencyTakesPriority());
- scheduler_->SetCriticalBeginMainFrameToActivateIsFast(false);
- EXPECT_FALSE(scheduler_->ImplLatencyTakesPriority());
- scheduler_->SetTreePrioritiesAndScrollState(
- SAME_PRIORITY_FOR_BOTH_TREES,
- ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER);
- scheduler_->SetCriticalBeginMainFrameToActivateIsFast(true);
- EXPECT_FALSE(scheduler_->ImplLatencyTakesPriority());
- scheduler_->SetCriticalBeginMainFrameToActivateIsFast(false);
- EXPECT_FALSE(scheduler_->ImplLatencyTakesPriority());
- }
- TEST_F(SchedulerTest, NoLayerTreeFrameSinkCreationWhileCommitPending) {
- SetUpScheduler(THROTTLED_BFS);
- // SetNeedsBeginMainFrame should begin the frame.
- scheduler_->SetNeedsBeginMainFrame();
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- // Lose the LayerTreeFrameSink and trigger the deadline.
- client_->Reset();
- scheduler_->DidLoseLayerTreeFrameSink();
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- EXPECT_NO_ACTION();
- // The scheduler should not trigger the LayerTreeFrameSink creation till the
- // commit is aborted.
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- EXPECT_NO_ACTION();
- // Abort the commit.
- client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->BeginMainFrameAborted(
- CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT);
- EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation");
- }
- TEST_F(SchedulerTest, ImplSideInvalidationInsideImplFrame) {
- SetUpScheduler(EXTERNAL_BFS);
- // Request an impl-side invalidation. Ensure that it runs before the deadline.
- bool needs_first_draw_on_activation = true;
- scheduler_->SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame",
- "ScheduledActionPerformImplSideInvalidation");
- }
- TEST_F(SchedulerTest, ImplSideInvalidationsMergedWithCommit) {
- SetUpScheduler(EXTERNAL_BFS);
- // Request a main frame and invalidation, the only action run should be
- // sending the main frame.
- SetShouldDeferInvalidationForMainFrame(true);
- scheduler_->SetNeedsBeginMainFrame();
- bool needs_first_draw_on_activation = true;
- scheduler_->SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- // Respond with a commit. The scheduler should only perform the commit
- // actions since the impl-side invalidation request will be merged with the
- // commit.
- client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
- EXPECT_FALSE(scheduler_->needs_impl_side_invalidation());
- }
- TEST_F(SchedulerTest, AbortedCommitsTriggerImplSideInvalidations) {
- SetUpScheduler(EXTERNAL_BFS);
- // Request a main frame and invalidation, with a fast main thread so we wait
- // for it to respond.
- SetShouldDeferInvalidationForMainFrame(true);
- scheduler_->SetNeedsBeginMainFrame();
- bool needs_first_draw_on_activation = true;
- scheduler_->SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- // Abort the main frame and request another one, the impl-side invalidations
- // should not be blocked on the main frame.
- client_->Reset();
- scheduler_->SetNeedsBeginMainFrame();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->BeginMainFrameAborted(CommitEarlyOutReason::FINISHED_NO_UPDATES);
- EXPECT_ACTIONS("ScheduledActionPerformImplSideInvalidation");
- }
- TEST_F(SchedulerTest, InvalidationNotBlockedOnMainFrame) {
- SetUpScheduler(EXTERNAL_BFS);
- // Request a main frame and invalidation, with a slow main thread so the
- // invalidation is not blocked on a commit.
- SetShouldDeferInvalidationForMainFrame(false);
- scheduler_->SetNeedsBeginMainFrame();
- bool needs_first_draw_on_activation = true;
- scheduler_->SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame",
- "ScheduledActionPerformImplSideInvalidation");
- }
- // The three letters appeneded to each version of this test mean the following:s
- // tree_priority: B = both trees same priority; A = active tree priority;
- // scroll_handler_state: H = affects scroll handler; N = does not affect scroll
- // handler;
- // durations: F = fast durations; S = slow durations
- bool SchedulerTest::BeginMainFrameOnCriticalPath(
- TreePriority tree_priority,
- ScrollHandlerState scroll_handler_state,
- base::TimeDelta durations) {
- SetUpScheduler(EXTERNAL_BFS);
- fake_compositor_timing_history_->SetAllEstimatesTo(durations);
- client_->Reset();
- scheduler_->SetTreePrioritiesAndScrollState(tree_priority,
- scroll_handler_state);
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_FALSE(client_->last_begin_main_frame_args().IsValid());
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_TRUE(client_->last_begin_main_frame_args().IsValid());
- return client_->last_begin_main_frame_args().on_critical_path;
- }
- TEST_F(SchedulerTest, BeginMainFrameOnCriticalPath_BNF) {
- EXPECT_TRUE(BeginMainFrameOnCriticalPath(
- SAME_PRIORITY_FOR_BOTH_TREES,
- ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER,
- kFastDuration));
- }
- TEST_F(SchedulerTest, BeginMainFrameOnCriticalPath_BNS) {
- EXPECT_TRUE(BeginMainFrameOnCriticalPath(
- SAME_PRIORITY_FOR_BOTH_TREES,
- ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER,
- kSlowDuration));
- }
- TEST_F(SchedulerTest, BeginMainFrameOnCriticalPath_BHF) {
- EXPECT_TRUE(BeginMainFrameOnCriticalPath(
- SAME_PRIORITY_FOR_BOTH_TREES,
- ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER, kFastDuration));
- }
- TEST_F(SchedulerTest, BeginMainFrameOnCriticalPath_BHS) {
- EXPECT_TRUE(BeginMainFrameOnCriticalPath(
- SAME_PRIORITY_FOR_BOTH_TREES,
- ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER, kSlowDuration));
- }
- TEST_F(SchedulerTest, BeginMainFrameOnCriticalPath_ANF) {
- EXPECT_FALSE(BeginMainFrameOnCriticalPath(
- SMOOTHNESS_TAKES_PRIORITY,
- ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER,
- kFastDuration));
- }
- TEST_F(SchedulerTest, BeginMainFrameOnCriticalPath_ANS) {
- EXPECT_FALSE(BeginMainFrameOnCriticalPath(
- SMOOTHNESS_TAKES_PRIORITY,
- ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER,
- kSlowDuration));
- }
- TEST_F(SchedulerTest, BeginMainFrameOnCriticalPath_AHF) {
- EXPECT_TRUE(BeginMainFrameOnCriticalPath(
- SMOOTHNESS_TAKES_PRIORITY,
- ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER, kFastDuration));
- }
- TEST_F(SchedulerTest, BeginMainFrameOnCriticalPath_AHS) {
- EXPECT_FALSE(BeginMainFrameOnCriticalPath(
- SMOOTHNESS_TAKES_PRIORITY,
- ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER, kSlowDuration));
- }
- TEST_F(SchedulerTest, BeginFrameAckForFinishedImplFrame) {
- // Sets up scheduler and sends two BeginFrames, both finished.
- SetUpScheduler(EXTERNAL_BFS);
- // Run a successful redraw and verify that a new ack is sent.
- scheduler_->SetNeedsRedraw();
- client_->Reset();
- viz::BeginFrameArgs args = SendNextBeginFrame();
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- // Successful draw caused damage.
- bool has_damage = true;
- EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
- client_->last_begin_frame_ack());
- client_->Reset();
- // Request another redraw, but fail it. Verify that a new ack is sent.
- scheduler_->SetNeedsRedraw();
- client_->Reset();
- args = SendNextBeginFrame();
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- client_->SetDrawWillHappen(false);
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible",
- // Failed draw triggers SendBeginMainFrame.
- "ScheduledActionSendBeginMainFrame");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- // Failed draw: no damage.
- has_damage = false;
- EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
- client_->last_begin_frame_ack());
- // The begin-main-frame sent has not been acknowledged yet (either by
- // doing a commit, or aborting the draw from the main-thread).
- EXPECT_EQ(FrameSkippedReason::kWaitingOnMain,
- client_->last_frame_skipped_reason());
- client_->Reset();
- // Start another frame, and end the frame without drawing.
- args = SendNextBeginFrame();
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- client_->SetDrawWillHappen(false);
- client_->SetSwapWillHappenIfDrawHappens(false);
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("ScheduledActionDrawIfPossible");
- // Draw with no damage.
- has_damage = false;
- EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
- client_->last_begin_frame_ack());
- // The main thread still has not responded to the begin-main-frame.
- EXPECT_EQ(FrameSkippedReason::kWaitingOnMain,
- client_->last_frame_skipped_reason());
- client_->Reset();
- // Allow the commit now. NotifyReadyToCommit should trigger the commit.
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- // Start another frame. For this frame, draw succeeds, but 'swap' does not
- // happen (i.e. no frame is submitted).
- args = SendNextBeginFrame();
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- client_->SetDrawWillHappen(true);
- client_->SetSwapWillHappenIfDrawHappens(false);
- task_runner_->RunPendingTasks(); // Run posted deadline.
- // Draw with no damage.
- has_damage = false;
- EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
- client_->last_begin_frame_ack());
- // The pending tree is not activated yet so the frame is still waiting on
- // Main thread update
- EXPECT_EQ(FrameSkippedReason::kWaitingOnMain,
- client_->last_frame_skipped_reason());
- }
- TEST_F(SchedulerTest, BeginFrameAckForBeginFrameBeforeLastDeadline) {
- SetUpScheduler(EXTERNAL_BFS);
- // Request tile preparation to schedule a proactive BeginFrame.
- scheduler_->SetNeedsPrepareTiles();
- client_->Reset();
- SendNextBeginFrame();
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- // Until tiles were prepared, further proactive BeginFrames are expected.
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- // Send the next BeginFrame before the previous one's deadline was executed.
- // This should post the previous BeginFrame's deadline, during which tiles
- // will be prepared. As a result of that, no further BeginFrames will be
- // needed, and the new BeginFrame should be dropped.
- viz::BeginFrameArgs args = SendNextBeginFrame();
- task_runner_->RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTIONS("ScheduledActionPrepareTiles", "RemoveObserver(this)");
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- EXPECT_FALSE(scheduler_->begin_frames_expected());
- // Latest ack should be for the dropped BeginFrame.
- bool has_damage = false;
- EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
- client_->last_begin_frame_ack());
- client_->Reset();
- }
- TEST_F(SchedulerTest, BeginFrameAckForDroppedBeginFrame) {
- SetUpScheduler(EXTERNAL_BFS);
- // Request a single BeginFrame.
- scheduler_->SetNeedsOneBeginImplFrame();
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- client_->Reset();
- // First BeginFrame is handled by StateMachine.
- viz::BeginFrameArgs first_args = SendNextBeginFrame();
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- // State machine is no longer interested in BeginFrames, but scheduler is
- // still observing the source.
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- EXPECT_FALSE(scheduler_->BeginFrameNeeded());
- client_->Reset();
- // Send the next BeginFrame before the previous one's deadline was executed.
- // The BeginFrame should be dropped immediately, since the state machine is
- // not expecting any BeginFrames.
- viz::BeginFrameArgs second_args = SendNextBeginFrame();
- EXPECT_NO_ACTION();
- // Latest ack should be for the dropped BeginFrame.
- bool has_damage = false;
- EXPECT_EQ(viz::BeginFrameAck(second_args, has_damage),
- client_->last_begin_frame_ack());
- client_->Reset();
- task_runner_->RunPendingTasks(); // Run deadline of prior BeginFrame.
- EXPECT_ACTIONS("RemoveObserver(this)");
- // We'd expect an out-of-order ack for the prior BeginFrame.
- has_damage = false;
- EXPECT_EQ(viz::BeginFrameAck(first_args, has_damage),
- client_->last_begin_frame_ack());
- client_->Reset();
- }
- TEST_F(SchedulerTest, BeginFrameAckForLateMissedBeginFrame) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsRedraw();
- client_->Reset();
- // Send a missed BeginFrame with a passed deadline.
- task_runner_->AdvanceMockTickClock(viz::BeginFrameArgs::DefaultInterval());
- viz::BeginFrameArgs args =
- fake_external_begin_frame_source_->CreateBeginFrameArgs(
- BEGINFRAME_FROM_HERE, task_runner_->GetMockTickClock());
- args.type = viz::BeginFrameArgs::MISSED;
- task_runner_->AdvanceMockTickClock(viz::BeginFrameArgs::DefaultInterval());
- EXPECT_GT(task_runner_->NowTicks(), args.deadline);
- fake_external_begin_frame_source_->TestOnBeginFrame(args);
- task_runner_->RunPendingTasks();
- EXPECT_NO_ACTION();
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- // Latest ack should be for the missed BeginFrame that was too late: no
- // damage.
- bool has_damage = false;
- EXPECT_EQ(viz::BeginFrameAck(args, has_damage),
- client_->last_begin_frame_ack());
- client_->Reset();
- }
- TEST_F(SchedulerTest, CriticalBeginMainFrameToActivateIsFast) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsRedraw();
- base::TimeDelta estimate_duration = base::Milliseconds(1);
- fake_compositor_timing_history_->SetAllEstimatesTo(estimate_duration);
- // If we have a scroll handler but the critical main frame is slow, we should
- // still prioritize impl thread latency.
- scheduler_->SetTreePrioritiesAndScrollState(
- SMOOTHNESS_TAKES_PRIORITY,
- ScrollHandlerState::SCROLL_AFFECTS_SCROLL_HANDLER);
- scheduler_->SetNeedsRedraw();
- // An interval of 2ms makes sure that the main frame is considered slow.
- base::TimeDelta interval = base::Milliseconds(2);
- task_runner_->AdvanceMockTickClock(interval);
- viz::BeginFrameArgs args = viz::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, 0u, 1u, task_runner_->NowTicks(),
- task_runner_->NowTicks() + interval, interval,
- viz::BeginFrameArgs::NORMAL);
- fake_external_begin_frame_source_->TestOnBeginFrame(args);
- EXPECT_TRUE(scheduler_->ImplLatencyTakesPriority());
- task_runner_->RunPendingTasks(); // Run posted deadline to finish the frame.
- ASSERT_FALSE(client_->IsInsideBeginImplFrame());
- // Set an interval of 10ms. The bmf_to_activate_interval should be 1*4 = 4ms,
- // to account for queue + main_frame + pending_tree + activation durations.
- // With a draw time of 1ms and fudge factor of 1ms, the interval available for
- // the main frame to be activated is 8ms, so it should be considered fast.
- scheduler_->SetNeedsRedraw();
- interval = base::Milliseconds(10);
- task_runner_->AdvanceMockTickClock(interval);
- args = viz::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, 0u, 2u,
- task_runner_->NowTicks(),
- task_runner_->NowTicks() + interval,
- interval, viz::BeginFrameArgs::NORMAL);
- fake_external_begin_frame_source_->TestOnBeginFrame(args);
- EXPECT_FALSE(scheduler_->ImplLatencyTakesPriority());
- task_runner_->RunPendingTasks(); // Run posted deadline to finish the frame.
- ASSERT_FALSE(client_->IsInsideBeginImplFrame());
- // Increase the draw duration to decrease the time available for the main
- // frame. This should prioritize the impl thread.
- scheduler_->SetNeedsRedraw();
- fake_compositor_timing_history_->SetDrawDurationEstimate(
- base::Milliseconds(7));
- task_runner_->AdvanceMockTickClock(interval);
- args = viz::BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, 0u, 3u,
- task_runner_->NowTicks(),
- task_runner_->NowTicks() + interval,
- interval, viz::BeginFrameArgs::NORMAL);
- fake_external_begin_frame_source_->TestOnBeginFrame(args);
- EXPECT_TRUE(scheduler_->ImplLatencyTakesPriority());
- }
- TEST_F(SchedulerTest, WaitForAllPipelineStagesUsesMissedBeginFrames) {
- scheduler_settings_.wait_for_all_pipeline_stages_before_draw = true;
- client_ = std::make_unique<FakeSchedulerClient>();
- CreateScheduler(EXTERNAL_BFS);
- // Initialize frame sink so that Scheduler and state machine need BeginFrames.
- scheduler_->SetVisible(true);
- scheduler_->SetCanDraw(true);
- EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation");
- client_->Reset();
- scheduler_->DidCreateAndInitializeLayerTreeFrameSink();
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // Uses MISSED BeginFrames even after the deadline has passed.
- base::TimeDelta interval = base::Milliseconds(16);
- task_runner_->AdvanceMockTickClock(interval);
- base::TimeTicks timestamp = task_runner_->NowTicks();
- // Deadline should have passed after this.
- task_runner_->AdvanceMockTickClock(interval * 2);
- viz::BeginFrameArgs args = viz::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, 0u, 1u, timestamp, timestamp + interval, interval,
- viz::BeginFrameArgs::MISSED);
- fake_external_begin_frame_source_->TestOnBeginFrame(args);
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- }
- TEST_F(SchedulerTest, WaitForAllPipelineStagesAlwaysObservesBeginFrames) {
- scheduler_settings_.wait_for_all_pipeline_stages_before_draw = true;
- client_ = std::make_unique<FakeSchedulerClient>();
- CreateScheduler(EXTERNAL_BFS);
- // Initialize frame sink, request a main frame but defer commits, so that
- // state machine is idle.
- scheduler_->SetVisible(true);
- scheduler_->SetCanDraw(true);
- EXPECT_ACTIONS("ScheduledActionBeginLayerTreeFrameSinkCreation");
- client_->Reset();
- scheduler_->DidCreateAndInitializeLayerTreeFrameSink();
- scheduler_->SetDeferBeginMainFrame(true);
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- EXPECT_FALSE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // In full-pipe mode, the SchedulerStateMachine always wants BeginFrames, even
- // if it is otherwise idle.
- EXPECT_TRUE(scheduler_->begin_frames_expected());
- EXPECT_TRUE(scheduler_->BeginFrameNeeded());
- // Scheduler begins a frame even if otherwise idle.
- base::TimeDelta interval = base::Milliseconds(16);
- task_runner_->AdvanceMockTickClock(interval);
- base::TimeTicks timestamp = task_runner_->NowTicks();
- viz::BeginFrameArgs args = viz::BeginFrameArgs::Create(
- BEGINFRAME_FROM_HERE, 0u, 1u, timestamp, timestamp + interval, interval,
- viz::BeginFrameArgs::NORMAL);
- fake_external_begin_frame_source_->TestOnBeginFrame(args);
- EXPECT_ACTIONS("WillBeginImplFrame");
- EXPECT_TRUE(client_->IsInsideBeginImplFrame());
- client_->Reset();
- // BeginFrame deadline is not blocked because commits are deferred.
- task_runner_->RunPendingTasks();
- EXPECT_ACTIONS();
- EXPECT_TRUE(!client_->IsInsideBeginImplFrame());
- client_->Reset();
- }
- TEST_F(SchedulerTest, CriticalBeginMainFrameIsFast_CommitEstimateSlow) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsBeginMainFrame();
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- fake_compositor_timing_history_->SetCommitDurationEstimate(kSlowDuration);
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_FALSE(scheduler_->state_machine()
- .critical_begin_main_frame_to_activate_is_fast());
- }
- TEST_F(SchedulerTest, CriticalBeginMainFrameIsFast_CommitEstimateFast) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsBeginMainFrame();
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_TRUE(scheduler_->state_machine()
- .critical_begin_main_frame_to_activate_is_fast());
- }
- TEST_F(SchedulerTest, ShouldDeferInvalidation_AllEstimatesFast) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsBeginMainFrame();
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_TRUE(scheduler_->state_machine()
- .should_defer_invalidation_for_fast_main_frame());
- }
- TEST_F(SchedulerTest, ShouldDeferInvalidation_BMFStartToReadyToCommitSlow) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsBeginMainFrame();
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- fake_compositor_timing_history_
- ->SetBeginMainFrameStartToReadyToCommitDurationEstimate(kSlowDuration);
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_FALSE(scheduler_->state_machine()
- .should_defer_invalidation_for_fast_main_frame());
- }
- TEST_F(SchedulerTest, ShouldDeferInvalidation_BMFQueueDurationCriticalSlow) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsBeginMainFrame();
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- fake_compositor_timing_history_
- ->SetBeginMainFrameQueueDurationCriticalEstimate(kSlowDuration);
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_FALSE(scheduler_->state_machine()
- .should_defer_invalidation_for_fast_main_frame());
- }
- TEST_F(SchedulerTest, ShouldDeferInvalidation_BMFQueueDurationNotCriticalSlow) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsBeginMainFrame();
- scheduler_->SetTreePrioritiesAndScrollState(
- TreePriority::SMOOTHNESS_TAKES_PRIORITY,
- ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER);
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- fake_compositor_timing_history_
- ->SetBeginMainFrameQueueDurationNotCriticalEstimate(kSlowDuration);
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_FALSE(scheduler_->state_machine()
- .should_defer_invalidation_for_fast_main_frame());
- }
- TEST_F(SchedulerTest, SlowMainThreadButEstimatedFastTriggersInvalidations) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsBeginMainFrame();
- scheduler_->SetNeedsImplSideInvalidation(true);
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- // Main thread is estimated fast, invalidation will be deferred.
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- // Draw deadline.
- client_->Reset();
- task_runner_->RunPendingTasks();
- EXPECT_ACTIONS();
- // Next frame. The invalidation should not be throttled.
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame",
- "ScheduledActionPerformImplSideInvalidation");
- }
- TEST_F(SchedulerTest,
- SlowMainThreadRasterButEstimatedFastDoesNotTriggersInvalidations) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsBeginMainFrame();
- scheduler_->SetNeedsImplSideInvalidation(true);
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- // Main thread is estimated fast, invalidation will be deferred.
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- // Commit before deadline but not ready to activate.
- client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
- // Draw deadline.
- client_->Reset();
- task_runner_->RunPendingTasks();
- EXPECT_ACTIONS();
- // Next frame. The invalidation should still be throttled.
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- }
- TEST_F(SchedulerTest, SynchronousCompositorImplSideInvalidation) {
- // Synchronous compositor doesn't have a deadline and our heuristics can't
- // work. We should never be prioritizing impl-side invalidations over main
- // frames.
- scheduler_settings_.using_synchronous_renderer_compositor = true;
- SetUpScheduler(EXTERNAL_BFS);
- fake_compositor_timing_history_->SetAllEstimatesTo(kSlowDuration);
- scheduler_->SetNeedsBeginMainFrame();
- const bool needs_first_draw_on_activation = true;
- scheduler_->SetNeedsImplSideInvalidation(needs_first_draw_on_activation);
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- }
- TEST_F(SchedulerTest, NoInvalidationForAnimateOnlyFrames) {
- SetUpScheduler(EXTERNAL_BFS);
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- client_->Reset();
- scheduler_->SetNeedsImplSideInvalidation(true);
- bool animate_only = true;
- EXPECT_SCOPED(AdvanceFrame(animate_only));
- EXPECT_ACTIONS("AddObserver(this)", "WillBeginImplFrame");
- client_->Reset();
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_ACTIONS();
- // Now send a frame which requires full updates.
- animate_only = false;
- EXPECT_SCOPED(AdvanceFrame(animate_only));
- EXPECT_ACTIONS("WillBeginImplFrame",
- "ScheduledActionPerformImplSideInvalidation");
- client_->Reset();
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_ACTIONS();
- }
- TEST_F(SchedulerTest, SendEarlyDidNotProduceFrameIfIdle) {
- SetUpScheduler(EXTERNAL_BFS);
- scheduler_->SetNeedsBeginMainFrame();
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- auto begin_main_frame_args = client_->last_begin_main_frame_args();
- EXPECT_NE(client_->last_begin_frame_ack().frame_id.sequence_number,
- begin_main_frame_args.frame_id.sequence_number);
- client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- // Request a new commit before finishing the current one to simulate behavior
- // seen in certain OOPIF renderers.
- scheduler_->SetNeedsBeginMainFrame();
- scheduler_->BeginMainFrameAborted(CommitEarlyOutReason::FINISHED_NO_UPDATES);
- EXPECT_EQ(client_->last_begin_frame_ack().frame_id.sequence_number,
- begin_main_frame_args.frame_id.sequence_number);
- }
- TEST_F(SchedulerTest,
- HighImplLatencyModePrioritizesMainFramesOverImplInvalidation) {
- SetUpScheduler(EXTERNAL_BFS);
- fake_compositor_timing_history_->SetAllEstimatesTo(kFastDuration);
- // Place the impl thread in high latency mode.
- scheduler_->SetNeedsImplSideInvalidation(true);
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame",
- "ScheduledActionPerformImplSideInvalidation");
- // Request a main frame and start the next impl frame. Since we have an impl
- // side pending tree, we will activate and draw it. This finishes the impl
- // frame before the main thread can respond causing the scheduler to
- // incorrectly assume the main thread is slow.
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame");
- client_->Reset();
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_ACTIONS("ScheduledActionSendBeginMainFrame");
- fake_compositor_timing_history_->SetBeginMainFrameSentTime(
- task_runner_->NowTicks() + base::Milliseconds(8));
- client_->Reset();
- scheduler_->NotifyReadyToActivate();
- task_runner_->RunTasksWhile(client_->InsideBeginImplFrame(true));
- EXPECT_ACTIONS("ScheduledActionActivateSyncTree",
- "ScheduledActionDrawIfPossible");
- // Start a new frame. We should not assume the main thread is slow.
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- scheduler_->SetNeedsImplSideInvalidation(true);
- // No invalidation should be performed since we are waiting for the main
- // thread to respond and merge with the commit.
- EXPECT_ACTIONS("WillBeginImplFrame");
- }
- namespace {
- class FakePowerModeObserver : public PowerModeArbiter::Observer {
- public:
- void OnPowerModeChanged(PowerMode old_mode, PowerMode new_mode) override {}
- };
- class SchedulerTestForPowerMode : public SchedulerTest {
- public:
- SchedulerTestForPowerMode()
- : time_overrides_(
- /*time_override=*/nullptr,
- &SchedulerTestForPowerMode::TimeTicksNow,
- /*thread_ticks_override=*/nullptr) {
- DCHECK_EQ(nullptr, current_test_);
- current_test_ = this;
- // Clear the arbiter's initial kCharging vote.
- power_mode_arbiter_.SetOnBatteryPowerForTesting(/*on_battery_power=*/true);
- power_mode_arbiter_.SetTaskRunnerForTesting(task_runner_);
- // Add a fake observer so that reset tasks are executed.
- power_mode_arbiter_.AddObserver(&observer_);
- }
- ~SchedulerTestForPowerMode() override {
- DCHECK_EQ(this, current_test_);
- current_test_ = nullptr;
- power_mode_arbiter_.RemoveObserver(&observer_);
- }
- void AdvanceToArbiterSnapAfter(base::TimeDelta delay) {
- // Align the mock clock with the phase of the arbiter's reset tasks.
- base::TimeTicks target_time =
- (task_runner_->NowTicks() + delay)
- .SnappedToNextTick(base::TimeTicks(),
- PowerModeArbiter::kResetVoteTimeResolution);
- task_runner_->RunUntilTime(target_time);
- }
- static base::TimeTicks TimeTicksNow() {
- DCHECK_NE(nullptr, current_test_);
- return current_test_->task_runner_->NowTicks();
- }
- private:
- // The ScopedTimeClockOverrides below require a function pointer (as opposed
- // to a bound callback). We store the current test instance in this static
- // variable to access its members from the static TimeTicksNow() method above.
- static SchedulerTestForPowerMode* current_test_;
- // The arbiter uses base::TimeTicks::Now(), which needs to be overridden by
- // the test's task runner. Ideally we'd be using base::test::TaskEnvironment
- // for scheduler unittests, which would do this for us.
- base::subtle::ScopedTimeClockOverrides time_overrides_;
- FakePowerModeObserver observer_;
- };
- // static
- SchedulerTestForPowerMode* SchedulerTestForPowerMode::current_test_;
- } // namespace
- TEST_F(SchedulerTestForPowerMode, BeginMainFramePowerModeVoter) {
- // Arbiter should start out in idle mode.
- EXPECT_EQ(power_mode_arbiter_.GetActiveModeForTesting(), PowerMode::kIdle);
- // SetUpScheduler will cause a BeginMainFrame and commit, which should change
- // the PowerMode vote.
- SetUpScheduler(EXTERNAL_BFS);
- EXPECT_EQ(power_mode_arbiter_.GetActiveModeForTesting(),
- PowerMode::kMainThreadAnimation);
- // The scheduler should now be idle, so the PowerMode vote should be reset
- // after kAnimationTimeout.
- AdvanceToArbiterSnapAfter(PowerModeVoter::kAnimationTimeout);
- EXPECT_EQ(power_mode_arbiter_.GetActiveModeForTesting(), PowerMode::kIdle);
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_EQ(power_mode_arbiter_.GetActiveModeForTesting(),
- PowerMode::kMainThreadAnimation);
- // While BeginMainFrame is needed, the vote is not reset
- AdvanceToArbiterSnapAfter(PowerModeVoter::kAnimationTimeout);
- EXPECT_EQ(power_mode_arbiter_.GetActiveModeForTesting(),
- PowerMode::kMainThreadAnimation);
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- // While BeginMainFrame is active, the vote is not reset
- AdvanceToArbiterSnapAfter(PowerModeVoter::kAnimationTimeout);
- EXPECT_EQ(power_mode_arbiter_.GetActiveModeForTesting(),
- PowerMode::kMainThreadAnimation);
- scheduler_->BeginMainFrameAborted(CommitEarlyOutReason::FINISHED_NO_UPDATES);
- // After aborting, the vote is reset.
- AdvanceToArbiterSnapAfter(PowerModeVoter::kAnimationTimeout);
- EXPECT_EQ(power_mode_arbiter_.GetActiveModeForTesting(), PowerMode::kIdle);
- // Go through another two BeginMainFrames that are aborted.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_EQ(power_mode_arbiter_.GetActiveModeForTesting(),
- PowerMode::kMainThreadAnimation);
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->BeginMainFrameAborted(CommitEarlyOutReason::FINISHED_NO_UPDATES);
- scheduler_->SetNeedsBeginMainFrame();
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->BeginMainFrameAborted(CommitEarlyOutReason::FINISHED_NO_UPDATES);
- // Still in animation mode, but a reset is pending.
- EXPECT_EQ(power_mode_arbiter_.GetActiveModeForTesting(),
- PowerMode::kMainThreadAnimation);
- AdvanceToArbiterSnapAfter(PowerModeVoter::kAnimationTimeout);
- EXPECT_EQ(power_mode_arbiter_.GetActiveModeForTesting(), PowerMode::kIdle);
- // Further BeginMainFrame will be ignored, because the main-thread animation
- // is considered no-op after three consecutive aborted BeginMainFrames.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_EQ(power_mode_arbiter_.GetActiveModeForTesting(), PowerMode::kIdle);
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->BeginMainFrameAborted(CommitEarlyOutReason::FINISHED_NO_UPDATES);
- EXPECT_EQ(power_mode_arbiter_.GetActiveModeForTesting(), PowerMode::kIdle);
- // But once the BeginMainFrame produces updates, we vote for animation again.
- scheduler_->SetNeedsBeginMainFrame();
- EXPECT_EQ(power_mode_arbiter_.GetActiveModeForTesting(), PowerMode::kIdle);
- client_->Reset();
- EXPECT_SCOPED(AdvanceFrame());
- EXPECT_ACTIONS("WillBeginImplFrame", "ScheduledActionSendBeginMainFrame");
- client_->Reset();
- scheduler_->NotifyBeginMainFrameStarted(task_runner_->NowTicks());
- scheduler_->NotifyReadyToCommit(nullptr);
- EXPECT_ACTIONS("ScheduledActionCommit", "ScheduledActionPostCommit");
- EXPECT_EQ(power_mode_arbiter_.GetActiveModeForTesting(),
- PowerMode::kMainThreadAnimation);
- client_->Reset();
- }
- } // namespace
- } // namespace cc
|