Jump to content
  • Advertisement
Steven Ford

DX11 DX11 - Problem with SOSetTargets

Recommended Posts

HI all,

I'm currently stuck on something which should be rather simple. I'm trying to use the Stream Out functionality to offload a set of calculations to the GPU but I'm having enormous difficulties in getting it to work. The code that I have to create my buffer (once, not per frame) is as follows:

// Member variable..
Microsoft::WRL::ComPtr<ID3D11Buffer> _streamOutBuffer;

	// Create the buffer which will be used to handle the stream output stage
	{
		D3D11_BUFFER_DESC bufferDesc;
		ZeroMemory(&bufferDesc, sizeof(bufferDesc));
		bufferDesc.ByteWidth =
			WATERMANAGER_GRIDX * _gameEngine->getWidth() *
			WATERMANAGER_GRIDY * _gameEngine->getHeight() *
			sizeof(WATERRENDERERERBASE_DROPLETINSTANCE_DETAILS); // This evaluates to 307200
		bufferDesc.BindFlags = D3D11_BIND_FLAG::D3D11_BIND_STREAM_OUTPUT | D3D11_BIND_FLAG::D3D11_BIND_VERTEX_BUFFER;
		hr = dxDevice->CreateBuffer(&bufferDesc, nullptr, &_streamOutBuffer);
		if (hr != S_OK)
			return;
	}

The code that I have to use the buffer subsequently is:

	// Set the target output
	UINT offset = 0;
	context->SOSetTargets(1, &_streamOutBuffer, &offset);	

	context->Draw(vertexCount, 0);

	// Reset the buffers
	ID3D11Buffer* buffers[1] = { 0 };
	context->SOSetTargets(0, buffers, &offset);

The problem that I have is that on the first call to 'SOSetTargets' the value of _streamOutBuffer gets set to being a null pointer which I simply don't understand why. If I use an intermediate value to store a copy of the pointer, then on subsequent frames I get access violation exceptions so it appears that something destructive is happening to the object. NOte that manually calling 'AddRef' didn't stop this.

Looking on MSDN (Getting started and Method doc) it doesn't appear that I'm doing anything different to the examples that I can find (including Frank Luna's DX11 book).

Can anyone shed any light as to what could be going on here / point me in the right direction please?

If it's helpful, the following is the following per frame code:

 

	// Set all the inputs
	context->IASetInputLayout(_inputLayoutExpanding.Get());
	context->VSSetShader(_vertexShaderExpanding->shader.Get(), nullptr, 0);
	context->GSSetShader(_geometryShaderWithSO.Get(), nullptr, 0);
	context->PSSetShader(nullptr, nullptr, 0);

	auto pointer = _vertexBuffer.Get();
	UINT vertexStride = sizeof(unsigned int);
	UINT vertexOffset = 0;
	context->IASetVertexBuffers(0, 1, &pointer, &vertexStride, &vertexOffset);

	// Set the constant buffers
	ID3D11Buffer* vertexShaderCBs[1] = { _vertexShaderConstantBuffer.Get() };
	ID3D11Buffer* geometryShaderCBs[1] = { _geometryShaderConstantBuffer.Get() };
	context->VSSetConstantBuffers(0, 1, vertexShaderCBs);
	context->GSSetConstantBuffers(0, 1, geometryShaderCBs);
	context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY::D3D_PRIMITIVE_TOPOLOGY_POINTLIST);

//	context->RSSetScissorRects(0, nullptr);

	ID3D11DepthStencilState* depthStencilStates[1];
	UINT stencilRef;
	context->OMGetDepthStencilState(depthStencilStates, &stencilRef);

	// Initialize the description of the stencil state.
	D3D11_DEPTH_STENCIL_DESC depthStencilDesc;
	ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));

	Set up the description of the stencil state.
	depthStencilDesc.DepthEnable = false;
	depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
	Microsoft::WRL::ComPtr<ID3D11DepthStencilState> noWriteDepthStencil;
	this->_device->CreateDepthStencilState(&depthStencilDesc, &noWriteDepthStencil);
	context->OMSetDepthStencilState(noWriteDepthStencil.Get(), 0);

	// Set the target output
	UINT offset = 0;
	context->SOSetTargets(1, &_streamOutBuffer, &offset);	

	context->Draw(vertexCount, 0);

	// Reset the buffers
	ID3D11Buffer* buffers[1] = { 0 };
	context->SOSetTargets(0, buffers, &offset);
	
	context->VSSetShader(nullptr, nullptr, 0);
	context->GSSetShader(nullptr, nullptr, 0);
	context->OMSetDepthStencilState(depthStencilStates [ 0 ], stencilRef);

Thanks

Steve

Share this post


Link to post
Share on other sites
Advertisement

SoldierOfLight is right, personally, i do not like the com ptr, so i usually roll my own smart pointer to deal with dx objects. 

 

On a side note, have you look at compute shaders, they are usually a better solution than the stream output because they don't involve the uber costly and inefficient geometry shader stage.

Share this post


Link to post
Share on other sites

Thanks guys, I've gotten it working now (Well, the DrawAuto call isn't working as I'd expect, but that's a small issue).

@galop1n - I have a large array representing a 2D water space (up to 200,000 points, each represented by 4bits), and was looking to use a GS to simply transfer that array to the GPU, and then run the GS over it to output the instance information (location / fluid colour) into a stream out buffer and then render that, using instancing to achieve the fluid representation. As I need to do the filtering, I was under the impression that the only way to do this on the GPU was to use geometry shaders they have conditionality?

The background to this project is to learn how the whole environment fits together so I can do the next project much quicker

One other option which has been cropped up in my mind would be to copy the array to a buffer, and then bind it as a form of texture and then render a single quad covering the entire level and have a pixel shader look up in my array based off where its screen position and either discard for empty values or pick the appropriate colour.

Although having said all of this, even on my old netbook, the CPU implementaiton of the looping through this data and building the instance buffer in CPU space in a single threaded approach still allows me to hit 60fps so I think it may well be an [admittedly quite interesting] optimisation too far.

waterRendering.png

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!