1

I try to use DirectX ChromaKey effect, but my function stucks on some step.
What I do:

  1. Create ID2D1Factory1
  2. Create ID3D11Device and ID3D11DeviceContext
  3. Obtain DXGIResource from received texture
  4. Obtain shared handle from DXGIResource
  5. Open DXGIResource as new ID3D11Texture2D using ID3D11Device
  6. Obtain D3D11_TEXTURE2D_DESC of new ID3D11Texture2D
  7. Create new ID3D11Texture2D using input ID3D11Texture2D and D3D11_TEXTURE2D_DESC
  8. Copy resource from obtained ID3D11Texture2D to created ID3D11Texture2D
  9. Obtain IDXGISurface from created ID3D11Texture2D
  10. Define D2D1_SIZE_U, D2D1_PIXEL_FORMAT, D2D1_BITMAP_PROPERTIES
  11. Obtain desktop DPI from ID2D1Factory1
  12. Create D2D1_RENDER_TARGET_PROPERTIES using obtained DPI
  13. Create ID2D1RenderTarget using ID2D1Factory1, IDXGISurface and D2D1_RENDER_TARGET_PROPERTIES
  14. Create shared ID2D1Bitmap using ID2D1RenderTarget, IDXGISurface and D2D1_BITMAP_PROPERTIES
  15. Obtain IDXGIDevice using ID3D11Device
  16. Create ID2D1Device using ID2D1Factory1 and IDXGIDevice
  17. Obtain ID2D1DeviceContext using ID2D1Device
  18. Create ChromaKey ID2D1Effect using ID2D1DeviceContext
  19. Define D2D1_VECTOR_3F basing on ChromaKey background
  20. Set parameters and D2D1_VECTOR_3F of ID2D1Effect
  21. Drow over ID2D1Bitmap using ID2D1DeviceContext, and ID2D1Effect
  22. Return new ID3D11Texture2D bound to ID2D1Bitmap

Here is a code.

Defines:

#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;

Device creation:

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_11_1,
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_10_0,
        D3D_FEATURE_LEVEL_9_3,
        D3D_FEATURE_LEVEL_9_2,
        D3D_FEATURE_LEVEL_9_1 };

    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 code:

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);
    // -----------------
}

Entry point:

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");
}

The input picture:
enter image description here

Now, I'm stucking on 13th step:

  1. Create ID2D1RenderTarget using ID2D1Factory1, IDXGISurface and D2D1_RENDER_TARGET_PROPERTIES
RET_HR_NULL(cpD2DFactory->CreateDxgiSurfaceRenderTarget(
        cpDXGISurface,
        &d2d1RenderTargetProperties,
        &cpRenderTarget),
        cpRenderTarget);

Despite D3D11_CREATE_DEVICE_DEBUG I get just follow error as HRESULT of CreateDxgiSurfaceRenderTarget:

E_INVALIDARG One or more arguments are invalid.

Here is content of td and description of 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
Olga Pshenichnikova
  • 1,509
  • 4
  • 22
  • 47
  • 1
    `1` use [Direct3D debug layer](https://learn.microsoft.com/en-us/windows/win32/direct3d11/using-the-debug-layer-to-test-apps) to get extended error information in your debug output `2` having `Map` failure you are interested in re-checking texture caps, the texture might be (and I guess it's the issue!) not mappable; you might need an additionalstep of copying this texture into staging texture first – Roman R. Mar 13 '20 at 15:09
  • I updated the question ) Thanx for advise! – Olga Pshenichnikova Mar 13 '20 at 16:06
  • 1
    Your original code was closer to what you need. You can't have staging there where you have it. You should revert it and then add copying to staging right before you `Map` later, so that you map staging texture instead. – Roman R. Mar 13 '20 at 16:19
  • But, I have to copy to staging rigth before Map in all my variants. I will upload now new version with last changes and error. – Olga Pshenichnikova Mar 16 '20 at 11:51
  • Please see updated version ) – Olga Pshenichnikova Mar 16 '20 at 12:15
  • Here I asked related question: https://stackoverflow.com/questions/60706884/a-d3d11-usage-staging-resource-cannot-be-shared-via-d3d11-resource-misc-shared-k – Olga Pshenichnikova Mar 16 '20 at 13:35
  • 1
    The error in "updated" section suggests you don't have `D3D11_CPU_ACCESS_READ` on the texture you are mapping. It's hard to follow the changes. – Roman R. Mar 16 '20 at 14:15
  • But I have D3D11_CPU_ACCESS_READ there... (See update) – Olga Pshenichnikova Mar 16 '20 at 15:13
  • I opened separeted question for it, as in previous time: https://stackoverflow.com/questions/60708675/idxgisurfacemap-this-object-was-not-created-with-cpuaccess-flags-that-allow-c – Olga Pshenichnikova Mar 16 '20 at 15:23
  • 1
    OK, I seem to understand now... I thought you're mapping output texture (for reading!) but you are mapping input texture. Why? In my defense the execution flow is hard to read from the snippets. I am also confused why you are using `IDXGISurface::Map` at all? You don't seem to need it. Perhaps you should explain yourself what you are trying to achieve. You already have a texture you use as input. Is it compatible with D2D? If yes, just use it first further. In it's not, create a compatible and copy input texture there. You don't need `Map` for either of the two. – Roman R. Mar 16 '20 at 15:56
  • 1
    Even if you do want `Map`, why `IDXGISurface::Map`? You have `ID3D11DeviceContext::Map` which is appropriate for accessing texture data with textures that assume this. I would say you are not supposed to do `IDXGISurface::Map` at all. Then if `Map` for reading output is intended you end drawing, then you either map the texture or copy it to mappable and map that second one. – Roman R. Mar 16 '20 at 16:07
  • The only type acceptable by SetInput of ID2D1Effect is ID2D1Image. And I can not convert ID3D11Texture2D to ID2D1Image in a simple way... I used manual at: https://stackoverflow.com/questions/22383209/id3d11texture2d-to-id2d1bitmap-is-it-possible . Now, I will try ID3D11DeviceContext::Map() but it weem much more difficult than IDXGISurface::Map() – Olga Pshenichnikova Mar 16 '20 at 16:12
  • 1
    You don't need `Map` anyway. Even though it is possible, this path with `Map` and `CreateBitmap` is an apparent performance hit. You could and should use other API instead. [By using `CreateSharedBitmap` to create an `ID2D1Bitmap` from an `IDXGISurface`, you can write a Direct3D scene to a bitmap and render it with Direct2D.](https://learn.microsoft.com/en-us/windows/win32/direct2d/direct2d-and-direct3d-interoperation-overview). – Roman R. Mar 16 '20 at 16:16
  • OK, I updated there the code. Now I have E_INVALIDARG on CreateDxgiSurfaceRenderTarget – Olga Pshenichnikova Mar 16 '20 at 16:50

0 Answers0