/*
 * Copyright 2011-2013 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 __KERNEL_TYPES_H__
#define __KERNEL_TYPES_H__

#if !defined(__KERNEL_GPU__) && defined(WITH_EMBREE)
#  include <embree3/rtcore.h>
#  include <embree3/rtcore_scene.h>
#  define __EMBREE__
#endif

#include "kernel/kernel_math.h"
#include "kernel/svm/svm_types.h"
#include "util/util_static_assert.h"

#ifndef __KERNEL_GPU__
#  define __KERNEL_CPU__
#endif

/* TODO(sergey): This is only to make it possible to include this header
 * from outside of the kernel. but this could be done somewhat cleaner?
 */
#ifndef ccl_addr_space
#  define ccl_addr_space
#endif

CCL_NAMESPACE_BEGIN

/* Constants */
#define OBJECT_MOTION_PASS_SIZE 2
#define FILTER_TABLE_SIZE       1024
#define RAMP_TABLE_SIZE         256
#define SHUTTER_TABLE_SIZE      256

#define BSSRDF_MIN_RADIUS			1e-8f
#define BSSRDF_MAX_HITS				4
#define BSSRDF_MAX_BOUNCES			256
#define LOCAL_MAX_HITS				4

#define VOLUME_BOUNDS_MAX       1024

#define BECKMANN_TABLE_SIZE		256

#define SHADER_NONE				(~0)
#define OBJECT_NONE				(~0)
#define PRIM_NONE				(~0)
#define LAMP_NONE				(~0)
#define ID_NONE					(0.0f)

#define VOLUME_STACK_SIZE		32

/* Split kernel constants */
#define WORK_POOL_SIZE_GPU 64
#define WORK_POOL_SIZE_CPU 1
#ifdef __KERNEL_GPU__
#  define WORK_POOL_SIZE WORK_POOL_SIZE_GPU
#else
#  define WORK_POOL_SIZE WORK_POOL_SIZE_CPU
#endif


#define SHADER_SORT_BLOCK_SIZE 2048

#ifdef __KERNEL_OPENCL__
#  define SHADER_SORT_LOCAL_SIZE 64
#elif defined(__KERNEL_CUDA__)
#  define SHADER_SORT_LOCAL_SIZE 32
#else
#  define SHADER_SORT_LOCAL_SIZE 1
#endif

/* Kernel features */
#define __SOBOL__
#define __INSTANCING__
#define __DPDU__
#define __UV__
#define __BACKGROUND__
#define __CAUSTICS_TRICKS__
#define __VISIBILITY_FLAG__
#define __RAY_DIFFERENTIALS__
#define __CAMERA_CLIPPING__
#define __INTERSECTION_REFINE__
#define __CLAMP_SAMPLE__
#define __PATCH_EVAL__
#define __SHADOW_TRICKS__
#define __DENOISING_FEATURES__
#define __SHADER_RAYTRACE__
#define __AO__
#define __PASSES__
#define __HAIR__

/* Without these we get an AO render, used by OpenCL preview kernel. */
#ifndef __KERNEL_AO_PREVIEW__
#  define __SVM__
#  define __EMISSION__
#  define __TEXTURES__
#  define __EXTRA_NODES__
#  define __HOLDOUT__
#  define __MULTI_CLOSURE__
#  define __TRANSPARENT_SHADOWS__
#  define __BACKGROUND_MIS__
#  define __LAMP_MIS__
#  define __CAMERA_MOTION__
#  define __OBJECT_MOTION__
#  define __HAIR__
#  define __BAKING__
#  define __PRINCIPLED__
#  define __SUBSURFACE__
#  define __VOLUME__
#  define __VOLUME_SCATTER__
#  define __CMJ__
#  define __SHADOW_RECORD_ALL__
#  define __BRANCHED_PATH__
#endif

/* Device specific features */
#ifdef __KERNEL_CPU__
#  ifdef __KERNEL_SSE2__
#    define __QBVH__
#  endif
#  ifdef WITH_OSL
#    define __OSL__
#  endif
#  define __VOLUME_DECOUPLED__
#  define __VOLUME_RECORD_ALL__
#endif  /* __KERNEL_CPU__ */

#ifdef __KERNEL_CUDA__
#  ifdef __SPLIT_KERNEL__
#    undef __BRANCHED_PATH__
#  endif
#endif  /* __KERNEL_CUDA__ */

#ifdef __KERNEL_OPENCL__
#endif  /* __KERNEL_OPENCL__ */

/* Scene-based selective features compilation. */
#ifdef __NO_CAMERA_MOTION__
#  undef __CAMERA_MOTION__
#endif
#ifdef __NO_OBJECT_MOTION__
#  undef __OBJECT_MOTION__
#endif
#ifdef __NO_HAIR__
#  undef __HAIR__
#endif
#ifdef __NO_VOLUME__
#  undef __VOLUME__
#  undef __VOLUME_SCATTER__
#endif
#ifdef __NO_SUBSURFACE__
#  undef __SUBSURFACE__
#endif
#ifdef __NO_BAKING__
#  undef __BAKING__
#endif
#ifdef __NO_BRANCHED_PATH__
#  undef __BRANCHED_PATH__
#endif
#ifdef __NO_PATCH_EVAL__
#  undef __PATCH_EVAL__
#endif
#ifdef __NO_TRANSPARENT__
#  undef __TRANSPARENT_SHADOWS__
#endif
#ifdef __NO_SHADOW_TRICKS__
#  undef __SHADOW_TRICKS__
#endif
#ifdef __NO_PRINCIPLED__
#  undef __PRINCIPLED__
#endif
#ifdef __NO_DENOISING__
#  undef __DENOISING_FEATURES__
#endif
#ifdef __NO_SHADER_RAYTRACE__
#  undef __SHADER_RAYTRACE__
#endif

/* Features that enable others */
#ifdef WITH_CYCLES_DEBUG
#  define __KERNEL_DEBUG__
#endif

#if defined(__SUBSURFACE__) || defined(__SHADER_RAYTRACE__)
#  define __BVH_LOCAL__
#endif

/* Shader Evaluation */

typedef enum ShaderEvalType {
	SHADER_EVAL_DISPLACE,
	SHADER_EVAL_BACKGROUND,
	/* bake types */
	SHADER_EVAL_BAKE, /* no real shade, it's used in the code to
	                   * differentiate the type of shader eval from the above
	                   */
	/* data passes */
	SHADER_EVAL_NORMAL,
	SHADER_EVAL_UV,
	SHADER_EVAL_ROUGHNESS,
	SHADER_EVAL_DIFFUSE_COLOR,
	SHADER_EVAL_GLOSSY_COLOR,
	SHADER_EVAL_TRANSMISSION_COLOR,
	SHADER_EVAL_SUBSURFACE_COLOR,
	SHADER_EVAL_EMISSION,

	/* light passes */
	SHADER_EVAL_AO,
	SHADER_EVAL_COMBINED,
	SHADER_EVAL_SHADOW,
	SHADER_EVAL_DIFFUSE,
	SHADER_EVAL_GLOSSY,
	SHADER_EVAL_TRANSMISSION,
	SHADER_EVAL_SUBSURFACE,

	/* extra */
	SHADER_EVAL_ENVIRONMENT,
} ShaderEvalType;

/* Path Tracing
 * note we need to keep the u/v pairs at even values */

enum PathTraceDimension {
	PRNG_FILTER_U = 0,
	PRNG_FILTER_V = 1,
	PRNG_LENS_U = 2,
	PRNG_LENS_V = 3,
	PRNG_TIME = 4,
	PRNG_UNUSED_0 = 5,
	PRNG_UNUSED_1 = 6,	/* for some reason (6, 7) is a bad sobol pattern */
	PRNG_UNUSED_2 = 7,  /* with a low number of samples (< 64) */
	PRNG_BASE_NUM = 10,

	PRNG_BSDF_U = 0,
	PRNG_BSDF_V = 1,
	PRNG_LIGHT_U = 2,
	PRNG_LIGHT_V = 3,
	PRNG_LIGHT_TERMINATE = 4,
	PRNG_TERMINATE = 5,
	PRNG_PHASE_CHANNEL = 6,
	PRNG_SCATTER_DISTANCE = 7,
	PRNG_BOUNCE_NUM = 8,

	PRNG_BEVEL_U = 6, /* reuse volume dimension, correlation won't harm */
	PRNG_BEVEL_V = 7,
};

enum SamplingPattern {
	SAMPLING_PATTERN_SOBOL = 0,
	SAMPLING_PATTERN_CMJ = 1,

	SAMPLING_NUM_PATTERNS,
};

/* these flags values correspond to raytypes in osl.cpp, so keep them in sync! */

enum PathRayFlag {
	PATH_RAY_CAMERA              = (1 << 0),
	PATH_RAY_REFLECT             = (1 << 1),
	PATH_RAY_TRANSMIT            = (1 << 2),
	PATH_RAY_DIFFUSE             = (1 << 3),
	PATH_RAY_GLOSSY              = (1 << 4),
	PATH_RAY_SINGULAR            = (1 << 5),
	PATH_RAY_TRANSPARENT         = (1 << 6),

	PATH_RAY_SHADOW_OPAQUE_NON_CATCHER       = (1 << 7),
	PATH_RAY_SHADOW_OPAQUE_CATCHER           = (1 << 8),
	PATH_RAY_SHADOW_OPAQUE                   = (PATH_RAY_SHADOW_OPAQUE_NON_CATCHER|PATH_RAY_SHADOW_OPAQUE_CATCHER),
	PATH_RAY_SHADOW_TRANSPARENT_NON_CATCHER  = (1 << 9),
	PATH_RAY_SHADOW_TRANSPARENT_CATCHER      = (1 << 10),
	PATH_RAY_SHADOW_TRANSPARENT              = (PATH_RAY_SHADOW_TRANSPARENT_NON_CATCHER|PATH_RAY_SHADOW_TRANSPARENT_CATCHER),
	PATH_RAY_SHADOW_NON_CATCHER              = (PATH_RAY_SHADOW_OPAQUE_NON_CATCHER|PATH_RAY_SHADOW_TRANSPARENT_NON_CATCHER),
	PATH_RAY_SHADOW                          = (PATH_RAY_SHADOW_OPAQUE|PATH_RAY_SHADOW_TRANSPARENT),

	PATH_RAY_CURVE               = (1 << 11), /* visibility flag to define curve segments */
	PATH_RAY_VOLUME_SCATTER      = (1 << 12), /* volume scattering */

	/* Special flag to tag unaligned BVH nodes. */
	PATH_RAY_NODE_UNALIGNED = (1 << 13),

	PATH_RAY_ALL_VISIBILITY = ((1 << 14)-1),

	/* Don't apply multiple importance sampling weights to emission from
	 * lamp or surface hits, because they were not direct light sampled. */
	PATH_RAY_MIS_SKIP                    = (1 << 14),
	/* Diffuse bounce earlier in the path, skip SSS to improve performance
	 * and avoid branching twice with disk sampling SSS. */
	PATH_RAY_DIFFUSE_ANCESTOR            = (1 << 15),
	/* Single pass has been written. */
	PATH_RAY_SINGLE_PASS_DONE            = (1 << 16),
	/* Ray is behind a shadow catcher .*/
	PATH_RAY_SHADOW_CATCHER              = (1 << 17),
	/* Store shadow data for shadow catcher or denoising. */
	PATH_RAY_STORE_SHADOW_INFO           = (1 << 18),
	/* Zero background alpha, for camera or transparent glass rays. */
	PATH_RAY_TRANSPARENT_BACKGROUND      = (1 << 19),
	/* Terminate ray immediately at next bounce. */
	PATH_RAY_TERMINATE_IMMEDIATE         = (1 << 20),
	/* Ray is to be terminated, but continue with transparent bounces and
	 * emission as long as we encounter them. This is required to make the
	 * MIS between direct and indirect light rays match, as shadow rays go
	 * through transparent surfaces to reach emisison too. */
	PATH_RAY_TERMINATE_AFTER_TRANSPARENT = (1 << 21),
	/* Ray is to be terminated. */
	PATH_RAY_TERMINATE                   = (PATH_RAY_TERMINATE_IMMEDIATE|PATH_RAY_TERMINATE_AFTER_TRANSPARENT),
	/* Path and shader is being evaluated for direct lighting emission. */
	PATH_RAY_EMISSION                    = (1 << 22)
};

/* Closure Label */

typedef enum ClosureLabel {
	LABEL_NONE = 0,
	LABEL_TRANSMIT = 1,
	LABEL_REFLECT = 2,
	LABEL_DIFFUSE = 4,
	LABEL_GLOSSY = 8,
	LABEL_SINGULAR = 16,
	LABEL_TRANSPARENT = 32,
	LABEL_VOLUME_SCATTER = 64,
	LABEL_TRANSMIT_TRANSPARENT = 128,
} ClosureLabel;

/* Render Passes */

#define PASS_NAME_JOIN(a, b) a ## _ ## b
#define PASSMASK(pass) (1 << ((PASS_NAME_JOIN(PASS, pass)) % 32))

#define PASSMASK_COMPONENT(comp) (PASSMASK(PASS_NAME_JOIN(comp, DIRECT)) |   \
                                  PASSMASK(PASS_NAME_JOIN(comp, INDIRECT)) | \
                                  PASSMASK(PASS_NAME_JOIN(comp, COLOR)))

typedef enum PassType {
	PASS_NONE = 0,

	/* Main passes */
	PASS_COMBINED = 1,
	PASS_DEPTH,
	PASS_NORMAL,
	PASS_UV,
	PASS_OBJECT_ID,
	PASS_MATERIAL_ID,
	PASS_MOTION,
	PASS_MOTION_WEIGHT,
#ifdef __KERNEL_DEBUG__
	PASS_BVH_TRAVERSED_NODES,
	PASS_BVH_TRAVERSED_INSTANCES,
	PASS_BVH_INTERSECTIONS,
	PASS_RAY_BOUNCES,
#endif
	PASS_RENDER_TIME,
	PASS_CRYPTOMATTE,
	PASS_CATEGORY_MAIN_END = 31,

	PASS_MIST = 32,
	PASS_EMISSION,
	PASS_BACKGROUND,
	PASS_AO,
	PASS_SHADOW,
	PASS_LIGHT, /* no real pass, used to force use_light_pass */
	PASS_DIFFUSE_DIRECT,
	PASS_DIFFUSE_INDIRECT,
	PASS_DIFFUSE_COLOR,
	PASS_GLOSSY_DIRECT,
	PASS_GLOSSY_INDIRECT,
	PASS_GLOSSY_COLOR,
	PASS_TRANSMISSION_DIRECT,
	PASS_TRANSMISSION_INDIRECT,
	PASS_TRANSMISSION_COLOR,
	PASS_SUBSURFACE_DIRECT,
	PASS_SUBSURFACE_INDIRECT,
	PASS_SUBSURFACE_COLOR,
	PASS_VOLUME_DIRECT,
	PASS_VOLUME_INDIRECT,
	/* No Scatter color since it's tricky to define what it would even mean. */
	PASS_CATEGORY_LIGHT_END = 63,
} PassType;

#define PASS_ANY (~0)

typedef enum CryptomatteType {
	CRYPT_NONE = 0,
	CRYPT_OBJECT = (1 << 0),
	CRYPT_MATERIAL = (1 << 1),
	CRYPT_ASSET = (1 << 2),
	CRYPT_ACCURATE = (1 << 3),
} CryptomatteType;

typedef enum DenoisingPassOffsets {
	DENOISING_PASS_NORMAL             = 0,
	DENOISING_PASS_NORMAL_VAR         = 3,
	DENOISING_PASS_ALBEDO             = 6,
	DENOISING_PASS_ALBEDO_VAR         = 9,
	DENOISING_PASS_DEPTH              = 12,
	DENOISING_PASS_DEPTH_VAR          = 13,
	DENOISING_PASS_SHADOW_A           = 14,
	DENOISING_PASS_SHADOW_B           = 17,
	DENOISING_PASS_COLOR              = 20,
	DENOISING_PASS_COLOR_VAR          = 23,
	DENOISING_PASS_CLEAN              = 26,

	DENOISING_PASS_PREFILTERED_DEPTH     = 0,
	DENOISING_PASS_PREFILTERED_NORMAL    = 1,
	DENOISING_PASS_PREFILTERED_SHADOWING = 4,
	DENOISING_PASS_PREFILTERED_ALBEDO    = 5,
	DENOISING_PASS_PREFILTERED_COLOR     = 8,
	DENOISING_PASS_PREFILTERED_VARIANCE  = 11,
	DENOISING_PASS_PREFILTERED_INTENSITY = 14,

	DENOISING_PASS_SIZE_BASE          = 26,
	DENOISING_PASS_SIZE_CLEAN         = 3,
	DENOISING_PASS_SIZE_PREFILTERED   = 15,
} DenoisingPassOffsets;

typedef enum eBakePassFilter {
	BAKE_FILTER_NONE = 0,
	BAKE_FILTER_DIRECT = (1 << 0),
	BAKE_FILTER_INDIRECT = (1 << 1),
	BAKE_FILTER_COLOR = (1 << 2),
	BAKE_FILTER_DIFFUSE = (1 << 3),
	BAKE_FILTER_GLOSSY = (1 << 4),
	BAKE_FILTER_TRANSMISSION = (1 << 5),
	BAKE_FILTER_SUBSURFACE = (1 << 6),
	BAKE_FILTER_EMISSION = (1 << 7),
	BAKE_FILTER_AO = (1 << 8),
} eBakePassFilter;

typedef enum BakePassFilterCombos {
	BAKE_FILTER_COMBINED = (
	    BAKE_FILTER_DIRECT |
	    BAKE_FILTER_INDIRECT |
	    BAKE_FILTER_DIFFUSE |
	    BAKE_FILTER_GLOSSY |
	    BAKE_FILTER_TRANSMISSION |
	    BAKE_FILTER_SUBSURFACE |
	    BAKE_FILTER_EMISSION |
	    BAKE_FILTER_AO),
	BAKE_FILTER_DIFFUSE_DIRECT = (BAKE_FILTER_DIRECT | BAKE_FILTER_DIFFUSE),
	BAKE_FILTER_GLOSSY_DIRECT = (BAKE_FILTER_DIRECT | BAKE_FILTER_GLOSSY),
	BAKE_FILTER_TRANSMISSION_DIRECT = (BAKE_FILTER_DIRECT | BAKE_FILTER_TRANSMISSION),
	BAKE_FILTER_SUBSURFACE_DIRECT = (BAKE_FILTER_DIRECT | BAKE_FILTER_SUBSURFACE),
	BAKE_FILTER_DIFFUSE_INDIRECT = (BAKE_FILTER_INDIRECT | BAKE_FILTER_DIFFUSE),
	BAKE_FILTER_GLOSSY_INDIRECT = (BAKE_FILTER_INDIRECT | BAKE_FILTER_GLOSSY),
	BAKE_FILTER_TRANSMISSION_INDIRECT = (BAKE_FILTER_INDIRECT | BAKE_FILTER_TRANSMISSION),
	BAKE_FILTER_SUBSURFACE_INDIRECT = (BAKE_FILTER_INDIRECT | BAKE_FILTER_SUBSURFACE),
} BakePassFilterCombos;

typedef enum DenoiseFlag {
	DENOISING_CLEAN_DIFFUSE_DIR      = (1 << 0),
	DENOISING_CLEAN_DIFFUSE_IND      = (1 << 1),
	DENOISING_CLEAN_GLOSSY_DIR       = (1 << 2),
	DENOISING_CLEAN_GLOSSY_IND       = (1 << 3),
	DENOISING_CLEAN_TRANSMISSION_DIR = (1 << 4),
	DENOISING_CLEAN_TRANSMISSION_IND = (1 << 5),
	DENOISING_CLEAN_SUBSURFACE_DIR   = (1 << 6),
	DENOISING_CLEAN_SUBSURFACE_IND   = (1 << 7),
	DENOISING_CLEAN_ALL_PASSES       = (1 << 8)-1,
} DenoiseFlag;

#ifdef __KERNEL_DEBUG__
/* NOTE: This is a runtime-only struct, alignment is not
 * really important here.
 */
typedef struct DebugData {
	int num_bvh_traversed_nodes;
	int num_bvh_traversed_instances;
	int num_bvh_intersections;
	int num_ray_bounces;
} DebugData;
#endif

typedef ccl_addr_space struct PathRadianceState {
#ifdef __PASSES__
	float3 diffuse;
	float3 glossy;
	float3 transmission;
	float3 subsurface;
	float3 scatter;

	float3 direct;
#endif
} PathRadianceState;

typedef ccl_addr_space struct PathRadiance {
#ifdef __PASSES__
	int use_light_pass;
#endif

	float transparent;
	float3 emission;
#ifdef __PASSES__
	float3 background;
	float3 ao;

	float3 indirect;
	float3 direct_emission;

	float3 color_diffuse;
	float3 color_glossy;
	float3 color_transmission;
	float3 color_subsurface;

	float3 direct_diffuse;
	float3 direct_glossy;
	float3 direct_transmission;
	float3 direct_subsurface;
	float3 direct_scatter;

	float3 indirect_diffuse;
	float3 indirect_glossy;
	float3 indirect_transmission;
	float3 indirect_subsurface;
	float3 indirect_scatter;

	float4 shadow;
	float mist;
#endif

	struct PathRadianceState state;

#ifdef __SHADOW_TRICKS__
	/* Total light reachable across the path, ignoring shadow blocked queries. */
	float3 path_total;
	/* Total light reachable across the path with shadow blocked queries
	 * applied here.
	 *
	 * Dividing this figure by path_total will give estimate of shadow pass.
	 */
	float3 path_total_shaded;

	/* Color of the background on which shadow is alpha-overed. */
	float3 shadow_background_color;

	/* Path radiance sum and throughput at the moment when ray hits shadow
	 * catcher object.
	 */
	float shadow_throughput;

	/* Accumulated transparency along the path after shadow catcher bounce. */
	float shadow_transparency;

	/* Indicate if any shadow catcher data is set. */
	int has_shadow_catcher;
#endif

#ifdef __DENOISING_FEATURES__
	float3 denoising_normal;
	float3 denoising_albedo;
	float denoising_depth;
#endif  /* __DENOISING_FEATURES__ */

#ifdef __KERNEL_DEBUG__
	DebugData debug_data;
#endif  /* __KERNEL_DEBUG__ */
} PathRadiance;

typedef struct BsdfEval {
#ifdef __PASSES__
	int use_light_pass;
#endif

	float3 diffuse;
#ifdef __PASSES__
	float3 glossy;
	float3 transmission;
	float3 transparent;
	float3 subsurface;
	float3 scatter;
#endif
#ifdef __SHADOW_TRICKS__
	float3 sum_no_mis;
#endif
} BsdfEval;

/* Shader Flag */

typedef enum ShaderFlag {
	SHADER_SMOOTH_NORMAL = (1 << 31),
	SHADER_CAST_SHADOW = (1 << 30),
	SHADER_AREA_LIGHT = (1 << 29),
	SHADER_USE_MIS = (1 << 28),
	SHADER_EXCLUDE_DIFFUSE = (1 << 27),
	SHADER_EXCLUDE_GLOSSY = (1 << 26),
	SHADER_EXCLUDE_TRANSMIT = (1 << 25),
	SHADER_EXCLUDE_CAMERA = (1 << 24),
	SHADER_EXCLUDE_SCATTER = (1 << 23),
	SHADER_EXCLUDE_ANY = (SHADER_EXCLUDE_DIFFUSE|SHADER_EXCLUDE_GLOSSY|SHADER_EXCLUDE_TRANSMIT|SHADER_EXCLUDE_CAMERA|SHADER_EXCLUDE_SCATTER),

	SHADER_MASK = ~(SHADER_SMOOTH_NORMAL|SHADER_CAST_SHADOW|SHADER_AREA_LIGHT|SHADER_USE_MIS|SHADER_EXCLUDE_ANY)
} ShaderFlag;

/* Light Type */

typedef enum LightType {
	LIGHT_POINT,
	LIGHT_DISTANT,
	LIGHT_BACKGROUND,
	LIGHT_AREA,
	LIGHT_SPOT,
	LIGHT_TRIANGLE
} LightType;

/* Camera Type */

enum CameraType {
	CAMERA_PERSPECTIVE,
	CAMERA_ORTHOGRAPHIC,
	CAMERA_PANORAMA
};

/* Panorama Type */

enum PanoramaType {
	PANORAMA_EQUIRECTANGULAR = 0,
	PANORAMA_FISHEYE_EQUIDISTANT = 1,
	PANORAMA_FISHEYE_EQUISOLID = 2,
	PANORAMA_MIRRORBALL = 3,

	PANORAMA_NUM_TYPES,
};

/* Differential */

typedef struct differential3 {
	float3 dx;
	float3 dy;
} differential3;

typedef struct differential {
	float dx;
	float dy;
} differential;

/* Ray */

typedef struct Ray {
/* TODO(sergey): This is only needed because current AMD
 * compiler has hard time building the kernel with this
 * reshuffle. And at the same time reshuffle will cause
 * less optimal CPU code in certain places.
 *
 * We'll get rid of this nasty exception once AMD compiler
 * is fixed.
 */
#ifndef __KERNEL_OPENCL_AMD__
	float3 P;		/* origin */
	float3 D;		/* direction */

	float t;		/* length of the ray */
	float time;		/* time (for motion blur) */
#else
	float t;		/* length of the ray */
	float time;		/* time (for motion blur) */
	float3 P;		/* origin */
	float3 D;		/* direction */
#endif

#ifdef __RAY_DIFFERENTIALS__
	differential3 dP;
	differential3 dD;
#endif
} Ray;

/* Intersection */

typedef struct Intersection {
#ifdef __EMBREE__
	float3 Ng;
#endif
	float t, u, v;
	int prim;
	int object;
	int type;

#ifdef __KERNEL_DEBUG__
	int num_traversed_nodes;
	int num_traversed_instances;
	int num_intersections;
#endif
} Intersection;

/* Primitives */

typedef enum PrimitiveType {
	PRIMITIVE_NONE            = 0,
	PRIMITIVE_TRIANGLE        = (1 << 0),
	PRIMITIVE_MOTION_TRIANGLE = (1 << 1),
	PRIMITIVE_CURVE           = (1 << 2),
	PRIMITIVE_MOTION_CURVE    = (1 << 3),
	/* Lamp primitive is not included below on purpose,
	 * since it is no real traceable primitive.
	 */
	PRIMITIVE_LAMP            = (1 << 4),

	PRIMITIVE_ALL_TRIANGLE = (PRIMITIVE_TRIANGLE|PRIMITIVE_MOTION_TRIANGLE),
	PRIMITIVE_ALL_CURVE = (PRIMITIVE_CURVE|PRIMITIVE_MOTION_CURVE),
	PRIMITIVE_ALL_MOTION = (PRIMITIVE_MOTION_TRIANGLE|PRIMITIVE_MOTION_CURVE),
	PRIMITIVE_ALL = (PRIMITIVE_ALL_TRIANGLE|PRIMITIVE_ALL_CURVE),

	/* Total number of different traceable primitives.
	 * NOTE: This is an actual value, not a bitflag.
	 */
	PRIMITIVE_NUM_TOTAL = 4,
} PrimitiveType;

#define PRIMITIVE_PACK_SEGMENT(type, segment) ((segment << PRIMITIVE_NUM_TOTAL) | (type))
#define PRIMITIVE_UNPACK_SEGMENT(type) (type >> PRIMITIVE_NUM_TOTAL)

/* Attributes */

typedef enum AttributePrimitive {
	ATTR_PRIM_TRIANGLE = 0,
	ATTR_PRIM_CURVE,
	ATTR_PRIM_SUBD,

	ATTR_PRIM_TYPES
} AttributePrimitive;

typedef enum AttributeElement {
	ATTR_ELEMENT_NONE,
	ATTR_ELEMENT_OBJECT,
	ATTR_ELEMENT_MESH,
	ATTR_ELEMENT_FACE,
	ATTR_ELEMENT_VERTEX,
	ATTR_ELEMENT_VERTEX_MOTION,
	ATTR_ELEMENT_CORNER,
	ATTR_ELEMENT_CORNER_BYTE,
	ATTR_ELEMENT_CURVE,
	ATTR_ELEMENT_CURVE_KEY,
	ATTR_ELEMENT_CURVE_KEY_MOTION,
	ATTR_ELEMENT_VOXEL
} AttributeElement;

typedef enum AttributeStandard {
	ATTR_STD_NONE = 0,
	ATTR_STD_VERTEX_NORMAL,
	ATTR_STD_FACE_NORMAL,
	ATTR_STD_UV,
	ATTR_STD_UV_TANGENT,
	ATTR_STD_UV_TANGENT_SIGN,
	ATTR_STD_GENERATED,
	ATTR_STD_GENERATED_TRANSFORM,
	ATTR_STD_POSITION_UNDEFORMED,
	ATTR_STD_POSITION_UNDISPLACED,
	ATTR_STD_MOTION_VERTEX_POSITION,
	ATTR_STD_MOTION_VERTEX_NORMAL,
	ATTR_STD_PARTICLE,
	ATTR_STD_CURVE_INTERCEPT,
	ATTR_STD_CURVE_RANDOM,
	ATTR_STD_PTEX_FACE_ID,
	ATTR_STD_PTEX_UV,
	ATTR_STD_VOLUME_DENSITY,
	ATTR_STD_VOLUME_COLOR,
	ATTR_STD_VOLUME_FLAME,
	ATTR_STD_VOLUME_HEAT,
	ATTR_STD_VOLUME_TEMPERATURE,
	ATTR_STD_VOLUME_VELOCITY,
	ATTR_STD_POINTINESS,
	ATTR_STD_NUM,

	ATTR_STD_NOT_FOUND = ~0
} AttributeStandard;

typedef enum AttributeFlag {
	ATTR_FINAL_SIZE = (1 << 0),
	ATTR_SUBDIVIDED = (1 << 1),
} AttributeFlag;

typedef struct AttributeDescriptor {
	AttributeElement element;
	NodeAttributeType type;
	uint flags; /* see enum AttributeFlag */
	int offset;
} AttributeDescriptor;

/* Closure data */

#ifdef __MULTI_CLOSURE__
#  ifdef __SPLIT_KERNEL__
#    define MAX_CLOSURE 1
#  else
#    ifndef __MAX_CLOSURE__
#       define MAX_CLOSURE 64
#    else
#      define MAX_CLOSURE __MAX_CLOSURE__
#    endif
#  endif
#else
#  define MAX_CLOSURE 1
#endif

/* This struct is the base class for all closures. The common members are
 * duplicated in all derived classes since we don't have C++ in the kernel
 * yet, and because it lets us lay out the members to minimize padding. The
 * weight member is located at the beginning of the struct for this reason.
 *
 * ShaderClosure has a fixed size, and any extra space must be allocated
 * with closure_alloc_extra().
 *
 * We pad the struct to 80 bytes and ensure it is aligned to 16 bytes, which
 * we assume to be the maximum required alignment for any struct. */

#define SHADER_CLOSURE_BASE \
	float3 weight; \
	ClosureType type; \
	float sample_weight; \
	float3 N

typedef ccl_addr_space struct ccl_align(16) ShaderClosure {
	SHADER_CLOSURE_BASE;

	float data[10]; /* pad to 80 bytes */
} ShaderClosure;

/* Shader Data
 *
 * Main shader state at a point on the surface or in a volume. All coordinates
 * are in world space.
 */

enum ShaderDataFlag {
	/* Runtime flags. */

	/* Set when ray hits backside of surface. */
	SD_BACKFACING      = (1 << 0),
	/* Shader has non-zero emission. */
	SD_EMISSION        = (1 << 1),
	/* Shader has BSDF closure. */
	SD_BSDF            = (1 << 2),
	/* Shader has non-singular BSDF closure. */
	SD_BSDF_HAS_EVAL   = (1 << 3),
	/* Shader has BSSRDF closure. */
	SD_BSSRDF          = (1 << 4),
	/* Shader has holdout closure. */
	SD_HOLDOUT         = (1 << 5),
	/* Shader has non-zero volume extinction. */
	SD_EXTINCTION      = (1 << 6),
	/* Shader has have volume phase (scatter) closure. */
	SD_SCATTER         = (1 << 7),
	/* Shader has transparent closure. */
	SD_TRANSPARENT     = (1 << 9),
	/* BSDF requires LCG for evaluation. */
	SD_BSDF_NEEDS_LCG  = (1 << 10),

	SD_CLOSURE_FLAGS = (SD_EMISSION |
	                    SD_BSDF |
	                    SD_BSDF_HAS_EVAL |
	                    SD_BSSRDF |
	                    SD_HOLDOUT |
	                    SD_EXTINCTION |
	                    SD_SCATTER |
	                    SD_BSDF_NEEDS_LCG),

	/* Shader flags. */

	/* direct light sample */
	SD_USE_MIS                = (1 << 16),
	/* Has transparent shadow. */
	SD_HAS_TRANSPARENT_SHADOW = (1 << 17),
	/* Has volume shader. */
	SD_HAS_VOLUME             = (1 << 18),
	/* Has only volume shader, no surface. */
	SD_HAS_ONLY_VOLUME        = (1 << 19),
	/* Has heterogeneous volume. */
	SD_HETEROGENEOUS_VOLUME   = (1 << 20),
	/* BSSRDF normal uses bump. */
	SD_HAS_BSSRDF_BUMP        = (1 << 21),
	/* Use equiangular volume sampling */
	SD_VOLUME_EQUIANGULAR     = (1 << 22),
	/* Use multiple importance volume sampling. */
	SD_VOLUME_MIS             = (1 << 23),
	/* Use cubic interpolation for voxels. */
	SD_VOLUME_CUBIC           = (1 << 24),
	/* Has data connected to the displacement input or uses bump map. */
	SD_HAS_BUMP               = (1 << 25),
	/* Has true displacement. */
	SD_HAS_DISPLACEMENT       = (1 << 26),
	/* Has constant emission (value stored in __shaders) */
	SD_HAS_CONSTANT_EMISSION  = (1 << 27),
	/* Needs to access attributes */
	SD_NEED_ATTRIBUTES        = (1 << 28),

	SD_SHADER_FLAGS = (SD_USE_MIS |
	                   SD_HAS_TRANSPARENT_SHADOW |
	                   SD_HAS_VOLUME |
	                   SD_HAS_ONLY_VOLUME |
	                   SD_HETEROGENEOUS_VOLUME |
	                   SD_HAS_BSSRDF_BUMP |
	                   SD_VOLUME_EQUIANGULAR |
	                   SD_VOLUME_MIS |
	                   SD_VOLUME_CUBIC |
	                   SD_HAS_BUMP |
	                   SD_HAS_DISPLACEMENT |
	                   SD_HAS_CONSTANT_EMISSION |
	                   SD_NEED_ATTRIBUTES)
};

	/* Object flags. */
enum ShaderDataObjectFlag {
	/* Holdout for camera rays. */
	SD_OBJECT_HOLDOUT_MASK           = (1 << 0),
	/* Has object motion blur. */
	SD_OBJECT_MOTION                 = (1 << 1),
	/* Vertices have transform applied. */
	SD_OBJECT_TRANSFORM_APPLIED      = (1 << 2),
	/* Vertices have negative scale applied. */
	SD_OBJECT_NEGATIVE_SCALE_APPLIED = (1 << 3),
	/* Object has a volume shader. */
	SD_OBJECT_HAS_VOLUME             = (1 << 4),
	/* Object intersects AABB of an object with volume shader. */
	SD_OBJECT_INTERSECTS_VOLUME      = (1 << 5),
	/* Has position for motion vertices. */
	SD_OBJECT_HAS_VERTEX_MOTION      = (1 << 6),
	/* object is used to catch shadows */
	SD_OBJECT_SHADOW_CATCHER         = (1 << 7),
	/* object has volume attributes */
	SD_OBJECT_HAS_VOLUME_ATTRIBUTES  = (1 << 8),

	SD_OBJECT_FLAGS = (SD_OBJECT_HOLDOUT_MASK |
	                   SD_OBJECT_MOTION |
	                   SD_OBJECT_TRANSFORM_APPLIED |
	                   SD_OBJECT_NEGATIVE_SCALE_APPLIED |
	                   SD_OBJECT_HAS_VOLUME |
	                   SD_OBJECT_INTERSECTS_VOLUME |
	                   SD_OBJECT_SHADOW_CATCHER |
	                   SD_OBJECT_HAS_VOLUME_ATTRIBUTES)
};

typedef ccl_addr_space struct ShaderData {
	/* position */
	float3 P;
	/* smooth normal for shading */
	float3 N;
	/* true geometric normal */
	float3 Ng;
	/* view/incoming direction */
	float3 I;
	/* shader id */
	int shader;
	/* booleans describing shader, see ShaderDataFlag */
	int flag;
	/* booleans describing object of the shader, see ShaderDataObjectFlag */
	int object_flag;

	/* primitive id if there is one, ~0 otherwise */
	int prim;

	/* combined type and curve segment for hair */
	int type;

	/* parametric coordinates
	 * - barycentric weights for triangles */
	float u;
	float v;
	/* object id if there is one, ~0 otherwise */
	int object;
	/* lamp id if there is one, ~0 otherwise */
	int lamp;

	/* motion blur sample time */
	float time;

	/* length of the ray being shaded */
	float ray_length;

#ifdef __RAY_DIFFERENTIALS__
	/* differential of P. these are orthogonal to Ng, not N */
	differential3 dP;
	/* differential of I */
	differential3 dI;
	/* differential of u, v */
	differential du;
	differential dv;
#endif
#ifdef __DPDU__
	/* differential of P w.r.t. parametric coordinates. note that dPdu is
	 * not readily suitable as a tangent for shading on triangles. */
	float3 dPdu;
	float3 dPdv;
#endif

#ifdef __OBJECT_MOTION__
	/* object <-> world space transformations, cached to avoid
	 * re-interpolating them constantly for shading */
	Transform ob_tfm;
	Transform ob_itfm;
#endif

	/* ray start position, only set for backgrounds */
	float3 ray_P;
	differential3 ray_dP;

#ifdef __OSL__
	struct KernelGlobals *osl_globals;
	struct PathState *osl_path_state;
#endif

	/* LCG state for closures that require additional random numbers. */
	uint lcg_state;

	/* Closure data, we store a fixed array of closures */
	int num_closure;
	int num_closure_left;
	float randb_closure;
	float3 svm_closure_weight;

	/* Closure weights summed directly, so we can evaluate
	 * emission and shadow transparency with MAX_CLOSURE 0. */
	float3 closure_emission_background;
	float3 closure_transparent_extinction;

	/* At the end so we can adjust size in ShaderDataTinyStorage. */
	struct ShaderClosure closure[MAX_CLOSURE];
} ShaderData;

typedef ccl_addr_space struct ShaderDataTinyStorage {
	char pad[sizeof(ShaderData) - sizeof(ShaderClosure) * MAX_CLOSURE];
} ShaderDataTinyStorage;
#define AS_SHADER_DATA(shader_data_tiny_storage) ((ShaderData*)shader_data_tiny_storage)

/* Path State */

#ifdef __VOLUME__
typedef struct VolumeStack {
	int object;
	int shader;
} VolumeStack;
#endif

typedef struct PathState {
	/* see enum PathRayFlag */
	int flag;

	/* random number generator state */
	uint rng_hash;          /* per pixel hash */
	int rng_offset;         /* dimension offset */
	int sample;             /* path sample number */
	int num_samples;        /* total number of times this path will be sampled */
	float branch_factor;    /* number of branches in indirect paths */

	/* bounce counting */
	int bounce;
	int diffuse_bounce;
	int glossy_bounce;
	int transmission_bounce;
	int transparent_bounce;

#ifdef __DENOISING_FEATURES__
	float denoising_feature_weight;
#endif  /* __DENOISING_FEATURES__ */

	/* multiple importance sampling */
	float min_ray_pdf; /* smallest bounce pdf over entire path up to now */
	float ray_pdf;     /* last bounce pdf */
#ifdef __LAMP_MIS__
	float ray_t;       /* accumulated distance through transparent surfaces */
#endif

	/* volume rendering */
#ifdef __VOLUME__
	int volume_bounce;
	int volume_bounds_bounce;
	VolumeStack volume_stack[VOLUME_STACK_SIZE];
#endif
} PathState;

/* Struct to gather multiple nearby intersections. */
typedef struct LocalIntersection {
	Ray ray;
	float3 weight[LOCAL_MAX_HITS];

	int num_hits;
	struct Intersection hits[LOCAL_MAX_HITS];
	float3 Ng[LOCAL_MAX_HITS];
} LocalIntersection;

/* Subsurface */

/* Struct to gather SSS indirect rays and delay tracing them. */
typedef struct SubsurfaceIndirectRays {
	PathState state[BSSRDF_MAX_HITS];

	int num_rays;

	struct Ray rays[BSSRDF_MAX_HITS];
	float3 throughputs[BSSRDF_MAX_HITS];
	struct PathRadianceState L_state[BSSRDF_MAX_HITS];
} SubsurfaceIndirectRays;
static_assert(BSSRDF_MAX_HITS <= LOCAL_MAX_HITS, "BSSRDF hits too high.");

/* Constant Kernel Data
 *
 * These structs are passed from CPU to various devices, and the struct layout
 * must match exactly. Structs are padded to ensure 16 byte alignment, and we
 * do not use float3 because its size may not be the same on all devices. */

typedef struct KernelCamera {
	/* type */
	int type;

	/* panorama */
	int panorama_type;
	float fisheye_fov;
	float fisheye_lens;
	float4 equirectangular_range;

	/* stereo */
	float interocular_offset;
	float convergence_distance;
	float pole_merge_angle_from;
	float pole_merge_angle_to;

	/* matrices */
	Transform cameratoworld;
	ProjectionTransform rastertocamera;

	/* differentials */
	float4 dx;
	float4 dy;

	/* depth of field */
	float aperturesize;
	float blades;
	float bladesrotation;
	float focaldistance;

	/* motion blur */
	float shuttertime;
	int num_motion_steps, have_perspective_motion;

	/* clipping */
	float nearclip;
	float cliplength;

	/* sensor size */
	float sensorwidth;
	float sensorheight;

	/* render size */
	float width, height;
	int resolution;

	/* anamorphic lens bokeh */
	float inv_aperture_ratio;

	int is_inside_volume;

	/* more matrices */
	ProjectionTransform screentoworld;
	ProjectionTransform rastertoworld;
	ProjectionTransform ndctoworld;
	ProjectionTransform worldtoscreen;
	ProjectionTransform worldtoraster;
	ProjectionTransform worldtondc;
	Transform worldtocamera;

	/* Stores changes in the projeciton matrix. Use for camera zoom motion
	 * blur and motion pass output for perspective camera. */
	ProjectionTransform perspective_pre;
	ProjectionTransform perspective_post;

	/* Transforms for motion pass. */
	Transform motion_pass_pre;
	Transform motion_pass_post;

	int shutter_table_offset;

	/* Rolling shutter */
	int rolling_shutter_type;
	float rolling_shutter_duration;

	int pad;
} KernelCamera;
static_assert_align(KernelCamera, 16);

typedef struct KernelFilm {
	float exposure;
	int pass_flag;
	int light_pass_flag;
	int pass_stride;
	int use_light_pass;

	int pass_combined;
	int pass_depth;
	int pass_normal;
	int pass_motion;

	int pass_motion_weight;
	int pass_uv;
	int pass_object_id;
	int pass_material_id;

	int pass_diffuse_color;
	int pass_glossy_color;
	int pass_transmission_color;
	int pass_subsurface_color;

	int pass_diffuse_indirect;
	int pass_glossy_indirect;
	int pass_transmission_indirect;
	int pass_subsurface_indirect;
	int pass_volume_indirect;

	int pass_diffuse_direct;
	int pass_glossy_direct;
	int pass_transmission_direct;
	int pass_subsurface_direct;
	int pass_volume_direct;

	int pass_emission;
	int pass_background;
	int pass_ao;
	float pass_alpha_threshold;

	int pass_shadow;
	float pass_shadow_scale;
	int filter_table_offset;
	int cryptomatte_passes;
	int cryptomatte_depth;
	int pass_cryptomatte;

	int pass_mist;
	float mist_start;
	float mist_inv_depth;
	float mist_falloff;

	int pass_denoising_data;
	int pass_denoising_clean;
	int denoising_flags;

	/* XYZ to rendering color space transform. float4 instead of float3 to
	 * ensure consistent padding/alignment across devices. */
	float4 xyz_to_r;
	float4 xyz_to_g;
	float4 xyz_to_b;
	float4 rgb_to_y;

#ifdef __KERNEL_DEBUG__
	int pass_bvh_traversed_nodes;
	int pass_bvh_traversed_instances;
	int pass_bvh_intersections;
	int pass_ray_bounces;
#endif
} KernelFilm;
static_assert_align(KernelFilm, 16);

typedef struct KernelBackground {
	/* only shader index */
	int surface_shader;
	int volume_shader;
	int transparent;
	float transparent_roughness_squared_threshold;

	/* ambient occlusion */
	float ao_factor;
	float ao_distance;
	float ao_bounces_factor;
	float ao_pad;
} KernelBackground;
static_assert_align(KernelBackground, 16);

typedef struct KernelIntegrator {
	/* emission */
	int use_direct_light;
	int use_ambient_occlusion;
	int num_distribution;
	int num_all_lights;
	float pdf_triangles;
	float pdf_lights;
	int pdf_background_res_x;
	int pdf_background_res_y;
	float light_inv_rr_threshold;

	/* light portals */
	float portal_pdf;
	int num_portals;
	int portal_offset;

	/* bounces */
	int max_bounce;

	int max_diffuse_bounce;
	int max_glossy_bounce;
	int max_transmission_bounce;
	int max_volume_bounce;

	int ao_bounces;

	/* transparent */
	int transparent_max_bounce;
	int transparent_shadows;

	/* caustics */
	int caustics_reflective;
	int caustics_refractive;
	float filter_glossy;

	/* seed */
	int seed;

	/* clamp */
	float sample_clamp_direct;
	float sample_clamp_indirect;

	/* branched path */
	int branched;
	int volume_decoupled;
	int diffuse_samples;
	int glossy_samples;
	int transmission_samples;
	int ao_samples;
	int mesh_light_samples;
	int subsurface_samples;
	int sample_all_lights_direct;
	int sample_all_lights_indirect;

	/* mis */
	int use_lamp_mis;

	/* sampler */
	int sampling_pattern;
	int aa_samples;

	/* volume render */
	int use_volumes;
	int volume_max_steps;
	float volume_step_size;
	int volume_samples;

	int start_sample;

	int max_closures;

	int pad1, pad2, pad3;
} KernelIntegrator;
static_assert_align(KernelIntegrator, 16);

typedef enum KernelBVHLayout {
	BVH_LAYOUT_NONE = 0,

	BVH_LAYOUT_BVH2 = (1 << 0),
	BVH_LAYOUT_BVH4 = (1 << 1),
	BVH_LAYOUT_BVH8 = (1 << 2),
	BVH_LAYOUT_EMBREE = (1 << 3),
	BVH_LAYOUT_DEFAULT = BVH_LAYOUT_BVH8,
	BVH_LAYOUT_ALL = (unsigned int)(-1),
} KernelBVHLayout;

typedef struct KernelBVH {
	/* Own BVH */
	int root;
	int have_motion;
	int have_curves;
	int have_instancing;
	int bvh_layout;
	int use_bvh_steps;

	/* Embree */
#ifdef __EMBREE__
	RTCScene scene;
#  ifndef __KERNEL_64_BIT__
	int pad1;
#  endif
#else
	int pad1, pad2;
#endif
} KernelBVH;
static_assert_align(KernelBVH, 16);

typedef enum CurveFlag {
	/* runtime flags */
	CURVE_KN_BACKFACING = 1,				/* backside of cylinder? */
	CURVE_KN_ENCLOSEFILTER = 2,				/* don't consider strands surrounding start point? */
	CURVE_KN_INTERPOLATE = 4,				/* render as a curve? */
	CURVE_KN_ACCURATE = 8,					/* use accurate intersections test? */
	CURVE_KN_INTERSECTCORRECTION = 16,		/* correct for width after determing closest midpoint? */
	CURVE_KN_TRUETANGENTGNORMAL = 32,		/* use tangent normal for geometry? */
	CURVE_KN_RIBBONS = 64,					/* use flat curve ribbons */
} CurveFlag;

typedef struct KernelCurves {
	int curveflags;
	int subdivisions;

	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;
	KernelFilm film;
	KernelBackground background;
	KernelIntegrator integrator;
	KernelBVH bvh;
	KernelCurves curve;
	KernelTables tables;
} KernelData;
static_assert_align(KernelData, 16);

/* Kernel data structures. */

typedef struct KernelObject {
	Transform tfm;
	Transform itfm;

	float surface_area;
	float pass_id;
	float random_number;
	int particle_index;

	float dupli_generated[3];
	float dupli_uv[2];

	int numkeys;
	int numsteps;
	int numverts;

	uint patch_map_offset;
	uint attribute_map_offset;
	uint motion_offset;
	uint pad1;

	float cryptomatte_object;
	float cryptomatte_asset;
	float pad2, pad3;
} KernelObject;
static_assert_align(KernelObject, 16);

typedef struct KernelSpotLight {
	float radius;
	float invarea;
	float spot_angle;
	float spot_smooth;
	float dir[3];
	float pad;
} KernelSpotLight;

/* PointLight is SpotLight with only radius and invarea being used. */

typedef struct KernelAreaLight {
	float axisu[3];
	float invarea;
	float axisv[3];
	float pad1;
	float dir[3];
	float pad2;
} KernelAreaLight;

typedef struct KernelDistantLight {
	float radius;
	float cosangle;
	float invarea;
	float pad;
} KernelDistantLight;

typedef struct KernelLight {
	int type;
	float co[3];
	int shader_id;
	int samples;
	float max_bounces;
	float random;
	Transform tfm;
	Transform itfm;
	union {
		KernelSpotLight spot;
		KernelAreaLight area;
		KernelDistantLight distant;
	};
} KernelLight;
static_assert_align(KernelLight, 16);

typedef struct KernelLightDistribution {
	float totarea;
	int prim;
	union {
		struct {
			int shader_flag;
			int object_id;
		} mesh_light;
		struct {
			float pad;
			float size;
		} lamp;
	};
} KernelLightDistribution;
static_assert_align(KernelLightDistribution, 16);

typedef struct KernelParticle {
	int index;
	float age;
	float lifetime;
	float size;
	float4 rotation;
	/* Only xyz are used of the following. float4 instead of float3 are used
	 * to ensure consistent padding/alignment across devices. */
	float4 location;
	float4 velocity;
	float4 angular_velocity;
} KernelParticle;
static_assert_align(KernelParticle, 16);

typedef struct KernelShader {
	float constant_emission[3];
	float cryptomatte_id;
	int flags;
	int pass_id;
	int pad2, pad3;
} KernelShader;
static_assert_align(KernelShader, 16);

/* Declarations required for split kernel */

/* Macro for queues */
/* Value marking queue's empty slot */
#define QUEUE_EMPTY_SLOT -1

/*
 * Queue 1 - Active rays
 * Queue 2 - Background queue
 * Queue 3 - Shadow ray cast kernel - AO
 * Queeu 4 - Shadow ray cast kernel - direct lighting
 */

/* Queue names */
enum QueueNumber {
	/* All active rays and regenerated rays are enqueued here. */
	QUEUE_ACTIVE_AND_REGENERATED_RAYS = 0,

	/* All
	 * 1. Background-hit rays,
	 * 2. Rays that has exited path-iteration but needs to update output buffer
	 * 3. Rays to be regenerated
	 * are enqueued here.
	 */
	QUEUE_HITBG_BUFF_UPDATE_TOREGEN_RAYS,

	/* All rays for which a shadow ray should be cast to determine radiance
	 * contribution for AO are enqueued here.
	 */
	QUEUE_SHADOW_RAY_CAST_AO_RAYS,

	/* All rays for which a shadow ray should be cast to determine radiance
	 * contributing for direct lighting are enqueued here.
	 */
	QUEUE_SHADOW_RAY_CAST_DL_RAYS,

	/* Rays sorted according to shader->id */
	QUEUE_SHADER_SORTED_RAYS,

#ifdef __BRANCHED_PATH__
	/* All rays moving to next iteration of the indirect loop for light */
	QUEUE_LIGHT_INDIRECT_ITER,
	/* Queue of all inactive rays. These are candidates for sharing work of indirect loops */
	QUEUE_INACTIVE_RAYS,
#  ifdef __VOLUME__
	/* All rays moving to next iteration of the indirect loop for volumes */
	QUEUE_VOLUME_INDIRECT_ITER,
#  endif
#  ifdef __SUBSURFACE__
	/* All rays moving to next iteration of the indirect loop for subsurface */
	QUEUE_SUBSURFACE_INDIRECT_ITER,
#  endif
#endif  /* __BRANCHED_PATH__ */

	NUM_QUEUES
};

/* We use RAY_STATE_MASK to get ray_state */
#define RAY_STATE_MASK 0x0F
#define RAY_FLAG_MASK 0xF0
enum RayState {
	RAY_INVALID = 0,
	/* Denotes ray is actively involved in path-iteration. */
	RAY_ACTIVE,
	/* Denotes ray has completed processing all samples and is inactive. */
	RAY_INACTIVE,
	/* Denotes ray has exited path-iteration and needs to update output buffer. */
	RAY_UPDATE_BUFFER,
	/* Denotes ray needs to skip most surface shader work. */
	RAY_HAS_ONLY_VOLUME,
	/* Donotes ray has hit background */
	RAY_HIT_BACKGROUND,
	/* Denotes ray has to be regenerated */
	RAY_TO_REGENERATE,
	/* Denotes ray has been regenerated */
	RAY_REGENERATED,
	/* Denotes ray is moving to next iteration of the branched indirect loop */
	RAY_LIGHT_INDIRECT_NEXT_ITER,
	RAY_VOLUME_INDIRECT_NEXT_ITER,
	RAY_SUBSURFACE_INDIRECT_NEXT_ITER,

	/* Ray flags */

	/* Flags to denote that the ray is currently evaluating the branched indirect loop */
	RAY_BRANCHED_LIGHT_INDIRECT = (1 << 4),
	RAY_BRANCHED_VOLUME_INDIRECT = (1 << 5),
	RAY_BRANCHED_SUBSURFACE_INDIRECT = (1 << 6),
	RAY_BRANCHED_INDIRECT = (RAY_BRANCHED_LIGHT_INDIRECT | RAY_BRANCHED_VOLUME_INDIRECT | RAY_BRANCHED_SUBSURFACE_INDIRECT),

	/* Ray is evaluating an iteration of an indirect loop for another thread */
	RAY_BRANCHED_INDIRECT_SHARED = (1 << 7),
};

#define ASSIGN_RAY_STATE(ray_state, ray_index, state) (ray_state[ray_index] = ((ray_state[ray_index] & RAY_FLAG_MASK) | state))
#define IS_STATE(ray_state, ray_index, state) ((ray_index) != QUEUE_EMPTY_SLOT && ((ray_state)[(ray_index)] & RAY_STATE_MASK) == (state))
#define ADD_RAY_FLAG(ray_state, ray_index, flag) (ray_state[ray_index] = (ray_state[ray_index] | flag))
#define REMOVE_RAY_FLAG(ray_state, ray_index, flag) (ray_state[ray_index] = (ray_state[ray_index] & (~flag)))
#define IS_FLAG(ray_state, ray_index, flag) (ray_state[ray_index] & flag)

/* Patches */

#define PATCH_MAX_CONTROL_VERTS 16

/* Patch map node flags */

#define PATCH_MAP_NODE_IS_SET (1 << 30)
#define PATCH_MAP_NODE_IS_LEAF (1u << 31)
#define PATCH_MAP_NODE_INDEX_MASK (~(PATCH_MAP_NODE_IS_SET | PATCH_MAP_NODE_IS_LEAF))

/* Work Tiles */

typedef struct WorkTile {
	uint x, y, w, h;

	uint start_sample;
	uint num_samples;

	uint offset;
	uint stride;

	ccl_global float *buffer;
} WorkTile;

CCL_NAMESPACE_END

#endif  /*  __KERNEL_TYPES_H__ */
