--[[ Optimize_Controller 模块: 1、提供了检测帧率,调整LOD自适应的策略 帧率检测方法:检测当前帧之前一定数量(CheckTotalCount)的游戏帧中,deltaTime超过某一阈值(DeltaTimeThreshold)的帧数。 若此帧数超过设定帧数(CheckFrameCount)的次数在一定时间内(TotalCheckTick)高于可容忍的次数(JankTolerateCount), 则进行档位自适应调整。 自适应方法:若当前LOD档位为非自定义档位,则自动下降一档;否则直接调整到Lod0档位。 ]]-- local LuaUpdater = require("Main/LuaUpdater") local EventSystem = require("Event/EventSystem") local DeltaTimeThreshold = 0.05 --检测达成降档的DT阈值 local CheckTotalCount = 30 -- 当前帧之前,需要统计DT状态的帧数 local CheckFrameCount = 20 -- 需要统计的帧数中,DT高于阈值的数量 local JankTolerateCount = 3 -- 帧率检测到不达标的容忍次数 local TotalCheckTick = 2000 -- 连续检测帧率的最大次数 local Optimize_Controller = {} local private = { _accumulateReachQueue = { head = 1, tail = 1, size = 0, capacity = CheckTotalCount, array = LuaExt.CreateTable(CheckTotalCount), }, _frFailTickQueue = { head = 1, tail = 1, size = 0, capacity = JankTolerateCount, array = LuaExt.CreateTable(JankTolerateCount), }, _enableAutoDownLOD = true, _accumulateReachCount = 0, _frameCheckTick = 0, } function Optimize_Controller.OnStartup() if MDL.Setting.HasKey(LuaConst.SettingKeyEnum.Adaptive) then private._enableAutoDownLOD = MDL.Setting.GetKeyValue(LuaConst.SettingKeyEnum.Adaptive) end Optimize_Controller.StartFrameCheck() end function Optimize_Controller.OnShutdown() Optimize_Controller.StopFrameCheck() end function Optimize_Controller.GetAdaptiveLODState() return private._enableAutoDownLOD end function Optimize_Controller.EnableAdaptiveLOD(enable) private._enableAutoDownLOD = enable MDL.Setting.SetKeyValue(LuaConst.SettingKeyEnum.Adaptive, enable) if enable then private.StartFrameCheck() else private.StopFrameCheck() end end -- 开启帧率检测 外部接口 function Optimize_Controller.StartFrameCheck() if private._enableAutoDownLOD then private.StartFrameCheck() end end -- 关闭帧率检测的 外部接口 function Optimize_Controller.StopFrameCheck() if private._enableAutoDownLOD then private.StopFrameCheck() end end function Optimize_Controller.OnRealTimeUpdate(deltaTime, timeSinceUpdate) private._frameCheckTick = private._frameCheckTick + 1 local reachQueue = private._accumulateReachQueue if reachQueue.size == CheckTotalCount then if private.Dequeue(reachQueue) then private._accumulateReachCount = private._accumulateReachCount - 1 end end local reach = deltaTime >= DeltaTimeThreshold private.Enqueue(reachQueue, reach) if not reach then --当前帧如果没有出现未达标的情况,可以跳出 return end private._accumulateReachCount = private._accumulateReachCount + 1 if private._accumulateReachCount < CheckFrameCount then --还未达到帧率不达标的情况,可以跳出 return end private.ClearQueue(reachQueue) private._accumulateReachCount = 0 local tickQueue = private._frFailTickQueue if tickQueue.size == JankTolerateCount and private._frameCheckTick - private.Dequeue(tickQueue) < TotalCheckTick then private.ClearQueue(tickQueue) private._frameCheckTick = 0 EventSystem.Dispatch(EventID.Setting_OnAdaptiveQualityTrigger, true) else private.Enqueue(tickQueue, private._frameCheckTick) end end function Optimize_Controller.AdjustFrameCheckSensitivity(dtThreshold, totalCount, frameCount, tolerateTimes) Optimize_Controller.StopFrameCheck() DeltaTimeThreshold = dtThreshold CheckTotalCount = totalCount CheckFrameCount = frameCount JankTolerateCount = tolerateTimes private._accumulateReachQueue.capacity = CheckTotalCount private._accumulateReachQueue.array = LuaExt.CreateTable(CheckTotalCount) private._frFailTickQueue.capacity = JankTolerateCount private._frFailTickQueue.array = LuaExt.CreateTable(JankTolerateCount) Optimize_Controller.StartFrameCheck() end function private.StartFrameCheck() LuaUpdater.StartRealTimeUpdate(Optimize_Controller.OnRealTimeUpdate) private.ClearQueue(private._accumulateReachQueue) private.ClearQueue(private._frFailTickQueue) private._accumulateReachCount = 0 private._frameCheckTick = 0 end function private.StopFrameCheck() LuaUpdater.StopRealTimeUpdate(Optimize_Controller.OnRealTimeUpdate) end function private.Enqueue(queue,item) if queue.size == queue.capacity then logging.error(LTAG.ERROR,"fail: push a full queue") return end queue.array[queue.tail] = item queue.tail = queue.tail % queue.capacity + 1 queue.size = queue.size + 1 end function private.Dequeue(queue) if queue.size <= 0 then return nil end local item = queue.array[queue.head] queue.array[queue.head] = nil queue.head = queue.head % queue.capacity + 1 queue.size = queue.size - 1 return item end function private.ClearQueue(queue) table.clearArray(queue.array) queue.head = 1 queue.tail = 1 queue.size = 0 end return Optimize_Controller