This PR significantly enhances the speed of the PixelArray.make_surface() method through two main optimizations:
Matching Array and Surface Sizes: When the array size matches the surface size, the method simply copies the original surface and returns it, thereby eliminating the need for an extra copy loop.
Optimized Slicing with Matching Bpp: When the sizes don't match (i.e., slicing) but the source and destination "Bpp" are the same, the method now uses a faster approach using memcpy to copy entire rows instead of processing each pixel individually.
Note to reviewers: The changes regarding the switch body are just me moving the entire switch inside an else block, so there's no changes there rly, just to let you know and avoid you wasting time on checking the diff.
These improvements lead to substantial performance gains, though the extent of the speedup varies based on image size and Bpp:
When building a same sized Surface
When slicing (basically row_length - 1, shows memcpy improvement)
Program used:
import pygame
from pygame import PixelArray
from pygame.transform import scale as scale_surf
from data_utils import plot_tests, run_tests
pygame.init()
# ===========| CONFIG |===========
DO_TEST = 1
MAX_SIZE = 1000
REPETITIONS = 100
NUM_CALLS = 1
TITLE = "pixelarray test"
X_LABEL = "Surface size"
DO_SCATTER = True
MODE = "MIN"
LIMIT_TO_RANGE = MAX_SIZE
COMPARE_LIST = [
(1, 0),
(3, 2),
(5, 4),
(7, 6),
]
screen = pygame.display.set_mode((100, 100))
kwargs_dict = {
}
img32 = pygame.image.load("test_progs/background.jpg").convert(32)
img24 = pygame.image.load("test_progs/background.jpg").convert(24)
img16 = pygame.image.load("test_progs/background.jpg").convert(16)
img8 = pygame.image.load("test_progs/background.jpg").convert(8)
def test_setup(curr_size: int, g: dict):
# for sliced test
c = curr_size + 1
size = (c, c)
g["px_arr32"] = PixelArray(scale_surf(img32, size))[:c - 1, :]
g["px_arr24"] = PixelArray(scale_surf(img24, size))[:c - 1, :]
g["px_arr16"] = PixelArray(scale_surf(img16, size))[:c - 1, :]
g["px_arr8"] = PixelArray(scale_surf(img8, size))[:c - 1, :]
# for non-sliced test
# g["px_arr32"] = PixelArray(scale_surf(img32, (curr_size, curr_size)))
# g["px_arr24"] = PixelArray(scale_surf(img24, (curr_size, curr_size)))
# g["px_arr16"] = PixelArray(scale_surf(img16, (curr_size, curr_size)))
# g["px_arr8"] = PixelArray(scale_surf(img8, (curr_size, curr_size)))
tests = [
("pixelArray make_surface new 32 (:)", "px_arr32.make_surface()"),
("pixelArray make_surface old 24 (:)", "px_arr24.make_surface()"),
("pixelArray make_surface old 16 (:)", "px_arr16.make_surface()"),
("pixelArray make_surface old 8 (:)", "px_arr8.make_surface()"),
]
files = [
# ("pixelArray make_surface new 32", "white"),
# ("pixelArray make_surface old 32", "violet"),
#
# ("pixelArray make_surface new 24", "red"),
# ("pixelArray make_surface old 24", "yellow"),
#
# ("pixelArray make_surface new 16", "lime"),
# ("pixelArray make_surface old 16", "blue"),
#
# ("pixelArray make_surface new 8", "yellow"),
# ("pixelArray make_surface old 8", "green"),
("pixelArray make_surface new 32 (:)", "white"),
("pixelArray make_surface old 32 (:)", "violet"),
("pixelArray make_surface new 24 (:)", "red"),
("pixelArray make_surface old 24 (:)", "yellow"),
("pixelArray make_surface new 16 (:)", "lime"),
("pixelArray make_surface old 16 (:)", "blue"),
("pixelArray make_surface new 8 (:)", "yellow"),
("pixelArray make_surface old 8 (:)", "green"),
]
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)
This PR significantly enhances the speed of the
PixelArray.make_surface()
method through two main optimizations:Note to reviewers: The changes regarding the switch body are just me moving the entire switch inside an else block, so there's no changes there rly, just to let you know and avoid you wasting time on checking the diff.
These improvements lead to substantial performance gains, though the extent of the speedup varies based on image size and Bpp:
When building a same sized Surface
When slicing (basically row_length - 1, shows memcpy improvement)
Program used:
background image:![background](https://github.com/pygame-community/pygame-ce/assets/103119829/64fa9bce-a16b-4012-ad28-74982eb93a2a)
data utils file (as .txt): data_utils.txt