Simple C++ reflection (to generate HLSL constant buffer declaration)

Recently I was working a bit more on my Direct3d11  shadow experiments code. I had to modify constant buffer layouts many times and that meant I had to make many matching updates in C++ and HLSL. I was thinking about a simple solution to only define one side and get the other one automatically generated. Without the redundancy I can also prevent some bugs. I though of many solutions and decided on using macros and some C++ code that generates the HLSL code though some form of reflection (getting type and name). This is how I define my constant buffer on C++ side:

START_STRUCT(SViewConstants)
  ENTRY(XMMATRIX, c_WorldViewProj)
  ENTRY(XMMATRIX, c_InvViewProj)
  ENTRY(XMMATRIX, c_World2Shadow)
  ENTRY(XMFLOAT3, c_EyePos)
  ENTRY(float,    c_ShadowBias)
  ENTRY(XMFLOAT3, c_SunDirection) // normalized
  ENTRY(float,    c_FracTime)
  ENTRY(XMFLOAT4, c_BackbufferExtent) // w, h, 1/w, 1/h
  ENTRY(uint32,   c_iBackbufferExtentX)
  ENTRY(uint32,   c_iBackbufferExtentY)
  ENTRY(uint32,   c_iFrameId)
  ENTRY(uint32,   c_iDummy9123)
  ENTRY(XMFLOAT4, c_ShadowmapExtent) // w, h, 1/w, 1/h
END_STRUCT()

This is the code needed for the reflection (WordPress ate all HTML looking parts in the templates so I had to post it as image and word document as it doesn’t support txt and cpp either):

reflection

reflection (as word document)

And this is how I generate the HLSL code:

struct SStructReflection : public IStructReflection
{
  FILE* out;
  SStructReflection(FILE* InOut) : out(InOut) {}

  virtual void Start(const char* StructName)
  {
    fprintf(out, "\r\ncbuffer %s\r\n{\r\n", StructName);
  }
  virtual void Add(const char* Type, const char* Name)
  {
    fprintf(out, "\t%s %s;\r\n", Type, Name);
  }
  virtual void End()
  {
    fprintf(out, "};\r\n");
  }
};
void GenerateAutoCommon()
{
  FILE* out = 0;
  if(_wfopen_s(&out, L"Shaders\\AutoCommon.hlsl", L"wb") == 0)
  {
    SStructReflection Refl(out);

    SViewConstants::Reflection(Refl);
    // ... other constant buffers

    fclose(out);
  }
}

This could be improved further e.g.

  • Checking for proper alignment (simply count the size and asset)
  • Make reflection defines independent from HLSL (simply return the type as string)
  • Avoid the virtual (create a data structure that can be processed later on)
  • Hide dummy functions from auto completion (could read/parse C++ as text and avoid macros)

However in it’s current form it fulfills its purpose and it’s much easier to get the idea (look at the defines, they create functions that produce a chain calling the reflection interface methods).

Advertisements

2 thoughts on “Simple C++ reflection (to generate HLSL constant buffer declaration)

  1. That’s a nice trick! Although for me the biggest pain and source of bugs is the alignment policy of DX constant buffers, which is different than in C++. Maybe it could be solved if cbuffer definition generated a header with C++ struct definition, not the other way around?

    • I guess you can add alignment but I prefer to do it manually and get an error if it is not valid (easy to do with the current implementation) – this teaches you the rules and you can make tighter layouts. If you start with HLSL you have to recompile C++. That is possible but I like to have shader changes not requiring .exe recompiles.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s