D3DX11SaveTextureToFile с общими ресурсами

#c #multithreading #directx

#c #многопоточность #directx

Вопрос:

Я использую общие ресурсы для отправки текстур с одного устройства D3D11 на другое, чтобы я мог скопировать обратный буфер на второе устройство и использовать контекст второго устройства для сохранения этой текстуры в файл. Кажется, это работает, но когда я сохраняю текстуру, она сохраняет пустой PNG. Я попытался сохранить текстуру с контекстом основного устройства, и это работает, за исключением того, что я использую D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX MiscFlag, который мне нужен для совместного использования ресурсов. Есть ли какая-либо причина, по которой D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX предотвращает сохранение текстуры? Или, может быть, я что-то упускаю, чтобы это заработало?

Вот код, который я использую:

 D3D11_TEXTURE2D_DESC td;
backBuffer->GetDesc(amp;td);
td.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
this->_device->CreateTexture2D(amp;td, 0, amp;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 **>(amp;g_dxgiResource));
g_dxgiResource->GetSharedHandle(amp;g_shaderHandle);
g_dxgiResource->Release();
g_tex->QueryInterface(__uuidof(IDXGIKeyedMutex), reinterpret_cast<void **>(amp;g_dxgiMutex));
  

И это код, используемый для сохранения общего текста на втором устройстве

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

Кроме того, код, который должен сохранять общую текстуру в файловой системе, выполняется в собственном потоке.

Ответ №1:

Вот как я решил проблему. Оказывается, использование флага D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX разное не позволяет сохранить текстуру в файл. Поэтому я использовал флаг D3D11_RESOURCE_MISC_SHARED вместо обычного мьютекса, без использования DXGIKeyedMutex.

Скопируйте обратный буфер в общую текстуру и создайте общий дескриптор:

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

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

Теперь, когда у нас есть общая копия заднего буфера и его дескриптор, мы можем сохранить его в файл из другого потока, не перегружая контекст устройства:

 // 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*)amp;texture);
    if (texture)
    {
        h = D3DX11SaveTextureToFile(context_2, texture, D3DX11_IFF_PNG, "image.png");
        texture->Release();
    }
}
  

В принципе, это позволяет мне сохранять снимки экрана высокой четкости без снижения частоты кадров, потому что контекст моего устройства не застрял в функции D3DX11SaveTextureToFile, он обрабатывается вторичным контекстом.
Кстати, я не тестировал его полностью, я просто взломал это сегодня утром, в некоторых случаях это может не сработать, но это решает проблему, которая у меня была с другим флагом, из-за чего пустые изображения сохранялись в файл.

Ответ №2:

Не было бы логичнее создать текстуру 2Dи скопировать ресурс с _устройства, которому принадлежит backBuffer?