Difference between revisions of "Optimizations"

From GiderosMobile
 
(5 intermediate revisions by the same user not shown)
Line 12: Line 12:
 
* '''[[Trigonometry Conversion Operators]]'''
 
* '''[[Trigonometry Conversion Operators]]'''
 
* '''[[Type Checking]]'''
 
* '''[[Type Checking]]'''
 +
 +
=== TexturePack ===
 +
You should always pack your textures ''';-)'''
 +
* '''[[TexturePack]]'''
 +
 +
=== Texture format ===
 +
You may want to change the Texture format to improve speed:
 +
<syntaxhighlight lang="lua">
 +
local tex = Texture.new("myimage.png", false, { format=TextureBase.RGBA4444 })
 +
local bitmap = Bitmap.new(tex)
 +
</syntaxhighlight>
 +
 +
Available formats:
 +
* TextureBase.A8
 +
* TextureBase.RGB565
 +
* TextureBase.RGB888
 +
* TextureBase.RGBA4444
 +
* TextureBase.RGBA5551
 +
* TextureBase.RGBA8888
 +
* TextureBase.Y8
 +
* TextureBase.YA8
 +
 +
Please see: '''[[TextureBase]]''' and '''[[Texture.new]]'''
 +
 +
=== Gideros Functions ===
 +
*'''[[Stage:setClearColorBuffer]]'''
 +
*'''[[Collectgarbage]]'''
 +
*'''[[Setsafeenv]]'''
  
 
=== Various Functions ===
 
=== Various Functions ===
 +
Gideros 2025.2 introduces '''setsafeenv'''(''flags'') which tells Luau the global environment is "safe" and so enables optimizations. ''flags'' parameter indicates which optimizations to enable, and you'll probably want them all by using -1 value.
 +
<syntaxhighlight lang="lua">
 +
setsafeenv(-1)
 +
</syntaxhighlight>
 +
 +
You can add '''''setsafeenv(-1)''''' at the beginning of the following tests to see the difference.
 +
 
==== '''Distance''' ====
 
==== '''Distance''' ====
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
Line 105: Line 140:
 
math.distance                  (53ms) distance: 9881.908570716489
 
math.distance                  (53ms) distance: 9881.908570716489
 
Luau VECTORS                    (24ms) distance: 9881.908520118976]]
 
Luau VECTORS                    (24ms) distance: 9881.908520118976]]
 +
</syntaxhighlight>
 +
 +
==== '''Clamp''' ====
 +
<syntaxhighlight lang="lua">
 +
-- clamp (based on simple functions test timer by @antix)
 +
local clamp, random = math.clamp, math.random
 +
 +
local v, mi, ma = random(-15, 15), -10, 10
 +
 +
-- init
 +
local result = clamp(v, mi, ma)
 +
print("")
 +
print("*** V: "..v, "MIN: "..mi, "MAX: "..ma)
 +
print("*** CLAMPED: "..result)
 +
print("")
 +
 +
local function fclamp(v, min, max)
 +
return (v <> min) >< max
 +
end
 +
 +
-- tests
 +
local data = {
 +
{
 +
"math.clamp ",
 +
function()
 +
result = clamp(v ,mi, ma)
 +
end, -- 38ms
 +
},
 +
{
 +
"clamp function ",
 +
function()
 +
result = fclamp(v ,mi, ma)
 +
end, -- 20ms, no comments!
 +
},
 +
}
 +
 +
-- run all functions
 +
for i = 1, #data do
 +
local block = data[i]
 +
local func = block[2]
 +
local start = os.timer()
 +
for i = 1, 1000000 do -- 1 million repetitions!
 +
func()
 +
end
 +
local elapsed = math.floor((os.timer() - start) * 1000)
 +
print(block[1].." ("..elapsed.."ms)", "", "clamped value: "..result)
 +
end
 +
 +
--[[ RESULTS
 +
 +
*** V: -1 MIN: -10 MAX: 10
 +
*** CLAMPED: -1
 +
 +
math.clamp (38ms) clamped value: -1
 +
clamp function (20ms) clamped value: -1
 +
 +
]]
 
</syntaxhighlight>
 
</syntaxhighlight>
  

Latest revision as of 20:58, 5 May 2025

Supported platforms: Platform android.pngPlatform ios.pngPlatform mac.pngPlatform pc.pngPlatform html5.pngPlatform winrt.pngPlatform win32.pngPlatform linux.png

When you're ready to optimize your game, this page can be helpful.

Luau

You can take advantage of Luau new features added to Gideros:

TexturePack

You should always pack your textures ;-)

Texture format

You may want to change the Texture format to improve speed:

local tex = Texture.new("myimage.png", false, { format=TextureBase.RGBA4444 })
local bitmap = Bitmap.new(tex)

Available formats:

  • TextureBase.A8
  • TextureBase.RGB565
  • TextureBase.RGB888
  • TextureBase.RGBA4444
  • TextureBase.RGBA5551
  • TextureBase.RGBA8888
  • TextureBase.Y8
  • TextureBase.YA8

Please see: TextureBase and Texture.new

Gideros Functions

Various Functions

Gideros 2025.2 introduces setsafeenv(flags) which tells Luau the global environment is "safe" and so enables optimizations. flags parameter indicates which optimizations to enable, and you'll probably want them all by using -1 value.

setsafeenv(-1)

You can add setsafeenv(-1) at the beginning of the following tests to see the difference.

Distance

-- distance (based on simple functions test timer by @antix)
local distance, random, sqrt = math.distance, math.random, math.sqrt

local x1, y1, x2, y2 = random(-10000, 10000), random(-10000, 10000), random(-10000, 10000), random(-10000, 10000)

-- classic (boring!)
local dx, dy
-- with vectors
local p1, p2 = vector(x1, y1), vector(x2, y2)

-- init
local dist = distance(x1, y1, x2, y2)
print("")
print("*** POINT A: "..x1, y1, "POINT B: "..x2, y2)
print("*** DISTANCE:      "..dist)

dist = #(p2-p1)
print("*** VECTORS DIST.: "..dist)
print("")

-- tests
local data = {
	{
		"sqrt                           ",
		function()
			dx, dy = x2-x1, y2-y1
			dist = sqrt(dx*dx + dy*dy)
		end, -- 50ms
	},
	{
		"exponent                       ",
		function()
			dx, dy = x2-x1, y2-y1
			dist = (dx^2 + dy^2)^0.5
		end, -- 37ms
	},
	{
		"multiply/exponent              ",
		function()
			dx, dy = x2-x1, y2-y1
			dist = (dx*dx + dy*dy)^0.5
		end, -- 40ms
	},
	{
		"multiply/exponent without power",
		function()
			dx, dy = x2-x1, y2-y1
--			dist = dx*dx + dy*dy
			dist = dx^2 + dy^2
		end, -- 36ms but wrong result!
	},
	{
		"math.distance                  ",
		function()
			dist = distance(x1, y1, x2, y2)
		end, -- 53ms
	},
	{
		"Luau VECTORS                   ",
		function()
			dist = #(p2-p1)
		end, -- 24ms => this is our WINNER (Gideros 2024.11+)
	},
}
 
-- run all functions
for i = 1, #data do
	local block = data[i]
	local func = block[2]
	local start = os.timer()
	for i = 1, 1000000 do -- 1 million repetitions!
		func()
	end
	local elapsed = math.floor((os.timer() - start) * 1000)
	print(block[1].." ("..elapsed.."ms)", "", "distance: "..dist)
end

--[[ RESULTS

*** POINT A: -4709	7129	POINT B: 5172	7263
*** DISTANCE:      9881.908570716489
*** VECTORS DIST.: 9881.908520118976

sqrt                            (50ms)		distance: 9881.908570716489
exponent                        (37ms)		distance: 9881.908570716489
multiply/exponent               (40ms)		distance: 9881.908570716489
multiply/exponent without power (36ms)		distance: 97652117
math.distance                   (53ms)		distance: 9881.908570716489
Luau VECTORS                    (24ms)		distance: 9881.908520118976]]

Clamp

-- clamp (based on simple functions test timer by @antix)
local clamp, random = math.clamp, math.random

local v, mi, ma = random(-15, 15), -10, 10

-- init
local result = clamp(v, mi, ma)
print("")
print("*** V: "..v, "MIN: "..mi, "MAX: "..ma)
print("*** CLAMPED:	"..result)
print("")

local function fclamp(v, min, max)
	return (v <> min) >< max
end

-- tests
local data = {
	{
		"math.clamp		",
		function()
			result = clamp(v ,mi, ma)
		end, -- 38ms
	},
	{
		"clamp function	",
		function()
			result = fclamp(v ,mi, ma)
		end, -- 20ms, no comments!
	},
}
 
-- run all functions
for i = 1, #data do
	local block = data[i]
	local func = block[2]
	local start = os.timer()
	for i = 1, 1000000 do -- 1 million repetitions!
		func()
	end
	local elapsed = math.floor((os.timer() - start) * 1000)
	print(block[1].." ("..elapsed.."ms)", "", "clamped value: "..result)
end

--[[ RESULTS

*** V: -1	MIN: -10	MAX: 10
*** CLAMPED:	-1

math.clamp		 (38ms)		clamped value: -1
clamp function	 (20ms)		clamped value: -1

]]

Sprite Sorting

-- sprite sorting (based on simple functions test timer by @antix)
local random = math.random

local sprites = {}

for i = 1, 64 do
	sprites[i] = {}
	sprites[i].spr1 = Pixel.new(0x0, 1, 64, 64)
	sprites[i].spr1:setPosition(random(1, 640), 48) -- 48, 96
	stage:addChild(sprites[i].spr1)
	sprites[i].spr2 = Pixel.new(0xff0000, 1, 64, 64)
	sprites[i].spr2:setPosition(random(1, 640), 64)
	stage:addChild(sprites[i].spr2)
end

local spr1y, spr2y = 0, 0

-- tests
local data = {
	{
		"swap",
		function()
			for _, v in pairs(sprites) do
				if v.spr1:getY() < v.spr2:getY() then
					spr1y, spr2y = v.spr1:getY(), v.spr2:getY()
					stage:swapChildren(v.spr1, v.spr2)
				end
			end
		end, -- 816ms (much better than addChildAt)
	},
	{
		"addChildAt",
		function()
			for _, v in pairs(sprites) do
				if v.spr1:getY() < v.spr2:getY() then
					spr1y, spr2y = v.spr1:getY(), v.spr2:getY()
					stage:addChildAt(v.spr1, stage:getChildIndex(v.spr2))
				end
			end
		end, -- 1272ms
	},
	{
		"async swap",
		function()
			local function fun()
				for _, v in pairs(sprites) do
					if v.spr1:getY() < v.spr2:getY() then
						spr1y, spr2y = v.spr1:getY(), v.spr2:getY()
						stage:swapChildren(v.spr1, v.spr2)
					end
				end
			end
			Core.asyncCall(fun) -- profiler seems to be faster without asyncCall (because of pairs traversing?)
		end, -- 29ms (the best but has some glitches!)
	},
}
 
-- run all functions
for i = 1, #data do
	local block = data[i]
	local func = block[2]
	local start = os.timer()
	for i = 1, 25000 do func() end -- 12500
	local elapsed = math.floor((os.timer() - start) * 1000)
	print(block[1].." ("..elapsed.."ms)", spr1y, spr2y)
end




More to come, God's willing!