Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/intern
diff options
context:
space:
mode:
Diffstat (limited to 'intern')
-rw-r--r--intern/atomic/atomic_ops.h12
-rw-r--r--intern/atomic/intern/atomic_ops_ext.h36
-rw-r--r--intern/atomic/intern/atomic_ops_msvc.h53
-rw-r--r--intern/atomic/intern/atomic_ops_unix.h131
-rw-r--r--intern/atomic/tests/atomic_test.cc189
-rw-r--r--intern/audaspace/CMakeLists.txt8
-rw-r--r--intern/cycles/blender/addon/__init__.py2
-rw-r--r--intern/cycles/blender/addon/camera.py2
-rw-r--r--intern/cycles/blender/addon/engine.py2
-rw-r--r--intern/cycles/blender/addon/operators.py2
-rw-r--r--intern/cycles/blender/addon/osl.py2
-rw-r--r--intern/cycles/blender/addon/presets.py2
-rw-r--r--intern/cycles/blender/addon/properties.py101
-rw-r--r--intern/cycles/blender/addon/ui.py16
-rw-r--r--intern/cycles/blender/addon/version_update.py2
-rw-r--r--intern/cycles/blender/image.cpp176
-rw-r--r--intern/cycles/blender/image.h8
-rw-r--r--intern/cycles/blender/mesh.cpp2
-rw-r--r--intern/cycles/blender/shader.cpp32
-rw-r--r--intern/cycles/blender/volume.cpp24
-rw-r--r--intern/cycles/bvh/build.cpp2
-rw-r--r--intern/cycles/cmake/external_libs.cmake4
-rw-r--r--intern/cycles/device/cuda/device_impl.cpp4
-rw-r--r--intern/cycles/device/hip/device_impl.cpp4
-rw-r--r--intern/cycles/device/memory.cpp2
-rw-r--r--intern/cycles/device/metal/device_impl.h6
-rw-r--r--intern/cycles/device/metal/device_impl.mm99
-rw-r--r--intern/cycles/device/metal/kernel.h108
-rw-r--r--intern/cycles/device/metal/kernel.mm858
-rw-r--r--intern/cycles/device/metal/queue.mm31
-rw-r--r--intern/cycles/device/optix/device_impl.cpp50
-rw-r--r--intern/cycles/kernel/CMakeLists.txt1
-rw-r--r--intern/cycles/kernel/device/cpu/image.h10
-rw-r--r--intern/cycles/kernel/device/gpu/image.h13
-rw-r--r--intern/cycles/kernel/device/metal/compat.h24
-rw-r--r--intern/cycles/kernel/osl/services.cpp38
-rw-r--r--intern/cycles/kernel/osl/services.h14
-rw-r--r--intern/cycles/kernel/osl/shaders/CMakeLists.txt2
-rw-r--r--intern/cycles/kernel/osl/shaders/node_color.h50
-rw-r--r--intern/cycles/kernel/osl/shaders/node_combine_color.osl16
-rw-r--r--intern/cycles/kernel/osl/shaders/node_separate_color.osl26
-rw-r--r--intern/cycles/kernel/svm/color_util.h26
-rw-r--r--intern/cycles/kernel/svm/sepcomb_color.h54
-rw-r--r--intern/cycles/kernel/svm/svm.h7
-rw-r--r--intern/cycles/kernel/svm/types.h8
-rw-r--r--intern/cycles/scene/attribute.cpp52
-rw-r--r--intern/cycles/scene/attribute.h1
-rw-r--r--intern/cycles/scene/image.cpp71
-rw-r--r--intern/cycles/scene/image.h9
-rw-r--r--intern/cycles/scene/image_oiio.cpp45
-rw-r--r--intern/cycles/scene/image_vdb.cpp37
-rw-r--r--intern/cycles/scene/image_vdb.h1
-rw-r--r--intern/cycles/scene/object.cpp6
-rw-r--r--intern/cycles/scene/osl.cpp7
-rw-r--r--intern/cycles/scene/osl.h2
-rw-r--r--intern/cycles/scene/shader_graph.cpp12
-rw-r--r--intern/cycles/scene/shader_nodes.cpp139
-rw-r--r--intern/cycles/scene/shader_nodes.h20
-rw-r--r--intern/cycles/util/color.h50
-rw-r--r--intern/cycles/util/image.h20
-rw-r--r--intern/cycles/util/texture.h2
-rw-r--r--intern/ghost/CMakeLists.txt2
-rw-r--r--intern/ghost/GHOST_C-api.h4
-rw-r--r--intern/ghost/GHOST_Types.h2
-rw-r--r--intern/ghost/intern/GHOST_Buttons.cpp24
-rw-r--r--intern/ghost/intern/GHOST_Buttons.h4
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp47
-rw-r--r--intern/ghost/intern/GHOST_ContextEGL.cpp94
-rw-r--r--intern/ghost/intern/GHOST_ContextGLX.cpp97
-rw-r--r--intern/ghost/intern/GHOST_ContextSDL.cpp65
-rw-r--r--intern/ghost/intern/GHOST_ContextWGL.cpp6
-rw-r--r--intern/ghost/intern/GHOST_DisplayManager.cpp8
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerSDL.cpp18
-rw-r--r--intern/ghost/intern/GHOST_DisplayManagerX11.cpp9
-rw-r--r--intern/ghost/intern/GHOST_DropTargetX11.cpp32
-rw-r--r--intern/ghost/intern/GHOST_ISystem.cpp6
-rw-r--r--intern/ghost/intern/GHOST_ISystemPaths.cpp8
-rw-r--r--intern/ghost/intern/GHOST_Path-api.cpp11
-rw-r--r--intern/ghost/intern/GHOST_System.cpp30
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm6
-rw-r--r--intern/ghost/intern/GHOST_SystemNULL.h6
-rw-r--r--intern/ghost/intern/GHOST_SystemPathsUnix.cpp51
-rw-r--r--intern/ghost/intern/GHOST_SystemSDL.cpp78
-rw-r--r--intern/ghost/intern/GHOST_SystemSDL.h2
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.cpp126
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.h8
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.cpp87
-rw-r--r--intern/ghost/intern/GHOST_SystemWin32.h10
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp136
-rw-r--r--intern/ghost/intern/GHOST_TaskbarX11.cpp20
-rw-r--r--intern/ghost/intern/GHOST_TimerTask.h2
-rw-r--r--intern/ghost/intern/GHOST_TrackpadWin32.cpp343
-rw-r--r--intern/ghost/intern/GHOST_TrackpadWin32.h138
-rw-r--r--intern/ghost/intern/GHOST_WaylandCursorSettings.h6
-rw-r--r--intern/ghost/intern/GHOST_Window.cpp38
-rw-r--r--intern/ghost/intern/GHOST_WindowCocoa.mm4
-rw-r--r--intern/ghost/intern/GHOST_WindowManager.cpp27
-rw-r--r--intern/ghost/intern/GHOST_WindowNULL.h2
-rw-r--r--intern/ghost/intern/GHOST_WindowSDL.cpp54
-rw-r--r--intern/ghost/intern/GHOST_WindowSDL.h2
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.cpp17
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp74
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.h21
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.cpp182
-rw-r--r--intern/guardedalloc/MEM_guardedalloc.h4
-rw-r--r--intern/guardedalloc/intern/mallocn_guarded_impl.c2
-rw-r--r--intern/iksolver/intern/IK_QTask.cpp2
-rw-r--r--intern/libmv/CMakeLists.txt1
-rwxr-xr-xintern/libmv/bundle.sh1
-rw-r--r--intern/libmv/libmv/multiview/euclidean_resection.h2
-rw-r--r--intern/libmv/libmv/simple_pipeline/bundle.cc17
-rw-r--r--intern/libmv/libmv/simple_pipeline/modal_solver.cc9
-rw-r--r--intern/opensubdiv/internal/evaluator/eval_output.h55
-rw-r--r--intern/opensubdiv/internal/evaluator/eval_output_cpu.h2
-rw-r--r--intern/opensubdiv/internal/evaluator/eval_output_gpu.cc6
-rw-r--r--intern/opensubdiv/internal/evaluator/eval_output_gpu.h2
-rw-r--r--intern/opensubdiv/internal/evaluator/evaluator_capi.cc14
-rw-r--r--intern/opensubdiv/internal/evaluator/evaluator_impl.cc12
-rw-r--r--intern/opensubdiv/internal/evaluator/evaluator_impl.h6
-rw-r--r--intern/opensubdiv/opensubdiv_evaluator_capi.h7
-rw-r--r--intern/rigidbody/RBI_api.h2
121 files changed, 3412 insertions, 1372 deletions
diff --git a/intern/atomic/atomic_ops.h b/intern/atomic/atomic_ops.h
index 6a4d6d263c0..65b0c8f9671 100644
--- a/intern/atomic/atomic_ops.h
+++ b/intern/atomic/atomic_ops.h
@@ -64,16 +64,22 @@ ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x);
ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x);
ATOMIC_INLINE uint64_t atomic_fetch_and_sub_uint64(uint64_t *p, uint64_t x);
ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _new);
+ATOMIC_INLINE uint64_t atomic_load_uint64(const uint64_t *v);
+ATOMIC_INLINE void atomic_store_uint64(uint64_t *p, uint64_t v);
ATOMIC_INLINE int64_t atomic_add_and_fetch_int64(int64_t *p, int64_t x);
ATOMIC_INLINE int64_t atomic_sub_and_fetch_int64(int64_t *p, int64_t x);
ATOMIC_INLINE int64_t atomic_fetch_and_add_int64(int64_t *p, int64_t x);
ATOMIC_INLINE int64_t atomic_fetch_and_sub_int64(int64_t *p, int64_t x);
ATOMIC_INLINE int64_t atomic_cas_int64(int64_t *v, int64_t old, int64_t _new);
+ATOMIC_INLINE int64_t atomic_load_int64(const int64_t *v);
+ATOMIC_INLINE void atomic_store_int64(int64_t *p, int64_t v);
ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x);
ATOMIC_INLINE uint32_t atomic_sub_and_fetch_uint32(uint32_t *p, uint32_t x);
ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _new);
+ATOMIC_INLINE uint32_t atomic_load_uint32(const uint32_t *v);
+ATOMIC_INLINE void atomic_store_uint32(uint32_t *p, uint32_t v);
ATOMIC_INLINE uint32_t atomic_fetch_and_add_uint32(uint32_t *p, uint32_t x);
ATOMIC_INLINE uint32_t atomic_fetch_and_or_uint32(uint32_t *p, uint32_t x);
@@ -82,6 +88,8 @@ ATOMIC_INLINE uint32_t atomic_fetch_and_and_uint32(uint32_t *p, uint32_t x);
ATOMIC_INLINE int32_t atomic_add_and_fetch_int32(int32_t *p, int32_t x);
ATOMIC_INLINE int32_t atomic_sub_and_fetch_int32(int32_t *p, int32_t x);
ATOMIC_INLINE int32_t atomic_cas_int32(int32_t *v, int32_t old, int32_t _new);
+ATOMIC_INLINE int32_t atomic_load_int32(const int32_t *v);
+ATOMIC_INLINE void atomic_store_int32(int32_t *p, int32_t v);
ATOMIC_INLINE int32_t atomic_fetch_and_add_int32(int32_t *p, int32_t x);
ATOMIC_INLINE int32_t atomic_fetch_and_or_int32(int32_t *p, int32_t x);
@@ -104,6 +112,8 @@ ATOMIC_INLINE size_t atomic_sub_and_fetch_z(size_t *p, size_t x);
ATOMIC_INLINE size_t atomic_fetch_and_add_z(size_t *p, size_t x);
ATOMIC_INLINE size_t atomic_fetch_and_sub_z(size_t *p, size_t x);
ATOMIC_INLINE size_t atomic_cas_z(size_t *v, size_t old, size_t _new);
+ATOMIC_INLINE size_t atomic_load_z(const size_t *v);
+ATOMIC_INLINE void atomic_store_z(size_t *p, size_t v);
/* Uses CAS loop, see warning below. */
ATOMIC_INLINE size_t atomic_fetch_and_update_max_z(size_t *p, size_t x);
@@ -114,6 +124,8 @@ ATOMIC_INLINE unsigned int atomic_fetch_and_sub_u(unsigned int *p, unsigned int
ATOMIC_INLINE unsigned int atomic_cas_u(unsigned int *v, unsigned int old, unsigned int _new);
ATOMIC_INLINE void *atomic_cas_ptr(void **v, void *old, void *_new);
+ATOMIC_INLINE void *atomic_load_ptr(void *const *v);
+ATOMIC_INLINE void atomic_store_ptr(void **p, void *v);
ATOMIC_INLINE float atomic_cas_float(float *v, float old, float _new);
diff --git a/intern/atomic/intern/atomic_ops_ext.h b/intern/atomic/intern/atomic_ops_ext.h
index aedf0985169..b5e1022fb91 100644
--- a/intern/atomic/intern/atomic_ops_ext.h
+++ b/intern/atomic/intern/atomic_ops_ext.h
@@ -102,6 +102,24 @@ ATOMIC_INLINE size_t atomic_cas_z(size_t *v, size_t old, size_t _new)
#endif
}
+ATOMIC_INLINE size_t atomic_load_z(const size_t *v)
+{
+#if (LG_SIZEOF_PTR == 8)
+ return (size_t)atomic_load_uint64((const uint64_t *)v);
+#elif (LG_SIZEOF_PTR == 4)
+ return (size_t)atomic_load_uint32((const uint32_t *)v);
+#endif
+}
+
+ATOMIC_INLINE void atomic_store_z(size_t *p, size_t v)
+{
+#if (LG_SIZEOF_PTR == 8)
+ atomic_store_uint64((uint64_t *)p, v);
+#elif (LG_SIZEOF_PTR == 4)
+ atomic_store_uint32((uint32_t *)p, v);
+#endif
+}
+
ATOMIC_INLINE size_t atomic_fetch_and_update_max_z(size_t *p, size_t x)
{
size_t prev_value;
@@ -187,6 +205,24 @@ ATOMIC_INLINE void *atomic_cas_ptr(void **v, void *old, void *_new)
#endif
}
+ATOMIC_INLINE void *atomic_load_ptr(void *const *v)
+{
+#if (LG_SIZEOF_PTR == 8)
+ return (void *)atomic_load_uint64((const uint64_t *)v);
+#elif (LG_SIZEOF_PTR == 4)
+ return (void *)atomic_load_uint32((const uint32_t *)v);
+#endif
+}
+
+ATOMIC_INLINE void atomic_store_ptr(void **p, void *v)
+{
+#if (LG_SIZEOF_PTR == 8)
+ atomic_store_uint64((uint64_t *)p, (uint64_t)v);
+#elif (LG_SIZEOF_PTR == 4)
+ atomic_store_uint32((uint32_t *)p, (uint32_t)v);
+#endif
+}
+
/******************************************************************************/
/* float operations. */
ATOMIC_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t), "sizeof(float) != sizeof(uint32_t)");
diff --git a/intern/atomic/intern/atomic_ops_msvc.h b/intern/atomic/intern/atomic_ops_msvc.h
index ea5ae666db9..e65691d3970 100644
--- a/intern/atomic/intern/atomic_ops_msvc.h
+++ b/intern/atomic/intern/atomic_ops_msvc.h
@@ -49,6 +49,16 @@
# pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
#endif
+/* TODO(sergey): On x64 platform both read and write of a variable aligned to its type size is
+ * atomic, so in theory it is possible to avoid memory barrier and gain performance. The downside
+ * of that would be that it will impose requirement to value which is being operated on. */
+#define __atomic_impl_load_generic(v) (MemoryBarrier(), *(v))
+#define __atomic_impl_store_generic(p, v) \
+ do { \
+ *(p) = (v); \
+ MemoryBarrier(); \
+ } while (0)
+
/* 64-bit operations. */
/* Unsigned */
ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x)
@@ -66,6 +76,16 @@ ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _ne
return InterlockedCompareExchange64((int64_t *)v, _new, old);
}
+ATOMIC_INLINE uint64_t atomic_load_uint64(const uint64_t *v)
+{
+ return __atomic_impl_load_generic(v);
+}
+
+ATOMIC_INLINE void atomic_store_uint64(uint64_t *p, uint64_t v)
+{
+ __atomic_impl_store_generic(p, v);
+}
+
ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x)
{
return InterlockedExchangeAdd64((int64_t *)p, (int64_t)x);
@@ -92,6 +112,16 @@ ATOMIC_INLINE int64_t atomic_cas_int64(int64_t *v, int64_t old, int64_t _new)
return InterlockedCompareExchange64(v, _new, old);
}
+ATOMIC_INLINE int64_t atomic_load_int64(const int64_t *v)
+{
+ return __atomic_impl_load_generic(v);
+}
+
+ATOMIC_INLINE void atomic_store_int64(int64_t *p, int64_t v)
+{
+ __atomic_impl_store_generic(p, v);
+}
+
ATOMIC_INLINE int64_t atomic_fetch_and_add_int64(int64_t *p, int64_t x)
{
return InterlockedExchangeAdd64(p, x);
@@ -120,6 +150,16 @@ ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _ne
return InterlockedCompareExchange((long *)v, _new, old);
}
+ATOMIC_INLINE uint32_t atomic_load_uint32(const uint32_t *v)
+{
+ return __atomic_impl_load_generic(v);
+}
+
+ATOMIC_INLINE void atomic_store_uint32(uint32_t *p, uint32_t v)
+{
+ __atomic_impl_store_generic(p, v);
+}
+
ATOMIC_INLINE uint32_t atomic_fetch_and_add_uint32(uint32_t *p, uint32_t x)
{
return InterlockedExchangeAdd(p, x);
@@ -151,6 +191,16 @@ ATOMIC_INLINE int32_t atomic_cas_int32(int32_t *v, int32_t old, int32_t _new)
return InterlockedCompareExchange((long *)v, _new, old);
}
+ATOMIC_INLINE int32_t atomic_load_int32(const int32_t *v)
+{
+ return __atomic_impl_load_generic(v);
+}
+
+ATOMIC_INLINE void atomic_store_int32(int32_t *p, int32_t v)
+{
+ __atomic_impl_store_generic(p, v);
+}
+
ATOMIC_INLINE int32_t atomic_fetch_and_add_int32(int32_t *p, int32_t x)
{
return InterlockedExchangeAdd((long *)p, x);
@@ -225,6 +275,9 @@ ATOMIC_INLINE int8_t atomic_fetch_and_or_int8(int8_t *p, int8_t b)
#endif
}
+#undef __atomic_impl_load_generic
+#undef __atomic_impl_store_generic
+
#if defined(__clang__)
# pragma GCC diagnostic pop
#endif
diff --git a/intern/atomic/intern/atomic_ops_unix.h b/intern/atomic/intern/atomic_ops_unix.h
index 2fcfe34d03c..8c703fc4a8d 100644
--- a/intern/atomic/intern/atomic_ops_unix.h
+++ b/intern/atomic/intern/atomic_ops_unix.h
@@ -99,6 +99,22 @@ ATOMIC_INLINE void atomic_spin_unlock(volatile AtomicSpinLock *lock)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Common part of x64 implementation
+ * \{ */
+
+/* TODO(sergey): On x64 platform both read and write of a variable aligned to its type size is
+ * atomic, so in theory it is possible to avoid memory barrier and gain performance. The downside
+ * of that would be that it will impose requirement to value which is being operated on. */
+#define __atomic_impl_load_generic(v) (__sync_synchronize(), *(v))
+#define __atomic_impl_store_generic(p, v) \
+ do { \
+ *(p) = (v); \
+ __sync_synchronize(); \
+ } while (0)
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Common part of locking fallback implementation
* \{ */
@@ -158,6 +174,23 @@ static _ATOMIC_MAYBE_UNUSED AtomicSpinLock _atomic_global_lock = {0};
return original_value; \
}
+#define ATOMIC_LOCKING_LOAD_DEFINE(_type) \
+ ATOMIC_INLINE _type##_t atomic_load_##_type(const _type##_t *v) \
+ { \
+ atomic_spin_lock(&_atomic_global_lock); \
+ const _type##_t value = *v; \
+ atomic_spin_unlock(&_atomic_global_lock); \
+ return value; \
+ }
+
+#define ATOMIC_LOCKING_STORE_DEFINE(_type) \
+ ATOMIC_INLINE void atomic_store_##_type(_type##_t *p, const _type##_t v) \
+ { \
+ atomic_spin_lock(&_atomic_global_lock); \
+ *p = v; \
+ atomic_spin_unlock(&_atomic_global_lock); \
+ }
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -192,6 +225,16 @@ ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _ne
return __sync_val_compare_and_swap(v, old, _new);
}
+ATOMIC_INLINE uint64_t atomic_load_uint64(const uint64_t *v)
+{
+ return __atomic_load_n(v, __ATOMIC_SEQ_CST);
+}
+
+ATOMIC_INLINE void atomic_store_uint64(uint64_t *p, uint64_t v)
+{
+ __atomic_store(p, &v, __ATOMIC_SEQ_CST);
+}
+
/* Signed */
ATOMIC_INLINE int64_t atomic_add_and_fetch_int64(int64_t *p, int64_t x)
{
@@ -218,6 +261,16 @@ ATOMIC_INLINE int64_t atomic_cas_int64(int64_t *v, int64_t old, int64_t _new)
return __sync_val_compare_and_swap(v, old, _new);
}
+ATOMIC_INLINE int64_t atomic_load_int64(const int64_t *v)
+{
+ return __atomic_load_n(v, __ATOMIC_SEQ_CST);
+}
+
+ATOMIC_INLINE void atomic_store_int64(int64_t *p, int64_t v)
+{
+ __atomic_store(p, &v, __ATOMIC_SEQ_CST);
+}
+
#elif !defined(ATOMIC_FORCE_USE_FALLBACK) && (defined(__amd64__) || defined(__x86_64__))
/* Unsigned */
ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x)
@@ -256,6 +309,16 @@ ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _ne
return ret;
}
+ATOMIC_INLINE uint64_t atomic_load_uint64(const uint64_t *v)
+{
+ return __atomic_impl_load_generic(v);
+}
+
+ATOMIC_INLINE void atomic_store_uint64(uint64_t *p, uint64_t v)
+{
+ __atomic_impl_store_generic(p, v);
+}
+
/* Signed */
ATOMIC_INLINE int64_t atomic_fetch_and_add_int64(int64_t *p, int64_t x)
{
@@ -292,6 +355,17 @@ ATOMIC_INLINE int64_t atomic_cas_int64(int64_t *v, int64_t old, int64_t _new)
asm volatile("lock; cmpxchgq %2,%1" : "=a"(ret), "+m"(*v) : "r"(_new), "0"(old) : "memory");
return ret;
}
+
+ATOMIC_INLINE int64_t atomic_load_int64(const int64_t *v)
+{
+ return __atomic_impl_load_generic(v);
+}
+
+ATOMIC_INLINE void atomic_store_int64(int64_t *p, int64_t v)
+{
+ __atomic_impl_store_generic(p, v);
+}
+
#else
/* Unsigned */
@@ -304,6 +378,9 @@ ATOMIC_LOCKING_FETCH_AND_SUB_DEFINE(uint64)
ATOMIC_LOCKING_CAS_DEFINE(uint64)
+ATOMIC_LOCKING_LOAD_DEFINE(uint64)
+ATOMIC_LOCKING_STORE_DEFINE(uint64)
+
/* Signed */
ATOMIC_LOCKING_ADD_AND_FETCH_DEFINE(int64)
ATOMIC_LOCKING_SUB_AND_FETCH_DEFINE(int64)
@@ -313,6 +390,9 @@ ATOMIC_LOCKING_FETCH_AND_SUB_DEFINE(int64)
ATOMIC_LOCKING_CAS_DEFINE(int64)
+ATOMIC_LOCKING_LOAD_DEFINE(int64)
+ATOMIC_LOCKING_STORE_DEFINE(int64)
+
#endif
/** \} */
@@ -339,6 +419,16 @@ ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _ne
return __sync_val_compare_and_swap(v, old, _new);
}
+ATOMIC_INLINE uint32_t atomic_load_uint32(const uint32_t *v)
+{
+ return __atomic_load_n(v, __ATOMIC_SEQ_CST);
+}
+
+ATOMIC_INLINE void atomic_store_uint32(uint32_t *p, uint32_t v)
+{
+ __atomic_store(p, &v, __ATOMIC_SEQ_CST);
+}
+
/* Signed */
ATOMIC_INLINE int32_t atomic_add_and_fetch_int32(int32_t *p, int32_t x)
{
@@ -355,6 +445,16 @@ ATOMIC_INLINE int32_t atomic_cas_int32(int32_t *v, int32_t old, int32_t _new)
return __sync_val_compare_and_swap(v, old, _new);
}
+ATOMIC_INLINE int32_t atomic_load_int32(const int32_t *v)
+{
+ return __atomic_load_n(v, __ATOMIC_SEQ_CST);
+}
+
+ATOMIC_INLINE void atomic_store_int32(int32_t *p, int32_t v)
+{
+ __atomic_store(p, &v, __ATOMIC_SEQ_CST);
+}
+
#elif !defined(ATOMIC_FORCE_USE_FALLBACK) && \
(defined(__i386__) || defined(__amd64__) || defined(__x86_64__))
/* Unsigned */
@@ -385,6 +485,16 @@ ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _ne
return ret;
}
+ATOMIC_INLINE uint32_t atomic_load_uint32(const uint32_t *v)
+{
+ return __atomic_load_n(v, __ATOMIC_SEQ_CST);
+}
+
+ATOMIC_INLINE void atomic_store_uint32(uint32_t *p, uint32_t v)
+{
+ __atomic_store(p, &v, __ATOMIC_SEQ_CST);
+}
+
/* Signed */
ATOMIC_INLINE int32_t atomic_add_and_fetch_int32(int32_t *p, int32_t x)
{
@@ -413,6 +523,16 @@ ATOMIC_INLINE int32_t atomic_cas_int32(int32_t *v, int32_t old, int32_t _new)
return ret;
}
+ATOMIC_INLINE int32_t atomic_load_int32(const int32_t *v)
+{
+ return __atomic_load_n(v, __ATOMIC_SEQ_CST);
+}
+
+ATOMIC_INLINE void atomic_store_int32(int32_t *p, int32_t v)
+{
+ __atomic_store(p, &v, __ATOMIC_SEQ_CST);
+}
+
#else
/* Unsigned */
@@ -422,6 +542,9 @@ ATOMIC_LOCKING_SUB_AND_FETCH_DEFINE(uint32)
ATOMIC_LOCKING_CAS_DEFINE(uint32)
+ATOMIC_LOCKING_LOAD_DEFINE(uint32)
+ATOMIC_LOCKING_STORE_DEFINE(uint32)
+
/* Signed */
ATOMIC_LOCKING_ADD_AND_FETCH_DEFINE(int32)
@@ -429,6 +552,9 @@ ATOMIC_LOCKING_SUB_AND_FETCH_DEFINE(int32)
ATOMIC_LOCKING_CAS_DEFINE(int32)
+ATOMIC_LOCKING_LOAD_DEFINE(int32)
+ATOMIC_LOCKING_STORE_DEFINE(int32)
+
#endif
#if !defined(ATOMIC_FORCE_USE_FALLBACK) && \
@@ -548,6 +674,9 @@ ATOMIC_LOCKING_FETCH_AND_OR_DEFINE(int8)
/** \} */
+#undef __atomic_impl_load_generic
+#undef __atomic_impl_store_generic
+
#undef ATOMIC_LOCKING_OP_AND_FETCH_DEFINE
#undef ATOMIC_LOCKING_FETCH_AND_OP_DEFINE
#undef ATOMIC_LOCKING_ADD_AND_FETCH_DEFINE
@@ -557,5 +686,7 @@ ATOMIC_LOCKING_FETCH_AND_OR_DEFINE(int8)
#undef ATOMIC_LOCKING_FETCH_AND_OR_DEFINE
#undef ATOMIC_LOCKING_FETCH_AND_AND_DEFINE
#undef ATOMIC_LOCKING_CAS_DEFINE
+#undef ATOMIC_LOCKING_LOAD_DEFINE
+#undef ATOMIC_LOCKING_STORE_DEFINE
#endif /* __ATOMIC_OPS_UNIX_H__ */
diff --git a/intern/atomic/tests/atomic_test.cc b/intern/atomic/tests/atomic_test.cc
index d79374416ec..37a66cf0e9c 100644
--- a/intern/atomic/tests/atomic_test.cc
+++ b/intern/atomic/tests/atomic_test.cc
@@ -143,6 +143,40 @@ TEST(atomic, atomic_cas_uint64)
}
}
+TEST(atomic, atomic_load_uint64)
+{
+ /* Make sure alias is implemented. */
+ {
+ uint64_t value = 2;
+ EXPECT_EQ(atomic_load_uint64(&value), 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const uint64_t uint64_t_max = std::numeric_limits<uint64_t>::max();
+ uint64_t value = uint64_t_max;
+ EXPECT_EQ(atomic_load_uint64(&value), uint64_t_max);
+ }
+}
+
+TEST(atomic, atomic_store_uint64)
+{
+ /* Make sure alias is implemented. */
+ {
+ uint64_t value = 0;
+ atomic_store_uint64(&value, 2);
+ EXPECT_EQ(value, 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const uint64_t uint64_t_max = std::numeric_limits<uint64_t>::max();
+ uint64_t value = 0;
+ atomic_store_uint64(&value, uint64_t_max);
+ EXPECT_EQ(value, uint64_t_max);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -277,6 +311,40 @@ TEST(atomic, atomic_cas_int64)
}
}
+TEST(atomic, atomic_load_int64)
+{
+ /* Make sure alias is implemented. */
+ {
+ int64_t value = 2;
+ EXPECT_EQ(atomic_load_int64(&value), 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const int64_t int64_t_max = std::numeric_limits<int64_t>::max();
+ int64_t value = int64_t_max;
+ EXPECT_EQ(atomic_load_int64(&value), int64_t_max);
+ }
+}
+
+TEST(atomic, atomic_store_int64)
+{
+ /* Make sure alias is implemented. */
+ {
+ int64_t value = 0;
+ atomic_store_int64(&value, 2);
+ EXPECT_EQ(value, 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const int64_t int64_t_max = std::numeric_limits<int64_t>::max();
+ int64_t value = 0;
+ atomic_store_int64(&value, int64_t_max);
+ EXPECT_EQ(value, int64_t_max);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -358,6 +426,40 @@ TEST(atomic, atomic_cas_uint32)
}
}
+TEST(atomic, atomic_load_uint32)
+{
+ /* Make sure alias is implemented. */
+ {
+ uint32_t value = 2;
+ EXPECT_EQ(atomic_load_uint32(&value), 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const uint32_t uint32_t_max = std::numeric_limits<uint32_t>::max();
+ uint32_t value = uint32_t_max;
+ EXPECT_EQ(atomic_load_uint32(&value), uint32_t_max);
+ }
+}
+
+TEST(atomic, atomic_store_uint32)
+{
+ /* Make sure alias is implemented. */
+ {
+ uint32_t value = 0;
+ atomic_store_uint32(&value, 2);
+ EXPECT_EQ(value, 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const uint32_t uint32_t_max = std::numeric_limits<uint32_t>::max();
+ uint32_t value = 0;
+ atomic_store_uint32(&value, uint32_t_max);
+ EXPECT_EQ(value, uint32_t_max);
+ }
+}
+
TEST(atomic, atomic_fetch_and_add_uint32)
{
{
@@ -505,6 +607,40 @@ TEST(atomic, atomic_cas_int32)
}
}
+TEST(atomic, atomic_load_int32)
+{
+ /* Make sure alias is implemented. */
+ {
+ int32_t value = 2;
+ EXPECT_EQ(atomic_load_int32(&value), 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const int32_t int32_t_max = std::numeric_limits<int32_t>::max();
+ int32_t value = int32_t_max;
+ EXPECT_EQ(atomic_load_int32(&value), int32_t_max);
+ }
+}
+
+TEST(atomic, atomic_store_int32)
+{
+ /* Make sure alias is implemented. */
+ {
+ int32_t value = 0;
+ atomic_store_int32(&value, 2);
+ EXPECT_EQ(value, 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const int32_t int32_t_max = std::numeric_limits<int32_t>::max();
+ int32_t value = 0;
+ atomic_store_int32(&value, int32_t_max);
+ EXPECT_EQ(value, int32_t_max);
+ }
+}
+
TEST(atomic, atomic_fetch_and_add_int32)
{
{
@@ -761,6 +897,40 @@ TEST(atomic, atomic_cas_z)
}
}
+TEST(atomic, atomic_load_z)
+{
+ /* Make sure alias is implemented. */
+ {
+ size_t value = 2;
+ EXPECT_EQ(atomic_load_z(&value), 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const size_t size_t_max = std::numeric_limits<size_t>::max();
+ size_t value = size_t_max;
+ EXPECT_EQ(atomic_load_z(&value), size_t_max);
+ }
+}
+
+TEST(atomic, atomic_store_z)
+{
+ /* Make sure alias is implemented. */
+ {
+ size_t value = 0;
+ atomic_store_z(&value, 2);
+ EXPECT_EQ(value, 2);
+ }
+
+ /* Make sure alias is using proper bitness. */
+ {
+ const size_t size_t_max = std::numeric_limits<size_t>::max();
+ size_t value = 0;
+ atomic_store_z(&value, size_t_max);
+ EXPECT_EQ(value, size_t_max);
+ }
+}
+
TEST(atomic, atomic_fetch_and_update_max_z)
{
const size_t size_t_max = std::numeric_limits<size_t>::max();
@@ -890,6 +1060,25 @@ TEST(atomic, atomic_cas_ptr)
}
}
+TEST(atomic, atomic_load_ptr)
+{
+ {
+ void *value = INT_AS_PTR(0x7f);
+ void *dest = atomic_load_ptr(&value);
+ EXPECT_EQ(dest, INT_AS_PTR(0x7f));
+ }
+}
+
+TEST(atomic, atomic_store_ptr)
+{
+ {
+ void *value = INT_AS_PTR(0x7f);
+ void *dest = nullptr;
+ atomic_store_ptr(&dest, value);
+ EXPECT_EQ(dest, INT_AS_PTR(0x7f));
+ }
+}
+
#undef INT_AS_PTR
/** \} */
diff --git a/intern/audaspace/CMakeLists.txt b/intern/audaspace/CMakeLists.txt
index 67b45be8158..0e2b27c0760 100644
--- a/intern/audaspace/CMakeLists.txt
+++ b/intern/audaspace/CMakeLists.txt
@@ -35,11 +35,15 @@ if(NOT WITH_SYSTEM_AUDASPACE)
else()
list(APPEND LIB
${AUDASPACE_C_LIBRARIES}
- ${AUDASPACE_PY_LIBRARIES}
)
+ if(WITH_PYTHON AND WITH_PYTHON_NUMPY)
+ list(APPEND LIB
+ ${AUDASPACE_PY_LIBRARIES}
+ )
+ endif()
endif()
-if(WITH_PYTHON)
+if(WITH_PYTHON AND WITH_PYTHON_NUMPY)
list(APPEND INC_SYS
${PYTHON_INCLUDE_DIRS}
)
diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py
index 74b28b8ea21..05f27bdbd4d 100644
--- a/intern/cycles/blender/addon/__init__.py
+++ b/intern/cycles/blender/addon/__init__.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
bl_info = {
diff --git a/intern/cycles/blender/addon/camera.py b/intern/cycles/blender/addon/camera.py
index 0e78112699e..3c821c98128 100644
--- a/intern/cycles/blender/addon/camera.py
+++ b/intern/cycles/blender/addon/camera.py
@@ -1,8 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-# <pep8 compliant>
-
# Fit to match default projective camera with focal_length 50 and sensor_width 36.
default_fisheye_polynomial = [
-1.1735143712967577e-05,
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py
index 724e1b8f727..e211f53cf31 100644
--- a/intern/cycles/blender/addon/engine.py
+++ b/intern/cycles/blender/addon/engine.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
diff --git a/intern/cycles/blender/addon/operators.py b/intern/cycles/blender/addon/operators.py
index e5d7f00a381..ab474cda0ab 100644
--- a/intern/cycles/blender/addon/operators.py
+++ b/intern/cycles/blender/addon/operators.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
import bpy
diff --git a/intern/cycles/blender/addon/osl.py b/intern/cycles/blender/addon/osl.py
index 9430dc5d115..1ee7ae421e3 100644
--- a/intern/cycles/blender/addon/osl.py
+++ b/intern/cycles/blender/addon/osl.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
import bpy
diff --git a/intern/cycles/blender/addon/presets.py b/intern/cycles/blender/addon/presets.py
index 5eaa592a9de..cc6d574da99 100644
--- a/intern/cycles/blender/addon/presets.py
+++ b/intern/cycles/blender/addon/presets.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
from bl_operators.presets import AddPresetBase
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 9b4799d252f..b444a806f8d 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
import bpy
@@ -24,12 +22,19 @@ from . import camera
enum_devices = (
('CPU', "CPU", "Use CPU for rendering"),
- ('GPU', "GPU Compute", "Use GPU compute device for rendering, configured in the system tab in the user preferences"),
+ ('GPU', "GPU Compute",
+ "Use GPU compute device for rendering, configured in the system tab in the user preferences"),
)
enum_feature_set = (
- ('SUPPORTED', "Supported", "Only use finished and supported features"),
- ('EXPERIMENTAL', "Experimental", "Use experimental and incomplete features that might be broken or change in the future", 'ERROR', 1),
+ ('SUPPORTED',
+ "Supported",
+ "Only use finished and supported features"),
+ ('EXPERIMENTAL',
+ "Experimental",
+ "Use experimental and incomplete features that might be broken or change in the future",
+ 'ERROR',
+ 1),
)
enum_displacement_methods = (
@@ -81,9 +86,14 @@ enum_sampling_pattern = (
)
enum_volume_sampling = (
- ('DISTANCE', "Distance", "Use distance sampling, best for dense volumes with lights far away"),
- ('EQUIANGULAR', "Equiangular", "Use equiangular sampling, best for volumes with low density with light inside or near the volume"),
- ('MULTIPLE_IMPORTANCE', "Multiple Importance",
+ ('DISTANCE',
+ "Distance",
+ "Use distance sampling, best for dense volumes with lights far away"),
+ ('EQUIANGULAR',
+ "Equiangular",
+ "Use equiangular sampling, best for volumes with low density with light inside or near the volume"),
+ ('MULTIPLE_IMPORTANCE',
+ "Multiple Importance",
"Combine distance and equi-angular sampling for volumes where neither method is ideal"),
)
@@ -93,10 +103,15 @@ enum_volume_interpolation = (
)
enum_world_mis = (
- ('NONE', "None", "Don't sample the background, faster but might cause noise for non-solid backgrounds"),
- ('AUTOMATIC', "Auto", "Automatically try to determine the best setting"),
- ('MANUAL', "Manual", "Manually set the resolution of the sampling map, higher values are slower and require more memory but reduce noise")
-)
+ ('NONE',
+ "None",
+ "Don't sample the background, faster but might cause noise for non-solid backgrounds"),
+ ('AUTOMATIC',
+ "Auto",
+ "Automatically try to determine the best setting"),
+ ('MANUAL',
+ "Manual",
+ "Manually set the resolution of the sampling map, higher values are slower and require more memory but reduce noise"))
enum_device_type = (
('CPU', "CPU", "CPU", 0),
@@ -210,17 +225,33 @@ enum_denoising_input_passes = (
)
enum_denoising_prefilter = (
- ('NONE', "None", "No prefiltering, use when guiding passes are noise-free", 1),
- ('FAST', "Fast", "Denoise color and guiding passes together. Improves quality when guiding passes are noisy using least amount of extra processing time", 2),
- ('ACCURATE', "Accurate", "Prefilter noisy guiding passes before denoising color. Improves quality when guiding passes are noisy using extra processing time", 3),
+ ('NONE',
+ "None",
+ "No prefiltering, use when guiding passes are noise-free",
+ 1),
+ ('FAST',
+ "Fast",
+ "Denoise color and guiding passes together. Improves quality when guiding passes are noisy using least amount of extra processing time",
+ 2),
+ ('ACCURATE',
+ "Accurate",
+ "Prefilter noisy guiding passes before denoising color. Improves quality when guiding passes are noisy using extra processing time",
+ 3),
)
enum_direct_light_sampling_type = (
- ('MULTIPLE_IMPORTANCE_SAMPLING', "Multiple Importance Sampling",
- "Multiple importance sampling is used to combine direct light contributions from next-event estimation and forward path tracing", 0),
- ('FORWARD_PATH_TRACING', "Forward Path Tracing", "Direct light contributions are only sampled using forward path tracing", 1),
- ('NEXT_EVENT_ESTIMATION', "Next-Event Estimation",
- "Direct light contributions are only sampled using next-event estimation", 2),
+ ('MULTIPLE_IMPORTANCE_SAMPLING',
+ "Multiple Importance Sampling",
+ "Multiple importance sampling is used to combine direct light contributions from next-event estimation and forward path tracing",
+ 0),
+ ('FORWARD_PATH_TRACING',
+ "Forward Path Tracing",
+ "Direct light contributions are only sampled using forward path tracing",
+ 1),
+ ('NEXT_EVENT_ESTIMATION',
+ "Next-Event Estimation",
+ "Direct light contributions are only sampled using next-event estimation",
+ 2),
)
@@ -357,7 +388,8 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
scrambling_distance: FloatProperty(
name="Scrambling Distance",
default=1.0,
- min=0.0, soft_max=1.0,
+ min=0.0,
+ soft_max=1.0,
description="Reduce randomization between pixels to improve GPU rendering performance, at the cost of possible rendering artifacts if set too low",
)
preview_scrambling_distance: BoolProperty(
@@ -383,7 +415,8 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
name="Light Sampling Threshold",
description="Probabilistically terminate light samples when the light contribution is below this threshold (more noise but faster rendering). "
"Zero disables the test and never ignores lights",
- min=0.0, max=1.0,
+ min=0.0,
+ max=1.0,
default=0.01,
)
@@ -395,7 +428,8 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
adaptive_threshold: FloatProperty(
name="Adaptive Sampling Threshold",
description="Noise level step to stop sampling at, lower values reduce noise at the cost of render time. Zero for automatic setting based on number of AA samples",
- min=0.0, max=1.0,
+ min=0.0,
+ max=1.0,
soft_min=0.001,
default=0.01,
precision=4,
@@ -403,7 +437,8 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
adaptive_min_samples: IntProperty(
name="Adaptive Min Samples",
description="Minimum AA samples for adaptive sampling, to discover noisy features before stopping sampling. Zero for automatic setting based on noise threshold",
- min=0, max=4096,
+ min=0,
+ max=4096,
default=0,
)
@@ -415,7 +450,8 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
preview_adaptive_threshold: FloatProperty(
name="Adaptive Sampling Threshold",
description="Noise level step to stop sampling at, lower values reduce noise at the cost of render time. Zero for automatic setting based on number of AA samples, for viewport renders",
- min=0.0, max=1.0,
+ min=0.0,
+ max=1.0,
soft_min=0.001,
default=0.1,
precision=4,
@@ -423,7 +459,8 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
preview_adaptive_min_samples: IntProperty(
name="Adaptive Min Samples",
description="Minimum AA samples for adaptive sampling, to discover noisy features before stopping sampling. Zero for automatic setting based on noise threshold, for viewport renders",
- min=0, max=4096,
+ min=0,
+ max=4096,
default=0,
)
@@ -550,7 +587,8 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
max_subdivisions: IntProperty(
name="Max Subdivisions",
description="Stop subdividing when this level is reached even if the dice rate would produce finer tessellation",
- min=0, max=16,
+ min=0,
+ max=16,
default=12,
)
@@ -817,8 +855,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
debug_use_optix_debug: BoolProperty(
name="OptiX Module Debug",
description="Load OptiX module in debug mode: lower logging verbosity level, enable validations, and lower optimization level",
- default=False
- )
+ default=False)
@classmethod
def register(cls):
@@ -1185,7 +1222,8 @@ class CyclesObjectSettings(bpy.types.PropertyGroup):
motion_steps: IntProperty(
name="Motion Steps",
description="Control accuracy of motion blur, more steps gives more memory usage (actual number of steps is 2^(steps - 1))",
- min=1, max=7,
+ min=1,
+ max=7,
default=1,
)
@@ -1224,7 +1262,8 @@ class CyclesObjectSettings(bpy.types.PropertyGroup):
shadow_terminator_geometry_offset: FloatProperty(
name="Shadow Terminator Geometry Offset",
description="Offset rays from the surface to reduce shadow terminator artifact on low poly geometry. Only affects triangles at grazing angles to light",
- min=0.0, max=1.0,
+ min=0.0,
+ max=1.0,
default=0.1,
)
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 886f5345020..5e918af322e 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
import bpy
@@ -1082,8 +1080,18 @@ class CYCLES_OBJECT_PT_motion_blur(CyclesButtonsPanel, Panel):
def has_geometry_visibility(ob):
- return ob and ((ob.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META', 'LIGHT', 'VOLUME', 'POINTCLOUD', 'CURVES'}) or
- (ob.instance_type == 'COLLECTION' and ob.instance_collection))
+ return ob and (
+ (ob.type in {
+ 'MESH',
+ 'CURVE',
+ 'SURFACE',
+ 'FONT',
+ 'META',
+ 'LIGHT',
+ 'VOLUME',
+ 'POINTCLOUD',
+ 'CURVES',
+ }) or (ob.instance_type == 'COLLECTION' and ob.instance_collection))
class CYCLES_OBJECT_PT_shading(CyclesButtonsPanel, Panel):
diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py
index 531ecc177da..12880496dfd 100644
--- a/intern/cycles/blender/addon/version_update.py
+++ b/intern/cycles/blender/addon/version_update.py
@@ -1,7 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2011-2022 Blender Foundation
-
-# <pep8 compliant>
from __future__ import annotations
import bpy
diff --git a/intern/cycles/blender/image.cpp b/intern/cycles/blender/image.cpp
index ca4c8f5904a..058fe3d46ac 100644
--- a/intern/cycles/blender/image.cpp
+++ b/intern/cycles/blender/image.cpp
@@ -7,27 +7,54 @@
#include "blender/session.h"
#include "blender/util.h"
+#include "util/half.h"
+
CCL_NAMESPACE_BEGIN
/* Packed Images */
BlenderImageLoader::BlenderImageLoader(BL::Image b_image,
const int frame,
+ const int tile_number,
const bool is_preview_render)
: b_image(b_image),
frame(frame),
+ tile_number(tile_number),
/* Don't free cache for preview render to avoid race condition from T93560, to be fixed
- properly later as we are close to release. */
+ * properly later as we are close to release. */
free_cache(!is_preview_render && !b_image.has_data())
{
}
bool BlenderImageLoader::load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata)
{
- metadata.width = b_image.size()[0];
- metadata.height = b_image.size()[1];
+ if (b_image.source() != BL::Image::source_TILED) {
+ /* Image sequence might have different dimensions, and hence needs to be handled in a special
+ * manner.
+ * NOTE: Currently the sequences are not handled by this image laoder. */
+ assert(b_image.source() != BL::Image::source_SEQUENCE);
+
+ metadata.width = b_image.size()[0];
+ metadata.height = b_image.size()[1];
+ metadata.channels = b_image.channels();
+ }
+ else {
+ /* Different UDIM tiles might have different resolutions, so get resolution from the actual
+ * tile. */
+ BL::UDIMTile b_udim_tile = b_image.tiles.get(tile_number);
+ if (b_udim_tile) {
+ metadata.width = b_udim_tile.size()[0];
+ metadata.height = b_udim_tile.size()[1];
+ metadata.channels = b_udim_tile.channels();
+ }
+ else {
+ metadata.width = 0;
+ metadata.height = 0;
+ metadata.channels = 0;
+ }
+ }
+
metadata.depth = 1;
- metadata.channels = b_image.channels();
if (b_image.is_float()) {
if (metadata.channels == 1) {
@@ -60,81 +87,134 @@ bool BlenderImageLoader::load_metadata(const ImageDeviceFeatures &, ImageMetaDat
}
bool BlenderImageLoader::load_pixels(const ImageMetaData &metadata,
- void *pixels,
- const size_t pixels_size,
+ void *out_pixels,
+ const size_t out_pixels_size,
const bool associate_alpha)
{
const size_t num_pixels = ((size_t)metadata.width) * metadata.height;
const int channels = metadata.channels;
- const int tile = 0; /* TODO(lukas): Support tiles here? */
- if (b_image.is_float()) {
- /* image data */
- float *image_pixels;
- image_pixels = image_get_float_pixels_for_frame(b_image, frame, tile);
+ if (metadata.type == IMAGE_DATA_TYPE_FLOAT || metadata.type == IMAGE_DATA_TYPE_FLOAT4) {
+ /* Float. */
+ float *in_pixels = image_get_float_pixels_for_frame(b_image, frame, tile_number);
- if (image_pixels && num_pixels * channels == pixels_size) {
- memcpy(pixels, image_pixels, pixels_size * sizeof(float));
+ if (in_pixels && num_pixels * channels == out_pixels_size) {
+ /* Straight copy pixel data. */
+ memcpy(out_pixels, in_pixels, out_pixels_size * sizeof(float));
}
else {
+ /* Missing or invalid pixel data. */
if (channels == 1) {
- memset(pixels, 0, num_pixels * sizeof(float));
+ memset(out_pixels, 0, num_pixels * sizeof(float));
}
else {
- const size_t num_pixels_safe = pixels_size / channels;
- float *fp = (float *)pixels;
- for (int i = 0; i < num_pixels_safe; i++, fp += channels) {
- fp[0] = 1.0f;
- fp[1] = 0.0f;
- fp[2] = 1.0f;
+ const size_t num_pixels_safe = out_pixels_size / channels;
+ float *out_pixel = (float *)out_pixels;
+ for (int i = 0; i < num_pixels_safe; i++, out_pixel += channels) {
+ out_pixel[0] = 1.0f;
+ out_pixel[1] = 0.0f;
+ out_pixel[2] = 1.0f;
if (channels == 4) {
- fp[3] = 1.0f;
+ out_pixel[3] = 1.0f;
}
}
}
}
- if (image_pixels) {
- MEM_freeN(image_pixels);
+ if (in_pixels) {
+ MEM_freeN(in_pixels);
}
}
- else {
- unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame, tile);
+ else if (metadata.type == IMAGE_DATA_TYPE_HALF || metadata.type == IMAGE_DATA_TYPE_HALF4) {
+ /* Half float. Blender does not have a half type, but in some cases
+ * we up-sample byte to half to avoid precision loss for colorspace
+ * conversion. */
+ unsigned char *in_pixels = image_get_pixels_for_frame(b_image, frame, tile_number);
- if (image_pixels && num_pixels * channels == pixels_size) {
- memcpy(pixels, image_pixels, pixels_size * sizeof(unsigned char));
+ if (in_pixels && num_pixels * channels == out_pixels_size) {
+ /* Convert uchar to half. */
+ const uchar *in_pixel = in_pixels;
+ half *out_pixel = (half *)out_pixels;
+ if (associate_alpha && channels == 4) {
+ for (size_t i = 0; i < num_pixels; i++, in_pixel += 4, out_pixel += 4) {
+ const float alpha = util_image_cast_to_float(in_pixel[3]);
+ out_pixel[0] = float_to_half_image(util_image_cast_to_float(in_pixel[0]) * alpha);
+ out_pixel[1] = float_to_half_image(util_image_cast_to_float(in_pixel[1]) * alpha);
+ out_pixel[2] = float_to_half_image(util_image_cast_to_float(in_pixel[2]) * alpha);
+ out_pixel[3] = float_to_half_image(alpha);
+ }
+ }
+ else {
+ for (size_t i = 0; i < num_pixels; i++) {
+ for (int c = 0; c < channels; c++, in_pixel++, out_pixel++) {
+ *out_pixel = float_to_half_image(util_image_cast_to_float(*in_pixel));
+ }
+ }
+ }
}
else {
+ /* Missing or invalid pixel data. */
if (channels == 1) {
- memset(pixels, 0, pixels_size * sizeof(unsigned char));
+ memset(out_pixels, 0, num_pixels * sizeof(half));
}
else {
- const size_t num_pixels_safe = pixels_size / channels;
- unsigned char *cp = (unsigned char *)pixels;
- for (size_t i = 0; i < num_pixels_safe; i++, cp += channels) {
- cp[0] = 255;
- cp[1] = 0;
- cp[2] = 255;
+ const size_t num_pixels_safe = out_pixels_size / channels;
+ half *out_pixel = (half *)out_pixels;
+ for (int i = 0; i < num_pixels_safe; i++, out_pixel += channels) {
+ out_pixel[0] = float_to_half_image(1.0f);
+ out_pixel[1] = float_to_half_image(0.0f);
+ out_pixel[2] = float_to_half_image(1.0f);
if (channels == 4) {
- cp[3] = 255;
+ out_pixel[3] = float_to_half_image(1.0f);
}
}
}
}
- if (image_pixels) {
- MEM_freeN(image_pixels);
+ if (in_pixels) {
+ MEM_freeN(in_pixels);
}
+ }
+ else {
+ /* Byte. */
+ unsigned char *in_pixels = image_get_pixels_for_frame(b_image, frame, tile_number);
+
+ if (in_pixels && num_pixels * channels == out_pixels_size) {
+ /* Straight copy pixel data. */
+ memcpy(out_pixels, in_pixels, out_pixels_size * sizeof(unsigned char));
- if (associate_alpha) {
- /* Premultiply, byte images are always straight for Blender. */
- unsigned char *cp = (unsigned char *)pixels;
- for (size_t i = 0; i < num_pixels; i++, cp += channels) {
- cp[0] = (cp[0] * cp[3]) / 255;
- cp[1] = (cp[1] * cp[3]) / 255;
- cp[2] = (cp[2] * cp[3]) / 255;
+ if (associate_alpha && channels == 4) {
+ /* Premultiply, byte images are always straight for Blender. */
+ unsigned char *out_pixel = (unsigned char *)out_pixels;
+ for (size_t i = 0; i < num_pixels; i++, out_pixel += 4) {
+ out_pixel[0] = (out_pixel[0] * out_pixel[3]) / 255;
+ out_pixel[1] = (out_pixel[1] * out_pixel[3]) / 255;
+ out_pixel[2] = (out_pixel[2] * out_pixel[3]) / 255;
+ }
}
}
+ else {
+ /* Missing or invalid pixel data. */
+ if (channels == 1) {
+ memset(out_pixels, 0, out_pixels_size * sizeof(unsigned char));
+ }
+ else {
+ const size_t num_pixels_safe = out_pixels_size / channels;
+ unsigned char *out_pixel = (unsigned char *)out_pixels;
+ for (size_t i = 0; i < num_pixels_safe; i++, out_pixel += channels) {
+ out_pixel[0] = 255;
+ out_pixel[1] = 0;
+ out_pixel[2] = 255;
+ if (channels == 4) {
+ out_pixel[3] = 255;
+ }
+ }
+ }
+ }
+
+ if (in_pixels) {
+ MEM_freeN(in_pixels);
+ }
}
/* Free image buffers to save memory during render. */
@@ -153,7 +233,13 @@ string BlenderImageLoader::name() const
bool BlenderImageLoader::equals(const ImageLoader &other) const
{
const BlenderImageLoader &other_loader = (const BlenderImageLoader &)other;
- return b_image == other_loader.b_image && frame == other_loader.frame;
+ return b_image == other_loader.b_image && frame == other_loader.frame &&
+ tile_number == other_loader.tile_number;
+}
+
+int BlenderImageLoader::get_tile_number() const
+{
+ return tile_number;
}
/* Point Density */
diff --git a/intern/cycles/blender/image.h b/intern/cycles/blender/image.h
index ee576b31f7e..c2cc0f51b9b 100644
--- a/intern/cycles/blender/image.h
+++ b/intern/cycles/blender/image.h
@@ -12,7 +12,10 @@ CCL_NAMESPACE_BEGIN
class BlenderImageLoader : public ImageLoader {
public:
- BlenderImageLoader(BL::Image b_image, const int frame, const bool is_preview_render);
+ BlenderImageLoader(BL::Image b_image,
+ const int frame,
+ const int tile_number,
+ const bool is_preview_render);
bool load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) override;
bool load_pixels(const ImageMetaData &metadata,
@@ -22,8 +25,11 @@ class BlenderImageLoader : public ImageLoader {
string name() const override;
bool equals(const ImageLoader &other) const override;
+ int get_tile_number() const override;
+
BL::Image b_image;
int frame;
+ int tile_number;
bool free_cache;
};
diff --git a/intern/cycles/blender/mesh.cpp b/intern/cycles/blender/mesh.cpp
index 635421d3d61..e2db52cc5c1 100644
--- a/intern/cycles/blender/mesh.cpp
+++ b/intern/cycles/blender/mesh.cpp
@@ -303,7 +303,7 @@ static void fill_generic_attribute(BL::Mesh &b_mesh,
assert(0);
}
else {
- /* Averge edge attributes at vertices. */
+ /* Average edge attributes at vertices. */
const size_t num_verts = b_mesh.vertices.length();
vector<int> count(num_verts, 0);
diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp
index d3527567b96..81a64457c88 100644
--- a/intern/cycles/blender/shader.cpp
+++ b/intern/cycles/blender/shader.cpp
@@ -355,6 +355,18 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeCombineHSV)) {
node = graph->create_node<CombineHSVNode>();
}
+ else if (b_node.is_a(&RNA_ShaderNodeSeparateColor)) {
+ BL::ShaderNodeSeparateColor b_separate_node(b_node);
+ SeparateColorNode *separate_node = graph->create_node<SeparateColorNode>();
+ separate_node->set_color_type((NodeCombSepColorType)b_separate_node.mode());
+ node = separate_node;
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeCombineColor)) {
+ BL::ShaderNodeCombineColor b_combine_node(b_node);
+ CombineColorNode *combine_node = graph->create_node<CombineColorNode>();
+ combine_node->set_color_type((NodeCombSepColorType)b_combine_node.mode());
+ node = combine_node;
+ }
else if (b_node.is_a(&RNA_ShaderNodeSeparateXYZ)) {
node = graph->create_node<SeparateXYZNode>();
}
@@ -764,9 +776,21 @@ static ShaderNode *add_node(Scene *scene,
*/
int scene_frame = b_scene.frame_current();
int image_frame = image_user_frame_number(b_image_user, b_image, scene_frame);
- image->handle = scene->image_manager->add_image(
- new BlenderImageLoader(b_image, image_frame, b_engine.is_preview()),
- image->image_params());
+ if (b_image.source() != BL::Image::source_TILED) {
+ image->handle = scene->image_manager->add_image(
+ new BlenderImageLoader(b_image, image_frame, 0, b_engine.is_preview()),
+ image->image_params());
+ }
+ else {
+ vector<ImageLoader *> loaders;
+ loaders.reserve(image->get_tiles().size());
+ for (int tile_number : image->get_tiles()) {
+ loaders.push_back(
+ new BlenderImageLoader(b_image, image_frame, tile_number, b_engine.is_preview()));
+ }
+
+ image->handle = scene->image_manager->add_image(loaders, image->image_params());
+ }
}
else {
ustring filename = ustring(
@@ -802,7 +826,7 @@ static ShaderNode *add_node(Scene *scene,
int scene_frame = b_scene.frame_current();
int image_frame = image_user_frame_number(b_image_user, b_image, scene_frame);
env->handle = scene->image_manager->add_image(
- new BlenderImageLoader(b_image, image_frame, b_engine.is_preview()),
+ new BlenderImageLoader(b_image, image_frame, 0, b_engine.is_preview()),
env->image_params());
}
else {
diff --git a/intern/cycles/blender/volume.cpp b/intern/cycles/blender/volume.cpp
index 8dd2d45c0b6..61b2f9ee276 100644
--- a/intern/cycles/blender/volume.cpp
+++ b/intern/cycles/blender/volume.cpp
@@ -219,7 +219,10 @@ static void sync_smoke_volume(
class BlenderVolumeLoader : public VDBImageLoader {
public:
- BlenderVolumeLoader(BL::BlendData &b_data, BL::Volume &b_volume, const string &grid_name)
+ BlenderVolumeLoader(BL::BlendData &b_data,
+ BL::Volume &b_volume,
+ const string &grid_name,
+ BL::VolumeRender::precision_enum precision_)
: VDBImageLoader(grid_name), b_volume(b_volume)
{
b_volume.grids.load(b_data.ptr.data);
@@ -241,6 +244,22 @@ class BlenderVolumeLoader : public VDBImageLoader {
}
}
#endif
+#ifdef WITH_NANOVDB
+ switch (precision_) {
+ case BL::VolumeRender::precision_FULL:
+ precision = 32;
+ break;
+ case BL::VolumeRender::precision_HALF:
+ precision = 16;
+ break;
+ default:
+ case BL::VolumeRender::precision_VARIABLE:
+ precision = 0;
+ break;
+ }
+#else
+ (void)precision_;
+#endif
}
BL::Volume b_volume;
@@ -318,7 +337,8 @@ static void sync_volume_object(BL::BlendData &b_data,
volume->attributes.add(std) :
volume->attributes.add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VOXEL);
- ImageLoader *loader = new BlenderVolumeLoader(b_data, b_volume, name.string());
+ ImageLoader *loader = new BlenderVolumeLoader(
+ b_data, b_volume, name.string(), b_render.precision());
ImageParams params;
params.frame = b_volume.grids.frame();
diff --git a/intern/cycles/bvh/build.cpp b/intern/cycles/bvh/build.cpp
index 79e9b800690..1df3517673e 100644
--- a/intern/cycles/bvh/build.cpp
+++ b/intern/cycles/bvh/build.cpp
@@ -811,7 +811,7 @@ BVHNode *BVHBuild::build_node(const BVHRange &range,
/* unalignedLeafSAH = params.sah_primitive_cost * split.leafSAH; */
unalignedSplitSAH = params.sah_node_cost * unaligned_split.bounds.half_area() +
params.sah_primitive_cost * unaligned_split.nodeSAH;
- /* TOOD(sergey): Check we can create leaf already. */
+ /* TODO(sergey): Check we can create leaf already. */
/* Check whether unaligned split is better than the regular one. */
if (unalignedSplitSAH < splitSAH) {
do_unalinged_split = true;
diff --git a/intern/cycles/cmake/external_libs.cmake b/intern/cycles/cmake/external_libs.cmake
index f4186374d10..d2f30fe764b 100644
--- a/intern/cycles/cmake/external_libs.cmake
+++ b/intern/cycles/cmake/external_libs.cmake
@@ -145,8 +145,8 @@ if(CYCLES_STANDALONE_REPOSITORY)
-DOIIO_STATIC_DEFINE
)
- set(OPENIMAGEIO_INCLUDE_DIR ${OPENIMAGEIO_ROOT_DIR}/include)
- set(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO_INCLUDE_DIR} ${OPENIMAGEIO_INCLUDE_DIR}/OpenImageIO)
+ set(OPENIMAGEIO_INCLUDE_DIR ${OPENIMAGEIO_ROOT_DIR}/include)
+ set(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO_INCLUDE_DIR} ${OPENIMAGEIO_INCLUDE_DIR}/OpenImageIO)
# Special exceptions for libraries which needs explicit debug version
set(OPENIMAGEIO_LIBRARIES
optimized ${OPENIMAGEIO_ROOT_DIR}/lib/OpenImageIO.lib
diff --git a/intern/cycles/device/cuda/device_impl.cpp b/intern/cycles/device/cuda/device_impl.cpp
index c9326a62f48..cb7e909a2d5 100644
--- a/intern/cycles/device/cuda/device_impl.cpp
+++ b/intern/cycles/device/cuda/device_impl.cpp
@@ -1086,7 +1086,9 @@ void CUDADevice::tex_alloc(device_texture &mem)
need_texture_info = true;
if (mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FLOAT &&
- mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3) {
+ mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3 &&
+ mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FPN &&
+ mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FP16) {
CUDA_RESOURCE_DESC resDesc;
memset(&resDesc, 0, sizeof(resDesc));
diff --git a/intern/cycles/device/hip/device_impl.cpp b/intern/cycles/device/hip/device_impl.cpp
index d27e9ddbedf..ea68c821166 100644
--- a/intern/cycles/device/hip/device_impl.cpp
+++ b/intern/cycles/device/hip/device_impl.cpp
@@ -1044,7 +1044,9 @@ void HIPDevice::tex_alloc(device_texture &mem)
need_texture_info = true;
if (mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FLOAT &&
- mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3) {
+ mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3 &&
+ mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FPN &&
+ mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FP16) {
/* Bindless textures. */
hipResourceDesc resDesc;
memset(&resDesc, 0, sizeof(resDesc));
diff --git a/intern/cycles/device/memory.cpp b/intern/cycles/device/memory.cpp
index 4c068dbdd3e..40cf2573cfb 100644
--- a/intern/cycles/device/memory.cpp
+++ b/intern/cycles/device/memory.cpp
@@ -165,6 +165,8 @@ device_texture::device_texture(Device *device,
case IMAGE_DATA_TYPE_BYTE:
case IMAGE_DATA_TYPE_NANOVDB_FLOAT:
case IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
+ case IMAGE_DATA_TYPE_NANOVDB_FPN:
+ case IMAGE_DATA_TYPE_NANOVDB_FP16:
data_type = TYPE_UCHAR;
data_elements = 1;
break;
diff --git a/intern/cycles/device/metal/device_impl.h b/intern/cycles/device/metal/device_impl.h
index 27c58ce6d2f..7506b9b069f 100644
--- a/intern/cycles/device/metal/device_impl.h
+++ b/intern/cycles/device/metal/device_impl.h
@@ -28,7 +28,8 @@ class MetalDevice : public Device {
id<MTLCommandQueue> mtlGeneralCommandQueue = nil;
id<MTLArgumentEncoder> mtlAncillaryArgEncoder =
nil; /* encoder used for fetching device pointers from MTLBuffers */
- string source_used_for_compile[PSO_NUM];
+ string source[PSO_NUM];
+ string source_md5[PSO_NUM];
KernelParamsMetal launch_params = {0};
@@ -72,7 +73,6 @@ class MetalDevice : public Device {
id<MTLBuffer> texture_bindings_3d = nil;
std::vector<id<MTLTexture>> texture_slot_map;
- MetalDeviceKernels kernels;
bool use_metalrt = false;
bool use_function_specialisation = false;
@@ -110,6 +110,8 @@ class MetalDevice : public Device {
virtual void build_bvh(BVH *bvh, Progress &progress, bool refit) override;
+ id<MTLLibrary> compile(string const &source);
+
/* ------------------------------------------------------------------ */
/* low-level memory management */
diff --git a/intern/cycles/device/metal/device_impl.mm b/intern/cycles/device/metal/device_impl.mm
index c01f51fb506..16aabacb4cf 100644
--- a/intern/cycles/device/metal/device_impl.mm
+++ b/intern/cycles/device/metal/device_impl.mm
@@ -275,96 +275,44 @@ bool MetalDevice::load_kernels(const uint _kernel_features)
* active, but may still need to be rendered without motion blur if that isn't active as well. */
motion_blur = kernel_features & KERNEL_FEATURE_OBJECT_MOTION;
- NSError *error = NULL;
+ source[PSO_GENERIC] = get_source(kernel_features);
+ mtlLibrary[PSO_GENERIC] = compile(source[PSO_GENERIC]);
- for (int i = 0; i < PSO_NUM; i++) {
- if (mtlLibrary[i]) {
- [mtlLibrary[i] release];
- mtlLibrary[i] = nil;
- }
- }
+ MD5Hash md5;
+ md5.append(source[PSO_GENERIC]);
+ source_md5[PSO_GENERIC] = md5.get_hex();
+
+ metal_printf("Front-end compilation finished (generic)\n");
+
+ bool result = MetalDeviceKernels::load(this, false);
+
+ reserve_local_memory(kernel_features);
+
+ return result;
+}
+id<MTLLibrary> MetalDevice::compile(string const &source)
+{
MTLCompileOptions *options = [[MTLCompileOptions alloc] init];
options.fastMathEnabled = YES;
if (@available(macOS 12.0, *)) {
options.languageVersion = MTLLanguageVersion2_4;
}
- else {
- return false;
- }
- string metalsrc;
-
- /* local helper: dump source to disk and return filepath */
- auto dump_source = [&](int kernel_type) -> string {
- string &source = source_used_for_compile[kernel_type];
- string metalsrc = path_cache_get(path_join("kernels",
- string_printf("%s.%s.metal",
- kernel_type_as_string(kernel_type),
- util_md5_string(source).c_str())));
- path_write_text(metalsrc, source);
- return metalsrc;
- };
-
- /* local helper: fetch the kernel source code, adjust it for specific PSO_.. kernel_type flavor,
- * then compile it into a MTLLibrary */
- auto fetch_and_compile_source = [&](int kernel_type) {
- /* Record the source used to compile this library, for hash building later. */
- string &source = source_used_for_compile[kernel_type];
-
- switch (kernel_type) {
- case PSO_GENERIC: {
- source = get_source(kernel_features);
- break;
- }
- case PSO_SPECIALISED: {
- /* PSO_SPECIALISED derives from PSO_GENERIC */
- string &generic_source = source_used_for_compile[PSO_GENERIC];
- if (generic_source.empty()) {
- generic_source = get_source(kernel_features);
- }
- source = "#define __KERNEL_METAL_USE_FUNCTION_SPECIALISATION__\n" + generic_source;
- break;
- }
- default:
- assert(0);
- }
-
- /* create MTLLibrary (front-end compilation) */
- mtlLibrary[kernel_type] = [mtlDevice newLibraryWithSource:@(source.c_str())
+ NSError *error = NULL;
+ id<MTLLibrary> mtlLibrary = [mtlDevice newLibraryWithSource:@(source.c_str())
options:options
error:&error];
- bool do_source_dump = (getenv("CYCLES_METAL_DUMP_SOURCE") != nullptr);
-
- if (!mtlLibrary[kernel_type] || do_source_dump) {
- string metalsrc = dump_source(kernel_type);
-
- if (!mtlLibrary[kernel_type]) {
- NSString *err = [error localizedDescription];
- set_error(string_printf("Failed to compile library:\n%s", [err UTF8String]));
-
- return false;
- }
- }
- return true;
- };
-
- fetch_and_compile_source(PSO_GENERIC);
-
- if (use_function_specialisation) {
- fetch_and_compile_source(PSO_SPECIALISED);
+ if (!mtlLibrary) {
+ NSString *err = [error localizedDescription];
+ set_error(string_printf("Failed to compile library:\n%s", [err UTF8String]));
}
- metal_printf("Front-end compilation finished\n");
-
- bool result = kernels.load(this, PSO_GENERIC);
-
[options release];
- reserve_local_memory(kernel_features);
- return result;
+ return mtlLibrary;
}
void MetalDevice::reserve_local_memory(const uint kernel_features)
@@ -749,8 +697,7 @@ void MetalDevice::tex_alloc_as_buffer(device_texture &mem)
void MetalDevice::tex_alloc(device_texture &mem)
{
/* Check that dimensions fit within maximum allowable size.
- See https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
- */
+ * See: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf */
if (mem.data_width > 16384 || mem.data_height > 16384) {
set_error(string_printf(
"Texture exceeds maximum allowed size of 16384 x 16384 (requested: %zu x %zu)",
diff --git a/intern/cycles/device/metal/kernel.h b/intern/cycles/device/metal/kernel.h
index b12491d820d..69b2a686ecc 100644
--- a/intern/cycles/device/metal/kernel.h
+++ b/intern/cycles/device/metal/kernel.h
@@ -54,103 +54,41 @@ enum {
const char *kernel_type_as_string(int kernel_type);
struct MetalKernelPipeline {
- void release()
- {
- if (pipeline) {
- [pipeline release];
- pipeline = nil;
- if (@available(macOS 11.0, *)) {
- for (int i = 0; i < METALRT_TABLE_NUM; i++) {
- if (intersection_func_table[i]) {
- [intersection_func_table[i] release];
- intersection_func_table[i] = nil;
- }
- }
- }
- }
- if (function) {
- [function release];
- function = nil;
- }
- if (@available(macOS 11.0, *)) {
- for (int i = 0; i < METALRT_TABLE_NUM; i++) {
- if (intersection_func_table[i]) {
- [intersection_func_table[i] release];
- }
- }
- }
- }
- bool loaded = false;
- id<MTLFunction> function = nil;
- id<MTLComputePipelineState> pipeline = nil;
-
- API_AVAILABLE(macos(11.0))
- id<MTLIntersectionFunctionTable> intersection_func_table[METALRT_TABLE_NUM] = {nil};
-};
-
-struct MetalKernelLoadDesc {
- int pso_index = 0;
- const char *function_name = nullptr;
- int kernel_index = 0;
- int threads_per_threadgroup = 0;
- MTLFunctionConstantValues *constant_values = nullptr;
- NSArray *linked_functions = nullptr;
-
- struct IntersectorFunctions {
- NSArray *defaults;
- NSArray *shadow;
- NSArray *local;
- NSArray *operator[](int index) const
- {
- if (index == METALRT_TABLE_DEFAULT)
- return defaults;
- if (index == METALRT_TABLE_SHADOW)
- return shadow;
- return local;
- }
- } intersector_functions = {nullptr};
-};
-
-/* Metal kernel and associate occupancy information. */
-class MetalDeviceKernel {
- public:
- ~MetalDeviceKernel();
+ void compile();
- bool load(MetalDevice *device, MetalKernelLoadDesc const &desc, class MD5Hash const &md5);
+ id<MTLLibrary> mtlLibrary = nil;
+ bool scene_specialized;
+ string source_md5;
- void mark_loaded(int pso_index)
- {
- pso[pso_index].loaded = true;
- }
+ bool use_metalrt;
+ bool metalrt_hair;
+ bool metalrt_hair_thick;
+ bool metalrt_pointcloud;
- int get_num_threads_per_block() const
- {
- return num_threads_per_block;
- }
- const MetalKernelPipeline &get_pso() const;
+ int threads_per_threadgroup;
- double load_duration = 0.0;
+ DeviceKernel device_kernel;
+ bool loaded = false;
+ id<MTLDevice> mtlDevice = nil;
+ id<MTLFunction> function = nil;
+ id<MTLComputePipelineState> pipeline = nil;
+ int num_threads_per_block = 0;
- private:
- MetalKernelPipeline pso[PSO_NUM];
+ string error_str;
- int num_threads_per_block = 0;
+ API_AVAILABLE(macos(11.0))
+ id<MTLIntersectionFunctionTable> intersection_func_table[METALRT_TABLE_NUM] = {nil};
+ id<MTLFunction> rt_intersection_function[METALRT_FUNC_NUM] = {nil};
};
/* Cache of Metal kernels for each DeviceKernel. */
-class MetalDeviceKernels {
- public:
- bool load(MetalDevice *device, int kernel_type);
- bool available(DeviceKernel kernel) const;
- const MetalDeviceKernel &get(DeviceKernel kernel) const;
+namespace MetalDeviceKernels {
- MetalDeviceKernel kernels_[DEVICE_KERNEL_NUM];
+bool load(MetalDevice *device, bool scene_specialized);
+const MetalKernelPipeline *get_best_pipeline(const MetalDevice *device, DeviceKernel kernel);
- id<MTLFunction> rt_intersection_funcs[PSO_NUM][METALRT_FUNC_NUM] = {{nil}};
-
- string loaded_md5[PSO_NUM];
-};
+} /* namespace MetalDeviceKernels */
CCL_NAMESPACE_END
diff --git a/intern/cycles/device/metal/kernel.mm b/intern/cycles/device/metal/kernel.mm
index a3c4839c21f..fec4cd80466 100644
--- a/intern/cycles/device/metal/kernel.mm
+++ b/intern/cycles/device/metal/kernel.mm
@@ -9,6 +9,7 @@
# include "util/path.h"
# include "util/tbb.h"
# include "util/time.h"
+# include "util/unique_ptr.h"
CCL_NAMESPACE_BEGIN
@@ -28,82 +29,377 @@ const char *kernel_type_as_string(int kernel_type)
return "";
}
-MetalDeviceKernel::~MetalDeviceKernel()
+bool kernel_has_intersection(DeviceKernel device_kernel)
{
- for (int i = 0; i < PSO_NUM; i++) {
- pso[i].release();
+ return (device_kernel == DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST ||
+ device_kernel == DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW ||
+ device_kernel == DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE ||
+ device_kernel == DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK ||
+ device_kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE ||
+ device_kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE);
+}
+
+struct ShaderCache {
+ ShaderCache(id<MTLDevice> _mtlDevice) : mtlDevice(_mtlDevice)
+ {
+ }
+ ~ShaderCache();
+
+ /* Get the fastest available pipeline for the specified kernel. */
+ MetalKernelPipeline *get_best_pipeline(DeviceKernel kernel, const MetalDevice *device);
+
+ /* Non-blocking request for a kernel, optionally specialized to the scene being rendered by
+ * device. */
+ void load_kernel(DeviceKernel kernel, MetalDevice *device, bool scene_specialized);
+
+ void wait_for_all();
+
+ private:
+ friend ShaderCache *get_shader_cache(id<MTLDevice> mtlDevice);
+
+ void compile_thread_func(int thread_index);
+
+ using PipelineCollection = std::vector<unique_ptr<MetalKernelPipeline>>;
+
+ struct PipelineRequest {
+ MetalKernelPipeline *pipeline = nullptr;
+ std::function<void(MetalKernelPipeline *)> completionHandler;
+ };
+
+ std::mutex cache_mutex;
+
+ PipelineCollection pipelines[DEVICE_KERNEL_NUM];
+ id<MTLDevice> mtlDevice;
+
+ bool running = false;
+ std::condition_variable cond_var;
+ std::deque<PipelineRequest> request_queue;
+ std::vector<std::thread> compile_threads;
+ std::atomic_int incomplete_requests = 0;
+};
+
+std::mutex g_shaderCacheMutex;
+std::map<id<MTLDevice>, unique_ptr<ShaderCache>> g_shaderCache;
+
+ShaderCache *get_shader_cache(id<MTLDevice> mtlDevice)
+{
+ thread_scoped_lock lock(g_shaderCacheMutex);
+ auto it = g_shaderCache.find(mtlDevice);
+ if (it != g_shaderCache.end()) {
+ return it->second.get();
+ }
+
+ g_shaderCache[mtlDevice] = make_unique<ShaderCache>(mtlDevice);
+ return g_shaderCache[mtlDevice].get();
+}
+
+ShaderCache::~ShaderCache()
+{
+ metal_printf("ShaderCache shutting down with incomplete_requests = %d\n",
+ int(incomplete_requests));
+
+ running = false;
+ cond_var.notify_all();
+ for (auto &thread : compile_threads) {
+ thread.join();
+ }
+}
+
+void ShaderCache::wait_for_all()
+{
+ while (incomplete_requests > 0) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ }
+}
+
+void ShaderCache::compile_thread_func(int thread_index)
+{
+ while (1) {
+
+ /* wait for / acquire next request */
+ PipelineRequest request;
+ {
+ thread_scoped_lock lock(cache_mutex);
+ cond_var.wait(lock, [&] { return !running || !request_queue.empty(); });
+ if (!running) {
+ break;
+ }
+
+ if (!request_queue.empty()) {
+ request = request_queue.front();
+ request_queue.pop_front();
+ }
+ }
+
+ /* service request */
+ if (request.pipeline) {
+ request.pipeline->compile();
+ incomplete_requests--;
+ }
}
}
-bool MetalDeviceKernel::load(MetalDevice *device,
- MetalKernelLoadDesc const &desc_in,
- MD5Hash const &md5)
+void ShaderCache::load_kernel(DeviceKernel device_kernel,
+ MetalDevice *device,
+ bool scene_specialized)
{
- __block MetalKernelLoadDesc const desc(desc_in);
- if (desc.kernel_index == DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL) {
+ {
+ /* create compiler threads on first run */
+ thread_scoped_lock lock(cache_mutex);
+ if (compile_threads.empty()) {
+ running = true;
+ for (int i = 0; i < max_mtlcompiler_threads; i++) {
+ compile_threads.push_back(std::thread([&] { compile_thread_func(i); }));
+ }
+ }
+ }
+
+ if (device_kernel == DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL) {
/* skip megakernel */
- return true;
+ return;
}
- bool use_binary_archive = true;
- if (device->device_vendor == METAL_GPU_APPLE) {
- /* Workaround for T94142: Cycles Metal crash with simultaneous viewport and final render */
- use_binary_archive = false;
+ if (scene_specialized) {
+ /* Only specialize kernels where it can make an impact. */
+ if (device_kernel < DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST ||
+ device_kernel > DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL) {
+ return;
+ }
}
- if (auto str = getenv("CYCLES_METAL_DISABLE_BINARY_ARCHIVES")) {
- use_binary_archive = (atoi(str) == 0);
+ {
+ /* check whether the kernel has already been requested / cached */
+ thread_scoped_lock lock(cache_mutex);
+ for (auto &pipeline : pipelines[device_kernel]) {
+ if (scene_specialized) {
+ if (pipeline->source_md5 == device->source_md5[PSO_SPECIALISED]) {
+ /* we already requested a pipeline that is specialized for this kernel data */
+ metal_printf("Specialized kernel already requested (%s)\n",
+ device_kernel_as_string(device_kernel));
+ return;
+ }
+ }
+ else {
+ if (pipeline->source_md5 == device->source_md5[PSO_GENERIC]) {
+ /* we already requested a generic pipeline for this kernel */
+ metal_printf("Generic kernel already requested (%s)\n",
+ device_kernel_as_string(device_kernel));
+ return;
+ }
+ }
+ }
}
- id<MTLBinaryArchive> archive = nil;
- string metalbin_path;
- if (use_binary_archive) {
- NSProcessInfo *processInfo = [NSProcessInfo processInfo];
- string osVersion = [[processInfo operatingSystemVersionString] UTF8String];
- MD5Hash local_md5(md5);
- local_md5.append(osVersion);
- string metalbin_name = string(desc.function_name) + "." + local_md5.get_hex() +
- to_string(desc.pso_index) + ".bin";
- metalbin_path = path_cache_get(path_join("kernels", metalbin_name));
- path_create_directories(metalbin_path);
+ incomplete_requests++;
+
+ PipelineRequest request;
+ request.pipeline = new MetalKernelPipeline;
+ request.pipeline->scene_specialized = scene_specialized;
+ request.pipeline->mtlDevice = mtlDevice;
+ request.pipeline->source_md5 =
+ device->source_md5[scene_specialized ? PSO_SPECIALISED : PSO_GENERIC];
+ request.pipeline->mtlLibrary =
+ device->mtlLibrary[scene_specialized ? PSO_SPECIALISED : PSO_GENERIC];
+ request.pipeline->device_kernel = device_kernel;
+ request.pipeline->threads_per_threadgroup = device->max_threads_per_threadgroup;
+
+ /* metalrt options */
+ request.pipeline->use_metalrt = device->use_metalrt;
+ request.pipeline->metalrt_hair = device->use_metalrt &&
+ (device->kernel_features & KERNEL_FEATURE_HAIR);
+ request.pipeline->metalrt_hair_thick = device->use_metalrt &&
+ (device->kernel_features & KERNEL_FEATURE_HAIR_THICK);
+ request.pipeline->metalrt_pointcloud = device->use_metalrt &&
+ (device->kernel_features & KERNEL_FEATURE_POINTCLOUD);
+
+ {
+ thread_scoped_lock lock(cache_mutex);
+ pipelines[device_kernel].push_back(unique_ptr<MetalKernelPipeline>(request.pipeline));
+ request_queue.push_back(request);
+ }
+ cond_var.notify_one();
+}
- if (path_exists(metalbin_path) && use_binary_archive) {
- if (@available(macOS 11.0, *)) {
- MTLBinaryArchiveDescriptor *archiveDesc = [[MTLBinaryArchiveDescriptor alloc] init];
- archiveDesc.url = [NSURL fileURLWithPath:@(metalbin_path.c_str())];
- archive = [device->mtlDevice newBinaryArchiveWithDescriptor:archiveDesc error:nil];
- [archiveDesc release];
+MetalKernelPipeline *ShaderCache::get_best_pipeline(DeviceKernel kernel, const MetalDevice *device)
+{
+ thread_scoped_lock lock(cache_mutex);
+ auto &collection = pipelines[kernel];
+ if (collection.empty()) {
+ return nullptr;
+ }
+
+ /* metalrt options */
+ bool use_metalrt = device->use_metalrt;
+ bool metalrt_hair = use_metalrt && (device->kernel_features & KERNEL_FEATURE_HAIR);
+ bool metalrt_hair_thick = use_metalrt && (device->kernel_features & KERNEL_FEATURE_HAIR_THICK);
+ bool metalrt_pointcloud = use_metalrt && (device->kernel_features & KERNEL_FEATURE_POINTCLOUD);
+
+ MetalKernelPipeline *best_pipeline = nullptr;
+ for (auto &pipeline : collection) {
+ if (!pipeline->loaded) {
+ /* still loading - ignore */
+ continue;
+ }
+
+ if (pipeline->use_metalrt != use_metalrt || pipeline->metalrt_hair != metalrt_hair ||
+ pipeline->metalrt_hair_thick != metalrt_hair_thick ||
+ pipeline->metalrt_pointcloud != metalrt_pointcloud) {
+ /* wrong combination of metalrt options */
+ continue;
+ }
+
+ if (pipeline->scene_specialized) {
+ if (pipeline->source_md5 == device->source_md5[PSO_SPECIALISED]) {
+ best_pipeline = pipeline.get();
}
}
+ else if (!best_pipeline) {
+ best_pipeline = pipeline.get();
+ }
+ }
+
+ return best_pipeline;
+}
+
+void MetalKernelPipeline::compile()
+{
+ int pso_type = scene_specialized ? PSO_SPECIALISED : PSO_GENERIC;
+
+ const std::string function_name = std::string("cycles_metal_") +
+ device_kernel_as_string(device_kernel);
+
+ int threads_per_threadgroup = this->threads_per_threadgroup;
+ if (device_kernel > DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL &&
+ device_kernel < DEVICE_KERNEL_INTEGRATOR_RESET) {
+ /* Always use 512 for the sorting kernels */
+ threads_per_threadgroup = 512;
}
- NSString *entryPoint = [@(desc.function_name) copy];
+ NSString *entryPoint = [@(function_name.c_str()) copy];
NSError *error = NULL;
if (@available(macOS 11.0, *)) {
MTLFunctionDescriptor *func_desc = [MTLIntersectionFunctionDescriptor functionDescriptor];
func_desc.name = entryPoint;
- if (desc.constant_values) {
- func_desc.constantValues = desc.constant_values;
- }
- pso[desc.pso_index].function = [device->mtlLibrary[desc.pso_index]
- newFunctionWithDescriptor:func_desc
- error:&error];
+ function = [mtlLibrary newFunctionWithDescriptor:func_desc error:&error];
}
+
[entryPoint release];
- if (pso[desc.pso_index].function == nil) {
+ if (function == nil) {
NSString *err = [error localizedDescription];
string errors = [err UTF8String];
+ metal_printf("Error getting function \"%s\": %s", function_name.c_str(), errors.c_str());
+ return;
+ }
+
+ function.label = [entryPoint copy];
+
+ if (use_metalrt) {
+ if (@available(macOS 11.0, *)) {
+ /* create the id<MTLFunction> for each intersection function */
+ const char *function_names[] = {
+ "__anyhit__cycles_metalrt_visibility_test_tri",
+ "__anyhit__cycles_metalrt_visibility_test_box",
+ "__anyhit__cycles_metalrt_shadow_all_hit_tri",
+ "__anyhit__cycles_metalrt_shadow_all_hit_box",
+ "__anyhit__cycles_metalrt_local_hit_tri",
+ "__anyhit__cycles_metalrt_local_hit_box",
+ "__intersection__curve_ribbon",
+ "__intersection__curve_ribbon_shadow",
+ "__intersection__curve_all",
+ "__intersection__curve_all_shadow",
+ "__intersection__point",
+ "__intersection__point_shadow",
+ };
+ assert(sizeof(function_names) / sizeof(function_names[0]) == METALRT_FUNC_NUM);
+
+ MTLFunctionDescriptor *desc = [MTLIntersectionFunctionDescriptor functionDescriptor];
+ for (int i = 0; i < METALRT_FUNC_NUM; i++) {
+ const char *function_name = function_names[i];
+ desc.name = [@(function_name) copy];
+
+ NSError *error = NULL;
+ rt_intersection_function[i] = [mtlLibrary newFunctionWithDescriptor:desc error:&error];
- device->set_error(
- string_printf("Error getting function \"%s\": %s", desc.function_name, errors.c_str()));
- return false;
+ if (rt_intersection_function[i] == nil) {
+ NSString *err = [error localizedDescription];
+ string errors = [err UTF8String];
+
+ error_str = string_printf(
+ "Error getting intersection function \"%s\": %s", function_name, errors.c_str());
+ break;
+ }
+
+ rt_intersection_function[i].label = [@(function_name) copy];
+ }
+ }
}
- pso[desc.pso_index].function.label = [@(desc.function_name) copy];
+ NSArray *table_functions[METALRT_TABLE_NUM] = {nil};
+ NSArray *linked_functions = nil;
+
+ if (use_metalrt) {
+ id<MTLFunction> curve_intersect_default = nil;
+ id<MTLFunction> curve_intersect_shadow = nil;
+ id<MTLFunction> point_intersect_default = nil;
+ id<MTLFunction> point_intersect_shadow = nil;
+ if (metalrt_hair) {
+ /* Add curve intersection programs. */
+ if (metalrt_hair_thick) {
+ /* Slower programs for thick hair since that also slows down ribbons.
+ * Ideally this should not be needed. */
+ curve_intersect_default = rt_intersection_function[METALRT_FUNC_CURVE_ALL];
+ curve_intersect_shadow = rt_intersection_function[METALRT_FUNC_CURVE_ALL_SHADOW];
+ }
+ else {
+ curve_intersect_default = rt_intersection_function[METALRT_FUNC_CURVE_RIBBON];
+ curve_intersect_shadow = rt_intersection_function[METALRT_FUNC_CURVE_RIBBON_SHADOW];
+ }
+ }
+ if (metalrt_pointcloud) {
+ point_intersect_default = rt_intersection_function[METALRT_FUNC_POINT];
+ point_intersect_shadow = rt_intersection_function[METALRT_FUNC_POINT_SHADOW];
+ }
+ table_functions[METALRT_TABLE_DEFAULT] = [NSArray
+ arrayWithObjects:rt_intersection_function[METALRT_FUNC_DEFAULT_TRI],
+ curve_intersect_default ?
+ curve_intersect_default :
+ rt_intersection_function[METALRT_FUNC_DEFAULT_BOX],
+ point_intersect_default ?
+ point_intersect_default :
+ rt_intersection_function[METALRT_FUNC_DEFAULT_BOX],
+ nil];
+ table_functions[METALRT_TABLE_SHADOW] = [NSArray
+ arrayWithObjects:rt_intersection_function[METALRT_FUNC_SHADOW_TRI],
+ curve_intersect_shadow ?
+ curve_intersect_shadow :
+ rt_intersection_function[METALRT_FUNC_SHADOW_BOX],
+ point_intersect_shadow ?
+ point_intersect_shadow :
+ rt_intersection_function[METALRT_FUNC_SHADOW_BOX],
+ nil];
+ table_functions[METALRT_TABLE_LOCAL] = [NSArray
+ arrayWithObjects:rt_intersection_function[METALRT_FUNC_LOCAL_TRI],
+ rt_intersection_function[METALRT_FUNC_LOCAL_BOX],
+ rt_intersection_function[METALRT_FUNC_LOCAL_BOX],
+ nil];
+
+ NSMutableSet *unique_functions = [NSMutableSet
+ setWithArray:table_functions[METALRT_TABLE_DEFAULT]];
+ [unique_functions addObjectsFromArray:table_functions[METALRT_TABLE_SHADOW]];
+ [unique_functions addObjectsFromArray:table_functions[METALRT_TABLE_LOCAL]];
+
+ if (kernel_has_intersection(device_kernel)) {
+ linked_functions = [[NSArray arrayWithArray:[unique_functions allObjects]]
+ sortedArrayUsingComparator:^NSComparisonResult(id<MTLFunction> f1, id<MTLFunction> f2) {
+ return [f1.label compare:f2.label];
+ }];
+ }
+ unique_functions = nil;
+ }
- __block MTLComputePipelineDescriptor *computePipelineStateDescriptor =
+ MTLComputePipelineDescriptor *computePipelineStateDescriptor =
[[MTLComputePipelineDescriptor alloc] init];
computePipelineStateDescriptor.buffers[0].mutability = MTLMutabilityImmutable;
@@ -111,52 +407,86 @@ bool MetalDeviceKernel::load(MetalDevice *device,
computePipelineStateDescriptor.buffers[2].mutability = MTLMutabilityImmutable;
if (@available(macos 10.14, *)) {
- computePipelineStateDescriptor.maxTotalThreadsPerThreadgroup = desc.threads_per_threadgroup;
+ computePipelineStateDescriptor.maxTotalThreadsPerThreadgroup = threads_per_threadgroup;
}
computePipelineStateDescriptor.threadGroupSizeIsMultipleOfThreadExecutionWidth = true;
- computePipelineStateDescriptor.computeFunction = pso[desc.pso_index].function;
+ computePipelineStateDescriptor.computeFunction = function;
+
if (@available(macOS 11.0, *)) {
/* Attach the additional functions to an MTLLinkedFunctions object */
- if (desc.linked_functions) {
+ if (linked_functions) {
computePipelineStateDescriptor.linkedFunctions = [[MTLLinkedFunctions alloc] init];
- computePipelineStateDescriptor.linkedFunctions.functions = desc.linked_functions;
+ computePipelineStateDescriptor.linkedFunctions.functions = linked_functions;
}
-
computePipelineStateDescriptor.maxCallStackDepth = 1;
+ if (use_metalrt) {
+ computePipelineStateDescriptor.maxCallStackDepth = 8;
+ }
}
- /* Create a new Compute pipeline state object */
MTLPipelineOption pipelineOptions = MTLPipelineOptionNone;
- bool creating_new_archive = false;
+ bool use_binary_archive = true;
+ if (auto str = getenv("CYCLES_METAL_DISABLE_BINARY_ARCHIVES")) {
+ use_binary_archive = (atoi(str) == 0);
+ }
+
+ id<MTLBinaryArchive> archive = nil;
+ string metalbin_path;
+ string metalbin_name;
+ if (use_binary_archive) {
+ NSProcessInfo *processInfo = [NSProcessInfo processInfo];
+ string osVersion = [[processInfo operatingSystemVersionString] UTF8String];
+ MD5Hash local_md5;
+ local_md5.append(source_md5);
+ local_md5.append(osVersion);
+ local_md5.append((uint8_t *)&this->threads_per_threadgroup,
+ sizeof(this->threads_per_threadgroup));
+
+ string options;
+ if (use_metalrt && kernel_has_intersection(device_kernel)) {
+ /* incorporate any MetalRT specializations into the archive name */
+ options += string_printf(".hair_%d.hair_thick_%d.pointcloud_%d",
+ metalrt_hair ? 1 : 0,
+ metalrt_hair_thick ? 1 : 0,
+ metalrt_pointcloud ? 1 : 0);
+ }
+
+ /* Replace non-alphanumerical characters with underscores. */
+ string device_name = [mtlDevice.name UTF8String];
+ for (char &c : device_name) {
+ if ((c < '0' || c > '9') && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z')) {
+ c = '_';
+ }
+ }
+
+ metalbin_name = device_name;
+ metalbin_name = path_join(metalbin_name, device_kernel_as_string(device_kernel));
+ metalbin_name = path_join(metalbin_name, kernel_type_as_string(pso_type));
+ metalbin_name = path_join(metalbin_name, local_md5.get_hex() + options + ".bin");
+
+ metalbin_path = path_cache_get(path_join("kernels", metalbin_name));
+ path_create_directories(metalbin_path);
+
+ if (path_exists(metalbin_path) && use_binary_archive) {
+ if (@available(macOS 11.0, *)) {
+ MTLBinaryArchiveDescriptor *archiveDesc = [[MTLBinaryArchiveDescriptor alloc] init];
+ archiveDesc.url = [NSURL fileURLWithPath:@(metalbin_path.c_str())];
+ archive = [mtlDevice newBinaryArchiveWithDescriptor:archiveDesc error:nil];
+ [archiveDesc release];
+ }
+ }
+ }
+
+ __block bool creating_new_archive = false;
if (@available(macOS 11.0, *)) {
if (use_binary_archive) {
if (!archive) {
MTLBinaryArchiveDescriptor *archiveDesc = [[MTLBinaryArchiveDescriptor alloc] init];
archiveDesc.url = nil;
- archive = [device->mtlDevice newBinaryArchiveWithDescriptor:archiveDesc error:nil];
+ archive = [mtlDevice newBinaryArchiveWithDescriptor:archiveDesc error:nil];
creating_new_archive = true;
-
- double starttime = time_dt();
-
- if (![archive addComputePipelineFunctionsWithDescriptor:computePipelineStateDescriptor
- error:&error]) {
- NSString *errStr = [error localizedDescription];
- metal_printf("Failed to add PSO to archive:\n%s\n",
- errStr ? [errStr UTF8String] : "nil");
- }
- else {
- double duration = time_dt() - starttime;
- metal_printf("%2d | %-55s | %7.2fs\n",
- desc.kernel_index,
- device_kernel_as_string((DeviceKernel)desc.kernel_index),
- duration);
-
- if (desc.pso_index == PSO_GENERIC) {
- this->load_duration = duration;
- }
- }
}
computePipelineStateDescriptor.binaryArchives = [NSArray arrayWithObjects:archive, nil];
pipelineOptions = MTLPipelineOptionFailOnBinaryArchiveMiss;
@@ -170,17 +500,14 @@ bool MetalDeviceKernel::load(MetalDevice *device,
MTLComputePipelineReflection *reflection,
NSError *error) {
bool recreate_archive = false;
- if (computePipelineState == nil && archive && !creating_new_archive) {
-
- assert(0);
-
+ if (computePipelineState == nil && archive) {
NSString *errStr = [error localizedDescription];
metal_printf(
"Failed to create compute pipeline state \"%s\" from archive - attempting recreation... "
"(error: %s)\n",
- device_kernel_as_string((DeviceKernel)desc.kernel_index),
+ device_kernel_as_string((DeviceKernel)device_kernel),
errStr ? [errStr UTF8String] : "nil");
- computePipelineState = [device->mtlDevice
+ computePipelineState = [mtlDevice
newComputePipelineStateWithDescriptor:computePipelineStateDescriptor
options:MTLPipelineOptionNone
reflection:nullptr
@@ -192,32 +519,23 @@ bool MetalDeviceKernel::load(MetalDevice *device,
if (computePipelineState == nil) {
NSString *errStr = [error localizedDescription];
- device->set_error(string_printf("Failed to create compute pipeline state \"%s\", error: \n",
- device_kernel_as_string((DeviceKernel)desc.kernel_index)) +
- (errStr ? [errStr UTF8String] : "nil"));
- metal_printf("%2d | %-55s | %7.2fs | FAILED!\n",
- desc.kernel_index,
- device_kernel_as_string((DeviceKernel)desc.kernel_index),
+ error_str = string_printf("Failed to create compute pipeline state \"%s\", error: \n",
+ device_kernel_as_string((DeviceKernel)device_kernel));
+ error_str += (errStr ? [errStr UTF8String] : "nil");
+ metal_printf("%16s | %2d | %-55s | %7.2fs | FAILED!\n",
+ kernel_type_as_string(pso_type),
+ device_kernel,
+ device_kernel_as_string((DeviceKernel)device_kernel),
duration);
return;
}
- pso[desc.pso_index].pipeline = computePipelineState;
- num_threads_per_block = round_down(computePipelineState.maxTotalThreadsPerThreadgroup,
- computePipelineState.threadExecutionWidth);
+ int num_threads_per_block = round_down(computePipelineState.maxTotalThreadsPerThreadgroup,
+ computePipelineState.threadExecutionWidth);
num_threads_per_block = std::max(num_threads_per_block,
(int)computePipelineState.threadExecutionWidth);
-
- if (!use_binary_archive) {
- metal_printf("%2d | %-55s | %7.2fs\n",
- desc.kernel_index,
- device_kernel_as_string((DeviceKernel)desc.kernel_index),
- duration);
-
- if (desc.pso_index == PSO_GENERIC) {
- this->load_duration = duration;
- }
- }
+ this->pipeline = computePipelineState;
+ this->num_threads_per_block = num_threads_per_block;
if (@available(macOS 11.0, *)) {
if (creating_new_archive || recreate_archive) {
@@ -228,305 +546,85 @@ bool MetalDeviceKernel::load(MetalDevice *device,
}
}
}
+ };
- [computePipelineStateDescriptor release];
- computePipelineStateDescriptor = nil;
-
- if (device->use_metalrt && desc.linked_functions) {
- for (int table = 0; table < METALRT_TABLE_NUM; table++) {
- if (@available(macOS 11.0, *)) {
- MTLIntersectionFunctionTableDescriptor *ift_desc =
- [[MTLIntersectionFunctionTableDescriptor alloc] init];
- ift_desc.functionCount = desc.intersector_functions[table].count;
-
- pso[desc.pso_index].intersection_func_table[table] = [pso[desc.pso_index].pipeline
- newIntersectionFunctionTableWithDescriptor:ift_desc];
-
- /* Finally write the function handles into this pipeline's table */
- for (int i = 0; i < 2; i++) {
- id<MTLFunctionHandle> handle = [pso[desc.pso_index].pipeline
- functionHandleWithFunction:desc.intersector_functions[table][i]];
- [pso[desc.pso_index].intersection_func_table[table] setFunction:handle atIndex:i];
- }
+ /* Block on load to ensure we continue with a valid kernel function */
+ if (creating_new_archive) {
+ starttime = time_dt();
+ NSError *error;
+ if (![archive addComputePipelineFunctionsWithDescriptor:computePipelineStateDescriptor
+ error:&error]) {
+ NSString *errStr = [error localizedDescription];
+ metal_printf("Failed to add PSO to archive:\n%s\n", errStr ? [errStr UTF8String] : "nil");
+ }
+ }
+ id<MTLComputePipelineState> pipeline = [mtlDevice
+ newComputePipelineStateWithDescriptor:computePipelineStateDescriptor
+ options:pipelineOptions
+ reflection:nullptr
+ error:&error];
+ completionHandler(pipeline, nullptr, error);
+
+ this->loaded = true;
+ [computePipelineStateDescriptor release];
+ computePipelineStateDescriptor = nil;
+
+ if (use_metalrt && linked_functions) {
+ for (int table = 0; table < METALRT_TABLE_NUM; table++) {
+ if (@available(macOS 11.0, *)) {
+ MTLIntersectionFunctionTableDescriptor *ift_desc =
+ [[MTLIntersectionFunctionTableDescriptor alloc] init];
+ ift_desc.functionCount = table_functions[table].count;
+ intersection_func_table[table] = [this->pipeline
+ newIntersectionFunctionTableWithDescriptor:ift_desc];
+
+ /* Finally write the function handles into this pipeline's table */
+ for (int i = 0; i < 2; i++) {
+ id<MTLFunctionHandle> handle = [pipeline
+ functionHandleWithFunction:table_functions[table][i]];
+ [intersection_func_table[table] setFunction:handle atIndex:i];
}
}
}
+ }
- mark_loaded(desc.pso_index);
- };
+ double duration = time_dt() - starttime;
- if (desc.pso_index == PSO_SPECIALISED) {
- /* Asynchronous load */
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- NSError *error;
- id<MTLComputePipelineState> pipeline = [device->mtlDevice
- newComputePipelineStateWithDescriptor:computePipelineStateDescriptor
- options:pipelineOptions
- reflection:nullptr
- error:&error];
- completionHandler(pipeline, nullptr, error);
- });
+ if (!use_binary_archive) {
+ metal_printf("%16s | %2d | %-55s | %7.2fs\n",
+ kernel_type_as_string(pso_type),
+ int(device_kernel),
+ device_kernel_as_string(device_kernel),
+ duration);
}
else {
- /* Block on load to ensure we continue with a valid kernel function */
- id<MTLComputePipelineState> pipeline = [device->mtlDevice
- newComputePipelineStateWithDescriptor:computePipelineStateDescriptor
- options:pipelineOptions
- reflection:nullptr
- error:&error];
- completionHandler(pipeline, nullptr, error);
- }
-
- return true;
-}
-
-const MetalKernelPipeline &MetalDeviceKernel::get_pso() const
-{
- if (pso[PSO_SPECIALISED].loaded) {
- return pso[PSO_SPECIALISED];
+ metal_printf("%16s | %2d | %-55s | %7.2fs | %s: %s\n",
+ kernel_type_as_string(pso_type),
+ device_kernel,
+ device_kernel_as_string((DeviceKernel)device_kernel),
+ duration,
+ creating_new_archive ? " new" : "load",
+ metalbin_name.c_str());
}
-
- assert(pso[PSO_GENERIC].loaded);
- return pso[PSO_GENERIC];
}
-bool MetalDeviceKernels::load(MetalDevice *device, int kernel_type)
+bool MetalDeviceKernels::load(MetalDevice *device, bool scene_specialized)
{
- bool any_error = false;
-
- MD5Hash md5;
-
- /* Build the function constant table */
- MTLFunctionConstantValues *constant_values = nullptr;
- if (kernel_type == PSO_SPECIALISED) {
- constant_values = [MTLFunctionConstantValues new];
-
-# define KERNEL_FILM(_type, name) \
- [constant_values setConstantValue:&data.film.name \
- type:get_MTLDataType_##_type() \
- atIndex:KernelData_film_##name]; \
- md5.append((uint8_t *)&data.film.name, sizeof(data.film.name));
-
-# define KERNEL_BACKGROUND(_type, name) \
- [constant_values setConstantValue:&data.background.name \
- type:get_MTLDataType_##_type() \
- atIndex:KernelData_background_##name]; \
- md5.append((uint8_t *)&data.background.name, sizeof(data.background.name));
-
-# define KERNEL_INTEGRATOR(_type, name) \
- [constant_values setConstantValue:&data.integrator.name \
- type:get_MTLDataType_##_type() \
- atIndex:KernelData_integrator_##name]; \
- md5.append((uint8_t *)&data.integrator.name, sizeof(data.integrator.name));
-
-# define KERNEL_BVH(_type, name) \
- [constant_values setConstantValue:&data.bvh.name \
- type:get_MTLDataType_##_type() \
- atIndex:KernelData_bvh_##name]; \
- md5.append((uint8_t *)&data.bvh.name, sizeof(data.bvh.name));
-
- /* METAL_WIP: populate constant_values based on KernelData */
- assert(0);
- /*
- const KernelData &data = device->launch_params.data;
- # include "kernel/types/background.h"
- # include "kernel/types/bvh.h"
- # include "kernel/types/film.h"
- # include "kernel/types/integrator.h"
- */
- }
-
- if (device->use_metalrt) {
- if (@available(macOS 11.0, *)) {
- /* create the id<MTLFunction> for each intersection function */
- const char *function_names[] = {
- "__anyhit__cycles_metalrt_visibility_test_tri",
- "__anyhit__cycles_metalrt_visibility_test_box",
- "__anyhit__cycles_metalrt_shadow_all_hit_tri",
- "__anyhit__cycles_metalrt_shadow_all_hit_box",
- "__anyhit__cycles_metalrt_local_hit_tri",
- "__anyhit__cycles_metalrt_local_hit_box",
- "__intersection__curve_ribbon",
- "__intersection__curve_ribbon_shadow",
- "__intersection__curve_all",
- "__intersection__curve_all_shadow",
- "__intersection__point",
- "__intersection__point_shadow",
- };
- assert(sizeof(function_names) / sizeof(function_names[0]) == METALRT_FUNC_NUM);
-
- MTLFunctionDescriptor *desc = [MTLIntersectionFunctionDescriptor functionDescriptor];
- if (kernel_type == PSO_SPECIALISED) {
- desc.constantValues = constant_values;
- }
- for (int i = 0; i < METALRT_FUNC_NUM; i++) {
- const char *function_name = function_names[i];
- desc.name = [@(function_name) copy];
-
- NSError *error = NULL;
- rt_intersection_funcs[kernel_type][i] = [device->mtlLibrary[kernel_type]
- newFunctionWithDescriptor:desc
- error:&error];
-
- if (rt_intersection_funcs[kernel_type][i] == nil) {
- NSString *err = [error localizedDescription];
- string errors = [err UTF8String];
-
- device->set_error(string_printf(
- "Error getting intersection function \"%s\": %s", function_name, errors.c_str()));
- any_error = true;
- break;
- }
-
- rt_intersection_funcs[kernel_type][i].label = [@(function_name) copy];
- }
- }
- }
- md5.append(device->source_used_for_compile[kernel_type]);
-
- string hash = md5.get_hex();
- if (loaded_md5[kernel_type] == hash) {
- return true;
- }
-
- if (!any_error) {
- NSArray *table_functions[METALRT_TABLE_NUM] = {nil};
- NSArray *function_list = nil;
-
- if (device->use_metalrt) {
- id<MTLFunction> curve_intersect_default = nil;
- id<MTLFunction> curve_intersect_shadow = nil;
- id<MTLFunction> point_intersect_default = nil;
- id<MTLFunction> point_intersect_shadow = nil;
- if (device->kernel_features & KERNEL_FEATURE_HAIR) {
- /* Add curve intersection programs. */
- if (device->kernel_features & KERNEL_FEATURE_HAIR_THICK) {
- /* Slower programs for thick hair since that also slows down ribbons.
- * Ideally this should not be needed. */
- curve_intersect_default = rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_ALL];
- curve_intersect_shadow =
- rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_ALL_SHADOW];
- }
- else {
- curve_intersect_default = rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_RIBBON];
- curve_intersect_shadow =
- rt_intersection_funcs[kernel_type][METALRT_FUNC_CURVE_RIBBON_SHADOW];
- }
- }
- if (device->kernel_features & KERNEL_FEATURE_POINTCLOUD) {
- point_intersect_default = rt_intersection_funcs[kernel_type][METALRT_FUNC_POINT];
- point_intersect_shadow = rt_intersection_funcs[kernel_type][METALRT_FUNC_POINT_SHADOW];
- }
- table_functions[METALRT_TABLE_DEFAULT] = [NSArray
- arrayWithObjects:rt_intersection_funcs[kernel_type][METALRT_FUNC_DEFAULT_TRI],
- curve_intersect_default ?
- curve_intersect_default :
- rt_intersection_funcs[kernel_type][METALRT_FUNC_DEFAULT_BOX],
- point_intersect_default ?
- point_intersect_default :
- rt_intersection_funcs[kernel_type][METALRT_FUNC_DEFAULT_BOX],
- nil];
- table_functions[METALRT_TABLE_SHADOW] = [NSArray
- arrayWithObjects:rt_intersection_funcs[kernel_type][METALRT_FUNC_SHADOW_TRI],
- curve_intersect_shadow ?
- curve_intersect_shadow :
- rt_intersection_funcs[kernel_type][METALRT_FUNC_SHADOW_BOX],
- point_intersect_shadow ?
- point_intersect_shadow :
- rt_intersection_funcs[kernel_type][METALRT_FUNC_SHADOW_BOX],
- nil];
- table_functions[METALRT_TABLE_LOCAL] = [NSArray
- arrayWithObjects:rt_intersection_funcs[kernel_type][METALRT_FUNC_LOCAL_TRI],
- rt_intersection_funcs[kernel_type][METALRT_FUNC_LOCAL_BOX],
- rt_intersection_funcs[kernel_type][METALRT_FUNC_LOCAL_BOX],
- nil];
-
- NSMutableSet *unique_functions = [NSMutableSet
- setWithArray:table_functions[METALRT_TABLE_DEFAULT]];
- [unique_functions addObjectsFromArray:table_functions[METALRT_TABLE_SHADOW]];
- [unique_functions addObjectsFromArray:table_functions[METALRT_TABLE_LOCAL]];
-
- function_list = [[NSArray arrayWithArray:[unique_functions allObjects]]
- sortedArrayUsingComparator:^NSComparisonResult(id<MTLFunction> f1, id<MTLFunction> f2) {
- return [f1.label compare:f2.label];
- }];
-
- unique_functions = nil;
- }
-
- metal_printf("Starting %s \"cycles_metal_...\" pipeline builds\n",
- kernel_type_as_string(kernel_type));
-
- tbb::task_arena local_arena(max_mtlcompiler_threads);
- local_arena.execute([&]() {
- parallel_for(int(0), int(DEVICE_KERNEL_NUM), [&](int i) {
- /* skip megakernel */
- if (i == DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL) {
- return;
- }
-
- /* Only specialize kernels where it can make an impact. */
- if (kernel_type == PSO_SPECIALISED) {
- if (i < DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST ||
- i > DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL) {
- return;
- }
- }
-
- MetalDeviceKernel &kernel = kernels_[i];
-
- const std::string function_name = std::string("cycles_metal_") +
- device_kernel_as_string((DeviceKernel)i);
- int threads_per_threadgroup = device->max_threads_per_threadgroup;
- if (i > DEVICE_KERNEL_INTEGRATOR_MEGAKERNEL && i < DEVICE_KERNEL_INTEGRATOR_RESET) {
- /* Always use 512 for the sorting kernels */
- threads_per_threadgroup = 512;
- }
-
- NSArray *kernel_function_list = nil;
-
- if (i == DEVICE_KERNEL_INTEGRATOR_INTERSECT_CLOSEST ||
- i == DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW ||
- i == DEVICE_KERNEL_INTEGRATOR_INTERSECT_SUBSURFACE ||
- i == DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK ||
- i == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE ||
- i == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE) {
- kernel_function_list = function_list;
- }
-
- MetalKernelLoadDesc desc;
- desc.pso_index = kernel_type;
- desc.kernel_index = i;
- desc.linked_functions = kernel_function_list;
- desc.intersector_functions.defaults = table_functions[METALRT_TABLE_DEFAULT];
- desc.intersector_functions.shadow = table_functions[METALRT_TABLE_SHADOW];
- desc.intersector_functions.local = table_functions[METALRT_TABLE_LOCAL];
- desc.constant_values = constant_values;
- desc.threads_per_threadgroup = threads_per_threadgroup;
- desc.function_name = function_name.c_str();
-
- bool success = kernel.load(device, desc, md5);
-
- any_error |= !success;
- });
- });
+ auto shader_cache = get_shader_cache(device->mtlDevice);
+ for (int i = 0; i < DEVICE_KERNEL_NUM; i++) {
+ shader_cache->load_kernel((DeviceKernel)i, device, scene_specialized);
}
- bool loaded = !any_error;
- if (loaded) {
- loaded_md5[kernel_type] = hash;
+ if (!scene_specialized || getenv("CYCLES_METAL_PROFILING")) {
+ shader_cache->wait_for_all();
}
- return loaded;
-}
-
-const MetalDeviceKernel &MetalDeviceKernels::get(DeviceKernel kernel) const
-{
- return kernels_[(int)kernel];
+ return true;
}
-bool MetalDeviceKernels::available(DeviceKernel kernel) const
+const MetalKernelPipeline *MetalDeviceKernels::get_best_pipeline(const MetalDevice *device,
+ DeviceKernel kernel)
{
- return kernels_[(int)kernel].get_pso().function != nil;
+ return get_shader_cache(device->mtlDevice)->get_best_pipeline(kernel, device);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/device/metal/queue.mm b/intern/cycles/device/metal/queue.mm
index df2b3321cf6..c1dab5b0d8f 100644
--- a/intern/cycles/device/metal/queue.mm
+++ b/intern/cycles/device/metal/queue.mm
@@ -108,9 +108,6 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
VLOG(3) << "Metal queue launch " << device_kernel_as_string(kernel) << ", work_size "
<< work_size;
- const MetalDeviceKernel &metal_kernel = metal_device->kernels.get(kernel);
- const MetalKernelPipeline &metal_kernel_pso = metal_kernel.get_pso();
-
id<MTLComputeCommandEncoder> mtlComputeCommandEncoder = get_compute_encoder(kernel);
/* Determine size requirement for argument buffer. */
@@ -212,6 +209,14 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
}
bytes_written = globals_offsets + sizeof(KernelParamsMetal);
+ const MetalKernelPipeline *metal_kernel_pso = MetalDeviceKernels::get_best_pipeline(metal_device,
+ kernel);
+ if (!metal_kernel_pso) {
+ metal_device->set_error(
+ string_printf("No MetalKernelPipeline for %s\n", device_kernel_as_string(kernel)));
+ return false;
+ }
+
/* Encode ancillaries */
[metal_device->mtlAncillaryArgEncoder setArgumentBuffer:arg_buffer offset:metal_offsets];
[metal_device->mtlAncillaryArgEncoder setBuffer:metal_device->texture_bindings_2d
@@ -228,14 +233,14 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
}
for (int table = 0; table < METALRT_TABLE_NUM; table++) {
- if (metal_kernel_pso.intersection_func_table[table]) {
- [metal_kernel_pso.intersection_func_table[table] setBuffer:arg_buffer
- offset:globals_offsets
- atIndex:1];
+ if (metal_kernel_pso->intersection_func_table[table]) {
+ [metal_kernel_pso->intersection_func_table[table] setBuffer:arg_buffer
+ offset:globals_offsets
+ atIndex:1];
[metal_device->mtlAncillaryArgEncoder
- setIntersectionFunctionTable:metal_kernel_pso.intersection_func_table[table]
+ setIntersectionFunctionTable:metal_kernel_pso->intersection_func_table[table]
atIndex:3 + table];
- [mtlComputeCommandEncoder useResource:metal_kernel_pso.intersection_func_table[table]
+ [mtlComputeCommandEncoder useResource:metal_kernel_pso->intersection_func_table[table]
usage:MTLResourceUsageRead];
}
else {
@@ -282,10 +287,10 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
}
}
- [mtlComputeCommandEncoder setComputePipelineState:metal_kernel_pso.pipeline];
+ [mtlComputeCommandEncoder setComputePipelineState:metal_kernel_pso->pipeline];
/* Compute kernel launch parameters. */
- const int num_threads_per_block = metal_kernel.get_num_threads_per_block();
+ const int num_threads_per_block = metal_kernel_pso->num_threads_per_block;
int shared_mem_bytes = 0;
@@ -315,7 +320,7 @@ bool MetalDeviceQueue::enqueue(DeviceKernel kernel,
threadsPerThreadgroup:size_threads_per_threadgroup];
[mtlCommandBuffer addCompletedHandler:^(id<MTLCommandBuffer> command_buffer) {
- NSString *kernel_name = metal_kernel_pso.function.label;
+ NSString *kernel_name = metal_kernel_pso->function.label;
/* Enhanced command buffer errors are only available in 11.0+ */
if (@available(macos 11.0, *)) {
@@ -548,6 +553,8 @@ id<MTLComputeCommandEncoder> MetalDeviceQueue::get_compute_encoder(DeviceKernel
computeCommandEncoderWithDispatchType:concurrent ? MTLDispatchTypeConcurrent :
MTLDispatchTypeSerial];
+ [mtlComputeEncoder setLabel:@(device_kernel_as_string(kernel))];
+
/* declare usage of MTLBuffers etc */
prepare_resources(kernel);
}
diff --git a/intern/cycles/device/optix/device_impl.cpp b/intern/cycles/device/optix/device_impl.cpp
index 9576643cff6..9ab9bbb59c5 100644
--- a/intern/cycles/device/optix/device_impl.cpp
+++ b/intern/cycles/device/optix/device_impl.cpp
@@ -23,6 +23,7 @@
# include "util/md5.h"
# include "util/path.h"
# include "util/progress.h"
+# include "util/task.h"
# include "util/time.h"
# undef __KERNEL_CPU__
@@ -216,6 +217,25 @@ static OptixResult optixUtilDenoiserInvokeTiled(OptixDenoiser denoiser,
return OPTIX_SUCCESS;
}
+# if OPTIX_ABI_VERSION >= 55
+static void execute_optix_task(TaskPool &pool, OptixTask task, OptixResult &failure_reason)
+{
+ OptixTask additional_tasks[16];
+ unsigned int num_additional_tasks = 0;
+
+ const OptixResult result = optixTaskExecute(task, additional_tasks, 16, &num_additional_tasks);
+ if (result == OPTIX_SUCCESS) {
+ for (unsigned int i = 0; i < num_additional_tasks; ++i) {
+ pool.push(function_bind(
+ &execute_optix_task, std::ref(pool), additional_tasks[i], std::ref(failure_reason)));
+ }
+ }
+ else {
+ failure_reason = result;
+ }
+}
+# endif
+
} // namespace
OptiXDevice::Denoiser::Denoiser(OptiXDevice *device)
@@ -456,6 +476,23 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
return false;
}
+# if OPTIX_ABI_VERSION >= 55
+ OptixTask task = nullptr;
+ OptixResult result = optixModuleCreateFromPTXWithTasks(context,
+ &module_options,
+ &pipeline_options,
+ ptx_data.data(),
+ ptx_data.size(),
+ nullptr,
+ nullptr,
+ &optix_module,
+ &task);
+ if (result == OPTIX_SUCCESS) {
+ TaskPool pool;
+ execute_optix_task(pool, task, result);
+ pool.wait_work();
+ }
+# else
const OptixResult result = optixModuleCreateFromPTX(context,
&module_options,
&pipeline_options,
@@ -464,6 +501,7 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
nullptr,
0,
&optix_module);
+# endif
if (result != OPTIX_SUCCESS) {
set_error(string_printf("Failed to load OptiX kernel from '%s' (%s)",
ptx_filename.c_str(),
@@ -515,7 +553,8 @@ bool OptiXDevice::load_kernels(const uint kernel_features)
OptixBuiltinISOptions builtin_options = {};
# if OPTIX_ABI_VERSION >= 55
builtin_options.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_CATMULLROM;
- builtin_options.buildFlags = OPTIX_BUILD_FLAG_PREFER_FAST_TRACE;
+ builtin_options.buildFlags = OPTIX_BUILD_FLAG_PREFER_FAST_TRACE |
+ OPTIX_BUILD_FLAG_ALLOW_COMPACTION;
builtin_options.curveEndcapFlags = OPTIX_CURVE_ENDCAP_DEFAULT; /* Disable end-caps. */
# else
builtin_options.builtinISModuleType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE;
@@ -1199,7 +1238,7 @@ bool OptiXDevice::denoise_configure_if_needed(DenoiseContext &context)
const OptixResult result = optixDenoiserSetup(
denoiser_.optix_denoiser,
0, /* Work around bug in r495 drivers that causes artifacts when denoiser setup is called
- on a stream that is not the default stream */
+ * on a stream that is not the default stream. */
tile_size.x + denoiser_.sizes.overlapWindowSizeInPixels * 2,
tile_size.y + denoiser_.sizes.overlapWindowSizeInPixels * 2,
denoiser_.state.device_pointer,
@@ -1349,7 +1388,10 @@ bool OptiXDevice::build_optix_bvh(BVHOptiX *bvh,
OptixAccelBufferSizes sizes = {};
OptixAccelBuildOptions options = {};
options.operation = operation;
- if (use_fast_trace_bvh) {
+ if (use_fast_trace_bvh ||
+ /* The build flags have to match the ones used to query the built-in curve intersection
+ program (see optixBuiltinISModuleGet above) */
+ build_input.type == OPTIX_BUILD_INPUT_TYPE_CURVES) {
VLOG(2) << "Using fast to trace OptiX BVH";
options.buildFlags = OPTIX_BUILD_FLAG_PREFER_FAST_TRACE | OPTIX_BUILD_FLAG_ALLOW_COMPACTION;
}
@@ -1874,7 +1916,7 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
{
/* Can disable __anyhit__kernel_optix_visibility_test by default (except for thick curves,
* since it needs to filter out end-caps there).
-
+ *
* It is enabled where necessary (visibility mask exceeds 8 bits or the other any-hit
* programs like __anyhit__kernel_optix_shadow_all_hit) via OPTIX_RAY_FLAG_ENFORCE_ANYHIT.
*/
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index d97854a52d0..473bdb67920 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -145,6 +145,7 @@ set(SRC_KERNEL_SVM_HEADERS
svm/normal.h
svm/ramp.h
svm/ramp_util.h
+ svm/sepcomb_color.h
svm/sepcomb_hsv.h
svm/sepcomb_vector.h
svm/sky.h
diff --git a/intern/cycles/kernel/device/cpu/image.h b/intern/cycles/kernel/device/cpu/image.h
index 3b714a3e580..7809ec5f4a7 100644
--- a/intern/cycles/kernel/device/cpu/image.h
+++ b/intern/cycles/kernel/device/cpu/image.h
@@ -817,6 +817,16 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals kg,
}
case IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
return NanoVDBInterpolator<nanovdb::Vec3f>::interp_3d(info, P.x, P.y, P.z, interp);
+ case IMAGE_DATA_TYPE_NANOVDB_FPN: {
+ const float f = NanoVDBInterpolator<nanovdb::FpN, float>::interp_3d(
+ info, P.x, P.y, P.z, interp);
+ return make_float4(f, f, f, 1.0f);
+ }
+ case IMAGE_DATA_TYPE_NANOVDB_FP16: {
+ const float f = NanoVDBInterpolator<nanovdb::Fp16, float>::interp_3d(
+ info, P.x, P.y, P.z, interp);
+ return make_float4(f, f, f, 1.0f);
+ }
#endif
default:
assert(0);
diff --git a/intern/cycles/kernel/device/gpu/image.h b/intern/cycles/kernel/device/gpu/image.h
index c5bc7d88e02..29d851ae478 100644
--- a/intern/cycles/kernel/device/gpu/image.h
+++ b/intern/cycles/kernel/device/gpu/image.h
@@ -125,7 +125,8 @@ kernel_tex_image_interp_tricubic(ccl_global const TextureInfo &info, float x, fl
#ifdef WITH_NANOVDB
template<typename T, typename S>
-ccl_device T kernel_tex_image_interp_tricubic_nanovdb(S &s, float x, float y, float z)
+ccl_device typename nanovdb::NanoGrid<T>::ValueType kernel_tex_image_interp_tricubic_nanovdb(
+ S &s, float x, float y, float z)
{
float px = floorf(x);
float py = floorf(y);
@@ -157,7 +158,7 @@ ccl_device T kernel_tex_image_interp_tricubic_nanovdb(S &s, float x, float y, fl
}
template<typename T>
-ccl_device_noinline T kernel_tex_image_interp_nanovdb(
+ccl_device_noinline typename nanovdb::NanoGrid<T>::ValueType kernel_tex_image_interp_nanovdb(
ccl_global const TextureInfo &info, float x, float y, float z, uint interpolation)
{
using namespace nanovdb;
@@ -238,6 +239,14 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals kg,
info, x, y, z, interpolation);
return make_float4(f[0], f[1], f[2], 1.0f);
}
+ if (texture_type == IMAGE_DATA_TYPE_NANOVDB_FPN) {
+ float f = kernel_tex_image_interp_nanovdb<nanovdb::FpN>(info, x, y, z, interpolation);
+ return make_float4(f, f, f, 1.0f);
+ }
+ if (texture_type == IMAGE_DATA_TYPE_NANOVDB_FP16) {
+ float f = kernel_tex_image_interp_nanovdb<nanovdb::Fp16>(info, x, y, z, interpolation);
+ return make_float4(f, f, f, 1.0f);
+ }
#endif
if (texture_type == IMAGE_DATA_TYPE_FLOAT4 || texture_type == IMAGE_DATA_TYPE_BYTE4 ||
texture_type == IMAGE_DATA_TYPE_HALF4 || texture_type == IMAGE_DATA_TYPE_USHORT4) {
diff --git a/intern/cycles/kernel/device/metal/compat.h b/intern/cycles/kernel/device/metal/compat.h
index 4e309f16c08..0ed52074a90 100644
--- a/intern/cycles/kernel/device/metal/compat.h
+++ b/intern/cycles/kernel/device/metal/compat.h
@@ -29,10 +29,26 @@ using namespace metal::raytracing;
/* Qualifiers */
-#define ccl_device
-#define ccl_device_inline ccl_device
-#define ccl_device_forceinline ccl_device
-#define ccl_device_noinline ccl_device __attribute__((noinline))
+#if defined(__KERNEL_METAL_APPLE__)
+
+/* Inline everything for Apple GPUs.
+ * This gives ~1.1x speedup and 10% spill reduction for integator_shade_surface
+ * at the cost of longer compile times (~4.5 minutes on M1 Max). */
+
+# define ccl_device __attribute__((always_inline))
+# define ccl_device_inline __attribute__((always_inline))
+# define ccl_device_forceinline __attribute__((always_inline))
+# define ccl_device_noinline __attribute__((always_inline))
+
+#else
+
+# define ccl_device
+# define ccl_device_inline ccl_device
+# define ccl_device_forceinline ccl_device
+# define ccl_device_noinline ccl_device __attribute__((noinline))
+
+#endif
+
#define ccl_device_noinline_cpu ccl_device
#define ccl_device_inline_method ccl_device
#define ccl_global device
diff --git a/intern/cycles/kernel/osl/services.cpp b/intern/cycles/kernel/osl/services.cpp
index 832498f1f73..e2e10b5b83f 100644
--- a/intern/cycles/kernel/osl/services.cpp
+++ b/intern/cycles/kernel/osl/services.cpp
@@ -1304,8 +1304,38 @@ bool OSLRenderServices::texture(ustring filename,
break;
}
case OSLTextureHandle::SVM: {
- /* Packed texture. */
- float4 rgba = kernel_tex_image_interp(kernel_globals, handle->svm_slot, s, 1.0f - t);
+ int id = -1;
+ if (handle->svm_slots[0].w == -1) {
+ /* Packed single texture. */
+ id = handle->svm_slots[0].y;
+ }
+ else {
+ /* Packed tiled texture. */
+ int tx = (int)s;
+ int ty = (int)t;
+ int tile = 1001 + 10 * ty + tx;
+ for (int4 tile_node : handle->svm_slots) {
+ if (tile_node.x == tile) {
+ id = tile_node.y;
+ break;
+ }
+ if (tile_node.z == tile) {
+ id = tile_node.w;
+ break;
+ }
+ }
+ s -= tx;
+ t -= ty;
+ }
+
+ float4 rgba;
+ if (id == -1) {
+ rgba = make_float4(
+ TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B, TEX_IMAGE_MISSING_A);
+ }
+ else {
+ rgba = kernel_tex_image_interp(kernel_globals, id, s, 1.0f - t);
+ }
result[0] = rgba[0];
if (nchannels > 1)
@@ -1319,7 +1349,7 @@ bool OSLRenderServices::texture(ustring filename,
}
case OSLTextureHandle::IES: {
/* IES light. */
- result[0] = kernel_ies_interp(kernel_globals, handle->svm_slot, s, t);
+ result[0] = kernel_ies_interp(kernel_globals, handle->svm_slots[0].y, s, t);
status = true;
break;
}
@@ -1413,7 +1443,7 @@ bool OSLRenderServices::texture3d(ustring filename,
/* Packed texture. */
ShaderData *sd = (ShaderData *)(sg->renderstate);
KernelGlobals kernel_globals = sd->osl_globals;
- int slot = handle->svm_slot;
+ int slot = handle->svm_slots[0].y;
float3 P_float3 = make_float3(P.x, P.y, P.z);
float4 rgba = kernel_tex_image_interp_3d(kernel_globals, slot, P_float3, INTERPOLATION_NONE);
diff --git a/intern/cycles/kernel/osl/services.h b/intern/cycles/kernel/osl/services.h
index 653fa017140..edffd912bad 100644
--- a/intern/cycles/kernel/osl/services.h
+++ b/intern/cycles/kernel/osl/services.h
@@ -39,18 +39,26 @@ struct KernelGlobalsCPU;
* with additional data.
*
* These are stored in a concurrent hash map, because OSL can compile multiple
- * shaders in parallel. */
+ * shaders in parallel.
+ *
+ * NOTE: The svm_slots array contains a compressed mapping of tile to svm_slot pairs
+ * stored as follows: x:tile_a, y:svm_slot_a, z:tile_b, w:svm_slot_b etc. */
struct OSLTextureHandle : public OIIO::RefCnt {
enum Type { OIIO, SVM, IES, BEVEL, AO };
+ OSLTextureHandle(Type type, const vector<int4> &svm_slots)
+ : type(type), svm_slots(svm_slots), oiio_handle(NULL), processor(NULL)
+ {
+ }
+
OSLTextureHandle(Type type = OIIO, int svm_slot = -1)
- : type(type), svm_slot(svm_slot), oiio_handle(NULL), processor(NULL)
+ : OSLTextureHandle(type, {make_int4(0, svm_slot, -1, -1)})
{
}
Type type;
- int svm_slot;
+ vector<int4> svm_slots;
OSL::TextureSystem::TextureHandle *oiio_handle;
ColorSpaceProcessor *processor;
};
diff --git a/intern/cycles/kernel/osl/shaders/CMakeLists.txt b/intern/cycles/kernel/osl/shaders/CMakeLists.txt
index 7ced21c5670..741bce7c399 100644
--- a/intern/cycles/kernel/osl/shaders/CMakeLists.txt
+++ b/intern/cycles/kernel/osl/shaders/CMakeLists.txt
@@ -16,6 +16,7 @@ set(SRC_OSL
node_camera.osl
node_checker_texture.osl
node_clamp.osl
+ node_combine_color.osl
node_combine_rgb.osl
node_combine_hsv.osl
node_combine_xyz.osl
@@ -68,6 +69,7 @@ set(SRC_OSL
node_refraction_bsdf.osl
node_rgb_curves.osl
node_rgb_ramp.osl
+ node_separate_color.osl
node_separate_rgb.osl
node_separate_hsv.osl
node_separate_xyz.osl
diff --git a/intern/cycles/kernel/osl/shaders/node_color.h b/intern/cycles/kernel/osl/shaders/node_color.h
index 388dd114e9a..06735f5b03d 100644
--- a/intern/cycles/kernel/osl/shaders/node_color.h
+++ b/intern/cycles/kernel/osl/shaders/node_color.h
@@ -148,3 +148,53 @@ color hsv_to_rgb(color hsv)
return rgb;
}
+
+color rgb_to_hsl(color rgb)
+{
+ float cmax, cmin, h, s, l;
+
+ cmax = max(rgb[0], max(rgb[1], rgb[2]));
+ cmin = min(rgb[0], min(rgb[1], rgb[2]));
+ l = min(1.0, (cmax + cmin) / 2.0);
+
+ if (cmax == cmin) {
+ h = s = 0.0; /* achromatic */
+ }
+ else {
+ float cdelta = cmax - cmin;
+ s = l > 0.5 ? cdelta / (2.0 - cmax - cmin) : cdelta / (cmax + cmin);
+ if (cmax == rgb[0]) {
+ h = (rgb[1] - rgb[2]) / cdelta + (rgb[1] < rgb[2] ? 6.0 : 0.0);
+ }
+ else if (cmax == rgb[1]) {
+ h = (rgb[2] - rgb[0]) / cdelta + 2.0;
+ }
+ else {
+ h = (rgb[0] - rgb[1]) / cdelta + 4.0;
+ }
+ }
+ h /= 6.0;
+
+ return color(h, s, l);
+}
+
+color hsl_to_rgb(color hsl)
+{
+ float nr, ng, nb, chroma, h, s, l;
+
+ h = hsl[0];
+ s = hsl[1];
+ l = hsl[2];
+
+ nr = abs(h * 6.0 - 3.0) - 1.0;
+ ng = 2.0 - abs(h * 6.0 - 2.0);
+ nb = 2.0 - abs(h * 6.0 - 4.0);
+
+ nr = clamp(nr, 0.0, 1.0);
+ nb = clamp(nb, 0.0, 1.0);
+ ng = clamp(ng, 0.0, 1.0);
+
+ chroma = (1.0 - abs(2.0 * l - 1.0)) * s;
+
+ return color((nr - 0.5) * chroma + l, (ng - 0.5) * chroma + l, (nb - 0.5) * chroma + l);
+}
diff --git a/intern/cycles/kernel/osl/shaders/node_combine_color.osl b/intern/cycles/kernel/osl/shaders/node_combine_color.osl
new file mode 100644
index 00000000000..681a592d2bb
--- /dev/null
+++ b/intern/cycles/kernel/osl/shaders/node_combine_color.osl
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2011-2022 Blender Foundation */
+
+#include "stdcycles.h"
+
+shader node_combine_color(string color_type = "rgb",
+ float Red = 0.0,
+ float Green = 0.0,
+ float Blue = 0.0,
+ output color Color = 0.8)
+{
+ if (color_type == "rgb" || color_type == "hsv" || color_type == "hsl")
+ Color = color(color_type, Red, Green, Blue);
+ else
+ warning("%s", "Unknown color space!");
+}
diff --git a/intern/cycles/kernel/osl/shaders/node_separate_color.osl b/intern/cycles/kernel/osl/shaders/node_separate_color.osl
new file mode 100644
index 00000000000..6f3e3149d8e
--- /dev/null
+++ b/intern/cycles/kernel/osl/shaders/node_separate_color.osl
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2011-2022 Blender Foundation */
+
+#include "node_color.h"
+#include "stdcycles.h"
+
+shader node_separate_color(string color_type = "rgb",
+ color Color = 0.8,
+ output float Red = 0.0,
+ output float Green = 0.0,
+ output float Blue = 0.0)
+{
+ color col;
+ if (color_type == "rgb")
+ col = Color;
+ else if (color_type == "hsv")
+ col = rgb_to_hsv(Color);
+ else if (color_type == "hsl")
+ col = rgb_to_hsl(Color);
+ else
+ warning("%s", "Unknown color space!");
+
+ Red = col[0];
+ Green = col[1];
+ Blue = col[2];
+}
diff --git a/intern/cycles/kernel/svm/color_util.h b/intern/cycles/kernel/svm/color_util.h
index b439721383c..fa22d4bc8c2 100644
--- a/intern/cycles/kernel/svm/color_util.h
+++ b/intern/cycles/kernel/svm/color_util.h
@@ -307,4 +307,30 @@ ccl_device_inline float3 svm_brightness_contrast(float3 color, float brightness,
return color;
}
+ccl_device float3 svm_combine_color(NodeCombSepColorType type, float3 color)
+{
+ switch (type) {
+ case NODE_COMBSEP_COLOR_HSV:
+ return hsv_to_rgb(color);
+ case NODE_COMBSEP_COLOR_HSL:
+ return hsl_to_rgb(color);
+ case NODE_COMBSEP_COLOR_RGB:
+ default:
+ return color;
+ }
+}
+
+ccl_device float3 svm_separate_color(NodeCombSepColorType type, float3 color)
+{
+ switch (type) {
+ case NODE_COMBSEP_COLOR_HSV:
+ return rgb_to_hsv(color);
+ case NODE_COMBSEP_COLOR_HSL:
+ return rgb_to_hsl(color);
+ case NODE_COMBSEP_COLOR_RGB:
+ default:
+ return color;
+ }
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/sepcomb_color.h b/intern/cycles/kernel/svm/sepcomb_color.h
new file mode 100644
index 00000000000..d186e7f163b
--- /dev/null
+++ b/intern/cycles/kernel/svm/sepcomb_color.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2011-2022 Blender Foundation */
+
+#pragma once
+
+CCL_NAMESPACE_BEGIN
+
+ccl_device_noinline void svm_node_combine_color(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint color_type,
+ uint inputs_stack_offsets,
+ uint result_stack_offset)
+{
+ uint red_stack_offset, green_stack_offset, blue_stack_offset;
+ svm_unpack_node_uchar3(
+ inputs_stack_offsets, &red_stack_offset, &green_stack_offset, &blue_stack_offset);
+
+ float r = stack_load_float(stack, red_stack_offset);
+ float g = stack_load_float(stack, green_stack_offset);
+ float b = stack_load_float(stack, blue_stack_offset);
+
+ /* Combine, and convert back to RGB */
+ float3 color = svm_combine_color((NodeCombSepColorType)color_type, make_float3(r, g, b));
+
+ if (stack_valid(result_stack_offset))
+ stack_store_float3(stack, result_stack_offset, color);
+}
+
+ccl_device_noinline void svm_node_separate_color(KernelGlobals kg,
+ ccl_private ShaderData *sd,
+ ccl_private float *stack,
+ uint color_type,
+ uint input_stack_offset,
+ uint results_stack_offsets)
+{
+ float3 color = stack_load_float3(stack, input_stack_offset);
+
+ /* Convert color space */
+ color = svm_separate_color((NodeCombSepColorType)color_type, color);
+
+ uint red_stack_offset, green_stack_offset, blue_stack_offset;
+ svm_unpack_node_uchar3(
+ results_stack_offsets, &red_stack_offset, &green_stack_offset, &blue_stack_offset);
+
+ if (stack_valid(red_stack_offset))
+ stack_store_float(stack, red_stack_offset, color.x);
+ if (stack_valid(green_stack_offset))
+ stack_store_float(stack, green_stack_offset, color.y);
+ if (stack_valid(blue_stack_offset))
+ stack_store_float(stack, blue_stack_offset, color.z);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h
index 08352a6231f..5def943c87f 100644
--- a/intern/cycles/kernel/svm/svm.h
+++ b/intern/cycles/kernel/svm/svm.h
@@ -181,6 +181,7 @@ CCL_NAMESPACE_END
#include "kernel/svm/noisetex.h"
#include "kernel/svm/normal.h"
#include "kernel/svm/ramp.h"
+#include "kernel/svm/sepcomb_color.h"
#include "kernel/svm/sepcomb_hsv.h"
#include "kernel/svm/sepcomb_vector.h"
#include "kernel/svm/sky.h"
@@ -508,6 +509,12 @@ ccl_device void svm_eval_nodes(KernelGlobals kg,
case NODE_MIX:
offset = svm_node_mix(kg, sd, stack, node.y, node.z, node.w, offset);
break;
+ case NODE_SEPARATE_COLOR:
+ svm_node_separate_color(kg, sd, stack, node.y, node.z, node.w);
+ break;
+ case NODE_COMBINE_COLOR:
+ svm_node_combine_color(kg, sd, stack, node.y, node.z, node.w);
+ break;
case NODE_SEPARATE_VECTOR:
svm_node_separate_vector(sd, stack, node.y, node.z, node.w);
break;
diff --git a/intern/cycles/kernel/svm/types.h b/intern/cycles/kernel/svm/types.h
index bede58f7a54..82109ec4c4f 100644
--- a/intern/cycles/kernel/svm/types.h
+++ b/intern/cycles/kernel/svm/types.h
@@ -92,6 +92,8 @@ typedef enum ShaderNodeType {
NODE_NORMAL_MAP,
NODE_INVERT,
NODE_MIX,
+ NODE_SEPARATE_COLOR,
+ NODE_COMBINE_COLOR,
NODE_SEPARATE_VECTOR,
NODE_COMBINE_VECTOR,
NODE_SEPARATE_HSV,
@@ -487,6 +489,12 @@ typedef enum NodePrincipledHairParametrization {
NODE_PRINCIPLED_HAIR_NUM,
} NodePrincipledHairParametrization;
+typedef enum NodeCombSepColorType {
+ NODE_COMBSEP_COLOR_RGB,
+ NODE_COMBSEP_COLOR_HSV,
+ NODE_COMBSEP_COLOR_HSL,
+} NodeCombSepColorType;
+
/* Closure */
typedef enum ClosureType {
diff --git a/intern/cycles/scene/attribute.cpp b/intern/cycles/scene/attribute.cpp
index df01189a54b..d6b4c0240f6 100644
--- a/intern/cycles/scene/attribute.cpp
+++ b/intern/cycles/scene/attribute.cpp
@@ -661,6 +661,26 @@ Attribute *AttributeSet::find(AttributeStandard std) const
return NULL;
}
+Attribute *AttributeSet::find_matching(const Attribute &other)
+{
+ for (Attribute &attr : attributes) {
+ if (attr.name != other.name) {
+ continue;
+ }
+ if (attr.std != other.std) {
+ continue;
+ }
+ if (attr.type != other.type) {
+ continue;
+ }
+ if (attr.element != other.element) {
+ continue;
+ }
+ return &attr;
+ }
+ return nullptr;
+}
+
void AttributeSet::remove(AttributeStandard std)
{
Attribute *attr = find(std);
@@ -729,32 +749,24 @@ void AttributeSet::clear(bool preserve_voxel_data)
void AttributeSet::update(AttributeSet &&new_attributes)
{
- /* add or update old_attributes based on the new_attributes */
- foreach (Attribute &attr, new_attributes.attributes) {
- Attribute *nattr = add(attr.name, attr.type, attr.element);
- nattr->std = attr.std;
- nattr->set_data_from(std::move(attr));
- }
-
- /* remove any attributes not on new_attributes */
+ /* Remove any attributes not on new_attributes. */
list<Attribute>::iterator it;
for (it = attributes.begin(); it != attributes.end();) {
- if (it->std != ATTR_STD_NONE) {
- if (new_attributes.find(it->std) == nullptr) {
- remove(it++);
- continue;
- }
- }
- else if (it->name != "") {
- if (new_attributes.find(it->name) == nullptr) {
- remove(it++);
- continue;
- }
+ const Attribute &old_attr = *it;
+ if (new_attributes.find_matching(old_attr) == nullptr) {
+ remove(it++);
+ continue;
}
-
it++;
}
+ /* Add or update old_attributes based on the new_attributes. */
+ foreach (Attribute &attr, new_attributes.attributes) {
+ Attribute *nattr = add(attr.name, attr.type, attr.element);
+ nattr->std = attr.std;
+ nattr->set_data_from(std::move(attr));
+ }
+
/* If all attributes were replaced, transform is no longer applied. */
geometry->transform_applied = false;
}
diff --git a/intern/cycles/scene/attribute.h b/intern/cycles/scene/attribute.h
index fd13b8ff6de..7f8cbf32049 100644
--- a/intern/cycles/scene/attribute.h
+++ b/intern/cycles/scene/attribute.h
@@ -194,6 +194,7 @@ class AttributeSet {
void remove(AttributeStandard std);
Attribute *find(AttributeRequest &req);
+ Attribute *find_matching(const Attribute &other);
void remove(Attribute *attribute);
diff --git a/intern/cycles/scene/image.cpp b/intern/cycles/scene/image.cpp
index 21fde88915e..1b44162351a 100644
--- a/intern/cycles/scene/image.cpp
+++ b/intern/cycles/scene/image.cpp
@@ -64,6 +64,10 @@ const char *name_from_type(ImageDataType type)
return "nanovdb_float";
case IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
return "nanovdb_float3";
+ case IMAGE_DATA_TYPE_NANOVDB_FPN:
+ return "nanovdb_fpn";
+ case IMAGE_DATA_TYPE_NANOVDB_FP16:
+ return "nanovdb_fp16";
case IMAGE_DATA_NUM_TYPES:
assert(!"System enumerator type, should never be used");
return "";
@@ -117,12 +121,12 @@ void ImageHandle::clear()
manager = NULL;
}
-bool ImageHandle::empty()
+bool ImageHandle::empty() const
{
return tile_slots.empty();
}
-int ImageHandle::num_tiles()
+int ImageHandle::num_tiles() const
{
return tile_slots.size();
}
@@ -154,6 +158,35 @@ int ImageHandle::svm_slot(const int tile_index) const
return tile_slots[tile_index];
}
+vector<int4> ImageHandle::get_svm_slots() const
+{
+ const size_t num_nodes = divide_up(tile_slots.size(), 2);
+
+ vector<int4> svm_slots;
+ svm_slots.reserve(num_nodes);
+ for (size_t i = 0; i < num_nodes; i++) {
+ int4 node;
+
+ int slot = tile_slots[2 * i];
+ node.x = manager->images[slot]->loader->get_tile_number();
+ node.y = slot;
+
+ if ((2 * i + 1) < tile_slots.size()) {
+ slot = tile_slots[2 * i + 1];
+ node.z = manager->images[slot]->loader->get_tile_number();
+ node.w = slot;
+ }
+ else {
+ node.z = -1;
+ node.w = -1;
+ }
+
+ svm_slots.push_back(node);
+ }
+
+ return svm_slots;
+}
+
device_texture *ImageHandle::image_memory(const int tile_index) const
{
if (tile_index >= tile_slots.size()) {
@@ -239,17 +272,12 @@ void ImageMetaData::detect_colorspace()
compress_as_srgb = true;
}
else {
- /* Always compress non-raw 8bit images as scene linear + sRGB, as a
- * heuristic to keep memory usage the same without too much data loss
- * due to quantization in common cases. */
- compress_as_srgb = (type == IMAGE_DATA_TYPE_BYTE || type == IMAGE_DATA_TYPE_BYTE4);
-
/* If colorspace conversion needed, use half instead of short so we can
* represent HDR values that might result from conversion. */
- if (type == IMAGE_DATA_TYPE_USHORT) {
+ if (type == IMAGE_DATA_TYPE_BYTE || type == IMAGE_DATA_TYPE_USHORT) {
type = IMAGE_DATA_TYPE_HALF;
}
- else if (type == IMAGE_DATA_TYPE_USHORT4) {
+ else if (type == IMAGE_DATA_TYPE_BYTE4 || type == IMAGE_DATA_TYPE_USHORT4) {
type = IMAGE_DATA_TYPE_HALF4;
}
}
@@ -266,6 +294,11 @@ ustring ImageLoader::osl_filepath() const
return ustring();
}
+int ImageLoader::get_tile_number() const
+{
+ return 0;
+}
+
bool ImageLoader::equals(const ImageLoader *a, const ImageLoader *b)
{
if (a == NULL && b == NULL) {
@@ -344,7 +377,9 @@ void ImageManager::load_image_metadata(Image *img)
metadata.detect_colorspace();
assert(features.has_nanovdb || (metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT ||
- metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3));
+ metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3 ||
+ metadata.type != IMAGE_DATA_TYPE_NANOVDB_FPN ||
+ metadata.type != IMAGE_DATA_TYPE_NANOVDB_FP16));
img->need_metadata = false;
}
@@ -397,6 +432,19 @@ ImageHandle ImageManager::add_image(ImageLoader *loader,
return handle;
}
+ImageHandle ImageManager::add_image(const vector<ImageLoader *> &loaders,
+ const ImageParams &params)
+{
+ ImageHandle handle;
+ for (ImageLoader *loader : loaders) {
+ const int slot = add_image_slot(loader, params, true);
+ handle.tile_slots.push_back(slot);
+ }
+
+ handle.manager = this;
+ return handle;
+}
+
int ImageManager::add_image_slot(ImageLoader *loader,
const ImageParams &params,
const bool builtin)
@@ -749,7 +797,8 @@ void ImageManager::device_load_image(Device *device, Scene *scene, int slot, Pro
}
}
#ifdef WITH_NANOVDB
- else if (type == IMAGE_DATA_TYPE_NANOVDB_FLOAT || type == IMAGE_DATA_TYPE_NANOVDB_FLOAT3) {
+ else if (type == IMAGE_DATA_TYPE_NANOVDB_FLOAT || type == IMAGE_DATA_TYPE_NANOVDB_FLOAT3 ||
+ type == IMAGE_DATA_TYPE_NANOVDB_FPN || type == IMAGE_DATA_TYPE_NANOVDB_FP16) {
thread_scoped_lock device_lock(device_mutex);
void *pixels = img->mem->alloc(img->metadata.byte_size, 0);
diff --git a/intern/cycles/scene/image.h b/intern/cycles/scene/image.h
index 4d0dee35eca..9edb6a7eaf5 100644
--- a/intern/cycles/scene/image.h
+++ b/intern/cycles/scene/image.h
@@ -112,6 +112,9 @@ class ImageLoader {
/* Optional for OSL texture cache. */
virtual ustring osl_filepath() const;
+ /* Optional for tiled textures loaded externally. */
+ virtual int get_tile_number() const;
+
/* Free any memory used for loading metadata and pixels. */
virtual void cleanup(){};
@@ -139,11 +142,12 @@ class ImageHandle {
void clear();
- bool empty();
- int num_tiles();
+ bool empty() const;
+ int num_tiles() const;
ImageMetaData metadata();
int svm_slot(const int tile_index = 0) const;
+ vector<int4> get_svm_slots() const;
device_texture *image_memory(const int tile_index = 0) const;
VDBImageLoader *vdb_loader(const int tile_index = 0) const;
@@ -169,6 +173,7 @@ class ImageManager {
const ImageParams &params,
const array<int> &tiles);
ImageHandle add_image(ImageLoader *loader, const ImageParams &params, const bool builtin = true);
+ ImageHandle add_image(const vector<ImageLoader *> &loaders, const ImageParams &params);
void device_update(Device *device, Scene *scene, Progress &progress);
void device_update_slot(Device *device, Scene *scene, int slot, Progress *progress);
diff --git a/intern/cycles/scene/image_oiio.cpp b/intern/cycles/scene/image_oiio.cpp
index 3f825afbe90..09676455308 100644
--- a/intern/cycles/scene/image_oiio.cpp
+++ b/intern/cycles/scene/image_oiio.cpp
@@ -94,10 +94,11 @@ bool OIIOImageLoader::load_metadata(const ImageDeviceFeatures & /*features*/,
template<TypeDesc::BASETYPE FileFormat, typename StorageType>
static void oiio_load_pixels(const ImageMetaData &metadata,
const unique_ptr<ImageInput> &in,
+ const bool associate_alpha,
StorageType *pixels)
{
- const int width = metadata.width;
- const int height = metadata.height;
+ const size_t width = metadata.width;
+ const size_t height = metadata.height;
const int depth = metadata.depth;
const int components = metadata.channels;
@@ -105,12 +106,12 @@ static void oiio_load_pixels(const ImageMetaData &metadata,
StorageType *readpixels = pixels;
vector<StorageType> tmppixels;
if (components > 4) {
- tmppixels.resize(((size_t)width) * height * components);
+ tmppixels.resize(width * height * components);
readpixels = &tmppixels[0];
}
if (depth <= 1) {
- size_t scanlinesize = ((size_t)width) * components * sizeof(StorageType);
+ size_t scanlinesize = width * components * sizeof(StorageType);
in->read_image(FileFormat,
(uchar *)readpixels + (height - 1) * scanlinesize,
AutoStride,
@@ -122,7 +123,7 @@ static void oiio_load_pixels(const ImageMetaData &metadata,
}
if (components > 4) {
- size_t dimensions = ((size_t)width) * height;
+ size_t dimensions = width * height;
for (size_t i = dimensions - 1, pixel = 0; pixel < dimensions; pixel++, i--) {
pixels[i * 4 + 3] = tmppixels[i * components + 3];
pixels[i * 4 + 2] = tmppixels[i * components + 2];
@@ -137,7 +138,7 @@ static void oiio_load_pixels(const ImageMetaData &metadata,
if (cmyk) {
const StorageType one = util_image_cast_from_float<StorageType>(1.0f);
- const size_t num_pixels = ((size_t)width) * height * depth;
+ const size_t num_pixels = width * height * depth;
for (size_t i = num_pixels - 1, pixel = 0; pixel < num_pixels; pixel++, i--) {
float c = util_image_cast_to_float(pixels[i * 4 + 0]);
float m = util_image_cast_to_float(pixels[i * 4 + 1]);
@@ -149,6 +150,16 @@ static void oiio_load_pixels(const ImageMetaData &metadata,
pixels[i * 4 + 3] = one;
}
}
+
+ if (components == 4 && associate_alpha) {
+ size_t dimensions = width * height;
+ for (size_t i = dimensions - 1, pixel = 0; pixel < dimensions; pixel++, i--) {
+ const StorageType alpha = pixels[i * 4 + 3];
+ pixels[i * 4 + 0] = util_image_multiply_native(pixels[i * 4 + 0], alpha);
+ pixels[i * 4 + 1] = util_image_multiply_native(pixels[i * 4 + 1], alpha);
+ pixels[i * 4 + 2] = util_image_multiply_native(pixels[i * 4 + 2], alpha);
+ }
+ }
}
bool OIIOImageLoader::load_pixels(const ImageMetaData &metadata,
@@ -172,33 +183,41 @@ bool OIIOImageLoader::load_pixels(const ImageMetaData &metadata,
ImageSpec spec = ImageSpec();
ImageSpec config = ImageSpec();
- if (!associate_alpha) {
- config.attribute("oiio:UnassociatedAlpha", 1);
- }
+ /* Load without automatic OIIO alpha conversion, we do it ourselves. OIIO
+ * will associate alpha in the the 8bit buffer for PNGs, which leads to too
+ * much precision loss when we load it as half float to do a colorspace
+ * transform. */
+ config.attribute("oiio:UnassociatedAlpha", 1);
if (!in->open(filepath.string(), spec, config)) {
return false;
}
+ const bool do_associate_alpha = associate_alpha &&
+ spec.get_int_attribute("oiio:UnassociatedAlpha", 0);
+
switch (metadata.type) {
case IMAGE_DATA_TYPE_BYTE:
case IMAGE_DATA_TYPE_BYTE4:
- oiio_load_pixels<TypeDesc::UINT8, uchar>(metadata, in, (uchar *)pixels);
+ oiio_load_pixels<TypeDesc::UINT8, uchar>(metadata, in, do_associate_alpha, (uchar *)pixels);
break;
case IMAGE_DATA_TYPE_USHORT:
case IMAGE_DATA_TYPE_USHORT4:
- oiio_load_pixels<TypeDesc::USHORT, uint16_t>(metadata, in, (uint16_t *)pixels);
+ oiio_load_pixels<TypeDesc::USHORT, uint16_t>(
+ metadata, in, do_associate_alpha, (uint16_t *)pixels);
break;
case IMAGE_DATA_TYPE_HALF:
case IMAGE_DATA_TYPE_HALF4:
- oiio_load_pixels<TypeDesc::HALF, half>(metadata, in, (half *)pixels);
+ oiio_load_pixels<TypeDesc::HALF, half>(metadata, in, do_associate_alpha, (half *)pixels);
break;
case IMAGE_DATA_TYPE_FLOAT:
case IMAGE_DATA_TYPE_FLOAT4:
- oiio_load_pixels<TypeDesc::FLOAT, float>(metadata, in, (float *)pixels);
+ oiio_load_pixels<TypeDesc::FLOAT, float>(metadata, in, do_associate_alpha, (float *)pixels);
break;
case IMAGE_DATA_TYPE_NANOVDB_FLOAT:
case IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
+ case IMAGE_DATA_TYPE_NANOVDB_FPN:
+ case IMAGE_DATA_TYPE_NANOVDB_FP16:
case IMAGE_DATA_NUM_TYPES:
break;
}
diff --git a/intern/cycles/scene/image_vdb.cpp b/intern/cycles/scene/image_vdb.cpp
index b6f0911fa2c..2209be60a97 100644
--- a/intern/cycles/scene/image_vdb.cpp
+++ b/intern/cycles/scene/image_vdb.cpp
@@ -44,14 +44,30 @@ struct ToDenseOp {
# ifdef WITH_NANOVDB
struct ToNanoOp {
nanovdb::GridHandle<> nanogrid;
+ int precision;
template<typename GridType, typename FloatGridType, typename FloatDataType, int channels>
bool operator()(const openvdb::GridBase::ConstPtr &grid)
{
if constexpr (!std::is_same_v<GridType, openvdb::MaskGrid>) {
try {
- nanogrid = nanovdb::openToNanoVDB(
- FloatGridType(*openvdb::gridConstPtrCast<GridType>(grid)));
+ FloatGridType floatgrid(*openvdb::gridConstPtrCast<GridType>(grid));
+ if constexpr (std::is_same_v<FloatGridType, openvdb::FloatGrid>) {
+ if (precision == 0) {
+ nanogrid = nanovdb::openToNanoVDB<nanovdb::HostBuffer,
+ typename FloatGridType::TreeType,
+ nanovdb::FpN>(floatgrid);
+ return true;
+ }
+ else if (precision == 16) {
+ nanogrid = nanovdb::openToNanoVDB<nanovdb::HostBuffer,
+ typename FloatGridType::TreeType,
+ nanovdb::Fp16>(floatgrid);
+ return true;
+ }
+ }
+
+ nanogrid = nanovdb::openToNanoVDB(floatgrid);
}
catch (const std::exception &e) {
VLOG(1) << "Error converting OpenVDB to NanoVDB grid: " << e.what();
@@ -98,10 +114,13 @@ bool VDBImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMet
# ifdef WITH_NANOVDB
if (features.has_nanovdb) {
/* NanoVDB expects no inactive leaf nodes. */
- /*openvdb::FloatGrid &pruned_grid = *openvdb::gridPtrCast<openvdb::FloatGrid>(grid);
+# if 0
+ openvdb::FloatGrid &pruned_grid = *openvdb::gridPtrCast<openvdb::FloatGrid>(grid);
openvdb::tools::pruneInactive(pruned_grid.tree());
- nanogrid = nanovdb::openToNanoVDB(pruned_grid);*/
+ nanogrid = nanovdb::openToNanoVDB(pruned_grid);
+# endif
ToNanoOp op;
+ op.precision = precision;
if (!openvdb::grid_type_operation(grid, op)) {
return false;
}
@@ -124,7 +143,15 @@ bool VDBImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMet
if (nanogrid) {
metadata.byte_size = nanogrid.size();
if (metadata.channels == 1) {
- metadata.type = IMAGE_DATA_TYPE_NANOVDB_FLOAT;
+ if (precision == 0) {
+ metadata.type = IMAGE_DATA_TYPE_NANOVDB_FPN;
+ }
+ else if (precision == 16) {
+ metadata.type = IMAGE_DATA_TYPE_NANOVDB_FP16;
+ }
+ else {
+ metadata.type = IMAGE_DATA_TYPE_NANOVDB_FLOAT;
+ }
}
else {
metadata.type = IMAGE_DATA_TYPE_NANOVDB_FLOAT3;
diff --git a/intern/cycles/scene/image_vdb.h b/intern/cycles/scene/image_vdb.h
index a5fd51915ef..ea5f6b0b3d9 100644
--- a/intern/cycles/scene/image_vdb.h
+++ b/intern/cycles/scene/image_vdb.h
@@ -51,6 +51,7 @@ class VDBImageLoader : public ImageLoader {
#endif
#ifdef WITH_NANOVDB
nanovdb::GridHandle<> nanogrid;
+ int precision = 0;
#endif
};
diff --git a/intern/cycles/scene/object.cpp b/intern/cycles/scene/object.cpp
index 8015be6393b..ddd89a16640 100644
--- a/intern/cycles/scene/object.cpp
+++ b/intern/cycles/scene/object.cpp
@@ -327,9 +327,11 @@ float Object::compute_volume_step_size() const
/* Auto detect step size. */
float3 size = one_float3();
#ifdef WITH_NANOVDB
- /* Dimensions were not applied to image transform with NanOVDB (see image_vdb.cpp) */
+ /* Dimensions were not applied to image transform with NanoVDB (see image_vdb.cpp) */
if (metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT &&
- metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3)
+ metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3 &&
+ metadata.type != IMAGE_DATA_TYPE_NANOVDB_FPN &&
+ metadata.type != IMAGE_DATA_TYPE_NANOVDB_FP16)
#endif
size /= make_float3(metadata.width, metadata.height, metadata.depth);
diff --git a/intern/cycles/scene/osl.cpp b/intern/cycles/scene/osl.cpp
index ffa1a2f5623..6698e6e2cce 100644
--- a/intern/cycles/scene/osl.cpp
+++ b/intern/cycles/scene/osl.cpp
@@ -1211,14 +1211,15 @@ void OSLCompiler::parameter_texture(const char *name, ustring filename, ustring
parameter(name, filename);
}
-void OSLCompiler::parameter_texture(const char *name, int svm_slot)
+void OSLCompiler::parameter_texture(const char *name, const ImageHandle &handle)
{
/* Texture loaded through SVM image texture system. We generate a unique
* name, which ends up being used in OSLRenderServices::get_texture_handle
* to get handle again. Note that this name must be unique between multiple
* render sessions as the render services are shared. */
ustring filename(string_printf("@svm%d", texture_shared_unique_id++).c_str());
- services->textures.insert(filename, new OSLTextureHandle(OSLTextureHandle::SVM, svm_slot));
+ services->textures.insert(filename,
+ new OSLTextureHandle(OSLTextureHandle::SVM, handle.get_svm_slots()));
parameter(name, filename);
}
@@ -1290,7 +1291,7 @@ void OSLCompiler::parameter_texture(const char * /* name */,
{
}
-void OSLCompiler::parameter_texture(const char * /* name */, int /* svm_slot */)
+void OSLCompiler::parameter_texture(const char * /* name */, const ImageHandle & /*handle*/)
{
}
diff --git a/intern/cycles/scene/osl.h b/intern/cycles/scene/osl.h
index f0f97dbcaad..bf27069b1b1 100644
--- a/intern/cycles/scene/osl.h
+++ b/intern/cycles/scene/osl.h
@@ -147,7 +147,7 @@ class OSLCompiler {
void parameter_attribute(const char *name, ustring s);
void parameter_texture(const char *name, ustring filename, ustring colorspace);
- void parameter_texture(const char *name, int svm_slot);
+ void parameter_texture(const char *name, const ImageHandle &handle);
void parameter_texture_ies(const char *name, int svm_slot);
ShaderType output_type()
diff --git a/intern/cycles/scene/shader_graph.cpp b/intern/cycles/scene/shader_graph.cpp
index d44e12f5fab..f25d0b7c7b9 100644
--- a/intern/cycles/scene/shader_graph.cpp
+++ b/intern/cycles/scene/shader_graph.cpp
@@ -888,7 +888,7 @@ void ShaderGraph::default_inputs(bool do_osl)
void ShaderGraph::refine_bump_nodes()
{
- /* we transverse the node graph looking for bump nodes, when we find them,
+ /* We transverse the node graph looking for bump nodes, when we find them,
* like in bump_from_displacement(), we copy the sub-graph defined from "bump"
* input to the inputs "center","dx" and "dy" What is in "bump" input is moved
* to "center" input. */
@@ -898,18 +898,18 @@ void ShaderGraph::refine_bump_nodes()
ShaderInput *bump_input = node->input("Height");
ShaderNodeSet nodes_bump;
- /* make 2 extra copies of the subgraph defined in Bump input */
+ /* Make 2 extra copies of the subgraph defined in Bump input. */
ShaderNodeMap nodes_dx;
ShaderNodeMap nodes_dy;
- /* find dependencies for the given input */
+ /* Find dependencies for the given input. */
find_dependencies(nodes_bump, bump_input);
copy_nodes(nodes_bump, nodes_dx);
copy_nodes(nodes_bump, nodes_dy);
- /* mark nodes to indicate they are use for bump computation, so
- that any texture coordinates are shifted by dx/dy when sampling */
+ /* Mark nodes to indicate they are use for bump computation, so
+ * that any texture coordinates are shifted by dx/dy when sampling. */
foreach (ShaderNode *node, nodes_bump)
node->bump = SHADER_BUMP_CENTER;
foreach (NodePair &pair, nodes_dx)
@@ -924,7 +924,7 @@ void ShaderGraph::refine_bump_nodes()
connect(out_dx, node->input("SampleX"));
connect(out_dy, node->input("SampleY"));
- /* add generated nodes */
+ /* Add generated nodes. */
foreach (NodePair &pair, nodes_dx)
add(pair.second);
foreach (NodePair &pair, nodes_dy)
diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp
index dce92dbe4da..3b58556f601 100644
--- a/intern/cycles/scene/shader_nodes.cpp
+++ b/intern/cycles/scene/shader_nodes.cpp
@@ -19,7 +19,6 @@
#include "util/color.h"
#include "util/foreach.h"
#include "util/log.h"
-#include "util/string.h"
#include "util/transform.h"
#include "kernel/tables.h"
@@ -450,22 +449,19 @@ void ImageTextureNode::compile(OSLCompiler &compiler)
const ustring known_colorspace = metadata.colorspace;
if (handle.svm_slot() == -1) {
- /* OIIO currently does not support <UVTILE> substitutions natively. Replace with a format they
- * understand. */
- std::string osl_filename = filename.string();
- string_replace(osl_filename, "<UVTILE>", "<U>_<V>");
compiler.parameter_texture(
- "filename", ustring(osl_filename), compress_as_srgb ? u_colorspace_raw : known_colorspace);
+ "filename", filename, compress_as_srgb ? u_colorspace_raw : known_colorspace);
}
else {
- compiler.parameter_texture("filename", handle.svm_slot());
+ compiler.parameter_texture("filename", handle);
}
const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) ||
alpha_type == IMAGE_ALPHA_CHANNEL_PACKED ||
alpha_type == IMAGE_ALPHA_IGNORE);
const bool is_tiled = (filename.find("<UDIM>") != string::npos ||
- filename.find("<UVTILE>") != string::npos);
+ filename.find("<UVTILE>") != string::npos) ||
+ handle.num_tiles() > 1;
compiler.parameter(this, "projection");
compiler.parameter(this, "projection_blend");
@@ -610,7 +606,7 @@ void EnvironmentTextureNode::compile(OSLCompiler &compiler)
"filename", filename, compress_as_srgb ? u_colorspace_raw : known_colorspace);
}
else {
- compiler.parameter_texture("filename", handle.svm_slot());
+ compiler.parameter_texture("filename", handle);
}
compiler.parameter(this, "projection");
@@ -965,7 +961,7 @@ void SkyTextureNode::compile(OSLCompiler &compiler)
compiler.parameter_array("nishita_data", sunsky.nishita_data, 10);
/* nishita texture */
if (sky_type == NODE_SKY_NISHITA) {
- compiler.parameter_texture("filename", handle.svm_slot());
+ compiler.parameter_texture("filename", handle);
}
compiler.add(this, "node_sky_texture");
}
@@ -1860,7 +1856,7 @@ void PointDensityTextureNode::compile(OSLCompiler &compiler)
handle = image_manager->add_image(filename.string(), image_params());
}
- compiler.parameter_texture("filename", handle.svm_slot());
+ compiler.parameter_texture("filename", handle);
if (space == NODE_TEX_VOXEL_SPACE_WORLD) {
compiler.parameter("mapping", tfm);
compiler.parameter("use_mapping", 1);
@@ -5010,6 +5006,63 @@ void MixNode::constant_fold(const ConstantFolder &folder)
}
}
+/* Combine Color */
+
+NODE_DEFINE(CombineColorNode)
+{
+ NodeType *type = NodeType::add("combine_color", create, NodeType::SHADER);
+
+ static NodeEnum type_enum;
+ type_enum.insert("rgb", NODE_COMBSEP_COLOR_RGB);
+ type_enum.insert("hsv", NODE_COMBSEP_COLOR_HSV);
+ type_enum.insert("hsl", NODE_COMBSEP_COLOR_HSL);
+ SOCKET_ENUM(color_type, "Type", type_enum, NODE_COMBSEP_COLOR_RGB);
+
+ SOCKET_IN_FLOAT(r, "Red", 0.0f);
+ SOCKET_IN_FLOAT(g, "Green", 0.0f);
+ SOCKET_IN_FLOAT(b, "Blue", 0.0f);
+
+ SOCKET_OUT_COLOR(color, "Color");
+
+ return type;
+}
+
+CombineColorNode::CombineColorNode() : ShaderNode(get_node_type())
+{
+}
+
+void CombineColorNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ folder.make_constant(svm_combine_color(color_type, make_float3(r, g, b)));
+ }
+}
+
+void CombineColorNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *red_in = input("Red");
+ ShaderInput *green_in = input("Green");
+ ShaderInput *blue_in = input("Blue");
+ ShaderOutput *color_out = output("Color");
+
+ int red_stack_offset = compiler.stack_assign(red_in);
+ int green_stack_offset = compiler.stack_assign(green_in);
+ int blue_stack_offset = compiler.stack_assign(blue_in);
+ int color_stack_offset = compiler.stack_assign(color_out);
+
+ compiler.add_node(
+ NODE_COMBINE_COLOR,
+ color_type,
+ compiler.encode_uchar4(red_stack_offset, green_stack_offset, blue_stack_offset),
+ color_stack_offset);
+}
+
+void CombineColorNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "color_type");
+ compiler.add(this, "node_combine_color");
+}
+
/* Combine RGB */
NODE_DEFINE(CombineRGBNode)
@@ -5250,6 +5303,70 @@ void BrightContrastNode::compile(OSLCompiler &compiler)
compiler.add(this, "node_brightness");
}
+/* Separate Color */
+
+NODE_DEFINE(SeparateColorNode)
+{
+ NodeType *type = NodeType::add("separate_color", create, NodeType::SHADER);
+
+ static NodeEnum type_enum;
+ type_enum.insert("rgb", NODE_COMBSEP_COLOR_RGB);
+ type_enum.insert("hsv", NODE_COMBSEP_COLOR_HSV);
+ type_enum.insert("hsl", NODE_COMBSEP_COLOR_HSL);
+ SOCKET_ENUM(color_type, "Type", type_enum, NODE_COMBSEP_COLOR_RGB);
+
+ SOCKET_IN_COLOR(color, "Color", zero_float3());
+
+ SOCKET_OUT_FLOAT(r, "Red");
+ SOCKET_OUT_FLOAT(g, "Green");
+ SOCKET_OUT_FLOAT(b, "Blue");
+
+ return type;
+}
+
+SeparateColorNode::SeparateColorNode() : ShaderNode(get_node_type())
+{
+}
+
+void SeparateColorNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ float3 col = svm_separate_color(color_type, color);
+
+ for (int channel = 0; channel < 3; channel++) {
+ if (outputs[channel] == folder.output) {
+ folder.make_constant(col[channel]);
+ return;
+ }
+ }
+ }
+}
+
+void SeparateColorNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *color_in = input("Color");
+ ShaderOutput *red_out = output("Red");
+ ShaderOutput *green_out = output("Green");
+ ShaderOutput *blue_out = output("Blue");
+
+ int color_stack_offset = compiler.stack_assign(color_in);
+ int red_stack_offset = compiler.stack_assign(red_out);
+ int green_stack_offset = compiler.stack_assign(green_out);
+ int blue_stack_offset = compiler.stack_assign(blue_out);
+
+ compiler.add_node(
+ NODE_SEPARATE_COLOR,
+ color_type,
+ color_stack_offset,
+ compiler.encode_uchar4(red_stack_offset, green_stack_offset, blue_stack_offset));
+}
+
+void SeparateColorNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "color_type");
+ compiler.add(this, "node_separate_color");
+}
+
/* Separate RGB */
NODE_DEFINE(SeparateRGBNode)
diff --git a/intern/cycles/scene/shader_nodes.h b/intern/cycles/scene/shader_nodes.h
index 9aef5d3151f..ac40a397c1e 100644
--- a/intern/cycles/scene/shader_nodes.h
+++ b/intern/cycles/scene/shader_nodes.h
@@ -1101,6 +1101,17 @@ class MixNode : public ShaderNode {
NODE_SOCKET_API(float, fac)
};
+class CombineColorNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(CombineColorNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(NodeCombSepColorType, color_type)
+ NODE_SOCKET_API(float, r)
+ NODE_SOCKET_API(float, g)
+ NODE_SOCKET_API(float, b)
+};
+
class CombineRGBNode : public ShaderNode {
public:
SHADER_NODE_CLASS(CombineRGBNode)
@@ -1150,6 +1161,15 @@ class BrightContrastNode : public ShaderNode {
NODE_SOCKET_API(float, contrast)
};
+class SeparateColorNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(SeparateColorNode)
+ void constant_fold(const ConstantFolder &folder);
+
+ NODE_SOCKET_API(NodeCombSepColorType, color_type)
+ NODE_SOCKET_API(float3, color)
+};
+
class SeparateRGBNode : public ShaderNode {
public:
SHADER_NODE_CLASS(SeparateRGBNode)
diff --git a/intern/cycles/util/color.h b/intern/cycles/util/color.h
index cccccde3ba6..795c3754976 100644
--- a/intern/cycles/util/color.h
+++ b/intern/cycles/util/color.h
@@ -152,6 +152,56 @@ ccl_device float3 hsv_to_rgb(float3 hsv)
return rgb;
}
+ccl_device float3 rgb_to_hsl(float3 rgb)
+{
+ float cmax, cmin, h, s, l;
+
+ cmax = fmaxf(rgb.x, fmaxf(rgb.y, rgb.z));
+ cmin = min(rgb.x, min(rgb.y, rgb.z));
+ l = min(1.0f, (cmax + cmin) / 2.0f);
+
+ if (cmax == cmin) {
+ h = s = 0.0f; /* achromatic */
+ }
+ else {
+ float cdelta = cmax - cmin;
+ s = l > 0.5f ? cdelta / (2.0f - cmax - cmin) : cdelta / (cmax + cmin);
+ if (cmax == rgb.x) {
+ h = (rgb.y - rgb.z) / cdelta + (rgb.y < rgb.z ? 6.0f : 0.0f);
+ }
+ else if (cmax == rgb.y) {
+ h = (rgb.z - rgb.x) / cdelta + 2.0f;
+ }
+ else {
+ h = (rgb.x - rgb.y) / cdelta + 4.0f;
+ }
+ }
+ h /= 6.0f;
+
+ return make_float3(h, s, l);
+}
+
+ccl_device float3 hsl_to_rgb(float3 hsl)
+{
+ float nr, ng, nb, chroma, h, s, l;
+
+ h = hsl.x;
+ s = hsl.y;
+ l = hsl.z;
+
+ nr = fabsf(h * 6.0f - 3.0f) - 1.0f;
+ ng = 2.0f - fabsf(h * 6.0f - 2.0f);
+ nb = 2.0f - fabsf(h * 6.0f - 4.0f);
+
+ nr = clamp(nr, 0.0f, 1.0f);
+ nb = clamp(nb, 0.0f, 1.0f);
+ ng = clamp(ng, 0.0f, 1.0f);
+
+ chroma = (1.0f - fabsf(2.0f * l - 1.0f)) * s;
+
+ return make_float3((nr - 0.5f) * chroma + l, (ng - 0.5f) * chroma + l, (nb - 0.5f) * chroma + l);
+}
+
ccl_device float3 xyY_to_xyz(float x, float y, float Y)
{
float X, Z;
diff --git a/intern/cycles/util/image.h b/intern/cycles/util/image.h
index 9348125d072..17446a83e59 100644
--- a/intern/cycles/util/image.h
+++ b/intern/cycles/util/image.h
@@ -78,6 +78,26 @@ template<> inline half util_image_cast_from_float(float value)
return float_to_half_image(value);
}
+/* Multiply image pixels in native data format. */
+template<typename T> inline T util_image_multiply_native(T a, T b);
+
+template<> inline float util_image_multiply_native(float a, float b)
+{
+ return a * b;
+}
+template<> inline uchar util_image_multiply_native(uchar a, uchar b)
+{
+ return ((uint32_t)a * (uint32_t)b) / 255;
+}
+template<> inline uint16_t util_image_multiply_native(uint16_t a, uint16_t b)
+{
+ return ((uint32_t)a * (uint32_t)b) / 65535;
+}
+template<> inline half util_image_multiply_native(half a, half b)
+{
+ return float_to_half_image(half_to_float_image(a) * half_to_float_image(b));
+}
+
CCL_NAMESPACE_END
#endif /* __UTIL_IMAGE_H__ */
diff --git a/intern/cycles/util/texture.h b/intern/cycles/util/texture.h
index e8bb058a3c9..90e842933c2 100644
--- a/intern/cycles/util/texture.h
+++ b/intern/cycles/util/texture.h
@@ -37,6 +37,8 @@ typedef enum ImageDataType {
IMAGE_DATA_TYPE_USHORT = 7,
IMAGE_DATA_TYPE_NANOVDB_FLOAT = 8,
IMAGE_DATA_TYPE_NANOVDB_FLOAT3 = 9,
+ IMAGE_DATA_TYPE_NANOVDB_FPN = 10,
+ IMAGE_DATA_TYPE_NANOVDB_FP16 = 11,
IMAGE_DATA_NUM_TYPES
} ImageDataType;
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index 9421edecf12..dceb9ced803 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -376,6 +376,7 @@ elseif(WIN32)
intern/GHOST_DisplayManagerWin32.cpp
intern/GHOST_DropTargetWin32.cpp
intern/GHOST_SystemWin32.cpp
+ intern/GHOST_TrackpadWin32.cpp
intern/GHOST_WindowWin32.cpp
intern/GHOST_Wintab.cpp
@@ -384,6 +385,7 @@ elseif(WIN32)
intern/GHOST_DropTargetWin32.h
intern/GHOST_SystemWin32.h
intern/GHOST_TaskbarWin32.h
+ intern/GHOST_TrackpadWin32.h
intern/GHOST_WindowWin32.h
intern/GHOST_Wintab.h
)
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index ec641938f1f..ae749eb3b8c 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -414,7 +414,7 @@ extern GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle,
*/
extern GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle,
GHOST_TGrabCursorMode mode,
- GHOST_TAxisFlag warp_axis,
+ GHOST_TAxisFlag wrap_axis,
int bounds[4],
const int mouse_ungrab_xy[2]);
@@ -727,7 +727,7 @@ extern unsigned int GHOST_GetContextDefaultOpenGLFramebuffer(GHOST_ContextHandle
/**
* Get the OpenGL frame-buffer handle that serves as a default frame-buffer.
*/
-extern unsigned int GHOST_GetDefaultOpenGLFramebuffer(GHOST_WindowHandle windwHandle);
+extern unsigned int GHOST_GetDefaultOpenGLFramebuffer(GHOST_WindowHandle windowhandle);
/**
* Set which tablet API to use. Only affects Windows, other platforms have a single API.
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 85913fbd10c..e2ed9830e4e 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -521,7 +521,7 @@ typedef struct {
} GHOST_TEventNDOFMotionData;
typedef enum { GHOST_kPress, GHOST_kRelease } GHOST_TButtonAction;
-/* Good for mouse or other buttons too, hmmm? */
+/* Good for mouse or other buttons too? */
typedef struct {
GHOST_TButtonAction action;
diff --git a/intern/ghost/intern/GHOST_Buttons.cpp b/intern/ghost/intern/GHOST_Buttons.cpp
index c948c7beadb..3367d256325 100644
--- a/intern/ghost/intern/GHOST_Buttons.cpp
+++ b/intern/ghost/intern/GHOST_Buttons.cpp
@@ -21,6 +21,14 @@ bool GHOST_Buttons::get(GHOST_TButtonMask mask) const
return m_ButtonMiddle;
case GHOST_kButtonMaskRight:
return m_ButtonRight;
+ case GHOST_kButtonMaskButton4:
+ return m_Button4;
+ case GHOST_kButtonMaskButton5:
+ return m_Button5;
+ case GHOST_kButtonMaskButton6:
+ return m_Button6;
+ case GHOST_kButtonMaskButton7:
+ return m_Button7;
default:
return false;
}
@@ -38,6 +46,18 @@ void GHOST_Buttons::set(GHOST_TButtonMask mask, bool down)
case GHOST_kButtonMaskRight:
m_ButtonRight = down;
break;
+ case GHOST_kButtonMaskButton4:
+ m_Button4 = down;
+ break;
+ case GHOST_kButtonMaskButton5:
+ m_Button5 = down;
+ break;
+ case GHOST_kButtonMaskButton6:
+ m_Button6 = down;
+ break;
+ case GHOST_kButtonMaskButton7:
+ m_Button7 = down;
+ break;
default:
break;
}
@@ -48,6 +68,10 @@ void GHOST_Buttons::clear()
m_ButtonLeft = false;
m_ButtonMiddle = false;
m_ButtonRight = false;
+ m_Button4 = false;
+ m_Button5 = false;
+ m_Button6 = false;
+ m_Button7 = false;
}
GHOST_Buttons::~GHOST_Buttons()
diff --git a/intern/ghost/intern/GHOST_Buttons.h b/intern/ghost/intern/GHOST_Buttons.h
index 17f25f1e082..72cb17a3322 100644
--- a/intern/ghost/intern/GHOST_Buttons.h
+++ b/intern/ghost/intern/GHOST_Buttons.h
@@ -44,4 +44,8 @@ struct GHOST_Buttons {
uint8_t m_ButtonLeft : 1;
uint8_t m_ButtonMiddle : 1;
uint8_t m_ButtonRight : 1;
+ uint8_t m_Button4 : 1;
+ uint8_t m_Button5 : 1;
+ uint8_t m_Button6 : 1;
+ uint8_t m_Button7 : 1;
};
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index 93e94893162..9374d087408 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -7,8 +7,8 @@
* C Api for GHOST
*/
-#include <stdlib.h>
-#include <string.h>
+#include <cstdlib>
+#include <cstring>
#include "GHOST_C-api.h"
#include "GHOST_IEvent.h"
@@ -206,13 +206,15 @@ GHOST_WindowHandle GHOST_BeginFullScreen(GHOST_SystemHandle systemhandle,
const int stereoVisual)
{
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
- GHOST_IWindow *window = NULL;
+ GHOST_IWindow *window = nullptr;
bool bstereoVisual;
- if (stereoVisual)
+ if (stereoVisual) {
bstereoVisual = true;
- else
+ }
+ else {
bstereoVisual = false;
+ }
system->beginFullScreen(*setting, &window, bstereoVisual);
@@ -371,7 +373,7 @@ GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle,
}
return window->setCursorGrab(
- mode, wrap_axis, bounds ? &bounds_rect : NULL, mouse_ungrab_xy ? mouse_xy : NULL);
+ mode, wrap_axis, bounds ? &bounds_rect : nullptr, mouse_ungrab_xy ? mouse_xy : nullptr);
}
GHOST_TSuccess GHOST_GetModifierKeyState(GHOST_SystemHandle systemhandle,
@@ -509,8 +511,8 @@ char *GHOST_GetTitle(GHOST_WindowHandle windowhandle)
char *ctitle = (char *)malloc(title.size() + 1);
- if (ctitle == NULL) {
- return NULL;
+ if (ctitle == nullptr) {
+ return nullptr;
}
strcpy(ctitle, title.c_str());
@@ -521,7 +523,7 @@ char *GHOST_GetTitle(GHOST_WindowHandle windowhandle)
GHOST_RectangleHandle GHOST_GetWindowBounds(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
- GHOST_Rect *rectangle = NULL;
+ GHOST_Rect *rectangle = nullptr;
rectangle = new GHOST_Rect();
window->getWindowBounds(*rectangle);
@@ -532,7 +534,7 @@ GHOST_RectangleHandle GHOST_GetWindowBounds(GHOST_WindowHandle windowhandle)
GHOST_RectangleHandle GHOST_GetClientBounds(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
- GHOST_Rect *rectangle = NULL;
+ GHOST_Rect *rectangle = nullptr;
rectangle = new GHOST_Rect();
window->getClientBounds(*rectangle);
@@ -646,10 +648,8 @@ GHOST_TSuccess GHOST_ActivateOpenGLContext(GHOST_ContextHandle contexthandle)
if (context) {
return context->activateDrawingContext();
}
- else {
- GHOST_PRINTF("%s: Context not valid\n", __func__);
- return GHOST_kFailure;
- }
+ GHOST_PRINTF("%s: Context not valid\n", __func__);
+ return GHOST_kFailure;
}
GHOST_TSuccess GHOST_ReleaseOpenGLContext(GHOST_ContextHandle contexthandle)
@@ -717,9 +717,9 @@ GHOST_TSuccess GHOST_IsEmptyRectangle(GHOST_RectangleHandle rectanglehandle)
{
GHOST_TSuccess result = GHOST_kFailure;
- if (((GHOST_Rect *)rectanglehandle)->isEmpty())
+ if (((GHOST_Rect *)rectanglehandle)->isEmpty()) {
result = GHOST_kSuccess;
-
+ }
return result;
}
@@ -727,9 +727,9 @@ GHOST_TSuccess GHOST_IsValidRectangle(GHOST_RectangleHandle rectanglehandle)
{
GHOST_TSuccess result = GHOST_kFailure;
- if (((GHOST_Rect *)rectanglehandle)->isValid())
+ if (((GHOST_Rect *)rectanglehandle)->isValid()) {
result = GHOST_kSuccess;
-
+ }
return result;
}
@@ -753,9 +753,9 @@ GHOST_TSuccess GHOST_IsInsideRectangle(GHOST_RectangleHandle rectanglehandle, in
{
GHOST_TSuccess result = GHOST_kFailure;
- if (((GHOST_Rect *)rectanglehandle)->isInside(x, y))
+ if (((GHOST_Rect *)rectanglehandle)->isInside(x, y)) {
result = GHOST_kSuccess;
-
+ }
return result;
}
@@ -785,9 +785,9 @@ GHOST_TSuccess GHOST_ClipRectangle(GHOST_RectangleHandle rectanglehandle,
{
GHOST_TSuccess result = GHOST_kFailure;
- if (((GHOST_Rect *)rectanglehandle)->clip(*(GHOST_Rect *)anotherrectanglehandle))
+ if (((GHOST_Rect *)rectanglehandle)->clip(*(GHOST_Rect *)anotherrectanglehandle)) {
result = GHOST_kSuccess;
-
+ }
return result;
}
@@ -824,8 +824,9 @@ void GHOST_UseWindowFocus(int use_focus)
float GHOST_GetNativePixelSize(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
- if (window)
+ if (window) {
return window->getNativePixelSize();
+ }
return 1.0f;
}
diff --git a/intern/ghost/intern/GHOST_ContextEGL.cpp b/intern/ghost/intern/GHOST_ContextEGL.cpp
index a2b58106f0d..8c44dfe0158 100644
--- a/intern/ghost/intern/GHOST_ContextEGL.cpp
+++ b/intern/ghost/intern/GHOST_ContextEGL.cpp
@@ -40,7 +40,7 @@ static const char *get_egl_error_enum_string(EGLint error)
CASE_CODE_RETURN_STR(EGL_BAD_NATIVE_WINDOW)
CASE_CODE_RETURN_STR(EGL_CONTEXT_LOST)
default:
- return NULL;
+ return nullptr;
}
}
@@ -106,11 +106,14 @@ static const char *get_egl_error_message_string(EGLint error)
"and objects to continue rendering.");
default:
- return NULL;
+ return nullptr;
}
}
-static bool egl_chk(bool result, const char *file = NULL, int line = 0, const char *text = NULL)
+static bool egl_chk(bool result,
+ const char *file = nullptr,
+ int line = 0,
+ const char *text = nullptr)
{
if (!result) {
const EGLint error = eglGetError();
@@ -158,7 +161,7 @@ static inline bool bindAPI(EGLenum api)
}
#ifdef WITH_GL_ANGLE
-HMODULE GHOST_ContextEGL::s_d3dcompiler = NULL;
+HMODULE GHOST_ContextEGL::s_d3dcompiler = nullptr;
#endif
EGLContext GHOST_ContextEGL::s_gl_sharedContext = EGL_NO_CONTEXT;
@@ -170,7 +173,9 @@ EGLint GHOST_ContextEGL::s_gles_sharedCount = 0;
EGLContext GHOST_ContextEGL::s_vg_sharedContext = EGL_NO_CONTEXT;
EGLint GHOST_ContextEGL::s_vg_sharedCount = 0;
-#pragma warning(disable : 4715)
+#ifdef _MSC_VER
+# pragma warning(disable : 4715)
+#endif
template<typename T> T &choose_api(EGLenum api, T &a, T &b, T &c)
{
@@ -223,23 +228,24 @@ GHOST_ContextEGL::~GHOST_ContextEGL()
bindAPI(m_api);
if (m_context != EGL_NO_CONTEXT) {
- if (m_context == ::eglGetCurrentContext())
+ if (m_context == ::eglGetCurrentContext()) {
EGL_CHK(::eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
-
+ }
if (m_context != m_sharedContext || m_sharedCount == 1) {
assert(m_sharedCount > 0);
m_sharedCount--;
- if (m_sharedCount == 0)
+ if (m_sharedCount == 0) {
m_sharedContext = EGL_NO_CONTEXT;
-
+ }
EGL_CHK(::eglDestroyContext(m_display, m_context));
}
}
- if (m_surface != EGL_NO_SURFACE)
+ if (m_surface != EGL_NO_SURFACE) {
EGL_CHK(::eglDestroySurface(m_display, m_surface));
+ }
}
}
@@ -256,13 +262,9 @@ GHOST_TSuccess GHOST_ContextEGL::setSwapInterval(int interval)
return GHOST_kSuccess;
}
- else {
- return GHOST_kFailure;
- }
- }
- else {
return GHOST_kFailure;
}
+ return GHOST_kFailure;
}
GHOST_TSuccess GHOST_ContextEGL::getSwapInterval(int &intervalOut)
@@ -293,13 +295,10 @@ GHOST_TSuccess GHOST_ContextEGL::activateDrawingContext()
{
if (m_display) {
bindAPI(m_api);
-
return EGL_CHK(::eglMakeCurrent(m_display, m_surface, m_surface, m_context)) ? GHOST_kSuccess :
GHOST_kFailure;
}
- else {
- return GHOST_kFailure;
- }
+ return GHOST_kFailure;
}
GHOST_TSuccess GHOST_ContextEGL::releaseDrawingContext()
@@ -311,9 +310,7 @@ GHOST_TSuccess GHOST_ContextEGL::releaseDrawingContext()
GHOST_kSuccess :
GHOST_kFailure;
}
- else {
- return GHOST_kFailure;
- }
+ return GHOST_kFailure;
}
bool GHOST_ContextEGL::initContextEGLEW()
@@ -322,7 +319,7 @@ bool GHOST_ContextEGL::initContextEGLEW()
* it requires a display argument. glewInit() does the same, but we only want
* to initialize EGLEW here. */
eglGetDisplay = (PFNEGLGETDISPLAYPROC)eglGetProcAddress("eglGetDisplay");
- if (eglGetDisplay == NULL) {
+ if (eglGetDisplay == nullptr) {
return false;
}
@@ -353,9 +350,9 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
std::vector<EGLint> attrib_list;
EGLint num_config = 0;
- if (m_stereoVisual)
+ if (m_stereoVisual) {
fprintf(stderr, "Warning! Stereo OpenGL ES contexts are not supported.\n");
-
+ }
m_stereoVisual = false; /* It doesn't matter what the Window wants. */
if (!initContextEGLEW()) {
@@ -364,12 +361,12 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
#ifdef WITH_GL_ANGLE
/* `d3dcompiler_XX.dll` needs to be loaded before ANGLE will work. */
- if (s_d3dcompiler == NULL) {
+ if (s_d3dcompiler == nullptr) {
s_d3dcompiler = LoadLibrary(D3DCOMPILER);
- WIN32_CHK(s_d3dcompiler != NULL);
+ WIN32_CHK(s_d3dcompiler != nullptr);
- if (s_d3dcompiler == NULL) {
+ if (s_d3dcompiler == nullptr) {
fprintf(stderr, "LoadLibrary(\"" D3DCOMPILER "\") failed!\n");
return GHOST_kFailure;
}
@@ -383,18 +380,19 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
EGLint egl_major, egl_minor;
- if (!EGL_CHK(::eglInitialize(m_display, &egl_major, &egl_minor)))
+ if (!EGL_CHK(::eglInitialize(m_display, &egl_major, &egl_minor))) {
goto error;
-
+ }
#ifdef WITH_GHOST_DEBUG
fprintf(stderr, "EGL Version %d.%d\n", egl_major, egl_minor);
#endif
- if (!EGL_CHK(::eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)))
+ if (!EGL_CHK(::eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))) {
goto error;
-
- if (!bindAPI(m_api))
+ }
+ if (!bindAPI(m_api)) {
goto error;
+ }
/* Build attribute list. */
@@ -462,15 +460,17 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
attrib_list.push_back(EGL_NONE);
- if (!EGL_CHK(::eglChooseConfig(m_display, &(attrib_list[0]), &m_config, 1, &num_config)))
+ if (!EGL_CHK(::eglChooseConfig(m_display, &(attrib_list[0]), &m_config, 1, &num_config))) {
goto error;
+ }
/* A common error is to assume that ChooseConfig worked because it returned EGL_TRUE. */
- if (num_config != 1) /* `num_config` should be exactly 1. */
+ if (num_config != 1) { /* `num_config` should be exactly 1. */
goto error;
+ }
if (m_nativeWindow != 0) {
- m_surface = ::eglCreateWindowSurface(m_display, m_config, m_nativeWindow, NULL);
+ m_surface = ::eglCreateWindowSurface(m_display, m_config, m_nativeWindow, nullptr);
}
else {
static const EGLint pb_attrib_list[] = {
@@ -483,9 +483,9 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
m_surface = ::eglCreatePbufferSurface(m_display, m_config, pb_attrib_list);
}
- if (!EGL_CHK(m_surface != EGL_NO_SURFACE))
+ if (!EGL_CHK(m_surface != EGL_NO_SURFACE)) {
goto error;
-
+ }
attrib_list.clear();
if (EGLEW_VERSION_1_5 || EGLEW_KHR_create_context) {
@@ -524,9 +524,10 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
}
}
else {
- if (m_contextProfileMask != 0)
+ if (m_contextProfileMask != 0) {
fprintf(
stderr, "Warning! Cannot select profile for %s contexts.", api_string(m_api).c_str());
+ }
}
if (m_api == EGL_OPENGL_API || EGLEW_VERSION_1_5) {
@@ -583,16 +584,19 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
m_context = ::eglCreateContext(m_display, m_config, m_sharedContext, &(attrib_list[0]));
- if (!EGL_CHK(m_context != EGL_NO_CONTEXT))
+ if (!EGL_CHK(m_context != EGL_NO_CONTEXT)) {
goto error;
+ }
- if (m_sharedContext == EGL_NO_CONTEXT)
+ if (m_sharedContext == EGL_NO_CONTEXT) {
m_sharedContext = m_context;
+ }
m_sharedCount++;
- if (!EGL_CHK(::eglMakeCurrent(m_display, m_surface, m_surface, m_context)))
+ if (!EGL_CHK(::eglMakeCurrent(m_display, m_surface, m_surface, m_context))) {
goto error;
+ }
initContextGLEW();
@@ -602,16 +606,16 @@ GHOST_TSuccess GHOST_ContextEGL::initializeDrawingContext()
return GHOST_kSuccess;
error:
- if (prev_display != EGL_NO_DISPLAY)
+ if (prev_display != EGL_NO_DISPLAY) {
EGL_CHK(eglMakeCurrent(prev_display, prev_draw, prev_read, prev_context));
-
+ }
return GHOST_kFailure;
}
GHOST_TSuccess GHOST_ContextEGL::releaseNativeHandles()
{
m_nativeWindow = 0;
- m_nativeDisplay = NULL;
+ m_nativeDisplay = nullptr;
return GHOST_kSuccess;
}
diff --git a/intern/ghost/intern/GHOST_ContextGLX.cpp b/intern/ghost/intern/GHOST_ContextGLX.cpp
index b7d613645dc..baabdc6c521 100644
--- a/intern/ghost/intern/GHOST_ContextGLX.cpp
+++ b/intern/ghost/intern/GHOST_ContextGLX.cpp
@@ -47,23 +47,24 @@ GHOST_ContextGLX::GHOST_ContextGLX(bool stereoVisual,
m_contextResetNotificationStrategy(contextResetNotificationStrategy),
m_context(None)
{
- assert(m_display != NULL);
+ assert(m_display != nullptr);
}
GHOST_ContextGLX::~GHOST_ContextGLX()
{
- if (m_display != NULL) {
+ if (m_display != nullptr) {
if (m_context != None) {
- if (m_window != 0 && m_context == ::glXGetCurrentContext())
- ::glXMakeCurrent(m_display, None, NULL);
-
+ if (m_window != 0 && m_context == ::glXGetCurrentContext()) {
+ ::glXMakeCurrent(m_display, None, nullptr);
+ }
if (m_context != s_sharedContext || s_sharedCount == 1) {
assert(s_sharedCount > 0);
s_sharedCount--;
- if (s_sharedCount == 0)
- s_sharedContext = NULL;
+ if (s_sharedCount == 0) {
+ s_sharedContext = nullptr;
+ }
::glXDestroyContext(m_display, m_context);
}
@@ -80,22 +81,18 @@ GHOST_TSuccess GHOST_ContextGLX::swapBuffers()
GHOST_TSuccess GHOST_ContextGLX::activateDrawingContext()
{
- if (m_display) {
- return ::glXMakeCurrent(m_display, m_window, m_context) ? GHOST_kSuccess : GHOST_kFailure;
- }
- else {
+ if (m_display == nullptr) {
return GHOST_kFailure;
}
+ return ::glXMakeCurrent(m_display, m_window, m_context) ? GHOST_kSuccess : GHOST_kFailure;
}
GHOST_TSuccess GHOST_ContextGLX::releaseDrawingContext()
{
- if (m_display) {
- return ::glXMakeCurrent(m_display, None, NULL) ? GHOST_kSuccess : GHOST_kFailure;
- }
- else {
+ if (m_display == nullptr) {
return GHOST_kFailure;
}
+ return ::glXMakeCurrent(m_display, None, nullptr) ? GHOST_kSuccess : GHOST_kFailure;
}
void GHOST_ContextGLX::initContextGLXEW()
@@ -113,15 +110,15 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
#ifdef USE_GLXEW_INIT_WORKAROUND
const GLubyte *extStart = (GLubyte *)"";
const GLubyte *extEnd;
- if (glXQueryExtension(m_display, NULL, NULL)) {
+ if (glXQueryExtension(m_display, nullptr, nullptr)) {
extStart = (const GLubyte *)glXGetClientString(m_display, GLX_EXTENSIONS);
- if ((extStart == NULL) ||
+ if ((extStart == nullptr) ||
(glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)glXGetProcAddressARB(
- (const GLubyte *)"glXChooseFBConfig")) == NULL ||
+ (const GLubyte *)"glXChooseFBConfig")) == nullptr ||
(glXCreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddressARB(
- (const GLubyte *)"glXCreateContextAttribsARB")) == NULL ||
+ (const GLubyte *)"glXCreateContextAttribsARB")) == nullptr ||
(glXCreatePbuffer = (PFNGLXCREATEPBUFFERPROC)glXGetProcAddressARB(
- (const GLubyte *)"glXCreatePbuffer")) == NULL) {
+ (const GLubyte *)"glXCreatePbuffer")) == nullptr) {
extStart = (GLubyte *)"";
}
}
@@ -161,11 +158,12 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
int profileBitES = m_contextProfileMask & GLX_CONTEXT_ES_PROFILE_BIT_EXT;
#endif
- if (!GLXEW_ARB_create_context_profile && profileBitCore)
+ if (!GLXEW_ARB_create_context_profile && profileBitCore) {
fprintf(stderr, "Warning! OpenGL core profile not available.\n");
-
- if (!GLXEW_ARB_create_context_profile && profileBitCompat)
+ }
+ if (!GLXEW_ARB_create_context_profile && profileBitCompat) {
fprintf(stderr, "Warning! OpenGL compatibility profile not available.\n");
+ }
#ifdef WITH_GLEW_ES
if (!GLXEW_EXT_create_context_es_profile && profileBitES && m_contextMajorVersion == 1)
@@ -177,20 +175,21 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
int profileMask = 0;
- if (GLXEW_ARB_create_context_profile && profileBitCore)
+ if (GLXEW_ARB_create_context_profile && profileBitCore) {
profileMask |= profileBitCore;
-
- if (GLXEW_ARB_create_context_profile && profileBitCompat)
+ }
+ if (GLXEW_ARB_create_context_profile && profileBitCompat) {
profileMask |= profileBitCompat;
+ }
#ifdef WITH_GLEW_ES
if (GLXEW_EXT_create_context_es_profile && profileBitES)
profileMask |= profileBitES;
#endif
- if (profileMask != m_contextProfileMask)
+ if (profileMask != m_contextProfileMask) {
fprintf(stderr, "Warning! Ignoring untested OpenGL context profile mask bits.");
-
+ }
/* max 10 attributes plus terminator */
int attribs[11];
int i = 0;
@@ -238,7 +237,7 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
}
}
else {
- GLXFBConfig *framebuffer_config = NULL;
+ GLXFBConfig *framebuffer_config = nullptr;
{
int glx_attribs[64];
int fbcount = 0;
@@ -269,12 +268,12 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
GHOST_TSuccess success;
- if (m_context != NULL) {
+ if (m_context != nullptr) {
const unsigned char *version;
- if (!s_sharedContext)
+ if (!s_sharedContext) {
s_sharedContext = m_context;
-
+ }
s_sharedCount++;
glXMakeCurrent(m_display, m_window, m_context);
@@ -319,14 +318,11 @@ GHOST_TSuccess GHOST_ContextGLX::releaseNativeHandles()
GHOST_TSuccess GHOST_ContextGLX::setSwapInterval(int interval)
{
- if (GLXEW_EXT_swap_control) {
+ if (!GLXEW_EXT_swap_control) {
::glXSwapIntervalEXT(m_display, m_window, interval);
-
return GHOST_kSuccess;
}
- else {
- return GHOST_kFailure;
- }
+ return GHOST_kFailure;
}
GHOST_TSuccess GHOST_ContextGLX::getSwapInterval(int &intervalOut)
@@ -340,9 +336,7 @@ GHOST_TSuccess GHOST_ContextGLX::getSwapInterval(int &intervalOut)
return GHOST_kSuccess;
}
- else {
- return GHOST_kFailure;
- }
+ return GHOST_kFailure;
}
/**
@@ -406,30 +400,36 @@ int GHOST_X11_GL_GetAttributes(
static GLuint _glewStrLen(const GLubyte *s)
{
GLuint i = 0;
- if (s == NULL)
+ if (s == nullptr) {
return 0;
- while (s[i] != '\0')
+ }
+ while (s[i] != '\0') {
i++;
+ }
return i;
}
static GLuint _glewStrCLen(const GLubyte *s, GLubyte c)
{
GLuint i = 0;
- if (s == NULL)
+ if (s == nullptr) {
return 0;
- while (s[i] != '\0' && s[i] != c)
+ }
+ while (s[i] != '\0' && s[i] != c) {
i++;
+ }
return (s[i] == '\0' || s[i] == c) ? i : 0;
}
static GLboolean _glewStrSame(const GLubyte *a, const GLubyte *b, GLuint n)
{
GLuint i = 0;
- if (a == NULL || b == NULL)
- return (a == NULL && b == NULL && n == 0) ? GL_TRUE : GL_FALSE;
- while (i < n && a[i] != '\0' && b[i] != '\0' && a[i] == b[i])
+ if (a == nullptr || b == nullptr) {
+ return (a == nullptr && b == nullptr && n == 0) ? GL_TRUE : GL_FALSE;
+ }
+ while (i < n && a[i] != '\0' && b[i] != '\0' && a[i] == b[i]) {
i++;
+ }
return i == n ? GL_TRUE : GL_FALSE;
}
@@ -440,8 +440,9 @@ static GLboolean _glewSearchExtension(const char *name, const GLubyte *start, co
p = start;
while (p < end) {
GLuint n = _glewStrCLen(p, ' ');
- if (len == n && _glewStrSame((const GLubyte *)name, p, n))
+ if (len == n && _glewStrSame((const GLubyte *)name, p, n)) {
return GL_TRUE;
+ }
p += n + 1;
}
return GL_FALSE;
diff --git a/intern/ghost/intern/GHOST_ContextSDL.cpp b/intern/ghost/intern/GHOST_ContextSDL.cpp
index 050f8e43aab..5b02fe1c1e6 100644
--- a/intern/ghost/intern/GHOST_ContextSDL.cpp
+++ b/intern/ghost/intern/GHOST_ContextSDL.cpp
@@ -15,7 +15,7 @@
#include <cstdio>
#include <cstring>
-SDL_GLContext GHOST_ContextSDL::s_sharedContext = NULL;
+SDL_GLContext GHOST_ContextSDL::s_sharedContext = nullptr;
int GHOST_ContextSDL::s_sharedCount = 0;
GHOST_ContextSDL::GHOST_ContextSDL(bool stereoVisual,
@@ -27,36 +27,39 @@ GHOST_ContextSDL::GHOST_ContextSDL(bool stereoVisual,
int contextResetNotificationStrategy)
: GHOST_Context(stereoVisual),
m_window(window),
- m_hidden_window(NULL),
+ m_hidden_window(nullptr),
m_contextProfileMask(contextProfileMask),
m_contextMajorVersion(contextMajorVersion),
m_contextMinorVersion(contextMinorVersion),
m_contextFlags(contextFlags),
m_contextResetNotificationStrategy(contextResetNotificationStrategy),
- m_context(NULL)
+ m_context(nullptr)
{
- // assert(m_window != NULL);
+ // assert(m_window != nullptr);
}
GHOST_ContextSDL::~GHOST_ContextSDL()
{
- if (m_context != NULL) {
- if (m_window != NULL && m_context == SDL_GL_GetCurrentContext())
- SDL_GL_MakeCurrent(m_window, NULL);
-
- if (m_context != s_sharedContext || s_sharedCount == 1) {
- assert(s_sharedCount > 0);
+ if (m_context == nullptr) {
+ return;
+ }
- s_sharedCount--;
+ if (m_window != nullptr && m_context == SDL_GL_GetCurrentContext()) {
+ SDL_GL_MakeCurrent(m_window, nullptr);
+ }
+ if (m_context != s_sharedContext || s_sharedCount == 1) {
+ assert(s_sharedCount > 0);
- if (s_sharedCount == 0)
- s_sharedContext = NULL;
+ s_sharedCount--;
- SDL_GL_DeleteContext(m_context);
+ if (s_sharedCount == 0) {
+ s_sharedContext = nullptr;
}
+ SDL_GL_DeleteContext(m_context);
+ }
- if (m_hidden_window != NULL)
- SDL_DestroyWindow(m_hidden_window);
+ if (m_hidden_window != nullptr) {
+ SDL_DestroyWindow(m_hidden_window);
}
}
@@ -69,23 +72,19 @@ GHOST_TSuccess GHOST_ContextSDL::swapBuffers()
GHOST_TSuccess GHOST_ContextSDL::activateDrawingContext()
{
- if (m_context) {
- return SDL_GL_MakeCurrent(m_window, m_context) ? GHOST_kSuccess : GHOST_kFailure;
- }
- else {
+ if (m_context == nullptr) {
return GHOST_kFailure;
}
+ return SDL_GL_MakeCurrent(m_window, m_context) ? GHOST_kSuccess : GHOST_kFailure;
}
GHOST_TSuccess GHOST_ContextSDL::releaseDrawingContext()
{
- if (m_context) {
- /* Untested, may not work */
- return SDL_GL_MakeCurrent(NULL, NULL) ? GHOST_kSuccess : GHOST_kFailure;
- }
- else {
+ if (m_context == nullptr) {
return GHOST_kFailure;
}
+ /* Untested, may not work. */
+ return SDL_GL_MakeCurrent(nullptr, nullptr) ? GHOST_kSuccess : GHOST_kFailure;
}
GHOST_TSuccess GHOST_ContextSDL::initializeDrawingContext()
@@ -115,7 +114,7 @@ GHOST_TSuccess GHOST_ContextSDL::initializeDrawingContext()
SDL_GL_SetAttribute(SDL_GL_STEREO, 1);
}
- if (m_window == NULL) {
+ if (m_window == nullptr) {
m_hidden_window = SDL_CreateWindow("Offscreen Context Windows",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
@@ -131,10 +130,10 @@ GHOST_TSuccess GHOST_ContextSDL::initializeDrawingContext()
GHOST_TSuccess success;
- if (m_context != NULL) {
- if (!s_sharedContext)
+ if (m_context != nullptr) {
+ if (!s_sharedContext) {
s_sharedContext = m_context;
-
+ }
s_sharedCount++;
success = (SDL_GL_MakeCurrent(m_window, m_context) < 0) ? GHOST_kFailure : GHOST_kSuccess;
@@ -155,19 +154,17 @@ GHOST_TSuccess GHOST_ContextSDL::initializeDrawingContext()
GHOST_TSuccess GHOST_ContextSDL::releaseNativeHandles()
{
- m_window = NULL;
+ m_window = nullptr;
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_ContextSDL::setSwapInterval(int interval)
{
- if (SDL_GL_SetSwapInterval(interval) != -1) {
- return GHOST_kSuccess;
- }
- else {
+ if (SDL_GL_SetSwapInterval(interval) == -1) {
return GHOST_kFailure;
}
+ return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_ContextSDL::getSwapInterval(int &intervalOut)
diff --git a/intern/ghost/intern/GHOST_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp
index fa9e2a8f360..7417358e9ae 100644
--- a/intern/ghost/intern/GHOST_ContextWGL.cpp
+++ b/intern/ghost/intern/GHOST_ContextWGL.cpp
@@ -136,10 +136,10 @@ static int weight_pixel_format(PIXELFORMATDESCRIPTOR &pfd, PIXELFORMATDESCRIPTOR
/* cull unusable pixel formats */
/* if no formats can be found, can we determine why it was rejected? */
if (!(pfd.dwFlags & PFD_SUPPORT_OPENGL) || !(pfd.dwFlags & PFD_DRAW_TO_WINDOW) ||
- !(pfd.dwFlags & PFD_DOUBLEBUFFER) || /* Blender _needs_ this */
+ !(pfd.dwFlags & PFD_DOUBLEBUFFER) || /* Blender _needs_ this. */
!(pfd.iPixelType == PFD_TYPE_RGBA) ||
- (pfd.cColorBits > 32) || /* 64 bit formats disable aero */
- (pfd.dwFlags & PFD_GENERIC_FORMAT)) /* no software renderers */
+ (pfd.cColorBits > 32) || /* 64 bit formats disable AERO. */
+ (pfd.dwFlags & PFD_GENERIC_FORMAT)) /* No software renderers. */
{
return 0;
}
diff --git a/intern/ghost/intern/GHOST_DisplayManager.cpp b/intern/ghost/intern/GHOST_DisplayManager.cpp
index 18de4ab6c8f..fa15d05232d 100644
--- a/intern/ghost/intern/GHOST_DisplayManager.cpp
+++ b/intern/ghost/intern/GHOST_DisplayManager.cpp
@@ -12,15 +12,15 @@
#include "GHOST_DisplayManager.h"
#include "GHOST_Debug.h"
-GHOST_DisplayManager::GHOST_DisplayManager(void) : m_settingsInitialized(false)
+GHOST_DisplayManager::GHOST_DisplayManager() : m_settingsInitialized(false)
{
}
-GHOST_DisplayManager::~GHOST_DisplayManager(void)
+GHOST_DisplayManager::~GHOST_DisplayManager()
{
}
-GHOST_TSuccess GHOST_DisplayManager::initialize(void)
+GHOST_TSuccess GHOST_DisplayManager::initialize()
{
GHOST_TSuccess success;
if (!m_settingsInitialized) {
@@ -139,7 +139,7 @@ GHOST_TSuccess GHOST_DisplayManager::findMatch(uint8_t display,
return success;
}
-GHOST_TSuccess GHOST_DisplayManager::initializeSettings(void)
+GHOST_TSuccess GHOST_DisplayManager::initializeSettings()
{
uint8_t numDisplays;
GHOST_TSuccess success = getNumDisplays(numDisplays);
diff --git a/intern/ghost/intern/GHOST_DisplayManagerSDL.cpp b/intern/ghost/intern/GHOST_DisplayManagerSDL.cpp
index 740fcc2ef1d..a2fe6a41fb4 100644
--- a/intern/ghost/intern/GHOST_DisplayManagerSDL.cpp
+++ b/intern/ghost/intern/GHOST_DisplayManagerSDL.cpp
@@ -109,7 +109,7 @@ GHOST_TSuccess GHOST_DisplayManagerSDL::setCurrentDisplaySetting(
SDL_GetDisplayMode(display, i, &mode);
- if (setting.xPixels > mode.w || setting.yPixels > mode.h) {
+ if ((int)setting.xPixels > mode.w || (int)setting.yPixels > mode.h) {
continue;
}
@@ -122,9 +122,9 @@ GHOST_TSuccess GHOST_DisplayManagerSDL::setCurrentDisplaySetting(
}
}
- if (best_fit == -1)
+ if (best_fit == -1) {
return GHOST_kFailure;
-
+ }
SDL_GetDisplayMode(display, best_fit, &mode);
}
@@ -142,12 +142,10 @@ GHOST_TSuccess GHOST_DisplayManagerSDL::setCurrentDisplaySetting(
return GHOST_kSuccess;
}
- else {
- /* this is a problem for the BGE player :S, perhaps SDL2 will resolve at some point.
- * we really need SDL_SetDisplayModeForDisplay() to become an API func! - campbell */
- printf("no windows available, can't fullscreen\n");
+ /* This is a problem for the BGE player :S, perhaps SDL2 will resolve at some point.
+ * we really need SDL_SetDisplayModeForDisplay() to become an API func! - campbell. */
+ printf("no windows available, can't fullscreen\n");
- /* do not fail, we will try again later when the window is created - wander */
- return GHOST_kSuccess;
- }
+ /* do not fail, we will try again later when the window is created - wander */
+ return GHOST_kSuccess;
}
diff --git a/intern/ghost/intern/GHOST_DisplayManagerX11.cpp b/intern/ghost/intern/GHOST_DisplayManagerX11.cpp
index 843f22df1c3..ab4a77cd660 100644
--- a/intern/ghost/intern/GHOST_DisplayManagerX11.cpp
+++ b/intern/ghost/intern/GHOST_DisplayManagerX11.cpp
@@ -39,8 +39,9 @@ GHOST_TSuccess GHOST_DisplayManagerX11::getNumDisplaySettings(uint8_t display,
GHOST_ASSERT(display < 1, "Only single display systems are currently supported.\n");
- if (dpy == NULL)
+ if (dpy == nullptr) {
return GHOST_kFailure;
+ }
majorVersion = minorVersion = 0;
if (!XF86VidModeQueryVersion(dpy, &majorVersion, &minorVersion)) {
@@ -77,8 +78,9 @@ GHOST_TSuccess GHOST_DisplayManagerX11::getDisplaySetting(uint8_t display,
{
Display *dpy = m_system->getXDisplay();
- if (dpy == NULL)
+ if (dpy == nullptr) {
return GHOST_kFailure;
+ }
(void)display;
@@ -143,8 +145,9 @@ GHOST_TSuccess GHOST_DisplayManagerX11::setCurrentDisplaySetting(
Display *dpy = m_system->getXDisplay();
int scrnum, num_vidmodes;
- if (dpy == NULL)
+ if (dpy == nullptr) {
return GHOST_kFailure;
+ }
scrnum = DefaultScreen(dpy);
diff --git a/intern/ghost/intern/GHOST_DropTargetX11.cpp b/intern/ghost/intern/GHOST_DropTargetX11.cpp
index 0212a71d2ff..70c2eb8c29e 100644
--- a/intern/ghost/intern/GHOST_DropTargetX11.cpp
+++ b/intern/ghost/intern/GHOST_DropTargetX11.cpp
@@ -8,15 +8,15 @@
#include "GHOST_DropTargetX11.h"
#include "GHOST_Debug.h"
-#include <assert.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
+#include <cassert>
+#include <cctype>
+#include <cstdio>
+#include <cstring>
bool GHOST_DropTargetX11::m_xdndInitialized = false;
DndClass GHOST_DropTargetX11::m_dndClass;
-Atom *GHOST_DropTargetX11::m_dndTypes = NULL;
-Atom *GHOST_DropTargetX11::m_dndActions = NULL;
+Atom *GHOST_DropTargetX11::m_dndTypes = nullptr;
+Atom *GHOST_DropTargetX11::m_dndActions = nullptr;
const char *GHOST_DropTargetX11::m_dndMimeTypes[] = {
"url/url", "text/uri-list", "text/plain", "application/octet-stream"};
int GHOST_DropTargetX11::m_refCounter = 0;
@@ -180,12 +180,12 @@ char *GHOST_DropTargetX11::FileUrlDecode(char *fileUrl)
return decodedPath;
}
- return NULL;
+ return nullptr;
}
void *GHOST_DropTargetX11::getURIListGhostData(unsigned char *dropBuffer, int dropBufferSize)
{
- GHOST_TStringArray *strArray = NULL;
+ GHOST_TStringArray *strArray = nullptr;
int totPaths = 0, curLength = 0;
/* Count total number of file paths in buffer. */
@@ -196,8 +196,9 @@ void *GHOST_DropTargetX11::getURIListGhostData(unsigned char *dropBuffer, int dr
curLength = 0;
}
}
- else
+ else {
curLength++;
+ }
}
strArray = (GHOST_TStringArray *)malloc(sizeof(GHOST_TStringArray));
@@ -224,8 +225,9 @@ void *GHOST_DropTargetX11::getURIListGhostData(unsigned char *dropBuffer, int dr
curLength = 0;
}
}
- else
+ else {
curLength++;
+ }
}
return strArray;
@@ -235,11 +237,11 @@ void *GHOST_DropTargetX11::getGhostData(Atom dropType,
unsigned char *dropBuffer,
int dropBufferSize)
{
- void *data = NULL;
+ void *data = nullptr;
unsigned char *tmpBuffer = (unsigned char *)malloc(dropBufferSize + 1);
bool needsFree = true;
- /* ensure NULL-terminator */
+ /* Ensure nil-terminator. */
memcpy(tmpBuffer, dropBuffer, dropBufferSize);
tmpBuffer[dropBufferSize] = 0;
@@ -265,8 +267,9 @@ void *GHOST_DropTargetX11::getGhostData(Atom dropType,
m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
}
- if (needsFree)
+ if (needsFree) {
free(tmpBuffer);
+ }
return data;
}
@@ -288,9 +291,10 @@ bool GHOST_DropTargetX11::GHOST_HandleClientMessage(XEvent *event)
&dropY)) {
void *data = getGhostData(dropType, dropBuffer, dropBufferSize);
- if (data)
+ if (data) {
m_system->pushDragDropEvent(
GHOST_kEventDraggingDropDone, m_draggedObjectType, m_window, dropX, dropY, data);
+ }
free(dropBuffer);
diff --git a/intern/ghost/intern/GHOST_ISystem.cpp b/intern/ghost/intern/GHOST_ISystem.cpp
index 7906002b2b5..87111306ec7 100644
--- a/intern/ghost/intern/GHOST_ISystem.cpp
+++ b/intern/ghost/intern/GHOST_ISystem.cpp
@@ -29,7 +29,7 @@
# include "GHOST_SystemCocoa.h"
#endif
-GHOST_ISystem *GHOST_ISystem::m_system = NULL;
+GHOST_ISystem *GHOST_ISystem::m_system = nullptr;
GHOST_TSuccess GHOST_ISystem::createSystem()
{
@@ -61,7 +61,7 @@ GHOST_TSuccess GHOST_ISystem::createSystem()
#elif defined(__APPLE__)
m_system = new GHOST_SystemCocoa();
#endif
- success = m_system != NULL ? GHOST_kSuccess : GHOST_kFailure;
+ success = m_system != nullptr ? GHOST_kSuccess : GHOST_kFailure;
}
else {
success = GHOST_kFailure;
@@ -77,7 +77,7 @@ GHOST_TSuccess GHOST_ISystem::disposeSystem()
GHOST_TSuccess success = GHOST_kSuccess;
if (m_system) {
delete m_system;
- m_system = NULL;
+ m_system = nullptr;
}
else {
success = GHOST_kFailure;
diff --git a/intern/ghost/intern/GHOST_ISystemPaths.cpp b/intern/ghost/intern/GHOST_ISystemPaths.cpp
index dacb5421da0..599a9fec681 100644
--- a/intern/ghost/intern/GHOST_ISystemPaths.cpp
+++ b/intern/ghost/intern/GHOST_ISystemPaths.cpp
@@ -9,8 +9,6 @@
* Copyright (C) 2001 NaN Technologies B.V.
*/
-#include <stdio.h> /* just for NULL */
-
#include "GHOST_ISystemPaths.h"
#ifdef WIN32
@@ -23,7 +21,7 @@
# endif
#endif
-GHOST_ISystemPaths *GHOST_ISystemPaths::m_systemPaths = NULL;
+GHOST_ISystemPaths *GHOST_ISystemPaths::m_systemPaths = nullptr;
GHOST_TSuccess GHOST_ISystemPaths::create()
{
@@ -38,7 +36,7 @@ GHOST_TSuccess GHOST_ISystemPaths::create()
m_systemPaths = new GHOST_SystemPathsUnix();
# endif
#endif
- success = m_systemPaths != NULL ? GHOST_kSuccess : GHOST_kFailure;
+ success = m_systemPaths != nullptr ? GHOST_kSuccess : GHOST_kFailure;
}
else {
success = GHOST_kFailure;
@@ -51,7 +49,7 @@ GHOST_TSuccess GHOST_ISystemPaths::dispose()
GHOST_TSuccess success = GHOST_kSuccess;
if (m_systemPaths) {
delete m_systemPaths;
- m_systemPaths = NULL;
+ m_systemPaths = nullptr;
}
else {
success = GHOST_kFailure;
diff --git a/intern/ghost/intern/GHOST_Path-api.cpp b/intern/ghost/intern/GHOST_Path-api.cpp
index c57af8a1a21..1b1c72d8a4b 100644
--- a/intern/ghost/intern/GHOST_Path-api.cpp
+++ b/intern/ghost/intern/GHOST_Path-api.cpp
@@ -25,25 +25,28 @@ GHOST_TSuccess GHOST_DisposeSystemPaths(void)
const char *GHOST_getSystemDir(int version, const char *versionstr)
{
GHOST_ISystemPaths *systemPaths = GHOST_ISystemPaths::get();
- return systemPaths ? systemPaths->getSystemDir(version, versionstr) : NULL;
+ return systemPaths ? systemPaths->getSystemDir(version, versionstr) : nullptr;
}
const char *GHOST_getUserDir(int version, const char *versionstr)
{
GHOST_ISystemPaths *systemPaths = GHOST_ISystemPaths::get();
- return systemPaths ? systemPaths->getUserDir(version, versionstr) : NULL; /* shouldn't be NULL */
+ /* Shouldn't be `nullptr`. */
+ return systemPaths ? systemPaths->getUserDir(version, versionstr) : nullptr;
}
const char *GHOST_getUserSpecialDir(GHOST_TUserSpecialDirTypes type)
{
GHOST_ISystemPaths *systemPaths = GHOST_ISystemPaths::get();
- return systemPaths ? systemPaths->getUserSpecialDir(type) : NULL; /* shouldn't be NULL */
+ /* Shouldn't be `nullptr`. */
+ return systemPaths ? systemPaths->getUserSpecialDir(type) : nullptr;
}
const char *GHOST_getBinaryDir()
{
GHOST_ISystemPaths *systemPaths = GHOST_ISystemPaths::get();
- return systemPaths ? systemPaths->getBinaryDir() : NULL; /* shouldn't be NULL */
+ /* Shouldn't be `nullptr`. */
+ return systemPaths ? systemPaths->getBinaryDir() : nullptr;
}
void GHOST_addToSystemRecentFiles(const char *filename)
diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp
index 0d0d41972fd..1ddf884bbc5 100644
--- a/intern/ghost/intern/GHOST_System.cpp
+++ b/intern/ghost/intern/GHOST_System.cpp
@@ -8,7 +8,7 @@
#include "GHOST_System.h"
#include <chrono>
-#include <stdio.h> /* just for printf */
+#include <cstdio> /* just for printf */
#include "GHOST_DisplayManager.h"
#include "GHOST_EventManager.h"
@@ -23,10 +23,10 @@
GHOST_System::GHOST_System()
: m_nativePixel(false),
m_windowFocus(true),
- m_displayManager(NULL),
- m_timerManager(NULL),
- m_windowManager(NULL),
- m_eventManager(NULL),
+ m_displayManager(nullptr),
+ m_timerManager(nullptr),
+ m_windowManager(nullptr),
+ m_eventManager(nullptr),
#ifdef WITH_INPUT_NDOF
m_ndofManager(0),
#endif
@@ -61,7 +61,7 @@ GHOST_ITimerTask *GHOST_System::installTimer(uint64_t delay,
}
else {
delete timer;
- timer = NULL;
+ timer = nullptr;
}
}
return timer;
@@ -205,7 +205,7 @@ GHOST_IWindow *GHOST_System::getWindowUnderCursor(int32_t x, int32_t y)
}
}
- return NULL;
+ return nullptr;
}
void GHOST_System::dispatchEvents()
@@ -331,20 +331,20 @@ GHOST_TSuccess GHOST_System::exit()
}
delete m_displayManager;
- m_displayManager = NULL;
+ m_displayManager = nullptr;
delete m_windowManager;
- m_windowManager = NULL;
+ m_windowManager = nullptr;
delete m_timerManager;
- m_timerManager = NULL;
+ m_timerManager = nullptr;
delete m_eventManager;
- m_eventManager = NULL;
+ m_eventManager = nullptr;
#ifdef WITH_INPUT_NDOF
delete m_ndofManager;
- m_ndofManager = NULL;
+ m_ndofManager = nullptr;
#endif
return GHOST_kSuccess;
@@ -376,13 +376,13 @@ GHOST_TSuccess GHOST_System::createFullScreenWindow(GHOST_Window **window,
GHOST_kDrawingContextTypeOpenGL,
glSettings,
true /* exclusive */);
- return (*window == NULL) ? GHOST_kFailure : GHOST_kSuccess;
+ return (*window == nullptr) ? GHOST_kFailure : GHOST_kSuccess;
}
-bool GHOST_System::useNativePixel(void)
+bool GHOST_System::useNativePixel()
{
m_nativePixel = true;
- return 1;
+ return true;
}
void GHOST_System::useWindowFocus(const bool use_focus)
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index b6836614962..8677c0b9552 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -967,7 +967,7 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent)
return anyProcessed;
}
-// Note: called from NSApplication delegate
+/* NOTE: called from #NSApplication delegate. */
GHOST_TSuccess GHOST_SystemCocoa::handleApplicationBecomeActiveEvent()
{
for (GHOST_IWindow *iwindow : m_windowManager->getWindows()) {
@@ -1046,7 +1046,7 @@ void GHOST_SystemCocoa::notifyExternalEventProcessed()
m_outsideLoopEventProcessed = true;
}
-// Note: called from NSWindow delegate
+/* NOTE: called from #NSWindow delegate. */
GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType,
GHOST_WindowCocoa *window)
{
@@ -1108,7 +1108,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType,
return GHOST_kSuccess;
}
-// Note: called from NSWindow subclass
+/* NOTE: called from #NSWindow subclass. */
GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType,
GHOST_TDragnDropTypes draggedObjectType,
GHOST_WindowCocoa *window,
diff --git a/intern/ghost/intern/GHOST_SystemNULL.h b/intern/ghost/intern/GHOST_SystemNULL.h
index 48973a00573..644eb1ba0a5 100644
--- a/intern/ghost/intern/GHOST_SystemNULL.h
+++ b/intern/ghost/intern/GHOST_SystemNULL.h
@@ -40,7 +40,7 @@ class GHOST_SystemNULL : public GHOST_System {
}
char *getClipboard(bool selection) const
{
- return NULL;
+ return nullptr;
}
void putClipboard(const char *buffer, bool selection) const
{ /* nop */
@@ -69,7 +69,7 @@ class GHOST_SystemNULL : public GHOST_System {
}
GHOST_IContext *createOffscreenContext(GHOST_GLSettings glSettings)
{
- return NULL;
+ return nullptr;
}
GHOST_TSuccess disposeContext(GHOST_IContext *context)
{
@@ -117,6 +117,6 @@ class GHOST_SystemNULL : public GHOST_System {
GHOST_IWindow *getWindowUnderCursor(int32_t x, int32_t y)
{
- return NULL;
+ return nullptr;
}
};
diff --git a/intern/ghost/intern/GHOST_SystemPathsUnix.cpp b/intern/ghost/intern/GHOST_SystemPathsUnix.cpp
index d2c678855f2..41babc5d312 100644
--- a/intern/ghost/intern/GHOST_SystemPathsUnix.cpp
+++ b/intern/ghost/intern/GHOST_SystemPathsUnix.cpp
@@ -17,8 +17,8 @@
#include <sys/time.h>
#include <unistd.h>
+#include <cstdio> /* for fprintf only */
#include <cstdlib> /* for exit */
-#include <stdio.h> /* for fprintf only */
#include <pwd.h> /* for get home without use getenv() */
#include <string>
@@ -28,7 +28,7 @@ using std::string;
#ifdef PREFIX
static const char *static_path = PREFIX "/share";
#else
-static const char *static_path = NULL;
+static const char *static_path = nullptr;
#endif
GHOST_SystemPathsUnix::GHOST_SystemPathsUnix()
@@ -39,7 +39,7 @@ GHOST_SystemPathsUnix::~GHOST_SystemPathsUnix()
{
}
-const char *GHOST_SystemPathsUnix::getSystemDir(int, const char *versionstr) const
+const char *GHOST_SystemPathsUnix::getSystemDir(int /*version*/, const char *versionstr) const
{
/* no prefix assumes a portable build which only uses bundled scripts */
if (static_path) {
@@ -47,7 +47,7 @@ const char *GHOST_SystemPathsUnix::getSystemDir(int, const char *versionstr) con
return system_path.c_str();
}
- return NULL;
+ return nullptr;
}
const char *GHOST_SystemPathsUnix::getUserDir(int version, const char *versionstr) const
@@ -67,32 +67,29 @@ const char *GHOST_SystemPathsUnix::getUserDir(int version, const char *versionst
user_path = string(home) + "/.blender/" + versionstr;
}
else {
- return NULL;
+ return nullptr;
}
}
return user_path.c_str();
}
- else {
- if (user_path.empty() || last_version != version) {
- const char *home = getenv("XDG_CONFIG_HOME");
-
- last_version = version;
+ if (user_path.empty() || last_version != version) {
+ const char *home = getenv("XDG_CONFIG_HOME");
- if (home) {
- user_path = string(home) + "/blender/" + versionstr;
- }
- else {
- home = getenv("HOME");
+ last_version = version;
- if (home == NULL)
- home = getpwuid(getuid())->pw_dir;
-
- user_path = string(home) + "/.config/blender/" + versionstr;
+ if (home) {
+ user_path = string(home) + "/blender/" + versionstr;
+ }
+ else {
+ home = getenv("HOME");
+ if (home == nullptr) {
+ home = getpwuid(getuid())->pw_dir;
}
+ user_path = string(home) + "/.config/blender/" + versionstr;
}
-
- return user_path.c_str();
}
+
+ return user_path.c_str();
}
const char *GHOST_SystemPathsUnix::getUserSpecialDir(GHOST_TUserSpecialDirTypes type) const
@@ -135,7 +132,7 @@ const char *GHOST_SystemPathsUnix::getUserSpecialDir(GHOST_TUserSpecialDirTypes
GHOST_ASSERT(
false,
"GHOST_SystemPathsUnix::getUserSpecialDir(): Invalid enum value for type parameter");
- return NULL;
+ return nullptr;
}
static string path = "";
@@ -143,8 +140,8 @@ const char *GHOST_SystemPathsUnix::getUserSpecialDir(GHOST_TUserSpecialDirTypes
string command = string("xdg-user-dir ") + type_str + " 2> /dev/null";
FILE *fstream = popen(command.c_str(), "r");
- if (fstream == NULL) {
- return NULL;
+ if (fstream == nullptr) {
+ return nullptr;
}
std::stringstream path_stream;
while (!feof(fstream)) {
@@ -157,7 +154,7 @@ const char *GHOST_SystemPathsUnix::getUserSpecialDir(GHOST_TUserSpecialDirTypes
}
if (pclose(fstream) == -1) {
perror("GHOST_SystemPathsUnix::getUserSpecialDir failed at pclose()");
- return NULL;
+ return nullptr;
}
if (!add_path.empty()) {
@@ -165,12 +162,12 @@ const char *GHOST_SystemPathsUnix::getUserSpecialDir(GHOST_TUserSpecialDirTypes
}
path = path_stream.str();
- return path[0] ? path.c_str() : NULL;
+ return path[0] ? path.c_str() : nullptr;
}
const char *GHOST_SystemPathsUnix::getBinaryDir() const
{
- return NULL;
+ return nullptr;
}
void GHOST_SystemPathsUnix::addToSystemRecentFiles(const char * /*filename*/) const
diff --git a/intern/ghost/intern/GHOST_SystemSDL.cpp b/intern/ghost/intern/GHOST_SystemSDL.cpp
index d088b6717f9..36c912d8821 100644
--- a/intern/ghost/intern/GHOST_SystemSDL.cpp
+++ b/intern/ghost/intern/GHOST_SystemSDL.cpp
@@ -4,7 +4,7 @@
* \ingroup GHOST
*/
-#include <assert.h>
+#include <cassert>
#include "GHOST_ContextSDL.h"
#include "GHOST_SystemSDL.h"
@@ -47,7 +47,7 @@ GHOST_IWindow *GHOST_SystemSDL::createWindow(const char *title,
const bool /* is_dialog */,
const GHOST_IWindow *parentWindow)
{
- GHOST_WindowSDL *window = NULL;
+ GHOST_WindowSDL *window = nullptr;
window = new GHOST_WindowSDL(this,
title,
@@ -79,7 +79,7 @@ GHOST_IWindow *GHOST_SystemSDL::createWindow(const char *title,
}
else {
delete window;
- window = NULL;
+ window = nullptr;
}
}
return window;
@@ -125,22 +125,22 @@ uint8_t GHOST_SystemSDL::getNumDisplays() const
return SDL_GetNumVideoDisplays();
}
-GHOST_IContext *GHOST_SystemSDL::createOffscreenContext(GHOST_GLSettings glSettings)
+GHOST_IContext *GHOST_SystemSDL::createOffscreenContext(GHOST_GLSettings /*glSettings*/)
{
- GHOST_Context *context = new GHOST_ContextSDL(0,
- NULL,
+ GHOST_Context *context = new GHOST_ContextSDL(false,
+ nullptr,
0, /* Profile bit. */
3,
3,
GHOST_OPENGL_SDL_CONTEXT_FLAGS,
GHOST_OPENGL_SDL_RESET_NOTIFICATION_STRATEGY);
- if (context->initializeDrawingContext())
+ if (context->initializeDrawingContext()) {
return context;
- else
- delete context;
+ }
+ delete context;
- return NULL;
+ return nullptr;
}
GHOST_TSuccess GHOST_SystemSDL::disposeContext(GHOST_IContext *context)
@@ -286,7 +286,7 @@ static GHOST_TKey convertSDLKey(SDL_Scancode key)
static SDL_Window *SDL_GetWindowFromID_fallback(Uint32 id)
{
SDL_Window *sdl_win = SDL_GetWindowFromID(id);
- if (sdl_win == NULL) {
+ if (sdl_win == nullptr) {
sdl_win = SDL_GL_GetCurrentWindow();
}
return sdl_win;
@@ -294,16 +294,16 @@ static SDL_Window *SDL_GetWindowFromID_fallback(Uint32 id)
void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
{
- GHOST_Event *g_event = NULL;
+ GHOST_Event *g_event = nullptr;
switch (sdl_event->type) {
case SDL_WINDOWEVENT: {
SDL_WindowEvent &sdl_sub_evt = sdl_event->window;
GHOST_WindowSDL *window = findGhostWindow(
SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
- /* Can be NULL on close window. */
+ /* Can be nullptr on close window. */
#if 0
- assert(window != NULL);
+ assert(window != nullptr);
#endif
switch (sdl_sub_evt.event) {
@@ -340,7 +340,7 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
SDL_MouseMotionEvent &sdl_sub_evt = sdl_event->motion;
SDL_Window *sdl_win = SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID);
GHOST_WindowSDL *window = findGhostWindow(sdl_win);
- assert(window != NULL);
+ assert(window != nullptr);
int x_win, y_win;
SDL_GetWindowPosition(sdl_win, &x_win, &y_win);
@@ -416,22 +416,28 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
GHOST_WindowSDL *window = findGhostWindow(
SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
- assert(window != NULL);
+ assert(window != nullptr);
/* process rest of normal mouse buttons */
- if (sdl_sub_evt.button == SDL_BUTTON_LEFT)
+ if (sdl_sub_evt.button == SDL_BUTTON_LEFT) {
gbmask = GHOST_kButtonMaskLeft;
- else if (sdl_sub_evt.button == SDL_BUTTON_MIDDLE)
+ }
+ else if (sdl_sub_evt.button == SDL_BUTTON_MIDDLE) {
gbmask = GHOST_kButtonMaskMiddle;
- else if (sdl_sub_evt.button == SDL_BUTTON_RIGHT)
+ }
+ else if (sdl_sub_evt.button == SDL_BUTTON_RIGHT) {
gbmask = GHOST_kButtonMaskRight;
- /* these buttons are untested! */
- else if (sdl_sub_evt.button == SDL_BUTTON_X1)
+ /* these buttons are untested! */
+ }
+ else if (sdl_sub_evt.button == SDL_BUTTON_X1) {
gbmask = GHOST_kButtonMaskButton4;
- else if (sdl_sub_evt.button == SDL_BUTTON_X2)
+ }
+ else if (sdl_sub_evt.button == SDL_BUTTON_X2) {
gbmask = GHOST_kButtonMaskButton5;
- else
+ }
+ else {
break;
+ }
g_event = new GHOST_EventButton(
getMilliSeconds(), type, window, gbmask, GHOST_TABLET_DATA_NONE);
@@ -441,7 +447,7 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
SDL_MouseWheelEvent &sdl_sub_evt = sdl_event->wheel;
GHOST_WindowSDL *window = findGhostWindow(
SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
- assert(window != NULL);
+ assert(window != nullptr);
g_event = new GHOST_EventWheel(getMilliSeconds(), window, sdl_sub_evt.y);
break;
}
@@ -454,7 +460,7 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
GHOST_WindowSDL *window = findGhostWindow(
SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
- assert(window != NULL);
+ assert(window != nullptr);
GHOST_TKey gkey = convertSDLKey(sdl_sub_evt.keysym.scancode);
/* NOTE: the `sdl_sub_evt.keysym.sym` is truncated,
@@ -590,7 +596,7 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
}
}
- g_event = new GHOST_EventKey(getMilliSeconds(), type, window, gkey, sym, NULL, false);
+ g_event = new GHOST_EventKey(getMilliSeconds(), type, window, gkey, sym, nullptr, false);
break;
}
}
@@ -660,14 +666,14 @@ bool GHOST_SystemSDL::processEvents(bool waitForEvent)
uint64_t next = timerMgr->nextFireTime();
if (next == GHOST_kFireTimeNever) {
- SDL_WaitEventTimeout(NULL, -1);
+ SDL_WaitEventTimeout(nullptr, -1);
// SleepTillEvent(m_display, -1);
}
else {
int64_t maxSleep = next - getMilliSeconds();
if (maxSleep >= 0) {
- SDL_WaitEventTimeout(NULL, next - getMilliSeconds());
+ SDL_WaitEventTimeout(nullptr, next - getMilliSeconds());
// SleepTillEvent(m_display, next - getMilliSeconds()); /* X11. */
}
}
@@ -693,9 +699,9 @@ bool GHOST_SystemSDL::processEvents(bool waitForEvent)
GHOST_WindowSDL *GHOST_SystemSDL::findGhostWindow(SDL_Window *sdl_win)
{
- if (sdl_win == NULL)
- return NULL;
-
+ if (sdl_win == nullptr) {
+ return nullptr;
+ }
/* It is not entirely safe to do this as the backptr may point
* to a window that has recently been removed.
* We should always check the window manager's list of windows
@@ -712,19 +718,19 @@ GHOST_WindowSDL *GHOST_SystemSDL::findGhostWindow(SDL_Window *sdl_win)
return window;
}
}
- return NULL;
+ return nullptr;
}
void GHOST_SystemSDL::addDirtyWindow(GHOST_WindowSDL *bad_wind)
{
- GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
+ GHOST_ASSERT((bad_wind != nullptr), "addDirtyWindow() nullptr ptr trapped (window)");
m_dirty_windows.push_back(bad_wind);
}
GHOST_TSuccess GHOST_SystemSDL::getButtons(GHOST_Buttons &buttons) const
{
- Uint8 state = SDL_GetMouseState(NULL, NULL);
+ Uint8 state = SDL_GetMouseState(nullptr, nullptr);
buttons.set(GHOST_kButtonMaskLeft, (state & SDL_BUTTON_LMASK) != 0);
buttons.set(GHOST_kButtonMaskMiddle, (state & SDL_BUTTON_MMASK) != 0);
buttons.set(GHOST_kButtonMaskRight, (state & SDL_BUTTON_RMASK) != 0);
@@ -732,12 +738,12 @@ GHOST_TSuccess GHOST_SystemSDL::getButtons(GHOST_Buttons &buttons) const
return GHOST_kSuccess;
}
-char *GHOST_SystemSDL::getClipboard(bool selection) const
+char *GHOST_SystemSDL::getClipboard(bool /*selection*/) const
{
return (char *)SDL_GetClipboardText();
}
-void GHOST_SystemSDL::putClipboard(const char *buffer, bool selection) const
+void GHOST_SystemSDL::putClipboard(const char *buffer, bool /*selection*/) const
{
SDL_SetClipboardText(buffer);
}
diff --git a/intern/ghost/intern/GHOST_SystemSDL.h b/intern/ghost/intern/GHOST_SystemSDL.h
index 77707924675..aefea5eda34 100644
--- a/intern/ghost/intern/GHOST_SystemSDL.h
+++ b/intern/ghost/intern/GHOST_SystemSDL.h
@@ -33,7 +33,7 @@ class GHOST_SystemSDL : public GHOST_System {
bool processEvents(bool waitForEvent);
- int setConsoleWindowState(GHOST_TConsoleWindowState action)
+ int setConsoleWindowState(GHOST_TConsoleWindowState /*action*/)
{
return 0;
}
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index 6f694bfd9a6..7e74287d6e3 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.cpp
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -38,7 +38,8 @@
#include <cstring>
-/* selected input event code defines from 'linux/input-event-codes.h'
+/**
+ * Selected input event code defines from `linux/input-event-codes.h`
* We include some of the button input event codes here, since the header is
* only available in more recent kernel versions. The event codes are used to
* to differentiate from which mouse button an event comes from.
@@ -46,6 +47,11 @@
#define BTN_LEFT 0x110
#define BTN_RIGHT 0x111
#define BTN_MIDDLE 0x112
+#define BTN_SIDE 0x113
+#define BTN_EXTRA 0x114
+#define BTN_FORWARD 0x115
+#define BTN_BACK 0x116
+// #define BTN_TASK 0x117 /* UNUSED. */
struct buffer_t {
void *data;
@@ -501,7 +507,7 @@ static std::string read_pipe(data_offer_t *data_offer, const std::string mime_re
* A target accepts an offered mime type.
*
* Sent when a target accepts pointer_focus or motion events. If
- * a target does not accept any of the offered types, type is NULL.
+ * a target does not accept any of the offered types, type is nullptr.
*/
static void data_source_target(void * /*data*/,
struct wl_data_source * /*wl_data_source*/,
@@ -516,7 +522,7 @@ static void data_source_send(void *data,
int32_t fd)
{
const char *const buffer = static_cast<char *>(data);
- if (write(fd, buffer, strlen(buffer) + 1) < 0) {
+ if (write(fd, buffer, strlen(buffer)) < 0) {
GHOST_PRINT("error writing to clipboard: " << std::strerror(errno) << std::endl);
}
close(fd);
@@ -761,7 +767,7 @@ static void data_device_selection(void *data,
input->data_offer_copy_paste = data_offer;
std::string mime_receive;
- for (const std::string &type : {mime_text_utf8, mime_text_plain}) {
+ for (const std::string type : {mime_text_utf8, mime_text_plain}) {
if (data_offer->types.count(type)) {
mime_receive = type;
break;
@@ -822,8 +828,9 @@ static bool update_cursor_scale(cursor_t &cursor, wl_shm *shm)
{
int scale = 0;
for (const output_t *output : cursor.outputs) {
- if (output->scale > scale)
+ if (output->scale > scale) {
scale = output->scale;
+ }
}
if (scale > 0 && cursor.scale != scale) {
@@ -974,6 +981,18 @@ static void pointer_button(void *data,
case BTN_RIGHT:
ebutton = GHOST_kButtonMaskRight;
break;
+ case BTN_SIDE:
+ ebutton = GHOST_kButtonMaskButton4;
+ break;
+ case BTN_EXTRA:
+ ebutton = GHOST_kButtonMaskButton5;
+ break;
+ case BTN_FORWARD:
+ ebutton = GHOST_kButtonMaskButton6;
+ break;
+ case BTN_BACK:
+ ebutton = GHOST_kButtonMaskButton7;
+ break;
}
input->data_source->source_serial = serial;
@@ -1520,8 +1539,9 @@ void GHOST_SystemWayland::putClipboard(const char *buffer, bool /*selection*/) c
data_source_t *data_source = d->inputs[0]->data_source;
/* Copy buffer. */
- data_source->buffer_out = static_cast<char *>(malloc(strlen(buffer) + 1));
- std::strcpy(data_source->buffer_out, buffer);
+ const size_t buffer_size = strlen(buffer) + 1;
+ data_source->buffer_out = static_cast<char *>(malloc(buffer_size));
+ std::memcpy(data_source->buffer_out, buffer, buffer_size);
data_source->data_source = wl_data_device_manager_create_data_source(d->data_device_manager);
@@ -1545,14 +1565,13 @@ uint8_t GHOST_SystemWayland::getNumDisplays() const
GHOST_TSuccess GHOST_SystemWayland::getCursorPosition(int32_t &x, int32_t &y) const
{
- if (!d->inputs.empty() && (d->inputs[0]->focus_pointer != nullptr)) {
- x = d->inputs[0]->x;
- y = d->inputs[0]->y;
- return GHOST_kSuccess;
- }
- else {
+ if (d->inputs.empty() || (d->inputs[0]->focus_pointer == nullptr)) {
return GHOST_kFailure;
}
+
+ x = d->inputs[0]->x;
+ y = d->inputs[0]->y;
+ return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_SystemWayland::setCursorPosition(int32_t /*x*/, int32_t /*y*/)
@@ -1597,10 +1616,10 @@ GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GLSettings /*g
GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
EGL_OPENGL_API);
- if (context->initializeDrawingContext())
+ if (context->initializeDrawingContext()) {
return context;
- else
- delete context;
+ }
+ delete context;
}
context = new GHOST_ContextEGL(this,
@@ -1617,9 +1636,7 @@ GHOST_IContext *GHOST_SystemWayland::createOffscreenContext(GHOST_GLSettings /*g
if (context->initializeDrawingContext()) {
return context;
}
- else {
- delete context;
- }
+ delete context;
GHOST_PRINT("Cannot create off-screen EGL context" << std::endl);
@@ -1788,7 +1805,7 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap,
cursor_t *cursor = &d->inputs[0]->cursor;
static const int32_t stride = sizex * 4; /* ARGB */
- cursor->file_buffer->size = size_t(stride * sizey);
+ cursor->file_buffer->size = (size_t)stride * sizey;
#ifdef HAVE_MEMFD_CREATE
const int fd = memfd_create("blender-cursor-custom", MFD_CLOEXEC | MFD_ALLOW_SEALING);
@@ -1902,6 +1919,8 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(bool visible)
}
GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mode,
+ const GHOST_TGrabCursorMode mode_current,
+
wl_surface *surface)
{
/* ignore, if the required protocols are not supported */
@@ -1913,38 +1932,51 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo
return GHOST_kFailure;
}
+ /* No change, success. */
+ if (mode == mode_current) {
+ return GHOST_kSuccess;
+ }
+
input_t *input = d->inputs[0];
- switch (mode) {
- case GHOST_kGrabDisable:
- if (input->relative_pointer) {
- zwp_relative_pointer_v1_destroy(input->relative_pointer);
- input->relative_pointer = nullptr;
- }
- if (input->locked_pointer) {
- zwp_locked_pointer_v1_destroy(input->locked_pointer);
- input->locked_pointer = nullptr;
- }
- break;
+ if (mode_current == GHOST_kGrabHide) {
+ setCursorVisibility(true);
+ }
- case GHOST_kGrabNormal:
- break;
- case GHOST_kGrabWrap:
- input->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
- d->relative_pointer_manager, input->pointer);
- zwp_relative_pointer_v1_add_listener(
- input->relative_pointer, &relative_pointer_listener, input);
- input->locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
- d->pointer_constraints,
- surface,
- input->pointer,
- nullptr,
- ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
- break;
+ if ((mode == GHOST_kGrabDisable) ||
+ /* Switching from one grab mode to another,
+ * in this case disable the current locks as it makes logic confusing,
+ * postpone changing the cursor to avoid flickering. */
+ (mode_current != GHOST_kGrabDisable)) {
+ if (input->relative_pointer) {
+ zwp_relative_pointer_v1_destroy(input->relative_pointer);
+ input->relative_pointer = nullptr;
+ }
+ if (input->locked_pointer) {
+ zwp_locked_pointer_v1_destroy(input->locked_pointer);
+ input->locked_pointer = nullptr;
+ }
+ }
- case GHOST_kGrabHide:
+ if (mode != GHOST_kGrabDisable) {
+ /* TODO(@campbellbarton): As WAYLAND does not support warping the pointer it may not be
+ * possible to support #GHOST_kGrabWrap by pragmatically settings it's coordinates.
+ * An alternative could be to draw the cursor in software (and hide the real cursor),
+ * or just accept a locked cursor on WAYLAND. */
+ input->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
+ d->relative_pointer_manager, input->pointer);
+ zwp_relative_pointer_v1_add_listener(
+ input->relative_pointer, &relative_pointer_listener, input);
+ input->locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
+ d->pointer_constraints,
+ surface,
+ input->pointer,
+ nullptr,
+ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
+
+ if (mode == GHOST_kGrabHide) {
setCursorVisibility(false);
- break;
+ }
}
return GHOST_kSuccess;
diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h
index 1f664915ad3..eeb65eb4fc3 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.h
+++ b/intern/ghost/intern/GHOST_SystemWayland.h
@@ -23,8 +23,8 @@ struct display_t;
struct output_t {
struct wl_output *output;
- int32_t width_pxl, height_pxl; // dimensions in pixel
- int32_t width_mm, height_mm; // dimensions in millimeter
+ int32_t width_pxl, height_pxl; /* Dimensions in pixel. */
+ int32_t width_mm, height_mm; /* Dimensions in millimeter. */
int transform;
int scale;
std::string make;
@@ -103,7 +103,9 @@ class GHOST_SystemWayland : public GHOST_System {
GHOST_TSuccess setCursorVisibility(bool visible);
- GHOST_TSuccess setCursorGrab(const GHOST_TGrabCursorMode mode, wl_surface *surface);
+ GHOST_TSuccess setCursorGrab(const GHOST_TGrabCursorMode mode,
+ const GHOST_TGrabCursorMode mode_current,
+ wl_surface *surface);
private:
struct display_t *d;
diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp
index 83869188b65..28c86db53e2 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.cpp
+++ b/intern/ghost/intern/GHOST_SystemWin32.cpp
@@ -8,12 +8,14 @@
#include "GHOST_SystemWin32.h"
#include "GHOST_ContextD3D.h"
#include "GHOST_EventDragnDrop.h"
+#include "GHOST_EventTrackpad.h"
#ifndef _WIN32_IE
# define _WIN32_IE 0x0501 /* shipped before XP, so doesn't impose additional requirements */
#endif
#include <commctrl.h>
+#include <dwmapi.h>
#include <psapi.h>
#include <shellapi.h>
#include <shellscalingapi.h>
@@ -414,6 +416,8 @@ bool GHOST_SystemWin32::processEvents(bool waitForEvent)
hasEventHandled = true;
}
+ driveTrackpad();
+
// Process all the events waiting for us
while (::PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE) != 0) {
// TranslateMessage doesn't alter the message, and doesn't change our raw keyboard data.
@@ -423,6 +427,8 @@ bool GHOST_SystemWin32::processEvents(bool waitForEvent)
hasEventHandled = true;
}
+ processTrackpad();
+
/* PeekMessage above is allowed to dispatch messages to the wndproc without us
* noticing, so we need to check the event manager here to see if there are
* events waiting in the queue.
@@ -1416,6 +1422,52 @@ bool GHOST_SystemWin32::processNDOF(RAWINPUT const &raw)
}
#endif // WITH_INPUT_NDOF
+void GHOST_SystemWin32::driveTrackpad()
+{
+ GHOST_WindowWin32 *active_window = static_cast<GHOST_WindowWin32 *>(
+ getWindowManager()->getActiveWindow());
+ if (active_window) {
+ active_window->updateDirectManipulation();
+ }
+}
+
+void GHOST_SystemWin32::processTrackpad()
+{
+ GHOST_WindowWin32 *active_window = static_cast<GHOST_WindowWin32 *>(
+ getWindowManager()->getActiveWindow());
+
+ if (!active_window) {
+ return;
+ }
+
+ GHOST_TTrackpadInfo trackpad_info = active_window->getTrackpadInfo();
+ GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
+
+ int32_t cursor_x, cursor_y;
+ system->getCursorPosition(cursor_x, cursor_y);
+
+ if (trackpad_info.x != 0 || trackpad_info.y != 0) {
+ system->pushEvent(new GHOST_EventTrackpad(system->getMilliSeconds(),
+ active_window,
+ GHOST_kTrackpadEventScroll,
+ cursor_x,
+ cursor_y,
+ trackpad_info.x,
+ trackpad_info.y,
+ trackpad_info.isScrollDirectionInverted));
+ }
+ if (trackpad_info.scale != 0) {
+ system->pushEvent(new GHOST_EventTrackpad(system->getMilliSeconds(),
+ active_window,
+ GHOST_kTrackpadEventMagnify,
+ cursor_x,
+ cursor_y,
+ trackpad_info.scale,
+ 0,
+ false));
+ }
+}
+
LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
GHOST_Event *event = NULL;
@@ -1968,6 +2020,8 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
suggestedWindowRect->right - suggestedWindowRect->left,
suggestedWindowRect->bottom - suggestedWindowRect->top,
SWP_NOZORDER | SWP_NOACTIVATE);
+
+ window->updateDPI();
}
break;
case WM_DISPLAYCHANGE: {
@@ -1985,6 +2039,12 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
::SetFocus(hwnd);
}
break;
+ case WM_SETTINGCHANGE:
+ /* Microsoft: "Note that some applications send this message with lParam set to NULL" */
+ if ((lParam != NULL) && (wcscmp(LPCWSTR(lParam), L"ImmersiveColorSet") == 0)) {
+ window->ThemeRefresh();
+ }
+ break;
////////////////////////////////////////////////////////////////////////
// Window events, ignored
////////////////////////////////////////////////////////////////////////
@@ -2056,6 +2116,12 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
* In GHOST, we let DefWindowProc call the timer callback.
*/
break;
+ case DM_POINTERHITTEST:
+ /* The DM_POINTERHITTEST message is sent to a window, when pointer input is first
+ * detected, in order to determine the most probable input target for Direct
+ * Manipulation. */
+ window->onPointerHitTest(wParam);
+ break;
}
}
else {
@@ -2145,31 +2211,28 @@ char *GHOST_SystemWin32::getClipboard(bool selection) const
void GHOST_SystemWin32::putClipboard(const char *buffer, bool selection) const
{
- if (selection) {
+ if (selection || !buffer) {
return;
} // for copying the selection, used on X11
if (OpenClipboard(NULL)) {
- HLOCAL clipbuffer;
- wchar_t *data;
+ EmptyClipboard();
- if (buffer) {
- size_t len = count_utf_16_from_8(buffer);
- EmptyClipboard();
+ // Get length of buffer including the terminating null
+ size_t len = count_utf_16_from_8(buffer);
- clipbuffer = LocalAlloc(LMEM_FIXED, sizeof(wchar_t) * len);
- data = (wchar_t *)GlobalLock(clipbuffer);
+ HGLOBAL clipbuffer = GlobalAlloc(GMEM_MOVEABLE, sizeof(wchar_t) * len);
+ if (clipbuffer) {
+ wchar_t *data = (wchar_t *)GlobalLock(clipbuffer);
conv_utf_8_to_16(buffer, data, len);
- LocalUnlock(clipbuffer);
+ GlobalUnlock(clipbuffer);
SetClipboardData(CF_UNICODETEXT, clipbuffer);
}
+
CloseClipboard();
}
- else {
- return;
- }
}
/* -------------------------------------------------------------------- */
diff --git a/intern/ghost/intern/GHOST_SystemWin32.h b/intern/ghost/intern/GHOST_SystemWin32.h
index 9f8d52f9ca3..689b78b0317 100644
--- a/intern/ghost/intern/GHOST_SystemWin32.h
+++ b/intern/ghost/intern/GHOST_SystemWin32.h
@@ -407,6 +407,16 @@ class GHOST_SystemWin32 : public GHOST_System {
#endif
/**
+ * Drives Direct Manipulation update.
+ */
+ void driveTrackpad();
+
+ /**
+ * Creates trackpad events for the active window.
+ */
+ void processTrackpad();
+
+ /**
* Returns the local state of the modifier keys (from the message queue).
* \param keys: The state of the keys.
*/
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index ebee5f58fff..e93a56cc8d4 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -58,12 +58,12 @@
#include <sys/time.h>
#include <unistd.h>
+#include <cstdio> /* for fprintf only */
#include <cstdlib> /* for exit */
#include <iostream>
-#include <stdio.h> /* for fprintf only */
#include <vector>
-/* for debugging - so we can breakpoint X11 errors */
+/* For debugging, so we can break-point X11 errors. */
// #define USE_X11_ERROR_HANDLERS
#ifdef WITH_X11_XINPUT
@@ -89,8 +89,8 @@ static GHOST_TKey ghost_key_from_keysym_or_keycode(const KeySym key,
const KeyCode keycode);
/* these are for copy and select copy */
-static char *txt_cut_buffer = NULL;
-static char *txt_select_buffer = NULL;
+static char *txt_cut_buffer = nullptr;
+static char *txt_select_buffer = nullptr;
#ifdef WITH_XWAYLAND_HACK
static bool use_xwayland_hack = false;
@@ -98,10 +98,10 @@ static bool use_xwayland_hack = false;
using namespace std;
-GHOST_SystemX11::GHOST_SystemX11() : GHOST_System(), m_xkb_descr(NULL), m_start_time(0)
+GHOST_SystemX11::GHOST_SystemX11() : GHOST_System(), m_xkb_descr(nullptr), m_start_time(0)
{
XInitThreads();
- m_display = XOpenDisplay(NULL);
+ m_display = XOpenDisplay(nullptr);
if (!m_display) {
std::cerr << "Unable to open a display" << std::endl;
@@ -117,7 +117,7 @@ GHOST_SystemX11::GHOST_SystemX11() : GHOST_System(), m_xkb_descr(NULL), m_start_
/* NOTE: Don't open connection to XIM server here, because the locale has to be
* set before opening the connection but `setlocale()` has not been called yet.
* the connection will be opened after entering the event loop. */
- m_xim = NULL;
+ m_xim = nullptr;
#endif
#define GHOST_INTERN_ATOM_IF_EXISTS(atom) \
@@ -165,7 +165,7 @@ GHOST_SystemX11::GHOST_SystemX11() : GHOST_System(), m_xkb_descr(NULL), m_start_
/* compute the initial time */
timeval tv;
- if (gettimeofday(&tv, NULL) == -1) {
+ if (gettimeofday(&tv, nullptr) == -1) {
GHOST_ASSERT(false, "Could not instantiate timer!");
}
@@ -180,7 +180,7 @@ GHOST_SystemX11::GHOST_SystemX11() : GHOST_System(), m_xkb_descr(NULL), m_start_
use_xkb = XkbQueryExtension(
m_display, &xkb_opcode, &xkb_event, &xkb_error, &xkb_major, &xkb_minor);
if (use_xkb) {
- XkbSetDetectableAutoRepeat(m_display, true, NULL);
+ XkbSetDetectableAutoRepeat(m_display, true, nullptr);
m_xkb_descr = XkbGetMap(m_display, 0, XkbUseCoreKbd);
if (m_xkb_descr) {
@@ -190,7 +190,7 @@ GHOST_SystemX11::GHOST_SystemX11() : GHOST_System(), m_xkb_descr(NULL), m_start_
}
#ifdef WITH_XWAYLAND_HACK
- use_xwayland_hack = getenv("WAYLAND_DISPLAY") != NULL;
+ use_xwayland_hack = getenv("WAYLAND_DISPLAY") != nullptr;
#endif
#ifdef WITH_X11_XINPUT
@@ -266,7 +266,7 @@ GHOST_TSuccess GHOST_SystemX11::init()
uint64_t GHOST_SystemX11::getMilliSeconds() const
{
timeval tv;
- if (gettimeofday(&tv, NULL) == -1) {
+ if (gettimeofday(&tv, nullptr) == -1) {
GHOST_ASSERT(false, "Could not compute time!");
}
@@ -334,10 +334,11 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title,
const bool is_dialog,
const GHOST_IWindow *parentWindow)
{
- GHOST_WindowX11 *window = NULL;
+ GHOST_WindowX11 *window = nullptr;
- if (!m_display)
- return 0;
+ if (!m_display) {
+ return nullptr;
+ }
window = new GHOST_WindowX11(this,
m_display,
@@ -367,7 +368,7 @@ GHOST_IWindow *GHOST_SystemX11::createWindow(const char *title,
}
else {
delete window;
- window = NULL;
+ window = nullptr;
}
}
return window;
@@ -395,7 +396,7 @@ GHOST_IContext *GHOST_SystemX11::createOffscreenContext(GHOST_GLSettings glSetti
#if defined(WITH_GL_PROFILE_CORE)
{
const char *version_major = (char *)glewGetString(GLEW_VERSION_MAJOR);
- if (version_major != NULL && version_major[0] == '1') {
+ if (version_major != nullptr && version_major[0] == '1') {
fprintf(stderr, "Error: GLEW version 2.0 and above is required.\n");
abort();
}
@@ -438,9 +439,9 @@ GHOST_IContext *GHOST_SystemX11::createOffscreenContext(GHOST_GLSettings glSetti
EGL_OPENGL_API);
#else
context = new GHOST_ContextGLX(false,
- (Window)NULL,
+ (Window) nullptr,
m_display,
- (GLXFBConfig)NULL,
+ (GLXFBConfig) nullptr,
profile_mask,
4,
minor,
@@ -449,10 +450,10 @@ GHOST_IContext *GHOST_SystemX11::createOffscreenContext(GHOST_GLSettings glSetti
GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
#endif
- if (context->initializeDrawingContext())
+ if (context->initializeDrawingContext()) {
return context;
- else
- delete context;
+ }
+ delete context;
}
#if defined(WITH_GL_EGL)
@@ -469,9 +470,9 @@ GHOST_IContext *GHOST_SystemX11::createOffscreenContext(GHOST_GLSettings glSetti
EGL_OPENGL_API);
#else
context = new GHOST_ContextGLX(false,
- (Window)NULL,
+ (Window) nullptr,
m_display,
- (GLXFBConfig)NULL,
+ (GLXFBConfig) nullptr,
profile_mask,
3,
3,
@@ -480,12 +481,12 @@ GHOST_IContext *GHOST_SystemX11::createOffscreenContext(GHOST_GLSettings glSetti
GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
#endif
- if (context->initializeDrawingContext())
+ if (context->initializeDrawingContext()) {
return context;
- else
- delete context;
+ }
+ delete context;
- return NULL;
+ return nullptr;
}
/**
@@ -506,7 +507,7 @@ static void destroyIMCallback(XIM /*xim*/, XPointer ptr, XPointer /*data*/)
GHOST_PRINT("XIM server died\n");
if (ptr)
- *(XIM *)ptr = NULL;
+ *(XIM *)ptr = nullptr;
}
bool GHOST_SystemX11::openX11_IM()
@@ -517,14 +518,14 @@ bool GHOST_SystemX11::openX11_IM()
/* set locale modifiers such as `@im=ibus` specified by XMODIFIERS. */
XSetLocaleModifiers("");
- m_xim = XOpenIM(m_display, NULL, (char *)GHOST_X11_RES_NAME, (char *)GHOST_X11_RES_CLASS);
+ m_xim = XOpenIM(m_display, nullptr, (char *)GHOST_X11_RES_NAME, (char *)GHOST_X11_RES_CLASS);
if (!m_xim)
return false;
XIMCallback destroy;
destroy.callback = (XIMProc)destroyIMCallback;
destroy.client_data = (XPointer)&m_xim;
- XSetIMValues(m_xim, XNDestroyCallback, &destroy, NULL);
+ XSetIMValues(m_xim, XNDestroyCallback, &destroy, nullptr);
return true;
}
#endif
@@ -532,8 +533,9 @@ bool GHOST_SystemX11::openX11_IM()
GHOST_WindowX11 *GHOST_SystemX11::findGhostWindow(Window xwind) const
{
- if (xwind == 0)
- return NULL;
+ if (xwind == 0) {
+ return nullptr;
+ }
/* It is not entirely safe to do this as the backptr may point
* to a window that has recently been removed.
@@ -551,7 +553,7 @@ GHOST_WindowX11 *GHOST_SystemX11::findGhostWindow(Window xwind) const
return window;
}
}
- return NULL;
+ return nullptr;
}
static void SleepTillEvent(Display *display, int64_t maxSleep)
@@ -563,7 +565,7 @@ static void SleepTillEvent(Display *display, int64_t maxSleep)
FD_SET(fd, &fds);
if (maxSleep == -1) {
- select(fd + 1, &fds, NULL, NULL, NULL);
+ select(fd + 1, &fds, nullptr, nullptr, nullptr);
}
else {
timeval tv;
@@ -571,7 +573,7 @@ static void SleepTillEvent(Display *display, int64_t maxSleep)
tv.tv_sec = maxSleep / 1000;
tv.tv_usec = (maxSleep - tv.tv_sec * 1000) * 1000;
- select(fd + 1, &fds, NULL, NULL, &tv);
+ select(fd + 1, &fds, nullptr, nullptr, &tv);
}
}
@@ -677,7 +679,7 @@ bool GHOST_SystemX11::processEvents(bool waitForEvent)
}
/* dispatch event to XIM server */
- if ((XFilterEvent(&xevent, (Window)NULL) == True)) {
+ if ((XFilterEvent(&xevent, (Window) nullptr) == True)) {
/* do nothing now, the event is consumed by XIM. */
continue;
}
@@ -739,7 +741,7 @@ bool GHOST_SystemX11::processEvents(bool waitForEvent)
window,
ghost_key_from_keysym(modifiers[i]),
'\0',
- NULL,
+ nullptr,
false));
}
}
@@ -773,7 +775,7 @@ static bool checkTabletProximity(Display *display, XDevice *device)
/* see: state.c from xinput, to get more data out of the device */
XDeviceState *state;
- if (device == NULL) {
+ if (device == nullptr) {
return false;
}
@@ -812,7 +814,7 @@ static bool checkTabletProximity(Display *display, XDevice *device)
void GHOST_SystemX11::processEvent(XEvent *xe)
{
GHOST_WindowX11 *window = findGhostWindow(xe->xany.window);
- GHOST_Event *g_event = NULL;
+ GHOST_Event *g_event = nullptr;
/* Detect auto-repeat. */
bool is_repeat = false;
@@ -822,7 +824,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
/* Set to true if this key will repeat. */
bool is_repeat_keycode = false;
- if (m_xkb_descr != NULL) {
+ if (m_xkb_descr != nullptr) {
/* Use XKB support. */
is_repeat_keycode = (
/* Should always be true, check just in case. */
@@ -954,8 +956,9 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
GHOST_Rect bounds;
/* fallback to window bounds */
- if (window->getCursorGrabBounds(bounds) == GHOST_kFailure)
+ if (window->getCursorGrabBounds(bounds) == GHOST_kFailure) {
window->getClientBounds(bounds);
+ }
/* Could also clamp to screen bounds wrap with a window outside the view will
* fail at the moment. Use offset of 8 in case the window is at screen bounds. */
@@ -1019,7 +1022,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
char *utf8_buf = utf8_array;
int len = 1; /* at least one null character will be stored */
#else
- char *utf8_buf = NULL;
+ char *utf8_buf = nullptr;
#endif
GHOST_TEventType type = (xke->type == KeyPress) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp;
@@ -1065,7 +1068,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
key_sym = XLookupKeysym(xke, 0);
}
- if (!XLookupString(xke, &ascii, 1, &key_sym_str, NULL)) {
+ if (!XLookupString(xke, &ascii, 1, &key_sym_str, nullptr)) {
ascii = '\0';
}
@@ -1117,7 +1120,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
#else
/* In keyboards like Latin ones,
* numbers needs a 'Shift' to be accessed but key_sym
- * is unmodified (or anyone swapping the keys with xmodmap).
+ * is unmodified (or anyone swapping the keys with `xmodmap`).
*
* Here we look at the 'Shifted' version of the key.
* If it is a number, then we take it instead of the normal key.
@@ -1135,7 +1138,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
gkey = ghost_key_from_keysym_or_keycode(key_sym, m_xkb_descr, xke->keycode);
- if (!XLookupString(xke, &ascii, 1, NULL, NULL)) {
+ if (!XLookupString(xke, &ascii, 1, nullptr, nullptr)) {
ascii = '\0';
}
#endif
@@ -1612,6 +1615,8 @@ GHOST_TSuccess GHOST_SystemX11::getButtons(GHOST_Buttons &buttons) const
buttons.set(GHOST_kButtonMaskLeft, (mask_return & Button1Mask) != 0);
buttons.set(GHOST_kButtonMaskMiddle, (mask_return & Button2Mask) != 0);
buttons.set(GHOST_kButtonMaskRight, (mask_return & Button3Mask) != 0);
+ buttons.set(GHOST_kButtonMaskButton4, (mask_return & Button4Mask) != 0);
+ buttons.set(GHOST_kButtonMaskButton5, (mask_return & Button5Mask) != 0);
}
else {
return GHOST_kFailure;
@@ -1713,7 +1718,7 @@ GHOST_TSuccess GHOST_SystemX11::setCursorPosition(int32_t x, int32_t y)
void GHOST_SystemX11::addDirtyWindow(GHOST_WindowX11 *bad_wind)
{
- GHOST_ASSERT((bad_wind != NULL), "addDirtyWindow() NULL ptr trapped (window)");
+ GHOST_ASSERT((bad_wind != nullptr), "addDirtyWindow() nullptr ptr trapped (window)");
m_dirty_windows.push_back(bad_wind);
}
@@ -2155,8 +2160,9 @@ char *GHOST_SystemX11::getClipboard(bool selection) const
return sel_buf;
}
}
- else if (owner == None)
- return NULL;
+ else if (owner == None) {
+ return nullptr;
+ }
/* Restore events so copy doesn't swallow other event types (keyboard/mouse). */
vector<XEvent> restore_events;
@@ -2222,7 +2228,7 @@ char *GHOST_SystemX11::getClipboard(bool selection) const
return tmp_data;
}
- return NULL;
+ return nullptr;
}
void GHOST_SystemX11::putClipboard(const char *buffer, bool selection) const
@@ -2350,14 +2356,16 @@ static void split(const char *text, const char *seps, char ***str, int *count)
*count = 0;
data = strdup(text);
- for (tok = strtok(data, seps); tok != NULL; tok = strtok(NULL, seps))
+ for (tok = strtok(data, seps); tok != nullptr; tok = strtok(nullptr, seps)) {
(*count)++;
+ }
free(data);
data = strdup(text);
*str = (char **)malloc((size_t)(*count) * sizeof(char *));
- for (i = 0, tok = strtok(data, seps); tok != NULL; tok = strtok(NULL, seps), i++)
+ for (i = 0, tok = strtok(data, seps); tok != nullptr; tok = strtok(nullptr, seps), i++) {
(*str)[i] = strdup(tok);
+ }
free(data);
}
@@ -2368,7 +2376,7 @@ GHOST_TSuccess GHOST_SystemX11::showMessageBox(const char *title,
const char *link,
GHOST_DialogOptions) const
{
- char **text_splitted = NULL;
+ char **text_splitted = nullptr;
int textLines = 0;
split(message, "\n", &text_splitted, &textLines);
@@ -2431,7 +2439,7 @@ GHOST_TSuccess GHOST_SystemX11::showMessageBox(const char *title,
XSelectInput(m_display, window, ExposureMask | ButtonPressMask | ButtonReleaseMask);
XMapWindow(m_display, window);
- while (1) {
+ while (true) {
XNextEvent(m_display, &e);
if (e.type == Expose) {
for (int i = 0; i < textLines; i++) {
@@ -2452,7 +2460,7 @@ GHOST_TSuccess GHOST_SystemX11::showMessageBox(const char *title,
if (dialog_data.isInsideButton(e, 1)) {
break;
}
- else if (dialog_data.isInsideButton(e, 2)) {
+ if (dialog_data.isInsideButton(e, 2)) {
if (strlen(link)) {
string cmd = "xdg-open \"" + string(link) + "\"";
if (system(cmd.c_str()) != 0) {
@@ -2492,7 +2500,7 @@ GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType,
}
#endif
/**
- * These callbacks can be used for debugging, so we can breakpoint on an X11 error.
+ * These callbacks can be used for debugging, so we can break-point on an X11 error.
*
* Dummy function to get around IO Handler exiting if device invalid
* Basically it will not crash blender now if you have a X device that
@@ -2578,19 +2586,19 @@ static bool match_token(const char *haystack, const char *needle)
static GHOST_TTabletMode tablet_mode_from_name(const char *name, const char *type)
{
int i;
- static const char *tablet_stylus_whitelist[] = {"stylus", "wizardpen", "acecad", "pen", NULL};
+ static const char *tablet_stylus_whitelist[] = {"stylus", "wizardpen", "acecad", "pen", nullptr};
- static const char *type_blacklist[] = {"pad", "cursor", "touch", NULL};
+ static const char *type_blacklist[] = {"pad", "cursor", "touch", nullptr};
/* Skip some known unsupported types. */
- for (i = 0; type_blacklist[i] != NULL; i++) {
+ for (i = 0; type_blacklist[i] != nullptr; i++) {
if (type && (strcasecmp(type, type_blacklist[i]) == 0)) {
return GHOST_kTabletModeNone;
}
}
/* First check device type to avoid cases where name is "Pen and Eraser" and type is "ERASER" */
- for (i = 0; tablet_stylus_whitelist[i] != NULL; i++) {
+ for (i = 0; tablet_stylus_whitelist[i] != nullptr; i++) {
if (type && match_token(type, tablet_stylus_whitelist[i])) {
return GHOST_kTabletModeStylus;
}
@@ -2598,7 +2606,7 @@ static GHOST_TTabletMode tablet_mode_from_name(const char *name, const char *typ
if (type && match_token(type, "eraser")) {
return GHOST_kTabletModeEraser;
}
- for (i = 0; tablet_stylus_whitelist[i] != NULL; i++) {
+ for (i = 0; tablet_stylus_whitelist[i] != nullptr; i++) {
if (name && match_token(name, tablet_stylus_whitelist[i])) {
return GHOST_kTabletModeStylus;
}
@@ -2627,7 +2635,7 @@ void GHOST_SystemX11::refreshXInputDevices()
for (int i = 0; i < device_count; ++i) {
char *device_type = device_info[i].type ? XGetAtomName(m_display, device_info[i].type) :
- NULL;
+ nullptr;
GHOST_TTabletMode tablet_mode = tablet_mode_from_name(device_info[i].name, device_type);
// printf("Tablet type:'%s', name:'%s', index:%d\n", device_type, device_info[i].name, i);
@@ -2644,15 +2652,15 @@ void GHOST_SystemX11::refreshXInputDevices()
xtablet.ID = device_info[i].id;
xtablet.Device = XOpenDevice(m_display, xtablet.ID);
- if (xtablet.Device != NULL) {
+ if (xtablet.Device != nullptr) {
/* Find how many pressure levels tablet has */
XAnyClassPtr ici = device_info[i].inputclassinfo;
- if (ici != NULL) {
+ if (ici != nullptr) {
for (int j = 0; j < device_info[i].num_classes; ++j) {
if (ici->c_class == ValuatorClass) {
XValuatorInfo *xvi = (XValuatorInfo *)ici;
- if (xvi->axes != NULL) {
+ if (xvi->axes != nullptr) {
xtablet.PressureLevels = xvi->axes[2].max_value;
if (xvi->num_axes > 3) {
diff --git a/intern/ghost/intern/GHOST_TaskbarX11.cpp b/intern/ghost/intern/GHOST_TaskbarX11.cpp
index 85ec5eb6943..1e568c3a2b0 100644
--- a/intern/ghost/intern/GHOST_TaskbarX11.cpp
+++ b/intern/ghost/intern/GHOST_TaskbarX11.cpp
@@ -11,10 +11,10 @@
#include <cstdlib>
#include <dlfcn.h>
-typedef void *(*unity_get_entry_t)(const char *);
-typedef void (*unity_set_progress_t)(void *, double);
-typedef void (*unity_set_progress_visible_t)(void *, int);
-typedef int (*unity_event_loop_t)(void *, int);
+using unity_get_entry_t = void *(*)(const char *);
+using unity_set_progress_t = void (*)(void *, double);
+using unity_set_progress_visible_t = void (*)(void *, int);
+using unity_event_loop_t = int (*)(void *, int);
static unity_get_entry_t unity_get_entry;
static unity_set_progress_t unity_set_progress;
@@ -23,13 +23,13 @@ static unity_event_loop_t unity_event_loop;
static bool libunity_initialized = false;
static bool libunity_available = false;
-static void *libunity_handle = NULL;
+static void *libunity_handle = nullptr;
void GHOST_TaskBarX11::free()
{
if (libunity_handle) {
dlclose(libunity_handle);
- libunity_handle = NULL;
+ libunity_handle = nullptr;
}
}
@@ -42,7 +42,7 @@ bool GHOST_TaskBarX11::init()
libunity_initialized = true;
const char *libunity_names[] = {
- "libunity.so.4", "libunity.so.6", "libunity.so.9", "libunity.so", NULL};
+ "libunity.so.4", "libunity.so.6", "libunity.so.9", "libunity.so", nullptr};
for (int i = 0; libunity_names[i]; i++) {
libunity_handle = dlopen(libunity_names[i], RTLD_LAZY);
if (libunity_handle) {
@@ -90,13 +90,13 @@ GHOST_TaskBarX11::GHOST_TaskBarX11(const char *name)
handle = unity_get_entry(name);
}
else {
- handle = NULL;
+ handle = nullptr;
}
}
bool GHOST_TaskBarX11::is_valid()
{
- return (handle != NULL);
+ return (handle != nullptr);
}
void GHOST_TaskBarX11::set_progress(double progress)
@@ -109,5 +109,5 @@ void GHOST_TaskBarX11::set_progress_enabled(bool enabled)
{
assert(is_valid());
unity_set_progress_visible(handle, enabled ? 1 : 0);
- unity_event_loop(NULL, 0);
+ unity_event_loop(nullptr, 0);
}
diff --git a/intern/ghost/intern/GHOST_TimerTask.h b/intern/ghost/intern/GHOST_TimerTask.h
index f59b832740f..8ca8e36837e 100644
--- a/intern/ghost/intern/GHOST_TimerTask.h
+++ b/intern/ghost/intern/GHOST_TimerTask.h
@@ -25,7 +25,7 @@ class GHOST_TimerTask : public GHOST_ITimerTask {
GHOST_TimerTask(uint64_t start,
uint64_t interval,
GHOST_TimerProcPtr timerProc,
- GHOST_TUserDataPtr userData = NULL)
+ GHOST_TUserDataPtr userData = nullptr)
: m_start(start),
m_interval(interval),
m_next(start),
diff --git a/intern/ghost/intern/GHOST_TrackpadWin32.cpp b/intern/ghost/intern/GHOST_TrackpadWin32.cpp
new file mode 100644
index 00000000000..d5317f0f780
--- /dev/null
+++ b/intern/ghost/intern/GHOST_TrackpadWin32.cpp
@@ -0,0 +1,343 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup GHOST
+ */
+
+#include <cmath>
+
+#include "GHOST_Debug.h"
+#include "GHOST_TrackpadWin32.h"
+
+GHOST_DirectManipulationHelper::GHOST_DirectManipulationHelper(
+ HWND hWnd,
+ Microsoft::WRL::ComPtr<IDirectManipulationManager> directManipulationManager,
+ Microsoft::WRL::ComPtr<IDirectManipulationUpdateManager> directManipulationUpdateManager,
+ Microsoft::WRL::ComPtr<IDirectManipulationViewport> directManipulationViewport,
+ Microsoft::WRL::ComPtr<GHOST_DirectManipulationViewportEventHandler>
+ directManipulationEventHandler,
+ DWORD directManipulationViewportHandlerCookie,
+ bool isScrollDirectionInverted)
+ : m_hWnd(hWnd),
+ m_scrollDirectionRegKey(NULL),
+ m_scrollDirectionChangeEvent(NULL),
+ m_directManipulationManager(directManipulationManager),
+ m_directManipulationUpdateManager(directManipulationUpdateManager),
+ m_directManipulationViewport(directManipulationViewport),
+ m_directManipulationEventHandler(directManipulationEventHandler),
+ m_directManipulationViewportHandlerCookie(directManipulationViewportHandlerCookie),
+ m_isScrollDirectionInverted(isScrollDirectionInverted)
+{
+}
+
+GHOST_DirectManipulationHelper *GHOST_DirectManipulationHelper::create(HWND hWnd, uint16_t dpi)
+{
+#define DM_CHECK_RESULT_AND_EXIT_EARLY(hr, failMessage) \
+ { \
+ if (!SUCCEEDED(hr)) { \
+ GHOST_PRINT(failMessage); \
+ return nullptr; \
+ } \
+ }
+
+ Microsoft::WRL::ComPtr<IDirectManipulationManager> directManipulationManager;
+ HRESULT hr = ::CoCreateInstance(CLSID_DirectManipulationManager,
+ nullptr,
+ CLSCTX_INPROC_SERVER,
+ IID_PPV_ARGS(&directManipulationManager));
+ DM_CHECK_RESULT_AND_EXIT_EARLY(hr, "DirectManipulationManager create failed\n");
+
+ /* Since we want to use fake viewport, we need to send fake updates to UpdateManager. */
+ Microsoft::WRL::ComPtr<IDirectManipulationUpdateManager> directManipulationUpdateManager;
+ hr = directManipulationManager->GetUpdateManager(IID_PPV_ARGS(&directManipulationUpdateManager));
+ DM_CHECK_RESULT_AND_EXIT_EARLY(hr, "Get UpdateManager failed\n");
+
+ Microsoft::WRL::ComPtr<IDirectManipulationViewport> directManipulationViewport;
+ hr = directManipulationManager->CreateViewport(
+ nullptr, hWnd, IID_PPV_ARGS(&directManipulationViewport));
+ DM_CHECK_RESULT_AND_EXIT_EARLY(hr, "Viewport create failed\n");
+
+ DIRECTMANIPULATION_CONFIGURATION configuration =
+ DIRECTMANIPULATION_CONFIGURATION_INTERACTION |
+ DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_X |
+ DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_Y |
+ DIRECTMANIPULATION_CONFIGURATION_TRANSLATION_INERTIA |
+ DIRECTMANIPULATION_CONFIGURATION_SCALING;
+
+ hr = directManipulationViewport->ActivateConfiguration(configuration);
+ DM_CHECK_RESULT_AND_EXIT_EARLY(hr, "Viewport set ActivateConfiguration failed\n");
+
+ /* Since we are using fake viewport and only want to use Direct Manipulation for touchpad, we
+ * need to use MANUALUPDATE option. */
+ hr = directManipulationViewport->SetViewportOptions(
+ DIRECTMANIPULATION_VIEWPORT_OPTIONS_MANUALUPDATE);
+ DM_CHECK_RESULT_AND_EXIT_EARLY(hr, "Viewport set ViewportOptions failed\n");
+
+ /* We receive Direct Manipulation transform updates in IDirectManipulationViewportEventHandler
+ * callbacks. */
+ Microsoft::WRL::ComPtr<GHOST_DirectManipulationViewportEventHandler>
+ directManipulationEventHandler =
+ Microsoft::WRL::Make<GHOST_DirectManipulationViewportEventHandler>(dpi);
+ DWORD directManipulationViewportHandlerCookie;
+ directManipulationViewport->AddEventHandler(
+ hWnd, directManipulationEventHandler.Get(), &directManipulationViewportHandlerCookie);
+ DM_CHECK_RESULT_AND_EXIT_EARLY(hr, "Viewport add EventHandler failed\n");
+
+ /* Set default rect for viewport before activating. */
+ RECT rect = {0, 0, 10000, 10000};
+ hr = directManipulationViewport->SetViewportRect(&rect);
+ DM_CHECK_RESULT_AND_EXIT_EARLY(hr, "Viewport set rect failed\n");
+
+ hr = directManipulationManager->Activate(hWnd);
+ DM_CHECK_RESULT_AND_EXIT_EARLY(hr, "DirectManipulationManager activate failed\n");
+
+ hr = directManipulationViewport->Enable();
+ DM_CHECK_RESULT_AND_EXIT_EARLY(hr, "Viewport enable failed\n");
+
+ directManipulationEventHandler->resetViewport(directManipulationViewport.Get());
+
+ bool isScrollDirectionInverted = getScrollDirectionFromReg();
+
+ auto instance = new GHOST_DirectManipulationHelper(hWnd,
+ directManipulationManager,
+ directManipulationUpdateManager,
+ directManipulationViewport,
+ directManipulationEventHandler,
+ directManipulationViewportHandlerCookie,
+ isScrollDirectionInverted);
+
+ instance->registerScrollDirectionChangeListener();
+
+ return instance;
+
+#undef DM_CHECK_RESULT_AND_EXIT_EARLY
+}
+
+bool GHOST_DirectManipulationHelper::getScrollDirectionFromReg()
+{
+ DWORD scrollDirectionRegValue, pcbData;
+ HRESULT hr = HRESULT_FROM_WIN32(
+ RegGetValueW(HKEY_CURRENT_USER,
+ L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\PrecisionTouchPad\\",
+ L"ScrollDirection",
+ RRF_RT_REG_DWORD,
+ NULL,
+ &scrollDirectionRegValue,
+ &pcbData));
+ if (!SUCCEEDED(hr)) {
+ GHOST_PRINT("Failed to get scroll direction from registry\n");
+ return false;
+ }
+
+ return scrollDirectionRegValue == 0;
+}
+
+void GHOST_DirectManipulationHelper::registerScrollDirectionChangeListener()
+{
+
+ if (!m_scrollDirectionRegKey) {
+ HRESULT hr = HRESULT_FROM_WIN32(
+ RegOpenKeyExW(HKEY_CURRENT_USER,
+ L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\PrecisionTouchPad\\",
+ 0,
+ KEY_NOTIFY,
+ &m_scrollDirectionRegKey));
+ if (!SUCCEEDED(hr)) {
+ GHOST_PRINT("Failed to open scroll direction registry key\n");
+ return;
+ }
+ }
+
+ if (!m_scrollDirectionChangeEvent) {
+ m_scrollDirectionChangeEvent = CreateEventW(NULL, true, false, NULL);
+ }
+ else {
+ ResetEvent(m_scrollDirectionChangeEvent);
+ }
+ HRESULT hr = HRESULT_FROM_WIN32(RegNotifyChangeKeyValue(m_scrollDirectionRegKey,
+ true,
+ REG_NOTIFY_CHANGE_LAST_SET,
+ m_scrollDirectionChangeEvent,
+ true));
+ if (!SUCCEEDED(hr)) {
+ GHOST_PRINT("Failed to register scroll direction change listener\n");
+ return;
+ }
+}
+
+void GHOST_DirectManipulationHelper::onPointerHitTest(UINT32 pointerId)
+{
+ [[maybe_unused]] HRESULT hr = m_directManipulationViewport->SetContact(pointerId);
+ GHOST_ASSERT(SUCCEEDED(hr), "Viewport set contact failed\n");
+
+ if (WaitForSingleObject(m_scrollDirectionChangeEvent, 0) == WAIT_OBJECT_0) {
+ m_isScrollDirectionInverted = getScrollDirectionFromReg();
+ registerScrollDirectionChangeListener();
+ }
+}
+
+void GHOST_DirectManipulationHelper::update()
+{
+ if (m_directManipulationEventHandler->dm_status == DIRECTMANIPULATION_RUNNING ||
+ m_directManipulationEventHandler->dm_status == DIRECTMANIPULATION_INERTIA) {
+ [[maybe_unused]] HRESULT hr = m_directManipulationUpdateManager->Update(nullptr);
+ GHOST_ASSERT(SUCCEEDED(hr), "DirectManipulationUpdateManager update failed\n");
+ }
+}
+
+void GHOST_DirectManipulationHelper::setDPI(uint16_t dpi)
+{
+ m_directManipulationEventHandler->dpi = dpi;
+}
+
+GHOST_TTrackpadInfo GHOST_DirectManipulationHelper::getTrackpadInfo()
+{
+ GHOST_TTrackpadInfo result = m_directManipulationEventHandler->accumulated_values;
+ result.isScrollDirectionInverted = m_isScrollDirectionInverted;
+
+ m_directManipulationEventHandler->accumulated_values = {0, 0, 0};
+ return result;
+}
+
+GHOST_DirectManipulationHelper::~GHOST_DirectManipulationHelper()
+{
+ HRESULT hr;
+ hr = m_directManipulationViewport->Stop();
+ GHOST_ASSERT(SUCCEEDED(hr), "Viewport stop failed\n");
+
+ hr = m_directManipulationViewport->RemoveEventHandler(m_directManipulationViewportHandlerCookie);
+ GHOST_ASSERT(SUCCEEDED(hr), "Viewport remove event handler failed\n");
+
+ hr = m_directManipulationViewport->Abandon();
+ GHOST_ASSERT(SUCCEEDED(hr), "Viewport abandon failed\n");
+
+ hr = m_directManipulationManager->Deactivate(m_hWnd);
+ GHOST_ASSERT(SUCCEEDED(hr), "DirectManipulationManager deactivate failed\n");
+
+ if (m_scrollDirectionChangeEvent) {
+ CloseHandle(m_scrollDirectionChangeEvent);
+ m_scrollDirectionChangeEvent = NULL;
+ }
+ if (m_scrollDirectionRegKey) {
+ RegCloseKey(m_scrollDirectionRegKey);
+ m_scrollDirectionRegKey = NULL;
+ }
+}
+
+GHOST_DirectManipulationViewportEventHandler::GHOST_DirectManipulationViewportEventHandler(
+ uint16_t dpi)
+ : accumulated_values({0, 0, 0}), dpi(dpi), dm_status(DIRECTMANIPULATION_BUILDING)
+{
+}
+
+void GHOST_DirectManipulationViewportEventHandler::resetViewport(
+ IDirectManipulationViewport *viewport)
+{
+ if (gesture_state != GESTURE_NONE) {
+ [[maybe_unused]] HRESULT hr = viewport->ZoomToRect(0.0f, 0.0f, 10000.0f, 10000.0f, FALSE);
+ GHOST_ASSERT(SUCCEEDED(hr), "Viewport reset failed\n");
+ }
+
+ gesture_state = GESTURE_NONE;
+
+ last_scale = PINCH_SCALE_FACTOR;
+ last_x = 0.0f;
+ last_y = 0.0f;
+}
+
+HRESULT GHOST_DirectManipulationViewportEventHandler::OnViewportStatusChanged(
+ IDirectManipulationViewport *viewport,
+ DIRECTMANIPULATION_STATUS current,
+ DIRECTMANIPULATION_STATUS previous)
+{
+ dm_status = current;
+
+ if (current == previous) {
+ return S_OK;
+ }
+
+ if (previous == DIRECTMANIPULATION_ENABLED || current == DIRECTMANIPULATION_READY ||
+ (previous == DIRECTMANIPULATION_INERTIA && current != DIRECTMANIPULATION_INERTIA)) {
+ resetViewport(viewport);
+ }
+
+ return S_OK;
+}
+
+HRESULT GHOST_DirectManipulationViewportEventHandler::OnViewportUpdated(
+ IDirectManipulationViewport *viewport)
+{
+ /* Nothing to do here. */
+ return S_OK;
+}
+
+HRESULT GHOST_DirectManipulationViewportEventHandler::OnContentUpdated(
+ IDirectManipulationViewport *viewport, IDirectManipulationContent *content)
+{
+ float transform[6];
+ HRESULT hr = content->GetContentTransform(transform, ARRAYSIZE(transform));
+ GHOST_ASSERT(SUCCEEDED(hr), "DirectManipulationContent get transform failed\n");
+
+ const float device_scale_factor = dpi / 96.0f;
+
+ const float scale = transform[0] * PINCH_SCALE_FACTOR;
+ const float x = transform[4] / device_scale_factor;
+ const float y = transform[5] / device_scale_factor;
+
+ const float EPS = 3e-5;
+
+ /* Ignore repeating or incorrect input. */
+ if ((fabs(scale - last_scale) <= EPS && fabs(x - last_x) <= EPS && fabs(y - last_y) <= EPS) ||
+ scale == 0.0f) {
+ GHOST_PRINT("Ignoring touchpad input\n");
+ return hr;
+ }
+
+ /* Assume that every gesture is a pan in the beginning.
+ * If it's a pinch, the gesture will be changed below. */
+ if (gesture_state == GESTURE_NONE) {
+ gesture_state = GESTURE_PAN;
+ }
+
+ /* DM doesn't always immediately recognize pinch gestures,
+ * so allow transition from pan to pinch. */
+ if (gesture_state == GESTURE_PAN) {
+ if (fabs(scale - PINCH_SCALE_FACTOR) > EPS) {
+ gesture_state = GESTURE_PINCH;
+ }
+ }
+
+ /* This state machine is used here because:
+ * 1. Pinch and pan gestures must be differentiated and cannot be processed at the same time
+ * because XY transform values become nonsensical during pinch gesture.
+ * 2. GHOST requires delta values for events while DM provides transformation matrix of the
+ * current gesture.
+ * 3. GHOST events accept integer values while DM values are non-integer.
+ * Truncated fractional parts are accumulated and accounted for in following updates.
+ */
+ switch (gesture_state) {
+ case GESTURE_PINCH: {
+ int32_t dscale = roundf(scale - last_scale);
+
+ last_scale += dscale;
+
+ accumulated_values.scale += dscale;
+ break;
+ }
+ case GESTURE_PAN: {
+ int32_t dx = roundf(x - last_x);
+ int32_t dy = roundf(y - last_y);
+
+ last_x += dx;
+ last_y += dy;
+
+ accumulated_values.x += dx;
+ accumulated_values.y += dy;
+ break;
+ }
+ case GESTURE_NONE:
+ break;
+ }
+
+ return hr;
+}
diff --git a/intern/ghost/intern/GHOST_TrackpadWin32.h b/intern/ghost/intern/GHOST_TrackpadWin32.h
new file mode 100644
index 00000000000..2e28f756965
--- /dev/null
+++ b/intern/ghost/intern/GHOST_TrackpadWin32.h
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup GHOST
+ * Declaration of GHOST DirectManipulation classes.
+ */
+
+#pragma once
+
+#ifndef WIN32
+# error WIN32 only!
+#endif // WIN32
+
+#include "GHOST_Types.h"
+
+#include <directmanipulation.h>
+#include <wrl.h>
+
+#define PINCH_SCALE_FACTOR 125.0f
+
+typedef struct {
+ int32_t x, y, scale;
+ bool isScrollDirectionInverted;
+} GHOST_TTrackpadInfo;
+
+class GHOST_DirectManipulationHelper;
+
+class GHOST_DirectManipulationViewportEventHandler
+ : public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::RuntimeClassType::ClassicCom>,
+ Microsoft::WRL::Implements<
+ Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::RuntimeClassType::ClassicCom>,
+ Microsoft::WRL::FtmBase,
+ IDirectManipulationViewportEventHandler>> {
+ public:
+ GHOST_DirectManipulationViewportEventHandler(uint16_t dpi);
+
+ /*
+ * Resets viewport and tracked touchpad state.
+ */
+ void resetViewport(IDirectManipulationViewport *viewport);
+
+ /* DirectManipulation callbacks. */
+ HRESULT STDMETHODCALLTYPE OnViewportStatusChanged(IDirectManipulationViewport *viewport,
+ DIRECTMANIPULATION_STATUS current,
+ DIRECTMANIPULATION_STATUS previous) override;
+
+ HRESULT STDMETHODCALLTYPE OnViewportUpdated(IDirectManipulationViewport *viewport) override;
+
+ HRESULT STDMETHODCALLTYPE OnContentUpdated(IDirectManipulationViewport *viewport,
+ IDirectManipulationContent *content) override;
+
+ private:
+ enum { GESTURE_NONE, GESTURE_PAN, GESTURE_PINCH } gesture_state;
+
+ int32_t last_x, last_y, last_scale;
+ GHOST_TTrackpadInfo accumulated_values;
+ uint16_t dpi;
+ DIRECTMANIPULATION_STATUS dm_status;
+
+ friend class GHOST_DirectManipulationHelper;
+};
+
+class GHOST_DirectManipulationHelper {
+ public:
+ /*
+ * Creates a GHOST_DirectManipulationHelper for the provided window.
+ * \param hWnd: The window receiving DirectManipulation events.
+ * \param dpi: The current DPI.
+ * \return Pointer to the new GHOST_DirectManipulationHelper if created, nullptr if there was an
+ * error.
+ */
+ static GHOST_DirectManipulationHelper *create(HWND hWnd, uint16_t dpi);
+
+ ~GHOST_DirectManipulationHelper();
+
+ /*
+ * Drives the DirectManipulation context.
+ * DirectManipulation's intended use is to tie user input into DirectComposition's compositor
+ * scaling and translating. We are not using DirectComposition and therefore must drive
+ * DirectManipulation manually.
+ */
+ void update();
+
+ /*
+ * Sets pointer in contact with the DirectManipulation context.
+ * \param pointerId: ID of the pointer in contact.
+ */
+ void onPointerHitTest(UINT32 pointerId);
+
+ /*
+ * Updates DPI information for touchpad scaling.
+ * \param dpi: The new DPI.
+ */
+ void setDPI(uint16_t dpi);
+
+ /*
+ * Retrieves trackpad input.
+ * \return The accumulated trackpad translation and scale since last call.
+ */
+ GHOST_TTrackpadInfo getTrackpadInfo();
+
+ private:
+ GHOST_DirectManipulationHelper(
+ HWND hWnd,
+ Microsoft::WRL::ComPtr<IDirectManipulationManager> directManipulationManager,
+ Microsoft::WRL::ComPtr<IDirectManipulationUpdateManager> directManipulationUpdateManager,
+ Microsoft::WRL::ComPtr<IDirectManipulationViewport> directManipulationViewport,
+ Microsoft::WRL::ComPtr<GHOST_DirectManipulationViewportEventHandler>
+ directManipulationEventHandler,
+ DWORD directManipulationViewportHandlerCookie,
+ bool isScrollDirectionInverted);
+
+ /*
+ * Retrieves the scroll direction from the registry.
+ * \return True if scroll direction is inverted.
+ */
+ static bool getScrollDirectionFromReg();
+
+ /*
+ * Registers listener for registry scroll direction entry changes.
+ */
+ void registerScrollDirectionChangeListener();
+
+ HWND m_hWnd;
+
+ HKEY m_scrollDirectionRegKey;
+ HANDLE m_scrollDirectionChangeEvent;
+
+ Microsoft::WRL::ComPtr<IDirectManipulationManager> m_directManipulationManager;
+ Microsoft::WRL::ComPtr<IDirectManipulationUpdateManager> m_directManipulationUpdateManager;
+ Microsoft::WRL::ComPtr<IDirectManipulationViewport> m_directManipulationViewport;
+ Microsoft::WRL::ComPtr<GHOST_DirectManipulationViewportEventHandler>
+ m_directManipulationEventHandler;
+ DWORD m_directManipulationViewportHandlerCookie;
+
+ bool m_isScrollDirectionInverted;
+};
diff --git a/intern/ghost/intern/GHOST_WaylandCursorSettings.h b/intern/ghost/intern/GHOST_WaylandCursorSettings.h
index 1e8cc2ac8a9..2491f6ca31f 100644
--- a/intern/ghost/intern/GHOST_WaylandCursorSettings.h
+++ b/intern/ghost/intern/GHOST_WaylandCursorSettings.h
@@ -28,7 +28,7 @@ static DBusMessage *get_setting_sync(DBusConnection *const connection,
message, DBUS_TYPE_STRING, &key, DBUS_TYPE_STRING, &value, DBUS_TYPE_INVALID);
if (!success) {
- return NULL;
+ return nullptr;
}
reply = dbus_connection_send_with_reply_and_block(
@@ -37,7 +37,7 @@ static DBusMessage *get_setting_sync(DBusConnection *const connection,
dbus_message_unref(message);
if (dbus_error_is_set(&error)) {
- return NULL;
+ return nullptr;
}
return reply;
@@ -76,7 +76,7 @@ static bool get_cursor_settings(std::string &theme, int &size)
DBusError error;
DBusConnection *connection;
DBusMessage *reply;
- const char *value_theme = NULL;
+ const char *value_theme = nullptr;
dbus_error_init(&error);
diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp
index 834836a7f4d..954f0bc244d 100644
--- a/intern/ghost/intern/GHOST_Window.cpp
+++ b/intern/ghost/intern/GHOST_Window.cpp
@@ -13,7 +13,7 @@
#include "GHOST_ContextNone.h"
-#include <assert.h>
+#include <cassert>
GHOST_Window::GHOST_Window(uint32_t width,
uint32_t height,
@@ -51,19 +51,19 @@ GHOST_Window::~GHOST_Window()
void *GHOST_Window::getOSWindow() const
{
- return NULL;
+ return nullptr;
}
GHOST_TSuccess GHOST_Window::setDrawingContextType(GHOST_TDrawingContextType type)
{
if (type != m_drawingContextType) {
delete m_context;
- m_context = NULL;
+ m_context = nullptr;
- if (type != GHOST_kDrawingContextTypeNone)
+ if (type != GHOST_kDrawingContextTypeNone) {
m_context = newDrawingContext(type);
-
- if (m_context != NULL) {
+ }
+ if (m_context != nullptr) {
m_drawingContextType = type;
}
else {
@@ -73,9 +73,7 @@ GHOST_TSuccess GHOST_Window::setDrawingContextType(GHOST_TDrawingContextType typ
return (type == m_drawingContextType) ? GHOST_kSuccess : GHOST_kFailure;
}
- else {
- return GHOST_kSuccess;
- }
+ return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_Window::swapBuffers()
@@ -119,9 +117,7 @@ GHOST_TSuccess GHOST_Window::setCursorVisibility(bool visible)
m_cursorVisible = visible;
return GHOST_kSuccess;
}
- else {
- return GHOST_kFailure;
- }
+ return GHOST_kFailure;
}
GHOST_TSuccess GHOST_Window::setCursorGrab(GHOST_TGrabCursorMode mode,
@@ -129,10 +125,10 @@ GHOST_TSuccess GHOST_Window::setCursorGrab(GHOST_TGrabCursorMode mode,
GHOST_Rect *bounds,
int32_t mouse_ungrab_xy[2])
{
- if (m_cursorGrab == mode)
+ if (m_cursorGrab == mode) {
return GHOST_kSuccess;
-
- /* override with new location */
+ }
+ /* Override with new location. */
if (mouse_ungrab_xy) {
assert(mode == GHOST_kGrabDisable);
m_cursorGrabInitPos[0] = mouse_ungrab_xy[0];
@@ -154,9 +150,7 @@ GHOST_TSuccess GHOST_Window::setCursorGrab(GHOST_TGrabCursorMode mode,
m_cursorGrabAxis = wrap_axis;
return GHOST_kSuccess;
}
- else {
- return GHOST_kFailure;
- }
+ return GHOST_kFailure;
}
GHOST_TSuccess GHOST_Window::getCursorGrabBounds(GHOST_Rect &bounds)
@@ -171,9 +165,7 @@ GHOST_TSuccess GHOST_Window::setCursorShape(GHOST_TStandardCursor cursorShape)
m_cursorShape = cursorShape;
return GHOST_kSuccess;
}
- else {
- return GHOST_kFailure;
- }
+ return GHOST_kFailure;
}
GHOST_TSuccess GHOST_Window::setCustomCursorShape(
@@ -183,9 +175,7 @@ GHOST_TSuccess GHOST_Window::setCustomCursorShape(
m_cursorShape = GHOST_kStandardCursorCustom;
return GHOST_kSuccess;
}
- else {
- return GHOST_kFailure;
- }
+ return GHOST_kFailure;
}
void GHOST_Window::setAcceptDragOperation(bool canAccept)
diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm
index 4a1b3c2fe16..e7f5fdaa011 100644
--- a/intern/ghost/intern/GHOST_WindowCocoa.mm
+++ b/intern/ghost/intern/GHOST_WindowCocoa.mm
@@ -426,8 +426,8 @@ GHOST_WindowCocoa::~GHOST_WindowCocoa()
[m_window close];
}
- // Check for other blender opened windows and make the frontmost key
- // Note: for some reason the closed window is still in the list
+ /* Check for other blender opened windows and make the front-most key
+ * NOTE: for some reason the closed window is still in the list. */
NSArray *windowsList = [NSApp orderedWindows];
for (int a = 0; a < [windowsList count]; a++) {
if (m_window != (CocoaWindow *)[windowsList objectAtIndex:a]) {
diff --git a/intern/ghost/intern/GHOST_WindowManager.cpp b/intern/ghost/intern/GHOST_WindowManager.cpp
index 28dd1bdb582..19684a44169 100644
--- a/intern/ghost/intern/GHOST_WindowManager.cpp
+++ b/intern/ghost/intern/GHOST_WindowManager.cpp
@@ -15,7 +15,7 @@
#include <algorithm>
GHOST_WindowManager::GHOST_WindowManager()
- : m_fullScreenWindow(0), m_activeWindow(0), m_activeWindowBeforeFullScreen(0)
+ : m_fullScreenWindow(nullptr), m_activeWindow(nullptr), m_activeWindowBeforeFullScreen(nullptr)
{
}
@@ -75,12 +75,12 @@ bool GHOST_WindowManager::getWindowFound(const GHOST_IWindow *window) const
return found;
}
-bool GHOST_WindowManager::getFullScreen(void) const
+bool GHOST_WindowManager::getFullScreen() const
{
- return m_fullScreenWindow != NULL;
+ return m_fullScreenWindow != nullptr;
}
-GHOST_IWindow *GHOST_WindowManager::getFullScreenWindow(void) const
+GHOST_IWindow *GHOST_WindowManager::getFullScreenWindow() const
{
return m_fullScreenWindow;
}
@@ -100,17 +100,17 @@ GHOST_TSuccess GHOST_WindowManager::beginFullScreen(GHOST_IWindow *window, bool
return success;
}
-GHOST_TSuccess GHOST_WindowManager::endFullScreen(void)
+GHOST_TSuccess GHOST_WindowManager::endFullScreen()
{
GHOST_TSuccess success = GHOST_kFailure;
if (getFullScreen()) {
- if (m_fullScreenWindow != NULL) {
+ if (m_fullScreenWindow != nullptr) {
// GHOST_PRINT("GHOST_WindowManager::endFullScreen(): deleting full-screen window\n");
setWindowInactive(m_fullScreenWindow);
m_fullScreenWindow->endFullScreen();
delete m_fullScreenWindow;
// GHOST_PRINT("GHOST_WindowManager::endFullScreen(): done\n");
- m_fullScreenWindow = NULL;
+ m_fullScreenWindow = nullptr;
if (m_activeWindowBeforeFullScreen) {
setActiveWindow(m_activeWindowBeforeFullScreen);
}
@@ -134,7 +134,7 @@ GHOST_TSuccess GHOST_WindowManager::setActiveWindow(GHOST_IWindow *window)
return success;
}
-GHOST_IWindow *GHOST_WindowManager::getActiveWindow(void) const
+GHOST_IWindow *GHOST_WindowManager::getActiveWindow() const
{
return m_activeWindow;
}
@@ -142,7 +142,7 @@ GHOST_IWindow *GHOST_WindowManager::getActiveWindow(void) const
void GHOST_WindowManager::setWindowInactive(const GHOST_IWindow *window)
{
if (window == m_activeWindow) {
- m_activeWindow = NULL;
+ m_activeWindow = nullptr;
}
}
@@ -156,11 +156,11 @@ GHOST_IWindow *GHOST_WindowManager::getWindowAssociatedWithOSWindow(void *osWind
std::vector<GHOST_IWindow *>::iterator iter;
for (iter = m_windows.begin(); iter != m_windows.end(); ++iter) {
- if ((*iter)->getOSWindow() == osWindow)
+ if ((*iter)->getOSWindow() == osWindow) {
return *iter;
+ }
}
-
- return NULL;
+ return nullptr;
}
bool GHOST_WindowManager::getAnyModifiedState()
@@ -169,8 +169,9 @@ bool GHOST_WindowManager::getAnyModifiedState()
std::vector<GHOST_IWindow *>::iterator iter;
for (iter = m_windows.begin(); iter != m_windows.end(); ++iter) {
- if ((*iter)->getModifiedState())
+ if ((*iter)->getModifiedState()) {
isAnyModified = true;
+ }
}
return isAnyModified;
diff --git a/intern/ghost/intern/GHOST_WindowNULL.h b/intern/ghost/intern/GHOST_WindowNULL.h
index 1cbca80a49c..01b50251d69 100644
--- a/intern/ghost/intern/GHOST_WindowNULL.h
+++ b/intern/ghost/intern/GHOST_WindowNULL.h
@@ -153,6 +153,6 @@ class GHOST_WindowNULL : public GHOST_Window {
*/
GHOST_Context *newDrawingContext(GHOST_TDrawingContextType type)
{
- return NULL;
+ return nullptr;
}
};
diff --git a/intern/ghost/intern/GHOST_WindowSDL.cpp b/intern/ghost/intern/GHOST_WindowSDL.cpp
index 7a9ff348b0a..09192d989e4 100644
--- a/intern/ghost/intern/GHOST_WindowSDL.cpp
+++ b/intern/ghost/intern/GHOST_WindowSDL.cpp
@@ -10,7 +10,7 @@
#include "GHOST_ContextSDL.h"
-#include <assert.h>
+#include <cassert>
GHOST_WindowSDL::GHOST_WindowSDL(GHOST_SystemSDL *system,
const char *title,
@@ -22,12 +22,12 @@ GHOST_WindowSDL::GHOST_WindowSDL(GHOST_SystemSDL *system,
GHOST_TDrawingContextType type,
const bool stereoVisual,
const bool exclusive,
- const GHOST_IWindow *parentWindow)
+ const GHOST_IWindow * /*parentWindow*/)
: GHOST_Window(width, height, state, stereoVisual, exclusive),
m_system(system),
m_valid_setup(false),
m_invalid_window(false),
- m_sdl_custom_cursor(NULL)
+ m_sdl_custom_cursor(nullptr)
{
/* creating the window _must_ come after setting attributes */
@@ -73,16 +73,16 @@ GHOST_Context *GHOST_WindowSDL::newDrawingContext(GHOST_TDrawingContextType type
GHOST_OPENGL_SDL_CONTEXT_FLAGS,
GHOST_OPENGL_SDL_RESET_NOTIFICATION_STRATEGY);
- if (context->initializeDrawingContext())
+ if (context->initializeDrawingContext()) {
return context;
- else
- delete context;
+ }
+ delete context;
}
- return NULL;
+ return nullptr;
}
-GHOST_TSuccess GHOST_WindowSDL::invalidate(void)
+GHOST_TSuccess GHOST_WindowSDL::invalidate()
{
if (m_invalid_window == false) {
m_system->addDirtyWindow(this);
@@ -120,12 +120,15 @@ GHOST_TWindowState GHOST_WindowSDL::getState() const
{
Uint32 flags = SDL_GetWindowFlags(m_sdl_win);
- if (flags & SDL_WINDOW_FULLSCREEN)
+ if (flags & SDL_WINDOW_FULLSCREEN) {
return GHOST_kWindowStateFullScreen;
- else if (flags & SDL_WINDOW_MAXIMIZED)
+ }
+ if (flags & SDL_WINDOW_MAXIMIZED) {
return GHOST_kWindowStateMaximized;
- else if (flags & SDL_WINDOW_MINIMIZED)
+ }
+ if (flags & SDL_WINDOW_MINIMIZED) {
return GHOST_kWindowStateMinimized;
+ }
return GHOST_kWindowStateNormal;
}
@@ -164,7 +167,7 @@ void GHOST_WindowSDL::getClientBounds(GHOST_Rect &bounds) const
GHOST_TSuccess GHOST_WindowSDL::setClientWidth(uint32_t width)
{
int height;
- SDL_GetWindowSize(m_sdl_win, NULL, &height);
+ SDL_GetWindowSize(m_sdl_win, nullptr, &height);
SDL_SetWindowSize(m_sdl_win, width, height);
return GHOST_kSuccess;
}
@@ -172,7 +175,7 @@ GHOST_TSuccess GHOST_WindowSDL::setClientWidth(uint32_t width)
GHOST_TSuccess GHOST_WindowSDL::setClientHeight(uint32_t height)
{
int width;
- SDL_GetWindowSize(m_sdl_win, &width, NULL);
+ SDL_GetWindowSize(m_sdl_win, &width, nullptr);
SDL_SetWindowSize(m_sdl_win, width, height);
return GHOST_kSuccess;
}
@@ -483,7 +486,7 @@ static unsigned char sdl_std_cursor_arrow[] = {
#define sdl_std_cursor_HOT_Y_arrow -14
/* end cursor data */
-static SDL_Cursor *sdl_std_cursor_array[(int)GHOST_kStandardCursorNumCursors] = {0};
+static SDL_Cursor *sdl_std_cursor_array[(int)GHOST_kStandardCursorNumCursors] = {nullptr};
/* utility function mostly a copy of SDL_CreateCursor but allows us to change
* color and supports blenders flipped bits */
@@ -505,7 +508,7 @@ static SDL_Cursor *sdl_ghost_CreateCursor(
/* Create the surface from a bitmap */
surface = SDL_CreateRGBSurface(0, w, h, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
if (!surface) {
- return NULL;
+ return nullptr;
}
for (y = 0; y < h; ++y) {
pixel = (Uint32 *)((Uint8 *)surface->pixels + y * surface->pitch);
@@ -539,7 +542,7 @@ static SDL_Cursor *sdl_ghost_CreateCursor(
/* TODO: this is currently never freed but it won't leak either. */
static SDL_Cursor *getStandardCursorShape(GHOST_TStandardCursor shape)
{
- if (sdl_std_cursor_array[0] == NULL) {
+ if (sdl_std_cursor_array[0] == nullptr) {
#define DEF_CURSOR(name, ind) \
{ \
sdl_std_cursor_array[(int)ind] = sdl_ghost_CreateCursor( \
@@ -549,7 +552,7 @@ static SDL_Cursor *getStandardCursorShape(GHOST_TStandardCursor shape)
sdl_std_cursor_HEIGHT_##name, \
(sdl_std_cursor_WIDTH_##name + (sdl_std_cursor_HOT_X_##name)) - 1, \
(sdl_std_cursor_HEIGHT_##name + (sdl_std_cursor_HOT_Y_##name)) - 1); \
- assert(sdl_std_cursor_array[(int)ind] != NULL); \
+ assert(sdl_std_cursor_array[(int)ind] != nullptr); \
} \
(void)0
@@ -581,7 +584,7 @@ static SDL_Cursor *getStandardCursorShape(GHOST_TStandardCursor shape)
return sdl_std_cursor_array[(int)shape];
}
-GHOST_TSuccess GHOST_WindowSDL::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
+GHOST_TSuccess GHOST_WindowSDL::setWindowCursorGrab(GHOST_TGrabCursorMode /*mode*/)
{
return GHOST_kSuccess;
}
@@ -589,7 +592,7 @@ GHOST_TSuccess GHOST_WindowSDL::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
GHOST_TSuccess GHOST_WindowSDL::setWindowCursorShape(GHOST_TStandardCursor shape)
{
SDL_Cursor *cursor = getStandardCursorShape(shape);
- if (cursor == NULL) {
+ if (cursor == nullptr) {
cursor = getStandardCursorShape(GHOST_kStandardCursorDefault);
}
@@ -602,15 +605,20 @@ GHOST_TSuccess GHOST_WindowSDL::hasCursorShape(GHOST_TStandardCursor shape)
return (getStandardCursorShape(shape)) ? GHOST_kSuccess : GHOST_kFailure;
}
-GHOST_TSuccess GHOST_WindowSDL::setWindowCustomCursorShape(
- uint8_t *bitmap, uint8_t *mask, int sizex, int sizey, int hotX, int hotY, bool canInvertColor)
+GHOST_TSuccess GHOST_WindowSDL::setWindowCustomCursorShape(uint8_t *bitmap,
+ uint8_t *mask,
+ int sizex,
+ int sizey,
+ int hotX,
+ int hotY,
+ bool /*canInvertColor*/)
{
if (m_sdl_custom_cursor) {
SDL_FreeCursor(m_sdl_custom_cursor);
}
m_sdl_custom_cursor = sdl_ghost_CreateCursor(
- (const Uint8 *)bitmap, (const Uint8 *)mask, sizex, sizex, hotX, hotY);
+ (const Uint8 *)bitmap, (const Uint8 *)mask, sizex, sizey, hotX, hotY);
SDL_SetCursor(m_sdl_custom_cursor);
return GHOST_kSuccess;
@@ -630,7 +638,7 @@ uint16_t GHOST_WindowSDL::getDPIHint()
}
float ddpi;
- if (SDL_GetDisplayDPI(displayIndex, &ddpi, NULL, NULL) != 0) {
+ if (SDL_GetDisplayDPI(displayIndex, &ddpi, nullptr, nullptr) != 0) {
return 96;
}
diff --git a/intern/ghost/intern/GHOST_WindowSDL.h b/intern/ghost/intern/GHOST_WindowSDL.h
index cdea7e0d0b6..5805febab65 100644
--- a/intern/ghost/intern/GHOST_WindowSDL.h
+++ b/intern/ghost/intern/GHOST_WindowSDL.h
@@ -109,7 +109,7 @@ class GHOST_WindowSDL : public GHOST_Window {
GHOST_TWindowState getState() const;
- GHOST_TSuccess setOrder(GHOST_TWindowOrder order)
+ GHOST_TSuccess setOrder(GHOST_TWindowOrder /*order*/)
{
// TODO
return GHOST_kSuccess;
diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp
index 7ae06623c91..f9f168f772d 100644
--- a/intern/ghost/intern/GHOST_WindowWayland.cpp
+++ b/intern/ghost/intern/GHOST_WindowWayland.cpp
@@ -134,8 +134,9 @@ static bool update_scale(GHOST_WindowWayland *window)
{
int scale = 0;
for (const output_t *output : window->outputs_active()) {
- if (output->scale > scale)
+ if (output->scale > scale) {
scale = output->scale;
+ }
}
if (scale > 0 && window->scale() != scale) {
@@ -320,7 +321,7 @@ int &GHOST_WindowWayland::scale()
GHOST_TSuccess GHOST_WindowWayland::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
{
- return m_system->setCursorGrab(mode, w->surface);
+ return m_system->setCursorGrab(mode, m_cursorGrab, w->surface);
}
GHOST_TSuccess GHOST_WindowWayland::setWindowCursorShape(GHOST_TStandardCursor shape)
@@ -453,12 +454,10 @@ GHOST_TWindowState GHOST_WindowWayland::getState() const
if (w->is_fullscreen) {
return GHOST_kWindowStateFullScreen;
}
- else if (w->is_maximised) {
+ if (w->is_maximised) {
return GHOST_kWindowStateMaximized;
}
- else {
- return GHOST_kWindowStateNormal;
- }
+ return GHOST_kWindowStateNormal;
}
GHOST_TSuccess GHOST_WindowWayland::invalidate()
@@ -525,10 +524,10 @@ GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType
GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
EGL_OPENGL_API);
- if (context->initializeDrawingContext())
+ if (context->initializeDrawingContext()) {
return context;
- else
- delete context;
+ }
+ delete context;
}
context = new GHOST_ContextEGL(this->m_system,
m_wantStereoVisual,
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index 2ce224b666b..2e17454d24f 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -16,9 +16,7 @@
#include "GHOST_ContextWGL.h"
-#ifdef WIN32_COMPOSITING
-# include <Dwmapi.h>
-#endif
+#include <Dwmapi.h>
#include <assert.h>
#include <math.h>
@@ -70,6 +68,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
m_normal_state(GHOST_kWindowStateNormal),
m_user32(::LoadLibrary("user32.dll")),
m_parentWindowHwnd(parentwindow ? parentwindow->m_hWnd : HWND_DESKTOP),
+ m_directManipulationHelper(NULL),
m_debug_context(is_debug)
{
DWORD style = parentwindow ?
@@ -172,6 +171,8 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
break;
}
+ ThemeRefresh();
+
::ShowWindow(m_hWnd, nCmdShow);
#ifdef WIN32_COMPOSITING
@@ -204,6 +205,42 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
/* Allow the showing of a progress bar on the taskbar. */
CoCreateInstance(
CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (LPVOID *)&m_Bar);
+
+ /* Initialize Direct Manipulation. */
+ m_directManipulationHelper = GHOST_DirectManipulationHelper::create(m_hWnd, getDPIHint());
+}
+
+void GHOST_WindowWin32::updateDirectManipulation()
+{
+ if (!m_directManipulationHelper) {
+ return;
+ }
+
+ m_directManipulationHelper->update();
+}
+
+void GHOST_WindowWin32::onPointerHitTest(WPARAM wParam)
+{
+ /* Only DM_POINTERHITTEST can be the first message of input sequence of touchpad input. */
+
+ if (!m_directManipulationHelper) {
+ return;
+ }
+
+ UINT32 pointerId = GET_POINTERID_WPARAM(wParam);
+ POINTER_INPUT_TYPE pointerType;
+ if (GetPointerType(pointerId, &pointerType) && pointerType == PT_TOUCHPAD) {
+ m_directManipulationHelper->onPointerHitTest(pointerId);
+ }
+}
+
+GHOST_TTrackpadInfo GHOST_WindowWin32::getTrackpadInfo()
+{
+ if (!m_directManipulationHelper) {
+ return {0, 0, 0};
+ }
+
+ return m_directManipulationHelper->getTrackpadInfo();
}
GHOST_WindowWin32::~GHOST_WindowWin32()
@@ -253,6 +290,9 @@ GHOST_WindowWin32::~GHOST_WindowWin32()
::DestroyWindow(m_hWnd);
m_hWnd = 0;
}
+
+ delete m_directManipulationHelper;
+ m_directManipulationHelper = NULL;
}
void GHOST_WindowWin32::adjustWindowRectForClosestMonitor(LPRECT win_rect,
@@ -282,7 +322,7 @@ void GHOST_WindowWin32::adjustWindowRectForClosestMonitor(LPRECT win_rect,
}
/* Adjust to allow for caption, borders, shadows, scaling, etc. Resulting values can be
- * correctly outside of monitor bounds. Note: You cannot specify WS_OVERLAPPED when calling. */
+ * correctly outside of monitor bounds. NOTE: You cannot specify #WS_OVERLAPPED when calling. */
if (fpAdjustWindowRectExForDpi) {
UINT dpiX, dpiY;
GetDpiForMonitor(hmonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
@@ -1016,6 +1056,32 @@ GHOST_TabletData GHOST_WindowWin32::getTabletData()
}
}
+void GHOST_WindowWin32::ThemeRefresh()
+{
+ DWORD lightMode;
+ DWORD pcbData = sizeof(lightMode);
+ if (RegGetValueW(HKEY_CURRENT_USER,
+ L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize\\",
+ L"AppsUseLightTheme",
+ RRF_RT_REG_DWORD,
+ NULL,
+ &lightMode,
+ &pcbData) == ERROR_SUCCESS) {
+ BOOL DarkMode = !lightMode;
+
+ /* 20 == DWMWA_USE_IMMERSIVE_DARK_MODE in Windows 11 SDK. This value was undocumented for
+ * Windows 10 versions 2004 and later, supported for Windows 11 Build 22000 and later. */
+ DwmSetWindowAttribute(this->m_hWnd, 20, &DarkMode, sizeof(DarkMode));
+ }
+}
+
+void GHOST_WindowWin32::updateDPI()
+{
+ if (m_directManipulationHelper) {
+ m_directManipulationHelper->setDPI(getDPIHint());
+ }
+}
+
uint16_t GHOST_WindowWin32::getDPIHint()
{
if (m_user32) {
diff --git a/intern/ghost/intern/GHOST_WindowWin32.h b/intern/ghost/intern/GHOST_WindowWin32.h
index d5f47871aff..c958a89ac48 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.h
+++ b/intern/ghost/intern/GHOST_WindowWin32.h
@@ -13,6 +13,7 @@
#endif // WIN32
#include "GHOST_TaskbarWin32.h"
+#include "GHOST_TrackpadWin32.h"
#include "GHOST_Window.h"
#include "GHOST_Wintab.h"
#ifdef WITH_INPUT_IME
@@ -286,6 +287,8 @@ class GHOST_WindowWin32 : public GHOST_Window {
return GHOST_kFailure;
}
+ void updateDPI();
+
uint16_t getDPIHint() override;
/** True if the mouse is either over or captured by the window. */
@@ -294,6 +297,9 @@ class GHOST_WindowWin32 : public GHOST_Window {
/** True if the window currently resizing. */
bool m_inLiveResize;
+ /** Called when OS colors change and when the window is created. */
+ void ThemeRefresh();
+
#ifdef WITH_INPUT_IME
GHOST_ImeWin32 *getImeInput()
{
@@ -305,6 +311,19 @@ class GHOST_WindowWin32 : public GHOST_Window {
void endIME();
#endif /* WITH_INPUT_IME */
+ /*
+ * Drive DirectManipulation context.
+ */
+ void updateDirectManipulation();
+
+ /*
+ * Handle DM_POINTERHITTEST events.
+ * \param wParam: wParam from the event.
+ */
+ void onPointerHitTest(WPARAM wParam);
+
+ GHOST_TTrackpadInfo getTrackpadInfo();
+
private:
/**
* \param type: The type of rendering context create.
@@ -388,6 +407,8 @@ class GHOST_WindowWin32 : public GHOST_Window {
HWND m_parentWindowHwnd;
+ GHOST_DirectManipulationHelper *m_directManipulationHelper;
+
#ifdef WITH_INPUT_IME
/** Handle input method editors event */
GHOST_ImeWin32 m_imeInput;
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp
index e2d23ceac0b..ac7a476c76f 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -44,19 +44,19 @@
#include <unistd.h>
#include <algorithm>
-#include <limits.h>
-#include <math.h>
+#include <climits>
+#include <cmath>
#include <string>
/* For obscure full screen mode stuff
* lifted verbatim from blut. */
-typedef struct {
+using MotifWmHints = struct {
long flags;
long functions;
long decorations;
long input_mode;
-} MotifWmHints;
+};
enum {
MWM_HINTS_FUNCTIONS = (1L << 0),
@@ -107,7 +107,7 @@ static XVisualInfo *x11_visualinfo_from_glx(Display *display,
int glx_major, glx_minor, glx_version; /* GLX version: major.minor */
int glx_attribs[64];
- *fbconfig = NULL;
+ *fbconfig = nullptr;
/* Set up the minimum attributes that we require and see if
* X can find us a visual matching those requirements. */
@@ -119,7 +119,7 @@ static XVisualInfo *x11_visualinfo_from_glx(Display *display,
__FILE__,
__LINE__);
- return NULL;
+ return nullptr;
}
glx_version = glx_major * 100 + glx_minor;
# ifndef WITH_X11_ALPHA
@@ -129,10 +129,10 @@ static XVisualInfo *x11_visualinfo_from_glx(Display *display,
# ifdef WITH_X11_ALPHA
if (needAlpha && glx_version >= 103 &&
(glXChooseFBConfig || (glXChooseFBConfig = (PFNGLXCHOOSEFBCONFIGPROC)glXGetProcAddressARB(
- (const GLubyte *)"glXChooseFBConfig")) != NULL) &&
+ (const GLubyte *)"glXChooseFBConfig")) != nullptr) &&
(glXGetVisualFromFBConfig ||
(glXGetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC)glXGetProcAddressARB(
- (const GLubyte *)"glXGetVisualFromFBConfig")) != NULL)) {
+ (const GLubyte *)"glXGetVisualFromFBConfig")) != nullptr)) {
GHOST_X11_GL_GetAttributes(glx_attribs, 64, stereoVisual, needAlpha, true);
@@ -177,7 +177,7 @@ static XVisualInfo *x11_visualinfo_from_glx(Display *display,
/* Any sample level or even zero, which means oversampling disabled, is good
* but we need a valid visual to continue */
- if (visual != NULL) {
+ if (visual != nullptr) {
return visual;
}
}
@@ -189,7 +189,7 @@ static XVisualInfo *x11_visualinfo_from_glx(Display *display,
__FILE__,
__LINE__);
- return NULL;
+ return nullptr;
}
#endif // WITH_GL_EGL
@@ -211,8 +211,8 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
const bool is_debug)
: GHOST_Window(width, height, state, stereoVisual, exclusive),
m_display(display),
- m_visualInfo(NULL),
- m_fbconfig(NULL),
+ m_visualInfo(nullptr),
+ m_fbconfig(nullptr),
m_normal_state(GHOST_kWindowStateNormal),
m_system(system),
m_invalid_window(false),
@@ -221,11 +221,11 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
m_visible_cursor(None),
m_taskbar("blender.desktop"),
#ifdef WITH_XDND
- m_dropTarget(NULL),
+ m_dropTarget(nullptr),
#endif
m_tabletData(GHOST_TABLET_DATA_NONE),
#if defined(WITH_X11_XINPUT) && defined(X_HAVE_UTF8_STRING)
- m_xic(NULL),
+ m_xic(nullptr),
#endif
m_valid_setup(false),
m_is_debug_context(is_debug)
@@ -240,13 +240,13 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
#endif
}
else {
- XVisualInfo tmp = {0};
+ XVisualInfo tmp = {nullptr};
int n;
m_visualInfo = XGetVisualInfo(m_display, 0, &tmp, &n);
}
/* caller needs to check 'getValid()' */
- if (m_visualInfo == NULL) {
+ if (m_visualInfo == nullptr) {
fprintf(stderr, "initial window could not find the GLX extension\n");
return;
}
@@ -477,7 +477,7 @@ static Bool destroyICCallback(XIC /*xic*/, XPointer ptr, XPointer /*data*/)
GHOST_PRINT("XIM input context destroyed\n");
if (ptr) {
- *(XIC *)ptr = NULL;
+ *(XIC *)ptr = nullptr;
}
/* Ignored by X11. */
return True;
@@ -505,12 +505,12 @@ bool GHOST_WindowX11::createX11_XIC()
GHOST_X11_RES_CLASS,
XNDestroyCallback,
&destroy,
- NULL);
+ nullptr);
if (!m_xic)
return false;
unsigned long fevent;
- XGetICValues(m_xic, XNFilterEvents, &fevent, NULL);
+ XGetICValues(m_xic, XNFilterEvents, &fevent, nullptr);
XSelectInput(m_display,
m_window,
ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask |
@@ -586,7 +586,7 @@ void GHOST_WindowX11::setTitle(const char *title)
std::string GHOST_WindowX11::getTitle() const
{
- char *name = NULL;
+ char *name = nullptr;
XFetchName(m_display, m_window, &name);
std::string title = name ? name : "untitled";
@@ -719,8 +719,9 @@ void GHOST_WindowX11::icccmSetState(int state)
{
XEvent xev;
- if (state != IconicState)
+ if (state != IconicState) {
return;
+ }
xev.xclient.type = ClientMessage;
xev.xclient.serial = 0;
@@ -737,7 +738,7 @@ void GHOST_WindowX11::icccmSetState(int state)
&xev);
}
-int GHOST_WindowX11::icccmGetState(void) const
+int GHOST_WindowX11::icccmGetState() const
{
struct {
CARD32 state;
@@ -748,7 +749,7 @@ int GHOST_WindowX11::icccmGetState(void) const
int ret, format_ret;
CARD32 st;
- prop_ret = NULL;
+ prop_ret = nullptr;
ret = XGetWindowProperty(m_display,
m_window,
m_system->m_atom.WM_STATE,
@@ -761,7 +762,7 @@ int GHOST_WindowX11::icccmGetState(void) const
&num_ret,
&bytes_after,
((unsigned char **)&prop_ret));
- if ((ret == Success) && (prop_ret != NULL) && (num_ret == 2)) {
+ if ((ret == Success) && (prop_ret != nullptr) && (num_ret == 2)) {
st = prop_ret->state;
}
else {
@@ -786,10 +787,12 @@ void GHOST_WindowX11::netwmMaximized(bool set)
xev.xclient.message_type = m_system->m_atom._NET_WM_STATE;
xev.xclient.format = 32;
- if (set == True)
+ if (set == True) {
xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
- else
+ }
+ else {
xev.xclient.data.l[0] = _NET_WM_STATE_REMOVE;
+ }
xev.xclient.data.l[1] = m_system->m_atom._NET_WM_STATE_MAXIMIZED_HORZ;
xev.xclient.data.l[2] = m_system->m_atom._NET_WM_STATE_MAXIMIZED_VERT;
@@ -802,7 +805,7 @@ void GHOST_WindowX11::netwmMaximized(bool set)
&xev);
}
-bool GHOST_WindowX11::netwmIsMaximized(void) const
+bool GHOST_WindowX11::netwmIsMaximized() const
{
Atom *prop_ret;
unsigned long bytes_after, num_ret, i;
@@ -810,7 +813,7 @@ bool GHOST_WindowX11::netwmIsMaximized(void) const
bool st;
int format_ret, ret, count;
- prop_ret = NULL;
+ prop_ret = nullptr;
st = False;
ret = XGetWindowProperty(m_display,
m_window,
@@ -840,8 +843,9 @@ bool GHOST_WindowX11::netwmIsMaximized(void) const
}
}
- if (prop_ret)
+ if (prop_ret) {
XFree(prop_ret);
+ }
return st;
}
@@ -856,10 +860,12 @@ void GHOST_WindowX11::netwmFullScreen(bool set)
xev.xclient.message_type = m_system->m_atom._NET_WM_STATE;
xev.xclient.format = 32;
- if (set == True)
+ if (set == True) {
xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
- else
+ }
+ else {
xev.xclient.data.l[0] = _NET_WM_STATE_REMOVE;
+ }
xev.xclient.data.l[1] = m_system->m_atom._NET_WM_STATE_FULLSCREEN;
xev.xclient.data.l[2] = 0;
@@ -872,7 +878,7 @@ void GHOST_WindowX11::netwmFullScreen(bool set)
&xev);
}
-bool GHOST_WindowX11::netwmIsFullScreen(void) const
+bool GHOST_WindowX11::netwmIsFullScreen() const
{
Atom *prop_ret;
unsigned long bytes_after, num_ret, i;
@@ -880,7 +886,7 @@ bool GHOST_WindowX11::netwmIsFullScreen(void) const
bool st;
int format_ret, ret;
- prop_ret = NULL;
+ prop_ret = nullptr;
st = False;
ret = XGetWindowProperty(m_display,
m_window,
@@ -903,8 +909,9 @@ bool GHOST_WindowX11::netwmIsFullScreen(void) const
}
}
- if (prop_ret)
+ if (prop_ret) {
XFree(prop_ret);
+ }
return st;
}
@@ -913,10 +920,12 @@ void GHOST_WindowX11::motifFullScreen(bool set)
MotifWmHints hints;
hints.flags = MWM_HINTS_DECORATIONS;
- if (set == True)
+ if (set == True) {
hints.decorations = 0;
- else
+ }
+ else {
hints.decorations = 1;
+ }
XChangeProperty(m_display,
m_window,
@@ -928,7 +937,7 @@ void GHOST_WindowX11::motifFullScreen(bool set)
4);
}
-bool GHOST_WindowX11::motifIsFullScreen(void) const
+bool GHOST_WindowX11::motifIsFullScreen() const
{
MotifWmHints *prop_ret;
unsigned long bytes_after, num_ret;
@@ -936,7 +945,7 @@ bool GHOST_WindowX11::motifIsFullScreen(void) const
bool state;
int format_ret, st;
- prop_ret = NULL;
+ prop_ret = nullptr;
state = False;
st = XGetWindowProperty(m_display,
m_window,
@@ -952,13 +961,15 @@ bool GHOST_WindowX11::motifIsFullScreen(void) const
(unsigned char **)&prop_ret);
if ((st == Success) && prop_ret) {
if (prop_ret->flags & MWM_HINTS_DECORATIONS) {
- if (!prop_ret->decorations)
+ if (!prop_ret->decorations) {
state = True;
+ }
}
}
- if (prop_ret)
+ if (prop_ret) {
XFree(prop_ret);
+ }
return state;
}
@@ -973,14 +984,18 @@ GHOST_TWindowState GHOST_WindowX11::getState() const
* In the Iconic and Withdrawn state, the window
* is unmapped, so only need return a Minimized state.
*/
- if ((state == IconicState) || (state == WithdrawnState))
+ if ((state == IconicState) || (state == WithdrawnState)) {
state_ret = GHOST_kWindowStateMinimized;
- else if (netwmIsFullScreen() == True)
+ }
+ else if (netwmIsFullScreen() == True) {
state_ret = GHOST_kWindowStateFullScreen;
- else if (motifIsFullScreen() == True)
+ }
+ else if (motifIsFullScreen() == True) {
state_ret = GHOST_kWindowStateFullScreen;
- else if (netwmIsMaximized() == True)
+ }
+ else if (netwmIsMaximized() == True) {
state_ret = GHOST_kWindowStateMaximized;
+ }
return state_ret;
}
@@ -990,8 +1005,9 @@ GHOST_TSuccess GHOST_WindowX11::setState(GHOST_TWindowState state)
bool is_max, is_full, is_motif_full;
cur_state = getState();
- if (state == (int)cur_state)
+ if (state == (int)cur_state) {
return GHOST_kSuccess;
+ }
if (cur_state != GHOST_kWindowStateMinimized) {
/*
@@ -1008,16 +1024,20 @@ GHOST_TSuccess GHOST_WindowX11::setState(GHOST_TWindowState state)
is_motif_full = motifIsFullScreen();
- if (state == GHOST_kWindowStateNormal)
+ if (state == GHOST_kWindowStateNormal) {
state = m_normal_state;
+ }
if (state == GHOST_kWindowStateNormal) {
- if (is_max == True)
+ if (is_max == True) {
netwmMaximized(False);
- if (is_full == True)
+ }
+ if (is_full == True) {
netwmFullScreen(False);
- if (is_motif_full == True)
+ }
+ if (is_motif_full == True) {
motifFullScreen(False);
+ }
icccmSetState(NormalState);
return GHOST_kSuccess;
}
@@ -1027,17 +1047,21 @@ GHOST_TSuccess GHOST_WindowX11::setState(GHOST_TWindowState state)
* We can't change to full screen if the window
* isn't mapped.
*/
- if (cur_state == GHOST_kWindowStateMinimized)
+ if (cur_state == GHOST_kWindowStateMinimized) {
return GHOST_kFailure;
+ }
m_normal_state = cur_state;
- if (is_max == True)
+ if (is_max == True) {
netwmMaximized(False);
- if (is_full == False)
+ }
+ if (is_full == False) {
netwmFullScreen(True);
- if (is_motif_full == False)
+ }
+ if (is_motif_full == False) {
motifFullScreen(True);
+ }
return GHOST_kSuccess;
}
@@ -1046,15 +1070,19 @@ GHOST_TSuccess GHOST_WindowX11::setState(GHOST_TWindowState state)
* We can't change to Maximized if the window
* isn't mapped.
*/
- if (cur_state == GHOST_kWindowStateMinimized)
+ if (cur_state == GHOST_kWindowStateMinimized) {
return GHOST_kFailure;
+ }
- if (is_full == True)
+ if (is_full == True) {
netwmFullScreen(False);
- if (is_motif_full == True)
+ }
+ if (is_motif_full == True) {
motifFullScreen(False);
- if (is_max == False)
+ }
+ if (is_max == False) {
netwmMaximized(True);
+ }
return GHOST_kSuccess;
}
@@ -1111,8 +1139,9 @@ GHOST_TSuccess GHOST_WindowX11::setOrder(GHOST_TWindowOrder order)
XGetWindowAttributes(m_display, m_window, &attr);
/* Minimized windows give bad match error. */
- if (attr.map_state == IsViewable)
+ if (attr.map_state == IsViewable) {
XSetInputFocus(m_display, m_window, RevertToPointerRoot, CurrentTime);
+ }
XFlush(m_display);
}
else if (order == GHOST_kWindowOrderBottom) {
@@ -1137,7 +1166,7 @@ bool GHOST_WindowX11::isDialog() const
bool st;
int format_ret, ret;
- prop_ret = NULL;
+ prop_ret = nullptr;
st = False;
ret = XGetWindowProperty(m_display,
m_window,
@@ -1272,7 +1301,7 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type
#if defined(WITH_GL_PROFILE_CORE)
{
const char *version_major = (char *)glewGetString(GLEW_VERSION_MAJOR);
- if (version_major != NULL && version_major[0] == '1') {
+ if (version_major != nullptr && version_major[0] == '1') {
fprintf(stderr, "Error: GLEW version 2.0 and above is required.\n");
abort();
}
@@ -1327,10 +1356,10 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type
GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
#endif
- if (context->initializeDrawingContext())
+ if (context->initializeDrawingContext()) {
return context;
- else
- delete context;
+ }
+ delete context;
}
#ifdef WITH_GL_EGL
@@ -1358,10 +1387,10 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type
GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY);
#endif
- if (context->initializeDrawingContext())
+ if (context->initializeDrawingContext()) {
return context;
- else
- delete context;
+ }
+ delete context;
/* Ugly, but we get crashes unless a whole bunch of systems are patched. */
fprintf(stderr, "Error! Unsupported graphics card or driver.\n");
@@ -1372,7 +1401,7 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type
exit(1);
}
- return NULL;
+ return nullptr;
}
GHOST_TSuccess GHOST_WindowX11::getStandardCursor(GHOST_TStandardCursor g_cursor, Cursor &xcursor)
@@ -1488,8 +1517,9 @@ GHOST_TSuccess GHOST_WindowX11::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
m_system->getCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
setCursorGrabAccum(0, 0);
- if (mode == GHOST_kGrabHide)
+ if (mode == GHOST_kGrabHide) {
setWindowCursorVisibility(false);
+ }
}
#ifdef GHOST_X11_GRAB
XGrabPointer(m_display,
@@ -1580,10 +1610,12 @@ GHOST_TSuccess GHOST_WindowX11::setWindowCustomCursorShape(uint8_t *bitmap,
Pixmap bitmap_pix, mask_pix;
XColor fg, bg;
- if (XAllocNamedColor(m_display, colormap, "White", &fg, &fg) == 0)
+ if (XAllocNamedColor(m_display, colormap, "White", &fg, &fg) == 0) {
return GHOST_kFailure;
- if (XAllocNamedColor(m_display, colormap, "Black", &bg, &bg) == 0)
+ }
+ if (XAllocNamedColor(m_display, colormap, "Black", &bg, &bg) == 0) {
return GHOST_kFailure;
+ }
if (m_custom_cursor) {
XFreeCursor(m_display, m_custom_cursor);
@@ -1631,8 +1663,9 @@ GHOST_TSuccess GHOST_WindowX11::beginFullScreen() const
int err;
err = XGrabKeyboard(m_display, m_window, False, GrabModeAsync, GrabModeAsync, CurrentTime);
- if (err != GrabSuccess)
+ if (err != GrabSuccess) {
printf("XGrabKeyboard failed %d\n", err);
+ }
err = XGrabPointer(m_display,
m_window,
@@ -1643,8 +1676,9 @@ GHOST_TSuccess GHOST_WindowX11::beginFullScreen() const
m_window,
None,
CurrentTime);
- if (err != GrabSuccess)
+ if (err != GrabSuccess) {
printf("XGrabPointer failed %d\n", err);
+ }
return GHOST_kSuccess;
}
@@ -1664,7 +1698,7 @@ uint16_t GHOST_WindowX11::getDPIHint()
if (resMan) {
XrmDatabase xrdb = XrmGetStringDatabase(resMan);
if (xrdb) {
- char *type = NULL;
+ char *type = nullptr;
XrmValue val;
int success = XrmGetResource(xrdb, "Xft.dpi", "Xft.Dpi", &type, &val);
@@ -1677,7 +1711,7 @@ uint16_t GHOST_WindowX11::getDPIHint()
XrmDestroyDatabase(xrdb);
}
- /* Fallback to calculating DPI using X reported DPI, set using xrandr --dpi */
+ /* Fallback to calculating DPI using X reported DPI, set using `xrandr --dpi`. */
XWindowAttributes attr;
if (!XGetWindowAttributes(m_display, m_window, &attr)) {
/* Failed to get window attributes, return X11 default DPI */
diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h
index 8cd2c9f94dd..fca19fb9731 100644
--- a/intern/guardedalloc/MEM_guardedalloc.h
+++ b/intern/guardedalloc/MEM_guardedalloc.h
@@ -55,8 +55,8 @@ extern void (*MEM_freeN)(void *vmemh);
#if 0 /* UNUSED */
/**
- * Return zero if memory is not in allocated list
- */
+ * Return zero if memory is not in allocated list
+ */
extern short (*MEM_testN)(void *vmemh);
#endif
diff --git a/intern/guardedalloc/intern/mallocn_guarded_impl.c b/intern/guardedalloc/intern/mallocn_guarded_impl.c
index acad413b4c1..8bf1680e6f8 100644
--- a/intern/guardedalloc/intern/mallocn_guarded_impl.c
+++ b/intern/guardedalloc/intern/mallocn_guarded_impl.c
@@ -54,7 +54,7 @@
# define DEBUG_MEMCOUNTER_ERROR_VAL 0
static int _mallocn_count = 0;
-/* breakpoint here */
+/* Break-point here. */
static void memcount_raise(const char *name)
{
fprintf(stderr, "%s: memcount-leak, %d\n", name, _mallocn_count);
diff --git a/intern/iksolver/intern/IK_QTask.cpp b/intern/iksolver/intern/IK_QTask.cpp
index caf9585a94e..80eda01b17f 100644
--- a/intern/iksolver/intern/IK_QTask.cpp
+++ b/intern/iksolver/intern/IK_QTask.cpp
@@ -116,7 +116,7 @@ void IK_QOrientationTask::ComputeJacobian(IK_QJacobian &jacobian)
}
// IK_QCenterOfMassTask
-// Note: implementation not finished!
+// NOTE: implementation not finished!
IK_QCenterOfMassTask::IK_QCenterOfMassTask(bool primary,
const IK_QSegment *segment,
diff --git a/intern/libmv/CMakeLists.txt b/intern/libmv/CMakeLists.txt
index f9fef9f7a29..e0ed68eb20e 100644
--- a/intern/libmv/CMakeLists.txt
+++ b/intern/libmv/CMakeLists.txt
@@ -26,7 +26,6 @@ if(WITH_LIBMV)
endif()
add_definitions(${GFLAGS_DEFINES})
add_definitions(${GLOG_DEFINES})
- add_definitions(${CERES_DEFINES})
add_definitions(-DLIBMV_GFLAGS_NAMESPACE=${GFLAGS_NAMESPACE})
list(APPEND INC
diff --git a/intern/libmv/bundle.sh b/intern/libmv/bundle.sh
index 6808e244c05..82293068745 100755
--- a/intern/libmv/bundle.sh
+++ b/intern/libmv/bundle.sh
@@ -124,7 +124,6 @@ if(WITH_LIBMV)
endif()
add_definitions(\${GFLAGS_DEFINES})
add_definitions(\${GLOG_DEFINES})
- add_definitions(\${CERES_DEFINES})
add_definitions(-DLIBMV_GFLAGS_NAMESPACE=\${GFLAGS_NAMESPACE})
list(APPEND INC
diff --git a/intern/libmv/libmv/multiview/euclidean_resection.h b/intern/libmv/libmv/multiview/euclidean_resection.h
index 3c4c3979ff6..cdb9b5af52e 100644
--- a/intern/libmv/libmv/multiview/euclidean_resection.h
+++ b/intern/libmv/libmv/multiview/euclidean_resection.h
@@ -118,7 +118,7 @@ void EuclideanResectionAnsarDaniilidis(const Mat2X& x_camera,
* This is the algorithm described in:
* "{EP$n$P: An Accurate $O(n)$ Solution to the P$n$P Problem", by V. Lepetit
* and F. Moreno-Noguer and P. Fua, IJCV 2009. vol. 81, no. 2
- * \note: the non-linear optimization is not implemented here.
+ * \note the non-linear optimization is not implemented here.
*/
bool EuclideanResectionEPnP(const Mat2X& x_camera,
const Mat3X& X_world,
diff --git a/intern/libmv/libmv/simple_pipeline/bundle.cc b/intern/libmv/libmv/simple_pipeline/bundle.cc
index e86c3bca57f..355c167d000 100644
--- a/intern/libmv/libmv/simple_pipeline/bundle.cc
+++ b/intern/libmv/libmv/simple_pipeline/bundle.cc
@@ -685,7 +685,7 @@ void EuclideanBundleCommonIntrinsics(const Tracks& tracks,
PackCamerasRotationAndTranslation(*reconstruction);
// Parameterization used to restrict camera motion for modal solvers.
- ceres::SubsetParameterization* constant_translation_parameterization = NULL;
+ ceres::SubsetManifold* constant_translation_manifold = NULL;
if (bundle_constraints & BUNDLE_NO_TRANSLATION) {
std::vector<int> constant_translation;
@@ -694,8 +694,8 @@ void EuclideanBundleCommonIntrinsics(const Tracks& tracks,
constant_translation.push_back(4);
constant_translation.push_back(5);
- constant_translation_parameterization =
- new ceres::SubsetParameterization(6, constant_translation);
+ constant_translation_manifold =
+ new ceres::SubsetManifold(6, constant_translation);
}
// Add residual blocks to the problem.
@@ -735,8 +735,7 @@ void EuclideanBundleCommonIntrinsics(const Tracks& tracks,
}
if (bundle_constraints & BUNDLE_NO_TRANSLATION) {
- problem.SetParameterization(current_camera_R_t,
- constant_translation_parameterization);
+ problem.SetManifold(current_camera_R_t, constant_translation_manifold);
}
zero_weight_tracks_flags[marker.track] = false;
@@ -787,11 +786,11 @@ void EuclideanBundleCommonIntrinsics(const Tracks& tracks,
#undef MAYBE_SET_CONSTANT
if (!constant_intrinsics.empty()) {
- ceres::SubsetParameterization* subset_parameterization =
- new ceres::SubsetParameterization(PackedIntrinsics::NUM_PARAMETERS,
- constant_intrinsics);
+ ceres::SubsetManifold* subset_parameterization =
+ new ceres::SubsetManifold(PackedIntrinsics::NUM_PARAMETERS,
+ constant_intrinsics);
- problem.SetParameterization(intrinsics_block, subset_parameterization);
+ problem.SetManifold(intrinsics_block, subset_parameterization);
}
}
diff --git a/intern/libmv/libmv/simple_pipeline/modal_solver.cc b/intern/libmv/libmv/simple_pipeline/modal_solver.cc
index 845b299e31e..206d264f1f8 100644
--- a/intern/libmv/libmv/simple_pipeline/modal_solver.cc
+++ b/intern/libmv/libmv/simple_pipeline/modal_solver.cc
@@ -180,7 +180,7 @@ void ModalSolver(const Tracks& tracks,
// NOTE: Parameterization is lazily initialized when it is really needed,
// and is re-used by all parameters block.
- ceres::LocalParameterization* quaternion_parameterization = NULL;
+ ceres::Manifold* quaternion_manifold = NULL;
int num_residuals = 0;
for (int i = 0; i < all_markers.size(); ++i) {
@@ -197,12 +197,11 @@ void ModalSolver(const Tracks& tracks,
&quaternion(0));
num_residuals++;
- if (quaternion_parameterization == NULL) {
- quaternion_parameterization = new ceres::QuaternionParameterization();
+ if (quaternion_manifold == NULL) {
+ quaternion_manifold = new ceres::QuaternionManifold();
}
- problem.SetParameterization(&quaternion(0),
- quaternion_parameterization);
+ problem.SetManifold(&quaternion(0), quaternion_manifold);
}
}
diff --git a/intern/opensubdiv/internal/evaluator/eval_output.h b/intern/opensubdiv/internal/evaluator/eval_output.h
index 57a9fab490f..e8480e8d816 100644
--- a/intern/opensubdiv/internal/evaluator/eval_output.h
+++ b/intern/opensubdiv/internal/evaluator/eval_output.h
@@ -107,6 +107,10 @@ class EvalOutputAPI::EvalOutput {
{
}
+ virtual void wrapSrcVertexDataBuffer(OpenSubdiv_Buffer * /*src_buffer*/)
+ {
+ }
+
virtual void fillFVarPatchArraysBuffer(const int /*face_varying_channel*/,
OpenSubdiv_Buffer * /*patch_arrays_buffer*/)
{
@@ -126,6 +130,11 @@ class EvalOutputAPI::EvalOutput {
OpenSubdiv_Buffer * /*src_buffer*/)
{
}
+
+ virtual bool hasVertexData() const
+ {
+ return false;
+ }
};
namespace {
@@ -367,15 +376,15 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput {
device_context_);
// Create evaluators for every face varying channel.
- face_varying_evaluators.reserve(all_face_varying_stencils.size());
+ face_varying_evaluators_.reserve(all_face_varying_stencils.size());
int face_varying_channel = 0;
for (const StencilTable *face_varying_stencils : all_face_varying_stencils) {
- face_varying_evaluators.push_back(new FaceVaryingEval(face_varying_channel,
- face_varying_stencils,
- face_varying_width,
- patch_table_,
- evaluator_cache_,
- device_context_));
+ face_varying_evaluators_.push_back(new FaceVaryingEval(face_varying_channel,
+ face_varying_stencils,
+ face_varying_width,
+ patch_table_,
+ evaluator_cache_,
+ device_context_));
++face_varying_channel;
}
}
@@ -388,7 +397,7 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput {
delete patch_table_;
delete vertex_stencils_;
delete varying_stencils_;
- for (FaceVaryingEval *face_varying_evaluator : face_varying_evaluators) {
+ for (FaceVaryingEval *face_varying_evaluator : face_varying_evaluators_) {
delete face_varying_evaluator;
}
}
@@ -433,8 +442,8 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput {
int num_vertices) override
{
assert(face_varying_channel >= 0);
- assert(face_varying_channel < face_varying_evaluators.size());
- face_varying_evaluators[face_varying_channel]->updateData(src, start_vertex, num_vertices);
+ assert(face_varying_channel < face_varying_evaluators_.size());
+ face_varying_evaluators_[face_varying_channel]->updateData(src, start_vertex, num_vertices);
}
bool hasVaryingData() const
@@ -446,7 +455,12 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput {
bool hasFaceVaryingData() const
{
- return face_varying_evaluators.size() != 0;
+ return face_varying_evaluators_.size() != 0;
+ }
+
+ bool hasVertexData() const override
+ {
+ return src_vertex_data_ != nullptr;
}
void refine() override
@@ -495,7 +509,7 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput {
}
// Evaluate face-varying data.
if (hasFaceVaryingData()) {
- for (FaceVaryingEval *face_varying_evaluator : face_varying_evaluators) {
+ for (FaceVaryingEval *face_varying_evaluator : face_varying_evaluators_) {
face_varying_evaluator->refine();
}
}
@@ -601,8 +615,8 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput {
float face_varying[2]) override
{
assert(face_varying_channel >= 0);
- assert(face_varying_channel < face_varying_evaluators.size());
- face_varying_evaluators[face_varying_channel]->evalPatches(
+ assert(face_varying_channel < face_varying_evaluators_.size());
+ face_varying_evaluators_[face_varying_channel]->evalPatches(
patch_coord, num_patch_coords, face_varying);
}
@@ -611,6 +625,11 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput {
return src_data_;
}
+ SRC_VERTEX_BUFFER *getSrcVertexDataBuffer() const
+ {
+ return src_vertex_data_;
+ }
+
PATCH_TABLE *getPatchTable() const
{
return patch_table_;
@@ -618,17 +637,17 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput {
SRC_VERTEX_BUFFER *getFVarSrcBuffer(const int face_varying_channel) const
{
- return face_varying_evaluators[face_varying_channel]->getSrcBuffer();
+ return face_varying_evaluators_[face_varying_channel]->getSrcBuffer();
}
int getFVarSrcBufferOffset(const int face_varying_channel) const
{
- return face_varying_evaluators[face_varying_channel]->getFVarSrcBufferOffset();
+ return face_varying_evaluators_[face_varying_channel]->getFVarSrcBufferOffset();
}
PATCH_TABLE *getFVarPatchTable(const int face_varying_channel) const
{
- return face_varying_evaluators[face_varying_channel]->getPatchTable();
+ return face_varying_evaluators_[face_varying_channel]->getPatchTable();
}
private:
@@ -646,7 +665,7 @@ class VolatileEvalOutput : public EvalOutputAPI::EvalOutput {
const STENCIL_TABLE *varying_stencils_;
int face_varying_width_;
- vector<FaceVaryingEval *> face_varying_evaluators;
+ vector<FaceVaryingEval *> face_varying_evaluators_;
EvaluatorCache *evaluator_cache_;
DEVICE_CONTEXT *device_context_;
diff --git a/intern/opensubdiv/internal/evaluator/eval_output_cpu.h b/intern/opensubdiv/internal/evaluator/eval_output_cpu.h
index 58bae7a322e..42aa052863a 100644
--- a/intern/opensubdiv/internal/evaluator/eval_output_cpu.h
+++ b/intern/opensubdiv/internal/evaluator/eval_output_cpu.h
@@ -32,7 +32,7 @@ using OpenSubdiv::Osd::CpuVertexBuffer;
namespace blender {
namespace opensubdiv {
-// Note: Define as a class instead of typedef to make it possible
+// NOTE: Define as a class instead of typedef to make it possible
// to have anonymous class in opensubdiv_evaluator_internal.h
class CpuEvalOutput : public VolatileEvalOutput<CpuVertexBuffer,
CpuVertexBuffer,
diff --git a/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc b/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc
index b352ed2c014..b85272008e6 100644
--- a/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc
+++ b/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc
@@ -84,6 +84,12 @@ void GpuEvalOutput::wrapSrcBuffer(OpenSubdiv_Buffer *src_buffer)
src_buffer->wrap_device_handle(src_buffer, vertex_buffer->BindVBO());
}
+void GpuEvalOutput::wrapSrcVertexDataBuffer(OpenSubdiv_Buffer *src_buffer)
+{
+ GLVertexBuffer *vertex_buffer = getSrcVertexDataBuffer();
+ src_buffer->wrap_device_handle(src_buffer, vertex_buffer->BindVBO());
+}
+
void GpuEvalOutput::fillFVarPatchArraysBuffer(const int face_varying_channel,
OpenSubdiv_Buffer *patch_arrays_buffer)
{
diff --git a/intern/opensubdiv/internal/evaluator/eval_output_gpu.h b/intern/opensubdiv/internal/evaluator/eval_output_gpu.h
index dc137e4322e..e65bd51cac0 100644
--- a/intern/opensubdiv/internal/evaluator/eval_output_gpu.h
+++ b/intern/opensubdiv/internal/evaluator/eval_output_gpu.h
@@ -51,6 +51,8 @@ class GpuEvalOutput : public VolatileEvalOutput<GLVertexBuffer,
void wrapSrcBuffer(OpenSubdiv_Buffer *src_buffer) override;
+ void wrapSrcVertexDataBuffer(OpenSubdiv_Buffer *src_buffer) override;
+
void fillFVarPatchArraysBuffer(const int face_varying_channel,
OpenSubdiv_Buffer *patch_arrays_buffer) override;
diff --git a/intern/opensubdiv/internal/evaluator/evaluator_capi.cc b/intern/opensubdiv/internal/evaluator/evaluator_capi.cc
index b8d603ec380..7f30e0e5660 100644
--- a/intern/opensubdiv/internal/evaluator/evaluator_capi.cc
+++ b/intern/opensubdiv/internal/evaluator/evaluator_capi.cc
@@ -197,6 +197,12 @@ void wrapSrcBuffer(struct OpenSubdiv_Evaluator *evaluator, struct OpenSubdiv_Buf
evaluator->impl->eval_output->wrapSrcBuffer(src_buffer);
}
+void wrapSrcVertexDataBuffer(struct OpenSubdiv_Evaluator *evaluator,
+ struct OpenSubdiv_Buffer *src_buffer)
+{
+ evaluator->impl->eval_output->wrapSrcVertexDataBuffer(src_buffer);
+}
+
void fillFVarPatchArraysBuffer(struct OpenSubdiv_Evaluator *evaluator,
const int face_varying_channel,
struct OpenSubdiv_Buffer *patch_array_buffer)
@@ -226,6 +232,11 @@ void wrapFVarSrcBuffer(struct OpenSubdiv_Evaluator *evaluator,
evaluator->impl->eval_output->wrapFVarSrcBuffer(face_varying_channel, src_buffer);
}
+bool hasVertexData(struct OpenSubdiv_Evaluator *evaluator)
+{
+ return evaluator->impl->eval_output->hasVertexData();
+}
+
void assignFunctionPointers(OpenSubdiv_Evaluator *evaluator)
{
evaluator->setSettings = setSettings;
@@ -254,11 +265,14 @@ void assignFunctionPointers(OpenSubdiv_Evaluator *evaluator)
evaluator->wrapPatchIndexBuffer = wrapPatchIndexBuffer;
evaluator->wrapPatchParamBuffer = wrapPatchParamBuffer;
evaluator->wrapSrcBuffer = wrapSrcBuffer;
+ evaluator->wrapSrcVertexDataBuffer = wrapSrcVertexDataBuffer;
evaluator->fillFVarPatchArraysBuffer = fillFVarPatchArraysBuffer;
evaluator->wrapFVarPatchIndexBuffer = wrapFVarPatchIndexBuffer;
evaluator->wrapFVarPatchParamBuffer = wrapFVarPatchParamBuffer;
evaluator->wrapFVarSrcBuffer = wrapFVarSrcBuffer;
+
+ evaluator->hasVertexData = hasVertexData;
}
} // namespace
diff --git a/intern/opensubdiv/internal/evaluator/evaluator_impl.cc b/intern/opensubdiv/internal/evaluator/evaluator_impl.cc
index 0b8baa754d4..49a59c44be8 100644
--- a/intern/opensubdiv/internal/evaluator/evaluator_impl.cc
+++ b/intern/opensubdiv/internal/evaluator/evaluator_impl.cc
@@ -388,6 +388,11 @@ void EvalOutputAPI::wrapSrcBuffer(OpenSubdiv_Buffer *src_buffer)
implementation_->wrapSrcBuffer(src_buffer);
}
+void EvalOutputAPI::wrapSrcVertexDataBuffer(OpenSubdiv_Buffer *src_buffer)
+{
+ implementation_->wrapSrcVertexDataBuffer(src_buffer);
+}
+
void EvalOutputAPI::fillFVarPatchArraysBuffer(const int face_varying_channel,
OpenSubdiv_Buffer *patch_arrays_buffer)
{
@@ -412,6 +417,11 @@ void EvalOutputAPI::wrapFVarSrcBuffer(const int face_varying_channel,
implementation_->wrapFVarSrcBuffer(face_varying_channel, src_buffer);
}
+bool EvalOutputAPI::hasVertexData() const
+{
+ return implementation_->hasVertexData();
+}
+
} // namespace opensubdiv
} // namespace blender
@@ -569,7 +579,7 @@ OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal(
evaluator_descr->eval_output = new blender::opensubdiv::EvalOutputAPI(eval_output, patch_map);
evaluator_descr->patch_map = patch_map;
evaluator_descr->patch_table = patch_table;
- // TOOD(sergey): Look into whether we've got duplicated stencils arrays.
+ // TODO(sergey): Look into whether we've got duplicated stencils arrays.
delete vertex_stencils;
delete varying_stencils;
for (const StencilTable *table : all_face_varying_stencils) {
diff --git a/intern/opensubdiv/internal/evaluator/evaluator_impl.h b/intern/opensubdiv/internal/evaluator/evaluator_impl.h
index dbd786c8524..a7e3d5dff59 100644
--- a/intern/opensubdiv/internal/evaluator/evaluator_impl.h
+++ b/intern/opensubdiv/internal/evaluator/evaluator_impl.h
@@ -166,6 +166,9 @@ class EvalOutputAPI {
// Wrap the buffer used by OpenSubDiv for the source data with the given buffer.
void wrapSrcBuffer(OpenSubdiv_Buffer *src_buffer);
+ // Wrap the buffer used by OpenSubDiv for the extra source data with the given buffer.
+ void wrapSrcVertexDataBuffer(OpenSubdiv_Buffer *src_buffer);
+
// Copy the patch arrays buffer used by OpenSubDiv for the face varying channel with the given
// buffer.
void fillFVarPatchArraysBuffer(const int face_varying_channel,
@@ -184,6 +187,9 @@ class EvalOutputAPI {
// Wrap thebuffer used by OpenSubDiv for the face varying channel with the given buffer.
void wrapFVarSrcBuffer(const int face_varying_channel, OpenSubdiv_Buffer *src_buffer);
+ // Return true if source vertex data has been set.
+ bool hasVertexData() const;
+
protected:
PatchMap *patch_map_;
EvalOutput *implementation_;
diff --git a/intern/opensubdiv/opensubdiv_evaluator_capi.h b/intern/opensubdiv/opensubdiv_evaluator_capi.h
index 7dcf85cca8d..6d94141e755 100644
--- a/intern/opensubdiv/opensubdiv_evaluator_capi.h
+++ b/intern/opensubdiv/opensubdiv_evaluator_capi.h
@@ -204,6 +204,10 @@ typedef struct OpenSubdiv_Evaluator {
void (*wrapSrcBuffer)(struct OpenSubdiv_Evaluator *evaluator,
struct OpenSubdiv_Buffer *src_buffer);
+ // Fill the given buffer with data from the evaluator's extra source buffer.
+ void (*wrapSrcVertexDataBuffer)(struct OpenSubdiv_Evaluator *evaluator,
+ struct OpenSubdiv_Buffer *src_buffer);
+
// Fill the given buffer with data from the evaluator's face varying patch array buffer.
void (*fillFVarPatchArraysBuffer)(struct OpenSubdiv_Evaluator *evaluator,
const int face_varying_channel,
@@ -224,6 +228,9 @@ typedef struct OpenSubdiv_Evaluator {
const int face_varying_channel,
struct OpenSubdiv_Buffer *src_buffer);
+ // Return true if the evaluator has source vertex data set.
+ bool (*hasVertexData)(struct OpenSubdiv_Evaluator *evaluator);
+
// Implementation of the evaluator.
struct OpenSubdiv_EvaluatorImpl *impl;
diff --git a/intern/rigidbody/RBI_api.h b/intern/rigidbody/RBI_api.h
index 791a4a6ac05..13b1c096a80 100644
--- a/intern/rigidbody/RBI_api.h
+++ b/intern/rigidbody/RBI_api.h
@@ -14,7 +14,7 @@ extern "C" {
#endif
/* API Notes:
- * Currently, this API is optimised for Bullet RigidBodies, and doesn't
+ * Currently, this API is optimized for Bullet RigidBodies, and doesn't
* take into account other Physics Engines. Some tweaking may be necessary
* to allow other systems to be used, in particular there may be references
* to datatypes that aren't used here...