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/intern')
-rw-r--r--source/blender/gpu/intern/gpu_backend.hh1
-rw-r--r--source/blender/gpu/intern/gpu_batch.cc51
-rw-r--r--source/blender/gpu/intern/gpu_batch_presets.c11
-rw-r--r--source/blender/gpu/intern/gpu_batch_private.hh5
-rw-r--r--source/blender/gpu/intern/gpu_batch_utils.c1
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c116
-rw-r--r--source/blender/gpu/intern/gpu_capabilities.cc27
-rw-r--r--source/blender/gpu/intern/gpu_capabilities_private.hh1
-rw-r--r--source/blender/gpu/intern/gpu_codegen.cc76
-rw-r--r--source/blender/gpu/intern/gpu_compute.cc1
-rw-r--r--source/blender/gpu/intern/gpu_context.cc73
-rw-r--r--source/blender/gpu/intern/gpu_context_private.hh30
-rw-r--r--source/blender/gpu/intern/gpu_drawlist.cc3
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer.cc62
-rw-r--r--source/blender/gpu/intern/gpu_framebuffer_private.hh7
-rw-r--r--source/blender/gpu/intern/gpu_immediate.cc4
-rw-r--r--source/blender/gpu/intern/gpu_immediate_private.hh6
-rw-r--r--source/blender/gpu/intern/gpu_immediate_util.c15
-rw-r--r--source/blender/gpu/intern/gpu_index_buffer.cc105
-rw-r--r--source/blender/gpu/intern/gpu_index_buffer_private.hh21
-rw-r--r--source/blender/gpu/intern/gpu_init_exit.c7
-rw-r--r--source/blender/gpu/intern/gpu_material.c77
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.c136
-rw-r--r--source/blender/gpu/intern/gpu_node_graph.h3
-rw-r--r--source/blender/gpu/intern/gpu_platform.cc14
-rw-r--r--source/blender/gpu/intern/gpu_private.h4
-rw-r--r--source/blender/gpu/intern/gpu_select.c4
-rw-r--r--source/blender/gpu/intern/gpu_select_pick.c1
-rw-r--r--source/blender/gpu/intern/gpu_select_sample_query.cc1
-rw-r--r--source/blender/gpu/intern/gpu_shader.cc48
-rw-r--r--source/blender/gpu/intern/gpu_shader_builder.cc1
-rw-r--r--source/blender/gpu/intern/gpu_shader_builder_stubs.cc78
-rw-r--r--source/blender/gpu/intern/gpu_shader_builtin.c55
-rw-r--r--source/blender/gpu/intern/gpu_shader_create_info.cc25
-rw-r--r--source/blender/gpu/intern/gpu_shader_create_info.hh128
-rw-r--r--source/blender/gpu/intern/gpu_shader_dependency.cc269
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.hh47
-rw-r--r--source/blender/gpu/intern/gpu_shader_log.cc3
-rw-r--r--source/blender/gpu/intern/gpu_shader_private.hh2
-rw-r--r--source/blender/gpu/intern/gpu_state.cc2
-rw-r--r--source/blender/gpu/intern/gpu_storage_buffer.cc6
-rw-r--r--source/blender/gpu/intern/gpu_storage_buffer_private.hh3
-rw-r--r--source/blender/gpu/intern/gpu_texture.cc156
-rw-r--r--source/blender/gpu/intern/gpu_texture_private.hh8
-rw-r--r--source/blender/gpu/intern/gpu_uniform_buffer_private.hh2
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer.cc23
-rw-r--r--source/blender/gpu/intern/gpu_vertex_buffer_private.hh12
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format.cc119
-rw-r--r--source/blender/gpu/intern/gpu_vertex_format_private.h1
-rw-r--r--source/blender/gpu/intern/gpu_viewport.c3
50 files changed, 1451 insertions, 403 deletions
diff --git a/source/blender/gpu/intern/gpu_backend.hh b/source/blender/gpu/intern/gpu_backend.hh
index 6e07e6c3229..d2890efee72 100644
--- a/source/blender/gpu/intern/gpu_backend.hh
+++ b/source/blender/gpu/intern/gpu_backend.hh
@@ -30,6 +30,7 @@ class VertBuf;
class GPUBackend {
public:
virtual ~GPUBackend() = default;
+ virtual void delete_resources() = 0;
static GPUBackend *get();
diff --git a/source/blender/gpu/intern/gpu_batch.cc b/source/blender/gpu/intern/gpu_batch.cc
index 32b117dac12..c871004deac 100644
--- a/source/blender/gpu/intern/gpu_batch.cc
+++ b/source/blender/gpu/intern/gpu_batch.cc
@@ -14,7 +14,6 @@
#include "GPU_batch.h"
#include "GPU_batch_presets.h"
-#include "GPU_matrix.h"
#include "GPU_platform.h"
#include "GPU_shader.h"
@@ -201,6 +200,13 @@ bool GPU_batch_vertbuf_has(GPUBatch *batch, GPUVertBuf *verts)
return false;
}
+void GPU_batch_resource_id_buf_set(GPUBatch *batch, GPUStorageBuf *resource_id_buf)
+{
+ BLI_assert(resource_id_buf);
+ batch->flag |= GPU_BATCH_DIRTY;
+ batch->resource_id_buf = resource_id_buf;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -221,6 +227,30 @@ void GPU_batch_set_shader(GPUBatch *batch, GPUShader *shader)
/** \name Drawing / Drawcall functions
* \{ */
+void GPU_batch_draw_parameter_get(
+ GPUBatch *gpu_batch, int *r_v_count, int *r_v_first, int *r_base_index, int *r_i_count)
+{
+ Batch *batch = static_cast<Batch *>(gpu_batch);
+
+ if (batch->elem) {
+ *r_v_count = batch->elem_()->index_len_get();
+ *r_v_first = batch->elem_()->index_start_get();
+ *r_base_index = batch->elem_()->index_base_get();
+ }
+ else {
+ *r_v_count = batch->verts_(0)->vertex_len;
+ *r_v_first = 0;
+ *r_base_index = -1;
+ }
+
+ int i_count = (batch->inst[0]) ? batch->inst_(0)->vertex_len : 1;
+ /* Meh. This is to be able to use different numbers of verts in instance VBO's. */
+ if (batch->inst[1] != nullptr) {
+ i_count = min_ii(i_count, batch->inst_(1)->vertex_len);
+ }
+ *r_i_count = i_count;
+}
+
void GPU_batch_draw(GPUBatch *batch)
{
GPU_shader_bind(batch->shader);
@@ -271,6 +301,25 @@ void GPU_batch_draw_advanced(
batch->draw(v_first, v_count, i_first, i_count);
}
+void GPU_batch_draw_indirect(GPUBatch *gpu_batch, GPUStorageBuf *indirect_buf, intptr_t offset)
+{
+ BLI_assert(Context::get()->shader != nullptr);
+ BLI_assert(indirect_buf != nullptr);
+ Batch *batch = static_cast<Batch *>(gpu_batch);
+
+ batch->draw_indirect(indirect_buf, offset);
+}
+
+void GPU_batch_multi_draw_indirect(
+ GPUBatch *gpu_batch, GPUStorageBuf *indirect_buf, int count, intptr_t offset, intptr_t stride)
+{
+ BLI_assert(Context::get()->shader != nullptr);
+ BLI_assert(indirect_buf != nullptr);
+ Batch *batch = static_cast<Batch *>(gpu_batch);
+
+ batch->multi_draw_indirect(indirect_buf, count, offset, stride);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c
index ab5e23a846c..4dff35c3633 100644
--- a/source/blender/gpu/intern/gpu_batch_presets.c
+++ b/source/blender/gpu/intern/gpu_batch_presets.c
@@ -11,15 +11,8 @@
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
-#include "DNA_userdef_types.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
#include "GPU_batch.h"
-#include "GPU_batch_presets.h" /* own include */
-#include "GPU_batch_utils.h"
-#include "GPU_context.h"
+#include "GPU_batch_presets.h" /* Own include. */
/* -------------------------------------------------------------------- */
/** \name Local Structures
@@ -139,7 +132,7 @@ GPUBatch *GPU_batch_preset_sphere_wire(int lod)
/** \name Create Sphere (3D)
* \{ */
-GPUBatch *gpu_batch_sphere(int lat_res, int lon_res)
+static GPUBatch *gpu_batch_sphere(int lat_res, int lon_res)
{
const float lon_inc = 2 * M_PI / lon_res;
const float lat_inc = M_PI / lat_res;
diff --git a/source/blender/gpu/intern/gpu_batch_private.hh b/source/blender/gpu/intern/gpu_batch_private.hh
index 23052f601d2..59646925d68 100644
--- a/source/blender/gpu/intern/gpu_batch_private.hh
+++ b/source/blender/gpu/intern/gpu_batch_private.hh
@@ -29,6 +29,11 @@ class Batch : public GPUBatch {
virtual ~Batch() = default;
virtual void draw(int v_first, int v_count, int i_first, int i_count) = 0;
+ virtual void draw_indirect(GPUStorageBuf *indirect_buf, intptr_t offset) = 0;
+ virtual void multi_draw_indirect(GPUStorageBuf *indirect_buf,
+ int count,
+ intptr_t offset,
+ intptr_t stride) = 0;
/* Convenience casts. */
IndexBuf *elem_() const
diff --git a/source/blender/gpu/intern/gpu_batch_utils.c b/source/blender/gpu/intern/gpu_batch_utils.c
index 43a47aab945..10a05fe90b9 100644
--- a/source/blender/gpu/intern/gpu_batch_utils.c
+++ b/source/blender/gpu/intern/gpu_batch_utils.c
@@ -8,7 +8,6 @@
#include "BLI_math.h"
#include "BLI_polyfill_2d.h"
-#include "BLI_rect.h"
#include "BLI_sort_utils.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index f7be2434fbf..8e3058b884d 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -14,26 +14,18 @@
#include "MEM_guardedalloc.h"
-#include "BLI_alloca.h"
-#include "BLI_array.h"
#include "BLI_bitmap.h"
#include "BLI_ghash.h"
-#include "BLI_hash.h"
-#include "BLI_math.h"
#include "BLI_math_color.h"
-#include "BLI_math_color_blend.h"
-#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
-#include "DNA_userdef_types.h"
#include "BKE_DerivedMesh.h"
#include "BKE_attribute.h"
#include "BKE_ccg.h"
#include "BKE_customdata.h"
-#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_paint.h"
#include "BKE_pbvh.h"
@@ -219,19 +211,18 @@ static void gpu_pbvh_batch_init(GPU_PBVH_Buffers *buffers, GPUPrimType prim)
* \{ */
static bool gpu_pbvh_is_looptri_visible(const MLoopTri *lt,
- const MVert *mvert,
+ const bool *hide_vert,
const MLoop *mloop,
const int *sculpt_face_sets)
{
- return (!paint_is_face_hidden(lt, mvert, mloop) && sculpt_face_sets &&
+ return (!paint_is_face_hidden(lt, hide_vert, mloop) && sculpt_face_sets &&
sculpt_face_sets[lt->poly] > SCULPT_FACE_SET_NONE);
}
void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id,
GPU_PBVH_Buffers *buffers,
+ const Mesh *mesh,
const MVert *mvert,
- const CustomData *vdata,
- const CustomData *ldata,
const float *vmask,
const int *sculpt_face_sets,
int face_sets_color_seed,
@@ -242,23 +233,25 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id,
GPUAttrRef vcol_refs[MAX_GPU_ATTR];
GPUAttrRef cd_uvs[MAX_GPU_ATTR];
- Mesh me_query;
- BKE_id_attribute_copy_domains_temp(ID_ME, vdata, NULL, ldata, NULL, NULL, &me_query.id);
+ const bool *hide_vert = (const bool *)CustomData_get_layer_named(
+ &mesh->vdata, CD_PROP_BOOL, ".hide_vert");
+ const int *material_indices = (const int *)CustomData_get_layer_named(
+ &mesh->pdata, CD_PROP_INT32, "material_index");
- CustomDataLayer *actcol = BKE_id_attributes_active_color_get(&me_query.id);
- eAttrDomain actcol_domain = actcol ? BKE_id_attribute_domain(&me_query.id, actcol) :
+ const CustomDataLayer *actcol = BKE_id_attributes_active_color_get(&mesh->id);
+ eAttrDomain actcol_domain = actcol ? BKE_id_attribute_domain(&mesh->id, actcol) :
ATTR_DOMAIN_AUTO;
- CustomDataLayer *rendercol = BKE_id_attributes_render_color_get(&me_query.id);
+ const CustomDataLayer *rendercol = BKE_id_attributes_render_color_get(&mesh->id);
int totcol;
if (update_flags & GPU_PBVH_BUFFERS_SHOW_VCOL) {
totcol = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_COLOR,
CD_MASK_COLOR_ALL,
- vdata,
+ &mesh->vdata,
NULL,
- ldata,
+ &mesh->ldata,
NULL,
vcol_refs,
vbo_id->active_attrs_only,
@@ -275,14 +268,14 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id,
CD_MASK_MLOOPUV,
NULL,
NULL,
- ldata,
+ &mesh->ldata,
NULL,
cd_uvs,
vbo_id->active_attrs_only,
CD_MLOOPUV,
ATTR_DOMAIN_CORNER,
- get_active_layer(ldata, CD_MLOOPUV),
- get_render_layer(ldata, CD_MLOOPUV));
+ get_active_layer(&mesh->ldata, CD_MLOOPUV),
+ get_render_layer(&mesh->ldata, CD_MLOOPUV));
const bool show_mask = vmask && (update_flags & GPU_PBVH_BUFFERS_SHOW_MASK) != 0;
const bool show_face_sets = sculpt_face_sets &&
@@ -316,13 +309,13 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id,
GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->uv[uv_i], &uv_step);
GPUAttrRef *ref = cd_uvs + uv_i;
- CustomDataLayer *layer = ldata->layers + ref->layer_idx;
+ CustomDataLayer *layer = mesh->ldata.layers + ref->layer_idx;
MLoopUV *muv = layer->data;
for (uint i = 0; i < buffers->face_indices_len; i++) {
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[i]];
- if (!gpu_pbvh_is_looptri_visible(lt, mvert, buffers->mloop, sculpt_face_sets)) {
+ if (!gpu_pbvh_is_looptri_visible(lt, hide_vert, buffers->mloop, sculpt_face_sets)) {
continue;
}
@@ -338,20 +331,20 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id,
for (int col_i = 0; col_i < totcol; col_i++) {
GPU_vertbuf_attr_get_raw_data(buffers->vert_buf, vbo_id->col[col_i], &col_step);
- MPropCol *pcol = NULL;
- MLoopCol *mcol = NULL;
+ const MPropCol *pcol = NULL;
+ const MLoopCol *mcol = NULL;
GPUAttrRef *ref = vcol_refs + col_i;
- const CustomData *cdata = ref->domain == ATTR_DOMAIN_POINT ? vdata : ldata;
- CustomDataLayer *layer = cdata->layers + ref->layer_idx;
+ const CustomData *cdata = ref->domain == ATTR_DOMAIN_POINT ? &mesh->vdata : &mesh->ldata;
+ const CustomDataLayer *layer = cdata->layers + ref->layer_idx;
bool color_loops = ref->domain == ATTR_DOMAIN_CORNER;
if (layer->type == CD_PROP_COLOR) {
- pcol = (MPropCol *)layer->data;
+ pcol = (const MPropCol *)layer->data;
}
else {
- mcol = (MLoopCol *)layer->data;
+ mcol = (const MLoopCol *)layer->data;
}
for (uint i = 0; i < buffers->face_indices_len; i++) {
@@ -362,7 +355,7 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id,
buffers->mloop[lt->tri[2]].v,
};
- if (!gpu_pbvh_is_looptri_visible(lt, mvert, buffers->mloop, sculpt_face_sets)) {
+ if (!gpu_pbvh_is_looptri_visible(lt, hide_vert, buffers->mloop, sculpt_face_sets)) {
continue;
}
@@ -373,7 +366,7 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id,
ushort scol[4] = {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX};
if (pcol) {
- MPropCol *pcol2 = pcol + (color_loops ? loop_index : vtri[j]);
+ const MPropCol *pcol2 = pcol + (color_loops ? loop_index : vtri[j]);
scol[0] = unit_float_to_ushort_clamp(pcol2->color[0]);
scol[1] = unit_float_to_ushort_clamp(pcol2->color[1]);
@@ -402,7 +395,7 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id,
buffers->mloop[lt->tri[2]].v,
};
- if (!gpu_pbvh_is_looptri_visible(lt, mvert, buffers->mloop, sculpt_face_sets)) {
+ if (!gpu_pbvh_is_looptri_visible(lt, hide_vert, buffers->mloop, sculpt_face_sets)) {
continue;
}
@@ -458,37 +451,39 @@ void GPU_pbvh_mesh_buffers_update(PBVHGPUFormat *vbo_id,
/* Get material index from the first face of this buffer. */
const MLoopTri *lt = &buffers->looptri[buffers->face_indices[0]];
- const MPoly *mp = &buffers->mpoly[lt->poly];
- buffers->material_index = mp->mat_nr;
+ buffers->material_index = material_indices ? material_indices[lt->poly] : 0;
buffers->show_overlay = !empty_mask || !default_face_set;
buffers->mvert = mvert;
}
-GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const MPoly *mpoly,
- const MLoop *mloop,
+GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const Mesh *mesh,
const MLoopTri *looptri,
- const MVert *mvert,
- const int *face_indices,
const int *sculpt_face_sets,
- const int face_indices_len,
- const struct Mesh *mesh)
+ const int *face_indices,
+ const int face_indices_len)
{
GPU_PBVH_Buffers *buffers;
int i, tottri;
int tot_real_edges = 0;
+ const MPoly *polys = BKE_mesh_polys(mesh);
+ const MLoop *loops = BKE_mesh_loops(mesh);
+
buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers");
+ const bool *hide_vert = (bool *)CustomData_get_layer_named(
+ &mesh->vdata, CD_PROP_BOOL, ".hide_vert");
+
/* smooth or flat for all */
- buffers->smooth = mpoly[looptri[face_indices[0]].poly].flag & ME_SMOOTH;
+ buffers->smooth = polys[looptri[face_indices[0]].poly].flag & ME_SMOOTH;
buffers->show_overlay = false;
/* Count the number of visible triangles */
for (i = 0, tottri = 0; i < face_indices_len; i++) {
const MLoopTri *lt = &looptri[face_indices[i]];
- if (gpu_pbvh_is_looptri_visible(lt, mvert, mloop, sculpt_face_sets)) {
+ if (gpu_pbvh_is_looptri_visible(lt, hide_vert, loops, sculpt_face_sets)) {
int r_edges[3];
BKE_mesh_looptri_get_real_edges(mesh, lt, r_edges);
for (int j = 0; j < 3; j++) {
@@ -503,8 +498,8 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const MPoly *mpoly,
if (tottri == 0) {
buffers->tot_tri = 0;
- buffers->mpoly = mpoly;
- buffers->mloop = mloop;
+ buffers->mpoly = polys;
+ buffers->mloop = loops;
buffers->looptri = looptri;
buffers->face_indices = face_indices;
buffers->face_indices_len = 0;
@@ -521,7 +516,7 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const MPoly *mpoly,
const MLoopTri *lt = &looptri[face_indices[i]];
/* Skip hidden faces */
- if (!gpu_pbvh_is_looptri_visible(lt, mvert, mloop, sculpt_face_sets)) {
+ if (!gpu_pbvh_is_looptri_visible(lt, hide_vert, loops, sculpt_face_sets)) {
continue;
}
@@ -543,8 +538,8 @@ GPU_PBVH_Buffers *GPU_pbvh_mesh_buffers_build(const MPoly *mpoly,
buffers->tot_tri = tottri;
- buffers->mpoly = mpoly;
- buffers->mloop = mloop;
+ buffers->mpoly = polys;
+ buffers->mloop = loops;
buffers->looptri = looptri;
buffers->face_indices = face_indices;
@@ -889,13 +884,14 @@ void GPU_pbvh_grid_buffers_update(PBVHGPUFormat *vbo_id,
buffers->show_overlay = !empty_mask || !default_face_set;
}
-GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hidden)
+GPU_PBVH_Buffers *GPU_pbvh_grid_buffers_build(int totgrid, BLI_bitmap **grid_hidden, bool smooth)
{
GPU_PBVH_Buffers *buffers;
buffers = MEM_callocN(sizeof(GPU_PBVH_Buffers), "GPU_Buffers");
buffers->grid_hidden = grid_hidden;
buffers->totgrid = totgrid;
+ buffers->smooth = smooth;
buffers->show_overlay = false;
@@ -1189,9 +1185,9 @@ GPU_PBVH_Buffers *GPU_pbvh_bmesh_buffers_build(bool smooth_shading)
* Builds a list of attributes from a set of domains and a set of
* customdata types.
*
- * \param active_only Returns only one item, a GPUAttrRef to active_layer
- * \param active_layer CustomDataLayer to use for the active layer
- * \param active_layer CustomDataLayer to use for the render layer
+ * \param active_only: Returns only one item, a #GPUAttrRef to active_layer.
+ * \param active_layer: #CustomDataLayer to use for the active layer.
+ * \param active_layer: #CustomDataLayer to use for the render layer.
*/
static int gpu_pbvh_make_attr_offs(eAttrDomainMask domain_mask,
eCustomDataMask type_mask,
@@ -1237,7 +1233,7 @@ static int gpu_pbvh_make_attr_offs(eAttrDomainMask domain_mask,
continue;
}
- CustomDataLayer *cl = cdata->layers;
+ const CustomDataLayer *cl = cdata->layers;
for (int i = 0; count < MAX_GPU_ATTR && i < cdata->totlayer; i++, cl++) {
if ((CD_TYPE_AS_MASK(cl->type) & type_mask) && !(cl->flag & CD_FLAG_TEMPORARY)) {
@@ -1253,9 +1249,7 @@ static int gpu_pbvh_make_attr_offs(eAttrDomainMask domain_mask,
}
}
- /* ensure render layer is last
- draw cache code seems to need this
- */
+ /* Ensure render layer is last, draw cache code seems to need this. */
for (int i = 0; i < count; i++) {
GPUAttrRef *ref = r_cd_attrs + i;
@@ -1326,12 +1320,12 @@ bool GPU_pbvh_attribute_names_update(PBVHType pbvh_type,
BKE_id_attribute_copy_domains_temp(ID_ME, vdata, NULL, ldata, NULL, NULL, &me_query.id);
- CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&me_query.id);
- CustomDataLayer *render_color_layer = BKE_id_attributes_render_color_get(&me_query.id);
+ const CustomDataLayer *active_color_layer = BKE_id_attributes_active_color_get(&me_query.id);
+ const CustomDataLayer *render_color_layer = BKE_id_attributes_render_color_get(&me_query.id);
eAttrDomain active_color_domain = active_color_layer ?
BKE_id_attribute_domain(&me_query.id,
active_color_layer) :
- ATTR_DOMAIN_NUM;
+ ATTR_DOMAIN_POINT;
GPUAttrRef vcol_layers[MAX_GPU_ATTR];
int totlayer = gpu_pbvh_make_attr_offs(ATTR_DOMAIN_MASK_COLOR,
@@ -1381,7 +1375,7 @@ bool GPU_pbvh_attribute_names_update(PBVHType pbvh_type,
vbo_id->totuv = 0;
if (pbvh_type == PBVH_FACES && ldata && CustomData_has_layer(ldata, CD_MLOOPUV)) {
GPUAttrRef uv_layers[MAX_GPU_ATTR];
- CustomDataLayer *active = NULL, *render = NULL;
+ const CustomDataLayer *active = NULL, *render = NULL;
active = get_active_layer(ldata, CD_MLOOPUV);
render = get_render_layer(ldata, CD_MLOOPUV);
@@ -1407,7 +1401,7 @@ bool GPU_pbvh_attribute_names_update(PBVHType pbvh_type,
vbo_id->uv[i] = GPU_vertformat_attr_add(
&vbo_id->format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- CustomDataLayer *cl = ldata->layers + ref->layer_idx;
+ const CustomDataLayer *cl = ldata->layers + ref->layer_idx;
bool is_active = ref->layer_idx == CustomData_get_active_layer_index(ldata, CD_MLOOPUV);
DRW_cdlayer_attr_aliases_add(&vbo_id->format, "u", ldata, cl, cl == render, is_active);
diff --git a/source/blender/gpu/intern/gpu_capabilities.cc b/source/blender/gpu/intern/gpu_capabilities.cc
index eb69a1d2635..e584b757a05 100644
--- a/source/blender/gpu/intern/gpu_capabilities.cc
+++ b/source/blender/gpu/intern/gpu_capabilities.cc
@@ -8,7 +8,7 @@
* with checks for drivers and GPU support.
*/
-#include "DNA_userdef_types.h"
+#include "DNA_userdef_types.h" /* For `U.glreslimit`. */
#include "GPU_capabilities.h"
@@ -33,6 +33,11 @@ int GPU_max_texture_size()
return GCaps.max_texture_size;
}
+int GPU_max_texture_3d_size(void)
+{
+ return GCaps.max_texture_3d_size;
+}
+
int GPU_texture_size_with_limit(int res)
{
int size = GPU_max_texture_size();
@@ -115,6 +120,11 @@ const char *GPU_extension_get(int i)
return GCaps.extension_get ? GCaps.extension_get(i) : "\0";
}
+int GPU_max_samplers()
+{
+ return GCaps.max_samplers;
+}
+
bool GPU_mip_render_workaround()
{
return GCaps.mip_render_workaround;
@@ -161,6 +171,11 @@ bool GPU_shader_image_load_store_support()
return GCaps.shader_image_load_store_support;
}
+bool GPU_shader_draw_parameters_support()
+{
+ return GCaps.shader_draw_parameters_support;
+}
+
int GPU_max_shader_storage_buffer_bindings()
{
return GCaps.max_shader_storage_buffer_bindings;
@@ -171,6 +186,16 @@ int GPU_max_compute_shader_storage_blocks()
return GCaps.max_compute_shader_storage_blocks;
}
+int GPU_minimum_per_vertex_stride(void)
+{
+ return GCaps.minimum_per_vertex_stride;
+}
+
+bool GPU_transform_feedback_support(void)
+{
+ return GCaps.transform_feedback_support;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/gpu/intern/gpu_capabilities_private.hh b/source/blender/gpu/intern/gpu_capabilities_private.hh
index a17dbe7f8e6..dadd14791e7 100644
--- a/source/blender/gpu/intern/gpu_capabilities_private.hh
+++ b/source/blender/gpu/intern/gpu_capabilities_private.hh
@@ -44,6 +44,7 @@ struct GPUCapabilities {
bool compute_shader_support = false;
bool shader_storage_buffer_objects_support = false;
bool shader_image_load_store_support = false;
+ bool shader_draw_parameters_support = false;
bool transform_feedback_support = false;
/* OpenGL related workarounds. */
diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc
index a5ba0949a83..0102b8db5b2 100644
--- a/source/blender/gpu/intern/gpu_codegen.cc
+++ b/source/blender/gpu/intern/gpu_codegen.cc
@@ -12,8 +12,6 @@
#include "DNA_customdata_types.h"
#include "DNA_image_types.h"
-#include "BLI_blenlib.h"
-#include "BLI_dynstr.h"
#include "BLI_ghash.h"
#include "BLI_hash_mm2a.h"
#include "BLI_link_utils.h"
@@ -23,7 +21,6 @@
#include "PIL_time.h"
#include "BKE_material.h"
-#include "BKE_world.h"
#include "GPU_capabilities.h"
#include "GPU_material.h"
@@ -35,7 +32,6 @@
#include "BLI_vector.hh"
#include "gpu_codegen.h"
-#include "gpu_material_library.h"
#include "gpu_node_graph.h"
#include "gpu_shader_create_info.hh"
#include "gpu_shader_dependency_private.h"
@@ -56,16 +52,19 @@ using namespace blender::gpu::shader;
*/
struct GPUCodegenCreateInfo : ShaderCreateInfo {
struct NameBuffer {
+ using NameEntry = std::array<char, 32>;
+
/** Duplicate attribute names to avoid reference the GPUNodeGraph directly. */
char attr_names[16][GPU_MAX_SAFE_ATTR_NAME + 1];
char var_names[16][8];
- blender::Vector<std::array<char, 32>, 16> sampler_names;
+ blender::Vector<std::unique_ptr<NameEntry>, 16> sampler_names;
/* Returns the appended name memory location */
const char *append_sampler_name(const char name[32])
{
- auto index = sampler_names.append_and_get_index(std::array<char, 32>());
- char *name_buffer = sampler_names[index].data();
+ auto index = sampler_names.size();
+ sampler_names.append(std::make_unique<NameEntry>());
+ char *name_buffer = sampler_names[index]->data();
memcpy(name_buffer, name, 32);
return name_buffer;
}
@@ -209,9 +208,10 @@ static std::ostream &operator<<(std::ostream &stream, const GPUConstant *input)
stream << input->type << "(";
for (int i = 0; i < input->type; i++) {
char formated_float[32];
- /* Print with the maximum precision for single precision float using scientific notation.
- * See https://stackoverflow.com/questions/16839658/#answer-21162120 */
- SNPRINTF(formated_float, "%.9g", input->vec[i]);
+ /* Use uint representation to allow exact same bit pattern even if NaN. This is because we can
+ * pass UINTs as floats for constants. */
+ const uint32_t *uint_vec = reinterpret_cast<const uint32_t *>(input->vec);
+ SNPRINTF(formated_float, "uintBitsToFloat(%uu)", uint_vec[i]);
stream << formated_float;
if (i < input->type - 1) {
stream << ", ";
@@ -260,6 +260,7 @@ class GPUCodegen {
MEM_SAFE_FREE(output.volume);
MEM_SAFE_FREE(output.thickness);
MEM_SAFE_FREE(output.displacement);
+ MEM_SAFE_FREE(output.composite);
MEM_SAFE_FREE(output.material_functions);
delete create_info;
BLI_freelistN(&ubo_inputs_);
@@ -281,6 +282,7 @@ class GPUCodegen {
void node_serialize(std::stringstream &eval_ss, const GPUNode *node);
char *graph_serialize(eGPUNodeTag tree_tag, GPUNodeLink *output_link);
+ char *graph_serialize(eGPUNodeTag tree_tag);
static char *extract_c_str(std::stringstream &stream)
{
@@ -303,7 +305,7 @@ void GPUCodegen::generate_attribs()
info.vertex_out(iface);
/* Input declaration, loading / assignment to interface and geometry shader passthrough. */
- std::stringstream decl_ss, iface_ss, load_ss;
+ std::stringstream load_ss;
int slot = 15;
LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &graph.attributes) {
@@ -352,24 +354,43 @@ void GPUCodegen::generate_resources()
{
GPUCodegenCreateInfo &info = *create_info;
+ /* Ref. T98190: Defines are optimizations for old compilers.
+ * Might become unnecessary with EEVEE-Next. */
+ if (GPU_material_flag_get(&mat, GPU_MATFLAG_PRINCIPLED_CLEARCOAT)) {
+ info.define("PRINCIPLED_CLEARCOAT");
+ }
+ if (GPU_material_flag_get(&mat, GPU_MATFLAG_PRINCIPLED_METALLIC)) {
+ info.define("PRINCIPLED_METALLIC");
+ }
+ if (GPU_material_flag_get(&mat, GPU_MATFLAG_PRINCIPLED_DIELECTRIC)) {
+ info.define("PRINCIPLED_DIELECTRIC");
+ }
+ if (GPU_material_flag_get(&mat, GPU_MATFLAG_PRINCIPLED_GLASS)) {
+ info.define("PRINCIPLED_GLASS");
+ }
+ if (GPU_material_flag_get(&mat, GPU_MATFLAG_PRINCIPLED_ANY)) {
+ info.define("PRINCIPLED_ANY");
+ }
+
std::stringstream ss;
/* Textures. */
+ int slot = 0;
LISTBASE_FOREACH (GPUMaterialTexture *, tex, &graph.textures) {
if (tex->colorband) {
const char *name = info.name_buffer.append_sampler_name(tex->sampler_name);
- info.sampler(0, ImageType::FLOAT_1D_ARRAY, name, Frequency::BATCH);
+ info.sampler(slot++, ImageType::FLOAT_1D_ARRAY, name, Frequency::BATCH);
}
else if (tex->tiled_mapping_name[0] != '\0') {
const char *name = info.name_buffer.append_sampler_name(tex->sampler_name);
- info.sampler(0, ImageType::FLOAT_2D_ARRAY, name, Frequency::BATCH);
+ info.sampler(slot++, ImageType::FLOAT_2D_ARRAY, name, Frequency::BATCH);
const char *name_mapping = info.name_buffer.append_sampler_name(tex->tiled_mapping_name);
- info.sampler(0, ImageType::FLOAT_1D_ARRAY, name_mapping, Frequency::BATCH);
+ info.sampler(slot++, ImageType::FLOAT_1D_ARRAY, name_mapping, Frequency::BATCH);
}
else {
const char *name = info.name_buffer.append_sampler_name(tex->sampler_name);
- info.sampler(0, ImageType::FLOAT_2D, name, Frequency::BATCH);
+ info.sampler(slot++, ImageType::FLOAT_2D, name, Frequency::BATCH);
}
}
@@ -382,7 +403,7 @@ void GPUCodegen::generate_resources()
}
ss << "};\n\n";
- info.uniform_buf(0, "NodeTree", GPU_UBO_BLOCK_NAME, Frequency::BATCH);
+ info.uniform_buf(1, "NodeTree", GPU_UBO_BLOCK_NAME, Frequency::BATCH);
}
if (!BLI_listbase_is_empty(&graph.uniform_attrs.list)) {
@@ -394,7 +415,7 @@ void GPUCodegen::generate_resources()
/* TODO(fclem): Use the macro for length. Currently not working for EEVEE. */
/* DRW_RESOURCE_CHUNK_LEN = 512 */
- info.uniform_buf(0, "UniformAttrs", GPU_ATTRIBUTE_UBO_BLOCK_NAME "[512]", Frequency::BATCH);
+ info.uniform_buf(2, "UniformAttrs", GPU_ATTRIBUTE_UBO_BLOCK_NAME "[512]", Frequency::BATCH);
}
info.typedef_source_generated = ss.str();
@@ -501,6 +522,19 @@ char *GPUCodegen::graph_serialize(eGPUNodeTag tree_tag, GPUNodeLink *output_link
return eval_c_str;
}
+char *GPUCodegen::graph_serialize(eGPUNodeTag tree_tag)
+{
+ std::stringstream eval_ss;
+ LISTBASE_FOREACH (GPUNode *, node, &graph.nodes) {
+ if (node->tag & tree_tag) {
+ node_serialize(eval_ss, node);
+ }
+ }
+ char *eval_c_str = extract_c_str(eval_ss);
+ BLI_hash_mm2a_add(&hm2a_, (uchar *)eval_c_str, eval_ss.str().size());
+ return eval_c_str;
+}
+
void GPUCodegen::generate_uniform_buffer()
{
/* Extract uniform inputs. */
@@ -540,6 +574,9 @@ void GPUCodegen::generate_graphs()
output.volume = graph_serialize(GPU_NODE_TAG_VOLUME, graph.outlink_volume);
output.displacement = graph_serialize(GPU_NODE_TAG_DISPLACEMENT, graph.outlink_displacement);
output.thickness = graph_serialize(GPU_NODE_TAG_THICKNESS, graph.outlink_thickness);
+ if (!BLI_listbase_is_empty(&graph.outlink_compositor)) {
+ output.composite = graph_serialize(GPU_NODE_TAG_COMPOSITOR);
+ }
if (!BLI_listbase_is_empty(&graph.material_functions)) {
std::stringstream eval_ss;
@@ -570,9 +607,10 @@ GPUPass *GPU_generate_pass(GPUMaterial *material,
GPUCodegenCallbackFn finalize_source_cb,
void *thunk)
{
- /* Prune the unused nodes and extract attributes before compiling so the
- * generated VBOs are ready to accept the future shader. */
gpu_node_graph_prune_unused(graph);
+
+ /* Extract attributes before compiling so the generated VBOs are ready to accept the future
+ * shader. */
gpu_node_graph_finalize_uniform_attrs(graph);
GPUCodegen codegen(material, graph);
diff --git a/source/blender/gpu/intern/gpu_compute.cc b/source/blender/gpu/intern/gpu_compute.cc
index b45cf8211cb..277f6d22280 100644
--- a/source/blender/gpu/intern/gpu_compute.cc
+++ b/source/blender/gpu/intern/gpu_compute.cc
@@ -7,7 +7,6 @@
#include "GPU_compute.h"
#include "gpu_backend.hh"
-#include "gpu_storage_buffer_private.hh"
void GPU_compute_dispatch(GPUShader *shader,
uint groups_x_len,
diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc
index c6eaf7defdc..bcc418169b7 100644
--- a/source/blender/gpu/intern/gpu_context.cc
+++ b/source/blender/gpu/intern/gpu_context.cc
@@ -23,12 +23,11 @@
#include "GPU_context.h"
#include "GPU_framebuffer.h"
-#include "GHOST_C-api.h"
-
#include "gpu_backend.hh"
#include "gpu_batch_private.hh"
#include "gpu_context_private.hh"
#include "gpu_matrix_private.h"
+#include "gpu_private.h"
#ifdef WITH_OPENGL_BACKEND
# include "gl_backend.hh"
@@ -45,17 +44,27 @@ using namespace blender::gpu;
static thread_local Context *active_ctx = nullptr;
+static std::mutex backend_users_mutex;
+static int num_backend_users = 0;
+
+static void gpu_backend_create();
+static void gpu_backend_discard();
+
/* -------------------------------------------------------------------- */
/** \name gpu::Context methods
* \{ */
namespace blender::gpu {
+int Context::context_counter = 0;
Context::Context()
{
thread_ = pthread_self();
is_active_ = false;
matrix_state = GPU_matrix_state_create();
+
+ context_id = Context::context_counter;
+ Context::context_counter++;
}
Context::~Context()
@@ -87,9 +96,13 @@ Context *Context::get()
GPUContext *GPU_context_create(void *ghost_window)
{
- if (GPUBackend::get() == nullptr) {
- /* TODO: move where it make sense. */
- GPU_backend_init(GPU_BACKEND_OPENGL);
+ {
+ std::scoped_lock lock(backend_users_mutex);
+ if (num_backend_users == 0) {
+ /* Automatically create backend when first context is created. */
+ gpu_backend_create();
+ }
+ num_backend_users++;
}
Context *ctx = GPUBackend::get()->context_alloc(ghost_window);
@@ -103,6 +116,16 @@ void GPU_context_discard(GPUContext *ctx_)
Context *ctx = unwrap(ctx_);
delete ctx;
active_ctx = nullptr;
+
+ {
+ std::scoped_lock lock(backend_users_mutex);
+ num_backend_users--;
+ BLI_assert(num_backend_users >= 0);
+ if (num_backend_users == 0) {
+ /* Discard backend when last context is discarded. */
+ gpu_backend_discard();
+ }
+ }
}
void GPU_context_active_set(GPUContext *ctx_)
@@ -125,6 +148,22 @@ GPUContext *GPU_context_active_get()
return wrap(Context::get());
}
+void GPU_context_begin_frame(GPUContext *ctx)
+{
+ blender::gpu::Context *_ctx = unwrap(ctx);
+ if (_ctx) {
+ _ctx->begin_frame();
+ }
+}
+
+void GPU_context_end_frame(GPUContext *ctx)
+{
+ blender::gpu::Context *_ctx = unwrap(ctx);
+ if (_ctx) {
+ _ctx->end_frame();
+ }
+}
+
/* -------------------------------------------------------------------- */
/** \name Main context global mutex
*
@@ -177,11 +216,12 @@ void GPU_render_step()
/** \name Backend selection
* \{ */
-static GPUBackend *g_backend;
+static const eGPUBackendType g_backend_type = GPU_BACKEND_OPENGL;
+static GPUBackend *g_backend = nullptr;
-bool GPU_backend_supported(eGPUBackendType type)
+bool GPU_backend_supported(void)
{
- switch (type) {
+ switch (g_backend_type) {
case GPU_BACKEND_OPENGL:
#ifdef WITH_OPENGL_BACKEND
return true;
@@ -200,12 +240,12 @@ bool GPU_backend_supported(eGPUBackendType type)
}
}
-void GPU_backend_init(eGPUBackendType backend_type)
+static void gpu_backend_create()
{
BLI_assert(g_backend == nullptr);
- BLI_assert(GPU_backend_supported(backend_type));
+ BLI_assert(GPU_backend_supported());
- switch (backend_type) {
+ switch (g_backend_type) {
#ifdef WITH_OPENGL_BACKEND
case GPU_BACKEND_OPENGL:
g_backend = new GLBackend;
@@ -222,10 +262,15 @@ void GPU_backend_init(eGPUBackendType backend_type)
}
}
-void GPU_backend_exit()
+void gpu_backend_delete_resources()
+{
+ BLI_assert(g_backend);
+ g_backend->delete_resources();
+}
+
+void gpu_backend_discard()
{
- /* TODO: assert no resource left. Currently UI textures are still not freed in their context
- * correctly. */
+ /* TODO: assert no resource left. */
delete g_backend;
g_backend = nullptr;
}
diff --git a/source/blender/gpu/intern/gpu_context_private.hh b/source/blender/gpu/intern/gpu_context_private.hh
index af9791fde88..2217e5262ed 100644
--- a/source/blender/gpu/intern/gpu_context_private.hh
+++ b/source/blender/gpu/intern/gpu_context_private.hh
@@ -28,11 +28,11 @@ namespace blender::gpu {
class Context {
public:
/** State management */
- Shader *shader = NULL;
- FrameBuffer *active_fb = NULL;
- GPUMatrixState *matrix_state = NULL;
- StateManager *state_manager = NULL;
- Immediate *imm = NULL;
+ Shader *shader = nullptr;
+ FrameBuffer *active_fb = nullptr;
+ GPUMatrixState *matrix_state = nullptr;
+ StateManager *state_manager = nullptr;
+ Immediate *imm = nullptr;
/**
* All 4 window frame-buffers.
@@ -41,18 +41,26 @@ class Context {
* Front frame-buffers contains (in principle, but not always) the last frame color.
* Default frame-buffer is back_left.
*/
- FrameBuffer *back_left = NULL;
- FrameBuffer *front_left = NULL;
- FrameBuffer *back_right = NULL;
- FrameBuffer *front_right = NULL;
+ FrameBuffer *back_left = nullptr;
+ FrameBuffer *front_left = nullptr;
+ FrameBuffer *back_right = nullptr;
+ FrameBuffer *front_right = nullptr;
DebugStack debug_stack;
+ /* GPUContext counter used to assign a unique ID to each GPUContext.
+ * NOTE(Metal): This is required by the Metal Backend, as a bug exists in the global OS shader
+ * cache wherein compilation of identical source from two distinct threads can result in an
+ * invalid cache collision, result in a broken shader object. Appending the unique context ID
+ * onto compiled sources ensures the source hashes are different. */
+ static int context_counter;
+ int context_id = 0;
+
protected:
/** Thread on which this context is active. */
pthread_t thread_;
bool is_active_;
- /** Avoid including GHOST headers. Can be NULL for off-screen contexts. */
+ /** Avoid including GHOST headers. Can be nullptr for off-screen contexts. */
void *ghost_window_;
public:
@@ -63,6 +71,8 @@ class Context {
virtual void activate() = 0;
virtual void deactivate() = 0;
+ virtual void begin_frame() = 0;
+ virtual void end_frame() = 0;
/* Will push all pending commands to the GPU. */
virtual void flush() = 0;
diff --git a/source/blender/gpu/intern/gpu_drawlist.cc b/source/blender/gpu/intern/gpu_drawlist.cc
index b5b8d2f90bc..e1699bd0036 100644
--- a/source/blender/gpu/intern/gpu_drawlist.cc
+++ b/source/blender/gpu/intern/gpu_drawlist.cc
@@ -7,9 +7,6 @@
* Implementation of Multi Draw Indirect.
*/
-#include "MEM_guardedalloc.h"
-
-#include "GPU_batch.h"
#include "GPU_drawlist.h"
#include "gpu_backend.hh"
diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc
index fb3c9549f18..8d93e49d588 100644
--- a/source/blender/gpu/intern/gpu_framebuffer.cc
+++ b/source/blender/gpu/intern/gpu_framebuffer.cc
@@ -7,7 +7,6 @@
#include "MEM_guardedalloc.h"
-#include "BLI_blenlib.h"
#include "BLI_math_base.h"
#include "BLI_utildefines.h"
@@ -18,7 +17,6 @@
#include "gpu_backend.hh"
#include "gpu_context_private.hh"
-#include "gpu_private.h"
#include "gpu_texture_private.hh"
#include "gpu_framebuffer_private.hh"
@@ -126,6 +124,43 @@ void FrameBuffer::attachment_remove(GPUAttachmentType type)
dirty_attachments_ = true;
}
+void FrameBuffer::load_store_config_array(const GPULoadStore *load_store_actions, uint actions_len)
+{
+ /* Follows attachment structure of GPU_framebuffer_config_array/GPU_framebuffer_ensure_config */
+ const GPULoadStore &depth_action = load_store_actions[0];
+ Span<GPULoadStore> color_attachments(load_store_actions + 1, actions_len - 1);
+
+ if (this->attachments_[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex) {
+ this->attachment_set_loadstore_op(
+ GPU_FB_DEPTH_STENCIL_ATTACHMENT, depth_action.load_action, depth_action.store_action);
+ }
+ if (this->attachments_[GPU_FB_DEPTH_ATTACHMENT].tex) {
+ this->attachment_set_loadstore_op(
+ GPU_FB_DEPTH_ATTACHMENT, depth_action.load_action, depth_action.store_action);
+ }
+
+ GPUAttachmentType type = GPU_FB_COLOR_ATTACHMENT0;
+ for (const GPULoadStore &actions : color_attachments) {
+ if (this->attachments_[type].tex) {
+ this->attachment_set_loadstore_op(type, actions.load_action, actions.store_action);
+ }
+ ++type;
+ }
+}
+
+unsigned int FrameBuffer::get_bits_per_pixel()
+{
+ unsigned int total_bits = 0;
+ for (GPUAttachment &attachment : attachments_) {
+ Texture *tex = reinterpret_cast<Texture *>(attachment.tex);
+ if (tex != nullptr) {
+ int bits = to_bytesize(tex->format_get()) * to_component_len(tex->format_get());
+ total_bits += bits;
+ }
+ }
+ return total_bits;
+}
+
void FrameBuffer::recursive_downsample(int max_lvl,
void (*callback)(void *userData, int level),
void *userData)
@@ -151,10 +186,21 @@ void FrameBuffer::recursive_downsample(int max_lvl,
attachment.mip = mip_lvl;
}
}
+
/* Update the internal attachments and viewport size. */
dirty_attachments_ = true;
this->bind(true);
+ /* Optimize load-store state. */
+ GPUAttachmentType type = GPU_FB_DEPTH_ATTACHMENT;
+ for (GPUAttachment &attachment : attachments_) {
+ Texture *tex = reinterpret_cast<Texture *>(attachment.tex);
+ if (tex != nullptr) {
+ this->attachment_set_loadstore_op(type, GPU_LOADACTION_DONT_CARE, GPU_STOREACTION_STORE);
+ }
+ ++type;
+ }
+
callback(userData, mip_lvl);
}
@@ -200,6 +246,18 @@ void GPU_framebuffer_bind(GPUFrameBuffer *gpu_fb)
unwrap(gpu_fb)->bind(enable_srgb);
}
+void GPU_framebuffer_bind_loadstore(GPUFrameBuffer *gpu_fb,
+ const GPULoadStore *load_store_actions,
+ uint actions_len)
+{
+ /* Bind */
+ GPU_framebuffer_bind(gpu_fb);
+
+ /* Update load store */
+ FrameBuffer *fb = unwrap(gpu_fb);
+ fb->load_store_config_array(load_store_actions, actions_len);
+}
+
void GPU_framebuffer_bind_no_srgb(GPUFrameBuffer *gpu_fb)
{
const bool enable_srgb = false;
diff --git a/source/blender/gpu/intern/gpu_framebuffer_private.hh b/source/blender/gpu/intern/gpu_framebuffer_private.hh
index d218662d17f..8cecc6b8b15 100644
--- a/source/blender/gpu/intern/gpu_framebuffer_private.hh
+++ b/source/blender/gpu/intern/gpu_framebuffer_private.hh
@@ -114,6 +114,10 @@ class FrameBuffer {
eGPUDataFormat data_format,
const void *clear_value) = 0;
+ virtual void attachment_set_loadstore_op(GPUAttachmentType type,
+ eGPULoadOp load_action,
+ eGPUStoreOp store_action) = 0;
+
virtual void read(eGPUFrameBufferBits planes,
eGPUDataFormat format,
const int area[4],
@@ -128,12 +132,15 @@ class FrameBuffer {
int dst_offset_x,
int dst_offset_y) = 0;
+ void load_store_config_array(const GPULoadStore *load_store_actions, uint actions_len);
+
void attachment_set(GPUAttachmentType type, const GPUAttachment &new_attachment);
void attachment_remove(GPUAttachmentType type);
void recursive_downsample(int max_lvl,
void (*callback)(void *userData, int level),
void *userData);
+ uint get_bits_per_pixel();
inline void size_set(int width, int height)
{
diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc
index 69467e5b28a..3b4accf9cc5 100644
--- a/source/blender/gpu/intern/gpu_immediate.cc
+++ b/source/blender/gpu/intern/gpu_immediate.cc
@@ -18,7 +18,6 @@
#include "gpu_context_private.hh"
#include "gpu_immediate_private.hh"
#include "gpu_shader_private.hh"
-#include "gpu_vertex_buffer_private.hh"
#include "gpu_vertex_format_private.h"
using namespace blender::gpu;
@@ -132,15 +131,12 @@ static void wide_line_workaround_start(GPUPrimType prim_type)
case GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR:
polyline_sh = GPU_SHADER_3D_POLYLINE_CLIPPED_UNIFORM_COLOR;
break;
- case GPU_SHADER_2D_UNIFORM_COLOR:
case GPU_SHADER_3D_UNIFORM_COLOR:
polyline_sh = GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR;
break;
- case GPU_SHADER_2D_FLAT_COLOR:
case GPU_SHADER_3D_FLAT_COLOR:
polyline_sh = GPU_SHADER_3D_POLYLINE_FLAT_COLOR;
break;
- case GPU_SHADER_2D_SMOOTH_COLOR:
case GPU_SHADER_3D_SMOOTH_COLOR:
polyline_sh = GPU_SHADER_3D_POLYLINE_SMOOTH_COLOR;
break;
diff --git a/source/blender/gpu/intern/gpu_immediate_private.hh b/source/blender/gpu/intern/gpu_immediate_private.hh
index 6c50fa01071..74ebbdc7ae3 100644
--- a/source/blender/gpu/intern/gpu_immediate_private.hh
+++ b/source/blender/gpu/intern/gpu_immediate_private.hh
@@ -19,7 +19,7 @@ namespace blender::gpu {
class Immediate {
public:
/** Pointer to the mapped buffer data for the current vertex. */
- uchar *vertex_data = NULL;
+ uchar *vertex_data = nullptr;
/** Current vertex index. */
uint vertex_idx = 0;
/** Length of the buffer in vertices. */
@@ -32,12 +32,12 @@ class Immediate {
/** Current draw call specification. */
GPUPrimType prim_type = GPU_PRIM_NONE;
GPUVertFormat vertex_format = {};
- GPUShader *shader = NULL;
+ GPUShader *shader = nullptr;
/** Enforce strict vertex count (disabled when using #immBeginAtMost). */
bool strict_vertex_len = true;
/** Batch in construction when using #immBeginBatch. */
- GPUBatch *batch = NULL;
+ GPUBatch *batch = nullptr;
/** Wide Line workaround. */
diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c
index daefd57a5b3..743bc058b45 100644
--- a/source/blender/gpu/intern/gpu_immediate_util.c
+++ b/source/blender/gpu/intern/gpu_immediate_util.c
@@ -13,7 +13,6 @@
#include "BLI_utildefines.h"
#include "GPU_immediate.h"
-#include "GPU_immediate_util.h"
#include "UI_resources.h"
@@ -122,7 +121,7 @@ void immRecti_complete(int x1, int y1, int x2, int y2, const float color[4])
{
GPUVertFormat *format = immVertexFormat();
uint pos = add_attr(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4fv(color);
immRecti(pos, x1, y1, x2, y2);
immUnbindProgram();
@@ -143,7 +142,7 @@ static void imm_draw_circle(GPUPrimType prim_type,
int nsegments)
{
if (prim_type == GPU_PRIM_LINE_LOOP) {
- /* Note(Metal/AMD): For small primitives, line list more efficient than line strip.. */
+ /* NOTE(Metal/AMD): For small primitives, line list more efficient than line strip.. */
immBegin(GPU_PRIM_LINES, nsegments * 2);
immVertex2f(shdr_pos, x + (radius_x * cosf(0.0f)), y + (radius_y * sinf(0.0f)));
@@ -240,9 +239,9 @@ void imm_draw_circle_partial_wire_2d(
}
void imm_draw_circle_partial_wire_3d(
- uint pos, float x, float y, float z, float rad, int nsegments, float start, float sweep)
+ uint pos, float x, float y, float z, float radius, int nsegments, float start, float sweep)
{
- imm_draw_circle_partial_3d(GPU_PRIM_LINE_STRIP, pos, x, y, z, rad, nsegments, start, sweep);
+ imm_draw_circle_partial_3d(GPU_PRIM_LINE_STRIP, pos, x, y, z, radius, nsegments, start, sweep);
}
static void imm_draw_disk_partial(GPUPrimType prim_type,
@@ -334,7 +333,7 @@ static void imm_draw_circle_3D(
GPUPrimType prim_type, uint pos, float x, float y, float radius, int nsegments)
{
if (prim_type == GPU_PRIM_LINE_LOOP) {
- /* Note(Metal/AMD): For small primitives, line list more efficient than line strip. */
+ /* NOTE(Metal/AMD): For small primitives, line list more efficient than line strip. */
immBegin(GPU_PRIM_LINES, nsegments * 2);
const float angle = (float)(2 * M_PI) / (float)nsegments;
@@ -387,7 +386,7 @@ void imm_draw_circle_fill_3d(uint pos, float x, float y, float radius, int nsegm
void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2)
{
- /* Note(Metal/AMD): For small primitives, line list more efficient than line-strip. */
+ /* NOTE(Metal/AMD): For small primitives, line list more efficient than line-strip. */
immBegin(GPU_PRIM_LINES, 8);
immVertex2f(pos, x1, y1);
immVertex2f(pos, x1, y2);
@@ -406,7 +405,7 @@ void imm_draw_box_wire_2d(uint pos, float x1, float y1, float x2, float y2)
void imm_draw_box_wire_3d(uint pos, float x1, float y1, float x2, float y2)
{
/* use this version when GPUVertFormat has a vec3 position */
- /* Note(Metal/AMD): For small primitives, line list more efficient than line-strip. */
+ /* NOTE(Metal/AMD): For small primitives, line list more efficient than line-strip. */
immBegin(GPU_PRIM_LINES, 8);
immVertex3f(pos, x1, y1, 0.0f);
immVertex3f(pos, x1, y2, 0.0f);
diff --git a/source/blender/gpu/intern/gpu_index_buffer.cc b/source/blender/gpu/intern/gpu_index_buffer.cc
index 146461d1dfb..3a66f547403 100644
--- a/source/blender/gpu/intern/gpu_index_buffer.cc
+++ b/source/blender/gpu/intern/gpu_index_buffer.cc
@@ -16,6 +16,8 @@
#include "gpu_index_buffer_private.hh"
+#include "GPU_platform.h"
+
#include <cstring>
#define KEEP_SINGLE_COPY 1
@@ -40,6 +42,28 @@ void GPU_indexbuf_init_ex(GPUIndexBufBuilder *builder,
builder->index_min = UINT32_MAX;
builder->index_max = 0;
builder->prim_type = prim_type;
+
+#ifdef __APPLE__
+ /* Only encode restart indices for restart-compatible primitive types.
+ * Resolves out-of-bounds read error on macOS. Using 0-index will ensure
+ * degenerative primitives when skipping primitives is required and will
+ * incur no additional performance cost for rendering. */
+ if (GPU_type_matches_ex(GPU_DEVICE_ANY, GPU_OS_MAC, GPU_DRIVER_ANY, GPU_BACKEND_METAL)) {
+ /* We will still use restart-indices for point primitives and then
+ * patch these during IndexBuf::init, as we cannot benefit from degenerative
+ * primitives to eliminate these. */
+ builder->restart_index_value = (is_restart_compatible(prim_type) ||
+ prim_type == GPU_PRIM_POINTS) ?
+ RESTART_INDEX :
+ 0;
+ }
+ else {
+ builder->restart_index_value = RESTART_INDEX;
+ }
+#else
+ builder->restart_index_value = RESTART_INDEX;
+#endif
+ builder->uses_restart_indices = false;
builder->data = (uint *)MEM_callocN(builder->max_index_len * sizeof(uint), "GPUIndexBuf data");
}
@@ -94,7 +118,8 @@ void GPU_indexbuf_add_primitive_restart(GPUIndexBufBuilder *builder)
assert(builder->data != nullptr);
assert(builder->index_len < builder->max_index_len);
#endif
- builder->data[builder->index_len++] = RESTART_INDEX;
+ builder->data[builder->index_len++] = builder->restart_index_value;
+ builder->uses_restart_indices = true;
}
void GPU_indexbuf_add_point_vert(GPUIndexBufBuilder *builder, uint v)
@@ -186,8 +211,9 @@ 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;
+ builder->data[elem++] = builder->restart_index_value;
builder->index_len = MAX2(builder->index_len, elem);
+ builder->uses_restart_indices = true;
}
void GPU_indexbuf_set_line_restart(GPUIndexBufBuilder *builder, uint elem)
@@ -195,9 +221,10 @@ void GPU_indexbuf_set_line_restart(GPUIndexBufBuilder *builder, uint elem)
BLI_assert(builder->prim_type == GPU_PRIM_LINES);
BLI_assert((elem + 1) * 2 <= builder->max_index_len);
uint idx = elem * 2;
- builder->data[idx++] = RESTART_INDEX;
- builder->data[idx++] = RESTART_INDEX;
+ builder->data[idx++] = builder->restart_index_value;
+ builder->data[idx++] = builder->restart_index_value;
builder->index_len = MAX2(builder->index_len, idx);
+ builder->uses_restart_indices = true;
}
void GPU_indexbuf_set_tri_restart(GPUIndexBufBuilder *builder, uint elem)
@@ -205,10 +232,11 @@ void GPU_indexbuf_set_tri_restart(GPUIndexBufBuilder *builder, uint elem)
BLI_assert(builder->prim_type == GPU_PRIM_TRIS);
BLI_assert((elem + 1) * 3 <= builder->max_index_len);
uint idx = elem * 3;
- builder->data[idx++] = RESTART_INDEX;
- builder->data[idx++] = RESTART_INDEX;
- builder->data[idx++] = RESTART_INDEX;
+ builder->data[idx++] = builder->restart_index_value;
+ builder->data[idx++] = builder->restart_index_value;
+ builder->data[idx++] = builder->restart_index_value;
builder->index_len = MAX2(builder->index_len, idx);
+ builder->uses_restart_indices = true;
}
/** \} */
@@ -226,7 +254,12 @@ IndexBuf::~IndexBuf()
}
}
-void IndexBuf::init(uint indices_len, uint32_t *indices, uint min_index, uint max_index)
+void IndexBuf::init(uint indices_len,
+ uint32_t *indices,
+ uint min_index,
+ uint max_index,
+ GPUPrimType prim_type,
+ bool uses_restart_indices)
{
is_init_ = true;
data_ = indices;
@@ -234,6 +267,21 @@ void IndexBuf::init(uint indices_len, uint32_t *indices, uint min_index, uint ma
index_len_ = indices_len;
is_empty_ = min_index > max_index;
+ /* Patch index buffer to remove restart indices from
+ * non-restart-compatible primitive types. Restart indices
+ * are situationally added to selectively hide vertices.
+ * Metal does not support restart-indices for non-restart-compatible
+ * types, as such we should remove these indices.
+ *
+ * We only need to perform this for point primitives, as
+ * line primitives/triangle primitives can use index 0 for all
+ * vertices to create a degenerative primitive, where all
+ * vertices share the same index and skip rendering via HW
+ * culling. */
+ if (prim_type == GPU_PRIM_POINTS && uses_restart_indices) {
+ this->strip_restart_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. */
@@ -243,7 +291,18 @@ void IndexBuf::init(uint indices_len, uint32_t *indices, uint min_index, uint ma
if (range <= 0xFFFF) {
index_type_ = GPU_INDEX_U16;
- this->squeeze_indices_short(min_index, max_index);
+ bool do_clamp_indices = false;
+# ifdef __APPLE__
+ /* NOTE: For the Metal Backend, we use degenerative primitives to hide vertices
+ * which are not restart compatible. When this is done, we need to ensure
+ * that compressed index ranges clamp all index values within the valid
+ * range, rather than maximally clamping against the USHORT restart index
+ * value of 0xFFFFu, as this will cause an out-of-bounds read during
+ * vertex assembly. */
+ do_clamp_indices = GPU_type_matches_ex(
+ GPU_DEVICE_ANY, GPU_OS_MAC, GPU_DRIVER_ANY, GPU_BACKEND_METAL);
+# endif
+ this->squeeze_indices_short(min_index, max_index, prim_type, do_clamp_indices);
}
#endif
}
@@ -302,7 +361,10 @@ uint IndexBuf::index_range(uint *r_min, uint *r_max)
return max_value - min_value;
}
-void IndexBuf::squeeze_indices_short(uint min_idx, uint max_idx)
+void IndexBuf::squeeze_indices_short(uint min_idx,
+ uint max_idx,
+ GPUPrimType prim_type,
+ bool clamp_indices_in_range)
{
/* data will never be *larger* than builder->data...
* converting in place to avoid extra allocation */
@@ -311,8 +373,22 @@ void IndexBuf::squeeze_indices_short(uint min_idx, uint max_idx)
if (max_idx >= 0xFFFF) {
index_base_ = min_idx;
+ /* NOTE: When using restart_index=0 for degenerative primitives indices,
+ * the compressed index will go below zero and wrap around when min_idx > 0.
+ * In order to ensure the resulting index is still within range, we instead
+ * clamp index to the maximum within the index range.
+ *
+ * `clamp_max_idx` represents the maximum possible index to clamp against. If primitive is
+ * restart-compatible, we can just clamp against the primitive-restart value, otherwise, we
+ * must assign to a valid index within the range.
+ *
+ * NOTE: For OpenGL we skip this by disabling clamping, as we still need to use
+ * restart index values for point primitives to disable rendering. */
+ uint16_t clamp_max_idx = (is_restart_compatible(prim_type) || !clamp_indices_in_range) ?
+ 0xFFFFu :
+ (max_idx - min_idx);
for (uint i = 0; i < index_len_; i++) {
- ushort_idx[i] = (uint16_t)MIN2(0xFFFF, uint_idx[i] - min_idx);
+ ushort_idx[i] = (uint16_t)MIN2(clamp_max_idx, uint_idx[i] - min_idx);
}
}
else {
@@ -363,7 +439,12 @@ 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, builder->index_min, builder->index_max);
+ unwrap(elem)->init(builder->index_len,
+ builder->data,
+ builder->index_min,
+ builder->index_max,
+ builder->prim_type,
+ builder->uses_restart_indices);
builder->data = nullptr;
}
diff --git a/source/blender/gpu/intern/gpu_index_buffer_private.hh b/source/blender/gpu/intern/gpu_index_buffer_private.hh
index 6ce62ae852e..4099d6641a6 100644
--- a/source/blender/gpu/intern/gpu_index_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_index_buffer_private.hh
@@ -59,7 +59,12 @@ class IndexBuf {
IndexBuf(){};
virtual ~IndexBuf();
- void init(uint indices_len, uint32_t *indices, uint min_index, uint max_index);
+ void init(uint indices_len,
+ uint32_t *indices,
+ uint min_index,
+ uint max_index,
+ GPUPrimType prim_type,
+ bool uses_restart_indices);
void init_subrange(IndexBuf *elem_src, uint start, uint length);
void init_build_on_device(uint index_len);
@@ -70,6 +75,14 @@ class IndexBuf {
* They can lead to graphical glitches on some systems. (See T96892) */
return is_empty_ ? 0 : index_len_;
}
+ uint32_t index_start_get() const
+ {
+ return index_start_;
+ }
+ uint32_t index_base_get() const
+ {
+ return index_base_;
+ }
/* Return size in byte of the drawable data buffer range. Actual buffer size might be bigger. */
size_t size_get() const
{
@@ -91,8 +104,12 @@ class IndexBuf {
virtual void update_sub(uint start, uint len, const void *data) = 0;
private:
- inline void squeeze_indices_short(uint min_idx, uint max_idx);
+ inline void squeeze_indices_short(uint min_idx,
+ uint max_idx,
+ GPUPrimType prim_type,
+ bool clamp_indices_in_range);
inline uint index_range(uint *r_min, uint *r_max);
+ virtual void strip_restart_indices() = 0;
};
/* Syntactic sugar. */
diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c
index e97c9e9c829..34b355eefaf 100644
--- a/source/blender/gpu/intern/gpu_init_exit.c
+++ b/source/blender/gpu/intern/gpu_init_exit.c
@@ -6,15 +6,10 @@
*/
#include "GPU_init_exit.h" /* interface */
-#include "BKE_global.h"
#include "BLI_sys_types.h"
#include "GPU_batch.h"
-#include "GPU_buffers.h"
-#include "GPU_context.h"
-#include "GPU_immediate.h"
#include "intern/gpu_codegen.h"
-#include "intern/gpu_material_library.h"
#include "intern/gpu_private.h"
#include "intern/gpu_shader_create_info_private.hh"
#include "intern/gpu_shader_dependency_private.h"
@@ -60,6 +55,8 @@ void GPU_exit(void)
gpu_shader_dependency_exit();
gpu_shader_create_info_exit();
+ gpu_backend_delete_resources();
+
initialized = false;
}
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 5d6651c3e3a..75066b21e7b 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -19,14 +19,11 @@
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
-#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_node.h"
-#include "BKE_scene.h"
-#include "BKE_world.h"
#include "NOD_shader.h"
@@ -94,6 +91,8 @@ struct GPUMaterial {
#ifndef NDEBUG
char name[64];
+#else
+ char name[16];
#endif
};
@@ -144,7 +143,7 @@ static void gpu_material_ramp_texture_build(GPUMaterial *mat)
mat->coba_builder = NULL;
}
-static void gpu_material_free_single(GPUMaterial *material)
+void GPU_material_free_single(GPUMaterial *material)
{
bool do_free = atomic_sub_and_fetch_uint32(&material->refcount, 1) == 0;
if (!do_free) {
@@ -176,7 +175,7 @@ void GPU_material_free(ListBase *gpumaterial)
LISTBASE_FOREACH (LinkData *, link, gpumaterial) {
GPUMaterial *material = link->data;
DRW_deferred_shader_remove(material);
- gpu_material_free_single(material);
+ GPU_material_free_single(material);
}
BLI_freelistN(gpumaterial);
}
@@ -196,6 +195,11 @@ GPUShader *GPU_material_get_shader(GPUMaterial *material)
return material->pass ? GPU_pass_shader_get(material->pass) : NULL;
}
+const char *GPU_material_get_name(GPUMaterial *material)
+{
+ return material->name;
+}
+
Material *GPU_material_get_material(GPUMaterial *material)
{
return material->ma;
@@ -208,12 +212,7 @@ GPUUniformBuf *GPU_material_uniform_buffer_get(GPUMaterial *material)
void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs)
{
-#ifndef NDEBUG
- const char *name = material->name;
-#else
- const char *name = "Material";
-#endif
- material->ubo = GPU_uniformbuf_create_from_list(inputs, name);
+ material->ubo = GPU_uniformbuf_create_from_list(inputs, material->name);
}
ListBase GPU_material_attributes(GPUMaterial *material)
@@ -226,9 +225,9 @@ ListBase GPU_material_textures(GPUMaterial *material)
return material->graph.textures;
}
-GPUUniformAttrList *GPU_material_uniform_attributes(GPUMaterial *material)
+const GPUUniformAttrList *GPU_material_uniform_attributes(const GPUMaterial *material)
{
- GPUUniformAttrList *attrs = &material->graph.uniform_attrs;
+ const GPUUniformAttrList *attrs = &material->graph.uniform_attrs;
return attrs->count > 0 ? attrs : NULL;
}
@@ -541,6 +540,13 @@ void GPU_material_add_output_link_aov(GPUMaterial *material, GPUNodeLink *link,
BLI_addtail(&material->graph.outlink_aovs, aov_link);
}
+void GPU_material_add_output_link_composite(GPUMaterial *material, GPUNodeLink *link)
+{
+ GPUNodeGraphOutputLink *compositor_link = MEM_callocN(sizeof(GPUNodeGraphOutputLink), __func__);
+ compositor_link->outlink = link;
+ BLI_addtail(&material->graph.outlink_compositor, compositor_link);
+}
+
char *GPU_material_split_sub_function(GPUMaterial *material,
eGPUType return_type,
GPUNodeLink **link)
@@ -668,11 +674,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene,
mat->graph.used_libraries = BLI_gset_new(
BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUNodeGraph.used_libraries");
mat->refcount = 1;
-#ifndef NDEBUG
STRNCPY(mat->name, name);
-#else
- UNUSED_VARS(name);
-#endif
if (is_lookdev) {
mat->flag |= GPU_MATFLAG_LOOKDEV_HACK;
}
@@ -724,7 +726,7 @@ void GPU_material_acquire(GPUMaterial *mat)
void GPU_material_release(GPUMaterial *mat)
{
- gpu_material_free_single(mat);
+ GPU_material_free_single(mat);
}
void GPU_material_compile(GPUMaterial *mat)
@@ -775,3 +777,42 @@ void GPU_materials_free(Main *bmain)
// BKE_world_defaults_free_gpu();
BKE_material_defaults_free_gpu();
}
+
+GPUMaterial *GPU_material_from_callbacks(ConstructGPUMaterialFn construct_function_cb,
+ GPUCodegenCallbackFn generate_code_function_cb,
+ void *thunk)
+{
+ /* Allocate a new material and its material graph, and initialize its reference count. */
+ GPUMaterial *material = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial");
+ material->graph.used_libraries = BLI_gset_new(
+ BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "GPUNodeGraph.used_libraries");
+ material->refcount = 1;
+
+ /* Construct the material graph by adding and linking the necessary GPU material nodes. */
+ construct_function_cb(thunk, material);
+
+ /* Create and initialize the texture storing color bands used by Ramp and Curve nodes. */
+ gpu_material_ramp_texture_build(material);
+
+ /* Lookup an existing pass in the cache or generate a new one. */
+ material->pass = GPU_generate_pass(material, &material->graph, generate_code_function_cb, thunk);
+
+ /* The pass already exists in the pass cache but its shader already failed to compile. */
+ if (material->pass == NULL) {
+ material->status = GPU_MAT_FAILED;
+ gpu_node_graph_free(&material->graph);
+ return material;
+ }
+
+ /* The pass already exists in the pass cache and its shader is already compiled. */
+ GPUShader *shader = GPU_pass_shader_get(material->pass);
+ if (shader != NULL) {
+ material->status = GPU_MAT_SUCCESS;
+ gpu_node_graph_free_nodes(&material->graph);
+ return material;
+ }
+
+ /* The material was created successfully but still needs to be compiled. */
+ material->status = GPU_MAT_CREATED;
+ return material;
+}
diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c
index 3c6a03c56d3..f82af7538b5 100644
--- a/source/blender/gpu/intern/gpu_node_graph.c
+++ b/source/blender/gpu/intern/gpu_node_graph.c
@@ -75,9 +75,26 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType
if (STR_ELEM(name, "set_value", "set_rgb", "set_rgba") && (input->type == type)) {
input = MEM_dupallocN(outnode->inputs.first);
+
+ switch (input->source) {
+ case GPU_SOURCE_ATTR:
+ input->attr->users++;
+ break;
+ case GPU_SOURCE_UNIFORM_ATTR:
+ input->uniform_attr->users++;
+ break;
+ case GPU_SOURCE_TEX:
+ case GPU_SOURCE_TEX_TILED_MAPPING:
+ input->texture->users++;
+ break;
+ default:
+ break;
+ }
+
if (input->link) {
input->link->users++;
}
+
BLI_addtail(&node->inputs, input);
return;
}
@@ -162,7 +179,7 @@ static const char *gpu_uniform_set_function_from_type(eNodeSocketDatatype type)
* This is called for the input/output sockets that are not connected.
*/
static GPUNodeLink *gpu_uniformbuffer_link(GPUMaterial *mat,
- bNode *node,
+ const bNode *node,
GPUNodeStack *stack,
const int index,
const eNodeSocketInOut in_out)
@@ -179,39 +196,25 @@ static GPUNodeLink *gpu_uniformbuffer_link(GPUMaterial *mat,
BLI_assert(socket != NULL);
BLI_assert(socket->in_out == in_out);
- if ((socket->flag & SOCK_HIDE_VALUE) == 0) {
- GPUNodeLink *link;
- switch (socket->type) {
- case SOCK_FLOAT: {
- bNodeSocketValueFloat *socket_data = socket->default_value;
- link = GPU_uniform(&socket_data->value);
- break;
- }
- case SOCK_VECTOR: {
- bNodeSocketValueVector *socket_data = socket->default_value;
- link = GPU_uniform(socket_data->value);
- break;
- }
- case SOCK_RGBA: {
- bNodeSocketValueRGBA *socket_data = socket->default_value;
- link = GPU_uniform(socket_data->value);
- break;
- }
- default:
- return NULL;
- break;
- }
+ if (socket->flag & SOCK_HIDE_VALUE) {
+ return NULL;
+ }
- if (in_out == SOCK_IN) {
- GPU_link(mat, gpu_uniform_set_function_from_type(socket->type), link, &stack->link);
- }
- return link;
+ if (!ELEM(socket->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA)) {
+ return NULL;
}
- return NULL;
+
+ GPUNodeLink *link = GPU_uniform(stack->vec);
+
+ if (in_out == SOCK_IN) {
+ GPU_link(mat, gpu_uniform_set_function_from_type(socket->type), link, &stack->link);
+ }
+
+ return link;
}
static void gpu_node_input_socket(
- GPUMaterial *material, bNode *bnode, GPUNode *node, GPUNodeStack *sock, const int index)
+ GPUMaterial *material, const bNode *bnode, GPUNode *node, GPUNodeStack *sock, const int index)
{
if (sock->link) {
gpu_node_input_link(node, sock->link, sock->type);
@@ -289,7 +292,7 @@ struct GHash *GPU_uniform_attr_list_hash_new(const char *info)
return BLI_ghash_new(uniform_attr_list_hash, uniform_attr_list_cmp, info);
}
-void GPU_uniform_attr_list_copy(GPUUniformAttrList *dest, GPUUniformAttrList *src)
+void GPU_uniform_attr_list_copy(GPUUniformAttrList *dest, const GPUUniformAttrList *src)
{
dest->count = src->count;
dest->hash_code = src->hash_code;
@@ -317,24 +320,20 @@ void gpu_node_graph_finalize_uniform_attrs(GPUNodeGraph *graph)
LISTBASE_FOREACH (GPUUniformAttr *, attr, &attrs->list) {
attr->id = next_id++;
-
- attrs->hash_code ^= BLI_ghashutil_strhash_p(attr->name);
-
- if (attr->use_dupli) {
- attrs->hash_code ^= BLI_ghashutil_uinthash(attr->id);
- }
+ attrs->hash_code ^= BLI_ghashutil_uinthash(attr->hash_code + (1 << (attr->id + 1)));
}
}
/* Attributes and Textures */
-static char attr_prefix_get(eCustomDataType type)
+static char attr_prefix_get(GPUMaterialAttribute *attr)
{
- switch (type) {
+ if (attr->is_default_color) {
+ return 'c';
+ }
+ switch (attr->type) {
case CD_TANGENT:
return 't';
- case CD_MCOL:
- return 'c';
case CD_AUTO_FROM_NAME:
return 'a';
case CD_HAIRLENGTH:
@@ -353,7 +352,7 @@ static void attr_input_name(GPUMaterialAttribute *attr)
STRNCPY(attr->input_name, "orco");
}
else {
- attr->input_name[0] = attr_prefix_get(attr->type);
+ attr->input_name[0] = attr_prefix_get(attr);
attr->input_name[1] = '\0';
if (attr->name[0] != '\0') {
/* XXX FIXME: see notes in mesh_render_data_create() */
@@ -365,21 +364,24 @@ static void attr_input_name(GPUMaterialAttribute *attr)
/** Add a new varying attribute of given type and name. Returns NULL if out of slots. */
static GPUMaterialAttribute *gpu_node_graph_add_attribute(GPUNodeGraph *graph,
eCustomDataType type,
- const char *name)
+ const char *name,
+ const bool is_default_color)
{
/* Find existing attribute. */
int num_attributes = 0;
GPUMaterialAttribute *attr = graph->attributes.first;
for (; attr; attr = attr->next) {
- if (attr->type == type && STREQ(attr->name, name)) {
+ if (attr->type == type && STREQ(attr->name, name) &&
+ attr->is_default_color == is_default_color) {
break;
}
num_attributes++;
}
/* Add new requested attribute if it's within GPU limits. */
- if (attr == NULL && num_attributes < GPU_MAX_ATTR) {
+ if (attr == NULL) {
attr = MEM_callocN(sizeof(*attr), __func__);
+ attr->is_default_color = is_default_color;
attr->type = type;
STRNCPY(attr->name, name);
attr_input_name(attr);
@@ -413,7 +415,13 @@ static GPUUniformAttr *gpu_node_graph_add_uniform_attribute(GPUNodeGraph *graph,
if (attr == NULL && attrs->count < GPU_MAX_UNIFORM_ATTR) {
attr = MEM_callocN(sizeof(*attr), __func__);
STRNCPY(attr->name, name);
+ {
+ char attr_name_esc[sizeof(attr->name) * 2];
+ BLI_str_escape(attr_name_esc, attr->name, sizeof(attr_name_esc));
+ SNPRINTF(attr->name_id_prop, "[\"%s\"]", attr_name_esc);
+ }
attr->use_dupli = use_dupli;
+ attr->hash_code = BLI_ghashutil_strhash_p(attr->name) << 1 | (attr->use_dupli ? 0 : 1);
attr->id = -1;
BLI_addtail(&attrs->list, attr);
attrs->count++;
@@ -471,7 +479,7 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph,
GPUNodeLink *GPU_attribute(GPUMaterial *mat, const eCustomDataType type, const char *name)
{
GPUNodeGraph *graph = gpu_material_node_graph(mat);
- GPUMaterialAttribute *attr = gpu_node_graph_add_attribute(graph, type, name);
+ GPUMaterialAttribute *attr = gpu_node_graph_add_attribute(graph, type, name, false);
if (type == CD_ORCO) {
/* OPTI: orco might be computed from local positions and needs object infos. */
@@ -490,6 +498,21 @@ GPUNodeLink *GPU_attribute(GPUMaterial *mat, const eCustomDataType type, const c
return link;
}
+GPUNodeLink *GPU_attribute_default_color(GPUMaterial *mat)
+{
+ GPUNodeGraph *graph = gpu_material_node_graph(mat);
+ GPUMaterialAttribute *attr = gpu_node_graph_add_attribute(graph, CD_AUTO_FROM_NAME, "", true);
+ if (attr == NULL) {
+ static const float zero_data[GPU_MAX_CONSTANT_DATA] = {0.0f};
+ return GPU_constant(zero_data);
+ }
+ attr->is_default_color = true;
+ GPUNodeLink *link = gpu_node_link_create();
+ link->link_type = GPU_NODE_LINK_ATTR;
+ link->attr = attr;
+ return link;
+}
+
GPUNodeLink *GPU_attribute_with_default(GPUMaterial *mat,
const eCustomDataType type,
const char *name,
@@ -502,16 +525,21 @@ GPUNodeLink *GPU_attribute_with_default(GPUMaterial *mat,
return link;
}
-GPUNodeLink *GPU_uniform_attribute(GPUMaterial *mat, const char *name, bool use_dupli)
+GPUNodeLink *GPU_uniform_attribute(GPUMaterial *mat,
+ const char *name,
+ bool use_dupli,
+ uint32_t *r_hash)
{
GPUNodeGraph *graph = gpu_material_node_graph(mat);
GPUUniformAttr *attr = gpu_node_graph_add_uniform_attribute(graph, name, use_dupli);
/* Dummy fallback if out of slots. */
if (attr == NULL) {
+ *r_hash = 0;
static const float zero_data[GPU_MAX_CONSTANT_DATA] = {0.0f};
return GPU_constant(zero_data);
}
+ *r_hash = attr->hash_code;
GPUNodeLink *link = gpu_node_link_create();
link->link_type = GPU_NODE_LINK_UNIFORM_ATTR;
@@ -630,7 +658,7 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...)
}
static bool gpu_stack_link_v(GPUMaterial *material,
- bNode *bnode,
+ const bNode *bnode,
const char *name,
GPUNodeStack *in,
GPUNodeStack *out,
@@ -702,7 +730,7 @@ static bool gpu_stack_link_v(GPUMaterial *material,
}
bool GPU_stack_link(GPUMaterial *material,
- bNode *bnode,
+ const bNode *bnode,
const char *name,
GPUNodeStack *in,
GPUNodeStack *out,
@@ -716,14 +744,6 @@ bool GPU_stack_link(GPUMaterial *material,
return valid;
}
-GPUNodeLink *GPU_uniformbuf_link_out(GPUMaterial *mat,
- bNode *node,
- GPUNodeStack *stack,
- const int index)
-{
- return gpu_uniformbuffer_link(mat, node, stack, index, SOCK_OUT);
-}
-
/* Node Graph */
static void gpu_inputs_free(ListBase *inputs)
@@ -784,6 +804,7 @@ void gpu_node_graph_free(GPUNodeGraph *graph)
{
BLI_freelistN(&graph->outlink_aovs);
BLI_freelistN(&graph->material_functions);
+ BLI_freelistN(&graph->outlink_compositor);
gpu_node_graph_free_nodes(graph);
BLI_freelistN(&graph->textures);
@@ -836,6 +857,9 @@ void gpu_node_graph_prune_unused(GPUNodeGraph *graph)
LISTBASE_FOREACH (GPUNodeGraphFunctionLink *, funclink, &graph->material_functions) {
gpu_nodes_tag(funclink->outlink, GPU_NODE_TAG_FUNCTION);
}
+ LISTBASE_FOREACH (GPUNodeGraphOutputLink *, compositor_link, &graph->outlink_compositor) {
+ gpu_nodes_tag(compositor_link->outlink, GPU_NODE_TAG_COMPOSITOR);
+ }
for (GPUNode *node = graph->nodes.first, *next = NULL; node; node = next) {
next = node->next;
diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h
index ae472d5b7aa..08ff8bbef58 100644
--- a/source/blender/gpu/intern/gpu_node_graph.h
+++ b/source/blender/gpu/intern/gpu_node_graph.h
@@ -59,6 +59,7 @@ typedef enum {
GPU_NODE_TAG_THICKNESS = (1 << 3),
GPU_NODE_TAG_AOV = (1 << 4),
GPU_NODE_TAG_FUNCTION = (1 << 5),
+ GPU_NODE_TAG_COMPOSITOR = (1 << 6),
} eGPUNodeTag;
ENUM_OPERATORS(eGPUNodeTag, GPU_NODE_TAG_FUNCTION)
@@ -158,6 +159,8 @@ typedef struct GPUNodeGraph {
ListBase outlink_aovs;
/* List of GPUNodeGraphFunctionLink */
ListBase material_functions;
+ /* List of GPUNodeGraphOutputLink */
+ ListBase outlink_compositor;
/* Requested attributes and textures. */
ListBase attributes;
diff --git a/source/blender/gpu/intern/gpu_platform.cc b/source/blender/gpu/intern/gpu_platform.cc
index d108dd468a0..f8e2c0fe6fc 100644
--- a/source/blender/gpu/intern/gpu_platform.cc
+++ b/source/blender/gpu/intern/gpu_platform.cc
@@ -79,11 +79,15 @@ void GPUPlatformGlobal::init(eGPUDeviceType gpu_device,
this->driver = driver_type;
this->support_level = gpu_support_level;
- this->vendor = BLI_strdup(vendor_str);
- this->renderer = BLI_strdup(renderer_str);
- this->version = BLI_strdup(version_str);
- this->support_key = create_key(gpu_support_level, vendor_str, renderer_str, version_str);
- this->gpu_name = create_gpu_name(vendor_str, renderer_str, version_str);
+ const char *vendor = vendor_str ? vendor_str : "UNKNOWN";
+ const char *renderer = renderer_str ? renderer_str : "UNKNOWN";
+ const char *version = version_str ? version_str : "UNKNOWN";
+
+ this->vendor = BLI_strdup(vendor);
+ this->renderer = BLI_strdup(renderer);
+ this->version = BLI_strdup(version);
+ this->support_key = create_key(gpu_support_level, vendor, renderer, version);
+ this->gpu_name = create_gpu_name(vendor, renderer, version);
this->backend = backend;
}
diff --git a/source/blender/gpu/intern/gpu_private.h b/source/blender/gpu/intern/gpu_private.h
index a8ee5187d98..0e293302086 100644
--- a/source/blender/gpu/intern/gpu_private.h
+++ b/source/blender/gpu/intern/gpu_private.h
@@ -10,6 +10,10 @@
extern "C" {
#endif
+/* gpu_backend.cc */
+
+void gpu_backend_delete_resources(void);
+
/* gpu_pbvh.c */
void gpu_pbvh_init(void);
diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c
index ac33c5d5ca8..7afba20c2d9 100644
--- a/source/blender/gpu/intern/gpu_select.c
+++ b/source/blender/gpu/intern/gpu_select.c
@@ -12,12 +12,8 @@
#include "GPU_select.h"
-#include "MEM_guardedalloc.h"
-
#include "BLI_rect.h"
-#include "DNA_userdef_types.h"
-
#include "BLI_utildefines.h"
#include "gpu_select_private.h"
diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c
index 840201c8c97..b5b2d7fa1a5 100644
--- a/source/blender/gpu/intern/gpu_select_pick.c
+++ b/source/blender/gpu/intern/gpu_select_pick.c
@@ -13,7 +13,6 @@
#include "GPU_debug.h"
#include "GPU_framebuffer.h"
-#include "GPU_immediate.h"
#include "GPU_select.h"
#include "GPU_state.h"
diff --git a/source/blender/gpu/intern/gpu_select_sample_query.cc b/source/blender/gpu/intern/gpu_select_sample_query.cc
index 26c9ed79d6c..7393dfd0d81 100644
--- a/source/blender/gpu/intern/gpu_select_sample_query.cc
+++ b/source/blender/gpu/intern/gpu_select_sample_query.cc
@@ -19,7 +19,6 @@
#include "BLI_rect.h"
-#include "BLI_bitmap.h"
#include "BLI_utildefines.h"
#include "BLI_vector.hh"
diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc
index fe9aacb95f9..4d059ae495e 100644
--- a/source/blender/gpu/intern/gpu_shader.cc
+++ b/source/blender/gpu/intern/gpu_shader.cc
@@ -7,6 +7,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_math_matrix.h"
#include "BLI_string_utils.h"
#include "GPU_capabilities.h"
@@ -94,6 +95,9 @@ static void standard_defines(Vector<const char *> &sources)
case GPU_BACKEND_OPENGL:
sources.append("#define GPU_OPENGL\n");
break;
+ case GPU_BACKEND_METAL:
+ sources.append("#define GPU_METAL\n");
+ break;
default:
BLI_assert(false && "Invalid GPU Backend Type");
break;
@@ -382,6 +386,8 @@ GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info)
sources.append(resources.c_str());
sources.append(layout.c_str());
sources.extend(code);
+ sources.extend(info.dependencies_generated);
+ sources.append(info.compute_source_generated.c_str());
shader->compute_shader_from_glsl(sources);
}
@@ -575,6 +581,12 @@ int GPU_shader_get_builtin_block(GPUShader *shader, int builtin)
return interface->ubo_builtin((GPUUniformBlockBuiltin)builtin);
}
+int GPU_shader_get_builtin_ssbo(GPUShader *shader, int builtin)
+{
+ ShaderInterface *interface = unwrap(shader)->interface;
+ return interface->ssbo_builtin((GPUStorageBufferBuiltin)builtin);
+}
+
int GPU_shader_get_ssbo(GPUShader *shader, const char *name)
{
ShaderInterface *interface = unwrap(shader)->interface;
@@ -603,6 +615,12 @@ int GPU_shader_get_texture_binding(GPUShader *shader, const char *name)
return tex ? tex->binding : -1;
}
+uint GPU_shader_get_attribute_len(const GPUShader *shader)
+{
+ ShaderInterface *interface = unwrap(shader)->interface;
+ return interface->attr_len_;
+}
+
int GPU_shader_get_attribute(GPUShader *shader, const char *name)
{
ShaderInterface *interface = unwrap(shader)->interface;
@@ -610,6 +628,23 @@ int GPU_shader_get_attribute(GPUShader *shader, const char *name)
return attr ? attr->location : -1;
}
+bool GPU_shader_get_attribute_info(const GPUShader *shader,
+ int attr_location,
+ char r_name[256],
+ int *r_type)
+{
+ ShaderInterface *interface = unwrap(shader)->interface;
+
+ const ShaderInput *attr = interface->attr_get(attr_location);
+ if (!attr) {
+ return false;
+ }
+
+ BLI_strncpy(r_name, interface->input_name_get(attr), 256);
+ *r_type = attr->location != -1 ? interface->attr_types_[attr->location] : -1;
+ return true;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -702,12 +737,25 @@ void GPU_shader_uniform_4fv(GPUShader *sh, const char *name, const float data[4]
GPU_shader_uniform_vector(sh, loc, 4, 1, data);
}
+void GPU_shader_uniform_2iv(GPUShader *sh, const char *name, const int data[2])
+{
+ const int loc = GPU_shader_get_uniform(sh, name);
+ GPU_shader_uniform_vector_int(sh, loc, 2, 1, data);
+}
+
void GPU_shader_uniform_mat4(GPUShader *sh, const char *name, const float data[4][4])
{
const int loc = GPU_shader_get_uniform(sh, name);
GPU_shader_uniform_vector(sh, loc, 16, 1, (const float *)data);
}
+void GPU_shader_uniform_mat3_as_mat4(GPUShader *sh, const char *name, const float data[3][3])
+{
+ float matrix[4][4];
+ copy_m4_m3(matrix, data);
+ GPU_shader_uniform_mat4(sh, name, matrix);
+}
+
void GPU_shader_uniform_2fv_array(GPUShader *sh, const char *name, int len, const float (*val)[2])
{
const int loc = GPU_shader_get_uniform(sh, name);
diff --git a/source/blender/gpu/intern/gpu_shader_builder.cc b/source/blender/gpu/intern/gpu_shader_builder.cc
index fc99b892554..9b699c60126 100644
--- a/source/blender/gpu/intern/gpu_shader_builder.cc
+++ b/source/blender/gpu/intern/gpu_shader_builder.cc
@@ -51,7 +51,6 @@ void ShaderBuilder::init()
void ShaderBuilder::exit()
{
- GPU_backend_exit();
GPU_exit();
GPU_context_discard(gpu_context_);
diff --git a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc
index 515f65adb73..e15054bd045 100644
--- a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc
+++ b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc
@@ -12,6 +12,7 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "BKE_attribute.h"
#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_material.h"
@@ -101,10 +102,42 @@ void UI_GetThemeColorShadeAlpha4ubv(int UNUSED(colorid),
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Stubs of BKE_attribute.h
+ * \{ */
+
+void BKE_id_attribute_copy_domains_temp(short UNUSED(id_type),
+ const struct CustomData *UNUSED(vdata),
+ const struct CustomData *UNUSED(edata),
+ const struct CustomData *UNUSED(ldata),
+ const struct CustomData *UNUSED(pdata),
+ const struct CustomData *UNUSED(cdata),
+ struct ID *UNUSED(r_id))
+{
+}
+
+struct CustomDataLayer *BKE_id_attributes_active_color_get(const struct ID *UNUSED(id))
+{
+ return nullptr;
+}
+
+struct CustomDataLayer *BKE_id_attributes_render_color_get(const struct ID *UNUSED(id))
+{
+ return nullptr;
+}
+
+eAttrDomain BKE_id_attribute_domain(const struct ID *UNUSED(id),
+ const struct CustomDataLayer *UNUSED(layer))
+{
+ return ATTR_DOMAIN_AUTO;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Stubs of BKE_paint.h
* \{ */
bool paint_is_face_hidden(const struct MLoopTri *UNUSED(lt),
- const struct MVert *UNUSED(mvert),
+ const bool *UNUSED(hide_vert),
const struct MLoop *UNUSED(mloop))
{
BLI_assert_unreachable();
@@ -170,6 +203,40 @@ int CustomData_get_offset(const struct CustomData *UNUSED(data), int UNUSED(type
return 0;
}
+int CustomData_get_named_layer_index(const struct CustomData *UNUSED(data),
+ int UNUSED(type),
+ const char *UNUSED(name))
+{
+ return -1;
+}
+
+int CustomData_get_active_layer_index(const struct CustomData *UNUSED(data), int UNUSED(type))
+{
+ return -1;
+}
+
+int CustomData_get_render_layer_index(const struct CustomData *UNUSED(data), int UNUSED(type))
+{
+ return -1;
+}
+
+bool CustomData_has_layer(const struct CustomData *UNUSED(data), int UNUSED(type))
+{
+ return false;
+}
+
+void *CustomData_get_layer_named(const struct CustomData *UNUSED(data),
+ int UNUSED(type),
+ const char *UNUSED(name))
+{
+ return nullptr;
+}
+
+void *CustomData_get_layer(const struct CustomData *UNUSED(data), int UNUSED(type))
+{
+ return nullptr;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -237,5 +304,14 @@ void DRW_deferred_shader_remove(struct GPUMaterial *UNUSED(mat))
BLI_assert_unreachable();
}
+void DRW_cdlayer_attr_aliases_add(struct GPUVertFormat *UNUSED(format),
+ const char *UNUSED(base_name),
+ const struct CustomData *UNUSED(data),
+ const struct CustomDataLayer *UNUSED(cl),
+ bool UNUSED(is_active_render),
+ bool UNUSED(is_active_layer))
+{
+}
+
/** \} */
}
diff --git a/source/blender/gpu/intern/gpu_shader_builtin.c b/source/blender/gpu/intern/gpu_shader_builtin.c
index b92fae4a89b..8a6586e06f6 100644
--- a/source/blender/gpu/intern/gpu_shader_builtin.c
+++ b/source/blender/gpu/intern/gpu_shader_builtin.c
@@ -5,25 +5,9 @@
* \ingroup gpu
*/
-#include "MEM_guardedalloc.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 "BKE_appdir.h"
-#include "BKE_global.h"
-
-#include "DNA_space_types.h"
-
-#include "GPU_matrix.h"
-#include "GPU_platform.h"
#include "GPU_shader.h"
-#include "GPU_texture.h"
-#include "GPU_uniform_buffer.h"
/* Adjust these constants as needed. */
#define MAX_DEFINE_LENGTH 256
@@ -41,10 +25,7 @@ extern char datatoc_gpu_shader_flat_id_frag_glsl[];
extern char datatoc_gpu_shader_2D_area_borders_vert_glsl[];
extern char datatoc_gpu_shader_2D_area_borders_frag_glsl[];
extern char datatoc_gpu_shader_2D_vert_glsl[];
-extern char datatoc_gpu_shader_2D_flat_color_vert_glsl[];
extern char datatoc_gpu_shader_2D_smooth_color_uniform_alpha_vert_glsl[];
-extern char datatoc_gpu_shader_2D_smooth_color_vert_glsl[];
-extern char datatoc_gpu_shader_2D_smooth_color_frag_glsl[];
extern char datatoc_gpu_shader_2D_image_vert_glsl[];
extern char datatoc_gpu_shader_2D_image_rect_vert_glsl[];
extern char datatoc_gpu_shader_2D_image_multi_rect_vert_glsl[];
@@ -155,10 +136,10 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
.name = "GPU_SHADER_3D_IMAGE",
.create_info = "gpu_shader_3D_image",
},
- [GPU_SHADER_3D_IMAGE_MODULATE_ALPHA] =
+ [GPU_SHADER_3D_IMAGE_COLOR] =
{
- .name = "GPU_SHADER_3D_IMAGE_MODULATE_ALPHA",
- .create_info = "gpu_shader_3D_image_modulate_alpha",
+ .name = "GPU_SHADER_3D_IMAGE_COLOR",
+ .create_info = "gpu_shader_3D_image_color",
},
[GPU_SHADER_2D_CHECKER] =
{
@@ -172,21 +153,6 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
.create_info = "gpu_shader_2D_diag_stripes",
},
- [GPU_SHADER_2D_UNIFORM_COLOR] =
- {
- .name = "GPU_SHADER_2D_UNIFORM_COLOR",
- .create_info = "gpu_shader_2D_uniform_color",
- },
- [GPU_SHADER_2D_FLAT_COLOR] =
- {
- .name = "GPU_SHADER_2D_FLAT_COLOR",
- .create_info = "gpu_shader_2D_flat_color",
- },
- [GPU_SHADER_2D_SMOOTH_COLOR] =
- {
- .name = "GPU_SHADER_2D_SMOOTH_COLOR",
- .create_info = "gpu_shader_2D_smooth_color",
- },
[GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE] =
{
.name = "GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE",
@@ -197,16 +163,6 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
.name = "GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE",
.create_info = "gpu_shader_2D_image_overlays_stereo_merge",
},
- [GPU_SHADER_2D_IMAGE] =
- {
- .name = "GPU_SHADER_2D_IMAGE",
- .create_info = "gpu_shader_2D_image",
- },
- [GPU_SHADER_2D_IMAGE_COLOR] =
- {
- .name = "GPU_SHADER_2D_IMAGE_COLOR",
- .create_info = "gpu_shader_2D_image_color",
- },
[GPU_SHADER_2D_IMAGE_DESATURATE_COLOR] =
{
.name = "GPU_SHADER_2D_IMAGE_DESATURATE_COLOR",
@@ -279,11 +235,6 @@ static const GPUShaderStages builtin_shader_stages[GPU_SHADER_BUILTIN_LEN] = {
.create_info = "gpu_shader_3D_polyline_smooth_color",
},
- [GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR] =
- {
- .name = "GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR",
- .create_info = "gpu_shader_2D_line_dashed_uniform_color",
- },
[GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR] =
{
.name = "GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR",
diff --git a/source/blender/gpu/intern/gpu_shader_create_info.cc b/source/blender/gpu/intern/gpu_shader_create_info.cc
index f5b90989481..a18fdcd32df 100644
--- a/source/blender/gpu/intern/gpu_shader_create_info.cc
+++ b/source/blender/gpu/intern/gpu_shader_create_info.cc
@@ -19,7 +19,6 @@
#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
#undef GPU_SHADER_CREATE_INFO
@@ -155,13 +154,13 @@ std::string ShaderCreateInfo::check_error() const
}
else {
if (!this->vertex_source_.is_empty()) {
- error += "Compute shader has vertex_source_ shader attached in" + this->name_ + ".\n";
+ error += "Compute shader has vertex_source_ shader attached in " + this->name_ + ".\n";
}
if (!this->geometry_source_.is_empty()) {
- error += "Compute shader has geometry_source_ shader attached in" + this->name_ + ".\n";
+ error += "Compute shader has geometry_source_ shader attached in " + this->name_ + ".\n";
}
if (!this->fragment_source_.is_empty()) {
- error += "Compute shader has fragment_source_ shader attached in" + this->name_ + ".\n";
+ error += "Compute shader has fragment_source_ shader attached in " + this->name_ + ".\n";
}
}
@@ -301,12 +300,25 @@ void gpu_shader_create_info_init()
draw_modelmat = draw_modelmat_legacy;
}
+ /* WORKAROUND: Replace the use of gpu_BaseInstance by an instance attribute. */
+ if (GPU_shader_draw_parameters_support() == false) {
+ draw_resource_id_new = draw_resource_id_fallback;
+ }
+
for (ShaderCreateInfo *info : g_create_infos->values()) {
if (info->do_static_compilation_) {
info->builtins_ |= gpu_shader_dependency_get_builtins(info->vertex_source_);
info->builtins_ |= gpu_shader_dependency_get_builtins(info->fragment_source_);
info->builtins_ |= gpu_shader_dependency_get_builtins(info->geometry_source_);
info->builtins_ |= gpu_shader_dependency_get_builtins(info->compute_source_);
+
+ /* Automatically amend the create info for ease of use of the debug feature. */
+ if ((info->builtins_ & BuiltinBits::USE_DEBUG_DRAW) == BuiltinBits::USE_DEBUG_DRAW) {
+ info->additional_info("draw_debug_draw");
+ }
+ if ((info->builtins_ & BuiltinBits::USE_DEBUG_PRINT) == BuiltinBits::USE_DEBUG_PRINT) {
+ info->additional_info("draw_debug_print");
+ }
}
}
@@ -334,8 +346,11 @@ bool gpu_shader_create_info_compile_all()
int skipped = 0;
int total = 0;
for (ShaderCreateInfo *info : g_create_infos->values()) {
+ info->finalize();
if (info->do_static_compilation_) {
- if (GPU_compute_shader_support() == false && info->compute_source_ != nullptr) {
+ if ((GPU_compute_shader_support() == false && info->compute_source_ != nullptr) ||
+ (GPU_shader_image_load_store_support() == false && info->has_resource_image()) ||
+ (GPU_shader_storage_buffer_objects_support() == false && info->has_resource_storage())) {
skipped++;
continue;
}
diff --git a/source/blender/gpu/intern/gpu_shader_create_info.hh b/source/blender/gpu/intern/gpu_shader_create_info.hh
index 4927ef75a75..25a79dd26ac 100644
--- a/source/blender/gpu/intern/gpu_shader_create_info.hh
+++ b/source/blender/gpu/intern/gpu_shader_create_info.hh
@@ -32,6 +32,7 @@ namespace blender::gpu::shader {
#endif
enum class Type {
+ /* Types supported natively across all GPU back-ends. */
FLOAT = 0,
VEC2,
VEC3,
@@ -47,6 +48,21 @@ enum class Type {
IVEC3,
IVEC4,
BOOL,
+ /* Additionally supported types to enable data optimization and native
+ * support in some GPU back-ends.
+ * NOTE: These types must be representable in all APIs. E.g. `VEC3_101010I2` is aliased as vec3
+ * in the GL back-end, as implicit type conversions from packed normal attribute data to vec3 is
+ * supported. UCHAR/CHAR types are natively supported in Metal and can be used to avoid
+ * additional data conversions for `GPU_COMP_U8` vertex attributes. */
+ VEC3_101010I2,
+ UCHAR,
+ UCHAR2,
+ UCHAR3,
+ UCHAR4,
+ CHAR,
+ CHAR2,
+ CHAR3,
+ CHAR4
};
/* All of these functions is a bit out of place */
@@ -86,6 +102,40 @@ static inline std::ostream &operator<<(std::ostream &stream, const Type type)
return stream << "mat3";
case Type::MAT4:
return stream << "mat4";
+ case Type::VEC3_101010I2:
+ return stream << "vec3_1010102_Inorm";
+ case Type::UCHAR:
+ return stream << "uchar";
+ case Type::UCHAR2:
+ return stream << "uchar2";
+ case Type::UCHAR3:
+ return stream << "uchar3";
+ case Type::UCHAR4:
+ return stream << "uchar4";
+ case Type::CHAR:
+ return stream << "char";
+ case Type::CHAR2:
+ return stream << "char2";
+ case Type::CHAR3:
+ return stream << "char3";
+ case Type::CHAR4:
+ return stream << "char4";
+ case Type::INT:
+ return stream << "int";
+ case Type::IVEC2:
+ return stream << "ivec2";
+ case Type::IVEC3:
+ return stream << "ivec3";
+ case Type::IVEC4:
+ return stream << "ivec4";
+ case Type::UINT:
+ return stream << "uint";
+ case Type::UVEC2:
+ return stream << "uvec2";
+ case Type::UVEC3:
+ return stream << "uvec3";
+ case Type::UVEC4:
+ return stream << "uvec4";
default:
BLI_assert(0);
return stream;
@@ -127,8 +177,12 @@ enum class BuiltinBits {
VERTEX_ID = (1 << 14),
WORK_GROUP_ID = (1 << 15),
WORK_GROUP_SIZE = (1 << 16),
+
+ /* Not a builtin but a flag we use to tag shaders that use the debug features. */
+ USE_DEBUG_DRAW = (1 << 29),
+ USE_DEBUG_PRINT = (1 << 30),
};
-ENUM_OPERATORS(BuiltinBits, BuiltinBits::WORK_GROUP_SIZE);
+ENUM_OPERATORS(BuiltinBits, BuiltinBits::USE_DEBUG_PRINT);
/**
* Follow convention described in:
@@ -224,6 +278,8 @@ enum class PrimitiveOut {
POINTS = 0,
LINE_STRIP,
TRIANGLE_STRIP,
+ LINES,
+ TRIANGLES,
};
struct StageInterfaceInfo {
@@ -268,10 +324,10 @@ struct StageInterfaceInfo {
/**
* \brief Describe inputs & outputs, stage interfaces, resources and sources of a shader.
* If all data is correctly provided, this is all that is needed to create and compile
- * a GPUShader.
+ * a #GPUShader.
*
* IMPORTANT: All strings are references only. Make sure all the strings used by a
- * ShaderCreateInfo are not freed until it is consumed or deleted.
+ * #ShaderCreateInfo are not freed until it is consumed or deleted.
*/
struct ShaderCreateInfo {
/** Shader name for debugging. */
@@ -290,7 +346,7 @@ struct ShaderCreateInfo {
DepthWrite depth_write_ = DepthWrite::ANY;
/**
* Maximum length of all the resource names including each null terminator.
- * Only for names used by gpu::ShaderInterface.
+ * Only for names used by #gpu::ShaderInterface.
*/
size_t interface_names_size_ = 0;
/** Manually set builtins. */
@@ -298,6 +354,7 @@ struct ShaderCreateInfo {
/** Manually set generated code. */
std::string vertex_source_generated = "";
std::string fragment_source_generated = "";
+ std::string compute_source_generated = "";
std::string geometry_source_generated = "";
std::string typedef_source_generated = "";
/** Manually set generated dependencies. */
@@ -740,33 +797,16 @@ struct ShaderCreateInfo {
* Used to share parts of the infos that are common to many shaders.
* \{ */
- Self &additional_info(StringRefNull info_name0,
- StringRefNull info_name1 = "",
- StringRefNull info_name2 = "",
- StringRefNull info_name3 = "",
- StringRefNull info_name4 = "",
- StringRefNull info_name5 = "",
- StringRefNull info_name6 = "")
- {
- additional_infos_.append(info_name0);
- if (!info_name1.is_empty()) {
- additional_infos_.append(info_name1);
- }
- if (!info_name2.is_empty()) {
- additional_infos_.append(info_name2);
- }
- if (!info_name3.is_empty()) {
- additional_infos_.append(info_name3);
- }
- if (!info_name4.is_empty()) {
- additional_infos_.append(info_name4);
- }
- if (!info_name5.is_empty()) {
- additional_infos_.append(info_name5);
- }
- if (!info_name6.is_empty()) {
- additional_infos_.append(info_name6);
- }
+ Self &additional_info(StringRefNull info_name)
+ {
+ additional_infos_.append(info_name);
+ return *(Self *)this;
+ }
+
+ template<typename... Args> Self &additional_info(StringRefNull info_name, Args... args)
+ {
+ additional_info(info_name);
+ additional_info(args...);
return *(Self *)this;
}
@@ -818,6 +858,7 @@ struct ShaderCreateInfo {
TEST_EQUAL(*this, b, builtins_);
TEST_EQUAL(*this, b, vertex_source_generated);
TEST_EQUAL(*this, b, fragment_source_generated);
+ TEST_EQUAL(*this, b, compute_source_generated);
TEST_EQUAL(*this, b, typedef_source_generated);
TEST_VECTOR_EQUAL(*this, b, vertex_inputs_);
TEST_EQUAL(*this, b, geometry_layout_);
@@ -872,6 +913,31 @@ struct ShaderCreateInfo {
return stream;
}
+ bool has_resource_type(Resource::BindType bind_type) const
+ {
+ for (auto &res : batch_resources_) {
+ if (res.bind_type == bind_type) {
+ return true;
+ }
+ }
+ for (auto &res : pass_resources_) {
+ if (res.bind_type == bind_type) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool has_resource_image() const
+ {
+ return has_resource_type(Resource::BindType::IMAGE);
+ }
+
+ bool has_resource_storage() const
+ {
+ return has_resource_type(Resource::BindType::STORAGE_BUFFER);
+ }
+
/** \} */
#undef TEST_EQUAL
diff --git a/source/blender/gpu/intern/gpu_shader_dependency.cc b/source/blender/gpu/intern/gpu_shader_dependency.cc
index 842914f5bed..2c59cb6e501 100644
--- a/source/blender/gpu/intern/gpu_shader_dependency.cc
+++ b/source/blender/gpu/intern/gpu_shader_dependency.cc
@@ -11,11 +11,11 @@
#include <algorithm>
#include <iomanip>
#include <iostream>
+#include <regex>
#include <sstream>
#include "BLI_ghash.h"
#include "BLI_map.hh"
-#include "BLI_set.hh"
#include "BLI_string_ref.hh"
#include "gpu_material_library.h"
@@ -43,7 +43,7 @@ struct GPUSource {
StringRefNull source;
Vector<GPUSource *> dependencies;
bool dependencies_init = false;
- shader::BuiltinBits builtins = (shader::BuiltinBits)0;
+ shader::BuiltinBits builtins = shader::BuiltinBits::NONE;
std::string processed_source;
GPUSource(const char *path,
@@ -55,46 +55,45 @@ 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. */
- if (source.find("gl_FragCoord", 0)) {
+ if (source.find("gl_FragCoord", 0) != StringRef::not_found) {
builtins |= shader::BuiltinBits::FRAG_COORD;
}
- if (source.find("gl_FrontFacing", 0)) {
+ if (source.find("gl_FrontFacing", 0) != StringRef::not_found) {
builtins |= shader::BuiltinBits::FRONT_FACING;
}
- if (source.find("gl_GlobalInvocationID", 0)) {
+ if (source.find("gl_GlobalInvocationID", 0) != StringRef::not_found) {
builtins |= shader::BuiltinBits::GLOBAL_INVOCATION_ID;
}
- if (source.find("gl_InstanceID", 0)) {
+ if (source.find("gl_InstanceID", 0) != StringRef::not_found) {
builtins |= shader::BuiltinBits::INSTANCE_ID;
}
- if (source.find("gl_LocalInvocationID", 0)) {
+ if (source.find("gl_LocalInvocationID", 0) != StringRef::not_found) {
builtins |= shader::BuiltinBits::LOCAL_INVOCATION_ID;
}
- if (source.find("gl_LocalInvocationIndex", 0)) {
+ if (source.find("gl_LocalInvocationIndex", 0) != StringRef::not_found) {
builtins |= shader::BuiltinBits::LOCAL_INVOCATION_INDEX;
}
- if (source.find("gl_NumWorkGroup", 0)) {
+ if (source.find("gl_NumWorkGroup", 0) != StringRef::not_found) {
builtins |= shader::BuiltinBits::NUM_WORK_GROUP;
}
- if (source.find("gl_PointCoord", 0)) {
+ if (source.find("gl_PointCoord", 0) != StringRef::not_found) {
builtins |= shader::BuiltinBits::POINT_COORD;
}
- if (source.find("gl_PointSize", 0)) {
+ if (source.find("gl_PointSize", 0) != StringRef::not_found) {
builtins |= shader::BuiltinBits::POINT_SIZE;
}
- if (source.find("gl_PrimitiveID", 0)) {
+ if (source.find("gl_PrimitiveID", 0) != StringRef::not_found) {
builtins |= shader::BuiltinBits::PRIMITIVE_ID;
}
- if (source.find("gl_VertexID", 0)) {
+ if (source.find("gl_VertexID", 0) != StringRef::not_found) {
builtins |= shader::BuiltinBits::VERTEX_ID;
}
- if (source.find("gl_WorkGroupID", 0)) {
+ if (source.find("gl_WorkGroupID", 0) != StringRef::not_found) {
builtins |= shader::BuiltinBits::WORK_GROUP_ID;
}
- if (source.find("gl_WorkGroupSize", 0)) {
+ if (source.find("gl_WorkGroupSize", 0) != StringRef::not_found) {
builtins |= shader::BuiltinBits::WORK_GROUP_SIZE;
}
-
/* TODO(fclem): We could do that at compile time. */
/* Limit to shared header files to avoid the temptation to use C++ syntax in .glsl files. */
if (filename.endswith(".h") || filename.endswith(".hh")) {
@@ -102,6 +101,18 @@ struct GPUSource {
quote_preprocess();
}
else {
+ if (source.find("'") != StringRef::not_found) {
+ char_literals_preprocess();
+ }
+ if (source.find("drw_print") != StringRef::not_found) {
+ string_preprocess();
+ }
+ if ((source.find("drw_debug_") != StringRef::not_found) &&
+ /* Avoid these two files where it makes no sense to add the dependency. */
+ (filename != "common_debug_draw_lib.glsl" &&
+ filename != "draw_debug_draw_display_vert.glsl")) {
+ builtins |= shader::BuiltinBits::USE_DEBUG_DRAW;
+ }
check_no_quotes();
}
@@ -523,6 +534,217 @@ struct GPUSource {
}
}
+ void char_literals_preprocess()
+ {
+ const StringRefNull input = source;
+ std::stringstream output;
+ int64_t cursor = -1;
+ int64_t last_pos = 0;
+
+ while (true) {
+ cursor = find_token(input, '\'', cursor + 1);
+ if (cursor == -1) {
+ break;
+ }
+ /* Output anything between 2 print statement. */
+ output << input.substr(last_pos, cursor - last_pos);
+
+ /* Extract string. */
+ int64_t char_start = cursor + 1;
+ int64_t char_end = find_token(input, '\'', char_start);
+ CHECK(char_end, input, cursor, "Malformed char literal. Missing ending `'`.");
+
+ StringRef input_char = input.substr(char_start, char_end - char_start);
+ if (input_char.size() == 0) {
+ CHECK(-1, input, cursor, "Malformed char literal. Empty character constant");
+ }
+
+ uint8_t char_value = input_char[0];
+
+ if (input_char[0] == '\\') {
+ if (input_char[1] == 'n') {
+ char_value = '\n';
+ }
+ else {
+ CHECK(-1, input, cursor, "Unsupported escaped character");
+ }
+ }
+ else {
+ if (input_char.size() > 1) {
+ CHECK(-1, input, cursor, "Malformed char literal. Multi-character character constant");
+ }
+ }
+
+ char hex[8];
+ SNPRINTF(hex, "0x%.2Xu", char_value);
+ output << hex;
+
+ cursor = last_pos = char_end + 1;
+ }
+ /* If nothing has been changed, do not allocate processed_source. */
+ if (last_pos == 0) {
+ return;
+ }
+
+ if (last_pos != 0) {
+ output << input.substr(last_pos);
+ }
+ processed_source = output.str();
+ source = processed_source.c_str();
+ }
+
+ /* Replace print(string) by equivalent drw_print_char4() sequence. */
+ void string_preprocess()
+ {
+ const StringRefNull input = source;
+ std::stringstream output;
+ int64_t cursor = -1;
+ int64_t last_pos = 0;
+
+ while (true) {
+ cursor = find_keyword(input, "drw_print", cursor + 1);
+ if (cursor == -1) {
+ break;
+ }
+
+ bool do_endl = false;
+ StringRef func = input.substr(cursor);
+ if (func.startswith("drw_print(")) {
+ do_endl = true;
+ }
+ else if (func.startswith("drw_print_no_endl(")) {
+ do_endl = false;
+ }
+ else {
+ continue;
+ }
+
+ /* Output anything between 2 print statement. */
+ output << input.substr(last_pos, cursor - last_pos);
+
+ /* Extract string. */
+ int64_t str_start = input.find('(', cursor) + 1;
+ int64_t semicolon = find_token(input, ';', str_start + 1);
+ CHECK(semicolon, input, cursor, "Malformed print(). Missing `;` .");
+ int64_t str_end = rfind_token(input, ')', semicolon);
+ if (str_end < str_start) {
+ CHECK(-1, input, cursor, "Malformed print(). Missing closing `)` .");
+ }
+
+ std::stringstream sub_output;
+ StringRef input_args = input.substr(str_start, str_end - str_start);
+
+ auto print_string = [&](std::string str) -> int {
+ size_t len_before_pad = str.length();
+ /* Pad string to uint size. */
+ while (str.length() % 4 != 0) {
+ str += " ";
+ }
+ /* Keep everything in one line to not mess with the shader logs. */
+ sub_output << "/* " << str << "*/";
+ sub_output << "drw_print_string_start(" << len_before_pad << ");";
+ for (size_t i = 0; i < len_before_pad; i += 4) {
+ uint8_t chars[4] = {*(reinterpret_cast<const uint8_t *>(str.c_str()) + i + 0),
+ *(reinterpret_cast<const uint8_t *>(str.c_str()) + i + 1),
+ *(reinterpret_cast<const uint8_t *>(str.c_str()) + i + 2),
+ *(reinterpret_cast<const uint8_t *>(str.c_str()) + i + 3)};
+ if (i + 4 > len_before_pad) {
+ chars[len_before_pad - i] = '\0';
+ }
+ char uint_hex[12];
+ SNPRINTF(uint_hex, "0x%.2X%.2X%.2X%.2Xu", chars[3], chars[2], chars[1], chars[0]);
+ sub_output << "drw_print_char4(" << StringRefNull(uint_hex) << ");";
+ }
+ return 0;
+ };
+
+ std::string func_args = input_args;
+ /* Workaround to support function call inside prints. We replace commas by a non control
+ * character `$` in order to use simpler regex later. */
+ bool string_scope = false;
+ int func_scope = 0;
+ for (char &c : func_args) {
+ if (c == '"') {
+ string_scope = !string_scope;
+ }
+ else if (!string_scope) {
+ if (c == '(') {
+ func_scope++;
+ }
+ else if (c == ')') {
+ func_scope--;
+ }
+ else if (c == ',' && func_scope != 0) {
+ c = '$';
+ }
+ }
+ }
+
+ const bool print_as_variable = (input_args[0] != '"') && find_token(input_args, ',') == -1;
+ if (print_as_variable) {
+ /* Variable or expression debugging. */
+ std::string arg = input_args;
+ /* Pad align most values. */
+ while (arg.length() % 4 != 0) {
+ arg += " ";
+ }
+ print_string(arg);
+ print_string("= ");
+ sub_output << "drw_print_value(" << input_args << ");";
+ }
+ else {
+ const std::regex arg_regex(
+ /* String args. */
+ "[\\s]*\"([^\r\n\t\f\v\"]*)\""
+ /* OR. */
+ "|"
+ /* value args. */
+ "([^,]+)");
+ std::smatch args_match;
+ std::string::const_iterator args_search_start(func_args.cbegin());
+ while (std::regex_search(args_search_start, func_args.cend(), args_match, arg_regex)) {
+ args_search_start = args_match.suffix().first;
+ std::string arg_string = args_match[1].str();
+ std::string arg_val = args_match[2].str();
+
+ if (arg_string.empty()) {
+ for (char &c : arg_val) {
+ if (c == '$') {
+ c = ',';
+ }
+ }
+ sub_output << "drw_print_value(" << arg_val << ");";
+ }
+ else {
+ print_string(arg_string);
+ }
+ }
+ }
+
+ if (do_endl) {
+ sub_output << "drw_print_newline();";
+ }
+
+ output << sub_output.str();
+
+ cursor = last_pos = str_end + 1;
+ }
+ /* If nothing has been changed, do not allocate processed_source. */
+ if (last_pos == 0) {
+ return;
+ }
+
+ if (filename != "common_debug_print_lib.glsl") {
+ builtins |= shader::BuiltinBits::USE_DEBUG_PRINT;
+ }
+
+ if (last_pos != 0) {
+ output << input.substr(last_pos);
+ }
+ processed_source = output.str();
+ source = processed_source.c_str();
+ }
+
#undef find_keyword
#undef rfind_keyword
#undef find_token
@@ -538,6 +760,15 @@ struct GPUSource {
this->dependencies_init = true;
int64_t pos = -1;
+ using namespace shader;
+ /* Auto dependency injection for debug capabilities. */
+ if ((builtins & BuiltinBits::USE_DEBUG_DRAW) == BuiltinBits::USE_DEBUG_DRAW) {
+ dependencies.append_non_duplicates(dict.lookup("common_debug_draw_lib.glsl"));
+ }
+ if ((builtins & BuiltinBits::USE_DEBUG_PRINT) == BuiltinBits::USE_DEBUG_PRINT) {
+ dependencies.append_non_duplicates(dict.lookup("common_debug_print_lib.glsl"));
+ }
+
while (true) {
GPUSource *dependency_source = nullptr;
@@ -559,6 +790,7 @@ struct GPUSource {
return 1;
}
}
+
/* Recursive. */
int result = dependency_source->init_dependencies(dict, g_functions);
if (result != 0) {
@@ -584,7 +816,7 @@ struct GPUSource {
shader::BuiltinBits builtins_get() const
{
- shader::BuiltinBits out_builtins = shader::BuiltinBits::NONE;
+ shader::BuiltinBits out_builtins = builtins;
for (auto *dep : dependencies) {
out_builtins |= dep->builtins;
}
@@ -594,7 +826,8 @@ struct GPUSource {
bool is_from_material_library() const
{
return (filename.startswith("gpu_shader_material_") ||
- filename.startswith("gpu_shader_common_")) &&
+ filename.startswith("gpu_shader_common_") ||
+ filename.startswith("gpu_shader_compositor_")) &&
filename.endswith(".glsl");
}
};
diff --git a/source/blender/gpu/intern/gpu_shader_interface.hh b/source/blender/gpu/intern/gpu_shader_interface.hh
index ac78af38fcc..41e06569bdc 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.hh
+++ b/source/blender/gpu/intern/gpu_shader_interface.hh
@@ -18,6 +18,7 @@
#include "BLI_utildefines.h"
#include "GPU_shader.h"
+#include "GPU_vertex_format.h" /* GPU_VERT_ATTR_MAX_LEN */
#include "gpu_shader_create_info.hh"
namespace blender::gpu {
@@ -39,9 +40,9 @@ class ShaderInterface {
/* TODO(fclem): should be protected. */
public:
/** Flat array. In this order: Attributes, Ubos, Uniforms. */
- ShaderInput *inputs_ = NULL;
+ ShaderInput *inputs_ = nullptr;
/** Buffer containing all inputs names separated by '\0'. */
- char *name_buffer_ = NULL;
+ char *name_buffer_ = nullptr;
/** Input counts inside input array. */
uint attr_len_ = 0;
uint ubo_len_ = 0;
@@ -56,6 +57,14 @@ class ShaderInterface {
/** Location of builtin uniforms. Fast access, no lookup needed. */
int32_t builtins_[GPU_NUM_UNIFORMS];
int32_t builtin_blocks_[GPU_NUM_UNIFORM_BLOCKS];
+ int32_t builtin_buffers_[GPU_NUM_STORAGE_BUFFERS];
+
+ /**
+ * Currently only used for `GPU_shader_get_attribute_info`.
+ * This utility is useful for automatic creation of `GPUVertFormat` in Python.
+ * Use `ShaderInput::location` to identify the `Type`.
+ */
+ uint8_t attr_types_[GPU_VERT_ATTR_MAX_LEN];
public:
ShaderInterface();
@@ -68,6 +77,10 @@ class ShaderInterface {
{
return input_lookup(inputs_, attr_len_, name);
}
+ inline const ShaderInput *attr_get(const int binding) const
+ {
+ return input_lookup(inputs_, attr_len_, binding);
+ }
inline const ShaderInput *ubo_get(const char *name) const
{
@@ -116,9 +129,17 @@ class ShaderInterface {
return builtin_blocks_[builtin];
}
+ /* Returns binding position. */
+ inline int32_t ssbo_builtin(const GPUStorageBufferBuiltin builtin) const
+ {
+ BLI_assert(builtin >= 0 && builtin < GPU_NUM_STORAGE_BUFFERS);
+ return builtin_buffers_[builtin];
+ }
+
protected:
static inline const char *builtin_uniform_name(GPUUniformBuiltin u);
static inline const char *builtin_uniform_block_name(GPUUniformBlockBuiltin u);
+ static inline const char *builtin_storage_block_name(GPUStorageBufferBuiltin u);
inline uint32_t set_input_name(ShaderInput *input, char *name, uint32_t name_len) const;
inline void copy_input_name(ShaderInput *input,
@@ -187,7 +208,7 @@ inline const char *ShaderInterface::builtin_uniform_name(GPUUniformBuiltin u)
return "srgbTarget";
default:
- return NULL;
+ return nullptr;
}
}
@@ -208,7 +229,19 @@ inline const char *ShaderInterface::builtin_uniform_block_name(GPUUniformBlockBu
case GPU_UNIFORM_BLOCK_DRW_INFOS:
return "drw_infos";
default:
- return NULL;
+ return nullptr;
+ }
+}
+
+inline const char *ShaderInterface::builtin_storage_block_name(GPUStorageBufferBuiltin u)
+{
+ switch (u) {
+ case GPU_STORAGE_BUFFER_DEBUG_VERTS:
+ return "drw_debug_verts_buf";
+ case GPU_STORAGE_BUFFER_DEBUG_PRINT:
+ return "drw_debug_print_buf";
+ default:
+ return nullptr;
}
}
@@ -258,7 +291,7 @@ inline const ShaderInput *ShaderInterface::input_lookup(const ShaderInput *const
return inputs + i; /* not found */
}
}
- return NULL; /* not found */
+ return nullptr; /* not found */
}
/* This is a bit dangerous since we could have a hash collision.
@@ -268,7 +301,7 @@ inline const ShaderInput *ShaderInterface::input_lookup(const ShaderInput *const
return inputs + i;
}
}
- return NULL; /* not found */
+ return nullptr; /* not found */
}
inline const ShaderInput *ShaderInterface::input_lookup(const ShaderInput *const inputs,
@@ -281,7 +314,7 @@ inline const ShaderInput *ShaderInterface::input_lookup(const ShaderInput *const
return inputs + i;
}
}
- return NULL; /* not found */
+ return nullptr; /* not found */
}
} // namespace blender::gpu
diff --git a/source/blender/gpu/intern/gpu_shader_log.cc b/source/blender/gpu/intern/gpu_shader_log.cc
index 83fc34a3278..dbc36c5afd0 100644
--- a/source/blender/gpu/intern/gpu_shader_log.cc
+++ b/source/blender/gpu/intern/gpu_shader_log.cc
@@ -15,8 +15,6 @@
#include "gpu_shader_dependency_private.h"
#include "gpu_shader_private.hh"
-#include "GPU_platform.h"
-
#include "CLG_log.h"
static CLG_LogRef LOG = {"gpu.shader"};
@@ -230,6 +228,7 @@ void Shader::print_log(Span<const char *> sources,
log_line = line_end + 1;
previous_location = log_item.cursor;
}
+ // printf("%s", sources_combined);
MEM_freeN(sources_combined);
CLG_Severity severity = error ? CLG_SEVERITY_ERROR : CLG_SEVERITY_WARN;
diff --git a/source/blender/gpu/intern/gpu_shader_private.hh b/source/blender/gpu/intern/gpu_shader_private.hh
index 4d318093c98..a822cd8aa38 100644
--- a/source/blender/gpu/intern/gpu_shader_private.hh
+++ b/source/blender/gpu/intern/gpu_shader_private.hh
@@ -55,8 +55,6 @@ class Shader {
virtual void uniform_float(int location, int comp_len, int array_size, const float *data) = 0;
virtual void uniform_int(int location, int comp_len, int array_size, const int *data) = 0;
- virtual void vertformat_from_shader(GPUVertFormat *) const = 0;
-
std::string defines_declare(const shader::ShaderCreateInfo &info) const;
virtual std::string resources_declare(const shader::ShaderCreateInfo &info) const = 0;
virtual std::string vertex_interface_declare(const shader::ShaderCreateInfo &info) const = 0;
diff --git a/source/blender/gpu/intern/gpu_state.cc b/source/blender/gpu/intern/gpu_state.cc
index f74d500340d..a1e0b8867a0 100644
--- a/source/blender/gpu/intern/gpu_state.cc
+++ b/source/blender/gpu/intern/gpu_state.cc
@@ -14,8 +14,6 @@
#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
-#include "BKE_global.h"
-
#include "GPU_state.h"
#include "gpu_context_private.hh"
diff --git a/source/blender/gpu/intern/gpu_storage_buffer.cc b/source/blender/gpu/intern/gpu_storage_buffer.cc
index 68020ec66f4..460a643089c 100644
--- a/source/blender/gpu/intern/gpu_storage_buffer.cc
+++ b/source/blender/gpu/intern/gpu_storage_buffer.cc
@@ -12,7 +12,6 @@
#include "BLI_math_base.h"
#include "gpu_backend.hh"
-#include "gpu_node_graph.h"
#include "GPU_material.h"
#include "GPU_vertex_buffer.h" /* For GPUUsageType. */
@@ -110,4 +109,9 @@ void GPU_storagebuf_copy_sub_from_vertbuf(
unwrap(ssbo)->copy_sub(unwrap(src), dst_offset, src_offset, copy_size);
}
+void GPU_storagebuf_read(GPUStorageBuf *ssbo, void *data)
+{
+ unwrap(ssbo)->read(data);
+}
+
/** \} */
diff --git a/source/blender/gpu/intern/gpu_storage_buffer_private.hh b/source/blender/gpu/intern/gpu_storage_buffer_private.hh
index 091e6c2d386..0c96f97ad30 100644
--- a/source/blender/gpu/intern/gpu_storage_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_storage_buffer_private.hh
@@ -29,7 +29,7 @@ class StorageBuf {
/** Data size in bytes. */
size_t size_in_bytes_;
/** Continuous memory block to copy to GPU. This data is owned by the StorageBuf. */
- void *data_ = NULL;
+ void *data_ = nullptr;
/** Debugging name */
char name_[DEBUG_NAME_LEN];
@@ -44,6 +44,7 @@ class StorageBuf {
eGPUDataFormat data_format,
void *data) = 0;
virtual void copy_sub(VertBuf *src, uint dst_offset, uint src_offset, uint copy_size) = 0;
+ virtual void read(void *data) = 0;
};
/* Syntactic sugar. */
diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc
index d78dc845074..bec8b8a0df3 100644
--- a/source/blender/gpu/intern/gpu_texture.cc
+++ b/source/blender/gpu/intern/gpu_texture.cc
@@ -13,7 +13,6 @@
#include "gpu_backend.hh"
#include "gpu_context_private.hh"
#include "gpu_framebuffer_private.hh"
-#include "gpu_vertex_buffer_private.hh"
#include "gpu_texture_private.hh"
@@ -52,13 +51,13 @@ Texture::~Texture()
#endif
}
-bool Texture::init_1D(int w, int layers, int mips, eGPUTextureFormat format)
+bool Texture::init_1D(int w, int layers, int mip_len, eGPUTextureFormat format)
{
w_ = w;
h_ = layers;
d_ = 0;
- int mips_max = 1 + floorf(log2f(w));
- mipmaps_ = min_ii(mips, mips_max);
+ int mip_len_max = 1 + floorf(log2f(w));
+ mipmaps_ = min_ii(mip_len, mip_len_max);
format_ = format;
format_flag_ = to_format_flag(format);
type_ = (layers > 0) ? GPU_TEXTURE_1D_ARRAY : GPU_TEXTURE_1D;
@@ -68,13 +67,13 @@ bool Texture::init_1D(int w, int layers, int mips, eGPUTextureFormat format)
return this->init_internal();
}
-bool Texture::init_2D(int w, int h, int layers, int mips, eGPUTextureFormat format)
+bool Texture::init_2D(int w, int h, int layers, int mip_len, eGPUTextureFormat format)
{
w_ = w;
h_ = h;
d_ = layers;
- int mips_max = 1 + floorf(log2f(max_ii(w, h)));
- mipmaps_ = min_ii(mips, mips_max);
+ int mip_len_max = 1 + floorf(log2f(max_ii(w, h)));
+ mipmaps_ = min_ii(mip_len, mip_len_max);
format_ = format;
format_flag_ = to_format_flag(format);
type_ = (layers > 0) ? GPU_TEXTURE_2D_ARRAY : GPU_TEXTURE_2D;
@@ -84,13 +83,13 @@ bool Texture::init_2D(int w, int h, int layers, int mips, eGPUTextureFormat form
return this->init_internal();
}
-bool Texture::init_3D(int w, int h, int d, int mips, eGPUTextureFormat format)
+bool Texture::init_3D(int w, int h, int d, int mip_len, eGPUTextureFormat format)
{
w_ = w;
h_ = h;
d_ = d;
- int mips_max = 1 + floorf(log2f(max_iii(w, h, d)));
- mipmaps_ = min_ii(mips, mips_max);
+ int mip_len_max = 1 + floorf(log2f(max_iii(w, h, d)));
+ mipmaps_ = min_ii(mip_len, mip_len_max);
format_ = format;
format_flag_ = to_format_flag(format);
type_ = GPU_TEXTURE_3D;
@@ -100,13 +99,13 @@ bool Texture::init_3D(int w, int h, int d, int mips, eGPUTextureFormat format)
return this->init_internal();
}
-bool Texture::init_cubemap(int w, int layers, int mips, eGPUTextureFormat format)
+bool Texture::init_cubemap(int w, int layers, int mip_len, eGPUTextureFormat format)
{
w_ = w;
h_ = w;
d_ = max_ii(1, layers) * 6;
- int mips_max = 1 + floorf(log2f(w));
- mipmaps_ = min_ii(mips, mips_max);
+ int mip_len_max = 1 + floorf(log2f(w));
+ mipmaps_ = min_ii(mip_len, mip_len_max);
format_ = format;
format_flag_ = to_format_flag(format);
type_ = (layers > 0) ? GPU_TEXTURE_CUBE_ARRAY : GPU_TEXTURE_CUBE;
@@ -238,29 +237,29 @@ static inline GPUTexture *gpu_texture_create(const char *name,
const int h,
const int d,
const eGPUTextureType type,
- int mips,
+ int mip_len,
eGPUTextureFormat tex_format,
eGPUDataFormat data_format,
const void *pixels)
{
- BLI_assert(mips > 0);
+ BLI_assert(mip_len > 0);
Texture *tex = GPUBackend::get()->texture_alloc(name);
bool success = false;
switch (type) {
case GPU_TEXTURE_1D:
case GPU_TEXTURE_1D_ARRAY:
- success = tex->init_1D(w, h, mips, tex_format);
+ success = tex->init_1D(w, h, mip_len, tex_format);
break;
case GPU_TEXTURE_2D:
case GPU_TEXTURE_2D_ARRAY:
- success = tex->init_2D(w, h, d, mips, tex_format);
+ success = tex->init_2D(w, h, d, mip_len, tex_format);
break;
case GPU_TEXTURE_3D:
- success = tex->init_3D(w, h, d, mips, tex_format);
+ success = tex->init_3D(w, h, d, mip_len, tex_format);
break;
case GPU_TEXTURE_CUBE:
case GPU_TEXTURE_CUBE_ARRAY:
- success = tex->init_cubemap(w, d, mips, tex_format);
+ success = tex->init_cubemap(w, d, mip_len, tex_format);
break;
default:
break;
@@ -361,6 +360,13 @@ GPUTexture *GPU_texture_create_compressed_2d(
GPUTexture *GPU_texture_create_from_vertbuf(const char *name, GPUVertBuf *vert)
{
+#ifndef NDEBUG
+ /* Vertex buffers used for texture buffers must be flagged with:
+ * GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY. */
+ BLI_assert_msg(unwrap(vert)->extended_usage_ & GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY,
+ "Vertex Buffers used for textures should have usage flag "
+ "GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY.");
+#endif
eGPUTextureFormat tex_format = to_texture_format(GPU_vertbuf_get_format(vert));
Texture *tex = GPUBackend::get()->texture_alloc(name);
@@ -642,6 +648,112 @@ eGPUTextureFormat GPU_texture_format(const GPUTexture *tex)
return reinterpret_cast<const Texture *>(tex)->format_get();
}
+const char *GPU_texture_format_description(eGPUTextureFormat texture_format)
+{
+ switch (texture_format) {
+ case GPU_RGBA8UI:
+ return "RGBA8UI";
+ case GPU_RGBA8I:
+ return "RGBA8I";
+ case GPU_RGBA8:
+ return "RGBA8";
+ case GPU_RGBA32UI:
+ return "RGBA32UI";
+ case GPU_RGBA32I:
+ return "RGBA32I";
+ case GPU_RGBA32F:
+ return "RGBA32F";
+ case GPU_RGBA16UI:
+ return "RGBA16UI";
+ case GPU_RGBA16I:
+ return "RGBA16I";
+ case GPU_RGBA16F:
+ return "RGBA16F";
+ case GPU_RGBA16:
+ return "RGBA16";
+ case GPU_RG8UI:
+ return "RG8UI";
+ case GPU_RG8I:
+ return "RG8I";
+ case GPU_RG8:
+ return "RG8";
+ case GPU_RG32UI:
+ return "RG32UI";
+ case GPU_RG32I:
+ return "RG32I";
+ case GPU_RG32F:
+ return "RG32F";
+ case GPU_RG16UI:
+ return "RG16UI";
+ case GPU_RG16I:
+ return "RG16I";
+ case GPU_RG16F:
+ return "RG16F";
+ case GPU_RG16:
+ return "RG16";
+ case GPU_R8UI:
+ return "R8UI";
+ case GPU_R8I:
+ return "R8I";
+ case GPU_R8:
+ return "R8";
+ case GPU_R32UI:
+ return "R32UI";
+ case GPU_R32I:
+ return "R32I";
+ case GPU_R32F:
+ return "R32F";
+ case GPU_R16UI:
+ return "R16UI";
+ case GPU_R16I:
+ return "R16I";
+ case GPU_R16F:
+ return "R16F";
+ case GPU_R16:
+ return "R16";
+
+ /* Special formats texture & render-buffer. */
+ case GPU_RGB10_A2:
+ return "RGB10A2";
+ case GPU_R11F_G11F_B10F:
+ return "R11FG11FB10F";
+ case GPU_DEPTH32F_STENCIL8:
+ return "DEPTH32FSTENCIL8";
+ case GPU_DEPTH24_STENCIL8:
+ return "DEPTH24STENCIL8";
+ case GPU_SRGB8_A8:
+ return "SRGB8A8";
+
+ /* Texture only format */
+ case (GPU_RGB16F):
+ return "RGB16F";
+
+ /* Special formats texture only */
+ case GPU_SRGB8_A8_DXT1:
+ return "SRGB8_A8_DXT1";
+ case GPU_SRGB8_A8_DXT3:
+ return "SRGB8_A8_DXT3";
+ case GPU_SRGB8_A8_DXT5:
+ return "SRGB8_A8_DXT5";
+ case GPU_RGBA8_DXT1:
+ return "RGBA8_DXT1";
+ case GPU_RGBA8_DXT3:
+ return "RGBA8_DXT3";
+ case GPU_RGBA8_DXT5:
+ return "RGBA8_DXT5";
+
+ /* Depth Formats */
+ case GPU_DEPTH_COMPONENT32F:
+ return "DEPTH32F";
+ case GPU_DEPTH_COMPONENT24:
+ return "DEPTH24";
+ case GPU_DEPTH_COMPONENT16:
+ return "DEPTH16";
+ }
+ BLI_assert_unreachable();
+ return "";
+}
+
bool GPU_texture_depth(const GPUTexture *tex)
{
return (reinterpret_cast<const Texture *>(tex)->format_flag_get() & GPU_FORMAT_DEPTH) != 0;
@@ -702,7 +814,11 @@ void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *r_size)
void GPU_samplers_update()
{
- GPUBackend::get()->samplers_update();
+ /* Backend may not exist when we are updating preferences from background mode. */
+ GPUBackend *backend = GPUBackend::get();
+ if (backend) {
+ backend->samplers_update();
+ }
}
/** \} */
diff --git a/source/blender/gpu/intern/gpu_texture_private.hh b/source/blender/gpu/intern/gpu_texture_private.hh
index 00bcc9fac00..8521b0fd77f 100644
--- a/source/blender/gpu/intern/gpu_texture_private.hh
+++ b/source/blender/gpu/intern/gpu_texture_private.hh
@@ -101,10 +101,10 @@ class Texture {
virtual ~Texture();
/* Return true on success. */
- bool init_1D(int w, int layers, int mips, eGPUTextureFormat format);
- bool init_2D(int w, int h, int layers, int mips, eGPUTextureFormat format);
- bool init_3D(int w, int h, int d, int mips, eGPUTextureFormat format);
- bool init_cubemap(int w, int layers, int mips, eGPUTextureFormat format);
+ bool init_1D(int w, int layers, int mip_len, eGPUTextureFormat format);
+ bool init_2D(int w, int h, int layers, int mip_len, eGPUTextureFormat format);
+ bool init_3D(int w, int h, int d, int mip_len, eGPUTextureFormat format);
+ bool init_cubemap(int w, int layers, int mip_len, eGPUTextureFormat format);
bool init_buffer(GPUVertBuf *vbo, eGPUTextureFormat format);
bool init_view(const GPUTexture *src,
eGPUTextureFormat format,
diff --git a/source/blender/gpu/intern/gpu_uniform_buffer_private.hh b/source/blender/gpu/intern/gpu_uniform_buffer_private.hh
index 6e3285b6fef..e3d70634ce1 100644
--- a/source/blender/gpu/intern/gpu_uniform_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_uniform_buffer_private.hh
@@ -29,7 +29,7 @@ class UniformBuf {
/** Data size in bytes. */
size_t size_in_bytes_;
/** Continuous memory block to copy to GPU. This data is owned by the UniformBuf. */
- void *data_ = NULL;
+ void *data_ = nullptr;
/** Debugging name */
char name_[DEBUG_NAME_LEN];
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.cc b/source/blender/gpu/intern/gpu_vertex_buffer.cc
index f47970d48d1..a441cfe2fb8 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer.cc
+++ b/source/blender/gpu/intern/gpu_vertex_buffer.cc
@@ -12,7 +12,6 @@
#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 "gpu_vertex_buffer_private.hh"
@@ -41,10 +40,21 @@ VertBuf::~VertBuf()
void VertBuf::init(const GPUVertFormat *format, GPUUsageType usage)
{
- usage_ = usage;
+ /* Strip extended usage flags. */
+ usage_ = usage & ~GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY;
+#ifndef NDEBUG
+ /* Store extended usage. */
+ extended_usage_ = usage;
+#endif
flag = GPU_VERTBUF_DATA_DIRTY;
GPU_vertformat_copy(&this->format, format);
- if (!format->packed) {
+ /* Avoid packing vertex formats which are used for texture buffers.
+ * These cases use singular types and do not need packing. They must
+ * also not have increased alignment padding to the minimum per-vertex stride. */
+ if (usage & GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY) {
+ VertexFormat_texture_buffer_pack(&this->format);
+ }
+ if (!this->format.packed) {
VertexFormat_pack(&this->format);
}
flag |= GPU_VERTBUF_INIT;
@@ -63,6 +73,10 @@ VertBuf *VertBuf::duplicate()
*dst = *this;
/* Almost full copy... */
dst->handle_refcount_ = 1;
+ /* Metadata. */
+#ifndef NDEBUG
+ dst->extended_usage_ = extended_usage_;
+#endif
/* Duplicate all needed implementation specifics data. */
this->duplicate_data(dst);
return dst;
@@ -193,6 +207,7 @@ void GPU_vertbuf_data_len_set(GPUVertBuf *verts_, uint v_len)
void GPU_vertbuf_attr_set(GPUVertBuf *verts_, uint a_idx, uint v_idx, const void *data)
{
VertBuf *verts = unwrap(verts_);
+ BLI_assert(verts->get_usage_type() != GPU_USAGE_DEVICE_ONLY);
const GPUVertFormat *format = &verts->format;
const GPUVertAttr *a = &format->attrs[a_idx];
BLI_assert(v_idx < verts->vertex_alloc);
@@ -216,6 +231,7 @@ void GPU_vertbuf_attr_fill(GPUVertBuf *verts_, uint a_idx, const void *data)
void GPU_vertbuf_vert_set(GPUVertBuf *verts_, uint v_idx, const void *data)
{
VertBuf *verts = unwrap(verts_);
+ BLI_assert(verts->get_usage_type() != GPU_USAGE_DEVICE_ONLY);
const GPUVertFormat *format = &verts->format;
BLI_assert(v_idx < verts->vertex_alloc);
BLI_assert(verts->data != nullptr);
@@ -226,6 +242,7 @@ void GPU_vertbuf_vert_set(GPUVertBuf *verts_, uint v_idx, const void *data)
void GPU_vertbuf_attr_fill_stride(GPUVertBuf *verts_, uint a_idx, uint stride, const void *data)
{
VertBuf *verts = unwrap(verts_);
+ BLI_assert(verts->get_usage_type() != GPU_USAGE_DEVICE_ONLY);
const GPUVertFormat *format = &verts->format;
const GPUVertAttr *a = &format->attrs[a_idx];
BLI_assert(a_idx < format->attr_len);
diff --git a/source/blender/gpu/intern/gpu_vertex_buffer_private.hh b/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
index 7a0b53cf958..f20f6caf6de 100644
--- a/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
+++ b/source/blender/gpu/intern/gpu_vertex_buffer_private.hh
@@ -29,7 +29,12 @@ class VertBuf {
/** Status flag. */
GPUVertBufStatus flag = GPU_VERTBUF_INVALID;
/** NULL indicates data in VRAM (unmapped) */
- uchar *data = NULL;
+ uchar *data = nullptr;
+
+#ifndef NDEBUG
+ /** Usage including extended usage flags. */
+ GPUUsageType extended_usage_ = GPU_USAGE_STATIC;
+#endif
protected:
/** Usage hint for GL optimization. */
@@ -83,6 +88,11 @@ class VertBuf {
}
}
+ GPUUsageType get_usage_type() const
+ {
+ return usage_;
+ }
+
virtual void update_sub(uint start, uint len, const void *data) = 0;
virtual const void *read() const = 0;
virtual void *unmap(const void *mapped_data) const = 0;
diff --git a/source/blender/gpu/intern/gpu_vertex_format.cc b/source/blender/gpu/intern/gpu_vertex_format.cc
index 59ae862aa51..897e80293bf 100644
--- a/source/blender/gpu/intern/gpu_vertex_format.cc
+++ b/source/blender/gpu/intern/gpu_vertex_format.cc
@@ -8,6 +8,9 @@
*/
#include "GPU_vertex_format.h"
+#include "GPU_capabilities.h"
+
+#include "gpu_shader_create_info.hh"
#include "gpu_shader_private.hh"
#include "gpu_vertex_format_private.h"
@@ -25,6 +28,7 @@
#endif
using namespace blender::gpu;
+using namespace blender::gpu::shader;
void GPU_vertformat_clear(GPUVertFormat *format)
{
@@ -66,7 +70,7 @@ static uint attr_size(const GPUVertAttr *a)
return a->comp_len * comp_size(static_cast<GPUVertCompType>(a->comp_type));
}
-static uint attr_align(const GPUVertAttr *a)
+static uint attr_align(const GPUVertAttr *a, uint minimum_stride)
{
if (a->comp_type == GPU_COMP_I10) {
return 4; /* always packed as 10_10_10_2 */
@@ -76,7 +80,10 @@ static uint attr_align(const GPUVertAttr *a)
return 4 * c; /* AMD HW can't fetch these well, so pad it out (other vendors too?) */
}
- return c; /* most fetches are ok if components are naturally aligned */
+ /* Most fetches are ok if components are naturally aligned.
+ * However, in Metal,the minimum supported per-vertex stride is 4,
+ * so we must query the GPU and pad out the size accordingly. */
+ return max_ii(minimum_stride, c);
}
uint vertex_buffer_size(const GPUVertFormat *format, uint vertex_len)
@@ -306,7 +313,7 @@ static void show_pack(uint a_idx, uint size, uint pad)
}
#endif
-void VertexFormat_pack(GPUVertFormat *format)
+static void VertexFormat_pack_impl(GPUVertFormat *format, uint minimum_stride)
{
GPUVertAttr *a0 = &format->attrs[0];
a0->offset = 0;
@@ -318,7 +325,7 @@ void VertexFormat_pack(GPUVertFormat *format)
for (uint a_idx = 1; a_idx < format->attr_len; a_idx++) {
GPUVertAttr *a = &format->attrs[a_idx];
- uint mid_padding = padding(offset, attr_align(a));
+ uint mid_padding = padding(offset, attr_align(a, minimum_stride));
offset += mid_padding;
a->offset = offset;
offset += a->size;
@@ -328,7 +335,7 @@ void VertexFormat_pack(GPUVertFormat *format)
#endif
}
- uint end_padding = padding(offset, attr_align(a0));
+ uint end_padding = padding(offset, attr_align(a0, minimum_stride));
#if PACK_DEBUG
show_pack(0, 0, end_padding);
@@ -338,8 +345,106 @@ void VertexFormat_pack(GPUVertFormat *format)
format->packed = true;
}
+void VertexFormat_pack(GPUVertFormat *format)
+{
+ /* Perform standard vertex packing, ensuring vertex format satisfies
+ * minimum stride requirements for vertex assembly. */
+ VertexFormat_pack_impl(format, GPU_minimum_per_vertex_stride());
+}
+
+void VertexFormat_texture_buffer_pack(GPUVertFormat *format)
+{
+ /* Validates packing for vertex formats used with texture buffers.
+ * In these cases, there must only be a single vertex attribute.
+ * This attribute should be tightly packed without padding, to ensure
+ * it aligns with the backing texture data format, skipping
+ * minimum per-vertex stride, which mandates 4-byte alignment in Metal.
+ * This additional alignment padding caused smaller data types, e.g. U16,
+ * to mis-align. */
+ BLI_assert_msg(format->attr_len == 1,
+ "Texture buffer mode should only use a single vertex attribute.");
+
+ /* Pack vertex format without minimum stride, as this is not required by texture buffers. */
+ VertexFormat_pack_impl(format, 1);
+}
+
+static uint component_size_get(const Type gpu_type)
+{
+ switch (gpu_type) {
+ case Type::VEC2:
+ case Type::IVEC2:
+ case Type::UVEC2:
+ return 2;
+ case Type::VEC3:
+ case Type::IVEC3:
+ case Type::UVEC3:
+ return 3;
+ case Type::VEC4:
+ case Type::IVEC4:
+ case Type::UVEC4:
+ return 4;
+ case Type::MAT3:
+ return 12;
+ case Type::MAT4:
+ return 16;
+ default:
+ return 1;
+ }
+}
+
+static void recommended_fetch_mode_and_comp_type(Type gpu_type,
+ GPUVertCompType *r_comp_type,
+ GPUVertFetchMode *r_fetch_mode)
+{
+ switch (gpu_type) {
+ case Type::FLOAT:
+ case Type::VEC2:
+ case Type::VEC3:
+ case Type::VEC4:
+ case Type::MAT3:
+ case Type::MAT4:
+ *r_comp_type = GPU_COMP_F32;
+ *r_fetch_mode = GPU_FETCH_FLOAT;
+ break;
+ case Type::INT:
+ case Type::IVEC2:
+ case Type::IVEC3:
+ case Type::IVEC4:
+ *r_comp_type = GPU_COMP_I32;
+ *r_fetch_mode = GPU_FETCH_INT;
+ break;
+ case Type::UINT:
+ case Type::UVEC2:
+ case Type::UVEC3:
+ case Type::UVEC4:
+ *r_comp_type = GPU_COMP_U32;
+ *r_fetch_mode = GPU_FETCH_INT;
+ break;
+ default:
+ BLI_assert(0);
+ }
+}
+
void GPU_vertformat_from_shader(GPUVertFormat *format, const struct GPUShader *gpushader)
{
- const Shader *shader = reinterpret_cast<const Shader *>(gpushader);
- shader->vertformat_from_shader(format);
+ GPU_vertformat_clear(format);
+
+ uint attr_len = GPU_shader_get_attribute_len(gpushader);
+ int location_test = 0, attrs_added = 0;
+ while (attrs_added < attr_len) {
+ char name[256];
+ Type gpu_type;
+ if (!GPU_shader_get_attribute_info(gpushader, location_test++, name, (int *)&gpu_type)) {
+ continue;
+ }
+
+ GPUVertCompType comp_type;
+ GPUVertFetchMode fetch_mode;
+ recommended_fetch_mode_and_comp_type(gpu_type, &comp_type, &fetch_mode);
+
+ int comp_len = component_size_get(gpu_type);
+
+ GPU_vertformat_attr_add(format, name, comp_type, comp_len, fetch_mode);
+ attrs_added++;
+ }
}
diff --git a/source/blender/gpu/intern/gpu_vertex_format_private.h b/source/blender/gpu/intern/gpu_vertex_format_private.h
index 0f8a869f6df..430008b4cb9 100644
--- a/source/blender/gpu/intern/gpu_vertex_format_private.h
+++ b/source/blender/gpu/intern/gpu_vertex_format_private.h
@@ -16,6 +16,7 @@ extern "C" {
struct GPUVertFormat;
void VertexFormat_pack(struct GPUVertFormat *format);
+void VertexFormat_texture_buffer_pack(struct GPUVertFormat *format);
uint padding(uint offset, uint alignment);
uint vertex_buffer_size(const struct GPUVertFormat *format, uint vertex_len);
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index c3118ca320c..71bdf9e336b 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -9,16 +9,13 @@
#include <string.h>
-#include "BLI_listbase.h"
#include "BLI_math_vector.h"
-#include "BLI_memblock.h"
#include "BLI_rect.h"
#include "BKE_colortools.h"
#include "IMB_colormanagement.h"
-#include "DNA_userdef_types.h"
#include "DNA_vec_types.h"
#include "GPU_capabilities.h"