HaxeFlixel / flixel

Free, cross-platform 2D game engine powered by Haxe and OpenFL
https://haxeflixel.com/
MIT License
1.92k stars 427 forks source link

Improve performance of debug drawing #3168

Open Cheemsandfriends opened 4 weeks ago

Cheemsandfriends commented 4 weeks ago

FlxObjects use lineStyle as an outline. This is common practice in Flash, but in OpenFL, everything is set to rendering to CPU, causing big unoptimised images when you're using a hardware accelerated mode of the application.

Fixes #3164

Cheemsandfriends commented 4 weeks ago
1. I'd like some actual benchmarking tests done on various targets and reported here, just to make sure it's doing what you say, and that it doesn't tank on a specific target

I don't think it should affect negatively in any shape or form, its basically using the GPU (hardware accelerated mode) of the Graphics, so it should not affect at all. I'm not really that good benchmarking, but from what I could gather in Windows and Hashlink, it works far far better than the old method, the performance is better and you can zoom in without having to worry about the memory in-game increasing

2. We should make a FlxDebugDrawUtil or some `abstract DebugGraphic(openfl.display.Graphics)` that creates new helpful drawing tools for all the debug drawing classes to use, right now all it needs is

* drawRect with ways to customize x, y, width, height, thickness, color and alpha

* drawLine with ways to customize x1, y1, x2, y2, thickness, color and alpha

* and maybe a drawCircle or ellipse with all the expected args

Thats... Thats way complicated than it sounds lol, I mean, drawRect should be easy enough with just adding a rectangle and adding 4 more, but drawCircle is a shader, same with drawLine. I have some tests im trying to do on OpenFL as a revamp of the Graphics rendering class so it doesn't have to use the CPU based rendering, but it should be part of a major PR there imo

Cheemsandfriends commented 4 weeks ago

Something worth noting, using this method basically removes the issue with memory rising when you zoom in, so not only it is performance wise, but also memory wise it helps

Geokureli commented 4 weeks ago

I don't think it should affect negatively in any shape or form, its basically using the GPU (hardware accelerated mode) of the Graphics, so it should not affect at all. I'm not really that good benchmarking, but from what I could gather in Windows and Hashlink, it works far far better than the old method, the performance is better and you can zoom in without having to worry about the memory in-game increasing

Point is I need to make sure this actually has the benefit that you claim it does, and doesn't have unintended side effects on some specific target

Thats... Thats way complicated than it sounds lol, I mean, drawRect should be easy enough with just adding a rectangle and adding 4 more, but drawCircle is a shader, same with drawLine. I have some tests im trying to do on OpenFL as a revamp of the Graphics rendering class so it doesn't have to use the CPU based rendering, but it should be part of a major PR there imo

drawHollowRect, and drawFilledRect should suffice, for now. draw line would be great too, its important that we centralize this because we're gonna need to convert all the existing debug drawers over anyway

Cheemsandfriends commented 4 weeks ago

Point is I need to make sure this actually has the benefit that you claim it does, and doesn't have unintended side effects on some specific target

I mean, Ik you have mac, you could test the changes on that platform, I could verdict that on Windows, Hashlink-Windows and HTML5 seem to be working good to me

Geokureli commented 4 weeks ago

I meant share actual tests and the results, this is pretty standard stuff on perf PRs

Geokureli commented 3 weeks ago

in my test I saw better performance on chrome, but far, FAR worse performance on macos and hl.

without this change, got 10-30fps (fluctuating wildly), with this change I see consistent 5fps. Seeing the same-ish results in HL. about 30-40 fps before and 8fps after

@Cheemsandfriends, could you try this code with my test state on windows and see if it performs better? We may need to check for mac

New version (CPP):

Screenshot 2024-06-12 at 4 29 09 PM

Old version (CPP):

Screenshot 2024-06-12 at 4 22 06 PM
Cheemsandfriends commented 2 weeks ago

Yeah... apparently it's due to the rendering being 4x when rendering per line, in Browser it seems to be fixed cos it does some caching on their end I believe, but desktop does not, I'm trying to fix it by doing some kind of shader that directly does this

Geokureli commented 2 weeks ago

Yeah... apparently it's due to the rendering being 4x when rendering per line, in Browser it seems to be fixed cos it does some caching on their end I believe, but desktop does not, I'm trying to fix it by doing some kind of shader that directly does this

does this mean you're also seeing worse performance on windows as well?

Cheemsandfriends commented 2 weeks ago

Yeah Yeah, sorry for not saying it sooner, normally on fewer elements and on really big graphics the new version clears the old version. Even now I think the equivalent of the method as it is right now is if the old version got called 4 times the same (it takes one render per line). That's why the way to fix it would be to call a drawQuads and make a small shader that does the outlining Kinda weird cos this specific example makes the old version look better, but whenever you use really really big fewer objects, then you can see the great difference

Geokureli commented 2 weeks ago

it takes one render per line

for shits and giggles i tried using a single shape, and now i'm seeing about 20fps instead of 5

// outer
this.moveTo(x, y);
this.lineTo(x + width, y);
this.lineTo(x + width, y + height);
this.lineTo(x, y + height);
this.lineTo(x, y);
// inner
this.lineTo(x + thickness, y + thickness);
this.lineTo(x + thickness, y + height - thickness);
this.lineTo(x + width - thickness, y + height - thickness);
this.lineTo(x + width - thickness, y + thickness);
this.lineTo(x + thickness, y + thickness);

this.endFill();

this specific example makes the old version look better, but whenever you use really really big fewer objects, then you can see the great difference

TBH i don't see a lot of issues from fewer large objects, it still runs pretty good, i mostly have trouble with tilemaps drawing hundreds of tiny boxes

Cheemsandfriends commented 2 weeks ago

lineTo uses the non hardware accelerated version of OpenFL, so doing what you did basically is doing the old version with more commands

Geokureli commented 2 weeks ago

this specific example makes the old version look better, but whenever you use really really big fewer objects, then you can see the great difference

I tried a fewer larger objects and both the old and new ways had no performance issues

Cheemsandfriends commented 2 weeks ago

TBH i don't see a lot of issues from fewer large objects, it still runs pretty good, i mostly have trouble with tilemaps drawing hundreds of tiny boxes

if you mean on the non accelerated version, No it does not, from my experience at least. Im taking this as an example of zoomed, which acts the same way as having a big image. Besides the point that, it is not benefitial to keep it due to memory reasons.

OLD VERSION (Windows) imagen

NEW VERSION (Windows) imagen

It does not run good, REALLY big images like 2k or 1k would be impossible to debug when it is at its normal zoom at its normal scale, imagine bigger zooms

Cheemsandfriends commented 2 weeks ago

the zoom here is 3

Geokureli commented 2 weeks ago

i think we can avoid using the shader if we use drawQuads to draw all 4 rects Edit: nah, still no good