Opened up my personal project earlier today and ran into a nasty crash when trying to load an instance of my proxy texture asset class. The crash was occurring here:
void* Data = RHILockTexture2D(DynamicResource->GetTexture2DRHI(), 0, RLM_WriteOnly, Stride, false);
DynamicResource was valid, all looked okay, until I could see further in that the result of
GetTexture2DRHI was not valid, even though I'd already called to initialize the resource beforehand. What was going on?
A little bit of further digging shows that calling
UTexture2DDynamic::Init eventually calls
FRenderResource::BeginInitResource. This, importantly, queues a command to the render thread to update the resource, rather than doing so on-the-spot.
As a result, trying to lock the resource too early gives you a nullptr instead of the resource. I'd been lucky when doing my initial work that there was enough lag between the two calls that I had a valid pointer by the time I wanted to lock it to copy some data in.
So, what to do? I want to block on the resource initialization if necessary, because I am loading the texture in dynamically and need to guarantee that the data's ready when the game uses it (and the game isn't so fast-paced that a one-frame hitch on initial load would be noticeable, if I had to wait a full frame in the worst case scenario).
FRenderCommandFence. Simply put, this is a synchronization primitive that allows you to block until the specified point in the render command queue is executed.
I added an instance to my runtime texture class:
Then began the fence after requesting the resource be allocated:
After that all that was required was to wait for the fence to be completed before I actually populate the texture data:
InitializationFence.Wait(); // Do things with the texture resource
Now everything works just fine, my proxy asset loads on-demand as expected!