Part of the geometry shader code looks like this:
layout(std430) restrict coherent buffer BufferName
{
uint bufferName[][MAX_EXPECTED_ENTRIES];
};
...
void main()
{
...
bufferName[a][b] = someValue;
...
}
Everything works as expected until I add a writeonly statement to either BufferName, bufferName or both.
With the writeonly statement I get the following error: error C7586: OpenGL does not allow reading writeonly variable 'bufferName'.
What's going on here?
All I do is writing to bufferName and the spec says that writeonly is allowed. This also happens for one-dimensional arrays within a storage block.
Thanks in advance.
Here's the full shader code (BufferName from the example is now IDsPerVertex):
#version 450
#define MAX_EXPECTED_VERTEX_PRIMITIVE_IDS 10
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
layout(std430) restrict coherent buffer IDsPerVertex
{
uint iDsPerVertex[][MAX_EXPECTED_VERTEX_PRIMITIVE_IDS];
};
layout(std430) restrict coherent buffer Counter
{
uint counter[];
};
in int ID[3]; // contains gl_VertexID
out vec4 debugColor;
uint index[3];
void writeIDsPerVertex()
{
// get the next free location for each vertex
index[0] = atomicAdd(counter[ID[0]], 1u);
index[1] = atomicAdd(counter[ID[1]], 1u);
index[2] = atomicAdd(counter[ID[2]], 1u);
// write the triangle primitive ID to each vertex list
iDsPerVertex[ID[0]][index[0]] = gl_PrimitiveIDIn;
iDsPerVertex[ID[1]][index[1]] = gl_PrimitiveIDIn;
iDsPerVertex[ID[2]][index[2]] = gl_PrimitiveIDIn;
}
void passThrough()
{
for(int i = 0; i < gl_in.length(); i++)
{
gl_Position = projection * view * model * gl_in[i].gl_Position;
debugColor = vec4(1);
EmitVertex();
}
EndPrimitive();
}
void main()
{
writeIDsPerVertex();
passThrough();
}
The full error message my environment gives me:
SHADER PROGRAM 37 LOG
Geometry info
-------------
(0) : error C7586: OpenGL does not allow reading writeonly variable 'iDsPerVertex'
Related
I am trying to get the uniform block name from a shader handle using glGetProgramResourceName().
Yet it throws (0xC0000005: Access violation executing location 0x0000000000000000) on std::vector<GLchar> blockName and I can't figure out why.
GLint numUniformBlocks = 0;
GLint maxLength;
GLsizei size;
glGetProgramiv(handle_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
glGetProgramInterfaceiv(handle_, GL_UNIFORM_BLOCK, GL_ACTIVE_RESOURCES, &numUniformBlocks);
std::array<GLenum, 3> blockProperties{GL_NAME_LENGTH, GL_NUM_ACTIVE_VARIABLES, GL_BUFFER_DATA_SIZE};
std::array<GLint, 3> blockData{};
for (int blockIx = 0; blockIx < numUniformBlocks; ++blockIx) {
glGetProgramResourceiv(handle_,GL_UNIFORM_BLOCK,blockIx,blockProperties.size(), blockProperties.data(), blockData.size(),nullptr,blockData.data()
);
//Retrieve name
//std::string blockName(blockData[0], ' ');
//std::vector<char> blockName(blockData[0]);
std::vector<GLchar> blockName; //Yes, not std::string. There's a reason for that.
blockName.resize(blockData[0]);
//GLchar* blockName = static_cast<GLchar*>(malloc(maxLength));
glGetProgramResourceName(handle_, GL_UNIFORM_BLOCK, blockIx, blockName.size(), &size, blockName.data());
}
Here is my shader
#version 400
layout (location = 0) in vec4 VertexPosition;
out vec2 TexCoords;
layout(std140) uniform Matrices_XY{
mat4 cameraToClipMatrix;
mat4 worldToCameraMatrix;
mat4 modelToWorldMatrix;
mat4 NormalMatrix;
};
void main(){
gl_Position = cameraToClipMatrix * worldToCameraMatrix * modelToWorldMatrix * vec4(VertexPosition.xy, 0.0, 1.0);
TexCoords = VertexPosition.zw;
}
I've tried std::string, std::vector<char>, GLchar* name = static_cast<GLchar*>(malloc(maxLength)) and all throw. I've tried appending '\0' and adjusting the size sent into function called but all throws. I am expecting to get the name of the lone UBO which is "Matrices_XY"
I'm on OpenGL 4.6, C++20, MSVC 2022/17.3.6, Windows Pro10, x64, MFC
I did not have function defined; once I added, all is well
glGetProgramResourceName = (PFNGLGETPROGRAMRESOURCENAMEPROC)wglGetProcAddress("glGetProgramResourceName");
I'm experimenting this frustrating error while compiling a fragment shader. If I try to compile the shader as it is :
#version 450 core
in vec2 tex_coord;
in flat int vertex_id;
out vec4 color;
layout (binding = 20) uniform sampler2D buildingTex;
layout (binding = 21) uniform sampler2D groundTex;
const int cube_vertices = 36;
const int ground_vertices = 4;
void main(void)
{
if(vertex_id < cube_vertices)
{
float scaleF = .5f;
vec2 scale = vec2(scaleF,scaleF);
color = texture(buildingTex,tex_coord*scale);
}
if(vertex_id >= cube_vertices)
{
color = texture(groundTex,tex_coord);
}
}
the compailer complains with : glsl UNEXPECTED NEW_IDENTIFIER, expecting $end.
However if I add to my fragment shader another fragment shader, that i had in another file , and then i comment all its rows like follows :
// #version 450 core
// in vec2 tex_coord;
// in flat int vertex_id;
// out vec4 color;
// layout (binding = 20) uniform sampler2D buildingTex;
// layout (binding = 21) uniform sampler2D groundTex;
// int cube_vertices;
// int ground_vertices;
// void main(void)
// {
// if(vertex_id < cube_vertices)
// {
// float scaleF = .5f;
// vec2 scale = vec2(scaleF,scaleF);
// color = texture(buildingTex,tex_coord*scale);
// //color = vec4(1.0,1.0,1.0,1.0);
// }
// if(vertex_id >= cube_vertices)
// {
// color = texture(groundTex,tex_coord);
// //color = vec4(1.0,0.0,0.0,1.0);
// }
#version 450 core
in vec2 tex_coord;
in flat int vertex_id;
out vec4 color;
layout (binding = 20) uniform sampler2D buildingTex;
layout (binding = 21) uniform sampler2D groundTex;
const int cube_vertices = 36;
const int ground_vertices = 4;
void main(void)
{
if(vertex_id < cube_vertices)
{
float scaleF = .5f;
vec2 scale = vec2(scaleF,scaleF);
color = texture(buildingTex,tex_coord*scale);
}
if(vertex_id >= cube_vertices)
{
color = texture(groundTex,tex_coord);
}
}
in this case the shader is compiled!
I tried to remove the commented line of the old code, and seems like I can remove just some of them, while others I cannot touch, to have the shader compiled.
At this moment the shader is :
// #version 450 core
// in vec2 tex_coord;
// in flat int vertex_id;
// out vec4 color;
// layout (binding = 20) uniform sampler2D buildingTex;
// layout (binding = 21) uniform sampler2D groundTex;
// int cube_vertices;
// if(vertex_id < cube_vertices)
#version 450 core
in vec2 tex_coord;
in flat int vertex_id;
out vec4 color;
layout (binding = 20) uniform sampler2D buildingTex;
layout (binding = 21) uniform sampler2D groundTex;
const int cube_vertices = 36;
const int ground_vertices = 4;
void main(void)
{
if(vertex_id < cube_vertices)
{
float scaleF = .5f;
vec2 scale = vec2(scaleF,scaleF);
color = texture(buildingTex,tex_coord*scale);
}
if(vertex_id >= cube_vertices)
{
color = texture(groundTex,tex_coord);
}
}
and seems I cannot remove anymore from the commented code.
Since this seems the most illogical problem I ever had in my life,and since the others questions having this same error warning, were solved in a way that doesn't match my case, I'm opening a new quest.
ps: I tried to make a completely new shader but it didn't work.
pps: the problem comes up after I changed the major-mode (through M-x and not modifying the init file of emacs!) of emacs in order to use the ordinary shortcut I use in cpp files, in the shaders files (.vert, .frag ...), however even restoring the default-mode and restarting emacs the shader does not compile!
EDIT: this is the method I use to load the shader
const char* Shader::loadShader(std::string shaderPath)
{
std::ifstream temp_ss(shaderPath,std::ifstream::in);
if(temp_ss)
{
char c;
char *ss = new char[shader_size];
unsigned i = 0 ;
while(temp_ss.get(c))
{
ss[i++] = c;
}
std::cout<<std::ends;
//ends adds a null, and then flushes the buffer
//if i don't use it , often, the window does not show anything
//I could use std::cout<<std::endl; in place of ends,
//but ends seem a more polite solution to me
//CHECK SHADER
for(int i = 0; i < shader_size; i++)
if(ss[i] == '\0')
std::cout<<"shader.cpp::ERROR: NULL CHARACTER FOUND ON SHADER "<<
shaderPath<<std::endl;
return ss;
}
else
std::clog<<"shader.cpp::loadShader() : ERROR ::: no shaders found at the path : "<<shaderPath<<std::endl;
}
From the OP:
TO SUMMARIZE : shader files MUST be null terminated , I modify the function that loads the shader source into the buffer like follows:
const char* Shader::loadShader(std::string shaderPath)
{
std::ifstream temp_ss(shaderPath,std::ifstream::in);
if(temp_ss)
{
char c;
char *ss = new char[shader_size];
unsigned i = 0 ;
while(temp_ss.get(c))
{
ss[i++] = c;
}
//CHECK SHADER
bool nullTerminated = false;
for(int i = 0; i < shader_size; i++)
if(ss[i] == '\0')
nullTerminated = true;
if(!nullTerminated)
ss[shader_size++] = '\0';
return ss;
}
else
std::clog<<"shader.cpp::loadShader() : ERROR ::: no shaders found at the path : "<<shaderPath<<std::endl;
}
and the fragment shader compiles!
I'm currently working with skeletal animation and I'm really close to getting it working. Currently, I have a struct that has a matrix with 100 spots ( this is so that I can max have 100 joints ) like so :
struct skelShader {
glm::mat4 currentJointTrans[100];
};
The struct should be binded in the shader, I've done it like this:
glGenBuffers(1, &sksBuff);
glBindBuffer(GL_UNIFORM_BUFFER, sksBuff);
// bind buffer to work further with it...
// allocate memory for the buffer in the GPU
glBufferData(GL_UNIFORM_BUFFER, sizeof(skelShader), NULL, GL_STATIC_DRAW);
// because we hard-coded "binding=3" in the shader code we can do this:
// bind Uniform Buffer to binding point 3 (without caring about index of UBO)
glBindBufferBase(GL_UNIFORM_BUFFER, 4, sksBuff);
// good practice, unbind buffer
glBindBuffer(GL_UNIFORM_BUFFER, 0);
sksBuff is just an GLuint.
I fill this array with new values every render/frame that goes by, these values are the new transformations for the joints. I do it like this:
for (int i = 0; i < skeleton.size(); i++) {
globalSkelInfo.currentJointTrans[i] = skeleton[i]->transformMat[currentFrame - 1] * skeleton[i]->globalBindPosMat;
}
This is working correctly for the root joint, but the rest of the joints/mesh remains in bind pose. The problem should be located in where I update the array. Currently I do it like this in the render function after I've done the multiplication for each joint:
for (int i = 0; i < skeleton.size(); i++) {
glUniformMatrix4fv(glGetUniformLocation(aShaderProgram, ("currentJointTrans[" + std::to_string(i) + "]").c_str()),
1, GL_FALSE, glm::value_ptr(globalSkelInfo.currentJointTrans[i]));
}
After this I draw. The root joints values seem to be moving correctly, but the rest of the mesh is in bindpose and doesn't move. In the Vertex Shader I try to update the matrix like this:
#version 440
const int maxJoints = 100;
const int maxWeights = 4;
layout(location = 0) in vec3 vertex_position;
layout(location = 1) in vec2 vertex_UV;
layout(location = 2) in vec3 vertex_normal;
layout(location = 3) in vec4 vertex_weight;
layout(location = 4) in ivec4 vertex_controllers;
out vec2 outUVs;
out vec3 outNorm;
layout(binding = 3 , std140) uniform uniformBlock
{
vec3 camPos;
mat4 world;
mat4 LookAt;
mat4 projection;
mat4 MVP;
};
layout(binding = 4 , std140) uniform animationStruct
{
mat4 currentJointTrans[maxJoints];
};
void main() {
vec4 finalModelPos = vec4(0.0);
vec4 finalNormal = vec4(0.0);
for (int i = 0; i < 4; i++) {
mat4 jointTrans = currentJointTrans[vertex_controllers[i]];
vec4 posePos = jointTrans * vec4(vertex_position, 1.0);
finalModelPos += posePos * vertex_weight[i];
vec4 worldNormal = jointTrans * vec4(vertex_normal, 0.0);
finalNormal += worldNormal * vertex_weight[i];
}
gl_Position = MVP * finalModelPos;
outNorm = finalNormal.xyz;
outUVs = vertex_UV;
}
My theory is that the updating of the struct skelShader with my currentJointTrans array is incorrect. Any tips on how I should do this instead?
glUniform* calls cannot set data in uniform buffers. Indeed, the whole point of uniform buffers is that the uniform data comes from a buffer object. That's why you had to create one.
So if you want to set the uniform data for a uniform block, you set that data into the buffer object.
I created two shaders for my program to render simple objects.
Vertex shader source:
#version 400 core
layout (location = 1) in vec4 i_vertexCoords;
layout (location = 2) in vec3 i_textureCoords;
layout (location = 3) in vec3 i_normalCoords;
layout (location = 4) in int i_material;
uniform mat4 u_transform;
out VertexData {
vec3 textureCoords;
vec3 normalCoords;
int material;
} vs_out;
void main() {
vs_out.textureCoords = i_textureCoords;
vs_out.material = i_material;
gl_Position = u_transform * i_vertexCoords;
vs_out.normalCoords = gl_Position.xyz;
}
Fragment shader source:
#version 400 core
struct MaterialStruct {
int ambientTexutre;
int diffuseTexture;
int specularTexture;
int bumpTexture;
vec4 ambientColor;
vec4 diffuseColor;
vec4 specularColor;
float specularComponent;
float alpha;
int illuminationModel;
};
in VertexData {
vec3 textureCoords;
vec3 normalCoords;
int material;
} vs_out;
layout (std140) uniform MaterialsBlock {
MaterialStruct materials[8];
} u_materials;
uniform sampler2D u_samplers[16];
out vec4 fs_color;
void main() {
MaterialStruct m = u_materials.materials[vs_out.material];
fs_color = vec4(m.diffuseColor.rgb, m.diffuseColor.a * m.alpha);
}
Program created with this two shaders renders picture 2
When I change main() function contents to next:
void main() {
MaterialStruct m = u_materials.materials[vs_out.material];
fs_color = vec4(m.diffuseColor.rgb * (vs_out.normalCoords.z + 0.5), m.diffuseColor.a * m.alpha);
}
It renders picture 1, but materials still exists (if I'm trying to select material from u_materials.materials manually it works). Shader thinks what vs_out.material is constant and equals 0, but it isn't. Data is not changed (excluding transformation matrix)
Could someone explain the solution of this problem?
The GLSL 4.5 spec states in section 4.3.4 "Input Variables":
Fragment shader inputs that are signed or unsigned integers, integer vectors, or any double-precision
floating-point type must be qualified with the interpolation qualifier flat.
You can't use interpolation with those types, and actually, your code shouldn't compile on a strict implementation.
I am trying to get a hold of how memoryBarrier() works in OpenGL 4.4
I tried the following once with a texture image and once with Shader Storage Buffer Object (SSBO).
The basic idea is to create an array of flags for however many objects that need to be rendered in my scene and then perform a simple test in the geometry shader.
For each primitive in GS, if at least one vertex passes the test, it
sets the corresponding flag in the array at the location specified
by this primitive's object ID (Object IDs are passed to GS as vertex
attributes).
I then perform a memoryBarrier() to make sure all threads have written their values.
Next, I have all primitives read from the flags array and only emit a vertex if the flag is set.
Here is some code from my shaders to explain:
// Vertex Shader:
#version 440
uniform mat4 model_view;
uniform mat4 projection;
layout(location = 0) in vec3 in_pos;
layout(location = 1) in vec3 in_color;
layout(location = 2) in int lineID;
out VS_GS_INTERFACE
{
vec4 position;
vec4 color;
int lineID;
} vs_out;
void main(void) {
vec4 pos = vec4(in_pos, 1.0);
vs_out.position = pos;
vs_out.color = vec4(in_colo, 1.0);
vs_out.lineID = lineID;
gl_Position = projection * model_view * pos;
}
and here is a simple Geometry shader in which I use only a simple test based on lineID ( I realize this test doesn't need a shared data structure but this is just to test program behavior)
#version 440
layout (lines) in;
layout (line_strip, max_vertices = 2) out;
layout (std430, binding = 0) buffer BO {
int IDs[];
};
in VS_GS_INTERFACE
{
vec4 position;
vec4 color;
int lineID;
} gs_in[];
out vec4 f_color;
void main()
{
if(gs_in[0].lineID < 500)
{
IDs[gs_in[0].lineID] = 1;
}
else
{
IDs[gs_in[0].lineID] = -1;
}
memoryBarrier();
// read back the flag value
int flag = IDs[gs_in[0].lineID];
if ( flag > 0)
{
int n;
for( n = 0; n < gl_in.length(), n++)
{
f_color = gs_in[n].color;
gl_Position = gl_in[n].gl_Position;
emitVertex();
}
}
}
No matter what value I put instead of 500, this code always renders only 2 objects. If I change the condition for rendering in the GS to if( flag > = 0) it seems to me that all objects are rendered which means the -1 is never written by the time these IDs are read back by the shader.
Can someone please explain why the writes are not coherently visible to all shader invocations despite the memoryBarrier() and what would be the most efficient work around to get this to work?
Thanks.