Skip to content

Commit 07e4522

Browse files
authored
Improve PixelArray.make_surface() performance (#2953)
* optimized PixelArray make_surface() both when making a same sized surf from the array and when slicing. * fix comment
1 parent 717c861 commit 07e4522

File tree

1 file changed

+78
-56
lines changed

1 file changed

+78
-56
lines changed

src_c/pixelarray_methods.c

Lines changed: 78 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -125,17 +125,22 @@ _make_surface(pgPixelArrayObject *array, PyObject *args)
125125

126126
surf = pgSurface_AsSurface(array->surface);
127127
bpp = PG_SURF_BytesPerPixel(surf);
128-
129-
/* Create the second surface. */
130-
131-
temp_surf = PG_CreateSurface((int)dim0, (int)dim1, surf->format->format);
132-
if (!temp_surf) {
133-
return RAISE(pgExc_SDLError, SDL_GetError());
128+
temp_surf = surf;
129+
const int same_dims = (dim0 == surf->w && dim1 == surf->h);
130+
131+
/* If the array dimensions are different from the surface dimensions,
132+
* create a new surface with the array dimensions */
133+
if (!same_dims) {
134+
if (!(temp_surf = PG_CreateSurface((int)dim0, (int)dim1,
135+
surf->format->format)))
136+
return RAISE(pgExc_SDLError, SDL_GetError());
134137
}
135138

136-
/* Guarantee an identical format. */
139+
/* Ensure the new surface has the same format as the original */
137140
new_surf = PG_ConvertSurface(temp_surf, surf->format);
138-
SDL_FreeSurface(temp_surf);
141+
if (temp_surf != surf)
142+
SDL_FreeSurface(temp_surf);
143+
139144
if (!new_surf) {
140145
return RAISE(pgExc_SDLError, SDL_GetError());
141146
}
@@ -146,6 +151,10 @@ _make_surface(pgPixelArrayObject *array, PyObject *args)
146151
return 0;
147152
}
148153

154+
/* if the surf and array dims match just return a copy */
155+
if (same_dims)
156+
return (PyObject *)new_surface;
157+
149158
/* Acquire a temporary lock. */
150159
if (SDL_MUSTLOCK(new_surf) == 0) {
151160
SDL_LockSurface(new_surf);
@@ -158,58 +167,71 @@ _make_surface(pgPixelArrayObject *array, PyObject *args)
158167
new_pixelrow = new_pixels;
159168

160169
Py_BEGIN_ALLOW_THREADS;
161-
switch (bpp) {
162-
case 1:
163-
for (y = 0; y < dim1; ++y) {
164-
pixel_p = pixelrow;
165-
new_pixel_p = new_pixelrow;
166-
for (x = 0; x < dim0; ++x) {
167-
*new_pixel_p = *pixel_p;
168-
pixel_p += stride0;
169-
new_pixel_p += new_stride0;
170+
171+
if (stride0 == new_stride0) {
172+
/* if src and dest have the same bpp, so we can copy the whole
173+
* rows at once */
174+
y = dim1;
175+
while (y--) {
176+
memcpy(new_pixelrow, pixelrow, stride0 * dim0);
177+
pixelrow += stride1;
178+
new_pixelrow += new_stride1;
179+
}
180+
}
181+
else {
182+
switch (bpp) {
183+
case 1:
184+
for (y = 0; y < dim1; ++y) {
185+
pixel_p = pixelrow;
186+
new_pixel_p = new_pixelrow;
187+
for (x = 0; x < dim0; ++x) {
188+
*new_pixel_p = *pixel_p;
189+
pixel_p += stride0;
190+
new_pixel_p += new_stride0;
191+
}
192+
pixelrow += stride1;
193+
new_pixelrow += new_stride1;
170194
}
171-
pixelrow += stride1;
172-
new_pixelrow += new_stride1;
173-
}
174-
break;
175-
case 2:
176-
for (y = 0; y < dim1; ++y) {
177-
pixel_p = pixelrow;
178-
new_pixel_p = new_pixelrow;
179-
for (x = 0; x < dim0; ++x) {
180-
*((Uint16 *)new_pixel_p) = *((Uint16 *)pixel_p);
181-
pixel_p += stride0;
182-
new_pixel_p += new_stride0;
195+
break;
196+
case 2:
197+
for (y = 0; y < dim1; ++y) {
198+
pixel_p = pixelrow;
199+
new_pixel_p = new_pixelrow;
200+
for (x = 0; x < dim0; ++x) {
201+
*((Uint16 *)new_pixel_p) = *((Uint16 *)pixel_p);
202+
pixel_p += stride0;
203+
new_pixel_p += new_stride0;
204+
}
205+
pixelrow += stride1;
206+
new_pixelrow += new_stride1;
183207
}
184-
pixelrow += stride1;
185-
new_pixelrow += new_stride1;
186-
}
187-
break;
188-
case 3:
189-
for (y = 0; y < dim1; ++y) {
190-
pixel_p = pixelrow;
191-
new_pixel_p = new_pixelrow;
192-
for (x = 0; x < dim0; ++x) {
193-
memcpy(new_pixel_p, pixel_p, 3);
194-
pixel_p += stride0;
195-
new_pixel_p += new_stride0;
208+
break;
209+
case 3:
210+
for (y = 0; y < dim1; ++y) {
211+
pixel_p = pixelrow;
212+
new_pixel_p = new_pixelrow;
213+
for (x = 0; x < dim0; ++x) {
214+
memcpy(new_pixel_p, pixel_p, 3);
215+
pixel_p += stride0;
216+
new_pixel_p += new_stride0;
217+
}
218+
pixelrow += stride1;
219+
new_pixelrow += new_stride1;
196220
}
197-
pixelrow += stride1;
198-
new_pixelrow += new_stride1;
199-
}
200-
break;
201-
default: /* case: 4 */
202-
for (y = 0; y < dim1; ++y) {
203-
pixel_p = pixelrow;
204-
new_pixel_p = new_pixelrow;
205-
for (x = 0; x < dim0; ++x) {
206-
*((Uint32 *)new_pixel_p) = *((Uint32 *)pixel_p);
207-
pixel_p += stride0;
208-
new_pixel_p += new_stride0;
221+
break;
222+
default: /* case: 4 */
223+
for (y = 0; y < dim1; ++y) {
224+
pixel_p = pixelrow;
225+
new_pixel_p = new_pixelrow;
226+
for (x = 0; x < dim0; ++x) {
227+
*((Uint32 *)new_pixel_p) = *((Uint32 *)pixel_p);
228+
pixel_p += stride0;
229+
new_pixel_p += new_stride0;
230+
}
231+
pixelrow += stride1;
232+
new_pixelrow += new_stride1;
209233
}
210-
pixelrow += stride1;
211-
new_pixelrow += new_stride1;
212-
}
234+
}
213235
}
214236
Py_END_ALLOW_THREADS;
215237

0 commit comments

Comments
 (0)