Add Chromium-only Blender WebEngine parity work
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "GPU_capabilities.hh"
|
||||
#include "GPU_compute.hh"
|
||||
#include "GPU_state.hh"
|
||||
#include "GPU_vertex_buffer.hh"
|
||||
#include "GPU_vertex_format.hh"
|
||||
|
||||
#include "BLI_math_vector_types.hh"
|
||||
|
||||
#include "gpu_testing.hh"
|
||||
|
||||
namespace blender::gpu::tests {
|
||||
|
||||
static void test_buffer_texture()
|
||||
{
|
||||
/* Build compute shader. */
|
||||
gpu::Shader *shader = GPU_shader_create_from_info_name("gpu_buffer_texture_test");
|
||||
EXPECT_NE(shader, nullptr);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
/* Vertex buffer. */
|
||||
GPUVertFormat format = {};
|
||||
uint value_pos = GPU_vertformat_attr_add(&format, "value", gpu::VertAttrType::SFLOAT_32);
|
||||
VertBuf *vertex_buffer = GPU_vertbuf_create_with_format_ex(format,
|
||||
GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY);
|
||||
float4 value = float4(42.42, 23.23, 1.0, -1.0);
|
||||
GPU_vertbuf_data_alloc(*vertex_buffer, 4);
|
||||
GPU_vertbuf_attr_fill(vertex_buffer, value_pos, &value);
|
||||
GPU_vertbuf_bind_as_texture(vertex_buffer,
|
||||
GPU_shader_get_sampler_binding(shader, "bufferTexture"));
|
||||
|
||||
/* Construct SSBO. */
|
||||
StorageBuf *ssbo = GPU_storagebuf_create_ex(
|
||||
4 * sizeof(float), nullptr, GPU_USAGE_STATIC, __func__);
|
||||
GPU_storagebuf_bind(ssbo, GPU_shader_get_ssbo_binding(shader, "data_out"));
|
||||
|
||||
/* Dispatch compute task. */
|
||||
GPU_compute_dispatch(shader, 4, 1, 1);
|
||||
|
||||
/* Check if compute has been done. */
|
||||
GPU_memory_barrier(GPU_BARRIER_BUFFER_UPDATE);
|
||||
|
||||
/* Download the storage buffer. */
|
||||
float4 read_data;
|
||||
GPU_storagebuf_read(ssbo, read_data);
|
||||
EXPECT_EQ(read_data, value);
|
||||
|
||||
/* Cleanup. */
|
||||
GPU_shader_unbind();
|
||||
GPU_storagebuf_free(ssbo);
|
||||
GPU_vertbuf_discard(vertex_buffer);
|
||||
GPU_shader_free(shader);
|
||||
}
|
||||
|
||||
GPU_TEST(buffer_texture)
|
||||
|
||||
} // namespace blender::gpu::tests
|
||||
111
blender-5.2.0/source/blender/gpu/tests/compute_test.cc
Normal file
111
blender-5.2.0/source/blender/gpu/tests/compute_test.cc
Normal file
@@ -0,0 +1,111 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "gpu_testing.hh"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_math_vector_types.hh"
|
||||
|
||||
#include "GPU_capabilities.hh"
|
||||
#include "GPU_compute.hh"
|
||||
#include "GPU_state.hh"
|
||||
#include "GPU_storage_buffer.hh"
|
||||
#include "GPU_texture.hh"
|
||||
|
||||
namespace blender::gpu::tests {
|
||||
static void test_compute_direct()
|
||||
{
|
||||
static constexpr uint SIZE = 4;
|
||||
|
||||
/* Build compute shader. */
|
||||
gpu::Shader *shader = GPU_shader_create_from_info_name("gpu_compute_2d_test");
|
||||
EXPECT_NE(shader, nullptr);
|
||||
|
||||
/* Create texture to store result and attach to shader. */
|
||||
gpu::Texture *texture = GPU_texture_create_2d("gpu_shader_compute_2d",
|
||||
SIZE,
|
||||
SIZE,
|
||||
1,
|
||||
TextureFormat::SFLOAT_32_32_32_32,
|
||||
GPU_TEXTURE_USAGE_GENERAL,
|
||||
nullptr);
|
||||
EXPECT_NE(texture, nullptr);
|
||||
|
||||
GPU_shader_bind(shader);
|
||||
GPU_texture_image_bind(texture, GPU_shader_get_sampler_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_UPDATE);
|
||||
float4 *data = static_cast<float4 *>(GPU_texture_read(texture, GPU_DATA_FLOAT, 0));
|
||||
const float4 expected_result(1.0f, 0.5f, 0.2f, 1.0f);
|
||||
EXPECT_NE(data, nullptr);
|
||||
for (int index = 0; index < SIZE * SIZE; index++) {
|
||||
EXPECT_EQ(data[index], expected_result);
|
||||
}
|
||||
MEM_delete(data);
|
||||
|
||||
/* Cleanup. */
|
||||
GPU_shader_unbind();
|
||||
GPU_texture_unbind(texture);
|
||||
GPU_texture_free(texture);
|
||||
GPU_shader_free(shader);
|
||||
}
|
||||
GPU_TEST(compute_direct)
|
||||
|
||||
static void test_compute_indirect()
|
||||
{
|
||||
static constexpr uint SIZE = 4;
|
||||
|
||||
/* Build compute shader. */
|
||||
gpu::Shader *shader = GPU_shader_create_from_info_name("gpu_compute_2d_test");
|
||||
EXPECT_NE(shader, nullptr);
|
||||
|
||||
/* Create texture to store result and attach to shader. */
|
||||
gpu::Texture *texture = GPU_texture_create_2d("gpu_shader_compute_2d",
|
||||
SIZE,
|
||||
SIZE,
|
||||
1,
|
||||
TextureFormat::SFLOAT_32_32_32_32,
|
||||
GPU_TEXTURE_USAGE_GENERAL,
|
||||
nullptr);
|
||||
EXPECT_NE(texture, nullptr);
|
||||
GPU_texture_clear(texture, GPU_DATA_FLOAT, float4(0.0f));
|
||||
|
||||
GPU_shader_bind(shader);
|
||||
GPU_texture_image_bind(texture, GPU_shader_get_sampler_binding(shader, "img_output"));
|
||||
|
||||
/* Generate compute tasks. */
|
||||
uint4 commands[1] = {
|
||||
{SIZE, SIZE, 1, 0},
|
||||
};
|
||||
StorageBuf *compute_commands = GPU_storagebuf_create_ex(
|
||||
sizeof(commands), &commands, GPU_USAGE_STATIC, __func__);
|
||||
|
||||
/* Dispatch compute task. */
|
||||
GPU_compute_dispatch_indirect(shader, compute_commands);
|
||||
|
||||
/* Check if compute has been done. */
|
||||
GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE);
|
||||
float4 *data = static_cast<float4 *>(GPU_texture_read(texture, GPU_DATA_FLOAT, 0));
|
||||
const float4 expected_result(1.0f, 0.5f, 0.2f, 1.0f);
|
||||
EXPECT_NE(data, nullptr);
|
||||
for (int index = 0; index < SIZE * SIZE; index++) {
|
||||
EXPECT_EQ(data[index], expected_result);
|
||||
}
|
||||
MEM_delete(data);
|
||||
|
||||
/* Cleanup. */
|
||||
GPU_storagebuf_free(compute_commands);
|
||||
GPU_shader_unbind();
|
||||
GPU_texture_unbind(texture);
|
||||
GPU_texture_free(texture);
|
||||
GPU_shader_free(shader);
|
||||
}
|
||||
GPU_TEST(compute_indirect);
|
||||
|
||||
} // namespace blender::gpu::tests
|
||||
481
blender-5.2.0/source/blender/gpu/tests/framebuffer_test.cc
Normal file
481
blender-5.2.0/source/blender/gpu/tests/framebuffer_test.cc
Normal file
@@ -0,0 +1,481 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "GPU_batch.hh"
|
||||
#include "GPU_context.hh"
|
||||
#include "GPU_framebuffer.hh"
|
||||
#include "GPU_shader.hh"
|
||||
#include "GPU_state.hh"
|
||||
#include "GPU_vertex_buffer.hh"
|
||||
#include "GPU_vertex_format.hh"
|
||||
|
||||
#include "gpu_testing.hh"
|
||||
|
||||
#include "BLI_math_vector.hh"
|
||||
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
namespace blender::gpu::tests {
|
||||
|
||||
static void test_framebuffer_clear_color_single_attachment()
|
||||
{
|
||||
const int2 size(1, 1);
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ;
|
||||
gpu::Texture *texture = GPU_texture_create_2d(
|
||||
__func__, UNPACK2(size), 1, TextureFormat::SFLOAT_32_32_32_32, usage, nullptr);
|
||||
|
||||
gpu::FrameBuffer *framebuffer = GPU_framebuffer_create(__func__);
|
||||
GPU_framebuffer_ensure_config(&framebuffer,
|
||||
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(texture)});
|
||||
GPU_framebuffer_bind(framebuffer);
|
||||
|
||||
const float4 clear_color(0.1f, 0.2f, 0.5f, 1.0f);
|
||||
GPU_framebuffer_clear_color(framebuffer, double4(clear_color));
|
||||
GPU_finish();
|
||||
|
||||
float4 *read_data = static_cast<float4 *>(GPU_texture_read(texture, GPU_DATA_FLOAT, 0));
|
||||
for (float4 pixel_color : Span<float4>(read_data, size.x * size.y)) {
|
||||
EXPECT_EQ(clear_color, pixel_color);
|
||||
}
|
||||
MEM_delete(read_data);
|
||||
|
||||
GPU_framebuffer_free(framebuffer);
|
||||
GPU_texture_free(texture);
|
||||
}
|
||||
GPU_TEST(framebuffer_clear_color_single_attachment);
|
||||
|
||||
static void test_framebuffer_clear_color_multiple_attachments()
|
||||
{
|
||||
const int2 size(1, 1);
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ;
|
||||
gpu::Texture *texture1 = GPU_texture_create_2d(
|
||||
__func__, UNPACK2(size), 1, TextureFormat::SFLOAT_32_32_32_32, usage, nullptr);
|
||||
gpu::Texture *texture2 = GPU_texture_create_2d(
|
||||
__func__, UNPACK2(size), 1, TextureFormat::UINT_32_32_32_32, usage, nullptr);
|
||||
|
||||
gpu::FrameBuffer *framebuffer = GPU_framebuffer_create(__func__);
|
||||
GPU_framebuffer_ensure_config(
|
||||
&framebuffer,
|
||||
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(texture1), GPU_ATTACHMENT_TEXTURE(texture2)});
|
||||
GPU_framebuffer_bind(framebuffer);
|
||||
|
||||
const float4 clear_color(0.1f, 0.2f, 0.5f, 1.0f);
|
||||
GPU_framebuffer_clear_color(framebuffer, double4(clear_color));
|
||||
GPU_finish();
|
||||
|
||||
float4 *read_data1 = static_cast<float4 *>(GPU_texture_read(texture1, GPU_DATA_FLOAT, 0));
|
||||
for (float4 pixel_color : Span<float4>(read_data1, size.x * size.y)) {
|
||||
EXPECT_EQ(clear_color, pixel_color);
|
||||
}
|
||||
MEM_delete(read_data1);
|
||||
|
||||
uint4 *read_data2 = static_cast<uint4 *>(GPU_texture_read(texture2, GPU_DATA_UINT, 0));
|
||||
uint4 clear_color_uint(0, 0, 0, 1);
|
||||
for (uint4 pixel_color : Span<uint4>(read_data2, size.x * size.y)) {
|
||||
EXPECT_EQ(clear_color_uint, pixel_color);
|
||||
}
|
||||
MEM_delete(read_data2);
|
||||
|
||||
GPU_framebuffer_free(framebuffer);
|
||||
GPU_texture_free(texture1);
|
||||
GPU_texture_free(texture2);
|
||||
}
|
||||
GPU_TEST(framebuffer_clear_color_multiple_attachments);
|
||||
|
||||
static void test_framebuffer_clear_multiple_color_multiple_attachments()
|
||||
{
|
||||
const int2 size(1, 1);
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ;
|
||||
gpu::Texture *texture1 = GPU_texture_create_2d(
|
||||
__func__, UNPACK2(size), 1, TextureFormat::SFLOAT_32_32_32_32, usage, nullptr);
|
||||
gpu::Texture *texture2 = GPU_texture_create_2d(
|
||||
__func__, UNPACK2(size), 1, TextureFormat::SFLOAT_32_32_32_32, usage, nullptr);
|
||||
|
||||
gpu::FrameBuffer *framebuffer = GPU_framebuffer_create(__func__);
|
||||
GPU_framebuffer_ensure_config(
|
||||
&framebuffer,
|
||||
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(texture1), GPU_ATTACHMENT_TEXTURE(texture2)});
|
||||
GPU_framebuffer_bind(framebuffer);
|
||||
|
||||
const std::array<double4, 2> clear_color = {double4(0.1f, 0.2f, 0.5f, 1.0f),
|
||||
double4(0.5f, 0.2f, 0.1f, 1.0f)};
|
||||
GPU_framebuffer_multi_clear(framebuffer, clear_color);
|
||||
GPU_finish();
|
||||
|
||||
float4 *read_data1 = static_cast<float4 *>(GPU_texture_read(texture1, GPU_DATA_FLOAT, 0));
|
||||
for (float4 pixel_color : Span<float4>(read_data1, size.x * size.y)) {
|
||||
EXPECT_EQ(float4(clear_color[0]), pixel_color);
|
||||
}
|
||||
MEM_delete(read_data1);
|
||||
|
||||
float4 *read_data2 = static_cast<float4 *>(GPU_texture_read(texture2, GPU_DATA_FLOAT, 0));
|
||||
for (float4 pixel_color : Span<float4>(read_data2, size.x * size.y)) {
|
||||
EXPECT_EQ(float4(clear_color[1]), pixel_color);
|
||||
}
|
||||
MEM_delete(read_data2);
|
||||
|
||||
GPU_framebuffer_free(framebuffer);
|
||||
GPU_texture_free(texture1);
|
||||
GPU_texture_free(texture2);
|
||||
}
|
||||
GPU_TEST(framebuffer_clear_multiple_color_multiple_attachments);
|
||||
|
||||
static void test_framebuffer_clear_depth()
|
||||
{
|
||||
const int2 size(1, 1);
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ;
|
||||
gpu::Texture *texture = GPU_texture_create_2d(
|
||||
__func__, UNPACK2(size), 1, TextureFormat::SFLOAT_32_DEPTH, usage, nullptr);
|
||||
|
||||
gpu::FrameBuffer *framebuffer = GPU_framebuffer_create(__func__);
|
||||
GPU_framebuffer_ensure_config(&framebuffer, {GPU_ATTACHMENT_TEXTURE(texture)});
|
||||
GPU_framebuffer_bind(framebuffer);
|
||||
|
||||
const float clear_depth = 0.5f;
|
||||
GPU_framebuffer_clear_depth(framebuffer, clear_depth);
|
||||
GPU_finish();
|
||||
|
||||
float *read_data = static_cast<float *>(GPU_texture_read(texture, GPU_DATA_FLOAT, 0));
|
||||
for (float pixel_depth : Span<float>(read_data, size.x * size.y)) {
|
||||
EXPECT_EQ(clear_depth, pixel_depth);
|
||||
}
|
||||
MEM_delete(read_data);
|
||||
|
||||
GPU_framebuffer_free(framebuffer);
|
||||
GPU_texture_free(texture);
|
||||
}
|
||||
GPU_TEST(framebuffer_clear_depth);
|
||||
|
||||
#ifndef __APPLE__ /* Clearing with scissors is not supported on Metal. */
|
||||
|
||||
static void test_framebuffer_scissor_test()
|
||||
{
|
||||
const int2 size(2, 2);
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ;
|
||||
gpu::Texture *texture = GPU_texture_create_2d(
|
||||
__func__, UNPACK2(size), 1, TextureFormat::SFLOAT_32_32_32_32, usage, nullptr);
|
||||
|
||||
gpu::FrameBuffer *framebuffer = GPU_framebuffer_create(__func__);
|
||||
GPU_framebuffer_ensure_config(&framebuffer,
|
||||
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(texture)});
|
||||
GPU_framebuffer_bind(framebuffer);
|
||||
|
||||
const float4 color1(0.0f);
|
||||
const float4 color2(0.5f);
|
||||
const float4 color3(1.0f);
|
||||
GPU_framebuffer_clear_color(framebuffer, double4(color1));
|
||||
|
||||
GPU_scissor_test(true);
|
||||
GPU_scissor(0, 0, 1, 2);
|
||||
GPU_framebuffer_clear_color(framebuffer, double4(color2));
|
||||
|
||||
GPU_scissor(0, 0, 2, 1);
|
||||
GPU_framebuffer_clear_color(framebuffer, double4(color3));
|
||||
GPU_scissor_test(false);
|
||||
GPU_finish();
|
||||
|
||||
float4 *read_data = static_cast<float4 *>(GPU_texture_read(texture, GPU_DATA_FLOAT, 0));
|
||||
EXPECT_EQ(color3, read_data[0]);
|
||||
EXPECT_EQ(color3, read_data[1]);
|
||||
EXPECT_EQ(color2, read_data[2]);
|
||||
EXPECT_EQ(color1, read_data[3]);
|
||||
MEM_delete(read_data);
|
||||
|
||||
GPU_framebuffer_free(framebuffer);
|
||||
GPU_texture_free(texture);
|
||||
}
|
||||
GPU_TEST(framebuffer_scissor_test);
|
||||
|
||||
#endif
|
||||
|
||||
/* Color each side of a cube-map with a different color. */
|
||||
static void test_framebuffer_cube()
|
||||
{
|
||||
const int SIZE = 32;
|
||||
GPU_render_begin();
|
||||
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ;
|
||||
gpu::Texture *tex = GPU_texture_create_cube(
|
||||
"tex", SIZE, 1, TextureFormat::SFLOAT_32_32_32_32, usage, nullptr);
|
||||
|
||||
const double4 clear_colors[6] = {
|
||||
{0.5f, 0.0f, 0.0f, 1.0f},
|
||||
{1.0f, 0.0f, 0.0f, 1.0f},
|
||||
{0.0f, 0.5f, 0.0f, 1.0f},
|
||||
{0.0f, 1.0f, 0.0f, 1.0f},
|
||||
{0.0f, 0.0f, 0.5f, 1.0f},
|
||||
{0.0f, 0.0f, 1.0f, 1.0f},
|
||||
};
|
||||
gpu::FrameBuffer *framebuffers[6] = {nullptr};
|
||||
|
||||
for (int i : IndexRange(6)) {
|
||||
GPU_framebuffer_ensure_config(&framebuffers[i],
|
||||
{
|
||||
GPU_ATTACHMENT_NONE,
|
||||
GPU_ATTACHMENT_TEXTURE_CUBEFACE(tex, i),
|
||||
});
|
||||
GPU_framebuffer_bind(framebuffers[i]);
|
||||
GPU_framebuffer_clear_color(framebuffers[i], clear_colors[i]);
|
||||
};
|
||||
|
||||
float4 *data = static_cast<float4 *>(GPU_texture_read(tex, GPU_DATA_FLOAT, 0));
|
||||
for (int side : IndexRange(6)) {
|
||||
for (int pixel_index : IndexRange(SIZE * SIZE)) {
|
||||
int index = pixel_index + (SIZE * SIZE) * side;
|
||||
EXPECT_EQ(float4(clear_colors[side]), data[index]);
|
||||
}
|
||||
}
|
||||
MEM_delete(data);
|
||||
|
||||
GPU_texture_free(tex);
|
||||
|
||||
for (int i : IndexRange(6)) {
|
||||
GPU_FRAMEBUFFER_FREE_SAFE(framebuffers[i]);
|
||||
}
|
||||
|
||||
GPU_render_end();
|
||||
}
|
||||
GPU_TEST(framebuffer_cube)
|
||||
|
||||
/* Effectively tests the same way EEVEE-Next shadows are rendered. */
|
||||
static void test_framebuffer_multi_viewport()
|
||||
{
|
||||
using namespace gpu::shader;
|
||||
if (GPU_type_matches_ex(
|
||||
GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_OFFICIAL, GPU_BACKEND_OPENGL) &&
|
||||
G.debug & G_DEBUG_GPU_FORCE_WORKAROUNDS)
|
||||
{
|
||||
GTEST_SKIP() << "NVIDIA fails to compile workaround due to reserved names. Gladly it doesn't "
|
||||
"need the workaround.";
|
||||
}
|
||||
|
||||
GPU_render_begin();
|
||||
|
||||
const int2 size(4, 4);
|
||||
const int layers = 256;
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ;
|
||||
gpu::Texture *texture = GPU_texture_create_2d_array(
|
||||
__func__, UNPACK2(size), layers, 1, TextureFormat::SINT_32_32, usage, nullptr);
|
||||
|
||||
gpu::FrameBuffer *framebuffer = GPU_framebuffer_create(__func__);
|
||||
GPU_framebuffer_ensure_config(&framebuffer,
|
||||
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(texture)});
|
||||
GPU_framebuffer_bind(framebuffer);
|
||||
|
||||
int viewport_rects[16][4];
|
||||
for (int i = 0; i < 16; i++) {
|
||||
viewport_rects[i][0] = i % 4;
|
||||
viewport_rects[i][1] = i / 4;
|
||||
viewport_rects[i][2] = 1;
|
||||
viewport_rects[i][3] = 1;
|
||||
}
|
||||
GPU_framebuffer_multi_viewports_set(framebuffer, viewport_rects);
|
||||
|
||||
GPU_framebuffer_clear_color(framebuffer, double4(0.0));
|
||||
|
||||
ShaderCreateInfo create_info("gpu_framebuffer_layer_viewport_test");
|
||||
create_info.vertex_source("gpu_framebuffer_layer_viewport_test.glsl");
|
||||
create_info.fragment_source("gpu_framebuffer_layer_viewport_test.glsl");
|
||||
create_info.builtins(BuiltinBits::VIEWPORT_INDEX | BuiltinBits::LAYER | BuiltinBits::VERTEX_ID);
|
||||
create_info.fragment_out(0, Type::int2_t, "out_value");
|
||||
|
||||
gpu::Shader *shader = GPU_shader_create_from_info(
|
||||
reinterpret_cast<GPUShaderCreateInfo *>(&create_info));
|
||||
|
||||
int tri_count = size.x * size.y * layers;
|
||||
|
||||
Batch *batch = GPU_batch_create_procedural(GPU_PRIM_TRIS, tri_count * 3);
|
||||
|
||||
GPU_batch_set_shader(batch, shader);
|
||||
|
||||
GPU_batch_draw(batch);
|
||||
|
||||
GPU_batch_discard(batch);
|
||||
|
||||
GPU_finish();
|
||||
|
||||
int2 *read_data = static_cast<int2 *>(GPU_texture_read(texture, GPU_DATA_INT, 0));
|
||||
for (auto layer : IndexRange(layers)) {
|
||||
for (auto viewport : IndexRange(16)) {
|
||||
int2 expected_color(layer, viewport);
|
||||
int2 pixel_color = read_data[viewport + layer * 16];
|
||||
EXPECT_EQ(pixel_color, expected_color);
|
||||
}
|
||||
}
|
||||
MEM_delete(read_data);
|
||||
|
||||
GPU_shader_unbind();
|
||||
|
||||
GPU_framebuffer_free(framebuffer);
|
||||
GPU_texture_free(texture);
|
||||
GPU_shader_free(shader);
|
||||
|
||||
GPU_render_end();
|
||||
}
|
||||
GPU_TEST(framebuffer_multi_viewport)
|
||||
|
||||
/**
|
||||
* Test sub-pass inputs on Vulkan and raster order groups on Metal and its emulation on other
|
||||
* backend.
|
||||
*/
|
||||
static void test_framebuffer_subpass_input()
|
||||
{
|
||||
using namespace gpu::shader;
|
||||
|
||||
GPU_render_begin();
|
||||
|
||||
const int2 size(1, 1);
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ;
|
||||
gpu::Texture *texture_a = GPU_texture_create_2d(
|
||||
__func__, UNPACK2(size), 1, TextureFormat::SINT_32, usage, nullptr);
|
||||
gpu::Texture *texture_b = GPU_texture_create_2d(
|
||||
__func__, UNPACK2(size), 1, TextureFormat::SINT_32, usage, nullptr);
|
||||
|
||||
gpu::FrameBuffer *framebuffer = GPU_framebuffer_create(__func__);
|
||||
GPU_framebuffer_ensure_config(
|
||||
&framebuffer,
|
||||
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(texture_a), GPU_ATTACHMENT_TEXTURE(texture_b)});
|
||||
GPU_framebuffer_bind(framebuffer);
|
||||
|
||||
GPU_framebuffer_clear_color(framebuffer, {0.0, 0.0, 0.0, 0.0});
|
||||
|
||||
ShaderCreateInfo create_info_write("gpu_framebuffer_subpass_input_test");
|
||||
create_info_write.define("WRITE");
|
||||
create_info_write.builtins(BuiltinBits::VERTEX_ID);
|
||||
create_info_write.vertex_source("gpu_framebuffer_subpass_input_test.glsl");
|
||||
create_info_write.fragment_source("gpu_framebuffer_subpass_input_test.glsl");
|
||||
create_info_write.fragment_out(0, Type::int_t, "out_value", DualBlend::NONE, 0);
|
||||
|
||||
gpu::Shader *shader_write = GPU_shader_create_from_info(
|
||||
reinterpret_cast<GPUShaderCreateInfo *>(&create_info_write));
|
||||
|
||||
ShaderCreateInfo create_info_read("gpu_framebuffer_subpass_input_test");
|
||||
create_info_read.define("READ");
|
||||
create_info_read.builtins(BuiltinBits::VERTEX_ID);
|
||||
create_info_read.vertex_source("gpu_framebuffer_subpass_input_test.glsl");
|
||||
create_info_read.fragment_source("gpu_framebuffer_subpass_input_test.glsl");
|
||||
create_info_read.subpass_in(0, Type::int_t, ImageType::Int2D, "in_value", 0);
|
||||
create_info_read.fragment_out(1, Type::int_t, "out_value");
|
||||
|
||||
gpu::Shader *shader_read = GPU_shader_create_from_info(
|
||||
reinterpret_cast<GPUShaderCreateInfo *>(&create_info_read));
|
||||
|
||||
Batch *batch = GPU_batch_create_procedural(GPU_PRIM_TRIS, 3);
|
||||
|
||||
/* Metal Raster Order Group does not need that. */
|
||||
GPU_framebuffer_subpass_transition(
|
||||
framebuffer, {GPU_ATTACHMENT_IGNORE, GPU_ATTACHMENT_WRITE, GPU_ATTACHMENT_IGNORE});
|
||||
|
||||
GPU_batch_set_shader(batch, shader_write);
|
||||
GPU_batch_draw(batch);
|
||||
|
||||
/* Metal Raster Order Group does not need that. */
|
||||
GPU_framebuffer_subpass_transition(
|
||||
framebuffer, {GPU_ATTACHMENT_IGNORE, GPU_ATTACHMENT_READ, GPU_ATTACHMENT_WRITE});
|
||||
|
||||
GPU_batch_set_shader(batch, shader_read);
|
||||
GPU_batch_draw(batch);
|
||||
|
||||
GPU_batch_discard(batch);
|
||||
|
||||
GPU_finish();
|
||||
|
||||
int *read_data_a = static_cast<int *>(GPU_texture_read(texture_a, GPU_DATA_INT, 0));
|
||||
EXPECT_EQ(*read_data_a, 0xDEADBEEF);
|
||||
MEM_delete(read_data_a);
|
||||
|
||||
int *read_data_b = static_cast<int *>(GPU_texture_read(texture_b, GPU_DATA_INT, 0));
|
||||
EXPECT_EQ(*read_data_b, 0xDEADC0DE);
|
||||
MEM_delete(read_data_b);
|
||||
|
||||
GPU_shader_unbind();
|
||||
|
||||
GPU_framebuffer_free(framebuffer);
|
||||
GPU_texture_free(texture_a);
|
||||
GPU_texture_free(texture_b);
|
||||
GPU_shader_free(shader_write);
|
||||
GPU_shader_free(shader_read);
|
||||
|
||||
GPU_render_end();
|
||||
}
|
||||
GPU_TEST(framebuffer_subpass_input)
|
||||
|
||||
static void test_framebuffer_subpass_input_clearops()
|
||||
{
|
||||
using namespace gpu::shader;
|
||||
|
||||
GPU_render_begin();
|
||||
|
||||
const int2 size(1, 1);
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ;
|
||||
gpu::Texture *texture_a = GPU_texture_create_2d(
|
||||
__func__, UNPACK2(size), 1, TextureFormat::SINT_32, usage, nullptr);
|
||||
gpu::Texture *texture_b = GPU_texture_create_2d(
|
||||
__func__, UNPACK2(size), 1, TextureFormat::SINT_32, usage, nullptr);
|
||||
|
||||
const int invalid_data = 0xDEADBEEF;
|
||||
texture_a->clear(double4(invalid_data));
|
||||
|
||||
gpu::FrameBuffer *framebuffer = GPU_framebuffer_create(__func__);
|
||||
GPU_framebuffer_ensure_config(
|
||||
&framebuffer,
|
||||
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(texture_a), GPU_ATTACHMENT_TEXTURE(texture_b)});
|
||||
GPU_framebuffer_bind_ex(
|
||||
framebuffer,
|
||||
{
|
||||
{GPU_LOADACTION_DONT_CARE, GPU_STOREACTION_DONT_CARE},
|
||||
{GPU_LOADACTION_CLEAR, GPU_STOREACTION_STORE, {0.0f, 0.0f, 0.0f, 0.0f}},
|
||||
{GPU_LOADACTION_CLEAR, GPU_STOREACTION_STORE, {0.0f, 0.0f, 0.0f, 0.0f}},
|
||||
});
|
||||
|
||||
ShaderCreateInfo create_info_read("gpu_framebuffer_subpass_input_test");
|
||||
create_info_read.define("READ");
|
||||
create_info_read.builtins(BuiltinBits::VERTEX_ID);
|
||||
create_info_read.vertex_source("gpu_framebuffer_subpass_input_test.glsl");
|
||||
create_info_read.fragment_source("gpu_framebuffer_subpass_input_test.glsl");
|
||||
create_info_read.subpass_in(0, Type::int_t, ImageType::Int2D, "in_value", 0);
|
||||
create_info_read.fragment_out(1, Type::int_t, "out_value");
|
||||
|
||||
gpu::Shader *shader_read = GPU_shader_create_from_info(
|
||||
reinterpret_cast<GPUShaderCreateInfo *>(&create_info_read));
|
||||
|
||||
Batch *batch = GPU_batch_create_procedural(GPU_PRIM_TRIS, 3);
|
||||
|
||||
/* Metal Raster Order Group does not need that. */
|
||||
GPU_framebuffer_subpass_transition(
|
||||
framebuffer, {GPU_ATTACHMENT_IGNORE, GPU_ATTACHMENT_WRITE, GPU_ATTACHMENT_IGNORE});
|
||||
|
||||
/* Metal Raster Order Group does not need that. */
|
||||
GPU_framebuffer_subpass_transition(
|
||||
framebuffer, {GPU_ATTACHMENT_IGNORE, GPU_ATTACHMENT_READ, GPU_ATTACHMENT_WRITE});
|
||||
|
||||
GPU_batch_set_shader(batch, shader_read);
|
||||
GPU_batch_draw(batch);
|
||||
|
||||
GPU_batch_discard(batch);
|
||||
|
||||
GPU_finish();
|
||||
|
||||
int *read_data_a = static_cast<int *>(GPU_texture_read(texture_a, GPU_DATA_INT, 0));
|
||||
EXPECT_EQ(*read_data_a, 0x0);
|
||||
MEM_delete(read_data_a);
|
||||
|
||||
int *read_data_b = static_cast<int *>(GPU_texture_read(texture_b, GPU_DATA_INT, 0));
|
||||
EXPECT_EQ(*read_data_b, 495);
|
||||
MEM_delete(read_data_b);
|
||||
|
||||
GPU_shader_unbind();
|
||||
|
||||
GPU_framebuffer_free(framebuffer);
|
||||
GPU_texture_free(texture_a);
|
||||
GPU_texture_free(texture_b);
|
||||
GPU_shader_free(shader_read);
|
||||
|
||||
GPU_render_end();
|
||||
}
|
||||
GPU_TEST(framebuffer_subpass_input_clearops)
|
||||
|
||||
} // namespace blender::gpu::tests
|
||||
92
blender-5.2.0/source/blender/gpu/tests/gpu_testing.cc
Normal file
92
blender-5.2.0/source/blender/gpu/tests/gpu_testing.cc
Normal file
@@ -0,0 +1,92 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
#include "BLI_math_color.h"
|
||||
|
||||
#include "BKE_gtest_base.hh"
|
||||
|
||||
#include "GPU_context.hh"
|
||||
#include "GPU_debug.hh"
|
||||
#include "GPU_init_exit.hh"
|
||||
|
||||
#include "gpu_testing.hh"
|
||||
|
||||
#include "GHOST_ISystem.hh"
|
||||
#include "GHOST_ISystemPaths.hh"
|
||||
#include "GHOST_Types.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
GHOST_ISystem *GPUTest::ghost_system_;
|
||||
GHOST_IContext *GPUTest::ghost_context_;
|
||||
GPUContext *GPUTest::context_;
|
||||
|
||||
int32_t GPUTest::prev_g_debug_;
|
||||
|
||||
void GPUTest::SetUpTestSuite(GHOST_TDrawingContextType draw_context_type,
|
||||
GPUBackendType gpu_backend_type,
|
||||
int32_t g_debug_flags)
|
||||
{
|
||||
prev_g_debug_ = G.debug;
|
||||
G.debug |= g_debug_flags;
|
||||
|
||||
bke::gtest_setup();
|
||||
GPU_backend_type_selection_set(gpu_backend_type);
|
||||
if (!GPU_backend_supported()) {
|
||||
GTEST_SKIP() << "GPU backend not supported";
|
||||
}
|
||||
GHOST_GPUSettings gpu_settings = {};
|
||||
gpu_settings.context_type = draw_context_type;
|
||||
gpu_settings.flags = GHOST_gpuDebugContext;
|
||||
GHOST_ISystem::createSystemBackground();
|
||||
ghost_system_ = GHOST_ISystem::getSystem();
|
||||
GPU_backend_ghost_system_set(ghost_system_);
|
||||
ghost_context_ = ghost_system_->createOffscreenContext(gpu_settings);
|
||||
ghost_context_->activateDrawingContext();
|
||||
context_ = GPU_context_create(nullptr, ghost_context_);
|
||||
GPU_init();
|
||||
|
||||
BLI_init_srgb_conversion();
|
||||
|
||||
GPU_render_begin();
|
||||
GPU_context_begin_frame(context_);
|
||||
GPU_debug_capture_begin(nullptr);
|
||||
}
|
||||
|
||||
void GPUTest::TearDownTestSuite()
|
||||
{
|
||||
GPU_debug_capture_end();
|
||||
GPU_context_end_frame(context_);
|
||||
GPU_render_end();
|
||||
|
||||
GPU_exit();
|
||||
GPU_context_discard(context_);
|
||||
ghost_system_->disposeContext(ghost_context_);
|
||||
GHOST_ISystem::disposeSystem();
|
||||
GHOST_ISystemPaths::dispose();
|
||||
|
||||
bke::gtest_teardown();
|
||||
|
||||
G.debug = prev_g_debug_;
|
||||
}
|
||||
|
||||
void GPUTest::SetUp()
|
||||
{
|
||||
const ::testing::TestInfo *info = ::testing::UnitTest::GetInstance()->current_test_info();
|
||||
std::stringstream ss;
|
||||
ss << info->test_suite_name() << "." << info->name();
|
||||
debug_group_name_ = ss.str();
|
||||
GPU_debug_group_begin(debug_group_name_.c_str());
|
||||
}
|
||||
|
||||
void GPUTest::TearDown()
|
||||
{
|
||||
GPU_debug_group_end();
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
||||
176
blender-5.2.0/source/blender/gpu/tests/gpu_testing.hh
Normal file
176
blender-5.2.0/source/blender/gpu/tests/gpu_testing.hh
Normal file
@@ -0,0 +1,176 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "BKE_global.hh"
|
||||
|
||||
#include "GHOST_IContext.hh"
|
||||
#include "GHOST_ISystem.hh"
|
||||
|
||||
#include "GPU_platform.hh"
|
||||
|
||||
struct GPUContext;
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
/**
|
||||
* Test class that setups a GPUContext for test cases.
|
||||
*/
|
||||
class GPUTest : public ::testing::Test {
|
||||
private:
|
||||
static GHOST_ISystem *ghost_system_;
|
||||
static GHOST_IContext *ghost_context_;
|
||||
static GPUContext *context_;
|
||||
|
||||
static int32_t prev_g_debug_;
|
||||
std::string debug_group_name_;
|
||||
|
||||
protected:
|
||||
static void SetUpTestSuite(GHOST_TDrawingContextType draw_context_type,
|
||||
GPUBackendType gpu_backend_type,
|
||||
int32_t g_debug_flags);
|
||||
static void TearDownTestSuite();
|
||||
|
||||
void SetUp() override;
|
||||
void TearDown() override;
|
||||
};
|
||||
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
class GPUOpenGLTest : public GPUTest {
|
||||
public:
|
||||
static void SetUpTestSuite()
|
||||
{
|
||||
GPUTest::SetUpTestSuite(GHOST_kDrawingContextTypeOpenGL,
|
||||
GPU_BACKEND_OPENGL,
|
||||
G_DEBUG_GPU | G_DEBUG_GPU_COMPILE_SHADERS | G_DEBUG_GPU_RENDERDOC);
|
||||
}
|
||||
static void TearDownTestSuite()
|
||||
{
|
||||
GPUTest::TearDownTestSuite();
|
||||
}
|
||||
};
|
||||
|
||||
class GPUOpenGLWorkaroundsTest : public GPUTest {
|
||||
public:
|
||||
static void SetUpTestSuite()
|
||||
{
|
||||
GPUTest::SetUpTestSuite(GHOST_kDrawingContextTypeOpenGL,
|
||||
GPU_BACKEND_OPENGL,
|
||||
G_DEBUG_GPU | G_DEBUG_GPU_COMPILE_SHADERS | G_DEBUG_GPU_RENDERDOC |
|
||||
G_DEBUG_GPU_FORCE_WORKAROUNDS);
|
||||
}
|
||||
static void TearDownTestSuite()
|
||||
{
|
||||
GPUTest::TearDownTestSuite();
|
||||
}
|
||||
};
|
||||
# define GPU_OPENGL_TEST(test_name) \
|
||||
TEST_F(GPUOpenGLTest, test_name) \
|
||||
{ \
|
||||
test_##test_name(); \
|
||||
} \
|
||||
TEST_F(GPUOpenGLWorkaroundsTest, test_name) \
|
||||
{ \
|
||||
test_##test_name(); \
|
||||
}
|
||||
#else
|
||||
# define GPU_OPENGL_TEST(test_name)
|
||||
#endif
|
||||
|
||||
#ifdef WITH_METAL_BACKEND
|
||||
class GPUMetalTest : public GPUTest {
|
||||
public:
|
||||
static void SetUpTestSuite()
|
||||
{
|
||||
GPUTest::SetUpTestSuite(GHOST_kDrawingContextTypeMetal, GPU_BACKEND_METAL, G_DEBUG_GPU);
|
||||
}
|
||||
static void TearDownTestSuite()
|
||||
{
|
||||
GPUTest::TearDownTestSuite();
|
||||
}
|
||||
};
|
||||
|
||||
class GPUMetalWorkaroundsTest : public GPUTest {
|
||||
public:
|
||||
static void SetUpTestSuite()
|
||||
{
|
||||
GPUTest::SetUpTestSuite(GHOST_kDrawingContextTypeMetal,
|
||||
GPU_BACKEND_METAL,
|
||||
G_DEBUG_GPU | G_DEBUG_GPU_FORCE_WORKAROUNDS);
|
||||
}
|
||||
static void TearDownTestSuite()
|
||||
{
|
||||
GPUTest::TearDownTestSuite();
|
||||
}
|
||||
};
|
||||
# define GPU_METAL_TEST(test_name) \
|
||||
TEST_F(GPUMetalTest, test_name) \
|
||||
{ \
|
||||
test_##test_name(); \
|
||||
} \
|
||||
TEST_F(GPUMetalWorkaroundsTest, test_name) \
|
||||
{ \
|
||||
test_##test_name(); \
|
||||
}
|
||||
#else
|
||||
# define GPU_METAL_TEST(test_name)
|
||||
#endif
|
||||
|
||||
#ifdef WITH_VULKAN_BACKEND
|
||||
class GPUVulkanTest : public GPUTest {
|
||||
public:
|
||||
static void SetUpTestSuite()
|
||||
{
|
||||
GPUTest::SetUpTestSuite(GHOST_kDrawingContextTypeVulkan,
|
||||
GPU_BACKEND_VULKAN,
|
||||
G_DEBUG_GPU | G_DEBUG_GPU_SHADER_DEBUG_INFO | G_DEBUG_GPU_RENDERDOC);
|
||||
}
|
||||
static void TearDownTestSuite()
|
||||
{
|
||||
GPUTest::TearDownTestSuite();
|
||||
}
|
||||
};
|
||||
|
||||
class GPUVulkanWorkaroundsTest : public GPUTest {
|
||||
public:
|
||||
static void SetUpTestSuite()
|
||||
{
|
||||
GPUTest::SetUpTestSuite(GHOST_kDrawingContextTypeVulkan,
|
||||
GPU_BACKEND_VULKAN,
|
||||
G_DEBUG_GPU | G_DEBUG_GPU_SHADER_DEBUG_INFO | G_DEBUG_GPU_RENDERDOC |
|
||||
G_DEBUG_GPU_FORCE_WORKAROUNDS);
|
||||
}
|
||||
static void TearDownTestSuite()
|
||||
{
|
||||
GPUTest::TearDownTestSuite();
|
||||
}
|
||||
};
|
||||
# define GPU_VULKAN_TEST(test_name) \
|
||||
TEST_F(GPUVulkanTest, test_name) \
|
||||
{ \
|
||||
test_##test_name(); \
|
||||
} \
|
||||
TEST_F(GPUVulkanWorkaroundsTest, test_name) \
|
||||
{ \
|
||||
test_##test_name(); \
|
||||
}
|
||||
#else
|
||||
# define GPU_VULKAN_TEST(test_name)
|
||||
#endif
|
||||
|
||||
#define GPU_TEST(test_name) \
|
||||
GPU_OPENGL_TEST(test_name) \
|
||||
GPU_METAL_TEST(test_name) \
|
||||
GPU_VULKAN_TEST(test_name)
|
||||
|
||||
#define BLOCK_GPU_TEST_ON(device_type, os_type, driver_type, backend_type) \
|
||||
if (!blender::tests::should_ignore_blocklist(device_type == GPU_DEVICE_ANY) && \
|
||||
GPU_type_matches_ex(device_type, os_type, driver_type, backend_type)) \
|
||||
{ \
|
||||
GTEST_SKIP(); \
|
||||
return; \
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
||||
133
blender-5.2.0/source/blender/gpu/tests/immediate_test.cc
Normal file
133
blender-5.2.0/source/blender/gpu/tests/immediate_test.cc
Normal file
@@ -0,0 +1,133 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "GPU_framebuffer.hh"
|
||||
#include "GPU_immediate.hh"
|
||||
#include "GPU_shader_builtin.hh"
|
||||
#include "GPU_state.hh"
|
||||
#include "gpu_testing.hh"
|
||||
|
||||
#include "BLI_math_vector.hh"
|
||||
|
||||
namespace blender::gpu::tests {
|
||||
|
||||
static constexpr int Size = 4;
|
||||
|
||||
static void test_immediate_one_plane()
|
||||
{
|
||||
GPUOffScreen *offscreen = GPU_offscreen_create(Size,
|
||||
Size,
|
||||
false,
|
||||
TextureFormat::SFLOAT_16_16_16_16,
|
||||
GPU_TEXTURE_USAGE_ATTACHMENT |
|
||||
GPU_TEXTURE_USAGE_HOST_READ,
|
||||
false,
|
||||
nullptr);
|
||||
BLI_assert(offscreen != nullptr);
|
||||
GPU_offscreen_bind(offscreen, false);
|
||||
|
||||
GPUVertFormat *format = immVertexFormat();
|
||||
uint pos = GPU_vertformat_attr_add(format, "pos", gpu::VertAttrType::SFLOAT_32_32_32);
|
||||
|
||||
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
|
||||
|
||||
float4 color(1.0, 0.5, 0.25, 1.0);
|
||||
immUniformColor4fv(color);
|
||||
immBegin(GPU_PRIM_TRI_STRIP, 4);
|
||||
immVertex3f(pos, -1.0f, 1.0f, 0.0f);
|
||||
immVertex3f(pos, 1.0f, 1.0f, 0.0f);
|
||||
immVertex3f(pos, -1.0f, -1.0f, 0.0f);
|
||||
immVertex3f(pos, 1.0f, -1.0f, 0.0f);
|
||||
immEnd();
|
||||
|
||||
GPU_offscreen_unbind(offscreen, false);
|
||||
GPU_flush();
|
||||
|
||||
/* Read back data and perform some basic tests. */
|
||||
Vector<float4> read_data(Size * Size);
|
||||
GPU_offscreen_read_color(offscreen, GPU_DATA_FLOAT, read_data.data());
|
||||
for (const float4 &read_color : read_data) {
|
||||
EXPECT_EQ(read_color, color);
|
||||
}
|
||||
|
||||
GPU_offscreen_free(offscreen);
|
||||
|
||||
immUnbindProgram();
|
||||
}
|
||||
GPU_TEST(immediate_one_plane)
|
||||
|
||||
/**
|
||||
* Draws two planes with two different colors.
|
||||
* - Tests that both planes are stored in the same buffer (depends on backend).
|
||||
* - Test that data of the first plane isn't overwritten by the second plane.
|
||||
* (push constants, buffer, bind points etc.)
|
||||
*/
|
||||
static void test_immediate_two_planes()
|
||||
{
|
||||
GPUOffScreen *offscreen = GPU_offscreen_create(Size,
|
||||
Size,
|
||||
false,
|
||||
TextureFormat::SFLOAT_16_16_16_16,
|
||||
GPU_TEXTURE_USAGE_ATTACHMENT |
|
||||
GPU_TEXTURE_USAGE_HOST_READ,
|
||||
false,
|
||||
nullptr);
|
||||
BLI_assert(offscreen != nullptr);
|
||||
GPU_offscreen_bind(offscreen, false);
|
||||
|
||||
GPUVertFormat *format = immVertexFormat();
|
||||
uint pos = GPU_vertformat_attr_add(format, "pos", gpu::VertAttrType::SFLOAT_32_32_32);
|
||||
|
||||
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
|
||||
|
||||
float4 color(1.0, 0.5, 0.25, 1.0);
|
||||
immUniformColor4fv(color);
|
||||
immBegin(GPU_PRIM_TRI_STRIP, 4);
|
||||
immVertex3f(pos, -1.0f, 1.0f, 0.0f);
|
||||
immVertex3f(pos, 0.0f, 1.0f, 0.0f);
|
||||
immVertex3f(pos, -1.0f, -1.0f, 0.0f);
|
||||
immVertex3f(pos, 0.0f, -1.0f, 0.0f);
|
||||
immEnd();
|
||||
|
||||
float4 color2(0.25, 0.5, 1.0, 1.0);
|
||||
immUniformColor4fv(color2);
|
||||
immBegin(GPU_PRIM_TRI_STRIP, 4);
|
||||
immVertex3f(pos, 0.0f, 1.0f, 0.0f);
|
||||
immVertex3f(pos, 1.0f, 1.0f, 0.0f);
|
||||
immVertex3f(pos, 0.0f, -1.0f, 0.0f);
|
||||
immVertex3f(pos, 1.0f, -1.0f, 0.0f);
|
||||
immEnd();
|
||||
|
||||
GPU_offscreen_unbind(offscreen, false);
|
||||
GPU_flush();
|
||||
|
||||
/* Read back data and perform some basic tests.
|
||||
* Not performing detailed tests as there might be driver specific limitations. */
|
||||
Vector<float4> read_data(Size * Size);
|
||||
GPU_offscreen_read_color(offscreen, GPU_DATA_FLOAT, read_data.data());
|
||||
int64_t color_num = 0;
|
||||
int64_t color2_num = 0;
|
||||
for (const float4 &read_color : read_data) {
|
||||
if (read_color == color) {
|
||||
color_num++;
|
||||
}
|
||||
else if (read_color == color2) {
|
||||
color2_num++;
|
||||
}
|
||||
else {
|
||||
EXPECT_TRUE(read_color == color || read_color == color2);
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(color_num > 0);
|
||||
EXPECT_TRUE(color2_num > 0);
|
||||
|
||||
GPU_offscreen_free(offscreen);
|
||||
|
||||
immUnbindProgram();
|
||||
}
|
||||
GPU_TEST(immediate_two_planes)
|
||||
|
||||
} // namespace blender::gpu::tests
|
||||
50
blender-5.2.0/source/blender/gpu/tests/index_buffer_test.cc
Normal file
50
blender-5.2.0/source/blender/gpu/tests/index_buffer_test.cc
Normal file
@@ -0,0 +1,50 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "GPU_index_buffer.hh"
|
||||
|
||||
#include "gpu_testing.hh"
|
||||
|
||||
namespace blender::gpu::tests {
|
||||
|
||||
static void test_index_buffer_subbuilders()
|
||||
{
|
||||
const uint num_subbuilders = 10;
|
||||
const uint verts_per_subbuilders = 100;
|
||||
const uint vertex_len = num_subbuilders * verts_per_subbuilders;
|
||||
|
||||
GPUIndexBufBuilder builder;
|
||||
GPU_indexbuf_init(&builder, GPU_PRIM_POINTS, vertex_len, vertex_len);
|
||||
|
||||
GPUIndexBufBuilder subbuilders[num_subbuilders];
|
||||
for (int subbuilder_index = 0; subbuilder_index < num_subbuilders; subbuilder_index++) {
|
||||
memcpy(&subbuilders[subbuilder_index], &builder, sizeof(builder));
|
||||
}
|
||||
|
||||
for (int subbuilder_index = 0; subbuilder_index < num_subbuilders; subbuilder_index++) {
|
||||
GPUIndexBufBuilder &subbuilder = subbuilders[subbuilder_index];
|
||||
for (int subbuilder_vert_index = 0; subbuilder_vert_index < verts_per_subbuilders;
|
||||
subbuilder_vert_index++)
|
||||
{
|
||||
int vert_index_to_update = subbuilder_index * verts_per_subbuilders + subbuilder_vert_index;
|
||||
GPU_indexbuf_set_point_vert(&subbuilder, vert_index_to_update, vert_index_to_update);
|
||||
}
|
||||
}
|
||||
|
||||
for (int subbuilder_index = 0; subbuilder_index < num_subbuilders; subbuilder_index++) {
|
||||
EXPECT_EQ(builder.index_len, subbuilder_index * verts_per_subbuilders);
|
||||
GPU_indexbuf_join(&builder, &subbuilders[subbuilder_index]);
|
||||
EXPECT_EQ(builder.index_len, (subbuilder_index + 1) * verts_per_subbuilders);
|
||||
}
|
||||
|
||||
IndexBuf *index_buffer = GPU_indexbuf_build(&builder);
|
||||
EXPECT_NE(index_buffer, nullptr);
|
||||
GPU_INDEXBUF_DISCARD_SAFE(index_buffer);
|
||||
}
|
||||
|
||||
GPU_TEST(index_buffer_subbuilders)
|
||||
|
||||
} // namespace blender::gpu::tests
|
||||
221
blender-5.2.0/source/blender/gpu/tests/push_constants_test.cc
Normal file
221
blender-5.2.0/source/blender/gpu/tests/push_constants_test.cc
Normal file
@@ -0,0 +1,221 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "GPU_capabilities.hh"
|
||||
#include "GPU_compute.hh"
|
||||
#include "GPU_shader.hh"
|
||||
#include "GPU_state.hh"
|
||||
#include "GPU_storage_buffer.hh"
|
||||
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_utility_mixins.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "gpu_testing.hh"
|
||||
|
||||
namespace blender::gpu::tests {
|
||||
struct CallData {
|
||||
StorageBuf *ssbo = nullptr;
|
||||
Vector<float> data;
|
||||
|
||||
float float_in;
|
||||
float2 vec2_in;
|
||||
float3 vec3_in;
|
||||
float4 vec4_in;
|
||||
|
||||
void init_ssbo(size_t num_floats)
|
||||
{
|
||||
if (ssbo == nullptr) {
|
||||
ssbo = GPU_storagebuf_create_ex(
|
||||
num_floats * sizeof(float), nullptr, GPU_USAGE_DEVICE_ONLY, __func__);
|
||||
data.resize(num_floats);
|
||||
}
|
||||
}
|
||||
|
||||
~CallData()
|
||||
{
|
||||
if (ssbo != nullptr) {
|
||||
GPU_storagebuf_free(ssbo);
|
||||
ssbo = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void generate_test_data(const float vector_mul, const float scalar_mul)
|
||||
{
|
||||
float_in = vector_mul;
|
||||
vec2_in = float2(vector_mul * 2.0, vector_mul * 2.0 + scalar_mul);
|
||||
vec3_in = float3(
|
||||
vector_mul * 3.0, vector_mul * 3.0 + scalar_mul, vector_mul * 3.0 + scalar_mul * 2.0);
|
||||
vec4_in = float4(vector_mul * 4.0,
|
||||
vector_mul * 4.0 + scalar_mul,
|
||||
vector_mul * 4.0 + scalar_mul * 2.0,
|
||||
vector_mul * 4.0 + scalar_mul * 3.0);
|
||||
}
|
||||
|
||||
void read_back()
|
||||
{
|
||||
GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE);
|
||||
GPU_storagebuf_read(ssbo, data.data());
|
||||
}
|
||||
|
||||
void validate()
|
||||
{
|
||||
/* Check the results. */
|
||||
EXPECT_EQ(float_in, data[0]);
|
||||
EXPECT_EQ(vec2_in.x, data[1]);
|
||||
EXPECT_EQ(vec2_in.y, data[2]);
|
||||
EXPECT_EQ(vec3_in.x, data[3]);
|
||||
EXPECT_EQ(vec3_in.y, data[4]);
|
||||
EXPECT_EQ(vec3_in.z, data[5]);
|
||||
EXPECT_EQ(vec4_in.x, data[6]);
|
||||
EXPECT_EQ(vec4_in.y, data[7]);
|
||||
EXPECT_EQ(vec4_in.z, data[8]);
|
||||
EXPECT_EQ(vec4_in.w, data[9]);
|
||||
}
|
||||
};
|
||||
|
||||
struct Shader {
|
||||
gpu::Shader *shader = nullptr;
|
||||
Vector<CallData> call_datas;
|
||||
|
||||
Shader()
|
||||
{
|
||||
call_datas.reserve(10);
|
||||
}
|
||||
|
||||
~Shader()
|
||||
{
|
||||
if (shader != nullptr) {
|
||||
GPU_shader_unbind();
|
||||
GPU_shader_free(shader);
|
||||
}
|
||||
}
|
||||
|
||||
void init_shader(const char *info_name)
|
||||
{
|
||||
if (shader == nullptr) {
|
||||
shader = GPU_shader_create_from_info_name(info_name);
|
||||
EXPECT_NE(shader, nullptr);
|
||||
GPU_shader_bind(shader);
|
||||
}
|
||||
}
|
||||
|
||||
CallData &new_call()
|
||||
{
|
||||
CallData call_data;
|
||||
call_datas.append(call_data);
|
||||
return call_datas.last();
|
||||
}
|
||||
|
||||
void bind(CallData &call_data)
|
||||
{
|
||||
GPU_storagebuf_bind(call_data.ssbo, GPU_shader_get_ssbo_binding(shader, "data_out"));
|
||||
}
|
||||
|
||||
void update_push_constants(const CallData &call_data)
|
||||
{
|
||||
GPU_shader_uniform_1f(shader, "float_in", call_data.float_in);
|
||||
GPU_shader_uniform_2fv(shader, "vec2_in", call_data.vec2_in);
|
||||
GPU_shader_uniform_3fv(shader, "vec3_in", call_data.vec3_in);
|
||||
GPU_shader_uniform_4fv(shader, "vec4_in", call_data.vec4_in);
|
||||
}
|
||||
|
||||
void dispatch()
|
||||
{
|
||||
/* Dispatching 1000000 times to add some stress to the GPU. Without it tests may succeed when
|
||||
* using too simple shaders. */
|
||||
GPU_compute_dispatch(shader, 1000, 1000, 1);
|
||||
}
|
||||
};
|
||||
|
||||
/** Test the given info when doing a single call. */
|
||||
static void do_push_constants_test(const char *info_name, const int num_calls_simultaneously = 1)
|
||||
{
|
||||
static constexpr uint SIZE = 16;
|
||||
|
||||
Shader shader;
|
||||
shader.init_shader(info_name);
|
||||
|
||||
for (const int call_index : IndexRange(num_calls_simultaneously)) {
|
||||
CallData &call_data = shader.new_call();
|
||||
call_data.generate_test_data(call_index * 10.0, (call_index + 1) * 1.0);
|
||||
call_data.init_ssbo(SIZE);
|
||||
shader.bind(call_data);
|
||||
shader.update_push_constants(call_data);
|
||||
shader.dispatch();
|
||||
}
|
||||
/* All calls will be "simultaneously" in flight. First read-back will wait until the dispatches
|
||||
* have finished execution. */
|
||||
for (const int call_index : IndexRange(num_calls_simultaneously)) {
|
||||
CallData &call_data = shader.call_datas[call_index];
|
||||
call_data.read_back();
|
||||
call_data.validate();
|
||||
}
|
||||
}
|
||||
|
||||
/* Test case with single call as sanity check, before we make it more interesting. */
|
||||
static void test_push_constants()
|
||||
{
|
||||
do_push_constants_test("gpu_push_constants_test");
|
||||
}
|
||||
GPU_TEST(push_constants)
|
||||
|
||||
static void test_push_constants_128bytes()
|
||||
{
|
||||
do_push_constants_test("gpu_push_constants_128bytes_test");
|
||||
}
|
||||
GPU_TEST(push_constants_128bytes)
|
||||
|
||||
static void test_push_constants_256bytes()
|
||||
{
|
||||
do_push_constants_test("gpu_push_constants_256bytes_test");
|
||||
}
|
||||
GPU_TEST(push_constants_256bytes)
|
||||
|
||||
static void test_push_constants_512bytes()
|
||||
{
|
||||
do_push_constants_test("gpu_push_constants_512bytes_test");
|
||||
}
|
||||
GPU_TEST(push_constants_512bytes)
|
||||
|
||||
static void test_push_constants_8192bytes()
|
||||
{
|
||||
do_push_constants_test("gpu_push_constants_8192bytes_test");
|
||||
}
|
||||
GPU_TEST(push_constants_8192bytes)
|
||||
|
||||
/* Schedule multiple simultaneously. */
|
||||
static void test_push_constants_multiple()
|
||||
{
|
||||
do_push_constants_test("gpu_push_constants_test", 10);
|
||||
}
|
||||
GPU_TEST(push_constants_multiple)
|
||||
|
||||
static void test_push_constants_multiple_128bytes()
|
||||
{
|
||||
do_push_constants_test("gpu_push_constants_128bytes_test", 10);
|
||||
}
|
||||
GPU_TEST(push_constants_multiple_128bytes)
|
||||
|
||||
static void test_push_constants_multiple_256bytes()
|
||||
{
|
||||
do_push_constants_test("gpu_push_constants_256bytes_test", 10);
|
||||
}
|
||||
GPU_TEST(push_constants_multiple_256bytes)
|
||||
|
||||
static void test_push_constants_multiple_512bytes()
|
||||
{
|
||||
do_push_constants_test("gpu_push_constants_512bytes_test", 10);
|
||||
}
|
||||
GPU_TEST(push_constants_multiple_512bytes)
|
||||
|
||||
static void test_push_constants_multiple_8192bytes()
|
||||
{
|
||||
do_push_constants_test("gpu_push_constants_8192bytes_test", 10);
|
||||
}
|
||||
GPU_TEST(push_constants_multiple_8192bytes)
|
||||
|
||||
} // namespace blender::gpu::tests
|
||||
@@ -0,0 +1,112 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "gpu_shader_create_info.hh"
|
||||
#include "gpu_shader_create_info_private.hh"
|
||||
#include "gpu_testing.hh"
|
||||
|
||||
#include "GPU_batch.hh"
|
||||
#include "GPU_context.hh"
|
||||
#include "GPU_framebuffer.hh"
|
||||
|
||||
namespace blender::gpu::tests {
|
||||
|
||||
using namespace blender::gpu::shader;
|
||||
|
||||
/**
|
||||
* Test if all static shaders can be compiled.
|
||||
*/
|
||||
static void test_static_shaders()
|
||||
{
|
||||
if (GPU_type_matches_ex(
|
||||
GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_OFFICIAL, GPU_BACKEND_OPENGL) &&
|
||||
G.debug & G_DEBUG_GPU_FORCE_WORKAROUNDS)
|
||||
{
|
||||
GTEST_SKIP() << "NVIDIA fails to compile workaround due to reserved names. Gladly it doesn't "
|
||||
"need the workaround.";
|
||||
}
|
||||
|
||||
EXPECT_TRUE(gpu_shader_create_info_compile_all(nullptr));
|
||||
}
|
||||
GPU_TEST(static_shaders)
|
||||
|
||||
static void test_shader_create_info_pipeline()
|
||||
{
|
||||
if (GPU_type_matches_ex(
|
||||
GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_OFFICIAL, GPU_BACKEND_OPENGL) &&
|
||||
G.debug & G_DEBUG_GPU_FORCE_WORKAROUNDS)
|
||||
{
|
||||
GTEST_SKIP() << "NVIDIA fails to compile workaround due to reserved names. Gladly it doesn't "
|
||||
"need the workaround.";
|
||||
}
|
||||
GPU_render_begin();
|
||||
|
||||
ShaderCreateInfo create_info("gpu_framebuffer_layer_viewport_test");
|
||||
create_info.vertex_source("gpu_framebuffer_layer_viewport_test.glsl");
|
||||
create_info.fragment_source("gpu_framebuffer_layer_viewport_test.glsl");
|
||||
create_info.builtins(BuiltinBits::VIEWPORT_INDEX | BuiltinBits::LAYER | BuiltinBits::VERTEX_ID);
|
||||
create_info.fragment_out(0, Type::int2_t, "out_value");
|
||||
|
||||
create_info.pipeline_state()
|
||||
.state(GPU_WRITE_COLOR,
|
||||
GPU_BLEND_NONE,
|
||||
GPU_CULL_NONE,
|
||||
GPU_DEPTH_NONE,
|
||||
GPU_STENCIL_NONE,
|
||||
GPU_STENCIL_OP_NONE,
|
||||
GPU_VERTEX_LAST)
|
||||
.primitive(GPU_PRIM_TRIS)
|
||||
.viewports(16)
|
||||
.color_format(TextureTargetFormat::SINT_32_32);
|
||||
|
||||
Shader *shader = GPU_shader_create_from_info(
|
||||
reinterpret_cast<GPUShaderCreateInfo *>(&create_info));
|
||||
|
||||
EXPECT_TRUE(shader != nullptr);
|
||||
|
||||
/* Setup framebuffer */
|
||||
const int2 size(4, 4);
|
||||
const int layers = 256;
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ;
|
||||
gpu::Texture *texture = GPU_texture_create_2d_array(
|
||||
__func__, UNPACK2(size), layers, 1, TextureFormat::SINT_32_32, usage, nullptr);
|
||||
|
||||
gpu::FrameBuffer *framebuffer = GPU_framebuffer_create(__func__);
|
||||
GPU_framebuffer_ensure_config(&framebuffer,
|
||||
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(texture)});
|
||||
GPU_framebuffer_bind(framebuffer);
|
||||
|
||||
/* Setup viewports. */
|
||||
int viewport_rects[16][4];
|
||||
for (int i = 0; i < 16; i++) {
|
||||
viewport_rects[i][0] = i % 4;
|
||||
viewport_rects[i][1] = i / 4;
|
||||
viewport_rects[i][2] = 1;
|
||||
viewport_rects[i][3] = 1;
|
||||
}
|
||||
GPU_framebuffer_multi_viewports_set(framebuffer, viewport_rects);
|
||||
int tri_count = size.x * size.y * layers;
|
||||
|
||||
Batch *batch = GPU_batch_create_procedural(GPU_PRIM_TRIS, tri_count * 3);
|
||||
GPU_batch_set_shader(batch, shader);
|
||||
/* On vulkan this triggers an assert when a new pipeline is created (`G.debug_value == 32`) */
|
||||
{
|
||||
GPUContext *context = GPU_context_active_get();
|
||||
DebugScopePipelineCreation scope(context);
|
||||
GPU_batch_draw(batch);
|
||||
}
|
||||
GPU_flush();
|
||||
|
||||
GPU_render_end();
|
||||
GPU_batch_discard(batch);
|
||||
GPU_framebuffer_free(framebuffer);
|
||||
GPU_texture_free(texture);
|
||||
GPU_shader_unbind();
|
||||
GPU_SHADER_FREE_SAFE(shader);
|
||||
}
|
||||
GPU_TEST(shader_create_info_pipeline)
|
||||
|
||||
} // namespace blender::gpu::tests
|
||||
3368
blender-5.2.0/source/blender/gpu/tests/shader_preprocess_test.cc
Normal file
3368
blender-5.2.0/source/blender/gpu/tests/shader_preprocess_test.cc
Normal file
File diff suppressed because it is too large
Load Diff
944
blender-5.2.0/source/blender/gpu/tests/shader_test.cc
Normal file
944
blender-5.2.0/source/blender/gpu/tests/shader_test.cc
Normal file
@@ -0,0 +1,944 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "BLI_math_base.h"
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
|
||||
#include "GPU_batch.hh"
|
||||
#include "GPU_batch_presets.hh"
|
||||
#include "GPU_capabilities.hh"
|
||||
#include "GPU_compute.hh"
|
||||
#include "GPU_context.hh"
|
||||
#include "GPU_framebuffer.hh"
|
||||
#include "GPU_index_buffer.hh"
|
||||
#include "GPU_shader.hh"
|
||||
#include "GPU_shader_shared.hh"
|
||||
#include "GPU_state.hh"
|
||||
#include "GPU_texture.hh"
|
||||
#include "GPU_vertex_buffer.hh"
|
||||
#include "GPU_vertex_format.hh"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "gpu_shader_create_info.hh"
|
||||
#include "gpu_shader_create_info_private.hh"
|
||||
#include "gpu_shader_dependency_private.hh"
|
||||
#include "gpu_shader_private.hh"
|
||||
#include "gpu_testing.hh"
|
||||
|
||||
/* GTest expects operator<< and Print to be defined in the same namespace as the type itself. */
|
||||
static std::ostream &operator<<(std::ostream &os, const TestOutput &test_output)
|
||||
{
|
||||
os << "expect: " << testing::PrintToString(test_output.expect) << "\n";
|
||||
os << "result: " << testing::PrintToString(test_output.result) << "\n";
|
||||
os << "status: " << test_output.status;
|
||||
os << ", line: " << test_output.line;
|
||||
os << ", type: " << test_output.type;
|
||||
return os;
|
||||
}
|
||||
|
||||
namespace blender {
|
||||
|
||||
namespace gpu::tests {
|
||||
|
||||
using namespace blender::gpu::shader;
|
||||
|
||||
/* This test should contain pure GLSL source as this is what we are expecting from the Python API.
|
||||
* Make sure to keep it in sync with the Python API. */
|
||||
static void test_shader_python_compute()
|
||||
{
|
||||
using namespace shader;
|
||||
|
||||
ShaderCreateInfo create_info("pyGPU_Shader");
|
||||
create_info.image(0,
|
||||
TextureFormat::SFLOAT_16_16_16_16,
|
||||
Qualifier::write,
|
||||
ImageReadWriteType::image2D,
|
||||
"test_img");
|
||||
create_info.local_group_size(16, 16, 1);
|
||||
create_info.compute_source_generated =
|
||||
R"(void main(){imageStore(test_img, ivec2(gl_GlobalInvocationID.xy), vec4(0));})";
|
||||
|
||||
gpu::Shader *shader = GPU_shader_create_from_info_python(
|
||||
reinterpret_cast<GPUShaderCreateInfo *>(&create_info));
|
||||
EXPECT_NE(shader, nullptr);
|
||||
|
||||
GPU_shader_free(shader);
|
||||
}
|
||||
GPU_TEST(shader_python_compute)
|
||||
|
||||
/* This test should contain pure GLSL source as this is what we are expecting from the Python API.
|
||||
* Make sure to keep it in sync with the Python API. */
|
||||
static void test_shader_python_graphic()
|
||||
{
|
||||
using namespace shader;
|
||||
|
||||
ShaderCreateInfo create_info("pyGPU_Shader");
|
||||
create_info.vertex_in(0, Type::float4_t, "vert_in");
|
||||
create_info.fragment_out(0, Type::float4_t, "frag_out");
|
||||
create_info.vertex_source_generated = R"(void main(){gl_Position = vert_in;})";
|
||||
create_info.fragment_source_generated = R"(void main() { frag_out = gl_FragCoord; })";
|
||||
|
||||
gpu::Shader *shader = GPU_shader_create_from_info_python(
|
||||
reinterpret_cast<GPUShaderCreateInfo *>(&create_info));
|
||||
EXPECT_NE(shader, nullptr);
|
||||
|
||||
GPU_shader_free(shader);
|
||||
}
|
||||
GPU_TEST(shader_python_graphic)
|
||||
|
||||
static void test_shader_compute_2d()
|
||||
{
|
||||
|
||||
static constexpr uint SIZE = 512;
|
||||
|
||||
/* Build compute shader. */
|
||||
gpu::Shader *shader = GPU_shader_create_from_info_name("gpu_compute_2d_test");
|
||||
EXPECT_NE(shader, nullptr);
|
||||
|
||||
/* Create texture to store result and attach to shader. */
|
||||
gpu::Texture *texture = GPU_texture_create_2d("gpu_shader_compute_2d",
|
||||
SIZE,
|
||||
SIZE,
|
||||
1,
|
||||
TextureFormat::SFLOAT_32_32_32_32,
|
||||
GPU_TEXTURE_USAGE_GENERAL,
|
||||
nullptr);
|
||||
EXPECT_NE(texture, nullptr);
|
||||
|
||||
GPU_shader_bind(shader);
|
||||
GPU_texture_image_bind(texture, GPU_shader_get_sampler_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_UPDATE);
|
||||
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_delete(data);
|
||||
|
||||
/* Cleanup. */
|
||||
GPU_shader_unbind();
|
||||
GPU_texture_unbind(texture);
|
||||
GPU_texture_free(texture);
|
||||
GPU_shader_free(shader);
|
||||
}
|
||||
GPU_TEST(shader_compute_2d)
|
||||
|
||||
static void test_shader_compute_1d()
|
||||
{
|
||||
static constexpr uint SIZE = 10;
|
||||
|
||||
/* Build compute shader. */
|
||||
gpu::Shader *shader = GPU_shader_create_from_info_name("gpu_compute_1d_test");
|
||||
EXPECT_NE(shader, nullptr);
|
||||
|
||||
/* Construct Texture. */
|
||||
gpu::Texture *texture = GPU_texture_create_1d("gpu_shader_compute_1d",
|
||||
SIZE,
|
||||
1,
|
||||
TextureFormat::SFLOAT_32_32_32_32,
|
||||
GPU_TEXTURE_USAGE_GENERAL,
|
||||
nullptr);
|
||||
EXPECT_NE(texture, nullptr);
|
||||
|
||||
GPU_shader_bind(shader);
|
||||
GPU_texture_image_bind(texture, GPU_shader_get_sampler_binding(shader, "img_output"));
|
||||
|
||||
/* Dispatch compute task. */
|
||||
GPU_compute_dispatch(shader, SIZE, 1, 1);
|
||||
|
||||
/* Check if compute has been done. */
|
||||
GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE);
|
||||
|
||||
/* 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_delete(data);
|
||||
|
||||
/* Cleanup. */
|
||||
GPU_shader_unbind();
|
||||
GPU_texture_unbind(texture);
|
||||
GPU_texture_free(texture);
|
||||
GPU_shader_free(shader);
|
||||
}
|
||||
GPU_TEST(shader_compute_1d)
|
||||
|
||||
static void test_shader_compute_vbo()
|
||||
{
|
||||
static constexpr uint SIZE = 128;
|
||||
|
||||
/* Build compute shader. */
|
||||
gpu::Shader *shader = GPU_shader_create_from_info_name("gpu_compute_vbo_test");
|
||||
EXPECT_NE(shader, nullptr);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
/* Construct VBO. */
|
||||
GPUVertFormat format = {0};
|
||||
GPU_vertformat_attr_add(&format, "pos", gpu::VertAttrType::SFLOAT_32_32_32_32);
|
||||
VertBuf *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_binding(shader, "out_positions"));
|
||||
|
||||
/* Dispatch compute task. */
|
||||
GPU_compute_dispatch(shader, SIZE, 1, 1);
|
||||
|
||||
/* Check if compute has been done. */
|
||||
GPU_memory_barrier(GPU_BARRIER_BUFFER_UPDATE);
|
||||
|
||||
/* Download the vertex buffer. */
|
||||
float data[SIZE * 4];
|
||||
GPU_vertbuf_read(vbo, data);
|
||||
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(shader_compute_vbo)
|
||||
|
||||
static void test_shader_compute_ibo()
|
||||
{
|
||||
static constexpr uint SIZE = 128;
|
||||
|
||||
/* Build compute shader. */
|
||||
gpu::Shader *shader = GPU_shader_create_from_info_name("gpu_compute_ibo_test");
|
||||
EXPECT_NE(shader, nullptr);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
/* Construct IBO. */
|
||||
IndexBuf *ibo = GPU_indexbuf_build_on_device(SIZE);
|
||||
GPU_indexbuf_bind_as_ssbo(ibo, GPU_shader_get_ssbo_binding(shader, "out_indices"));
|
||||
|
||||
/* Dispatch compute task. */
|
||||
GPU_compute_dispatch(shader, SIZE, 1, 1);
|
||||
|
||||
/* Check if compute has been done. */
|
||||
GPU_memory_barrier(GPU_BARRIER_BUFFER_UPDATE);
|
||||
|
||||
/* Download the index buffer. */
|
||||
uint32_t data[SIZE];
|
||||
GPU_indexbuf_read(ibo, data);
|
||||
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(shader_compute_ibo)
|
||||
|
||||
static void test_shader_compute_ssbo()
|
||||
{
|
||||
static constexpr uint SIZE = 128;
|
||||
|
||||
/* Build compute shader. */
|
||||
gpu::Shader *shader = GPU_shader_create_from_info_name("gpu_compute_ssbo_test");
|
||||
EXPECT_NE(shader, nullptr);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
/* Construct SSBO. */
|
||||
StorageBuf *ssbo = GPU_storagebuf_create_ex(
|
||||
SIZE * sizeof(uint32_t), nullptr, GPU_USAGE_DEVICE_ONLY, __func__);
|
||||
GPU_storagebuf_bind(ssbo, GPU_shader_get_ssbo_binding(shader, "data_out"));
|
||||
|
||||
/* Dispatch compute task. */
|
||||
GPU_compute_dispatch(shader, SIZE, 1, 1);
|
||||
|
||||
/* Check if compute has been done. */
|
||||
GPU_memory_barrier(GPU_BARRIER_BUFFER_UPDATE);
|
||||
|
||||
/* Download the storage buffer. */
|
||||
uint32_t data[SIZE];
|
||||
GPU_storagebuf_read(ssbo, data);
|
||||
for (int index = 0; index < SIZE; index++) {
|
||||
uint32_t expected = index * 4;
|
||||
EXPECT_EQ(data[index], expected);
|
||||
}
|
||||
|
||||
/* Cleanup. */
|
||||
GPU_shader_unbind();
|
||||
GPU_storagebuf_free(ssbo);
|
||||
GPU_shader_free(shader);
|
||||
}
|
||||
GPU_TEST(shader_compute_ssbo)
|
||||
|
||||
static void test_shader_ssbo_binding()
|
||||
{
|
||||
/* Build compute shader. */
|
||||
gpu::Shader *shader = GPU_shader_create_from_info_name("gpu_compute_ssbo_binding_test");
|
||||
EXPECT_NE(shader, nullptr);
|
||||
|
||||
/* Perform tests. */
|
||||
EXPECT_EQ(0, GPU_shader_get_ssbo_binding(shader, "data0"));
|
||||
EXPECT_EQ(1, GPU_shader_get_ssbo_binding(shader, "data1"));
|
||||
|
||||
/* Cleanup. */
|
||||
GPU_shader_free(shader);
|
||||
}
|
||||
GPU_TEST(shader_ssbo_binding)
|
||||
|
||||
#ifdef WITH_METAL_BACKEND
|
||||
static void test_shader_sampler_argument_buffer_binding()
|
||||
{
|
||||
gpu::Shader *shader = GPU_shader_create_from_info_name("gpu_sampler_arg_buf_test");
|
||||
EXPECT_NE(shader, nullptr);
|
||||
|
||||
gpu::StorageBuf *ssbo = GPU_storagebuf_create(sizeof(float) * 4 * 18);
|
||||
|
||||
GPU_storagebuf_bind(ssbo, GPU_shader_get_ssbo_binding(shader, "data_out"));
|
||||
|
||||
float4 tx_data(-1.0f, 1.0f, 2.0f, 3.0f);
|
||||
gpu::Texture *tex = GPU_texture_create_2d(
|
||||
"tx", 1, 1, 1, TextureFormat::SFLOAT_32_32_32_32, GPU_TEXTURE_USAGE_SHADER_READ, &tx_data.x);
|
||||
|
||||
GPU_texture_bind(tex, GPU_shader_get_sampler_binding(shader, "tex_1"));
|
||||
GPU_texture_bind(tex, GPU_shader_get_sampler_binding(shader, "tex_2"));
|
||||
GPU_texture_bind(tex, GPU_shader_get_sampler_binding(shader, "tex_3"));
|
||||
GPU_texture_bind(tex, GPU_shader_get_sampler_binding(shader, "tex_4"));
|
||||
GPU_texture_bind(tex, GPU_shader_get_sampler_binding(shader, "tex_5"));
|
||||
GPU_texture_bind(tex, GPU_shader_get_sampler_binding(shader, "tex_6"));
|
||||
GPU_texture_bind(tex, GPU_shader_get_sampler_binding(shader, "tex_7"));
|
||||
GPU_texture_bind(tex, GPU_shader_get_sampler_binding(shader, "tex_8"));
|
||||
GPU_texture_bind(tex, GPU_shader_get_sampler_binding(shader, "tex_9"));
|
||||
GPU_texture_bind(tex, GPU_shader_get_sampler_binding(shader, "tex_10"));
|
||||
GPU_texture_bind(tex, GPU_shader_get_sampler_binding(shader, "tex_11"));
|
||||
GPU_texture_bind(tex, GPU_shader_get_sampler_binding(shader, "tex_12"));
|
||||
GPU_texture_bind(tex, GPU_shader_get_sampler_binding(shader, "tex_13"));
|
||||
GPU_texture_bind(tex, GPU_shader_get_sampler_binding(shader, "tex_14"));
|
||||
GPU_texture_bind(tex, GPU_shader_get_sampler_binding(shader, "tex_15"));
|
||||
GPU_texture_bind(tex, GPU_shader_get_sampler_binding(shader, "tex_16"));
|
||||
GPU_texture_bind(tex, GPU_shader_get_sampler_binding(shader, "tex_17"));
|
||||
GPU_texture_bind(tex, GPU_shader_get_sampler_binding(shader, "tex_18"));
|
||||
|
||||
gpu::FrameBuffer *fb = GPU_framebuffer_create("test_fb");
|
||||
GPU_framebuffer_default_size(fb, 1, 1);
|
||||
GPU_framebuffer_bind(fb);
|
||||
|
||||
Batch *batch = GPU_batch_create_procedural(GPU_PRIM_POINTS, 3);
|
||||
|
||||
GPU_batch_set_shader(batch, shader);
|
||||
GPU_batch_draw(batch);
|
||||
|
||||
GPU_batch_discard(batch);
|
||||
|
||||
GPU_finish();
|
||||
|
||||
float4 data[18];
|
||||
GPU_storagebuf_read(ssbo, &data);
|
||||
|
||||
for (int index = 0; index < 18; index++) {
|
||||
EXPECT_EQ(data[index], tx_data);
|
||||
}
|
||||
|
||||
/* Cleanup. */
|
||||
GPU_shader_unbind();
|
||||
GPU_framebuffer_free(fb);
|
||||
GPU_storagebuf_free(ssbo);
|
||||
GPU_texture_free(tex);
|
||||
GPU_shader_free(shader);
|
||||
}
|
||||
GPU_TEST(shader_sampler_argument_buffer_binding)
|
||||
#endif
|
||||
|
||||
static void test_shader_texture_atomic()
|
||||
{
|
||||
gpu::Shader *shader = GPU_shader_create_from_info_name("gpu_texture_atomic_test");
|
||||
EXPECT_NE(shader, nullptr);
|
||||
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE |
|
||||
GPU_TEXTURE_USAGE_ATOMIC;
|
||||
uint32_t tx_data[4] = {0u, 0u, 0u, 0u};
|
||||
gpu::Texture *tex_2d = GPU_texture_create_2d(
|
||||
"tex_2d", 1, 1, 1, TextureFormat::UINT_32, usage, nullptr);
|
||||
gpu::Texture *tex_2d_array = GPU_texture_create_2d_array(
|
||||
"tex_2d_array", 1, 1, 2, 1, TextureFormat::UINT_32, usage, nullptr);
|
||||
gpu::Texture *tex_3d = GPU_texture_create_3d(
|
||||
"tex_3d", 1, 1, 2, 1, TextureFormat::UINT_32, usage, nullptr);
|
||||
|
||||
GPU_texture_clear(tex_2d, eGPUDataFormat::GPU_DATA_UINT, &tx_data[0]);
|
||||
GPU_texture_clear(tex_2d_array, eGPUDataFormat::GPU_DATA_UINT, &tx_data[0]);
|
||||
GPU_texture_clear(tex_3d, eGPUDataFormat::GPU_DATA_UINT, &tx_data[0]);
|
||||
|
||||
GPU_texture_image_bind(tex_2d, GPU_shader_get_sampler_binding(shader, "img_atomic_2D"));
|
||||
GPU_texture_image_bind(tex_2d_array,
|
||||
GPU_shader_get_sampler_binding(shader, "img_atomic_2D_array"));
|
||||
GPU_texture_image_bind(tex_3d, GPU_shader_get_sampler_binding(shader, "img_atomic_3D"));
|
||||
|
||||
gpu::StorageBuf *ssbo = GPU_storagebuf_create(sizeof(uint32_t) * 5);
|
||||
GPU_storagebuf_bind(ssbo, GPU_shader_get_ssbo_binding(shader, "data_out"));
|
||||
|
||||
GPU_shader_bind(shader);
|
||||
GPU_shader_uniform_1b(shader, "write_phase", true);
|
||||
GPU_compute_dispatch(shader, 1, 1, 1);
|
||||
GPU_memory_barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
|
||||
|
||||
/* We can't host read atomic texture. So we do a manual read phase to a SSBO. */
|
||||
GPU_shader_uniform_1b(shader, "write_phase", false);
|
||||
GPU_compute_dispatch(shader, 1, 1, 1);
|
||||
GPU_memory_barrier(GPU_BARRIER_BUFFER_UPDATE);
|
||||
GPU_finish();
|
||||
|
||||
uint32_t data[5];
|
||||
GPU_storagebuf_read(ssbo, &data);
|
||||
|
||||
EXPECT_EQ(data[0], 0xFFFFFFFFu);
|
||||
EXPECT_EQ(data[1], 0xFFFFFFFFu);
|
||||
EXPECT_EQ(data[2], 0xFFFFFFFFu);
|
||||
EXPECT_EQ(data[3], 0xFFFFFFFFu);
|
||||
EXPECT_EQ(data[4], 0xFFFFFFFFu);
|
||||
|
||||
/* Cleanup. */
|
||||
GPU_texture_free(tex_2d);
|
||||
GPU_texture_free(tex_2d_array);
|
||||
GPU_texture_free(tex_3d);
|
||||
GPU_storagebuf_free(ssbo);
|
||||
GPU_shader_unbind();
|
||||
GPU_shader_free(shader);
|
||||
}
|
||||
GPU_TEST(shader_texture_atomic)
|
||||
|
||||
static std::string print_test_data(const TestOutputRawData &raw, TestType type)
|
||||
{
|
||||
std::stringstream ss;
|
||||
switch (type) {
|
||||
case TEST_TYPE_BOOL:
|
||||
case TEST_TYPE_UINT:
|
||||
ss << *reinterpret_cast<const uint *>(&raw);
|
||||
break;
|
||||
case TEST_TYPE_INT:
|
||||
ss << *reinterpret_cast<const int *>(&raw);
|
||||
break;
|
||||
case TEST_TYPE_FLOAT:
|
||||
ss << *reinterpret_cast<const float *>(&raw);
|
||||
break;
|
||||
case TEST_TYPE_IVEC2:
|
||||
ss << *reinterpret_cast<const int2 *>(&raw);
|
||||
break;
|
||||
case TEST_TYPE_IVEC3:
|
||||
ss << *reinterpret_cast<const int3 *>(&raw);
|
||||
break;
|
||||
case TEST_TYPE_IVEC4:
|
||||
ss << *reinterpret_cast<const int4 *>(&raw);
|
||||
break;
|
||||
case TEST_TYPE_UVEC2:
|
||||
ss << *reinterpret_cast<const uint2 *>(&raw);
|
||||
break;
|
||||
case TEST_TYPE_UVEC3:
|
||||
ss << *reinterpret_cast<const uint3 *>(&raw);
|
||||
break;
|
||||
case TEST_TYPE_UVEC4:
|
||||
ss << *reinterpret_cast<const uint4 *>(&raw);
|
||||
break;
|
||||
case TEST_TYPE_VEC2:
|
||||
ss << *reinterpret_cast<const float2 *>(&raw);
|
||||
break;
|
||||
case TEST_TYPE_VEC3:
|
||||
ss << *reinterpret_cast<const float3 *>(&raw);
|
||||
break;
|
||||
case TEST_TYPE_VEC4:
|
||||
ss << *reinterpret_cast<const float4 *>(&raw);
|
||||
break;
|
||||
case TEST_TYPE_MAT2X2:
|
||||
ss << *reinterpret_cast<const float2x2 *>(&raw);
|
||||
break;
|
||||
case TEST_TYPE_MAT2X3:
|
||||
ss << *reinterpret_cast<const float2x3 *>(&raw);
|
||||
break;
|
||||
case TEST_TYPE_MAT2X4:
|
||||
ss << *reinterpret_cast<const float2x4 *>(&raw);
|
||||
break;
|
||||
case TEST_TYPE_MAT3X2:
|
||||
ss << *reinterpret_cast<const float3x2 *>(&raw);
|
||||
break;
|
||||
case TEST_TYPE_MAT3X3:
|
||||
ss << *reinterpret_cast<const float3x3 *>(&raw);
|
||||
break;
|
||||
case TEST_TYPE_MAT3X4:
|
||||
ss << *reinterpret_cast<const float3x4 *>(&raw);
|
||||
break;
|
||||
case TEST_TYPE_MAT4X2:
|
||||
ss << *reinterpret_cast<const float4x2 *>(&raw);
|
||||
break;
|
||||
case TEST_TYPE_MAT4X3:
|
||||
ss << *reinterpret_cast<const float4x3 *>(&raw);
|
||||
break;
|
||||
case TEST_TYPE_MAT4X4:
|
||||
ss << *reinterpret_cast<const float4x4 *>(&raw);
|
||||
break;
|
||||
default:
|
||||
ss << *reinterpret_cast<const MatBase<uint, 4, 4> *>(&raw);
|
||||
break;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static StringRef print_test_line(StringRefNull test_src, int64_t test_line)
|
||||
{
|
||||
std::string needle = "].line = " + std::to_string(test_line) + ";";
|
||||
|
||||
int64_t pos = test_src.find(needle);
|
||||
if (pos == std::string::npos) {
|
||||
return "";
|
||||
}
|
||||
int64_t start = test_src.rfind('\n', pos);
|
||||
if (start == std::string::npos) {
|
||||
return "";
|
||||
}
|
||||
int64_t end = test_src.find('\n', pos);
|
||||
if (end == std::string::npos) {
|
||||
return "";
|
||||
}
|
||||
return test_src.substr(start, end - start);
|
||||
}
|
||||
|
||||
static void gpu_shader_lib_test(StringRefNull create_info_name)
|
||||
{
|
||||
using namespace shader;
|
||||
|
||||
GPU_render_begin();
|
||||
|
||||
const GPUShaderCreateInfo *info = gpu_shader_create_info_get(create_info_name.c_str());
|
||||
gpu::shader::ShaderCreateInfo create_info =
|
||||
*reinterpret_cast<const gpu::shader::ShaderCreateInfo *>(info);
|
||||
|
||||
StringRefNull test_src_name = create_info.compute_source_;
|
||||
StringRefNull test_src = gpu_shader_dependency_get_source(test_src_name);
|
||||
|
||||
gpu::Shader *shader = GPU_shader_create_from_info(
|
||||
reinterpret_cast<GPUShaderCreateInfo *>(&create_info));
|
||||
|
||||
int test_count = 0;
|
||||
/* Count tests. */
|
||||
int64_t pos = 0;
|
||||
StringRefNull target = "EXPECT_";
|
||||
while ((pos = test_src.find(target, pos)) != std::string::npos) {
|
||||
test_count++;
|
||||
pos += sizeof("EXPECT_");
|
||||
}
|
||||
|
||||
gpu::StorageBuf *output_buf = GPU_storagebuf_create(test_count * sizeof(TestOutput));
|
||||
|
||||
GPU_storagebuf_clear(output_buf, 0xFFFFFFFFu);
|
||||
GPU_storagebuf_bind(output_buf, 0);
|
||||
|
||||
GPU_compute_dispatch(shader, 1, 1, 1);
|
||||
|
||||
GPU_finish();
|
||||
|
||||
blender::Vector<TestOutput> tests;
|
||||
tests.resize(test_count);
|
||||
GPU_storagebuf_read(output_buf, tests.data());
|
||||
|
||||
for (const TestOutput &test : tests) {
|
||||
if (ELEM(test.status, TEST_STATUS_NONE, TEST_STATUS_PASSED)) {
|
||||
continue;
|
||||
}
|
||||
if (test.status == TEST_STATUS_FAILED) {
|
||||
ADD_FAILURE_AT(test_src_name.c_str(), test.line)
|
||||
<< "Value of: " << print_test_line(test_src, test.line) << "\n"
|
||||
<< " Actual: " << print_test_data(test.expect, TestType(test.type)) << "\n"
|
||||
<< "Expected: " << print_test_data(test.result, TestType(test.type)) << "\n";
|
||||
}
|
||||
else {
|
||||
ADD_FAILURE() << "Unexpected test status " << test.status << ", test output:\n" << test;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cleanup. */
|
||||
GPU_shader_unbind();
|
||||
GPU_shader_free(shader);
|
||||
GPU_storagebuf_free(output_buf);
|
||||
|
||||
GPU_render_end();
|
||||
}
|
||||
|
||||
static void test_math_lib()
|
||||
{
|
||||
gpu_shader_lib_test("gpu_math_test");
|
||||
}
|
||||
GPU_TEST(math_lib)
|
||||
|
||||
static void test_eevee_lib()
|
||||
{
|
||||
if (GPU_type_matches_ex(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_OFFICIAL, GPU_BACKEND_VULKAN))
|
||||
{
|
||||
GTEST_SKIP() << "Test is failing on NVIDIA/Vulkan for unknown reasons. It runs, but outputs "
|
||||
"back the initial value 0xFFFFFFFFu.";
|
||||
}
|
||||
|
||||
/* TODO(fclem): Not passing currently. Need to be updated. */
|
||||
// gpu_shader_lib_test("eevee_shadow_test.bsl.hh");
|
||||
gpu_shader_lib_test("eevee_test_occupancy");
|
||||
gpu_shader_lib_test("eevee_test_fast_gi");
|
||||
/* Disabled on mac because of a buffer reuse bug. Seems to be fixed on Tahoe. */
|
||||
if (!GPU_type_matches(GPU_DEVICE_APPLE, GPU_OS_MAC, GPU_DRIVER_ANY)) {
|
||||
gpu_shader_lib_test("eevee_test_gbuffer_normal");
|
||||
gpu_shader_lib_test("eevee_test_gbuffer_closure");
|
||||
}
|
||||
}
|
||||
GPU_TEST(eevee_lib)
|
||||
|
||||
static void test_shader_preprocessor()
|
||||
{
|
||||
{
|
||||
std::string input = R"(
|
||||
# define MACRO() A
|
||||
MACRO()
|
||||
)";
|
||||
std::string expect = R"(
|
||||
|
||||
A
|
||||
)";
|
||||
std::string result = blender::gpu::Shader::run_preprocessor(input, true);
|
||||
EXPECT_EQ(expect, result);
|
||||
}
|
||||
{
|
||||
std::string input = R"(
|
||||
# define MACRO(A, B)
|
||||
MACRO(a, 1)
|
||||
)";
|
||||
std::string expect = R"(
|
||||
|
||||
|
||||
)";
|
||||
std::string result = blender::gpu::Shader::run_preprocessor(input, true);
|
||||
EXPECT_EQ(expect, result);
|
||||
}
|
||||
{
|
||||
std::string input = R"(
|
||||
#define MACRO(A, B, ...) \
|
||||
A to_##A(B m) \
|
||||
{ \
|
||||
return A(__VA_ARGS__); \
|
||||
}
|
||||
|
||||
MACRO(a, b, 1, 2)
|
||||
)";
|
||||
std::string expect = R"(
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
a to_a(b m) { return a(1, 2); }
|
||||
)";
|
||||
std::string result = blender::gpu::Shader::run_preprocessor(input, true);
|
||||
EXPECT_EQ(expect, result);
|
||||
}
|
||||
{
|
||||
std::string input = R"(
|
||||
# if 1
|
||||
# define drw_view_id 0
|
||||
# else
|
||||
uint drw_view_id = 0;
|
||||
# endif
|
||||
)";
|
||||
std::string expect = R"(
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
)";
|
||||
std::string result = blender::gpu::Shader::run_preprocessor(input, true);
|
||||
EXPECT_EQ(expect, result);
|
||||
}
|
||||
{
|
||||
std::string input = R"(
|
||||
#define SMAATexturePass2D(tex) tex
|
||||
#define mad(a, b, c) (a * b + c)
|
||||
mad(-(255.0f / 127.0f), SMAASearchLength(SMAATexturePass2D(searchTex), e, 0.0f), 3.25f);
|
||||
)";
|
||||
std::string expect = R"(
|
||||
|
||||
|
||||
(-(255.0f / 127.0f) * SMAASearchLength(searchTex, e, 0.0f) + 3.25f);
|
||||
)";
|
||||
std::string result = blender::gpu::Shader::run_preprocessor(input, true);
|
||||
EXPECT_EQ(expect, result);
|
||||
}
|
||||
{
|
||||
std::string input = R"(
|
||||
#define A() B
|
||||
A)";
|
||||
std::string expect = R"(
|
||||
|
||||
A)";
|
||||
std::string result = blender::gpu::Shader::run_preprocessor(input, true);
|
||||
EXPECT_EQ(expect, result);
|
||||
}
|
||||
{
|
||||
std::string input = R"(
|
||||
#define A(a, b) C(a[b])[(b)]
|
||||
#define B(a, b) (A(a, b) != 0u)
|
||||
B(foo, bar);
|
||||
)";
|
||||
std::string expect = R"(
|
||||
|
||||
|
||||
(C(foo[bar])[(bar)] != 0u);
|
||||
)";
|
||||
std::string result = blender::gpu::Shader::run_preprocessor(input, true);
|
||||
EXPECT_EQ(expect, result);
|
||||
}
|
||||
{
|
||||
std::string input = R"(
|
||||
#define B2 5
|
||||
#define A(a,b) a##b
|
||||
#define B(a,b) a ## b
|
||||
#define C 3
|
||||
#define D(a,b) B(a,b)
|
||||
A( , )
|
||||
A(,2)
|
||||
A(1, )
|
||||
A(1,2)
|
||||
A(B,2)
|
||||
B(B,2)
|
||||
B(C,2)
|
||||
D(C,2)
|
||||
)";
|
||||
std::string expect = R"(
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
2
|
||||
1
|
||||
12
|
||||
5
|
||||
5
|
||||
C2
|
||||
32
|
||||
)";
|
||||
std::string result = blender::gpu::Shader::run_preprocessor(input, true);
|
||||
EXPECT_EQ(expect, result);
|
||||
}
|
||||
{
|
||||
std::string input = R"(
|
||||
#define ATOMIC_OP_EX(A, B, C) \
|
||||
template<typename T> T atomic##B(A T &mem, T data) \
|
||||
{ \
|
||||
return atomic_##C##_explicit((A _atomic<T> *)&mem, data, memory_order_relaxed); \
|
||||
}
|
||||
|
||||
#define ATOMIC_OP(B, C) \
|
||||
ATOMIC_OP_EX(threadgroup, B, C) \
|
||||
ATOMIC_OP_EX(device, B, C)
|
||||
|
||||
ATOMIC_OP(Max, fetch_max)
|
||||
)";
|
||||
std::string expect = R"(
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T> T atomicMax(threadgroup T &mem, T data) { return atomic_fetch_max_explicit((threadgroup _atomic<T> *)&mem, data, memory_order_relaxed); } template<typename T> T atomicMax(device T &mem, T data) { return atomic_fetch_max_explicit((device _atomic<T> *)&mem, data, memory_order_relaxed); }
|
||||
)";
|
||||
std::string result = blender::gpu::Shader::run_preprocessor(input, true);
|
||||
EXPECT_EQ(expect, result);
|
||||
}
|
||||
{
|
||||
std::string input = R"(
|
||||
#define A
|
||||
#if defined(A) && !defined ( B ) && defined A && !defined B
|
||||
High there!
|
||||
#endif
|
||||
)";
|
||||
std::string expect = R"(
|
||||
|
||||
|
||||
High there!
|
||||
|
||||
)";
|
||||
std::string result = blender::gpu::Shader::run_preprocessor(input, true);
|
||||
EXPECT_EQ(expect, result);
|
||||
}
|
||||
{
|
||||
/* Undefined identifier should evaluated to 0. */
|
||||
std::string input = R"(
|
||||
#if !A
|
||||
A
|
||||
#endif
|
||||
)";
|
||||
std::string expect = R"(
|
||||
|
||||
A
|
||||
|
||||
)";
|
||||
std::string result = blender::gpu::Shader::run_preprocessor(input, true);
|
||||
EXPECT_EQ(expect, result);
|
||||
}
|
||||
{
|
||||
/* Infinite recursion. */
|
||||
std::string input = R"(
|
||||
#define X (X + 1)
|
||||
X
|
||||
)";
|
||||
std::string expect = R"(
|
||||
|
||||
(X + 1)
|
||||
)";
|
||||
std::string result = blender::gpu::Shader::run_preprocessor(input, true);
|
||||
EXPECT_EQ(expect, result);
|
||||
}
|
||||
{
|
||||
/* Arguments must be expanded before substitution. */
|
||||
std::string input = R"(
|
||||
#define ESCAPE(x) x
|
||||
#define STR(x) x
|
||||
#define NAME shader_func
|
||||
STR(ESCAPE(NAME))
|
||||
)";
|
||||
/* STR(ESCAPE(NAME)) -> STR(shader_func) -> "shader_func" */
|
||||
std::string expect = R"(
|
||||
|
||||
|
||||
|
||||
shader_func
|
||||
)";
|
||||
std::string result = blender::gpu::Shader::run_preprocessor(input, true);
|
||||
EXPECT_EQ(expect, result);
|
||||
}
|
||||
{
|
||||
/* Commas inside parentheses should not split macro arguments. */
|
||||
std::string input = R"(
|
||||
#define GLSL_FUNC(a, b) a = b;
|
||||
GLSL_FUNC(vec3(0.0, 1.0, 0.0), color)
|
||||
)";
|
||||
std::string expect = R"(
|
||||
|
||||
vec3(0.0, 1.0, 0.0) = color;
|
||||
)";
|
||||
std::string result = blender::gpu::Shader::run_preprocessor(input, true);
|
||||
EXPECT_EQ(expect, result);
|
||||
}
|
||||
{
|
||||
/* PITFALL: Pasting an empty argument. */
|
||||
std::string input = R"(
|
||||
#define CONCAT(a, b) a##b
|
||||
CONCAT(prefix_, )
|
||||
CONCAT(, _suffix)
|
||||
)";
|
||||
std::string expect = R"(
|
||||
|
||||
prefix_
|
||||
_suffix
|
||||
)";
|
||||
std::string result = blender::gpu::Shader::run_preprocessor(input, true);
|
||||
EXPECT_EQ(expect, result);
|
||||
}
|
||||
{
|
||||
/* PITFALL: Evaluation of complex logical expressions and nested #if. */
|
||||
std::string input = R"(
|
||||
#define VERSION 2
|
||||
#if (VERSION == 1 + 1) && (UNDEFINED_VAR == 0)
|
||||
#if 0
|
||||
Inside nested false
|
||||
#else
|
||||
Success
|
||||
#endif
|
||||
#else
|
||||
Success
|
||||
#endif
|
||||
)";
|
||||
std::string expect = R"(
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Success
|
||||
|
||||
|
||||
|
||||
|
||||
)";
|
||||
std::string result = blender::gpu::Shader::run_preprocessor(input, true);
|
||||
EXPECT_EQ(expect, result);
|
||||
}
|
||||
{
|
||||
std::string input = R"(
|
||||
#define saturate(a) clamp(a, 0.0f, 1.0f)
|
||||
float s = saturate(pow5f(1.0f - saturate(HV)));
|
||||
)";
|
||||
std::string expect = R"(
|
||||
|
||||
float s = clamp(pow5f(1.0f - clamp(HV, 0.0f, 1.0f)), 0.0f, 1.0f);
|
||||
)";
|
||||
std::string result = blender::gpu::Shader::run_preprocessor(input, true);
|
||||
EXPECT_EQ(expect, result);
|
||||
}
|
||||
{
|
||||
std::string input = R"(
|
||||
#define POINTS
|
||||
H
|
||||
#if defined(POINTS)
|
||||
I
|
||||
#else
|
||||
J
|
||||
# if !defined(SELECT_ENABLE)
|
||||
K
|
||||
# endif
|
||||
P
|
||||
#endif
|
||||
Q
|
||||
)";
|
||||
std::string expect = R"(
|
||||
|
||||
H
|
||||
|
||||
I
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Q
|
||||
)";
|
||||
std::string result = blender::gpu::Shader::run_preprocessor(input, true);
|
||||
EXPECT_EQ(expect, result);
|
||||
}
|
||||
}
|
||||
GPU_TEST(shader_preprocessor)
|
||||
|
||||
} // namespace gpu::tests
|
||||
} // namespace blender
|
||||
@@ -0,0 +1,54 @@
|
||||
# SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
set(INC_GLSL
|
||||
.
|
||||
..
|
||||
../..
|
||||
../../intern
|
||||
|
||||
../../shaders/common
|
||||
../../shaders
|
||||
)
|
||||
|
||||
set(SRC_GLSL_VERT
|
||||
gpu_framebuffer_layer_viewport_test.glsl
|
||||
gpu_framebuffer_subpass_input_test.glsl
|
||||
gpu_texture_test.glsl
|
||||
)
|
||||
|
||||
set(SRC_GLSL_FRAG
|
||||
gpu_framebuffer_layer_viewport_test.glsl
|
||||
gpu_framebuffer_subpass_input_test.glsl
|
||||
gpu_specialization_test.glsl
|
||||
gpu_texture_test.glsl
|
||||
)
|
||||
|
||||
set(SRC_GLSL_COMP
|
||||
gpu_buffer_texture_test.glsl
|
||||
gpu_compute_1d_test.glsl
|
||||
gpu_compute_2d_test.glsl
|
||||
gpu_compute_dummy_test.glsl
|
||||
gpu_compute_ibo_test.glsl
|
||||
gpu_compute_ssbo_test.glsl
|
||||
gpu_compute_vbo_test.glsl
|
||||
gpu_push_constants_test.glsl
|
||||
gpu_specialization_test.glsl
|
||||
gpu_texture_atomic_test.glsl
|
||||
)
|
||||
|
||||
set(SRC_BSL
|
||||
bsl_shader_linting.cc
|
||||
)
|
||||
|
||||
# Compile shaders with shader code.
|
||||
if(WITH_GPU_SHADER_CPP_COMPILATION)
|
||||
compile_sources_as_cpp(gpu_test_cpp_shaders_vert "${SRC_GLSL_VERT}" "GPU_VERTEX_SHADER")
|
||||
compile_sources_as_cpp(gpu_test_cpp_shaders_frag "${SRC_GLSL_FRAG}" "GPU_FRAGMENT_SHADER")
|
||||
compile_sources_as_cpp(gpu_test_cpp_shaders_comp "${SRC_GLSL_COMP}" "GPU_COMPUTE_SHADER")
|
||||
compile_sources_as_cpp(gpu_test_cpp_shaders_bsl "${SRC_BSL}" "")
|
||||
# Only enable to make sure they compile on their own.
|
||||
# Otherwise it creates a warning about `pragma once`.
|
||||
# compile_sources_as_cpp(gpu_test_cpp_shaders_lib "${SRC_GLSL_LIB}" "GPU_LIBRARY_SHADER")
|
||||
endif()
|
||||
@@ -0,0 +1,11 @@
|
||||
/* SPDX-FileCopyrightText: 2026 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/**
|
||||
* Compile shader files as C++ inside one compilation unit to lint syntax and get IDE integration.
|
||||
*/
|
||||
|
||||
#include "gpu_math_test.bsl.hh" /* IWYU pragma: export */
|
||||
|
||||
void main() {}
|
||||
@@ -0,0 +1,14 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "infos/gpu_shader_test_infos.hh"
|
||||
|
||||
COMPUTE_SHADER_CREATE_INFO(gpu_buffer_texture_test)
|
||||
|
||||
void main()
|
||||
{
|
||||
int index = int(gl_GlobalInvocationID.x);
|
||||
float value = texelFetch(bufferTexture, index).r;
|
||||
data_out[index] = value;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "infos/gpu_shader_test_infos.hh"
|
||||
|
||||
COMPUTE_SHADER_CREATE_INFO(gpu_compute_1d_test)
|
||||
|
||||
void main()
|
||||
{
|
||||
int index = int(gl_GlobalInvocationID.x);
|
||||
float4 pos = float4(gl_GlobalInvocationID.x);
|
||||
imageStore(img_output, index, pos);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "infos/gpu_shader_test_infos.hh"
|
||||
|
||||
COMPUTE_SHADER_CREATE_INFO(gpu_compute_2d_test)
|
||||
|
||||
void main()
|
||||
{
|
||||
float4 pixel = float4(1.0f, 0.5f, 0.2f, 1.0f);
|
||||
imageStore(img_output, int2(gl_GlobalInvocationID.xy), pixel);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "infos/gpu_shader_test_infos.hh"
|
||||
|
||||
COMPUTE_SHADER_CREATE_INFO(gpu_compute_ssbo_binding_test)
|
||||
|
||||
void main() {}
|
||||
@@ -0,0 +1,13 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "infos/gpu_shader_test_infos.hh"
|
||||
|
||||
COMPUTE_SHADER_CREATE_INFO(gpu_compute_ibo_test)
|
||||
|
||||
void main()
|
||||
{
|
||||
int store_index = int(gl_GlobalInvocationID.x);
|
||||
out_indices[store_index] = store_index;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "infos/gpu_shader_test_infos.hh"
|
||||
|
||||
COMPUTE_SHADER_CREATE_INFO(gpu_compute_ssbo_test)
|
||||
|
||||
void main()
|
||||
{
|
||||
int store_index = int(gl_GlobalInvocationID.x);
|
||||
data_out[store_index] = store_index * 4;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "infos/gpu_shader_test_infos.hh"
|
||||
|
||||
COMPUTE_SHADER_CREATE_INFO(gpu_compute_vbo_test)
|
||||
|
||||
void main()
|
||||
{
|
||||
int index = int(gl_GlobalInvocationID.x);
|
||||
float4 pos = float4(gl_GlobalInvocationID.x);
|
||||
out_positions[index] = pos;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "gpu_shader_compat.hh"
|
||||
|
||||
#include "infos/gpu_shader_test_infos.hh"
|
||||
|
||||
#ifdef GPU_VERTEX_SHADER
|
||||
VERTEX_SHADER_CREATE_INFO(gpu_framebuffer_layer_viewport_test)
|
||||
|
||||
void main()
|
||||
{
|
||||
/* Full-screen triangle. */
|
||||
int v = gl_VertexID % 3;
|
||||
float x = -1.0f + float((v & 1) << 2);
|
||||
float y = -1.0f + float((v & 2) << 1);
|
||||
/* NOTE: Make it cover more than one viewport to test default scissors. */
|
||||
gl_Position = float4(x * 2.0f, y * 2.0f, 1.0f, 1.0f);
|
||||
|
||||
int index = gl_VertexID / 3;
|
||||
gpu_ViewportIndex = index % 16;
|
||||
gpu_Layer = index / 16;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef GPU_FRAGMENT_SHADER
|
||||
FRAGMENT_SHADER_CREATE_INFO(gpu_framebuffer_layer_viewport_test)
|
||||
|
||||
void main()
|
||||
{
|
||||
out_value = int2(gpu_Layer, gpu_ViewportIndex);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "gpu_shader_compat.hh"
|
||||
|
||||
#include "infos/gpu_shader_test_infos.hh"
|
||||
|
||||
#ifdef GPU_VERTEX_SHADER
|
||||
VERTEX_SHADER_CREATE_INFO(gpu_framebuffer_subpass_input_test)
|
||||
|
||||
void main()
|
||||
{
|
||||
/* Full-screen triangle. */
|
||||
int v = gl_VertexID % 3;
|
||||
float x = -1.0f + float((v & 1) << 2);
|
||||
float y = -1.0f + float((v & 2) << 1);
|
||||
gl_Position = float4(x, y, 1.0f, 1.0f);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef GPU_FRAGMENT_SHADER
|
||||
FRAGMENT_SHADER_CREATE_INFO(gpu_framebuffer_subpass_input_test)
|
||||
|
||||
# ifdef WRITE
|
||||
void main()
|
||||
{
|
||||
out_value = 0xDEADBEEF;
|
||||
}
|
||||
# endif
|
||||
|
||||
# ifdef READ
|
||||
void main()
|
||||
{
|
||||
out_value = in_value + 495;
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,355 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/* Directive for resetting the line numbering so the failing tests lines can be printed.
|
||||
* This conflict with the shader compiler error logging scheme.
|
||||
* Comment out for correct compilation error line. */
|
||||
#line 9
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "infos/gpu_shader_test_infos.hh"
|
||||
|
||||
#include "gpu_shader_test_lib.bsl.hh"
|
||||
|
||||
#include "gpu_shader_math_axis_angle_lib.glsl"
|
||||
#include "gpu_shader_math_euler_lib.glsl"
|
||||
#include "gpu_shader_math_matrix_adjoint_lib.glsl"
|
||||
#include "gpu_shader_math_matrix_construct_lib.glsl"
|
||||
#include "gpu_shader_math_matrix_interpolate_lib.glsl"
|
||||
#include "gpu_shader_math_matrix_lib.glsl"
|
||||
#include "gpu_shader_math_matrix_normalize_lib.glsl"
|
||||
#include "gpu_shader_math_matrix_projection_lib.glsl"
|
||||
#include "gpu_shader_math_matrix_transform_lib.glsl"
|
||||
#include "gpu_shader_math_quaternion_lib.glsl"
|
||||
#include "gpu_shader_math_rotation_conversion_lib.glsl"
|
||||
#include "gpu_shader_math_rotation_lib.glsl"
|
||||
|
||||
[[compute, local_size(1)]]
|
||||
void gpu_math_test_main([[resource_table]] const ShaderTestOutput & /*srt*/)
|
||||
{
|
||||
TEST(math_matrix, MatrixInverse)
|
||||
{
|
||||
float3x3 mat = mat3x3_diagonal(2);
|
||||
float3x3 inv = invert(mat);
|
||||
float3x3 expect = mat3x3_diagonal(0.5f);
|
||||
EXPECT_NEAR(inv, expect, 1e-5f);
|
||||
|
||||
bool success;
|
||||
float3x3 m2 = mat3x3_all(1);
|
||||
float3x3 inv2 = invert(m2, success);
|
||||
float3x3 expect2 = mat3x3_all(0);
|
||||
EXPECT_NEAR(inv2, expect2, 1e-5f);
|
||||
EXPECT_FALSE(success);
|
||||
}
|
||||
|
||||
TEST(math_matrix, MatrixDeterminant)
|
||||
{
|
||||
float2x2 m2 = float2x2(float2(1, 2), float2(3, 4));
|
||||
float3x3 m3 = float3x3(float3(1, 2, 3), float3(-3, 4, -5), float3(5, -6, 7));
|
||||
float4x4 m4 = float4x4(
|
||||
float4(1, 2, -3, 3), float4(3, 4, -5, 3), float4(5, 6, 7, -3), float4(5, 6, 7, 1));
|
||||
EXPECT_NEAR(determinant(m2), -2.0f, 1e-8f);
|
||||
EXPECT_NEAR(determinant(m3), -16.0f, 1e-8f);
|
||||
EXPECT_NEAR(determinant(m4), -112.0f, 1e-8f);
|
||||
}
|
||||
|
||||
TEST(math_matrix, MatrixAdjoint)
|
||||
{
|
||||
float2x2 m2 = float2x2(float2(1, 2), float2(3, 4));
|
||||
float3x3 m3 = float3x3(float3(1, 2, 3), float3(-3, 4, -5), float3(5, -6, 7));
|
||||
float4x4 m4 = float4x4(
|
||||
float4(1, 2, -3, 3), float4(3, 4, -5, 3), float4(5, 6, 7, -3), float4(5, 6, 7, 1));
|
||||
float2x2 expect2 = transpose(float2x2(float2(4, -3), float2(-2, 1)));
|
||||
float3x3 expect3 = transpose(
|
||||
float3x3(float3(-2, -4, -2), float3(-32, -8, 16), float3(-22, -4, 10)));
|
||||
float4x4 expect4 = transpose(float4x4(float4(232, -184, -8, -0),
|
||||
float4(-128, 88, 16, 0),
|
||||
float4(80, -76, 4, 28),
|
||||
float4(-72, 60, -12, -28)));
|
||||
EXPECT_NEAR(adjoint(m2), expect2, 1e-8f);
|
||||
EXPECT_NEAR(adjoint(m3), expect3, 1e-8f);
|
||||
EXPECT_NEAR(adjoint(m4), expect4, 1e-8f);
|
||||
}
|
||||
|
||||
TEST(math_matrix, MatrixInit)
|
||||
{
|
||||
float4x4 expect;
|
||||
|
||||
float4x4 m = from_location(float3(1, 2, 3));
|
||||
expect = float4x4(
|
||||
float4(1, 0, 0, 0), float4(0, 1, 0, 0), float4(0, 0, 1, 0), float4(1, 2, 3, 1));
|
||||
EXPECT_TRUE(is_equal(m, expect, 0.00001f));
|
||||
|
||||
expect = transpose(float4x4(float4(0.411982f, -0.833738f, -0.36763f, 0),
|
||||
float4(-0.0587266f, -0.426918f, 0.902382f, 0),
|
||||
float4(-0.909297f, -0.350175f, -0.224845f, 0),
|
||||
float4(0, 0, 0, 1)));
|
||||
EulerXYZ euler = EulerXYZ{1, 2, 3};
|
||||
Quaternion quat = to_quaternion(euler);
|
||||
AxisAngle axis_angle = to_axis_angle(euler);
|
||||
m = to_float4x4(from_rotation(euler));
|
||||
EXPECT_NEAR(m, expect, 1e-5f);
|
||||
m = to_float4x4(from_rotation(quat));
|
||||
EXPECT_NEAR(m, expect, 1e-5f);
|
||||
m = to_float4x4(from_rotation(axis_angle));
|
||||
EXPECT_NEAR(m, expect, 3e-4f); /* Has some precision issue on some platform. */
|
||||
|
||||
m = from_scale(float4(1, 2, 3, 4));
|
||||
expect = float4x4(
|
||||
float4(1, 0, 0, 0), float4(0, 2, 0, 0), float4(0, 0, 3, 0), float4(0, 0, 0, 4));
|
||||
EXPECT_TRUE(is_equal(m, expect, 0.00001f));
|
||||
|
||||
m = to_float4x4(from_scale(float3(1, 2, 3)));
|
||||
expect = float4x4(
|
||||
float4(1, 0, 0, 0), float4(0, 2, 0, 0), float4(0, 0, 3, 0), float4(0, 0, 0, 1));
|
||||
EXPECT_TRUE(is_equal(m, expect, 0.00001f));
|
||||
|
||||
m = to_float4x4(from_scale(float2(1, 2)));
|
||||
expect = float4x4(
|
||||
float4(1, 0, 0, 0), float4(0, 2, 0, 0), float4(0, 0, 1, 0), float4(0, 0, 0, 1));
|
||||
EXPECT_TRUE(is_equal(m, expect, 0.00001f));
|
||||
|
||||
m = from_loc_rot(float3(1, 2, 3), EulerXYZ{1, 2, 3});
|
||||
expect = float4x4(float4(0.411982f, -0.0587266f, -0.909297f, 0),
|
||||
float4(-0.833738f, -0.426918f, -0.350175f, 0),
|
||||
float4(-0.36763f, 0.902382f, -0.224845f, 0),
|
||||
float4(1, 2, 3, 1));
|
||||
EXPECT_TRUE(is_equal(m, expect, 0.00001f));
|
||||
|
||||
m = from_loc_rot_scale(float3(1, 2, 3), EulerXYZ{1, 2, 3}, float3(1, 2, 3));
|
||||
expect = float4x4(float4(0.411982f, -0.0587266f, -0.909297f, 0),
|
||||
float4(-1.66748f, -0.853835f, -0.700351f, 0),
|
||||
float4(-1.10289f, 2.70714f, -0.674535f, 0),
|
||||
float4(1, 2, 3, 1));
|
||||
EXPECT_TRUE(is_equal(m, expect, 0.00001f));
|
||||
}
|
||||
|
||||
TEST(math_matrix, MatrixModify)
|
||||
{
|
||||
constexpr float epsilon = 1e-6f;
|
||||
float4x4 result, expect;
|
||||
float4x4 m1 = float4x4(
|
||||
float4(0, 3, 0, 0), float4(2, 0, 0, 0), float4(0, 0, 2, 0), float4(0, 0, 0, 1));
|
||||
|
||||
expect = float4x4(
|
||||
float4(0, 3, 0, 0), float4(2, 0, 0, 0), float4(0, 0, 2, 0), float4(4, 9, 2, 1));
|
||||
result = translate(m1, float3(3, 2, 1));
|
||||
EXPECT_NEAR(result, expect, epsilon);
|
||||
|
||||
expect = float4x4(
|
||||
float4(0, 3, 0, 0), float4(2, 0, 0, 0), float4(0, 0, 2, 0), float4(4, 0, 0, 1));
|
||||
result = translate(m1, float2(0, 2));
|
||||
EXPECT_NEAR(result, expect, epsilon);
|
||||
|
||||
expect = float4x4(
|
||||
float4(0, 0, -2, 0), float4(2, 0, 0, 0), float4(0, 3, 0, 0), float4(0, 0, 0, 1));
|
||||
result = rotate(m1, AxisAngle{float3(0, 1, 0), M_PI_2});
|
||||
EXPECT_NEAR(result, expect, epsilon);
|
||||
|
||||
expect = float4x4(
|
||||
float4(0, 9, 0, 0), float4(4, 0, 0, 0), float4(0, 0, 8, 0), float4(0, 0, 0, 1));
|
||||
result = scale(m1, float3(3, 2, 4));
|
||||
EXPECT_NEAR(result, expect, epsilon);
|
||||
|
||||
expect = float4x4(
|
||||
float4(0, 9, 0, 0), float4(4, 0, 0, 0), float4(0, 0, 2, 0), float4(0, 0, 0, 1));
|
||||
result = scale(m1, float2(3, 2));
|
||||
EXPECT_NEAR(result, expect, epsilon);
|
||||
}
|
||||
|
||||
TEST(math_matrix, MatrixCompareTest)
|
||||
{
|
||||
float4x4 m1 = float4x4(
|
||||
float4(0, 3, 0, 0), float4(2, 0, 0, 0), float4(0, 0, 2, 0), float4(0, 0, 0, 1));
|
||||
float4x4 m2 = float4x4(float4(0, 3.001f, 0, 0),
|
||||
float4(1.999f, 0, 0, 0),
|
||||
float4(0, 0, 2.001f, 0),
|
||||
float4(0, 0, 0, 1.001f));
|
||||
float4x4 m3 = float4x4(float4(0, 3.001f, 0, 0),
|
||||
float4(1, 1, 0, 0),
|
||||
float4(0, 0, 2.001f, 0),
|
||||
float4(0, 0, 0, 1.001f));
|
||||
float4x4 m4 = float4x4(
|
||||
float4(0, 1, 0, 0), float4(1, 0, 0, 0), float4(0, 0, 1, 0), float4(0, 0, 0, 1));
|
||||
float4x4 m5 = float4x4(
|
||||
float4(0, 0, 0, 0), float4(0, 0, 0, 0), float4(0, 0, 0, 0), float4(0, 0, 0, 0));
|
||||
float4x4 m6 = float4x4(
|
||||
float4(1, 0, 0, 0), float4(0, 1, 0, 0), float4(0, 0, 1, 0), float4(0, 0, 0, 1));
|
||||
EXPECT_TRUE(is_equal(m1, m2, 0.01f));
|
||||
EXPECT_FALSE(is_equal(m1, m2, 0.0001f));
|
||||
EXPECT_FALSE(is_equal(m1, m3, 0.01f));
|
||||
EXPECT_TRUE(is_orthogonal(m1));
|
||||
EXPECT_FALSE(is_orthogonal(m3));
|
||||
EXPECT_TRUE(is_orthonormal(m4));
|
||||
EXPECT_FALSE(is_orthonormal(m1));
|
||||
EXPECT_FALSE(is_orthonormal(m3));
|
||||
EXPECT_FALSE(is_uniformly_scaled(m1));
|
||||
EXPECT_TRUE(is_uniformly_scaled(m4));
|
||||
EXPECT_FALSE(is_zero(m4));
|
||||
EXPECT_TRUE(is_zero(m5));
|
||||
EXPECT_TRUE(is_negative(m4));
|
||||
EXPECT_FALSE(is_negative(m5));
|
||||
EXPECT_FALSE(is_negative(m6));
|
||||
}
|
||||
|
||||
TEST(math_matrix, MatrixMethods)
|
||||
{
|
||||
float4x4 m = float4x4(
|
||||
float4(0, 3, 0, 0), float4(2, 0, 0, 0), float4(0, 0, 2, 0), float4(0, 1, 0, 1));
|
||||
EulerXYZ expect_eul = EulerXYZ{0, 0, M_PI_2};
|
||||
Quaternion expect_qt = Quaternion{0, -M_SQRT1_2, M_SQRT1_2, 0};
|
||||
float3 expect_scale = float3(3, 2, 2);
|
||||
float3 expect_location = float3(0, 1, 0);
|
||||
|
||||
EXPECT_NEAR(to_euler(m).as_float3(), expect_eul.as_float3(), 0.0002f);
|
||||
EXPECT_NEAR(to_quaternion(m).as_float4(), expect_qt.as_float4(), 0.0002f);
|
||||
EXPECT_NEAR(to_scale(m), expect_scale, 0.00001f);
|
||||
|
||||
float4 expect_size = float4(3, 2, 2, M_SQRT2);
|
||||
float4 size;
|
||||
float4x4 m1 = normalize_and_get_size(m, size);
|
||||
EXPECT_TRUE(is_unit_scale(m1));
|
||||
EXPECT_NEAR(size, expect_size, 0.0002f);
|
||||
|
||||
float4x4 m2 = normalize(m);
|
||||
EXPECT_TRUE(is_unit_scale(m2));
|
||||
|
||||
EulerXYZ eul;
|
||||
Quaternion qt;
|
||||
float3 scale;
|
||||
to_rot_scale(to_float3x3(m), eul, scale);
|
||||
to_rot_scale(to_float3x3(m), qt, scale);
|
||||
EXPECT_NEAR(scale, expect_scale, 0.00001f);
|
||||
EXPECT_NEAR(qt.as_float4(), expect_qt.as_float4(), 0.0002f);
|
||||
EXPECT_NEAR(eul.as_float3(), expect_eul.as_float3(), 0.0002f);
|
||||
|
||||
float3 loc;
|
||||
to_loc_rot_scale(m, loc, eul, scale);
|
||||
to_loc_rot_scale(m, loc, qt, scale);
|
||||
EXPECT_NEAR(scale, expect_scale, 0.00001f);
|
||||
EXPECT_NEAR(loc, expect_location, 0.00001f);
|
||||
EXPECT_NEAR(qt.as_float4(), expect_qt.as_float4(), 0.0002f);
|
||||
EXPECT_NEAR(eul.as_float3(), expect_eul.as_float3(), 0.0002f);
|
||||
}
|
||||
|
||||
TEST(math_matrix, MatrixTranspose)
|
||||
{
|
||||
float4x4 m = float4x4(
|
||||
float4(1, 2, 3, 4), float4(5, 6, 7, 8), float4(9, 1, 2, 3), float4(2, 5, 6, 7));
|
||||
float4x4 transposed = transpose(m);
|
||||
float4x4 expect = float4x4(
|
||||
float4(1, 5, 9, 2), float4(2, 6, 1, 5), float4(3, 7, 2, 6), float4(4, 8, 3, 7));
|
||||
/* Split into vector comparison because lack of operator==(matrix,matrix) on metal. */
|
||||
EXPECT_NEAR(transposed[0], expect[0], 0.0f);
|
||||
EXPECT_NEAR(transposed[1], expect[1], 0.0f);
|
||||
EXPECT_NEAR(transposed[2], expect[2], 0.0f);
|
||||
EXPECT_NEAR(transposed[3], expect[3], 0.0f);
|
||||
}
|
||||
|
||||
TEST(math_matrix, MatrixInterpolationRegular)
|
||||
{
|
||||
/* Test 4x4 matrix interpolation without singularity, i.e. without axis flip. */
|
||||
|
||||
/* Transposed matrix, so that the code here is written in the same way as print_m4() outputs.
|
||||
*/
|
||||
/* This matrix represents T=(0.1, 0.2, 0.3), R=(40, 50, 60) degrees, S=(0.7, 0.8, 0.9) */
|
||||
float4x4 m2 = transpose(float4x4(float4(0.224976f, -0.333770f, 0.765074f, 0.100000f),
|
||||
float4(0.389669f, 0.647565f, 0.168130f, 0.200000f),
|
||||
float4(-0.536231f, 0.330541f, 0.443163f, 0.300000f),
|
||||
float4(0.000000f, 0.000000f, 0.000000f, 1.000000f)));
|
||||
float4x4 m1 = mat4x4_identity();
|
||||
float4x4 result;
|
||||
constexpr float epsilon = 2e-5f;
|
||||
result = interpolate_fast(m1, m2, 0.0f);
|
||||
EXPECT_NEAR(result, m1, epsilon);
|
||||
result = interpolate_fast(m1, m2, 1.0f);
|
||||
EXPECT_NEAR(result, m2, epsilon);
|
||||
|
||||
/* This matrix is based on the current implementation of the code, and isn't guaranteed to be
|
||||
* correct. It's just consistent with the current implementation. */
|
||||
float4x4 expect = transpose(float4x4(float4(0.690643f, -0.253244f, 0.484996f, 0.050000f),
|
||||
float4(0.271924f, 0.852623f, 0.012348f, 0.100000f),
|
||||
float4(-0.414209f, 0.137484f, 0.816778f, 0.150000f),
|
||||
float4(0.000000f, 0.000000f, 0.000000f, 1.000000f)));
|
||||
result = interpolate_fast(m1, m2, 0.5f);
|
||||
EXPECT_NEAR(result, expect, epsilon);
|
||||
}
|
||||
|
||||
TEST(math_matrix, MatrixTransform)
|
||||
{
|
||||
float3 expect, result;
|
||||
constexpr float3 p = float3(1, 2, 3);
|
||||
float4x4 m4 = from_loc_rot(float3(10, 0, 0), EulerXYZ{M_PI_2, M_PI_2, M_PI_2});
|
||||
float3x3 m3 = from_rotation(EulerXYZ{M_PI_2, M_PI_2, M_PI_2});
|
||||
float4x4 pers4 = projection_perspective(-0.1f, 0.1f, -0.1f, 0.1f, -0.1f, -1.0f);
|
||||
float3x3 pers3 = float3x3(float3(1, 0, 0.1f), float3(0, 1, 0.1f), float3(0, 0.1f, 1));
|
||||
|
||||
expect = float3(13, 2, -1);
|
||||
result = transform_point(m4, p);
|
||||
EXPECT_NEAR(result, expect, 1e-2f);
|
||||
|
||||
expect = float3(3, 2, -1);
|
||||
result = transform_point(m3, p);
|
||||
EXPECT_NEAR(result, expect, 1e-5f);
|
||||
|
||||
result = transform_direction(m4, p);
|
||||
EXPECT_NEAR(result, expect, 1e-5f);
|
||||
|
||||
result = transform_direction(m3, p);
|
||||
EXPECT_NEAR(result, expect, 1e-5f);
|
||||
|
||||
expect = float3(-0.333333f, -0.666667f, -1.14815f);
|
||||
result = project_point(pers4, p);
|
||||
EXPECT_NEAR(result, expect, 1e-5f);
|
||||
|
||||
float2 expect2 = float2(0.76923f, 1.61538f);
|
||||
float2 result2 = project_point(pers3, p.xy);
|
||||
EXPECT_NEAR(result2, expect2, 1e-5f);
|
||||
}
|
||||
|
||||
TEST(math_matrix, MatrixProjection)
|
||||
{
|
||||
float4x4 expect;
|
||||
float4x4 ortho = projection_orthographic(-0.2f, 0.3f, -0.2f, 0.4f, -0.2f, -0.5f);
|
||||
float4x4 pers1 = projection_perspective(-0.2f, 0.3f, -0.2f, 0.4f, -0.2f, -0.5f);
|
||||
float4x4 pers2 = projection_perspective_fov(
|
||||
atan(-0.2f), atan(0.3f), atan(-0.2f), atan(0.4f), -0.2f, -0.5f);
|
||||
|
||||
expect = transpose(float4x4(float4(4.0f, 0.0f, 0.0f, -0.2f),
|
||||
float4(0.0f, 3.33333f, 0.0f, -0.333333f),
|
||||
float4(0.0f, 0.0f, 6.66667f, -2.33333f),
|
||||
float4(0.0f, 0.0f, 0.0f, 1.0f)));
|
||||
EXPECT_NEAR(ortho, expect, 1e-5f);
|
||||
|
||||
expect = transpose(float4x4(float4(-0.8f, 0.0f, 0.2f, 0.0f),
|
||||
float4(0.0f, -0.666667f, 0.333333f, 0.0f),
|
||||
float4(0.0f, 0.0f, -2.33333f, 0.666667f),
|
||||
float4(0.0f, 0.0f, -1.0f, 0.0f)));
|
||||
EXPECT_NEAR(pers1, expect, 1e-4f);
|
||||
|
||||
expect = transpose(float4x4(float4(4.0f, 0.0f, 0.2f, 0.0f),
|
||||
float4(0.0f, 3.33333f, 0.333333f, 0.0f),
|
||||
float4(0.0f, 0.0f, -2.33333f, 0.666667f),
|
||||
float4(0.0f, 0.0f, -1.0f, 0.0f)));
|
||||
EXPECT_NEAR(pers2, expect, 1e-4f);
|
||||
}
|
||||
|
||||
TEST(math_matrix, OrderedInt)
|
||||
{
|
||||
/* Identity. */
|
||||
EXPECT_EQ(orderedIntBitsToFloat(floatBitsToOrderedInt(0.5f)), 0.5f);
|
||||
EXPECT_EQ(orderedIntBitsToFloat(floatBitsToOrderedInt(-0.5f)), -0.5f);
|
||||
EXPECT_EQ(orderedIntBitsToFloat(floatBitsToOrderedInt(0.0f)), 0.0f);
|
||||
EXPECT_EQ(orderedIntBitsToFloat(floatBitsToOrderedInt(-0.0f)), -0.0f);
|
||||
|
||||
EXPECT_GE(floatBitsToOrderedInt(-0.5f), floatBitsToOrderedInt(-1.0f));
|
||||
EXPECT_LE(floatBitsToOrderedInt(0.5f), floatBitsToOrderedInt(1.0f));
|
||||
EXPECT_LE(floatBitsToOrderedInt(-0.5f), floatBitsToOrderedInt(1.0f));
|
||||
EXPECT_GE(floatBitsToOrderedInt(0.5f), floatBitsToOrderedInt(-1.0f));
|
||||
EXPECT_LE(floatBitsToOrderedInt(-0.0f), floatBitsToOrderedInt(0.0f));
|
||||
}
|
||||
}
|
||||
|
||||
PipelineCompute gpu_math_test(gpu_math_test_main);
|
||||
@@ -0,0 +1,24 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "infos/gpu_shader_test_infos.hh"
|
||||
|
||||
COMPUTE_SHADER_CREATE_INFO(gpu_push_constants_test)
|
||||
|
||||
void main()
|
||||
{
|
||||
data_out[0] = float_in;
|
||||
|
||||
data_out[1] = vec2_in.x;
|
||||
data_out[2] = vec2_in.y;
|
||||
|
||||
data_out[3] = vec3_in.x;
|
||||
data_out[4] = vec3_in.y;
|
||||
data_out[5] = vec3_in.z;
|
||||
|
||||
data_out[6] = vec4_in.x;
|
||||
data_out[7] = vec4_in.y;
|
||||
data_out[8] = vec4_in.z;
|
||||
data_out[9] = vec4_in.w;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "infos/gpu_shader_test_infos.hh"
|
||||
|
||||
COMPUTE_SHADER_CREATE_INFO(gpu_graphic_specialization_test)
|
||||
|
||||
#if defined(GPU_COMPUTE_SHADER) || defined(GPU_VERTEX_SHADER)
|
||||
|
||||
void main()
|
||||
{
|
||||
data_out[0] = int(float_in);
|
||||
data_out[1] = int(uint_in);
|
||||
data_out[2] = int(int_in);
|
||||
data_out[3] = int(bool_in);
|
||||
|
||||
# if defined(GPU_VERTEX_SHADER)
|
||||
gl_Position = float4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
gl_PointSize = 1.0f;
|
||||
# endif
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void main() {}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
/* SPDX-FileCopyrightText: 2025 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "infos/gpu_shader_test_infos.hh"
|
||||
|
||||
COMPUTE_SHADER_CREATE_INFO(gpu_texture_atomic_test)
|
||||
|
||||
void main()
|
||||
{
|
||||
if (write_phase) {
|
||||
imageAtomicXor(img_atomic_2D, int2(0), uint(1u << gl_LocalInvocationIndex));
|
||||
imageAtomicXor(img_atomic_2D_array, int3(0, 0, 0), uint(1u << gl_LocalInvocationIndex));
|
||||
imageAtomicXor(img_atomic_2D_array, int3(0, 0, 1), uint(1u << gl_LocalInvocationIndex));
|
||||
imageAtomicXor(img_atomic_3D, int3(0, 0, 0), uint(1u << gl_LocalInvocationIndex));
|
||||
imageAtomicXor(img_atomic_3D, int3(0, 0, 1), uint(1u << gl_LocalInvocationIndex));
|
||||
}
|
||||
else {
|
||||
data_out[0] = int(imageLoad(img_atomic_2D, int2(0)).x);
|
||||
data_out[1] = int(imageLoad(img_atomic_2D_array, int3(0, 0, 0)).x);
|
||||
data_out[2] = int(imageLoad(img_atomic_2D_array, int3(0, 0, 1)).x);
|
||||
data_out[3] = int(imageLoad(img_atomic_3D, int3(0, 0, 0)).x);
|
||||
data_out[4] = int(imageLoad(img_atomic_3D, int3(0, 0, 1)).x);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/* SPDX-FileCopyrightText: 2025 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "infos/gpu_shader_test_infos.hh"
|
||||
|
||||
#if defined(GPU_VERTEX_SHADER)
|
||||
|
||||
VERTEX_SHADER_CREATE_INFO(gpu_sampler_arg_buf_test)
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = float4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
gl_PointSize = 1.0f;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
FRAGMENT_SHADER_CREATE_INFO(gpu_sampler_arg_buf_test)
|
||||
|
||||
void main()
|
||||
{
|
||||
data_out[0] = texture(tex_1, float2(0));
|
||||
data_out[1] = texture(tex_2, float2(0));
|
||||
data_out[2] = texture(tex_3, float2(0));
|
||||
data_out[3] = texture(tex_4, float2(0));
|
||||
data_out[4] = texture(tex_5, float2(0));
|
||||
data_out[5] = texture(tex_6, float2(0));
|
||||
data_out[6] = texture(tex_7, float2(0));
|
||||
data_out[7] = texture(tex_8, float2(0));
|
||||
data_out[8] = texture(tex_9, float2(0));
|
||||
data_out[9] = texture(tex_10, float2(0));
|
||||
data_out[10] = texture(tex_11, float2(0));
|
||||
data_out[11] = texture(tex_12, float2(0));
|
||||
data_out[12] = texture(tex_13, float2(0));
|
||||
data_out[13] = texture(tex_14, float2(0));
|
||||
data_out[14] = texture(tex_15, float2(0));
|
||||
data_out[15] = texture(tex_16, float2(0));
|
||||
data_out[16] = texture(tex_17, float2(0));
|
||||
data_out[17] = texture(tex_18, float2(0));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,135 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "GPU_batch.hh"
|
||||
#include "GPU_capabilities.hh"
|
||||
#include "GPU_compute.hh"
|
||||
#include "GPU_context.hh"
|
||||
#include "GPU_framebuffer.hh"
|
||||
#include "GPU_shader.hh"
|
||||
#include "GPU_state.hh"
|
||||
#include "GPU_storage_buffer.hh"
|
||||
#include "GPU_vertex_format.hh"
|
||||
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "gpu_shader_create_info.hh"
|
||||
#include "gpu_shader_create_info_private.hh"
|
||||
#include "gpu_testing.hh"
|
||||
|
||||
namespace blender::gpu::tests {
|
||||
|
||||
struct ShaderSpecializationConst {
|
||||
gpu::Shader *shader = nullptr;
|
||||
StorageBuf *ssbo = nullptr;
|
||||
Vector<int> data;
|
||||
|
||||
float float_in;
|
||||
uint uint_in;
|
||||
int int_in;
|
||||
bool bool_in;
|
||||
|
||||
bool is_graphic = false;
|
||||
|
||||
ShaderSpecializationConst(const char *info_name)
|
||||
{
|
||||
GPU_render_begin();
|
||||
|
||||
this->init_shader(info_name);
|
||||
|
||||
GPU_storagebuf_bind(ssbo, GPU_shader_get_ssbo_binding(shader, "data_out"));
|
||||
|
||||
/* Test values. */
|
||||
float_in = 52;
|
||||
uint_in = 324;
|
||||
int_in = 455;
|
||||
bool_in = false;
|
||||
|
||||
int float_in_loc = GPU_shader_get_constant(shader, "float_in");
|
||||
int uint_in_loc = GPU_shader_get_constant(shader, "uint_in");
|
||||
int int_in_loc = GPU_shader_get_constant(shader, "int_in");
|
||||
int bool_in_loc = GPU_shader_get_constant(shader, "bool_in");
|
||||
|
||||
shader::SpecializationConstants constants = GPU_shader_get_default_constant_state(shader);
|
||||
constants.set_value(float_in_loc, float_in);
|
||||
constants.set_value(uint_in_loc, uint_in);
|
||||
constants.set_value(int_in_loc, int_in);
|
||||
constants.set_value(bool_in_loc, bool_in);
|
||||
|
||||
this->validate(constants);
|
||||
|
||||
GPU_render_end();
|
||||
}
|
||||
|
||||
~ShaderSpecializationConst()
|
||||
{
|
||||
if (shader != nullptr) {
|
||||
GPU_shader_unbind();
|
||||
GPU_shader_free(shader);
|
||||
}
|
||||
if (ssbo != nullptr) {
|
||||
GPU_storagebuf_free(ssbo);
|
||||
}
|
||||
}
|
||||
|
||||
void init_shader(const char *info_name)
|
||||
{
|
||||
using namespace blender::gpu::shader;
|
||||
|
||||
uint data_len = 4;
|
||||
ssbo = GPU_storagebuf_create_ex(data_len * sizeof(int), nullptr, GPU_USAGE_STREAM, __func__);
|
||||
data.resize(data_len);
|
||||
|
||||
const GPUShaderCreateInfo *_info = gpu_shader_create_info_get(info_name);
|
||||
const ShaderCreateInfo &info = *reinterpret_cast<const ShaderCreateInfo *>(_info);
|
||||
is_graphic = info.compute_source_.is_empty();
|
||||
shader = GPU_shader_create_from_info_name(info_name);
|
||||
EXPECT_NE(shader, nullptr);
|
||||
}
|
||||
|
||||
void validate(shader::SpecializationConstants &constants)
|
||||
{
|
||||
if (is_graphic) {
|
||||
gpu::FrameBuffer *fb = GPU_framebuffer_create("test_fb");
|
||||
GPU_framebuffer_default_size(fb, 1, 1);
|
||||
GPU_framebuffer_bind(fb);
|
||||
|
||||
Batch *batch = GPU_batch_create_procedural(GPU_PRIM_POINTS, 1);
|
||||
|
||||
GPU_batch_set_shader(batch, shader, &constants);
|
||||
GPU_batch_draw_advanced(batch, 0, 1, 0, 1);
|
||||
GPU_batch_discard(batch);
|
||||
|
||||
GPU_framebuffer_free(fb);
|
||||
}
|
||||
else {
|
||||
GPU_compute_dispatch(shader, 1, 1, 1, &constants);
|
||||
}
|
||||
|
||||
GPU_finish();
|
||||
GPU_memory_barrier(GPU_BARRIER_BUFFER_UPDATE);
|
||||
GPU_storagebuf_read(ssbo, data.data());
|
||||
|
||||
EXPECT_EQ(data[0], int(float_in));
|
||||
EXPECT_EQ(data[1], int(uint_in));
|
||||
EXPECT_EQ(data[2], int(int_in));
|
||||
EXPECT_EQ(data[3], int(bool_in));
|
||||
}
|
||||
};
|
||||
|
||||
static void test_specialization_constants_compute()
|
||||
{
|
||||
ShaderSpecializationConst("gpu_compute_specialization_test");
|
||||
}
|
||||
GPU_TEST(specialization_constants_compute)
|
||||
|
||||
static void test_specialization_constants_graphic()
|
||||
{
|
||||
ShaderSpecializationConst("gpu_graphic_specialization_test");
|
||||
}
|
||||
GPU_TEST(specialization_constants_graphic)
|
||||
|
||||
} // namespace blender::gpu::tests
|
||||
154
blender-5.2.0/source/blender/gpu/tests/state_blend_test.cc
Normal file
154
blender-5.2.0/source/blender/gpu/tests/state_blend_test.cc
Normal file
@@ -0,0 +1,154 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "GPU_batch_utils.hh"
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "gpu_testing.hh"
|
||||
|
||||
#include "GPU_batch.hh"
|
||||
#include "GPU_batch_presets.hh"
|
||||
#include "GPU_framebuffer.hh"
|
||||
#include "GPU_state.hh"
|
||||
|
||||
#include "BLI_math_vector.hh"
|
||||
|
||||
#include "intern/draw_cache.hh"
|
||||
|
||||
namespace blender::gpu::tests {
|
||||
|
||||
template<GPUBlend blend_type>
|
||||
void blend_test(float4 source_a, float4 source_b, float4 expected_result)
|
||||
{
|
||||
GPUOffScreen *offscreen = GPU_offscreen_create(1,
|
||||
1,
|
||||
false,
|
||||
TextureFormat::SFLOAT_16_16_16_16,
|
||||
GPU_TEXTURE_USAGE_ATTACHMENT |
|
||||
GPU_TEXTURE_USAGE_HOST_READ,
|
||||
false,
|
||||
nullptr);
|
||||
BLI_assert(offscreen != nullptr);
|
||||
GPU_offscreen_bind(offscreen, false);
|
||||
gpu::Texture *color_texture = GPU_offscreen_color_texture(offscreen);
|
||||
GPU_texture_clear(color_texture, GPU_DATA_FLOAT, source_a);
|
||||
|
||||
Batch *batch = GPU_batch_preset_quad();
|
||||
|
||||
GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR);
|
||||
GPU_batch_uniform_4fv(batch, "color", source_b);
|
||||
GPU_blend(blend_type);
|
||||
|
||||
GPU_batch_draw(batch);
|
||||
GPU_offscreen_unbind(offscreen, false);
|
||||
GPU_flush();
|
||||
|
||||
float4 read_back;
|
||||
GPU_memory_barrier(GPU_BARRIER_TEXTURE_FETCH);
|
||||
GPU_offscreen_read_color(offscreen, GPU_DATA_FLOAT, &read_back);
|
||||
EXPECT_EQ(read_back, expected_result);
|
||||
|
||||
GPU_offscreen_free(offscreen);
|
||||
|
||||
/* Reset default. */
|
||||
GPU_blend(GPU_BLEND_NONE);
|
||||
}
|
||||
|
||||
static void test_blend_none()
|
||||
{
|
||||
blend_test<GPU_BLEND_NONE>(float4(1.0f, 0.0f, 1.0f, 1.0f),
|
||||
float4(0.0f, 1.0f, 0.0f, 0.5f),
|
||||
float4(0.0f, 1.0f, 0.0f, 0.5f));
|
||||
}
|
||||
GPU_TEST(blend_none)
|
||||
|
||||
static void test_blend_alpha()
|
||||
{
|
||||
blend_test<GPU_BLEND_ALPHA>(float4(1.0f, 0.0f, 1.0f, 1.0f),
|
||||
float4(0.0f, 1.0f, 0.0f, 0.5f),
|
||||
float4(0.5f, 0.5f, 0.5f, 1.0f));
|
||||
}
|
||||
GPU_TEST(blend_alpha)
|
||||
|
||||
static void test_blend_alpha_premult()
|
||||
{
|
||||
blend_test<GPU_BLEND_ALPHA_PREMULT>(float4(1.0f, 0.0f, 1.0f, 1.0f),
|
||||
float4(0.0f, 1.0f, 0.0f, 0.5f),
|
||||
float4(0.5f, 1.0f, 0.5f, 1.0f));
|
||||
}
|
||||
GPU_TEST(blend_alpha_premult)
|
||||
|
||||
static void test_blend_additive()
|
||||
{
|
||||
blend_test<GPU_BLEND_ADDITIVE>(float4(1.0f, 0.0f, 1.0f, 1.0f),
|
||||
float4(0.0f, 1.0f, 0.0f, 0.5f),
|
||||
float4(1.0f, 0.5f, 1.0f, 1.0f));
|
||||
}
|
||||
GPU_TEST(blend_additive)
|
||||
|
||||
static void test_blend_additive_premult()
|
||||
{
|
||||
blend_test<GPU_BLEND_ADDITIVE_PREMULT>(float4(1.0f, 0.0f, 1.0f, 1.0f),
|
||||
float4(0.0f, 1.0f, 0.0f, 0.5f),
|
||||
float4(1.0f, 1.0f, 1.0f, 1.5f));
|
||||
}
|
||||
GPU_TEST(blend_additive_premult)
|
||||
|
||||
static void test_blend_multiply()
|
||||
{
|
||||
blend_test<GPU_BLEND_MULTIPLY>(float4(1.0f, 0.0f, 1.0f, 1.0f),
|
||||
float4(0.0f, 1.0f, 0.0f, 0.5f),
|
||||
float4(0.0f, 0.0f, 0.0f, 0.5f));
|
||||
}
|
||||
GPU_TEST(blend_multiply)
|
||||
|
||||
static void test_blend_subtract()
|
||||
{
|
||||
blend_test<GPU_BLEND_SUBTRACT>(float4(1.0f, 1.0f, 1.0f, 1.0f),
|
||||
float4(0.0f, 1.0f, 0.0f, 0.5f),
|
||||
float4(1.0f, 0.0f, 1.0f, 0.5f));
|
||||
}
|
||||
GPU_TEST(blend_subtract)
|
||||
|
||||
static void test_blend_invert()
|
||||
{
|
||||
blend_test<GPU_BLEND_INVERT>(float4(1.0f, 1.0f, 1.0f, 1.0f),
|
||||
float4(0.0f, 1.0f, 0.0f, 0.5f),
|
||||
float4(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
}
|
||||
GPU_TEST(blend_invert)
|
||||
|
||||
static void test_blend_oit()
|
||||
{
|
||||
blend_test<GPU_BLEND_OIT>(float4(1.0f, 1.0f, 1.0f, 1.0f),
|
||||
float4(0.0f, 1.0f, 0.0f, 0.5f),
|
||||
float4(1.0f, 2.0f, 1.0f, 0.5f));
|
||||
}
|
||||
GPU_TEST(blend_oit)
|
||||
|
||||
static void test_blend_background()
|
||||
{
|
||||
blend_test<GPU_BLEND_BACKGROUND>(float4(1.0f, 1.0f, 1.0f, 1.0f),
|
||||
float4(0.0f, 1.0f, 0.0f, 0.5f),
|
||||
float4(0.5f, 0.5f, 0.5f, 0.5f));
|
||||
}
|
||||
GPU_TEST(blend_background)
|
||||
|
||||
static void test_blend_min()
|
||||
{
|
||||
blend_test<GPU_BLEND_MIN>(float4(1.0f, 2.0f, 3.0f, 4.0f),
|
||||
float4(4.0f, 3.0f, 2.0f, 1.0f),
|
||||
float4(1.0f, 2.0f, 2.0f, 1.0f));
|
||||
}
|
||||
GPU_TEST(blend_min)
|
||||
|
||||
static void test_blend_max()
|
||||
{
|
||||
blend_test<GPU_BLEND_MAX>(float4(1.0f, 2.0f, 3.0f, 4.0f),
|
||||
float4(4.0f, 3.0f, 2.0f, 1.0f),
|
||||
float4(4.0f, 3.0f, 3.0f, 4.0f));
|
||||
}
|
||||
GPU_TEST(blend_max)
|
||||
|
||||
} // namespace blender::gpu::tests
|
||||
203
blender-5.2.0/source/blender/gpu/tests/storage_buffer_test.cc
Normal file
203
blender-5.2.0/source/blender/gpu/tests/storage_buffer_test.cc
Normal file
@@ -0,0 +1,203 @@
|
||||
/* 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()
|
||||
{
|
||||
StorageBuf *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()
|
||||
{
|
||||
StorageBuf *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()
|
||||
{
|
||||
StorageBuf *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()
|
||||
{
|
||||
StorageBuf *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()
|
||||
{
|
||||
StorageBuf *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<float>(expected_data, read_data.as_span().slice(IndexRange(24)));
|
||||
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
|
||||
1197
blender-5.2.0/source/blender/gpu/tests/texture_test.cc
Normal file
1197
blender-5.2.0/source/blender/gpu/tests/texture_test.cc
Normal file
File diff suppressed because it is too large
Load Diff
242
blender-5.2.0/source/blender/gpu/tests/texture_view_test.cc
Normal file
242
blender-5.2.0/source/blender/gpu/tests/texture_view_test.cc
Normal file
@@ -0,0 +1,242 @@
|
||||
/* SPDX-FileCopyrightText: 2026 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
/*
|
||||
* Set of tests to identify issues with glTextureView and glGetTexImage. Note; these tests
|
||||
* rely on device-to-host data conversion (f16 -> f32) for texture readback, which is only
|
||||
* currently supported on OpenGL. Hence, they are only enabled on OpenGL.
|
||||
*/
|
||||
|
||||
#include "gpu_testing.hh"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_math_half.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "GPU_context.hh"
|
||||
#include "GPU_framebuffer.hh"
|
||||
#include "GPU_state.hh"
|
||||
#include "GPU_texture.hh"
|
||||
#include "gpu_texture_private.hh"
|
||||
|
||||
#include <bitset>
|
||||
|
||||
namespace blender::gpu::tests {
|
||||
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
|
||||
/* Test operates on a 4x4 texture patch. */
|
||||
constexpr uint texture_size_x = 4;
|
||||
constexpr uint texture_size_y = 4;
|
||||
constexpr uint texture_size = texture_size_x * texture_size_y;
|
||||
|
||||
/* Repeat the first `components` components of a float4 `n` times, into a vector. */
|
||||
template<typename T> static Vector<T> repeat_data(VecBase<T, 4> data, size_t n, size_t components)
|
||||
{
|
||||
Vector<T> out(n * components);
|
||||
for (uint i = 0; i < out.size(); ++i) {
|
||||
out[i] = data[i % components];
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Create a base texture of the specified format and clear it to black. */
|
||||
static gpu::Texture *create_base_texture(TextureFormat format)
|
||||
{
|
||||
constexpr eGPUTextureUsage usage = GPU_TEXTURE_USAGE_GENERAL | GPU_TEXTURE_USAGE_HOST_READ |
|
||||
GPU_TEXTURE_USAGE_FORMAT_VIEW;
|
||||
|
||||
gpu::Texture *base = GPU_texture_create_2d(
|
||||
"base", texture_size_x, texture_size_y, 1, format, usage, nullptr);
|
||||
GPU_texture_mipmap_mode(base, false, false);
|
||||
GPU_memory_barrier(GPU_BARRIER_FRAMEBUFFER);
|
||||
|
||||
/* Bind the texture as attachment to a temporary framebuffer, and clear to black. */
|
||||
gpu::FrameBuffer *fbo = nullptr;
|
||||
GPU_framebuffer_ensure_config(&fbo, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(base)});
|
||||
GPU_framebuffer_bind(fbo);
|
||||
GPU_framebuffer_clear(fbo, GPUFrameBufferBits::GPU_COLOR_BIT, {0.0, 0.0, 0.0, 0.0}, 0.0f, 0u);
|
||||
GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE);
|
||||
GPU_framebuffer_free(fbo);
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
/* Create a view texture of compatible aliasing format. */
|
||||
static gpu::Texture *create_view_texture(TextureFormat format, gpu::Texture *base)
|
||||
{
|
||||
gpu::Texture *view = GPU_texture_create_view("view", base, format, 0, 1, 0, 1, false, false);
|
||||
GPU_texture_mipmap_mode(view, false, false);
|
||||
GPU_memory_barrier(GPU_BARRIER_FRAMEBUFFER);
|
||||
return view;
|
||||
}
|
||||
|
||||
/* Read back a texture into a contiguous vector of T. */
|
||||
template<typename T>
|
||||
static Vector<T> read_texture(gpu::Texture *texture, eGPUDataFormat data_format)
|
||||
{
|
||||
TextureFormat format = GPU_texture_format(texture);
|
||||
const int channels = to_component_len(format);
|
||||
|
||||
void *src = GPU_texture_read(texture, data_format, 0);
|
||||
Vector<T> dst;
|
||||
dst.resize(texture_size * channels);
|
||||
std::memcpy(static_cast<void *>(dst.data()), src, sizeof(float) * dst.size());
|
||||
|
||||
MEM_delete_void(src);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
/* Given a pair of TextureFormat values, create base and view textures and
|
||||
* attempt to perform a framebuffer color clear over the view texture. */
|
||||
template<TextureFormat FormatA, TextureFormat FormatB> static void texture_view_create_test()
|
||||
{
|
||||
GPU_render_begin();
|
||||
|
||||
/* Float comparator threshold; half-to-full conversion has significant precision loss. */
|
||||
constexpr auto f_eq = [](float a, float b) { return std::abs(a - b) < 1e5f; };
|
||||
|
||||
gpu::Texture *base = create_base_texture(FormatA);
|
||||
gpu::Texture *view = create_view_texture(FormatB, base);
|
||||
|
||||
/* First check; the view texture should be all zeroes. */
|
||||
float4 zero(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
if (ELEM(to_texture_data_format(FormatB), GPU_DATA_UINT, GPU_DATA_2_10_10_10_REV)) {
|
||||
uint4 uzero(zero);
|
||||
auto zero_expected = repeat_data(uzero, texture_size, to_component_len(FormatB));
|
||||
auto zero_readback = read_texture<uint>(view, GPU_DATA_UINT);
|
||||
EXPECT_TRUE(std::equal(zero_expected.begin(), zero_expected.end(), zero_readback.begin()));
|
||||
}
|
||||
else if (to_texture_data_format(FormatB) == GPU_DATA_INT) {
|
||||
int4 izero(zero);
|
||||
auto zero_expected = repeat_data(izero, texture_size, to_component_len(FormatB));
|
||||
auto zero_readback = read_texture<int>(view, GPU_DATA_INT);
|
||||
EXPECT_TRUE(std::equal(zero_expected.begin(), zero_expected.end(), zero_readback.begin()));
|
||||
}
|
||||
else if (ELEM(to_texture_data_format(FormatB), GPU_DATA_FLOAT, GPU_DATA_10_11_11_REV)) {
|
||||
auto zero_expected = repeat_data(zero, texture_size, to_component_len(FormatB));
|
||||
auto zero_readback = read_texture<float>(view, GPU_DATA_FLOAT);
|
||||
EXPECT_TRUE(
|
||||
std::equal(zero_expected.begin(), zero_expected.end(), zero_readback.begin(), f_eq));
|
||||
}
|
||||
else {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
/* Create FBO with view as color attachment 0. */
|
||||
gpu::FrameBuffer *fbo = nullptr;
|
||||
GPU_framebuffer_ensure_config(&fbo, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(view)});
|
||||
GPU_framebuffer_bind(fbo);
|
||||
|
||||
/* Clear FBO to specific color with a different value on each channel. */
|
||||
float4 colr = (ELEM(to_texture_data_format(FormatB), GPU_DATA_FLOAT, GPU_DATA_10_11_11_REV)) ?
|
||||
float4(0.75f, 0.5f, 0.25f, 0.0f) :
|
||||
float4(128.0f, 64.0f, 32.0f, 16.0f);
|
||||
GPU_framebuffer_clear(fbo, GPUFrameBufferBits::GPU_COLOR_BIT, double4(colr), 0.0f, 0u);
|
||||
GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE);
|
||||
|
||||
/* Second check; the view texture should read back this color. */
|
||||
if (ELEM(to_texture_data_format(FormatB), GPU_DATA_UINT, GPU_DATA_2_10_10_10_REV)) {
|
||||
uint4 ucolr(colr);
|
||||
auto colr_expected = repeat_data(ucolr, texture_size, to_component_len(FormatB));
|
||||
auto colr_readback = read_texture<uint>(view, GPU_DATA_UINT);
|
||||
EXPECT_TRUE(std::equal(colr_expected.begin(), colr_expected.end(), colr_expected.begin()));
|
||||
}
|
||||
else if (to_texture_data_format(FormatB) == GPU_DATA_INT) {
|
||||
int4 icolr(colr);
|
||||
auto colr_expected = repeat_data(icolr, texture_size, to_component_len(FormatB));
|
||||
auto colr_readback = read_texture<int>(view, GPU_DATA_INT);
|
||||
EXPECT_TRUE(std::equal(colr_expected.begin(), colr_expected.end(), colr_expected.begin()));
|
||||
}
|
||||
else if (ELEM(to_texture_data_format(FormatB), GPU_DATA_FLOAT, GPU_DATA_10_11_11_REV)) {
|
||||
auto colr_expected = repeat_data(colr, texture_size, to_component_len(FormatB));
|
||||
auto colr_readback = read_texture<float>(view, GPU_DATA_FLOAT);
|
||||
EXPECT_TRUE(
|
||||
std::equal(colr_expected.begin(), colr_expected.end(), colr_expected.begin(), f_eq));
|
||||
}
|
||||
else {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
GPU_framebuffer_free(fbo);
|
||||
GPU_texture_free(view);
|
||||
GPU_texture_free(base);
|
||||
|
||||
GPU_render_end();
|
||||
}
|
||||
|
||||
static void test_texture_view_SFLOAT_32_32_32_32()
|
||||
{
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32_32_32_32, TextureFormat::SFLOAT_32_32_32_32>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32_32_32_32, TextureFormat::UINT_32_32_32_32>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32_32_32_32, TextureFormat::SINT_32_32_32_32>();
|
||||
}
|
||||
GPU_OPENGL_TEST(texture_view_SFLOAT_32_32_32_32);
|
||||
|
||||
static void test_texture_view_SFLOAT_32_32()
|
||||
{
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32_32, TextureFormat::SFLOAT_32_32>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32_32, TextureFormat::SFLOAT_16_16_16_16>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32_32, TextureFormat::UINT_32_32>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32_32, TextureFormat::UINT_16_16_16_16>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32_32, TextureFormat::SINT_32_32>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32_32, TextureFormat::SINT_16_16_16_16>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32_32, TextureFormat::SNORM_16_16_16_16>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32_32, TextureFormat::UNORM_16_16_16_16>();
|
||||
}
|
||||
GPU_OPENGL_TEST(texture_view_SFLOAT_32_32);
|
||||
|
||||
static void test_texture_view_SFLOAT_32()
|
||||
{
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32, TextureFormat::SFLOAT_32>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32, TextureFormat::SFLOAT_16_16>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32, TextureFormat::UINT_32>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32, TextureFormat::UINT_16_16>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32, TextureFormat::UINT_8_8_8_8>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32, TextureFormat::SINT_32>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32, TextureFormat::SINT_16_16>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32, TextureFormat::SINT_8_8_8_8>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32, TextureFormat::SNORM_16_16>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32, TextureFormat::SNORM_8_8_8_8>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32, TextureFormat::UNORM_16_16>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32, TextureFormat::UNORM_8_8_8_8>();
|
||||
|
||||
/* Note the special formats. */
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32, TextureFormat::UFLOAT_11_11_10>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_32, TextureFormat::SRGBA_8_8_8_8>();
|
||||
|
||||
/* Skipped: readback is not handled as we store these in reverse order. */
|
||||
// texture_view_create_test<TextureFormat::SFLOAT_32, TextureFormat::UINT_10_10_10_2>();
|
||||
// texture_view_create_test<TextureFormat::SFLOAT_32, TextureFormat::UNORM_10_10_10_2>();
|
||||
}
|
||||
GPU_OPENGL_TEST(texture_view_SFLOAT_32);
|
||||
|
||||
static void test_texture_view_SFLOAT_16()
|
||||
{
|
||||
texture_view_create_test<TextureFormat::SFLOAT_16, TextureFormat::SFLOAT_16>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_16, TextureFormat::UINT_16>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_16, TextureFormat::UINT_8_8>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_16, TextureFormat::SINT_16>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_16, TextureFormat::SINT_8_8>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_16, TextureFormat::SNORM_16>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_16, TextureFormat::UNORM_8_8>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_16, TextureFormat::UNORM_16>();
|
||||
texture_view_create_test<TextureFormat::SFLOAT_16, TextureFormat::UNORM_8_8>();
|
||||
}
|
||||
GPU_OPENGL_TEST(texture_view_SFLOAT_16);
|
||||
|
||||
static void test_texture_view_UINT_8()
|
||||
{
|
||||
texture_view_create_test<TextureFormat::UINT_8, TextureFormat::UINT_8>();
|
||||
texture_view_create_test<TextureFormat::UINT_8, TextureFormat::SINT_8>();
|
||||
texture_view_create_test<TextureFormat::UINT_8, TextureFormat::SNORM_8>();
|
||||
texture_view_create_test<TextureFormat::UINT_8, TextureFormat::UNORM_8>();
|
||||
}
|
||||
GPU_OPENGL_TEST(texture_view_UINT_8);
|
||||
#endif
|
||||
} // namespace blender::gpu::tests
|
||||
141
blender-5.2.0/source/blender/gpu/tests/vertex_buffer_test.cc
Normal file
141
blender-5.2.0/source/blender/gpu/tests/vertex_buffer_test.cc
Normal file
@@ -0,0 +1,141 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "GPU_attribute_convert.hh"
|
||||
#include "GPU_batch.hh"
|
||||
#include "GPU_framebuffer.hh"
|
||||
#include "GPU_shader.hh"
|
||||
#include "GPU_state.hh"
|
||||
#include "GPU_vertex_buffer.hh"
|
||||
#include "GPU_vertex_format.hh"
|
||||
|
||||
#include "BLI_index_range.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
|
||||
#include "gpu_testing.hh"
|
||||
|
||||
namespace blender::gpu::tests {
|
||||
|
||||
static constexpr int Size = 2;
|
||||
|
||||
template<VertAttrType attr_type, typename ColorType>
|
||||
static void vertex_buffer_fetch_mode(ColorType color)
|
||||
{
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ;
|
||||
GPUOffScreen *offscreen = GPU_offscreen_create(
|
||||
Size, Size, false, TextureFormat::SFLOAT_32_32_32_32, usage, false, nullptr);
|
||||
BLI_assert(offscreen != nullptr);
|
||||
GPU_offscreen_bind(offscreen, false);
|
||||
gpu::Texture *color_texture = GPU_offscreen_color_texture(offscreen);
|
||||
GPU_texture_clear(color_texture, GPU_DATA_FLOAT, float4(1.0f, 2.0f, 3.0f, 0.0f));
|
||||
|
||||
GPUVertFormat format = {0};
|
||||
GPU_vertformat_attr_add(&format, "pos", gpu::VertAttrType::SFLOAT_32_32);
|
||||
GPU_vertformat_attr_add(&format, "color", attr_type);
|
||||
|
||||
struct Vert {
|
||||
float2 pos;
|
||||
ColorType color;
|
||||
};
|
||||
std::array<Vert, 3> data = {
|
||||
Vert{float2(-1.0, -1.0), color},
|
||||
Vert{float2(3.0, -1.0), color},
|
||||
Vert{float2(-1.0, 3.0), color},
|
||||
};
|
||||
|
||||
VertBuf *vbo = GPU_vertbuf_create_with_format(format);
|
||||
GPU_vertbuf_data_alloc(*vbo, data.size());
|
||||
|
||||
for (int i : IndexRange(data.size())) {
|
||||
GPU_vertbuf_vert_set(vbo, i, &data[i]);
|
||||
}
|
||||
|
||||
Batch *batch = GPU_batch_create_ex(GPU_PRIM_TRIS, vbo, nullptr, GPU_BATCH_OWNS_VBO);
|
||||
GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR);
|
||||
GPU_batch_draw(batch);
|
||||
|
||||
GPU_offscreen_unbind(offscreen, false);
|
||||
GPU_flush();
|
||||
|
||||
/* Read back data and perform some basic tests. */
|
||||
Vector<float4> read_data(Size * Size);
|
||||
|
||||
GPU_offscreen_read_color(offscreen, GPU_DATA_FLOAT, read_data.data());
|
||||
|
||||
switch (attr_type) {
|
||||
case VertAttrType::SNORM_8_8_8_8:
|
||||
read_data[0] = read_data[0] * float(127);
|
||||
break;
|
||||
case VertAttrType::UNORM_8_8_8_8:
|
||||
read_data[0] = read_data[0] * float(255);
|
||||
break;
|
||||
case VertAttrType::SNORM_16_16_16_16:
|
||||
read_data[0] = read_data[0] * float(32767);
|
||||
break;
|
||||
case VertAttrType::UNORM_16_16_16_16:
|
||||
read_data[0] = read_data[0] * float(65535);
|
||||
break;
|
||||
case VertAttrType::SNORM_10_10_10_2:
|
||||
read_data[0] = read_data[0] * float4(511, 511, 511, 1);
|
||||
break;
|
||||
case VertAttrType::SFLOAT_32_32_32_32:
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
if (attr_type == VertAttrType::SFLOAT_32_32_32_32) {
|
||||
EXPECT_EQ(read_data[0], float4(color));
|
||||
}
|
||||
else {
|
||||
/* Do integer comparison to avoid floating point inaccuracies from each conversion steps. */
|
||||
EXPECT_EQ(int4(read_data[0]), int4(float4(color)));
|
||||
}
|
||||
|
||||
GPU_batch_discard(batch);
|
||||
GPU_offscreen_free(offscreen);
|
||||
}
|
||||
|
||||
static void test_vertex_buffer_fetch_mode__GPU_COMP_I8__GPU_FETCH_INT_TO_FLOAT_UNIT()
|
||||
{
|
||||
vertex_buffer_fetch_mode<VertAttrType::SNORM_8_8_8_8, char4>(char4(100, -127, 127, 0));
|
||||
}
|
||||
GPU_TEST(vertex_buffer_fetch_mode__GPU_COMP_I8__GPU_FETCH_INT_TO_FLOAT_UNIT);
|
||||
|
||||
static void test_vertex_buffer_fetch_mode__GPU_COMP_U8__GPU_FETCH_INT_TO_FLOAT_UNIT()
|
||||
{
|
||||
vertex_buffer_fetch_mode<VertAttrType::UNORM_8_8_8_8, uchar4>(uchar4(100, 0, 255, 127));
|
||||
}
|
||||
GPU_TEST(vertex_buffer_fetch_mode__GPU_COMP_U8__GPU_FETCH_INT_TO_FLOAT_UNIT);
|
||||
|
||||
static void test_vertex_buffer_fetch_mode__GPU_COMP_I16__GPU_FETCH_INT_TO_FLOAT_UNIT()
|
||||
{
|
||||
vertex_buffer_fetch_mode<VertAttrType::SNORM_16_16_16_16, short4>(
|
||||
short4(12034, -32767, 32767, 0));
|
||||
}
|
||||
GPU_TEST(vertex_buffer_fetch_mode__GPU_COMP_I16__GPU_FETCH_INT_TO_FLOAT_UNIT);
|
||||
|
||||
static void test_vertex_buffer_fetch_mode__GPU_COMP_U16__GPU_FETCH_INT_TO_FLOAT_UNIT()
|
||||
{
|
||||
vertex_buffer_fetch_mode<VertAttrType::UNORM_16_16_16_16, ushort4>(
|
||||
ushort4(12034, 0, 65535, 32767));
|
||||
}
|
||||
GPU_TEST(vertex_buffer_fetch_mode__GPU_COMP_U16__GPU_FETCH_INT_TO_FLOAT_UNIT);
|
||||
|
||||
static void test_vertex_buffer_fetch_mode__GPU_COMP_I10__GPU_FETCH_INT_TO_FLOAT_UNIT()
|
||||
{
|
||||
vertex_buffer_fetch_mode<VertAttrType::SNORM_10_10_10_2, PackedNormal>(
|
||||
PackedNormal(321, -511, 511, 0));
|
||||
}
|
||||
GPU_TEST(vertex_buffer_fetch_mode__GPU_COMP_I10__GPU_FETCH_INT_TO_FLOAT_UNIT);
|
||||
|
||||
static void test_vertex_buffer_fetch_mode__GPU_COMP_F32__GPU_FETCH_FLOAT()
|
||||
{
|
||||
vertex_buffer_fetch_mode<VertAttrType::SFLOAT_32_32_32_32, float4>(float4(4, 5, 6, 1));
|
||||
}
|
||||
GPU_TEST(vertex_buffer_fetch_mode__GPU_COMP_F32__GPU_FETCH_FLOAT);
|
||||
|
||||
} // namespace blender::gpu::tests
|
||||
Reference in New Issue
Block a user