Blender V4.3
shader_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "testing/testing.h"
6
8#include "GPU_batch.hh"
10#include "GPU_capabilities.hh"
11#include "GPU_compute.hh"
12#include "GPU_context.hh"
13#include "GPU_framebuffer.hh"
14#include "GPU_index_buffer.hh"
15#include "GPU_shader.hh"
16#include "GPU_shader_shared.hh"
17#include "GPU_texture.hh"
18#include "GPU_vertex_buffer.hh"
19#include "GPU_vertex_format.hh"
20
21#include "MEM_guardedalloc.h"
22
26#include "gpu_testing.hh"
27
28namespace blender::gpu::tests {
29
30using namespace blender::gpu::shader;
31
33{
34
35 static constexpr uint SIZE = 512;
36
37 /* Build compute shader. */
38 GPUShader *shader = GPU_shader_create_from_info_name("gpu_compute_2d_test");
39 EXPECT_NE(shader, nullptr);
40
41 /* Create texture to store result and attach to shader. */
42 GPUTexture *texture = GPU_texture_create_2d(
43 "gpu_shader_compute_2d", SIZE, SIZE, 1, GPU_RGBA32F, GPU_TEXTURE_USAGE_GENERAL, nullptr);
44 EXPECT_NE(texture, nullptr);
45
46 GPU_shader_bind(shader);
47 GPU_texture_image_bind(texture, GPU_shader_get_sampler_binding(shader, "img_output"));
48
49 /* Dispatch compute task. */
50 GPU_compute_dispatch(shader, SIZE, SIZE, 1);
51
52 /* Check if compute has been done. */
54 float *data = static_cast<float *>(GPU_texture_read(texture, GPU_DATA_FLOAT, 0));
55 EXPECT_NE(data, nullptr);
56 for (int index = 0; index < SIZE * SIZE; index++) {
57 EXPECT_FLOAT_EQ(data[index * 4 + 0], 1.0f);
58 EXPECT_FLOAT_EQ(data[index * 4 + 1], 0.5f);
59 EXPECT_FLOAT_EQ(data[index * 4 + 2], 0.2f);
60 EXPECT_FLOAT_EQ(data[index * 4 + 3], 1.0f);
61 }
62 MEM_freeN(data);
63
64 /* Cleanup. */
66 GPU_texture_unbind(texture);
67 GPU_texture_free(texture);
68 GPU_shader_free(shader);
69}
70GPU_TEST(shader_compute_2d)
71
73{
74 static constexpr uint SIZE = 10;
75
76 /* Build compute shader. */
77 GPUShader *shader = GPU_shader_create_from_info_name("gpu_compute_1d_test");
78 EXPECT_NE(shader, nullptr);
79
80 /* Construct Texture. */
81 GPUTexture *texture = GPU_texture_create_1d(
82 "gpu_shader_compute_1d", SIZE, 1, GPU_RGBA32F, GPU_TEXTURE_USAGE_GENERAL, nullptr);
83 EXPECT_NE(texture, nullptr);
84
85 GPU_shader_bind(shader);
86 GPU_texture_image_bind(texture, GPU_shader_get_sampler_binding(shader, "img_output"));
87
88 /* Dispatch compute task. */
89 GPU_compute_dispatch(shader, SIZE, 1, 1);
90
91 /* Check if compute has been done. */
93
94 /* Create texture to load back result. */
95 float *data = static_cast<float *>(GPU_texture_read(texture, GPU_DATA_FLOAT, 0));
96 EXPECT_NE(data, nullptr);
97 for (int index = 0; index < SIZE; index++) {
98 float expected_value = index;
99 EXPECT_FLOAT_EQ(data[index * 4 + 0], expected_value);
100 EXPECT_FLOAT_EQ(data[index * 4 + 1], expected_value);
101 EXPECT_FLOAT_EQ(data[index * 4 + 2], expected_value);
102 EXPECT_FLOAT_EQ(data[index * 4 + 3], expected_value);
103 }
104 MEM_freeN(data);
105
106 /* Cleanup. */
108 GPU_texture_unbind(texture);
109 GPU_texture_free(texture);
110 GPU_shader_free(shader);
111}
112GPU_TEST(shader_compute_1d)
113
115{
116 static constexpr uint SIZE = 128;
117
118 /* Build compute shader. */
119 GPUShader *shader = GPU_shader_create_from_info_name("gpu_compute_vbo_test");
120 EXPECT_NE(shader, nullptr);
121 GPU_shader_bind(shader);
122
123 /* Construct VBO. */
124 GPUVertFormat format = {0};
128 GPU_vertbuf_bind_as_ssbo(vbo, GPU_shader_get_ssbo_binding(shader, "out_positions"));
129
130 /* Dispatch compute task. */
131 GPU_compute_dispatch(shader, SIZE, 1, 1);
132
133 /* Check if compute has been done. */
135
136 /* Download the vertex buffer. */
137 float data[SIZE * 4];
138 GPU_vertbuf_read(vbo, data);
139 for (int index = 0; index < SIZE; index++) {
140 float expected_value = index;
141 EXPECT_FLOAT_EQ(data[index * 4 + 0], expected_value);
142 EXPECT_FLOAT_EQ(data[index * 4 + 1], expected_value);
143 EXPECT_FLOAT_EQ(data[index * 4 + 2], expected_value);
144 EXPECT_FLOAT_EQ(data[index * 4 + 3], expected_value);
145 }
146
147 /* Cleanup. */
150 GPU_shader_free(shader);
151}
152GPU_TEST(shader_compute_vbo)
153
155{
156 static constexpr uint SIZE = 128;
157
158 /* Build compute shader. */
159 GPUShader *shader = GPU_shader_create_from_info_name("gpu_compute_ibo_test");
160 EXPECT_NE(shader, nullptr);
161 GPU_shader_bind(shader);
162
163 /* Construct IBO. */
165 GPU_indexbuf_bind_as_ssbo(ibo, GPU_shader_get_ssbo_binding(shader, "out_indices"));
166
167 /* Dispatch compute task. */
168 GPU_compute_dispatch(shader, SIZE, 1, 1);
169
170 /* Check if compute has been done. */
172
173 /* Download the index buffer. */
174 uint32_t data[SIZE];
175 GPU_indexbuf_read(ibo, data);
176 for (int index = 0; index < SIZE; index++) {
177 uint32_t expected = index;
178 EXPECT_EQ(data[index], expected);
179 }
180
181 /* Cleanup. */
184 GPU_shader_free(shader);
185}
186GPU_TEST(shader_compute_ibo)
187
189{
190 static constexpr uint SIZE = 128;
191
192 /* Build compute shader. */
193 GPUShader *shader = GPU_shader_create_from_info_name("gpu_compute_ssbo_test");
194 EXPECT_NE(shader, nullptr);
195 GPU_shader_bind(shader);
196
197 /* Construct SSBO. */
198 GPUStorageBuf *ssbo = GPU_storagebuf_create_ex(
199 SIZE * sizeof(uint32_t), nullptr, GPU_USAGE_DEVICE_ONLY, __func__);
200 GPU_storagebuf_bind(ssbo, GPU_shader_get_ssbo_binding(shader, "data_out"));
201
202 /* Dispatch compute task. */
203 GPU_compute_dispatch(shader, SIZE, 1, 1);
204
205 /* Check if compute has been done. */
207
208 /* Download the storage buffer. */
209 uint32_t data[SIZE];
210 GPU_storagebuf_read(ssbo, data);
211 for (int index = 0; index < SIZE; index++) {
212 uint32_t expected = index * 4;
213 EXPECT_EQ(data[index], expected);
214 }
215
216 /* Cleanup. */
219 GPU_shader_free(shader);
220}
221GPU_TEST(shader_compute_ssbo)
222
224{
225 /* Build compute shader. */
226 GPUShader *shader = GPU_shader_create_from_info_name("gpu_compute_ssbo_binding_test");
227 EXPECT_NE(shader, nullptr);
228
229 /* Perform tests. */
230 EXPECT_EQ(0, GPU_shader_get_ssbo_binding(shader, "data0"));
231 EXPECT_EQ(1, GPU_shader_get_ssbo_binding(shader, "data1"));
232
233 /* Cleanup. */
234 GPU_shader_free(shader);
235}
236GPU_TEST(shader_ssbo_binding)
237
238static std::string print_test_data(const TestOutputRawData &raw, TestType type)
239{
240 std::stringstream ss;
241 switch (type) {
242 case TEST_TYPE_BOOL:
243 case TEST_TYPE_UINT:
244 ss << *reinterpret_cast<const uint *>(&raw);
245 break;
246 case TEST_TYPE_INT:
247 ss << *reinterpret_cast<const int *>(&raw);
248 break;
249 case TEST_TYPE_FLOAT:
250 ss << *reinterpret_cast<const float *>(&raw);
251 break;
252 case TEST_TYPE_IVEC2:
253 ss << *reinterpret_cast<const int2 *>(&raw);
254 break;
255 case TEST_TYPE_IVEC3:
256 ss << *reinterpret_cast<const int3 *>(&raw);
257 break;
258 case TEST_TYPE_IVEC4:
259 ss << *reinterpret_cast<const int4 *>(&raw);
260 break;
261 case TEST_TYPE_UVEC2:
262 ss << *reinterpret_cast<const uint2 *>(&raw);
263 break;
264 case TEST_TYPE_UVEC3:
265 ss << *reinterpret_cast<const uint3 *>(&raw);
266 break;
267 case TEST_TYPE_UVEC4:
268 ss << *reinterpret_cast<const uint4 *>(&raw);
269 break;
270 case TEST_TYPE_VEC2:
271 ss << *reinterpret_cast<const float2 *>(&raw);
272 break;
273 case TEST_TYPE_VEC3:
274 ss << *reinterpret_cast<const float3 *>(&raw);
275 break;
276 case TEST_TYPE_VEC4:
277 ss << *reinterpret_cast<const float4 *>(&raw);
278 break;
279 case TEST_TYPE_MAT2X2:
280 ss << *reinterpret_cast<const float2x2 *>(&raw);
281 break;
282 case TEST_TYPE_MAT2X3:
283 ss << *reinterpret_cast<const float2x3 *>(&raw);
284 break;
285 case TEST_TYPE_MAT2X4:
286 ss << *reinterpret_cast<const float2x4 *>(&raw);
287 break;
288 case TEST_TYPE_MAT3X2:
289 ss << *reinterpret_cast<const float3x2 *>(&raw);
290 break;
291 case TEST_TYPE_MAT3X3:
292 ss << *reinterpret_cast<const float3x3 *>(&raw);
293 break;
294 case TEST_TYPE_MAT3X4:
295 ss << *reinterpret_cast<const float3x4 *>(&raw);
296 break;
297 case TEST_TYPE_MAT4X2:
298 ss << *reinterpret_cast<const float4x2 *>(&raw);
299 break;
300 case TEST_TYPE_MAT4X3:
301 ss << *reinterpret_cast<const float4x3 *>(&raw);
302 break;
303 case TEST_TYPE_MAT4X4:
304 ss << *reinterpret_cast<const float4x4 *>(&raw);
305 break;
306 default:
307 ss << *reinterpret_cast<const MatBase<uint, 4, 4> *>(&raw);
308 break;
309 }
310 return ss.str();
311}
312
314{
315 /* Start at line one like the line report scheme. */
316 int64_t line = 1;
317 int64_t last_pos = 0;
318 int64_t pos = 0;
319 while ((pos = test_src.find('\n', pos)) != std::string::npos) {
320 if (line == test_line) {
321 return test_src.substr(last_pos, pos - last_pos);
322 }
323 pos += 1; /* Skip newline */
324 last_pos = pos;
325 line++;
326 }
327 return "";
328}
329
330static void gpu_shader_lib_test(const char *test_src_name, const char *additional_info = nullptr)
331{
332 using namespace shader;
333
335
336 ShaderCreateInfo create_info(test_src_name);
337 create_info.fragment_source(test_src_name);
338 create_info.additional_info("gpu_shader_test");
339 if (additional_info) {
340 create_info.additional_info(additional_info);
341 }
342
343 StringRefNull test_src = gpu_shader_dependency_get_source(test_src_name);
344
346 reinterpret_cast<GPUShaderCreateInfo *>(&create_info));
347
348 int test_count = 0;
349 /* Count tests. */
350 int64_t pos = 0;
351 StringRefNull target = "EXPECT_";
352 while ((pos = test_src.find(target, pos)) != std::string::npos) {
353 test_count++;
354 pos += sizeof("EXPECT_");
355 }
356
357 int test_output_px_len = divide_ceil_u(sizeof(TestOutput), 4 * 4);
358
360 GPUTexture *tex = GPU_texture_create_2d(
361 "tx", test_output_px_len, test_count, 1, GPU_RGBA32UI, usage, nullptr);
362 GPUFrameBuffer *fb = GPU_framebuffer_create("test_fb");
365
366 /* TODO(fclem): remove this boilerplate. */
372
374 GPU_batch_draw_advanced(batch, 0, 3, 0, 1);
375
377
378 GPU_finish();
379
381 Span<TestOutput> tests(test_data, test_count);
382
383 for (const TestOutput &test : tests) {
384 if (ELEM(test.status, TEST_STATUS_NONE, TEST_STATUS_PASSED)) {
385 continue;
386 }
387 else if (test.status == TEST_STATUS_FAILED) {
388 ADD_FAILURE_AT(test_src_name, test.line)
389 << "Value of: " << print_test_line(test_src, test.line) << "\n"
390 << " Actual: " << print_test_data(test.expect, TestType(test.type)) << "\n"
391 << "Expected: " << print_test_data(test.result, TestType(test.type)) << "\n";
392 }
393 else {
395 }
396 }
397
399
400 /* Cleanup. */
402 GPU_shader_free(shader);
405
407}
408
409static void test_math_lib()
410{
411 gpu_shader_lib_test("gpu_math_test.glsl");
412}
413GPU_TEST(math_lib)
414
415static void test_eevee_lib()
416{
417 // gpu_shader_lib_test("eevee_shadow_test.glsl", "eevee_shared");
418 gpu_shader_lib_test("eevee_occupancy_test.glsl");
419 gpu_shader_lib_test("eevee_horizon_scan_test.glsl");
420 gpu_shader_lib_test("eevee_gbuffer_normal_test.glsl", "eevee_shared");
421 gpu_shader_lib_test("eevee_gbuffer_closure_test.glsl", "eevee_shared");
422}
423GPU_TEST(eevee_lib)
424
425} // namespace blender::gpu::tests
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
MINLINE uint divide_ceil_u(uint a, uint b)
unsigned int uint
#define ELEM(...)
blender::gpu::Batch * GPU_batch_create_ex(GPUPrimType primitive_type, blender::gpu::VertBuf *vertex_buf, blender::gpu::IndexBuf *index_buf, eGPUBatchFlag owns_flag)
Definition gpu_batch.cc:56
void GPU_batch_discard(blender::gpu::Batch *batch)
void GPU_batch_draw_advanced(blender::gpu::Batch *batch, int vertex_first, int vertex_count, int instance_first, int instance_count)
void GPU_batch_set_shader(blender::gpu::Batch *batch, GPUShader *shader)
@ GPU_BATCH_OWNS_VBO
Definition GPU_batch.hh:42
void GPU_compute_dispatch(GPUShader *shader, uint groups_x_len, uint groups_y_len, uint groups_z_len)
void GPU_render_end()
void GPU_render_begin()
GPUFrameBuffer * GPU_framebuffer_create(const char *name)
#define GPU_ATTACHMENT_TEXTURE(_texture)
#define GPU_ATTACHMENT_NONE
void GPU_framebuffer_bind(GPUFrameBuffer *framebuffer)
#define GPU_framebuffer_ensure_config(_fb,...)
void GPU_framebuffer_free(GPUFrameBuffer *framebuffer)
void GPU_indexbuf_discard(blender::gpu::IndexBuf *elem)
blender::gpu::IndexBuf * GPU_indexbuf_build_on_device(uint index_len)
void GPU_indexbuf_bind_as_ssbo(blender::gpu::IndexBuf *elem, int binding)
void GPU_indexbuf_read(blender::gpu::IndexBuf *elem, uint32_t *data)
@ GPU_PRIM_TRIS
int GPU_shader_get_sampler_binding(GPUShader *shader, const char *name)
GPUShader * GPU_shader_create_from_info_name(const char *info_name)
int GPU_shader_get_ssbo_binding(GPUShader *shader, const char *name)
void GPU_shader_bind(GPUShader *shader)
GPUShader * GPU_shader_create_from_info(const GPUShaderCreateInfo *_info)
void GPU_shader_free(GPUShader *shader)
void GPU_shader_unbind()
@ TEST_TYPE_IVEC2
@ TEST_TYPE_UINT
@ TEST_TYPE_INT
@ TEST_TYPE_IVEC4
@ TEST_TYPE_MAT2X2
@ TEST_TYPE_VEC2
@ TEST_TYPE_FLOAT
@ TEST_TYPE_VEC3
@ TEST_TYPE_BOOL
@ TEST_TYPE_IVEC3
@ TEST_TYPE_UVEC3
@ TEST_TYPE_MAT3X3
@ TEST_TYPE_UVEC2
@ TEST_TYPE_MAT4X4
@ TEST_TYPE_MAT2X3
@ TEST_TYPE_MAT4X3
@ TEST_TYPE_MAT3X2
@ TEST_TYPE_MAT4X2
@ TEST_TYPE_UVEC4
@ TEST_TYPE_MAT2X4
@ TEST_TYPE_VEC4
@ TEST_TYPE_MAT3X4
@ TEST_STATUS_NONE
@ TEST_STATUS_PASSED
@ TEST_STATUS_FAILED
void GPU_memory_barrier(eGPUBarrier barrier)
Definition gpu_state.cc:374
void GPU_finish()
Definition gpu_state.cc:299
@ GPU_BARRIER_BUFFER_UPDATE
Definition GPU_state.hh:56
@ GPU_BARRIER_TEXTURE_UPDATE
Definition GPU_state.hh:39
void GPU_storagebuf_bind(GPUStorageBuf *ssbo, int slot)
GPUStorageBuf * GPU_storagebuf_create_ex(size_t size, const void *data, GPUUsageType usage, const char *name)
void GPU_storagebuf_free(GPUStorageBuf *ssbo)
void GPU_storagebuf_read(GPUStorageBuf *ssbo, void *data)
GPUTexture * GPU_texture_create_2d(const char *name, int width, int height, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const float *data)
GPUTexture * GPU_texture_create_1d(const char *name, int width, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const float *data)
void GPU_texture_free(GPUTexture *texture)
void * GPU_texture_read(GPUTexture *texture, eGPUDataFormat data_format, int mip_level)
void GPU_texture_unbind(GPUTexture *texture)
@ GPU_DATA_UINT
@ GPU_DATA_FLOAT
eGPUTextureUsage
@ GPU_TEXTURE_USAGE_HOST_READ
@ GPU_TEXTURE_USAGE_ATTACHMENT
@ GPU_TEXTURE_USAGE_GENERAL
void GPU_texture_image_bind(GPUTexture *texture, int unit)
@ GPU_RGBA32UI
#define GPU_vertbuf_create_with_format(format)
blender::gpu::VertBuf * GPU_vertbuf_create_with_format_ex(const GPUVertFormat &format, GPUUsageType usage)
void GPU_vertbuf_read(const blender::gpu::VertBuf *verts, void *data)
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
void GPU_vertbuf_bind_as_ssbo(blender::gpu::VertBuf *verts, int binding)
void GPU_vertbuf_discard(blender::gpu::VertBuf *)
@ GPU_USAGE_DEVICE_ONLY
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
@ GPU_COMP_U32
Read Guarded memory(de)allocation.
struct GPUShader GPUShader
constexpr int64_t find(char c, int64_t pos=0) const
constexpr StringRef substr(int64_t start, int64_t size) const
local_group_size(16, 16) .push_constant(Type additional_info("compositor_box_mask_shared") .define("CMP_NODE_MASKTYPE_ADD") .do_static_compilation(true)
additional_info("compositor_sum_float_shared") .push_constant(Type additional_info("compositor_sum_float_shared") .push_constant(Type GPU_RGBA32F
static float verts[][3]
struct @620::@622 batch
#define GPU_TEST(test_name)
BLI_INLINE float fb(float length, float L)
format
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
StringRefNull gpu_shader_dependency_get_source(const StringRefNull source_name)
static void test_shader_compute_2d()
static void test_shader_compute_ssbo()
static std::string print_test_data(const TestOutputRawData &raw, TestType type)
static Vector< int32_t > test_data()
static void test_eevee_lib()
static void test_shader_compute_vbo()
static void gpu_shader_lib_test(const char *test_src_name, const char *additional_info=nullptr)
static void test_math_lib()
static void test_shader_ssbo_binding()
static void test_shader_compute_1d()
static StringRef print_test_line(StringRefNull test_src, int64_t test_line)
static void test_shader_compute_ibo()
unsigned int uint32_t
Definition stdint.h:80
__int64 int64_t
Definition stdint.h:89
Describe inputs & outputs, stage interfaces, resources and sources of a shader. If all data is correc...
Self & fragment_source(StringRefNull filename)
Self & additional_info(StringRefNull info_name)