Jump to content

  • Log In with Google      Sign In   
  • Create Account

Questions about Map/UpdateSubResource


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
19 replies to this topic

#1 Tape_Worm   Crossbones+   -  Reputation: 1761

Like
0Likes
Like

Posted 19 January 2012 - 10:26 PM

I'm finding the whole change from Lock/Unlock to Map/Unmap and UpdateSubResource to be a little perplexing.

So, here's how I handle when to use Map and when to use UpdateSubResource:
For dynamic usage buffers, I use Map/Unmap (UpdateSubResource doesn't like dynamic from what I gather), and for default usage I use UpdateSubResource. Is this a good rule of thumb? Or does this change depending on the type of buffer? For constant buffers I tend to just use default usage and UpdateSubResource, but I've read that UpdateSubResource for Textures and Vertex/Index buffers is on the slow side.

Secondly, with Lock in D3D9, you can Lock a region of the buffer. Am I able to Map a region of a buffer? Or how about UpdateSubResource on a particular portion of the buffer? I've read that when you update a constant buffer, you have to do the entire buffer. For textures you can update a region of the buffer, and for vertex/index buffers... well, I've read about people suggesting to update a portion of those buffers, but I've not found any concrete examples of anyone actually doing it. So is it possible with Vertex/Index buffers? If you can, how in the hell do you map it out so that you map at an offset of 16 bytes in the buffer and a range of 32 bytes? This whole stride/index/rowpitch thing is a little weird for a linear buffer.

I'm not a big fan of the API layout thus far. Having the Map/UpdateSubResource on the context and not the object with the "kitchen sink" parameters is a little more than confusing and what I've found in the docs don't really explain in detail what applies to what, or more accurately, they don't seem to say what -not- to do.

Sorry if this all sounds really dumb, but I'm quite new to the API and trying to make sense of it. Thanks in advance for any insight.

Sponsor:

#2 Jason Z   Crossbones+   -  Reputation: 5062

Like
2Likes
Like

Posted 20 January 2012 - 04:50 PM

Map is used to map a complete subresource - for buffers that means the whole buffer, and for textures that can mean a lot of different things depending on the dimension, array size, and mip levels. UpdateSubResource has the ability to update only a portion of a subresource, which can be an advantage in some cases.

I personally use Map to update my constant buffers in Hieroglyph3, but I think either method can be used...

#3 jsedlak   Members   -  Reputation: 100

Like
0Likes
Like

Posted 20 January 2012 - 09:40 PM

Map is used to map a complete subresource - for buffers that means the whole buffer, and for textures that can mean a lot of different things depending on the dimension, array size, and mip levels. UpdateSubResource has the ability to update only a portion of a subresource, which can be an advantage in some cases.


How do you map a subresource into a position in an array of another?

#4 Jason Z   Crossbones+   -  Reputation: 5062

Like
0Likes
Like

Posted 21 January 2012 - 12:42 AM


Map is used to map a complete subresource - for buffers that means the whole buffer, and for textures that can mean a lot of different things depending on the dimension, array size, and mip levels. UpdateSubResource has the ability to update only a portion of a subresource, which can be an advantage in some cases.


How do you map a subresource into a position in an array of another?

Sorry, I don't understand the question - do you mean mapping a texture subresource to another texture array subresource? If so, then for mapping you just map the two subresources and then copy the data directly. With UpdateSubResource you more or less specify the locations in the parameter arguments and the function does the copying for you.

#5 Erik Rufelt   Crossbones+   -  Reputation: 3480

Like
0Likes
Like

Posted 21 January 2012 - 06:55 AM

In general, I believe dynamic buffers are best if you want to use them the same frame as you update them. If you have a lot of data and want to update once and then use the same data multiple times on the GPU, default buffers with UpdateSubResource are probably better.

#6 jsedlak   Members   -  Reputation: 100

Like
0Likes
Like

Posted 21 January 2012 - 10:37 AM



Map is used to map a complete subresource - for buffers that means the whole buffer, and for textures that can mean a lot of different things depending on the dimension, array size, and mip levels. UpdateSubResource has the ability to update only a portion of a subresource, which can be an advantage in some cases.


How do you map a subresource into a position in an array of another?

Sorry, I don't understand the question - do you mean mapping a texture subresource to another texture array subresource? If so, then for mapping you just map the two subresources and then copy the data directly. With UpdateSubResource you more or less specify the locations in the parameter arguments and the function does the copying for you.


I'm probably not asking the right question... (and yes, sorry for the hijack)
http://www.gamedev.net/topic/618817-using-texture2darray-and-shaderresourceview/

#7 Tape_Worm   Crossbones+   -  Reputation: 1761

Like
0Likes
Like

Posted 21 January 2012 - 02:12 PM

Map is used to map a complete subresource - for buffers that means the whole buffer, and for textures that can mean a lot of different things depending on the dimension, array size, and mip levels. UpdateSubResource has the ability to update only a portion of a subresource, which can be an advantage in some cases.

I personally use Map to update my constant buffers in Hieroglyph3, but I think either method can be used...


So, you can update a portion of a vertex buffer with UpdateSubResource then? I'm just wondering how I would pass the offset within the buffer and the number of bytes to update to the UpdateSubResource method? Can you use UpdateSubResource to update a portion of a constant buffer?

#8 Erik Rufelt   Crossbones+   -  Reputation: 3480

Like
0Likes
Like

Posted 21 January 2012 - 05:46 PM

You can also update just part of it with Map, if you use D3D11_MAP_WRITE instead of D3D11_MAP_WRITE_DISCARD. I'm not sure what restrictions apply to the usage and bind-flags for uncommon cases, but that is easy to look up or test.
http://msdn.microsoft.com/en-us/library/windows/desktop/ff476181%28v=vs.85%29.aspx
You probably don't want to do that for a constant-buffer, as they are usually relatively small. Doubtful it's ever worth it compared to overwriting the whole thing with a discarding map.
http://msdn.microsoft.com/en-us/library/windows/desktop/ff476259%28v=vs.85%29.aspx has additional discussion on dynamic usage.

#9 Jason Z   Crossbones+   -  Reputation: 5062

Like
1Likes
Like

Posted 22 January 2012 - 01:41 AM

In the remarks on this page, it explicitly says that you can't update a portion of a constant buffer, but there is no mention of doing it for a vertex buffer (although it mentions updating vertex buffers in general, so it should be possible). I've never explicitly tried it, but I would assume that you use the same addressing concept for the destination box as you would for a 1D texture (there is also a sample of that on the link above).

It would probably be worth doing a quick test, where you create a vertex buffer that is all zeros, then update only the second element with all ones. If it works in that case (which can be verified with PIX) then you should be good to go.

As a side note, the two methods are similar enough that it shouldn't be too hard to build support for either method and dynamically decide which one to use. This would be ideal so that you can profile and see how fast one or the other is. In the end, they both end up doing the same thing - copying data from CPU memory to a resource in GPU memory. There is some difference in the way that the driver handles it, but I suspect there isn't much performance difference between the two methods. To be honest, I've never heard anyone say that one is better than the other...

And one final point - notice the comments about deferred contexts at the bottom of the linked page!

EDIT: I also found this link, which has some good discussion about the topic. In there it says that mapping a buffer uses bytes in the D3D11_BOX, while textures use pixels for the units...

#10 Jason Z   Crossbones+   -  Reputation: 5062

Like
0Likes
Like

Posted 22 January 2012 - 01:53 AM

You can also update just part of it with Map, if you use D3D11_MAP_WRITE instead of D3D11_MAP_WRITE_DISCARD. I'm not sure what restrictions apply to the usage and bind-flags for uncommon cases, but that is easy to look up or test.
http://msdn.microsof...v=vs.85%29.aspx
You probably don't want to do that for a constant-buffer, as they are usually relatively small. Doubtful it's ever worth it compared to overwriting the whole thing with a discarding map.
http://msdn.microsof...v=vs.85%29.aspx has additional discussion on dynamic usage.

Mapping with write will end up mapping the whole sub-resource too, as far as I know. There are some specialized cases where a vertex or index buffer can be partially updated with WRITE_DISCARD and WRITE_NO_OVERWRITE flags, but they are very special cases (building dynamic vertex / index buffers as opposed to dynamically updating the contents of the buffers).

#11 Tape_Worm   Crossbones+   -  Reputation: 1761

Like
0Likes
Like

Posted 24 January 2012 - 04:59 PM


You can also update just part of it with Map, if you use D3D11_MAP_WRITE instead of D3D11_MAP_WRITE_DISCARD. I'm not sure what restrictions apply to the usage and bind-flags for uncommon cases, but that is easy to look up or test.
http://msdn.microsof...v=vs.85%29.aspx
You probably don't want to do that for a constant-buffer, as they are usually relatively small. Doubtful it's ever worth it compared to overwriting the whole thing with a discarding map.
http://msdn.microsof...v=vs.85%29.aspx has additional discussion on dynamic usage.

Mapping with write will end up mapping the whole sub-resource too, as far as I know. There are some specialized cases where a vertex or index buffer can be partially updated with WRITE_DISCARD and WRITE_NO_OVERWRITE flags, but they are very special cases (building dynamic vertex / index buffers as opposed to dynamically updating the contents of the buffers).

You can also update just part of it with Map, if you use D3D11_MAP_WRITE instead of D3D11_MAP_WRITE_DISCARD. I'm not sure what restrictions apply to the usage and bind-flags for uncommon cases, but that is easy to look up or test.
http://msdn.microsof...v=vs.85%29.aspx
You probably don't want to do that for a constant-buffer, as they are usually relatively small. Doubtful it's ever worth it compared to overwriting the whole thing with a discarding map.
http://msdn.microsof...v=vs.85%29.aspx has additional discussion on dynamic usage.


So, I did some investigation (boy, I wish they'd document this stuff more explicitly) and I found this:
I -can- update a portion of the vertex buffer when I use UpdateSubResource by defining the left and right fields of the destination box. So there's that.

I can't seem to do it for Map though. I tried using the Write flag and the debug gave me this:
D3D11: ERROR: ID3D11DeviceContext::Map: Map cannot be called with MAP_WRITE access, because the Resource was created as D3D11_USAGE_DYNAMIC. D3D11_USAGE_DYNAMIC Resources must use either MAP_WRITE_DISCARD or MAP_WRITE_NO_OVERWRITE with Map. [ RESOURCE_MANIPULATION ERROR #2097210: RESOURCE_MAP_INVALIDMAPTYPE ]
So, I changed it to default, with no CPU write access (can't use CPU write with default resources) and I got this:
D3D11: ERROR: ID3D11DeviceContext::Map: Map cannot be called with MAP_WRITE access, because the Resource was not created with the D3D11_CPU_ACCESS_WRITE flag. [ RESOURCE_MANIPULATION ERROR #2097210: RESOURCE_MAP_INVALIDMAPTYPE ]

Anyway, this has been extremely helpful, so thank you all.

I do have another question though... what is this Subresource parameter I'm seeing? What's its purpose and how is it used?

Thanks!

#12 Jason Z   Crossbones+   -  Reputation: 5062

Like
1Likes
Like

Posted 25 January 2012 - 12:17 AM

Your first error is because your vertex buffer either didn't have a dynamic usage, or perhaps that you didn't indicate that you wanted write access with the CPU flags parameter. The second one makes sense, since you don't have any way to update a default resource with the CPU...

The sub-resource is a portion of a complete resource (obviously :) ) that is simply an index to point to that part of it. So for textures there is a separate subresource index for each mip level, each array slice, etc... For buffers, there is only one subresource - the whole buffer.

I dedicated quite a bit of time to researching each possibility and they are explicitly shown in our book (chapter 2, for each resource type) - but if you trawl through the online documentation you can also find the subresource information.

#13 Tape_Worm   Crossbones+   -  Reputation: 1761

Like
0Likes
Like

Posted 27 January 2012 - 10:42 AM

Your first error is because your vertex buffer either didn't have a dynamic usage, or perhaps that you didn't indicate that you wanted write access with the CPU flags parameter. The second one makes sense, since you don't have any way to update a default resource with the CPU...

The sub-resource is a portion of a complete resource (obviously Posted Image ) that is simply an index to point to that part of it. So for textures there is a separate subresource index for each mip level, each array slice, etc... For buffers, there is only one subresource - the whole buffer.

I dedicated quite a bit of time to researching each possibility and they are explicitly shown in our book (chapter 2, for each resource type) - but if you trawl through the online documentation you can also find the subresource information.


Awesome.

As an additional thank you, I've purchased your book.

#14 Jason Z   Crossbones+   -  Reputation: 5062

Like
0Likes
Like

Posted 27 January 2012 - 12:06 PM

Great - I look forward to hearing what you think about it!

#15 360GAMZ   Members   -  Reputation: 133

Like
0Likes
Like

Posted 31 January 2012 - 05:18 PM

On a related note, D3D11_MAP_WRITE_NO_OVERWRITE is not allowed with Structured Buffers, Raw Buffers, or regular buffers. This is unfortunate when you want to dynamically append data to what you've already written. DX 11.1 fixes this, but not sure when it'll be released, whether it'll be available on Windows 7, and whether existing DX11 graphics cards will support it.

Assuming that DX 11.1 isn't a possibility, the only ways we have of updating a Structured Buffer are either D3D11_MAP_WRITE_DISCARD or UpdateSubresource. For our app, DISCARD won't work because it makes all previously written data unavailable to further draw calls, and our shaders need access to the entire buffer. So that leaves UpdateSubresource as our only option, I believe. I'm unclear as to whether our Structured Buffer should be created as DEFAULT or DYNAMIC for best performance with UpdateSubresource.

Structured Buffers created as DYNAMIC reside permanently in system memory. The data is streamed to the graphics card over the bus as the shader needs it. I assume that when UpdateResource is called, the driver makes a copy of the data in temp memory and then simply copies it to the buffer in system memory when it's safe to. Contrast this with D3D11_MAP_WRITE_NO_OVERWRITE on vertex buffers, where the app can write directly to the destination memory location without the driver making a copy.

StructuredBuffers created as DEFAULT reside in video memory with faster access by the shader. When UpdateResource is called, I assume the driver still needs to make a copy of the data in temp memory and then upload it to video memory at a safe time. Still a lot of copying.

If anyone has experience with the fastest way to incrementally update Structured Buffers, would love to hear it!

#16 360GAMZ   Members   -  Reputation: 133

Like
0Likes
Like

Posted 01 February 2012 - 03:33 PM

I'm unclear as to whether our Structured Buffer should be created as DEFAULT or DYNAMIC for best performance with UpdateSubresource.


Update: UpdateSubresource requires that the resource have been created as DEFAULT without CPU write access.

#17 mhagain   Crossbones+   -  Reputation: 7979

Like
0Likes
Like

Posted 01 February 2012 - 05:21 PM

I've used MAP_WRITE_NO_OVERWRITE and MAP_WRITE_DISCARD and it doesn't seem to have had any adverse impact on performance (overall a good deal faster than D3D9, but I haven't benched this in isolation), but still ... it would be really nice to see some clear documentation or guidelines coming from MS on what you need to do in order to replicate the old NOOVERWRITE/DISCARD Locking pattern, because right now it's just as head-scratching as GL_ARB_vertex_buffer_object, and that's not a good thing.

It appears that the gentleman thought C++ was extremely difficult and he was overjoyed that the machine was absorbing it; he understood that good C++ is difficult but the best C++ is well-nigh unintelligible.


#18 360GAMZ   Members   -  Reputation: 133

Like
0Likes
Like

Posted 01 February 2012 - 05:28 PM

For vertex & index buffers, you should be able to use the NO_OVERWRITE/DISCARD locking pattern just as in the DX9 days. You'll just need to make sure you create the resources with DYNAMIC and CPU write access.

For Structured Buffers, Raw Buffers, and normal buffers, NO_OVERWRITE isn't supported which is very unfortunate. So, the only way to do incremental updating of one of these types of buffers is through UpdateSubresource(). In this case, the resource needs to be created with DEFAULT and no CPU write access.

#19 mhagain   Crossbones+   -  Reputation: 7979

Like
0Likes
Like

Posted 02 February 2012 - 08:55 AM

The key difference however is: with the old way, when locking with no overwrite, you specify a start offset and size to lock. When mapping you don't - you get the entire buffer contents. And that is the source of confusion: what assurance have you that your no overwrite map is going to stand a chance of actually doing what you asked it to do (and not stalling the pipeline)?

OK, I know that the old locking flags were hints, not absolute assurances, but that doesn't make the difference go away - how do you hint to D3D11 that this is the behaviour you want?

So right now I'm just casting the pData member of D3D11_MAPPED_SUBRESOURCE to my vertex structure type, incrementing the pointer by the required amount, and writing in. Like I said, that seems to work and it doesn't cause any performance loss, but in the absence of any documented description of what's happening (and it could be as simple as "yeah, do this" and "no, don't do that") it feels an awful lot like throwing magic pixie dust in the air and seeing what comes down. That's not fun. D3D9 had a clear and well-documented approach for this buffer usage pattern (and let's leave out buffer types to which it doesn't apply), D3D11 doesn't.

So I guess what's needed is a D3D11 equivalent of usage style 2 in the old "Using Dynamic Vertex and Index Buffers" SDK entry.

It appears that the gentleman thought C++ was extremely difficult and he was overjoyed that the machine was absorbing it; he understood that good C++ is difficult but the best C++ is well-nigh unintelligible.


#20 360GAMZ   Members   -  Reputation: 133

Like
0Likes
Like

Posted 02 February 2012 - 03:58 PM

So right now I'm just casting the pData member of D3D11_MAPPED_SUBRESOURCE to my vertex structure type, incrementing the pointer by the required amount, and writing in. Like I said, that seems to work and it doesn't cause any performance loss, but in the absence of any documented description of what's happening (and it could be as simple as "yeah, do this" and "no, don't do that") it feels an awful lot like throwing magic pixie dust in the air and seeing what comes down. That's not fun. D3D9 had a clear and well-documented approach for this buffer usage pattern (and let's leave out buffer types to which it doesn't apply), D3D11 doesn't.


What you're describing sounds correct to me and consistent with the link provided by Erik above. The DX11 docs also suggest that you use NO_OVERWRITE along with DISCARD to insure you won't be overwriting any data the GPU may be using. Same as with DX9, but the DX9 docs explain it a lot better (i.e. use DISCARD when you reach the end of the buffer). As you pointed out, the difference between the DX9 and DX11 APIs are that you specified the region in DX9 whereas DX11 gives you a pointer to the start of the buffer, and then we must apply the offset afterwards. I agree that the docs could explain all of this better.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS