hajimehoshi / ebiten

Ebitengine - A dead simple 2D game engine for Go
https://ebitengine.org
Apache License 2.0
10.78k stars 651 forks source link

Shaders using an image's origin or size tend not to be batched #2802

Open Zyko0 opened 11 months ago

Zyko0 commented 11 months ago

Operating System

What feature would you like to be added?

Following a discussion on discord

The graphic commands DrawTrianglesShader and DrawRectShader with different source images and/or on different destination images cannot be batched if they use origin or size information about the images, even if the source and destination textures are the same for several consecutive calls, e.g:

func Fragment(dst vec4, src vec2, color vec4) vec4 {
  origin, size := imageSrc1Origin(), imageSrc1Size()
  dstorigin, dstsize := imageDstOrigin(), imageDstSize()
  // do whatever calculations because you need this (idk why but can happen)
  return imageSrc1At(newSrc)
}

Because the information is stored in two uniforms, that need to be re-uploaded with the new values (https://github.com/hajimehoshi/ebiten/blob/v2.7.0-alpha.2/internal/graphics/shader.go#L77-L81)

Suggestion (but I might be missing some details):

I'm not sure it would work, since it's only theoretical from my point of view, so I might be missing crucial details. And even though there seems to exist counterparts for other graphic drivers, the above idea is opengl-specific in terms of wording at least.

Why is this needed?

Custom shaders that make use of origin or size information from a source or a destination texture, don't make use of atlasing at all, which is unfortunate. There's no way to batch them (e.g: 500 triangles with the above shader would be catastophic).

The usecase is not so uncommon, one could write their own DrawImage with their custom shader making use of origin, size information for a particular effect on all their images, and would be in this situation without control over batching.

An entrypoint or a first proof of concept could be (from the user side) to create its own image as an atlas texture, since .SubImage would contain the origin information, and provide it manually for source and destination in vertex attributes once there's support for more (see https://github.com/hajimehoshi/ebiten/issues/2640). It would need 8 attributes to store srcOriginX, srcOriginY, srcWidth, srcHeight, dstOriginX, dstOriginY, dstWidth, dstHeight, in order to "emulate" the 2 id attributes (for src and dst) that would represent the indices of respective UBOs, containing origin,size information.

Zyko0 commented 10 months ago

Note: I think this is called "instancing"

hajimehoshi commented 1 day ago

I've not come up with a good solution. Let me remove the milestone.