Jump to content

  • Log In with Google      Sign In   
  • Create Account


Buffer corruption or is my code breaking?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
6 replies to this topic

#1 CirdanValen   Members   -  Reputation: 174

Like
0Likes
Like

Posted 14 May 2012 - 01:24 PM

Hey guys, so I'm trying to write a UI in OpenGL and have run into a problem when I resize this window.

Posted Image

As I shrink my window, the text texture seems to shrink or get corrupted and eventually the buttons get corrupted. The buttons are not tied to the size of the window, so the problem isn't with calculating the sizes. I printed the size of the text texture and the button sizes and they stayed consistent during the test. The textures, as far as I can tell, are not getting corrupted. Looks like it's the vertex buffers that are getting messed up?

So every time I resize the window, here is what is happening:

onResize
    Delete TexturedRectangle object
        | Delete 9 sprites (including vertex data) used for the TexturedRectangle
        | Delete the RenderTexture 
    New TexturedRectangle Object
        | Create 9 sprites (new vertex data) for the textured rectangle
        | Render the rectangle using the 9 sprites to a new RenderTexture the size of the window

I went through the code and made sure I am deleting the old data off the gpu before creating new buffers. Are my buffers getting corrupted or is the way I'm rendering to the RenderTextures incorrect? There is a lot of code here, so let me know which part of the code you want me to post.

Sponsor:

#2 CirdanValen   Members   -  Reputation: 174

Like
0Likes
Like

Posted 15 May 2012 - 01:21 PM

Here's some code
    Sprite::Sprite() 
    	: ISprite(), mVbo(0) {
    	mDiffuse = ResourceCache::getSingleton().getTexture("Texture_NOTFOUND");
    	createVbo();
    }

    Sprite::Sprite(ITexture *diffuse, FloatRect textureBounds)
    	: ISprite(), mVbo(0) {
    	mDiffuse = diffuse;

    	if(textureBounds.x == 0 && textureBounds.y == 0) {
    		mTextureBounds = diffuse->getBounds();
    	} else {
    		mTextureBounds = textureBounds;
    	}

    	createVbo();
    }

    Sprite::~Sprite() {
    	glDeleteBuffers(1, &mVbo);
    }

    void Sprite::draw(IRenderTarget *target, RenderState *state) const {
    	glEnableClientState(GL_VERTEX_ARRAY);
    	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    	
    	glBindBuffer(GL_ARRAY_BUFFER, mVbo);

    	switch(state->getRenderMode()) {
    	default:
    	case RenderState::DIFFUSE:
    		mDiffuse->bindTexture();
    		break;
    	case RenderState::NORMAL_MAP:
    		mNormalMap->bindTexture();
    		break;
    	case RenderState::HEIGHT_MAP:
    		mHeightMap->bindTexture();
    		break;
    	};
    	
    	glPushMatrix();
    	glTranslatef(mPosition.x, mPosition.y, mPosition.z);
    	glColor4f(mColor.r, mColor.g, mColor.b, mColor.a);

    	glVertexPointer(3, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, x));
    	glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, tx));

    	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    	
    	glPopMatrix();

    	glBindBuffer(GL_ARRAY_BUFFER, 0);
    	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    	glDisableClientState(GL_VERTEX_ARRAY);
    }

    void Sprite::createVbo() {
    	if(mVbo != 0) {
    		glDeleteBuffers(1, &mVbo);
    	}

    	// Generate the VBO
    	glGenBuffers(1, &mVbo);
    	Vector2f size = getSize();

    	float texW = mDiffuse->getWidth();
    	float texH = mDiffuse->getHeight();
    	float srcW = size.x / texW;
    	float srcH = size.y / texH;
    	

    	// Calculate the vertices
    	Vertex verts[] = {{0.f, 0.f, 0.f, mTextureBounds.x / texW, mTextureBounds.y / texH},
    						{size.x, 0.f, 0.f, (mTextureBounds.x / texW) + srcW, mTextureBounds.y / texH},
    						{0.f, size.y, 0.f, mTextureBounds.x / texW, (mTextureBounds.y / texH ) + srcH},
    						{size.x, size.y, 0.f, (mTextureBounds.x / texW) + srcW, (mTextureBounds.y  / texH) + srcH}};
    		
    	int vertSize = sizeof(verts);

    	// Bind the VBO
    	glBindBuffer(GL_ARRAY_BUFFER, mVbo);

    	// Submit the vertex data to the GPU
    	glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * 4, &verts[0].x, GL_STATIC_DRAW_ARB);

    	// Unbind the VBO
    	glBindBuffer(GL_ARRAY_BUFFER, 0);
    }
Repeating Sprite
    RepeatingSprite::RepeatingSprite(Texture *diffuseTexture, FloatRect spriteBounds, int xRepeat, int yRepeat) 
    	: ISprite(), mXRepeat(xRepeat), mYRepeat(yRepeat) {
    	mVbo = 0;
    	mDiffuse = diffuseTexture;
    	mTextureBounds = spriteBounds;
    	createVbo();
    }

    RepeatingSprite::~RepeatingSprite() {
    	glDeleteBuffers(1, &mVbo);
    }



    void RepeatingSprite::draw(IRenderTarget *target, RenderState *state) const {
    	glEnableClientState(GL_VERTEX_ARRAY);
    	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    	
    	glBindBuffer(GL_ARRAY_BUFFER, mVbo);

    	switch(state->getRenderMode()) {
    	default:
    	case RenderState::DIFFUSE:
    		mDiffuse->bindTexture();
    		break;
    	case RenderState::NORMAL_MAP:
    		mNormalMap->bindTexture();
    		break;
    	case RenderState::HEIGHT_MAP:
    		mHeightMap->bindTexture();
    		break;
    	};
    	
    	glPushMatrix();
    	glTranslatef(mPosition.x, mPosition.y, mPosition.z);
    	glColor4f(mColor.r, mColor.g, mColor.b, mColor.a);

    	glVertexPointer(3, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, x));
    	glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, tx));

    	glDrawArrays(GL_QUADS, 0, (mXRepeat * mYRepeat) * 4);
    	
    	glPopMatrix();

    	glBindBuffer(GL_ARRAY_BUFFER, 0);
    	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    	glDisableClientState(GL_VERTEX_ARRAY);
    }

    void RepeatingSprite::createVbo() {
    	int totalRepeats = mXRepeat * mYRepeat;
    	float textureWidth = mDiffuse->getWidth();
    	float textureHeight = mDiffuse->getHeight();
    	Vertex *vertices = new Vertex[totalRepeats*4];

    	int counter = 0;
    	// For each sprite count, create a quad
    	for(float y = 0; y < mYRepeat; y++) {
    		for(float x = 0; x < mXRepeat; x++) {	
    		
    			Vertex v1 = {x * mTextureBounds.w, 
    						 y * mTextureBounds.h, 0.f, 
    						 mTextureBounds.x / textureWidth, 
    						 mTextureBounds.y / textureHeight};

    			Vertex v2 = {x * mTextureBounds.w + mTextureBounds.w, 
    						 y * mTextureBounds.h, 0.f, 
    						 (mTextureBounds.x / textureWidth) + (mTextureBounds.w / textureWidth), 
    						 mTextureBounds.y / textureHeight};
    			
    			Vertex v3 = {x * mTextureBounds.w, 
    						 y * mTextureBounds.h + mTextureBounds.h, 0.f, 
    						 mTextureBounds.x / textureWidth, 
    						 (mTextureBounds.y / textureHeight) + (mTextureBounds.h / textureHeight)};

    			Vertex v4 = {x * mTextureBounds.w + mTextureBounds.w, 
    						 y * mTextureBounds.h + mTextureBounds.h, 0.f, 
    						 (mTextureBounds.x / textureWidth) + (mTextureBounds.w / textureWidth), 
    						 (mTextureBounds.y / textureHeight) + (mTextureBounds.h / textureHeight)};

    			
    			vertices[counter] = v1;
    			counter++;
    			vertices[counter] = v2;
    			counter++;
    			vertices[counter] = v4;
    			counter++;
    			vertices[counter] = v3;
    			counter++;
    		}
    	}

    	glGenBuffers(1, &mVbo);

    	glBindBuffer(GL_ARRAY_BUFFER, mVbo);

    	glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * (totalRepeats*4), &vertices[0].x, GL_STATIC_DRAW_ARB);

    	glBindBuffer(GL_ARRAY_BUFFER, 0);

    	delete[] vertices;
    }
Render Texture
    RenderTexture::RenderTexture(float width, float height) {
    	mWidth = width;
    	mHeight = height;

    	// Create the color buffer
    	glGenTextures(1, &mId);
    	glBindTexture(GL_TEXTURE_2D, mId);
    	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)mWidth, (int)mHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    	glBindTexture(GL_TEXTURE_2D, 0);

    	// Create the framebuffer
    	glGenFramebuffers(1, &mFbo);
    	glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
    	
    	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mId, 0);

    	GLenum err = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    	assert(err == GL_FRAMEBUFFER_COMPLETE); // Make sure texture is valid
    	
    	glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }

    RenderTexture::~RenderTexture() {
    	glDeleteBuffers(1, &mFbo);
    	glDeleteTextures(1, &mId);
    	mFbo = 0;
    }


    void RenderTexture::preDraw() {
    	// store the glViewport and glEnable states
    	glPushAttrib(GL_VIEWPORT_BIT);

    	// Bind the frame buffer
    	//glBindTexture(GL_TEXTURE_2D, 0);
    	glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
    	
    	// Save the current matrix
    	glPushMatrix();
    	glLoadIdentity();

    	// Setup the projection matrix for the render target
    	glMatrixMode(GL_PROJECTION);
    	glPushMatrix();
    	glLoadIdentity();
    	glViewport(0, 0, (int)mWidth, (int)mHeight);
    	glOrtho(0, mWidth, 0.f, mHeight, 0.f, 100.f);

    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    	glDrawBuffer(GL_COLOR_ATTACHMENT0);
    }

    void RenderTexture::postDraw() {
    	// Pop the render target's projection matrix off the stack
    	glPopMatrix();
    	// Restore previouse projection matrix
    	glPopMatrix();
    	glBindFramebuffer(GL_FRAMEBUFFER, 0);
    	// Restore the previous viewport settings
    	glPopAttrib();
    }

String Sprite

StringSprite::StringSprite(const std::string &string, Font *font)
	: mString(string), mFont(font)  {
		// Calling this forces the string to be rendered
		mDiffuse = NULL;
		mVbo = 0;
		renderText();
}

StringSprite::~StringSprite() {
	delete mDiffuse;
}

void StringSprite::setText(const std::string &str) {
	mString = str;
	renderText();
}

void StringSprite::draw(IRenderTarget *target, RenderState *state) const {

	/*std::stringstream vbo;
	vbo << mVbo;
	Log::getSingleton().writeLine("Drawing StringSprite \"" + mString + "\" with Vbo ID " + vbo.str() + " Size: " + mDiffuse->getBounds().toString());*/

	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	
	glBindBuffer(GL_ARRAY_BUFFER, mVbo);

	mDiffuse->bindTexture();
	
	glPushMatrix();
	
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	glTranslatef(mPosition.x, mPosition.y, mPosition.z);
	glColor4f(mColor.r, mColor.g, mColor.b, mColor.a);

	glVertexPointer(3, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, x));
	glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, tx));

	glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
	
	glDisable(GL_BLEND);
	glPopMatrix();

	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glDisableClientState(GL_VERTEX_ARRAY);
}

void StringSprite::renderText() {
	if(mDiffuse)
		delete mDiffuse;

	mDiffuse = mFont->renderString(mString);
	mTextureBounds = mDiffuse->getBounds();
	createVbo();
}

void StringSprite::createVbo() {
	if(mVbo != 0) {
		glDeleteBuffers(1, &mVbo);
		mVbo = 0;
	}

	// Generate the VBO
	glGenBuffers(1, &mVbo);

	float texW = (float)mDiffuse->getWidth();
	float texH = (float)mDiffuse->getHeight();
	float srcW = 1;
	float srcH = 1;

	// Calculate the verticies
	Vertex verts[] = {{0, 0, 0, 0, 0},
					   {texW, 0, 0, srcW, 0},
						{0, texH, 0, 0, srcH},
						{texW, texH, 0, srcW, srcH}};
		
	int vertSize = sizeof(verts);

	// Bind the VBO
	glBindBuffer(GL_ARRAY_BUFFER_ARB, mVbo);

	// Submit the vertex data to the GPU
	glBufferData(GL_ARRAY_BUFFER_ARB, sizeof(Vertex) * 4, &verts[0].x, GL_STATIC_DRAW_ARB);

	// Unbind the VBO
	glBindBuffer(GL_ARRAY_BUFFER_ARB, 0);
}

Edited by CirdanValen, 15 May 2012 - 04:16 PM.


#3 mhagain   Crossbones+   -  Reputation: 7338

Like
0Likes
Like

Posted 15 May 2012 - 01:40 PM

Are you by any chance calling createVbo again (but not otherwise deleting your sprite objects) when this happens? glDeleteBuffers doesn't reset the buffer names to 0.

It appears that the gentleman thought C++ was extremely difficult and he was overjoyed that the machine was absorbing it; he understood that good C++ is difficult but the best C++ is well-nigh unintelligible.


#4 CirdanValen   Members   -  Reputation: 174

Like
0Likes
Like

Posted 15 May 2012 - 02:18 PM

Ah, interesting. I figured the existing value would get overwritten.

I put mVbo = 0 in the createVbo methods for Sprite after I call glDeleteBuffers, but that didn't seem to change anything. When I resize the panel, I literally delete the objects, run the deconstructors, and instantiate new objects.. I'm sure there is a more efficient way to do this, but I'm just trying to get it working right now.

#5 Batch2   Members   -  Reputation: 118

Like
0Likes
Like

Posted 15 May 2012 - 04:56 PM

It would be alot easier to use glBufferSubData to update the vbo with new vertex information on resize than to delete and remake all the objects...
something like this

onResize(){
	 float texW = (float)mDiffuse->getWidth();	  
	 float texH = (float)mDiffuse->getHeight();	  
	 float srcW = 1;	  
	  float srcH = 1;	  
// Calculate the verticies	  
	 Vertex verts[] = {{0, 0, 0, 0, 0},										  
		  {texW, 0, 0, srcW, 0},											  
		  {0, texH, 0, 0, srcH},											  
		  {texW, texH, 0, srcW, srcH}};					  
		  int vertSize = sizeof(verts);	  
// Bind the VBO	  
glBindBuffer(GL_ARRAY_BUFFER_ARB, mVbo);	  
// Submit the vertex data to the GPU	  
glBufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(Vertex) * 4, verts);	  
// Unbind the VBO	  
glBindBuffer(GL_ARRAY_BUFFER_ARB, 0);
}
This would also check if indeed the problem is with deleting and recreating the objects or if there is some error in setting the new vertex positions you missed.

Also if you're going to be updating the VBO declare it as GL_DYNAMIC_DRAW

Edited by Batch2, 15 May 2012 - 04:57 PM.


#6 CirdanValen   Members   -  Reputation: 174

Like
0Likes
Like

Posted 15 May 2012 - 10:18 PM

I don't know if that would work with how things are setup currently. The sprites for the window that need to repeat are done by just drawing multiple sprites until the area is covered, similar to how a tile map is done. So when I resize something, I have to add or subtract vertex data each time. I have to do it this way because of how OpenGL does texture mapping. I can't have repeating textures when using a texture atlas, and I really don't want to have a mess of 9 different texture files to keep track of. And, as far as I know, there is no way to resize a framebuffer so I have to recreate that every time.

Edited by CirdanValen, 15 May 2012 - 10:19 PM.


#7 Batch2   Members   -  Reputation: 118

Like
0Likes
Like

Posted 16 May 2012 - 09:10 AM

The code I passed should still work for your string sprite since it does not appear that you are adding or removing any vertex data. That's the protion of the code I was was looking at when I suggested it. I apologize that I missed how you were doing the buttons and windows, but you have alot of code posted and none of your methods or functions have comments describing what they do. It is very time consuming to read...

You only need to resize the vbo if you're going to be passing in more vertex data than is already allocated. Which happens when you're expanding the window size. I'd make a conditional statement that remakes the vbo when a window is enlargened and just works within the current space if it's the same size or smaller. The unused space in the vbo is definitely worth the performance gain of not having to continueously call glBUFFERDATA, which is slower than glBUFFERSUBDATA.

At the very least this should help you to issolate the problem.

I implement a simular solution in my project for constantly updating text display (my FPS counter etc.). I have the full font as a texture atlas and render the individual characters to an array of quads. The quad array is only resized when increasing the amount of characters. Obviously this doesn't makes sense for your text but an approach like this should work for your windows and buttons.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS