Blender V4.5
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
7#include "BLI_math_base.h"
9#include "GPU_batch.hh"
10#include "GPU_batch_presets.hh"
11#include "GPU_capabilities.hh"
12#include "GPU_compute.hh"
13#include "GPU_context.hh"
14#include "GPU_framebuffer.hh"
15#include "GPU_index_buffer.hh"
16#include "GPU_shader.hh"
17#include "GPU_shader_shared.hh"
18#include "GPU_state.hh"
19#include "GPU_texture.hh"
20#include "GPU_vertex_buffer.hh"
21#include "GPU_vertex_format.hh"
22
23#include "MEM_guardedalloc.h"
24
28#include "gpu_testing.hh"
29
30namespace blender::gpu::tests {
31
32using namespace blender::gpu::shader;
33
35{
36
37 static constexpr uint SIZE = 512;
38
39 /* Build compute shader. */
40 GPUShader *shader = GPU_shader_create_from_info_name("gpu_compute_2d_test");
41 EXPECT_NE(shader, nullptr);
42
43 /* Create texture to store result and attach to shader. */
44 GPUTexture *texture = GPU_texture_create_2d(
45 "gpu_shader_compute_2d", SIZE, SIZE, 1, GPU_RGBA32F, GPU_TEXTURE_USAGE_GENERAL, nullptr);
46 EXPECT_NE(texture, nullptr);
47
50
51 /* Dispatch compute task. */
53
54 /* Check if compute has been done. */
56 float *data = static_cast<float *>(GPU_texture_read(texture, GPU_DATA_FLOAT, 0));
57 EXPECT_NE(data, nullptr);
58 for (int index = 0; index < SIZE * SIZE; index++) {
59 EXPECT_FLOAT_EQ(data[index * 4 + 0], 1.0f);
60 EXPECT_FLOAT_EQ(data[index * 4 + 1], 0.5f);
61 EXPECT_FLOAT_EQ(data[index * 4 + 2], 0.2f);
62 EXPECT_FLOAT_EQ(data[index * 4 + 3], 1.0f);
63 }
65
66 /* Cleanup. */
71}
72GPU_TEST(shader_compute_2d)
73
75{
76 static constexpr uint SIZE = 10;
77
78 /* Build compute shader. */
79 GPUShader *shader = GPU_shader_create_from_info_name("gpu_compute_1d_test");
80 EXPECT_NE(shader, nullptr);
81
82 /* Construct Texture. */
83 GPUTexture *texture = GPU_texture_create_1d(
84 "gpu_shader_compute_1d", SIZE, 1, GPU_RGBA32F, GPU_TEXTURE_USAGE_GENERAL, nullptr);
85 EXPECT_NE(texture, nullptr);
86
89
90 /* Dispatch compute task. */
92
93 /* Check if compute has been done. */
95
96 /* Create texture to load back result. */
97 float *data = static_cast<float *>(GPU_texture_read(texture, GPU_DATA_FLOAT, 0));
98 EXPECT_NE(data, nullptr);
99 for (int index = 0; index < SIZE; index++) {
100 float expected_value = index;
101 EXPECT_FLOAT_EQ(data[index * 4 + 0], expected_value);
102 EXPECT_FLOAT_EQ(data[index * 4 + 1], expected_value);
103 EXPECT_FLOAT_EQ(data[index * 4 + 2], expected_value);
104 EXPECT_FLOAT_EQ(data[index * 4 + 3], expected_value);
105 }
107
108 /* Cleanup. */
113}
114GPU_TEST(shader_compute_1d)
115
117{
118 static constexpr uint SIZE = 128;
119
120 /* Build compute shader. */
121 GPUShader *shader = GPU_shader_create_from_info_name("gpu_compute_vbo_test");
122 EXPECT_NE(shader, nullptr);
124
125 /* Construct VBO. */
126 GPUVertFormat format = {0};
131
132 /* Dispatch compute task. */
134
135 /* Check if compute has been done. */
137
138 /* Download the vertex buffer. */
139 float data[SIZE * 4];
141 for (int index = 0; index < SIZE; index++) {
142 float expected_value = index;
143 EXPECT_FLOAT_EQ(data[index * 4 + 0], expected_value);
144 EXPECT_FLOAT_EQ(data[index * 4 + 1], expected_value);
145 EXPECT_FLOAT_EQ(data[index * 4 + 2], expected_value);
146 EXPECT_FLOAT_EQ(data[index * 4 + 3], expected_value);
147 }
148
149 /* Cleanup. */
153}
154GPU_TEST(shader_compute_vbo)
155
157{
158 static constexpr uint SIZE = 128;
159
160 /* Build compute shader. */
161 GPUShader *shader = GPU_shader_create_from_info_name("gpu_compute_ibo_test");
162 EXPECT_NE(shader, nullptr);
164
165 /* Construct IBO. */
168
169 /* Dispatch compute task. */
171
172 /* Check if compute has been done. */
174
175 /* Download the index buffer. */
176 uint32_t data[SIZE];
178 for (int index = 0; index < SIZE; index++) {
179 uint32_t expected = index;
180 EXPECT_EQ(data[index], expected);
181 }
182
183 /* Cleanup. */
187}
188GPU_TEST(shader_compute_ibo)
189
191{
192 static constexpr uint SIZE = 128;
193
194 /* Build compute shader. */
195 GPUShader *shader = GPU_shader_create_from_info_name("gpu_compute_ssbo_test");
196 EXPECT_NE(shader, nullptr);
198
199 /* Construct SSBO. */
200 GPUStorageBuf *ssbo = GPU_storagebuf_create_ex(
201 SIZE * sizeof(uint32_t), nullptr, GPU_USAGE_DEVICE_ONLY, __func__);
203
204 /* Dispatch compute task. */
206
207 /* Check if compute has been done. */
209
210 /* Download the storage buffer. */
211 uint32_t data[SIZE];
213 for (int index = 0; index < SIZE; index++) {
214 uint32_t expected = index * 4;
215 EXPECT_EQ(data[index], expected);
216 }
217
218 /* Cleanup. */
222}
223GPU_TEST(shader_compute_ssbo)
224
226{
227 /* Build compute shader. */
228 GPUShader *shader = GPU_shader_create_from_info_name("gpu_compute_ssbo_binding_test");
229 EXPECT_NE(shader, nullptr);
230
231 /* Perform tests. */
234
235 /* Cleanup. */
237}
238GPU_TEST(shader_ssbo_binding)
239
240static std::string print_test_data(const TestOutputRawData &raw, TestType type)
241{
242 std::stringstream ss;
243 switch (type) {
244 case TEST_TYPE_BOOL:
245 case TEST_TYPE_UINT:
246 ss << *reinterpret_cast<const uint *>(&raw);
247 break;
248 case TEST_TYPE_INT:
249 ss << *reinterpret_cast<const int *>(&raw);
250 break;
251 case TEST_TYPE_FLOAT:
252 ss << *reinterpret_cast<const float *>(&raw);
253 break;
254 case TEST_TYPE_IVEC2:
255 ss << *reinterpret_cast<const int2 *>(&raw);
256 break;
257 case TEST_TYPE_IVEC3:
258 ss << *reinterpret_cast<const int3 *>(&raw);
259 break;
260 case TEST_TYPE_IVEC4:
261 ss << *reinterpret_cast<const int4 *>(&raw);
262 break;
263 case TEST_TYPE_UVEC2:
264 ss << *reinterpret_cast<const uint2 *>(&raw);
265 break;
266 case TEST_TYPE_UVEC3:
267 ss << *reinterpret_cast<const uint3 *>(&raw);
268 break;
269 case TEST_TYPE_UVEC4:
270 ss << *reinterpret_cast<const uint4 *>(&raw);
271 break;
272 case TEST_TYPE_VEC2:
273 ss << *reinterpret_cast<const float2 *>(&raw);
274 break;
275 case TEST_TYPE_VEC3:
276 ss << *reinterpret_cast<const float3 *>(&raw);
277 break;
278 case TEST_TYPE_VEC4:
279 ss << *reinterpret_cast<const float4 *>(&raw);
280 break;
281 case TEST_TYPE_MAT2X2:
282 ss << *reinterpret_cast<const float2x2 *>(&raw);
283 break;
284 case TEST_TYPE_MAT2X3:
285 ss << *reinterpret_cast<const float2x3 *>(&raw);
286 break;
287 case TEST_TYPE_MAT2X4:
288 ss << *reinterpret_cast<const float2x4 *>(&raw);
289 break;
290 case TEST_TYPE_MAT3X2:
291 ss << *reinterpret_cast<const float3x2 *>(&raw);
292 break;
293 case TEST_TYPE_MAT3X3:
294 ss << *reinterpret_cast<const float3x3 *>(&raw);
295 break;
296 case TEST_TYPE_MAT3X4:
297 ss << *reinterpret_cast<const float3x4 *>(&raw);
298 break;
299 case TEST_TYPE_MAT4X2:
300 ss << *reinterpret_cast<const float4x2 *>(&raw);
301 break;
302 case TEST_TYPE_MAT4X3:
303 ss << *reinterpret_cast<const float4x3 *>(&raw);
304 break;
305 case TEST_TYPE_MAT4X4:
306 ss << *reinterpret_cast<const float4x4 *>(&raw);
307 break;
308 default:
309 ss << *reinterpret_cast<const MatBase<uint, 4, 4> *>(&raw);
310 break;
311 }
312 return ss.str();
313}
314
316{
317 /* Start at line one like the line report scheme. */
318 int64_t line = 1;
319 int64_t last_pos = 0;
320 int64_t pos = 0;
321 while ((pos = test_src.find('\n', pos)) != std::string::npos) {
322 if (line == test_line) {
323 return test_src.substr(last_pos, pos - last_pos);
324 }
325 pos += 1; /* Skip newline */
326 last_pos = pos;
327 line++;
328 }
329 return "";
330}
331
332static void gpu_shader_lib_test(const char *test_src_name, const char *additional_info = nullptr)
333{
334 using namespace shader;
335
337
338 ShaderCreateInfo create_info(test_src_name);
339 create_info.fragment_source(test_src_name);
340 create_info.additional_info("gpu_shader_test");
341 if (additional_info) {
342 create_info.additional_info(additional_info);
343 }
344
345 StringRefNull test_src = gpu_shader_dependency_get_source(test_src_name);
346
348 reinterpret_cast<GPUShaderCreateInfo *>(&create_info));
349
350 int test_count = 0;
351 /* Count tests. */
352 int64_t pos = 0;
353 StringRefNull target = "EXPECT_";
354 while ((pos = test_src.find(target, pos)) != std::string::npos) {
355 test_count++;
356 pos += sizeof("EXPECT_");
357 }
358
359 int test_output_px_len = divide_ceil_u(sizeof(TestOutput), 4 * 4);
360
362 GPUTexture *tex = GPU_texture_create_2d(
363 "tx", test_output_px_len, test_count, 1, GPU_RGBA32UI, usage, nullptr);
364 GPUFrameBuffer *fb = GPU_framebuffer_create("test_fb");
367
368 /* TODO(fclem): remove this boilerplate. */
374
376 GPU_batch_draw_advanced(batch, 0, 3, 0, 1);
377
379
380 GPU_finish();
381
383 Span<TestOutput> tests(test_data, test_count);
384
385 for (const TestOutput &test : tests) {
386 if (ELEM(test.status, TEST_STATUS_NONE, TEST_STATUS_PASSED)) {
387 continue;
388 }
389 if (test.status == TEST_STATUS_FAILED) {
390 ADD_FAILURE_AT(test_src_name, test.line)
391 << "Value of: " << print_test_line(test_src, test.line) << "\n"
392 << " Actual: " << print_test_data(test.expect, TestType(test.type)) << "\n"
393 << "Expected: " << print_test_data(test.result, TestType(test.type)) << "\n";
394 }
395 else {
397 }
398 }
399
401
402 /* Cleanup. */
406 GPU_texture_free(tex);
407
409}
410
411static void test_math_lib()
412{
413 gpu_shader_lib_test("gpu_math_test.glsl");
414}
415GPU_TEST(math_lib)
416
417static void test_eevee_lib()
418{
419 /* TODO(fclem): Not passing currently. Need to be updated. */
420 // gpu_shader_lib_test("eevee_shadow_test.glsl", "eevee_shared");
421 gpu_shader_lib_test("eevee_occupancy_test.glsl");
422 gpu_shader_lib_test("eevee_horizon_scan_test.glsl");
423#ifndef __APPLE__ /* PSOs fail to compile on Mac. Try to port them to compute shader to see if it \
424 * fixes the issue. */
425 gpu_shader_lib_test("eevee_gbuffer_normal_test.glsl", "eevee_shared");
426 gpu_shader_lib_test("eevee_gbuffer_closure_test.glsl", "eevee_shared");
427#endif
428}
429GPU_TEST(eevee_lib)
430
431} // namespace blender::gpu::tests
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
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:51
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, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
@ GPU_BATCH_OWNS_VBO
Definition GPU_batch.hh:41
void GPU_compute_dispatch(GPUShader *shader, uint groups_x_len, uint groups_y_len, uint groups_z_len, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
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_free(GPUFrameBuffer *fb)
void GPU_framebuffer_bind(GPUFrameBuffer *fb)
#define GPU_framebuffer_ensure_config(_fb,...)
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)
void GPU_shader_bind(GPUShader *shader, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
int GPU_shader_get_ssbo_binding(GPUShader *shader, const char *name)
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:385
void GPU_finish()
Definition gpu_state.cc:310
@ 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_RGBA32F
@ 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 *, blender::StringRef name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
@ GPU_COMP_U32
Read Guarded memory(de)allocation.
BMesh const char void * data
long long int int64_t
constexpr int64_t find(char c, int64_t pos=0) const
constexpr StringRef substr(int64_t start, int64_t size) const
static float verts[][3]
uint pos
struct @064345207361167251075330302113175271221317160336::@113254110077376341056327177062323111323010325277 batch
TEX_TEMPLATE DataVec texture(T, FltCoord, float=0.0f) RET
#define GPU_TEST(test_name)
BLI_INLINE float fb(float length, float L)
format
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
StringRefNull gpu_shader_dependency_get_source(const StringRefNull shader_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()
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)