From a24448cdd72ffdbd8f7f571886625b8a53100979 Mon Sep 17 00:00:00 2001 From: Adam Czupryna Date: Fri, 7 Jul 2017 11:42:37 +0200 Subject: [PATCH] Add CTS_ARB_gl_spirv test implementation Add CTS_ARB_gl_spirv test implementation that contains: SpirvModulesPositiveTest, SpirvModulesShaderBinaryMultipleShaderObjectsTest, SpirvModulesStateQueriesTest, SpirvModulesErrorVerificationTest, SpirvGlslToSpirVEnableTest, SpirvGlslToSpirVBuiltInFunctionsTest, SpirvGlslToSpirVSpecializationConstantsTest, SpirvValidationBuiltInVariableDecorationsTest Affects: KHR-GL45.gl_spirv.* Components: Framework, OpenGL VK-GL-CTS issue: 554 Change-Id: I0d54c70df619dbbd80b28350d2ac5e31aca08927 --- .../gl/khronos_mustpass/4.6.0.x/gl45-master.txt | 8 + .../gl/khronos_mustpass/4.6.0.x/gl46-master.txt | 8 + .../glsl_to_spirv_builtin_functions/binary_0.nspv | Bin 0 -> 1209 bytes .../glsl_to_spirv_builtin_functions/binary_1.nspv | Bin 0 -> 389 bytes .../glsl_to_spirv_builtin_functions/binary_10.nspv | Bin 0 -> 1293 bytes .../glsl_to_spirv_builtin_functions/binary_11.nspv | Bin 0 -> 1133 bytes .../glsl_to_spirv_builtin_functions/binary_12.nspv | Bin 0 -> 2189 bytes .../glsl_to_spirv_builtin_functions/binary_13.nspv | Bin 0 -> 513 bytes .../glsl_to_spirv_builtin_functions/binary_14.nspv | Bin 0 -> 517 bytes .../glsl_to_spirv_builtin_functions/binary_15.nspv | Bin 0 -> 549 bytes .../glsl_to_spirv_builtin_functions/binary_16.nspv | Bin 0 -> 505 bytes .../glsl_to_spirv_builtin_functions/binary_17.nspv | Bin 0 -> 937 bytes .../glsl_to_spirv_builtin_functions/binary_18.nspv | Bin 0 -> 1805 bytes .../glsl_to_spirv_builtin_functions/binary_19.nspv | Bin 0 -> 1213 bytes .../glsl_to_spirv_builtin_functions/binary_2.nspv | Bin 0 -> 369 bytes .../glsl_to_spirv_builtin_functions/binary_20.nspv | Bin 0 -> 733 bytes .../glsl_to_spirv_builtin_functions/binary_21.nspv | Bin 0 -> 733 bytes .../glsl_to_spirv_builtin_functions/binary_22.nspv | Bin 0 -> 781 bytes .../glsl_to_spirv_builtin_functions/binary_23.nspv | Bin 0 -> 1225 bytes .../glsl_to_spirv_builtin_functions/binary_24.nspv | Bin 0 -> 257 bytes .../glsl_to_spirv_builtin_functions/binary_25.nspv | Bin 0 -> 257 bytes .../glsl_to_spirv_builtin_functions/binary_26.nspv | Bin 0 -> 257 bytes .../glsl_to_spirv_builtin_functions/binary_27.nspv | Bin 0 -> 257 bytes .../glsl_to_spirv_builtin_functions/binary_28.nspv | Bin 0 -> 257 bytes .../glsl_to_spirv_builtin_functions/binary_29.nspv | Bin 0 -> 257 bytes .../glsl_to_spirv_builtin_functions/binary_3.nspv | Bin 0 -> 753 bytes .../glsl_to_spirv_builtin_functions/binary_4.nspv | Bin 0 -> 2129 bytes .../glsl_to_spirv_builtin_functions/binary_5.nspv | Bin 0 -> 485 bytes .../glsl_to_spirv_builtin_functions/binary_6.nspv | Bin 0 -> 485 bytes .../glsl_to_spirv_builtin_functions/binary_7.nspv | Bin 0 -> 1485 bytes .../glsl_to_spirv_builtin_functions/binary_8.nspv | Bin 0 -> 1373 bytes .../glsl_to_spirv_builtin_functions/binary_9.nspv | Bin 0 -> 1313 bytes .../common_tesseval.nspv | Bin 0 -> 1509 bytes .../common_vertex.nspv | Bin 0 -> 1101 bytes .../fragment.nspv | Bin 0 -> 469 bytes .../vertex.nspv | Bin 0 -> 965 bytes .../spirv/modules_error_verification/vertex.nspv | Bin 0 -> 845 bytes .../data/spirv/modules_positive/fragment.nspv | Bin 0 -> 377 bytes .../data/spirv/modules_positive/geometry.nspv | Bin 0 -> 1641 bytes .../data/spirv/modules_positive/tess_control.nspv | Bin 0 -> 2049 bytes .../spirv/modules_positive/tess_evaluation.nspv | Bin 0 -> 1757 bytes .../data/spirv/modules_positive/vertex.nspv | Bin 0 -> 1073 bytes .../data/spirv/modules_state_queries/vertex.nspv | Bin 0 -> 1333 bytes .../binary.nspv | Bin 0 -> 1129 bytes .../shader_0_0.nspv | Bin 0 -> 2709 bytes .../shader_1_0.nspv | Bin 0 -> 1441 bytes .../shader_1_1.nspv | Bin 0 -> 453 bytes .../shader_2_0.nspv | Bin 0 -> 1425 bytes .../shader_2_1.nspv | Bin 0 -> 837 bytes .../shader_3_0.nspv | Bin 0 -> 1509 bytes .../shader_3_1.nspv | Bin 0 -> 825 bytes .../shader_4_0.nspv | Bin 0 -> 1425 bytes .../shader_4_1.nspv | Bin 0 -> 2461 bytes .../shader_4_2.nspv | Bin 0 -> 1901 bytes .../shader_4_3.nspv | Bin 0 -> 2145 bytes .../shader_4_4.nspv | Bin 0 -> 453 bytes .../shader_5_0.nspv | Bin 0 -> 1425 bytes .../shader_5_1.nspv | Bin 0 -> 1265 bytes external/openglcts/modules/gl/CMakeLists.txt | 27 + external/openglcts/modules/gl/gl4cGlSpirvTests.cpp | 3444 ++++++++++++++++++++ external/openglcts/modules/gl/gl4cGlSpirvTests.hpp | 288 ++ external/openglcts/modules/gl/gl4cTestPackages.cpp | 2 + framework/opengl/gluShaderProgram.cpp | 150 + framework/opengl/gluShaderProgram.hpp | 102 + framework/opengl/wrapper/glwEnums.inl | 2 + framework/opengl/wrapper/glwInitExtGL.inl | 5 + scripts/opengl/src_util.py | 1 + 67 files changed, 4037 insertions(+) create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_0.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_1.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_10.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_11.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_12.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_13.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_14.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_15.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_16.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_17.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_18.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_19.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_2.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_20.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_21.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_22.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_23.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_24.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_25.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_26.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_27.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_28.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_29.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_3.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_4.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_5.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_6.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_7.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_8.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_9.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/common_tesseval.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/common_vertex.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_specialization_constants/fragment.nspv create mode 100644 external/openglcts/data/spirv/glsl_to_spirv_specialization_constants/vertex.nspv create mode 100644 external/openglcts/data/spirv/modules_error_verification/vertex.nspv create mode 100644 external/openglcts/data/spirv/modules_positive/fragment.nspv create mode 100644 external/openglcts/data/spirv/modules_positive/geometry.nspv create mode 100644 external/openglcts/data/spirv/modules_positive/tess_control.nspv create mode 100644 external/openglcts/data/spirv/modules_positive/tess_evaluation.nspv create mode 100644 external/openglcts/data/spirv/modules_positive/vertex.nspv create mode 100644 external/openglcts/data/spirv/modules_state_queries/vertex.nspv create mode 100644 external/openglcts/data/spirv/spirv_modules_shader_binary_multiple_shader_objects/binary.nspv create mode 100644 external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_0_0.nspv create mode 100644 external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_1_0.nspv create mode 100644 external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_1_1.nspv create mode 100644 external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_2_0.nspv create mode 100644 external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_2_1.nspv create mode 100644 external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_3_0.nspv create mode 100644 external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_3_1.nspv create mode 100644 external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_4_0.nspv create mode 100644 external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_4_1.nspv create mode 100644 external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_4_2.nspv create mode 100644 external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_4_3.nspv create mode 100644 external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_4_4.nspv create mode 100644 external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_5_0.nspv create mode 100644 external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_5_1.nspv create mode 100644 external/openglcts/modules/gl/gl4cGlSpirvTests.cpp create mode 100644 external/openglcts/modules/gl/gl4cGlSpirvTests.hpp diff --git a/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/gl45-master.txt b/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/gl45-master.txt index c5b3131..db5583c 100644 --- a/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/gl45-master.txt +++ b/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/gl45-master.txt @@ -7403,3 +7403,11 @@ KHR-GL45.polygon_offset_clamp.PolygonOffsetClampZeroInfinity KHR-GL45.separable_programs_tf.tessellation_active KHR-GL45.separable_programs_tf.geometry_active KHR-GL45.spirv_extensions.spirv_extensions_queries +KHR-GL45.gl_spirv.spirv_modules_positive_test +KHR-GL45.gl_spirv.spirv_modules_shader_binary_multiple_shader_objects_test +KHR-GL45.gl_spirv.spirv_modules_state_queries_test +KHR-GL45.gl_spirv.spirv_modules_error_verification_test +KHR-GL45.gl_spirv.spirv_glsl_to_spirv_enable_test +KHR-GL45.gl_spirv.spirv_glsl_to_spirv_builtin_functions_test +KHR-GL45.gl_spirv.spirv_glsl_to_spirv_specialization_constants_test +KHR-GL45.gl_spirv.spirv_validation_builtin_variable_decorations_test diff --git a/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/gl46-master.txt b/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/gl46-master.txt index 893ee14..5f3dfd8 100644 --- a/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/gl46-master.txt +++ b/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.0.x/gl46-master.txt @@ -7403,3 +7403,11 @@ KHR-GL46.polygon_offset_clamp.PolygonOffsetClampZeroInfinity KHR-GL46.separable_programs_tf.tessellation_active KHR-GL46.separable_programs_tf.geometry_active KHR-GL46.spirv_extensions.spirv_extensions_queries +KHR-GL46.gl_spirv.spirv_modules_positive_test +KHR-GL46.gl_spirv.spirv_modules_shader_binary_multiple_shader_objects_test +KHR-GL46.gl_spirv.spirv_modules_state_queries_test +KHR-GL46.gl_spirv.spirv_modules_error_verification_test +KHR-GL46.gl_spirv.spirv_glsl_to_spirv_enable_test +KHR-GL46.gl_spirv.spirv_glsl_to_spirv_builtin_functions_test +KHR-GL46.gl_spirv.spirv_glsl_to_spirv_specialization_constants_test +KHR-GL46.gl_spirv.spirv_validation_builtin_variable_decorations_test diff --git a/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_0.nspv b/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_0.nspv new file mode 100644 index 0000000000000000000000000000000000000000..ccdc3ee3a0ec295837107a225ae35ffe9003cc50 GIT binary patch literal 1209 zcmYk5$w~u36h$kEag6gk$9agxF;Nh8>BgO3Am~C+5ghjZnqTEc@SG+Os+&jMTenWV z9!u4fQl-4slTwMZH=W@AOCg#{Q1Z@4k^3B9(Gqxp}HCCMRg@^ zq$uYa@Q!^H$90>IGWPUvk6&iI_6ufZ?e7@g{`xCco4MCzXWs#|b2Ylyr$%|7&Rel= z5S_0Z!n@A(X5UuW` zFKZ98U}w-CxiJCBw(4|V~avx|6H@5?OMCA7SGu*>M2t>b0AH?v?@ z(DHRE*j04SuHl0<3w9kXZyxLhI%hZWvOZ(8V7Jin=D}{Gb9M(W>$@-ub{8#g9&7`h zvwL`1--lVS`)GOdV4LWiJ;2NQZq0)AN0c`Y_6VJ`$9P%40kdFF(DLTNo}zQMg_rd^ UFblSgmN)m`^FMU%kJabYKawCTIsgCw literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_1.nspv b/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_1.nspv new file mode 100644 index 0000000000000000000000000000000000000000..42c8063c7d3690c7b0831559af7a3cae7a1ba4b5 GIT binary patch literal 389 zcmYk1PYVH26veOk=g*8mO4*U6nk{H;c)8~+}7OaSX;vFi3>708yMXCdb!1NIZdSm&ibwO)0 z*F-$bWRdYvhqo`)#mjtZ$(avd>oyu$t0FhnnO@10f+un?w<+-NzQA2{a>zvcN?iy) D%tjJ7 literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_10.nspv b/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_10.nspv new file mode 100644 index 0000000000000000000000000000000000000000..c7def2602b6143ec390c1f92524f7ac577f3cc1d GIT binary patch literal 1293 zcmZ9M%}!H67>0+|B8u`O2>yEz|A8u{MH2%o-E`*_K-`$98x0quH{b;rV~la(y4;T& z6Q5_8?_}a>Ci6Y-yl>CUd`+i%DWz^_{cK88d}h)v?6a6Ua7wdjI?pf1ug3ikA7A%} zqo=OVrLI$6n@>GHDV<@wJACtAeSw_3$nbk&bjfw#-v~V%bw)nN+VSA{@a^{L`o-YE zDKEoE#i0L6%Y*!VH(K7w+_XH*e7EIM=7%lsX5Px2U!U2-9pLwVCKTAuT#Ivk% zCU3)fg=(6)VXU%0E;h4k4LrlF=GcJso@ekJ1kVB|lkxs0Z`5~zp+`MDbJQo3$zJe$ z=J7#f7GOQ<%k0cPxSvbR*0G-@YTu#m{x%Ei@kaF7BOlNB2gP2$K=my4%Y3l?3iiA0 zSIzdTX8Toh^B>!Fv;7M8{q{@VXZP;ayR>$n-q9ZCaQ!mF_23n1J>NO4 zceBdSqi)`FsfGV4b)CNkoBvtz*QxcWoA(~nB7c**&fkK~|0wy})Oys-dv9uyU!$(` zcVP3sN`9SMkGlDWSuOJSsO$WF*!w7T#W=4=%?mr$Gda;`rmcFFI- zS0*g^y?A@Xz%8?o4umug)~)Orcj1dj}smt8;okE;+wJyywrL>dMob zJBxQ!=H6AA`xfR~>}IcLGq%sUH`&M81~IWq)SP)VW1i(Jn4D)B_wL-oy~UzFmg~5> z?kr-VF;1+;Rn~Y;ELLi~AQvw+#6sg`uHzmx#6n|&SdCvUq=a$#7XBHE4uK)Y2Mc*8;efRmD=845Z z!#ubP#Bv|t`kyUgVsd?Z^WeTEmfHtY?h@vCcQ9+wBOX2Ph|8X3a(ljD)}lxJ50y{Y EKYgn>)&Kwi literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_12.nspv b/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_12.nspv new file mode 100644 index 0000000000000000000000000000000000000000..f7a95cca1f8a1c52c8491d4728ed95109eb3f6ef GIT binary patch literal 2189 zcmZ{lSx*%~5QT?*RZs*}TrQ%5idRKc6v16wt}8Am7$gD7RS+VE5a0Z3KI{MS#l-KM znMx)^n^daK>FU!}J>8d@nj}f;Y6qH?tE2#x%egxl^G^Ti}GF>Ted|fP$ zUN~#s&ZJJ4&UKJePpqvjR6onlVx8p3HDh)B)#863-T+(76}K=~-5lAdep^cCcY?nz zZH?T3l<4--j;? z%eU56*1o_^v4?ve!t6ir5n_i}P3P?+aB<$Aop*GRWnO>UdA6n-jYhZ<<{rIZK0wNu zTLODla#{~-TT?zs_HjaO#A4SLN8mp4+nF#=tsQxi+<1=d(QyiFEuAUKYUv_YKWf=S zY#s9EJJ*XjhB;OFy_lTlp8N69lQoyX+iSL7&0)>`_)=>1Nt~ygHH$rWhvzkjSI_(7 zenWWolaHQG6WfC|I#|M$BZ%X+&aB+X*i_~u)_UbVIH%tRwoo2l6#va9fFW*Vv{lvbL zBKDmG9wPQ#h$mR@J?X%_Ba2|~(XO0Z&d+jp&UtSpsmT51Vto&>>#O8@KlWjA-V^h! zPcHHg5Eu752$uWE{@zdDlbmbqMeJJd$5Ctmv(^&+7$)~AUwb^~Tx;Lr*!Lu{`_9n) zApR64XPut8=O4Ml#OA)vbI%aVnd>(wW8djl9e*6vGAGubBQEyn@2cEbsa zox>floa_Hp!(DiF%nOYv;$j~au$+C=W4?dichvESSRM01<1ulj(UN|TCtx`>+Og0m z6Nk=IVztZ-ooB@A%;jhLoLJ6&{#DB~ygKHE#tY(1Bdg^lSWb=q)$)otwag8j*Tm|) k&uf_>ma`}C*Y-Q|22LIGe1HDV$QjS#=deHg7Z}6-0=u|x8dP@}jFSE((-SmArqt>%co=LeJ%_-M+n2lNk{?qW zU8XtjC{2!3?^4&$dSH+9JUVfA>B0Z^jHF*z+?l>~pXr;G-+8OC2+Vjy?#+j@(rqUn!p*4sJ?Hf(!A%E6TV07 IkH2;W7Q~+xIRF3v literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_14.nspv b/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_14.nspv new file mode 100644 index 0000000000000000000000000000000000000000..aee9d4bdfa73e2ef2e9165614c7c745de0728d5c GIT binary patch literal 517 zcmYk2yGjFL5QS%V-58DLVn7i=qLxY!Q4vHNg*53btpZ*U)Idz(^Z8UZLcZ^J7c$E* zbIzQ9E}LZ$QRGLf5gA`I`e3aWIXI#fjTA@Yhw<=h{xm$lIJMr6!jNhmG%Mu#$K>r( zehu%Uk!#`wUrzj?X$iZmEn(EZ%qFjQ)A#9&T+JqN{``G*PaJ{O?Bkl)y4XEyd`PbK zndZEMG&xefP2PYT;5)qM=!D&60RG=I5`SG`XL{)_)7LA#^Omi~dnj8J)Y)&N63N+5 z?9Q6=J4E-f|1sFSi)$w!>pfhq_DlYZce%6X+h3THcmwOKHtw89SZ~~_ID6gl!kgs& I_;XkI0u@*mPXGV_ literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_15.nspv b/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_15.nspv new file mode 100644 index 0000000000000000000000000000000000000000..c77aedcd4f6bd0a16d1fb356670a1ab00a4ab2ce GIT binary patch literal 549 zcmYk2%Sr=55Jf99PK-wLFh&tUMqMgFL`4wYC}fkJKVZNIf*Ocf_Wo8yP&J8TFKhqx;d|bM`nmJ3q1CirkcXZ9GfV;(h%3 zp}qn-c+?so=gY|7Tw0(mdJ7c&&(rbC?c{ATrPi}fo;`h?-jRoJJ$t~A+n2lNoF7md zJ*GKtKTVEQZ&BCLO0dm&9-X+ml<@yOBk5Naccw4hVft$2civ*m`7X{T4Sn9XR+-ei zPwvi!^V?+ianB>Tbq5&7`~mx2peFiwHpnG#rf1|mU|ev`5M(dTEHD1 WnCAO8E6q9HbHgd$tp3ZCOYjG;<`(<_ literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_16.nspv b/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_16.nspv new file mode 100644 index 0000000000000000000000000000000000000000..e22b70c00ca154e243872e340fe1810ca71be36d GIT binary patch literal 505 zcmZ9Iy-EX75QQhZ*(4gxpQKMnDFh1@L9k7eE>EzKCXm?pQ~PYbijBU3jo|m~-j(27 zhPmg=%$d2jRYXLdExHjcPA?{4Z5$c6j#FYkIu%~6H|yoo^LBZCb7kEiazm9HM!|__ zoEdKC zeM(PTO8np-|Avb7L);$oAE|c4{aB-^^}nq*|G+lRmiuA*JNy^jw-^@y literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_17.nspv b/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_17.nspv new file mode 100644 index 0000000000000000000000000000000000000000..92012c46362ce5507ff8464180fdb5c523f5c72b GIT binary patch literal 937 zcmYk4OG^Vm5QIC48>7)YjPb2WjE{p5L{tRPtCyVg7X%V8pdL*0>~HhG=s^%4Coh8a zEz>fyG*jJORnxmWnZ(R;+4iJaMo+Z=a+-AU|O3=YoqJl z{h&{+CPzG5@@6VfloQcc%vkGc&Vvtu9%)ciVC74Aj(BFCTwscPcSOciDHN#8dpA>@1hG6<7MT> z==Ys-iga{(QdIp_)qizYou;jxQtD_QKaf%zzpiv2?CMYL;8M?^yHjU@*VZ@Ir+0Rr zPS4I=H?JpksESx`s`E>!hHN#Ouk`n^Pu!2l7t+DLcJN0Wbu#ij;)BF?n(sGJMf?c* zb#v?4%!3lkx6|0#F5~rdY(M^Rqx99%Fvi~OcJm!t&a>#Z`yBN&4t~?zYrK54xr-S0;0bAP_d{UyiYDq!v+ z9Af+7vPK^|>dJW({4b~cIp+Y_Wv-lJ`{wc6W>l?`{#EScnsTjAzmimx;=<< zeGb;&TlrR~Cb!sJXEum9uNPovalG=GYh7{hp2U{-F{icXXAphP%Y4tJFY?b}JGUor zYnx|}m#Acqt|0bRzy15dX`Ry~Vr&A@uZ}%a*!iBX)t;;Pjpchja8CKA5jo8Xo@>}S z&$o)lf0D*p@!Y^KmpQ@X|Jt1Ad&P4Tzp++4v-ssQCwS(tbDkd+&pdu(t$1$Xm&=^s zS-{SDepWoU@f&N!a|gd%<^<0ocFyyu;#tCPtQF5Pe!0vEp1asN&u6|sXR?YI3m)g} Y8xhCc?qSQhiuir`o$LF}%UeMH0u@_U&j0`b literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_19.nspv b/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_19.nspv new file mode 100644 index 0000000000000000000000000000000000000000..276198c575bfd25bbd26b8790caac579eacbdc33 GIT binary patch literal 1213 zcmYk4-A)rx6opS)3n-Nz5l|Fu#eZrw5se7}FSy{Qc;ge06bK1YQ=5o)`f9#_|N1K4 znD~7&XD2h0mA%%Qb@uF;b85AeQlq{$nNp2=Dm_7a&8IrLtWR^@piZZW!r$$`?)Tn} z2fdAF#gduS;Hh0wnoX1G996v8KR%_THSh?`k<*_74emPiGmDzI)qIm@=Xv%P$XnFG zS;=SRA41qy3|u;mL3W-{r05ZUARj zn^Ai$FrhPcifL29m*5k4ZLmz9pI2yeZM5H}C)UwsF95GDQ|M0vJ>i;LRNwEj&8(eE zZxMZm+RoaZ>btsi)|tU9tc;b#BjY#Xi@S#^t({3RjKjeie3Qm?q&Tn4-${@kA*N7bI3c!!!nI_JJlq3Xb)YWj!++E{*SUC`Rh ym57H-7Bk*bc>7W+Uh=6WCm+7nZFftC1vT!ij;V@RG9Pim6}U!HA{S)Jp!dBC{_w|8XJrj%5$LW$oo_{${YAY0bDeuks%GMU@Z9FRT23d@2pxncm0t zaXa#%v!<~qqahDk2DMY42d+A#?}w3j#~C%eg?ZPAhdTO}5uN_%+eUQi=zB(V=0e{$ zqEo;2MD#`DqsOl+yxpy<>|=f~aOMx3yYL2qb2je~IA`$|@OyWs7qi{DH+O0~s0F?r z@r|0}jPAz;!-ItR0Kf~g}UfMD7clPK`z8p+6dy$^JnNEaU*!X zo7~bHrZaQS+&MEzOJy^wln-lWB|UZ9P|oRCS&v!6mV}!PhNEGBmOb}R&raZ*R>66$ zr5duT>~-u?@HJUmC|K9WRUa$#cLKM&!0jlePel*fUlNXVYq4)6t%kUly3%|`AsrY>-3iMvVM+pU{rbIb$xo+NWF(tPa4 zxzmKq!wEiMXoBGbmcP?{&w!yp9eWPco0z(8@eL0A8_BUP#Y^IPvTfbahx0jiHZkuNJ|hCSsg^4tg8SAb21BRm>+-(nkhf$Uax~gLGdq?7 x8l3_I4~Evda{5wpuJ_6A?85>76%xr`>z7*oPt1bel`6>T{jDv3WPh>?**`5EE{OmD literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_22.nspv b/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_22.nspv new file mode 100644 index 0000000000000000000000000000000000000000..e5790755f4e1c076365778042fc1126e7dd0026b GIT binary patch literal 781 zcmYk4%Sr=55JfAGG0|uq#s~N!;!+7NGzfwq3UQHz5O6C&2Wc25l8hjJp5LMW;YRSD z&U8o(m8yHIx^DGM3Pm$36^|-r1wB>U5XM?o)H91c#hNXtZq^?R2iKP2Lm>*YqXNe?@GNjTD}#krBRYO1{?kN5H9 zA)aLMhoIOQPfl$-b(tHdVk^F%J9yru+0cE)^o1H)s@){+?bc1RQTi0mYwSbqJxS)Z zNc(X=>`oi94;EtJ(1arf4lOw5296w#d-hc!r>`%Dd|!@%(G9qrf2%{CVFqWmlr1TC zDpcj!3!0kD3l7R;6*{`Z3%WM3vpA-T8clMvz+wZSWBKC#NU9arM2o zv%4+77+F_^u*5p^EO9<4N)qcscuu?~mSN;x5mAr-2J>qcwQ4S{YoYfP?#J-km;B;u zeo^JWDM2T=bGgyDsESbuIv4xZk9bj5r^QunU*gn)`!pN*$Foo$m%m151C@`DBEB){`_HSmgEfD76`$r+ZkkuQXA+i&eX%d028PB`@C9ZmD~0xl!; z^^$Dw1e=ZDpL>d{;M82DQ3``r@9?KDFKwa`t89O~U(gKl=_*7qjmU_xr>j1>jr& literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_24.nspv b/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_24.nspv new file mode 100644 index 0000000000000000000000000000000000000000..9a744d405bd3f52f0bb14084ebb5913d567a15a6 GIT binary patch literal 257 zcmYk0F$%&^5JV^W{umLALF^SvAy}w*1DkZ7K(MjUMo;Joyn?r|5q$G8;4Z`d+1VL> z7A1vz(U&s1)Bx_PmBXc>iZu7_p>1yWQ?uTztdA5tl2$3wQV(2?=d1T)eC9Q9PKSUm zhd)?EF8)0e6l-&CobLCOi-I`=uH}#O;gs3&68@~DEvfc7*X5iy8~^VGv(L95+&l0E DpI8m0 literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_25.nspv b/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_25.nspv new file mode 100644 index 0000000000000000000000000000000000000000..ee0e1db68af3ae2b4438ca884c9880f2bf2e482e GIT binary patch literal 257 zcmYk0F$%&!6htSxZj1^*a}HdqALqk4v*VRT!gi$E=UkU_-faB87tB82esJ%>7jowe A$^ZZW literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_26.nspv b/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_26.nspv new file mode 100644 index 0000000000000000000000000000000000000000..d5fdb95cb65ad81d27aca48741bf7a83bfc43b0c GIT binary patch literal 257 zcmYk0u?oUK5JV?;CPoA`h`nMd1Pc{QJDYTVLBPgB8~sB6#J{i+d~+CZmtk*qc81Gx zNii(@Qbv~=z+IIBTpFrK^Vpo4`u;fAo9){ANYNu{W978e1K0L)^L~QQyaLYY5b*{0 zlSR(Ozh{bKZNZJx{ho1AFz3Lv`f)y-GCN+v4`4^Cea>|`=gr3dd%^7U?FaWBd;xzO B4F&)J literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_27.nspv b/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_27.nspv new file mode 100644 index 0000000000000000000000000000000000000000..d98739961d2b8a7cea14f0f677bcbdf377391f0d GIT binary patch literal 257 zcmYk0Jqp4=5QSfM-53$nAohx-5G+)@flWG3AlO)FqbKwx-oi%kdy4^Q7-rwRAGS!6 zVp#U2g03_GyJ`inG*p@Qp*^?ew+{I%#K$Uxpt)5=UkU_-c07jv@= A&Hw-a literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_29.nspv b/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_29.nspv new file mode 100644 index 0000000000000000000000000000000000000000..fa82565cb423722bfb8dab8c47f70d5f18744018 GIT binary patch literal 257 zcmYk0F$%&!6htSxZj1^*a}HdqALqk4v*VRT3_DWobFRxdZ#Mql3ud2hKe+ec3vz)B A$N&HU literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_3.nspv b/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_3.nspv new file mode 100644 index 0000000000000000000000000000000000000000..ffc43e142a597287d2f99d1c350637cb5a724e63 GIT binary patch literal 753 zcmYk3%Sr=L5JWpqqltMKjc<*(4+<)R=+;ekenCJNf)T;!-e2>p+z2^mLc`2Z+^$*!M^sJL zae;bpu>$Vh&_Rzgea!r^)4`>_3B3CO(5s%_ zF7?XWEWACq-b0}F!^!N?2li3Vtl!nS9UOYLfY~FUmf0b-dG*Y0QXGdl)qnYEXB^#}g2 L|I@vH+_zu}YeyXf literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_4.nspv b/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_4.nspv new file mode 100644 index 0000000000000000000000000000000000000000..58ae79b62bec4ab8e9f16646f321c2811222f74c GIT binary patch literal 2129 zcmZ9M=T22Y6orS5f)pusyod!wu>qn;QB*8gC@NSX5fc(c62QcN_yE3vK7dbQqJQ;$ z{A1$xoqIQ)cyD%Qt=W66nb~vBDXU5;Rg`ztq*TVgHZ8*aHK%fTN_D9^8z&}bCVSV` zU-kC&pE2K%Djc$0W2)kxQYGk*T`$hyo+;$>@ad(s*$=BrsfC@mmrnNNX~gZI zYQ{nqm5Ih=;am@T$87|^(cpDO{;iFCJ-9%4-U56FqaMy%@7PGBv^j2l6R05NXTANh z-g)aCTL|iZ#CoSPp2mXr!+-sp90`88$hY=4p4D$|@rk0IUX`awaOmcWbz>c@Yo9!; z`yHT@_Qt#NXRm%UwdjA$Kc*uaC_jr1^0~JTX0A3Ezi9-`3S4&ZO_H}+HbL* z_EM~$eHvyz?z@e!wjL&LC%hBSU@q!*f%T8N-C*m~nES{n#d`=n%!hU_IIrCYSL>X) z(C!DTHy_#q;Jmg2uGZd~3++L$dh?+zfb-f;xLTt?g!T|vz4_2~f%DqKaCP3VxzHW~ zt2ZCoqu{*u7+kG)V=lDaVD;uhdmNnCo`9?Mj?9I&2dv(FXitLGek$EXFW5QXgV3D@ zt2GxoKUBpvYqC2$2X{@+Y0hUX^yk5PSQGj_a9%$ESMS-(`QC;80$2}gLO%%3>o3C9 zcN6CF`b%&Wu+p67co0@ug7@E8T#g+ zZ?xaAyM%LJ=~Ol2z0#asdWP41uzu#l>j7A=FD0)juyf%x4R-E-uNmg_Gap{FV7-Dr z1l#|5X5H5#!n69ES*xctvA@S)eXaAGG|%{iP~$TRuAA=kw`$=3{>gU_GpH%~r+*;tz^J;xC3xY`y>h literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_5.nspv b/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/binary_5.nspv new file mode 100644 index 0000000000000000000000000000000000000000..a21b53e8259dbc613af9946b10007540c653705f GIT binary patch literal 485 zcmYk2y-EX75QWd~W|L?%KL)K=EQMg9B8WCAY|{Az0WAV*qp`B^*?cM+!S7oV$h{0_ z&diy)GqFG53$Mooe4d$B- zoaI_Ge!j`?;V0j7_4{~@l%swCT4P+jc!;S#;iVy7(^@AZP_40RCUypQ@;K8k5&!0v vs5FG53$Mooe4d$B- zoaI_Ge!j`?;V0j7_4{~@l%swCT4P+jc!;S#;iVy7(^@AZP_40RCUypQ@;K8k5&!0v vs5A8_z7Pxw0nwO3yc_WHe!fL{hh=IlVOPM<+BaFPt>508wH@bqUdQ#@%e-x1?cgu4t>byj>t{P9 z{odCO>k+V@!(%^v2jttwbNYG5zwtOrL%iOl^I*Q*dvG3t+tYbya_6DRorflO9)f!| z=OMUza~^_Q-+7Ra*`0gwt+d^TcRXTW##caz_v*VWGykTJsd2BXAT+oC)7*i#z#%ZE z#`EY`n#b7gSB>X;0@NGrCm-7z zn@`M7q?${an@n{+DO~`Eoli&ZPf;hI2KoeQ)K%d>*{Gw)YvdQnovxpDK0h7gCxSm4 z@GHUB2YeP@AZIE4TC4}X<9`3kfZu~39rq3+zd}%S4!Q-a?|a1B>lVZMTH>{-d(tU$ zywY5cCC$*aeYfb}lN-+xjj%Ss99~>v$;~(6W329pRk+$q;Me*2cJOgH&u;KWNx$x{ zp|vqSkD3R>`MV#&eRt$niM{&zxK@RX{DZ0s#P~Gr&QrLo!)?b7E=|R(oCAl=ZE&^cJpj-*xcRQ zHa?eX9yvCj>ikl=g!MYdefb4+;zi7R!fNQM;6D&`GRhk9RbsuJVdvYcar}DVoiSbm z4@>bofs6S4od5Nt_uc$@dY19YkHOI?%=nHMnH!vT`e(TYUX{9sM}vs(=J;`c$hkzd z*1JyKcC5dQH^te&R;ZcbWo&E}Jk2R5Zh)^8Sbh_%b_Tl`jSd3Of_dI=QIXnfm^t#1 zGlzdMYPSNaVy!UQ%dZ%;Sr!VK~-uU=U{=&F_ z?_iy^J7j)fcPOwmxXoaC(2exGCZ6?hZh-hLJOEqrt2)jL=}W)I(c)Y#8Hrp6f=Q{%Uj|3~C4_8;1^OgsPp literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/common_tesseval.nspv b/external/openglcts/data/spirv/glsl_to_spirv_builtin_functions/common_tesseval.nspv new file mode 100644 index 0000000000000000000000000000000000000000..ec2f82f407e457d4c0c7e08bc4be8232b460c9ce GIT binary patch literal 1509 zcmZ{kTWb?x5Qe|z&{nHGSlfE2b!$CWQw0@46iS77(F>vCtrWY+LQEuyAl~^0{89cY zZv>xbcc+AEzc87ZcjlXSW_FXQR!XVa*qTXciqC9%jPF@WjnqWXrD^b#y88$FozeKH z^W^Cx&KTw|*fw)X;WV>kI&;}?N8*^{-}^e{*4 zQ}4sueE2>ej`MH0pcSrdY%nUu#h?#5Q|8N2;zfUaP<+qLi(kh2eH#0JpRID| z@RSeY4c)psPw2qp6;lT$pP01+tKNg^`F4pIH?PZ6au53M#{8I5%oEs2u9$6-D`pb& z`O6h~%P`8h31&aqt60+CPJBFYEYc(cTx^z>+s=7*jIx z&Y@!mFKXX;#pIbU^QyY?=r151`&vZHW4`s4(Dop1J$?5m7JV*bd(6LxHf9a`bSEeK zjC+@eWr*`#Mw?qE mfNv}~A7YDnKR7$s@*0zK2kjrS@1wO|v1xtt{_tdk6vof)x~pZmsrgcx&E};dUQ`58Aqtz|g(7q-l7kFvv$8vac-3d?Q*{&g z`_0a*{f9H>f1dO9oHNr1POG^+8`0pIi){hUVl=TM=A%>U{>k~t-nh8hd;eiy|3b7> zrLP-L%li!PUzb^~@dQ~y){q|Z4r%c;(SIo1jv1cE_%?_+MS6EQ9FDHIf^^~q`g(A2 znvQ;?Bb?%$3iqyWIL?Y}n1jxi@$xS5EHBQp`_#DFXMcQ$gY4!g8yA=P&vfc@B7L`m z!PM7=vvYXl=sY)d!wPdg@+Jh2k4oOo3wE4OdVogsnb;Y(5IKG)()m2|6E(&3i~S!b zcQJX^x!%RxWgn0AjI)vAbyF#kROPZ(T#5 zBDY1fJoL*=+wUl5pJjA{Sl2$KOW5unf?SAWgV_zW=zrPvp-p!Sp zc7it6KIUup5V6|!duV@TSMJ!Ic&zgm#P9YM%N@JNFGR>^9g)i!5%PFlVW=s#QDN4v m<2EbIUZ;E=xxPWnH(tLp9Z=VK-XiYMJ;_7c_WmpUR8q_l+w$ zL(x;!O;t~;6%l#1zZ}uxc47nW8Ab+==teu$>FjDYdU{@r#>a>Ddy!jGug}a9Z}Bj{ zdsJTm17_4ZAm?V(cT5Y^|FZ>(^EdVUc2eC}HSdD?F15a1#FT0KyTBv2=YFeT6KB2m zQc9%vHt#lC33iz0gNd74!hd#(q@Ok141cu+*S7>_95vj`FK__YdmTi)On!Mk@xT5c y@z;wJe&c>-d(8MiDX3NBwZ>cjH&nfQK+TLxwsij?P&Y?!agLjN+xukOQ}7LD=@<(D literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/glsl_to_spirv_specialization_constants/vertex.nspv b/external/openglcts/data/spirv/glsl_to_spirv_specialization_constants/vertex.nspv new file mode 100644 index 0000000000000000000000000000000000000000..a0564fd5e2af15a8d89ab84fe3c1efd5e5487354 GIT binary patch literal 965 zcmYL`TT22_6orqMQOnBA)Gj7QkAd`15ky5KnBapU^cqq_3{0cw1kqE!tzXqk(E85I zu`_J_c*=CGRE_+loCZn%p+7LQblNC0mYzo%*hvQ*)5x;a#&rXPMm>kZ=DrUvr z^ZI?81QB3ewk2!H4rDofS@~}@^-Nyhf3Bw)W#QNGY2?oz{dw$v2#QU3?!=~xAP%OH z*rLrxpXGxn9tWR3c`n8*#qPpj)(aN#BzpFjF_aT~55r~5lRh+aJbh@Nxq&IiTU3__ z9Q2e`ux}GLh>{s%jk#BZ_i&tdT(Z+-Z;nGNdFXN+cR2RcSA;uxeKBZr{}UKp#Jx1m zzQF}qO;yw#ss}x}H*_P`ku_DXKi^_z)rCv)9U131#r(r)Zwar;QxDhHjajY-F|4D! zHF@`r%M`O?IOc5FyreI4z!ez>U7PaEA)kI#c{IS&56mv$s3&(@X3WdPDUWbBRITuTX<{9h@(ko^G!sz5#f literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/modules_error_verification/vertex.nspv b/external/openglcts/data/spirv/modules_error_verification/vertex.nspv new file mode 100644 index 0000000000000000000000000000000000000000..33f7707a4ef886b6da4970731f758eb7dfef4efa GIT binary patch literal 845 zcmYL`UrPc}5XG;5cC{?cOzk0LqsKscs0gAU5=`(R5PA)%B`$2M=mycp>r?d-bbfdD z+AQPTbI#nExns%5D&>=!F(rLbEwkm$ zRsFutZ3@_xx8*%~UtZByR{U1cz*P19=LYK05PnOZALG?iyvpKFL9sc{8Evt)nO&q} zYc8Mp9B^hsLFY!iWam*=T|0V`ePS$Lveru;6%$?&Skc zM#>7^+r&-MyoXq09;EOd%tz1VJI(jzIc6n~xje@ijy;W~a3*gohS>&k49r~UL4nyf zIFxsEi+jhaK~2s*ozNnAU-$LrJ4~;xa9uHyW2Xh?A7=I=;cZ3k!wqzzm#=|_N6On# z^zXPXFgu2$Pt)b)b?F0c$uaKlDbkbL+z0b^IP{Jpwa~#`MKtP=4`w%T9? z0$pG6rNL#X|MhTsj@#^#-E*J*Q^AwMA4ucC@!`zrYBIA&Zi~6Rr#zH46#A;tCmpAL zD4xH`oW3eJZ{TP6HAOx3=fl~Fw$KmQ$1Dy#Zz*NPwN!T11?o3)nG64@dntSY{`?a! literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/modules_positive/geometry.nspv b/external/openglcts/data/spirv/modules_positive/geometry.nspv new file mode 100644 index 0000000000000000000000000000000000000000..8522d2d75fe33ee357f2d6fdb11d0d5ed24172c0 GIT binary patch literal 1641 zcmZ{k+iDY06oz-2qz9`#*pr7^r&g^RjrE8iDy2fb=!H=5R*D80h>0X4h*y0jU%|)F z_Yf5Xzi(!C7>nJ*Vy*SB^V&008w(-S$2KNHsPRmOd+46|Fvb(YbQlK@VRvtTuRYA( zw(mdK(moUFvfMTsrgE);{{A5CiBCZ@&?eM^=J3$IoXd?|M$F@*?Lx(N4%rHI9{c!8 z6HTJ3HPo&1Zl~Yv4+^_AvrYjti9L&+LQUqlqHp*0%g*3cXOMM1p@J5;vbO#(&C-4k zbRze6_8d=p*?#)DqhGYy7q*>l`r&yx%no{QIwPCCYx~&kj%@bhK0Nkw4Q}qE{fK+= zx|M#!kLyRPPy8Bc&{smpTL(g=Ba+x#P^$+;LX1*jJpfnmhU}l<)F7-uhc_8EG7zKr3{^2axObm7q_; z^%Z|y>b`4YOXw%y3FK*&dhBNv{Uo@tV&*#quR-GGQ+Kyw=9`5lrEWg;Iml!DJX~LM zYPa`AD1^gjvHlX8v+3`5X0OGJjc^9pSo6mG39>$mM6H*&b8SG@a*oSzbBL`WdH?1S z(eh)I=HsDryI!D7B`Q2tHfg8cS`*s?~L<$XCCYS1Zl#J zb!NYR>u!U(!_$y^cehXQ(Y64IKP7{AtggR1T!F;gt#)@#<{t(&jwA x)3+h-MIUES*XJ8sw@-VvmOR$lLblc+Iqdr`B<4NDJ&0BJV9(#l`3HIg{RL%ZbMpWI literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/modules_positive/tess_control.nspv b/external/openglcts/data/spirv/modules_positive/tess_control.nspv new file mode 100644 index 0000000000000000000000000000000000000000..0bf59a11dfa0a9fb3ba49115121e0958fcc31ad3 GIT binary patch literal 2049 zcmZ{kYflqV5Qc|R3JM~~%?m;+-ch^(qR351kc31Mj9*QI8?#B>ns(b5Klyw78U86R ziHYxXc86@DJo>Fh(!!uwpFTsjE1NZLC4(Ebig2_2!{fuHcKUv4 zdF3JeXka;IcHTz9UY7o`9w+c40XLh}en;|H@=UTR8MCrJW|t))zrIV-zbn{4&UqYc zVx=d$%|^2&zM_0)9~$otl5X>)p2p4OU@x2_S2uH$Js9%J?@iQhA4c7%@w$^nE&0Gv zPmw!FlANp9YQ`N!t+!DtjXuj%)(l72xua$~CbQ7N;7=a{9w+H>{3XKAIqoKIw-JBZ zi`!{EIf+g=?hn^#G)_70Os|ADJ1O;6Y(2C8sR^7Fau;d>?^P3AubSX`)x_H=Pk7+{ z{9WeqSlGPFuw+Pr&3nL8$G)O62l&9D4CJUOANkRzrB$?7B{Ql;m~U}yf!3jX-PQ)f-Wnp6j` zY4>wCrPDX+yrrEpVC226ojBmsiOsx$dE77cJpLblA5TEla+Bpw4Cyn`|Ctz?0eowW-`TMR(Cnh*~u=!sABM!6nzc??1!}+^y zNT-$zFB>+$Ww2HK2Dmr9WD)zPkOA!*LV1HR33KB1RBrFci#MNoz6zb74@nSsYH@=H0-48da;`6sfO508%x|4VgvJ?wt3 r=hBP)-pXxyL%+8rydO9*z2`g9wV^?;lV~P zKiSyY-ZVZ{MBNp_beMo0g1J5)Wo=YAhfE>YkY!{InPHEdg^KO|h}W@e{LJ;6Kpl29 zr@ndfwApEOx<%X?`Em3|!xj8bt&i{0?uWFSr{8cnK_AyP*6C$=)@g%|6?}Ur@T{F5 zX5UkJF=j8snyu{1o2-`~wU5)&nDa6AwbeR})#=|eyXr7KJDm4vuh;B!x+f8D^zr}t z6n7QrQ> zd&JBYF>NvLbf1X%|(1bFk&F!jPlAfHjIvkVSgo zV<>$4Oz_9ia>ZYizVA?M9)ALzAg=Y&x9A+EF1B@zS<`Rw8RC01mvh#a_m|hPi~Iw35ORwE literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/modules_positive/vertex.nspv b/external/openglcts/data/spirv/modules_positive/vertex.nspv new file mode 100644 index 0000000000000000000000000000000000000000..f7652899b1fac080956408d3991285ebad70139a GIT binary patch literal 1073 zcmYL{O=}cE5QaOuJDX@UF~%f*#5lpD5*0EgNBn+2uUo-Q>^AlQdxVwPkY|AZP2(brc>dQH%vlA0Yd)V=vrpBmt9}4s zd*0aGbY6G$w1r)c^=gcK-F9d7&&s--a~8S7roK3;=iPbxrCQ`vZ|<^b7P$g_>h=^o z>c7YXBR7ioxjLLS(^+5R-RRQ`K0e~Dal9+saof*?4dDYB@8`)rbKXHtpEzGGfxA4xf-hLZ+ zHOSjf>~7?I-`YD^2*2K0e~-v_)n>ie-O1(pU1HBus;qm6$z`*jz4E@*XfLsQcXq~Q z!Y}y}?%92Moc9OD@AC#${hOHDKfwVYv-e)3k+O3W05GJsu!!rrad}u{xCQL=$J2*Pn9abm1uU%Vk9MSJTtW#an_Slr#R=9bC$$u%XyzYJZZlk zj9eG-h5Tz~oXUdv$T^d7s!d#A?An|}wbPu}`s?^;g( z-NrU2&36ww^}pZvt*75!D~QMZ2WWRSU+f#2>z?)#`(|R(4PME)b3`}mEyqxYQZJZ$)sw+S{^-aPl*Ld_Xr-=9H%pb7C#{Hw}TjW0=u1M|x literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/spirv_modules_shader_binary_multiple_shader_objects/binary.nspv b/external/openglcts/data/spirv/spirv_modules_shader_binary_multiple_shader_objects/binary.nspv new file mode 100644 index 0000000000000000000000000000000000000000..1ea715f5eec383b22f00c890eea265580c060728 GIT binary patch literal 1129 zcmYk5&ubJx5QWQKC#y!Y#+bw(F;4WT1P>~LsEC0zkV7QkRf0}rV4Z~QDB{V#&A-Zv z;P>@RFWaG}`n`Hx^?GJA2v+g!xNd%2$h(u_;Nd7jJcw6(8Ebz zr=Je1^N-beTm1yWcD#FQr?a}PPaD`#(tESS*G+p=|EkpGn)9f=o7QK0^{hQ^K3DUa zcd+(-I-S>wa}R4qiEfqby{x}nz;e#HK`sgVI!C-lxb$_C>>Ty> zTPLfPx1U(g`MlZk3x;tm5?)RemCvZJ!ovVPf+tW|rF(M+-6FZ^#JGs=kf0UuIq zCn=WqHD{!ey|+rMxl*!TD9x2WCmV(RVp5))_3>K2|3*?ucBM4q>b(x-&mU~BB)gw- zyUD@Mo>G0SF3mpoYKl)8z6P%I`nC4&LW-cN&+@K=8~hoSmzS1GNj`tT@<-Er?&ClC z<;{;@e7@wk;`WxmYwAs<7~01lrdTRdypUq4N%5-`tD18;t>?~~WSkF7Z@`=%OrO9f z0`3p^WWeYpP9FIPIU{2j?oFY`=p{~{iG$-f`iawb;@~*Wd5H7Mh=b!e=OfNrAr6k? z=tgh1tX);8)1%$k55Gfe>NIC%XzUc$N8mYfvce6T;V|+WJ+FTnQkZyE6k&D5Y@ww^b^Fw7fZ7^de8 z!}OS8`xoSYZ*gv1Uj%j8n?XN*is3hjwe*qS5bhpKAKEH#R|V!fiSzp^@Ib&*+K;|8 z%jor2Vb)2O=cc8G+F;9Vmrvi9q>wu~CWB)b*C8K{o)~vLaGZ59yoXNttS6s1^*9?m zKIh`iSZ%%;-iqycRz4iVxU77*xOPwA;@Z99Sf7; zvB3EsQ~Bt$^Nq{rzU?eG<-;+IyCokkKHp^E((~2(@8h;O){{@1?`K1r(1!-%rg_@? z|1{qbjy2B+!(ohA^Ic)yh3UH|AC6(%efe;#Gj29;vE~QjSWiB2(~Q0u8FAB`lg~G9 z_xwnHta(lt4r5T;?)kBN-j->3A|H-nTwXq0todo+V$Jj7SWiB2(~Lee5I4<>@)rW; zZ7j)R&Cdb{&xkcI3-dlr-*fqJ4C7wNhl@483|y>vMI7tNCvKY2hX&%N`L%q0EA5`& z$d5I@6^6qYvF3Ned>^Loy?i)^aUbNv#hOs z)ajhqD)eXHo(iA+A4S0&tLFD1Znrzix4WI=<@}DHw|bpke-!I|@f%$PuO0GvKTq($ zyn~oLFnbrX&%l($oLdWvvVJWPdtHS*>dswzwb0#xc57(2KkXH0fh^{!lhYc?OGw7n zpk@4dFu88+Mf7QS4f3oP`YB}dub}%Pj2Bx)vR35KCe`pe1CM*XEOd7uW}VsGZT{5F)U9z2B3sjZ^GL>uhyMby$9r6WYtu*nMYy@dt*`DZBfs}thCKRTglmiZ@~hC# z3F=P8QpSrsk&vyge8At!OkyHBi+W5Oj_U5dj|8?YX{|$8fe}%n)W{mZWch~A0 zWHHYp$Qt7mz4;F8?Kv;O8t&I){2vhCN0YyEJrB7X=f8=Ey0h2rTrNS*&Uw8ele4)D ziHFY>WPN-W;j@A)t{(e#X1yXu9k~YmppH4OL(W|Mdx5PXn@3yJx`}Kp=N+|fA&c)9 zv$=z8kH%|rM#ekGdyx0_{diw>{hM^*Jnlo<-B0+4xu5WPfUJ)@3Li1+nA2UkpTBJ3 G1@sSCeOCYg literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_1_1.nspv b/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_1_1.nspv new file mode 100644 index 0000000000000000000000000000000000000000..4d6b16131c8a2f1c26b1bc7cc30e137134a5e960 GIT binary patch literal 453 zcmYk2%W48a5JhWde7_}-?1CYC$-;;bl1&zF-1!AT2?UIS5kD|r!wMMRN5)*~`@BL=W*7&#o#j#|p|#d0zJIjqN%=O_JM6sF|$qaGE`#`nk9R=rL1 zhynN18$`j*$-fk?qF&#Zn|Q0;X16EH);PZZ3$pb-OP-hhJ(_dM`m*bWPWF08T_c@u zIoHre#2xo}bYkZi!Oo~=$Stz9<(HD3Nlm{?_Agv~*%{QPyukj}cB!3Es$^@~%lG>2 aD{Sr%)_>!+o_z88oYnN~A)lFKM*IPy_7>a# literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_2_0.nspv b/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_2_0.nspv new file mode 100644 index 0000000000000000000000000000000000000000..591448d2201a80ca853b9decebbad9642fbc0bda GIT binary patch literal 1425 zcmYk5+fGwa5QY~$fubNH-~q7}&tN@7jfoM{KmsIOkdSz5h&E;?wIyve#w)$>A@Fg0 zDsN2uzPII*g`Q509N*qM*lUl* zAKK5JKL$=SsjA9jv*~PZ*ZBMCFzf4_M;4JA$Rp$lQsq}c|E5qq)%gAA*Qqm&|FQRO zzdL-}9ge$SaX|}Q+t^@~jk7@?bTa4LbB<^I@j>>jD=%W!BDUGfj<&MV_^|)JdlIvI zW1oAylUSYp?Auf4Xa7f0FvlACd$_mTFY@hf<#;WB%_#G~)rjWNUar-k~N9M_5o)$T+p}mOZ z-6paGpARPYt-XLhg>E9AwbDO>ZT@9^zXt9f(_%r}SSUGd=0V|#qZCA2X)@)ywN61Tp-vyA+{a|!Xtzl=5(`PJ8v zU&qHA#$(3zX+C{-aXQ~Ed}kc}-^EVp`y21y$FetP75%Sa2j9F85jp0U?{4+ix#d0o zLCtwuq8ImWFE7}o&HvoNv^+gDt*a&gLGr zJ$m1mGxEN3e1P~~zZc)DFTX<<&SM=h?mmJeR^%u+?ULh;f+Hr!obJl~{ACL-k$(c+ BRY?E< literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_2_1.nspv b/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_2_1.nspv new file mode 100644 index 0000000000000000000000000000000000000000..24a71ffe6dbb781a02c21c8651915ce0e2f11fef GIT binary patch literal 837 zcmYk3%}N775QKYolT9?5A2o^p+2An{Jg5kwq5*TsLGS@27z{#mVHM9FeJ-EMi(q}T zJCIqLo~oMa>7ES&GmFBbidmqqYJFi=%R*tZn#C@UCl8b1`^Ri}a(awjw}|AlhI}RM ziP!1N8+=VsSM(H3okgoEB7LFqkBXPYE_=W$(w@>qnkj>+^Et{1@Ve8}Z07XX-7#N0 z-euGID9vf-Dsvb3qQKk-=P^Bi2hyqCRIu8@E#(BDg$~|u2)?8q^V;~lzvJ|;TYr9Ac)9+5 zu3zJ4R{o&x56m0Do#_RcpV?S&zhcVD^vC~0c<}*XZwIDJF1rxjwglhz-+>I8#JdbrJLz?C12W zx(Rxoz4x-dVa>PJyWVdd_fX2$8w`2TQ_bv4c+Gspt+0P#_kUxoV@iR!7w?;pQTo-yqAoi}^! zqu1@DLHjc%Xo0Ki>-Doi*6V_fOHyq&EaujM^{+U#|DN5xzFg;z8J>lN|r&l7iG z_8{gRn6-;pXJG1L&TSiyy1Z==Yn?|t+Rk17aA~^({pQebefsOj6j6+`NKA96&!G9X zfy~0^gUM}kPh*dAHxSQqX`ezj{v5Vngzv@X(aaSw^eGK^XSk!U=cVlq#LP3E^NP6U z(Vjreqiv3J2+>-`n?&=ic<`stJ@#>dTb~^H)7-`qH@~*CjQI9Bi+JQ;Uhc2!iJ9bXJGR7i$1NlxKV_rj?v-r0XTS7OEzQ}b0-CWK%a@|B1-(#xI z^)_OSzSrmceeW#qBKGSyW53$+TU6mZ?jic!NpQr97zL+Ua@yy^!pfH e>_^$#3c8rPi@Mj)#oeD`JZp6S`u?!>XUJd5XIZTP literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_3_1.nspv b/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_3_1.nspv new file mode 100644 index 0000000000000000000000000000000000000000..f2da4b040eb8ba22b83911e6459fff75084c709c GIT binary patch literal 825 zcmYk3$x1^(5JfwqLo_B1iL(hVh2TO(5CzF1n=AxBK*XQ~VjjfcANXT_l^elxIO^!WJPW?LGex74}9dE6?*tx6~s~0=7+zxmP-@*LOa=g8OQNKfMKhH?{ zU1IeK9}=hY-Q5>W^NPI_xhr16I(PMx`+=$8oz2~Sx1@C!-${H+UcZL9{~c;;#pc{^ z6LU9n>csbScZU`x=Wf=!PaBg@HG9O?xL>N-Czk)BkD3EaoqW-cjr{?%`6rG5 literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_4_0.nspv b/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_4_0.nspv new file mode 100644 index 0000000000000000000000000000000000000000..591448d2201a80ca853b9decebbad9642fbc0bda GIT binary patch literal 1425 zcmYk5+fGwa5QY~$fubNH-~q7}&tN@7jfoM{KmsIOkdSz5h&E;?wIyve#w)$>A@Fg0 zDsN2uzPII*g`Q509N*qM*lUl* zAKK5JKL$=SsjA9jv*~PZ*ZBMCFzf4_M;4JA$Rp$lQsq}c|E5qq)%gAA*Qqm&|FQRO zzdL-}9ge$SaX|}Q+t^@~jk7@?bTa4LbB<^I@j>>jD=%W!BDUGfj<&MV_^|)JdlIvI zW1oAylUSYp?Auf4Xa7f0FvlACd$_mTFY@hf<#;WB%_#G~)rjWNUar-k~N9M_5o)$T+p}mOZ z-6paGpARPYt-XLhg>E9AwbDO>ZT@9^zXt9f(_%r}SSUGd=0V|#qZCA2X)@)ywN61Tp-vyA+{a|!Xtzl=5(`PJ8v zU&qHA#$(3zX+C{-aXQ~Ed}kc}-^EVp`y21y$FetP75%Sa2j9F85jp0U?{4+ix#d0o zLCtwuq8ImWFE7}o&HvoNv^+gDt*a&gLGr zJ$m1mGxEN3e1P~~zZc)DFTX<<&SM=h?mmJeR^%u+?ULh;f+Hr!obJl~{ACL-k$(c+ BRY?E< literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_4_1.nspv b/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_4_1.nspv new file mode 100644 index 0000000000000000000000000000000000000000..5ff409f5701010fd68ab0e2891c5895ebabe588a GIT binary patch literal 2461 zcmZ{lYfn=_5QdjhS`<-`n-|0u6fY>=08s>53zljX6yjIY)Dvw|TSE`T_{op{7Jr6+ z%1dJ6`<$~wPEfWPX6BvQd1rU0rK{UH*PWWmI@hI7uiKH&8gwZ~44v~jFWu)d%5$z< z-LB4d!nd-KM~>14NH$pZc6S;RwO0KfJ^J++&M|q zlm4b;e^!ct)Jgy=%UywD#NeTG(i}Dr?a``1a#8`PqnDd0Vxx z{{D5a8#d}er=kvt(UW33L8ns<_Jii;UKs2OBSx>uSf$nSv5Z@aV_U&46@yQ5)lrON z!`JRK=t^id%IBUUywM7`8=nL6EXKJND>WM**BYI$)~W{wG46)gUbA@+<36}Y;qASU zelxBR`~UO=&WgAbJr#r<)f2I!dLnjIPrR#mq5&xTH=FRa@OiU7Nv{N-w<1m-_{<6M zlab#Yy$^ec@m9o;vO3^>EQSrvjBMyOcpnxR%P@Gr(1vkNFwSHcHW>2>7xl;^UXW%b zYZv4nt_^m$HrV0XmN%qq^7G0d2YXajMmi@MQ#bn3Mm~Lw$mbq&64s3OkI82LxcuYN z>;cQkw{wCod7nEYpL+dKUVIkvc?Zq~PCh<&4rY9VvU3vnPD{fVV`(=en_O`Aqe)gZQpg-+#`L@ zNV5lwK5j@;2b@0enZFo|`g!it5H#ELE@547Q8$K}j7Nn^S4j(=< zZG61*0}1un|4^F!U=y;KPwoti7((77X=3*N%d)8%<7tP_?+6%m3ex|pQxs0j-u1C; zdI6_j{F28w&$_qi$L{B;YrWT66VbO5$_k3#mtOJm?Lm< z==qEUoE+we|0~QkwN}J}Pma|*FFVO`K|ZtARz3RWcM0sP>fz@kV9Z}p$fWd?1P*HD zCGdddB*t?|Hay={XIlD-1dO@-q5Nyotl#1#c2xq#onUhwxNb?9LH5Ce&kS1pj%?!0 zA#wa<{GN|9m&Eat@kRN}oYluC{!4vWKWIDGs_f+bt$Dww*I1YRL{gG~!%1ECa+hTZ zadJ7^hJ-n!rsdKjIJw4Ik)7mx=6&O=%7+u2c}sFWmrvX{U&w}&nwASEIJw5TDLcuz m<$Y#=S$rvh6WsW+vR_Gvk;go4OW>m(d2oS|_ebBRMaf@}v#`(r literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_4_2.nspv b/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_4_2.nspv new file mode 100644 index 0000000000000000000000000000000000000000..2e67053e226723115f44ba9ca59edcb5bc8d1fee GIT binary patch literal 1901 zcmZ{k+fGwa5QZ1f0)lc70S|~pJfnyTh$0Yz30`nvg7MZ6XiSsZns%EQ?|cCt%BS+i z#P8ePLw1O4GS19Dv;H}(W&0{ArGfs%p_Kag8%{g;ev_#`4HUXo=mqp>8YC~J{e#1U z_$R$>Y|@j>8|!xj#2Qy{~sZ);n4KJ7Fg1;o8R9-A2}Ew?K#Te0#|8 zMk_mP{HU83F?%7l*KB-!+vsLTt>gM>%zYXA)@+`}s`T&7epNEBqvbx^kGNl6x73gL zdHonWuODOo@28UQpE~))*pqjG|DoRP?zP*U6Wp|4>~_B3(Ra7{)_lh_-kaZOPn}}+ zE2fS-&xqMmVA^8d={^zpf;;w6=8j#Ixnl=q?wGyI9eK{-yv8meQ&hC(0`=`jdj@L| zT|;Kc=RZg8+h+}b7;UcjX5sq|#isE`&^5$wsqn2=L+0==qCMNgDtRA$_~P=}m%A2| zZya4KeEIYz5I_5wM4KyT)Voq()|d~?|LCoZqPzX4*_^-XE_c3$BwdNuW88#BJk^b6?Qh&zuw`NV2S@ZG@Y1(*KQ0`q+EuVBmX`wRYO*y6$e0$YCXrOdyIZ!GxN zu*E$8v#7a_ZCztga|7F&-fPr+g)JU6Ut?P{b{%)Q31%#6zQGpreAL{+wyrU2`kSzg RxNG}&&-&*5<)v*P{{WEMcPIb= literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_4_3.nspv b/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_4_3.nspv new file mode 100644 index 0000000000000000000000000000000000000000..8be0d63cb9b389884138e3128ea19b91e75f71ca GIT binary patch literal 2145 zcmZ{l*-jKu5Qfh%8w#?>=7M+-6&1w|5JkWd5+vcmgoIl|q(eFxX2{U4SH6<3;A7}} z7&S5R|4yGG9U?s`tLm>hf7PjK+ESNuuG}?Mcdn#gw_B6XGw8bX%e9YsGU}(&J+7vF z=Qg&sw`PyBz1g|>2XbAXE2BcJ-}MHsBL84FZGoSW^hrh}I9vZ+?qk6yp2p{h<5>)}&#f34kYck(#(vm^(qt{!^XZ@zimNe|L2eV=Tu zZ-!p0VxvdJwst=yI?efd=vmlKntV8Hce2gaUh*-Im7SN7hP;})D-Cbb*-1KCo>SA@ zz?uK`Oo#C?^e9q(Zp7cocf(D;` z;ImWW)|ywWXgwqQJlaSt%GVe}71EyJ+E@_x#Jk38Zwry{q_sK{-zDRSFPirkhr z6#v#H)d}^fH!7vImlytdxdnlZk?ctGZdI5(QpKl`=b?2i^KMQ&%;pd&;q4qB! zRcX#L123U&Lnu2sFJZ6jZdp0Rh9uxCV&EOZC&ujf7PGgud}@wG3_f8V;C12G8d%P_Ho0j|$2mUn) zT%5(Wvvab&q@kNL%LNJZ1!rG27w-B*LcF1ybJs-)JGMOT1xB9n^M9k482>Zb@PpG| zk$*`(apQk38-B}!AB;TXUzY79oME3U68OQ5o1Lyoh_NTW6)z-klLIe4Ip19=%$b=p gE40;W$o7&i;^19)DFG|)5v;gJX8uE*eN+YRsaA1 literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_4_4.nspv b/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_4_4.nspv new file mode 100644 index 0000000000000000000000000000000000000000..c157ad237ec894d897e2b03763fb1cc0c4f30bec GIT binary patch literal 453 zcmYk2%Sr=55JhWd%*&XE1k6q*xDPH&2n5}@$R<0#Kq88u4j8{MUzJTD=d=?@55=u} zZ*^7mWLZQM`CTg_<7>wd?zxT}9?^|v!qxg^J>CAjO&@0W`u!+`*tSp zm*^8i>eSmr!Iy(O8aGhS>*XE1P4!j%f^vI&JpT)F`@PqERr|MS_L1w$JtHPLYm%l$ z%5TV~)b=P1&{}8t cUhh7_#Vf-8PgLv4Pu_rBP0tzf1Dh;}Bb3?}&;S4c literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_5_0.nspv b/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_5_0.nspv new file mode 100644 index 0000000000000000000000000000000000000000..591448d2201a80ca853b9decebbad9642fbc0bda GIT binary patch literal 1425 zcmYk5+fGwa5QY~$fubNH-~q7}&tN@7jfoM{KmsIOkdSz5h&E;?wIyve#w)$>A@Fg0 zDsN2uzPII*g`Q509N*qM*lUl* zAKK5JKL$=SsjA9jv*~PZ*ZBMCFzf4_M;4JA$Rp$lQsq}c|E5qq)%gAA*Qqm&|FQRO zzdL-}9ge$SaX|}Q+t^@~jk7@?bTa4LbB<^I@j>>jD=%W!BDUGfj<&MV_^|)JdlIvI zW1oAylUSYp?Auf4Xa7f0FvlACd$_mTFY@hf<#;WB%_#G~)rjWNUar-k~N9M_5o)$T+p}mOZ z-6paGpARPYt-XLhg>E9AwbDO>ZT@9^zXt9f(_%r}SSUGd=0V|#qZCA2X)@)ywN61Tp-vyA+{a|!Xtzl=5(`PJ8v zU&qHA#$(3zX+C{-aXQ~Ed}kc}-^EVp`y21y$FetP75%Sa2j9F85jp0U?{4+ix#d0o zLCtwuq8ImWFE7}o&HvoNv^+gDt*a&gLGr zJ$m1mGxEN3e1P~~zZc)DFTX<<&SM=h?mmJeR^%u+?ULh;f+Hr!obJl~{ACL-k$(c+ BRY?E< literal 0 HcmV?d00001 diff --git a/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_5_1.nspv b/external/openglcts/data/spirv/spirv_validation_builtin_variable_decorations/shader_5_1.nspv new file mode 100644 index 0000000000000000000000000000000000000000..bf191662498266563b154437c67490bb0b61f816 GIT binary patch literal 1265 zcmYk4c}tX06o>C@uH}+ji{-0ho7z}W5ky5448jP4A0UP-85$dLq`&(-ehj}a?{UkIE-Gw$GgJy`)XAG+Fm*M9WtDzl^6^~>4*6a38;9~Rr{yb3B z(3tzM`*pv4blm;E^CkM+M%PEN*Xx5vW9@4nl%3N~&*o~(WKY+&-FE+H)K_DlKT@4$ zs`~(&J89Chb*G|Sjk0~+O4wP&a|v5RJfE;TFqhvP(>woa+(d}-BJv2j0$QRr$BEe8 z6kzwJP7+VR?MwVFVe6?|0N;cc3F~j)+SKbWb{=(`$$u8vZ=Q~v%RUz2_GQ23S%O@pO>pO5x+AE^-XSy!C*V!joy`Hjo=HRR!ZkHLOhcfW_wrNs4^0iO zulMs^=UDgXn-#yuF24bJ!w*F3E7oTH8OVE`k=DT|Y*@Loq zywN?#`&h&J;!oss?**jJd+6^CR-ppQK6PY$+-de%M^?Yb6wdJw@)pKwQ_eGKyPzlg owKsdrHt#rW)5p5rp#ga-=ha{At?a>?FCcfO&6|k-^J?BgSMak(r~m)} literal 0 HcmV?d00001 diff --git a/external/openglcts/modules/gl/CMakeLists.txt b/external/openglcts/modules/gl/CMakeLists.txt index 6084bd6..a50d553 100644 --- a/external/openglcts/modules/gl/CMakeLists.txt +++ b/external/openglcts/modules/gl/CMakeLists.txt @@ -122,6 +122,8 @@ set(GLCTS_GL_SRCS gl4cIndirectParametersTests.hpp gl4cLimitsTests.cpp gl4cLimitsTests.hpp + gl4cGlSpirvTests.cpp + gl4cGlSpirvTests.hpp ) set(GLCTS_GL_LIBS @@ -130,6 +132,31 @@ set(GLCTS_GL_LIBS tcutil ) +# Add glslang +if (DEQP_HAVE_GLSLANG) + include_directories(${GLSLANG_INCLUDE_PATH}) + add_definitions(-DDEQP_HAVE_GLSLANG=1) + + # \note Code interfacing with glslang needs to include third-party headers + # that cause all sorts of warnings to appear. + if (DE_COMPILER_IS_GCC OR DE_COMPILER_IS_CLANG) + set_source_files_properties( + FILES gl4cGlSpirvTests.cpp + PROPERTIES COMPILE_FLAGS "${DE_3RD_PARTY_CXX_FLAGS} -std=c++11") + endif () + + set(GLCTS_GL_LIBS ${GLCTS_GL_LIBS} ${GLSLANG_LIBRARY}) +endif () + +# Add spirv-tools +if(DEQP_HAVE_SPIRV_TOOLS) + include_directories(${spirv-tools_SOURCE_DIR}/include) + include_directories(${spirv-tools_SOURCE_DIR}/external/include) + + add_definitions(-DDEQP_HAVE_SPIRV_TOOLS=1) + set(GLCTS_GL_LIBS ${GLCTS_GL_LIBS} SPIRV-Tools) +endif() + if (DEQP_GTF_AVAILABLE) list(APPEND GLCTS_GL_LIBS glcts-gtf) endif () diff --git a/external/openglcts/modules/gl/gl4cGlSpirvTests.cpp b/external/openglcts/modules/gl/gl4cGlSpirvTests.cpp new file mode 100644 index 0000000..696572e --- /dev/null +++ b/external/openglcts/modules/gl/gl4cGlSpirvTests.cpp @@ -0,0 +1,3444 @@ +/*------------------------------------------------------------------------- + * OpenGL Conformance Test Suite + * ----------------------------- + * + * Copyright (c) 2017 The Khronos Group Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ /*! + * \file + * \brief + */ /*-------------------------------------------------------------------*/ + +/** + */ /*! + * \file gl4cGlSpirvTests.cpp + * \brief Conformance tests for the GL_ARB_gl_spirv functionality. + */ /*-------------------------------------------------------------------*/ + +#include "gl4cGlSpirvTests.hpp" +#include "deArrayUtil.hpp" +#include "deSingleton.h" +#include "deStringUtil.hpp" +#include "gluContextInfo.hpp" +#include "gluDefs.hpp" +#include "gluShaderProgram.hpp" +#include "gluStrUtil.hpp" +#include "glwEnums.hpp" +#include "glwFunctions.hpp" +#include "tcuRenderTarget.hpp" +#include "tcuResource.hpp" +#include "tcuTestLog.hpp" + +#if defined DEQP_HAVE_GLSLANG +#include "SPIRV/GlslangToSpv.h" +#include "SPIRV/disassemble.h" +#include "SPIRV/doc.h" +#include "glslang/MachineIndependent/localintermediate.h" +#include "glslang/Public/ShaderLang.h" +#endif // DEQP_HAVE_GLSLANG + +#if defined DEQP_HAVE_SPIRV_TOOLS +#include "spirv-tools/libspirv.hpp" +#include "spirv-tools/optimizer.hpp" +#endif // DEQP_HAVE_SPIRV_TOOLS + +using namespace glu; +using namespace glw; + +namespace gl4cts +{ + +namespace glslangUtils +{ + +#if defined DEQP_HAVE_GLSLANG + +EShLanguage getGlslangStage(glu::ShaderType type) +{ + static const EShLanguage stageMap[] = { + EShLangVertex, EShLangFragment, EShLangGeometry, EShLangTessControl, EShLangTessEvaluation, EShLangCompute, + }; + + return de::getSizedArrayElement(stageMap, type); +} + +static volatile deSingletonState s_glslangInitState = DE_SINGLETON_STATE_NOT_INITIALIZED; + +void initGlslang(void*) +{ + // Main compiler + glslang::InitializeProcess(); + + // SPIR-V disassembly + spv::Parameterize(); +} + +void prepareGlslang(void) +{ + deInitSingleton(&s_glslangInitState, initGlslang, DE_NULL); +} + +void getDefaultLimits(TLimits* limits) +{ + limits->nonInductiveForLoops = true; + limits->whileLoops = true; + limits->doWhileLoops = true; + limits->generalUniformIndexing = true; + limits->generalAttributeMatrixVectorIndexing = true; + limits->generalVaryingIndexing = true; + limits->generalSamplerIndexing = true; + limits->generalVariableIndexing = true; + limits->generalConstantMatrixVectorIndexing = true; +} + +void getDefaultBuiltInResources(TBuiltInResource* builtin) +{ + getDefaultLimits(&builtin->limits); + + builtin->maxLights = 32; + builtin->maxClipPlanes = 6; + builtin->maxTextureUnits = 32; + builtin->maxTextureCoords = 32; + builtin->maxVertexAttribs = 64; + builtin->maxVertexUniformComponents = 4096; + builtin->maxVaryingFloats = 64; + builtin->maxVertexTextureImageUnits = 32; + builtin->maxCombinedTextureImageUnits = 80; + builtin->maxTextureImageUnits = 32; + builtin->maxFragmentUniformComponents = 4096; + builtin->maxDrawBuffers = 32; + builtin->maxVertexUniformVectors = 128; + builtin->maxVaryingVectors = 8; + builtin->maxFragmentUniformVectors = 16; + builtin->maxVertexOutputVectors = 16; + builtin->maxFragmentInputVectors = 15; + builtin->minProgramTexelOffset = -8; + builtin->maxProgramTexelOffset = 7; + builtin->maxClipDistances = 8; + builtin->maxComputeWorkGroupCountX = 65535; + builtin->maxComputeWorkGroupCountY = 65535; + builtin->maxComputeWorkGroupCountZ = 65535; + builtin->maxComputeWorkGroupSizeX = 1024; + builtin->maxComputeWorkGroupSizeY = 1024; + builtin->maxComputeWorkGroupSizeZ = 64; + builtin->maxComputeUniformComponents = 1024; + builtin->maxComputeTextureImageUnits = 16; + builtin->maxComputeImageUniforms = 8; + builtin->maxComputeAtomicCounters = 8; + builtin->maxComputeAtomicCounterBuffers = 1; + builtin->maxVaryingComponents = 60; + builtin->maxVertexOutputComponents = 64; + builtin->maxGeometryInputComponents = 64; + builtin->maxGeometryOutputComponents = 128; + builtin->maxFragmentInputComponents = 128; + builtin->maxImageUnits = 8; + builtin->maxCombinedImageUnitsAndFragmentOutputs = 8; + builtin->maxCombinedShaderOutputResources = 8; + builtin->maxImageSamples = 0; + builtin->maxVertexImageUniforms = 0; + builtin->maxTessControlImageUniforms = 0; + builtin->maxTessEvaluationImageUniforms = 0; + builtin->maxGeometryImageUniforms = 0; + builtin->maxFragmentImageUniforms = 8; + builtin->maxCombinedImageUniforms = 8; + builtin->maxGeometryTextureImageUnits = 16; + builtin->maxGeometryOutputVertices = 256; + builtin->maxGeometryTotalOutputComponents = 1024; + builtin->maxGeometryUniformComponents = 1024; + builtin->maxGeometryVaryingComponents = 64; + builtin->maxTessControlInputComponents = 128; + builtin->maxTessControlOutputComponents = 128; + builtin->maxTessControlTextureImageUnits = 16; + builtin->maxTessControlUniformComponents = 1024; + builtin->maxTessControlTotalOutputComponents = 4096; + builtin->maxTessEvaluationInputComponents = 128; + builtin->maxTessEvaluationOutputComponents = 128; + builtin->maxTessEvaluationTextureImageUnits = 16; + builtin->maxTessEvaluationUniformComponents = 1024; + builtin->maxTessPatchComponents = 120; + builtin->maxPatchVertices = 32; + builtin->maxTessGenLevel = 64; + builtin->maxViewports = 16; + builtin->maxVertexAtomicCounters = 0; + builtin->maxTessControlAtomicCounters = 0; + builtin->maxTessEvaluationAtomicCounters = 0; + builtin->maxGeometryAtomicCounters = 0; + builtin->maxFragmentAtomicCounters = 8; + builtin->maxCombinedAtomicCounters = 8; + builtin->maxAtomicCounterBindings = 1; + builtin->maxVertexAtomicCounterBuffers = 0; + builtin->maxTessControlAtomicCounterBuffers = 0; + builtin->maxTessEvaluationAtomicCounterBuffers = 0; + builtin->maxGeometryAtomicCounterBuffers = 0; + builtin->maxFragmentAtomicCounterBuffers = 1; + builtin->maxCombinedAtomicCounterBuffers = 1; + builtin->maxAtomicCounterBufferSize = 16384; + builtin->maxTransformFeedbackBuffers = 4; + builtin->maxTransformFeedbackInterleavedComponents = 64; + builtin->maxCullDistances = 8; + builtin->maxCombinedClipAndCullDistances = 8; + builtin->maxSamples = 4; +}; + +bool compileGlslToSpirV(tcu::TestLog& log, std::string source, glu::ShaderType type, ShaderBinaryDataType* dst) +{ + TBuiltInResource builtinRes; + + prepareGlslang(); + getDefaultBuiltInResources(&builtinRes); + + const EShLanguage shaderStage = getGlslangStage(type); + + glslang::TShader shader(shaderStage); + glslang::TProgram program; + + const char* src[] = { source.c_str() }; + + shader.setStrings(src, 1); + program.addShader(&shader); + + const int compileRes = shader.parse(&builtinRes, 100, false, EShMsgSpvRules); + if (compileRes != 0) + { + const int linkRes = program.link(EShMsgSpvRules); + + if (linkRes != 0) + { + const glslang::TIntermediate* const intermediate = program.getIntermediate(shaderStage); + glslang::GlslangToSpv(*intermediate, *dst); + + return true; + } + else + { + log << tcu::TestLog::Message << "Program linking error:\n" + << program.getInfoLog() << "\n" + << "Source:\n" + << source << "\n" + << tcu::TestLog::EndMessage; + } + } + else + { + log << tcu::TestLog::Message << "Shader compilation error:\n" + << shader.getInfoLog() << "\n" + << "Source:\n" + << source << "\n" + << tcu::TestLog::EndMessage; + } + + return false; +} + +#else // DEQP_HAVE_GLSLANG + +bool compileGlslToSpirV(tcu::TestLog& log, std::string source, glu::ShaderType type, ShaderBinaryDataType* dst) +{ + DE_UNREF(log); + DE_UNREF(source); + DE_UNREF(type); + DE_UNREF(dst); + + TCU_THROW(InternalError, "Glslang not available."); + + return false; +} + +#endif // DEQP_HAVE_GLSLANG + +#if defined DEQP_HAVE_SPIRV_TOOLS + +void spirvAssemble(ShaderBinaryDataType& dst, const std::string& src) +{ + spvtools::SpirvTools core(SPV_ENV_OPENGL_4_5); + + auto print_msg_to_stderr = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) { + std::cerr << "error: " << m << std::endl; + }; + + core.SetMessageConsumer(print_msg_to_stderr); + + if (!core.Assemble(src, &dst)) + TCU_THROW(InternalError, "Failed to assemble Spir-V source."); + if (!core.Validate(dst)) + TCU_THROW(InternalError, "Failed to validate Spir-V module."); +} + +void spirvDisassemble(std::string& dst, const ShaderBinaryDataType& src) +{ + spvtools::SpirvTools core(SPV_ENV_OPENGL_4_5); + + auto print_msg_to_stderr = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) { + std::cerr << "error: " << m << std::endl; + }; + + core.SetMessageConsumer(print_msg_to_stderr); + + if (!core.Disassemble(src, &dst)) + TCU_THROW(InternalError, "Failed to disassemble Spir-V module."); +} + +#else //DEQP_HAVE_SPIRV_TOOLS + +void spirvAssemble(ShaderBinaryDataType& dst, const std::string& src) +{ + DE_UNREF(dst); + DE_UNREF(src); + + TCU_THROW(InternalError, "Spirv-tools not available."); +} + +void spirvDisassemble(std::string& dst, ShaderBinaryDataType& src) +{ + DE_UNREF(dst); + DE_UNREF(src); + + TCU_THROW(InternalError, "Glslang not available."); +} + +#endif // DEQP_HAVE_SPIRV_TOOLS + +ShaderBinary makeSpirV(tcu::TestLog& log, ShaderSource source) +{ + ShaderBinary binary; + + if (!glslangUtils::compileGlslToSpirV(log, source.source, source.shaderType, &binary.binary)) + TCU_THROW(InternalError, "Failed to convert GLSL to Spir-V"); + + binary << source.shaderType << "main"; + + return binary; +} + +/** Verifying if GLSL to SpirV mapping was performed correctly + * + * @param glslSource GLSL shader template + * @param spirVSource SpirV disassembled source + * @param mappings Glsl to SpirV mappings vector + * @param anyOf any occurence indicator + * + * @return true if GLSL code occurs as many times as all of SpirV code for each mapping if anyOf is false + * or true if SpirV code occurs at least once if GLSL code found, false otherwise. + **/ +bool verifyMappings(std::string glslSource, std::string spirVSource, SpirVMapping& mappings, bool anyOf) +{ + std::vector spirVSourceLines = de::splitString(spirVSource, '\n'); + + // Iterate through all glsl functions + for (SpirVMapping::iterator it = mappings.begin(); it != mappings.end(); it++) + { + int glslCodeCount = 0; + int spirVCodeCount = 0; + + // To avoid finding functions with similar names (ie. "cos", "acos", "cosh") + // add characteristic characters that delimits finding results + std::string glslCode = it->first; + + // Count GLSL code occurrences in GLSL source + size_t codePosition = glslSource.find(glslCode); + while (codePosition != std::string::npos) + { + glslCodeCount++; + codePosition = glslSource.find(glslCode, codePosition + 1); + } + + if (glslCodeCount > 0) + { + // Count all SpirV code variants occurrences in SpirV source + for (int s = 0; s < it->second.size(); ++s) + { + std::vector spirVCodes = de::splitString(it->second[s], ' '); + + for (int v = 0; v < spirVSourceLines.size(); ++v) + { + std::vector spirVLineCodes = de::splitString(spirVSourceLines[v], ' '); + + bool matchAll = true; + for (int j = 0; j < spirVCodes.size(); ++j) + { + bool match = false; + for (int i = 0; i < spirVLineCodes.size(); ++i) + { + if (spirVLineCodes[i] == spirVCodes[j]) + match = true; + } + + matchAll = matchAll && match; + } + + if (matchAll) + spirVCodeCount++; + } + } + + // Check if both counts match + if (anyOf && (glslCodeCount > 0 && spirVCodeCount == 0)) + return false; + else if (!anyOf && glslCodeCount != spirVCodeCount) + return false; + } + } + + return true; +} + +} // namespace glslangUtils + +namespace commonUtils +{ + +void writeSpirV(const char* filename, ShaderBinary binary) +{ + FILE* file = fopen(filename, "wb"); + if (file) + { + // As one binary could be associated with many shader objects it should be stored either a type of each shader + // This will be extended in the future + deUint8 count = (deUint8)binary.shaderTypes.size(); + fwrite((void*)&count, 1, 1, file); + for (int i = 0; i < binary.shaderTypes.size(); ++i) + { + fwrite((void*)&binary.shaderTypes[i], 1, sizeof(ShaderType), file); + + if (count > 1) + { + deUint8 strLen = (deUint8)binary.shaderEntryPoints[i].size(); + fwrite((void*)&strLen, 1, 1, file); + fwrite((void*)binary.shaderEntryPoints[i].data(), 1, strLen, file); + } + } + + fwrite((void*)binary.binary.data(), 1, binary.binary.size() * 4, file); + fclose(file); + } +} + +ShaderBinary readSpirV(tcu::Resource* resource) +{ + ShaderBinary binary; + if (!resource) + return binary; + + // As one binary could be associated with many shader objects it should be stored either a type of each shader + deUint8 count; + resource->read(&count, 1); + binary.shaderTypes.resize(count); + binary.shaderEntryPoints.resize(count); + for (int i = 0; i < binary.shaderTypes.size(); ++i) + { + resource->read((deUint8*)&binary.shaderTypes[i], sizeof(ShaderType)); + + if (count > 1) + { + deUint8 strLen; + resource->read(&strLen, 1); + + binary.shaderEntryPoints[i].resize(strLen); + resource->read((deUint8*)binary.shaderEntryPoints[i].data(), strLen); + } + else + binary.shaderEntryPoints[i] = "main"; + } + + binary.binary.resize((resource->getSize() - resource->getPosition()) / sizeof(deUint32)); + resource->read((deUint8*)binary.binary.data(), binary.binary.size() * sizeof(deUint32)); + + return binary; +} + +/** Replace all occurance of with in + * + * @param token Token string + * @param text String th at will be used as replacement for + * @param string String to work on + **/ +void replaceToken(const GLchar* token, const GLchar* text, std::string& string) +{ + const size_t text_length = strlen(text); + const size_t token_length = strlen(token); + + size_t token_position; + while ((token_position = string.find(token, 0)) != std::string::npos) + { + string.replace(token_position, token_length, text, text_length); + } +} + +bool compareUintColors(const GLuint inColor, const GLuint refColor, const int epsilon) +{ + int r1 = (inColor & 0xFF); + int g1 = ((inColor >> 8) & 0xFF); + int b1 = ((inColor >> 16) & 0xFF); + int a1 = ((inColor >> 24) & 0xFF); + + int r2 = (refColor & 0xFF); + int g2 = ((refColor >> 8) & 0xFF); + int b2 = ((refColor >> 16) & 0xFF); + int a2 = ((refColor >> 24) & 0xFF); + + if (r1 >= r2 - epsilon && r1 <= r2 + epsilon && g1 >= g2 - epsilon && g1 <= g2 + epsilon && b1 >= b2 - epsilon && + b1 <= b2 + epsilon) + { + return true; + } + + return false; +} + +} // namespace commonUtils + +/** Constructor. + * + * @param context Rendering context + * @param name Test name + * @param description Test description + */ +SpirvModulesPositiveTest::SpirvModulesPositiveTest(deqp::Context& context) + : TestCase(context, "spirv_modules_positive_test", + "Test verifies if using SPIR-V modules for each shader stage works as expected") +{ + /* Left blank intentionally */ +} + +/** Stub init method */ +void SpirvModulesPositiveTest::init() +{ + if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gl_spirv")) + TCU_THROW(NotSupportedError, "GL_ARB_gl_spirv is not supported"); + + m_vertex = "#version 450\n" + "\n" + "layout (location = 0) in vec3 position;\n" + "\n" + "layout (location = 1) out vec4 vColor;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = vec4(position, 1.0);\n" + " vColor = vec4(0.0, 0.0, 0.0, 1.0);\n" + "}\n"; + + m_tesselationCtrl = "#version 450\n" + "\n" + "layout (vertices = 3) out;\n" + "\n" + "layout (location = 1) in vec4 vColor[];\n" + "layout (location = 2) out vec4 tcColor[];\n" + "\n" + "void main()\n" + "{\n" + " tcColor[gl_InvocationID] = vColor[gl_InvocationID];\n" + " tcColor[gl_InvocationID].r = 1.0;\n" + "\n" + " if (gl_InvocationID == 0) {\n" + " gl_TessLevelOuter[0] = 1.0;\n" + " gl_TessLevelOuter[1] = 1.0;\n" + " gl_TessLevelOuter[2] = 1.0;\n" + " gl_TessLevelInner[0] = 1.0;\n" + " }\n" + "\n" + " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" + "}\n"; + + m_tesselationEval = "#version 450\n" + "\n" + "layout (triangles) in;\n" + "\n" + "layout (location = 2) in vec4 tcColor[];\n" + "layout (location = 3) out vec4 teColor;\n" + "\n" + "void main()\n" + "{\n" + " teColor = tcColor[0];\n" + " teColor.g = 1.0;\n" + "\n" + " gl_Position = gl_TessCoord.x * gl_in[0].gl_Position +\n" + " gl_TessCoord.y * gl_in[1].gl_Position +\n" + " gl_TessCoord.z * gl_in[2].gl_Position;\n" + "}\n"; + + m_geometry = "#version 450\n" + "\n" + "layout (triangles) in;\n" + "layout (triangle_strip, max_vertices = 3) out;\n" + "\n" + "layout (location = 3) in vec4 teColor[];\n" + "layout (location = 4) out vec4 gColor;\n" + "\n" + "void main()\n" + "{\n" + " gColor = teColor[0];\n" + " gColor.b = 1.0;\n" + "\n" + " for (int i = 0; i < 3; ++i) {\n" + " gl_Position = gl_in[i].gl_Position;\n" + " EmitVertex();\n" + " }\n" + " EndPrimitive();\n" + "}\n"; + + m_fragment = "#version 450\n" + "\n" + "layout (location = 4) in vec4 gColor;\n" + "layout (location = 0) out vec4 fColor;\n" + "\n" + "void main()\n" + "{\n" + " fColor = gColor;\n" + "}\n"; + + const Functions& gl = m_context.getRenderContext().getFunctions(); + + gl.genTextures(1, &m_texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "genTextures"); + gl.bindTexture(GL_TEXTURE_2D, m_texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture"); + gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 32, 32); + GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage2D"); + + gl.genFramebuffers(1, &m_fbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "genFramenuffers"); + gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer"); + gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0); + GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture2D"); + + gl.viewport(0, 0, 32, 32); + GLU_EXPECT_NO_ERROR(gl.getError(), "viewport"); +} + +/** Stub de-init method */ +void SpirvModulesPositiveTest::deinit() +{ + const Functions& gl = m_context.getRenderContext().getFunctions(); + + if (m_fbo) + { + gl.deleteFramebuffers(1, &m_fbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "deleteFramebuffers"); + } + if (m_texture) + { + gl.deleteTextures(1, &m_texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "deleteTextures"); + } +} + +/** Executes test iteration. + * + * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. + */ +tcu::TestNode::IterateResult SpirvModulesPositiveTest::iterate() +{ + const Functions& gl = m_context.getRenderContext().getFunctions(); + + const GLfloat vertices[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f }; + + GLuint vao; + gl.genVertexArrays(1, &vao); + GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays"); + gl.bindVertexArray(vao); + GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray"); + + GLuint vbo; + gl.genBuffers(1, &vbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers"); + gl.bindBuffer(GL_ARRAY_BUFFER, vbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer"); + + gl.bufferData(GL_ARRAY_BUFFER, 9 * sizeof(GLfloat), (GLvoid*)vertices, GL_DYNAMIC_DRAW); + GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData"); + + enum Iterates + { + ITERATE_GLSL, + ITERATE_SPIRV, + ITERATE_LAST + }; + + deUint32 outputs[ITERATE_LAST]; + for (int it = ITERATE_GLSL; it < ITERATE_LAST; ++it) + { + ShaderProgram* program = DE_NULL; + if (it == ITERATE_GLSL) + { + ProgramSources sources; + sources << VertexSource(m_vertex); + sources << TessellationControlSource(m_tesselationCtrl); + sources << TessellationEvaluationSource(m_tesselationEval); + sources << GeometrySource(m_geometry); + sources << FragmentSource(m_fragment); + program = new ShaderProgram(gl, sources); + } + else if (it == ITERATE_SPIRV) + { +#if defined DEQP_HAVE_GLSLANG + ProgramBinaries binaries; + binaries << glslangUtils::makeSpirV(m_context.getTestContext().getLog(), VertexSource(m_vertex)); + binaries << glslangUtils::makeSpirV(m_context.getTestContext().getLog(), + TessellationControlSource(m_tesselationCtrl)); + binaries << glslangUtils::makeSpirV(m_context.getTestContext().getLog(), + TessellationEvaluationSource(m_tesselationEval)); + binaries << glslangUtils::makeSpirV(m_context.getTestContext().getLog(), GeometrySource(m_geometry)); + binaries << glslangUtils::makeSpirV(m_context.getTestContext().getLog(), FragmentSource(m_fragment)); + program = new ShaderProgram(gl, binaries); +#else // DEQP_HAVE_GLSLANG + tcu::Archive& archive = m_testCtx.getArchive(); + ProgramBinaries binaries; + binaries << commonUtils::readSpirV(archive.getResource("spirv/modules_positive/vertex.nspv")); + binaries << commonUtils::readSpirV(archive.getResource("spirv/modules_positive/tess_control.nspv")); + binaries << commonUtils::readSpirV(archive.getResource("spirv/modules_positive/tess_evaluation.nspv")); + binaries << commonUtils::readSpirV(archive.getResource("spirv/modules_positive/geometry.nspv")); + binaries << commonUtils::readSpirV(archive.getResource("spirv/modules_positive/fragment.nspv")); + program = new ShaderProgram(gl, binaries); +#endif // DEQP_HAVE_GLSLANG + } + + if (!program->isOk()) + { + m_testCtx.getLog() << tcu::TestLog::Message << "Shader build failed.\n" + << "Vertex: " << program->getShaderInfo(SHADERTYPE_VERTEX).infoLog << "\n" + << m_vertex << "\n" + << "TesselationCtrl: " << program->getShaderInfo(SHADERTYPE_TESSELLATION_CONTROL).infoLog + << "\n" + << m_tesselationCtrl << "\n" + << "TesselationEval: " + << program->getShaderInfo(SHADERTYPE_TESSELLATION_EVALUATION).infoLog << "\n" + << m_tesselationEval << "\n" + << "Geometry: " << program->getShaderInfo(SHADERTYPE_GEOMETRY).infoLog << "\n" + << m_geometry << "\n" + << "Fragment: " << program->getShaderInfo(SHADERTYPE_FRAGMENT).infoLog << "\n" + << m_fragment << "\n" + << "Program: " << program->getProgramInfo().infoLog << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + + gl.useProgram(program->getProgram()); + GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram"); + + gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); + GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor"); + gl.clear(GL_COLOR_BUFFER_BIT); + GLU_EXPECT_NO_ERROR(gl.getError(), "glClear"); + + gl.enableVertexAttribArray(0); + GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray"); + + gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, DE_NULL); + GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer"); + + gl.patchParameteri(GL_PATCH_VERTICES, 3); + gl.drawArrays(GL_PATCHES, 0, 3); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArray"); + + gl.disableVertexAttribArray(0); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDisableVertexAttribArray"); + + gl.readPixels(16, 16, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)&outputs[it]); + GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels"); + + if (program) + delete program; + } + + if (vbo) + { + gl.deleteBuffers(1, &vbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers"); + } + + if (vao) + { + gl.deleteVertexArrays(1, &vao); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteVertexArrays"); + } + + if ((outputs[ITERATE_GLSL] & outputs[ITERATE_SPIRV]) != 0xFFFFFFFF) + { + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + m_testCtx.getLog() << tcu::TestLog::Message << "Wrong output color read from framebuffer.\n" + << "GLSL: " << outputs[ITERATE_GLSL] << ", SPIR-V: " << outputs[ITERATE_SPIRV] + << "Expected: " << (deUint32)0xFFFFFFFF << tcu::TestLog::EndMessage; + return STOP; + } + + m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); + return STOP; +} + +/** Constructor. + * + * @param context Rendering context + * @param name Test name + * @param description Test description + */ +SpirvShaderBinaryMultipleShaderObjectsTest::SpirvShaderBinaryMultipleShaderObjectsTest(deqp::Context& context) + : TestCase(context, "spirv_modules_shader_binary_multiple_shader_objects_test", + "Test verifies if one binary module can be associated with multiple shader objects.") +{ + /* Left blank intentionally */ +} + +/** Stub init method */ +void SpirvShaderBinaryMultipleShaderObjectsTest::init() +{ + m_spirv = "OpCapability Shader\n" + "%1 = OpExtInstImport \"GLSL.std.450\"\n" + "OpMemoryModel Logical GLSL450\n" + "OpEntryPoint Vertex %mainv \"mainv\" %_ %position %gl_VertexID %gl_InstanceID\n" + "OpEntryPoint Fragment %mainf \"mainf\" %fColor\n" + "OpSource GLSL 450\n" + "OpName %mainv \"mainv\"\n" + "OpName %mainf \"mainf\"\n" + "OpName %gl_PerVertex \"gl_PerVertex\"\n" + "OpMemberName %gl_PerVertex 0 \"gl_Position\"\n" + "OpMemberName %gl_PerVertex 1 \"gl_PointSize\"\n" + "OpMemberName %gl_PerVertex 2 \"gl_ClipDistance\"\n" + "OpMemberName %gl_PerVertex 3 \"gl_CullDistance\"\n" + "OpName %_ \"\"\n" + "OpName %position \"position\"\n" + "OpName %gl_VertexID \"gl_VertexID\"\n" + "OpName %gl_InstanceID \"gl_InstanceID\"\n" + "OpMemberDecorate %gl_PerVertex 0 BuiltIn Position\n" + "OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize\n" + "OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance\n" + "OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance\n" + "OpDecorate %gl_PerVertex Block\n" + "OpDecorate %position Location 0\n" + "OpDecorate %gl_VertexID BuiltIn VertexId\n" + "OpDecorate %gl_InstanceID BuiltIn InstanceId\n" + "OpDecorate %fColor Location 0\n" + "%void = OpTypeVoid\n" + "%3 = OpTypeFunction %void\n" + "%float = OpTypeFloat 32\n" + "%v4float = OpTypeVector %float 4\n" + "%uint = OpTypeInt 32 0\n" + "%uint_1 = OpConstant %uint 1\n" + "%_arr_float_uint_1 = OpTypeArray %float %uint_1\n" + "%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1\n" + "%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex\n" + "%_ = OpVariable %_ptr_Output_gl_PerVertex Output\n" + "%int = OpTypeInt 32 1\n" + "%int_0 = OpConstant %int 0\n" + "%v3float = OpTypeVector %float 3\n" + "%_ptr_Input_v3float = OpTypePointer Input %v3float\n" + "%position = OpVariable %_ptr_Input_v3float Input\n" + "%float_1 = OpConstant %float 1\n" + "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" + "%_ptr_Input_int = OpTypePointer Input %int\n" + "%gl_VertexID = OpVariable %_ptr_Input_int Input\n" + "%gl_InstanceID = OpVariable %_ptr_Input_int Input\n" + "%fColor = OpVariable %_ptr_Output_v4float Output\n" + "%fVec4_1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1\n" + "\n" + "%mainv = OpFunction %void None %3\n" + "%5 = OpLabel\n" + "%19 = OpLoad %v3float %position\n" + "%21 = OpCompositeExtract %float %19 0\n" + "%22 = OpCompositeExtract %float %19 1\n" + "%23 = OpCompositeExtract %float %19 2\n" + "%24 = OpCompositeConstruct %v4float %21 %22 %23 %float_1\n" + "%26 = OpAccessChain %_ptr_Output_v4float %_ %int_0\n" + "OpStore %26 %24\n" + "OpReturn\n" + "OpFunctionEnd\n" + "\n" + "%mainf = OpFunction %void None %3\n" + "%32 = OpLabel\n" + "OpStore %fColor %fVec4_1\n" + "OpReturn\n" + "OpFunctionEnd\n"; +} + +/** Stub init method */ +void SpirvShaderBinaryMultipleShaderObjectsTest::deinit() +{ +} + +/** Executes test iteration. + * + * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. + */ +tcu::TestNode::IterateResult SpirvShaderBinaryMultipleShaderObjectsTest::iterate() +{ + const Functions& gl = m_context.getRenderContext().getFunctions(); + + const GLfloat vertices[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f }; + + GLuint texture; + GLuint fbo; + + gl.genTextures(1, &texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "genTextures"); + gl.bindTexture(GL_TEXTURE_2D, texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture"); + gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 32, 32); + GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage2D"); + + gl.genFramebuffers(1, &fbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "genFramenuffers"); + gl.bindFramebuffer(GL_FRAMEBUFFER, fbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer"); + gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); + GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture2D"); + + GLuint vao; + gl.genVertexArrays(1, &vao); + GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays"); + gl.bindVertexArray(vao); + GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray"); + + GLuint vbo; + gl.genBuffers(1, &vbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers"); + gl.bindBuffer(GL_ARRAY_BUFFER, vbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer"); + + gl.bufferData(GL_ARRAY_BUFFER, 9 * sizeof(GLfloat), (GLvoid*)vertices, GL_DYNAMIC_DRAW); + GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData"); + +#if DEQP_HAVE_SPIRV_TOOLS + ShaderBinary binary; + binary << SHADERTYPE_VERTEX << "mainv"; + binary << SHADERTYPE_FRAGMENT << "mainf"; + + glslangUtils::spirvAssemble(binary.binary, m_spirv); +#else // DEQP_HAVE_SPIRV_TOOLS + tcu::Archive& archive = m_testCtx.getArchive(); + ShaderBinary binary = commonUtils::readSpirV( + archive.getResource("spirv/spirv_modules_shader_binary_multiple_shader_objects/binary.nspv")); +#endif // DEQP_HAVE_SPIRV_TOOLS + + ProgramBinaries binaries; + binaries << binary; + ShaderProgram program(gl, binaries); + + if (!program.isOk()) + { + m_testCtx.getLog() << tcu::TestLog::Message << "Shader build failed.\n" + << "Vertex: " << program.getShaderInfo(SHADERTYPE_VERTEX).infoLog << "\n" + << "Fragment: " << program.getShaderInfo(SHADERTYPE_FRAGMENT).infoLog << "\n" + << "Program: " << program.getProgramInfo().infoLog << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + + gl.viewport(0, 0, 32, 32); + GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport"); + + gl.useProgram(program.getProgram()); + GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram"); + + gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); + GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor"); + gl.clear(GL_COLOR_BUFFER_BIT); + GLU_EXPECT_NO_ERROR(gl.getError(), "glClear"); + + gl.enableVertexAttribArray(0); + GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray"); + + gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, DE_NULL); + GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer"); + + gl.drawArrays(GL_TRIANGLE_STRIP, 0, 3); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArray"); + + gl.disableVertexAttribArray(0); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDisableVertexAttribArray"); + + GLuint insidePixel; + GLuint outsidePixel; + gl.readPixels(16, 16, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)&insidePixel); + GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels"); + gl.readPixels(2, 30, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)&outsidePixel); + GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels"); + + if (vbo) + { + gl.deleteBuffers(1, &vbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers"); + } + + if (vao) + { + gl.deleteVertexArrays(1, &vao); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteVertexArrays"); + } + + if (fbo) + { + gl.deleteFramebuffers(1, &fbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteFramebuffers"); + } + + if (texture) + { + gl.deleteTextures(1, &texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures"); + } + + if (insidePixel == 0xFFFFFFFF && outsidePixel == 0xFF000000) + m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); + else + { + m_testCtx.getLog() << tcu::TestLog::Message << "Wrong pixels color read.\n" + << "Expected (inside/outside): " << 0xFFFFFFFF << "/" << 0xFF000000 << "\n" + << "Read: " << insidePixel << "/" << outsidePixel << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + } + + return STOP; +} + +/** Constructor. + * + * @param context Rendering context + * @param name Test name + * @param description Test description + */ +SpirvModulesStateQueriesTest::SpirvModulesStateQueriesTest(deqp::Context& context) + : TestCase(context, "spirv_modules_state_queries_test", + "Test verifies if state queries for new features added by ARB_gl_spirv works as expected.") +{ + /* Left blank intentionally */ +} + +/** Stub init method */ +void SpirvModulesStateQueriesTest::init() +{ + if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gl_spirv")) + TCU_THROW(NotSupportedError, "GL_ARB_gl_spirv is not supported"); + + m_vertex = "#version 450\n" + "\n" + "layout (location = 0) in vec4 position;\n" + "layout (location = 20) uniform vec4 extPosition;\n" + "layout (location = 40) uniform ComponentsBlock\n" + "{\n" + " vec4 c1;\n" + " vec2 c2;\n" + "} components;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = position + extPosition + components.c1 + vec4(components.c2, 0.0, 0.0);\n" + "}\n"; +} + +/** Stub de-init method */ +void SpirvModulesStateQueriesTest::deinit() +{ +} + +/** Executes test iteration. + * + * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. + */ +tcu::TestNode::IterateResult SpirvModulesStateQueriesTest::iterate() +{ + const Functions& gl = m_context.getRenderContext().getFunctions(); + + ProgramBinaries binaries; + ShaderBinary vertexBinary; + +#if defined DEQP_HAVE_GLSLANG && DEQP_HAVE_SPIRV_TOOLS + { + vertexBinary = glslangUtils::makeSpirV(m_context.getTestContext().getLog(), VertexSource(m_vertex)); + + // Disassemble Spir-V module + std::string output; + glslangUtils::spirvDisassemble(output, vertexBinary.binary); + + // Remove name reflection for defined variables + std::vector lines = de::splitString(output, '\n'); + std::string input; + for (int i = 0; i < lines.size(); ++i) + { + if (lines[i].find("OpName %position") != std::string::npos) + continue; + if (lines[i].find("OpName %extPosition") != std::string::npos) + continue; + if (lines[i].find("OpName %ComponentsBlock") != std::string::npos) + continue; + if (lines[i].find("OpName %components") != std::string::npos) + continue; + + input.append(lines[i] + "\n"); + } + + // Assemble Spir-V module + vertexBinary.binary.clear(); + glslangUtils::spirvAssemble(vertexBinary.binary, input); + } +#else // DEQP_HAVE_GLSLANG && DEQP_HAVE_SPIRV_TOOLS + tcu::Archive& archive = m_testCtx.getArchive(); + vertexBinary = commonUtils::readSpirV(archive.getResource("spirv/modules_state_queries/vertex.nspv")); +#endif // DEQP_HAVE_GLSLANG && DEQP_HAVE_SPIRV_TOOLS + + binaries << vertexBinary; + ShaderProgram program(gl, binaries); + + Shader* shader = program.getShader(SHADERTYPE_VERTEX); + + // 1) Check compile status + if (!program.getShaderInfo(SHADERTYPE_VERTEX).compileOk) + { + m_testCtx.getLog() << tcu::TestLog::Message << "Check compile status failed.\n" + << "Vertex: " << program.getShaderInfo(SHADERTYPE_VERTEX).infoLog << "\n" + << m_vertex << "\n" + << "Program: " << program.getProgramInfo().infoLog << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + + // 2) Check if SPIR_V_BINARY_ARB state is TRUE + GLint shaderState; + gl.getShaderiv(shader->getShader(), GL_SPIR_V_BINARY_ARB, &shaderState); + GLU_EXPECT_NO_ERROR(gl.getError(), "getShaderiv"); + if (shaderState != GL_TRUE) + { + m_testCtx.getLog() << tcu::TestLog::Message << "SPIR_V_BINARY_ARB state set to FALSE. Expected TRUE." + << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + + // 3) Check if queries for ACTIVE_ATTRIBUTE_MAX_LENGTH, ACTIVE_UNIFORM_MAX_LENGTH, TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, + // ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH return value equal to 1. + GLint programState[4]; + gl.getProgramiv(program.getProgram(), GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &programState[0]); + GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramiv"); + + gl.getProgramiv(program.getProgram(), GL_ACTIVE_UNIFORM_MAX_LENGTH, &programState[1]); + GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramiv"); + + gl.getProgramiv(program.getProgram(), GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &programState[2]); + GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramiv"); + + gl.getProgramiv(program.getProgram(), GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &programState[3]); + GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramiv"); + + bool programStateResult = true; + for (int i = 0; i < 4; ++i) + { + if (programState[i] != 1) + { + m_testCtx.getLog() << tcu::TestLog::Message << "Check max name length [" << i << "] failed. " + << "Expected: 1, Queried: " << programState[i] << "\n" + << tcu::TestLog::EndMessage; + programStateResult = false; + } + } + + if (!programStateResult) + { + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + + // 4) Check if ShaderSource command usage on Spir-V binary shader will change SPIR_V_BINARY_ARB state to FALSE + const char* source = m_vertex.c_str(); + const int length = m_vertex.length(); + gl.shaderSource(shader->getShader(), 1, &source, &length); + GLU_EXPECT_NO_ERROR(gl.getError(), "shaderSource"); + + gl.getShaderiv(shader->getShader(), GL_SPIR_V_BINARY_ARB, &shaderState); + GLU_EXPECT_NO_ERROR(gl.getError(), "getShaderiv"); + if (shaderState != GL_FALSE) + { + m_testCtx.getLog() << tcu::TestLog::Message << "SPIR_V_BINARY_ARB state set to TRUE. Expected FALSE." + << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + + m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); + return STOP; +} + +/** Constructor. + * + * @param context Rendering context + * @param name Test name + * @param description Test description + */ +SpirvModulesErrorVerificationTest::SpirvModulesErrorVerificationTest(deqp::Context& context) + : TestCase(context, "spirv_modules_error_verification_test", + "Test verifies if new features added by ARB_gl_spirv generate error messages as expected.") +{ + /* Left blank intentionally */ +} + +/** Stub init method */ +void SpirvModulesErrorVerificationTest::init() +{ + if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gl_spirv")) + TCU_THROW(NotSupportedError, "GL_ARB_gl_spirv is not supported"); + + const Functions& gl = m_context.getRenderContext().getFunctions(); + + m_vertex = "#version 450\n" + "\n" + "layout (location = 0) in vec4 position;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = position;\n" + "}\n"; + + m_glslShaderId = gl.createShader(GL_VERTEX_SHADER); + GLU_EXPECT_NO_ERROR(gl.getError(), "createShader"); + + m_spirvShaderId = gl.createShader(GL_VERTEX_SHADER); + GLU_EXPECT_NO_ERROR(gl.getError(), "createShader"); + + m_programId = gl.createProgram(); + GLU_EXPECT_NO_ERROR(gl.getError(), "createProgram"); + + gl.genTextures(1, &m_textureId); + GLU_EXPECT_NO_ERROR(gl.getError(), "genTextures"); +} + +/** Stub de-init method */ +void SpirvModulesErrorVerificationTest::deinit() +{ + const Functions& gl = m_context.getRenderContext().getFunctions(); + + gl.deleteTextures(1, &m_textureId); + GLU_EXPECT_NO_ERROR(gl.getError(), "deleteTextures"); + + gl.deleteProgram(m_programId); + GLU_EXPECT_NO_ERROR(gl.getError(), "deleteProgram"); + + gl.deleteShader(m_glslShaderId); + GLU_EXPECT_NO_ERROR(gl.getError(), "deleteShader"); + + gl.deleteShader(m_spirvShaderId); + GLU_EXPECT_NO_ERROR(gl.getError(), "deleteShader"); +} + +/** Executes test iteration. + * + * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. + */ +tcu::TestNode::IterateResult SpirvModulesErrorVerificationTest::iterate() +{ + const Functions& gl = m_context.getRenderContext().getFunctions(); + + const char* shaderSrc = m_vertex.c_str(); + const int shaderLen = m_vertex.length(); + + ShaderBinary vertexBinary; + +#if defined DEQP_HAVE_GLSLANG + vertexBinary = glslangUtils::makeSpirV(m_context.getTestContext().getLog(), VertexSource(m_vertex)); +#else // DEQP_HAVE_GLSLANG + tcu::Archive& archive = m_testCtx.getArchive(); + vertexBinary = commonUtils::readSpirV(archive.getResource("spirv/modules_error_verification/vertex.nspv")); +#endif // DEQP_HAVE_GLSLANG + + gl.shaderSource(m_glslShaderId, 1, &shaderSrc, &shaderLen); + GLU_EXPECT_NO_ERROR(gl.getError(), "shaderSource"); + + gl.shaderBinary(1, &m_spirvShaderId, GL_SHADER_BINARY_FORMAT_SPIR_V_ARB, (GLvoid*)vertexBinary.binary.data(), + vertexBinary.binary.size() * sizeof(deUint32)); + GLU_EXPECT_NO_ERROR(gl.getError(), "shaderBinary"); + + gl.attachShader(m_programId, m_spirvShaderId); + GLU_EXPECT_NO_ERROR(gl.getError(), "attachShader"); + + GLint err; + + // 1) Verify if CompileShader function used on shader with SPIR_V_BINARY_ARB state + // will result in generating INVALID_OPERATION error. + gl.compileShader(m_spirvShaderId); + err = gl.getError(); + if (err != GL_INVALID_OPERATION) + { + m_testCtx.getLog() + << tcu::TestLog::Message + << "Unexpected error code generated by CompileShader [1]. Expected INVALID_OPERATION, generated: " + << glu::getErrorName(err) << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + + // 2) Verify if SpecializeShader function generate INVALID_VALUE error when + // is not the name of either a program or shader object. + gl.specializeShader(0xFFFF, "main", 0, DE_NULL, DE_NULL); + err = gl.getError(); + if (err != GL_INVALID_VALUE) + { + m_testCtx.getLog() + << tcu::TestLog::Message + << "Unexpected error code generated by SpecializeShader [2]. Expected INVALID_VALUE, generated: " + << glu::getErrorName(err) << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + + // 3) Verify if SpecializeShader function generate INVALID_OPERATION error when + // is the name of a program object. + gl.specializeShader(m_programId, "main", 0, DE_NULL, DE_NULL); + err = gl.getError(); + if (err != GL_INVALID_OPERATION) + { + m_testCtx.getLog() + << tcu::TestLog::Message + << "Unexpected error code generated by SpecializeShader [3]. Expected INVALID_OPERATION, generated: " + << glu::getErrorName(err) << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + + // 4) Verify if SpecializeShader function generate INVALID_OPERATION error when + // SPIR_V_BINARY_ARB state for is not TRUE. + gl.specializeShader(m_glslShaderId, "main", 0, DE_NULL, DE_NULL); + err = gl.getError(); + if (err != GL_INVALID_OPERATION) + { + m_testCtx.getLog() + << tcu::TestLog::Message + << "Unexpected error code generated by SpecializeShader [4]. Expected INVALID_OPERATION, generated: " + << glu::getErrorName(err) << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + + // 5) Verify if SpecializeShader function generate INVALID_VALUE when + // does not name a valid entry point for . + gl.specializeShader(m_spirvShaderId, "entry", 0, DE_NULL, DE_NULL); + err = gl.getError(); + if (err != GL_INVALID_VALUE) + { + m_testCtx.getLog() + << tcu::TestLog::Message + << "Unexpected error code generated by SpecializeShader [5]. Expected INVALID_VALUE, generated: " + << glu::getErrorName(err) << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + + // 6) Verify if SpecializeShader function generate INVALID_VALUE when any element + // of refers to a specialization constant that does not exist + // in the shader module contained in . + const GLuint specID = 10; + const GLuint specValue = 10; + gl.specializeShader(m_spirvShaderId, "main", 1, &specID, &specValue); + err = gl.getError(); + if (err != GL_INVALID_VALUE) + { + m_testCtx.getLog() + << tcu::TestLog::Message + << "Unexpected error code generated by SpecializeShader [6]. Expected INVALID_VALUE, generated: " + << glu::getErrorName(err) << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + + // 7) Verify if LinkProgram fail when one or more of the shader objects attached to + // are not specialized. + gl.linkProgram(m_programId); + err = gl.getError(); + if (err == GL_NO_ERROR) + { + GLint linkStatus; + gl.getProgramiv(m_programId, GL_LINK_STATUS, &linkStatus); + GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramiv"); + + if (linkStatus != 0) + { + m_testCtx.getLog() << tcu::TestLog::Message << "Unexpected result of LinkProgram [7]." + << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + } + + // 8) Verify if SpecializeShader function generate INVALID_OPERATION error if the + // shader has already been specialized. + gl.specializeShader(m_spirvShaderId, "main", 0, DE_NULL, DE_NULL); + GLU_EXPECT_NO_ERROR(gl.getError(), "specializeShader"); + + gl.specializeShader(m_spirvShaderId, "main", 0, DE_NULL, DE_NULL); + err = gl.getError(); + if (err != GL_INVALID_OPERATION) + { + m_testCtx.getLog() + << tcu::TestLog::Message + << "Unexpected error code generated by SpecializeShader [8]. Expected INVALID_OPERATION, generated: " + << glu::getErrorName(err) << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + + // 9) Verify if LinkProgram fail when not all of shaders attached to have + // the same value for the SPIR_V_BINARY_ARB state. + gl.compileShader(m_glslShaderId); + GLU_EXPECT_NO_ERROR(gl.getError(), "compileShader"); + + gl.attachShader(m_programId, m_glslShaderId); + GLU_EXPECT_NO_ERROR(gl.getError(), "attachShader"); + + gl.linkProgram(m_programId); + err = gl.getError(); + if (err == GL_NO_ERROR) + { + GLint linkStatus; + gl.getProgramiv(m_programId, GL_LINK_STATUS, &linkStatus); + GLU_EXPECT_NO_ERROR(gl.getError(), "getProgramiv"); + + if (linkStatus != 0) + { + m_testCtx.getLog() << tcu::TestLog::Message << "Unexpected result of LinkProgram [9]." + << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + } + + m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); + return STOP; +} + +/** Constructor. + * + * @param context Rendering context + * @param name Test name + * @param description Test description + */ +SpirvGlslToSpirVEnableTest::SpirvGlslToSpirVEnableTest(deqp::Context& context) + : TestCase(context, "spirv_glsl_to_spirv_enable_test", "Test verifies if glsl supports Spir-V features.") +{ + /* Left blank intentionally */ +} + +/** Stub init method */ +void SpirvGlslToSpirVEnableTest::init() +{ + if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gl_spirv")) + TCU_THROW(NotSupportedError, "GL_ARB_gl_spirv is not supported"); + + m_vertex = "#version 450\n" + "\n" + "#ifdef GL_SPIRV\n" + " layout (location = 0) in vec4 enabled;\n" + "#else\n" + " layout (location = 0) in vec4 notEnabled;\n" + "#endif // GL_SPIRV\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = vec4(0.0, 0.0, 0.0, 0.0);\n" + "}\n"; +} + +/** Stub de-init method */ +void SpirvGlslToSpirVEnableTest::deinit() +{ +} + +/** Executes test iteration. + * + * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. + */ +tcu::TestNode::IterateResult SpirvGlslToSpirVEnableTest::iterate() +{ + +#if defined DEQP_HAVE_GLSLANG && DEQP_HAVE_SPIRV_TOOLS + { + const Functions& gl = m_context.getRenderContext().getFunctions(); + + ProgramBinaries binaries; + ShaderBinary vertexBinary = + glslangUtils::makeSpirV(m_context.getTestContext().getLog(), VertexSource(m_vertex)); + binaries << vertexBinary; + ShaderProgram spirvProgram(gl, binaries); + + std::string spirvSource; + glslangUtils::spirvDisassemble(spirvSource, vertexBinary.binary); + + if (spirvSource.find("OpName %enabled") == std::string::npos) + { + m_testCtx.getLog() << tcu::TestLog::Message << "GL_SPIRV not defined. Spir-V source:\n" + << spirvSource.c_str() << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + + if (!spirvProgram.isOk()) + { + m_testCtx.getLog() << tcu::TestLog::Message << "Shader compilation failed. Source:\n" + << spirvSource.c_str() << "InfoLog:\n" + << spirvProgram.getShaderInfo(SHADERTYPE_VERTEX).infoLog << "\n" + << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + + m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); + } +#else // DEQP_HAVE_GLSLANG && DEQP_HAVE_SPIRV_TOOLS + + TCU_THROW(InternalError, "Either glslang or spirv-tools not available."); + +#endif // DEQP_HAVE_GLSLANG && DEQP_HAVE_SPIRV_TOOLS + + return STOP; +} + +enum EShaderTemplate +{ + COMPUTE_TEMPLATE, + TESSCTRL_TEMPLATE, + GEOMETRY_TEMPLATE, + FRAGMENT_TEMPLATE +}; + +struct FunctionMapping +{ + EShaderTemplate shaderTemplate; + std::string glslFunc; + std::string glslArgs; + std::string spirVFunc; + + FunctionMapping() : shaderTemplate(COMPUTE_TEMPLATE), glslFunc(""), glslArgs(""), spirVFunc("") + { + } + + FunctionMapping(EShaderTemplate shaderTemplate_, std::string glslFunc_, std::string glslArgs_, + std::string spirVFunc_) + : shaderTemplate(shaderTemplate_), glslFunc(glslFunc_), glslArgs(glslArgs_), spirVFunc(spirVFunc_) + { + } +}; + +/** Constructor. + * + * @param context Rendering context + * @param name Test name + * @param description Test description + */ +SpirvGlslToSpirVBuiltInFunctionsTest::SpirvGlslToSpirVBuiltInFunctionsTest(deqp::Context& context) + : TestCase(context, "spirv_glsl_to_spirv_builtin_functions_test", + "Test verifies if GLSL built-in functions are supported by Spir-V.") +{ + /* Left blank intentionally */ +} + +/** Stub init method */ +void SpirvGlslToSpirVBuiltInFunctionsTest::init() +{ + if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gl_spirv")) + TCU_THROW(NotSupportedError, "GL_ARB_gl_spirv is not supported"); + + initMappings(); + + m_commonVertex = "#version 450\n" + "\n" + "layout (location = 0) in vec3 position;\n" + "layout (location = 1) out vec2 texCoord;\n" + "\n" + "void main()\n" + "{\n" + " texCoord = vec2(0.0, 0.0);\n" + " gl_Position = vec4(position, 1.0);\n" + "}\n"; + + m_commonTessEval = "#version 450\n" + "\n" + "layout (triangles) in;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = gl_TessCoord.x * gl_in[0].gl_Position +\n" + " gl_TessCoord.y * gl_in[1].gl_Position +\n" + " gl_TessCoord.z * gl_in[2].gl_Position;\n" + "}\n"; + + m_sources.clear(); + + // Angle Trigonometry + m_sources.push_back(ComputeSource("#version 450\n" + "\n" + "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" + "\n" + "void main()\n" + "{\n" + " float tmp0 = 0.5;\n" + " float value;\n" + " value = radians(tmp0) +\n" + " degrees(tmp0) +\n" + " sin(tmp0) +\n" + " cos(tmp0) +\n" + " tan(tmp0) +\n" + " asin(tmp0) +\n" + " acos(tmp0) +\n" + " atan(tmp0) +\n" + " atan(tmp0) +\n" + " sinh(tmp0) +\n" + " cosh(tmp0) +\n" + " tanh(tmp0) +\n" + " asinh(tmp0) +\n" + " acosh(tmp0) +\n" + " atanh(tmp0);\n" + "}\n")); + + // To avoid duplicated mappings create additional shaders for specific functions + const std::string strAnlgeVariants = "#version 450\n" + "\n" + "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" + "\n" + "void main()\n" + "{\n" + " float tmp0 = 0.5;\n" + " float value = ;\n" + "}\n"; + std::string strATan = strAnlgeVariants; + std::string strATan2 = strAnlgeVariants; + commonUtils::replaceToken("", "atan(tmp0, tmp0)", strATan); + commonUtils::replaceToken("", "atan(tmp0)", strATan2); + + m_sources.push_back(ComputeSource(strATan)); + m_sources.push_back(ComputeSource(strATan2)); + + // Exponential + m_sources.push_back(ComputeSource("#version 450\n" + "\n" + "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" + "\n" + "void main()\n" + "{\n" + " float tmp0;\n" + " float tmp1;\n" + " float value;\n" + " value = pow(tmp1, tmp0) +\n" + " exp(tmp0) +\n" + " log(tmp1) +\n" + " exp2(tmp0) +\n" + " log2(tmp1) +\n" + " sqrt(tmp1) +\n" + " inversesqrt(tmp1);\n" + "}\n")); + + // Common (without bit operations) + m_sources.push_back(ComputeSource("#version 450\n" + "\n" + "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" + "\n" + "void main()\n" + "{\n" + " float value;\n" + " float outval;\n" + " float fpval = 0.5;\n" + " float fnval = -0.5;\n" + " int ival = 0x43800000;\n" + " uint uival= 0xC3800000;\n" + " value = abs(fnval) +\n" + " sign(fpval) +\n" + " floor(fpval) +\n" + " trunc(fpval) +\n" + " round(fpval) +\n" + " roundEven(fpval) +\n" + " ceil(fpval) +\n" + " fract(fpval) +\n" + " mod(fpval, 2.0) +\n" + " modf(fpval, outval) +\n" + " min(fpval, 0.2) +\n" + " max(fpval, 0.2) +\n" + " clamp(fpval, 0.8, 2.0) +\n" + " mix(fnval, fpval, 0.5) +\n" + " step(1.0, fpval) +\n" + " smoothstep(0.0, 1.0, fpval) +\n" + " float( isnan(fpval)) +\n" + " float( isinf(fpval)) +\n" + " fma(fpval, 1.0, fnval) +\n" + " frexp(4.0, ival) +\n" + " ldexp(4.0, ival);\n" + "}\n")); + + // To avoid duplicated mappings create additional shaders for specific functions + const std::string strBitsOpsVariants = "#version 450\n" + "\n" + "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" + "\n" + "void main()\n" + "{\n" + " float value;\n" + " int ival = 0x43800000;\n" + " uint uval = 0x43800000;\n" + " value = ;\n" + "}\n"; + std::string strIntBits = strBitsOpsVariants; + std::string strUIntBits = strBitsOpsVariants; + commonUtils::replaceToken("", "intBitsToFloat(ival)", strIntBits); + commonUtils::replaceToken("", "uintBitsToFloat(uval)", strUIntBits); + + m_sources.push_back(ComputeSource(strIntBits)); + m_sources.push_back(ComputeSource(strUIntBits)); + + // Float Pack Unpack + m_sources.push_back(ComputeSource("#version 450\n" + "\n" + "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" + "\n" + "void main()\n" + "{\n" + " vec2 v2val = vec2(0.1, 0.2);\n" + " vec4 v4val = vec4(0.1, 0.2, 0.3, 0.4);\n" + " uint uival1 = packUnorm2x16(v2val);\n" + " uint uival2 = packSnorm2x16(v2val);\n" + " uint uival3 = packUnorm4x8(v4val);\n" + " uint uival4 = packSnorm4x8(v4val);\n" + " v2val = unpackUnorm2x16(uival1);\n" + " v2val = unpackSnorm2x16(uival2);\n" + " v4val = unpackUnorm4x8(uival3);\n" + " v4val = unpackSnorm4x8(uival4);\n" + " uvec2 uv2val = uvec2(10, 20);\n" + " double dval = packDouble2x32(uv2val);\n" + " uv2val = unpackDouble2x32(dval);\n" + " uint uival5 = packHalf2x16(v2val);\n" + " v2val = unpackHalf2x16(uival5);\n" + "}\n")); + + // Geometric + m_sources.push_back(ComputeSource("#version 450\n" + "\n" + "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" + "\n" + "void main()\n" + "{\n" + " vec3 v3val1 = vec3(0.1, 0.5, 1.0);\n" + " vec3 v3val2 = vec3(0.5, 0.3, 0.9);\n" + " vec3 v3val3 = vec3(1.0, 0.0, 0.0);\n" + " float fval = length(v3val1) +\n" + " distance(v3val1, v3val2) +\n" + " dot(v3val1, v3val2);\n" + " vec3 crossp = cross(v3val1, v3val2);\n" + " vec3 norm = normalize(crossp);\n" + " vec3 facef = faceforward(v3val1, v3val2, v3val3);\n" + " vec3 refl = reflect(v3val1, v3val2);\n" + " float eta = 0.1;\n" + " vec3 refr = refract(v3val1, v3val2, eta);" + "}\n")); + + // Matrix + m_sources.push_back(ComputeSource("#version 450\n" + "\n" + "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" + "\n" + "void main()\n" + "{\n" + " mat2 m2val1 = mat2(\n" + " 0.1, 0.5,\n" + " 0.2, 0.4\n" + " );\n" + " mat2 m2val2 = mat2(\n" + " 0.8, 0.2,\n" + " 0.9, 0.1\n" + " );\n" + " vec2 v2val1 = vec2(0.3, 0.4);\n" + " vec2 v2val2 = vec2(0.5, 0.6);\n" + "\n" + " mat2 m2comp = matrixCompMult(m2val1, m2val2);\n" + " mat2 m2outerp = outerProduct(v2val1, v2val2);\n" + " mat2 m2trans = transpose(m2val1);\n" + " float fdet = determinant(m2val2);\n" + " mat2 m2inv = inverse(m2trans);\n" + "}\n")); + + // Vector Relational + m_sources.push_back(ComputeSource("#version 450\n" + "\n" + "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" + "\n" + "void main()\n" + "{\n" + " vec2 v2val1 = vec2(0.5, 0.2);\n" + " vec2 v2val2 = vec2(0.1, 0.8);\n" + " bvec2 bv2val1 = lessThan(v2val1, v2val2);\n" + " bvec2 bv2val2 = lessThanEqual(v2val1, v2val2);\n" + " bvec2 bv2val3 = greaterThan(v2val1, v2val2);\n" + " bvec2 bv2val4 = greaterThanEqual(v2val1, v2val2);\n" + " bvec2 bv2val5 = equal(v2val1, v2val2);\n" + " bvec2 bv2val6 = notEqual(v2val1, v2val2);\n" + " bool bval1 = any(bv2val1);\n" + " bool bval2 = all(bv2val1);\n" + " bvec2 bv2val7 = not(bv2val1);\n" + "}\n")); + + // Integer + m_sources.push_back(ComputeSource("#version 450\n" + "\n" + "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" + "\n" + "void main()\n" + "{\n" + " int ival = 0;\n" + " uint uival = 200;\n" + " uint uivalRet1;\n" + " uint uivalRet2;\n" + " uivalRet2 = uaddCarry(uival, 0xFFFFFFFF, uivalRet1);\n" + " uivalRet2 = usubBorrow(uival, 0xFFFFFFFF, uivalRet1);\n" + " umulExtended(uival, 0xFFFFFFFF, uivalRet1, uivalRet2);\n" + " uivalRet1 = bitfieldExtract(uival, 3, 8);\n" + " uivalRet1 = bitfieldInsert(uival, 0xFFFFFFFF, 3, 8);\n" + " uivalRet1 = bitfieldReverse(uival);\n" + " ival = bitCount(uival);\n" + " ival = findLSB(uival);\n" + " ival = findMSB(uival);\n" + "}\n")); + + // Texture + m_sources.push_back( + FragmentSource("#version 450\n" + "\n" + "layout (location = 0) out vec4 fragColor;\n" + "\n" + "layout (location = 1) uniform sampler2D tex2D;\n" + "layout (location = 2) uniform sampler2DMS tex2DMS;\n" + "\n" + "void main()\n" + "{\n" + " ivec2 iv2size = textureSize(tex2D, 0);\n" + " vec2 v2lod = textureQueryLod(tex2D, vec2(0.0));\n" + " int ilev = textureQueryLevels(tex2D);\n" + " int isamp = textureSamples(tex2DMS);\n" + " vec4 v4pix = textureLod(tex2D, vec2(0.0), 0.0) +\n" + " textureOffset(tex2D, vec2(0.0), ivec2(2)) +\n" + " texelFetch(tex2D, ivec2(2), 0) +\n" + " texelFetchOffset(tex2D, ivec2(2), 0, ivec2(2)) +\n" + " textureProjOffset(tex2D, vec3(0.0), ivec2(2)) +\n" + " textureLodOffset(tex2D, vec2(0.0), 0.0, ivec2(2)) +\n" + " textureProjLod(tex2D, vec3(0.0), 0.0) +\n" + " textureProjLodOffset(tex2D, vec3(0.0), 0.0, ivec2(2)) +\n" + " textureGrad(tex2D, vec2(0.0), vec2(0.2), vec2(0.5)) +\n" + " textureGradOffset(tex2D, vec2(0.0), vec2(0.2), vec2(0.5), ivec2(2)) +\n" + " textureProjGrad(tex2D, vec3(0.0), vec2(0.2), vec2(0.5)) +\n" + " textureProjGradOffset(tex2D, vec3(0.0), vec2(0.2), vec2(0.5), ivec2(2)) +\n" + " textureGatherOffset(tex2D, vec2(0.0), ivec2(2), 0);\n" + " fragColor = vec4(0.0);\n" + "}\n")); + + // To avoid duplicated mappings create additional shaders for specific functions + const std::string strTextureVariants = "#version 450\n" + "\n" + "layout (location = 0) out vec4 fragColor;\n" + "\n" + "layout (location = 1) uniform sampler2D tex2D;\n" + "\n" + "void main()\n" + "{\n" + " fragColor = ;\n" + "}\n"; + std::string strTexture = strTextureVariants; + std::string strTextureProj = strTextureVariants; + std::string strTextureGather = strTextureVariants; + commonUtils::replaceToken("", "texture(tex2D, vec2(0.0))", strTexture); + commonUtils::replaceToken("", "textureProj(tex2D, vec3(0.0))", strTextureProj); + commonUtils::replaceToken("", "textureGather(tex2D, vec2(0.0), 0)", strTextureGather); + + m_sources.push_back(FragmentSource(strTexture)); + m_sources.push_back(FragmentSource(strTextureProj)); + m_sources.push_back(FragmentSource(strTextureGather)); + + // Atomic Counter + m_sources.push_back(ComputeSource("#version 450\n" + "\n" + "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" + "\n" + "layout (binding = 0) uniform atomic_uint auival;\n" + "\n" + "void main()\n" + "{\n" + " uint uival = atomicCounterIncrement(auival) +\n" + " atomicCounterDecrement(auival) +\n" + " atomicCounter(auival);\n" + "}\n")); + + // Atomic Memory + m_sources.push_back(ComputeSource("#version 450\n" + "\n" + "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" + "\n" + "shared uint uishared;\n" + "\n" + "void main()\n" + "{\n" + " uint uival2 = 5;\n" + " uint uivalRet = atomicAdd(uishared, uival2) +\n" + " atomicMin(uishared, uival2) +\n" + " atomicMax(uishared, uival2) +\n" + " atomicAnd(uishared, uival2) +\n" + " atomicOr(uishared, uival2) +\n" + " atomicXor(uishared, uival2) +\n" + " atomicExchange(uishared, uival2) +\n" + " atomicCompSwap(uishared, uishared, uival2);\n" + "}\n")); + + // Image + m_sources.push_back(ComputeSource("#version 450\n" + "\n" + "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" + "\n" + "layout (location = 1, rgba8ui) uniform readonly uimage2D rimg2D;\n" + "layout (location = 2, rgba8ui) uniform readonly uimage2DMS rimg2DMS;\n" + "layout (location = 3, rgba8ui) uniform writeonly uimage2D wimg2D;\n" + "layout (location = 4, r32ui) uniform uimage2D aimg2D;\n" + "\n" + "void main()\n" + "{\n" + " ivec2 size = imageSize(rimg2D);\n" + " int samp = imageSamples(rimg2DMS);\n" + " uvec4 v4pix = imageLoad(rimg2D, ivec2(0));\n" + " imageStore(wimg2D, ivec2(0), uvec4(255));\n" + " uint uivalRet = imageAtomicAdd(aimg2D, ivec2(0), 1) +\n" + " imageAtomicMin(aimg2D, ivec2(0), 1) +\n" + " imageAtomicMax(aimg2D, ivec2(0), 1) +\n" + " imageAtomicAnd(aimg2D, ivec2(0), 1) +\n" + " imageAtomicOr(aimg2D, ivec2(0), 1) +\n" + " imageAtomicXor(aimg2D, ivec2(0), 1) +\n" + " imageAtomicExchange(aimg2D, ivec2(0), 1) +\n" + " imageAtomicCompSwap(aimg2D, ivec2(0), 1, 2);\n" + "}\n")); + + // Fragment Processing + m_sources.push_back(FragmentSource("#version 450\n" + "\n" + "layout (location = 0) out vec4 fragColor;\n" + "layout (location = 1) in vec2 texCoord;\n" + "\n" + "void main()\n" + "{\n" + " vec2 p = vec2(0.0);\n" + " vec2 dx = dFdx(p);\n" + " vec2 dy = dFdy(p);\n" + " dx = dFdxFine(p);\n" + " dy = dFdyFine(p);\n" + " dx = dFdxCoarse(p);\n" + " dy = dFdyCoarse(p);\n" + " vec2 fw = fwidth(p);\n" + " fw = fwidthFine(p);\n" + " fw = fwidthCoarse(p);\n" + " vec2 interp = interpolateAtCentroid(texCoord) +\n" + " interpolateAtSample(texCoord, 0) +\n" + " interpolateAtOffset(texCoord, vec2(0.0));\n" + " fragColor = vec4(1.0);\n" + "}\n")); + + // To avoid duplicated mappings create additional shaders for specific functions + const std::string strEmitVariants = "#version 450\n" + "\n" + "layout (points) in;\n" + "layout (points, max_vertices = 3) out;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = vec4(0.0);\n" + " ;\n" + " ;\n" + "}\n"; + std::string strEmit = strEmitVariants; + std::string strEmitStream = strEmitVariants; + commonUtils::replaceToken("", "EmitVertex()", strEmit); + commonUtils::replaceToken("", "EmitStreamVertex(0)", strEmitStream); + commonUtils::replaceToken("", "EndPrimitive()", strEmit); + commonUtils::replaceToken("", "EndStreamPrimitive(0)", strEmitStream); + + m_sources.push_back(GeometrySource(strEmit)); + m_sources.push_back(GeometrySource(strEmitStream)); + + // Shader Invocation Control + m_sources.push_back( + TessellationControlSource("#version 450\n" + "\n" + "layout (vertices = 3) out;\n" + "\n" + "void main()\n" + "{\n" + " barrier();\n" + "\n" + " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" + "}\n")); + + // Shared Memory Control + // To avoid duplicated mappings create additional shaders for specific functions + const std::string strMemoryBarrierSource = "#version 450\n" + "\n" + "layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n" + "\n" + "void main()\n" + "{\n" + " ;\n" + "}\n"; + std::string strMemoryBarrier = strMemoryBarrierSource; + std::string strMemoryBarrierAtomicCounter = strMemoryBarrierSource; + std::string strMemoryBarrierBuffer = strMemoryBarrierSource; + std::string strMemoryBarrierShared = strMemoryBarrierSource; + std::string strMemoryBarrierImage = strMemoryBarrierSource; + std::string strGroupMemoryBarrier = strMemoryBarrierSource; + commonUtils::replaceToken("", "memoryBarrier()", strMemoryBarrier); + commonUtils::replaceToken("", "memoryBarrierAtomicCounter()", strMemoryBarrierAtomicCounter); + commonUtils::replaceToken("", "memoryBarrierBuffer()", strMemoryBarrierBuffer); + commonUtils::replaceToken("", "memoryBarrierShared()", strMemoryBarrierShared); + commonUtils::replaceToken("", "memoryBarrierImage()", strMemoryBarrierImage); + commonUtils::replaceToken("", "groupMemoryBarrier()", strGroupMemoryBarrier); + + m_sources.push_back(ComputeSource(strMemoryBarrier)); + m_sources.push_back(ComputeSource(strMemoryBarrierAtomicCounter)); + m_sources.push_back(ComputeSource(strMemoryBarrierBuffer)); + m_sources.push_back(ComputeSource(strMemoryBarrierShared)); + m_sources.push_back(ComputeSource(strMemoryBarrierImage)); + m_sources.push_back(ComputeSource(strGroupMemoryBarrier)); +} + +/** Stub de-init method */ +void SpirvGlslToSpirVBuiltInFunctionsTest::deinit() +{ +} + +/** Executes test iteration. + * + * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. + */ +tcu::TestNode::IterateResult SpirvGlslToSpirVBuiltInFunctionsTest::iterate() +{ + const Functions& gl = m_context.getRenderContext().getFunctions(); + + for (int i = 0; i < m_sources.size(); ++i) + { + ShaderSource shaderSource = m_sources[i]; + + ProgramSources sources; + ProgramBinaries binaries; + + if (shaderSource.shaderType != glu::SHADERTYPE_COMPUTE) + { + ShaderSource vertexSource(glu::SHADERTYPE_VERTEX, m_commonVertex); + + sources << vertexSource; + ShaderBinary vertexBinary; +#if defined DEQP_HAVE_GLSLANG + vertexBinary = glslangUtils::makeSpirV(m_context.getTestContext().getLog(), vertexSource); +#else // DEQP_HAVE_GLSLANG + tcu::Archive& archive = m_testCtx.getArchive(); + vertexBinary = + commonUtils::readSpirV(archive.getResource("spirv/glsl_to_spirv_builtin_functions/common_vertex.nspv")); +#endif //DEQP_HAVE_GLSLANG + binaries << vertexBinary; + } + + sources << shaderSource; + ShaderBinary shaderBinary; + std::string spirvSource; + +#if defined DEQP_HAVE_GLSLANG + shaderBinary = glslangUtils::makeSpirV(m_context.getTestContext().getLog(), shaderSource); +#else // DEQP_HAVE_GLSLANG + { + std::stringstream ss; + ss << "spirv/glsl_to_spirv_builtin_functions/binary_" << i << ".nspv"; + + tcu::Archive& archive = m_testCtx.getArchive(); + shaderBinary = commonUtils::readSpirV(archive.getResource(ss.str().c_str())); + } +#endif // DEQP_HAVE_GLSLANG + +#if defined DEQP_HAVE_SPIRV_TOOLS + { + glslangUtils::spirvDisassemble(spirvSource, shaderBinary.binary); + + if (!glslangUtils::verifyMappings(shaderSource.source, spirvSource, m_mappings, false)) + { + m_testCtx.getLog() << tcu::TestLog::Message << "Mappings for shader failed.\n" + << "GLSL source:\n" + << shaderSource.source.c_str() << "\n" + << "SpirV source:\n" + << spirvSource.c_str() << tcu::TestLog::EndMessage; + + TCU_THROW(InternalError, "Mappings for shader failed."); + } + } +#else // DEQP_HAVE_SPIRV_TOOLS + spirvSource = "Could not disassemble Spir-V module. SPIRV-TOOLS not available."; +#endif // DEQP_HAVE_SPIRV_TOOLS + + binaries << shaderBinary; + + if (shaderSource.shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL) + { + ShaderSource tessEvalSource(glu::SHADERTYPE_TESSELLATION_EVALUATION, m_commonTessEval); + + sources << tessEvalSource; + ShaderBinary tessEvalBinary; +#if defined DEQP_HAVE_GLSLANG + tessEvalBinary = glslangUtils::makeSpirV(m_context.getTestContext().getLog(), tessEvalSource); +#else // DEQP_HAVE_GLSLANG + tcu::Archive& archive = m_testCtx.getArchive(); + tessEvalBinary = commonUtils::readSpirV( + archive.getResource("spirv/glsl_to_spirv_builtin_functions/common_tesseval.nspv")); +#endif // DEQP_HAVE_GLSLANG + binaries << tessEvalBinary; + } + + ShaderProgram glslProgram(gl, sources); + if (!glslProgram.isOk()) + { + m_testCtx.getLog() << tcu::TestLog::Message << "GLSL shader compilation failed. Source:\n" + << shaderSource.source.c_str() << "InfoLog:\n" + << glslProgram.getShaderInfo(shaderSource.shaderType).infoLog << "\n" + << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + + ShaderProgram spirvProgram(gl, binaries); + if (!spirvProgram.isOk()) + { + m_testCtx.getLog() << tcu::TestLog::Message << "SpirV shader compilation failed. Source:\n" + << spirvSource.c_str() << "InfoLog:\n" + << spirvProgram.getShaderInfo(shaderSource.shaderType).infoLog << "\n" + << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + } + + m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); + return STOP; +} + +/** Mappings init method */ +void SpirvGlslToSpirVBuiltInFunctionsTest::initMappings() +{ + m_mappings.clear(); + m_mappings["radians"].push_back("OpExtInst Radians"); + m_mappings["degrees"].push_back("OpExtInst Degrees"); + m_mappings["sin"].push_back("OpExtInst Sin"); + m_mappings["cos"].push_back("OpExtInst Cos"); + m_mappings["tan"].push_back("OpExtInst Tan"); + m_mappings["asin"].push_back("OpExtInst Asin"); + m_mappings["acos"].push_back("OpExtInst Acos"); + m_mappings["atan"].push_back("OpExtInst Atan2"); + m_mappings["atan"].push_back("OpExtInst Atan"); + m_mappings["sinh"].push_back("OpExtInst Sinh"); + m_mappings["cosh"].push_back("OpExtInst Cosh"); + m_mappings["tanh"].push_back("OpExtInst Tanh"); + m_mappings["asinh"].push_back("OpExtInst Asinh"); + m_mappings["acosh"].push_back("OpExtInst Acosh"); + m_mappings["atanh"].push_back("OpExtInst Atanh"); + m_mappings["pow"].push_back("OpExtInst Pow"); + m_mappings["exp"].push_back("OpExtInst Exp"); + m_mappings["log"].push_back("OpExtInst Log"); + m_mappings["exp2"].push_back("OpExtInst Exp2"); + m_mappings["log2"].push_back("OpExtInst Log2"); + m_mappings["sqrt"].push_back("OpExtInst Sqrt"); + m_mappings["inversesqrt"].push_back("OpExtInst InverseSqrt"); + m_mappings["abs"].push_back("OpExtInst FAbs"); + m_mappings["sign"].push_back("OpExtInst FSign"); + m_mappings["floor"].push_back("OpExtInst Floor"); + m_mappings["trunc"].push_back("OpExtInst Trunc"); + m_mappings["round"].push_back("OpExtInst Round"); + m_mappings["roundEven"].push_back("OpExtInst RoundEven"); + m_mappings["ceil"].push_back("OpExtInst Ceil"); + m_mappings["fract"].push_back("OpExtInst Fract"); + m_mappings["mod"].push_back("OpFMod"); + m_mappings["modf"].push_back("OpExtInst Modf"); + m_mappings["min"].push_back("OpExtInst FMin"); + m_mappings["max"].push_back("OpExtInst FMax"); + m_mappings["clamp"].push_back("OpExtInst FClamp"); + m_mappings["mix"].push_back("OpExtInst FMix"); + m_mappings["step"].push_back("OpExtInst Step"); + m_mappings["smoothstep"].push_back("OpExtInst SmoothStep"); + m_mappings["intBitsToFloat"].push_back("OpBitcast"); + m_mappings["uintBitsToFloat"].push_back("OpBitcast"); + m_mappings["isnan"].push_back("OpIsNan"); + m_mappings["isinf"].push_back("OpIsInf"); + m_mappings["fma"].push_back("OpExtInst Fma"); + m_mappings["frexp"].push_back("OpExtInst FrexpStruct"); + m_mappings["ldexp"].push_back("OpExtInst Ldexp"); + m_mappings["packUnorm2x16"].push_back("OpExtInst PackUnorm2x16"); + m_mappings["packSnorm2x16"].push_back("OpExtInst PackSnorm2x16"); + m_mappings["packUnorm4x8"].push_back("OpExtInst PackUnorm4x8"); + m_mappings["packSnorm4x8"].push_back("OpExtInst PackSnorm4x8"); + m_mappings["unpackUnorm2x16"].push_back("OpExtInst UnpackUnorm2x16"); + m_mappings["unpackSnorm2x16"].push_back("OpExtInst UnpackSnorm2x16"); + m_mappings["unpackUnorm4x8"].push_back("OpExtInst UnpackUnorm4x8"); + m_mappings["unpackSnorm4x8"].push_back("OpExtInst UnpackSnorm4x8"); + m_mappings["packDouble2x32"].push_back("OpExtInst PackDouble2x32"); + m_mappings["unpackDouble2x32"].push_back("OpExtInst UnpackDouble2x32"); + m_mappings["packHalf2x16"].push_back("OpExtInst PackHalf2x16"); + m_mappings["unpackHalf2x16"].push_back("OpExtInst UnpackHalf2x16"); + m_mappings["length"].push_back("OpExtInst Length"); + m_mappings["distance"].push_back("OpExtInst Distance"); + m_mappings["dot"].push_back("OpDot"); + m_mappings["cross"].push_back("OpExtInst Cross"); + m_mappings["normalize"].push_back("OpExtInst Normalize"); + m_mappings["faceforward"].push_back("OpExtInst FaceForward"); + m_mappings["reflect"].push_back("OpExtInst Reflect"); + m_mappings["refract"].push_back("OpExtInst Refract"); + // This one could not be mapped as Spir-V equivalent need more steps + // m_mappings["matrixCompMult"].push_back(""); + m_mappings["outerProduct"].push_back("OpOuterProduct"); + m_mappings["transpose"].push_back("OpTranspose"); + m_mappings["determinant"].push_back("OpExtInst Determinant"); + m_mappings["inverse"].push_back("OpExtInst MatrixInverse"); + m_mappings["lessThan"].push_back("OpFOrdLessThan"); + m_mappings["lessThanEqual"].push_back("OpFOrdLessThanEqual"); + m_mappings["greaterThan"].push_back("OpFOrdGreaterThan"); + m_mappings["greaterThanEqual"].push_back("OpFOrdGreaterThanEqual"); + m_mappings["equal"].push_back("OpFOrdEqual"); + m_mappings["notEqual"].push_back("OpFOrdNotEqual"); + m_mappings["any"].push_back("OpAny"); + m_mappings["all"].push_back("OpAll"); + m_mappings["not"].push_back("OpLogicalNot"); + m_mappings["uaddCarry"].push_back("OpIAddCarry"); + m_mappings["usubBorrow"].push_back("OpISubBorrow"); + m_mappings["umulExtended"].push_back("OpUMulExtended"); + m_mappings["bitfieldExtract"].push_back("OpBitFieldUExtract"); + m_mappings["bitfieldInsert"].push_back("OpBitFieldInsert"); + m_mappings["bitfieldReverse"].push_back("OpBitReverse"); + m_mappings["bitCount"].push_back("OpBitCount"); + m_mappings["findLSB"].push_back("OpExtInst FindILsb"); + m_mappings["findMSB"].push_back("OpExtInst FindUMsb"); + m_mappings["textureSize"].push_back("OpImageQuerySizeLod"); + m_mappings["textureQueryLod"].push_back("OpImageQueryLod"); + m_mappings["textureQueryLevels"].push_back("OpImageQueryLevels"); + m_mappings["textureSamples"].push_back("OpImageQuerySamples"); + m_mappings["texture"].push_back("OpImageSampleImplicitLod"); + m_mappings["textureProj"].push_back("OpImageSampleProjImplicitLod"); + m_mappings["textureLod"].push_back("OpImageSampleExplicitLod Lod"); + m_mappings["textureOffset"].push_back("OpImageSampleImplicitLod ConstOffset"); + m_mappings["texelFetch"].push_back("OpImageFetch Lod"); + m_mappings["texelFetchOffset"].push_back("OpImageFetch Lod|ConstOffset"); + m_mappings["textureProjOffset"].push_back("OpImageSampleProjImplicitLod ConstOffset"); + m_mappings["textureLodOffset"].push_back("OpImageSampleExplicitLod Lod|ConstOffset"); + m_mappings["textureProjLod"].push_back("OpImageSampleProjExplicitLod Lod"); + m_mappings["textureProjLodOffset"].push_back("OpImageSampleProjExplicitLod Lod|ConstOffset"); + m_mappings["textureGrad"].push_back("OpImageSampleExplicitLod Grad"); + m_mappings["textureGradOffset"].push_back("OpImageSampleExplicitLod Grad|ConstOffset"); + m_mappings["textureProjGrad"].push_back("OpImageSampleProjExplicitLod Grad"); + m_mappings["textureProjGradOffset"].push_back("OpImageSampleProjExplicitLod Grad|ConstOffset"); + m_mappings["textureGather"].push_back("OpImageGather"); + m_mappings["textureGatherOffset"].push_back("OpImageGather ConstOffset"); + m_mappings["atomicCounterIncrement"].push_back("OpAtomicIIncrement"); + m_mappings["atomicCounterDecrement"].push_back("OpAtomicIDecrement"); + m_mappings["atomicCounter"].push_back("OpAtomicLoad"); + m_mappings["atomicAdd"].push_back("OpAtomicIAdd"); + m_mappings["atomicMin"].push_back("OpAtomicUMin"); + m_mappings["atomicMax"].push_back("OpAtomicUMax"); + m_mappings["atomicAnd"].push_back("OpAtomicAnd"); + m_mappings["atomicOr"].push_back("OpAtomicOr"); + m_mappings["atomicXor"].push_back("OpAtomicXor"); + m_mappings["atomicExchange"].push_back("OpAtomicExchange"); + m_mappings["atomicCompSwap"].push_back("OpAtomicCompareExchange"); + m_mappings["imageSize"].push_back("OpImageQuerySize"); + m_mappings["imageSamples"].push_back("OpImageQuerySamples"); + m_mappings["imageLoad"].push_back("OpImageRead"); + m_mappings["imageStore"].push_back("OpImageWrite"); + m_mappings["imageAtomicAdd"].push_back("OpAtomicIAdd"); + m_mappings["imageAtomicMin"].push_back("OpAtomicUMin"); + m_mappings["imageAtomicMax"].push_back("OpAtomicUMax"); + m_mappings["imageAtomicAnd"].push_back("OpAtomicAnd"); + m_mappings["imageAtomicOr"].push_back("OpAtomicOr"); + m_mappings["imageAtomicXor"].push_back("OpAtomicXor"); + m_mappings["imageAtomicExchange"].push_back("OpAtomicExchange"); + m_mappings["imageAtomicCompSwap"].push_back("OpAtomicCompareExchange"); + m_mappings["dFdx"].push_back("OpDPdx"); + m_mappings["dFdy"].push_back("OpDPdy"); + m_mappings["dFdxFine"].push_back("OpDPdxFine"); + m_mappings["dFdyFine"].push_back("OpDPdyFine"); + m_mappings["dFdxCoarse"].push_back("OpDPdxCoarse"); + m_mappings["dFdyCoarse"].push_back("OpDPdyCoarse"); + m_mappings["fwidth"].push_back("OpFwidth"); + m_mappings["fwidthFine"].push_back("OpFwidthFine"); + m_mappings["fwidthCoarse"].push_back("OpFwidthCoarse"); + m_mappings["interpolateAtCentroid"].push_back("OpExtInst InterpolateAtCentroid"); + m_mappings["interpolateAtSample"].push_back("OpExtInst InterpolateAtSample"); + m_mappings["interpolateAtOffset"].push_back("OpExtInst InterpolateAtOffset"); + m_mappings["EmitStreamVertex"].push_back("OpEmitStreamVertex"); + m_mappings["EndStreamPrimitive"].push_back("OpEndStreamPrimitive"); + m_mappings["EmitVertex"].push_back("OpEmitVertex"); + m_mappings["EndPrimitive"].push_back("OpEndPrimitive"); + m_mappings["barrier"].push_back("OpControlBarrier"); + m_mappings["memoryBarrier"].push_back("OpMemoryBarrier"); + m_mappings["memoryBarrierAtomicCounter"].push_back("OpMemoryBarrier"); + m_mappings["memoryBarrierBuffer"].push_back("OpMemoryBarrier"); + m_mappings["memoryBarrierShared"].push_back("OpMemoryBarrier"); + m_mappings["memoryBarrierImage"].push_back("OpMemoryBarrier"); + m_mappings["groupMemoryBarrier"].push_back("OpMemoryBarrier"); + + // Add a space prefix and parenthesis sufix to avoid searching for similar names + SpirVMapping tempMappings; + SpirVMapping::iterator it; + for (it = m_mappings.begin(); it != m_mappings.end(); ++it) + { + tempMappings[std::string(" ") + it->first + "("] = it->second; + } + + m_mappings = tempMappings; +} + +/** Constructor. + * + * @param context Rendering context + * @param name Test name + * @param description Test description + */ +SpirvGlslToSpirVSpecializationConstantsTest::SpirvGlslToSpirVSpecializationConstantsTest(deqp::Context& context) + : TestCase(context, "spirv_glsl_to_spirv_specialization_constants_test", + "Test verifies if constant specialization feature works as expected.") +{ + /* Left blank intentionally */ +} + +/** Stub init method */ +void SpirvGlslToSpirVSpecializationConstantsTest::init() +{ + if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gl_spirv")) + TCU_THROW(NotSupportedError, "GL_ARB_gl_spirv is not supported"); + + const Functions& gl = m_context.getRenderContext().getFunctions(); + + m_vertex = "#version 450\n" + "\n" + "layout (location = 0) in vec3 position;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = vec4(position, 1.0);\n" + "}\n"; + + m_fragment = "#version 450\n" + "\n" + "layout (constant_id = 10) const int red = 255;\n" + "\n" + "layout (location = 0) out vec4 fragColor;\n" + "\n" + "void main()\n" + "{\n" + " fragColor = vec4(float(red) / 255, 0.0, 1.0, 1.0);\n" + "}\n"; + + gl.genTextures(1, &m_texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "genTextures"); + gl.bindTexture(GL_TEXTURE_2D, m_texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture"); + gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 32, 32); + GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage2D"); + + gl.genFramebuffers(1, &m_fbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "genFramenuffers"); + gl.bindFramebuffer(GL_FRAMEBUFFER, m_fbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer"); + gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0); + GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture2D"); + + gl.viewport(0, 0, 32, 32); + GLU_EXPECT_NO_ERROR(gl.getError(), "viewport"); +} + +/** Stub de-init method */ +void SpirvGlslToSpirVSpecializationConstantsTest::deinit() +{ + const Functions& gl = m_context.getRenderContext().getFunctions(); + + if (m_fbo) + { + gl.deleteFramebuffers(1, &m_fbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "deleteFramebuffers"); + } + if (m_texture) + { + gl.deleteTextures(1, &m_texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "deleteTextures"); + } +} + +/** Executes test iteration. + * + * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. + */ +tcu::TestNode::IterateResult SpirvGlslToSpirVSpecializationConstantsTest::iterate() +{ + const Functions& gl = m_context.getRenderContext().getFunctions(); + + const GLfloat vertices[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f }; + + GLuint vao; + gl.genVertexArrays(1, &vao); + GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays"); + gl.bindVertexArray(vao); + GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray"); + + GLuint vbo; + gl.genBuffers(1, &vbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers"); + gl.bindBuffer(GL_ARRAY_BUFFER, vbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer"); + + gl.bufferData(GL_ARRAY_BUFFER, 9 * sizeof(GLfloat), (GLvoid*)vertices, GL_DYNAMIC_DRAW); + GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData"); + + ShaderBinary vertexBinary; + ShaderBinary fragmentBinary; +#if defined DEQP_HAVE_GLSLANG + { + vertexBinary = glslangUtils::makeSpirV(m_context.getTestContext().getLog(), VertexSource(m_vertex)); + fragmentBinary = glslangUtils::makeSpirV(m_context.getTestContext().getLog(), FragmentSource(m_fragment)); + } +#else // DEQP_HAVE_GLSLANG + { + tcu::Archive& archive = m_testCtx.getArchive(); + vertexBinary = + commonUtils::readSpirV(archive.getResource("spirv/glsl_to_spirv_specialization_constants/vertex.nspv")); + fragmentBinary = + commonUtils::readSpirV(archive.getResource("spirv/glsl_to_spirv_specialization_constants/fragment.nspv")); + } +#endif // DEQP_HAVE_GLSLANG + fragmentBinary << SpecializationData(10, 128); + + ProgramBinaries binaries; + binaries << vertexBinary; + binaries << fragmentBinary; + ShaderProgram spirvProgram(gl, binaries); + + if (!spirvProgram.isOk()) + { + m_testCtx.getLog() << tcu::TestLog::Message << "Shader compilation failed.\n" + << "Vertex:\n" + << m_vertex.c_str() << "Fragment:\n" + << m_fragment.c_str() << "InfoLog:\n" + << spirvProgram.getShaderInfo(SHADERTYPE_VERTEX).infoLog << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + + gl.useProgram(spirvProgram.getProgram()); + GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram"); + + gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); + GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor"); + gl.clear(GL_COLOR_BUFFER_BIT); + GLU_EXPECT_NO_ERROR(gl.getError(), "glClear"); + + gl.enableVertexAttribArray(0); + GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray"); + + gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, DE_NULL); + GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer"); + + gl.drawArrays(GL_TRIANGLES, 0, 3); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArray"); + + gl.disableVertexAttribArray(0); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDisableVertexAttribArray"); + + GLuint output; + + gl.readPixels(16, 16, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)&output); + GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels"); + + if (output != 0xFFFF0080) + { + m_testCtx.getLog() << tcu::TestLog::Message + << "Color value read from framebuffer is wrong. Expected: " << 0xFFFF0080 + << ", Read: " << output << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + + m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); + return STOP; +} + +/** Constructor. + * + * @param context Rendering context + * @param name Test name + * @param description Test description + */ +SpirvValidationBuiltInVariableDecorationsTest::SpirvValidationBuiltInVariableDecorationsTest(deqp::Context& context) + : TestCase(context, "spirv_validation_builtin_variable_decorations_test", + "Test verifies if Spir-V built in variable decorations works as expected.") +{ + /* Left blank intentionally */ +} + +/** Stub init method */ +void SpirvValidationBuiltInVariableDecorationsTest::init() +{ + if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_gl_spirv")) + TCU_THROW(NotSupportedError, "GL_ARB_gl_spirv is not supported"); + + m_compute = "#version 450\n" + "\n" + "layout (local_size_x = 1, local_size_y = 2, local_size_z = 1) in;\n" + "\n" + "layout (location = 0, rgba8ui) uniform uimage2D img0;\n" + "layout (location = 1, rgba8ui) uniform uimage2D img1;\n" + "layout (location = 2, rgba8ui) uniform uimage2D img2;\n" + "layout (location = 3, rgba8ui) uniform uimage2D img3;\n" + "layout (location = 4, rgba8ui) uniform uimage2D img4;\n" + "\n" + "void main()\n" + "{\n" + " ivec3 point = ivec3(gl_GlobalInvocationID);\n" + " uvec3 color0 = uvec3(gl_NumWorkGroups);\n" + " uvec3 color1 = uvec3(gl_WorkGroupSize);\n" + " uvec3 color2 = uvec3(gl_WorkGroupID);\n" + " uvec3 color3 = uvec3(gl_LocalInvocationID);\n" + " uvec3 color4 = uvec3(gl_LocalInvocationIndex);\n" + " imageStore(img0, point.xy, uvec4(color0, 0xFF));\n" + " imageStore(img1, point.xy, uvec4(color1, 0xFF));\n" + " imageStore(img2, point.xy, uvec4(color2, 0xFF));\n" + " imageStore(img3, point.xy, uvec4(color3, 0xFF));\n" + " imageStore(img4, point.xy, uvec4(color4, 0xFF));\n" + " memoryBarrier();\n" + "}\n"; + + m_vertex = "#version 450\n" + "\n" + "layout (location = 0) in vec3 position;\n" + "\n" + "layout (location = 1) out vec4 vColor;\n" + "\n" + "void main()\n" + "{\n" + " gl_PointSize = 10.0f;\n" + " gl_Position = vec4(position.x, position.y + 0.3 * gl_InstanceID, position.z, 1.0);\n" + " gl_ClipDistance[0] = ;\n" + " gl_CullDistance[0] = ;\n" + " vColor = ;\n" + "}\n"; + + m_tesselationCtrl = "#version 450\n" + "\n" + "layout (vertices = 3) out;\n" + "\n" + "layout (location = 1) in vec4 vColor[];\n" + "layout (location = 2) out vec4 tcColor[];\n" + "\n" + "void main()\n" + "{\n" + " tcColor[gl_InvocationID] = vColor[gl_InvocationID];\n" + " tcColor[gl_InvocationID].r = float(gl_PatchVerticesIn) / 3;\n" + "\n" + " if (gl_InvocationID == 0) {\n" + " gl_TessLevelOuter[0] = 1.0;\n" + " gl_TessLevelOuter[1] = 1.0;\n" + " gl_TessLevelOuter[2] = 1.0;\n" + " gl_TessLevelInner[0] = 1.0;\n" + " }\n" + "\n" + " gl_out[gl_InvocationID].gl_ClipDistance[0] = gl_in[gl_InvocationID].gl_ClipDistance[0];\n" + " gl_out[gl_InvocationID].gl_CullDistance[0] = gl_in[gl_InvocationID].gl_CullDistance[0];\n" + " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" + "}\n"; + + m_tesselationEval = "#version 450\n" + "\n" + "layout (triangles) in;\n" + "\n" + "layout (location = 2) in vec4 tcColor[];\n" + "layout (location = 3) out vec4 teColor;\n" + "\n" + "void main()\n" + "{\n" + " teColor = tcColor[0];\n" + "\n" + " gl_ClipDistance[0] = gl_in[0].gl_ClipDistance[0];\n" + " gl_CullDistance[0] = gl_in[0].gl_CullDistance[0];\n" + " gl_Position = gl_TessCoord.x * gl_in[0].gl_Position +\n" + " gl_TessCoord.y * gl_in[1].gl_Position +\n" + " gl_TessCoord.z * gl_in[2].gl_Position;\n" + "}\n"; + + m_geometry = "#version 450\n" + "\n" + "layout (triangles) in;\n" + "layout (triangle_strip, max_vertices = 3) out;\n" + "\n" + "layout (location = 3) in vec4 teColor[];\n" + "layout (location = 4) out vec4 gColor;\n" + "\n" + "void main()\n" + "{\n" + " gColor = teColor[0];\n" + " gColor.b = float(gl_PrimitiveIDIn);\n" + "\n" + " gl_Layer = 1;\n" + " gl_ViewportIndex = 1;\n" + "\n" + " for (int i = 0; i < 3; ++i) {\n" + " gl_ClipDistance[0] = gl_in[i].gl_ClipDistance[0];\n" + " gl_CullDistance[0] = gl_in[i].gl_CullDistance[0];\n" + " gl_Position = gl_in[i].gl_Position;\n" + " EmitVertex();\n" + " }\n" + " EndPrimitive();\n" + "}\n"; + + m_fragment = "#version 450\n" + "\n" + "layout (location = ) in vec4 ;\n" + "layout (location = 0) out vec4 fColor;\n" + "\n" + "void main()\n" + "{\n" + " vec4 color = ;\n" + " \n" + " fColor = color;\n" + "}\n"; + + ValidationStruct validationCompute(&SpirvValidationBuiltInVariableDecorationsTest::validComputeFunc); + validationCompute.shaders.push_back(ComputeSource(m_compute)); + m_validations.push_back(validationCompute); + + std::string clipNegativeVertex = m_vertex; + std::string clipNegativeFragment = m_fragment; + commonUtils::replaceToken("", "-1.0", clipNegativeVertex); + commonUtils::replaceToken("", "1.0", clipNegativeVertex); + commonUtils::replaceToken("", "vec4(1.0, 1.0, 1.0, 1.0)", clipNegativeVertex); + commonUtils::replaceToken("", "1", clipNegativeFragment); + commonUtils::replaceToken("", "vColor", clipNegativeFragment); + commonUtils::replaceToken("", "", clipNegativeFragment); + ValidationStruct validationClipNegative(&SpirvValidationBuiltInVariableDecorationsTest::validPerVertexFragFunc); + validationClipNegative.shaders.push_back(VertexSource(clipNegativeVertex)); + validationClipNegative.shaders.push_back(FragmentSource(clipNegativeFragment)); + validationClipNegative.outputs.push_back(ValidationOutputStruct(32, 32, 0xFF000000)); + m_validations.push_back(validationClipNegative); + + std::string perVertexFragVertex = m_vertex; + std::string perVertexFragFragment = m_fragment; + std::string fragCode = "vec4 coord = gl_FragCoord;\n" + "color = vec4(0.0, coord.s / 64, coord.t / 64, 1.0);\n"; + commonUtils::replaceToken("", "1.0", perVertexFragVertex); + commonUtils::replaceToken("", "1.0", perVertexFragVertex); + commonUtils::replaceToken("", "vec4(1.0, 1.0, 1.0, 1.0)", perVertexFragVertex); + commonUtils::replaceToken("", "1", perVertexFragFragment); + commonUtils::replaceToken("", "vColor", perVertexFragFragment); + commonUtils::replaceToken("", fragCode.c_str(), perVertexFragFragment); + ValidationStruct validationFrag(&SpirvValidationBuiltInVariableDecorationsTest::validPerVertexFragFunc); + validationFrag.shaders.push_back(VertexSource(perVertexFragVertex)); + validationFrag.shaders.push_back(FragmentSource(perVertexFragFragment)); + validationFrag.outputs.push_back(ValidationOutputStruct(32, 32, 0xFF7F7F00)); + m_validations.push_back(validationFrag); + + std::string perVertexPointVertex = m_vertex; + std::string perVertexPointFragment = m_fragment; + std::string pointCode = "vec2 coord = gl_PointCoord;\n" + "color.b = coord.s * coord.t;\n"; + commonUtils::replaceToken("", "1.0", perVertexPointVertex); + commonUtils::replaceToken("", "1.0", perVertexPointVertex); + commonUtils::replaceToken("", "vec4(float(gl_VertexID) / 3, 0.0, 0.0, 1.0)", perVertexPointVertex); + commonUtils::replaceToken("", "1", perVertexPointFragment); + commonUtils::replaceToken("", "vColor", perVertexPointFragment); + commonUtils::replaceToken("", pointCode.c_str(), perVertexPointFragment); + ValidationStruct validationPoint(&SpirvValidationBuiltInVariableDecorationsTest::validPerVertexPointFunc); + validationPoint.shaders.push_back(VertexSource(perVertexPointVertex)); + validationPoint.shaders.push_back(FragmentSource(perVertexPointFragment)); + validationPoint.outputs.push_back(ValidationOutputStruct(64, 64, 0xFF3F0055)); + validationPoint.outputs.push_back(ValidationOutputStruct(45, 45, 0xFF3F0000)); + validationPoint.outputs.push_back(ValidationOutputStruct(83, 83, 0xFF3F00AA)); + m_validations.push_back(validationPoint); + + std::string tessGeomVertex = m_vertex; + std::string tessGeomFragment = m_fragment; + commonUtils::replaceToken("", "1.0", tessGeomVertex); + commonUtils::replaceToken("", "1.0", tessGeomVertex); + commonUtils::replaceToken("", "vec4(1.0, 1.0, 1.0, 1.0)", tessGeomVertex); + commonUtils::replaceToken("", "4", tessGeomFragment); + commonUtils::replaceToken("", "gColor", tessGeomFragment); + commonUtils::replaceToken("", "", tessGeomFragment); + ValidationStruct validationTessGeom(&SpirvValidationBuiltInVariableDecorationsTest::validTesselationGeometryFunc); + validationTessGeom.shaders.push_back(VertexSource(tessGeomVertex)); + validationTessGeom.shaders.push_back(TessellationControlSource(m_tesselationCtrl)); + validationTessGeom.shaders.push_back(TessellationEvaluationSource(m_tesselationEval)); + validationTessGeom.shaders.push_back(GeometrySource(m_geometry)); + validationTessGeom.shaders.push_back(FragmentSource(tessGeomFragment)); + validationTessGeom.outputs.push_back(ValidationOutputStruct(48, 32, 1, 0xFF00FFFF)); + m_validations.push_back(validationTessGeom); + + std::string multisampleVertex = m_vertex; + std::string multisampleFragment = m_fragment; + std::string samplingCode = "if (gl_SampleID == 0)\n" + "{\n" + " vec2 sampPos = gl_SamplePosition;\n" + " color = vec4(1.0, sampPos.x, sampPos.y, 1.0);\n" + "}\n" + "else\n" + "{\n" + " color = vec4(0.0, 1.0, 0.0, 1.0);\n" + "}\n" + "gl_SampleMask[0] = 0x02;"; + commonUtils::replaceToken("", "1.0", multisampleVertex); + commonUtils::replaceToken("", "1.0", multisampleVertex); + commonUtils::replaceToken("", "vec4(1.0, 1.0, 1.0, 1.0)", multisampleVertex); + commonUtils::replaceToken("", "1", multisampleFragment); + commonUtils::replaceToken("", "vColor", multisampleFragment); + commonUtils::replaceToken("", samplingCode.c_str(), multisampleFragment); + ValidationStruct validationMultisample(&SpirvValidationBuiltInVariableDecorationsTest::validMultiSamplingFunc); + validationMultisample.shaders.push_back(VertexSource(multisampleVertex)); + validationMultisample.shaders.push_back(FragmentSource(multisampleFragment)); + validationMultisample.outputs.push_back(ValidationOutputStruct(16, 16, 0xFF00BC00)); + m_validations.push_back(validationMultisample); + + m_mappings["gl_NumWorkGroups"].push_back("BuiltIn NumWorkgroups"); + m_mappings["gl_WorkGroupSize"].push_back("BuiltIn WorkgroupSize"); + m_mappings["gl_WorkGroupID"].push_back("BuiltIn WorkgroupId"); + m_mappings["gl_LocalInvocationID"].push_back("BuiltIn LocalInvocationId"); + m_mappings["gl_GlobalInvocationID"].push_back("BuiltIn GlobalInvocationId"); + m_mappings["gl_LocalInvocationIndex"].push_back("BuiltIn LocalInvocationIndex"); + m_mappings["gl_VertexID"].push_back("BuiltIn VertexId"); + m_mappings["gl_InstanceID"].push_back("BuiltIn InstanceId"); + m_mappings["gl_Position"].push_back("BuiltIn Position"); + m_mappings["gl_PointSize"].push_back("BuiltIn PointSize"); + m_mappings["gl_ClipDistance"].push_back("BuiltIn ClipDistance"); + m_mappings["gl_CullDistance"].push_back("BuiltIn CullDistance"); + m_mappings["gl_PrimitiveIDIn"].push_back("BuiltIn PrimitiveId"); + m_mappings["gl_InvocationID"].push_back("BuiltIn InvocationId"); + m_mappings["gl_Layer"].push_back("BuiltIn Layer"); + m_mappings["gl_ViewportIndex"].push_back("BuiltIn ViewportIndex"); + m_mappings["gl_PatchVerticesIn"].push_back("BuiltIn PatchVertices"); + m_mappings["gl_TessLevelOuter"].push_back("BuiltIn TessLevelOuter"); + m_mappings["gl_TessLevelInner"].push_back("BuiltIn TessLevelInner"); + m_mappings["gl_TessCoord"].push_back("BuiltIn TessCoord"); + m_mappings["gl_FragCoord"].push_back("BuiltIn FragCoord"); + m_mappings["gl_FrontFacing"].push_back("BuiltIn FrontFacing"); + m_mappings["gl_PointCoord"].push_back("BuiltIn PointCoord"); + m_mappings["gl_SampleId"].push_back("BuiltIn SampleId"); + m_mappings["gl_SamplePosition"].push_back("BuiltIn SamplePosition"); + m_mappings["gl_SampleMask"].push_back("BuiltIn SampleMask"); +} + +/** Stub de-init method */ +void SpirvValidationBuiltInVariableDecorationsTest::deinit() +{ +} + +/** Executes test iteration. + * + * @return Returns STOP when test has finished executing, CONTINUE if more iterations are needed. + */ +tcu::TestNode::IterateResult SpirvValidationBuiltInVariableDecorationsTest::iterate() +{ + const Functions& gl = m_context.getRenderContext().getFunctions(); + + GLuint vao; + gl.genVertexArrays(1, &vao); + GLU_EXPECT_NO_ERROR(gl.getError(), "glGenVertexArrays"); + gl.bindVertexArray(vao); + GLU_EXPECT_NO_ERROR(gl.getError(), "glBindVertexArray"); + + GLuint vbo; + gl.genBuffers(1, &vbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "glGenBuffers"); + gl.bindBuffer(GL_ARRAY_BUFFER, vbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBuffer"); + + enum Iterates + { + ITERATE_GLSL, + ITERATE_SPIRV, + ITERATE_LAST + }; + + bool result = true; + + for (int v = 0; v < m_validations.size(); ++v) + { + for (int it = ITERATE_GLSL; it < ITERATE_LAST; ++it) + { + ShaderProgram* program = DE_NULL; + if (it == ITERATE_GLSL) + { + ProgramSources sources; + for (int s = 0; s < m_validations[v].shaders.size(); ++s) + sources << m_validations[v].shaders[s]; + + program = new ShaderProgram(gl, sources); + } + else if (it == ITERATE_SPIRV) + { + std::vector binariesVec; + +#if defined DEQP_HAVE_GLSLANG + ProgramBinaries binaries; + for (int s = 0; s < m_validations[v].shaders.size(); ++s) + { + ShaderBinary shaderBinary = + glslangUtils::makeSpirV(m_context.getTestContext().getLog(), m_validations[v].shaders[s]); + binariesVec.push_back(shaderBinary); + binaries << shaderBinary; + } +#else // DEQP_HAVE_GLSLANG + tcu::Archive& archive = m_testCtx.getArchive(); + ProgramBinaries binaries; + for (int s = 0; s < m_validations[v].shaders.size(); ++s) + { + std::stringstream ss; + ss << "spirv/spirv_validation_builtin_variable_decorations/shader_" << v << "_" << s << ".nspv"; + + ShaderBinary shaderBinary = commonUtils::readSpirV(archive.getResource(ss.str().c_str())); + binariesVec.push_back(shaderBinary); + binaries << shaderBinary; + } +#endif // DEQP_HAVE_GLSLANG + program = new ShaderProgram(gl, binaries); + +#if defined DEQP_HAVE_SPIRV_TOOLS + std::string spirvSource; + + for (int s = 0; s < m_validations[v].shaders.size(); ++s) + { + ShaderSource shaderSource = m_validations[v].shaders[s]; + + glslangUtils::spirvDisassemble(spirvSource, binariesVec[s].binary); + + if (!glslangUtils::verifyMappings(shaderSource.source, spirvSource, m_mappings, true)) + { + m_testCtx.getLog() << tcu::TestLog::Message << "Mappings for shader failed.\n" + << "GLSL source:\n" + << shaderSource.source.c_str() << "\n" + << "SpirV source:\n" + << spirvSource.c_str() << tcu::TestLog::EndMessage; + + TCU_THROW(InternalError, "Mappings for shader failed."); + } + } +#endif // DEQP_HAVE_SPIRV_TOOLS + } + + if (!program->isOk()) + { + std::stringstream message; + message << "Shader build failed.\n"; + + if (program->hasShader(SHADERTYPE_COMPUTE)) + message << "ComputeInfo: " << program->getShaderInfo(SHADERTYPE_COMPUTE).infoLog << "\n" + << "ComputeSource: " << program->getShader(SHADERTYPE_COMPUTE)->getSource() << "\n"; + if (program->hasShader(SHADERTYPE_VERTEX)) + message << "VertexInfo: " << program->getShaderInfo(SHADERTYPE_VERTEX).infoLog << "\n" + << "VertexSource: " << program->getShader(SHADERTYPE_VERTEX)->getSource() << "\n"; + if (program->hasShader(SHADERTYPE_TESSELLATION_CONTROL)) + message << "TesselationCtrlInfo: " + << program->getShaderInfo(SHADERTYPE_TESSELLATION_CONTROL).infoLog << "\n" + << "TesselationCtrlSource: " + << program->getShader(SHADERTYPE_TESSELLATION_CONTROL)->getSource() << "\n"; + if (program->hasShader(SHADERTYPE_TESSELLATION_EVALUATION)) + message << "TesselationEvalInfo: " + << program->getShaderInfo(SHADERTYPE_TESSELLATION_EVALUATION).infoLog << "\n" + << "TesselationEvalSource: " + << program->getShader(SHADERTYPE_TESSELLATION_EVALUATION)->getSource() << "\n"; + if (program->hasShader(SHADERTYPE_GEOMETRY)) + message << "GeometryInfo: " << program->getShaderInfo(SHADERTYPE_GEOMETRY).infoLog << "\n" + << "GeometrySource: " << program->getShader(SHADERTYPE_GEOMETRY)->getSource() << "\n"; + if (program->hasShader(SHADERTYPE_FRAGMENT)) + message << "FragmentInfo: " << program->getShaderInfo(SHADERTYPE_FRAGMENT).infoLog << "\n" + << "FragmentSource: " << program->getShader(SHADERTYPE_FRAGMENT)->getSource() << "\n"; + + message << "ProgramInfo: " << program->getProgramInfo().infoLog; + + m_testCtx.getLog() << tcu::TestLog::Message << message.str() << tcu::TestLog::EndMessage; + + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; + } + + gl.useProgram(program->getProgram()); + GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram"); + + ValidationFuncPtr funcPtr = m_validations[v].validationFuncPtr; + result = (this->*funcPtr)(m_validations[v].outputs); + + if (program) + delete program; + + if (!result) + { + m_testCtx.getLog() << tcu::TestLog::Message << "Validation " << v << " failed!" + << tcu::TestLog::EndMessage; + + break; + } + } + } + + if (vbo) + { + gl.deleteBuffers(1, &vbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteBuffers"); + } + + if (vao) + { + gl.deleteVertexArrays(1, &vao); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteVertexArrays"); + } + + if (result) + m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); + else + m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail"); + return STOP; +} + +bool SpirvValidationBuiltInVariableDecorationsTest::validComputeFunc(ValidationOutputVec& outputs) +{ + const Functions& gl = m_context.getRenderContext().getFunctions(); + + GLuint textures[5]; + + gl.genTextures(5, textures); + GLU_EXPECT_NO_ERROR(gl.getError(), "genTextures"); + for (int i = 0; i < 5; ++i) + { + gl.bindTexture(GL_TEXTURE_2D, textures[i]); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture"); + gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8UI, 4, 4); + GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage2D"); + } + + gl.bindImageTexture(0, textures[0], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8UI); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindImageTexture"); + gl.bindImageTexture(1, textures[1], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8UI); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindImageTexture"); + gl.bindImageTexture(2, textures[2], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8UI); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindImageTexture"); + gl.bindImageTexture(3, textures[3], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8UI); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindImageTexture"); + gl.bindImageTexture(4, textures[4], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8UI); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindImageTexture"); + gl.uniform1i(0, 0); + GLU_EXPECT_NO_ERROR(gl.getError(), "uniform1i"); + gl.uniform1i(1, 1); + GLU_EXPECT_NO_ERROR(gl.getError(), "uniform1i"); + gl.uniform1i(2, 2); + GLU_EXPECT_NO_ERROR(gl.getError(), "uniform1i"); + gl.uniform1i(3, 3); + GLU_EXPECT_NO_ERROR(gl.getError(), "uniform1i"); + gl.uniform1i(4, 4); + GLU_EXPECT_NO_ERROR(gl.getError(), "uniform1i"); + gl.dispatchCompute(4, 2, 1); + GLU_EXPECT_NO_ERROR(gl.getError(), "dispatchCompute"); + + gl.memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); + GLU_EXPECT_NO_ERROR(gl.getError(), "memoryBarrier"); + + std::vector expectedResults[5]; + for (int i = 0; i < 5; ++i) + { + for (int y = 0; y < 4; ++y) + { + for (int x = 0; x < 4; ++x) + { + //"uvec3 color0 = uvec3(gl_NumWorkGroups);" + if (i == 0) + { + expectedResults[i].push_back(4); + expectedResults[i].push_back(2); + expectedResults[i].push_back(1); + expectedResults[i].push_back(0xFF); + } + //"uvec3 color1 = uvec3(gl_WorkGroupSize);" + else if (i == 1) + { + expectedResults[i].push_back(1); + expectedResults[i].push_back(2); + expectedResults[i].push_back(1); + expectedResults[i].push_back(0xFF); + } + //"uvec3 color2 = uvec3(gl_WorkGroupID);" + else if (i == 2) + { + expectedResults[i].push_back(x); + expectedResults[i].push_back(y / 2); + expectedResults[i].push_back(0); + expectedResults[i].push_back(0xFF); + } + //"uvec3 color3 = uvec3(gl_LocalInvocationID);" + else if (i == 3) + { + expectedResults[i].push_back(0); + expectedResults[i].push_back(y % 2); + expectedResults[i].push_back(0); + expectedResults[i].push_back(0xFF); + } + //"uvec3 color4 = uvec3(gl_LocalInvocationIndex);" + else if (i == 4) + { + expectedResults[i].push_back(y % 2); + expectedResults[i].push_back(y % 2); + expectedResults[i].push_back(y % 2); + expectedResults[i].push_back(0xFF); + } + } + } + } + + bool result = true; + for (int i = 0; i < 5; ++i) + { + gl.bindTexture(GL_TEXTURE_2D, textures[i]); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture"); + + std::vector pixels; + pixels.resize(4 * 4 * 4); + gl.getTexImage(GL_TEXTURE_2D, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, (GLvoid*)pixels.data()); + GLU_EXPECT_NO_ERROR(gl.getError(), "getTexImage"); + + if (pixels != expectedResults[i]) + { + m_testCtx.getLog() << tcu::TestLog::Message << "Invalid image computed [" << i << "]." + << tcu::TestLog::EndMessage; + + result = false; + } + } + + if (textures) + { + gl.deleteTextures(5, textures); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures"); + } + + return result; +} + +bool SpirvValidationBuiltInVariableDecorationsTest::validPerVertexFragFunc(ValidationOutputVec& outputs) +{ + const Functions& gl = m_context.getRenderContext().getFunctions(); + + const GLfloat vertices[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f }; + + GLuint texture; + GLuint fbo; + + gl.genTextures(1, &texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "genTextures"); + gl.bindTexture(GL_TEXTURE_2D, texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture"); + gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 64, 64); + GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage2D"); + + gl.genFramebuffers(1, &fbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "genFramenuffers"); + gl.bindFramebuffer(GL_FRAMEBUFFER, fbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer"); + gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); + GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture2D"); + + gl.viewport(0, 0, 64, 64); + GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport"); + + gl.bufferData(GL_ARRAY_BUFFER, 9 * sizeof(GLfloat), (GLvoid*)vertices, GL_DYNAMIC_DRAW); + GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData"); + + gl.enable(GL_CLIP_DISTANCE0); + + gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); + GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor"); + gl.clear(GL_COLOR_BUFFER_BIT); + GLU_EXPECT_NO_ERROR(gl.getError(), "glClear"); + + gl.enableVertexAttribArray(0); + GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray"); + + gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, DE_NULL); + GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer"); + + gl.drawArrays(GL_TRIANGLES, 0, 3); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArray"); + + gl.disableVertexAttribArray(0); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDisableVertexAttribArray"); + + gl.disable(GL_CLIP_DISTANCE0); + + bool result = true; + for (int o = 0; o < outputs.size(); ++o) + { + GLuint output; + gl.readPixels(outputs[o].x, outputs[o].y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)&output); + GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels"); + + if (!commonUtils::compareUintColors(output, outputs[o].value, 2)) + { + m_testCtx.getLog() << tcu::TestLog::Message << "Invalid output color read at [" << (int)outputs[o].x << "/" + << (int)outputs[o].y << "]. Expected: " << outputs[o].value << ", " + << "Read: " << output << tcu::TestLog::EndMessage; + + result = false; + } + } + + if (fbo) + { + gl.deleteFramebuffers(1, &fbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteFramebuffers"); + } + + if (texture) + { + gl.deleteTextures(1, &texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures"); + } + + return result; +} + +bool SpirvValidationBuiltInVariableDecorationsTest::validPerVertexPointFunc(ValidationOutputVec& outputs) +{ + const Functions& gl = m_context.getRenderContext().getFunctions(); + + const GLfloat vertices[] = { -0.3f, -0.3f, 0.0f, 0.0f, -0.3f, 0.0f, 0.3f, -0.3f, 0.0f }; + + GLuint texture; + GLuint fbo; + + gl.genTextures(1, &texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "genTextures"); + gl.bindTexture(GL_TEXTURE_2D, texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture"); + gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 128, 128); + GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage2D"); + + gl.genFramebuffers(1, &fbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "genFramenuffers"); + gl.bindFramebuffer(GL_FRAMEBUFFER, fbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer"); + gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); + GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture2D"); + + gl.viewport(0, 0, 128, 128); + GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport"); + + gl.bufferData(GL_ARRAY_BUFFER, 9 * sizeof(GLfloat), (GLvoid*)vertices, GL_DYNAMIC_DRAW); + GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData"); + + gl.enable(GL_CLIP_DISTANCE0); + gl.enable(GL_PROGRAM_POINT_SIZE); + + gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); + GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor"); + gl.clear(GL_COLOR_BUFFER_BIT); + GLU_EXPECT_NO_ERROR(gl.getError(), "glClear"); + + gl.enableVertexAttribArray(0); + GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray"); + + gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, DE_NULL); + GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer"); + + gl.drawArraysInstanced(GL_POINTS, 0, 3, 3); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArray"); + + gl.disableVertexAttribArray(0); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDisableVertexAttribArray"); + + gl.disable(GL_PROGRAM_POINT_SIZE); + gl.disable(GL_CLIP_DISTANCE0); + + bool result = true; + for (int o = 0; o < outputs.size(); ++o) + { + GLuint output; + gl.readPixels(outputs[o].x, outputs[o].y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)&output); + GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels"); + + if (!commonUtils::compareUintColors(output, outputs[o].value, 2)) + { + m_testCtx.getLog() << tcu::TestLog::Message << "Invalid output color read at [" << (int)outputs[o].x << "/" + << (int)outputs[o].y << "]. Expected: " << outputs[o].value << ", " + << "Read: " << output << tcu::TestLog::EndMessage; + + result = false; + } + } + + if (fbo) + { + gl.deleteFramebuffers(1, &fbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteFramebuffers"); + } + + if (texture) + { + gl.deleteTextures(1, &texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures"); + } + + return result; +} + +bool SpirvValidationBuiltInVariableDecorationsTest::validTesselationGeometryFunc(ValidationOutputVec& outputs) +{ + const Functions& gl = m_context.getRenderContext().getFunctions(); + + const GLfloat vertices[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f }; + + GLuint texture; + GLuint fbo; + + gl.genTextures(1, &texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "genTextures"); + gl.bindTexture(GL_TEXTURE_2D_ARRAY, texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture"); + gl.texStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, 64, 64, 2); + GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage2D"); + + gl.genFramebuffers(1, &fbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "genFramenuffers"); + gl.bindFramebuffer(GL_FRAMEBUFFER, fbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer"); + gl.framebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0); + GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture2D"); + + gl.viewportIndexedf(0, 0.0f, 0.0f, 32.0f, 64.0f); + GLU_EXPECT_NO_ERROR(gl.getError(), "glViewportIndexed"); + + gl.viewportIndexedf(1, 32.0f, 0.0f, 32.0f, 64.0f); + GLU_EXPECT_NO_ERROR(gl.getError(), "glViewportIndexed"); + + gl.bufferData(GL_ARRAY_BUFFER, 9 * sizeof(GLfloat), (GLvoid*)vertices, GL_DYNAMIC_DRAW); + GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData"); + + gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); + GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor"); + gl.clear(GL_COLOR_BUFFER_BIT); + GLU_EXPECT_NO_ERROR(gl.getError(), "glClear"); + + gl.enableVertexAttribArray(0); + GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray"); + + gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, DE_NULL); + GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer"); + + gl.patchParameteri(GL_PATCH_VERTICES, 3); + gl.drawArrays(GL_PATCHES, 0, 3); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArray"); + + gl.disableVertexAttribArray(0); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDisableVertexAttribArray"); + + gl.viewport(0, 0, 128, 64); + GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport"); + + std::vector pixels; + pixels.resize(64 * 64 * 2); + gl.getTexImage(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)pixels.data()); + GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTexImage"); + + bool result = true; + for (int o = 0; o < outputs.size(); ++o) + { + GLuint output = pixels[(outputs[o].x + outputs[o].y * 64) + outputs[o].z * 64 * 64]; + + if (!commonUtils::compareUintColors(output, outputs[o].value, 2)) + { + m_testCtx.getLog() << tcu::TestLog::Message << "Invalid output color read at [" << (int)outputs[o].x << "/" + << (int)outputs[o].y << "/" << (int)outputs[o].z << "]. Expected: " << outputs[o].value + << ", " + << "Read: " << output << tcu::TestLog::EndMessage; + + result = false; + } + } + + if (fbo) + { + gl.deleteFramebuffers(1, &fbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteFramebuffers"); + } + + if (texture) + { + gl.deleteTextures(1, &texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures"); + } + + return result; +} + +bool SpirvValidationBuiltInVariableDecorationsTest::validMultiSamplingFunc(ValidationOutputVec& outputs) +{ + const Functions& gl = m_context.getRenderContext().getFunctions(); + + const GLfloat vertices[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f }; + + GLuint textureMS; + GLuint texture; + GLuint fboMS; + GLuint fbo; + + gl.genTextures(1, &textureMS); + GLU_EXPECT_NO_ERROR(gl.getError(), "genTextures"); + gl.bindTexture(GL_TEXTURE_2D_MULTISAMPLE, textureMS); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture"); + gl.texStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 2, GL_RGBA8, 32, 32, GL_TRUE); + GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage2DMultisample"); + + gl.genTextures(1, &texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "genTextures"); + gl.bindTexture(GL_TEXTURE_2D, texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindTexture"); + gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 32, 32); + GLU_EXPECT_NO_ERROR(gl.getError(), "texStorage2D"); + + gl.genFramebuffers(1, &fboMS); + GLU_EXPECT_NO_ERROR(gl.getError(), "genFramenuffers"); + gl.bindFramebuffer(GL_FRAMEBUFFER, fboMS); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer"); + gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, textureMS, 0); + GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture2D"); + + gl.genFramebuffers(1, &fbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "genFramenuffers"); + gl.bindFramebuffer(GL_FRAMEBUFFER, fbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer"); + gl.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); + GLU_EXPECT_NO_ERROR(gl.getError(), "framebufferTexture2D"); + + gl.bindFramebuffer(GL_FRAMEBUFFER, fboMS); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer"); + + gl.viewport(0, 0, 32, 32); + GLU_EXPECT_NO_ERROR(gl.getError(), "glViewport"); + + gl.bufferData(GL_ARRAY_BUFFER, 9 * sizeof(GLfloat), (GLvoid*)vertices, GL_DYNAMIC_DRAW); + GLU_EXPECT_NO_ERROR(gl.getError(), "glBufferData"); + + gl.enable(GL_CLIP_DISTANCE0); + + gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); + GLU_EXPECT_NO_ERROR(gl.getError(), "glClearColor"); + gl.clear(GL_COLOR_BUFFER_BIT); + GLU_EXPECT_NO_ERROR(gl.getError(), "glClear"); + + gl.enableVertexAttribArray(0); + GLU_EXPECT_NO_ERROR(gl.getError(), "glEnableVertexAttribArray"); + + gl.vertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, DE_NULL); + GLU_EXPECT_NO_ERROR(gl.getError(), "glVertexAttribPointer"); + + gl.drawArrays(GL_TRIANGLES, 0, 3); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawArray"); + + gl.disableVertexAttribArray(0); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDisableVertexAttribArray"); + + gl.disable(GL_CLIP_DISTANCE0); + + gl.bindFramebuffer(GL_READ_FRAMEBUFFER, fboMS); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer"); + gl.bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer"); + + gl.blitFramebuffer(0, 0, 32, 32, 0, 0, 32, 32, GL_COLOR_BUFFER_BIT, GL_NEAREST); + GLU_EXPECT_NO_ERROR(gl.getError(), "blitFramebuffer"); + + gl.bindFramebuffer(GL_FRAMEBUFFER, 0); + GLU_EXPECT_NO_ERROR(gl.getError(), "bindFramebuffer"); + + bool result = true; + for (int o = 0; o < outputs.size(); ++o) + { + GLuint output; + gl.readPixels(outputs[o].x, outputs[o].y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)&output); + GLU_EXPECT_NO_ERROR(gl.getError(), "glReadPixels"); + + if (!commonUtils::compareUintColors(output, outputs[o].value, 2)) + { + m_testCtx.getLog() << tcu::TestLog::Message << "Invalid output color read at [" << (int)outputs[o].x << "/" + << (int)outputs[o].y << "]. Expected: " << outputs[o].value << ", " + << "Read: " << output << tcu::TestLog::EndMessage; + + result = false; + } + } + + if (fboMS) + { + gl.deleteFramebuffers(1, &fboMS); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteFramebuffers"); + } + + if (fbo) + { + gl.deleteFramebuffers(1, &fbo); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteFramebuffers"); + } + + if (textureMS) + { + gl.deleteTextures(1, &texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures"); + } + + if (texture) + { + gl.deleteTextures(1, &texture); + GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteTextures"); + } + + return result; +} + +/** Constructor. + * + * @param context Rendering context. + */ +GlSpirvTests::GlSpirvTests(deqp::Context& context) + : TestCaseGroup(context, "gl_spirv", "Verify conformance of ARB_gl_spirv implementation") +{ +} + +/** Initializes the test group contents. */ +void GlSpirvTests::init() +{ + addChild(new SpirvModulesPositiveTest(m_context)); + addChild(new SpirvShaderBinaryMultipleShaderObjectsTest(m_context)); + addChild(new SpirvModulesStateQueriesTest(m_context)); + addChild(new SpirvModulesErrorVerificationTest(m_context)); + addChild(new SpirvGlslToSpirVEnableTest(m_context)); + addChild(new SpirvGlslToSpirVBuiltInFunctionsTest(m_context)); + addChild(new SpirvGlslToSpirVSpecializationConstantsTest(m_context)); + addChild(new SpirvValidationBuiltInVariableDecorationsTest(m_context)); +} + +} /* gl4cts namespace */ diff --git a/external/openglcts/modules/gl/gl4cGlSpirvTests.hpp b/external/openglcts/modules/gl/gl4cGlSpirvTests.hpp new file mode 100644 index 0000000..25034b0 --- /dev/null +++ b/external/openglcts/modules/gl/gl4cGlSpirvTests.hpp @@ -0,0 +1,288 @@ +#ifndef _GL4CGLSPIRVTESTS_HPP +#define _GL4CGLSPIRVTESTS_HPP +/*------------------------------------------------------------------------- + * OpenGL Conformance Test Suite + * ----------------------------- + * + * Copyright (c) 2017 The Khronos Group Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ /*! + * \file + * \brief + */ /*-------------------------------------------------------------------*/ + +/** + */ /*! + * \file gl4cGlSpirvTests.hpp + * \brief Conformance tests for the GL_ARB_gl_spirv functionality. + */ /*-------------------------------------------------------------------*/ + +#include "glcTestCase.hpp" +#include "gluShaderProgram.hpp" +#include "glwDefs.hpp" +#include "tcuDefs.hpp" +#include +#include + +using namespace glu; +using namespace glw; + +namespace gl4cts +{ + +typedef std::map > SpirVMapping; + +/** Verifies if using SPIR-V modules for each shader stage works as expected. */ +class SpirvModulesPositiveTest : public deqp::TestCase +{ +public: + /* Public methods */ + SpirvModulesPositiveTest(deqp::Context& context); + + void init(); + void deinit(); + + tcu::TestNode::IterateResult iterate(); + +private: + /* Private methods */ + + /* Private members */ + GLuint m_texture; + GLuint m_fbo; + + std::string m_vertex; + std::string m_tesselationCtrl; + std::string m_tesselationEval; + std::string m_geometry; + std::string m_fragment; +}; + +/** Verifies if one binary module can be associated with multiple shader objects. */ +class SpirvShaderBinaryMultipleShaderObjectsTest : public deqp::TestCase +{ +public: + /* Public methods */ + SpirvShaderBinaryMultipleShaderObjectsTest(deqp::Context& context); + + void init(); + void deinit(); + + tcu::TestNode::IterateResult iterate(); + +private: + /* Private methods */ + + /* Private members */ + std::string m_spirv; +}; + +/** Verifies if state queries for new features added by ARB_gl_spirv works as expected. */ +class SpirvModulesStateQueriesTest : public deqp::TestCase +{ +public: + /* Public methods */ + SpirvModulesStateQueriesTest(deqp::Context& context); + + void init(); + void deinit(); + + tcu::TestNode::IterateResult iterate(); + +private: + /* Private methods */ + + /* Private members */ + std::string m_vertex; +}; + +/** Verifies if new features added by ARB_gl_spirv generate error messages as expected. */ +class SpirvModulesErrorVerificationTest : public deqp::TestCase +{ +public: + /* Public methods */ + SpirvModulesErrorVerificationTest(deqp::Context& context); + + void init(); + void deinit(); + + tcu::TestNode::IterateResult iterate(); + +private: + /* Private methods */ + + /* Private members */ + std::string m_vertex; + + GLuint m_glslShaderId; + GLuint m_spirvShaderId; + GLuint m_programId; + GLuint m_textureId; +}; + +/** Verifies if GLSL to Spir-V converter supports Spir-V features. */ +class SpirvGlslToSpirVEnableTest : public deqp::TestCase +{ +public: + /* Public methods */ + SpirvGlslToSpirVEnableTest(deqp::Context& context); + + void init(); + void deinit(); + + tcu::TestNode::IterateResult iterate(); + +private: + /* Private methods */ + + /* Private members */ + std::string m_vertex; +}; + +/** Verifies if GLSL built-in functions are supported by Spir-V. */ +class SpirvGlslToSpirVBuiltInFunctionsTest : public deqp::TestCase +{ +public: + /* Public methods */ + SpirvGlslToSpirVBuiltInFunctionsTest(deqp::Context& context); + + void init(); + void deinit(); + + tcu::TestNode::IterateResult iterate(); + +private: + /* Private methods */ + void initMappings(); + + /* Private members */ + SpirVMapping m_mappings; + + std::string m_commonVertex; + std::string m_commonTessEval; + std::vector m_sources; +}; + +/** Verifies if constant specialization feature works as expected. */ +class SpirvGlslToSpirVSpecializationConstantsTest : public deqp::TestCase +{ +public: + /* Public methods */ + SpirvGlslToSpirVSpecializationConstantsTest(deqp::Context& context); + + void init(); + void deinit(); + + tcu::TestNode::IterateResult iterate(); + +private: + /* Private methods */ + + /* Private members */ + GLuint m_texture; + GLuint m_fbo; + + std::string m_vertex; + std::string m_fragment; +}; + +/** Verifies if Spir-V built in variable decorations works as expected. */ +class SpirvValidationBuiltInVariableDecorationsTest : public deqp::TestCase +{ +public: + /* Public methods */ + SpirvValidationBuiltInVariableDecorationsTest(deqp::Context& context); + + void init(); + void deinit(); + + tcu::TestNode::IterateResult iterate(); + +private: + /* Private structs */ + struct ValidationOutputStruct + { + GLubyte x, y, z; + GLuint value; + + ValidationOutputStruct() : x(0), y(0), z(0), value(0) + { + } + + ValidationOutputStruct(GLubyte _x, GLubyte _y, GLuint _value) : x(_x), y(_y), z(0), value(_value) + { + } + + ValidationOutputStruct(GLubyte _x, GLubyte _y, GLubyte _z, GLuint _value) : x(_x), y(_y), z(_z), value(_value) + { + } + }; + + typedef std::vector ValidationOutputVec; + + typedef bool (SpirvValidationBuiltInVariableDecorationsTest::*ValidationFuncPtr)(ValidationOutputVec& outputs); + + struct ValidationStruct + { + std::vector shaders; + ValidationOutputVec outputs; + ValidationFuncPtr validationFuncPtr; + + ValidationStruct() : validationFuncPtr(DE_NULL) + { + } + + ValidationStruct(ValidationFuncPtr funcPtr) : validationFuncPtr(funcPtr) + { + } + }; + + /* Private methods */ + bool validComputeFunc(ValidationOutputVec& outputs); + bool validPerVertexFragFunc(ValidationOutputVec& outputs); + bool validPerVertexPointFunc(ValidationOutputVec& outputs); + bool validTesselationGeometryFunc(ValidationOutputVec& outputs); + bool validMultiSamplingFunc(ValidationOutputVec& outputs); + + /* Private members */ + SpirVMapping m_mappings; + + std::vector m_validations; + + std::string m_compute; + std::string m_vertex; + std::string m_tesselationCtrl; + std::string m_tesselationEval; + std::string m_geometry; + std::string m_fragment; +}; + +/** Test group which encapsulates all sparse buffer conformance tests */ +class GlSpirvTests : public deqp::TestCaseGroup +{ +public: + /* Public methods */ + GlSpirvTests(deqp::Context& context); + + void init(); + +private: + GlSpirvTests(const GlSpirvTests& other); + GlSpirvTests& operator=(const GlSpirvTests& other); +}; + +} /* glcts namespace */ + +#endif // _GL4CGLSPIRVTESTS_HPP diff --git a/external/openglcts/modules/gl/gl4cTestPackages.cpp b/external/openglcts/modules/gl/gl4cTestPackages.cpp index 73d4cb1..a1bc0a7 100644 --- a/external/openglcts/modules/gl/gl4cTestPackages.cpp +++ b/external/openglcts/modules/gl/gl4cTestPackages.cpp @@ -35,6 +35,7 @@ #include "gl4cEnhancedLayoutsTests.hpp" #include "gl4cGPUShaderFP64Tests.hpp" #include "gl4cGetTextureSubImageTests.hpp" +#include "gl4cGlSpirvTests.hpp" #include "gl4cIncompleteTextureAccessTests.hpp" #include "gl4cIndirectParametersTests.hpp" #include "gl4cKHRDebugTests.hpp" @@ -372,6 +373,7 @@ void GL45TestPackage::init(void) addChild(new glcts::PolygonOffsetClamp(getContext())); addChild(new glcts::SeparableProgramsTransformFeedbackTests(getContext())); addChild(new gl4cts::SpirvExtensionsTests(getContext())); + addChild(new gl4cts::GlSpirvTests(getContext())); } catch (...) { diff --git a/framework/opengl/gluShaderProgram.cpp b/framework/opengl/gluShaderProgram.cpp index 333e0d5..94b310b 100644 --- a/framework/opengl/gluShaderProgram.cpp +++ b/framework/opengl/gluShaderProgram.cpp @@ -132,6 +132,65 @@ void Shader::compile (void) } } +void Shader::specialize (const char* entryPoint, glw::GLuint numSpecializationConstants, + const glw::GLuint* constantIndex, const glw::GLuint* constantValue) +{ + m_info.compileOk = false; + m_info.compileTimeUs = 0; + m_info.infoLog.clear(); + + { + deUint64 compileStart = deGetMicroseconds(); + m_gl.specializeShader(m_shader, entryPoint, numSpecializationConstants, constantIndex, constantValue); + m_info.compileTimeUs = deGetMicroseconds() - compileStart; + } + + GLU_EXPECT_NO_ERROR(m_gl.getError(), "glSpecializeShader()"); + + // Query status + { + int compileStatus = 0; + + m_gl.getShaderiv(m_shader, GL_COMPILE_STATUS, &compileStatus); + GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderiv()"); + + m_info.compileOk = compileStatus != GL_FALSE; + } + + // Query log + { + int infoLogLen = 0; + int unusedLen; + + m_gl.getShaderiv(m_shader, GL_INFO_LOG_LENGTH, &infoLogLen); + GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderiv()"); + + if (infoLogLen > 0) + { + // The INFO_LOG_LENGTH query and the buffer query implementations have + // very commonly off-by-one errors. Try to work around these issues. + + // add tolerance for off-by-one in log length, buffer write, and for terminator + std::vector infoLog(infoLogLen + 3, '\0'); + + // claim buf size is one smaller to protect from off-by-one writing over buffer bounds + m_gl.getShaderInfoLog(m_shader, (int)infoLog.size() - 1, &unusedLen, &infoLog[0]); + GLU_EXPECT_NO_ERROR(m_gl.getError(), "glGetShaderInfoLog()"); + + if (infoLog[(int)(infoLog.size()) - 1] != '\0') + { + // return whole buffer if null terminator was overwritten + m_info.infoLog = std::string(&infoLog[0], infoLog.size()); + } + else + { + // read as C string. infoLog is guaranteed to be 0-terminated + m_info.infoLog = std::string(&infoLog[0]); + } + } + } +} + // Program static bool getProgramLinkStatus (const glw::Functions& gl, deUint32 program) @@ -312,12 +371,24 @@ ShaderProgram::ShaderProgram (const RenderContext& renderCtx, const ProgramSourc init(renderCtx.getFunctions(), sources); } +ShaderProgram::ShaderProgram (const RenderContext& renderCtx, const ProgramBinaries& binaries) + : m_program(renderCtx.getFunctions()) +{ + init(renderCtx.getFunctions(), binaries); +} + ShaderProgram::ShaderProgram (const glw::Functions& gl, const ProgramSources& sources) : m_program(gl) { init(gl, sources); } +ShaderProgram::ShaderProgram (const glw::Functions& gl, const ProgramBinaries& binaries) + : m_program(gl) +{ + init(gl, binaries); +} + void ShaderProgram::init (const glw::Functions& gl, const ProgramSources& sources) { try @@ -375,6 +446,85 @@ void ShaderProgram::init (const glw::Functions& gl, const ProgramSources& source } } +void ShaderProgram::init (const glw::Functions& gl, const ProgramBinaries& binaries) +{ + try + { + bool shadersOk = true; + + for (deUint32 binaryNdx = 0; binaryNdx < binaries.binaries.size(); ++binaryNdx) + { + ShaderBinary shaderBinary = binaries.binaries[binaryNdx]; + if (!shaderBinary.binary.empty()) + { + const char* binary = (const char*)shaderBinary.binary.data(); + const int length = (int)(shaderBinary.binary.size() * sizeof(deUint32)); + + DE_ASSERT(shaderBinary.shaderEntryPoints.size() == shaderBinary.shaderTypes.size()); + + std::vector shaders; + for (deUint32 shaderTypeNdx = 0; shaderTypeNdx < shaderBinary.shaderTypes.size(); ++shaderTypeNdx) + { + ShaderType shaderType = shaderBinary.shaderTypes[shaderTypeNdx]; + + Shader* shader = new Shader(gl, ShaderType(shaderType)); + + m_shaders[shaderType].reserve(m_shaders[shaderType].size() + 1); + m_shaders[shaderType].push_back(shader); + shaders.push_back(shader); + } + + setBinary(gl, shaders, binaries.binaryFormat, binary, length); + + for (deUint32 shaderNdx = 0; shaderNdx < shaders.size(); ++shaderNdx) + { + shaders[shaderNdx]->specialize(shaderBinary.shaderEntryPoints[shaderNdx].c_str(), + (deUint32)shaderBinary.specializationIndices.size(), + shaderBinary.specializationIndices.data(), + shaderBinary.specializationValues.data()); + + shadersOk = shadersOk && shaders[shaderNdx]->getCompileStatus(); + } + } + } + + if (shadersOk) + { + for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++) + for (int shaderNdx = 0; shaderNdx < (int)m_shaders[shaderType].size(); ++shaderNdx) + m_program.attachShader(m_shaders[shaderType][shaderNdx]->getShader()); + + m_program.link(); + } + } + catch (...) + { + for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++) + for (int shaderNdx = 0; shaderNdx < (int)m_shaders[shaderType].size(); ++shaderNdx) + delete m_shaders[shaderType][shaderNdx]; + throw; + } +} + +void ShaderProgram::setBinary (const glw::Functions& gl, std::vector& shaders, glw::GLenum binaryFormat, const void* binaryData, const int length) +{ + std::vector shaderVec; + for (deUint32 shaderNdx = 0; shaderNdx < shaders.size(); ++shaderNdx) + shaderVec.push_back(shaders[shaderNdx]->getShader()); + + gl.shaderBinary((glw::GLsizei)shaderVec.size(), shaderVec.data(), binaryFormat, binaryData, length); + GLU_EXPECT_NO_ERROR(gl.getError(), "glShaderBinary"); + + for (deUint32 shaderNdx = 0; shaderNdx < shaders.size(); ++shaderNdx) + { + glw::GLint shaderState; + gl.getShaderiv(shaders[shaderNdx]->getShader(), GL_SPIR_V_BINARY_ARB, &shaderState); + GLU_EXPECT_NO_ERROR(gl.getError(), "getShaderiv"); + + DE_ASSERT(shaderState == GL_TRUE); + } +} + ShaderProgram::~ShaderProgram (void) { for (int shaderType = 0; shaderType < SHADERTYPE_LAST; shaderType++) diff --git a/framework/opengl/gluShaderProgram.hpp b/framework/opengl/gluShaderProgram.hpp index e2c7ad2..3a8b263 100644 --- a/framework/opengl/gluShaderProgram.hpp +++ b/framework/opengl/gluShaderProgram.hpp @@ -25,6 +25,7 @@ #include "gluDefs.hpp" #include "gluShaderUtil.hpp" +#include "glwEnums.hpp" #include "qpTestLog.h" #include @@ -40,6 +41,8 @@ namespace glu class RenderContext; +typedef std::vector ShaderBinaryDataType; + /*--------------------------------------------------------------------*//*! * \brief Shader information (compile status, log, etc.). *//*--------------------------------------------------------------------*/ @@ -87,6 +90,8 @@ public: void setSources (int numSourceStrings, const char* const* sourceStrings, const int* lengths); void compile (void); + void specialize (const char* entryPoint, glw::GLuint numSpecializationConstants, + const glw::GLuint* constantIndex, const glw::GLuint* constantValue); deUint32 getShader (void) const { return m_shader; } const ShaderInfo& getInfo (void) const { return m_info; } @@ -173,6 +178,7 @@ private: }; struct ProgramSources; +struct ProgramBinaries; /*--------------------------------------------------------------------*//*! * \brief Shader program manager. @@ -184,13 +190,16 @@ class ShaderProgram { public: ShaderProgram (const glw::Functions& gl, const ProgramSources& sources); + ShaderProgram (const glw::Functions& gl, const ProgramBinaries& binaries); ShaderProgram (const RenderContext& renderCtx, const ProgramSources& sources); + ShaderProgram (const RenderContext& renderCtx, const ProgramBinaries& binaries); ~ShaderProgram (void); bool isOk (void) const { return m_program.getLinkStatus(); } deUint32 getProgram (void) const { return m_program.getProgram(); } bool hasShader (glu::ShaderType shaderType) const { return !m_shaders[shaderType].empty(); } + Shader* getShader (glu::ShaderType shaderType, int shaderNdx = 0) const { return m_shaders[shaderType][shaderNdx]; } int getNumShaders (glu::ShaderType shaderType) const { return (int)m_shaders[shaderType].size(); } const ShaderInfo& getShaderInfo (glu::ShaderType shaderType, int shaderNdx = 0) const { return m_shaders[shaderType][shaderNdx]->getInfo(); } const ProgramInfo& getProgramInfo (void) const { return m_program.getInfo(); } @@ -199,6 +208,8 @@ private: ShaderProgram (const ShaderProgram& other); ShaderProgram& operator= (const ShaderProgram& other); void init (const glw::Functions& gl, const ProgramSources& sources); + void init (const glw::Functions& gl, const ProgramBinaries& binaries); + void setBinary (const glw::Functions& gl, std::vector& shaders, glw::GLenum binaryFormat, const void* binaryData, const int length); std::vector m_shaders[SHADERTYPE_LAST]; Program m_program; @@ -317,6 +328,97 @@ struct ProgramSources ProgramSources& operator<< (const TransformFeedbackVaryings& varyings); }; +struct SpecializationData +{ + deUint32 index; + deUint32 value; + + SpecializationData (void) : index(0), value(0) {} + SpecializationData (const deUint32 index_, const deUint32 value_) : index(index_), value(value_) {} +}; + +struct ShaderBinary +{ + ShaderBinaryDataType binary; + std::vector shaderTypes; + std::vector shaderEntryPoints; + std::vector specializationIndices; + std::vector specializationValues; + + ShaderBinary (void) {} + ShaderBinary (const ShaderBinaryDataType binary_) : binary(binary_) + { + DE_ASSERT(!binary_.empty()); + } + ShaderBinary (const ShaderBinaryDataType binary_, glu::ShaderType shaderType_) : binary(binary_) + { + DE_ASSERT(!binary_.empty()); + shaderTypes.push_back(shaderType_); + shaderEntryPoints.push_back("main"); + } + + ShaderBinary& operator<< (const ShaderType& shaderType) + { + shaderTypes.push_back(shaderType); + return *this; + } + + ShaderBinary& operator<< (const std::string& entryPoint) + { + shaderEntryPoints.push_back(entryPoint); + return *this; + } + + ShaderBinary& operator<< (const SpecializationData& specData) + { + specializationIndices.push_back(specData.index); + specializationValues.push_back(specData.value); + return *this; + } +}; + +struct VertexBinary : public ShaderBinary +{ + VertexBinary (const ShaderBinaryDataType binary_) : ShaderBinary(binary_, glu::SHADERTYPE_VERTEX) {} +}; + +struct FragmentBinary : public ShaderBinary +{ + FragmentBinary (const ShaderBinaryDataType binary_) : ShaderBinary(binary_, glu::SHADERTYPE_FRAGMENT) {} +}; + +struct GeometryBinary : public ShaderBinary +{ + GeometryBinary (const ShaderBinaryDataType binary_) : ShaderBinary(binary_, glu::SHADERTYPE_GEOMETRY) {} +}; + +struct ComputeBinary : public ShaderBinary +{ + ComputeBinary (const ShaderBinaryDataType binary_) : ShaderBinary(binary_, glu::SHADERTYPE_COMPUTE) {} +}; + +struct TessellationControlBinary : public ShaderBinary +{ + TessellationControlBinary (const ShaderBinaryDataType binary_) : ShaderBinary(binary_, glu::SHADERTYPE_TESSELLATION_CONTROL) {} +}; + +struct TessellationEvaluationBinary : public ShaderBinary +{ + TessellationEvaluationBinary (const ShaderBinaryDataType binary_) : ShaderBinary(binary_, glu::SHADERTYPE_TESSELLATION_EVALUATION) {} +}; + +struct ProgramBinaries +{ + std::vector binaries; + + glw::GLenum binaryFormat; + + ProgramBinaries (void) : binaryFormat(GL_SHADER_BINARY_FORMAT_SPIR_V_ARB) {} + ProgramBinaries (glw::GLenum binaryFormat_) : binaryFormat(binaryFormat_) {} + + ProgramBinaries& operator<< (const ShaderBinary& shaderBinary) { binaries.push_back(shaderBinary); return *this; } +}; + template inline ProgramSources& ProgramSources::operator<< (const TransformFeedbackVaryings& varyings) { diff --git a/framework/opengl/wrapper/glwEnums.inl b/framework/opengl/wrapper/glwEnums.inl index e8c9d0b..17b523e 100644 --- a/framework/opengl/wrapper/glwEnums.inl +++ b/framework/opengl/wrapper/glwEnums.inl @@ -1780,6 +1780,8 @@ #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12 0x93DD #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD #define GL_SHADER_BINARY_FORMAT_SPIR_V 0x9551 +#define GL_SHADER_BINARY_FORMAT_SPIR_V_ARB 0x9551 #define GL_SPIR_V_BINARY 0x9552 +#define GL_SPIR_V_BINARY_ARB 0x9552 #define GL_SPIR_V_EXTENSIONS 0x9553 #define GL_NUM_SPIR_V_EXTENSIONS 0x9554 diff --git a/framework/opengl/wrapper/glwInitExtGL.inl b/framework/opengl/wrapper/glwInitExtGL.inl index 419398f..5cfe14b 100644 --- a/framework/opengl/wrapper/glwInitExtGL.inl +++ b/framework/opengl/wrapper/glwInitExtGL.inl @@ -705,6 +705,11 @@ if (de::contains(extSet, "GL_ARB_get_program_binary")) gl->programParameteri = (glProgramParameteriFunc) loader->get("glProgramParameteri"); } +if (de::contains(extSet, "GL_ARB_gl_spirv")) +{ + gl->specializeShader = (glSpecializeShaderFunc) loader->get("glSpecializeShaderARB"); +} + if (de::contains(extSet, "GL_ARB_indirect_parameters")) { gl->multiDrawArraysIndirectCount = (glMultiDrawArraysIndirectCountFunc) loader->get("glMultiDrawArraysIndirectCountARB"); diff --git a/scripts/opengl/src_util.py b/scripts/opengl/src_util.py index 96ae341..006a5e0 100644 --- a/scripts/opengl/src_util.py +++ b/scripts/opengl/src_util.py @@ -100,6 +100,7 @@ EXTENSIONS = [ 'GL_ARB_draw_elements_base_vertex', 'GL_ARB_direct_state_access', 'GL_ARB_get_program_binary', + 'GL_ARB_gl_spirv', 'GL_ARB_indirect_parameters', 'GL_ARB_internalformat_query', 'GL_ARB_instanced_arrays', -- 2.7.4