Limits on where texture resources can be accessed?

Started by
7 comments, last by Meltac 8 years, 5 months ago

I've recently run into an issue with shader compilation.

I have managed to pretty much boil it down to occurring when I try to sample a texture (or to be specific, a Texture2DArray) from a standalone function that is called from my pixel shader. Whenever I do this, the shader compiler seemingly gets stuck in an infinite loop. If it threw me an error, OK, but since that doesn't happen it feels like this may not be an actually invalid operation?

Furthermore, if I sample the texture array from the pixel shader itself (it's main function) everything compiles quickly and cleanly just as usual.

I don't want it there though since doing it that way would mean having to move a lot of should-be reusable code into several pixel shaders.

Edit - did some more tests while writing this:

It appears that you can indeed sample the texture array from another function, and that the problem rather arises from this happening inside a for-loop. The loop is used to iterate over light sources, so it has a dynamic number of iterations, and the texture lookup is of a shadow map. It should also be noted that the loop isn't inside the function itself, rather it goes something like this (pseudo code to highlight what seems to be the issue):


float4 PS_EntryPoint(vs_out IN): Sv_Target {
    // ...
    CalculateLightInfluence();
    // ...
}

void CalculateLightInfluence(output parameters) {
    // ...
    for(uint l = 0; l < NumSpotLights; l++)
        CalculateSpotLightInfluence(l);
    // ...
}

void CalculateSpotLightInfluence(uint lightId) {
    // ...
    // If the below line is left as-is, the shader compiler seems to get stuck in an infinite loop.
    // If outcommented the shader works as intended (except for the depth test of course).
    float depth = ShadowMap.Sample(ShadowMapSampler, float3(lp.xy, spotLight[lightId].shadowMapId));
    // ...
}

So my question basically boils down to whether it is some kind of known limitation that you can't sample textures from within such a loop?

For clarity, yes, the shadow map array is bound to all used shader stages, even if the mentioned helper-function that fails to compile is only ever called from the pixel shader.
Or may it be caused by something else failing, such as running out of instruction slots? Or does the compiler just get completely lost trying to unroll the for-loop with a dynamic number of iterations? But if so, why doesn't this happen when I remove the sampling instruction from there?
It seems that either of these cases, if true, really should make the D3DXCompileShader return some error code rather than just get stuck, but this is the first time I've run into this kind of issue so I thought I would ask.

Thanks in advance for any pointers.

Advertisement
I'm not much of an expert in HLSL, but I suspect it may have to do with dynamic branching. Have you tried using an unroll attribute on your for loop (NumSpotLights will need to be const)? This should give you a clue if nothing else.
Here is an Article on possibly related behavior in GLSL. (sorry I can't get the GD edit feature to work).

Thank you, yes I was afraid it was going to be something like that...

With the system I have in mind I have a dynamic buffer to list what lights affect each individual mesh instance so that I won't have to process them all (consider a large outdoors scene with a lot of lights overall but not very many in the same place) for each mesh. I'm not sure whether this will ultimately be the most efficient when considering branching but it seemed like the reasonable approach at the time of conception. So therefore I'm not really able to use a const count.
On the other hand the number of lights clearly doesn't change for the same mesh instance, and I can't believe the same wave / warp / whatever you want to call it would be used for different instances, so there really should hopefully not be any branching inside the thread groups. Of course this is just a feeling and I may well be wrong.

In any case, it seems the main problem here was due to mip level calculations. Since the sampled texture is a shadow map, it only has a single mip and using SampleLevel(sampler, texcoord, 0) does indeed allow the shader to compile. So that will work for now it seems (in fact that is probably the sampling function that should be used in this case anyway) :)

I still wonder why there was no proper failure instead of the compiler just getting stuck though, most unhelpful...

With the system I have in mind I have a dynamic buffer to list what lights affect each individual mesh instance so that I won't have to process them all (consider a large outdoors scene with a lot of lights overall but not very many in the same place) for each mesh


Why not just do Deferred Lighting?

Sean Middleditch – Game Systems Engineer – Join my team!

If you're using the D3DX compilation functions, then the version of the shader compiler that you're using is a few versions out-of-date (d3dcompiler_43.dll). The Windows 8.0 SDK introduced d3dcompiler_46 and d3dcompiler_47, while the Windows 10 SDK includes the latest version (which is confusingly also named d3dcompiler_47.dll). You might want to try using those versions and see if they still have the same behavior. The easiest way to do this is to simply install the Windows 10 SDK (which is included with Visual Studio 2015), and then use the version of fxc.exe that comes with the SDK. If using the new version works, then you might want to switch to the newer compiler. Ideally you would do this by completely switching over to using the D3D headers and libraries from the Windows SDK instead of using the old DirectX SDK, but if that's not an easy option then you can also do it by loading d3dcompiler_47.dll at runtime. You can do this by using LoadLibrary, and then you can use GetProcAddress to get a pointer to the D3DCompile function.

If you're using the D3DX compilation functions, then the version of the shader compiler that you're using is a few versions out-of-date (d3dcompiler_43.dll). The Windows 8.0 SDK introduced d3dcompiler_46 and d3dcompiler_47, while the Windows 10 SDK includes the latest version (which is confusingly also named d3dcompiler_47.dll).

Related question, are there any known compiling performance gains (or disadvantages) when using the newer version of the compiler? Or in other words, in case that several of those versions do work as expected, which would be the fastest (in terms of compilation times)?

Related question, are there any known compiling performance gains (or disadvantages) when using the newer version of the compiler? Or in other words, in case that several of those versions do work as expected, which would be the fastest (in terms of compilation times)?


I do know that the _46 compiler and onward was many times faster for certain compute shaders that accessed shared memory inside of loops, however I couldn't say for sure which version is the fastest in all cases.

Ok thanks - I think I'll just try myself then rolleyes.gif

This topic is closed to new replies.

Advertisement