Cycles: Use static assert to control structures alignment
authorSergey Sharybin <sergey.vfx@gmail.com>
Thu, 11 Aug 2016 07:52:39 +0000 (09:52 +0200)
committerSergey Sharybin <sergey.vfx@gmail.com>
Thu, 11 Aug 2016 08:12:06 +0000 (10:12 +0200)
intern/cycles/kernel/CMakeLists.txt
intern/cycles/kernel/kernel_types.h
intern/cycles/util/CMakeLists.txt
intern/cycles/util/util_debug.h
intern/cycles/util/util_static_assert.h [new file with mode: 0644]

index 7bef247d3bd667e6ce6169151f6cb7da7f4ec17f..9317bfbb703dd7dadf6f64b9eea4f3830a7a33b6 100644 (file)
@@ -176,6 +176,7 @@ set(SRC_UTIL_HEADERS
        ../util/util_half.h
        ../util/util_math.h
        ../util/util_math_fast.h
+       ../util/util_static_assert.h
        ../util/util_transform.h
        ../util/util_texture.h
        ../util/util_types.h
index 2ae42a83dc937ccaba6b490a1c8ea801a0cc23ff..a94d544b87316525cd8d1cc4ede7b3a8a7d8c439 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "kernel_math.h"
 #include "svm/svm_types.h"
+#include "util_static_assert.h"
 
 #ifndef __KERNEL_GPU__
 #  define __KERNEL_CPU__
@@ -986,6 +987,7 @@ typedef struct KernelCamera {
 
        int pad;
 } KernelCamera;
+static_assert_align(KernelCamera, 16);
 
 typedef struct KernelFilm {
        float exposure;
@@ -1040,6 +1042,7 @@ typedef struct KernelFilm {
        int pass_pad3;
 #endif
 } KernelFilm;
+static_assert_align(KernelFilm, 16);
 
 typedef struct KernelBackground {
        /* only shader index */
@@ -1053,6 +1056,7 @@ typedef struct KernelBackground {
        float ao_distance;
        float ao_pad1, ao_pad2;
 } KernelBackground;
+static_assert_align(KernelBackground, 16);
 
 typedef struct KernelIntegrator {
        /* emission */
@@ -1123,6 +1127,7 @@ typedef struct KernelIntegrator {
        int pad1;
        int pad2;
 } KernelIntegrator;
+static_assert_align(KernelIntegrator, 16);
 
 typedef struct KernelBVH {
        /* root node */
@@ -1134,6 +1139,7 @@ typedef struct KernelBVH {
        int use_qbvh;
        int pad1, pad2;
 } KernelBVH;
+static_assert_align(KernelBVH, 16);
 
 typedef enum CurveFlag {
        /* runtime flags */
@@ -1153,11 +1159,13 @@ typedef struct KernelCurves {
        float minimum_width;
        float maximum_width;
 } KernelCurves;
+static_assert_align(KernelCurves, 16);
 
 typedef struct KernelTables {
        int beckmann_offset;
        int pad1, pad2, pad3;
 } KernelTables;
+static_assert_align(KernelTables, 16);
 
 typedef struct KernelData {
        KernelCamera cam;
@@ -1168,8 +1176,12 @@ typedef struct KernelData {
        KernelCurves curve;
        KernelTables tables;
 } KernelData;
+static_assert_align(KernelData, 16);
 
 #ifdef __KERNEL_DEBUG__
+/* NOTE: This is a runtime-only struct, alignment is not
+ * really important here.
+ */
 typedef ccl_addr_space struct DebugData {
        // Total number of BVH node traversal steps and primitives intersections
        // for the camera rays.
index e6140b3ed0915b02cbc5387cc3e1ef4d2c48ca36..7eb5a9c7c6408f0f1e9fee174c967cbb9a50bcdf 100644 (file)
@@ -71,6 +71,7 @@ set(SRC_HEADERS
        util_ssef.h
        util_ssei.h
        util_stack_allocator.h
+       util_static_assert.h
        util_stats.h
        util_string.h
        util_system.h
index 1787ff648ee343efec606fabcee280f0afb6cd47..73fd228b5d9c267d33f3572bd468e0ab8e86663c 100644 (file)
@@ -20,6 +20,8 @@
 #include <cassert>
 #include <iostream>
 
+#include "util_static_assert.h"
+
 CCL_NAMESPACE_BEGIN
 
 /* Global storage for all sort of flags used to fine-tune behavior of particular
diff --git a/intern/cycles/util/util_static_assert.h b/intern/cycles/util/util_static_assert.h
new file mode 100644 (file)
index 0000000..1b94570
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UTIL_STATIC_ASSERT_H__
+#define __UTIL_STATIC_ASSERT_H__
+
+CCL_NAMESPACE_BEGIN
+
+/* TODO(sergey): In theory CUDA might work with own static assert
+ * implementation since it's just pure C++.
+ */
+#ifndef __KERNEL_GPU__
+#  if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
+/* C++11 has built-in static_assert() */
+#  else  /* C++11 or MSVC2015 */
+template <bool Test> class StaticAssertFailure;
+template <> class StaticAssertFailure<true> {};
+#    define _static_assert_private_glue_impl(A, B) A ## B
+#    define _static_assert_glue(A, B) _static_assert_private_glue_impl(A, B)
+#    ifdef __COUNTER__
+#      define static_assert(condition, message) \
+  enum {_static_assert_glue(q_static_assert_result, __COUNTER__) = sizeof(StaticAssertFailure<!!(condition)>)}  // NOLINT
+#    else  /* __COUNTER__ */
+#      define static_assert(condition, message) \
+  enum {_static_assert_glue(q_static_assert_result, __LINE__) = sizeof(StaticAssertFailure<!!(condition)>)}  // NOLINT
+#    endif  /* __COUNTER__ */
+#  endif  /* C++11 or MSVC2015 */
+#else  /* __KERNEL_GPU__ */
+#  define static_assert(statement, message)
+#endif  /* __KERNEL_GPU__ */
+
+/* TODO(sergey): For until C++11 is a bare minimum for us,
+ * we do a bit of a trickery to show meaningful message so
+ * it's more or less clear what's wrong when building without
+ * C++11.
+ *
+ * The thing here is: our non-C++11 implementation doesn't
+ * have a way to print any message after preprocessor
+ * substitution so we rely on the message which is passed to
+ * static_assert() since that's the only message visible when
+ * compilation fails.
+ *
+ * After C++11 bump it should be possible to glue structure
+ * name to the error message,
+ */
+#  define static_assert_align(st, align) \
+  static_assert((sizeof(st) % (align) == 0), "Structure must be strictly aligned")  // NOLINT
+
+CCL_NAMESPACE_END
+
+#endif /* __UTIL_STATIC_ASSERT_H__ */