2

I've looked at other peoples implementation of it, and I'm still not sure what I'm doing wrong. My graphics drivers are up to date, and I'm getting no error messages.

I'm trying to use a GLSL compute shader to write to a texture which is then rendered onto a screen-size quad.

Here is the code for my main.cpp:

unsigned int hRes = 512;
unsigned int vRes = 512;

int main(void) {

    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow* window = glfwCreateWindow(hRes, vRes, "Learn OpenGL", NULL, NULL);

    if (window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }

    glfwMakeContextCurrent(window);

    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    glViewport(0, 0, hRes, vRes);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    //
    float vertices[] = {
         // positions     // Tex coords
         1.f,  1.f, 0.0f,  1.f,  1.f, // top right
         1.f, -1.f, 0.0f,  1.f,  0.f,  // bottom right
        -1.f, -1.f, 0.0f,  0.f,  0.f,  // bottom left
        -1.f,  1.f, 0.0f,  0.f,  1.f,   // top left 
    };
    unsigned int indices[] = {  
        0, 1, 3,   // first triangle
        1, 2, 3    // second triangle
    };

    unsigned int VAO;
    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    unsigned int VBO;
    glGenBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(0));
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3));
    glEnableVertexAttribArray(1);


    unsigned int EBO;
    glGenBuffers(1, &EBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);


    unsigned int texture;
    glGenTextures(1, &texture);


    glBindTexture(GL_TEXTURE_2D, texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    float borderColor[] = { 1.0f, 1.0f, 0.0f, 1.0f };
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);


    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, hRes, vRes, 0, GL_RGBA, GL_FLOAT, NULL);
    glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);

    // Vertex and fragment shaders are pretty much empty, and just pass through vertex/texture coord data
    Shader vertex("doNothing.vert", GL_VERTEX_SHADER);
    Shader fragment("doNothing.frag", GL_FRAGMENT_SHADER);
    ShaderProgram renderProg;
    renderProg.attach(vertex);
    renderProg.attach(fragment);
    renderProg.link();

    Shader computeShader("julia.comp", GL_COMPUTE_SHADER);
    ShaderProgram computeProg;
    computeProg.attach(computeShader);
    computeProg.link();

    while (!glfwWindowShouldClose(window))
    {
        // Input (currently does nothing)
        processInput(window);

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        computeProg.use();
        glDispatchCompute(hRes / 16, vRes / 16, 1); // For local work group size 16. Ensures entire texture is written to

        glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);

        renderProg.use();
        glBindTexture(GL_TEXTURE_2D, texture);
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);


        // End drawing current frame
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteBuffers(1, &EBO);
    glfwTerminate();
    return 0;
    }

ShaderProgram and Shader are just helper classes that wrap the OpenGL object ID.

Shader code: doNothing.frag:

#version 460 core
out vec4 FragColor;

in vec2 TexCoord;
uniform sampler2D ourTexture;

void main()
{
    FragColor = texture(ourTexture, TexCoord);
}

doNothing.vert:

#version 460 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;

out vec2 TexCoord;

void main()
{
    gl_Position = vec4(aPos, 1.0);
    TexCoord = aTexCoord;
}

julia.comp:

#version 460
layout (binding = 0, rgba32f) uniform writeonly image2D destTex;
layout (local_size_x = 16, local_size_y = 16) in;
void main() {
    ivec2 storePos = ivec2(gl_GlobalInvocationID.xy);

    if(storePos.x > 100){
        imageStore(destTex, storePos, vec4(0., 0., 1.0, 1.0));
    }else{
        imageStore(destTex, storePos, vec4(1., 0., 0.0, 1.0));
    }
}

I expected this code to output an image where one portion was red, and the other portion was blue. What instead happens is that it outputs a single-colour image where the entire screen is a blend of the red and blue colours.

I have played around with the conditions inside of the julia.comp shader, and it seems that if I set the conditions such that the corners are each coloured differently, I get a blend of the corner colours (E.G. if I set the condition to storePos.x > 100 && storePos.x < 511 I get only the colour from the else block, but if I set it to storePos.x > 100 && storePos.x < 513 I get a blend of both colours.

Any help would be appreciated.

EDIT: image of what I get: image of what I get

And this is what happens if I replace vec4(0., 0., 1., 1.) with vec4(0., 1., 0., 1.) in the "if" code block:

yellow

Which is why I believe it is blending the colours somehow. (Note that the yellow colour is also fairly dim, which suggests the colours have been averaged, not added together)

EDIT: I tried setting the magnification filter to GL_NEAREST, and this results in a bright red texture across the entire screen. (No blending between the two colours)

EDIT: the post "OpenGL compute shader - strange results" does not solve my problem. That askers problem was with a particular library he was using for their matrix calculations, and I am not even using a single matrix in my answer. I have also tried other suggestions people on that post had, and none of them worked.

Trevor Galivan
  • 373
  • 2
  • 13
  • Can you post a picture of what you get? – Nathan Wride May 25 '20 at 22:20
  • Sure thing, added the image. – Trevor Galivan May 25 '20 at 22:23
  • 2
    I'm guessing this has to do with uv coordinates being incorrectly set – Elijah Seed Arita May 25 '20 at 23:02
  • @Elihah Seed Arita do you know how I could fix my UV coordinates then? My understanding is that UV coordinates should always be in the [0, 1] range, and the coords seem to match up with those used in the vertices. – Trevor Galivan May 25 '20 at 23:10
  • @TrevorGalivan: "*That askers problem was with a particular library he was using for their matrix calculations, and I am not even using a single matrix in my answer.*" No, that problem was (in part) with which memory barrier was being used. And you're making the same mistake. – Nicol Bolas May 25 '20 at 23:25
  • @NicolBolas The asker stated that that did not solve his problem, but that the problem was with the matrix constructor. That said, I did try changing the memory barrier, and it did not change the result. It is possible that the memory barrier could cause problems down the line so thank you for catching it, but I don't think this is the immediate problem. – Trevor Galivan May 25 '20 at 23:27
  • @TrevorGalivan: Then modify your code to use the correct memory barrier, and I'll unmark it as a duplicate. – Nicol Bolas May 25 '20 at 23:31
  • @NicolBolas changes have been made. Thanks. – Trevor Galivan May 25 '20 at 23:34
  • @TrevorGalivan: No, that's the memory barrier that solved *his* problem, because he was reading from it via `glGetTexImage`. You are sampling from it as a texture, so you have to use a memory barrier appropriate to that usage. – Nicol Bolas May 25 '20 at 23:53
  • @NicolBolas Alright, I changed it again, I'm not sure exactly which bit is appropriate, so please bear with me. However, I also want to point out that even with `GL_ALL_BARRIER_BITS` , the issue still appears, so this is definitely not the issue. – Trevor Galivan May 26 '20 at 00:02

1 Answers1

4

The offset to glVertexAttribPointer is in bytes. You pass a (void*)(3) for what should be (void*)(3*sizeof(float)):

glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3*sizeof(float))); // <--- here
Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
  • 1
    This solved the problem. Thank you so much! I should have realized since the `stride` parameter before it takes an argument in bytes. – Trevor Galivan May 26 '20 at 01:03