diff options
Diffstat (limited to 'source/blender/gpu/intern')
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" |