In preparation of supporting vulkan. Draw/GPU tests should use GPU_TEST or DRAW_TEST macros. These macros will run the test on available drawing context backends like OpenGL or Vulkan. As in master there is only an OpenGL backend nothing changed.
307 lines
8.0 KiB
C++
307 lines
8.0 KiB
C++
/* Apache License, Version 2.0 */
|
|
|
|
#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 {
|
|
|
|
static void test_gpu_shader_compute_2d()
|
|
{
|
|
|
|
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);
|
|
}
|
|
GPU_TEST(gpu_shader_compute_2d)
|
|
|
|
static void test_gpu_shader_compute_1d()
|
|
{
|
|
|
|
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. */
|
|
GPUTexture *texture = GPU_texture_create_1d("gpu_shader_compute_1d", SIZE, 0, GPU_RGBA32F, NULL);
|
|
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);
|
|
}
|
|
GPU_TEST(gpu_shader_compute_1d)
|
|
|
|
static void test_gpu_shader_compute_vbo()
|
|
{
|
|
|
|
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);
|
|
}
|
|
GPU_TEST(gpu_shader_compute_vbo)
|
|
|
|
static void test_gpu_shader_compute_ibo()
|
|
{
|
|
|
|
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);
|
|
}
|
|
GPU_TEST(gpu_shader_compute_ibo)
|
|
|
|
static void test_gpu_shader_ssbo_binding()
|
|
{
|
|
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);
|
|
}
|
|
GPU_TEST(gpu_shader_ssbo_binding)
|
|
|
|
} // namespace blender::gpu::tests
|