Objects.cpp 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // Objects.cpp //
  4. // Copyright (C) Microsoft Corporation. All rights reserved. //
  5. // This file is distributed under the University of Illinois Open Source //
  6. // License. See LICENSE.TXT for details. //
  7. // //
  8. // //
  9. ///////////////////////////////////////////////////////////////////////////////
  10. #include "dxc/Test/CompilationResult.h"
  11. #include "dxc/Test/HLSLTestData.h"
  12. #include <stdint.h>
  13. #ifdef _WIN32
  14. #include "WexTestClass.h"
  15. #endif
  16. #include "dxc/Test/HlslTestUtils.h"
  17. #include <exception>
  18. #include <set>
  19. ///////////////////////////////////////////////////////////////////////////////
  20. // Utilities.
  21. namespace std {
  22. /// Returns the first element of the container.
  23. template <class Container>
  24. auto first(Container& cont) -> decltype (*begin(cont))
  25. {
  26. auto iter = begin(cont);
  27. return *iter;
  28. }
  29. /// Returns the first element of the container or the default value if empty.
  30. template <typename Container, typename ElementType>
  31. ElementType first_or_default(
  32. Container& cont,
  33. const ElementType& defaultValue
  34. )
  35. {
  36. auto iter = begin(cont);
  37. auto endIter = end(cont);
  38. if (iter == endIter) return defaultValue;
  39. return *iter;
  40. }
  41. }
  42. template <typename TEnumeration>
  43. class EnumFlagsIterator : public std::iterator<std::input_iterator_tag, TEnumeration>
  44. {
  45. private:
  46. unsigned long _value;
  47. public:
  48. EnumFlagsIterator(TEnumeration value) : _value(value) { }
  49. TEnumeration operator*() const
  50. {
  51. unsigned long l;
  52. _BitScanForward(&l, _value);
  53. return static_cast<TEnumeration>(1 << l);
  54. }
  55. EnumFlagsIterator<TEnumeration>& operator++()
  56. {
  57. unsigned long l;
  58. _BitScanForward(&l, _value);
  59. _value = _value & ~(1 << l);
  60. return *this;
  61. }
  62. bool equal(const EnumFlagsIterator<TEnumeration>& other)
  63. {
  64. return _value == other._value;
  65. }
  66. bool operator==(const EnumFlagsIterator<TEnumeration>& other)
  67. {
  68. return _value == other._value;
  69. }
  70. bool operator!=(const EnumFlagsIterator<TEnumeration>& other)
  71. {
  72. return _value != other._value;
  73. }
  74. };
  75. ///////////////////////////////////////////////////////////////////////////////
  76. // Shader model test data.
  77. enum ShaderModel
  78. {
  79. ShaderModel4 = 4,
  80. ShaderModel5 = 5
  81. };
  82. enum ShaderType
  83. {
  84. /// Vertex shader.
  85. ST_Vertex = 1 << 0,
  86. /// Hull shader.
  87. ST_Hull = 1 << 1,
  88. /// Domain shader.
  89. ST_Domain = 1 << 2,
  90. /// Geometry shader type.
  91. ST_Geometry = 1 << 3,
  92. /// Pixel shader type.
  93. ST_Pixel = 1 << 4,
  94. /// Compute shader type.
  95. ST_Compute = 1 << 5,
  96. /// Hull and geometry shader types.
  97. ST_HullGeometry = ST_Hull | ST_Geometry,
  98. /// Hull and domain shader types.
  99. ST_HullDomain = ST_Hull | ST_Domain,
  100. /// Pixel and compute shader types.
  101. ST_PixelCompute = ST_Pixel | ST_Compute,
  102. /// All shader types.
  103. ST_All = ST_Vertex | ST_Hull | ST_Domain | ST_Geometry | ST_Pixel | ST_Compute
  104. };
  105. typedef EnumFlagsIterator<ShaderType> ShaderTypeIterator;
  106. ShaderTypeIterator begin(ShaderType value) { return ShaderTypeIterator(value); }
  107. ShaderTypeIterator end(ShaderType value) { return ShaderTypeIterator((ShaderType)0); }
  108. /// Enumerates types of shader objects like textures or buffers.
  109. enum ShaderObjectKind
  110. {
  111. /// Output buffer that appears as a stream the shader may append to.
  112. SOK_AppendStructuredBuffer,
  113. ///
  114. SOK_Buffer,
  115. SOK_ByteAddressBuffer,
  116. /// An input buffer that appears as a stream the shader may pull values from.
  117. SOK_ConsumeStructuredBuffer,
  118. /// Represents an array of control points that are available to the hull shader as inputs.
  119. SOK_InputPatch,
  120. /// Represents an array of output control points that are available to the hull shader's patch-constant function as well as the domain shader.
  121. SOK_OutputPatch,
  122. /// A read/write buffer.
  123. SOK_RWBuffer,
  124. /// A read/write buffer that indexes in bytes.
  125. SOK_RWByteAddressBuffer,
  126. /// A read/write buffer that can take a T type that is a structure.
  127. SOK_RWStructuredBuffer,
  128. /// A read/write resource.
  129. SOK_RWTexture1D,
  130. /// A read/write resource.
  131. SOK_RWTexture1DArray,
  132. /// A read/write resource.
  133. SOK_RWTexture2D,
  134. /// A read/write resource.
  135. SOK_RWTexture2DArray,
  136. /// A read/write resource.
  137. SOK_RWTexture3D,
  138. /// A stream-output object is a templated object that streams data out of the geometry-shader stage.
  139. SOK_StreamOutputLine,
  140. /// A stream-output object is a templated object that streams data out of the geometry-shader stage.
  141. SOK_StreamOutputPoint,
  142. /// A stream-output object is a templated object that streams data out of the geometry-shader stage.
  143. SOK_StreamOutputTriangle,
  144. /// A read-only buffer, which can take a T type that is a structure.
  145. SOK_StructuredBuffer,
  146. /// A read-only resource.
  147. SOK_Texture1D,
  148. /// A read-only resource.
  149. SOK_Texture1DArray,
  150. /// A read-only resource.
  151. SOK_Texture2D,
  152. /// A read-only resource.
  153. SOK_Texture2DArray,
  154. /// A read-only resource.
  155. SOK_Texture2DMS,
  156. /// A read-only resource.
  157. SOK_Texture2DArrayMS,
  158. /// A read-only resource.
  159. SOK_Texture3D,
  160. /// A read-only resource.
  161. SOK_TextureCube,
  162. /// A read-only resource.
  163. SOK_TextureCubeArray
  164. };
  165. struct ShaderObjectDataItem
  166. {
  167. ShaderObjectKind Kind;
  168. const char* TypeName;
  169. ShaderModel MinShaderModel;
  170. ShaderType ValidShaderTypes;
  171. };
  172. static const
  173. ShaderObjectDataItem ShaderObjectData[] =
  174. {
  175. { SOK_AppendStructuredBuffer, "AppendStructuredBuffer", ShaderModel5, ST_PixelCompute },
  176. { SOK_Buffer, "Buffer", ShaderModel5, ST_All },
  177. { SOK_ByteAddressBuffer, "ByteAddressBuffer", ShaderModel5, ST_All },
  178. { SOK_ConsumeStructuredBuffer, "ConsumeStructuredBuffer", ShaderModel5, ST_PixelCompute },
  179. { SOK_InputPatch, "InputPatch", ShaderModel5, ST_HullGeometry },
  180. { SOK_OutputPatch, "OutputPatch", ShaderModel5, ST_HullDomain },
  181. { SOK_RWBuffer, "RWBuffer", ShaderModel5, ST_PixelCompute },
  182. { SOK_RWByteAddressBuffer, "RWByteAddressBuffer", ShaderModel5, ST_PixelCompute },
  183. { SOK_RWStructuredBuffer, "RWStructuredBuffer", ShaderModel5, ST_PixelCompute },
  184. { SOK_RWTexture1D, "RWTexture1D", ShaderModel5, ST_PixelCompute },
  185. { SOK_RWTexture1DArray, "RWTexture1DArray", ShaderModel5, ST_PixelCompute },
  186. { SOK_RWTexture2D, "RWTexture2D", ShaderModel5, ST_PixelCompute },
  187. { SOK_RWTexture2DArray, "RWTexture2DArray", ShaderModel5, ST_PixelCompute },
  188. { SOK_RWTexture3D, "RWTexture3D", ShaderModel5, ST_PixelCompute },
  189. { SOK_StreamOutputLine, "LineStream", ShaderModel4, ST_Geometry },
  190. { SOK_StreamOutputPoint, "PointStream", ShaderModel4, ST_Geometry },
  191. { SOK_StreamOutputTriangle, "TriangleStream", ShaderModel4, ST_Geometry },
  192. { SOK_StructuredBuffer, "StructuredBuffer", ShaderModel5, ST_All },
  193. { SOK_Texture1D, "Texture1D", ShaderModel4, ST_All },
  194. { SOK_Texture1DArray, "Texture1DArray", ShaderModel4, ST_All },
  195. { SOK_Texture2D, "Texture2D", ShaderModel4, ST_All },
  196. { SOK_Texture2DArray, "Texture2DArray", ShaderModel4, ST_All },
  197. { SOK_Texture2DMS, "Texture2DMS", ShaderModel4, ST_All },
  198. { SOK_Texture2DArrayMS, "Texture2DMSArray", ShaderModel4, ST_All },
  199. { SOK_Texture3D, "Texture3D", ShaderModel4, ST_All },
  200. { SOK_TextureCube, "TextureCube", ShaderModel4, ST_All },
  201. { SOK_TextureCubeArray, "TextureCubeArray", ShaderModel4, ST_All }
  202. };
  203. /// Enumerates the template shapes.
  204. /// This is a crude simplification of what the type system could do,
  205. /// but it covers all cases without unused generality.
  206. enum ShaderObjectTemplateKind
  207. {
  208. /// No parameters.
  209. SOTK_NoParams,
  210. /// Single parameter of type scalar or vector.
  211. SOTK_SingleSVParam,
  212. /// Single parameter of type scalar, vector or struct.
  213. SOTK_SingleSVCParam,
  214. /// Two parameters; a scalar or vector type and a sample count.
  215. SOTK_SVAndSampleCountParams,
  216. /// Two parameters; a scalar or vector type and a control point count (1-32).
  217. SOTK_SVCAndControlPointCountParams
  218. };
  219. struct ShaderObjectTemplateDataItem
  220. {
  221. ShaderObjectKind Kind;
  222. ShaderObjectTemplateKind TemplateKind;
  223. bool TemplateParamsOptional;
  224. };
  225. static const bool OptionalTrue = true;
  226. static const bool OptionalFalse = false;
  227. static const
  228. ShaderObjectTemplateDataItem ShaderObjectTemplateData[] =
  229. {
  230. { SOK_AppendStructuredBuffer, SOTK_SingleSVCParam, OptionalFalse },
  231. { SOK_Buffer, SOTK_SingleSVParam, OptionalFalse },
  232. { SOK_ByteAddressBuffer, SOTK_NoParams, OptionalTrue },
  233. { SOK_ConsumeStructuredBuffer, SOTK_SingleSVCParam, OptionalFalse },
  234. { SOK_InputPatch, SOTK_SVCAndControlPointCountParams, OptionalFalse },
  235. { SOK_OutputPatch, SOTK_SVCAndControlPointCountParams, OptionalFalse },
  236. { SOK_RWBuffer, SOTK_SingleSVParam, OptionalFalse },
  237. { SOK_RWByteAddressBuffer, SOTK_NoParams, OptionalTrue },
  238. { SOK_RWStructuredBuffer, SOTK_SingleSVCParam, OptionalFalse },
  239. { SOK_RWTexture1D, SOTK_SingleSVParam, OptionalFalse },
  240. { SOK_RWTexture1DArray, SOTK_SingleSVParam, OptionalFalse },
  241. { SOK_RWTexture2D, SOTK_SingleSVParam, OptionalFalse },
  242. { SOK_RWTexture2DArray, SOTK_SingleSVParam, OptionalFalse },
  243. { SOK_RWTexture3D, SOTK_SingleSVParam, OptionalFalse },
  244. { SOK_StreamOutputLine, SOTK_SingleSVCParam, OptionalFalse },
  245. { SOK_StreamOutputPoint, SOTK_SingleSVCParam, OptionalFalse },
  246. { SOK_StreamOutputTriangle, SOTK_SingleSVCParam, OptionalFalse },
  247. { SOK_StructuredBuffer, SOTK_SingleSVCParam, OptionalFalse },
  248. { SOK_Texture1D, SOTK_SingleSVParam, OptionalTrue },
  249. { SOK_Texture1DArray, SOTK_SingleSVParam, OptionalTrue },
  250. { SOK_Texture2D, SOTK_SingleSVParam, OptionalTrue },
  251. { SOK_Texture2DArray, SOTK_SingleSVParam, OptionalTrue },
  252. { SOK_Texture2DMS, SOTK_SVAndSampleCountParams, OptionalFalse },
  253. { SOK_Texture2DArrayMS, SOTK_SVAndSampleCountParams, OptionalFalse },
  254. { SOK_Texture3D, SOTK_SingleSVParam, OptionalTrue },
  255. { SOK_TextureCube, SOTK_SingleSVParam, OptionalTrue },
  256. { SOK_TextureCubeArray, SOTK_SingleSVParam, OptionalTrue }
  257. };
  258. static
  259. const ShaderObjectTemplateDataItem& GetTemplateData(const ShaderObjectDataItem& sod)
  260. {
  261. static_assert(
  262. _countof(ShaderObjectTemplateData) == _countof(ShaderObjectData),
  263. "otherwise lookup tables have different elements");
  264. struct Unary {
  265. ShaderObjectKind ObjectKind;
  266. Unary(ShaderObjectKind ok) : ObjectKind(ok) { }
  267. bool operator()(const ShaderObjectTemplateDataItem& i) { return i.Kind == ObjectKind; }
  268. };
  269. Unary filter(sod.Kind);
  270. auto iter = std::find_if(std::begin(ShaderObjectTemplateData), std::end(ShaderObjectTemplateData), filter);
  271. assert(iter != std::end(ShaderObjectTemplateData));
  272. return *iter;
  273. }
  274. static
  275. int CountOptionalTemplateArguments(const ShaderObjectTemplateDataItem& templateData)
  276. {
  277. if (!templateData.TemplateParamsOptional) {
  278. return 0;
  279. }
  280. switch (templateData.TemplateKind) {
  281. default:
  282. case SOTK_NoParams: return 0;
  283. case SOTK_SingleSVParam: return 1;
  284. case SOTK_SingleSVCParam: return 1;
  285. case SOTK_SVAndSampleCountParams: return 2;
  286. case SOTK_SVCAndControlPointCountParams: return 2;
  287. }
  288. }
  289. // - a RWBuffer supports globallycoherent storage class to generate memory barriers
  290. // TODO: ByteAddressBuffer is supported on SM4 on compute shaders
  291. // TODO: RWByteAddressBuffer is supported on SM4 on compute shaders
  292. // TODO: RWStructuredBuffer is supported on SM4 on compute shaders
  293. #include "dxc/dxcapi.internal.h"
  294. #include "dxc/HlslIntrinsicOp.h"
  295. #include "gen_intrin_main_tables_15.h"
  296. struct ShaderObjectIntrinsicDataItem
  297. {
  298. // Kind of shader object described.
  299. ShaderObjectKind Kind;
  300. // Pointer to first intrinsic in table.
  301. const HLSL_INTRINSIC* Intrinsics;
  302. // Count of elements in intrinsic table.
  303. size_t IntrinsicCount;
  304. };
  305. // The test that requires this is pending complete
  306. // support for primitive types
  307. #if 0
  308. const ShaderObjectIntrinsicDataItem ShaderObjectIntrinsicData[] = {
  309. { SOK_AppendStructuredBuffer, g_AppendStructuredBufferMethods, _countof(g_AppendStructuredBufferMethods) },
  310. { SOK_Buffer, g_BufferMethods, _countof(g_BufferMethods) },
  311. { SOK_ByteAddressBuffer, g_ByteAddressBufferMethods, _countof(g_ByteAddressBufferMethods) },
  312. { SOK_ConsumeStructuredBuffer, g_ConsumeStructuredBufferMethods, _countof(g_ByteAddressBufferMethods) },
  313. { SOK_InputPatch, nullptr, 0 },
  314. { SOK_OutputPatch, nullptr, 0 },
  315. { SOK_RWBuffer, g_RWBufferMethods, _countof(g_RWBufferMethods) },
  316. { SOK_RWByteAddressBuffer, g_RWByteAddressBufferMethods, _countof(g_RWByteAddressBufferMethods) },
  317. { SOK_RWStructuredBuffer, g_RWStructuredBufferMethods, _countof(g_RWStructuredBufferMethods) },
  318. { SOK_RWTexture1D, g_RWTexture1DMethods, _countof(g_RWTexture1DMethods) },
  319. { SOK_RWTexture1DArray, g_RWTexture1DArrayMethods, _countof(g_RWTexture1DArrayMethods) },
  320. { SOK_RWTexture2D, g_RWTexture2DMethods, _countof(g_RWTexture2DMethods) },
  321. { SOK_RWTexture2DArray, g_RWTexture2DArrayMethods, _countof(g_RWTexture2DArrayMethods) },
  322. { SOK_RWTexture3D, g_RWTexture3DMethods, _countof(g_RWTexture3DMethods) },
  323. { SOK_StreamOutputLine, g_StreamMethods, _countof(g_StreamMethods) },
  324. { SOK_StreamOutputPoint, g_StreamMethods, _countof(g_StreamMethods) },
  325. { SOK_StreamOutputTriangle, g_StreamMethods, _countof(g_StreamMethods) },
  326. { SOK_StructuredBuffer, g_StructuredBufferMethods, _countof(g_StructuredBufferMethods) },
  327. { SOK_Texture1D, g_Texture1DMethods, _countof(g_Texture1DMethods) },
  328. { SOK_Texture1DArray, g_Texture1DArrayMethods, _countof(g_Texture1DArrayMethods) },
  329. { SOK_Texture2D, g_Texture2DMethods, _countof(g_Texture2DMethods) },
  330. { SOK_Texture2DArray, g_Texture2DArrayMethods, _countof(g_Texture2DArrayMethods) },
  331. { SOK_Texture2DMS, g_Texture2DMSMethods, _countof(g_Texture2DMSMethods) },
  332. { SOK_Texture2DArrayMS, g_Texture2DArrayMSMethods, _countof(g_Texture2DArrayMSMethods) },
  333. { SOK_Texture3D, g_Texture3DMethods, _countof(g_Texture3DMethods) },
  334. { SOK_TextureCube, g_TextureCUBEMethods, _countof(g_TextureCUBEMethods) },
  335. { SOK_TextureCubeArray, g_TextureCUBEArrayMethods, _countof(g_TextureCUBEArrayMethods) }
  336. };
  337. static
  338. const ShaderObjectIntrinsicDataItem& GetIntrinsicData(const ShaderObjectDataItem& sod)
  339. {
  340. for (unsigned i = 0; i < _countof(ShaderObjectIntrinsicData); i++)
  341. {
  342. if (sod.Kind == ShaderObjectIntrinsicData[i].Kind)
  343. {
  344. return ShaderObjectIntrinsicData[i];
  345. }
  346. }
  347. throw std::runtime_error("cannot find shader object kind");
  348. }
  349. #endif
  350. // The test fixture.
  351. #ifdef _WIN32
  352. class ObjectTest {
  353. #else
  354. class ObjectTest : public ::testing::Test {
  355. #endif
  356. private:
  357. HlslIntellisenseSupport m_isenseSupport;
  358. public:
  359. BEGIN_TEST_CLASS(ObjectTest)
  360. TEST_CLASS_PROPERTY(L"Parallel", L"true")
  361. TEST_METHOD_PROPERTY(L"Priority", L"0")
  362. END_TEST_CLASS()
  363. TEST_CLASS_SETUP(ObjectTestSetup);
  364. TEST_METHOD(DeclareLocalObject)
  365. TEST_METHOD(OptionalTemplateArgs)
  366. TEST_METHOD(MissingTemplateArgs)
  367. TEST_METHOD(TooManyTemplateArgs)
  368. TEST_METHOD(PassAsParameter)
  369. TEST_METHOD(AssignVariables)
  370. TEST_METHOD(AssignReturnResult)
  371. TEST_METHOD(PassToInoutArgs)
  372. TEST_METHOD(TemplateArgConstraints)
  373. TEST_METHOD(FunctionInvoke)
  374. void FormatTypeNameAndPreamble(const ShaderObjectDataItem& sod,
  375. char (&typeName)[64],
  376. const char** preambleDecl) {
  377. *preambleDecl = "";
  378. auto templateData = GetTemplateData(sod);
  379. switch (templateData.TemplateKind) {
  380. case SOTK_NoParams:
  381. sprintf_s(typeName, _countof(typeName), "%s", sod.TypeName);
  382. break;
  383. case SOTK_SingleSVParam:
  384. sprintf_s(typeName, _countof(typeName), "%s<float4>", sod.TypeName);
  385. break;
  386. case SOTK_SingleSVCParam:
  387. *preambleDecl = "struct MY_STRUCT { float4 f4; bool b; int3 i3; };\n";
  388. sprintf_s(typeName, _countof(typeName), "%s<MY_STRUCT>", sod.TypeName);
  389. break;
  390. case SOTK_SVAndSampleCountParams:
  391. case SOTK_SVCAndControlPointCountParams:
  392. default:
  393. sprintf_s(typeName, _countof(typeName), "%s<float4, 1>", sod.TypeName);
  394. break;
  395. }
  396. }
  397. std::string BuildDeclarationFunction(const ShaderObjectDataItem& sod) {
  398. return BuildDeclarationFunction(sod, 0, false);
  399. }
  400. std::string BuildDeclarationFunction(const ShaderObjectDataItem& sod, int missingTemplateCount,
  401. bool collapseEmptyArgs) {
  402. char result[256];
  403. auto templateData = GetTemplateData(sod);
  404. const char StructDecl[] = "struct MY_STRUCT { float4 f4; bool b; int3 i3; };\n";
  405. const char StructParam[] = "<MY_STRUCT>\n";
  406. const char VectorParam[] = "<float4>\n";
  407. const char VectorAndCountParam[] = "<float4, 4>\n";
  408. const char EmptyTemplateArgs[] = "<>";
  409. const char MissingTemplateArgs[] = "";
  410. // Default setup for a 'SOTK_NoParams' case.
  411. const char* StructDeclFragment = "";
  412. const char* TemplateDeclFragment = MissingTemplateArgs;
  413. if (templateData.TemplateKind == SOTK_SingleSVParam && missingTemplateCount == 0) {
  414. TemplateDeclFragment = VectorParam;
  415. } else if (templateData.TemplateKind == SOTK_SingleSVCParam && missingTemplateCount == 0) {
  416. StructDeclFragment = StructDecl;
  417. TemplateDeclFragment = StructParam;
  418. } else if ((templateData.TemplateKind == SOTK_SVAndSampleCountParams ||
  419. templateData.TemplateKind == SOTK_SVCAndControlPointCountParams)) {
  420. if (missingTemplateCount == 0) {
  421. TemplateDeclFragment = VectorAndCountParam;
  422. } else if (missingTemplateCount == 1) {
  423. TemplateDeclFragment = VectorParam;
  424. }
  425. }
  426. // Allow 'Object<>' to collapse to 'Object' when collapseEmptyArgs is set.
  427. if (templateData.TemplateKind != SOTK_NoParams && TemplateDeclFragment == MissingTemplateArgs) {
  428. TemplateDeclFragment = collapseEmptyArgs ? MissingTemplateArgs : EmptyTemplateArgs;
  429. }
  430. sprintf_s(result, _countof(result), "%s"
  431. "float ps(float4 color : COLOR) { %s%s localVar; return 0; }",
  432. StructDeclFragment, sod.TypeName, TemplateDeclFragment);
  433. return std::string(result);
  434. }
  435. std::string BuildDeclarationFunctionTooManyArgs(const ShaderObjectDataItem& sod) {
  436. char result[256];
  437. auto templateData = GetTemplateData(sod);
  438. switch (templateData.TemplateKind) {
  439. case SOTK_NoParams:
  440. sprintf_s(result, _countof(result),
  441. "float ps(float4 color : COLOR) { %s localVar<float>; return 0; }", sod.TypeName);
  442. break;
  443. case SOTK_SingleSVParam:
  444. sprintf_s(result, _countof(result),
  445. "float ps(float4 color : COLOR) { %s<float4, 1> localVar; return 0; }", sod.TypeName);
  446. break;
  447. case SOTK_SingleSVCParam:
  448. sprintf_s(result, _countof(result),
  449. "struct MY_STRUCT { float4 f4; bool b; int3 i3; };\n"
  450. "float ps(float4 color : COLOR) { %s<MY_STRUCT, 1> localVar; return 0; }", sod.TypeName);
  451. break;
  452. case SOTK_SVAndSampleCountParams:
  453. case SOTK_SVCAndControlPointCountParams:
  454. default:
  455. sprintf_s(result, _countof(result),
  456. "float ps(float4 color : COLOR) { %s<float4, 4, 4> localVar; return 0; }", sod.TypeName);
  457. break;
  458. }
  459. return std::string(result);
  460. }
  461. std::string BuildPassAsParameter(const ShaderObjectDataItem& sod) {
  462. char result[256];
  463. char typeName[64];
  464. const char* preambleDecl;
  465. FormatTypeNameAndPreamble(sod, typeName, &preambleDecl);
  466. std::string parmType = typeName;
  467. // Stream-output objects must be declared as inout.
  468. switch (sod.Kind) {
  469. case SOK_StreamOutputLine:
  470. case SOK_StreamOutputPoint:
  471. case SOK_StreamOutputTriangle:
  472. parmType = "inout " + parmType;
  473. break;
  474. default:
  475. // Other kinds need no alteration
  476. break;
  477. }
  478. sprintf_s(result, _countof(result),
  479. "%s"
  480. "void f(%s parameter) { }\n"
  481. "float ps(float4 color : COLOR) { %s localVar; f(localVar); return 0; }",
  482. preambleDecl, parmType.c_str(), typeName);
  483. return std::string(result);
  484. }
  485. std::string BuildAssignment(const ShaderObjectDataItem& sod) {
  486. char result[256];
  487. char typeName[64];
  488. const char* preambleDecl;
  489. FormatTypeNameAndPreamble(sod, typeName, &preambleDecl);
  490. sprintf_s(result, _countof(result),
  491. "%s"
  492. "float ps(float4 color : COLOR) { %s lv1; %s lv2; lv1 = lv2; return 0; }",
  493. preambleDecl, typeName, typeName);
  494. return std::string(result);
  495. }
  496. std::string BuildAssignmentFromResult(const ShaderObjectDataItem& sod) {
  497. char result[256];
  498. char typeName[64];
  499. const char* preambleDecl;
  500. FormatTypeNameAndPreamble(sod, typeName, &preambleDecl);
  501. sprintf_s(result, _countof(result),
  502. "%s"
  503. "%s f() { %s local; return local; }\n"
  504. "float ps(float4 color : COLOR) { %s lv1 = f(); return 0; }",
  505. preambleDecl, typeName, typeName, typeName);
  506. return std::string(result);
  507. }
  508. void CheckCompiles(const std::string& text, bool expected) {
  509. CheckCompiles(text.c_str(), text.size(), expected);
  510. }
  511. void CheckCompiles(const char* text, size_t textLen, bool expected) {
  512. CompilationResult result(
  513. CompilationResult::CreateForProgram(text, textLen));
  514. // Uncomment the line to print out the AST unconditionally.
  515. // printf("%s", result.BuildASTString().c_str());
  516. if (expected != result.ParseSucceeded())
  517. {
  518. EXPECT_EQ(expected, result.ParseSucceeded());
  519. // TODO: log this out
  520. //<< "for program " << text << "\n with AST\n" << result.BuildASTString()
  521. //<< "and errors\n" << result.GetTextForErrors();
  522. }
  523. }
  524. };
  525. bool ObjectTest::ObjectTestSetup()
  526. {
  527. m_isenseSupport.Initialize();
  528. return m_isenseSupport.IsEnabled();
  529. }
  530. TEST_F(ObjectTest, DeclareLocalObject) {
  531. for (const auto &sod : ShaderObjectData) {
  532. // When shader models are validated, run through all of them.
  533. // for (const auto &st : sod.ValidShaderTypes)
  534. // const auto st = std::first(sod.ValidShaderTypes);
  535. CheckCompiles(BuildDeclarationFunction(sod), true);
  536. }
  537. }
  538. TEST_F(ObjectTest, OptionalTemplateArgs) {
  539. for (const auto &sod : ShaderObjectData) {
  540. // When shader models are validated, run through all of them.
  541. // for (const auto &st : sod.ValidShaderTypes)
  542. //const auto st = std::first(sod.ValidShaderTypes);
  543. const ShaderObjectTemplateDataItem& templateData = GetTemplateData(sod);
  544. int argCount = CountOptionalTemplateArguments(templateData);
  545. if (argCount == 0) {
  546. continue;
  547. }
  548. for (int missingCount = 1; missingCount <= argCount; missingCount++) {
  549. CheckCompiles(BuildDeclarationFunction(sod, missingCount, false), true);
  550. }
  551. }
  552. }
  553. TEST_F(ObjectTest, MissingTemplateArgs) {
  554. for (const auto &sod : ShaderObjectData) {
  555. // When shader models are validated, run through all of them.
  556. // for (const auto &st : sod.ValidShaderTypes)
  557. // const auto st = std::first(sod.ValidShaderTypes);
  558. const ShaderObjectTemplateDataItem& templateData = GetTemplateData(sod);
  559. int argCount = CountOptionalTemplateArguments(templateData);
  560. if (argCount == 0) {
  561. continue;
  562. }
  563. CheckCompiles(BuildDeclarationFunction(sod, argCount, true), true);
  564. }
  565. }
  566. TEST_F(ObjectTest, TooManyTemplateArgs) {
  567. for (const auto &sod : ShaderObjectData) {
  568. // When shader models are validated, run through all of them.
  569. // for (const auto &st : sod.ValidShaderTypes)
  570. // const auto st = std::first(sod.ValidShaderTypes);
  571. CheckCompiles(BuildDeclarationFunctionTooManyArgs(sod), false);
  572. }
  573. }
  574. TEST_F(ObjectTest, PassAsParameter) {
  575. for (const auto &sod : ShaderObjectData) {
  576. // When shader models are validated, run through all of them.
  577. // for (const auto &st : sod.ValidShaderTypes)
  578. // const auto st = std::first(sod.ValidShaderTypes);
  579. CheckCompiles(BuildPassAsParameter(sod), true);
  580. }
  581. }
  582. TEST_F(ObjectTest, AssignVariables) {
  583. for (const auto &sod : ShaderObjectData) {
  584. // When shader models are validated, run through all of them.
  585. // for (const auto &st : sod.ValidShaderTypes)
  586. // const auto st = std::first(sod.ValidShaderTypes);
  587. CheckCompiles(BuildAssignment(sod), true);
  588. }
  589. }
  590. TEST_F(ObjectTest, AssignReturnResult) {
  591. for (const auto &sod : ShaderObjectData) {
  592. // When shader models are validated, run through all of them.
  593. // for (const auto &st : sod.ValidShaderTypes)
  594. // const auto st = std::first(sod.ValidShaderTypes);
  595. CheckCompiles(BuildAssignmentFromResult(sod), true);
  596. }
  597. }
  598. TEST_F(ObjectTest, PassToInoutArgs) {
  599. for (const auto &sod : ShaderObjectData) {
  600. // Speed up the test by building one large program with all inout parameter modifiers per object.
  601. std::stringstream programText;
  602. unsigned uniqueId = 0;
  603. for (const auto &iop : InOutParameterModifierData) {
  604. switch (sod.Kind) {
  605. case SOK_StreamOutputLine:
  606. case SOK_StreamOutputPoint:
  607. case SOK_StreamOutputTriangle:
  608. // Stream-output objects can only be inout. Skip other cases.
  609. if (std::string(iop.Keyword) != "inout")
  610. continue;
  611. default:
  612. // other cases can be what they want
  613. break;
  614. }
  615. char typeName[64];
  616. const char* preambleDecl;
  617. // When shader models are validated, run through all of them.
  618. // for (const auto &st : sod.ValidShaderTypes)
  619. // const auto st = std::first(sod.ValidShaderTypes);
  620. FormatTypeNameAndPreamble(sod, typeName, &preambleDecl);
  621. if (uniqueId == 0) { // do this only once
  622. programText << preambleDecl << std::endl;
  623. }
  624. programText <<
  625. "float ps_" << uniqueId << "(" << iop.Keyword << " " << typeName << " o) { return 1.0f; }" << std::endl;
  626. programText << "void caller_" << uniqueId << "() { " << typeName << " lv; ps_" << uniqueId << "(lv); }" << std::endl;
  627. programText << std::endl;
  628. uniqueId++;
  629. }
  630. std::string programTextStr(programText.str());
  631. CheckCompiles(programTextStr.c_str(), programTextStr.size(), true);
  632. }
  633. }
  634. class TemplateSampleDataItem
  635. {
  636. public:
  637. TemplateSampleDataItem() { }
  638. TemplateSampleDataItem(const TemplateSampleDataItem& other)
  639. : Preamble(other.Preamble), TypeName(other.TypeName), IsValid(other.IsValid)
  640. {
  641. }
  642. TemplateSampleDataItem(const char* preamble, const char* typeName, bool isValid)
  643. : Preamble(preamble), TypeName(typeName), IsValid(isValid)
  644. {
  645. }
  646. std::string Preamble;
  647. std::string TypeName;
  648. bool IsValid;
  649. };
  650. std::vector<TemplateSampleDataItem>
  651. CreateSampleDataForTemplateArg(
  652. const ShaderObjectDataItem& sod,
  653. int templateIndex)
  654. {
  655. std::vector<TemplateSampleDataItem> result;
  656. char typeName[64];
  657. auto templateData = GetTemplateData(sod);
  658. assert(templateData.TemplateKind != SOTK_NoParams && "shouldn't call CreateSampleDataForTemplateArg");
  659. switch (templateData.TemplateKind) {
  660. case SOTK_NoParams:
  661. assert(!"shouldn't call CreateSampleDataForTemplateArg");
  662. break;
  663. case SOTK_SingleSVParam:
  664. case SOTK_SingleSVCParam:
  665. sprintf_s(typeName, _countof(typeName), "%s<float4>", sod.TypeName);
  666. result.push_back(TemplateSampleDataItem("", typeName, true));
  667. sprintf_s(typeName, _countof(typeName), "%s<SamplerState>", sod.TypeName);
  668. result.push_back(TemplateSampleDataItem("", typeName, false));
  669. break;
  670. case SOTK_SVAndSampleCountParams:
  671. case SOTK_SVCAndControlPointCountParams:
  672. if (templateIndex == 0) {
  673. sprintf_s(typeName, _countof(typeName), "%s<float4, 4>", sod.TypeName);
  674. result.push_back(TemplateSampleDataItem("", typeName, true));
  675. sprintf_s(typeName, _countof(typeName), "%s<SamplerState, 4>", sod.TypeName);
  676. result.push_back(TemplateSampleDataItem("", typeName, false));
  677. } else {
  678. sprintf_s(typeName, _countof(typeName), "%s<float4, 1>", sod.TypeName);
  679. result.push_back(TemplateSampleDataItem("", typeName, true));
  680. sprintf_s(typeName, _countof(typeName), "%s<float4, 128>", sod.TypeName);
  681. result.push_back(TemplateSampleDataItem("", typeName, true));
  682. // These are deferred to back-end validation for now.
  683. // bool largeNumberValid = sod.Kind == SOK_InputPatch || sod.Kind == SOK_OutputPatch;
  684. sprintf_s(typeName, _countof(typeName), "%s<float4, 129>", sod.TypeName);
  685. result.push_back(TemplateSampleDataItem("", typeName, false));
  686. }
  687. break;
  688. }
  689. return result;
  690. }
  691. TEST_F(ObjectTest, TemplateArgConstraints) {
  692. for (const auto &sod : ShaderObjectData) {
  693. // When shader models are validated, run through all of them.
  694. // for (const auto &st : sod.ValidShaderTypes)
  695. // const auto st = std::first(sod.ValidShaderTypes);
  696. const ShaderObjectTemplateDataItem& templateData = GetTemplateData(sod);
  697. int argCount = CountOptionalTemplateArguments(templateData);
  698. if (argCount == 0) {
  699. continue;
  700. }
  701. for (int i = 0; i < argCount; i++) {
  702. std::vector<TemplateSampleDataItem> sampleData =
  703. CreateSampleDataForTemplateArg(sod, i);
  704. for (auto sampleDataItem : sampleData) {
  705. char result[256];
  706. sprintf_s(result, _countof(result),
  707. "%s"
  708. "float ps(float4 color : COLOR) { %s lv1; %s lv2; lv1 = lv2; return 0; }",
  709. sampleDataItem.Preamble.c_str(),
  710. sampleDataItem.TypeName.c_str(), sampleDataItem.TypeName.c_str());
  711. CheckCompiles(result, strlen(result), sampleDataItem.IsValid);
  712. }
  713. }
  714. }
  715. }
  716. // The test that requires this function is pending complete
  717. // support for primitive types
  718. #if 0
  719. static
  720. std::string SelectComponentType(BYTE legalTypes)
  721. {
  722. switch ((LEGAL_INTRINSIC_COMPTYPES)legalTypes)
  723. {
  724. case LICOMPTYPE_VOID: return "void";
  725. case LICOMPTYPE_BOOL: return "bool";
  726. case LICOMPTYPE_INT: return "int";
  727. case LICOMPTYPE_UINT: return "uint";
  728. case LICOMPTYPE_ANY_INT: return "int";
  729. case LICOMPTYPE_ANY_INT32: return "int";
  730. case LICOMPTYPE_UINT_ONLY: return "uint";
  731. case LICOMPTYPE_FLOAT: return "float";
  732. case LICOMPTYPE_ANY_FLOAT: return "float";
  733. case LICOMPTYPE_FLOAT_LIKE: return "float";
  734. case LICOMPTYPE_FLOAT_DOUBLE: return "double";
  735. case LICOMPTYPE_DOUBLE: return "double";
  736. case LICOMPTYPE_DOUBLE_ONLY: return "double";
  737. case LICOMPTYPE_NUMERIC: return "int";
  738. case LICOMPTYPE_NUMERIC32: return "float";
  739. case LICOMPTYPE_NUMERIC32_ONLY: return "double";
  740. case LICOMPTYPE_ANY: return "int";
  741. default: return "";
  742. //LICOMPTYPE_SAMPLER1D,
  743. //LICOMPTYPE_SAMPLER2D,
  744. //LICOMPTYPE_SAMPLER3D,
  745. //LICOMPTYPE_SAMPLERCUBE,
  746. //LICOMPTYPE_SAMPLERCMP,
  747. //LICOMPTYPE_SAMPLER,
  748. //LICOMPTYPE_STRING,
  749. }
  750. }
  751. #endif
  752. TEST_F(ObjectTest, FunctionInvoke) {
  753. // This is pending complete support for primitive types - there are many
  754. // instances of uint usage, which isn't currently supported.
  755. #if 0
  756. // Tests for too many or too few arguments are available as lit-based tests.
  757. // Invoke each method, assigning the result of each method invocation as necessary.
  758. uint64_t iteration = 0;
  759. for (const auto &sod : ShaderObjectData) {
  760. const ShaderObjectIntrinsicDataItem& intrinsicData = GetIntrinsicData(sod);
  761. const ShaderObjectTemplateDataItem& templateData = GetTemplateData(sod);
  762. for (size_t i = 0; i < intrinsicData.IntrinsicCount; i++) {
  763. const HLSL_INTRINSIC* intrinsic = &intrinsicData.Intrinsics[i];
  764. ++iteration;
  765. // Build a program that will call this intrinsic.
  766. // Select an element type for the class if needed.
  767. std::string objectType;
  768. std::string elementType;
  769. std::string elementParameters;
  770. switch (templateData.TemplateKind)
  771. {
  772. case ShaderObjectTemplateKind::SOTK_NoParams:
  773. break;
  774. case ShaderObjectTemplateKind::SOTK_SingleSVCParam:
  775. case ShaderObjectTemplateKind::SOTK_SingleSVParam:
  776. elementParameters = "<float3>";
  777. elementType = "float3";
  778. break;
  779. case ShaderObjectTemplateKind::SOTK_SVAndSampleCountParams:
  780. case ShaderObjectTemplateKind::SOTK_SVCAndControlPointCountParams:
  781. elementParameters = "<float3, 4>";
  782. elementType = "float3";
  783. break;
  784. }
  785. objectType = sod.TypeName + elementParameters;
  786. // Select types for all arguments.
  787. // This implementation is brain-dead but (a) different from production,
  788. // so it's a sensible oracle, and (b) very straightforward. We simply
  789. // keep instantiating argument types until we finished.
  790. std::string argumentTypes[g_MaxIntrinsicParamCount];
  791. {
  792. bool madeProgress = false;
  793. int argsRemaining = intrinsic->uNumArgs - 1;
  794. do
  795. {
  796. madeProgress = false;
  797. for (int i = 1; i < intrinsic->uNumArgs; i++)
  798. {
  799. if (!argumentTypes[i - 1].empty())
  800. {
  801. continue;
  802. }
  803. // Determine whether we can make an independent selection.
  804. if (intrinsic->pArgs[i].uTemplateId == INTRIN_TEMPLATE_FROM_TYPE)
  805. {
  806. argumentTypes[i - 1] = elementType;
  807. madeProgress = true;
  808. --argsRemaining;
  809. continue;
  810. }
  811. // An independent scalar.
  812. if (intrinsic->pArgs[i].uTemplateId == i && intrinsic->pArgs[i].uComponentTypeId == i &&
  813. intrinsic->pArgs[i].uLegalComponentTypes != LITEMPLATE_ANY &&
  814. intrinsic->pArgs[i].uLegalTemplates == LITEMPLATE_SCALAR)
  815. {
  816. argumentTypes[i - 1] = SelectComponentType(intrinsic->pArgs[i].uLegalComponentTypes);
  817. madeProgress = true;
  818. --argsRemaining;
  819. continue;
  820. }
  821. // An independent vector.
  822. if (intrinsic->pArgs[i].uTemplateId == i && intrinsic->pArgs[i].uComponentTypeId == i &&
  823. intrinsic->pArgs[i].uLegalComponentTypes != LITEMPLATE_ANY &&
  824. intrinsic->pArgs[i].uLegalTemplates == LITEMPLATE_VECTOR)
  825. {
  826. argumentTypes[i - 1] = SelectComponentType(intrinsic->pArgs[i].uLegalComponentTypes) + "2";
  827. madeProgress = true;
  828. --argsRemaining;
  829. continue;
  830. }
  831. // TODO: complete the assignment cases with primitive types
  832. // Determine whether we have all dependencies assigned for a selection.
  833. }
  834. } while (madeProgress && argsRemaining > 0);
  835. EXPECT_EQ(0, argsRemaining) <<
  836. "otherwise we're unable to complete the signature for " << intrinsic->pArgs[0].pName <<
  837. " in iteration " << iteration;
  838. }
  839. // Determine what the result type is.
  840. bool resultIsVoid = intrinsic->pArgs[0].uLegalTemplates == LITEMPLATE_VOID;
  841. std::string resultType;
  842. if (!resultIsVoid) {
  843. }
  844. // Assemble the program as a series of declarations, a method call
  845. // and possibly an assignment if there's a return value.
  846. std::stringstream program;
  847. std::string assignmentLeftHand(resultIsVoid ? "" : (resultType + " result = "));
  848. program << "// iteration " << iteration << "\n"
  849. "void f() {\n"
  850. " " << objectType << " testObject;\n";
  851. for (int i = 1; i < intrinsic->uNumArgs; i++) {
  852. program << argumentTypes[i - 1] << ' ' << intrinsic->pArgs[i].pName << ";\n";
  853. }
  854. program << assignmentLeftHand << "testObject." << intrinsic->pArgs[0].pName << "(";
  855. for (int i = 1; i < intrinsic->uNumArgs; i++) {
  856. program << intrinsic->pArgs[i].pName;
  857. if (i != intrinsic->uNumArgs - 1) {
  858. program << ", ";
  859. }
  860. }
  861. program << ");\n}";
  862. // Verify it runs.
  863. CheckCompiles(program.str(), true);
  864. }
  865. }
  866. #endif
  867. }
  868. // TODO: force type promotion to occur for arguments.