[DX11]UpdateSubresource-What am I missing?

Started by
12 comments, last by DieterVW 13 years, 11 months ago
Im trying to change the mesh of a vertex buffer using UpdateSubresource, the layout is the same, everything is the same, I just trying to change the vertices(from a ball to a cube, lets say). Since everything is the same I though doing just a call to UpdateSubresource and then IASetVertexBuffers would be fine, but notting happens, the ball is still being rendered...So Im probaly missing some concepts..No warnings or errors are being displayed on the output.. Some code: The buffer I create at first, this works fine:

D3D11_BUFFER_DESC buffdesc = {0};
		buffdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
		buffdesc.ByteWidth = iSizeOfpV_p;//sizeof( vposnormaltex )*24;//
		buffdesc.Usage = D3D11_USAGE_DEFAULT;
		D3D11_SUBRESOURCE_DATA subres = {0};
			subres.pSysMem = pV_p;//vertex array(ball)


	if( pDevice_p->CreateBuffer( &buffdesc, &subres, &pVBuff_p ) != S_OK ) return E_FAIL;

So I create the Input Layout to the input assemble stage, this works fine also.

//Create Input Layout(based on the desc passed as param)
	D3DX11_PASS_DESC passdesc = {0};
		pEPass_p->GetDesc( &passdesc );

	donne( pInputLayout_p );

	if( pDevice_p->CreateInputLayout(	InputElmDesc_p, NumElm,
										passdesc.pIAInputSignature, passdesc.IAInputSignatureSize,
										&pInputLayout_p ) != S_OK ){
		
		for( UINT i=0; i<NumVB; i++ ) donne( pVBuff_p );
		for( UINT i=0; i<NumIB; i++ ) donne( pIBuff_p );

		return E_FAIL;
	}


	//bind buffers(vertex mesh) to the IA:
	UINT offset = NULL;
	pDIContext_p->IASetVertexBuffers( 0, NumVB, pVBuff_p, strides, &offset );


	//set the input layout to the Input Assembly
	pDIContext_p->IASetInputLayout( pInputLayout_p );

	//set primitive type:
	pDIContext_p->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
Now Im trying to just update the vertex buffer, so I can display other stuff, Im doing this:

//Update VBuffer with new data:
	D3D11_BOX bla; ZeroMemory( &bla, sizeof(D3D11_BOX));
	pDIContext_p->UpdateSubresource( pVBuff_p, 0, &bla, pV_p, 0, 0 );


	//Bind VBuffer to the Input Assemble
	UINT offset = NULL;	
	pDIContext_p->IASetVertexBuffers( 0, 1, &pVBuff_p, &strides[0], &offset );
pVBuff is the same vertex buffer used for the ball, its not Resource interface, is a Buffer interface.. Like I said, nothing happens..What Is going on?
Advertisement
Please run this in a debugger with a debug device and then step through the code call to UpdateSubResource() and see what debug messages occur. That should tell us what the problem is.

And, your D3D10_BOX is all zeros, which should mean copy nothing. To copy the entire contents you should pass in NULL for the box.
Quote:Original post by DieterVW
Please run this in a debugger with a debug device and then step through the code call to UpdateSubResource() and see what debug messages occur. That should tell us what the problem is.

And, your D3D10_BOX is all zeros, which should mean copy nothing. To copy the entire contents you should pass in NULL for the box.


1- Im alredy runing with a debug device.
2- Null for D3D11_BOX results on access violation
Should I set this box with 1 ? Just tryied that, nothing happens yet.
-edit-
Just checked the sdk for the box:
A box that defines the portion of the destination subresource to copy the resource data into. Coordinates are in bytes for buffers and in texels for textures. If NULL, the data is written to the destination subresource with no offset. The dimensions of the source must fit the destination.

So why Im getting access violation when passing NULL? Because my cube have less vertices than the ball? How should I set this cube?
Maybe the D3D debug layer has a bug. Try running without the debug layer and see if null works then.
Very weird, I tested a bunch of times, some times it works, sometimes dont,most times dont, but when it works, it works ALWAYS when I dont quit the application, so I quit and restart, and it will (probaly) dont work again...
This happens on both debug and normal layer...this happens doesnt matter if the box is null or no, and if the rowpitch is null or not...

btw, can someone explain me what should go in the rowpich?(since my buffer is a vertex buffer..)
Just curious, are you doing this for some sort of smooth vertex animation or morphing?

And, this behavior sounds bit more like the use of uninitialized memory. Are you saying that your app always starts out by not working, and then randomly starts working and stays working until you restart?
Im doing this because I want display any number of meshs I want, and all of they have the same layout/format..isnt this a motive for use update subresource?

And no, it doesnt starts working, or it works, or it dont, never both on the same execution.

I alredy asked something like this before, the thing is, since you have a buffer count limit to use, you have to use the same buffer to display lots of stuff, its just that what Im trying to do, reuse the buffer with a new mesh everytime I want. Since its the same format/layout, Im trying to use updatesubresource(and not Map).

Im also not putting everything on the same buffer at once because I want each mesh to have its own world transformations...

Theres any mistake on this concept? Thats how I understand the pipeline...(displaying just one mesh is easy, now I want a entire scene).
So I would use UpdateSubResource only to modify a small part of a buffer while maintaining the data surrounding it, for instance deforming part of a mesh or splatting a texture. Using update subresource may cause the driver to allocate temporary space to store your data due to dependencies of the resource by pending commands in the gpu buffer. Updating the same location in a resource several times a frame in this way will result in worst case performance. UpdateSubResource can perform very well if the driver can schedule the transfer immediately and if there are no pending commands (at least 2 frames worth) that require the data you're trying to overwrite. There's not much you can do about the first. For the second you may make the determination based on your algorithm and how long ago that data was last used, or by keeping track of dependencies by using a query to determine when the gpu is finished with a task.

You can create quite a number of vertex buffers, but creating a couple large ones and then packing them with data is certainly best. You don't want to have to upload the same data more than once if that's at all possible -- you want to limit the amount of data that needs to be moved to the GPU each frame in order to maximize performance. If you have to stream objects in and out then you'll have to work out a way to consolidate or fill holes in the resource.

What you're describing here sounds like a good fit for using Map with a dynamic vertex buffer. Dynamic buffers are designed to provide the fastest path for getting large chunks of new data to the GPU. They also prevent the need for temporary storage allocation and allow the GPU to decide the best scheduling for the transfer. Recommendations will vary depending on many factors so I'll just suggest a few. But the key here is to use Map append.

Simple option:
Once data is on the gpu it can stay there since we're not worried about running out of space. Allocate a very large dynamic buffer and just append new models to it as they are needed. This approach means that you won't use DISCARD since that will cause previously written data in the buffer to be lost. Drawing will require you to know the offsets of each model in the buffer.

More Complicated:
Objects need to be streamed in and have a variable lifetime on the GPU. In this case I would use the dynamic vertex buffer to get data to the GPU, and then do a gpu copy of the new data to a very large default resource in order to maintain it long term. Drawing will still require you to know the offsets into the vertex buffer for each model. The same offsets can also be used to keep track of free spaces as they open up. Depending on how much streaming you end up doing, you will probably have to consolidate the data occasionally to prevent fragmentation. Make sure that the dynamic buffer is large enough to contain all data that you want to stream over the course of at least 2-4 frames so that you don't have to call discard too often.
Dude, this map is so more complex than the old lock or Im getting dumber with experience?..

Doesnt the old lock method returns a pointer to a pointer to the data, so u could just update the data by updating the address pointed to(since is a pointer to a pointer, and not a pointer to the data)..

Now you just cant do it? I will have to update all the data pointed to one by one? I hope Im wrong(probaly).

I mean I cant do this:
D3D11_MAPPED_SUBRESOURCE newdata_map; ZeroMemory( &newdata_map, sizeof(D3D11_MAPPED_SUBRESOURCE) );if( pDIContext_p->Map( pVBuff_p, 0, D3D11_MAP_WRITE_DISCARD, NULL, &newdata_map )!= S_OK ) return E_FAIL;	newdata_map.pData = pV_p;pDIContext_p->Unmap( pVBuff_p, 0 );

neither this:( this copies just the index[0] on the array right?)
D3D11_MAPPED_SUBRESOURCE newdata_map; ZeroMemory( &newdata_map, sizeof(D3D11_MAPPED_SUBRESOURCE) );if( pDIContext_p->Map( pVBuff_p, 0, D3D11_MAP_WRITE_DISCARD, NULL, &newdata_map )!= S_OK ) return E_FAIL;	vposnormaltexmaterial * pData_SRC = (vposnormaltexmaterial*)pV_p;	vposnormaltexmaterial * pData_DST = (vposnormaltexmaterial*)newdata_map.pData;		*pData_DST = *pData_SRC;pDIContext_p->Unmap( pVBuff_p, 0 );

Just that seems to work:
	D3D11_MAPPED_SUBRESOURCE newdata_map; ZeroMemory( &newdata_map, sizeof(D3D11_MAPPED_SUBRESOURCE) );	if( pDIContext_p->Map( pVBuff_p, 0, D3D11_MAP_WRITE_DISCARD, NULL, &newdata_map )!= S_OK ) return E_FAIL;	memcpy( newdata_map.pData, pV_p, iRowPitch_aka_Width );pDIContext_p->Unmap( pVBuff_p, 0 );


Am I doing what is suppose to do?(im using discard now to make my life easier)
Isnt that much less efficient than the lock method?
The pointer returned when calling Map() is the location of the resource on the CPU side. You should memcpy or write your vertex data directly to this memory (making sure not to exceed the resource size) and then Unmap it.

Mapping a dynamic resource many times a frame with D3D11_MAP_WRITE_NO_OVERWRITE will not incur any additional cost. In this scenario you just want to append data to the buffer. Data already in the buffer is still usable by the GPU and unaffected by the call to Map (no locking involved). Of course you have to keep track of where the current 'end' to the buffer is. Mapping with D3D11_MAP_WRITE_DISCARD means that a new buffer will be allocated for you (also no locking involved).

Dynamic resources have a CPU side space and a GPU side space. The CPU side resource makes Mapping them cheap for write new data to them. Later on when you go to use the data, the driver will figure out that it needs do a transfer to the GPU and do so in the most efficient way possible. The driver will also ensure that it only transferred the data that was actually needed to draw the model. So essentially the driver is keeping track of what parts of the dynamic buffer are valid and managing a few things for you.

The transfer is one way, calling discard invalidates everything in the buffer and essentially resets the drivers information about the resource.

This topic is closed to new replies.

Advertisement