magic-lang / ooc-kean

ooc port of parts of Kean.
MIT License
7 stars 30 forks source link

OpenGL safety #1427

Open davidpiuva opened 8 years ago

davidpiuva commented 8 years ago

A problem with OpenGL is the high level of abstraction without safety below it. Giving textures by name is like having a sparse table with an index for each possible typo of the name. A way to access textures as registers without names would improve safety against typos and uninitialized pixels. Some GLSL compilers might complain about hard coded registers. (http://stackoverflow.com/questions/14022274/hardcoding-glsl-texture-sampler2d)

Safety features

(1) Prevent any input texture from also being the output texture. This may crash on some graphics cards. (2) Unassigned textures will show a default texture. This require strict naming convention or direct register access setting unused slots to default instead of null when unbinding a texture. (3) Prevent uniforms from leaking to another draw call. (4) Keep track of which textures has been written to and which were just created. This will prevent uninitialized and recycled images from getting in to a shader. Forgetting to give a texture should trigger check (2).

Alternative solutions

Give input arguments in the draw call as varargs (+) Easy to use. (+) Easy to adapt to since it can overlap existing arguments given to the shader's dictionary. (-) The list of input arguments might have to be freed manually since garbage collection is disabled. (--) This removes the ability to reuse input arguments.

state draw("scale", 0.3f, "time", x, ...)

Give a separate dictionary (+) Can reuse arguments. (--) More complicated than giving to the shader.

args := Dictionary new("scale", 0.3f, "time", x, ...)
state draw(args)
args free()

Both separate dictionary and varargs (+) Can reuse arguments. (+) Easy to use since you don't have to allocate an extra dictionary. (-) Complex to implement with 3 layers of arguments. (varargs, extra dictionary, shader dictionary) (-) Uploading unused argument is a performance bottleneck on desktop computers with dedicated graphics.

common := Dictionary new("scale", 0.3f, ...)
state draw(common, "time", x, ...)
common free()

Fixed size array of up to 16 input textures (Can be combined with the above) (++) No garbage collection. (+) Can reuse input arguments. (+) Much safer checks when rendering. No need to check if the name is spelled right. (+) Possible tiny performance benefit from using hard coded register indices. (-) Upper limit on texture count (But shader model 2.0 only has 16 sampler registers which is enough). (-) All input textures must be named texture0 to texure15 but giving by name may still exist without safety until implemented.

// Named to make it easy to remember the names in the shader.
DrawState new(target) setTexture0(firstImage) setTexture1(secondImage)...

Just checking what we can when textures are given to OpenGL (Part of https://github.com/magic-lang/ooc-kean/pull/1429) (++) Lightweight implementation. (+) No difference in calling convention. (+) Can still check that input is not output for compatibility. (--) Will only catch 30% of the mistakes.

davidpiuva commented 8 years ago

@emilwestergren @sebastianbaginski @fredrikbryntesson any suggestions?

emilwestergren commented 8 years ago

I don't think this should be the priority right now, but we can keep the issue and discuss it later.