Failure to write to texture as GL_R32UI using imageStore - opengl

I have a 3D texture with an internal format of GL_R32UI, writing to it works fine as long as I pretend its a floating point texture.
That is if I bind it as
layout(binding = 0) uniform image3D Voxels;
And write to it with
imageStore(Voxels, coord.xyz, vec4(1));
Everything works exactly as expected.
However trying to bind it while specifying the correct type as
layout(r32ui, binding = 0) uniform uimage3D Voxels;
and writing to its with
imageStore(Voxels, coord.zxy, uvec4(1));
doesn't seem to work, that is, nothing gets written to the texture. I'd like to get this work correctly so that I can then use the imageAtomic operations. Anyone have any idea what could be going on?

Related

Weird behaviour using mipmapping from glsl

I am trying to use mipmapping with vulkan. I do understand that I should use vkCmdBlit between each layer for each image, but before doing that, I just wanted to know how to change the layer in GLSL.
Here is what I did.
First I load and draw a texture (using layer 0) and there was no problem. The "rendered image" is the texture I load, so it is good.
Second, I use this shader (so I wanted to use the second layer (number 1)) but the "rendered image" does not change :
#version 450
layout(set = 0, binding = 0) uniform sampler2D tex;
in vec2 texCoords;
layout(location = 0) out vec4 outColor;
void main() {
outColor = textureLod(tex, texCoords, 1);
}
According to me, the rendered image should be changed, but not at all, it is always the same image, even if I increase the "1" (the number of the layer).
Third instead changing anything in the glsl code, I change the layer number into the ImageSubresourceRange to create the imageView, and the "rendered image" changed, so it seems normal to me and when I will use vkCmdBlit, I must see the original image in lower resolution.
The real problem is, when I try to use a mipmapping (through mipmapping) in GLSL, it does not affect at all the rendered image, but in C++ it does (and that seems fair).
here is (all) my source code
https://github.com/qnope/Vulkan-Example/tree/master/Mipmap
Judging by your default sampler creation info (https://github.com/qnope/Vulkan-Example/blob/master/Mipmap/VkTools/System/sampler.cpp#L28) you always set the maxLod member of your samplers to zero, so your lod is always clamped between 0.0 and 0.0 (minLod/maxLod). This would fit the behaviour you described.
So try setting the maxLod member of your sampler creation info to the actual number of mip maps in your texture and changing the lod level in the shader shoudl work fine.

Read from one texture and write to a separate texture with in the same frame buffer

I have a Framebuffer with 2 textures attached is it possible to read from texture A and write to texture B, in the same fragment shader function ?
Thanks.
This is trickier than I expected. I thought that as long as you don't sample from and render to the same texture you would be fine, no matter if the texture is attached to an FBO. But while trying to find some conclusive spec quotes to back this up, things became much less clear.
The 4.5 spec does contain a phrase that seems to confirm my initial instinct (emphasis added):
Specifically, the values of rendered fragments are undefined if any shader stage fetches texels and the same texels are written via fragment shader outputs, even if the reads and writes are not in the same draw call
The interesting aspect is that the "written via fragment shader outputs" does not appear in spec versions up to and including 4.4. I don't know if adding this in 4.5 was intended as just a clarification, or if the rules for feedback loops were relaxed in 4.5. I couldn't find anything in the change log that would provide more background on the change.
Up to 4.4, the spec says that if a texture is attached to the current draw framebuffer, and is sampled, you have a feedback loop. Since nothing says otherwise, this would include the situation where the texture is attached to the FBO, but not used as a draw buffer.
I wouldn't be surprised if things mostly work fine as long as you don't render to and sample from the same texture. But to be completely safe, particularly if you don't rely on having OpenGL 4.5, you should un-attach the sampled texture from the FBO. Not including it in the list of draw buffers would be insufficient.
Extending Reto's answer.
You can read from texture A and write to texture B, BUT you cannot do this:
uniform sampler2D B; // Sampler for texture B.
layout (location = 0) out vec3 A; // Write to texture
A = texture(B,Texcoord);
This is invalid, and you must use a tertiary variable.
You cannot read and write to the texture on the same draw call, but you can read from one texture and write to another texture that both reside on the same framebuffer in the same draw call. You have to make sure when you bind the frame buffer you bind it like this.
glbindframebuffer(GL_FRAMEBUFFER, fboHandle)
This is because the framebuffer will be written to and read from and the `GL_FRAMEBUFFER, will allow you to do this.

Create an image2D from a uint64_t image handle

To use bindless images in OpenGL, you need to create a GLuint64 handle using glGetImageHandleARB. You can then set this handle to a uniform image2D variable and use the image as if you had bound it the old way. No problems with that. With textures/samplers, it is further possible to set the (texture) handle not to a sampler2D, but to a plain uniform uint64_t variable. This handle can then be used to "construct" a sampler object at runtime with the constructor sampler2D(handle).
The extension description says:
Samplers are represented using 64-bit integer handles, and may be
converted to and from 64-bit integers using constructors.
and
Images are represented using 64-bit integer handles, and may be
converted to and from 64-bit integers using constructors.
So I would assume that the construction for images works the same way as it does for samplers, but this is not the case. Sample code:
#version 450
#extension GL_ARB_bindless_texture : enable
#extension GL_NV_gpu_shader5 : enable
layout(bindless_image, rgba8) uniform image2D myBindlessImage;
uniform uint64_t textureHandle;
uniform uint64_t imageHandle;
void main()
{
sampler2D mySampler = sampler2D(textureHandle); // works like a charm
... = texture(mySampler, texCoord);
... = imageLoad(myBindlessImage, texCoordI); // works like a charm
layout(rgba8) image2D myImage = image2D(imageHandle); // error C7011: implicit cast from "uint64_t" to "int"
... = imageLoad(myImage, texCoordI);
}
Apparently, neither the image2D(uint64_t) constructor nor the image2D(uvec2) constructor mentioned in the extension description are known to the compiler. Am I missing something here or is this simply not implemented right now, although it should be? The video driver I am using right now is Nvidia's 355.82. I would be glad if someone could shed some light on whether this works with any other driver/vendor's card.
By the way, why would I need that feature: In contrast to texture handles, image handles do not identify the whole underlying data, but only one texture level. If you want to do any mipmap or otherwise hierarchical work in shaders and need to bind several/all texture levels, you could provide the handles of all levels in a buffer and then construct them at shader runtime as needed. Right now, you have to define n different uniform image2Ds for your n texture levels, which is rather tedious, especially if the image size changes.
Addendum: The fastest way to reproduce the compile error is to just put image2D(0lu); somewhere in your shader code.
The syntax you're using is wrong. The correct syntax to cast a uint64_t to an image is:
layout(rgba8) image2D myImage = layout(rgba8) image2D(imageHandle);
It is required to specify the format multiple times. I have no idea why, nor why it's even required to specify the format at all. The spec is woefully vague on this.

OpenGL - layout informations

I have GLSL compute shader. Very simple one. I specify input texture and output image, mapped to the texture.
layout (binding=2) uniform sampler2D srcTex;
layout (binding=5, r32f) writeonly uniform image2D destTex;
In my code, I need to call glBindImageTexture to attach texture to image. Now, first parameter of this function is
unit
Specifies the index of the image unit to which to bind the texture
I know, that I can set this value to 5 from code manually, but how to do this automatically.
If I create shader I use refraction to get variable names and its locations.
How can I get binding ID?
How can I get texture format from layout (r32f) to set it in my code automatically?
If I create shader I use refraction to get variable names and its locations.
I think you mean reflection and not refraction, assuming you mean the programming language concept.
Now, the interesting thing here is that image2D and sampler2D are what are known as opaque types in GLSL (handles to an image unit). Ordinarily, you could use the modern glGetProgramResource* (...) API (GL_ARB_program_interface_query or core in 4.3) to query really detailed information about uniforms, buffers, etc. in a GLSL shader. However, opaque types are not considered program resources by GLSL and are not compatible with that feature - the information you want is related to the image unit the uniform references and not the uniform itself.
How can I get binding ID?
This is fairly straight-forward.
You can call glGetUniformiv (...) to get the value assigned to your image2D. On the GL-side of things opaque uniforms work no differently than any other uniform (for assigning and querying values), but in GLSL you cannot assign a value to an opaque data type using the = operator. That is why the layout (binding = ...) semantics were created, they allow you to assign the binding in the shader itself rather than having to call an API function and are completely optional.
How can I get texture format from layout (r32f) to set it in my code automatically?
That is not currently possible, and in the future may become irrelevant for loads (it already is for stores). You do not technically need an exact match here. As long as image format size / class match, you can do an image load no problem.
In truth, the only reason you have to declare the format in GLSL is so that the return format for imageLoad (...) is known at compile-time (that makes it irrelevant for writeonly qualified images). There is an EXT extension right now (GL_EXT_shader_image_load_formatted) that completely eliminates the need to establish the image format for non-writeonly images.
Even for non-writeonly images, since only the size / class need to match, I do not think you really need this. r32f has an image class of 1x32 and a size of 32, but the fact that it is floating-point is not relevant to anything. Thus, what you might really consider is naming your uniforms by their image class instead - call this uniform something like destTex_1x32 and it will be obvious that it's a 1-component 32-bit image.

glUniform fails to set sampler value

I'm using OpenGL and GLSL to draw a texture over a simple mesh.
My problem is that when I am using glUniform1i to set the value of a sampler2D uniform, it was not set. For example in the in this code:
glUseProgram(programObject);
glUniform1i(glGetUniformLocation(programObject, "texture"), 1);
GLint val;
glGetUniformiv(programObject,
glGetUniformLocation(programObject, "texture"),
&val);
printf("Value is %d\n", val);
The value printed at command line out is 0. I have checked that the shaders are compiled correctly and the program is linked correctly. glGetUniformLocation outputs an index > 0. Furthermore, glGetError doesn't output any error at any point.
This only happens when the uniform is a sampler. As the texture is not set, quering it in the shader always returns (0, 0, 0, 1). (I have also checked, using apitrace, that my texture is correctly bound to GL_TEXTURE1, which is done inmediately after the code shown).
I have searched extensively for this problem and I have only found one instance of something similar to this here. The solution was to initialize GLEW, but this hasn't worked for me.
I'm happy to provide any extended info needed (or the trace from apitrace).
Edit
Here is the shader:
uniform sampler2D texture;
varying vec2 textureCoord;
void main() {
gl_FragColor = texture2D(texture, textureCoord);
}
Solution
I managed to solve the problem after some work.
As it turns out, this problem wasn't due to the uniform not being set, as always returning 0 for samplers regardless of actual value appears to be a quirk of the gl implementation. This happened under Intel's driver for Sandy Bridge only. Testing the code under other implementations always returned the correct sampler value.
The problem of the texture returning (0, 0, 0, 1) always was due to a mistake I made during the generation of the texture.
Now the glGerUniformiv still returns 0, but the texture used is the correct one.
Solution
I managed to solve the problem after some work.
As it turns out, this problem wasn't due to the uniform not being set, as always returning 0 for samplers regardless of actual value appears to be a quirk of the gl implementation. This happened under Intel's driver for Sandy Bridge only. Testing the code under other implementations always returned the correct sampler value.
The problem of the texture returning (0, 0, 0, 1) always was due to a mistake I made during the generation of the texture.
Now the glGerUniformiv still returns 0, but the texture used is the correct one.