-
-
Notifications
You must be signed in to change notification settings - Fork 262
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
low framerate when drawing graphical tiles #152
Comments
Hi @jonbro, thanks for the report. It would be very beneficial to find out what part of the whole task is being the framerate bottleneck: is it the actual canvas drawing (i.e. |
yep, of course! I did a few tests on my way to this conclusion, though unfortunately I was having difficulty using performance.now() to isolate just the drawing functions. It seemed like the best test that I could get was via measuring the time from the beginning of the loop to the beginning of the next loop. My suspicion is that the browser is deferring the canvas draw calls until after the javascript thread is done, so you can't actually measure how much they cost :( At first I tried hacking up rot js, and seeing if I could get the core loop fast there. It seems like rotjs isn't adding much overhead to the drawcalls. So I pulled out the core loop as best I could, and started hacking it up. all these examples are dumping out frametimes, avg'd over the the last 20 frames to the console. https://grateful-kilometer.glitch.me/rotNoColor.html https://grateful-kilometer.glitch.me/onlyDrawImageCall.html https://grateful-kilometer.glitch.me/rotjsColorizeApproach.html https://grateful-kilometer.glitch.me/fast_draw.html One thing to look at is that once you do enough ROT.display.draw calls to get an actual number out of the loop (i.e. something higher than a reasonable vsync division), then the time scales linearly with the number of draw calls. on my computer, it seems like each call is taking about 0.2ms I don't have it any more, but I did another test to see if batching each type of call would help, but unfortunately it didn't... I did:
My suspicion is that canvas operations are just slow. it isn't just drawImage, but also fillRect seems slow as well - minimizing the number of calls to it seems critical for getting a fast drawing loop. |
going back to the early tickets on this topic #22 and #50 it seems like the pixel based approach that I am suggesting was proposed but rejected in favor of the current approach. I wonder if under certain circumstances, the globalCompositeOperation is actually faster. Possibly with fewer, but more high resolution tiles. |
Wow, thanks for the detailed post! I will try to look into this, even though it looks like a more complex issue and my time is pretty limited these days.
I am pretty certain that globalCompositeOperation is faster than individual per-pixel processing, but only when you compare comparable: your code is way faster because you are only drawing the canvas once per frame (the I see two ways of handling the issue now:
|
Yeah, I recognize that this is a big issue :) and its a real pain to get it right too - I ended up reimplementing the parts of Rot.Display that I needed for my particular project - it is doing a number of hacks to get speed even higher than my demos that I posted above. This is passing every tile via a normal Display.draw(x,y,char) call. https://glitch.com/edit/#!/asc-paint?path=src/Display.js:7:20 The feature that I cut here was the multilayer tiles, and there is also some cleverness happening so I don't need to support the tiles alpha channels. Both of those things feel like they could be addable with a switch that regains performance if they aren't necessary. The WebGL is something I have considered for sure, and I think that is probably the most reasonable option for someone like me that wants the most speed. |
This would make sense the most to me as well. I would, on the other hand, prefer to not have as many performance-related switches (multilayer, alpha) as possible, to keep the stuff readable and minimize complexity. I believe WebGL provides enough performance to comfortably fit within the 60 FPS cap of the requestAnimationFrame loop. |
Hi @jonbro, please feel free to check out my work-in-progress demo implementation of the WebGL-based tile rendering mechanism: https://beta.observablehq.com/@ondras/new-rot-js-display-backend-for-image-tiles I would say that it performs just fine. The demo is slowed down by CSS-based canvas resizing, because I am using huge (64x64) tiles on a large (80x25) display. It uses colorization (tinting) and currently only draws one image per tile, but I think it might be sufficient as a proof of concept. A more performant version would probably batch individual draw calls, passing multiple tile definitions (coordinates, colors, ...) as WebGL attributes. I will try to stick with the current implementation, though. |
Impressive! I was seeing a teeny bit of slowdown on my phone, but like you say, batching will make that issue go away completely. This is great. |
Hello Ondřej, |
Hi @Gerhard-Wonner, I got distracted and forgot about this feature. Sorry. Let me put it back to my priority list to see what can be done. |
Good morning @ondras, you are awesome! 👍 |
I pushed some initial preparations to the tile-gl branch. The implementation is taking much longer than I thought, though, because I constantly run into corner issues regarding blending, opacity and redrawing. WebGL is not something I am 100% versed in :-( |
I just merged the tile-gl branch to master. This means that you are invited to test the webgl functionality! Please use the This new WebGL renderer is also mentioned in the interactive manual, along with a code sample. |
Hello @ondras, thanks a lot for the quick help and the enhancment of the performance. Please excuse my late response. I had troubles to get the tiles displayed in my local version of the game and got the error message "Cross origin requests are only supported for HTTP". But after I uploaded everything to the server it worked and I can see that the performance is better now. :-) |
Hi @Gerhard-Wonner, I very briefly linked the image loading issue at the very bottom of the manual page. TL;DR: use a (local) web server to serve images; develop either using Longer read: https://hacks.mozilla.org/2011/11/using-cors-to-load-webgl-textures-from-cross-domain-images/ |
@ondras Thank you for the explanation. I will try it soon. Sorry if I ask silly questions, but I just used the 7DRL-challenge as an opportunity to learn JavaScript. So this whole web developing thing is quite new to me. |
@ondras I found a solution for me that works well: I just open my local version using the "Live Server"-extension of Visual Studio Code and all the tiles are displayed correctly. :-) |
Hi @Gerhard-Wonner,
no problem, feel free to ask more! You will soon find that although the whole frontend tech stack looks simple, it contains many convoluted difficulties. But this particular complexity (cross-domain image requests) is actually very reasonable.
Right, that is exactly what I meant by |
Hello @ondras, there seems to be a problem with some browsers when opening http://ondras.github.io/rot.js/manual/#tiles. |
Hi @Gerhard-Wonner, that would correspond to the WebGL2 support status across browsers: https://caniuse.com/#feat=webgl2 Someone more skilled with WebGL might be able to re-factor the code using an older WebGL implementation (version 1), though. |
Hello @ondras, |
I don't think you ever got a confirmation, but yes @Gerhard-Wonner , |
when attempting to update a full console worth of graphical tiles (80x40 of 8x8 tiles) using colorized mode, I am getting really bad framerates, somewhere on the order of 700ms per frame. You can see a simple example here:
https://grateful-kilometer.glitch.me/
I built a version that uses more bit twiddling to get the images onto the canvas, and for my simple case (a single layer of tiles with background and foreground colors:
https://grateful-kilometer.glitch.me/imgdata_drawTiles.html
This is running at 60fps, and checking the core loop, it seems to take around 3-5ms to do all the operations. There would be a bit of work to extend this test to support all the behaviors that the current colorized graphical tiles do, but I just wanted to open up this issue.
My use case for this is doing a full screen ansi art editor with swappable text sets, but things like brogue with graphical tiles would also suffer from this low frame rate.
The text was updated successfully, but these errors were encountered: