App for windows, Delphi. I can’t debug one crash - the glTexSubImage2D call. It’s called to refresh a subtexture in texture atlas. Subtexture bitmap extents are ATextureImage.Width x ATextureImage.Height. To avoid linear filtering artifacts, each subtexture is padded by AtlasGap texels at each of 4 sides. So real subtexture extents are FSubTexWidth x FSubTexHeight (see code). ATextureImage is a bitmap class, it has Bits property of type pointer. CheckGLError() calls glGetError() and if there is an error, raises exception. So first CheckGLError() passes, second raises exception (gl error code is GL_INVALID_VALUE) on single configuration - Mobile Intel® 4 Series Express Chipset Family but passes OK on every other platform tried so far.
Look at this:
glBindTexture(GL_TEXTURE_2D, FAtlases[ AAtlasInx ].AtlasID);
{FSubTexWidth/FSubTexHeight are enlarged to fit gaps}
assert(ATextureImage.Width = FSubTexWidth - 2*AtlasGap);
assert(ATextureImage.Height = FSubTexHeight - 2*AtlasGap);
CheckGLError(); // <-- this passes
assert((c * FSubTexWidth + AtlasGap) + ATextureImage.Width <= FAtlasWidth );
assert((r * FSubTexHeight + AtlasGap) + ATextureImage.Height <= FAtlasHeight);
glTexSubImage2D(GL_TEXTURE_2D,0{level},
c * FSubTexWidth + AtlasGap {xoffset},
r * FSubTexHeight + AtlasGap {yoffset},
ATextureImage.Width,
ATextureImage.Height,
GL_BGRA_EXT,
GL_UNSIGNED_BYTE,
ATextureImage.Bits);
CheckGLError(); // <-- raises exception, GL_INVALID_VALUE
Texture atlas is created a bit earlier(BytesPerPixel = 4):
...
InitTextureAtlas(@FAtlases[AAtlasInx].AtlasID,
FAtlasWidth,
FAtlasHeight,
GL_RGBA {internal format},
GL_BGRA_EXT {pixel format}
);
...
procedure InitTextureAtlas(AAtlasID:PGLuint;
AAtlasWidth,AAtlasHeight:integer;
AInternalFormat:integer;
AFormat:GLuint);
var
InitBuf:PByte;
width:integer;
begin
AAtlasWidth := RoundUpToPowerOf2(AAtlasWidth);
AAtlasHeight := RoundUpToPowerOf2(AAtlasHeight);
glGenTextures(1, AAtlasID);
glBindTexture(GL_TEXTURE_2D, AAtlasID^);
CheckGLError();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
CheckGLError();
{ check capability with proxy texture }
glTexImage2d(GL_PROXY_TEXTURE_2D,
0{level},
AInternalFormat{components},
AAtlasWidth,
AAtlasHeight,
0 {border},
AFormat,
GL_UNSIGNED_BYTE, nil);
glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, @width);
if width = 0 then
begin
raise ESystemRequirements.Create('Unsufficient texture memory');
end;
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
GetMem(InitBuf, AAtlasWidth * AAtlasHeight * BytesPerPixel);
try
FillChar(InitBuf^,AAtlasWidth * AAtlasHeight * BytesPerPixel,$00);
glTexImage2d(GL_TEXTURE_2D,
0{level},
AInternalFormat{components},
AAtlasWidth,
AAtlasHeight,
0 {border},
AFormat,
GL_UNSIGNED_BYTE, InitBuf);
finally
FreeMem(InitBuf);
end;
CheckGLError();
end;
To believe documentation, there are only next possible cases:
1)GL_INVALID_VALUE is generated if level is less than 0.
2)GL_INVALID_VALUE may be generated if level is greater than log 2 max, where max is the returned value of GL_MAX_TEXTURE_SIZE.
3)GL_INVALID_VALUE is generated if xoffset < - b , xoffset + width > w - b , yoffset < - b , or yoffset + height > h - b , where w is the GL_TEXTURE_WIDTH, h is the GL_TEXTURE_HEIGHT, and b is the border width of the texture image being modified. Note that w and h include twice the border width.
4)GL_INVALID_VALUE is generated if width or height is less than 0.
1,2 and 4 are excluded, 3 is checked by assertions. Again, I can reproduce it only on one machine. Any suggestions?