DiligentGraphics / DiligentEngine

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

Support for Texture Misc flags - D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX and D3D11_RESOURCE_MISC_SHARED_NTHANDLE #301

Closed Ron-Linares closed 3 months ago

Ron-Linares commented 3 months ago

Would it be possible to get support for these flags on a texture?

We need to share a texture to another process.

We were able to get D3D11_RESOURCE_MISC_SHARED to work by creating a native texture then binding to a Diligent texture, but that flag does not give us what we need in our application.

Ideally would like support in dx11, dx12 and vulkan. As I understand texture sharing out of process is supported on those backends.

Ron-Linares commented 3 months ago

We tried making a native texture but these flags are used for other purposes in Diligent so I believe attaching a native texture fails.

These are the diligent flags that conflict

In Diligent:: BIND_FLAGS enum

BIND_SHADING_RATE

BIND_INDIRECT_DRAW_ARGS

MikhailGorobets commented 3 months ago

@Ron-Linares These flags should conflict. One is used for a texture that is used in Variable Rate Shading, while the other flag indicates that your buffer will be used as an argument in DispatchIndirect/DrawIndirect.

Ron-Linares commented 3 months ago

I understand. Can we change the enum value on the Diligent enums to allow the dx share flags to not conflict? If so I can make a native texture, or maybe the diligent texture create will work once the enums have changed values

MikhailGorobets commented 3 months ago

@Ron-Linares What specific conflict is occurring? Diligent simply retrieves the descriptor of the D3D11 object and initializes its own descriptor if such a flag is supported by Diligent. https://github.com/DiligentGraphics/DiligentCore/blob/88c3cb6ab5209a8b47f6407f63d9a83ff7cbcd56/Graphics/GraphicsEngineD3D11/src/Texture2D_D3D11.cpp#L139 In the case where a resource has the D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX flag, no errors should occur. Unsupported flags are simply ignored. https://github.com/DiligentGraphics/DiligentCore/blob/88c3cb6ab5209a8b47f6407f63d9a83ff7cbcd56/Graphics/GraphicsEngineD3D11/include/D3D11TypeConversions.hpp#L168

Ron-Linares commented 3 months ago

I will restore this code, test and report back.

TheMostDiligent commented 3 months ago

@Ron-Linares Like Mikhail said, Diligent enum values are orthogonal to DX enum values. They may be the same or different - this may not create any conflict with other D3D11 enum values.

Ron-Linares commented 3 months ago

Correction, I am able to wrap the native texture with a diligent texture with those flags, it crashes binding to my shaders in this method

void DeviceContextD3D11Impl::DvpVerifyCommittedResources

on this error check line

    for (Uint32 Slot = 0; Slot < _countof(pctxResources); ++Slot)
    {
        if (Slot < NumCommittedResources)
        {
            **DEV_CHECK_ERR(CommittedResources[Slot] == pctxResources[Slot], ResourceName, " binding mismatch found for ", ShaderName, " shader type at slot ", Slot);**

call stack

GraphicsEngineD3D11_64d.dll!Diligent::WindowsDebug::AssertionFailed(const char * Message, const char * Function, const char * File, int Line) Line 96   C++
GraphicsEngineD3D11_64d.dll!Diligent::DebugAssertionFailed(const char * Message, const char * Function, const char * File, int Line) Line 125   C++
GraphicsEngineD3D11_64d.dll!Diligent::DeviceContextD3D11Impl::DvpVerifyCommittedResources<128,ID3D11ShaderResourceView *,void (__cdecl ID3D11DeviceContext::*const)(unsigned int,unsigned int,ID3D11ShaderResourceView * *)>(ID3D11ShaderResourceView *[128] * CommittedD3D11ResourcesArr, unsigned char * NumCommittedResourcesArr, void(ID3D11DeviceContext::*)(unsigned int, unsigned int, ID3D11ShaderResourceView * *) * GetD3D11ResMethods, const char * ResourceName, Diligent::SHADER_TYPE ShaderStages) Line 2421  C++
GraphicsEngineD3D11_64d.dll!Diligent::DeviceContextD3D11Impl::DvpVerifyCommittedSRVs(Diligent::SHADER_TYPE ShaderStages) Line 2465  C++
GraphicsEngineD3D11_64d.dll!Diligent::DeviceContextD3D11Impl::BindCacheResources(const Diligent::ShaderResourceCacheD3D11 & ResourceCache, const std::array<Diligent::D3D11ResourceRangeCounters,4> & BaseBindings, Diligent::DeviceContextD3D11Impl::PixelShaderUAVBindMode & PsUavBindMode) Line 294  C++
GraphicsEngineD3D11_64d.dll!Diligent::DeviceContextD3D11Impl::BindShaderResources(unsigned int BindSRBMask) Line 404    C++
GraphicsEngineD3D11_64d.dll!Diligent::DeviceContextD3D11Impl::PrepareForDraw(Diligent::DRAW_FLAGS Flags) Line 604   C++

GraphicsEngineD3D11_64d.dll!Diligent::DeviceContextD3D11Impl::Draw(const Diligent::DrawAttribs & Attribs) Line 667 C++

Ron-Linares commented 3 months ago

If I drop those flags and just use the native texture wrapped connected to the diligent texture manually that works in my code

Here is a code frag that shows the manual wrapping with the failing flags

texDesc.Width = texDiligentDescription.Width;
texDesc.Height = texDiligentDescription.Height;
texDesc.MipLevels = 1;
texDesc.Format = (DXGI_FORMAT)texDiligentDescription.Format;
texDesc.SampleDesc.Count = 1;
texDesc.ArraySize = 1;
texDesc.Usage = D3D11_USAGE_DEFAULT;
texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX | D3D11_RESOURCE_MISC_SHARED_NTHANDLE; // D3D11_RESOURCE_MISC_SHARED;
texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;

//Get the Diligent API specific Render Device interface
Diligent::IRenderDeviceD3D11* native_device = (Diligent::IRenderDeviceD3D11*)m_RenderDevice.RawPtr();

ID3D11Texture2D* pd3d11Texture;

hr = native_device->GetD3D11Device()->CreateTexture2D(&texDesc, NULL, &pd3d11Texture);

if (FAILED(hr))
{
    return false;
}

native_device->CreateTexture2DFromD3DResource(pd3d11Texture, Diligent::RESOURCE_STATE_RENDER_TARGET, &retTexture);
MikhailGorobets commented 3 months ago

@Ron-Linares Check the debug log; I suspect the issue is not in this location Do you use IDXGIKeyedMutex object when operate with the shared resource? Also, use QueryInterface instead of the С-cast you're using

TheMostDiligent commented 3 months ago

texDesc.Format = (DXGI_FORMAT)texDiligentDescription.Format; is incorrect. Diligent texture formats are not convertible to DXGI formats even if they happen to have the same value.

Here is the code that I tried to put into tutorial 01 and it worked without any issues:

    D3D11_TEXTURE2D_DESC texDesc = {};
    texDesc.Width                = 256;
    texDesc.Height               = 256;
    texDesc.MipLevels            = 1;
    texDesc.Format               = DXGI_FORMAT_R8G8B8A8_UNORM;
    texDesc.SampleDesc.Count     = 1;
    texDesc.ArraySize            = 1;
    texDesc.Usage                = D3D11_USAGE_DEFAULT;
    texDesc.MiscFlags            = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX | D3D11_RESOURCE_MISC_SHARED_NTHANDLE; // D3D11_RESOURCE_MISC_SHARED;
    texDesc.BindFlags            = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;

    //Get the Diligent API specific Render Device interface
    Diligent::IRenderDeviceD3D11* native_device = (Diligent::IRenderDeviceD3D11*)m_pDevice.RawPtr();

    ID3D11Texture2D* pd3d11Texture;

    HRESULT hr = native_device->GetD3D11Device()->CreateTexture2D(&texDesc, NULL, &pd3d11Texture);
    if (FAILED(hr))
    {
        return;
    }

    RefCntAutoPtr<ITexture> retTexture;
    native_device->CreateTexture2DFromD3DResource(pd3d11Texture, Diligent::RESOURCE_STATE_RENDER_TARGET, &retTexture);
TheMostDiligent commented 3 months ago

Correction, I am able to wrap the native texture with a diligent texture with those flags, it crashes binding to my shaders in this method

void DeviceContextD3D11Impl::DvpVerifyCommittedResources

on this error check line

    for (Uint32 Slot = 0; Slot < _countof(pctxResources); ++Slot)
    {
        if (Slot < NumCommittedResources)
        {
            **DEV_CHECK_ERR(CommittedResources[Slot] == pctxResources[Slot], ResourceName, " binding mismatch found for ", ShaderName, " shader type at slot ", Slot);**

call stack

GraphicsEngineD3D11_64d.dll!Diligent::WindowsDebug::AssertionFailed(const char * Message, const char * Function, const char * File, int Line) Line 96 C++
GraphicsEngineD3D11_64d.dll!Diligent::DebugAssertionFailed(const char * Message, const char * Function, const char * File, int Line) Line 125 C++
GraphicsEngineD3D11_64d.dll!Diligent::DeviceContextD3D11Impl::DvpVerifyCommittedResources<128,ID3D11ShaderResourceView *,void (__cdecl ID3D11DeviceContext::*const)(unsigned int,unsigned int,ID3D11ShaderResourceView * *)>(ID3D11ShaderResourceView *[128] * CommittedD3D11ResourcesArr, unsigned char * NumCommittedResourcesArr, void(ID3D11DeviceContext::*)(unsigned int, unsigned int, ID3D11ShaderResourceView * *) * GetD3D11ResMethods, const char * ResourceName, Diligent::SHADER_TYPE ShaderStages) Line 2421    C++
GraphicsEngineD3D11_64d.dll!Diligent::DeviceContextD3D11Impl::DvpVerifyCommittedSRVs(Diligent::SHADER_TYPE ShaderStages) Line 2465    C++
GraphicsEngineD3D11_64d.dll!Diligent::DeviceContextD3D11Impl::BindCacheResources(const Diligent::ShaderResourceCacheD3D11 & ResourceCache, const std::array<Diligent::D3D11ResourceRangeCounters,4> & BaseBindings, Diligent::DeviceContextD3D11Impl::PixelShaderUAVBindMode & PsUavBindMode) Line 294    C++
GraphicsEngineD3D11_64d.dll!Diligent::DeviceContextD3D11Impl::BindShaderResources(unsigned int BindSRBMask) Line 404  C++
GraphicsEngineD3D11_64d.dll!Diligent::DeviceContextD3D11Impl::PrepareForDraw(Diligent::DRAW_FLAGS Flags) Line 604 C++

GraphicsEngineD3D11_64d.dll!Diligent::DeviceContextD3D11Impl::Draw(const Diligent::DrawAttribs & Attribs) Line 667 C++

This happens when you bind a resource using D3D11 directly, which breaks internal Diligent resource tracking. If you do this, you should call IDeviceContext::Invalidate

TheMostDiligent commented 3 months ago

@Ron-Linares Like Mikhail said, check the error messages from D3D11 debug layer. This is the error that I get when using your texture in Tutorial 03:

D3D11 WARNING: ID3D11DeviceContext::PSSetShaderResources: Resource being set to PS shader resource slot 0 is inaccessible because of a previous call to ReleaseSync or GetDC. [ STATE_SETTING WARNING #7: DEVICE_PSSETSHADERRESOURCES_HAZARD]

The texture created this way cannot immediately be bound to device context, which is why the assert is triggered. This is not an issue with Diligent.

Ron-Linares commented 3 months ago

OK, I did not realize that I could not render directly to that type of texture. I can copy from diligent rendered output to a texture with those flags so I will stick with that method.

TheMostDiligent commented 3 months ago

The error says that you can't bind it as a shader resource, not as a render target. Like Mikhail suggested, you may need to acquire a IDXGIKeyedMutex before working with the shared resource. After that you should be able to successfully commit an SRB or set it as render target in Diligent.

Ron-Linares commented 3 months ago

Good info, we will put that in. I did not realize that was necessary on the "source" side.

TheMostDiligent commented 3 months ago

Sharing resources between processes is a very specific use case. Heaving it in the common Diligent API is both not necessary and quite involved due the differences in low-level APIs. Resource sharing can be achieved through the low-level API interoperability with the specific API.

Closing this issue for now.