Unexpected Behavior: PBO atlas texture copy

Hi, I’m using PBO texture uploads for a couple of years now - code is working fine. Now I wanted to change my multi PBO, multi Texture approach to using a singular texture as a 2D Atlas.

When I copy one tile into the texture though, I get the result that the copied tile has reduced in height and is copied multiple times in width instead.

This is my scenario:

atlas texture: 5760x1080
tile: 1920x1080

result: attached

original: attached

It looks like the texture is filling a row of a 3x3 array instead of just one tile of a 1x3 array… the issues scales with the atlas size:
1920x1080 atlas -> no error (tile size = atlas size)
3840x1080 atlas -> expected: 1x2, but actually: 2x2
5760x1080 atlas -> expected: 1x3, but actually: 3x3
and so on…

Any clues?

Code:



int m_textureWidth = 5760;
int m_textureHeight = 1080;
int m_atlasSize =  m_textureWidth*m_textureHeight*3;
int m_tileSize = 1920*1080*3;
GLuint* m_textureIds;
GLuint* m_pboIds;
unsigned char* m_pBuf = .. contains the image bytes ..

void InitAtlasTexture()
{
	m_textureIds = new GLuint[1];
	glGenTextures(1, m_textureIds);
	
	glBindTexture(GL_TEXTURE_2D, m_textureIds[0]);
	
	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);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_BGR, m_textureWidth, m_textureHeight, 0, GL_BGR, GL_UNSIGNED_BYTE, NULL);

	glBindTexture(GL_TEXTURE_2D, 0);
}

void InitPBO()
{
	m_pboIds = new GLuint[1];
	glGenBuffers(1, m_pboIds);

	glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_pboIds[0]);
	glBufferStorage(GL_PIXEL_UNPACK_BUFFER, m_atlasSize, 0, GL_MAP_WRITE_BIT);
	glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}

bool CopyTexture()
{
	GLubyte* ptr = NULL;
	ptr = (GLubyte*)glMapNamedBufferRange(m_pboIds[0], 0, m_atlasSize, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_INVALIDATE_RANGE_BIT);

	if (ptr)
	{
		memcpy(ptr, m_pBuf, m_tileSize);

		glUnmapNamedBuffer(m_pboIds[0]);
	}
	else
	{
		return false;
	}
	
	glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, m_pboIds[0]);
	glTextureSubImage2D(m_textureIds[0], 0, 0, 0, m_textureWidth, m_textureHeight, GL_BGR, GL_UNSIGNED_BYTE, 0);
	glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);

	return true;
}

void Render()
{
    //..just the snipet thats important here:

   float left = 0.0;
   float right = 1.0;
   float top = 1.0;
   float bottom = 0.0;

   glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
   glEnable(GL_TEXTURE_2D);
   glBindTexture(GL_TEXTURE_2D, m_textureIds[0]);

	glBegin(GL_TRIANGLE_STRIP);
		glTexCoord2f(left, bottom);
		glVertex3f(-width/2.0, -height/2.0, 0.0f);

		glTexCoord2f(right, bottom);
		glVertex3f(width/2.0, -height/2.0, 0.0f);

		glTexCoord2f(left, top);
		glVertex3f(-width/2.0, height/2.0, 0.0f);

		glTexCoord2f(right, top);
		glVertex3f(width/2.0, height/2.0, 0.0f);
	glEnd();

    glBindTexture(GL_TEXTURE_2D, 0);
    glDisable(GL_TEXTURE_2D);
}


You’re telling it to fill the entire width of the texture. It should be


	glTextureSubImage2D(m_textureIds[0], 0, 0, 0, m_textureWidth/3, m_textureHeight, GL_BGR, GL_UNSIGNED_BYTE, 0);

Except that there should probably a variable which holds the tile width rather than using m_textureWidth/3.

Thank you so much! I knew it was something simple :slight_smile: