Selaa lähdekoodia

Reflection dumper for testing, add tests, fix more empty struct breaks

Tex Riddell 7 vuotta sitten
vanhempi
commit
7d7ce64f8f

+ 5 - 3
lib/HLSL/DxilContainerReflection.cpp

@@ -922,13 +922,15 @@ HRESULT CShaderReflectionType::Initialize(
       name = name.ltrim("struct.");
       m_Name = name;
 
-      unsigned int fieldCount = type->getStructNumElements();
-
       // Fields may have annotations, and we need to look at these
       // in order to decode their types properly.
       DxilTypeSystem &typeSys = M.GetTypeSystem();
       DxilStructAnnotation *structAnnotation = typeSys.GetStructAnnotation(structType);
-      DXASSERT(structAnnotation, "else type system is missing annotations for user-defined struct");
+
+      // There is no annotation for empty structs
+      unsigned int fieldCount = 0;
+      if (structAnnotation)
+        fieldCount = type->getStructNumElements();
 
       // The DXBC reflection info computes `Columns` for a
       // `struct` type from the fields (see below)

+ 51 - 0
tools/clang/test/CodeGenHLSL/quick-test/d3dreflect/anon_struct.hlsl

@@ -0,0 +1,51 @@
+// RUN: %dxc -T ps_6_0 -E main %s | %D3DReflect %s | FileCheck %s
+
+struct {
+    int X;
+} CB;
+
+float main(int N : A, int C : B) : SV_TARGET {
+    return CB.X;
+}
+
+// CHECK: ID3D12ShaderReflection:
+// CHECK:   D3D12_SHADER_BUFFER_DESC:
+// CHECK:     Shader Version: Pixel 6.0
+// CHECK:     ConstantBuffers: 1
+// CHECK:     BoundResources: 1
+// CHECK:     InputParameters: 2
+// CHECK:     OutputParameters: 1
+// CHECK:   Constant Buffers:
+// CHECK:     ID3D12ShaderReflectionConstantBuffer:
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:         Type: D3D_CT_CBUFFER
+// CHECK:         Size: 16
+// CHECK:         Num Variables: 1
+// CHECK:       {
+// CHECK:         ID3D12ShaderReflectionVariable:
+// CHECK:           D3D12_SHADER_VARIABLE_DESC: Name: CB
+// CHECK:             Size: 4
+// CHECK:             uFlags: 0x2
+// CHECK:           ID3D12ShaderReflectionType:
+// CHECK:             D3D12_SHADER_TYPE_DESC: Name: anon
+// CHECK:               Class: D3D_SVC_STRUCT
+// CHECK:               Type: D3D_SVT_VOID
+// CHECK:               Rows: 1
+// CHECK:               Columns: 1
+// CHECK:               Members: 1
+// CHECK:             {
+// CHECK:               ID3D12ShaderReflectionType:
+// CHECK:                 D3D12_SHADER_TYPE_DESC: Name: int
+// CHECK:                   Class: D3D_SVC_SCALAR
+// CHECK:                   Type: D3D_SVT_INT
+// CHECK:                   Rows: 1
+// CHECK:                   Columns: 1
+// CHECK:             }
+// CHECK:           CBuffer: $Globals
+// CHECK:       }
+// CHECK:   Bound Resources:
+// CHECK:     D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:       Type: D3D_SIT_CBUFFER
+// CHECK:       uID: 0
+// CHECK:       BindPoint: 0
+// CHECK:       Dimension: D3D_SRV_DIMENSION_UNKNOWN

+ 41 - 0
tools/clang/test/CodeGenHLSL/quick-test/d3dreflect/cb_array.hlsl

@@ -0,0 +1,41 @@
+// RUN: %dxc -E main -T ps_6_0 %s | %D3DReflect %s | FileCheck %s
+
+float A[6] : register(b0);
+float main(int i : A) : SV_TARGET
+{
+  return A[i] + A[i+1] + A[i+2] ;
+}
+
+// CHECK: ID3D12ShaderReflection:
+// CHECK:   D3D12_SHADER_BUFFER_DESC:
+// CHECK:     Shader Version: Pixel 6.0
+// CHECK:     ConstantBuffers: 1
+// CHECK:     BoundResources: 1
+// CHECK:     InputParameters: 1
+// CHECK:     OutputParameters: 1
+// CHECK:   Constant Buffers:
+// CHECK:     ID3D12ShaderReflectionConstantBuffer:
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:         Type: D3D_CT_CBUFFER
+// CHECK:         Size: 96
+// CHECK:         Num Variables: 1
+// CHECK:       {
+// CHECK:         ID3D12ShaderReflectionVariable:
+// CHECK:           D3D12_SHADER_VARIABLE_DESC: Name: A
+// CHECK:             Size: 84
+// CHECK:             uFlags: 0x2
+// CHECK:           ID3D12ShaderReflectionType:
+// CHECK:             D3D12_SHADER_TYPE_DESC: Name: float
+// CHECK:               Class: D3D_SVC_SCALAR
+// CHECK:               Type: D3D_SVT_FLOAT
+// CHECK:               Elements: 6
+// CHECK:               Rows: 1
+// CHECK:               Columns: 1
+// CHECK:           CBuffer: $Globals
+// CHECK:       }
+// CHECK:   Bound Resources:
+// CHECK:     D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:       Type: D3D_SIT_CBUFFER
+// CHECK:       uID: 0
+// CHECK:       BindPoint: 0
+// CHECK:       Dimension: D3D_SRV_DIMENSION_UNKNOWN

+ 42 - 0
tools/clang/test/CodeGenHLSL/quick-test/d3dreflect/cbuffer_default_val.hlsl

@@ -0,0 +1,42 @@
+// RUN: %dxc -E main -T ps_6_0 %s | %D3DReflect %s | FileCheck %s
+
+float t = 0.5;
+
+float main() : SV_TARGET
+{
+  return sqrt(t);
+}
+
+// Default value unsupported for now:
+// CHECK: ID3D12ShaderReflection:
+// CHECK:   D3D12_SHADER_BUFFER_DESC:
+// CHECK:     Shader Version: Pixel 6.0
+// CHECK:     ConstantBuffers: 1
+// CHECK:     BoundResources: 1
+// CHECK:     OutputParameters: 1
+// CHECK:   Constant Buffers:
+// CHECK:     ID3D12ShaderReflectionConstantBuffer:
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:         Type: D3D_CT_CBUFFER
+// CHECK:         Size: 16
+// CHECK:         Num Variables: 1
+// CHECK:       {
+// CHECK:         ID3D12ShaderReflectionVariable:
+// CHECK:           D3D12_SHADER_VARIABLE_DESC: Name: t
+// CHECK:             Size: 4
+// CHECK:             uFlags: 0x2
+// CHECK-NOT:             DefaultValue
+// CHECK:           ID3D12ShaderReflectionType:
+// CHECK:             D3D12_SHADER_TYPE_DESC: Name: float
+// CHECK:               Class: D3D_SVC_SCALAR
+// CHECK:               Type: D3D_SVT_FLOAT
+// CHECK:               Rows: 1
+// CHECK:               Columns: 1
+// CHECK:           CBuffer: $Globals
+// CHECK:       }
+// CHECK:   Bound Resources:
+// CHECK:     D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:       Type: D3D_SIT_CBUFFER
+// CHECK:       uID: 0
+// CHECK:       BindPoint: 0
+// CHECK:       Dimension: D3D_SRV_DIMENSION_UNKNOWN

+ 62 - 0
tools/clang/test/CodeGenHLSL/quick-test/d3dreflect/empty_struct2.hlsl

@@ -0,0 +1,62 @@
+// RUN: %dxc -E main -T vs_6_0 %s | %D3DReflect %s | FileCheck %s
+
+// Make sure nest empty struct works.
+
+struct KillerStruct {};
+
+struct InnerStruct {
+  KillerStruct s;
+};
+
+struct OuterStruct {
+  InnerStruct s;
+};
+
+cbuffer Params_cbuffer : register(b0) {
+  OuterStruct constants;
+  float4 foo;
+};
+
+float4 main(float4 pos : POSITION) : SV_POSITION { return foo; }
+
+
+// CHECK: ID3D12ShaderReflection:
+// CHECK:   D3D12_SHADER_BUFFER_DESC:
+// CHECK:     Shader Version: Vertex 6.0
+// CHECK:     ConstantBuffers: 1
+// CHECK:     BoundResources: 1
+// CHECK:     InputParameters: 1
+// CHECK:     OutputParameters: 1
+// CHECK:   Constant Buffers:
+// CHECK:     ID3D12ShaderReflectionConstantBuffer:
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: Params_cbuffer
+// CHECK:         Type: D3D_CT_CBUFFER
+// CHECK:         Size: 16
+// CHECK:         Num Variables: 2
+// CHECK:       {
+// CHECK:         ID3D12ShaderReflectionVariable:
+// CHECK:           D3D12_SHADER_VARIABLE_DESC: Name: constants
+// CHECK:           ID3D12ShaderReflectionType:
+// CHECK:             D3D12_SHADER_TYPE_DESC: Name: OuterStruct
+// CHECK:               Class: D3D_SVC_STRUCT
+// CHECK:               Type: D3D_SVT_VOID
+// CHECK:               Rows: 1
+// CHECK:           CBuffer: Params_cbuffer
+// CHECK:         ID3D12ShaderReflectionVariable:
+// CHECK:           D3D12_SHADER_VARIABLE_DESC: Name: foo
+// CHECK:             Size: 16
+// CHECK:             uFlags: 0x2
+// CHECK:           ID3D12ShaderReflectionType:
+// CHECK:             D3D12_SHADER_TYPE_DESC: Name: float4
+// CHECK:               Class: D3D_SVC_VECTOR
+// CHECK:               Type: D3D_SVT_FLOAT
+// CHECK:               Rows: 1
+// CHECK:               Columns: 4
+// CHECK:           CBuffer: Params_cbuffer
+// CHECK:       }
+// CHECK:   Bound Resources:
+// CHECK:     D3D12_SHADER_BUFFER_DESC: Name: Params_cbuffer
+// CHECK:       Type: D3D_SIT_CBUFFER
+// CHECK:       uID: 0
+// CHECK:       BindPoint: 0
+// CHECK:       Dimension: D3D_SRV_DIMENSION_UNKNOWN

+ 245 - 0
tools/clang/test/CodeGenHLSL/quick-test/d3dreflect/reflect-lib-1.hlsl

@@ -0,0 +1,245 @@
+// RUN: %dxc -T lib_6_3 %s | %D3DReflect %s | FileCheck %s
+
+float cbval1;
+cbuffer MyCB : register(b11, space2) { int4 cbval2, cbval3; }
+RWTexture1D<int4> tex : register(u5);
+Texture1D<float4> tex2 : register(t0);
+SamplerState samp : register(s7);
+RWByteAddressBuffer b_buf;
+float function0(min16float x) { 
+  return x + cbval2.x + tex[0].x; }
+float function1(float x, min12int i) {
+  return x + cbval1 + b_buf.Load(x) + tex2.Sample(samp, x).x; }
+[shader("vertex")]
+float function2(float4 x : POSITION) : SV_Position { return x + cbval1 + cbval3.x; }
+
+
+// CHECK: ID3D12LibraryReflection:
+// CHECK:   D3D12_LIBRARY_DESC:
+// CHECK:     FunctionCount: 4
+// CHECK:   ID3D12FunctionReflection:
+// CHECK:     D3D12_FUNCTION_DESC: Name: \01?function0@@YAM$f16@@Z
+// CHECK:       Shader Version: Library 6.3
+// CHECK:       ConstantBuffers: 1
+// CHECK:       BoundResources: 2
+// CHECK:     Constant Buffers:
+// CHECK:       ID3D12ShaderReflectionConstantBuffer:
+// CHECK:         D3D12_SHADER_BUFFER_DESC: Name: MyCB
+// CHECK:           Type: D3D_CT_CBUFFER
+// CHECK:           Size: 32
+// CHECK:           Num Variables: 2
+// CHECK:         {
+// CHECK:           ID3D12ShaderReflectionVariable:
+// CHECK:             D3D12_SHADER_VARIABLE_DESC: Name: cbval2
+// CHECK:               Size: 16
+// CHECK:               uFlags: 0x2
+// CHECK:             ID3D12ShaderReflectionType:
+// CHECK:               D3D12_SHADER_TYPE_DESC: Name: int4
+// CHECK:                 Class: D3D_SVC_VECTOR
+// CHECK:                 Type: D3D_SVT_INT
+// CHECK:                 Rows: 1
+// CHECK:                 Columns: 4
+// CHECK:             CBuffer: MyCB
+// CHECK:           ID3D12ShaderReflectionVariable:
+// CHECK:             D3D12_SHADER_VARIABLE_DESC: Name: cbval3
+// CHECK:               Size: 16
+// CHECK:               StartOffset: 16
+// CHECK:               uFlags: 0x2
+// CHECK:             ID3D12ShaderReflectionType:
+// CHECK:               D3D12_SHADER_TYPE_DESC: Name: int4
+// CHECK:                 Class: D3D_SVC_VECTOR
+// CHECK:                 Type: D3D_SVT_INT
+// CHECK:                 Rows: 1
+// CHECK:                 Columns: 4
+// CHECK:             CBuffer: MyCB
+// CHECK:         }
+// CHECK:     Bound Resources:
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: MyCB
+// CHECK:         Type: D3D_SIT_CBUFFER
+// CHECK:         uID: 1
+// CHECK:         BindPoint: 11
+// CHECK:         Space: 2
+// CHECK:         Dimension: D3D_SRV_DIMENSION_UNKNOWN
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: tex
+// CHECK:         Type: D3D_SIT_UAV_RWTYPED
+// CHECK:         uID: 0
+// CHECK:         BindPoint: 5
+// CHECK:         ReturnType: D3D_RETURN_TYPE_SINT
+// CHECK:         Dimension: D3D_SRV_DIMENSION_TEXTURE1D
+// CHECK:         uFlags: 0xc
+// CHECK:   ID3D12FunctionReflection:
+// CHECK:     D3D12_FUNCTION_DESC: Name: \01?function1@@YAMMF@Z
+// CHECK:       Shader Version: Library 6.3
+// CHECK:       ConstantBuffers: 1
+// CHECK:       BoundResources: 4
+// CHECK:     Constant Buffers:
+// CHECK:       ID3D12ShaderReflectionConstantBuffer:
+// CHECK:         D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:           Type: D3D_CT_CBUFFER
+// CHECK:           Size: 16
+// CHECK:           Num Variables: 1
+// CHECK:         {
+// CHECK:           ID3D12ShaderReflectionVariable:
+// CHECK:             D3D12_SHADER_VARIABLE_DESC: Name: cbval1
+// CHECK:               Size: 4
+// CHECK:               uFlags: 0x2
+// CHECK:             ID3D12ShaderReflectionType:
+// CHECK:               D3D12_SHADER_TYPE_DESC: Name: float
+// CHECK:                 Class: D3D_SVC_SCALAR
+// CHECK:                 Type: D3D_SVT_FLOAT
+// CHECK:                 Rows: 1
+// CHECK:                 Columns: 1
+// CHECK:             CBuffer: $Globals
+// CHECK:         }
+// CHECK:     Bound Resources:
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:         Type: D3D_SIT_CBUFFER
+// CHECK:         uID: 0
+// CHECK:         Dimension: D3D_SRV_DIMENSION_UNKNOWN
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: samp
+// CHECK:         Type: D3D_SIT_SAMPLER
+// CHECK:         uID: 0
+// CHECK:         BindPoint: 7
+// CHECK:         Dimension: D3D_SRV_DIMENSION_UNKNOWN
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: tex2
+// CHECK:         Type: D3D_SIT_TEXTURE
+// CHECK:         uID: 0
+// CHECK:         BindPoint: 0
+// CHECK:         ReturnType: D3D_RETURN_TYPE_FLOAT
+// CHECK:         Dimension: D3D_SRV_DIMENSION_TEXTURE1D
+// CHECK:         uFlags: 0xc
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: b_buf
+// CHECK:         Type: D3D_SIT_UAV_RWBYTEADDRESS
+// CHECK:         uID: 1
+// CHECK:         ReturnType: D3D_RETURN_TYPE_MIXED
+// CHECK:         Dimension: D3D_SRV_DIMENSION_BUFFER
+// CHECK:   ID3D12FunctionReflection:
+// CHECK:     D3D12_FUNCTION_DESC: Name: \01?function2@@YAMV?$vector@M$03@@@Z
+// CHECK:       Shader Version: Library 6.3
+// CHECK:       ConstantBuffers: 2
+// CHECK:       BoundResources: 2
+// CHECK:     Constant Buffers:
+// CHECK:       ID3D12ShaderReflectionConstantBuffer:
+// CHECK:         D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:           Type: D3D_CT_CBUFFER
+// CHECK:           Size: 16
+// CHECK:           Num Variables: 1
+// CHECK:         {
+// CHECK:           ID3D12ShaderReflectionVariable:
+// CHECK:             D3D12_SHADER_VARIABLE_DESC: Name: cbval1
+// CHECK:               Size: 4
+// CHECK:               uFlags: 0x2
+// CHECK:             ID3D12ShaderReflectionType:
+// CHECK:               D3D12_SHADER_TYPE_DESC: Name: float
+// CHECK:                 Class: D3D_SVC_SCALAR
+// CHECK:                 Type: D3D_SVT_FLOAT
+// CHECK:                 Rows: 1
+// CHECK:                 Columns: 1
+// CHECK:             CBuffer: $Globals
+// CHECK:         }
+// CHECK:       ID3D12ShaderReflectionConstantBuffer:
+// CHECK:         D3D12_SHADER_BUFFER_DESC: Name: MyCB
+// CHECK:           Type: D3D_CT_CBUFFER
+// CHECK:           Size: 32
+// CHECK:           Num Variables: 2
+// CHECK:         {
+// CHECK:           ID3D12ShaderReflectionVariable:
+// CHECK:             D3D12_SHADER_VARIABLE_DESC: Name: cbval2
+// CHECK:               Size: 16
+// CHECK:               uFlags: 0x2
+// CHECK:             ID3D12ShaderReflectionType:
+// CHECK:               D3D12_SHADER_TYPE_DESC: Name: int4
+// CHECK:                 Class: D3D_SVC_VECTOR
+// CHECK:                 Type: D3D_SVT_INT
+// CHECK:                 Rows: 1
+// CHECK:                 Columns: 4
+// CHECK:             CBuffer: MyCB
+// CHECK:           ID3D12ShaderReflectionVariable:
+// CHECK:             D3D12_SHADER_VARIABLE_DESC: Name: cbval3
+// CHECK:               Size: 16
+// CHECK:               StartOffset: 16
+// CHECK:               uFlags: 0x2
+// CHECK:             ID3D12ShaderReflectionType:
+// CHECK:               D3D12_SHADER_TYPE_DESC: Name: int4
+// CHECK:                 Class: D3D_SVC_VECTOR
+// CHECK:                 Type: D3D_SVT_INT
+// CHECK:                 Rows: 1
+// CHECK:                 Columns: 4
+// CHECK:             CBuffer: MyCB
+// CHECK:         }
+// CHECK:     Bound Resources:
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:         Type: D3D_SIT_CBUFFER
+// CHECK:         uID: 0
+// CHECK:         Dimension: D3D_SRV_DIMENSION_UNKNOWN
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: MyCB
+// CHECK:         Type: D3D_SIT_CBUFFER
+// CHECK:         uID: 1
+// CHECK:         BindPoint: 11
+// CHECK:         Space: 2
+// CHECK:         Dimension: D3D_SRV_DIMENSION_UNKNOWN
+// CHECK:   ID3D12FunctionReflection:
+// CHECK:     D3D12_FUNCTION_DESC: Name: function2
+// CHECK:       Shader Version: Vertex 6.3
+// CHECK:       ConstantBuffers: 2
+// CHECK:       BoundResources: 2
+// CHECK:     Constant Buffers:
+// CHECK:       ID3D12ShaderReflectionConstantBuffer:
+// CHECK:         D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:           Type: D3D_CT_CBUFFER
+// CHECK:           Size: 16
+// CHECK:           Num Variables: 1
+// CHECK:         {
+// CHECK:           ID3D12ShaderReflectionVariable:
+// CHECK:             D3D12_SHADER_VARIABLE_DESC: Name: cbval1
+// CHECK:               Size: 4
+// CHECK:               uFlags: 0x2
+// CHECK:             ID3D12ShaderReflectionType:
+// CHECK:               D3D12_SHADER_TYPE_DESC: Name: float
+// CHECK:                 Class: D3D_SVC_SCALAR
+// CHECK:                 Type: D3D_SVT_FLOAT
+// CHECK:                 Rows: 1
+// CHECK:                 Columns: 1
+// CHECK:             CBuffer: $Globals
+// CHECK:         }
+// CHECK:       ID3D12ShaderReflectionConstantBuffer:
+// CHECK:         D3D12_SHADER_BUFFER_DESC: Name: MyCB
+// CHECK:           Type: D3D_CT_CBUFFER
+// CHECK:           Size: 32
+// CHECK:           Num Variables: 2
+// CHECK:         {
+// CHECK:           ID3D12ShaderReflectionVariable:
+// CHECK:             D3D12_SHADER_VARIABLE_DESC: Name: cbval2
+// CHECK:               Size: 16
+// CHECK:               uFlags: 0x2
+// CHECK:             ID3D12ShaderReflectionType:
+// CHECK:               D3D12_SHADER_TYPE_DESC: Name: int4
+// CHECK:                 Class: D3D_SVC_VECTOR
+// CHECK:                 Type: D3D_SVT_INT
+// CHECK:                 Rows: 1
+// CHECK:                 Columns: 4
+// CHECK:             CBuffer: MyCB
+// CHECK:           ID3D12ShaderReflectionVariable:
+// CHECK:             D3D12_SHADER_VARIABLE_DESC: Name: cbval3
+// CHECK:               Size: 16
+// CHECK:               StartOffset: 16
+// CHECK:               uFlags: 0x2
+// CHECK:             ID3D12ShaderReflectionType:
+// CHECK:               D3D12_SHADER_TYPE_DESC: Name: int4
+// CHECK:                 Class: D3D_SVC_VECTOR
+// CHECK:                 Type: D3D_SVT_INT
+// CHECK:                 Rows: 1
+// CHECK:                 Columns: 4
+// CHECK:             CBuffer: MyCB
+// CHECK:         }
+// CHECK:     Bound Resources:
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: $Globals
+// CHECK:         Type: D3D_SIT_CBUFFER
+// CHECK:         uID: 0
+// CHECK:         Dimension: D3D_SRV_DIMENSION_UNKNOWN
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: MyCB
+// CHECK:         Type: D3D_SIT_CBUFFER
+// CHECK:         uID: 1
+// CHECK:         BindPoint: 11
+// CHECK:         Space: 2
+// CHECK:         Dimension: D3D_SRV_DIMENSION_UNKNOWN

+ 30 - 0
tools/clang/test/CodeGenHLSL/quick-test/d3dreflect/structured_buffer_getdim_stride.hlsl

@@ -0,0 +1,30 @@
+// RUN: %dxc -T lib_6_3 %s | %D3DReflect %s | FileCheck %s
+
+struct Foo
+{
+    float4 a;
+    uint b;
+};
+
+RWStructuredBuffer<Foo> g_buffer[2] : register(u0);
+
+uint UseBuf(int2 idx) {
+  return g_buffer[idx.x][idx.y].b;
+}
+
+// CHECK: ID3D12LibraryReflection:
+// CHECK:   D3D12_LIBRARY_DESC:
+// CHECK:     FunctionCount: 1
+// CHECK:   ID3D12FunctionReflection:
+// CHECK:     D3D12_FUNCTION_DESC: Name: \01?UseBuf@@YAIV?$vector@H$01@@@Z
+// CHECK:       Shader Version: Library 6.3
+// CHECK:       BoundResources: 1
+// CHECK:     Bound Resources:
+// CHECK:       D3D12_SHADER_BUFFER_DESC: Name: g_buffer
+// CHECK:         Type: D3D_SIT_UAV_RWSTRUCTURED
+// CHECK:         uID: 0
+// CHECK:         BindCount: 2
+// CHECK:         BindPoint: 0
+// CHECK:         ReturnType: D3D_RETURN_TYPE_MIXED
+// CHECK:         Dimension: D3D_SRV_DIMENSION_BUFFER
+// CHECK:         NumSamples (or stride): 40

+ 12 - 4
tools/clang/tools/dxcompiler/dxcdisassembler.cpp

@@ -676,10 +676,18 @@ void PrintStructLayout(StructType *ST, DxilTypeSystem &typeSys,
 
   unsigned fieldIndent = indent + 4;
 
-  for (unsigned i = 0; i < ST->getNumElements(); i++) {
-    PrintFieldLayout(ST->getElementType(i), annotation->GetFieldAnnotation(i),
-                     typeSys, OS, comment, offset, fieldIndent,
-                     offsetIndent - 4);
+  if (!annotation) {
+    if (!sizeOfStruct) {
+      (OS << comment).indent(indent) << "/* empty struct */\n";
+    } else {
+      (OS << comment).indent(indent) << "[" << sizeOfStruct << " x i8] (type annotation not present)\n";
+    }
+  } else {
+    for (unsigned i = 0; i < ST->getNumElements(); i++) {
+      PrintFieldLayout(ST->getElementType(i), annotation->GetFieldAnnotation(i),
+                       typeSys, OS, comment, offset, fieldIndent,
+                       offsetIndent - 4);
+    }
   }
   (OS << comment).indent(indent) << "\n";
   // The 2 in offsetIndent-indent-2 is for "} ".

+ 1 - 0
tools/clang/unittests/HLSL/CMakeLists.txt

@@ -31,6 +31,7 @@ add_clang_library(clang-hlsl-tests SHARED
   FunctionTest.cpp
   HLSLTestData.h
   HlslTestUtils.h
+  D3DReflectionDumper.cpp
   LinkerTest.cpp
   MSFileSysTest.cpp
   Objects.cpp

+ 623 - 0
tools/clang/unittests/HLSL/D3DReflectionDumper.cpp

@@ -0,0 +1,623 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// D3DReflectionDumper.cpp                                                   //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Use this to dump D3D Reflection data for testing.                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#include "dxc/Support/Global.h"
+#include "D3DReflectionDumper.h"
+#include "dxc/HLSL/DxilContainer.h"
+#include <sstream>
+
+// Copied from llvm/ADT/StringExtras.h
+static inline char hexdigit(unsigned X, bool LowerCase = false) {
+  const char HexChar = LowerCase ? 'a' : 'A';
+  return X < 10 ? '0' + X : HexChar + X - 10;
+}
+// Copied from lib/IR/AsmWriter.cpp
+// PrintEscapedString - Print each character of the specified string, escaping
+// it if it is not printable or if it is an escape char.
+static std::string EscapedString(const char *text) {
+  std::ostringstream ss;
+  size_t size = strlen(text);
+  for (unsigned i = 0, e = size; i != e; ++i) {
+    unsigned char C = text[i];
+    if (isprint(C) && C != '\\' && C != '"')
+      ss << C;
+    else
+      ss << '\\' << hexdigit(C >> 4) << hexdigit(C & 0x0F);
+  }
+  return ss.str();
+}
+
+LPCSTR ToString(D3D_CBUFFER_TYPE CBType) {
+  switch (CBType) {
+  case D3D_CT_CBUFFER: return "D3D_CT_CBUFFER";
+  case D3D_CT_TBUFFER: return "D3D_CT_TBUFFER";
+  case D3D_CT_INTERFACE_POINTERS: return "D3D_CT_INTERFACE_POINTERS";
+  case D3D_CT_RESOURCE_BIND_INFO: return "D3D_CT_RESOURCE_BIND_INFO";
+  default: return nullptr;
+  }
+}
+LPCSTR ToString(D3D_SHADER_INPUT_TYPE Type) {
+  switch (Type) {
+  case D3D_SIT_CBUFFER: return "D3D_SIT_CBUFFER";
+  case D3D_SIT_TBUFFER: return "D3D_SIT_TBUFFER";
+  case D3D_SIT_TEXTURE: return "D3D_SIT_TEXTURE";
+  case D3D_SIT_SAMPLER: return "D3D_SIT_SAMPLER";
+  case D3D_SIT_UAV_RWTYPED: return "D3D_SIT_UAV_RWTYPED";
+  case D3D_SIT_STRUCTURED: return "D3D_SIT_STRUCTURED";
+  case D3D_SIT_UAV_RWSTRUCTURED: return "D3D_SIT_UAV_RWSTRUCTURED";
+  case D3D_SIT_BYTEADDRESS: return "D3D_SIT_BYTEADDRESS";
+  case D3D_SIT_UAV_RWBYTEADDRESS: return "D3D_SIT_UAV_RWBYTEADDRESS";
+  case D3D_SIT_UAV_APPEND_STRUCTURED: return "D3D_SIT_UAV_APPEND_STRUCTURED";
+  case D3D_SIT_UAV_CONSUME_STRUCTURED: return "D3D_SIT_UAV_CONSUME_STRUCTURED";
+  case D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER: return "D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER";
+  default: return nullptr;
+  }
+}
+LPCSTR ToString(D3D_RESOURCE_RETURN_TYPE ReturnType) {
+  switch (ReturnType) {
+  case D3D_RETURN_TYPE_UNORM: return "D3D_RETURN_TYPE_UNORM";
+  case D3D_RETURN_TYPE_SNORM: return "D3D_RETURN_TYPE_SNORM";
+  case D3D_RETURN_TYPE_SINT: return "D3D_RETURN_TYPE_SINT";
+  case D3D_RETURN_TYPE_UINT: return "D3D_RETURN_TYPE_UINT";
+  case D3D_RETURN_TYPE_FLOAT: return "D3D_RETURN_TYPE_FLOAT";
+  case D3D_RETURN_TYPE_MIXED: return "D3D_RETURN_TYPE_MIXED";
+  case D3D_RETURN_TYPE_DOUBLE: return "D3D_RETURN_TYPE_DOUBLE";
+  case D3D_RETURN_TYPE_CONTINUED: return "D3D_RETURN_TYPE_CONTINUED";
+  default: return nullptr;
+  }
+}
+LPCSTR ToString(D3D_SRV_DIMENSION Dimension) {
+  switch (Dimension) {
+  case D3D_SRV_DIMENSION_UNKNOWN: return "D3D_SRV_DIMENSION_UNKNOWN";
+  case D3D_SRV_DIMENSION_BUFFER: return "D3D_SRV_DIMENSION_BUFFER";
+  case D3D_SRV_DIMENSION_TEXTURE1D: return "D3D_SRV_DIMENSION_TEXTURE1D";
+  case D3D_SRV_DIMENSION_TEXTURE1DARRAY: return "D3D_SRV_DIMENSION_TEXTURE1DARRAY";
+  case D3D_SRV_DIMENSION_TEXTURE2D: return "D3D_SRV_DIMENSION_TEXTURE2D";
+  case D3D_SRV_DIMENSION_TEXTURE2DARRAY: return "D3D_SRV_DIMENSION_TEXTURE2DARRAY";
+  case D3D_SRV_DIMENSION_TEXTURE2DMS: return "D3D_SRV_DIMENSION_TEXTURE2DMS";
+  case D3D_SRV_DIMENSION_TEXTURE2DMSARRAY: return "D3D_SRV_DIMENSION_TEXTURE2DMSARRAY";
+  case D3D_SRV_DIMENSION_TEXTURE3D: return "D3D_SRV_DIMENSION_TEXTURE3D";
+  case D3D_SRV_DIMENSION_TEXTURECUBE: return "D3D_SRV_DIMENSION_TEXTURECUBE";
+  case D3D_SRV_DIMENSION_TEXTURECUBEARRAY: return "D3D_SRV_DIMENSION_TEXTURECUBEARRAY";
+  case D3D_SRV_DIMENSION_BUFFEREX: return "D3D_SRV_DIMENSION_BUFFEREX";
+  default: return nullptr;
+  }
+}
+LPCSTR ToString(D3D_PRIMITIVE_TOPOLOGY GSOutputTopology) {
+  switch (GSOutputTopology) {
+  case D3D_PRIMITIVE_TOPOLOGY_UNDEFINED: return "D3D_PRIMITIVE_TOPOLOGY_UNDEFINED";
+  case D3D_PRIMITIVE_TOPOLOGY_POINTLIST: return "D3D_PRIMITIVE_TOPOLOGY_POINTLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_LINELIST: return "D3D_PRIMITIVE_TOPOLOGY_LINELIST";
+  case D3D_PRIMITIVE_TOPOLOGY_LINESTRIP: return "D3D_PRIMITIVE_TOPOLOGY_LINESTRIP";
+  case D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST: return "D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST";
+  case D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP: return "D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP";
+  case D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ: return "D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ";
+  case D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ: return "D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ";
+  case D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ: return "D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ";
+  case D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ: return "D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ";
+  case D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_31_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_31_CONTROL_POINT_PATCHLIST";
+  case D3D_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST: return "D3D_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST";
+  default: return nullptr;
+  }
+}
+LPCSTR ToString(D3D_PRIMITIVE InputPrimitive) {
+  switch (InputPrimitive) {
+  case D3D_PRIMITIVE_UNDEFINED: return "D3D_PRIMITIVE_UNDEFINED";
+  case D3D_PRIMITIVE_POINT: return "D3D_PRIMITIVE_POINT";
+  case D3D_PRIMITIVE_LINE: return "D3D_PRIMITIVE_LINE";
+  case D3D_PRIMITIVE_TRIANGLE: return "D3D_PRIMITIVE_TRIANGLE";
+  case D3D_PRIMITIVE_LINE_ADJ: return "D3D_PRIMITIVE_LINE_ADJ";
+  case D3D_PRIMITIVE_TRIANGLE_ADJ: return "D3D_PRIMITIVE_TRIANGLE_ADJ";
+  case D3D_PRIMITIVE_1_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_1_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_2_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_2_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_3_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_3_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_4_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_4_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_5_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_5_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_6_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_6_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_7_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_7_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_8_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_8_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_9_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_9_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_10_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_10_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_11_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_11_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_12_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_12_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_13_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_13_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_14_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_14_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_15_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_15_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_16_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_16_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_17_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_17_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_18_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_18_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_19_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_19_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_20_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_20_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_21_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_21_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_22_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_22_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_23_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_23_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_24_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_24_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_25_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_25_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_26_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_26_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_27_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_27_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_28_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_28_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_29_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_29_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_30_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_30_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_31_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_31_CONTROL_POINT_PATCH";
+  case D3D_PRIMITIVE_32_CONTROL_POINT_PATCH: return "D3D_PRIMITIVE_32_CONTROL_POINT_PATCH";
+  default: return nullptr;
+  }
+}
+LPCSTR ToString(D3D_TESSELLATOR_OUTPUT_PRIMITIVE HSOutputPrimitive) {
+  switch (HSOutputPrimitive) {
+  case D3D_TESSELLATOR_OUTPUT_UNDEFINED: return "D3D_TESSELLATOR_OUTPUT_UNDEFINED";
+  case D3D_TESSELLATOR_OUTPUT_POINT: return "D3D_TESSELLATOR_OUTPUT_POINT";
+  case D3D_TESSELLATOR_OUTPUT_LINE: return "D3D_TESSELLATOR_OUTPUT_LINE";
+  case D3D_TESSELLATOR_OUTPUT_TRIANGLE_CW: return "D3D_TESSELLATOR_OUTPUT_TRIANGLE_CW";
+  case D3D_TESSELLATOR_OUTPUT_TRIANGLE_CCW: return "D3D_TESSELLATOR_OUTPUT_TRIANGLE_CCW";
+  default: return nullptr;
+  }
+}
+LPCSTR ToString(D3D_TESSELLATOR_PARTITIONING HSPartitioning) {
+  switch (HSPartitioning) {
+  case D3D_TESSELLATOR_PARTITIONING_UNDEFINED: return "D3D_TESSELLATOR_PARTITIONING_UNDEFINED";
+  case D3D_TESSELLATOR_PARTITIONING_INTEGER: return "D3D_TESSELLATOR_PARTITIONING_INTEGER";
+  case D3D_TESSELLATOR_PARTITIONING_POW2: return "D3D_TESSELLATOR_PARTITIONING_POW2";
+  case D3D_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD: return "D3D_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD";
+  case D3D_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN: return "D3D_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN";
+  default: return nullptr;
+  }
+}
+LPCSTR ToString(D3D_TESSELLATOR_DOMAIN TessellatorDomain) {
+  switch (TessellatorDomain) {
+  case D3D_TESSELLATOR_DOMAIN_UNDEFINED: return "D3D_TESSELLATOR_DOMAIN_UNDEFINED";
+  case D3D_TESSELLATOR_DOMAIN_ISOLINE: return "D3D_TESSELLATOR_DOMAIN_ISOLINE";
+  case D3D_TESSELLATOR_DOMAIN_TRI: return "D3D_TESSELLATOR_DOMAIN_TRI";
+  case D3D_TESSELLATOR_DOMAIN_QUAD: return "D3D_TESSELLATOR_DOMAIN_QUAD";
+  default: return nullptr;
+  }
+}
+LPCSTR ToString(D3D_SHADER_VARIABLE_CLASS Class) {
+  switch (Class) {
+  case D3D_SVC_SCALAR: return "D3D_SVC_SCALAR";
+  case D3D_SVC_VECTOR: return "D3D_SVC_VECTOR";
+  case D3D_SVC_MATRIX_ROWS: return "D3D_SVC_MATRIX_ROWS";
+  case D3D_SVC_MATRIX_COLUMNS: return "D3D_SVC_MATRIX_COLUMNS";
+  case D3D_SVC_OBJECT: return "D3D_SVC_OBJECT";
+  case D3D_SVC_STRUCT: return "D3D_SVC_STRUCT";
+  case D3D_SVC_INTERFACE_CLASS: return "D3D_SVC_INTERFACE_CLASS";
+  case D3D_SVC_INTERFACE_POINTER: return "D3D_SVC_INTERFACE_POINTER";
+  default: return nullptr;
+  }
+}
+LPCSTR ToString(D3D_SHADER_VARIABLE_TYPE Type) {
+  switch (Type) {
+  case D3D_SVT_VOID: return "D3D_SVT_VOID";
+  case D3D_SVT_BOOL: return "D3D_SVT_BOOL";
+  case D3D_SVT_INT: return "D3D_SVT_INT";
+  case D3D_SVT_FLOAT: return "D3D_SVT_FLOAT";
+  case D3D_SVT_STRING: return "D3D_SVT_STRING";
+  case D3D_SVT_TEXTURE: return "D3D_SVT_TEXTURE";
+  case D3D_SVT_TEXTURE1D: return "D3D_SVT_TEXTURE1D";
+  case D3D_SVT_TEXTURE2D: return "D3D_SVT_TEXTURE2D";
+  case D3D_SVT_TEXTURE3D: return "D3D_SVT_TEXTURE3D";
+  case D3D_SVT_TEXTURECUBE: return "D3D_SVT_TEXTURECUBE";
+  case D3D_SVT_SAMPLER: return "D3D_SVT_SAMPLER";
+  case D3D_SVT_SAMPLER1D: return "D3D_SVT_SAMPLER1D";
+  case D3D_SVT_SAMPLER2D: return "D3D_SVT_SAMPLER2D";
+  case D3D_SVT_SAMPLER3D: return "D3D_SVT_SAMPLER3D";
+  case D3D_SVT_SAMPLERCUBE: return "D3D_SVT_SAMPLERCUBE";
+  case D3D_SVT_PIXELSHADER: return "D3D_SVT_PIXELSHADER";
+  case D3D_SVT_VERTEXSHADER: return "D3D_SVT_VERTEXSHADER";
+  case D3D_SVT_PIXELFRAGMENT: return "D3D_SVT_PIXELFRAGMENT";
+  case D3D_SVT_VERTEXFRAGMENT: return "D3D_SVT_VERTEXFRAGMENT";
+  case D3D_SVT_UINT: return "D3D_SVT_UINT";
+  case D3D_SVT_UINT8: return "D3D_SVT_UINT8";
+  case D3D_SVT_GEOMETRYSHADER: return "D3D_SVT_GEOMETRYSHADER";
+  case D3D_SVT_RASTERIZER: return "D3D_SVT_RASTERIZER";
+  case D3D_SVT_DEPTHSTENCIL: return "D3D_SVT_DEPTHSTENCIL";
+  case D3D_SVT_BLEND: return "D3D_SVT_BLEND";
+  case D3D_SVT_BUFFER: return "D3D_SVT_BUFFER";
+  case D3D_SVT_CBUFFER: return "D3D_SVT_CBUFFER";
+  case D3D_SVT_TBUFFER: return "D3D_SVT_TBUFFER";
+  case D3D_SVT_TEXTURE1DARRAY: return "D3D_SVT_TEXTURE1DARRAY";
+  case D3D_SVT_TEXTURE2DARRAY: return "D3D_SVT_TEXTURE2DARRAY";
+  case D3D_SVT_RENDERTARGETVIEW: return "D3D_SVT_RENDERTARGETVIEW";
+  case D3D_SVT_DEPTHSTENCILVIEW: return "D3D_SVT_DEPTHSTENCILVIEW";
+  case D3D_SVT_TEXTURE2DMS: return "D3D_SVT_TEXTURE2DMS";
+  case D3D_SVT_TEXTURE2DMSARRAY: return "D3D_SVT_TEXTURE2DMSARRAY";
+  case D3D_SVT_TEXTURECUBEARRAY: return "D3D_SVT_TEXTURECUBEARRAY";
+  case D3D_SVT_HULLSHADER: return "D3D_SVT_HULLSHADER";
+  case D3D_SVT_DOMAINSHADER: return "D3D_SVT_DOMAINSHADER";
+  case D3D_SVT_INTERFACE_POINTER: return "D3D_SVT_INTERFACE_POINTER";
+  case D3D_SVT_COMPUTESHADER: return "D3D_SVT_COMPUTESHADER";
+  case D3D_SVT_DOUBLE: return "D3D_SVT_DOUBLE";
+  case D3D_SVT_RWTEXTURE1D: return "D3D_SVT_RWTEXTURE1D";
+  case D3D_SVT_RWTEXTURE1DARRAY: return "D3D_SVT_RWTEXTURE1DARRAY";
+  case D3D_SVT_RWTEXTURE2D: return "D3D_SVT_RWTEXTURE2D";
+  case D3D_SVT_RWTEXTURE2DARRAY: return "D3D_SVT_RWTEXTURE2DARRAY";
+  case D3D_SVT_RWTEXTURE3D: return "D3D_SVT_RWTEXTURE3D";
+  case D3D_SVT_RWBUFFER: return "D3D_SVT_RWBUFFER";
+  case D3D_SVT_BYTEADDRESS_BUFFER: return "D3D_SVT_BYTEADDRESS_BUFFER";
+  case D3D_SVT_RWBYTEADDRESS_BUFFER: return "D3D_SVT_RWBYTEADDRESS_BUFFER";
+  case D3D_SVT_STRUCTURED_BUFFER: return "D3D_SVT_STRUCTURED_BUFFER";
+  case D3D_SVT_RWSTRUCTURED_BUFFER: return "D3D_SVT_RWSTRUCTURED_BUFFER";
+  case D3D_SVT_APPEND_STRUCTURED_BUFFER: return "D3D_SVT_APPEND_STRUCTURED_BUFFER";
+  case D3D_SVT_CONSUME_STRUCTURED_BUFFER: return "D3D_SVT_CONSUME_STRUCTURED_BUFFER";
+  case D3D_SVT_MIN8FLOAT: return "D3D_SVT_MIN8FLOAT";
+  case D3D_SVT_MIN10FLOAT: return "D3D_SVT_MIN10FLOAT";
+  case D3D_SVT_MIN16FLOAT: return "D3D_SVT_MIN16FLOAT";
+  case D3D_SVT_MIN12INT: return "D3D_SVT_MIN12INT";
+  case D3D_SVT_MIN16INT: return "D3D_SVT_MIN16INT";
+  case D3D_SVT_MIN16UINT: return "D3D_SVT_MIN16UINT";
+  default: return nullptr;
+  }
+}
+
+void D3DReflectionDumper::DumpDefaultValue(LPCVOID pDefaultValue, UINT Size) {
+  DXASSERT_NOMSG(pDefaultValue);
+  WriteLn("DefaultValue present.");    // TODO: Dump DefaultValue
+}
+void D3DReflectionDumper::DumpShaderVersion(UINT Version) {
+  const char *szType = "<unknown>";
+  UINT Type = D3D12_SHVER_GET_TYPE(Version);
+  switch (Type) {
+  case (UINT)hlsl::DXIL::ShaderKind::Pixel: szType = "Pixel"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::Vertex: szType = "Vertex"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::Geometry: szType = "Geometry"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::Hull: szType = "Hull"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::Domain: szType = "Domain"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::Compute: szType = "Compute"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::Library: szType = "Library"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::RayGeneration: szType = "RayGeneration"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::Intersection: szType = "Intersection"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::AnyHit: szType = "AnyHit"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::ClosestHit: szType = "ClosestHit"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::Miss: szType = "Miss"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::Callable: szType = "Callable"; break;
+  case (UINT)hlsl::DXIL::ShaderKind::Invalid: szType = "Invalid"; break;
+  }
+  UINT Major = D3D12_SHVER_GET_MAJOR(Version);
+  UINT Minor = D3D12_SHVER_GET_MINOR(Version);
+  WriteLn("Shader Version: ", szType, " ", Major, ".", Minor);
+}
+
+void D3DReflectionDumper::Dump(D3D12_SHADER_TYPE_DESC &tyDesc) {
+  SetLastName(tyDesc.Name);
+  WriteLn("D3D12_SHADER_TYPE_DESC: Name: ", m_LastName);
+  Indent();
+  DumpEnum("Class", tyDesc.Class);
+  DumpEnum("Type", tyDesc.Type);
+  if (tyDesc.Elements)  WriteLn("Elements: ", tyDesc.Elements);
+  if (tyDesc.Rows)      WriteLn("Rows: ", tyDesc.Rows);
+  if (tyDesc.Columns)   WriteLn("Columns: ", tyDesc.Columns);
+  if (tyDesc.Members)   WriteLn("Members: ", tyDesc.Members);
+  if (tyDesc.Offset)    WriteLn("Offset: ", tyDesc.Offset);
+  Dedent();
+}
+void D3DReflectionDumper::Dump(D3D12_SHADER_VARIABLE_DESC &varDesc) {
+  SetLastName(varDesc.Name);
+  WriteLn("D3D12_SHADER_VARIABLE_DESC: Name: ", m_LastName);
+  Indent();
+  if (varDesc.Size)         WriteLn("Size: ", varDesc.Size);
+  if (varDesc.StartOffset)  WriteLn("StartOffset: ", varDesc.StartOffset);
+  if (varDesc.uFlags)       WriteLn("uFlags: ", std::hex, std::showbase, varDesc.uFlags);
+  if (varDesc.DefaultValue) DumpDefaultValue(varDesc.DefaultValue, varDesc.Size);
+  Dedent();
+}
+void D3DReflectionDumper::Dump(D3D12_SHADER_BUFFER_DESC &Desc) {
+  SetLastName(Desc.Name);
+  WriteLn("D3D12_SHADER_BUFFER_DESC: Name: ", m_LastName);
+  Indent();
+  DumpEnum("Type", Desc.Type);
+  WriteLn("Size: ", Desc.Size);
+  if (Desc.uFlags)      WriteLn("uFlags: ", std::hex, std::showbase, Desc.uFlags);
+  if (Desc.Variables)   WriteLn("Num Variables: ", Desc.Variables);
+  Dedent();
+}
+void D3DReflectionDumper::Dump(D3D12_SHADER_INPUT_BIND_DESC &resDesc) {
+  SetLastName(resDesc.Name);
+  WriteLn("D3D12_SHADER_BUFFER_DESC: Name: ", m_LastName);
+  Indent();
+  DumpEnum("Type", resDesc.Type);
+  WriteLn("uID: ", resDesc.uID);
+  if (resDesc.BindCount != 1)         WriteLn("BindCount: ", resDesc.BindCount);
+  if (resDesc.BindPoint != UINT_MAX)  WriteLn("BindPoint: ", resDesc.BindPoint);
+  if (resDesc.Space)                  WriteLn("Space: ", resDesc.Space);
+  if (resDesc.ReturnType)             DumpEnum("ReturnType", resDesc.ReturnType);
+  DumpEnum("Dimension", resDesc.Dimension);
+  if (resDesc.NumSamples && resDesc.NumSamples != 4294967295)
+    WriteLn("NumSamples (or stride): ", resDesc.NumSamples);
+  if (resDesc.uFlags)                 WriteLn("uFlags: ", std::hex, std::showbase, resDesc.uFlags);
+  Dedent();
+}
+void D3DReflectionDumper::Dump(D3D12_SHADER_DESC &Desc) {
+  WriteLn("D3D12_SHADER_BUFFER_DESC:");
+  Indent();
+  DumpShaderVersion(Desc.Version);
+  if (Desc.Creator)           WriteLn("Creator: ", Desc.Creator);
+  if (Desc.Flags)             WriteLn("Flags: ", std::hex, std::showbase, Desc.Flags);
+  if (Desc.ConstantBuffers)   WriteLn("ConstantBuffers: ", Desc.ConstantBuffers);
+  if (Desc.BoundResources)    WriteLn("BoundResources: ", Desc.BoundResources);
+  if (Desc.InputParameters)   WriteLn("InputParameters: ", Desc.InputParameters);
+  if (Desc.OutputParameters)  WriteLn("OutputParameters: ", Desc.OutputParameters);
+  hlsl::DXIL::ShaderKind ShaderKind = (hlsl::DXIL::ShaderKind)D3D12_SHVER_GET_TYPE(Desc.Version);
+  if (ShaderKind == hlsl::DXIL::ShaderKind::Geometry) {
+    WriteLn("cGSInstanceCount: ", Desc.cGSInstanceCount);
+    WriteLn("GSMaxOutputVertexCount: ", Desc.GSMaxOutputVertexCount);
+    DumpEnum("GSOutputTopology", Desc.GSOutputTopology);
+    DumpEnum("InputPrimitive", Desc.InputPrimitive);
+  }
+  if (ShaderKind == hlsl::DXIL::ShaderKind::Hull) {
+    WriteLn("PatchConstantParameters: ", Desc.PatchConstantParameters);
+    WriteLn("cControlPoints: ", Desc.cControlPoints);
+    DumpEnum("InputPrimitive", Desc.InputPrimitive);
+    DumpEnum("HSOutputPrimitive", Desc.HSOutputPrimitive);
+    DumpEnum("HSPartitioning", Desc.HSPartitioning);
+    DumpEnum("TessellatorDomain", Desc.TessellatorDomain);
+  }
+  if (ShaderKind == hlsl::DXIL::ShaderKind::Domain) {
+    WriteLn("PatchConstantParameters: ", Desc.PatchConstantParameters);
+    WriteLn("cControlPoints: ", Desc.cControlPoints);
+    DumpEnum("TessellatorDomain", Desc.TessellatorDomain);
+  }
+  // TODO
+  Dedent();
+}
+void D3DReflectionDumper::Dump(D3D12_FUNCTION_DESC &Desc) {
+  SetLastName(Desc.Name);
+  WriteLn("D3D12_FUNCTION_DESC: Name: ", EscapedString(m_LastName));
+  Indent();
+  DumpShaderVersion(Desc.Version);
+  if (Desc.Creator)                 WriteLn("Creator: ", Desc.Creator);
+  if (Desc.Flags)                   WriteLn("Flags: ", std::hex, std::showbase, Desc.Flags);
+  if (Desc.ConstantBuffers)         WriteLn("ConstantBuffers: ", Desc.ConstantBuffers);
+  if (Desc.BoundResources)          WriteLn("BoundResources: ", Desc.BoundResources);
+  if (Desc.FunctionParameterCount)  WriteLn("FunctionParameterCount: ", Desc.FunctionParameterCount);
+  if (Desc.HasReturn)               WriteLn("HasReturn: TRUE");
+  Dedent();
+}
+void D3DReflectionDumper::Dump(D3D12_LIBRARY_DESC &Desc) {
+  WriteLn("D3D12_LIBRARY_DESC:");
+  Indent();
+  if (Desc.Creator) WriteLn("Creator: ", Desc.Creator);
+  if (Desc.Flags)   WriteLn("Flags: ", std::hex, std::showbase, Desc.Flags);
+  WriteLn("FunctionCount: ", Desc.FunctionCount);
+  Dedent();
+}
+
+void D3DReflectionDumper::Dump(ID3D12ShaderReflectionType *pType) {
+  WriteLn("ID3D12ShaderReflectionType:");
+  Indent();
+  D3D12_SHADER_TYPE_DESC tyDesc;
+  if (!pType || FAILED(pType->GetDesc(&tyDesc))) {
+    Failure("GetDesc");
+    Dedent();
+    return;
+  }
+  Dump(tyDesc);
+  if (tyDesc.Members) {
+    WriteLn("{");
+    Indent();
+    for (UINT uMember = 0; uMember < tyDesc.Members; uMember++) {
+      Dump(pType->GetMemberTypeByIndex(uMember));
+    }
+    Dedent();
+    WriteLn("}");
+  }
+  Dedent();
+}
+void D3DReflectionDumper::Dump(ID3D12ShaderReflectionVariable *pVar) {
+  WriteLn("ID3D12ShaderReflectionVariable:");
+  Indent();
+  D3D12_SHADER_VARIABLE_DESC varDesc;
+  if (!pVar || FAILED(pVar->GetDesc(&varDesc))) {
+    Failure("GetDesc");
+    Dedent();
+    return;
+  }
+  Dump(varDesc);
+  Dump(pVar->GetType());
+  ID3D12ShaderReflectionConstantBuffer* pCB = pVar->GetBuffer();
+  D3D12_SHADER_BUFFER_DESC CBDesc;
+  if (pCB && SUCCEEDED(pCB->GetDesc(&CBDesc))) {
+    WriteLn("CBuffer: ", CBDesc.Name);
+  }
+  Dedent();
+}
+
+void D3DReflectionDumper::Dump(ID3D12ShaderReflectionConstantBuffer *pCBReflection) {
+  WriteLn("ID3D12ShaderReflectionConstantBuffer:");
+  Indent();
+  D3D12_SHADER_BUFFER_DESC Desc;
+  if (!pCBReflection || FAILED(pCBReflection->GetDesc(&Desc))) {
+    Failure("GetDesc");
+    Dedent();
+    return;
+  }
+  Dump(Desc);
+  if (Desc.Variables) {
+    WriteLn("{");
+    Indent();
+    bool bCheckByNameFailed = false;
+    for (UINT uVar = 0; uVar < Desc.Variables; uVar++) {
+      if (m_bCheckByName)
+        SetLastName();
+      ID3D12ShaderReflectionVariable *pVar = pCBReflection->GetVariableByIndex(uVar);
+      Dump(pVar);
+      if (m_bCheckByName) {
+        if (pCBReflection->GetVariableByName(m_LastName) != pVar) {
+          bCheckByNameFailed = true;
+          Failure("GetVariableByName ", m_LastName);
+        }
+      }
+    }
+    if (m_bCheckByName && !bCheckByNameFailed) {
+      WriteLn("GetVariableByName checks succeeded.");
+    }
+    Dedent();
+    WriteLn("}");
+  }
+  Dedent();
+}
+
+void D3DReflectionDumper::Dump(ID3D12ShaderReflection *pShaderReflection) {
+  WriteLn("ID3D12ShaderReflection:");
+  Indent();
+  D3D12_SHADER_DESC Desc;
+  if (!pShaderReflection || FAILED(pShaderReflection->GetDesc(&Desc))) {
+    Failure("GetDesc");
+    Dedent();
+    return;
+  }
+  Dump(Desc);
+  if (Desc.ConstantBuffers) {
+    WriteLn("Constant Buffers:");
+    Indent();
+    bool bCheckByNameFailed = false;
+    for (UINT uCB = 0; uCB < Desc.ConstantBuffers; uCB++) {
+      ID3D12ShaderReflectionConstantBuffer *pCB = pShaderReflection->GetConstantBufferByIndex(uCB);
+      Dump(pCB);
+      if (m_bCheckByName && m_LastName) {
+        if (pShaderReflection->GetConstantBufferByName(m_LastName) != pCB) {
+          bCheckByNameFailed = true;
+          Failure("GetConstantBufferByName ", m_LastName);
+        }
+      }
+    }
+    if (m_bCheckByName && !bCheckByNameFailed) {
+      WriteLn("GetConstantBufferByName checks succeeded.");
+    }
+    Dedent();
+  }
+  if (Desc.BoundResources) {
+    WriteLn("Bound Resources:");
+    Indent();
+    bool bCheckByNameFailed = false;
+    for (UINT uRes = 0; uRes < Desc.BoundResources; uRes++) {
+      D3D12_SHADER_INPUT_BIND_DESC bindDesc;
+      if (FAILED(pShaderReflection->GetResourceBindingDesc(uRes, &bindDesc))) {
+      }
+      Dump(bindDesc);
+      if (m_bCheckByName && bindDesc.Name) {
+        D3D12_SHADER_INPUT_BIND_DESC bindDesc2;
+        if (FAILED(pShaderReflection->GetResourceBindingDescByName(bindDesc.Name, &bindDesc2)) || bindDesc2.Name != bindDesc.Name) {
+          bCheckByNameFailed = true;
+          Failure("GetResourceBindingDescByName ", bindDesc.Name);
+        }
+      }
+    }
+    if (m_bCheckByName && !bCheckByNameFailed) {
+      WriteLn("GetResourceBindingDescByName checks succeeded.");
+    }
+    Dedent();
+  }
+  // TODO
+  Dedent();
+}
+
+void D3DReflectionDumper::Dump(ID3D12FunctionReflection *pFunctionReflection) {
+  WriteLn("ID3D12FunctionReflection:");
+  Indent();
+  D3D12_FUNCTION_DESC Desc;
+  if (!pFunctionReflection || FAILED(pFunctionReflection->GetDesc(&Desc))) {
+    Failure("GetDesc");
+    Dedent();
+    return;
+  }
+  Dump(Desc);
+  if (Desc.ConstantBuffers) {
+    WriteLn("Constant Buffers:");
+    Indent();
+    bool bCheckByNameFailed = false;
+    for (UINT uCB = 0; uCB < Desc.ConstantBuffers; uCB++) {
+      ID3D12ShaderReflectionConstantBuffer *pCB = pFunctionReflection->GetConstantBufferByIndex(uCB);
+      Dump(pCB);
+      if (m_bCheckByName && m_LastName) {
+        if (pFunctionReflection->GetConstantBufferByName(m_LastName) != pCB) {
+          bCheckByNameFailed = true;
+          Failure("GetConstantBufferByName ", m_LastName);
+        }
+      }
+    }
+    if (m_bCheckByName && !bCheckByNameFailed) {
+      WriteLn("GetConstantBufferByName checks succeeded.");
+    }
+    Dedent();
+  }
+  if (Desc.BoundResources) {
+    WriteLn("Bound Resources:");
+    Indent();
+    bool bCheckByNameFailed = false;
+    for (UINT uRes = 0; uRes < Desc.BoundResources; uRes++) {
+      D3D12_SHADER_INPUT_BIND_DESC bindDesc;
+      if (FAILED(pFunctionReflection->GetResourceBindingDesc(uRes, &bindDesc))) {
+      }
+      Dump(bindDesc);
+      if (m_bCheckByName && bindDesc.Name) {
+        D3D12_SHADER_INPUT_BIND_DESC bindDesc2;
+        if (FAILED(pFunctionReflection->GetResourceBindingDescByName(bindDesc.Name, &bindDesc2)) || bindDesc2.Name != bindDesc.Name) {
+          bCheckByNameFailed = true;
+          Failure("GetResourceBindingDescByName ", bindDesc.Name);
+        }
+      }
+    }
+    if (m_bCheckByName && !bCheckByNameFailed) {
+      WriteLn("GetResourceBindingDescByName checks succeeded.");
+    }
+    Dedent();
+  }
+  // TODO
+  Dedent();
+}
+
+void D3DReflectionDumper::Dump(ID3D12LibraryReflection *pLibraryReflection) {
+  WriteLn("ID3D12LibraryReflection:");
+  Indent();
+  D3D12_LIBRARY_DESC Desc;
+  if (!pLibraryReflection || FAILED(pLibraryReflection->GetDesc(&Desc))) {
+    Failure("GetDesc");
+    Dedent();
+    return;
+  }
+  Dump(Desc);
+  if (Desc.FunctionCount) {
+    for (UINT uFunc = 0; uFunc < Desc.FunctionCount; uFunc++)
+      Dump(pLibraryReflection->GetFunctionByIndex((INT)uFunc));
+  }
+  Dedent();
+}
+

+ 118 - 0
tools/clang/unittests/HLSL/D3DReflectionDumper.h

@@ -0,0 +1,118 @@
+///////////////////////////////////////////////////////////////////////////////
+//                                                                           //
+// D3DReflectionDumper.h                                                     //
+// Copyright (C) Microsoft Corporation. All rights reserved.                 //
+// This file is distributed under the University of Illinois Open Source     //
+// License. See LICENSE.TXT for details.                                     //
+//                                                                           //
+// Use this to dump D3D Reflection data for testing.                         //
+//                                                                           //
+///////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "dxc/Support/Global.h"
+#include <algorithm>
+#include <string>
+#include <ostream>
+#include <iomanip>
+#include "dxc/Support/WinIncludes.h"
+#include <d3d12shader.h>
+#include "dxc/HLSL/DxilContainer.h"
+
+LPCSTR ToString(D3D_CBUFFER_TYPE CBType);
+LPCSTR ToString(D3D_SHADER_INPUT_TYPE Type);
+LPCSTR ToString(D3D_RESOURCE_RETURN_TYPE ReturnType);
+LPCSTR ToString(D3D_SRV_DIMENSION Dimension);
+LPCSTR ToString(D3D_PRIMITIVE_TOPOLOGY GSOutputTopology);
+LPCSTR ToString(D3D_PRIMITIVE InputPrimitive);
+LPCSTR ToString(D3D_TESSELLATOR_OUTPUT_PRIMITIVE HSOutputPrimitive);
+LPCSTR ToString(D3D_TESSELLATOR_PARTITIONING HSPartitioning);
+LPCSTR ToString(D3D_TESSELLATOR_DOMAIN TessellatorDomain);
+LPCSTR ToString(D3D_SHADER_VARIABLE_CLASS Class);
+LPCSTR ToString(D3D_SHADER_VARIABLE_TYPE Type);
+
+class DumperBase {
+private:
+  std::ostream &m_out;
+  unsigned m_indent = 0;
+  bool m_bCheckByName = false;
+  std::ostream &DoIndent() {
+    return m_out << std::setfill(' ')
+      << std::setw(std::min(m_indent * 2, (unsigned)32))
+      << "";
+  }
+
+public:
+  DumperBase(std::ostream &outStream) : m_out(outStream) {}
+
+  void Indent() { if (m_indent < (1 << 30)) m_indent++; }
+  void Dedent() { if (m_indent > 0) m_indent--; }
+
+  template<typename _T>
+  std::ostream &Write(std::ostream &out, _T t) {
+    return out << t;
+  }
+  template<typename _T, typename... Args>
+  std::ostream &Write(std::ostream &out, _T t, Args... args) {
+    return Write(out << t, args...);
+  }
+
+  template<typename _T>
+  std::ostream &WriteLn(_T t) {
+    return Write(DoIndent(), t) << std::endl
+      << std::resetiosflags(std::ios_base::basefield | std::ios_base::showbase);
+  }
+  template<typename _T, typename... Args>
+  std::ostream &WriteLn(_T t, Args... args) {
+    return Write(Write(DoIndent(), t), args...) << std::endl
+      << std::resetiosflags(std::ios_base::basefield | std::ios_base::showbase);
+  }
+
+  template<typename _T>
+  void DumpEnum(const char *Name, _T eValue) {
+    LPCSTR szValue = ToString(eValue);
+    if (szValue)
+      WriteLn(Name, ": ", szValue);
+    else
+      WriteLn(Name, ": <unknown: ", std::hex, std::showbase, (UINT)eValue, ">");
+  }
+
+  template<typename... Args>
+  void Failure(Args... args) {
+    WriteLn("Failed: ", args...);
+  }
+
+};
+
+class D3DReflectionDumper : public DumperBase {
+private:
+  bool m_bCheckByName = false;
+  const char *m_LastName = nullptr;
+  void SetLastName(const char *Name = nullptr) { m_LastName = Name ? Name : "<nullptr>"; }
+
+public:
+  D3DReflectionDumper(std::ostream &outStream) : DumperBase(outStream) {}
+  void SetCheckByName(bool bCheckByName) { m_bCheckByName = bCheckByName; }
+
+  void DumpShaderVersion(UINT Version);
+  void DumpDefaultValue(LPCVOID pDefaultValue, UINT Size);
+
+  void Dump(D3D12_SHADER_TYPE_DESC &tyDesc);
+  void Dump(D3D12_SHADER_VARIABLE_DESC &varDesc);
+  void Dump(D3D12_SHADER_BUFFER_DESC &Desc);
+  void Dump(D3D12_SHADER_INPUT_BIND_DESC &resDesc);
+  void Dump(D3D12_SHADER_DESC &Desc);
+  void Dump(D3D12_FUNCTION_DESC &Desc);
+  void Dump(D3D12_LIBRARY_DESC &Desc);
+
+  void Dump(ID3D12ShaderReflectionType *pType);
+  void Dump(ID3D12ShaderReflectionVariable *pVar);
+
+  void Dump(ID3D12ShaderReflectionConstantBuffer *pCBReflection);
+
+  void Dump(ID3D12ShaderReflection *pShaderReflection);
+  void Dump(ID3D12FunctionReflection *pFunctionReflection);
+  void Dump(ID3D12LibraryReflection *pLibraryReflection);
+
+};

+ 3 - 0
tools/clang/unittests/HLSL/DxcTestUtils.h

@@ -9,6 +9,8 @@
 //                                                                           //
 ///////////////////////////////////////////////////////////////////////////////
 
+#pragma once
+
 #include <string>
 #include <vector>
 #include "dxc/dxcapi.h"
@@ -58,6 +60,7 @@ private:
   void RunDxc(const FileRunCommandPart *Prior);
   void RunDxv(const FileRunCommandPart *Prior);
   void RunOpt(const FileRunCommandPart *Prior);
+  void RunD3DReflect(const FileRunCommandPart *Prior);
   void RunTee(const FileRunCommandPart *Prior);
 public:
   FileRunCommandPart(const FileRunCommandPart&) = default;

+ 90 - 0
tools/clang/unittests/HLSL/FileCheckerTest.cpp

@@ -32,6 +32,10 @@
 #include "dxc/Support/dxcapi.use.h"
 #include "dxc/Support/HLSLOptions.h"
 #include "dxc/Support/Unicode.h"
+#include "dxc/HLSL/DxilContainer.h"
+#include "D3DReflectionDumper.h"
+
+#include "d3d12shader.h"
 
 using namespace std;
 using namespace hlsl_test;
@@ -105,6 +109,9 @@ static string trim(string value) {
       else if (0 == _stricmp(Command.c_str(), "%opt")) {
         RunOpt(Prior);
       }
+      else if (0 == _stricmp(Command.c_str(), "%D3DReflect")) {
+        RunD3DReflect(Prior);
+      }
       else {
         RunResult = 1;
         StdErr = "Unrecognized command ";
@@ -364,6 +371,89 @@ static string trim(string value) {
       RunResult = 0;
     }
 
+    void FileRunCommandPart::RunD3DReflect(const FileRunCommandPart *Prior) {
+      std::string args(strtrim(Arguments));
+      if (args != "%s") {
+        StdErr = "Only supported pattern is a plain input file";
+        RunResult = 1;
+        return;
+      }
+      if (!Prior) {
+        StdErr = "Prior command required to generate stdin";
+        RunResult = 1;
+        return;
+      }
+
+      CComPtr<IDxcLibrary> pLibrary;
+      CComPtr<IDxcBlobEncoding> pSource;
+      CComPtr<IDxcAssembler> pAssembler;
+      CComPtr<IDxcOperationResult> pResult;
+      CComPtr<ID3D12ShaderReflection> pShaderReflection;
+      CComPtr<ID3D12LibraryReflection> pLibraryReflection;
+      CComPtr<IDxcContainerReflection> containerReflection;
+      uint32_t partCount;
+      CComPtr<IDxcBlob> pContainerBlob;
+      HRESULT resultStatus;
+      bool blobFound = false;
+      std::ostringstream ss;
+      D3DReflectionDumper dumper(ss);
+
+      IFT(DllSupport->CreateInstance(CLSID_DxcLibrary, &pLibrary));
+      IFT(DllSupport->CreateInstance(CLSID_DxcAssembler, &pAssembler));
+
+      IFT(pLibrary->CreateBlobWithEncodingFromPinned(
+          (LPBYTE)Prior->StdOut.c_str(), Prior->StdOut.size(), CP_UTF8,
+          &pSource));
+
+      IFT(pAssembler->AssembleToContainer(pSource, &pResult));
+      IFT(pResult->GetStatus(&resultStatus));
+      if (FAILED(resultStatus)) {
+        CComPtr<IDxcBlobEncoding> pAssembleBlob;
+        IFT(pResult->GetErrorBuffer(&pAssembleBlob));
+        StdErr = BlobToUtf8(pAssembleBlob);
+        RunResult = resultStatus;
+        return;
+      }
+      IFT(pResult->GetResult(&pContainerBlob));
+
+      VERIFY_SUCCEEDED(DllSupport->CreateInstance(CLSID_DxcContainerReflection, &containerReflection));
+      VERIFY_SUCCEEDED(containerReflection->Load(pContainerBlob));
+      VERIFY_SUCCEEDED(containerReflection->GetPartCount(&partCount));
+
+      for (uint32_t i = 0; i < partCount; ++i) {
+        uint32_t kind;
+        VERIFY_SUCCEEDED(containerReflection->GetPartKind(i, &kind));
+        if (kind == (uint32_t)hlsl::DxilFourCC::DFCC_DXIL) {
+          blobFound = true;
+          CComPtr<IDxcBlob> pPart;
+          IFT(containerReflection->GetPartContent(i, &pPart));
+          const hlsl::DxilProgramHeader *pProgramHeader =
+            reinterpret_cast<const hlsl::DxilProgramHeader*>(pPart->GetBufferPointer());
+          VERIFY_IS_TRUE(IsValidDxilProgramHeader(pProgramHeader, (uint32_t)pPart->GetBufferSize()));
+          hlsl::DXIL::ShaderKind SK = hlsl::GetVersionShaderType(pProgramHeader->ProgramVersion);
+          if (SK == hlsl::DXIL::ShaderKind::Library)
+            VERIFY_SUCCEEDED(containerReflection->GetPartReflection(i, IID_PPV_ARGS(&pLibraryReflection)));
+          else
+            VERIFY_SUCCEEDED(containerReflection->GetPartReflection(i, IID_PPV_ARGS(&pShaderReflection)));
+          break;
+        }
+      }
+
+      if (!blobFound) {
+        StdErr = "Unable to find DXIL part";
+        RunResult = 1;
+        return;
+      } else if (pShaderReflection) {
+        dumper.Dump(pShaderReflection);
+      } else if (pLibraryReflection) {
+        dumper.Dump(pLibraryReflection);
+      }
+
+      ss.flush();
+      StdOut = ss.str();
+      RunResult = 0;
+    }
+
     void FileRunCommandPart::RunTee(const FileRunCommandPart *Prior) {
       if (Prior == nullptr) {
         StdErr = "tee requires a prior command";