每天学习一点点9.12: d3d12中的 drawing Vertex, texture, frame buffering, const buffers, bundles, 一次性全部源码解释

这一期我们来梳理初始化之后的一些基本入门操作

此篇blog都是和第一篇D3d的初始化文章比对进行讲解的.

1.D3D12HelloTriangle

1.Viewport 和scissorRect的区别就是如图所示

2.代码新增了啥?

新增了Vertex格式声明:

这个就是老生常谈了,d3d9里面也有, 就是顶点格式的描述,后面计算的时候能知道input和output

ComPtr<ID3D12RootSignature> m_rootSignature:

 

首先signature确定哪些资源会被绑定到渲染管线, 以及这些资源将如何映射到shader的输入寄存器. signature一定要和shader兼容,不然你的映射方法得到的输入不是shader想要的那就搞笑了. 并且signature还要提供所有shader需要的资源, 这个检查会在渲染管线被创建时进行.

而且不同的draw call 可能还会需要不同的shader 程序,这个时候就又需要不同的signature.


它需要填写一系列的参数包括 root 常量, root 描述符, 描述 table(有点像d3dshader的mapping table). 描述表就是一系列连续的描述堆里的描述符


大概可以理解成root signature是资源和shader的桥梁, 以及哪些shader用哪些资源,

m_scissorRect, m_viewport.:

这个上面已经谈了

ComPtr<ID3D12Resource> m_vertexBuffer:

这个其实和

d3d9的vertex buffer差不多没啥好说的

D3D12_VERTEX_BUFFER_VIEW m_vertexBufferView

这个看都不用看都知道是有关drawing index和drawing stride, primitive type这些内容的.


3. 下面看代码里的一些新增玩意:

主要都是在D3D12HelloTriangle.cpp里面

  1. 新增对viewportRect和scissorRect的填充

  1. LoadAsset这里增加了非常多的内容

老办法源码逐行分析:只看新增部分哈, 之前的一些部分基本没变的就不说了

void D3D12HelloTriangle::LoadAssets()

{

    // 创建一个空的rootsignature    

    {

       // 注意这个Init函数

       // 参数1: 参数个数

       //参数2: 参数的数组 

       // 参数3: 静态的采样的个数,打个比方ue4里经常一个matl里n个texture这个就是

       //参数4 :静态采样的样本数组

       // 参数5: 告诉我们这个signature的类型://D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT:

//The app is opting in to using the Input Assembler (requiring an input layout that defines a set of //vertex buffer bindings)

        CD3DX12_ROOT_SIGNATURE_DESC rootSignatureDesc;

        rootSignatureDesc.Init(0, nullptr, 0, nullptr, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

   //Blob其实是d3d12里的一团数据的意思用于序列化,这样省空间

        ComPtr<ID3DBlob> signature;

        ComPtr<ID3DBlob> error;

//先创建序列化的signature然后创建解压版的

        ThrowIfFailed(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, &error));

 //从序列化的signature里面摆好放回m_rootSignature;

        ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature)));

    }

    //创建一个包括pixelshader和vertex shader的pipeline object

上一节的pipeline啥也没有

    {

        ComPtr<ID3DBlob> vertexShader;

        ComPtr<ID3DBlob> pixelShader;

//debug 的分支编译选项

#if defined(_DEBUG)

//debug 的话就没有优化了

        // Enable better shader debugging with the graphics debugging tools.

        UINT compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;

#else

        UINT compileFlags = 0;

#endif

  //从文件编译shader文件

 // parameter 

1:文件名

2:shader用到的宏

3:shader用到的include文件

4:入口函数

5:编译目标平台

6: flag1

7. flag2

8. 填入的blob code的shader 文件地址

9.Error messages存的地方

        ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "VSMain", "vs_5_0", compileFlags, 0, &vertexShader, nullptr));

        ThrowIfFailed(D3DCompileFromFile(GetAssetFullPath(L"shaders.hlsl").c_str(), nullptr, nullptr, "PSMain", "ps_5_0", compileFlags, 0, &pixelShader, nullptr));


        // 定义顶点输入映射

        // 输入一个position一个color

       //结构体

 D3D12_INPUT_ELEMENT_DESC

    {

    LPCSTR SemanticName;  // 在shader里的名字

    UINT SemanticIndex;   // 语义索引

    DXGI_FORMAT Format;  //格式

    UINT InputSlot;  //输入槽

    UINT AlignedByteOffset;  //对齐offset

    D3D12_INPUT_CLASSIFICATION InputSlotClass; // 输入槽的类型

    UINT InstanceDataStepRate;  // 不清楚

    }


        D3D12_INPUT_ELEMENT_DESC inputElementDescs[] =

        {

            { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },

            { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }

        };


        // Describe and create the graphics pipeline state object (PSO).

       //创建pipeline 管线

        D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; // 渲染管线状态描述符

        psoDesc.InputLayout = { inputElementDescs, _countof(inputElementDescs) }; //输入elment 的描述

        psoDesc.pRootSignature = m_rootSignature.Get(); //指定root signature一个signature就指定了资源和layout

        psoDesc.VS = CD3DX12_SHADER_BYTECODE(vertexShader.Get()); // 设定vertex shader

        psoDesc.PS = CD3DX12_SHADER_BYTECODE(pixelShader.Get()); // 设定pixel shader

        psoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT); //光栅化状态

        psoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT); // blend 状态主要是α混合时候的计算公式在这里指定

        psoDesc.DepthStencilState.DepthEnable = FALSE; //直接取消depth 

        psoDesc.DepthStencilState.StencilEnable = FALSE; // 直接取消stencil

        psoDesc.SampleMask = UINT_MAX; // 采样mask

        psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; // primitive 类型

        psoDesc.NumRenderTargets = 1; //渲染喂过去的target有几个

        psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; //render target view 格式

        psoDesc.SampleDesc.Count = 1; //采样DESC的个数

        ThrowIfFailed(m_device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_pipelineState))); 

    }

    // Create the vertex buffer.

    {

        // Define the geometry for a triangle.

        Vertex triangleVertices[] =

        {

            { { 0.0f, 0.25f * m_aspectRatio, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f } },

            { { 0.25f, -0.25f * m_aspectRatio, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f } },

            { { -0.25f, -0.25f * m_aspectRatio, 0.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } }

        };


        const UINT vertexBufferSize = sizeof(triangleVertices);

       //这里的创建committed resource就是在创建顶点缓存, D3D12_HEAP_TYPE_UPLOAD其实不太适合这种静态数据, 这里只是为了代码简洁

        ThrowIfFailed(m_device->CreateCommittedResource(

            &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),

            D3D12_HEAP_FLAG_NONE,

            &CD3DX12_RESOURCE_DESC::Buffer(vertexBufferSize),

            D3D12_RESOURCE_STATE_GENERIC_READ,

            nullptr,

            IID_PPV_ARGS(&m_vertexBuffer)));


        // 把geometry的数据复制到vertex buffer,跟d3d9差不多

        UINT8* pVertexDataBegin;

        CD3DX12_RANGE readRange(0, 0);        // We do not intend to read from this resource on the CPU.

        //其实就是d3d9里面的锁定

        ThrowIfFailed(m_vertexBuffer->Map(0, &readRange, reinterpret_cast<void**>(&pVertexDataBegin)));

//其实就是把pVertexDataBegin的地址换成了vertexbuffer里面的raw指针的内存首地址.

//然后直接用pVertexDataBegin的地址来进行拷贝

        memcpy(pVertexDataBegin, triangleVertices, sizeof(triangleVertices));

//搞完之后unlock

        m_vertexBuffer->Unmap(0, nullptr);


        // Initialize the vertex buffer view.

       //果然view就是关于vertex的地址,stride等的信息

        m_vertexBufferView.BufferLocation = m_vertexBuffer->GetGPUVirtualAddress();

        m_vertexBufferView.StrideInBytes = sizeof(Vertex);

        m_vertexBufferView.SizeInBytes = vertexBufferSize;

    }

   }

  1. PopulateCommandList()

我们这里删除一些之前都有的代码只看新增的

void D3D12HelloTriangle::PopulateCommandList()

{

     //设置signature其实就是设置shader

    m_commandList->SetGraphicsRootSignature(m_rootSignature.Get());

   //这里如果在geometry shader里面不指定SV_ViewportArrayIndex的话就会使用setviewports里面的viewport数组的第一个

    m_commandList->RSSetViewports(1, &m_viewport);

  

    m_commandList->RSSetScissorRects(1, &m_scissorRect);




    CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSize);

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


    m_commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    m_commandList->IASetVertexBuffers(0, 1, &m_vertexBufferView);

    m_commandList->DrawInstanced(3, 1, 0, 0);


}


2.D3D12HelloTexture

1.新增了啥?

LoadPipeline():

新增了另外一种resource view的heap创建

// Describe and create a shader resource view (SRV) heap for the texture.

        D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};

        srvHeapDesc.NumDescriptors = 1;

        srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;

        srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;

        ThrowIfFailed(m_device->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&m_srvHeap)));


LoadAssets(): 

// 创建rootsignature有很大变化

    {

        D3D12_FEATURE_DATA_ROOT_SIGNATURE featureData = {};


        // 版本检查

        featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1;


        if (FAILED(m_device->CheckFeatureSupport(D3D12_FEATURE_ROOT_SIGNATURE, &featureData, sizeof(featureData))))

        {

            featureData.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_0;

        }


        CD3DX12_DESCRIPTOR_RANGE1 ranges[1];

        ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);


        CD3DX12_ROOT_PARAMETER1 rootParameters[1];

        rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL);

       //创建采样器sampler, 

       它定义了采样的时候的一些标准,比如超过寻址范围之后如何寻址

        D3D12_STATIC_SAMPLER_DESC sampler = {};

        sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;

        sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER;

        sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER;

        sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER;

        sampler.MipLODBias = 0;

        sampler.MaxAnisotropy = 0;

        sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;

        sampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;

        sampler.MinLOD = 0.0f;

        sampler.MaxLOD = D3D12_FLOAT32_MAX;

        sampler.ShaderRegister = 0;

        sampler.RegisterSpace = 0;

        sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;


       // 新版本的root signature desc的创建

       //这里在初始化signature的时候就要传入sampler说明,signature其实和sampler绑定了渲染的一些行为.

        CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc;

        rootSignatureDesc.Init_1_1(_countof(rootParameters), rootParameters, 1, &sampler, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);


        ComPtr<ID3DBlob> signature;

        ComPtr<ID3DBlob> error;

        ThrowIfFailed(D3DX12SerializeVersionedRootSignature(&rootSignatureDesc, featureData.HighestVersion, &signature, &error));

        ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature)));

    }


// 创建pipeline state中也就input element声明那有点变化

// Create the pipeline state, which includes compiling and loading shaders.

    {



        // Define the vertex input layout.

        D3D12_INPUT_ELEMENT_DESC inputElementDescs[] =

        {

            { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },

            { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }

        };


    }

//创建texture

 ComPtr<ID3D12Resource> textureUploadHeap

 // Create the texture.

    {

        // 一样描述你这个texture是怎样的

        D3D12_RESOURCE_DESC textureDesc = {};

        textureDesc.MipLevels = 1;

        textureDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;

        textureDesc.Width = TextureWidth;

        textureDesc.Height = TextureHeight;

        textureDesc.Flags = D3D12_RESOURCE_FLAG_NONE;

        textureDesc.DepthOrArraySize = 1;

        textureDesc.SampleDesc.Count = 1;

        textureDesc.SampleDesc.Quality = 0;

        textureDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;

       //然后直接创建resource的内存空间

        ThrowIfFailed(m_device->CreateCommittedResource(

            &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),

            D3D12_HEAP_FLAG_NONE,

            &textureDesc,

            D3D12_RESOURCE_STATE_COPY_DEST,

            nullptr,

            IID_PPV_ARGS(&m_texture)));

       //获得upload的buffer size

        const UINT64 uploadBufferSize = GetRequiredIntermediateSize(m_texture.Get(), 0, 1);


        // 创建GPU upload的buffer

        //D3D12_HEAP_TYPE_UPLOAD这个意思其实就是堆里面一块是专门针对CPU 读一次,GPU 读一次优化的,即专门用来上传内存到显存的快速通道

        ThrowIfFailed(m_device->CreateCommittedResource(

            &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),

            D3D12_HEAP_FLAG_NONE,

            &CD3DX12_RESOURCE_DESC::Buffer(uploadBufferSize),

            D3D12_RESOURCE_STATE_GENERIC_READ,

            nullptr,

            IID_PPV_ARGS(&textureUploadHeap)));


        // Copy data to the intermediate upload heap and then schedule a copy 

        // from the upload heap to the Texture2D.

        //把texture的数据从textureUploadHeap和texture移到m_texture

        std::vector<UINT8> texture = GenerateTextureData();

        //获取texture的data的数据头指针,之后就不用texture了

        D3D12_SUBRESOURCE_DATA textureData = {};

        textureData.pData = &texture[0];

        textureData.RowPitch = TextureWidth * TexturePixelSize;

        textureData.SlicePitch = textureData.RowPitch * TextureHeight;


        UpdateSubresources(m_commandList.Get(), m_texture.Get(), textureUploadHeap.Get(), 0, 0, 1, &textureData);

   //把m_texture从copy_dest状态调整到pixel_shader_resource供着色器使用

        m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_texture.Get(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE));


        // Describe and create a SRV for the texture.

        D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};

        srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;

        srvDesc.Format = textureDesc.Format;

        srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;

        srvDesc.Texture2D.MipLevels = 1;

       //实际就是veiw和resource联系到一起才能起作用

        m_device->CreateShaderResourceView(m_texture.Get(), &srvDesc, m_srvHeap->GetCPUDescriptorHandleForHeapStart());

    }

GenerateTextureData():

下面看一看textureData怎么generate的

std::vector<UINT8> D3D12HelloTexture::GenerateTextureData()

{

    const UINT rowPitch = TextureWidth * TexturePixelSize;//1024 bytes

    const UINT cellPitch = rowPitch >> 3;    //128 bytes //32 pixel    // The width of a cell in the checkboard texture.

    const UINT cellHeight = TextureWidth >> 3;   //32 byte //8 pixel The height of a cell in the checkerboard texture.

    const UINT textureSize = rowPitch * TextureHeight;


    std::vector<UINT8> data(textureSize);

    UINT8* pData = &data[0];


    for (UINT n = 0; n < textureSize; n += TexturePixelSize)

    {

        UINT x = n % rowPitch; //字节 第几列

        UINT y = n / rowPitch;   //字节第几行

        UINT i = x / cellPitch;   //第几列的格子

        UINT j = y / cellHeight;  //第几行的


        if (i % 2 == j % 2) // 格子横纵坐标奇偶一致的都是白色

        {

            pData[n] = 0x00;        // R

            pData[n + 1] = 0x00;    // G

            pData[n + 2] = 0x00;    // B

            pData[n + 3] = 0xff;    // A

        }

        else

        {

            pData[n] = 0xff;        // R

            pData[n + 1] = 0xff;    // G

            pData[n + 2] = 0xff;    // B

            pData[n + 3] = 0xff;    // A

        }

    }


    return data;

}

PopulateCommandList():我们只写新增的, 其余部分跟上一期的一样

void D3D12HelloTexture::PopulateCommandList()

{

     //设置了一个Texture资源heap

     //之前的都没有,因为不存在资源啊

    ID3D12DescriptorHeap* ppHeaps[] = { m_srvHeap.Get() };

    m_commandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);

    // 还要设置Root 描述符的表其实就是设置要用的资源

    m_commandList->SetGraphicsRootDescriptorTable(0, m_srvHeap->GetGPUDescriptorHandleForHeapStart());

   //这里其实就是先拿到handle的start位置然后offset m_frameIndex*m_rtvDescriptorSize 就到了我们当前的backbuffer的handle

    CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle(m_rtvHeap->GetCPUDescriptorHandleForHeapStart(), m_frameIndex, m_rtvDescriptorSize);

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

    }


3.D3D12HelloFrameBuffering

1.主要变化

成员数据

//每个frame都有一个allocator了

ComPtr<ID3D12CommandAllocator> m_commandAllocators[FrameCount];

//每个frame都有一个m_fenceValue了

UINT64 m_fenceValues[FrameCount];

函数

LoadPipeline()

for (UINT n = 0; n < FrameCount; n++)

        {

            ThrowIfFailed(m_swapChain->GetBuffer(n, IID_PPV_ARGS(&m_renderTargets[n])));

            m_device->CreateRenderTargetView(m_renderTargets[n].Get(), nullptr, rtvHandle);

            rtvHandle.Offset(1, m_rtvDescriptorSize);


            //其实就是新增了一个allocator而已

ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocators[n])));

        }



LoadAssets()

//创建同步objects的并等待所有asset已经被加载至GPU

 {

        ThrowIfFailed(m_device->CreateFence(m_fenceValues[m_frameIndex], D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence)));

        m_fenceValues[m_frameIndex]++;


        // Create an event handle to use for frame synchronization.

        m_fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);

        if (m_fenceEvent == nullptr)

        {

            ThrowIfFailed(HRESULT_FROM_WIN32(GetLastError()));

        }

            //等GPU加载完成

              WaitForGpu();

    }


MoveToNextFrame()

{

    // Schedule a Signal command in the queue.

    const UINT64 currentFenceValue = m_fenceValues[m_frameIndex];

    ThrowIfFailed(m_commandQueue->Signal(m_fence.Get(), currentFenceValue));

    // Update the frame index.

    m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();

    // If the next frame is not ready to be rendered yet, wait until it is ready.

    if (m_fence->GetCompletedValue() < m_fenceValues[m_frameIndex])

    {

        ThrowIfFailed(m_fence->SetEventOnCompletion(m_fenceValues[m_frameIndex], m_fenceEvent));

        WaitForSingleObjectEx(m_fenceEvent, INFINITE, FALSE);

    }


    // Set the fence value for the next frame.

    m_fenceValues[m_frameIndex] = currentFenceValue + 1;

}

我们可以看到这一次除了第一次等待GPU和第一的MoveToNextFrame需要等待,其余时间就没有WatiforSingleObject了,就非常完美,减少了堵塞的可能性. 之前的版本就很离谱需要你每次渲染的时候都要堵塞一下.

WaitForGpu();

倒也没啥太大变化,等GPU上面的command 全部处理完

void D3D12HelloFrameBuffering::WaitForGpu()

{

    // Schedule a Signal command in the queue.

    ThrowIfFailed(m_commandQueue->Signal(m_fence.Get(), m_fenceValues[m_frameIndex]));


    // Wait until the fence has been processed.

    ThrowIfFailed(m_fence->SetEventOnCompletion(m_fenceValues[m_frameIndex], m_fenceEvent));

    WaitForSingleObjectEx(m_fenceEvent, INFINITE, FALSE);


    // Increment the fence value for the current frame.

    m_fenceValues[m_frameIndex]++;

}



4.D3D12HelloConstBuffers

1.新增了啥

ComPtr<ID3D12Resource> m_constantBuffer:

const buffer的资源类接口

SceneConstantBuffer m_constantBufferData

其实就是类似于ue4材质节点的world position offset一样的东西

struct SceneConstantBuffer

    {

        XMFLOAT4 offset;

        float padding[60]; // 256字节对齐

    };

constant_buffer的实际数据位置

UINT8* m_pCbvDataBegin:

const buffer数据的开始指针


ComPtr<ID3D12DescriptorHeap> m_cbvHeap:

新增了存储const buffer view的heap


LoadPipeLine():

 D3D12_DESCRIPTOR_HEAP_DESC cbvHeapDesc = {};

        cbvHeapDesc.NumDescriptors = 1;

        cbvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;

        cbvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;

        ThrowIfFailed(m_device->CreateDescriptorHeap(&cbvHeapDesc, IID_PPV_ARGS(&m_cbvHeap)));

其实就是在这里新增了存放Constant Buffer的位置资源的位置


Load Assets():

创建一个带有cbv的descriptor table

{

        ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);

        rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_VERTEX);


        // Allow input layout and deny uneccessary access to certain pipeline stages.

        D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =

            D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |

            D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |

            D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |

            D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |

            D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS;


        CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc;

        rootSignatureDesc.Init_1_1(_countof(rootParameters), rootParameters, 0, nullptr, rootSignatureFlags);


        ComPtr<ID3DBlob> signature;

        ComPtr<ID3DBlob> error;

        ThrowIfFailed(D3DX12SerializeVersionedRootSignature(&rootSignatureDesc, featureData.HighestVersion, &signature, &error));

        ThrowIfFailed(m_device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature)));

    }


创建Constant Buffer

    // Create the constant buffer.

    {

        const UINT constantBufferSize = sizeof(SceneConstantBuffer);    // CB size is required to be 256-byte aligned.


        ThrowIfFailed(m_device->CreateCommittedResource(

            &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),

            D3D12_HEAP_FLAG_NONE,

            &CD3DX12_RESOURCE_DESC::Buffer(constantBufferSize),

            D3D12_RESOURCE_STATE_GENERIC_READ,

            nullptr,

            IID_PPV_ARGS(&m_constantBuffer)));


        // Describe and create a constant buffer view.

        D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};

        cbvDesc.BufferLocation = m_constantBuffer->GetGPUVirtualAddress();

        cbvDesc.SizeInBytes = constantBufferSize;

        m_device->CreateConstantBufferView(&cbvDesc, m_cbvHeap->GetCPUDescriptorHandleForHeapStart());


        // Map and initialize the constant buffer. We don't unmap this until the

        // app closes. Keeping things mapped for the lifetime of the resource is okay.

        CD3DX12_RANGE readRange(0, 0);        // We do not intend to read from this resource on the CPU.

    //把resource的buffer的指针给m_pCbvDataBegin赋值,然后把m_constantBufferData的值赋给资源

        ThrowIfFailed(m_constantBuffer->Map(0, &readRange, reinterpret_cast<void**>(&m_pCbvDataBegin)));

        memcpy(m_pCbvDataBegin, &m_constantBufferData, sizeof(m_constantBufferData));

    }


OnUpdate():

其实就是在不断改变这个offset的值并拷贝给资源所在的内存

const float translationSpeed = 0.005f;

    const float offsetBounds = 1.25f;

    

    m_constantBufferData.offset.x += translationSpeed;

    if (m_constantBufferData.offset.x > offsetBounds)

    {

        m_constantBufferData.offset.x = -offsetBounds;

    }

    memcpy(m_pCbvDataBegin, &m_constantBufferData, sizeof(m_constantBufferData));

PopulateCommandList():

{

//把cbv_heap设置为当前使用的descriptor heap

ID3D12DescriptorHeap* ppHeaps[] = { m_cbvHeap.Get() };

    m_commandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);

   m_commandList->SetGraphicsRootDescriptorTable(0, m_cbvHeap->GetGPUDescriptorHandleForHeapStart());

}



5.D3D12HelloBundles

1.新增了啥

成员数据

 m_bundleAllocator:

ComPtr<ID3D12CommandAllocator>类型的allocator专门个bundle分配内存.

m_bundle:

ComPtr<ID3D12GraphicsCommandList>类型的command list用来存command



函数变化:


LoadPipeline()

就创建了一个bundle_allocator

 ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_BUNDLE, IID_PPV_ARGS(&m_bundleAllocator)));



LoadAssets(): 

我们可以把bundle理解为一个包就行了

其实这个很适合像UE4里面每一个物体都有很复杂的shader的时候, 每个object的command 就做成一个bundle就挺好. 保证了更好的封装性,性能也更好.

其实就是创建了一个command list bundle

 // Create and record the bundle.

    {

        ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_BUNDLE, m_bundleAllocator.Get(), m_pipelineState.Get(), IID_PPV_ARGS(&m_bundle)));

        m_bundle->SetGraphicsRootSignature(m_rootSignature.Get());

        m_bundle->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

        m_bundle->IASetVertexBuffers(0, 1, &m_vertexBufferView);

        m_bundle->DrawInstanced(3, 1, 0, 0);

        ThrowIfFailed(m_bundle->Close());

    }


PopulateCommandList()

// 其实这里应该不是真的执行而是把bundle里面的命令添加到commandlist里面

    m_commandList->ExecuteBundle(m_bundle.Get());




posted @ 2021-09-13 20:27  Tonarinototoro  阅读(273)  评论(0编辑  收藏  举报