diff options
Diffstat (limited to 'intern')
108 files changed, 3144 insertions, 1254 deletions
diff --git a/intern/atomic/atomic_ops.h b/intern/atomic/atomic_ops.h index 6a4d6d263c0..2bedce1b4f0 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); diff --git a/intern/atomic/intern/atomic_ops_ext.h b/intern/atomic/intern/atomic_ops_ext.h index aedf0985169..6ecc47f18be 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; 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..ee06085c95d 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(); 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/properties.py b/intern/cycles/blender/addon/properties.py index 9b4799d252f..9acc9e99ad0 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -24,12 +24,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 +88,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 +105,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 +227,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 +390,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 +417,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 +430,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 +439,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 +452,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 +461,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 +589,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 +857,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 +1224,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 +1264,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..9d2dbdf6732 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -1082,8 +1082,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/image.cpp b/intern/cycles/blender/image.cpp index ca4c8f5904a..e01b72c1653 100644 --- a/intern/cycles/blender/image.cpp +++ b/intern/cycles/blender/image.cpp @@ -13,9 +13,11 @@ CCL_NAMESPACE_BEGIN 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. */ free_cache(!is_preview_render && !b_image.has_data()) @@ -66,12 +68,11 @@ bool BlenderImageLoader::load_pixels(const ImageMetaData &metadata, { 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); + image_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)); @@ -99,7 +100,7 @@ bool BlenderImageLoader::load_pixels(const ImageMetaData &metadata, } } else { - unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame, tile); + unsigned char *image_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)); @@ -153,7 +154,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 6908ae5ead3..75177566901 100644 --- a/intern/cycles/device/cuda/device_impl.cpp +++ b/intern/cycles/device/cuda/device_impl.cpp @@ -1084,7 +1084,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 7159277b325..f8fdb86ca29 100644 --- a/intern/cycles/device/hip/device_impl.cpp +++ b/intern/cycles/device/hip/device_impl.cpp @@ -1042,7 +1042,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..e1438a9d6e2 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) 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 9555ca03c8e..304efc813ec 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,376 @@ 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); +} + +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 +406,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 +499,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 +518,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,304 +545,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) { - 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 1686ab95ffa..ec10e091b25 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 { @@ -281,10 +286,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; @@ -314,7 +319,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, *)) { @@ -547,6 +552,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 8830d8c44ac..9fc265bc327 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) @@ -453,6 +473,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, @@ -461,6 +498,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(), 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/image.cpp b/intern/cycles/scene/image.cpp index 21fde88915e..2aa9a6bc1a1 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()) { @@ -266,6 +299,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 +382,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 +437,19 @@ ImageHandle ImageManager::add_image(ImageLoader *loader, return handle; } +ImageHandle ImageManager::add_image(const vector<ImageLoader *> &loaders, + const ImageParams ¶ms) +{ + 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 ¶ms, const bool builtin) @@ -749,7 +802,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 ¶ms, const array<int> &tiles); ImageHandle add_image(ImageLoader *loader, const ImageParams ¶ms, const bool builtin = true); + ImageHandle add_image(const vector<ImageLoader *> &loaders, const ImageParams ¶ms); 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..1b7f8f49696 100644 --- a/intern/cycles/scene/image_oiio.cpp +++ b/intern/cycles/scene/image_oiio.cpp @@ -199,6 +199,8 @@ bool OIIOImageLoader::load_pixels(const ImageMetaData &metadata, 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..d0b41a239df 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(); @@ -102,6 +118,7 @@ bool VDBImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMet openvdb::tools::pruneInactive(pruned_grid.tree()); nanogrid = nanovdb::openToNanoVDB(pruned_grid);*/ ToNanoOp op; + op.precision = precision; if (!openvdb::grid_type_operation(grid, op)) { return false; } @@ -124,7 +141,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_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/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/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..3569c9574f1 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); 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... |