Jump to content
  • Advertisement
Sign in to follow this  
Juliean

DX11 HLSL consecutive constant register declaration?

This topic is 2103 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello,

 

for a while now I've been usingt only the DirectX11 renderer of my engine, now I've the whole afternoon on catching up with my DirectX9-equivalent. When updating the shaders, I came across a problem, or rather an annoyance at first. In DX11, I' ve been supporting up to three cbuffers: Application wide, per instance, and per render stage. This allowed me to conveniently write my buffers like this:

cbuffer instance : register(b1)
{
	matrix mModel;
}

cbuffer stage : register(b2)
{
	float4	corner00, corner01, corner10, corner11;
	float2	vInvMapSize;
}

Now, I've been typing out the register variable every time, however this isn't as practical in DX9 as it is here. In order for my engine not having to rely on a self-made reflection, or shader annotations, I'm simply reserving a certain number of registers for each "constant buffer", e.g. from register 0-12 can be used for the application, 13-48 is for the model, and so on. Now this gets a little more tedious, as I'd have to do this:

float4x4 mModel : register(c13); 

float4 corner00 : register(c49), corner01 : register(c50), corner10 : register(c51), corner11 : register(c52);
float2 vInvMapSize : register(c53);

Not only is it tedious, but also easy to get things wrong, and I also want to allow the ranges to change easily (maybe I'm going to need more registers once I start doing skinning). I'm already using shader macros for permutations, so I figured, why not add a few macros for the c-registers? Said and done, but here comes my actual problem:

#define C_INSTANCE c48 // would be passed in as D3DXCompile parameter

float4x4 mModel : register(C_INSTANCE); 

float4 corner00 : register(C_STAGE), corner01, corner10, corner11;
float2 vInvMapSize;

I had the slight hope that the compiler would be nice enough to increment the registers automatically, the after corner00 it would go to C_PASS to c49, and so forth. However it appears that rather the shader "jumps back" and fills out the unused earlier registers, like c0, c1, ... . Is there any way around this? Some way to tell the compiler "this is the current register. Each constant after this, use the next one", or some method to modulate the define (I tried C_STAGE + 1, but it didn't seem to work)...

Share this post


Link to post
Share on other sites
Advertisement
At the moment I use custom annotations, and at my last job we wrote a parser that could understand the cbuffer format but then convert it into the DX9 equivalent.
However, at the job before that, the engine team had simply pre-declared hundreds of variables in specific registers (in contiguous blocks), that you could then rename with macros, e.g.
#define materialColor u_material01
#define fxDirection u_user07

Share this post


Link to post
Share on other sites

Oh, man, so much to do myself :D Any tricks on how to read annotations or write a custom parser that is performant? Is there some better way than just to use getline on a filestream and check each line if it contains a certain annotation with std::string::find? I think I'll go with a limited parser, where I'd need to set a placeholder to each constant, so that I'll at least don't need to allocate a new file buffer:

float4 corner00 : register(C_STAGE), corner01 : register(cXX), corner10 : register(cXX), corner11 : register(CXX);
float2 vInvMapSize : register(cXX);

where XX will be replaced by C_STAGE's value consecutevly incremented. Does that sound resonable to you, or is there some better way of reducing the overhead introduced when I want to add custom text to a file loaded into a char* buffer? From what I gather everytime I want to add something, I eigther need to manually resize the buffer I store the file in, or have to use a std::string which internally probably just does that, which sounds wasteful..

Share this post


Link to post
Share on other sites

Instead of writing a parser, I scan for "/*[FX]" and then a following "*/", and execute the text in between as Lua code.

I've described my current solution before in this thread: http://www.gamedev.net/topic/618167-emulating-cbuffers/

You can see in that thread for example that the Lua code can call functions like cbuffer, passing tables of data to describe the variables. I then store all that data and use it when compiling the shader.

 

I don't really care about uber-performance here, because I compile my shaders from HLSL to binary ahead of time -- the toolchain does it, not the game/engine.

 

If you do want to do it very simply without allocating extra buffers, then what you've described above sounds simple enough to implement. Except you might want to use the token cXXX instead, in case you need to replace it with c123, etc...

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!