3

I have an HLSL shader that defines some resources, say a constant buffer:

cbuffer MyCB : register(b0);

If I compile my shader, I will then be able to query the register through the reflection API. But is it possible to change the register (for instance, to b3) in a compiled shader blob in a similar manner you can assign bind points to resources in a compiled OpenGL program?

Egor
  • 779
  • 5
  • 20

2 Answers2

3

There is no API to change the shader bindings at runtime in a compiled shader.

If you jumped through many hoops, you might be able to achieve this with dynamic shader linking in Shader Model 5.0, although it would be lots of work and not really worth it, when there is a very easy alternative - simply create a new compiled shader with the bindings you want.

MuertoExcobito
  • 9,741
  • 2
  • 37
  • 78
  • You can also look at the [shader linking](https://msdn.microsoft.com/en-us/library/windows/desktop/dn466359.aspx) technology as well--a Direct3D 11 equivalent to the old "FWLINK" tech. – Chuck Walbourn Apr 27 '16 at 15:27
  • @MuertoExcobito I do want to change the bindings at runtime. The reason is that in D3D12, there is an issue when resources from different shader stages (PS and VS) map to the same register: such resources must be put into different descriptor tables. I want all my resources to be in a single descriptor table and the only way I can imagine is to reassign bindings in compiled shaders so that they do not overlap. I think it is possible to bother with the bytecode (timjones.tw/blog/archive/2015/09/02/…), but I was hoping there is an official way to do this. – Egor Apr 27 '16 at 17:41
  • Unless I'm misunderstanding, you can just edit your HLSL shaders, and make sure that the bindings don't overlap. Editing bytecode directly is possible, but tedious, and not necessarily forward compatible. – MuertoExcobito Apr 27 '16 at 18:33
  • @MooseBoys - the OP asked if there was an API to change the shader bindings within a compiled shader blob - there is not. While your answer add something useful (it essentially expands on the second part of mine), my answer is not "incorrect". – MuertoExcobito May 02 '16 at 10:12
1

You can accomplish this in by specifying a BaseShaderRegister other than zero, or using different RegisterSpace values, in the D3D12_DESCRIPTOR_RANGE struct. If code changes are not feasible, you can isolate each set of registers implicitly by setting the root parameter's ShaderVisibility property. This will isolate, for example, VS b0 from PS b0. For more details, you can check out the developer video on the topic.

The only time you will run into trouble is if you've actually explicitly bound two resources to the same slot and register space (by explicitly specifying it using shader model 5.1 syntax). In this case, you are expected to understand that in D3D12, registers are shared cross-stage, and it's up to you to make sure you have no collisions.

In D3D11, this problem does not occur as each stage has its own register space (VS b0 is not the same as PS b0) and you can't share even if you wanted to. Still, if you for some reason have a component hard-coded to attach data to VS b0 but your vertex shader has already been compiled to expect it at b1, there's not much you can do.

MooseBoys
  • 6,641
  • 1
  • 19
  • 43
  • I was thinking about doing exactly the same: assigning different spaces to different shader stages to have all descriptors in one table. The problem is that I do not want/have access to the shader source code. If I was able to change the shader code as follows `cbuffer CBinVS : register(b0,space0);` and `cbuffer CBinPS : register(b0,space1);`, that would solve my problem. What I have is the source code with register bindings that my potentially be in conflict. And I am wondering if I can programmatically correct such conflicts _without_ altering the source code. – Egor May 01 '16 at 17:34
  • @Egor Unless you have already altered the source code to explicitly specify the register space, they should already be in different spaces. All vertex shader bindings are in space 0 and all pixel shader bindings are in space 4. – MooseBoys May 01 '16 at 17:38
  • _All vertex shader bindings are in space 0 and all pixel shader bindings are in space 4_ How did you achieve this? This [MSDN page](https://msdn.microsoft.com/en-us/library/windows/desktop/dn899207(v=vs.85).aspx) specifically says: If the "space" keyword is omitted, the default space index of 0 is implicitly assigned to the range. I double checked that and all bindings in all shader stages are indeed in space 0. – Egor May 01 '16 at 18:08
  • @Egor You're right. The intent is actually to use the `SHADER_VISIBILITY` property to isolate shader stages, which are independent from register spaces. I'll update my answer. – MooseBoys May 01 '16 at 18:32
  • Be careful, when creating a PSO with a different root signature than the one that was used when compiling the shaders, you in fact, under the hood, trigger a shader compilation in the driver. – galop1n May 21 '16 at 17:49