Skip to content

Remove imageMain and printMain in favor of render and print imports #167

@Devon7925

Description

@Devon7925

Problem

The current system for main entrypoints has a number of issues:

  • imageMain and printMain must be in user.slang (not a problem for the website, but is for the extension)
  • They obscure functionality from the user
  • They require extra code to handle
  • imageMain doesn't allow writing to arbitrary locations, which makes things like only drawing to part of the screen harder(ex. drawing particles)
  • They can't be used at the same time, meaning you can't use print statements to debug image shaders
  • They require unnecessary bind slots. The print buffer is always bound in image shaders, and the outputTexture is always bound in print shaders, even though they are unused. This can eat up the webgpu bind limits, thereby preventing the user from doing some complex shaders.

Proposal

Introduce printing.slang and render.slang. These would be imported by the user when necessary and would bind their own requirements.

Printing functionality (g_printBufferIndex, g_printedBuffer, IPrintF, etc.) currently in playground.slang would move to printing.slang.
Render functionality (mostly outputTexture) would move to render.slang. The special functionality of imageMain (getting the render size, discarding threads outside it, and writing to the output) could be provided by a function drawPixel that takes a lambda.

Examples

Print shader

import playground;
import printing;

[shader("compute")]
[numthreads(1, 1, 1)]
[playground::CALL(1, 1, 1)]
[playground::CALL::ONCE]
void printMain()
{
    print("%d, %3.2d, 0x%x, %8.3f, %s, %e\n", 2, 3456, 2134, 40.1234, "hello world", 12.547);
}

Image shader

import playground;
import render;

[shader("compute")]
[numthreads(16, 16, 1)]
[playground::CALL::SIZE_OF("outputTexture")]
void imageMain(uint2 dispatchThreadID : SV_DispatchThreadID)
{
    drawPixel(dispatchThreadID, (uint2 screenSize) => {
        return float4(0.3, 0.7, 0.55, 1.0);
    });
}

Downsides

This would require specifying more information in all current example shaders. For print shaders users have to include:

[shader("compute")]
[numthreads(1, 1, 1)]
[playground::CALL(1, 1, 1)]
[playground::CALL::ONCE]

Which is boilerplate. However, this also arguably makes the playground easier to learn, and makes it more clear what print shaders are actually doing.

Translated imageMain shaders would need to reference outputTexture in their boilerplate, and the lack of clear definition of outputTexture in user visible code could cause confusion. In addition, drawPixel would add an extra indentation level.

UI would also have to be altered to support printing and rendering at the same time.

Alternatives

Add RENDER_RESULT attribute, do not use render.slang

We could create an attribute that allows setting any texture as the render result. In this case, users would have to implement the special functionality of imageMain themselves, which would be extra boilerplate but could be more comprehensible. We could also do this in addition to offering render.slang and use it to implement render.slang without special logic. It would also potentially require extra logic for rendering non-screen size output textures.

Add PRINT_RESULT attribute, do not use printing.slang

We could have the user include current printing logic in their shaders. This would add a lot of boilerplate to every print shader, which would make how printing works more understandable. It would crowd out what shaders are actually trying to do/show with logic that can be abstracted away.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions