How to make FTexture2DRHI with D3D12_TEXTURE_LAYOUT_ROW_MAJOR

I want to create opencv Mat from FTexture2DRHIRef BackBuffer when it ready to present.
In project settings i set frame buffer format to 8bit RGBA.
I get ID3D12Resource from BackBuffer and it descripton.
Descripton has D3D12_TEXTURE_LAYOUT_UNKNOWN layout. I think i need D3D12_TEXTURE_LAYOUT_ROW_MAJOR. But i cant even create ID3D12Resource with this layout

ID3D12Resource* texture2D_copy;
D3D12_RESOURCE_DESC textureDesc = {};
textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
textureDesc.Alignment = 0; 
textureDesc.Width = 1024;
textureDesc.Height = 1024;
textureDesc.DepthOrArraySize = 1; 
textureDesc.MipLevels = 1; 
textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 
textureDesc.SampleDesc.Count = 1; 
textureDesc.SampleDesc.Quality = 0; 
textureDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
textureDesc.Flags = D3D12_RESOURCE_FLAG_NONE; 

D3D12_HEAP_PROPERTIES heapProperties = {};
heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;

HRESULT Result = m_device->CreateCommittedResource(
    &heapProperties,
    D3D12_HEAP_FLAG_NONE,
    &textureDesc,
    D3D12_RESOURCE_STATE_COPY_DEST,
    nullptr,
    IID_PPV_ARGS(&texture2D_copy)
);
check(SUCCEEDED(Result));

With D3D12_TEXTURE_LAYOUT_UNKNOWN all ok.

Now opencv image and screen:

c++ code:

void AScreenCaptureActor::BeginPlay()
{
	Super::BeginPlay();

    gameWindow = GEngine->GameViewport->GetWindow().Get();
    FSlateApplication::Get().GetRenderer()->OnBackBufferReadyToPresent().AddUObject(this, &AScreenCaptureActor::OnBackBufferReady_RenderThread);
}



void AScreenCaptureActor::getExternalMemory(DX12Texture& d3d12Texture)
{
    cudaExternalMemoryHandleDesc memDesc{};
    memset(&memDesc, 0, sizeof(memDesc));

    memDesc.type = cudaExternalMemoryHandleTypeD3D12Resource;
    memDesc.handle.win32.handle = d3d12Texture.handle;
    memDesc.size = d3d12Texture.memSize;
    memDesc.flags = cudaExternalMemoryDedicated;

    cudaError_t cudaError = cudaImportExternalMemory(&m_externalMemory, &memDesc);

}

void AScreenCaptureActor::mapMemory(DX12Texture& d3d12Texture)
{

    void* pData = nullptr;
    cudaExternalMemoryBufferDesc buffDesc{};
    memset(&buffDesc, 0, sizeof(buffDesc));

    buffDesc.offset = 0;
    buffDesc.size = d3d12Texture.memSize; 

    cudaExternalMemoryGetMappedBuffer(&pData, m_externalMemory, &buffDesc);  

    D3D12_RESOURCE_DESC Desc = d3d12Texture.resource->GetDesc();
    int height = static_cast<int>(Desc.Height);
    int width = static_cast<int>(Desc.Width);

     cv::cuda::GpuMat mat = cv::cuda::GpuMat(height, width, CV_8UC4, (char*)pData); 
    auto step = mat.step;

    cv::Mat rgba;
    mat.download(rgba);
        
    cv::Mat rgb;
    cv::cvtColor(rgba, rgb, cv::COLOR_BGRA2BGR);

    cv::imshow("rgb", rgb);
    cv::waitKey(1);

    /*
    for (int i = 0; i < 2; i++)
    {
        int w = 2048;
        int h = 256;
        cv::cuda::GpuMat device_mat = cv::cuda::GpuMat(h, w, CV_8UC4, (char*)pData + i * 4 * w * h * sizeof(char), 2048*4);
        
        cv::Mat host_rgba;
        device_mat.download(host_rgba);

        cv::Mat host_rgb;
        cv::cvtColor(host_rgba, host_rgb, cv::COLOR_BGRA2BGR);
        cv::imshow("patch_" + std::to_string(i), host_rgb);
    }
    */
    

    cv::waitKey(1);
    cudaFree(pData);
}


void AScreenCaptureActor::OnBackBufferReady_RenderThread(SWindow& SlateWindow, const FTexture2DRHIRef& BackBuffer)
{
    if (gameWindow == &SlateWindow)
    {
        FRHICommandListImmediate& RHICmdList = GRHICommandList.GetImmediateCommandList();
        FRHITexture2D* CachedTexture = BackBuffer->GetTexture2D();
        int32 Width = BackBuffer->GetSizeX();  
        int32 Height = BackBuffer->GetSizeY();  

        static HANDLE SharedHandle = nullptr;
        if (GDynamicRHI)
        {
            ID3D12Resource* NativeResource = reinterpret_cast<ID3D12Resource*>(BackBuffer->GetNativeResource());

            if (NativeResource)
            {
                ID3D12Device* m_device = reinterpret_cast<ID3D12Device*>(GDynamicRHI->RHIGetNativeDevice());
                
                if (SharedHandle == nullptr)
                {
                    SECURITY_ATTRIBUTES windowsSecurityAttributes;
                    LPCWSTR name = nullptr;

                    HRESULT Result = m_device->CreateSharedHandle(
                        NativeResource,
                        &windowsSecurityAttributes,
                        GENERIC_ALL,
                        name,
                        &SharedHandle);
                }

                D3D12_RESOURCE_DESC Desc = NativeResource->GetDesc();
               // Desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; 

                D3D12_RESOURCE_ALLOCATION_INFO allocInfo = m_device->GetResourceAllocationInfo(0, 1, &Desc);
                DX12Texture Texture{ SharedHandle, NativeResource, allocInfo.SizeInBytes };

                FRHITexture2D* TextureRHI = BackBuffer->GetTexture2D();

                getExternalMemory(Texture);
                mapMemory(Texture);
            }
        }
        
        /*
        FReadSurfaceDataFlags ReadDataFlags;
        ReadDataFlags.SetLinearToGamma(false); 
        ReadDataFlags.SetOutputStencil(false); 
        TArray<FColor> PixelData;
        RHICmdList.ReadSurfaceData(
            BackBuffer,
            FIntRect(0, 0, Width, Height),
            PixelData,
            FReadSurfaceDataFlags(RCM_UNorm)
        );     

        //cv::Mat Image(Height, Width, CV_8UC3);
        
        cv::Mat Image(Height, Width, CV_8UC4, PixelData.GetData());

        // Convert from RGBA to BGR (OpenCV uses BGR by default)
        cv::cvtColor(Image, Image, cv::COLOR_RGBA2RGB);
                
        // Display the image
        cv::imshow("Unreal Engine Screenshot", Image);
        cv::waitKey(1);
        */      
    }
}

I use

RHICmdList.MapStagingSurface(BackBuffer, RawData, Width, Height);``` 
it's much faster then RHICmdList.ReadSurfaceData

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.