Falcor
Falcor copied to clipboard
Cannot use ParameterBlock<> in shader.
If you add new ParameterBlock<> inside a shader, the root descriptor in dx12 fails to compile and issues warning.
The easiest way to reproduce is to change Shadow texture in ForwardRenderer sample to be in ParameterBlock.
ForwardRenderer.slang:
Texture2D gVisibilityBuffer;
becomes
struct ShadowTextureData { Texture2D gVisibilityBuffer; }; ParameterBlock<ShadowTextureData> Shadow;
This fails on runtime when trying to compile the root descriptor for this program with
Shader register range of type CBV (root parameter [3], visibility ALL, descriptor table slot [7]) overlaps with another shader register range (root parameter[0], visibility ALL, descriptor table slot [0]).
It looks like some constant buffer has the same index as the ParameterBlock created in ShaderCommon.slang for material data.
Am I doing something wrong, or there is a bug inside Falcor, which prevents from adding multiple ParameterBlocks ?
You should be able to add multiple ParameterBlocks
. I'm looking into it.
I found the issue. The problem is that Falcor reflection always create an entry for a CB named as the ParameterBlock
. In this case, there's no real CB, so the indices are incorrect. I have a fix, will test it and release it with Falcor 3.1.1 later this week.
@tfoleyNV somewhat related, I was under the assumption that each ParameterBlock
resides in its own register-space. Is that not true?
Awesome. Thanks for the quick reaction.
I have a fix in my fork.
If you don't want to wait for the release, replace ParameterBlockReflection::addResource()
in ProgramReflection.cpp
with the following:
void ParameterBlockReflection::addResource(const ReflectionVar::SharedConstPtr& pVar)
{
const ReflectionResourceType* pResourceType = pVar->getType()->unwrapArray()->asResourceType();
assert(pResourceType);
uint32_t elementCount = max(1u, pVar->getType()->getTotalArraySize());
const ReflectionType* pType = pResourceType->getStructType().get();
const ReflectionStructType* pStruct = (pType != nullptr) ? pType->asStructType() : nullptr;
// pVar might be a CB for a ParameterBlock. If it's empty, don't add it
if(pStruct == nullptr || pStruct->getSize())
{
mResources.push_back(getResourceDesc(pVar, elementCount, pVar->getName()));
mpResourceVars->addMember(pVar);
}
// If this is a constant-buffer, it might contain resources. Extract them.
if (pStruct)
{
for (const auto& pMember : *pStruct)
{
if (doesTypeContainsResources(pMember->getType().get()))
{
mpResourceVars->addMember(pMember);
}
}
flattenResources(pStruct, mResources);
}
}
I was just about to come here and comment that a ParameterBlock<X>
where X
contains only resources won't generate a constant buffer, and Falcor probably doesn't account for that. Putting an int dummy;
field into the ShadowTextureData
field above should serve as a workaround for the issue.
I was under the assumption that each ParameterBlock resides in its own register-space. Is that not true?
For Vulkan, each (non-empty) ParameterBlock
will end up getting a distinct set
. For D3D, there is the problem that users might not want distinct space
s, especially when outputting for Shader Model 5.0 or earlier. There is an option to make Slang use a strategy like what it does for Vulkan, but it isn't on by default because D3D never actually requires that you give things distinct space
s - you can still assign them to different descriptor tables even when they are in the same space.
Thanks the fix worked.