New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Faster blit_with_alpha() #14448
Faster blit_with_alpha() #14448
Conversation
Texture test nodes can be helpful to test if `blit_with_alpha` works correctly. The alpha compositing test node covers different cases where pixel colours are mixed with each other. The test currently fails because `blitPixel` does not work correctly if a semi-transparent colour is drawn on top of another semi-transparent colour. The test nodes for the fill texture modifier show if the size and position arguments of the modifer work correctly. They do not cover special cases such as very large or negative position or size values.
d5db142
to
cfc8524
Compare
The `blit_with_alpha` function has a noticeable effect on the time it takes to join a game. To reduce the join times, I replace the `blit_with_alpha` function with a new one: * It does not uses floating-point numbers. * It directly operates on the raw pixel data instead of using the comparatively slow `setPixel` and `getPixel` functions from Irrlicht. Only ECF_A8R8G8B8 base images are supported now. If the top image does not have the ECF_A8R8G8B8 colour format, it is converted; I assume that this happens rarely. * There are case distinctions for fully opaque, fully transparent and semi-transparent pixels. This empirically increases the performance since the mixing between two semi-transparent happens rarely. * The new function no longer has the `src_pos` argument since it was always the zero vector. * The function is only documented once where it is declared. For backwards compatibility, `blit_with_alpha` still mixes colours without gamma correction. `blit_with_alpha` nonetheless behaves slightly different than before: If a semi-transparent pixel is drawn on top of another semi-transparent pixel, the colour is mixed in a way which we can consider to be more correct now.
cfc8524
to
b436467
Compare
I have tested the performance with different implementation decisions now by collecting the I tried it 9 times and there were 1687 With the branches the median duration was ca. 0.037 s. Without the branches the median was ca. 0.082 s. With the branches, a small reordering, and using SColor, the median was ca. 0.026 s. With |
I also noticed how texture overlay is not alpha blending if both are semitransparent. I've made test mod for this: codelocal function trigger_hud(player)
local row_height = 0.05
local base_pos = {x=0.2,y=0.2}
local ncolumns = 4
local tex_checker = "[png:"..minetest.encode_base64(minetest.encode_png(ncolumns, 1, {
{a=255, r=200, g=200, b=200},
{a=255, r=55, g=55, b=55},
{a=255, r=200, g=200, b=200},
{a=255, r=55, g=55, b=55},
}))
local tex_a = "[png:"..minetest.encode_base64(minetest.encode_png(ncolumns, 1, {
{a=255, r=255, g=255, b=255},
{a=250, r=255, g=255, b=255},
{a=1, r=0, g=255, b=0},
{a=0, r=0, g=255, b=0},
}))
local tex_b = "[png:"..minetest.encode_base64(minetest.encode_png(ncolumns, 1, {
{a=8, r=255, g=0, b=0},
{a=8, r=255, g=0, b=0},
{a=127, r=255, g=0, b=0},
{a=127, r=255, g=0, b=0},
}))
-- name, texturestring
local rows = {
{"test_tmp:checker", tex_checker},
{"test_tmp:a", tex_a},
{"test_tmp:b", tex_b},
{"test_tmp:a_b", tex_a.."^"..tex_b},
{"test_tmp:a_b_hud", tex_a},
}
local function draw_row_at(i, at, z_offset)
player:hud_add({
type = "image",
position = {x=base_pos.x, y=base_pos.y+at*row_height},
name = rows[i][1],
scale = {x=-100*row_height*ncolumns, y=-100*row_height},
text = rows[i][2],
alignment = {x=1, y=1},
offset = {x=0, y=0},
z_index = 1000 + (z_offset or 0),
})
end
for row = 1, #rows do
draw_row_at(row, row)
end
draw_row_at(3, 5, 1)
end
minetest.register_node("test_tmp:node1", {
description = "Node1",
tiles = {"default_pine_tree_top.png"},
groups = { dig_immediate = 2 },
on_punch = function(_pos, _node, puncher, _pointed_thing)
if minetest.is_player(puncher) then
trigger_hud(puncher)
end
end,
}) But the alpha test node you added also shows this. In master, there are some texels that are different. I agree that we can consider this change in behaviour a bugfix though. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code looks fine otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested, works. 👍
Joined your land server. It was about 1/3 (5 s) faster. And blit_with_alpha
is in the flamegraph basically completely gone.
Thanks!
Avoid braces and auto
More verbose blit_pixel documentation and fix rounding
More verbose blit_pixel documentation and fix rounding
cast max output instead of its arguments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
blit_with_alpha
function has a noticeable effect on the time it takes to join a game.To reduce the join times, I replace the
blit_with_alpha
function with a new one:slow
setPixel
andgetPixel
functions from Irrlicht.Only ECF_A8R8G8B8 base images are supported now.
If the top image does not have the ECF_A8R8G8B8 colour format, it is converted;
I assume that this happens rarely.
This empirically increases the performance since the mixing between two semi-transparent happens rarely.
src_pos
argument since it was always the zero vector.For backwards compatibility,
blit_with_alpha
still mixes colours without gamma correction.blit_with_alpha
nonetheless behaves slightly different than before:If a semi-transparent pixel is drawn on top of another semi-transparent pixel,
the colour is mixed in a way which we can consider to be more correct now.
Related issue: #14322
Roadmap goal: 2.1 Rendering/Graphics improvements (perhaps)
To do
This PR is a Ready for Review.
How to test
time
, join the server with the following command:time bin/minetest --name your_name --address 127.0.0.1 --go
With the mods I commonly use, I could observe a speedup from 2.5 s to 2.2 s real time and a speedup from 1.3 s to 1.0 s user CPU time.
The speedup may be different with large textures and/or a different selection of mods.
Joining the game may not be the only situation which is faster with the new
blit_with_alpha
function.