@doegis/core
Version:
DOE GIS API
3 lines (1 loc) • 11.3 kB
JavaScript
import e from"../../core/Handles.js";import"../../core/has.js";import t from"../../core/Logger.js";import{removeMaybe as s,isSome as r}from"../../core/maybe.js";import i from"../../core/PerformanceSampler.js";import a from"../../core/PooledArray.js";import{isAborted as n,createAbortError as _,when as u}from"../../core/promiseUtils.js";import{watch as h,initial as o,when as d}from"../../core/reactiveUtils.js";import{Milliseconds as E}from"../../core/time.js";import{ObservableValue as l}from"../../core/accessorSupport/tracking/ObservableValue.js";import{PromiseQueue as T}from"../../layers/support/PromiseQueue.js";import c from"./debugFlags.js";import{RenderState as m}from"./RenderState.js";function g(){return new U.Scheduler}var I,R;!function(e){e[e.YIELD=1]="YIELD"}(I||(I={})),function(e){e.RESOURCE_CONTROLLER_IMMEDIATE="immediate",e.RESOURCE_CONTROLLER="schedule",e.SLIDE="slide",e.STREAM_DATA_LOADER="stream loader",e.ELEVATION_QUERY="elevation query",e.TERRAIN_SURFACE="terrain",e.SURFACE_GEOMETRY_UPDATES="surface geometry updates",e.LOD_RENDERER="LoD renderer",e.GRAPHICS_CORE="Graphics3D",e.I3S_CONTROLLER="I3S",e.POINT_CLOUD_LAYER="point cloud",e.FEATURE_TILE_FETCHER="feature fetcher",e.OVERLAY="overlay",e.STAGE="stage",e.GRAPHICS_DECONFLICTOR="graphics deconflictor",e.FILTER_VISIBILITY="Graphics3D filter visibility",e.SCALE_VISIBILITY="Graphics3D scale visibility",e.FRUSTUM_VISIBILITY="Graphics3D frustum visibility",e.POINT_OF_INTEREST_FREQUENT="POI frequent",e.POINT_OF_INTEREST_INFREQUENT="POI infrequent",e.LABELER="labeler",e.FEATURE_QUERY_ENGINE="feature query",e.FEATURE_TILE_TREE="feature tile tree",e.FEATURE_TILE_TREE_ACTIVE="fast feature tile tree",e.ELEVATION_ALIGNMENT="elevation alignment",e.TEXT_TEXTURE_ATLAS="text texture atlas",e.TEXTURE_UNLOAD="texture unload",e.LINE_OF_SIGHT_TOOL="line of sight tool",e.LINE_OF_SIGHT_TOOL_INTERACTIVE="interactive line of sight tool",e.ELEVATION_PROFILE="elevation profile",e.SNAPPING="snapping",e.SHADOW_ACCUMULATOR="shadow accumulator",e.CLOUDS_GENERATOR="clouds generator",e[e.TEST_PRIO=1]="TEST_PRIO"}(R||(R={}));const p=0,f=new Map([[R.RESOURCE_CONTROLLER_IMMEDIATE,p],[R.RESOURCE_CONTROLLER,4],[R.SLIDE,p],[R.STREAM_DATA_LOADER,p],[R.ELEVATION_QUERY,p],[R.TERRAIN_SURFACE,1],[R.SURFACE_GEOMETRY_UPDATES,1],[R.LOD_RENDERER,2],[R.GRAPHICS_CORE,2],[R.I3S_CONTROLLER,2],[R.POINT_CLOUD_LAYER,2],[R.FEATURE_TILE_FETCHER,2],[R.OVERLAY,4],[R.STAGE,4],[R.GRAPHICS_DECONFLICTOR,4],[R.FILTER_VISIBILITY,4],[R.SCALE_VISIBILITY,4],[R.FRUSTUM_VISIBILITY,4],[R.CLOUDS_GENERATOR,4],[R.POINT_OF_INTEREST_FREQUENT,6],[R.POINT_OF_INTEREST_INFREQUENT,30],[R.LABELER,8],[R.FEATURE_QUERY_ENGINE,8],[R.FEATURE_TILE_TREE,16],[R.FEATURE_TILE_TREE_ACTIVE,p],[R.ELEVATION_ALIGNMENT,12],[R.TEXT_TEXTURE_ATLAS,12],[R.TEXTURE_UNLOAD,12],[R.LINE_OF_SIGHT_TOOL,16],[R.LINE_OF_SIGHT_TOOL_INTERACTIVE,p],[R.SNAPPING,p],[R.SHADOW_ACCUMULATOR,30]]);function L(e){return f.has(e)?f.get(e):"number"==typeof e?e:1}const A=E(6.5),b=E(1),S=E(30),k=E(1e3/30),O=E(100),N=.9;var U,C;!function(n){class _{get updating(){return this._updating.get()}_updatingChanged(){this._updating.set(this._tasks.some((e=>e.needsUpdate)))}constructor(){this._updating=new l(!0),this._microTaskQueued=!1,this._frameNumber=0,this.performanceInfo={total:new i("total"),tasks:new Map},this._frameTaskTimes=new Map,this._budget=new g,this._state=m.INTERACTING,this._tasks=new a,this._runQueue=new a,this._load=0,this._idleStateCallbacks=new a,this._idleUpdatesStartFired=!1,this._forceTask=!1,this._debug=!1,this._debugHandle=h((()=>c.SCHEDULER_LOG_SLOW_TASKS),(e=>this._debug=e),o);for(const t of Object.keys(R))this.performanceInfo.tasks.set(R[t],new i(R[t]));const e=this;this._test={FRAME_SAFETY_BUDGET:A,INTERACTING_BUDGET:k,IDLE_BUDGET:O,get availableBudget(){return e._budget.budget},usedBudget:0,getBudget:()=>e._budget,setBudget:t=>e._budget=t,updateTask:e=>this._updateTask(e),getState:e=>this._getState(e),getRuntime:e=>this._getRuntime(e),frameTaskTimes:this._frameTaskTimes,resetRuntimes:()=>this._resetRuntimes(),getRunning:()=>this._getRunning()}}destroy(){this._tasks.toArray().forEach((e=>e.remove())),this._tasks.clear(),s(this._debugHandle),this._microTaskQueued=!1,this._updatingChanged()}taskRunningChanged(e){this._updatingChanged(),e&&this._budget.remaining>0&&!this._microTaskQueued&&(this._microTaskQueued=!0,queueMicrotask((()=>{this._microTaskQueued&&(this._microTaskQueued=!1,this._budget.remaining>0&&this._schedule()&&this.frame())})))}registerTask(e,t){const s=L(e),r=new u(this,e,t,s);return this._tasks.push(r),this._updatingChanged(),this.performanceInfo.tasks.has(e)||this.performanceInfo.tasks.set(e,new i(e)),r}registerIdleStateCallbacks(e,t){const s={idleBegin:e,idleEnd:t};this._idleStateCallbacks.push(s),this.state===m.IDLE&&this._idleUpdatesStartFired&&s.idleBegin();const r=this;return{remove:()=>this._removeIdleStateCallbacks(s),set idleBegin(e){r._idleUpdatesStartFired&&(s.idleEnd(),r._state===m.IDLE&&e()),s.idleBegin=e},set idleEnd(e){s.idleEnd=e}}}get load(){return this._load}set state(e){this._state!==e&&(this._state=e,this.state!==m.IDLE&&this._idleUpdatesStartFired&&(this._idleUpdatesStartFired=!1,this._idleStateCallbacks.forAll((e=>e.idleEnd()))))}get state(){return this._state}updateBudget(e){this._test.usedBudget=0,++this._frameNumber;let t=A,s=e.frameDuration,r=b;switch(this.state){case m.IDLE:t=E(0),s=E(Math.max(O,e.frameDuration)),r=S;break;case m.INTERACTING:s=E(Math.max(k,e.frameDuration));case m.ANIMATING:}return s=E(s-e.elapsedFrameTime-t),this.state!==m.IDLE&&s<b&&!this._forceTask?(this._forceTask=!0,!1):(s=E(Math.max(s,r)),this._budget.reset(s,this.state),this._updateLoad(),this._schedule())}frame(){switch(this._forceTask=!1,this._microTaskQueued=!1,this.state){case m.IDLE:this._idleUpdatesStartFired||(this._idleUpdatesStartFired=!0,this._idleStateCallbacks.forAll((e=>e.idleBegin()))),this._runIdle();break;case m.INTERACTING:this._runInteracting();break;default:this._runAnimating()}this._test.usedBudget=this._budget.elapsed}stopFrame(){this._budget.reset(E(0),this._state),this._budget.madeProgress()}_removeIdleStateCallbacks(e){this._idleUpdatesStartFired&&e.idleEnd(),this._idleStateCallbacks.removeUnordered(e)}removeTask(e){this._tasks.removeUnordered(e),this._runQueue.removeUnordered(e),this._updatingChanged()}_updateTask(e){this._tasks.forAll((t=>{t.name===e&&t.setPriority(e)}))}_getState(e){if(this._runQueue.some((t=>t.name===e)))return C.SCHEDULED;let t=C.IDLE;return this._tasks.forAll((s=>{s.name===e&&s.needsUpdate&&(s.schedulePriority<=1?t=C.READY:t!==C.READY&&(t=C.WAITING))})),t}_getRuntime(e){let t=0;return this._tasks.forAll((s=>{s.name===e&&(t+=s.runtime)})),t}_resetRuntimes(){this._tasks.forAll((e=>e.runtime=0))}_getRunning(){const e=new Map;if(this._tasks.forAll((t=>{t.needsUpdate&&e.set(t.name,(e.get(t.name)||0)+1)})),0===e.size)return null;let t="";return e.forEach(((e,s)=>{t+=e>1?` ${e}x ${s}`:` ${s}`})),t}_runIdle(){this._run()}_runInteracting(){this._run()}_runAnimating(){this._run()}_updateLoad(){const e=this._tasks.reduce(((e,t)=>t.needsUpdate?++e:e),0);this._load=this._load*N+e*(1-N)}_schedule(){for(this._runQueue.filterInPlace((e=>!!e.needsUpdate||(e.schedulePriority=e.basePriority,!1))),this._tasks.forAll((e=>{e.basePriority===p&&e.needsUpdate&&!this._runQueue.includes(e)&&e.blockFrame!==this._frameNumber&&this._runQueue.unshift(e)}));0===this._runQueue.length;){let e=!1,t=0;if(this._tasks.forAll((s=>{if(s.needsUpdate&&0!==s.schedulePriority&&s.basePriority!==p&&s.blockFrame!==this._frameNumber)if(e=!0,t=Math.max(t,s.basePriority),1===s.schedulePriority)s.schedulePriority=0,this._runQueue.push(s);else--s.schedulePriority})),!e)return this._updatingChanged(),!1}return this._updatingChanged(),!0}_run(){const e=this._budget.now();this._startFrameTaskTimes();do{for(;this._runQueue.length>0;){const r=this._budget.now(),i=this._runQueue.pop();this._budget.resetProgress();try{i.task.runTask(this._budget)===I.YIELD&&(i.blockFrame=this._frameNumber)}catch(s){t.getLogger("esri.views.support.Scheduler").error(`Exception in task "${i.name}"`,s)}!this._budget.hasProgressed&&i.blockFrame!==this._frameNumber&&i.needsUpdate&&(i.name,R.I3S_CONTROLLER,i.blockFrame=this._frameNumber),i.schedulePriority=i.basePriority;const a=this._budget.now()-r;if(i.runtime+=a,this._frameTaskTimes.set(i.priority,this._frameTaskTimes.get(i.priority)+a),this._debug&&a>2*this._budget.budget&&console.log("Task",i.name,"used",a,"of max",this._budget.budget,"ms"),this._budget.remaining<=0)return this._updatingChanged(),void this._recordFrameTaskTimes(this._budget.now()-e)}}while(this._schedule());this._updatingChanged(),this._recordFrameTaskTimes(this._budget.now()-e)}_startFrameTaskTimes(){for(const e of Object.keys(R))this._frameTaskTimes.set(R[e],0)}_recordFrameTaskTimes(e){this._frameTaskTimes.forEach(((e,t)=>this.performanceInfo.tasks.get(t).record(e))),this.performanceInfo.total.record(e)}get test(){return this._test}}n.Scheduler=_;class u{get task(){return this._task.get()}get updating(){return this._queue.running}constructor(t,s,i,a){this._scheduler=t,this.name=s,this._basePriority=a,this.blockFrame=0,this.runtime=0,this._queue=new T,this._handles=new e,this.schedulePriority=this._basePriority,this._task=new l(r(i)?i:this._queue),this._handles.add(d((()=>this.task.running),(e=>t.taskRunningChanged(e))))}remove(){this.processQueue(P),this._scheduler.removeTask(this),this.schedule=D.schedule,this.reschedule=D.reschedule,this._handles.destroy()}get basePriority(){return this._basePriority}setPriority(e){this.name=e;const t=L(e);this._basePriority!==p&&0===this.schedulePriority||(this.schedulePriority=t),this._basePriority=t}get priority(){return this.name}set priority(e){this.setPriority(e)}get needsUpdate(){return this.updating||this.task.running}schedule(e,t,s){return this._queue.push(e,t,s)}reschedule(e,t,s){return this._queue.unshift(e,t,s)}processQueue(e){this._queue.runTask(e)}}class g{constructor(){this._begin="undefined"!=typeof performance?performance.now():0,this._budget=0,this._state=m.IDLE,this._done=!1,this._progressed=!1,this._enabled=!0}run(e){return!this.done&&(!0===e()&&this.madeProgress(),!0)}get done(){return this._done}get budget(){return this._budget}madeProgress(){return this._progressed=!0,this._done=this.elapsed>=this._budget&&this._enabled,this._done}get state(){return this._state}get enabled(){return this._enabled}set enabled(e){this._enabled=e}reset(e,t){this._begin=this.now(),this._budget=e,this._state=t,this.resetProgress()}get remaining(){return Math.max(this._budget-this.elapsed,0)}now(){return performance.now()}get elapsed(){return performance.now()-this._begin}resetProgress(){this._progressed=!1,this._done=!1}get hasProgressed(){return this._progressed}}n.Budget=g}(U||(U={})),function(e){e.SCHEDULED="s",e.READY="r",e.WAITING="w",e.IDLE="i"}(C||(C={}));const P=(()=>{const e=new U.Budget;return e.enabled=!1,e})();class F{remove(){}processQueue(){}schedule(e,t,s){try{if(n(t)){const e=_();return s?Promise.resolve(s(e)):Promise.reject(e)}return u(e(P))}catch(r){return Promise.reject(r)}}reschedule(e,t,s){return this.schedule(e,t,s)}}const D=new F;export{D as ImmediateTask,I as Task,R as TaskPriority,C as TaskState,L as getTaskPriority,g as newScheduler,P as noBudget,f as taskPriorities};