C++ 多常数缓冲区-寄存器-dx12

C++ 多常数缓冲区-寄存器-dx12,c++,graphics,directx,directx-12,C++,Graphics,Directx,Directx 12,我通过该教程学习dx12: 我试图修改这个步骤,得到2个常量缓冲区(如果我理解得很好的话,是一个寄存器b0和一个b1) 为此,我开始在我的根符号中说,有两个参数: // create root signature // create a descriptor range (descriptor table) and fill it out // this is a range of descriptors inside a descriptor heap D3D12_DESCRIPTOR_R

我通过该教程学习dx12:

我试图修改这个步骤,得到2个常量缓冲区(如果我理解得很好的话,是一个寄存器b0和一个b1)

为此,我开始在我的根符号中说,有两个参数:

// create root signature

// create a descriptor range (descriptor table) and fill it out
// this is a range of descriptors inside a descriptor heap
D3D12_DESCRIPTOR_RANGE  descriptorTableRanges[1]; // only one range right now
descriptorTableRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; // this is a range of constant buffer views (descriptors)
descriptorTableRanges[0].NumDescriptors = 2; // we only have one constant buffer, so the range is only 1
descriptorTableRanges[0].BaseShaderRegister = 0; // start index of the shader registers in the range
descriptorTableRanges[0].RegisterSpace = 0; // space 0. can usually be zero
descriptorTableRanges[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; // this appends the range to the end of the root signature descriptor tables

// create a descriptor table
D3D12_ROOT_DESCRIPTOR_TABLE descriptorTable;
descriptorTable.NumDescriptorRanges = 0;// _countof(descriptorTableRanges); // we only have one range
descriptorTable.pDescriptorRanges = &descriptorTableRanges[0]; // the pointer to the beginning of our ranges array
D3D12_ROOT_DESCRIPTOR_TABLE descriptorTable2;
descriptorTable2.NumDescriptorRanges = 1;// _countof(descriptorTableRanges); // we only have one range
descriptorTable2.pDescriptorRanges = &descriptorTableRanges[0]; // the pointer to the beginning of our ranges array


// create a root parameter and fill it out
D3D12_ROOT_PARAMETER  rootParameters[2]; // only one parameter right now
rootParameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; // this is a descriptor table
rootParameters[0].DescriptorTable = descriptorTable; // this is our descriptor table for this root parameter
rootParameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; // our pixel shader will be the only shader accessing this parameter for now
rootParameters[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; // this is a descriptor table
rootParameters[1].DescriptorTable = descriptorTable2; // this is our descriptor table for this root parameter
rootParameters[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; // our pixel shader will be the only shader accessing this parameter for now
但现在我无法将常量缓冲区链接到变量,我尝试在代码的这一部分进行修改:

 // Create a constant buffer descriptor heap for each frame
// this is the descriptor heap that will store our constant buffer descriptor
for (int i = 0; i < frameBufferCount; ++i)
{
    D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
    heapDesc.NumDescriptors = 1;
    heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
    heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
    hr = device->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&mainDescriptorHeap[i]));
    if (FAILED(hr))
    {
        Running = false;
    }
}

// create the constant buffer resource heap
// We will update the constant buffer one or more times per frame, so we will use only an upload heap
// unlike previously we used an upload heap to upload the vertex and index data, and then copied over
// to a default heap. If you plan to use a resource for more than a couple frames, it is usually more
// efficient to copy to a default heap where it stays on the gpu. In this case, our constant buffer
// will be modified and uploaded at least once per frame, so we only use an upload heap

// create a resource heap, descriptor heap, and pointer to cbv for each frame
for (int i = 0; i < frameBufferCount; ++i)
{
    hr = device->CreateCommittedResource(
        &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD), // this heap will be used to upload the constant buffer data
        D3D12_HEAP_FLAG_NONE, // no flags
        &CD3DX12_RESOURCE_DESC::Buffer(1024 * 64), // size of the resource heap. Must be a multiple of 64KB for single-textures and constant buffers
        D3D12_RESOURCE_STATE_GENERIC_READ, // will be data that is read from so we keep it in the generic read state
        nullptr, // we do not have use an optimized clear value for constant buffers
        IID_PPV_ARGS(&constantBufferUploadHeap[i]));
    constantBufferUploadHeap[i]->SetName(L"Constant Buffer Upload Resource Heap");

    D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
    cbvDesc.BufferLocation = constantBufferUploadHeap[i]->GetGPUVirtualAddress();
    cbvDesc.SizeInBytes = (sizeof(ConstantBuffer) + 255) & ~255;    // CB size is required to be 256-byte aligned.
    device->CreateConstantBufferView(&cbvDesc, mainDescriptorHeap[i]->GetCPUDescriptorHandleForHeapStart());

    ZeroMemory(&cbColorMultiplierData, sizeof(cbColorMultiplierData));

    CD3DX12_RANGE readRange(0, 0);    // We do not intend to read from this resource on the CPU. (End is less than or equal to begin)
    hr = constantBufferUploadHeap[i]->Map(0, &readRange, reinterpret_cast<void**>(&cbColorMultiplierGPUAddress[i]));
    memcpy(cbColorMultiplierGPUAddress[i], &cbColorMultiplierData, sizeof(cbColorMultiplierData));
}
//为每个帧创建一个常量缓冲区描述符堆
//这是将存储常量缓冲区描述符的描述符堆
对于(int i=0;iCreateDescriptorHeap(&heapDesc,IID_PPV_ARGS(&mainscriptorHeap[i]);
如果(失败(小时))
{
运行=错误;
}
}
//创建常量缓冲区资源堆
//我们将在每帧更新常量缓冲区一次或多次,因此我们将只使用上载堆
//与以前不同的是,我们使用上载堆上载顶点和索引数据,然后进行复制
//添加到默认堆。如果计划将资源用于多个帧,则通常需要更多
//高效地复制到gpu上的默认堆。在本例中,我们的常量缓冲区
//每个帧将被修改和上传至少一次,所以我们只使用上传堆
//为每个帧创建资源堆、描述符堆和指向cbv的指针
对于(int i=0;iCreateCommittedResource(
&CD3DX12_HEAP_属性(D3D12_HEAP_TYPE_UPLOAD),//此堆将用于上载常量缓冲区数据
D3D12\u堆\u标志\u无,//无标志
&CD3DX12_RESOURCE_DESC::Buffer(1024*64),//资源堆的大小。对于单个纹理和常量缓冲区,必须是64KB的倍数
D3D12_RESOURCE_STATE_GENERIC_READ,//将是从中读取的数据,因此我们将其保持在GENERIC READ状态
nullptr,//我们没有为常量缓冲区使用优化的清除值
IID_PPV_ARGS(&constantBufferUploadHeap[i]);
constantBufferUploadHeap[i]->SetName(L“常量缓冲区上载资源堆”);
D3D12_常量_缓冲区_视图_DESC cbvDesc={};
cbvDesc.BufferLocation=constantBufferUploadHeap[i]->GetGPUVirtualAddress();
cbvDesc.SizeInBytes=(sizeof(ConstantBuffer)+255)&~255;//CB size需要256字节对齐。
设备->CreateConstantBufferView(&cbvDesc,mainDescriptorHeap[i]->GetCPUDescriptorHandleForHeapStart());
ZeroMemory(&cbColorMultiplierData,sizeof(cbColorMultiplierData));
CD3DX12_RANGE readRange(0,0);//我们不打算在CPU上读取此资源。(End小于或等于begin)
hr=constantBufferUploadHeap[i]->Map(0,&readRange,reinterpret_cast(&cbColorMultiplierGPUAddress[i]);
memcpy(cbColorMultiplierGPUAddress[i],&cbColorMultiplierData,sizeof(cbColorMultiplierData));
}

谢谢您的根签名不正确,您正在尝试设置一个没有范围的描述符表

在根签名中注册常量缓冲区有三种方法:根常量、根常量缓冲区和描述符表。前两种方法为每个根参数连接一个常量缓冲区,而第三种方法允许在一个表中设置多个常量缓冲区

在您的例子中,描述符表类型的单个根参数,以及引用2数组的单个范围,足以让您绑定2个常量缓冲区

我建议您阅读HLSL中声明的内容,以便更好地理解概念及其如何转化为C++声明。 至于操作常量缓冲区的运行时部分。您将不得不再次非常小心,他们在d3d12中没有生命周期管理,也没有像d3d11那样的驱动程序,如果不确保GPU已经使用以前的内容完成,您就无法就地更新恒定的缓冲内存。解决方案通常是使用环形缓冲区来分配帧常量缓冲区,并使用围栏防止过早覆盖


我强烈建议您坚持使用d3d11。d3d12并不是它的替代品,它是为了克服某些性能问题而设计的,这些性能问题只有在极其复杂的渲染器中才能找到,并且只有具备GPU和d3d11专业知识的人才能使用,前提是您的应用程序的复杂度没有达到GTA V的水平(只是一个示例),切换到d3d12只会给你带来麻烦。

谢谢,指出这些问题并给我指向HLSL根签名的链接:)我不再有这些代码了,我实际上正在处理这些代码:但我会在将来重新处理这个问题,我会开始图形编程,所以我对dx11也一无所知。谢谢你的警告,但现在我更愿意继续使用dx12:)@Zeldarck这是一个非常糟糕的主意,但如果你坚持下去的话。反复阅读Microsoft文档,避免教程,学习文档以建立自己对API的理解。在危险方面,尤其要注意CPU/GPU同步和内存管理。