Giter VIP home page Giter VIP logo

sdsl's People

Contributors

ykafia avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

ykafia

sdsl's Issues

Storing shaders as assets

As the library is getting closer to generating SPIR-V code, one question starts to draw itself : What file format(s) should we use for storing shaders as assets for the Stride engine or other engine ?

Ideally, the library can be a plug and run compiler for shaders used for Stride (primarily) but also usable for other engines or frameworks.

Considerations

Currently, Stride stores shaders as text assets. It is loaded once and goes through the process of parsing, AST building, AST modifications and translation, and finally, those shaders are compiled as binaries and cached for future reuse.

For this new shader compiler a shader file goes through different formats, many similar to those previously used:

  • A text file : *.sdsl files can contain one or many shader classes
  • A parse tree generated by the Eto.Parse library and the SDSL grammar defined
  • An AST built from the parse tree
  • Many Quadruple arrays representing each method in three address code for optimization purposes.
  • A SDSL flavored SPIR-V (that i want to call sdspv), it's invalid SPIR-V but has enough information to be mixed together.
  • Compiled SPIR-V modules

Favored way of writing shaders

The most important format in the previous list is sdspv. It's a binary format that is very close to SPIR-V but has the advantage of being mixed the same way SDSL would be done on the AST level.

Given the nature of the composition system that SDSL and SDFX offers, there's a high value in writing shaders only at design time and composing them through the SDFX either at design time or at runtime.
During the asset compilation, the shader compiler should compile those shaders into sdspv binary files, known permutations will be compiled as SPIR-V modules directly.

  • SPIR-V modules can then be directly consumed by Vulkan, wgpu and OpenGL 4.6, removing the need to parse and translates shaders.
  • sdspv shaders can be mixed at runtime and translated using naga, tint or spirv-cross.
    • For Windows platforms, we can ship the dxc compiler using the official nuget package
    • For Android platforms using OpenGL ES, the driver will consume the GLSL translation directly
    • For console platforms, a lot of the work can be done by a private company, but here are some thoughts
      • The Nintendo Switch has a Vulkan driver which could potentially consume the SPIR-V generated
      • The Xbox console runs with DirectX, we might have very little changes compared to Windows Desktop platforms
      • The Playstation 4 and 5 uses a proprietary driver and shader language. There is not much we can do on our side to make it work on these platforms. There might be some work done by the folks at FNA or Monogame on this front.

Optimization passes

As user code is generally not optimized, there might be a need to implement optimization passes.

On the shader side

Optimization can happen on the AST generated, some passes like constant propagation, type checking and type coercion are better fit in this part of the compiler.

There is an api for creating an intermediate representation between SDSL and SPIR-V for control flow graph optimization, like finding dead code and such. This IR is created with arrays of quadruples/three address code that can be converted in a graph representation.

On the sdspv side

As this library creates an SDSL flavored SPIR-V to be able to mix and combine modules together, there might be considerations for optimizations on this level.

On the SPIR-V

SPIR-V is an binary intermediate representation of shader code. It is generally consumed by drivers and is most likely optimized for binaries generated for GPUs. We can't know to which extent it is optimized and how performance could be affected since there are so many different GPUs and drivers that work differently.

SPIR-V Tools offers spirv-opt, a tool to reduce binary size of SPIR-V modules, unfortunately not usable directly in C# unless we create bindings to the library. Fortunately, the lunarg sdk has a little pdf talking about various optimization passes possible on SPIR-V level.

Type coercion in SDSL

Since the SDSL language is being rewritten one question to ask is how do we handle type coercion and inference.

details to note about SPIR-V :

  • The built-in types of SPIR-V are the same as GLSL (bool, int, uint, float, double), in order to add (half, short, ushort, byte, sbyte, long, ulong) we should use SPIR-V extensions.
  • SPIR-V has some instruction for bit conversions, everything starting by OpConvert, which gives us the power to convert anything to anything conserving bit patterns.
  • Type coercion is going to be a little bit more difficult.

[RFC] Drop support for preprocessor macros in SDSL

SDSL uses preprocessor macros for platform specific code and other uses. It offers a similar user experience for both C# and SDSL.

Since macros can be defined through C# code and used by the preprocessor, this makes SDSL compilation impredictible.

Definitions

  • Shader snippet : A piece of SDSL code that cannot be assembled as a spirv module, but can be used in inheritance or composition context. The typical .sdsl file that user write
  • sdspv binary : A shader snippet that has been compiled into SDSL flavored spirv binary (invalid spirv) that is meant to be used in inheritance and composition scenarios.
  • spirv binary : A valid spirv module that can be fed to the gpu driver or spirv-cross. It can be composed of many sdspv binaries thanks to the binary mixin system.

The shader compiler can compile shader snippets into sdspv and cache them for future use. This has the advantage of removing the need to parse and compile a shader snippet many times.

In an ideal scenario, if we have a shader snippet composed of many other snippets that were already compiled as sdspv, only our snippet need to be compiled, then the assembler will mix all those sdspv binaries together.

Here's a graph of how the compiler should work

flowchart TD
    subgraph Spirv Compilation
        A[Compile user shader A] --> B{Is shader \nalready \ncompiled ?}
        B --> |yes| Spirv[Return spirv binaries]
        B --> |no| C[Fetch shader code\n from asset system]
        C --> ParseShader[Parse Shader]
        ParseShader --> D{Does shader A \nhave compositions\nor inherited classes\nnot compiled \nto sdspv?}
        D --> |no| E[Compile and mix sdspv A with \nall inherited and composed sdspv]
        E --> F[Assemble shader A \nwith other snippet\n from the inherited and \ncomposed spirv shaders]
        D --> |yes| G[Fetch and compile \ninherited/composed shader \nsnippets to sdspv]
        G --> E
        F --> Spirv
    end
    subgraph Parsing
        Load[Load shader text \nfrom asset system] --> CommentParsing[Parse shader comments]
        CommentParsing --> RemovalQ{Does shader\nhave comments ?}
        RemovalQ --> |yes| Removal[build a list of ReadOnlyMemory \n of char for non-comment \ncode and use StringBuilder to \nconcatenate it into a new string]
        RemovalQ --> |no| AllowedMacros{Are\nmacros\nallowed?}
        AllowedMacros --> |yes| MacroRetrieve
        AllowedMacros --> |no| StartCompilation
        Removal --> AllowedMacros
        subgraph MacroParsing
            MacroRetrieve[Retrieve macro values] --> MacroObject[Replace macro objects by\ntheir defined values]
            MacroObject --> MacroFunc[Replace macro function \nwith their expansions]
            MacroFunc --> BuildString
            BuildString[Build a string \nusing String builder] --> StartCompilation
        end
    end

The issue with macros

The fact that branching through shader macros can become very complex and that a user can change these shader macro values at runtime make caching shader complicated. It also breaks the type system since a single shader can be reused with different definition in different context.

Ideally a shader type would be defined once, with a specific definition across all shaders. Everything that the preprocessor can do can be done through the inheritance and composition system. Since we would have one definition per shader type, we can cache sdspv with just the identifier of the shader type. We cut short of all re-parsing of the same type, saving some precious CPU at the cost of a different UX for users.

Impacts

Both Stride and VL.Stride use macros extensively, this will need some work to rewrite things.

Control flow graph generation

Generate a control flow graph that can be usable for SPIR-V generation.

One idea is to probably replace all control flow nodes into GOTO and LABEL in the CFG.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.