Geometry Node: Index of Nearest #104619
@ -865,29 +865,40 @@ Unfortunate Corner Cases
|
||||
Besides all expected cases listed above, there are a few others that should not be
|
||||
an issue but, due to internal implementation details, currently are:
|
||||
|
||||
- ``Object.hide_viewport``, ``Object.hide_select`` and ``Object.hide_render``:
|
||||
Setting any of those Booleans will trigger a rebuild of Collection caches,
|
||||
thus breaking any current iteration over ``Collection.all_objects``.
|
||||
|
||||
Collection Objects
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Changing: ``Object.hide_viewport``, ``Object.hide_select`` or ``Object.hide_render``
|
||||
will trigger a rebuild of Collection caches, thus breaking any current iteration over ``Collection.all_objects``.
|
||||
|
||||
.. rubric:: Do not:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# `all_objects` is an iterator. Using it directly while performing operations on its members that will update
|
||||
# the memory accessed by the `all_objects` iterator will lead to invalid memory accesses and crashes.
|
||||
for object in bpy.data.collections["Collection"].all_objects:
|
||||
object.hide_viewport = True
|
||||
|
||||
|
||||
.. rubric:: Do not:
|
||||
.. rubric:: Do:
|
||||
|
||||
.. code-block:: python
|
||||
.. code-block:: python
|
||||
|
||||
# `all_objects` is an iterator. Using it directly while performing operations on its members that will update
|
||||
# the memory accessed by the `all_objects` iterator will lead to invalid memory accesses and crashes.
|
||||
for object in bpy.data.collections["Collection"].all_objects:
|
||||
object.hide_viewport = True
|
||||
# `all_objects[:]` is an independent list generated from the iterator. As long as no objects are deleted,
|
||||
# its content will remain valid even if the data accessed by the `all_objects` iterator is modified.
|
||||
for object in bpy.data.collections["Collection"].all_objects[:]:
|
||||
object.hide_viewport = True
|
||||
|
||||
|
||||
.. rubric:: Do:
|
||||
Data-Blocks Renaming During Iteration
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# `all_objects[:]` is an independent list generated from the iterator. As long as no objects are deleted,
|
||||
# its content will remain valid even if the data accessed by the `all_objects` iterator is modified.
|
||||
for object in bpy.data.collections["Collection"].all_objects[:]:
|
||||
object.hide_viewport = True
|
||||
Data-blocks accessed from ``bpy.data`` are sorted when their name is set.
|
||||
Any loop that iterates of a data such as ``bpy.data.objects`` for example,
|
||||
and sets the objects ``name`` must get all items from the iterator first (typically by converting to a list or tuple)
|
||||
to avoid missing some objects and iterating over others multiple times.
|
||||
|
||||
|
||||
sys.exit
|
||||
|
@ -903,13 +903,14 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext()
|
||||
auto extensions_available = getExtensionsAvailable();
|
||||
|
||||
vector<const char *> layers_enabled;
|
||||
if (m_debug) {
|
||||
enableLayer(layers_available, layers_enabled, VkLayer::KHRONOS_validation, m_debug);
|
||||
}
|
||||
|
||||
vector<const char *> extensions_device;
|
||||
vector<const char *> extensions_enabled;
|
||||
|
||||
if (m_debug) {
|
||||
enableLayer(layers_available, layers_enabled, VkLayer::KHRONOS_validation, m_debug);
|
||||
requireExtension(extensions_available, extensions_enabled, VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
if (use_window_surface) {
|
||||
const char *native_surface_extension_name = getPlatformSpecificSurfaceExtension();
|
||||
|
||||
|
@ -99,7 +99,12 @@ static bool use_xwayland_hack = false;
|
||||
|
||||
using namespace std;
|
||||
|
||||
GHOST_SystemX11::GHOST_SystemX11() : GHOST_System(), m_xkb_descr(nullptr), m_start_time(0)
|
||||
GHOST_SystemX11::GHOST_SystemX11()
|
||||
: GHOST_System(),
|
||||
m_xkb_descr(nullptr),
|
||||
m_start_time(0),
|
||||
m_keyboard_vector{0},
|
||||
m_keycode_last_repeat_key(uint(-1))
|
||||
{
|
||||
XInitThreads();
|
||||
m_display = XOpenDisplay(nullptr);
|
||||
@ -897,7 +902,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
#endif /* WITH_X11_XINPUT */
|
||||
switch (xe->type) {
|
||||
case Expose: {
|
||||
XExposeEvent &xee = xe->xexpose;
|
||||
const XExposeEvent &xee = xe->xexpose;
|
||||
|
||||
if (xee.count == 0) {
|
||||
/* Only generate a single expose event
|
||||
@ -909,7 +914,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
}
|
||||
|
||||
case MotionNotify: {
|
||||
XMotionEvent &xme = xe->xmotion;
|
||||
const XMotionEvent &xme = xe->xmotion;
|
||||
|
||||
bool is_tablet = window->GetTabletData().Active != GHOST_kTabletModeNone;
|
||||
|
||||
@ -1235,7 +1240,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
|
||||
case ButtonPress:
|
||||
case ButtonRelease: {
|
||||
XButtonEvent &xbe = xe->xbutton;
|
||||
const XButtonEvent &xbe = xe->xbutton;
|
||||
GHOST_TButton gbmask = GHOST_kButtonMaskLeft;
|
||||
GHOST_TEventType type = (xbe.type == ButtonPress) ? GHOST_kEventButtonDown :
|
||||
GHOST_kEventButtonUp;
|
||||
@ -1290,14 +1295,14 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
|
||||
/* change of size, border, layer etc. */
|
||||
case ConfigureNotify: {
|
||||
// XConfigureEvent & xce = xe->xconfigure;
|
||||
// const XConfigureEvent & xce = xe->xconfigure;
|
||||
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window);
|
||||
break;
|
||||
}
|
||||
|
||||
case FocusIn:
|
||||
case FocusOut: {
|
||||
XFocusChangeEvent &xfe = xe->xfocus;
|
||||
const XFocusChangeEvent &xfe = xe->xfocus;
|
||||
|
||||
/* TODO: make sure this is the correct place for activate/deactivate */
|
||||
// printf("X: focus %s for window %d\n",
|
||||
@ -1385,7 +1390,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
* (really crossing between windows) since some window-managers
|
||||
* also send grab/un-grab crossings for mouse-wheel events.
|
||||
*/
|
||||
XCrossingEvent &xce = xe->xcrossing;
|
||||
const XCrossingEvent &xce = xe->xcrossing;
|
||||
if (xce.mode == NotifyNormal) {
|
||||
g_event = new GHOST_EventCursor(getMilliSeconds(),
|
||||
GHOST_kEventCursorMove,
|
||||
@ -2376,7 +2381,7 @@ class DialogData {
|
||||
}
|
||||
|
||||
/* Is the mouse inside the given button */
|
||||
bool isInsideButton(XEvent &e, uint button_num)
|
||||
bool isInsideButton(const XEvent &e, uint button_num)
|
||||
{
|
||||
return (
|
||||
(e.xmotion.y > int(height - padding_y - button_height)) &&
|
||||
|
@ -21,22 +21,21 @@ GHOST_Window::GHOST_Window(uint32_t width,
|
||||
const bool wantStereoVisual,
|
||||
const bool /*exclusive*/)
|
||||
: m_drawingContextType(GHOST_kDrawingContextTypeNone),
|
||||
m_userData(nullptr),
|
||||
m_cursorVisible(true),
|
||||
m_cursorGrab(GHOST_kGrabDisable),
|
||||
m_cursorGrabAxis(GHOST_kAxisNone),
|
||||
m_cursorGrabInitPos{0, 0},
|
||||
m_cursorGrabAccumPos{0, 0},
|
||||
m_cursorShape(GHOST_kStandardCursorDefault),
|
||||
m_progressBarVisible(false),
|
||||
m_canAcceptDragOperation(false),
|
||||
m_isUnsavedChanges(false),
|
||||
m_wantStereoVisual(wantStereoVisual),
|
||||
m_nativePixelSize(1.0f),
|
||||
m_context(new GHOST_ContextNone(false))
|
||||
|
||||
{
|
||||
m_isUnsavedChanges = false;
|
||||
m_canAcceptDragOperation = false;
|
||||
|
||||
m_progressBarVisible = false;
|
||||
|
||||
m_cursorGrabAccumPos[0] = 0;
|
||||
m_cursorGrabAccumPos[1] = 0;
|
||||
|
||||
m_nativePixelSize = 1.0f;
|
||||
|
||||
m_fullScreen = state == GHOST_kWindowStateFullScreen;
|
||||
if (m_fullScreen) {
|
||||
|
@ -55,7 +55,7 @@ struct BasisCache {
|
||||
class CurvesGeometryRuntime {
|
||||
public:
|
||||
/** Implicit sharing user count for #CurvesGeometry::curve_offsets. */
|
||||
ImplicitSharingInfo *curve_offsets_sharing_info = nullptr;
|
||||
const ImplicitSharingInfo *curve_offsets_sharing_info = nullptr;
|
||||
|
||||
/**
|
||||
* The cached number of curves with each type. Unlike other caches here, this is not computed
|
||||
|
@ -98,7 +98,7 @@ struct MeshRuntime {
|
||||
std::mutex render_mutex;
|
||||
|
||||
/** Implicit sharing user count for #Mesh::poly_offset_indices. */
|
||||
ImplicitSharingInfoHandle *poly_offsets_sharing_info;
|
||||
const ImplicitSharingInfoHandle *poly_offsets_sharing_info;
|
||||
|
||||
/**
|
||||
* A cache of bounds shared between data-blocks with unchanged positions. When changing positions
|
||||
|
@ -2376,9 +2376,9 @@ class CustomDataLayerImplicitSharing : public ImplicitSharingInfo {
|
||||
};
|
||||
|
||||
/** Create a #ImplicitSharingInfo that takes ownership of the data. */
|
||||
static ImplicitSharingInfo *make_implicit_sharing_info_for_layer(const eCustomDataType type,
|
||||
const void *data,
|
||||
const int totelem)
|
||||
static const ImplicitSharingInfo *make_implicit_sharing_info_for_layer(const eCustomDataType type,
|
||||
const void *data,
|
||||
const int totelem)
|
||||
{
|
||||
return MEM_new<CustomDataLayerImplicitSharing>(__func__, data, totelem, type);
|
||||
}
|
||||
|
@ -431,7 +431,9 @@ CDataFileLayer *cdf_layer_add(CDataFile *cdf, int type, const char *name, size_t
|
||||
|
||||
/* expand array */
|
||||
newlayer = MEM_calloc_arrayN((cdf->totlayer + 1), sizeof(CDataFileLayer), "CDataFileLayer");
|
||||
memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer) * cdf->totlayer);
|
||||
if (cdf->totlayer > 0) {
|
||||
memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer) * cdf->totlayer);
|
||||
}
|
||||
cdf->layer = newlayer;
|
||||
|
||||
cdf->totlayer++;
|
||||
|
@ -63,20 +63,10 @@ BLI_INLINE void mesh_calc_tessellation_for_face_impl(const Span<int> corner_vert
|
||||
MLoopTri *mlt_a = mlt++;
|
||||
create_tri(0, 2, 3);
|
||||
MLoopTri *mlt_b = mlt;
|
||||
|
||||
if (UNLIKELY(face_normal ? is_quad_flip_v3_first_third_fast_with_normal(
|
||||
/* Simpler calculation (using the normal). */
|
||||
positions[corner_verts[mlt_a->tri[0]]],
|
||||
positions[corner_verts[mlt_a->tri[1]]],
|
||||
positions[corner_verts[mlt_a->tri[2]]],
|
||||
positions[corner_verts[mlt_b->tri[2]]],
|
||||
normal_precalc) :
|
||||
is_quad_flip_v3_first_third_fast(
|
||||
/* Expensive calculation (no normal). */
|
||||
positions[corner_verts[mlt_a->tri[0]]],
|
||||
positions[corner_verts[mlt_a->tri[1]]],
|
||||
positions[corner_verts[mlt_a->tri[2]]],
|
||||
positions[corner_verts[mlt_b->tri[2]]]))) {
|
||||
if (UNLIKELY(is_quad_flip_v3_first_third_fast(positions[corner_verts[mlt_a->tri[0]]],
|
||||
positions[corner_verts[mlt_a->tri[1]]],
|
||||
positions[corner_verts[mlt_a->tri[2]]],
|
||||
positions[corner_verts[mlt_b->tri[2]]]))) {
|
||||
/* Flip out of degenerate 0-2 state. */
|
||||
mlt_a->tri[2] = mlt_b->tri[2];
|
||||
mlt_b->tri[0] = mlt_a->tri[1];
|
||||
|
@ -110,11 +110,11 @@ void *resize_trivial_array_impl(void *old_data,
|
||||
int64_t old_size,
|
||||
int64_t new_size,
|
||||
int64_t alignment,
|
||||
ImplicitSharingInfo **sharing_info);
|
||||
const ImplicitSharingInfo **sharing_info);
|
||||
void *make_trivial_data_mutable_impl(void *old_data,
|
||||
int64_t size,
|
||||
int64_t alignment,
|
||||
ImplicitSharingInfo **sharing_info);
|
||||
const ImplicitSharingInfo **sharing_info);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@ -124,9 +124,9 @@ void *make_trivial_data_mutable_impl(void *old_data,
|
||||
*/
|
||||
template<typename T>
|
||||
void copy_shared_pointer(T *src_ptr,
|
||||
ImplicitSharingInfo *src_sharing_info,
|
||||
const ImplicitSharingInfo *src_sharing_info,
|
||||
T **r_dst_ptr,
|
||||
ImplicitSharingInfo **r_dst_sharing_info)
|
||||
const ImplicitSharingInfo **r_dst_sharing_info)
|
||||
{
|
||||
*r_dst_ptr = src_ptr;
|
||||
*r_dst_sharing_info = src_sharing_info;
|
||||
@ -139,7 +139,7 @@ void copy_shared_pointer(T *src_ptr,
|
||||
/**
|
||||
* Remove this reference to the shared data and remove dangling pointers.
|
||||
*/
|
||||
template<typename T> void free_shared_data(T **data, ImplicitSharingInfo **sharing_info)
|
||||
template<typename T> void free_shared_data(T **data, const ImplicitSharingInfo **sharing_info)
|
||||
{
|
||||
if (*sharing_info) {
|
||||
BLI_assert(*data != nullptr);
|
||||
@ -153,13 +153,15 @@ template<typename T> void free_shared_data(T **data, ImplicitSharingInfo **shari
|
||||
* Create an implicit sharing object that takes ownership of the data, allowing it to be shared.
|
||||
* When it is no longer used, the data is freed with #MEM_freeN, so it must be a trivial type.
|
||||
*/
|
||||
ImplicitSharingInfo *info_for_mem_free(void *data);
|
||||
const ImplicitSharingInfo *info_for_mem_free(void *data);
|
||||
|
||||
/**
|
||||
* Make data mutable (single-user) if it is shared. For trivially-copyable data only.
|
||||
*/
|
||||
template<typename T>
|
||||
void make_trivial_data_mutable(T **data, ImplicitSharingInfo **sharing_info, const int64_t size)
|
||||
void make_trivial_data_mutable(T **data,
|
||||
const ImplicitSharingInfo **sharing_info,
|
||||
const int64_t size)
|
||||
{
|
||||
*data = static_cast<T *>(
|
||||
detail::make_trivial_data_mutable_impl(*data, sizeof(T) * size, alignof(T), sharing_info));
|
||||
@ -171,7 +173,7 @@ void make_trivial_data_mutable(T **data, ImplicitSharingInfo **sharing_info, con
|
||||
*/
|
||||
template<typename T>
|
||||
void resize_trivial_array(T **data,
|
||||
ImplicitSharingInfo **sharing_info,
|
||||
const ImplicitSharingInfo **sharing_info,
|
||||
int64_t old_size,
|
||||
int64_t new_size)
|
||||
{
|
||||
|
@ -145,11 +145,6 @@ bool is_quad_flip_v3_first_third_fast(const float v1[3],
|
||||
const float v2[3],
|
||||
const float v3[3],
|
||||
const float v4[3]);
|
||||
bool is_quad_flip_v3_first_third_fast_with_normal(const float v1[3],
|
||||
const float v2[3],
|
||||
const float v3[3],
|
||||
const float v4[3],
|
||||
const float normal[3]);
|
||||
|
||||
/** \} */
|
||||
|
||||
|
@ -26,7 +26,7 @@ class MEMFreeImplicitSharing : public ImplicitSharingInfo {
|
||||
}
|
||||
};
|
||||
|
||||
ImplicitSharingInfo *info_for_mem_free(void *data)
|
||||
const ImplicitSharingInfo *info_for_mem_free(void *data)
|
||||
{
|
||||
return MEM_new<MEMFreeImplicitSharing>(__func__, data);
|
||||
}
|
||||
@ -36,7 +36,7 @@ namespace detail {
|
||||
void *make_trivial_data_mutable_impl(void *old_data,
|
||||
const int64_t size,
|
||||
const int64_t alignment,
|
||||
ImplicitSharingInfo **sharing_info)
|
||||
const ImplicitSharingInfo **sharing_info)
|
||||
{
|
||||
if (!old_data) {
|
||||
BLI_assert(size == 0);
|
||||
@ -59,7 +59,7 @@ void *resize_trivial_array_impl(void *old_data,
|
||||
const int64_t old_size,
|
||||
const int64_t new_size,
|
||||
const int64_t alignment,
|
||||
ImplicitSharingInfo **sharing_info)
|
||||
const ImplicitSharingInfo **sharing_info)
|
||||
{
|
||||
if (new_size == 0) {
|
||||
if (*sharing_info) {
|
||||
@ -79,7 +79,8 @@ void *resize_trivial_array_impl(void *old_data,
|
||||
|
||||
BLI_assert(old_size != 0);
|
||||
if ((*sharing_info)->is_mutable()) {
|
||||
if (auto *info = dynamic_cast<MEMFreeImplicitSharing *>(*sharing_info)) {
|
||||
if (auto *info = const_cast<MEMFreeImplicitSharing *>(
|
||||
dynamic_cast<const MEMFreeImplicitSharing *>(*sharing_info))) {
|
||||
/* If the array was allocated with the MEM allocator, we can use realloc directly, which
|
||||
* could theoretically give better performance if the data can be reused in place. */
|
||||
void *new_data = static_cast<int *>(MEM_reallocN(old_data, new_size));
|
||||
|
@ -5889,6 +5889,9 @@ bool is_quad_flip_v3_first_third_fast(const float v1[3],
|
||||
const float v3[3],
|
||||
const float v4[3])
|
||||
{
|
||||
/* NOTE: if the faces normal has been calculated it's possible to simplify the following checks,
|
||||
* however this means the solution may be different depending on the existence of normals
|
||||
* causing tessellation to be "unstable" depending on the existence of normals, see #106469. */
|
||||
float d_12[3], d_13[3], d_14[3];
|
||||
float cross_a[3], cross_b[3];
|
||||
sub_v3_v3v3(d_12, v2, v1);
|
||||
@ -5899,19 +5902,6 @@ bool is_quad_flip_v3_first_third_fast(const float v1[3],
|
||||
return dot_v3v3(cross_a, cross_b) > 0.0f;
|
||||
}
|
||||
|
||||
bool is_quad_flip_v3_first_third_fast_with_normal(const float v1[3],
|
||||
const float v2[3],
|
||||
const float v3[3],
|
||||
const float v4[3],
|
||||
const float normal[3])
|
||||
{
|
||||
float dir_v3v1[3], tangent[3];
|
||||
sub_v3_v3v3(dir_v3v1, v3, v1);
|
||||
cross_v3_v3v3(tangent, dir_v3v1, normal);
|
||||
const float dot = dot_v3v3(v1, tangent);
|
||||
return (dot_v3v3(v4, tangent) >= dot) || (dot_v3v3(v2, tangent) <= dot);
|
||||
}
|
||||
|
||||
float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3])
|
||||
{
|
||||
BLI_ASSERT_UNIT_V3(tan_l);
|
||||
|
@ -2728,7 +2728,7 @@ void svd_m4(float U[4][4], float s[4], float V[4][4], float A_[4][4])
|
||||
e[k + 1] += 1.0f;
|
||||
}
|
||||
e[k] = -e[k];
|
||||
if ((k + 1 < m) & (e[k] != 0.0f)) {
|
||||
if ((k + 1 < m) && (e[k] != 0.0f)) {
|
||||
float invek1;
|
||||
|
||||
/* Apply the transformation. */
|
||||
@ -2812,7 +2812,7 @@ void svd_m4(float U[4][4], float s[4], float V[4][4], float A_[4][4])
|
||||
/* If required, generate V. */
|
||||
|
||||
for (k = n - 1; k >= 0; k--) {
|
||||
if ((k < nrt) & (e[k] != 0.0f)) {
|
||||
if ((k < nrt) && (e[k] != 0.0f)) {
|
||||
for (j = k + 1; j < nu; j++) {
|
||||
float t = 0;
|
||||
for (i = k + 1; i < n; i++) {
|
||||
|
@ -1962,17 +1962,19 @@ static Face *cdt_tri_as_imesh_face(
|
||||
return facep;
|
||||
}
|
||||
|
||||
/* Like BLI_math's is_quad_flip_v3_first_third_fast_with_normal, with const double3's. */
|
||||
/* Like BLI_math's is_quad_flip_v3_first_third_fast, with const double3's. */
|
||||
static bool is_quad_flip_first_third(const double3 &v1,
|
||||
const double3 &v2,
|
||||
const double3 &v3,
|
||||
const double3 &v4,
|
||||
const double3 &normal)
|
||||
const double3 &v4)
|
||||
{
|
||||
double3 dir_v3v1 = v3 - v1;
|
||||
double3 tangent = math::cross(dir_v3v1, normal);
|
||||
double dot = math::dot(v1, tangent);
|
||||
return (math::dot(v4, tangent) >= dot) || (math::dot(v2, tangent) <= dot);
|
||||
const double3 d_12 = v2 - v1;
|
||||
const double3 d_13 = v3 - v1;
|
||||
const double3 d_14 = v4 - v1;
|
||||
|
||||
const double3 cross_a = math::cross(d_12, d_13);
|
||||
const double3 cross_b = math::cross(d_14, d_13);
|
||||
return math::dot(cross_a, cross_b) > 0.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2008,7 +2010,7 @@ static Array<Face *> polyfill_triangulate_poly(Face *f, IMeshArena *arena)
|
||||
int eo_23 = f->edge_orig[2];
|
||||
int eo_30 = f->edge_orig[3];
|
||||
Face *f0, *f1;
|
||||
if (UNLIKELY(is_quad_flip_first_third(v0->co, v1->co, v2->co, v3->co, f->plane->norm))) {
|
||||
if (UNLIKELY(is_quad_flip_first_third(v0->co, v1->co, v2->co, v3->co))) {
|
||||
f0 = arena->add_face({v0, v1, v3}, f->orig, {eo_01, -1, eo_30}, {false, false, false});
|
||||
f1 = arena->add_face({v1, v2, v3}, f->orig, {eo_12, eo_23, -1}, {false, false, false});
|
||||
}
|
||||
|
@ -37,22 +37,16 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
/* Declarations */
|
||||
/* Declarations. */
|
||||
|
||||
static int BLI_path_unc_prefix_len(const char *path);
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
/**
|
||||
* Return true if the path is absolute ie starts with a drive specifier
|
||||
* (eg A:\) or is a UNC path.
|
||||
*/
|
||||
static bool BLI_path_is_abs(const char *name);
|
||||
|
||||
static bool BLI_path_is_abs_win32(const char *name);
|
||||
#endif /* WIN32 */
|
||||
|
||||
// #define DEBUG_STRSIZE
|
||||
|
||||
/* implementation */
|
||||
|
||||
int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort *r_digits_len)
|
||||
{
|
||||
uint nums = 0, nume = 0;
|
||||
@ -102,9 +96,8 @@ int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort
|
||||
strcpy(tail, string + name_end);
|
||||
}
|
||||
if (head) {
|
||||
/* name_end points to last character of head,
|
||||
* make it +1 so null-terminator is nicely placed
|
||||
*/
|
||||
/* Name_end points to last character of head,
|
||||
* make it +1 so null-terminator is nicely placed. */
|
||||
BLI_strncpy(head, string, name_end + 1);
|
||||
}
|
||||
if (r_digits_len) {
|
||||
@ -119,8 +112,6 @@ void BLI_path_sequence_encode(
|
||||
BLI_sprintf(string, "%s%.*d%s", head, numlen, MAX2(0, pic), tail);
|
||||
}
|
||||
|
||||
static int BLI_path_unc_prefix_len(const char *path); /* defined below in same file */
|
||||
|
||||
void BLI_path_normalize(const char *relabase, char *path)
|
||||
{
|
||||
ptrdiff_t a;
|
||||
@ -131,19 +122,18 @@ void BLI_path_normalize(const char *relabase, char *path)
|
||||
else {
|
||||
if (path[0] == '/' && path[1] == '/') {
|
||||
if (path[2] == '\0') {
|
||||
return; /* path is "//" - can't clean it */
|
||||
return; /* Path is `//` - can't clean it. */
|
||||
}
|
||||
path = path + 2; /* leave the initial "//" untouched */
|
||||
path = path + 2; /* Leave the initial `//` untouched. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Note
|
||||
* memmove(start, eind, strlen(eind) + 1);
|
||||
/* NOTE(@ideasman42):
|
||||
* `memmove(start, eind, strlen(eind) + 1);`
|
||||
* is the same as
|
||||
* strcpy(start, eind);
|
||||
* except strcpy should not be used because there is overlap,
|
||||
* so use memmove's slightly more obscure syntax - Campbell
|
||||
*/
|
||||
* `strcpy(start, eind);`
|
||||
* except `strcpy` should not be used because there is overlap,
|
||||
* so use `memmove` 's slightly more obscure syntax. */
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
@ -152,8 +142,8 @@ void BLI_path_normalize(const char *relabase, char *path)
|
||||
memmove(start, eind, strlen(eind) + 1);
|
||||
}
|
||||
|
||||
/* remove two consecutive backslashes, but skip the UNC prefix,
|
||||
* which needs to be preserved */
|
||||
/* Remove two consecutive backslashes, but skip the UNC prefix,
|
||||
* which needs to be preserved. */
|
||||
while ((start = strstr(path + BLI_path_unc_prefix_len(path), "\\\\"))) {
|
||||
eind = start + strlen("\\\\") - 1;
|
||||
memmove(start, eind, strlen(eind) + 1);
|
||||
@ -179,21 +169,21 @@ void BLI_path_normalize(const char *relabase, char *path)
|
||||
#else
|
||||
|
||||
while ((start = strstr(path, "/./"))) {
|
||||
eind = start + (3 - 1) /* strlen("/./") - 1 */;
|
||||
eind = start + (3 - 1) /* `strlen("/./") - 1` */;
|
||||
memmove(start, eind, strlen(eind) + 1);
|
||||
}
|
||||
|
||||
while ((start = strstr(path, "//"))) {
|
||||
eind = start + (2 - 1) /* strlen("//") - 1 */;
|
||||
eind = start + (2 - 1) /* `strlen("//") - 1` */;
|
||||
memmove(start, eind, strlen(eind) + 1);
|
||||
}
|
||||
|
||||
while ((start = strstr(path, "/../"))) {
|
||||
a = start - path - 1;
|
||||
if (a > 0) {
|
||||
/* <prefix>/<parent>/../<postfix> => <prefix>/<postfix> */
|
||||
eind = start + (4 - 1) /* strlen("/../") - 1 */; /* strip "/.." and keep last "/" */
|
||||
while (a > 0 && path[a] != '/') { /* find start of <parent> */
|
||||
/* `<prefix>/<parent>/../<postfix> => <prefix>/<postfix>`. */
|
||||
eind = start + (4 - 1) /* `strlen("/../") - 1` */; /* Strip "/.." and keep last "/". */
|
||||
while (a > 0 && path[a] != '/') { /* Find start of `<parent>`. */
|
||||
a--;
|
||||
}
|
||||
memmove(path + a, eind, strlen(eind) + 1);
|
||||
@ -253,7 +243,7 @@ bool BLI_filename_make_safe_ex(char *fname, bool allow_tokens)
|
||||
|
||||
/* Forbid only dots. */
|
||||
for (fn = fname; *fn == '.'; fn++) {
|
||||
/* pass */
|
||||
/* Pass. */
|
||||
}
|
||||
if (*fn == '\0') {
|
||||
*fname = '_';
|
||||
@ -279,15 +269,14 @@ bool BLI_filename_make_safe_ex(char *fname, bool allow_tokens)
|
||||
|
||||
/* Check for forbidden names - not we have to check all combination
|
||||
* of upper and lower cases, hence the usage of lower_fname
|
||||
* (more efficient than using BLI_strcasestr repeatedly). */
|
||||
* (more efficient than using #BLI_strcasestr repeatedly). */
|
||||
BLI_str_tolower_ascii(lower_fname, len);
|
||||
for (iname = invalid_names; *iname; iname++) {
|
||||
if (strstr(lower_fname, *iname) == lower_fname) {
|
||||
const size_t iname_len = strlen(*iname);
|
||||
/* Only invalid if the whole name is made of the invalid chunk, or it has an
|
||||
* (assumed extension) dot just after. This means it will also catch 'valid'
|
||||
* names like 'aux.foo.bar', but should be
|
||||
* good enough for us! */
|
||||
* (assumed extension) dot just after. This means it will also catch *valid*
|
||||
* names like `aux.foo.bar`, but should be good enough for us! */
|
||||
if ((iname_len == len) || (lower_fname[iname_len] == '.')) {
|
||||
*fname = '_';
|
||||
changed = true;
|
||||
@ -311,14 +300,14 @@ bool BLI_filename_make_safe(char *fname)
|
||||
bool BLI_path_make_safe(char *path)
|
||||
{
|
||||
/* Simply apply #BLI_filename_make_safe() over each component of the path.
|
||||
* Luckily enough, same 'safe' rules applies to file & directory names. */
|
||||
* Luckily enough, same *safe* rules applies to file & directory names. */
|
||||
char *curr_slash, *curr_path = path;
|
||||
bool changed = false;
|
||||
bool skip_first = false;
|
||||
|
||||
#ifdef WIN32
|
||||
if (BLI_path_is_abs(path)) {
|
||||
/* Do not make safe 'C:' in 'C:\foo\bar'... */
|
||||
if (BLI_path_is_abs_win32(path)) {
|
||||
/* Do not make safe `C:` in `C:\foo\bar`. */
|
||||
skip_first = true;
|
||||
}
|
||||
#endif
|
||||
@ -361,7 +350,7 @@ static int BLI_path_unc_prefix_len(const char *path)
|
||||
{
|
||||
if (BLI_path_is_unc(path)) {
|
||||
if ((path[2] == '?') && (path[3] == '\\')) {
|
||||
/* we assume long UNC path like \\?\server\share\folder etc... */
|
||||
/* We assume long UNC path like `\\?\server\share\folder` etc. */
|
||||
return 4;
|
||||
}
|
||||
|
||||
@ -374,10 +363,14 @@ static int BLI_path_unc_prefix_len(const char *path)
|
||||
#if defined(WIN32)
|
||||
|
||||
/**
|
||||
* Return true if the path is absolute ie starts with a drive specifier
|
||||
* (eg A:\) or is a UNC path.
|
||||
* Return true if the path is an absolute path on a WIN32 file-system, it either:
|
||||
* - Starts with a drive specifier* (eg `A:\`).
|
||||
* - Is a UNC path.
|
||||
*
|
||||
* \note Not to be confused with the opposite of #BLI_path_is_rel which checks for the
|
||||
* Blender specific convention of using `//` prefix for blend-file relative paths.
|
||||
*/
|
||||
static bool BLI_path_is_abs(const char *name)
|
||||
static bool BLI_path_is_abs_win32(const char *name)
|
||||
{
|
||||
return (name[1] == ':' && ELEM(name[2], '\\', '/')) || BLI_path_is_unc(name);
|
||||
}
|
||||
@ -409,9 +402,10 @@ static void BLI_path_unc_to_short(wchar_t *unc)
|
||||
wchar_t tmp[PATH_MAX];
|
||||
|
||||
int len = wcslen(unc);
|
||||
/* convert:
|
||||
* \\?\UNC\server\share\folder\... to \\server\share\folder\...
|
||||
* \\?\C:\ to C:\ and \\?\C:\folder\... to C:\folder\...
|
||||
/* Convert:
|
||||
* - `\\?\UNC\server\share\folder\...` to `\\server\share\folder\...`
|
||||
* - `\\?\C:\` to `C:\`
|
||||
* - `\\?\C:\folder\...` to `C:\folder\...`
|
||||
*/
|
||||
if ((len > 3) && (unc[0] == L'\\') && (unc[1] == L'\\') && (unc[2] == L'?') &&
|
||||
ELEM(unc[3], L'\\', L'/')) {
|
||||
@ -450,18 +444,18 @@ void BLI_path_rel(char *file, const char *relfile)
|
||||
char temp[FILE_MAX];
|
||||
char res[FILE_MAX];
|
||||
|
||||
/* if file is already relative, bail out */
|
||||
/* If file is already relative, bail out. */
|
||||
if (BLI_path_is_rel(file)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* also bail out if relative path is not set */
|
||||
/* Also bail out if relative path is not set. */
|
||||
if (relfile[0] == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
if (BLI_strnlen(relfile, 3) > 2 && !BLI_path_is_abs(relfile)) {
|
||||
if (BLI_strnlen(relfile, 3) > 2 && !BLI_path_is_abs_win32(relfile)) {
|
||||
char *ptemp;
|
||||
/* Fix missing volume name in relative base,
|
||||
* can happen with old `recent-files.txt` files. */
|
||||
@ -479,12 +473,12 @@ void BLI_path_rel(char *file, const char *relfile)
|
||||
if (BLI_strnlen(file, 3) > 2) {
|
||||
bool is_unc = BLI_path_is_unc(file);
|
||||
|
||||
/* Ensure paths are both UNC paths or are both drives */
|
||||
/* Ensure paths are both UNC paths or are both drives. */
|
||||
if (BLI_path_is_unc(temp) != is_unc) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ensure both UNC paths are on the same share */
|
||||
/* Ensure both UNC paths are on the same share. */
|
||||
if (is_unc) {
|
||||
int off;
|
||||
int slash = 0;
|
||||
@ -509,16 +503,16 @@ void BLI_path_rel(char *file, const char *relfile)
|
||||
BLI_str_replace_char(temp + BLI_path_unc_prefix_len(temp), '\\', '/');
|
||||
BLI_str_replace_char(file + BLI_path_unc_prefix_len(file), '\\', '/');
|
||||
|
||||
/* remove /./ which confuse the following slash counting... */
|
||||
/* Remove `/./` which confuse the following slash counting. */
|
||||
BLI_path_normalize(NULL, file);
|
||||
BLI_path_normalize(NULL, temp);
|
||||
|
||||
/* the last slash in the file indicates where the path part ends */
|
||||
/* The last slash in the file indicates where the path part ends. */
|
||||
lslash = BLI_path_slash_rfind(temp);
|
||||
|
||||
if (lslash) {
|
||||
/* find the prefix of the filename that is equal for both filenames.
|
||||
* This is replaced by the two slashes at the beginning */
|
||||
/* Find the prefix of the filename that is equal for both filenames.
|
||||
* This is replaced by the two slashes at the beginning. */
|
||||
const char *p = temp;
|
||||
const char *q = file;
|
||||
char *r = res;
|
||||
@ -532,16 +526,14 @@ void BLI_path_rel(char *file, const char *relfile)
|
||||
p++;
|
||||
q++;
|
||||
|
||||
/* don't search beyond the end of the string
|
||||
* in the rare case they match */
|
||||
/* Don't search beyond the end of the string in the rare case they match. */
|
||||
if ((*p == '\0') || (*q == '\0')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* we might have passed the slash when the beginning of a dir matches
|
||||
* so we rewind. Only check on the actual filename
|
||||
*/
|
||||
/* We might have passed the slash when the beginning of a dir matches
|
||||
* so we rewind. Only check on the actual filename. */
|
||||
if (*q != '/') {
|
||||
while ((q >= file) && (*q != '/')) {
|
||||
q--;
|
||||
@ -557,11 +549,10 @@ void BLI_path_rel(char *file, const char *relfile)
|
||||
|
||||
r += BLI_strcpy_rlen(r, "//");
|
||||
|
||||
/* p now points to the slash that is at the beginning of the part
|
||||
/* `p` now points to the slash that is at the beginning of the part
|
||||
* where the path is different from the relative path.
|
||||
* We count the number of directories we need to go up in the
|
||||
* hierarchy to arrive at the common 'prefix' of the path
|
||||
*/
|
||||
* hierarchy to arrive at the common prefix of the path. */
|
||||
if (p < temp) {
|
||||
p = temp;
|
||||
}
|
||||
@ -572,7 +563,7 @@ void BLI_path_rel(char *file, const char *relfile)
|
||||
p++;
|
||||
}
|
||||
|
||||
/* don't copy the slash at the beginning */
|
||||
/* Don't copy the slash at the beginning. */
|
||||
r += BLI_strncpy_rlen(r, q + 1, FILE_MAX - (r - res));
|
||||
|
||||
#ifdef WIN32
|
||||
@ -627,7 +618,7 @@ bool BLI_path_parent_dir(char *path)
|
||||
return false;
|
||||
}
|
||||
if (tail_len == 1) {
|
||||
/* Last path is ".", as normalize should remove this, it's safe to assume failure.
|
||||
/* Last path is `.`, as normalize should remove this, it's safe to assume failure.
|
||||
* This happens when the input a single period (possibly with slashes before or after). */
|
||||
if (path[tail_ofs] == '.') {
|
||||
return false;
|
||||
@ -646,7 +637,7 @@ bool BLI_path_parent_dir_until_exists(char *dir)
|
||||
|
||||
/* Loop as long as cur path is not a dir, and we can get a parent path. */
|
||||
while ((BLI_access(dir, R_OK) != 0) && (valid_path = BLI_path_parent_dir(dir))) {
|
||||
/* pass */
|
||||
/* Pass. */
|
||||
}
|
||||
return (valid_path && dir[0]);
|
||||
}
|
||||
@ -659,11 +650,11 @@ bool BLI_path_parent_dir_until_exists(char *dir)
|
||||
static bool stringframe_chars(const char *path, int *char_start, int *char_end)
|
||||
{
|
||||
uint ch_sta, ch_end, i;
|
||||
/* Insert current frame: file### -> file001 */
|
||||
/* Insert current frame: `file###` -> `file001`. */
|
||||
ch_sta = ch_end = 0;
|
||||
for (i = 0; path[i] != '\0'; i++) {
|
||||
if (ELEM(path[i], '\\', '/')) {
|
||||
ch_end = 0; /* this is a directory name, don't use any hashes we found */
|
||||
ch_end = 0; /* This is a directory name, don't use any hashes we found. */
|
||||
}
|
||||
else if (path[i] == '#') {
|
||||
ch_sta = i;
|
||||
@ -671,9 +662,9 @@ static bool stringframe_chars(const char *path, int *char_start, int *char_end)
|
||||
while (path[ch_end] == '#') {
|
||||
ch_end++;
|
||||
}
|
||||
i = ch_end - 1; /* keep searching */
|
||||
i = ch_end - 1; /* Keep searching. */
|
||||
|
||||
/* don't break, there may be a slash after this that invalidates the previous #'s */
|
||||
/* Don't break, there may be a slash after this that invalidates the previous #'s. */
|
||||
}
|
||||
}
|
||||
|
||||
@ -718,7 +709,7 @@ bool BLI_path_frame(char *path, int frame, int digits)
|
||||
ensure_digits(path, digits);
|
||||
}
|
||||
|
||||
if (stringframe_chars(path, &ch_sta, &ch_end)) { /* warning, ch_end is the last # +1 */
|
||||
if (stringframe_chars(path, &ch_sta, &ch_end)) { /* Warning: `ch_end` is the last # +1. */
|
||||
char tmp[FILE_MAX];
|
||||
BLI_snprintf(
|
||||
tmp, sizeof(tmp), "%.*s%.*d%s", ch_sta, path, ch_end - ch_sta, frame, path + ch_end);
|
||||
@ -736,7 +727,7 @@ bool BLI_path_frame_range(char *path, int sta, int end, int digits)
|
||||
ensure_digits(path, digits);
|
||||
}
|
||||
|
||||
if (stringframe_chars(path, &ch_sta, &ch_end)) { /* warning, ch_end is the last # +1 */
|
||||
if (stringframe_chars(path, &ch_sta, &ch_end)) { /* Warning: `ch_end` is the last # +1. */
|
||||
char tmp[FILE_MAX];
|
||||
BLI_snprintf(tmp,
|
||||
sizeof(tmp),
|
||||
@ -812,8 +803,8 @@ void BLI_path_frame_strip(char *path, char *r_ext, const size_t ext_maxlen)
|
||||
|
||||
bool BLI_path_frame_check_chars(const char *path)
|
||||
{
|
||||
int ch_sta, ch_end; /* dummy args */
|
||||
return stringframe_chars(path, &ch_sta, &ch_end);
|
||||
int ch_sta_dummy, ch_end_dummy;
|
||||
return stringframe_chars(path, &ch_sta_dummy, &ch_end_dummy);
|
||||
}
|
||||
|
||||
void BLI_path_to_display_name(char *display_name, int maxlen, const char *name)
|
||||
@ -860,16 +851,14 @@ bool BLI_path_abs(char *path, const char *basepath)
|
||||
char base[FILE_MAX];
|
||||
#ifdef WIN32
|
||||
|
||||
/* without this: "" --> "C:\" */
|
||||
/* Without this, an empty string converts to: `C:\` */
|
||||
if (*path == '\0') {
|
||||
return wasrelative;
|
||||
}
|
||||
|
||||
/* we are checking here if we have an absolute path that is not in the current
|
||||
* blend file as a lib main - we are basically checking for the case that a
|
||||
* UNIX root '/' is passed.
|
||||
*/
|
||||
if (!wasrelative && !BLI_path_is_abs(path)) {
|
||||
/* We are checking here if we have an absolute path that is not in the current `.blend` file
|
||||
* as a lib main - we are basically checking for the case that a UNIX root `/` is passed. */
|
||||
if (!wasrelative && !BLI_path_is_abs_win32(path)) {
|
||||
char *p = path;
|
||||
BLI_windows_get_default_root_dir(tmp);
|
||||
/* Get rid of the slashes at the beginning of the path. */
|
||||
@ -892,7 +881,7 @@ bool BLI_path_abs(char *path, const char *basepath)
|
||||
* `C:\foo.JPG` -> `/c/foo.JPG` */
|
||||
|
||||
if (isalpha(tmp[0]) && (tmp[1] == ':') && ELEM(tmp[2], '\\', '/')) {
|
||||
tmp[1] = tolower(tmp[0]); /* Replace ':' with drive-letter. */
|
||||
tmp[1] = tolower(tmp[0]); /* Replace `:` with drive-letter. */
|
||||
tmp[0] = '/';
|
||||
/* `\` the slash will be converted later. */
|
||||
}
|
||||
@ -916,28 +905,28 @@ bool BLI_path_abs(char *path, const char *basepath)
|
||||
const char *lslash;
|
||||
BLI_strncpy(base, basepath, sizeof(base));
|
||||
|
||||
/* file component is ignored, so don't bother with the trailing slash */
|
||||
/* File component is ignored, so don't bother with the trailing slash. */
|
||||
BLI_path_normalize(NULL, base);
|
||||
lslash = BLI_path_slash_rfind(base);
|
||||
BLI_str_replace_char(base + BLI_path_unc_prefix_len(base), '\\', '/');
|
||||
|
||||
if (lslash) {
|
||||
/* length up to and including last "/" */
|
||||
/* Length up to and including last `/`. */
|
||||
const int baselen = (int)(lslash - base) + 1;
|
||||
/* use path for temp storage here, we copy back over it right away */
|
||||
BLI_strncpy(path, tmp + 2, FILE_MAX); /* strip "//" */
|
||||
/* Use path for temp storage here, we copy back over it right away. */
|
||||
BLI_strncpy(path, tmp + 2, FILE_MAX); /* Strip `//` prefix. */
|
||||
|
||||
memcpy(tmp, base, baselen); /* prefix with base up to last "/" */
|
||||
BLI_strncpy(tmp + baselen, path, sizeof(tmp) - baselen); /* append path after "//" */
|
||||
BLI_strncpy(path, tmp, FILE_MAX); /* return as result */
|
||||
memcpy(tmp, base, baselen); /* Prefix with base up to last `/`. */
|
||||
BLI_strncpy(tmp + baselen, path, sizeof(tmp) - baselen); /* Append path after `//`. */
|
||||
BLI_strncpy(path, tmp, FILE_MAX); /* Return as result. */
|
||||
}
|
||||
else {
|
||||
/* base doesn't seem to be a directory--ignore it and just strip "//" prefix on path */
|
||||
/* Base doesn't seem to be a directory, ignore it and just strip `//` prefix on path. */
|
||||
BLI_strncpy(path, tmp + 2, FILE_MAX);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* base ignored */
|
||||
/* Base ignored. */
|
||||
BLI_strncpy(path, tmp, FILE_MAX);
|
||||
}
|
||||
|
||||
@ -948,7 +937,7 @@ bool BLI_path_abs(char *path, const char *basepath)
|
||||
BLI_str_replace_char(path + 2, '/', '\\');
|
||||
#endif
|
||||
|
||||
/* ensure this is after correcting for path switch */
|
||||
/* Ensure this is after correcting for path switch. */
|
||||
BLI_path_normalize(NULL, path);
|
||||
|
||||
return wasrelative;
|
||||
@ -960,7 +949,7 @@ bool BLI_path_is_abs_from_cwd(const char *path)
|
||||
const int path_len_clamp = BLI_strnlen(path, 3);
|
||||
|
||||
#ifdef WIN32
|
||||
if ((path_len_clamp >= 3 && BLI_path_is_abs(path)) || BLI_path_is_unc(path)) {
|
||||
if ((path_len_clamp >= 3 && BLI_path_is_abs_win32(path)) || BLI_path_is_unc(path)) {
|
||||
is_abs = true;
|
||||
}
|
||||
#else
|
||||
@ -979,7 +968,7 @@ bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
|
||||
|
||||
if (!BLI_path_is_abs_from_cwd(path)) {
|
||||
char cwd[FILE_MAX];
|
||||
/* in case the full path to the blend isn't used */
|
||||
/* In case the full path to the blend isn't used. */
|
||||
if (BLI_current_working_dir(cwd, sizeof(cwd))) {
|
||||
char origpath[FILE_MAX];
|
||||
BLI_strncpy(origpath, path, FILE_MAX);
|
||||
@ -996,7 +985,7 @@ bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
|
||||
|
||||
#ifdef _WIN32
|
||||
/**
|
||||
* Tries appending each of the semicolon-separated extensions in the PATHEXT
|
||||
* Tries appending each of the semicolon-separated extensions in the `PATHEXT`
|
||||
* environment variable (Windows-only) onto `name` in turn until such a file is found.
|
||||
* Returns success/failure.
|
||||
*/
|
||||
@ -1007,7 +996,7 @@ bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen)
|
||||
|
||||
type = BLI_exists(name);
|
||||
if ((type == 0) || S_ISDIR(type)) {
|
||||
/* typically 3-5, ".EXE", ".BAT"... etc */
|
||||
/* Typically 3-5, ".EXE", ".BAT"... etc. */
|
||||
const int ext_max = 12;
|
||||
const char *ext = BLI_getenv("PATHEXT");
|
||||
if (ext) {
|
||||
@ -1016,7 +1005,7 @@ bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen)
|
||||
char *filename_ext;
|
||||
const char *ext_next;
|
||||
|
||||
/* null terminated in the loop */
|
||||
/* Null terminated in the loop. */
|
||||
memcpy(filename, name, name_len);
|
||||
filename_ext = filename + name_len;
|
||||
|
||||
@ -1101,11 +1090,9 @@ bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *na
|
||||
|
||||
void BLI_setenv(const char *env, const char *val)
|
||||
{
|
||||
/* free windows */
|
||||
|
||||
#if (defined(_WIN32) || defined(_WIN64))
|
||||
/* MS-Windows. */
|
||||
uputenv(env, val);
|
||||
|
||||
#else
|
||||
/* Linux/macOS/BSD */
|
||||
if (val) {
|
||||
@ -1158,7 +1145,7 @@ bool BLI_make_existing_file(const char *name)
|
||||
char di[FILE_MAX];
|
||||
BLI_split_dir_part(name, di, sizeof(di));
|
||||
|
||||
/* make if the dir doesn't exist */
|
||||
/* Make if the dir doesn't exist. */
|
||||
return BLI_dir_create_recursive(di);
|
||||
}
|
||||
|
||||
@ -1260,7 +1247,7 @@ bool BLI_path_extension_glob_validate(char *ext_fnmatch)
|
||||
/* Non-wildcard char, we can break here and consider the pattern valid. */
|
||||
return false;
|
||||
}
|
||||
/* So far, only wildcards in last group of the pattern... */
|
||||
/* So far, only wildcards in last group of the pattern. */
|
||||
only_wildcards = true;
|
||||
}
|
||||
/* Only one group in the pattern, so even if its only made of wildcard(s),
|
||||
@ -1352,7 +1339,7 @@ void BLI_split_dirfile(
|
||||
|
||||
if (dir) {
|
||||
if (lslash) {
|
||||
/* +1 to include the slash and the last char */
|
||||
/* +1 to include the slash and the last char. */
|
||||
BLI_strncpy(dir, string, MIN2(dirlen, lslash + 1));
|
||||
}
|
||||
else {
|
||||
@ -1429,7 +1416,7 @@ size_t BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__
|
||||
}
|
||||
|
||||
if (dirlen >= maxlen) {
|
||||
return dirlen; /* fills the path */
|
||||
return dirlen; /* Fills the path. */
|
||||
}
|
||||
|
||||
return dirlen + BLI_strncpy_rlen(dst + dirlen, file, maxlen - dirlen);
|
||||
@ -1470,7 +1457,7 @@ size_t BLI_path_join_array(char *__restrict dst,
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
/* Special case "//" for relative paths, don't use separator #SEP
|
||||
/* Special case `//` for relative paths, don't use separator #SEP
|
||||
* as this has a special meaning on both WIN32 & UNIX.
|
||||
* Without this check joining `"//", "path"`. results in `"//\path"`. */
|
||||
if (ofs != 0) {
|
||||
@ -1519,7 +1506,7 @@ size_t BLI_path_join_array(char *__restrict dst,
|
||||
}
|
||||
|
||||
if (len != 0) {
|
||||
/* the very first path may have a slash at the end */
|
||||
/* The very first path may have a slash at the end. */
|
||||
if (ofs && !BLI_path_slash_is_native_compat(dst[ofs - 1])) {
|
||||
dst[ofs++] = SEP;
|
||||
if (ofs == dst_last) {
|
||||
@ -1574,7 +1561,7 @@ static bool path_name_at_index_forward(const char *__restrict path,
|
||||
if ((c == '\0') || BLI_path_slash_is_native_compat(c)) {
|
||||
if (prev + 1 != i) {
|
||||
prev += 1;
|
||||
/* Skip '/./' (behave as if they don't exist). */
|
||||
/* Skip `/./` (behave as if they don't exist). */
|
||||
if (!((i - prev == 1) && (prev != 0) && (path[prev] == '.'))) {
|
||||
if (index_step == index) {
|
||||
*r_offset = prev;
|
||||
@ -1609,7 +1596,7 @@ static bool path_name_at_index_backward(const char *__restrict path,
|
||||
if ((c == '\0') || BLI_path_slash_is_native_compat(c)) {
|
||||
if (prev - 1 != i) {
|
||||
i += 1;
|
||||
/* Skip '/./' (behave as if they don't exist). */
|
||||
/* Skip `/./` (behave as if they don't exist). */
|
||||
if (!((prev - i == 1) && (i != 0) && (path[i] == '.'))) {
|
||||
if (index_step == index) {
|
||||
*r_offset = i;
|
||||
@ -1644,7 +1631,7 @@ bool BLI_path_contains(const char *container_path, const char *containee_path)
|
||||
char containee_native[PATH_MAX];
|
||||
|
||||
/* Keep space for a trailing slash. If the path is truncated by this, the containee path is
|
||||
* longer than PATH_MAX and the result is ill-defined. */
|
||||
* longer than #PATH_MAX and the result is ill-defined. */
|
||||
BLI_strncpy(container_native, container_path, PATH_MAX - 1);
|
||||
BLI_strncpy(containee_native, containee_path, PATH_MAX);
|
||||
|
||||
|
@ -81,11 +81,8 @@ BLI_INLINE void bmesh_calc_tessellation_for_face_impl(BMLoop *(*looptris)[3],
|
||||
efa->no, l_ptr_a[0]->v->co, l_ptr_a[1]->v->co, l_ptr_a[2]->v->co, l_ptr_b[2]->v->co);
|
||||
}
|
||||
|
||||
if (UNLIKELY(is_quad_flip_v3_first_third_fast_with_normal(l_ptr_a[0]->v->co,
|
||||
l_ptr_a[1]->v->co,
|
||||
l_ptr_a[2]->v->co,
|
||||
l_ptr_b[2]->v->co,
|
||||
efa->no))) {
|
||||
if (UNLIKELY(is_quad_flip_v3_first_third_fast(
|
||||
l_ptr_a[0]->v->co, l_ptr_a[1]->v->co, l_ptr_a[2]->v->co, l_ptr_b[2]->v->co))) {
|
||||
/* Flip out of degenerate 0-2 state. */
|
||||
l_ptr_a[2] = l_ptr_b[2];
|
||||
l_ptr_b[0] = l_ptr_a[1];
|
||||
|
@ -166,7 +166,8 @@ void DepthOfField::sync()
|
||||
/* Now that we know the maximum render resolution of every view, using depth of field, allocate
|
||||
* the reduced buffers. Color needs to be signed format here. See note in shader for
|
||||
* explanation. Do not use texture pool because of needs mipmaps. */
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT |
|
||||
GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW;
|
||||
reduced_color_tx_.ensure_2d(GPU_RGBA16F, reduce_size, usage, nullptr, DOF_MIP_COUNT);
|
||||
reduced_coc_tx_.ensure_2d(GPU_R16F, reduce_size, usage, nullptr, DOF_MIP_COUNT);
|
||||
reduced_color_tx_.ensure_mip_views();
|
||||
|
@ -24,7 +24,8 @@ void HiZBuffer::sync()
|
||||
int2 hiz_extent = math::ceil_to_multiple(render_extent, int2(1u << (HIZ_MIP_COUNT - 1)));
|
||||
int2 dispatch_size = math::divide_ceil(hiz_extent, int2(HIZ_GROUP_SIZE));
|
||||
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE;
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE |
|
||||
GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW;
|
||||
hiz_tx_.ensure_2d(GPU_R32F, hiz_extent, usage, nullptr, HIZ_MIP_COUNT);
|
||||
hiz_tx_.ensure_mip_views();
|
||||
GPU_texture_mipmap_mode(hiz_tx_, true, false);
|
||||
|
@ -628,7 +628,7 @@ struct LightData {
|
||||
float radius_squared;
|
||||
/** NOTE: It is ok to use float3 here. A float is declared right after it.
|
||||
* float3 is also aligned to 16 bytes. */
|
||||
float3 color;
|
||||
packed_float3 color;
|
||||
/** Light Type. */
|
||||
eLightType type;
|
||||
/** Spot size. Aligned to size of float2. */
|
||||
|
@ -257,7 +257,8 @@ class ShadowModule {
|
||||
/** Tile to physical page mapping. This is an array texture with one layer per view. */
|
||||
Texture render_map_tx_ = {"ShadowRenderMap",
|
||||
GPU_R32UI,
|
||||
GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE,
|
||||
GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE |
|
||||
GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW,
|
||||
int2(SHADOW_TILEMAP_RES),
|
||||
64,
|
||||
nullptr,
|
||||
|
@ -12,7 +12,7 @@ void main()
|
||||
|
||||
/* Display backfacing surfels with a transparent checkerboard grid. */
|
||||
if (!gl_FrontFacing) {
|
||||
ivec2 grid_uv = ivec2(gl_FragCoord) / 5;
|
||||
ivec2 grid_uv = ivec2(gl_FragCoord.xy) / 5;
|
||||
if ((grid_uv.x + grid_uv.y) % 2 == 0) {
|
||||
discard;
|
||||
return;
|
||||
|
@ -45,7 +45,8 @@ void main()
|
||||
case LIGHT_RECT:
|
||||
case LIGHT_ELLIPSE:
|
||||
case LIGHT_POINT:
|
||||
sphere = Sphere(light._position, light.influence_radius_max);
|
||||
sphere.center = light._position;
|
||||
sphere.radius = light.influence_radius_max;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,7 @@ bool debug_tilemaps(vec3 P, LightData light)
|
||||
out_color_add = vec4(debug_tile_state_color(tile), 0.0);
|
||||
out_color_mul = vec4(0.0);
|
||||
|
||||
if (ivec2(gl_FragCoord.xy) == ivec2(0)) {
|
||||
if (all(equal(ivec2(gl_FragCoord.xy), ivec2(0)))) {
|
||||
drw_print(light.object_mat);
|
||||
}
|
||||
return true;
|
||||
|
@ -25,7 +25,9 @@
|
||||
#pragma BLENDER_REQUIRE(eevee_shadow_tilemap_lib.glsl)
|
||||
|
||||
/* TODO(@fclem): Implement. */
|
||||
#define assert(check)
|
||||
#ifndef GPU_METAL
|
||||
# define assert(check)
|
||||
#endif
|
||||
|
||||
/* Remove page ownership from the tile and append it to the cache. */
|
||||
void shadow_page_free(inout ShadowTileData tile)
|
||||
|
@ -45,7 +45,7 @@ float pixel_size_at(float linear_depth)
|
||||
if (is_persp) {
|
||||
pixel_size *= max(0.01, linear_depth);
|
||||
}
|
||||
return pixel_size * exp2(fb_lod);
|
||||
return pixel_size * exp2(float(fb_lod));
|
||||
}
|
||||
|
||||
void step_bounding_sphere(vec3 vs_near_plane,
|
||||
@ -117,6 +117,7 @@ void main()
|
||||
step_bounding_sphere(vs_near_plane, vs_view_direction, t, t + step_size, P, step_radius);
|
||||
vec3 vP = point_world_to_view(P);
|
||||
|
||||
shadow_tag_usage(vP, P, ws_view_direction, step_radius, t, gl_FragCoord.xy * exp2(fb_lod));
|
||||
shadow_tag_usage(
|
||||
vP, P, ws_view_direction, step_radius, t, gl_FragCoord.xy * exp2(float(fb_lod)));
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ void inflate_bounds(vec3 ls_center, inout vec3 P, inout vec3 lP)
|
||||
{
|
||||
vec3 vP = point_world_to_view(P);
|
||||
|
||||
float inflate_scale = pixel_world_radius * exp2(fb_lod);
|
||||
float inflate_scale = pixel_world_radius * exp2(float(fb_lod));
|
||||
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
|
||||
if (is_persp) {
|
||||
inflate_scale *= -vP.z;
|
||||
|
@ -45,6 +45,8 @@ void write_depth(ivec2 texel_co, const int lod, ivec2 tile_co, float depth)
|
||||
/* Quantization bias. Equivalent to nextafter in C without all the safety. 1 is not enough. */
|
||||
u_depth += 2;
|
||||
|
||||
/* TOOD(Metal): For Metal, textures will need to be viewed as buffers to workaround missing image
|
||||
* atomics support. */
|
||||
imageAtomicMin(shadow_atlas_img, out_texel, u_depth);
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,11 @@
|
||||
/** \name Shadow pipeline
|
||||
* \{ */
|
||||
|
||||
/* NOTE(Metal): As this is implemented using a fundamental data type, this needs to be specified
|
||||
* explicitly as uint for code generation, as the MSLShaderGenerator needs to be able to
|
||||
* distinguish between classes and fundamental types during code generation. */
|
||||
#define SHADOW_TILE_DATA_PACKED "uint"
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_shadow_clipmap_clear)
|
||||
.do_static_compilation(true)
|
||||
.local_group_size(SHADOW_CLIPMAP_GROUP_SIZE)
|
||||
@ -34,7 +39,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tilemap_init)
|
||||
.do_static_compilation(true)
|
||||
.local_group_size(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES)
|
||||
.storage_buf(0, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.storage_buf(2, Qualifier::READ_WRITE, "ShadowTileMapClip", "tilemaps_clip_buf[]")
|
||||
.storage_buf(4, Qualifier::READ_WRITE, "uvec2", "pages_cached_buf[]")
|
||||
.additional_info("eevee_shared")
|
||||
@ -44,7 +49,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_update)
|
||||
.do_static_compilation(true)
|
||||
.local_group_size(1, 1, 1)
|
||||
.storage_buf(0, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.storage_buf(5, Qualifier::READ, "ObjectBounds", "bounds_buf[]")
|
||||
.storage_buf(6, Qualifier::READ, "uint", "resource_ids_buf[]")
|
||||
.additional_info("eevee_shared", "draw_view", "draw_view_culling")
|
||||
@ -55,7 +60,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_opaque)
|
||||
.local_group_size(SHADOW_DEPTH_SCAN_GROUP_SIZE, SHADOW_DEPTH_SCAN_GROUP_SIZE)
|
||||
.sampler(0, ImageType::DEPTH_2D, "depth_tx")
|
||||
.storage_buf(5, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(6, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
|
||||
.storage_buf(6, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.push_constant(Type::FLOAT, "tilemap_projection_ratio")
|
||||
.additional_info("eevee_shared", "draw_view", "draw_view_culling", "eevee_light_data")
|
||||
.compute_source("eevee_shadow_tag_usage_comp.glsl");
|
||||
@ -71,7 +76,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_transparent)
|
||||
.vertex_in(0, Type::VEC3, "pos")
|
||||
.storage_buf(4, Qualifier::READ, "ObjectBounds", "bounds_buf[]")
|
||||
.storage_buf(5, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(6, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
|
||||
.storage_buf(6, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.push_constant(Type::FLOAT, "tilemap_projection_ratio")
|
||||
.push_constant(Type::FLOAT, "pixel_world_radius")
|
||||
.push_constant(Type::IVEC2, "fb_resolution")
|
||||
@ -91,7 +96,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_page_mask)
|
||||
.do_static_compilation(true)
|
||||
.local_group_size(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES)
|
||||
.storage_buf(0, Qualifier::READ, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.additional_info("eevee_shared")
|
||||
.compute_source("eevee_shadow_page_mask_comp.glsl");
|
||||
|
||||
@ -99,7 +104,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_page_free)
|
||||
.do_static_compilation(true)
|
||||
.local_group_size(SHADOW_TILEMAP_LOD0_LEN)
|
||||
.storage_buf(0, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.storage_buf(2, Qualifier::READ_WRITE, "ShadowPagesInfoData", "pages_infos_buf")
|
||||
.storage_buf(3, Qualifier::READ_WRITE, "uint", "pages_free_buf[]")
|
||||
.storage_buf(4, Qualifier::READ_WRITE, "uvec2", "pages_cached_buf[]")
|
||||
@ -110,7 +115,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_page_defrag)
|
||||
.do_static_compilation(true)
|
||||
.local_group_size(1)
|
||||
.typedef_source("draw_shader_shared.h")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.storage_buf(2, Qualifier::READ_WRITE, "ShadowPagesInfoData", "pages_infos_buf")
|
||||
.storage_buf(3, Qualifier::READ_WRITE, "uint", "pages_free_buf[]")
|
||||
.storage_buf(4, Qualifier::READ_WRITE, "uvec2", "pages_cached_buf[]")
|
||||
@ -124,7 +129,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_page_allocate)
|
||||
.local_group_size(SHADOW_TILEMAP_LOD0_LEN)
|
||||
.typedef_source("draw_shader_shared.h")
|
||||
.storage_buf(0, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.storage_buf(2, Qualifier::READ_WRITE, "ShadowPagesInfoData", "pages_infos_buf")
|
||||
.storage_buf(3, Qualifier::READ_WRITE, "uint", "pages_free_buf[]")
|
||||
.storage_buf(4, Qualifier::READ_WRITE, "uvec2", "pages_cached_buf[]")
|
||||
@ -137,7 +142,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tilemap_finalize)
|
||||
.typedef_source("draw_shader_shared.h")
|
||||
.local_group_size(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES)
|
||||
.storage_buf(0, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.storage_buf(2, Qualifier::READ_WRITE, "ShadowPagesInfoData", "pages_infos_buf")
|
||||
.storage_buf(3, Qualifier::WRITE, "ViewMatrices", "view_infos_buf[64]")
|
||||
.storage_buf(4, Qualifier::READ_WRITE, "ShadowStatistics", "statistics_buf")
|
||||
@ -183,11 +188,12 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_debug)
|
||||
.do_static_compilation(true)
|
||||
.additional_info("eevee_shared")
|
||||
.storage_buf(5, Qualifier::READ, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(6, Qualifier::READ, "ShadowTileDataPacked", "tiles_buf[]")
|
||||
.storage_buf(6, Qualifier::READ, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.fragment_out(0, Type::VEC4, "out_color_add", DualBlend::SRC_0)
|
||||
.fragment_out(0, Type::VEC4, "out_color_mul", DualBlend::SRC_1)
|
||||
.push_constant(Type::INT, "debug_mode")
|
||||
.push_constant(Type::INT, "debug_tilemap_index")
|
||||
.depth_write(DepthWrite::ANY)
|
||||
.fragment_source("eevee_shadow_debug_frag.glsl")
|
||||
.additional_info(
|
||||
"draw_fullscreen", "draw_view", "eevee_hiz_data", "eevee_light_data", "eevee_shadow_data");
|
||||
|
@ -33,7 +33,12 @@
|
||||
|
||||
BLI_INLINE eParticleRefineShaderType drw_curves_shader_type_get()
|
||||
{
|
||||
if (GPU_compute_shader_support() && GPU_shader_storage_buffer_objects_support()) {
|
||||
/* NOTE: Curve refine is faster using transform feedback via vertex processing pipeline with
|
||||
* Metal and Apple Silicon GPUs. This is also because vertex work can more easily be executed in
|
||||
* parallel with fragment work, whereas compute inserts an explicit dependency,
|
||||
* due to switching of command encoder types. */
|
||||
if (GPU_compute_shader_support() && GPU_shader_storage_buffer_objects_support() &&
|
||||
(GPU_backend_get_type() != GPU_BACKEND_METAL)) {
|
||||
return PART_REFINE_SHADER_COMPUTE;
|
||||
}
|
||||
if (GPU_transform_feedback_support()) {
|
||||
|
@ -36,7 +36,12 @@
|
||||
|
||||
BLI_INLINE eParticleRefineShaderType drw_hair_shader_type_get()
|
||||
{
|
||||
if (GPU_compute_shader_support() && GPU_shader_storage_buffer_objects_support()) {
|
||||
/* NOTE: Hair refine is faster using transform feedback via vertex processing pipeline with Metal
|
||||
* and Apple Silicon GPUs. This is also because vertex work can more easily be executed in
|
||||
* parallel with fragment work, whereas compute inserts an explicit dependency,
|
||||
* due to switching of command encoder types. */
|
||||
if (GPU_compute_shader_support() && GPU_shader_storage_buffer_objects_support() &&
|
||||
(GPU_backend_get_type() != GPU_BACKEND_METAL)) {
|
||||
return PART_REFINE_SHADER_COMPUTE;
|
||||
}
|
||||
if (GPU_transform_feedback_support()) {
|
||||
|
@ -350,6 +350,16 @@ struct DRWDebugVert {
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(DRWDebugVert, 16)
|
||||
|
||||
inline DRWDebugVert debug_vert_make(uint in_pos0, uint in_pos1, uint in_pos2, uint in_vert_color)
|
||||
{
|
||||
DRWDebugVert debug_vert;
|
||||
debug_vert.pos0 = in_pos0;
|
||||
debug_vert.pos1 = in_pos1;
|
||||
debug_vert.pos2 = in_pos2;
|
||||
debug_vert.vert_color = in_vert_color;
|
||||
return debug_vert;
|
||||
}
|
||||
|
||||
/* Take the header (DrawCommand) into account. */
|
||||
#define DRW_DEBUG_DRAW_VERT_MAX (64 * 8192) - 1
|
||||
|
||||
|
@ -34,9 +34,9 @@ uint drw_debug_color_pack(vec4 v_color)
|
||||
|
||||
void drw_debug_line(inout uint vertid, vec3 v1, vec3 v2, uint v_color)
|
||||
{
|
||||
drw_debug_verts_buf[vertid++] = DRWDebugVert(
|
||||
drw_debug_verts_buf[vertid++] = debug_vert_make(
|
||||
floatBitsToUint(v1.x), floatBitsToUint(v1.y), floatBitsToUint(v1.z), v_color);
|
||||
drw_debug_verts_buf[vertid++] = DRWDebugVert(
|
||||
drw_debug_verts_buf[vertid++] = debug_vert_make(
|
||||
floatBitsToUint(v2.x), floatBitsToUint(v2.y), floatBitsToUint(v2.z), v_color);
|
||||
}
|
||||
|
||||
|
@ -154,7 +154,7 @@ struct SculptUndoNodeGeometry {
|
||||
CustomData ldata;
|
||||
CustomData pdata;
|
||||
int *poly_offset_indices;
|
||||
blender::ImplicitSharingInfo *poly_offsets_sharing_info;
|
||||
const blender::ImplicitSharingInfo *poly_offsets_sharing_info;
|
||||
int totvert;
|
||||
int totedge;
|
||||
int totloop;
|
||||
|
@ -510,7 +510,7 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (BLI_listbase_count(&sspreadsheet->viewer_path.path) == 1) {
|
||||
if (BLI_listbase_is_single(&sspreadsheet->viewer_path.path)) {
|
||||
if (const GeometrySet *geometry_eval = object_eval->runtime.geometry_set_eval) {
|
||||
geometry_set = *geometry_eval;
|
||||
}
|
||||
|
@ -3181,7 +3181,7 @@ static float uv_sphere_project(const Scene *scene,
|
||||
const float branch_init)
|
||||
{
|
||||
float max_u = 0.0f;
|
||||
if (BM_elem_flag_test(efa_init, BM_ELEM_TAG)) {
|
||||
if (use_seams && BM_elem_flag_test(efa_init, BM_ELEM_TAG)) {
|
||||
return max_u;
|
||||
}
|
||||
|
||||
@ -3358,7 +3358,7 @@ static float uv_cylinder_project(const Scene *scene,
|
||||
const float branch_init)
|
||||
{
|
||||
float max_u = 0.0f;
|
||||
if (BM_elem_flag_test(efa_init, BM_ELEM_TAG)) {
|
||||
if (use_seams && BM_elem_flag_test(efa_init, BM_ELEM_TAG)) {
|
||||
return max_u;
|
||||
}
|
||||
|
||||
|
@ -235,6 +235,7 @@ set(VULKAN_SRC
|
||||
vulkan/vk_common.hh
|
||||
vulkan/vk_context.hh
|
||||
vulkan/vk_data_conversion.hh
|
||||
vulkan/vk_debug.hh
|
||||
vulkan/vk_descriptor_pools.hh
|
||||
vulkan/vk_descriptor_set.hh
|
||||
vulkan/vk_drawlist.hh
|
||||
|
@ -458,6 +458,9 @@ GPUTexture *GPU_texture_create_view(const char *name,
|
||||
{
|
||||
BLI_assert(mip_len > 0);
|
||||
BLI_assert(layer_len > 0);
|
||||
BLI_assert_msg(
|
||||
GPU_texture_usage(src) & GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW,
|
||||
"Source texture of TextureView must have GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW usage flag.");
|
||||
Texture *view = GPUBackend::get()->texture_alloc(name);
|
||||
view->init_view(src,
|
||||
format,
|
||||
|
@ -189,6 +189,16 @@ MTLContext::MTLContext(void *ghost_window, void *ghost_context)
|
||||
[this->queue retain];
|
||||
[this->device retain];
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wobjc-method-access"
|
||||
/* Enable increased concurrent shader compiler limit.
|
||||
* Note: Disable warning for missing method when building on older OS's, as compiled code will
|
||||
* still work correctly when run on a system with the API available. */
|
||||
if (@available(macOS 13.3, *)) {
|
||||
[this->device setShouldMaximizeConcurrentCompilation:YES];
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
/* Register present callback. */
|
||||
this->ghost_context_->metalRegisterPresentCallback(&present);
|
||||
|
||||
|
@ -83,9 +83,7 @@ struct constexp_uvec3 {
|
||||
uint3 xyz;
|
||||
};
|
||||
|
||||
constexpr constexp_uvec3(uint _x, uint _y, uint _z) : x(_x), y(_y), z(_z)
|
||||
{
|
||||
}
|
||||
constexpr constexp_uvec3(uint _x, uint _y, uint _z) : x(_x), y(_y), z(_z) {}
|
||||
constexpr uint operator[](int i)
|
||||
{
|
||||
/* Note: Need to switch on each elem value as array accessor triggers
|
||||
@ -294,6 +292,8 @@ struct SStruct {
|
||||
#define textureGather3(__tex, __uv, __comp) _texture_gather_internal(__tex, __uv, __comp)
|
||||
#define textureGatherOffset(__tex, __offset, __uv, __comp) \
|
||||
_texture_gather_internal(__tex, __uv, __comp, __offset)
|
||||
#define textureGrad(__tex, __uv, __dpdx, __dpdy) \
|
||||
_texture_grad_internal(__tex, __uv, __dpdx, __dpdy)
|
||||
|
||||
#define TEXURE_MACRO(_1, _2, _3, TEXNAME, ...) TEXNAME
|
||||
#define texture(...) TEXURE_MACRO(__VA_ARGS__, texture3, texture2)(__VA_ARGS__)
|
||||
@ -849,6 +849,34 @@ inline vec<T, 4> _texture_gather_internal(
|
||||
return tex.texture->gather(*tex.samp, uva.xy, uint(uva.z), offset);
|
||||
}
|
||||
|
||||
/* Texture Grad. */
|
||||
inline float4 _texture_grad_internal(
|
||||
thread _mtl_combined_image_sampler_2d<float, access::sample> tex,
|
||||
float2 uv,
|
||||
float2 dpdx,
|
||||
float2 dpdy)
|
||||
{
|
||||
return tex.texture->sample(*tex.samp, uv, gradient2d(dpdx, dpdy));
|
||||
}
|
||||
|
||||
inline float4 _texture_grad_internal(
|
||||
thread _mtl_combined_image_sampler_2d_array<float, access::sample> tex,
|
||||
float3 uva,
|
||||
float2 dpdx,
|
||||
float2 dpdy)
|
||||
{
|
||||
return tex.texture->sample(*tex.samp, uva.xy, uint(uva.z), gradient2d(dpdx, dpdy));
|
||||
}
|
||||
|
||||
inline float4 _texture_grad_internal(
|
||||
thread _mtl_combined_image_sampler_3d<float, access::sample> tex,
|
||||
float3 uvw,
|
||||
float3 dpdx,
|
||||
float3 dpdy)
|
||||
{
|
||||
return tex.texture->sample(*tex.samp, uvw, gradient3d(dpdx, dpdy));
|
||||
}
|
||||
|
||||
/* Texture write support. */
|
||||
template<typename S, typename T, access A>
|
||||
inline void _texture_write_internal(thread _mtl_combined_image_sampler_1d<S, A> tex,
|
||||
|
@ -145,7 +145,7 @@ static void test_shader_compute_vbo()
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
/* Construct VBO. */
|
||||
static GPUVertFormat format = {0};
|
||||
GPUVertFormat format = {0};
|
||||
GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
|
||||
GPUVertBuf *vbo = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_DEVICE_ONLY);
|
||||
GPU_vertbuf_data_alloc(vbo, SIZE);
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <typeinfo>
|
||||
|
||||
#ifdef __APPLE__
|
||||
# include <MoltenVK/vk_mvk_moltenvk.h>
|
||||
#else
|
||||
@ -26,4 +28,66 @@ VkImageViewType to_vk_image_view_type(const eGPUTextureType type);
|
||||
VkImageType to_vk_image_type(const eGPUTextureType type);
|
||||
VkClearColorValue to_vk_clear_color_value(const eGPUDataFormat format, const void *data);
|
||||
|
||||
template<typename T> VkObjectType to_vk_object_type(T /*vk_obj*/)
|
||||
{
|
||||
const std::type_info &tid = typeid(T);
|
||||
#define VK_EQ_TYPEID(name, name2) \
|
||||
if (tid == typeid(name)) { \
|
||||
return VK_OBJECT_TYPE_##name2; \
|
||||
}
|
||||
|
||||
VK_EQ_TYPEID(VkInstance, INSTANCE);
|
||||
VK_EQ_TYPEID(VkPhysicalDevice, PHYSICAL_DEVICE);
|
||||
VK_EQ_TYPEID(VkDevice, DEVICE);
|
||||
VK_EQ_TYPEID(VkQueue, QUEUE);
|
||||
VK_EQ_TYPEID(VkSemaphore, SEMAPHORE);
|
||||
VK_EQ_TYPEID(VkCommandBuffer, COMMAND_BUFFER);
|
||||
VK_EQ_TYPEID(VkFence, FENCE);
|
||||
VK_EQ_TYPEID(VkDeviceMemory, DEVICE_MEMORY);
|
||||
VK_EQ_TYPEID(VkBuffer, BUFFER);
|
||||
VK_EQ_TYPEID(VkImage, IMAGE);
|
||||
VK_EQ_TYPEID(VkEvent, EVENT);
|
||||
VK_EQ_TYPEID(VkQueryPool, QUERY_POOL);
|
||||
VK_EQ_TYPEID(VkBufferView, BUFFER_VIEW);
|
||||
VK_EQ_TYPEID(VkImageView, IMAGE_VIEW);
|
||||
VK_EQ_TYPEID(VkShaderModule, SHADER_MODULE);
|
||||
VK_EQ_TYPEID(VkPipelineCache, PIPELINE_CACHE);
|
||||
VK_EQ_TYPEID(VkPipelineLayout, PIPELINE_LAYOUT);
|
||||
VK_EQ_TYPEID(VkRenderPass, RENDER_PASS);
|
||||
VK_EQ_TYPEID(VkPipeline, PIPELINE);
|
||||
VK_EQ_TYPEID(VkDescriptorSetLayout, DESCRIPTOR_SET_LAYOUT);
|
||||
VK_EQ_TYPEID(VkSampler, SAMPLER);
|
||||
VK_EQ_TYPEID(VkDescriptorPool, DESCRIPTOR_POOL);
|
||||
VK_EQ_TYPEID(VkDescriptorSet, DESCRIPTOR_SET);
|
||||
VK_EQ_TYPEID(VkFramebuffer, FRAMEBUFFER);
|
||||
VK_EQ_TYPEID(VkCommandPool, COMMAND_POOL);
|
||||
VK_EQ_TYPEID(VkSamplerYcbcrConversion, SAMPLER_YCBCR_CONVERSION);
|
||||
VK_EQ_TYPEID(VkDescriptorUpdateTemplate, DESCRIPTOR_UPDATE_TEMPLATE);
|
||||
VK_EQ_TYPEID(VkSurfaceKHR, SURFACE_KHR);
|
||||
VK_EQ_TYPEID(VkSwapchainKHR, SWAPCHAIN_KHR);
|
||||
VK_EQ_TYPEID(VkDisplayKHR, DISPLAY_KHR);
|
||||
VK_EQ_TYPEID(VkDisplayModeKHR, DISPLAY_MODE_KHR);
|
||||
VK_EQ_TYPEID(VkDebugReportCallbackEXT, DEBUG_REPORT_CALLBACK_EXT);
|
||||
#ifdef VK_ENABLE_BETA_EXTENSIONS
|
||||
VK_EQ_TYPEID(VkVideoSessionKHR, VIDEO_SESSION_KHR);
|
||||
#endif
|
||||
#ifdef VK_ENABLE_BETA_EXTENSIONS
|
||||
VK_EQ_TYPEID(VkVideoSessionParametersKHR, VIDEO_SESSION_PARAMETERS_KHR);
|
||||
#endif
|
||||
VK_EQ_TYPEID(VkCuModuleNVX, CU_MODULE_NVX);
|
||||
VK_EQ_TYPEID(VkCuFunctionNVX, CU_FUNCTION_NVX);
|
||||
VK_EQ_TYPEID(VkDebugUtilsMessengerEXT, DEBUG_UTILS_MESSENGER_EXT);
|
||||
VK_EQ_TYPEID(VkAccelerationStructureKHR, ACCELERATION_STRUCTURE_KHR);
|
||||
VK_EQ_TYPEID(VkValidationCacheEXT, VALIDATION_CACHE_EXT);
|
||||
VK_EQ_TYPEID(VkAccelerationStructureNV, ACCELERATION_STRUCTURE_NV);
|
||||
VK_EQ_TYPEID(VkPerformanceConfigurationINTEL, PERFORMANCE_CONFIGURATION_INTEL);
|
||||
VK_EQ_TYPEID(VkDeferredOperationKHR, DEFERRED_OPERATION_KHR);
|
||||
VK_EQ_TYPEID(VkIndirectCommandsLayoutNV, INDIRECT_COMMANDS_LAYOUT_NV);
|
||||
VK_EQ_TYPEID(VkPrivateDataSlotEXT, PRIVATE_DATA_SLOT_EXT);
|
||||
|
||||
BLI_assert_unreachable();
|
||||
#undef VK_EQ_TYPEID
|
||||
return VK_OBJECT_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
} // namespace blender::gpu
|
||||
|
@ -4,8 +4,8 @@
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#include "vk_context.hh"
|
||||
#include "vk_debug.hh"
|
||||
|
||||
#include "vk_backend.hh"
|
||||
#include "vk_framebuffer.hh"
|
||||
@ -31,8 +31,12 @@ VKContext::VKContext(void *ghost_window, void *ghost_context)
|
||||
&vk_device_,
|
||||
&vk_queue_family_,
|
||||
&vk_queue_);
|
||||
debug::init_callbacks(this, vkGetInstanceProcAddr);
|
||||
init_physical_device_limits();
|
||||
|
||||
debug::object_label(this, vk_device_, "LogicalDevice");
|
||||
debug::object_label(this, vk_queue_, "GenericQueue");
|
||||
|
||||
/* Initialize the memory allocator. */
|
||||
VmaAllocatorCreateInfo info = {};
|
||||
/* Should use same vulkan version as GHOST (1.2), but set to 1.0 as 1.2 requires
|
||||
@ -57,6 +61,7 @@ VKContext::VKContext(void *ghost_window, void *ghost_context)
|
||||
VKContext::~VKContext()
|
||||
{
|
||||
vmaDestroyAllocator(mem_allocator_);
|
||||
debug::destroy_callbacks(this);
|
||||
}
|
||||
|
||||
void VKContext::init_physical_device_limits()
|
||||
|
@ -8,8 +8,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "gpu_context_private.hh"
|
||||
|
||||
#include "vk_command_buffer.hh"
|
||||
#include "vk_common.hh"
|
||||
#include "vk_debug.hh"
|
||||
#include "vk_descriptor_pools.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
@ -32,6 +33,9 @@ class VKContext : public Context {
|
||||
/** Limits of the device linked to this context. */
|
||||
VkPhysicalDeviceLimits vk_physical_device_limits_;
|
||||
|
||||
/** Functions of vk_ext_debugutils to use in this context. */
|
||||
debug::VKDebuggingTools debugging_tools_;
|
||||
|
||||
void *ghost_context_;
|
||||
|
||||
public:
|
||||
@ -74,6 +78,11 @@ class VKContext : public Context {
|
||||
return vk_physical_device_limits_;
|
||||
}
|
||||
|
||||
VkInstance instance_get() const
|
||||
{
|
||||
return vk_instance_;
|
||||
};
|
||||
|
||||
VkDevice device_get() const
|
||||
{
|
||||
return vk_device_;
|
||||
@ -104,6 +113,16 @@ class VKContext : public Context {
|
||||
return mem_allocator_;
|
||||
}
|
||||
|
||||
debug::VKDebuggingTools &debugging_tools_get()
|
||||
{
|
||||
return debugging_tools_;
|
||||
}
|
||||
|
||||
const debug::VKDebuggingTools &debugging_tools_get() const
|
||||
{
|
||||
return debugging_tools_;
|
||||
}
|
||||
|
||||
private:
|
||||
void init_physical_device_limits();
|
||||
|
||||
|
@ -5,13 +5,22 @@
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#include "BKE_global.h"
|
||||
|
||||
#include "vk_backend.hh"
|
||||
#include "vk_context.hh"
|
||||
#include "vk_debug.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
void VKContext::debug_group_begin(const char *, int) {}
|
||||
void VKContext::debug_group_begin(const char *name, int)
|
||||
{
|
||||
debug::push_marker(this, vk_queue_, name);
|
||||
}
|
||||
|
||||
void VKContext::debug_group_end() {}
|
||||
void VKContext::debug_group_end()
|
||||
{
|
||||
debug::pop_marker(this, vk_queue_);
|
||||
}
|
||||
|
||||
bool VKContext::debug_capture_begin()
|
||||
{
|
||||
@ -54,3 +63,164 @@ bool VKContext::debug_capture_scope_begin(void * /*scope*/)
|
||||
|
||||
void VKContext::debug_capture_scope_end(void * /*scope*/) {}
|
||||
} // namespace blender::gpu
|
||||
|
||||
namespace blender::gpu::debug {
|
||||
|
||||
static void load_dynamic_functions(VKContext *context,
|
||||
PFN_vkGetInstanceProcAddr instance_proc_addr)
|
||||
{
|
||||
VKDebuggingTools &debugging_tools = context->debugging_tools_get();
|
||||
VkInstance vk_instance = context->instance_get();
|
||||
|
||||
if (instance_proc_addr) {
|
||||
|
||||
debugging_tools.enabled = false;
|
||||
debugging_tools.vkCmdBeginDebugUtilsLabelEXT_r = (PFN_vkCmdBeginDebugUtilsLabelEXT)
|
||||
instance_proc_addr(vk_instance, "vkCmdBeginDebugUtilsLabelEXT");
|
||||
debugging_tools.vkCmdEndDebugUtilsLabelEXT_r = (PFN_vkCmdEndDebugUtilsLabelEXT)
|
||||
instance_proc_addr(vk_instance, "vkCmdEndDebugUtilsLabelEXT");
|
||||
debugging_tools.vkCmdInsertDebugUtilsLabelEXT_r = (PFN_vkCmdInsertDebugUtilsLabelEXT)
|
||||
instance_proc_addr(vk_instance, "vkCmdInsertDebugUtilsLabelEXT");
|
||||
debugging_tools.vkCreateDebugUtilsMessengerEXT_r = (PFN_vkCreateDebugUtilsMessengerEXT)
|
||||
instance_proc_addr(vk_instance, "vkCreateDebugUtilsMessengerEXT");
|
||||
debugging_tools.vkDestroyDebugUtilsMessengerEXT_r = (PFN_vkDestroyDebugUtilsMessengerEXT)
|
||||
instance_proc_addr(vk_instance, "vkDestroyDebugUtilsMessengerEXT");
|
||||
debugging_tools.vkQueueBeginDebugUtilsLabelEXT_r = (PFN_vkQueueBeginDebugUtilsLabelEXT)
|
||||
instance_proc_addr(vk_instance, "vkQueueBeginDebugUtilsLabelEXT");
|
||||
debugging_tools.vkQueueEndDebugUtilsLabelEXT_r = (PFN_vkQueueEndDebugUtilsLabelEXT)
|
||||
instance_proc_addr(vk_instance, "vkQueueEndDebugUtilsLabelEXT");
|
||||
debugging_tools.vkQueueInsertDebugUtilsLabelEXT_r = (PFN_vkQueueInsertDebugUtilsLabelEXT)
|
||||
instance_proc_addr(vk_instance, "vkQueueInsertDebugUtilsLabelEXT");
|
||||
debugging_tools.vkSetDebugUtilsObjectNameEXT_r = (PFN_vkSetDebugUtilsObjectNameEXT)
|
||||
instance_proc_addr(vk_instance, "vkSetDebugUtilsObjectNameEXT");
|
||||
debugging_tools.vkSetDebugUtilsObjectTagEXT_r = (PFN_vkSetDebugUtilsObjectTagEXT)
|
||||
instance_proc_addr(vk_instance, "vkSetDebugUtilsObjectTagEXT");
|
||||
debugging_tools.vkSubmitDebugUtilsMessageEXT_r = (PFN_vkSubmitDebugUtilsMessageEXT)
|
||||
instance_proc_addr(vk_instance, "vkSubmitDebugUtilsMessageEXT");
|
||||
if (debugging_tools.vkCmdBeginDebugUtilsLabelEXT_r) {
|
||||
debugging_tools.enabled = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
debugging_tools.vkCmdBeginDebugUtilsLabelEXT_r = nullptr;
|
||||
debugging_tools.vkCmdEndDebugUtilsLabelEXT_r = nullptr;
|
||||
debugging_tools.vkCmdInsertDebugUtilsLabelEXT_r = nullptr;
|
||||
debugging_tools.vkCreateDebugUtilsMessengerEXT_r = nullptr;
|
||||
debugging_tools.vkDestroyDebugUtilsMessengerEXT_r = nullptr;
|
||||
debugging_tools.vkQueueBeginDebugUtilsLabelEXT_r = nullptr;
|
||||
debugging_tools.vkQueueEndDebugUtilsLabelEXT_r = nullptr;
|
||||
debugging_tools.vkQueueInsertDebugUtilsLabelEXT_r = nullptr;
|
||||
debugging_tools.vkSetDebugUtilsObjectNameEXT_r = nullptr;
|
||||
debugging_tools.vkSetDebugUtilsObjectTagEXT_r = nullptr;
|
||||
debugging_tools.vkSubmitDebugUtilsMessageEXT_r = nullptr;
|
||||
debugging_tools.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool init_callbacks(VKContext *context, PFN_vkGetInstanceProcAddr instance_proc_addr)
|
||||
{
|
||||
if (instance_proc_addr) {
|
||||
load_dynamic_functions(context, instance_proc_addr);
|
||||
return true;
|
||||
};
|
||||
return false;
|
||||
}
|
||||
|
||||
void destroy_callbacks(VKContext *context)
|
||||
{
|
||||
VKDebuggingTools &debugging_tools = context->debugging_tools_get();
|
||||
if (debugging_tools.enabled) {
|
||||
load_dynamic_functions(context, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void object_label(VKContext *context,
|
||||
VkObjectType vk_object_type,
|
||||
uint64_t object_handle,
|
||||
const char *name)
|
||||
{
|
||||
if (G.debug & G_DEBUG_GPU) {
|
||||
const VKDebuggingTools &debugging_tools = context->debugging_tools_get();
|
||||
if (debugging_tools.enabled) {
|
||||
VkDebugUtilsObjectNameInfoEXT info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
|
||||
info.objectType = vk_object_type;
|
||||
info.objectHandle = object_handle;
|
||||
info.pObjectName = name;
|
||||
debugging_tools.vkSetDebugUtilsObjectNameEXT_r(context->device_get(), &info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void push_marker(VKContext *context, VkCommandBuffer vk_command_buffer, const char *name)
|
||||
{
|
||||
if (G.debug & G_DEBUG_GPU) {
|
||||
const VKDebuggingTools &debugging_tools = context->debugging_tools_get();
|
||||
if (debugging_tools.enabled) {
|
||||
VkDebugUtilsLabelEXT info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
|
||||
info.pLabelName = name;
|
||||
debugging_tools.vkCmdBeginDebugUtilsLabelEXT_r(vk_command_buffer, &info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_marker(VKContext *context, VkCommandBuffer vk_command_buffer, const char *name)
|
||||
{
|
||||
if (G.debug & G_DEBUG_GPU) {
|
||||
const VKDebuggingTools &debugging_tools = context->debugging_tools_get();
|
||||
if (debugging_tools.enabled) {
|
||||
VkDebugUtilsLabelEXT info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
|
||||
info.pLabelName = name;
|
||||
debugging_tools.vkCmdInsertDebugUtilsLabelEXT_r(vk_command_buffer, &info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pop_marker(VKContext *context, VkCommandBuffer vk_command_buffer)
|
||||
{
|
||||
if (G.debug & G_DEBUG_GPU) {
|
||||
const VKDebuggingTools &debugging_tools = context->debugging_tools_get();
|
||||
if (debugging_tools.enabled) {
|
||||
debugging_tools.vkCmdEndDebugUtilsLabelEXT_r(vk_command_buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void push_marker(VKContext *context, VkQueue vk_queue, const char *name)
|
||||
{
|
||||
if (G.debug & G_DEBUG_GPU) {
|
||||
const VKDebuggingTools &debugging_tools = context->debugging_tools_get();
|
||||
if (debugging_tools.enabled) {
|
||||
VkDebugUtilsLabelEXT info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
|
||||
info.pLabelName = name;
|
||||
debugging_tools.vkQueueBeginDebugUtilsLabelEXT_r(vk_queue, &info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_marker(VKContext *context, VkQueue vk_queue, const char *name)
|
||||
{
|
||||
if (G.debug & G_DEBUG_GPU) {
|
||||
const VKDebuggingTools &debugging_tools = context->debugging_tools_get();
|
||||
if (debugging_tools.enabled) {
|
||||
VkDebugUtilsLabelEXT info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
|
||||
info.pLabelName = name;
|
||||
debugging_tools.vkQueueInsertDebugUtilsLabelEXT_r(vk_queue, &info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pop_marker(VKContext *context, VkQueue vk_queue)
|
||||
{
|
||||
if (G.debug & G_DEBUG_GPU) {
|
||||
const VKDebuggingTools &debugging_tools = context->debugging_tools_get();
|
||||
if (debugging_tools.enabled) {
|
||||
debugging_tools.vkQueueEndDebugUtilsLabelEXT_r(vk_queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace blender::gpu::debug
|
||||
|
60
source/blender/gpu/vulkan/vk_debug.hh
Normal file
60
source/blender/gpu/vulkan/vk_debug.hh
Normal file
@ -0,0 +1,60 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation. All rights reserved. */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "BKE_global.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "vk_common.hh"
|
||||
|
||||
#include <typeindex>
|
||||
|
||||
namespace blender::gpu {
|
||||
class VKContext;
|
||||
namespace debug {
|
||||
typedef struct VKDebuggingTools {
|
||||
bool enabled = false;
|
||||
/* Function pointer definitions. */
|
||||
PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT_r = nullptr;
|
||||
PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT_r = nullptr;
|
||||
PFN_vkSubmitDebugUtilsMessageEXT vkSubmitDebugUtilsMessageEXT_r = nullptr;
|
||||
PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT_r = nullptr;
|
||||
PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT_r = nullptr;
|
||||
PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT_r = nullptr;
|
||||
PFN_vkQueueBeginDebugUtilsLabelEXT vkQueueBeginDebugUtilsLabelEXT_r = nullptr;
|
||||
PFN_vkQueueEndDebugUtilsLabelEXT vkQueueEndDebugUtilsLabelEXT_r = nullptr;
|
||||
PFN_vkQueueInsertDebugUtilsLabelEXT vkQueueInsertDebugUtilsLabelEXT_r = nullptr;
|
||||
PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT_r = nullptr;
|
||||
PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT_r = nullptr;
|
||||
|
||||
} VKDebuggingTools;
|
||||
|
||||
bool init_callbacks(VKContext *context, PFN_vkGetInstanceProcAddr instance_proc_addr);
|
||||
void destroy_callbacks(VKContext *context);
|
||||
void object_label(VKContext *context, VkObjectType vk_object_type, uint64_t object_handle, const char *name);
|
||||
|
||||
template<typename T> void object_label(VKContext *context, T vk_object_type, const char *name)
|
||||
{
|
||||
if (!(G.debug & G_DEBUG_GPU)) {
|
||||
return;
|
||||
}
|
||||
const size_t label_size = 64;
|
||||
char label[label_size];
|
||||
memset(label, 0, label_size);
|
||||
static int stats = 0;
|
||||
SNPRINTF(label, "%s_%d", name, stats++);
|
||||
object_label(context, to_vk_object_type(vk_object_type), (uint64_t)vk_object_type, (const char *)label);
|
||||
};
|
||||
|
||||
void push_marker(VKContext *context, VkCommandBuffer vk_command_buffer, const char *name);
|
||||
void set_marker(VKContext *context, VkCommandBuffer vk_command_buffer, const char *name);
|
||||
void pop_marker(VKContext *context, VkCommandBuffer vk_command_buffer);
|
||||
void push_marker(VKContext *context, VkQueue vk_queue, const char *name);
|
||||
void set_marker(VKContext *context, VkQueue vk_queue, const char *name);
|
||||
void pop_marker(VKContext *context, VkQueue vk_queue);
|
||||
} // namespace debug
|
||||
} // namespace blender::gpu
|
@ -230,7 +230,7 @@ static void FlipDXTCImage(ImBuf *ibuf)
|
||||
|
||||
const uint8_t *data_end = data + data_size;
|
||||
|
||||
for (uint i = 0; i < levels; i++) {
|
||||
for (uint level = 0; level < levels; level++) {
|
||||
uint blocks_per_row = (mip_width + 3) / 4;
|
||||
uint blocks_per_col = (mip_height + 3) / 4;
|
||||
uint blocks = blocks_per_row * blocks_per_col;
|
||||
@ -238,7 +238,7 @@ static void FlipDXTCImage(ImBuf *ibuf)
|
||||
if (data + block_bytes * blocks > data_end) {
|
||||
/* Stop flipping when running out of data to be modified, avoiding possible buffer overrun
|
||||
* on a malformed files. */
|
||||
*num_valid_levels = i;
|
||||
*num_valid_levels = level;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -753,6 +753,7 @@ static void rna_def_attribute_float(BlenderRNA *brna)
|
||||
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "FloatAttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Attribute_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -785,6 +786,7 @@ static void rna_def_attribute_float_vector(BlenderRNA *brna)
|
||||
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "FloatVectorAttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Attribute_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -823,6 +825,7 @@ static void rna_def_attribute_float_color(BlenderRNA *brna)
|
||||
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "FloatColorAttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Attribute_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -870,6 +873,7 @@ static void rna_def_attribute_byte_color(BlenderRNA *brna)
|
||||
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "ByteColorAttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Attribute_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -918,6 +922,7 @@ static void rna_def_attribute_int(BlenderRNA *brna)
|
||||
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "IntAttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Attribute_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -947,6 +952,7 @@ static void rna_def_attribute_string(BlenderRNA *brna)
|
||||
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "StringAttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Attribute_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -976,6 +982,7 @@ static void rna_def_attribute_bool(BlenderRNA *brna)
|
||||
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "BoolAttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Attribute_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -1005,6 +1012,7 @@ static void rna_def_attribute_int8(BlenderRNA *brna)
|
||||
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "ByteIntAttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Attribute_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -1036,6 +1044,7 @@ static void rna_def_attribute_int2(BlenderRNA *brna)
|
||||
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "Int2AttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Attribute_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -1071,6 +1080,7 @@ static void rna_def_attribute_float2(BlenderRNA *brna)
|
||||
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "Float2AttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Attribute_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -345,6 +345,7 @@ static void rna_def_curves_curve(BlenderRNA *brna)
|
||||
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "CurvePoint");
|
||||
RNA_def_property_ui_text(prop, "Points", "Control points of the curve");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_CurveSlice_points_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -384,6 +385,7 @@ static void rna_def_curves(BlenderRNA *brna)
|
||||
/* Point and Curve RNA API helpers. */
|
||||
|
||||
prop = RNA_def_property(srna, "curves", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Curves_curves_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -398,6 +400,7 @@ static void rna_def_curves(BlenderRNA *brna)
|
||||
|
||||
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "CurvePoint");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Curves_position_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -412,6 +415,7 @@ static void rna_def_curves(BlenderRNA *brna)
|
||||
/* Direct access to built-in attributes. */
|
||||
|
||||
prop = RNA_def_property(srna, "position_data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Curves_position_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -426,6 +430,7 @@ static void rna_def_curves(BlenderRNA *brna)
|
||||
|
||||
prop = RNA_def_property(srna, "curve_offset_data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "IntAttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Curves_curve_offset_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -440,6 +445,7 @@ static void rna_def_curves(BlenderRNA *brna)
|
||||
rna_def_read_only_float_vector(brna);
|
||||
|
||||
prop = RNA_def_property(srna, "normals", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_struct_type(prop, "FloatVectorValueReadOnly");
|
||||
/* `lookup_int` isn't provided since the entire normals array is allocated and calculated when
|
||||
* it's accessed. */
|
||||
|
@ -3107,6 +3107,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
|
||||
prop,
|
||||
"MeshUVLoop (Deprecated)",
|
||||
"Deprecated, use 'uv', 'vertex_select', 'edge_select' or 'pin' properties instead");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_MeshUVLoopLayer_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -3147,6 +3148,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
|
||||
prop = RNA_def_property(srna, "uv", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "Float2AttributeValue");
|
||||
RNA_def_property_ui_text(prop, "UV", "UV coordinates on face corners");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_MeshUVLoopLayer_uv_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -3161,6 +3163,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
|
||||
RNA_def_property_struct_type(prop, "BoolAttributeValue");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "UV Vertex Selection", "Selection state of the face corner the UV editor");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_MeshUVLoopLayer_vert_select_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -3175,6 +3178,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
|
||||
RNA_def_property_struct_type(prop, "BoolAttributeValue");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "UV Edge Selection", "Selection state of the edge in the UV editor");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_MeshUVLoopLayer_edge_select_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -3188,6 +3192,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
|
||||
prop = RNA_def_property(srna, "pin", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "BoolAttributeValue");
|
||||
RNA_def_property_ui_text(prop, "UV Pin", "UV pinned state in the UV editor");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_MeshUVLoopLayer_pin_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -3256,6 +3261,7 @@ static void rna_def_mloopcol(BlenderRNA *brna)
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "MeshLoopColor");
|
||||
RNA_def_property_ui_text(prop, "Data", "");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_MeshLoopColorLayer_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -3317,6 +3323,7 @@ static void rna_def_MPropCol(BlenderRNA *brna)
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "MeshVertColor");
|
||||
RNA_def_property_ui_text(prop, "Data", "");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_MeshVertColorLayer_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -3362,6 +3369,7 @@ static void rna_def_mproperties(BlenderRNA *brna)
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); \
|
||||
RNA_def_property_struct_type(prop, "Mesh" elemname "FloatProperty"); \
|
||||
RNA_def_property_ui_text(prop, "Data", ""); \
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); \
|
||||
RNA_def_property_collection_funcs(prop, \
|
||||
"rna_Mesh" elemname "FloatPropertyLayer_data_begin", \
|
||||
"rna_iterator_array_next", \
|
||||
@ -3405,6 +3413,7 @@ static void rna_def_mproperties(BlenderRNA *brna)
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); \
|
||||
RNA_def_property_struct_type(prop, "Mesh" elemname "IntProperty"); \
|
||||
RNA_def_property_ui_text(prop, "Data", ""); \
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); \
|
||||
RNA_def_property_collection_funcs(prop, \
|
||||
"rna_Mesh" elemname "IntPropertyLayer_data_begin", \
|
||||
"rna_iterator_array_next", \
|
||||
@ -3447,6 +3456,7 @@ static void rna_def_mproperties(BlenderRNA *brna)
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); \
|
||||
RNA_def_property_struct_type(prop, "Mesh" elemname "StringProperty"); \
|
||||
RNA_def_property_ui_text(prop, "Data", ""); \
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); \
|
||||
RNA_def_property_collection_funcs(prop, \
|
||||
"rna_Mesh" elemname "StringPropertyLayer_data_begin", \
|
||||
"rna_iterator_array_next", \
|
||||
@ -3955,6 +3965,7 @@ static void rna_def_skin_vertices(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "MeshSkinVertex");
|
||||
RNA_def_property_ui_text(prop, "Data", "");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_MeshSkinVertexLayer_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -4008,6 +4019,7 @@ static void rna_def_vertex_creases(BlenderRNA *brna)
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "MeshVertexCrease");
|
||||
RNA_def_property_ui_text(prop, "Data", "");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_MeshVertexCreaseLayer_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
@ -4042,6 +4054,7 @@ static void rna_def_edge_creases(BlenderRNA *brna)
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "MeshEdgeCrease");
|
||||
RNA_def_property_ui_text(prop, "Data", "");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_MeshEdgeCreaseLayer_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -177,6 +177,7 @@ static void rna_def_pointcloud(BlenderRNA *brna)
|
||||
/* geometry */
|
||||
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "Point");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_PointCloud_points_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -138,7 +138,7 @@ static std::function<ID *(const bNode &node)> get_default_id_getter(const bNodeT
|
||||
return nullptr;
|
||||
}
|
||||
const bNodeTree &ntree = *reinterpret_cast<const bNodeTree *>(node.id);
|
||||
const bNodeSocket *io_socket;
|
||||
const bNodeSocket *io_socket = nullptr;
|
||||
if (in_out == SOCK_IN) {
|
||||
/* Better be safe than sorry when the underlying node group changed. */
|
||||
if (socket_index < ntree.interface_inputs().size()) {
|
||||
|
Loading…
Reference in New Issue
Block a user