Skip to content

Extremely poor VertexArray performance #151

Description

@Flandan

Hi, I am hitting a bit of a performance barrier using this library.

Using the sf.VertexArray I have done some quick and dirty benchmarks:
with N = 5000
sf.VertexArray of size N: ~15ms for a single window.draw() call
list of N sf.CircleShape objects: ~14ms for N window.draw() calls (for loop)

If I increase N, the time taken increases much faster for the list of CircleShapes as expected. For the vertex array the increase is marginal for up to N=50000. Great news!
Only problem is this weird baseline ~15ms that is used regardless. With any application we only have 16.7ms to maintain a constant 60 fps which leaves us with no budget for anything other than drawing. Given the VertexArray is really the only goto for batch-like drawing this poses a serious problem.

Is there some sort of workaround for this issue?

My quick (and very dirty) test:

from sfml import sf
import time

N = 5000

vertex_array = sf.VertexArray(sf.PrimitiveType.POINTS, N)
shape_list = [sf.CircleShape(5.0) for i in range(N)]

window = sf.RenderWindow(sf.VideoMode(1366, 768), "Benchmark Window")#, sf.Style.FULLSCREEN)

window.clear()

time.sleep(0.3)

time_initial = time.time()
window.draw(vertex_array)

time_va = time.time()
for shape in shape_list:
    window.draw(shape)
    
time_sa = time.time()

elapsedA = (time_va - time_initial)*1000.0
elapsedB = (time_sa - time_va)*1000.0

print("VertexArray: %f" % elapsedA, flush=True)
print("list of shapes: %f" % elapsedB, flush=True)

Activity

  1. Flandan commented on Mar 24, 2017

    @Flandan
    Author

    Ok so after some more exploration of the examples in this repository I have come up with a workaround. By wrapping the VertexArray in a class that inherits from sf.Drawable and drawing that instead, the mystery 15ms seems to disappear and becomes < 1ms.

    class VertDrawable(sf.Drawable):
        def __init__(self):
            sf.Drawable.__init__(self)
            self.points = sf.VertexArray(sf.PrimitiveType.POINTS)
            for i in range(0, LENGTH):
                self.points.append(sf.Vertex(sf.Vector2(0, 0), sf.Color(255, 255, 255)))
    
        def draw(self, target, states):
            target.draw(self.points, states)

    This is the way it is done in the shader.py example. If anyone has a good explaination as to why it works this way I would love to understand more. I am guessing it is due to the way cython interacts with the c++ code but it seems odd, and inconsistent as it doesnt follow the way the c++ api behaves as far as I can tell.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions