From 72c222fc1f3378252b6bb8138db4d67f4a103084 Mon Sep 17 00:00:00 2001 From: richard Date: Sun, 13 Jun 2021 16:31:08 +0100 Subject: [PATCH] benchmark --- README.md | 20 +++- examples/textures/resources/wabbit_alpha.png | Bin 0 -> 496 bytes examples/textures/textures_bunnymark.py | 111 ++++++++++++++++++ .../textures/textures_bunnymark_dynamic.py | 111 ++++++++++++++++++ .../textures_bunnymark_more_pythonic.py | 110 +++++++++++++++++ 5 files changed, 350 insertions(+), 2 deletions(-) create mode 100644 examples/textures/resources/wabbit_alpha.png create mode 100644 examples/textures/textures_bunnymark.py create mode 100644 examples/textures/textures_bunnymark_dynamic.py create mode 100644 examples/textures/textures_bunnymark_more_pythonic.py diff --git a/README.md b/README.md index 1f080dc..aa02798 100644 --- a/README.md +++ b/README.md @@ -222,5 +222,21 @@ See test_dynamic.py for how to use. * converting more examples from C to python * testing and building on more platforms - * sorting out binary wheel distribution for Mac/Win and compile-from-source distributtion for Linux - + +# Performance + +For fastest permformance use Pypy rather than standard python. + +Every call to C is costly, so it's slightly faster if you use Python data structures and functions when calculating +in your update loop +and then only convert them to C data structures when you have to call the C functions for drawing. + +## Bunnymark + + +| Library | Implementation | Bunnies (60 FPS) | Percentage | +| ------------- | ------------- | ------------- | ------------- | +| Raylib 3.7 | C | 168100 | 100% | +| Raylib Python CFFI 3.7 | Pypy 3.7 | 33800 | 20% | +| Raylib Python CFFI 3.7 | Python 3.9 | 6800 | 4% | + diff --git a/examples/textures/resources/wabbit_alpha.png b/examples/textures/resources/wabbit_alpha.png new file mode 100644 index 0000000000000000000000000000000000000000..db4081fec5a801d4b6f2beeafca4a0dffbe5d333 GIT binary patch literal 496 zcmVkdg0005ENklL3}oV1UkKwj zR!p+}SzGQ1Lo9AdRLcO<$^;0*lnoX=&J$YA5LPS!VBaua0r+$qJpH~0V9wxJFD(PA z&1m1B(Y*nPt}2}R`nVc48-pGk+oY0f~#SXp#a2JUX%FH!|NU~u>Ux$NYShaVV# zxM9^@%P2RMzigf8kd2c+5PIidYcGl)n+CSN2R)N`?X1;_lBc?+5VD(*r^hK+fbnP$;y&koBO>l}`piuGtifTyxd7z=IjkKWV z<|mKp*eBaXAq@k&-1Y5Kafh=3yHrmDg>;#_$(i-TN-@4D-e)DRsn`coS6h^eTRRO$T00ld@}3ZH m<2RER$xNr(&-FgA{~G{&g0wAMhB_|*0000 GetScreenWidth()) or ((bunnies[i].position.x + texBunny.width/2) < 0): + bunnies[i].speed.x *= -1 + if ((bunnies[i].position.y + texBunny.height/2) > GetScreenHeight()) or ((bunnies[i].position.y + texBunny.height/2 - 40) < 0): + bunnies[i].speed.y *= -1 + + # //---------------------------------------------------------------------------------- + # + # // Draw + # //---------------------------------------------------------------------------------- + BeginDrawing() + + ClearBackground(RAYWHITE) + + for i in range(0, bunniesCount): + # // NOTE: When internal batch buffer limit is reached (MAX_BATCH_ELEMENTS), + # // a draw call is launched and buffer starts being filled again; + # // before issuing a draw call, updated vertex data from internal CPU buffer is send to GPU... + # // Process of sending data is costly and it could happen that GPU data has not been completely + # // processed for drawing while new data is tried to be sent (updating current in-use buffers) + # // it could generates a stall and consequently a frame drop, limiting the number of drawn bunnies + DrawTexture(texBunny, int(bunnies[i].position.x), int(bunnies[i].position.y), bunnies[i].color) + + DrawRectangle(0, 0, screenWidth, 40, BLACK) + text = f"bunnies {bunniesCount}" + DrawText(text.encode('utf-8'), 120, 10, 20, GREEN) + text = f"batched draw calls: { 1 + int(bunniesCount/MAX_BATCH_ELEMENTS)}" + DrawText(text.encode('utf-8'), 320, 10, 20, MAROON) + + DrawFPS(10, 10) + + EndDrawing() + #//---------------------------------------------------------------------------------- + + +#// De-Initialization +#//-------------------------------------------------------------------------------------- + + +UnloadTexture(texBunny); #Unload bunny texture + +CloseWindow() # Close window and OpenGL context +#//-------------------------------------------------------------------------------------- + diff --git a/examples/textures/textures_bunnymark_dynamic.py b/examples/textures/textures_bunnymark_dynamic.py new file mode 100644 index 0000000..aa78fcd --- /dev/null +++ b/examples/textures/textures_bunnymark_dynamic.py @@ -0,0 +1,111 @@ +# /******************************************************************************************* +# * +# * raylib [textures] example - Bunnymark +# * +# * This example has been created using raylib 1.6 (www.raylib.com) +# * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +# * +# * Copyright (c) 2014-2019 Ramon Santamaria (@raysan5) +# * +# ********************************************************************************************/ + +from raylib.static import * +MAX_BUNNIES = 500000 + +# This is the maximum amount of elements (quads) per batch +# NOTE: This value is defined in [rlgl] module and can be changed there +MAX_BATCH_ELEMENTS = 8192 + + +class Bunny: + def __init__(self): + self.position = ffi.new('struct Vector2 *', [0.0, 0.0]) + self.speed = ffi.new('struct Vector2 *', [0.0, 0.0]) + self.color = ffi.new('struct Color *', [0, 0, 0, 0]) + + +# // Initialization +# //-------------------------------------------------------------------------------------- +screenWidth = 1920; +screenHeight = 1080; + +InitWindow(screenWidth, screenHeight, b"raylib [textures] example - bunnymark") + +# // Load bunny texture +texBunny = LoadTexture(b"resources/wabbit_alpha.png") + +bunnies = [] +for i in range(0, MAX_BUNNIES): + bunnies.append(Bunny()) + +bunniesCount = 0; # Bunnies counter + +SetTargetFPS(60); # Set our game to run at 60 frames-per-second +#//-------------------------------------------------------------------------------------- + +#// Main game loop +while not WindowShouldClose(): #// Detect window close button or ESC key + #// Update + #//---------------------------------------------------------------------------------- + if IsMouseButtonDown(MOUSE_LEFT_BUTTON): + #// Create more bunnies + for i in range(0, 100): + if bunniesCount < MAX_BUNNIES: + bunnies[bunniesCount].position = GetMousePosition() + bunnies[bunniesCount].speed.x = GetRandomValue(-250, 250)/60.0 + bunnies[bunniesCount].speed.y = GetRandomValue(-250, 250)/60.0 + bunnies[bunniesCount].color = (GetRandomValue(50, 240), + GetRandomValue(80, 240), + GetRandomValue(100, 240), 255 ) + + bunniesCount+=1 + + + # // Update bunnies + for i in range(0, bunniesCount): + bunnies[i].position.x += bunnies[i].speed.x; + bunnies[i].position.y += bunnies[i].speed.y; + + if ((bunnies[i].position.x + texBunny.width/2) > GetScreenWidth()) or ((bunnies[i].position.x + texBunny.width/2) < 0): + bunnies[i].speed.x *= -1 + if ((bunnies[i].position.y + texBunny.height/2) > GetScreenHeight()) or ((bunnies[i].position.y + texBunny.height/2 - 40) < 0): + bunnies[i].speed.y *= -1 + + # //---------------------------------------------------------------------------------- + # + # // Draw + # //---------------------------------------------------------------------------------- + BeginDrawing() + + ClearBackground(RAYWHITE) + + for i in range(0, bunniesCount): + # // NOTE: When internal batch buffer limit is reached (MAX_BATCH_ELEMENTS), + # // a draw call is launched and buffer starts being filled again; + # // before issuing a draw call, updated vertex data from internal CPU buffer is send to GPU... + # // Process of sending data is costly and it could happen that GPU data has not been completely + # // processed for drawing while new data is tried to be sent (updating current in-use buffers) + # // it could generates a stall and consequently a frame drop, limiting the number of drawn bunnies + DrawTexture(texBunny, int(bunnies[i].position.x), int(bunnies[i].position.y), bunnies[i].color) + + DrawRectangle(0, 0, screenWidth, 40, BLACK) + text = f"bunnies {bunniesCount}" + DrawText(text.encode('utf-8'), 120, 10, 20, GREEN) + text = f"batched draw calls: { 1 + int(bunniesCount/MAX_BATCH_ELEMENTS)}" + DrawText(text.encode('utf-8'), 320, 10, 20, MAROON) + + DrawFPS(10, 10) + + EndDrawing() + #//---------------------------------------------------------------------------------- + + +#// De-Initialization +#//-------------------------------------------------------------------------------------- + + +UnloadTexture(texBunny); #Unload bunny texture + +CloseWindow() # Close window and OpenGL context +#//-------------------------------------------------------------------------------------- + diff --git a/examples/textures/textures_bunnymark_more_pythonic.py b/examples/textures/textures_bunnymark_more_pythonic.py new file mode 100644 index 0000000..ab8cd27 --- /dev/null +++ b/examples/textures/textures_bunnymark_more_pythonic.py @@ -0,0 +1,110 @@ +# Dont use C data structures when we can avoid it. Makes Pypy slightly faster. + +from raylib.static import * +import random + +MAX_BUNNIES = 500000 + +# This is the maximum amount of elements (quads) per batch +# NOTE: This value is defined in [rlgl] module and can be changed there +MAX_BATCH_ELEMENTS = 8192 + + +class Bunny: + def __init__(self): + self.position_x = 0.0 + self.position_y = 0.0 + self.speed_x = 0.0 + self.speed_y = 0.0 + self.color_r = 0 + self.color_g = 0 + self.color_b = 0 + self.color_a = 0 + + +# // Initialization +# //-------------------------------------------------------------------------------------- +screenWidth = 1920; +screenHeight = 1080; + +InitWindow(screenWidth, screenHeight, b"raylib [textures] example - bunnymark") + +# // Load bunny texture +texBunny = LoadTexture(b"resources/wabbit_alpha.png") + +bunnies = [] +for i in range(0, MAX_BUNNIES): + bunnies.append(Bunny()) + +bunniesCount = 0; # Bunnies counter + +SetTargetFPS(60); # Set our game to run at 60 frames-per-second +#//-------------------------------------------------------------------------------------- + +#// Main game loop +while not WindowShouldClose(): #// Detect window close button or ESC key + #// Update + #//---------------------------------------------------------------------------------- + if IsMouseButtonDown(MOUSE_LEFT_BUTTON): + #// Create more bunnies + for i in range(0, 100): + if bunniesCount < MAX_BUNNIES: + bunnies[bunniesCount].position_x = GetMousePosition().x + bunnies[bunniesCount].position_y = GetMousePosition().y + bunnies[bunniesCount].speed_x = random.randint(-250, 250)/60.0 + bunnies[bunniesCount].speed_y = random.randint(-250, 250)/60.0 + bunnies[bunniesCount].color_r = random.randint(50,240) + bunnies[bunniesCount].color_g = random.randint(80, 240) + bunnies[bunniesCount].color_b = random.randint(100, 240) + bunnies[bunniesCount].color_a = 255 + bunniesCount+=1 + + + # // Update bunnies + for i in range(0, bunniesCount): + bunnies[i].position_x += bunnies[i].speed_x + bunnies[i].position_y += bunnies[i].speed_y + + if ((bunnies[i].position_x + texBunny.width/2) > GetScreenWidth()) or ((bunnies[i].position_x + texBunny.width/2) < 0): + bunnies[i].speed_x *= -1 + if ((bunnies[i].position_y + texBunny.height/2) > GetScreenHeight()) or ((bunnies[i].position_y + texBunny.height/2 - 40) < 0): + bunnies[i].speed_y *= -1 + + # //---------------------------------------------------------------------------------- + # + # // Draw + # //---------------------------------------------------------------------------------- + BeginDrawing() + + ClearBackground(RAYWHITE) + + for i in range(0, bunniesCount): + # // NOTE: When internal batch buffer limit is reached (MAX_BATCH_ELEMENTS), + # // a draw call is launched and buffer starts being filled again; + # // before issuing a draw call, updated vertex data from internal CPU buffer is send to GPU... + # // Process of sending data is costly and it could happen that GPU data has not been completely + # // processed for drawing while new data is tried to be sent (updating current in-use buffers) + # // it could generates a stall and consequently a frame drop, limiting the number of drawn bunnies + DrawTexture(texBunny, int(bunnies[i].position_x), int(bunnies[i].position_y), (bunnies[i].color_r,bunnies[i].color_g,bunnies[i].color_b,bunnies[i].color_a)) + + DrawRectangle(0, 0, screenWidth, 40, BLACK) + text = f"bunnies {bunniesCount}" + DrawText(text.encode('utf-8'), 120, 10, 20, GREEN) + text = f"batched draw calls: { 1 + int(bunniesCount/MAX_BATCH_ELEMENTS)}" + DrawText(text.encode('utf-8'), 320, 10, 20, MAROON) + + DrawFPS(10, 10) + + EndDrawing() + #//---------------------------------------------------------------------------------- + + +#// De-Initialization +#//-------------------------------------------------------------------------------------- + + +UnloadTexture(texBunny); #Unload bunny texture + +CloseWindow() # Close window and OpenGL context +#//-------------------------------------------------------------------------------------- +