summaryrefslogtreecommitdiff
path: root/source/slang/slang-emit-glsl.cpp
AgeCommit message (Collapse)Author
2019-10-22User IR-based layout for all IR steps (#1084)Tim Foley
This change builds on previous work that moves toward a more IR-based representation of layout. Those steps added some instructions for representing layout in the IR (initially just proxies for the AST layout objects), and an explicit lowering pass that could build a target-specific IR module that binds parameters and entry points to layout information. This change aims to complete that work, in the sense that the IR representation of layout is now self-contained and does not rely on having pointers back into the AST-level representation. Achieving this requires two main kinds of work: 1. Update any code that used layout information derived from the IR (most notably all the `slang-emit-*` code) to use the new IR representation and its accessors. 2. Update any code that *constructs* layouts using information derived from the IR to construct IR layouts instead. The biggest new infrastructure feature in this change is support for "attributes" in the IR (I'd welcome feedback on the naming). An attribute can either be thought of like key/value arguments that can be added to certain instructions to encode optional data, or alternatively like a decoration that is referenced as an operand instead of a child. The value of attributes over decorations is that they can affect the hash/identity of an instruction (which decorations can't), while the advantage of decorations is that they can easily be added/removed over the lifetime of an instruction (which attributes can't). We mostly use them here to represent operands that are logically optional. Once attributes are available, the encoding of layout information into the IR is mostly straightforward: * An `IRVarLayout` has a fixed operand for its type layout, and can accept a few different attributes * Zero or more `IRVarOffsetAttr`s that specify the offset of the variable for a given resource kind. These are equivalent to the `VarLayout::ResourceInfo`s at the AST level. * An optional `IRUserSemanticAttr` and `IRSystemValueSemanticAttr` to represent the (possibly derived) semantic of a varying input/output parameter. * An option `IRStageAttr` to represent the known stage for a parameter. * An `IREntryPointLayout` has a var layout for the entry point parameters (logically grouped in to a struct) and another var layout for the result parameter. * There is a small type hierarchy rooted at `IRTypeLayout` where each subtype can add fixed operands and attributes that are expected to appear. It also supports `IRTypeSizeAttr`s that serve a similar role to the `IRVarOffsetAttr`s. * Structure types maintain the mapping of fields to their var layouts using `IRStructFieldLayoutAttr`s. With the encoding in place, most of the changes in category (1) (code that just *uses* rather than *creates* layouts) was straightforward. The biggest different beyond name changes was that everything needs to be fetched using accessors instead of bare fields. It would have been possible to stage this commit and make the diffs smaller by first introducing mandatory acessors to the AST layout types. The changes in category (2) were more involved. There were a lot of places in the existing code where a `TypeLayout` or `VarLayout` would be created, and then initialized piecemeal over several lines of code (and sometimes even across functions). Because of the way that layouts need to support many optional properties, it did not seem practical to just have monolithic factory functions that took all the options as arguments, so I instead opted for a builder approach. The builders for `IRVarLayout` and `IREntryPointLayout` are both straightforward, and honestly there is no realy need for a builder for entry point layouts right now, but I was trying to future-proof in case we decidd to add some optional attributes to them. The builders for type layouts are more involved because of the inheritance hierarchy. Each concrete sub-type of type layout needs to define its own builder type that customizes the opcode, operands, and attributes of the final instruction. The refactoring that had to go into this change was a nice excuse to clean up a few ugly warts in the AST layout code that were largely there to support IR use cases. While this change adds a lot of new infrastructure code to the IR, most of the client code has stayed the same or gotten simpler. One annoying wart that remains with this change is the notion of an "offset element type layout" for parameter group types. That idea was added to deal with a legacy feature in the reflection API that we realized was a mistake, but unfortunately having that "offset" layout handy made writing a few other pieces of code simpler so that there are use cases of the feature even in the IR. Removing those uses is do-able, but requires careful refactoring so it is best left to a follow-on change. Another thing that could be considered for a follow-on change is how much information should be specified when constructing a `Builder` for an IR type layout, and how much should be allowed to be specified statefully/piecemeal. It would be nice to force all the required operands to be specified up front, but `IRParameterGroupTypeLayout::Builder` doesn't currently work that way because so much of the client code that needs it involved a lot of stateful setting and would need to be refactored heavily to provide the necessary information up front.
2019-10-08Fixed from Review of Entry Point decoration #1068 (#1072)jsmall-nvidia
* Remove typo around GeometryPrimitiveTypeDecoration * * GeometryPrimitiveTypeDecoration -> GeometryInputPrimitiveTypeDecoration (to try and closer match meaning and the Modifier name) * Remove a small problem around definition of IRGeometryPrimitiveTypeDecoration * Fix comment around IRStreamOutputTypeDecoration
2019-10-08Remove EntryPointLayout* use in emit logic. (#1071)jsmall-nvidia
* Split out EntryPointParamDecoration. * Add profile to EntryPointDecoration. * WIP for GS handling for GLSL. * WIP for StreamOut GLSL * Fixed GLSL geometry output. * Clean up - remove unneeded/commented out code from the entry point change. * Use Op nums to identify GeometryTypeDecorations (as opposed to contained enum). * Remove setSampleRateFlag & doSampleRateInputCheck * Remove EntryPointLayout from emit. * Change to force CI.
2019-10-08Feature/ir entry point profile (#1068)jsmall-nvidia
* Split out EntryPointParamDecoration. * Add profile to EntryPointDecoration. * WIP for GS handling for GLSL. * WIP for StreamOut GLSL * Fixed GLSL geometry output. * Clean up - remove unneeded/commented out code from the entry point change. * Use Op nums to identify GeometryTypeDecorations (as opposed to contained enum).
2019-10-04IR types for subset of Attributes (#1067)jsmall-nvidia
* IROutputControlPointsDecoration * IROutputTopologyDecoration * IRPartitioningDecoration * IRDomainDecoration * Use IRPatchConstantDecoration alone for hlsl output. * IRMaxVertexCountDecoration * IRInstanceDecoration * Removed _emitHLSLAttributeSingleString and _emitHLSLAttributeSingleInt Removed GLSLBindingAttribute and just use NumThreadsAttribute * Added IRNumThreadsDecoration. * Added IRNumThreadsDecoration * Fix build problem on x86. Improve diagnostic text based on review.
2019-09-18Clean up some behavior of operator% (#1060)Tim Foley
Work on #1059 The `%` operator in the Slang implementation had several issues, and this change tries to address some of them: * Renamed most occurences of "mod" describing this operator to be "rem" for "remainder" to better match its semantics in HLSL * Split the operator into distinct integer and floating-point variants (`IRem` and `FRem`) to simplify having different codegen for the two * Added floating-point variants of `operator%` and `operator%=` to the stdlib. * Added custom C++ codegen for `kIROp_FRem` such that it maps to the standard C/C++ `remainder()` function * Added custom GLSL codegen so that `kIROp_FRem` maps to the GLSL `mod()` function (which isn't correct...) * Added a test case to confirm that D3D11, D3D12, and CPU targets all agree on the definition of floating-point `%` * Fixed `render-test-tool` to allow a negative integer in a `data=...` specification. This didn't end up being used in the final test, but still seems like a good fix. * Added a customized baseline for the Vulkan flavor of that test to confirm that we are *not* compiling correctly to SPIR-V just yet Addressing the correctness of the output for GLSL/SPIR-V will have to come as a later change given that the operation we want is not exposed directly by unextended GLSL.
2019-08-08Revise new COM-lite API (#1007)Tim Foley
* Revise new COM-lite API This change revises the "COM-lite" API that was recently introduced to try to streamline it and introduce some missing central/base concepts. The central new abstraction in the API is the notion of a "component type," which is a unit of shader code composition. A component type can have: * IR code for some number of functions/types/etc. * Zero or more global shader parameters * Zero or more "entry point" functions at which execution can start * Zero or more "specialization" parameters (types or values that must be filled in before kernel code can be generated) * Zero or more "requirements" (dependencies on other component types that must be satisfied before kernel code can be generated) Both individual compiled modules, and validated entry points are then examples of component types, and we additionally define a few services that apply to all component types: * We can take N component types and compose them to create a new component type that combines their code, shader parameters, entry points, and specialization parameters. A composed component type may also include requirements from the sub-component types, but it is also possible that by composing thing we satisfy requirements (if `A` requires `B`, and we compose `A` and `B`, then the requirement is now satisfied, and doesn't appear on the composite). * We can take a component type with N specialization parameters, and specialize it by giving N compatible specialization arguments. The result of specialization is a new component type with zero specialization parameters. Under the right circumstances the specialzed component type will be layout compatible with the unspecialized one. * One more example that isn't exposed in the public API today is that we can take a component with requirements and "complete" it by automatically composing it with component types that satisfy those requirements. This can be seen as a kind of linking step that pulls together the transitive closure of dependencies. * We can query the layout for the shader parameters and entry points of a component type, for a specific target. * We can query compiled kernel code for an entry point in a component type (for a specific target). This only works for component types with zero specialization parameters and zero requirements. The idea is that by giving users a fairly general algebra of operations on component types, they can compose final programs in ways that meet their requirements. For example, it becomes possible to incrementally "grow" a component type to represent the global root signature for ray tracing shaders as new entry points are added, in such a way that it always stays layout-compatible with kernels that have already been compiled. Much of the implementation work here is in implementing the unifying component type abstraction, and in particular re-writing code that used to assume a program consisted of a flat list of modules and entry points to work with a hierarchical representation that reflects the underlying algebra (e.g., with types to represent composite and specialized component types). There's also a hidden "legacy" case of a component type to deal with some legacy compiler behaviors that can't be directly modeled on top of the simple algebra with modules and entry points. This API is by no means feature-complete or fully developed. It is expected that we will flesh it out more when bringing up application code (e.g., Falcor) on top of the revamped API. One notable thing that went away in this change is explicit support for "entry point groups" and notions of local root signatures (especially the Falcor-specific handling of the `shared` keyword, which a previous change turned into an explicitly supported feature). With the new "building blocks" approach, it should be possible for a DXR application to deal with local root signatures as a matter of policy (on top of the API we provide). If/when we need to provide some kind of emulation of local root signatures for Vulkan (and/or if Vulkan is extended with an explicit notion of local root signatures), we might need to revisit this choice. * Fix debug build There was invalid code inside an `assert()`, so the release build didn't catch it. * fixup: warnings * fixup: more warnings-as-errors * fixup: review notes * fixup: use component type visitors in place of dynamic casting
2019-07-17Change how global-scope constants are handled (#1001)Tim Foley
Before this change, global and function-scope `static const` declarations were represented as instructions of type `IRGlobalConstant`, which was represented similarly to an `IRGlobalVar`: with a "body" block of instructions that compute/return the initial value. This representation inhibited optimizations (because a reference to a global constant would not in general be replaced with a reference to its value), and also caused problems for resource type legalization because the logic for type legalization did not (and still does not) handle initializers on globals (so global *variables* that contain resource types are still unsupported). The change here is simple at the high level: we get rid of `IRGlobalConstant` and instead handle global-scope constants as "ordinary" instructions at the global scope. E.g., if we have a declaration like: static const int a[] = { ... } that will be represented in the IR as a `makeArray` instruction at the global scope, referencing other global-scope instructions that represent the values in the array. This simple choice addresses both of the main limitations. A `static const` variable of integer/float/whatever type is now represented as just a reference to the given IR value and thus enables all the same optimizations. When a `static const` variable uses a type with resources, the existing legalization logic (which can handle most of the "ordinary" instructions already) applies. Another secondary benefit of this approach is that the hacky `IREmitMode` enumeration is no longer needed to help us special-case source code emit for `static const` variables. Beyond just removing `IRGlobalConstant`, and updating the lowering logic to use the initializer direclty, the main change here is to the emit logic to make it properly handle "ordinary" instructions that might appear at global scope. One open issue with this change, that could be addressed in a follow-up change, is that "extern" global constants that need to be imported from another module (but which might not have a known value when the current module is compiled) aren't supported - we don't have a way to put a linkage decoration on them. A future change might re-introduce global constants as a distinct IR instruction type that just references the value as an operand (if it is available). We would then need to replace references to an IR constant with references to its value right after linking.
2019-06-06Split out target code generation from CLikeSourceEmitter (#976)jsmall-nvidia
* * Added SourceStyle to CLikeSourceEmitter, to limit cases to actual target types. * Made Impl methods _ prefixed * Small tidyup * * SourceStream -> SourceWriter * use slang-emit- prefix on SourceWriter file * * Remove EmitContext -> merge into CLikeSourceEmitter * slang-c-like-source-emitter -> slang-emit-source.cpp * ExtensionUsageTracker -> GLSLExtensionTracker slang-extension-usage-tracker.cpp/.h -> slang-emit-glsl-extension-tracker.cpp/.h * emit-source.cpp.h -> emit-c-like.cpp/.h * Small fix to move where some _ prefixed functions are declared in CLikeSourceEmitter. * * CLikeSourceEmitter::CInfo -> Desc * Functions to get and find CodeGenTarget by name * Split out empty language impls * Create an impl based on SourceStyle * * CodeGenTarget conversion to and from string * Move HLSL specific functions to HLSLEmitSource. * Emitting texture and image types. * Move move GLSL specific functionality to GLSLSourceEmitter * Split more out of slang-emit-c-like * Refactor more out of slang-emit-c-like * * tryEmitIRInstExprImpl(IRInst* inst, IREmitMode mode, const EmitOpInfo& inOuterPrec) * Fix bug around output of uintBitsToFloat * More work refactoring out target specifics from slang-emit-c-like * Move functions that are only implemented once in GLSL impl into their Impl method. * Move rate qualification out of slang-emit-c-like * * Added getEmitOpForOp - allows for table usage so different ops can be dealt with the same way * Moved vector comparison to slang-emit-glsl * * * Use EmitOpInfo to control output in slang-emit-c-like.cpp for unary ops * Move more functionality from CLikeSourceEmitter to HLSLSourceEmitter * Make output of parameters implementaion specific. * Extracted interpolation modifiers. * Remove IR from methods that don't need them. * Remove IR from method names. * Refactor handling of output of types - to make the impls implement the full path without lots of cases for specific impls * Add variable declaration modifiers and matrix layout to larget specific in slang-emit. * Make target specific internal functions _ prefixed.