Organizing Functions, D3D setup and initialization.

Started by
3 comments, last by JWColeman 5 years, 7 months ago

Hi all, I'm trying to cut down on some of the spaghetti in my code after running through a few lessons and tutorials. Currently, I have everything grouped in a "Renderer" class and I'm trying to break my larger functions down into more manageable bits.

 

I have three main functions that are initializing all my d3d and graphics:

 


void Renderer::InitD3D(HWND hWnd)
{
	// create a struct to hold information about the swap chain
	DXGI_SWAP_CHAIN_DESC scd;

	// clear out the struct for use
	ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));

	// fill the swap chain description struct
	scd.BufferCount = 1;                                   // one back buffer
	scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;    // use 32-bit color
	scd.BufferDesc.Width = SCREEN_WIDTH;                   // set the back buffer width
	scd.BufferDesc.Height = SCREEN_HEIGHT;                 // set the back buffer height
	scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;     // how swap chain is to be used
	scd.OutputWindow = hWnd;                               // the window to be used
	scd.SampleDesc.Count = 4;                              // how many multisamples
	scd.Windowed = TRUE;                                   // windowed/full-screen mode
	scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;    // allow full-screen switching

														   // create a device, device context and swap chain using the information in the scd struct
	D3D11CreateDeviceAndSwapChain(NULL,
		D3D_DRIVER_TYPE_HARDWARE,
		NULL,
		NULL,
		NULL,
		NULL,
		D3D11_SDK_VERSION,
		&scd,
		&swapchain,
		&dev,
		NULL,
		&devcon);


	// get the address of the back buffer
	ID3D11Texture2D *pBackBuffer;
	swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);

	// use the back buffer address to create the render target
	dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer);
	pBackBuffer->Release();

	// set the render target as the back buffer
	devcon->OMSetRenderTargets(1, &backbuffer, NULL);


	// Set the viewport
	D3D11_VIEWPORT viewport;
	ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));

	viewport.TopLeftX = 0;
	viewport.TopLeftY = 0;
	viewport.Width = SCREEN_WIDTH;
	viewport.Height = SCREEN_HEIGHT;

	devcon->RSSetViewports(1, &viewport);
}
void Renderer::InitPipeline(ID3D11Device * dev, ID3D11DeviceContext * devcon)
{
	// load and compile the two shaders
	ID3D10Blob *VS, *PS;
	D3DX11CompileFromFile("Shaders.shader", 0, 0, "VShader", "vs_4_0", 0, 0, 0, &VS, 0, 0);
	D3DX11CompileFromFile("Shaders.shader", 0, 0, "PShader", "ps_4_0", 0, 0, 0, &PS, 0, 0);

	// encapsulate both shaders into shader objects
	dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS);
	dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS);

	// set the shader objects
	devcon->VSSetShader(pVS, 0, 0);
	devcon->PSSetShader(pPS, 0, 0);

	// create the input layout object
	createInputLayout(dev, devcon, VS);
}
void Renderer::InitGraphics(std::vector<Renderable_Object*> Game_Objects)
{
	for (int i = 0; i < Game_Objects.size(); i++)
	{
		for (int j = 0; j < Game_Objects[i]->getVertices().size(); j++)
		{
			OurVertices.push_back(Game_Objects[i]->getVertices()[j]);
		}
	}

	createVertexBuffer(dev);
	createInstanceBuffer(dev);
	createProjectionBuffer(dev);
	createWorldBuffer(dev);
}

I have InitD3D, which creates my device, swapchain, and device context. This seems to make sense to me, its all of the "background" work. The comes InitPipeline, this function in my mind, should be in charge of preparing the pathway in which we will shove data into our shaders for rendering. Then, I have my InitGraphics, which really all I want it to do is setup the data to be shoved down previously mentioned pipeline, right now in my mind i think it is doing more than that. Am I right in thinking creating buffers is part of the pipeline setup, and then after the setup is done, updating those buffers is part of the graphics initiation I am thinking of.

Again, three Phases:

Initialize D3D window and device and crap -> initialize pipeline and way of sending data to it -> push data onto the pipeline for initial rendering

 

One more side question: do I need to use the same subresource that I used to initialize a buffer when I go to update it with map/unmap? Or do I set a new subresource_data? I'm starting to think I need the original subresource_data, or at least a pointer to it, because when I call CreateBuffer I pass it a reference to a subresource_data object...

Sorry all, I tend to ask before I invetigate, given that this code here works just fine for me, it would suggest that I do not need the original subresource, all I need is the data I'm going to update with.


	if (createVertexBuffer(dev))
	{
		// copy the vertices into the buffer
		D3D11_MAPPED_SUBRESOURCE ms;
		devcon->Map(pVBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms);    // map the buffer
		memcpy(ms.pData, OurVertices.data(), sizeof(Vertex) * OurVertices.size());                 // copy the data
		devcon->Unmap(pVBuffer, NULL);                                      // unmap the buffer

	}

So, this means I can successfully separate my buffer creation, from my buffer initialization. I can create my buffers as the cars that will carry crap down the pipeline, in the init pipeline funciton, then I can put people in said cars in the initgraphics function.

Advertisement

So, I just realized that I'm gonna have some difficulty separating the creation of my vertex buffer and the actual filling of the vertex buffer due to the fact that creating the vertex buffer requires me to enter byte width. But to know that I need to know how many vertices I have.

Hmmm, I should be able to get this information another way.

Just trying to organize things in a way that makes sense. I'm sure someone here has gone through these design questions.

 

Okay, maybe I should do this in a blog or something instead of a post, but now I am having difficulty with my instance buffer.

 

I create it like this:


bool Renderer::createInstanceBuffer(ID3D11Device * dev, UINT bufferSize)
{
	HRESULT hr;
	D3D11_BUFFER_DESC bd;

	// Set up the description of the instance buffer.
	bd.Usage = D3D11_USAGE_DYNAMIC;
	bd.ByteWidth = bufferSize;
	bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
	bd.MiscFlags = 0;
	bd.StructureByteStride = 0;

	hr = dev->CreateBuffer(&bd, NULL, &pIBuffer);
	if (!FAILED(hr))
	{
		return true;
	}
	else
	{
		return false;
	}

}

it's so weird, I reduced to one instance, to make sure all my functional parameters and such were correct, then like, every other time I run, it throws an exception, and then it doesn't, and then it does.

And then, I fill it like this:


bool Renderer::UpdateBuffer(ID3D11DeviceContext * devcon, ID3D11Buffer * buffer, void * data, size_t size)
{
	HRESULT hr;
	D3D11_MAPPED_SUBRESOURCE ms;

	hr = devcon->Map(buffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms);    // map the buffer
	if (!FAILED(hr))
	{
		memcpy(ms.pData, data, size);                 // copy the data
		devcon->Unmap(buffer, NULL);                                      // unmap the buffer
		return true;
	}
	else
	{
		return false;
	}
}

 

I'm making the two calls like this:

 


	for (int i = 0; i < instanceCount; i++)
	{
		OurInstances.push_back(instances[i]);
	}

	if (createInstanceBuffer(dev, sizeof(InstanceBuffer) * instanceCount))
	{
		UpdateBuffer(devcon, pIBuffer, OurInstances.data(), sizeof(InstanceBuffer) * OurInstances.size()); // Initialize Vertex Buffer
	}

Eventually, another bit of code will take care of preparing the OurInstances vector (something in my renderable_object)

 

Both calls to create instance buffer and updatebuffer seem to be working successfully, they aren't creating any immediate exceptions or explicitly failing, I even see my instances drawn on my screen!

image.png.2bd16428617f03f03227571c5433a440.png

 

But on exiting the application, the thing seems to shut down and throw an exception that I can't really track down, is this something I should turn debug mode on to explain to me? Can any of you identify what I'm doing wrong?

image.thumb.png.b02120047ce8dd921e733c1fbe7ecbd0.png

 

 

Hey guys, just thought I'd like to update you on the stupidity of my error, now resolved.

 

Never do this:

 


	InstanceBuffer * instances;
	
	instances = new InstanceBuffer[instanceCount];
	instances[0].position = D3DXVECTOR3(-300, -100, 0);
	
	instances[1].position = D3DXVECTOR3(-200, 100, 0);
	instances[2].position = D3DXVECTOR3(-100, -100, 0);
	/*
	instances[3].position = D3DXVECTOR3(0, 100, 0);
	instances[5].position = D3DXVECTOR3(100, -100, 0);
	instances[6].position = D3DXVECTOR3(200, 100, 0);
	instances[7].position = D3DXVECTOR3(300, -100, 0);
	*/
	instanceCount = 3;

 

Instead, do this:


	InstanceBuffer * instances;
	instanceCount = 3;
	instances = new InstanceBuffer[instanceCount];
	instances[0].position = D3DXVECTOR3(-300, -100, 0);
	
	instances[1].position = D3DXVECTOR3(-200, 100, 0);
	instances[2].position = D3DXVECTOR3(-100, -100, 0);
	/*
	instances[3].position = D3DXVECTOR3(0, 100, 0);
	instances[5].position = D3DXVECTOR3(100, -100, 0);
	instances[6].position = D3DXVECTOR3(200, 100, 0);
	instances[7].position = D3DXVECTOR3(300, -100, 0);
	*/

 

Anyways, I'll quit posting here unless someone responds, I'll move my commentary to my blog! :)

This topic is closed to new replies.

Advertisement