Fixing SBT alignment

This commit is contained in:
mklefrancois 2020-05-27 16:50:02 +02:00
parent ccdc90f35c
commit 41d6bbeea4
2 changed files with 48 additions and 29 deletions

View file

@ -218,9 +218,10 @@ The size of each group can be described as follows:
~~~~ C++ ~~~~ C++
// Sizes // Sizes
uint32_t rayGenSize = groupHandleSize; uint32_t rayGenSize = baseAlignment;
uint32_t missSize = groupHandleSize; uint32_t missSize = baseAlignment;
uint32_t hitSize = groupHandleSize + sizeof(HitRecordBuffer); uint32_t hitSize =
ROUND_UP(groupHandleSize + static_cast<int>(sizeof(HitRecordBuffer)), baseAlignment);
uint32_t newSbtSize = rayGenSize + 2 * missSize + 2 * hitSize; uint32_t newSbtSize = rayGenSize + 2 * missSize + 2 * hitSize;
~~~~ ~~~~
@ -238,14 +239,16 @@ Then write the new SBT like this, where only Hit 1 has extra data.
memcpy(pBuffer, handles[2], groupHandleSize); // Miss 1 memcpy(pBuffer, handles[2], groupHandleSize); // Miss 1
pBuffer += missSize; pBuffer += missSize;
memcpy(pBuffer, handles[3], groupHandleSize); // Hit 0 uint8_t* pHitBuffer = pBuffer;
pBuffer += groupHandleSize; memcpy(pHitBuffer, handles[3], groupHandleSize); // Hit 0
pBuffer += sizeof(HitRecordBuffer); // No data // No data
pBuffer += hitSize;
memcpy(pBuffer, handles[4], groupHandleSize); // Hit 1 pHitBuffer = pBuffer;
pBuffer += groupHandleSize; memcpy(pHitBuffer, handles[4], groupHandleSize); // Hit 1
memcpy(pBuffer, &m_hitShaderRecord[0], sizeof(HitRecordBuffer)); // Hit 1 data pHitBuffer += groupHandleSize;
pBuffer += sizeof(HitRecordBuffer); memcpy(pHitBuffer, &m_hitShaderRecord[0], sizeof(HitRecordBuffer)); // Hit 1 data
pBuffer += hitSize;
} }
~~~~ ~~~~
@ -255,12 +258,21 @@ Then change the call to `m_alloc.createBuffer` to create the SBT buffer from `sb
m_rtSBTBuffer = m_alloc.createBuffer(cmdBuf, sbtBuffer, vk::BufferUsageFlagBits::eRayTracingKHR); m_rtSBTBuffer = m_alloc.createBuffer(cmdBuf, sbtBuffer, vk::BufferUsageFlagBits::eRayTracingKHR);
~~~~ ~~~~
Note: we are using this `define` for rounding up to the correct alignment
~~~~ C++
#ifndef ROUND_UP
#define ROUND_UP(v, powerOf2Alignment) (((v) + (powerOf2Alignment)-1) & ~((powerOf2Alignment)-1))
#endif
~~~~
## `raytrace` ## `raytrace`
Finally, since the size of the hit group is now larger than just the handle, we need to set the new value of the hit group stride in `HelloVulkan::raytrace`. Finally, since the size of the hit group is now larger than just the handle, we need to set the new value of the hit group stride in `HelloVulkan::raytrace`.
~~~~ C++ ~~~~ C++
vk::DeviceSize hitGroupStride = progSize + sizeof(HitRecordBuffer); vk::DeviceSize hitGroupStride =
ROUND_UP(m_rtProperties.shaderGroupHandleSize + sizeof(HitRecordBuffer), progOffset);
~~~~ ~~~~
!!! Note: !!! Note:
@ -316,10 +328,11 @@ The size of the SBT will now account for its 3 hit groups:
Finally, we need to add the new entry as well at the end of the buffer, reusing the handle of the second Hit Group and setting a different color. Finally, we need to add the new entry as well at the end of the buffer, reusing the handle of the second Hit Group and setting a different color.
~~~~ C++ ~~~~ C++
memcpy(pBuffer, handles[4], groupHandleSize); // Hit 2 pHitBuffer = pBuffer;
pBuffer += groupHandleSize; memcpy(pHitBuffer, handles[4], groupHandleSize); // Hit 2
memcpy(pBuffer, &m_hitShaderRecord[1], sizeof(HitRecordBuffer)); // Hit 2 data pHitBuffer += groupHandleSize;
pBuffer += sizeof(HitRecordBuffer); memcpy(pHitBuffer, &m_hitShaderRecord[1], sizeof(HitRecordBuffer)); // Hit 2 data
pBuffer += hitSize;
~~~~ ~~~~
!!! Warning !!! Warning

View file

@ -1238,9 +1238,9 @@ group for that instance.
The SBT is an array containing the handles to the shader groups used in the ray tracing pipeline. In our example, we The SBT is an array containing the handles to the shader groups used in the ray tracing pipeline. In our example, we
will create a buffer for the three groups: raygen, miss and closest hit. The size of the handle is given by the will create a buffer for the three groups: raygen, miss and closest hit. The size of the handle is given by the
`shaderGroupHandleSize` member of the ray tracing properties. We will then allocate a buffer of size `3 * `shaderGroupHandleSize` member of the ray tracing properties, but the offset need to be aligned on `shaderGroupBaseAlignment`.
shaderGroupHandleSize` and will consecutively write the handle of each shader group. To retrieve all the handles, we We will then allocate a buffer of size `3 * shaderGroupBaseAlignment` and will consecutively write the handle of each shader group.
will call `vkGetRayTracingShaderGroupHandlesKHR`. To retrieve all the handles, we will call `vkGetRayTracingShaderGroupHandlesKHR`.
The buffer will have the following information, which will later be used when calling `vkCmdTraceRaysKHR`: The buffer will have the following information, which will later be used when calling `vkCmdTraceRaysKHR`:
@ -1279,9 +1279,10 @@ void HelloVulkan::createRtShaderBindingTable()
auto groupCount = auto groupCount =
static_cast<uint32_t>(m_rtShaderGroups.size()); // 3 shaders: raygen, miss, chit static_cast<uint32_t>(m_rtShaderGroups.size()); // 3 shaders: raygen, miss, chit
uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier uint32_t groupHandleSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier
uint32_t baseAlignment = m_rtProperties.shaderGroupBaseAlignment; // Size of shader alignment
// Fetch all the shader handles used in the pipeline, so that they can be written in the SBT // Fetch all the shader handles used in the pipeline, so that they can be written in the SBT
uint32_t sbtSize = groupCount * groupHandleSize; uint32_t sbtSize = groupCount * baseAlignment;
```` ````
We then fetch the handles to the shader groups of the pipeline, and let the allocator allocate the device memory and We then fetch the handles to the shader groups of the pipeline, and let the allocator allocate the device memory and
@ -1291,16 +1292,21 @@ copy the handles into the SBT:
std::vector<uint8_t> shaderHandleStorage(sbtSize); std::vector<uint8_t> shaderHandleStorage(sbtSize);
m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize, m_device.getRayTracingShaderGroupHandlesKHR(m_rtPipeline, 0, groupCount, sbtSize,
shaderHandleStorage.data()); shaderHandleStorage.data());
// Write the handles in the SBT
m_rtSBTBuffer = m_alloc.createBuffer(sbtSize, vk::BufferUsageFlagBits::eTransferSrc,
vk::MemoryPropertyFlagBits::eHostVisible
| vk::MemoryPropertyFlagBits::eHostCoherent);
m_debug.setObjectName(m_rtSBTBuffer.buffer, std::string("SBT").c_str());
// Write the handles in the SBT // Write the handles in the SBT
nvvk::CommandPool genCmdBuf(m_device, m_graphicsQueueIndex); void* mapped = m_alloc.map(m_rtSBTBuffer);
vk::CommandBuffer cmdBuf = genCmdBuf.createCommandBuffer(); auto* pData = reinterpret_cast<uint8_t*>(mapped);
for(uint32_t g = 0; g < groupCount; g++)
m_rtSBTBuffer = {
m_alloc.createBuffer(cmdBuf, shaderHandleStorage, vk::BufferUsageFlagBits::eRayTracingKHR); memcpy(pData, shaderHandleStorage.data() + g * groupHandleSize, groupHandleSize); // raygen
m_debug.setObjectName(m_rtSBTBuffer.buffer, "SBT"); pData += baseAlignment;
}
m_alloc.unmap(m_rtSBTBuffer);
genCmdBuf.submitAndWait(cmdBuf);
m_alloc.finalizeAndReleaseStaging(); m_alloc.finalizeAndReleaseStaging();
} }
@ -1360,7 +1366,7 @@ each shader. In our case the stride is simply the size of a shader group handle,
shader-group-specific data within the SBT, resulting in a larger stride. shader-group-specific data within the SBT, resulting in a larger stride.
```` C ```` C
vk::DeviceSize progSize = m_rtProperties.shaderGroupHandleSize; // Size of a program identifier vk::DeviceSize progSize = m_rtProperties.shaderGroupBaseAlignment; // Size of a program identifier
vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer vk::DeviceSize rayGenOffset = 0u * progSize; // Start at the beginning of m_sbtBuffer
vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen vk::DeviceSize missOffset = 1u * progSize; // Jump over raygen
vk::DeviceSize missStride = progSize; vk::DeviceSize missStride = progSize;