diff --git a/docs/using-the-compiler.md b/docs/using-the-compiler.md index 1ef6688f..00ba625b 100644 --- a/docs/using-the-compiler.md +++ b/docs/using-the-compiler.md @@ -13,7 +13,7 @@ When using `rolling-translate` Varjo will check the data flowing from stage to s Stages are made using the [make-stage](http://techsnuffle.com/varjo/varjo-reference.html#VARJO.API%3AMAKE-STAGE) function. -Vari supports all of the kinds of GLSL stage. When calling make-stage the stage kind is passed one of the following keywords: +Vari supports all of the kinds of GLSL stages. When calling make-stage the stage kind is passed one of the following keywords: - `:vertex` - `:tessellation-control` @@ -293,3 +293,260 @@ Just with this we already have enough that we could go back to using `define-var ### A quick note of v-defstruct As with `v-defun` there is a `v-defstruct` macro which is still commonly used. I'm trying to move to more consistent naming as we prepare to leave beta and so I advise preferring `define-vari-struct` over `v-defstruct`. It gives you nicer highlighting when using slime and will stay more consistent with the rest of public api as I update them. + +## Extensions + +We allow you to enable (or disable) GLSL extensions by passing them to Varjo as a sublist of the `context` argument of `make-stage`. +While all keywords in the `context` list are interpreted as version specifiers, the last list whose first element is `:extensions` is used to enable or disable extensions. + +To enable extensions you can simply add the name of the extension as a string like this: + + '(:400 (:extensions "GL_ARB_separate_shader_objects")) + +To specifiy a specific behavior for an extension you can use a list containing the name of the extension as its first element and the behavior as a keyword as the second element: + + '(:400 (:extensions ("GL_ARB_shading_language_420pack" :require))) + +Allowed behaviors are `:enable`, `:disable`, `:warn` and `:require`. + +This is how extensions look when used in a stage: + + TESTS> (glsl-code + (translate + (make-stage :fragment '((color :vec4)) + nil + '(:400 + (:extensions + "GL_ARB_separate_shader_objects" + ("GL_ARB_shading_language_420pack" :require))) + '(color)))) + + "// fragment-stage + #version 400 + + #extension GL_ARB_separate_shader_objects : enable + #extension GL_ARB_shading_language_420pack : require + + in _IN_BLOCK_ + { + in vec4 COLOR; + } v_in; + + layout(location = 0) out vec4 _FRAGMENT_STAGE_OUT_0; + + void main() + { + _FRAGMENT_STAGE_OUT_0 = v_in.COLOR; + return; + } + + " + +## Experimental Vulkan Support + +Varjo offers experimental support for Vulkan (or SPIR-V). +Currently only new qualifiers and types added for Vulkan are supported, but new GLSL functions, variables and shader stages (ray tracing and mesh shaders) are still missing. + +To enable Vulkan specific features you need to pass the target environment `:vulkan` to `make-stage` within the `context` argument. +E.g. like this: + + '(:440 (:target-environment :vulkan)) + +This will add `location` qualifiers to members of interface blocks (e.g. `v_out`), since SPIR-V matches in/out variable only by their `location` and not their names. +Because GLSL versions < 4.40 don't support `location` qualifiers for interface blocks, you must specifiy at least version `:440` when targetting Vulkan. +E.g.: + + TESTS> (glsl-code + (translate + (make-stage :fragment '((color :vec4)) + nil + '(:440 + (:target-environment :vulkan)) + '(color)))) + "// fragment-stage + #version 440 + + in _IN_BLOCK_ + { + layout(location = 0) in vec4 COLOR; + } v_in; + + layout(location = 0) out vec4 _FRAGMENT_STAGE_OUT_0; + + void main() + { + _FRAGMENT_STAGE_OUT_0 = v_in.COLOR; + return; + } + " + +### Descriptor Sets + +To specify the descriptor set and binding (within the set) for a uniform, you can pass them as extra qualifiers (`:set` and `:binding`) to the uniform definition. +Since both qualifiers require a value the qualifiers must be specified as lists where the first element is the qualifier and the second one is the value. +E.g.: + + '((some-buffer my-uniform-buffer :ubo :std-140 (:set 0) (:binding 0))) + +Used in a vertex shader: + + TESTS> (define-vari-struct uniform-buffer () + (mvpc :mat4)) + UNIFORM-BUFFER + TESTS> (glsl-code + (translate + (make-stage :vertex '((pos :vec4) + (color :vec4)) + '((uniform-buffer uniform-buffer :ubo :std-140 (:set 0) (:binding 0))) + '(:440 + (:target-environment :vulkan)) + '((with-slots (mvpc) uniform-buffer + (values + (* mvpc pos) + color)))))) + "// vertex-stage + #version 440 + + layout(location = 0) in vec4 POS; + layout(location = 1) in vec4 COLOR; + + out _FROM_VERTEX_STAGE_ + { + layout(location = 0) out vec4 _VERTEX_STAGE_OUT_1; + } v_out; + + layout(std140, set = 0, binding = 0) uniform _UBO_UNIFORM_BUFFER + { + mat4 MVPC; + } UNIFORM_BUFFER; + + void main() + { + vec4 g_PROG1_TMP1531 = (UNIFORM_BUFFER.MVPC * POS); + v_out._VERTEX_STAGE_OUT_1 = COLOR; + vec4 g_GEXPR0_1532 = g_PROG1_TMP1531; + gl_Position = g_GEXPR0_1532; + return; + } + " + +### Push Constants + +UBOs can be specified specified as push constants using the `:push-constant` qualifier. +Like for other UBOs the default layout for push constants is `:std-140`: + + TESTS> (glsl-code + (translate + (make-stage :vertex '((pos :vec4) + (color :vec4)) + '((uniform-buffer uniform-buffer :ubo :push-constant)) + '(:440 + (:target-environment :vulkan)) + '((with-slots (mvpc) uniform-buffer + (values + (* mvpc pos) + color)))))) + "// vertex-stage + #version 440 + + layout(location = 0) in vec4 POS; + layout(location = 1) in vec4 COLOR; + + out _FROM_VERTEX_STAGE_ + { + layout(location = 0) out vec4 _VERTEX_STAGE_OUT_1; + } v_out; + + layout(std140, push_constant) uniform _UBO_UNIFORM_BUFFER + { + mat4 MVPC; + } UNIFORM_BUFFER; + + void main() + { + vec4 g_PROG1_TMP1556 = (UNIFORM_BUFFER.MVPC * POS); + v_out._VERTEX_STAGE_OUT_1 = COLOR; + vec4 g_GEXPR0_1557 = g_PROG1_TMP1556; + gl_Position = g_GEXPR0_1557; + return; + } + " + +### Textures & Samplers + +Vulkan allows splitting textures and samplers by introducting the new sampler types `:sampler` and `:sampler-shadows` which can be used to sample different texture types (e.g. `:itexture-2d`). + +However, the [glsl-spec](https://github.com/cbaggers/glsl-spec) doesn't yet specify the functions needed to construct a texture sampler from a sampler and a texture (e.g. `sampler2D(texture, sampler)`, so you'll have to use combined texture samplers (e.g. `:sampler-2d`) for now. + +### Subpass Inputs + +Subpass inputs require `input_attachment_index` to be set. You can specify this qualifier like `set` or `binding`: + + '((albedo :subpass-input (:input-attachment-index 1) (:set 0) (:binding 1)) + +Since the GLSL functions for reading subpass inputs (i.e. `subpassLoad`) are not yet specified in [glsl-spec](https://github.com/cbaggers/glsl-spec), they are pretty useless at the moment. + +### Vulkan Types + +The following new types are allowed when targetting Vulkan: + +- `:sampler` +- `:sampler-shadow` +- `:subpass-input` +- `:subpass-input-ms` +- `:isubpass-input` +- `:isubpass-input-ms` +- `:usubpass-input` +- `:usubpass-input-ms` +- `:texture-1d` +- `:texture-1d-array` +- `:texture-2d` +- `:texture-2d-array` +- `:texture-2d-ms` +- `:texture-2d-ms-array` +- `:texture-2d-rect` +- `:texture-3d` +- `:texture-buffer` +- `:texture-cube` +- `:texture-cube-array` +- `:itexture-1d` +- `:itexture-1d-array` +- `:itexture-2d` +- `:itexture-2d-array` +- `:itexture-2d-ms` +- `:itexture-2d-ms-array` +- `:itexture-2d-rect` +- `:itexture-3d` +- `:itexture-buffer` +- `:itexture-cube` +- `:itexture-cube-array` +- `:utexture-1d` +- `:utexture-1d-array` +- `:utexture-2d` +- `:utexture-2d-array` +- `:utexture-2d-ms` +- `:utexture-2d-ms-array` +- `:utexture-2d-rect` +- `:utexture-3d` +- `:utexture-buffer` +- `:utexture-cube` +- `:utexture-cube-array` +- `:acceleration-structure-ext` (only if `GL_EXT_ray_query` is enabled) +- `:ray-query-ext` (only if `GL_EXT_ray_query` is enabled) + +#### Initializing rayQueryEXT instances (GL_EXT_ray_query extension) + +Unlike most types in GLSL, `rayQueryEXT` instances cannot by constructed by calling a GLSL function. +They are usually declared only in a function's scope and initialized by a call to `rayQueryInitializeEXT`: + + void main() { + rayQueryEXT q; + rayQueryInitializeEXT(q, ...); + ... + } + +To achieve the same in Vari, we define an uninitialized typed symbol (e.g. using `let`) and the proceed as we normally would: + + (let (((q :ray-query-ext))) + (ray-query-initialize-ext q ...)) + diff --git a/package.lisp b/package.lisp index 2d9af7a0..29d95ff1 100644 --- a/package.lisp +++ b/package.lisp @@ -232,7 +232,59 @@ :v-uimage-3d :v-uimage-cube :v-uimage-cube-array - :v-uimage-rect)) + :v-uimage-rect + ;; + :v-sampler-vulkan + :v-sampler-shadow-vulkan + ;; + :v-subpass-input + :v-subpass-input-ms + :v-isubpass-input + :v-isubpass-input-ms + :v-usubpass-input + :v-usubpass-input-ms + ;; + :v-itexture-1d + :v-itexture-1d-array + :v-itexture-2d + :v-itexture-2d-array + :v-itexture-2d-ms + :v-itexture-2d-ms-array + :v-itexture-2d-rect + :v-itexture-3d + :v-itexture-buffer + :v-itexture-cube + :v-itexture-cube-array + :v-texture-1d + :v-texture-1d-array + :v-texture-2d + :v-texture-2d-array + :v-texture-2d-ms + :v-texture-2d-ms-array + :v-texture-2d-rect + :v-texture-3d + :v-texture-buffer + :v-texture-cube + :v-texture-cube-array + :v-utexture-1d + :v-utexture-1d-array + :v-utexture-2d + :v-utexture-2d-array + :v-utexture-2d-ms + :v-utexture-2d-ms-array + :v-utexture-2d-rect + :v-utexture-3d + :v-utexture-buffer + :v-utexture-cube + :v-utexture-cube-array + :v-utexture-rect + :v-itexture-rect + :v-texture-rect + ;; + :v-acceleration-structure-ext + ;; + :v-ray-query-ext + )) ;;;; package.lisp (uiop:define-package #:varjo-conditions diff --git a/src/docs.lisp b/src/docs.lisp index 45319fab..dc6d2f06 100644 --- a/src/docs.lisp +++ b/src/docs.lisp @@ -519,17 +519,53 @@ specified a struct type the following additional qualifiers are allowed: - `:std-140` - `:std-430` +When targetting Vulkan the following additional qualifiers are allowed for uniforms: + +- `:set` +- `:binding` +- `:push-constant` (only for struct types) + +`:set` and `:binding` require an argument, so you have to specify them using a list like so: + + (:set 0) + +where the second element is the value you want to set. + The result of `make-stage` is an instance of one of the subclasses of the `stage` type. ### context The context argument must be a list that may contain any number of symbols from -*supported-versions*. Context is used to specify the GLSL version to compile the -stage. +*supported-versions* as well as other lists for other context specific settings. +Context is used to specify the GLSL version to compile the stage. + +Apart from GLSL versions, context can be used for specifying extension behaviour using a list in the following format: + + (:extension \"GL_ARB_some_extension\") + +or: + + (:extension (\"GL_ARB_some_extension1\" :enable) \"GL_ARB_some_extension2\") + +So either extensions are enabled by just passing their names as strings or a specific behaviour can be set for an extension using one of the following behaviours: + +- `:enable` +- `:disable` +- `:require` +- `:warn` + +Furthermore a target environment can be specified using a list in the following format: + + (:target-environment :opengl) + +Allowed target environments are + +- `:opengl` +- `:vulkan` -NOTE: The name 'context' is legacy at this point as it is only used to specify -GLSL versions. +The default is environment is `:opengl`. +To enable Vulkan features you have to explicitly set `:vulkan` as the stage's target environment. ### code diff --git a/src/vari.glsl/parse-from-spec.lisp b/src/vari.glsl/parse-from-spec.lisp index c470994c..df320e08 100644 --- a/src/vari.glsl/parse-from-spec.lisp +++ b/src/vari.glsl/parse-from-spec.lisp @@ -2,7 +2,8 @@ (in-readtable fn:fn-reader) (defparameter *glsl-type->varjo-type* - '(("atomic_uint" v-atomic-uint) + '(("accelerationStructureEXT" v-acceleration-structure-ext) + ("atomic_uint" v-atomic-uint) ("bool" v-bool) ("bufferImage" v-buffer-image) ("bvec2" v-bvec2) @@ -62,6 +63,19 @@ ("isamplerCube" v-isampler-cube) ("isamplerCubeArray" v-isampler-cube-array) ("isamplerRect" v-isampler-rect) + ("isubpassInput" v-isubpass-input) + ("isubpassInputMS" v-isubpass-input-ms) + ("itexture1D" v-itexture-1d) + ("itexture1DArray" v-itexture-1d-array) + ("itexture2D" v-itexture-2d) + ("itexture2DArray" v-itexture-2d-array) + ("itexture2DMS" v-itexture-2d-ms) + ("itexture2DRect" v-itexture-2d-rect) + ("itexture3D" v-itexture-3d) + ("itextureBuffer" v-itexture-buffer) + ("itextureCube" v-itexture-cube) + ("itextureCubeArray" v-itexture-cube-array) + ("itextureRect" v-itexture-rect) ("ivec2" v-ivec2) ("ivec3" v-ivec3) ("ivec4" v-ivec4) @@ -77,6 +91,8 @@ ("mat4x2" v-mat4x2) ("mat4x3" v-mat4x3) ("mat4x4" v-mat4x4) + ("rayQueryEXT" v-ray-query-ext) + ("sampler" v-sampler-vulkan) ("sampler1D" v-sampler-1d) ("sampler1DArray" v-sampler-1d-array) ("sampler1DArrayShadow" v-sampler-1d-array-shadow) @@ -96,6 +112,20 @@ ("samplerCubeArrayShadow" v-sampler-cube-array-shadow) ("samplerCubeShadow" v-sampler-cube-shadow) ("samplerRect" v-sampler-rect) + ("samplerShadow" v-sampler-shadow-vulkan) + ("subpassInput" v-subpass-input) + ("subpassInputMS" v-subpass-input-ms) + ("texture1D" v-texture-1d) + ("texture1DArray" v-texture-1d-array) + ("texture2D" v-texture-2d) + ("texture2DArray" v-texture-2d-array) + ("texture2DMS" v-texture-2d-ms) + ("texture2DRect" v-texture-2d-rect) + ("texture3D" v-texture-3d) + ("textureBuffer" v-texture-buffer) + ("textureCube" v-texture-cube) + ("textureCubeArray" v-texture-cube-array) + ("textureRect" v-texture-rect) ("ubufferImage" v-ubuffer-image) ("uimage1D" v-uimage-1d) ("uimage1DArray" v-uimage-1d-array) @@ -121,6 +151,19 @@ ("usamplerCube" v-usampler-cube) ("usamplerCubeArray" v-usampler-cube-array) ("usamplerRect" v-usampler-rect) + ("usubpassInput" v-usubpass-input) + ("usubpassInputMS" v-usubpass-input-ms) + ("utexture1D" v-utexture-1d) + ("utexture1DArray" v-utexture-1d-array) + ("utexture2D" v-utexture-2d) + ("utexture2DArray" v-utexture-2d-array) + ("utexture2DMS" v-utexture-2d-ms) + ("utexture2DRect" v-utexture-2d-rect) + ("utexture3D" v-utexture-3d) + ("utextureBuffer" v-utexture-buffer) + ("utextureCube" v-utexture-cube) + ("utextureCubeArray" v-utexture-cube-array) + ("utextureRect" v-utexture-rect) ("uvec2" v-uvec2) ("uvec3" v-uvec3) ("uvec4" v-uvec4) diff --git a/src/vari.types/types.lisp b/src/vari.types/types.lisp index e99c48a7..d4267a2d 100644 --- a/src/vari.types/types.lisp +++ b/src/vari.types/types.lisp @@ -936,6 +936,342 @@ (tertiary-score :initform 1 :initarg :tertiary-score :reader tertiary-score))) +;;---------------------------------------------------------------------- +;; Sampler (Vulkan only) + +(define-v-type-class v-sampler-vulkan (v-sampler-type) + ((core :initform t :reader core-typep) + (glsl-string :initform "sampler" :reader v-glsl-string) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-sampler-shadow-vulkan (v-sampler-type) + ((core :initform t :reader core-typep) + (glsl-string :initform "samplerShadow" :reader v-glsl-string) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +;;---------------------------------------------------------------------- +;; Subpass Input (Vulkan only) + +(define-v-type-class v-subpass-input (v-subpass-input-type) + ((core :initform t :reader core-typep) + (glsl-string :initform "subpassInput" :reader v-glsl-string) + (element-type :initform 'v-vec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-subpass-input-ms (v-subpass-input-type) + ((core :initform t :reader core-typep) + (glsl-string :initform "subpassInputMS" :reader v-glsl-string) + (element-type :initform 'v-vec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-isubpass-input (v-subpass-input-type) + ((core :initform t :reader core-typep) + (glsl-string :initform "isubpassInput" :reader v-glsl-string) + (element-type :initform 'v-ivec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-isubpass-input-ms (v-subpass-input-type) + ((core :initform t :reader core-typep) + (glsl-string :initform "isubpassInputMS" :reader v-glsl-string) + (element-type :initform 'v-ivec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-usubpass-input (v-subpass-input-type) + ((core :initform t :reader core-typep) + (glsl-string :initform "usubpassInput" :reader v-glsl-string) + (element-type :initform 'v-uvec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-usubpass-input-ms (v-subpass-input-type) + ((core :initform t :reader core-typep) + (glsl-string :initform "usubpassInputMS" :reader v-glsl-string) + (element-type :initform 'v-uvec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +;;---------------------------------------------------------------------- +;; Texture (Vulkan only) + +(define-v-type-class v-itexture-1d (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "itexture1D" :reader v-glsl-string) + (element-type :initform 'v-ivec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-itexture-1d-array (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "itexture1DArray" :reader v-glsl-string) + (element-type :initform 'v-ivec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-itexture-2d (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "itexture2D" :reader v-glsl-string) + (element-type :initform 'v-ivec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-itexture-2d-array (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "itexture2DArray" :reader v-glsl-string) + (element-type :initform 'v-ivec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-itexture-2d-ms (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "itexture2DMS" :reader v-glsl-string) + (element-type :initform 'v-ivec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-itexture-2d-ms-array (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "itexture2DMSArray" :reader v-glsl-string) + (element-type :initform 'v-ivec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-itexture-2d-rect (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "itexture2DRect" :reader v-glsl-string) + (element-type :initform 'v-ivec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-itexture-3d (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "itexture3D" :reader v-glsl-string) + (element-type :initform 'v-ivec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-itexture-buffer (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "itextureBuffer" :reader v-glsl-string) + (element-type :initform 'v-ivec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-itexture-cube (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "itextureCube" :reader v-glsl-string) + (element-type :initform 'v-ivec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-itexture-cube-array (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "itextureCubeArray" :reader v-glsl-string) + (element-type :initform 'v-ivec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-texture-1d (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "texture1D" :reader v-glsl-string) + (element-type :initform 'v-vec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-texture-1d-array (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "texture1DArray" :reader v-glsl-string) + (element-type :initform 'v-vec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-texture-2d (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "texture2D" :reader v-glsl-string) + (element-type :initform 'v-vec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-texture-2d-array (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "texture2DArray" :reader v-glsl-string) + (element-type :initform 'v-vec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-texture-2d-ms (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "texture2DMS" :reader v-glsl-string) + (element-type :initform 'v-vec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-texture-2d-ms-array (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "texture2DMSArray" :reader v-glsl-string) + (element-type :initform 'v-vec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-texture-2d-rect (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "texture2DRect" :reader v-glsl-string) + (element-type :initform 'v-vec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-texture-3d (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "texture3D" :reader v-glsl-string) + (element-type :initform 'v-vec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-texture-buffer (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "textureBuffer" :reader v-glsl-string) + (element-type :initform 'v-vec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-texture-cube (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "textureCube" :reader v-glsl-string) + (element-type :initform 'v-vec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-texture-cube-array (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "textureCubeArray" :reader v-glsl-string) + (element-type :initform 'v-vec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-utexture-1d (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "utexture1D" :reader v-glsl-string) + (element-type :initform 'v-uvec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-utexture-1d-array (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "utexture1DArray" :reader v-glsl-string) + (element-type :initform 'v-uvec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-utexture-2d (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "utexture2D" :reader v-glsl-string) + (element-type :initform 'v-uvec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-utexture-2d-array (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "utexture2DArray" :reader v-glsl-string) + (element-type :initform 'v-uvec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-utexture-2d-ms (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "utexture2DMS" :reader v-glsl-string) + (element-type :initform 'v-uvec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-utexture-2d-ms-array (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "utexture2DMSArray" :reader v-glsl-string) + (element-type :initform 'v-uvec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-utexture-2d-rect (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "utexture2DRect" :reader v-glsl-string) + (element-type :initform 'v-uvec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-utexture-3d (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "utexture3D" :reader v-glsl-string) + (element-type :initform 'v-uvec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-utexture-buffer (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "utextureBuffer" :reader v-glsl-string) + (element-type :initform 'v-uvec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-utexture-cube (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "utextureCube" :reader v-glsl-string) + (element-type :initform 'v-uvec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-utexture-cube-array (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "utextureCubeArray" :reader v-glsl-string) + (element-type :initform 'v-uvec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-texture-rect (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "textureRect" :reader v-glsl-string) + (element-type :initform 'v-uvec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-itexture-rect (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "itextureRect" :reader v-glsl-string) + (element-type :initform 'v-uvec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +(define-v-type-class v-utexture-rect (v-texture) + ((core :initform t :reader core-typep) + (glsl-string :initform "utextureRect" :reader v-glsl-string) + (element-type :initform 'v-uvec4) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +;;---------------------------------------------------------------------- +;; accelerationStructureEXT (Vulkan only) + +(define-v-type-class v-acceleration-structure-ext (v-opaque-vulkan-type) + ((core :initform t :reader core-typep) + (glsl-string :initform "accelerationStructureEXT" :reader v-glsl-string) + (element-type :initform 'v-type) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score))) + +;;---------------------------------------------------------------------- +;; rayQueryEXT (Vulkan only) + +(define-v-type-class v-ray-query-ext (v-opaque-vulkan-type) + ((core :initform t :reader core-typep) + (glsl-string :initform "rayQueryEXT" :reader v-glsl-string) + (element-type :initform 'v-type) + (tertiary-score :initform 1 :initarg :tertiary-score + :reader tertiary-score) + (allow-unboundp :initform t :reader allow-unboundp))) + ;;---------------------------------------------------------------------- ;; Type Stubs ;; diff --git a/src/varjo.internals/compile-result.lisp b/src/varjo.internals/compile-result.lisp index ba58029d..a8cc1a6d 100644 --- a/src/varjo.internals/compile-result.lisp +++ b/src/varjo.internals/compile-result.lisp @@ -11,6 +11,8 @@ (uniform-variables nil uniforms-set) (implicit-uniforms nil implicit-uniforms-set) (context nil context-set) + (target-environment nil target-environment-set) + (extensions nil extensions-set) (stemcells-allowed nil a-s-set) (used-external-functions nil used-external-functions-set) (previous-stage nil previous-stage-set) @@ -42,6 +44,12 @@ :context (if context-set context (context original)) + :target-environment (if target-environment-set + target-environment + (target-environment original)) + :extensions (if extensions-set + extensions + (extensions original)) :stemcells-allowed (if a-s-set stemcells-allowed (stemcells-allowed original)) diff --git a/src/varjo.internals/compile-vars.lisp b/src/varjo.internals/compile-vars.lisp index c0b46418..565ed89b 100644 --- a/src/varjo.internals/compile-vars.lisp +++ b/src/varjo.internals/compile-vars.lisp @@ -41,7 +41,8 @@ (defun compile-symbol (symbol env &key allow-unbound) (let ((binding (get-symbol-binding symbol t env))) (etypecase binding - (uninitialized-value (if allow-unbound + (uninitialized-value (if (or allow-unbound + (allow-unboundp (v-type-of binding))) (v-variable->code-obj symbol binding env) (error 'uninitialized-var :name symbol))) (v-symbol-macro (expand-symbol-macro binding env)) diff --git a/src/varjo.internals/environment.lisp b/src/varjo.internals/environment.lisp index 9828f573..3e66a413 100644 --- a/src/varjo.internals/environment.lisp +++ b/src/varjo.internals/environment.lisp @@ -145,6 +145,7 @@ :stage stage :env-depth 0 :context (context stage) + :extensions (extensions stage) :stemcells-allowed stemcells-allowed))) (setf (slot-value result 'base-env) result) result)) diff --git a/src/varjo.internals/extension.lisp b/src/varjo.internals/extension.lisp new file mode 100644 index 00000000..dd99208c --- /dev/null +++ b/src/varjo.internals/extension.lisp @@ -0,0 +1,21 @@ +(in-package :varjo.internals) +(in-readtable fn:fn-reader) + +;;------------------------------------------------------------ + +(defun make-extension (extension-form) + (let* ((ext (listify extension-form)) + (name (first ext)) + (behavior (or (and (= (length ext) 2) + (second ext)) + :enable))) + (assert (stringp (first ext))) + (assert (and (keywordp behavior) + (member behavior *glsl-extension-behaviors*)) + () "Varjo: Not a valid extension behavior: ~a" behavior) + (make-instance 'extension + :name name + :behavior behavior + :glsl-string (format nil "~a : ~(~a~)" + name behavior)))) + diff --git a/src/varjo.internals/globals.lisp b/src/varjo.internals/globals.lisp index a1eb08ee..a7b36ee5 100644 --- a/src/varjo.internals/globals.lisp +++ b/src/varjo.internals/globals.lisp @@ -6,6 +6,8 @@ (defvar *supported-versions* '(:140 :150 :330 :400 :410 :420 :430 :440 :450 :460)) +(defvar *target-environments* '(:opengl :vulkan)) + (defvar *stage-names* '(:vertex :tessellation-control @@ -69,33 +71,104 @@ (defvar +ascii-alpha-num+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") +(defvar *glsl-extension-behaviors* + '(:require + :enable + :warn + :disable)) + +(defparameter *glsl-image-float-format-qualifiers* + '((:rgba32f "rgba32f") + (:rgba16f "rgba16f") + (:rg32f "rg32f") + (:rg16f "rg16f") + (:r11f-g11f-b10f "r11f_g11f_b10f") + (:r32f "r32f") + (:r16f "r16f") + (:rgba16 "rgba16") + (:rgb10-a2 "rgb10_a2") + (:rgba8 "rgba8") + (:rg16 "rg16") + (:rg8 "rg8") + (:r16 "r16") + (:r8 "r8") + (:rgba16-snorm "rgba16_snorm") + (:rgba8-snorm "rgba8_snorm") + (:rg16-snorm "rg16_snorm") + (:rg8-snorm "rg8_snorm") + (:r16-snorm "r16_snorm") + (:r8-snorm "r8_snorm"))) + +(defparameter *glsl-image-int-format-qualifiers* + '((:rgba32i "rgba32i") + (:rgba16i "rgba16i") + (:rgba8i "rgba8i") + (:rg32i "rg32i") + (:rg16i "rg16i") + (:rg8i "rg8i") + (:r32i "r32i") + (:r16i "r16i") + (:r8i "r8i") + (:rgba32ui))) + +(defparameter *glsl-image-uint-format-qualifiers* + '((:rgba32ui "rgba32ui") + (:rgba16ui "rgba16ui") + (:rgba10-a2ui "rgb10_a2ui") + (:rgba8ui "rgba8ui") + (:rg32ui "rg32ui") + (:rg16ui "rg16ui") + (:rg8ui "rg8ui") + (:r32ui "r32ui") + (:r16ui "r16ui") + (:r8ui "r8ui"))) + +(defparameter *glsl-image-format-qualifiers* + (concatenate 'list + *glsl-image-float-format-qualifiers* + *glsl-image-int-format-qualifiers* + *glsl-image-uint-format-qualifiers*)) + +(defparameter *glsl-vulkan-qualifiers* + '((:set "set" t) + (:constant-id "constant_id" t) ;; only allowed for const qualified + (:push-constant "push_constant") + (:input-attachment-index "input_attachment_index" t) ;; only allowed and required by subpassInput types + (:local-size-x-id "local_size_x_id" t) + (:local-size-y-id "local_size_y_id" t) + (:local-size-z-id "local_size_z_id" t))) + (defparameter *glsl-qualifiers* - '((:attribute "attribute") - (:buffer "buffer") - (:centroid "centroid") - (:coherent "coherent") - (:const "const") - (:flat "flat") - (:highp "highp") - (:in "in") - (:invariant "invariant") - (:lowp "lowp") - (:mediump "mediump") - (:noperspective "noperspective") - (:out "out") - (:in/out "inout") - (:packed "packed") - (:readonly "readonly") - (:restrict "restrict") - (:sample "sample") - (:shared "shared") - (:smooth "smooth") - (:std-140 "std140") - (:std-430 "std430") - (:uniform "uniform") - (:varying "varying") - (:volatile "volatile") - (:writeonly "writeonly"))) + (concatenate 'list + '((:attribute "attribute") + (:buffer "buffer") + (:centroid "centroid") + (:coherent "coherent") + (:const "const") + (:flat "flat") + (:highp "highp") + (:in "in") + (:invariant "invariant") + (:lowp "lowp") + (:mediump "mediump") + (:noperspective "noperspective") + (:out "out") + (:in/out "inout") + (:packed "packed") + (:readonly "readonly") + (:restrict "restrict") + (:sample "sample") + (:shared "shared") + (:smooth "smooth") + (:std-140 "std140") + (:std-430 "std430") + (:uniform "uniform") + (:varying "varying") + (:volatile "volatile") + (:writeonly "writeonly") + (:binding "binding" t)) + *glsl-vulkan-qualifiers* + *glsl-image-format-qualifiers*)) (defparameter *varjo-qualifiers* (append @@ -248,7 +321,53 @@ (:ibuffer-image . v-ibuffer-image) (:ubuffer-image . v-ubuffer-image) (:void . v-void) - (:shadow-type . v-shadow-type))) + (:shadow-type . v-shadow-type) + (:sampler . v-sampler-vulkan) + (:sampler-shadow . v-sampler-shadow-vulkan) + (:isubpass-input . v-isubpass-input) + (:isubpass-input-ms . v-isubpass-input-ms) + (:subpass-input . v-subpass-input) + (:subpass-input-ms . v-subpass-input-ms) + (:usubpass-input . v-usubpass-input) + (:usubpass-input-ms . v-usubpass-input-ms) + (:itexture-1d . v-itexture-1d) + (:itexture-1d-array . v-itexture-1d-array) + (:itexture-2d . v-itexture-2d) + (:itexture-2d-array . v-itexture-2d-array) + (:itexture-2d-ms . v-itexture-2d-ms) + (:itexture-2d-ms-array . v-itexture-2d-ms-array) + (:itexture-2d-rect . v-itexture-2d-rect) + (:itexture-3d . v-itexture-3d) + (:itexture-buffer . v-itexture-buffer) + (:itexture-cube . v-itexture-cube) + (:itexture-cube-array . v-itexture-cube-array) + (:texture-1d . v-texture-1d) + (:texture-1d-array . v-texture-1d-array) + (:texture-2d . v-texture-2d) + (:texture-2d-array . v-texture-2d-array) + (:texture-2d-ms . v-texture-2d-ms) + (:texture-2d-ms-array . v-texture-2d-ms-array) + (:texture-2d-rect . v-texture-2d-rect) + (:texture-3d . v-texture-3d) + (:texture-buffer . v-texture-buffer) + (:texture-cube . v-texture-cube) + (:texture-cube-array . v-texture-cube-array) + (:utexture-1d . v-utexture-1d) + (:utexture-1d-array . v-utexture-1d-array) + (:utexture-2d . v-utexture-2d) + (:utexture-2d-array . v-utexture-2d-array) + (:utexture-2d-ms . v-utexture-2d-ms) + (:utexture-2d-ms-array . v-utexture-2d-ms-array) + (:utexture-2d-rect . v-utexture-2d-rect) + (:utexture-3d . v-utexture-3d) + (:utexture-buffer . v-utexture-buffer) + (:utexture-cube . v-utexture-cube) + (:utexture-cube-array . v-utexture-cube-array) + (:texture-rect . v-texture-rect) + (:itexture-rect . v-itexture-rect) + (:utexture-rect . v-utexture-rect) + (:acceleration-structure-ext . v-acceleration-structure-ext) + (:ray-query-ext . v-ray-query-ext))) (defvar *base-reserved* '("active" @@ -452,3 +571,50 @@ "volatile" "while" "writeonly")) + +;;{TODO} add this to validation of glsl name strings when target is vulkan +(defvar *reserved-vulkan* + '("accelerationStructureEXT" + "isubpassInput" + "isubpassInputMS" + "itexture1D" + "itexture1DArray" + "itexture2D" + "itexture2DArray" + "itexture2DMS" + "itexture2DMSArray" + "itexture2DRect" + "itexture3D" + "itextureBuffer" + "itextureCube" + "itextureCubeArray" + "rayQueryEXT" + "sampler" + "samplerShadow" + "subpassInput" + "subpassInputMS" + "texture1D" + "texture1DArray" + "texture2D" + "texture2DArray" + "texture2DMS" + "texture2DMSArray" + "texture2DRect" + "texture3D" + "texture3DRect" + "textureBuffer" + "textureCube" + "textureCubeArray" + "usubpassInput" + "usubpassInputMS" + "utexture1D" + "utexture1DArray" + "utexture2D" + "utexture2DArray" + "utexture2DMS" + "utexture2DMSArray" + "utexture2DRect" + "utexture3D" + "utextureBuffer" + "utextureCube" + "utextureCubeArray")) diff --git a/src/varjo.internals/glsl-generation/string-generation.lisp b/src/varjo.internals/glsl-generation/string-generation.lisp index 4d64b422..08075ae1 100644 --- a/src/varjo.internals/glsl-generation/string-generation.lisp +++ b/src/varjo.internals/glsl-generation/string-generation.lisp @@ -184,9 +184,28 @@ (prefix-type-to-string type glsl-name (append qualifiers (list *in-qualifier*))))) -(defun gen-uniform-decl-string (glsl-name type qualifiers) +(defun uniform-memory-layout-string (target-name layout &optional imagep) + (let ((qualifiers (listify layout))) + (assert (every (lambda (q) + (typep q 'qualifier)) + qualifiers)) + (assert (every (lambda (q) + (uniform-memory-layout-qualifier-p q imagep)) + qualifiers) + () + 'unknown-layout-specifier + :name target-name + :target-kind :uniform + :specifier layout) + (format nil "~{~a~^, ~}" (mapcar #'glsl-string layout)))) + +;;{TODO} check if type is an image type and pass to uniform-memory-layout-string +(defun gen-uniform-decl-string (glsl-name type qualifiers &optional layout) (declare (ignore qualifiers)) - (format nil "uniform ~a;" (prefix-type-to-string type glsl-name))) + (format nil "~@[layout(~a) ~]uniform ~a;" + (when layout + (uniform-memory-layout-string glsl-name layout)) + (prefix-type-to-string type glsl-name))) (defun gen-shared-decl-string (glsl-name type qualifiers) (declare (ignore qualifiers)) @@ -234,15 +253,20 @@ (:cw "cw") (:ccw "ccw")))))) +(defun format-extensions-from-env (env) + (format nil "~{#extension ~a~%~}" + (mapcar #'glsl-string (v-extensions env)))) + (defun gen-shader-string (post-proc-obj) (let* ((funcs (all-functions post-proc-obj)) (func-code (remove nil (mapcar #'glsl-code funcs))) (func-sigs (remove nil (mappend #'signatures funcs)))) (with-slots (env) post-proc-obj (format - nil "// ~a~%#version ~a~%~{~%~{~a~%~}~}" + nil "// ~a~%#version ~a~%~@[~%~a~]~{~%~{~a~%~}~}" (string-downcase (type-of (stage env))) (get-version-from-context env) + (format-extensions-from-env env) (remove nil (list (used-user-structs post-proc-obj) (in-declarations post-proc-obj) @@ -312,13 +336,16 @@ ""))) (defun block-memory-layout-string (target-name target-kind layout) - (assert (typep layout 'qualifier)) - (assert (block-memory-layout-qualfier-p layout) () - 'unknown-layout-specifier - :name target-name - :target-kind target-kind - :specifier layout) - (glsl-string layout)) + (let ((qualifiers (listify layout))) + (assert (every (lambda (q) + (typep q 'qualifier)) + qualifiers)) + (assert (every #'block-memory-layout-qualifier-p qualifiers) () + 'unknown-layout-specifier + :name target-name + :target-kind target-kind + :specifier layout) + (format nil "~{~a~^, ~}" (mapcar #'glsl-string qualifiers)))) (defun write-ubo-block (storage-qualifier block-name slots layout) (format nil "~@[layout(~a) ~]~a ~a~%{~%~{~a~%~}} ~a;" diff --git a/src/varjo.internals/internal-types.lisp b/src/varjo.internals/internal-types.lisp index ddfb0077..4c593d47 100644 --- a/src/varjo.internals/internal-types.lisp +++ b/src/varjo.internals/internal-types.lisp @@ -88,6 +88,10 @@ (uniform-variables :initarg :uniform-variables :accessor uniform-variables) (shared-variables :initarg :shared-variables :accessor shared-variables) (context :initarg :context :accessor context) + (target-environment :initarg :target-environment :accessor target-environment + :initform :opengl) + (extensions :initarg :extensions :accessor extensions + :initform nil) (lisp-code :initarg :lisp-code :accessor lisp-code) (stemcells-allowed :initarg :stemcells-allowed :accessor stemcells-allowed) (previous-stage :initarg :previous-stage :accessor previous-stage @@ -162,6 +166,14 @@ ;;---------------------------------------------------------------------- +(defclass extension () + ((name :initarg :name :reader name) + (behavior + :initform :enable :initarg :behavior :reader behavior) + (glsl-string :initarg :glsl-string :reader glsl-string))) + +;;---------------------------------------------------------------------- + (defclass environment () ((base-env :initform nil :initarg :base-env) @@ -173,6 +185,8 @@ :reader v-previous-env-with-form-bindings) (context :initform nil :initarg :context :reader v-context) + (extensions + :initform nil :initarg :extensions :reader v-extensions) (symbol-bindings :initform nil :initarg :symbol-bindings :reader v-symbol-bindings) (form-bindings @@ -200,6 +214,7 @@ (uniforms :initform nil :initarg :uniforms :accessor v-uniforms) (shared :initform nil :initarg :shared :accessor v-shared) (context :initform nil :initarg :context :reader v-context) + (extensions :initform nil :initarg :extensions :reader v-extensions) (stemcell->flow-id :initform (make-hash-table :test #'eq) :initarg :stemcell->flow-id) (name-map :initform (make-hash-table :test #'equal)) diff --git a/src/varjo.internals/qualifiers.lisp b/src/varjo.internals/qualifiers.lisp index 7b45e032..4cd7f9c2 100644 --- a/src/varjo.internals/qualifiers.lisp +++ b/src/varjo.internals/qualifiers.lisp @@ -14,11 +14,18 @@ (let ((spec (find name *varjo-qualifiers* :key #'first))) ;; {TODO} Proper error (assert spec () "Varjo: '~a' is not a valid qualifier." name) + (when (third spec) + (assert (first args) () + "Varjo: Qualifier '~a' requires an argument, but none was specified" (first spec))) (case name (:feedback (parse-feedback-qualifier name args)) (otherwise (make-instance 'qualifier :name name - :glsl-string (second spec))))))) + :glsl-string (if (third spec) + (format nil "~a = ~a" + (second spec) + (first args)) + (second spec)))))))) (defun parse-feedback-qualifier (name args) (let ((fb-arg-len (length args)) @@ -49,11 +56,38 @@ b))) (string= a b))) +(defun constant-memory-layout-qualifier-p (qualifier) + (check-type qualifier qualifier) + (not (null (member (name qualifier) + '(:constant-id))))) + +(defun image-memory-layout-qualifier-p (qualifier) + (check-type qualifier qualifier) + (not (null (find (name qualifier) *glsl-image-format-qualifiers* :key #'first)))) -(defun block-memory-layout-qualfier-p (qualifier) +(defun uniform-memory-layout-qualifier-p (qualifier &optional imagep) + (check-type qualifier qualifier) + (or (not (null (member (name qualifier) + '(:binding + :set + :input-attachment-index)))) + (and imagep + (image-memory-layout-qualifier-p qualifier)))) + +(defun block-memory-layout-qualifier-p (qualifier) (check-type qualifier qualifier) (not (null (member (name qualifier) - '(:std-140 :std-430 :packed :shared))))) + '(:std-140 + :std-430 + :packed + :shared + :binding + :set + :push-constant))))) + +(defun memory-layout-qualifier-p (qualifier) + (or (block-memory-layout-qualifier-p qualifier) + (uniform-memory-layout-qualifier-p qualifier))) (defmethod qualifiers ((obj shader-variable)) (qualifiers (v-type-of obj))) diff --git a/src/varjo.internals/stages.lisp b/src/varjo.internals/stages.lisp index 5393d2c0..0f1ac4e5 100644 --- a/src/varjo.internals/stages.lisp +++ b/src/varjo.internals/stages.lisp @@ -7,12 +7,18 @@ &optional (stemcells-allowed t) primitive) (assert (listp context) () "Varjo: The context argument to make-stage must be a list") - (create-stage kind context - :input-variables in-args - :uniform-variables uniforms - :code code - :stemcells-allowed stemcells-allowed - :primitive primitive)) + (multiple-value-bind (version/s target-env extensions includes) + (destructure-context context) + (create-stage kind version/s + :input-variables in-args + :uniform-variables uniforms + :code code + :stemcells-allowed stemcells-allowed + :primitive primitive + :target-environment target-env + :extensions extensions + ;; actually includes don't make a lot of sense in Varjo, but who knows... + :includes includes))) (defun create-stage (kind version/s &key @@ -21,9 +27,16 @@ shared-variables code (stemcells-allowed t) - primitive) + primitive + (target-environment :opengl) + includes + extensions) (when (and (every #'check-arg-form input-variables) - (every #'check-arg-form uniform-variables) + (every (lambda (arg) + (check-arg-form arg + :uniformp t + :target-environment target-environment)) + uniform-variables) (check-for-dups input-variables uniform-variables shared-variables)) @@ -78,10 +91,16 @@ :shared-variables (mapcar λ(make-var 'shared-variable _) shared-variables) :context version/s + :target-environment target-environment + :extensions (mapcar #'make-extension extensions) :lisp-code code :stemcells-allowed stemcells-allowed :primitive-in (%process-primitive-type stage-type primitive)))) + (when (eq target-environment :vulkan) + ;; {TODO} proper error + (assert (intersection version/s '(:440 :450 :460)) () + "Varjo: Target environment Vulkan requires a GLSL version of at least 440.")) (when (equal kind :geometry) ;; {TODO} proper error (assert (intersection version/s '(:150 :330 :400 :410 :420 :430 :440 :450 :460)) () @@ -146,6 +165,8 @@ (uniform-variables nil uv-set) (shared-variables nil sv-set) (context nil c-set) + (target-environment nil env-set) + (extensions nil ext-set) (lisp-code nil lc-set) (previous-stage nil ps-set) (stemcells-allowed nil sa-set) @@ -165,6 +186,12 @@ :context (if c-set context (context stage)) + :target-environment (if env-set + target-environment + (target-environment stage)) + :extensions (if ext-set + extensions + (extensions stage)) :lisp-code (if lc-set lisp-code (lisp-code stage)) @@ -180,6 +207,24 @@ ;;------------------------------------------------------------ +(defun destructure-context (context) + (flet ((check-for-key (ctx key) + (and (listp ctx) + (>= (length ctx) 2) + (eq (first ctx) key)))) + (let ((target-env :opengl) + (extensions nil) + (includes nil)) + (loop for ctx in context + if (keywordp ctx) collect ctx into version/s + if (check-for-key ctx :target-environment) do (setf target-env (second ctx)) + if (check-for-key ctx :extensions) do (setf extensions (cdr ctx)) + if (check-for-key ctx :includes) do (setf includes (cdr ctx)) + finally (return (values version/s + target-env + extensions + includes)))))) + (defun extract-glsl-name (qual-and-maybe-name) (let ((glsl-name (last1 qual-and-maybe-name))) (if (stringp glsl-name) @@ -238,7 +283,10 @@ (list *default-version*))) ;;{TODO} proper error -(defun check-arg-form (arg) +(defun check-arg-form (arg + &key + uniformp + (target-environment :opengl)) (unless (and ;; needs to at least have name and type @@ -253,7 +301,22 @@ (qualifiers (if (stringp (last1 qualifiers)) (butlast qualifiers) qualifiers))) - (every #'keywordp qualifiers))) + (loop :for qualifier-form :in qualifiers + :for qualifier := (first (listify qualifier-form)) + :do (assert (keywordp qualifier) () + "Varjo: Qualifier ~a within declaration ~a is badly formed.~%Should be (-var-name- -var-type- &optional qualifiers) and ~%the arg name may not have the same name as a constant." + qualifier arg) + :when (find qualifier *glsl-vulkan-qualifiers* :key #'first) + :do (assert (eq :vulkan target-environment) () + "Varjo: Qualifier ~a within declaration ~a is only allowed in target environment :vulkan, but not in ~a" + qualifier arg target-environment) + :when (eq qualifier :input-attachment-index) + :do (assert (member (second arg) '(:subpass-input + :subpass-input-ms)) + () + "Varjo: Qualifier ~a within declaration ~a is only allowed for subpass inputs." + qualifier arg target-environment)) + t)) (error "Declaration ~a is badly formed.~%Should be (-var-name- -var-type- &optional qualifiers) and ~%the arg name may not have the same name as a constant." arg)) t) diff --git a/src/varjo.internals/translate.lisp b/src/varjo.internals/translate.lisp index ed7a5f2a..a3649aaa 100644 --- a/src/varjo.internals/translate.lisp +++ b/src/varjo.internals/translate.lisp @@ -466,7 +466,8 @@ (v-dimensions (v-type-of (first expanded-vars)))))))) - (locations (if (typep (stage post-proc-obj) 'vertex-stage) + (locations (if (or (typep (stage post-proc-obj) 'vertex-stage) + (eq :vulkan (target-environment stage))) (calc-locations (mapcar #'v-type-of expanded-vars)) (n-of nil (length expanded-vars)))) (glsl-decls @@ -501,12 +502,19 @@ ;;---------------------------------------------------------------------- (defgeneric gen-stage-locations (stage out-set) + (:method ((stage fragment-stage) out-set) (let ((out-types (type-set-to-type-list out-set))) (calc-locations out-types))) + (:method (stage out-set) - (declare (ignore stage)) - (n-of nil (length out-set)))) + (if (and (eq :vulkan (target-environment stage)) + (stage-where-first-return-is-position-p stage)) + (concatenate 'list + '(nil) + (calc-locations (type-set-to-type-list + (subseq out-set 1)))) + (n-of nil (length out-set))))) (defun gen-out-glsl-decls (stage out-set locations) (loop :for out-val :across out-set @@ -616,7 +624,7 @@ :for glsl-name = (glsl-name uniform) :do (let ((string-name (or glsl-name (safe-glsl-name-string name))) - (layout (find-if #'block-memory-layout-qualfier-p qualifiers))) + (layout (remove-if-not #'memory-layout-qualifier-p qualifiers))) (push (make-instance 'uniform-variable :name name @@ -624,7 +632,9 @@ :type type-obj :glsl-decl (cond ((find :ubo qualifiers :test #'qualifier=) - (assert (not (qualifier= layout :std-430))) + (assert (notany (lambda (q) + (qualifier= q :std-430)) + (listify layout))) (write-ubo-block (parse-qualifier :uniform) string-name (v-slots type-obj) @@ -636,7 +646,8 @@ layout)) ((ephemeral-p type-obj) nil) (t (gen-uniform-decl-string string-name type-obj - qualifiers)))) + qualifiers + layout)))) final-strings))) (loop :for s :in (stemcells post-proc-obj) :do @@ -654,7 +665,8 @@ (gen-uniform-decl-string (or string-name (error "stem cell without glsl-name")) type-obj - nil))) + nil + (remove-if-not #'uniform-memory-layout-qualifier-p (qualifiers type-obj))))) implicit-uniforms) (when (and (v-typep type-obj 'v-user-struct) @@ -713,6 +725,8 @@ :uniform-variables (uniforms post-proc-obj) :shared-variables (shared-variables (stage post-proc-obj)) :context context + :target-environment (target-environment stage) + :extensions (extensions stage) :lisp-code (lisp-code stage) :stemcells-allowed (allows-stemcellsp env) :primitive-in (primitive-in (stage post-proc-obj)) diff --git a/src/varjo.internals/types/early-types.lisp b/src/varjo.internals/types/early-types.lisp index dbe5be97..9936918f 100644 --- a/src/varjo.internals/types/early-types.lisp +++ b/src/varjo.internals/types/early-types.lisp @@ -15,7 +15,9 @@ (default-value :initarg :default-value) (qualifiers :initform nil :initarg :qualifiers :reader qualifiers) (tertiary-score :initform 0 :initarg :tertiary-score - :reader tertiary-score))) + :reader tertiary-score) + (vulkan-onlyp :initform nil :reader vulkan-onlyp) + (allow-unboundp :initform nil :reader allow-unboundp))) ;;------------------------------------------------------------ ;; Core type methods diff --git a/src/varjo.internals/types/types.lisp b/src/varjo.internals/types/types.lisp index 35b7a1c3..a109c6dc 100644 --- a/src/varjo.internals/types/types.lisp +++ b/src/varjo.internals/types/types.lisp @@ -205,6 +205,59 @@ (define-v-type-class v-shadow-type (v-type) ((shadowed-type :initform nil :reader shadowed-type))) +;;------------------------------------------------------------ +;; Vulkan-only Type +;; +;; The supertype for all types which are only allowed in a +;; Vulkan/SPIR-V context. + +(define-v-type-class v-opaque-vulkan-type (v-opaque) + ((vulkan-onlyp :initform t :reader vulkan-onlyp))) + +;;---------------------------------------------------------------------- +;; Sampler (Vulkan only) + +(define-v-type-class v-sampler-type (v-opaque-vulkan-type) + ((element-type :initform 'v-type))) + +;;---------------------------------------------------------------------- +;; Subpass Input (Vulkan only) + +(define-v-type-class v-subpass-input-type (v-opaque-vulkan-type) + ((element-type :initform 'v-type))) + +(defmethod post-initialise ((object v-subpass-input-type)) + (with-slots (element-type) object + (unless (typep element-type 'v-type) + (setf element-type (type-spec->type element-type))))) + +(defmethod v-element-type ((object v-subpass-input-type)) + (let ((result (slot-value object 'element-type))) + ;; {TODO} dedicated error + (assert (typep result 'v-type) (object) + "The element-type of ~a was ~a which is not an instance of a type." + object result) + result)) + +;;---------------------------------------------------------------------- +;; Texture (Vulkan only) + +(define-v-type-class v-texture (v-opaque) + ((element-type :initform 'v-type))) + +(defmethod post-initialise ((object v-texture)) + (with-slots (element-type) object + (unless (typep element-type 'v-type) + (setf element-type (type-spec->type element-type))))) + +(defmethod v-element-type ((object v-texture)) + (let ((result (slot-value object 'element-type))) + ;; {TODO} dedicated error + (assert (typep result 'v-type) (object) + "The element-type of ~a was ~a which is not an instance of a type." + object result) + result)) + ;;------------------------------------------------------------ ;; Sampler diff --git a/varjo.asd b/varjo.asd index 923c6983..fa794907 100644 --- a/varjo.asd +++ b/varjo.asd @@ -24,6 +24,7 @@ (:file "src/varjo.internals/globals") (:file "src/varjo.internals/names") (:file "src/varjo.internals/internal-types") + (:file "src/varjo.internals/extension") (:file "src/varjo.internals/glsl-generation/line-and-chunk") (:file "src/varjo.internals/qualifiers") (:file "src/varjo.internals/types/def-v-core-type")