DiligentGraphics / DiligentEngine

A modern cross-platform low-level graphics library and rendering framework
http://diligentgraphics.com/diligent-engine/
Apache License 2.0
3.37k stars 318 forks source link

Is it possible add suport for D3D11_RESOURCE_MISC_SHARED flag? #287

Closed dmhud closed 2 months ago

dmhud commented 2 months ago

Is it possible add suport for D3D11_RESOURCE_MISC_SHARED flag for create texture sharing with DX9 (BackBuffer of D3DImage in WPF ) for rendering directly in GUI window? Or maybe exists another way for sharing 2d texture for this purpose?


Possible solution in Diligent below. Is it good?

D3D11TypeConversions.h

inline UINT MiscTextureFlagsToD3D11Flags(Uint32 Flags)
{
    UINT D3D11MiscFlags = 0;
    D3D11MiscFlags |= (Flags & MISC_TEXTURE_FLAG_GENERATE_MIPS) ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0;
    D3D11MiscFlags |= (Flags & MISC_TEXTURE_FLAG_SHARED) ? D3D11_RESOURCE_MISC_SHARED : 0;
    return D3D11MiscFlags;
}

inline MISC_TEXTURE_FLAGS D3D11MiscFlagsToMiscTextureFlags(UINT D3D11MiscFlags)
{
    MISC_TEXTURE_FLAGS MiscFlags = MISC_TEXTURE_FLAG_NONE;
    MiscFlags |= (D3D11MiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS) ? MISC_TEXTURE_FLAG_GENERATE_MIPS : MISC_TEXTURE_FLAG_NONE;
    MiscFlags |= (D3D11MiscFlags & D3D11_RESOURCE_MISC_SHARED) ? MISC_TEXTURE_FLAG_SHARED : MISC_TEXTURE_FLAG_NONE;
    return MiscFlags;
}

Texture.h

    enum MISC_TEXTURE_FLAGS : uint8_t
    {
        ...
        MISC_TEXTURE_FLAG_SHARED = 1u << 4,
    };

DX9 shared texture creation:

int D3D9_CreateTexture(const void* pDeviceD3D9, uint32_t width, uint32_t height, const void* pTextureSharedHandle, const void** ppTextureD3D9)
{
        IDirect3DDevice9Ex* deviceD3D9 = (IDirect3DDevice9Ex*)pDeviceD3D9;
        HANDLE sharedHandle = (HANDLE)pTextureSharedHandle;

        // Textures being shared from D3D9 to D3D 11 have the following restrictions :
        //      - Textures must be 2D
        //      - Only 1 mip level is allowed
        //      - Texture must have default usage
        //      - Texture must be write only
        //      - MSAA textures are not allowed
        //      - Bind flags must have SHADER_RESOURCE and RENDER_TARGET set
        //      - Only these formats are allowed
        //          - R10G10B10A2_UNORM,
        //          - R16G16B16A16_FLOAT
        //          - R8G8B8A8_UNORM 
        //
        // Additionally, if we want use the texture as a backbuffer in Direct3D9, we are further limited to
        //      - R8G8B8A8_UNORM
        //      - R10G10B10A2_UNORM

        // Create DX9 shared texture
        HRESULT hr = deviceD3D9->CreateTexture(width, height, 1,
            D3DUSAGE_RENDERTARGET,
            D3DFMT_A8R8G8B8,
            D3DPOOL_DEFAULT,
            (IDirect3DTexture9**)ppTextureD3D9,
            &sharedHandle);
}

Create shared texture (DX11) and shared handle for DX9:


    RefCntAutoPtr<ITexture> CreateSharedTexture(IRenderDevice* device, uint32_t width, uint32_t height)
    {
        // Create Texture2D
        TextureDesc desc;
        desc.Name = "Shared Texture2D for D3D9";
        desc.Type = Diligent::RESOURCE_DIM_TEX_2D;
        desc.Width = width;
        desc.Height = height;
        desc.MipLevels = 1;
        desc.Usage = Diligent::USAGE_DEFAULT;
        desc.Format = Diligent::TEX_FORMAT_BGRA8_UNORM; // 32 bit format that allowed in shared texture and allowed as backbuffer in D3D9 
        desc.BindFlags = Diligent::BIND_SHADER_RESOURCE | Diligent::BIND_RENDER_TARGET;
        desc.MiscFlags = MISC_TEXTURE_FLAG_SHARED;

        RefCntAutoPtr<ITexture> sharedTexture;
        device->CreateTexture(desc, nullptr, &sharedTexture);
        return sharedTexture;
    }

    HANDLE GetSharedTextureHandle(ITexture* texture)
    {
        HANDLE sharedHandle;
        ComPtr<IUnknown> unk((IUnknown*)texture->GetNativeHandle());
        ComPtr<IDXGIResource> dxgiResource;
        unk.As(&dxgiResource);
        HRESULT hr = dxgiResource->GetSharedHandle(&sharedHandle);
        if (FAILED(hr))
            return nullptr;

        return sharedHandle;
    }

    ComPtr<IUnknown> OpenSharedResource(IRenderDevice* device, HANDLE sharedResourceHandle)
    {
        auto deviceDx11 = static_cast<Diligent::IRenderDeviceD3D11*>(device);
        ID3D11Device* d3dDevice = deviceDx11->GetD3D11Device();

        ComPtr<IUnknown> surface;
        HRESULT hr = d3dDevice->OpenSharedResource(sharedResourceHandle, __uuidof(ID3D11Texture2D), (void**)surface.GetAddressOf());
        if (FAILED(hr))
            return nullptr;

        return surface;
    }
...
sharedTexture = CreateSharedTexture(device, width, height);
sharedTextureHandle = GetSharedTextureHandle(sharedTexture);
surface = OpenSharedResource(device, sharedTextureHandle);

...

D3D9_CreateTexture(pDeviceD3D9, width, height, sharedTextureHandle, ppTextureD3D9)

OS: Windows 10

IDE/Compiler version: Visual Studio 2017 x64 Version 15.9.60

CMake version: 3.27.1

Diligent version: git clone --branch v2.5.4 --recursive https://github.com/DiligentGraphics/DiligentEngine.git

TheMostDiligent commented 2 months ago

That functionality is exclusive to Direct3D11, so having it in common API is not ideal. I would suggest creating the texture using raw Direct3D11 and then attaching it to Diligent texture.

dmhud commented 2 months ago

Thanks for link, I'll try to use it

TheMostDiligent commented 2 months ago

Did you make it work?

TheMostDiligent commented 2 months ago

@dmhud Let me know if interoperability with D3D11 did not work for you.