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/GPU_select.h31
-rw-r--r--source/blender/gpu/GPU_shader.h2
-rw-r--r--source/blender/gpu/GPU_texture.h3
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c6
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.cc2
-rw-r--r--source/blender/gpu/intern/gpu_select.c44
-rw-r--r--source/blender/gpu/intern/gpu_select_pick.c206
-rw-r--r--source/blender/gpu/intern/gpu_select_private.h7
-rw-r--r--source/blender/gpu/intern/gpu_select_sample_query.cc49
-rw-r--r--source/blender/gpu/intern/gpu_shader.cc22
-rw-r--r--source/blender/gpu/intern/gpu_shader_create_info.cc17
-rw-r--r--source/blender/gpu/intern/gpu_shader_create_info.hh24
-rw-r--r--source/blender/gpu/intern/gpu_shader_dependency.cc35
-rw-r--r--source/blender/gpu/intern/gpu_shader_dependency_private.h5
-rw-r--r--source/blender/gpu/intern/gpu_shader_log.cc2
-rw-r--r--source/blender/gpu/opengl/gl_backend.cc6
-rw-r--r--source/blender/gpu/opengl/gl_context.hh2
-rw-r--r--source/blender/gpu/opengl/gl_shader.cc175
-rw-r--r--source/blender/gpu/opengl/gl_shader.hh8
-rw-r--r--source/blender/gpu/opengl/gl_shader_interface.cc4
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl2
-rw-r--r--source/blender/gpu/shaders/material/gpu_shader_material_subsurface_scattering.glsl2
24 files changed, 456 insertions, 202 deletions
diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h
index c02af763311..3076058c075 100644
--- a/source/blender/gpu/GPU_select.h
+++ b/source/blender/gpu/GPU_select.h
@@ -32,7 +32,7 @@ extern "C" {
struct rcti;
/** Flags for mode of operation. */
-enum {
+typedef enum eGPUSelectMode {
GPU_SELECT_ALL = 1,
/* gpu_select_query */
GPU_SELECT_NEAREST_FIRST_PASS = 2,
@@ -40,13 +40,32 @@ enum {
/* gpu_select_pick */
GPU_SELECT_PICK_ALL = 4,
GPU_SELECT_PICK_NEAREST = 5,
-};
+} eGPUSelectMode;
+
+/**
+ * The result of calling #GPU_select_begin & #GPU_select_end.
+ */
+typedef struct GPUSelectResult {
+ /** The selection identifier matching the value passed in by #GPU_select_load_id. */
+ unsigned int id;
+ /**
+ * The nearest depth.
+ * - Only supported by picking modes (#GPU_SELECT_PICK_ALL and #GPU_SELECT_PICK_NEAREST)
+ * since occlusion quires don't provide a convenient way of accessing the depth-buffer.
+ * - OpenGL's `GL_SELECT` supported both near and far depths,
+ * this has not been included as Blender doesn't need this however support could be added.
+ */
+ unsigned int depth;
+} GPUSelectResult;
/**
* Initialize and provide buffer for results.
*/
-void GPU_select_begin(
- unsigned int *buffer, unsigned int bufsize, const struct rcti *input, char mode, int oldhits);
+void GPU_select_begin(GPUSelectResult *buffer,
+ unsigned int buffer_len,
+ const struct rcti *input,
+ eGPUSelectMode mode,
+ int oldhits);
/**
* Loads a new selection id and ends previous query, if any.
* In second pass of selection it also returns
@@ -79,8 +98,8 @@ void GPU_select_cache_end(void);
*
* Note that comparing depth as uint is fine.
*/
-const uint *GPU_select_buffer_near(const uint *buffer, int hits);
-uint GPU_select_buffer_remove_by_id(uint *buffer, int hits, uint select_id);
+const GPUSelectResult *GPU_select_buffer_near(const GPUSelectResult *buffer, int hits);
+uint GPU_select_buffer_remove_by_id(GPUSelectResult *buffer, int hits, uint select_id);
/**
* Part of the solution copied from `rect_subregion_stride_calc`.
*/
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 972758febd4..05c992274eb 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -71,6 +71,8 @@ GPUShader *GPU_shader_create_ex(const char *vertcode,
GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info);
GPUShader *GPU_shader_create_from_info_name(const char *info_name);
+const GPUShaderCreateInfo *GPU_shader_create_info_get(const char *info_name);
+
struct GPU_ShaderCreateFromArray_Params {
const char **vert, **geom, **frag, **defs;
};
diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h
index 6fae4a13918..7812c7a7257 100644
--- a/source/blender/gpu/GPU_texture.h
+++ b/source/blender/gpu/GPU_texture.h
@@ -272,7 +272,8 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat data_format, int miplvl);
* Fills the whole texture with the same data for all pixels.
* \warning Only work for 2D texture for now.
* \warning Only clears the mip 0 of the texture.
- * \param data_format: data format of the pixel data. \note The format is float for unorm textures.
+ * \param data_format: data format of the pixel data.
+ * \note The format is float for unorm textures.
* \param data: 1 pixel worth of data to fill the texture with.
*/
void GPU_texture_clear(GPUTexture *tex, eGPUDataFormat data_format, const void *data);
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 568462ec2a6..e1c6901470a 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -711,10 +711,10 @@ static char *code_generate_vertex(GPUNodeGraph *graph,
LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph->attributes) {
const char *type_str = gpu_data_type_to_string(attr->gputype);
const char *prefix = attr_prefix_get(attr->type);
- /* XXX FIXME : see notes in mesh_render_data_create() */
- /* NOTE : Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */
+ /* XXX FIXME: see notes in mesh_render_data_create() */
+ /* NOTE: Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */
if (attr->type == CD_ORCO) {
- /* OPTI : orco is computed from local positions, but only if no modifier is present. */
+ /* OPTI: orco is computed from local positions, but only if no modifier is present. */
BLI_dynstr_append(ds, datatoc_gpu_shader_common_obinfos_lib_glsl);
BLI_dynstr_append(ds, "DEFINE_ATTR(vec4, orco);\n");
}
diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc
index 5b1eac2e82f..28f5b8b02b0 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.cc
+++ b/source/blender/gpu/intern/gpu_framebuffer.cc
@@ -437,7 +437,7 @@ void GPU_framebuffer_blit(GPUFrameBuffer *gpufb_read,
fb_read->blit_to(blit_buffers, read_slot, fb_write, write_slot, 0, 0);
- /* FIXME(fclem) sRGB is not saved. */
+ /* FIXME(@fclem): sRGB is not saved. */
prev_fb->bind(true);
}
diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c
index 958aab65b57..afef0e70ccc 100644
--- a/source/blender/gpu/intern/gpu_select.c
+++ b/source/blender/gpu/intern/gpu_select.c
@@ -43,22 +43,22 @@
* \{ */
/* Internal algorithm used */
-enum {
+typedef enum eGPUSelectAlgo {
/** glBegin/EndQuery(GL_SAMPLES_PASSED... ), `gpu_select_query.c`
* Only sets 4th component (ID) correctly. */
ALGO_GL_QUERY = 1,
/** Read depth buffer for every drawing pass and extract depths, `gpu_select_pick.c`
* Only sets 4th component (ID) correctly. */
ALGO_GL_PICK = 2,
-};
+} eGPUSelectAlgo;
typedef struct GPUSelectState {
/* To ignore selection id calls when not initialized */
bool select_is_active;
/* mode of operation */
- char mode;
+ eGPUSelectMode mode;
/* internal algorithm for selection */
- char algorithm;
+ eGPUSelectAlgo algorithm;
/* allow GPU_select_begin/end without drawing */
bool use_cache;
/**
@@ -80,7 +80,11 @@ static GPUSelectState g_select_state = {0};
/** \name Public API
* \{ */
-void GPU_select_begin(uint *buffer, uint bufsize, const rcti *input, char mode, int oldhits)
+void GPU_select_begin(GPUSelectResult *buffer,
+ const uint buffer_len,
+ const rcti *input,
+ eGPUSelectMode mode,
+ int oldhits)
{
if (mode == GPU_SELECT_NEAREST_SECOND_PASS) {
/* In the case hits was '-1',
@@ -119,12 +123,12 @@ void GPU_select_begin(uint *buffer, uint bufsize, const rcti *input, char mode,
switch (g_select_state.algorithm) {
case ALGO_GL_QUERY: {
- gpu_select_query_begin((uint(*)[4])buffer, bufsize / 4, input, mode, oldhits);
+ gpu_select_query_begin(buffer, buffer_len, input, mode, oldhits);
break;
}
default: /* ALGO_GL_PICK */
{
- gpu_select_pick_begin((uint(*)[4])buffer, bufsize / 4, input, mode);
+ gpu_select_pick_begin(buffer, buffer_len, input, mode);
break;
}
}
@@ -219,35 +223,35 @@ bool GPU_select_is_cached(void)
/** \name Utilities
* \{ */
-const uint *GPU_select_buffer_near(const uint *buffer, int hits)
+const GPUSelectResult *GPU_select_buffer_near(const GPUSelectResult *buffer, int hits)
{
- const uint *buffer_near = NULL;
+ const GPUSelectResult *buffer_near = NULL;
uint depth_min = (uint)-1;
for (int i = 0; i < hits; i++) {
- if (buffer[1] < depth_min) {
- BLI_assert(buffer[3] != -1);
- depth_min = buffer[1];
+ if (buffer->depth < depth_min) {
+ BLI_assert(buffer->id != -1);
+ depth_min = buffer->depth;
buffer_near = buffer;
}
- buffer += 4;
+ buffer++;
}
return buffer_near;
}
-uint GPU_select_buffer_remove_by_id(uint *buffer, int hits, uint select_id)
+uint GPU_select_buffer_remove_by_id(GPUSelectResult *buffer, int hits, uint select_id)
{
- uint *buffer_src = buffer;
- uint *buffer_dst = buffer;
+ GPUSelectResult *buffer_src = buffer;
+ GPUSelectResult *buffer_dst = buffer;
int hits_final = 0;
for (int i = 0; i < hits; i++) {
- if (buffer_src[3] != select_id) {
+ if (buffer_src->id != select_id) {
if (buffer_dst != buffer_src) {
- memcpy(buffer_dst, buffer_src, sizeof(int[4]));
+ memcpy(buffer_dst, buffer_src, sizeof(GPUSelectResult));
}
- buffer_dst += 4;
+ buffer_dst++;
hits_final += 1;
}
- buffer_src += 4;
+ buffer_src++;
}
return hits_final;
}
diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c
index ddd3dfc6879..a5c0b2b1a14 100644
--- a/source/blender/gpu/intern/gpu_select_pick.c
+++ b/source/blender/gpu/intern/gpu_select_pick.c
@@ -55,15 +55,19 @@
/** \name #SubRectStride
* \{ */
-/* For looping over a sub-region of a rect, could be moved into 'rct.c'. */
+/** For looping over a sub-region of a #rcti, could be moved into 'rct.c'. */
typedef struct SubRectStride {
- uint start; /* start here */
- uint span; /* read these */
- uint span_len; /* len times (read span 'len' times). */
- uint skip; /* skip those */
+ /** Start here. */
+ uint start;
+ /** Read these. */
+ uint span;
+ /** `len` times (read span 'len' times). */
+ uint span_len;
+ /** Skip those. */
+ uint skip;
} SubRectStride;
-/* we may want to change back to float if uint isn't well supported */
+/** We may want to change back to float if `uint` isn't well supported. */
typedef uint depth_t;
/**
@@ -104,11 +108,11 @@ BLI_INLINE bool depth_is_filled(const depth_t *prev, const depth_t *curr)
/* -------------------------------------------------------------------- */
/** \name #DepthBufCache
*
- * Result of reading #glReadPixels,
+ * Result of reading #GPU_framebuffer_read_depth,
* use for both cache and non-cached storage.
* \{ */
-/** Store result of #glReadPixels. */
+/** Store result of #GPU_framebuffer_read_depth. */
typedef struct DepthBufCache {
struct DepthBufCache *next, *prev;
uint id;
@@ -174,7 +178,7 @@ static bool depth_buf_subrect_depth_any_filled(const DepthBufCache *rect_src,
const DepthBufCache *rect_dst,
const SubRectStride *sub_rect)
{
- /* same as above but different rect sizes */
+ /* Same as above but different rectangle sizes. */
const depth_t *prev = rect_src->buf + sub_rect->start;
const depth_t *curr = rect_dst->buf + sub_rect->start;
for (uint i = 0; i < sub_rect->span_len; i++) {
@@ -235,66 +239,68 @@ static int depth_cmp(const void *v1, const void *v2)
/** \name Main Selection Begin/End/Load API
* \{ */
-/* depth sorting */
+/** Depth sorting. */
typedef struct GPUPickState {
- /* cache on initialization */
- uint (*buffer)[4];
+ /** Cache on initialization. */
+ GPUSelectResult *buffer;
+ uint buffer_len;
+ /** Mode of this operation. */
+ eGPUSelectMode mode;
- /* Buffer size (stores number of integers, for actual size multiply by sizeof integer). */
- uint bufsize;
- /* mode of operation */
- char mode;
-
- /* OpenGL drawing, never use when (is_cached == true). */
+ /** GPU drawing, never use when `is_cached == true`. */
struct {
- /* The current depth, accumulated as we draw */
+ /** The current depth, accumulated while drawing. */
DepthBufCache *rect_depth;
- /* Scratch buffer, avoid allocs every time (when not caching) */
+ /** Scratch buffer, avoid allocations every time (when not caching). */
DepthBufCache *rect_depth_test;
- /* Pass to glReadPixels (x, y, w, h) */
+ /** Pass to `GPU_framebuffer_read_depth(x, y, w, h)`. */
int clip_readpixels[4];
- /* Set after first draw */
+ /** Set after first draw. */
bool is_init;
uint prev_id;
- } gl;
+ } gpu;
- /* src: data stored in 'cache' and 'gl',
- * dst: use when cached region is smaller (where src -> dst isn't 1:1) */
+ /**
+ * `src`: data stored in 'cache' and 'gpu',
+ * `dst`: use when cached region is smaller (where `src` -> `dst` isn't 1:1).
+ */
struct {
rcti clip_rect;
uint rect_len;
} src, dst;
- /* Store cache between `GPU_select_cache_begin/end` */
+ /** Store cache between `GPU_select_cache_begin/end` */
bool use_cache;
bool is_cached;
struct {
- /* Cleanup used for iterating over both source and destination buffers:
- * src.clip_rect -> dst.clip_rect */
+ /**
+ * Cleanup used for iterating over both source and destination buffers:
+ * `src.clip_rect` -> `dst.clip_rect`.
+ */
SubRectStride sub_rect;
- /* List of DepthBufCache, sized of 'src.clip_rect' */
+ /** List of #DepthBufCache, sized of 'src.clip_rect'. */
ListBase bufs;
} cache;
- /* Picking methods. */
+ /** Picking methods. */
union {
- /* GPU_SELECT_PICK_ALL */
+ /** #GPU_SELECT_PICK_ALL */
struct {
DepthID *hits;
uint hits_len;
uint hits_len_alloc;
} all;
- /* GPU_SELECT_PICK_NEAREST */
+ /** #GPU_SELECT_PICK_NEAREST */
struct {
uint *rect_id;
} nearest;
};
- /* Previous state to restore after drawing. */
+ /** Previous state to restore after drawing. */
int viewport[4];
int scissor[4];
eGPUWriteMask write_mask;
@@ -303,37 +309,44 @@ typedef struct GPUPickState {
static GPUPickState g_pick_state = {0};
-void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, char mode)
+void gpu_select_pick_begin(GPUSelectResult *buffer,
+ const uint buffer_len,
+ const rcti *input,
+ eGPUSelectMode mode)
{
GPUPickState *ps = &g_pick_state;
#ifdef DEBUG_PRINT
- printf("%s: mode=%d, use_cache=%d, is_cache=%d\n", __func__, mode, ps->use_cache, ps->is_cached);
+ printf("%s: mode=%d, use_cache=%d, is_cache=%d\n",
+ __func__,
+ (int)mode,
+ ps->use_cache,
+ ps->is_cached);
#endif
GPU_debug_group_begin("Selection Pick");
- ps->bufsize = bufsize;
ps->buffer = buffer;
+ ps->buffer_len = buffer_len;
ps->mode = mode;
const uint rect_len = (uint)(BLI_rcti_size_x(input) * BLI_rcti_size_y(input));
ps->dst.clip_rect = *input;
ps->dst.rect_len = rect_len;
- /* Restrict OpenGL operations for when we don't have cache */
+ /* Avoids unnecessary GPU operations when cache is available and they are unnecessary. */
if (ps->is_cached == false) {
ps->write_mask = GPU_write_mask_get();
ps->depth_test = GPU_depth_test_get();
GPU_scissor_get(ps->scissor);
- /* disable writing to the framebuffer */
+ /* Disable writing to the frame-buffer. */
GPU_color_mask(false, false, false, false);
GPU_depth_mask(true);
- /* Always use #GL_LEQUAL even though GPU_SELECT_PICK_ALL always clears the buffer. This is
- * because individual objects themselves might have sections that overlap and we need these
- * to have the correct distance information. */
+ /* Always use #GPU_DEPTH_LESS_EQUAL even though #GPU_SELECT_PICK_ALL always clears the buffer.
+ * This is because individual objects themselves might have sections that overlap and we need
+ * these to have the correct distance information. */
GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
float viewport[4];
@@ -342,35 +355,35 @@ void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, c
ps->src.clip_rect = *input;
ps->src.rect_len = rect_len;
- ps->gl.clip_readpixels[0] = (int)viewport[0];
- ps->gl.clip_readpixels[1] = (int)viewport[1];
- ps->gl.clip_readpixels[2] = BLI_rcti_size_x(&ps->src.clip_rect);
- ps->gl.clip_readpixels[3] = BLI_rcti_size_y(&ps->src.clip_rect);
+ ps->gpu.clip_readpixels[0] = (int)viewport[0];
+ ps->gpu.clip_readpixels[1] = (int)viewport[1];
+ ps->gpu.clip_readpixels[2] = BLI_rcti_size_x(&ps->src.clip_rect);
+ ps->gpu.clip_readpixels[3] = BLI_rcti_size_y(&ps->src.clip_rect);
- GPU_viewport(UNPACK4(ps->gl.clip_readpixels));
+ GPU_viewport(UNPACK4(ps->gpu.clip_readpixels));
/* It's possible we don't want to clear depth buffer,
* so existing elements are masked by current z-buffer. */
GPU_clear_depth(1.0f);
/* scratch buffer (read new values here) */
- ps->gl.rect_depth_test = depth_buf_malloc(rect_len);
- ps->gl.rect_depth = depth_buf_malloc(rect_len);
+ ps->gpu.rect_depth_test = depth_buf_malloc(rect_len);
+ ps->gpu.rect_depth = depth_buf_malloc(rect_len);
- /* set initial 'far' value */
+ /* Set initial 'far' value. */
for (uint i = 0; i < rect_len; i++) {
- ps->gl.rect_depth->buf[i] = DEPTH_MAX;
+ ps->gpu.rect_depth->buf[i] = DEPTH_MAX;
}
- ps->gl.is_init = false;
- ps->gl.prev_id = 0;
+ ps->gpu.is_init = false;
+ ps->gpu.prev_id = 0;
}
else {
- /* Using cache (ps->is_cached == true) */
- /* src.clip_rect -> dst.clip_rect */
+ /* Using cache `ps->is_cached == true`. */
+ /* `src.clip_rect` -> `dst.clip_rect`. */
rect_subregion_stride_calc(&ps->src.clip_rect, &ps->dst.clip_rect, &ps->cache.sub_rect);
- BLI_assert(ps->gl.rect_depth == NULL);
- BLI_assert(ps->gl.rect_depth_test == NULL);
+ BLI_assert(ps->gpu.rect_depth == NULL);
+ BLI_assert(ps->gpu.rect_depth_test == NULL);
}
if (mode == GPU_SELECT_PICK_ALL) {
@@ -379,7 +392,7 @@ void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, c
ps->all.hits_len_alloc = ALLOC_DEPTHS;
}
else {
- /* Set to 0xff for SELECT_ID_NONE */
+ /* Set to 0xff for #SELECT_ID_NONE. */
ps->nearest.rect_id = MEM_mallocN(sizeof(uint) * ps->dst.rect_len, __func__);
memset(ps->nearest.rect_id, 0xff, sizeof(uint) * ps->dst.rect_len);
}
@@ -411,7 +424,7 @@ static void gpu_select_load_id_pass_all(const DepthBufCache *rect_curr)
}
}
else {
- /* same as above but different rect sizes */
+ /* Same as above but different rectangle sizes. */
const depth_t *curr = rect_curr->buf + ps->cache.sub_rect.start;
for (uint i = 0; i < ps->cache.sub_rect.span_len; i++) {
const depth_t *curr_end = curr + ps->cache.sub_rect.span;
@@ -424,7 +437,7 @@ static void gpu_select_load_id_pass_all(const DepthBufCache *rect_curr)
#undef EVAL_TEST
- /* ensure enough space */
+ /* Ensure enough space. */
if (UNLIKELY(ps->all.hits_len == ps->all.hits_len_alloc)) {
ps->all.hits_len_alloc += ALLOC_DEPTHS;
ps->all.hits = MEM_reallocN(ps->all.hits, ps->all.hits_len_alloc * sizeof(*ps->all.hits));
@@ -439,7 +452,7 @@ static void gpu_select_load_id_pass_nearest(const DepthBufCache *rect_prev,
{
GPUPickState *ps = &g_pick_state;
const uint id = rect_curr->id;
- /* keep track each pixels ID in 'nearest.rect_id' */
+ /* Keep track each pixels ID in `nearest.rect_id`. */
if (id != SELECT_ID_NONE) {
uint *id_ptr = ps->nearest.rect_id;
@@ -483,8 +496,8 @@ bool gpu_select_pick_load_id(uint id, bool end)
{
GPUPickState *ps = &g_pick_state;
- if (ps->gl.is_init) {
- if (id == ps->gl.prev_id && !end) {
+ if (ps->gpu.is_init) {
+ if (id == ps->gpu.prev_id && !end) {
/* No need to read if we are still drawing for the same id since
* all these depths will be merged / de-duplicated in the end. */
return true;
@@ -493,21 +506,21 @@ bool gpu_select_pick_load_id(uint id, bool end)
const uint rect_len = ps->src.rect_len;
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);
+ fb, UNPACK4(ps->gpu.clip_readpixels), GPU_DATA_UINT, ps->gpu.rect_depth_test->buf);
/* Perform initial check since most cases the array remains unchanged. */
bool do_pass = false;
if (g_pick_state.mode == GPU_SELECT_PICK_ALL) {
- if (depth_buf_rect_depth_any(ps->gl.rect_depth_test, rect_len)) {
- ps->gl.rect_depth_test->id = ps->gl.prev_id;
- gpu_select_load_id_pass_all(ps->gl.rect_depth_test);
+ if (depth_buf_rect_depth_any(ps->gpu.rect_depth_test, rect_len)) {
+ ps->gpu.rect_depth_test->id = ps->gpu.prev_id;
+ gpu_select_load_id_pass_all(ps->gpu.rect_depth_test);
do_pass = true;
}
}
else {
- if (depth_buf_rect_depth_any_filled(ps->gl.rect_depth, ps->gl.rect_depth_test, rect_len)) {
- ps->gl.rect_depth_test->id = ps->gl.prev_id;
- gpu_select_load_id_pass_nearest(ps->gl.rect_depth, ps->gl.rect_depth_test);
+ if (depth_buf_rect_depth_any_filled(ps->gpu.rect_depth, ps->gpu.rect_depth_test, rect_len)) {
+ ps->gpu.rect_depth_test->id = ps->gpu.prev_id;
+ gpu_select_load_id_pass_nearest(ps->gpu.rect_depth, ps->gpu.rect_depth_test);
do_pass = true;
}
}
@@ -515,11 +528,11 @@ bool gpu_select_pick_load_id(uint id, bool end)
if (do_pass) {
/* Store depth in cache */
if (ps->use_cache) {
- BLI_addtail(&ps->cache.bufs, ps->gl.rect_depth);
- ps->gl.rect_depth = depth_buf_malloc(ps->src.rect_len);
+ BLI_addtail(&ps->cache.bufs, ps->gpu.rect_depth);
+ ps->gpu.rect_depth = depth_buf_malloc(ps->src.rect_len);
}
- SWAP(DepthBufCache *, ps->gl.rect_depth, ps->gl.rect_depth_test);
+ SWAP(DepthBufCache *, ps->gpu.rect_depth, ps->gpu.rect_depth_test);
if (g_pick_state.mode == GPU_SELECT_PICK_ALL) {
/* (fclem) This is to be on the safe side. I don't know if this is required. */
@@ -533,8 +546,8 @@ bool gpu_select_pick_load_id(uint id, bool end)
}
}
- ps->gl.is_init = true;
- ps->gl.prev_id = id;
+ ps->gpu.is_init = true;
+ ps->gpu.prev_id = id;
return true;
}
@@ -548,9 +561,9 @@ uint gpu_select_pick_end(void)
#endif
if (ps->is_cached == false) {
- if (ps->gl.is_init) {
+ if (ps->gpu.is_init) {
/* force finishing last pass */
- gpu_select_pick_load_id(ps->gl.prev_id, true);
+ gpu_select_pick_load_id(ps->gpu.prev_id, true);
}
GPU_write_mask(ps->write_mask);
GPU_depth_test(ps->depth_test);
@@ -559,39 +572,39 @@ uint gpu_select_pick_end(void)
GPU_debug_group_end();
- /* assign but never free directly since it may be in cache */
+ /* Assign but never free directly since it may be in cache. */
DepthBufCache *rect_depth_final;
/* Store depth in cache */
if (ps->use_cache && !ps->is_cached) {
- BLI_addtail(&ps->cache.bufs, ps->gl.rect_depth);
- ps->gl.rect_depth = NULL;
+ BLI_addtail(&ps->cache.bufs, ps->gpu.rect_depth);
+ ps->gpu.rect_depth = NULL;
rect_depth_final = ps->cache.bufs.last;
}
else if (ps->is_cached) {
rect_depth_final = ps->cache.bufs.last;
}
else {
- /* common case, no cache */
- rect_depth_final = ps->gl.rect_depth;
+ /* Common case, no cache. */
+ rect_depth_final = ps->gpu.rect_depth;
}
- uint maxhits = g_pick_state.bufsize;
+ uint maxhits = g_pick_state.buffer_len;
DepthID *depth_data;
uint depth_data_len = 0;
if (g_pick_state.mode == GPU_SELECT_PICK_ALL) {
depth_data = ps->all.hits;
depth_data_len = ps->all.hits_len;
- /* move ownership */
+ /* Move ownership. */
ps->all.hits = NULL;
ps->all.hits_len = 0;
ps->all.hits_len_alloc = 0;
}
else {
- /* GPU_SELECT_PICK_NEAREST */
+ /* #GPU_SELECT_PICK_NEAREST */
- /* Over alloc (unlikely we have as many depths as pixels) */
+ /* Over allocate (unlikely we have as many depths as pixels). */
uint depth_data_len_first_pass = 0;
depth_data = MEM_mallocN(ps->dst.rect_len * sizeof(*depth_data), __func__);
@@ -624,7 +637,7 @@ uint gpu_select_pick_end(void)
}
}
else {
- /* same as above but different rect sizes */
+ /* Same as above but different rectangle sizes. */
uint i_src = ps->cache.sub_rect.start, i_dst = 0;
for (uint j = 0; j < ps->cache.sub_rect.span_len; j++) {
const uint i_src_end = i_src + ps->cache.sub_rect.span;
@@ -640,7 +653,7 @@ uint gpu_select_pick_end(void)
qsort(depth_data, depth_data_len_first_pass, sizeof(DepthID), depth_id_cmp);
- /* Sort by ID's then keep the best depth for each ID */
+ /* Sort by ID's then keep the best depth for each ID. */
depth_data_len = 0;
{
DepthID *depth_last = NULL;
@@ -657,25 +670,22 @@ uint gpu_select_pick_end(void)
}
/* Finally sort each unique (id, depth) pair by depth
- * so the final hit-list is sorted by depth (nearest first) */
+ * so the final hit-list is sorted by depth (nearest first). */
uint hits = 0;
if (depth_data_len > maxhits) {
hits = (uint)-1;
}
else {
- /* leave sorting up to the caller */
+ /* Leave sorting up to the caller. */
qsort(depth_data, depth_data_len, sizeof(DepthID), depth_cmp);
for (uint i = 0; i < depth_data_len; i++) {
#ifdef DEBUG_PRINT
printf(" hit: %u: depth %u\n", depth_data[i].id, depth_data[i].depth);
#endif
- /* first 3 are dummy values */
- g_pick_state.buffer[hits][0] = 1;
- g_pick_state.buffer[hits][1] = depth_data[i].depth;
- g_pick_state.buffer[hits][2] = 0x0; /* z-far is currently never used. */
- g_pick_state.buffer[hits][3] = depth_data[i].id;
+ g_pick_state.buffer[hits].depth = depth_data[i].depth;
+ g_pick_state.buffer[hits].id = depth_data[i].id;
hits++;
}
BLI_assert(hits < maxhits);
@@ -683,8 +693,8 @@ uint gpu_select_pick_end(void)
MEM_freeN(depth_data);
- MEM_SAFE_FREE(ps->gl.rect_depth);
- MEM_SAFE_FREE(ps->gl.rect_depth_test);
+ MEM_SAFE_FREE(ps->gpu.rect_depth);
+ MEM_SAFE_FREE(ps->gpu.rect_depth_test);
if (g_pick_state.mode == GPU_SELECT_PICK_ALL) {
/* 'hits' already freed as 'depth_data' */
@@ -744,8 +754,8 @@ void gpu_select_pick_cache_load_id(void)
#endif
LISTBASE_FOREACH (DepthBufCache *, rect_depth, &ps->cache.bufs) {
if (rect_depth->next != NULL) {
- /* we know the buffers differ, but this sub-region may not.
- * double check before adding an id-pass */
+ /* We know the buffers differ, but this sub-region may not.
+ * Double check before adding an id-pass. */
if (g_pick_state.mode == GPU_SELECT_PICK_ALL) {
if (depth_buf_subrect_depth_any(rect_depth->next, &ps->cache.sub_rect)) {
gpu_select_load_id_pass_all(rect_depth->next);
diff --git a/source/blender/gpu/intern/gpu_select_private.h b/source/blender/gpu/intern/gpu_select_private.h
index e5a84a037a6..0ec9f083c07 100644
--- a/source/blender/gpu/intern/gpu_select_private.h
+++ b/source/blender/gpu/intern/gpu_select_private.h
@@ -31,7 +31,10 @@ extern "C" {
/* gpu_select_pick */
-void gpu_select_pick_begin(uint (*buffer)[4], uint bufsize, const rcti *input, char mode);
+void gpu_select_pick_begin(GPUSelectResult *buffer,
+ uint buffer_len,
+ const rcti *input,
+ eGPUSelectMode mode);
bool gpu_select_pick_load_id(uint id, bool end);
uint gpu_select_pick_end(void);
@@ -46,7 +49,7 @@ void gpu_select_pick_cache_load_id(void);
/* gpu_select_sample_query */
void gpu_select_query_begin(
- uint (*buffer)[4], uint bufsize, const rcti *input, char mode, int oldhits);
+ GPUSelectResult *buffer, uint buffer_len, const rcti *input, eGPUSelectMode mode, int oldhits);
bool gpu_select_query_load_id(uint id);
uint gpu_select_query_end(void);
diff --git a/source/blender/gpu/intern/gpu_select_sample_query.cc b/source/blender/gpu/intern/gpu_select_sample_query.cc
index a430d4a9d62..7559358aaca 100644
--- a/source/blender/gpu/intern/gpu_select_sample_query.cc
+++ b/source/blender/gpu/intern/gpu_select_sample_query.cc
@@ -48,22 +48,22 @@ 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. */
+ /** GPU queries abstraction. Contains an array of queries. */
QueryPool *queries;
- /* Array holding the id corresponding id to each query. */
+ /** Array holding the id corresponding id to each query. */
Vector<uint> *ids;
- /* Cache on initialization. */
- uint (*buffer)[4];
- /* Buffer size (stores number of integers, for actual size multiply by `sizeof(int)`). */
- uint bufsize;
- /* Mode of operation. */
- char mode;
+ /** Cache on initialization. */
+ GPUSelectResult *buffer;
+ /** The capacity of the `buffer` array. */
+ uint buffer_len;
+ /** Mode of operation. */
+ eGPUSelectMode mode;
uint index;
int oldhits;
- /* Previous state to restore after drawing. */
+ /** Previous state to restore after drawing. */
int viewport[4];
int scissor[4];
eGPUWriteMask write_mask;
@@ -72,14 +72,17 @@ struct GPUSelectQueryState {
static GPUSelectQueryState g_query_state = {false};
-void gpu_select_query_begin(
- uint (*buffer)[4], uint bufsize, const rcti *input, char mode, int oldhits)
+void gpu_select_query_begin(GPUSelectResult *buffer,
+ uint buffer_len,
+ const rcti *input,
+ const eGPUSelectMode mode,
+ int oldhits)
{
GPU_debug_group_begin("Selection Queries");
g_query_state.query_issued = false;
- g_query_state.bufsize = bufsize;
g_query_state.buffer = buffer;
+ g_query_state.buffer_len = buffer_len;
g_query_state.mode = mode;
g_query_state.index = 0;
g_query_state.oldhits = oldhits;
@@ -111,7 +114,7 @@ void gpu_select_query_begin(
/* occlusion queries operates on fragments that pass tests and since we are interested on all
* objects in the view frustum independently of their order, we need to disable the depth test */
if (mode == GPU_SELECT_ALL) {
- /* glQueries on Windows+Intel drivers only works with depth testing turned on.
+ /* #glQueries on Windows+Intel drivers only works with depth testing turned on.
* See T62947 for details */
GPU_depth_test(GPU_DEPTH_ALWAYS);
GPU_depth_mask(true);
@@ -138,10 +141,11 @@ bool gpu_select_query_load_id(uint id)
g_query_state.query_issued = true;
if (g_query_state.mode == GPU_SELECT_NEAREST_SECOND_PASS) {
- /* Second pass should never run if first pass fails, can read past 'bufsize' in this case. */
+ /* Second pass should never run if first pass fails,
+ * can read past `buffer_len` in this case. */
BLI_assert(g_query_state.oldhits != -1);
if (g_query_state.index < g_query_state.oldhits) {
- if (g_query_state.buffer[g_query_state.index][3] == id) {
+ if (g_query_state.buffer[g_query_state.index].id == id) {
g_query_state.index++;
return true;
}
@@ -154,7 +158,7 @@ bool gpu_select_query_load_id(uint id)
uint gpu_select_query_end()
{
uint hits = 0;
- const uint maxhits = g_query_state.bufsize;
+ const uint maxhits = g_query_state.buffer_len;
if (g_query_state.query_issued) {
g_query_state.queries->end_query();
@@ -168,10 +172,8 @@ uint gpu_select_query_end()
if (result[i] != 0) {
if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) {
if (hits < maxhits) {
- g_query_state.buffer[hits][0] = 1;
- g_query_state.buffer[hits][1] = 0xFFFF;
- g_query_state.buffer[hits][2] = 0xFFFF;
- g_query_state.buffer[hits][3] = ids[i];
+ g_query_state.buffer[hits].depth = 0xFFFF;
+ g_query_state.buffer[hits].id = ids[i];
hits++;
}
else {
@@ -183,9 +185,8 @@ uint gpu_select_query_end()
int j;
/* search in buffer and make selected object first */
for (j = 0; j < g_query_state.oldhits; j++) {
- if (g_query_state.buffer[j][3] == ids[i]) {
- g_query_state.buffer[j][1] = 0;
- g_query_state.buffer[j][2] = 0;
+ if (g_query_state.buffer[j].id == ids[i]) {
+ g_query_state.buffer[j].depth = 0;
}
}
break;
diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc
index ef800abc3c9..2e924925ab8 100644
--- a/source/blender/gpu/intern/gpu_shader.cc
+++ b/source/blender/gpu/intern/gpu_shader.cc
@@ -249,6 +249,11 @@ GPUShader *GPU_shader_create_compute(const char *computecode,
shname);
}
+const GPUShaderCreateInfo *GPU_shader_create_info_get(const char *info_name)
+{
+ return gpu_shader_create_info_get(info_name);
+}
+
GPUShader *GPU_shader_create_from_info_name(const char *info_name)
{
using namespace blender::gpu::shader;
@@ -309,9 +314,8 @@ GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info)
}
if (!info.vertex_source_.is_empty()) {
- uint32_t builtins = 0;
+ char *code = gpu_shader_dependency_get_resolved_source(info.vertex_source_.c_str());
std::string interface = shader->vertex_interface_declare(info);
- char *code = gpu_shader_dependency_get_resolved_source(info.vertex_source_.c_str(), &builtins);
Vector<const char *> sources;
standard_defines(sources);
@@ -336,10 +340,8 @@ GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info)
}
if (!info.fragment_source_.is_empty()) {
- uint32_t builtins = 0;
+ char *code = gpu_shader_dependency_get_resolved_source(info.fragment_source_.c_str());
std::string interface = shader->fragment_interface_declare(info);
- char *code = gpu_shader_dependency_get_resolved_source(info.fragment_source_.c_str(),
- &builtins);
Vector<const char *> sources;
standard_defines(sources);
@@ -364,11 +366,9 @@ GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info)
}
if (!info.geometry_source_.is_empty()) {
- uint32_t builtins = 0;
- std::string interface = shader->geometry_interface_declare(info);
+ char *code = gpu_shader_dependency_get_resolved_source(info.geometry_source_.c_str());
std::string layout = shader->geometry_layout_declare(info);
- char *code = gpu_shader_dependency_get_resolved_source(info.geometry_source_.c_str(),
- &builtins);
+ std::string interface = shader->geometry_interface_declare(info);
Vector<const char *> sources;
standard_defines(sources);
@@ -391,9 +391,7 @@ GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info)
}
if (!info.compute_source_.is_empty()) {
- uint32_t builtins = 0;
- char *code = gpu_shader_dependency_get_resolved_source(info.compute_source_.c_str(),
- &builtins);
+ char *code = gpu_shader_dependency_get_resolved_source(info.compute_source_.c_str());
std::string layout = shader->compute_layout_declare(info);
Vector<const char *> sources;
diff --git a/source/blender/gpu/intern/gpu_shader_create_info.cc b/source/blender/gpu/intern/gpu_shader_create_info.cc
index 492b247e192..1464a7ade24 100644
--- a/source/blender/gpu/intern/gpu_shader_create_info.cc
+++ b/source/blender/gpu/intern/gpu_shader_create_info.cc
@@ -34,6 +34,7 @@
#include "gpu_shader_create_info.hh"
#include "gpu_shader_create_info_private.hh"
+#include "gpu_shader_dependency_private.h"
#include "gpu_shader_private.hh"
#undef GPU_SHADER_INTERFACE_INFO
@@ -167,7 +168,7 @@ void ShaderCreateInfo::validate(const ShaderCreateInfo &other_info)
}
}
{
- /* TODO(fclem) Push constant validation. */
+ /* TODO(@fclem): Push constant validation. */
}
}
@@ -209,6 +210,19 @@ void gpu_shader_create_info_init()
draw_modelmat = draw_modelmat_legacy;
}
+ for (ShaderCreateInfo *info : g_create_infos->values()) {
+ if (info->do_static_compilation_) {
+ info->builtins_ |= static_cast<BuiltinBits>(
+ gpu_shader_dependency_get_builtins(info->vertex_source_.c_str()));
+ info->builtins_ |= static_cast<BuiltinBits>(
+ gpu_shader_dependency_get_builtins(info->fragment_source_.c_str()));
+ info->builtins_ |= static_cast<BuiltinBits>(
+ gpu_shader_dependency_get_builtins(info->geometry_source_.c_str()));
+ info->builtins_ |= static_cast<BuiltinBits>(
+ gpu_shader_dependency_get_builtins(info->compute_source_.c_str()));
+ }
+ }
+
/* TEST */
// gpu_shader_create_info_compile_all();
}
@@ -302,6 +316,7 @@ const GPUShaderCreateInfo *gpu_shader_create_info_get(const char *info_name)
{
if (g_create_infos->contains(info_name) == false) {
printf("Error: Cannot find shader create info named \"%s\"\n", info_name);
+ return nullptr;
}
ShaderCreateInfo *info = g_create_infos->lookup(info_name);
return reinterpret_cast<const GPUShaderCreateInfo *>(info);
diff --git a/source/blender/gpu/intern/gpu_shader_create_info.hh b/source/blender/gpu/intern/gpu_shader_create_info.hh
index 63c6e94f4c8..736a8ed0590 100644
--- a/source/blender/gpu/intern/gpu_shader_create_info.hh
+++ b/source/blender/gpu/intern/gpu_shader_create_info.hh
@@ -63,6 +63,7 @@ enum class Type {
};
enum class BuiltinBits {
+ NONE = 0,
/**
* Allow getting barycentric coordinates inside the fragment shader.
* \note Emulated on OpenGL.
@@ -72,6 +73,10 @@ enum class BuiltinBits {
FRONT_FACING = (1 << 4),
GLOBAL_INVOCATION_ID = (1 << 5),
INSTANCE_ID = (1 << 6),
+ /**
+ * Allow setting the target layer when the output is a layered framebuffer.
+ * \note Emulated through geometry shader on older hardware.
+ */
LAYER = (1 << 7),
LOCAL_INVOCATION_ID = (1 << 8),
LOCAL_INVOCATION_INDEX = (1 << 9),
@@ -125,10 +130,13 @@ enum class ImageType {
/* Storage qualifiers. */
enum class Qualifier {
- RESTRICT = (1 << 0),
- READ_ONLY = (1 << 1),
- WRITE_ONLY = (1 << 2),
- QUALIFIER_MAX = (WRITE_ONLY << 1) - 1,
+ /** Restrict flag is set by default. Unless specified otherwise. */
+ NO_RESTRICT = (1 << 0),
+ READ = (1 << 1),
+ WRITE = (1 << 2),
+ /** Shorthand version of combined flags. */
+ READ_WRITE = READ | WRITE,
+ QUALIFIER_MAX = (WRITE << 1) - 1,
};
ENUM_OPERATORS(Qualifier, Qualifier::QUALIFIER_MAX);
@@ -226,6 +234,8 @@ struct ShaderCreateInfo {
* Only for names used by gpu::ShaderInterface.
*/
size_t interface_names_size_ = 0;
+ /** Manually set builtins. */
+ BuiltinBits builtins_ = BuiltinBits::NONE;
struct VertIn {
int index;
@@ -538,6 +548,12 @@ struct ShaderCreateInfo {
return *(Self *)this;
}
+ Self &builtins(BuiltinBits builtin)
+ {
+ builtins_ |= builtin;
+ return *(Self *)this;
+ }
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc
index 5e03f7d0767..0db03c2b636 100644
--- a/source/blender/gpu/intern/gpu_shader_dependency.cc
+++ b/source/blender/gpu/intern/gpu_shader_dependency.cc
@@ -59,7 +59,6 @@ struct GPUSource {
/* Scan for builtins. */
/* FIXME: This can trigger false positive caused by disabled #if blocks. */
/* TODO(fclem): Could be made faster by scanning once. */
- /* TODO(fclem): BARYCENTRIC_COORD. */
if (source.find("gl_FragCoord", 0)) {
builtins |= shader::BuiltinBits::FRAG_COORD;
}
@@ -72,9 +71,6 @@ struct GPUSource {
if (source.find("gl_InstanceID", 0)) {
builtins |= shader::BuiltinBits::INSTANCE_ID;
}
- if (source.find("gl_Layer", 0)) {
- builtins |= shader::BuiltinBits::LAYER;
- }
if (source.find("gl_LocalInvocationID", 0)) {
builtins |= shader::BuiltinBits::LOCAL_INVOCATION_ID;
}
@@ -336,13 +332,23 @@ struct GPUSource {
}
/* Returns the final string with all includes done. */
- void build(std::string &str, shader::BuiltinBits &out_builtins)
+ std::string build() const
{
+ std::string str;
for (auto *dep : dependencies) {
- out_builtins |= builtins;
str += dep->source;
}
str += source;
+ return str;
+ }
+
+ shader::BuiltinBits builtins_get() const
+ {
+ shader::BuiltinBits out_builtins = shader::BuiltinBits::NONE;
+ for (auto *dep : dependencies) {
+ out_builtins |= dep->builtins;
+ }
+ return out_builtins;
}
};
@@ -377,14 +383,19 @@ void gpu_shader_dependency_exit()
delete g_sources;
}
-char *gpu_shader_dependency_get_resolved_source(const char *shader_source_name, uint32_t *builtins)
+uint32_t gpu_shader_dependency_get_builtins(const char *shader_source_name)
+{
+ if (shader_source_name[0] == '\0') {
+ return 0;
+ }
+ GPUSource *source = g_sources->lookup(shader_source_name);
+ return static_cast<uint32_t>(source->builtins_get());
+}
+
+char *gpu_shader_dependency_get_resolved_source(const char *shader_source_name)
{
GPUSource *source = g_sources->lookup(shader_source_name);
- std::string str;
- shader::BuiltinBits out_builtins;
- source->build(str, out_builtins);
- *builtins |= (uint32_t)out_builtins;
- return strdup(str.c_str());
+ return strdup(source->build().c_str());
}
char *gpu_shader_dependency_get_source(const char *shader_source_name)
diff --git a/source/blender/gpu/intern/gpu_shader_dependency_private.h b/source/blender/gpu/intern/gpu_shader_dependency_private.h
index b129ca74a48..083c38897ce 100644
--- a/source/blender/gpu/intern/gpu_shader_dependency_private.h
+++ b/source/blender/gpu/intern/gpu_shader_dependency_private.h
@@ -35,10 +35,11 @@ void gpu_shader_dependency_init(void);
void gpu_shader_dependency_exit(void);
/* User must free the resulting string using free. */
-char *gpu_shader_dependency_get_resolved_source(const char *shader_source_name,
- uint32_t *builtins);
+char *gpu_shader_dependency_get_resolved_source(const char *shader_source_name);
char *gpu_shader_dependency_get_source(const char *shader_source_name);
+uint32_t gpu_shader_dependency_get_builtins(const char *shader_source_name);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/gpu/intern/gpu_shader_log.cc b/source/blender/gpu/intern/gpu_shader_log.cc
index 12459b4b721..21973cf976a 100644
--- a/source/blender/gpu/intern/gpu_shader_log.cc
+++ b/source/blender/gpu/intern/gpu_shader_log.cc
@@ -102,7 +102,7 @@ void Shader::print_log(Span<const char *> sources,
found_line_id = true;
break;
}
-/* TODO(fclem) Make this an option to display N lines before error. */
+/* 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);
diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc
index 92d180f1140..2ee7c0503f4 100644
--- a/source/blender/gpu/opengl/gl_backend.cc
+++ b/source/blender/gpu/opengl/gl_backend.cc
@@ -248,6 +248,8 @@ static void detect_workarounds()
GLContext::direct_state_access_support = false;
GLContext::fixed_restart_index_support = false;
GLContext::geometry_shader_invocations = false;
+ GLContext::layered_rendering_support = false;
+ GLContext::native_barycentric_support = false;
GLContext::multi_bind_support = false;
GLContext::multi_draw_indirect_support = false;
GLContext::shader_draw_parameters_support = false;
@@ -445,6 +447,8 @@ bool GLContext::direct_state_access_support = false;
bool GLContext::explicit_location_support = false;
bool GLContext::geometry_shader_invocations = false;
bool GLContext::fixed_restart_index_support = false;
+bool GLContext::layered_rendering_support = false;
+bool GLContext::native_barycentric_support = false;
bool GLContext::multi_bind_support = false;
bool GLContext::multi_draw_indirect_support = false;
bool GLContext::shader_draw_parameters_support = false;
@@ -505,6 +509,8 @@ void GLBackend::capabilities_init()
GLContext::explicit_location_support = GLEW_VERSION_4_3;
GLContext::geometry_shader_invocations = GLEW_ARB_gpu_shader5;
GLContext::fixed_restart_index_support = GLEW_ARB_ES3_compatibility;
+ GLContext::layered_rendering_support = GLEW_AMD_vertex_shader_layer;
+ GLContext::native_barycentric_support = GLEW_AMD_shader_explicit_vertex_parameter;
GLContext::multi_bind_support = GLEW_ARB_multi_bind;
GLContext::multi_draw_indirect_support = GLEW_ARB_multi_draw_indirect;
GLContext::shader_draw_parameters_support = GLEW_ARB_shader_draw_parameters;
diff --git a/source/blender/gpu/opengl/gl_context.hh b/source/blender/gpu/opengl/gl_context.hh
index dd22418972b..b7a74863ac4 100644
--- a/source/blender/gpu/opengl/gl_context.hh
+++ b/source/blender/gpu/opengl/gl_context.hh
@@ -72,6 +72,8 @@ class GLContext : public Context {
static bool explicit_location_support;
static bool geometry_shader_invocations;
static bool fixed_restart_index_support;
+ static bool layered_rendering_support;
+ static bool native_barycentric_support;
static bool multi_bind_support;
static bool multi_draw_indirect_support;
static bool shader_draw_parameters_support;
diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc
index e031047f844..3ab3b11d1f4 100644
--- a/source/blender/gpu/opengl/gl_shader.cc
+++ b/source/blender/gpu/opengl/gl_shader.cc
@@ -277,15 +277,15 @@ static void print_image_type(std::ostream &os,
static std::ostream &print_qualifier(std::ostream &os, const Qualifier &qualifiers)
{
- if ((qualifiers & Qualifier::RESTRICT) == Qualifier::RESTRICT) {
+ if (bool(qualifiers & Qualifier::NO_RESTRICT) == false) {
os << "restrict ";
}
- if ((qualifiers & Qualifier::READ_ONLY) == Qualifier::READ_ONLY) {
- os << "readonly ";
- }
- if ((qualifiers & Qualifier::WRITE_ONLY) == Qualifier::WRITE_ONLY) {
+ if (bool(qualifiers & Qualifier::READ) == false) {
os << "writeonly ";
}
+ if (bool(qualifiers & Qualifier::WRITE) == false) {
+ os << "readonly ";
+ }
return os;
}
@@ -370,7 +370,7 @@ static void print_interface(std::ostream &os,
const StageInterfaceInfo &iface,
const StringRefNull &suffix = "")
{
- /* TODO(fclem) Move that to interface check. */
+ /* TODO(@fclem): Move that to interface check. */
// if (iface.instance_name.is_empty()) {
// BLI_assert_msg(0, "Interfaces require an instance name for geometry shader.");
// std::cout << iface.name << ": Interfaces require an instance name for geometry shader.\n";
@@ -426,9 +426,28 @@ std::string GLShader::resources_declare(const ShaderCreateInfo &info) const
return ss.str();
}
+static std::string main_function_wrapper(std::string &pre_main, std::string &post_main)
+{
+ std::stringstream ss;
+ /* Prototype for the original main. */
+ ss << "\n";
+ ss << "void main_function_();\n";
+ /* Wrapper to the main function in order to inject code processing on globals. */
+ ss << "void main() {\n";
+ ss << pre_main;
+ ss << " main_function_();\n";
+ ss << post_main;
+ ss << "}\n";
+ /* Rename the original main. */
+ ss << "#define main main_function_\n";
+ ss << "\n";
+ return ss.str();
+}
+
std::string GLShader::vertex_interface_declare(const ShaderCreateInfo &info) const
{
std::stringstream ss;
+ std::string post_main = "";
ss << "\n/* Inputs. */\n";
for (const ShaderCreateInfo::VertIn &attr : info.vertex_inputs_) {
@@ -441,13 +460,35 @@ std::string GLShader::vertex_interface_declare(const ShaderCreateInfo &info) con
for (const StageInterfaceInfo *iface : info.vertex_out_interfaces_) {
print_interface(ss, "out", *iface);
}
+ if (!GLContext::layered_rendering_support && bool(info.builtins_ & BuiltinBits::LAYER)) {
+ ss << "out int gpu_Layer;\n";
+ }
+ if (bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD)) {
+ if (!GLContext::native_barycentric_support) {
+ /* Disabled or unsupported. */
+ }
+ else if (GLEW_AMD_shader_explicit_vertex_parameter) {
+ /* Need this for stable barycentric. */
+ ss << "flat out vec4 gpu_pos_flat;\n";
+ ss << "out vec4 gpu_pos;\n";
+
+ post_main += " gpu_pos = gpu_pos_flat = gl_Position;\n";
+ }
+ }
ss << "\n";
+
+ if (post_main.empty() == false) {
+ std::string pre_main = "";
+ ss << main_function_wrapper(pre_main, post_main);
+ }
return ss.str();
}
std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) const
{
std::stringstream ss;
+ std::string pre_main = "";
+
ss << "\n/* Interfaces. */\n";
const Vector<StageInterfaceInfo *> &in_interfaces = (info.geometry_source_.is_empty()) ?
info.vertex_out_interfaces_ :
@@ -455,6 +496,32 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c
for (const StageInterfaceInfo *iface : in_interfaces) {
print_interface(ss, "in", *iface);
}
+ if (bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD)) {
+ if (!GLContext::native_barycentric_support) {
+ ss << "smooth in vec3 gpu_BaryCoord;\n";
+ ss << "noperspective in vec3 gpu_BaryCoordNoPersp;\n";
+ }
+ else if (GLEW_AMD_shader_explicit_vertex_parameter) {
+ /* NOTE(fclem): This won't work with geometry shader. Hopefully, we don't need geometry
+ * shader workaround if this extension/feature is detected. */
+ ss << "\n/* Stable Barycentric Coordinates. */\n";
+ ss << "flat in vec4 gpu_pos_flat;\n";
+ ss << "__explicitInterpAMD in vec4 gpu_pos;\n";
+ /* Globals. */
+ ss << "vec3 gpu_BaryCoord;\n";
+ ss << "vec3 gpu_BaryCoordNoPersp;\n";
+ ss << "\n";
+ ss << "vec2 stable_bary_(vec2 in_bary) {\n";
+ ss << " vec3 bary = vec3(in_bary, 1.0 - in_bary.x - in_bary.y);\n";
+ ss << " if (interpolateAtVertexAMD(gpu_pos, 0) == gpu_pos_flat) { return bary.zxy; }\n";
+ ss << " if (interpolateAtVertexAMD(gpu_pos, 2) == gpu_pos_flat) { return bary.yzx; }\n";
+ ss << " return bary.xyz;\n";
+ ss << "}\n";
+
+ pre_main += " gpu_BaryCoord = stable_bary_(gl_BaryCoordSmoothAMD);\n";
+ pre_main += " gpu_BaryCoordNoPersp = stable_bary_(gl_BaryCoordNoPerspAMD);\n";
+ }
+ }
ss << "\n/* Outputs. */\n";
for (const ShaderCreateInfo::FragOut &output : info.fragment_outputs_) {
ss << "layout(location = " << output.index;
@@ -472,6 +539,11 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c
ss << "out " << to_string(output.type) << " " << output.name << ";\n";
}
ss << "\n";
+
+ if (pre_main.empty() == false) {
+ std::string post_main = "";
+ ss << main_function_wrapper(pre_main, post_main);
+ }
return ss.str();
}
@@ -503,7 +575,7 @@ static StageInterfaceInfo *find_interface_by_name(const Vector<StageInterfaceInf
const StringRefNull &name)
{
for (auto *iface : ifaces) {
- if (iface->name == name) {
+ if (iface->instance_name == name) {
return iface;
}
}
@@ -512,8 +584,8 @@ static StageInterfaceInfo *find_interface_by_name(const Vector<StageInterfaceInf
std::string GLShader::geometry_interface_declare(const ShaderCreateInfo &info) const
{
-
std::stringstream ss;
+
ss << "\n/* Interfaces. */\n";
for (const StageInterfaceInfo *iface : info.vertex_out_interfaces_) {
bool has_matching_output_iface = find_interface_by_name(info.geometry_out_interfaces_,
@@ -547,6 +619,76 @@ std::string GLShader::compute_layout_declare(const ShaderCreateInfo &info) const
ss << "\n";
return ss.str();
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Passthrough geometry shader emulation
+ *
+ * \{ */
+
+std::string GLShader::workaround_geometry_shader_source_create(
+ const shader::ShaderCreateInfo &info)
+{
+ std::stringstream ss;
+
+ const bool do_layer_workaround = !GLContext::layered_rendering_support &&
+ bool(info.builtins_ & BuiltinBits::LAYER);
+ const bool do_barycentric_workaround = !GLContext::native_barycentric_support &&
+ bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD);
+
+ shader::ShaderCreateInfo info_modified = info;
+ info_modified.geometry_out_interfaces_ = info_modified.vertex_out_interfaces_;
+ /**
+ * NOTE(@fclem): Assuming we will render TRIANGLES. This will not work with other primitive
+ * types. In this case, it might not trigger an error on some implementations.
+ */
+ info_modified.geometry_layout(PrimitiveIn::TRIANGLES, PrimitiveOut::TRIANGLE_STRIP, 3);
+
+ ss << geometry_layout_declare(info_modified);
+ ss << geometry_interface_declare(info_modified);
+ if (do_layer_workaround) {
+ ss << "in int gpu_Layer[];\n";
+ }
+ if (do_barycentric_workaround) {
+ ss << "smooth out vec3 gpu_BaryCoord;\n";
+ ss << "noperspective out vec3 gpu_BaryCoordNoPersp;\n";
+ }
+ ss << "\n";
+
+ ss << "void main()\n";
+ ss << "{\n";
+ if (do_layer_workaround) {
+ ss << " gl_Layer = gpu_Layer[0];\n";
+ }
+ for (auto i : IndexRange(3)) {
+ for (auto iface : info_modified.vertex_out_interfaces_) {
+ for (auto &inout : iface->inouts) {
+ ss << " " << iface->instance_name << "_out." << inout.name;
+ ss << " = " << iface->instance_name << "_in[" << i << "]." << inout.name << ";\n";
+ }
+ }
+ if (do_barycentric_workaround) {
+ ss << " gpu_BaryCoordNoPersp = gpu_BaryCoord =";
+ ss << " vec3(" << int(i == 0) << ", " << int(i == 1) << ", " << int(i == 2) << ");\n";
+ }
+ ss << " gl_Position = gl_in[" << i << "].gl_Position;\n";
+ ss << " EmitVertex();\n";
+ }
+ ss << "}\n";
+ return ss.str();
+}
+
+bool GLShader::do_geometry_shader_injection(const shader::ShaderCreateInfo *info)
+{
+ BuiltinBits builtins = info->builtins_;
+ if (!GLContext::native_barycentric_support && bool(builtins & BuiltinBits::BARYCENTRIC_COORD)) {
+ return true;
+ }
+ if (!GLContext::layered_rendering_support && bool(builtins & BuiltinBits::LAYER)) {
+ return true;
+ }
+ return false;
+}
/** \} */
@@ -557,7 +699,7 @@ std::string GLShader::compute_layout_declare(const ShaderCreateInfo &info) const
static char *glsl_patch_default_get()
{
/** Used for shader patching. Init once. */
- static char patch[700] = "\0";
+ static char patch[1024] = "\0";
if (patch[0] != '\0') {
return patch;
}
@@ -601,6 +743,13 @@ static char *glsl_patch_default_get()
STR_CONCAT(patch, slen, "#extension GL_ARB_shader_image_load_store: enable\n");
STR_CONCAT(patch, slen, "#extension GL_ARB_shading_language_420pack: enable\n");
}
+ if (GLContext::layered_rendering_support) {
+ STR_CONCAT(patch, slen, "#extension GL_AMD_vertex_shader_layer: enable\n");
+ STR_CONCAT(patch, slen, "#define gpu_Layer gl_Layer\n");
+ }
+ if (GLContext::native_barycentric_support) {
+ STR_CONCAT(patch, slen, "#extension GL_AMD_shader_explicit_vertex_parameter: enable\n");
+ }
/* Fallbacks. */
if (!GLContext::shader_draw_parameters_support) {
@@ -717,6 +866,14 @@ bool GLShader::finalize(const shader::ShaderCreateInfo *info)
return false;
}
+ if (info && do_geometry_shader_injection(info)) {
+ std::string source = workaround_geometry_shader_source_create(*info);
+ Vector<const char *> sources;
+ sources.append("version");
+ sources.append(source.c_str());
+ geometry_shader_from_glsl(sources);
+ }
+
glLinkProgram(shader_program_);
GLint status;
diff --git a/source/blender/gpu/opengl/gl_shader.hh b/source/blender/gpu/opengl/gl_shader.hh
index a82ab026c16..cc1c93142f8 100644
--- a/source/blender/gpu/opengl/gl_shader.hh
+++ b/source/blender/gpu/opengl/gl_shader.hh
@@ -94,6 +94,14 @@ class GLShader : public Shader {
/** Create, compile and attach the shader stage to the shader program. */
GLuint create_shader_stage(GLenum gl_stage, MutableSpan<const char *> sources);
+ /**
+ * \brief features available on newer implementation such as native barycentric coordinates
+ * and layered rendering, necessitate a geometry shader to work on older hardware.
+ */
+ std::string workaround_geometry_shader_source_create(const shader::ShaderCreateInfo &info);
+
+ bool do_geometry_shader_injection(const shader::ShaderCreateInfo *info);
+
MEM_CXX_CLASS_ALLOC_FUNCS("GLShader");
};
diff --git a/source/blender/gpu/opengl/gl_shader_interface.cc b/source/blender/gpu/opengl/gl_shader_interface.cc
index 71b908665d3..83016fca8a5 100644
--- a/source/blender/gpu/opengl/gl_shader_interface.cc
+++ b/source/blender/gpu/opengl/gl_shader_interface.cc
@@ -497,7 +497,7 @@ GLShaderInterface::~GLShaderInterface()
void GLShaderInterface::ref_add(GLVaoCache *ref)
{
for (int i = 0; i < refs_.size(); i++) {
- if (refs_[i] == NULL) {
+ if (refs_[i] == nullptr) {
refs_[i] = ref;
return;
}
@@ -509,7 +509,7 @@ void GLShaderInterface::ref_remove(GLVaoCache *ref)
{
for (int i = 0; i < refs_.size(); i++) {
if (refs_[i] == ref) {
- refs_[i] = NULL;
+ refs_[i] = nullptr;
break; /* cannot have duplicates */
}
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl
index 01a16e194ca..ab6024b073d 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_diffuse.glsl
@@ -18,7 +18,7 @@ void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
result.radiance = out_Diffuse_0.radiance;
- /* TODO(fclem) Try to not use this. */
+ /* TODO(@fclem): Try to not use this. */
closure_load_ssr_data(vec3(0.0), 0.0, in_Diffuse_0.N, -1.0, result);
}
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
index bba84c2be52..c97fc090fe2 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl
@@ -166,7 +166,7 @@ void node_bsdf_principled(vec4 base_color,
float btdf = (do_multiscatter != 0.0) ?
1.0 :
btdf_lut(NV, in_Refraction_3.roughness, in_Refraction_3.ior).x;
- /* TODO(fclem) This could be going to a transmission render pass instead. */
+ /* TODO(@fclem): This could be going to a transmission render pass instead. */
out_Refraction_3.radiance *= btdf;
out_Refraction_3.radiance = render_pass_glossy_mask(vec3(1), out_Refraction_3.radiance);
out_Refraction_3.radiance *= base_color.rgb;
diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl
index 7cbc7218f5c..8a42a131f43 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_refraction.glsl
@@ -21,7 +21,7 @@ void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Cl
result.radiance = out_Refraction_0.radiance;
- /* TODO(fclem) Try to not use this. */
+ /* TODO(@fclem): Try to not use this. */
result.ssr_normal = normal_encode(mat3(ViewMatrix) * in_Refraction_0.N,
viewCameraVec(viewPosition));
}
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 d0c159cdf37..20b634aa801 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
@@ -22,7 +22,7 @@ void node_subsurface_scattering(vec4 color,
closure_load_sss_data(scale, out_Diffuse_0.radiance, color.rgb, int(sss_id), result);
- /* TODO(fclem) Try to not use this. */
+ /* TODO(@fclem): Try to not use this. */
closure_load_ssr_data(vec3(0.0), 0.0, in_Diffuse_0.N, -1.0, result);
}