Jump to content

  • Log In with Google      Sign In   
  • Create Account

Interested in a FREE copy of HTML5 game maker Construct 2?

We'll be giving away three Personal Edition licences in next Tuesday's GDNet Direct email newsletter!

Sign up from the right-hand sidebar on our homepage and read Tuesday's newsletter for details!


We're also offering banner ads on our site from just $5! 1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


Texture Streaming synchronization


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
8 replies to this topic

#1 Funkymunky   Members   -  Reputation: 660

Like
0Likes
Like

Posted 01 February 2014 - 09:35 PM

I have a separate thread that I use for loading texture data.  It fills out a "PixelData" buffer with pixel data.  With my OpenGL code, I can use "fences" to synchronize the upload to the card.  I call glFenceSync to get a synchronization object, then tell the driver to upload my PixelData to the card via glTexSubImage2D.  This call doesn't block; I can check the state of the synchronization object, and when it's completed I know that the texture is available to me.

 

How does one do this with DirectX?  Right now, my DX texture updating code just calls ID3D11DeviceContext::Map, then a memcpy, and then an Unmap.  DirectX is threadsafe, though, right?  So I could actually make these three calls from within the thread, and just check with a mutex before using the texture... right?



Sponsor:

#2 MJP   Moderators   -  Reputation: 11569

Like
0Likes
Like

Posted 01 February 2014 - 10:25 PM

DirectX is thread-safe for resource allocation, as long as the device sets DriverConcurrentCreates to TRUE. You can read this for more info: http://msdn.microsoft.com/en-us/library/windows/desktop/ff476893(v=vs.85).aspx

 

Note that this only means resource creation is thread-safe, calling device context methods from multiple threads still isn't thread safe. However you can just have your streaming thread create the texture resource, and pass the new texture data through the D3D11_SUBRESOURCE_DATA structure.



#3 Funkymunky   Members   -  Reputation: 660

Like
0Likes
Like

Posted 02 February 2014 - 12:57 AM

By calling ID3D11DeviceContext::UpdateSubresource?  (or perhaps better by creating a second resource and calling ID3D11DeviceContext::CopyResource or ::CopySubresourceRegion)?  Those functions do talk about being asynchronous calls.  But then I'm back to the same point of needing a synchronization object like the fences in OpenGL to know when the copy has succeeded.

 

I've been researching it while typing out this post.  It looks like I want to do a ID3D11Device::CreateQuery call with D3D11_QUERY_EVENT...?  (It also looks like I was doing my call to glFenceSync out of order; it should be after the asynchronous call to upload the data).  I call CreateQuery, then CopyResource, and then Context->End(Query).   I can then check the state of the query with Context->GetData.

 

Does that sound right?  I'm going to bed anyway so I'll just give it a shot tomorrow.



#4 Hodgman   Moderators   -  Reputation: 30926

Like
2Likes
Like

Posted 02 February 2014 - 03:06 AM

If you want to know when the GPU has finished a draw operation, you can use events, yes.

However, this isn't required for updating resources. The update call will complete immediately, copying the supplied data into an internal temporary buffer if required. The actual update will occur asynchronously in the background. Any draw-calls submitted before the update call will use the old data, any draw-calls submitted after the update will use the new data (stalling automatically, if necessary to avoid a race condition). Everything should just work™ without the need for any events.

#5 Funkymunky   Members   -  Reputation: 660

Like
0Likes
Like

Posted 02 February 2014 - 10:05 AM

I'm intentionally trying to circumvent the "stalling automatically" part.

 

Thanks guys!



#6 Adam_42   Crossbones+   -  Reputation: 2562

Like
1Likes
Like

Posted 02 February 2014 - 11:08 AM

Simply call ID3D11Device::CreateTexture2D() and fill in the pInitialData parameter on the background thread. The same applies to any other ID3D11Device function.

 

Once you  have done that just hand the resulting ID3D11Texture2D * over to the main thread somehow.

 

 

That should be all you need to do.



#7 Hodgman   Moderators   -  Reputation: 30926

Like
0Likes
Like

Posted 02 February 2014 - 05:09 PM

Any draw-calls submitted before the update call will use the old data, any draw-calls submitted after the update will use the new data (stalling automatically, if necessary to avoid a race condition).

I'm intentionally trying to circumvent the "stalling automatically" part.
 
Thanks guys!

I don't know if this is possible. If the texture update is performed as a command in the internal command buffer, then yep, your idea of inserting an event right after the update call would work -- when the event is ready, you'd know that the update is complete.
However, I don't think that's how it works.
I don't know if there is a way to tell when an update is actually complete.

Is this actually a performance problem for you though? In normal usage, your command buffer will have about a frame's worth of latency in it, which should be enough time for any sensible update to complete (if you're doing a 16ms memcpy, then something is wrong).
To be extra sure, you could simply wait a frame after your update call before using the updated resource. In normal usage, no update is going to take 2 frames to complete.

#8 MJP   Moderators   -  Reputation: 11569

Like
0Likes
Like

Posted 02 February 2014 - 11:33 PM

Simply call ID3D11Device::CreateTexture2D() and fill in the pInitialData parameter on the background thread. The same applies to any other ID3D11Device function.

 

Once you  have done that just hand the resulting ID3D11Texture2D * over to the main thread somehow.

 

 

That should be all you need to do.

 

Yes, this is what I was originally suggesting. It's possible to update the contents of already-created textures (as long as they're not creating with D3D11_USAGE_IMMUTABLE), but (IMO) the simplest way to do it is to simply create a new resource and give it the data. This is how we handle our texture streaming for the Windows version of our engine at work.

If you need to update an existing texture, then the two ways you mentioned (UpdateSubresource or Map a STAGING texture and then use CopyResource or CopySubresourceRegion) are the two ways of doing it. I recall reading from a GDC presentation a few years ago that both Nvidia and AMD recommended using a poll of STAGING textures for frequent texture updates, although I haven't actually profiled vs. UpdateSubresource. Like Hodgman mentioned there isn't any explicit synchronization required in either case. You just need to either provide the data to UpdateSubresource or call CopyResource, and the driver handles asynchronously updating the destination texture in such a way that it the data is available for any subsequent commands.



#9 imoogiBG   Members   -  Reputation: 1218

Like
0Likes
Like

Posted 04 February 2014 - 06:58 AM

http://msdn.microsoft.com/en-us/library/windows/hardware/ff568288(v=vs.85).aspx






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