DirectX 11 render BGRA32 Frame

Viewed 124

First time trying to render something and I have big troubles... I am using DirectN library and SwapChainSurface class from KlearTouch.MediaPlayer. I am trying to render BGRA32 frame using D3D11Device.

For this I have slightly modified OnNewSurfaceAvailable:

public void OnNewSurfaceAvailable2(Action<ID3D11Device, ID3D11DeviceContext> updateSurface)
{
    if (rendering)
    {
        return;
    }

    try
    {
        if (this.swapChain is null || swapChainComObject is null)
        {
            return;
        }

        swapChainComObject.GetDesc(out var swapChainDesc).ThrowOnError();

        if (swapChainDesc.BufferDesc.Width != PanelWidth || swapChainDesc.BufferDesc.Height != PanelHeight)
        {
            swapChainComObject.ResizeBuffers(2, PanelWidth, PanelHeight, DXGI_FORMAT.DXGI_FORMAT_UNKNOWN, 0).ThrowOnError();
        }

        var device = swapChain.Object.GetDevice1().Object.As<ID3D11Device>();

        device.GetImmediateContext(out var context);

        // context.ClearRenderTargetView(renderTargetView.Object, new []{0f, 1f, 1f, 1f});

        updateSurface(device, context);

        swapChainComObject.Present(1, 0).ThrowOnError();
    }
    catch (ObjectDisposedException)
    {
        Reinitialize();
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine("\nException: " + ex, nameof(SwapChainSurface) + '.' + nameof(OnNewSurfaceAvailable));
    }

    rendering = false;
}

OnSurfaceAvailable2 is called from:

void VideoFrameArrived(Bgra32VideoFrame frame)
    {
        DispatcherQueue.TryEnqueue(() =>
        {
            previewSurface.OnNewSurfaceAvailable2((device, context) =>
            {
                var size = frame.m_height * frame.m_height * 4;

                D3D11_TEXTURE2D_DESC td;
                td.ArraySize = 1;
                td.BindFlags = (uint) D3D11_BIND_FLAG.D3D11_BIND_SHADER_RESOURCE;
                td.Usage = D3D11_USAGE.D3D11_USAGE_DYNAMIC;
                td.CPUAccessFlags = (uint) D3D11_CPU_ACCESS_FLAG.D3D11_CPU_ACCESS_WRITE;
                td.Format = DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM;
                td.Height = (uint) frame.m_height;
                td.Width = (uint) frame.m_width;
                td.MipLevels = 1;
                td.MiscFlags = 0;
                td.SampleDesc.Count = 1;
                td.SampleDesc.Quality = 0;

                D3D11_SUBRESOURCE_DATA srd;
                srd.pSysMem = frame.m_pixelBuffer;
                srd.SysMemPitch = (uint) frame.m_height;
                srd.SysMemSlicePitch = 0;

                var texture = device.CreateTexture2D<ID3D11Texture2D>(td, new []{srd});

                var mappedResource = context.Map(texture.Object, 0, D3D11_MAP.D3D11_MAP_WRITE_DISCARD);

                var mappedData = mappedResource.pData;
                

                unsafe
                {
                    Buffer.MemoryCopy(frame.m_pixelBuffer.ToPointer(), mappedData.ToPointer(), size, size);
                }

                // Just for debug
                var pixelsInFrame = new byte[size];
                var pixelsInResource = new byte[size];

                Marshal.Copy(frame.m_pixelBuffer, pixelsInFrame, 0, size);
                Marshal.Copy(mappedResource.pData, pixelsInResource, 0, size);
                
                context.Unmap(texture.Object, 0);
            });
        });
    }

Problem is that I can't see anything rendered and surface stay black and I assume it should not be.

Update: Project repository

Update 2:

I solved my issue. I had too little knowledge about DX11 so I had to study more how things work there. With this knowledge I updated repository which can display preview from black magic design card. It is just example with many issues so be careful and feel free to look for or inspiration there.

1 Answers

There's a various amount of issues here.

First on frame arrived, you have

var texture = device.CreateTexture2D<ID3D11Texture2D>(td, new []{srd});

So your create a texture, but you do not use it anywhere, it needs to be blitted to the swapchain (can do a CopyResource on device context or draw a full screen triangle/quad).

Note that CopyResource will only work if your swapchain has the same size as your incoming texture, which is rather unlikely, so you will have to draw a blit with a shader most likely.

Also you actually copying the data in the texture twice :

 var texture = device.CreateTexture2D<ID3D11Texture2D>(td, new []{srd});

Since you provide initial data, the content is already there.

also, pitch is incorrect : srd.SysMemPitch = (uint) frame.m_height;

pitch is the length (in bytes) of a line, so it should be :

srd.SysMemPitch = frame.GetRowBytes();

Please also note that in case of a non converted Decklink frame, GetRowBytes can be different from width*4 (they can align row size to multiple of 16/32 or other values).

Next, in the case of resource map, the following is also incorrect :

unsafe
{
    Buffer.MemoryCopy(frame.m_pixelBuffer.ToPointer(), mappedData.ToPointer(), size, size);
}

You are not checking the pitch/stride requirement of a texture (which can be different as well),

so you need to do :

if (mappedResource.RowPitch == frame.GetRowBytes())
{
    //here you can use a direct copy as above
}
else
{
   //here you need to copy data line per line
}
Related