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

即:这有效:

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非规范化数据,还需要更改什么?


更改对glTextImage2D的调用
从着色器中的sampler2D更改为usampler2D
更改着色器以使用uint而不是floats
更改着色器中的数学运算以处理规范化和非规范化数据。




我现在已经在英特尔中记录了一个错误报告: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;
}

最佳答案

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

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

07-27 13:18