Blender V5.0
draw_curves.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2017 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include "BLT_translation.hh"
12#include "DNA_curves_types.h"
13
14#include "BLI_math_base.h"
15
16#include "BKE_attribute.hh"
17#include "BKE_curves.hh"
18
19#include "GPU_batch.hh"
20#include "GPU_capabilities.hh"
21#include "GPU_material.hh"
22#include "GPU_shader.hh"
23#include "GPU_texture.hh"
24#include "GPU_vertex_buffer.hh"
25
26#include "DRW_gpu_wrapper.hh"
27#include "DRW_render.hh"
28
29#include "draw_cache_impl.hh"
30#include "draw_common.hh"
34#include "draw_hair_private.hh"
35#include "draw_shader.hh"
36
37namespace blender::draw {
38
40
42{
44 if (used >= ubos.size()) {
45 ubos.append(std::make_unique<CurvesInfosBuf>());
46 ptr = ubos.last().get();
47 }
48 else {
49 ptr = ubos[used++].get();
50 }
51
52 memset(ptr->data(), 0, sizeof(CurvesInfos));
53 return *ptr;
54}
55
56gpu::VertBuf *CurvesModule::drw_curves_ensure_dummy_vbo()
57{
59 uint dummy_id = GPU_vertformat_attr_add(&format, "dummy", gpu::VertAttrType::SFLOAT_32_32_32_32);
60
63
64 const float vert[4] = {0.0f, 0.0f, 0.0f, 0.0f};
66 GPU_vertbuf_attr_fill(vbo, dummy_id, vert);
67 /* Create vbo immediately to bind to texture buffer. */
68 GPU_vertbuf_use(vbo);
69 return vbo;
70}
71
72void DRW_curves_init(DRWData *drw_data)
73{
74 if (drw_data == nullptr) {
75 drw_data = drw_get().data;
76 }
77 if (drw_data->curves_module == nullptr) {
78 drw_data->curves_module = MEM_new<CurvesModule>("CurvesModule");
79 }
80}
81
83{
84 drw_data->curves_module->init();
85}
86
88{
89 MEM_delete(curves_module);
90}
91
92void CurvesModule::dispatch(const int curve_count, PassSimple::Sub &pass)
93{
94 /* Note that the GPU_max_work_group_count can be INT_MAX.
95 * Promote to 64bit int to avoid overflow. */
96 const int64_t max_strands_per_call = int64_t(GPU_max_work_group_count(0)) *
98 int strands_start = 0;
99 while (strands_start < curve_count) {
100 int batch_strands_len = std::min(int64_t(curve_count - strands_start), max_strands_per_call);
101 pass.push_constant("curves_start", strands_start);
102 pass.push_constant("curves_count", batch_strands_len);
103 pass.dispatch(divide_ceil_u(batch_strands_len, CURVES_PER_THREADGROUP));
104 strands_start += batch_strands_len;
105 }
106}
107
109 const int point_count,
110 CurvesEvalCache &cache,
111 bool is_ribbon,
112 bool has_cyclic)
113{
114 int element_count = is_ribbon ? (point_count + curve_count) : (point_count - curve_count);
115 if (has_cyclic) {
116 element_count += curve_count;
117 }
118 gpu::VertBufPtr indirection_buf = gpu::VertBuf::device_only<int>(element_count);
119
120 PassSimple::Sub &pass = refine.sub("Topology");
122 pass.bind_ssbo("evaluated_offsets_buf", cache.evaluated_points_by_curve_buf);
123 pass.bind_ssbo("curves_cyclic_buf", cache.curves_cyclic_buf);
124 pass.bind_ssbo("indirection_buf", indirection_buf);
125 pass.push_constant("is_ribbon_topology", is_ribbon);
126 pass.push_constant("use_cyclic", has_cyclic);
127 dispatch(curve_count, pass);
128
129 return indirection_buf;
130}
131
132void CurvesModule::evaluate_curve_attribute(const bool has_catmull,
133 const bool has_bezier,
134 const bool has_poly,
135 const bool has_nurbs,
136 const bool has_cyclic,
137 const int curve_count,
138 CurvesEvalCache &cache,
139 CurvesEvalShader shader_type,
140 gpu::VertBufPtr input_buf,
141 gpu::VertBufPtr &output_buf,
142 gpu::VertBuf *input2_buf /* = nullptr */,
143 float4x4 transform /* = float4x4::identity() */)
144{
145 BLI_assert(input_buf != nullptr);
146 BLI_assert(output_buf != nullptr);
147
148 gpu::Shader *shader = DRW_shader_curves_refine_get(shader_type);
149
150 const char *pass_name = nullptr;
151
152 switch (shader_type) {
154 pass_name = "Position";
155 break;
157 pass_name = "Float Attribute";
158 break;
160 pass_name = "Float2 Attribute";
161 break;
163 pass_name = "Float3 Attribute";
164 break;
166 pass_name = "Float4 Attribute";
167 break;
169 pass_name = "Length-Intercept Attributes";
170 break;
171 }
172
173 PassSimple::Sub &pass = refine.sub(pass_name);
179
180 switch (shader_type) {
182 pass.bind_ssbo(POINT_POSITIONS_SLOT, input_buf);
183 pass.bind_ssbo(POINT_RADII_SLOT, input2_buf);
185 /* Move ownership of the radius input vbo to the module. */
186 this->transient_buffers.append(gpu::VertBufPtr(input2_buf));
187 break;
192 pass.bind_ssbo(POINT_ATTR_SLOT, input_buf);
193 pass.bind_ssbo(EVALUATED_ATTR_SLOT, output_buf);
194 break;
199 /* Synchronize positions reads. */
201 break;
202 }
203
204 if (has_catmull) {
205 PassSimple::Sub &sub = pass.sub("Catmull-Rom");
206 sub.specialize_constant(shader, "evaluated_type", int(CURVE_TYPE_CATMULL_ROM));
207 sub.shader_set(shader);
208 /* Dummy, not used for Catmull-Rom. */
209 sub.bind_ssbo("handles_positions_left_buf", this->dummy_vbo);
210 sub.bind_ssbo("handles_positions_right_buf", this->dummy_vbo);
211 sub.bind_ssbo("bezier_offsets_buf", this->dummy_vbo);
212 /* Bake object transform for legacy hair particle. */
213 sub.push_constant("transform", transform);
214 sub.push_constant("use_cyclic", has_cyclic);
215 dispatch(curve_count, sub);
216 }
217
218 if (has_bezier) {
219 PassSimple::Sub &sub = pass.sub("Bezier");
220 sub.specialize_constant(shader, "evaluated_type", int(CURVE_TYPE_BEZIER));
221 sub.shader_set(shader);
222 sub.bind_ssbo("handles_positions_left_buf", cache.handles_positions_left_buf);
223 sub.bind_ssbo("handles_positions_right_buf", cache.handles_positions_right_buf);
224 sub.bind_ssbo("bezier_offsets_buf", cache.bezier_offsets_buf);
225 /* Bake object transform for legacy hair particle. */
226 sub.push_constant("transform", transform);
227 sub.push_constant("use_cyclic", has_cyclic);
228 dispatch(curve_count, sub);
229 }
230
231 if (has_nurbs) {
232 PassSimple::Sub &sub = pass.sub("Nurbs");
233 sub.specialize_constant(shader, "evaluated_type", int(CURVE_TYPE_NURBS));
234 sub.shader_set(shader);
235 sub.bind_ssbo("curves_resolution_buf", cache.curves_order_buf);
236 sub.bind_ssbo("handles_positions_left_buf", cache.basis_cache_buf);
237 sub.bind_ssbo("handles_positions_right_buf",
238 cache.control_weights_buf.get() ? cache.control_weights_buf :
239 cache.basis_cache_buf);
240 sub.bind_ssbo("bezier_offsets_buf", cache.basis_cache_offset_buf);
241 sub.push_constant("use_point_weight", cache.control_weights_buf.get() != nullptr);
242 /* Bake object transform for legacy hair particle. */
243 sub.push_constant("transform", transform);
244 sub.push_constant("use_cyclic", has_cyclic);
245 dispatch(curve_count, sub);
246 }
247
248 if (has_poly) {
249 PassSimple::Sub &sub = pass.sub("Poly");
250 sub.specialize_constant(shader, "evaluated_type", int(CURVE_TYPE_POLY));
251 sub.shader_set(shader);
252 /* Dummy, not used for Poly. */
253 sub.bind_ssbo("curves_resolution_buf", this->dummy_vbo);
254 sub.bind_ssbo("handles_positions_left_buf", this->dummy_vbo);
255 sub.bind_ssbo("handles_positions_right_buf", this->dummy_vbo);
256 sub.bind_ssbo("bezier_offsets_buf", this->dummy_vbo);
257 /* Bake object transform for legacy hair particle. */
258 sub.push_constant("transform", transform);
259 sub.push_constant("use_cyclic", has_cyclic);
260 dispatch(curve_count, sub);
261 }
262
263 /* Move ownership of the input vbo to the module. */
264 this->transient_buffers.append(std::move(input_buf));
265}
266
268 const int curve_count,
269 CurvesEvalCache &cache)
270{
272
273 PassSimple::Sub &pass = refine.sub("Length-Intercept Attributes");
274 pass.shader_set(shader);
280
285 /* Bake object transform for legacy hair particle. */
286 pass.push_constant("use_cyclic", has_cyclic);
287 dispatch(curve_count, pass);
288}
289
290static int attribute_index_in_material(const GPUMaterial *gpu_material,
291 const StringRef name,
292 bool is_curve_length = false,
293 bool is_curve_intercept = false)
294{
295 if (!gpu_material) {
296 return -1;
297 }
298
299 int index = 0;
300
301 ListBase gpu_attrs = GPU_material_attributes(gpu_material);
302 LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) {
303 if (gpu_attr->is_hair_length == true) {
304 if (gpu_attr->is_hair_length == is_curve_length) {
305 return index;
306 }
307 }
308 else if (gpu_attr->is_hair_intercept == true) {
309 if (gpu_attr->is_hair_intercept == is_curve_intercept) {
310 return index;
311 }
312 }
313 else if (gpu_attr->name == name) {
314 return index;
315 }
316 index++;
317 }
318
319 return -1;
320}
321
323{
325
326 /* TODO(fclem): Remove Global access. */
328
329 /* NOTE: This also update legacy hairs too as they populate the same pass. */
330 manager.submit(module.refine);
332
333 module.transient_buffers.clear();
334
335 /* Make sure calling this function again will not subdivide the same data. */
336 module.refine.init();
337
339}
340
341/* New Draw Manager. */
342
344{
347
348 CurvesEvalCache &cache = curves_get_eval_cache(curves);
349 cache.ensure_positions(module, curves.geometry.wrap());
350
351 return cache.evaluated_pos_rad_buf.get();
352}
353
354static std::optional<StringRef> get_first_uv_name(const bke::AttributeAccessor &attributes)
355{
356 std::optional<StringRef> name;
357 attributes.foreach_attribute([&](const bke::AttributeIter &iter) {
358 if (iter.data_type == bke::AttrType::Float2) {
359 name = iter.name;
360 iter.stop();
361 }
362 });
363 return name;
364}
365
366/* Return true if attribute exists in shader. */
367static bool set_attribute_type(const GPUMaterial *gpu_material,
368 const StringRef name,
369 CurvesInfosBuf &curves_infos,
370 const bool is_point_domain)
371{
372 /* Some attributes may not be used in the shader anymore and were not garbage collected yet, so
373 * we need to find the right index for this attribute as uniforms defining the scope of the
374 * attributes are based on attribute loading order, which is itself based on the material's
375 * attributes. */
376 const int index = attribute_index_in_material(gpu_material, name);
377 if (index == -1) {
378 return false;
379 }
380 curves_infos.is_point_attribute[index][0] = is_point_domain;
381 return true;
382}
383
384template<typename PassT>
387 CurvesEvalCache &cache,
388 const int face_per_segment,
389 GPUMaterial *gpu_material,
390 gpu::VertBufPtr &indirection_buf,
391 const std::optional<StringRef> uv_name)
392{
393 /* Ensure we have no unbound resources.
394 * Required for Vulkan.
395 * Fixes issues with certain GL drivers not drawing anything. */
396 sub_ps.bind_texture("u", module.dummy_vbo);
397 sub_ps.bind_texture("au", module.dummy_vbo);
398 sub_ps.bind_texture("a", module.dummy_vbo);
399 sub_ps.bind_texture("c", module.dummy_vbo);
400 sub_ps.bind_texture("ac", module.dummy_vbo);
401 sub_ps.bind_texture("l", module.dummy_vbo);
402 sub_ps.bind_texture("i", module.dummy_vbo);
403 if (gpu_material) {
404 ListBase attr_list = GPU_material_attributes(gpu_material);
406 for (const GPUMaterialAttribute *attr : attrs) {
407 sub_ps.bind_texture(attr->input_name, module.dummy_vbo);
408 }
409 }
410
411 CurvesInfosBuf &curves_infos = module.ubo_pool.alloc();
412
413 {
414 /* TODO(fclem): Compute only if needed. */
415 const int index = attribute_index_in_material(gpu_material, "", true, false);
416 if (index != -1) {
417 sub_ps.bind_texture("l", cache.curves_length_buf);
418 curves_infos.is_point_attribute[index][0] = false;
419 }
420 }
421 {
422 /* TODO(fclem): Compute only if needed. */
423 const int index = attribute_index_in_material(gpu_material, "", false, true);
424 if (index != -1) {
425 sub_ps.bind_texture("i", cache.evaluated_time_buf);
426 curves_infos.is_point_attribute[index][0] = true;
427 }
428 }
429
430 const VectorSet<std::string> &attrs = cache.attr_used;
431 for (const int i : attrs.index_range()) {
432 const StringRef name = attrs[i];
433 char sampler_name[32];
435
436 if (cache.attributes_point_domain[i]) {
437 if (!cache.evaluated_attributes_buf[i]) {
438 continue;
439 }
440 if (set_attribute_type(gpu_material, name, curves_infos, true)) {
441 sub_ps.bind_texture(sampler_name, cache.evaluated_attributes_buf[i]);
442 }
443 if (name == uv_name) {
444 if (set_attribute_type(gpu_material, "", curves_infos, true)) {
445 sub_ps.bind_texture("a", cache.evaluated_attributes_buf[i]);
446 }
447 }
448 }
449 else {
450 if (!cache.curve_attributes_buf[i]) {
451 continue;
452 }
453 if (set_attribute_type(gpu_material, name, curves_infos, false)) {
454 sub_ps.bind_texture(sampler_name, cache.curve_attributes_buf[i]);
455 }
456 if (name == uv_name) {
457 if (set_attribute_type(gpu_material, "", curves_infos, false)) {
458 sub_ps.bind_texture("a", cache.curve_attributes_buf[i]);
459 }
460 }
461 }
462 }
463
464 curves_infos.half_cylinder_face_count = face_per_segment;
465 curves_infos.vertex_per_segment = face_per_segment < 2 ? (face_per_segment + 1) :
466 ((face_per_segment + 1) * 2 + 1);
467
468 curves_infos.push_update();
469
470 sub_ps.bind_ubo("drw_curves", curves_infos);
471 sub_ps.bind_texture("curves_pos_rad_buf", cache.evaluated_pos_rad_buf);
472 sub_ps.bind_texture("curves_indirection_buf", indirection_buf);
473}
474
477 CurvesEvalCache &cache,
478 const int face_per_segment,
479 GPUMaterial *gpu_material,
480 gpu::VertBufPtr &indirection_buf,
481 const std::optional<StringRef> active_uv_name)
482{
484 sub_ps, module, cache, face_per_segment, gpu_material, indirection_buf, active_uv_name);
485}
486
488 CurvesModule &module,
489 CurvesEvalCache &cache,
490 const int face_per_segment,
491 GPUMaterial *gpu_material,
492 gpu::VertBufPtr &indirection_buf,
493 const std::optional<StringRef> active_uv_name)
494{
496 sub_ps, module, cache, face_per_segment, gpu_material, indirection_buf, active_uv_name);
497}
498
499template<typename PassT>
500gpu::Batch *curves_sub_pass_setup_implementation(PassT &sub_ps,
501 const Scene *scene,
502 Object *ob,
503 const char *&r_error,
504 GPUMaterial *gpu_material = nullptr)
505{
506 BLI_assert(ob->type == OB_CURVES);
508 const bke::CurvesGeometry &curves = curves_id.geometry.wrap();
509
510 const int face_per_segment = (scene->r.hair_type == SCE_HAIR_SHAPE_STRAND) ? 0 :
511 (scene->r.hair_type == SCE_HAIR_SHAPE_CYLINDER) ? 3 :
512 1;
513
514 CurvesEvalCache &curves_cache = curves_get_eval_cache(curves_id);
515
516 if (curves.curves_num() == 0) {
517 /* Nothing to draw. Just return an empty drawcall that will be skipped. */
518 bool unused_error = false;
519 return curves_cache.batch_get(0, 0, face_per_segment, false, unused_error);
520 }
521
523
524 curves_cache.ensure_positions(module, curves);
525 curves_cache.ensure_attributes(module, curves, gpu_material);
526
527 gpu::VertBufPtr &indirection_buf = curves_cache.indirection_buf_get(
528 module, curves, face_per_segment);
529
530 const std::optional<StringRef> uv_name = get_first_uv_name(
531 curves_id.geometry.wrap().attributes());
532
534 sub_ps, module, curves_cache, face_per_segment, gpu_material, indirection_buf, uv_name);
535
536 bool error = false;
537 gpu::Batch *batch = curves_cache.batch_get(curves.evaluated_points_num(),
538 curves.curves_num(),
539 face_per_segment,
540 curves.has_cyclic_curve(),
541 error);
542 if (error) {
543 r_error = RPT_(
544 "Error: Curves object contains too many points. "
545 "Reduce curve resolution or curve count to fix this issue.\n");
546 }
547 return batch;
548}
549
551 const Scene *scene,
552 Object *ob,
553 const char *&r_error,
554 GPUMaterial *gpu_material)
555{
556 return curves_sub_pass_setup_implementation(ps, scene, ob, r_error, gpu_material);
557}
558
560 const Scene *scene,
561 Object *ob,
562 const char *&r_error,
563 GPUMaterial *gpu_material)
564{
565 return curves_sub_pass_setup_implementation(ps, scene, ob, r_error, gpu_material);
566}
567
568} // namespace blender::draw
Low-level operations for curves.
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
MINLINE uint divide_ceil_u(uint a, uint b)
unsigned int uint
#define RPT_(msgid)
@ OB_CURVES
@ SCE_HAIR_SHAPE_CYLINDER
@ SCE_HAIR_SHAPE_STRAND
void DRW_submission_end()
void DRW_submission_start()
T & DRW_object_get_data_for_drawing(const Object &object)
int GPU_max_work_group_count(int index)
ListBase GPU_material_attributes(const GPUMaterial *material)
@ GPU_BARRIER_SHADER_STORAGE
Definition GPU_state.hh:48
void GPU_memory_barrier(GPUBarrier barrier)
Definition gpu_state.cc:326
void GPU_vertbuf_use(blender::gpu::VertBuf *)
void GPU_vertbuf_attr_fill(blender::gpu::VertBuf *, uint a_idx, const void *data)
blender::gpu::VertBuf * GPU_vertbuf_create_with_format_ex(const GPUVertFormat &format, GPUUsageType usage)
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
@ GPU_USAGE_STATIC
@ GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
long long int int64_t
IndexRange index_range() const
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
void submit(PassSimple &pass, View &view)
void shader_set(gpu::Shader *shader)
void specialize_constant(gpu::Shader *shader, const char *name, const float &data)
PassBase< DrawCommandBufType > & sub(const char *name)
Definition draw_pass.hh:690
void barrier(GPUBarrier type)
void push_constant(const char *name, const float &data)
void bind_ssbo(const char *name, gpu::StorageBuf *buffer)
detail::PassBase< command::DrawCommandBuf > Sub
Definition draw_pass.hh:499
static VertBufPtr device_only(uint size)
DRWContext & drw_get()
#define CURVES_PER_THREADGROUP
#define POINT_ATTR_SLOT
#define EVALUATED_ATTR_SLOT
#define CURVE_TYPE_SLOT
#define POINT_RADII_SLOT
#define POINTS_BY_CURVES_SLOT
#define EVALUATED_POS_RAD_SLOT
#define EVALUATED_TIME_SLOT
#define EVALUATED_POINT_SLOT
#define CURVES_LENGTH_SLOT
#define CURVE_CYCLIC_SLOT
#define POINT_POSITIONS_SLOT
#define CURVE_RESOLUTION_SLOT
blender::gpu::Shader * DRW_shader_curves_refine_get(blender::draw::CurvesEvalShader type)
blender::gpu::Shader * DRW_shader_curves_topology_get()
struct @021025263243242147216143265077100330027142264337::@225245033123204053237120173316075113304004012000 batch
format
static void error(const char *str)
void DRW_curves_module_free(draw::CurvesModule *module)
void curves_bind_resources(PassMain::Sub &sub_ps, CurvesModule &module, CurvesEvalCache &cache, const int face_per_segment, GPUMaterial *gpu_material, gpu::VertBufPtr &indirection_buf, const std::optional< StringRef > active_uv_name)
static int attribute_index_in_material(const GPUMaterial *gpu_material, const StringRef name, bool is_curve_length=false, bool is_curve_intercept=false)
CurvesEvalCache & curves_get_eval_cache(Curves &curves_id)
void DRW_curves_init(DRWData *drw_data=nullptr)
static std::optional< StringRef > get_first_uv_name(const bke::AttributeAccessor &attributes)
gpu::Batch * curves_sub_pass_setup(PassMain::Sub &ps, const Scene *scene, Object *ob, const char *&r_error, GPUMaterial *gpu_material=nullptr)
gpu::VertBuf * curves_pos_buffer_get(Object *object)
void DRW_curves_update(draw::Manager &manager)
void drw_curves_get_attribute_sampler_name(const StringRef layer_name, char r_sampler_name[32])
void DRW_curves_begin_sync(DRWData *drw_data)
static bool set_attribute_type(const GPUMaterial *gpu_material, const StringRef name, CurvesInfosBuf &curves_infos, const bool is_point_domain)
gpu::Batch * curves_sub_pass_setup_implementation(PassT &sub_ps, const Scene *scene, Object *ob, const char *&r_error, GPUMaterial *gpu_material=nullptr)
UniformBuffer< CurvesInfos > CurvesInfosBuf
void curves_bind_resources_implementation(PassT &sub_ps, CurvesModule &module, CurvesEvalCache &cache, const int face_per_segment, GPUMaterial *gpu_material, gpu::VertBufPtr &indirection_buf, const std::optional< StringRef > uv_name)
std::unique_ptr< gpu::VertBuf, gpu::VertBufDeleter > VertBufPtr
MatBase< float, 4, 4 > float4x4
ListBaseWrapperTemplate< ListBase, T > ListBaseWrapper
static struct PyModuleDef module
Definition python.cpp:796
const char * name
uint4 is_point_attribute[DRW_ATTRIBUTE_PER_CURVES_MAX]
CurvesGeometry geometry
DRWData * data
blender::draw::CurvesModule * curves_module
struct RenderData r
gpu::VertBufPtr evaluated_attributes_buf[GPU_MAX_ATTR]
std::array< bool, GPU_MAX_ATTR > attributes_point_domain
gpu::Batch * batch_get(int evaluated_point_count, int curve_count, int face_per_segment, bool use_cyclic, bool &r_over_limit)
gpu::VertBufPtr & indirection_buf_get(CurvesModule &module, const bke::CurvesGeometry &curves, int face_per_segment)
void ensure_attributes(struct CurvesModule &module, const bke::CurvesGeometry &curves, const GPUMaterial *gpu_material)
void ensure_positions(CurvesModule &module, const bke::CurvesGeometry &curves)
gpu::VertBufPtr curve_attributes_buf[GPU_MAX_ATTR]
VectorSet< std::string > attr_used
void evaluate_curve_attribute(bool has_catmull, bool has_bezier, bool has_poly, bool has_nurbs, bool has_cyclic, int curve_count, CurvesEvalCache &cache, CurvesEvalShader shader_type, gpu::VertBufPtr input_buf, gpu::VertBufPtr &output_buf, gpu::VertBuf *input2_buf=nullptr, float4x4 transform=float4x4::identity())
Vector< gpu::VertBufPtr > transient_buffers
gpu::VertBufPtr evaluate_topology_indirection(const int curve_count, const int point_count, CurvesEvalCache &cache, bool is_ribbon, bool has_cyclic)
void evaluate_curve_length_intercept(bool has_cyclic, int curve_count, CurvesEvalCache &cache)
Vector< std::unique_ptr< CurvesInfosBuf > > ubos
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4238