Files
test/source/blender/gpu/tests/storage_buffer_test.cc
Mattias Fredriksson 407dcb39d4 Tests: EXPECT_EQ_SPAN utility macro
Replaces pointer based EXPECT_EQ_ARRAY with EXPECT_EQ_SPAN in most cases
as they already used spans (or span compatible datastructures).
Currently EXPECT_EQ_ARRAY only takes in one size variable and doesn't
compare the  number of elements between arguments (requiring an
additional line to do so).

This should make the code cleaner and safer. Goal is also to promote
the use Spans in new test code.

Pull Request: https://projects.blender.org/blender/blender/pulls/140340
2025-06-16 20:31:00 +02:00

209 lines
5.5 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: Apache-2.0 */
#include "testing/testing.h"
#include "GPU_storage_buffer.hh"
#include "BLI_math_vector.hh"
#include "BLI_vector.hh"
#include "gpu_testing.hh"
namespace blender::gpu::tests {
constexpr size_t SIZE = 128;
constexpr size_t SIZE_IN_BYTES = SIZE * sizeof(int);
static Vector<int32_t> test_data()
{
Vector<int32_t> data;
for (int i : IndexRange(SIZE)) {
data.append(i);
}
return data;
}
static void test_storage_buffer_create_update_read()
{
GPUStorageBuf *ssbo = GPU_storagebuf_create_ex(
SIZE_IN_BYTES, nullptr, GPU_USAGE_STATIC, __func__);
EXPECT_NE(ssbo, nullptr);
/* Upload some dummy data. */
const Vector<int32_t> data = test_data();
GPU_storagebuf_update(ssbo, data.data());
/* Read back data from SSBO. */
Vector<int32_t> read_data;
read_data.resize(SIZE, 0);
GPU_storagebuf_read(ssbo, read_data.data());
/* Check if data is the same. */
for (int i : IndexRange(SIZE)) {
EXPECT_EQ(data[i], read_data[i]);
}
GPU_storagebuf_free(ssbo);
}
GPU_TEST(storage_buffer_create_update_read);
static void test_storage_buffer_clear_zero()
{
GPUStorageBuf *ssbo = GPU_storagebuf_create_ex(
SIZE_IN_BYTES, nullptr, GPU_USAGE_STATIC, __func__);
EXPECT_NE(ssbo, nullptr);
/* Upload some dummy data. */
const Vector<int32_t> data = test_data();
GPU_storagebuf_update(ssbo, data.data());
GPU_storagebuf_clear_to_zero(ssbo);
/* Read back data from SSBO. */
Vector<int32_t> read_data;
read_data.resize(SIZE, 0);
GPU_storagebuf_read(ssbo, read_data.data());
/* Check if data is the same. */
for (int i : IndexRange(SIZE)) {
EXPECT_EQ(0, read_data[i]);
}
GPU_storagebuf_free(ssbo);
}
GPU_TEST(storage_buffer_clear_zero);
static void test_storage_buffer_clear()
{
GPUStorageBuf *ssbo = GPU_storagebuf_create_ex(
SIZE_IN_BYTES, nullptr, GPU_USAGE_STATIC, __func__);
EXPECT_NE(ssbo, nullptr);
GPU_storagebuf_clear(ssbo, 157255);
/* Read back data from SSBO. */
Vector<int32_t> read_data;
read_data.resize(SIZE, 0);
GPU_storagebuf_read(ssbo, read_data.data());
/* Check if datatest_ is the same. */
for (int i : IndexRange(SIZE)) {
EXPECT_EQ(157255, read_data[i]);
}
GPU_storagebuf_free(ssbo);
}
GPU_TEST(storage_buffer_clear);
static void test_storage_buffer_clear_byte_pattern()
{
GPUStorageBuf *ssbo = GPU_storagebuf_create_ex(
SIZE_IN_BYTES, nullptr, GPU_USAGE_STATIC, __func__);
EXPECT_NE(ssbo, nullptr);
/* Tests a different clear command on Metal. */
GPU_storagebuf_clear(ssbo, 0xFCFCFCFCu);
/* Read back data from SSBO. */
Vector<int32_t> read_data;
read_data.resize(SIZE, 0);
GPU_storagebuf_read(ssbo, read_data.data());
/* Check if datatest_ is the same. */
for (int i : IndexRange(SIZE)) {
EXPECT_EQ(0xFCFCFCFCu, read_data[i]);
}
GPU_storagebuf_free(ssbo);
}
GPU_TEST(storage_buffer_clear_byte_pattern);
static void test_storage_buffer_copy_from_vertex_buffer()
{
GPUStorageBuf *ssbo = GPU_storagebuf_create_ex(
SIZE_IN_BYTES, nullptr, GPU_USAGE_STATIC, __func__);
EXPECT_NE(ssbo, nullptr);
/* Create vertex buffer. */
GPUVertFormat format = {0};
GPU_vertformat_attr_add(&format, "pos", gpu::VertAttrType::SFLOAT_32_32);
GPU_vertformat_attr_add(&format, "color", gpu::VertAttrType::SFLOAT_32_32_32_32);
VertBuf *vbo = GPU_vertbuf_create_with_format(format);
GPU_vertbuf_data_alloc(*vbo, 4);
struct Vert {
float2 pos;
float4 color;
};
Vert data[4] = {
{float2(-1.0, -1.0), float4(0.0, 0.0, 0.0, 1.0)},
{float2(1.0, -1.0), float4(1.0, 0.0, 0.0, 1.0)},
{float2(1.0, 1.0), float4(1.0, 1.0, 0.0, 1.0)},
{float2(-1.0, 1.0), float4(0.0, 1.0, 0.0, 1.0)},
};
for (int i : IndexRange(4)) {
GPU_vertbuf_vert_set(vbo, i, &data[i]);
}
Span<float> expected_data(static_cast<float *>(static_cast<void *>(&data)), 24);
Vector<float> read_data;
read_data.resize(SIZE, 0);
/* Copy vertex buffer to storage buffer. */
{
GPU_storagebuf_clear_to_zero(ssbo);
GPU_storagebuf_copy_sub_from_vertbuf(ssbo, vbo, 0, 0, sizeof(data));
/* Validate content of SSBO. */
GPU_storagebuf_read(ssbo, read_data.data());
EXPECT_EQ_SPAN(expected_data, read_data);
for (int i : IndexRange(24, SIZE - 24)) {
EXPECT_EQ(0.0, read_data[i]);
}
}
/* Copy vertex buffer to storage buffer with 16 bytes of offset. */
{
GPU_storagebuf_clear_to_zero(ssbo);
GPU_storagebuf_copy_sub_from_vertbuf(ssbo, vbo, 16, 0, sizeof(data));
/* Validate content of SSBO. */
GPU_storagebuf_read(ssbo, read_data.data());
for (int i : IndexRange(4)) {
EXPECT_EQ(0.0, read_data[i]);
}
EXPECT_EQ_SPAN(expected_data, read_data.as_span().slice(4, 24));
for (int i : IndexRange(28, SIZE - 28)) {
EXPECT_EQ(0.0, read_data[i]);
}
}
/* Partially Copy vertex buffer to storage buffer with 16 bytes of offset. */
{
GPU_storagebuf_clear_to_zero(ssbo);
GPU_storagebuf_copy_sub_from_vertbuf(ssbo, vbo, 16, sizeof(Vert), sizeof(data) / 2);
/* Validate content of SSBO. */
GPU_storagebuf_read(ssbo, read_data.data());
for (int i : IndexRange(4)) {
EXPECT_EQ(0.0, read_data[i]);
}
EXPECT_EQ_SPAN(expected_data.slice(6, 12), read_data.as_span().slice(4, 12));
for (int i : IndexRange(16, SIZE - 16)) {
EXPECT_EQ(0.0, read_data[i]);
}
}
GPU_vertbuf_discard(vbo);
GPU_storagebuf_free(ssbo);
}
GPU_TEST(storage_buffer_copy_from_vertex_buffer);
} // namespace blender::gpu::tests