Objects.cpp 36 KB

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