2
0

test_glsl_shader.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. from panda3d import core
  2. import pytest
  3. from _pytest.outcomes import Failed
  4. # This is the template for the compute shader that is used by run_glsl_test.
  5. # It defines an assert() macro that writes failures to a buffer, indexed by
  6. # line number.
  7. # The reset() function serves to prevent the _triggered variable from being
  8. # optimized out in the case that the assertions are being optimized out.
  9. GLSL_COMPUTE_TEMPLATE = """#version {version}
  10. layout(local_size_x = 1, local_size_y = 1) in;
  11. {preamble}
  12. layout(r8ui) uniform writeonly uimageBuffer _triggered;
  13. void _reset() {{
  14. imageStore(_triggered, 0, uvec4(0, 0, 0, 0));
  15. }}
  16. void _assert(bool cond, int line) {{
  17. if (!cond) {{
  18. imageStore(_triggered, line, uvec4(1));
  19. }}
  20. }}
  21. #define assert(cond) _assert(cond, __LINE__)
  22. void main() {{
  23. _reset();
  24. {body}
  25. }}
  26. """
  27. def run_glsl_test(gsg, body, preamble="", inputs={}, version=430):
  28. """ Runs a GLSL test on the given GSG. The given body is executed in the
  29. main function and should call assert(). The preamble should contain all
  30. of the shader inputs. """
  31. if not gsg.supports_compute_shaders or not gsg.supports_glsl:
  32. pytest.skip("compute shaders not supported")
  33. __tracebackhide__ = True
  34. preamble = preamble.strip()
  35. body = body.rstrip().lstrip('\n')
  36. code = GLSL_COMPUTE_TEMPLATE.format(version=version, preamble=preamble, body=body)
  37. line_offset = code[:code.find(body)].count('\n') + 1
  38. shader = core.Shader.make_compute(core.Shader.SL_GLSL, code)
  39. assert shader, code
  40. # Create a buffer to hold the results of the assertion. We use one byte
  41. # per line of shader code, so we can show which lines triggered.
  42. result = core.Texture("")
  43. result.set_clear_color((0, 0, 0, 0))
  44. result.setup_buffer_texture(code.count('\n'), core.Texture.T_unsigned_byte,
  45. core.Texture.F_r8i, core.GeomEnums.UH_static)
  46. # Build up the shader inputs
  47. attrib = core.ShaderAttrib.make(shader)
  48. for name, value in inputs.items():
  49. attrib = attrib.set_shader_input(name, value)
  50. attrib = attrib.set_shader_input('_triggered', result)
  51. # Run the compute shader.
  52. engine = core.GraphicsEngine.get_global_ptr()
  53. try:
  54. engine.dispatch_compute((1, 1, 1), attrib, gsg)
  55. except AssertionError as exc:
  56. assert False, "Error executing compute shader:\n" + code
  57. # Download the texture to check whether the assertion triggered.
  58. assert engine.extract_texture_data(result, gsg)
  59. triggered = result.get_ram_image()
  60. if any(triggered):
  61. count = len(triggered) - triggered.count(0)
  62. lines = body.split('\n')
  63. formatted = ''
  64. for i, line in enumerate(lines):
  65. if triggered[i + line_offset]:
  66. formatted += '=> ' + line + '\n'
  67. else:
  68. formatted += ' ' + line + '\n'
  69. pytest.fail("{0} GLSL assertions triggered:\n{1}".format(count, formatted))
  70. def test_glsl_test(gsg):
  71. "Test to make sure that the GLSL tests work correctly."
  72. run_glsl_test(gsg, "assert(true);")
  73. def test_glsl_test_fail(gsg):
  74. "Same as above, but making sure that the failure case works correctly."
  75. with pytest.raises(Failed):
  76. run_glsl_test(gsg, "assert(false);")
  77. def test_glsl_sampler(gsg):
  78. tex1 = core.Texture("")
  79. tex1.setup_1d_texture(1, core.Texture.T_unsigned_byte, core.Texture.F_rgba8)
  80. tex1.set_clear_color((0, 2 / 255.0, 1, 1))
  81. tex2 = core.Texture("")
  82. tex2.setup_2d_texture(1, 1, core.Texture.T_float, core.Texture.F_rgba32)
  83. tex2.set_clear_color((1.0, 2.0, -3.14, 0.0))
  84. preamble = """
  85. uniform sampler1D tex1;
  86. uniform sampler2D tex2;
  87. """
  88. code = """
  89. assert(texelFetch(tex1, 0, 0) == vec4(0, 2 / 255.0, 1, 1));
  90. assert(texelFetch(tex2, ivec2(0, 0), 0) == vec4(1.0, 2.0, -3.14, 0.0));
  91. """
  92. run_glsl_test(gsg, code, preamble, {'tex1': tex1, 'tex2': tex2}), code
  93. def test_glsl_image(gsg):
  94. tex1 = core.Texture("")
  95. tex1.setup_1d_texture(1, core.Texture.T_unsigned_byte, core.Texture.F_rgba8)
  96. tex1.set_clear_color((0, 2 / 255.0, 1, 1))
  97. tex2 = core.Texture("")
  98. tex2.setup_2d_texture(1, 1, core.Texture.T_float, core.Texture.F_rgba32)
  99. tex2.set_clear_color((1.0, 2.0, -3.14, 0.0))
  100. preamble = """
  101. layout(rgba8) uniform image1D tex1;
  102. layout(rgba32f) uniform image2D tex2;
  103. """
  104. code = """
  105. assert(imageLoad(tex1, 0) == vec4(0, 2 / 255.0, 1, 1));
  106. assert(imageLoad(tex2, ivec2(0, 0)) == vec4(1.0, 2.0, -3.14, 0.0));
  107. """
  108. run_glsl_test(gsg, code, preamble, {'tex1': tex1, 'tex2': tex2}), code
  109. def test_glsl_ssbo(gsg):
  110. from struct import pack
  111. num1 = pack('<i', 1234567)
  112. num2 = pack('<i', -1234567)
  113. buffer1 = core.ShaderBuffer("buffer1", num1, core.GeomEnums.UH_static)
  114. buffer2 = core.ShaderBuffer("buffer2", num2, core.GeomEnums.UH_static)
  115. preamble = """
  116. layout(std430, binding=0) buffer buffer1 {
  117. int value1;
  118. };
  119. layout(std430, binding=1) buffer buffer2 {
  120. int value2;
  121. };
  122. """
  123. code = """
  124. assert(value1 == 1234567);
  125. assert(value2 == -1234567);
  126. """
  127. run_glsl_test(gsg, code, preamble, {'buffer1': buffer1, 'buffer2': buffer2}), code
  128. def test_glsl_int(gsg):
  129. inputs = dict(
  130. zero=0,
  131. intmax=0x7fffffff,
  132. intmin=-0x80000000,
  133. )
  134. preamble = """
  135. uniform int zero;
  136. uniform int intmax;
  137. uniform int intmin;
  138. """
  139. code = """
  140. assert(zero == 0);
  141. assert(intmax == 0x7fffffff);
  142. assert(intmin == -0x80000000);
  143. """
  144. run_glsl_test(gsg, code, preamble, inputs)
  145. @pytest.mark.xfail
  146. def test_glsl_uint(gsg):
  147. #TODO: fix passing uints greater than intmax
  148. inputs = dict(
  149. zero=0,
  150. intmax=0x7fffffff,
  151. )
  152. preamble = """
  153. uniform unsigned int zero;
  154. uniform unsigned int intmax;
  155. """
  156. code = """
  157. assert(zero == 0);
  158. assert(intmax == 0x7fffffff);
  159. """
  160. run_glsl_test(gsg, code, preamble, inputs)
  161. def test_glsl_bool(gsg):
  162. flags = dict(
  163. flag1=False,
  164. flag2=0,
  165. flag3=0.0,
  166. flag4=True,
  167. flag5=1,
  168. flag6=3,
  169. )
  170. preamble = """
  171. uniform bool flag1;
  172. uniform bool flag2;
  173. uniform bool flag3;
  174. uniform bool flag4;
  175. uniform bool flag5;
  176. uniform bool flag6;
  177. """
  178. code = """
  179. assert(!flag1);
  180. assert(!flag2);
  181. assert(!flag3);
  182. assert(flag4);
  183. assert(flag5);
  184. assert(flag6);
  185. """
  186. run_glsl_test(gsg, code, preamble, flags)
  187. def test_glsl_pta_int(gsg):
  188. pta = core.PTA_int((0, 1, 2, 3))
  189. preamble = """
  190. uniform int pta[4];
  191. """
  192. code = """
  193. assert(pta[0] == 0);
  194. assert(pta[1] == 1);
  195. assert(pta[2] == 2);
  196. assert(pta[3] == 3);
  197. """
  198. run_glsl_test(gsg, code, preamble, {'pta': pta}), code
  199. def test_glsl_pta_ivec4(gsg):
  200. pta = core.PTA_LVecBase4i(((0, 1, 2, 3), (4, 5, 6, 7)))
  201. preamble = """
  202. uniform ivec4 pta[2];
  203. """
  204. code = """
  205. assert(pta[0] == ivec4(0, 1, 2, 3));
  206. assert(pta[1] == ivec4(4, 5, 6, 7));
  207. """
  208. run_glsl_test(gsg, code, preamble, {'pta': pta}), code
  209. def test_glsl_pta_mat4(gsg):
  210. pta = core.PTA_LMatrix4f((
  211. (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
  212. (16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31),
  213. ))
  214. preamble = """
  215. uniform mat4 pta[2];
  216. """
  217. code = """
  218. assert(pta[0][0] == vec4(0, 1, 2, 3));
  219. assert(pta[0][1] == vec4(4, 5, 6, 7));
  220. assert(pta[0][2] == vec4(8, 9, 10, 11));
  221. assert(pta[0][3] == vec4(12, 13, 14, 15));
  222. assert(pta[1][0] == vec4(16, 17, 18, 19));
  223. assert(pta[1][1] == vec4(20, 21, 22, 23));
  224. assert(pta[1][2] == vec4(24, 25, 26, 27));
  225. assert(pta[1][3] == vec4(28, 29, 30, 31));
  226. """
  227. run_glsl_test(gsg, code, preamble, {'pta': pta}), code