| 
									
										
										
										
											2022-02-11 09:07:11 +11:00
										 |  |  | /* SPDX-License-Identifier: Apache-2.0 */ | 
					
						
							| 
									
										
										
										
											2021-05-26 16:49:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "testing/testing.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "GPU_capabilities.h"
 | 
					
						
							|  |  |  | #include "GPU_compute.h"
 | 
					
						
							|  |  |  | #include "GPU_index_buffer.h"
 | 
					
						
							|  |  |  | #include "GPU_shader.h"
 | 
					
						
							|  |  |  | #include "GPU_texture.h"
 | 
					
						
							|  |  |  | #include "GPU_vertex_buffer.h"
 | 
					
						
							|  |  |  | #include "GPU_vertex_format.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "MEM_guardedalloc.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "gpu_testing.hh"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "GPU_glew.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace blender::gpu::tests { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-28 08:28:56 +02:00
										 |  |  | static void test_gpu_shader_compute_2d() | 
					
						
							| 
									
										
										
										
											2021-05-26 16:49:17 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!GPU_compute_shader_support()) { | 
					
						
							|  |  |  |     /* We can't test as a the platform does not support compute shaders. */ | 
					
						
							|  |  |  |     std::cout << "Skipping compute shader test: platform not supported"; | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   static constexpr uint SIZE = 512; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Build compute shader. */ | 
					
						
							|  |  |  |   const char *compute_glsl = R"( | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | layout(local_size_x = 1, local_size_y = 1) in; | 
					
						
							|  |  |  | layout(rgba32f, binding = 0) uniform image2D img_output; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void main() { | 
					
						
							|  |  |  |   vec4 pixel = vec4(1.0, 0.5, 0.2, 1.0); | 
					
						
							|  |  |  |   imageStore(img_output, ivec2(gl_GlobalInvocationID.xy), pixel); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | )"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPUShader *shader = GPU_shader_create_compute( | 
					
						
							|  |  |  |       compute_glsl, nullptr, nullptr, "gpu_shader_compute_2d"); | 
					
						
							|  |  |  |   EXPECT_NE(shader, nullptr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Create texture to store result and attach to shader. */ | 
					
						
							|  |  |  |   GPUTexture *texture = GPU_texture_create_2d( | 
					
						
							|  |  |  |       "gpu_shader_compute_2d", SIZE, SIZE, 0, GPU_RGBA32F, nullptr); | 
					
						
							|  |  |  |   EXPECT_NE(texture, nullptr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPU_shader_bind(shader); | 
					
						
							|  |  |  |   GPU_texture_image_bind(texture, GPU_shader_get_texture_binding(shader, "img_output")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Dispatch compute task. */ | 
					
						
							|  |  |  |   GPU_compute_dispatch(shader, SIZE, SIZE, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Check if compute has been done. */ | 
					
						
							|  |  |  |   GPU_memory_barrier(GPU_BARRIER_TEXTURE_FETCH); | 
					
						
							|  |  |  |   float *data = static_cast<float *>(GPU_texture_read(texture, GPU_DATA_FLOAT, 0)); | 
					
						
							|  |  |  |   EXPECT_NE(data, nullptr); | 
					
						
							|  |  |  |   for (int index = 0; index < SIZE * SIZE; index++) { | 
					
						
							|  |  |  |     EXPECT_FLOAT_EQ(data[index * 4 + 0], 1.0f); | 
					
						
							|  |  |  |     EXPECT_FLOAT_EQ(data[index * 4 + 1], 0.5f); | 
					
						
							|  |  |  |     EXPECT_FLOAT_EQ(data[index * 4 + 2], 0.2f); | 
					
						
							|  |  |  |     EXPECT_FLOAT_EQ(data[index * 4 + 3], 1.0f); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   MEM_freeN(data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Cleanup. */ | 
					
						
							|  |  |  |   GPU_shader_unbind(); | 
					
						
							|  |  |  |   GPU_texture_unbind(texture); | 
					
						
							|  |  |  |   GPU_texture_free(texture); | 
					
						
							|  |  |  |   GPU_shader_free(shader); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-06-28 08:28:56 +02:00
										 |  |  | GPU_TEST(gpu_shader_compute_2d) | 
					
						
							| 
									
										
										
										
											2021-05-26 16:49:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-28 08:28:56 +02:00
										 |  |  | static void test_gpu_shader_compute_1d() | 
					
						
							| 
									
										
										
										
											2021-05-26 16:49:17 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!GPU_compute_shader_support()) { | 
					
						
							|  |  |  |     /* We can't test as a the platform does not support compute shaders. */ | 
					
						
							|  |  |  |     std::cout << "Skipping compute shader test: platform not supported"; | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   static constexpr uint SIZE = 10; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Build compute shader. */ | 
					
						
							|  |  |  |   const char *compute_glsl = R"( | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | layout(local_size_x = 1) in; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | layout(rgba32f, binding = 1) uniform image1D outputVboData; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void main() { | 
					
						
							|  |  |  |   int index = int(gl_GlobalInvocationID.x); | 
					
						
							|  |  |  |   vec4 pos = vec4(gl_GlobalInvocationID.x); | 
					
						
							|  |  |  |   imageStore(outputVboData, index, pos); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | )"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPUShader *shader = GPU_shader_create_compute( | 
					
						
							|  |  |  |       compute_glsl, nullptr, nullptr, "gpu_shader_compute_1d"); | 
					
						
							|  |  |  |   EXPECT_NE(shader, nullptr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Construct Texture. */ | 
					
						
							| 
									
										
										
										
											2021-08-11 10:11:12 +10:00
										 |  |  |   GPUTexture *texture = GPU_texture_create_1d( | 
					
						
							|  |  |  |       "gpu_shader_compute_1d", SIZE, 0, GPU_RGBA32F, nullptr); | 
					
						
							| 
									
										
										
										
											2021-05-26 16:49:17 +02:00
										 |  |  |   EXPECT_NE(texture, nullptr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPU_shader_bind(shader); | 
					
						
							|  |  |  |   GPU_texture_image_bind(texture, GPU_shader_get_texture_binding(shader, "outputVboData")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Dispatch compute task. */ | 
					
						
							|  |  |  |   GPU_compute_dispatch(shader, SIZE, 1, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Check if compute has been done. */ | 
					
						
							|  |  |  |   GPU_memory_barrier(GPU_BARRIER_TEXTURE_FETCH); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Create texture to load back result. */ | 
					
						
							|  |  |  |   float *data = static_cast<float *>(GPU_texture_read(texture, GPU_DATA_FLOAT, 0)); | 
					
						
							|  |  |  |   EXPECT_NE(data, nullptr); | 
					
						
							|  |  |  |   for (int index = 0; index < SIZE; index++) { | 
					
						
							|  |  |  |     float expected_value = index; | 
					
						
							|  |  |  |     EXPECT_FLOAT_EQ(data[index * 4 + 0], expected_value); | 
					
						
							|  |  |  |     EXPECT_FLOAT_EQ(data[index * 4 + 1], expected_value); | 
					
						
							|  |  |  |     EXPECT_FLOAT_EQ(data[index * 4 + 2], expected_value); | 
					
						
							|  |  |  |     EXPECT_FLOAT_EQ(data[index * 4 + 3], expected_value); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   MEM_freeN(data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Cleanup. */ | 
					
						
							|  |  |  |   GPU_shader_unbind(); | 
					
						
							|  |  |  |   GPU_texture_unbind(texture); | 
					
						
							|  |  |  |   GPU_texture_free(texture); | 
					
						
							|  |  |  |   GPU_shader_free(shader); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-06-28 08:28:56 +02:00
										 |  |  | GPU_TEST(gpu_shader_compute_1d) | 
					
						
							| 
									
										
										
										
											2021-05-26 16:49:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-28 08:28:56 +02:00
										 |  |  | static void test_gpu_shader_compute_vbo() | 
					
						
							| 
									
										
										
										
											2021-05-26 16:49:17 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!GPU_compute_shader_support()) { | 
					
						
							|  |  |  |     /* We can't test as a the platform does not support compute shaders. */ | 
					
						
							|  |  |  |     std::cout << "Skipping compute shader test: platform not supported"; | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   static constexpr uint SIZE = 128; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Build compute shader. */ | 
					
						
							|  |  |  |   const char *compute_glsl = R"( | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | layout(local_size_x = 1) in; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | layout(std430, binding = 0) writeonly buffer outputVboData | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   vec4 out_positions[]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void main() { | 
					
						
							|  |  |  |   uint index = gl_GlobalInvocationID.x; | 
					
						
							|  |  |  |   vec4 pos = vec4(gl_GlobalInvocationID.x); | 
					
						
							|  |  |  |   out_positions[index] = pos; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | )"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPUShader *shader = GPU_shader_create_compute( | 
					
						
							|  |  |  |       compute_glsl, nullptr, nullptr, "gpu_shader_compute_vbo"); | 
					
						
							|  |  |  |   EXPECT_NE(shader, nullptr); | 
					
						
							|  |  |  |   GPU_shader_bind(shader); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Construct VBO. */ | 
					
						
							|  |  |  |   static GPUVertFormat format = {0}; | 
					
						
							|  |  |  |   GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); | 
					
						
							|  |  |  |   GPUVertBuf *vbo = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_DEVICE_ONLY); | 
					
						
							|  |  |  |   GPU_vertbuf_data_alloc(vbo, SIZE); | 
					
						
							|  |  |  |   GPU_vertbuf_bind_as_ssbo(vbo, GPU_shader_get_ssbo(shader, "outputVboData")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Dispatch compute task. */ | 
					
						
							|  |  |  |   GPU_compute_dispatch(shader, SIZE, 1, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Check if compute has been done. */ | 
					
						
							|  |  |  |   GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Download the vertex buffer. */ | 
					
						
							|  |  |  |   const float *data = static_cast<const float *>(GPU_vertbuf_read(vbo)); | 
					
						
							|  |  |  |   ASSERT_NE(data, nullptr); | 
					
						
							|  |  |  |   for (int index = 0; index < SIZE; index++) { | 
					
						
							|  |  |  |     float expected_value = index; | 
					
						
							|  |  |  |     EXPECT_FLOAT_EQ(data[index * 4 + 0], expected_value); | 
					
						
							|  |  |  |     EXPECT_FLOAT_EQ(data[index * 4 + 1], expected_value); | 
					
						
							|  |  |  |     EXPECT_FLOAT_EQ(data[index * 4 + 2], expected_value); | 
					
						
							|  |  |  |     EXPECT_FLOAT_EQ(data[index * 4 + 3], expected_value); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Cleanup. */ | 
					
						
							|  |  |  |   GPU_shader_unbind(); | 
					
						
							|  |  |  |   GPU_vertbuf_discard(vbo); | 
					
						
							|  |  |  |   GPU_shader_free(shader); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-06-28 08:28:56 +02:00
										 |  |  | GPU_TEST(gpu_shader_compute_vbo) | 
					
						
							| 
									
										
										
										
											2021-05-26 16:49:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-28 08:28:56 +02:00
										 |  |  | static void test_gpu_shader_compute_ibo() | 
					
						
							| 
									
										
										
										
											2021-05-26 16:49:17 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!GPU_compute_shader_support()) { | 
					
						
							|  |  |  |     /* We can't test as a the platform does not support compute shaders. */ | 
					
						
							|  |  |  |     std::cout << "Skipping compute shader test: platform not supported"; | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   static constexpr uint SIZE = 128; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Build compute shader. */ | 
					
						
							|  |  |  |   const char *compute_glsl = R"( | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | layout(local_size_x = 1) in; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | layout(std430, binding = 1) writeonly buffer outputIboData | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   uint out_indexes[]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void main() { | 
					
						
							|  |  |  |   uint store_index = int(gl_GlobalInvocationID.x); | 
					
						
							|  |  |  |   out_indexes[store_index] = store_index; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | )"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPUShader *shader = GPU_shader_create_compute( | 
					
						
							|  |  |  |       compute_glsl, nullptr, nullptr, "gpu_shader_compute_vbo"); | 
					
						
							|  |  |  |   EXPECT_NE(shader, nullptr); | 
					
						
							|  |  |  |   GPU_shader_bind(shader); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Construct IBO. */ | 
					
						
							|  |  |  |   GPUIndexBuf *ibo = GPU_indexbuf_build_on_device(SIZE); | 
					
						
							|  |  |  |   GPU_indexbuf_bind_as_ssbo(ibo, GPU_shader_get_ssbo(shader, "outputIboData")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Dispatch compute task. */ | 
					
						
							|  |  |  |   GPU_compute_dispatch(shader, SIZE, 1, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Check if compute has been done. */ | 
					
						
							|  |  |  |   GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Download the index buffer. */ | 
					
						
							|  |  |  |   const uint32_t *data = GPU_indexbuf_read(ibo); | 
					
						
							|  |  |  |   ASSERT_NE(data, nullptr); | 
					
						
							|  |  |  |   for (int index = 0; index < SIZE; index++) { | 
					
						
							|  |  |  |     uint32_t expected = index; | 
					
						
							|  |  |  |     EXPECT_EQ(data[index], expected); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Cleanup. */ | 
					
						
							|  |  |  |   GPU_shader_unbind(); | 
					
						
							|  |  |  |   GPU_indexbuf_discard(ibo); | 
					
						
							|  |  |  |   GPU_shader_free(shader); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-06-28 08:28:56 +02:00
										 |  |  | GPU_TEST(gpu_shader_compute_ibo) | 
					
						
							| 
									
										
										
										
											2021-05-26 16:49:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-28 08:28:56 +02:00
										 |  |  | static void test_gpu_shader_ssbo_binding() | 
					
						
							| 
									
										
										
										
											2021-05-26 16:49:17 +02:00
										 |  |  | { | 
					
						
							|  |  |  |   if (!GPU_compute_shader_support()) { | 
					
						
							|  |  |  |     /* We can't test as a the platform does not support compute shaders. */ | 
					
						
							|  |  |  |     std::cout << "Skipping compute shader test: platform not supported"; | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Build compute shader. */ | 
					
						
							|  |  |  |   const char *compute_glsl = R"( | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | layout(local_size_x = 1) in; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | layout(std430, binding = 0) buffer ssboBinding0 | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   int data0[]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | layout(std430, binding = 1) buffer ssboBinding1 | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   int data1[]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void main() { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | )"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   GPUShader *shader = GPU_shader_create_compute(compute_glsl, nullptr, nullptr, "gpu_shader_ssbo"); | 
					
						
							|  |  |  |   EXPECT_NE(shader, nullptr); | 
					
						
							|  |  |  |   GPU_shader_bind(shader); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   EXPECT_EQ(0, GPU_shader_get_ssbo(shader, "ssboBinding0")); | 
					
						
							|  |  |  |   EXPECT_EQ(1, GPU_shader_get_ssbo(shader, "ssboBinding1")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* Cleanup. */ | 
					
						
							|  |  |  |   GPU_shader_unbind(); | 
					
						
							|  |  |  |   GPU_shader_free(shader); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-06-28 08:28:56 +02:00
										 |  |  | GPU_TEST(gpu_shader_ssbo_binding) | 
					
						
							| 
									
										
										
										
											2021-05-26 16:49:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | }  // namespace blender::gpu::tests
 |