Selaa lähdekoodia

More work on developer manuals

BearishSun 8 vuotta sitten
vanhempi
sitoutus
c1e8500a49

+ 152 - 46
Documentation/Manuals/Native/gpuPrograms.md

@@ -2,23 +2,18 @@ GPU programs									{#gpuPrograms}
 ===============
 [TOC]
 
-GPU programs are programmable parts of the GPU pipeline, in other literature often called shaders (Banshee uses the word shader for a higher level concept, see the [material](@ref materials) manual).
+GPU programs are programmable parts of the GPU pipeline, in other literature often called shaders (Banshee uses the word shader for a higher level concept, so we won't call them that). They are core objects, meaning they can be used on both sim and core threads. We'll focus on the core thread version and note the differences between the two where relevant.
 
-GPU programs in Banshee are represented with the @ref bs::GpuProgram "GpuProgram" and @ref bs::ct::GpuProgram "ct::GpuProgram" classes. Both of these provide almost equivalent functionality, but the former is for use on the simulation thread, and the latter is for use on the core thread. If you are confused by the dual nature of the objects, read the [core thread](@ref coreThread) manual. 
+In Banshee they are represented with the @ref bs::ct::GpuProgram "ct::GpuProgram" class. There are six types of GPU programs: vertex, hull (tesselation control), domain (tesselation evaluation), geometry, fragment (pixel) and compute programs. Each is used for a different purpose but has the same interface. We assume the user is familiar with the GPU pipeline and what the different program types do. 
 
-In this manual we will focus on the simulation thread implementation, and then note the differences in the core thread version at the end.
-
-There are six types of GPU programs: vertex, hull (tesselation control), geometry, domain (tesselation evaluation), fragment (pixel) and compute programs. Each is used for a different purpose but has the same interface. We assume the user is familiar with the GPU pipeline and what the different programs types do. 
-
-Although GPU programs can be used on their own (which we will cover in this manual), they are more commonly used as parts of @ref bs::Shader "Shaders". Read the [material](@ref materials) manual for more information.
+> Note that if you are using Banshee Shading Language you do not need to create GPU programs manually - any shaders you import and materials created from those shaders will have GPU programs created internally, but they will be hidden from the normal user.
 
 # Creating GPU programs {#gpuPrograms_a}
-To create a GPU program call @ref bs::GpuProgram::create() "GpuProgram::create". This method expects the following parameters:
- - Source code of the GPU program. This should be in a language supported by the current render API (e.g. HLSL for DirectX, GLSL for OpenGL).
- - Name of the entry point into the GPU program. This is the name of the function that will be called when the program is ran. Must be "main" for OpenGL.
- - Language the source code is written in. This can be "hlsl" or "glsl" by default, but more languages can be added by extensions.
- - @ref bs::GpuProgramType "Type" of the GPU program (vertex, fragment, etc.).
- - @ref bs::GpuProgramProfile "Profile" of the GPU program. Determines what functionality does the underyling hardware support. Nowadays it is safe to always set this to profile 5.0 unless creating programs for very old hardware.
+To create a GPU program call @ref bs::ct::GpuProgram::create() "ct::GpuProgram::create()" with a @ref bs::GPU_PROGRAM_DESC "GPU_PROGRAM_DESC" structure. The structure needs to have the following fields populated:
+ - @ref bs::GPU_PROGRAM_DESC::source "GPU_PROGRAM_DESC::source" - Source code of the GPU program. This should be in a language supported by the current render API (e.g. HLSL for DirectX, GLSL for OpenGL/Vulkan).
+ - @ref bs::GPU_PROGRAM_DESC::entryPoint "GPU_PROGRAM_DESC::entryPoint" - Name of the entry point into the GPU program. This is the name of the function that will be called when the program is ran. Must be "main" for OpenGL & Vulkan.
+ - @ref bs::GPU_PROGRAM_DESC::language "GPU_PROGRAM_DESC::language" - Language the source code is written in. This can be "hlsl" or "glsl".
+ - @ref bs::GPU_PROGRAM_DESC::type "GPU_PROGRAM_DESC::type" - @ref bs::GpuProgramType "GpuProgramType" of the GPU program (vertex, fragment, etc.).
  
 For example if we wanted to create a HLSL fragment program (HLSL source not shown):
 ~~~~~~~~~~~~~{.cpp}
@@ -29,23 +24,38 @@ desc.type = GPT_FRAGMENT_PROGRAM;
 desc.source = hlslSource;
 desc.entryPoint = "main";
 desc.language = "hlsl";
-desc.profile = GPP_FS_5_0;
 
 SPtr<GpuProgram> myProgram = GpuProgram::create(desc);
 ~~~~~~~~~~~~~ 
  
-Once the GPU program has been created it is not guaranteed to be usable. The compilation of the provided source code could have failed, which you can check by calling @ref bs::GpuProgram::isCompiled() "GpuProgram::isCompiled", and retrieve the error message by calling @ref bs::GpuProgram::getCompileErrorMessage() "GpuProgram::getCompileErrorMessage". Be aware that both of these methods are only valid after the core thread has initialized the object. You can ensure this by calling @ref bs::CoreObject::blockUntilCoreInitialized "GpuProgram::blockUntilCoreInitialized" but be aware this will block the calling thread which can result in a significant performance impact.
+Once the GPU program has been created it is not guaranteed to be usable. The compilation of the provided source code could have failed, which you can check by calling @ref bs::ct::GpuProgram::isCompiled() "ct::GpuProgram::isCompiled()", and retrieve the error message by calling @ref bs::ct::GpuProgram::getCompileErrorMessage() "ct::GpuProgram::getCompileErrorMessage()". 
+
+~~~~~~~~~~~~~{.cpp}
+if(!myProgram->isCompiled())
+	gDebug().logError("GPU program compilation failed with error: " + myProgram->getCompileErrorMessage());
+~~~~~~~~~~~~~ 
+
+Be aware that shader compilation happens on the core thread. Therefore if calling these methods on the sim thread GPU program, you must first ensure the GPU program is initialized by calling **CoreThread::submit()** with @p blockUntilComplete parameter set to true, or use the core-object-specific method @ref bs::CoreObject::blockUntilCoreInitialized "GpuProgram::blockUntilCoreInitialized()".
+
+~~~~~~~~~~~~~{.cpp}
+// If program is used on sim thread
+myProgram->blockUntilCoreInitialized();
+
+if(!myProgram->isCompiled())
+	gDebug().logError("GPU program compilation failed with error: " + myProgram->getCompileErrorMessage());
+~~~~~~~~~~~~~ 
 
 # Using GPU programs for rendering {#gpuPrograms_b}
-To use a GPU program in a draw or dispatch call, you must first create a GPU pipeline object using the relevant GPU programs.
+To use a GPU program in a draw or dispatch call, you must first create a GPU pipeline object using the relevant GPU programs. There are two types of pipeline states:
+ - @ref bs::ct::GraphicsPipelineState "ct::GraphicsPipelineState" - Supports vertex, hull, domain, geometry and fragment programs. At minimum requires a vertex program, while most pipelines will use vertex & fragment programs.
+ - @ref bs::ct::ComputePipelineState "ct::ComputePipelineState" - Supports only the compute GPU program type.
 
-There are two types of pipeline objects: @ref bs::GraphicsPipelineState "GraphicsPipelineState" and @ref bs::ComputePipelineState "ComputePipelineState".
+To create a graphics pipeline you need to fill out the @ref bs::ct::PIPELINE_STATE_DESC "ct::PIPELINE_STATE_DESC" structure with references to relevant GPU programs, followed by a call to @ref bs::ct::GraphicsPipelineState::create() "ct::GraphicsPipelineState::create()".
 
-Example to create a graphics pipeline:
 ~~~~~~~~~~~~~{.cpp}
 PIPELINE_STATE_DESC desc;
-desc.vertexProgram = ...
-desc.fragmentProgram = ...;
+desc.vertexProgram = ...;
+desc.fragmentProgram = myProgram; // Program we created in the example above
 desc.geometryProgram = ...;
 desc.hullProgram = ...;
 desc.domainProgram = ...;
@@ -53,63 +63,157 @@ desc.domainProgram = ...;
 SPtr<GraphicsPipelineState> graphicsPipeline = GraphicsPipelineState::create(desc);
 ~~~~~~~~~~~~~
 
-Example to create a compute pipeline:
+> Note that graphics pipelines also support a set of fixed (non-programmable) states we'll discuss later.
+ 
+Compute pipeline states are simpler, accepting just a single compute GPU program as a parameter to their @ref bs::ct::ComputePipelineState::create() "ct::ComputePipelineState::create()" method.
+
 ~~~~~~~~~~~~~{.cpp}
 SPtr<GpuProgram> computeProgram = ...;
 SPtr<ComputePipelineState> computePipeline = ComputePipelineState::create(computeProgram);
 ~~~~~~~~~~~~~
 
-Once created the pipeline can be bound for rendering by calling @ref bs::ct::RenderAPI::setGraphicsPipeline "ct::RenderAPI::setGraphicsPipeline" or @ref bs::RenderAPI::setComputePipeline "RenderAPI::setComputePipeline".
+Once created pipelines can be bound for rendering through the globally accessible @ref bs::ct::RenderAPI "ct::RenderAPI" interface. This interface is the primary entry point in the low-level rendering API and it will be used for most low-level rendering operations, as we'll see throughout this set of manuals.
+
+Call @ref bs::ct::RenderAPI::setGraphicsPipeline "ct::RenderAPI::setGraphicsPipeline()" or @ref bs::ct::RenderAPI::setComputePipeline "ct::RenderAPI::setComputePipeline()" to bind a graphics or a compute pipeline state, respectively.
 
 ~~~~~~~~~~~~~{.cpp}
-// Bind pipeline for use (continued from above)
+// Bind pipeline for use
 
 RenderAPI& rapi = RenderAPI::instance();
 rapi.setGraphicsPipeline(graphicsPipeline);
 // Or: rapi.setComputePipeline(computePipeline);
 ~~~~~~~~~~~~~
 
-Once pipeline state is bound, any subsequent draw/dispatch calls will then use the GPU programs attached to that state. 
-
-Much more detailed information about pipelines and rendering is provided in the [render API manual](@ref renderAPI).
+Once bound any *draw* or *dispatch* calls will be executed using the bound pipeline states. Draw/dispatch calls are explained in more detail later on.
 
 # GPU program parameters {#gpuPrograms_c}
-Although you can use a GPU program without any parameters, most will require some additional data in order to perform their operations. Program parameters represent data that is static throughout a single GPU program execution (e.g. a draw call). For example, when drawing a 3D object you will usually want to provide a projection matrix that transforms the object from 3D to 2D, according to the camera the user is viewing the object through.
+Although you can use a GPU program without any parameters, most will require some additional data in order to perform their operations. Program parameters represent data that is static throughout a single GPU program execution (a draw/dispatch call). For example, when drawing a 3D object you will usually want to provide a projection matrix that transforms the object from 3D to 2D, according to the camera the user is viewing the object through.
+
+You can access information about GPU program parameters by calling @ref bs::ct::GpuProgram::getParamDesc "ct::GpuProgram::getParamDesc()". This will return a @ref bs::GpuParamDesc "GpuParamDesc" structure containing information about all GPU parameters used by that GPU program. This includes primitives (int, float, etc.), textures, samplers, buffers and parameter buffers (constant/uniform buffers in DirectX/OpenGL lingo). 
 
-You can access information about GPU program parameters by calling @ref bs::GpuProgram::getParamDesc "GpuProgram::getParamDesc". This will return a structure containing information about all GPU parameters used by that GPU program. This includes primitives (int, float, etc.), textures, samplers, buffers and parameter buffers (constant/uniform buffers in DirectX/OpenGL lingo). 
+You generally don't need to use this information directly. It is instead automatically parsed when you create a GPU pipeline. Once you have a pipeline you can use it to create a @ref bs::ct::GpuParams "ct::GpuParams" object that allows you to assign values to all parameters of a specific pipeline.
 
-You generally don't need to use this information directly. It is instead automatically parsed when you create a GPU pipeline. Once you have a pipeline you can use it to create a *GpuParams* object that allows you to assign values to all parameters of a specific pipeline.
+## GpuParams {#gpuPrograms_c_a}
+**GpuParams** is a container for all parameters required by a single GPU pipeline (graphics or compute). It allows you to set primitive/texture/sampler/buffer parameters used by the GPU programs, which it stores in an internal buffer. You can then bind it
+to a **RenderAPI** similar to how you bind the pipeline themselves. Assigned parameter will then be using with the current pipeline in any following *draw* or *dispatch* calls.
 
-## GpuParams {#gpuPrograms_b_a}
-@ref bs::GpuParams "GpuParams" is a container for all parameters required by a single GPU pipeline (graphics or compute). It allows you to set primitive/texture/sampler/buffer parameters used by the GPU programs, which it stores in an internal buffer. You can then bind it before executing at draw/dispatch call, and the assigned parameters will be used by GPU programs in the current pipeline.
+To create a **GpuParams** object call @ref bs::ct::GpuParams::create "ct::GpuParams::create()" with either a graphics or a compute pipeline state as a parameter.
 
-For example to assign a texture and a 2D vector as input to the program we created earlier:
 ~~~~~~~~~~~~~{.cpp}
 SPtr<GraphicsPipelineState> graphicsPipeline = ...;
 SPtr<GpuParams> params = GpuParams::create(graphicsPipeline);
+~~~~~~~~~~~~~
+
+Once created you can assign values to parameter by calling any of the following methods (depending on parameter type):
+ - @ref bs::ct::GpuParams::setTexture(GpuProgramType, const String&, const TextureType&, const TextureSurface&) "ct::GpuParams::setTexture()" - Assigns a read-only (sampled) texture to a GPU program.
+ - @ref bs::ct::GpuParams::setLoadStoreTexture(GpuProgramType, const String&, const TextureType&, const TextureSurface&) "ct::GpuParams::setLoadStoreTexture()" - Assign a load-store (writable) texture to a GPU program.
+ - @ref bs::ct::GpuParams::setBuffer(GpuProgramType, const String&, const BufferType&) "ct::GpuParams::setBuffer()" - Assigns a buffer (either read-only or read-write) to a GPU program.
+ - @ref bs::ct::GpuParams::setSamplerState(GpuProgramType, const String&, const SamplerType&) "ct::GpuParams::setSamplerState()" - Assigns a sampler state that determines how is a sampled texture read by the shader.
+ - @ref bs::ct::GpuParams::setParam<T>(GpuProgramType, const String&, const T&) "ct::GpuParams::setParam()" - Assigns a primitive type like *float*, *int*, **Vector3**, **Matrix4** or others. Supported primitive types are:
+  - *float*
+  - **Vector2**
+  - **Vector3**
+  - **Vector4**
+  - *int*
+  - **Vector2I**
+  - **Vector3I**
+  - **Vector4I**
+  - **Matrix3**
+  - **Matrix4**
+  - **Color** (maps to 4-component float in GPU program, same as **Vector4**)
+ 
+Each of the methods accepts a **GpuProgramType** of the program whose parameter to assign, name of the parameter (as specified in the GPU program code) and a value of the parameter.
+
+~~~~~~~~~~~~~{.cpp}
+Matrix4 viewProjMat = ...;
+params->setParam(GPT_VERTEX_PROGRAM, "vertProjMatrix", viewProjMat);
+
+SPtr<Texture> someTexture = ...;
+params->setTexture(GPT_FRAGMENT_PROGRAM, "mainTexture", someTexture);
+~~~~~~~~~~~~~
 
-// Retrieve GPU param handles we can then read/write to
-GpuParamVec2 myVectorParam;
+If parameters are modified often you can instead use *parameter handles* for faster access. Use the following methods to retrieve a handle to the parameter:
+ - @ref bs::ct::GpuParams::getTextureParam "ct::GpuParams::getTextureParam()" - Outputs a @ref bs::TGpuParamTexture<Core> "GpuParamTexture" handle that can be used for reading & writing the parameter value.
+ - @ref bs::ct::GpuParams::getLoadStoreTextureParam "GpuParams::getLoadStoreTextureParam()" - Outputs a @ref bs::TGpuParamLoadStoreTexture<Core> "ct::GpuParamLoadStoreTexture" handle that can be used for reading & writing the parameter value.
+ - @ref bs::ct::GpuParams::getBufferParam "ct::GpuParams::getBufferParam()" - Outputs a @ref bs::TGpuParamBuffer<Core> "GpuParamBuffer" handle that can be used for reading & writing the parameter value.
+ - @ref bs::ct::GpuParams::getSamplerStateParam "ct::GpuParams::getSamplerStateParam()" - Outputs a @ref bs::TGpuParamSampState<Core> "GpuParamSampState" handle that can be used for reading & writing the parameter value.
+ - @ref bs::ct::GpuParams::getParam<T> "ct::GpuParams::getParam<T>()" - Outputs a @ref bs::TGpuDataParam<Core, T> "TGpuDataParam<T>" handle that can be used for reading & writing the parameter value.
+
+Each of the methods accepts a **GpuProgramType** of the program whose parameter to assign, name of the parameter (as specified in the GPU program code), and outputs a handle to the parameter as specified above. Handles provide **set()** and **get()** methods that can be used for writing and reading the parameter values.
+ 
+~~~~~~~~~~~~~{.cpp}
+// Same result as above, only using handles
+GpuParamMat4 myMatParam;
 GpuParamTexture myTextureParam;
 
-params->getParam(GPT_FRAGMENT_PROGRAM, "myVector", myVectorParam); // Assuming "myVector" is the variable name in the program source code
-params->getTextureParam(GPT_FRAGMENT_PROGRAM, "myTexture", myTextureParam); // Assuming "myTexture" is the variable name in the program source code
+params->getParam(GPT_VERTEX_PROGRAM, "vertProjMatrix", myMatParam);
+params->getTextureParam(GPT_FRAGMENT_PROGRAM, "mainTexture", myTextureParam);
 
-myVectorParam.set(Vector2(1, 2));
-myTextureParam.set(myTexture); // Assuming we created "myTexture" earlier.
+Matrix4 viewProjMat = ...;
+SPtr<Texture> someTexture = ...;
+
+myVectorParam.set(viewProjMat);
+myTextureParam.set(someTexture);
+~~~~~~~~~~~~~
+
+Parameter handles can be retrieved once and stored, then used for quick access to the parameter without an otherwise expensive lookup that happens when setting parameter directly.
+
+## Parameter blocks {#gpuPrograms_c_b}
+All primitive (*int*, *float*, **Vector3**, etc.) GPU parameters are grouped in parameter blocks - each GPU program must have at least one. These are better known as *constant buffers* in DirectX or *uniform blocks* in OpenGL/Vulkan. 
+
+Before we can assign primitive parameters to **GpuParams** we must first allocate their parameter blocks (in the examples above we skipped this step). Parameter blocks are represented by @ref bs::ct::GpuParamBlockBuffer "ct::GpuParamBlockBuffer". They are essentially just blocks of memory and only require a size in bytes in their call to @ref bs::ct::GpuParamBlockBuffer::create() "ct::GpuParamBlockBuffer::create()".
+
+~~~~~~~~~~~~~{.cpp}
+// Buffer with 256 bytes in size
+SPtr<GpuParamBlockBuffer> buffer = GpuParamBlockBuffer::create(256);
+~~~~~~~~~~~~~
+
+You can find out which parameter blocks (and their sizes) a GPU program contains from its **GpuParamDesc** structure retrieved from **GpuProgram::getParamDesc()**.
+
+~~~~~~~~~~~~~{.cpp}
+// Create the first available parameter block, with adequate size to fit all of its fields
+SPtr<GpuParamDesc> paramDesc = myProgram->getParamDesc();
+
+SPtr<GpuParamBlockBuffer> buffer;
+if(paramDesc.paramBlocks.size() > 0)
+{
+	UINT32 sizeBytes = paramDesc.paramBlocks[0].blockSize * 4; // Block size is in multiples of 4 bytes
+	buffer = GpuParamBlockBuffer::create(sizeBytes);
+}
+~~~~~~~~~~~~~
+
+Finally you can bind the parameter block to **GpuParams** by calling @ref bs::ct::GpuParams::setParamBlockBuffer "ct::GpuParams::setParamBlockBuffer()" with the GPU program type, parameter block variable name, and the parameter block buffer.
+
+~~~~~~~~~~~~~{.cpp}
+params->setParamBlockBuffer(GPT_FRAGMENT_PROGRAM, "myParamBlock", buffer);
+~~~~~~~~~~~~~
+
+After it is bound you we free to set primitive parameters and they will be stored in the bound buffer. This buffer can then be shared between multiple GPU programs and/or GPU pipelines.
+
+> You can also write to **GpuParamBlockBuffer** directly by calling its @ref bs::ct::GpuParamBlockBuffer::write "ct::GpuParamBlockBuffer::write()" method. In this case you must be careful to respect the layout of the variables in the buffer as expected by the shader. This layout can be determined by examining the other entries in **GpuParamDesc** structure.
+
+## Binding GPU params {#gpuPrograms_c_c}
+Once **GpuParams** has been created and populated with necessary data, you can bind it to the GPU by calling @ref bs::ct::RenderAPI::setGpuParams "ct::RenderAPI::setGpuParams()". 
+
+~~~~~~~~~~~~~{.cpp}
+// This should be called after the pipeline expecting these parameters is bound
+RenderAPI::instance().setGpuParams(params);
 ~~~~~~~~~~~~~
 
-As you can see we must first retrieve a handle to the parameter, and then we can use that handle for reading/writing to the parameter. You can store those handles for easier access to the parameters, as looking them up by using the parameter name can be relatively slow.
+# Vertex input {#gpuPrograms_d}
+Vertex GPU programs provide information about their inputs in the form of a **VertexDeclaration**. This is the same structure that we used for describing per-vertex components while creating a mesh. Per-vertex input declaration can be retrieved from a GPU program by calling @ref bs::ct::GpuProgram::getInputDeclaration "ct::GpuProgram::getInputDeclaration()".
 
-See the [render API manual](@ref renderAPI) for more information about how to set and bind GPU program parameters.
+~~~~~~~~~~~~~{.cpp}
+SPtr<GpuProgram> vertProg = ...;
+SPtr<VertexDeclaration> inputs = vertProg->getInputDeclaration();
+~~~~~~~~~~~~~
 
-# Core thread GPU programs {#gpuPrograms_e}
-So far we have only talked about the simulation thread @ref bs::GpuProgram "GpuProgram" but have ignored the core thread @ref bs::ct::GpuProgram "ct::GpuProgram". The functionality between the two is mostly the same, with the major difference being that operations performed on the core thread version are immediate. So calls to @ref bs::ct::GpuProgram::isCompiled() "ct::GpuProgram::isCompiled" and @ref bs::ct::GpuProgram::getCompileErrorMessage() "ct::GpuProgram::getCompileErrorMessage" don't require any waiting.
+Input declaration can be used for creating meshes or vertex buffers that provide per-vertex information that a GPU program expects.
 
-Addtionally the core thread object can provide information about vertex input declaration. Vertex input declaration is only available for vertex shaders, and it defines in what format does the GPU program expect vertices to be in. This can be useful for setting up your meshes in the valid format. Use @ref bs::ct::GpuProgram::getInputDeclaration "ct::GpuProgram::getInputDeclaration" to retrieve the @ref bs::ct::VertexDeclaration "ct::VertexDeclaration". Check out the [mesh](@ref meshes) manual for more information on how to use vertex declarations.
+> Note: This method is only available on the core thread version of **GpuProgram**.
 
-# OpenGL specifics {#gpuPrograms_f}
-When creating vertex inputs for a GPU program written in GLSL a set of built-in variables are provided:
+## GLSL specifics {#gpuPrograms_d_a}
+When declaring vertex inputs for a GPU program written in GLSL you should use the following variable names depending on the input usage:
  - bs_position - Vertex position
  - bs_normal - Vertex normal
  - bs_tangent - Vertex tangent
@@ -119,4 +223,6 @@ When creating vertex inputs for a GPU program written in GLSL a set of built-in
  - bs_blendweights - Blend weights used for skinning
  - bs_blendindices - Blend indices used for skinning
  
-You can append 0-8 to the names to receive more than one element of the same name. For HLSL the standard HLSL semantics are used instead. Actual types of these elements, as well as the data stored by them doesn't need to match the names and it's up to the user to provide whatever data he needs.
+This allows the system to map the semantics specified in **VertexDeclaration** of the bound mesh or vertex buffer to the GPU program inputs. This is not required for HLSL as HLSL has built-in support for semantics which are used instead. 
+ 
+You can append 0-8 to the names to receive more than one element of the same name. Actual types of these elements, as well as the data stored by them doesn't need to match the names and it's up to the user to provide whatever data he needs.

+ 7 - 1
Documentation/Manuals/Native/manuals.md

@@ -76,7 +76,13 @@ A set of manuals covering advanced functionality intented for those wanting to e
 - **Low level rendering API**
  - [Core thread](@ref coreThread)
  - [GPU programs](@ref gpuPrograms)
- - [Render API](@ref renderAPI)
+ - [Non-programmable states](@ref nonProgrammableStates)
+ - [Load-store textures](@ref loadStoreTextures)
+ - [Vertex & index buffer](@ref vertexIndexBuffers)
+ - [Generic buffers](@ref genericBuffers)
+ - [Drawing](@ref drawing)
+ - [Compute](@ref compute)
+ - [Command buffers](@ref commandBuffers)
 
 ## General guides
 Name                                      | Description

+ 63 - 0
Documentation/Manuals/Native/nonProgrammableStates.md

@@ -0,0 +1,63 @@
+Non-programmable states									{#nonProgrammableStates}
+===============
+[TOC]
+
+When creating a **GraphicsPipelineState** and filling out a **PIPELINE_STATE_DESC** you can provide it with a set of non-programmable states, along with GPU programs. These states control the non-programmable (fixed) parts of the GPU pipeline which control rasterization, depth/stencil and blending.
+
+~~~~~~~~~~~~~{.cpp}
+PIPELINE_STATE_DESC desc;
+// Bind GPU programs
+desc.rasterizerState = ...;
+desc.depthStencilState = ...;
+desc.blendState = ...;
+
+SPtr<GraphicsPipelineState> graphicsPipeline = GraphicsPipelineState::create(desc);
+~~~~~~~~~~~~~
+
+There are three non-programmable state objects in total:
+ - @ref bs::ct::RasterizerState "ct::RasterizerState"
+ - @ref bs::ct::DepthStencilState "ct::DepthStencilState"
+ - @ref bs::ct::BlendState "ct::BlendState"
+ 
+> If using Banshee Shading Language you can specify these states directly in a BSL file and should have no need to create them manually. 
+ 
+# Rasterizer state {#nonProg_a}
+Rasterizer state allows you to control how are 3D polygons, lines or points converted to 2D pixels. You can create it by filling out the @ref bs::RASTERIZER_STATE_DESC "RASTERIZER_STATE_DESC" structure and passing it to @ref bs::ct::RasterizerState::create "ct::RasterizerState::create()".
+
+~~~~~~~~~~~~~{.cpp}
+// Draw wireframe geometry with no backface culling
+RASTERIZER_STATE_DESC desc;
+desc.polygonMode = PM_WIREFRAME; // Draw wireframe instead of solid
+desc.cullMode = CULL_NONE; // Disable blackface culling
+
+SPtr<RasterizerState> rasterizerState = RasterizerState::create(desc);
+~~~~~~~~~~~~~
+
+# Depth-stencil state {#nonProg_b}
+Depth-stencil state allows you to control how are depth and/or stencil buffers modified during rendering. You can create it by filling out the @ref bs::DEPTH_STENCIL_STATE_DESC "DEPTH_STENCIL_STATE_DESC" structure and passing it to @ref bs::ct::DepthStencilState::create "ct::DepthStencilState::create()".
+
+~~~~~~~~~~~~~{.cpp}
+// Draw with no depth testing or writing, and with a stencil operation that writes 1 for each sample written
+DEPTH_STENCIL_STATE_DESC desc;
+desc.depthReadEnable = false; // Don't test against current contents of depth buffer
+desc.depthWriteEnable = false; // Don't make any changes to depth buffer
+desc.stencilEnable = true; // Enable stencil operations
+desc.frontStencilPassOp = SOP_INCREMENT; // Increment by one whenever a front-face stencil operation passes
+desc.frontStencilComparisonFunc = CMPF_ALWAYS_PASS; // Always pass the stencil operation
+
+SPtr<DepthStencilState> depthStencilState = DepthStencilState::create(desc);
+~~~~~~~~~~~~~
+
+# Blend state {#nonProg_c}
+Blend state allows to you to control how is a rendered pixel blended with any previously rendered pixels. You can create it by filling out the @ref bs::BLEND_STATE_DESC "BLEND_STATE_DESC" structure and passing it to @ref bs::ct::BlendState::create "ct::BlendState::create()". Most of blend state options can be controlled individually for up to 8 render targets.
+
+~~~~~~~~~~~~~{.cpp}
+// Set up blending (e.g. for transparent rendering) for the first render target
+BLEND_STATE_DESC desc;
+desc.renderTargetDesc[0].blendEnable = true; // Enable blending
+desc.renderTargetDesc[0].srcBlend = BF_SOURCE_ALPHA; // Use the current alpha value to blend the source (new value)
+desc.renderTargetDesc[0].dstBlend = BF_INV_SOURCE_ALPHA; // Use the inverse of the current alpha value to blend the destination (stored value)
+desc.renderTargetDesc[0].blendOp = BO_ADD; // Add the source and destination together
+
+SPtr<BlendState> blendState = BlendState::create(desc);
+~~~~~~~~~~~~~

+ 66 - 48
Source/BansheeCore/Include/BsBlendState.h

@@ -33,14 +33,54 @@ namespace bs
 
 		bool operator==(const RENDER_TARGET_BLEND_STATE_DESC& rhs) const;
 
+		/**
+		 * Queries is blending enabled for the specified render target. Blending allows you to combine the color from 
+		 * current and previous pixel based on some value.
+		 */
 		bool blendEnable;
+
+		/**
+		 * Determines what should the source blend factor be. This value determines what will the color being generated 
+		 * currently be multiplied by.
+		 */
 		BlendFactor srcBlend;
+
+		/**
+		 * Determines what should the destination blend factor be. This value determines what will the color already in 
+		 * render target be multiplied by.
+		 */
 		BlendFactor dstBlend;
+
+		/**
+		 * Determines how are source and destination colors combined (after they are multiplied by their respective blend 
+		 * factors).
+		 */
 		BlendOperation blendOp;
+
+		/**
+		 * Determines what should the alpha source blend factor be. This value determines what will the alpha value being 
+		 * generated currently be multiplied by.
+		 */
 		BlendFactor srcBlendAlpha;
+
+		/**
+		 * Determines what should the alpha destination blend factor be. This value determines what will the alpha value 
+		 * already in render target be multiplied by.
+		 */
 		BlendFactor dstBlendAlpha;
+
+		/**
+		 * Determines how are source and destination alpha values combined (after they are multiplied by their respective
+		 * blend factors).
+		 */
 		BlendOperation blendOpAlpha;
-		// Enable write to RGBA channels separately by setting first four bits (0 - R, 1 - G, 2 - B, 3 - A)
+
+		/**
+		 * Render target write mask allows to choose which pixel components should the pixel shader output.
+		 * 			
+		 * Only the first four bits are used. First bit representing red, second green, third blue and fourth alpha value. 
+		 * Set bits means pixel shader will output those channels.
+		 */
 		UINT8 renderTargetWriteMask;
 	};
 
@@ -54,17 +94,6 @@ namespace bs
 
 		bool operator==(const BLEND_STATE_DESC& rhs) const;
 
-		bool alphaToCoverageEnable;
-		bool independantBlendEnable;
-		RENDER_TARGET_BLEND_STATE_DESC renderTargetDesc[BS_MAX_MULTIPLE_RENDER_TARGETS];
-	};
-
-	/** Properties of a BlendState. Shared between sim and core thread versions of BlendState. */
-	class BS_CORE_EXPORT BlendProperties
-	{
-	public:
-		BlendProperties(const BLEND_STATE_DESC& desc);
-
 		/**
 		 * Alpha to coverage allows you to perform blending without needing to worry about order of rendering like regular 
 		 * blending does. It requires multi-sampling to be active in order to work, and you need to supply an alpha texture
@@ -76,62 +105,51 @@ namespace bs
 		 * Be aware this is a limited technique only useful for certain situations. Unless you are having performance 
 		 * problems use regular blending.
 		 */
-		bool getAlphaToCoverageEnabled() const { return mData.alphaToCoverageEnable; }
+		bool alphaToCoverageEnable;
 
 		/**
 		 * When not set, only the first render target blend descriptor will be used for all render targets. If set each 
 		 * render target will use its own blend descriptor.
 		 */
+		bool independantBlendEnable;
+
+		RENDER_TARGET_BLEND_STATE_DESC renderTargetDesc[BS_MAX_MULTIPLE_RENDER_TARGETS];
+	};
+
+	/** Properties of a BlendState. Shared between sim and core thread versions of BlendState. */
+	class BS_CORE_EXPORT BlendProperties
+	{
+	public:
+		BlendProperties(const BLEND_STATE_DESC& desc);
+
+		/** @copydoc BLEND_STATE_DESC::alphaToCoverageEnable */
+		bool getAlphaToCoverageEnabled() const { return mData.alphaToCoverageEnable; }
+
+		/** @copydoc BLEND_STATE_DESC::independantBlendEnable */
 		bool getIndependantBlendEnable() const { return mData.independantBlendEnable; }
 
-		/**
-		 * Queries is blending enabled for the specified render target. Blending allows you to combine the color from 
-		 * current and previous pixel based on some value.
-		 */
+		/** @copydoc RENDER_TARGET_BLEND_STATE_DESC::blendEnable */
 		bool getBlendEnabled(UINT32 renderTargetIdx) const;
 
-		/**
-		 * Determines what should the source blend factor be. This value determines what will the color being generated 
-		 * currently be multiplied by.
-		 */
+		/** @copydoc RENDER_TARGET_BLEND_STATE_DESC::srcBlend */
 		BlendFactor getSrcBlend(UINT32 renderTargetIdx) const;
 
-		/**
-		 * Determines what should the destination blend factor be. This value determines what will the color already in 
-		 * render target be multiplied by.
-		 */
+		/** @copydoc RENDER_TARGET_BLEND_STATE_DESC::dstBlend */
 		BlendFactor getDstBlend(UINT32 renderTargetIdx) const;
 
-		/**
-		 * Determines how are source and destination colors combined (after they are multiplied by their respective blend 
-		 * factors).
-		 */
+		/** @copydoc RENDER_TARGET_BLEND_STATE_DESC::blendOp */
 		BlendOperation getBlendOperation(UINT32 renderTargetIdx) const;
 
-		/**
-		 * Determines what should the alpha source blend factor be. This value determines what will the alpha value being 
-		 * generated currently be multiplied by.
-		 */
+		/** @copydoc RENDER_TARGET_BLEND_STATE_DESC::srcBlendAlpha */
 		BlendFactor getAlphaSrcBlend(UINT32 renderTargetIdx) const;
 
-		/**
-		 * Determines what should the alpha destination blend factor be. This value determines what will the alpha value 
-		 * already in render target be multiplied by.
-		 */
+		/** @copydoc RENDER_TARGET_BLEND_STATE_DESC::dstBlendAlpha */
 		BlendFactor getAlphaDstBlend(UINT32 renderTargetIdx) const;
 
-		/**
-		 * Determines how are source and destination alpha values combined (after they are multiplied by their respective
-		 * blend factors).
-		 */
+		/** @copydoc RENDER_TARGET_BLEND_STATE_DESC::blendOpAlpha */
 		BlendOperation getAlphaBlendOperation(UINT32 renderTargetIdx) const;
 
-		/**
-		 * Render target write mask allows to choose which pixel components should the pixel shader output.
-		 * 			
-		 * Only the first four bits are used. First bit representing red, second green, third blue and fourth alpha value. 
-		 * Set bits means pixel shader will output those channels.
-		 */
+		/** @copydoc RENDER_TARGET_BLEND_STATE_DESC::renderTargetWriteMask */
 		UINT8 getRenderTargetWriteMask(UINT32 renderTargetIdx) const;
 
 		/** Returns the hash value generated from the blend state properties. */
@@ -148,7 +166,7 @@ namespace bs
 
 	/**
 	 * Render system pipeline state that allows you to modify how an object is rendered. More exactly this state allows to 
-	 * you to control how is a rendered object blended with any previously renderer objects.
+	 * you to control how is a rendered object blended with any previously rendered objects.
 	 * 			
 	 * @note	Blend states are immutable. Sim thread only.
 	 */

+ 54 - 30
Source/BansheeCore/Include/BsDepthStencilState.h

@@ -38,22 +38,62 @@ namespace bs
 
 		bool operator==(const DEPTH_STENCIL_STATE_DESC& rhs) const;
 
+		/**
+		 * If enabled, any pixel about to be written will be tested against the depth value currently in the buffer. If the 
+		 * depth test passes (depending on the set valueand chosen depth comparison function), that pixel is written and 
+		 * depth is updated (if depth write is enabled).
+		 */
 		bool depthReadEnable;
+
+		/** If enabled rendering pixels will update the depth buffer value. */
 		bool depthWriteEnable;
+
+		/**
+		 * Determines what operation should the renderer use when comparing previous and current depth value. If the 
+		 * operation passes, pixel with the current depth value will be considered visible.
+		 */
 		CompareFunction depthComparisonFunc;
 
+		/**
+		 * If true then stencil buffer will also be updated when a pixel is written, and pixels will be tested against 
+		 * the stencil buffer before rendering.
+		 */
 		bool stencilEnable;
+
+		/** Mask to apply to any value read from the stencil buffer, before applying the stencil comparison function. */
 		UINT8 stencilReadMask;
+
+		/**	Mask to apply to any value about to be written in the stencil buffer. */
 		UINT8 stencilWriteMask;
 
+		/**	Operation that happens when stencil comparison function fails on a front facing polygon. */
 		StencilOperation frontStencilFailOp;
+
+		/** Operation that happens when stencil comparison function passes but depth test fails on a front facing polygon. */
 		StencilOperation frontStencilZFailOp;
+
+		/**	Operation that happens when stencil comparison function passes on a front facing polygon. */
 		StencilOperation frontStencilPassOp;
+
+		/**
+		 * Stencil comparison function used for front facing polygons. Stencil buffer will be modified according to 
+		 * previously set stencil operations depending whether this comparison passes or fails.
+		 */
 		CompareFunction frontStencilComparisonFunc;
 
+		/** Operation that happens when stencil comparison function fails on a back facing polygon. */
 		StencilOperation backStencilFailOp;
+
+		/** Operation that happens when stencil comparison function passes but depth test fails on a back facing polygon. */
 		StencilOperation backStencilZFailOp;
+
+		/**	Operation that happens when stencil comparison function passes on a back facing polygon. */
 		StencilOperation backStencilPassOp;
+
+		/**
+		 * Stencil comparison function used for back facing polygons. Stencil buffer will be modified according	to 
+		 * previously set stencil operations depending whether this comparison passes or fails.
+		 */
 		CompareFunction backStencilComparisonFunc;
 	};
 
@@ -67,62 +107,46 @@ namespace bs
 	public:
 		DepthStencilProperties(const DEPTH_STENCIL_STATE_DESC& desc);
 
-		/**
-		 * If enabled, any pixel about to be written will be tested against the depth value currently in the buffer. If the 
-		 * depth test passes (depending on the set valueand chosen depth comparison function), that pixel is written and 
-		 * depth is updated (if depth write is enabled).
-		 */
+		/** @copydoc DEPTH_STENCIL_STATE_DESC::depthReadEnable */
 		bool getDepthReadEnable() const { return mData.depthReadEnable; }
 
-		/** If enabled rendering pixels will update the depth buffer value. */
+		/** @copydoc DEPTH_STENCIL_STATE_DESC::depthWriteEnable */
 		bool getDepthWriteEnable() const { return mData.depthWriteEnable; }
 
-		/**
-		 * Determines what operation should the renderer use when comparing previous and current depth value. If the 
-		 * operation passes, pixel with the current depth value will be considered visible.
-		 */
+		/** @copydoc DEPTH_STENCIL_STATE_DESC::depthComparisonFunc */
 		CompareFunction getDepthComparisonFunc() const { return mData.depthComparisonFunc; }
 
-		/**
-		 * If true then stencil buffer will also be updated when a pixel is written, and pixels will be tested against 
-		 * the stencil buffer before rendering.
-		 */
+		/** @copydoc DEPTH_STENCIL_STATE_DESC::stencilEnable */
 		bool getStencilEnable() const { return mData.stencilEnable; }
 
-		/** Mask to apply to any value read from the stencil buffer, before applying the stencil comparison function. */
+		/** @copydoc DEPTH_STENCIL_STATE_DESC::stencilReadMask */
 		UINT8 getStencilReadMask() const { return mData.stencilReadMask; }
 
-		/**	Mask to apply to any value about to be written in the stencil buffer. */
+		/** @copydoc DEPTH_STENCIL_STATE_DESC::stencilWriteMask */
 		UINT8 getStencilWriteMask() const { return mData.stencilWriteMask; }
 
-		/**	Operation that happens when stencil comparison function fails on a front facing polygon. */
+		/** @copydoc DEPTH_STENCIL_STATE_DESC::frontStencilFailOp */
 		StencilOperation getStencilFrontFailOp() const { return mData.frontStencilFailOp; }
 
-		/** Operation that happens when stencil comparison function passes but depth test fails on a front facing polygon. */
+		/** @copydoc DEPTH_STENCIL_STATE_DESC::frontStencilZFailOp */
 		StencilOperation getStencilFrontZFailOp() const { return mData.frontStencilZFailOp; }
 
-		/**	Operation that happens when stencil comparison function passes on a front facing polygon. */
+		/** @copydoc DEPTH_STENCIL_STATE_DESC::frontStencilPassOp */
 		StencilOperation getStencilFrontPassOp() const { return mData.frontStencilPassOp; }
 
-		/**
-		 * Stencil comparison function used for front facing polygons. Stencil buffer will be modified according to 
-		 * previously set stencil operations depending whether this comparison passes or fails.
-		 */
+		/** @copydoc DEPTH_STENCIL_STATE_DESC::frontStencilComparisonFunc */
 		CompareFunction getStencilFrontCompFunc() const { return mData.frontStencilComparisonFunc; }
 
-		/** Operation that happens when stencil comparison function fails on a back facing polygon. */
+		/** @copydoc DEPTH_STENCIL_STATE_DESC::backStencilFailOp */
 		StencilOperation getStencilBackFailOp() const { return mData.backStencilFailOp; }
 
-		/** Operation that happens when stencil comparison function passes but depth test fails on a back facing polygon. */
+		/** @copydoc DEPTH_STENCIL_STATE_DESC::backStencilZFailOp */
 		StencilOperation getStencilBackZFailOp() const { return mData.backStencilZFailOp; }
 
-		/**	Operation that happens when stencil comparison function passes on a back facing polygon. */
+		/** @copydoc DEPTH_STENCIL_STATE_DESC::backStencilPassOp */
 		StencilOperation getStencilBackPassOp() const { return mData.backStencilPassOp; }
 
-		/**
-		 * Stencil comparison function used for back facing polygons. Stencil buffer will be modified according	to 
-		 * previously set stencil operations depending whether this comparison passes or fails.
-		 */
+		/** @copydoc DEPTH_STENCIL_STATE_DESC::backStencilComparisonFunc */
 		CompareFunction getStencilBackCompFunc() const { return mData.backStencilComparisonFunc; }
 
 		/** Returns the hash value generated from the depth-stencil state properties. */

+ 42 - 27
Source/BansheeCore/Include/BsRasterizerState.h

@@ -29,43 +29,24 @@ namespace bs
 
 		bool operator==(const RASTERIZER_STATE_DESC& rhs) const;
 
-		PolygonMode polygonMode;
-		CullingMode cullMode;
-
-		float depthBias;
-		float depthBiasClamp;
-		float slopeScaledDepthBias;
-
-		bool depthClipEnable;
-		bool scissorEnable;
-		bool multisampleEnable;
-		bool antialiasedLineEnable;
-	};
-
-	/** Properties of RasterizerState. Shared between sim and core thread versions of RasterizerState. */
-	class BS_CORE_EXPORT RasterizerProperties
-	{
-	public:
-		RasterizerProperties(const RASTERIZER_STATE_DESC& desc);
-
 		/** Polygon mode allows you to draw polygons as solid objects or as wireframe by just drawing their edges. */
-		PolygonMode getPolygonMode() const { return mData.polygonMode; }
+		PolygonMode polygonMode;
 
 		/**
 		 * Sets vertex winding order. Faces that contain vertices with this order will be culled and not rasterized. Used 
 		 * primarily for saving cycles by not rendering backfacing faces.
 		 */
-		CullingMode getCullMode() const { return mData.cullMode; }
+		CullingMode cullMode;
 
 		/**
 		 * Represents a constant depth bias that will offset the depth values of new pixels by the specified amount.
 		 *
 		 * @note		This is useful if you want to avoid z fighting for objects at the same or similar depth.
 		 */
-		float getDepthBias() const { return mData.depthBias; }
+		float depthBias;
 
 		/**	Maximum depth bias value. */
-		float getDepthBiasClamp() const { return mData.depthBiasClamp; }
+		float depthBiasClamp;
 
 		/**
 		 * Represents a dynamic depth bias that increases as the slope of the rendered polygons surface increases. 
@@ -73,7 +54,7 @@ namespace bs
 		 *
 		 * @note	This is useful if you want to avoid z fighting for objects at the same or similar depth.
 		 */
-		float getSlopeScaledDepthBias() const { return mData.slopeScaledDepthBias; }
+		float slopeScaledDepthBias;
 
 		/**
 		 * If true, clipping of polygons past the far Z plane is enabled. This ensures proper Z ordering for polygons 
@@ -81,14 +62,14 @@ namespace bs
 		 * performing stencil operations that count on objects having a front and a back (like stencil shadow) and don't 
 		 * want to clip the back.
 		 */
-		bool getDepthClipEnable() const { return mData.depthClipEnable; }
+		bool depthClipEnable;
 
 		/**
 		 * Scissor rectangle allows you to cull all pixels outside of the scissor rectangle.
 		 *			
 		 * @see		ct::RenderAPI::setScissorRect
 		 */
-		bool getScissorEnable() const { return mData.scissorEnable; }
+		bool scissorEnable;
 
 		/**
 		 * Determines how are samples in multi-sample render targets handled. If disabled all samples in the render target 
@@ -96,7 +77,7 @@ namespace bs
 		 *			
 		 * @note	In order to get an antialiased image you need to both enable this option and use a MSAA render target.
 		 */
-		bool getMultisampleEnable() const { return mData.multisampleEnable; }
+		bool multisampleEnable;
 
 		/**
 		 * Determines should the lines be antialiased. This is separate from multi-sample antialiasing setting as lines can
@@ -104,6 +85,40 @@ namespace bs
 		 *
 		 * @note	This setting is usually ignored if MSAA is used, as that provides sufficient antialiasing.
 		 */
+		bool antialiasedLineEnable;
+	};
+
+	/** Properties of RasterizerState. Shared between sim and core thread versions of RasterizerState. */
+	class BS_CORE_EXPORT RasterizerProperties
+	{
+	public:
+		RasterizerProperties(const RASTERIZER_STATE_DESC& desc);
+
+		/** @copydoc RASTERIZER_STATE_DESC::polygonMode */
+		PolygonMode getPolygonMode() const { return mData.polygonMode; }
+
+		/** @copydoc RASTERIZER_STATE_DESC::cullMode */
+		CullingMode getCullMode() const { return mData.cullMode; }
+
+		/** @copydoc RASTERIZER_STATE_DESC::depthBias */
+		float getDepthBias() const { return mData.depthBias; }
+
+		/** @copydoc RASTERIZER_STATE_DESC::depthBiasClamp */
+		float getDepthBiasClamp() const { return mData.depthBiasClamp; }
+
+		/** @copydoc RASTERIZER_STATE_DESC::slopeScaledDepthBias */
+		float getSlopeScaledDepthBias() const { return mData.slopeScaledDepthBias; }
+
+		/** @copydoc RASTERIZER_STATE_DESC::depthClipEnable */
+		bool getDepthClipEnable() const { return mData.depthClipEnable; }
+
+		/** @copydoc RASTERIZER_STATE_DESC::scissorEnable */
+		bool getScissorEnable() const { return mData.scissorEnable; }
+
+		/** @copydoc RASTERIZER_STATE_DESC::multisampleEnable */
+		bool getMultisampleEnable() const { return mData.multisampleEnable; }
+
+		/** @copydoc RASTERIZER_STATE_DESC::antialiasedLineEnable */
 		bool getAntialiasedLineEnable() const { return mData.antialiasedLineEnable; }
 
 		/** Returns the hash value generated from the rasterizer state properties. */