Sign in to follow this  
AgentShiva

Explanation of ID3D10Buffer::Map() and Unmap()

Recommended Posts

I have read through the MSDN page and looked through the SDK documentation but still the usage of these functions eludes me. Could someone explain how I would read the data from a ID3D10Buffer of verticies, and store it in a vector of custom vertexs, please? Thanks in advance =) [Edited by - AgentShiva on October 24, 2008 3:49:59 PM]

Share this post


Link to post
Share on other sites
Map() is the same as the DX9 Lock() method, if you know what that is.

If not, Map() is a way of getting ownership of a buffer (or part of it) for a given period of time. During that time, you have ownership of the data in the buffer, and may read or write to it (depending on certain factors), and DX does not modify the data (or move it around) while you have this ownership.

Calling Map() is pretty simple. You tell it what actions you need to be able to do on the data (Read, write, etc). You can also pass in an optional flag for special types of locks, but for basic needs you can just pass 0 for that parameter. Finally, you pass in the address of a pointer. This is an out parameter that is assigned the address of the start of the mapped region of the resource or subresource. In the case of a buffer, it'll be the start of the buffer. From there, you read the data from the pointer as you would with any pointer to regular memory (either cast it to the correct pointer-to-data-type or use memcpy). When you're done with the mapped region, you unmap to tell DX you no longer require ownership of the resource.

That's the basics of it.

If you have any more questions, feel free to ask.

[EDIT] it is important to remember that not every resource can be mapped. Some resources cannot be mapped since they were not created with the correct CPU access flag. To map those resources, you'll need to use CopyResource to copy the data in the resource to a new one of the same dimensions, that was created with the correct CPU access flags. Once you copy, you can map the copy and access the data from there.

Share this post


Link to post
Share on other sites
So if I wanted to Map a vertex buffer to a vector of custom vertex type, such as


struct VertexStruct
{
D3DXVECTOR3 pos;
};



I would create an empty vector<VertexStruct> tempVerts then pass a pointer to that as the third parameter in Map? Of course passing it as &tempVerts[0], just like any other vector.

Share this post


Link to post
Share on other sites
Quote:
Original post by sirob
Map() is the same as the DX9 Lock() method, if you know what that is.

If not, Map() is a way of getting ownership of a buffer (or part of it) for a given period of time. During that time, you have ownership of the data in the buffer, and may read or write to it (depending on certain factors), and DX does not modify the data (or move it around) while you have this ownership.

Calling Map() is pretty simple. You tell it what actions you need to be able to do on the data (Read, write, etc). You can also pass in an optional flag for special types of locks, but for basic needs you can just pass 0 for that parameter. Finally, you pass in the address of a pointer. This is an out parameter that is assigned the address of the start of the mapped region of the resource or subresource. In the case of a buffer, it'll be the start of the buffer. From there, you read the data from the pointer as you would with any pointer to regular memory (either cast it to the correct pointer-to-data-type or use memcpy). When you're done with the mapped region, you unmap to tell DX you no longer require ownership of the resource.

That's the basics of it.

If you have any more questions, feel free to ask.

[EDIT] it is important to remember that not every resource can be mapped. Some resources cannot be mapped since they were not created with the correct CPU access flag. To map those resources, you'll need to use CopyResource to copy the data in the resource to a new one of the same dimensions, that was created with the correct CPU access flags. Once you copy, you can map the copy and access the data from there.

Is one of the two methods better (performance only)? So let's say either mapping and unmapping the buffer or using a second resource and copying it? Except memory usage!

I know that copyresource may... or better MS says that it shouldn't stall the GPU. Does anyone know if this works: I write my data always to the second resource, call copyresource and the data will be copied sometime. Would it be possible that the GPU gets stalled again if lets say one or two frames next it tries to copy the resource (which may already been updated once or twice by me) to "its" resource and "can't do this because I have locked the source resource for updating it".

thx,
Vertex


Share this post


Link to post
Share on other sites
Trying to make a terrain editor too Vertex? Mapping I guess is one of the huge things for them, updating vertex positions and what not to create the actual terrain. That is what I am doing. I have also heard about the copysubresource method, but that all. No one ever go into detail when it comes to the hard stuff.

Share this post


Link to post
Share on other sites
Quote:
Original post by AgentShiva
I would create an empty vector<VertexStruct> tempVerts then pass a pointer to that as the third parameter in Map? Of course passing it as &tempVerts[0], just like any other vector.

Not quite, the indirection level is different. &tempVerts[0] returns a Vertex*, while the method expects a Vertex **.

The correct way to use Map() would be something like this:
void *data;
m_Buffer()->Map(..., &data);
Vertex *verts = (Vertex*)data;

You'll notice that you don't tell DX where to put the data, but rather DX gives you the address of where the data is. That's why you can't Map directly to a vector.
If you do want to use a vector to handle your vertices, you'll need to copy the data from the array-of-bytes you get from DX (the data pointer) to a new vector that has been resized to the size of the buffer.

Share this post


Link to post
Share on other sites
Quote:
Original post by Vertex333
Is one of the two methods better (performance only)? So let's say either mapping and unmapping the buffer or using a second resource and copying it? Except memory usage!

From a simple performance standpoint, calling Map (without copying the resource) would be faster. That is, it does less work. However, the situation is much more complicated if the resource you are copying to is in-use. In this case, a normal Map() call (with no special flags) would stall until the resource is no longer in-use. On the other hand, a CopyResource call would simply be queue'd up to the command queue and wait until all previous commands were completed, and then perform the copy. In this situation, there is a chance using a "Staging" resource that isn't in use by the GPU, and Map()ing it, then using CopyResource to copy the data over might be quicker. Keep in mind, however, that there is quite a bit of overhead involved in this process (Resource Creation and an extra copy of all the data in the resource) which might make this slower than a regular map.

In addition, if you're modifying most of the resource, Map()ing with the Discard flag would likely be quicker than an extra copy.

Share this post


Link to post
Share on other sites
Quote:
Original post by sirob
Quote:
Original post by Vertex333
Is one of the two methods better (performance only)? So let's say either mapping and unmapping the buffer or using a second resource and copying it? Except memory usage!

From a simple performance standpoint, calling Map (without copying the resource) would be faster. That is, it does less work. However, the situation is much more complicated if the resource you are copying to is in-use. In this case, a normal Map() call (with no special flags) would stall until the resource is no longer in-use. On the other hand, a CopyResource call would simply be queue'd up to the command queue and wait until all previous commands were completed, and then perform the copy. In this situation, there is a chance using a "Staging" resource that isn't in use by the GPU, and Map()ing it, then using CopyResource to copy the data over might be quicker. Keep in mind, however, that there is quite a bit of overhead involved in this process (Resource Creation and an extra copy of all the data in the resource) which might make this slower than a regular map.

In addition, if you're modifying most of the resource, Map()ing with the Discard flag would likely be quicker than an extra copy.
Thx!

I have one more question that "should be more" logical. Am I right that when rendering is done in only every 100ms (so not more than 10FPS) I should ignore gpu stalling anyway? Ok, maybe a bad idea to say this in general, but my first test showed me that copying may not be that good.

Vertex

Share this post


Link to post
Share on other sites
My tests showed to me that UpdateSubresource is faster or as fast as Map. This may be due to the different buffer usages (default and dynamic). MSDN says that it is possible that one of each can be faster. Nevertheless, how can I determine if there is resource contention in my application. I know that PIX shows stalling, but I want to be able to know/speculate it from a technical view. So, how can I say if my resources have contention or not.


Another question: What should cost more? Handling more arrays and copy only some of them with updatesubresource to a large constant buffer or handling one big array and always copying the whole buffer to a large constant buffer. Consider that there is either no update (nothing affected), update for some parts (some small arrays affected or the big array affected) or all parts (all small arrays affected or the big array affected). A large array means only one call, many small arrays mean a lot calls. From the CPU perspective (less CPU usage, which is important more important for me than GPU usage) a large array with one call of updatesubresource could be less cpu overhead (but it's also more to copy for the cpu, so... I don't know).

As a note the effect system seem to work also with updatesubresource (according to what I have seen with PIX in my application) for setting constant buffers/variables. This says to me that it may even be better to pack variables that may not be used by all techniques together if they would get update at the same frequency (saves updatesubresource calls). Or maybe there is a call for every variable anyway (which would be quite bad :().

Vertex.

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

Sign in to follow this