Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/gpu')
-rw-r--r--source/blender/gpu/CMakeLists.txt11
-rw-r--r--source/blender/gpu/GPU_capabilities.h4
-rw-r--r--source/blender/gpu/GPU_compute.h38
-rw-r--r--source/blender/gpu/GPU_index_buffer.h21
-rw-r--r--source/blender/gpu/GPU_matrix.h36
-rw-r--r--source/blender/gpu/GPU_primitive.h2
-rw-r--r--source/blender/gpu/GPU_shader.h8
-rw-r--r--source/blender/gpu/GPU_state.h1
-rw-r--r--source/blender/gpu/GPU_vertex_buffer.h10
-rw-r--r--source/blender/gpu/GPU_viewport.h20
-rw-r--r--source/blender/gpu/intern/gpu_backend.hh1
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c4
-rw-r--r--source/blender/gpu/intern/gpu_capabilities.cc20
-rw-r--r--source/blender/gpu/intern/gpu_capabilities_private.hh4
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c6
-rw-r--r--source/blender/gpu/intern/gpu_compute.cc41
-rw-r--r--source/blender/gpu/intern/gpu_context.cc6
-rw-r--r--source/blender/gpu/intern/gpu_index_buffer.cc93
-rw-r--r--source/blender/gpu/intern/gpu_index_buffer_private.hh16
-rw-r--r--source/blender/gpu/intern/gpu_material_library.c11
-rw-r--r--source/blender/gpu/intern/gpu_material_library.h2
-rw-r--r--source/blender/gpu/intern/gpu_matrix.cc47
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.c4
-rw-r--r--source/blender/gpu/intern/gpu_select_pick.c6
-rw-r--r--source/blender/gpu/intern/gpu_select_sample_query.cc8
-rw-r--r--source/blender/gpu/intern/gpu_shader.cc261
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.cc9
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.hh6
-rw-r--r--source/blender/gpu/intern/gpu_shader_log.cc217
-rw-r--r--source/blender/gpu/intern/gpu_shader_private.hh45
-rw-r--r--source/blender/gpu/intern/gpu_state.cc2
-rw-r--r--source/blender/gpu/intern/gpu_state_private.hh2
-rw-r--r--source/blender/gpu/intern/gpu_texture.cc8
-rw-r--r--source/blender/gpu/intern/gpu_texture_private.hh4
-rw-r--r--source/blender/gpu/intern/gpu_uniform_buffer.cc4
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer.cc25
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer_private.hh3
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format.cc11
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c4
-rw-r--r--source/blender/gpu/opengl/gl_backend.cc52
-rw-r--r--source/blender/gpu/opengl/gl_backend.hh7
-rw-r--r--source/blender/gpu/opengl/gl_compute.cc35
-rw-r--r--source/blender/gpu/opengl/gl_compute.hh30
-rw-r--r--source/blender/gpu/opengl/gl_context.cc2
-rw-r--r--source/blender/gpu/opengl/gl_debug.cc8
-rw-r--r--source/blender/gpu/opengl/gl_drawlist.hh2
-rw-r--r--source/blender/gpu/opengl/gl_framebuffer.cc8
-rw-r--r--source/blender/gpu/opengl/gl_immediate.cc2
-rw-r--r--source/blender/gpu/opengl/gl_index_buffer.cc34
-rw-r--r--source/blender/gpu/opengl/gl_index_buffer.hh7
-rw-r--r--source/blender/gpu/opengl/gl_query.cc8
-rw-r--r--source/blender/gpu/opengl/gl_shader.cc48
-rw-r--r--source/blender/gpu/opengl/gl_shader.hh15
-rw-r--r--source/blender/gpu/opengl/gl_shader_interface.cc45
-rw-r--r--source/blender/gpu/opengl/gl_shader_log.cc87
-rw-r--r--source/blender/gpu/opengl/gl_state.cc8
-rw-r--r--source/blender/gpu/opengl/gl_state.hh3
-rw-r--r--source/blender/gpu/opengl/gl_texture.cc10
-rw-r--r--source/blender/gpu/opengl/gl_texture.hh2
-rw-r--r--source/blender/gpu/opengl/gl_vertex_buffer.cc45
-rw-r--r--source/blender/gpu/opengl/gl_vertex_buffer.hh8
-rw-r--r--source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl6
-rw-r--r--source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl4
-rw-r--r--source/blender/gpu/shaders/gpu_shader_text_frag.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl5
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl6
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_wavelength.glsl15
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl2
-rw-r--r--source/blender/gpu/tests/gpu_index_buffer_test.cc49
-rw-r--r--source/blender/gpu/tests/gpu_shader_builtin_test.cc94
-rw-r--r--source/blender/gpu/tests/gpu_shader_test.cc306
-rw-r--r--source/blender/gpu/tests/gpu_testing.hh18
74 files changed, 1624 insertions, 376 deletions
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 2ff72266a64..b7dc3210c41 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -62,6 +62,7 @@ set(SRC
intern/gpu_buffers.c
intern/gpu_capabilities.cc
intern/gpu_codegen.c
+ intern/gpu_compute.cc
intern/gpu_context.cc
intern/gpu_debug.cc
intern/gpu_drawlist.cc
@@ -82,6 +83,7 @@ set(SRC
intern/gpu_shader.cc
intern/gpu_shader_builtin.c
intern/gpu_shader_interface.cc
+ intern/gpu_shader_log.cc
intern/gpu_state.cc
intern/gpu_texture.cc
intern/gpu_uniform_buffer.cc
@@ -91,6 +93,7 @@ set(SRC
opengl/gl_backend.cc
opengl/gl_batch.cc
+ opengl/gl_compute.cc
opengl/gl_context.cc
opengl/gl_debug.cc
opengl/gl_debug_layer.cc
@@ -101,6 +104,7 @@ set(SRC
opengl/gl_query.cc
opengl/gl_shader.cc
opengl/gl_shader_interface.cc
+ opengl/gl_shader_log.cc
opengl/gl_state.cc
opengl/gl_texture.cc
opengl/gl_uniform_buffer.cc
@@ -113,6 +117,7 @@ set(SRC
GPU_buffers.h
GPU_capabilities.h
GPU_common.h
+ GPU_compute.h
GPU_context.h
GPU_debug.h
GPU_drawlist.h
@@ -163,6 +168,7 @@ set(SRC
opengl/gl_backend.hh
opengl/gl_batch.hh
+ opengl/gl_compute.hh
opengl/gl_context.hh
opengl/gl_debug.hh
opengl/gl_drawlist.hh
@@ -275,6 +281,7 @@ data_to_c_simple(shaders/material/gpu_shader_material_anisotropic.glsl SRC)
data_to_c_simple(shaders/material/gpu_shader_material_attribute.glsl SRC)
data_to_c_simple(shaders/material/gpu_shader_material_background.glsl SRC)
data_to_c_simple(shaders/material/gpu_shader_material_bevel.glsl SRC)
+data_to_c_simple(shaders/material/gpu_shader_material_wavelength.glsl SRC)
data_to_c_simple(shaders/material/gpu_shader_material_blackbody.glsl SRC)
data_to_c_simple(shaders/material/gpu_shader_material_bright_contrast.glsl SRC)
data_to_c_simple(shaders/material/gpu_shader_material_bump.glsl SRC)
@@ -390,6 +397,10 @@ if(WITH_GTESTS)
set(TEST_SRC
tests/gpu_testing.cc
+ tests/gpu_index_buffer_test.cc
+ tests/gpu_shader_builtin_test.cc
+ tests/gpu_shader_test.cc
+
tests/gpu_testing.hh
)
set(TEST_INC
diff --git a/source/blender/gpu/GPU_capabilities.h b/source/blender/gpu/GPU_capabilities.h
index f54ecece659..0c054d4f264 100644
--- a/source/blender/gpu/GPU_capabilities.h
+++ b/source/blender/gpu/GPU_capabilities.h
@@ -37,6 +37,8 @@ int GPU_max_textures(void);
int GPU_max_textures_vert(void);
int GPU_max_textures_geom(void);
int GPU_max_textures_frag(void);
+int GPU_max_work_group_count(int index);
+int GPU_max_work_group_size(int index);
int GPU_max_uniforms_vert(void);
int GPU_max_uniforms_frag(void);
int GPU_max_batch_indices(void);
@@ -55,6 +57,8 @@ bool GPU_use_main_context_workaround(void);
bool GPU_use_hq_normals_workaround(void);
bool GPU_crappy_amd_driver(void);
+bool GPU_compute_shader_support(void);
+bool GPU_shader_storage_buffer_objects_support(void);
bool GPU_shader_image_load_store_support(void);
bool GPU_mem_stats_supported(void);
diff --git a/source/blender/gpu/GPU_compute.h b/source/blender/gpu/GPU_compute.h
new file mode 100644
index 00000000000..a048f72c0a0
--- /dev/null
+++ b/source/blender/gpu/GPU_compute.h
@@ -0,0 +1,38 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#pragma once
+
+#include "BLI_sys_types.h"
+
+#include "GPU_shader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void GPU_compute_dispatch(GPUShader *shader,
+ uint groups_x_len,
+ uint groups_y_len,
+ uint groups_z_len);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/gpu/GPU_index_buffer.h b/source/blender/gpu/GPU_index_buffer.h
index 76aab3c196b..197077cf76c 100644
--- a/source/blender/gpu/GPU_index_buffer.h
+++ b/source/blender/gpu/GPU_index_buffer.h
@@ -40,6 +40,8 @@ typedef struct GPUIndexBufBuilder {
uint max_allowed_index;
uint max_index_len;
uint index_len;
+ uint index_min;
+ uint index_max;
GPUPrimType prim_type;
uint32_t *data;
} GPUIndexBufBuilder;
@@ -49,6 +51,14 @@ void GPU_indexbuf_init_ex(GPUIndexBufBuilder *, GPUPrimType, uint index_len, uin
/* supports only GPU_PRIM_POINTS, GPU_PRIM_LINES and GPU_PRIM_TRIS. */
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len);
+GPUIndexBuf *GPU_indexbuf_build_on_device(uint index_len);
+
+/*
+ * Thread safe.
+ *
+ * Function inspired by the reduction directives of multithread work APIs..
+ */
+void GPU_indexbuf_join(GPUIndexBufBuilder *builder, const GPUIndexBufBuilder *builder_from);
void GPU_indexbuf_add_generic_vert(GPUIndexBufBuilder *, uint v);
void GPU_indexbuf_add_primitive_restart(GPUIndexBufBuilder *);
@@ -70,6 +80,8 @@ void GPU_indexbuf_set_tri_restart(GPUIndexBufBuilder *builder, uint elem);
GPUIndexBuf *GPU_indexbuf_build(GPUIndexBufBuilder *);
void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *, GPUIndexBuf *);
+void GPU_indexbuf_bind_as_ssbo(GPUIndexBuf *elem, int binding);
+
/* Create a sub-range of an existing index-buffer. */
GPUIndexBuf *GPU_indexbuf_create_subrange(GPUIndexBuf *elem_src, uint start, uint length);
void GPU_indexbuf_create_subrange_in_place(GPUIndexBuf *elem,
@@ -77,6 +89,15 @@ void GPU_indexbuf_create_subrange_in_place(GPUIndexBuf *elem,
uint start,
uint length);
+/**
+ * (Download and) return a pointer containing the data of an index buffer.
+ *
+ * Note that the returned pointer is still owned by the driver. To get an
+ * local copy, use `GPU_indexbuf_unmap` after calling `GPU_indexbuf_read`.
+ */
+const uint32_t *GPU_indexbuf_read(GPUIndexBuf *elem);
+uint32_t *GPU_indexbuf_unmap(const GPUIndexBuf *elem, const uint32_t *mapped_buffer);
+
void GPU_indexbuf_discard(GPUIndexBuf *elem);
bool GPU_indexbuf_is_init(GPUIndexBuf *elem);
diff --git a/source/blender/gpu/GPU_matrix.h b/source/blender/gpu/GPU_matrix.h
index aad6ae9e2ba..e073263f352 100644
--- a/source/blender/gpu/GPU_matrix.h
+++ b/source/blender/gpu/GPU_matrix.h
@@ -118,21 +118,27 @@ bool GPU_matrix_unproject_precalc(struct GPUMatrixUnproject_Precalc *unproj_prec
const float proj[4][4],
const int view[4]);
-void GPU_matrix_project(const float world[3],
- const float model[4][4],
- const float proj[4][4],
- const int view[4],
- float r_win[3]);
-
-bool GPU_matrix_unproject(const float win[3],
- const float model[4][4],
- const float proj[4][4],
- const int view[4],
- float r_world[3]);
-
-void GPU_matrix_unproject_with_precalc(const struct GPUMatrixUnproject_Precalc *unproj_precalc,
- const float win[3],
- float r_world[3]);
+void GPU_matrix_project_3fv(const float world[3],
+ const float model[4][4],
+ const float proj[4][4],
+ const int view[4],
+ float r_win[3]);
+
+void GPU_matrix_project_2fv(const float world[3],
+ const float model[4][4],
+ const float proj[4][4],
+ const int view[4],
+ float r_win[2]);
+
+bool GPU_matrix_unproject_3fv(const float win[3],
+ const float model[4][4],
+ const float proj[4][4],
+ const int view[4],
+ float r_world[3]);
+
+void GPU_matrix_unproject_3fv_with_precalc(const struct GPUMatrixUnproject_Precalc *unproj_precalc,
+ const float win[3],
+ float r_world[3]);
/* 2D Projection Matrix */
diff --git a/source/blender/gpu/GPU_primitive.h b/source/blender/gpu/GPU_primitive.h
index b1d70326b45..f64a673d461 100644
--- a/source/blender/gpu/GPU_primitive.h
+++ b/source/blender/gpu/GPU_primitive.h
@@ -57,7 +57,7 @@ typedef enum {
} GPUPrimClass;
/**
- * TODO Improve error checking by validating that the shader is suited for this primitive type.
+ * TODO: Improve error checking by validating that the shader is suited for this primitive type.
* GPUPrimClass GPU_primtype_class(GPUPrimType);
* bool GPU_primtype_belongs_to_class(GPUPrimType, GPUPrimClass);
*/
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 9824c7016dc..f834ee5b234 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -27,6 +27,7 @@
extern "C" {
#endif
+struct GPUIndexBuf;
struct GPUVertBuf;
/** Opaque type hiding #blender::gpu::Shader */
@@ -45,6 +46,10 @@ GPUShader *GPU_shader_create(const char *vertcode,
const char *libcode,
const char *defines,
const char *shname);
+GPUShader *GPU_shader_create_compute(const char *computecode,
+ const char *libcode,
+ const char *defines,
+ const char *shname);
GPUShader *GPU_shader_create_from_python(const char *vertcode,
const char *fragcode,
const char *geomcode,
@@ -53,6 +58,7 @@ GPUShader *GPU_shader_create_from_python(const char *vertcode,
GPUShader *GPU_shader_create_ex(const char *vertcode,
const char *fragcode,
const char *geomcode,
+ const char *computecode,
const char *libcode,
const char *defines,
const eGPUShaderTFBType tf_type,
@@ -126,6 +132,7 @@ int GPU_shader_get_uniform(GPUShader *shader, const char *name);
int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin);
int GPU_shader_get_builtin_block(GPUShader *shader, int builtin);
int GPU_shader_get_uniform_block(GPUShader *shader, const char *name);
+int GPU_shader_get_ssbo(GPUShader *shader, const char *name);
int GPU_shader_get_uniform_block_binding(GPUShader *shader, const char *name);
int GPU_shader_get_texture_binding(GPUShader *shader, const char *name);
@@ -359,7 +366,6 @@ typedef enum eGPUBuiltinShader {
GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE, /* Uniformly scaled */
/* grease pencil drawing */
GPU_SHADER_GPENCIL_STROKE,
- GPU_SHADER_GPENCIL_FILL,
/* specialized for widget drawing */
GPU_SHADER_2D_AREA_EDGES,
GPU_SHADER_2D_WIDGET_BASE,
diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h
index 0687f271670..a338728804c 100644
--- a/source/blender/gpu/GPU_state.h
+++ b/source/blender/gpu/GPU_state.h
@@ -39,6 +39,7 @@ typedef enum eGPUBarrier {
GPU_BARRIER_NONE = 0,
GPU_BARRIER_SHADER_IMAGE_ACCESS = (1 << 0),
GPU_BARRIER_TEXTURE_FETCH = (1 << 1),
+ GPU_BARRIER_SHADER_STORAGE = (1 << 2),
} eGPUBarrier;
ENUM_OPERATORS(eGPUBarrier, GPU_BARRIER_TEXTURE_FETCH)
diff --git a/source/blender/gpu/GPU_vertex_buffer.h b/source/blender/gpu/GPU_vertex_buffer.h
index aae58de533b..2c54016daa7 100644
--- a/source/blender/gpu/GPU_vertex_buffer.h
+++ b/source/blender/gpu/GPU_vertex_buffer.h
@@ -59,6 +59,7 @@ typedef enum {
GPU_USAGE_STREAM,
GPU_USAGE_STATIC, /* do not keep data in memory */
GPU_USAGE_DYNAMIC,
+ GPU_USAGE_DEVICE_ONLY, /* Do not do host->device data transfers. */
} GPUUsageType;
/** Opaque type hiding blender::gpu::VertBuf. */
@@ -70,6 +71,14 @@ GPUVertBuf *GPU_vertbuf_create_with_format_ex(const GPUVertFormat *, GPUUsageTyp
#define GPU_vertbuf_create_with_format(format) \
GPU_vertbuf_create_with_format_ex(format, GPU_USAGE_STATIC)
+/**
+ * (Download and) return a pointer containing the data of a vertex buffer.
+ *
+ * Note that the returned pointer is still owned by the driver. To get an
+ * local copy, use `GPU_vertbuf_unmap` after calling `GPU_vertbuf_read`.
+ */
+const void *GPU_vertbuf_read(GPUVertBuf *verts);
+void *GPU_vertbuf_unmap(const GPUVertBuf *verts, const void *mapped_data);
void GPU_vertbuf_clear(GPUVertBuf *verts);
void GPU_vertbuf_discard(GPUVertBuf *);
@@ -138,6 +147,7 @@ uint GPU_vertbuf_get_vertex_len(const GPUVertBuf *verts);
GPUVertBufStatus GPU_vertbuf_get_status(const GPUVertBuf *verts);
void GPU_vertbuf_use(GPUVertBuf *);
+void GPU_vertbuf_bind_as_ssbo(struct GPUVertBuf *verts, int binding);
/* XXX do not use. */
void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, void *data);
diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h
index 095e17f344e..8b2a14a1a96 100644
--- a/source/blender/gpu/GPU_viewport.h
+++ b/source/blender/gpu/GPU_viewport.h
@@ -43,7 +43,7 @@ typedef struct GPUViewport GPUViewport;
struct GPUFrameBuffer;
-/* Contains memory pools information */
+/* Contains memory pools information. */
typedef struct ViewportMemoryPool {
struct BLI_memblock *commands;
struct BLI_memblock *commands_small;
@@ -62,21 +62,21 @@ typedef struct ViewportMemoryPool {
uint ubo_len;
} ViewportMemoryPool;
-/* All FramebufferLists are just the same pointers with different names */
+/* All FramebufferLists are just the same pointers with different names. */
typedef struct FramebufferList {
- struct GPUFrameBuffer *framebuffers[0];
+ struct GPUFrameBuffer *framebuffers[1];
} FramebufferList;
typedef struct TextureList {
- struct GPUTexture *textures[0];
+ struct GPUTexture *textures[1];
} TextureList;
typedef struct PassList {
- struct DRWPass *passes[0];
+ struct DRWPass *passes[1];
} PassList;
typedef struct StorageList {
- void *storage[0]; /* custom structs from the engine */
+ void *storage[1]; /* Custom structs from the engine. */
} StorageList;
typedef struct ViewportEngineData {
@@ -90,10 +90,10 @@ typedef struct ViewportEngineData {
TextureList *txl_stereo;
StorageList *stl_stereo;
- /* we may want to put this elsewhere */
+ /* We may want to put this elsewhere. */
struct DRWTextStore *text_draw_cache;
- /* Profiling data */
+ /* Profiling data. */
double init_time;
double render_time;
double background_time;
@@ -141,7 +141,7 @@ void GPU_viewport_size_get(const GPUViewport *viewport, int size[2]);
void GPU_viewport_size_set(GPUViewport *viewport, const int size[2]);
void GPU_viewport_active_view_set(GPUViewport *viewport, int view);
-/* Profiling */
+/* Profiling. */
double *GPU_viewport_cache_time_get(GPUViewport *viewport);
void GPU_viewport_tag_update(GPUViewport *viewport);
@@ -149,7 +149,7 @@ bool GPU_viewport_do_update(GPUViewport *viewport);
GPUTexture *GPU_viewport_color_texture(GPUViewport *viewport, int view);
-/* Texture pool */
+/* Texture pool. */
GPUTexture *GPU_viewport_texture_pool_query(
GPUViewport *viewport, void *engine, int width, int height, int format);
diff --git a/source/blender/gpu/intern/gpu_backend.hh b/source/blender/gpu/intern/gpu_backend.hh
index 04ec82a9213..73792215569 100644
--- a/source/blender/gpu/intern/gpu_backend.hh
+++ b/source/blender/gpu/intern/gpu_backend.hh
@@ -47,6 +47,7 @@ class GPUBackend {
static GPUBackend *get(void);
virtual void samplers_update(void) = 0;
+ virtual void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len) = 0;
virtual Context *context_alloc(void *ghost_window) = 0;
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index 13d0139e406..43483916236 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -707,7 +707,7 @@ void GPU_pbvh_grid_buffers_update(GPU_PBVH_Buffers *buffers,
float fno[3];
short no_short[3];
- /* Note: Clockwise indices ordering, that's why we invert order here. */
+ /* NOTE: Clockwise indices ordering, that's why we invert order here. */
normal_quad_v3(fno, co[3], co[2], co[1], co[0]);
normal_float_to_short_v3(no_short, fno);
@@ -916,7 +916,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
return;
}
- /* TODO, make mask layer optional for bmesh buffer */
+ /* TODO: make mask layer optional for bmesh buffer. */
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
/* Fill vertex buffer */
diff --git a/source/blender/gpu/intern/gpu_capabilities.cc b/source/blender/gpu/intern/gpu_capabilities.cc
index d8764502800..c6e9dc210cb 100644
--- a/source/blender/gpu/intern/gpu_capabilities.cc
+++ b/source/blender/gpu/intern/gpu_capabilities.cc
@@ -82,6 +82,16 @@ int GPU_max_textures(void)
return GCaps.max_textures;
}
+int GPU_max_work_group_count(int index)
+{
+ return GCaps.max_work_group_count[index];
+}
+
+int GPU_max_work_group_size(int index)
+{
+ return GCaps.max_work_group_size[index];
+}
+
int GPU_max_uniforms_vert(void)
{
return GCaps.max_uniforms_vert;
@@ -148,6 +158,16 @@ bool GPU_use_hq_normals_workaround(void)
return GCaps.use_hq_normals_workaround;
}
+bool GPU_compute_shader_support(void)
+{
+ return GCaps.compute_shader_support;
+}
+
+bool GPU_shader_storage_buffer_objects_support(void)
+{
+ return GCaps.shader_storage_buffer_objects_support;
+}
+
bool GPU_shader_image_load_store_support(void)
{
return GCaps.shader_image_load_store_support;
diff --git a/source/blender/gpu/intern/gpu_capabilities_private.hh b/source/blender/gpu/intern/gpu_capabilities_private.hh
index 7c1d4590ce8..95cf7fd335d 100644
--- a/source/blender/gpu/intern/gpu_capabilities_private.hh
+++ b/source/blender/gpu/intern/gpu_capabilities_private.hh
@@ -41,6 +41,8 @@ struct GPUCapabilities {
int max_textures_vert = 0;
int max_textures_geom = 0;
int max_textures_frag = 0;
+ int max_work_group_count[3] = {0, 0, 0};
+ int max_work_group_size[3] = {0, 0, 0};
int max_uniforms_vert = 0;
int max_uniforms_frag = 0;
int max_batch_indices = 0;
@@ -51,6 +53,8 @@ struct GPUCapabilities {
const char *(*extension_get)(int);
bool mem_stats_support = false;
+ bool compute_shader_support = false;
+ bool shader_storage_buffer_objects_support = false;
bool shader_image_load_store_support = false;
/* OpenGL related workarounds. */
bool mip_render_workaround = false;
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index a2072e504fd..d12cecd129e 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -810,7 +810,7 @@ static char *code_generate_geometry(GPUNodeGraph *graph,
}
LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
- /* TODO let shader choose what to do depending on what the attribute is. */
+ /* TODO: let shader choose what to do depending on what the attribute is. */
BLI_dynstr_appendf(ds, "dataAttrOut.var%d = dataAttrIn[vert].var%d;\\\n", attr->id, attr->id);
}
BLI_dynstr_append(ds, "}\n\n");
@@ -938,9 +938,9 @@ GPUPass *GPU_generate_pass(GPUMaterial *material,
return pass;
}
-static int count_active_texture_sampler(GPUShader *shader, char *source)
+static int count_active_texture_sampler(GPUShader *shader, const char *source)
{
- char *code = source;
+ const char *code = source;
/* Remember this is per stage. */
GSet *sampler_ids = BLI_gset_int_new(__func__);
diff --git a/source/blender/gpu/intern/gpu_compute.cc b/source/blender/gpu/intern/gpu_compute.cc
new file mode 100644
index 00000000000..7a8ae2acf9a
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_compute.cc
@@ -0,0 +1,41 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "GPU_compute.h"
+
+#include "gpu_backend.hh"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void GPU_compute_dispatch(GPUShader *shader,
+ uint groups_x_len,
+ uint groups_y_len,
+ uint groups_z_len)
+{
+ blender::gpu::GPUBackend &gpu_backend = *blender::gpu::GPUBackend::get();
+ GPU_shader_bind(shader);
+ gpu_backend.compute_dispatch(groups_x_len, groups_y_len, groups_z_len);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc
index b5a437b46f7..943a6151ced 100644
--- a/source/blender/gpu/intern/gpu_context.cc
+++ b/source/blender/gpu/intern/gpu_context.cc
@@ -28,7 +28,7 @@
* - free can be called from any thread
*/
-/* TODO Create cmake option. */
+/* TODO: Create cmake option. */
#define WITH_OPENGL_BACKEND 1
#include "BLI_assert.h"
@@ -99,7 +99,7 @@ Context *Context::get()
GPUContext *GPU_context_create(void *ghost_window)
{
if (GPUBackend::get() == nullptr) {
- /* TODO move where it make sense. */
+ /* TODO: move where it make sense. */
GPU_backend_init(GPU_BACKEND_OPENGL);
}
@@ -182,7 +182,7 @@ void GPU_backend_init(eGPUBackendType backend_type)
void GPU_backend_exit(void)
{
- /* TODO assert no resource left. Currently UI textures are still not freed in their context
+ /* TODO: assert no resource left. Currently UI textures are still not freed in their context
* correctly. */
delete g_backend;
g_backend = nullptr;
diff --git a/source/blender/gpu/intern/gpu_index_buffer.cc b/source/blender/gpu/intern/gpu_index_buffer.cc
index 65932d2dbf4..be7470e79c1 100644
--- a/source/blender/gpu/intern/gpu_index_buffer.cc
+++ b/source/blender/gpu/intern/gpu_index_buffer.cc
@@ -25,12 +25,15 @@
#include "MEM_guardedalloc.h"
+#include "BLI_math_base.h"
#include "BLI_utildefines.h"
#include "gpu_backend.hh"
#include "gpu_index_buffer_private.hh"
+#include <cstring>
+
#define KEEP_SINGLE_COPY 1
#define RESTART_INDEX 0xFFFFFFFF
@@ -50,6 +53,8 @@ void GPU_indexbuf_init_ex(GPUIndexBufBuilder *builder,
builder->max_allowed_index = vertex_len - 1;
builder->max_index_len = index_len;
builder->index_len = 0; // start empty
+ builder->index_min = UINT32_MAX;
+ builder->index_max = 0;
builder->prim_type = prim_type;
builder->data = (uint *)MEM_callocN(builder->max_index_len * sizeof(uint), "GPUIndexBuf data");
}
@@ -66,6 +71,22 @@ void GPU_indexbuf_init(GPUIndexBufBuilder *builder,
GPU_indexbuf_init_ex(builder, prim_type, prim_len * (uint)verts_per_prim, vertex_len);
}
+GPUIndexBuf *GPU_indexbuf_build_on_device(uint index_len)
+{
+ GPUIndexBuf *elem_ = GPU_indexbuf_calloc();
+ IndexBuf *elem = unwrap(elem_);
+ elem->init_build_on_device(index_len);
+ return elem_;
+}
+
+void GPU_indexbuf_join(GPUIndexBufBuilder *builder_to, const GPUIndexBufBuilder *builder_from)
+{
+ BLI_assert(builder_to->data == builder_from->data);
+ builder_to->index_len = max_uu(builder_to->index_len, builder_from->index_len);
+ builder_to->index_min = min_uu(builder_to->index_min, builder_from->index_min);
+ builder_to->index_max = max_uu(builder_to->index_max, builder_from->index_max);
+}
+
void GPU_indexbuf_add_generic_vert(GPUIndexBufBuilder *builder, uint v)
{
#if TRUST_NO_ONE
@@ -74,6 +95,8 @@ void GPU_indexbuf_add_generic_vert(GPUIndexBufBuilder *builder, uint v)
assert(v <= builder->max_allowed_index);
#endif
builder->data[builder->index_len++] = v;
+ builder->index_min = MIN2(builder->index_min, v);
+ builder->index_max = MAX2(builder->index_max, v);
}
void GPU_indexbuf_add_primitive_restart(GPUIndexBufBuilder *builder)
@@ -132,9 +155,9 @@ void GPU_indexbuf_set_point_vert(GPUIndexBufBuilder *builder, uint elem, uint v1
BLI_assert(builder->prim_type == GPU_PRIM_POINTS);
BLI_assert(elem < builder->max_index_len);
builder->data[elem++] = v1;
- if (builder->index_len < elem) {
- builder->index_len = elem;
- }
+ builder->index_min = MIN2(builder->index_min, v1);
+ builder->index_max = MAX2(builder->index_max, v1);
+ builder->index_len = MAX2(builder->index_len, elem);
}
void GPU_indexbuf_set_line_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2)
@@ -147,9 +170,9 @@ void GPU_indexbuf_set_line_verts(GPUIndexBufBuilder *builder, uint elem, uint v1
uint idx = elem * 2;
builder->data[idx++] = v1;
builder->data[idx++] = v2;
- if (builder->index_len < idx) {
- builder->index_len = idx;
- }
+ builder->index_min = MIN3(builder->index_min, v1, v2);
+ builder->index_max = MAX3(builder->index_max, v1, v2);
+ builder->index_len = MAX2(builder->index_len, idx);
}
void GPU_indexbuf_set_tri_verts(GPUIndexBufBuilder *builder, uint elem, uint v1, uint v2, uint v3)
@@ -164,9 +187,10 @@ void GPU_indexbuf_set_tri_verts(GPUIndexBufBuilder *builder, uint elem, uint v1,
builder->data[idx++] = v1;
builder->data[idx++] = v2;
builder->data[idx++] = v3;
- if (builder->index_len < idx) {
- builder->index_len = idx;
- }
+
+ builder->index_min = MIN4(builder->index_min, v1, v2, v3);
+ builder->index_max = MAX4(builder->index_max, v1, v2, v3);
+ builder->index_len = MAX2(builder->index_len, idx);
}
void GPU_indexbuf_set_point_restart(GPUIndexBufBuilder *builder, uint elem)
@@ -174,9 +198,7 @@ void GPU_indexbuf_set_point_restart(GPUIndexBufBuilder *builder, uint elem)
BLI_assert(builder->prim_type == GPU_PRIM_POINTS);
BLI_assert(elem < builder->max_index_len);
builder->data[elem++] = RESTART_INDEX;
- if (builder->index_len < elem) {
- builder->index_len = elem;
- }
+ builder->index_len = MAX2(builder->index_len, elem);
}
void GPU_indexbuf_set_line_restart(GPUIndexBufBuilder *builder, uint elem)
@@ -186,9 +208,7 @@ void GPU_indexbuf_set_line_restart(GPUIndexBufBuilder *builder, uint elem)
uint idx = elem * 2;
builder->data[idx++] = RESTART_INDEX;
builder->data[idx++] = RESTART_INDEX;
- if (builder->index_len < idx) {
- builder->index_len = idx;
- }
+ builder->index_len = MAX2(builder->index_len, idx);
}
void GPU_indexbuf_set_tri_restart(GPUIndexBufBuilder *builder, uint elem)
@@ -199,9 +219,7 @@ void GPU_indexbuf_set_tri_restart(GPUIndexBufBuilder *builder, uint elem)
builder->data[idx++] = RESTART_INDEX;
builder->data[idx++] = RESTART_INDEX;
builder->data[idx++] = RESTART_INDEX;
- if (builder->index_len < idx) {
- builder->index_len = idx;
- }
+ builder->index_len = MAX2(builder->index_len, idx);
}
/** \} */
@@ -219,7 +237,7 @@ IndexBuf::~IndexBuf()
}
}
-void IndexBuf::init(uint indices_len, uint32_t *indices)
+void IndexBuf::init(uint indices_len, uint32_t *indices, uint min_index, uint max_index)
{
is_init_ = true;
data_ = indices;
@@ -229,8 +247,7 @@ void IndexBuf::init(uint indices_len, uint32_t *indices)
#if GPU_TRACK_INDEX_RANGE
/* Everything remains 32 bit while building to keep things simple.
* Find min/max after, then convert to smallest index type possible. */
- uint min_index, max_index;
- uint range = this->index_range(&min_index, &max_index);
+ uint range = min_index < max_index ? max_index - min_index : 0;
/* count the primitive restart index. */
range += 1;
@@ -241,6 +258,15 @@ void IndexBuf::init(uint indices_len, uint32_t *indices)
#endif
}
+void IndexBuf::init_build_on_device(uint index_len)
+{
+ is_init_ = true;
+ index_start_ = 0;
+ index_len_ = index_len;
+ index_type_ = GPU_INDEX_U32;
+ data_ = nullptr;
+}
+
void IndexBuf::init_subrange(IndexBuf *elem_src, uint start, uint length)
{
/* We don't support nested subranges. */
@@ -307,6 +333,14 @@ void IndexBuf::squeeze_indices_short(uint min_idx, uint max_idx)
}
}
+uint32_t *IndexBuf::unmap(const uint32_t *mapped_memory) const
+{
+ size_t size = size_get();
+ uint32_t *result = static_cast<uint32_t *>(MEM_mallocN(size, __func__));
+ memcpy(result, mapped_memory, size);
+ return result;
+}
+
} // namespace blender::gpu
/** \} */
@@ -339,7 +373,7 @@ void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *builder, GPUIndexBuf *elem)
BLI_assert(builder->data != nullptr);
/* Transfer data ownership to GPUIndexBuf.
* It will be uploaded upon first use. */
- unwrap(elem)->init(builder->index_len, builder->data);
+ unwrap(elem)->init(builder->index_len, builder->data, builder->index_min, builder->index_max);
builder->data = nullptr;
}
@@ -351,6 +385,16 @@ void GPU_indexbuf_create_subrange_in_place(GPUIndexBuf *elem,
unwrap(elem)->init_subrange(unwrap(elem_src), start, length);
}
+const uint32_t *GPU_indexbuf_read(GPUIndexBuf *elem)
+{
+ return unwrap(elem)->read();
+}
+
+uint32_t *GPU_indexbuf_unmap(const GPUIndexBuf *elem, const uint32_t *mapped_buffer)
+{
+ return unwrap(elem)->unmap(mapped_buffer);
+}
+
void GPU_indexbuf_discard(GPUIndexBuf *elem)
{
delete unwrap(elem);
@@ -366,4 +410,9 @@ int GPU_indexbuf_primitive_len(GPUPrimType prim_type)
return indices_per_primitive(prim_type);
}
+void GPU_indexbuf_bind_as_ssbo(GPUIndexBuf *elem, int binding)
+{
+ unwrap(elem)->bind_as_ssbo(binding);
+}
+
/** \} */
diff --git a/source/blender/gpu/intern/gpu_index_buffer_private.hh b/source/blender/gpu/intern/gpu_index_buffer_private.hh
index 2405db8664a..ed7dd830c8c 100644
--- a/source/blender/gpu/intern/gpu_index_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_index_buffer_private.hh
@@ -51,7 +51,7 @@ class IndexBuf {
protected:
/** Type of indices used inside this buffer. */
GPUIndexBufType index_type_ = GPU_INDEX_U32;
- /** Offset in this buffer to the first index to render. Is 0 if not a subrange. */
+ /** Offset in this buffer to the first index to render. Is 0 if not a subrange. */
uint32_t index_start_ = 0;
/** Number of indices to render. */
uint32_t index_len_ = 0;
@@ -73,15 +73,16 @@ class IndexBuf {
IndexBuf(){};
virtual ~IndexBuf();
- void init(uint indices_len, uint32_t *indices);
+ void init(uint indices_len, uint32_t *indices, uint min_index, uint max_index);
void init_subrange(IndexBuf *elem_src, uint start, uint length);
+ void init_build_on_device(uint index_len);
uint32_t index_len_get(void) const
{
return index_len_;
}
/* Return size in byte of the drawable data buffer range. Actual buffer size might be bigger. */
- size_t size_get(void)
+ size_t size_get(void) const
{
return index_len_ * to_bytesize(index_type_);
};
@@ -91,6 +92,11 @@ class IndexBuf {
return is_init_;
};
+ virtual void bind_as_ssbo(uint binding) = 0;
+
+ virtual const uint32_t *read() const = 0;
+ uint32_t *unmap(const uint32_t *mapped_memory) const;
+
private:
inline void squeeze_indices_short(uint min_idx, uint max_idx);
inline uint index_range(uint *r_min, uint *r_max);
@@ -105,6 +111,10 @@ static inline IndexBuf *unwrap(GPUIndexBuf *indexbuf)
{
return reinterpret_cast<IndexBuf *>(indexbuf);
}
+static inline const IndexBuf *unwrap(const GPUIndexBuf *indexbuf)
+{
+ return reinterpret_cast<const IndexBuf *>(indexbuf);
+}
static inline int indices_per_primitive(GPUPrimType prim_type)
{
diff --git a/source/blender/gpu/intern/gpu_material_library.c b/source/blender/gpu/intern/gpu_material_library.c
index 175facc0a8d..73a80c62bdc 100644
--- a/source/blender/gpu/intern/gpu_material_library.c
+++ b/source/blender/gpu/intern/gpu_material_library.c
@@ -47,6 +47,7 @@ extern char datatoc_gpu_shader_material_anisotropic_glsl[];
extern char datatoc_gpu_shader_material_attribute_glsl[];
extern char datatoc_gpu_shader_material_background_glsl[];
extern char datatoc_gpu_shader_material_bevel_glsl[];
+extern char datatoc_gpu_shader_material_wavelength_glsl[];
extern char datatoc_gpu_shader_material_blackbody_glsl[];
extern char datatoc_gpu_shader_material_bright_contrast_glsl[];
extern char datatoc_gpu_shader_material_bump_glsl[];
@@ -191,6 +192,11 @@ static GPUMaterialLibrary gpu_shader_material_bevel_library = {
.dependencies = {NULL},
};
+static GPUMaterialLibrary gpu_shader_material_wavelength_library = {
+ .code = datatoc_gpu_shader_material_wavelength_glsl,
+ .dependencies = {NULL},
+};
+
static GPUMaterialLibrary gpu_shader_material_blackbody_library = {
.code = datatoc_gpu_shader_material_blackbody_glsl,
.dependencies = {NULL},
@@ -593,6 +599,7 @@ static GPUMaterialLibrary *gpu_material_libraries[] = {
&gpu_shader_material_attribute_library,
&gpu_shader_material_background_library,
&gpu_shader_material_bevel_library,
+ &gpu_shader_material_wavelength_library,
&gpu_shader_material_blackbody_library,
&gpu_shader_material_bright_contrast_library,
&gpu_shader_material_bump_library,
@@ -677,7 +684,7 @@ static GPUMaterialLibrary *gpu_material_libraries[] = {
static GHash *FUNCTION_HASH = NULL;
-char *gpu_str_skip_token(char *str, char *token, int max)
+const char *gpu_str_skip_token(const char *str, char *token, int max)
{
int len = 0;
@@ -745,7 +752,7 @@ static void gpu_parse_material_library(GHash *hash, GPUMaterialLibrary *library)
eGPUType type;
GPUFunctionQual qual;
int i;
- char *code = library->code;
+ const char *code = library->code;
while ((code = strstr(code, "void "))) {
function = MEM_callocN(sizeof(GPUFunction), "GPUFunction");
diff --git a/source/blender/gpu/intern/gpu_material_library.h b/source/blender/gpu/intern/gpu_material_library.h
index da7b1636fa3..782d89d6f2a 100644
--- a/source/blender/gpu/intern/gpu_material_library.h
+++ b/source/blender/gpu/intern/gpu_material_library.h
@@ -62,5 +62,5 @@ char *gpu_material_library_generate_code(struct GSet *used_libraries, const char
/* Code Parsing */
-char *gpu_str_skip_token(char *str, char *token, int max);
+const char *gpu_str_skip_token(const char *str, char *token, int max);
const char *gpu_data_type_to_string(const eGPUType type);
diff --git a/source/blender/gpu/intern/gpu_matrix.cc b/source/blender/gpu/intern/gpu_matrix.cc
index 569b51a407a..6eb9cb823d5 100644
--- a/source/blender/gpu/intern/gpu_matrix.cc
+++ b/source/blender/gpu/intern/gpu_matrix.cc
@@ -474,11 +474,11 @@ void GPU_matrix_look_at(float eyeX,
GPU_matrix_translate_3f(-eyeX, -eyeY, -eyeZ);
}
-void GPU_matrix_project(const float world[3],
- const float model[4][4],
- const float proj[4][4],
- const int view[4],
- float win[3])
+void GPU_matrix_project_3fv(const float world[3],
+ const float model[4][4],
+ const float proj[4][4],
+ const int view[4],
+ float win[3])
{
float v[4];
@@ -494,6 +494,25 @@ void GPU_matrix_project(const float world[3],
win[2] = (v[2] + 1) * 0.5f;
}
+void GPU_matrix_project_2fv(const float world[3],
+ const float model[4][4],
+ const float proj[4][4],
+ const int view[4],
+ float win[2])
+{
+ float v[4];
+
+ mul_v4_m4v3(v, model, world);
+ mul_m4_v4(proj, v);
+
+ if (v[3] != 0.0f) {
+ mul_v2_fl(v, 1.0f / v[3]);
+ }
+
+ win[0] = view[0] + (view[2] * (v[0] + 1)) * 0.5f;
+ win[1] = view[1] + (view[3] * (v[1] + 1)) * 0.5f;
+}
+
/**
* The same result could be obtained as follows:
*
@@ -556,9 +575,9 @@ bool GPU_matrix_unproject_precalc(struct GPUMatrixUnproject_Precalc *precalc,
return true;
}
-void GPU_matrix_unproject_with_precalc(const struct GPUMatrixUnproject_Precalc *precalc,
- const float win[3],
- float r_world[3])
+void GPU_matrix_unproject_3fv_with_precalc(const struct GPUMatrixUnproject_Precalc *precalc,
+ const float win[3],
+ float r_world[3])
{
float in[3] = {
(win[0] - precalc->view[0]) / precalc->view[2],
@@ -569,18 +588,18 @@ void GPU_matrix_unproject_with_precalc(const struct GPUMatrixUnproject_Precalc *
mul_v3_m4v3(r_world, precalc->model_inverted, in);
}
-bool GPU_matrix_unproject(const float win[3],
- const float model[4][4],
- const float proj[4][4],
- const int view[4],
- float r_world[3])
+bool GPU_matrix_unproject_3fv(const float win[3],
+ const float model[4][4],
+ const float proj[4][4],
+ const int view[4],
+ float r_world[3])
{
struct GPUMatrixUnproject_Precalc precalc;
if (!GPU_matrix_unproject_precalc(&precalc, model, proj, view)) {
zero_v3(r_world);
return false;
}
- GPU_matrix_unproject_with_precalc(&precalc, win, r_world);
+ GPU_matrix_unproject_3fv_with_precalc(&precalc, win, r_world);
return true;
}
diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c
index b220c60e979..7646cce2a3e 100644
--- a/source/blender/gpu/intern/gpu_node_graph.c
+++ b/source/blender/gpu/intern/gpu_node_graph.c
@@ -174,7 +174,7 @@ static const char *gpu_uniform_set_function_from_type(eNodeSocketDatatype type)
case SOCK_RGBA:
return "set_rgba";
default:
- BLI_assert(!"No gpu function for non-supported eNodeSocketDatatype");
+ BLI_assert_msg(0, "No gpu function for non-supported eNodeSocketDatatype");
return NULL;
}
}
@@ -259,7 +259,7 @@ static void gpu_node_output(GPUNode *node, const eGPUType type, GPUNodeLink **li
output->link->link_type = GPU_NODE_LINK_OUTPUT;
output->link->output = output;
- /* note: the caller owns the reference to the link, GPUOutput
+ /* NOTE: the caller owns the reference to the link, GPUOutput
* merely points to it, and if the node is destroyed it will
* set that pointer to NULL */
}
diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c
index 89c94fd3ba5..7fb704c29dd 100644
--- a/source/blender/gpu/intern/gpu_select_pick.c
+++ b/source/blender/gpu/intern/gpu_select_pick.c
@@ -55,7 +55,7 @@
* SubRectStride
*/
-/* For looping over a sub-region of a rect, could be moved into 'rct.c'*/
+/* For looping over a sub-region of a rect, could be moved into 'rct.c'. */
typedef struct SubRectStride {
uint start; /* start here */
uint span; /* read these */
@@ -230,7 +230,7 @@ typedef struct GPUPickState {
/* cache on initialization */
uint (*buffer)[4];
- /* buffer size (stores number of integers, for actual size multiply by sizeof integer)*/
+ /* Buffer size (stores number of integers, for actual size multiply by sizeof integer). */
uint bufsize;
/* mode of operation */
char mode;
@@ -484,7 +484,7 @@ bool gpu_select_pick_load_id(uint id, bool end)
GPUFrameBuffer *fb = GPU_framebuffer_active_get();
GPU_framebuffer_read_depth(
fb, UNPACK4(ps->gl.clip_readpixels), GPU_DATA_UINT, ps->gl.rect_depth_test->buf);
- /* perform initial check since most cases the array remains unchanged */
+ /* Perform initial check since most cases the array remains unchanged. */
bool do_pass = false;
if (g_pick_state.mode == GPU_SELECT_PICK_ALL) {
diff --git a/source/blender/gpu/intern/gpu_select_sample_query.cc b/source/blender/gpu/intern/gpu_select_sample_query.cc
index 5d8689c0d6a..fc755568687 100644
--- a/source/blender/gpu/intern/gpu_select_sample_query.cc
+++ b/source/blender/gpu/intern/gpu_select_sample_query.cc
@@ -48,17 +48,17 @@ using namespace blender;
using namespace blender::gpu;
struct GPUSelectQueryState {
- /* Tracks whether a query has been issued so that gpu_load_id can end the previous one */
+ /* Tracks whether a query has been issued so that gpu_load_id can end the previous one. */
bool query_issued;
/* GPU queries abstraction. Contains an array of queries. */
QueryPool *queries;
/* Array holding the id corresponding id to each query. */
Vector<uint> *ids;
- /* cache on initialization */
+ /* Cache on initialization. */
uint (*buffer)[4];
- /* buffer size (stores number of integers, for actual size multiply by sizeof integer)*/
+ /* Buffer size (stores number of integers, for actual size multiply by sizeof integer). */
uint bufsize;
- /* mode of operation */
+ /* Mode of operation. */
char mode;
uint index;
int oldhits;
diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc
index aea27756708..c754a649924 100644
--- a/source/blender/gpu/intern/gpu_shader.cc
+++ b/source/blender/gpu/intern/gpu_shader.cc
@@ -23,226 +23,24 @@
#include "MEM_guardedalloc.h"
-#include "BLI_dynstr.h"
-#include "BLI_math_base.h"
-#include "BLI_math_vector.h"
-#include "BLI_path_util.h"
-#include "BLI_string.h"
#include "BLI_string_utils.h"
-#include "BLI_utildefines.h"
-#include "BLI_vector.hh"
-
-#include "BKE_appdir.h"
-#include "BKE_global.h"
-
-#include "DNA_space_types.h"
#include "GPU_capabilities.h"
#include "GPU_matrix.h"
#include "GPU_platform.h"
-#include "GPU_shader.h"
-#include "GPU_texture.h"
-#include "GPU_uniform_buffer.h"
#include "gpu_backend.hh"
#include "gpu_context_private.hh"
#include "gpu_shader_private.hh"
-#include "CLG_log.h"
-
extern "C" char datatoc_gpu_shader_colorspace_lib_glsl[];
-static CLG_LogRef LOG = {"gpu.shader"};
-
using namespace blender;
using namespace blender::gpu;
static bool gpu_shader_srgb_uniform_dirty_get();
/* -------------------------------------------------------------------- */
-/** \name Debug functions
- * \{ */
-
-void Shader::print_log(Span<const char *> sources, char *log, const char *stage, const bool error)
-{
- const char line_prefix[] = " | ";
- char err_col[] = "\033[31;1m";
- char warn_col[] = "\033[33;1m";
- char info_col[] = "\033[0;2m";
- char reset_col[] = "\033[0;0m";
- char *sources_combined = BLI_string_join_arrayN((const char **)sources.data(), sources.size());
- DynStr *dynstr = BLI_dynstr_new();
-
- if (!CLG_color_support_get(&LOG)) {
- err_col[0] = warn_col[0] = info_col[0] = reset_col[0] = '\0';
- }
-
- BLI_dynstr_appendf(dynstr, "\n");
-
- char *log_line = log, *line_end;
- char *error_line_number_end;
- int error_line, error_char, last_error_line = -2, last_error_char = -1;
- bool found_line_id = false;
- while ((line_end = strchr(log_line, '\n'))) {
- /* Skip empty lines. */
- if (line_end == log_line) {
- log_line++;
- continue;
- }
- /* 0 = error, 1 = warning. */
- int type = -1;
- /* Skip ERROR: or WARNING:. */
- const char *prefix[] = {"ERROR", "WARNING"};
- for (int i = 0; i < ARRAY_SIZE(prefix); i++) {
- if (STREQLEN(log_line, prefix[i], strlen(prefix[i]))) {
- log_line += strlen(prefix[i]);
- type = i;
- break;
- }
- }
- /* Skip whitespaces and separators. */
- while (ELEM(log_line[0], ':', '(', ' ')) {
- log_line++;
- }
- /* Parse error line & char numbers. */
- error_line = error_char = -1;
- if (log_line[0] >= '0' && log_line[0] <= '9') {
- error_line = (int)strtol(log_line, &error_line_number_end, 10);
- /* Try to fetch the error character (not always available). */
- if (ELEM(error_line_number_end[0], '(', ':') && error_line_number_end[1] != ' ') {
- error_char = (int)strtol(error_line_number_end + 1, &log_line, 10);
- }
- else {
- log_line = error_line_number_end;
- }
- /* There can be a 3rd number (case of mesa driver). */
- if (ELEM(log_line[0], '(', ':') && log_line[1] >= '0' && log_line[1] <= '9') {
- error_line = error_char;
- error_char = (int)strtol(log_line + 1, &error_line_number_end, 10);
- log_line = error_line_number_end;
- }
- }
- /* Skip whitespaces and separators. */
- while (ELEM(log_line[0], ':', ')', ' ')) {
- log_line++;
- }
- if (error_line == -1) {
- found_line_id = false;
- }
- const char *src_line = sources_combined;
- if ((error_line != -1) && (error_char != -1)) {
- if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OFFICIAL)) {
- /* source:line */
- int error_source = error_line;
- if (error_source < sources.size()) {
- src_line = sources[error_source];
- error_line = error_char;
- error_char = -1;
- }
- }
- else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_OFFICIAL) ||
- GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_OFFICIAL)) {
- /* 0:line */
- error_line = error_char;
- error_char = -1;
- }
- else {
- /* line:char */
- }
- }
- /* Separate from previous block. */
- if (last_error_line != error_line) {
- BLI_dynstr_appendf(dynstr, "%s%s%s\n", info_col, line_prefix, reset_col);
- }
- else if (error_char != last_error_char) {
- BLI_dynstr_appendf(dynstr, "%s\n", line_prefix);
- }
- /* Print line from the source file that is producing the error. */
- if ((error_line != -1) && (error_line != last_error_line || error_char != last_error_char)) {
- const char *src_line_end = src_line;
- found_line_id = false;
- /* error_line is 1 based in this case. */
- int src_line_index = 1;
- while ((src_line_end = strchr(src_line, '\n'))) {
- if (src_line_index == error_line) {
- found_line_id = true;
- break;
- }
-/* TODO(fclem) Make this an option to display N lines before error. */
-#if 0 /* Uncomment to print shader file up to the error line to have more context. */
- BLI_dynstr_appendf(dynstr, "%5d | ", src_line_index);
- BLI_dynstr_nappend(dynstr, src_line, (src_line_end + 1) - src_line);
-#endif
- /* Continue to next line. */
- src_line = src_line_end + 1;
- src_line_index++;
- }
- /* Print error source. */
- if (found_line_id) {
- if (error_line != last_error_line) {
- BLI_dynstr_appendf(dynstr, "%5d | ", src_line_index);
- }
- else {
- BLI_dynstr_appendf(dynstr, line_prefix);
- }
- BLI_dynstr_nappend(dynstr, src_line, (src_line_end + 1) - src_line);
- /* Print char offset. */
- BLI_dynstr_appendf(dynstr, line_prefix);
- if (error_char != -1) {
- for (int i = 0; i < error_char; i++) {
- BLI_dynstr_appendf(dynstr, " ");
- }
- BLI_dynstr_appendf(dynstr, "^");
- }
- BLI_dynstr_appendf(dynstr, "\n");
- }
- }
- BLI_dynstr_appendf(dynstr, line_prefix);
- /* Skip to message. Avoid redundant info. */
- const char *keywords[] = {"error", "warning"};
- for (int i = 0; i < ARRAY_SIZE(prefix); i++) {
- if (STREQLEN(log_line, keywords[i], strlen(keywords[i]))) {
- log_line += strlen(keywords[i]);
- type = i;
- break;
- }
- }
- /* Skip and separators. */
- while (ELEM(log_line[0], ':', ')')) {
- log_line++;
- }
- if (type == 0) {
- BLI_dynstr_appendf(dynstr, "%s%s%s: ", err_col, "Error", info_col);
- }
- else if (type == 1) {
- BLI_dynstr_appendf(dynstr, "%s%s%s: ", warn_col, "Warning", info_col);
- }
- /* Print the error itself. */
- BLI_dynstr_append(dynstr, info_col);
- BLI_dynstr_nappend(dynstr, log_line, (line_end + 1) - log_line);
- BLI_dynstr_append(dynstr, reset_col);
- /* Continue to next line. */
- log_line = line_end + 1;
- last_error_line = error_line;
- last_error_char = error_char;
- }
- MEM_freeN(sources_combined);
-
- CLG_Severity severity = error ? CLG_SEVERITY_ERROR : CLG_SEVERITY_WARN;
-
- if (((LOG.type->flag & CLG_FLAG_USE) && (LOG.type->level >= 0)) ||
- (severity >= CLG_SEVERITY_WARN)) {
- const char *_str = BLI_dynstr_get_cstring(dynstr);
- CLG_log_str(LOG.type, severity, this->name, stage, _str);
- MEM_freeN((void *)_str);
- }
-
- BLI_dynstr_free(dynstr);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Creation / Destruction
* \{ */
@@ -290,6 +88,7 @@ static void standard_defines(Vector<const char *> &sources)
GPUShader *GPU_shader_create_ex(const char *vertcode,
const char *fragcode,
const char *geomcode,
+ const char *computecode,
const char *libcode,
const char *defines,
const eGPUShaderTFBType tf_type,
@@ -297,8 +96,10 @@ GPUShader *GPU_shader_create_ex(const char *vertcode,
const int tf_count,
const char *shname)
{
- /* At least a vertex shader and a fragment shader are required. */
- BLI_assert((fragcode != nullptr) && (vertcode != nullptr));
+ /* At least a vertex shader and a fragment shader are required, or only a compute shader. */
+ BLI_assert(((fragcode != nullptr) && (vertcode != nullptr) && (computecode == nullptr)) ||
+ ((fragcode == nullptr) && (vertcode == nullptr) && (geomcode == nullptr) &&
+ (computecode != nullptr)));
Shader *shader = GPUBackend::get()->shader_alloc(shname);
@@ -349,6 +150,21 @@ GPUShader *GPU_shader_create_ex(const char *vertcode,
shader->geometry_shader_from_glsl(sources);
}
+ if (computecode) {
+ Vector<const char *> sources;
+ standard_defines(sources);
+ sources.append("#define GPU_COMPUTE_SHADER\n");
+ if (defines) {
+ sources.append(defines);
+ }
+ if (libcode) {
+ sources.append(libcode);
+ }
+ sources.append(computecode);
+
+ shader->compute_shader_from_glsl(sources);
+ }
+
if (tf_names != nullptr && tf_count > 0) {
BLI_assert(tf_type != GPU_SHADER_TFB_NONE);
shader->transform_feedback_names_set(Span<const char *>(tf_names, tf_count), tf_type);
@@ -380,8 +196,33 @@ GPUShader *GPU_shader_create(const char *vertcode,
const char *defines,
const char *shname)
{
- return GPU_shader_create_ex(
- vertcode, fragcode, geomcode, libcode, defines, GPU_SHADER_TFB_NONE, nullptr, 0, shname);
+ return GPU_shader_create_ex(vertcode,
+ fragcode,
+ geomcode,
+ nullptr,
+ libcode,
+ defines,
+ GPU_SHADER_TFB_NONE,
+ nullptr,
+ 0,
+ shname);
+}
+
+GPUShader *GPU_shader_create_compute(const char *computecode,
+ const char *libcode,
+ const char *defines,
+ const char *shname)
+{
+ return GPU_shader_create_ex(nullptr,
+ nullptr,
+ nullptr,
+ computecode,
+ libcode,
+ defines,
+ GPU_SHADER_TFB_NONE,
+ nullptr,
+ 0,
+ shname);
}
GPUShader *GPU_shader_create_from_python(const char *vertcode,
@@ -402,6 +243,7 @@ GPUShader *GPU_shader_create_from_python(const char *vertcode,
GPUShader *sh = GPU_shader_create_ex(vertcode,
fragcode,
geomcode,
+ nullptr,
libcode,
defines,
GPU_SHADER_TFB_NONE,
@@ -567,6 +409,13 @@ int GPU_shader_get_builtin_block(GPUShader *shader, int builtin)
return interface->ubo_builtin((GPUUniformBlockBuiltin)builtin);
}
+int GPU_shader_get_ssbo(GPUShader *shader, const char *name)
+{
+ ShaderInterface *interface = unwrap(shader)->interface;
+ const ShaderInput *ssbo = interface->ssbo_get(name);
+ return ssbo ? ssbo->location : -1;
+}
+
/* DEPRECATED. */
int GPU_shader_get_uniform_block(GPUShader *shader, const char *name)
{
diff --git a/source/blender/gpu/intern/gpu_shader_interface.cc b/source/blender/gpu/intern/gpu_shader_interface.cc
index c584c40eca8..ae94112b17b 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.cc
+++ b/source/blender/gpu/intern/gpu_shader_interface.cc
@@ -80,6 +80,8 @@ void ShaderInterface::debug_print()
Span<ShaderInput> attrs = Span<ShaderInput>(inputs_, attr_len_);
Span<ShaderInput> ubos = Span<ShaderInput>(inputs_ + attr_len_, ubo_len_);
Span<ShaderInput> uniforms = Span<ShaderInput>(inputs_ + attr_len_ + ubo_len_, uniform_len_);
+ Span<ShaderInput> ssbos = Span<ShaderInput>(inputs_ + attr_len_ + ubo_len_ + uniform_len_,
+ ssbo_len_);
char *name_buf = name_buffer_;
const char format[] = " | %.8x : %4d : %s\n";
@@ -117,6 +119,13 @@ void ShaderInterface::debug_print()
}
}
+ if (ssbos.size() > 0) {
+ printf("\n Shader Storage Objects :\n");
+ }
+ for (const ShaderInput &ssbo : ssbos) {
+ printf(format, ssbo.name_hash, ssbo.binding, name_buf + ssbo.name_offset);
+ }
+
printf("\n");
}
diff --git a/source/blender/gpu/intern/gpu_shader_interface.hh b/source/blender/gpu/intern/gpu_shader_interface.hh
index aec58544111..ebed7b15170 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.hh
+++ b/source/blender/gpu/intern/gpu_shader_interface.hh
@@ -60,6 +60,7 @@ class ShaderInterface {
uint attr_len_ = 0;
uint ubo_len_ = 0;
uint uniform_len_ = 0;
+ uint ssbo_len_ = 0;
/** Enabled bind-points that needs to be fed with data. */
uint16_t enabled_attr_mask_ = 0;
uint16_t enabled_ubo_mask_ = 0;
@@ -99,6 +100,11 @@ class ShaderInterface {
return input_lookup(inputs_ + attr_len_ + ubo_len_, uniform_len_, binding);
}
+ inline const ShaderInput *ssbo_get(const char *name) const
+ {
+ return input_lookup(inputs_ + attr_len_ + ubo_len_ + uniform_len_, ssbo_len_, name);
+ }
+
inline const char *input_name_get(const ShaderInput *input) const
{
return name_buffer_ + input->name_offset;
diff --git a/source/blender/gpu/intern/gpu_shader_log.cc b/source/blender/gpu/intern/gpu_shader_log.cc
new file mode 100644
index 00000000000..12459b4b721
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_shader_log.cc
@@ -0,0 +1,217 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_dynstr.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+
+#include "gpu_shader_private.hh"
+
+#include "GPU_platform.h"
+
+#include "CLG_log.h"
+
+static CLG_LogRef LOG = {"gpu.shader"};
+
+namespace blender::gpu {
+
+/* -------------------------------------------------------------------- */
+/** \name Debug functions
+ * \{ */
+
+void Shader::print_log(Span<const char *> sources,
+ char *log,
+ const char *stage,
+ const bool error,
+ GPULogParser *parser)
+{
+ const char line_prefix[] = " | ";
+ char err_col[] = "\033[31;1m";
+ char warn_col[] = "\033[33;1m";
+ char info_col[] = "\033[0;2m";
+ char reset_col[] = "\033[0;0m";
+ char *sources_combined = BLI_string_join_arrayN((const char **)sources.data(), sources.size());
+ DynStr *dynstr = BLI_dynstr_new();
+
+ if (!CLG_color_support_get(&LOG)) {
+ err_col[0] = warn_col[0] = info_col[0] = reset_col[0] = '\0';
+ }
+
+ BLI_dynstr_appendf(dynstr, "\n");
+
+ char *log_line = log, *line_end;
+
+ LogCursor previous_location;
+
+ bool found_line_id = false;
+ while ((line_end = strchr(log_line, '\n'))) {
+ /* Skip empty lines. */
+ if (line_end == log_line) {
+ log_line++;
+ continue;
+ }
+
+ GPULogItem log_item;
+ log_line = parser->parse_line(log_line, log_item);
+
+ if (log_item.cursor.row == -1) {
+ found_line_id = false;
+ }
+
+ const char *src_line = sources_combined;
+
+ /* Separate from previous block. */
+ if (previous_location.source != log_item.cursor.source ||
+ previous_location.row != log_item.cursor.row) {
+ BLI_dynstr_appendf(dynstr, "%s%s%s\n", info_col, line_prefix, reset_col);
+ }
+ else if (log_item.cursor.column != previous_location.column) {
+ BLI_dynstr_appendf(dynstr, "%s\n", line_prefix);
+ }
+ /* Print line from the source file that is producing the error. */
+ if ((log_item.cursor.row != -1) && (log_item.cursor.row != previous_location.row ||
+ log_item.cursor.column != previous_location.column)) {
+ const char *src_line_end;
+ found_line_id = false;
+ /* error_line is 1 based in this case. */
+ int src_line_index = 1;
+ while ((src_line_end = strchr(src_line, '\n'))) {
+ if (src_line_index == log_item.cursor.row) {
+ found_line_id = true;
+ break;
+ }
+/* TODO(fclem) Make this an option to display N lines before error. */
+#if 0 /* Uncomment to print shader file up to the error line to have more context. */
+ BLI_dynstr_appendf(dynstr, "%5d | ", src_line_index);
+ BLI_dynstr_nappend(dynstr, src_line, (src_line_end + 1) - src_line);
+#endif
+ /* Continue to next line. */
+ src_line = src_line_end + 1;
+ src_line_index++;
+ }
+ /* Print error source. */
+ if (found_line_id) {
+ if (log_item.cursor.row != previous_location.row) {
+ BLI_dynstr_appendf(dynstr, "%5d | ", src_line_index);
+ }
+ else {
+ BLI_dynstr_appendf(dynstr, line_prefix);
+ }
+ BLI_dynstr_nappend(dynstr, src_line, (src_line_end + 1) - src_line);
+ /* Print char offset. */
+ BLI_dynstr_appendf(dynstr, line_prefix);
+ if (log_item.cursor.column != -1) {
+ for (int i = 0; i < log_item.cursor.column; i++) {
+ BLI_dynstr_appendf(dynstr, " ");
+ }
+ BLI_dynstr_appendf(dynstr, "^");
+ }
+ BLI_dynstr_appendf(dynstr, "\n");
+ }
+ }
+ BLI_dynstr_appendf(dynstr, line_prefix);
+
+ if (log_item.severity == Severity::Error) {
+ BLI_dynstr_appendf(dynstr, "%s%s%s: ", err_col, "Error", info_col);
+ }
+ else if (log_item.severity == Severity::Error) {
+ BLI_dynstr_appendf(dynstr, "%s%s%s: ", warn_col, "Warning", info_col);
+ }
+ /* Print the error itself. */
+ BLI_dynstr_append(dynstr, info_col);
+ BLI_dynstr_nappend(dynstr, log_line, (line_end + 1) - log_line);
+ BLI_dynstr_append(dynstr, reset_col);
+ /* Continue to next line. */
+ log_line = line_end + 1;
+ previous_location = log_item.cursor;
+ }
+ MEM_freeN(sources_combined);
+
+ CLG_Severity severity = error ? CLG_SEVERITY_ERROR : CLG_SEVERITY_WARN;
+
+ if (((LOG.type->flag & CLG_FLAG_USE) && (LOG.type->level >= 0)) ||
+ (severity >= CLG_SEVERITY_WARN)) {
+ const char *_str = BLI_dynstr_get_cstring(dynstr);
+ CLG_log_str(LOG.type, severity, this->name, stage, _str);
+ MEM_freeN((void *)_str);
+ }
+
+ BLI_dynstr_free(dynstr);
+}
+
+char *GPULogParser::skip_severity(char *log_line,
+ GPULogItem &log_item,
+ const char *error_msg,
+ const char *warning_msg) const
+{
+ if (STREQLEN(log_line, error_msg, strlen(error_msg))) {
+ log_line += strlen(error_msg);
+ log_item.severity = Severity::Error;
+ }
+ else if (STREQLEN(log_line, warning_msg, strlen(warning_msg))) {
+ log_line += strlen(warning_msg);
+ log_item.severity = Severity::Warning;
+ }
+ return log_line;
+}
+
+char *GPULogParser::skip_separators(char *log_line, const StringRef separators) const
+{
+ while (at_any(log_line, separators)) {
+ log_line++;
+ }
+ return log_line;
+}
+
+char *GPULogParser::skip_until(char *log_line, char stop_char) const
+{
+ char *cursor = log_line;
+ while (!ELEM(cursor[0], '\n', '\0')) {
+ if (cursor[0] == stop_char) {
+ return cursor;
+ }
+ cursor++;
+ }
+ return log_line;
+}
+
+bool GPULogParser::at_number(const char *log_line) const
+{
+ return log_line[0] >= '0' && log_line[0] <= '9';
+}
+
+bool GPULogParser::at_any(const char *log_line, const StringRef chars) const
+{
+ return chars.find(log_line[0]) != StringRef::not_found;
+}
+
+int GPULogParser::parse_number(const char *log_line, char **r_new_position) const
+{
+ return (int)strtol(log_line, r_new_position, 10);
+}
+
+/** \} */
+
+} // namespace blender::gpu
diff --git a/source/blender/gpu/intern/gpu_shader_private.hh b/source/blender/gpu/intern/gpu_shader_private.hh
index d9327bbc0f4..65720e457d8 100644
--- a/source/blender/gpu/intern/gpu_shader_private.hh
+++ b/source/blender/gpu/intern/gpu_shader_private.hh
@@ -21,6 +21,7 @@
#pragma once
#include "BLI_span.hh"
+#include "BLI_string_ref.hh"
#include "GPU_shader.h"
#include "gpu_shader_interface.hh"
@@ -29,6 +30,8 @@
namespace blender {
namespace gpu {
+class GPULogParser;
+
/**
* Implementation of shader compilation and uniforms handling.
* Base class which is then specialized for each implementation (GL, VK, ...).
@@ -49,6 +52,7 @@ class Shader {
virtual void vertex_shader_from_glsl(MutableSpan<const char *> sources) = 0;
virtual void geometry_shader_from_glsl(MutableSpan<const char *> sources) = 0;
virtual void fragment_shader_from_glsl(MutableSpan<const char *> sources) = 0;
+ virtual void compute_shader_from_glsl(MutableSpan<const char *> sources) = 0;
virtual bool finalize(void) = 0;
virtual void transform_feedback_names_set(Span<const char *> name_list,
@@ -73,7 +77,11 @@ class Shader {
};
protected:
- void print_log(Span<const char *> sources, char *log, const char *stage, const bool error);
+ void print_log(Span<const char *> sources,
+ char *log,
+ const char *stage,
+ const bool error,
+ GPULogParser *parser);
};
/* Syntactic sugar. */
@@ -90,6 +98,41 @@ static inline const Shader *unwrap(const GPUShader *vert)
return reinterpret_cast<const Shader *>(vert);
}
+enum class Severity {
+ Unknown,
+ Warning,
+ Error,
+};
+
+struct LogCursor {
+ int source = -1;
+ int row = -1;
+ int column = -1;
+};
+
+struct GPULogItem {
+ LogCursor cursor;
+ Severity severity = Severity::Unknown;
+};
+
+class GPULogParser {
+ public:
+ virtual char *parse_line(char *log_line, GPULogItem &log_item) = 0;
+
+ protected:
+ char *skip_severity(char *log_line,
+ GPULogItem &log_item,
+ const char *error_msg,
+ const char *warning_msg) const;
+ char *skip_separators(char *log_line, const StringRef separators) const;
+ char *skip_until(char *log_line, char stop_char) const;
+ bool at_number(const char *log_line) const;
+ bool at_any(const char *log_line, const StringRef chars) const;
+ int parse_number(const char *log_line, char **r_new_position) const;
+
+ MEM_CXX_CLASS_ALLOC_FUNCS("GPULogParser");
+};
+
} // namespace gpu
} // namespace blender
diff --git a/source/blender/gpu/intern/gpu_state.cc b/source/blender/gpu/intern/gpu_state.cc
index 5c33066c720..9ee8a8b8d32 100644
--- a/source/blender/gpu/intern/gpu_state.cc
+++ b/source/blender/gpu/intern/gpu_state.cc
@@ -187,7 +187,7 @@ void GPU_point_size(float size)
/* Programmable point size
* - shaders set their own point size when enabled
* - use GPU_point_size when disabled */
-/* TODO remove and use program point size everywhere */
+/* TODO: remove and use program point size everywhere. */
void GPU_program_point_size(bool enable)
{
StateManager *stack = Context::get()->state_manager;
diff --git a/source/blender/gpu/intern/gpu_state_private.hh b/source/blender/gpu/intern/gpu_state_private.hh
index b79350a6506..b96b71a7ac4 100644
--- a/source/blender/gpu/intern/gpu_state_private.hh
+++ b/source/blender/gpu/intern/gpu_state_private.hh
@@ -96,7 +96,7 @@ inline GPUState operator~(const GPUState &a)
union GPUStateMutable {
struct {
/* Viewport State */
- /** TODO remove */
+ /** TODO: remove. */
float depth_range[2];
/** Positive if using program point size. */
/* TODO(fclem): should be passed as uniform to all shaders. */
diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc
index 997064e82a2..6564cbda694 100644
--- a/source/blender/gpu/intern/gpu_texture.cc
+++ b/source/blender/gpu/intern/gpu_texture.cc
@@ -154,7 +154,7 @@ void Texture::attach_to(FrameBuffer *fb, GPUAttachmentType type)
return;
}
}
- BLI_assert(!"GPU: Error: Texture: Not enough attachment");
+ BLI_assert_msg(0, "GPU: Error: Texture: Not enough attachment");
}
void Texture::detach_from(FrameBuffer *fb)
@@ -166,7 +166,7 @@ void Texture::detach_from(FrameBuffer *fb)
return;
}
}
- BLI_assert(!"GPU: Error: Texture: Framebuffer is not attached");
+ BLI_assert_msg(0, "GPU: Error: Texture: Framebuffer is not attached");
}
void Texture::update(eGPUDataFormat format, const void *data)
@@ -400,7 +400,7 @@ void GPU_texture_update(GPUTexture *tex, eGPUDataFormat data_format, const void
}
/* Makes data interpretation aware of the source layout.
- * Skipping pixels correctly when changing rows when doing partial update.*/
+ * Skipping pixels correctly when changing rows when doing partial update. */
void GPU_unpack_row_length_set(uint len)
{
Context::get()->state_manager->texture_unpack_row_length_set(len);
@@ -600,7 +600,7 @@ void GPU_texture_py_reference_set(GPUTexture *tex, void **py_ref)
}
#endif
-/* TODO remove */
+/* TODO: remove. */
int GPU_texture_opengl_bindcode(const GPUTexture *tex)
{
return reinterpret_cast<const Texture *>(tex)->gl_bindcode_get();
diff --git a/source/blender/gpu/intern/gpu_texture_private.hh b/source/blender/gpu/intern/gpu_texture_private.hh
index a8f2e482bdd..2b8a5a5cc12 100644
--- a/source/blender/gpu/intern/gpu_texture_private.hh
+++ b/source/blender/gpu/intern/gpu_texture_private.hh
@@ -155,7 +155,7 @@ class Texture {
void mip_size_get(int mip, int r_size[3]) const
{
- /* TODO assert if lvl is below the limit of 1px in each dimension. */
+ /* TODO: assert if lvl is below the limit of 1px in each dimension. */
int div = 1 << mip;
r_size[0] = max_ii(1, w_ / div);
@@ -559,7 +559,7 @@ static inline eGPUTextureFormat to_texture_format(const GPUVertFormat *format)
case GPU_COMP_I16:
return GPU_RGBA16I;
case GPU_COMP_U16:
- /* Note: Checking the fetch mode to select the right GPU texture format. This can be
+ /* NOTE: Checking the fetch mode to select the right GPU texture format. This can be
* added to other formats as well. */
switch (format->attrs[0].fetch_mode) {
case GPU_FETCH_INT:
diff --git a/source/blender/gpu/intern/gpu_uniform_buffer.cc b/source/blender/gpu/intern/gpu_uniform_buffer.cc
index 3edb090d81c..3a9269d1753 100644
--- a/source/blender/gpu/intern/gpu_uniform_buffer.cc
+++ b/source/blender/gpu/intern/gpu_uniform_buffer.cc
@@ -114,11 +114,11 @@ static void buffer_from_list_inputs_sort(ListBase *inputs)
if (input->type == GPU_MAT3) {
/* Alignment for mat3 is not handled currently, so not supported */
- BLI_assert(!"mat3 not supported in UBO");
+ BLI_assert_msg(0, "mat3 not supported in UBO");
continue;
}
if (input->type > MAX_UBO_GPU_TYPE) {
- BLI_assert(!"GPU type not supported in UBO");
+ BLI_assert_msg(0, "GPU type not supported in UBO");
continue;
}
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.cc b/source/blender/gpu/intern/gpu_vertex_buffer.cc
index 09b9eba9f95..7ff68242c17 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer.cc
+++ b/source/blender/gpu/intern/gpu_vertex_buffer.cc
@@ -28,8 +28,8 @@
#include "gpu_backend.hh"
#include "gpu_vertex_format_private.h"
-#include "gl_vertex_buffer.hh" /* TODO remove */
-#include "gpu_context_private.hh" /* TODO remove */
+#include "gl_vertex_buffer.hh" /* TODO: remove. */
+#include "gpu_context_private.hh" /* TODO: remove. */
#include "gpu_vertex_buffer_private.hh"
@@ -149,6 +149,16 @@ GPUVertBuf *GPU_vertbuf_duplicate(GPUVertBuf *verts_)
return wrap(unwrap(verts_)->duplicate());
}
+const void *GPU_vertbuf_read(GPUVertBuf *verts)
+{
+ return unwrap(verts)->read();
+}
+
+void *GPU_vertbuf_unmap(const GPUVertBuf *verts, const void *mapped_data)
+{
+ return unwrap(verts)->unmap(mapped_data);
+}
+
/** Same as discard but does not free. */
void GPU_vertbuf_clear(GPUVertBuf *verts)
{
@@ -219,7 +229,7 @@ void GPU_vertbuf_attr_fill(GPUVertBuf *verts_, uint a_idx, const void *data)
GPU_vertbuf_attr_fill_stride(verts_, a_idx, stride, data);
}
-/** Fills a whole vertex (all attributes). Data must match packed layout. */
+/** Fills a whole vertex (all attributes). Data must match packed layout. */
void GPU_vertbuf_vert_set(GPUVertBuf *verts_, uint v_idx, const void *data)
{
VertBuf *verts = unwrap(verts_);
@@ -277,7 +287,7 @@ void GPU_vertbuf_attr_get_raw_data(GPUVertBuf *verts_, uint a_idx, GPUVertBufRaw
/* NOTE: Be careful when using this. The data needs to match the expected format. */
void *GPU_vertbuf_get_data(const GPUVertBuf *verts)
{
- /* TODO Assert that the format has no padding. */
+ /* TODO: Assert that the format has no padding. */
return unwrap(verts)->data;
}
@@ -286,7 +296,7 @@ void *GPU_vertbuf_get_data(const GPUVertBuf *verts)
void *GPU_vertbuf_steal_data(GPUVertBuf *verts_)
{
VertBuf *verts = unwrap(verts_);
- /* TODO Assert that the format has no padding. */
+ /* TODO: Assert that the format has no padding. */
BLI_assert(verts->data);
void *data = verts->data;
verts->data = nullptr;
@@ -324,6 +334,11 @@ void GPU_vertbuf_use(GPUVertBuf *verts)
unwrap(verts)->upload();
}
+void GPU_vertbuf_bind_as_ssbo(struct GPUVertBuf *verts, int binding)
+{
+ unwrap(verts)->bind_as_ssbo(binding);
+}
+
/* XXX this is just a wrapper for the use of the Hair refine workaround.
* To be used with GPU_vertbuf_use(). */
void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, void *data)
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer_private.hh b/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
index 67a09f6f83c..9531c2c1a5f 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
@@ -66,6 +66,7 @@ class VertBuf {
void allocate(uint vert_len);
void resize(uint vert_len);
void upload(void);
+ virtual void bind_as_ssbo(uint binding) = 0;
VertBuf *duplicate(void);
@@ -96,6 +97,8 @@ class VertBuf {
}
virtual void update_sub(uint start, uint len, void *data) = 0;
+ virtual const void *read() const = 0;
+ virtual void *unmap(const void *mapped_data) const = 0;
protected:
virtual void acquire_data(void) = 0;
diff --git a/source/blender/gpu/intern/gpu_vertex_format.cc b/source/blender/gpu/intern/gpu_vertex_format.cc
index 8498da11507..78a119bcec8 100644
--- a/source/blender/gpu/intern/gpu_vertex_format.cc
+++ b/source/blender/gpu/intern/gpu_vertex_format.cc
@@ -284,7 +284,7 @@ void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uin
data[i] = attr_name[i];
}
/* We use a hash to identify each data layer based on its name.
- * NOTE: This is still prone to hash collision but the risks are very low.*/
+ * NOTE: This is still prone to hash collision but the risks are very low. */
/* Start hashing after the first 2 chars. */
*(uint *)&data[4] = BLI_ghashutil_strhash_p_murmur(attr_name + 4);
}
@@ -306,7 +306,8 @@ void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uin
#endif
}
-/* Make attribute layout non-interleaved.
+/**
+ * Make attribute layout non-interleaved.
* Warning! This does not change data layout!
* Use direct buffer access to fill the data.
* This is for advanced usage.
@@ -314,11 +315,11 @@ void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uin
* De-interleaved data means all attribute data for each attribute
* is stored continuously like this:
* 000011112222
- * instead of :
+ * instead of:
* 012012012012
*
- * Note this is per attribute de-interleaving, NOT per component.
- * */
+ * \note This is per attribute de-interleaving, NOT per component.
+ */
void GPU_vertformat_deinterleave(GPUVertFormat *format)
{
/* Ideally we should change the stride and offset here. This would allow
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index c118145ebd6..96bf1ec40b0 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -248,7 +248,7 @@ void *GPU_viewport_engine_data_create(GPUViewport *viewport, void *engine_type)
}
}
- BLI_assert(!"Too many draw engines enabled at the same time");
+ BLI_assert_msg(0, "Too many draw engines enabled at the same time");
return NULL;
}
@@ -284,7 +284,7 @@ static void gpu_viewport_engines_data_free(GPUViewport *viewport)
MEM_freeN(data);
- /* Mark as unused*/
+ /* Mark as unused. */
viewport->engine_data[i].handle = NULL;
}
diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc
index e7d67be6d0e..f90c37e5c50 100644
--- a/source/blender/gpu/opengl/gl_backend.cc
+++ b/source/blender/gpu/opengl/gl_backend.cc
@@ -38,6 +38,17 @@ namespace blender::gpu {
/** \name Platform
* \{ */
+static bool match_renderer(StringRef renderer, const Vector<std::string> &items)
+{
+ for (const std::string &item : items) {
+ const std::string wrapped = " " + item + " ";
+ if (renderer.endswith(item) || renderer.find(wrapped) != StringRef::not_found) {
+ return true;
+ }
+ }
+ return false;
+}
+
void GLBackend::platform_init()
{
BLI_assert(!GPG.initialized);
@@ -288,14 +299,25 @@ static void detect_workarounds()
* The work around uses `GPU_RGBA16I`.
*/
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_OFFICIAL)) {
- if (strstr(renderer, " RX 460 ") || strstr(renderer, " RX 470 ") ||
- strstr(renderer, " RX 480 ") || strstr(renderer, " RX 490 ") ||
- strstr(renderer, " RX 560 ") || strstr(renderer, " RX 560X ") ||
- strstr(renderer, " RX 570 ") || strstr(renderer, " RX 580 ") ||
- strstr(renderer, " RX 580X ") || strstr(renderer, " RX 590 ") ||
- strstr(renderer, " RX550/550 ") || strstr(renderer, " (TM) 520 ") ||
- strstr(renderer, " (TM) 530 ") || strstr(renderer, " R5 ") || strstr(renderer, " R7 ") ||
- strstr(renderer, " R9 ")) {
+ const Vector<std::string> matches = {"RX 460",
+ "RX 470",
+ "RX 480",
+ "RX 490",
+ "RX 560",
+ "RX 560X",
+ "RX 570",
+ "RX 580",
+ "RX 580X",
+ "RX 590",
+ "RX550/550",
+ "(TM) 520",
+ "(TM) 530",
+ "(TM) 535",
+ "R5",
+ "R7",
+ "R9"};
+
+ if (match_renderer(renderer, matches)) {
GCaps.use_hq_normals_workaround = true;
}
}
@@ -343,8 +365,8 @@ static void detect_workarounds()
(strstr(version, "Build 20.19.15.4285"))) {
GCaps.use_main_context_workaround = true;
}
- /* See T70187: merging vertices fail. This has been tested from 18.2.2 till 19.3.0~dev of the
- * Mesa driver */
+ /* See T70187: merging vertices fail. This has been tested from `18.2.2` till `19.3.0~dev`
+ * of the Mesa driver */
if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE) &&
(strstr(version, "Mesa 18.") || strstr(version, "Mesa 19.0") ||
strstr(version, "Mesa 19.1") || strstr(version, "Mesa 19.2"))) {
@@ -437,6 +459,16 @@ void GLBackend::capabilities_init()
GCaps.mem_stats_support = GLEW_NVX_gpu_memory_info || GLEW_ATI_meminfo;
GCaps.shader_image_load_store_support = GLEW_ARB_shader_image_load_store;
+ GCaps.compute_shader_support = GLEW_ARB_compute_shader;
+ if (GCaps.compute_shader_support) {
+ glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &GCaps.max_work_group_count[0]);
+ glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &GCaps.max_work_group_count[1]);
+ glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &GCaps.max_work_group_count[2]);
+ glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &GCaps.max_work_group_size[0]);
+ glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, &GCaps.max_work_group_size[1]);
+ glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, &GCaps.max_work_group_size[2]);
+ }
+ GCaps.shader_storage_buffer_objects_support = GLEW_ARB_shader_storage_buffer_object;
/* GL specific capabilities. */
glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &GLContext::max_texture_3d_size);
glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &GLContext::max_cubemap_size);
diff --git a/source/blender/gpu/opengl/gl_backend.hh b/source/blender/gpu/opengl/gl_backend.hh
index 231e5811b45..e9dcdffced0 100644
--- a/source/blender/gpu/opengl/gl_backend.hh
+++ b/source/blender/gpu/opengl/gl_backend.hh
@@ -28,6 +28,7 @@
#include "BLI_vector.hh"
#include "gl_batch.hh"
+#include "gl_compute.hh"
#include "gl_context.hh"
#include "gl_drawlist.hh"
#include "gl_framebuffer.hh"
@@ -126,6 +127,12 @@ class GLBackend : public GPUBackend {
return shared_orphan_list_;
};
+ void compute_dispatch(int groups_x_len, int groups_y_len, int groups_z_len) override
+ {
+ GLContext::get()->state_manager_active_get()->apply_state();
+ GLCompute::dispatch(groups_x_len, groups_y_len, groups_z_len);
+ }
+
private:
static void platform_init(void);
static void platform_exit(void);
diff --git a/source/blender/gpu/opengl/gl_compute.cc b/source/blender/gpu/opengl/gl_compute.cc
new file mode 100644
index 00000000000..fa8317dde4a
--- /dev/null
+++ b/source/blender/gpu/opengl/gl_compute.cc
@@ -0,0 +1,35 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gl_compute.hh"
+
+#include "gl_debug.hh"
+
+#include "glew-mx.h"
+
+namespace blender::gpu {
+
+void GLCompute::dispatch(int group_x_len, int group_y_len, int group_z_len)
+{
+ glDispatchCompute(group_x_len, group_y_len, group_z_len);
+ debug::check_gl_error("Dispatch Compute");
+}
+
+} // namespace blender::gpu
diff --git a/source/blender/gpu/opengl/gl_compute.hh b/source/blender/gpu/opengl/gl_compute.hh
new file mode 100644
index 00000000000..2fd918ddd10
--- /dev/null
+++ b/source/blender/gpu/opengl/gl_compute.hh
@@ -0,0 +1,30 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#pragma once
+
+namespace blender::gpu {
+
+class GLCompute {
+ public:
+ static void dispatch(int group_x_len, int group_y_len, int group_z_len);
+};
+
+} // namespace blender::gpu
diff --git a/source/blender/gpu/opengl/gl_context.cc b/source/blender/gpu/opengl/gl_context.cc
index 6c9c6e10774..23654cb96f3 100644
--- a/source/blender/gpu/opengl/gl_context.cc
+++ b/source/blender/gpu/opengl/gl_context.cc
@@ -39,7 +39,7 @@
#include "gl_state.hh"
#include "gl_uniform_buffer.hh"
-#include "gl_backend.hh" /* TODO remove */
+#include "gl_backend.hh" /* TODO: remove. */
#include "gl_context.hh"
using namespace blender;
diff --git a/source/blender/gpu/opengl/gl_debug.cc b/source/blender/gpu/opengl/gl_debug.cc
index ac42a950945..3e259235515 100644
--- a/source/blender/gpu/opengl/gl_debug.cc
+++ b/source/blender/gpu/opengl/gl_debug.cc
@@ -81,9 +81,11 @@ static void APIENTRY debug_callback(GLenum UNUSED(source),
return;
}
- if (TRIM_NVIDIA_BUFFER_INFO &&
- GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_OFFICIAL) &&
- STRPREFIX(message, "Buffer detailed info")) {
+ /* NOTE: callback function can be triggered during before the platform is initialized.
+ * In this case invoking `GPU_type_matches` would fail and
+ * therefore the message is checked before the platform matching. */
+ if (TRIM_NVIDIA_BUFFER_INFO && STRPREFIX(message, "Buffer detailed info") &&
+ GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_OFFICIAL)) {
/** Suppress buffer infos flooding the output. */
return;
}
diff --git a/source/blender/gpu/opengl/gl_drawlist.hh b/source/blender/gpu/opengl/gl_drawlist.hh
index db4b9c03c3c..6f80fdd5a8a 100644
--- a/source/blender/gpu/opengl/gl_drawlist.hh
+++ b/source/blender/gpu/opengl/gl_drawlist.hh
@@ -72,7 +72,7 @@ class GLDrawList : public DrawList {
GLuint buffer_id_;
/** Length of whole the buffer (in byte). */
GLsizeiptr buffer_size_;
- /** Offset of data_ inside the whole buffer (in byte). */
+ /** Offset of `data_` inside the whole buffer (in byte). */
GLintptr data_offset_;
/** To free the buffer_id_. */
diff --git a/source/blender/gpu/opengl/gl_framebuffer.cc b/source/blender/gpu/opengl/gl_framebuffer.cc
index 920dac407d7..8da114d9270 100644
--- a/source/blender/gpu/opengl/gl_framebuffer.cc
+++ b/source/blender/gpu/opengl/gl_framebuffer.cc
@@ -86,7 +86,7 @@ GLFrameBuffer::~GLFrameBuffer()
/* Restore default frame-buffer if this frame-buffer was bound. */
if (context_->active_fb == this && context_->back_left != this) {
/* If this assert triggers it means the frame-buffer is being freed while in use by another
- * context which, by the way, is TOTALLY UNSAFE!!! */
+ * context which, by the way, is TOTALLY UNSAFE! */
BLI_assert(context_ == Context::get());
GPU_framebuffer_restore();
}
@@ -268,7 +268,7 @@ void GLFrameBuffer::bind(bool enabled_srgb)
}
if (context_ != GLContext::get()) {
- BLI_assert(!"Trying to use the same frame-buffer in multiple context");
+ BLI_assert_msg(0, "Trying to use the same frame-buffer in multiple context");
return;
}
@@ -379,7 +379,7 @@ void GLFrameBuffer::clear_attachment(GPUAttachmentType type,
glClearBufferfv(GL_DEPTH, 0, &depth);
}
else {
- BLI_assert(!"Unhandled data format");
+ BLI_assert_msg(0, "Unhandled data format");
}
}
else {
@@ -395,7 +395,7 @@ void GLFrameBuffer::clear_attachment(GPUAttachmentType type,
glClearBufferiv(GL_COLOR, slot, (GLint *)clear_value);
break;
default:
- BLI_assert(!"Unhandled data format");
+ BLI_assert_msg(0, "Unhandled data format");
break;
}
}
diff --git a/source/blender/gpu/opengl/gl_immediate.cc b/source/blender/gpu/opengl/gl_immediate.cc
index 63e3162944d..2f7fa5a78fc 100644
--- a/source/blender/gpu/opengl/gl_immediate.cc
+++ b/source/blender/gpu/opengl/gl_immediate.cc
@@ -155,7 +155,7 @@ void GLImmediate::end()
GLContext::get()->state_manager->apply_state();
/* We convert the offset in vertex offset from the buffer's start.
- * This works because we added some padding to align the first vertex vertex. */
+ * This works because we added some padding to align the first vertex vertex. */
uint v_first = buffer_offset() / vertex_format.stride;
GLVertArray::update_bindings(
vao_id_, v_first, &vertex_format, reinterpret_cast<Shader *>(shader)->interface);
diff --git a/source/blender/gpu/opengl/gl_index_buffer.cc b/source/blender/gpu/opengl/gl_index_buffer.cc
index e2c18c5d0b9..e305f765ad9 100644
--- a/source/blender/gpu/opengl/gl_index_buffer.cc
+++ b/source/blender/gpu/opengl/gl_index_buffer.cc
@@ -40,17 +40,14 @@ void GLIndexBuf::bind()
return;
}
- if (ibo_id_ == 0) {
+ const bool allocate_on_device = ibo_id_ == 0;
+ if (allocate_on_device) {
glGenBuffers(1, &ibo_id_);
-
- if (data_ == nullptr) {
- debug::raise_gl_error("Trying to use Index Buffer but the buffer contains no data");
- }
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_id_);
- if (data_ != nullptr) {
+ if (data_ != nullptr || allocate_on_device) {
size_t size = this->size_get();
/* Sends data to GPU. */
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data_, GL_STATIC_DRAW);
@@ -59,4 +56,29 @@ void GLIndexBuf::bind()
}
}
+void GLIndexBuf::bind_as_ssbo(uint binding)
+{
+ bind();
+ BLI_assert(ibo_id_ != 0);
+ glBindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, ibo_id_);
+}
+
+const uint32_t *GLIndexBuf::read() const
+{
+ BLI_assert(is_active());
+ void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
+ uint32_t *result = static_cast<uint32_t *>(data);
+ return result;
+}
+
+bool GLIndexBuf::is_active() const
+{
+ if (!ibo_id_) {
+ return false;
+ }
+ int active_ibo_id = 0;
+ glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &active_ibo_id);
+ return ibo_id_ == active_ibo_id;
+}
+
} // namespace blender::gpu
diff --git a/source/blender/gpu/opengl/gl_index_buffer.hh b/source/blender/gpu/opengl/gl_index_buffer.hh
index b84934bb77f..0dbdaa6d398 100644
--- a/source/blender/gpu/opengl/gl_index_buffer.hh
+++ b/source/blender/gpu/opengl/gl_index_buffer.hh
@@ -34,6 +34,7 @@ namespace blender::gpu {
class GLIndexBuf : public IndexBuf {
friend class GLBatch;
friend class GLDrawList;
+ friend class GLShader; /* For compute shaders. */
private:
GLuint ibo_id_ = 0;
@@ -42,6 +43,9 @@ class GLIndexBuf : public IndexBuf {
~GLIndexBuf();
void bind(void);
+ void bind_as_ssbo(uint binding) override;
+
+ const uint32_t *read() const override;
void *offset_ptr(uint additional_vertex_offset) const
{
@@ -57,6 +61,9 @@ class GLIndexBuf : public IndexBuf {
return (index_type_ == GPU_INDEX_U16) ? 0xFFFFu : 0xFFFFFFFFu;
}
+ private:
+ bool is_active() const;
+
MEM_CXX_CLASS_ALLOC_FUNCS("GLIndexBuf")
};
diff --git a/source/blender/gpu/opengl/gl_query.cc b/source/blender/gpu/opengl/gl_query.cc
index 8a42719c665..da9770b4cc1 100644
--- a/source/blender/gpu/opengl/gl_query.cc
+++ b/source/blender/gpu/opengl/gl_query.cc
@@ -41,7 +41,7 @@ void GLQueryPool::init(GPUQueryType type)
query_issued_ = 0;
}
-#if 0 /* TODO to avoid realloc of permanent query pool. */
+#if 0 /* TODO: to avoid realloc of permanent query pool. */
void GLQueryPool::reset(GPUQueryType type)
{
initialized_ = false;
@@ -50,7 +50,7 @@ void GLQueryPool::reset(GPUQueryType type)
void GLQueryPool::begin_query()
{
- /* TODO add assert about expected usage. */
+ /* TODO: add assert about expected usage. */
while (query_issued_ >= query_ids_.size()) {
int64_t prev_size = query_ids_.size();
query_ids_.resize(prev_size + QUERY_CHUNCK_LEN);
@@ -61,7 +61,7 @@ void GLQueryPool::begin_query()
void GLQueryPool::end_query()
{
- /* TODO add assert about expected usage. */
+ /* TODO: add assert about expected usage. */
glEndQuery(gl_type_);
}
@@ -70,7 +70,7 @@ void GLQueryPool::get_occlusion_result(MutableSpan<uint32_t> r_values)
BLI_assert(r_values.size() == query_issued_);
for (int i = 0; i < query_issued_; i++) {
- /* Note: This is a sync point. */
+ /* NOTE: This is a sync point. */
glGetQueryObjectuiv(query_ids_[i], GL_QUERY_RESULT, &r_values[i]);
}
}
diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc
index dd08a67517e..66a1bd5ceb7 100644
--- a/source/blender/gpu/opengl/gl_shader.cc
+++ b/source/blender/gpu/opengl/gl_shader.cc
@@ -26,6 +26,7 @@
#include "BLI_string.h"
#include "BLI_vector.hh"
+#include "GPU_capabilities.h"
#include "GPU_platform.h"
#include "gl_backend.hh"
@@ -63,6 +64,7 @@ GLShader::~GLShader()
glDeleteShader(vert_shader_);
glDeleteShader(geom_shader_);
glDeleteShader(frag_shader_);
+ glDeleteShader(compute_shader_);
glDeleteProgram(shader_program_);
}
@@ -72,7 +74,7 @@ GLShader::~GLShader()
/** \name Shader stage creation
* \{ */
-char *GLShader::glsl_patch_get()
+static char *glsl_patch_default_get()
{
/** Used for shader patching. Init once. */
static char patch[512] = "\0";
@@ -111,6 +113,30 @@ char *GLShader::glsl_patch_get()
return patch;
}
+static char *glsl_patch_compute_get()
+{
+ /** Used for shader patching. Init once. */
+ static char patch[512] = "\0";
+ if (patch[0] != '\0') {
+ return patch;
+ }
+
+ size_t slen = 0;
+ /* Version need to go first. */
+ STR_CONCAT(patch, slen, "#version 430\n");
+ STR_CONCAT(patch, slen, "#extension GL_ARB_compute_shader :enable\n");
+ BLI_assert(slen < sizeof(patch));
+ return patch;
+}
+
+char *GLShader::glsl_patch_get(GLenum gl_stage)
+{
+ if (gl_stage == GL_COMPUTE_SHADER) {
+ return glsl_patch_compute_get();
+ }
+ return glsl_patch_default_get();
+}
+
/* Create, compile and attach the shader stage to the shader program. */
GLuint GLShader::create_shader_stage(GLenum gl_stage, MutableSpan<const char *> sources)
{
@@ -121,7 +147,7 @@ GLuint GLShader::create_shader_stage(GLenum gl_stage, MutableSpan<const char *>
}
/* Patch the shader code using the first source slot. */
- sources[0] = glsl_patch_get();
+ sources[0] = glsl_patch_get(gl_stage);
glShaderSource(shader, sources.size(), sources.data(), nullptr);
glCompileShader(shader);
@@ -132,15 +158,19 @@ GLuint GLShader::create_shader_stage(GLenum gl_stage, MutableSpan<const char *>
char log[5000] = "";
glGetShaderInfoLog(shader, sizeof(log), nullptr, log);
if (log[0] != '\0') {
+ GLLogParser parser;
switch (gl_stage) {
case GL_VERTEX_SHADER:
- this->print_log(sources, log, "VertShader", !status);
+ this->print_log(sources, log, "VertShader", !status, &parser);
break;
case GL_GEOMETRY_SHADER:
- this->print_log(sources, log, "GeomShader", !status);
+ this->print_log(sources, log, "GeomShader", !status, &parser);
break;
case GL_FRAGMENT_SHADER:
- this->print_log(sources, log, "FragShader", !status);
+ this->print_log(sources, log, "FragShader", !status, &parser);
+ break;
+ case GL_COMPUTE_SHADER:
+ this->print_log(sources, log, "ComputeShader", !status, &parser);
break;
}
}
@@ -172,6 +202,11 @@ void GLShader::fragment_shader_from_glsl(MutableSpan<const char *> sources)
frag_shader_ = this->create_shader_stage(GL_FRAGMENT_SHADER, sources);
}
+void GLShader::compute_shader_from_glsl(MutableSpan<const char *> sources)
+{
+ compute_shader_ = this->create_shader_stage(GL_COMPUTE_SHADER, sources);
+}
+
bool GLShader::finalize()
{
if (compilation_failed_) {
@@ -186,7 +221,8 @@ bool GLShader::finalize()
char log[5000];
glGetProgramInfoLog(shader_program_, sizeof(log), nullptr, log);
Span<const char *> sources;
- this->print_log(sources, log, "Linking", true);
+ GLLogParser parser;
+ this->print_log(sources, log, "Linking", true, &parser);
return false;
}
diff --git a/source/blender/gpu/opengl/gl_shader.hh b/source/blender/gpu/opengl/gl_shader.hh
index 152eb2f068a..770bc29747e 100644
--- a/source/blender/gpu/opengl/gl_shader.hh
+++ b/source/blender/gpu/opengl/gl_shader.hh
@@ -43,6 +43,7 @@ class GLShader : public Shader {
GLuint vert_shader_ = 0;
GLuint geom_shader_ = 0;
GLuint frag_shader_ = 0;
+ GLuint compute_shader_ = 0;
/** True if any shader failed to compile. */
bool compilation_failed_ = false;
@@ -56,6 +57,7 @@ class GLShader : public Shader {
void vertex_shader_from_glsl(MutableSpan<const char *> sources) override;
void geometry_shader_from_glsl(MutableSpan<const char *> sources) override;
void fragment_shader_from_glsl(MutableSpan<const char *> sources) override;
+ void compute_shader_from_glsl(MutableSpan<const char *> sources) override;
bool finalize(void) override;
void transform_feedback_names_set(Span<const char *> name_list,
@@ -75,12 +77,23 @@ class GLShader : public Shader {
int program_handle_get(void) const override;
private:
- char *glsl_patch_get(void);
+ char *glsl_patch_get(GLenum gl_stage);
GLuint create_shader_stage(GLenum gl_stage, MutableSpan<const char *> sources);
MEM_CXX_CLASS_ALLOC_FUNCS("GLShader");
};
+class GLLogParser : public GPULogParser {
+ public:
+ char *parse_line(char *log_line, GPULogItem &log_item) override;
+
+ protected:
+ char *skip_severity_prefix(char *log_line, GPULogItem &log_item);
+ char *skip_severity_keyword(char *log_line, GPULogItem &log_item);
+
+ MEM_CXX_CLASS_ALLOC_FUNCS("GLLogParser");
+};
+
} // namespace gpu
} // namespace blender
diff --git a/source/blender/gpu/opengl/gl_shader_interface.cc b/source/blender/gpu/opengl/gl_shader_interface.cc
index 5870c645bf4..9cf072b2e8a 100644
--- a/source/blender/gpu/opengl/gl_shader_interface.cc
+++ b/source/blender/gpu/opengl/gl_shader_interface.cc
@@ -29,6 +29,8 @@
#include "gl_shader_interface.hh"
+#include "GPU_capabilities.h"
+
namespace blender::gpu {
/* -------------------------------------------------------------------- */
@@ -125,6 +127,18 @@ static inline int image_binding(int32_t program,
return -1;
}
}
+
+static inline int ssbo_binding(int32_t program, uint32_t ssbo_index)
+{
+ GLint binding = -1;
+ GLenum property = GL_BUFFER_BINDING;
+ GLint values_written = 0;
+ glGetProgramResourceiv(
+ program, GL_SHADER_STORAGE_BLOCK, ssbo_index, 1, &property, 1, &values_written, &binding);
+
+ return binding;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -149,6 +163,13 @@ GLShaderInterface::GLShaderInterface(GLuint program)
glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &active_uniform_len);
uniform_len = active_uniform_len;
+ GLint max_ssbo_name_len = 0, ssbo_len = 0;
+ if (GPU_shader_storage_buffer_objects_support()) {
+ glGetProgramInterfaceiv(program, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &ssbo_len);
+ glGetProgramInterfaceiv(
+ program, GL_SHADER_STORAGE_BLOCK, GL_MAX_NAME_LENGTH, &max_ssbo_name_len);
+ }
+
BLI_assert(ubo_len <= 16 && "enabled_ubo_mask_ is uint16_t");
/* Work around driver bug with Intel HD 4600 on Windows 7/8, where
@@ -162,6 +183,9 @@ GLShaderInterface::GLShaderInterface(GLuint program)
if (uniform_len > 0 && max_uniform_name_len == 0) {
max_uniform_name_len = 256;
}
+ if (ssbo_len > 0 && max_ssbo_name_len == 0) {
+ max_ssbo_name_len = 256;
+ }
/* GL_ACTIVE_UNIFORMS lied to us! Remove the UBO uniforms from the total before
* allocating the uniform array. */
@@ -186,11 +210,12 @@ GLShaderInterface::GLShaderInterface(GLuint program)
}
MEM_freeN(ubo_uni_ids);
- int input_tot_len = attr_len + ubo_len + uniform_len;
+ int input_tot_len = attr_len + ubo_len + uniform_len + ssbo_len;
inputs_ = (ShaderInput *)MEM_callocN(sizeof(ShaderInput) * input_tot_len, __func__);
const uint32_t name_buffer_len = attr_len * max_attr_name_len + ubo_len * max_ubo_name_len +
- uniform_len * max_uniform_name_len;
+ uniform_len * max_uniform_name_len +
+ ssbo_len * max_ssbo_name_len;
name_buffer_ = (char *)MEM_mallocN(name_buffer_len, "name_buffer");
uint32_t name_buffer_offset = 0;
@@ -257,6 +282,22 @@ GLShaderInterface::GLShaderInterface(GLuint program)
}
}
+ /* SSBOs */
+ for (int i = 0; i < ssbo_len; i++) {
+ char *name = name_buffer_ + name_buffer_offset;
+ GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
+ GLsizei name_len = 0;
+ glGetProgramResourceName(
+ program, GL_SHADER_STORAGE_BLOCK, i, remaining_buffer, &name_len, name);
+
+ const GLint binding = ssbo_binding(program, i);
+
+ ShaderInput *input = &inputs_[attr_len_ + ubo_len_ + uniform_len_ + ssbo_len_++];
+ input->binding = input->location = binding;
+
+ name_buffer_offset += this->set_input_name(input, name, name_len);
+ }
+
/* Builtin Uniforms */
for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORMS; u_int++) {
GPUUniformBuiltin u = static_cast<GPUUniformBuiltin>(u_int);
diff --git a/source/blender/gpu/opengl/gl_shader_log.cc b/source/blender/gpu/opengl/gl_shader_log.cc
new file mode 100644
index 00000000000..174cc63ad81
--- /dev/null
+++ b/source/blender/gpu/opengl/gl_shader_log.cc
@@ -0,0 +1,87 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2021 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup gpu
+ */
+
+#include "gl_shader.hh"
+
+#include "GPU_platform.h"
+
+namespace blender::gpu {
+
+char *GLLogParser::parse_line(char *log_line, GPULogItem &log_item)
+{
+ /* Skip ERROR: or WARNING:. */
+ log_line = skip_severity_prefix(log_line, log_item);
+ log_line = skip_separators(log_line, "(: ");
+
+ /* Parse error line & char numbers. */
+ if (at_number(log_line)) {
+ char *error_line_number_end;
+ log_item.cursor.row = parse_number(log_line, &error_line_number_end);
+ /* Try to fetch the error character (not always available). */
+ if (at_any(error_line_number_end, "(:") && at_number(&error_line_number_end[1])) {
+ log_item.cursor.column = parse_number(error_line_number_end + 1, &log_line);
+ }
+ else {
+ log_line = error_line_number_end;
+ }
+ /* There can be a 3rd number (case of mesa driver). */
+ if (at_any(log_line, "(:") && at_number(&log_line[1])) {
+ log_item.cursor.source = log_item.cursor.row;
+ log_item.cursor.row = log_item.cursor.column;
+ log_item.cursor.column = parse_number(log_line + 1, &error_line_number_end);
+ log_line = error_line_number_end;
+ }
+ }
+
+ if ((log_item.cursor.row != -1) && (log_item.cursor.column != -1)) {
+ if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_OFFICIAL) ||
+ GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_OFFICIAL)) {
+ /* 0:line */
+ log_item.cursor.row = log_item.cursor.column;
+ log_item.cursor.column = -1;
+ }
+ else {
+ /* line:char */
+ }
+ }
+
+ log_line = skip_separators(log_line, ":) ");
+
+ /* Skip to message. Avoid redundant info. */
+ log_line = skip_severity_keyword(log_line, log_item);
+ log_line = skip_separators(log_line, ":) ");
+
+ return log_line;
+}
+
+char *GLLogParser::skip_severity_prefix(char *log_line, GPULogItem &log_item)
+{
+ return skip_severity(log_line, log_item, "ERROR", "WARNING");
+}
+
+char *GLLogParser::skip_severity_keyword(char *log_line, GPULogItem &log_item)
+{
+ return skip_severity(log_line, log_item, "error", "warning");
+}
+
+} // namespace blender::gpu
diff --git a/source/blender/gpu/opengl/gl_state.cc b/source/blender/gpu/opengl/gl_state.cc
index b837eae4871..1106e3dab50 100644
--- a/source/blender/gpu/opengl/gl_state.cc
+++ b/source/blender/gpu/opengl/gl_state.cc
@@ -131,7 +131,7 @@ void GLStateManager::set_state(const GPUState &state)
set_shadow_bias(state.shadow_bias);
}
- /* TODO remove */
+ /* TODO: remove. */
if (changed.polygon_smooth) {
if (state.polygon_smooth) {
glEnable(GL_POLYGON_SMOOTH);
@@ -156,7 +156,7 @@ void GLStateManager::set_mutable_state(const GPUStateMutable &state)
{
GPUStateMutable changed = state ^ current_mutable_;
- /* TODO remove, should be uniform. */
+ /* TODO: remove, should be uniform. */
if (float_as_uint(changed.point_size) != 0) {
if (state.point_size > 0.0f) {
glEnable(GL_PROGRAM_POINT_SIZE);
@@ -168,12 +168,12 @@ void GLStateManager::set_mutable_state(const GPUStateMutable &state)
}
if (changed.line_width != 0) {
- /* TODO remove, should use wide line shader. */
+ /* TODO: remove, should use wide line shader. */
glLineWidth(clamp_f(state.line_width, line_width_range_[0], line_width_range_[1]));
}
if (changed.depth_range[0] != 0 || changed.depth_range[1] != 0) {
- /* TODO remove, should modify the projection matrix instead. */
+ /* TODO: remove, should modify the projection matrix instead. */
glDepthRange(UNPACK2(state.depth_range));
}
diff --git a/source/blender/gpu/opengl/gl_state.hh b/source/blender/gpu/opengl/gl_state.hh
index 651c3c22afa..3b4b40b1d10 100644
--- a/source/blender/gpu/opengl/gl_state.hh
+++ b/source/blender/gpu/opengl/gl_state.hh
@@ -121,6 +121,9 @@ static inline GLbitfield to_gl(eGPUBarrier barrier_bits)
if (barrier_bits & GPU_BARRIER_TEXTURE_FETCH) {
barrier |= GL_TEXTURE_FETCH_BARRIER_BIT;
}
+ if (barrier_bits & GPU_BARRIER_SHADER_STORAGE) {
+ barrier |= GL_SHADER_STORAGE_BARRIER_BIT;
+ }
return barrier;
}
diff --git a/source/blender/gpu/opengl/gl_texture.cc b/source/blender/gpu/opengl/gl_texture.cc
index b65686165d9..db1fda63c28 100644
--- a/source/blender/gpu/opengl/gl_texture.cc
+++ b/source/blender/gpu/opengl/gl_texture.cc
@@ -32,7 +32,7 @@
#include "gl_backend.hh"
#include "gl_debug.hh"
#include "gl_state.hh"
-#include "gpu_vertex_buffer_private.hh" /* TODO should be `gl_vertex_buffer.hh` */
+#include "gpu_vertex_buffer_private.hh" /* TODO: should be `gl_vertex_buffer.hh`. */
#include "gl_texture.hh"
@@ -79,7 +79,7 @@ bool GLTexture::init_internal()
target_ = to_gl_target(type_);
- /* We need to bind once to define the texture type. */
+ /* We need to bind once to define the texture type. */
GLContext::state_manager_active_get()->texture_bind_temp(this);
if (!this->proxy_check(0)) {
@@ -106,7 +106,7 @@ bool GLTexture::init_internal(GPUVertBuf *vbo)
GLVertBuf *gl_vbo = static_cast<GLVertBuf *>(unwrap(vbo));
target_ = to_gl_target(type_);
- /* We need to bind once to define the texture type. */
+ /* We need to bind once to define the texture type. */
GLContext::state_manager_active_get()->texture_bind_temp(this);
GLenum internal_format = to_gl_internal_format(format_);
@@ -347,7 +347,7 @@ void GLTexture::copy_to(Texture *dst_)
BLI_assert((dst->w_ == src->w_) && (dst->h_ == src->h_) && (dst->d_ == src->d_));
BLI_assert(dst->format_ == src->format_);
BLI_assert(dst->type_ == src->type_);
- /* TODO support array / 3D textures. */
+ /* TODO: support array / 3D textures. */
BLI_assert(dst->d_ == 0);
if (GLContext::copy_image_support) {
@@ -368,7 +368,7 @@ void GLTexture::copy_to(Texture *dst_)
void *GLTexture::read(int mip, eGPUDataFormat type)
{
BLI_assert(!(format_flag_ & GPU_FORMAT_COMPRESSED));
- BLI_assert(mip <= mipmaps_);
+ BLI_assert(mip <= mipmaps_ || mip == 0);
BLI_assert(validate_data_format(format_, type));
/* NOTE: mip_size_get() won't override any dimension that is equal to 0. */
diff --git a/source/blender/gpu/opengl/gl_texture.hh b/source/blender/gpu/opengl/gl_texture.hh
index 9da27056269..dc048ea05c0 100644
--- a/source/blender/gpu/opengl/gl_texture.hh
+++ b/source/blender/gpu/opengl/gl_texture.hh
@@ -44,7 +44,7 @@ class GLTexture : public Texture {
/** All samplers states. */
static GLuint samplers_[GPU_SAMPLER_MAX];
- /** Target to bind the texture to (GL_TEXTURE_1D, GL_TEXTURE_2D, etc...)*/
+ /** Target to bind the texture to (#GL_TEXTURE_1D, #GL_TEXTURE_2D, etc...). */
GLenum target_ = -1;
/** opengl identifier for texture. */
GLuint tex_id_ = 0;
diff --git a/source/blender/gpu/opengl/gl_vertex_buffer.cc b/source/blender/gpu/opengl/gl_vertex_buffer.cc
index a56d5269fde..ce16a491528 100644
--- a/source/blender/gpu/opengl/gl_vertex_buffer.cc
+++ b/source/blender/gpu/opengl/gl_vertex_buffer.cc
@@ -29,6 +29,10 @@ namespace blender::gpu {
void GLVertBuf::acquire_data()
{
+ if (usage_ == GPU_USAGE_DEVICE_ONLY) {
+ return;
+ }
+
/* Discard previous data if any. */
MEM_SAFE_FREE(data);
data = (uchar *)MEM_mallocN(sizeof(uchar) * this->size_alloc_get(), __func__);
@@ -36,6 +40,10 @@ void GLVertBuf::acquire_data()
void GLVertBuf::resize_data()
{
+ if (usage_ == GPU_USAGE_DEVICE_ONLY) {
+ return;
+ }
+
data = (uchar *)MEM_reallocN(data, sizeof(uchar) * this->size_alloc_get());
}
@@ -94,8 +102,10 @@ void GLVertBuf::bind()
vbo_size_ = this->size_used_get();
/* Orphan the vbo to avoid sync then upload data. */
glBufferData(GL_ARRAY_BUFFER, vbo_size_, nullptr, to_gl(usage_));
- glBufferSubData(GL_ARRAY_BUFFER, 0, vbo_size_, data);
-
+ /* Do not transfer data from host to device when buffer is device only. */
+ if (usage_ != GPU_USAGE_DEVICE_ONLY) {
+ glBufferSubData(GL_ARRAY_BUFFER, 0, vbo_size_, data);
+ }
memory_usage += vbo_size_;
if (usage_ == GPU_USAGE_STATIC) {
@@ -106,6 +116,37 @@ void GLVertBuf::bind()
}
}
+void GLVertBuf::bind_as_ssbo(uint binding)
+{
+ bind();
+ BLI_assert(vbo_id_ != 0);
+ glBindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, vbo_id_);
+}
+
+const void *GLVertBuf::read() const
+{
+ BLI_assert(is_active());
+ void *result = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
+ return result;
+}
+
+void *GLVertBuf::unmap(const void *mapped_data) const
+{
+ void *result = MEM_mallocN(vbo_size_, __func__);
+ memcpy(result, mapped_data, vbo_size_);
+ return result;
+}
+
+bool GLVertBuf::is_active() const
+{
+ if (!vbo_id_) {
+ return false;
+ }
+ int active_vbo_id = 0;
+ glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &active_vbo_id);
+ return vbo_id_ == active_vbo_id;
+}
+
void GLVertBuf::update_sub(uint start, uint len, void *data)
{
glBufferSubData(GL_ARRAY_BUFFER, start, len, data);
diff --git a/source/blender/gpu/opengl/gl_vertex_buffer.hh b/source/blender/gpu/opengl/gl_vertex_buffer.hh
index e2bf6cd00e8..6c38a2225b3 100644
--- a/source/blender/gpu/opengl/gl_vertex_buffer.hh
+++ b/source/blender/gpu/opengl/gl_vertex_buffer.hh
@@ -47,12 +47,19 @@ class GLVertBuf : public VertBuf {
void update_sub(uint start, uint len, void *data) override;
+ const void *read() const override;
+ void *unmap(const void *mapped_data) const override;
+
protected:
void acquire_data(void) override;
void resize_data(void) override;
void release_data(void) override;
void upload_data(void) override;
void duplicate_data(VertBuf *dst) override;
+ void bind_as_ssbo(uint binding) override;
+
+ private:
+ bool is_active() const;
MEM_CXX_CLASS_ALLOC_FUNCS("GLVertBuf");
};
@@ -65,6 +72,7 @@ static inline GLenum to_gl(GPUUsageType type)
case GPU_USAGE_DYNAMIC:
return GL_DYNAMIC_DRAW;
case GPU_USAGE_STATIC:
+ case GPU_USAGE_DEVICE_ONLY:
return GL_STATIC_DRAW;
default:
BLI_assert(0);
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl
index 21c7f79a57c..6dd0201535d 100644
--- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_frag.glsl
@@ -36,6 +36,9 @@ vec3 compute_masks(vec2 uv)
corner_rad = right_half ? outRoundCorners.y : outRoundCorners.x;
}
+ /* Fade emboss at the border. */
+ float emboss_size = upper_half ? 0.0 : min(1.0, uv_sdf.x / (corner_rad * ratio));
+
/* Signed distance field from the corner (in pixel).
* inner_sdf is sharp and outer_sdf is rounded. */
uv_sdf -= corner_rad;
@@ -43,9 +46,6 @@ vec3 compute_masks(vec2 uv)
float outer_sdf = -length(min(uv_sdf, 0.0));
float sdf = inner_sdf + outer_sdf + corner_rad;
- /* Fade emboss at the border. */
- float emboss_size = clamp((upper_half) ? 0.0 : (uv.x / corner_rad), 0.0, 1.0);
-
/* Clamp line width to be at least 1px wide. This can happen if the projection matrix
* has been scaled (i.e: Node editor)... */
float line_width = (lineWidth > 0.0) ? max(fwidth(uv.y), lineWidth) : 0.0;
diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl
index da6e6502e62..b937323f62a 100644
--- a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl
@@ -170,7 +170,7 @@ void main(void)
length_b = finalThickness[2];
}
- /* generate the start endcap (alpha < 0 used as endcap flag)*/
+ /* Generate the start end-cap (alpha < 0 used as end-cap flag). */
float extend = (fill_stroke > 0) ? 2 : 1;
if ((caps_start != GPENCIL_FLATCAP) && is_equal(P0, P2)) {
mTexCoord = vec2(1, 0.5);
@@ -211,7 +211,7 @@ void main(void)
gl_Position = vec4((sp2 - length_b * miter_b) / Viewport, getZdepth(P2), 1.0);
EmitVertex();
- /* generate the end endcap (alpha < 0 used as endcap flag)*/
+ /* Generate the end end-cap (alpha < 0 used as end-cap flag). */
if ((caps_end != GPENCIL_FLATCAP) && is_equal(P1, P3)) {
mTexCoord = vec2(0, 1);
mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0);
diff --git a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
index d85884e0a25..2568cd74445 100644
--- a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl
@@ -7,7 +7,7 @@ flat in int interp_size;
out vec4 fragColor;
-uniform sampler1DArray glyph;
+uniform sampler2D glyph;
const vec2 offsets4[4] = vec2[4](
vec2(-0.5, 0.5), vec2(0.5, 0.5), vec2(-0.5, -0.5), vec2(-0.5, -0.5));
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
index 4db27c3049d..a14ff5021bf 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_geometry.glsl
@@ -37,8 +37,13 @@ void node_geometry(vec3 I,
normal = (toworld * vec4(N, 0.0)).xyz;
true_normal = normal;
# endif
+
+# ifdef HAIR_SHADER
+ tangent = -hairTangent;
+# else
tangent_orco_z(orco, orco);
node_tangent(N, orco, objmat, tangent);
+# endif
parametric = vec3(barycentric, 0.0);
backfacing = (gl_FrontFacing) ? 0.0 : 1.0;
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl
index 5a68f802659..5129bf71903 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl
@@ -23,8 +23,8 @@ void node_subsurface_scattering(vec4 color,
/* Not perfect for texture_blur values between 0.0 and 1.0.
* Interpolate between separated color and color applied on irradiance. */
float one_minus_texture_blur = 1.0 - texture_blur;
- vec3 sss_albedo = color.rgb * texture_blur + one_minus_texture_blur;
- vec3 radiance_tint = color.rgb * one_minus_texture_blur + texture_blur;
+ vec3 sss_albedo = color.rgb * one_minus_texture_blur + texture_blur;
+ vec3 radiance_tint = color.rgb * texture_blur + one_minus_texture_blur;
/* Consider output radiance as irradiance. */
out_Diffuse_0.radiance *= radiance_tint;
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
index d8d9ecdf287..5745f11ede4 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_noise.glsl
@@ -2,7 +2,7 @@
* coordinates to act as a seed since the noise functions don't have seed values.
* A seed value is needed for generating distortion textures and color outputs.
* The offset's components are in the range [100, 200], not too high to cause
- * bad precision and not to small to be noticeable. We use float seed because
+ * bad precision and not too small to be noticeable. We use float seed because
* OSL only support float hashes.
*/
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl
index 60ed098beb3..4ad5d4232de 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_vector_math.glsl
@@ -150,3 +150,9 @@ void vector_math_faceforward(
{
outVector = faceforward(a, b, c);
}
+
+void vector_math_multiply_add(
+ vec3 a, vec3 b, vec3 c, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = a * b + c;
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_wavelength.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_wavelength.glsl
new file mode 100644
index 00000000000..2c5d38eabbe
--- /dev/null
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_wavelength.glsl
@@ -0,0 +1,15 @@
+void node_wavelength(float wavelength,
+ sampler1DArray spectrummap,
+ float layer,
+ vec3 xyz_to_r,
+ vec3 xyz_to_g,
+ vec3 xyz_to_b,
+ out vec4 color)
+{
+ mat3 xyz_to_rgb = mat3(xyz_to_r, xyz_to_g, xyz_to_b);
+ float t = (wavelength - 380.0) / (780.0 - 380.0);
+ vec3 xyz = texture(spectrummap, vec2(t, layer)).rgb;
+ vec3 rgb = xyz * xyz_to_rgb;
+ rgb *= 1.0 / 2.52; /* Empirical scale from lg to make all comps <= 1. */
+ color = vec4(clamp(rgb, 0.0, 1.0), 1.0);
+}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl
index d33465fa846..40e46bc250c 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_world_normals.glsl
@@ -1,4 +1,4 @@
-/* TODO : clean this ifdef mess */
+/* TODO: clean this `ifdef` mess. */
void world_normals_get(out vec3 N)
{
#ifndef VOLUMETRICS
diff --git a/source/blender/gpu/tests/gpu_index_buffer_test.cc b/source/blender/gpu/tests/gpu_index_buffer_test.cc
new file mode 100644
index 00000000000..9d767b58a7b
--- /dev/null
+++ b/source/blender/gpu/tests/gpu_index_buffer_test.cc
@@ -0,0 +1,49 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "GPU_index_buffer.h"
+
+#include "gpu_testing.hh"
+
+namespace blender::gpu::tests {
+
+static void test_gpu_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);
+ }
+
+ GPUIndexBuf *index_buffer = GPU_indexbuf_build(&builder);
+ EXPECT_NE(index_buffer, nullptr);
+ GPU_INDEXBUF_DISCARD_SAFE(index_buffer);
+}
+
+GPU_TEST(gpu_index_buffer_subbuilders)
+
+} // namespace blender::gpu::tests
diff --git a/source/blender/gpu/tests/gpu_shader_builtin_test.cc b/source/blender/gpu/tests/gpu_shader_builtin_test.cc
new file mode 100644
index 00000000000..f0061a6bf5c
--- /dev/null
+++ b/source/blender/gpu/tests/gpu_shader_builtin_test.cc
@@ -0,0 +1,94 @@
+/* Apache License, Version 2.0 */
+
+#include "gpu_testing.hh"
+
+#include "GPU_shader.h"
+
+namespace blender::gpu::tests {
+
+static void test_compile_builtin_shader(eGPUBuiltinShader shader_type, eGPUShaderConfig sh_cfg)
+{
+ GPUShader *sh = GPU_shader_get_builtin_shader_with_config(shader_type, sh_cfg);
+ EXPECT_NE(sh, nullptr);
+}
+
+static void test_compile_builtin_shader(eGPUBuiltinShader shader_type)
+{
+ test_compile_builtin_shader(shader_type, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(shader_type, GPU_SHADER_CFG_CLIPPED);
+}
+
+static void test_shader_builtin()
+{
+ GPU_shader_free_builtin_shaders();
+
+ test_compile_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR);
+ test_compile_builtin_shader(GPU_SHADER_3D_SMOOTH_COLOR);
+ test_compile_builtin_shader(GPU_SHADER_3D_DEPTH_ONLY);
+ test_compile_builtin_shader(GPU_SHADER_3D_FLAT_COLOR);
+ test_compile_builtin_shader(GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE);
+ test_compile_builtin_shader(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
+ test_compile_builtin_shader(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
+ test_compile_builtin_shader(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
+
+ test_compile_builtin_shader(GPU_SHADER_TEXT, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_KEYFRAME_DIAMOND, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_SIMPLE_LIGHTING, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_UNIFORM_COLOR, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_FLAT_COLOR, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_SMOOTH_COLOR, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_IMAGE, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_COLOR, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_DESATURATE_COLOR, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_CHECKER, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_DIAG_STRIPES, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_3D_POLYLINE_CLIPPED_UNIFORM_COLOR,
+ GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_3D_POLYLINE_FLAT_COLOR, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_3D_POLYLINE_SMOOTH_COLOR, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_POINT_FIXED_SIZE_UNIFORM_COLOR,
+ GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_POINT_UNIFORM_SIZE_VARYING_COLOR_OUTLINE_AA,
+ GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR,
+ GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR,
+ GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA,
+ GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA,
+ GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR,
+ GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_3D_POINT_VARYING_SIZE_UNIFORM_COLOR,
+ GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR,
+ GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_GPENCIL_STROKE, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_AREA_EDGES, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_WIDGET_BASE, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_WIDGET_BASE_INST, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_WIDGET_SHADOW, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_NODELINK, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_NODELINK_INST, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_UV_UNIFORM_COLOR, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_UV_VERTS, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_UV_FACEDOTS, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_UV_EDGES, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_UV_EDGES_SMOOTH, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_UV_FACES, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_UV_FACES_STRETCH_AREA, GPU_SHADER_CFG_DEFAULT);
+ test_compile_builtin_shader(GPU_SHADER_2D_UV_FACES_STRETCH_ANGLE, GPU_SHADER_CFG_DEFAULT);
+}
+
+GPU_TEST(shader_builtin)
+
+} // namespace blender::gpu::tests
diff --git a/source/blender/gpu/tests/gpu_shader_test.cc b/source/blender/gpu/tests/gpu_shader_test.cc
new file mode 100644
index 00000000000..43ff86ebbd8
--- /dev/null
+++ b/source/blender/gpu/tests/gpu_shader_test.cc
@@ -0,0 +1,306 @@
+/* Apache License, Version 2.0 */
+
+#include "testing/testing.h"
+
+#include "GPU_capabilities.h"
+#include "GPU_compute.h"
+#include "GPU_index_buffer.h"
+#include "GPU_shader.h"
+#include "GPU_texture.h"
+#include "GPU_vertex_buffer.h"
+#include "GPU_vertex_format.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "gpu_testing.hh"
+
+#include "GPU_glew.h"
+
+namespace blender::gpu::tests {
+
+static void test_gpu_shader_compute_2d()
+{
+
+ if (!GPU_compute_shader_support()) {
+ /* We can't test as a the platform does not support compute shaders. */
+ std::cout << "Skipping compute shader test: platform not supported";
+ return;
+ }
+
+ static constexpr uint SIZE = 512;
+
+ /* Build compute shader. */
+ const char *compute_glsl = R"(
+
+layout(local_size_x = 1, local_size_y = 1) in;
+layout(rgba32f, binding = 0) uniform image2D img_output;
+
+void main() {
+ vec4 pixel = vec4(1.0, 0.5, 0.2, 1.0);
+ imageStore(img_output, ivec2(gl_GlobalInvocationID.xy), pixel);
+}
+
+)";
+
+ GPUShader *shader = GPU_shader_create_compute(
+ compute_glsl, nullptr, nullptr, "gpu_shader_compute_2d");
+ EXPECT_NE(shader, nullptr);
+
+ /* Create texture to store result and attach to shader. */
+ GPUTexture *texture = GPU_texture_create_2d(
+ "gpu_shader_compute_2d", SIZE, SIZE, 0, GPU_RGBA32F, nullptr);
+ EXPECT_NE(texture, nullptr);
+
+ GPU_shader_bind(shader);
+ GPU_texture_image_bind(texture, GPU_shader_get_texture_binding(shader, "img_output"));
+
+ /* Dispatch compute task. */
+ GPU_compute_dispatch(shader, SIZE, SIZE, 1);
+
+ /* Check if compute has been done. */
+ GPU_memory_barrier(GPU_BARRIER_TEXTURE_FETCH);
+ float *data = static_cast<float *>(GPU_texture_read(texture, GPU_DATA_FLOAT, 0));
+ EXPECT_NE(data, nullptr);
+ for (int index = 0; index < SIZE * SIZE; index++) {
+ EXPECT_FLOAT_EQ(data[index * 4 + 0], 1.0f);
+ EXPECT_FLOAT_EQ(data[index * 4 + 1], 0.5f);
+ EXPECT_FLOAT_EQ(data[index * 4 + 2], 0.2f);
+ EXPECT_FLOAT_EQ(data[index * 4 + 3], 1.0f);
+ }
+ MEM_freeN(data);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+ GPU_texture_unbind(texture);
+ GPU_texture_free(texture);
+ GPU_shader_free(shader);
+}
+GPU_TEST(gpu_shader_compute_2d)
+
+static void test_gpu_shader_compute_1d()
+{
+
+ if (!GPU_compute_shader_support()) {
+ /* We can't test as a the platform does not support compute shaders. */
+ std::cout << "Skipping compute shader test: platform not supported";
+ return;
+ }
+
+ static constexpr uint SIZE = 10;
+
+ /* Build compute shader. */
+ const char *compute_glsl = R"(
+
+layout(local_size_x = 1) in;
+
+layout(rgba32f, binding = 1) uniform image1D outputVboData;
+
+void main() {
+ int index = int(gl_GlobalInvocationID.x);
+ vec4 pos = vec4(gl_GlobalInvocationID.x);
+ imageStore(outputVboData, index, pos);
+}
+
+)";
+
+ GPUShader *shader = GPU_shader_create_compute(
+ compute_glsl, nullptr, nullptr, "gpu_shader_compute_1d");
+ EXPECT_NE(shader, nullptr);
+
+ /* Construct Texture. */
+ GPUTexture *texture = GPU_texture_create_1d("gpu_shader_compute_1d", SIZE, 0, GPU_RGBA32F, NULL);
+ EXPECT_NE(texture, nullptr);
+
+ GPU_shader_bind(shader);
+ GPU_texture_image_bind(texture, GPU_shader_get_texture_binding(shader, "outputVboData"));
+
+ /* Dispatch compute task. */
+ GPU_compute_dispatch(shader, SIZE, 1, 1);
+
+ /* Check if compute has been done. */
+ GPU_memory_barrier(GPU_BARRIER_TEXTURE_FETCH);
+
+ /* Create texture to load back result. */
+ float *data = static_cast<float *>(GPU_texture_read(texture, GPU_DATA_FLOAT, 0));
+ EXPECT_NE(data, nullptr);
+ for (int index = 0; index < SIZE; index++) {
+ float expected_value = index;
+ EXPECT_FLOAT_EQ(data[index * 4 + 0], expected_value);
+ EXPECT_FLOAT_EQ(data[index * 4 + 1], expected_value);
+ EXPECT_FLOAT_EQ(data[index * 4 + 2], expected_value);
+ EXPECT_FLOAT_EQ(data[index * 4 + 3], expected_value);
+ }
+ MEM_freeN(data);
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+ GPU_texture_unbind(texture);
+ GPU_texture_free(texture);
+ GPU_shader_free(shader);
+}
+GPU_TEST(gpu_shader_compute_1d)
+
+static void test_gpu_shader_compute_vbo()
+{
+
+ if (!GPU_compute_shader_support()) {
+ /* We can't test as a the platform does not support compute shaders. */
+ std::cout << "Skipping compute shader test: platform not supported";
+ return;
+ }
+
+ static constexpr uint SIZE = 128;
+
+ /* Build compute shader. */
+ const char *compute_glsl = R"(
+
+layout(local_size_x = 1) in;
+
+layout(std430, binding = 0) writeonly buffer outputVboData
+{
+ vec4 out_positions[];
+};
+
+void main() {
+ uint index = gl_GlobalInvocationID.x;
+ vec4 pos = vec4(gl_GlobalInvocationID.x);
+ out_positions[index] = pos;
+}
+
+)";
+
+ GPUShader *shader = GPU_shader_create_compute(
+ compute_glsl, nullptr, nullptr, "gpu_shader_compute_vbo");
+ EXPECT_NE(shader, nullptr);
+ GPU_shader_bind(shader);
+
+ /* Construct VBO. */
+ static GPUVertFormat format = {0};
+ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_DEVICE_ONLY);
+ GPU_vertbuf_data_alloc(vbo, SIZE);
+ GPU_vertbuf_bind_as_ssbo(vbo, GPU_shader_get_ssbo(shader, "outputVboData"));
+
+ /* Dispatch compute task. */
+ GPU_compute_dispatch(shader, SIZE, 1, 1);
+
+ /* Check if compute has been done. */
+ GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE);
+
+ /* Download the vertex buffer. */
+ const float *data = static_cast<const float *>(GPU_vertbuf_read(vbo));
+ ASSERT_NE(data, nullptr);
+ for (int index = 0; index < SIZE; index++) {
+ float expected_value = index;
+ EXPECT_FLOAT_EQ(data[index * 4 + 0], expected_value);
+ EXPECT_FLOAT_EQ(data[index * 4 + 1], expected_value);
+ EXPECT_FLOAT_EQ(data[index * 4 + 2], expected_value);
+ EXPECT_FLOAT_EQ(data[index * 4 + 3], expected_value);
+ }
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+ GPU_vertbuf_discard(vbo);
+ GPU_shader_free(shader);
+}
+GPU_TEST(gpu_shader_compute_vbo)
+
+static void test_gpu_shader_compute_ibo()
+{
+
+ if (!GPU_compute_shader_support()) {
+ /* We can't test as a the platform does not support compute shaders. */
+ std::cout << "Skipping compute shader test: platform not supported";
+ return;
+ }
+
+ static constexpr uint SIZE = 128;
+
+ /* Build compute shader. */
+ const char *compute_glsl = R"(
+
+layout(local_size_x = 1) in;
+
+layout(std430, binding = 1) writeonly buffer outputIboData
+{
+ uint out_indexes[];
+};
+
+void main() {
+ uint store_index = int(gl_GlobalInvocationID.x);
+ out_indexes[store_index] = store_index;
+}
+
+)";
+
+ GPUShader *shader = GPU_shader_create_compute(
+ compute_glsl, nullptr, nullptr, "gpu_shader_compute_vbo");
+ EXPECT_NE(shader, nullptr);
+ GPU_shader_bind(shader);
+
+ /* Construct IBO. */
+ GPUIndexBuf *ibo = GPU_indexbuf_build_on_device(SIZE);
+ GPU_indexbuf_bind_as_ssbo(ibo, GPU_shader_get_ssbo(shader, "outputIboData"));
+
+ /* Dispatch compute task. */
+ GPU_compute_dispatch(shader, SIZE, 1, 1);
+
+ /* Check if compute has been done. */
+ GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE);
+
+ /* Download the index buffer. */
+ const uint32_t *data = GPU_indexbuf_read(ibo);
+ ASSERT_NE(data, nullptr);
+ for (int index = 0; index < SIZE; index++) {
+ uint32_t expected = index;
+ EXPECT_EQ(data[index], expected);
+ }
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+ GPU_indexbuf_discard(ibo);
+ GPU_shader_free(shader);
+}
+GPU_TEST(gpu_shader_compute_ibo)
+
+static void test_gpu_shader_ssbo_binding()
+{
+ if (!GPU_compute_shader_support()) {
+ /* We can't test as a the platform does not support compute shaders. */
+ std::cout << "Skipping compute shader test: platform not supported";
+ return;
+ }
+
+ /* Build compute shader. */
+ const char *compute_glsl = R"(
+
+layout(local_size_x = 1) in;
+
+layout(std430, binding = 0) buffer ssboBinding0
+{
+ int data0[];
+};
+layout(std430, binding = 1) buffer ssboBinding1
+{
+ int data1[];
+};
+
+void main() {
+}
+
+)";
+
+ GPUShader *shader = GPU_shader_create_compute(compute_glsl, nullptr, nullptr, "gpu_shader_ssbo");
+ EXPECT_NE(shader, nullptr);
+ GPU_shader_bind(shader);
+
+ EXPECT_EQ(0, GPU_shader_get_ssbo(shader, "ssboBinding0"));
+ EXPECT_EQ(1, GPU_shader_get_ssbo(shader, "ssboBinding1"));
+
+ /* Cleanup. */
+ GPU_shader_unbind();
+ GPU_shader_free(shader);
+}
+GPU_TEST(gpu_shader_ssbo_binding)
+
+} // namespace blender::gpu::tests
diff --git a/source/blender/gpu/tests/gpu_testing.hh b/source/blender/gpu/tests/gpu_testing.hh
index cf902a91264..c45770cb94e 100644
--- a/source/blender/gpu/tests/gpu_testing.hh
+++ b/source/blender/gpu/tests/gpu_testing.hh
@@ -15,13 +15,31 @@ namespace blender::gpu {
*/
class GPUTest : public ::testing::Test {
private:
+ GHOST_TDrawingContextType draw_context_type = GHOST_kDrawingContextTypeNone;
GHOST_SystemHandle ghost_system;
GHOST_ContextHandle ghost_context;
struct GPUContext *context;
protected:
+ GPUTest(GHOST_TDrawingContextType draw_context_type) : draw_context_type(draw_context_type)
+ {
+ }
+
void SetUp() override;
void TearDown() override;
};
+class GPUOpenGLTest : public GPUTest {
+ public:
+ GPUOpenGLTest() : GPUTest(GHOST_kDrawingContextTypeOpenGL)
+ {
+ }
+};
+
+#define GPU_TEST(test_name) \
+ TEST_F(GPUOpenGLTest, test_name) \
+ { \
+ test_##test_name(); \
+ }
+
} // namespace blender::gpu