pycraft icon indicating copy to clipboard operation
pycraft copied to clipboard

Improve performance

Open traverseda opened this issue 9 years ago • 10 comments

traverseda avatar Apr 09 '16 12:04 traverseda

I doubt the problem is opengl. So the first step should be profiling.

traverseda avatar Apr 09 '16 12:04 traverseda

<@traverseda> I doubt the speed problems are openGL. We're not rending a complex scene. Reducing number of objects probably isn't going to help
<@traverseda> It might be pyglet related, in which case, fuck.
<@Nitori> hm... the update method takes like 0.0003 seconds
<@Nitori> hmhm, pyglet calls the window.update method repeatedly, right? the wohle method and all the python stuff takes like 0.0003 seconds, but from update call to update call (meaning the part that pyglet does) it takes around 0.1-0.2 seconds
<@Nitori> but I don't know anything of that stuff
<@traverseda> I'm presuming it's stuff like checking what blocks are visable, or re-calculating the current sectors
<@traverseda> Or the collision detection
<@Nitori> isn't that done in main.py?
<@Nitori> that's all part of the update and _update method afaik
<@Nitori> which takes less than a millisecond
<@traverseda> Hmm, weird
<@Nitori> maybe research into other libs like PySDL2 might be good?
<@Nitori> or maybe just read the pyglet docs for now
<@traverseda> Nitori, yeah, I was thinking about things along those lines. Also the possibility of having this project essentially just be a "server" and to write a 3D client in golang. For now even the slow stuff lets people immediatly see the results of their effors, though.
<@Nitori> hm yea
<@traverseda> I set the tickrate to 600 (on my shitty arm chromebook) and performance seems a lot better. I think there's something wrong with pyglets clock.

traverseda avatar Apr 09 '16 13:04 traverseda

In hindsight, I'm not certain about that tickrate thing. It goes up a bit, but I'm nearing max CPU anyway.

traverseda avatar Apr 09 '16 13:04 traverseda

On my own pyglet-related projects, I had to patch out part of the idle method to keep it from calling update repeatedly, and that helped performance quite a bit. Here's what I did (I found this code elsewhere:)

import pyglet
# Patch for pyglet idle loop
def patch_idle_loop():
    def idle(self):
        self.clock.call_scheduled_functions(self.clock.update_time())
        return self.clock.get_sleep_time(True)
    if pyglet.app.EventLoop.idle != idle:
        pyglet.app.EventLoop.idle = idle

# Window patch for OpenGL
def patch_window_for_opengl_core():
    def draw_mouse_cursor(self):
        pass
    pyglet.window.BaseWindow.draw_mouse_cursor = draw_mouse_cursor

patch_idle_loop()
patch_window_for_opengl_core()

Also don't forget that if you don't run any Pyglet application with the -O or -OO switches passed to the Python interpreter, it starts in debug mode by default, another performance killer.

syegulalp avatar Apr 09 '16 14:04 syegulalp

Also note that if you use this, you have to write some event-loop functions yourself. Example:

import pyglet

#assume the above patch goes here...

import random

w = pyglet.window.Window()
b = pyglet.graphics.Batch()

l = pyglet.text.Label("abc", font_size=w.height,
                          batch=b,
                          x=w.width/2, y=w.height/2,
                          anchor_x="center", anchor_y="center")

def update(n):
    w.dispatch_events()
    w.clear()
    b.draw()
    w.flip()

pyglet.clock.schedule_interval(update,1/60)
pyglet.app.run()

syegulalp avatar Apr 09 '16 14:04 syegulalp

Might make sense to use python3.5's async loop. Now sure how that would interact with pyglet's event parsing stuff.

http://www.curiousefficiency.org/posts/2015/07/asyncio-background-calls.html

traverseda avatar Apr 19 '16 19:04 traverseda

I've written pyglet/OpenGL projects before, using Pyglet's own event loop, that drew hundreds of separate OpenGL meshes, with independent positions and orientations for each, at 60fps or better on very old/modest hardware. I don't think your problem is fundamentally due to Pyglet's event loop.

The '-O' or '-OO' flags (mentioned in a prevoious comment) are CRITICAL for good performance.

tartley avatar Apr 21 '16 16:04 tartley

Wild speculation: If you are re-creating the vertices and sending them over to OpenGL every frame, that is very slow. Creating the contiguous arrays of vertex data in memory is slow, then sending that data over to the GPU is slow. You need to create your mesh(es) once, then send them over to OpenGL on startup (using VAO/VBOs) and then each frame, request that OpenGL render each mesh, by passing in integer handles to identify the mesh (rather than re-sending the mesh vertex data.)

If meshes get modified while running (which presumably they do, when blocks are added or removed) then perhaps instead of regenerating a mesh for the whole world every time a block is added or removed, you need to split the world into a number of meshes (e.g. maybe one for every 16x16 column of the world) and regen just the modified mesh.

tartley avatar Apr 21 '16 16:04 tartley

@tartley In my case I think I was experiencing problems w/Pyglet triggered into doing a full repaint outside of the event loop, and I didn't need repaints more than every 1/60th of a second. Hence my loop patch. But yes, -O or -OO is vital, and many people don't know it.

BTW, am following the Gloopy project, love the idea!

syegulalp avatar Apr 21 '16 16:04 syegulalp

Fair enough, I shall staunch my uninformed speculations. Love what you folks are doing here, too!

tartley avatar Apr 21 '16 16:04 tartley