2012-12-30 198 views
1

這比出於任何實際目的更加出於好奇:OpenGL規範中是否有任何建議多次調用glTexImage2D(例如,每幀一次)是非法的?我的意思是非法,因爲'它可能會產生錯誤的結果',而不僅僅是效率低下(假設我不關心不使用glTexSubImage2D而不考慮性能影響)。OpenGL重複調用glTexImage2D和alpha混合

我問的原因是,當繪製重疊的紋理映射圖元時,我注意到一些非常奇怪的圖元,它們使用部分透明的圖元,每個圖片使用glTexImage2D(見附圖)加載一次:after幾秒鐘(即幾百幀),屏幕上出現小的矩形黑色補丁(它們實際上在連續幀之間在黑色和正常之間翻轉)。

Artifacts

我附加下面的最簡單的示例代碼可以寫表現出的問題。

#include <stdio.h> 

#ifndef __APPLE__ 
# include <SDL/SDL.h> 
# include <SDL/SDL_opengl.h> 
#else 
# include <SDL.h> 
# include <SDL_opengl.h> 
#endif 

/* some constants and variables that several functions use */ 
const int width = 640; 
const int height = 480; 
#define texSize 64 

GLuint vbo; 
GLuint tex; 

/* forward declaration, creates a random texture; uses glTexSubImage2D if 
    update is non-zero (otherwise glTexImage2D) */ 
void createTexture(GLuint label, int update); 

int init() 
{ 
    /* SDL initialization */ 
    if (SDL_Init(SDL_INIT_VIDEO) < 0) 
    return 0; 

    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 
    if (!SDL_SetVideoMode(width, height, 0, SDL_OPENGL)) { 
    fprintf(stderr, "Couldn't initialize OpenGL"); 
    return 0; 
    } 

    /* OpenGL initialization */ 
    glClearColor(0, 0, 0, 0); 
    glEnable(GL_TEXTURE_2D); 
    glEnable(GL_BLEND); 
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 

    glViewport(0, 0, width, height); 

    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    glOrtho(0, width, height, 0, -1, 1); 
    glMatrixMode(GL_MODELVIEW); 

    /* creating the VBO and the textures */ 
    glGenBuffers(1, &vbo); 
    glBindBuffer(GL_ARRAY_BUFFER, vbo); 
    glBufferData(GL_ARRAY_BUFFER, 1024, 0, GL_DYNAMIC_DRAW); 

    glGenTextures(1, &tex); 
    createTexture(tex, 0); 

    glEnableClientState(GL_VERTEX_ARRAY); 
    glEnableClientState(GL_TEXTURE_COORD_ARRAY); 

    return 1; 
} 

/* draw a triangle at the specified point */ 
void drawTriangle(GLfloat x, GLfloat y) 
{ 
    GLfloat coords1[12] = {0, 0, 0, 0, /**/200, 0, 1, 0, /**/200, 150, 1, 1}; 

    glLoadIdentity(); 
    glTranslatef(x, y, 0); 

    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(coords1), coords1); 
    glVertexPointer(2, GL_FLOAT, 4*sizeof(GLfloat), (void*)0); 
    glTexCoordPointer(2, GL_FLOAT, 4*sizeof(GLfloat), 
    (char*)0 + 2*sizeof(GLfloat)); 

    glDrawArrays(GL_TRIANGLES, 0, 3); 
} 

void render() 
{ 
    glClear(GL_COLOR_BUFFER_BIT); 

    drawTriangle(250, 50); 

    createTexture(tex, 0); 
    drawTriangle(260, 120); 

    SDL_GL_SwapBuffers(); 
} 

void cleanup() 
{ 
    glDeleteTextures(1, &tex); 
    glDeleteBuffers(1, &vbo); 

    SDL_Quit(); 
} 

int main(int argc, char* argv[]) 
{ 
    SDL_Event event; 

    if (!init()) return 1; 

    while (1) { 
    while (SDL_PollEvent(&event)) 
     if (event.type == SDL_QUIT) 
     return 0; 

    render(); 
    } 

    cleanup(); 

    return 0; 
} 

void createTexture(GLuint label, int update) 
{ 
    GLubyte data[texSize*texSize*4]; 
    GLubyte* p; 
    int i, j; 

    glBindTexture(GL_TEXTURE_2D, label); 

    for (i = 0; i < texSize; ++i) { 
    for (j = 0; j < texSize; ++j) { 
     p = data + (i + j*texSize)*4; 
     p[0] = ((i % 8) > 4?255:0); 
     p[1] = ((j % 8) > 4?255:0); 
     p[2] = ((i % 8) > 4?255:0); 
     p[3] = 255 - i*3; 
    } 
    } 

    if (!update) 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texSize, texSize, 0, GL_RGBA, 
     GL_UNSIGNED_BYTE, data); 
    else 
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texSize, texSize, GL_RGBA, 
     GL_UNSIGNED_BYTE, data); 

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
} 

注:

  1. 我使用SDL,但我已經看到了wxWidgets的相同情況發生,所以它不是一個SDL相關的問題。

  2. 如果我用glTexSubImage2D代替每個幀(使用update = 1,createTexture),那麼工件消失。

  3. 如果我禁用混合,則不會有更多的工件。

  4. 我一直在2010年底的MacBook Air上進行測試,儘管我懷疑這是特別相關的。

+0

只是出於興趣......如果你將createTexture移動到第一個drawTriangles之前......它工作嗎? (我懷疑驅動程序紋理同步路徑中存在一個錯誤) – Goz

+0

@Goz如果我在'drawTriangle'前面移動'createTexture',問題就會消失。我想我沒有真正考慮驅動程序中的錯誤......當我有機會時,我會在其他系統上嘗試代碼。 – Legendre17

+0

基本上,它看起來像系統正在更新紋理,而它仍然在之前的繪製調用中使用。我猜想關閉alpha混合會影響渲染路徑,直到紋理更改沒有發生,而前一次繪製正在進行中。過去寫過驅動程序是一個非常基本的(而且很容易實現)的錯誤。你最好的選擇是解決它,並接受它失控。仍然值得將這個bug發佈給蘋果,希望他們能夠修復驅動程序! – Goz

回答

1

這顯然是一個OpenGL的實現bug(只是在循環中調用glTexImage2D不應該導致這種情況發生)。

+0

這很好,這可能只是一個錯誤。這很難讓人注意,因爲大多數應用程序調用'glTexImage2D'的頻率比一次幀的頻率少得多......我會在更多的系統上試試這個,看看它有多可重複性。 – Legendre17

+0

這可能是正確的答案。爲了獲得一些支持,我在另一臺機器上運行了程序(運行Ubuntu Linux),並且看不到這些工件。而且,即使在Macbook Air(運行Ubuntu Linux的虛擬機)上的虛擬框中運行程序時,工件也會消失。 – Legendre17

+0

@ Legendre17:謝謝你的提升。 – datenwolf