Directx 11 vertexBufferDesc.ByteWidth issue

Started by
4 comments, last by JariRG 4 years, 6 months ago

Hi guys,

i am trying to implement a simple font renderer using bitmap font texture with a dynamic vertex buffer, i am  able to successfully display text with correct glyph from bitmap texture.

right now i am trying to draw a dynamic string that changes at user input, i.e user able change the displayded text by typing the new one.

The issue is that  length of string is exactly same as what it was initialized with even when updating string at every render frame. string gets updated every fram but is capped at length equal to what is was initialized with.

i am suspecting that vertexBufferDesc.ByteWidth is not getting updated even when i update vertexbuffer by map and unmap it.

initialize


bool GlyphClass::Initialize(ID3D11Device* device, HWND hwnd, int screenWidth, int screenHeight, WCHAR* path)
{
	bool result;
	m_GlyphWidthData.open("Font/AgencyFBFont_64x64_width.txt");
	while (1)
	{
		if (m_GlyphWidthData.eof())
		{
			break;
		}

		int tmp = 0;
		m_GlyphWidthData >> tmp;
		if (tmp != 0)
		{
			m_GlyphWidth.push_back(tmp);
		}
	}
	m_GlyphWidthData.close();

	m_GlyphCharacter = 'A';
	m_StringToDraw = "TEXTTEST@xyz";//userInputString != "" ? userInputString : "VIVEK599 xyz";

	m_fontTextureShader = new TextureShaderClass;
	if (!m_fontTextureShader)
	{
		return false;
	}

	result = m_fontTextureShader->Initialize(device, hwnd);
	if (!result)
	{
		MessageBox(hwnd, L"Could not initialize font texture shader object!", L"Error", MB_OK);
		return false;
	}

	m_ScreenWidth = screenWidth;
	m_ScreenHeight = screenHeight;

	result = InitializeBuffers(device);
	if (!result)
	{
		return false;
	}

	result = LoadTexture(device, path);
	if (!result)
	{
		return false;
	}



	return true;

}

updatebuffer


bool GlyphClass::UpdateBuffers(ID3D11DeviceContext* context, int posX, int posY)
{
	m_StringToDraw = userInputString != "" ? userInputString : "STRING 555@xyz0123456789";
			
	VertexType* vertices;
	D3D11_MAPPED_SUBRESOURCE mappedResource;
	VertexType* vertexPtr;
	HRESULT hr;

	vertices = new VertexType[m_VertexCount * m_StringToDraw.length()];
	if (!vertices)
	{
		return false;
	}

	// Initialize vertex array to zeros at first.
	memset(vertices, 0, sizeof(VertexType) * m_VertexCount * m_StringToDraw.length() );

	float posXOffset = (float)posX;
	float posYOffset = (float)posY;

	for ( int i = 0; i < m_StringToDraw.length(); i++ )
	{
		int cx = m_StringToDraw[i] % 16;
		int cy = m_StringToDraw[i] / 16;

		float tex_left = (float)cx * (1.f / 16.f);
		float tex_top = (float)cy * (1.f / 16.f);
		float tex_right = tex_left + (1.f / 16.f) * ((float)m_GlyphWidth[m_StringToDraw[i]] / 64.f);
		float tex_bottom = tex_top + (1.f / 16.f);

		int totalCharWidth = 64;

		float left = (float)((float)(m_ScreenWidth / 2.f) * -1) + posXOffset;
		float right = left + (float)m_GlyphWidth[m_StringToDraw[i]];
		float top = (float)(m_ScreenHeight / 2.f) - posYOffset;
		float bottom = top - (float)totalCharWidth;

		//triangle 1 - clockwise
		vertices[0 + m_VertexCount * i].position = Vector3(left, top, 0.f);
		vertices[0 + m_VertexCount * i].texture = Vector2(tex_left, tex_top);

		vertices[1 + m_VertexCount * i].position = Vector3(right, bottom, 0.f);
		vertices[1 + m_VertexCount * i].texture = Vector2(tex_right, tex_bottom);

		vertices[2 + m_VertexCount * i].position = Vector3(left, bottom, 0.f);
		vertices[2 + m_VertexCount * i].texture = Vector2(tex_left, tex_bottom);

		//triangle + i 2
		vertices[3 + m_VertexCount * i].position = Vector3(left, top, 0.f);
		vertices[3 + m_VertexCount * i].texture = Vector2(tex_left, tex_top);

		vertices[4 + m_VertexCount * i].position = Vector3(right, top, 0.f);
		vertices[4 + m_VertexCount * i].texture = Vector2(tex_right, tex_top);

		vertices[5 + m_VertexCount * i].position = Vector3(right, bottom, 0.f);
		vertices[5 + m_VertexCount * i].texture = Vector2(tex_right, tex_bottom);

		posXOffset += m_GlyphWidth[m_StringToDraw[i]];
	
	}


	hr = context->Map(m_VertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
	if (FAILED(hr))
	{
		return false;
	}

	vertexPtr = (VertexType*)mappedResource.pData;
	int bufferSize = sizeof(VertexType) * m_VertexCount * m_StringToDraw.length();
	memcpy(vertexPtr, (void*)vertices, bufferSize);

	D3D11_BUFFER_DESC tmpDesc;
	m_VertexBuffer->GetDesc(&tmpDesc);

	context->Unmap(m_VertexBuffer, 0);

	delete[] vertices;
	vertices = 0;

	return true;

}

 

Advertisement

You've not shown the buffer creation code, or the code for the buffer binding and draw call, which in this case are quite important. However, there's a standard way to create variable quantities of dynamic geometry using D3D.

The basic process is:

  1. Create a large (e.g. 1MB) dynamic vertex buffer, once during initialization.
  2. The first time in a frame that you want to add vertices to it, Map() it with D3D11_MAP_WRITE_DISCARD. For all subsequent Map()s during the frame use D3D11_MAP_WRITE_NO_OVERWRITE.
  3. When it's locked, you can append an arbitrary quantity of vertex data (up to the 1MB limit) to the buffer.
  4. When you call IASetVertexBuffers() you can set up the appropriate offset within that large buffer, and the stride for the vertex data that you've just added.
  5. In the Draw() call you can pass in the vertex count for the data you just added.

A very similar process applies if you want to create index buffer data too.


bool GlyphClass::InitializeBuffers(ID3D11Device* device)
{
	VertexType* vertices;
	unsigned long* indices;
	D3D11_BUFFER_DESC vertexBufferDesc, indexBufferDesc;
	D3D11_SUBRESOURCE_DATA vertexData, indexData;
	HRESULT result;
	int i;

	m_VertexCount = 6;

	m_IndexCount = m_VertexCount * m_MaxCharInLine;

	vertices = new VertexType[m_VertexCount];
	if (!vertices)
	{
		return false;
	}

	indices = new unsigned long[m_IndexCount];
	if (!indices)
	{
		return false;
	}

	memset(vertices, 0, sizeof(VertexType) * m_VertexCount);

	for (i = 0; i < m_IndexCount; i++)
	{
		indices[i] = i;
	}

	vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
	vertexBufferDesc.ByteWidth = sizeof(VertexType) * m_VertexCount;
	vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
	vertexBufferDesc.MiscFlags = 0;
	vertexBufferDesc.StructureByteStride = 0;

	vertexData.pSysMem = vertices;
	vertexData.SysMemPitch = 0;
	vertexData.SysMemSlicePitch = 0;

	result = device->CreateBuffer(&vertexBufferDesc, &vertexData, &m_VertexBuffer);
	if (FAILED(result))
	{
		return false;
	}

	indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	indexBufferDesc.ByteWidth = sizeof(unsigned long) * m_IndexCount;
	indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
	indexBufferDesc.CPUAccessFlags = 0;
	indexBufferDesc.MiscFlags = 0;
	indexBufferDesc.StructureByteStride = 0;

	indexData.pSysMem = indices;
	indexData.SysMemPitch = 0;
	indexData.SysMemSlicePitch = 0;

	result = device->CreateBuffer(&indexBufferDesc, &indexData, &m_IndexBuffer);
	if (FAILED(result))
	{
		return false;
	}

	delete[] vertices;
	vertices = 0;

	delete[] indices;
	indices = 0;

	return true;


}

vertex buffer will be variable each frame.... user will be typing and glyph vertex buffer data will add to or decrease depend upon typing ...

 

i am allocating only 6 vertices ( m_VertexCount = 6 ) and i see only one glyph instead of of complete text of m_StringToDraw ...

 

vertexbufferDesc is not updating with ... WRITE_DISCARD even...  

 

user with BACKSPACE can reduce m_StringtToDraw to null even or max 260 chars.

vertexbuffer must update in accordance with new string... 

 

 iam getting bad screen flickering if i do


vertexBufferDesc.ByteWidth = sizeof(VertexType) * m_VertexCount * m_MaxCharInLine;

m_MaxCharInLine = 260

Calling ID3D11DeviceContext::Map won't increase the size of the buffer. Think about it: how would that even work? Nowhere do you even have a place to inform D3D how big the buffer should be when you call Map...this is because the buffer has a fixed size specified when you create it. What seems to be happening in your code is that Map is returning a pointer to a block of memory with size == 6 * sizeof(VertexType) and you are overrunning that buffer whenever your string is greater than a single character. To be honest I'm surprised you're not crashing with an access violation. If you enable the debug validation layer I'm sure it will also complain that you're drawing with more indices/vertices than what's present in your buffer.

Your second approach is definitely more in line with what you want: you want to pre-allocate your dynamic vertex buffer to some maximum size and make sure that you write no more than that maximum size whenever you call Map. If this isn't working you probably have another bug somewhere. Have you verified that your strings don't have a length greater than m_MaxCharInLine? You may need to clamp the size, or break up those strings into multiple batches of Map, Copy, Unmap, Draw sequences. Either way I would definitely enable the debug validation layer like I suggested earlier, since it will often let you know when you're doing things incorrectly.

Just a side note, you have possible memory leaks in your codes (both in Init and Update), for example if CreateBuffer or Map fails you return leaving the allocated memory (vertices, indices) unreleased.

This topic is closed to new replies.

Advertisement