Roblox backend: 60 Hz render cap (SetRenderRate) and MicroProfiler labels (SetProfiling)
This commit is contained in:
@@ -1 +1 @@
|
||||
[[12, "imgui.lua"], [13741, "imgui_demo.lua"], [14674, "imgui_demo_2.lua"], [17749, "imgui_demo_apps.lua"], [19008, "imgui_demo_tools.lua"], [20334, "imgui_demo_widgets.lua"], [22258, "imgui_docking.lua"], [25386, "imgui_dragdrop.lua"], [25678, "imgui_draw.lua"], [30866, "imgui_h.lua"], [33079, "imgui_impl_roblox.lua"], [33866, "imgui_impl_roblox_fonts.lua"], [40269, "imgui_internal.lua"], [43439, "imgui_tables.lua"], [47786, "imgui_tabs.lua"], [48953, "imgui_widgets.lua"], [57477, "imstb_rectpack.lua"], [57923, "imstb_textedit.lua"], [59164, "imstb_truetype.lua"], [61632, "imstd_minstdio.lua"]]
|
||||
[[12, "imgui.lua"], [13741, "imgui_demo.lua"], [14674, "imgui_demo_2.lua"], [17749, "imgui_demo_apps.lua"], [19008, "imgui_demo_tools.lua"], [20334, "imgui_demo_widgets.lua"], [22258, "imgui_docking.lua"], [25386, "imgui_dragdrop.lua"], [25678, "imgui_draw.lua"], [30866, "imgui_h.lua"], [33079, "imgui_impl_roblox.lua"], [33903, "imgui_impl_roblox_fonts.lua"], [40306, "imgui_internal.lua"], [43476, "imgui_tables.lua"], [47823, "imgui_tabs.lua"], [48990, "imgui_widgets.lua"], [57514, "imstb_rectpack.lua"], [57960, "imstb_textedit.lua"], [59201, "imstb_truetype.lua"], [61669, "imstd_minstdio.lua"]]
|
||||
+41
-2
@@ -33561,10 +33561,18 @@ local function DestroyTiles(bd)
|
||||
bd.Tiles = {}
|
||||
end
|
||||
|
||||
-- MicroProfiler labels, enabled with ImGui_ImplRoblox.SetProfiling(true)
|
||||
local profilebegin, profileend = debug.profilebegin, debug.profileend
|
||||
local profiling = false
|
||||
local function PB(name) if profiling then profilebegin(name) end end
|
||||
local function PE() if profiling then profileend() end end
|
||||
|
||||
@native
|
||||
function ImGui_ImplRoblox_RenderDrawData(draw_data)
|
||||
local bd = ImGui_ImplRoblox_GetBackendData()
|
||||
PB("ImGui RenderDrawData")
|
||||
|
||||
PB("ImGui textures")
|
||||
if draw_data.Textures ~= nil then
|
||||
for _, tex in draw_data.Textures:iter() do
|
||||
if tex.Status ~= ImTextureStatus.OK then
|
||||
@@ -33573,9 +33581,17 @@ function ImGui_ImplRoblox_RenderDrawData(draw_data)
|
||||
end
|
||||
end
|
||||
end
|
||||
PE()
|
||||
|
||||
-- Render rate cap: textures are always updated (imgui expects it), tiles only at bd.RenderRate Hz
|
||||
if bd.RenderRate > 0 then
|
||||
local now = os.clock()
|
||||
if now + 0.002 < bd.NextRender then PE(); return end
|
||||
bd.NextRender = math.max(bd.NextRender + 1 / bd.RenderRate, now)
|
||||
end
|
||||
|
||||
local sw, sh = floor(draw_data.DisplaySize.x), floor(draw_data.DisplaySize.y)
|
||||
if sw <= 0 or sh <= 0 then return end
|
||||
if sw <= 0 or sh <= 0 then PE(); return end
|
||||
local cols, rows = ceil(sw / TILE), ceil(sh / TILE)
|
||||
if cols ~= bd.TileCols or rows ~= bd.TileRows then
|
||||
DestroyTiles(bd)
|
||||
@@ -33592,6 +33608,7 @@ function ImGui_ImplRoblox_RenderDrawData(draw_data)
|
||||
end
|
||||
|
||||
-- Pass 1: collect primitives, hash them into tiles
|
||||
PB("ImGui tile hash")
|
||||
local n = 0
|
||||
for _, draw_list in draw_data.CmdLists:iter() do
|
||||
local vtx, idx = draw_list.VtxBuffer.Data, draw_list.IdxBuffer.Data
|
||||
@@ -33666,7 +33683,10 @@ function ImGui_ImplRoblox_RenderDrawData(draw_data)
|
||||
end
|
||||
end
|
||||
|
||||
PE()
|
||||
|
||||
-- Pass 2: redraw + upload changed tiles
|
||||
PB("ImGui raster+upload")
|
||||
local force = bd.ForceRedraw
|
||||
bd.ForceRedraw = false
|
||||
for ty = 0, rows - 1 do
|
||||
@@ -33702,7 +33722,9 @@ function ImGui_ImplRoblox_RenderDrawData(draw_data)
|
||||
DrawTriangle(va, pr_b[p], vc, pr_t[p], cx0, cy0, cx1, cy1, tox, toy)
|
||||
end
|
||||
end
|
||||
PB("ImGui upload")
|
||||
tile.Image:WritePixelsBuffer(Vector2.zero, TILE_SIZE, buf)
|
||||
PE()
|
||||
end
|
||||
if not tile.Visible then
|
||||
tile.Visible = true
|
||||
@@ -33715,6 +33737,7 @@ function ImGui_ImplRoblox_RenderDrawData(draw_data)
|
||||
-- drop references so old vertex tables can be collected
|
||||
for k = n + 1, bd.LastPrimCount do pr_a[k], pr_b[k], pr_c[k], pr_d[k], pr_t[k] = nil, nil, nil, nil, nil end
|
||||
bd.LastPrimCount = n
|
||||
PE(); PE()
|
||||
end
|
||||
|
||||
---------------------------------------------------------
|
||||
@@ -33738,7 +33761,7 @@ function ImGui_ImplRoblox_Init(parent, render_scale)
|
||||
local bd = {
|
||||
Time = os.clock(), Gui = gui, Connections = {},
|
||||
Textures = {}, TextureCount = 0, MouseX = -1, MouseY = -1,
|
||||
Tiles = {}, TileCols = 0, TileRows = 0, Scale = render_scale or 1, TilesActive = false, TH1 = {}, TH2 = {}, TN = {}, TL = {}, LastPrimCount = 0, ForceRedraw = true,
|
||||
Tiles = {}, TileCols = 0, TileRows = 0, Scale = render_scale or 1, TilesActive = false, RenderRate = 60, NextRender = 0, TH1 = {}, TH2 = {}, TN = {}, TL = {}, LastPrimCount = 0, ForceRedraw = true,
|
||||
}
|
||||
io.BackendPlatformUserData = bd
|
||||
|
||||
@@ -33811,6 +33834,7 @@ function ImGui_ImplRoblox_Shutdown()
|
||||
end
|
||||
|
||||
function ImGui_ImplRoblox_NewFrame()
|
||||
PB("ImGui NewFrame (backend)")
|
||||
local io = ImGui.GetIO()
|
||||
local bd = ImGui_ImplRoblox_GetBackendData()
|
||||
|
||||
@@ -33839,8 +33863,18 @@ function ImGui_ImplRoblox_NewFrame()
|
||||
bd.TilesActive = want
|
||||
for _, tile in pairs(bd.Tiles) do tile.Label.Active = want end
|
||||
end
|
||||
PE()
|
||||
end
|
||||
|
||||
--- Max tile redraws per second (default 60); 0 = every frame. imgui logic still runs every frame.
|
||||
function ImGui_ImplRoblox_SetRenderRate(hz)
|
||||
ImGui_ImplRoblox_GetBackendData().RenderRate = hz or 0
|
||||
end
|
||||
|
||||
--- Toggle MicroProfiler labels (debug.profilebegin) for the backend
|
||||
function ImGui_ImplRoblox_SetProfiling(enabled) profiling = enabled and true or false end
|
||||
local function ImGui_ImplRoblox_IsProfiling() return profiling end
|
||||
|
||||
function ImGui_ImplRoblox_SetRenderScale(scale)
|
||||
local bd = ImGui_ImplRoblox_GetBackendData()
|
||||
if scale == bd.Scale then return end
|
||||
@@ -33857,6 +33891,9 @@ ImGui_ImplRoblox = {
|
||||
RenderDrawData = ImGui_ImplRoblox_RenderDrawData,
|
||||
AddFile = ImGui_ImplRoblox_AddFile,
|
||||
SetRenderScale = ImGui_ImplRoblox_SetRenderScale,
|
||||
SetRenderRate = ImGui_ImplRoblox_SetRenderRate,
|
||||
SetProfiling = ImGui_ImplRoblox_SetProfiling,
|
||||
IsProfiling = ImGui_ImplRoblox_IsProfiling,
|
||||
}
|
||||
|
||||
return true -- [Roblox] ModuleScripts must return exactly one value
|
||||
@@ -62244,6 +62281,8 @@ return {
|
||||
ImGui_ImplRoblox_Init = ImGui_ImplRoblox_Init,
|
||||
ImGui_ImplRoblox_NewFrame = ImGui_ImplRoblox_NewFrame,
|
||||
ImGui_ImplRoblox_RenderDrawData = ImGui_ImplRoblox_RenderDrawData,
|
||||
ImGui_ImplRoblox_SetProfiling = ImGui_ImplRoblox_SetProfiling,
|
||||
ImGui_ImplRoblox_SetRenderRate = ImGui_ImplRoblox_SetRenderRate,
|
||||
ImGui_ImplRoblox_SetRenderScale = ImGui_ImplRoblox_SetRenderScale,
|
||||
ImGui_ImplRoblox_Shutdown = ImGui_ImplRoblox_Shutdown,
|
||||
ImGui_ImplRoblox_UpdateTexture = ImGui_ImplRoblox_UpdateTexture,
|
||||
|
||||
@@ -483,10 +483,18 @@ local function DestroyTiles(bd)
|
||||
bd.Tiles = {}
|
||||
end
|
||||
|
||||
-- MicroProfiler labels, enabled with ImGui_ImplRoblox.SetProfiling(true)
|
||||
local profilebegin, profileend = debug.profilebegin, debug.profileend
|
||||
local profiling = false
|
||||
local function PB(name) if profiling then profilebegin(name) end end
|
||||
local function PE() if profiling then profileend() end end
|
||||
|
||||
@native
|
||||
function ImGui_ImplRoblox_RenderDrawData(draw_data)
|
||||
local bd = ImGui_ImplRoblox_GetBackendData()
|
||||
PB("ImGui RenderDrawData")
|
||||
|
||||
PB("ImGui textures")
|
||||
if draw_data.Textures ~= nil then
|
||||
for _, tex in draw_data.Textures:iter() do
|
||||
if tex.Status ~= ImTextureStatus.OK then
|
||||
@@ -495,9 +503,17 @@ function ImGui_ImplRoblox_RenderDrawData(draw_data)
|
||||
end
|
||||
end
|
||||
end
|
||||
PE()
|
||||
|
||||
-- Render rate cap: textures are always updated (imgui expects it), tiles only at bd.RenderRate Hz
|
||||
if bd.RenderRate > 0 then
|
||||
local now = os.clock()
|
||||
if now + 0.002 < bd.NextRender then PE(); return end
|
||||
bd.NextRender = math.max(bd.NextRender + 1 / bd.RenderRate, now)
|
||||
end
|
||||
|
||||
local sw, sh = floor(draw_data.DisplaySize.x), floor(draw_data.DisplaySize.y)
|
||||
if sw <= 0 or sh <= 0 then return end
|
||||
if sw <= 0 or sh <= 0 then PE(); return end
|
||||
local cols, rows = ceil(sw / TILE), ceil(sh / TILE)
|
||||
if cols ~= bd.TileCols or rows ~= bd.TileRows then
|
||||
DestroyTiles(bd)
|
||||
@@ -514,6 +530,7 @@ function ImGui_ImplRoblox_RenderDrawData(draw_data)
|
||||
end
|
||||
|
||||
-- Pass 1: collect primitives, hash them into tiles
|
||||
PB("ImGui tile hash")
|
||||
local n = 0
|
||||
for _, draw_list in draw_data.CmdLists:iter() do
|
||||
local vtx, idx = draw_list.VtxBuffer.Data, draw_list.IdxBuffer.Data
|
||||
@@ -588,7 +605,10 @@ function ImGui_ImplRoblox_RenderDrawData(draw_data)
|
||||
end
|
||||
end
|
||||
|
||||
PE()
|
||||
|
||||
-- Pass 2: redraw + upload changed tiles
|
||||
PB("ImGui raster+upload")
|
||||
local force = bd.ForceRedraw
|
||||
bd.ForceRedraw = false
|
||||
for ty = 0, rows - 1 do
|
||||
@@ -624,7 +644,9 @@ function ImGui_ImplRoblox_RenderDrawData(draw_data)
|
||||
DrawTriangle(va, pr_b[p], vc, pr_t[p], cx0, cy0, cx1, cy1, tox, toy)
|
||||
end
|
||||
end
|
||||
PB("ImGui upload")
|
||||
tile.Image:WritePixelsBuffer(Vector2.zero, TILE_SIZE, buf)
|
||||
PE()
|
||||
end
|
||||
if not tile.Visible then
|
||||
tile.Visible = true
|
||||
@@ -637,6 +659,7 @@ function ImGui_ImplRoblox_RenderDrawData(draw_data)
|
||||
-- drop references so old vertex tables can be collected
|
||||
for k = n + 1, bd.LastPrimCount do pr_a[k], pr_b[k], pr_c[k], pr_d[k], pr_t[k] = nil, nil, nil, nil, nil end
|
||||
bd.LastPrimCount = n
|
||||
PE(); PE()
|
||||
end
|
||||
|
||||
---------------------------------------------------------
|
||||
@@ -660,7 +683,7 @@ function ImGui_ImplRoblox_Init(parent, render_scale)
|
||||
local bd = {
|
||||
Time = os.clock(), Gui = gui, Connections = {},
|
||||
Textures = {}, TextureCount = 0, MouseX = -1, MouseY = -1,
|
||||
Tiles = {}, TileCols = 0, TileRows = 0, Scale = render_scale or 1, TilesActive = false, TH1 = {}, TH2 = {}, TN = {}, TL = {}, LastPrimCount = 0, ForceRedraw = true,
|
||||
Tiles = {}, TileCols = 0, TileRows = 0, Scale = render_scale or 1, TilesActive = false, RenderRate = 60, NextRender = 0, TH1 = {}, TH2 = {}, TN = {}, TL = {}, LastPrimCount = 0, ForceRedraw = true,
|
||||
}
|
||||
io.BackendPlatformUserData = bd
|
||||
|
||||
@@ -733,6 +756,7 @@ function ImGui_ImplRoblox_Shutdown()
|
||||
end
|
||||
|
||||
function ImGui_ImplRoblox_NewFrame()
|
||||
PB("ImGui NewFrame (backend)")
|
||||
local io = ImGui.GetIO()
|
||||
local bd = ImGui_ImplRoblox_GetBackendData()
|
||||
|
||||
@@ -761,8 +785,18 @@ function ImGui_ImplRoblox_NewFrame()
|
||||
bd.TilesActive = want
|
||||
for _, tile in pairs(bd.Tiles) do tile.Label.Active = want end
|
||||
end
|
||||
PE()
|
||||
end
|
||||
|
||||
--- Max tile redraws per second (default 60); 0 = every frame. imgui logic still runs every frame.
|
||||
function ImGui_ImplRoblox_SetRenderRate(hz)
|
||||
ImGui_ImplRoblox_GetBackendData().RenderRate = hz or 0
|
||||
end
|
||||
|
||||
--- Toggle MicroProfiler labels (debug.profilebegin) for the backend
|
||||
function ImGui_ImplRoblox_SetProfiling(enabled) profiling = enabled and true or false end
|
||||
local function ImGui_ImplRoblox_IsProfiling() return profiling end
|
||||
|
||||
function ImGui_ImplRoblox_SetRenderScale(scale)
|
||||
local bd = ImGui_ImplRoblox_GetBackendData()
|
||||
if scale == bd.Scale then return end
|
||||
@@ -779,6 +813,9 @@ ImGui_ImplRoblox = {
|
||||
RenderDrawData = ImGui_ImplRoblox_RenderDrawData,
|
||||
AddFile = ImGui_ImplRoblox_AddFile,
|
||||
SetRenderScale = ImGui_ImplRoblox_SetRenderScale,
|
||||
SetRenderRate = ImGui_ImplRoblox_SetRenderRate,
|
||||
SetProfiling = ImGui_ImplRoblox_SetProfiling,
|
||||
IsProfiling = ImGui_ImplRoblox_IsProfiling,
|
||||
}
|
||||
|
||||
return true -- [Roblox] ModuleScripts must return exactly one value
|
||||
|
||||
+11
-3
@@ -74,10 +74,17 @@ for _, name in ipairs({ "Cousine-Regular", "DroidSans", "Karla-Regular", "Proggy
|
||||
end
|
||||
|
||||
ImGui_ImplRoblox.Init(nil, render_scale)
|
||||
ImGui_ImplRoblox.SetRenderRate(60) -- tile redraws per second; imgui logic + your code still run every frame
|
||||
ImGui_ImplRoblox.SetProfiling(true) -- MicroProfiler (Ctrl+F6) labels; turn off when not profiling
|
||||
|
||||
local function P(name) if ImGui_ImplRoblox.IsProfiling() then debug.profilebegin(name) end end
|
||||
local function PE() if ImGui_ImplRoblox.IsProfiling() then debug.profileend() end end
|
||||
|
||||
RunService.Stepped:Connect(function()
|
||||
P("ImGui frame")
|
||||
ImGui_ImplRoblox.NewFrame()
|
||||
ImGui.NewFrame()
|
||||
P("ImGui.NewFrame"); ImGui.NewFrame(); PE()
|
||||
P("ImGui UI")
|
||||
|
||||
-- Dockspace covering the whole screen; the centre stays transparent so the game shows through
|
||||
ImGui.DockSpaceOverViewport(0, nil, G.ImGuiDockNodeFlags.PassthruCentralNode)
|
||||
@@ -119,7 +126,8 @@ RunService.Stepped:Connect(function()
|
||||
ImGui.End()
|
||||
end
|
||||
|
||||
ImGui.EndFrame()
|
||||
ImGui.Render()
|
||||
PE()
|
||||
P("ImGui.Render"); ImGui.EndFrame(); ImGui.Render(); PE()
|
||||
ImGui_ImplRoblox.RenderDrawData(ImGui.GetDrawData())
|
||||
PE()
|
||||
end)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
debug = setmetatable({ profilebegin = function() end, profileend = function() end }, { __index = debug })
|
||||
-- Minimal Roblox mock for running the imgui Roblox backend + the real CanvasDraw module in the Luau CLI.
|
||||
local realG = {} -- (no getfenv: it would mark the global env unsafe and deoptimize everything)
|
||||
FAKE_TIME = 0
|
||||
|
||||
Reference in New Issue
Block a user