I am trying to understand the logic of setTextureReg and why it cannot be done automatically together with issuing the CbTexture commands in fillBuffersForV1/fillBuffersForV2. From the implementation is look like all the setTextureReg calls must be placed in notifyPropertiesMergedPreGenerationStep (because it is called from createShaderCacheEntry where the clearing of texture registers and names is done).
The problem to understand the topic, that the structure of checks and increments of texUnit variable must be in sync with issuing of the CbTexture commands in fillBuffersFor implemention. I expect that the implementations are in sync, but just look there it doesn't look like they are.
In HlmsPbs::notifyPropertiesMergedPreGenerationStep
Code: Select all
int32 texUnit = mReservedTexBufferSlots;
if( getProperty( tid, HlmsBaseProp::ForwardPlus ) )
{
if( mVaoManager->readOnlyIsTexBuffer() )
setTextureReg( tid, PixelShader, "f3dLightList", texUnit++ );
else
setProperty( tid, "f3dLightList", texUnit++ );
setTextureReg( tid, PixelShader, "f3dGrid", texUnit++ );
}
texUnit += mReservedTexSlots;
bool depthTextureDefined = false;
if( getProperty( tid, HlmsBaseProp::UsePrePass ) )
{
setTextureReg( tid, PixelShader, "gBuf_normals", texUnit++ );
setTextureReg( tid, PixelShader, "gBuf_shadowRoughness", texUnit++ );
if( getProperty( tid, HlmsBaseProp::UsePrePassMsaa ) )
{
setTextureReg( tid, PixelShader, "gBuf_depthTexture", texUnit++ );
depthTextureDefined = true;
}
else
{
++texUnit;
}
if( getProperty( tid, HlmsBaseProp::UseSsr ) )
setTextureReg( tid, PixelShader, "ssrTexture", texUnit++ );
}
And corresponding code in HlmsPbs::fillBuffersFor:
Code: Select all
size_t texUnit = mReservedTexBufferSlots;
if( !casterPass )
{
constBufferSlot += mAtmosphere->bindConstBuffers( commandBuffer, constBufferSlot );
if( mGridBuffer )
{
*commandBuffer->addCommand<CbShaderBuffer>() =
CbShaderBuffer( PixelShader, (uint16)texUnit++, mGlobalLightListBuffer, 0, 0 );
*commandBuffer->addCommand<CbShaderBuffer>() =
CbShaderBuffer( PixelShader, (uint16)texUnit++, mGridBuffer, 0, 0 );
}
texUnit += mReservedTexSlots;
if( !mPrePassTextures->empty() )
{
*commandBuffer->addCommand<CbTexture>() =
CbTexture( (uint16)texUnit++, ( *mPrePassTextures )[0], 0 );
*commandBuffer->addCommand<CbTexture>() =
CbTexture( (uint16)texUnit++, ( *mPrePassTextures )[1], 0 );
}
if( mPrePassMsaaDepthTexture )
{
*commandBuffer->addCommand<CbTexture>() = CbTexture(
(uint16)texUnit++, mPrePassMsaaDepthTexture, 0,
PixelFormatGpuUtils::isDepth( mPrePassMsaaDepthTexture->getPixelFormat() ) );
}
if( mDepthTexture )
{
*commandBuffer->addCommand<CbTexture>() =
CbTexture( (uint16)texUnit++, mDepthTexture, mDecalsSamplerblock,
PixelFormatGpuUtils::isDepth( mDepthTexture->getPixelFormat() ) );
}
if( mSsrTexture )
{
*commandBuffer->addCommand<CbTexture>() =
CbTexture( (uint16)texUnit++, mSsrTexture, 0 );
}
Almost every condition is written differently. In notifyPropertiesMergedPreGenerationStep, the properties are checked, but in fillBuffersFor, the member variables are checked. It is really hard to track.
Anyway, my question is whether it is not feasible to make everything on once place - specifically in fillBuffersFor - when CbTexture command is issued, together there also update the texture register. Probably it is necessary to cache the texture registers together with properties, but it would be at least at one place. Issuing of the CbTexture command and calling of setTextureReg can be wrapped in the helper function.
Why the textures are set for every renderable? Isn't it more efficient to track the active textures and update the slots only if needed? Or is it done somewhere? If CbTexture command is issued, later when RenderSystem::_setTexture is called from CommandBuffer::execute_setTexture, it just sets the texture.
Edit: I see that calling setProperty within fillBuffersFor is not possible, so try to think in other direction - after calling setTextureReg, somehow translate those calls automatically to the CbTexture commands. E.g. if setTextureReg accepts also texture+sampler, it could be done .. I am trying to come out with the idea how to simplify the implementation on the "user" side if new HLMS is implemented (as I have in my app).
Edit2: The HlmsPbs uses some "global" or "pass" textures which are set only if HLMS type is changed - so there is no need to check which textures are active at the texture slots and then the datablock textures which are baked into texture sets and described by datablock->mTexturesDescSet. This is actually checked against the member variable mLastDescTexture to avoid useless rebindings.
