GLSL-to-HLSL reference
You port your OpenGL Shader Language (GLSL) code to Microsoft High Level Shader Language (HLSL) code when you port your graphics architecture from OpenGL ES 2.0 to Direct3D 11 to create a game for Universal Windows Platform (UWP). The GLSL that is referred to herein is compatible with OpenGL ES 2.0; the HLSL is compatible with Direct3D 11. For info about the differences between Direct3D 11 and previous versions of Direct3D, see Feature mapping.
- Comparing OpenGL ES 2.0 with Direct3D 11
- Porting GLSL variables to HLSL
- Porting GLSL types to HLSL
- Porting GLSL pre-defined global variables to HLSL
- Examples of porting GLSL variables to HLSL
- Examples of porting OpenGL rendering code to Direct3D
- Related topics
Comparing OpenGL ES 2.0 with Direct3D 11
OpenGL ES 2.0 and Direct3D 11 have many similarities. They both have similar rendering pipelines and graphics features. But Direct3D 11 is a rendering implementation and API, not a specification; OpenGL ES 2.0 is a rendering specification and API, not an implementation. Direct3D 11 and OpenGL ES 2.0 generally differ in these ways:
OpenGL ES 2.0 | Direct3D 11 |
---|---|
Hardware and operating system agnostic specification with vendor provided implementations | Microsoft implementation of hardware abstraction and certification on Windows platforms |
Abstracted for hardware diversity, runtime manages most resources | Direct access to hardware layout; app can manage resources and processing |
Provides higher-level modules via third-party libraries (for example, Simple DirectMedia Layer (SDL)) | Higher-level modules, like Direct2D, are built upon lower modules to simplify development for Windows apps |
Hardware vendors differentiate via extensions | Microsoft adds optional features to the API in a generic way so they aren't specific to any particular hardware vendor |
GLSL and HLSL generally differ in these ways:
GLSL | HLSL |
---|---|
Procedural, step-centric (C like) | Object oriented, data-centric (C++ like) |
Shader compilation integrated into the graphics API | The HLSL compiler compiles the shader to an intermediate binary representation before Direct3D passes it to the driver.
Note This binary representation is hardware independent. It's typically compiled at app build time, rather than at app run time.
|
Variable storage modifiers | Constant buffers and data transfers via input layout declarations |
Typical vector type: vec2/3/4 lowp, mediump, highp |
Typical vector type: float2/3/4 min10float, min16float |
texture2D [Function] | texture.Sample [datatype.Function] |
sampler2D [datatype] | Texture2D [datatype] |
Row-major matrices (default) | Column-major matrices (default)
Note Use the row_major type-modifier to change the layout for one variable. For more info, see Variable Syntax. You can also specify a compiler flag or a pragma to change the global default.
|
Fragment shader | Pixel shader |
Note HLSL has textures and samplers as two separate objects. In GLSL, like Direct3D 9, the texture binding is part of the sampler state.
In GLSL, you present much of the OpenGL state as pre-defined global variables. For example, with GLSL, you use the gl_Position variable to specify vertex position and the gl_FragColor variable to specify fragment color. In HLSL, you pass Direct3D state explicitly from the app code to the shader. For example, with Direct3D and HLSL, the input to the vertex shader must match the data format in the vertex buffer, and the structure of a constant buffer in the app code must match the structure of a constant buffer (cbuffer) in shader code.
Porting GLSL variables to HLSL
In GLSL, you apply modifiers (qualifiers) to a global shader variable declaration to give that variable a specific behavior in your shaders. In HLSL, you don’t need these modifiers because you define the flow of the shader with the arguments that you pass to your shader and that you return from your shader.
GLSL variable behavior | HLSL equivalent |
---|---|
uniform You pass a uniform variable from the app code into either or both vertex and fragment shaders. You must set the values of all uniforms before you draw any triangles with those shaders so their values stay the same throughout the drawing of a triangle mesh. These values are uniform. Some uniforms are set for the entire frame and others uniquely to one particular vertex-pixel shader pair. Uniform variables are per-polygon variables. |
Use constant buffer. |
varying You initialize a varying variable inside the vertex shader and pass it through to an identically named varying variable in the fragment shader. Because the vertex shader only sets the value of the varying variables at each vertex, the rasterizer interpolates those values (in a perspective-correct manner) to generate per fragment values to pass into the fragment shader. These variables vary across each triangle. |
Use the structure that you return from your vertex shader as the input to your pixel shader. Make sure the semantic values match. |
attribute An attribute is a part of the description of a vertex that you pass from the app code to the vertex shader alone. Unlike a uniform, you set each attribute’s value for each vertex, which, in turn, allows each vertex to have a different value. Attribute variables are per-vertex variables. |
Define a vertex buffer in your Direct3D app code and match it to the vertex input defined in the vertex shader. Optionally, define an index buffer. See How to: Create a Vertex Buffer and How to: Create an Index Buffer. Create an input layout in your Direct3D app code and match semantic values with those in the vertex input. See Create the input layout. |
const Constants that are compiled into the shader and never change. |
Use a static const. static means the value isn't exposed to constant buffers, const means the shader can't change the value. So, the value is known at compile time based on its initializer. |
In GLSL, variables without modifiers are just ordinary global variables that are private to each shader.
When you pass data to textures (Texture2D in HLSL) and their associated samplers (SamplerState in HLSL), you typically declare them as global variables in the pixel shader.
Porting GLSL types to HLSL
Use this table to port your GLSL types to HLSL.
GLSL type | HLSL type |
---|---|
scalar types: float, int, bool | scalar types: float, int, bool also, uint, double For more info, see Scalar Types. |
vector type
|
vector type
For more info, see Vector Type and Keywords. vector is also type defined as float4 (typedef vector <float, 4> vector;). For more info, see User-Defined Type. |
matrix type
|
matrix type
You can also use the matrix type to define a matrix. For example: matrix <float, 2, 2> fMatrix = {0.0f, 0.1, 2.1f, 2.2f}; matrix is also type defined as float4x4 (typedef matrix <float, 4, 4> matrix;). For more info, see User-Defined Type. |
precision qualifiers for float, int, sampler
|
precision types
For more info, see Scalar Types and Using HLSL minimum precision. |
sampler2D | Texture2D |
samplerCube | TextureCube |
Porting GLSL pre-defined global variables to HLSL
Use this table to port GLSL pre-defined global variables to HLSL.
GLSL pre-defined global variable | HLSL semantics |
---|---|
gl_Position This variable is type vec4. Vertex position for example - gl_Position = position; |
SV_Position POSITION in Direct3D 9 This semantic is type float4. Vertex shader output Vertex position for example - float4 vPosition : SV_Position; |
gl_PointSize This variable is type float. Point size |
PSIZE No meaning unless you target Direct3D 9 This semantic is type float. Vertex shader output Point size |
gl_FragColor This variable is type vec4. Fragment color for example - gl_FragColor = vec4(colorVarying, 1.0); |
SV_Target COLOR in Direct3D 9 This semantic is type float4. Pixel shader output Pixel color for example - float4 Color[4] : SV_Target; |
gl_FragData[n] This variable is type vec4. Fragment color for color attachment n |
SV_Target[n] This semantic is type float4. Pixel shader output value that is stored in n render target, where 0 <= n <= 7. |
gl_FragCoord This variable is type vec4. Fragment position within frame buffer |
SV_Position Not available in Direct3D 9 This semantic is type float4. Pixel shader input Screen space coordinates for example - float4 screenSpace : SV_Position |
gl_FrontFacing This variable is type bool. Determines whether fragment belongs to a front-facing primitive. |
SV_IsFrontFace VFACE in Direct3D 9 SV_IsFrontFace is type bool. VFACE is type float. Pixel shader input Primitive facing |
gl_PointCoord This variable is type vec2. Fragment position within a point (point rasterization only) |
SV_Position VPOS in Direct3D 9 SV_Position is type float4. VPOS is type float2. Pixel shader input The pixel or sample position in screen space for example - float4 pos : SV_Position |
gl_FragDepth This variable is type float. Depth buffer data |
SV_Depth DEPTH in Direct3D 9 SV_Depth is type float. Pixel shader output Depth buffer data |
You use semantics to specify position, color, and so on for vertex shader input and pixel shader input. You must match the semantics values in the input layout with the vertex shader input. For examples, see Examples of porting GLSL variables to HLSL. For more info about the HLSL semantics, see Semantics.
Examples of porting GLSL variables to HLSL
Here we show examples of using GLSL variables in OpenGL/GLSL code and then the equivalent example in Direct3D/HLSL code.
Uniform, attribute, and varying in GLSL
OpenGL app code
// Uniform values can be set in app code and then processed in the shader code.
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
// Incoming position of vertex
attribute vec4 position;
// Incoming color for the vertex
attribute vec3 color;
// The varying variable tells the shader pipeline to pass it
// on to the fragment shader.
varying vec3 colorVarying;
GLSL vertex shader code
//The shader entry point is the main method.
void main()
{
colorVarying = color; //Use the varying variable to pass the color to the fragment shader
gl_Position = position; //Copy the position to the gl_Position pre-defined global variable
}
GLSL fragment shader code
void main()
{
//Pad the colorVarying vec3 with a 1.0 for alpha to create a vec4 color
//and assign that color to the gl_FragColor pre-defined global variable
//This color then becomes the fragment's color.
gl_FragColor = vec4(colorVarying, 1.0);
}
Constant buffers and data transfers in HLSL
Here is an example of how you pass data to the HLSL vertex shader that then flows through to the pixel shader. In your app code, define a vertex and a constant buffer. Then, in your vertex shader code, define the constant buffer as a cbuffer and store the per-vertex data and the pixel shader input data. Here we use structures called VertexShaderInput and PixelShaderInput.
Direct3D app code
struct ConstantBuffer
{
XMFLOAT4X4 model;
XMFLOAT4X4 view;
XMFLOAT4X4 projection;
};
struct SimpleCubeVertex
{
XMFLOAT3 pos; // position
XMFLOAT3 color; // color
};
// Create an input layout that matches the layout defined in the vertex shader code.
const D3D11_INPUT_ELEMENT_DESC basicVertexLayoutDesc[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
// Create vertex and index buffers that define a geometry.
HLSL vertex shader code
cbuffer ModelViewProjectionCB : register( b0 )
{
matrix model;
matrix view;
matrix projection;
};
// The POSITION and COLOR semantics must match the semantics in the input layout Direct3D app code.
struct VertexShaderInput
{
float3 pos : POSITION; // Incoming position of vertex
float3 color : COLOR; // Incoming color for the vertex
};
struct PixelShaderInput
{
float4 pos : SV_Position; // Copy the vertex position.
float4 color : COLOR; // Pass the color to the pixel shader.
};
PixelShaderInput main(VertexShaderInput input)
{
PixelShaderInput vertexShaderOutput;
// shader source code
return vertexShaderOutput;
}
HLSL pixel shader code
// Collect input from the vertex shader.
// The COLOR semantic must match the semantic in the vertex shader code.
struct PixelShaderInput
{
float4 pos : SV_Position;
float4 color : COLOR; // Color for the pixel
};
// Set the pixel color value for the renter target.
float4 main(PixelShaderInput input) : SV_Target
{
return input.color;
}
Examples of porting OpenGL rendering code to Direct3D
Here we show an example of rendering in OpenGL ES 2.0 code and then the equivalent example in Direct3D 11 code.
OpenGL rendering code
// Bind shaders to the pipeline.
// Both vertex shader and fragment shader are in a program.
glUseProgram(m_shader->getProgram());
// Input assembly
// Get the position and color attributes of the vertex.
m_positionLocation = glGetAttribLocation(m_shader->getProgram(), "position");
glEnableVertexAttribArray(m_positionLocation);
m_colorLocation = glGetAttribColor(m_shader->getProgram(), "color");
glEnableVertexAttribArray(m_colorLocation);
// Bind the vertex buffer object to the input assembler.
glBindBuffer(GL_ARRAY_BUFFER, m_geometryBuffer);
glVertexAttribPointer(m_positionLocation, 4, GL_FLOAT, GL_FALSE, 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER, m_colorBuffer);
glVertexAttribPointer(m_colorLocation, 3, GL_FLOAT, GL_FALSE, 0, NULL);
// Draw a triangle with 3 vertices.
glDrawArray(GL_TRIANGLES, 0, 3);
Direct3D rendering code
// Bind the vertex shader and pixel shader to the pipeline.
m_d3dDeviceContext->VSSetShader(vertexShader.Get(),nullptr,0);
m_d3dDeviceContext->PSSetShader(pixelShader.Get(),nullptr,0);
// Declare the inputs that the shaders expect.
m_d3dDeviceContext->IASetInputLayout(inputLayout.Get());
m_d3dDeviceContext->IASetVertexBuffers(0, 1, vertexBuffer.GetAddressOf(), &stride, &offset);
// Set the primitive's topology.
m_d3dDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// Draw a triangle with 3 vertices. triangleVertices is an array of 3 vertices.
m_d3dDeviceContext->Draw(ARRAYSIZE(triangleVertices),0);
Related topics