diff --git a/docs/rendering/index.md b/docs/rendering/index.md index 4607f238..4f7034e5 100644 --- a/docs/rendering/index.md +++ b/docs/rendering/index.md @@ -139,14 +139,13 @@ Textures are objects that contain images. Textures are mostly 2D, but can be 1D or 3D as well. A texture can also contain an array of images or multiple levels where each level has half the resolution of the previous level. -#### Programs +#### Shaders -Programs are objects that contains one or more shaders that are run -on the GPU. +Shaders are objects which contain code that runs on the GPU. #### Framebuffers -A framebuffer is an object that holds the output of a program that ran +A framebuffer is an object that holds the output of a shader that ran on the GPU. Usually it consists of a color buffer and a depth buffer. An application always has at least one framebuffer: the default framebuffer, which is the window of the application. For off-screen rendering, needed @@ -229,10 +228,10 @@ Bind the buffer as an SSBO so that it can be accessed in the vertex shader: Buffer_1.Bind (Shader_Storage, 0); ``` -#### Program +#### Shaders -The third step is to create a program with a vertex shader and a fragment -shader. Save the following vertex shader in `triangle.vert`: +The third step is to create a vertex shader and a fragment shader. +Save the following vertex shader in `triangle.vert`: ```glsl linenums="1" title="triangle.vert" #version 420 core @@ -273,24 +272,24 @@ void main(void) { } ``` -The program is then created as follows: +The shaders are then created as follows: ```ada Location_Shaders : constant Locations.Location_Ptr := Locations.Directories.Create_Location ("."); -Program_1 : Shader_Programs := - (Vertex_Shader => Create_Program (Location_Shaders, Vertex_Shader, "triangle.vert"), - Fragment_Shader => Create_Program (Location_Shaders, Fragment_Shader, "triangle.frag"), +Pipeline_1 : Shader_Objects := + (Vertex_Shader => Create_Shader (Location_Shaders, Vertex_Shader, "triangle.vert"), + Fragment_Shader => Create_Shader (Location_Shaders, Fragment_Shader, "triangle.frag"), others => Empty); ``` `Location_Shader` is an object that loads `triangle.vert` and `triangle.frag` from the current directory. Let's tell -OpenGL that we want to use this program: +OpenGL that we want to bind the shaders in `Pipeline_1`: ```ada -Context.Bind_Shaders (Program_1); +Context.Bind_Shaders (Pipeline_1); ``` #### Framebuffer @@ -335,7 +334,7 @@ and then draw the triangle. Press ++esc++ to close the application. with Orka.Rendering.Buffers; with Orka.Rendering.Drawing; with Orka.Rendering.Framebuffers; - with Orka.Rendering.Programs.Shaders; + with Orka.Rendering.Shaders.Objects; with Orka.Resources.Locations.Directories; with Orka.Windows; @@ -350,16 +349,16 @@ and then draw the triangle. Press ++esc++ to close the application. use Orka.Resources; use Orka.Rendering.Buffers; use Orka.Rendering.Framebuffers; - use all type Orka.Rendering.Programs.Shader_Kind; - use Orka.Rendering.Programs.Shaders; + use all type Orka.Rendering.Shaders.Shader_Kind; + use Orka.Rendering.Shaders.Objects; use Orka; Location_Shaders : constant Locations.Location_Ptr := Locations.Directories.Create_Location ("."); - Program_1 : Shader_Programs := - (Vertex_Shader => Create_Program (Location_Shaders, Vertex_Shader, "triangle.vert"), - Fragment_Shader => Create_Program (Location_Shaders, Fragment_Shader, "triangle.frag"), + Pipeline_1 : Shader_Objects := + (Vertex_Shader => Create_Shader (Location_Shaders, Vertex_Shader, "triangle.vert"), + Fragment_Shader => Create_Shader (Location_Shaders, Fragment_Shader, "triangle.frag"), others => Empty); FB_D : Framebuffer := Create_Default_Framebuffer (Window.Width, Window.Height); @@ -374,7 +373,7 @@ and then draw the triangle. Press ++esc++ to close the application. FB_D.Set_Default_Values ((Color => (0.0, 0.0, 0.0, 1.0), others => <>)); FB_D.Use_Framebuffer; - Context.Bind_Shaders (Program_1); + Context.Bind_Shaders (Pipeline_1); Buffer_1.Bind (Shader_Storage, 0); diff --git a/docs/rendering/programs.md b/docs/rendering/programs.md deleted file mode 100644 index 1dbaba54..00000000 --- a/docs/rendering/programs.md +++ /dev/null @@ -1,138 +0,0 @@ -# Programs - -Programs are objects which run one or more shaders on the GPU. -A shader is a stage of the program that operates on a vertex, some -geometry, or a fragment (a pixel on the screen). -Programs that wish to read or write to buffers and textures arbitrarily -use compute shaders. - -Progams containing vertex and fragment shaders are launched by draw commands, -while programs containing compute shaders are dispatched. - -!!! info - The various objects described on this page are declared in - the package `Orka.Rendering.Programs` and its child packages. - -## Creating a program - -To create a program, call function `Create_Program`, giving it a value of -the type `Module` (defined in the child package `:::ada Modules`): - -```ada -Program_1 : Program := Create_Program (Module_1); -``` - -In this case `Module_1` should contain either a vertex shader and a fragment shader, -or just a compute shader. - -Another way is to create a program from multiple modules by giving `Create_Program` -a value of the type `Module_Array` (also defined in the child package `:::ada Modules`): - -```ada -Program_2 : Program := Create_Program (Modules.Module_Array' - (Module_VS, Module_FS)); -``` - -## Modules - -Modules contain one or more shaders, which are all retrieved from files -or from inline text. -A module is created by the function `Create_Module` from the package -`:::ada Orka.Rendering.Programs.Modules`: - -```ada -Module_1 : Modules.Module := Modules.Create_Module - (Shader_Location, - VS => "tools/gltf.vert", - FS => "tools/gltf.frag") -``` - -In this example `Shader_Location` is a pointer to an object implementing -the interface `Location`. The location object is responsible for retrieving -the files given by the parameters `VS` and `FS` -(for a vertex and fragment shader). -Implementations exist which can read files from a directory or from an archive file. -See [Locations](/resources/locations/) for more information. - -For the example which creates `Program_2`, the modules are created separately using calls to -the function `Create_Module`: - -```ada -Module_VS : Modules.Module := - Modules.Create_Module (Shader_Location, VS => "oversized-triangle.vert"); -``` - -To create a module from text instead of a file, use `Create_Module_From_Sources`: - -```ada -Module_FS : Modules.Module := - Modules.Create_Module_From_Sources (FS => Text_Of_Fragment_Shader); -``` - -This can be useful if you need to programmatically construct a shader. - -## Uniforms - -Programs may contain uniforms. A uniform is a variable that can be read by a shader -and written to from Ada code prior to running the program. -Uniforms should contain a small amount of data. -For a larger amount of data, like a few matrices for cameras, a buffer binded as a UBO can be used. -Very large buffers must be binded as an SSBO. - -A uniform can be retrieved using the function `Uniform`. -It return a type `Uniform` from the child package `:::ada Uniforms`: - -```ada -Uniform_View : Uniforms.Uniform := Program_1.Uniform ("view"); -Uniform_Proj : Uniforms.Uniform := Program_1.Uniform ("proj"); -``` - -In the shader, the uniforms are declared as following: - -```glsl -uniform mat4 view; -uniform mat4 proj; -``` - -and then used in the `main()` function of the shader: - -```glsl -gl_Position = proj * view * some_vertex; -``` - -!!! warning "Retrieving an unused uniform may raise an exception" - If a uniform is defined by a shader, but is unused, retrieving it - may raise the exception `:::ada Uniforms.Uniform_Inactive_Error`. - -### Textures and images - -For textures and images it is sufficient to bind them by calling -`:::ada Orka.Rendering.Textures.Bind`. - -If it is needed to get the uniform of a texture or image so that -it can be verified that the kind and format of the sampler and texture -are compatible, call the functions `Uniform_Sampler` or `Uniform_Image`: - -```ada -Uniform_Texture : Uniforms.Uniform_Sampler := - Program_1.Uniform_Sampler ("diffuseTexture"); -``` - -Type `Uniform_Sampler` provides the procedure `Verify_Compatibility` to -verify the kind and format: - -```ada -Uniform_Texture.Verify_Compatibility (Texture_1); -``` - -## Using a program - -To use a program before executing a rendering command, call the -procedure `Use_Program`: - -```ada -Program_1.Use_Program; -``` - -After a program has been made active, rendering commands can be issued -to render to a framebuffer. diff --git a/docs/rendering/shaders.md b/docs/rendering/shaders.md new file mode 100644 index 00000000..40107536 --- /dev/null +++ b/docs/rendering/shaders.md @@ -0,0 +1,162 @@ +# Shaders + +Shaders are programs running a single stage of the graphics or compute +pipeline on the GPU. They operate on a vertex, some geometry, or a +fragment (a pixel on the screen). +Compute shaders, which form the the one and only stage of a compute pipeline, +can read or write to buffers and textures arbitrarily. + +Pipelines containing vertex and fragment shaders are launched by draw commands, +while pipelines containing compute shaders are dispatched. + +!!! info + The various objects described on this page are declared in + the package `Orka.Rendering.Shaders` and its child packages. + +## Creating a shader + +To create a shader, call the function `Create_Shader` in the child package `:::ada Objects`, +giving it the desired shader kind, and the path to a file in the given location: + +```ada +Pipeline_1 : Shader_Objects := + (Vertex_Shader => Create_Shader (Location_Shaders, Vertex_Shader, "example.vert"), + Fragment_Shader => Create_Shader (Location_Shaders, Fragment_Shader, "example.frag"), + others => Empty); +``` + +In this case `Pipeline_1` contains a vertex and a fragment shader. +Leave unused stages of the pipeline empty by using the function `Empty` +in the child package `:::Objects`. + +There are 4 ways to create a shader: + +1. From a file by using the function `Create_Shader`. + +2. From multiple files by using the function `Create_Shader_From_Files`. In this case + the parameter `Paths` must be given an array of pointers to `aliased constant String`, + each containing the path to a file. + +3. From source text by using the function `Create_Shader_From_Source`. This function is useful + if you need to programmatically construct the text of a shader. + +4. From one or more modules by using the function `Create_Shader`, giving it a value + of the type `Shader_Module_Array` (defined in the child package `:::ada Modules`), + which is an array of `Shader_Module`. Each module contains a part of the shader + and can be created from a file or from text. + +## Modules + +A module can be created from one or more files or from text. This allows you to create a shader +whose code comes partially from files and partially from text. +This can be useful if you need to programmatically construct a shader. + +A `Shader_Module` can be created by calling one of the appropriate functions +from the child package `:::ada Modules`. For example: + +```ada +Module_1 : Shader_Module_Array := Create_Modules + (Shader_Location, Fragment_Shader, [File_1'Access, File_2'Access]); +``` + +where `File_1` and `File_2` are each an `aliased constant String` containing the path to a file. + +In this example `Shader_Location` is a pointer to an object implementing +the interface `Location`. The location object is responsible for retrieving +the files given in the array. +Implementations exist which can read files from a directory or from an archive file. +See [Locations](/resources/locations/) for more information. + +There are 3 ways to create module: + +1. From a file by using the function `Create_Module`. + This function returns a `Shader_Module`. + +2. From multiple files by using the function `Create_Modules`. In this case + the parameter `Paths` must be given an array of pointers to `aliased constant String`, + each containing the path to a file. + This function returns a `Shader_Module_Array`, not a single `Shader_Module`. + +3. From source text by using the function `Create_Module_From_Source`. This function is useful + if you need to programmatically construct the text of a shader. + This function returns a `Shader_Module`. + +After one or more modules have been created, use the function `Create_Shader` in the child +package `:::ada Objects` to create the actual shader. + +!!! note "Use modules only if the code comes from files *and* text" + If a shader's code comes from only one or more files, or only from + source text, then just use the functions in the child package `:::ada Objects` + to create a shader. In that case there is no need to create modules first. + +## Uniforms + +Shaders may contain uniforms. A uniform is a variable that can be read by a shader +and written to from Ada code prior to running the shaders of a pipeline. +Uniforms should contain a small amount of data. +For a larger amount of data, like a few matrices for cameras, a buffer binded +as a [UBO](/rendering/buffers/#ubo) can be used. +Very large buffers must be binded as an [SSBO](/rendering/buffers/#ssbo). + +A uniform can be retrieved using the function `Uniform`. +It return a type `Uniform` from the child package `:::ada Uniforms`: + +```ada +Uniform_View : Uniform := Pipeline_1 (Vertex_Shader).Value.Uniform ("view"); +Uniform_Proj : Uniform := Pipeline_1 (Vertex_Shader).Value.Uniform ("proj"); +``` + +In the shader, the uniforms are declared as following: + +```glsl +uniform mat4 view; +uniform mat4 proj; +``` + +and then used in the `main()` function of the shader: + +```glsl +gl_Position = proj * view * some_vertex; +``` + +!!! warning "Retrieving an unused uniform may raise an exception" + If a uniform is defined by a shader, but is unused, retrieving it + may raise the exception `:::ada Uniforms.Uniform_Inactive_Error`. + +!!! tip "Use a UBO for multi-stage uniforms" + If a uniform is used in multiple stages, then multiple `Uniform` objects + should be created and given a value. + In this case it can be easier to create a buffer and bind it as a [UBO](/rendering/buffers/#ubo). + +### Textures and images + +For textures and images it is sufficient to bind them by calling +`:::ada Orka.Rendering.Textures.Bind`. + +If it is needed to get the uniform of a texture or image so that +it can be verified that the kind and format of the sampler and texture +are compatible, call the functions `Uniform_Sampler` or `Uniform_Image`: + +```ada +Uniform_Texture : Uniform_Sampler := + Pipeline_1 (Fragment_Shader).Value.Uniform_Sampler ("diffuseTexture"); +``` + +Type `Uniform_Sampler` provides the procedure `Verify_Compatibility` to +verify the kind and format: + +```ada +Uniform_Texture.Verify_Compatibility (Texture_1); +``` + +## Using a set of shaders + +To use a set of shaders stored in a `Shader_Objects` array before executing +a rendering command, call the procedure `Bind_Shaders` of the current `Context`: + +```ada +Context.Bind_Shaders (Pipeline_1); +``` + +After a set of shaders have been made active, rendering commands can be issued +to render to a framebuffer. diff --git a/mkdocs.yml b/mkdocs.yml index 4d73545d..72d95b63 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -92,23 +92,12 @@ nav: - Getting started: - Installation: installation.md - Documentation: - - Parallel programming: parallel-programming.md - - Containers: containers.md - - Logging: logging.md - - Windows and input: - - Introduction: windows-input/index.md - - Windows: windows-input/windows.md - - Monitors: windows-input/monitors.md - - Drag and drop: windows-input/drag-and-drop.md - - Clipboard: windows-input/clipboard.md - - Pointer and keyboard: windows-input/pointer-keyboard.md - - Gamepads: windows-input/gamepads.md - Rendering: - Introduction: rendering/index.md - Contexts: rendering/contexts.md - Buffers: rendering/buffers.md - Vertex formats: rendering/vertex-formats.md - - Programs: rendering/programs.md + - Shaders: rendering/shaders.md - Textures: rendering/textures.md - Framebuffers: rendering/framebuffers.md - Frame graph: rendering/frame-graph.md @@ -116,6 +105,14 @@ nav: - Effects: rendering/effects.md - Timers: rendering/timers.md - Removed features: rendering/removed-features.md + - Windows and input: + - Introduction: windows-input/index.md + - Windows: windows-input/windows.md + - Monitors: windows-input/monitors.md + - Drag and drop: windows-input/drag-and-drop.md + - Clipboard: windows-input/clipboard.md + - Pointer and keyboard: windows-input/pointer-keyboard.md + - Gamepads: windows-input/gamepads.md - Computing: - Introduction: computing/index.md - Algorithms: computing/algorithms.md @@ -138,6 +135,10 @@ nav: - Indexing: numerics/tensors/indexing.md - Statistics: numerics/tensors/statistics.md - Filtering: numerics/filtering.md + - Other: + - Parallel programming: parallel-programming.md + - Containers: containers.md + - Logging: logging.md - Plug-ins: - Archives: plugins/archives.md - Atmosphere: plugins/atmosphere.md