glTexImage2d和GL_R8UI在某些GPU

时间:2017-11-20 08:16:07

标签: opengl

我正在尝试使用GL_R8UI将未签名的非标准化数据传递给着色器,但是发现在至少一个GPU上它不起作用。

ie:这有效:

glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 32, 32, 0, GL_RED, GL_UNSIGNED_BYTE, pData);

但这不是:

glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, 32, 32, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, pData);

我也正在更改着色器以使用sampler2D与usampler2D并在适当的情况下更新着色器中的数学,但发现它适用于AMD / Radeon卡,但在Intel 和NVidia 卡上失败 - usampler2D似乎总是回零。

我把最小sample program here放在一起。 #define NORMALIZED在两种方法之间切换。

所以...我的主要问题是:这只是一个驱动程序问题,还是我的代码中有其他错误导致了这个问题?

以另一种方式提出这个问题......还有什么需要改变以从GL_R8标准化数据切换到GL_R8UI非标准化数据,此外:

  1. 将调用更改为glTextImage2D
  2. 在着色器中从sampler2D更改为usampler2D
  3. 更改着色器以使用uint而非浮动
  4. 更改着色器中的数学以处理规范化与非规范化数据。
  5. 我现在已经与英特尔记录了一个错误报告:https://software.intel.com/en-us/forums/graphics-driver-bug-reporting/topic/748843

    因为这里要求的是完整的示例程序源:

    // ShaderTest.cpp : Defines the entry point for the application.
    //
    
    #include "stdafx.h"
    #include "ShaderTest.h"
    
    #include <stdlib.h>
    #include <stdint.h>
    #include <GL/gl3w.h>
    
    #pragma comment(lib, "opengl32.lib")
    
    #define NORMALIZED
    
    const char* pszVertexShader = R"***(
    
    #version 150
    
    uniform mat4 transform;
    
    attribute vec3 position;
    
    varying vec2 vPosition;
    
    void main()
    {
        gl_Position = transform * vec4(position,1.);
        vPosition = position.xy;
    }
    
    )***";
    
    
    #ifdef NORMALIZED
    
    const char* pszFragmentShader = R"***(
    
    #version 150
    
    uniform sampler2D TextureData;
    
    varying vec2 vPosition;
    
    void main()
    {
        float red = texelFetch(TextureData, ivec2(0, 0), 0).r;
        gl_FragColor = vec4(red , 0, 0, 1);
    }
    
    )***";
    
    #else
    
    const char* pszFragmentShader = R"***(
    
    #version 150
    
    uniform usampler2D TextureData;
    
    varying vec2 vPosition;
    
    void main()
    {
        // Original post had this wrong
        // float red = float(texelFetch(TextureData, ivec2(0, 0), 0)).r/255.0;
    
        // Fixed version - still fails on Intel GPUs though
        float red = float(texelFetch(TextureData, ivec2(0, 0), 0).r)/255.0;
    
        gl_FragColor = vec4(red, 0, 0, 1);
    }
    
    )***";
    
    #endif
    
    int CompileShader(GLenum type, const char* pszSource)
    {
        int iShader = glCreateShader(type);
        glShaderSource(iShader, 1, &pszSource, NULL);
        glCompileShader(iShader);
    
        // Dump log
        int length;
        glGetShaderiv(iShader, GL_INFO_LOG_LENGTH, &length);
        if (length != 0)
        {
            char* pszLog = (char*)_alloca((sizeof(char) + 10) * length);
            GLsizei len;
            glGetShaderInfoLog(iShader, length, &len, pszLog);
            OutputDebugStringA(pszLog);
        }
    
        // Check for error
        int status;
        glGetShaderiv(iShader, GL_COMPILE_STATUS, &status);
        if (status == 0)
        {
            // Clean up after failuer
            glDeleteShader(iShader);
            return 0;
        }
    
        // Success
        return iShader;
    }
    
    // Globals
    HINSTANCE hInst;
    HGLRC g_hRC;
    GLint g_iVertexShader = 0;
    GLint g_iFragmentShader = 0;
    GLint g_iShaderProgram = 0;
    GLuint g_iTexture = 0;
    GLuint g_iVertexBuffer = 0;
    
    #define glCheck() assert(glGetError() == 0)
    
    struct VERTEX
    {
        float x;
        float y;
        float z;
    };
    
    bool Setup()
    {
        // Compile shaders
        g_iVertexShader = CompileShader(GL_VERTEX_SHADER, pszVertexShader);
        g_iFragmentShader = CompileShader(GL_FRAGMENT_SHADER, pszFragmentShader);
    
        // Link program
        g_iShaderProgram = glCreateProgram();
        glAttachShader(g_iShaderProgram, g_iVertexShader);
        glAttachShader(g_iShaderProgram, g_iFragmentShader);
        glLinkProgram(g_iShaderProgram);
    
        // Dump log
        int length;
        glGetProgramiv(g_iShaderProgram, GL_INFO_LOG_LENGTH, &length);
        if (length != 0)
        {
            char* pszLog = (char*)_alloca((sizeof(char) + 10) * length);
            GLsizei len;
            glGetProgramInfoLog(g_iShaderProgram, length, &len, pszLog);
            OutputDebugStringA(pszLog);
        }
    
        // Check for error
        int status;
        glGetProgramiv(g_iShaderProgram, GL_LINK_STATUS, &status);
        if (status == 0)
            return false;
    
        // Create texture
        glGenTextures(1, &g_iTexture);
        glBindTexture(GL_TEXTURE_2D, g_iTexture);
        uint8_t* pData = (uint8_t*)_alloca(32 * 32 * sizeof(uint8_t));
        memset(pData, 128, 32 * 32 * sizeof(uint8_t));
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    #ifdef NORMALIZED
        glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, 32, 32, 0, GL_RED, GL_UNSIGNED_BYTE, pData);
    #else
        glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, 32, 32, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, pData);
    #endif
        glBindTexture(GL_TEXTURE_2D, 0);
    
        // Create vertex buffer
        glGenBuffers(1, &g_iVertexBuffer);
        glBindBuffer(GL_ARRAY_BUFFER, g_iVertexBuffer);
        VERTEX v[] = {
            { 10, 10, 0, },
            { 10, 230, 0, },
            { 310, 10, 0, },
            { 310, 230, 0, },
        };
        glBufferData(GL_ARRAY_BUFFER, sizeof(v), v, GL_STATIC_DRAW);
    
        // Done
        return true;
    }
    
    void Cleanup()
    {
        if (g_iVertexBuffer)
            glDeleteBuffers(1, &g_iVertexBuffer);
        if (g_iTexture)
            glDeleteTextures(1, &g_iTexture);
        if (g_iShaderProgram)
            glDeleteProgram(g_iShaderProgram);
        if (g_iVertexShader)
            glDeleteShader(g_iVertexShader);
        if (g_iFragmentShader)
            glDeleteShader(g_iFragmentShader);
    }
    
    void Display(RECT* prc)
    {
        // Setup viewport
        glViewport(0, 0, prc->right, prc->bottom);
    
        // Clear background
        glClearColor(0, 0, 0.5f, 1);
        glClear(GL_COLOR_BUFFER_BIT);
    
        // Setup program
        glUseProgram(g_iShaderProgram);
    
        // Bind vertex buffer
        glBindBuffer(GL_ARRAY_BUFFER, g_iVertexBuffer);
    
        // Setup vertex buffer
        int aPosition = glGetAttribLocation(g_iShaderProgram, "position");
        glEnableVertexAttribArray(aPosition);
        glVertexAttribPointer(aPosition, 3, GL_FLOAT, false, sizeof(VERTEX), 0);
    
        // Setup texture
        glActiveTexture(GL_TEXTURE0 + 0);
        glBindTexture(GL_TEXTURE_2D, g_iTexture);
        int uTextureData = glGetUniformLocation(g_iShaderProgram, "TextureData");
        glUniform1i(uTextureData, 0);
    
        // Setup ortho projection
        float left = 0;
        float right = 320;
        float top = 0;
        float bottom = 240;
        float fnear = -1;
        float ffar = 1;
        float proj[] = {
            (float)(2.0 / (right - left)), 0.0f, 0.0f, 0.0f,
            0.0f, (float)(2.0 / (top - bottom)), 0.0f, 0.0f,
            0.0f, 0.0f, (float)(-2.0 / (ffar - fnear)), 0.0f,
            (float)(-(right + left) / (right - left)), (float)(-(top + bottom) / (top - bottom)), (float)(-(ffar + fnear) / (ffar - fnear)), 1.0f
        };
        int uTransform = glGetUniformLocation(g_iShaderProgram, "transform");
        glUniformMatrix4fv(uTransform, 1, false, proj);
    
        // Draw 
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    
        glFlush();
    }
    
    bool InitOpenGLContext(HWND hWnd)
    {
        // Setup pixel format
        HDC hDC = GetDC(hWnd);
        PIXELFORMATDESCRIPTOR pfd;
        memset(&pfd, 0, sizeof(pfd));
        pfd.nSize = sizeof(pfd);
        pfd.nVersion = 1;
        pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
        pfd.iPixelType = PFD_TYPE_RGBA;
        pfd.cColorBits = 32;
        int pf = ChoosePixelFormat(hDC, &pfd);
        if (pf == 0 || !SetPixelFormat(hDC, pf, &pfd))
            return false;
        DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
        g_hRC = wglCreateContext(hDC);
        if (!g_hRC)
            return false;
    
        // Init gl3w
        wglMakeCurrent(hDC, g_hRC);
        int err = gl3wInit();
        if (err)
        {
            wglMakeCurrent(NULL, NULL);
            wglDeleteContext(g_hRC);
            g_hRC = NULL;
            return false;
        }
    
        // Setup
        if (!Setup())
        {
            assert(false);
            Cleanup();
            wglMakeCurrent(NULL, NULL);
            wglDeleteContext(g_hRC);
            g_hRC = NULL;
            return false;
        }
    
        ReleaseDC(hWnd, hDC);
        return true;
    }
    
    void CleanupOpenGLContext(HWND hWnd)
    {
        HDC hDC = GetDC(hWnd);
        wglMakeCurrent(hDC, g_hRC);
        Cleanup();  
        wglMakeCurrent(NULL, NULL);
        ReleaseDC(hWnd, hDC);
        wglDeleteContext(g_hRC);
    }
    
    
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message)
        {
            case WM_PAINT:
            {
                PAINTSTRUCT ps;
                RECT rc;
                GetClientRect(hWnd, &rc);
                HDC hdc = BeginPaint(hWnd, &ps);
                wglMakeCurrent(hdc, g_hRC);
                Display(&rc);
                wglMakeCurrent(NULL, NULL);
                EndPaint(hWnd, &ps);
            }
            break;
    
            case WM_CLOSE:
                PostQuitMessage(0);
                break;
    
            case WM_ERASEBKGND:
                return 0;
        }
    
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    
    int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
    {
        // Register Class
        WNDCLASSEXW wcex;
        wcex.cbSize = sizeof(WNDCLASSEX);
        wcex.style = CS_HREDRAW | CS_VREDRAW;
        wcex.lpfnWndProc = WndProc;
        wcex.cbClsExtra = 0;
        wcex.cbWndExtra = 0;
        wcex.hInstance = hInstance;
        wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SHADERTEST));
        wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
        wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
        wcex.lpszMenuName = NULL;
        wcex.lpszClassName = L"ShaderTest";
        wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
        RegisterClassExW(&wcex);
    
        // Create Window
        HWND hWnd = CreateWindowW(L"ShaderTest", L"ShaderTest", WS_OVERLAPPEDWINDOW,
            50, 50, 100, 100, nullptr, nullptr, hInstance, nullptr);
        if (!hWnd)
            return 7;
    
        RECT rc;
        rc.left = 0;
        rc.top = 0;
        rc.right = 320;
        rc.bottom = 240;
        AdjustWindowRect(&rc, GetWindowLong(hWnd, GWL_STYLE), FALSE);
    
        SetWindowPos(hWnd, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
    
        if (!InitOpenGLContext(hWnd))
        { 
            DestroyWindow(hWnd);
            return 7;
        }
    
        // Show window
        ShowWindow(hWnd, nCmdShow);
        UpdateWindow(hWnd);
    
        // Main message loop:
        MSG msg;
        while (GetMessage(&msg, nullptr, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    
        CleanupOpenGLContext(hWnd);
    
        DestroyWindow(hWnd);
    
        return (int) msg.wParam;
    }
    

1 个答案:

答案 0 :(得分:0)

整数纹理需要进行最近的过滤(不是线性或mipmap):

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);