問題に至るまで:
C を使用して OpenGL について学び、自分でデザインした (おそらく簡単な) タイルベースのゲームを作成します。最初は、テスト用に 10 個ほどの三角形しか描いていませんでしたが、バッファ データとインデックスを次のように設定しました。
const float vertexPositions[] = {
-1.0f, -0.8f, //0
-1.0f, -1.0f, //1
-0.8f, -0.8f, //2
-0.8f, -1.0f, //3
-0.8f, -0.8f, //2
-0.8f, -1.0f, //3
-0.6f, -0.8f, //4
-0.6f, -1.0f, //5
-0.6f, -0.8f, //4
-0.6f, -1.0f, //5
-0.4f, -0.8f, //6
-0.4f, -1.0f, //7
-0.4f, -0.8f, //6
-0.4f, -1.0f, //7
-0.2f, -0.8f, //8
-0.2f, -1.0f, //9
-0.2f, -0.8f, //8
-0.2f, -1.0f, //9
0.0f, -0.8f, //10
0.0f, -1.0f, //11
0.0f, -0.8f, //10
0.0f, -1.0f, //11
/////////////////////////////////// Texture coords:
0.0f, 1.0f, //0
0.0f, 0.0f, //1
1.0f, 1.0f, //2
1.0f, 0.0f, //3
0.0f, 1.0f, //2
0.0f, 0.0f, //3
1.0f, 1.0f, //4
1.0f, 0.0f, //5
0.0f, 1.0f, //4
0.0f, 0.0f, //5
1.0f, 1.0f, //6
1.0f, 0.0f, //7
0.0f, 1.0f, //6
0.0f, 0.0f, //7
1.0f, 1.0f, //8
1.0f, 0.0f, //9
0.0f, 1.0f, //8
0.0f, 0.0f, //9
1.0f, 1.0f, //10
1.0f, 0.0f, //11
0.0f, 1.0f, //10
0.0f, 0.0f, //11
const GLubyte indices[] = {
0, 1, 2,
3, 2, 1,
4, 5, 6,
7, 6, 5,
8, 9, 10,
11, 10, 9,
12, 13, 14,
15, 14, 13,
16, 17, 18,
19, 18, 17,
};
より多くの三角形を作成するにはさらに多くの三角形が必要になるため、自動化することにしました (また、シェーダーでいくつかのマトリックスを使用するつもりであるため、値は画面/ビューポート座標ではなくピクセル単位です)。
float vertexPositions[6400]; //Declared globally outside the function
int blah()
{
int count = 0, texture_start;
for (int y = 0; y < 20; y++)
{
for (int x = 0; x < 21; x++)
{
vertexPositions[count++] = x * 32.0f;
vertexPositions[count++] = (y + 1) * 32.0f;
vertexPositions[count++] = x * 32.0f;
vertexPositions[count++] = y * 32.0f;
if (x > 0 && x < 20)
{
vertexPositions[count++] = x * 32.0f;
vertexPositions[count++] = (y + 1) * 32.0f;
vertexPositions[count++] = x * 32.0f;
vertexPositions[count++] = y * 32.0f;
}
}
}
texture_start = count;
for (int z = 0; z < 400; z++)
{
vertexPositions[count++] = 0.0f;
vertexPositions[count++] = 1.0f;
vertexPositions[count++] = 0.0f;
vertexPositions[count++] = 0.0f;
vertexPositions[count++] = 1.0f;
vertexPositions[count++] = 1.0f;
vertexPositions[count++] = 1.0f;
vertexPositions[count++] = 0.0f;
}
return 0;
}
この新しいデータから正確に同じ三角形を取得できることを確認したかったので、インデックスを自動化していないことに注意してください。
問題:
特定のGL 呼び出しでアクセス違反が繰り返し発生します。ブレークポイント間を手動で移動すると、 に達すると常に失敗しますglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, positionBufferObject);
。
この行に 1 つのブレークポイントがあり、この行の後に 1 つのブレークポイントがある場合、その間の行をスキップ (無視しますか? サイレントに失敗しますか?) しGLuint fShader = glCreateShader(GL_FRAGMENT_SHADER);
、呼び出し内に到達すると中断しmyProgram = CreateProgram();
ます (私の頂点シェーダーは直前に同一の呼び出しで正常に動作します)。
GLvoid InitGL(GLvoid)
{
blah(); <----where i initialize my vertex data
FnLdInit();
GetBitmap();
//char * glVer = (char *)glGetString(GL_VERSION);
//char * glSLV = (char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL); ---------------------------//~BREAKPOINT HERE!~
glGenBuffers(1, &positionBufferObject);
errort = glGetError();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, positionBufferObject);
//errort = glGetError();
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(vertexPositions), (const float *)vertexPositions, GL_STATIC_DRAW);
//errort = glGetError();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
//errort = glGetError();
myProgram = CreateProgram(); -------------------------//~BREAKPOINT HERE!~
}
すべての glGetError() は 0 を返します。これは、仕様によると、問題がないか、glGetError に独自のエラーが発生したことを意味します。
ただし、どこで壊れても、呼び出しスタック pelles C は、壊れたときに 'atio6axx.dll; を示します。DrvPresentBuffers() +163B7B' で、常にここにあります。
最近、Radeon HD 6850 用の最新の Catalyst アップデートをインストールしました。GPU/頂点バッファ オブジェクトなどに関するメモリの制限については何も見つかりません。また、25KB までのデータが何かの多くを壊すとは思えません。これは OpenGL の問題ではなく、コードの実装方法に問題があるか、慣れていない制限/メモリの問題であると感じています。
このサイトのポスター #20にも同様の問題がありますが、コードではなくプログラムの障害に関連しているようです (10 月 11 日に投稿されたにもかかわらず、最新のドライバーが公開される前に発生したと思います)。GetBitmap()
glBindTexture やその他の呼び出しを問題なく使用できます。
これは最も明白なように思えますが、古いアルゴリズムから新しいアルゴリズムに変更したのは、データ作成の自動化だけです。const float *
ポインターは関係ありません。また、コンパイラーが必要であると警告さえしなかった にキャストすることさえあります。
単純な問題の解決策を探すのに間違った場所を探していませんか? コードを説明したり、必要に応じてさらに追加したりしますので、お尋ねください。手動で ~6400 以上の値を書き出すのは本当に避けたいと思います。
編集#1:他のいくつかのテストの後、古い実装でもこのエラーが発生するようです。私はしばらくそれをコンパイルしていなかったに違いありません (別のファイルであるシェーダーに取り組んでいました)。私はとても混乱しています。
編集#2:さらにコード。これは、InitGL の前に発生する唯一の関数であり、InitGl を呼び出す関数です。:
bool CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
{
GLuint PixelFormat;
WNDCLASS wc;
DWORD dwExStyle;
DWORD dwStyle;
RECT WindowRect;
WindowRect.left = (long)0;
WindowRect.right = (long)width;
WindowRect.top = (long)0;
WindowRect.bottom = (long)height;
fullscreen = fullscreenflag;
hInstance = GetModuleHandle(NULL);
wc.style = CS_HREDRAW |CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "OpenGL";
if (!RegisterClass(&wc))
{
MessageBox(NULL, "Failed to register the window class", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
if (fullscreen)
{
int changeresult;
//char msg[100];
DISPLAY_DEVICE disp;
DEVMODE dmScreenSettings;
int dw;
memset(&disp, 0, sizeof(disp));
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
disp.cb = sizeof(disp);
if (!(EnumDisplayDevices(NULL, 0, &disp, 0)))
{
return 1;
}
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
//ENUM_CURRENT_SETTINGS
if (!(EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &dmScreenSettings)))
{
dw = GetLastError();
}
dmScreenSettings.dmPelsWidth = width; //enable this in real
dmScreenSettings.dmPelsHeight = height; //enable this in real
changeresult = ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
//dmScreenSettings.dmPelsWidth = width;
//dmScreenSettings.dmPelsHeight = height;
//dmScreenSettings.dmBitsPerPel = bits;
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
if (changeresult != DISP_CHANGE_SUCCESSFUL)
{
if (MessageBox(NULL, "Use window mode?", "GL", MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
{
fullscreen = FALSE;
}
else
{
return FALSE;
}
}
}
if (fullscreen)
{
dwExStyle = WS_EX_APPWINDOW;
dwStyle = WS_POPUP;
ShowCursor(FALSE);
}
else
{
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle = WS_OVERLAPPEDWINDOW;
}
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
if(!(hWnd = CreateWindowEx( dwExStyle,
"OpenGL",
title,
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dwStyle,
0,
0,
WindowRect.right - WindowRect.left,
WindowRect.bottom - WindowRect.top,
NULL,
NULL,
hInstance,
NULL)))
{
KillGLWindow();
MessageBox(NULL, "Window Creation error", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
static PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be
{
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
1, // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER, // Must Support Double Buffering
PFD_TYPE_RGBA, // Request An RGBA Format
0, // Select Our Color Depth
0, 0, 0, 0, 0, 0, // Color Bits Ignored
0, // No Alpha Buffer
0, // Shift Bit Ignored
0, // No Accumulation Buffer
0, 0, 0, 0, // Accumulation Bits Ignored
16, // 16Bit Z-Buffer (Depth Buffer)
0, // No Stencil Buffer
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 // Layer Masks Ignored
};
pfd.cColorBits = bits;
if (!(hDC = GetDC(hWnd)))
{
KillGLWindow();
MessageBox(NULL, "Can't create a GL device context", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd)))
{
KillGLWindow();
MessageBox(NULL, "Can't find a suitable pixelformat", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
if (!SetPixelFormat(hDC, PixelFormat, &pfd))
{
KillGLWindow();
MessageBox(NULL, "Can't set the pixel format", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
if (!(hRC = wglCreateContext(hDC)))
{
KillGLWindow();
MessageBox(NULL, "Can't create a GL rendering context", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
if (!wglMakeCurrent(hDC, hRC))
{
KillGLWindow();
MessageBox(NULL, "Can't activate the GL rendering context", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
ShowWindow(hWnd, SW_SHOW);
SetForegroundWindow(hWnd);
SetFocus(hWnd);
InitGL();
ResizeGLScene(width, height);
//char * glVer = (char *)glGetString(GL_VERSION);
//char * glSLV = (char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
return TRUE;
}
FnLdInit は、すべての拡張機能を接続する場所です。
void FnLdInit(void)
{
HINSTANCE hGLLIB = NULL;
hGLLIB = LoadLibrary("opengl32.dll");
glActiveTexture = (PFNGLACTIVETEXTUREPROC)wglGetProcAddress("glActiveTexture");
glAttachShader = (PFNGLATTACHSHADERPROC)wglGetProcAddress("glAttachShader");
glBindBuffer = (PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer");
glBufferData = (PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData");
glCompileShader = (PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader");
glCreateProgram = (PFNGLCREATEPROGRAMPROC)wglGetProcAddress("glCreateProgram");
glCreateShader = (PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader");
glDeleteShader = (PFNGLDELETESHADERPROC)wglGetProcAddress("glDeleteShader");
glDetachShader = (PFNGLDETACHSHADERPROC)wglGetProcAddress("glDetachShader");
glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glDisableVertexAttribArray");
glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glEnableVertexAttribArray");
glGenBuffers = (PFNGLGENBUFFERSPROC)wglGetProcAddress("glGenBuffers");
glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)wglGetProcAddress("glGetShaderInfoLog");
glGetShaderiv = (PFNGLGETSHADERIVPROC)wglGetProcAddress("glGetShaderiv");
glGetUniformfv = (PFNGLGETUNIFORMFVPROC)wglGetProcAddress("glGetUniformfv");
glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)wglGetProcAddress("glGetUniformLocation");
glLinkProgram = (PFNGLLINKPROGRAMPROC)wglGetProcAddress("glLinkProgram");
glShaderSource = (PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource");
glUniform1i = (PFNGLUNIFORM1IPROC)wglGetProcAddress("glUniform1i");
glUniform2f = (PFNGLUNIFORM2FPROC)wglGetProcAddress("glUniform2f");
glUseProgram = (PFNGLUSEPROGRAMPROC)wglGetProcAddress("glUseProgram");
glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)wglGetProcAddress("glVertexAttribPointer");
glBindTexture = (PFNGLBINDTEXTUREPROC)GetProcAddress(hGLLIB, "glBindTexture");
glClear = (PFNGLCLEARPROC)GetProcAddress(hGLLIB, "glClear");
glClearColor = (PFNGLCLEARCOLORPROC)GetProcAddress(hGLLIB, "glClearColor");
glClearDepth = (PFNGLCLEARDEPTHPROC)GetProcAddress(hGLLIB, "glClearDepth");
glDepthFunc = (PFNGLDEPTHFUNCPROC)GetProcAddress(hGLLIB, "glDepthFunc");
glDrawArrays = (PFNGLDRAWARRAYSPROC)GetProcAddress(hGLLIB, "glDrawArrays");
glEnable = (PFNGLENABLEPROC)GetProcAddress(hGLLIB, "glEnable");
glGenTextures = (PFNGLGENTEXTURESPROC)GetProcAddress(hGLLIB, "glGenTextures");
glTexImage2D = (PFNGLTEXIMAGE2DPROC)GetProcAddress(hGLLIB, "glTexImage2D");
glTexParameteri = (PFNGLTEXPARAMETERIPROC)GetProcAddress(hGLLIB, "glTexParameteri");
glViewport = (PFNGLVIEWPORTPROC)GetProcAddress(hGLLIB, "glViewport");
glDrawElements = (PFNGLDRAWELEMENTSPROC)GetProcAddress(hGLLIB, "glDrawElements");
glGetError = (PFNGLGETERRORPROC)GetProcAddress(hGLLIB, "glGetError");
glGetString = (PFNGLGETSTRINGPROC)GetProcAddress(hGLLIB, "glGetString");
}
GetBitmap() は次のとおりです。
int GetBitmap(void)
{
char * bmBuffer, * pxPtr;
FILE * bmFile;
//FILE * result;
GLuint texture;
int bmSize,
dataOffset,
dibSize,
bmWidthPx,
bmHeightPx,
bmCompression,
dataSize,
dataHorRes,
dataVerRes,
paletteNumClrs,
importantClrs,
bmBytesPerPixel = 3, //Default -> RGB
totalBytesPerRow,
pixelBytesPerRow,
padCount = 0;
short int bmClrPlane, bmBPP;
char bmChar0, bmChar1;
//char msgData[100];
bmFile = fopen("multisquare.bmp", "rb");
if (bmFile == NULL)
{
return 1;
}
bmChar0 = fgetc(bmFile);
bmChar1 = fgetc(bmFile);
if (bmChar0 != 'B' || bmChar1 != 'M')
{
return 2;
}
//sprintf(msgData, "%c%c", bmChar0, bmChar1);
//MessageBox(NULL, msgData, NULL, MB_OK | MB_ICONINFORMATION);
bmSize = Get4Bytes(bmFile);
//Skip 4 bytes. These bytes are application specific,
//and generally unused.
if (fseek(bmFile, 4, SEEK_CUR) != 0)
{
return 3;
}
dataOffset = Get4Bytes(bmFile);
dibSize = Get4Bytes(bmFile);
//Replace 'if dibSize' check with case statement
//which branches to functions for different sized
//DIBHeaders.
//
//
if (dibSize != 40)
{
return 4;
}
bmWidthPx = Get4Bytes(bmFile);
bmHeightPx = Get4Bytes(bmFile); //Later -> handle negative = top->bottom.
bmClrPlane = Get2Bytes(bmFile); //Must always be 1 anyways, consider removing this and skipping 2 bytes.
bmBPP = Get2Bytes(bmFile);
if (bmBPP == 24)
{
bmBytesPerPixel = 3;
}
bmCompression = Get4Bytes(bmFile);
//Handle other compressions at some later time.
if (bmCompression != 0)
{
return 5;
}
//Can use this to allocate appropriate memory space.
dataSize = Get4Bytes(bmFile);
//Resolutions doesn't seem too important atm.
dataHorRes = Get4Bytes(bmFile);
dataVerRes = Get4Bytes(bmFile);
//Will probably both be 0. Irrelevant atm.
paletteNumClrs = Get4Bytes(bmFile);
importantClrs = Get4Bytes(bmFile);
bmBuffer = (char *) calloc(dataSize, sizeof(char)); //Space allocated.
fseek(bmFile, dataOffset, SEEK_SET);
//Ex: 10 pixels * 3 bytes/pixel = 30 bytes
// 30 + 3 = 33 -> 0010 0001
// Right shift 2: 0000 1000 -> These operations round to nearest
// Shift left 2: 0010 0000 -> multiple of 4.
// 32 bytes to reach 4byte multiple
// So 30 bytes for 10 pixles plus 2 extra bytes of padding, per row.
pixelBytesPerRow = bmWidthPx * bmBytesPerPixel;
totalBytesPerRow = ((pixelBytesPerRow + bmBytesPerPixel) >> 2) << 2;
padCount = totalBytesPerRow - pixelBytesPerRow;
pxPtr = bmBuffer;
switch(padCount)
{
case 0:
{
for (int A = 0; A <= bmHeightPx; A++)
{
/*
for (int B = 0; B <= bmWidthPx; B++)
{
*(pxPtr + 2) = fgetc(bmFile);
*(pxPtr + 1) = fgetc(bmFile);
*pxPtr = fgetc(bmFile);
}
*/
fread(pxPtr, 1, pixelBytesPerRow, bmFile);
pxPtr += totalBytesPerRow;
}
break;
}
case 1:
case 2:
case 3:
{
for (int A = 0; A <= bmHeightPx; A++)
{
/*
for (int B = 0; B <= bmWidthPx; B++)
{
*(pxPtr + 2) = fgetc(bmFile);
*(pxPtr + 1) = fgetc(bmFile);
*pxPtr = fgetc(bmFile);
}
*/
fread(pxPtr, 1, pixelBytesPerRow, bmFile);
if (fseek(bmFile, padCount, SEEK_CUR) != 0)
{
return 3;
}
pxPtr += totalBytesPerRow;
}
break;
}
default:
//Shouldn't get here
break;
}
//result = fopen("test.txt","w");
//fwrite(bmBuffer, 1, dataSize , result);
//fclose(result);
fclose(bmFile);
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, /*Type of texture*/
0, /*Level of Detail number*/
GL_RGB, /*Internal format*/
bmWidthPx, /*Width in texels(pixels?)*/
bmHeightPx, /*Height in texels(pixels?)*/
0, /*Border. Must be 0 (probably only for 2D)*/
GL_BGR, /*Format, of the data the texture will be created from*/
GL_UNSIGNED_BYTE,/*Data type of the pixel data*/
bmBuffer); /*Pointer to the image data to create the texture from*/
//glBindTexture(GL_TEXTURE_2D, 0);
free(bmBuffer);
return 0;
}
編集 #3 : アンインストールされた Catalyst 12.10 および関連するすべてのドライバー。12.8を再インストールしました。同じ問題ですが、現在は GenBuffers で発生しています。奇数。
編集 #4 : プロジェクトを 32 ビットにしてコンパイルしてみました。まったく同じ問題が発生しますが、なんらかの理由で Pelles C が LIB にラベルを付けていないため (言及するたびに「無題」と表示されます)、AMD が提供する 32 ビット lib も失敗しているとしか思えません (atio6axx.dll/. lib がロードされていません)。この問題は、私のコードではなくドライバーに起因しているように見えるため、実際の解決策はないと感じています。このような関連する問題を検索して確認した後、実際にはクライアント側の解決策はないようです。
編集#5:この時点でプログラムがアクセス違反を発生させなかったため、以前は気付かなかった別の問題は、コードが到達glActiveTexture(GL_TEXTURE0);
して突然すべての行をスキップして関数を終了することです。この行を削除すると、次の行が実行されます。glActiveTexture(GL_TEXTURE0);
は from ですがatio6axx.dll
、それ以外のコマンドはすべて fromOPENGL32.dll
であるため、絞り込んだようです。奇妙なのは、この時点でアクセス違反がなく、奇妙なスキップがあることです。
これが起こった理由を誰も理解できないと思いますか?15\11\2012 (先週の木曜日) のバージョン atio6axx.dll を持つベータ版の Catalyst ドライバーもインストールしました。したがって、最新のドライバーは問題ではありません。Catalyst 12.4 (現在は 12.10 で、このプログラムは 12.8 で実行されました) 以降、すべてのドライバー バージョンを試しました。途方に暮れ、新しいプログラムでさえ同じ問題に遭遇します。