CLSID_D2D1ChromaKey проблемы

Я пытаюсь использовать эффект DirectX ChromaKey, но моя функция зависает на каком-то шаге.
Что я делаю:

  1. Создать ID2D1Factory1
  2. Создайте ID3D11Device и ID3D11DeviceContext
  3. Получить DXGIResource из полученной текстуры
  4. Получить общий дескриптор из DXGIResource
  5. Откройте DXGIResource как новый ID3D11Texture2D, используя ID3D11Device.
  6. Получите D3D11_TEXTURE2D_DESC нового ID3D11Texture2D
  7. Создайте новый ID3D11Texture2D, используя входные данные ID3D11Texture2D и D3D11_TEXTURE2D_DESC.
  8. Скопируйте ресурс из полученного ID3D11Texture2D в созданный ID3D11Texture2D.
  9. Получите IDXGISurface из созданного ID3D11Texture2D
  10. Определите D2D1_SIZE_U, D2D1_PIXEL_FORMAT, D2D1_BITMAP_PROPERTIES
  11. Получите DPI рабочего стола от ID2D1Factory1
  12. Создайте D2D1_RENDER_TARGET_PROPERTIES, используя полученный DPI.
  13. Создайте ID2D1RenderTarget, используя ID2D1Factory1, IDXGISurface и D2D1_RENDER_TARGET_PROPERTIES.
  14. Создайте общий ID2D1Bitmap, используя ID2D1RenderTarget, IDXGISurface и D2D1_BITMAP_PROPERTIES.
  15. Получите IDXGIDevice с помощью ID3D11Device
  16. Создайте ID2D1Device, используя ID2D1Factory1 и IDXGIDevice.
  17. Получите ID2D1DeviceContext с помощью ID2D1Device
  18. Создайте ChromaKey ID2D1Effect, используя ID2D1DeviceContext
  19. Определите D2D1_VECTOR_3F на основе фона ChromaKey
  20. Установите параметры и D2D1_VECTOR_3F ID2D1Effect
  21. Нарисуйте ID2D1Bitmap, используя ID2D1DeviceContext и ID2D1Effect.
  22. Вернуть новый ID3D11Texture2D, связанный с ID2D1Bitmap

Вот код.

Определяет:

#define SIZEOF_ARRAY(arr)   (sizeof(arr)/sizeof((arr)[0]))
#define RET_HR(_f) hr = _f; if (FAILED(hr)) return hr;
#define RET_HR_NULL( _f, _obj ) hr = _f; if (FAILED(hr) || !_obj) return FAILED(hr) ? hr : S_FALSE;

Создание устройства:

inline CComPtr<ID3D11Device> DX11_CreateDevice(IDXGIAdapter* _pAdapter, ID3D11DeviceContext** _ppD2D1DeviceContext = NULL)
{
    DXGI_ADAPTER_DESC dxgiDesc = {};
    CComQIPtr<IDXGIAdapter> qpDXGIAdapter(_pAdapter);
    if (qpDXGIAdapter)
        qpDXGIAdapter->GetDesc(&dxgiDesc);

    CComPtr<ID3D11Device> cpD3D11Device;
    D3D_FEATURE_LEVEL d3dFeature = (D3D_FEATURE_LEVEL)0;
    D3D_FEATURE_LEVEL arrD3DFeatures[] = {
        D3D_FEATURE_LEVEL
td  {Width=0x00000354 Height=0x000001e0 MipLevels=0x00000001 ...}   D3D11_TEXTURE2D_DESC
    Width   0x00000354  unsigned int
    Height  0x000001e0  unsigned int
    MipLevels   0x00000001  unsigned int
    ArraySize   0x00000001  unsigned int
    Format  DXGI_FORMAT_B8G8R8A8_UNORM (0x00000057) DXGI_FORMAT
    SampleDesc  {Count=0x00000001 Quality=0x00000000 }  DXGI_SAMPLE_DESC
    Usage   D3D11_USAGE_DEFAULT (0x00000000)    D3D11_USAGE
    BindFlags   0x00000008  unsigned int
    CPUAccessFlags  0x00020000  unsigned int
    MiscFlags   0x00000002  unsigned int

sd  {Width=0x00000354 Height=0x000001e0 Format=DXGI_FORMAT_B8G8R8A8_UNORM (0x00000057) ...} DXGI_SURFACE_DESC
    Width   0x00000354  unsigned int
    Height  0x000001e0  unsigned int
    Format  DXGI_FORMAT_B8G8R8A8_UNORM (0x00000057) DXGI_FORMAT
    SampleDesc  {Count=0x00000001 Quality=0x00000000 }  DXGI_SAMPLE_DESC
1, D3D_FEATURE_LEVEL
td  {Width=0x00000354 Height=0x000001e0 MipLevels=0x00000001 ...}   D3D11_TEXTURE2D_DESC
    Width   0x00000354  unsigned int
    Height  0x000001e0  unsigned int
    MipLevels   0x00000001  unsigned int
    ArraySize   0x00000001  unsigned int
    Format  DXGI_FORMAT_B8G8R8A8_UNORM (0x00000057) DXGI_FORMAT
    SampleDesc  {Count=0x00000001 Quality=0x00000000 }  DXGI_SAMPLE_DESC
    Usage   D3D11_USAGE_DEFAULT (0x00000000)    D3D11_USAGE
    BindFlags   0x00000008  unsigned int
    CPUAccessFlags  0x00020000  unsigned int
    MiscFlags   0x00000002  unsigned int

sd  {Width=0x00000354 Height=0x000001e0 Format=DXGI_FORMAT_B8G8R8A8_UNORM (0x00000057) ...} DXGI_SURFACE_DESC
    Width   0x00000354  unsigned int
    Height  0x000001e0  unsigned int
    Format  DXGI_FORMAT_B8G8R8A8_UNORM (0x00000057) DXGI_FORMAT
    SampleDesc  {Count=0x00000001 Quality=0x00000000 }  DXGI_SAMPLE_DESC
0, D3D_FEATURE_LEVELcpDXGISurface1, D3D_FEATURE_LEVELcpDXGISurface0, D3D_FEATURE_LEVELtd3, D3D_FEATURE_LEVELtd2, D3D_FEATURE_LEVELtd1 }; HRESULT hr = S_OK; RET_HR(D3D11CreateDevice( qpDXGIAdapter, qpDXGIAdapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_DEBUG, arrD3DFeatures, SIZEOF_ARRAY(arrD3DFeatures), D3D11_SDK_VERSION, &cpD3D11Device, &d3dFeature, _ppD2D1DeviceContext )); CComQIPtr<ID3D10Multithread> qpMTProtect(cpD3D11Device); ATLASSERT(qpMTProtect); if (qpMTProtect) qpMTProtect->SetMultithreadProtected(TRUE); return cpD3D11Device; }

Код ChromaKey:

HRESULT DXV_ChromaKey(ID3D11Texture2D* _pTexIn, ID3D11Texture2D** _pTexOut)
{
    // -----------------
    HRESULT hr = S_OK;

    CComPtr<ID2D1Factory1> cpD2DFactory;
    RET_HR_NULL(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &cpD2DFactory), cpD2DFactory);

    // Create the DX11 API device object, and get a corresponding context.
    CComPtr<ID3D11DeviceContext> cpD3D11DeviceContext;

    CComPtr<IDXGIAdapter> cpNVidiaAdpt = DXGI_AdapterByType(eGPU_NVidia);
    CComPtr<ID3D11Device> cpD3D11Device = DX11_CreateDevice(cpNVidiaAdpt, &cpD3D11DeviceContext);

    CComPtr<IDXGIResource> cpDXGIResource;
    RET_HR_NULL(_pTexIn->QueryInterface(__uuidof(IDXGIResource), (void**)&cpDXGIResource), cpDXGIResource);

    HANDLE sharedHandle;
    cpDXGIResource->GetSharedHandle(&sharedHandle);

    CComPtr<ID3D11Texture2D> cpTexIn;
    cpD3D11Device->OpenSharedResource(sharedHandle, __uuidof(ID3D11Resource), (void**)(&cpTexIn));

    D3D11_TEXTURE2D_DESC td;
    cpTexIn->GetDesc(&td);
    td.BindFlags = D3D11_BIND_SHADER_RESOURCE;
    td.CPUAccessFlags = D3D11_CPU_ACCESS_READ;

    CComPtr<ID3D11Texture2D> cpNewTexture;
    RET_HR_NULL(cpD3D11Device->CreateTexture2D(&td, NULL, &cpNewTexture), cpNewTexture);

    cpD3D11DeviceContext->CopyResource(cpNewTexture, cpTexIn);

    CComPtr<IDXGISurface> cpDXGISurface;
    RET_HR_NULL(cpNewTexture->QueryInterface(&cpDXGISurface), cpDXGISurface);

    // -----------------

    D2D1_SIZE_U size = D2D1::SizeU(200, 200); // Adapt to your own size.

    D2D1_PIXEL_FORMAT desc2d;
    desc2d.format = DXGI_FORMAT_B8G8R8A8_UNORM;
    desc2d.alphaMode = D2D1_ALPHA_MODE_IGNORE; // Adapt to your needs.      

    D2D1_BITMAP_PROPERTIES bmpprops;
    bmpprops.dpiX = 96.0f;
    bmpprops.dpiY = 96.0f;
    bmpprops.pixelFormat = desc2d;

    FLOAT dpiX;
    FLOAT dpiY;
    cpD2DFactory->GetDesktopDpi(&dpiX, &dpiY);

    D2D1_RENDER_TARGET_PROPERTIES d2d1RenderTargetProperties =
        D2D1::RenderTargetProperties(
            D2D1_RENDER_TARGET_TYPE_DEFAULT,
            D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
            dpiX,
            dpiY
        );

    CComPtr<ID2D1RenderTarget> cpRenderTarget;
    RET_HR_NULL(cpD2DFactory->CreateDxgiSurfaceRenderTarget(
        cpDXGISurface,
        &d2d1RenderTargetProperties,
        &cpRenderTarget),
        cpRenderTarget);

    // -----------------

    CComPtr<ID2D1Bitmap> cpBitmap;
    cpRenderTarget->CreateSharedBitmap(__uuidof(IDXGISurface), cpDXGISurface, &bmpprops, &cpBitmap);

    // -----------------

    CComPtr<IDXGIDevice> cpDXGIDevice;
    // Obtain the underlying DXGI device of the Direct3D11 device.
    RET_HR_NULL(cpD3D11Device->QueryInterface(&cpDXGIDevice), cpDXGIDevice);

    CComPtr<ID2D1Device> cpD2D1Device;
    // Obtain the Direct2D device for 2-D rendering.
    RET_HR_NULL(cpD2DFactory->CreateDevice(cpDXGIDevice, &cpD2D1Device), cpD2D1Device);

    CComPtr<ID2D1DeviceContext> cpD2DContext;
    // Get Direct2D device's corresponding device context object.
    RET_HR_NULL(cpD2D1Device->CreateDeviceContext(
        D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
        &cpD2DContext
    ), cpD2DContext);

    CComPtr<ID2D1Effect> chromakeyEffect;
    RET_HR_NULL(cpD2DContext->CreateEffect(CLSID_D2D1ChromaKey, &chromakeyEffect), chromakeyEffect);

    D2D1_VECTOR_3F Vector3F;
    Vector3F.x = .32f;
    Vector3F.y = .99f;
    Vector3F.z = .48f;

    int nSize = sizeof(Vector3F);
    BYTE* pData = (BYTE*)&Vector3F;

    chromakeyEffect->SetInput(0, cpBitmap);
    RET_HR(chromakeyEffect->SetValue(D2D1_CHROMAKEY_PROP_COLOR, pData, nSize));
    RET_HR(chromakeyEffect->SetValue(D2D1_CHROMAKEY_PROP_TOLERANCE, 0.2f));
    RET_HR(chromakeyEffect->SetValue(D2D1_CHROMAKEY_PROP_INVERT_ALPHA, false));
    RET_HR(chromakeyEffect->SetValue(D2D1_CHROMAKEY_PROP_FEATHER, false));

    cpD2DContext->BeginDraw();
    cpD2DContext->DrawImage(chromakeyEffect);
    RET_HR(cpD2DContext->EndDraw());

    return cpNewTexture->QueryInterface(_pTexOut);
    // -----------------
}

Точка входа:

TEST_METHOD(UT_DXV_ChromaKey)
{
    MTimeout timeOut(__FUNCTION__);
    HRESULT hr = S_OK;

    DX11Texture::TPtr apTexturePicOrg;
    DX_TextureLoadFromFile(cbsChromaCat, &apTexturePicOrg);
    Assert::IsTrue(apTexturePicOrg);

    CComPtr<ID3D11Texture2D> cpD3D11Texture;
    hr = m_arrVidProcessor[0]->DXV_ChromaKey(apTexturePicOrg, &cpD3D11Texture);

    CComPtr<IMFFrame> cpMFFrameCnv;
    MCreator::MFFrameCreateFromTexture(NULL, cpD3D11Texture, 0, NULL, &cpMFFrameCnv, NULL);
    cpMFFrameCnv->MFVideoSaveToFile(L"C:\\temp\\Kosh.bmp");
}

Входное изображение:
введите здесь описание изображения

Теперь я застрял на 13-м шаге:

  1. Создайте ID2D1RenderTarget, используя ID2D1Factory1, IDXGISurface и D2D1_RENDER_TARGET_PROPERTIES.
RET_HR_NULL(cpD2DFactory->CreateDxgiSurfaceRenderTarget(
        cpDXGISurface,
        &d2d1RenderTargetProperties,
        &cpRenderTarget),
        cpRenderTarget);

Несмотря на D3D11_CREATE_DEVICE_DEBUG, я получаю сообщение об ошибке HRESULT из CreateDxgiSurfaceRenderTarget:

E_INVALIDARG Один или несколько аргументов недопустимы.

Вот содержание td и описание cpDXGISurface:

td  {Width=0x00000354 Height=0x000001e0 MipLevels=0x00000001 ...}   D3D11_TEXTURE2D_DESC
    Width   0x00000354  unsigned int
    Height  0x000001e0  unsigned int
    MipLevels   0x00000001  unsigned int
    ArraySize   0x00000001  unsigned int
    Format  DXGI_FORMAT_B8G8R8A8_UNORM (0x00000057) DXGI_FORMAT
    SampleDesc  {Count=0x00000001 Quality=0x00000000 }  DXGI_SAMPLE_DESC
    Usage   D3D11_USAGE_DEFAULT (0x00000000)    D3D11_USAGE
    BindFlags   0x00000008  unsigned int
    CPUAccessFlags  0x00020000  unsigned int
    MiscFlags   0x00000002  unsigned int

sd  {Width=0x00000354 Height=0x000001e0 Format=DXGI_FORMAT_B8G8R8A8_UNORM (0x00000057) ...} DXGI_SURFACE_DESC
    Width   0x00000354  unsigned int
    Height  0x000001e0  unsigned int
    Format  DXGI_FORMAT_B8G8R8A8_UNORM (0x00000057) DXGI_FORMAT
    SampleDesc  {Count=0x00000001 Quality=0x00000000 }  DXGI_SAMPLE_DESC

person Olga Pshenichnikova    schedule 10.03.2020    source источник
comment
1 использовать отладку Direct3D слой, чтобы получить расширенную информацию об ошибках в выводе отладки 2 с ошибкой Map вы заинтересованы в повторной проверке заглушек текстуры, текстура может быть (и я думаю, это проблема!) не может быть сопоставлена; вам может понадобиться дополнительный шаг копирования этой текстуры в промежуточную текстуру.   -  person Roman R.    schedule 13.03.2020
comment
Я обновил вопрос) Спасибо за совет!   -  person Olga Pshenichnikova    schedule 13.03.2020
comment
Ваш исходный код был ближе к тому, что вам нужно. Вы не можете иметь постановку там, где она у вас есть. Вы должны отменить это, а затем добавить копирование в промежуточную структуру прямо перед тем, как Map позже, чтобы вместо этого вы наложили промежуточную текстуру.   -  person Roman R.    schedule 13.03.2020
comment
Но я должен копировать в постановку прямо перед Map во всех моих вариантах. Сейчас загружу новую версию с последними изменениями и ошибками.   -  person Olga Pshenichnikova    schedule 16.03.2020
comment
Пожалуйста, смотрите обновленную версию)   -  person Olga Pshenichnikova    schedule 16.03.2020
comment
Здесь я задал связанный вопрос: stackoverflow.com/questions/60706884/   -  person Olga Pshenichnikova    schedule 16.03.2020
comment
Ошибка в обновленном разделе предполагает, что у вас нет D3D11_CPU_ACCESS_READ на текстуре, которую вы накладываете. Трудно следить за изменениями.   -  person Roman R.    schedule 16.03.2020
comment
Но у меня там D3D11_CPU_ACCESS_READ... (см. обновление)   -  person Olga Pshenichnikova    schedule 16.03.2020
comment
Я открыл для него отдельный вопрос, как и в предыдущий раз: stackoverflow.com/questions/60708675/   -  person Olga Pshenichnikova    schedule 16.03.2020
comment
Хорошо, теперь я, кажется, понял... Я думал, что вы сопоставляете выходную текстуру (для чтения!), но вы сопоставляете входную текстуру. Почему? В мою защиту поток выполнения трудно прочитать из фрагментов. Я также смущен, почему вы вообще используете IDXGISurface::Map? Кажется, тебе это не нужно. Возможно, вам следует объяснить себе, чего вы пытаетесь достичь. У вас уже есть текстура, которую вы используете в качестве входных данных. Совместимо ли это с D2D? Если да, просто используйте его сначала дальше. Если это не так, создайте совместимую и скопируйте туда входную текстуру. Вам не нужно Map ни для одного из двух.   -  person Roman R.    schedule 16.03.2020
comment
Даже если вы хотите Map, почему IDXGISurface::Map? У вас есть ID3D11DeviceContext::Map, который подходит для доступа к данным текстуры с текстурами, которые предполагают это. Я бы сказал, что вы вообще не должны делать IDXGISurface::Map. Затем, если Map для чтения вывода предназначено для завершения рисования, вы либо сопоставляете текстуру, либо копируете ее в отображаемую и сопоставляете вторую.   -  person Roman R.    schedule 16.03.2020
comment
Единственным допустимым для SetInput типом ID2D1Effect является ID2D1Image. И я не могу преобразовать ID3D11Texture2D в ID2D1Image простым способом... Я использовал руководство по адресу: stackoverflow.com/questions/22383209/ . Теперь я попробую ID3D11DeviceContext::Map(), но это намного сложнее, чем IDXGISurface::Map().   -  person Olga Pshenichnikova    schedule 16.03.2020
comment
Вам все равно не нужно Map. Несмотря на то, что это возможно, этот путь с Map и CreateBitmap явно снижает производительность. Вместо этого вы можете и должны использовать другой API. Используя CreateSharedBitmap для создания ID2D1Bitmap из IDXGISurface, вы можете записать сцену Direct3D в растровое изображение и визуализировать его с помощью Direct2D..   -  person Roman R.    schedule 16.03.2020
comment
Хорошо, я обновил там код. Теперь у меня есть E_INVALIDARG на CreateDxgiSurfaceRenderTarget.   -  person Olga Pshenichnikova    schedule 16.03.2020