简体   繁体   中英

OpenGL + SDL2 + Compute Shader = black screen

I'm translating a C raytracer into glsl so I can use it in a compute shader. For now I'm just trying to render some fuzzy patterns on screen. There are no compilation errors, however nothing renders.

I was following these two tutorials (the latter is fairly incomplete and leaves some portions out, I might have missed some stuff there) SDL2 with OpenGL - Lee Zhi Eng Compute Shaders - Anton's OpenGL4 Tutorials

I'm not an expert in opengl, so I'm not sure if the shader outputs to the texture? Or is the texture not drawn? Or is the issue elsewhere?

Please post the exact syntax instead of just a vague instruction like "you need to do x by initializing y and flushing z" because I probably won't know the syntax to do xyz.

Mind you: the main program is still in C, not C++.

Compiled with: -std=gnu18 -ffast-math -O3 -lm -lGLEW -lGL -lglut -Wall -pedantic -Werror -Wshadow -Wstrict-aliasing -Wstrict-overflow

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include <math.h>

#define GLEW_STATIC
#include <GL/glew.h>
#include <GL/glu.h>
#include <GL/gl.h>

#include <SDL2/SDL.h>

int main(void)
{
    int tex_w = 1920;
    int tex_h = 1080;



    //////////////////////
    //
    //   SDL Stuff

    if (SDL_Init(SDL_INIT_VIDEO) < 0){
        printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
        return EXIT_FAILURE;
    }

    SDL_Window * window;
    window = SDL_CreateWindow(
        "Rendering first frame", 
        SDL_WINDOWPOS_UNDEFINED, 
        SDL_WINDOWPOS_UNDEFINED, 
        tex_w*scale, 
        tex_h*scale, 
        SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE
    );

    if (window == NULL){
        printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());
        return EXIT_FAILURE;
    }

    #ifdef FULLSCREEN
    SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
    #endif

    SDL_Event event;



    //////////////////////
    //
    //   GL Stuff

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

    SDL_GLContext glContext = SDL_GL_CreateContext(window);

    if (glContext == NULL){
        printf("OpenGL context could not be created! SDL Error: %s\n", SDL_GetError());
        return EXIT_FAILURE;
    }

    glewInit();

    GLuint tex_output;
    glGenTextures(1, &tex_output);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, tex_output);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, tex_w, tex_h, 0, GL_RGBA, GL_FLOAT, NULL);
    glBindImageTexture(0, tex_output, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);



    //////////////////////
    //
    //   init compute shader

        const GLchar *the_ray_shader_string = "#ifdef GL_ES\
precision mediump float;\
#endif\
\
#extension GL_OES_standard_derivatives : enable\
\
uniform float time;\
uniform vec2 mouse;\
uniform vec2 resolution;\
layout(local_size_x = 1, local_size_y = 1) in;\
layout(rgba32f, binding = 0) uniform image2D img_output;\
\
void main( void ) {\
\
    vec2 position = ( gl_FragCoord.xy / resolution.xy ) + mouse / 4.0;\
\
    float color = 0.0;\
    color += sin( position.x * cos( time / 15.0 ) * 80.0 ) + cos( position.y * cos( time / 15.0 ) * 10.0 );\
    color += sin( position.y * sin( time / 10.0 ) * 40.0 ) + cos( position.x * sin( time / 25.0 ) * 40.0 );\
    color += sin( position.x * sin( time / 5.0 ) * 10.0 ) + sin( position.y * sin( time / 35.0 ) * 80.0 );\
    color *= sin( time / 10.0 ) * 0.5;\
\
    gl_FragColor = vec4( vec3( color, color * 0.5, sin( color + time / 3.0 ) * 0.75 ), 1.0 );\
\
}\0";

    GLuint ray_shader = glCreateShader(GL_COMPUTE_SHADER);
    glShaderSource(ray_shader, 1, &the_ray_shader_string, NULL);
    glCompileShader(ray_shader);

    GLuint ray_program = glCreateProgram();
    glAttachShader(ray_program, ray_shader);
    glLinkProgram(ray_program);


    int delta, leftToWait;

    int startTime, i = 0;

    while (++i && demoRunning)
    {
        startTime = SDL_GetTicks();

        SDL_PollEvent(&event);
        demoHandleInput(&event);

        glClear(GL_COLOR_BUFFER_BIT);

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, tex_output);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

        glUseProgram(ray_program);
        glDispatchCompute((GLuint)tex_w, (GLuint)tex_h, 1);

        glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);

        SDL_GL_SwapWindow(window);

        delta = SDL_GetTicks() - startTime;
        leftToWait = (16 - delta); // aim for 60 fps

        if (leftToWait > 0){
            SDL_Delay(leftToWait);
        }
    }

    SDL_DestroyWindow(window);
    SDL_Quit();

    return EXIT_SUCCES;
}

What you call a compute shader actually is more a Fragment Shader than a Compute Shader . gl_FragCoord is a fragment shader built-in input and gl_FragColor is a (deprecated) fragment shader output variable. Attached to a GL_COMPUTE_SHADER shader object, this shader will fail to compile.

You've to usegl_GlobalInvocationID to identify the invocation and you've to use imageStore to write a texel to the output image ( img_output ). eg:

#version 460

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;
layout(local_size_x = 1, local_size_y = 1) in;
layout(rgba32f, binding = 0) uniform image2D img_output;

void main( void ) {

    vec2 position = vec2(gl_GlobalInvocationID.xy) / resolution.xy + mouse / 4.0;

    float color = 0.0;
    color += sin( position.x * cos( time / 15.0 ) * 80.0 ) + cos( position.y * cos( time / 15.0 ) * 10.0 );
    color += sin( position.y * sin( time / 10.0 ) * 40.0 ) + cos( position.x * sin( time / 25.0 ) * 40.0 );
    color += sin( position.x * sin( time /  5.0 ) * 10.0 ) + sin( position.y * sin( time / 35.0 ) * 80.0 );
    color *= sin( time / 10.0 ) * 0.5;

    vec4 pixel = vec4( vec3( color, color * 0.5, sin( color + time / 3.0 ) * 0.75 ), 1.0 );
    imageStore(img_output, ivec2(gl_GlobalInvocationID.xy), pixel);
}

But note, this won't draw anything to the window (default framebuffer), the target of the computer shader is an image. The compute shader just sets the pixel in the image.
If you want to "see" the image on the display then you've to render a quad with the texture object on it or attach the texture to a framebuffer and "blit" ( glBlitFramebuffer ) it to the default framebuffer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM