创建 DirectX12 纹理的正确方法

问题描述 投票:0回答:0

我实现了一个渲染图像的 CPU 路径跟踪器。该图像稍后使用 DirectX 12 在屏幕上传输。
在我昨天尝试之前,该代码已经工作了多年。 我突然得到了人工制品.
例如,这里通过路径跟踪生成的浮点图像:

在屏幕上闪烁后我得到了什么

我在代码方面,这里是我的基本图像类:

class Image
{
public:
    Image(const Image& src);
    virtual ~Image() {};

    nbUint32 getWidth() const;
    nbUint32 getHeight() const;
    nbUint64 getBytesPerRow() const;
    const unsigned char* getRawData() const;

    ImageFormat getFormat() const;
    nbUint32 getNbPixels() const;

protected:
    Image(ImageFormat imFormat);
    Image(nbUint32 width, nbUint32 height, ImageFormat imFormat);

    cv::Mat m_image;
    ImageFormat m_format;
};

这是我在屏幕上绘制图像的渲染器类。

class DX12Renderer 
{
public:
    void drawImage(const Texture::Image& image) override;

    void createTexture2D(const Texture::Image* image, Dx12TextureHandle& dst);
    void releaseTexture(Dx12TextureHandle& textureHandle) const;

    //etc....
private:
    void prepareViewportRender();

    enum class CommandType
    {
        Direct,
        Copy
    };

    struct CommandBuffer
    {
        ID3D12CommandAllocator* commandAllocator[SwapChainBufferCount];
        ID3D12GraphicsCommandList* commandList;
        ID3D12CommandQueue* commandQueue;
        ID3D12Fence* fences[SwapChainBufferCount];
        HANDLE fenceEvent;
        UINT64 fenceValue[SwapChainBufferCount];
        nbInt32 frameIndex;
    };

    std::unordered_map<CommandType, CommandBuffer> m_commandBuffers;

    Dx12TextureHandle m_blittingBuffers[SwapChainBufferCount];

    ID3D12Resource* m_renderTargets[SwapChainBufferCount];

    // Descriptor allocators
    std::unique_ptr<Descriptor::CBV_SRV_UAV_DescriptorAllocator> m_cbs_srv_uavAllocator;
    std::unique_ptr<Descriptor::RTV_DescriptorAllocator> m_rtvAllocator;
    std::unique_ptr<Descriptor::DSV_DescriptorAllocator> m_dsvAllocator;

    //etc....
}


inline void DX12Renderer::drawImage(const Texture::Image& image)
{   
    prepareViewportRender();

    auto& commandList = m_commandBuffers[CommandType::Direct].commandList;
    const nbInt32 frameIdx = m_commandBuffers[CommandType::Direct].frameIndex;
    Dx12TextureHandle& blitBuffer = m_blittingBuffers[frameIdx];

    // TODO : Only recreate texture when image size is different.
    // Release current blit buffer
    if (blitBuffer.buffer)
        releaseTexture(blitBuffer);
    // Create texture from image
    createTexture2D(&image, blitBuffer);

    // Now draw
    commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[frameIdx], D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));

    CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvDescriptorsHandle.getCpuHandle(),
        frameIdx,
        m_rtvAllocator->getDescriptorSize());

    commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr);

    {
        Effect::RenderRectanglePushArgs args = { blitBuffer };
        m_renderRectangleEffect->pushDrawCommands(args, commandList, frameIdx);
    }

    commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_renderTargets[frameIdx], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
}


inline void DX12Renderer::prepareViewportRender()
{
    auto& commandList = m_commandBuffers[CommandType::Direct].commandList;
    const nbInt32 frameIdx = m_commandBuffers[CommandType::Direct].frameIndex;

    // Set the viewport
    commandList->RSSetViewports(1, &m_viewport);

    // Set the scissor rect
    commandList->RSSetScissorRects(1, &m_scissorRect);

    // Set the descriptor heaps
    ID3D12DescriptorHeap* descriptorHeaps[] = { m_cbs_srv_uavAllocator->getHeap() };
    commandList->SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps);
}

inline void DX12Renderer::createTexture2D(const Texture::Image* image, Dx12TextureHandle& dst)
{
    const nbUint32 width = image->getWidth();
    const nbUint32 height = image->getHeight();

    if (width > D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION)
        throw CreateTextureException("Image width is too high.");

    if (height > D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION)
        throw CreateTextureException("Image height is too high");

    D3D12_RESOURCE_DESC textureDesc = {};
    textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
    textureDesc.Alignment = 0; // may be 0, 4KB, 64KB, or 4MB. 0 will let runtime decide between 64KB and 4MB (4MB for multi-sampled textures)
    textureDesc.Width = width;
    textureDesc.Height = height;
    textureDesc.DepthOrArraySize = 1; // if 3d image, depth of 3d image. Otherwise an array of 1D or 2D textures.
    textureDesc.MipLevels = 1; // Number of mipmaps. We are not generating mipmaps for this texture, so we have only one level.

    const Texture::ImageFormat imageFormat = image->getFormat();
    switch (imageFormat)
    {
    case Texture::ImageFormat::RGBA8:
        textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    break;

    case Texture::ImageFormat::RGB32F:
        textureDesc.Format = DXGI_FORMAT_R32G32B32_FLOAT;
    break;

    case Texture::ImageFormat::RGBA32F:
        textureDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
    break;

    default:
        throw CreateTextureException("Unsupported image format");
    }

    textureDesc.SampleDesc.Count = 1; // This is the number of samples per pixel, we just want 1 sample
    textureDesc.SampleDesc.Quality = 0; // The quality level of the samples. Higher is better quality, but worse performance
    textureDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // The arrangement of the pixels. Setting to unknown lets the driver choose the most efficient one
    textureDesc.Flags = D3D12_RESOURCE_FLAG_NONE; // no flags

    // Create a default heap.
    HRESULT hr = D3D12Device->CreateCommittedResource(
        &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
        D3D12_HEAP_FLAG_NONE,
        &textureDesc,
        D3D12_RESOURCE_STATE_COPY_DEST, // We will copy the texture from the upload heap to here, so we start it out in a copy dest state
        nullptr,
        IID_PPV_ARGS(&dst.buffer));

    if (FAILED(hr))
    {
        return;
    }

    dst.format = textureDesc.Format;


    UINT64 textureUploadBufferSize;
    D3D12Device->GetCopyableFootprints(&textureDesc, 0, 1, 0, nullptr, nullptr, nullptr, &textureUploadBufferSize);

    // Now we create an upload heap to upload our texture to the GPU
    ID3D12Resource* textureBufferUploadHeap;

    hr = D3D12Device->CreateCommittedResource(
        &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
        D3D12_HEAP_FLAG_NONE,
        &CD3DX12_RESOURCE_DESC::Buffer(textureUploadBufferSize),
        D3D12_RESOURCE_STATE_GENERIC_READ,
        nullptr,
        IID_PPV_ARGS(&textureBufferUploadHeap));

    if (FAILED(hr))
    {
        return;
    }


    // Initialize subresources
    D3D12_SUBRESOURCE_DATA subResourceData;
    subResourceData.pData = image->getRawData();
    subResourceData.RowPitch = image->getBytesPerRow();
    subResourceData.SlicePitch = image->getBytesPerRow() * height;

    // Now we copy the upload buffer contents to the default heap
    UpdateSubresources(m_commandBuffers[CommandType::Direct].commandList, dst.buffer, textureBufferUploadHeap, 0, 0, 1, &subResourceData);

    m_commandBuffers[CommandType::Direct].commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(dst.buffer, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COMMON));

    // Create buffer view
    D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
    srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
    srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
    srvDesc.Format = dst.format;
    srvDesc.Texture2D.MipLevels = 1;
    dst.descriptorHandle = m_cbs_srv_uavAllocator->allocate({ dst.buffer }, srvDesc);
}

inline void releaseTexture(Dx12TextureHandle& textureHandle) const
{
    m_cbs_srv_uavAllocator->release(textureHandle.descriptorHandle);
    textureHandle.buffer->Release();
    textureHandle.buffer = nullptr;
}

我检查了渲染文档以验证输入纹理是问题所在。 我得到这个作为输入:

这是输出:

输入的纹理明显错误。我相信这是由于 createTexture2D 功能。 此外,输出与输入纹理惊人地不同。

c++ directx
© www.soinside.com 2019 - 2024. All rights reserved.