Search code examples
shaderrenderdoc

RenderDoc wont let me debug?


enter image description hereIve got this simple shader code that I want to step through. I launch the program in RenderDoc. I select a pixel, but the option to debug is grayed out. Why? and how can I fix it?

Im assuming it may have something to do with the version of glsl not being supported?

Im using AMD Radeon RX 6650 XT on Windows 11

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <string>

// Vertex Shader Source
const char* vertexShaderSource = R"(
#version 330 core
layout (location = 0) in vec3 aPos;
void main() {
    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}
)";

// Fragment Shader Source
const char* fragmentShaderSource = R"(
#version 330 core
out vec4 FragColor;

const int emax = 127;

int floorLog2(float x) {
    if (x == 0.) return -emax;
    for (int e = emax; e >= 1 - emax; --e)
        if (x >= exp2(float(e))) return e;
    return emax + 1;
}

int biasedExp(float x) {
    return emax + floorLog2(abs(x));
}

float significand(float x) {
    float expo = float(floorLog2(abs(x)));
    return abs(x) / exp2(expo);
}

int part(float x, int N) {
    const float byteShift = 256.;
    for (int n = 0; n < N; ++n)
        x *= byteShift;
    float q = fract(x);
    float c = floor(byteShift * q);
    return int(c);
}

ivec3 significandAsIVec3(float x) {
    ivec3 result;
    float sig = significand(x) / 2.;
    result.x = part(sig, 0);
    result.y = part(sig, 1);
    result.z = part(sig, 2);
    return result;
}

ivec4 unpackIEEE754binary32(float x) {
    int e = biasedExp(x);
    int s = x < 0. ? 128 : 0;
    ivec4 binary32;
    binary32.yzw = significandAsIVec3(x);
    if (binary32.y >= 128) {
        binary32.y -= 128;
    }
    binary32.y += 128 * int(mod(float(e), 2.));
    e /= 2;
    binary32.x = e + s;
    binary32.x -= 1;
    binary32.y -= 1;
    binary32.z -= 1;
    binary32.w -= 1;
    return binary32;
}

void main() {
    float testValue = 3.0;
    ivec4 result = unpackIEEE754binary32(testValue);
    
    // Normalize the result to see the output
    vec4 color = vec4(
        float(result.x) / 255.0,
        float(result.y) / 255.0,
        float(result.z) / 255.0,
        float(result.w) / 255.0
    );
    FragColor = color;
}
)";

GLFWwindow* createWindow() {
    if (!glfwInit()) {
        std::cerr << "Failed to initialize GLFW" << std::endl;
        return nullptr;
    }

    // Request OpenGL Debug Context
    glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE);

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow* window = glfwCreateWindow(800, 600, "Shader Debug", NULL, NULL);
    if (!window) {
        std::cerr << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return nullptr;
    }

    glfwMakeContextCurrent(window);
    return window;
}

void APIENTRY openglDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity,
                                  GLsizei length, const GLchar* message, const void* userParam) {
    std::cerr << "OpenGL Debug Message: " << message << std::endl;
}

GLuint compileShader(const char* shaderSource, GLenum shaderType) {
    GLuint shader = glCreateShader(shaderType);
    
    // Provide the shader source code
    glShaderSource(shader, 1, &shaderSource, nullptr);
    
    // Compile the shader with debug info (if supported)
    glCompileShader(shader);

    // Check for compile errors
    GLint success;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
    
    if (!success) {
        // Retrieve and print the error log
        GLchar infoLog[1024];
        glGetShaderInfoLog(shader, 1024, NULL, infoLog);
        const char* shaderTypeStr = shaderType == GL_VERTEX_SHADER ? "VERTEX" : "FRAGMENT";
        std::cerr << "ERROR::SHADER_COMPILATION_ERROR of type: " << shaderTypeStr << "\n" 
                  << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
    }

    return shader;
}

GLuint createShaderProgram() {
    GLuint vertexShader = compileShader(vertexShaderSource, GL_VERTEX_SHADER);
    GLuint fragmentShader = compileShader(fragmentShaderSource, GL_FRAGMENT_SHADER);

    // Create the shader program
    GLuint shaderProgram = glCreateProgram();
    
    // Attach shaders
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    
    // Link the program
    glLinkProgram(shaderProgram);

    // Check for linking errors
    GLint success;
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    
    if (!success) {
        // Retrieve and print the error log
        GLchar infoLog[1024];
        glGetProgramInfoLog(shaderProgram, 1024, NULL, infoLog);
        std::cerr << "ERROR::PROGRAM_LINKING_ERROR\n" 
                  << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
    }

    // Delete the shaders as they're linked into our program now and no longer needed
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    return shaderProgram;
}

int main() {
    GLFWwindow* window = createWindow();
    if (!window) return -1;

    // Initialize GLEW with experimental features enabled
    glewExperimental = GL_TRUE; 
    if (glewInit() != GLEW_OK) {
        std::cerr << "Failed to initialize GLEW" << std::endl;
        return -1;
    }

    // Enable OpenGL debug output if available
    GLint flags;
    glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
    if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) {
        std::cout << "Debug context active" << std::endl;
        glEnable(GL_DEBUG_OUTPUT);
        glDebugMessageCallback(openglDebugCallback, nullptr);
    }

    // Vertex data for a full-screen quad
    float vertices[] = {
        // positions
        -1.0f,  1.0f, 0.0f,  // top left
        -1.0f, -1.0f, 0.0f,  // bottom left
         1.0f,  1.0f, 0.0f,  // top right
         1.0f, -1.0f, 0.0f   // bottom right
    };

    // Set up vertex data and buffers
    GLuint VBO, VAO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    
    // Bind Vertex Array Object
    glBindVertexArray(VAO);
    
    // Bind and set vertex buffer(s)
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    
    // Configure vertex attributes
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // Create shader program
    GLuint shaderProgram = createShaderProgram();

    // Render loop
    while (!glfwWindowShouldClose(window)) {
        // Clear the screen
        glClear(GL_COLOR_BUFFER_BIT);
        
        // Use shader program and draw
        glUseProgram(shaderProgram);
        glBindVertexArray(VAO);
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

        // Swap buffers and poll IO events
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // Cleanup resources
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    glDeleteProgram(shaderProgram);

    // Terminate GLFW
    glfwTerminate();
    return 0;
}

Solution

  • According to RenderDoc's How do I debug a shader page, OpenGL shader debugging is not supported.

    Shader debugging is currently only supported on D3D11, D3D12, and Vulkan.

    If you hover over the Debug button, RenderDoc shows a tooltip, saying

    Shader debugging not supported on this API

    The good news is that even the newest GLSL version is supported by RenderDoc, you can use it with Vulkan for example. Also, if you use another API, make sure to select a draw call in the Event Browser, because RenderDoc has to know which draw call do you want to debug.