Jump to content
  • Advertisement
Sign in to follow this  
cozzie

Copying A D3D11 Buffer To 2D Texture Of Floats

This topic is 876 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all,

I've been struggling with one of my d3d11 book exercises.

What I'm trying to do is create 2 SRV's, based on two float arrays, which will eventually serve as input for a computer shader.

 

My approach:

1 - Create a 2D texture

-- width * height = number of float values in the texture

-- format: DXGI_FORMAT_R32_FLOAT

2 - Create a ID3D11Buffer with the same size

-- bytewidth = width * height * sizeof(float)

-- stride = sizeof(float)

3 - Fill the ID3D11Buffer with the float array's values

4 - Copy the buffer contents to the 2D texture

5 - Create the SRV for the 2D texture

6 - Clean up

 

Although this sounds logical (to me), I'm overseeing something.

The following warning occurs in my approach:

D3D11 ERROR: ID3D11DeviceContext::CopyResource: Cannot invoke CopyResource when the source and destination are not the same Resource type, nor have equivalent dimensions. Src has the following dimensions: Width (102400), Height (1), Depth (1), MipLevels (1), and ArraySize (1). Dst has the following dimensions: Width (160), Height (160), Depth (1), MipLevels (1), and ArraySize (1).  [ RESOURCE_MANIPULATION ERROR #284: COPYRESOURCE_INVALIDSOURCE]

Somehow for the source data (id3d11buffer), a width is defined (width * height, 160x160) and height = 1.

Maybe this is caused by the fact that a d3d11 buffer is 1 dimensional and the texture has 2 dimensions.

 

Can someone give me some pointers on how to solve/ approach this?

 

Here's the code I've made so far:

void CSWrapper::Init(ID3D11Device *pDevice, ID3D11DeviceContext *dc, DirectX::XMFLOAT3* pPrevSolution, DirectX::XMFLOAT3* pCurrSolution, const int pM, const int pN)
{
	// There are 4 views

	// 2 input SRV's	-> prev and curr solution
	// 2 output UAV's	-> curr and next solution

	// The SRV's has to initially be filled and created: textures
	
	/***************************************/
	/**** 1: input SRV (prev solution)	****/
	/***************************************/

	// create texture
	D3D11_TEXTURE2D_DESC inputPrevSolTexDesc;
	inputPrevSolTexDesc.Width				= pM;		// grid size of the waves, rows
	inputPrevSolTexDesc.Height				= pN;		// grid size of the waves, colums
	inputPrevSolTexDesc.MipLevels			= 1;
	inputPrevSolTexDesc.ArraySize			= 1;
	inputPrevSolTexDesc.Format				= DXGI_FORMAT_R32_FLOAT;
	inputPrevSolTexDesc.SampleDesc.Count	= 1;
	inputPrevSolTexDesc.SampleDesc.Quality	= 0;
	inputPrevSolTexDesc.Usage				= D3D11_USAGE_DEFAULT;
	inputPrevSolTexDesc.BindFlags			= D3D11_BIND_SHADER_RESOURCE;
	inputPrevSolTexDesc.CPUAccessFlags		= 0;
	inputPrevSolTexDesc.MiscFlags			= 0;

	ID3D11Texture2D *inputPrevSolTex = 0;
	HR(pDevice->CreateTexture2D(&inputPrevSolTexDesc, 0, &inputPrevSolTex));
	
	// create buffer with the right data
	D3D11_BUFFER_DESC inputDesc;
	inputDesc.Usage					= D3D11_USAGE_DEFAULT;
	inputDesc.ByteWidth				= sizeof(float) * pM * pN;
	inputDesc.BindFlags				= D3D11_BIND_SHADER_RESOURCE;
	inputDesc.CPUAccessFlags		= 0;
	inputDesc.StructureByteStride	= sizeof(float);
	inputDesc.MiscFlags				= 0;	//D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;

	float *tempArrayA = new float[pM*pN];
	for(int i=0;i<pM*pN;++i) tempArrayA[i] = pPrevSolution[0].y;
	
	D3D11_SUBRESOURCE_DATA vinitDataA;
	vinitDataA.pSysMem = &tempArrayA[0];

	delete[] tempArrayA;

	ID3D11Buffer *inputBuffer = NULL;
	HR(pDevice->CreateBuffer(&inputDesc, &vinitDataA, &inputBuffer));

	dc->CopyResource(inputPrevSolTex, inputBuffer);
	ReleaseCOM(inputBuffer);

	// create SRV
	D3D11_SHADER_RESOURCE_VIEW_DESC prevSolSrvDesc;
	prevSolSrvDesc.Format					= DXGI_FORMAT_R32_FLOAT;
	prevSolSrvDesc.ViewDimension			= D3D11_SRV_DIMENSION_TEXTURE2D;
	prevSolSrvDesc.BufferEx.FirstElement	= 0;
	prevSolSrvDesc.BufferEx.Flags			= 0;
	prevSolSrvDesc.BufferEx.NumElements		= pM * pN;

	pDevice->CreateShaderResourceView(inputPrevSolTex, &prevSolSrvDesc, &mInputPrevSolSRV);
	ReleaseCOM(inputPrevSolTex);

Edited by cozzie

Share this post


Link to post
Share on other sites
Advertisement

CopyResource and CopySubresourceRegion require the source and destination resources to be the same type -- so copying from a buffer to a texture is not possible.

You can perform that kind of copy by making an RTV or a UAV for the texture and an SRV for the buffer, and then write a shader that reads from the SRV and writes to the RTV/UAV.
 
This looks like a really complicated way to initialize a texture though:
* Copy from pPrevSolution to a new array.
delete the new array.
Ask D3D to copy your new array (which has been deleted!) into a GPU buffer.
Ask the GPU to copy the buffer into a texture.
Ask D3D to delete the buffer.
 
You can also initialize the texture when you create it in the same way that you've done with the buffer here (specifying initial data as the 2nd parameter to CreateBuffer/CreateTexture).
 
However, some of your variables are called prev/next, indicating you're doing this per frame? And you mention that the data is used by a compute-shader, on the GPU? If so, it's a red flag that this data is being moved back and forth between the CPU and GPU.
What's the big picture problem that you're trying to solve here?

Share this post


Link to post
Share on other sites
Thanks.
The bigger goal is that I want to update the texture through a compute shader, containing heights for waves vertices.

This code is just for initializing the inital wave heights, aka floats in the texture.

Initializing the texture at once when creating the texture initially, sounds like a good solution. How would I do that exactly?

Share this post


Link to post
Share on other sites

You can use a D3D11_SUBRESOURCE_DATA like you do for the buffer, but must also fill in the vinitDataA. SysMemPitch field with the number of bytes per row (e.g. sizeof float * width).

 

Ironically, filling a buffer and copying that into a texture actually is the right way to do this in d3d12 :)

Edited by Hodgman

Share this post


Link to post
Share on other sites
If I said I was already preparing for d3d12 I'd be lying :)

Thanks for helping out, i'll give it a shot tonight (NL time)

Share this post


Link to post
Share on other sites

A first attempt, basically only setting SysMemPitch didn't do the trick, same values for the source and dest resources:

	// create buffer with the right data
	D3D11_BUFFER_DESC inputDesc;
	inputDesc.Usage					= D3D11_USAGE_DEFAULT;
	inputDesc.ByteWidth				= sizeof(float) * pM * pN;
	inputDesc.BindFlags				= D3D11_BIND_SHADER_RESOURCE;
	inputDesc.CPUAccessFlags		= 0;
	inputDesc.StructureByteStride	= sizeof(float);
	inputDesc.MiscFlags				= 0;	//D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;

	float *tempArrayA = new float[pM*pN];
	for(int i=0;i<pM*pN;++i) tempArrayA[i] = pPrevSolution[i].y;
	
	D3D11_SUBRESOURCE_DATA vinitDataA;
	vinitDataA.SysMemPitch = sizeof(float) * pM;
	vinitDataA.pSysMem = &tempArrayA[0];

	delete[] tempArrayA;

	ID3D11Buffer *inputBuffer = NULL;
	HR(pDevice->CreateBuffer(&inputDesc, &vinitDataA, &inputBuffer));

	dc->CopyResource(inputPrevSolTex, inputBuffer);
	ReleaseCOM(inputBuffer);

This might mean that the particular piece of code isn't doing anything anyway... will dig in deeper.

If there's something else I've messed, please shout it out :)

 

Also good to mention, I also get this warning/error with the CopyResource:

D3D11 ERROR: ID3D11DeviceContext::CopyResource: Cannot invoke CopyResource when the Formats of each Resource are not the same or at least castable to each other,

I already figured out that 102400 = 160x160x4, where the texture has 160 width and 160 height and the buffer says '102400' width and '1' height.

Bytes and pixels mixed up ?!?! btw, I'm using DXGI_FORMAT_R32_FLOAT.

Edited by cozzie

Share this post


Link to post
Share on other sites

Sorry, you should be passing vinitDataA to CreateTexture, not CrrateBuffer.

Edited by Hodgman

Share this post


Link to post
Share on other sites

It all works like a charm now, thanks.

Also good to know that when moving the d3d11, I need to still approach it like it did initially now.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

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

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!