Skip to content

coalesce draw calls with same texture/clip#766

Open
david-vanderson wants to merge 3 commits into
mainfrom
batching
Open

coalesce draw calls with same texture/clip#766
david-vanderson wants to merge 3 commits into
mainfrom
batching

Conversation

@david-vanderson
Copy link
Copy Markdown
Owner

Fixes #637

While running the demo, this generally halves the number of backend.drawClippedTriangles calls.

Need some feedback about whether this actually addresses the performance issues.

@david-vanderson
Copy link
Copy Markdown
Owner Author

@foxnne When you get a chance can you see if this helps your performance issues with Pixi and Graphl?

@david-vanderson
Copy link
Copy Markdown
Owner Author

I should have said - I added a checkbox "Log Stats" to the Debug Window that outputs the number of backend draw calls each frame.

Unsure how useful this specifically is. I think it will be useful to keep track of various stats and expose them through the debug window, so this is an initial step in that direction.

@foxnne
Copy link
Copy Markdown
Collaborator

foxnne commented Mar 7, 2026

It seemed to improve the performance quite a bit, but I'm still getting sub 60 in some conditions. I think that's my fault though, as the little bubbles I draw for sprites are still all using individual draw calls, and a lot of them each. So I need to rewrite my code to combine as many things as I can. I didn't have a chance to test Graphl yet, but I think I'd see improvements but we will still pursue batching on our own?

@david-vanderson
Copy link
Copy Markdown
Owner Author

david-vanderson commented Mar 7, 2026

It seemed to improve the performance quite a bit, but I'm still getting sub 60 in some conditions. I think that's my fault though, as the little bubbles I draw for sprites are still all using individual draw calls, and a lot of them each. So I need to rewrite my code to combine as many things as I can. I didn't have a chance to test Graphl yet, but I think I'd see improvements but we will still pursue batching on our own?

Sorry! Argh! I totally screwed this up the first time. I've added a commit that actually turns it on (I had turned it off during testing and accidentally committed that). Also now there is a toggle for it (for the time being):

Screenshot 2026-03-06 at 8 29 26 PM

Ok, now does it make any difference? (with "Log Stats" on you should see a log for each frame in the terminal with the total draw calls actually sent to the backend)

Theoretically if this works, then trying to batch yourself shouldn't help at all.

@foxnne
Copy link
Copy Markdown
Collaborator

foxnne commented Mar 7, 2026

This is interesting, I'm not sure if it's a bug or just me misunderstanding, but it seems like the logging for the draw calls doesn't really change when I enable or disable batching. Sometimes I have 1500 draw calls and sometimes 200 in the same scene, without touching the batching button. Is the draw calls an average?

At any case, it doesn't seem to remedy my Pixi issue with the cell bubbles, but I need to test Graphl.

@david-vanderson
Copy link
Copy Markdown
Owner Author

Is the draw calls an average?

No. Hmm this is suspicious, need to figure this out. I will try with Pixi.

When you run the demo do you see the draw count being affected by batching?

@foxnne
Copy link
Copy Markdown
Collaborator

foxnne commented Mar 7, 2026

I do see it working now, I think I needed to clear my caches and that what I was observing before was some cache issues.

It still seems that my code is producing a lot of draw calls, I believe its the explicit calls to fillConvex and individual stroke calls? but I havent had time to look into what your code is doing, I assumed it probably corrected performance of all buttons, but maybe not explicit fillConvex calls? It seems it does typically about half the amount of draw calls, but I still get sometimes over 1500 drawcalls when a semi-large grid is selected.

@foxnne
Copy link
Copy Markdown
Collaborator

foxnne commented Mar 7, 2026

I also seem to be getting the below error with pixi only on this branch, but I cant observe any issues with whats being drawn. Is that perhaps that I have animations that could start at 0?

info(AccessKit): initialized successfully
warning(dvui): iconTexture Tinyvg error error.InvalidWidth rendering icon DropIcon at height 1

error(dvui): render.zig:446:27: renderIcon got tvgError: Could not create texture from tvg file "DropIcon"
Error trace:
C:\Users\foxnn\AppData\Local\zig\p\z2d-0.8.0-j5P_HqfdFAAhoTDoRcm7Iix_8aszukCODbGuw2JxID-Z\src\surface.zig:349:28: 0x7ff7e6184a2c in init (Pixi_zcu.obj)
            if (width < 1) return error.InvalidWidth;
                           ^
C:\Users\foxnn\AppData\Local\zig\p\z2d-0.8.0-j5P_HqfdFAAhoTDoRcm7Iix_8aszukCODbGuw2JxID-Z\src\surface.zig:142:25: 0x7ff7e60b9904 in initPixel (Pixi_zcu.obj)
                return (try ImageSurface(@TypeOf(px)).init(
                        ^
C:\Users\foxnn\AppData\Local\zig\p\svg2tvg-0.0.0-HpMZuWZ3BgApRrFbd9CxtabLoXEA5odBFUDFrDqno8Ih\src\rendering.zig:71:15: 0x7ff7e60b74f6 in renderStream__anon_124629 (Pixi_zcu.obj)
    var sfc = try z2d.Surface.initPixel(.{ .rgba = .fromClamped(1, 0, 1, 0) }, gpa, @intCast(new_width), @intCast(new_height));
              ^
C:\Users\foxnn\dev\proj\dvui-dev\src\Color.zig:471:13: 0x7ff7e60bdee7 in fromTvgFile (Pixi_zcu.obj)
            return dvui.TvgError.tvgError;
            ^
C:\Users\foxnn\dev\proj\dvui-dev\src\Texture.zig:348:109: 0x7ff7e5f669a5 in fromTvgFile (Pixi_zcu.obj)
    const img = Color.PMAImage.fromTvgFile(name, cw.lifo(), cw.arena(), tvg_bytes, height, icon_opts) catch return TvgError.tvgError;
                                                                                                            ^

Stack trace:
C:\Users\foxnn\dev\proj\dvui-dev\src\render.zig:446:26: 0x7ff7e5e0dc0c in renderIcon (Pixi_zcu.obj)
            dvui.logError(@src(), err, "Could not create texture from tvg file \"{s}\"", .{name});
                         ^
C:\Users\foxnn\dev\proj\dvui-dev\src\widgets\IconWidget.zig:67:20: 0x7ff7e5cdab87 in draw (Pixi_zcu.obj)
    dvui.renderIcon(
                   ^
C:\Users\foxnn\dev\proj\dvui-dev\src\dvui.zig:3614:12: 0x7ff7e5bb1f0e in icon (Pixi_zcu.obj)
    iw.draw();
           ^
C:\Users\foxnn\dev\proj\pixi\src\editor\explorer\files.zig:642:38: 0x7ff7e5bd2117 in search (Pixi_zcu.obj)
                        _ = dvui.icon(
                                     ^
C:\Users\foxnn\dev\proj\pixi\src\editor\explorer\files.zig:723:17: 0x7ff7e5bde5b5 in recurseFiles (Pixi_zcu.obj)
    try recursor(root_directory, outer_tree, unique_id, &id_extra, &color_i, outer_filter_text, null);
                ^
C:\Users\foxnn\dev\proj\pixi\src\editor\explorer\files.zig:174:25: 0x7ff7e5bdfbe8 in drawFiles (Pixi_zcu.obj)
        try recurseFiles(path, tree, unique_id, filter_text);
                        ^
C:\Users\foxnn\dev\proj\pixi\src\editor\explorer\files.zig:48:22: 0x7ff7e5be167a in draw (Pixi_zcu.obj)
        try drawFiles(path, tree);
                     ^
C:\Users\foxnn\dev\proj\pixi\src\editor\explorer\Explorer.zig:111:33: 0x7ff7e5c2bfea in draw (Pixi_zcu.obj)
        .files => try files.draw(),
                                ^
C:\Users\foxnn\dev\proj\pixi\src\editor\Editor.zig:430:56: 0x7ff7e5c964a7 in tick (Pixi_zcu.obj)
                const result = try editor.explorer.draw();
                                                       ^
C:\Users\foxnn\dev\proj\pixi\src\App.zig:82:32: 0x7ff7e5b85696 in AppFrame (Pixi_zcu.obj)
    return try pixi.editor.tick();
                               ^
C:\Users\foxnn\dev\proj\dvui-dev\src\backends\sdl.zig:1775:26: 0x7ff7e5b785b7 in appIterate (Pixi_zcu.obj)
    var res = app.frameFn() catch |err| {
                         ^
C:\Users\foxnn\AppData\Local\zig\p\sdl-0.4.0+3.4.0-SDL--rq2owEZsySGuHCuVJ9naEvH3i3e_pyUIjziBtJ-\src\main\SDL_main_callbacks.c:130:0: 0x7ff7e7735026 in SDL_IterateMainCallbacks (SDL3.lib)
        rc = SDL_main_iteration_callback(SDL_main_appstate);

david-vanderson added a commit that referenced this pull request May 12, 2026
seen in #766

We have protections against trying to rasterize an icon with zero height.  But
if an icon has a ratio of like 5x10 (so tall), then if we ask to render it at
1px tall, internally we see a width if 0.5.

We were truncating that to 0 and then failing the rasterization.

Now we ensure the width is at least 1 for rasterization.
@david-vanderson
Copy link
Copy Markdown
Owner Author

I also seem to be getting the below error with pixi only on this branch, but I cant observe any issues with whats being drawn. Is that perhaps that I have animations that could start at 0?

Sorry I dropped this on the floor. We had code that would fail if a tall icon was rendered at a small height (like 1px tall, so the width was < 1px).

I've pushed a fix for this to main, but I'm still unsure why you only saw it on this branch.

@david-vanderson
Copy link
Copy Markdown
Owner Author

@foxnne Can you help me get back up to speed with this? I'm unsure where we stand:

  • Do you still suspect that this (batching draw calls) is needed to address performance issues you are seeing?
  • If so, do we have a way to reproduce the performance problem (in pixi or dvui examples)?
  • Anything else since last we thought about this?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

batching draw calls

2 participants