pygame-community / pygame-ce

🐍🎮 pygame - Community Edition is a FOSS Python library for multimedia applications (like games). Built on top of the excellent SDL library.
https://pyga.me
767 stars 120 forks source link

Optimized `mask.from_surface()` when converting an alpha surface. #2895

Open itzpr3d4t0r opened 1 month ago

itzpr3d4t0r commented 1 month ago

This PR massively speeds up mask.from_surface() when dealing with the threshold argument (for 24 and 32 bit surfaces, about a 12% improvement for 16 and lower).

It achieves so by directly accessing the pixel's alpha channels instead of using SDL's functionality which is not only slow but actually did more work that we actually need for this operation by also returning the rgb channels.

With this new strategy we just jump from pixel's alpha to pixel's alpha and check that against the threshold.

I've also added a fast path for 24-bit surfaces bringing an astonishing 737 times improved runtime since we now use bitmask_fill.

I've also added a validity check for the threshold argument which wasn't there before.

here are the results: image

made with this test program:

from data_utils import plot_tests, run_tests
import pygame
from pygame.mask import from_surface

pygame.init()

# ===========| CONFIG |===========

DO_TEST = 0
MAX_SIZE = 1000
REPETITIONS = 100
NUM_CALLS = 1

TITLE = "from_surface"
X_LABEL = "Surface size"
DO_SCATTER = True
MODE = "MIN"
LIMIT_TO_RANGE = MAX_SIZE
COMPARE_LIST = [(-1, 0)]
kwargs_dict = {"from_surface": from_surface}

def test_setup(curr_size: int, g: dict):
    s = pygame.Surface((curr_size, curr_size), pygame.SRCALPHA, 32)
    pygame.draw.circle(s, (255, 255, 255, 128), (curr_size // 2, curr_size // 2), curr_size // 2)
    g["s"] = s

tests = [
    ("mask from_surface new", "from_surface(s)"),
]

files = [
    ("mask from_surface new", "red"),
    ("mask from_surface old", "white")
]

if DO_TEST:
    run_tests(tests, test_setup, MAX_SIZE, REPETITIONS, NUM_CALLS, **kwargs_dict)

pygame.quit()

plot_tests(TITLE, files, MODE, LIMIT_TO_RANGE, DO_SCATTER, False, COMPARE_LIST,
           X_LABEL)

The data utils file (as txt): data_utils.txt