Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm using shared resources to send textures from one D3D11 device to another, so that I can copy the back buffer over the second device and use the second device context to save that texture to a file. This seems to be working, but when I save the texture, it saves an empty PNG. I tried saving the texture with the primary device context and it works, except if I use the D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX MiscFlag, which I need in order to share the resources. Is there any reason D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX prevents a texture from being saved ? Or am I maybe missing something out in order for it to work ?

Here is the code I'm using:

D3D11_TEXTURE2D_DESC td;
backBuffer->GetDesc(&td);
td.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
this->_device->CreateTexture2D(&td, 0, &g_tex);
this->_context->CopyResource(g_tex, backBuffer);

// saves a blank image if using D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX
D3DX11SaveTextureToFile(this->_context, g_tex, D3DX11_IFF_JPG, "test.jpg");

g_tex->QueryInterface(__uuidof(IDXGIResource), reinterpret_cast<void **>(&g_dxgiResource));
g_dxgiResource->GetSharedHandle(&g_shaderHandle);
g_dxgiResource->Release();
g_tex->QueryInterface(__uuidof(IDXGIKeyedMutex), reinterpret_cast<void **>(&g_dxgiMutex));

And this is the code used to save the shared textue in the second device

ID3D11Texture2D *texture = 0;
IDXGIKeyedMutex *keyedMutex = 0;
device2->OpenSharedResource(g_shaderHandle, __uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&texture));
texture->QueryInterface(__uuidof(IDXGIKeyedMutex), reinterpret_cast<void **>(&keyedMutex));
UINT acqKey = 0;
UINT relKey = 1;
DWORD timeout = 16;
DWORD res = keyedMutex->AcquireSync(acqKey, timeout);
if (res == WAIT_OBJECT_0 && texture)
{
    // saves a blank image too
    D3DX10SaveTextureToFile(texture, D3DX10_IFF_JPG, "test2.jpg");
}
keyedMutex->ReleaseSync(relKey);

Edit: Also, the code that is supposed to save the shared texture to the filesystem is running in it's own thread.

share|improve this question
    
Nice question. I'm interested what is practical usage of this approach. –  Notabene Apr 6 '11 at 21:22
    
The main goal would be to save textures with a secondary device so it doesn't block the device used for rendering. –  dotminic Apr 7 '11 at 2:55
add comment

3 Answers

up vote 2 down vote accepted

Here is how I solved the problem. Turns out, using the D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX misc flag doesn't allow to save the texture to a file. So I used the D3D11_RESOURCE_MISC_SHARED flag instead with a regular mutex, without using the DXGIKeyedMutex stuff.

Copy the back buffer to shared texture and create a shared handle:

D3D11_TEXTURE2D_DESC td;
backBuffer->GetDesc(&td);
td.MiscFlags = D3D11_RESOURCE_MISC_SHARED;

this->_device->CreateTexture2D(&td, 0, &g_tex);
this->_context->CopyResource(g_tex, backBuffer);
IDXGIResource *dxgiResource = 0;
g_tex->QueryInterface(__uuidof(IDXGIResource), reinterpret_cast<void **>(&dxgiResource));
dxgiResource->GetSharedHandle(&g_shaderHandle);
dxgiResource->Release();
backBuffer->Release();

Now that we have a shared copy of the back buffer and handle to it, we can save it to a file from another thread without hogging the device context:

// device_2 and context_2 are the "secondary" device and context
bool imgSaved = true;
ID3D11Texture2D *texture = 0;
HRESULT h = WaitForSingleObject(g_mutex, INFINITE);
if (h == WAIT_OBJECT_0)
{
    // check to see if there is an image to save
    if (wdata->hasFrame)
    {
        wdata->hasFrame = false;
        imgSaved = false
    }
}
ReleaseMutex(g_mutex);
if (!imgSaved)
{
    device_2->OpenSharedResource(g_shaderHandle, __uuidof(ID3D11Texture2D), (LPVOID*)&texture);
    if (texture)
    {
        h = D3DX11SaveTextureToFile(context_2, texture, D3DX11_IFF_PNG, "image.png");
        texture->Release();
    }
}

Basically this allows me to save HD screen captures without killing the frame rate because my device context is not stuck in the D3DX11SaveTextureToFile function, it's handled by the secondary context. On a side note, I've not tested it a whole lot, I just hack this together this morning, it might not work in some cases, but it solves the problem I had with the other flag, which caused empty images to be saved to file.

share|improve this answer
    
Thats pretty cool. –  Notabene Apr 8 '11 at 18:43
add comment

I have to say that you will not save any extra memory by using this. Textures are not stored in gpu's ram by the creation. They are sended after SetResource(SRV). And cleared from gpu ram after the SetResource(NULL) call. That's the way how to save space. Always clear after your shader pass.

share|improve this answer
    
I'm not trying to save memory at all. On the contrary, what I'm doing will take up a more memory. I'm trying to save HD textures to file without killing the frame rate, and for that, I share a texture, and save it with a second device/context. I've worked it out, I'll post the answer a little later. –  dotminic Apr 8 '11 at 14:39
add comment

Have you tried using D2D interop ? This is just a stab in the dark, but you could maybe try sharing the surface with a D3D10 device instead, and then save it the texture as a bitmap with D2D.

The fact you can't save a shared texture may have something to do with how it is stored in memory, since it has to be shared between devices, but then again, I'm not sure so I might be wrong.

share|improve this answer
    
I'm sharing resources between D3D11 devices, I'm not sure how using a D3D10 device could solve the problem. –  dotminic Apr 7 '11 at 22:32
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.