It was pointed out to me that the benchmark wasn't all that fair.
The python implementation didn't return a list of rects.

With that, Surface.blits takes 82%-85% of the time. Not 88%-92% as I stated
earlier.



In [4]: def blits(blit_list):
   ...:     ret = []
   ...:     for surface, dest in blit_list:
   ...:         ret.append(dst.blit(surface, dest))
   ...:     return ret
   ...:

In [5]:

In [5]: %timeit results = blits(blit_list)
841 µs ± 15 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [6]: %timeit results = dst.blits(blit_list)
715 µs ± 15.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [7]: (100. / 841) * 717
Out[7]: 85.25564803804994

In [8]: (100. / 841) * 688
Out[8]: 81.80737217598097




On Tue, Apr 3, 2018 at 3:45 PM, René Dudfield <ren...@gmail.com> wrote:

> Hellos,
>
> I made an initial implementation of Surface.blits(), focusing just on
> correctness, with no optimizations.
> https://github.com/pygame/pygame/pull/439
>
> In the micro benchmark below it takes from 88% to 92% of the time for 255
> surfaces
> compared to using Surface.blit in python in a loop over the same list.
>
>
>    .. method:: blits
>
>       | :sl:`draw many images onto another`
>       | :sg:`blits(blit_sequence=(source, dest), ...), doreturn=1) ->
> (Rect, ...)`
>       | :sg:`blits((source, dest, area), ...)) -> (Rect, ...)`
>       | :sg:`blits((source, dest, area, special_flags), ...)) -> (Rect,
> ...)`
>
>       Draws many surfaces onto this Surface. It takes a sequence as input,
>       with each of the elements corresponding to the ones of
> ``Surface.blit()``.
>       It needs at minimum a sequence of (source, dest).
>
>
>
> Considering blit is usually the slow part in most pygame apps, this is
> sort of nice.
>
> Note, I haven't updated pygame.sprite to use it. Volunteers?
> I feel without updating pygame.sprite, many people won't use it.
>
>
> Some benchmarking and other notes below.
>
>
> cheers,
>
>
>
>
> 1) Why not work on a faster implementation that saves the unwrapped
> objects?
> This would allow you to save a list into a C object like:
>
> struct blitinfo {
>  SDL_Surface dest;
>  GAME_Rect *src_rect;
>  GAME_Rect *area;
>  int flags;
> }
>
> Then if you promise not to change the C list (ie, you are updating rects
> in place, and all your Surfaces are still there),
> then it could avoid a lot of the unwrapping work.
>
> However, I did a test where I commented out the blit call. So only the
> unwrapping and looping over the list is done.
> And it seems that the python book keeping for these 255 10x10 surfaces is
> only 2.1%-3.3% of the total time taken.
>
>
>
> 2) Another optimization would be to avoid subsurface checks, and avoid a
> few other preparations for surfaces.
> I tried this, and didn't see any noticeable improvement.
>
> 3) Currently neither SDL1 or SDL2 have a special batched blit, but there
> are proposals and implementations around.
> Such as SDL_GPU.
> This could see a bigger improvement on such backends where changing state
> is slow (OpenGL etc).
>
>
>
>
>
> import pygame
> from pygame.locals import *
> NUM_SURFS = 255
> dst = pygame.Surface((NUM_SURFS * 10, 10), SRCALPHA, 32)
> dst.fill((230, 230, 230))
>
> blit_list = []
> for i in range(NUM_SURFS):
>     dest = (i * 10, 0)
>     surf = pygame.Surface((10, 10), SRCALPHA, 32)
>     color = (i * 1, i * 1, i * 1)
>     surf.fill(color)
>     blit_list.append((surf, dest))
>
> def blits(blit_list):
>     for surface, dest in blit_list:
>         dst.blit(surface, dest)
>
>
>
> In [17]: %timeit results = blits(blit_list)
> 774 µs ± 24.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
>
> In [18]: %timeit results = dst.blits(blit_list)
> 717 µs ± 12.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
>
> In [19]: %timeit results = dst.blits(blit_list, doreturn=0)
> 688 µs ± 14.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
>
> In [20]: (100. / 774) * 717
> Out[20]: 92.63565891472868
>
> In [21]: (100. / 774) * 688
> Out[21]: 88.88888888888889
>
>
>
> If I comment out the actual blit call...
>
> In [3]:  %timeit results = dst.blits(blit_list)
> 26.2 µs ± 695 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
>
> In [4]: %timeit results = dst.blits(blit_list, doreturn=0)
> 17.6 µs ± 314 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
>
>
> In [5]: (100. / 774) * 26
> Out[5]: 3.3591731266149867
>
> In [6]: (100. / 774) * 17
> Out[6]: 2.1963824289405682
>
>
>
>
> On Thu, Mar 30, 2017 at 7:12 PM, Leif Theden <leif.the...@gmail.com>
> wrote:
>
>> Pull request sent with basic functionality of Surface.blits.
>>
>> https://bitbucket.org/pygame/pygame/pull-requests/79
>>
>> On Thu, Mar 30, 2017 at 2:44 AM, René Dudfield <ren...@gmail.com> wrote:
>>
>>> Not sure. I need to do some benchmarking, and then more research into if
>>> the API can cover everything we want it to do. (which of course means
>>> figuring it out). So far I think the API I proposed will help with the
>>> Groups we have, and will also help with people who don't care about dirty
>>> rects.
>>>
>>> It's not really much code... as you can see Leif has already done
>>> something like it... it's just a for loop around blit basically.
>>> https://gist.github.com/bitcraft/1785face7c5684916cde
>>>
>>> If someone who just knows python wants to help, they could begin writing
>>> unit tests for it in test/surface_test.py
>>>
>>> My pygame things are basically these at the moment. If anyone wants to
>>> do the blits() API, that's fine too!
>>>
>>> * keep improving https://pygame.org/wiki/GettingStarted , gather and
>>> file usability bugs with pip, python, pygame...
>>> * help finalise github move decision/move.
>>> * blits
>>> * cython sprites.*Group
>>> * SDL2 stuff
>>>
>>>
>>> cheers,
>>>
>>>
>>>
>>>
>>> On Thu, Mar 30, 2017 at 8:02 AM, DiliupG <dili...@gmail.com> wrote:
>>>
>>>> When will this fabulous upgrade be available? :)
>>>>
>>>> On 29 March 2017 at 12:58, René Dudfield <ren...@gmail.com> wrote:
>>>>
>>>>> On Wed, Mar 29, 2017 at 8:33 AM, Radomir Dopieralski <
>>>>> pyg...@sheep.art.pl> wrote:
>>>>>
>>>>>> I think that special_flags could be shared for all the blits in the
>>>>>> list. I can't think of a case where I would want to use different
>>>>>> flags
>>>>>> for each.
>>>>>>
>>>>>>
>>>>> Yeah, I think you may be right. When I've used it (for particles as an
>>>>> example) it was for everything in a Group. I searched through some code
>>>>> online and found a few uses where it was used in Sprites. But then all of
>>>>> those Sprites were rendered the same. There's some sort of nice symmetry 
>>>>> by
>>>>> using the same arguments with blit, and blits however.
>>>>>
>>>>
>>>>
>>>>
>>>> --
>>>> Kalasuri Diliup Gabadamudalige
>>>>
>>>> https://dahamgatalu.wordpress.com/
>>>> http://soft.diliupg.com/
>>>> http://www.diliupg.com
>>>>
>>>> ************************************************************
>>>> **********************************
>>>> This e-mail is confidential. It may also be legally privileged. If you
>>>> are not the intended recipient or have received it in error, please delete
>>>> it and all copies from your system and notify the sender immediately by
>>>> return e-mail. Any unauthorized reading, reproducing, printing or further
>>>> dissemination of this e-mail or its contents is strictly prohibited and may
>>>> be unlawful. Internet communications cannot be guaranteed to be timely,
>>>> secure, error or virus-free. The sender does not accept liability for any
>>>> errors or omissions.
>>>> ************************************************************
>>>> **********************************
>>>>
>>>>
>>>
>>
>

Reply via email to