I'm using a mat3 uniform in a GLSL shader.
layout (std140)
struct UNI {
mat3 mat;
} u;
A mat3 is stored as 3 rows of vec4 in GLSL so that means there's 3 unused floats in there.
Is there any way to access those floats? I want to to pack some more data in there.
nb. I tried using u.mat[0][3] but it says "array index out of bounds" when I compile it.
I think you are mixing two things here:
the actual memory layout of the data
the API that GLSL provides you to access the data
When you are using Uniform Buffer Objects (UBO) to back the storage of the mat3 and are using the std140 layout, then yes, a mat3 is layed out in exactly the same way as 3 vec4 values. So, essentially, under std140 layout there is no difference in the memory layout between a mat3x4 (three columns each with 4 rows/elements) and a mat3 or mat3x3.
However, you cannot access the fourth row of each column when using a mat3 as the API type in the GLSL shader.
What you could do instead is simply use the mat3x4 type, which would give you access to the fourth row. And when you need a mat3 you can cast it with mat3(theMat3x4Value).
Related
I was wondering if I can index into a uniform buffer array with a value contained in the vertices I draw, like:
layout (location = 0) in vec3 position;
layout (location = 1) in flat int idx;
layout(binding = 0, std140) uniform uniformValues
{
float values[100];
};
void main()
{
values[idx];
}
My understanding is that this is not possible because
'in flat int idx'
Is most likely not a 'dynamically uniform expression', and according to the documentation cannot be used to index into a uniform buffer array:
There are places where GLSL requires the expression to be dynamically
uniform. All of the following must use a dynamically uniform
expression:
-The index to buffer-backed interface block arrays.
However I came across information from the same source regarding how to access an array of samplers holding texture handles for 'bindless textures', and it says (emphasis mine):
Sampler and image types used in default block uniform variables can be
populated from handles rather than the index of a binding point.
These types can also now be passed as Shader Stage inputs/outputs (using the flat interpolation qualifier where needed). They can be
used as Vertex Attributes, where they are treated as 64-bit integers
on the OpenGL side. And they can be used in Interface Blocks of all
kinds; buffer-backed interface blocks treat them as 64-bit integers.
It's saying, I believe, that instead of doing this:
layout (location = 0) in flat int textureBinding;
layout (binding = 0) uniform sampler2D textures[16];
void main()
{
textures[textureBinding];
}
You do this:
layout (location = 0) in flat int bindlessTextureHandle;
layout (binding = 0) uniform textureBuffer
{
sampler2D textures[200];
}
void main()
{
textures[bindlessTextureHandle];
}
'bindlessTextureHandle' isn't a 'dynamically uniform expression', how can it be used to index into uniform buffer?
All of the following must use a dynamically uniformexpression:
-The index to buffer-backed interface block arrays.
So why is it saying that you can index into 'interface blocks' of all kinds with values from vertex inputs?
Also are you allowed to index into:
'uniform sampler2D[16] textures;'
with a 'non-dynamically uniform expression'?
My understanding is that this is not possible because
in flat int idx
Is most likely not a 'dynamically uniform expression', and according
to the documentation cannot be used to index into a uniform buffer
array.
You are right that you need a dynamically uniform value to index into an uniform buffer array. However, this:
layout(binding = 0, std140) uniform uniformValues
{
float values[100];
};
is not a uniform buffer array. That is an array inside a single uniform buffer object, and you can index with non-uniform values into this array as you like. A uniform buffer array would be:
layout(binding = 0, std140) uniform myUBO
{
float value;
} myUBOArray[4];
The rest of your question gets even more obscure. You sometimes reference "The index to buffer-backed interface block arrays", which your code never uses. This is talking about SSBOs, which use interface blocks of the form layout(...) buffer foo {...}.
So why is it saying that you can index into 'interface blocks' of all kinds with values from vertex inputs?
Because that is how it is. You just need to understand that indexing into an array of interface blocks is not the same as indexing some other array (which might or might not be defined inside an interface block, doesn't matter).
Also are you allowed to index into:
uniform sampler2D[16] textures; with a 'non-dynamically uniform expression'?
No, not in standard GL.
The first thing about bindless textures is that this is not a core feature of any OpenGL version released to date (which is 4.6 at the time of writing this).It is only defined as an extension GL_ARB_bindless_textures which some modern GPUs and drivers expose, but the availability of that feature is quite far from being universal.
Second, the extension spec above explains: "Sampler and image handles passed to texture built-in functions must be dynamically uniform", so it still doesn't get you there. However, the extension GL_NV_gpu_shader5 removes that restriction. So on recent NVIDIA GPUs, you can get a non-dymically uniform index into an array of bindless texture samplers - but performance will still suffer by a significant amount if you do so.
There are a myriad of separate, overlapping issues here.
Indexing an array within a uniform block has never been limited to dynamically uniform expressions (generally, see below). Even in GL 3.x, you can index an array within a buffer-backed block with an arbitrary index.
However, you're not asking about a general array; you're asking about arrays of textures. Or to be more general, the entire sequence of operations leading to the computation of a sampler type through bindless textures.
That entire sequence must be dynamically uniform (unless you're on NVIDIA, which allows arbitrary expressions). It doesn't matter if you're indexing an SSBO array, using an input variable to pass a texture handle directly, or anything else. The value that leads to the acquisition of a sampler type must be dynamically uniform.
So why is it saying that you can index into 'interface blocks' of all kinds with values from vertex inputs?
Because you can.
A common misunderstanding of what "dynamically uniform" means is that it is a static property. That an expression by itself is either dynamically uniform or not. This is close to true, but it's not actually true.
Some expressions are dynamically uniform by their nature. You could call these "statically dynamically uniform" expressions. A constant expression is always dynamically uniform, for example.
However, being dynamically uniform is about the value of the expression. All invocations (within the rendering command) must result in the same value. An in variable for a shader stage can be dynamically uniform so long as it just so happens to always have the same value within the rendering command. For example, a VS could access a value from a uniform array using gl_DrawID (which is dynamically uniform), pass that as an in to the FS, and the FS can use that value as a sampler. Or to access an array of samplers. Or whatever. All FS invocations will get the same value within the draw command, so that value is dynamically uniform.
I already have an ubo:
layout (std140, binding = 0) uniform view_shared_data {
uniform int matrixIndex;
uniform int projectionIndex;
uniform uint set_only_input_id;
uniform Matrices[MAX_MATRICES] matrices;
};
I am trying to add an array of bindless images to the ubo:
layout(bindless_image, r32ui) coherent uniform uimage2D[MAX_MATRICES] id_texture;
I will only write to the images using imageAtomicMax().
This compiles fine on windows using nvida gpu, but not on linux using amd. I am assuming something is wrong with my bindless_image, r32ui and coherent qualifiers, but I'm not sure how to set them correctly.
If you want to put bindless images/samplers in a uniform block, you have to actually put them inside the block definition. Just like any other variable:
layout (std140, binding = 0) uniform view_shared_data {
uniform int matrixIndex;
uniform int projectionIndex;
uniform uint set_only_input_id;
uniform Matrices[MAX_MATRICES] matrices;
layout(r32ui) coherent uimage2D[MAX_MATRICES] id_texture;
};
Each opaque type in a buffer-backed interface block is a single 64-bit integer. As such, the array stride of id_texture is 8-bytes, which matches a C or C++ array of 64-bit integers.
shader code:
// UBO for MVP matrices
layout (binding = 0) uniform UniformBufferObject {
mat4 model;
mat4 view;
mat4 proj;
} ubo;
this works fine because its just one struct and I can set the VkWriteDescriptorSet.descriptorCount to 1. But how can I create an array of those structs?
// Want to do something like this
// for lighting calculations
layout (binding = 2) uniform Light {
vec3 position;
vec3 color;
} lights[4];
I have the data for all of the four lights stored in one buffer. When I set the VkWriteDescriptorSet.descriptorCount to four,
Do I have to create four VkDescriptorBufferInfo? If so, I dont know what to put into offset and range.
All of the blocks in a uniform buffer array live in the same descriptor. However, they are still different blocks; they get a different VkDescriptorBufferInfo info object. So those blocks don't have to come from sequential regions of storage.
Note: The KHR_vulkan_glsl extension gets this wrong, if you look pay close attention. It notes that arrays of opaque types should go into a single descriptor, but arrays of interface blocks don't. The actual glslangValidator compiler (and SPIR-V and Vulkan) do handle it as I described.
However, you cannot access the elements of an interface block array with anything other than dynamically uniform expressions. And even that requires having a certain feature available; without that feature, you can only access the array with constant expressions.
What you probably want is an array within the block, not an array of blocks:
struct Light
{
vec4 position; //(NEVER use `vec3` in blocks)
vec4 color;
};
layout (set = 0, binding = 2, std140) uniform Lights {
Light lights[4];
};
This means that you have a single descriptor in binding slot 2 (descriptorCount is 1). And the buffer's data should be 4 sequential structs.
The following glsl code appears in my fragment shader. The struct definition causes no problems, but my attempt to use it as the type of a uniform array causes an "invalid operation" error, which is not particularly helpful.
struct InstanceData
{
vec3 rotation;
vec3 scale;
mat4 position;
};
layout (std140) uniform InstanceData instances[100];
How do I structure this code correctly so that it compiles without error, and is thus ready for me to populate with data? Note that I am using core profile version 4.5.
Edit: It seems to be something to do with the use of layout (std140). Removal of that part allows the code to compile, though don't I need that to ensure that the glsl compiler packs the struct data in a predictable way?
Edit: Still not working. My entire vertex shader code looks like this:
#version 450
layout(location=0) in vec4 in_Position;
layout(location=1) in vec4 in_Color;
out vec4 ex_Color;
flat out int ex_Instance;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
// ------ preliminary addition of uniform block to be used soon ------
struct layout (std140) InstanceData
{
vec3 rotation;
vec3 scale;
mat4 position;
};
layout (std140, binding = 0) uniform InstanceData
{
InstanceData instances[100];
};
// -------------------------------------------------------------------
void main(void)
{
gl_Position = (projectionMatrix * viewMatrix * modelMatrix) * in_Position;
ex_Color = in_Color;
}
Note that I haven't written any code externally to populate the uniform buffer yet, nor, as you can see above, have I adjusted my code to make use of the data either. I just want it to compile and work initially as-is (i.e. declared but not used), at which point I will add additional code to start making use of it. There's no point going even that far if the program doesn't like the declaration to begin with.
Edit: Finally figured out the problem by using the shader info log, like so:
GLint infoLogLength;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &infoLogLength);
GLchar* strInfoLog = new GLchar[infoLogLength + 1];
glGetShaderInfoLog(id, infoLogLength, NULL, strInfoLog);
In a nutshell, as Anton said, I was using layout incorrectly, and my uniform block had the same name as my struct, creating all kinds of confusion for the compiler.
To do this portably, you should use a Uniform Buffer Object.
Presently, your struct uses 3+3+16=22 floating-point components and you are trying to build an array of 100 of these. OpenGL implementations are only required to support 1024 floating-point uniform components in any stage, and your array requires 2200.
Uniform Buffer Objects will allow you to store up to 64 KiB (minimum) of data; well exceeding the limitation above. However, you need to be mindful of data alignment when using UBOs and that is what the layout (std140) qualifier you tried to use is for.
struct InstanceData
{
vec3 rotation;
vec3 scale;
mat4 position;
};
// Uniform block named InstanceBlock, follows std140 alignment rules
layout (std140, binding = 0) uniform InstanceBlock {
InstanceData instances [100];
};
The struct above is not correctly aligned for std140, you will need to be careful when using it.
This is how the data is actually laid out:
struct InstanceData
{
vec3 rotation; // 0,1,2
float padding03; // 3
vec3 scale; // 4,5,6
float padding07; // 7
mat4 position; // 8-23
} // Size: 24 * sizeof (float)
vec3 types are treated the same as vec4 in GLSL and mat4 is effectively an array of 4 vec4, so that means they all need to begin on 4-float boundaries. GLSL automatically inserts padding to satisfy these alignment rules; the changes I made above are to show you the correct way to write this data structure in C. You have to account for 2 floats worth of implicit padding in your structure.
Regarding your edit, you do not have to worry about how GLSL packs a struct until you start using buffer objects.
Without using a Uniform Buffer Object, you have to use functions like glUniform3f (...) to set uniforms. Those functions do not directly expose the data structure to you, so packing does not matter. To set the values for an instance N you would call glUniform3f (...) using the location of "instances [N].rotation" and "instances [N].scale" and glUniformMatrix4fv (...) on "instances [N].position".
That would require 300 API calls to initialize all 100 instances of your struct, so you can see why UBOs are more practical (even ignoring the above mentioned 1024 limitation).
I have the following vertex shader:
#version 330
layout (location = 0) in vec3 Position;
uniform mat4 gWVP;
out vec4 Color;
void main()
{
gl_Position = gWVP * vec4(Position, 1.0);
};
How can I get, for example, the third value of vec3? The first my thought was: "Maybe I can get it by multiplying this vector(Position) on something?" But I am not sure that something like "vertical vector type" exists.
So, what is the best way? I need this value to set the color of the pixel.
There are at least 4 options:
You can access vector components with component names x, y, z, w. This is mostly used for vectors that represent points/vectors. In your example, that would be Position.z.
You can use component names r, g, b, a. This is mostly used for vectors that represent colors. In your example, you could use Position.b, even though that would not be very readable. On the other hand, Color.b would be a good option for the other variable.
You can use component names s, t, p, q. This is mostly used for vectors that represent texture coordinates. In our example, Position.p would also give you the 3rd component.
You can use the subscript notation with 0-based indices. In your example, Position[2] also gives he 3rd element.
Each vector has overloaded access to elements. In this case, using Position.z should work.