這比出於任何實際目的更加出於好奇:OpenGL規範中是否有任何建議多次調用glTexImage2D
(例如,每幀一次)是非法的?我的意思是非法,因爲'它可能會產生錯誤的結果',而不僅僅是效率低下(假設我不關心不使用glTexSubImage2D
而不考慮性能影響)。OpenGL重複調用glTexImage2D和alpha混合
我問的原因是,當繪製重疊的紋理映射圖元時,我注意到一些非常奇怪的圖元,它們使用部分透明的圖元,每個圖片使用glTexImage2D
(見附圖)加載一次:after幾秒鐘(即幾百幀),屏幕上出現小的矩形黑色補丁(它們實際上在連續幀之間在黑色和正常之間翻轉)。
我附加下面的最簡單的示例代碼可以寫表現出的問題。
#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);
}
注:
我使用SDL,但我已經看到了wxWidgets的相同情況發生,所以它不是一個SDL相關的問題。
如果我用
glTexSubImage2D
代替每個幀(使用update = 1
,createTexture
),那麼工件消失。如果我禁用混合,則不會有更多的工件。
我一直在2010年底的MacBook Air上進行測試,儘管我懷疑這是特別相關的。
只是出於興趣......如果你將createTexture移動到第一個drawTriangles之前......它工作嗎? (我懷疑驅動程序紋理同步路徑中存在一個錯誤) – Goz
@Goz如果我在'drawTriangle'前面移動'createTexture',問題就會消失。我想我沒有真正考慮驅動程序中的錯誤......當我有機會時,我會在其他系統上嘗試代碼。 – Legendre17
基本上,它看起來像系統正在更新紋理,而它仍然在之前的繪製調用中使用。我猜想關閉alpha混合會影響渲染路徑,直到紋理更改沒有發生,而前一次繪製正在進行中。過去寫過驅動程序是一個非常基本的(而且很容易實現)的錯誤。你最好的選擇是解決它,並接受它失控。仍然值得將這個bug發佈給蘋果,希望他們能夠修復驅動程序! – Goz